@opengsd/gsd-core 1.14.0 → 1.15.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/README.ja-JP.md +3 -3
- package/README.ko-KR.md +3 -3
- package/README.pt-BR.md +3 -3
- package/README.zh-CN.md +3 -3
- package/agents/gsd-code-fixer.compact.md +7 -6
- package/agents/gsd-code-fixer.md +9 -8
- package/agents/gsd-debug-session-manager.compact.md +17 -2
- package/agents/gsd-debug-session-manager.md +17 -2
- package/agents/gsd-debugger.md +2 -2
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +13 -8
- package/agents/gsd-intel-updater.compact.md +1 -1
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-phase-researcher.md +19 -11
- package/agents/gsd-plan-checker.md +8 -7
- package/agents/gsd-planner.md +12 -8
- package/agents/gsd-project-researcher.compact.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +1 -1
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-ui-auditor.md +155 -17
- package/agents/gsd-ui-researcher.compact.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +10 -9
- package/bin/install.js +642 -95
- package/commands/gsd/autonomous.md +2 -2
- package/commands/gsd/capture.md +1 -1
- package/commands/gsd/mempalace-capture.md +7 -3
- package/commands/gsd/plan-review-convergence.md +6 -6
- package/commands/gsd/progress.md +1 -1
- package/commands/gsd/quick-batch.md +1 -1
- package/commands/gsd/review.md +2 -3
- package/gsd-core/bin/gsd-tools.cjs +335 -22
- package/gsd-core/bin/lib/adr-parser.cjs +3 -1
- package/gsd-core/bin/lib/audit.cjs +81 -13
- package/gsd-core/bin/lib/capability-registry.cjs +82 -187
- package/gsd-core/bin/lib/capability-validator.cjs +0 -1
- package/gsd-core/bin/lib/check-command-router.cjs +101 -14
- package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
- package/gsd-core/bin/lib/commands.cjs +175 -42
- package/gsd-core/bin/lib/config-loader.cjs +65 -4
- package/gsd-core/bin/lib/config.cjs +33 -7
- package/gsd-core/bin/lib/decisions.cjs +30 -14
- package/gsd-core/bin/lib/frontmatter.cjs +13 -0
- package/gsd-core/bin/lib/graphify.cjs +10 -2
- package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
- package/gsd-core/bin/lib/init.cjs +207 -41
- package/gsd-core/bin/lib/install-engine.cjs +13 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +8 -1
- package/gsd-core/bin/lib/milestone.cjs +18 -5
- package/gsd-core/bin/lib/model-resolver.cjs +159 -50
- package/gsd-core/bin/lib/phase-command-router.cjs +9 -1
- package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
- package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
- package/gsd-core/bin/lib/phase-id.cjs +109 -7
- package/gsd-core/bin/lib/phase-locator.cjs +29 -10
- package/gsd-core/bin/lib/phase.cjs +227 -26
- package/gsd-core/bin/lib/plan-document.cjs +49 -1
- package/gsd-core/bin/lib/planning-document.cjs +459 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +18 -1
- package/gsd-core/bin/lib/planning-workspace.cjs +8 -3
- package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
- package/gsd-core/bin/lib/probe-core.cjs +7 -1
- package/gsd-core/bin/lib/project-root.cjs +41 -2
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
- package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
- package/gsd-core/bin/lib/roadmap-parser.cjs +163 -3
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
- package/gsd-core/bin/lib/roadmap.cjs +251 -31
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +283 -31
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +3 -1
- package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +215 -33
- package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
- package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
- package/gsd-core/bin/lib/state-transition.cjs +39 -2
- package/gsd-core/bin/lib/state.cjs +42 -0
- package/gsd-core/bin/lib/surface.cjs +17 -1
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +78 -5
- package/gsd-core/bin/lib/uat-predicate.cjs +47 -4
- package/gsd-core/bin/lib/uat.cjs +8 -0
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +100 -9
- package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
- package/gsd-core/bin/lib/verification.cjs +268 -15
- package/gsd-core/bin/lib/verify-command-grounding.cjs +46 -2
- package/gsd-core/bin/lib/verify.cjs +132 -25
- package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
- package/gsd-core/bin/lib/worktree-safety.cjs +784 -51
- package/gsd-core/bin/shared/config-defaults.manifest.json +3 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
- package/gsd-core/references/checkpoints.md +5 -3
- package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe.md +195 -21
- package/gsd-core/references/execute-phase-between-wave-reset.md +7 -6
- package/gsd-core/references/execute-phase-wave-guard.md +22 -11
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/model-profiles.md +1 -1
- package/gsd-core/references/phase-argument-parsing.md +9 -7
- package/gsd-core/references/phase-id-convention.md +28 -0
- package/gsd-core/references/planner-gap-closure.md +2 -0
- package/gsd-core/references/planner-load-graph-context.md +24 -13
- package/gsd-core/references/planner-verify-command-grounding.md +14 -0
- package/gsd-core/references/planning-config.md +11 -2
- package/gsd-core/references/tdd.md +27 -4
- package/gsd-core/references/ui-consideration-probe.md +10 -5
- package/gsd-core/references/verify-command-path-resolvability.md +10 -2
- package/gsd-core/references/worktree-path-safety.md +321 -0
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +1 -1
- package/gsd-core/workflows/add-tests.md +2 -2
- package/gsd-core/workflows/add-todo.md +3 -3
- package/gsd-core/workflows/ai-integration-phase.md +11 -3
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +1 -1
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
- package/gsd-core/workflows/autonomous.md +16 -6
- package/gsd-core/workflows/check-todos.md +2 -2
- package/gsd-core/workflows/cleanup.md +2 -2
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +1 -1
- package/gsd-core/workflows/code-review-fix.md +108 -22
- package/gsd-core/workflows/code-review.md +63 -46
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +1 -1
- package/gsd-core/workflows/complete-milestone.md +2 -2
- package/gsd-core/workflows/debug.md +3 -3
- package/gsd-core/workflows/diagnose-issues.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +2 -2
- package/gsd-core/workflows/docs-update.md +3 -3
- package/gsd-core/workflows/edit-phase.md +1 -1
- package/gsd-core/workflows/eval-review.md +10 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +3 -3
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +37 -3
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +24 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
- package/gsd-core/workflows/execute-phase.md +36 -26
- package/gsd-core/workflows/execute-plan.md +5 -4
- package/gsd-core/workflows/explore.md +3 -3
- package/gsd-core/workflows/extract-learnings.md +2 -1
- package/gsd-core/workflows/fast.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +2 -2
- package/gsd-core/workflows/help/modes/full.compact.md +3 -3
- package/gsd-core/workflows/help/modes/full.md +5 -5
- package/gsd-core/workflows/help/modes/topic.md +15 -5
- package/gsd-core/workflows/import.md +2 -2
- package/gsd-core/workflows/inbox.md +2 -2
- package/gsd-core/workflows/ingest-docs.md +3 -3
- package/gsd-core/workflows/insert-phase.md +1 -1
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +2 -2
- package/gsd-core/workflows/map-codebase.md +2 -2
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +2 -2
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
- package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
- package/gsd-core/workflows/new-project.md +7 -7
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/note.md +1 -1
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
- package/gsd-core/workflows/plan-phase.md +24 -7
- package/gsd-core/workflows/plan-review-convergence.md +21 -5
- package/gsd-core/workflows/plant-seed.md +62 -20
- package/gsd-core/workflows/pr-branch.md +113 -13
- package/gsd-core/workflows/profile-user.md +2 -2
- package/gsd-core/workflows/progress.md +1 -1
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +25 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +1 -1
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +1 -1
- package/gsd-core/workflows/quick.md +21 -9
- package/gsd-core/workflows/reapply-patches.md +9 -3
- package/gsd-core/workflows/remove-phase.md +1 -1
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +1 -1
- package/gsd-core/workflows/review.md +31 -16
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +3 -2
- package/gsd-core/workflows/settings-advanced.md +30 -10
- package/gsd-core/workflows/settings-integrations.md +2 -3
- package/gsd-core/workflows/settings.md +4 -4
- package/gsd-core/workflows/ship.md +3 -2
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +2 -2
- package/gsd-core/workflows/spec-phase.md +15 -5
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/sync-skills.md +5 -5
- package/gsd-core/workflows/thread.md +1 -1
- package/gsd-core/workflows/transition.md +1 -1
- package/gsd-core/workflows/ui-phase.md +44 -8
- package/gsd-core/workflows/ui-review.md +18 -4
- package/gsd-core/workflows/ultraplan-phase.md +1 -1
- package/gsd-core/workflows/undo.md +339 -20
- package/gsd-core/workflows/update.md +7 -7
- package/gsd-core/workflows/validate-phase.md +3 -2
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +81 -16
- package/hooks/dist/gsd-agent-isolation-guard.js +24 -0
- package/hooks/dist/gsd-secret-read-guard.js +27 -1
- package/hooks/dist/gsd-statusline.js +70 -13
- package/hooks/dist/gsd-validate-commit.sh +63 -4
- package/hooks/gsd-agent-isolation-guard.js +24 -0
- package/hooks/gsd-secret-read-guard.js +27 -1
- package/hooks/gsd-statusline.js +70 -13
- package/hooks/gsd-validate-commit.sh +63 -4
- package/package.json +3 -2
- package/scripts/build-hooks.js +15 -6
- package/scripts/check-contract-drift.cjs +127 -11
- package/scripts/command-contract-helpers.cjs +3 -0
- package/scripts/docs-guard-registry.cjs +28 -0
- package/scripts/gen-loop-host-contract.cjs +69 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +14 -0
- package/scripts/lib/ndjson-reporter.cjs +3 -2
- package/scripts/lib/platform-conformance-tier.generated.cjs +11 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +28 -1
- package/scripts/lint-phase-arg-assignment.cjs +257 -0
- package/scripts/lint-phase-id-drift.cjs +290 -5
- package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
- package/scripts/lint-retired-runtime-name.cjs +619 -0
- package/scripts/lint-state-write-path-drift.cjs +93 -0
- package/scripts/lint-test-file-count.allowlist.json +28 -9
- package/scripts/lint-workflow-shellcheck-baseline.json +15 -0
- package/scripts/prompt-injection-scan.sh +4 -0
- package/scripts/release-tarball-smoke.cjs +194 -1
- package/skills/gsd-autonomous/SKILL.md +2 -2
- package/skills/gsd-capture/SKILL.md +1 -1
- package/skills/gsd-mempalace-capture/SKILL.md +7 -3
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
- package/skills/gsd-progress/SKILL.md +1 -1
- package/skills/gsd-quick-batch/SKILL.md +1 -1
- package/skills/gsd-review/SKILL.md +2 -3
- package/vscode/package.json +1 -1
|
@@ -854,8 +854,15 @@ function scanQuantitativeCriteria(content) {
|
|
|
854
854
|
// Not a markdown table: the negated-pipe class matches a SHELL pipeline
|
|
855
855
|
// stage boundary (git before the next `|`), the same shape the
|
|
856
856
|
// #429/#968 scanners use; there is no table row to parse.
|
|
857
|
+
// #4774: the lookahead keeps `||` — a logical OR, the construct that
|
|
858
|
+
// HANDLES the failure (e.g. the `git cat-file -e <sha> || echo missing`
|
|
859
|
+
// ghost-control idiom, reachable here when prose apostrophes leave the
|
|
860
|
+
// segment's quote state unclosed) — quiet, while `|` and `|&` (a real
|
|
861
|
+
// pipeline stage, stderr-merged or not) still warn. Accepted trade-off:
|
|
862
|
+
// a QUOTED `||` literal ahead of a real pipe (``git grep 'a||b' f | wc -l``)
|
|
863
|
+
// also goes quiet — the lookahead cannot reach past the doubled pipe.
|
|
857
864
|
// allow-adhoc-markdown: shell pipeline stage boundary, not a table cell (#4024)
|
|
858
|
-
if (/\bgit\s+[a-z][^\n|]
|
|
865
|
+
if (/\bgit\s+[a-z][^\n|]*\|(?!\|)/.test(seg)) {
|
|
859
866
|
record(warnings, 'R4', '[plan-criteria R4] A fallible `git` in a non-final pipeline stage is swallowed — the pipeline reports ' +
|
|
860
867
|
'the last stage\'s status, so a broken command reads as clean. Capture the status first.', seenWarn);
|
|
861
868
|
}
|
|
@@ -926,6 +933,13 @@ function extractPlanTaskInfos(content) {
|
|
|
926
933
|
const nameArr = (0, markdown_sectionizer_cjs_1.extractTaggedBlocks)(body, 'name');
|
|
927
934
|
const hasName = nameArr.length > 0;
|
|
928
935
|
const name = hasName ? nameArr[0].trim() : '';
|
|
936
|
+
// `(?:^|\s)` (not `\b`) so a hyphenated attribute ending in `auto_select`
|
|
937
|
+
// can never be mistaken for the real attribute — the same defensive
|
|
938
|
+
// anchor as extractOptionIds' `id` match below (#4095).
|
|
939
|
+
const autoSelectMatch = attrs.match(/(?:^|\s)auto_select\s*=\s*["']([^"']*)["']/);
|
|
940
|
+
const autoSelect = autoSelectMatch ? autoSelectMatch[1] : null;
|
|
941
|
+
const optionsArr = (0, markdown_sectionizer_cjs_1.extractTaggedBlocks)(body, 'options');
|
|
942
|
+
const optionIds = optionsArr.length > 0 ? extractOptionIds(optionsArr[0]) : [];
|
|
929
943
|
infos.push({
|
|
930
944
|
name,
|
|
931
945
|
type,
|
|
@@ -943,6 +957,8 @@ function extractPlanTaskInfos(content) {
|
|
|
943
957
|
hasHowToVerify: /<how-to-verify[\s>]/.test(body),
|
|
944
958
|
hasDecision: /<decision[\s>]/.test(body),
|
|
945
959
|
hasOptions: /<options[\s>]/.test(body),
|
|
960
|
+
autoSelect,
|
|
961
|
+
optionIds,
|
|
946
962
|
hasInstructions: /<instructions[\s>]/.test(body),
|
|
947
963
|
hasVerification: /<verification[\s>]/.test(body),
|
|
948
964
|
hasResumeSignal: /<resume-signal[\s>]/.test(body),
|
|
@@ -954,6 +970,35 @@ function extractPlanTaskInfos(content) {
|
|
|
954
970
|
}
|
|
955
971
|
return infos;
|
|
956
972
|
}
|
|
973
|
+
/**
|
|
974
|
+
* Extract the `id` attribute of every `<option id="…">` opening tag found in
|
|
975
|
+
* `optionsBody` (the inner text of one `<options>…</options>` block), in
|
|
976
|
+
* document order. Bounded attribute scan (`[^>]{0,500}`), mirroring the same
|
|
977
|
+
* ReDoS-safe idiom `extractPlanTaskInfos` uses for the `<task type="…">`
|
|
978
|
+
* attribute string — this file's established pattern for reading an
|
|
979
|
+
* attribute value without a general XML parser (#4095).
|
|
980
|
+
*/
|
|
981
|
+
function extractOptionIds(optionsBody) {
|
|
982
|
+
const ids = [];
|
|
983
|
+
if (typeof optionsBody !== 'string' || optionsBody.length === 0)
|
|
984
|
+
return ids;
|
|
985
|
+
const OPTION_OPEN_RE = /<option(\s[^>]{0,500})?>/g;
|
|
986
|
+
let match;
|
|
987
|
+
while ((match = OPTION_OPEN_RE.exec(optionsBody)) !== null) {
|
|
988
|
+
const attrs = match[1] ?? '';
|
|
989
|
+
// `(?:^|\s)` (not `\b`) so a decoy attribute like `data-id="…"` inside
|
|
990
|
+
// the same opening tag cannot be mistaken for the real `id` — `\b`
|
|
991
|
+
// matches at the `-`→`i` boundary too, which `.match()`'s
|
|
992
|
+
// first-hit-wins semantics would then silently prefer (#4095).
|
|
993
|
+
const idMatch = attrs.match(/(?:^|\s)id\s*=\s*["']([^"']{1,200})["']/);
|
|
994
|
+
if (idMatch)
|
|
995
|
+
ids.push(idMatch[1]);
|
|
996
|
+
if (match.index === OPTION_OPEN_RE.lastIndex) {
|
|
997
|
+
OPTION_OPEN_RE.lastIndex++;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
return ids;
|
|
1001
|
+
}
|
|
957
1002
|
function isCheckpointType(type) {
|
|
958
1003
|
return type.startsWith('checkpoint:');
|
|
959
1004
|
}
|
|
@@ -996,6 +1041,15 @@ function validatePlanTaskStructure(task) {
|
|
|
996
1041
|
errors.push(`Task '${taskName}' missing <decision>`);
|
|
997
1042
|
if (!task.hasOptions)
|
|
998
1043
|
errors.push(`Task '${taskName}' missing <options>`);
|
|
1044
|
+
if (task.autoSelect !== null) {
|
|
1045
|
+
if (task.autoSelect.length === 0) {
|
|
1046
|
+
errors.push(`Task '${taskName}' auto_select is empty — name an <option id="…">`);
|
|
1047
|
+
}
|
|
1048
|
+
else if (task.hasOptions && !task.optionIds.includes(task.autoSelect)) {
|
|
1049
|
+
errors.push(`Task '${taskName}' auto_select="${task.autoSelect}" does not match any `
|
|
1050
|
+
+ `<option id="…"> (available: ${task.optionIds.join(', ') || 'none'})`);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
999
1053
|
break;
|
|
1000
1054
|
case 'checkpoint:human-action':
|
|
1001
1055
|
if (!task.hasAction)
|
|
@@ -1165,6 +1219,11 @@ function cmdVerifyPhaseCompleteness(cwd, phase, raw) {
|
|
|
1165
1219
|
warnings,
|
|
1166
1220
|
}, raw, errors.length === 0 ? 'complete' : 'incomplete');
|
|
1167
1221
|
}
|
|
1222
|
+
// #4678: citations may carry a trailing line suffix (":42", ":1-20") that
|
|
1223
|
+
// describes a location inside the file, not part of the path itself.
|
|
1224
|
+
function stripLineSuffix(ref) {
|
|
1225
|
+
return ref.replace(/:\d+(?:-\d+)?$/, '');
|
|
1226
|
+
}
|
|
1168
1227
|
function cmdVerifyReferences(cwd, filePath, raw) {
|
|
1169
1228
|
if (!filePath) {
|
|
1170
1229
|
error('file path required');
|
|
@@ -1180,9 +1239,10 @@ function cmdVerifyReferences(cwd, filePath, raw) {
|
|
|
1180
1239
|
const atRefs = content.match(/@([^\s\n,)]+\/[^\s\n,)]+)/g) || [];
|
|
1181
1240
|
for (const ref of atRefs) {
|
|
1182
1241
|
const cleanRef = ref.slice(1);
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1185
|
-
|
|
1242
|
+
const fsRef = stripLineSuffix(cleanRef);
|
|
1243
|
+
const resolved = fsRef.startsWith('~/')
|
|
1244
|
+
? node_path_1.default.join(process.env['HOME'] || '', fsRef.slice(2))
|
|
1245
|
+
: node_path_1.default.join(cwd, fsRef);
|
|
1186
1246
|
if (node_fs_1.default.existsSync(resolved)) {
|
|
1187
1247
|
found.push(cleanRef);
|
|
1188
1248
|
}
|
|
@@ -1190,14 +1250,14 @@ function cmdVerifyReferences(cwd, filePath, raw) {
|
|
|
1190
1250
|
missing.push(cleanRef);
|
|
1191
1251
|
}
|
|
1192
1252
|
}
|
|
1193
|
-
const backtickRefs = content.match(/`([^`]+\/[^`]+\.[a-zA-Z]{1,10})`/g) || [];
|
|
1253
|
+
const backtickRefs = content.match(/`([^`]+\/[^`]+\.[a-zA-Z]{1,10}(?::\d+(?:-\d+)?)?)`/g) || [];
|
|
1194
1254
|
for (const ref of backtickRefs) {
|
|
1195
1255
|
const cleanRef = ref.slice(1, -1);
|
|
1196
1256
|
if (cleanRef.startsWith('http') || cleanRef.includes('${') || cleanRef.includes('{{'))
|
|
1197
1257
|
continue;
|
|
1198
1258
|
if (found.includes(cleanRef) || missing.includes(cleanRef))
|
|
1199
1259
|
continue;
|
|
1200
|
-
const resolved = node_path_1.default.join(cwd, cleanRef);
|
|
1260
|
+
const resolved = node_path_1.default.join(cwd, stripLineSuffix(cleanRef));
|
|
1201
1261
|
if (node_fs_1.default.existsSync(resolved)) {
|
|
1202
1262
|
found.push(cleanRef);
|
|
1203
1263
|
}
|
|
@@ -1259,28 +1319,75 @@ function cmdVerifyArtifacts(cwd, planFilePath, raw) {
|
|
|
1259
1319
|
const artFullPath = node_path_1.default.join(cwd, artPath);
|
|
1260
1320
|
const exists = node_fs_1.default.existsSync(artFullPath);
|
|
1261
1321
|
const check = { path: artPath, exists, issues: [], passed: false };
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1322
|
+
// #4685: one artifact's I/O problem is that artifact's failure, never the
|
|
1323
|
+
// whole plan's. `safeReadFile` rethrows every errno except ENOENT, so before
|
|
1324
|
+
// this an unreadable entry — a directory most commonly, but equally an EACCES
|
|
1325
|
+
// file or a dangling mount — threw out of the loop and the command reported
|
|
1326
|
+
// NOTHING: not the offending entry, and not the plan's other, perfectly good
|
|
1327
|
+
// artifacts either. A check that disappears is worse than a check that fails,
|
|
1328
|
+
// because a failure is visible.
|
|
1329
|
+
//
|
|
1330
|
+
// Scope of this guard, stated precisely (review nit): the `try` encloses the
|
|
1331
|
+
// whole per-artifact body, but the only statements in it that can throw are the
|
|
1332
|
+
// `statSync` and the read — the `min_lines`/`contains`/`exports` checks below
|
|
1333
|
+
// are pure string operations. So this catches I/O, and nothing here is a
|
|
1334
|
+
// deliberate guard around those criteria checks. A path `fs.existsSync` already
|
|
1335
|
+
// rejected never reaches here either (that is the `File not found` branch), so
|
|
1336
|
+
// this is not a claim to catch every way a path can be unusable.
|
|
1337
|
+
try {
|
|
1338
|
+
if (exists) {
|
|
1339
|
+
// A directory is reported as its own kind of failure, distinct from
|
|
1340
|
+
// `File not found`: the path resolved, it simply is not the thing an
|
|
1341
|
+
// artifact entry can be checked against. Verifying a directory (matching
|
|
1342
|
+
// `contains:`/`min_lines:`/`exports:` across the files inside it) is a
|
|
1343
|
+
// feature decision, deliberately not made here.
|
|
1344
|
+
if (node_fs_1.default.statSync(artFullPath).isDirectory()) {
|
|
1345
|
+
check['issues'].push('Not a file: path is a directory');
|
|
1278
1346
|
}
|
|
1347
|
+
else {
|
|
1348
|
+
// `safeReadFile` returns null on ENOENT, and `|| ''` would turn that
|
|
1349
|
+
// into an empty file — which an entry carrying only `path`/`provides`
|
|
1350
|
+
// would then PASS, having checked nothing. `statSync` just succeeded, so
|
|
1351
|
+
// a null here means the artifact went away mid-check. Report that rather
|
|
1352
|
+
// than inheriting a pass from it. (Pre-existing above this fix, reachable
|
|
1353
|
+
// through the same race after `existsSync`; found in review.)
|
|
1354
|
+
const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(artFullPath);
|
|
1355
|
+
if (rawContent === null) {
|
|
1356
|
+
check['issues'].push('Unreadable: disappeared during check');
|
|
1357
|
+
results.push(check);
|
|
1358
|
+
continue;
|
|
1359
|
+
}
|
|
1360
|
+
const fileContent = rawContent;
|
|
1361
|
+
const lineCount = fileContent.split('\n').length;
|
|
1362
|
+
if (artifact['min_lines'] && lineCount < artifact['min_lines']) {
|
|
1363
|
+
check['issues'].push(`Only ${lineCount} lines, need ${artifact['min_lines']}`);
|
|
1364
|
+
}
|
|
1365
|
+
if (artifact['contains'] && !fileContent.includes(artifact['contains'])) {
|
|
1366
|
+
check['issues'].push(`Missing pattern: ${artifact['contains']}`);
|
|
1367
|
+
}
|
|
1368
|
+
if (artifact['exports']) {
|
|
1369
|
+
const exports = Array.isArray(artifact['exports'])
|
|
1370
|
+
? artifact['exports']
|
|
1371
|
+
: [artifact['exports']];
|
|
1372
|
+
for (const exp of exports) {
|
|
1373
|
+
if (!fileContent.includes(exp))
|
|
1374
|
+
check['issues'].push(`Missing export: ${exp}`);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
check['passed'] = check['issues'].length === 0;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
else {
|
|
1381
|
+
check['issues'].push('File not found');
|
|
1279
1382
|
}
|
|
1280
|
-
check['passed'] = check['issues'].length === 0;
|
|
1281
1383
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1384
|
+
catch (err) {
|
|
1385
|
+
// Unreadable for some other reason. Record the errno rather than a generic
|
|
1386
|
+
// message — an operator seeing EACCES acts differently from one seeing EIO —
|
|
1387
|
+
// and leave `passed` false.
|
|
1388
|
+
const e = err;
|
|
1389
|
+
check['issues'].push(`Unreadable: ${e.code || (e.message ?? String(err))}`);
|
|
1390
|
+
check['passed'] = false;
|
|
1284
1391
|
}
|
|
1285
1392
|
results.push(check);
|
|
1286
1393
|
}
|