@mjasnikovs/pi-task 0.38.29 → 0.38.30
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/dist/config/config.d.ts +70 -70
- package/dist/config/config.js +26 -35
- package/dist/config/extension-list.d.ts +6 -5
- package/dist/config/extension-list.js +3 -2
- package/dist/config/reasoning-args.d.ts +9 -7
- package/dist/config/reasoning-args.js +12 -10
- package/dist/config/reasoning.d.ts +44 -105
- package/dist/config/reasoning.js +27 -704
- package/dist/config/register.d.ts +34 -48
- package/dist/config/register.js +41 -51
- package/dist/config/tool-list.d.ts +16 -16
- package/dist/config/tool-list.js +1 -1
- package/dist/remote/bridge.d.ts +19 -10
- package/dist/remote/bridge.js +3 -2
- package/dist/remote/broadcast.js +3 -1
- package/dist/remote/events.js +12 -11
- package/dist/remote/history.d.ts +1 -1
- package/dist/remote/protocol.d.ts +6 -3
- package/dist/remote/protocol.js +2 -1
- package/dist/remote/push.d.ts +16 -16
- package/dist/remote/push.js +27 -27
- package/dist/remote/register.d.ts +3 -3
- package/dist/remote/register.js +17 -19
- package/dist/remote/server.d.ts +9 -8
- package/dist/remote/server.js +15 -14
- package/dist/remote/session-state.d.ts +5 -4
- package/dist/remote/session-state.js +8 -5
- package/dist/remote/sw.d.ts +7 -6
- package/dist/remote/sw.js +7 -6
- package/dist/remote/tailscale.d.ts +4 -2
- package/dist/remote/tailscale.js +4 -2
- package/dist/remote/ui-highlight.js +6 -5
- package/dist/remote/ui-render.js +4 -4
- package/dist/remote/ui-script.js +24 -24
- package/dist/remote/ui-styles.d.ts +1 -1
- package/dist/remote/ui-styles.js +10 -13
- package/dist/remote/ui-tools.js +9 -6
- package/dist/shared/child-extensions.d.ts +29 -17
- package/dist/shared/child-extensions.js +29 -17
- package/dist/shared/child-output.d.ts +30 -24
- package/dist/shared/child-output.js +25 -17
- package/dist/shared/child-process.d.ts +47 -40
- package/dist/shared/child-process.js +50 -59
- package/dist/shared/command-watchdog.d.ts +22 -16
- package/dist/shared/command-watchdog.js +28 -21
- package/dist/shared/fs-text.d.ts +16 -10
- package/dist/shared/fs-text.js +16 -10
- package/dist/shared/git-runner.d.ts +25 -25
- package/dist/shared/git-runner.js +25 -25
- package/dist/shared/leaked-tool-call.d.ts +17 -11
- package/dist/shared/leaked-tool-call.js +23 -15
- package/dist/shared/model-endpoint.d.ts +29 -16
- package/dist/shared/model-endpoint.js +33 -21
- package/dist/shared/pi-invocation.d.ts +7 -4
- package/dist/shared/pi-invocation.js +12 -7
- package/dist/shared/pkg-version.d.ts +13 -5
- package/dist/shared/pkg-version.js +13 -5
- package/dist/shared/reasoning-capability.d.ts +35 -24
- package/dist/shared/reasoning-capability.js +35 -24
- package/dist/shared/stream-watchdog.d.ts +60 -44
- package/dist/shared/stream-watchdog.js +62 -45
- package/dist/task/accept-debt.d.ts +41 -43
- package/dist/task/accept-debt.js +73 -65
- package/dist/task/api-synthesis.d.ts +24 -21
- package/dist/task/api-synthesis.js +32 -26
- package/dist/task/apis-contract.d.ts +32 -64
- package/dist/task/apis-contract.js +32 -64
- package/dist/task/artifact-closure.d.ts +27 -13
- package/dist/task/artifact-closure.js +95 -67
- package/dist/task/auto-commit.d.ts +46 -35
- package/dist/task/auto-commit.js +51 -38
- package/dist/task/auto-io.d.ts +45 -25
- package/dist/task/auto-io.js +57 -29
- package/dist/task/auto-orchestrator.d.ts +26 -24
- package/dist/task/auto-orchestrator.js +178 -162
- package/dist/task/auto-prompts.d.ts +36 -24
- package/dist/task/auto-prompts.js +40 -26
- package/dist/task/autofix-ledger.d.ts +27 -25
- package/dist/task/autofix-ledger.js +29 -26
- package/dist/task/batch-test-task.d.ts +20 -12
- package/dist/task/batch-test-task.js +67 -60
- package/dist/task/boot-probe.d.ts +60 -44
- package/dist/task/boot-probe.js +91 -72
- package/dist/task/cancel-input.d.ts +30 -16
- package/dist/task/cancel-input.js +20 -11
- package/dist/task/cancel-points.d.ts +27 -20
- package/dist/task/cancel-points.js +30 -22
- package/dist/task/child-runner.d.ts +46 -51
- package/dist/task/child-runner.js +48 -49
- package/dist/task/child-status.d.ts +23 -16
- package/dist/task/child-status.js +23 -16
- package/dist/task/clamp-output.js +12 -5
- package/dist/task/command-run.d.ts +31 -28
- package/dist/task/command-run.js +44 -35
- package/dist/task/command-shrink.d.ts +25 -18
- package/dist/task/command-shrink.js +37 -31
- package/dist/task/command-watchdog.d.ts +9 -6
- package/dist/task/command-watchdog.js +21 -15
- package/dist/task/context-attribution.d.ts +34 -26
- package/dist/task/context-attribution.js +34 -26
- package/dist/task/context-silence.d.ts +39 -29
- package/dist/task/context-silence.js +35 -25
- package/dist/task/context-usage.d.ts +16 -9
- package/dist/task/context-usage.js +16 -9
- package/dist/task/contracts.d.ts +8 -4
- package/dist/task/contracts.js +25 -17
- package/dist/task/coverage-loop.d.ts +22 -18
- package/dist/task/coverage-loop.js +35 -30
- package/dist/task/critique-probes.d.ts +13 -14
- package/dist/task/critique-probes.js +50 -39
- package/dist/task/debug-log.d.ts +13 -5
- package/dist/task/debug-log.js +32 -20
- package/dist/task/decompose-fidelity.d.ts +11 -9
- package/dist/task/decompose-fidelity.js +38 -33
- package/dist/task/decompose-granularity.d.ts +41 -38
- package/dist/task/decompose-granularity.js +41 -38
- package/dist/task/deep-render-check.d.ts +22 -14
- package/dist/task/deep-render-check.js +40 -31
- package/dist/task/dropped-input.d.ts +12 -7
- package/dist/task/dropped-input.js +5 -2
- package/dist/task/enforce-attribution.d.ts +38 -47
- package/dist/task/enforce-attribution.js +46 -52
- package/dist/task/enforce-guidelines.d.ts +31 -20
- package/dist/task/enforce-guidelines.js +32 -21
- package/dist/task/enrichment.d.ts +7 -2
- package/dist/task/enrichment.js +26 -14
- package/dist/task/env-notes.d.ts +16 -7
- package/dist/task/env-notes.js +48 -31
- package/dist/task/env-template-closure.d.ts +4 -4
- package/dist/task/env-template-closure.js +42 -34
- package/dist/task/external-context.d.ts +28 -21
- package/dist/task/external-context.js +17 -12
- package/dist/task/failure-classifier.d.ts +4 -5
- package/dist/task/failure-classifier.js +6 -7
- package/dist/task/file-inventory.d.ts +15 -11
- package/dist/task/file-inventory.js +25 -22
- package/dist/task/final-gate-fix.d.ts +74 -86
- package/dist/task/final-gate-fix.js +97 -116
- package/dist/task/final-gate-progress.d.ts +29 -46
- package/dist/task/final-gate-progress.js +40 -51
- package/dist/task/final-gate.d.ts +64 -97
- package/dist/task/final-gate.js +192 -199
- package/dist/task/fix-child.d.ts +21 -27
- package/dist/task/fix-child.js +21 -27
- package/dist/task/foreign-path.d.ts +6 -5
- package/dist/task/foreign-path.js +0 -0
- package/dist/task/frozen-conflict.d.ts +9 -10
- package/dist/task/frozen-conflict.js +61 -64
- package/dist/task/frozen-path-guard.d.ts +35 -14
- package/dist/task/frozen-path-guard.js +56 -39
- package/dist/task/gate-child.d.ts +27 -28
- package/dist/task/gate-child.js +36 -35
- package/dist/task/gate-deps.d.ts +34 -27
- package/dist/task/gate-deps.js +169 -159
- package/dist/task/gate-tally.d.ts +77 -80
- package/dist/task/gate-tally.js +65 -68
- package/dist/task/git-state-guard.d.ts +15 -11
- package/dist/task/git-state-guard.js +76 -66
- package/dist/task/impl-widget.d.ts +25 -16
- package/dist/task/impl-widget.js +27 -17
- package/dist/task/implementation-thinking.d.ts +33 -31
- package/dist/task/implementation-thinking.js +5 -6
- package/dist/task/implementation-turn.d.ts +34 -31
- package/dist/task/implementation-turn.js +29 -27
- package/dist/task/inline-markdown.d.ts +20 -7
- package/dist/task/inline-markdown.js +15 -6
- package/dist/task/launch-config-gap.js +25 -39
- package/dist/task/launch-contract.d.ts +18 -21
- package/dist/task/launch-contract.js +28 -30
- package/dist/task/launch-manifest.d.ts +6 -2
- package/dist/task/launch-manifest.js +35 -34
- package/dist/task/ledger.js +16 -14
- package/dist/task/lint-fix.d.ts +6 -8
- package/dist/task/lint-fix.js +67 -69
- package/dist/task/loop-detector.d.ts +9 -8
- package/dist/task/loop-detector.js +16 -12
- package/dist/task/mid-run-input.d.ts +17 -15
- package/dist/task/mid-run-input.js +17 -15
- package/dist/task/orchestrator.d.ts +24 -28
- package/dist/task/orchestrator.js +62 -64
- package/dist/task/orientation.d.ts +18 -23
- package/dist/task/orientation.js +24 -31
- package/dist/task/owned-freeze-conflict.d.ts +21 -20
- package/dist/task/owned-freeze-conflict.js +52 -85
- package/dist/task/owned-freeze-reassign.d.ts +40 -60
- package/dist/task/owned-freeze-reassign.js +41 -61
- package/dist/task/parsers.d.ts +4 -2
- package/dist/task/parsers.js +4 -4
- package/dist/task/phases.d.ts +41 -48
- package/dist/task/phases.js +179 -248
- package/dist/task/plan-io.d.ts +6 -7
- package/dist/task/plan-io.js +6 -7
- package/dist/task/plan-orchestrator.d.ts +10 -8
- package/dist/task/plan-orchestrator.js +14 -10
- package/dist/task/plan-prompts.d.ts +6 -5
- package/dist/task/plan-prompts.js +6 -5
- package/dist/task/plan-readonly.d.ts +4 -5
- package/dist/task/plan-readonly.js +4 -5
- package/dist/task/plan-rounds.d.ts +17 -29
- package/dist/task/plan-rounds.js +21 -34
- package/dist/task/plan-session.d.ts +58 -72
- package/dist/task/plan-session.js +61 -83
- package/dist/task/probe-gaming.d.ts +28 -27
- package/dist/task/probe-gaming.js +0 -0
- package/dist/task/prohibition-probe.d.ts +14 -16
- package/dist/task/prompts.d.ts +3 -4
- package/dist/task/prompts.js +17 -26
- package/dist/task/qa-transcript.d.ts +15 -22
- package/dist/task/qa-transcript.js +15 -21
- package/dist/task/question-box.d.ts +17 -13
- package/dist/task/question-box.js +19 -15
- package/dist/task/question-dedup.d.ts +6 -7
- package/dist/task/question-dedup.js +13 -14
- package/dist/task/question-dialog.d.ts +22 -32
- package/dist/task/question-dialog.js +22 -32
- package/dist/task/question-source.d.ts +18 -44
- package/dist/task/question-source.js +22 -51
- package/dist/task/refuted-constraint.d.ts +11 -31
- package/dist/task/refuted-constraint.js +27 -51
- package/dist/task/regenerable-artifacts.d.ts +12 -31
- package/dist/task/regenerable-artifacts.js +12 -31
- package/dist/task/render-check.d.ts +11 -22
- package/dist/task/render-check.js +33 -46
- package/dist/task/repo-health-check.d.ts +10 -14
- package/dist/task/repo-health-check.js +17 -23
- package/dist/task/requirements.d.ts +38 -71
- package/dist/task/requirements.js +78 -126
- package/dist/task/research-fanout-budget.d.ts +51 -88
- package/dist/task/research-fanout-budget.js +51 -88
- package/dist/task/research-worker.d.ts +29 -39
- package/dist/task/research-worker.js +37 -61
- package/dist/task/resume-gap.d.ts +14 -15
- package/dist/task/root-cause-repair.d.ts +9 -9
- package/dist/task/root-cause-repair.js +28 -40
- package/dist/task/run-bracket.d.ts +10 -13
- package/dist/task/run-end.d.ts +12 -22
- package/dist/task/run-end.js +8 -16
- package/dist/task/run-final-gate.d.ts +19 -21
- package/dist/task/run-final-gate.js +62 -80
- package/dist/task/runner-globs.d.ts +12 -13
- package/dist/task/runner-globs.js +12 -13
- package/dist/task/runner-resolve.d.ts +9 -9
- package/dist/task/runner-resolve.js +22 -23
- package/dist/task/script-escape.d.ts +10 -12
- package/dist/task/script-escape.js +13 -14
- package/dist/task/serve-entry.d.ts +1 -1
- package/dist/task/serve-entry.js +22 -25
- package/dist/task/service-blocks.js +4 -2
- package/dist/task/shipped-source.d.ts +11 -29
- package/dist/task/shipped-source.js +11 -29
- package/dist/task/skip-escape.js +10 -14
- package/dist/task/spec-urls.d.ts +26 -65
- package/dist/task/spec-urls.js +26 -65
- package/dist/task/spec-validation.d.ts +17 -20
- package/dist/task/spec-validation.js +17 -20
- package/dist/task/stall-detector.d.ts +23 -30
- package/dist/task/stall-detector.js +23 -30
- package/dist/task/stream-watchdog.d.ts +14 -12
- package/dist/task/stream-watchdog.js +14 -12
- package/dist/task/substitution-probe.d.ts +17 -20
- package/dist/task/substitution-probe.js +17 -20
- package/dist/task/task-gates.d.ts +36 -41
- package/dist/task/task-gates.js +95 -106
- package/dist/task/task-io.d.ts +4 -4
- package/dist/task/task-io.js +4 -4
- package/dist/task/task-parsers.js +4 -3
- package/dist/task/task-provenance.d.ts +2 -2
- package/dist/task/task-provenance.js +11 -13
- package/dist/task/task-types.d.ts +4 -3
- package/dist/task/terminal-outcome.d.ts +14 -16
- package/dist/task/terminal-outcome.js +12 -14
- package/dist/task/test-assembly.d.ts +13 -20
- package/dist/task/test-assembly.js +13 -20
- package/dist/task/timings.d.ts +5 -3
- package/dist/task/timings.js +5 -3
- package/dist/task/title-label.d.ts +9 -4
- package/dist/task/title-label.js +9 -4
- package/dist/task/type-only-answer.d.ts +44 -52
- package/dist/task/type-only-answer.js +44 -52
- package/dist/task/unfailable-command.d.ts +18 -24
- package/dist/task/unfailable-command.js +21 -27
- package/dist/task/unknown-routing.d.ts +10 -4
- package/dist/task/unknown-routing.js +10 -4
- package/dist/task/user-directives.d.ts +5 -8
- package/dist/task/user-directives.js +5 -8
- package/dist/task/verify-quality.d.ts +18 -22
- package/dist/task/verify-quality.js +45 -46
- package/dist/task/verify-reconcile.d.ts +15 -10
- package/dist/task/verify-reconcile.js +45 -43
- package/dist/task/verify-resolution.d.ts +24 -20
- package/dist/task/verify-resolution.js +51 -50
- package/dist/task/verify-work.d.ts +59 -66
- package/dist/task/verify-work.js +101 -138
- package/dist/task/widget.d.ts +15 -14
- package/dist/task/widget.js +22 -17
- package/dist/task/wiring-claims.d.ts +25 -32
- package/dist/task/wiring-claims.js +30 -35
- package/dist/task/write-guard.d.ts +39 -39
- package/dist/task/write-guard.js +48 -51
- package/dist/task/yolo.d.ts +34 -30
- package/dist/task/yolo.js +42 -37
- package/dist/workers/abstention.d.ts +21 -41
- package/dist/workers/abstention.js +27 -48
- package/dist/workers/brave-search.d.ts +4 -3
- package/dist/workers/brave-search.js +5 -2
- package/dist/workers/brave-warning.d.ts +7 -4
- package/dist/workers/brave-warning.js +19 -7
- package/dist/workers/ddg-search.d.ts +6 -6
- package/dist/workers/ddg-search.js +18 -12
- package/dist/workers/docs-cache.js +5 -2
- package/dist/workers/docs-chunk.d.ts +30 -37
- package/dist/workers/docs-chunk.js +37 -41
- package/dist/workers/docs-core.d.ts +28 -44
- package/dist/workers/docs-core.js +25 -44
- package/dist/workers/docs-index.js +4 -3
- package/dist/workers/docs-lookup.d.ts +15 -22
- package/dist/workers/docs-lookup.js +12 -21
- package/dist/workers/docs-project.d.ts +15 -9
- package/dist/workers/docs-project.js +17 -10
- package/dist/workers/docs-resolve.d.ts +19 -20
- package/dist/workers/docs-resolve.js +35 -32
- package/dist/workers/docs-retrieve.d.ts +5 -6
- package/dist/workers/docs-retrieve.js +18 -15
- package/dist/workers/exa-search.d.ts +9 -6
- package/dist/workers/exa-search.js +23 -12
- package/dist/workers/fetch-core.d.ts +13 -16
- package/dist/workers/fetch-core.js +23 -23
- package/dist/workers/focused-extractor.d.ts +12 -12
- package/dist/workers/focused-extractor.js +16 -19
- package/dist/workers/html-clean.js +24 -14
- package/dist/workers/http-request.d.ts +28 -20
- package/dist/workers/http-request.js +22 -17
- package/dist/workers/npm-version.d.ts +28 -11
- package/dist/workers/npm-version.js +24 -15
- package/dist/workers/phantom-imports.d.ts +15 -12
- package/dist/workers/phantom-imports.js +30 -24
- package/dist/workers/pi-worker-core.d.ts +69 -71
- package/dist/workers/pi-worker-core.js +100 -109
- package/dist/workers/pi-worker-docs.d.ts +24 -19
- package/dist/workers/pi-worker-docs.js +67 -76
- package/dist/workers/pi-worker-fetch.d.ts +7 -3
- package/dist/workers/pi-worker-fetch.js +27 -19
- package/dist/workers/pi-worker-search.js +12 -8
- package/dist/workers/pi-worker.d.ts +9 -4
- package/dist/workers/pi-worker.js +21 -14
- package/dist/workers/reasoning-warning.d.ts +18 -17
- package/dist/workers/reasoning-warning.js +22 -20
- package/dist/workers/research-cache.js +50 -78
- package/dist/workers/search-core.js +7 -5
- package/dist/workers/search-types.d.ts +10 -9
- package/dist/workers/search-types.js +9 -8
- package/dist/workers/session-hint.d.ts +13 -14
- package/dist/workers/session-hint.js +8 -9
- package/dist/workers/shared.d.ts +21 -25
- package/dist/workers/shared.js +0 -0
- package/dist/workers/single-read-extension.d.ts +14 -7
- package/dist/workers/single-read-extension.js +14 -7
- package/dist/workers/single-read-guard.d.ts +25 -28
- package/dist/workers/single-read-guard.js +32 -32
- package/dist/workers/typeonly-log.d.ts +12 -9
- package/dist/workers/typeonly-log.js +29 -33
- package/dist/workers/worker-channels.d.ts +15 -23
- package/dist/workers/worker-channels.js +15 -23
- package/dist/workers/worker-failure.d.ts +38 -46
- package/dist/workers/worker-failure.js +31 -39
- package/dist/workers/worker-kill.d.ts +25 -26
- package/dist/workers/worker-kill.js +16 -19
- package/dist/workers/worker-profiles.d.ts +43 -53
- package/dist/workers/worker-profiles.js +30 -38
- package/package.json +10 -8
|
@@ -6,9 +6,6 @@ import { isYoloMode, yoloFinalGateChoice, YOLO_STAMP } from './yolo.js';
|
|
|
6
6
|
import { ignoredWriteTrailLine, ignoredWriteDebtReason } from './write-guard.js';
|
|
7
7
|
import { readOwnedRequirements } from './requirements.js';
|
|
8
8
|
import { unclaimedPendingRequirements } from './owned-freeze-reassign.js';
|
|
9
|
-
// `final-gate-progress.ts`'s five pure functions are `AutofixLedger`'s internals
|
|
10
|
-
// now — each was called from exactly ONE site inside this loop, extracted for
|
|
11
|
-
// testability while the ordering and carry-forward decisions stayed out here.
|
|
12
9
|
import { classifyFinalGateAnswer, MAX_FINAL_GATE_AUTOFIX, FINAL_LEAVE_LABEL, FINAL_LEAVE_VALUE, FINAL_ACCEPT_LABEL, FINAL_ACCEPT_VALUE, FINAL_AUTOFIX_LABEL, FINAL_AUTOFIX_VALUE, STRANDED_FIX_COMMIT, strandedFixNote } from './final-gate-fix.js';
|
|
13
10
|
/**
|
|
14
11
|
* Show the run-end picker and return the raw answer. Card ORDER is fixed —
|
|
@@ -49,10 +46,9 @@ function completedResult(id, taskCount, unobservedNote) {
|
|
|
49
46
|
/**
|
|
50
47
|
* Run the whole-repo gate and resolve its verdict with the user.
|
|
51
48
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* USER_CANCELLED path handles it).
|
|
49
|
+
* Shares no state with /task-auto's run loop: the stage reads no per-task variable
|
|
50
|
+
* and writes none. Never throws for a gate outcome — only a user cancel inside a
|
|
51
|
+
* gate child propagates (the caller's USER_CANCELLED path handles it).
|
|
56
52
|
*/
|
|
57
53
|
export async function runFinalGateStage(active, deps, p) {
|
|
58
54
|
const { cwd, runId: id, planText, taskCount } = p;
|
|
@@ -91,9 +87,8 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
91
87
|
// recording must never break the gate
|
|
92
88
|
}
|
|
93
89
|
};
|
|
94
|
-
// Trail EVERY aggregated failure entry
|
|
95
|
-
//
|
|
96
|
-
// the first entry.
|
|
90
|
+
// Trail EVERY aggregated failure entry: the gate runs all sections and ranks the
|
|
91
|
+
// list, so a single sliced reason line would hide everything past the first.
|
|
97
92
|
const trailGateFail = async (f) => {
|
|
98
93
|
const list = f.failures ?? [f.reason];
|
|
99
94
|
if (list.length <= 1) {
|
|
@@ -106,14 +101,12 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
106
101
|
}
|
|
107
102
|
};
|
|
108
103
|
let fin = await deps.finalGate(cwd, planText);
|
|
109
|
-
// Record the outcome
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
// but it is labelled here, warned about, and recorded as durable debt so the next
|
|
116
|
-
// run's gate re-surfaces it.
|
|
104
|
+
// Record the outcome SYMMETRICALLY — trailing only FAIL would leave a passing
|
|
105
|
+
// gate indistinguishable from a gate that never ran, and the PASS reason names
|
|
106
|
+
// the commands that were run. THREE verdicts, not two (gate-tally.ts
|
|
107
|
+
// `unobservedVerdict`): a gate that observed nothing dynamic is UNOBSERVED, never
|
|
108
|
+
// PASS. It does not block, but it is labelled here, warned about, and recorded as
|
|
109
|
+
// durable debt so the next run's gate re-surfaces it.
|
|
117
110
|
if (fin.ok && fin.unobserved) {
|
|
118
111
|
unobservedNote = fin.unobserved;
|
|
119
112
|
await recGate(`final-gate: UNOBSERVED — ${fin.reason.slice(0, 300)}`);
|
|
@@ -128,9 +121,8 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
128
121
|
else {
|
|
129
122
|
await trailGateFail(fin);
|
|
130
123
|
}
|
|
131
|
-
// ACCEPT-debt
|
|
132
|
-
//
|
|
133
|
-
// current tree. Surface them at the gate moment — on PASS or FAIL — so a run never
|
|
124
|
+
// ACCEPT-debt surfacing: tasks the user accepted despite a verify-FAIL that the
|
|
125
|
+
// gate could not prove resolved against the current tree. Surface them at the gate moment — on PASS or FAIL — so a run never
|
|
134
126
|
// completes silently carrying an accepted defect. Informational: the per-task
|
|
135
127
|
// ACCEPT was already a human decision, so this reports, it does not re-fail.
|
|
136
128
|
const debtKey = (d) => `${d.taskId}\t${d.reason}`;
|
|
@@ -146,10 +138,10 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
146
138
|
// rather than blindly re-printed.
|
|
147
139
|
let reportedDebts = fin.openDebts ?? [];
|
|
148
140
|
await surfaceOpenDebts(reportedDebts);
|
|
149
|
-
// An owned obligation a task DETACHED
|
|
150
|
-
// satisfy it
|
|
151
|
-
//
|
|
152
|
-
//
|
|
141
|
+
// An owned obligation a task DETACHED — its own spec froze the only file that
|
|
142
|
+
// could satisfy it — and no later task claimed. Detach never deletes the quote, so
|
|
143
|
+
// the run ends holding it. Say so, or the detach becomes a quieter version of the
|
|
144
|
+
// deletion it exists to prevent.
|
|
153
145
|
const unclaimed = unclaimedPendingRequirements(await (deps.ownedRequirements ?? readOwnedRequirements)(cwd).catch(() => []));
|
|
154
146
|
for (const o of unclaimed) {
|
|
155
147
|
await recGate(`owned requirement UNCLAIMED — "${o.quote.slice(0, 200)}"`
|
|
@@ -162,12 +154,11 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
162
154
|
+ ' file, and nothing else claimed it. See the gate trail.', 'warning');
|
|
163
155
|
}
|
|
164
156
|
/**
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
* with, and correct the record.
|
|
157
|
+
* Re-derive the debt report against the tree the run actually ends with.
|
|
158
|
+
*
|
|
159
|
+
* The lines above are emitted from the FIRST gate result, so without this the
|
|
160
|
+
* run's last word on its own defects describes a tree the autofix has since
|
|
161
|
+
* changed.
|
|
171
162
|
*
|
|
172
163
|
* FP-safe by inheritance: `deriveOpenDebts` auto-closes only what a deterministic
|
|
173
164
|
* check can stand behind (a static-class debt when the statics provably pass, a
|
|
@@ -192,7 +183,7 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
192
183
|
openDebts: fresh.openDebts,
|
|
193
184
|
...(fresh.debtNote ? { debtNote: fresh.debtNote } : {})
|
|
194
185
|
};
|
|
195
|
-
// Per-debt evidence from the VERIFY-COMMAND re-check
|
|
186
|
+
// Per-debt evidence from the VERIFY-COMMAND re-check: which
|
|
196
187
|
// command was re-run and what it did. A close that cannot be read back from
|
|
197
188
|
// the trail is a close nobody can audit, and an INCONCLUSIVE re-run is worth
|
|
198
189
|
// saying out loud — it is the difference between "still broken" and "nothing
|
|
@@ -226,16 +217,15 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
226
217
|
await recGate(`defect re-check after autofix: ${closed.length} resolved, `
|
|
227
218
|
+ `${fresh.openDebts.length} still open (re-derived against the FINAL tree)`);
|
|
228
219
|
};
|
|
229
|
-
// Resolution loop: Leave-failed (recommended) / Autofix (bounded, model-driven
|
|
230
|
-
// pass + gate re-run
|
|
231
|
-
//
|
|
232
|
-
//
|
|
233
|
-
//
|
|
234
|
-
//
|
|
220
|
+
// Resolution loop: Leave-failed (recommended) / Autofix (bounded, model-driven
|
|
221
|
+
// fix pass + gate re-run) / Accept. The user always decides; after
|
|
222
|
+
// MAX_FINAL_GATE_AUTOFIX attempts that still FAIL the autofix card is withdrawn,
|
|
223
|
+
// so the loop cannot run unbounded.
|
|
224
|
+
//
|
|
225
|
+
// Everything the loop remembers lives in the ledger, not in closure locals: the
|
|
226
|
+
// attempt count and its bound, the accumulated gitignored writes, the stranded
|
|
235
227
|
// sub-fixes, the previous failure signature, the demoted set and the
|
|
236
|
-
// rejected-edits flag.
|
|
237
|
-
// non-progress rule applied downstream from the evidence it judges — the shape
|
|
238
|
-
// `final-gate-progress.ts`'s own comment names as the run-21 defect.
|
|
228
|
+
// rejected-edits flag. That keeps the non-progress rule where its evidence is.
|
|
239
229
|
// `GateTally`'s twin, one altitude up (autofix-ledger.ts).
|
|
240
230
|
const ledger = new AutofixLedger(MAX_FINAL_GATE_AUTOFIX);
|
|
241
231
|
const refreshStranded = async () => {
|
|
@@ -250,9 +240,8 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
250
240
|
}
|
|
251
241
|
};
|
|
252
242
|
// Commit whatever guard-clean repairs the fix passes left, on ANY terminal
|
|
253
|
-
// non-converged outcome.
|
|
254
|
-
// tree
|
|
255
|
-
// silently.
|
|
243
|
+
// non-converged outcome. A run that ends on LEAVE can hold real repairs dirty in
|
|
244
|
+
// the tree, and the next checkout would destroy them silently.
|
|
256
245
|
const commitStranded = async (outcome) => {
|
|
257
246
|
const stranded = ledger.stranded();
|
|
258
247
|
if (stranded.length === 0)
|
|
@@ -263,13 +252,11 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
263
252
|
+ `so the tree holds REJECTED edits: ${stranded.slice(0, 8).join(', ')}`);
|
|
264
253
|
return;
|
|
265
254
|
}
|
|
266
|
-
// REPORT WHAT ACTUALLY HAPPENED
|
|
267
|
-
//
|
|
268
|
-
//
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
// unmerged index — so on that path the catch below never fires and the trail
|
|
272
|
-
// claimed a commit over changes that were still sitting in the working tree.
|
|
255
|
+
// REPORT WHAT ACTUALLY HAPPENED, which means reading `committed`. A
|
|
256
|
+
// CommitResult is {committed, reason?, note?} and carries NO sha, and
|
|
257
|
+
// gitCommitAll answers {committed:false} WITHOUT throwing — so a trail line
|
|
258
|
+
// written from the catch alone would claim a commit over changes still sitting
|
|
259
|
+
// in the working tree.
|
|
273
260
|
const notCommitted = async (why) => {
|
|
274
261
|
await recGate(`final-gate: could NOT commit ${stranded.length} stranded fix-pass `
|
|
275
262
|
+ `change(s) (${why}) — they remain UNCOMMITTED in the working `
|
|
@@ -293,25 +280,23 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
293
280
|
};
|
|
294
281
|
while (!fin.ok) {
|
|
295
282
|
const canAutofix = deps.finalGateFix !== undefined && ledger.canAutofix();
|
|
296
|
-
// The picker question shows the debts
|
|
297
|
-
// below deliberately does not
|
|
298
|
-
// an
|
|
283
|
+
// The picker question shows the debts, because the HUMAN weighs them. The
|
|
284
|
+
// autofix seed below deliberately does not: a debt claim is prose about a
|
|
285
|
+
// defect, and a write-enabled child reads prose as an instruction.
|
|
299
286
|
const question = `Final integration gate FAILED for ${id}.\n\n${fin.reason}${fin.debtNote ?? ''}\n\n`
|
|
300
287
|
+ 'All tasks are checked off — this is the whole-repo check '
|
|
301
288
|
+ '(the project’s own test/build/static commands, run unaided).'
|
|
302
289
|
+ (ledger.attempts() > 0 ?
|
|
303
290
|
`\n\nAutofix attempts so far: ${ledger.attempts()}/${MAX_FINAL_GATE_AUTOFIX}.`
|
|
304
291
|
: '')
|
|
305
|
-
// Never let a partial repair be invisible at the moment the human
|
|
306
|
-
//
|
|
307
|
-
// by an ACCEPT).
|
|
292
|
+
// Never let a partial repair be invisible at the moment the human
|
|
293
|
+
// decides — an ACCEPT here would otherwise strand a real fix.
|
|
308
294
|
+ strandedFixNote([...ledger.stranded()]);
|
|
309
295
|
// YOLO: keep autofixing WHILE the card is still offered — the loop withdraws it
|
|
310
296
|
// after MAX_FINAL_GATE_AUTOFIX, so the cap that bounds a non-converging fix pass
|
|
311
297
|
// still bounds this — then LEAVE the run failed. Never 'accept': an unattended
|
|
312
298
|
// run that could not green the whole-repo gate has not produced a working
|
|
313
|
-
// project, and
|
|
314
|
-
// shipped app that 404s at `/`).
|
|
299
|
+
// project, and nobody is there to judge the FAIL it would be accepting.
|
|
315
300
|
const yoloFinal = yoloFinalGateChoice(isYoloMode(), canAutofix);
|
|
316
301
|
if (yoloFinal !== null) {
|
|
317
302
|
await recGate(`final-gate: auto-chose ${yoloFinal.action.toUpperCase()} ${YOLO_STAMP}`);
|
|
@@ -328,7 +313,7 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
328
313
|
// repaired but never committed would be lost to the next `git checkout`
|
|
329
314
|
// while HEAD keeps the defect it fixed. Commit it as its own, named
|
|
330
315
|
// commit — the ACCEPT is a decision about the FAILING gate, never an
|
|
331
|
-
// instruction to throw away work
|
|
316
|
+
// instruction to throw away work.
|
|
332
317
|
await commitStranded('accepted');
|
|
333
318
|
active.ui.notify(`${id}: final integration gate FAIL accepted by user — completing.`
|
|
334
319
|
+ (ledger.stranded().length > 0 ?
|
|
@@ -342,7 +327,7 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
342
327
|
active.ui.notify(`${id}: final-gate autofix (${attempt}/${MAX_FINAL_GATE_AUTOFIX}) — bounded fix pass, then the gate re-runs…`, 'info');
|
|
343
328
|
const seed = choice.guidance ? `${fin.reason}\n\nUser guidance: ${choice.guidance}` : fin.reason;
|
|
344
329
|
const fix = await deps.finalGateFix(active, cwd, seed, [...ledger.ignoredWrites()]);
|
|
345
|
-
// IGNORED-PATH WRITES
|
|
330
|
+
// IGNORED-PATH WRITES. The pass wrote file(s) git ignores, so
|
|
346
331
|
// they are not in the commit and a fresh clone does not have them. Trailed
|
|
347
332
|
// on EVERY outcome — a rejected attempt's tracked edits are discarded while
|
|
348
333
|
// its ignored writes survive on disk — and carried forward, so a later
|
|
@@ -371,10 +356,9 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
371
356
|
}
|
|
372
357
|
await recGate(`final-gate: autofix ${fix.unobserved ? 'ended UNOBSERVED' : 'converged'} — ${fix.reason.slice(0, 200)}`);
|
|
373
358
|
active.ui.notify(`${id}: final integration gate ${fix.unobserved ? 'is UNOBSERVED' : 'PASSES'} after autofix — ${fix.reason.slice(0, 140)}`, fix.unobserved ? 'warning' : 'info');
|
|
374
|
-
// The gate's own outcome,
|
|
375
|
-
//
|
|
376
|
-
//
|
|
377
|
-
// them back — the recorded mx5 run-18 defect.
|
|
359
|
+
// The gate's own outcome, WHOLE, with this door's reason on it.
|
|
360
|
+
// Rebuilding it as a two-key literal would drop `openDebts` and
|
|
361
|
+
// `observedFailures` from the value entirely.
|
|
378
362
|
fin = { ...(fix.gate ?? fin), ok: true, reason: fix.reason };
|
|
379
363
|
// The gate itself just passed, statics included, so `staticOk` here is
|
|
380
364
|
// proof rather than assumption.
|
|
@@ -397,12 +381,12 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
397
381
|
+ `uncommitted change(s) — ${ledger.stranded().slice(0, 8).join(', ')}`);
|
|
398
382
|
}
|
|
399
383
|
active.ui.notify(`${id}: final-gate autofix did not converge — ${fix.reason.slice(0, 140)}`, 'warning');
|
|
400
|
-
// NON-PROGRESS CLASSIFIER
|
|
401
|
-
//
|
|
402
|
-
//
|
|
403
|
-
//
|
|
404
|
-
//
|
|
405
|
-
//
|
|
384
|
+
// NON-PROGRESS CLASSIFIER. An attempt that changed the tree, re-ran the
|
|
385
|
+
// gate, and got back the SAME ranked-first failure as the previous such
|
|
386
|
+
// attempt is evidence about the CHECK, not about the fix — a check that
|
|
387
|
+
// cannot observe anything in this environment answers identically however
|
|
388
|
+
// the tree moves. Demote that one check to UNOBSERVED-with-debt and let
|
|
389
|
+
// the REMAINING checks decide.
|
|
406
390
|
//
|
|
407
391
|
// The judgement, the observed check and the signature carry-forward are
|
|
408
392
|
// the ledger's — made where the evidence is, not downstream from it.
|
|
@@ -446,12 +430,10 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
446
430
|
// next picker and the next fix seed target only what is still falsifiable —
|
|
447
431
|
// never re-aiming the child at the check the classifier just proved it
|
|
448
432
|
// cannot move.
|
|
449
|
-
// Outcome to outcome. The base is the FRESH gate outcome when the
|
|
450
|
-
// pass got as far as re-running it, otherwise the one we already hold
|
|
451
|
-
//
|
|
452
|
-
// `observedFailures`) is dropped by the assignment.
|
|
453
|
-
// literal with four keys, and the field it omitted is the recorded mx5
|
|
454
|
-
// run-18 defect.
|
|
433
|
+
// Outcome to outcome, WHOLE. The base is the FRESH gate outcome when the
|
|
434
|
+
// fix pass got as far as re-running it, otherwise the one we already hold;
|
|
435
|
+
// either way it is spread rather than rebuilt, so no field (`openDebts`,
|
|
436
|
+
// `observedFailures`) is dropped by the assignment.
|
|
455
437
|
const base = fix.gate ?? fin;
|
|
456
438
|
const carried = base.failures === undefined ? undefined : ledger.remaining(base);
|
|
457
439
|
fin = {
|
|
@@ -477,9 +459,9 @@ export async function runFinalGateStage(active, deps, p) {
|
|
|
477
459
|
`final-gate: left failed — autofix budget spent, nobody to ask ${YOLO_STAMP}`
|
|
478
460
|
: 'final-gate: left failed (user)');
|
|
479
461
|
// Leaving the run failed is TERMINAL for an unattended run, so the fix passes'
|
|
480
|
-
// guard-clean repairs are committed here too
|
|
481
|
-
//
|
|
482
|
-
//
|
|
462
|
+
// guard-clean repairs are committed here too, rather than left dirty for a
|
|
463
|
+
// `git checkout` to destroy. The user still owns the outcome; they own it with
|
|
464
|
+
// the work in HEAD, named in the trail.
|
|
483
465
|
await commitStranded('left-failed');
|
|
484
466
|
return {
|
|
485
467
|
kind: 'failed',
|
|
@@ -2,18 +2,16 @@
|
|
|
2
2
|
* runner-globs — deterministic detection of TWO TEST RUNNERS FIGHTING OVER THE SAME
|
|
3
3
|
* FILES, checked as soon as a project declares both rather than discovered at run end.
|
|
4
4
|
*
|
|
5
|
-
* The failure this closes
|
|
6
|
-
* `
|
|
7
|
-
* `*.test.*` / `*.spec
|
|
8
|
-
* `bun test` imports Playwright spec files, which import `@playwright/test`
|
|
9
|
-
* Playwright runner, and the whole suite dies on a module it was never
|
|
5
|
+
* The failure this closes: a project declares both `bun test` and
|
|
6
|
+
* `playwright test`. `bun test` with no arguments scans the whole project tree for
|
|
7
|
+
* `*.test.*` / `*.spec.*`, and Playwright's component/e2e specs ARE `*.spec.tsx`.
|
|
8
|
+
* So `bun test` imports Playwright spec files, which import `@playwright/test`
|
|
9
|
+
* outside a Playwright runner, and the whole suite dies on a module it was never
|
|
10
|
+
* meant to load.
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* defect that recurs across runs and survives its own fix is not a discovery problem;
|
|
15
|
-
* it is a missing invariant. This module states the invariant so it can be checked the
|
|
16
|
-
* moment both runners are declared:
|
|
12
|
+
* Finding that at the final gate is too late: the fix is a one-line config change
|
|
13
|
+
* that can still be sitting uncommitted when the run ends. So the invariant is
|
|
14
|
+
* checked the moment both runners are declared:
|
|
17
15
|
*
|
|
18
16
|
* if two runners are declared, their file sets must be provably DISJOINT
|
|
19
17
|
*
|
|
@@ -51,8 +49,9 @@ export interface RunnerGlobInputs {
|
|
|
51
49
|
*/
|
|
52
50
|
export declare function parsePathIgnorePatterns(bunfig: string | null): string[] | null;
|
|
53
51
|
/**
|
|
54
|
-
* Playwright's `testMatch`, when the config states one. Null
|
|
55
|
-
*
|
|
52
|
+
* Playwright's `testMatch`, when the config states one. Null when the config
|
|
53
|
+
* states none (or there is no config), in which case the NAMING form cannot be
|
|
54
|
+
* proven and `assessRunnerGlobs` falls through to the exclusion check.
|
|
56
55
|
*/
|
|
57
56
|
export declare function parseTestMatch(playwrightConfig: string | null): string[] | null;
|
|
58
57
|
/** Playwright's `testDir`, when stated (used to explain the collision concretely). */
|
|
@@ -2,18 +2,16 @@
|
|
|
2
2
|
* runner-globs — deterministic detection of TWO TEST RUNNERS FIGHTING OVER THE SAME
|
|
3
3
|
* FILES, checked as soon as a project declares both rather than discovered at run end.
|
|
4
4
|
*
|
|
5
|
-
* The failure this closes
|
|
6
|
-
* `
|
|
7
|
-
* `*.test.*` / `*.spec
|
|
8
|
-
* `bun test` imports Playwright spec files, which import `@playwright/test`
|
|
9
|
-
* Playwright runner, and the whole suite dies on a module it was never
|
|
5
|
+
* The failure this closes: a project declares both `bun test` and
|
|
6
|
+
* `playwright test`. `bun test` with no arguments scans the whole project tree for
|
|
7
|
+
* `*.test.*` / `*.spec.*`, and Playwright's component/e2e specs ARE `*.spec.tsx`.
|
|
8
|
+
* So `bun test` imports Playwright spec files, which import `@playwright/test`
|
|
9
|
+
* outside a Playwright runner, and the whole suite dies on a module it was never
|
|
10
|
+
* meant to load.
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* defect that recurs across runs and survives its own fix is not a discovery problem;
|
|
15
|
-
* it is a missing invariant. This module states the invariant so it can be checked the
|
|
16
|
-
* moment both runners are declared:
|
|
12
|
+
* Finding that at the final gate is too late: the fix is a one-line config change
|
|
13
|
+
* that can still be sitting uncommitted when the run ends. So the invariant is
|
|
14
|
+
* checked the moment both runners are declared:
|
|
17
15
|
*
|
|
18
16
|
* if two runners are declared, their file sets must be provably DISJOINT
|
|
19
17
|
*
|
|
@@ -53,8 +51,9 @@ export function parsePathIgnorePatterns(bunfig) {
|
|
|
53
51
|
return [...m[1].matchAll(/["']([^"']+)["']/g)].map(x => x[1]);
|
|
54
52
|
}
|
|
55
53
|
/**
|
|
56
|
-
* Playwright's `testMatch`, when the config states one. Null
|
|
57
|
-
*
|
|
54
|
+
* Playwright's `testMatch`, when the config states one. Null when the config
|
|
55
|
+
* states none (or there is no config), in which case the NAMING form cannot be
|
|
56
|
+
* proven and `assessRunnerGlobs` falls through to the exclusion check.
|
|
58
57
|
*/
|
|
59
58
|
export function parseTestMatch(playwrightConfig) {
|
|
60
59
|
if (playwrightConfig === null)
|
|
@@ -24,13 +24,12 @@ export declare function resolveRunner(bin: string, opts?: {
|
|
|
24
24
|
* Output shapes a RUNNER emits when the command inside a script chain does not
|
|
25
25
|
* exist, on platforms where that is not reported as exit 127.
|
|
26
26
|
*
|
|
27
|
-
* 127 is a POSIX-SHELL convention:
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* wording. Recognising the shape restores one env-gap contract on all three.
|
|
27
|
+
* 127 is a POSIX-SHELL convention: bun hands the script to a shell, the shell
|
|
28
|
+
* prints `…: command not found` and exits 127, and the whole env-gap contract
|
|
29
|
+
* keys off that number. Where no such shell runs the script, the runner reports
|
|
30
|
+
* the miss itself (`bun: command not found: X`) and the status alone cannot be
|
|
31
|
+
* told from a real code fault. cmd.exe (9009) and PowerShell have their own
|
|
32
|
+
* wording. Recognising the shape restores the env-gap contract there.
|
|
34
33
|
*
|
|
35
34
|
* Deliberately narrow: only wordings a RUNNER/SHELL produces, never the bare
|
|
36
35
|
* phrase. A suite that prints "command not found" inside a failing assertion is
|
|
@@ -41,8 +40,9 @@ export declare const COMMAND_NOT_FOUND_OUTPUT_RE: RegExp;
|
|
|
41
40
|
* Did this command fail because the thing it tried to run does not exist here,
|
|
42
41
|
* rather than because the code is wrong? Exit 127 (POSIX shell) or 9009
|
|
43
42
|
* (cmd.exe) say so outright; anything else needs the runner's own wording (see
|
|
44
|
-
* COMMAND_NOT_FOUND_OUTPUT_RE)
|
|
45
|
-
*
|
|
43
|
+
* COMMAND_NOT_FOUND_OUTPUT_RE), because a runner that resolves the command
|
|
44
|
+
* itself can report the miss and still exit 1. Callers treat a true here as an
|
|
45
|
+
* environment gap → skip, never FAIL.
|
|
46
46
|
*/
|
|
47
47
|
export declare function isCommandNotFound(status: number | null, output?: string): boolean;
|
|
48
48
|
/**
|
|
@@ -2,26 +2,25 @@
|
|
|
2
2
|
* runner-resolve — make the deterministic gates able to SPAWN the project's own
|
|
3
3
|
* runner when the host PATH lost it.
|
|
4
4
|
*
|
|
5
|
-
* The failure this closes
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `bun run dev`, and therefore the render check
|
|
11
|
-
*
|
|
12
|
-
*
|
|
5
|
+
* The failure this closes: a host whose PATH lost the runner — pi launched
|
|
6
|
+
* through a login shell whose profile rebuilt PATH without `~/.bun/bin`, say.
|
|
7
|
+
* `bun` is then unspawnable in every gate spawn, and under the env-gap contract
|
|
8
|
+
* (ENOENT / exit 127 → skip, deliberately, so a missing tool is never a code
|
|
9
|
+
* fault) EVERY dynamic check silently skips: the test command, the boot of
|
|
10
|
+
* `bun run dev`, and therefore the render check too. The gate converges on static
|
|
11
|
+
* checks alone and stamps the run green while the binary sits in a directory
|
|
12
|
+
* nothing looked in.
|
|
13
13
|
*
|
|
14
14
|
* Resolution is discovery, never installation: try the bare name first (PATH
|
|
15
15
|
* serves it → nothing changes), then probe well-known install locations. Each
|
|
16
16
|
* probe is a real `<candidate> --version` spawn — an existing but broken binary
|
|
17
17
|
* must not count as resolved.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* resolved binary.
|
|
19
|
+
* {@link runnerEnv} prepends the resolved directory to PATH for the spawned
|
|
20
|
+
* script chain. Spawn sites should use it rather than the resolved binary alone:
|
|
21
|
+
* a `bun run test` re-invokes commands INSIDE the script, and a runner that does
|
|
22
|
+
* not put itself within reach of those inner calls would fail them for the same
|
|
23
|
+
* reason the outer spawn failed.
|
|
25
24
|
*/
|
|
26
25
|
import { spawnSync } from 'node:child_process';
|
|
27
26
|
import { existsSync } from 'node:fs';
|
|
@@ -87,13 +86,12 @@ export function resolveRunner(bin, opts = {}) {
|
|
|
87
86
|
* Output shapes a RUNNER emits when the command inside a script chain does not
|
|
88
87
|
* exist, on platforms where that is not reported as exit 127.
|
|
89
88
|
*
|
|
90
|
-
* 127 is a POSIX-SHELL convention:
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* wording. Recognising the shape restores one env-gap contract on all three.
|
|
89
|
+
* 127 is a POSIX-SHELL convention: bun hands the script to a shell, the shell
|
|
90
|
+
* prints `…: command not found` and exits 127, and the whole env-gap contract
|
|
91
|
+
* keys off that number. Where no such shell runs the script, the runner reports
|
|
92
|
+
* the miss itself (`bun: command not found: X`) and the status alone cannot be
|
|
93
|
+
* told from a real code fault. cmd.exe (9009) and PowerShell have their own
|
|
94
|
+
* wording. Recognising the shape restores the env-gap contract there.
|
|
97
95
|
*
|
|
98
96
|
* Deliberately narrow: only wordings a RUNNER/SHELL produces, never the bare
|
|
99
97
|
* phrase. A suite that prints "command not found" inside a failing assertion is
|
|
@@ -104,8 +102,9 @@ export const COMMAND_NOT_FOUND_OUTPUT_RE = /\b(?:bun|npm|pnpm|yarn|node|deno): c
|
|
|
104
102
|
* Did this command fail because the thing it tried to run does not exist here,
|
|
105
103
|
* rather than because the code is wrong? Exit 127 (POSIX shell) or 9009
|
|
106
104
|
* (cmd.exe) say so outright; anything else needs the runner's own wording (see
|
|
107
|
-
* COMMAND_NOT_FOUND_OUTPUT_RE)
|
|
108
|
-
*
|
|
105
|
+
* COMMAND_NOT_FOUND_OUTPUT_RE), because a runner that resolves the command
|
|
106
|
+
* itself can report the miss and still exit 1. Callers treat a true here as an
|
|
107
|
+
* environment gap → skip, never FAIL.
|
|
109
108
|
*/
|
|
110
109
|
export function isCommandNotFound(status, output = '') {
|
|
111
110
|
if (status === 127 || status === 9009)
|
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* script-escape — deterministic detection of CHECK SCRIPTS THAT CANNOT FAIL.
|
|
3
3
|
*
|
|
4
|
-
* The failure this closes
|
|
5
|
-
* declared, verbatim,
|
|
4
|
+
* The failure this closes: a package.json declaring
|
|
6
5
|
* "lint": "prettier … && eslint --fix … && (tsc --noEmit 2>&1 | grep -qv 'TS18003' || true)"
|
|
7
6
|
* The typecheck is neutered twice over — its output is piped into an INVERTED grep
|
|
8
7
|
* (so the status becomes "some line did not match", never tsc's verdict), and the
|
|
9
8
|
* whole group is closed with `|| true` (so the script exits 0 unconditionally). Every
|
|
10
9
|
* consumer of that script — the repo-health verify gate, the final integration gate,
|
|
11
|
-
* a human reading a green CI line — is reading a constant, not a measurement.
|
|
10
|
+
* a human reading a green CI line — is reading a constant, not a measurement. It
|
|
11
|
+
* looks fine for exactly as long as the checker happens to be clean.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* `bun run lint` could be authored into a no-op and every gate would salute it.
|
|
13
|
+
* This is a skip-escape moved one level out. `findSkipEscapes` (skip-escape.ts)
|
|
14
|
+
* scans a spec's own VERIFY block; nothing else scans the SCRIPT DEFINITIONS those
|
|
15
|
+
* VERIFY blocks then invoke by name, so `bun run lint` can be authored into a no-op
|
|
16
|
+
* and every gate salutes it.
|
|
18
17
|
*
|
|
19
18
|
* TWO SHAPES, both crisp, both scoped to CHECK-CLASS script names:
|
|
20
19
|
*
|
|
21
20
|
* A. ALWAYS-ZERO TAIL — the script's last command cannot fail (`… || true`,
|
|
22
|
-
* `…
|
|
21
|
+
* `… ||:`, `… || exit 0`, `…; exit 0`, a trailing `|| echo` fallback). A
|
|
23
22
|
* shell script's status is its last command's status, so this is a proof, not
|
|
24
23
|
* a heuristic: the script exits 0 no matter what the checker found.
|
|
25
24
|
*
|
|
@@ -27,9 +26,8 @@
|
|
|
27
26
|
* "Some line of the output does NOT match X" is never a checker's verdict; it
|
|
28
27
|
* is true of virtually any non-empty output, including a wall of errors.
|
|
29
28
|
*
|
|
30
|
-
* Deliberately NOT flagged, because each is legitimate
|
|
31
|
-
*
|
|
32
|
-
* - `|| exit 1` — a HARDENING, the opposite of an escape (aiz-server).
|
|
29
|
+
* Deliberately NOT flagged, because each is legitimate:
|
|
30
|
+
* - `|| exit 1` — a HARDENING, the opposite of an escape.
|
|
33
31
|
* - any `||`/pipe in a NON-check script (`clean`, `dev`, `start`, `copy-fonts`) —
|
|
34
32
|
* a teardown `rm -rf dist || true` is correct and common.
|
|
35
33
|
* - pipes into formatters/reporters (`| tap-spec`, `| tee`) — those propagate
|
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* script-escape — deterministic detection of CHECK SCRIPTS THAT CANNOT FAIL.
|
|
3
3
|
*
|
|
4
|
-
* The failure this closes
|
|
5
|
-
* declared, verbatim,
|
|
4
|
+
* The failure this closes: a package.json declaring
|
|
6
5
|
* "lint": "prettier … && eslint --fix … && (tsc --noEmit 2>&1 | grep -qv 'TS18003' || true)"
|
|
7
6
|
* The typecheck is neutered twice over — its output is piped into an INVERTED grep
|
|
8
7
|
* (so the status becomes "some line did not match", never tsc's verdict), and the
|
|
9
8
|
* whole group is closed with `|| true` (so the script exits 0 unconditionally). Every
|
|
10
9
|
* consumer of that script — the repo-health verify gate, the final integration gate,
|
|
11
|
-
* a human reading a green CI line — is reading a constant, not a measurement.
|
|
10
|
+
* a human reading a green CI line — is reading a constant, not a measurement. It
|
|
11
|
+
* looks fine for exactly as long as the checker happens to be clean.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* `bun run lint` could be authored into a no-op and every gate would salute it.
|
|
13
|
+
* This is a skip-escape moved one level out. `findSkipEscapes` (skip-escape.ts)
|
|
14
|
+
* scans a spec's own VERIFY block; nothing else scans the SCRIPT DEFINITIONS those
|
|
15
|
+
* VERIFY blocks then invoke by name, so `bun run lint` can be authored into a no-op
|
|
16
|
+
* and every gate salutes it.
|
|
18
17
|
*
|
|
19
18
|
* TWO SHAPES, both crisp, both scoped to CHECK-CLASS script names:
|
|
20
19
|
*
|
|
21
20
|
* A. ALWAYS-ZERO TAIL — the script's last command cannot fail (`… || true`,
|
|
22
|
-
* `…
|
|
21
|
+
* `… ||:`, `… || exit 0`, `…; exit 0`, a trailing `|| echo` fallback). A
|
|
23
22
|
* shell script's status is its last command's status, so this is a proof, not
|
|
24
23
|
* a heuristic: the script exits 0 no matter what the checker found.
|
|
25
24
|
*
|
|
@@ -27,9 +26,8 @@
|
|
|
27
26
|
* "Some line of the output does NOT match X" is never a checker's verdict; it
|
|
28
27
|
* is true of virtually any non-empty output, including a wall of errors.
|
|
29
28
|
*
|
|
30
|
-
* Deliberately NOT flagged, because each is legitimate
|
|
31
|
-
*
|
|
32
|
-
* - `|| exit 1` — a HARDENING, the opposite of an escape (aiz-server).
|
|
29
|
+
* Deliberately NOT flagged, because each is legitimate:
|
|
30
|
+
* - `|| exit 1` — a HARDENING, the opposite of an escape.
|
|
33
31
|
* - any `||`/pipe in a NON-check script (`clean`, `dev`, `start`, `copy-fonts`) —
|
|
34
32
|
* a teardown `rm -rf dist || true` is correct and common.
|
|
35
33
|
* - pipes into formatters/reporters (`| tap-spec`, `| tee`) — those propagate
|
|
@@ -57,7 +55,8 @@ const ALWAYS_ZERO_TAILS = [
|
|
|
57
55
|
const INVERTED_GREP_RE = /\|\s*grep\s+(?:-\w*v\w*|-\w+\s+-\w*v\w*)/;
|
|
58
56
|
/**
|
|
59
57
|
* Strip trailing subshell/group closers and separators so the tail patterns see the
|
|
60
|
-
* real last command
|
|
58
|
+
* real last command: a script ending `… && (tsc --noEmit || true)` hides its tail
|
|
59
|
+
* behind the `)`.
|
|
61
60
|
*/
|
|
62
61
|
function tailOf(body) {
|
|
63
62
|
let s = body.trim();
|
|
@@ -177,7 +176,7 @@ export function scriptEscapeVerifyFindings(findings) {
|
|
|
177
176
|
export function scriptEscapeDefectText(findings) {
|
|
178
177
|
return [
|
|
179
178
|
'NEUTERED CHECK SCRIPT — this spec defines a check script that CANNOT FAIL, so every',
|
|
180
|
-
'gate that runs it reads a constant instead of a measurement (
|
|
179
|
+
'gate that runs it reads a constant instead of a measurement (a run shipped',
|
|
181
180
|
'`"lint": "… && (tsc --noEmit 2>&1 | grep -qv \'TS18003\' || true)"` — the typecheck',
|
|
182
181
|
'was fully disarmed, and it went unnoticed only because tsc happened to be clean).',
|
|
183
182
|
"Rewrite each so it PROPAGATES the checker's exit status: drop the `|| true` /",
|
|
@@ -20,7 +20,7 @@ export declare function findBindEvidence(src: string, appNames?: Set<string>): s
|
|
|
20
20
|
/** Why this file makes the project a SERVING one, or null. */
|
|
21
21
|
export declare function findServeExpectation(src: string): string | null;
|
|
22
22
|
/** A design/spec clause that names a served path — the plan-side half of the same
|
|
23
|
-
* expectation
|
|
23
|
+
* expectation, e.g. a design that says "serves `/api` + static `dist/`". */
|
|
24
24
|
export declare function planExpectsServing(planText: string | undefined): string | null;
|
|
25
25
|
/** The platform that would bind on this project's behalf, or null. */
|
|
26
26
|
export declare function opaqueLauncher(cwd: string): string | null;
|