chainlesschain 0.166.106 → 0.166.108

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 (225) hide show
  1. package/README.md +187 -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-CKwEku2e.js → AIOps-B5HWUFaS.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-BSUOuTpW.js → ActionButton-DCIKpxoQ.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-CGxvL_FI.js → Analytics-dsgvjCEQ.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-bCPwz-5w.js → AppLayout-DWDH5Qbm.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-2_BOWo6e.js → Artifacts-BD8S8kzU.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-CBOruzgW.js → Audit-CDXv4Aoj.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-lg0IU5HN.js → BackgroundAgents-BLAQ5Uy0.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-OspCi452.js → Backup-moPac6tF.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-BMkliqlz.js → BaseInput-C_6nzsLU.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-BfoiUZwp.js → Chat-cYuslkFG.js} +6 -6
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-BjnfMwep.js → ChatBubbleRenderer-Ceh3MG6M.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-jTMlkNQZ.js → Checkbox-Qjb-XOX_.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-CycyJcnU.js → Codegen-IYRWXlMA.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-BVWlReQj.js → Col-CsQ9jv8M.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-CKRHl4xK.js → Community-BbNmfTwe.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-BtpfMdhT.js → Compact-SShDx-nr.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-DtHB1Ct1.js → Compliance-CLWhKIJp.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-D_8X7-RK.js → Cowork-D4tK9_s3.js} +2 -2
  23. package/src/assets/web-panel/assets/{Cron-DMCOyvEa.js → Cron-D7GnfQ1z.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-CeHdsu7m.js → Crosschain-TG86SH3X.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-CL6mR6zX.js → DID-6pue0NCO.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-oz9n6DC7.js → Dashboard-BwkJ29du.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-CbWm8mWu.js → Dropdown-DEvpYDof.js} +1 -1
  28. package/src/assets/web-panel/assets/EmailListRenderer-CQj7UlKJ.js +1 -0
  29. package/src/assets/web-panel/assets/{EvolutionSettings-DPwqgRYm.js → EvolutionSettings-tpvPMM9W.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DkV4YMFj.js → FamilyGuardDashboard-CWYFW75O.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-CpUKHIOH.js → Federation-gRIi96rM.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-C6KXRgjR.js → FormItemContext-B7Nr3YkV.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-C5Y4L5E3.js → GenericCardRenderer-b1BgGgLT.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-CBwKdF8s.js → Git-Dis1jjO7.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-Dt-OR7Aa.js → Governance-C4Yg99Am.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-Czkl-Lhl.js → Inference-D4UQRbGu.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-C7NE4949.js → KnowledgeGraph-Co_kLMAq.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-CoAuZiMG.js → Logs-D4BRp7bg.js} +2 -2
  39. package/src/assets/web-panel/assets/{MarkdownRenderer-DTkjTwGI.js → MarkdownRenderer-Dgy8arQI.js} +1 -1
  40. package/src/assets/web-panel/assets/{Marketplace-IzrV-7zH.js → Marketplace-ys0j1vr9.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-DYEea7aS.js → McpTools-B3ZvRZe_.js} +2 -2
  42. package/src/assets/web-panel/assets/{Memory-Uqe7ZrV6.js → Memory-BOa0jbr-.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-D092EGyM.js → MobileBridge-CWJRmUbj.js} +1 -1
  44. package/src/assets/web-panel/assets/MobileProjects-7ty8vTpj.js +1 -0
  45. package/src/assets/web-panel/assets/{Mtc-gg4jzfB-.js → Mtc-CCcOk5m5.js} +5 -5
  46. package/src/assets/web-panel/assets/{MtcAudit-BibGfs71.js → MtcAudit-vlrrScbQ.js} +4 -4
  47. package/src/assets/web-panel/assets/{Multisig-BmB5yRXP.js → Multisig-C8K59S_8.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-BBSlPDyY.js → NLProgramming-oTpFYVme.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-Bui3-KiC.js → Notes-BhqAJWiz.js} +3 -3
  50. package/src/assets/web-panel/assets/{NotificationSettings-ovXtbHe5.js → NotificationSettings-DCnV1CJM.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-Bq-qD7eG.js → OrderTableRenderer-CZGnsrVW.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-DacIY9oJ.js → Organization-DX1LuQlJ.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-CX8osheZ.js → Overflow-CbfKrFdT.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-1lnikqVp.js → P2P-BEwYZuHL.js} +2 -2
  55. package/src/assets/web-panel/assets/{PdhVaultBrowser-DCrU-V6A.js → PdhVaultBrowser-YNmWbwd7.js} +3 -3
  56. package/src/assets/web-panel/assets/{Permissions-Dfcb6kM2.js → Permissions-DyZ18LiA.js} +4 -4
  57. package/src/assets/web-panel/assets/{PersonalDataHub-dvgai4hf.js → PersonalDataHub-B2J3aw2g.js} +4 -4
  58. package/src/assets/web-panel/assets/{Pipeline-nymAEtnK.js → Pipeline-CXl2ZlhQ.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-D0Vd91oM.js → Privacy-I5SDmgAp.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-BpUBcu7o.js → ProjectInit-Crl9tXw3.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-DIzwTT-M.js → ProjectSettings-DCFtFlSK.js} +2 -2
  62. package/src/assets/web-panel/assets/{Projects-Den4RUw6.js → Projects-Do5BQq1i.js} +1 -1
  63. package/src/assets/web-panel/assets/{Providers-Cq8p-M0d.js → Providers-Cb7OWa3y.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-DSmqOfYk.js → QrScannerModal-CJmhAU-s.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-BDHCeSnA.js → QuickAsk-Cu6lEWou.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-B_9M8oF4.js → Recommend-Crip3jLB.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-5ot4leHy.js → RemoteSession-KxYY-2CB.js} +3 -3
  68. package/src/assets/web-panel/assets/{Reputation-B3F013PY.js → Reputation-D0vN-htI.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-BMyBJnZw.js → Row-wqzd_xCD.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-WmV0l52g.js → RssFeed-8lsPfb0a.js} +3 -3
  71. package/src/assets/web-panel/assets/{Search-Wl80yXnR.js → Search-C-e8qAeU.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-gbDMKb5m.js → Security-CMM9WgFy.js} +4 -4
  73. package/src/assets/web-panel/assets/{Services-Bx2Bjhah.js → Services-CZdxjN2B.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-BvJNybjV.js → Skeleton-BI3XNk35.js} +1 -1
  75. package/src/assets/web-panel/assets/Skills-DMlsh9It.js +1 -0
  76. package/src/assets/web-panel/assets/{Sla-BM9gyZwc.js → Sla-HQruznKY.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-Bu9FL9Tz.js → SpeechSettings-Dl-MFq3w.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-D8ICJsMt.js → SyncSettings-BU224vDm.js} +2 -2
  79. package/src/assets/web-panel/assets/Tasks-DESg3yCs.js +1 -0
  80. package/src/assets/web-panel/assets/{Templates-BJzpTD0W.js → Templates-Jb3TPz4Q.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-BN8eX4R2.js → Tenant-CQ-GTrfa.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-CjtP9bpq.js → Terminal-BbMl3Rue.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-CpNRa4XW.js → TimelineRenderer-CS_vstKF.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-2lNNvNAH.js → Tokens-BaopVl1f.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-DxtxXyPg.js → Trigger-DtnD4WUN.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-CakzGeF9.js → Trust-CsvG4Tmf.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-CvJeRXwV.js → UkeySign-C1-A-cOV.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-D80pMzcO.js → VideoEditing-CNgJPdSL.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-BF-VOBmZ.js → Wallet-CdF41501.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-DXyoAzE_.js → WebAuthn-D-JmxD5g.js} +4 -4
  91. package/src/assets/web-panel/assets/{WorkflowEditor-X6CDxzrF.js → WorkflowEditor-C0XunR13.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-BcUhqjeA.js → chat-BBAZpD_G.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-Dw4bKaCm.js → colors-BxSxO5BX.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-BWhu5Eri.js → compact-item-BoxL8pg5.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-BLJ9JKoN.js → createContext-W5JAyZmY.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-BI5TZ7EX.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-DIkCiJbt.js → hasIn-HpiKDPVC.js} +1 -1
  98. package/src/assets/web-panel/assets/index-9-JLDK5n.js +1 -0
  99. package/src/assets/web-panel/assets/{index-BAwcMKaD.js → index-9caMEwQ-.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-0mHbawfQ.js → index-B05_YRHZ.js} +1 -1
  101. package/src/assets/web-panel/assets/index-B7m8ioaQ.js +1 -0
  102. package/src/assets/web-panel/assets/{index-D3wp_jgy.js → index-B9VxE1C-.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BotMuGS2.js → index-BA3WWQAT.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-LOsZYbic.js → index-BSJ0cAle.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C5qms36i.js → index-BW4PP5GN.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CDfB6hWf.js → index-BZAbaY64.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BipG-tDs.js → index-Ba4usRFM.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CgsVg5Up.js → index-BgMViZIY.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CTPoBbIR.js → index-BtFAEG08.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DKzG3kBM.js → index-Bwn6k_qw.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-PRYboDFm.js → index-C4uI7WCB.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DQbWGvE4.js → index-C5kqii-G.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-B1fufz1A.js → index-C7GIUWWF.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DjEP26Te.js → index-CM_gdohF.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BcTch6Fp.js → index-CRg3aOoj.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-04SKBH8l.js → index-CcyzZloJ.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DHLW27Je.js → index-CehxfRUR.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-5vzPcr1g.js → index-D6m6B4Wy.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DV4FSjmI.js → index-DSyfxxQS.js} +3 -3
  120. package/src/assets/web-panel/assets/{index-D5vFJmmX.js → index-DaJk9U9V.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BxLDNxEQ.js → index-DcmAiq_Y.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-D-Erv8A9.js → index-DdEcQ1rp.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CqGqoID5.js → index-DinY7IQa.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BGMzh2oj.js → index-DkSnlgK_.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BxfimJOH.js → index-DlPvZgv8.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DOjQi7oU.js → index-DuM9I1If.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-uMtx6e3D.js → index-DwidpDEE.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CXJ8t1hK.js → index-IO2I7nzu.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-Cmc7qH2C.js → index-JrMBRi62.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BaStonJm.js → index-QzlEbtRL.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Cr05twNa.js → index-V6VIJe2N.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-BGFqk1-E.js → index-_38IJqoP.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-u0tqS0iq.js → index-_p4e3KfB.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-D1r2R4a-.js → index-gvfIRZxJ.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-CFGOV-YT.js → index-ooP1pQCt.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-BUC4TZWg.js → index-p6rNtYud.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-Bx6Hj_FG.js → initDefaultProps-Dfn6M05J.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-BSWivB70.js → motion-BRRwFqGO.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-Dv1Pg9R7.js → move-DpDPN6zR.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-Bqtl8fsk.js → mtc-parser-BHlSE87F.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-DpOBjOSQ.js → omit-CEOri_L5.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-D-M-dz48.js → pickAttrs-DqICh-ad.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-DsTLAifk.js → placementArrow-DQizFFiV.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-BVTetMpc.js → responsiveObserve-DmFHPdvC.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-abEcz-Cv.js → slide-s2s1XS3T.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-CBhrdU2G.js → statusUtils-IwEIbBan.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-CFq8ZCKa.js → styleChecker-CIFLlbXH.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-o4eE7fDV.js → useFlexGapSupport-CFkN2Cgh.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-Hs9W8ihi.js → useFs-BSY6O48s.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-Bnet5Jho.js → usePersonalDataHub-iJl3VnU0.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-DJfN4kWs.js → vnode-vu8ReMs7.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-BzV-2e7X.js → zoom-CeSrYAHp.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/command-help-index.json +2 -2
  155. package/src/commands/agent.js +20 -20
  156. package/src/commands/goal.js +299 -1
  157. package/src/commands/plugin.js +129 -68
  158. package/src/constants.js +2 -2
  159. package/src/data/changelog.json +29 -3
  160. package/src/harness/jsonl-session-store.js +128 -5
  161. package/src/harness/prompt-compressor.js +18 -10
  162. package/src/harness/structured-handoff.js +151 -13
  163. package/src/lib/agent-session-export.js +20 -0
  164. package/src/lib/background-agent-supervisor.js +54 -0
  165. package/src/lib/cli-goal-catalog.js +129 -0
  166. package/src/lib/cli-goal-source.js +119 -0
  167. package/src/lib/coding-task-guidance.js +2 -1
  168. package/src/lib/config-schema.js +1 -1
  169. package/src/lib/context-memory-kernel/live-compaction.js +75 -12
  170. package/src/lib/eval/stream-terminal.js +27 -2
  171. package/src/lib/evolution/evolution-artifact-ports.js +22 -11
  172. package/src/lib/evolution/evolution-file-witness.js +86 -63
  173. package/src/lib/evolution/evolution-ledger-file-backend.js +22 -0
  174. package/src/lib/evolution/evolution-ledger-file-manifest-catalog.js +34 -35
  175. package/src/lib/evolution/evolution-ledger-file-manifest-head-store.js +32 -39
  176. package/src/lib/evolution/evolution-ledger.js +367 -169
  177. package/src/lib/evolution/evolution-manifest-state-reader.js +58 -0
  178. package/src/lib/evolution/evolution-physical-state-reader.js +308 -0
  179. package/src/lib/evolution/evolution-witness-segments.js +12 -13
  180. package/src/lib/evolution/governed-wiki-pruning-ledger-adapter.js +82 -56
  181. package/src/lib/evolution/rrsi-observed-text-index.js +17 -1
  182. package/src/lib/evolution/rrsi-tenant-index-anchor-history.js +5 -0
  183. package/src/lib/execution-location-failure-site.js +20 -3
  184. package/src/lib/goal-store.js +8 -1
  185. package/src/lib/image-input.js +43 -14
  186. package/src/lib/llm-providers.js +1 -0
  187. package/src/lib/plugin-runtime/capabilities.js +10 -0
  188. package/src/lib/plugin-runtime/cli-goal-draft-request.js +138 -0
  189. package/src/lib/plugin-runtime/cli-goal-drafts.js +413 -0
  190. package/src/lib/plugin-runtime/cli-goal-extension-host.js +234 -0
  191. package/src/lib/plugin-runtime/examples/goal-description-drafter/plugin.json +17 -0
  192. package/src/lib/plugin-runtime/examples/goal-evidence-viewer/plugin.json +25 -0
  193. package/src/lib/plugin-runtime/examples/goal-progress-viewer/plugin.json +21 -0
  194. package/src/lib/plugin-runtime/examples/project-delivery-assistant/plugin.json +38 -0
  195. package/src/lib/plugin-runtime/goal-extension-contract.js +190 -0
  196. package/src/lib/plugin-runtime/goal-extensions.js +277 -0
  197. package/src/lib/plugin-runtime/install.js +40 -40
  198. package/src/lib/plugin-runtime/manifest.js +12 -0
  199. package/src/lib/plugin-runtime/policy.js +1 -0
  200. package/src/lib/project-goal-connection.js +225 -0
  201. package/src/lib/project-goal-draft-connection.js +217 -0
  202. package/src/lib/read-file-loop-guard.js +124 -8
  203. package/src/lib/session-host-snapshot.js +3 -0
  204. package/src/lib/session-message-provenance.js +24 -5
  205. package/src/lib/session-tool-round.js +39 -0
  206. package/src/lib/session-transcript-history.js +2 -0
  207. package/src/lib/session-transcript-page.js +4 -1
  208. package/src/lib/session-transcript-structure.js +4 -0
  209. package/src/lib/task-model-selector.js +1 -1
  210. package/src/repl/agent-repl.js +14 -7
  211. package/src/repl/config-summary.js +1 -1
  212. package/src/runtime/__tests__/message-roles.test.js +29 -0
  213. package/src/runtime/agent-core.js +116 -44
  214. package/src/runtime/headless-runner.js +191 -34
  215. package/src/runtime/headless-stream.js +144 -48
  216. package/src/runtime/message-roles.js +43 -0
  217. package/src/runtime/policies/agent-policy.js +1 -0
  218. package/src/workers/background-agent-worker.js +146 -47
  219. package/src/assets/web-panel/assets/EmailListRenderer-DXlmbC45.js +0 -1
  220. package/src/assets/web-panel/assets/MobileProjects-CwA1VoVJ.js +0 -1
  221. package/src/assets/web-panel/assets/Skills-Tz4rQcDp.js +0 -1
  222. package/src/assets/web-panel/assets/Tasks-B6MowBDo.js +0 -1
  223. package/src/assets/web-panel/assets/devWarning-D_MJgDGJ.js +0 -1
  224. package/src/assets/web-panel/assets/index-BP8log78.js +0 -1
  225. package/src/assets/web-panel/assets/index-PexF9zYf.js +0 -1
@@ -66,14 +66,17 @@ import {
66
66
  agentLoop as coreAgentLoop,
67
67
  } from "./agent-core.js";
68
68
  import { composeSystemPrompt } from "./system-prompt.js";
69
- import { collapseConsecutiveMessagesInPlace } from "./message-roles.js";
69
+ import { createResumeRoleProjection } from "./message-roles.js";
70
70
  import {
71
71
  estimateMessagesTokens,
72
72
  sanitizeToolPairs,
73
73
  } from "../harness/prompt-compressor.js";
74
74
  import { compactConversationWithProvider } from "../harness/provider-backed-compaction.js";
75
75
  import { HostResourceBudget } from "../lib/host-resource-budget.js";
76
- import { projectCanonicalResumeMessages } from "../lib/session-message-provenance.js";
76
+ import {
77
+ projectCanonicalResumeMessages,
78
+ markRuntimeOnlySessionMessage,
79
+ } from "../lib/session-message-provenance.js";
77
80
  import { isAbortError } from "../lib/abort-utils.js";
78
81
  import { expandFileRefsAsync } from "./file-ref-expander.js";
79
82
  // Per-turn helpers resolved at module load (not re-`await import`ed inside the
@@ -137,6 +140,7 @@ import {
137
140
  appendToolCallCompact as jsonlAppendToolCallCompact,
138
141
  appendLlmRetryCompact as jsonlAppendLlmRetryCompact,
139
142
  appendCompactEventIfMessagesMatch as jsonlAppendCompactEventIfMessagesMatch,
143
+ appendToolRoundsIfMessagesMatch as jsonlAppendToolRoundsIfMessagesMatch,
140
144
  appendEvent as jsonlAppendEvent,
141
145
  appendAuthorityEvent as jsonlAppendAuthorityEvent,
142
146
  readEvents as jsonlReadEvents,
@@ -965,28 +969,6 @@ async function runTurn(
965
969
  sideEffects?.ledger,
966
970
  );
967
971
 
968
- // Collapse consecutive same-role turns before the model call ONLY when the
969
- // caller flags a resume-degenerate transcript (`mergeRoles`): a resumed
970
- // session whose previous run produced NO assistant response leaves a trailing
971
- // bare `user` turn, so splicing the first live prompt after it sends two
972
- // adjacent `user` messages — which Anthropic/Bedrock reject as "roles must
973
- // alternate" (Claude Code 2.1.187 parity). It is GATED rather than applied
974
- // every turn because the live turn loop legitimately produces consecutive
975
- // `user` messages — an interrupted turn's dangling prompt, a PDH feedback
976
- // note (§3.5.13) — that must reach the model distinctly and must not be
977
- // folded (folding the interrupt-dangling turn even resurrects the abandoned
978
- // request).
979
- //
980
- // Collapse IN PLACE (not a folded copy): the persistent `messages` array is
981
- // reused for every later turn, so leaving the `[user, user]` pair in it would
982
- // re-break the SECOND live turn (which re-sends the lingering pair). The gated
983
- // turn is the first after resume, still tool-free (resumed history is
984
- // user/assistant/system only), so an in-place fold is safe and the helper
985
- // never folds `tool` turns regardless. Un-gated later turns are untouched, so
986
- // the intentional interrupt/feedback consecutive-`user` states are preserved.
987
- if (loopOptions.mergeRoles) {
988
- collapseConsecutiveMessagesInPlace(messages);
989
- }
990
972
  for await (const event of runLoop(messages, loopOptions)) {
991
973
  if (evolutionIngress !== null) {
992
974
  await evolutionIngress.ingestAgentEvent(event);
@@ -2079,10 +2061,8 @@ async function runAgentHeadlessStreamInWorkspace(
2079
2061
  return { exitCode: 1, turns: 0 };
2080
2062
  }
2081
2063
  }
2082
- // Vision model (config.llm.visionModel) — image turns switch to it for that
2083
- // turn only (resolveVisionLlm falls back to the default when unset), so a
2084
- // pasted/typed image is read by a vision-capable model even though the
2085
- // session's default model is text-only.
2064
+ // Vision fallback for a text-only main model. Multimodal main models keep
2065
+ // handling both image turns and follow-ups themselves.
2086
2066
  let visionModel = options.visionModel;
2087
2067
  if (!visionModel) {
2088
2068
  try {
@@ -2294,6 +2274,11 @@ async function runAgentHeadlessStreamInWorkspace(
2294
2274
  ? () => null
2295
2275
  : jsonlFindLatestEvent);
2296
2276
  const store = {
2277
+ appendToolRoundsIfMessagesMatch:
2278
+ deps.appendToolRoundsIfMessagesMatch ||
2279
+ (hasInjectedSessionStore
2280
+ ? unavailableAuthorityCapability("appendToolRoundsIfMessagesMatch")
2281
+ : jsonlAppendToolRoundsIfMessagesMatch),
2297
2282
  sessionExists: deps.sessionExists || jsonlSessionExists,
2298
2283
  startSession: deps.startSession || jsonlStartSession,
2299
2284
  appendUserMessage: deps.appendUserMessage || jsonlAppendUserMessage,
@@ -3282,14 +3267,12 @@ async function runAgentHeadlessStreamInWorkspace(
3282
3267
  }
3283
3268
  }
3284
3269
 
3285
- // Resume-degenerate role sanitation (Claude Code 2.1.187 parity): when the
3286
- // replayed history ends with a bare `user` turn (the prior run produced no
3287
- // assistant response), the FIRST live prompt would make two adjacent `user`
3288
- // messages. Arm a one-shot flag consumed by the first model call so the merge
3289
- // fires exactly once — the live turn loop's intentional consecutive-`user`
3290
- // states (interrupt-dangling turn, PDH feedback note) are never folded.
3270
+ // Capture the first resumed request's adjacent role pairs, then normalize
3271
+ // those pairs in provider projections across later turns. Canonical history
3272
+ // and new feedback/interrupt message pairs retain their original structure.
3291
3273
  let sanitizeRolesNextTurn =
3292
3274
  resumedMessages > 0 && messages[messages.length - 1]?.role === "user";
3275
+ let projectProviderMessages;
3293
3276
 
3294
3277
  if (
3295
3278
  options.taskWorklog === true ||
@@ -3780,6 +3763,63 @@ async function runAgentHeadlessStreamInWorkspace(
3780
3763
  };
3781
3764
  }
3782
3765
 
3766
+ const settleToolRounds = () => {
3767
+ if (
3768
+ !persist ||
3769
+ !messages.some(
3770
+ (message) => message.role === "assistant" && message.tool_calls?.length,
3771
+ )
3772
+ )
3773
+ return;
3774
+ sessionHostLease?.assert?.();
3775
+ const expected = requireSynchronousRecoveryResult(
3776
+ store.readVerifiedProjection(sessionId, () => ({
3777
+ accept() {},
3778
+ finish(authority) {
3779
+ return authority.readMessages();
3780
+ },
3781
+ })),
3782
+ "readVerifiedProjection",
3783
+ );
3784
+ return requireSynchronousRecoveryResult(
3785
+ store.appendToolRoundsIfMessagesMatch(sessionId, messages, expected),
3786
+ "appendToolRoundsIfMessagesMatch",
3787
+ );
3788
+ };
3789
+ const settleToolRoundsForHost = (phase, clientMessageId = null) => {
3790
+ try {
3791
+ settleToolRounds();
3792
+ return true;
3793
+ } catch (error) {
3794
+ const persistence = projectSessionPersistenceFailure(
3795
+ createSessionPersistenceFailure(error, {
3796
+ sessionId,
3797
+ operation: "append-event",
3798
+ }),
3799
+ { phase },
3800
+ );
3801
+ if (persistence) terminalPersistenceFailure = persistence;
3802
+ emit({
3803
+ type: "result",
3804
+ is_error: true,
3805
+ session_id: sessionId,
3806
+ subtype: clientMessageId
3807
+ ? "error_input_receipt"
3808
+ : persistence
3809
+ ? "error_persistence"
3810
+ : "error_session_persistence",
3811
+ code: error?.code || "CC_SESSION_TOOL_ROUND_PERSISTENCE_FAILED",
3812
+ error:
3813
+ "Cannot settle completed tool rounds; refresh the session before continuing",
3814
+ ...(clientMessageId
3815
+ ? { client_message_id: clientMessageId, acceptance: "unknown" }
3816
+ : {}),
3817
+ ...(persistence ? { persistence } : {}),
3818
+ });
3819
+ sawError = true;
3820
+ return false;
3821
+ }
3822
+ };
3783
3823
  const loopOptionsBase = {
3784
3824
  ...(evolutionIngress === null ? {} : { evolutionIngress }),
3785
3825
  model,
@@ -3850,8 +3890,14 @@ async function runAgentHeadlessStreamInWorkspace(
3850
3890
  mcpCallLedger: mcpRecoveryRuntime.ledger,
3851
3891
  mcpDispatchAdmission: sessionHostLease?.admitMcpDispatch || null,
3852
3892
  getTaskWorklogContext: () => taskWorklog?.context() || null,
3853
- onBeforeCompaction: () =>
3854
- updateWorklog((log) => log.record({ type: "before-compaction" })),
3893
+ onBeforeCompaction: () => {
3894
+ updateWorklog((log) => log.record({ type: "before-compaction" }));
3895
+ try {
3896
+ settleToolRounds();
3897
+ } catch (error) {
3898
+ throw markRuntimeLedgerPersistenceError(error);
3899
+ }
3900
+ },
3855
3901
  onCompaction: persist
3856
3902
  ? (stats, compacted, settlement = {}) => {
3857
3903
  sessionHostLease?.assert?.();
@@ -4451,6 +4497,7 @@ async function runAgentHeadlessStreamInWorkspace(
4451
4497
  continue;
4452
4498
  }
4453
4499
  if (parsed.compact) {
4500
+ if (!settleToolRoundsForHost("before-model")) break;
4454
4501
  updateWorklog((log) => log.record({ type: "before-compaction" }));
4455
4502
  const before = messages.length;
4456
4503
  const expectedMessages = [...messages];
@@ -5078,10 +5125,42 @@ async function runAgentHeadlessStreamInWorkspace(
5078
5125
  // fall through into the normal turn machinery with the correction prompt
5079
5126
  } else {
5080
5127
  const tag = kind === "positive" ? "认可" : "不满意";
5081
- messages.push({
5128
+ const feedbackMessage = {
5082
5129
  role: "user",
5083
5130
  content: `(用户反馈:对上一轮回复表示${tag}。请在后续回复中延续/修正此偏好。)`,
5084
- });
5131
+ };
5132
+ if (persist) {
5133
+ if (!settleToolRoundsForHost("before-model")) break;
5134
+ try {
5135
+ sessionHostLease?.assert?.();
5136
+ requireSynchronousRecoveryResult(
5137
+ store.appendUserMessage(sessionId, feedbackMessage.content),
5138
+ "appendUserMessage",
5139
+ );
5140
+ } catch (error) {
5141
+ const persistence = projectSessionPersistenceFailure(
5142
+ createSessionPersistenceFailure(error, {
5143
+ sessionId,
5144
+ operation: "user-turn-append",
5145
+ }),
5146
+ { phase: "before-model" },
5147
+ );
5148
+ if (persistence) terminalPersistenceFailure = persistence;
5149
+ emit({
5150
+ type: "result",
5151
+ subtype: "error_persistence",
5152
+ is_error: true,
5153
+ session_id: sessionId,
5154
+ code: error?.code || "CC_SESSION_FEEDBACK_PERSISTENCE_FAILED",
5155
+ error:
5156
+ "Feedback could not be saved; refresh the session before retrying",
5157
+ ...(persistence ? { persistence } : {}),
5158
+ });
5159
+ sawError = true;
5160
+ break;
5161
+ }
5162
+ }
5163
+ messages.push(feedbackMessage);
5085
5164
  continue;
5086
5165
  }
5087
5166
  }
@@ -5313,8 +5392,8 @@ async function runAgentHeadlessStreamInWorkspace(
5313
5392
  if (conversationHasImages) {
5314
5393
  turnVisionLlm = resolveVisionLlm({
5315
5394
  hasImage: true,
5316
- flags: {},
5317
- llm: { provider, baseUrl, apiKey, visionModel },
5395
+ flags: { visionModel: options.visionModel },
5396
+ llm: { provider, model, baseUrl, apiKey, visionModel },
5318
5397
  });
5319
5398
  if (parsed.images && parsed.images.length) {
5320
5399
  writeErr(
@@ -5359,6 +5438,8 @@ async function runAgentHeadlessStreamInWorkspace(
5359
5438
  let inputReceipt = null;
5360
5439
  let userEventId = null;
5361
5440
  if (persist) {
5441
+ if (!settleToolRoundsForHost("before-model", parsed.clientMessageId))
5442
+ break;
5362
5443
  try {
5363
5444
  if (parsed.clientMessageId) {
5364
5445
  if (!store.appendInputWithReceipt)
@@ -5453,11 +5534,12 @@ async function runAgentHeadlessStreamInWorkspace(
5453
5534
  ? AbortSignal.any([options.signal, currentAbort.signal])
5454
5535
  : currentAbort.signal;
5455
5536
 
5456
- // Consume the one-shot resume-degeneracy flag for THIS turn (see
5457
- // sanitizeRolesNextTurn) so the role merge fires exactly once, whether the
5458
- // model call completes or is interrupted.
5459
- const mergeRolesThisTurn = sanitizeRolesNextTurn;
5460
- sanitizeRolesNextTurn = false;
5537
+ // Capture the resumed pairs once, then normalize those same pairs only in
5538
+ // every provider request. The live authority array retains separate turns.
5539
+ if (sanitizeRolesNextTurn) {
5540
+ projectProviderMessages = createResumeRoleProjection(messages);
5541
+ sanitizeRolesNextTurn = false;
5542
+ }
5461
5543
 
5462
5544
  let outcome;
5463
5545
  try {
@@ -5524,8 +5606,7 @@ async function runAgentHeadlessStreamInWorkspace(
5524
5606
  event.text.trim().length > 0 &&
5525
5607
  !event.text.trimStart().startsWith("/")),
5526
5608
  ),
5527
- // Resume-degenerate role merge for the first live model call only.
5528
- mergeRoles: mergeRolesThisTurn,
5609
+ projectProviderMessages,
5529
5610
  },
5530
5611
  {
5531
5612
  runLoop,
@@ -5642,9 +5723,21 @@ async function runAgentHeadlessStreamInWorkspace(
5642
5723
  // the array length unchanged. sanitizeToolPairs is idempotent on an
5643
5724
  // already-balanced array and leaves user/text turns untouched, so the
5644
5725
  // intentional dangling-user state above is preserved.
5726
+ const originalMessages = new Set(messages);
5645
5727
  const balanced = sanitizeToolPairs(messages);
5728
+ // Only the sanitizer's newly-created commentary for discarded calls
5729
+ // is ephemeral. Existing real messages retain their authority.
5730
+ for (const message of balanced) {
5731
+ if (
5732
+ !originalMessages.has(message) &&
5733
+ message.role === "assistant" &&
5734
+ !message.tool_calls?.length
5735
+ )
5736
+ markRuntimeOnlySessionMessage(message);
5737
+ }
5646
5738
  messages.length = 0;
5647
5739
  messages.push(...balanced);
5740
+ if (!settleToolRoundsForHost("after-model")) break;
5648
5741
  emit({
5649
5742
  type: "result",
5650
5743
  subtype: "interrupted",
@@ -5656,6 +5749,7 @@ async function runAgentHeadlessStreamInWorkspace(
5656
5749
  continue;
5657
5750
  }
5658
5751
  if (isAbort) break; // outer options.signal — caller is shutting down
5752
+ if (!settleToolRoundsForHost("after-model")) break;
5659
5753
  const transportDetails = transportErrorDetails(err);
5660
5754
  emit({
5661
5755
  type: "result",
@@ -5678,6 +5772,7 @@ async function runAgentHeadlessStreamInWorkspace(
5678
5772
  currentAbort = null;
5679
5773
 
5680
5774
  if (outcome.endReason === "user-input-pending") {
5775
+ if (!settleToolRoundsForHost("after-model")) break;
5681
5776
  emit({
5682
5777
  type: "result",
5683
5778
  subtype: "interrupted",
@@ -5740,9 +5835,9 @@ async function runAgentHeadlessStreamInWorkspace(
5740
5835
  }
5741
5836
 
5742
5837
  // Grow the conversation so the next turn has context.
5743
- messages.push({ role: "assistant", content: outcome.finalText });
5744
5838
  let assistantEventId = null;
5745
5839
  if (persist) {
5840
+ if (!settleToolRoundsForHost("after-model")) break;
5746
5841
  try {
5747
5842
  assistantEventId = transcriptMessageEventId(
5748
5843
  store.appendAssistantMessage(sessionId, outcome.finalText),
@@ -5766,6 +5861,7 @@ async function runAgentHeadlessStreamInWorkspace(
5766
5861
  }
5767
5862
  }
5768
5863
  }
5864
+ messages.push({ role: "assistant", content: outcome.finalText });
5769
5865
 
5770
5866
  const exhausted =
5771
5867
  outcome.endReason === "budget-exhausted" ||
@@ -1,3 +1,5 @@
1
+ import { canonicalJson } from "@chainlesschain/context-memory-kernel";
2
+
1
3
  /**
2
4
  * Conversation role sanitation shared by the headless runner and the
3
5
  * stream-json runtime.
@@ -111,6 +113,47 @@ export function mergeConsecutiveMessages(messages) {
111
113
  return out;
112
114
  }
113
115
 
116
+ /**
117
+ * Capture only the adjacent plain-role pairs present at resume. Reapply their
118
+ * provider normalization on later requests without mutating canonical history
119
+ * or folding newly added interrupt/feedback turns. Canonical fingerprints also
120
+ * recognize the same retained messages after compaction recreates objects.
121
+ */
122
+ export function createResumeRoleProjection(messages) {
123
+ const pairs = new Map();
124
+ const pairKey = (left, right) => canonicalJson([left, right]);
125
+ for (let index = 1; index < messages.length; index++) {
126
+ const left = messages[index - 1];
127
+ const right = messages[index];
128
+ if (
129
+ left &&
130
+ right &&
131
+ MERGEABLE_ROLES.has(left.role) &&
132
+ left.role === right.role &&
133
+ !hasToolCalls(left) &&
134
+ !hasToolCalls(right)
135
+ ) {
136
+ const key = pairKey(left, right);
137
+ pairs.set(key, (pairs.get(key) || 0) + 1);
138
+ }
139
+ }
140
+ return (requestMessages) => {
141
+ const remaining = new Map(pairs);
142
+ const projected = [];
143
+ for (let index = 0; index < requestMessages.length; index++) {
144
+ const message = requestMessages[index];
145
+ const key =
146
+ index > 0 ? pairKey(requestMessages[index - 1], message) : null;
147
+ if (key && remaining.get(key) > 0) {
148
+ const previous = projected.pop();
149
+ projected.push(...mergeConsecutiveMessages([previous, message]));
150
+ remaining.set(key, remaining.get(key) - 1);
151
+ } else projected.push(message);
152
+ }
153
+ return projected;
154
+ };
155
+ }
156
+
114
157
  /**
115
158
  * In-place variant: collapse consecutive mergeable-role turns by mutating the
116
159
  * given array (same reference is kept, so closures over it stay valid). Used by
@@ -10,6 +10,7 @@ export function resolveAgentPolicy({
10
10
 
11
11
  return {
12
12
  model: overrides.model || llm.model || defaults.model || "qwen2:7b",
13
+ visionModel: overrides.visionModel,
13
14
  provider:
14
15
  overrides.provider || llm.provider || defaults.provider || "ollama",
15
16
  baseUrl:
@@ -24,6 +24,7 @@ import {
24
24
  deliverBackgroundNeedsInputNotification,
25
25
  insertArgumentsBeforeOptionTerminator,
26
26
  mutateBackgroundAgentState,
27
+ mutateBackgroundAgentStateWithLockRetry,
27
28
  openBackgroundLogFile,
28
29
  readBackgroundAgentState,
29
30
  removeJobFile,
@@ -88,6 +89,7 @@ let server = null;
88
89
  let child = null;
89
90
  let heartbeat = null;
90
91
  let finalized = false;
92
+ let finalizing = false;
91
93
  let phase = "turn";
92
94
  let turnCount = 0;
93
95
  let lastExit = { code: 0, signal: null };
@@ -112,6 +114,79 @@ const pendingInteractions = new Map();
112
114
  // relays the throw as {type:"error", message}) instead of silently queued.
113
115
  const MAX_PROMPT_QUEUE = 100;
114
116
 
117
+ export function isBackgroundAgentWorkerClosing(isFinalized, isFinalizing) {
118
+ return isFinalized === true || isFinalizing === true;
119
+ }
120
+
121
+ export function assertBackgroundAgentWorkerAcceptsPrompt(
122
+ isFinalized,
123
+ isFinalizing,
124
+ ) {
125
+ if (isBackgroundAgentWorkerClosing(isFinalized, isFinalizing)) {
126
+ throw new Error("this background session is closing");
127
+ }
128
+ }
129
+
130
+ function ownsBackgroundAgentWorkerRecord(current, workerPid, workerGeneration) {
131
+ return Boolean(
132
+ current &&
133
+ (!current.workerGeneration ||
134
+ current.workerGeneration === workerGeneration) &&
135
+ (Number(current.workerClaimedPid) === workerPid ||
136
+ (current.workerClaimedPid == null &&
137
+ Number(current.workerPid ?? current.pid) === workerPid)),
138
+ );
139
+ }
140
+
141
+ export function createBackgroundAgentWorkerFinalStateUpdater({
142
+ id,
143
+ workerPid,
144
+ workerGeneration,
145
+ code,
146
+ signal,
147
+ errorMessage,
148
+ now = Date.now,
149
+ }) {
150
+ return (current) => {
151
+ if (!current || !ownsBackgroundAgentWorkerRecord(
152
+ current,
153
+ workerPid,
154
+ workerGeneration,
155
+ )) {
156
+ return null;
157
+ }
158
+ if (current.status !== "running") {
159
+ return { ...current, phase: null, transport: null };
160
+ }
161
+ if (current.stopRequestedAt) return null;
162
+ return {
163
+ ...current,
164
+ id,
165
+ status: errorMessage ? "failed" : code === 0 ? "completed" : "failed",
166
+ endedAt: now(),
167
+ exitCode: errorMessage ? (code ?? 1) : code,
168
+ signal: signal || null,
169
+ ...(errorMessage ? { error: errorMessage } : {}),
170
+ phase: null,
171
+ transport: null,
172
+ };
173
+ };
174
+ }
175
+
176
+ export function isBackgroundAgentWorkerFinalStateSettledOrSuperseded(
177
+ mutation,
178
+ { workerPid, workerGeneration },
179
+ ) {
180
+ if (mutation.applied) return true;
181
+ const current = mutation.state;
182
+ return (
183
+ !current ||
184
+ current.status !== "running" ||
185
+ Boolean(current.stopRequestedAt) ||
186
+ !ownsBackgroundAgentWorkerRecord(current, workerPid, workerGeneration)
187
+ );
188
+ }
189
+
115
190
  /**
116
191
  * Bind one idempotent termination settlement to a turn child.
117
192
  *
@@ -576,36 +651,38 @@ function finalize(code, signal, errorMessage) {
576
651
  // worker and heartbeat alive until its fresh-lease reload either settles
577
652
  // every disk-visible pending request or persists retry evidence.
578
653
  if (interactionFinalSweep) return;
579
- if (finalized) return;
580
- finalized = true;
581
- clearInterval(heartbeat);
582
- try {
583
- mutateBackgroundAgentState(job.id, (current) => {
584
- if (!current) return null;
585
- const ownsRecord =
586
- (!current.workerGeneration ||
587
- current.workerGeneration === job.workerGeneration) &&
588
- (Number(current.workerClaimedPid) === process.pid ||
589
- (current.workerClaimedPid == null &&
590
- Number(current.workerPid ?? current.pid) === process.pid));
591
- if (!ownsRecord) return null;
592
- // An external stop/remove owns an already-terminal or deleted record.
593
- if (current.status !== "running") {
594
- return { ...current, phase: null, transport: null };
654
+ if (finalized || finalizing) return;
655
+ finalizing = true;
656
+
657
+ const workerIdentity = {
658
+ workerPid: process.pid,
659
+ workerGeneration: job.workerGeneration,
660
+ };
661
+ const finish = (persistenceFailed) => {
662
+ finalized = true;
663
+ finalizing = false;
664
+ clearInterval(heartbeat);
665
+ const done = () => {
666
+ keeperClient?.close();
667
+ keeperClient = null;
668
+ try {
669
+ log?.close();
670
+ } catch {
671
+ /* log fd already closed */
595
672
  }
596
- return {
597
- ...current,
598
- id: job.id,
599
- status: errorMessage ? "failed" : code === 0 ? "completed" : "failed",
600
- endedAt: Date.now(),
601
- exitCode: errorMessage ? (code ?? 1) : code,
602
- signal: signal || null,
603
- ...(errorMessage ? { error: errorMessage } : {}),
604
- phase: null,
605
- transport: null,
606
- };
607
- });
608
- } catch (error) {
673
+ const originalExitCode = errorMessage ? 1 : (code ?? 1);
674
+ process.exit(
675
+ persistenceFailed && originalExitCode === 0 ? 1 : originalExitCode,
676
+ );
677
+ };
678
+ if (server) {
679
+ server.broadcast({ type: "closing" });
680
+ server.close().then(done, done);
681
+ } else {
682
+ done();
683
+ }
684
+ };
685
+ const reportPersistenceFailure = (error) => {
609
686
  try {
610
687
  writeSync(
611
688
  2,
@@ -616,23 +693,39 @@ function finalize(code, signal, errorMessage) {
616
693
  } catch {
617
694
  /* inherited stderr may already be closed */
618
695
  }
619
- }
620
- const done = () => {
621
- keeperClient?.close();
622
- keeperClient = null;
623
- try {
624
- log?.close();
625
- } catch {
626
- /* log fd already closed */
627
- }
628
- process.exit(errorMessage ? 1 : (code ?? 1));
629
696
  };
630
- if (server) {
631
- server.broadcast({ type: "closing" });
632
- server.close().then(done, done);
633
- } else {
634
- done();
635
- }
697
+
698
+ void mutateBackgroundAgentStateWithLockRetry(
699
+ job.id,
700
+ createBackgroundAgentWorkerFinalStateUpdater({
701
+ id: job.id,
702
+ ...workerIdentity,
703
+ code,
704
+ signal,
705
+ errorMessage,
706
+ }),
707
+ )
708
+ .then((mutation) => {
709
+ if (
710
+ isBackgroundAgentWorkerFinalStateSettledOrSuperseded(
711
+ mutation,
712
+ workerIdentity,
713
+ )
714
+ ) {
715
+ finish(false);
716
+ return;
717
+ }
718
+ const error = new Error(
719
+ "The active worker still owns a nonterminal state after finalization",
720
+ );
721
+ error.code = "BACKGROUND_AGENT_FINAL_STATE_UNRESOLVED";
722
+ reportPersistenceFailure(error);
723
+ finish(true);
724
+ })
725
+ .catch((error) => {
726
+ reportPersistenceFailure(error);
727
+ finish(true);
728
+ });
636
729
  }
637
730
 
638
731
  function scheduleTurnLaunchSettlementRetry(context, delayMs = 250) {
@@ -946,7 +1039,12 @@ function beginTurnLaunchSettlement({
946
1039
  }
947
1040
 
948
1041
  function startTurn(argv, promptText) {
949
- if (!writeHeartbeat()) return false;
1042
+ if (
1043
+ isBackgroundAgentWorkerClosing(finalized, finalizing) ||
1044
+ !writeHeartbeat()
1045
+ ) {
1046
+ return false;
1047
+ }
950
1048
  const nextTurn = turnCount + 1;
951
1049
  const turnLaunchToken = randomBytes(16).toString("hex");
952
1050
  // Private spawn-generation binding for the dedicated child IPC channel.
@@ -1483,7 +1581,7 @@ function startTurn(argv, promptText) {
1483
1581
  }
1484
1582
 
1485
1583
  function maybeContinue() {
1486
- if (finalized) return;
1584
+ if (isBackgroundAgentWorkerClosing(finalized, finalizing)) return;
1487
1585
  // External stop marked the session terminal while a turn was in flight —
1488
1586
  // don't start another turn against a stopped session.
1489
1587
  const current = readBackgroundAgentState(job.id);
@@ -1696,6 +1794,7 @@ async function main() {
1696
1794
  token,
1697
1795
  getStatus,
1698
1796
  onPrompt: (text) => {
1797
+ assertBackgroundAgentWorkerAcceptsPrompt(finalized, finalizing);
1699
1798
  if (!Array.isArray(job.followUpArgv)) {
1700
1799
  throw new Error(
1701
1800
  "this session was launched without follow-up support — start a new one with cc agent --bg",
@@ -1 +0,0 @@
1
- import{I as C,P as c,J as f,U as r,c as h,_ as k,R as n,V as l,K as d,Q as u,S as g,b as t}from"./vendor-Bn1JzzAn.js";import{_ as j}from"./index-DV4FSjmI.js";import{aH as w}from"./icons-DG5UD-6K.js";const M={__name:"EmailListRenderer",props:{event:{type:Object,required:!0}},setup(_,{expose:m}){m();const a=_,e=t(()=>a.event.content||{}),i=t(()=>a.event.extra||{}),p=t(()=>e.value.from||e.value.sender||e.value.fromName||a.event.actor||"(未知发件人)"),s=t(()=>e.value.subject||e.value.title||"(无主题)"),y=t(()=>e.value.snippet||e.value.preview||e.value.body?.slice(0,100)||null),b=t(()=>Array.isArray(e.value.attachments)?e.value.attachments.length:typeof e.value.attachmentCount=="number"?e.value.attachmentCount:0),x=t(()=>i.value.category||e.value.category),S=t(()=>e.value.unread===!0),T=t(()=>{if(!a.event.occurredAt)return"";const o=new Date(a.event.occurredAt);return`${o.getFullYear()}-${String(o.getMonth()+1).padStart(2,"0")}-${String(o.getDate()).padStart(2,"0")} ${String(o.getHours()).padStart(2,"0")}:${String(o.getMinutes()).padStart(2,"0")}`}),v={props:a,c:e,e:i,fromText:p,subjectText:s,snippetText:y,attachmentCount:b,category:x,isUnread:S,formattedTime:T,computed:t,get MailOutlined(){return w}};return Object.defineProperty(v,"__isScriptSetup",{enumerable:!1,value:!0}),v}},N={class:"email-row"},O={class:"left"},V={class:"body"},A={class:"head"},B={class:"from"},E={class:"time"},L={class:"subject"},R={key:0,class:"snippet"},D={class:"meta"};function H(_,m,a,e,i,p){const s=C("a-tag");return c(),f("div",N,[r("div",O,[h(e.MailOutlined,{class:k(["icon",{unread:e.isUnread}])},null,8,["class"])]),r("div",V,[r("div",A,[r("span",B,n(e.fromText),1),r("span",E,n(e.formattedTime),1)]),r("div",L,n(e.subjectText),1),e.snippetText?(c(),f("div",R,n(e.snippetText),1)):l("v-if",!0),r("div",D,[h(s,{color:"blue",class:"src"},{default:d(()=>[u(n(a.event.source.adapter),1)]),_:1}),e.attachmentCount>0?(c(),g(s,{key:0,color:"orange"},{default:d(()=>[u(" 📎 "+n(e.attachmentCount),1)]),_:1})):l("v-if",!0),e.category?(c(),g(s,{key:1},{default:d(()=>[u(n(e.category),1)]),_:1})):l("v-if",!0)])])])}const P=j(M,[["render",H],["__scopeId","data-v-e4ddf632"],["__file","/tmp/cc-web-panel-HKM6TL/repo/packages/web-panel/src/components/pdh/renderers/EmailListRenderer.vue"]]);export{P as default};
@@ -1 +0,0 @@
1
- import{I as n,J as g,c as l,K as r,N as u,P as h,U as o,R as t,Q as b}from"./vendor-Bn1JzzAn.js";import{_ as v,b as m}from"./index-DV4FSjmI.js";import{a8 as M,M as y}from"./icons-DG5UD-6K.js";const B={__name:"MobileProjects",setup(p,{expose:i}){i();const c=u(),{t:e}=m();function a(){c.push("/projects")}function _(){c.push("/mobile-bridge")}const s={router:c,t:e,goToProjects:a,goToMobileBridge:_,get useRouter(){return u},get useI18n(){return m},get MobileOutlined(){return y},get FolderOutlined(){return M}};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}},x={class:"mobile-projects-placeholder"},O={class:"title"},T={class:"subtitle"},k={class:"explainer"};function w(p,i,c,e,a,_){const s=n("a-alert"),d=n("a-button"),f=n("a-space"),P=n("a-empty"),j=n("a-card");return h(),g("div",x,[l(j,null,{default:r(()=>[l(P,{description:!1},{image:r(()=>[l(e.MobileOutlined,{style:{fontSize:"64px",color:"#bfbfbf"}})]),default:r(()=>[o("h2",O,t(e.t("mobileProjects.title")),1),o("p",T,t(e.t("mobileProjects.subtitle")),1),l(s,{message:e.t("mobileProjects.v02Banner"),type:"info","show-icon":"",class:"banner"},null,8,["message"]),o("div",k,[o("h3",null,t(e.t("mobileProjects.currentDirection")),1),o("p",null,t(e.t("mobileProjects.currentDirectionBody")),1),o("ul",null,[o("li",null,t(e.t("mobileProjects.stepPhone")),1),o("li",null,t(e.t("mobileProjects.stepTap")),1),o("li",null,t(e.t("mobileProjects.stepPull")),1)]),o("h3",null,t(e.t("mobileProjects.reverseDirection")),1),o("p",null,t(e.t("mobileProjects.reverseDirectionBody")),1)]),l(f,{class:"actions"},{default:r(()=>[l(d,{type:"primary",onClick:e.goToProjects},{default:r(()=>[l(e.FolderOutlined),b(" "+t(e.t("mobileProjects.viewLocalProjects")),1)]),_:1}),l(d,{onClick:e.goToMobileBridge},{default:r(()=>[l(e.MobileOutlined),b(" "+t(e.t("mobileProjects.checkBridge")),1)]),_:1})]),_:1})]),_:1})]),_:1})])}const N=v(B,[["render",w],["__scopeId","data-v-9262cc45"],["__file","/tmp/cc-web-panel-HKM6TL/repo/packages/web-panel/src/views/MobileProjects.vue"]]);export{N as default};