@mjasnikovs/pi-task 0.38.28 → 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 +25 -7
- package/dist/task/context-usage.js +21 -6
- 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 +37 -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 +180 -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 +33 -36
- package/dist/task/research-worker.js +39 -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 +86 -54
- package/dist/workers/pi-worker-core.js +112 -112
- 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 +23 -10
- 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
|
@@ -9,23 +9,24 @@
|
|
|
9
9
|
* Only a command that demonstrably ran and exited non-zero for a reason of its
|
|
10
10
|
* own is a failure, and only exit 0 is a pass.
|
|
11
11
|
*
|
|
12
|
-
* Why a module.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
12
|
+
* Why a module. The same ladder is needed by every caller that runs a project
|
|
13
|
+
* command and must decide what its ending MEANS — the gate's own
|
|
14
|
+
* `runGateCommand`, `runVerifyCommandLine` here, and accept-debt's
|
|
15
|
+
* `rerunDebtVerifyCommand`. Stated separately at each site the copies drift: one
|
|
16
|
+
* applies the infrastructure pattern unconditionally, the next only on request,
|
|
17
|
+
* and two trails then disagree about whether the same output was a gap or a
|
|
18
|
+
* failure. repo-health-check.ts defers to this module rather than carrying its
|
|
19
|
+
* own version — its header says so in as many words.
|
|
19
20
|
*
|
|
20
21
|
* The second half is the seam. Classification is now pure over a `CommandRun`
|
|
21
22
|
* value, and SPAWNING is a `CommandRunner` the caller injects. That is what lets
|
|
22
23
|
* the gate's tests state a case as `{status: 1, stdout: "…"}` instead of writing
|
|
23
|
-
* a real `node -e` child, creating a temp directory for it, and — for the
|
|
24
|
-
*
|
|
25
|
-
* resetting a module-level cache, which
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* had none.
|
|
24
|
+
* a real `node -e` child, creating a temp directory for it, and — for the cases
|
|
25
|
+
* only reachable that way — shadowing a binary on `process.env.PATH` and
|
|
26
|
+
* resetting a module-level cache, which makes those tests order-sensitive.
|
|
27
|
+
*
|
|
28
|
+
* It also closes an asymmetry: `BootDeps` carries twelve injectable probes for
|
|
29
|
+
* the gate's boot half, while its command half had none.
|
|
29
30
|
*/
|
|
30
31
|
/** What one finished command looks like, stripped of how it was spawned. */
|
|
31
32
|
export interface CommandRun {
|
|
@@ -57,14 +58,12 @@ export interface CommandSpec {
|
|
|
57
58
|
* The injectable half. The gate takes one of these so its tests can script
|
|
58
59
|
* verdicts instead of paying process-spawn cost for every classification case.
|
|
59
60
|
*
|
|
60
|
-
* ASYNC by contract
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* doc comment already told gate callers not to do it, while `final-gate.ts`'s
|
|
67
|
-
* repo-health call did exactly that.
|
|
61
|
+
* ASYNC by contract, and the type is what enforces it. A synchronous
|
|
62
|
+
* `(spec) => CommandRun` can only be implemented with `spawnSync`, which blocks
|
|
63
|
+
* the event loop for the whole command — so the run-end gate, which runs
|
|
64
|
+
* repo-health and then every lockfile, test, build, launch and ACCEPT-debt
|
|
65
|
+
* command in sequence, would hold the loop for all of it and no loader could
|
|
66
|
+
* paint a single frame through it.
|
|
68
67
|
*/
|
|
69
68
|
export type CommandRunner = (spec: CommandSpec) => Promise<CommandRun>;
|
|
70
69
|
/**
|
|
@@ -76,15 +75,19 @@ export type CommandRunner = (spec: CommandSpec) => Promise<CommandRun>;
|
|
|
76
75
|
* THE RUN SETTLES ON THE CHILD, NOT ON THE PIPE. `close` fires only once every
|
|
77
76
|
* stdio pipe has reached EOF, and a backgrounded grandchild INHERITS stdout: a
|
|
78
77
|
* seed script that starts a daemon, a build that leaves a watcher, a launch
|
|
79
|
-
* script.
|
|
80
|
-
*
|
|
81
|
-
*
|
|
78
|
+
* script.
|
|
79
|
+
*
|
|
80
|
+
* Measured on exactly that shape — a child that backgrounds a sleeper and exits
|
|
81
|
+
* at once — `exit` fired after 1ms and `close` NEVER fired. Sending SIGKILL to
|
|
82
|
+
* the direct child did not release it either, because the grandchild holds the
|
|
83
|
+
* pipe. Waiting for `close` is therefore waiting for something no timeout can
|
|
84
|
+
* reach. `exit` settles the run, and the deadline settles it itself.
|
|
82
85
|
*/
|
|
83
86
|
export declare const spawnCommand: CommandRunner;
|
|
84
87
|
/**
|
|
85
88
|
* A non-zero exit whose output shows an EXTERNAL runtime dependency is missing, not
|
|
86
89
|
* a code fault: a browser suite (Playwright/Cypress) whose browser binaries or system
|
|
87
|
-
* libraries were never installed here (
|
|
90
|
+
* libraries were never installed here (a component-test runner must run in the
|
|
88
91
|
* gate, but on a box with no Playwright browsers it is an environment gap, not a FAIL).
|
|
89
92
|
* These exit non-zero (not 127), so they need output-shape recognition to skip.
|
|
90
93
|
*/
|
|
@@ -164,15 +167,15 @@ export type VerifyRerunOutcome = {
|
|
|
164
167
|
detail: string;
|
|
165
168
|
};
|
|
166
169
|
/**
|
|
167
|
-
* Re-run one VERIFY-block command line
|
|
170
|
+
* Re-run one VERIFY-block command line under the gate's existing
|
|
168
171
|
* env-gap contract, so a debt whose reason NAMES that command can be closed by the
|
|
169
172
|
* command itself rather than by a judgement about it.
|
|
170
173
|
*
|
|
171
|
-
* Runs through `sh -c` because a VERIFY line is a shell line, not an argv:
|
|
174
|
+
* Runs through `sh -c` because a VERIFY line is a shell line, not an argv: a
|
|
172
175
|
* is `AGENT=1 bun test test/listings.test.ts`, and env prefixes, `&&` and redirects
|
|
173
176
|
* are all ordinary there. The leading command word is still resolved through
|
|
174
177
|
* runner-resolve so a login-shell-stripped PATH cannot make every re-run look like a
|
|
175
|
-
* gap
|
|
178
|
+
* gap.
|
|
176
179
|
*
|
|
177
180
|
* The asymmetry is the point: only exit 0 is conclusive. Every other ending — real
|
|
178
181
|
* failure, missing tool, unreachable database, timeout, no POSIX shell — leaves the
|
package/dist/task/command-run.js
CHANGED
|
@@ -9,36 +9,41 @@
|
|
|
9
9
|
* Only a command that demonstrably ran and exited non-zero for a reason of its
|
|
10
10
|
* own is a failure, and only exit 0 is a pass.
|
|
11
11
|
*
|
|
12
|
-
* Why a module.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
12
|
+
* Why a module. The same ladder is needed by every caller that runs a project
|
|
13
|
+
* command and must decide what its ending MEANS — the gate's own
|
|
14
|
+
* `runGateCommand`, `runVerifyCommandLine` here, and accept-debt's
|
|
15
|
+
* `rerunDebtVerifyCommand`. Stated separately at each site the copies drift: one
|
|
16
|
+
* applies the infrastructure pattern unconditionally, the next only on request,
|
|
17
|
+
* and two trails then disagree about whether the same output was a gap or a
|
|
18
|
+
* failure. repo-health-check.ts defers to this module rather than carrying its
|
|
19
|
+
* own version — its header says so in as many words.
|
|
19
20
|
*
|
|
20
21
|
* The second half is the seam. Classification is now pure over a `CommandRun`
|
|
21
22
|
* value, and SPAWNING is a `CommandRunner` the caller injects. That is what lets
|
|
22
23
|
* the gate's tests state a case as `{status: 1, stdout: "…"}` instead of writing
|
|
23
|
-
* a real `node -e` child, creating a temp directory for it, and — for the
|
|
24
|
-
*
|
|
25
|
-
* resetting a module-level cache, which
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* had none.
|
|
24
|
+
* a real `node -e` child, creating a temp directory for it, and — for the cases
|
|
25
|
+
* only reachable that way — shadowing a binary on `process.env.PATH` and
|
|
26
|
+
* resetting a module-level cache, which makes those tests order-sensitive.
|
|
27
|
+
*
|
|
28
|
+
* It also closes an asymmetry: `BootDeps` carries twelve injectable probes for
|
|
29
|
+
* the gate's boot half, while its command half had none.
|
|
29
30
|
*/
|
|
30
31
|
import { spawn } from 'node:child_process';
|
|
31
32
|
import { isCommandNotFound, resolveRunner, runnerEnv } from './runner-resolve.js';
|
|
32
33
|
/**
|
|
33
34
|
* How much of ONE stream may be held in the HOST process, and how it is split.
|
|
34
35
|
*
|
|
35
|
-
* `spawnSync`
|
|
36
|
-
*
|
|
37
|
-
*
|
|
36
|
+
* `spawnSync` came with a bound for free — its default `maxBuffer` is 1 MiB, and
|
|
37
|
+
* exceeding it fails the call with ENOBUFS (checked: 2 MiB of output truncates at
|
|
38
|
+
* 1,114,112 bytes). An async runner has no such bound, so without this two
|
|
39
|
+
* strings grow in the host's own process for as long as the command keeps
|
|
40
|
+
* talking.
|
|
38
41
|
*
|
|
39
|
-
* BOTH ENDS are kept, because both are read
|
|
40
|
-
* regexes match wording a runner prints FIRST
|
|
41
|
-
* reason take the LAST 400 characters. A single-ended cap loses one of
|
|
42
|
+
* BOTH ENDS are kept, because both are read: `isCommandNotFound` and the gap
|
|
43
|
+
* regexes match wording a runner prints FIRST, while `outputTail` and every
|
|
44
|
+
* failure reason take the LAST 400 characters. A single-ended cap loses one of
|
|
45
|
+
* them. Run against a real 2 MB command, the capture keeps its opening bytes,
|
|
46
|
+
* its closing bytes, and an elision marker between them.
|
|
42
47
|
*/
|
|
43
48
|
const OUTPUT_HEAD_CAP = 256 * 1024;
|
|
44
49
|
const OUTPUT_TAIL_CAP = 768 * 1024;
|
|
@@ -81,9 +86,13 @@ const DRAIN_MS = 50;
|
|
|
81
86
|
* THE RUN SETTLES ON THE CHILD, NOT ON THE PIPE. `close` fires only once every
|
|
82
87
|
* stdio pipe has reached EOF, and a backgrounded grandchild INHERITS stdout: a
|
|
83
88
|
* seed script that starts a daemon, a build that leaves a watcher, a launch
|
|
84
|
-
* script.
|
|
85
|
-
*
|
|
86
|
-
*
|
|
89
|
+
* script.
|
|
90
|
+
*
|
|
91
|
+
* Measured on exactly that shape — a child that backgrounds a sleeper and exits
|
|
92
|
+
* at once — `exit` fired after 1ms and `close` NEVER fired. Sending SIGKILL to
|
|
93
|
+
* the direct child did not release it either, because the grandchild holds the
|
|
94
|
+
* pipe. Waiting for `close` is therefore waiting for something no timeout can
|
|
95
|
+
* reach. `exit` settles the run, and the deadline settles it itself.
|
|
87
96
|
*/
|
|
88
97
|
export const spawnCommand = spec => new Promise(resolve => {
|
|
89
98
|
const out = new BoundedOutput();
|
|
@@ -97,8 +106,8 @@ export const spawnCommand = spec => new Promise(resolve => {
|
|
|
97
106
|
cwd: spec.cwd,
|
|
98
107
|
// stdin CLOSED. `spawnSync` gave the child none; the default `spawn`
|
|
99
108
|
// stdio is a live pipe nobody ever ends, so a check that reads stdin —
|
|
100
|
-
// a `cat`-style pipeline, a tool that prompts, a pager —
|
|
101
|
-
// the kill timer
|
|
109
|
+
// a `cat`-style pipeline, a tool that prompts, a pager — would block
|
|
110
|
+
// until the kill timer fires instead of returning at once.
|
|
102
111
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
103
112
|
...(spec.env ? { env: spec.env } : {})
|
|
104
113
|
});
|
|
@@ -140,12 +149,12 @@ export const spawnCommand = spec => new Promise(resolve => {
|
|
|
140
149
|
clearTimeout(drain);
|
|
141
150
|
drain = setTimeout(() => done(null), DRAIN_MS);
|
|
142
151
|
};
|
|
143
|
-
// NOT unref'd.
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
152
|
+
// NOT unref'd. This timer is the only bound left on every gate command,
|
|
153
|
+
// repo-health command and ACCEPT-debt re-run, and an unref'd timer is only
|
|
154
|
+
// guaranteed to fire while something ref'd is still pending — not a
|
|
155
|
+
// guarantee this can rely on. It is cleared the moment the run settles, so
|
|
156
|
+
// it holds the loop open only while a command the caller is awaiting
|
|
157
|
+
// anyway is still running.
|
|
149
158
|
const timer = setTimeout(killAndSettle, spec.timeoutMs);
|
|
150
159
|
if (spec.signal) {
|
|
151
160
|
if (spec.signal.aborted)
|
|
@@ -180,7 +189,7 @@ export const spawnCommand = spec => new Promise(resolve => {
|
|
|
180
189
|
/**
|
|
181
190
|
* A non-zero exit whose output shows an EXTERNAL runtime dependency is missing, not
|
|
182
191
|
* a code fault: a browser suite (Playwright/Cypress) whose browser binaries or system
|
|
183
|
-
* libraries were never installed here (
|
|
192
|
+
* libraries were never installed here (a component-test runner must run in the
|
|
184
193
|
* gate, but on a box with no Playwright browsers it is an environment gap, not a FAIL).
|
|
185
194
|
* These exit non-zero (not 127), so they need output-shape recognition to skip.
|
|
186
195
|
*/
|
|
@@ -202,7 +211,7 @@ export const INFRA_GAP_OUTPUT_RE = /ECONNREFUSED|connection refused|ENOTFOUND|EA
|
|
|
202
211
|
* `spawn-failed` is first and is kept distinguishable from every other row by its
|
|
203
212
|
* id: a tool-level gap (127 inside the chain, a missing browser, a timeout) means
|
|
204
213
|
* the runner demonstrably RAN, and only genuine spawn failures feed the gate's
|
|
205
|
-
* full-blindness guard (
|
|
214
|
+
* full-blindness guard (see observabilityGapFailure).
|
|
206
215
|
*/
|
|
207
216
|
const GAP_RULES = [
|
|
208
217
|
{
|
|
@@ -281,15 +290,15 @@ function leadingBin(line) {
|
|
|
281
290
|
return null;
|
|
282
291
|
}
|
|
283
292
|
/**
|
|
284
|
-
* Re-run one VERIFY-block command line
|
|
293
|
+
* Re-run one VERIFY-block command line under the gate's existing
|
|
285
294
|
* env-gap contract, so a debt whose reason NAMES that command can be closed by the
|
|
286
295
|
* command itself rather than by a judgement about it.
|
|
287
296
|
*
|
|
288
|
-
* Runs through `sh -c` because a VERIFY line is a shell line, not an argv:
|
|
297
|
+
* Runs through `sh -c` because a VERIFY line is a shell line, not an argv: a
|
|
289
298
|
* is `AGENT=1 bun test test/listings.test.ts`, and env prefixes, `&&` and redirects
|
|
290
299
|
* are all ordinary there. The leading command word is still resolved through
|
|
291
300
|
* runner-resolve so a login-shell-stripped PATH cannot make every re-run look like a
|
|
292
|
-
* gap
|
|
301
|
+
* gap.
|
|
293
302
|
*
|
|
294
303
|
* The asymmetry is the point: only exit 0 is conclusive. Every other ending — real
|
|
295
304
|
* failure, missing tool, unreachable database, timeout, no POSIX shell — leaves the
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
* SCOPE-SHRINK detection for the final-gate fix pass.
|
|
3
3
|
*
|
|
4
4
|
* The label guard (final-gate-fix.ts) compares the SET of discoverable gate
|
|
5
|
-
* commands before and after the fix child
|
|
6
|
-
* it
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* commands before and after the fix child, and a fix child walks straight through
|
|
6
|
+
* it. Rewrite `"test": "AGENT=1 bun test"` to `"AGENT=1 bun test ./test"` and the
|
|
7
|
+
* label `bun run test` exists before and after, so the set difference is empty —
|
|
8
|
+
* while the gate now re-runs a suite that no longer covers the repository, and
|
|
9
|
+
* reports that the autofix converged. Fed to `classifyBodyChange`, those two
|
|
10
|
+
* bodies come back `narrow` / `path-added`, which is the whole point of this
|
|
11
|
+
* module.
|
|
10
12
|
*
|
|
11
13
|
* What changed was not the command's NAME but its SCOPE. This module compares
|
|
12
14
|
* the RESOLVED BODIES (`scripts[name]` for package.json, the recipe lines for a
|
|
@@ -16,23 +18,27 @@
|
|
|
16
18
|
* 1. a path/glob argument is ADDED to a command member that had none
|
|
17
19
|
* (`bun test` → `bun test ./test`);
|
|
18
20
|
* 2. an existing path/glob argument is replaced by a strict SUBPATH of itself
|
|
19
|
-
* (`eslint src` → `eslint src/server`)
|
|
21
|
+
* (`eslint ./src` → `eslint ./src/server`). Note the argument has to LOOK
|
|
22
|
+
* like a path — a bare `src` with no separator, dot or glob is not treated
|
|
23
|
+
* as one, so `eslint src` → `eslint src/server` reads as neutral;
|
|
20
24
|
* 3. an exclusion flag/pattern is ADDED (`--ignore`, `--exclude`,
|
|
21
25
|
* `--testPathIgnorePatterns`, `-x`, …);
|
|
22
26
|
* 4. a config-file argument is swapped for one the fix pass itself created.
|
|
23
27
|
*
|
|
24
|
-
* With ONE excuse,
|
|
25
|
-
*
|
|
26
|
-
*
|
|
28
|
+
* With ONE excuse, documented at `excusedByRelocation`: rule 3 does not fire when
|
|
29
|
+
* the same pass hands the excluded input to another command the gate already
|
|
30
|
+
* runs. Rules 1, 2 and 4 have no excuse.
|
|
27
31
|
*
|
|
28
|
-
* Everything else passes: new env
|
|
29
|
-
* input set, reordering, added chain
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
+
* Everything else passes, each checked by running it: a new env var, a flag that
|
|
33
|
+
* does not restrict the input set, reordering, an added chain member, an
|
|
34
|
+
* identical body. A path replaced by its PARENT classifies as `widen`, not
|
|
35
|
+
* `narrow`. The guard's job is to stop the fix pass from silently redefining the
|
|
36
|
+
* gate's own success criterion — not to review the fix.
|
|
32
37
|
*
|
|
33
|
-
* PURE by construction
|
|
34
|
-
*
|
|
35
|
-
* from git blobs.
|
|
38
|
+
* PURE by construction: the module has no imports at all — no fs, no git, no
|
|
39
|
+
* clock. The live guard feeds it two body maps from `discoverGateCommandBodies`;
|
|
40
|
+
* anything replaying history feeds it two maps built from git blobs. The same
|
|
41
|
+
* code decides both.
|
|
36
42
|
*/
|
|
37
43
|
/** Which of the four mechanical shapes fired. */
|
|
38
44
|
export type ShrinkKind = 'path-added' | 'path-narrowed' | 'exclusion-added' | 'config-swapped';
|
|
@@ -64,8 +70,9 @@ export interface Narrowing {
|
|
|
64
70
|
kinds: ShrinkKind[];
|
|
65
71
|
reasons: string[];
|
|
66
72
|
}
|
|
67
|
-
/** Split a shell body into chain members
|
|
68
|
-
*
|
|
73
|
+
/** Split a shell body into chain members on `&&`, `||`, `;`, `|` and newlines
|
|
74
|
+
* (Makefile recipes arrive as multiple lines). Quote-aware, and it matters:
|
|
75
|
+
* `bun test --name 'a && b' && lint` splits into two members, not three. */
|
|
69
76
|
export declare function splitChainMembers(body: string): string[];
|
|
70
77
|
/** Is this token SYNTACTICALLY a path or glob? Deliberately lexical: no fs. */
|
|
71
78
|
export declare function looksLikePath(tok: string): boolean;
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
* SCOPE-SHRINK detection for the final-gate fix pass.
|
|
3
3
|
*
|
|
4
4
|
* The label guard (final-gate-fix.ts) compares the SET of discoverable gate
|
|
5
|
-
* commands before and after the fix child
|
|
6
|
-
* it
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* commands before and after the fix child, and a fix child walks straight through
|
|
6
|
+
* it. Rewrite `"test": "AGENT=1 bun test"` to `"AGENT=1 bun test ./test"` and the
|
|
7
|
+
* label `bun run test` exists before and after, so the set difference is empty —
|
|
8
|
+
* while the gate now re-runs a suite that no longer covers the repository, and
|
|
9
|
+
* reports that the autofix converged. Fed to `classifyBodyChange`, those two
|
|
10
|
+
* bodies come back `narrow` / `path-added`, which is the whole point of this
|
|
11
|
+
* module.
|
|
10
12
|
*
|
|
11
13
|
* What changed was not the command's NAME but its SCOPE. This module compares
|
|
12
14
|
* the RESOLVED BODIES (`scripts[name]` for package.json, the recipe lines for a
|
|
@@ -16,27 +18,32 @@
|
|
|
16
18
|
* 1. a path/glob argument is ADDED to a command member that had none
|
|
17
19
|
* (`bun test` → `bun test ./test`);
|
|
18
20
|
* 2. an existing path/glob argument is replaced by a strict SUBPATH of itself
|
|
19
|
-
* (`eslint src` → `eslint src/server`)
|
|
21
|
+
* (`eslint ./src` → `eslint ./src/server`). Note the argument has to LOOK
|
|
22
|
+
* like a path — a bare `src` with no separator, dot or glob is not treated
|
|
23
|
+
* as one, so `eslint src` → `eslint src/server` reads as neutral;
|
|
20
24
|
* 3. an exclusion flag/pattern is ADDED (`--ignore`, `--exclude`,
|
|
21
25
|
* `--testPathIgnorePatterns`, `-x`, …);
|
|
22
26
|
* 4. a config-file argument is swapped for one the fix pass itself created.
|
|
23
27
|
*
|
|
24
|
-
* With ONE excuse,
|
|
25
|
-
*
|
|
26
|
-
*
|
|
28
|
+
* With ONE excuse, documented at `excusedByRelocation`: rule 3 does not fire when
|
|
29
|
+
* the same pass hands the excluded input to another command the gate already
|
|
30
|
+
* runs. Rules 1, 2 and 4 have no excuse.
|
|
27
31
|
*
|
|
28
|
-
* Everything else passes: new env
|
|
29
|
-
* input set, reordering, added chain
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
+
* Everything else passes, each checked by running it: a new env var, a flag that
|
|
33
|
+
* does not restrict the input set, reordering, an added chain member, an
|
|
34
|
+
* identical body. A path replaced by its PARENT classifies as `widen`, not
|
|
35
|
+
* `narrow`. The guard's job is to stop the fix pass from silently redefining the
|
|
36
|
+
* gate's own success criterion — not to review the fix.
|
|
32
37
|
*
|
|
33
|
-
* PURE by construction
|
|
34
|
-
*
|
|
35
|
-
* from git blobs.
|
|
38
|
+
* PURE by construction: the module has no imports at all — no fs, no git, no
|
|
39
|
+
* clock. The live guard feeds it two body maps from `discoverGateCommandBodies`;
|
|
40
|
+
* anything replaying history feeds it two maps built from git blobs. The same
|
|
41
|
+
* code decides both.
|
|
36
42
|
*/
|
|
37
43
|
// ── tokenizing ──────────────────────────────────────────────────────────────
|
|
38
|
-
/** Split a shell body into chain members
|
|
39
|
-
*
|
|
44
|
+
/** Split a shell body into chain members on `&&`, `||`, `;`, `|` and newlines
|
|
45
|
+
* (Makefile recipes arrive as multiple lines). Quote-aware, and it matters:
|
|
46
|
+
* `bun test --name 'a && b' && lint` splits into two members, not three. */
|
|
40
47
|
export function splitChainMembers(body) {
|
|
41
48
|
const out = [];
|
|
42
49
|
let cur = '';
|
|
@@ -262,21 +269,20 @@ export function makefileRecipe(makefileText, target) {
|
|
|
262
269
|
}
|
|
263
270
|
// ── the rules ───────────────────────────────────────────────────────────────
|
|
264
271
|
/**
|
|
265
|
-
* RELOCATION EXCUSE
|
|
272
|
+
* RELOCATION EXCUSE.
|
|
266
273
|
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
* command, so the excluded specs never left the gate's coverage — the pass
|
|
272
|
-
* separated two runners that collide, it did not shrink what is measured.
|
|
273
|
-
* Rejecting it would be a false positive, and the rule as first written did.
|
|
274
|
+
* A fix pass can split two runners that collide — excluding a set of specs from
|
|
275
|
+
* one command while adding, in the same body, a chain member that another
|
|
276
|
+
* ALREADY-DISCOVERED gate command runs over exactly those specs. Nothing left the
|
|
277
|
+
* gate's coverage there, so rejecting it would be a false positive.
|
|
274
278
|
*
|
|
275
|
-
* The excuse is deliberately narrow and hard to game: the pass must have
|
|
276
|
-
*
|
|
277
|
-
* discovered gate command's body.
|
|
278
|
-
* near-copy pointed at a different config
|
|
279
|
-
*
|
|
279
|
+
* The excuse is deliberately narrow and hard to game: the pass must have ADDED a
|
|
280
|
+
* chain member that is VERBATIM (whitespace-normalized) a member of another
|
|
281
|
+
* discovered gate command's body. Run both ways — with the sibling present the
|
|
282
|
+
* exclusion classifies neutral, and a near-copy pointed at a different config
|
|
283
|
+
* does NOT excuse it. An added FLAG alone can never qualify, because there is no
|
|
284
|
+
* added member to match. Nothing excuses rules 1, 2 or 4: a path narrowing stands
|
|
285
|
+
* on its own.
|
|
280
286
|
*
|
|
281
287
|
* Returns the matching sibling member, or null.
|
|
282
288
|
*/
|
|
@@ -6,14 +6,17 @@ import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
|
6
6
|
* returns — `godot --headless --check-only` with no timeout, a dev server, a
|
|
7
7
|
* hung test — and the run wedges until the user manually aborts and tells the
|
|
8
8
|
* model to add a timeout. pi's bash tool takes an OPTIONAL `timeout` with NO
|
|
9
|
-
* default
|
|
10
|
-
*
|
|
9
|
+
* default: its schema in `core/tools/bash.js` says "optional, no default
|
|
10
|
+
* timeout" and its resolver returns undefined for an absent value, so no timer is
|
|
11
|
+
* ever armed. This supplies the missing default from the host side.
|
|
11
12
|
*
|
|
12
13
|
* HOW: arm a wall-clock timer on `tool_execution_start`, disarm it on
|
|
13
|
-
* `tool_execution_end
|
|
14
|
-
* operation
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* `tool_execution_end` — both real pi events. If it elapses, `ctx.abort()`
|
|
15
|
+
* cancels the in-flight operation, which fires the tool's AbortSignal; pi's bash
|
|
16
|
+
* executor imports `killProcessTree` and its own comment on that listener reads
|
|
17
|
+
* "Handle abort signal by killing the entire process tree". A follow-up user turn
|
|
18
|
+
* then tells the model what happened so it retries with a timeout instead of
|
|
19
|
+
* hanging again.
|
|
17
20
|
*
|
|
18
21
|
* Tool-agnostic by default: it arms on every tool except exact names listed in
|
|
19
22
|
* `commandTimeoutExemptTools`, which /task-config fills from the live tool list
|
|
@@ -7,14 +7,17 @@ import { CommandWatchdog, realTimerDeps, reminderMessage } from '../shared/comma
|
|
|
7
7
|
* returns — `godot --headless --check-only` with no timeout, a dev server, a
|
|
8
8
|
* hung test — and the run wedges until the user manually aborts and tells the
|
|
9
9
|
* model to add a timeout. pi's bash tool takes an OPTIONAL `timeout` with NO
|
|
10
|
-
* default
|
|
11
|
-
*
|
|
10
|
+
* default: its schema in `core/tools/bash.js` says "optional, no default
|
|
11
|
+
* timeout" and its resolver returns undefined for an absent value, so no timer is
|
|
12
|
+
* ever armed. This supplies the missing default from the host side.
|
|
12
13
|
*
|
|
13
14
|
* HOW: arm a wall-clock timer on `tool_execution_start`, disarm it on
|
|
14
|
-
* `tool_execution_end
|
|
15
|
-
* operation
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* `tool_execution_end` — both real pi events. If it elapses, `ctx.abort()`
|
|
16
|
+
* cancels the in-flight operation, which fires the tool's AbortSignal; pi's bash
|
|
17
|
+
* executor imports `killProcessTree` and its own comment on that listener reads
|
|
18
|
+
* "Handle abort signal by killing the entire process tree". A follow-up user turn
|
|
19
|
+
* then tells the model what happened so it retries with a timeout instead of
|
|
20
|
+
* hanging again.
|
|
18
21
|
*
|
|
19
22
|
* Tool-agnostic by default: it arms on every tool except exact names listed in
|
|
20
23
|
* `commandTimeoutExemptTools`, which /task-config fills from the live tool list
|
|
@@ -33,16 +36,19 @@ import { CommandWatchdog, realTimerDeps, reminderMessage } from '../shared/comma
|
|
|
33
36
|
export { CommandWatchdog, commandTimeoutHint, realTimerDeps, reminderMessage, WATCHDOG_CANCEL_MARKER } from '../shared/command-watchdog.js';
|
|
34
37
|
/**
|
|
35
38
|
* One-shot marker: the most recent turn abort was issued BY THE WATCHDOG, not by
|
|
36
|
-
* a human ESC. Both end the assistant turn
|
|
37
|
-
*
|
|
38
|
-
* steer loop can win the race against the watchdog's queued
|
|
39
|
-
* show a steering prompt to an empty room
|
|
39
|
+
* a human ESC. Both end the assistant turn the same way, and `classifyTurnEnd`
|
|
40
|
+
* has nothing else to go on — it decides with `last?.stopReason === 'aborted'`.
|
|
41
|
+
* Without this flag the steer loop can win the race against the watchdog's queued
|
|
42
|
+
* follow-up turn and show a steering prompt to an empty room, wedging an
|
|
43
|
+
* unattended run.
|
|
40
44
|
*
|
|
41
|
-
* Set synchronously in onFire BEFORE ctx.abort(), so it is observable by the
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
45
|
+
* Set synchronously in onFire BEFORE ctx.abort(), so it is observable by the time
|
|
46
|
+
* any waitForIdle resolves; consumed by the first reader. Run: it reads false
|
|
47
|
+
* before any abort, true once after a note, false again immediately after — and
|
|
48
|
+
* two notes still yield exactly one true. A stale flag (the aborted turn was not
|
|
49
|
+
* one the steer loop was watching) only costs the consumer a bounded wait before
|
|
50
|
+
* it falls back to prompting; it can never permanently suppress a human's steer
|
|
51
|
+
* prompt.
|
|
46
52
|
*/
|
|
47
53
|
let watchdogAbortPending = false;
|
|
48
54
|
/** @internal Set by onFire when it aborts a turn. Exported for the adapter and tests. */
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Deterministic detector for the
|
|
2
|
+
* Deterministic detector for the laundering shape: a CONTEXT bullet that asserts
|
|
3
3
|
* external API USAGE SEMANTICS under an attribution cue that no EXTERNAL CONTEXT block
|
|
4
4
|
* can actually support.
|
|
5
5
|
*
|
|
6
|
-
* THE SHAPE
|
|
6
|
+
* THE SHAPE:
|
|
7
7
|
*
|
|
8
8
|
* - The `hono` dependency is pinned at `^4.12.31` in package.json, and the external
|
|
9
9
|
* context confirms `hc<AppType>` pattern with base URL `/api` for same-origin
|
|
10
10
|
* relative paths works correctly (per Hono RPC docs LIVE data).
|
|
11
11
|
*
|
|
12
|
-
* worker:context
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* The `worker:context` row in phases.ts gives that worker `tools: 'read,grep'` and
|
|
13
|
+
* nothing else — no fetch, no docs channel — so a base-URL claim like that one is
|
|
14
|
+
* necessarily from model memory. It then ships into a task's CONSTRAINTS and
|
|
15
|
+
* ACCEPTANCE, the implementation obeys it exactly, and every request goes to the
|
|
16
|
+
* wrong path.
|
|
17
17
|
*
|
|
18
18
|
* WHY THE OBVIOUS TEST DOES NOT WORK. "Flag a bullet whose package has no EXTERNAL
|
|
19
19
|
* CONTEXT block" misses this case: EXTERNAL CONTEXT *did* carry a `### npm: hono` block.
|
|
20
20
|
* That block contains version numbers and nothing else, so it cannot support a claim
|
|
21
21
|
* about what a base URL MEANS — yet it lends the sentence an air of having been checked.
|
|
22
|
-
* That is the whole mechanism
|
|
22
|
+
* That is the whole mechanism: one citable fact, the pinned version, fused in a
|
|
23
23
|
* single sentence with an uncitable one under a shared attribution. The true half
|
|
24
24
|
* launders the false half.
|
|
25
25
|
*
|
|
@@ -30,27 +30,35 @@
|
|
|
30
30
|
* ### url: fetched page content -> CAN source a semantics claim
|
|
31
31
|
* ### service: 3 search-result SNIPPETS -> cannot source a semantics claim
|
|
32
32
|
*
|
|
33
|
-
* The `service` exclusion is not a judgement call — it is the LIVE-DATA RULE's own
|
|
34
|
-
* That rule makes a service block authoritative for "current
|
|
35
|
-
* status, and replacement systems", i.e. versions
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
33
|
+
* The `service` exclusion is not a judgement call — it is the LIVE-DATA RULE's own
|
|
34
|
+
* scope. That rule (prompts.ts) makes a service block authoritative for "current
|
|
35
|
+
* API surface, deprecation status, and replacement systems", i.e. versions, status
|
|
36
|
+
* and names. And a service block is only ever a title, a URL and a one-line
|
|
37
|
+
* description per result — see `formatServiceBlock` — so it cannot carry what a
|
|
38
|
+
* parameter MEANS.
|
|
39
|
+
*
|
|
40
|
+
* This matters concretely, and was checked: with a single
|
|
41
|
+
* `### service: Hono RPC client` block as the only external context, the fatal
|
|
42
|
+
* bullet IS flagged. Were `service` treated as source-capable, that subject would
|
|
43
|
+
* match the package `hono` and the bullet would pass — leaving the detector unable
|
|
44
|
+
* to catch the one defect it exists for.
|
|
43
45
|
*
|
|
44
46
|
* A bullet is FLAGGED iff all three hold:
|
|
45
|
-
* 1. it carries an attribution cue ("per
|
|
46
|
-
* confirms", "docs confirm", "per the official docs"
|
|
47
|
-
* 2. it asserts API usage semantics — how something is called, what a parameter
|
|
48
|
-
* what a default is, what behaviour results — as opposed to a version
|
|
47
|
+
* 1. it carries an attribution cue ("per... LIVE data", "the external context
|
|
48
|
+
* confirms", "docs confirm", "per the official docs",...);
|
|
49
|
+
* 2. it asserts API usage semantics — how something is called, what a parameter
|
|
50
|
+
* means, what a default is, what behaviour results — as opposed to a version
|
|
51
|
+
* or a status;
|
|
49
52
|
* 3. no `### url:` or `### docs:` block exists for any package the bullet names.
|
|
50
53
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
+
* All six branches were run against the laundering bullet above. It is FLAGGED with
|
|
55
|
+
* an npm-only block, with a service-only block, and with no external context at
|
|
56
|
+
* all; it is NOT flagged once a `### docs:` or `### url:` block for that package
|
|
57
|
+
* exists. And the same context leaves alone a version claim made under an
|
|
58
|
+
* attribution cue, a semantics claim made with NO cue, and a plain "is pinned at"
|
|
59
|
+
* statement of fact.
|
|
60
|
+
*
|
|
61
|
+
* Pure and side-effect free; also unit-tested in context-attribution.test.ts.
|
|
54
62
|
*/
|
|
55
63
|
/** A block that actually appears in an EXTERNAL CONTEXT header. */
|
|
56
64
|
export interface ContextBlock {
|
|
@@ -81,7 +89,7 @@ export interface BulletSpan {
|
|
|
81
89
|
/**
|
|
82
90
|
* Split a CONTEXT section into bullets WITH their line ranges. Continuation lines are
|
|
83
91
|
* folded into the bullet above so a hard-wrapped claim is judged as one sentence — which
|
|
84
|
-
* is exactly how the fatal
|
|
92
|
+
* is exactly how the fatal bullet was written.
|
|
85
93
|
*/
|
|
86
94
|
export declare function splitBulletSpans(context: string): BulletSpan[];
|
|
87
95
|
/** Split a CONTEXT section into its bullets, joining hard-wrapped continuation lines. */
|