@opengsd/gsd-core 1.7.0-rc.1 → 1.7.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +20 -0
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +711 -0
- package/GEMINI.md +25 -23
- package/README.md +3 -3
- package/agents/gsd-advisor-researcher.md +3 -1
- package/agents/gsd-ai-researcher.md +2 -2
- package/agents/gsd-assumptions-analyzer.md +2 -0
- package/agents/gsd-code-fixer.md +3 -1
- package/agents/gsd-code-reviewer.md +2 -0
- package/agents/gsd-codebase-mapper.md +2 -0
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +3 -1
- package/agents/gsd-doc-writer.md +2 -0
- package/agents/gsd-domain-researcher.md +1 -1
- package/agents/gsd-eval-auditor.md +3 -1
- package/agents/gsd-executor.md +12 -9
- package/agents/gsd-integration-checker.md +2 -0
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +1 -1
- package/agents/gsd-nyquist-auditor.md +2 -0
- package/agents/gsd-phase-researcher.md +4 -2
- package/agents/gsd-plan-checker.md +3 -1
- package/agents/gsd-planner.md +4 -2
- package/agents/gsd-project-researcher.md +4 -2
- package/agents/gsd-research-synthesizer.md +3 -1
- package/agents/gsd-roadmapper.md +2 -0
- package/agents/gsd-security-auditor.md +2 -0
- package/agents/gsd-ui-auditor.md +2 -0
- package/agents/gsd-ui-checker.md +2 -0
- package/agents/gsd-ui-researcher.md +4 -2
- package/agents/gsd-verifier.md +6 -4
- package/bin/install.js +226 -459
- package/commands/gsd/mempalace-capture.md +1 -1
- package/commands/gsd/mempalace-recall.md +9 -5
- package/commands/gsd/next.md +29 -0
- package/commands/gsd/ns-workflow.md +5 -2
- package/gsd-core/bin/ensure-runtime-build.cjs +246 -0
- package/gsd-core/bin/gsd-tools.cjs +43 -8
- package/gsd-core/bin/lib/capability-loader.cjs +27 -9
- package/gsd-core/bin/lib/capability-registry.cjs +209 -205
- package/gsd-core/bin/lib/capability-source.cjs +22 -7
- package/gsd-core/bin/lib/capability-validator.cjs +24 -2
- package/gsd-core/bin/lib/check-command-router.cjs +111 -1
- package/gsd-core/bin/lib/clusters.cjs +1 -0
- package/gsd-core/bin/lib/commands.cjs +2 -1
- package/gsd-core/bin/lib/config.cjs +19 -1
- package/gsd-core/bin/lib/core-utils.cjs +41 -0
- package/gsd-core/bin/lib/external-job.cjs +287 -0
- package/gsd-core/bin/lib/frontmatter.cjs +53 -6
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +151 -0
- package/gsd-core/bin/lib/graphify.cjs +41 -9
- package/gsd-core/bin/lib/handshake-serialized.cjs +70 -0
- package/gsd-core/bin/lib/host-integration-sdk.cjs +53 -0
- package/gsd-core/bin/lib/host-integration.cjs +61 -0
- package/gsd-core/bin/lib/init.cjs +34 -6
- package/gsd-core/bin/lib/milestone.cjs +56 -11
- package/gsd-core/bin/lib/phase-id.cjs +18 -0
- package/gsd-core/bin/lib/phase.cjs +51 -29
- package/gsd-core/bin/lib/phases-command-router.cjs +4 -3
- package/gsd-core/bin/lib/plan-scan.cjs +9 -1
- package/gsd-core/bin/lib/probe-core.cjs +44 -4
- package/gsd-core/bin/lib/profile-output.cjs +1 -1
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +21 -19
- package/gsd-core/bin/lib/roadmap-command-router.cjs +3 -2
- package/gsd-core/bin/lib/roadmap-parser.cjs +21 -11
- package/gsd-core/bin/lib/roadmap.cjs +45 -22
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +18 -13
- package/gsd-core/bin/lib/runtime-name-policy.cjs +8 -10
- package/gsd-core/bin/lib/shell-command-projection.cjs +12 -8
- package/gsd-core/bin/lib/smart-entry.cjs +521 -0
- package/gsd-core/bin/lib/state-transition.cjs +15 -0
- package/gsd-core/bin/lib/state.cjs +27 -8
- package/gsd-core/bin/lib/surface.cjs +18 -9
- package/gsd-core/bin/lib/update-context.cjs +0 -5
- package/gsd-core/bin/lib/validate.cjs +2 -1
- package/gsd-core/bin/lib/verify.cjs +6 -4
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +12 -2
- package/gsd-core/bin/lib/workstream-inventory.cjs +28 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -13
- package/gsd-core/bin/shared/runtime-aliases.manifest.json +0 -5
- package/gsd-core/references/agent-skills-bootstrap.md +60 -0
- package/gsd-core/references/gates.md +1 -1
- package/gsd-core/references/model-profiles.md +27 -0
- package/gsd-core/references/planning-config.md +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +1 -1
- package/gsd-core/workflows/add-tests.md +1 -1
- package/gsd-core/workflows/add-todo.md +1 -1
- package/gsd-core/workflows/ai-integration-phase.md +1 -1
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +1 -1
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous.md +23 -25
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +1 -1
- package/gsd-core/workflows/code-review-fix.md +1 -1
- package/gsd-core/workflows/code-review.md +1 -1
- package/gsd-core/workflows/complete-milestone.md +7 -11
- package/gsd-core/workflows/debug.md +1 -1
- package/gsd-core/workflows/diagnose-issues.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/auto.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
- package/gsd-core/workflows/discuss-phase.md +2 -2
- package/gsd-core/workflows/do.md +1 -1
- package/gsd-core/workflows/docs-update.md +1 -1
- package/gsd-core/workflows/edit-phase.md +1 -1
- package/gsd-core/workflows/eval-review.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
- package/gsd-core/workflows/execute-phase.md +5 -6
- package/gsd-core/workflows/execute-plan.md +1 -1
- package/gsd-core/workflows/explore.md +1 -1
- package/gsd-core/workflows/extract-learnings.md +1 -1
- package/gsd-core/workflows/forensics.md +4 -4
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +1 -1
- package/gsd-core/workflows/help/modes/full.md +15 -1
- package/gsd-core/workflows/help/modes/topic.md +1 -0
- package/gsd-core/workflows/import.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- package/gsd-core/workflows/insert-phase.md +1 -1
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +1 -1
- package/gsd-core/workflows/map-codebase.md +1 -1
- package/gsd-core/workflows/milestone-summary.md +4 -4
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +7 -1
- package/gsd-core/workflows/new-project.md +1 -1
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-milestone-gaps.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +42 -0
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +102 -0
- package/gsd-core/workflows/plan-phase/steps/windows-troubleshooting.md +23 -0
- package/gsd-core/workflows/plan-phase.md +12 -160
- package/gsd-core/workflows/plan-review-convergence.md +1 -1
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +1 -1
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress.md +1 -1
- package/gsd-core/workflows/quick.md +1 -1
- package/gsd-core/workflows/reapply-patches.md +1 -1
- package/gsd-core/workflows/remove-phase.md +1 -1
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +1 -1
- package/gsd-core/workflows/review.md +50 -9
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/settings-advanced.md +13 -11
- package/gsd-core/workflows/settings-integrations.md +1 -1
- package/gsd-core/workflows/settings.md +1 -1
- package/gsd-core/workflows/ship.md +1 -1
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +120 -0
- package/gsd-core/workflows/spec-phase.md +8 -6
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/thread.md +1 -1
- package/gsd-core/workflows/transition.md +1 -1
- package/gsd-core/workflows/ui-phase.md +1 -1
- package/gsd-core/workflows/ui-review.md +1 -1
- package/gsd-core/workflows/ultraplan-phase.md +1 -1
- package/gsd-core/workflows/update.md +3 -6
- package/gsd-core/workflows/validate-phase.md +1 -1
- package/gsd-core/workflows/verify-phase.md +1 -1
- package/gsd-core/workflows/verify-work.md +63 -6
- package/package.json +5 -5
- package/scripts/ci-test-scope.cjs +19 -1
- package/scripts/generate-package-identity.cjs +27 -2
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -148
- package/scripts/lint-regression-test-names.allowlist.json +1 -273
- package/scripts/lint-test-file-count.allowlist.json +7 -91
- package/scripts/research-profiles.cjs +6 -6
- package/scripts/run-tests.cjs +67 -4
- package/scripts/slurm-adapter.cjs +269 -0
- package/scripts/sync-manifest-versions.cjs +67 -14
- package/skills/gsd-mempalace-capture/SKILL.md +1 -1
- package/skills/gsd-mempalace-recall/SKILL.md +9 -5
- package/skills/gsd-next/SKILL.md +30 -0
- package/skills/gsd-ns-workflow/SKILL.md +4 -1
- package/skills/gsd-review/SKILL.md +6 -0
- package/gemini-extension.json +0 -6
|
@@ -22,7 +22,7 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
22
22
|
const node_path_1 = __importDefault(require("node:path"));
|
|
23
23
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
24
24
|
const phaseIdModule = require("./phase-id.cjs");
|
|
25
|
-
const { escapeRegex, phaseMarkdownRegexSource, phaseMarkdownRegexSourceExact, stripProjectCodePrefix, OPTIONAL_PROJECT_CODE_PREFIX_SOURCE, } = phaseIdModule;
|
|
25
|
+
const { escapeRegex, phaseMarkdownRegexSource, phaseMarkdownRegexSourceExact, stripProjectCodePrefix, OPTIONAL_PROJECT_CODE_PREFIX_SOURCE, OPTIONAL_PHASE_TAG_SOURCE, } = phaseIdModule;
|
|
26
26
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
27
27
|
const planningWorkspace = require("./planning-workspace.cjs");
|
|
28
28
|
const { planningDir } = planningWorkspace;
|
|
@@ -82,7 +82,8 @@ function extractCurrentMilestone(content, cwd) {
|
|
|
82
82
|
const preambleCutoff = firstMilestoneMatch ? firstMilestoneMatch.index : detailsOpenIdx;
|
|
83
83
|
const preamble = content.slice(0, preambleCutoff)
|
|
84
84
|
.replace(/<details>[\s\S]*?<\/details>/gi, '')
|
|
85
|
-
|
|
85
|
+
// #1729: `(?:\s*\([^)\n]*\))?` tolerates a pre-colon ( ) tag (literal mirror of OPTIONAL_PHASE_TAG_SOURCE).
|
|
86
|
+
.replace(/^#{2,4}\s*Phase\s+[\w][\w.-]*(?:\s*\([^)\n]*\))?\s*:[^\n]*(?:\n(?!#{1,6}\s)[^\n]*)*\n?/gim, '')
|
|
86
87
|
.replace(/^#{1,4}\s*Phase Details\b[^\n]*\n?/gim, '');
|
|
87
88
|
return preamble + content.slice(detailsOpenIdx, detailsEnd);
|
|
88
89
|
}
|
|
@@ -151,7 +152,8 @@ function extractCurrentMilestone(content, cwd) {
|
|
|
151
152
|
}
|
|
152
153
|
const preamble = beforeMilestones
|
|
153
154
|
.replace(/<details>[\s\S]*?<\/details>/gi, '')
|
|
154
|
-
|
|
155
|
+
// #1729: `(?:\s*\([^)\n]*\))?` tolerates a pre-colon ( ) tag (literal mirror of OPTIONAL_PHASE_TAG_SOURCE).
|
|
156
|
+
.replace(/^#{2,4}\s*Phase\s+[\w][\w.-]*(?:\s*\([^)\n]*\))?\s*:[^\n]*(?:\n(?!#{1,6}\s)[^\n]*)*\n?/gim, '')
|
|
155
157
|
.replace(/^#{1,4}\s*Phase Details\b[^\n]*\n?/gim, '');
|
|
156
158
|
return detailsSection
|
|
157
159
|
? preamble + currentSection + '\n' + detailsSection
|
|
@@ -171,16 +173,20 @@ function replaceInCurrentMilestone(content, pattern, replacement) {
|
|
|
171
173
|
return before + after.replace(pattern, replacement);
|
|
172
174
|
}
|
|
173
175
|
function findRoadmapPhaseInContent(content, phaseNum, phaseSource) {
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
+
// #1729: OPTIONAL_PHASE_TAG_SOURCE after the number tolerates a pre-colon ( ) tag.
|
|
177
|
+
const headingPattern = new RegExp(`^(?:\\[[^\\]]+\\]\\s*)?Phase\\s+${phaseSource ?? phaseMarkdownRegexSource(phaseNum)}${OPTIONAL_PHASE_TAG_SOURCE}:\\s*(.+)$`, 'i');
|
|
178
|
+
const headings = (0, markdown_sectionizer_cjs_1.tokenizeHeadings)(content);
|
|
179
|
+
const headingIndex = headings.findIndex((heading) => headingPattern.test(heading.text));
|
|
180
|
+
if (headingIndex === -1)
|
|
181
|
+
return null;
|
|
182
|
+
const heading = headings[headingIndex];
|
|
183
|
+
const headerMatch = heading.text.match(headingPattern);
|
|
176
184
|
if (!headerMatch)
|
|
177
185
|
return null;
|
|
178
186
|
const phaseName = headerMatch[1].trim();
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
const sectionEnd = nextHeaderMatch ? headerIndex + nextHeaderMatch.index : content.length;
|
|
183
|
-
const section = content.slice(headerIndex, sectionEnd).trim();
|
|
187
|
+
const nextHeading = headings.slice(headingIndex + 1).find((candidate) => candidate.level <= heading.level);
|
|
188
|
+
const sectionEnd = nextHeading ? nextHeading.offset : content.length;
|
|
189
|
+
const section = content.slice(heading.offset, sectionEnd).trim();
|
|
184
190
|
const goalMatch = section.match(/\*\*Goal(?:\*\*:|\*?\*?:\*\*)\s*([^\n]+)/i);
|
|
185
191
|
const goal = goalMatch ? goalMatch[1].trim() : null;
|
|
186
192
|
return {
|
|
@@ -209,6 +215,9 @@ function roadmapPhaseLookupSources(phaseNum) {
|
|
|
209
215
|
function getRoadmapPhaseInternal(cwd, phaseNum) {
|
|
210
216
|
if (!phaseNum)
|
|
211
217
|
return null;
|
|
218
|
+
const normalizedPhase = stripProjectCodePrefix(phaseNum);
|
|
219
|
+
if (/^999(?:\.|$)/.test(normalizedPhase))
|
|
220
|
+
return null;
|
|
212
221
|
const roadmapPath = node_path_1.default.join(planningDir(cwd), 'ROADMAP.md');
|
|
213
222
|
if (!node_fs_1.default.existsSync(roadmapPath))
|
|
214
223
|
return null;
|
|
@@ -369,7 +378,8 @@ function getMilestonePhaseFilter(cwd, versionOverride, phaseIdConvention) {
|
|
|
369
378
|
}
|
|
370
379
|
// Use tokenizeHeadings (fence-aware) instead of stripFencedLines + regex.
|
|
371
380
|
// T4 seam migration: phase headings inside fences are excluded automatically.
|
|
372
|
-
|
|
381
|
+
// #1729: `(?:\s*\([^)\n]*\))?` tolerates a pre-colon ( ) tag (literal mirror of OPTIONAL_PHASE_TAG_SOURCE).
|
|
382
|
+
const phaseHeadingPattern = /^(?:\[[^\]]+\]\s*)?Phase\s+([\w][\w.-]*)(?:\s*\([^)\n]*\))?\s*:/i;
|
|
373
383
|
for (const h of (0, markdown_sectionizer_cjs_1.tokenizeHeadings)(roadmap)) {
|
|
374
384
|
if (h.level < 2 || h.level > 4)
|
|
375
385
|
continue;
|
|
@@ -17,13 +17,14 @@ const ioMod = require("./io.cjs");
|
|
|
17
17
|
const { output, error } = ioMod;
|
|
18
18
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
19
19
|
const phaseIdMod = require("./phase-id.cjs");
|
|
20
|
-
const { escapeRegex, normalizePhaseName, phaseMarkdownRegexSource, phaseMarkdownRegexSourceExact, phaseTokenMatches } = phaseIdMod;
|
|
20
|
+
const { escapeRegex, normalizePhaseName, phaseMarkdownRegexSource, phaseMarkdownRegexSourceExact, phaseTokenMatches, stripProjectCodePrefix, OPTIONAL_PHASE_TAG_SOURCE } = phaseIdMod;
|
|
21
21
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
22
22
|
const phaseLocatorMod = require("./phase-locator.cjs");
|
|
23
23
|
const { findPhaseInternal } = phaseLocatorMod;
|
|
24
24
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
25
25
|
const roadmapParserModule = require("./roadmap-parser.cjs");
|
|
26
26
|
const { stripShippedMilestones, extractCurrentMilestone, replaceInCurrentMilestone } = roadmapParserModule;
|
|
27
|
+
const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
|
|
27
28
|
const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
|
|
28
29
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
29
30
|
const planningWorkspace = require("./planning-workspace.cjs");
|
|
@@ -31,8 +32,14 @@ const { planningPaths, withPlanningLock, findContextMdIn } = planningWorkspace;
|
|
|
31
32
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
32
33
|
const scanPhasePlans = require("./plan-scan.cjs");
|
|
33
34
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
35
|
+
const coreUtils = require("./core-utils.cjs");
|
|
36
|
+
const { countMatchedSummaries } = coreUtils;
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
34
38
|
const frontmatter = require("./frontmatter.cjs");
|
|
35
39
|
const { extractFrontmatter, parseMustHavesBlock } = frontmatter;
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
41
|
+
const verificationMod = require("./verification.cjs");
|
|
42
|
+
const { readVerificationStatus } = verificationMod;
|
|
36
43
|
// ─── coerceTruthToString ──────────────────────────────────────────────────────
|
|
37
44
|
/**
|
|
38
45
|
* Coerce an arbitrary YAML scalar/object into a string for cross-cutting
|
|
@@ -94,12 +101,14 @@ function countPhasePlansAndSummaries(phaseDir) {
|
|
|
94
101
|
* checklist-only match), or null if the phase is not present at all.
|
|
95
102
|
*/
|
|
96
103
|
function searchPhaseInContent(content, escapedPhase, phaseNum) {
|
|
97
|
-
//
|
|
98
|
-
const
|
|
99
|
-
const
|
|
104
|
+
// #1729: OPTIONAL_PHASE_TAG_SOURCE after the number tolerates a pre-colon ( ) tag.
|
|
105
|
+
const headingPattern = new RegExp(`^(?:\\[[^\\]]+\\]\\s*)?Phase\\s+${escapedPhase}${OPTIONAL_PHASE_TAG_SOURCE}:\\s*(.+)$`, 'i');
|
|
106
|
+
const headings = (0, markdown_sectionizer_cjs_1.tokenizeHeadings)(content);
|
|
107
|
+
const headingIndex = headings.findIndex((heading) => headingPattern.test(heading.text));
|
|
108
|
+
const headerMatch = headingIndex === -1 ? null : headings[headingIndex].text.match(headingPattern);
|
|
100
109
|
if (!headerMatch) {
|
|
101
110
|
// Fallback: check if phase exists in summary list but missing detail section
|
|
102
|
-
const checklistPattern = new RegExp(`-\\s*\\[[ x]\\]\\s*\\*\\*Phase\\s+${escapedPhase}:\\s*([^*]+)\\*\\*`, 'i');
|
|
111
|
+
const checklistPattern = new RegExp(`-\\s*\\[[ x]\\]\\s*\\*\\*Phase\\s+${escapedPhase}${OPTIONAL_PHASE_TAG_SOURCE}:\\s*([^*]+)\\*\\*`, 'i');
|
|
103
112
|
const checklistMatch = content.match(checklistPattern);
|
|
104
113
|
if (checklistMatch) {
|
|
105
114
|
return {
|
|
@@ -113,14 +122,12 @@ function searchPhaseInContent(content, escapedPhase, phaseNum) {
|
|
|
113
122
|
return null;
|
|
114
123
|
}
|
|
115
124
|
const phaseName = headerMatch[1].trim();
|
|
116
|
-
const headerIndex =
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const sectionEnd =
|
|
122
|
-
? headerIndex + nextHeaderMatch.index
|
|
123
|
-
: content.length;
|
|
125
|
+
const headerIndex = headings[headingIndex].offset;
|
|
126
|
+
const currentHeading = headings[headingIndex];
|
|
127
|
+
const nextHeading = headings
|
|
128
|
+
.slice(headingIndex + 1)
|
|
129
|
+
.find((candidate) => candidate.level <= currentHeading.level);
|
|
130
|
+
const sectionEnd = nextHeading ? nextHeading.offset : content.length;
|
|
124
131
|
const section = content.slice(headerIndex, sectionEnd).trim();
|
|
125
132
|
// Extract goal if present (supports both **Goal:** and **Goal**: formats)
|
|
126
133
|
const goalMatch = section.match(/\*\*Goal(?::\*\*|\*\*:)\s*([^\n]+)/i);
|
|
@@ -159,6 +166,8 @@ function searchPhaseInContent(content, escapedPhase, phaseNum) {
|
|
|
159
166
|
* phase resolution as `roadmap.get-phase` — not a milestone-only subset.
|
|
160
167
|
*/
|
|
161
168
|
function getRoadmapPhaseWithFallback(cwd, phaseNum) {
|
|
169
|
+
if (/^999(?:\.|$)/.test(stripProjectCodePrefix(phaseNum)))
|
|
170
|
+
return null;
|
|
162
171
|
const roadmapPath = planningPaths(cwd).roadmap;
|
|
163
172
|
if (!node_fs_1.default.existsSync(roadmapPath))
|
|
164
173
|
return null;
|
|
@@ -185,6 +194,10 @@ function getRoadmapPhaseWithFallback(cwd, phaseNum) {
|
|
|
185
194
|
}
|
|
186
195
|
// ─── cmdRoadmapGetPhase ───────────────────────────────────────────────────────
|
|
187
196
|
function cmdRoadmapGetPhase(cwd, phaseNum, raw) {
|
|
197
|
+
if (/^999(?:\.|$)/.test(stripProjectCodePrefix(phaseNum))) {
|
|
198
|
+
output({ found: false, phase_number: phaseNum }, raw, '');
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
188
201
|
const roadmapPath = planningPaths(cwd).roadmap;
|
|
189
202
|
if (!node_fs_1.default.existsSync(roadmapPath)) {
|
|
190
203
|
output({ found: false, error: 'ROADMAP.md not found' }, raw, '');
|
|
@@ -249,7 +262,8 @@ function cmdRoadmapAnalyze(cwd, raw) {
|
|
|
249
262
|
const content = extractCurrentMilestone(rawContent, cwd);
|
|
250
263
|
const phasesDir = planningPaths(cwd).phases;
|
|
251
264
|
// Extract all phase headings: ## Phase N: Name or ### Phase N: Name
|
|
252
|
-
|
|
265
|
+
// #1729: `(?:\s*\([^)\n]*\))?` tolerates a pre-colon ( ) tag (literal mirror of OPTIONAL_PHASE_TAG_SOURCE).
|
|
266
|
+
const phasePattern = /#{2,4}\s*(?:\[[^\]]+\]\s*)?Phase\s+(\d+[A-Z]?(?:[.-]\d+)*)(?:\s*\([^)\n]*\))?\s*:\s*([^\n]+)/gi;
|
|
253
267
|
const phases = [];
|
|
254
268
|
let match;
|
|
255
269
|
// Phase 0 (pre-milestone) and Phase 999 (backlog) are sentinels, not real
|
|
@@ -325,7 +339,7 @@ function cmdRoadmapAnalyze(cwd, raw) {
|
|
|
325
339
|
// #3537: padding-tolerant fragment — the heading discovered above may use
|
|
326
340
|
// a different padding than the summary-bullet checkbox below it (mixed
|
|
327
341
|
// padding inside one ROADMAP is legal and seen in real projects).
|
|
328
|
-
const checkboxPattern = new RegExp(`-\\s*\\[(x| )\\]\\s*.*Phase\\s+${phaseMarkdownRegexSource(phaseNum)}[:\\s]`, 'i');
|
|
342
|
+
const checkboxPattern = new RegExp(`-\\s*\\[(x| )\\]\\s*.*Phase\\s+${phaseMarkdownRegexSource(phaseNum)}${OPTIONAL_PHASE_TAG_SOURCE}[:\\s]`, 'i');
|
|
329
343
|
const checkboxMatch = content.match(checkboxPattern);
|
|
330
344
|
const roadmapComplete = checkboxMatch ? checkboxMatch[1] === 'x' : false;
|
|
331
345
|
// If roadmap marks phase complete, trust that over disk file structure.
|
|
@@ -402,12 +416,21 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
402
416
|
error(`Phase ${phaseNum} not found`);
|
|
403
417
|
}
|
|
404
418
|
const planCount = phaseInfo.plans.length;
|
|
405
|
-
|
|
419
|
+
// Count only summaries that pair with a real plan (#1988): stray non-plan
|
|
420
|
+
// summaries (30-FIX-CR02-SUMMARY.md, 30-GAPCLOSURE-SUMMARY.md, …) must not
|
|
421
|
+
// inflate summary_count and silently flip the phase to Complete.
|
|
422
|
+
const summaryCount = countMatchedSummaries(phaseInfo.plans, phaseInfo.summaries);
|
|
406
423
|
if (planCount === 0) {
|
|
407
424
|
output({ updated: false, reason: 'No plans found', plan_count: 0, summary_count: 0 }, raw, 'no plans');
|
|
408
425
|
return;
|
|
409
426
|
}
|
|
410
|
-
|
|
427
|
+
// Verification gate (#2022): do NOT check the phase checkbox or stamp a
|
|
428
|
+
// completion date until the phase's verification status is 'passed', matching
|
|
429
|
+
// cmdPhaseComplete's gate (phase.cts:1436). Previously the checkbox fired the
|
|
430
|
+
// moment the last plan summary landed — before gsd-verifier had verified.
|
|
431
|
+
const phaseDir = node_path_1.default.join(cwd, phaseInfo.directory);
|
|
432
|
+
const verificationPassed = readVerificationStatus(phaseDir).status === 'passed';
|
|
433
|
+
const isComplete = summaryCount >= planCount && verificationPassed;
|
|
411
434
|
const status = isComplete ? 'Complete' : summaryCount > 0 ? 'In Progress' : 'Planned';
|
|
412
435
|
const today = clock_cjs_1.realClock.today();
|
|
413
436
|
if (!node_fs_1.default.existsSync(roadmapPath)) {
|
|
@@ -450,14 +473,14 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
450
473
|
// `**Plans**: N plans` — bold word + outer colon (gsd-core/templates/roadmap.md)
|
|
451
474
|
// `**Plans:** N plans` — bold "Plans:" (colon inside bold)
|
|
452
475
|
// `Plans: N plans` — plain text header
|
|
453
|
-
const planCountPattern = new RegExp(`(#{2,4}\\s*Phase\\s+${phasePattern}(?=[:\\s])[\\s\\S]*?(?:\\*\\*Plans\\*\\*:|\\*\\*Plans:\\*\\*|(?:^|\\n)Plans:)\\s*)[^\\n]+`, 'i');
|
|
476
|
+
const planCountPattern = new RegExp(`(#{2,4}\\s*Phase\\s+${phasePattern}${OPTIONAL_PHASE_TAG_SOURCE}(?=[:\\s])[\\s\\S]*?(?:\\*\\*Plans\\*\\*:|\\*\\*Plans:\\*\\*|(?:^|\\n)Plans:)\\s*)[^\\n]+`, 'i');
|
|
454
477
|
const planCountText = isComplete
|
|
455
478
|
? `${summaryCount}/${planCount} plans complete`
|
|
456
479
|
: `${summaryCount}/${planCount} plans executed`;
|
|
457
480
|
roadmapContent = replaceInCurrentMilestone(roadmapContent, planCountPattern, `$1${planCountText}`);
|
|
458
481
|
// If complete: check checkbox
|
|
459
482
|
if (isComplete) {
|
|
460
|
-
const checkboxPattern = new RegExp(`(-\\s*\\[)[ ](\\]\\s*.*Phase\\s+${phasePattern}[:\\s][^\\n]*)`, 'i');
|
|
483
|
+
const checkboxPattern = new RegExp(`(-\\s*\\[)[ ](\\]\\s*.*Phase\\s+${phasePattern}${OPTIONAL_PHASE_TAG_SOURCE}[:\\s][^\\n]*)`, 'i');
|
|
461
484
|
roadmapContent = replaceInCurrentMilestone(roadmapContent, checkboxPattern, `$1x$2 (completed ${today})`);
|
|
462
485
|
}
|
|
463
486
|
// Mark completed plan checkboxes (e.g. "- [ ] 50-01-PLAN.md", "- [ ] 50-01:", or "- [ ] **50-01**")
|
|
@@ -507,8 +530,8 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
507
530
|
//
|
|
508
531
|
// Pattern A: anchor to bare `Plans:` header (preferred).
|
|
509
532
|
// Pattern B: fallback to bold summary when no bare header exists.
|
|
510
|
-
const insertRowsPatternA = new RegExp(`(#{2,4}\\s*Phase\\s+${phasePattern}(?=[:\\s])[\\s\\S]*?(?:^|\\n)(?:Plans:)[^\\n]*)`, 'i');
|
|
511
|
-
const insertRowsPatternB = new RegExp(`(#{2,4}\\s*Phase\\s+${phasePattern}(?=[:\\s])[\\s\\S]*?(?:\\*\\*Plans\\*\\*:|\\*\\*Plans:\\*\\*)[^\\n]*)`, 'i');
|
|
533
|
+
const insertRowsPatternA = new RegExp(`(#{2,4}\\s*Phase\\s+${phasePattern}${OPTIONAL_PHASE_TAG_SOURCE}(?=[:\\s])[\\s\\S]*?(?:^|\\n)(?:Plans:)[^\\n]*)`, 'i');
|
|
534
|
+
const insertRowsPatternB = new RegExp(`(#{2,4}\\s*Phase\\s+${phasePattern}${OPTIONAL_PHASE_TAG_SOURCE}(?=[:\\s])[\\s\\S]*?(?:\\*\\*Plans\\*\\*:|\\*\\*Plans:\\*\\*)[^\\n]*)`, 'i');
|
|
512
535
|
const sortedMissing = [...missingPlans].sort();
|
|
513
536
|
const newRows = sortedMissing.map(p => `- [ ] ${p}`).join('\n');
|
|
514
537
|
const inserter = (match) => `${match}\n${newRows}`;
|
|
@@ -645,7 +668,7 @@ function cmdRoadmapAnnotateDependencies(cwd, phaseNum, raw) {
|
|
|
645
668
|
// #3537: padding-tolerant fragment so the caller's resolved padded id
|
|
646
669
|
// matches un-padded ROADMAP headings.
|
|
647
670
|
const phaseEscaped = phaseMarkdownRegexSource(phaseNum);
|
|
648
|
-
const phaseHeaderPattern = new RegExp(`(#{2,4}\\s*Phase\\s+${phaseEscaped}:[^\\n]*)`, 'i');
|
|
671
|
+
const phaseHeaderPattern = new RegExp(`(#{2,4}\\s*Phase\\s+${phaseEscaped}${OPTIONAL_PHASE_TAG_SOURCE}:[^\\n]*)`, 'i');
|
|
649
672
|
const phaseMatch = content.match(phaseHeaderPattern);
|
|
650
673
|
if (!phaseMatch)
|
|
651
674
|
return;
|
|
@@ -1039,7 +1039,7 @@ function applySettingsJsonHooks(settings, opts) {
|
|
|
1039
1039
|
// Configure PreToolUse hook for prompt injection detection
|
|
1040
1040
|
// ADR-857 phase 5f-2: drive dialect from opts.hookEvents (registry descriptor).
|
|
1041
1041
|
// hookEvents='gemini' → BeforeTool; all others → PreToolUse.
|
|
1042
|
-
// Equivalence: hookEvents='gemini' iff runtime
|
|
1042
|
+
// Equivalence: hookEvents='gemini' iff runtime===antigravity (same as old check).
|
|
1043
1043
|
const preToolEvent = hookEvents === 'gemini' ? 'BeforeTool' : 'PreToolUse';
|
|
1044
1044
|
if (!settings.hooks[preToolEvent]) {
|
|
1045
1045
|
settings.hooks[preToolEvent] = [];
|
|
@@ -1312,9 +1312,14 @@ function applySettingsJsonHooks(settings, opts) {
|
|
|
1312
1312
|
}
|
|
1313
1313
|
}
|
|
1314
1314
|
// ── end SubagentStop / Stop / PreCompact events ────────────────────────────
|
|
1315
|
-
// ──
|
|
1316
|
-
// Gemini
|
|
1317
|
-
//
|
|
1315
|
+
// ── Extended hook events (#776; Gemini runtime removed #1928) ──────────────
|
|
1316
|
+
// The Gemini-3-backend dialect exposes several hook events beyond
|
|
1317
|
+
// BeforeTool/AfterTool. These were added for the now-removed Gemini CLI
|
|
1318
|
+
// runtime (#776). No currently supported runtime declares them —
|
|
1319
|
+
// Antigravity's descriptor carries `extendedHookEvents: []` — so this loop
|
|
1320
|
+
// is an inert, descriptor-driven seam: it no-ops for every present runtime
|
|
1321
|
+
// and re-activates automatically if a future runtime declares any of them.
|
|
1322
|
+
// Three high-value events would be wired here:
|
|
1318
1323
|
//
|
|
1319
1324
|
// BeforeAgent — fires after user submits a prompt, before the agent
|
|
1320
1325
|
// plans. Wire gsd-context-monitor for context headroom
|
|
@@ -1335,15 +1340,15 @@ function applySettingsJsonHooks(settings, opts) {
|
|
|
1335
1340
|
// gsd hook use case at this time; deferred to a follow-on issue.
|
|
1336
1341
|
//
|
|
1337
1342
|
// Guard is now descriptor-driven: only events present in extendedEvents are wired.
|
|
1338
|
-
for (const
|
|
1339
|
-
if (!extendedEvents.includes(
|
|
1343
|
+
for (const extendedEvent of ['BeforeAgent', 'AfterAgent', 'BeforeModel']) {
|
|
1344
|
+
if (!extendedEvents.includes(extendedEvent))
|
|
1340
1345
|
continue;
|
|
1341
|
-
if (!Array.isArray(settings.hooks[
|
|
1342
|
-
settings.hooks[
|
|
1346
|
+
if (!Array.isArray(settings.hooks[extendedEvent])) {
|
|
1347
|
+
settings.hooks[extendedEvent] = [];
|
|
1343
1348
|
}
|
|
1344
|
-
const alreadyHasContextMonitor = settings.hooks[
|
|
1349
|
+
const alreadyHasContextMonitor = settings.hooks[extendedEvent].some((entry) => entry.hooks && entry.hooks.some((h) => referencesHook(h, 'gsd-context-monitor')));
|
|
1345
1350
|
if (!alreadyHasContextMonitor && node_fs_1.default.existsSync(contextMonitorFile) && contextMonitorCommand) {
|
|
1346
|
-
settings.hooks[
|
|
1351
|
+
settings.hooks[extendedEvent].push({
|
|
1347
1352
|
hooks: [
|
|
1348
1353
|
{
|
|
1349
1354
|
type: 'command',
|
|
@@ -1352,13 +1357,13 @@ function applySettingsJsonHooks(settings, opts) {
|
|
|
1352
1357
|
}
|
|
1353
1358
|
]
|
|
1354
1359
|
});
|
|
1355
|
-
console.log(` ${green}✓${reset} Configured ${
|
|
1360
|
+
console.log(` ${green}✓${reset} Configured ${extendedEvent} context monitor hook`);
|
|
1356
1361
|
}
|
|
1357
1362
|
else if (!alreadyHasContextMonitor && !node_fs_1.default.existsSync(contextMonitorFile)) {
|
|
1358
|
-
console.warn(` ${yellow}⚠${reset} Skipped ${
|
|
1363
|
+
console.warn(` ${yellow}⚠${reset} Skipped ${extendedEvent} hook — gsd-context-monitor.js not found at target`);
|
|
1359
1364
|
}
|
|
1360
1365
|
}
|
|
1361
|
-
// ── end
|
|
1366
|
+
// ── end Antigravity-only extended hook events ──────────────────────────────
|
|
1362
1367
|
// ── FileChanged hook: hot-reload gsd config on .planning/config.json edits ─
|
|
1363
1368
|
// Claude Code fires FileChanged when a watched file changes on disk. Wire
|
|
1364
1369
|
// gsd-config-reload.js to reload the gsd config context whenever the user
|
|
@@ -29,7 +29,6 @@ const FALLBACK_ALIASES = {
|
|
|
29
29
|
claude: ['claude', 'claude-code', 'claude-cli'],
|
|
30
30
|
opencode: ['opencode', 'open-code', 'opencode-cli'],
|
|
31
31
|
kilo: ['kilo', 'kilo-cli'],
|
|
32
|
-
gemini: ['gemini', 'gemini-cli', 'gemini-code'],
|
|
33
32
|
codex: ['codex', 'codex-app', 'codex-cli', 'codex_desktop', 'codex-desktop'],
|
|
34
33
|
copilot: ['copilot', 'copilot-cli', 'github-copilot'],
|
|
35
34
|
antigravity: ['antigravity', 'antigravity-cli', 'antigravity-agent'],
|
|
@@ -114,7 +113,7 @@ function resolveRuntimeNameFromCandidates(...candidates) {
|
|
|
114
113
|
* claude → .claude/CLAUDE.md
|
|
115
114
|
* codex, opencode, kilo, kimi → AGENTS.md
|
|
116
115
|
* copilot → .github/copilot-instructions.md
|
|
117
|
-
* antigravity
|
|
116
|
+
* antigravity → GEMINI.md
|
|
118
117
|
* unknown / future runtimes → AGENTS.md (safe cross-agent default)
|
|
119
118
|
*
|
|
120
119
|
* Source-of-truth references for each runtime's read path:
|
|
@@ -126,7 +125,9 @@ function resolveRuntimeNameFromCandidates(...candidates) {
|
|
|
126
125
|
* 'copilot-instructions' writes the same `.github/copilot-instructions.md`.)
|
|
127
126
|
* - codex/opencode/kilo/kimi: AGENTS.md is the documented cross-agent
|
|
128
127
|
* instruction file (agentsmd/agents.md convention).
|
|
129
|
-
* - antigravity
|
|
128
|
+
* - antigravity: GEMINI.md is Antigravity CLI's contextFileName (the Gemini
|
|
129
|
+
* CLI runtime that historically shared this file was removed — #1928;
|
|
130
|
+
* Google sunset Gemini CLI 2026-06-18 and Antigravity CLI is its successor).
|
|
130
131
|
*
|
|
131
132
|
* Aliases are normalized via `canonicalizeRuntimeName` first, so inputs like
|
|
132
133
|
* `codex-cli` resolve to `codex` → `AGENTS.md`. Replaces the prior codex-only
|
|
@@ -139,7 +140,7 @@ function getProjectInstructionFile(runtime) {
|
|
|
139
140
|
return '.claude/CLAUDE.md';
|
|
140
141
|
if (canonical === 'copilot')
|
|
141
142
|
return '.github/copilot-instructions.md';
|
|
142
|
-
if (canonical === 'antigravity'
|
|
143
|
+
if (canonical === 'antigravity')
|
|
143
144
|
return 'GEMINI.md';
|
|
144
145
|
// codex, opencode, kilo, kimi, AND unknown/future runtimes all default to
|
|
145
146
|
// root AGENTS.md (the safe cross-agent instruction file).
|
|
@@ -180,7 +181,7 @@ function getDirName(runtime) {
|
|
|
180
181
|
*
|
|
181
182
|
* Voice: these are the SHORT UI labels, intentionally distinct from the
|
|
182
183
|
* descriptor `title` (the long product name — e.g. "OpenAI Codex CLI",
|
|
183
|
-
* "GitHub Copilot"
|
|
184
|
+
* "GitHub Copilot") which serves documentation/registry display,
|
|
184
185
|
* not the install console. A future slice may relocate this to a
|
|
185
186
|
* `runtime.label` descriptor field; until then this table is the source.
|
|
186
187
|
*
|
|
@@ -195,7 +196,6 @@ function getDirName(runtime) {
|
|
|
195
196
|
const RUNTIME_LABELS = {
|
|
196
197
|
claude: 'Claude Code',
|
|
197
198
|
opencode: 'OpenCode',
|
|
198
|
-
gemini: 'Gemini',
|
|
199
199
|
kilo: 'Kilo',
|
|
200
200
|
codex: 'Codex',
|
|
201
201
|
copilot: 'Copilot',
|
|
@@ -231,7 +231,7 @@ function getRuntimeLabel(runtime) {
|
|
|
231
231
|
* bin/install.js (ADR-1239 Phase B / #1679, AC2 slice 2) — the add-a-host tax:
|
|
232
232
|
* a new runtime meant remembering to add a branch here. Values are preserved
|
|
233
233
|
* BYTE-FOR-BYTE from the prior chain; golden install parity asserts generated
|
|
234
|
-
* hook output is unchanged across all
|
|
234
|
+
* hook output is unchanged across all 15 runtimes.
|
|
235
235
|
*
|
|
236
236
|
* Two runtimes are intentionally absent (handled by the caller, NOT this table):
|
|
237
237
|
* - `claude` → the default; falls through to `DEFAULT_FRAGMENT`.
|
|
@@ -244,7 +244,6 @@ const DEFAULT_CONFIG_HOME_FRAGMENT = "'.claude'";
|
|
|
244
244
|
const GLOBAL_CONFIG_HOME_FRAGMENTS = {
|
|
245
245
|
copilot: "'.copilot'",
|
|
246
246
|
opencode: "'.config', 'opencode'",
|
|
247
|
-
gemini: "'.gemini'",
|
|
248
247
|
kilo: "'.config', 'kilo'",
|
|
249
248
|
codex: "'.codex'",
|
|
250
249
|
cursor: "'.cursor'",
|
|
@@ -277,7 +276,7 @@ function getGlobalConfigHomeFragment(runtime) {
|
|
|
277
276
|
* removes).
|
|
278
277
|
*/
|
|
279
278
|
const RUNTIME_FLAG_IDS = Object.freeze([
|
|
280
|
-
'opencode', 'kilo', '
|
|
279
|
+
'opencode', 'kilo', 'codex', 'copilot', 'antigravity', 'cursor',
|
|
281
280
|
'windsurf', 'augment', 'trae', 'qwen', 'hermes', 'codebuddy', 'cline', 'kimi',
|
|
282
281
|
]);
|
|
283
282
|
/**
|
|
@@ -303,7 +302,6 @@ function runtimeFlags(runtime) {
|
|
|
303
302
|
*/
|
|
304
303
|
const DEFAULT_NEW_PROJECT_COMMAND = '/gsd-new-project';
|
|
305
304
|
const RUNTIME_NEW_PROJECT_COMMANDS = {
|
|
306
|
-
gemini: '/gsd:new-project',
|
|
307
305
|
codex: '$gsd-new-project',
|
|
308
306
|
cursor: 'gsd-new-project (mention the skill name)',
|
|
309
307
|
kimi: '/skill:gsd-new-project',
|
|
@@ -56,16 +56,20 @@ const node_child_process_1 = __importDefault(require("node:child_process"));
|
|
|
56
56
|
* runtime/shell combination.
|
|
57
57
|
*
|
|
58
58
|
* Current evidence-backed policy:
|
|
59
|
-
* -
|
|
60
|
-
*
|
|
61
|
-
*
|
|
59
|
+
* - Claude Code on Windows does NOT need it: its hook commands execute under
|
|
60
|
+
* bash/Git Bash and `& ` breaks there (#3413).
|
|
61
|
+
* - #1928: Gemini CLI — the ONLY runtime with a verified need for the `& `
|
|
62
|
+
* prefix on Windows — was removed (Google sunset it 2026-06-18). No currently
|
|
63
|
+
* supported runtime has a verified need, so this seam is now inert. It is
|
|
64
|
+
* retained (not deleted) so a future runtime with a verified need is a
|
|
65
|
+
* one-line re-enable, per the conservative policy below. Note: Antigravity —
|
|
66
|
+
* the Gemini-backend successor — never matched the old `runtime === 'gemini'`
|
|
67
|
+
* check, so its behavior (no prefix) is unchanged.
|
|
62
68
|
*
|
|
63
69
|
* Keep the policy conservative until another runtime has a verified need.
|
|
64
70
|
*/
|
|
65
|
-
function hookCommandNeedsPowerShellCallOperator(
|
|
66
|
-
|
|
67
|
-
const runtime = opts.runtime || 'generic';
|
|
68
|
-
return platform === 'win32' && runtime === 'gemini';
|
|
71
|
+
function hookCommandNeedsPowerShellCallOperator(_opts = {}) {
|
|
72
|
+
return false;
|
|
69
73
|
}
|
|
70
74
|
/**
|
|
71
75
|
* Project a fully-assembled hook command string for the target runtime.
|
|
@@ -121,7 +125,7 @@ function formatManagedHookScriptToken(scriptPath, opts = {}) {
|
|
|
121
125
|
function projectLocalHookPrefix({ runtime = 'claude', dirName }) {
|
|
122
126
|
if (!dirName)
|
|
123
127
|
return dirName;
|
|
124
|
-
return (runtime === '
|
|
128
|
+
return (runtime === 'antigravity')
|
|
125
129
|
? dirName
|
|
126
130
|
: `"$CLAUDE_PROJECT_DIR"/${dirName}`;
|
|
127
131
|
}
|