@tea-agent/loop-agent 0.44.0-next.1 → 0.44.0-next.10
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/CHANGELOG.md +379 -416
- package/dist/application/evaluation/budget.js +21 -0
- package/dist/application/evaluation/corpus-hash.js +10 -15
- package/dist/application/evaluation/corpus.js +2 -1
- package/dist/application/evaluation/frontend-browser-acceptance.js +77 -0
- package/dist/application/evaluation/frontend-corpus-browser-acceptance.js +175 -0
- package/dist/application/evaluation/frontend-gateway-evidence.js +226 -0
- package/dist/application/evaluation/frontend-pair-registration.js +143 -0
- package/dist/application/evaluation/frontend-paired-summary.js +150 -0
- package/dist/application/evaluation/frontend-run-observation.js +144 -0
- package/dist/application/evaluation/frontend-shared-evidence.js +105 -0
- package/dist/application/evaluation/types.js +45 -12
- package/dist/application/task-lifecycle/observe.js +26 -1
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +11 -0
- package/dist/cli/program.js +4 -0
- package/dist/commands/task-advance.js +3 -5
- package/dist/commands/task-source-prepare.js +13 -1
- package/dist/executors/dag-pi/guards.js +4 -0
- package/dist/executors/dag-pi/model-config.js +30 -0
- package/dist/executors/dag-pi/plan/fact-adoption.js +55 -0
- package/dist/{workflows/dag/frontend-plan-completeness.js → executors/dag-pi/plan/facts.js} +22 -28
- package/dist/executors/dag-pi/plan/finalize-tools.js +259 -0
- package/dist/executors/dag-pi/plan/ledger-contract.js +55 -0
- package/dist/executors/dag-pi/plan/record-tools.js +861 -0
- package/dist/executors/dag-pi/plan/schema.js +129 -0
- package/dist/executors/dag-pi/plan/session.js +1 -0
- package/dist/executors/dag-pi/plan/tool-helpers.js +16 -0
- package/dist/executors/dag-pi/tools/contract-tools.js +515 -0
- package/dist/executors/dag-pi/tools/design-terminal-tools.js +159 -0
- package/dist/executors/dag-pi/tools/plan-decision-tools.js +529 -0
- package/dist/executors/dag-pi/tools/review-terminal-tools.js +159 -0
- package/dist/executors/dag-pi/tools/scout-evidence-tools.js +270 -0
- package/dist/executors/dag-pi-executor.js +398 -3384
- package/dist/executors/pi-executor.js +6 -1
- package/dist/executors/pi-sdk-executor.js +112 -19
- package/dist/executors/shell-executor.js +88 -12
- package/dist/executors/shell-presets.js +1 -1
- package/dist/executors/shell-write-guard.js +26 -3
- package/dist/infrastructure/console/operation-store.js +48 -14
- package/dist/infrastructure/evaluation/corpus-store.js +37 -12
- package/dist/shared/file-identity.js +23 -0
- package/dist/shared/git-workspace-status.js +482 -0
- package/dist/shared/operator/capabilities.js +10 -5
- package/dist/shared/path-safety.js +2 -2
- package/dist/shared/wizard-local-telemetry.js +51 -0
- package/dist/task/config-types.js +22 -8
- package/dist/task/contract/project.js +13 -0
- package/dist/task/contract/schema.js +2 -7
- package/dist/task/frontend-preflight.js +1 -1
- package/dist/task/source-prepare/parse-intent.js +124 -5
- package/dist/task/source-prepare/prepare.js +6 -1
- package/dist/task/source-prepare/semantic-intake.js +18 -3
- package/dist/task/source-prepare/source-execution.js +65 -0
- package/dist/task/source-prepare/source-fidelity-pi.js +22 -9
- package/dist/task/source-prepare/source-provider-budget.js +290 -0
- package/dist/worker/console/chat/assistant-content.js +5 -34
- package/dist/worker/console/chat/chat-event-store.js +62 -10
- package/dist/worker/console/chat/context-insights.js +723 -0
- package/dist/worker/console/chat/conversation-nodes.js +383 -0
- package/dist/worker/console/chat/db-connections.js +854 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +1 -1
- package/dist/worker/console/chat/pi-runtime/custom-tools/sql-tools.js +655 -0
- package/dist/worker/console/chat/pi-runtime.js +445 -36
- package/dist/worker/console/chat/provider-error.js +0 -12
- package/dist/worker/console/chat/repo-browser.js +52 -4
- package/dist/worker/console/chat/routes.js +577 -72
- package/dist/worker/console/chat/sdd-data-alignment.js +8 -31
- package/dist/worker/console/chat/session-store.js +147 -19
- package/dist/worker/console/chat/shortcuts.js +7 -0
- package/dist/worker/console/chat/timeline-message-order.js +22 -0
- package/dist/worker/console/chat/tools.js +34 -0
- package/dist/worker/console/chat/turn-process.js +237 -66
- package/dist/worker/console/chat/user-turn-outline.js +19 -0
- package/dist/worker/console/console-update-runtime.js +2 -2
- package/dist/worker/console/dag-confirmation.js +3 -0
- package/dist/worker/console/dag-execution-receipt.js +3 -0
- package/dist/worker/console/operator-actions.js +32 -3
- package/dist/worker/console/operator-user-error.js +28 -1
- package/dist/worker/console/pi-readiness.js +4 -4
- package/dist/worker/console/prd-intake-bridge.js +5 -12
- package/dist/worker/console/recovery-cta.js +14 -14
- package/dist/worker/console/server.js +5 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-8-j6y-sd.js → abnfDiagram-N423BO3Z-r1NAPU_5.js} +1 -1
- package/dist/worker/console/static/assets/{arc-eoQiMvuk.js → arc-dT5T4sVL.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-C4A3uMcI.js → architectureDiagram-T3A2C74G-CP_cOq46.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-D4zD2F-Q.js → blockDiagram-VBNYF7ZC-sToEZxEf.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-j1RkJziL.js → c4Diagram-5PPSVZJV-DSxwwi2m.js} +1 -1
- package/dist/worker/console/static/assets/channel-CyBY_yGk.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-YBHmhik1.js → chunk-2GRJ4B5K-B9fh0IkF.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-COfWyo9P.js → chunk-2Q5K7J3B-CAUNl-A6.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-I99OUkHY.js → chunk-5RXB4S5H-BomeqbNX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-XKxoJNJ4.js → chunk-5VM5RSS4-BNAuTOLE.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DLT_cYx1.js → chunk-6Q2QTUOP-DfzjRD5y.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CxcKZ9mV.js → chunk-GF5L2VYU-C3uE-yc2.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-V1EqXdjY.js → chunk-JWPE2WC7-C3sQMMYr.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DebTtdFp.js → chunk-KBJHAD2P-D_AtEYQL.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-B-ivNRDf.js → chunk-RYQCIY6F-DW4TwhKv.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DC_Ds11b.js → chunk-XXDRQBXY-CTQDmJcp.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-D5lN4E_E.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-D5lN4E_E.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-sWEqKwIb.js → cose-bilkent-JH36ORCC-iMqPuBsL.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BXa_dcu4.js → cynefin-VYW2F7L2-DktIuDWs.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-C-Mle84F.js → cynefinDiagram-MW4NZA55-BgVnjyEs.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-CXPDBITe.js → dagre-VZM6K2ZE-CR25E4bu.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-CC-WJQfa.js → diagram-7IWD3JNH-CPM2h5HY.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-CDAV5Vs4.js → diagram-B4RE2ZJO-DqF0x2g1.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-CmFiAcNz.js → diagram-LBJQPF4R-G8BYp2eb.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DPBZHuyn.js → diagram-Q27KOJAE-BbC4kT_D.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-jUlm_Ds3.js → diagram-UB23O5K3-CKZwZ-G5.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DWhQ3mfY.js → ebnfDiagram-BXEA7PRR-kJDmheia.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-Tr2gMqet.js → erDiagram-JOGREHBK-DFTVHyxB.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-DJjVQHPA.js → flowDiagram-UKHOOZJN-BqdN5_os.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-D74dQ4u0.js → ganttDiagram-PKOTCBZU-SYDjVakh.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-DwW0tZ0X.js → gitGraphDiagram-DS77QQ5N-Bf8bNpGA.js} +1 -1
- package/dist/worker/console/static/assets/index-B28Onmfy.css +1 -0
- package/dist/worker/console/static/assets/index-CTMZsDmh.js +486 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-ILCbxJyb.js → infoDiagram-6WML65LV-DIeAmJ45.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-DeuWBQ89.js → ishikawaDiagram-WSZJBQD7-oikqUAlo.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CF5ih8Fk.js → journeyDiagram-NVQOT4AX-mKEF_xYT.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-C7yOSuRO.js → kanban-definition-27J2QSJJ-BdWJHPnN.js} +1 -1
- package/dist/worker/console/static/assets/{linear-BDZ9riWi.js → linear-DGRlieMH.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-7pKqYtpZ.js → mermaid.core-4P9yPC9c.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-LeJDybSU.js → mindmap-definition-FAOFIHXS-5PTSkos6.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BJvT3pMD.js → pegDiagram-VL7TDLO6-DONIFpG5.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-_rGqpMan.js → pieDiagram-7S7Q4E2Y-D_Z4S70M.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-DPcSv5aA.js → quadrantDiagram-CIZ2JOQS-CAsjh8iY.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Drxx4hkJ.js → railroadDiagram-AXF67PYL-Cx4Dd6ac.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BCTUdU4z.js → requirementDiagram-LRYGKXZP-cQb7mwyH.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-B6wzbZmB.js → sankeyDiagram-W5VNT64P-Cd-DhUdf.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BGt8d3QQ.js → sequenceDiagram-SI44F4Z6-AlKYRgIk.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-7nlhJKo7.js → sizeCapture-X5ZJPWSS-CUy_ET4e.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Cv2stqMA.js → stateDiagram-OKZ733FA-CTuVe6Sa.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BsWhs8O7.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-qDAo4Yc1.js → swimlanes-SLNWSIFB-ChFLJb-v.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CJcioYGH.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CKbDNKTr.js → timeline-definition-Z64GVDOM-DZZeiAPr.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DI-9EHic.js → vennDiagram-T6HMQDX7-t4O91cZU.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-BrzzRDpX.js → wardleyDiagram-T6FBY63Y-CV5qGHZu.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-BclH5hGh.js → xychartDiagram-ELKLHX3M-DyXbytUI.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/console-types.js +9 -1
- package/dist/worker/console/static-src/operator-chat/animation-frame-batcher.js +38 -0
- package/dist/worker/console/static-src/operator-chat/chat-link.js +20 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +186 -5
- package/dist/worker/console/static-src/operator-chat/chat-stream-continuity.js +101 -0
- package/dist/worker/console/static-src/operator-chat/compaction-message.js +18 -3
- package/dist/worker/console/static-src/operator-chat/context-insights-store.js +64 -0
- package/dist/worker/console/static-src/operator-chat/details-rail-surfaces.js +98 -0
- package/dist/worker/console/static-src/operator-chat/file-palette-nav.js +81 -0
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +17 -3
- package/dist/worker/console/static-src/operator-chat/process-label.js +27 -5
- package/dist/worker/console/static-src/operator-chat/tools-catalog.js +16 -7
- package/dist/worker/console/static-src/operator-chat/transcript-mode.js +21 -0
- package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +4 -1
- package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +13 -5
- package/dist/worker/console/static-src/operator-chat/turn-state-projection.js +166 -0
- package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +56 -2
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +211 -40
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +124 -27
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +88 -20
- package/dist/worker/console/static-src/operator-chat/useComposer.js +80 -6
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +13 -3
- package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +36 -17
- package/dist/worker/console/static-src/operator-chat/useRuntimeSnapshot.js +18 -0
- package/dist/worker/console/static-src/operator-chat/useWorkspaceBrowserGate.js +4 -0
- package/dist/worker/console/static-src/shell/console-update-reload.js +1 -1
- package/dist/worker/console/workspace-context.js +2 -0
- package/dist/worker/console/workspace-initialization.js +3 -3
- package/dist/worker/observability/read-model.js +23 -2
- package/dist/worker/observe/node-context-insights.js +479 -0
- package/dist/worker/observe/static/console-theme.css +174 -0
- package/dist/worker/observe/static/console-theme.js +36 -0
- package/dist/worker/observe/static/operator-chrome.css +85 -0
- package/dist/worker/observe/static/operator-chrome.js +51 -0
- package/dist/worker/scheduler/scheduled-goal-dispatch.js +3 -2
- package/dist/worker/scheduler/scheduled-goal-evidence.js +66 -3
- package/dist/worker/scheduler/scheduled-goal-store.js +10 -0
- package/dist/workflows/dag/budget-enforcement.js +31 -2
- package/dist/workflows/dag/frontend-closeout.js +3 -1
- package/dist/workflows/dag/frontend-contract-facts.js +11 -8
- package/dist/workflows/dag/frontend-design-policy.js +6 -6
- package/dist/workflows/dag/frontend-durable-tools.js +90 -70
- package/dist/workflows/dag/frontend-implementation-contract.js +146 -57
- package/dist/workflows/dag/frontend-plan-canary.js +66 -16
- package/dist/workflows/dag/frontend-plan-decision-contract.js +13 -21
- package/dist/workflows/dag/frontend-plan-progress.js +92 -0
- package/dist/workflows/dag/frontend-recovery-plan.js +10 -5
- package/dist/workflows/dag/frontend-recovery-run.js +51 -46
- package/dist/workflows/dag/frontend-repair-assertions.js +36 -0
- package/dist/workflows/dag/frontend-review-context.js +29 -1
- package/dist/workflows/dag/frontend-review-scopes.js +92 -2
- package/dist/workflows/dag/frontend-risk.js +8 -3
- package/dist/workflows/dag/frontend-root-observation.js +261 -0
- package/dist/workflows/dag/frontend-session-budget.js +52 -39
- package/dist/workflows/dag/frontend-session-context.js +10 -0
- package/dist/workflows/dag/frontend-test-execution-evidence.js +206 -48
- package/dist/workflows/dag/frontend-typed-event-store.js +11 -1
- package/dist/workflows/dag/frontend-verification-trace.js +6 -0
- package/dist/workflows/dag/frontend-writer-admission.js +3 -1
- package/dist/workflows/dag/init-hybrid.js +108 -37
- package/dist/workflows/dag/node-execution.js +11 -11
- package/dist/workflows/dag/output-protocol.js +1 -0
- package/dist/workflows/dag/rerun-feedback.js +35 -4
- package/dist/workflows/dag/rerun-task.js +62 -66
- package/dist/workflows/dag/runner.js +58 -12
- package/dist/workflows/dag/types.js +15 -8
- package/dist/workflows/loop/benchmark.js +11 -8
- package/docs/README.md +1 -1
- package/docs/architecture/runtime-boundaries.md +1 -1
- package/docs/governance/harness-methodology-verification.md +11 -0
- package/docs/templates/backend-test-dag.json +5 -4
- package/docs/templates/frontend-implementation-contract.schema.json +31 -11
- package/package.json +6 -4
- package/skills/frontend-design-review/SKILL.md +8 -11
- package/skills/frontend-design-review/references/review-checklist.md +3 -4
- package/skills/frontend-review/SKILL.md +5 -1
- package/skills/loop-agent/references/command-reference.md +8 -0
- package/skills/loop-agent/references/hybrid-dag.md +1 -1
- package/dist/worker/console/static/assets/channel-ChE7y-cx.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C01TCf2X.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C01TCf2X.js +0 -1
- package/dist/worker/console/static/assets/index-BWkIfcrK.css +0 -1
- package/dist/worker/console/static/assets/index-Cdkvw_H6.js +0 -469
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DC7V5vcq.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bwy4QUTO.js +0 -8
|
@@ -6,6 +6,26 @@ import { buildFrontendSplitAggregateCloseout, computeFrontendSplitDigest, finali
|
|
|
6
6
|
import { frontendCloseoutFactsSchema, frontendTestHandoffSchema, } from "../../workflows/dag/frontend-closeout.js";
|
|
7
7
|
import { listJsonFiles, readJsonIfExists, sha256Json, writeSecureJson, } from "./app-data.js";
|
|
8
8
|
export const TERMINAL_OPERATION_STATES = new Set(["succeeded", "failed", "timed-out", "restarting"]);
|
|
9
|
+
/**
|
|
10
|
+
* Operation states that hold an admission slot. needs-reconcile requires
|
|
11
|
+
* inspection but does not itself prove a live operation; callers still check
|
|
12
|
+
* DAG/Worker/chat activity separately. restarting is the terminal receipt of
|
|
13
|
+
* a successful Console handoff, retained across boots, not a live slot.
|
|
14
|
+
* A needs-reconcile record remains visible as a non-business outcome, but
|
|
15
|
+
* must never strand later mutations after its runtime is gone.
|
|
16
|
+
*/
|
|
17
|
+
export const OCCUPIED_OPERATION_STATES = new Set(["queued", "starting", "running"]);
|
|
18
|
+
/** True when the state can still make progress and therefore holds the slot. */
|
|
19
|
+
export function isOperationOccupied(state) {
|
|
20
|
+
return OCCUPIED_OPERATION_STATES.has(state);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* True when no further state transition will ever occur: a business terminal
|
|
24
|
+
* (succeeded/failed/timed-out/restarting) or a stranded needs-reconcile.
|
|
25
|
+
*/
|
|
26
|
+
export function isOperationSettled(state) {
|
|
27
|
+
return TERMINAL_OPERATION_STATES.has(state) || state === "needs-reconcile";
|
|
28
|
+
}
|
|
9
29
|
function operationFile(appData, operationId) {
|
|
10
30
|
return path.join(appData.operations, `${operationId}.json`);
|
|
11
31
|
}
|
|
@@ -359,14 +379,11 @@ export class OperationStore {
|
|
|
359
379
|
for (const op of await this.list()) {
|
|
360
380
|
if (TERMINAL_OPERATION_STATES.has(op.state))
|
|
361
381
|
continue;
|
|
362
|
-
// A consoleUpdateAndInit
|
|
363
|
-
//
|
|
364
|
-
//
|
|
365
|
-
// handoff target. Mark it succeeded instead of surfacing the
|
|
366
|
-
// generic needs-reconcile failure copy to the operator.
|
|
382
|
+
// A consoleUpdateAndInit that proved its handoff before the process
|
|
383
|
+
// died must not be reported as a stranded failure: the booting
|
|
384
|
+
// process IS the handoff target, so the update actually succeeded.
|
|
367
385
|
if (op.action === "consoleUpdateAndInit" &&
|
|
368
|
-
op
|
|
369
|
-
isProvenConsoleUpdateHandoff(op.result)) {
|
|
386
|
+
isProvenConsoleUpdateHandoff(op)) {
|
|
370
387
|
changed.push(await this.update(op.operationId, {
|
|
371
388
|
state: "succeeded",
|
|
372
389
|
errorCode: undefined,
|
|
@@ -398,17 +415,34 @@ export function isTerminalOperationState(state) {
|
|
|
398
415
|
return TERMINAL_OPERATION_STATES.has(state);
|
|
399
416
|
}
|
|
400
417
|
/**
|
|
401
|
-
* True when a consoleUpdateAndInit
|
|
402
|
-
* (install verified +
|
|
403
|
-
*
|
|
404
|
-
*
|
|
418
|
+
* True when a consoleUpdateAndInit record proves the handoff actually
|
|
419
|
+
* succeeded (install verified + new Console spawned), so boot reconcile can
|
|
420
|
+
* close it as succeeded even though the dying process never wrote its
|
|
421
|
+
* terminal state.
|
|
422
|
+
*
|
|
423
|
+
* The proof reads the maintenance projection rather than only `result.state`.
|
|
424
|
+
* The old check required `result.state === "restarting"`, but the executor
|
|
425
|
+
* writes `state` and `maintenance` together (`console-update-and-init.ts`),
|
|
426
|
+
* so any path that recorded the handoff proof together with a non-restarting
|
|
427
|
+
* `state` — most importantly the `needs-reconcile` record that
|
|
428
|
+
* `acceptConsoleUpdateAndInit` writes when the executor throws *after* a
|
|
429
|
+
* successful handoff — could never satisfy it. Such records were stranded
|
|
430
|
+
* forever: boot reconcile skipped them and they blocked later updates.
|
|
431
|
+
*
|
|
432
|
+
* `handoff.status === "requested"` is only ever set on the success path, and
|
|
433
|
+
* `package.status === "failed"` explicitly disqualifies a record, so this
|
|
434
|
+
* stays fail-closed for genuine failures.
|
|
405
435
|
*/
|
|
406
|
-
function isProvenConsoleUpdateHandoff(
|
|
436
|
+
export function isProvenConsoleUpdateHandoff(operation) {
|
|
437
|
+
if (!operation || operation.action !== "consoleUpdateAndInit")
|
|
438
|
+
return false;
|
|
439
|
+
const result = operation.result;
|
|
407
440
|
if (!result || typeof result !== "object")
|
|
408
441
|
return false;
|
|
409
442
|
const shape = result;
|
|
410
|
-
|
|
411
|
-
|
|
443
|
+
if (shape.maintenance?.handoff?.status !== "requested")
|
|
444
|
+
return false;
|
|
445
|
+
return shape.maintenance?.package?.status !== "failed";
|
|
412
446
|
}
|
|
413
447
|
export function clipPreview(text, max = 4096) {
|
|
414
448
|
if (text.length <= max)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readFileBoundarySafe } from "../../shared/path-safety.js";
|
|
1
2
|
import { access, mkdir, readdir, readFile, rename, rm } from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { mkdtemp } from "node:fs/promises";
|
|
@@ -30,28 +31,27 @@ async function pathExists(filePath) {
|
|
|
30
31
|
function serializeManifest(manifest) {
|
|
31
32
|
return `${JSON.stringify(manifest, null, 2)}\n`;
|
|
32
33
|
}
|
|
34
|
+
function compareArtifactPaths(a, b) {
|
|
35
|
+
return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
|
|
36
|
+
}
|
|
33
37
|
function normalizeTasksForStorage(tasks) {
|
|
34
38
|
return [...tasks]
|
|
35
39
|
.map((task) => ({
|
|
36
40
|
...task,
|
|
37
41
|
taskRef: task.taskRef.replace(/\\/g, "/"),
|
|
38
42
|
seeds: [...task.seeds].sort((a, b) => a - b),
|
|
43
|
+
...("category" in task ? {
|
|
44
|
+
requirements: [...task.requirements].sort(compareArtifactPaths),
|
|
45
|
+
initialFiles: [...task.initialFiles].sort(compareArtifactPaths),
|
|
46
|
+
oracleFiles: [...task.oracleFiles].sort(compareArtifactPaths),
|
|
47
|
+
} : {}),
|
|
39
48
|
}))
|
|
40
49
|
.sort((a, b) => a.taskRef < b.taskRef ? -1 : a.taskRef > b.taskRef ? 1 : 0);
|
|
41
50
|
}
|
|
42
51
|
export async function materializeCorpusManifest(raw) {
|
|
43
52
|
const input = corpusManifestInputSchema.parse(raw);
|
|
44
53
|
const tasks = normalizeTasksForStorage(input.tasks);
|
|
45
|
-
const
|
|
46
|
-
schemaVersion: 1,
|
|
47
|
-
corpusId: input.corpusId,
|
|
48
|
-
createdAt: input.createdAt,
|
|
49
|
-
...(input.description !== undefined
|
|
50
|
-
? { description: input.description }
|
|
51
|
-
: {}),
|
|
52
|
-
tasks,
|
|
53
|
-
};
|
|
54
|
-
const corpusHash = computeCorpusHash(withoutHash);
|
|
54
|
+
const corpusHash = computeCorpusHash(input);
|
|
55
55
|
if (input.corpusHash) {
|
|
56
56
|
const provided = formatContentSha(normalizeContentSha(input.corpusHash));
|
|
57
57
|
if (provided !== corpusHash) {
|
|
@@ -59,10 +59,30 @@ export async function materializeCorpusManifest(raw) {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
return corpusManifestSchema.parse({
|
|
62
|
-
...
|
|
62
|
+
...input,
|
|
63
|
+
tasks,
|
|
63
64
|
corpusHash,
|
|
64
65
|
});
|
|
65
66
|
}
|
|
67
|
+
export async function assertCorpusArtifacts(repoRoot, manifest) {
|
|
68
|
+
if (manifest.schemaVersion !== 2)
|
|
69
|
+
return;
|
|
70
|
+
const snapshots = new Map();
|
|
71
|
+
for (const task of manifest.tasks)
|
|
72
|
+
for (const ref of [...task.requirements, ...task.initialFiles, ...task.oracleFiles]) {
|
|
73
|
+
const bytes = await readFileBoundarySafe({ boundaryRoot: repoRoot,
|
|
74
|
+
targetPath: path.resolve(repoRoot, ref.path), label: "frontend corpus artifact" });
|
|
75
|
+
if (sha256Hex(bytes) !== ref.sha256)
|
|
76
|
+
throw Error(`corpus artifact hash mismatch: ${ref.path}`);
|
|
77
|
+
snapshots.set(ref.path, bytes);
|
|
78
|
+
}
|
|
79
|
+
for (const [file, expected] of snapshots) {
|
|
80
|
+
const actual = await readFileBoundarySafe({ boundaryRoot: repoRoot,
|
|
81
|
+
targetPath: path.resolve(repoRoot, file), label: "frontend corpus artifact recheck" });
|
|
82
|
+
if (!actual.equals(expected))
|
|
83
|
+
throw Error(`corpus artifact changed during collection: ${file}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
66
86
|
async function assertManifestIntegrity(repoRoot, corpusId, rawManifest) {
|
|
67
87
|
const integrityPath = path.join(corpusDir(repoRoot, corpusId), MANIFEST_INTEGRITY_FILE);
|
|
68
88
|
const expected = (await readFile(integrityPath, "utf-8")).trim();
|
|
@@ -98,6 +118,7 @@ export async function readCorpusManifest(repoRoot, corpusId) {
|
|
|
98
118
|
if (recomputed !== stored.corpusHash) {
|
|
99
119
|
throw new Error(`corpusHash mismatch for ${corpusId}: expected ${recomputed}, got ${stored.corpusHash}`);
|
|
100
120
|
}
|
|
121
|
+
await assertCorpusArtifacts(repoRoot, stored);
|
|
101
122
|
return stored;
|
|
102
123
|
}
|
|
103
124
|
export async function listCorpusIds(repoRoot) {
|
|
@@ -117,7 +138,11 @@ export async function listCorpusIds(repoRoot) {
|
|
|
117
138
|
}
|
|
118
139
|
}
|
|
119
140
|
export async function registerCorpusManifest(input) {
|
|
120
|
-
const
|
|
141
|
+
const repoRoot = input.repoRoot;
|
|
142
|
+
const manifest = corpusManifestSchema.parse(input.manifest);
|
|
143
|
+
if (computeCorpusHash(manifest) !== manifest.corpusHash)
|
|
144
|
+
throw Error("corpusHash mismatch");
|
|
145
|
+
await assertCorpusArtifacts(repoRoot, manifest);
|
|
121
146
|
assertCorpusId(manifest.corpusId);
|
|
122
147
|
const manifestPath = corpusManifestPath(repoRoot, manifest.corpusId);
|
|
123
148
|
if (await pathExists(manifestPath)) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare two stat records as the same file identity.
|
|
3
|
+
*
|
|
4
|
+
* POSIX: `dev` and `ino` together identify the inode; both must match.
|
|
5
|
+
*
|
|
6
|
+
* win32: libuv reports `dev` inconsistently across stat APIs — `fstat()`
|
|
7
|
+
* (from an open handle) returns the volume serial number while `lstat()`
|
|
8
|
+
* (from a path) returns 0. A cross-API comparison therefore always fails on
|
|
9
|
+
* Windows even when the path still refers to the same file, breaking every
|
|
10
|
+
* guard that rechecks identity after opening (user-reported on 0.42.1 and
|
|
11
|
+
* 0.43.0, Node 23.x). On win32 the `dev` field is skipped and `ino` plus the
|
|
12
|
+
* caller-side type/link/realpath checks remain the identity boundary.
|
|
13
|
+
*
|
|
14
|
+
* When both stats come from the same API the comparison is exact on every
|
|
15
|
+
* platform; the win32 relaxation only affects cross-API rechecks.
|
|
16
|
+
*/
|
|
17
|
+
export function sameFileIdentity(opened, current, platform = process.platform) {
|
|
18
|
+
if (current.ino !== opened.ino)
|
|
19
|
+
return false;
|
|
20
|
+
if (platform !== "win32" && current.dev !== opened.dev)
|
|
21
|
+
return false;
|
|
22
|
+
return true;
|
|
23
|
+
}
|