@opengsd/gsd-core 1.9.0 → 1.10.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 +2 -3
- package/.opencode/plugins/gsd-core.js +8 -1
- package/agents/gsd-code-fixer.md +131 -34
- package/agents/gsd-debugger.md +12 -246
- package/agents/gsd-executor.md +7 -5
- package/agents/gsd-integration-checker.md +3 -0
- package/agents/gsd-plan-checker.md +9 -0
- package/agents/gsd-planner.md +5 -8
- package/agents/gsd-roadmapper.md +21 -3
- package/agents/gsd-verifier.md +14 -70
- package/bin/install.js +503 -341
- package/commands/gsd/mempalace-capture.md +1 -1
- package/commands/gsd/new-milestone.md +1 -1
- package/commands/gsd/plan-phase.md +1 -1
- package/gsd-core/bin/gsd-tools.cjs +607 -63
- package/gsd-core/bin/lib/active-workstream-store.cjs +25 -0
- package/gsd-core/bin/lib/agent-install-check.cjs +38 -6
- package/gsd-core/bin/lib/api-coverage.cjs +120 -0
- package/gsd-core/bin/lib/audit.cjs +89 -1
- package/gsd-core/bin/lib/broken-windows.cjs +36 -6
- package/gsd-core/bin/lib/capability-registry.cjs +96 -110
- package/gsd-core/bin/lib/capability-validator.cjs +12 -2
- package/gsd-core/bin/lib/check-command-router.cjs +43 -1
- package/gsd-core/bin/lib/command-aliases.cjs +72 -0
- package/gsd-core/bin/lib/commands.cjs +26 -25
- package/gsd-core/bin/lib/commonjs-marker.cjs +136 -0
- package/gsd-core/bin/lib/config-loader.cjs +1 -0
- package/gsd-core/bin/lib/config.cjs +12 -1
- package/gsd-core/bin/lib/context-composer.cjs +278 -0
- package/gsd-core/bin/lib/context-predicates.cjs +506 -0
- package/gsd-core/bin/lib/core-utils.cjs +91 -12
- package/gsd-core/bin/lib/docs.cjs +3 -2
- package/gsd-core/bin/lib/external-job.cjs +19 -4
- package/gsd-core/bin/lib/frontmatter.cjs +84 -12
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +57 -6
- package/gsd-core/bin/lib/git-base-branch.cjs +58 -15
- package/gsd-core/bin/lib/graphify.cjs +142 -27
- package/gsd-core/bin/lib/gsd2-import.cjs +27 -4
- package/gsd-core/bin/lib/host-integration.cjs +13 -1
- package/gsd-core/bin/lib/init-command-router.cjs +83 -8
- package/gsd-core/bin/lib/init.cjs +1021 -57
- package/gsd-core/bin/lib/install-engine.cjs +64 -10
- package/gsd-core/bin/lib/install-profiles.cjs +27 -1
- package/gsd-core/bin/lib/installer-migration-authoring.cjs +3 -1
- package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
- package/gsd-core/bin/lib/installer-migrations/007-retire-config-root-commonjs-marker.cjs +149 -0
- package/gsd-core/bin/lib/installer-migrations/008-cursor-retire-commands-surface.cjs +55 -0
- package/gsd-core/bin/lib/installer-migrations/009-pi-retire-reserved-hooks-dir.cjs +199 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +87 -1
- package/gsd-core/bin/lib/io.cjs +28 -3
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +6 -0
- package/gsd-core/bin/lib/mcp-catalog.cjs +518 -0
- package/gsd-core/bin/lib/mcp-server.cjs +135 -3
- package/gsd-core/bin/lib/milestone.cjs +106 -51
- package/gsd-core/bin/lib/phase-id.cjs +63 -0
- package/gsd-core/bin/lib/phase-locator.cjs +138 -45
- package/gsd-core/bin/lib/phase.cjs +260 -25
- package/gsd-core/bin/lib/plan-dependency-graph.cjs +232 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +4 -0
- package/gsd-core/bin/lib/project-root.cjs +48 -0
- package/gsd-core/bin/lib/prompt-budget.cjs +128 -165
- package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +80 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +99 -0
- package/gsd-core/bin/lib/review-lane-runner.cjs +30 -6
- package/gsd-core/bin/lib/roadmap-command-router.cjs +42 -9
- package/gsd-core/bin/lib/roadmap-parser.cjs +100 -18
- package/gsd-core/bin/lib/roadmap.cjs +37 -7
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +195 -62
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +15 -3
- package/gsd-core/bin/lib/runtime-homes.cjs +154 -41
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +105 -41
- package/gsd-core/bin/lib/section-manifest.cjs +209 -0
- package/gsd-core/bin/lib/shell-command-projection.cjs +113 -27
- package/gsd-core/bin/lib/smart-entry.cjs +12 -0
- package/gsd-core/bin/lib/state-transition.cjs +73 -8
- package/gsd-core/bin/lib/state.cjs +151 -62
- package/gsd-core/bin/lib/surface.cjs +12 -1
- package/gsd-core/bin/lib/uat-predicate.cjs +11 -1
- package/gsd-core/bin/lib/uat.cjs +320 -21
- package/gsd-core/bin/lib/unusable-input.cjs +9 -0
- package/gsd-core/bin/lib/verification.cjs +29 -12
- package/gsd-core/bin/lib/verify.cjs +29 -5
- package/gsd-core/bin/lib/workflow-fragments.cjs +557 -0
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +181 -18
- package/gsd-core/bin/lib/workstream-inventory.cjs +519 -27
- package/gsd-core/bin/lib/workstream.cjs +6 -0
- package/gsd-core/bin/lib/worktree-base-ref.cjs +50 -6
- package/gsd-core/bin/lib/worktree-safety.cjs +276 -118
- package/gsd-core/bin/shared/config-schema.manifest.json +2 -0
- package/gsd-core/references/artifact-types.md +10 -3
- package/gsd-core/references/autonomous-ui-design-contract.md +42 -0
- package/gsd-core/references/debugger-techniques.md +255 -0
- package/gsd-core/references/research-documentation-lookup.md +5 -3
- package/gsd-core/references/specless-probe-fallback.md +7 -6
- package/gsd-core/references/verifier-wiring-patterns.md +100 -0
- package/gsd-core/references/worktree-branch-check.md +2 -2
- package/gsd-core/templates/summary-complex.md +2 -0
- package/gsd-core/templates/summary-minimal.md +2 -0
- package/gsd-core/templates/summary-standard.md +2 -0
- package/gsd-core/templates/summary.md +2 -0
- package/gsd-core/workflows/audit-milestone.md +3 -0
- package/gsd-core/workflows/autonomous/steps/converge-banner.md +1 -0
- package/gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md +11 -0
- package/gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md +7 -0
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +21 -0
- package/gsd-core/workflows/autonomous/steps/converge-loop.md +7 -0
- package/gsd-core/workflows/autonomous.md +32 -69
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +39 -0
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +83 -0
- package/gsd-core/workflows/code-review.md +42 -145
- package/gsd-core/workflows/complete-milestone/steps/git-tag.md +29 -0
- package/gsd-core/workflows/complete-milestone.md +23 -81
- package/gsd-core/workflows/debug.md +9 -12
- package/gsd-core/workflows/diagnose-issues.md +22 -0
- package/gsd-core/workflows/discovery-phase.md +4 -4
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +15 -0
- package/gsd-core/workflows/discuss-phase-assumptions.md +5 -16
- package/gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md +51 -0
- package/gsd-core/workflows/docs-update.md +8 -51
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +34 -2
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +50 -0
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +31 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +19 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +42 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +43 -37
- package/gsd-core/workflows/execute-phase.md +65 -137
- package/gsd-core/workflows/execute-plan.md +1 -1
- package/gsd-core/workflows/help/modes/full.md +6 -1
- package/gsd-core/workflows/ingest-docs.md +2 -1
- package/gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md +16 -0
- package/gsd-core/workflows/new-milestone/steps/reset-phase-safety.md +19 -0
- package/gsd-core/workflows/new-milestone.md +21 -38
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +176 -0
- package/gsd-core/workflows/new-project/steps/auto-mode-detection.md +32 -0
- package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +18 -0
- package/gsd-core/workflows/new-project.md +13 -226
- package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +15 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +110 -0
- package/gsd-core/workflows/plan-phase/steps/prd-express-gate.md +8 -0
- package/gsd-core/workflows/plan-phase/steps/research-only-early-exit.md +17 -0
- package/gsd-core/workflows/plan-phase/steps/research-only-modifiers.md +16 -0
- package/gsd-core/workflows/plan-phase/steps/reviews-prerequisite.md +17 -0
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +149 -0
- package/gsd-core/workflows/plan-phase.md +49 -193
- package/gsd-core/workflows/progress/steps/forensic-audit.md +125 -0
- package/gsd-core/workflows/progress/steps/mvp-display.md +18 -0
- package/gsd-core/workflows/progress.md +11 -153
- package/gsd-core/workflows/quick/steps/discussion-phase.md +124 -0
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +111 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +46 -0
- package/gsd-core/workflows/quick/steps/research-phase.md +72 -0
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +37 -0
- package/gsd-core/workflows/quick.md +20 -390
- package/gsd-core/workflows/resume-project.md +3 -0
- package/gsd-core/workflows/review/steps/reviewer-instances-note-1.md +4 -0
- package/gsd-core/workflows/review/steps/reviewer-instances-note-2.md +3 -0
- package/gsd-core/workflows/review.md +15 -8
- package/gsd-core/workflows/section-manifest.json +219 -0
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/spec-phase.md +17 -14
- package/gsd-core/workflows/spike-wrap-up.md +20 -5
- package/gsd-core/workflows/spike.md +50 -16
- package/gsd-core/workflows/sync-skills.md +49 -11
- package/gsd-core/workflows/transition/steps/workstream-collision-check.md +17 -0
- package/gsd-core/workflows/transition.md +8 -21
- package/gsd-core/workflows/ui-phase.md +8 -7
- package/gsd-core/workflows/update/steps/channel-banner.md +7 -0
- package/gsd-core/workflows/update.md +18 -7
- package/gsd-core/workflows/verify-phase.md +4 -7
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +36 -0
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +21 -0
- package/gsd-core/workflows/verify-work.md +8 -58
- package/hooks/dist/gsd-agent-isolation-guard.js +428 -0
- package/hooks/dist/gsd-check-update-worker.js +14 -5
- package/hooks/dist/gsd-cursor-subagent-start.js +532 -26
- package/hooks/dist/gsd-read-injection-scanner.js +7 -0
- package/hooks/dist/gsd-statusline.js +72 -6
- package/hooks/dist/gsd-worktree-path-guard.js +2 -1
- package/hooks/dist/gsd-write-guard.js +359 -0
- package/hooks/dist/lib/isolation-sentinel.js +268 -0
- package/hooks/dist/managed-hooks-registry.cjs +2 -0
- package/hooks/gsd-agent-isolation-guard.js +428 -0
- package/hooks/gsd-check-update-worker.js +14 -5
- package/hooks/gsd-cursor-subagent-start.js +532 -26
- package/hooks/gsd-read-injection-scanner.js +7 -0
- package/hooks/gsd-statusline.js +72 -6
- package/hooks/gsd-worktree-path-guard.js +2 -1
- package/hooks/gsd-write-guard.js +359 -0
- package/hooks/hooks.json +12 -0
- package/hooks/lib/isolation-sentinel.js +268 -0
- package/hooks/managed-hooks-registry.cjs +2 -0
- package/package.json +14 -5
- package/pi/gsd.cjs +57 -12
- package/scripts/build-hooks.js +9 -0
- package/scripts/changeset/lint.cjs +9 -2
- package/scripts/changeset/serialize.cjs +5 -1
- package/scripts/gen-capability-matrix.cjs +1 -1
- package/scripts/gen-context-index.cjs +448 -0
- package/scripts/gen-inventory-manifest.cjs +101 -1
- package/scripts/gen-prompt-budget-parity-corpus.cjs +645 -0
- package/scripts/gen-registry.cjs +39 -15
- package/scripts/gen-section-manifest.cjs +638 -0
- package/scripts/generate-package-identity.cjs +4 -2
- package/scripts/lint-allow-test-rule-refs.allowlist.json +17 -31
- package/scripts/lint-compiled-artifact-sync.cjs +6 -1
- package/scripts/lint-docs-command-form.cjs +195 -0
- package/scripts/lint-docs-required.cjs +9 -1
- package/scripts/lint-emitted-drift-ack.cjs +215 -20
- package/scripts/lint-example-parser-parity.cjs +395 -0
- package/scripts/lint-test-file-count.allowlist.json +27 -1
- package/scripts/mutation-matrix.cjs +13 -0
- package/scripts/prompt-injection-scan.sh +27 -6
- package/scripts/registry-schema.cjs +323 -94
- package/scripts/run-tests.cjs +3 -2
- package/scripts/validate-registry.cjs +10 -6
- package/skills/gsd-autonomous/SKILL.md +1 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -1
- package/skills/gsd-mempalace-capture/SKILL.md +1 -1
- package/skills/gsd-new-milestone/SKILL.md +1 -1
- package/skills/gsd-plan-phase/SKILL.md +2 -2
- package/vscode/package.json +1 -1
- package/scripts/gen-emitted-baseline.cjs +0 -145
|
@@ -61,6 +61,78 @@ function sha256Text(value) {
|
|
|
61
61
|
* the correct outcome — refusing to proceed beats silently copying referent
|
|
62
62
|
* bytes.
|
|
63
63
|
*/
|
|
64
|
+
/**
|
|
65
|
+
* Evaluate and, if safe, perform a `remove-empty-dir` action against `fullPath`.
|
|
66
|
+
*
|
|
67
|
+
* This is deliberately WEAKER than a recursive directory-removal primitive
|
|
68
|
+
* (which 003's docblock records as an intentional absence in the ADR-0008
|
|
69
|
+
* design): it only ever calls `fs.rmdirSync` — never `fs.rmSync`, never
|
|
70
|
+
* `{ recursive: true }`, never `{ force: true }` — so a non-empty directory
|
|
71
|
+
* fails the underlying syscall rather than being swept. The emptiness check
|
|
72
|
+
* immediately above the call is what turns that failure mode into a
|
|
73
|
+
* deliberate, non-error "left in place" outcome instead of surfacing ENOTEMPTY.
|
|
74
|
+
*
|
|
75
|
+
* Guards, in order:
|
|
76
|
+
* - lstat (not stat): a symlinked directory is refused outright, never
|
|
77
|
+
* followed. A missing target is reported distinctly so callers can tell
|
|
78
|
+
* "nothing was ever there" from "something was there and is left alone".
|
|
79
|
+
* - must actually be a directory (not a file masquerading under the relPath).
|
|
80
|
+
* - containment: the REALPATH of the target must resolve strictly inside the
|
|
81
|
+
* REALPATH of configDir — never equal to it (removing the config root
|
|
82
|
+
* itself is never in scope) and never escaping it (e.g. via an ancestor
|
|
83
|
+
* symlink the lstat check alone would not catch).
|
|
84
|
+
* - emptiness, re-checked here rather than trusted from planning time: a
|
|
85
|
+
* directory that still holds any entry (managed-but-undeleted, unknown,
|
|
86
|
+
* or created between plan and apply) is left in place. This is reported
|
|
87
|
+
* as 'skipped-not-empty', a successful no-op, not a failure.
|
|
88
|
+
*
|
|
89
|
+
* Any unexpected error along the way (EACCES, EBUSY, a race that removes the
|
|
90
|
+
* target between the lstat and the rmdir, etc.) degrades to 'left-in-place'.
|
|
91
|
+
* This action must never throw out of the executor, matching every sibling
|
|
92
|
+
* action type's failure posture.
|
|
93
|
+
*/
|
|
94
|
+
function evaluateRemoveEmptyDir(configDir, fullPath) {
|
|
95
|
+
let stat;
|
|
96
|
+
try {
|
|
97
|
+
stat = node_fs_1.default.lstatSync(fullPath);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return 'missing';
|
|
101
|
+
}
|
|
102
|
+
if (stat.isSymbolicLink())
|
|
103
|
+
return 'left-in-place';
|
|
104
|
+
if (!stat.isDirectory())
|
|
105
|
+
return 'left-in-place';
|
|
106
|
+
let resolvedRoot;
|
|
107
|
+
let resolvedTarget;
|
|
108
|
+
try {
|
|
109
|
+
resolvedRoot = node_fs_1.default.realpathSync(configDir);
|
|
110
|
+
resolvedTarget = node_fs_1.default.realpathSync(fullPath);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return 'left-in-place';
|
|
114
|
+
}
|
|
115
|
+
if (resolvedTarget === resolvedRoot || !resolvedTarget.startsWith(resolvedRoot + node_path_1.default.sep)) {
|
|
116
|
+
// Refuses both "target IS configDir" and "target escaped configDir".
|
|
117
|
+
return 'left-in-place';
|
|
118
|
+
}
|
|
119
|
+
let entries;
|
|
120
|
+
try {
|
|
121
|
+
entries = node_fs_1.default.readdirSync(fullPath);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return 'left-in-place';
|
|
125
|
+
}
|
|
126
|
+
if (entries.length > 0)
|
|
127
|
+
return 'skipped-not-empty';
|
|
128
|
+
try {
|
|
129
|
+
node_fs_1.default.rmdirSync(fullPath);
|
|
130
|
+
return 'removed';
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return 'left-in-place';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
64
136
|
function copyPreservingSymlink(srcPath, destPath) {
|
|
65
137
|
if (node_fs_1.default.lstatSync(srcPath).isSymbolicLink()) {
|
|
66
138
|
// symlinkSync fails with EEXIST on an occupied path, so clear it first.
|
|
@@ -643,7 +715,8 @@ function applyInstallerMigrationPlan({ configDir, plan, now = () => new Date().t
|
|
|
643
715
|
action.type !== 'backup-and-remove' &&
|
|
644
716
|
action.type !== 'rewrite-json' &&
|
|
645
717
|
action.type !== 'record-baseline' &&
|
|
646
|
-
action.type !== 'baseline-preserve-user'
|
|
718
|
+
action.type !== 'baseline-preserve-user' &&
|
|
719
|
+
action.type !== 'remove-empty-dir') {
|
|
647
720
|
throw new Error(`unsupported migration action type: ${action.type}`);
|
|
648
721
|
}
|
|
649
722
|
const { normalized, fullPath } = ensureInsideConfig(configDir, action.relPath);
|
|
@@ -655,6 +728,18 @@ function applyInstallerMigrationPlan({ configDir, plan, now = () => new Date().t
|
|
|
655
728
|
journal.actions.push(journalAction(action, action.type === 'record-baseline' ? 'recorded' : 'preserved'));
|
|
656
729
|
continue;
|
|
657
730
|
}
|
|
731
|
+
if (action.type === 'remove-empty-dir') {
|
|
732
|
+
// Directory actions never enter the file-copy/rollback machinery below:
|
|
733
|
+
// there is nothing to snapshot-and-restore for a directory node itself
|
|
734
|
+
// (its former CONTENTS were already snapshotted by their own file-level
|
|
735
|
+
// actions before this one runs), and rollback of a removed empty
|
|
736
|
+
// directory is simply re-creating it, which the rollback path below
|
|
737
|
+
// does not model. Non-recursive by construction (evaluateRemoveEmptyDir
|
|
738
|
+
// only ever calls fs.rmdirSync), so there is nothing destructive to undo
|
|
739
|
+
// beyond an mkdir the next install/migration run will happily redo.
|
|
740
|
+
journal.actions.push(journalAction(action, evaluateRemoveEmptyDir(configDir, fullPath)));
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
658
743
|
const rollbackPath = node_path_1.default.join(rollbackRoot, normalized);
|
|
659
744
|
node_fs_1.default.mkdirSync(node_path_1.default.dirname(rollbackPath), { recursive: true });
|
|
660
745
|
copyPreservingSymlink(fullPath, rollbackPath);
|
|
@@ -853,6 +938,7 @@ module.exports = {
|
|
|
853
938
|
applyInstallerMigrationPlan,
|
|
854
939
|
classifyArtifact,
|
|
855
940
|
discoverInstallerMigrations,
|
|
941
|
+
evaluateRemoveEmptyDir,
|
|
856
942
|
migrationChecksum,
|
|
857
943
|
planInstallerMigrations,
|
|
858
944
|
readInstallManifest,
|
package/gsd-core/bin/lib/io.cjs
CHANGED
|
@@ -118,6 +118,22 @@ function writeAllSync(fd, data) {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* The wire form of a JSON result: the exact bytes `output()` emits for it.
|
|
123
|
+
*
|
|
124
|
+
* Exported because a caller that has to reason about the size of its own
|
|
125
|
+
* response — graphify's `--budget` accounting (#2738) — must measure the string
|
|
126
|
+
* this function produces rather than a second, privately-maintained
|
|
127
|
+
* serialization that can drift from it. One definition, so estimator and
|
|
128
|
+
* emitter cannot disagree about indentation or shape.
|
|
129
|
+
*
|
|
130
|
+
* The `@file:` redirection in `output()` is a transport detail, not a payload
|
|
131
|
+
* change: the caller still consumes these bytes, so these are the right ones to
|
|
132
|
+
* measure.
|
|
133
|
+
*/
|
|
134
|
+
function serializeForOutput(result) {
|
|
135
|
+
return JSON.stringify(result, null, 2);
|
|
136
|
+
}
|
|
121
137
|
function output(result, raw, rawValue) {
|
|
122
138
|
let data;
|
|
123
139
|
if (raw && rawValue !== undefined) {
|
|
@@ -125,7 +141,7 @@ function output(result, raw, rawValue) {
|
|
|
125
141
|
data = String(rawValue);
|
|
126
142
|
}
|
|
127
143
|
else {
|
|
128
|
-
const json =
|
|
144
|
+
const json = serializeForOutput(result);
|
|
129
145
|
// Large payloads exceed Claude Code's Bash tool buffer (~50KB).
|
|
130
146
|
// Write to tmpfile and output the path prefixed with @file: so callers can detect it.
|
|
131
147
|
if (json.length > 50000) {
|
|
@@ -168,6 +184,7 @@ const ERROR_REASON = Object.freeze({
|
|
|
168
184
|
// workflow / phase
|
|
169
185
|
PHASE_NOT_FOUND: 'phase_not_found',
|
|
170
186
|
PHASE_VERIFICATION_INCOMPLETE: 'phase_verification_incomplete',
|
|
187
|
+
PHASE_PLAN_COVERAGE_INCOMPLETE: 'phase_plan_coverage_incomplete',
|
|
171
188
|
SUMMARY_NO_PLANNING: 'summary_no_planning',
|
|
172
189
|
// graphify
|
|
173
190
|
GRAPHIFY_NO_GRAPH: 'graphify_no_graph',
|
|
@@ -198,10 +215,17 @@ function getJsonErrorMode() { return _jsonErrorMode; }
|
|
|
198
215
|
* process is in JSON-error mode, stderr receives `{ ok: false, reason,
|
|
199
216
|
* message }` so callers can parse it; otherwise stderr keeps the plain
|
|
200
217
|
* text form for human operators.
|
|
218
|
+
*
|
|
219
|
+
* `extra` (optional) lets a caller attach additional structured fields
|
|
220
|
+
* (e.g. `{ verification_stale_check_indeterminate: true }`) onto the
|
|
221
|
+
* JSON-error-mode payload, spread alongside `ok`/`reason`/`message`, so a
|
|
222
|
+
* test can assert on the value directly instead of regexing `message`'s
|
|
223
|
+
* human-readable text. Ignored entirely in plain-text mode — the human
|
|
224
|
+
* message is the only thing an operator sees there.
|
|
201
225
|
*/
|
|
202
|
-
function error(message, reason = ERROR_REASON.UNKNOWN) {
|
|
226
|
+
function error(message, reason = ERROR_REASON.UNKNOWN, extra) {
|
|
203
227
|
if (_jsonErrorMode) {
|
|
204
|
-
const payload = JSON.stringify({ ok: false, reason, message }) + '\n';
|
|
228
|
+
const payload = JSON.stringify({ ok: false, reason, message, ...(extra || {}) }) + '\n';
|
|
205
229
|
writeAllSync(2, payload);
|
|
206
230
|
}
|
|
207
231
|
else {
|
|
@@ -214,6 +238,7 @@ module.exports = {
|
|
|
214
238
|
ensureGsdTempDir,
|
|
215
239
|
reapStaleTempFiles,
|
|
216
240
|
output,
|
|
241
|
+
serializeForOutput,
|
|
217
242
|
ERROR_REASON,
|
|
218
243
|
setJsonErrorMode,
|
|
219
244
|
getJsonErrorMode,
|
|
@@ -14,6 +14,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
14
14
|
exports.stripFencedCode = stripFencedCode;
|
|
15
15
|
exports.stripInlineCode = stripInlineCode;
|
|
16
16
|
exports.scanInlineCodeSpans = scanInlineCodeSpans;
|
|
17
|
+
exports.scanFencedBlocks = scanFencedBlocks;
|
|
17
18
|
exports.extractFencedBlock = extractFencedBlock;
|
|
18
19
|
exports.tokenizeHeadings = tokenizeHeadings;
|
|
19
20
|
exports.collectSections = collectSections;
|
|
@@ -206,6 +207,11 @@ function stripInlineCodeLine(line) {
|
|
|
206
207
|
* Tracked duplication (same status as `tokenizeHeadings`'s copy, see its
|
|
207
208
|
* comment above): this is a second independent copy of the fence state
|
|
208
209
|
* machine, pending a T-tier consolidation.
|
|
210
|
+
*
|
|
211
|
+
* Exported so `context-predicates.cts` can consume this seam directly for its
|
|
212
|
+
* line-preserving fenced-line skip detection, instead of carrying a third
|
|
213
|
+
* independent copy of the fence state machine (see that module's doc
|
|
214
|
+
* comment).
|
|
209
215
|
*/
|
|
210
216
|
function scanFencedBlocks(lines) {
|
|
211
217
|
const delimRe = /^( {0,3})(`{3,}|~{3,})(.*)$/;
|