chainlesschain 0.166.104 → 0.166.106
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/README.md +15 -4
- package/package.json +2 -1
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-Bah3HREy.js → AIOps-CKwEku2e.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DY2aeZMc.js → ActionButton-BSUOuTpW.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BFly8Xaa.js → Analytics-CGxvL_FI.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-dp0Zz-JM.js → AppLayout-bCPwz-5w.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-DcIg09ai.js → Artifacts-2_BOWo6e.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DkN-lsjZ.js → Audit-CBOruzgW.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BjzgusLx.js → BackgroundAgents-lg0IU5HN.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CU8S6qu9.js → Backup-OspCi452.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-B1pC2gjL.js → BaseInput-BMkliqlz.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-B6xFp6gD.js → Chat-BfoiUZwp.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-DxNCLZ_X.js → ChatBubbleRenderer-BjnfMwep.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-QHw7Vc4U.js → Checkbox-jTMlkNQZ.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-gdecsfjg.js → Codegen-CycyJcnU.js} +1 -1
- package/src/assets/web-panel/assets/{Col-B0_JmAmc.js → Col-BVWlReQj.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DRCcP5xR.js → Community-CKRHl4xK.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DZtoGzhX.js → Compact-BtpfMdhT.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BfNTvEnT.js → Compliance-DtHB1Ct1.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CDXTLm84.js → Cowork-D_8X7-RK.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-Big35CbN.js → Cron-DMCOyvEa.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-C8ArrAVr.js → Crosschain-CeHdsu7m.js} +1 -1
- package/src/assets/web-panel/assets/{DID-D_77BI2O.js → DID-CL6mR6zX.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-D2SxTzEp.js → Dashboard-oz9n6DC7.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-mR1-b9ud.js → Dropdown-CbWm8mWu.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DPl7TE1c.js → EmailListRenderer-DXlmbC45.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-BxRYLRSH.js → EvolutionSettings-DPwqgRYm.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-rnGtXJ5Z.js → FamilyGuardDashboard-DkV4YMFj.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BpxenYK8.js → Federation-CpUKHIOH.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cz1kDf6l.js → FormItemContext-C6KXRgjR.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CGV3KN6U.js → GenericCardRenderer-C5Y4L5E3.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CIRP4UTx.js → Git-CBwKdF8s.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DX4r8Vmt.js → Governance-Dt-OR7Aa.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DQKk02Hl.js → Inference-Czkl-Lhl.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DdD6J-By.js → KnowledgeGraph-C7NE4949.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DA2w-1_m.js → Logs-CoAuZiMG.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-C9aSGETh.js → MarkdownRenderer-DTkjTwGI.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-BsJ6_6KW.js → Marketplace-IzrV-7zH.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-_6k30z6u.js → McpTools-DYEea7aS.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-C0_dYY0A.js → Memory-Uqe7ZrV6.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CCTnVqiC.js → MobileBridge-D092EGyM.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-CwA1VoVJ.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-D4Ys8lvX.js → Mtc-gg4jzfB-.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BKTC--a2.js → MtcAudit-BibGfs71.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-CGR1qOe1.js → Multisig-BmB5yRXP.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-hKKD4qWb.js → NLProgramming-BBSlPDyY.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-pCn7Ec40.js → Notes-Bui3-KiC.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-B9eEJXEs.js → NotificationSettings-ovXtbHe5.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-Bq-qD7eG.js +1 -0
- package/src/assets/web-panel/assets/{Organization-CcQbrnwW.js → Organization-DacIY9oJ.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-HmD4Mn72.js → Overflow-CX8osheZ.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-B7LIgx5H.js → P2P-1lnikqVp.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CXiHnBfX.js → PdhVaultBrowser-DCrU-V6A.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CQRI3y_l.js → Permissions-Dfcb6kM2.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-1EeHmsy5.js → PersonalDataHub-dvgai4hf.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-BFyoIdn8.js → Pipeline-nymAEtnK.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BxWthXMF.js → Privacy-D0Vd91oM.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DfigBilu.js → ProjectInit-BpUBcu7o.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CFmIcVc-.js → ProjectSettings-DIzwTT-M.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-CR7H59v3.js → Projects-Den4RUw6.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-2ulom-76.js → Providers-Cq8p-M0d.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BwhO07b_.js → QrScannerModal-DSmqOfYk.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-_Wg34OwF.js → QuickAsk-BDHCeSnA.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-D_jq6Svg.js → Recommend-B_9M8oF4.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BlzvEfsa.js → RemoteSession-5ot4leHy.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-9CTXHfL4.js → Reputation-B3F013PY.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DlCYCN-t.js → Row-BMyBJnZw.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BvlInFCH.js → RssFeed-WmV0l52g.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CfaUzKuL.js → Search-Wl80yXnR.js} +1 -1
- package/src/assets/web-panel/assets/{Security-bAWgLyve.js → Security-gbDMKb5m.js} +4 -4
- package/src/assets/web-panel/assets/{Services-C4LOGACW.js → Services-Bx2Bjhah.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-Dd0Uwh3_.js → Skeleton-BvJNybjV.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-ZYF1kYCU.js → Skills-Tz4rQcDp.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DpsmIaEo.js → Sla-BM9gyZwc.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BBXoJ4yc.js → SpeechSettings-Bu9FL9Tz.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-SOnROi2Y.js → SyncSettings-D8ICJsMt.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-HFA_ZlDk.js → Tasks-B6MowBDo.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-fsK-RCEc.js → Templates-BJzpTD0W.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CuqYxamb.js → Tenant-BN8eX4R2.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-GKlI2R5F.js → Terminal-CjtP9bpq.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DMDMHLeY.js → TimelineRenderer-CpNRa4XW.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BoV60rh3.js → Tokens-2lNNvNAH.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CE344-Ws.js → Trigger-DxtxXyPg.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DENwgkVc.js → Trust-CakzGeF9.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-FrcM7yfm.js → UkeySign-CvJeRXwV.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DAY9WaC2.js → VideoEditing-D80pMzcO.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BuUR5i82.js → Wallet-BF-VOBmZ.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-nfSQuq85.js → WebAuthn-DXyoAzE_.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-DHhPOp9l.js → WorkflowEditor-X6CDxzrF.js} +1 -1
- package/src/assets/web-panel/assets/{chat-C4nsLzYy.js → chat-BcUhqjeA.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BwXH0Wjn.js → colors-Dw4bKaCm.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-uApFG30S.js → compact-item-BWhu5Eri.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BpyYs4fe.js → createContext-BLJ9JKoN.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-D_MJgDGJ.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-MXCLi00p.js → hasIn-DIkCiJbt.js} +1 -1
- package/src/assets/web-panel/assets/{index-IvgszJ3C.js → index-04SKBH8l.js} +1 -1
- package/src/assets/web-panel/assets/{index-1LxX2IwJ.js → index-0mHbawfQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CF0bUOP4.js → index-5vzPcr1g.js} +1 -1
- package/src/assets/web-panel/assets/{index-CwVvk2i7.js → index-B1fufz1A.js} +1 -1
- package/src/assets/web-panel/assets/{index-pgHGBAoF.js → index-BAwcMKaD.js} +1 -1
- package/src/assets/web-panel/assets/{index-Gz2rGWef.js → index-BGFqk1-E.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dkncxel3.js → index-BGMzh2oj.js} +1 -1
- package/src/assets/web-panel/assets/index-BP8log78.js +1 -0
- package/src/assets/web-panel/assets/{index-Btv--Nnt.js → index-BUC4TZWg.js} +1 -1
- package/src/assets/web-panel/assets/{index-S80LLjdx.js → index-BaStonJm.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLxKx5_J.js → index-BcTch6Fp.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7jojVc7.js → index-BipG-tDs.js} +1 -1
- package/src/assets/web-panel/assets/{index-nn22NSDK.js → index-BotMuGS2.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRmNdEk_.js → index-BxLDNxEQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3_tj06B.js → index-BxfimJOH.js} +1 -1
- package/src/assets/web-panel/assets/{index-XHBXtvqp.js → index-C5qms36i.js} +1 -1
- package/src/assets/web-panel/assets/{index-DffWVpZv.js → index-CDfB6hWf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNjUPfJP.js → index-CFGOV-YT.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaBwXpAp.js → index-CTPoBbIR.js} +1 -1
- package/src/assets/web-panel/assets/{index-xLGf7f9K.js → index-CXJ8t1hK.js} +1 -1
- package/src/assets/web-panel/assets/{index-pCIAE2yS.js → index-CgsVg5Up.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiIpIYhs.js → index-Cmc7qH2C.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOhjapd5.js → index-CqGqoID5.js} +1 -1
- package/src/assets/web-panel/assets/{index-61CBBrHE.js → index-Cr05twNa.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dn12gJJU.js → index-D-Erv8A9.js} +1 -1
- package/src/assets/web-panel/assets/{index-pRpMLhMt.js → index-D1r2R4a-.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_oOpXhP.js → index-D3wp_jgy.js} +1 -1
- package/src/assets/web-panel/assets/{index-Daco83me.js → index-D5vFJmmX.js} +1 -1
- package/src/assets/web-panel/assets/{index-DucLR6YX.js → index-DHLW27Je.js} +1 -1
- package/src/assets/web-panel/assets/{index-ugIUt5TL.js → index-DKzG3kBM.js} +1 -1
- package/src/assets/web-panel/assets/{index-WKbnwbKa.js → index-DOjQi7oU.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTXi_gQh.js → index-DQbWGvE4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DE4W4vLO.js → index-DV4FSjmI.js} +3 -3
- package/src/assets/web-panel/assets/{index-Dt-nq2eF.js → index-DjEP26Te.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChUTKrOq.js → index-LOsZYbic.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0P1Z_oa.js → index-PRYboDFm.js} +1 -1
- package/src/assets/web-panel/assets/index-PexF9zYf.js +1 -0
- package/src/assets/web-panel/assets/{index-Du01X9N9.js → index-u0tqS0iq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEGMfaOo.js → index-uMtx6e3D.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C58CkKEo.js → initDefaultProps-Bx6Hj_FG.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BLWPO2NV.js → motion-BSWivB70.js} +1 -1
- package/src/assets/web-panel/assets/{move-BgrFMwYp.js → move-Dv1Pg9R7.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Cq2AuGzl.js → mtc-parser-Bqtl8fsk.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Bb-9L7if.js → omit-DpOBjOSQ.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-vLmOxYr1.js → pickAttrs-D-M-dz48.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BNySU_dJ.js → placementArrow-DsTLAifk.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-xnbwagnm.js → responsiveObserve-BVTetMpc.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BccbY5Cn.js → slide-abEcz-Cv.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DOp9d2-w.js → statusUtils-CBhrdU2G.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Bu1w6ho9.js → styleChecker-CFq8ZCKa.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-ZsUOrVdL.js → useFlexGapSupport-o4eE7fDV.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-C0zpzKtO.js → useFs-Hs9W8ihi.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DO1OdgXK.js → usePersonalDataHub-Bnet5Jho.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-jTIRyhR5.js → vnode-DJfN4kWs.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DKvS7-Qs.js → zoom-BzV-2e7X.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +26 -0
- package/src/lib/coding-task-guidance.js +15 -0
- package/src/lib/file-import-diagnostics.js +246 -0
- package/src/lib/provider-http-error.js +4 -5
- package/src/lib/transport-error-details.js +83 -0
- package/src/runtime/agent-core.js +137 -2
- package/src/runtime/coding-agent-contract-shared.cjs +3 -2
- package/src/runtime/headless-runner.js +83 -49
- package/src/runtime/headless-stream.js +8 -2
- package/src/assets/web-panel/assets/MobileProjects-RZdxDSwC.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CmJuhaT2.js +0 -1
- package/src/assets/web-panel/assets/devWarning-Bk6HGn3N.js +0 -1
- package/src/assets/web-panel/assets/index-Bb1LPYdi.js +0 -1
- package/src/assets/web-panel/assets/index-C-FsTuFG.js +0 -1
package/src/data/changelog.json
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "CHANGELOG.md",
|
|
3
3
|
"releases": [
|
|
4
|
+
{
|
|
5
|
+
"productVersion": null,
|
|
6
|
+
"cliVersion": "0.166.106",
|
|
7
|
+
"cliVersions": ["0.166.105", "0.166.106"],
|
|
8
|
+
"date": "2026-10-18",
|
|
9
|
+
"title": "",
|
|
10
|
+
"sections": [
|
|
11
|
+
{
|
|
12
|
+
"heading": "Fixed - cc CLI 0.166.106: task delivery follow-up (candidate, 2026-10-18)",
|
|
13
|
+
"body": "- Guide coding tasks toward brief action statements and complete file writes split into bounded segments.\n- Ground regression expectations and defaults in the source contract, exercise actual boundaries with valid fault-injection fixtures, and use independent expected values or authoritative state.\n- Preserve the explicit provider reason for HTTP 403 responses that are not authentication or billing errors.\n- Keep JetBrains asynchronous draft-save receipts in a separate status update so they do not interrupt the assistant reply.\n- Wait up to two seconds for final JetBrains stdout callbacks on the background process waiter and schedule exit alongside result rendering on the IDE event queue.\n- Close unused Windows ACL subprocess input, require complete output before success, and share one bounded drain/cleanup deadline; native ACL startup timeouts remain under investigation.\n- Pair candidate VS Code 0.37.151 and JetBrains 0.4.168 with CLI 0.166.106; retain the existing published child-package versions.\n- Current public versions remain CLI 0.166.105, Open VSX 0.37.150 and JetBrains 0.4.167. Publish this candidate only after complete exact-commit gates, npm OIDC and public artifact readback, then retest unfinished samples.\n- Public .105 retesting completed generation 20/20 and acceptance 20/20, adding 6 candidate acceptances and 6 full-flow passes. Cumulative acceptance is 31/45 (ordinary 26/36, first-use 5/9), with 14 remaining. The original 25 accepted artifacts were reused byte-for-byte; cross-version cumulative acceptance is not a single-round 45/45 success. Candidates .106/.151/.168 remain unpublished and have not been retested."
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"productVersion": null,
|
|
19
|
+
"cliVersion": "0.166.105",
|
|
20
|
+
"cliVersions": ["0.166.105"],
|
|
21
|
+
"date": "2026-10-18",
|
|
22
|
+
"title": "",
|
|
23
|
+
"sections": [
|
|
24
|
+
{
|
|
25
|
+
"heading": "Fixed - cc CLI 0.166.105: task delivery quality and safe diagnostics (candidate, 2026-10-18)",
|
|
26
|
+
"body": "- Add general coding guidance and static relative-import feedback without executing candidate code or injecting task-specific answers.\n- Do not report completion while deferred writes remain; distinguish provider transport aborts from owned cancellation.\n- Preserve bounded allowlisted transport cause details without changing original errors, exits, fetch, retries or replay.\n- Pair candidate VS Code 0.37.150 and JetBrains 0.4.167 with CLI 0.166.105 after exact-commit matrices, OIDC publishing and public readback. JetBrains restores saved Markdown consistently with live rendering.\n- Campaign: 25/45 cumulative candidate acceptances; latest 22/25 collected, 4 end-to-end passes, 3 Windows JetBrains samples ongoing. New versions are not yet published or retested."
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
4
30
|
{
|
|
5
31
|
"productVersion": null,
|
|
6
32
|
"cliVersion": "0.166.104",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Shared correctness guidance for normal and file-only coding sessions. */
|
|
2
|
+
export const CODING_TASK_QUALITY_GUIDANCE = `Coding task quality:
|
|
3
|
+
- Read the actual implementation and its exported API before writing a caller or test. Check parameter order, return shapes, asynchronous lifecycle and fixture requirements against the source; an example in another directory can have different relative imports.
|
|
4
|
+
- Keep progress explanations to one or two sentences. Once the relevant API and behavior are clear, make the next tool call; resolve a remaining uncertainty with a targeted read. Put implementation code directly in write/edit tool arguments instead of rehearsing the code or repeatedly analyzing the same source in ordinary assistant text.
|
|
5
|
+
- Resolve each relative import from the destination file's directory. Read back the completed file and fix newDiagnostics from write/edit results before finishing. A successful write confirms persistence, not syntax, test execution or acceptance.
|
|
6
|
+
- Regression tests need a working positive control and a negative control that exercises the requested behavior through the real production entry point. Assert observable effects; avoid mocks or alternate calls that bypass the behavior under test. Complete the current worker/request when testing cancellation and replacement.
|
|
7
|
+
- For boundary regressions, derive expected defaults, computed values and rejection rules from the implementation or the explicit requested contract. Inject mismatched, tampered or stale input through the real entry point while keeping other prerequisites valid; verify that the fixture reaches the intended check rather than failing during setup. Compare observable results with independent expected values or authoritative state, not a helper that merely recomputes the same result.
|
|
8
|
+
- Use available execution tools for a focused check when permitted. When execution tools are unavailable, inspect imports, API contracts and fixtures using the available file tools, and clearly say that tests were not run. Never describe a read-back or static check as a passing test or end-to-end verification.
|
|
9
|
+
- Finish requested file changes before the final response. Reserve output and remaining requests for writing, read-back and focused validation. For large files, aim for a few thousand characters of new content per call: write a small complete section, then extend it with edit_file using a unique existing anchor and a replacement containing that anchor plus the next complete section. Keep each tool call complete and wait for its result before extending the file again; do not repeatedly rewrite the growing file. State what was delivered, what was checked and what remains unverified.`;
|
|
10
|
+
|
|
11
|
+
export const HERMETIC_CODING_SYSTEM_PROMPT = `You are a hermetic coding assistant. The exposed file tools are the complete tool surface. Inspect and mutate only the exact paths authorized by the user request. Do not invoke hidden tools, commands, language servers or other execution paths.
|
|
12
|
+
|
|
13
|
+
${CODING_TASK_QUALITY_GUIDANCE}
|
|
14
|
+
|
|
15
|
+
Return a concise, evidence-based completion message within these tool limits.`;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parse } from "acorn";
|
|
4
|
+
|
|
5
|
+
export const FILE_IMPORT_LIMITS = Object.freeze({
|
|
6
|
+
contentBytes: 256 * 1024,
|
|
7
|
+
references: 64,
|
|
8
|
+
specifierChars: 512,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const JS_EXTENSION = /\.(?:js|mjs|cjs)$/;
|
|
12
|
+
|
|
13
|
+
function inside(root, target) {
|
|
14
|
+
const relative = path.relative(root, target);
|
|
15
|
+
return (
|
|
16
|
+
relative === "" ||
|
|
17
|
+
(!path.isAbsolute(relative) &&
|
|
18
|
+
relative !== ".." &&
|
|
19
|
+
!relative.startsWith(`..${path.sep}`))
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Inspect each component before descending. Never stat/realpath a link, read
|
|
24
|
+
// target contents, enumerate directories, or include OS errors in feedback.
|
|
25
|
+
// As with other path-based Node APIs, this is not atomic against directory
|
|
26
|
+
// replacement by another process. The caller supplies its authorized root.
|
|
27
|
+
function inspectPath(root, target) {
|
|
28
|
+
if (!inside(root, target)) return "outside-workspace";
|
|
29
|
+
const components = path
|
|
30
|
+
.relative(root, target)
|
|
31
|
+
.split(path.sep)
|
|
32
|
+
.filter(Boolean);
|
|
33
|
+
let current = root;
|
|
34
|
+
for (let index = -1; index < components.length; index++) {
|
|
35
|
+
if (index >= 0) current = path.join(current, components[index]);
|
|
36
|
+
let stat;
|
|
37
|
+
try {
|
|
38
|
+
stat = fs.lstatSync(current);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
return error?.code === "ENOENT" ? "missing" : "unavailable";
|
|
41
|
+
}
|
|
42
|
+
if (stat.isSymbolicLink()) return "symbolic-link";
|
|
43
|
+
if (index < components.length - 1 && !stat.isDirectory()) {
|
|
44
|
+
return "missing";
|
|
45
|
+
}
|
|
46
|
+
if (index === components.length - 1) {
|
|
47
|
+
return stat.isFile() ? "file" : "not-file";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return "not-file";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function inspectReference(root, target, kind) {
|
|
54
|
+
const state = inspectPath(root, target);
|
|
55
|
+
if (kind !== "require") return state;
|
|
56
|
+
// CommonJS can load directories and append extensions even when a request
|
|
57
|
+
// already has a suffix. Do not claim those uncertain cases are unresolved.
|
|
58
|
+
if (state === "not-file") return "commonjs-resolution";
|
|
59
|
+
if (state === "missing") {
|
|
60
|
+
for (const extension of [".js", ".json", ".node"]) {
|
|
61
|
+
const fallback = inspectPath(root, target + extension);
|
|
62
|
+
if (fallback !== "missing" && fallback !== "not-file") {
|
|
63
|
+
return "commonjs-resolution";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return state;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function parseSource(content, extension) {
|
|
71
|
+
const options = { ecmaVersion: "latest", locations: true };
|
|
72
|
+
if (extension === ".cjs") {
|
|
73
|
+
return parse(content, {
|
|
74
|
+
...options,
|
|
75
|
+
sourceType: "script",
|
|
76
|
+
allowReturnOutsideFunction: true,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
return parse(content, { ...options, sourceType: "module" });
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (extension === ".mjs") throw error;
|
|
83
|
+
return parse(content, {
|
|
84
|
+
...options,
|
|
85
|
+
sourceType: "script",
|
|
86
|
+
allowReturnOutsideFunction: true,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function collectReferences(ast) {
|
|
92
|
+
const references = [];
|
|
93
|
+
const pending = [{ node: ast, parent: null }];
|
|
94
|
+
let uncertainRequire = false;
|
|
95
|
+
let truncated = false;
|
|
96
|
+
while (pending.length) {
|
|
97
|
+
const { node, parent } = pending.pop();
|
|
98
|
+
// Conservative across the whole file: local bindings, assignments, and
|
|
99
|
+
// indirect uses make require's meaning uncertain. Imports remain useful.
|
|
100
|
+
if (
|
|
101
|
+
(node.type === "Identifier" &&
|
|
102
|
+
node.name === "require" &&
|
|
103
|
+
!(parent?.type === "CallExpression" && parent.callee === node)) ||
|
|
104
|
+
node.type === "WithStatement" ||
|
|
105
|
+
(node.type === "CallExpression" && node.callee?.name === "eval")
|
|
106
|
+
) {
|
|
107
|
+
uncertainRequire = true;
|
|
108
|
+
}
|
|
109
|
+
let source;
|
|
110
|
+
let kind;
|
|
111
|
+
if (
|
|
112
|
+
node.type === "ImportDeclaration" ||
|
|
113
|
+
node.type === "ExportNamedDeclaration" ||
|
|
114
|
+
node.type === "ExportAllDeclaration" ||
|
|
115
|
+
node.type === "ImportExpression"
|
|
116
|
+
) {
|
|
117
|
+
source = node.source;
|
|
118
|
+
kind = "import";
|
|
119
|
+
} else if (
|
|
120
|
+
node.type === "CallExpression" &&
|
|
121
|
+
!node.optional &&
|
|
122
|
+
node.callee?.type === "Identifier" &&
|
|
123
|
+
node.callee.name === "require" &&
|
|
124
|
+
node.arguments.length === 1
|
|
125
|
+
) {
|
|
126
|
+
source = node.arguments[0];
|
|
127
|
+
kind = "require";
|
|
128
|
+
}
|
|
129
|
+
if (
|
|
130
|
+
source?.type === "Literal" &&
|
|
131
|
+
typeof source.value === "string" &&
|
|
132
|
+
/^\.{1,2}\//.test(source.value) &&
|
|
133
|
+
JS_EXTENSION.test(source.value) &&
|
|
134
|
+
!/[\\%?#:\u0000-\u001f\u007f]/.test(source.value)
|
|
135
|
+
) {
|
|
136
|
+
if (references.length < FILE_IMPORT_LIMITS.references) {
|
|
137
|
+
references.push({ source, kind });
|
|
138
|
+
} else {
|
|
139
|
+
truncated = true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const children = [];
|
|
143
|
+
for (const value of Object.values(node)) {
|
|
144
|
+
if (value?.type) children.push(value);
|
|
145
|
+
else if (Array.isArray(value)) {
|
|
146
|
+
for (const child of value) if (child?.type) children.push(child);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
150
|
+
pending.push({ node: children[index], parent: node });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return { references, uncertainRequire, truncated };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Best-effort feedback after an authorized write. Only explicit JS relative
|
|
158
|
+
* runtime references are checked, using supplied content and metadata inside
|
|
159
|
+
* workspaceRoot. This does not run code, resolve packages, or prove tests pass.
|
|
160
|
+
* Missing/inaccessible inputs and unsupported syntax never throw to the writer.
|
|
161
|
+
* line/column are one-based. uncheckedReferences never disclose resolved paths.
|
|
162
|
+
*/
|
|
163
|
+
export function collectFileImportDiagnostics(input) {
|
|
164
|
+
const result = {
|
|
165
|
+
status: "skipped",
|
|
166
|
+
diagnostics: [],
|
|
167
|
+
checkedReferences: 0,
|
|
168
|
+
uncheckedReferences: [],
|
|
169
|
+
truncated: false,
|
|
170
|
+
};
|
|
171
|
+
const skip = (reason) => ({ ...result, reason });
|
|
172
|
+
try {
|
|
173
|
+
const { filePath, content, workspaceRoot } = input ?? {};
|
|
174
|
+
if (
|
|
175
|
+
typeof filePath !== "string" ||
|
|
176
|
+
!filePath ||
|
|
177
|
+
filePath.length > 4096 ||
|
|
178
|
+
typeof workspaceRoot !== "string" ||
|
|
179
|
+
!workspaceRoot ||
|
|
180
|
+
workspaceRoot.length > 4096 ||
|
|
181
|
+
!path.isAbsolute(workspaceRoot) ||
|
|
182
|
+
typeof content !== "string"
|
|
183
|
+
) {
|
|
184
|
+
return skip("invalid-input");
|
|
185
|
+
}
|
|
186
|
+
if (!JS_EXTENSION.test(filePath)) return skip("unsupported-file");
|
|
187
|
+
if (
|
|
188
|
+
content.length > FILE_IMPORT_LIMITS.contentBytes ||
|
|
189
|
+
Buffer.byteLength(content, "utf8") > FILE_IMPORT_LIMITS.contentBytes
|
|
190
|
+
) {
|
|
191
|
+
return skip("content-limit");
|
|
192
|
+
}
|
|
193
|
+
const root = path.resolve(workspaceRoot);
|
|
194
|
+
const file = path.resolve(root, filePath);
|
|
195
|
+
if (!inside(root, file)) return skip("outside-workspace");
|
|
196
|
+
const fileState = inspectPath(root, file);
|
|
197
|
+
if (fileState !== "file") return skip(fileState);
|
|
198
|
+
let ast;
|
|
199
|
+
try {
|
|
200
|
+
ast = parseSource(content, path.extname(file));
|
|
201
|
+
} catch {
|
|
202
|
+
return skip("unsupported-syntax");
|
|
203
|
+
}
|
|
204
|
+
const { references, uncertainRequire, truncated } = collectReferences(ast);
|
|
205
|
+
result.status = "checked";
|
|
206
|
+
result.truncated = truncated;
|
|
207
|
+
for (const { source, kind } of references) {
|
|
208
|
+
const location = {
|
|
209
|
+
specifier: source.value.slice(0, FILE_IMPORT_LIMITS.specifierChars),
|
|
210
|
+
line: source.loc.start.line,
|
|
211
|
+
column: source.loc.start.column + 1,
|
|
212
|
+
};
|
|
213
|
+
let state;
|
|
214
|
+
if (source.value.length > FILE_IMPORT_LIMITS.specifierChars) {
|
|
215
|
+
state = "specifier-limit";
|
|
216
|
+
} else if (kind === "require" && uncertainRequire) {
|
|
217
|
+
state = "uncertain-require";
|
|
218
|
+
} else {
|
|
219
|
+
state = inspectReference(
|
|
220
|
+
root,
|
|
221
|
+
path.resolve(path.dirname(file), source.value),
|
|
222
|
+
kind,
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
if (state === "file" || state === "missing" || state === "not-file") {
|
|
226
|
+
result.checkedReferences++;
|
|
227
|
+
if (state !== "file") {
|
|
228
|
+
result.diagnostics.push({
|
|
229
|
+
source: "relative-import",
|
|
230
|
+
code: "UNRESOLVED_RELATIVE_IMPORT",
|
|
231
|
+
severity: "error",
|
|
232
|
+
filePath: file,
|
|
233
|
+
...location,
|
|
234
|
+
message: `Relative import ${JSON.stringify(location.specifier)} does not point to an existing file from this file's directory. Verify the importing file's location before running tests.`,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
result.uncheckedReferences.push({ ...location, reason: state });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
} catch {
|
|
243
|
+
// Do not allow optional feedback to turn a completed mutation into failure.
|
|
244
|
+
return skip("unavailable");
|
|
245
|
+
}
|
|
246
|
+
}
|
|
@@ -84,11 +84,10 @@ export function formatProviderHttpError(
|
|
|
84
84
|
);
|
|
85
85
|
}
|
|
86
86
|
if (status === 403) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
);
|
|
87
|
+
// Gateways can use 403 for request/output policy failures. An explicit
|
|
88
|
+
// reason without auth/billing evidence must not imply a credential fix.
|
|
89
|
+
if (detailSentence) return `${base} — ${detailSentence}.`;
|
|
90
|
+
return `${base} — access forbidden. Check the API key, model access permissions, and account status/balance.`;
|
|
92
91
|
}
|
|
93
92
|
if (status === 429) return `${base} — rate limited; please retry shortly.`;
|
|
94
93
|
return detailSentence ? `${base} — ${detailSentence}` : base;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { types } from "node:util";
|
|
2
|
+
|
|
3
|
+
const NAMES = new Set([
|
|
4
|
+
"Error",
|
|
5
|
+
"TypeError",
|
|
6
|
+
"AggregateError",
|
|
7
|
+
"AbortError",
|
|
8
|
+
"TimeoutError",
|
|
9
|
+
"ConnectTimeoutError",
|
|
10
|
+
"HeadersTimeoutError",
|
|
11
|
+
"BodyTimeoutError",
|
|
12
|
+
"SocketError",
|
|
13
|
+
"RequestAbortedError",
|
|
14
|
+
"ClientDestroyedError",
|
|
15
|
+
"ClientClosedError",
|
|
16
|
+
]);
|
|
17
|
+
const CODES = new Set([
|
|
18
|
+
"ECONNRESET",
|
|
19
|
+
"ECONNREFUSED",
|
|
20
|
+
"ENOTFOUND",
|
|
21
|
+
"EAI_AGAIN",
|
|
22
|
+
"ETIMEDOUT",
|
|
23
|
+
"EHOSTUNREACH",
|
|
24
|
+
"ENETUNREACH",
|
|
25
|
+
"EPIPE",
|
|
26
|
+
"ERR_TLS_CERT_ALTNAME_INVALID",
|
|
27
|
+
"DEPTH_ZERO_SELF_SIGNED_CERT",
|
|
28
|
+
"UNABLE_TO_VERIFY_LEAF_SIGNATURE",
|
|
29
|
+
"CERT_HAS_EXPIRED",
|
|
30
|
+
"ABORT_ERR",
|
|
31
|
+
"UND_ERR_SOCKET",
|
|
32
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
33
|
+
"UND_ERR_HEADERS_TIMEOUT",
|
|
34
|
+
"UND_ERR_BODY_TIMEOUT",
|
|
35
|
+
"UND_ERR_ABORTED",
|
|
36
|
+
"UND_ERR_DESTROYED",
|
|
37
|
+
"UND_ERR_CLOSED",
|
|
38
|
+
"UND_ERR_REQ_CONTENT_LENGTH_MISMATCH",
|
|
39
|
+
"UND_ERR_RES_CONTENT_LENGTH_MISMATCH",
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
// Never invoke accessors, coercion hooks or Proxy traps. Native Error.name is
|
|
43
|
+
// inherited, so inspect a bounded number of prototype data descriptors.
|
|
44
|
+
function data(object, key) {
|
|
45
|
+
for (let depth = 0; depth < 4 && object !== null; depth++) {
|
|
46
|
+
if (typeof object !== "object" || types.isProxy(object)) return undefined;
|
|
47
|
+
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
48
|
+
if (descriptor) return "value" in descriptor ? descriptor.value : undefined;
|
|
49
|
+
object = Object.getPrototypeOf(object);
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Optional diagnostic projection only: no messages, endpoints or request data. */
|
|
55
|
+
export function transportErrorDetails(error) {
|
|
56
|
+
try {
|
|
57
|
+
const name = data(error, "name");
|
|
58
|
+
const code = data(error, "code");
|
|
59
|
+
let causeCode;
|
|
60
|
+
const seen = new Set([error]);
|
|
61
|
+
let cause = error;
|
|
62
|
+
for (let depth = 0; depth < 4; depth++) {
|
|
63
|
+
cause = data(cause, "cause");
|
|
64
|
+
if (!cause || seen.has(cause)) break;
|
|
65
|
+
seen.add(cause);
|
|
66
|
+
const value = data(cause, "code");
|
|
67
|
+
if (CODES.has(value)) {
|
|
68
|
+
causeCode = value;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (!CODES.has(code) && !causeCode) return undefined;
|
|
73
|
+
return {
|
|
74
|
+
kind: "transport",
|
|
75
|
+
...(NAMES.has(name) ? { name } : {}),
|
|
76
|
+
...(CODES.has(code) ? { code } : {}),
|
|
77
|
+
...(causeCode ? { causeCode } : {}),
|
|
78
|
+
};
|
|
79
|
+
} catch {
|
|
80
|
+
// Diagnostics must never replace the original error or exit outcome.
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -49,6 +49,7 @@ import { ReadFileLoopGuard } from "../lib/read-file-loop-guard.js";
|
|
|
49
49
|
import { gitToolInputError } from "../lib/git-tool-input.js";
|
|
50
50
|
import { shellOutputPage, shellOutputPreview } from "../lib/shell-output.js";
|
|
51
51
|
import { DIAGNOSTIC_WORKFLOW_GUIDANCE } from "../lib/diagnostic-workflow.js";
|
|
52
|
+
import { CODING_TASK_QUALITY_GUIDANCE } from "../lib/coding-task-guidance.js";
|
|
52
53
|
import { RemoteReadLoopGuard } from "../lib/remote-read-loop-guard.js";
|
|
53
54
|
import {
|
|
54
55
|
isPrActionRequest,
|
|
@@ -1167,6 +1168,8 @@ export function getBaseSystemPrompt(cwd) {
|
|
|
1167
1168
|
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.
|
|
1168
1169
|
|
|
1169
1170
|
Key behaviors:
|
|
1171
|
+
${CODING_TASK_QUALITY_GUIDANCE}
|
|
1172
|
+
|
|
1170
1173
|
- 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.
|
|
1171
1174
|
- When asked to modify code, read the file first, then edit it
|
|
1172
1175
|
- When asked to create something, use write_file to create it
|
|
@@ -4927,19 +4930,63 @@ export async function _withPostEditDiagnostics(
|
|
|
4927
4930
|
cwd,
|
|
4928
4931
|
additionalDirectories,
|
|
4929
4932
|
managedCheckpoint = false,
|
|
4933
|
+
writtenContent = null,
|
|
4930
4934
|
) {
|
|
4935
|
+
// Parsing the bytes we just wrote is safe even when starting a language
|
|
4936
|
+
// server is forbidden. Feed definite local import mistakes back in the same
|
|
4937
|
+
// tool result; a successful write still means persistence, not test success.
|
|
4938
|
+
let enriched = result;
|
|
4939
|
+
if (
|
|
4940
|
+
result?.success === true &&
|
|
4941
|
+
typeof writtenContent === "string" &&
|
|
4942
|
+
/\.(?:js|mjs|cjs)$/i.test(filePath) &&
|
|
4943
|
+
process.env.CC_EDIT_DIAGNOSTICS !== "0"
|
|
4944
|
+
) {
|
|
4945
|
+
try {
|
|
4946
|
+
const root = pickRootForFile(
|
|
4947
|
+
path.resolve(cwd || process.cwd(), filePath),
|
|
4948
|
+
workspaceRootsFor(cwd, additionalDirectories),
|
|
4949
|
+
);
|
|
4950
|
+
if (root) {
|
|
4951
|
+
const { collectFileImportDiagnostics } = await import(
|
|
4952
|
+
"../lib/file-import-diagnostics.js"
|
|
4953
|
+
);
|
|
4954
|
+
const checked = collectFileImportDiagnostics({
|
|
4955
|
+
filePath,
|
|
4956
|
+
content: writtenContent,
|
|
4957
|
+
workspaceRoot: root,
|
|
4958
|
+
});
|
|
4959
|
+
if (checked.diagnostics.length) {
|
|
4960
|
+
enriched = {
|
|
4961
|
+
...result,
|
|
4962
|
+
newDiagnostics: [
|
|
4963
|
+
...(result.newDiagnostics || []),
|
|
4964
|
+
...checked.diagnostics.slice(0, 8),
|
|
4965
|
+
],
|
|
4966
|
+
};
|
|
4967
|
+
}
|
|
4968
|
+
}
|
|
4969
|
+
} catch {
|
|
4970
|
+
// Optional diagnostics must not turn a persisted edit into a failed one.
|
|
4971
|
+
}
|
|
4972
|
+
}
|
|
4931
4973
|
// A cold language server is a long-lived child process. Starting one inside
|
|
4932
4974
|
// a managed workspace transaction would keep a writer bound past tool
|
|
4933
4975
|
// settlement and make commit/rollback unverifiable. Managed edits therefore
|
|
4934
4976
|
// skip this best-effort enrichment; callers can request diagnostics after the
|
|
4935
4977
|
// checkpoint has sealed.
|
|
4936
|
-
if (managedCheckpoint) return
|
|
4978
|
+
if (managedCheckpoint) return enriched;
|
|
4937
4979
|
const newDiagnostics = await _postEditDiagnostics(
|
|
4938
4980
|
filePath,
|
|
4939
4981
|
cwd,
|
|
4940
4982
|
additionalDirectories,
|
|
4941
4983
|
);
|
|
4942
|
-
return newDiagnostics
|
|
4984
|
+
return newDiagnostics
|
|
4985
|
+
? {
|
|
4986
|
+
...enriched,
|
|
4987
|
+
newDiagnostics: [...(enriched.newDiagnostics || []), ...newDiagnostics],
|
|
4988
|
+
}
|
|
4989
|
+
: enriched;
|
|
4943
4990
|
}
|
|
4944
4991
|
|
|
4945
4992
|
// ─── Lazy subtree instruction injection (large-monorepo lever) ─────────────
|
|
@@ -5791,6 +5838,7 @@ async function executeToolInner(
|
|
|
5791
5838
|
cwd,
|
|
5792
5839
|
additionalDirectories,
|
|
5793
5840
|
managedCheckpoint || hermeticExecution,
|
|
5841
|
+
args.content,
|
|
5794
5842
|
),
|
|
5795
5843
|
filePath,
|
|
5796
5844
|
cwd,
|
|
@@ -5992,6 +6040,7 @@ async function executeToolInner(
|
|
|
5992
6040
|
cwd,
|
|
5993
6041
|
additionalDirectories,
|
|
5994
6042
|
managedCheckpoint || hermeticExecution,
|
|
6043
|
+
newContent,
|
|
5995
6044
|
),
|
|
5996
6045
|
filePath,
|
|
5997
6046
|
cwd,
|
|
@@ -6094,6 +6143,7 @@ async function executeToolInner(
|
|
|
6094
6143
|
cwd,
|
|
6095
6144
|
additionalDirectories,
|
|
6096
6145
|
managedCheckpoint || hermeticExecution,
|
|
6146
|
+
result.content,
|
|
6097
6147
|
),
|
|
6098
6148
|
filePath,
|
|
6099
6149
|
cwd,
|
|
@@ -14622,6 +14672,53 @@ export async function* agentLoop(messages, options) {
|
|
|
14622
14672
|
options.hostResourceBudget || new HostResourceBudget();
|
|
14623
14673
|
const taskProgressTracker =
|
|
14624
14674
|
options.taskProgressTracker || new TaskProgressTracker();
|
|
14675
|
+
// A subtree preflight is deliberately not an executed mutation. Keep this
|
|
14676
|
+
// obligation outside transcript compaction and never replay it automatically.
|
|
14677
|
+
const pendingSubtreeMutations = new Map();
|
|
14678
|
+
let subtreeMutationReprompted = false;
|
|
14679
|
+
const recordSubtreeMutation = (tool, args, result) => {
|
|
14680
|
+
if (!GUARDED_FILE_MUTATION_TOOLS.has(tool)) return;
|
|
14681
|
+
if (!args || typeof args !== "object" || Array.isArray(args)) return;
|
|
14682
|
+
// Invalid tool arguments/results must retain their existing error path;
|
|
14683
|
+
// bookkeeping must not introduce a new exception or completion verdict.
|
|
14684
|
+
const requestedPaths = fileMutationPaths(tool, args);
|
|
14685
|
+
if (
|
|
14686
|
+
!requestedPaths.length ||
|
|
14687
|
+
requestedPaths.some((target) => typeof target !== "string")
|
|
14688
|
+
)
|
|
14689
|
+
return;
|
|
14690
|
+
const targets = [
|
|
14691
|
+
...new Set(
|
|
14692
|
+
requestedPaths.map((target) =>
|
|
14693
|
+
path.resolve(options.cwd || process.cwd(), target),
|
|
14694
|
+
),
|
|
14695
|
+
),
|
|
14696
|
+
].sort();
|
|
14697
|
+
// These tools are alternative ways to deliver content to the same target.
|
|
14698
|
+
// A successful explicit replacement must settle a deferred edit (and vice
|
|
14699
|
+
// versa); move/delete/notebook effects retain their distinct obligations.
|
|
14700
|
+
const effect = ["write_file", "edit_file", "edit_file_hashed"].includes(tool)
|
|
14701
|
+
? "file-content"
|
|
14702
|
+
: tool;
|
|
14703
|
+
const key = JSON.stringify([effect, targets]);
|
|
14704
|
+
if (
|
|
14705
|
+
result?.policy?.via === "subtree-instructions" &&
|
|
14706
|
+
result.policy.decision === "deferred" &&
|
|
14707
|
+
result.mutationPerformed === false
|
|
14708
|
+
) {
|
|
14709
|
+
pendingSubtreeMutations.set(key, { tool, targets });
|
|
14710
|
+
} else if (
|
|
14711
|
+
result &&
|
|
14712
|
+
!result.error &&
|
|
14713
|
+
result.success === true &&
|
|
14714
|
+
result.isError !== true &&
|
|
14715
|
+
result.policy?.decision !== "deny" &&
|
|
14716
|
+
result.policy?.decision !== "deferred" &&
|
|
14717
|
+
result.mutationPerformed !== false
|
|
14718
|
+
) {
|
|
14719
|
+
pendingSubtreeMutations.delete(key);
|
|
14720
|
+
}
|
|
14721
|
+
};
|
|
14625
14722
|
const signal = options.signal || null;
|
|
14626
14723
|
const workflowEffectId = _normalizeWorkflowEffectId(options.workflowEffectId);
|
|
14627
14724
|
// Optional OpenTelemetry recorder (TelemetryRecorder). When present, the loop
|
|
@@ -16397,6 +16494,42 @@ export async function* agentLoop(messages, options) {
|
|
|
16397
16494
|
}
|
|
16398
16495
|
continue;
|
|
16399
16496
|
}
|
|
16497
|
+
if (pendingSubtreeMutations.size) {
|
|
16498
|
+
const pending = [...pendingSubtreeMutations.values()];
|
|
16499
|
+
if (!subtreeMutationReprompted && budget.remaining() > 0) {
|
|
16500
|
+
subtreeMutationReprompted = true;
|
|
16501
|
+
messages.push({ role: "assistant", content: msg.content || "" });
|
|
16502
|
+
messages.push({
|
|
16503
|
+
role: "user",
|
|
16504
|
+
content:
|
|
16505
|
+
"Runtime status: these mutations were deferred before any effect: " +
|
|
16506
|
+
JSON.stringify(pending) +
|
|
16507
|
+
". Review the authoritative subtree instructions already returned. " +
|
|
16508
|
+
"If still authorized and appropriate, explicitly issue the required tool call. " +
|
|
16509
|
+
"Do not bypass rules or perform a prohibited write. Otherwise report the unfinished work and its blocker. " +
|
|
16510
|
+
"A promise to retry does not execute the mutation.",
|
|
16511
|
+
});
|
|
16512
|
+
yield {
|
|
16513
|
+
type: "iteration-warning",
|
|
16514
|
+
message:
|
|
16515
|
+
"Subtree-deferred mutations remain unexecuted; one recovery turn requested.",
|
|
16516
|
+
};
|
|
16517
|
+
continue;
|
|
16518
|
+
}
|
|
16519
|
+
yield {
|
|
16520
|
+
type: "response-complete",
|
|
16521
|
+
content:
|
|
16522
|
+
(msg.content ? msg.content + "\n\n" : "") +
|
|
16523
|
+
"Incomplete: subtree-deferred mutations remain unexecuted.",
|
|
16524
|
+
};
|
|
16525
|
+
yield {
|
|
16526
|
+
type: "run-ended",
|
|
16527
|
+
runId,
|
|
16528
|
+
reason: "deferred-mutation-unresolved",
|
|
16529
|
+
pendingMutations: pending,
|
|
16530
|
+
};
|
|
16531
|
+
return;
|
|
16532
|
+
}
|
|
16400
16533
|
// Surface the final answer's extended-thinking reasoning (Anthropic, when
|
|
16401
16534
|
// --think is on) so non-streaming consumers (the REPL) can show it. The
|
|
16402
16535
|
// streaming path forwards reasoning live via onThinking instead.
|
|
@@ -16638,6 +16771,7 @@ export async function* agentLoop(messages, options) {
|
|
|
16638
16771
|
} = await promise;
|
|
16639
16772
|
if (fatalError) throw fatalError;
|
|
16640
16773
|
throwIfAborted(signal);
|
|
16774
|
+
recordSubtreeMutation(call.function.name, toolArgs, toolResult);
|
|
16641
16775
|
const taskAdvanced = taskProgressTracker.record(
|
|
16642
16776
|
call.function.name,
|
|
16643
16777
|
toolResult,
|
|
@@ -17181,6 +17315,7 @@ export async function* agentLoop(messages, options) {
|
|
|
17181
17315
|
// context — but tell the model when we cut it (no more silent
|
|
17182
17316
|
// mid-content slice). See MAX_TOOL_RESULT_CHARS / capToolResultString.
|
|
17183
17317
|
const resultStr = toolResultForModel(toolName, toolResult, messages);
|
|
17318
|
+
recordSubtreeMutation(toolName, toolArgs, toolResult);
|
|
17184
17319
|
const taskAdvanced = taskProgressTracker.record(
|
|
17185
17320
|
toolName,
|
|
17186
17321
|
toolResult,
|
|
@@ -77,7 +77,8 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
77
77
|
title: "Write File",
|
|
78
78
|
kind: "filesystem",
|
|
79
79
|
tier: "mvp",
|
|
80
|
-
description:
|
|
80
|
+
description:
|
|
81
|
+
"Write content to a file (create or overwrite). For a large new file, write a small complete section first, then extend it with edit_file using a unique existing anchor. Aim for a few thousand characters of new content per call and wait for the result before continuing; each write_file call replaces the whole file.",
|
|
81
82
|
inputSchema: {
|
|
82
83
|
type: "object",
|
|
83
84
|
properties: {
|
|
@@ -200,7 +201,7 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
200
201
|
kind: "filesystem",
|
|
201
202
|
tier: "mvp",
|
|
202
203
|
description:
|
|
203
|
-
"Replace a string in a file. old_string must match EXACTLY ONE place — include enough surrounding context to make it unique, or the edit is rejected. Pass replace_all:true to change every occurrence instead.",
|
|
204
|
+
"Replace a string in a file. old_string must match EXACTLY ONE place — include enough surrounding context to make it unique, or the edit is rejected. To extend a file in small complete sections, use a unique existing anchor as old_string and retain that anchor plus the new section in new_string; do not resend the whole growing file. Wait for each edit result before continuing. Pass replace_all:true to change every occurrence instead.",
|
|
204
205
|
inputSchema: {
|
|
205
206
|
type: "object",
|
|
206
207
|
properties: {
|