@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
|
@@ -39,7 +39,7 @@ const ioMod = require("./io.cjs");
|
|
|
39
39
|
const { output: coreOutput, error: coreError } = ioMod;
|
|
40
40
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
41
41
|
const activationMod = require("./capability-activation.cjs");
|
|
42
|
-
const { _resolveActivationValue } = activationMod;
|
|
42
|
+
const { _resolveActivationValue, _resolvePointGate } = activationMod;
|
|
43
43
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
44
44
|
const configLoaderMod = require("./config-loader.cjs");
|
|
45
45
|
const { loadConfig } = configLoaderMod;
|
|
@@ -179,6 +179,12 @@ function resolveCapabilityState(input) {
|
|
|
179
179
|
// (mirrors loop-resolver.isActive: `typeof when !== 'string' || when.length === 0` → false)
|
|
180
180
|
configured = false;
|
|
181
181
|
}
|
|
182
|
+
// #3661: optional point-selection gate, ANDed in — mirrors loop-resolver.isActive
|
|
183
|
+
// EXACTLY (see capability-activation.cts's _resolvePointGate doc comment; this
|
|
184
|
+
// parity is load-bearing, see tests/capability-precedence-parity.test.cjs).
|
|
185
|
+
if (configured) {
|
|
186
|
+
configured = _resolvePointGate(h['pointFrom'], point, config, cwd, registry);
|
|
187
|
+
}
|
|
182
188
|
// Hook active = capability-level active AND hook's own config gate.
|
|
183
189
|
// The capability's `active` constant (= enabled && configActivation) is
|
|
184
190
|
// used here so that a config-disabled capability (active=false) cannot
|
|
@@ -1643,6 +1643,28 @@ function validateRuntimeBody(cap) {
|
|
|
1643
1643
|
' (or "undocumented") (got: ' + JSON.stringify(d.isolation) + ')',
|
|
1644
1644
|
);
|
|
1645
1645
|
}
|
|
1646
|
+
|
|
1647
|
+
// maxConcurrency — ADR-1239 Phase 1 (#3673). A numeric dispatch
|
|
1648
|
+
// sub-field (not a closed-vocabulary enum member — same numeric
|
|
1649
|
+
// dispatch sub-field treatment as maxDepth above; unlike maxDepth,
|
|
1650
|
+
// 0 and negative values are invalid — 1 is the fail-closed floor, not
|
|
1651
|
+
// a legitimate "no concurrency" declaration).
|
|
1652
|
+
// OPTIONAL, like isolation: added after existing descriptors, so an
|
|
1653
|
+
// omitted maxConcurrency is legitimate — negotiateHostCapabilities
|
|
1654
|
+
// degrades it to 1 (the safe floor) and warns, exactly as for any
|
|
1655
|
+
// other undeclared dispatch sub-field. Only a PRESENT value is
|
|
1656
|
+
// checked against the positive-safe-integer contract.
|
|
1657
|
+
if (d.maxConcurrency === undefined) {
|
|
1658
|
+
// absent — nothing to validate; negotiateHostCapabilities fails it closed.
|
|
1659
|
+
} else if (
|
|
1660
|
+
d.maxConcurrency !== 'undocumented' &&
|
|
1661
|
+
(!Number.isSafeInteger(d.maxConcurrency) || d.maxConcurrency < 1)
|
|
1662
|
+
) {
|
|
1663
|
+
errors.push(
|
|
1664
|
+
'runtime.hostIntegration.dispatch.maxConcurrency must be a positive safe integer or "undocumented" ' +
|
|
1665
|
+
'(got: ' + JSON.stringify(d.maxConcurrency) + ')',
|
|
1666
|
+
);
|
|
1667
|
+
}
|
|
1646
1668
|
}
|
|
1647
1669
|
}
|
|
1648
1670
|
|
|
@@ -1824,9 +1846,29 @@ const KNOWN_REVIEWER_FIELDS = new Set([
|
|
|
1824
1846
|
// missed a configured model and silently disabled the pinned-model escape hatch
|
|
1825
1847
|
// #2073 added. A convention one shipped lane already violates is not a contract.
|
|
1826
1848
|
'modelConfigKey',
|
|
1849
|
+
// `timeoutConfigKey` added by #3274, same optional/backward-compatible shape as
|
|
1850
|
+
// `modelConfigKey` above: a manifest authored before this field existed must keep validating.
|
|
1851
|
+
'timeoutConfigKey',
|
|
1852
|
+
// `effortConfigKey` / `defaultEffort` added by #4255, same optional/backward-compatible shape
|
|
1853
|
+
// as the two above. Lane effort used to be resolved by querying the `gsd-plan-checker` AGENT
|
|
1854
|
+
// through a hardcoded id, so every prompt-fed lane ran at that verifier's frontmatter effort;
|
|
1855
|
+
// it is a property of the review, so the lane declares it. A manifest authored before these
|
|
1856
|
+
// fields existed must keep validating — absent is read as "this lane declares no review
|
|
1857
|
+
// effort", which emits no effort argument at all.
|
|
1858
|
+
'effortConfigKey',
|
|
1859
|
+
'defaultEffort',
|
|
1827
1860
|
'handler',
|
|
1828
1861
|
]);
|
|
1829
1862
|
|
|
1863
|
+
/**
|
|
1864
|
+
* The effort levels a lane may declare as its review default (#4255, #3533 vocabulary).
|
|
1865
|
+
*
|
|
1866
|
+
* `inherit` is deliberately NOT a member. It is a legitimate CONFIGURED value — it selects "emit
|
|
1867
|
+
* no argument, the CLI's own configuration decides" — but as a DECLARED default it would be a
|
|
1868
|
+
* second spelling of `null` and split one behaviour across two shapes.
|
|
1869
|
+
*/
|
|
1870
|
+
const REVIEWER_EFFORT_LEVELS = new Set(['minimal', 'low', 'medium', 'high', 'xhigh', 'max']);
|
|
1871
|
+
|
|
1830
1872
|
/**
|
|
1831
1873
|
* The closed `runtime.hostBehaviors` vocabulary (ADR-1016, closed via #2801).
|
|
1832
1874
|
*
|
|
@@ -2371,6 +2413,50 @@ function validateReviewerBodyFields(cap) {
|
|
|
2371
2413
|
);
|
|
2372
2414
|
}
|
|
2373
2415
|
|
|
2416
|
+
// OPTIONAL, mirroring modelConfigKey's D4 forward/backward-compat treatment (#3274): a manifest
|
|
2417
|
+
// authored before this field existed must keep validating. Absent/null means "no override for
|
|
2418
|
+
// this lane, use timeoutFloorMs". An empty string is neither absent nor a key, and is rejected.
|
|
2419
|
+
if (r.timeoutConfigKey !== undefined && r.timeoutConfigKey !== null &&
|
|
2420
|
+
(typeof r.timeoutConfigKey !== 'string' || r.timeoutConfigKey.length === 0)) {
|
|
2421
|
+
errors.push(
|
|
2422
|
+
ctx + ' reviewer.timeoutConfigKey must be a dotted config key or null ' +
|
|
2423
|
+
'(got: ' + describeValue(r.timeoutConfigKey) + ')',
|
|
2424
|
+
);
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
// OPTIONAL, mirroring the two keys above (#4255). Absent/null means "this lane declares no
|
|
2428
|
+
// review effort", which is the shape that emits no effort argument at all — the correct state
|
|
2429
|
+
// for the nine lanes with no effort channel to feed. An empty string is neither.
|
|
2430
|
+
if (r.effortConfigKey !== undefined && r.effortConfigKey !== null &&
|
|
2431
|
+
(typeof r.effortConfigKey !== 'string' || r.effortConfigKey.length === 0)) {
|
|
2432
|
+
errors.push(
|
|
2433
|
+
ctx + ' reviewer.effortConfigKey must be a dotted config key or null ' +
|
|
2434
|
+
'(got: ' + describeValue(r.effortConfigKey) + ')',
|
|
2435
|
+
);
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
// A declared default must be a level the effort axis knows, or the lane would render an
|
|
2439
|
+
// argument the reviewer CLI rejects and kill itself on every run. Closed vocabulary, checked
|
|
2440
|
+
// here rather than at resolution time so a malformed manifest fails at the trust boundary.
|
|
2441
|
+
if (r.defaultEffort !== undefined && r.defaultEffort !== null
|
|
2442
|
+
&& !(typeof r.defaultEffort === 'string' && REVIEWER_EFFORT_LEVELS.has(r.defaultEffort))) {
|
|
2443
|
+
errors.push(
|
|
2444
|
+
ctx + ' reviewer.defaultEffort must be one of ' +
|
|
2445
|
+
Array.from(REVIEWER_EFFORT_LEVELS).join('/') + ' or null ' +
|
|
2446
|
+
'(got: ' + describeValue(r.defaultEffort) + ')',
|
|
2447
|
+
);
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
// A default with nothing to configure it through is a value the operator cannot change — the
|
|
2451
|
+
// shape #4255 exists to end. Declared together or not at all.
|
|
2452
|
+
if ((r.defaultEffort !== undefined && r.defaultEffort !== null)
|
|
2453
|
+
&& (r.effortConfigKey === undefined || r.effortConfigKey === null)) {
|
|
2454
|
+
errors.push(
|
|
2455
|
+
ctx + ' reviewer.defaultEffort is declared without an effortConfigKey, so the level ' +
|
|
2456
|
+
'could never be overridden',
|
|
2457
|
+
);
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2374
2460
|
// `null` is the declared "no per-lane budget"; an empty string is not.
|
|
2375
2461
|
if (r.promptBudgetKey !== null && (typeof r.promptBudgetKey !== 'string' || r.promptBudgetKey.length === 0)) {
|
|
2376
2462
|
errors.push(
|
|
@@ -2858,6 +2944,10 @@ function validateStep(step, prefix, declaredSkills, declaredAgents) {
|
|
|
2858
2944
|
errors.push(prefix + '.when must be a string if present');
|
|
2859
2945
|
}
|
|
2860
2946
|
|
|
2947
|
+
if (step.pointFrom !== undefined && typeof step.pointFrom !== 'string') {
|
|
2948
|
+
errors.push(prefix + '.pointFrom must be a string if present');
|
|
2949
|
+
}
|
|
2950
|
+
|
|
2861
2951
|
if (step.fragment !== undefined) {
|
|
2862
2952
|
errors.push(...validateFragment(step.fragment, prefix + '.fragment'));
|
|
2863
2953
|
}
|
|
@@ -2997,6 +3087,31 @@ function validateAgainstContract(cap, capId) {
|
|
|
2997
3087
|
}
|
|
2998
3088
|
}
|
|
2999
3089
|
|
|
3090
|
+
// pointFrom (#3661): selects which of possibly several same-capability steps is
|
|
3091
|
+
// active for its own `point`, based on an enum config key. Require it references
|
|
3092
|
+
// an enum key in cap.config whose values include THIS step's own point — otherwise
|
|
3093
|
+
// the step could never activate (a silently-dead step).
|
|
3094
|
+
for (const step of cap.steps) {
|
|
3095
|
+
if (step.pointFrom !== undefined) {
|
|
3096
|
+
if (typeof step.pointFrom !== 'string') continue; // already reported above
|
|
3097
|
+
const slice = typeof cap.config === 'object' && cap.config !== null ? cap.config[step.pointFrom] : undefined;
|
|
3098
|
+
if (!slice || typeof slice !== 'object') {
|
|
3099
|
+
errors.push(
|
|
3100
|
+
prefix + ' step.pointFrom "' + step.pointFrom + '" is not defined in capability config keys',
|
|
3101
|
+
);
|
|
3102
|
+
} else if (slice.type !== 'enum') {
|
|
3103
|
+
errors.push(
|
|
3104
|
+
prefix + ' step.pointFrom "' + step.pointFrom + '" must reference an enum config key (got type: ' + slice.type + ')',
|
|
3105
|
+
);
|
|
3106
|
+
} else if (!Array.isArray(slice.values) || !slice.values.includes(step.point)) {
|
|
3107
|
+
errors.push(
|
|
3108
|
+
prefix + ' step.pointFrom "' + step.pointFrom + '" enum values do not include this step\'s own point "' +
|
|
3109
|
+
step.point + '" — the step could never activate',
|
|
3110
|
+
);
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
|
|
3000
3115
|
for (const contrib of cap.contributions) {
|
|
3001
3116
|
if (contrib.when !== undefined) {
|
|
3002
3117
|
if (typeof contrib.when !== 'string') continue;
|
|
@@ -3605,11 +3720,12 @@ const HOOK_GROUP_KINDS = Object.freeze({
|
|
|
3605
3720
|
* double-report.
|
|
3606
3721
|
*
|
|
3607
3722
|
* KNOWN LIMITATION (#3606): coverage is the UNION across all call sites for a
|
|
3608
|
-
* point in
|
|
3609
|
-
*
|
|
3723
|
+
* point in HOST_LOOP_FILES. Quick's plan:pre planner contribution seam has an
|
|
3724
|
+
* additional generator-owned per-file check. Other consumers outside that
|
|
3725
|
+
* universe (autonomous.md, code-review*.md, audit-milestone.md,
|
|
3610
3726
|
* secure-phase.md, validate-phase.md) are not per-file checked — a narrowed
|
|
3611
|
-
* consumer there passes as long as one host file covers the point.
|
|
3612
|
-
* coverage maps are the tightening path.
|
|
3727
|
+
* consumer there passes as long as one host file covers the point. More
|
|
3728
|
+
* per-file coverage maps are the tightening path.
|
|
3613
3729
|
*
|
|
3614
3730
|
* @param {object} cap Validated capability object.
|
|
3615
3731
|
* @param {Map<string, Set<string>>} wiredKinds Per point, the hook kinds the
|
|
@@ -184,6 +184,7 @@ function setCapabilityState(cwd, runtimeConfigDir, desired, opts) {
|
|
|
184
184
|
};
|
|
185
185
|
}
|
|
186
186
|
// ── Step 4: APPLY PASS ────────────────────────────────────────────────────
|
|
187
|
+
let pendingSurfaceForCommit;
|
|
187
188
|
// ── Surface writes ────────────────────────────────────────────────────────
|
|
188
189
|
if (needsSurface && (idsToDisable.length > 0 || idsToEnable.length > 0)) {
|
|
189
190
|
const existing = readSurface(resolvedConfigDir);
|
|
@@ -242,13 +243,19 @@ function setCapabilityState(cwd, runtimeConfigDir, desired, opts) {
|
|
|
242
243
|
}
|
|
243
244
|
}
|
|
244
245
|
if (surfaceChanged) {
|
|
245
|
-
|
|
246
|
+
pendingSurfaceForCommit = pendingSurface;
|
|
246
247
|
}
|
|
247
248
|
}
|
|
248
249
|
// ── Config writes (once, batched) ─────────────────────────────────────────
|
|
249
250
|
if (pendingGateWrites.length > 0) {
|
|
250
251
|
setConfigValues(cwd, pendingGateWrites);
|
|
251
252
|
}
|
|
253
|
+
// State-only callers preserve the existing direct-write behavior. A caller
|
|
254
|
+
// that requests materialization lets applySurface publish the candidate only
|
|
255
|
+
// after every artifact kind has staged and synchronized successfully.
|
|
256
|
+
if (pendingSurfaceForCommit && !opts?.materialize) {
|
|
257
|
+
writeSurface(resolvedConfigDir, pendingSurfaceForCommit);
|
|
258
|
+
}
|
|
252
259
|
// ── Materialize (optional) ────────────────────────────────────────────────
|
|
253
260
|
if (opts?.materialize) {
|
|
254
261
|
const { runtime, scope } = opts.materialize;
|
|
@@ -274,9 +281,12 @@ function setCapabilityState(cwd, runtimeConfigDir, desired, opts) {
|
|
|
274
281
|
// folded:issue-1575-agent-descriptor-parity describe block in
|
|
275
282
|
// tests/golden-parity-single-source.test.cjs).
|
|
276
283
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
277
|
-
applySurface(resolvedConfigDir, layout, manifest, undefined, registry,
|
|
278
|
-
? {
|
|
279
|
-
|
|
284
|
+
applySurface(resolvedConfigDir, layout, manifest, undefined, registry, {
|
|
285
|
+
...(pendingSurfaceForCommit ? { surfaceState: pendingSurfaceForCommit } : {}),
|
|
286
|
+
...(opts.materialize.resolveAttribution
|
|
287
|
+
? { resolveAttribution: opts.materialize.resolveAttribution }
|
|
288
|
+
: {}),
|
|
289
|
+
});
|
|
280
290
|
}
|
|
281
291
|
catch (err) {
|
|
282
292
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -31,7 +31,7 @@ const ui_safety_gate_cjs_1 = require("./ui-safety-gate.cjs");
|
|
|
31
31
|
const ui_frontend_evidence_cjs_1 = require("./ui-frontend-evidence.cjs");
|
|
32
32
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
33
33
|
const verifyModule = require("./verify.cjs");
|
|
34
|
-
const { cmdVerifySchemaDrift, cmdVerifyCodebaseDrift } = verifyModule;
|
|
34
|
+
const { cmdVerifySchemaDrift, cmdVerifyCodebaseDrift, cmdVerifyContextDrift } = verifyModule;
|
|
35
35
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
36
36
|
const roadmapModule = require("./roadmap.cjs");
|
|
37
37
|
const { getRoadmapPhaseWithFallback } = roadmapModule;
|
|
@@ -39,6 +39,7 @@ const { getRoadmapPhaseWithFallback } = roadmapModule;
|
|
|
39
39
|
const gapCheckerModule = require("./gap-checker.cjs");
|
|
40
40
|
const { runGapAnalysis } = gapCheckerModule;
|
|
41
41
|
const prohibition_enforcement_cjs_1 = require("./prohibition-enforcement.cjs");
|
|
42
|
+
const tdd_red_evidence_cjs_1 = require("./tdd-red-evidence.cjs");
|
|
42
43
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
43
44
|
const gatePredicateEval = require("./gate-predicate-evaluator.cjs");
|
|
44
45
|
const { evaluatePredicate } = gatePredicateEval;
|
|
@@ -825,6 +826,74 @@ function cmdTddReviewCheckpoint(projectDir, args, raw) {
|
|
|
825
826
|
// the host-loop dispatch's advisory branch can surface it.
|
|
826
827
|
output(result, raw, undefined);
|
|
827
828
|
}
|
|
829
|
+
// ─── tdd-red-evidence (#3770) ──────────────────────────────────────────────────
|
|
830
|
+
/**
|
|
831
|
+
* tdd-red-evidence: validates a persisted RED-phase test-run record for a
|
|
832
|
+
* `type: tdd` plan (#3770). Only an INTENTIONAL failure of the target test
|
|
833
|
+
* (verdict RED_EVIDENCE_OK) may authorize GREEN; zero-test discovery, fixture/
|
|
834
|
+
* load crashes, nonzero exits without a failing test, unrelated failures, and
|
|
835
|
+
* unexpected greens are INVALID_RED and block GREEN.
|
|
836
|
+
*
|
|
837
|
+
* The record is the JSON the executor persists after running the RED command:
|
|
838
|
+
* { command, exitCode, output, targetTest, targetFile?, expected?, actual? }
|
|
839
|
+
* Fail-closed: a missing/unreadable/unparseable record is INVALID_RED
|
|
840
|
+
* (reason unreadable_record), never a pass.
|
|
841
|
+
*
|
|
842
|
+
* Args: check tdd-red-evidence <record.json>
|
|
843
|
+
*/
|
|
844
|
+
function cmdTddRedEvidence(_projectDir, args, raw) {
|
|
845
|
+
const recordPath = typeof args[2] === 'string' ? args[2] : '';
|
|
846
|
+
if (!recordPath) {
|
|
847
|
+
error('tdd-red-evidence requires a record path: check tdd-red-evidence <record.json>', ERROR_REASON.SDK_MISSING_ARG);
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
const resolved = node_path_1.default.resolve(recordPath);
|
|
851
|
+
const text = readIfExists(resolved);
|
|
852
|
+
const input = (() => {
|
|
853
|
+
if (!text)
|
|
854
|
+
return null;
|
|
855
|
+
try {
|
|
856
|
+
return (JSON.parse(text) ?? {});
|
|
857
|
+
}
|
|
858
|
+
catch {
|
|
859
|
+
return null;
|
|
860
|
+
}
|
|
861
|
+
})();
|
|
862
|
+
if (!input) {
|
|
863
|
+
output({
|
|
864
|
+
passed: false,
|
|
865
|
+
block: true,
|
|
866
|
+
verdict: 'INVALID_RED',
|
|
867
|
+
reason: 'unreadable_record',
|
|
868
|
+
record: resolved,
|
|
869
|
+
readError: text ? `record is not valid JSON: ${resolved}` : `record not found or unreadable: ${resolved}`,
|
|
870
|
+
}, raw, undefined);
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
const evidenceInput = {
|
|
874
|
+
command: input['command'],
|
|
875
|
+
exitCode: input['exitCode'],
|
|
876
|
+
output: input['output'],
|
|
877
|
+
targetTest: input['targetTest'],
|
|
878
|
+
targetFile: input['targetFile'],
|
|
879
|
+
expected: input['expected'],
|
|
880
|
+
actual: input['actual'],
|
|
881
|
+
};
|
|
882
|
+
const result = (0, tdd_red_evidence_cjs_1.classifyRedEvidence)(evidenceInput);
|
|
883
|
+
const record = (0, tdd_red_evidence_cjs_1.buildRedEvidenceRecord)(evidenceInput, result);
|
|
884
|
+
output({
|
|
885
|
+
// Uniform gate contract: block = !passed. INVALID_RED blocks GREEN.
|
|
886
|
+
passed: result.verdict === 'RED_EVIDENCE_OK',
|
|
887
|
+
block: result.verdict !== 'RED_EVIDENCE_OK',
|
|
888
|
+
verdict: result.verdict,
|
|
889
|
+
reason: result.reason,
|
|
890
|
+
evidence: result.evidence,
|
|
891
|
+
record,
|
|
892
|
+
message: result.verdict === 'RED_EVIDENCE_OK'
|
|
893
|
+
? `RED evidence verified: target test "${result.evidence.target_test}" failed as expected (exit ${result.evidence.exit_code}). GREEN authorized.`
|
|
894
|
+
: `INVALID_RED (${result.reason}): GREEN blocked. Fix the RED phase — only an intentional failure of target test "${result.evidence.target_test}" authorizes production edits.`,
|
|
895
|
+
}, raw, undefined);
|
|
896
|
+
}
|
|
828
897
|
/**
|
|
829
898
|
* Resolve a phase argument to an absolute phase directory, or '' when it
|
|
830
899
|
* cannot be resolved. Shared by every `check` arm that probes a phase's
|
|
@@ -1472,6 +1541,12 @@ function routeCheckCommand({ args, cwd, raw }) {
|
|
|
1472
1541
|
cmdTddReviewCheckpoint(cwd, args, raw);
|
|
1473
1542
|
return;
|
|
1474
1543
|
}
|
|
1544
|
+
if (subcommand === 'tdd-red-evidence') {
|
|
1545
|
+
// #3770: intentional-RED evidence gate — only a target-test failure may
|
|
1546
|
+
// authorize GREEN. Validates the persisted record; never executes anything.
|
|
1547
|
+
cmdTddRedEvidence(cwd, args, raw);
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1475
1550
|
if (subcommand === 'ui-safety-gate') {
|
|
1476
1551
|
cmdUiSafetyGate(cwd, args, raw);
|
|
1477
1552
|
return;
|
|
@@ -1491,6 +1566,13 @@ function routeCheckCommand({ args, cwd, raw }) {
|
|
|
1491
1566
|
cmdVerifyCodebaseDrift(cwd, raw);
|
|
1492
1567
|
return;
|
|
1493
1568
|
}
|
|
1569
|
+
if (subcommand === 'verify-context-drift') {
|
|
1570
|
+
// Delegates to verify.context-drift — drift capability gate at plan:pre (non-blocking).
|
|
1571
|
+
// Dot-to-hyphen normalization means query "verify.context-drift" routes here.
|
|
1572
|
+
const phaseArg = typeof args[2] === 'string' ? args[2] : '';
|
|
1573
|
+
cmdVerifyContextDrift(cwd, phaseArg, raw);
|
|
1574
|
+
return;
|
|
1575
|
+
}
|
|
1494
1576
|
if (subcommand === 'predicate') {
|
|
1495
1577
|
// Generic gate-predicate evaluator (#2008). The workflow gate-dispatch calls
|
|
1496
1578
|
// this for any gate whose `check` carries a `predicate` (instead of a `query`),
|
|
@@ -1508,7 +1590,7 @@ function routeCheckCommand({ args, cwd, raw }) {
|
|
|
1508
1590
|
(0, prohibition_enforcement_cjs_1.routeProhibitionEnforcement)(args, raw);
|
|
1509
1591
|
return;
|
|
1510
1592
|
}
|
|
1511
|
-
error('Unknown check subcommand. Available: api-coverage-verify-pre, auto-mode, decision-coverage-plan, decision-coverage-verify, gap-analysis-plan-post, predicate, prohibition-enforcement, tdd-review-checkpoint, ui-plan-gate, ui-safety-gate, verify-command-paths, verify-failure-directions, verify-schema-drift, verify-codebase-drift', ERROR_REASON.SDK_UNKNOWN_COMMAND);
|
|
1593
|
+
error('Unknown check subcommand. Available: api-coverage-verify-pre, auto-mode, decision-coverage-plan, decision-coverage-verify, gap-analysis-plan-post, predicate, prohibition-enforcement, tdd-red-evidence, tdd-review-checkpoint, ui-plan-gate, ui-safety-gate, verify-command-paths, verify-failure-directions, verify-schema-drift, verify-codebase-drift, verify-context-drift', ERROR_REASON.SDK_UNKNOWN_COMMAND);
|
|
1512
1594
|
}
|
|
1513
1595
|
module.exports = {
|
|
1514
1596
|
routeCheckCommand,
|
|
@@ -1520,6 +1602,7 @@ module.exports = {
|
|
|
1520
1602
|
cmdVerifyCommandPaths,
|
|
1521
1603
|
cmdVerifyFailureDirections,
|
|
1522
1604
|
cmdTddReviewCheckpoint,
|
|
1605
|
+
cmdTddRedEvidence,
|
|
1523
1606
|
cmdCheckPredicate,
|
|
1524
1607
|
buildPredicateDeps,
|
|
1525
1608
|
parsePredicateFlags,
|
|
@@ -43,6 +43,9 @@
|
|
|
43
43
|
*
|
|
44
44
|
* Zero external dependencies. Pure functions. Never throws on bad input.
|
|
45
45
|
*/
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- file-overlap-partitioner.cjs is an export= CommonJS module
|
|
47
|
+
const fileOverlapPartitionerMod = require("./file-overlap-partitioner.cjs");
|
|
48
|
+
const { partitionByFileOverlap } = fileOverlapPartitionerMod;
|
|
46
49
|
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
47
50
|
/**
|
|
48
51
|
* The Agent SDK version that introduced the Workflow tool (#1143 prior art).
|
|
@@ -226,33 +229,15 @@ function detectWorkflowBackend(input) {
|
|
|
226
229
|
*
|
|
227
230
|
* This is the same overlap rule execute-phase applies inline — the only difference
|
|
228
231
|
* is the execution vehicle (Workflow `parallel()` vs one-agent-per-message).
|
|
232
|
+
*
|
|
233
|
+
* #3674: the algorithm itself now lives in the generic, dependency-free
|
|
234
|
+
* `file-overlap-partitioner.cts` module (`partitionByFileOverlap`) — this is a
|
|
235
|
+
* thin adapter mapping this module's own `Plan[]` shape onto that module's
|
|
236
|
+
* generic `{ id, files }[]` input and back. Behavior-preserving extraction:
|
|
237
|
+
* same greedy first-fit algorithm, same output, only the implementation moved.
|
|
229
238
|
*/
|
|
230
239
|
function partitionStages(plans) {
|
|
231
|
-
|
|
232
|
-
for (const plan of plans) {
|
|
233
|
-
const fileSet = new Set(plan.files_modified);
|
|
234
|
-
let placed = false;
|
|
235
|
-
for (const stage of stages) {
|
|
236
|
-
let overlap = false;
|
|
237
|
-
for (const f of fileSet) {
|
|
238
|
-
if (stage.files.has(f)) {
|
|
239
|
-
overlap = true;
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
if (!overlap) {
|
|
244
|
-
stage.plans.push(plan);
|
|
245
|
-
for (const f of fileSet)
|
|
246
|
-
stage.files.add(f);
|
|
247
|
-
placed = true;
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
if (!placed) {
|
|
252
|
-
stages.push({ plans: [plan], files: new Set(fileSet) });
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return stages.map((s) => s.plans.map((p) => p.id));
|
|
240
|
+
return partitionByFileOverlap(plans.map((p) => ({ id: p.id, files: p.files_modified })));
|
|
256
241
|
}
|
|
257
242
|
/**
|
|
258
243
|
* Quote a free-text value for safe embedding as a JavaScript/Workflow double-quoted
|
|
@@ -248,6 +248,14 @@ exports.VERIFY_COMMAND_ALIASES = [
|
|
|
248
248
|
],
|
|
249
249
|
"subcommand": "codebase-drift",
|
|
250
250
|
"mutation": false
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"canonical": "verify.context-drift",
|
|
254
|
+
"aliases": [
|
|
255
|
+
"verify context-drift"
|
|
256
|
+
],
|
|
257
|
+
"subcommand": "context-drift",
|
|
258
|
+
"mutation": false
|
|
251
259
|
}
|
|
252
260
|
];
|
|
253
261
|
exports.INIT_COMMAND_ALIASES = [
|
|
@@ -299,6 +307,14 @@ exports.INIT_COMMAND_ALIASES = [
|
|
|
299
307
|
"subcommand": "quick",
|
|
300
308
|
"mutation": false
|
|
301
309
|
},
|
|
310
|
+
{
|
|
311
|
+
"canonical": "init.quick-batch",
|
|
312
|
+
"aliases": [
|
|
313
|
+
"init quick-batch"
|
|
314
|
+
],
|
|
315
|
+
"subcommand": "quick-batch",
|
|
316
|
+
"mutation": false
|
|
317
|
+
},
|
|
302
318
|
{
|
|
303
319
|
"canonical": "init.ingest-docs",
|
|
304
320
|
"aliases": [
|