@tea-agent/loop-agent 0.43.0-next.17 → 0.43.0-next.3
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 +9 -140
- package/dist/application/task-lifecycle/advance.js +4 -17
- package/dist/application/task-lifecycle/observe.js +29 -43
- package/dist/application/task-lifecycle/plan-transitions.js +4 -5
- package/dist/build-stamp.json +3 -3
- package/dist/commands/client-recovery.js +55 -20
- package/dist/commands/new-task.js +5 -0
- package/dist/commands/status.js +57 -0
- package/dist/commands/task-contract.js +269 -0
- package/dist/executors/dag-pi-executor.js +230 -269
- package/dist/executors/pi-executor.js +0 -2
- package/dist/executors/pi-sdk-executor.js +39 -77
- package/dist/executors/shell-executor.js +2 -3
- package/dist/executors/shell-write-guard.js +32 -27
- package/dist/shared/pi-context-pressure/extension.js +16 -26
- package/dist/shared/pi-retry-settings.js +0 -40
- package/dist/shared/prompts.js +26 -0
- package/dist/task/config.js +2 -0
- package/dist/task/contract/validate-draft.js +106 -0
- package/dist/task/goal.js +3 -0
- package/dist/task/index.js +12 -0
- package/dist/task/lifecycle.js +1 -0
- package/dist/task/operator/capabilities.js +6 -0
- package/dist/task/operator/envelope.js +2 -0
- package/dist/task/operator/index.js +5 -0
- package/dist/task/operator/registry.js +2 -0
- package/dist/task/operator/types.js +1 -0
- package/dist/task/paths.js +1 -0
- package/dist/task/source-prepare/source-fidelity-pi.js +2 -2
- package/dist/task/source-references.js +23 -48
- package/dist/task/source-state.js +1 -0
- package/dist/task/subagent-guidance.js +1 -0
- package/dist/worker/console/chat/assistant-content.js +2 -23
- package/dist/worker/console/chat/explore-tools.js +0 -13
- package/dist/worker/console/chat/pi-runtime.js +1182 -221
- package/dist/worker/console/chat/routes.js +71 -213
- package/dist/worker/console/chat/sdd-data-alignment.js +9 -65
- package/dist/worker/console/chat/session-catalog.js +0 -32
- package/dist/worker/console/chat/session-store.js +6 -22
- package/dist/worker/console/chat/shortcuts.js +0 -6
- package/dist/worker/console/chat/sift-bridge.js +1 -0
- package/dist/worker/console/chat/tool-preview.js +0 -11
- package/dist/worker/console/chat/tools.js +0 -6
- package/dist/worker/console/console-update-and-init.js +19 -1
- package/dist/worker/console/console-update-runtime.js +20 -5
- package/dist/worker/console/index.js +20 -0
- package/dist/worker/console/operator-actions.js +1 -13
- package/dist/worker/console/routes.js +0 -8
- package/dist/worker/console/server.js +29 -11
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C4NXyedy.js → abnfDiagram-N423BO3Z-hUmM_GRf.js} +1 -1
- package/dist/worker/console/static/assets/{arc-NZ3qXvBI.js → arc-Bt-xuieW.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-COZSRvml.js → architectureDiagram-T3A2C74G-DTqkL4DJ.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Ck0Gxi9C.js → blockDiagram-VBNYF7ZC-Cy0MNnzV.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BX5HQ4Ox.js → c4Diagram-5PPSVZJV-DDdlT0Pd.js} +1 -1
- package/dist/worker/console/static/assets/channel-BpzRnZmU.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-CoviemSL.js → chunk-2GRJ4B5K-3JawwNZ6.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DbOdOkbZ.js → chunk-2Q5K7J3B-DoTp7Cri.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BsG2pmdQ.js → chunk-5RXB4S5H-CcirhZaS.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-DGdvrNm8.js → chunk-5VM5RSS4-VrG21gnP.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BAy7Yd6y.js → chunk-6Q2QTUOP-DDOgIS70.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-D9UA7hUb.js → chunk-GF5L2VYU-CBjmgvJ_.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-DPz7SZ8V.js → chunk-JWPE2WC7-CCQSht8M.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BmuEOIh7.js → chunk-KBJHAD2P-BpGMkUUV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CIhBWnd8.js → chunk-RYQCIY6F-DNDT41QL.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CScR6mDD.js → chunk-XXDRQBXY-euXnDFbn.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BhlMVqCc.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BhlMVqCc.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BjpfWaUr.js → cose-bilkent-JH36ORCC-BJ6NAeql.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BFQohJgT.js → cynefin-VYW2F7L2-F5JKIvIq.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-D3gzRJnS.js → cynefinDiagram-MW4NZA55-Cwmkl_Gi.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-5eojkhoA.js → dagre-VZM6K2ZE-BmCZ8815.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-CpD8LWu_.js → diagram-7IWD3JNH-zWA3hUnX.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-B8_4qJ2a.js → diagram-B4RE2ZJO-BzA-888F.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-HOsXf0eu.js → diagram-LBJQPF4R-tPNheoch.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BqwRwiWP.js → diagram-Q27KOJAE-Cdi7Fyqp.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BRVCNZe1.js → diagram-UB23O5K3-DFK9VBf1.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Cvb1TgGh.js → ebnfDiagram-BXEA7PRR-xCUr1kpg.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DS0O0qG9.js → erDiagram-JOGREHBK-BANQHY_A.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-BHIRvRr3.js → flowDiagram-UKHOOZJN-VHJYEMkP.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DcCJ1JWx.js → ganttDiagram-PKOTCBZU-DiyZQ0C6.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-B9ia5ony.js → gitGraphDiagram-DS77QQ5N-CZtIeBBa.js} +1 -1
- package/dist/worker/console/static/assets/index-BlN6ytLr.css +1 -0
- package/dist/worker/console/static/assets/index-CA-jfWlE.js +449 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-3ogpgegn.js → infoDiagram-6WML65LV-BuSspC0X.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-4tgpQ5SL.js → ishikawaDiagram-WSZJBQD7-DRJZyPFy.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DNfgHqFx.js → journeyDiagram-NVQOT4AX-DIfXIVuE.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-Dz7ngC8z.js → kanban-definition-27J2QSJJ-CT10_7Lt.js} +1 -1
- package/dist/worker/console/static/assets/{linear-DI7Jv62E.js → linear-ufemj74H.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-CQA4Nzmo.js → mermaid.core-DEQe8-_m.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-CtsMc8Mf.js → mindmap-definition-FAOFIHXS-BRLUrbrC.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-ByppE9yH.js → pegDiagram-VL7TDLO6-BgibKtiF.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-B5PtgFgt.js → pieDiagram-7S7Q4E2Y-D3eyfdV9.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-Cq4p0k2K.js → quadrantDiagram-CIZ2JOQS-DXeTk5Px.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-DjfkyljN.js → railroadDiagram-AXF67PYL-BgXdFEe7.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-DzynNRSl.js → requirementDiagram-LRYGKXZP-CseC2A7R.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cj7TCpTJ.js → sankeyDiagram-W5VNT64P-D80PFzfJ.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-C73C6ykA.js → sequenceDiagram-SI44F4Z6-BWzHW7LS.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-BiNLgN2x.js → sizeCapture-X5ZJPWSS-xWQYTLAn.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-UwvjS64-.js → stateDiagram-OKZ733FA-CLxtpZeL.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-CiVoq4G-.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CC7DH98r.js → swimlanes-SLNWSIFB-DwugtmWV.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BkdgdpfR.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-LSBXTR70.js → timeline-definition-Z64GVDOM-DHEOwHIe.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BAuxWwGP.js → vennDiagram-T6HMQDX7-pmbZKlBK.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y--E5_gjZx.js → wardleyDiagram-T6FBY63Y-CivHoM5q.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-dJWNmyzF.js → xychartDiagram-ELKLHX3M-BfHIE7o6.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +10 -122
- package/dist/worker/console/static-src/operator-chat/compaction-message.js +0 -7
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +15 -35
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +62 -136
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +68 -159
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +56 -75
- package/dist/worker/console/static-src/operator-chat/useComposer.js +78 -206
- package/dist/worker/console/workspace-context.js +1 -21
- package/dist/worker/observe/static/router.js +1 -1
- package/dist/worker/observe/static/styles.css +4 -7
- package/dist/worker/observe/static/views/dag-inspector.js +19 -12
- package/dist/worker/observe/static/views/dag.js +2 -2
- package/dist/worker/scheduler/index.js +25 -0
- package/dist/workflows/dag/facts.js +4 -0
- package/dist/workflows/dag/frontend-closeout.js +1 -1
- package/dist/workflows/dag/frontend-design-policy.js +1 -2
- package/dist/workflows/dag/frontend-implementation-contract.js +4 -8
- package/dist/workflows/dag/frontend-prewrite-gate.js +3 -3
- package/dist/workflows/dag/frontend-repair.js +76 -55
- package/dist/workflows/dag/frontend-review-context.js +1 -2
- package/dist/workflows/dag/frontend-review-scopes.js +12 -34
- package/dist/workflows/dag/frontend-shape-facts.js +2 -12
- package/dist/workflows/dag/frontend-verification-trace.js +42 -8
- package/dist/workflows/dag/index.js +6 -0
- package/dist/workflows/dag/init-hybrid.js +160 -97
- package/dist/workflows/dynamic/index.js +7 -0
- package/docs/architecture/runtime-boundaries.md +3 -3
- package/docs/templates/frontend-implementation-dag.json +8 -9
- package/package.json +3 -7
- package/skills/frontend-bounded-implement/SKILL.md +3 -4
- package/skills/frontend-bounded-implement/references/code-standards.md +3 -3
- package/skills/frontend-contract/references/contract-protocol.md +1 -3
- package/skills/frontend-design-review/SKILL.md +7 -12
- package/skills/frontend-design-review/references/review-checklist.md +7 -7
- package/skills/frontend-plan/SKILL.md +0 -19
- package/skills/frontend-plan/references/decision-contract.md +19 -26
- package/skills/frontend-review/SKILL.md +18 -12
- package/skills/frontend-review/references/review-findings.md +43 -24
- package/dist/shared/pi-provider-recovery.js +0 -182
- package/dist/worker/console/chat/browser-automation.js +0 -363
- package/dist/worker/console/chat/browser-policy.js +0 -113
- package/dist/worker/console/chat/browser-routes.js +0 -162
- package/dist/worker/console/chat/pi-runtime/custom-tools/ask-user-question.js +0 -44
- package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +0 -89
- package/dist/worker/console/chat/pi-runtime/custom-tools/explore-tools.js +0 -202
- package/dist/worker/console/chat/pi-runtime/custom-tools/goal-tools.js +0 -79
- package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +0 -86
- package/dist/worker/console/chat/pi-runtime/custom-tools/todo-write.js +0 -38
- package/dist/worker/console/chat/pi-runtime/inspection-types.js +0 -28
- package/dist/worker/console/chat/pi-runtime/inspection.js +0 -439
- package/dist/worker/console/chat/pi-runtime/sdk-bindings.js +0 -153
- package/dist/worker/console/chat/pi-runtime/sdk-session.js +0 -5
- package/dist/worker/console/chat/scm-routes.js +0 -217
- package/dist/worker/console/chat/scm-service.js +0 -283
- package/dist/worker/console/chat/scm-tools.js +0 -111
- package/dist/worker/console/chat/session-mode-view.js +0 -49
- package/dist/worker/console/chat/session-mode.js +0 -220
- package/dist/worker/console/chat/terminal-routes.js +0 -216
- package/dist/worker/console/chat/terminal-sessions.js +0 -348
- package/dist/worker/console/chat/terminal-tools.js +0 -211
- package/dist/worker/console/static/assets/channel-BxdTlb_5.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-_ByA1Nf8.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-_ByA1Nf8.js +0 -1
- package/dist/worker/console/static/assets/index-B9goN3S5.css +0 -1
- package/dist/worker/console/static/assets/index-wXlQohNs.js +0 -469
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-nLgMZ0D3.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BcYqTady.js +0 -8
- package/dist/worker/console/static-src/operator-chat/active-turn-tail.js +0 -10
- package/dist/worker/console/static-src/operator-chat/chat-link.js +0 -94
- package/dist/worker/console/static-src/operator-chat/chat-scroll-position.js +0 -24
- package/dist/worker/console/static-src/operator-chat/composer-session-ledger.js +0 -192
- package/dist/worker/console/static-src/operator-chat/process-label.js +0 -41
- package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +0 -13
- package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +0 -10
- package/dist/worker/console/static-src/operator-chat/use-searchable-hidden.js +0 -51
- package/dist/worker/console/static-src/operator-chat/user-turn-anchor-equality.js +0 -21
- package/dist/worker/console/workspace-initialization.js +0 -209
- package/dist/workflows/dag/frontend-capacity.js +0 -9
- package/dist/workflows/dag/frontend-plan-completeness.js +0 -186
- package/dist/workflows/dag/frontend-plan-recovery-policy.js +0 -18
|
@@ -707,8 +707,6 @@ function shouldFallbackSdkToCli(sdkResult, validationIssues, options) {
|
|
|
707
707
|
return true;
|
|
708
708
|
if (!sdkResult.ok &&
|
|
709
709
|
(sdkResult.failureCategory === "auth" ||
|
|
710
|
-
sdkResult.failureCategory === "output-limit" ||
|
|
711
|
-
sdkResult.failureCategory === "cancelled" ||
|
|
712
710
|
sdkResult.failureCategory === "timeout" ||
|
|
713
711
|
sdkResult.failureCategory === "termination-unconfirmed")) {
|
|
714
712
|
return false;
|
|
@@ -9,9 +9,6 @@ import { BoundedTextPreview, classifyPiFailure, createPiJsonlStreamCollector, DE
|
|
|
9
9
|
import { serializeSessionEvent } from "./pi-event-serializer.js";
|
|
10
10
|
import { PI_RECOMMENDED_COMPACTION, PI_RECOMMENDED_RETRY, } from "../shared/pi-retry-settings.js";
|
|
11
11
|
import { createCompactionController, createContextPressureExtension, createSiftBridgeState, inMemoryCompactionSettings, isDagSiftEnabled, parseCompactionPolicy, parseSiftBridgeConfig, SIFT_RETRIEVE_TOOL_NAME, } from "../shared/pi-context-pressure/index.js";
|
|
12
|
-
/** Maximum number of same-session continuations after provider output truncation. */
|
|
13
|
-
export const PI_SDK_OUTPUT_LIMIT_CONTINUE_MAX = 3;
|
|
14
|
-
export const PI_SDK_OUTPUT_LIMIT_CONTINUE_PROMPT = "继续。上一轮因输出长度上限(stopReason=length)截断;当前会话、工具与已完成工作仍保留。只完成尚未完成的部分,不重做已成功的写入或事实提交。";
|
|
15
12
|
/** Wrap the actual stream seam: tool turns, retries and compaction all await it. */
|
|
16
13
|
export async function installPiProviderRequestBudget(session, reserve, onFailure, capacity) {
|
|
17
14
|
const agent = session.agent;
|
|
@@ -614,8 +611,6 @@ async function executeSingleSdkAttemptInternal(options) {
|
|
|
614
611
|
const requestEnvelopeObservation = { peakBytes: 0, peakEstimatedTokens: 0, estimatorVersion: "utf8-bytes-div3-v1-estimate" };
|
|
615
612
|
const stdoutPreview = new BoundedTextPreview("stdout");
|
|
616
613
|
const stdoutCollector = createPiJsonlStreamCollector();
|
|
617
|
-
let turnCollector = createPiJsonlStreamCollector();
|
|
618
|
-
let committedTerminalObserved = false;
|
|
619
614
|
const usageSamples = [];
|
|
620
615
|
const observationEvents = [];
|
|
621
616
|
const readObservation = createFrontendReadObservation();
|
|
@@ -627,9 +622,6 @@ async function executeSingleSdkAttemptInternal(options) {
|
|
|
627
622
|
// length-stopped thinking-only attempt with no persisted write tool calls is
|
|
628
623
|
// still distinguishable from generic empty output.
|
|
629
624
|
let stopReason;
|
|
630
|
-
let providerErrorMessage;
|
|
631
|
-
let promptIndex = 0;
|
|
632
|
-
let outputContinuesSent = 0;
|
|
633
625
|
let thinkingObserved = false;
|
|
634
626
|
let writeToolCallCount = 0;
|
|
635
627
|
const observeWriterThinkingExhaustionEvidence = (event) => {
|
|
@@ -776,8 +768,6 @@ async function executeSingleSdkAttemptInternal(options) {
|
|
|
776
768
|
resolveContextBudget?.("context-budget");
|
|
777
769
|
};
|
|
778
770
|
unsubscribe = session.subscribe((event) => {
|
|
779
|
-
if (event.type === "tool_execution_end" && event.isError !== true && typeof event.toolName === "string" && options.outputLimitRecovery?.terminalToolNames.includes(event.toolName) && isRecord(event.result) && isRecord(event.result.details) && event.result.details.ok === true)
|
|
780
|
-
committedTerminalObserved = true;
|
|
781
771
|
if (event.type === "agent_settled" && !settled) {
|
|
782
772
|
settled = true;
|
|
783
773
|
resolveSettlement?.("settled");
|
|
@@ -798,8 +788,6 @@ async function executeSingleSdkAttemptInternal(options) {
|
|
|
798
788
|
}
|
|
799
789
|
}
|
|
800
790
|
const observationMessage = isRecord(event.message) ? event.message : undefined;
|
|
801
|
-
if (typeof observationMessage?.errorMessage === "string")
|
|
802
|
-
providerErrorMessage = observationMessage.errorMessage;
|
|
803
791
|
try {
|
|
804
792
|
readObservation.observe(event);
|
|
805
793
|
}
|
|
@@ -808,7 +796,7 @@ async function executeSingleSdkAttemptInternal(options) {
|
|
|
808
796
|
observationEvents.push({ responseId: event.responseId, messageId: event.messageId, usage: event.usage, tokenUsage: event.tokenUsage, message: observationMessage ? { role: observationMessage.role, id: observationMessage.id, responseId: observationMessage.responseId, usage: observationMessage.usage } : undefined });
|
|
809
797
|
const usageSample = extractSdkUsageSample(event);
|
|
810
798
|
if (usageSample)
|
|
811
|
-
usageSamples.push(
|
|
799
|
+
usageSamples.push(usageSample);
|
|
812
800
|
if (event.type === "turn_end")
|
|
813
801
|
observedTurns += 1;
|
|
814
802
|
checkContextBudget();
|
|
@@ -822,7 +810,6 @@ async function executeSingleSdkAttemptInternal(options) {
|
|
|
822
810
|
const line = serializeSessionEvent(event);
|
|
823
811
|
stdoutPreview.append(`${line}\n`);
|
|
824
812
|
stdoutCollector.append(`${line}\n`);
|
|
825
|
-
turnCollector.append(`${line}\n`);
|
|
826
813
|
sessionEventAppender?.append(line, event);
|
|
827
814
|
});
|
|
828
815
|
const timeoutPromise = timeoutMs > 0
|
|
@@ -833,9 +820,6 @@ async function executeSingleSdkAttemptInternal(options) {
|
|
|
833
820
|
})
|
|
834
821
|
: null;
|
|
835
822
|
const runTurn = async (userMessage) => {
|
|
836
|
-
promptIndex += 1;
|
|
837
|
-
stopReason = undefined;
|
|
838
|
-
turnCollector = createPiJsonlStreamCollector();
|
|
839
823
|
const settlementPromise = resetSettlement();
|
|
840
824
|
const stallPromise = resetStallPromise();
|
|
841
825
|
const contextBudgetPromise = options.contextBudget
|
|
@@ -881,55 +865,44 @@ async function executeSingleSdkAttemptInternal(options) {
|
|
|
881
865
|
: options.userMessage;
|
|
882
866
|
let continuesSent = 0;
|
|
883
867
|
let raced = await runTurn(promptMessage);
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
: "pi SDK stall continue hit the absolute timeout", true);
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
else {
|
|
914
|
-
await failClosedAfterWait("stall", !abortConfirmed
|
|
915
|
-
? undefined
|
|
916
|
-
: writeToolCallCount > 0
|
|
917
|
-
? "pi SDK stall continue skipped because write tools already ran"
|
|
918
|
-
: "pi SDK stall continue skipped because absolute timeout elapsed", false);
|
|
868
|
+
if (raced === "context-budget") {
|
|
869
|
+
appendStderr(contextBudgetDetail);
|
|
870
|
+
abortConfirmed = await runSessionActionWithGrace("abort", () => session.abort());
|
|
871
|
+
await disposeSession();
|
|
872
|
+
}
|
|
873
|
+
else if (raced === "stall") {
|
|
874
|
+
abortConfirmed = await runSessionActionWithGrace("abort", () => session.abort());
|
|
875
|
+
const withinAbsoluteTimeout = timeoutMs <= 0 || Date.now() - startedAt < timeoutMs;
|
|
876
|
+
const canContinue = abortConfirmed &&
|
|
877
|
+
writeToolCallCount === 0 &&
|
|
878
|
+
withinAbsoluteTimeout &&
|
|
879
|
+
continuesSent < PI_SDK_STALL_CONTINUE_MAX;
|
|
880
|
+
if (canContinue) {
|
|
881
|
+
// The aborted turn's stopReason must not leak onto a recovered continue.
|
|
882
|
+
stopReason = undefined;
|
|
883
|
+
continuesSent += 1;
|
|
884
|
+
persistRuntimeNote({
|
|
885
|
+
type: "loop-agent-stall-continue",
|
|
886
|
+
prompt: PI_SDK_STALL_CONTINUE_PROMPT,
|
|
887
|
+
maxContinues: PI_SDK_STALL_CONTINUE_MAX,
|
|
888
|
+
});
|
|
889
|
+
raced = await runTurn(PI_SDK_STALL_CONTINUE_PROMPT);
|
|
890
|
+
if (raced !== "done" && raced !== "settled") {
|
|
891
|
+
await failClosedAfterWait(raced === "stall" ? "stall" : "absolute-timeout", raced === "stall"
|
|
892
|
+
? "pi SDK stall continue did not recover; treating as timeout"
|
|
893
|
+
: "pi SDK stall continue hit the absolute timeout", true);
|
|
919
894
|
}
|
|
920
895
|
}
|
|
921
|
-
else
|
|
922
|
-
await failClosedAfterWait("
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
stdoutPreview.append(`${note}\n`);
|
|
928
|
-
stdoutCollector.append(`${note}\n`);
|
|
929
|
-
raced = await runTurn(PI_SDK_OUTPUT_LIMIT_CONTINUE_PROMPT);
|
|
930
|
-
continue;
|
|
896
|
+
else {
|
|
897
|
+
await failClosedAfterWait("stall", !abortConfirmed
|
|
898
|
+
? undefined
|
|
899
|
+
: writeToolCallCount > 0
|
|
900
|
+
? "pi SDK stall continue skipped because write tools already ran"
|
|
901
|
+
: "pi SDK stall continue skipped because absolute timeout elapsed", false);
|
|
931
902
|
}
|
|
932
|
-
|
|
903
|
+
}
|
|
904
|
+
else if (raced === "absolute-timeout") {
|
|
905
|
+
await failClosedAfterWait("absolute-timeout");
|
|
933
906
|
}
|
|
934
907
|
}
|
|
935
908
|
catch (error) {
|
|
@@ -958,29 +931,20 @@ async function executeSingleSdkAttemptInternal(options) {
|
|
|
958
931
|
}
|
|
959
932
|
}
|
|
960
933
|
}
|
|
961
|
-
if (providerErrorMessage && stopReason === "error" && !stderr)
|
|
962
|
-
appendStderr(providerErrorMessage);
|
|
963
|
-
if (options.outputLimitRecovery && stopReason === "length" && !committedTerminalObserved && outputContinuesSent >= PI_SDK_OUTPUT_LIMIT_CONTINUE_MAX) {
|
|
964
|
-
const note = serializeSessionEvent({ type: "loop-agent-output-limit-exhausted", maxContinues: PI_SDK_OUTPUT_LIMIT_CONTINUE_MAX });
|
|
965
|
-
stdoutPreview.append(`${note}\n`);
|
|
966
|
-
}
|
|
967
934
|
const stdout = stdoutPreview.text();
|
|
968
935
|
const durationMs = Date.now() - startedAt;
|
|
969
936
|
const collected = stdoutCollector.finish();
|
|
970
937
|
const fallbackParsed = collected.parsedEvents > 0
|
|
971
938
|
? undefined
|
|
972
939
|
: extractAssistantTextFromPiJson(stdout);
|
|
973
|
-
const finalTurn = turnCollector.finish();
|
|
974
940
|
const assistantText = collected.parsedEvents > 0
|
|
975
|
-
?
|
|
941
|
+
? collected.assistantText
|
|
976
942
|
: (fallbackParsed?.assistantText ?? "");
|
|
977
943
|
const parsedEvents = collected.parsedEvents > 0
|
|
978
944
|
? collected.parsedEvents
|
|
979
945
|
: (fallbackParsed?.parsedEvents ?? 0);
|
|
980
946
|
const tokensUsed = aggregateSdkTokenUsage(usageSamples);
|
|
981
|
-
const
|
|
982
|
-
const outputLimitExhausted = Boolean(options.outputLimitRecovery && stopReason === "length" && !committedTerminalObserved && !timedOut && !stderr);
|
|
983
|
-
const failureCategory = !terminationConfirmed ? "termination-unconfirmed" : stopReason === "aborted" ? "cancelled" : outputLimitExhausted ? "output-limit" : providerBudgetFailure ? (providerBudgetFailure.includes("REQUEST_ABORTED") ? "interrupted" : providerBudgetFailure.startsWith("FRONTEND_CONTEXT_ESTIMATE_EXCEEDED") ? "context-budget-exhausted" : "budget_breach") : terminationConfirmed
|
|
947
|
+
const failureCategory = !terminationConfirmed ? "termination-unconfirmed" : providerBudgetFailure ? (providerBudgetFailure.includes("REQUEST_ABORTED") ? "interrupted" : providerBudgetFailure.startsWith("FRONTEND_CONTEXT_ESTIMATE_EXCEEDED") ? "context-budget-exhausted" : "budget_breach") : terminationConfirmed
|
|
984
948
|
? classifyPiFailure({
|
|
985
949
|
assistantText,
|
|
986
950
|
exitCode: timedOut ? 1 : stderr ? 1 : 0,
|
|
@@ -995,14 +959,12 @@ async function executeSingleSdkAttemptInternal(options) {
|
|
|
995
959
|
backend: "sdk",
|
|
996
960
|
command: ["pi-sdk", ...piSdkArgs],
|
|
997
961
|
durationMs,
|
|
998
|
-
exitCode: timedOut || stderr
|
|
962
|
+
exitCode: timedOut || stderr ? 1 : 0,
|
|
999
963
|
failureCategory,
|
|
1000
964
|
modelDisplay,
|
|
1001
965
|
ok: terminationConfirmed &&
|
|
1002
966
|
!timedOut &&
|
|
1003
967
|
!stderr &&
|
|
1004
|
-
!outputLimitExhausted &&
|
|
1005
|
-
!cancelled &&
|
|
1006
968
|
assistantText.length > 0 &&
|
|
1007
969
|
!collected.outputTooLarge,
|
|
1008
970
|
parsedEvents,
|
|
@@ -2329,7 +2329,7 @@ async function collectReviewTerminalKinds(runDir, reviewNodeId) {
|
|
|
2329
2329
|
const kind = record.fact.kind;
|
|
2330
2330
|
return typeof kind === "string" ? kind : "";
|
|
2331
2331
|
})
|
|
2332
|
-
.filter(
|
|
2332
|
+
.filter(Boolean);
|
|
2333
2333
|
}
|
|
2334
2334
|
catch {
|
|
2335
2335
|
return [];
|
|
@@ -2348,7 +2348,7 @@ async function collectDesignTerminalKinds(runDir, designNodeId) {
|
|
|
2348
2348
|
const kind = record.fact.kind;
|
|
2349
2349
|
return typeof kind === "string" ? kind : "";
|
|
2350
2350
|
})
|
|
2351
|
-
.filter(
|
|
2351
|
+
.filter(Boolean);
|
|
2352
2352
|
}
|
|
2353
2353
|
catch {
|
|
2354
2354
|
return [];
|
|
@@ -2974,7 +2974,6 @@ async function executeFrontendCloseout(input, meta) {
|
|
|
2974
2974
|
const contract = frontendImplementationContractSchema.parse(JSON.parse(contractRaw));
|
|
2975
2975
|
const trace = context.verificationTrace;
|
|
2976
2976
|
const verificationTargets = (trace?.targets ?? []).map((target) => ({
|
|
2977
|
-
mode: contract.verificationTargets.find((entry) => entry.id === target.id)?.mode ?? "static",
|
|
2978
2977
|
status: target.status === "ok" ? "ok" : "failed",
|
|
2979
2978
|
}));
|
|
2980
2979
|
const mockEvidenceBound = contract.mockApi.strategy !== "not-needed" &&
|
|
@@ -94,43 +94,48 @@ const DAG_RUNS_PREFIX = ".harness/dag-runs/";
|
|
|
94
94
|
* They are not product evidence and must not fail exclusive write guards.
|
|
95
95
|
* Intentional report/product writes remain governed by writePolicy/writeSet.
|
|
96
96
|
*/
|
|
97
|
-
|
|
97
|
+
export function isEphemeralToolCachePath(filePath) {
|
|
98
|
+
const normalized = normalizePath(filePath);
|
|
99
|
+
if (!normalized)
|
|
100
|
+
return false;
|
|
98
101
|
// CodeGraph extension sync side effect (plan 2026-08-21 D7): a loaded
|
|
99
102
|
// pi-codegraph extension keeps an existing .codegraph/ index fresh at
|
|
100
103
|
// session start; those index files are extension-owned run state, not
|
|
101
104
|
// writer output, so they never count as write-guard violations.
|
|
102
|
-
".codegraph"
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
".
|
|
105
|
+
if (normalized === ".codegraph" || normalized.startsWith(".codegraph/")) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
if (normalized === ".pytest_cache" ||
|
|
109
|
+
normalized.startsWith(".pytest_cache/")) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
if (normalized === ".mypy_cache" || normalized.startsWith(".mypy_cache/")) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
if (normalized === ".ruff_cache" || normalized.startsWith(".ruff_cache/")) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
106
118
|
// playwright-cli default session dumps (console/page/network) under repo cwd.
|
|
107
119
|
// Real browser case evidence must still be written under testcase/** explicitly.
|
|
108
|
-
".playwright-cli"
|
|
109
|
-
|
|
110
|
-
|
|
120
|
+
if (normalized === ".playwright-cli" ||
|
|
121
|
+
normalized.startsWith(".playwright-cli/")) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
if (normalized === ".coverage" || normalized.startsWith(".coverage.")) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
111
127
|
// vite/vitest runtime caches live under node_modules/.vite (e.g.
|
|
112
128
|
// node_modules/.vite/vitest/results.json). node_modules is the gitignored
|
|
113
129
|
// dependency tree — tool cache writes there are never a writer's product
|
|
114
130
|
// change and must not trip the write guard.
|
|
115
|
-
"node_modules/.vite"
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
/\.(?:pyc|pyo)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return names.some((name) => value === name || value.startsWith(`${name}/`));
|
|
124
|
-
}
|
|
125
|
-
export function isEphemeralToolCachePath(filePath) {
|
|
126
|
-
const normalized = normalizePath(filePath);
|
|
127
|
-
if (!normalized)
|
|
128
|
-
return false;
|
|
129
|
-
return (isExactOrChildPath(normalized, EPHEMERAL_CACHE_DIRS) ||
|
|
130
|
-
EPHEMERAL_CACHE_DIR_PREFIXES.some((prefix) => normalized.startsWith(`${prefix}/`)) ||
|
|
131
|
-
EPHEMERAL_CACHE_FILES.has(normalized) ||
|
|
132
|
-
normalized.startsWith(".coverage.") ||
|
|
133
|
-
EPHEMERAL_CACHE_PATH_PATTERNS.some((pattern) => pattern.test(normalized)));
|
|
131
|
+
if (normalized.startsWith("node_modules/.vite/")) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
if (/(?:^|\/)__pycache__(?:\/|$)/.test(normalized))
|
|
135
|
+
return true;
|
|
136
|
+
if (/\.(?:pyc|pyo)$/.test(normalized))
|
|
137
|
+
return true;
|
|
138
|
+
return false;
|
|
134
139
|
}
|
|
135
140
|
/** MVP post-run guard: only paths that changed during the shell node are checked. */
|
|
136
141
|
export function validateShellWriteGuard(input) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { shouldRewriteAssistantTransientProviderError } from "../pi-provider-recovery.js";
|
|
2
1
|
import { buildOverflowCheckpoint } from "./checkpoint.js";
|
|
3
2
|
import { shouldRewriteAssistantOverflow } from "./overflow.js";
|
|
4
3
|
import { clearRetrieveBypass, compressProviderPayload, createSiftRetrieveToolDefinition, SIFT_RETRIEVE_TOOL_NAME, } from "./sift-bridge.js";
|
|
@@ -12,44 +11,35 @@ export function createCompactionController() {
|
|
|
12
11
|
export function createContextPressureExtension(options) {
|
|
13
12
|
const l2 = options.policy.mode !== "off";
|
|
14
13
|
const l1 = Boolean(options.sift);
|
|
15
|
-
|
|
16
|
-
if (!l2 && !l1 && !transientRecovery)
|
|
14
|
+
if (!l2 && !l1)
|
|
17
15
|
return undefined;
|
|
18
16
|
return {
|
|
19
17
|
name: options.name ?? "operator-chat-context-pressure",
|
|
20
18
|
hidden: true,
|
|
21
19
|
factory: (api) => {
|
|
22
|
-
if (l2
|
|
20
|
+
if (l2) {
|
|
23
21
|
api.on("message_end", (event) => {
|
|
24
22
|
const message = event.message;
|
|
25
23
|
if (!message || typeof message !== "object")
|
|
26
24
|
return undefined;
|
|
27
25
|
const rec = message;
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
options.controller.lastError = rec.errorMessage;
|
|
31
|
-
}
|
|
32
|
-
if (rec.role === "assistant") {
|
|
33
|
-
clearRetrieveBypassIfPresent(options.sift);
|
|
34
|
-
}
|
|
35
|
-
const rewritten = shouldRewriteAssistantOverflow(message);
|
|
36
|
-
if (rewritten) {
|
|
37
|
-
incrementCounter(options.controller.counters, "overflow");
|
|
38
|
-
return {
|
|
39
|
-
message: {
|
|
40
|
-
...rec,
|
|
41
|
-
errorMessage: rewritten,
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
}
|
|
26
|
+
if (typeof rec.errorMessage === "string") {
|
|
27
|
+
options.controller.lastError = rec.errorMessage;
|
|
45
28
|
}
|
|
46
|
-
if (
|
|
47
|
-
|
|
29
|
+
if (rec.role === "assistant") {
|
|
30
|
+
clearRetrieveBypassIfPresent(options.sift);
|
|
48
31
|
}
|
|
49
|
-
|
|
32
|
+
const rewritten = shouldRewriteAssistantOverflow(message);
|
|
33
|
+
if (!rewritten)
|
|
34
|
+
return undefined;
|
|
35
|
+
incrementCounter(options.controller.counters, "overflow");
|
|
36
|
+
return {
|
|
37
|
+
message: {
|
|
38
|
+
...rec,
|
|
39
|
+
errorMessage: rewritten,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
50
42
|
});
|
|
51
|
-
}
|
|
52
|
-
if (l2) {
|
|
53
43
|
api.on("session_before_compact", (event) => {
|
|
54
44
|
const reason = event.reason;
|
|
55
45
|
if (reason === "overflow") {
|
|
@@ -21,43 +21,3 @@ export const PI_RECOMMENDED_RETRY = {
|
|
|
21
21
|
},
|
|
22
22
|
};
|
|
23
23
|
export const PI_RECOMMENDED_COMPACTION = { enabled: true };
|
|
24
|
-
function validBoolean(value) {
|
|
25
|
-
return typeof value === "boolean";
|
|
26
|
-
}
|
|
27
|
-
function validNonNegativeNumber(value) {
|
|
28
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
29
|
-
}
|
|
30
|
-
function preferredOptionalNonNegativeNumber(...values) {
|
|
31
|
-
return values.find(validNonNegativeNumber);
|
|
32
|
-
}
|
|
33
|
-
function preferredValue(projectValue, globalValue, fallback, isValid) {
|
|
34
|
-
if (isValid(projectValue))
|
|
35
|
-
return projectValue;
|
|
36
|
-
if (isValid(globalValue))
|
|
37
|
-
return globalValue;
|
|
38
|
-
return fallback;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Apply Console-owned retry defaults without writing settings files.
|
|
42
|
-
* Explicit project fields win over global fields, which win over defaults.
|
|
43
|
-
*/
|
|
44
|
-
export function applyProcessRetryOverride(manager) {
|
|
45
|
-
if (!manager?.applyOverrides)
|
|
46
|
-
return { applied: false };
|
|
47
|
-
const project = manager.getProjectSettings?.()?.retry;
|
|
48
|
-
const global = manager.getGlobalSettings?.()?.retry;
|
|
49
|
-
const currentProvider = manager.getProviderRetrySettings?.();
|
|
50
|
-
const timeoutMs = preferredOptionalNonNegativeNumber(project?.provider?.timeoutMs, global?.provider?.timeoutMs, currentProvider?.timeoutMs);
|
|
51
|
-
const retry = {
|
|
52
|
-
enabled: preferredValue(project?.enabled, global?.enabled, PI_RECOMMENDED_RETRY.enabled, validBoolean),
|
|
53
|
-
maxRetries: preferredValue(project?.maxRetries, global?.maxRetries, PI_RECOMMENDED_RETRY.maxRetries, validNonNegativeNumber),
|
|
54
|
-
baseDelayMs: preferredValue(project?.baseDelayMs, global?.baseDelayMs, PI_RECOMMENDED_RETRY.baseDelayMs, validNonNegativeNumber),
|
|
55
|
-
provider: {
|
|
56
|
-
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
57
|
-
maxRetries: preferredValue(project?.provider?.maxRetries, global?.provider?.maxRetries, PI_RECOMMENDED_RETRY.provider.maxRetries, validNonNegativeNumber),
|
|
58
|
-
maxRetryDelayMs: preferredValue(project?.provider?.maxRetryDelayMs, global?.provider?.maxRetryDelayMs, PI_RECOMMENDED_RETRY.provider.maxRetryDelayMs, validNonNegativeNumber),
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
manager.applyOverrides({ retry });
|
|
62
|
-
return { applied: true, retry };
|
|
63
|
-
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isFeatureStudyTask } from './reference-context.js';
|
|
4
|
+
export async function loadPrompt(repoRoot, step, taskConfig) {
|
|
5
|
+
const filename = resolvePromptFilename(step, taskConfig);
|
|
6
|
+
const promptPath = path.join(repoRoot, '.harness', 'prompts', filename);
|
|
7
|
+
try {
|
|
8
|
+
return await readFile(promptPath, 'utf-8');
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
if (filename !== `${step}.md`) {
|
|
12
|
+
return readFile(path.join(repoRoot, '.harness', 'prompts', `${step}.md`), 'utf-8');
|
|
13
|
+
}
|
|
14
|
+
throw new Error(`prompt not found: ${promptPath}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function resolvePromptFilename(step, taskConfig) {
|
|
18
|
+
if (!taskConfig || !isFeatureStudyTask(taskConfig)) {
|
|
19
|
+
return `${step}.md`;
|
|
20
|
+
}
|
|
21
|
+
if (step === 'analyze')
|
|
22
|
+
return 'feature-study-analyze.md';
|
|
23
|
+
if (step === 'plan')
|
|
24
|
+
return 'feature-study-plan.md';
|
|
25
|
+
return `${step}.md`;
|
|
26
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { safeParseTaskContractDraft } from "./schema.js";
|
|
3
|
+
import { getTaskContractPaths } from "./paths.js";
|
|
4
|
+
import { readSourceManifest } from "../source-references.js";
|
|
5
|
+
function isPathOutsideRepoHint(p) {
|
|
6
|
+
if (path.isAbsolute(p))
|
|
7
|
+
return true;
|
|
8
|
+
if (p.includes("\0"))
|
|
9
|
+
return true;
|
|
10
|
+
const normalized = p.replace(/\\/g, "/");
|
|
11
|
+
if (normalized.startsWith("../") || normalized.includes("/../"))
|
|
12
|
+
return true;
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
export async function validateTaskContractDraft(input) {
|
|
16
|
+
const errors = [];
|
|
17
|
+
const warnings = [];
|
|
18
|
+
const parsed = safeParseTaskContractDraft(input.draft);
|
|
19
|
+
if (!parsed.success) {
|
|
20
|
+
for (const issue of parsed.error.issues) {
|
|
21
|
+
errors.push({
|
|
22
|
+
code: issue.message.includes("schemaVersion") ||
|
|
23
|
+
issue.path[0] === "schemaVersion"
|
|
24
|
+
? "UNSUPPORTED_SCHEMA_VERSION"
|
|
25
|
+
: "INVALID_INPUT",
|
|
26
|
+
path: issue.path.join("."),
|
|
27
|
+
message: issue.message,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
taskId: input.taskId,
|
|
32
|
+
valid: false,
|
|
33
|
+
errors,
|
|
34
|
+
warnings,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const draft = parsed.data;
|
|
38
|
+
if (draft.taskId !== input.taskId) {
|
|
39
|
+
errors.push({
|
|
40
|
+
code: "INVALID_INPUT",
|
|
41
|
+
path: "taskId",
|
|
42
|
+
message: `draft.taskId (${draft.taskId}) does not match task (${input.taskId})`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
for (const p of draft.constraints.allowedPaths) {
|
|
46
|
+
if (isPathOutsideRepoHint(p) && !p.includes("*")) {
|
|
47
|
+
// globs may be relative; absolute is out of repo
|
|
48
|
+
if (path.isAbsolute(p)) {
|
|
49
|
+
errors.push({
|
|
50
|
+
code: "PATH_OUTSIDE_REPO",
|
|
51
|
+
path: "constraints.allowedPaths",
|
|
52
|
+
message: `absolute path not allowed: ${p}`,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const p of draft.constraints.forbiddenPaths) {
|
|
58
|
+
if (path.isAbsolute(p)) {
|
|
59
|
+
errors.push({
|
|
60
|
+
code: "PATH_OUTSIDE_REPO",
|
|
61
|
+
path: "constraints.forbiddenPaths",
|
|
62
|
+
message: `absolute path not allowed: ${p}`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (draft.references && draft.references.length > 0) {
|
|
67
|
+
const paths = getTaskContractPaths(input.repoRoot, input.taskId);
|
|
68
|
+
const manifest = await readSourceManifest(paths.sourceDir);
|
|
69
|
+
if (!manifest) {
|
|
70
|
+
warnings.push({
|
|
71
|
+
code: "MISSING_SOURCE_MANIFEST",
|
|
72
|
+
message: "draft references present but source-manifest.json is missing; import-prd first for immutable evidence",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
for (const ref of draft.references) {
|
|
77
|
+
const normalized = ref.ref.replace(/\\/g, "/");
|
|
78
|
+
const hit = manifest.documents.some((doc) => {
|
|
79
|
+
const mat = doc.materializedPath.replace(/\\/g, "/");
|
|
80
|
+
return (mat === normalized ||
|
|
81
|
+
`source/${mat}` === normalized ||
|
|
82
|
+
normalized.endsWith(mat));
|
|
83
|
+
});
|
|
84
|
+
if (!hit) {
|
|
85
|
+
warnings.push({
|
|
86
|
+
code: "REFERENCE_NOT_IN_MANIFEST",
|
|
87
|
+
message: `reference not found in source-manifest: ${ref.ref}`,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (draft.sourceResolutions &&
|
|
94
|
+
draft.sourceResolutions.some((r) => r.decidedBy !== "human")) {
|
|
95
|
+
warnings.push({
|
|
96
|
+
code: "NON_HUMAN_SOURCE_RESOLUTION",
|
|
97
|
+
message: "one or more sourceResolutions are not decidedBy=human; blocking conflicts require human resolution before apply",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
taskId: input.taskId,
|
|
102
|
+
valid: errors.length === 0,
|
|
103
|
+
errors,
|
|
104
|
+
warnings,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./ids.js";
|
|
2
|
+
export * from "./paths.js";
|
|
3
|
+
export * from "./source-state.js";
|
|
4
|
+
export * from "./lifecycle.js";
|
|
5
|
+
export * from "./goal.js";
|
|
6
|
+
export * from "./subagent-guidance.js";
|
|
7
|
+
export * from "./runtime.js";
|
|
8
|
+
export * from "./config.js";
|
|
9
|
+
export * from "./worktree.js";
|
|
10
|
+
export * as taskContract from "./contract/index.js";
|
|
11
|
+
export * as taskOperator from "./operator/index.js";
|
|
12
|
+
export * from "./contract/index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createTask, getNextStep, getSupportedNextCommand, getTaskStatus, markStepCompleted, markTaskCompleted, markTaskFailed, markTaskRunning, markVerifyGoalPending, resolveTaskFlow, shouldRunRetrospective, } from "./runtime.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compatibility re-export — canonical capabilities document lives in
|
|
3
|
+
* src/shared/operator (includes Console negotiation `dag` block).
|
|
4
|
+
* No independent projection / dual implementation.
|
|
5
|
+
*/
|
|
6
|
+
export { buildOperatorCapabilitiesDocument, } from "../../shared/operator/capabilities.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getTaskDir, getTaskPaths, listTaskSourceFiles, } from "./runtime.js";
|
|
@@ -69,7 +69,7 @@ const reviewResponseSchema = z.object({
|
|
|
69
69
|
disposition: z.enum(FRAGMENT_DISPOSITIONS).optional(),
|
|
70
70
|
reason: z.string().min(1).optional(),
|
|
71
71
|
})
|
|
72
|
-
.
|
|
72
|
+
.optional(),
|
|
73
73
|
});
|
|
74
74
|
/**
|
|
75
75
|
* 模型队列构建镜像 semantic-intake.ts:MED→HIGH→LOW(harness executors.pi)+
|
|
@@ -134,7 +134,7 @@ function buildReviewPrompt(request) {
|
|
|
134
134
|
"- approved: true only when the exclusion/conflict handling is justified.",
|
|
135
135
|
"- fragmentId: MUST equal the requested fragment id exactly (echo the `fragment id:` line verbatim); identity mismatch is rejected.",
|
|
136
136
|
"- reason: recommended; explain the verdict.",
|
|
137
|
-
"- revision:
|
|
137
|
+
"- revision: optional single bounded revision {disposition, reason}; never invent requirements or human resolutions.",
|
|
138
138
|
JSON.stringify({
|
|
139
139
|
fragmentId: "REQ-SRC-AB12CD34EF56",
|
|
140
140
|
approved: true,
|