chainlesschain 0.166.80 → 0.166.82

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.
Files changed (175) hide show
  1. package/README.md +8 -8
  2. package/package.json +2 -2
  3. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  4. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  5. package/src/assets/web-panel/assets/{AIOps-C5NtVVBN.js → AIOps-DMzLSUWK.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-CE9-HsoR.js → ActionButton-CgnA23oA.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-DRO6sI0Z.js → Analytics-CtXmm8Qe.js} +2 -2
  8. package/src/assets/web-panel/assets/{AppLayout-CuVJiyC_.js → AppLayout-C5RIh5jA.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-GNahHsyZ.js → Artifacts-DM525zx0.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-DWvTomfm.js → Audit-ChBx6f2l.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-k4TuA3ec.js → BackgroundAgents-BBHDxCda.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-BxqN-65D.js → Backup-B-qzCAoM.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-CYYLvwwD.js → BaseInput-C5yoIWAD.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-CoDmZ9yb.js → Chat-NmTrci9a.js} +5 -5
  15. package/src/assets/web-panel/assets/ChatBubbleRenderer-pPuUDG2V.js +1 -0
  16. package/src/assets/web-panel/assets/{Checkbox-CRVlfbkN.js → Checkbox-KdFSU3vd.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-BttMy7rW.js → Codegen-L__BOv_4.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-DsdlE4QC.js → Col-Dfuw4IQV.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-BulheyO-.js → Community-BRlEhSbx.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-BC_7wMxW.js → Compact-D7dRkv8n.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-BA3PDNLK.js → Compliance-CdlFYNR3.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-B6Y3L-GP.js → Cowork-Ey7ksHq4.js} +4 -4
  23. package/src/assets/web-panel/assets/{Cron-DLk_CG77.js → Cron-DBH__wGJ.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-CvsKV-90.js → Crosschain-D3nu9dw7.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-CD8K9G3F.js → DID-DS6vZBNv.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-CXNE434f.js → Dashboard-DwFRk2T0.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-C_P5mttB.js → Dropdown-D7b73q3I.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer-MxZvItNA.js → EmailListRenderer-DPNaVH36.js} +1 -1
  29. package/src/assets/web-panel/assets/{EvolutionSettings-DRoJQrDb.js → EvolutionSettings-BEsOtdpf.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-CBrz9T6T.js → FamilyGuardDashboard-ijSqsSsF.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-DKlGgjNs.js → Federation-C0BOzPDh.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-CteicPS5.js → FormItemContext-DkF5NoAg.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-Bs10mDna.js → GenericCardRenderer-DQsMcyJj.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-CXwzFBIh.js → Git-DQRt88PU.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-CYzcwfwf.js → Governance-DIjPmDN8.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-pYpCF1ws.js → Inference-BWMFtT7i.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-B0YJnOpj.js → KnowledgeGraph-M7TfkUVl.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-D-hJWfq-.js → Logs-BZv9Z6BY.js} +2 -2
  39. package/src/assets/web-panel/assets/MarkdownRenderer-D5NZGdg3.js +1 -0
  40. package/src/assets/web-panel/assets/{Marketplace-D5ZmI-si.js → Marketplace-Crd9MYHg.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-DByD6jY1.js → McpTools-C37yOQV0.js} +2 -2
  42. package/src/assets/web-panel/assets/{Memory--lsjJd7Y.js → Memory-BBsijJCd.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-GQ3vGZO9.js → MobileBridge-CiXIQCju.js} +1 -1
  44. package/src/assets/web-panel/assets/{MobileProjects-Dh2wq-NU.js → MobileProjects-C0KSvQm5.js} +1 -1
  45. package/src/assets/web-panel/assets/{Mtc-uQFoRe_Z.js → Mtc-C0XaQsOY.js} +2 -2
  46. package/src/assets/web-panel/assets/{MtcAudit-BUBYbvuz.js → MtcAudit-DPqggKhw.js} +2 -2
  47. package/src/assets/web-panel/assets/{Multisig-D790SLqM.js → Multisig-Bie0ZVHe.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-DcV9gSqn.js → NLProgramming-BbuJlQ5b.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-sVl7Y_vt.js → Notes-CgqrJV8w.js} +4 -4
  50. package/src/assets/web-panel/assets/{NotificationSettings-BHRPqBZ3.js → NotificationSettings-CusdZEQl.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-B029pIMF.js → OrderTableRenderer-B7RrCvCQ.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-BKrF-dtp.js → Organization-BnFpz3bb.js} +2 -2
  53. package/src/assets/web-panel/assets/{Overflow-DOAGxhhi.js → Overflow-C_4_HyyZ.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-7uQ4F7lh.js → P2P-D0KpHxeg.js} +2 -2
  55. package/src/assets/web-panel/assets/PdhVaultBrowser-Cfd_C9nc.js +7 -0
  56. package/src/assets/web-panel/assets/{Permissions-C0qK0tAi.js → Permissions-D2LxL66N.js} +3 -3
  57. package/src/assets/web-panel/assets/{PersonalDataHub-DCnfXKyb.js → PersonalDataHub-CvSNIxt0.js} +4 -4
  58. package/src/assets/web-panel/assets/{Pipeline-D8wdVvao.js → Pipeline-rUl-SM7V.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-C-dGmb9y.js → Privacy-BD8cWSNd.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-ChKvrsfc.js → ProjectInit-RM7J4X2F.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-CaWnzNBi.js → ProjectSettings-BIH38RsB.js} +2 -2
  62. package/src/assets/web-panel/assets/Projects-CTgx3Fxc.js +1 -0
  63. package/src/assets/web-panel/assets/{Providers-DTufbN-S.js → Providers-B9Kja2RK.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-CGv6QJMC.js → QrScannerModal-ByDKowTD.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-BfNcUCfG.js → QuickAsk-DqEN1QOE.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-B0s5YT2K.js → Recommend-CLrYwNiv.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-YCs5wa8P.js → RemoteSession-DyDltVPC.js} +3 -3
  68. package/src/assets/web-panel/assets/{Reputation-DBC__Ylq.js → Reputation-BfP8rJ1-.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-D_NT1ROe.js → Row-BpnP6r1H.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-Dd9ktNRw.js → RssFeed-CBNI1lCN.js} +3 -3
  71. package/src/assets/web-panel/assets/{Search-BsmlT4PY.js → Search-CLjrM-xj.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-DN-_e3oM.js → Security-dRXtg-Mq.js} +2 -2
  73. package/src/assets/web-panel/assets/{Services-Bm_KqSDz.js → Services-DAHCtOHL.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-BYldeYI0.js → Skeleton-D11Jgtur.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-h7XAXSls.js → Skills-DchvTO4k.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-4ArxAaMJ.js → Sla-BFOc2SbL.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-B639ejZr.js → SpeechSettings-Dud1xDd2.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-DR6RRo1O.js → SyncSettings-CILfsA2S.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-DysrrJVE.js → Tasks-C6Qrah_5.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-DyyB9L9f.js → Templates--puiHyCR.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-XbmWbUl1.js → Tenant-cz5vITz_.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-C5GeciJG.js → Terminal-YRs75Gz8.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-Db-NjeVy.js → TimelineRenderer-C5myb_QZ.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-Btm9pYvJ.js → Tokens-Bk60iMIj.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-BhJ35b0V.js → Trigger-BAb-Fd4z.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-C5T4GJky.js → Trust-BlqwmpEB.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-CqWxh5U0.js → UkeySign-C6jvuF-7.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-DKyI9zg1.js → VideoEditing-7zbsdQUj.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-kgvyQOtT.js → Wallet-BAouk_kp.js} +2 -2
  90. package/src/assets/web-panel/assets/{WebAuthn-1wWucdJt.js → WebAuthn-BQapv504.js} +5 -5
  91. package/src/assets/web-panel/assets/{WorkflowEditor-rHVIbLME.js → WorkflowEditor-ChUXM-Qx.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-DV8ZtfWQ.js → chat-7B6U8zgJ.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-zznFfEpj.js → colors-C8UqaLpe.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-CWk10Qsu.js → compact-item-x47giTCj.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-CtoMW-kY.js → createContext-D6ZwjgaZ.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-BFfV5AtN.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-ieyHKAZZ.js → hasIn-Cv3d9-Bu.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-14ADEHo7.js → index-B7Dorc7r.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-Dz1TqS34.js → index-BGxo1YH0.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DNlvUg0O.js → index-BM-NYjej.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-zY56IXHj.js → index-BMPk5D1m.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-D7yq9nAq.js → index-BTBkdyLk.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CrBful_u.js → index-BTisPSqa.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-G9bqTRu6.js → index-BUzw-kDo.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BGYCtfL-.js → index-C1ElqYDD.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-B9w6Zr_O.js → index-CQ0-ny-o.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BrpyZMUe.js → index-CUUgXcPh.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Bf9069uM.js → index-CUtcWTSe.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-McW2cdbg.js → index-CXG6yiAf.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DPwOEcUt.js → index-CXIUyx4U.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Cn71LASJ.js → index-CaPZ_8kP.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-B2WI4Jse.js → index-Cbf4RqOd.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BG9KlVJl.js → index-Cc2bhSuI.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-0GSB8LOT.js → index-Cc6jr0Yb.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CdSnkhrR.js → index-Ce666S9v.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CjkiJdIX.js → index-CiVEatgH.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CewbVIM8.js → index-CrGQsbpb.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-DR1Uw5as.js → index-D4ZHX6wo.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-2TTLREp7.js → index-D9lFBkS4.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DjNjO-VL.js → index-DD-V-N_m.js} +3 -3
  121. package/src/assets/web-panel/assets/{index-9fgmdiB_.js → index-DLHnYXVa.js} +1 -1
  122. package/src/assets/web-panel/assets/index-DUz_bv5i.js +1 -0
  123. package/src/assets/web-panel/assets/{index-Cqpfzkch.js → index-DVBG0Jqz.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CGZGQTF5.js → index-Dc0hePXV.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DSnQWQ4L.js → index-DtBUgc0G.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CLeX8Qp7.js → index-Dv5E07PZ.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DdMho2Wr.js → index-DvoMGeL9.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CxSgg3Xc.js → index-EDWA9JL1.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-D9jmNLfO.js → index-IVelXaiQ.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DmtyRKy8.js → index-N9hNOl1i.js} +1 -1
  131. package/src/assets/web-panel/assets/{index--6zQrvYc.js → index-WhoNHp50.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-CBS8OtL2.js → index-dbM4QvQZ.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-fmwnODwg.js → index-jgN2e0Oy.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-esCpkxIZ.js → index-nogjrcQE.js} +1 -1
  135. package/src/assets/web-panel/assets/index-rQ59l7GO.js +1 -0
  136. package/src/assets/web-panel/assets/{index-DRuSuXJh.js → index-yYdCdtY1.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-CVk4LKJK.js → initDefaultProps-DkKS5xtR.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-IAABGXc_.js → motion-CU-zBUIg.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-B9HSYeZc.js → move-zBE0VEd4.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-CJfDtM89.js → mtc-parser-B9WyO1je.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-D5dYnom7.js → omit-6sCoBNTL.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-xbUkaZdY.js → pickAttrs-DDRv_sFc.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-CIUU5NKN.js → placementArrow-Cy_CBDw5.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-BZpgHE8P.js → responsiveObserve-CIczLq9K.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-x_8rsSKk.js → slide-DFfZCvnG.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-BZyDnVJs.js → statusUtils-DW-0HUl-.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-DusfWp6J.js → styleChecker-BPYaBorP.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-022JzYAL.js → useFlexGapSupport-DYPoOaZc.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-DRDxX7-3.js → useFs-ODUEWR17.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-DFrCp7m_.js → usePersonalDataHub-CstUt15X.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-bCuSFOmr.js → vnode-D2GW8xCL.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-sCpZ0sw7.js → zoom-Bz6GoDwq.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/data/changelog.json +26 -0
  155. package/src/gateways/ws/ws-approval-gate.js +7 -0
  156. package/src/lib/auto-mode-config.js +129 -40
  157. package/src/lib/context-memory-kernel/task-worklog-port.js +73 -24
  158. package/src/lib/diagnostic-excerpt.js +91 -10
  159. package/src/lib/diagnostic-workflow.js +2 -0
  160. package/src/lib/git-tool-input.js +7 -0
  161. package/src/lib/plan-mode.js +15 -4
  162. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +2 -2
  163. package/src/lib/process-execution-broker/linux-open-flags.js +26 -0
  164. package/src/lib/process-execution-broker/platform-sandbox.js +5 -9
  165. package/src/lib/remote-read-loop-guard.js +59 -14
  166. package/src/lib/task-progress-tracker.js +112 -12
  167. package/src/repl/agent-repl.js +15 -14
  168. package/src/runtime/agent-core.js +88 -2
  169. package/src/assets/web-panel/assets/ChatBubbleRenderer-ChTIMWch.js +0 -1
  170. package/src/assets/web-panel/assets/MarkdownRenderer-BPQlDtB7.js +0 -1
  171. package/src/assets/web-panel/assets/PdhVaultBrowser-BegpATva.js +0 -7
  172. package/src/assets/web-panel/assets/Projects-2uNBqS05.js +0 -1
  173. package/src/assets/web-panel/assets/devWarning-_Wlo1cZJ.js +0 -1
  174. package/src/assets/web-panel/assets/index-Cj8Mcdok.js +0 -1
  175. package/src/assets/web-panel/assets/index-vira2aS_.js +0 -1
@@ -1,12 +1,41 @@
1
+ // Prefer test-runner verdicts over arbitrary "Error:" lines printed by tests.
2
+ // A verdict is evidence to retain, not a claim about which defect caused it.
3
+ const TEST_FAILURE =
4
+ /\bFAIL(?:ED)?\s+[^\r\n]*\.(?:[cm]?[jt]sx?|py|go|rs|java)(?=[:\s]|$)|(?:^|\s)not ok \d+\s+-|\bTest Files\s+\d+ failed/;
5
+ export function hasTestFailureVerdict(value) {
6
+ return (
7
+ typeof value === "string" &&
8
+ TEST_FAILURE.test(stripVTControlCharacters(value))
9
+ );
10
+ }
11
+
1
12
  /** Retain source context for several errors; an error line is not a root cause. */
2
13
  export function diagnosticExcerpt(value, limit = 1600) {
3
- const text = typeof value === "string" ? value : JSON.stringify(value ?? "");
14
+ const text = stripVTControlCharacters(
15
+ typeof value === "string" ? value : JSON.stringify(value ?? ""),
16
+ );
4
17
  if (text.length <= limit) return text;
18
+ if (limit < 256) return text.slice(0, Math.max(0, limit));
5
19
  const marker = "\n[... omitted ...]\n";
6
- const lines = text.split("\n");
20
+ // gh prefixes every log line with job/step/timestamp. Keep the original
21
+ // head/tail, but spend diagnostic windows on the actual failure and stack.
22
+ const lines = text
23
+ .split("\n")
24
+ .map((line) =>
25
+ line.replace(/^[^\t\r\n]+\t[^\t\r\n]+\t\d{4}-\d\d-\d\dT[\d:.]+Z\s?/, ""),
26
+ );
7
27
  const errors = [];
8
28
  const workers = [];
29
+ const failures = [];
30
+ const summaries = [];
9
31
  for (let i = 0; i < lines.length; i++) {
32
+ if (TEST_FAILURE.test(lines[i])) failures.push(i);
33
+ if (
34
+ /\b(?:Test Files|Tests)\s+\d+ (?:failed|passed)|\b[\w -]+ tests (?:PASSED|FAILED)\b|\b(?:PASS|ok \d+ -)\b.*(?:negative|spawn|gate)/i.test(
35
+ lines[i],
36
+ )
37
+ )
38
+ summaries.push(i);
10
39
  if (
11
40
  /\b\w*Error:|Exception in thread|Caused by:|\bpanic:|panicked at|\bFAIL\b|error TS\d+|##\[error\]/.test(
12
41
  lines[i],
@@ -20,11 +49,21 @@ export function diagnosticExcerpt(value, limit = 1600) {
20
49
  )
21
50
  workers.push(i);
22
51
  }
23
- // Keep both an early diagnostic (possibly expected negative-test output)
24
- // and later runner failures. Never infer causality from their ordering.
52
+ // A middle failed-test block used to disappear between an expected early
53
+ // error and the final gate error. Keep its location and adjacent assertion,
54
+ // alongside process summaries; never infer causality from their ordering.
55
+ const lastError = errors.at(-1);
56
+ const finalError =
57
+ lastError !== undefined &&
58
+ /Process completed with exit code/.test(lines[lastError]) &&
59
+ errors.at(-2) >= lastError - 2
60
+ ? errors.at(-2)
61
+ : lastError;
25
62
  const indices = [
26
63
  ...new Set(
27
- [workers[0], errors[0], errors.at(-1)].filter((i) => i !== undefined),
64
+ [failures[0], workers[0], errors[0], finalError].filter(
65
+ (i) => i !== undefined,
66
+ ),
28
67
  ),
29
68
  ].sort((a, b) => a - b);
30
69
  if (!indices.length) {
@@ -33,19 +72,61 @@ export function diagnosticExcerpt(value, limit = 1600) {
33
72
  text.slice(0, head) + marker + text.slice(-(limit - marker.length - head))
34
73
  );
35
74
  }
36
- const available = limit - marker.length * (indices.length + 1);
75
+ const failedSuites = summaries.filter((index) =>
76
+ /tests FAILED\b/.test(lines[index]),
77
+ );
78
+ const verdictIndices = failedSuites.length
79
+ ? [
80
+ ...new Set(
81
+ [
82
+ ...failedSuites,
83
+ summaries.find((index) => /tests PASSED\b/.test(lines[index])),
84
+ ...failedSuites.map((index) => {
85
+ const suite = /([\w-]+ tests) FAILED\b/.exec(lines[index])?.[1];
86
+ return suite
87
+ ? summaries.findLast((next) =>
88
+ lines[next].includes(`${suite} PASSED`),
89
+ )
90
+ : undefined;
91
+ }),
92
+ ].filter((index) => index !== undefined),
93
+ ),
94
+ ]
95
+ : summaries.slice(-5);
96
+ const verdicts = verdictIndices
97
+ .map((index) => lines[index])
98
+ .join("\n")
99
+ .slice(0, Math.floor(limit * 0.2));
100
+ const available =
101
+ limit -
102
+ marker.length * (indices.length + 1 + (verdicts ? 1 : 0)) -
103
+ verdicts.length;
37
104
  const head = Math.floor(available * 0.1);
38
105
  const tail = Math.floor(available * 0.15);
39
- const perWindow = Math.floor((available - head - tail) / indices.length);
106
+ const windowBudget = available - head - tail;
107
+ const failureBudget = failures.length
108
+ ? Math.floor(windowBudget * (indices.length > 1 ? 0.55 : 1))
109
+ : 0;
110
+ const perWindow = Math.floor(
111
+ (windowBudget - failureBudget) /
112
+ Math.max(1, indices.length - (failures.length ? 1 : 0)),
113
+ );
40
114
  const windows = indices.map((index) => {
115
+ const size = index === failures[0] ? failureBudget : perWindow;
41
116
  const before = lines
42
117
  .slice(Math.max(0, index - 2), index)
43
118
  .join("\n")
44
- .slice(-Math.floor(perWindow * 0.2));
119
+ .slice(-Math.floor(size * 0.1));
45
120
  return (before + "\n" + lines.slice(index, index + 10).join("\n")).slice(
46
121
  0,
47
- perWindow,
122
+ size,
48
123
  );
49
124
  });
50
- return [text.slice(0, head), ...windows, text.slice(-tail)].join(marker);
125
+ return [
126
+ text.slice(0, head),
127
+ ...windows,
128
+ ...(verdicts ? [verdicts] : []),
129
+ text.slice(-tail),
130
+ ].join(marker);
51
131
  }
132
+ import { stripVTControlCharacters } from "node:util";
@@ -4,6 +4,8 @@ export const DIAGNOSTIC_WORKFLOW_GUIDANCE =
4
4
  "For debugging, retain the original failure signature (error, source location, stack, command, environment and revision when verified). " +
5
5
  "Label each observation by its source and reproduction scope. A passing subset is not a successful full reproduction; a different error is a separate finding until evidence connects it to the original failure. " +
6
6
  "Expected negative-test output, dependency/setup failures, failed assertions and runner/infrastructure failures are different possibilities. Inspect surrounding output and process outcomes before selecting one. Timing alone does not identify the cause, and argument order is not execution order. " +
7
+ "Keep confirmed facts separate from hypotheses and ruled-out signals, with their source. Preserve an established failure and excluded negative-test errors across compaction; a later command syntax error does not invalidate an earlier successful observation. Reopen a ruled-out hypothesis only when new evidence contradicts it. " +
8
+ "An issue, its linked PR, the PR head, a synthetic merge ref, the merged commit, and each workflow run/attempt are separate identities. Keep their numbers and revisions distinct. A green diagnostic retry does not replace the primary failure or prove that a flaky test was fixed. A different release workflow failing on that commit is a separate finding until connected to this task. " +
7
9
  "State one hypothesis and the smallest check that can disprove it; after that check, update the hypothesis from the observed result instead of restarting discovery. " +
8
10
  "Do not change dependencies while a reproduction using them is running. Poll background tasks by task_id and drain has_more_output after exit. " +
9
11
  "Bind reports to verified paths, runs and attempts; do not substitute a local or stale report for the target run. A green report alone does not override a nonzero exit, unhandled errors or incomplete output. " +
@@ -1,6 +1,13 @@
1
1
  // The git tool accepts argv text, not a shell program. Diagnose shell syntax
2
2
  // before spawning git while preserving literal operators in quoted arguments.
3
3
  export function gitToolInputError(command) {
4
+ if (/^\s*(?:git\s+)?gh(?:\.exe)?(?:\s|$)/i.test(command))
5
+ return {
6
+ success: false,
7
+ code: "CC_GIT_WRONG_TOOL",
8
+ error: "gh is the GitHub CLI, not a Git subcommand.",
9
+ hint: "Use run_shell for the original gh command, subject to its normal permissions. Use the git tool only for Git arguments such as status or log. No command was executed.",
10
+ };
4
11
  let quote = null;
5
12
  for (let i = 0; i < command.length; i++) {
6
13
  const char = command[i];
@@ -893,8 +893,8 @@ export class PlanModeManager extends EventEmitter {
893
893
  }
894
894
 
895
895
  _commitMutation(transaction, eventType) {
896
+ const previousRevision = this.revision;
896
897
  if (!this._persistence) {
897
- const previousRevision = this.revision;
898
898
  this.revision += 1;
899
899
  this.updatedAt = Date.now();
900
900
  this.lastEvent = this.sessionId
@@ -906,6 +906,11 @@ export class PlanModeManager extends EventEmitter {
906
906
  timestamp: this.updatedAt,
907
907
  })
908
908
  : null;
909
+ this.emit("revision-changed", {
910
+ revision: this.revision,
911
+ previousRevision,
912
+ type: eventType,
913
+ });
909
914
  if (this.lastEvent) this.emit("session-event", { ...this.lastEvent });
910
915
  return null;
911
916
  }
@@ -920,6 +925,11 @@ export class PlanModeManager extends EventEmitter {
920
925
  this.revision = snapshot.revision;
921
926
  this.updatedAt = snapshot.updatedAt;
922
927
  this.lastEvent = snapshot.event;
928
+ this.emit("revision-changed", {
929
+ revision: this.revision,
930
+ previousRevision,
931
+ type: eventType,
932
+ });
923
933
  this.emit("session-event", { ...this.lastEvent });
924
934
  return null;
925
935
  } catch (error) {
@@ -1369,7 +1379,7 @@ export class PlanModeManager extends EventEmitter {
1369
1379
  /**
1370
1380
  * Check if a tool is allowed in current state
1371
1381
  */
1372
- isToolAllowed(toolName) {
1382
+ isToolAllowed(toolName, { recordBlocked = true } = {}) {
1373
1383
  if (!this.isActive()) return true;
1374
1384
  if (
1375
1385
  this.state === PlanState.APPROVED ||
@@ -1377,7 +1387,8 @@ export class PlanModeManager extends EventEmitter {
1377
1387
  ) {
1378
1388
  const allowed =
1379
1389
  this.executionLock?.allowedTools.includes(toolName) === true;
1380
- if (!allowed) this._recordBlockedTool(toolName, "execution-lock");
1390
+ if (!allowed && recordBlocked)
1391
+ this._recordBlockedTool(toolName, "execution-lock");
1381
1392
  return allowed;
1382
1393
  }
1383
1394
 
@@ -1386,7 +1397,7 @@ export class PlanModeManager extends EventEmitter {
1386
1397
 
1387
1398
  // Block write tools and log
1388
1399
  if (WRITE_TOOLS.has(toolName)) {
1389
- this._recordBlockedTool(toolName, "planning");
1400
+ if (recordBlocked) this._recordBlockedTool(toolName, "planning");
1390
1401
  return false;
1391
1402
  }
1392
1403
 
@@ -21,13 +21,13 @@ import {
21
21
  buildLinuxBwrapDescriptorScrubbedLaunch,
22
22
  LINUX_BWRAP_DESCRIPTOR_SCRUBBER_PATH,
23
23
  } from "./linux-bwrap-descriptor-launch.js";
24
+ import { linuxTmpfileFlag } from "./linux-open-flags.js";
24
25
 
25
26
  const BWRAP_PATH = "/usr/bin/bwrap";
26
27
  const MAX_ATTESTED_FILE_BYTES = 256 * 1024 * 1024;
27
28
  const MAX_MOUNTINFO_BYTES = 4 * 1024 * 1024;
28
29
  const MOUNTINFO_PATH = "/proc/self/mountinfo";
29
30
  const MOUNT_TOPOLOGY_VERSION = 1;
30
- const O_TMPFILE = 0x410000;
31
31
  const SYSTEM_DESTINATIONS = [
32
32
  "/usr",
33
33
  "/bin",
@@ -1085,7 +1085,7 @@ function createTrustedResources(
1085
1085
  const flags =
1086
1086
  Number(constants.O_RDWR) |
1087
1087
  Number(constants.O_EXCL) |
1088
- Number(constants.O_TMPFILE ?? O_TMPFILE) |
1088
+ linuxTmpfileFlag(constants) |
1089
1089
  Number(constants.O_NOFOLLOW || 0) |
1090
1090
  Number(constants.O_NONBLOCK || 0);
1091
1091
  const fd = track(runtime.fs.openSync("/tmp", flags, 0o400), phase);
@@ -0,0 +1,26 @@
1
+ // Linux defines O_TMPFILE as __O_TMPFILE | O_DIRECTORY. O_DIRECTORY is
2
+ // architecture-specific (0x4000 on ARM64, 0x10000 on x64), while Node does
3
+ // not expose O_TMPFILE on every supported build.
4
+ const LINUX_ANONYMOUS_TMPFILE_BIT = 0x400000;
5
+
6
+ export function linuxTmpfileFlag(constants) {
7
+ const directoryFlag = constants?.O_DIRECTORY;
8
+ if (
9
+ !Number.isSafeInteger(directoryFlag) ||
10
+ directoryFlag <= 0 ||
11
+ (directoryFlag & (directoryFlag - 1)) !== 0
12
+ ) {
13
+ throw new Error("linux_o_directory_unavailable");
14
+ }
15
+
16
+ const fallbackFlag = LINUX_ANONYMOUS_TMPFILE_BIT | directoryFlag;
17
+ const tmpfileFlag = constants.O_TMPFILE ?? fallbackFlag;
18
+ if (
19
+ !Number.isSafeInteger(tmpfileFlag) ||
20
+ (tmpfileFlag & LINUX_ANONYMOUS_TMPFILE_BIT) === 0 ||
21
+ (tmpfileFlag & directoryFlag) !== directoryFlag
22
+ ) {
23
+ throw new Error("linux_o_tmpfile_invalid");
24
+ }
25
+ return tmpfileFlag;
26
+ }
@@ -33,6 +33,7 @@ import {
33
33
  applyLinuxGenericWorkspaceSandbox,
34
34
  isLinuxGenericWorkspaceContract,
35
35
  } from "./linux-generic-bwrap-runtime.js";
36
+ import { linuxTmpfileFlag } from "./linux-open-flags.js";
36
37
  import {
37
38
  buildLinuxBwrapDescriptorScrubbedLaunch,
38
39
  LINUX_BWRAP_DESCRIPTOR_SCRUBBER_PATH,
@@ -288,10 +289,7 @@ const LINUX_ELF_MACHINES = Object.freeze({
288
289
  arm64: 183,
289
290
  riscv64: 243,
290
291
  });
291
- // Linux asm-generic: __O_TMPFILE (0x400000) | O_DIRECTORY (0x010000).
292
- // x64, arm64, and riscv64 use this value; unsupported seccomp architectures
293
- // already fail closed before the anonymous filter is created.
294
- const LINUX_O_TMPFILE = 0x410000;
292
+ // Anonymous snapshots and seccomp filters require the native O_TMPFILE flag.
295
293
  const LINUX_CLONE_NEWNS = 0x00020000;
296
294
  const LINUX_CLONE_NEWUSER = 0x10000000;
297
295
  const LINUX_NAMESPACE_CLONE_FLAGS = LINUX_CLONE_NEWNS | LINUX_CLONE_NEWUSER;
@@ -2728,9 +2726,7 @@ function sameWindowsFileIdentity(left, right) {
2728
2726
  // the deletion authority.
2729
2727
  function sameWindowsFileObjectIdentity(left, right) {
2730
2728
  return (
2731
- left.dev === right.dev &&
2732
- left.ino === right.ino &&
2733
- left.mode === right.mode
2729
+ left.dev === right.dev && left.ino === right.ino && left.mode === right.mode
2734
2730
  );
2735
2731
  }
2736
2732
 
@@ -5853,7 +5849,7 @@ function createLinuxRegularFileSnapshot(
5853
5849
  const writerFlags =
5854
5850
  Number(constants.O_RDWR) |
5855
5851
  Number(constants.O_EXCL) |
5856
- Number(constants.O_TMPFILE ?? LINUX_O_TMPFILE) |
5852
+ linuxTmpfileFlag(constants) |
5857
5853
  Number(constants.O_NOFOLLOW || 0) |
5858
5854
  Number(constants.O_NONBLOCK || 0);
5859
5855
  writerFd = runtime.fs.openSync("/tmp", writerFlags, snapshotSourceMode);
@@ -7442,7 +7438,7 @@ function pinLinuxNetworkSeccompFilter(runtime, options = {}) {
7442
7438
  const flags =
7443
7439
  Number(constants.O_RDWR) |
7444
7440
  Number(constants.O_EXCL) |
7445
- Number(constants.O_TMPFILE ?? LINUX_O_TMPFILE) |
7441
+ linuxTmpfileFlag(constants) |
7446
7442
  Number(constants.O_NOFOLLOW || 0) |
7447
7443
  Number(constants.O_NONBLOCK || 0);
7448
7444
  // An anonymous inode avoids a same-UID process opening the filter by path.
@@ -18,6 +18,19 @@ function pullRequestTarget(repo, id = "list") {
18
18
  return { ...githubTarget(repo, "pulls", id), pullRequest: true };
19
19
  }
20
20
 
21
+ function issueTarget(repo, id = "list") {
22
+ return { ...githubTarget(repo, "issues", id), issue: true };
23
+ }
24
+
25
+ const ISSUE_WORKFLOW_GUIDANCE =
26
+ "Issue investigation: retain the issue, linked PR and workflow run as separate targets, with verified revisions and observed test outcomes. " +
27
+ "Use gh issue view for an issue and gh pr view for its linked PR; their numbers need not match. " +
28
+ "Use gh run view <run-id> for one run; gh run list accepts filters, not a positional run ID. " +
29
+ "For unknown JSON fields, inspect stderr/help and request supported fields without jq or shell pipelines first. " +
30
+ "A completed metadata read remains evidence after an unrelated command fails; do not restart the same investigation. " +
31
+ "Once the failing test and source are known, state a falsifiable hypothesis, run the focused reproduction, then make and validate the authorized fix. " +
32
+ "A merged PR or a passing diagnostic retry alone does not resolve the reported failure. Perform issue closure only when authorized and supported by the requested resolution evidence. ";
33
+
21
34
  function commandFlag(command, names) {
22
35
  return new RegExp(
23
36
  `(?:^|\\s)(?:${names})(?:=|\\s+)(?:"([^"]*)"|'([^']*)'|([^\\s;&|]+))`,
@@ -27,13 +40,16 @@ function commandFlag(command, names) {
27
40
  .find((value) => value !== undefined);
28
41
  }
29
42
 
30
- function pullRequestCommandTarget(command) {
43
+ function discussionCommandTarget(command) {
31
44
  const match =
32
- /(?:^|[\s;&|])gh(?:\.exe)?\s+pr\s+(list|view|diff)\b([^;&|\r\n]*)/i.exec(
45
+ /(?:^|[\s;&|])gh(?:\.exe)?\s+(pr|issue)\s+(list|view|diff)\b([^;&|\r\n]*)/i.exec(
33
46
  command,
34
47
  );
35
48
  if (!match) return null;
36
- const fields = commandFlag(match[2], "--json")?.split(",");
49
+ const target =
50
+ match[1].toLowerCase() === "issue" ? issueTarget : pullRequestTarget;
51
+ const tail = match[3];
52
+ const fields = commandFlag(tail, "--json")?.split(",");
37
53
  // Lightweight status polling is intentional waiting, not repeated review.
38
54
  if (
39
55
  fields?.length &&
@@ -44,18 +60,20 @@ function pullRequestCommandTarget(command) {
44
60
  )
45
61
  )
46
62
  return null;
47
- const repo = commandFlag(match[2], "--repo|-R") || "current-repo";
48
- if (match[1].toLowerCase() === "list") return pullRequestTarget(repo);
63
+ const repo = commandFlag(tail, "--repo|-R") || "current-repo";
64
+ if (match[2].toLowerCase() === "list") return target(repo);
49
65
  const prUrl =
50
- /https:\/\/github\.com\/([^/\s]+\/[^/\s]+)\/pull\/(\d+)\b/i.exec(match[2]);
51
- if (prUrl) return pullRequestTarget(prUrl[1], prUrl[2]);
66
+ /https:\/\/github\.com\/([^/\s]+\/[^/\s]+)\/(?:pull|issues)\/(\d+)\b/i.exec(
67
+ tail,
68
+ );
69
+ if (prUrl) return target(prUrl[1], prUrl[2]);
52
70
  // Remove flags that consume values before finding the positional PR number.
53
- const positional = match[2].replace(
71
+ const positional = tail.replace(
54
72
  /(?:^|\s)(?:--repo|-R|--json|--jq|-q|--template|-t|--color)(?:=|\s+)(?:"[^"]*"|'[^']*'|[^\s]+)/g,
55
73
  " ",
56
74
  );
57
75
  const number = /(?:^|\s)["']?(\d+)["']?(?=\s|$)/.exec(positional)?.[1];
58
- return number ? pullRequestTarget(repo, number) : null;
76
+ return number ? target(repo, number) : null;
59
77
  }
60
78
 
61
79
  function urlTarget(value) {
@@ -69,6 +87,10 @@ function urlTarget(value) {
69
87
  };
70
88
  }
71
89
  if (url.hostname === "github.com") {
90
+ const issue = /^\/([^/]+\/[^/]+)\/issues(?:\/(\d+))?\/?$/.exec(
91
+ url.pathname,
92
+ );
93
+ if (issue) return issueTarget(issue[1], issue[2]);
72
94
  const pr =
73
95
  /^\/([^/]+\/[^/]+)\/(?:pulls\/?|pull\/(\d+)(?:\/(?:files|commits|checks))?\/?|pull\/(\d+)\.(?:diff|patch))$/.exec(
74
96
  url.pathname,
@@ -87,6 +109,11 @@ function urlTarget(value) {
87
109
  );
88
110
  }
89
111
  if (url.hostname === "api.github.com") {
112
+ const issue =
113
+ /^\/repos\/([^/]+\/[^/]+)\/issues(?:\/(\d+)(?:\/(?:comments|events|timeline))?)?\/?$/.exec(
114
+ url.pathname,
115
+ );
116
+ if (issue) return issueTarget(issue[1], issue[2]);
90
117
  const pr =
91
118
  /^\/repos\/([^/]+\/[^/]+)\/pulls(?:\/(\d+)(?:\/(?:files|commits|reviews|comments))?)?\/?$/.exec(
92
119
  url.pathname,
@@ -144,8 +171,8 @@ export function remoteReadTarget(tool, args = {}) {
144
171
  }
145
172
  if (tool !== "run_shell") return null;
146
173
  const command = typeof args.command === "string" ? args.command : "";
147
- const pr = pullRequestCommandTarget(command);
148
- if (pr) return pr;
174
+ const discussion = discussionCommandTarget(command);
175
+ if (discussion) return discussion;
149
176
  const view = /(?:^|[\s;&|])gh(?:\.exe)?\s+run\s+view\s+([^;&|\r\n]+)/i.exec(
150
177
  command,
151
178
  );
@@ -172,6 +199,11 @@ export function remoteReadTarget(tool, args = {}) {
172
199
  /(?:^|\s)(?:(?:--field|--raw-field|--input)(?:=|\s)|-[fF])/.test(command)
173
200
  )
174
201
  return null;
202
+ const issueApi =
203
+ /(?:https:\/\/api\.github\.com\/)?\/?repos\/([\w.-]+\/[\w.-]+)\/issues(?:\/(\d+)(?:\/(?:comments|events|timeline))?)?(?=[?\s"']|$)/.exec(
204
+ command,
205
+ );
206
+ if (issueApi) return issueTarget(issueApi[1], issueApi[2]);
175
207
  const prApi =
176
208
  /(?:https:\/\/api\.github\.com\/)?\/?repos\/([\w.-]+\/[\w.-]+)\/pulls(?:\/(\d+)(?:\/(?:files|commits|reviews|comments))?)?(?=[?\s"']|$)/.exec(
177
209
  command,
@@ -369,6 +401,14 @@ export class RemoteReadLoopGuard {
369
401
  get recoveryHint() {
370
402
  if (!(this.targets.get(this.activeKey)?.repeats >= RECOVERY_AFTER))
371
403
  return null;
404
+ if (this.targets.get(this.activeKey)?.issue) {
405
+ return (
406
+ "Remote-read loop recovery: repeated issue reads returned failures or already-seen evidence. " +
407
+ "Use the retained observations; identify the exact missing fact before a new focused read. " +
408
+ ISSUE_WORKFLOW_GUIDANCE +
409
+ DIAGNOSTIC_WORKFLOW_GUIDANCE
410
+ );
411
+ }
372
412
  if (this.targets.get(this.activeKey)?.shellPolicy) {
373
413
  return (
374
414
  "Tool-policy loop recovery: the same execution policy keeps rejecting commands, even when their arguments change. " +
@@ -449,6 +489,8 @@ export class RemoteReadLoopGuard {
449
489
  }
450
490
 
451
491
  get workflowHint() {
492
+ if (this.targets.get(this.activeKey)?.issue)
493
+ return ISSUE_WORKFLOW_GUIDANCE + DIAGNOSTIC_WORKFLOW_GUIDANCE;
452
494
  const active = this.targets.get(this.activeKey);
453
495
  if (active?.github && !active.pullRequest) {
454
496
  return (
@@ -505,6 +547,7 @@ export class RemoteReadLoopGuard {
505
547
  page,
506
548
  localLog,
507
549
  pullRequest,
550
+ issue,
508
551
  shellPolicy,
509
552
  gitRepository,
510
553
  }) => ({
@@ -515,9 +558,11 @@ export class RemoteReadLoopGuard {
515
558
  : github
516
559
  ? pullRequest
517
560
  ? "GitHub pull requests"
518
- : localLog
519
- ? "saved GitHub Actions log"
520
- : "GitHub Actions logs"
561
+ : issue
562
+ ? "GitHub issues"
563
+ : localLog
564
+ ? "saved GitHub Actions log"
565
+ : "GitHub Actions logs"
521
566
  : tool === "web_search"
522
567
  ? "web_search"
523
568
  : "web_fetch",