* feat(sdk): add typed query foundation and gsd-sdk query (Phase 1) Add sdk/src/query registry and handlers with tests, GSDQueryError, CLI query wiring, and supporting type/tool-scoping hooks. Update CHANGELOG. Vitest 4 constructor mock fixes in milestone-runner tests. Made-with: Cursor * fix(2137): skip worktree isolation when .gitmodules detected When a project contains git submodules, worktree isolation cannot correctly handle submodule commits — three separate gaps exist in worktree setup, executor commit protocol, and merge-back. Rather than patch each gap individually, detect .gitmodules at phase start and fall back to sequential execution, which handles submodules transparently (Option B). Affected workflows: execute-phase.md, quick.md --------- Co-authored-by: David Sienkowski <dave@sienkowski.com>
34 lines
1.1 KiB
TypeScript
34 lines
1.1 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 { posix } 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';
|
|
// Use POSIX segments so the same logical path string is used on all platforms (Windows included).
|
|
return posix.join('.planning', 'workstreams', workstream);
|
|
}
|