Add a --ws <name> CLI flag that routes all .planning/ paths to .planning/workstreams/<name>/, enabling multi-workstream projects without directory conflicts. Changes: - workstream-utils.ts: validateWorkstreamName() and relPlanningPath() helpers - cli.ts: Parse --ws flag with input validation - types.ts: Add workstream? to GSDOptions - gsd-tools.ts: Inject --ws <name> into all gsd-tools.cjs invocations - config.ts: Resolve workstream-aware config path with root fallback - context-engine.ts: Constructor accepts workstream via positional param - index.ts: GSD class propagates workstream to all subsystems - ws-flag.test.ts: 22 tests covering all workstream functionality Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
33 lines
1.0 KiB
TypeScript
33 lines
1.0 KiB
TypeScript
/**
|
|
* Workstream utility functions for multi-workstream project support.
|
|
*
|
|
* When --ws <name> is provided, all .planning/ paths are routed to
|
|
* .planning/workstreams/<name>/ instead.
|
|
*/
|
|
|
|
import { join } from 'node:path';
|
|
|
|
/**
|
|
* Validate a workstream name.
|
|
* Allowed: alphanumeric, hyphens, underscores, dots.
|
|
* Disallowed: empty, spaces, slashes, special chars, path traversal.
|
|
*/
|
|
export function validateWorkstreamName(name: string): boolean {
|
|
if (!name || name.length === 0) return false;
|
|
// Only allow alphanumeric, hyphens, underscores, dots
|
|
// Must not be ".." or start with ".." (path traversal)
|
|
if (name === '..' || name.startsWith('../')) return false;
|
|
return /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name);
|
|
}
|
|
|
|
/**
|
|
* Return the relative planning directory path.
|
|
*
|
|
* - Without workstream: `.planning`
|
|
* - With workstream: `.planning/workstreams/<name>`
|
|
*/
|
|
export function relPlanningPath(workstream?: string): string {
|
|
if (!workstream) return '.planning';
|
|
return join('.planning', 'workstreams', workstream);
|
|
}
|