@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
|
@@ -2,41 +2,43 @@
|
|
|
2
2
|
* git-state-guard — deterministic repo-state snapshot/reconcile around the
|
|
3
3
|
* read-only gate children (verify, recommend).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* running `eslint --fix .` mid-verification and ad-hoc DDL against the test DB.
|
|
5
|
+
* Those children hold a `read,bash` contract whose "never modify the tree" clause
|
|
6
|
+
* is PROMPT-LEVEL ONLY: `bash` can stash, check out, commit and rewrite files, and
|
|
7
|
+
* nothing but the prompt says not to. A child that stashes the task's uncommitted
|
|
8
|
+
* work and never pops it leaves the verify judging an empty tree AND leaves an
|
|
9
|
+
* orphan stash that only detonates when something later pops it onto a moved HEAD.
|
|
10
|
+
* So this is capability-shaped rather than prompt-shaped: snapshot the repo state
|
|
11
|
+
* BEFORE the child runs, deterministically restore whatever it moved afterwards,
|
|
12
|
+
* no model in the loop.
|
|
14
13
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* - The WORKTREE CONTENT as a git tree object, built through a
|
|
24
|
-
* (`read-tree --empty` + `add -A` + `write-tree`, excluding
|
|
25
|
-
* gate's own debug logs land there DURING the run).
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
14
|
+
* What is captured and reconciled — each one run against a real repo:
|
|
15
|
+
* - HEAD (sha + symbolic branch ref). A child that checked out another commit,
|
|
16
|
+
* detached, is put back on its branch AND its sha. LIMIT: a child that COMMITS
|
|
17
|
+
* on the current branch is NOT undone — the restore checks out
|
|
18
|
+
* `before.branchRef`, and that branch now points at the child's commit, so the
|
|
19
|
+
* `checked HEAD back out to <branch>` line is honest about the ref and says
|
|
20
|
+
* nothing about the sha. The move is still classed verdict-tainting, so the
|
|
21
|
+
* verdict is discarded; the commit stays.
|
|
22
|
+
* - The WORKTREE CONTENT as a git tree object, built through a THROWAWAY index
|
|
23
|
+
* (`read-tree --empty` + `add -A` + `write-tree`, excluding `.pi-tasks` — the
|
|
24
|
+
* gate's own debug logs land there DURING the run). Measured on a repo with a
|
|
25
|
+
* staged file, an untracked file, a gitignored file and a `.pi-tasks/` log: the
|
|
26
|
+
* tree holds the tracked and untracked files and neither of the other two, and
|
|
27
|
+
* the REAL index still shows the same staged path afterwards. Restoration
|
|
28
|
+
* re-materialises every changed or deleted file and deletes what the child
|
|
29
|
+
* created.
|
|
29
30
|
* - The STASH ref: entries the child pushed are dropped AFTER the worktree is
|
|
30
|
-
* restored from the snapshot
|
|
31
|
-
* truth
|
|
31
|
+
* restored from the snapshot — the snapshot, not the stash, is the source of
|
|
32
|
+
* truth — so no orphan stash survives the reconcile.
|
|
32
33
|
*
|
|
33
34
|
* The real index's staging state is deliberately NOT restored: pre-commit gate
|
|
34
35
|
* children run against a tree whose work is unstaged, and the auto-commit that
|
|
35
|
-
* follows re-stages everything with `add -A`
|
|
36
|
+
* follows re-stages everything with `git add -A` (auto-commit.ts:192).
|
|
36
37
|
*
|
|
37
|
-
* Everything is best-effort: a repo where git
|
|
38
|
-
*
|
|
39
|
-
*
|
|
38
|
+
* Everything is best-effort: a repo where git fails disables the guard — capture
|
|
39
|
+
* returns `ok: false` and reconcile no-ops. Measured: a fresh `git init` with no
|
|
40
|
+
* commits answers non-zero to `rev-parse -q --verify HEAD`, which is the unborn-HEAD
|
|
41
|
+
* case the capture bails on.
|
|
40
42
|
*/
|
|
41
43
|
import { readFileSync } from 'node:fs';
|
|
42
44
|
import * as fsp from 'node:fs/promises';
|
|
@@ -48,29 +50,30 @@ import { isRegenerableArtifact } from './regenerable-artifacts.js';
|
|
|
48
50
|
const EXCLUDE_TASKS_DIR = ':(exclude).pi-tasks';
|
|
49
51
|
/**
|
|
50
52
|
* Untracked paths that are regenerable test/build OUTPUT, not graded source. A gate
|
|
51
|
-
* child creating or rewriting one of these has not mutated the work under
|
|
52
|
-
* so its verdict stands. Gitignored files never reach the snapshot
|
|
53
|
-
* them
|
|
54
|
-
* `test-results/` and `playwright-report/` above all
|
|
55
|
-
*
|
|
56
|
-
*
|
|
53
|
+
* child creating or rewriting one of these has not mutated the work under
|
|
54
|
+
* judgement, so its verdict stands. Gitignored files never reach the snapshot at
|
|
55
|
+
* all — measured, `add -A` skips them — so this list is for the ones a typical
|
|
56
|
+
* project leaves UNIGNORED, `test-results/` and `playwright-report/` above all.
|
|
57
|
+
* Kept deliberately narrow: anything NOT matched here that a child modifies or
|
|
58
|
+
* deletes is graded state, and taints the verdict.
|
|
57
59
|
*
|
|
58
|
-
* The list
|
|
59
|
-
*
|
|
60
|
-
*
|
|
60
|
+
* The list lives in `regenerable-artifacts.ts` because three call sites need the
|
|
61
|
+
* same knowledge — this guard, the write-guard's deletion check, and the per-task
|
|
62
|
+
* commit — and three private copies would drift.
|
|
61
63
|
*/
|
|
62
64
|
const isBenignArtifact = isRegenerableArtifact;
|
|
63
65
|
/**
|
|
64
|
-
* Regenerable machine state that is benign EVEN WHEN TRACKED
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* DELIBERATELY narrow: snapshot BASELINE images (`*-snapshots/*.png`) are NOT here —
|
|
66
|
+
* Regenerable machine state that is benign EVEN WHEN TRACKED, so a project that
|
|
67
|
+
* commits it does not have a child's incidental rewrite discard the verdict. Two
|
|
68
|
+
* classes: the component-test build cache under `ctCacheDir`, which a component
|
|
69
|
+
* test run rewrites every time, and the test runner's `.last-run.json` run-state
|
|
70
|
+
* file.
|
|
71
|
+
*
|
|
72
|
+
* DELIBERATELY narrow. Snapshot BASELINE images (`*-snapshots/*.png`) are NOT here:
|
|
72
73
|
* a child that rewrites a baseline to make a screenshot test pass is the real
|
|
73
|
-
* mutate-to-pass catch
|
|
74
|
+
* mutate-to-pass catch. Measured on a real repo — a tracked file under a custom
|
|
75
|
+
* `ctCacheDir` and a tracked `.last-run.json` both restore WITHOUT tainting, while
|
|
76
|
+
* a tracked `tests/a-snapshots/x.png` taints.
|
|
74
77
|
*/
|
|
75
78
|
const ALWAYS_REGENERABLE_PATTERNS = [/(?:^|\/)\.last-run\.json$/];
|
|
76
79
|
/** Playwright config files that may declare a custom `ctCacheDir`. */
|
|
@@ -80,7 +83,10 @@ const CT_CONFIG_FILES = [
|
|
|
80
83
|
'playwright.config.ts',
|
|
81
84
|
'playwright.config.js'
|
|
82
85
|
];
|
|
83
|
-
/** ctCacheDir
|
|
86
|
+
/** The ctCacheDir values assumed when no config declares one. Playwright is not a
|
|
87
|
+
* dependency here, so these are not verifiable against an installed package —
|
|
88
|
+
* what IS verified is that a config declaring `ctCacheDir: './custom-cache/'` is
|
|
89
|
+
* parsed and its directory treated as regenerable. */
|
|
84
90
|
const DEFAULT_CT_CACHE_DIRS = ['.playwright-cache', 'playwright/.cache'];
|
|
85
91
|
/**
|
|
86
92
|
* The component-test cache dir(s) for this project: the `ctCacheDir` any Playwright
|
|
@@ -183,14 +189,15 @@ function pushCapped(actions, verb, paths) {
|
|
|
183
189
|
}
|
|
184
190
|
/**
|
|
185
191
|
* Restore every file recorded in `beforeTree` (content + deletions) and remove
|
|
186
|
-
* files that exist in `afterTree` but not in `beforeTree`
|
|
187
|
-
* created
|
|
192
|
+
* files that exist in `afterTree` but not in `beforeTree` — the ones the child
|
|
193
|
+
* created. Uses a throwaway index seeded from the snapshot tree; `checkout-index
|
|
188
194
|
* -a -f` re-materialises the snapshot verbatim.
|
|
189
195
|
*
|
|
190
|
-
* Returns whether any restored change was *verdict-tainting
|
|
191
|
-
* path that is tracked-in-HEAD or an untracked non-artifact (see
|
|
192
|
-
* Creations and test-runner-artifact churn restore identically
|
|
193
|
-
* Each changed path is itemised
|
|
196
|
+
* Returns whether any restored change was *verdict-tainting*: a modified or
|
|
197
|
+
* deleted path that is tracked-in-HEAD, or an untracked non-artifact (see
|
|
198
|
+
* isBenignArtifact). Creations and test-runner-artifact churn restore identically
|
|
199
|
+
* but do NOT taint. Each changed path is itemised, capped, so the gate trail says
|
|
200
|
+
* WHICH files moved.
|
|
194
201
|
*/
|
|
195
202
|
async function restoreWorktree(cwd, git, beforeTree, afterTree, tracked, ctCacheDirs, actions) {
|
|
196
203
|
const tmpIndex = path.join(os.tmpdir(), `pi-task-guard-restore-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
@@ -209,8 +216,11 @@ async function restoreWorktree(cwd, git, beforeTree, afterTree, tracked, ctCache
|
|
|
209
216
|
const trimmed = line.trim();
|
|
210
217
|
if (trimmed.length === 0)
|
|
211
218
|
continue;
|
|
212
|
-
// "M\tpath", "A\tpath", "D\tpath", "T\tpath" — no -M, so
|
|
213
|
-
// as a D + an A pair
|
|
219
|
+
// "M\tpath", "A\tpath", "D\tpath", "T\tpath" — no -M, so a rename
|
|
220
|
+
// shows as a D + an A pair and each half is classified on its own
|
|
221
|
+
// merits. Measured: renaming a tracked `a.txt` to `b.txt` yields
|
|
222
|
+
// "removed child-created file b.txt" plus "restored deleted file
|
|
223
|
+
// a.txt", and taints.
|
|
214
224
|
const tab = trimmed.indexOf('\t');
|
|
215
225
|
if (tab < 0)
|
|
216
226
|
continue;
|
|
@@ -225,7 +235,7 @@ async function restoreWorktree(cwd, git, beforeTree, afterTree, tracked, ctCache
|
|
|
225
235
|
|| (isBenignArtifact(name) && !tracked.has(name))) {
|
|
226
236
|
// Regenerable test/build output — not graded work. Either an
|
|
227
237
|
// always-regenerable class (ct cache / run-state, benign even when
|
|
228
|
-
// tracked
|
|
238
|
+
// tracked) or untracked test-runner output.
|
|
229
239
|
artifactChanges.push(name);
|
|
230
240
|
}
|
|
231
241
|
else if (code === 'D') {
|
|
@@ -268,11 +278,11 @@ async function restoreWorktree(cwd, git, beforeTree, afterTree, tracked, ctCache
|
|
|
268
278
|
* whatever a gate child moved. Ordering matters:
|
|
269
279
|
*
|
|
270
280
|
* 1. HEAD first — a child parked on another commit must be back on the original
|
|
271
|
-
* ref before the worktree comparison
|
|
272
|
-
* 2. Worktree content from the snapshot TREE
|
|
273
|
-
* have pushed
|
|
274
|
-
* 3. Child-pushed stash entries are dropped LAST, once the work they swallowed
|
|
275
|
-
*
|
|
281
|
+
* ref before the worktree comparison and restore make sense.
|
|
282
|
+
* 2. Worktree content from the snapshot TREE, never from a stash the child may
|
|
283
|
+
* have pushed: the snapshot is the authoritative "as the child found it".
|
|
284
|
+
* 3. Child-pushed stash entries are dropped LAST, once the work they swallowed is
|
|
285
|
+
* already restored — dropping first would destroy the only other copy.
|
|
276
286
|
*
|
|
277
287
|
* Never throws; failures degrade to actions[] lines so the caller can log them.
|
|
278
288
|
*/
|
|
@@ -308,9 +318,9 @@ export async function reconcileGitState(cwd, before, signal, spawnFn) {
|
|
|
308
318
|
}
|
|
309
319
|
}
|
|
310
320
|
// 3. Stash entries the child pushed. Drop stash@{0} until the ref matches the
|
|
311
|
-
// snapshot again
|
|
312
|
-
//
|
|
313
|
-
// reconstructed
|
|
321
|
+
// snapshot again, bounded at 10 so a runaway cannot loop here. A stash the
|
|
322
|
+
// child POPPED — the ref is gone or no longer contains the snapshot's tip —
|
|
323
|
+
// cannot be reconstructed, so report it instead of guessing.
|
|
314
324
|
const stashNow = async () => {
|
|
315
325
|
const s = await git(['rev-parse', '-q', '--verify', 'refs/stash']);
|
|
316
326
|
return s.exitCode === 0 ? s.stdout.trim() : null;
|
|
@@ -318,7 +328,7 @@ export async function reconcileGitState(cwd, before, signal, spawnFn) {
|
|
|
318
328
|
let stash = await stashNow();
|
|
319
329
|
if (stash !== before.stashSha) {
|
|
320
330
|
// A child that pushed/popped a stash moved graded work in or out of the tree
|
|
321
|
-
// (
|
|
331
|
+
// (a stash-and-abandon) — always verdict-tainting.
|
|
322
332
|
tainted = true;
|
|
323
333
|
if (before.stashSha === null || (await stashContains(git, stash, before.stashSha))) {
|
|
324
334
|
let dropped = 0;
|
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Implementation-turn status widget.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* `TaskRunner._deliverSpec` is preceded by `_disposeWidget()`, so the phase widget
|
|
5
|
+
* (widget.ts) is gone before the spec is handed off. Without this module the host
|
|
6
|
+
* agent's implementation turn — the longest, most visible part of a run — would
|
|
7
|
+
* show only pi's own working indicator, whose default message is the literal
|
|
8
|
+
* `"Working..."`. This keeps the SAME rich status block alive across that turn
|
|
9
|
+
* (task id · implementing/elapsed/context bar · ↳ last tool), driven by the host's
|
|
10
|
+
* own live `ctx.getContextUsage()`, which pi declares as
|
|
11
|
+
* `getContextUsage(): ContextUsage | undefined`.
|
|
9
12
|
*
|
|
10
|
-
*
|
|
13
|
+
* Event-driven rather than poll-wrapped, because the two delivery paths differ:
|
|
11
14
|
*
|
|
12
|
-
* • /task (fire-and-forget): the command returns right after
|
|
13
|
-
* so the host runs the
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* the
|
|
15
|
+
* • /task (fire-and-forget): the command returns right after
|
|
16
|
+
* `piApi.sendUserMessage(spec, {deliverAs: 'followUp'})`, so the host runs the
|
|
17
|
+
* impl turn AFTER this code is gone and only an `agent_start` handler can pick
|
|
18
|
+
* it up. Armed one-shot, and `agent_end` disarms it.
|
|
19
|
+
* • /task-auto (awaited): the caller blocks across `waitForIdle` plus any resume
|
|
20
|
+
* or steer turns. Armed sticky — each `agent_start` re-shows the widget,
|
|
21
|
+
* `agent_end` only hides it between turns, and the caller disarms in a
|
|
22
|
+
* `finally` once the whole implementation phase has settled.
|
|
19
23
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
24
|
+
* `_deliverSpec` picks between them with `oneShot: !this._implAwaited`.
|
|
25
|
+
*
|
|
26
|
+
* A single module-level slot is enough because only one task runs at a time —
|
|
27
|
+
* `orchestrator.ts` keeps one module-level `activeTask`.
|
|
22
28
|
*/
|
|
23
29
|
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
24
30
|
export interface ImplWidgetMeta {
|
|
@@ -36,5 +42,8 @@ export declare function armImplWidget(meta: ImplWidgetMeta, opts: {
|
|
|
36
42
|
}): void;
|
|
37
43
|
/** Tear down the widget and clear the armed slot (sticky/awaited path). */
|
|
38
44
|
export declare function disarmImplWidget(): void;
|
|
39
|
-
/** Wire the agent-lifecycle handlers that drive the widget. Call once at setup.
|
|
45
|
+
/** Wire the agent-lifecycle handlers that drive the widget. Call once at setup.
|
|
46
|
+
* All three events are pi's own: `agent_start`, `tool_execution_start` and
|
|
47
|
+
* `agent_end` each have an `on()` overload, and ToolExecutionStartEvent carries
|
|
48
|
+
* the `toolName` and `args` read below. */
|
|
40
49
|
export declare function setupImplWidget(pi: ExtensionAPI): void;
|
package/dist/task/impl-widget.js
CHANGED
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Implementation-turn status widget.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* `TaskRunner._deliverSpec` is preceded by `_disposeWidget()`, so the phase widget
|
|
5
|
+
* (widget.ts) is gone before the spec is handed off. Without this module the host
|
|
6
|
+
* agent's implementation turn — the longest, most visible part of a run — would
|
|
7
|
+
* show only pi's own working indicator, whose default message is the literal
|
|
8
|
+
* `"Working..."`. This keeps the SAME rich status block alive across that turn
|
|
9
|
+
* (task id · implementing/elapsed/context bar · ↳ last tool), driven by the host's
|
|
10
|
+
* own live `ctx.getContextUsage()`, which pi declares as
|
|
11
|
+
* `getContextUsage(): ContextUsage | undefined`.
|
|
9
12
|
*
|
|
10
|
-
*
|
|
13
|
+
* Event-driven rather than poll-wrapped, because the two delivery paths differ:
|
|
11
14
|
*
|
|
12
|
-
* • /task (fire-and-forget): the command returns right after
|
|
13
|
-
* so the host runs the
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* the
|
|
15
|
+
* • /task (fire-and-forget): the command returns right after
|
|
16
|
+
* `piApi.sendUserMessage(spec, {deliverAs: 'followUp'})`, so the host runs the
|
|
17
|
+
* impl turn AFTER this code is gone and only an `agent_start` handler can pick
|
|
18
|
+
* it up. Armed one-shot, and `agent_end` disarms it.
|
|
19
|
+
* • /task-auto (awaited): the caller blocks across `waitForIdle` plus any resume
|
|
20
|
+
* or steer turns. Armed sticky — each `agent_start` re-shows the widget,
|
|
21
|
+
* `agent_end` only hides it between turns, and the caller disarms in a
|
|
22
|
+
* `finally` once the whole implementation phase has settled.
|
|
19
23
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
24
|
+
* `_deliverSpec` picks between them with `oneShot: !this._implAwaited`.
|
|
25
|
+
*
|
|
26
|
+
* A single module-level slot is enough because only one task runs at a time —
|
|
27
|
+
* `orchestrator.ts` keeps one module-level `activeTask`.
|
|
22
28
|
*/
|
|
23
29
|
import { WIDGET_KEY, WIDGET_REFRESH_MS, buildImplLines, buildImplData } from './widget.js';
|
|
24
30
|
import { setTaskWidget } from '../remote/session-state.js';
|
|
@@ -27,7 +33,8 @@ let lastLine;
|
|
|
27
33
|
let timer = null;
|
|
28
34
|
let activeCtx = null;
|
|
29
35
|
/** Map the host's live context usage to the widget snapshot, or undefined when the
|
|
30
|
-
* token count is unknown
|
|
36
|
+
* token count is unknown. pi types `ContextUsage.tokens` as `number | null` and
|
|
37
|
+
* documents the null as "right after compaction, before next LLM response". */
|
|
31
38
|
function snapshot(ctx) {
|
|
32
39
|
const u = ctx.getContextUsage?.();
|
|
33
40
|
if (!u || u.tokens == null)
|
|
@@ -100,7 +107,10 @@ export function disarmImplWidget() {
|
|
|
100
107
|
activeCtx = null;
|
|
101
108
|
lastLine = undefined;
|
|
102
109
|
}
|
|
103
|
-
/** Wire the agent-lifecycle handlers that drive the widget. Call once at setup.
|
|
110
|
+
/** Wire the agent-lifecycle handlers that drive the widget. Call once at setup.
|
|
111
|
+
* All three events are pi's own: `agent_start`, `tool_execution_start` and
|
|
112
|
+
* `agent_end` each have an `on()` overload, and ToolExecutionStartEvent carries
|
|
113
|
+
* the `toolName` and `args` read below. */
|
|
104
114
|
export function setupImplWidget(pi) {
|
|
105
115
|
pi.on('agent_start', (_event, ctx) => {
|
|
106
116
|
if (!armed)
|
|
@@ -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;
|
|
@@ -124,18 +125,18 @@ export declare function turnDepsFor(ctx: SteerCtx, opts?: SuperviseOptions): Imp
|
|
|
124
125
|
/**
|
|
125
126
|
* Nudge that resumes an implementation turn the runtime parked at a compaction
|
|
126
127
|
* 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
|
-
*
|
|
128
|
+
* threshold by its own final message) confirm completion without inventing busywork.
|
|
129
|
+
* The classifier sees only the boundary's POSITION, so it cannot tell "paused
|
|
130
|
+
* mid-task by compaction" from "finished, then compacted"; the wording lets a done
|
|
131
|
+
* turn end in one line.
|
|
130
132
|
*/
|
|
131
133
|
export declare const CONTINUE_AFTER_COMPACTION: string;
|
|
132
134
|
/**
|
|
133
135
|
* 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.
|
|
136
|
+
* resume follows a real compaction, which pi only runs once `shouldCompact` says
|
|
137
|
+
* the context crossed its threshold. The cap exists to stop a pathological loop
|
|
138
|
+
* from auto-sending forever with no user watching. Hitting it stops resuming and
|
|
139
|
+
* lets the verify gate and `/task-auto-resume` catch any leftover incompleteness.
|
|
139
140
|
*/
|
|
140
141
|
export declare const MAX_COMPACTION_RESUMES = 20;
|
|
141
142
|
/**
|
|
@@ -154,10 +155,12 @@ export declare function resumeAcrossCompactions(deps: ImplementationTurnDeps): P
|
|
|
154
155
|
* `waitForIdle` resolves both on natural completion AND on an ESC (which aborts
|
|
155
156
|
* the turn → idle). When the last turn was aborted, the host's main input loop is
|
|
156
157
|
* blocked inside our command handler, so a message typed in the editor would only
|
|
157
|
-
* queue, never run
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
158
|
+
* queue, never run: interactive-mode's submit handler calls `onInputCallback` when
|
|
159
|
+
* the session is idle, and that callback is set only inside `getUserInput()` — the
|
|
160
|
+
* REPL loop we are holding — so the text lands in `pendingUserInputs` instead. We
|
|
161
|
+
* therefore solicit the steering text ourselves and feed it back as another turn
|
|
162
|
+
* via `sendUserMessage`, which forwards to `prompt()` and, on an idle session, runs
|
|
163
|
+
* the turn rather than queueing it. Repeat until a turn finishes uninterrupted.
|
|
161
164
|
*
|
|
162
165
|
* A WATCHDOG abort also ends the turn with stopReason 'aborted' — indistinguishable
|
|
163
166
|
* from a human ESC by the session entries alone at that instant. The watchdog
|