@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
|
@@ -3,24 +3,30 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A cancel is a *request*, never a kill. It is honoured only where the on-disk
|
|
5
5
|
* state is durable and /task-auto-resume provably continues from it. Killing a
|
|
6
|
-
* child mid-phase would also stop the run
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* child mid-phase would also stop the run — the abort signal reaches every
|
|
7
|
+
* child's process group — but it throws away that phase's work and can leave a
|
|
8
|
+
* half-written tree, so the flag is polled at boundaries instead.
|
|
9
9
|
*
|
|
10
|
-
* The checkpoint set
|
|
10
|
+
* The checkpoint set is exactly these four, one call site each:
|
|
11
11
|
*
|
|
12
|
-
* loop-top the previous task is checked off
|
|
13
|
-
*
|
|
14
|
-
* pre-task after the pre-task checkpoint commit,
|
|
15
|
-
* constructed: tree committed, no inner id
|
|
16
|
-
* entry is simply still unchecked and a
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* the
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
12
|
+
* loop-top (auto-orchestrator) the previous task is checked off and
|
|
13
|
+
* committed and the next one has not started.
|
|
14
|
+
* pre-task (auto-orchestrator) after the pre-task checkpoint commit,
|
|
15
|
+
* before the runner is constructed: tree committed, no inner id
|
|
16
|
+
* stamped yet, so the entry is simply still unchecked and a
|
|
17
|
+
* resume restarts it.
|
|
18
|
+
* phase:<name> (orchestrator, inside the phase loop) after setTaskSection and
|
|
19
|
+
* postCommitPhase have persisted this phase's output. Front-matter
|
|
20
|
+
* `phase` still names the phase that JUST FINISHED, not the next
|
|
21
|
+
* one: `advance()` writes it at the TOP of each iteration and
|
|
22
|
+
* nothing moves it afterwards — postCommitPhase writes only
|
|
23
|
+
* `title` and `label`. Since the resume skip rule is
|
|
24
|
+
* `idx < resumeIdx`, a resume therefore RE-ENTERS this phase and
|
|
25
|
+
* runs it again. Nothing is lost, because its section is already
|
|
26
|
+
* on disk; the cost is repeating one phase, not zero.
|
|
27
|
+
* pre-final-gate (run-final-gate) every task is checked off and committed; the
|
|
28
|
+
* whole-repo gate has not started. A resume re-enters the same
|
|
29
|
+
* branch.
|
|
24
30
|
*
|
|
25
31
|
* DELIBERATELY NOT checkpoints — stopping here is not safe:
|
|
26
32
|
* - mid implementation turn: uncommitted, half-applied edits. The user's ESC
|
|
@@ -31,7 +37,8 @@
|
|
|
31
37
|
*/
|
|
32
38
|
let requested = false;
|
|
33
39
|
/** Checkpoints actually reached since the last reset, in order. Instrumentation
|
|
34
|
-
*
|
|
40
|
+
* only: `checkpointsCrossed` and `resetCheckpointTrail` have no caller anywhere
|
|
41
|
+
* in src/ — every consumer is a test. */
|
|
35
42
|
const crossed = [];
|
|
36
43
|
export function requestCancel() {
|
|
37
44
|
requested = true;
|
|
@@ -51,7 +58,7 @@ export function isCancelRequested() {
|
|
|
51
58
|
export function resetCancel() {
|
|
52
59
|
requested = false;
|
|
53
60
|
}
|
|
54
|
-
/** Drop the recorded checkpoint trail
|
|
61
|
+
/** Drop the recorded checkpoint trail. */
|
|
55
62
|
export function resetCheckpointTrail() {
|
|
56
63
|
crossed.length = 0;
|
|
57
64
|
}
|
|
@@ -64,14 +71,15 @@ export function resetCheckpointTrail() {
|
|
|
64
71
|
*/
|
|
65
72
|
export function cancelCheckpoint(where) {
|
|
66
73
|
crossed.push(where);
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
74
|
+
// CANCEL_AB_ARM=baseline collapses the checkpoint set back to loop-top alone,
|
|
75
|
+
// so the two arms differ in exactly one thing. Nothing in src/ ever sets it;
|
|
76
|
+
// the only writer in the tree is cancel-points.test.ts, which uses it to pin
|
|
77
|
+
// that the extra checkpoints — and only they — are what the flag gates.
|
|
70
78
|
if (process.env.CANCEL_AB_ARM === 'baseline' && where !== 'loop-top')
|
|
71
79
|
return false;
|
|
72
80
|
return requested;
|
|
73
81
|
}
|
|
74
|
-
/** Checkpoints crossed since the last reset
|
|
82
|
+
/** Checkpoints crossed since the last reset. */
|
|
75
83
|
export function checkpointsCrossed() {
|
|
76
84
|
return crossed;
|
|
77
85
|
}
|
|
@@ -18,22 +18,19 @@ export declare const MAX_LOOP_RESTARTS = 2;
|
|
|
18
18
|
/**
|
|
19
19
|
* Optional wall-clock bound on ONE spawn of a phase child. DEFAULT: OFF.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* WHY OFF, AND NOT A NUMBER. A wall clock on a model child measures the
|
|
22
|
+
* MODEL'S SPEED, not its health. The same planning child that answers well in
|
|
23
|
+
* seconds on one backend takes many minutes on another, or on the same backend
|
|
24
|
+
* with thinking turned on — so any cap generous enough to be safe is too loose
|
|
25
|
+
* to catch anything, and any cap tight enough to catch a runaway kills healthy
|
|
26
|
+
* work. Assume a model that emits one token per second and the number has no
|
|
27
|
+
* defensible value at all.
|
|
24
28
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* pathology, it was measuring one model's speed on one day.
|
|
31
|
-
*
|
|
32
|
-
* The runaway it was there to catch — a decompose child that ran 16m23s at
|
|
33
|
-
* 117,370 of a 120,064-token window, forward-paging past the loop detector — is
|
|
34
|
-
* now caught by StallDetector (stall-detector.ts), which bounds NON-PROGRESS and
|
|
35
|
-
* CONTEXT CHURN instead of elapsed seconds. Both of those are properties of the
|
|
36
|
-
* pathology, so neither has to be re-tuned for a slower model or a bigger repo.
|
|
29
|
+
* The runaway it was there to catch — a child forward-paging through its whole
|
|
30
|
+
* context window, past the loop detector, never going to return — is caught by
|
|
31
|
+
* StallDetector (stall-detector.ts) instead. That bounds NON-PROGRESS and
|
|
32
|
+
* CONTEXT CHURN, both properties of the pathology itself, so neither has to be
|
|
33
|
+
* re-tuned for a slower model or a bigger repo.
|
|
37
34
|
*
|
|
38
35
|
* The value and the plumbing stay for a caller that genuinely wants a hard stop
|
|
39
36
|
* (tests inject a short one), but nothing sets it in production. Pass
|
|
@@ -84,13 +81,13 @@ export declare const USER_CANCELLED = "__user_cancelled__";
|
|
|
84
81
|
/**
|
|
85
82
|
* One child-pi invocation, as a value.
|
|
86
83
|
*
|
|
87
|
-
* WHY A RECORD
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
84
|
+
* WHY A RECORD RATHER THAN POSITIONALS. With this many optional parameters of
|
|
85
|
+
* the same type, a caller reaching a late one must write bare `undefined`s to get
|
|
86
|
+
* there, and one that miscounts silently lands the wrong value in the wrong slot.
|
|
87
|
+
* The failure that shape produces here is a child spawned with the RAW signal
|
|
88
|
+
* instead of the wall-clocked one, escaping a guard its siblings run under, with
|
|
89
|
+
* nothing to catch it. Named fields make adjacent optionals of the same type
|
|
90
|
+
* impossible to swap without a type error.
|
|
94
91
|
*/
|
|
95
92
|
export interface ChildRun {
|
|
96
93
|
cwd: string;
|
|
@@ -111,9 +108,11 @@ export interface ChildRun {
|
|
|
111
108
|
*/
|
|
112
109
|
onToolResult?: (text: string, isError: boolean) => void;
|
|
113
110
|
/**
|
|
114
|
-
* The child's context window in tokens. Nothing in pi's
|
|
115
|
-
* one
|
|
116
|
-
*
|
|
111
|
+
* The child's context window in tokens. Nothing in pi's `--mode json` stream
|
|
112
|
+
* reports one — a real capture carries token counts and a model id, but no key
|
|
113
|
+
* naming a window — so the parent hands its own down. Children carry no `-m`
|
|
114
|
+
* (CHILD_BASE_ARGS) and resolve the same default model, which is what makes
|
|
115
|
+
* the parent's window the honest value. 0 or omitted = unknown.
|
|
117
116
|
*/
|
|
118
117
|
contextWindow?: number;
|
|
119
118
|
/**
|
|
@@ -132,12 +131,12 @@ export interface PhaseDeps {
|
|
|
132
131
|
/**
|
|
133
132
|
* The parent session's context window in tokens, handed down to every child.
|
|
134
133
|
*
|
|
135
|
-
* pi's `--mode json` stream reports token counts but no window
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* run the parent's own default model
|
|
140
|
-
* Absent = unknown, and both consumers degrade
|
|
134
|
+
* pi's `--mode json` stream reports token counts but no window, so without
|
|
135
|
+
* this the gauge shows a bare number and — worse — the StallDetector's CONTEXT
|
|
136
|
+
* CHURN rule can never fire: it opens with `if (this.contextWindow <= 0)
|
|
137
|
+
* return false`. Children are spawned without `-m` (CHILD_BASE_ARGS) and so
|
|
138
|
+
* run the parent's own default model, which is what makes its window the
|
|
139
|
+
* honest value. Absent = unknown, and both consumers degrade.
|
|
141
140
|
*/
|
|
142
141
|
contextWindow?: number;
|
|
143
142
|
/**
|
|
@@ -185,11 +184,10 @@ export interface PhaseDeps {
|
|
|
185
184
|
* the substitute answers directly and NONE of those guards run.
|
|
186
185
|
*
|
|
187
186
|
* The child's NAME is the first parameter because the name is what a caller
|
|
188
|
-
* branches on and what a test wants to assert.
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
* rewording prompts and A/B-ing them.
|
|
187
|
+
* branches on and what a test wants to assert. Discarded before it reaches
|
|
188
|
+
* the only injectable boundary (`spawn`), a phase test has to reconstruct it
|
|
189
|
+
* by matching prompt PROSE against prompts.ts — which makes prompt copy
|
|
190
|
+
* load-bearing test infrastructure in a codebase that rewords prompts.
|
|
193
191
|
*
|
|
194
192
|
* `spawn` stays: the ladder's OWN tests must drive a real process to exercise
|
|
195
193
|
* the rungs. This seam is for callers to whom the child is a premise.
|
|
@@ -232,13 +230,10 @@ export interface PhaseDeps {
|
|
|
232
230
|
* The subset of `PhaseDeps` a CALLER may supply — every injectable seam, derived
|
|
233
231
|
* by naming what the runner owns instead of by listing what it does not.
|
|
234
232
|
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
* you skipped one — the exact indictment this codebase already recorded against
|
|
240
|
-
* `ConfigItem`. Four seams (`timeoutMs`, `sleepFor`, `childExtensions`,
|
|
241
|
-
* `logDebug`) had in fact been left behind, so a runner-driven test of the
|
|
233
|
+
* Declaring the seams separately on `TaskRunnerOptions`, re-picking them on
|
|
234
|
+
* `RunSingleTaskOptions`, re-forwarding each by name and spreading them back
|
|
235
|
+
* together is four coordinated edits, none of which fails to compile if you skip
|
|
236
|
+
* one. Seams get left behind that way, and a runner-driven test of the
|
|
242
237
|
* connection-error rung really slept and the debug trail could not be asserted at
|
|
243
238
|
* all. Derived by `Omit`, a NEW seam field joins this with no second edit.
|
|
244
239
|
*/
|
|
@@ -254,16 +249,16 @@ export type PhaseSeams = Omit<PhaseDeps, 'cwd' | 'taskId' | 'signal' | 'onChildO
|
|
|
254
249
|
*
|
|
255
250
|
* THREE RUNAWAY GUARDS ride the same budget, because this is the runner every
|
|
256
251
|
* /task-auto planning child goes through (clarify, decompose, coverage,
|
|
257
|
-
* contract-extract) and
|
|
252
|
+
* contract-extract), and an unguarded planning child can burn a whole run:
|
|
258
253
|
* • a LoopDetector, so an identical repeated tool call is killed and
|
|
259
254
|
* re-prompted instead of being allowed to fill the context window;
|
|
260
255
|
* • a StallDetector, the backstop for the varied-args thrash the loop
|
|
261
|
-
* detector's short window cannot see —
|
|
262
|
-
*
|
|
256
|
+
* detector's short window cannot see — a child that keeps calling tools with
|
|
257
|
+
* different arguments, learns nothing, and is never going to return. It bounds
|
|
263
258
|
* consecutive no-new-ground calls and total context churn, NOT elapsed time;
|
|
264
|
-
* • PHASE_CHILD_TIMEOUT_MS, a hard wall clock, OFF by default
|
|
265
|
-
*
|
|
266
|
-
*
|
|
259
|
+
* • PHASE_CHILD_TIMEOUT_MS, a hard wall clock, OFF by default: a healthy
|
|
260
|
+
* reasoning-on planning child and a runaway one occupy the same range of
|
|
261
|
+
* elapsed times, so no threshold separates them. See its comment.
|
|
267
262
|
* All three are checked BEFORE the triage ladder: we killed the child, so its
|
|
268
263
|
* exit status describes our SIGTERM and says nothing about its verdict.
|
|
269
264
|
*/
|
|
@@ -292,8 +287,8 @@ export declare function prependHint(hint: string | null, prompt: string): string
|
|
|
292
287
|
/**
|
|
293
288
|
* The two things a phase child can disagree about. Everything else — the loop
|
|
294
289
|
* and stall detectors, the wall clock, the loop trail, the triage ladder and its
|
|
295
|
-
* budget — is the one loop's
|
|
296
|
-
*
|
|
290
|
+
* budget — is the one loop's. These two are the only differences observable from
|
|
291
|
+
* outside it.
|
|
297
292
|
*/
|
|
298
293
|
export interface PhaseChildOptions {
|
|
299
294
|
/**
|
|
@@ -28,22 +28,19 @@ export const MAX_LOOP_RESTARTS = 2; // 3 strikes total (initial attempt + 2 rest
|
|
|
28
28
|
/**
|
|
29
29
|
* Optional wall-clock bound on ONE spawn of a phase child. DEFAULT: OFF.
|
|
30
30
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* WHY OFF, AND NOT A NUMBER. A wall clock on a model child measures the
|
|
32
|
+
* MODEL'S SPEED, not its health. The same planning child that answers well in
|
|
33
|
+
* seconds on one backend takes many minutes on another, or on the same backend
|
|
34
|
+
* with thinking turned on — so any cap generous enough to be safe is too loose
|
|
35
|
+
* to catch anything, and any cap tight enough to catch a runaway kills healthy
|
|
36
|
+
* work. Assume a model that emits one token per second and the number has no
|
|
37
|
+
* defensible value at all.
|
|
34
38
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* pathology, it was measuring one model's speed on one day.
|
|
41
|
-
*
|
|
42
|
-
* The runaway it was there to catch — a decompose child that ran 16m23s at
|
|
43
|
-
* 117,370 of a 120,064-token window, forward-paging past the loop detector — is
|
|
44
|
-
* now caught by StallDetector (stall-detector.ts), which bounds NON-PROGRESS and
|
|
45
|
-
* CONTEXT CHURN instead of elapsed seconds. Both of those are properties of the
|
|
46
|
-
* pathology, so neither has to be re-tuned for a slower model or a bigger repo.
|
|
39
|
+
* The runaway it was there to catch — a child forward-paging through its whole
|
|
40
|
+
* context window, past the loop detector, never going to return — is caught by
|
|
41
|
+
* StallDetector (stall-detector.ts) instead. That bounds NON-PROGRESS and
|
|
42
|
+
* CONTEXT CHURN, both properties of the pathology itself, so neither has to be
|
|
43
|
+
* re-tuned for a slower model or a bigger repo.
|
|
47
44
|
*
|
|
48
45
|
* The value and the plumbing stay for a caller that genuinely wants a hard stop
|
|
49
46
|
* (tests inject a short one), but nothing sets it in production. Pass
|
|
@@ -145,8 +142,8 @@ thinking = []) {
|
|
|
145
142
|
// `--mode json` puts the child into the structured event stream the
|
|
146
143
|
// unified runner parses in `mode: 'json-events'`. Without it the child
|
|
147
144
|
// emits plain text, every line fails JSON.parse, finalText stays empty,
|
|
148
|
-
// and every phase fails with "X child produced no output".
|
|
149
|
-
// dropped
|
|
145
|
+
// and every phase fails with "X child produced no output". A refactor has
|
|
146
|
+
// dropped it once already; do not remove it again.
|
|
150
147
|
//
|
|
151
148
|
// An empty `tools` string means "no tools at all" — emit `--no-tools`
|
|
152
149
|
// instead of `--tools ''` (which pi would reject). Used by pure-judgment
|
|
@@ -154,8 +151,9 @@ thinking = []) {
|
|
|
154
151
|
// hand them, never spend time reading the repo.
|
|
155
152
|
//
|
|
156
153
|
// The prompt is NOT an argv element: it goes to the child over stdin (see
|
|
157
|
-
// runChild below / getPiInvocation), so a large inlined-design prompt
|
|
158
|
-
//
|
|
154
|
+
// runChild below / getPiInvocation), so a large inlined-design prompt cannot
|
|
155
|
+
// exceed the OS argv ceiling — which fails the spawn outright rather than
|
|
156
|
+
// truncating (`E2BIG` on this platform).
|
|
159
157
|
//
|
|
160
158
|
// `extensions` are internal `-e` loads for in-run guards (the caller supplies
|
|
161
159
|
// the path). A no-tools child cannot make a tool call, so it never carries
|
|
@@ -173,7 +171,7 @@ export async function runChild({ cwd, tools, prompt, signal, onLine, onContextUs
|
|
|
173
171
|
const result = await runChildUnified(spawnFn ?? spawn, invocation, cwd, signal, {
|
|
174
172
|
mode: 'json-events',
|
|
175
173
|
// A hung model stream reports nothing at all, so without this the
|
|
176
|
-
// phase child waits forever
|
|
174
|
+
// phase child waits forever. The kill
|
|
177
175
|
// is reported below as a connection-class cause, which routes it into
|
|
178
176
|
// the retry/backoff path this file already has for a LOUD disconnect.
|
|
179
177
|
streamInactivityMs: getConfig().streamInactivityMs,
|
|
@@ -226,9 +224,8 @@ export async function runChild({ cwd, tools, prompt, signal, onLine, onContextUs
|
|
|
226
224
|
* verdict, so a fix to any rung lands in every caller at once.
|
|
227
225
|
*
|
|
228
226
|
* `attempt` is the caller's 0-based counter, `budget` the matching restart
|
|
229
|
-
* allowance
|
|
230
|
-
*
|
|
231
|
-
* loop now) — so a phase runs `budget + 1` attempts before a rung gives up.
|
|
227
|
+
* allowance — MAX_LEAK_RETRIES and MAX_LOOP_RESTARTS are both 2, and one loop
|
|
228
|
+
* spends the pair — so a phase runs `budget + 1` attempts before a rung gives up.
|
|
232
229
|
*
|
|
233
230
|
* `verb` names the restart in the debug log ("retry" by default, "restart" for
|
|
234
231
|
* refine and grill-gen). It is the only externally visible thing that differed
|
|
@@ -240,7 +237,11 @@ export async function runChild({ cwd, tools, prompt, signal, onLine, onContextUs
|
|
|
240
237
|
*/
|
|
241
238
|
async function triageChildResult(deps, name, r, attempt, budget, verb) {
|
|
242
239
|
if (r.exitCode !== 0) {
|
|
243
|
-
|
|
240
|
+
// The exit code is the only signal when stderr is empty, and pi exits
|
|
241
|
+
// silently on several paths (143 = SIGTERM/loop-kill, 137 = SIGKILL/OOM).
|
|
242
|
+
// Dropping it left "(no stderr)" as the whole diagnosis.
|
|
243
|
+
const why = r.stderr || `no stderr, exit ${r.exitCode}`;
|
|
244
|
+
throw new Error(`${name} child failed: ${why}`);
|
|
244
245
|
}
|
|
245
246
|
if (r.modelError) {
|
|
246
247
|
// The model/provider failed (pi exited 0 with a stopReason "error"
|
|
@@ -286,16 +287,16 @@ async function triageChildResult(deps, name, r, attempt, budget, verb) {
|
|
|
286
287
|
*
|
|
287
288
|
* THREE RUNAWAY GUARDS ride the same budget, because this is the runner every
|
|
288
289
|
* /task-auto planning child goes through (clarify, decompose, coverage,
|
|
289
|
-
* contract-extract) and
|
|
290
|
+
* contract-extract), and an unguarded planning child can burn a whole run:
|
|
290
291
|
* • a LoopDetector, so an identical repeated tool call is killed and
|
|
291
292
|
* re-prompted instead of being allowed to fill the context window;
|
|
292
293
|
* • a StallDetector, the backstop for the varied-args thrash the loop
|
|
293
|
-
* detector's short window cannot see —
|
|
294
|
-
*
|
|
294
|
+
* detector's short window cannot see — a child that keeps calling tools with
|
|
295
|
+
* different arguments, learns nothing, and is never going to return. It bounds
|
|
295
296
|
* consecutive no-new-ground calls and total context churn, NOT elapsed time;
|
|
296
|
-
* • PHASE_CHILD_TIMEOUT_MS, a hard wall clock, OFF by default
|
|
297
|
-
*
|
|
298
|
-
*
|
|
297
|
+
* • PHASE_CHILD_TIMEOUT_MS, a hard wall clock, OFF by default: a healthy
|
|
298
|
+
* reasoning-on planning child and a runaway one occupy the same range of
|
|
299
|
+
* elapsed times, so no threshold separates them. See its comment.
|
|
299
300
|
* All three are checked BEFORE the triage ladder: we killed the child, so its
|
|
300
301
|
* exit status describes our SIGTERM and says nothing about its verdict.
|
|
301
302
|
*/
|
|
@@ -351,10 +352,10 @@ export async function runPhaseChild(deps, name, tools, prompt, opts = {}) {
|
|
|
351
352
|
throw new Error(USER_CANCELLED);
|
|
352
353
|
const detector = new LoopDetector(LOOP_WINDOW, LOOP_THRESHOLD);
|
|
353
354
|
const stall = new StallDetector();
|
|
354
|
-
// Arm the churn rule BEFORE the first tool call.
|
|
355
|
-
//
|
|
356
|
-
//
|
|
357
|
-
//
|
|
355
|
+
// Arm the churn rule BEFORE the first tool call. pi's stream carries no
|
|
356
|
+
// context WINDOW, so a detector that waited to be told one would sit at 0,
|
|
357
|
+
// and the churn rule returns false on a non-positive window. The parent
|
|
358
|
+
// knows the value at spawn time — say it then, not later.
|
|
358
359
|
stall.noteContext(deps.contextWindow ?? 0);
|
|
359
360
|
const clock = phaseTimeout(deps.signal, budgetMs);
|
|
360
361
|
let r;
|
|
@@ -365,9 +366,10 @@ export async function runPhaseChild(deps, name, tools, prompt, opts = {}) {
|
|
|
365
366
|
signal: clock.signal,
|
|
366
367
|
thinking,
|
|
367
368
|
onContextUsage: snapshot => {
|
|
368
|
-
// Real window or nothing: noteContext ignores 0,
|
|
369
|
-
//
|
|
370
|
-
//
|
|
369
|
+
// Real window or nothing: `noteContext` ignores 0, which is
|
|
370
|
+
// why the parent's value must be supplied at spawn — a
|
|
371
|
+
// stream that only ever reports 0 leaves the churn rule
|
|
372
|
+
// permanently disarmed.
|
|
371
373
|
stall.noteContext(snapshot.contextWindow);
|
|
372
374
|
deps.onContextUsage?.(snapshot);
|
|
373
375
|
},
|
|
@@ -450,8 +452,8 @@ export function prependHint(hint, prompt) {
|
|
|
450
452
|
* Append one line to the task file's `loop events` section.
|
|
451
453
|
*
|
|
452
454
|
* Best-effort by contract: it runs for EVERY phase child now that there is one
|
|
453
|
-
* loop, and
|
|
454
|
-
*
|
|
455
|
+
* loop, and not every caller owns a task file on disk (a scripted harness, a
|
|
456
|
+
* bare unit deps bag). A trail
|
|
455
457
|
* that cannot be written must cost the phase nothing — the loop kill itself is
|
|
456
458
|
* already reported through the debug log and the thrown LoopExhaustedError.
|
|
457
459
|
*/
|
|
@@ -480,11 +482,9 @@ async function appendLoopEvent(cwd, taskId, phase, hit, strike, outcome) {
|
|
|
480
482
|
*/
|
|
481
483
|
async function runDegradedFinalAttempt(deps, name, prompt, hit, loopHistory) {
|
|
482
484
|
deps.logDebug?.(`${name}: loop budget exhausted — degrading to a no-tools final attempt`);
|
|
483
|
-
//
|
|
484
|
-
//
|
|
485
|
-
//
|
|
486
|
-
// positionals — so the one attempt made after a loop budget was spent was
|
|
487
|
-
// also the one attempt that could hang forever.
|
|
485
|
+
// This attempt runs under the same wall clock as the strikes that led here.
|
|
486
|
+
// Passing `deps.signal` raw instead would make the one attempt taken after a
|
|
487
|
+
// loop budget is spent the one attempt that can hang forever.
|
|
488
488
|
const clock = phaseTimeout(deps.signal, deps.timeoutMs ?? PHASE_CHILD_TIMEOUT_MS);
|
|
489
489
|
let r;
|
|
490
490
|
try {
|
|
@@ -502,11 +502,10 @@ async function runDegradedFinalAttempt(deps, name, prompt, hit, loopHistory) {
|
|
|
502
502
|
clock.cleanup();
|
|
503
503
|
}
|
|
504
504
|
if (r.exitCode !== 0 || r.modelError || r.text.trim().length === 0) {
|
|
505
|
-
// A wall-clock kill is NOT a loop.
|
|
506
|
-
//
|
|
507
|
-
//
|
|
508
|
-
//
|
|
509
|
-
// the very path that clock was added to guard.
|
|
505
|
+
// A wall-clock kill is NOT a loop. Without this check a child that outran
|
|
506
|
+
// its budget is reported as "loop budget exhausted", carrying a loop
|
|
507
|
+
// history that did not cause it — the same mislabel class the worker-kill
|
|
508
|
+
// roster exists to prevent, on the very path the clock guards.
|
|
510
509
|
if (clock.timedOut()) {
|
|
511
510
|
throw new PhaseTimeoutError(name, deps.timeoutMs ?? PHASE_CHILD_TIMEOUT_MS, 1);
|
|
512
511
|
}
|
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
* ChildStatus — the live status of the child pi currently running under a
|
|
3
3
|
* status loader: its latest output line and its context usage.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Without it each spawn site keeps this state by hand — `let lastLine; let contextUsage;`
|
|
6
6
|
* plus two callbacks (`onChildOutput` writes the line, `onContextUsage` folds a
|
|
7
7
|
* snapshot through `resolveContextUsage` with the parent window), a reset before
|
|
8
|
-
* every child, and a loader whose every tick
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
8
|
+
* every child, and a loader whose every tick reads both.
|
|
9
|
+
*
|
|
10
|
+
* Three sites share that ritual and are now this class: `/task-auto`'s planning
|
|
11
|
+
* `runChild`, `buildGateDeps`, and `/task-plan` — one `new ChildStatus` each, and
|
|
12
|
+
* no others. The single-task `TaskRunner` deliberately stays where it is: its
|
|
13
|
+
* state is the whole-run `WidgetState`, shared by reference with `PhaseContext`
|
|
14
|
+
* and written by the phases themselves (see `orchestrator.ts`).
|
|
14
15
|
*
|
|
15
16
|
* `track` is the loader ritual: reset, raise the loader reading this status on
|
|
16
17
|
* every tick, run, always stop. The status OUTLIVES a track — `buildGateDeps`
|
|
17
18
|
* shares one across every gate child, and the verify gate raises its own
|
|
18
|
-
* gate-wide loader over a child that renders none (`frame: null
|
|
19
|
-
* see the same object.
|
|
19
|
+
* gate-wide loader over a child that renders none (`frame: null`, reached when
|
|
20
|
+
* `deps.loader === false` in gate-child), so both must see the same object.
|
|
20
21
|
*/
|
|
21
22
|
import type { ExtensionCommandContext } from '@earendil-works/pi-coding-agent';
|
|
22
23
|
import type { ContextSnapshot } from '../shared/child-process.js';
|
|
@@ -55,12 +56,17 @@ export declare class ChildStatus {
|
|
|
55
56
|
};
|
|
56
57
|
/**
|
|
57
58
|
* Run `run` under the loader: reset, raise a loader whose every tick is
|
|
58
|
-
* `frame()`
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
59
|
+
* `frame()` spread OVER the live line and gauge, and stop it in a `finally`.
|
|
60
|
+
* All four behaviours were run against a fake loader:
|
|
61
|
+
* - the reset lands first, so the previous child's line never reaches the
|
|
62
|
+
* new loader's first tick;
|
|
63
|
+
* - `frame` wins on a clash, because it is spread last — which is how the
|
|
64
|
+
* verify gate shows its deterministic-stage label until the child has a
|
|
65
|
+
* line of its own;
|
|
66
|
+
* - `frame: null` raises NO loader at all (the caller already has one
|
|
67
|
+
* reading this status) but still resets;
|
|
68
|
+
* - a child that THROWS still stops the loader, so a failure never leaves
|
|
69
|
+
* the widget up.
|
|
64
70
|
*/
|
|
65
71
|
track<T>(ctx: ExtensionCommandContext, frame: (() => AutoLoaderState) | null, run: () => Promise<T>): Promise<T>;
|
|
66
72
|
}
|
|
@@ -98,6 +104,7 @@ export declare function runPlanningChild(opts: {
|
|
|
98
104
|
}): Promise<string>;
|
|
99
105
|
/**
|
|
100
106
|
* Wire a `ChildStatus` as a phase child's stream callbacks — plus the window the
|
|
101
|
-
* child must be TOLD, since pi's
|
|
107
|
+
* child must be TOLD, since pi's `--mode json` stream reports token counts but no
|
|
108
|
+
* context window.
|
|
102
109
|
*/
|
|
103
110
|
export declare function statusCallbacks(status: ChildStatus): Pick<PhaseDeps, 'onChildOutput' | 'onContextUsage' | 'contextWindow'>;
|
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
* ChildStatus — the live status of the child pi currently running under a
|
|
3
3
|
* status loader: its latest output line and its context usage.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Without it each spawn site keeps this state by hand — `let lastLine; let contextUsage;`
|
|
6
6
|
* plus two callbacks (`onChildOutput` writes the line, `onContextUsage` folds a
|
|
7
7
|
* snapshot through `resolveContextUsage` with the parent window), a reset before
|
|
8
|
-
* every child, and a loader whose every tick
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
8
|
+
* every child, and a loader whose every tick reads both.
|
|
9
|
+
*
|
|
10
|
+
* Three sites share that ritual and are now this class: `/task-auto`'s planning
|
|
11
|
+
* `runChild`, `buildGateDeps`, and `/task-plan` — one `new ChildStatus` each, and
|
|
12
|
+
* no others. The single-task `TaskRunner` deliberately stays where it is: its
|
|
13
|
+
* state is the whole-run `WidgetState`, shared by reference with `PhaseContext`
|
|
14
|
+
* and written by the phases themselves (see `orchestrator.ts`).
|
|
14
15
|
*
|
|
15
16
|
* `track` is the loader ritual: reset, raise the loader reading this status on
|
|
16
17
|
* every tick, run, always stop. The status OUTLIVES a track — `buildGateDeps`
|
|
17
18
|
* shares one across every gate child, and the verify gate raises its own
|
|
18
|
-
* gate-wide loader over a child that renders none (`frame: null
|
|
19
|
-
* see the same object.
|
|
19
|
+
* gate-wide loader over a child that renders none (`frame: null`, reached when
|
|
20
|
+
* `deps.loader === false` in gate-child), so both must see the same object.
|
|
20
21
|
*/
|
|
21
22
|
import { runPhaseChild } from './child-runner.js';
|
|
22
23
|
import { resolveContextUsage } from './context-usage.js';
|
|
@@ -59,12 +60,17 @@ export class ChildStatus {
|
|
|
59
60
|
}
|
|
60
61
|
/**
|
|
61
62
|
* Run `run` under the loader: reset, raise a loader whose every tick is
|
|
62
|
-
* `frame()`
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
63
|
+
* `frame()` spread OVER the live line and gauge, and stop it in a `finally`.
|
|
64
|
+
* All four behaviours were run against a fake loader:
|
|
65
|
+
* - the reset lands first, so the previous child's line never reaches the
|
|
66
|
+
* new loader's first tick;
|
|
67
|
+
* - `frame` wins on a clash, because it is spread last — which is how the
|
|
68
|
+
* verify gate shows its deterministic-stage label until the child has a
|
|
69
|
+
* line of its own;
|
|
70
|
+
* - `frame: null` raises NO loader at all (the caller already has one
|
|
71
|
+
* reading this status) but still resets;
|
|
72
|
+
* - a child that THROWS still stops the loader, so a failure never leaves
|
|
73
|
+
* the widget up.
|
|
68
74
|
*/
|
|
69
75
|
async track(ctx, frame, run) {
|
|
70
76
|
this.reset();
|
|
@@ -99,7 +105,8 @@ export async function runPlanningChild(opts) {
|
|
|
99
105
|
}
|
|
100
106
|
/**
|
|
101
107
|
* Wire a `ChildStatus` as a phase child's stream callbacks — plus the window the
|
|
102
|
-
* child must be TOLD, since pi's
|
|
108
|
+
* child must be TOLD, since pi's `--mode json` stream reports token counts but no
|
|
109
|
+
* context window.
|
|
103
110
|
*/
|
|
104
111
|
export function statusCallbacks(status) {
|
|
105
112
|
return {
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* clamp-output — the ONE trail-side ceiling for captured tool output.
|
|
3
3
|
*
|
|
4
|
-
* `appendGateRecord`
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* `appendGateRecord` already collapses every run of whitespace-around-newline
|
|
5
|
+
* into a single space, so each trail entry is one line. What it does NOT do is
|
|
6
|
+
* bound the LENGTH, which is this. A wedged tool has no upper limit on what it
|
|
7
|
+
* prints, and the trail is a task file a human reads.
|
|
8
|
+
*
|
|
9
|
+
* Both probes that carry tool output into a failure detail — the render check and
|
|
10
|
+
* the gate's own command records — call THIS function, so the two trails cannot
|
|
11
|
+
* start disagreeing about what was captured. A second clamp with a second ceiling
|
|
12
|
+
* is exactly how that happens.
|
|
13
|
+
*
|
|
14
|
+
* At the boundary: 1200 characters pass through untouched, 1201 or more come back
|
|
15
|
+
* clamped to 1200 plus a single ellipsis.
|
|
9
16
|
*/
|
|
10
17
|
const TRAIL_OUTPUT_MAX_CHARS = 1200;
|
|
11
18
|
export function clampOutput(output) {
|