@mjasnikovs/pi-task 0.38.29 → 0.38.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/config.d.ts +70 -70
- package/dist/config/config.js +26 -35
- package/dist/config/extension-list.d.ts +6 -5
- package/dist/config/extension-list.js +3 -2
- package/dist/config/reasoning-args.d.ts +9 -7
- package/dist/config/reasoning-args.js +12 -10
- package/dist/config/reasoning.d.ts +44 -105
- package/dist/config/reasoning.js +27 -704
- package/dist/config/register.d.ts +34 -48
- package/dist/config/register.js +41 -51
- package/dist/config/tool-list.d.ts +16 -16
- package/dist/config/tool-list.js +1 -1
- package/dist/remote/bridge.d.ts +19 -10
- package/dist/remote/bridge.js +3 -2
- package/dist/remote/broadcast.js +3 -1
- package/dist/remote/events.js +12 -11
- package/dist/remote/history.d.ts +1 -1
- package/dist/remote/protocol.d.ts +6 -3
- package/dist/remote/protocol.js +2 -1
- package/dist/remote/push.d.ts +16 -16
- package/dist/remote/push.js +27 -27
- package/dist/remote/register.d.ts +3 -3
- package/dist/remote/register.js +17 -19
- package/dist/remote/server.d.ts +9 -8
- package/dist/remote/server.js +15 -14
- package/dist/remote/session-state.d.ts +5 -4
- package/dist/remote/session-state.js +8 -5
- package/dist/remote/sw.d.ts +7 -6
- package/dist/remote/sw.js +7 -6
- package/dist/remote/tailscale.d.ts +4 -2
- package/dist/remote/tailscale.js +4 -2
- package/dist/remote/ui-highlight.js +6 -5
- package/dist/remote/ui-render.js +4 -4
- package/dist/remote/ui-script.js +24 -24
- package/dist/remote/ui-styles.d.ts +1 -1
- package/dist/remote/ui-styles.js +10 -13
- package/dist/remote/ui-tools.js +9 -6
- package/dist/shared/child-extensions.d.ts +29 -17
- package/dist/shared/child-extensions.js +29 -17
- package/dist/shared/child-output.d.ts +30 -24
- package/dist/shared/child-output.js +25 -17
- package/dist/shared/child-process.d.ts +47 -40
- package/dist/shared/child-process.js +50 -59
- package/dist/shared/command-watchdog.d.ts +22 -16
- package/dist/shared/command-watchdog.js +28 -21
- package/dist/shared/fs-text.d.ts +16 -10
- package/dist/shared/fs-text.js +16 -10
- package/dist/shared/git-runner.d.ts +25 -25
- package/dist/shared/git-runner.js +25 -25
- package/dist/shared/leaked-tool-call.d.ts +17 -11
- package/dist/shared/leaked-tool-call.js +23 -15
- package/dist/shared/model-endpoint.d.ts +29 -16
- package/dist/shared/model-endpoint.js +33 -21
- package/dist/shared/pi-invocation.d.ts +7 -4
- package/dist/shared/pi-invocation.js +12 -7
- package/dist/shared/pkg-version.d.ts +13 -5
- package/dist/shared/pkg-version.js +13 -5
- package/dist/shared/reasoning-capability.d.ts +35 -24
- package/dist/shared/reasoning-capability.js +35 -24
- package/dist/shared/stream-watchdog.d.ts +60 -44
- package/dist/shared/stream-watchdog.js +62 -45
- package/dist/task/accept-debt.d.ts +41 -43
- package/dist/task/accept-debt.js +73 -65
- package/dist/task/api-synthesis.d.ts +24 -21
- package/dist/task/api-synthesis.js +32 -26
- package/dist/task/apis-contract.d.ts +32 -64
- package/dist/task/apis-contract.js +32 -64
- package/dist/task/artifact-closure.d.ts +27 -13
- package/dist/task/artifact-closure.js +95 -67
- package/dist/task/auto-commit.d.ts +46 -35
- package/dist/task/auto-commit.js +51 -38
- package/dist/task/auto-io.d.ts +45 -25
- package/dist/task/auto-io.js +57 -29
- package/dist/task/auto-orchestrator.d.ts +26 -24
- package/dist/task/auto-orchestrator.js +178 -162
- package/dist/task/auto-prompts.d.ts +36 -24
- package/dist/task/auto-prompts.js +40 -26
- package/dist/task/autofix-ledger.d.ts +27 -25
- package/dist/task/autofix-ledger.js +29 -26
- package/dist/task/batch-test-task.d.ts +20 -12
- package/dist/task/batch-test-task.js +67 -60
- package/dist/task/boot-probe.d.ts +60 -44
- package/dist/task/boot-probe.js +91 -72
- package/dist/task/cancel-input.d.ts +30 -16
- package/dist/task/cancel-input.js +20 -11
- package/dist/task/cancel-points.d.ts +27 -20
- package/dist/task/cancel-points.js +30 -22
- package/dist/task/child-runner.d.ts +46 -51
- package/dist/task/child-runner.js +48 -49
- package/dist/task/child-status.d.ts +23 -16
- package/dist/task/child-status.js +23 -16
- package/dist/task/clamp-output.js +12 -5
- package/dist/task/command-run.d.ts +31 -28
- package/dist/task/command-run.js +44 -35
- package/dist/task/command-shrink.d.ts +25 -18
- package/dist/task/command-shrink.js +37 -31
- package/dist/task/command-watchdog.d.ts +9 -6
- package/dist/task/command-watchdog.js +21 -15
- package/dist/task/context-attribution.d.ts +34 -26
- package/dist/task/context-attribution.js +34 -26
- package/dist/task/context-silence.d.ts +39 -29
- package/dist/task/context-silence.js +35 -25
- package/dist/task/context-usage.d.ts +16 -9
- package/dist/task/context-usage.js +16 -9
- package/dist/task/contracts.d.ts +8 -4
- package/dist/task/contracts.js +25 -17
- package/dist/task/coverage-loop.d.ts +22 -18
- package/dist/task/coverage-loop.js +35 -30
- package/dist/task/critique-probes.d.ts +13 -14
- package/dist/task/critique-probes.js +50 -39
- package/dist/task/debug-log.d.ts +13 -5
- package/dist/task/debug-log.js +32 -20
- package/dist/task/decompose-fidelity.d.ts +11 -9
- package/dist/task/decompose-fidelity.js +38 -33
- package/dist/task/decompose-granularity.d.ts +41 -38
- package/dist/task/decompose-granularity.js +41 -38
- package/dist/task/deep-render-check.d.ts +22 -14
- package/dist/task/deep-render-check.js +40 -31
- package/dist/task/dropped-input.d.ts +12 -7
- package/dist/task/dropped-input.js +5 -2
- package/dist/task/enforce-attribution.d.ts +38 -47
- package/dist/task/enforce-attribution.js +46 -52
- package/dist/task/enforce-guidelines.d.ts +31 -20
- package/dist/task/enforce-guidelines.js +32 -21
- package/dist/task/enrichment.d.ts +7 -2
- package/dist/task/enrichment.js +26 -14
- package/dist/task/env-notes.d.ts +16 -7
- package/dist/task/env-notes.js +48 -31
- package/dist/task/env-template-closure.d.ts +4 -4
- package/dist/task/env-template-closure.js +42 -34
- package/dist/task/external-context.d.ts +28 -21
- package/dist/task/external-context.js +17 -12
- package/dist/task/failure-classifier.d.ts +4 -5
- package/dist/task/failure-classifier.js +6 -7
- package/dist/task/file-inventory.d.ts +15 -11
- package/dist/task/file-inventory.js +25 -22
- package/dist/task/final-gate-fix.d.ts +74 -86
- package/dist/task/final-gate-fix.js +97 -116
- package/dist/task/final-gate-progress.d.ts +29 -46
- package/dist/task/final-gate-progress.js +40 -51
- package/dist/task/final-gate.d.ts +64 -97
- package/dist/task/final-gate.js +192 -199
- package/dist/task/fix-child.d.ts +21 -27
- package/dist/task/fix-child.js +21 -27
- package/dist/task/foreign-path.d.ts +6 -5
- package/dist/task/foreign-path.js +0 -0
- package/dist/task/frozen-conflict.d.ts +9 -10
- package/dist/task/frozen-conflict.js +61 -64
- package/dist/task/frozen-path-guard.d.ts +35 -14
- package/dist/task/frozen-path-guard.js +56 -39
- package/dist/task/gate-child.d.ts +27 -28
- package/dist/task/gate-child.js +36 -35
- package/dist/task/gate-deps.d.ts +34 -27
- package/dist/task/gate-deps.js +169 -159
- package/dist/task/gate-tally.d.ts +77 -80
- package/dist/task/gate-tally.js +65 -68
- package/dist/task/git-state-guard.d.ts +15 -11
- package/dist/task/git-state-guard.js +76 -66
- package/dist/task/impl-widget.d.ts +25 -16
- package/dist/task/impl-widget.js +27 -17
- package/dist/task/implementation-thinking.d.ts +33 -31
- package/dist/task/implementation-thinking.js +5 -6
- package/dist/task/implementation-turn.d.ts +34 -31
- package/dist/task/implementation-turn.js +29 -27
- package/dist/task/inline-markdown.d.ts +20 -7
- package/dist/task/inline-markdown.js +15 -6
- package/dist/task/launch-config-gap.js +25 -39
- package/dist/task/launch-contract.d.ts +18 -21
- package/dist/task/launch-contract.js +28 -30
- package/dist/task/launch-manifest.d.ts +6 -2
- package/dist/task/launch-manifest.js +35 -34
- package/dist/task/ledger.js +16 -14
- package/dist/task/lint-fix.d.ts +6 -8
- package/dist/task/lint-fix.js +67 -69
- package/dist/task/loop-detector.d.ts +9 -8
- package/dist/task/loop-detector.js +16 -12
- package/dist/task/mid-run-input.d.ts +17 -15
- package/dist/task/mid-run-input.js +17 -15
- package/dist/task/orchestrator.d.ts +24 -28
- package/dist/task/orchestrator.js +62 -64
- package/dist/task/orientation.d.ts +18 -23
- package/dist/task/orientation.js +24 -31
- package/dist/task/owned-freeze-conflict.d.ts +21 -20
- package/dist/task/owned-freeze-conflict.js +52 -85
- package/dist/task/owned-freeze-reassign.d.ts +40 -60
- package/dist/task/owned-freeze-reassign.js +41 -61
- package/dist/task/parsers.d.ts +4 -2
- package/dist/task/parsers.js +4 -4
- package/dist/task/phases.d.ts +41 -48
- package/dist/task/phases.js +179 -248
- package/dist/task/plan-io.d.ts +6 -7
- package/dist/task/plan-io.js +6 -7
- package/dist/task/plan-orchestrator.d.ts +10 -8
- package/dist/task/plan-orchestrator.js +14 -10
- package/dist/task/plan-prompts.d.ts +6 -5
- package/dist/task/plan-prompts.js +6 -5
- package/dist/task/plan-readonly.d.ts +4 -5
- package/dist/task/plan-readonly.js +4 -5
- package/dist/task/plan-rounds.d.ts +17 -29
- package/dist/task/plan-rounds.js +21 -34
- package/dist/task/plan-session.d.ts +58 -72
- package/dist/task/plan-session.js +61 -83
- package/dist/task/probe-gaming.d.ts +28 -27
- package/dist/task/probe-gaming.js +0 -0
- package/dist/task/prohibition-probe.d.ts +14 -16
- package/dist/task/prompts.d.ts +3 -4
- package/dist/task/prompts.js +17 -26
- package/dist/task/qa-transcript.d.ts +15 -22
- package/dist/task/qa-transcript.js +15 -21
- package/dist/task/question-box.d.ts +17 -13
- package/dist/task/question-box.js +19 -15
- package/dist/task/question-dedup.d.ts +6 -7
- package/dist/task/question-dedup.js +13 -14
- package/dist/task/question-dialog.d.ts +22 -32
- package/dist/task/question-dialog.js +22 -32
- package/dist/task/question-source.d.ts +18 -44
- package/dist/task/question-source.js +22 -51
- package/dist/task/refuted-constraint.d.ts +11 -31
- package/dist/task/refuted-constraint.js +27 -51
- package/dist/task/regenerable-artifacts.d.ts +12 -31
- package/dist/task/regenerable-artifacts.js +12 -31
- package/dist/task/render-check.d.ts +11 -22
- package/dist/task/render-check.js +33 -46
- package/dist/task/repo-health-check.d.ts +10 -14
- package/dist/task/repo-health-check.js +17 -23
- package/dist/task/requirements.d.ts +38 -71
- package/dist/task/requirements.js +78 -126
- package/dist/task/research-fanout-budget.d.ts +51 -88
- package/dist/task/research-fanout-budget.js +51 -88
- package/dist/task/research-worker.d.ts +29 -39
- package/dist/task/research-worker.js +37 -61
- package/dist/task/resume-gap.d.ts +14 -15
- package/dist/task/root-cause-repair.d.ts +9 -9
- package/dist/task/root-cause-repair.js +28 -40
- package/dist/task/run-bracket.d.ts +10 -13
- package/dist/task/run-end.d.ts +12 -22
- package/dist/task/run-end.js +8 -16
- package/dist/task/run-final-gate.d.ts +19 -21
- package/dist/task/run-final-gate.js +62 -80
- package/dist/task/runner-globs.d.ts +12 -13
- package/dist/task/runner-globs.js +12 -13
- package/dist/task/runner-resolve.d.ts +9 -9
- package/dist/task/runner-resolve.js +22 -23
- package/dist/task/script-escape.d.ts +10 -12
- package/dist/task/script-escape.js +13 -14
- package/dist/task/serve-entry.d.ts +1 -1
- package/dist/task/serve-entry.js +22 -25
- package/dist/task/service-blocks.js +4 -2
- package/dist/task/shipped-source.d.ts +11 -29
- package/dist/task/shipped-source.js +11 -29
- package/dist/task/skip-escape.js +10 -14
- package/dist/task/spec-urls.d.ts +26 -65
- package/dist/task/spec-urls.js +26 -65
- package/dist/task/spec-validation.d.ts +17 -20
- package/dist/task/spec-validation.js +17 -20
- package/dist/task/stall-detector.d.ts +23 -30
- package/dist/task/stall-detector.js +23 -30
- package/dist/task/stream-watchdog.d.ts +14 -12
- package/dist/task/stream-watchdog.js +14 -12
- package/dist/task/substitution-probe.d.ts +17 -20
- package/dist/task/substitution-probe.js +17 -20
- package/dist/task/task-gates.d.ts +36 -41
- package/dist/task/task-gates.js +95 -106
- package/dist/task/task-io.d.ts +4 -4
- package/dist/task/task-io.js +4 -4
- package/dist/task/task-parsers.js +4 -3
- package/dist/task/task-provenance.d.ts +2 -2
- package/dist/task/task-provenance.js +11 -13
- package/dist/task/task-types.d.ts +4 -3
- package/dist/task/terminal-outcome.d.ts +14 -16
- package/dist/task/terminal-outcome.js +12 -14
- package/dist/task/test-assembly.d.ts +13 -20
- package/dist/task/test-assembly.js +13 -20
- package/dist/task/timings.d.ts +5 -3
- package/dist/task/timings.js +5 -3
- package/dist/task/title-label.d.ts +9 -4
- package/dist/task/title-label.js +9 -4
- package/dist/task/type-only-answer.d.ts +44 -52
- package/dist/task/type-only-answer.js +44 -52
- package/dist/task/unfailable-command.d.ts +18 -24
- package/dist/task/unfailable-command.js +21 -27
- package/dist/task/unknown-routing.d.ts +10 -4
- package/dist/task/unknown-routing.js +10 -4
- package/dist/task/user-directives.d.ts +5 -8
- package/dist/task/user-directives.js +5 -8
- package/dist/task/verify-quality.d.ts +18 -22
- package/dist/task/verify-quality.js +45 -46
- package/dist/task/verify-reconcile.d.ts +15 -10
- package/dist/task/verify-reconcile.js +45 -43
- package/dist/task/verify-resolution.d.ts +24 -20
- package/dist/task/verify-resolution.js +51 -50
- package/dist/task/verify-work.d.ts +59 -66
- package/dist/task/verify-work.js +101 -138
- package/dist/task/widget.d.ts +15 -14
- package/dist/task/widget.js +22 -17
- package/dist/task/wiring-claims.d.ts +25 -32
- package/dist/task/wiring-claims.js +30 -35
- package/dist/task/write-guard.d.ts +39 -39
- package/dist/task/write-guard.js +48 -51
- package/dist/task/yolo.d.ts +34 -30
- package/dist/task/yolo.js +42 -37
- package/dist/workers/abstention.d.ts +21 -41
- package/dist/workers/abstention.js +27 -48
- package/dist/workers/brave-search.d.ts +4 -3
- package/dist/workers/brave-search.js +5 -2
- package/dist/workers/brave-warning.d.ts +7 -4
- package/dist/workers/brave-warning.js +19 -7
- package/dist/workers/ddg-search.d.ts +6 -6
- package/dist/workers/ddg-search.js +18 -12
- package/dist/workers/docs-cache.js +5 -2
- package/dist/workers/docs-chunk.d.ts +30 -37
- package/dist/workers/docs-chunk.js +37 -41
- package/dist/workers/docs-core.d.ts +28 -44
- package/dist/workers/docs-core.js +25 -44
- package/dist/workers/docs-index.js +4 -3
- package/dist/workers/docs-lookup.d.ts +15 -22
- package/dist/workers/docs-lookup.js +12 -21
- package/dist/workers/docs-project.d.ts +15 -9
- package/dist/workers/docs-project.js +17 -10
- package/dist/workers/docs-resolve.d.ts +19 -20
- package/dist/workers/docs-resolve.js +35 -32
- package/dist/workers/docs-retrieve.d.ts +5 -6
- package/dist/workers/docs-retrieve.js +18 -15
- package/dist/workers/exa-search.d.ts +9 -6
- package/dist/workers/exa-search.js +23 -12
- package/dist/workers/fetch-core.d.ts +13 -16
- package/dist/workers/fetch-core.js +23 -23
- package/dist/workers/focused-extractor.d.ts +12 -12
- package/dist/workers/focused-extractor.js +16 -19
- package/dist/workers/html-clean.js +24 -14
- package/dist/workers/http-request.d.ts +28 -20
- package/dist/workers/http-request.js +22 -17
- package/dist/workers/npm-version.d.ts +28 -11
- package/dist/workers/npm-version.js +24 -15
- package/dist/workers/phantom-imports.d.ts +15 -12
- package/dist/workers/phantom-imports.js +30 -24
- package/dist/workers/pi-worker-core.d.ts +69 -71
- package/dist/workers/pi-worker-core.js +100 -109
- package/dist/workers/pi-worker-docs.d.ts +24 -19
- package/dist/workers/pi-worker-docs.js +67 -76
- package/dist/workers/pi-worker-fetch.d.ts +7 -3
- package/dist/workers/pi-worker-fetch.js +27 -19
- package/dist/workers/pi-worker-search.js +12 -8
- package/dist/workers/pi-worker.d.ts +9 -4
- package/dist/workers/pi-worker.js +21 -14
- package/dist/workers/reasoning-warning.d.ts +18 -17
- package/dist/workers/reasoning-warning.js +22 -20
- package/dist/workers/research-cache.js +50 -78
- package/dist/workers/search-core.js +7 -5
- package/dist/workers/search-types.d.ts +10 -9
- package/dist/workers/search-types.js +9 -8
- package/dist/workers/session-hint.d.ts +13 -14
- package/dist/workers/session-hint.js +8 -9
- package/dist/workers/shared.d.ts +21 -25
- package/dist/workers/shared.js +0 -0
- package/dist/workers/single-read-extension.d.ts +14 -7
- package/dist/workers/single-read-extension.js +14 -7
- package/dist/workers/single-read-guard.d.ts +25 -28
- package/dist/workers/single-read-guard.js +32 -32
- package/dist/workers/typeonly-log.d.ts +12 -9
- package/dist/workers/typeonly-log.js +29 -33
- package/dist/workers/worker-channels.d.ts +15 -23
- package/dist/workers/worker-channels.js +15 -23
- package/dist/workers/worker-failure.d.ts +38 -46
- package/dist/workers/worker-failure.js +31 -39
- package/dist/workers/worker-kill.d.ts +25 -26
- package/dist/workers/worker-kill.js +16 -19
- package/dist/workers/worker-profiles.d.ts +43 -53
- package/dist/workers/worker-profiles.js +30 -38
- package/package.json +10 -8
|
@@ -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 { SessionUI } from '../remote/bridge.js';
|
|
18
19
|
import { consumeWatchdogAbort, WATCHDOG_CANCEL_MARKER } from './command-watchdog.js';
|
|
@@ -33,21 +34,20 @@ function tailPositions(entries) {
|
|
|
33
34
|
/**
|
|
34
35
|
* Classify how the most recent turn ended, from the session entries alone.
|
|
35
36
|
*
|
|
36
|
-
* Precedence, when several signals are present at once
|
|
37
|
-
* supervision sequence has always applied, now stated in one place):
|
|
37
|
+
* Precedence, when several signals are present at once:
|
|
38
38
|
* 1. `aborted` — the last assistant message has stopReason "aborted". A user
|
|
39
39
|
* ESC (or watchdog abort) wins over everything: it is not a
|
|
40
40
|
* compaction pause, and the steer loop owns it.
|
|
41
41
|
* 2. `compaction` — a `compaction` entry sits AFTER the last assistant message.
|
|
42
|
-
* Position-based, not timestamp-based:
|
|
43
|
-
* boundary
|
|
44
|
-
*
|
|
42
|
+
* Position-based, not timestamp-based: `appendCompaction`
|
|
43
|
+
* pushes the boundary onto the tail of the entry list, and
|
|
44
|
+
* `getEntries()` returns that list in append order, so a
|
|
45
45
|
* 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.
|
|
46
|
+
* A finished turn ends on an assistant message. An overflow
|
|
47
|
+
* compaction that is going to retry continues the turn itself
|
|
48
|
+
* and never reaches us idle.
|
|
49
|
+
* 3. `error` — the last assistant message has stopReason "error": the model
|
|
50
|
+
* or provider failed after pi exhausted its own retries.
|
|
51
51
|
* 4. `stop` — anything else, including a session with no assistant turn.
|
|
52
52
|
*/
|
|
53
53
|
export function classifyTurnEnd(entries) {
|
|
@@ -143,9 +143,10 @@ export function turnDepsFor(ctx, opts = {}) {
|
|
|
143
143
|
/**
|
|
144
144
|
* Nudge that resumes an implementation turn the runtime parked at a compaction
|
|
145
145
|
* 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
|
-
*
|
|
146
|
+
* threshold by its own final message) confirm completion without inventing busywork.
|
|
147
|
+
* The classifier sees only the boundary's POSITION, so it cannot tell "paused
|
|
148
|
+
* mid-task by compaction" from "finished, then compacted"; the wording lets a done
|
|
149
|
+
* turn end in one line.
|
|
149
150
|
*/
|
|
150
151
|
export const CONTINUE_AFTER_COMPACTION = 'Your context was automatically compacted. Continue implementing this task from '
|
|
151
152
|
+ 'exactly where you left off, and keep going until it is fully done. If the '
|
|
@@ -153,11 +154,10 @@ export const CONTINUE_AFTER_COMPACTION = 'Your context was automatically compact
|
|
|
153
154
|
+ 'extra work or restart the task.';
|
|
154
155
|
/**
|
|
155
156
|
* 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.
|
|
157
|
+
* resume follows a real compaction, which pi only runs once `shouldCompact` says
|
|
158
|
+
* the context crossed its threshold. The cap exists to stop a pathological loop
|
|
159
|
+
* from auto-sending forever with no user watching. Hitting it stops resuming and
|
|
160
|
+
* lets the verify gate and `/task-auto-resume` catch any leftover incompleteness.
|
|
161
161
|
*/
|
|
162
162
|
export const MAX_COMPACTION_RESUMES = 20;
|
|
163
163
|
/**
|
|
@@ -209,10 +209,12 @@ async function awaitWatchdogFollowUp(deps) {
|
|
|
209
209
|
* `waitForIdle` resolves both on natural completion AND on an ESC (which aborts
|
|
210
210
|
* the turn → idle). When the last turn was aborted, the host's main input loop is
|
|
211
211
|
* blocked inside our command handler, so a message typed in the editor would only
|
|
212
|
-
* queue, never run
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
212
|
+
* queue, never run: interactive-mode's submit handler calls `onInputCallback` when
|
|
213
|
+
* the session is idle, and that callback is set only inside `getUserInput()` — the
|
|
214
|
+
* REPL loop we are holding — so the text lands in `pendingUserInputs` instead. We
|
|
215
|
+
* therefore solicit the steering text ourselves and feed it back as another turn
|
|
216
|
+
* via `sendUserMessage`, which forwards to `prompt()` and, on an idle session, runs
|
|
217
|
+
* the turn rather than queueing it. Repeat until a turn finishes uninterrupted.
|
|
216
218
|
*
|
|
217
219
|
* A WATCHDOG abort also ends the turn with stopReason 'aborted' — indistinguishable
|
|
218
220
|
* from a human ESC by the session entries alone at that instant. The watchdog
|
|
@@ -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;
|
|
@@ -3,13 +3,10 @@
|
|
|
3
3
|
* declares the finished project must expose, extracted once at plan time and diffed
|
|
4
4
|
* by the final gate against the shipped manifest.
|
|
5
5
|
*
|
|
6
|
-
* The
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* the finished manifest against the design's own list, so the run completed missing
|
|
11
|
-
* two of its declared entrypoints. A per-slice gate cannot catch this — it is a
|
|
12
|
-
* whole-project launch-surface fact — and the final gate never had the design's list.
|
|
6
|
+
* The gap it closes is structural. A script the design names but no task owned can
|
|
7
|
+
* fall through decompose and ship missing, and a per-slice gate cannot see that: it
|
|
8
|
+
* is a whole-project launch-surface fact, and nothing else re-reads the finished
|
|
9
|
+
* manifest against the design's own list.
|
|
13
10
|
*
|
|
14
11
|
* Mechanism (mirrors contracts.ts): a plan-time child EMITs `SCRIPT:` lines naming the
|
|
15
12
|
* scripts the design declares; the host GROUNDS each against the design — a name is
|
|
@@ -17,9 +14,13 @@
|
|
|
17
14
|
* form designs use to declare a script. A paraphrase or a script the model invented is
|
|
18
15
|
* not grounded and is dropped, so the diff can never false-flag on a hallucinated
|
|
19
16
|
* requirement. The grounded list is appended HOST-SIDE to `.pi-tasks/launch-contract.md`
|
|
20
|
-
*
|
|
17
|
+
* — the extraction child runs `--no-tools` and so has no write tool at all. Both halves
|
|
18
|
+
* of `discardTreeEdits` skip that directory (`checkout -- . :(exclude).pi-tasks`, then
|
|
19
|
+
* `clean -fd -e .pi-tasks`), and the git-state guard excludes it from the tree it
|
|
20
|
+
* hashes, so the file outlives a discarded pass.
|
|
21
21
|
*
|
|
22
|
-
* At run end the final gate reads the list, reads the manifest's
|
|
22
|
+
* At run end the final gate reads the list, reads the shipped manifest's script names
|
|
23
|
+
* (`readLaunchManifest`: package.json `scripts`, else a Makefile's targets), and FAILs
|
|
23
24
|
* naming any declared script the manifest is missing. FP-safe by construction: an
|
|
24
25
|
* empty/ungrounded list (a design that never backticks a script name) yields no check.
|
|
25
26
|
*/
|
|
@@ -93,22 +94,20 @@ export function keepGroundedScripts(names, sourceDoc) {
|
|
|
93
94
|
return kept;
|
|
94
95
|
}
|
|
95
96
|
/**
|
|
96
|
-
* DETERMINISTIC RECALL
|
|
97
|
+
* DETERMINISTIC RECALL: enumerate every backticked, script-name-shaped
|
|
97
98
|
* token in a paragraph that mentions the word "script", as extraction CANDIDATES.
|
|
98
99
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* enumerates candidates and hands them to the child as an explicit checklist; the
|
|
105
|
-
* model's job flips from recall (weak) to per-candidate classification (strong).
|
|
100
|
+
* Grounding can only DROP a candidate, never add one, so without this the recall of a
|
|
101
|
+
* script declared far from the design's summary list is entirely the model's. This
|
|
102
|
+
* makes recall mechanical: the host enumerates the candidates and hands them to the
|
|
103
|
+
* child as an explicit checklist, so the model's job flips from recall (weak) to
|
|
104
|
+
* per-candidate classification (strong).
|
|
106
105
|
*
|
|
107
106
|
* The paragraph gate (`\bscripts?\b`, word-bounded so "TypeScript"/"JavaScript"
|
|
108
107
|
* don't match) is a grounded-context filter, not a tuned knob: a design declares a
|
|
109
|
-
* script by calling it one. It keeps package-name paragraphs
|
|
110
|
-
*
|
|
111
|
-
*
|
|
108
|
+
* script by calling it one. It keeps package-name paragraphs out of the checklist so
|
|
109
|
+
* a weak model isn't invited to keep junk the grounding guard would then bless —
|
|
110
|
+
* every package name is backticked somewhere. A design with no
|
|
112
111
|
* such paragraph yields no candidates and the prompt is unchanged.
|
|
113
112
|
*/
|
|
114
113
|
export function enumerateScriptCandidates(sourceDoc) {
|
|
@@ -153,13 +152,12 @@ export async function appendDeclaredScripts(cwd, names) {
|
|
|
153
152
|
*/
|
|
154
153
|
const BOOT_CLASS_RE = /^(?:dev|start|serve|preview|watch)(?:[:_-].*)?$/i;
|
|
155
154
|
/**
|
|
156
|
-
* The declared scripts the final gate must EXECUTE as one-shot commands
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
* existence is not launchability.
|
|
155
|
+
* The declared scripts the final gate must EXECUTE as one-shot commands: everything
|
|
156
|
+
* the launch contract declares that is neither boot-class (the boot check exercises
|
|
157
|
+
* those) nor already covered by the gate's integration commands (`covered`,
|
|
158
|
+
* case-insensitive — the test/build-shaped scripts that ran). Checking only that a
|
|
159
|
+
* script is DECLARED says nothing about whether running it works; existence is not
|
|
160
|
+
* launchability.
|
|
163
161
|
*/
|
|
164
162
|
export function runnableDeclaredScripts(declared, covered) {
|
|
165
163
|
const have = new Set(covered.map(s => s.toLowerCase()));
|
|
@@ -189,9 +187,9 @@ export function missingDeclaredScripts(declared, manifestScripts) {
|
|
|
189
187
|
* (keepGroundedScripts), so a hallucinated script cannot reach the diff.
|
|
190
188
|
*
|
|
191
189
|
* `candidates` is enumerateScriptCandidates' mechanical checklist. It exists so the
|
|
192
|
-
* model cannot MISS a declared script buried far from the design's summary list
|
|
193
|
-
*
|
|
194
|
-
*
|
|
190
|
+
* model cannot MISS a declared script buried far from the design's summary list; the
|
|
191
|
+
* model still classifies each candidate against the design, and the host grounding
|
|
192
|
+
* still applies. Empty ⇒ the prompt is unchanged.
|
|
195
193
|
*/
|
|
196
194
|
export const LAUNCH_EXTRACT_PROMPT = (feature, candidates = []) => [
|
|
197
195
|
'You are recording the PACKAGE/BUILD SCRIPTS the design below says the finished',
|
|
@@ -31,12 +31,16 @@ export declare function makeTargets(src: string): string[];
|
|
|
31
31
|
export declare function readLaunchManifest(cwd: string): LaunchManifest;
|
|
32
32
|
/**
|
|
33
33
|
* The one line an INERT contract leaves behind. It rides in the gate's UNOBSERVED
|
|
34
|
-
* channel rather than in `warnings` for
|
|
34
|
+
* channel rather than in `warnings` for one reason: a check that
|
|
35
35
|
* silently did nothing must not read later as a check that passed.
|
|
36
36
|
*/
|
|
37
37
|
export declare function inertLaunchContractNote(declared: string[], manifest: LaunchManifest): string;
|
|
38
38
|
/** The `scripts` map of this tree's package.json, or `{}` when there isn't one.
|
|
39
39
|
* Shared by the gate and the boot probe — both ask the same manifest question. */
|
|
40
40
|
export declare function packageScripts(cwd: string): Record<string, string>;
|
|
41
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Does this tree's Makefile declare `target`? Reads the literal name `Makefile`
|
|
43
|
+
* only — unlike {@link readLaunchManifest}, this one does not walk make's lookup
|
|
44
|
+
* order, so a `GNUmakefile`-only tree answers false.
|
|
45
|
+
*/
|
|
42
46
|
export declare function makeHasTarget(cwd: string, target: string): boolean;
|
|
@@ -1,54 +1,50 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* launch-manifest — WHICH manifest the launch-contract diff is entitled to diff
|
|
3
|
-
* against, and whether there is one at all
|
|
3
|
+
* against, and whether there is one at all.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* design does. The diff end hardcoded the ecosystem anyway:
|
|
5
|
+
* WHY THE DIFF NEEDS ITS OWN RESOLVER. The extraction end of the launch contract
|
|
6
|
+
* has no ecosystem test anywhere in it: `enumerateScriptCandidates` scrapes
|
|
7
|
+
* backticked, script-name-shaped tokens out of any design paragraph that says
|
|
8
|
+
* "script", and `keepGroundedScripts` can only DROP a candidate. A Makefile design
|
|
9
|
+
* saying *"the Makefile must expose `build`, `test`, `migrate`"* therefore records
|
|
10
|
+
* exactly the same artifact an npm design does.
|
|
12
11
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* That text seeds the autofix child's prompt (final-gate.ts's FinalGateOutcome.reason),
|
|
20
|
-
* so the most likely repair on a CMake project was to write a package.json.
|
|
21
|
-
*
|
|
22
|
-
* IAR1 is how close this got: `plan-debug.log:10` records "launch-contract
|
|
23
|
-
* extraction: 0 grounded script(s) kept from 3 emitted" — a non-npm project that
|
|
24
|
-
* reached extraction and emitted three candidates, saved only by its design not
|
|
25
|
-
* backticking them in a "script" paragraph.
|
|
12
|
+
* The diff cannot then reach for `packageScripts` alone. Its catch returns `{}`, so
|
|
13
|
+
* "this project has no package.json" is indistinguishable from "its package.json
|
|
14
|
+
* declares no scripts", and every declared script reads as missing — in wording that
|
|
15
|
+
* NAMES a file the project was never meant to have. `tally.fail` text becomes the
|
|
16
|
+
* gate's `reason`, which `buildFinalFixPrompt` hands to the autofix child, so on a
|
|
17
|
+
* non-npm tree the repair that text invites is to write a package.json.
|
|
26
18
|
*
|
|
27
19
|
* THE RULE, and it is deliberately two ecosystems wide, not three:
|
|
28
20
|
* • package.json present and parseable ⇒ diff against its `scripts` keys, exactly
|
|
29
|
-
* as before (byte-identical failure text on every npm tree —
|
|
21
|
+
* as before (byte-identical failure text on every npm tree — a missing
|
|
30
22
|
* `build`/`seed` is a TRUE positive and must keep failing).
|
|
31
|
-
* • no package.json but a Makefile ⇒ diff against its TARGETS.
|
|
32
|
-
* already in final-gate.ts (`makeHasTarget`); the diff simply never called it.
|
|
23
|
+
* • no package.json but a Makefile ⇒ diff against its TARGETS.
|
|
33
24
|
* • neither ⇒ the check is INERT. No failure, and a note saying the contract was
|
|
34
25
|
* recorded but is not checkable here, so the silence is not read later as a pass
|
|
35
26
|
* (the repo-health-check / env-template-closure discipline: ENOENT = pass, and a
|
|
36
27
|
* check must never invent a file the project chose not to have).
|
|
37
28
|
*
|
|
38
|
-
* cargo/poetry/gradle are NOT here on purpose
|
|
39
|
-
*
|
|
40
|
-
* that
|
|
29
|
+
* cargo/poetry/gradle are NOT here on purpose: nothing in this repo knows how to
|
|
30
|
+
* enumerate their entrypoints, and a third resolver written without one would be a
|
|
31
|
+
* guess that can only produce false FAILs.
|
|
41
32
|
*/
|
|
42
33
|
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
43
34
|
import * as path from 'node:path';
|
|
44
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* GNU make's own lookup order, and nothing beyond it — this is one ecosystem.
|
|
37
|
+
* Confirmed against `make` itself: with all three files present in one directory it
|
|
38
|
+
* runs GNUmakefile; with only `makefile` and `Makefile`, it runs `makefile`.
|
|
39
|
+
*/
|
|
45
40
|
const MAKEFILE_NAMES = ['GNUmakefile', 'makefile', 'Makefile'];
|
|
46
41
|
/** A target we are willing to name in a failure: an ordinary word-shaped target. */
|
|
47
42
|
const TARGET_NAME_RE = /^[a-z0-9][a-z0-9._-]{0,39}$/i;
|
|
48
43
|
/**
|
|
49
44
|
* A variable assignment, in every form make accepts (`=`, `:=`, `::=`, `?=`, `+=`,
|
|
50
45
|
* `!=`, with an optional `override`/`export`). Matched BEFORE the target rule
|
|
51
|
-
* because `FLAGS ::= -O2` otherwise reads as a target named `FLAGS
|
|
46
|
+
* because `FLAGS ::= -O2` otherwise reads as a target named `FLAGS` — make itself
|
|
47
|
+
* reports that line as a variable, not a rule.
|
|
52
48
|
*/
|
|
53
49
|
const ASSIGN_RE = /^(?:override\s+|export\s+)?[A-Za-z_][A-Za-z0-9_.]*\s*(?:::|:|\?|\+|!)?=/;
|
|
54
50
|
/**
|
|
@@ -87,9 +83,10 @@ export function makeTargets(src) {
|
|
|
87
83
|
}
|
|
88
84
|
/**
|
|
89
85
|
* The makefiles that really exist in `cwd`, in GNU make's lookup order, named as
|
|
90
|
-
* the DIRECTORY spells them.
|
|
91
|
-
*
|
|
92
|
-
*
|
|
86
|
+
* the DIRECTORY spells them. The invariant is that `manifest.file` is always a name
|
|
87
|
+
* `readdirSync(cwd)` contains, so a failure can never name a file the project does
|
|
88
|
+
* not have. An `existsSync` probe per candidate name cannot promise that, because it
|
|
89
|
+
* answers about a name we chose rather than a name on disk.
|
|
93
90
|
*/
|
|
94
91
|
function makefilesOnDisk(cwd) {
|
|
95
92
|
let entries;
|
|
@@ -141,7 +138,7 @@ export function readLaunchManifest(cwd) {
|
|
|
141
138
|
}
|
|
142
139
|
/**
|
|
143
140
|
* The one line an INERT contract leaves behind. It rides in the gate's UNOBSERVED
|
|
144
|
-
* channel rather than in `warnings` for
|
|
141
|
+
* channel rather than in `warnings` for one reason: a check that
|
|
145
142
|
* silently did nothing must not read later as a check that passed.
|
|
146
143
|
*/
|
|
147
144
|
export function inertLaunchContractNote(declared, manifest) {
|
|
@@ -160,7 +157,11 @@ export function packageScripts(cwd) {
|
|
|
160
157
|
return {};
|
|
161
158
|
}
|
|
162
159
|
}
|
|
163
|
-
/**
|
|
160
|
+
/**
|
|
161
|
+
* Does this tree's Makefile declare `target`? Reads the literal name `Makefile`
|
|
162
|
+
* only — unlike {@link readLaunchManifest}, this one does not walk make's lookup
|
|
163
|
+
* order, so a `GNUmakefile`-only tree answers false.
|
|
164
|
+
*/
|
|
164
165
|
export function makeHasTarget(cwd, target) {
|
|
165
166
|
try {
|
|
166
167
|
const mk = readFileSync(path.join(cwd, 'Makefile'), 'utf8');
|
package/dist/task/ledger.js
CHANGED
|
@@ -3,24 +3,26 @@
|
|
|
3
3
|
* `.pi-tasks/` (contracts, launch-contract, env-notes, accept-debt, repair-queue,
|
|
4
4
|
* requirements, requirements-owned).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
6
|
+
* The ritual is seven steps: read the file (ANY error → ''), parse it into records,
|
|
7
|
+
* key the records, drop an incoming item whose key is already present, cap to the
|
|
8
|
+
* newest MAX (oldest dropped), mkdir the tasks dir, write the whole file back
|
|
9
|
+
* (`lines.join('\n') + '\n'`, plain `writeFile`, NOT atomic). Every fault is
|
|
10
|
+
* swallowed — a ledger is a sharpener or an auditing aid, never a blocker of the
|
|
11
|
+
* phase or gate that calls it.
|
|
12
|
+
*
|
|
13
|
+
* What varies per site is the DATA SHAPE (file name, cap, key, line format, parser)
|
|
14
|
+
* and exactly one RULE — what an append does when it adds nothing new (see
|
|
15
|
+
* `onNoop`). Everything else here is the ritual, so a module that keeps a ledger is
|
|
16
|
+
* an ADAPTER: it declares its ledger and calls read/append/write.
|
|
16
17
|
*
|
|
17
18
|
* Contract details a caller can rely on:
|
|
18
19
|
* • `readRaw` is the trimmed file text ('' when absent or unreadable). Prompt-block
|
|
19
20
|
* builders take this string.
|
|
20
|
-
* • `read` is `parse(readRaw)`; every parser skips blank lines and lines
|
|
21
|
-
* read, so a corrupt line is dropped, never thrown on.
|
|
22
|
-
* • `append` with an empty batch is a no-op
|
|
23
|
-
* the first item with a key wins; a key already stored wins over
|
|
21
|
+
* • `read` is `parse(readRaw)`; every adapter's parser skips blank lines and lines
|
|
22
|
+
* it cannot read, so a corrupt line is dropped, never thrown on.
|
|
23
|
+
* • `append` with an empty batch is a no-op — it does not even create `.pi-tasks/`.
|
|
24
|
+
* Within a batch the first item with a key wins; a key already stored wins over
|
|
25
|
+
* the batch.
|
|
24
26
|
* • `write` overwrites with exactly these records; an empty list writes an empty
|
|
25
27
|
* file (this is how a drained queue and a fully-resolved debt ledger look).
|
|
26
28
|
* • Neither `append` nor `write` ever throws.
|