@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
|
@@ -367,6 +367,35 @@ gsd_run query commit "docs($PHASE): UI design contract" --files "$PHASE_DIR/$PAD
|
|
|
367
367
|
UI-SPEC complete. Checker can now validate.
|
|
368
368
|
```
|
|
369
369
|
|
|
370
|
+
## Revision Conflict
|
|
371
|
+
|
|
372
|
+
Revision mode only. Emit this INSTEAD OF `## UI-SPEC COMPLETE` when a checker `fix_hint`
|
|
373
|
+
contradicts a locked user answer, active capability guidance, or a constraint this UI-SPEC already
|
|
374
|
+
encodes — or when the `required_property` is unreachable without breaking one. Resolve every
|
|
375
|
+
non-conflicting issue first. This is not a failure: `/gsd:ui-phase` routes it to the user and does
|
|
376
|
+
not spend a revision iteration on it.
|
|
377
|
+
|
|
378
|
+
```markdown
|
|
379
|
+
## REVISION_CONFLICT
|
|
380
|
+
|
|
381
|
+
**Conflicts:** {N} | **Issues resolved anyway:** {M}
|
|
382
|
+
|
|
383
|
+
| Issue | required_property | Conflicts with | Why the hint cannot be applied |
|
|
384
|
+
|-------|-------------------|----------------|-------------------------------|
|
|
385
|
+
| Dimension {N} | {property} | {locked answer / CLAUDE.md rule / spec constraint} | {one line} |
|
|
386
|
+
|
|
387
|
+
### Alternatives Considered
|
|
388
|
+
|
|
389
|
+
| Issue | Alternative | Satisfies required_property? | Cost of adopting |
|
|
390
|
+
|-------|-------------|------------------------------|------------------|
|
|
391
|
+
| Dimension {N} | {smaller or different mechanism} | {yes / partially — how} | {what it changes} |
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
**Every field is one line of plain text.** No newlines inside a cell, and never begin a field with
|
|
395
|
+
`#`, `-`, `|` or a code fence. This table is presented directly to the user in ui-phase's revision
|
|
396
|
+
step, not persisted to a shared file; a field that opens a heading, list item, table cell, or
|
|
397
|
+
fence would corrupt that presentation.
|
|
398
|
+
|
|
370
399
|
## UI-SPEC Blocked
|
|
371
400
|
|
|
372
401
|
```markdown
|
package/agents/gsd-verifier.md
CHANGED
|
@@ -42,6 +42,7 @@ Every truth must resolve to VERIFIED, FAILED (BLOCKER), or UNCERTAIN (WARNING wi
|
|
|
42
42
|
@~/.claude/gsd-core/references/verification-overrides.md
|
|
43
43
|
@~/.claude/gsd-core/references/gates.md
|
|
44
44
|
@~/.claude/gsd-core/references/verifier-phase-gates.md
|
|
45
|
+
@~/.claude/gsd-core/references/verifier-evidence-gate.md
|
|
45
46
|
</required_reading>
|
|
46
47
|
|
|
47
48
|
This agent implements the **Escalation Gate** pattern (surfaces unresolvable gaps to the developer for decision).
|
|
@@ -410,7 +411,9 @@ grep -n -B 2 -A 2 "console\.log" "$file" 2>/dev/null | grep -E "^\s*(const|funct
|
|
|
410
411
|
|
|
411
412
|
**Debt marker gate:** Any `TBD`, `FIXME`, or `XXX` marker in a file modified by this phase is a 🛑 BLOCKER unless the same line references formal follow-up work (`issue #123`, `PR #123`, `#123`, or `DEF-*`). Unreferenced markers mean completion is not auditable; set `status: gaps_found` and list each marker under `gaps`.
|
|
412
413
|
|
|
413
|
-
|
|
414
|
+
**Re-verification evidence gate (#3304):** in re-verification mode, a 🛑 Blocker other than an unresolved debt marker (always self-evidencing) blocks unconditionally only if it is a carried-forward gap (Step 0's `gaps:`) or the flagged file was git-modified since the prior `verified:` timestamp (fail closed: unresolvable history counts as modified). Otherwise it predates the gap-closure round unflagged and needs deterministic evidence — a named test run red, or another concrete reproducible artifact — to stay blocking. Full algorithm: @gsd-core/references/verifier-evidence-gate.md. Unevidenced → 📋 Advisory: record in `advisory:` frontmatter, exclude from Step 9 Rule 1, never revert a completed must-have.
|
|
415
|
+
|
|
416
|
+
Categorize: 🛑 Blocker (prevents goal or unresolved debt marker) | ⚠️ Warning (incomplete) | ℹ️ Info (notable) | 📋 Advisory (re-verification only — new-scope, unevidenced; see above)
|
|
414
417
|
|
|
415
418
|
## Step 7b: Behavioral Spot-Checks
|
|
416
419
|
|
|
@@ -665,6 +668,8 @@ If `valid != true`, refuse to verify. Surface the discrepancy and ask the user t
|
|
|
665
668
|
|
|
666
669
|
**ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation.
|
|
667
670
|
|
|
671
|
+
**#4155:** `covered_files`: every phase PLAN/SUMMARY (+superseded, nested `plans/`), mapped requirement, changed impl file — ROOT-relative. `gsd_run query verification.fingerprint {phaseDir} {file}...`, copy output — never hand-write `covered_digest`.
|
|
672
|
+
|
|
668
673
|
Create `.planning/phases/{phase_dir}/{phase_num}-VERIFICATION.md`:
|
|
669
674
|
|
|
670
675
|
```markdown
|
|
@@ -673,6 +678,8 @@ phase: XX-name
|
|
|
673
678
|
verified: YYYY-MM-DDTHH:MM:SSZ
|
|
674
679
|
status: passed | gaps_found | human_needed
|
|
675
680
|
score: N/M must-haves verified
|
|
681
|
+
covered_files: [...]
|
|
682
|
+
covered_digest: "v1:sha256:..."
|
|
676
683
|
behavior_unverified: 0 # Count of ⚠️ PRESENT_BEHAVIOR_UNVERIFIED truths (present + wired, behavior not exercised); each is detailed in behavior_unverified_items below (and in human_verification when status is human_needed)
|
|
677
684
|
overrides_applied: 0 # Count of PASSED (override) items included in score
|
|
678
685
|
overrides: # Only if overrides exist — carried forward or newly added
|
|
@@ -700,6 +707,11 @@ deferred: # Only if deferred items exist (Step 9b)
|
|
|
700
707
|
- truth: "Observable truth addressed in a later phase"
|
|
701
708
|
addressed_in: "Phase N"
|
|
702
709
|
evidence: "Matching goal or success criteria text"
|
|
710
|
+
advisory: # Only if unevidenced new-scope findings exist (Step 7, re-verification only)
|
|
711
|
+
- finding: "Short description of the new-scope concern"
|
|
712
|
+
category: architectural | security | other
|
|
713
|
+
reason: "Why raised; what would resolve it"
|
|
714
|
+
evidence_status: "none provided"
|
|
703
715
|
behavior_unverified_items: # Only if behavior_unverified > 0 — emitted regardless of overall status, so these survive a gaps_found phase
|
|
704
716
|
- truth: "Observable truth whose state transition or cancellation/cleanup/ordering invariant no test exercises"
|
|
705
717
|
test: "What to trigger"
|
|
@@ -744,6 +756,15 @@ Only include this section if deferred items exist (from Step 9b).
|
|
|
744
756
|
|---|------|-------------|----------|
|
|
745
757
|
| 1 | {truth} | Phase {N} | {matching goal or success criteria} |
|
|
746
758
|
|
|
759
|
+
### Advisory (New Scope, Unevidenced)
|
|
760
|
+
|
|
761
|
+
New-scope findings from Step 7 with no deterministic evidence — reported,
|
|
762
|
+
not blocking. Include this section (even "None") whenever re-verification ran.
|
|
763
|
+
|
|
764
|
+
| # | Finding | Category | Why Advisory |
|
|
765
|
+
|---|---------|----------|--------------|
|
|
766
|
+
| 1 | {finding} | {category} | new-scope, no deterministic evidence |
|
|
767
|
+
|
|
747
768
|
### Required Artifacts
|
|
748
769
|
|
|
749
770
|
| Artifact | Expected | Status | Details |
|
|
@@ -918,6 +939,7 @@ return <div>No messages</div> // Always shows "no messages"
|
|
|
918
939
|
- [ ] Gaps structured in YAML frontmatter (if gaps_found)
|
|
919
940
|
- [ ] Deferred items structured in YAML frontmatter (if deferred items exist)
|
|
920
941
|
- [ ] Re-verification metadata included (if previous existed)
|
|
942
|
+
- [ ] fingerprint fields written via verification.fingerprint (#4155)
|
|
921
943
|
- [ ] VERIFICATION.md created with complete report
|
|
922
944
|
- [ ] Results returned to orchestrator (NOT committed)
|
|
923
945
|
</success_criteria>
|
package/bin/install.js
CHANGED
|
@@ -183,10 +183,11 @@ function isCodexHooksFeatureKey(key) {
|
|
|
183
183
|
return CODEX_HOOKS_FEATURE_ALL_KEYS.includes(key);
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
// #768 \u2014 Claude Code permissions.allow
|
|
186
|
+
// #768 \u2014 Claude Code permissions.allow entries.
|
|
187
187
|
// Pre-populated during Claude installs to eliminate first-run approval friction
|
|
188
|
-
// for gsd-core's own known-safe tool calls
|
|
189
|
-
//
|
|
188
|
+
// for gsd-core's own known-safe tool calls. (The defense-in-depth deny entries
|
|
189
|
+
// for credential files that #768 also wrote are retired \u2014 see
|
|
190
|
+
// GSD_CLAUDE_LEGACY_DENY_PERMISSIONS below.)
|
|
190
191
|
//
|
|
191
192
|
// Format: each string uses Claude Code's documented permission rule syntax \u2014
|
|
192
193
|
// "Tool(pattern)" e.g. "Bash(npx gsd-core *)", "Read(.planning/*)"
|
|
@@ -204,7 +205,20 @@ const GSD_CLAUDE_ALLOW_PERMISSIONS = Object.freeze([
|
|
|
204
205
|
'Read(STATE.md)',
|
|
205
206
|
'Edit(STATE.md)',
|
|
206
207
|
]);
|
|
207
|
-
|
|
208
|
+
// #4221 \u2014 Retired deny rules. #768 wrote these three `Read()` deny rules
|
|
209
|
+
// into settings.json; Claude Code 2.1.259 hardened the Bash-side enforcement
|
|
210
|
+
// of Read() deny rules so that ANY such rule makes every
|
|
211
|
+
// `cd DIR && grep/cat relative-path` compound prompt for approval, even in
|
|
212
|
+
// `auto` permission mode \u2014 and GSD subagents emit hundreds of those per
|
|
213
|
+
// session. The same protection now ships as the managed PreToolUse hook
|
|
214
|
+
// hooks/gsd-secret-read-guard.js (a hook denial is not a permission rule and
|
|
215
|
+
// never arms that check). Unlike the #2278 allow-side migration, there is no
|
|
216
|
+
// surviving "current" deny list: the constant is RENAMED to its legacy role
|
|
217
|
+
// and only ever filtered, never added. Byte-equal strings only \u2014 a user's
|
|
218
|
+
// own hand-written identical rule is indistinguishable and is removed too
|
|
219
|
+
// (the install manifest never recorded permission strings, so a
|
|
220
|
+
// manifest-gated cleanup is not possible).
|
|
221
|
+
const GSD_CLAUDE_LEGACY_DENY_PERMISSIONS = Object.freeze([
|
|
208
222
|
'Read(.env)',
|
|
209
223
|
'Read(.env.*)',
|
|
210
224
|
'Read(.secrets)',
|
|
@@ -236,6 +250,13 @@ const GSD_CLAUDE_LEGACY_ALLOW_PERMISSIONS = Object.freeze([
|
|
|
236
250
|
* so existing installs end up with the working `Edit(...)` forms instead of
|
|
237
251
|
* both the dead legacy entry and its replacement sitting side by side.
|
|
238
252
|
*
|
|
253
|
+
* Migration (#4221): the retired GSD_CLAUDE_LEGACY_DENY_PERMISSIONS entries
|
|
254
|
+
* are removed from permissions.deny (byte-equal only). Nothing is added to
|
|
255
|
+
* deny any more: an absent `deny` key is left absent (never created as an
|
|
256
|
+
* empty array), and a `deny` array emptied BY THIS FILTER is deleted so the
|
|
257
|
+
* retirement leaves no `"deny": []` residue; a user's pre-existing empty
|
|
258
|
+
* `deny: []` is untouched.
|
|
259
|
+
*
|
|
239
260
|
* Defensive: if settings is not a plain object, returns immediately without
|
|
240
261
|
* throwing. If permissions.allow / permissions.deny exist but are not arrays
|
|
241
262
|
* (malformed settings), they are replaced with valid arrays.
|
|
@@ -252,7 +273,7 @@ function mergeClaudePermissions(settings) {
|
|
|
252
273
|
if (!Array.isArray(settings.permissions.allow)) {
|
|
253
274
|
settings.permissions.allow = [];
|
|
254
275
|
}
|
|
255
|
-
if (!Array.isArray(settings.permissions.deny)) {
|
|
276
|
+
if (settings.permissions.deny !== undefined && !Array.isArray(settings.permissions.deny)) {
|
|
256
277
|
settings.permissions.deny = [];
|
|
257
278
|
}
|
|
258
279
|
|
|
@@ -265,9 +286,13 @@ function mergeClaudePermissions(settings) {
|
|
|
265
286
|
settings.permissions.allow.push(entry);
|
|
266
287
|
}
|
|
267
288
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
289
|
+
if (Array.isArray(settings.permissions.deny)) {
|
|
290
|
+
const before = settings.permissions.deny.length;
|
|
291
|
+
settings.permissions.deny = settings.permissions.deny.filter(
|
|
292
|
+
(e) => !GSD_CLAUDE_LEGACY_DENY_PERMISSIONS.includes(e)
|
|
293
|
+
);
|
|
294
|
+
if (settings.permissions.deny.length === 0 && before > 0) {
|
|
295
|
+
delete settings.permissions.deny;
|
|
271
296
|
}
|
|
272
297
|
}
|
|
273
298
|
}
|
|
@@ -411,7 +436,7 @@ const GSD_CHANGESET_FILES = [
|
|
|
411
436
|
'github-release-notes.cjs', 'lint.cjs', 'new.cjs',
|
|
412
437
|
'README.md', // documentation only — not user-authored
|
|
413
438
|
];
|
|
414
|
-
const GSD_SCRIPTS_LIB_FILES = ['cli-exit.cjs', 'allowlist-ratchet.cjs', 'drift-scan.cjs', 'alias-drift-families.cjs', 'exit-code-registry.cjs', 'ndjson-reporter.cjs', 'ci-job-timing.cjs'];
|
|
439
|
+
const GSD_SCRIPTS_LIB_FILES = ['cli-exit.cjs', 'allowlist-ratchet.cjs', 'drift-scan.cjs', 'alias-drift-families.cjs', 'exit-code-registry.cjs', 'ndjson-reporter.cjs', 'ci-job-timing.cjs', 'shellcheck-fetch.cjs'];
|
|
415
440
|
|
|
416
441
|
/**
|
|
417
442
|
* Resolve a runtime's shared-hooks directory name from its descriptor.
|
|
@@ -790,6 +815,10 @@ const {
|
|
|
790
815
|
const {
|
|
791
816
|
resolveRuntimeArtifactLayout,
|
|
792
817
|
} = require(path.join(_gsdLibDir, 'runtime-artifact-layout.cjs'));
|
|
818
|
+
const {
|
|
819
|
+
readSurface,
|
|
820
|
+
resolveSurface,
|
|
821
|
+
} = require(path.join(_gsdLibDir, 'surface.cjs'));
|
|
793
822
|
const {
|
|
794
823
|
assertDestWithinConfigHome,
|
|
795
824
|
createRuntimeArtifactInstallPlan,
|
|
@@ -1796,8 +1825,20 @@ const kiloAgentPermissionOrder = [
|
|
|
1796
1825
|
'lsp',
|
|
1797
1826
|
];
|
|
1798
1827
|
|
|
1828
|
+
const kiloMcpPermissionPattern = /^mcp__([A-Za-z0-9_-]+)__((?:[A-Za-z0-9_-]+)|\*)$/;
|
|
1829
|
+
|
|
1830
|
+
// Derives Kilo's native `{server}_{tool}` MCP permission key (kilo.ai/docs —
|
|
1831
|
+
// external, fixed format). Not injective: both capture groups allow `_`, so
|
|
1832
|
+
// e.g. `mcp__a_b__c` and `mcp__a__b_c` derive the same key. The `Set` below
|
|
1833
|
+
// resolves any such collision deterministically to first-seen-wins — see
|
|
1834
|
+
// src/runtime-artifact-conversion.cts's regression test. Mirrors that file's
|
|
1835
|
+
// convertClaudeToKiloPermissionTool exactly (#4032).
|
|
1799
1836
|
function convertClaudeToKiloPermissionTool(claudeTool) {
|
|
1800
|
-
|
|
1837
|
+
const builtinPermission = claudeToKiloAgentPermissions[claudeTool];
|
|
1838
|
+
if (builtinPermission) return builtinPermission;
|
|
1839
|
+
|
|
1840
|
+
const mcpPermission = kiloMcpPermissionPattern.exec(claudeTool);
|
|
1841
|
+
return mcpPermission ? `${mcpPermission[1]}_${mcpPermission[2]}` : null;
|
|
1801
1842
|
}
|
|
1802
1843
|
|
|
1803
1844
|
function buildKiloAgentPermissionBlock(claudeTools) {
|
|
@@ -1814,6 +1855,10 @@ function buildKiloAgentPermissionBlock(claudeTools) {
|
|
|
1814
1855
|
for (const permission of kiloAgentPermissionOrder) {
|
|
1815
1856
|
lines.push(` ${permission}: ${allowedPermissions.has(permission) ? 'allow' : 'deny'}`);
|
|
1816
1857
|
}
|
|
1858
|
+
for (const permission of allowedPermissions) {
|
|
1859
|
+
if (kiloAgentPermissionOrder.includes(permission)) continue;
|
|
1860
|
+
lines.push(` ${permission}: allow`);
|
|
1861
|
+
}
|
|
1817
1862
|
|
|
1818
1863
|
return lines;
|
|
1819
1864
|
}
|
|
@@ -3849,26 +3894,37 @@ Execute mode fallback:
|
|
|
3849
3894
|
## C. Task() → spawn_agent Mapping
|
|
3850
3895
|
GSD workflows use \`Task(...)\` (Claude Code syntax). Translate to Codex collaboration tools:
|
|
3851
3896
|
|
|
3852
|
-
**Schema detection (required first step):**
|
|
3853
|
-
|
|
3854
|
-
|
|
3897
|
+
**Schema detection (required first step):** Before spawning, inspect the \`spawn_agent\`
|
|
3898
|
+
tool's visible parameter schema (via \`tool_search\` or the tool list). Use the presence
|
|
3899
|
+
of \`agent_type\` only to choose typed dispatch versus the generic-agent workaround.
|
|
3900
|
+
Detect optional fields independently: \`model\`, \`reasoning_effort\`, \`task_name\`,
|
|
3901
|
+
\`fork_turns\`, and \`fork_context\` may be added or removed without \`agent_type\` changing.
|
|
3902
|
+
Never infer one field from a schema/version label or from the presence of another field.
|
|
3855
3903
|
|
|
3856
|
-
|
|
3904
|
+
- **agent_type-capable schema:** \`spawn_agent\` advertises \`agent_type\` — typed GSD agent dispatch is available.
|
|
3905
|
+
- **Generic schema:** \`spawn_agent\` does not advertise \`agent_type\` — typed GSD agent dispatch is unavailable in this session, even if other optional fields are present.
|
|
3857
3906
|
|
|
3858
3907
|
Typed mapping (agent_type-capable schema only):
|
|
3859
3908
|
- \`Task(subagent_type="X", prompt="Y")\` → \`spawn_agent(agent_type="X", message="Y")\`
|
|
3860
3909
|
- \`Agent(subagent_type="X", prompt="Y")\` → \`spawn_agent(agent_type="X", message="Y")\`
|
|
3861
|
-
- \`Task(model="
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3910
|
+
- \`Task(model="{resolved_model}")\` → pass \`model="{resolved_model}"\` when the
|
|
3911
|
+
visible \`spawn_agent\` schema advertises \`model\` and the resolved value is explicit.
|
|
3912
|
+
This is how \`model_profile\` tier routing, including \`adaptive\`, reaches the child agent.
|
|
3913
|
+
Omit \`model\` only when the schema does not advertise \`model\`, or when the value is
|
|
3914
|
+
missing, empty, or \`"inherit"\`; omission deliberately inherits the session/static agent
|
|
3915
|
+
configuration. Explicit \`model_overrides\` may also be embedded in agent \`.toml\` files,
|
|
3916
|
+
but ordinary profile-resolved models are not, so a TOML file is not a reason to discard
|
|
3917
|
+
an available inline value.
|
|
3918
|
+
- Before each typed spawn, obtain the paired effort for its role with
|
|
3919
|
+
\`gsd_run query resolve-model <subagent_type> --pick effort\` when the workflow has not
|
|
3920
|
+
already exposed it. The resolver's unified \`effort\` field maps to the Codex spawn argument
|
|
3921
|
+
\`reasoning_effort\`; do not look for a resolver field named \`reasoning_effort\`.
|
|
3922
|
+
Pass it when the visible \`spawn_agent\` schema advertises \`reasoning_effort\`. Omit the
|
|
3923
|
+
field when it is not advertised, or when the value is missing, empty, \`"inherit"\`, or
|
|
3924
|
+
unsupported; do not invent one-off effort literals in workflow prose.
|
|
3869
3925
|
- \`fork_context: false\` by default — GSD agents load their own context via \`<required_reading>\` blocks
|
|
3870
|
-
- \`task_name\` —
|
|
3871
|
-
- \`fork_turns\` —
|
|
3926
|
+
- \`task_name\` — when advertised, provide a descriptive name for each spawned task
|
|
3927
|
+
- \`fork_turns\` — when advertised, controls turn-forking depth; coexists with \`fork_context\` (not a replacement)
|
|
3872
3928
|
- \`Task(isolation="worktree")\` / \`Agent(isolation="worktree")\` → no direct \`spawn_agent\` mapping,
|
|
3873
3929
|
but Codex declares \`dispatch.isolation: orchestrator-worktree\` (#2584). Codex
|
|
3874
3930
|
\`spawn_agent\` still does not create or bind a git worktree; instead GSD itself
|
|
@@ -7372,7 +7428,8 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
|
|
|
7372
7428
|
|
|
7373
7429
|
if (isAgent && inAgentTools) {
|
|
7374
7430
|
if (trimmed.startsWith('- ')) {
|
|
7375
|
-
|
|
7431
|
+
const tool = runtimeArtifactConversion._decodeToolScalar(trimmed.substring(2));
|
|
7432
|
+
if (tool !== null) agentTools.push(tool);
|
|
7376
7433
|
continue;
|
|
7377
7434
|
}
|
|
7378
7435
|
if (trimmed && !trimmed.startsWith('-')) {
|
|
@@ -7384,8 +7441,12 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
|
|
|
7384
7441
|
if (trimmed.startsWith('tools:')) {
|
|
7385
7442
|
if (isAgent) {
|
|
7386
7443
|
const toolsValue = trimmed.substring(6).trim();
|
|
7387
|
-
|
|
7388
|
-
|
|
7444
|
+
// A comment-only value (`tools: # note`) is not real inline content —
|
|
7445
|
+
// fall through to the block-list scan instead of decoding the
|
|
7446
|
+
// comment as a bogus tool name and dropping the list (mirrors
|
|
7447
|
+
// src/runtime-artifact-conversion.cts's convertClaudeToKiloFrontmatter, #4032).
|
|
7448
|
+
if (toolsValue && !toolsValue.startsWith('#')) {
|
|
7449
|
+
const tools = runtimeArtifactConversion._splitToolScalars(toolsValue).map(runtimeArtifactConversion._decodeToolScalar).filter(tool => tool !== null);
|
|
7389
7450
|
agentTools.push(...tools);
|
|
7390
7451
|
} else {
|
|
7391
7452
|
inAgentTools = true;
|
|
@@ -7451,7 +7512,8 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
|
|
|
7451
7512
|
if (trimmed.startsWith('- ')) {
|
|
7452
7513
|
const tool = trimmed.substring(2).trim();
|
|
7453
7514
|
if (isAgent) {
|
|
7454
|
-
|
|
7515
|
+
const decoded = runtimeArtifactConversion._decodeToolScalar(tool);
|
|
7516
|
+
if (decoded !== null) agentTools.push(decoded);
|
|
7455
7517
|
} else {
|
|
7456
7518
|
allowedTools.push(tool);
|
|
7457
7519
|
}
|
|
@@ -9039,17 +9101,29 @@ function uninstall(isGlobal, runtime = DEFAULT_RUNTIME) {
|
|
|
9039
9101
|
);
|
|
9040
9102
|
if (settings.permissions.allow.length !== before) {
|
|
9041
9103
|
permissionsModified = true;
|
|
9104
|
+
// #4221: an array this filter emptied was GSD-only \u2014 remove the
|
|
9105
|
+
// key rather than leave an empty array behind (Antigravity symmetry).
|
|
9106
|
+
if (settings.permissions.allow.length === 0) {
|
|
9107
|
+
delete settings.permissions.allow;
|
|
9108
|
+
}
|
|
9042
9109
|
}
|
|
9043
9110
|
}
|
|
9044
9111
|
if (Array.isArray(settings.permissions.deny)) {
|
|
9045
9112
|
const before = settings.permissions.deny.length;
|
|
9113
|
+
// #4221: the deny rules are retired, so this is a legacy-only filter.
|
|
9046
9114
|
settings.permissions.deny = settings.permissions.deny.filter(
|
|
9047
|
-
(e) => !
|
|
9115
|
+
(e) => !GSD_CLAUDE_LEGACY_DENY_PERMISSIONS.includes(e)
|
|
9048
9116
|
);
|
|
9049
9117
|
if (settings.permissions.deny.length !== before) {
|
|
9050
9118
|
permissionsModified = true;
|
|
9119
|
+
if (settings.permissions.deny.length === 0) {
|
|
9120
|
+
delete settings.permissions.deny;
|
|
9121
|
+
}
|
|
9051
9122
|
}
|
|
9052
9123
|
}
|
|
9124
|
+
if (permissionsModified && Object.keys(settings.permissions).length === 0) {
|
|
9125
|
+
delete settings.permissions;
|
|
9126
|
+
}
|
|
9053
9127
|
if (permissionsModified) {
|
|
9054
9128
|
settingsModified = true;
|
|
9055
9129
|
console.log(` ${green}✓${reset} Removed GSD permissions from settings.json`);
|
|
@@ -10111,19 +10185,57 @@ function saveLocalPatches(configDir, pristineCtx) {
|
|
|
10111
10185
|
const modified = [];
|
|
10112
10186
|
const pristineHashes = {};
|
|
10113
10187
|
|
|
10188
|
+
// #4086: skills/ manifest keys may live OUTSIDE configDir at the runtime's
|
|
10189
|
+
// ACTUAL skills root — codex global installs to $HOME/.agents/skills (the
|
|
10190
|
+
// ADR-1239 skills-kind `home` override), which writeManifest() already
|
|
10191
|
+
// hashes from via _resolveSkillsRootDir (#2088/#3738). Resolving every key
|
|
10192
|
+
// against configDir alone made every skills/ key miss here, so user
|
|
10193
|
+
// modifications to Codex skills were never hash-compared, never backed up,
|
|
10194
|
+
// and were silently overwritten by the next update. configDir stays FIRST
|
|
10195
|
+
// (Postel: runtimes whose skills genuinely live under configDir resolve
|
|
10196
|
+
// byte-identically to before); the skills root is a fallback, only for keys
|
|
10197
|
+
// under the SAME descriptor-driven manifest prefix writeManifest uses, and
|
|
10198
|
+
// only when that root resolves outside configDir. Containment + symlink
|
|
10199
|
+
// guards apply to the alternate root too (resolveInstallRelativePath).
|
|
10200
|
+
const patchRuntime = (pristineCtx && pristineCtx.runtime) || manifest.runtime || null;
|
|
10201
|
+
const patchScope = manifest.scope === 'local' ? 'local' : 'global';
|
|
10202
|
+
let skillsRedirect = null;
|
|
10203
|
+
if (patchRuntime) {
|
|
10204
|
+
const skillsRoot = _resolveSkillsRootDir(patchRuntime, configDir, patchScope);
|
|
10205
|
+
const resolvedConfig = path.resolve(configDir);
|
|
10206
|
+
if (
|
|
10207
|
+
skillsRoot &&
|
|
10208
|
+
skillsRoot !== resolvedConfig &&
|
|
10209
|
+
!skillsRoot.startsWith(resolvedConfig + path.sep)
|
|
10210
|
+
) {
|
|
10211
|
+
const prefix = _hostBehaviors(patchRuntime).skillsManifestPrefix || 'skills/';
|
|
10212
|
+
skillsRedirect = { root: skillsRoot, prefix };
|
|
10213
|
+
}
|
|
10214
|
+
}
|
|
10215
|
+
|
|
10114
10216
|
for (const [relPath, originalHash] of Object.entries(manifest.files || {})) {
|
|
10115
10217
|
const safeRef = resolveInstallRelativePath(configDir, relPath);
|
|
10116
10218
|
if (!safeRef) continue;
|
|
10117
10219
|
const { relPath: safeRelPath, fullPath } = safeRef;
|
|
10118
|
-
|
|
10119
|
-
|
|
10220
|
+
let installedPath = fullPath;
|
|
10221
|
+
if (!fs.existsSync(installedPath) && skillsRedirect && safeRelPath.startsWith(skillsRedirect.prefix)) {
|
|
10222
|
+
const altRef = resolveInstallRelativePath(
|
|
10223
|
+
skillsRedirect.root,
|
|
10224
|
+
safeRelPath.slice(skillsRedirect.prefix.length)
|
|
10225
|
+
);
|
|
10226
|
+
if (altRef && fs.existsSync(altRef.fullPath)) {
|
|
10227
|
+
installedPath = altRef.fullPath;
|
|
10228
|
+
}
|
|
10229
|
+
}
|
|
10230
|
+
if (!fs.existsSync(installedPath)) continue;
|
|
10231
|
+
const currentHash = fileHash(installedPath);
|
|
10120
10232
|
if (currentHash !== originalHash) {
|
|
10121
10233
|
// Back up the user's modified version
|
|
10122
10234
|
const backupRef = resolveInstallRelativePath(patchesDir, safeRelPath);
|
|
10123
10235
|
if (!backupRef) continue;
|
|
10124
10236
|
const backupPath = backupRef.fullPath;
|
|
10125
10237
|
fs.mkdirSync(path.dirname(backupPath), { recursive: true });
|
|
10126
|
-
fs.copyFileSync(
|
|
10238
|
+
fs.copyFileSync(installedPath, backupPath);
|
|
10127
10239
|
modified.push(safeRelPath);
|
|
10128
10240
|
pristineHashes[safeRelPath] = originalHash;
|
|
10129
10241
|
}
|
|
@@ -10512,7 +10624,7 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) {
|
|
|
10512
10624
|
// one) is honored on every profile, `full` included (#2322 blocker 2).
|
|
10513
10625
|
const _commandsDir = path.join(src, 'commands', 'gsd');
|
|
10514
10626
|
const _skillsManifest = _isCoreProfileAlias ? new Map() : loadSkillsManifest(_commandsDir);
|
|
10515
|
-
|
|
10627
|
+
let _resolvedProfile = resolveProfile({
|
|
10516
10628
|
modes: [_activeProfileName],
|
|
10517
10629
|
manifest: _skillsManifest,
|
|
10518
10630
|
registry: _installedCapabilityRegistry,
|
|
@@ -10863,6 +10975,28 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) {
|
|
|
10863
10975
|
return Array.isArray(scopeLayout) && scopeLayout.length > 0;
|
|
10864
10976
|
})();
|
|
10865
10977
|
|
|
10978
|
+
// Install the distribution-owned gsd-core tree before layout materialization.
|
|
10979
|
+
// installRuntimeArtifacts then provisions the durable Runtime Surface corpus
|
|
10980
|
+
// exactly once into this final tree instead of having that corpus overwritten
|
|
10981
|
+
// by a later whole-tree copy and needing a second provisioning pass.
|
|
10982
|
+
const skillSrc = path.join(src, 'gsd-core');
|
|
10983
|
+
const skillDest = path.join(targetDir, 'gsd-core');
|
|
10984
|
+
const _gsdArtifactsStagingRoot = _tryResolveUserArtifactStagingRoot(targetDir);
|
|
10985
|
+
if (_gsdArtifactsStagingRoot === null) {
|
|
10986
|
+
console.warn(` ${yellow}!${reset} Skipping gsd-core/${USER_OWNED_ARTIFACTS.join(', gsd-core/')} preservation (staging unavailable) — it will be lost if present.`);
|
|
10987
|
+
copyWithPathReplacement(skillSrc, skillDest, pathPrefix, runtime, false, isGlobal, targetDir);
|
|
10988
|
+
} else {
|
|
10989
|
+
const stagedGsdArtifacts = stageUserArtifacts(skillDest, USER_OWNED_ARTIFACTS, _gsdArtifactsStagingRoot);
|
|
10990
|
+
copyWithPathReplacement(skillSrc, skillDest, pathPrefix, runtime, false, isGlobal, targetDir);
|
|
10991
|
+
restoreStagedUserArtifacts(skillDest, stagedGsdArtifacts);
|
|
10992
|
+
discardStagedUserArtifacts(stagedGsdArtifacts);
|
|
10993
|
+
}
|
|
10994
|
+
if (verifyInstalled(skillDest, 'gsd-core')) {
|
|
10995
|
+
console.log(` ${green}✓${reset} Installed workflow assets`);
|
|
10996
|
+
} else {
|
|
10997
|
+
failures.push('gsd-core');
|
|
10998
|
+
}
|
|
10999
|
+
|
|
10866
11000
|
// #2624: write the .gsd-source marker. Extracted from its former late position so it can be
|
|
10867
11001
|
// called BEFORE staging reads the marker (see the call site below). Scoped to the Claude-global
|
|
10868
11002
|
// layout (issue #1477) — the only install path that ships the skills layout without a
|
|
@@ -10879,6 +11013,9 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) {
|
|
|
10879
11013
|
// ADR-1239 Phase B write-confinement: the descriptor-sourced marker filename
|
|
10880
11014
|
// must resolve under targetDir (parity with the other descriptor-driven writes).
|
|
10881
11015
|
const _markerPath = assertDestWithinConfigHome(targetDir, _hostBehaviors(runtime).sourceMarkerFile);
|
|
11016
|
+
if (hasExistingSymlinkBetween(path.resolve(targetDir), _markerPath, { allowOptInFollow: isSymlinkedDestOptIn() })) {
|
|
11017
|
+
throw new Error(`compatibility marker "${_markerPath}" contains an untrusted symlink`);
|
|
11018
|
+
}
|
|
10882
11019
|
fs.writeFileSync(_markerPath, gsdSourceCommands + '\n', 'utf8');
|
|
10883
11020
|
} catch (err) {
|
|
10884
11021
|
// Non-fatal: install proceeds. But on the Claude-global layout walk-up
|
|
@@ -10905,6 +11042,19 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) {
|
|
|
10905
11042
|
if (_isSkillsRuntime) {
|
|
10906
11043
|
// Layout-driven install for skills-based runtimes (full and minimal modes)
|
|
10907
11044
|
const scope = _installScopeId;
|
|
11045
|
+
// Preserve an existing Runtime Surface selection during upgrades. The
|
|
11046
|
+
// installer refreshes the source corpus first, then emits exactly the
|
|
11047
|
+
// already-committed selection instead of widening it to the base profile.
|
|
11048
|
+
const _committedSurface = readSurface(targetDir);
|
|
11049
|
+
if (_committedSurface) {
|
|
11050
|
+
_resolvedProfile = resolveSurface(
|
|
11051
|
+
targetDir,
|
|
11052
|
+
loadSkillsManifest(_commandsDir),
|
|
11053
|
+
undefined,
|
|
11054
|
+
_installedCapabilityRegistry,
|
|
11055
|
+
_committedSurface,
|
|
11056
|
+
);
|
|
11057
|
+
}
|
|
10908
11058
|
// ADR-1239 upgrade 3 / #2088: a kind may declare an alternate install `home`
|
|
10909
11059
|
// (e.g. Codex skills -> $HOME/.agents/skills) instead of the runtime's normal
|
|
10910
11060
|
// configDir. Resolve the ACTUAL on-disk skills root here, descriptor-driven
|
|
@@ -11197,36 +11347,6 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) {
|
|
|
11197
11347
|
_installNativePluginIfDeclared(runtime, targetDir, _hostBehaviors(runtime), src);
|
|
11198
11348
|
}
|
|
11199
11349
|
|
|
11200
|
-
// Copy gsd-core skill with path replacement
|
|
11201
|
-
// Stage user-generated files DURABLY to disk before the wipe-and-copy so
|
|
11202
|
-
// they survive re-install even if the process dies mid-copy (#2875 /
|
|
11203
|
-
// #1874-F19) — copyWithPathReplacement wipes and recursively re-copies the
|
|
11204
|
-
// entire gsd-core/ tree, the single longest operation in the install, on
|
|
11205
|
-
// the path every user takes (40-design.md "Site 4 is far worse...").
|
|
11206
|
-
const skillSrc = path.join(src, 'gsd-core');
|
|
11207
|
-
const skillDest = path.join(targetDir, 'gsd-core');
|
|
11208
|
-
// #2875 defect fix: this IS the mainline install step (installing
|
|
11209
|
-
// gsd-core/ itself) — unlike the optional legacy-cleanup blocks above,
|
|
11210
|
-
// install must still be able to proceed and actually write gsd-core/ even
|
|
11211
|
-
// when the staging root cannot be resolved. Degrade by skipping ONLY the
|
|
11212
|
-
// USER_OWNED_ARTIFACTS preserve/restore wrapper around the copy (warn),
|
|
11213
|
-
// never the copy itself.
|
|
11214
|
-
const _gsdArtifactsStagingRoot = _tryResolveUserArtifactStagingRoot(targetDir);
|
|
11215
|
-
if (_gsdArtifactsStagingRoot === null) {
|
|
11216
|
-
console.warn(` ${yellow}!${reset} Skipping gsd-core/${USER_OWNED_ARTIFACTS.join(', gsd-core/')} preservation (staging unavailable) — it will be lost if present.`);
|
|
11217
|
-
copyWithPathReplacement(skillSrc, skillDest, pathPrefix, runtime, false, isGlobal, targetDir);
|
|
11218
|
-
} else {
|
|
11219
|
-
const stagedGsdArtifacts = stageUserArtifacts(skillDest, USER_OWNED_ARTIFACTS, _gsdArtifactsStagingRoot);
|
|
11220
|
-
copyWithPathReplacement(skillSrc, skillDest, pathPrefix, runtime, false, isGlobal, targetDir);
|
|
11221
|
-
restoreStagedUserArtifacts(skillDest, stagedGsdArtifacts);
|
|
11222
|
-
discardStagedUserArtifacts(stagedGsdArtifacts);
|
|
11223
|
-
}
|
|
11224
|
-
if (verifyInstalled(skillDest, 'gsd-core')) {
|
|
11225
|
-
console.log(` ${green}✓${reset} Installed workflow assets`);
|
|
11226
|
-
} else {
|
|
11227
|
-
failures.push('gsd-core');
|
|
11228
|
-
}
|
|
11229
|
-
|
|
11230
11350
|
// #2624: the .gsd-source marker is now written by _writeGsdSourceMarker()
|
|
11231
11351
|
// BEFORE staging reads it (see the early call above the _isSkillsRuntime
|
|
11232
11352
|
// block). The former write lived here — AFTER staging — which on an upgrade
|
|
@@ -11314,7 +11434,8 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) {
|
|
|
11314
11434
|
} else if (_isSkillsRuntime) {
|
|
11315
11435
|
console.log(` ${dim}↳${reset} Agents installed via descriptor-driven layout (${runtime})`);
|
|
11316
11436
|
} else {
|
|
11317
|
-
const
|
|
11437
|
+
const _standaloneProjectDir = isGlobal ? process.cwd() : targetDir;
|
|
11438
|
+
const _standaloneAgentsResult = installAgentsKindStandalone(runtime, targetDir, _installScopeId, _resolvedProfile, pathPrefix, getCommitAttribution, _installedCapabilityRegistry, _standaloneProjectDir);
|
|
11318
11439
|
if (_standaloneAgentsResult) {
|
|
11319
11440
|
// #2875 defect fix: installAgentsKindStandalone now returns `null`
|
|
11320
11441
|
// (rather than a truthy result pointing at an empty destDir) whenever a
|
|
@@ -12064,8 +12185,18 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) {
|
|
|
12064
12185
|
// require()s managed-hooks-registry.cjs for MANAGED_HOOKS — so all four must be
|
|
12065
12186
|
// installed/refreshed together for every profile, or Codex is wired to a dependency
|
|
12066
12187
|
// chain the same installer never delivers.
|
|
12067
|
-
// We deliberately do *not* copy gsd-graphify-update.sh
|
|
12068
|
-
//
|
|
12188
|
+
// We deliberately do *not* copy gsd-graphify-update.sh for Codex in this
|
|
12189
|
+
// change (graphify auto-update support for Codex is out of scope for #3579).
|
|
12190
|
+
// hooks/lib/ WAS excluded here for the same reason, and that stopped being
|
|
12191
|
+
// correct when #3911 (2ea5efc15) gave gsd-context-monitor.js a real
|
|
12192
|
+
// `require('./lib/hook-exit.js')`: the allowlist below is flat and never
|
|
12193
|
+
// recursed, so the hook shipped without its helper and died with
|
|
12194
|
+
// MODULE_NOT_FOUND at load, before its own try/catch, on every registered
|
|
12195
|
+
// event (#4087, #4098). The libs are now derived from what the staged
|
|
12196
|
+
// scripts actually require rather than hand-listed — see the
|
|
12197
|
+
// stageTransitiveHookLibs call after the copy loop. The #3579 boundary is
|
|
12198
|
+
// preserved: helpers no staged Codex hook requires (graphify tooling among
|
|
12199
|
+
// them) are still not shipped.
|
|
12069
12200
|
const CODEX_HOOKS_TO_COPY = [
|
|
12070
12201
|
'gsd-check-update.js',
|
|
12071
12202
|
'gsd-check-update-worker.js',
|
|
@@ -12081,6 +12212,12 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) {
|
|
|
12081
12212
|
// is not the same as an allowlisted file landing in it — see the marker
|
|
12082
12213
|
// gate below.
|
|
12083
12214
|
let codexStagedHooks = false;
|
|
12215
|
+
// The entries THIS invocation actually staged. Seeding the lib scan from
|
|
12216
|
+
// `existsSync` over the destination instead would also pick up a file
|
|
12217
|
+
// left by a PREVIOUS install whose source is no longer staged — e.g. a
|
|
12218
|
+
// name dropped from the allowlist — and derive helpers for a hook that is
|
|
12219
|
+
// no longer shipped (review of #4087).
|
|
12220
|
+
const codexStagedEntries = [];
|
|
12084
12221
|
for (const entry of fs.readdirSync(codexHooksSrc)) {
|
|
12085
12222
|
if (!CODEX_HOOKS_TO_COPY.includes(entry)) continue;
|
|
12086
12223
|
const srcFile = path.join(codexHooksSrc, entry);
|
|
@@ -12115,8 +12252,43 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) {
|
|
|
12115
12252
|
try { fs.chmodSync(destFile, 0o755); } catch (e) { /* Windows */ }
|
|
12116
12253
|
}
|
|
12117
12254
|
codexStagedHooks = true;
|
|
12255
|
+
codexStagedEntries.push(entry);
|
|
12256
|
+
}
|
|
12257
|
+
// Stage the hooks/lib/ helpers the staged scripts require, transitively
|
|
12258
|
+
// (#4087, #4098). Shares writeCursorHooksJson's walker rather than a
|
|
12259
|
+
// second copy: both reduced bundles hand-pick SCRIPTS, and the identical
|
|
12260
|
+
// MODULE_NOT_FOUND was already fixed once for Cursor in 704859e9c. A flat
|
|
12261
|
+
// list of today's three helpers would re-break the next time a
|
|
12262
|
+
// Codex-bundled hook grows a lib dependency, which is exactly how this
|
|
12263
|
+
// regressed. Gated on codexStagedHooks for the same reason the CommonJS
|
|
12264
|
+
// marker below is: hooks/ is shared space, and staging nothing must not
|
|
12265
|
+
// leave a GSD-owned lib/ behind in a directory GSD created but did not
|
|
12266
|
+
// fill (#2544). Seeded from the copies staged by THIS invocation, so the
|
|
12267
|
+
// scan sees the same bytes Node will load and never derives helpers for a
|
|
12268
|
+
// hook left behind by an earlier install.
|
|
12269
|
+
let codexStagedLibs = [];
|
|
12270
|
+
if (codexStagedHooks) {
|
|
12271
|
+
codexStagedLibs = hooksSurface.stageTransitiveHookLibs({
|
|
12272
|
+
seedSources: codexStagedEntries
|
|
12273
|
+
.map((entry) => fs.readFileSync(path.join(codexHooksDest, entry), 'utf8')),
|
|
12274
|
+
srcLibDir: path.join(codexHooksSrc, 'lib'),
|
|
12275
|
+
destLibDir: path.join(codexHooksDest, 'lib'),
|
|
12276
|
+
runtimeLabel: 'Codex',
|
|
12277
|
+
// Same substitutions the .js branch above applies to hook scripts, so
|
|
12278
|
+
// a helper that ever gains a runtime path or version token is
|
|
12279
|
+
// rewritten identically instead of shipping a Claude-shaped path.
|
|
12280
|
+
// No-ops on today's helpers, which carry neither.
|
|
12281
|
+
transform: (content) => content
|
|
12282
|
+
.replace(/'\.claude'/g, configDirReplacement)
|
|
12283
|
+
.replace(/\/\.claude\//g, `/${getDirName(runtime)}/`)
|
|
12284
|
+
.replace(/\.claude\//g, `${getDirName(runtime)}/`)
|
|
12285
|
+
.replace(/\{\{GSD_VERSION\}\}/g, pkg.version),
|
|
12286
|
+
});
|
|
12118
12287
|
}
|
|
12119
12288
|
console.log(` ${green}✓${reset} Installed hooks (Codex)`);
|
|
12289
|
+
if (codexStagedLibs.length > 0) {
|
|
12290
|
+
console.log(` ${green}✓${reset} Installed hooks/lib/ helpers (${codexStagedLibs.join(', ')})`);
|
|
12291
|
+
}
|
|
12120
12292
|
// #2717: write the CommonJS marker into hooks/ alongside the staged .js
|
|
12121
12293
|
// scripts. Codex is excluded from installSharedHooksBundle by the
|
|
12122
12294
|
// !isCodex gate, so it never received the marker the shared-bundle path
|
|
@@ -13881,7 +14053,7 @@ module.exports = {
|
|
|
13881
14053
|
mergeClaudePermissions,
|
|
13882
14054
|
GSD_CLAUDE_ALLOW_PERMISSIONS,
|
|
13883
14055
|
GSD_CLAUDE_LEGACY_ALLOW_PERMISSIONS,
|
|
13884
|
-
|
|
14056
|
+
GSD_CLAUDE_LEGACY_DENY_PERMISSIONS,
|
|
13885
14057
|
GSD_CODEX_MARKER,
|
|
13886
14058
|
// #3897 rung 3 (ADR-3473 §8.3, HALT.md option 2)
|
|
13887
14059
|
CODEX_SANDBOX_HOLDS,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gsd:execute-phase
|
|
3
|
-
description:
|
|
3
|
+
description: SDD phase execution — execute all plans in a phase with dependency-aware wave parallelization
|
|
4
4
|
argument-hint: "<phase-number> [--wave N] [--gaps-only] [--interactive] [--tdd]"
|
|
5
5
|
effort: max
|
|
6
6
|
allowed-tools:
|
|
@@ -5,7 +5,7 @@ argument-hint: ""
|
|
|
5
5
|
allowed-tools:
|
|
6
6
|
- Read
|
|
7
7
|
- Skill
|
|
8
|
-
requires: [discuss-phase, spec-phase, plan-phase, execute-phase, verify-work, phase, progress, next, ultraplan-phase, plan-review-convergence, add-tests, ai-integration-phase, autonomous, fast, mvp-phase, quick]
|
|
8
|
+
requires: [discuss-phase, spec-phase, plan-phase, execute-phase, verify-work, phase, progress, next, ultraplan-phase, plan-review-convergence, add-tests, ai-integration-phase, autonomous, fast, mvp-phase, quick, quick-batch]
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
Route to the appropriate phase-pipeline skill based on the user's intent.
|
|
@@ -33,5 +33,6 @@ workflow-advance command.
|
|
|
33
33
|
| Execute a trivial task inline | gsd-fast |
|
|
34
34
|
| Plan a phase as a vertical MVP slice | gsd-mvp-phase |
|
|
35
35
|
| Execute a quick task with GSD guarantees | gsd-quick |
|
|
36
|
+
| Batch several quick-shaped tasks together | gsd-quick-batch |
|
|
36
37
|
|
|
37
38
|
Invoke the matched skill directly using the Skill tool.
|