@mjasnikovs/pi-task 0.38.29 → 0.38.31
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/index.js +2 -0
- 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 +85 -16
- package/dist/shared/command-watchdog.js +115 -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 +192 -165
- 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 +124 -55
- package/dist/task/child-runner.js +298 -90
- package/dist/task/child-status.d.ts +23 -16
- package/dist/task/child-status.js +23 -16
- package/dist/task/clamp-output.js +12 -5
- package/dist/task/command-run.d.ts +31 -28
- package/dist/task/command-run.js +44 -35
- package/dist/task/command-shrink.d.ts +25 -18
- package/dist/task/command-shrink.js +37 -31
- package/dist/task/command-watchdog.d.ts +9 -6
- package/dist/task/command-watchdog.js +21 -15
- package/dist/task/context-attribution.d.ts +34 -26
- package/dist/task/context-attribution.js +34 -26
- package/dist/task/context-silence.d.ts +39 -29
- package/dist/task/context-silence.js +35 -25
- package/dist/task/context-usage.d.ts +16 -9
- package/dist/task/context-usage.js +16 -9
- package/dist/task/contracts.d.ts +8 -4
- package/dist/task/contracts.js +25 -17
- package/dist/task/coverage-loop.d.ts +22 -18
- package/dist/task/coverage-loop.js +35 -30
- package/dist/task/critique-probes.d.ts +13 -14
- package/dist/task/critique-probes.js +50 -39
- package/dist/task/debug-log.d.ts +13 -5
- package/dist/task/debug-log.js +32 -20
- package/dist/task/decompose-fidelity.d.ts +11 -9
- package/dist/task/decompose-fidelity.js +38 -33
- package/dist/task/decompose-granularity.d.ts +41 -38
- package/dist/task/decompose-granularity.js +41 -38
- package/dist/task/deep-render-check.d.ts +22 -14
- package/dist/task/deep-render-check.js +40 -31
- package/dist/task/dropped-input.d.ts +12 -7
- package/dist/task/dropped-input.js +5 -2
- package/dist/task/enforce-attribution.d.ts +38 -47
- package/dist/task/enforce-attribution.js +46 -52
- package/dist/task/enforce-guidelines.d.ts +31 -20
- package/dist/task/enforce-guidelines.js +32 -21
- package/dist/task/enrichment.d.ts +7 -2
- package/dist/task/enrichment.js +26 -14
- package/dist/task/env-notes.d.ts +16 -7
- package/dist/task/env-notes.js +48 -31
- package/dist/task/env-template-closure.d.ts +4 -4
- package/dist/task/env-template-closure.js +42 -34
- package/dist/task/external-context.d.ts +28 -21
- package/dist/task/external-context.js +17 -12
- package/dist/task/failure-classifier.d.ts +4 -5
- package/dist/task/failure-classifier.js +30 -8
- package/dist/task/file-inventory.d.ts +15 -11
- package/dist/task/file-inventory.js +25 -22
- package/dist/task/final-gate-fix.d.ts +74 -86
- package/dist/task/final-gate-fix.js +97 -116
- package/dist/task/final-gate-progress.d.ts +29 -46
- package/dist/task/final-gate-progress.js +40 -51
- package/dist/task/final-gate.d.ts +64 -97
- package/dist/task/final-gate.js +192 -199
- package/dist/task/fix-child.d.ts +21 -27
- package/dist/task/fix-child.js +21 -27
- package/dist/task/foreign-path.d.ts +6 -5
- package/dist/task/foreign-path.js +0 -0
- package/dist/task/frozen-conflict.d.ts +9 -10
- package/dist/task/frozen-conflict.js +61 -64
- package/dist/task/frozen-path-guard.d.ts +35 -14
- package/dist/task/frozen-path-guard.js +56 -39
- package/dist/task/gate-child.d.ts +27 -28
- package/dist/task/gate-child.js +36 -35
- package/dist/task/gate-deps.d.ts +34 -27
- package/dist/task/gate-deps.js +169 -159
- package/dist/task/gate-tally.d.ts +77 -80
- package/dist/task/gate-tally.js +65 -68
- package/dist/task/git-state-guard.d.ts +15 -11
- package/dist/task/git-state-guard.js +76 -66
- package/dist/task/impl-widget.d.ts +25 -16
- package/dist/task/impl-widget.js +27 -17
- package/dist/task/implementation-guards.d.ts +26 -0
- package/dist/task/implementation-guards.js +177 -0
- package/dist/task/implementation-thinking.d.ts +33 -31
- package/dist/task/implementation-thinking.js +5 -6
- package/dist/task/implementation-turn.d.ts +39 -31
- package/dist/task/implementation-turn.js +41 -28
- 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 +27 -8
- package/dist/task/loop-detector.js +38 -14
- 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 +89 -66
- 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 +196 -252
- package/dist/task/plan-io.d.ts +6 -7
- package/dist/task/plan-io.js +6 -7
- package/dist/task/plan-orchestrator.d.ts +10 -8
- package/dist/task/plan-orchestrator.js +14 -10
- package/dist/task/plan-prompts.d.ts +6 -5
- package/dist/task/plan-prompts.js +6 -5
- package/dist/task/plan-readonly.d.ts +4 -5
- package/dist/task/plan-readonly.js +4 -5
- package/dist/task/plan-rounds.d.ts +17 -29
- package/dist/task/plan-rounds.js +21 -34
- package/dist/task/plan-session.d.ts +58 -72
- package/dist/task/plan-session.js +61 -83
- package/dist/task/probe-gaming.d.ts +28 -27
- package/dist/task/probe-gaming.js +0 -0
- package/dist/task/prohibition-probe.d.ts +14 -16
- package/dist/task/prompts.d.ts +3 -4
- package/dist/task/prompts.js +17 -26
- package/dist/task/qa-transcript.d.ts +15 -22
- package/dist/task/qa-transcript.js +15 -21
- package/dist/task/question-box.d.ts +17 -13
- package/dist/task/question-box.js +19 -15
- package/dist/task/question-dedup.d.ts +6 -7
- package/dist/task/question-dedup.js +13 -14
- package/dist/task/question-dialog.d.ts +22 -32
- package/dist/task/question-dialog.js +22 -32
- package/dist/task/question-source.d.ts +18 -44
- package/dist/task/question-source.js +22 -51
- package/dist/task/refuted-constraint.d.ts +11 -31
- package/dist/task/refuted-constraint.js +27 -51
- package/dist/task/regenerable-artifacts.d.ts +12 -31
- package/dist/task/regenerable-artifacts.js +12 -31
- package/dist/task/render-check.d.ts +11 -22
- package/dist/task/render-check.js +33 -46
- package/dist/task/repo-health-check.d.ts +10 -14
- package/dist/task/repo-health-check.js +17 -23
- package/dist/task/requirements.d.ts +38 -71
- package/dist/task/requirements.js +78 -126
- package/dist/task/research-fanout-budget.d.ts +51 -88
- package/dist/task/research-fanout-budget.js +51 -88
- package/dist/task/research-worker.d.ts +29 -39
- package/dist/task/research-worker.js +37 -61
- package/dist/task/resume-gap.d.ts +14 -15
- package/dist/task/root-cause-repair.d.ts +9 -9
- package/dist/task/root-cause-repair.js +28 -40
- package/dist/task/run-bracket.d.ts +10 -13
- package/dist/task/run-end.d.ts +12 -22
- package/dist/task/run-end.js +8 -16
- package/dist/task/run-final-gate.d.ts +19 -21
- package/dist/task/run-final-gate.js +62 -80
- package/dist/task/runner-globs.d.ts +12 -13
- package/dist/task/runner-globs.js +12 -13
- package/dist/task/runner-resolve.d.ts +9 -9
- package/dist/task/runner-resolve.js +22 -23
- package/dist/task/script-escape.d.ts +10 -12
- package/dist/task/script-escape.js +13 -14
- package/dist/task/serve-entry.d.ts +1 -1
- package/dist/task/serve-entry.js +22 -25
- package/dist/task/service-blocks.js +4 -2
- package/dist/task/shipped-source.d.ts +11 -29
- package/dist/task/shipped-source.js +11 -29
- package/dist/task/skip-escape.js +10 -14
- package/dist/task/spec-urls.d.ts +26 -65
- package/dist/task/spec-urls.js +26 -65
- package/dist/task/spec-validation.d.ts +17 -20
- package/dist/task/spec-validation.js +17 -20
- package/dist/task/stall-detector.d.ts +23 -30
- package/dist/task/stall-detector.js +23 -30
- package/dist/task/stream-watchdog.d.ts +14 -12
- package/dist/task/stream-watchdog.js +14 -12
- package/dist/task/substitution-probe.d.ts +17 -20
- package/dist/task/substitution-probe.js +17 -20
- package/dist/task/task-gates.d.ts +36 -41
- package/dist/task/task-gates.js +95 -106
- package/dist/task/task-io.d.ts +4 -4
- package/dist/task/task-io.js +4 -4
- package/dist/task/task-parsers.js +4 -3
- package/dist/task/task-provenance.d.ts +2 -2
- package/dist/task/task-provenance.js +11 -13
- package/dist/task/task-types.d.ts +4 -3
- package/dist/task/terminal-outcome.d.ts +14 -16
- package/dist/task/terminal-outcome.js +12 -14
- package/dist/task/test-assembly.d.ts +13 -20
- package/dist/task/test-assembly.js +13 -20
- package/dist/task/timings.d.ts +5 -3
- package/dist/task/timings.js +5 -3
- package/dist/task/title-label.d.ts +9 -4
- package/dist/task/title-label.js +9 -4
- package/dist/task/type-only-answer.d.ts +44 -52
- package/dist/task/type-only-answer.js +44 -52
- package/dist/task/unfailable-command.d.ts +18 -24
- package/dist/task/unfailable-command.js +21 -27
- package/dist/task/unknown-routing.d.ts +10 -4
- package/dist/task/unknown-routing.js +10 -4
- package/dist/task/user-directives.d.ts +5 -8
- package/dist/task/user-directives.js +5 -8
- package/dist/task/verify-quality.d.ts +18 -22
- package/dist/task/verify-quality.js +45 -46
- package/dist/task/verify-reconcile.d.ts +15 -10
- package/dist/task/verify-reconcile.js +45 -43
- package/dist/task/verify-resolution.d.ts +24 -20
- package/dist/task/verify-resolution.js +51 -50
- package/dist/task/verify-work.d.ts +59 -66
- package/dist/task/verify-work.js +101 -138
- package/dist/task/widget.d.ts +15 -14
- package/dist/task/widget.js +22 -17
- package/dist/task/wiring-claims.d.ts +25 -32
- package/dist/task/wiring-claims.js +30 -35
- package/dist/task/write-guard.d.ts +39 -39
- package/dist/task/write-guard.js +48 -51
- package/dist/task/yolo.d.ts +34 -30
- package/dist/task/yolo.js +42 -37
- package/dist/workers/abstention.d.ts +21 -41
- package/dist/workers/abstention.js +27 -48
- package/dist/workers/brave-search.d.ts +4 -3
- package/dist/workers/brave-search.js +5 -2
- package/dist/workers/brave-warning.d.ts +7 -4
- package/dist/workers/brave-warning.js +19 -7
- package/dist/workers/ddg-search.d.ts +6 -6
- package/dist/workers/ddg-search.js +18 -12
- package/dist/workers/docs-cache.js +5 -2
- package/dist/workers/docs-chunk.d.ts +30 -37
- package/dist/workers/docs-chunk.js +37 -41
- package/dist/workers/docs-core.d.ts +28 -44
- package/dist/workers/docs-core.js +25 -44
- package/dist/workers/docs-index.js +4 -3
- package/dist/workers/docs-lookup.d.ts +15 -22
- package/dist/workers/docs-lookup.js +12 -21
- package/dist/workers/docs-project.d.ts +15 -9
- package/dist/workers/docs-project.js +17 -10
- package/dist/workers/docs-resolve.d.ts +19 -20
- package/dist/workers/docs-resolve.js +35 -32
- package/dist/workers/docs-retrieve.d.ts +5 -6
- package/dist/workers/docs-retrieve.js +18 -15
- package/dist/workers/exa-search.d.ts +9 -6
- package/dist/workers/exa-search.js +23 -12
- package/dist/workers/fetch-core.d.ts +13 -16
- package/dist/workers/fetch-core.js +23 -23
- package/dist/workers/focused-extractor.d.ts +13 -12
- package/dist/workers/focused-extractor.js +27 -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 +65 -96
- package/dist/workers/pi-worker-core.js +93 -181
- package/dist/workers/pi-worker-docs.d.ts +24 -19
- package/dist/workers/pi-worker-docs.js +67 -76
- package/dist/workers/pi-worker-fetch.d.ts +7 -3
- package/dist/workers/pi-worker-fetch.js +27 -19
- package/dist/workers/pi-worker-search.js +12 -8
- package/dist/workers/pi-worker.d.ts +9 -4
- package/dist/workers/pi-worker.js +21 -14
- package/dist/workers/reasoning-warning.d.ts +18 -17
- package/dist/workers/reasoning-warning.js +22 -20
- package/dist/workers/research-cache.js +50 -78
- package/dist/workers/search-core.js +7 -5
- package/dist/workers/search-types.d.ts +10 -9
- package/dist/workers/search-types.js +9 -8
- package/dist/workers/session-hint.d.ts +13 -14
- package/dist/workers/session-hint.js +8 -9
- package/dist/workers/shared.d.ts +21 -25
- package/dist/workers/shared.js +0 -0
- package/dist/workers/single-read-extension.d.ts +14 -7
- package/dist/workers/single-read-extension.js +14 -7
- package/dist/workers/single-read-guard.d.ts +27 -30
- package/dist/workers/single-read-guard.js +36 -36
- 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 +54 -56
- package/dist/workers/worker-profiles.js +63 -39
- package/package.json +10 -8
|
@@ -2,41 +2,43 @@
|
|
|
2
2
|
* Hold the host session at the `implementation` group's thinking level for the
|
|
3
3
|
* duration of one implementation turn, then put it back.
|
|
4
4
|
*
|
|
5
|
-
* WHY THIS IS NOT LIKE THE
|
|
6
|
-
*
|
|
7
|
-
* Every other group
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* WHY THIS GROUP IS NOT LIKE THE OTHERS
|
|
6
|
+
* -------------------------------------
|
|
7
|
+
* Every other reasoning group runs in a child process, so its level is one argv
|
|
8
|
+
* flag (`--thinking <level>`, built in reasoning-args.ts) and it dies with the
|
|
9
|
+
* child. The implementation turn runs in the USER'S OWN session
|
|
10
|
+
* (orchestrator.ts `sendSpec` -> `sendUserMessage` -> `superviseImplementation`),
|
|
11
|
+
* so the only lever is `pi.setThinkingLevel`, which is session-global.
|
|
11
12
|
*
|
|
12
|
-
* THREE THINGS pi DOES that this has to survive
|
|
13
|
-
* pi-coding-agent's agent-session `setThinkingLevel`:
|
|
13
|
+
* THREE THINGS pi DOES that this has to survive:
|
|
14
14
|
*
|
|
15
|
-
* 1. IT PERSISTS.
|
|
16
|
-
* `settingsManager.setDefaultThinkingLevel(...)
|
|
17
|
-
*
|
|
18
|
-
* the restore, running one task would
|
|
19
|
-
* default. That makes `release()`
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
15
|
+
* 1. IT PERSISTS. pi-coding-agent's agent-session `setThinkingLevel` calls
|
|
16
|
+
* `settingsManager.setDefaultThinkingLevel(...)` whenever the effective
|
|
17
|
+
* level actually changes, and that writes pi's global settings file
|
|
18
|
+
* (`~/.pi/agent/settings.json`). Without the restore, running one task would
|
|
19
|
+
* silently rewrite the user's global default. That makes `release()`
|
|
20
|
+
* load-bearing, not tidy-up.
|
|
21
|
+
* 2. IT CLAMPS, to the levels the model declares. A model with no reasoning
|
|
22
|
+
* support offers only `off`, so asking for `medium` yields `off`. The
|
|
23
|
+
* restore therefore writes back what was READ after setting, never what was
|
|
24
|
+
* asked for — otherwise a clamp would ratchet the stored default a little
|
|
25
|
+
* further every run.
|
|
26
|
+
* 3. IT IS OBSERVABLE, and the user can change it mid-turn: `shift+tab` is the
|
|
27
|
+
* default binding for `app.thinking.cycle`, and a change invalidates the
|
|
28
|
+
* footer. Restoring blindly would clobber a choice they just made. We detect
|
|
29
|
+
* it by comparing the live level at release against what we applied: if it
|
|
30
|
+
* has moved, somebody else moved it, and we leave it alone.
|
|
28
31
|
*
|
|
29
|
-
* We compare rather than subscribe because `
|
|
30
|
-
* handle
|
|
31
|
-
* comparison answers the same question with no
|
|
32
|
+
* We compare rather than subscribe because the extension API's `on(...)` returns
|
|
33
|
+
* `void` — there is no unsubscribe handle — so a per-turn listener could only
|
|
34
|
+
* ever be added, never removed. The comparison answers the same question with no
|
|
35
|
+
* accumulating state.
|
|
32
36
|
*/
|
|
33
37
|
import type { ThinkingLevel } from '@earendil-works/pi-agent-core';
|
|
34
38
|
import { type GroupSetting } from '../config/reasoning.js';
|
|
35
39
|
/**
|
|
36
|
-
* The slice of the extension API this needs, named so tests can drive
|
|
37
|
-
* a
|
|
38
|
-
* injectable; this one has to be too, or the restore logic is only exercisable
|
|
39
|
-
* by running a real task.
|
|
40
|
+
* The slice of the extension API this needs, named so tests can drive the
|
|
41
|
+
* hold-and-restore with a fake object instead of a live pi session.
|
|
40
42
|
*/
|
|
41
43
|
export interface ThinkingControl {
|
|
42
44
|
get(): ThinkingLevel;
|
|
@@ -47,8 +49,8 @@ export interface ThinkingControl {
|
|
|
47
49
|
* that puts it back. Always call the returned function — `finally`, not the
|
|
48
50
|
* happy path.
|
|
49
51
|
*
|
|
50
|
-
* `inherit` makes NO call at all, not even a redundant set-to-current
|
|
51
|
-
*
|
|
52
|
-
*
|
|
52
|
+
* `inherit` makes NO call at all, not even a redundant set-to-current. It means
|
|
53
|
+
* the same thing here as in `thinkingArgs`, which emits no `--thinking` flag for
|
|
54
|
+
* it: leave the level wherever it already is.
|
|
53
55
|
*/
|
|
54
56
|
export declare function holdImplementationThinking(control: ThinkingControl, setting?: GroupSetting): () => void;
|
|
@@ -5,9 +5,9 @@ import { resolveReasoning } from '../config/reasoning.js';
|
|
|
5
5
|
* that puts it back. Always call the returned function — `finally`, not the
|
|
6
6
|
* happy path.
|
|
7
7
|
*
|
|
8
|
-
* `inherit` makes NO call at all, not even a redundant set-to-current
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* `inherit` makes NO call at all, not even a redundant set-to-current. It means
|
|
9
|
+
* the same thing here as in `thinkingArgs`, which emits no `--thinking` flag for
|
|
10
|
+
* it: leave the level wherever it already is.
|
|
11
11
|
*/
|
|
12
12
|
export function holdImplementationThinking(control, setting = resolveReasoning('implementation', getConfig())) {
|
|
13
13
|
if (setting === 'inherit')
|
|
@@ -21,9 +21,8 @@ export function holdImplementationThinking(control, setting = resolveReasoning('
|
|
|
21
21
|
return () => { };
|
|
22
22
|
let released = false;
|
|
23
23
|
return () => {
|
|
24
|
-
// Idempotent
|
|
25
|
-
//
|
|
26
|
-
// between.
|
|
24
|
+
// Idempotent by contract: only the first call restores. A later call
|
|
25
|
+
// would write `before` on top of whatever the level is by then.
|
|
27
26
|
if (released)
|
|
28
27
|
return;
|
|
29
28
|
released = true;
|
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
* • `aborted` — a user ESC (or the command watchdog) cut the turn short;
|
|
8
8
|
* • `compaction` — a threshold auto-compaction parked the turn at idle without
|
|
9
9
|
* auto-continuing (the runtime expects a manual continue);
|
|
10
|
-
* • `error` — the model
|
|
10
|
+
* • `error` — the model or provider failed after pi exhausted the retries
|
|
11
|
+
* in its own retry settings;
|
|
11
12
|
* • `stop` — genuine completion.
|
|
12
|
-
* `classifyTurnEnd` reads the session entries and names ONE of those
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* `classifyTurnEnd` reads the session entries and names ONE of those;
|
|
14
|
+
* `superviseImplementation` then resumes across compactions, lets the user steer
|
|
15
|
+
* after an interrupt, and reports the terminal outcome. The orchestrator calls it
|
|
16
|
+
* from one place, inside the `sendSpec` closure.
|
|
16
17
|
*/
|
|
17
18
|
import type { ExtensionCommandContext } from '@earendil-works/pi-coding-agent';
|
|
18
19
|
/** How the most recent implementation turn ended. See {@link classifyTurnEnd}. */
|
|
@@ -34,21 +35,20 @@ export type SessionEntryLike = {
|
|
|
34
35
|
/**
|
|
35
36
|
* Classify how the most recent turn ended, from the session entries alone.
|
|
36
37
|
*
|
|
37
|
-
* Precedence, when several signals are present at once
|
|
38
|
-
* supervision sequence has always applied, now stated in one place):
|
|
38
|
+
* Precedence, when several signals are present at once:
|
|
39
39
|
* 1. `aborted` — the last assistant message has stopReason "aborted". A user
|
|
40
40
|
* ESC (or watchdog abort) wins over everything: it is not a
|
|
41
41
|
* compaction pause, and the steer loop owns it.
|
|
42
42
|
* 2. `compaction` — a `compaction` entry sits AFTER the last assistant message.
|
|
43
|
-
* Position-based, not timestamp-based:
|
|
44
|
-
* boundary
|
|
45
|
-
*
|
|
43
|
+
* Position-based, not timestamp-based: `appendCompaction`
|
|
44
|
+
* pushes the boundary onto the tail of the entry list, and
|
|
45
|
+
* `getEntries()` returns that list in append order, so a
|
|
46
46
|
* trailing compaction means we are parked with no continuation.
|
|
47
|
-
* A finished turn ends on an assistant message
|
|
48
|
-
* compaction
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* after pi exhausted its own retries.
|
|
47
|
+
* A finished turn ends on an assistant message. An overflow
|
|
48
|
+
* compaction that is going to retry continues the turn itself
|
|
49
|
+
* and never reaches us idle.
|
|
50
|
+
* 3. `error` — the last assistant message has stopReason "error": the model
|
|
51
|
+
* or provider failed after pi exhausted its own retries.
|
|
52
52
|
* 4. `stop` — anything else, including a session with no assistant turn.
|
|
53
53
|
*/
|
|
54
54
|
export declare function classifyTurnEnd(entries: ReadonlyArray<SessionEntryLike>): TurnEnd;
|
|
@@ -78,10 +78,11 @@ export type SteerCtx = ExtensionCommandContext & {
|
|
|
78
78
|
};
|
|
79
79
|
/**
|
|
80
80
|
* Timing knobs for the watchdog-abort guard in {@link steerUntilDone}, injectable
|
|
81
|
-
* so
|
|
82
|
-
* how long the loop waits for the watchdog's follow-up to be DELIVERED
|
|
83
|
-
* finish
|
|
84
|
-
*
|
|
81
|
+
* so a test can exercise the grace expiry without waiting it out. `graceMs`
|
|
82
|
+
* bounds how long the loop waits for the watchdog's follow-up to be DELIVERED,
|
|
83
|
+
* not to finish: once it lands, the wait for its turn is unbounded. `onFire`
|
|
84
|
+
* sends the follow-up in the same block that raised the flag, so the grace
|
|
85
|
+
* expires only when the flag was already stale.
|
|
85
86
|
*/
|
|
86
87
|
export interface SteerWatchdogDeps {
|
|
87
88
|
consume: () => boolean;
|
|
@@ -95,6 +96,8 @@ export interface SteerWatchdogDeps {
|
|
|
95
96
|
export interface ImplementationTurnDeps {
|
|
96
97
|
/** The live session entries — the only thing the classifier reads. */
|
|
97
98
|
entries: () => ReadonlyArray<SessionEntryLike>;
|
|
99
|
+
/** Test seam over the module-level one-shot; the real reader is the default. */
|
|
100
|
+
consumeGuardTermination?: () => boolean;
|
|
98
101
|
/** Queue a follow-up user turn on the (idle) session. */
|
|
99
102
|
send: (text: string) => Promise<void>;
|
|
100
103
|
/** Wait for the session to go idle again. */
|
|
@@ -124,20 +127,23 @@ export declare function turnDepsFor(ctx: SteerCtx, opts?: SuperviseOptions): Imp
|
|
|
124
127
|
/**
|
|
125
128
|
* Nudge that resumes an implementation turn the runtime parked at a compaction
|
|
126
129
|
* boundary. It must let a turn that was genuinely finished (then tipped over the
|
|
127
|
-
* threshold by its own final message) confirm completion without inventing busywork
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
+
* threshold by its own final message) confirm completion without inventing busywork.
|
|
131
|
+
* The classifier sees only the boundary's POSITION, so it cannot tell "paused
|
|
132
|
+
* mid-task by compaction" from "finished, then compacted"; the wording lets a done
|
|
133
|
+
* turn end in one line.
|
|
130
134
|
*/
|
|
131
135
|
export declare const CONTINUE_AFTER_COMPACTION: string;
|
|
132
136
|
/**
|
|
133
137
|
* Safety cap on compaction-driven resumes for a single implementation turn. Each
|
|
134
|
-
* resume follows a real compaction
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* the verify gate / `/task-auto-resume` catch any leftover incompleteness.
|
|
138
|
+
* resume follows a real compaction, which pi only runs once `shouldCompact` says
|
|
139
|
+
* the context crossed its threshold. The cap exists to stop a pathological loop
|
|
140
|
+
* from auto-sending forever with no user watching. Hitting it stops resuming and
|
|
141
|
+
* lets the verify gate and `/task-auto-resume` catch any leftover incompleteness.
|
|
139
142
|
*/
|
|
140
143
|
export declare const MAX_COMPACTION_RESUMES = 20;
|
|
144
|
+
/** How a guard-stopped turn is reported. Named so a caller can tell it from a
|
|
145
|
+
* provider error: the fix is a different task, not a retry of this one. */
|
|
146
|
+
export declare const GUARD_TERMINATED = "the runaway guard stopped this turn: one tool call was repeated past every warning";
|
|
141
147
|
/**
|
|
142
148
|
* Resume an implementation turn that went idle at a threshold-compaction boundary.
|
|
143
149
|
* The runtime compacts and parks at idle without auto-continuing; we send a
|
|
@@ -154,10 +160,12 @@ export declare function resumeAcrossCompactions(deps: ImplementationTurnDeps): P
|
|
|
154
160
|
* `waitForIdle` resolves both on natural completion AND on an ESC (which aborts
|
|
155
161
|
* the turn → idle). When the last turn was aborted, the host's main input loop is
|
|
156
162
|
* blocked inside our command handler, so a message typed in the editor would only
|
|
157
|
-
* queue, never run
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
163
|
+
* queue, never run: interactive-mode's submit handler calls `onInputCallback` when
|
|
164
|
+
* the session is idle, and that callback is set only inside `getUserInput()` — the
|
|
165
|
+
* REPL loop we are holding — so the text lands in `pendingUserInputs` instead. We
|
|
166
|
+
* therefore solicit the steering text ourselves and feed it back as another turn
|
|
167
|
+
* via `sendUserMessage`, which forwards to `prompt()` and, on an idle session, runs
|
|
168
|
+
* the turn rather than queueing it. Repeat until a turn finishes uninterrupted.
|
|
161
169
|
*
|
|
162
170
|
* A WATCHDOG abort also ends the turn with stopReason 'aborted' — indistinguishable
|
|
163
171
|
* from a human ESC by the session entries alone at that instant. The watchdog
|
|
@@ -7,15 +7,17 @@
|
|
|
7
7
|
* • `aborted` — a user ESC (or the command watchdog) cut the turn short;
|
|
8
8
|
* • `compaction` — a threshold auto-compaction parked the turn at idle without
|
|
9
9
|
* auto-continuing (the runtime expects a manual continue);
|
|
10
|
-
* • `error` — the model
|
|
10
|
+
* • `error` — the model or provider failed after pi exhausted the retries
|
|
11
|
+
* in its own retry settings;
|
|
11
12
|
* • `stop` — genuine completion.
|
|
12
|
-
* `classifyTurnEnd` reads the session entries and names ONE of those
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* `classifyTurnEnd` reads the session entries and names ONE of those;
|
|
14
|
+
* `superviseImplementation` then resumes across compactions, lets the user steer
|
|
15
|
+
* after an interrupt, and reports the terminal outcome. The orchestrator calls it
|
|
16
|
+
* from one place, inside the `sendSpec` closure.
|
|
16
17
|
*/
|
|
17
18
|
import { SessionUI } from '../remote/bridge.js';
|
|
18
19
|
import { consumeWatchdogAbort, WATCHDOG_CANCEL_MARKER } from './command-watchdog.js';
|
|
20
|
+
import { consumeGuardTermination } from './implementation-guards.js';
|
|
19
21
|
const isAssistant = (e) => e.message !== undefined && e.message.role === 'assistant';
|
|
20
22
|
/** Index of the last assistant message and of the last compaction boundary. */
|
|
21
23
|
function tailPositions(entries) {
|
|
@@ -33,21 +35,20 @@ function tailPositions(entries) {
|
|
|
33
35
|
/**
|
|
34
36
|
* Classify how the most recent turn ended, from the session entries alone.
|
|
35
37
|
*
|
|
36
|
-
* Precedence, when several signals are present at once
|
|
37
|
-
* supervision sequence has always applied, now stated in one place):
|
|
38
|
+
* Precedence, when several signals are present at once:
|
|
38
39
|
* 1. `aborted` — the last assistant message has stopReason "aborted". A user
|
|
39
40
|
* ESC (or watchdog abort) wins over everything: it is not a
|
|
40
41
|
* compaction pause, and the steer loop owns it.
|
|
41
42
|
* 2. `compaction` — a `compaction` entry sits AFTER the last assistant message.
|
|
42
|
-
* Position-based, not timestamp-based:
|
|
43
|
-
* boundary
|
|
44
|
-
*
|
|
43
|
+
* Position-based, not timestamp-based: `appendCompaction`
|
|
44
|
+
* pushes the boundary onto the tail of the entry list, and
|
|
45
|
+
* `getEntries()` returns that list in append order, so a
|
|
45
46
|
* trailing compaction means we are parked with no continuation.
|
|
46
|
-
* A finished turn ends on an assistant message
|
|
47
|
-
* compaction
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* after pi exhausted its own retries.
|
|
47
|
+
* A finished turn ends on an assistant message. An overflow
|
|
48
|
+
* compaction that is going to retry continues the turn itself
|
|
49
|
+
* and never reaches us idle.
|
|
50
|
+
* 3. `error` — the last assistant message has stopReason "error": the model
|
|
51
|
+
* or provider failed after pi exhausted its own retries.
|
|
51
52
|
* 4. `stop` — anything else, including a session with no assistant turn.
|
|
52
53
|
*/
|
|
53
54
|
export function classifyTurnEnd(entries) {
|
|
@@ -143,9 +144,10 @@ export function turnDepsFor(ctx, opts = {}) {
|
|
|
143
144
|
/**
|
|
144
145
|
* Nudge that resumes an implementation turn the runtime parked at a compaction
|
|
145
146
|
* boundary. It must let a turn that was genuinely finished (then tipped over the
|
|
146
|
-
* threshold by its own final message) confirm completion without inventing busywork
|
|
147
|
-
*
|
|
148
|
-
*
|
|
147
|
+
* threshold by its own final message) confirm completion without inventing busywork.
|
|
148
|
+
* The classifier sees only the boundary's POSITION, so it cannot tell "paused
|
|
149
|
+
* mid-task by compaction" from "finished, then compacted"; the wording lets a done
|
|
150
|
+
* turn end in one line.
|
|
149
151
|
*/
|
|
150
152
|
export const CONTINUE_AFTER_COMPACTION = 'Your context was automatically compacted. Continue implementing this task from '
|
|
151
153
|
+ 'exactly where you left off, and keep going until it is fully done. If the '
|
|
@@ -153,13 +155,15 @@ export const CONTINUE_AFTER_COMPACTION = 'Your context was automatically compact
|
|
|
153
155
|
+ 'extra work or restart the task.';
|
|
154
156
|
/**
|
|
155
157
|
* Safety cap on compaction-driven resumes for a single implementation turn. Each
|
|
156
|
-
* resume follows a real compaction
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* the verify gate / `/task-auto-resume` catch any leftover incompleteness.
|
|
158
|
+
* resume follows a real compaction, which pi only runs once `shouldCompact` says
|
|
159
|
+
* the context crossed its threshold. The cap exists to stop a pathological loop
|
|
160
|
+
* from auto-sending forever with no user watching. Hitting it stops resuming and
|
|
161
|
+
* lets the verify gate and `/task-auto-resume` catch any leftover incompleteness.
|
|
161
162
|
*/
|
|
162
163
|
export const MAX_COMPACTION_RESUMES = 20;
|
|
164
|
+
/** How a guard-stopped turn is reported. Named so a caller can tell it from a
|
|
165
|
+
* provider error: the fix is a different task, not a retry of this one. */
|
|
166
|
+
export const GUARD_TERMINATED = 'the runaway guard stopped this turn: one tool call was repeated past every warning';
|
|
163
167
|
/**
|
|
164
168
|
* Resume an implementation turn that went idle at a threshold-compaction boundary.
|
|
165
169
|
* The runtime compacts and parks at idle without auto-continuing; we send a
|
|
@@ -209,10 +213,12 @@ async function awaitWatchdogFollowUp(deps) {
|
|
|
209
213
|
* `waitForIdle` resolves both on natural completion AND on an ESC (which aborts
|
|
210
214
|
* the turn → idle). When the last turn was aborted, the host's main input loop is
|
|
211
215
|
* blocked inside our command handler, so a message typed in the editor would only
|
|
212
|
-
* queue, never run
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
+
* queue, never run: interactive-mode's submit handler calls `onInputCallback` when
|
|
217
|
+
* the session is idle, and that callback is set only inside `getUserInput()` — the
|
|
218
|
+
* REPL loop we are holding — so the text lands in `pendingUserInputs` instead. We
|
|
219
|
+
* therefore solicit the steering text ourselves and feed it back as another turn
|
|
220
|
+
* via `sendUserMessage`, which forwards to `prompt()` and, on an idle session, runs
|
|
221
|
+
* the turn rather than queueing it. Repeat until a turn finishes uninterrupted.
|
|
216
222
|
*
|
|
217
223
|
* A WATCHDOG abort also ends the turn with stopReason 'aborted' — indistinguishable
|
|
218
224
|
* from a human ESC by the session entries alone at that instant. The watchdog
|
|
@@ -258,6 +264,13 @@ export async function superviseWith(deps) {
|
|
|
258
264
|
const interrupted = await steerUntilDone(deps);
|
|
259
265
|
// A user-declined steer (interrupted) is its own paused path; otherwise
|
|
260
266
|
// inspect how the turn actually ended.
|
|
261
|
-
|
|
267
|
+
// The runaway guard ends a turn WITHOUT an error stopReason, so classifyTurnEnd
|
|
268
|
+
// reads `'stop'` and the caller would verify a half-done implementation and
|
|
269
|
+
// re-deliver to a model that deterministically re-thrashes. Consumed here
|
|
270
|
+
// because this is the one place that reports how the turn really ended.
|
|
271
|
+
const guardEnded = deps.consumeGuardTermination?.() ?? consumeGuardTermination();
|
|
272
|
+
const error = interrupted ? undefined
|
|
273
|
+
: guardEnded ? GUARD_TERMINATED
|
|
274
|
+
: turnErrorMessage(deps.entries());
|
|
262
275
|
return { interrupted, error, resumes };
|
|
263
276
|
}
|
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Inline-markdown helpers for the
|
|
2
|
+
* Inline-markdown helpers for the question dialogs (grill, clarify, /task-plan).
|
|
3
3
|
*
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* The question arrives carrying markdown because our own prompts ask for it:
|
|
5
|
+
* auto-prompts.ts and plan-prompts.ts both say "Put the core question in
|
|
6
|
+
* **bold** ... Backticks around code/identifiers are fine."
|
|
7
|
+
*
|
|
8
|
+
* One question then needs two forms, and question-dialog.ts `settleQuestion`
|
|
9
|
+
* builds both:
|
|
10
|
+
* • RENDERED — passed as `localTitle`, which reaches `ctx.ui.input`. pi wraps
|
|
11
|
+
* that title in `theme.fg("accent", ...)` and hands it to a pi-tui `Text`,
|
|
12
|
+
* which passes embedded escape sequences straight through, so the bold and
|
|
13
|
+
* code spans survive to the terminal.
|
|
14
|
+
* • STRIPPED — passed as the browser card's `question`, as the editable
|
|
15
|
+
* `recommended` default, and as the text recorded in QaTranscript, whose
|
|
16
|
+
* `forRecord()` is written into the task file's `grill Q&A` section. All
|
|
17
|
+
* three are plain text, never ANSI.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Minimal theme surface we need. pi's `Theme` satisfies it: it declares
|
|
21
|
+
* `bold(text)` and `fg(color, text)`, and `mdCode` is one of its `ThemeColor`
|
|
22
|
+
* values, so `ctx.ui.theme` is passed in directly.
|
|
9
23
|
*/
|
|
10
|
-
/** Minimal theme surface we need; ExtensionCommandContext['ui'].theme satisfies it. */
|
|
11
24
|
export interface InlineMarkdownTheme {
|
|
12
25
|
bold(text: string): string;
|
|
13
26
|
fg(color: 'mdCode', text: string): string;
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Inline-markdown helpers for the
|
|
2
|
+
* Inline-markdown helpers for the question dialogs (grill, clarify, /task-plan).
|
|
3
3
|
*
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* The question arrives carrying markdown because our own prompts ask for it:
|
|
5
|
+
* auto-prompts.ts and plan-prompts.ts both say "Put the core question in
|
|
6
|
+
* **bold** ... Backticks around code/identifiers are fine."
|
|
7
|
+
*
|
|
8
|
+
* One question then needs two forms, and question-dialog.ts `settleQuestion`
|
|
9
|
+
* builds both:
|
|
10
|
+
* • RENDERED — passed as `localTitle`, which reaches `ctx.ui.input`. pi wraps
|
|
11
|
+
* that title in `theme.fg("accent", ...)` and hands it to a pi-tui `Text`,
|
|
12
|
+
* which passes embedded escape sequences straight through, so the bold and
|
|
13
|
+
* code spans survive to the terminal.
|
|
14
|
+
* • STRIPPED — passed as the browser card's `question`, as the editable
|
|
15
|
+
* `recommended` default, and as the text recorded in QaTranscript, whose
|
|
16
|
+
* `forRecord()` is written into the task file's `grill Q&A` section. All
|
|
17
|
+
* three are plain text, never ANSI.
|
|
9
18
|
*/
|
|
10
19
|
const BOLD_SPAN = /\*\*(.+?)\*\*/g;
|
|
11
20
|
const CODE_SPAN = /`([^`]+)`/g;
|
|
@@ -1,65 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* launch-config-gap — a launch script that cannot run because a variable the
|
|
3
3
|
* project's own tracked template DECLARES is absent from this box is an
|
|
4
|
-
* ENVIRONMENT GAP, not a code fault
|
|
4
|
+
* ENVIRONMENT GAP, not a code fault.
|
|
5
5
|
*
|
|
6
|
-
* THE
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* exactly this, and it is self-inflicted at the last moment: pre-gate
|
|
16
|
-
* `package.json` had no `seed` script at all, so `if (!present.has(name)) continue`
|
|
17
|
-
* skipped it. Attempt 3 added the script to clear the launch-contract diff — and
|
|
18
|
-
* thereby armed the check that killed the run.
|
|
19
|
-
*
|
|
20
|
-
* The loop was closed by construction. The gate runs every declared non-boot
|
|
21
|
-
* script with `runnerEnv(runner)` = `process.env` plus a PATH prefix and nothing
|
|
22
|
-
* else; "Missing required environment variable" matches neither ENV_GAP_OUTPUT_RE
|
|
23
|
-
* nor INFRA_GAP_OUTPUT_RE, so it is a hard FAIL; and the only way to supply the
|
|
24
|
-
* value is a gitignored `.env`, whose writes nexttask 4 correctly refuses to
|
|
25
|
-
* credit. The static half of this already shipped and WORKED — `.env.example`
|
|
26
|
-
* declares ADMIN_PHONE/ADMIN_PASSWORD, so `findMissingEnvDeclarations` was
|
|
27
|
-
* correctly silent. This is the execution half.
|
|
6
|
+
* WHY THE GATE CANNOT SETTLE THIS ON ITS OWN. final-gate.ts runs every declared
|
|
7
|
+
* non-boot script (`runnableDeclaredScripts`, which filters on `BOOT_CLASS_RE`)
|
|
8
|
+
* as `bun run <name>`, with `runnerEnv(runner)` — `process.env` plus at most a
|
|
9
|
+
* PATH prefix, and nothing else. A project's own "missing environment variable"
|
|
10
|
+
* message matches neither `ENV_GAP_OUTPUT_RE` nor `INFRA_GAP_OUTPUT_RE`, so it
|
|
11
|
+
* lands as a hard FAIL. The only way to supply the value is a gitignored `.env`,
|
|
12
|
+
* and final-gate-fix.ts downgrades a converged PASS to UNOBSERVED when the gate
|
|
13
|
+
* stops passing with the ignored paths moved aside. Without this check the loop
|
|
14
|
+
* has no exit.
|
|
28
15
|
*
|
|
29
16
|
* FOUR STATIC CONDITIONS, ALL REQUIRED. Deliberately over-constrained: the
|
|
30
17
|
* failure mode of getting this wrong is a gate that excuses real breakage.
|
|
31
18
|
*
|
|
32
|
-
* 1. the script's resolved body names a TRACKED SOURCE FILE
|
|
33
|
-
* (`bun run src/server/seed.ts` → `src/server/seed.ts`);
|
|
19
|
+
* 1. the script's resolved body names a TRACKED SOURCE FILE;
|
|
34
20
|
* 2. that file REQUIRES an env var `X` under `scanSource` — i.e. none of its
|
|
35
|
-
* step-asides (default
|
|
21
|
+
* step-asides (`default`, `compared`, `assigned`, `ambient`,
|
|
22
|
+
* `optional-api`, `probe`) applies;
|
|
36
23
|
* 3. `X` is DECLARED in the tracked template. If it is NOT,
|
|
37
24
|
* `findMissingEnvDeclarations` has already failed the gate statically and
|
|
38
25
|
* this path must not fire — otherwise the two checks would cancel out and a
|
|
39
26
|
* project with no template at all would gain a blanket excuse;
|
|
40
27
|
* 4. `X` is ABSENT from the env the gate spawned the child with.
|
|
41
28
|
*
|
|
42
|
-
* NOTHING IS PARSED FROM THE CHILD'S STDERR.
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* differently or not at all.
|
|
29
|
+
* NOTHING IS PARSED FROM THE CHILD'S STDERR. A "missing variable" message is a
|
|
30
|
+
* string the PROJECT authored; matching on it would be a rule about one project's
|
|
31
|
+
* phrasing, and the next project phrases it differently or not at all.
|
|
46
32
|
*
|
|
47
33
|
* THE FIFTH CONDITION IS DYNAMIC, AND IT IS WHAT MAKES THE RULE HONEST. The four
|
|
48
34
|
* above cannot tell "exited BECAUSE the variable is absent" from "exited for its
|
|
49
35
|
* own reasons, and also happens to read an absent variable". A script that throws
|
|
50
|
-
* a TypeError on line 1 and also reads
|
|
36
|
+
* a TypeError on line 1 and also reads the variable on line 3 satisfies all four.
|
|
51
37
|
* So the script is re-run once with the gap variables supplied as OBVIOUSLY
|
|
52
38
|
* SYNTHETIC placeholders, and the exit code decides:
|
|
53
39
|
*
|
|
54
|
-
* still non-zero
|
|
55
|
-
* now zero
|
|
40
|
+
* still non-zero -> the absence did not cause it -> FAIL, unchanged
|
|
41
|
+
* now zero -> the absence did cause it -> skip + UNOBSERVED + debt
|
|
56
42
|
*
|
|
57
|
-
* The probe run is a DIAGNOSTIC, never an observation.
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* harness-authored string;
|
|
61
|
-
* because
|
|
62
|
-
* them would be a fabricated observation.
|
|
43
|
+
* The probe run is a DIAGNOSTIC, never an observation. On a passing probe
|
|
44
|
+
* final-gate.ts calls `tally.unobserve()` and files the script as skipped, so the
|
|
45
|
+
* verdict is UNOBSERVED with debt and never a PASS. The placeholder is one fixed
|
|
46
|
+
* harness-authored string ({@link CONFIG_GAP_PROBE_VALUE}); the template's own
|
|
47
|
+
* values are never injected, because those are placeholders too and a green run
|
|
48
|
+
* against them would be a fabricated observation.
|
|
63
49
|
*/
|
|
64
50
|
import { readFileSync } from 'node:fs';
|
|
65
51
|
import * as path from 'node:path';
|
|
@@ -12,22 +12,20 @@ export declare function parseScriptLines(text: string): string[];
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function keepGroundedScripts(names: string[], sourceDoc: string): string[];
|
|
14
14
|
/**
|
|
15
|
-
* DETERMINISTIC RECALL
|
|
15
|
+
* DETERMINISTIC RECALL: enumerate every backticked, script-name-shaped
|
|
16
16
|
* token in a paragraph that mentions the word "script", as extraction CANDIDATES.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* enumerates candidates and hands them to the child as an explicit checklist; the
|
|
24
|
-
* model's job flips from recall (weak) to per-candidate classification (strong).
|
|
18
|
+
* Grounding can only DROP a candidate, never add one, so without this the recall of a
|
|
19
|
+
* script declared far from the design's summary list is entirely the model's. This
|
|
20
|
+
* makes recall mechanical: the host enumerates the candidates and hands them to the
|
|
21
|
+
* child as an explicit checklist, so the model's job flips from recall (weak) to
|
|
22
|
+
* per-candidate classification (strong).
|
|
25
23
|
*
|
|
26
24
|
* The paragraph gate (`\bscripts?\b`, word-bounded so "TypeScript"/"JavaScript"
|
|
27
25
|
* don't match) is a grounded-context filter, not a tuned knob: a design declares a
|
|
28
|
-
* script by calling it one. It keeps package-name paragraphs
|
|
29
|
-
*
|
|
30
|
-
*
|
|
26
|
+
* script by calling it one. It keeps package-name paragraphs out of the checklist so
|
|
27
|
+
* a weak model isn't invited to keep junk the grounding guard would then bless —
|
|
28
|
+
* every package name is backticked somewhere. A design with no
|
|
31
29
|
* such paragraph yields no candidates and the prompt is unchanged.
|
|
32
30
|
*/
|
|
33
31
|
export declare function enumerateScriptCandidates(sourceDoc: string): string[];
|
|
@@ -38,13 +36,12 @@ export declare function readDeclaredScripts(cwd: string): Promise<string[]>;
|
|
|
38
36
|
/** Append grounded script names, deduped against what is stored, keeping newest MAX. */
|
|
39
37
|
export declare function appendDeclaredScripts(cwd: string, names: string[]): Promise<void>;
|
|
40
38
|
/**
|
|
41
|
-
* The declared scripts the final gate must EXECUTE as one-shot commands
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* existence is not launchability.
|
|
39
|
+
* The declared scripts the final gate must EXECUTE as one-shot commands: everything
|
|
40
|
+
* the launch contract declares that is neither boot-class (the boot check exercises
|
|
41
|
+
* those) nor already covered by the gate's integration commands (`covered`,
|
|
42
|
+
* case-insensitive — the test/build-shaped scripts that ran). Checking only that a
|
|
43
|
+
* script is DECLARED says nothing about whether running it works; existence is not
|
|
44
|
+
* launchability.
|
|
48
45
|
*/
|
|
49
46
|
export declare function runnableDeclaredScripts(declared: string[], covered: string[]): string[];
|
|
50
47
|
/**
|
|
@@ -59,8 +56,8 @@ export declare function missingDeclaredScripts(declared: string[], manifestScrip
|
|
|
59
56
|
* (keepGroundedScripts), so a hallucinated script cannot reach the diff.
|
|
60
57
|
*
|
|
61
58
|
* `candidates` is enumerateScriptCandidates' mechanical checklist. It exists so the
|
|
62
|
-
* model cannot MISS a declared script buried far from the design's summary list
|
|
63
|
-
*
|
|
64
|
-
*
|
|
59
|
+
* model cannot MISS a declared script buried far from the design's summary list; the
|
|
60
|
+
* model still classifies each candidate against the design, and the host grounding
|
|
61
|
+
* still applies. Empty ⇒ the prompt is unchanged.
|
|
65
62
|
*/
|
|
66
63
|
export declare const LAUNCH_EXTRACT_PROMPT: (feature: string, candidates?: string[]) => string;
|