@tea-agent/loop-agent 0.39.0-next.3 → 0.39.0-next.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/AGENTS.md +4 -1
- package/CHANGELOG.md +267 -65
- package/README.md +11 -5
- package/bin/loop-agent.js +7 -3
- package/dist/application/dag/generate-task-dag.js +9 -0
- package/dist/application/task-lifecycle/advance.js +4 -0
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +16 -5
- package/dist/cli/program.js +16 -2
- package/dist/cli/update/notifier.js +2 -2
- package/dist/cli.js +2 -1
- package/dist/commands/dag-rerun.js +55 -1
- package/dist/commands/init-model-catalog.js +464 -0
- package/dist/commands/init-upgrade.js +265 -97
- package/dist/commands/init.js +428 -27
- package/dist/commands/inspect-next.js +8 -0
- package/dist/commands/task-advance.js +31 -0
- package/dist/executors/dag-pi-executor.js +118 -14
- package/dist/executors/pi-event-serializer.js +42 -1
- package/dist/executors/pi-executor.js +51 -0
- package/dist/executors/pi-extension-resolver.js +233 -0
- package/dist/executors/pi-playwright-cli-tool.js +8 -1
- package/dist/executors/pi-sdk-executor.js +187 -59
- package/dist/executors/shell-executor.js +533 -29
- package/dist/executors/shell-write-guard.js +7 -0
- package/dist/shared/dag-prompt-override.js +28 -0
- package/dist/shared/operator/capabilities.js +181 -27
- package/dist/shared/update/console-notifier.js +100 -0
- package/dist/{cli → shared}/update/npm-client.js +41 -8
- package/dist/{cli → shared}/update/state.js +41 -13
- package/dist/task/config-types.js +22 -0
- package/dist/task/contract/constants.js +1 -0
- package/dist/task/contract/diff.js +26 -0
- package/dist/task/contract/project.js +5 -0
- package/dist/task/contract/schema.js +6 -1
- package/dist/task/source-prepare/build-draft.js +15 -0
- package/dist/worker/cli.js +31 -1
- package/dist/worker/console/chat/deferred-turn.js +91 -0
- package/dist/worker/console/chat/mcp-inventory.js +221 -0
- package/dist/worker/console/chat/pi-runtime.js +165 -83
- package/dist/worker/console/chat/repo-walk.js +10 -1
- package/dist/worker/console/chat/routes.js +478 -55
- package/dist/worker/console/chat/semantic-activity.js +20 -8
- package/dist/worker/console/chat/session-store.js +146 -2
- package/dist/worker/console/chat/turn-process.js +17 -30
- package/dist/worker/console/harness-pi-model-matrix.js +137 -0
- package/dist/worker/console/operator-actions.js +244 -4
- package/dist/worker/console/operator-user-error.js +19 -0
- package/dist/worker/console/pi-readiness.js +12 -5
- package/dist/worker/console/recovery-cta.js +4 -4
- package/dist/worker/console/recovery-error-copy.js +4 -4
- package/dist/worker/console/routes.js +43 -2
- package/dist/worker/console/security.js +83 -10
- package/dist/worker/console/server.js +42 -6
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-DSvF6RXQ.js → abnfDiagram-N423BO3Z-CiGOV5eG.js} +1 -1
- package/dist/worker/console/static/assets/{arc-DuI4ogtJ.js → arc-Ds9Gyfd8.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DdBbgD4y.js → architectureDiagram-T3A2C74G-C6V6uC98.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-xQC2HELm.js → blockDiagram-VBNYF7ZC-DezF7Ol9.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DPMSgwIZ.js → c4Diagram-5PPSVZJV-BCWk3gCT.js} +1 -1
- package/dist/worker/console/static/assets/channel-DMvu1nmi.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-WTEKTxin.js → chunk-2GRJ4B5K-DbYr-Cxy.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-B6vZ0Pv_.js → chunk-2Q5K7J3B-XSlusW4G.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BrerNAix.js → chunk-5RXB4S5H-BtcKAj9i.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-D_ch2aaI.js → chunk-5VM5RSS4-BF57lhXj.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-VvfacNrq.js → chunk-6Q2QTUOP-DJIlR25o.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-B-uGFIg2.js → chunk-GF5L2VYU-DklNc7dm.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BlysCtod.js → chunk-JWPE2WC7-fZNtEdQZ.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BjAUAfcT.js → chunk-KBJHAD2P-BBgLqV4h.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-BeZnBmb-.js → chunk-RYQCIY6F-Dl9e5n_J.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-Bbfe3UJG.js → chunk-XXDRQBXY-B0JK51NT.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DVzM-02m.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DVzM-02m.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BKJQnYVM.js → cose-bilkent-JH36ORCC-Ch-ajv4O.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-B1wtI3hU.js → cynefin-VYW2F7L2-xn_NxcfB.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-DCF6DBSu.js → cynefinDiagram-MW4NZA55-DRD0fyga.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BJyNGRlP.js → dagre-VZM6K2ZE-COtnKp4B.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-B7j1-VsZ.js → diagram-7IWD3JNH-BQp_CAqG.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BREJ140a.js → diagram-B4RE2ZJO-x0y-vNgq.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-CDPHmHGH.js → diagram-LBJQPF4R-N2ezwL31.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BtZLrez1.js → diagram-Q27KOJAE-CSaxRH6Q.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-mzybu8oU.js → diagram-UB23O5K3-6Ro7Kpbd.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Dk3I2uO6.js → ebnfDiagram-BXEA7PRR-CrIIQEAI.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-BT97u_tQ.js → erDiagram-JOGREHBK-DivKcq8g.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CMOtYzui.js → flowDiagram-UKHOOZJN-BXrfDo8y.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DiNydkuY.js → ganttDiagram-PKOTCBZU-LTTQmMRJ.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Cwt6fLkl.js → gitGraphDiagram-DS77QQ5N-DP3o_5qd.js} +1 -1
- package/dist/worker/console/static/assets/index-C2jmYBfu.js +404 -0
- package/dist/worker/console/static/assets/index-C8rOIAJr.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-AsGIGKKB.js → infoDiagram-6WML65LV-wVfSY1WH.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BL8ITZh3.js → ishikawaDiagram-WSZJBQD7-BRKfFL0I.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-VPKAUX8M.js → journeyDiagram-NVQOT4AX-DEml3jLb.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-BL56hfGp.js → kanban-definition-27J2QSJJ-DTzBmOqN.js} +1 -1
- package/dist/worker/console/static/assets/{linear-BmSG3nIZ.js → linear-Cpy1d873.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-DWGK9kwP.js → mermaid.core-C1cSavOy.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS--vvKLjo0.js → mindmap-definition-FAOFIHXS-BEBSKvYM.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-B41mxb2-.js → pegDiagram-VL7TDLO6-BrLs4Oac.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-DTlu77sw.js → pieDiagram-7S7Q4E2Y-B47AZcLa.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-Bk5A7alv.js → quadrantDiagram-CIZ2JOQS-s0dVeYR2.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Csf9jzQy.js → railroadDiagram-AXF67PYL-lW8aJ7Q6.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-CeptoSNx.js → requirementDiagram-LRYGKXZP-BcHJPf6Q.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-A-DLCLer.js → sankeyDiagram-W5VNT64P-DdegpUUf.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-22VbPdOI.js → sequenceDiagram-SI44F4Z6-BxFWqNv8.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DWvAyBC9.js → sizeCapture-X5ZJPWSS-cOdUDPbR.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-qICZ75yT.js → stateDiagram-OKZ733FA-DpxlYl8P.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BwecGAkM.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-xi7lcMyp.js → swimlanes-SLNWSIFB-DQOfurE0.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-D5WW_LbN.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Bu6Nl6O2.js → timeline-definition-Z64GVDOM-CIp3tC6V.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BzMz4Bn9.js → vennDiagram-T6HMQDX7-C-adIPKn.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-CxaJnzc5.js → wardleyDiagram-T6FBY63Y-CiYrar9M.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-5JK-omQK.js → xychartDiagram-ELKLHX3M-WHrdTV0-.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/console-types.js +39 -0
- package/dist/worker/console/static-src/app/useOperatorActions.js +1 -1
- package/dist/worker/console/static-src/app/useRecoveryActions.js +2 -2
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +82 -22
- package/dist/worker/console/static-src/operator-chat/mutation-gate.js +45 -0
- package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +328 -0
- package/dist/worker/console/static-src/operator-chat/resource-diagnostics.js +204 -0
- package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +8 -1
- package/dist/worker/console/static-src/operator-chat/turn-submission.js +42 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +18 -0
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +216 -10
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +50 -22
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +26 -1
- package/dist/worker/observe/node-input.js +74 -3
- package/dist/worker/observe/node-process.js +377 -0
- package/dist/worker/observe/routes.js +36 -3
- package/dist/worker/observe/shell-handler-keys.js +34 -0
- package/dist/worker/observe/static/api.js +66 -0
- package/dist/worker/observe/static/constants.js +8 -1
- package/dist/worker/observe/static/dag-history-labels.js +4 -0
- package/dist/worker/observe/static/format.js +23 -0
- package/dist/worker/observe/static/markdown-render.js +20 -1
- package/dist/worker/observe/static/operator-chrome.js +4 -0
- package/dist/worker/observe/static/state.js +13 -2
- package/dist/worker/observe/static/styles.css +73 -0
- package/dist/worker/observe/static/views/dag-inspector.js +612 -8
- package/dist/worker/observe/static/views/dag.js +8 -1
- package/dist/worker/observe/static/views/session-timeline.js +78 -9
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +827 -53
- package/dist/workflows/dag/backend-test-case-manifest.js +4 -0
- package/dist/workflows/dag/backend-test-execution-contract.js +18 -9
- package/dist/workflows/dag/backend-test-gap-fill.js +205 -0
- package/dist/workflows/dag/backend-test-intake-context.js +32 -0
- package/dist/workflows/dag/backend-test-layout.js +133 -0
- package/dist/workflows/dag/backend-test-markdown-workflow.js +167 -32
- package/dist/workflows/dag/backend-test-module-stem.js +5 -0
- package/dist/workflows/dag/backend-test-pytest-collection.js +368 -33
- package/dist/workflows/dag/backend-test-result-contract.js +1 -1
- package/dist/workflows/dag/backend-test-scenario-param.js +884 -140
- package/dist/workflows/dag/backend-test-scenario-partitions.js +321 -0
- package/dist/workflows/dag/backend-test-writer-completeness.js +100 -56
- package/dist/workflows/dag/contract-output-registry.js +15 -0
- package/dist/workflows/dag/contract-validator-registrations.js +3 -1
- package/dist/workflows/dag/convergence/controller.js +141 -0
- package/dist/workflows/dag/dynamic-runtime/map.js +24 -8
- package/dist/workflows/dag/dynamic-runtime/shared.js +1 -1
- package/dist/workflows/dag/failure-category.js +12 -0
- package/dist/workflows/dag/frontend-implementation-contract.js +493 -2
- package/dist/workflows/dag/frontend-plan-render.js +90 -0
- package/dist/workflows/dag/frontend-prewrite-gate.js +221 -31
- package/dist/workflows/dag/frontend-test-case-quality.js +5 -13
- package/dist/workflows/dag/frontend-test-environment-probe.js +227 -0
- package/dist/workflows/dag/frontend-test-markdown.js +61 -0
- package/dist/workflows/dag/frontend-test-result-contract.js +10 -18
- package/dist/workflows/dag/frontend-test-standard-scenarios.js +68 -0
- package/dist/workflows/dag/init-hybrid.js +805 -113
- package/dist/workflows/dag/node-execution.js +194 -6
- package/dist/workflows/dag/prompt.js +60 -1
- package/dist/workflows/dag/rerun-feedback.js +212 -0
- package/dist/workflows/dag/rerun-plan.js +224 -27
- package/dist/workflows/dag/rerun-run.js +61 -6
- package/dist/workflows/dag/rerun-task.js +61 -2
- package/dist/workflows/dag/retry-policy.js +113 -0
- package/dist/workflows/dag/structured-output-repair.js +712 -0
- package/dist/workflows/dag/types.js +157 -1
- package/dist/workflows/dag/validate.js +41 -1
- package/docs/init-surface.manifest.json +5 -0
- package/docs/operations/README.md +1 -1
- package/docs/operations/local-development-environment.md +1 -5
- package/docs/skills/vetted-skill-registry.md +14 -0
- package/docs/templates/README.md +1 -1
- package/docs/templates/agent-dag.schema.json +44 -0
- package/docs/templates/backend-test-dag.json +60 -35
- package/docs/templates/frontend-implementation-contract.schema.json +9 -2
- package/docs/templates/frontend-test-dag.json +8 -10
- package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +1 -1
- package/docs/templates/init-managed-agents.md +13 -3
- package/harness.json +3 -1
- package/package.json +12 -4
- package/scripts/next-info.mjs +356 -0
- package/scripts/next-publish-gate.mjs +238 -0
- package/scripts/release-source-binding.mjs +251 -0
- package/skills/analyze-product-requirements/SKILL.md +8 -5
- package/skills/analyze-product-requirements/references/acceptance-criteria.md +1 -1
- package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +10 -6
- package/skills/analyze-product-requirements/references/example.md +50 -0
- package/skills/analyze-product-requirements/references/forward-test-cases.md +11 -7
- package/skills/analyze-product-requirements/references/kb-integration.md +5 -5
- package/skills/analyze-product-requirements/references/product-analysis-schema.md +8 -4
- package/skills/analyze-product-requirements/references/product-requirement-schema.md +2 -2
- package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +1 -1
- package/skills/analyze-product-requirements/scripts/test-validators.mjs +11 -1
- package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +20 -1
- package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +9 -0
- package/skills/codebase-scout/SKILL.md +1 -1
- package/skills/frontend-design-review/references/review-checklist.md +2 -0
- package/skills/frontend-implementation/references/design-spec.md +16 -19
- package/skills/frontend-implementation/references/node-contracts.md +9 -6
- package/skills/improve-codebase-architecture/SKILL.md +81 -0
- package/skills/improve-codebase-architecture/deepening.md +37 -0
- package/skills/improve-codebase-architecture/html-report.md +123 -0
- package/skills/improve-codebase-architecture/interface-design.md +44 -0
- package/skills/improve-codebase-architecture/language.md +53 -0
- package/skills/loop-agent/references/command-reference.md +11 -4
- package/dist/worker/console/static/assets/channel-DLVz9TYW.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BeAuGcO9.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BeAuGcO9.js +0 -1
- package/dist/worker/console/static/assets/index-DQxiso1w.js +0 -325
- package/dist/worker/console/static/assets/index-_j0Hzo69.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DzKvfHTX.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Cxqr_qM1.js +0 -8
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { access, readFile } from "node:fs/promises";
|
|
2
|
-
import { buildOperatorCapabilitiesDocument } from "../../shared/operator/capabilities.js";
|
|
2
|
+
import { buildOperatorCapabilitiesDocument, OFFICIAL_TAIL_ACTION_IDS, } from "../../shared/operator/capabilities.js";
|
|
3
|
+
import { DAG_RERUN_PROMPT_OVERRIDE_ENV, isDagRerunPromptOverrideEnabled, MAX_DAG_RERUN_PROMPT_OVERRIDE_CHARS, } from "../../shared/dag-prompt-override.js";
|
|
3
4
|
import { buildOperatorResult, operatorFailed, operatorSucceeded, } from "../../shared/operator/envelope.js";
|
|
4
5
|
import { CANONICAL_TASK_ID_PATTERN, formatLocalBusinessDate, getTaskPaths, loadTaskConfig, } from "../../task/runtime.js";
|
|
5
6
|
import { diffTaskContract, validateDraftForTask, } from "../../task/contract/index.js";
|
|
@@ -11,6 +12,7 @@ import { resolveLatestDagRunIdForTask } from "./resolve-dag-run-for-task.js";
|
|
|
11
12
|
import { repoFingerprintV1 } from "./repo-fingerprint.js";
|
|
12
13
|
import { scheduleOperation, } from "./operation-runner.js";
|
|
13
14
|
import { readinessGateFailure, } from "./pi-readiness.js";
|
|
15
|
+
import { validatePiModelMatrixTiers, writePiModelMatrix, } from "./harness-pi-model-matrix.js";
|
|
14
16
|
import { isAssessmentFreshForDraft } from "./interview/assessment.js";
|
|
15
17
|
import { applyGrillMeAnswer, draftSummary, emptyDraft, isDraftStructurallyComplete, nextGrillMeQuestion, } from "./interview/grill-me.js";
|
|
16
18
|
import { toCanonicalDraftForCli, } from "./draft-store.js";
|
|
@@ -400,6 +402,85 @@ async function runReadCli(ctx, args, command) {
|
|
|
400
402
|
});
|
|
401
403
|
}
|
|
402
404
|
}
|
|
405
|
+
/**
|
|
406
|
+
* Parse and bound the experimental promptOverrides action param. The env
|
|
407
|
+
* switch is checked separately so disabled deployments fail closed before any
|
|
408
|
+
* staging happens. `mode` defaults to "replace"; "append" keeps the frozen
|
|
409
|
+
* base prompt and only appends the operator text as a marked addendum.
|
|
410
|
+
*/
|
|
411
|
+
function parsePromptOverrideParams(raw) {
|
|
412
|
+
if (raw === undefined || raw === null)
|
|
413
|
+
return { kind: "ok", overrides: [] };
|
|
414
|
+
if (!Array.isArray(raw)) {
|
|
415
|
+
return {
|
|
416
|
+
kind: "error",
|
|
417
|
+
message: "promptOverrides must be an array of {nodeId, prompt, mode?}",
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
if (raw.length === 0)
|
|
421
|
+
return { kind: "ok", overrides: [] };
|
|
422
|
+
if (raw.length > 8) {
|
|
423
|
+
return { kind: "error", message: "promptOverrides supports at most 8 nodes" };
|
|
424
|
+
}
|
|
425
|
+
const overrides = [];
|
|
426
|
+
const seen = new Set();
|
|
427
|
+
for (const item of raw) {
|
|
428
|
+
if (!item || typeof item !== "object") {
|
|
429
|
+
return {
|
|
430
|
+
kind: "error",
|
|
431
|
+
message: "promptOverrides entries must be objects {nodeId, prompt, mode?}",
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
const record = item;
|
|
435
|
+
const nodeId = typeof record.nodeId === "string" ? record.nodeId.trim() : "";
|
|
436
|
+
const prompt = typeof record.prompt === "string" ? record.prompt : "";
|
|
437
|
+
const mode = record.mode === undefined || record.mode === null
|
|
438
|
+
? undefined
|
|
439
|
+
: typeof record.mode === "string"
|
|
440
|
+
? record.mode
|
|
441
|
+
: "invalid";
|
|
442
|
+
if (!nodeId) {
|
|
443
|
+
return { kind: "error", message: "promptOverrides nodeId is required" };
|
|
444
|
+
}
|
|
445
|
+
if (seen.has(nodeId)) {
|
|
446
|
+
return {
|
|
447
|
+
kind: "error",
|
|
448
|
+
message: `promptOverrides contains duplicate nodeId: ${nodeId}`,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
seen.add(nodeId);
|
|
452
|
+
if (mode !== undefined && mode !== "append" && mode !== "replace") {
|
|
453
|
+
return {
|
|
454
|
+
kind: "error",
|
|
455
|
+
message: `promptOverrides mode for ${nodeId} must be append or replace`,
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
if (!prompt.trim() || prompt.length > MAX_DAG_RERUN_PROMPT_OVERRIDE_CHARS) {
|
|
459
|
+
return {
|
|
460
|
+
kind: "error",
|
|
461
|
+
message: `promptOverrides prompt for ${nodeId} must be 1-${MAX_DAG_RERUN_PROMPT_OVERRIDE_CHARS} characters`,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
overrides.push(mode === undefined ? { nodeId, prompt } : { nodeId, prompt, mode });
|
|
465
|
+
}
|
|
466
|
+
return { kind: "ok", overrides };
|
|
467
|
+
}
|
|
468
|
+
/** Stage override bodies under app-data and build `--prompt-override` CLI
|
|
469
|
+
* args. The flag carries the mode: `--prompt-override-append` for append. */
|
|
470
|
+
async function buildPromptOverrideCliArgs(ctx, overrides) {
|
|
471
|
+
const args = [];
|
|
472
|
+
for (const override of overrides) {
|
|
473
|
+
const staged = await stageUtf8Text(ctx.appData, override.prompt, {
|
|
474
|
+
extension: ".md",
|
|
475
|
+
label: `prompt-override-${override.nodeId}`,
|
|
476
|
+
});
|
|
477
|
+
const flag = override.mode === "append"
|
|
478
|
+
? "--prompt-override-append"
|
|
479
|
+
: "--prompt-override";
|
|
480
|
+
args.push(flag, `${override.nodeId}@${staged.path}`);
|
|
481
|
+
}
|
|
482
|
+
return args;
|
|
483
|
+
}
|
|
403
484
|
async function acceptOperation(ctx, input) {
|
|
404
485
|
const created = await ctx.operations.create({
|
|
405
486
|
clientRequestId: input.clientRequestId,
|
|
@@ -671,6 +752,80 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
671
752
|
const body = await runReadCli(ctx, ["dag", "report", "--run-id", runId, "--json"], "dag report");
|
|
672
753
|
return { kind: "sync", status: body.ok ? 200 : 400, body };
|
|
673
754
|
}
|
|
755
|
+
case "dagDoctor": {
|
|
756
|
+
const runId = str(p.runId) ?? str(p.dagRunId);
|
|
757
|
+
const args = ["dag", "doctor"];
|
|
758
|
+
if (runId)
|
|
759
|
+
args.push("--run-id", runId);
|
|
760
|
+
const body = await runReadCli(ctx, args, "dag doctor");
|
|
761
|
+
return { kind: "sync", status: body.ok ? 200 : 400, body };
|
|
762
|
+
}
|
|
763
|
+
case "dagStatus": {
|
|
764
|
+
const runId = str(p.runId) ?? str(p.dagRunId);
|
|
765
|
+
if (!runId)
|
|
766
|
+
return invalid(action, "runId is required");
|
|
767
|
+
const body = await runReadCli(ctx, ["dag", "status", "--run-id", runId], "dag status");
|
|
768
|
+
return { kind: "sync", status: body.ok ? 200 : 400, body };
|
|
769
|
+
}
|
|
770
|
+
case "workerPoolDoctor": {
|
|
771
|
+
const taskId = str(p.taskId);
|
|
772
|
+
const run = ctx.runCommand ??
|
|
773
|
+
((args, options) => ctx.client.runExternal
|
|
774
|
+
? ctx.client.runExternal(resolveSiblingAgentWorkerBin(), args, options)
|
|
775
|
+
: ctx.client.run(args, options));
|
|
776
|
+
let result;
|
|
777
|
+
try {
|
|
778
|
+
result = await run(["pool", "doctor", "--repo", ctx.repoRoot, "--json"], {
|
|
779
|
+
cwd: ctx.repoRoot,
|
|
780
|
+
artifactName: "read-pool-doctor",
|
|
781
|
+
expectJson: true,
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
catch (error) {
|
|
785
|
+
return {
|
|
786
|
+
kind: "error",
|
|
787
|
+
status: 400,
|
|
788
|
+
body: operatorFailed({
|
|
789
|
+
command: action,
|
|
790
|
+
outcome: "invalid",
|
|
791
|
+
code: "INVALID_INPUT",
|
|
792
|
+
message: `cannot read pool doctor facts: ${error instanceof Error ? error.message : String(error)}`,
|
|
793
|
+
}),
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
if (!result.ok || result.exitCode !== 0 || !result.json) {
|
|
797
|
+
return {
|
|
798
|
+
kind: "error",
|
|
799
|
+
status: 400,
|
|
800
|
+
body: operatorFailed({
|
|
801
|
+
command: action,
|
|
802
|
+
outcome: "invalid",
|
|
803
|
+
code: "INVALID_INPUT",
|
|
804
|
+
message: summarizeReadCliFailure(result),
|
|
805
|
+
}),
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
const inventory = result.json;
|
|
809
|
+
if (!taskId) {
|
|
810
|
+
return {
|
|
811
|
+
kind: "sync",
|
|
812
|
+
status: 200,
|
|
813
|
+
body: operatorSucceeded(action, inventory),
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
const v2 = (inventory.v2 ?? []).filter((entry) => entry.taskId === taskId);
|
|
817
|
+
const legacy = (inventory.legacy ?? []).filter((entry) => entry.taskId === taskId);
|
|
818
|
+
return {
|
|
819
|
+
kind: "sync",
|
|
820
|
+
status: 200,
|
|
821
|
+
body: operatorSucceeded(action, {
|
|
822
|
+
...inventory,
|
|
823
|
+
v2,
|
|
824
|
+
legacy,
|
|
825
|
+
focusedTaskId: taskId,
|
|
826
|
+
}),
|
|
827
|
+
};
|
|
828
|
+
}
|
|
674
829
|
case "status": {
|
|
675
830
|
const taskId = str(p.taskId);
|
|
676
831
|
if (!taskId) {
|
|
@@ -985,7 +1140,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
985
1140
|
}
|
|
986
1141
|
if (operatorAction) {
|
|
987
1142
|
const target = buildOperatorCapabilitiesDocument().actions.find((entry) => entry.action === operatorAction &&
|
|
988
|
-
entry.
|
|
1143
|
+
OFFICIAL_TAIL_ACTION_IDS.has(entry.action) &&
|
|
989
1144
|
entry.humanConfirmation === "required");
|
|
990
1145
|
if (!target)
|
|
991
1146
|
return invalid(action, "operatorAction must name a required official action");
|
|
@@ -2003,12 +2158,35 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2003
2158
|
}
|
|
2004
2159
|
return accepted;
|
|
2005
2160
|
}
|
|
2161
|
+
case "dagPromptOverrideConfig": {
|
|
2162
|
+
// Experimental internal switch; the browser UI hides the prompt-edit
|
|
2163
|
+
// entry unless this reports enabled=true.
|
|
2164
|
+
return {
|
|
2165
|
+
kind: "sync",
|
|
2166
|
+
status: 200,
|
|
2167
|
+
body: operatorSucceeded(action, {
|
|
2168
|
+
enabled: isDagRerunPromptOverrideEnabled(),
|
|
2169
|
+
envVar: DAG_RERUN_PROMPT_OVERRIDE_ENV,
|
|
2170
|
+
}),
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2006
2173
|
case "dagRerunPlan": {
|
|
2007
2174
|
const runId = str(p.runId);
|
|
2008
2175
|
const fromNode = str(p.fromNode);
|
|
2009
2176
|
if (!runId || !fromNode) {
|
|
2010
2177
|
return invalid(action, "runId and fromNode are required");
|
|
2011
2178
|
}
|
|
2179
|
+
const parsedOverrides = parsePromptOverrideParams(p.promptOverrides);
|
|
2180
|
+
if (parsedOverrides.kind === "error") {
|
|
2181
|
+
return invalid(action, parsedOverrides.message);
|
|
2182
|
+
}
|
|
2183
|
+
if (parsedOverrides.overrides.length > 0 &&
|
|
2184
|
+
!isDagRerunPromptOverrideEnabled()) {
|
|
2185
|
+
return invalid(action, `prompt override rerun is disabled; set ${DAG_RERUN_PROMPT_OVERRIDE_ENV}=1 to enable this experimental capability`);
|
|
2186
|
+
}
|
|
2187
|
+
const overrideArgs = parsedOverrides.overrides.length > 0
|
|
2188
|
+
? await buildPromptOverrideCliArgs(ctx, parsedOverrides.overrides)
|
|
2189
|
+
: [];
|
|
2012
2190
|
const body = await runReadCli(ctx, [
|
|
2013
2191
|
"dag",
|
|
2014
2192
|
"rerun",
|
|
@@ -2017,6 +2195,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2017
2195
|
"--from-node",
|
|
2018
2196
|
fromNode,
|
|
2019
2197
|
"--plan",
|
|
2198
|
+
...overrideArgs,
|
|
2020
2199
|
"--json",
|
|
2021
2200
|
], "dag rerun plan");
|
|
2022
2201
|
return { kind: "sync", status: body.ok ? 200 : 400, body };
|
|
@@ -2030,6 +2209,17 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2030
2209
|
if (!runId || !fromNode || !planHash || !reason || !clientRequestId) {
|
|
2031
2210
|
return invalid(action, "runId, fromNode, planHash, reason, and clientRequestId are required");
|
|
2032
2211
|
}
|
|
2212
|
+
const parsedOverrides = parsePromptOverrideParams(p.promptOverrides);
|
|
2213
|
+
if (parsedOverrides.kind === "error") {
|
|
2214
|
+
return invalid(action, parsedOverrides.message);
|
|
2215
|
+
}
|
|
2216
|
+
if (parsedOverrides.overrides.length > 0 &&
|
|
2217
|
+
!isDagRerunPromptOverrideEnabled()) {
|
|
2218
|
+
return invalid(action, `prompt override rerun is disabled; set ${DAG_RERUN_PROMPT_OVERRIDE_ENV}=1 to enable this experimental capability`);
|
|
2219
|
+
}
|
|
2220
|
+
const overrideArgs = parsedOverrides.overrides.length > 0
|
|
2221
|
+
? await buildPromptOverrideCliArgs(ctx, parsedOverrides.overrides)
|
|
2222
|
+
: [];
|
|
2033
2223
|
return acceptOperation(ctx, {
|
|
2034
2224
|
action,
|
|
2035
2225
|
actionParams: p,
|
|
@@ -2047,6 +2237,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2047
2237
|
clientRequestId,
|
|
2048
2238
|
"--reason",
|
|
2049
2239
|
reason,
|
|
2240
|
+
...overrideArgs,
|
|
2050
2241
|
"--json",
|
|
2051
2242
|
],
|
|
2052
2243
|
});
|
|
@@ -2483,12 +2674,61 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2483
2674
|
}),
|
|
2484
2675
|
};
|
|
2485
2676
|
}
|
|
2677
|
+
case "savePiModelMatrix": {
|
|
2678
|
+
// 「模型与认证」页模型矩阵编辑器:三档字符串值经校验后原子写入
|
|
2679
|
+
// harness.json executors.pi,并自动重测 readiness。写路径本身由 HTTP
|
|
2680
|
+
// 层 evaluateMutationGate 拦截(cookie + confirmation 头 + origin)。
|
|
2681
|
+
const matrixInput = p.matrix ?? p;
|
|
2682
|
+
const validation = validatePiModelMatrixTiers(matrixInput);
|
|
2683
|
+
if (!validation.ok) {
|
|
2684
|
+
return {
|
|
2685
|
+
kind: "error",
|
|
2686
|
+
status: 400,
|
|
2687
|
+
body: operatorFailed({
|
|
2688
|
+
command: action,
|
|
2689
|
+
outcome: "invalid",
|
|
2690
|
+
code: validation.code,
|
|
2691
|
+
message: validation.message,
|
|
2692
|
+
...(validation.tier ? { details: { tier: validation.tier } } : {}),
|
|
2693
|
+
}),
|
|
2694
|
+
};
|
|
2695
|
+
}
|
|
2696
|
+
try {
|
|
2697
|
+
await writePiModelMatrix(ctx.repoRoot, validation.tiers);
|
|
2698
|
+
}
|
|
2699
|
+
catch (error) {
|
|
2700
|
+
return {
|
|
2701
|
+
kind: "error",
|
|
2702
|
+
status: 500,
|
|
2703
|
+
body: operatorFailed({
|
|
2704
|
+
command: action,
|
|
2705
|
+
outcome: "blocked",
|
|
2706
|
+
code: "PI_MODEL_MATRIX_WRITE_FAILED",
|
|
2707
|
+
message: error instanceof Error ? error.message : String(error),
|
|
2708
|
+
}),
|
|
2709
|
+
};
|
|
2710
|
+
}
|
|
2711
|
+
// 保存成功自动重测 readiness(复用 probePiReadiness),让页面立即
|
|
2712
|
+
// 展示新的 modelsAvailable / modelsMessage / piModelMatrix(AC-4)。
|
|
2713
|
+
const report = ctx.refreshReadiness
|
|
2714
|
+
? await ctx.refreshReadiness()
|
|
2715
|
+
: ctx.getReadiness?.() ?? ctx.readiness;
|
|
2716
|
+
return {
|
|
2717
|
+
kind: "sync",
|
|
2718
|
+
status: 200,
|
|
2719
|
+
body: operatorSucceeded("savePiModelMatrix", {
|
|
2720
|
+
tiers: validation.tiers,
|
|
2721
|
+
readiness: report,
|
|
2722
|
+
}),
|
|
2723
|
+
};
|
|
2724
|
+
}
|
|
2486
2725
|
default: {
|
|
2487
2726
|
// M5 official-command coverage uses one generic tail for newly registered
|
|
2488
2727
|
// CLI actions. It remains inside dispatchOperatorAction (the sole dispatch
|
|
2489
2728
|
// surface) and only accepts argv arrays declared by the capability schema.
|
|
2490
|
-
|
|
2491
|
-
|
|
2729
|
+
// 2026-08-18: high-frequency entries got real descriptions; membership is
|
|
2730
|
+
// now derived from OFFICIAL_TAIL_ACTION_IDS, not description prefixes.
|
|
2731
|
+
const capability = buildOperatorCapabilitiesDocument().actions.find((entry) => entry.action === action && OFFICIAL_TAIL_ACTION_IDS.has(entry.action));
|
|
2492
2732
|
if (capability) {
|
|
2493
2733
|
const rawArgs = p.args;
|
|
2494
2734
|
if (rawArgs !== undefined &&
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import { rewriteRecoveryOperatorError } from "./recovery-error-copy.js";
|
|
2
|
+
/** Mutation-gate raw English messages (worker/console/security.ts) → copy. */
|
|
3
|
+
const MUTATION_GATE_COPY = [
|
|
4
|
+
{
|
|
5
|
+
pattern: /invalid (boot capability|confirmation header) token/i,
|
|
6
|
+
copy: "页面凭证已失效(控制台可能已重启),请刷新页面(F5)后重试。",
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
pattern: /mutation requires boot capability cookie|mutation requires confirmation header token/i,
|
|
10
|
+
copy: "页面状态异常,请刷新页面(F5)后重试。",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
pattern: /Host header is required for non-loopback/i,
|
|
14
|
+
copy: "请求主机校验失败:非回环绑定时要求 Host 头,请刷新页面或检查访问地址。",
|
|
15
|
+
},
|
|
16
|
+
];
|
|
2
17
|
/** Map internal spawn/controller errors to actionable Chinese copy. */
|
|
3
18
|
export function formatOperatorUserError(message) {
|
|
4
19
|
const raw = (message ?? "").trim();
|
|
@@ -22,5 +37,9 @@ export function formatOperatorUserError(message) {
|
|
|
22
37
|
if (/force-required|requires --force/i.test(raw)) {
|
|
23
38
|
return "该终态需要强制 Discard。请确认后勾选强制再试。";
|
|
24
39
|
}
|
|
40
|
+
for (const entry of MUTATION_GATE_COPY) {
|
|
41
|
+
if (entry.pattern.test(raw))
|
|
42
|
+
return entry.copy;
|
|
43
|
+
}
|
|
25
44
|
return raw;
|
|
26
45
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { mapSnapshotAvailableModels, resolveHarnessPiExecutorMatrix, } from "./chat/model-resolver.js";
|
|
7
|
+
import { readPiModelMatrixProjection, } from "./harness-pi-model-matrix.js";
|
|
7
8
|
const SETUP_BLOCKED = Object.freeze([
|
|
8
9
|
"newTask",
|
|
9
10
|
"importPrd",
|
|
@@ -84,7 +85,7 @@ function hasProviderConfig(snapshot) {
|
|
|
84
85
|
/**
|
|
85
86
|
* Discover live Pi SDK / auth / model readiness via ModelRuntime.
|
|
86
87
|
* Kept inside worker/console (dynamic import) so Worker does not depend on
|
|
87
|
-
* executors; contract matches pi-sdk-executor 0.
|
|
88
|
+
* executors; contract matches pi-sdk-executor 0.83.0.
|
|
88
89
|
*/
|
|
89
90
|
export async function discoverPiReadinessProbe(options) {
|
|
90
91
|
const repoRoot = options?.repoRoot ?? process.cwd();
|
|
@@ -117,7 +118,7 @@ export async function discoverPiReadinessProbe(options) {
|
|
|
117
118
|
modelsAvailable: false,
|
|
118
119
|
interviewSessionOk: false,
|
|
119
120
|
details: {
|
|
120
|
-
sdkMessage: "Pi SDK incompatible: requires createAgentSession, getAgentDir, and ModelRuntime.create (0.
|
|
121
|
+
sdkMessage: "Pi SDK incompatible: requires createAgentSession, getAgentDir, and ModelRuntime.create (0.83.0)",
|
|
121
122
|
authMessage: "skipped (sdk incompatible)",
|
|
122
123
|
modelsMessage: "skipped (sdk incompatible)",
|
|
123
124
|
sessionMessage: "skipped (sdk incompatible)",
|
|
@@ -158,7 +159,7 @@ export async function discoverPiReadinessProbe(options) {
|
|
|
158
159
|
modelsAvailable: false,
|
|
159
160
|
interviewSessionOk: false,
|
|
160
161
|
details: {
|
|
161
|
-
sdkMessage: "Pi SDK 0.
|
|
162
|
+
sdkMessage: "Pi SDK 0.83.0 contract available",
|
|
162
163
|
authMessage: `ModelRuntime.create failed: ${message}`,
|
|
163
164
|
modelsMessage: "skipped (runtime init failed)",
|
|
164
165
|
sessionMessage: "skipped (runtime init failed)",
|
|
@@ -221,8 +222,9 @@ export async function discoverPiReadinessProbe(options) {
|
|
|
221
222
|
authReady,
|
|
222
223
|
modelsAvailable,
|
|
223
224
|
interviewSessionOk,
|
|
225
|
+
piAvailableModels: availableModels,
|
|
224
226
|
details: {
|
|
225
|
-
sdkMessage: `Pi SDK 0.
|
|
227
|
+
sdkMessage: `Pi SDK 0.83.0 contract available (agentDir=${agentDir})`,
|
|
226
228
|
authMessage: authReady
|
|
227
229
|
? `credentials/providers ready (available=${availableCount}, providerConfig=${providerConfigured})`
|
|
228
230
|
: "no available models and no stored/configured provider credentials (set Pi auth or provider API keys)",
|
|
@@ -238,13 +240,18 @@ export async function discoverPiReadinessProbe(options) {
|
|
|
238
240
|
* override is injected. Tests inject override for determinism.
|
|
239
241
|
*/
|
|
240
242
|
export async function probePiReadiness(options) {
|
|
243
|
+
const repoRoot = options?.repoRoot ?? process.cwd();
|
|
244
|
+
// 模型矩阵投影与 SDK 探测解耦:即使 SDK 不可用 / 测试注入 override,仍要
|
|
245
|
+
// 投影 harness.json 三档值供模型矩阵编辑器预填(AC-1 / AC-4)。
|
|
246
|
+
const piModelMatrix = await readPiModelMatrixProjection(repoRoot);
|
|
241
247
|
if (options?.override) {
|
|
242
|
-
return buildPiReadinessReport(options.override);
|
|
248
|
+
return buildPiReadinessReport({ ...options.override, piModelMatrix });
|
|
243
249
|
}
|
|
244
250
|
try {
|
|
245
251
|
const probe = await discoverPiReadinessProbe({
|
|
246
252
|
repoRoot: options?.repoRoot,
|
|
247
253
|
});
|
|
254
|
+
probe.piModelMatrix = piModelMatrix;
|
|
248
255
|
if (options?.siblingControllerOk && !probe.details) {
|
|
249
256
|
probe.details = {};
|
|
250
257
|
}
|
|
@@ -59,20 +59,20 @@ const CTA = {
|
|
|
59
59
|
},
|
|
60
60
|
dagRerun: {
|
|
61
61
|
id: "dagRerun",
|
|
62
|
-
label: "
|
|
62
|
+
label: "从失败节点恢复",
|
|
63
63
|
requiresReason: true,
|
|
64
64
|
action: "dagRerun",
|
|
65
65
|
lane: "dag",
|
|
66
|
-
guide: "
|
|
66
|
+
guide: "Provider、网络、限流或超时等非代码问题的首选:先评估安全子图,合格后创建 continuation run 从有效节点恢复(无需 Human Gate)。Worker 持有的 run、workspace/controller 漂移或含 unsafe shell 时不要强跑子图",
|
|
67
67
|
commandHint: "loop-agent dag rerun --run-id <run-id> --from-node <node-id> --plan",
|
|
68
68
|
},
|
|
69
69
|
standaloneTaskRerun: {
|
|
70
70
|
id: "standaloneTaskRerun",
|
|
71
|
-
label: "
|
|
71
|
+
label: "带反馈重新执行任务",
|
|
72
72
|
requiresReason: true,
|
|
73
73
|
action: "standaloneTaskRerun",
|
|
74
74
|
lane: "dag",
|
|
75
|
-
guide: "独立 DAG run
|
|
75
|
+
guide: "独立 DAG run 无法安全从节点恢复时,重新生成完整 DAG,并带入上一轮仍未解决的 verify/review 反馈;没有可继承反馈时会明确说明(无需 Human Gate)。Worker 持有的 run 请用下方「重新排队 Worker Task」",
|
|
76
76
|
commandHint: "loop-agent dag rerun-task --run-id <run-id> --reason <text> --json",
|
|
77
77
|
},
|
|
78
78
|
workerTaskRetry: {
|
|
@@ -107,7 +107,7 @@ export function nextActionForIneligibleRerun(reasons) {
|
|
|
107
107
|
"worker-managed-rerun-unsupported")) {
|
|
108
108
|
return "下一步:请点下方「重新排队 Worker Task」,从头完整执行。";
|
|
109
109
|
}
|
|
110
|
-
return "
|
|
110
|
+
return "下一步:请改用「带反馈重新执行任务」,重新生成完整 DAG。";
|
|
111
111
|
}
|
|
112
112
|
export function formatIneligibleRerunMessage(input) {
|
|
113
113
|
const fallback = input.fallbackMessage?.trim();
|
|
@@ -141,16 +141,16 @@ export function rewriteRecoveryOperatorError(raw) {
|
|
|
141
141
|
return formatIneligibleRerunMessage({ fallbackMessage: text });
|
|
142
142
|
}
|
|
143
143
|
if (/action must be a mutation-gate target/i.test(text)) {
|
|
144
|
-
return "这个操作不能再走确认门。Worker 启动的任务请直接点「重新排队 Worker Task
|
|
144
|
+
return "这个操作不能再走确认门。Worker 启动的任务请直接点「重新排队 Worker Task」;独立运行请点「带反馈重新执行任务」。";
|
|
145
145
|
}
|
|
146
146
|
if (/cannot read dagReport run facts/i.test(text)) {
|
|
147
147
|
return "读不到这次运行的失败报告,不能完整重跑。请先点「查看报告」或「Doctor 诊断」。";
|
|
148
148
|
}
|
|
149
149
|
if (/dagRerunPlan run facts unavailable/i.test(text)) {
|
|
150
|
-
return "
|
|
150
|
+
return "读不到节点恢复资格,不能直接改走完整重跑。请先点「从失败节点恢复」查看资格,或先「查看报告」。";
|
|
151
151
|
}
|
|
152
152
|
if (/node rerun plan is eligible/i.test(text)) {
|
|
153
|
-
return "
|
|
153
|
+
return "节点恢复是安全的,请改用「从失败节点恢复」,不必重新执行完整任务。";
|
|
154
154
|
}
|
|
155
155
|
if (/does not support autonomous standaloneTaskRerun/i.test(text)) {
|
|
156
156
|
return "当前失败不适合自动完整重跑。请先点「查看报告」,按建议操作。";
|
|
@@ -116,6 +116,7 @@ async function handleRecoveryCandidates(_req, res, ctx, url) {
|
|
|
116
116
|
}
|
|
117
117
|
async function handleSessionPing(req, res, ctx) {
|
|
118
118
|
const failure = evaluateMutationGate(req, {
|
|
119
|
+
cookieName: ctx.bootToken.cookieName,
|
|
119
120
|
bootToken: ctx.bootToken.value,
|
|
120
121
|
confirmationToken: ctx.bootToken.confirmationToken,
|
|
121
122
|
consoleOrigin: ctx.getConsoleOrigin(),
|
|
@@ -130,6 +131,16 @@ async function handleSessionPing(req, res, ctx) {
|
|
|
130
131
|
}
|
|
131
132
|
sendJson(res, 200, { ok: true, pong: true });
|
|
132
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Actions the inspect-scoped mutation token may dispatch. Deliberately
|
|
136
|
+
* minimal: the experimental prompt-override rerun tab needs plan preflight +
|
|
137
|
+
* execution only. Everything else (task creation, runDag, reconcile, chat,
|
|
138
|
+
* worker actions…) requires the general Console token.
|
|
139
|
+
*/
|
|
140
|
+
export const INSPECT_MUTATION_ALLOWED_ACTIONS = new Set([
|
|
141
|
+
"dagRerunPlan",
|
|
142
|
+
"dagRerun",
|
|
143
|
+
]);
|
|
133
144
|
async function handleCreateOperation(req, res, ctx) {
|
|
134
145
|
if (!ctx.operator) {
|
|
135
146
|
sendJson(res, 503, {
|
|
@@ -141,12 +152,31 @@ async function handleCreateOperation(req, res, ctx) {
|
|
|
141
152
|
});
|
|
142
153
|
return;
|
|
143
154
|
}
|
|
144
|
-
const
|
|
155
|
+
const generalGateContext = {
|
|
156
|
+
cookieName: ctx.bootToken.cookieName,
|
|
145
157
|
bootToken: ctx.bootToken.value,
|
|
146
158
|
confirmationToken: ctx.bootToken.confirmationToken,
|
|
147
159
|
consoleOrigin: ctx.getConsoleOrigin(),
|
|
148
160
|
allowNonLoopbackAccess: ctx.allowNonLoopbackAccess === true,
|
|
149
|
-
}
|
|
161
|
+
};
|
|
162
|
+
let failure = evaluateMutationGate(req, generalGateContext);
|
|
163
|
+
let inspectScoped = false;
|
|
164
|
+
if (failure && ctx.inspectBootToken) {
|
|
165
|
+
// Scoped /inspect credentials: try the inspect gate before failing. The
|
|
166
|
+
// general gate already rejected, so passing here only ever yields the
|
|
167
|
+
// allowlisted actions below — never general write capability.
|
|
168
|
+
const scopedFailure = evaluateMutationGate(req, {
|
|
169
|
+
cookieName: ctx.inspectBootToken.cookieName,
|
|
170
|
+
bootToken: ctx.inspectBootToken.value,
|
|
171
|
+
confirmationToken: ctx.inspectBootToken.confirmationToken,
|
|
172
|
+
consoleOrigin: ctx.getConsoleOrigin(),
|
|
173
|
+
allowNonLoopbackAccess: ctx.allowNonLoopbackAccess === true,
|
|
174
|
+
});
|
|
175
|
+
if (!scopedFailure) {
|
|
176
|
+
inspectScoped = true;
|
|
177
|
+
failure = undefined;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
150
180
|
if (failure) {
|
|
151
181
|
sendJson(res, failure.status, {
|
|
152
182
|
ok: false,
|
|
@@ -173,6 +203,16 @@ async function handleCreateOperation(req, res, ctx) {
|
|
|
173
203
|
? body.actionParams
|
|
174
204
|
: {};
|
|
175
205
|
const clientRequestId = typeof body.clientRequestId === "string" ? body.clientRequestId : undefined;
|
|
206
|
+
if (inspectScoped && !INSPECT_MUTATION_ALLOWED_ACTIONS.has(action)) {
|
|
207
|
+
sendJson(res, 403, {
|
|
208
|
+
ok: false,
|
|
209
|
+
error: {
|
|
210
|
+
code: "ACTION_NOT_IN_INSPECT_SCOPE",
|
|
211
|
+
message: `inspect-scoped token only allows: ${[...INSPECT_MUTATION_ALLOWED_ACTIONS].join(", ")}`,
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
176
216
|
const result = await dispatchOperatorAction(ctx.operator.actionContext, {
|
|
177
217
|
action,
|
|
178
218
|
actionParams,
|
|
@@ -428,6 +468,7 @@ export async function handleConsoleOperatorRequest(req, res, ctx) {
|
|
|
428
468
|
}
|
|
429
469
|
if (isMutationMethod(method)) {
|
|
430
470
|
const failure = evaluateMutationGate(req, {
|
|
471
|
+
cookieName: ctx.bootToken.cookieName,
|
|
431
472
|
bootToken: ctx.bootToken.value,
|
|
432
473
|
confirmationToken: ctx.bootToken.confirmationToken,
|
|
433
474
|
consoleOrigin: ctx.getConsoleOrigin(),
|