@opengsd/gsd-core 1.12.0 → 1.13.0
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 +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +12 -0
- package/agents/gsd-executor.md +63 -35
- package/agents/gsd-plan-checker.md +76 -57
- package/agents/gsd-planner.md +14 -0
- package/agents/gsd-ui-checker.md +19 -3
- package/agents/gsd-ui-researcher.md +29 -0
- package/agents/gsd-verifier.md +23 -1
- package/bin/install.js +239 -67
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/ns-workflow.md +2 -1
- package/commands/gsd/phase.md +1 -1
- package/commands/gsd/quick-batch.md +105 -0
- package/commands/gsd/surface.md +18 -8
- package/gsd-core/bin/gsd-tools.cjs +195 -50
- package/gsd-core/bin/lib/capability-activation.cjs +27 -0
- package/gsd-core/bin/lib/capability-registry.cjs +514 -114
- package/gsd-core/bin/lib/capability-state.cjs +7 -1
- package/gsd-core/bin/lib/capability-validator.cjs +120 -4
- package/gsd-core/bin/lib/capability-writer.cjs +14 -4
- package/gsd-core/bin/lib/check-command-router.cjs +85 -2
- package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
- package/gsd-core/bin/lib/clusters.cjs +1 -0
- package/gsd-core/bin/lib/command-aliases.cjs +16 -0
- package/gsd-core/bin/lib/commands.cjs +337 -13
- package/gsd-core/bin/lib/config-loader.cjs +3 -0
- package/gsd-core/bin/lib/core-utils.cjs +34 -7
- package/gsd-core/bin/lib/decisions.cjs +213 -1
- package/gsd-core/bin/lib/edge-probe.cjs +14 -1
- package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
- package/gsd-core/bin/lib/frontmatter.cjs +137 -23
- package/gsd-core/bin/lib/gap-checker.cjs +22 -13
- package/gsd-core/bin/lib/git-base-branch.cjs +10 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +54 -11
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
- package/gsd-core/bin/lib/host-integration.cjs +57 -5
- package/gsd-core/bin/lib/init-command-router.cjs +14 -0
- package/gsd-core/bin/lib/init.cjs +132 -15
- package/gsd-core/bin/lib/install-engine.cjs +184 -12
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +45 -0
- package/gsd-core/bin/lib/install-profiles.cjs +22 -14
- package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
- package/gsd-core/bin/lib/io.cjs +35 -0
- package/gsd-core/bin/lib/loop-resolver.cjs +14 -8
- package/gsd-core/bin/lib/markdown-table.cjs +123 -0
- package/gsd-core/bin/lib/milestone.cjs +22 -2
- package/gsd-core/bin/lib/phase-command-router.cjs +13 -6
- package/gsd-core/bin/lib/phase-id.cjs +251 -9
- package/gsd-core/bin/lib/phase.cjs +774 -35
- package/gsd-core/bin/lib/plan-document.cjs +10 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +147 -20
- package/gsd-core/bin/lib/planning-workspace.cjs +103 -28
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
- package/gsd-core/bin/lib/quick-batch.cjs +840 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +53 -5
- package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
- package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
- package/gsd-core/bin/lib/roadmap-parser.cjs +499 -26
- package/gsd-core/bin/lib/roadmap.cjs +187 -58
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +233 -33
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +286 -108
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +215 -43
- package/gsd-core/bin/lib/shell-command-projection.cjs +4 -0
- package/gsd-core/bin/lib/smart-entry.cjs +7 -9
- package/gsd-core/bin/lib/state-document.cjs +30 -5
- package/gsd-core/bin/lib/state-md-schema.cjs +23 -13
- package/gsd-core/bin/lib/state-transition.cjs +333 -44
- package/gsd-core/bin/lib/state.cjs +684 -125
- package/gsd-core/bin/lib/surface.cjs +23 -8
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
- package/gsd-core/bin/lib/uat.cjs +1419 -515
- package/gsd-core/bin/lib/update-context.cjs +6 -2
- package/gsd-core/bin/lib/validate.cjs +230 -12
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +273 -12
- package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
- package/gsd-core/bin/lib/verify.cjs +346 -16
- package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
- package/gsd-core/bin/lib/worktree-safety.cjs +8 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +8 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +70 -3
- package/gsd-core/references/agent-contracts.md +3 -3
- package/gsd-core/references/edge-probe.md +17 -13
- package/gsd-core/references/execute-mvp-tdd.md +18 -16
- package/gsd-core/references/execute-phase-response-language.md +6 -0
- package/gsd-core/references/executor-examples.md +42 -0
- package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
- package/gsd-core/references/mvp-concepts.md +2 -2
- package/gsd-core/references/plan-checker-examples.md +41 -0
- package/gsd-core/references/planner-antipatterns.md +25 -0
- package/gsd-core/references/planner-chunked.md +5 -1
- package/gsd-core/references/planner-coupling.md +42 -0
- package/gsd-core/references/planner-quick-batch.md +71 -0
- package/gsd-core/references/planner-reviews.md +47 -0
- package/gsd-core/references/planner-revision.md +75 -2
- package/gsd-core/references/planning-config.md +2 -1
- package/gsd-core/references/response-language-directive.md +9 -0
- package/gsd-core/references/revision-loop.md +118 -11
- package/gsd-core/references/tdd.md +14 -9
- package/gsd-core/references/verifier-evidence-gate.md +160 -0
- package/gsd-core/templates/phase-prompt.md +4 -0
- package/gsd-core/templates/verification-report.md +5 -0
- package/gsd-core/workflows/add-backlog.md +2 -0
- package/gsd-core/workflows/add-phase.md +2 -0
- 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/analyze-dependencies.md +2 -0
- package/gsd-core/workflows/audit-fix.md +2 -0
- package/gsd-core/workflows/audit-milestone.md +2 -0
- package/gsd-core/workflows/audit-uat.md +2 -0
- package/gsd-core/workflows/autonomous.md +2 -0
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +1 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +15 -13
- package/gsd-core/workflows/code-review-fix.md +2 -0
- package/gsd-core/workflows/code-review.md +73 -31
- package/gsd-core/workflows/complete-milestone.md +13 -4
- package/gsd-core/workflows/debug.md +1 -1
- package/gsd-core/workflows/diagnose-issues.md +5 -1
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/text.md +2 -0
- package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
- package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
- package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
- package/gsd-core/workflows/discuss-phase-power.md +2 -0
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +43 -13
- package/gsd-core/workflows/docs-update.md +1 -1
- package/gsd-core/workflows/edit-phase.md +2 -0
- package/gsd-core/workflows/eval-review.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +17 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +8 -2
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
- package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
- package/gsd-core/workflows/execute-phase.md +32 -14
- package/gsd-core/workflows/execute-plan.md +8 -8
- package/gsd-core/workflows/explore.md +2 -0
- package/gsd-core/workflows/extract-learnings.md +2 -0
- package/gsd-core/workflows/fast.md +6 -0
- package/gsd-core/workflows/forensics.md +2 -0
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +1 -1
- package/gsd-core/workflows/help/modes/brief.md +2 -0
- package/gsd-core/workflows/help/modes/default.md +2 -0
- package/gsd-core/workflows/help/modes/full.md +12 -0
- package/gsd-core/workflows/help/modes/topic.md +2 -0
- package/gsd-core/workflows/help.md +2 -0
- package/gsd-core/workflows/import.md +3 -3
- package/gsd-core/workflows/inbox.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- package/gsd-core/workflows/insert-phase.md +2 -0
- package/gsd-core/workflows/list-phase-assumptions.md +2 -0
- package/gsd-core/workflows/list-seeds.md +2 -0
- package/gsd-core/workflows/list-workspaces.md +2 -0
- package/gsd-core/workflows/manager.md +3 -3
- package/gsd-core/workflows/map-codebase.md +2 -0
- package/gsd-core/workflows/milestone-summary.md +2 -0
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +1 -1
- package/gsd-core/workflows/new-project.md +5 -3
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +2 -0
- package/gsd-core/workflows/node-repair.md +2 -0
- package/gsd-core/workflows/note.md +2 -0
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +19 -4
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -0
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +9 -0
- package/gsd-core/workflows/plan-phase.md +130 -12
- package/gsd-core/workflows/plan-review-convergence.md +102 -10
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +11 -3
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
- package/gsd-core/workflows/progress.md +25 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +37 -2
- package/gsd-core/workflows/quick/steps/research-phase.md +3 -3
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
- package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
- package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
- package/gsd-core/workflows/quick-batch.md +203 -0
- package/gsd-core/workflows/quick.md +13 -3
- package/gsd-core/workflows/reapply-patches.md +2 -0
- package/gsd-core/workflows/remove-phase.md +2 -0
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +6 -2
- package/gsd-core/workflows/review.md +215 -10
- package/gsd-core/workflows/scan.md +2 -0
- package/gsd-core/workflows/section-manifest.json +12 -0
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/session-report.md +2 -0
- package/gsd-core/workflows/settings-advanced.md +2 -0
- package/gsd-core/workflows/settings-integrations.md +9 -8
- package/gsd-core/workflows/settings.md +1 -1
- package/gsd-core/workflows/ship.md +10 -10
- package/gsd-core/workflows/sketch-wrap-up.md +2 -0
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +1 -1
- package/gsd-core/workflows/spec-phase.md +24 -19
- package/gsd-core/workflows/spike-wrap-up.md +2 -0
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +2 -0
- package/gsd-core/workflows/sync-skills.md +12 -4
- package/gsd-core/workflows/thread.md +2 -0
- package/gsd-core/workflows/transition.md +2 -0
- package/gsd-core/workflows/ui-phase.md +26 -5
- package/gsd-core/workflows/ui-review.md +1 -1
- package/gsd-core/workflows/ultraplan-phase.md +2 -0
- package/gsd-core/workflows/undo.md +1 -1
- package/gsd-core/workflows/update.md +41 -38
- package/gsd-core/workflows/validate-phase.md +1 -1
- package/gsd-core/workflows/verify-work.md +49 -3
- package/hooks/dist/gsd-check-update-worker.js +19 -2
- package/hooks/dist/gsd-context-monitor.js +283 -12
- package/hooks/dist/gsd-node-runner.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +30 -5
- package/hooks/dist/gsd-read-guard.js +2 -0
- package/hooks/dist/gsd-read-injection-scanner.js +5 -5
- package/hooks/dist/gsd-secret-read-guard.js +1079 -0
- package/hooks/dist/gsd-statusline.js +7 -3
- package/hooks/dist/gsd-validate-commit.sh +444 -7
- package/hooks/dist/gsd-workflow-guard.js +2 -1
- package/hooks/dist/lib/git-cmd.js +210 -1
- package/hooks/dist/lib/injection-patterns.js +36 -6
- package/hooks/dist/managed-hooks-registry.cjs +1 -0
- package/hooks/gsd-check-update-worker.js +19 -2
- package/hooks/gsd-context-monitor.js +283 -12
- package/hooks/gsd-node-runner.sh +1 -0
- package/hooks/gsd-prompt-guard.js +30 -5
- package/hooks/gsd-read-guard.js +2 -0
- package/hooks/gsd-read-injection-scanner.js +5 -5
- package/hooks/gsd-secret-read-guard.js +1079 -0
- package/hooks/gsd-statusline.js +7 -3
- package/hooks/gsd-validate-commit.sh +444 -7
- package/hooks/gsd-workflow-guard.js +2 -1
- package/hooks/hooks.json +6 -0
- package/hooks/lib/git-cmd.js +210 -1
- package/hooks/lib/injection-patterns.js +36 -6
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +5 -5
- package/scripts/build-hooks.js +11 -4
- package/scripts/ci-test-scope.cjs +7 -0
- package/scripts/docs-guard-registry.cjs +10 -0
- package/scripts/gen-loop-host-contract.cjs +67 -15
- package/scripts/lib/shellcheck-fetch.cjs +247 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +5 -0
- package/scripts/lint-phase-enumeration-drift.cjs +24 -6
- package/scripts/lint-phase-id-drift.cjs +133 -8
- package/scripts/lint-portable-grep.cjs +176 -0
- package/scripts/lint-response-language-coverage.cjs +524 -0
- package/scripts/lint-test-file-count.allowlist.json +3 -1
- package/scripts/lint-workflow-shellcheck-baseline.json +1027 -0
- package/scripts/lint-workflow-shellcheck.cjs +614 -0
- package/scripts/npm-audit-baseline.cjs +376 -0
- package/scripts/prompt-injection-scan.sh +8 -0
- package/scripts/require-issue-link-policy.cjs +16 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -1
- package/skills/gsd-ns-workflow/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -1
- package/skills/gsd-quick-batch/SKILL.md +105 -0
- package/skills/gsd-surface/SKILL.md +18 -8
- package/vscode/package.json +1 -1
|
@@ -150,6 +150,18 @@
|
|
|
150
150
|
"read": "gsd-core/workflows/progress/steps/forensic-audit.md"
|
|
151
151
|
}
|
|
152
152
|
],
|
|
153
|
+
"quick-batch": [
|
|
154
|
+
{
|
|
155
|
+
"id": "research-phase",
|
|
156
|
+
"when": "flag:--research",
|
|
157
|
+
"read": "gsd-core/workflows/quick-batch/steps/research-phase.md"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"id": "verification-wave",
|
|
161
|
+
"when": "flag:--validate",
|
|
162
|
+
"read": "gsd-core/workflows/quick-batch/steps/verification-wave.md"
|
|
163
|
+
}
|
|
164
|
+
],
|
|
153
165
|
"quick": [
|
|
154
166
|
{
|
|
155
167
|
"id": "discussion-phase",
|
|
@@ -23,7 +23,7 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
|
23
23
|
AGENT_SKILLS_AUDITOR=$(gsd_run query agent-skills gsd-security-auditor)
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
26
|
+
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
27
27
|
|
|
28
28
|
Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`.
|
|
29
29
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@~/.claude/gsd-core/references/response-language-directive.md
|
|
2
|
+
|
|
1
3
|
<purpose>
|
|
2
4
|
Generate a post-session summary document capturing work performed, outcomes achieved, and estimated resource usage. Writes SESSION_REPORT.md to .planning/reports/ for human review and stakeholder sharing.
|
|
3
5
|
</purpose>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
|
|
2
|
+
|
|
1
3
|
<purpose>
|
|
2
4
|
Interactive configuration of GSD power-user knobs — plan bounce, node repair, subagent timeouts,
|
|
3
5
|
inline plan threshold, cross-AI execution, base branch, branch templates, response language,
|
|
@@ -60,7 +60,7 @@ if [[ -z "${GSD_CONFIG_PATH:-}" ]]; then
|
|
|
60
60
|
fi
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
63
|
+
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
64
64
|
|
|
65
65
|
Store `$GSD_CONFIG_PATH`. Every subsequent read/write uses it.
|
|
66
66
|
</step>
|
|
@@ -163,12 +163,13 @@ namespace — any other slug fails with `Unknown config key`.
|
|
|
163
163
|
Settable keys (the shipped registry's model-bearing lanes):
|
|
164
164
|
|
|
165
165
|
`review.models.agy` (Antigravity), `review.models.claude`, `review.models.codex`,
|
|
166
|
-
`review.models.
|
|
167
|
-
`review.models.
|
|
166
|
+
`review.models.cursor`, `review.models.gemini`, `review.models.kimi-code`,
|
|
167
|
+
`review.models.llama_cpp`, `review.models.lm_studio`, `review.models.ollama`,
|
|
168
|
+
`review.models.opencode`.
|
|
168
169
|
|
|
169
|
-
Reviewer lanes `
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
Reviewer lanes `qwen` and `coderabbit` declare no `modelConfigKey` — there is
|
|
171
|
+
nothing to configure for them here (whether they should have a per-lane model
|
|
172
|
+
key is a separate question, out of scope for this workflow).
|
|
172
173
|
If the user asks for one of those, say exactly that and skip.
|
|
173
174
|
|
|
174
175
|
```text
|
|
@@ -208,8 +209,8 @@ If it is not one of the settable keys, print:
|
|
|
208
209
|
|
|
209
210
|
```text
|
|
210
211
|
Rejected: review.models.<slug> is not settable — only the reviewer lanes whose
|
|
211
|
-
keys are enumerated above can be configured here. (
|
|
212
|
-
|
|
212
|
+
keys are enumerated above can be configured here. (qwen and coderabbit have no
|
|
213
|
+
per-lane model key.)
|
|
213
214
|
```
|
|
214
215
|
|
|
215
216
|
and re-prompt.
|
|
@@ -28,7 +28,7 @@ if [[ -z "${GSD_CONFIG_PATH:-}" ]]; then
|
|
|
28
28
|
fi
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
31
|
+
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
32
32
|
|
|
33
33
|
Creates `config.json` (at the resolved path) with defaults if missing. `INIT` still holds `state.load` output for any step that needs STATE fields.
|
|
34
34
|
Store `$GSD_CONFIG_PATH` — all subsequent reads and writes use this path, not a hardcoded `.planning/config.json`, so active-workstream installs target the correct file (#2282).
|
|
@@ -30,7 +30,7 @@ INIT=$(gsd_run query init.phase-op "${PHASE_ARG}")
|
|
|
30
30
|
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
33
|
+
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
34
34
|
|
|
35
35
|
Parse from init JSON: `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `padded_phase`, `commit_docs`.
|
|
36
36
|
|
|
@@ -309,16 +309,16 @@ Example configured sections:
|
|
|
309
309
|
|
|
310
310
|
**8. TDD Audit section:**
|
|
311
311
|
|
|
312
|
-
Reconstruct the per-commit TDD gate trail before squash-merge discards it. Walk the PR branch's own commits (merges excluded) and read each commit's `
|
|
312
|
+
Reconstruct the per-commit TDD gate trail before squash-merge discards it. Walk the PR branch's own commits (merges excluded) and read each commit's `gate-status:` trailer with Git's native trailer machinery — never a raw `%B` grep, which would also match the string written in prose:
|
|
313
313
|
|
|
314
314
|
```bash
|
|
315
315
|
# Anchor on the merge-base so a stale local ${BASE_BRANCH} ref cannot over-count.
|
|
316
316
|
RANGE_BASE=$(git merge-base "${BASE_BRANCH}" HEAD)
|
|
317
317
|
git log "${RANGE_BASE}..HEAD" --no-merges --reverse \
|
|
318
|
-
--format='%H%x1f%s%x1f%(trailers:key=
|
|
318
|
+
--format='%H%x1f%s%x1f%(trailers:key=gate-status,valueonly,separator=%x2c)%x1e'
|
|
319
319
|
```
|
|
320
320
|
|
|
321
|
-
Records are separated by `\x1e`; the fields inside each are `\x1f`-separated — `<sha>`, `<subject>`, `<
|
|
321
|
+
Records are separated by `\x1e`; the fields inside each are `\x1f`-separated — `<sha>`, `<subject>`, `<gate-status value>`.
|
|
322
322
|
|
|
323
323
|
Pair commits by their conventional-commit type (the `type:` prefix of the subject):
|
|
324
324
|
|
|
@@ -326,16 +326,16 @@ Pair commits by their conventional-commit type (the `type:` prefix of the subjec
|
|
|
326
326
|
- A `refactor:`, `docs:`, or `chore:` commit that is not consumed as an Impl pairing is a standalone row with Impl commit `—`.
|
|
327
327
|
- A `feat:`/`fix:` commit with no preceding unpaired `test:` is a standalone row.
|
|
328
328
|
|
|
329
|
-
Surface each commit's `
|
|
329
|
+
Surface each commit's `gate-status:` value, normalized to exactly one of `skill`, `fallback`, `exempt`, or `missing` — never the raw trailer text. A commit whose trailer is absent, whose value is none of the first three, or which carries more than one `gate-status:` trailer (ambiguous) is counted as **missing** and still listed. This section is informational; it never blocks the ship.
|
|
330
330
|
|
|
331
|
-
**Self-suppress when every commit is missing (#2431):** the execute pipeline only writes `
|
|
331
|
+
**Self-suppress when every commit is missing (#2431):** the execute pipeline only writes `gate-status:` trailers when TDD mode is active. If every commit in the scan normalizes to `missing`, skip this section and the aggregate trailer (step 9) entirely — a 100%-missing table is pure noise. Only emit when at least one commit carries a real value (`skill`, `fallback`, or `exempt`).
|
|
332
332
|
|
|
333
|
-
Harden every table cell against injection, not just subjects: escape `|` as `\|` and strip `\r`/`\n` from both commit subjects and the rendered `
|
|
333
|
+
Harden every table cell against injection, not just subjects: escape `|` as `\|` and strip `\r`/`\n` from both commit subjects and the rendered `gate-status` value. Prefer NUL (`-z` / `%x00`) record separation, and reject any record whose fields contain the `\x1f`/`\x1e` delimiters, so an adversarial commit message cannot corrupt record or field boundaries.
|
|
334
334
|
|
|
335
335
|
```markdown
|
|
336
336
|
## TDD Audit
|
|
337
337
|
|
|
338
|
-
| Test commit | Impl commit |
|
|
338
|
+
| Test commit | Impl commit | gate-status |
|
|
339
339
|
|---|---|---|
|
|
340
340
|
| `a1b2c3d` test: failing parser test | `e4f5g6h` feat: implement parser | skill |
|
|
341
341
|
| `i7j8k9l` test: failing export test | `m0n1o2p` feat: implement export | fallback |
|
|
@@ -346,12 +346,12 @@ Aggregate: 2 skill, 1 fallback, 1 exempt — 0 missing.
|
|
|
346
346
|
|
|
347
347
|
This `## TDD Audit` section is the final body section — it renders after the configured `pr_body_sections`, immediately before the aggregate trailer — so the frozen core sections and the append-only configured sections both keep their existing order.
|
|
348
348
|
|
|
349
|
-
**9. Aggregate
|
|
349
|
+
**9. Aggregate gate-status trailer (final line)** (only when step 8 was emitted — i.e., at least one real `gate-status` value exists):
|
|
350
350
|
|
|
351
351
|
After every other section — including any configured `pr_body_sections` — emit the audit aggregate as a single Git trailer on the **final line** of the PR body, preceded by a blank line so it parses as a valid trailer:
|
|
352
352
|
|
|
353
353
|
```
|
|
354
|
-
|
|
354
|
+
gate-status: skill=2, fallback=1, exempt=1, missing=0
|
|
355
355
|
```
|
|
356
356
|
|
|
357
357
|
Use the exact key order `skill=`, `fallback=`, `exempt=`, `missing=` so downstream tooling parses it stably. Keeping it last means a GitHub squash-merge that defaults its commit message to the PR description carries the aggregate into `${BASE_BRANCH}`, preserving the audit footprint in `git log` after the PR branch is deleted. (Best-effort: it depends on the repo's squash-message default; the in-body `## TDD Audit` section is the source of truth regardless.)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@~/.claude/gsd-core/references/response-language-directive.md
|
|
2
|
+
|
|
1
3
|
<purpose>
|
|
2
4
|
Curate sketch design findings and package them into a persistent project skill for future
|
|
3
5
|
UI implementation. Reads from `.planning/sketches/`, writes skill to `./.claude/skills/sketch-findings-[project]/`
|
|
@@ -102,7 +102,7 @@ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --raw --default "
|
|
|
102
102
|
COMMIT_DOCS=$(gsd_run query config-get commit_docs --raw 2>/dev/null || echo "true")
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
105
|
+
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
106
106
|
</step>
|
|
107
107
|
|
|
108
108
|
<step name="mood_intake">
|
|
@@ -34,7 +34,7 @@ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --raw --default "
|
|
|
34
34
|
SNAPSHOT=$(gsd_run smart-entry --json 2>/dev/null)
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
37
|
+
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
38
38
|
|
|
39
39
|
Parse `SNAPSHOT` as JSON. It has the shape:
|
|
40
40
|
|
|
@@ -63,7 +63,7 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
|
63
63
|
|
|
64
64
|
Parse JSON for: `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `state_path`, `requirements_path`, `roadmap_path`, `planning_path`, `response_language`, `commit_docs`.
|
|
65
65
|
|
|
66
|
-
**If `response_language` is set:** All user-facing text in this workflow MUST be in `{response_language}`. Technical terms, code, and file paths stay in English.
|
|
66
|
+
**If `response_language` is set:** All user-facing text in this workflow — narration between tool calls, status updates, progress notes, findings, questions, and report prose — MUST be in `{response_language}`. Technical terms, code, and file paths stay in English.
|
|
67
67
|
|
|
68
68
|
**If `phase_found` is false:**
|
|
69
69
|
```
|
|
@@ -192,21 +192,25 @@ If gate passes (ambiguity ≤ 0.20 AND all minimums met):
|
|
|
192
192
|
Run AFTER the ambiguity gate passes (you probe edges of clear requirements, not vague
|
|
193
193
|
ones). Reference: @~/.claude/gsd-core/references/edge-probe.md.
|
|
194
194
|
|
|
195
|
-
**Non-English projects —
|
|
196
|
-
classifier matches are **English** word-boundary patterns, so
|
|
197
|
-
another language matches nothing, classifies to zero shapes, and
|
|
198
|
-
`unclassified` (#1110) — the taxonomy contributes nothing and `--auto`
|
|
199
|
-
`unresolved`.
|
|
200
|
-
|
|
201
|
-
requirement's `text`
|
|
202
|
-
|
|
195
|
+
**Non-English projects — `text_en` carries the classifier-facing translation; the SPEC is
|
|
196
|
+
not.** The shape cues the classifier matches are **English** word-boundary patterns, so
|
|
197
|
+
requirement prose written in another language matches nothing, classifies to zero shapes, and
|
|
198
|
+
lands every row in `unclassified` (#1110) — the taxonomy contributes nothing and `--auto`
|
|
199
|
+
leaves it all `unresolved`. When this project has `response_language` set, add an optional
|
|
200
|
+
`text_en` key to each `$REQS_JSON` entry: a faithful **English** translation of that
|
|
201
|
+
requirement's `text`. `text_en` is **engine input, never user-facing output**, so the
|
|
202
|
+
`response_language` rule at the top of this workflow does not govern it — but `text` itself is
|
|
203
|
+
NOT translated: write it as the requirement's own text, exactly as it appears in the SPEC.
|
|
204
|
+
The SPEC keeps the original language — only `text_en` is translated, and requirement
|
|
203
205
|
`id`s are never translated or renumbered (coverage rows join back on `id`, and any Acceptance
|
|
204
|
-
Criteria you write from the resolved edges go into the SPEC in `response_language`).
|
|
205
|
-
|
|
206
|
+
Criteria you write from the resolved edges go into the SPEC in `response_language`). Populate
|
|
207
|
+
`text_en` for **every** requirement, not only the ones that look edge-relevant: the
|
|
206
208
|
`$APPLICABLE = 0` warning below fires only when *all* requirements are unclassified, so a
|
|
207
|
-
partly-classified spec slips through with no signal at all.
|
|
208
|
-
|
|
209
|
-
|
|
209
|
+
partly-classified spec slips through with no signal at all. When `response_language` is unset
|
|
210
|
+
(an English-language project), omit `text_en` — `text` is already English and the engine
|
|
211
|
+
falls back to it automatically (`text_en ?? text`).
|
|
212
|
+
If a requirement still classifies to zero shapes with `text_en` populated, it carries no cue in
|
|
213
|
+
any language (the recorded recall gap — ADR-857 §98 / ADR-550 D7b, not a translation failure);
|
|
210
214
|
author an explicit `shapes` array on that requirement instead of relying on the prose
|
|
211
215
|
classifier.
|
|
212
216
|
|
|
@@ -251,11 +255,12 @@ fi
|
|
|
251
255
|
|
|
252
256
|
# Write the Requirements gathered in THIS spec session to a temp JSON, then invoke the
|
|
253
257
|
# canonical coverage compute. Populate the heredoc from the SPEC's Requirements — one object
|
|
254
|
-
# per requirement: {"id","text","shapes"?}. This is the load-bearing step: an empty
|
|
255
|
-
# the probe a no-op, so the guard below fails loud rather than silently skipping
|
|
256
|
-
# When `response_language` is set, `
|
|
257
|
-
# the shape cues are English-only, so original-language
|
|
258
|
-
#
|
|
258
|
+
# per requirement: {"id","text","text_en"?,"shapes"?}. This is the load-bearing step: an empty
|
|
259
|
+
# file makes the probe a no-op, so the guard below fails loud rather than silently skipping
|
|
260
|
+
# (RR-04). When `response_language` is set, ALSO add `text_en` — a faithful ENGLISH
|
|
261
|
+
# translation of `text` (see above) — the shape cues are English-only, so original-language
|
|
262
|
+
# `text` alone classifies to zero shapes; `text` itself stays the SPEC's own requirement text
|
|
263
|
+
# and is never translated. Keep every `id` exactly as it appears in the SPEC.
|
|
259
264
|
# BSD/macOS mktemp only randomizes XXXXXX when it is the final path component, so make a
|
|
260
265
|
# suffixless temp then append the extension — portable across BSD + GNU (#1520).
|
|
261
266
|
REQS_JSON=$(mktemp "${TMPDIR:-/tmp}/edge-probe-reqs-XXXXXX") && mv "$REQS_JSON" "${REQS_JSON}.json" && REQS_JSON="${REQS_JSON}.json" || exit 1
|
|
@@ -18,7 +18,7 @@ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-pars
|
|
|
18
18
|
RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --raw --default "" 2>/dev/null || echo "")
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
21
|
+
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
22
22
|
|
|
23
23
|
<step name="banner">
|
|
24
24
|
```
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@~/.claude/gsd-core/references/response-language-directive.md
|
|
2
|
+
|
|
1
3
|
# sync-skills — Cross-Runtime GSD Skill Sync
|
|
2
4
|
|
|
3
5
|
**Command:** `/gsd-sync-skills`
|
|
@@ -30,14 +32,14 @@ IS_APPLY=false
|
|
|
30
32
|
|
|
31
33
|
# Parse --from
|
|
32
34
|
if [[ "$@" == *"--from"* ]]; then
|
|
33
|
-
FROM_RUNTIME=$(echo "$@" |
|
|
35
|
+
FROM_RUNTIME=$(echo "$@" | sed -E 's/.*--from[[:space:]]+([^[:space:]]+).*/\1/')
|
|
34
36
|
fi
|
|
35
37
|
|
|
36
38
|
# Parse --to
|
|
37
39
|
if [[ "$@" == *"--to all"* ]]; then
|
|
38
40
|
TO_RUNTIMES=(antigravity augment claude cline codebuddy codex copilot cursor grok hermes kilo kimi kimi-code opencode pi qwen trae windsurf zcode)
|
|
39
41
|
elif [[ "$@" == *"--to"* ]]; then
|
|
40
|
-
TO_RUNTIMES=( $(echo "$@" |
|
|
42
|
+
TO_RUNTIMES=( $(echo "$@" | sed -E 's/.*--to[[:space:]]+([^[:space:]]+).*/\1/') )
|
|
41
43
|
fi
|
|
42
44
|
|
|
43
45
|
# Parse --apply
|
|
@@ -237,12 +239,18 @@ mkdir -p "$DEST_ROOT"
|
|
|
237
239
|
# empty. If per-runtime conversion is ever wired in, this is where it would go;
|
|
238
240
|
# until then the cp -r must never run for a destination != source.
|
|
239
241
|
|
|
240
|
-
|
|
242
|
+
# Rewrapped through unquoted command substitution (gsd-core#4109): a bare
|
|
243
|
+
# `$VAR` word-splits under bash but not zsh, collapsing every element onto
|
|
244
|
+
# one iteration there.
|
|
245
|
+
for SKILL in $(printf '%s' "$CREATE_LIST") $(printf '%s' "$UPDATE_LIST"); do
|
|
241
246
|
rm -rf "$DEST_ROOT/$SKILL"
|
|
242
247
|
cp -r "$SRC_SKILLS_ROOT/$SKILL" "$DEST_ROOT/$SKILL"
|
|
243
248
|
done
|
|
244
249
|
|
|
245
|
-
|
|
250
|
+
# Rewrapped through unquoted command substitution (gsd-core#4109): a bare
|
|
251
|
+
# `$VAR` word-splits under bash but not zsh, collapsing every element onto
|
|
252
|
+
# one iteration there.
|
|
253
|
+
for SKILL in $(printf '%s' "$REMOVE_LIST"); do
|
|
246
254
|
rm -rf "$DEST_ROOT/$SKILL"
|
|
247
255
|
done
|
|
248
256
|
```
|
|
@@ -28,7 +28,7 @@ AGENT_SKILLS_UI_CHECKER=$(gsd_run query agent-skills gsd-ui-checker)
|
|
|
28
28
|
|
|
29
29
|
Parse JSON for: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_context`, `has_research`, `commit_docs`, `response_language`.
|
|
30
30
|
|
|
31
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
31
|
+
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
32
32
|
|
|
33
33
|
**File paths:** `state_path`, `roadmap_path`, `requirements_path`, `context_path`, `research_path`.
|
|
34
34
|
|
|
@@ -238,8 +238,9 @@ Display blocking issues. Proceed to step 9.
|
|
|
238
238
|
Track `revision_count` (starts at 0).
|
|
239
239
|
|
|
240
240
|
**If `revision_count` < 2:**
|
|
241
|
-
-
|
|
242
|
-
|
|
241
|
+
- Re-spawn gsd-ui-researcher with revision context. `revision_count` is incremented on the
|
|
242
|
+
researcher's RETURN, not here — a return of `## REVISION_CONFLICT` must not spend an
|
|
243
|
+
iteration, and an increment made before dispatch cannot be withheld afterwards:
|
|
243
244
|
|
|
244
245
|
```markdown
|
|
245
246
|
<revision>
|
|
@@ -248,12 +249,32 @@ The UI checker found issues with the current UI-SPEC.md.
|
|
|
248
249
|
### Issues to Fix
|
|
249
250
|
{paste blocking issues from checker return}
|
|
250
251
|
|
|
251
|
-
|
|
252
|
+
`required_property` + evidence + severity BIND. `fix_hint` is ONE non-binding example route: a
|
|
253
|
+
smaller or different mechanism reaching the same property resolves the issue in full — say which
|
|
254
|
+
you used. Re-check the user's locked answers, capability guidance (CLAUDE.md, project skills) and
|
|
255
|
+
the constraints this UI-SPEC already encodes BEFORE editing; if a hint would contradict one, or
|
|
256
|
+
the property is unreachable without breaking one, return `## REVISION_CONFLICT` with the conflict
|
|
257
|
+
and the alternatives rather than applying or working around it — see your `## Revision Conflict`
|
|
258
|
+
section for its shape.
|
|
259
|
+
|
|
260
|
+
Read the existing UI-SPEC.md, resolve ONLY the listed issues, re-write the file.
|
|
252
261
|
Do NOT re-ask the user questions that are already answered.
|
|
253
262
|
</revision>
|
|
254
263
|
```
|
|
255
264
|
|
|
256
|
-
-
|
|
265
|
+
- **If the researcher returns `## REVISION_CONFLICT`:** do NOT increment `revision_count` and do
|
|
266
|
+
NOT re-spawn the checker — a conflict is not resolvable by re-running the same loop. Present the
|
|
267
|
+
conflict and its alternatives to the user and ask which to take: adopt a named alternative /
|
|
268
|
+
override the named constraint and apply the hint / amend the constraint itself. Every option
|
|
269
|
+
resolves the conflict — accepting the spec with the BLOCK still open is NOT offered here, because
|
|
270
|
+
the blocking `required_property` still fails; that choice belongs to the cap escalation below.
|
|
271
|
+
Re-spawn the researcher with the chosen resolution and return to this step.
|
|
272
|
+
|
|
273
|
+
**Bounded:** a conflict naming the SAME `required_property` twice in a row (no successful revision in between) is a stall, and so is
|
|
274
|
+
the THIRD conflict return of this loop whatever property it names — alternating property names
|
|
275
|
+
would otherwise never trip the repeat rule. Stop re-spawning and route it to the same cap
|
|
276
|
+
escalation below, so declining to spend an iteration cannot make this path unbounded.
|
|
277
|
+
- **On any other return:** increment `revision_count`, then re-spawn checker (step 7)
|
|
257
278
|
|
|
258
279
|
**If `revision_count` >= 2:**
|
|
259
280
|
```
|
|
@@ -23,7 +23,7 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
|
23
23
|
AGENT_SKILLS_UI_REVIEWER=$(gsd_run query agent-skills gsd-ui-auditor)
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
26
|
+
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
27
27
|
|
|
28
28
|
Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `commit_docs`.
|
|
29
29
|
|
|
@@ -13,7 +13,7 @@ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-pars
|
|
|
13
13
|
RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --raw --default "" 2>/dev/null || echo "")
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
16
|
+
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
17
17
|
|
|
18
18
|
<step name="banner" priority="first">
|
|
19
19
|
Display the stage banner:
|
|
@@ -7,14 +7,14 @@ Read all files referenced by the invoking prompt's execution_context before star
|
|
|
7
7
|
</required_reading>
|
|
8
8
|
|
|
9
9
|
<process>
|
|
10
|
-
**If `response_language` is configured:** All user-facing questions, prompts, and explanations
|
|
10
|
+
**If `response_language` is configured:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in that language. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
11
11
|
|
|
12
12
|
<step name="get_installed_version">
|
|
13
13
|
Detect the installed GSD version, scope, runtime, and config dir.
|
|
14
14
|
|
|
15
15
|
First, derive `PREFERRED_CONFIG_DIR` and `PREFERRED_RUNTIME` from the invoking prompt's `execution_context` path — this is the one input only the workflow knows:
|
|
16
16
|
- If the path contains `/gsd-core/workflows/update.md`, strip that suffix and store the remainder as `PREFERRED_CONFIG_DIR`.
|
|
17
|
-
- Infer `PREFERRED_RUNTIME` from the path: `/.codex/` -> `codex`; `/.gemini/antigravity-ide/`, `/.gemini/antigravity-cli/`, `/.gemini/antigravity/`, `/.agents/` or `/.agent/` -> `antigravity` (`.agents` is the canonical local Antigravity install dir (#791); `.agent` is the legacy form (#503); see bin/install.js `getDirName('antigravity')`); `/.config/kilo/` or `/.kilo/` -> `kilo`; `/.config/opencode/` or `/.opencode/` -> `opencode`; otherwise
|
|
17
|
+
- Infer `PREFERRED_RUNTIME` from the path: `/.claude/` -> `claude`; `/.codex/` -> `codex`; `/.gemini/antigravity-ide/`, `/.gemini/antigravity-cli/`, `/.gemini/antigravity/`, `/.agents/` or `/.agent/` -> `antigravity` (`.agents` is the canonical local Antigravity install dir (#791); `.agent` is the legacy form (#503); see bin/install.js `getDirName('antigravity')`); `/.windsurf/`, `/.devin/` -> `windsurf`; `/.config/kilo/` or `/.kilo/` -> `kilo`; `/.config/opencode/` or `/.opencode/` -> `opencode`; otherwise leave it empty.
|
|
18
18
|
|
|
19
19
|
Then resolve the install context via the deterministic projection (#498). **Do NOT re-derive scope, runtime, or version by hand** — `update-context` owns that cascade in tested code (`gsd-core/bin/lib/update-context.cjs`), the same way `check-latest-version` owns the package name (#2992):
|
|
20
20
|
|
|
@@ -50,17 +50,17 @@ if [ -n "$UC" ]; then
|
|
|
50
50
|
# then silently degrades to the fresh-install fallback. The field name is
|
|
51
51
|
# passed as argv, never interpolated into the script text.
|
|
52
52
|
uc_field() {
|
|
53
|
-
printf '%s' "$UC" | node -e "let d='';process.stdin.setEncoding('utf8');process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const v=JSON.parse(d)[process.argv[1]];process.stdout.write(v==null?'':String(v));}catch{}})" "$1" 2>/dev/null
|
|
53
|
+
printf '%s' "${2:-$UC}" | node -e "let d='';process.stdin.setEncoding('utf8');process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const v=JSON.parse(d)[process.argv[1]];process.stdout.write(v==null?'':String(v));}catch{}})" "$1" 2>/dev/null
|
|
54
54
|
}
|
|
55
55
|
INSTALLED_VERSION="$(uc_field installedVersion)"
|
|
56
56
|
INSTALL_SCOPE="$(uc_field scope)"
|
|
57
57
|
TARGET_RUNTIME="$(uc_field runtime)"
|
|
58
58
|
GSD_DIR="$(uc_field gsdDir)"
|
|
59
59
|
else
|
|
60
|
-
# No tool resolvable / projection failed ->
|
|
60
|
+
# No tool resolvable / projection failed -> no update target is known.
|
|
61
61
|
INSTALLED_VERSION="0.0.0"
|
|
62
62
|
INSTALL_SCOPE="UNKNOWN"
|
|
63
|
-
TARGET_RUNTIME="
|
|
63
|
+
TARGET_RUNTIME=""
|
|
64
64
|
GSD_DIR=""
|
|
65
65
|
fi
|
|
66
66
|
|
|
@@ -73,15 +73,26 @@ echo "$GSD_DIR"
|
|
|
73
73
|
Parse output:
|
|
74
74
|
- Line 1 = installed version (`0.0.0` means unknown version)
|
|
75
75
|
- Line 2 = install scope (`LOCAL`, `GLOBAL`, or `UNKNOWN`)
|
|
76
|
-
- Line 3 = target runtime (`claude`, `opencode`, `kilo`, `codex`, `antigravity`)
|
|
77
|
-
- Line 4 = resolved GSD config dir (e.g. `/Users/me/.claude`, `/Users/me/.gemini`); empty
|
|
78
|
-
- If scope is `UNKNOWN`, proceed to install using the `--claude --global` fallback.
|
|
76
|
+
- Line 3 = target runtime (`claude`, `opencode`, `kilo`, `codex`, `antigravity`, `windsurf`); empty when no installed target is resolved
|
|
77
|
+
- Line 4 = resolved GSD config dir (e.g. `/Users/me/.claude`, `/Users/me/.gemini`); empty when no installed target is resolved. Capture this as `GSD_DIR` and pass it to subsequent steps so they don't re-derive the runtime path.
|
|
79
78
|
|
|
80
79
|
`update-context` reproduces the previous detection cascade — preferred-config-dir fast path, local-over-global with same-path dedup (so `CWD=$HOME` does not misdetect as LOCAL), env-var overrides (`CLAUDE_CONFIG_DIR`, `OPENCODE_CONFIG_DIR`, `KILO_CONFIG`, `XDG_CONFIG_HOME`, `CODEX_HOME`, …), and semver validation — but as a tested projection rather than ~280 lines of inline bash. Branch coverage lives in `tests/update-context.test.cjs`.
|
|
81
80
|
|
|
82
81
|
If multiple runtime installs are detected and the invoking runtime cannot be determined from execution_context, ask the user which runtime to update before running install.
|
|
83
82
|
|
|
84
|
-
**If
|
|
83
|
+
**If `INSTALL_SCOPE` is `UNKNOWN`, `TARGET_RUNTIME` is empty, or `GSD_DIR` is empty:** this gate takes precedence over the VERSION-missing case below — a fully-unresolved target also reports version `0.0.0`, and must exit here rather than fall through to "proceed to install".
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
UPDATE_TARGET_UNRESOLVED
|
|
87
|
+
|
|
88
|
+
GSD could not resolve an installed update target. No update was performed.
|
|
89
|
+
|
|
90
|
+
Rerun from a valid installed runtime: `/gsd:update`. For a fresh installation, run `npx -y --package=@opengsd/gsd-core@latest -- gsd-core --global`.
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Exit.
|
|
94
|
+
|
|
95
|
+
**Otherwise, if VERSION file missing (version resolves to `0.0.0`) but the target above resolved:** report the installed version as Unknown and proceed to install (treated as `0.0.0` for comparison).
|
|
85
96
|
</step>
|
|
86
97
|
|
|
87
98
|
<step name="parse_update_channel">
|
|
@@ -121,34 +132,31 @@ Extract `section_manifest` from `INIT_UPDATE` — gates the `channel-banner` sec
|
|
|
121
132
|
<step name="check_latest_version">
|
|
122
133
|
Check npm for latest version via the deterministic script. **Do NOT run `npm view` or `npm search` directly** — the package name must come from the script, not from a free choice at execution time. (#2992: LLM-driven prescriptions of npm package names produced wrong-package queries; moving the package name into a script constant closes that gap.)
|
|
123
134
|
|
|
124
|
-
The `GSD_DIR` value emitted by `get_installed_version` (line 4) resolves to the runtime-specific config dir (`~/.claude/`, `~/.gemini/`, `~/.codex/`, etc.), so the script invocation works for every runtime — not just Claude.
|
|
135
|
+
The `GSD_DIR` value emitted by `get_installed_version` (line 4) resolves to the runtime-specific config dir (`~/.claude/`, `~/.gemini/`, `~/.codex/`, etc.), so the script invocation works for every runtime — not just Claude. An unresolved target exits in `get_installed_version` before this step.
|
|
125
136
|
|
|
126
|
-
`LATEST_RESULT` is a JSON document with the documented shape `{ ok: bool, version: string, reason: string, detail?: string }`. Parse
|
|
137
|
+
`LATEST_RESULT` is a JSON document with the documented shape `{ ok: bool, version: string, reason: string, detail?: string }`. Parse it with the Node-only `uc_field` helper. When the script cannot run or returns nothing, preserve its failure as a meaningful diagnostic (#2993 CR feedback):
|
|
127
138
|
|
|
128
139
|
```bash
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
140
|
+
uc_field() {
|
|
141
|
+
printf '%s' "$2" | node -e "let d='';process.stdin.setEncoding('utf8');process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const v=JSON.parse(d)[process.argv[1]];process.stdout.write(v==null?'':String(v));}catch{}})" "$1" 2>/dev/null
|
|
142
|
+
}
|
|
143
|
+
if LATEST_RESULT="$(node "$GSD_DIR/gsd-core/bin/check-latest-version.cjs" --json --tag "$TAG" 2>/dev/null)"; then
|
|
132
144
|
LATEST_STATUS=0
|
|
133
|
-
LATEST_OK=false
|
|
134
|
-
LATEST_VERSION=""
|
|
135
|
-
LATEST_REASON="no_install_detected"
|
|
136
145
|
else
|
|
137
|
-
LATEST_RESULT="$(node "$GSD_DIR/gsd-core/bin/check-latest-version.cjs" --json --tag "$TAG" 2>/dev/null)"
|
|
138
146
|
LATEST_STATUS=$?
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
147
|
+
fi
|
|
148
|
+
# #2993 CR: when node is missing or the script doesn't exist, LATEST_RESULT
|
|
149
|
+
# is empty. Fail the check with a meaningful reason instead of a blank
|
|
150
|
+
# diagnostic.
|
|
151
|
+
if [ -n "$LATEST_RESULT" ]; then
|
|
152
|
+
LATEST_OK="$(uc_field ok "$LATEST_RESULT")"
|
|
153
|
+
LATEST_OK="${LATEST_OK:-false}"
|
|
154
|
+
LATEST_VERSION="$(uc_field version "$LATEST_RESULT")"
|
|
155
|
+
LATEST_REASON="$(uc_field reason "$LATEST_RESULT")"
|
|
156
|
+
else
|
|
157
|
+
LATEST_OK=false
|
|
158
|
+
LATEST_VERSION=""
|
|
159
|
+
LATEST_REASON="script_not_found_or_node_unavailable"
|
|
152
160
|
fi
|
|
153
161
|
```
|
|
154
162
|
|
|
@@ -305,8 +313,8 @@ detected in `get_installed_version`:
|
|
|
305
313
|
|
|
306
314
|
```bash
|
|
307
315
|
# RUNTIME_DIR is the resolved config directory (e.g. ~/.config/opencode, ~/.gemini).
|
|
308
|
-
# get_installed_version emits it as GSD_DIR
|
|
309
|
-
#
|
|
316
|
+
# get_installed_version emits it as GSD_DIR for a resolved LOCAL or GLOBAL install.
|
|
317
|
+
# The unresolved-target gate exits before this step; the empty guard remains defensive.
|
|
310
318
|
RUNTIME_DIR="$GSD_DIR"
|
|
311
319
|
```
|
|
312
320
|
|
|
@@ -387,11 +395,6 @@ npx -y --package=@opengsd/gsd-core@"$TAG" -- gsd-core "$RUNTIME_FLAG" --local
|
|
|
387
395
|
npx -y --package=@opengsd/gsd-core@"$TAG" -- gsd-core "$RUNTIME_FLAG" --global
|
|
388
396
|
```
|
|
389
397
|
|
|
390
|
-
**If UNKNOWN install:**
|
|
391
|
-
```bash
|
|
392
|
-
npx -y --package=@opengsd/gsd-core@"$TAG" -- gsd-core --claude --global
|
|
393
|
-
```
|
|
394
|
-
|
|
395
398
|
Capture output. If install fails, show error and exit.
|
|
396
399
|
|
|
397
400
|
Clear the update cache so statusline indicator disappears:
|
|
@@ -23,7 +23,7 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
|
23
23
|
AGENT_SKILLS_AUDITOR=$(gsd_run query agent-skills gsd-nyquist-auditor)
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
26
|
+
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
27
27
|
|
|
28
28
|
Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`.
|
|
29
29
|
|