chainlesschain 0.166.107 → 0.166.109

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 (184) hide show
  1. package/README.md +18 -9
  2. package/package.json +1 -1
  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-DCx6L_HW.js → AIOps-DkrNbDzS.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-DYm1CN3Z.js → ActionButton-DJjFXDhv.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-D5ItUS_y.js → Analytics-DyUbagRn.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-Cb7XeRdH.js → AppLayout-p7kJWSvn.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-DDDeqCDQ.js → Artifacts-C3rVh4Ak.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-BRt3x13w.js → Audit-Bch_L_YO.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-C_oNALMd.js → BackgroundAgents-BNHy8zP6.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-PSU2p6CR.js → Backup-BUaye_Ys.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-G3oL4hcX.js → BaseInput-D49mzAVz.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-C2cLI10b.js → Chat-2MDzM_us.js} +6 -6
  15. package/src/assets/web-panel/assets/ChatBubbleRenderer-DOX3Y5EJ.js +1 -0
  16. package/src/assets/web-panel/assets/{Checkbox-CHLnEgFD.js → Checkbox-5p1T_KEq.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-DZm9g_Bc.js → Codegen-TKtiLaoZ.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-D5Z4zSay.js → Col-BVCMG9mS.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-DHw69NSk.js → Community-D09-QczH.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-B-vjYNWz.js → Compact-QuRMCnj7.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-DaIYVZQY.js → Compliance-CN0PV7fk.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-CoA9U-gF.js → Cowork-5N2zhAty.js} +2 -2
  23. package/src/assets/web-panel/assets/{Cron-DXqmxlRC.js → Cron-BxT8UZ0S.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-Cdkc3ue1.js → Crosschain-Dp-noQl4.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-oKfYyNSR.js → DID-B7MZFkjG.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-n_ycvgWu.js → Dashboard-DulJ3rKV.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-D38rZ8WY.js → Dropdown-DV4ov4zF.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer-BjreeBQ1.js → EmailListRenderer-DB2-ooz6.js} +1 -1
  29. package/src/assets/web-panel/assets/{EvolutionSettings-CTxA_SIq.js → EvolutionSettings-B1Rb6p7q.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DmECNwV5.js → FamilyGuardDashboard-U8aHayx-.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-B2IaaDmQ.js → Federation-BkQULBHY.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-DgcgqUIk.js → FormItemContext-CtviG260.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-B1-du6Qm.js → GenericCardRenderer-DnPirB24.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-XceM21Il.js → Git-CK57Oro6.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-CV97iz3z.js → Governance-DbI-LB8-.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-CI7fj305.js → Inference-sEG4T1Jg.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-B5mekWRy.js → KnowledgeGraph-9SLJR3h9.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-BlxFA0xY.js → Logs-BIZYcISQ.js} +2 -2
  39. package/src/assets/web-panel/assets/{MarkdownRenderer-rDE-XyMY.js → MarkdownRenderer-9nfWupWP.js} +1 -1
  40. package/src/assets/web-panel/assets/{Marketplace-DL1BVCiX.js → Marketplace-CRmLLwAE.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-BPtwrO3c.js → McpTools-DkOFkSO1.js} +3 -3
  42. package/src/assets/web-panel/assets/{Memory-DuSNw4E-.js → Memory-M29Kd9TU.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-DTgY9ywI.js → MobileBridge-Tl6JvPw_.js} +1 -1
  44. package/src/assets/web-panel/assets/MobileProjects-Bq-FPDzS.js +1 -0
  45. package/src/assets/web-panel/assets/{Mtc-h4fCLjXw.js → Mtc-DkUjX1F5.js} +2 -2
  46. package/src/assets/web-panel/assets/{MtcAudit-fqMDY3-w.js → MtcAudit-BCqr1I4q.js} +2 -2
  47. package/src/assets/web-panel/assets/{Multisig-Do3FehBL.js → Multisig-DmoqYGQ5.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-CQVY0kQF.js → NLProgramming-DNRQeRke.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-4c3oNvWh.js → Notes-CQSBeiY6.js} +3 -3
  50. package/src/assets/web-panel/assets/{NotificationSettings-BKr2JD4k.js → NotificationSettings-gNY9bbH6.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-Bq4jgzRt.js → OrderTableRenderer-DW0CNjh8.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-Dy3XidyA.js → Organization-CthnbKag.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-DFF0qN5K.js → Overflow-_GQ3sbXu.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-DAgYYykd.js → P2P-BTr7ea6W.js} +2 -2
  55. package/src/assets/web-panel/assets/PdhVaultBrowser-D9McHF9I.js +7 -0
  56. package/src/assets/web-panel/assets/{Permissions-Cev6uSBc.js → Permissions-DMny2Cjs.js} +3 -3
  57. package/src/assets/web-panel/assets/{PersonalDataHub-DJzbN06K.js → PersonalDataHub-CyYlMSoI.js} +4 -4
  58. package/src/assets/web-panel/assets/{Pipeline-CoJWvbQ5.js → Pipeline-FASu2Oc4.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-DZxV6etm.js → Privacy-9bC5FnsJ.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-BFW87JnM.js → ProjectInit-BOYZwB5G.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-LBrRT27p.js → ProjectSettings-45DViNG-.js} +2 -2
  62. package/src/assets/web-panel/assets/Projects-C2fZzMZc.js +1 -0
  63. package/src/assets/web-panel/assets/{Providers-CnRbjOYk.js → Providers-BgjvZx9F.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-BVFnIS3r.js → QrScannerModal-Brw-3csB.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-DrcHx5f1.js → QuickAsk-DWG-A5zB.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-CbRgrSJm.js → Recommend-DuQGxjIR.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-B2Uz_ElB.js → RemoteSession-T1cdSSRL.js} +2 -2
  68. package/src/assets/web-panel/assets/{Reputation-DS0ljTxL.js → Reputation-9FT2dI4G.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-ClLobFht.js → Row-yNIbNftX.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-DxxcTD0x.js → RssFeed-BIchNoPd.js} +3 -3
  71. package/src/assets/web-panel/assets/{Search-BbHN0Fik.js → Search-msDJ8UTZ.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-BAVU_EcY.js → Security-DE46oBYT.js} +3 -3
  73. package/src/assets/web-panel/assets/{Services-CtqRSVq_.js → Services-Dori7vc3.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-IJ8ZKdSZ.js → Skeleton-D3O3sUFz.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-DXxcznnO.js → Skills-BV0ct8SO.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-fRkhnA3i.js → Sla-DflIVOrh.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-Bi8sYJ-I.js → SpeechSettings-Cpbv2Zz6.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-CjeplUtS.js → SyncSettings-Dgg6-wbe.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-D4KB2Hbx.js → Tasks-Cb6e4Klx.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-BwVugi8n.js → Templates-GfdAATGz.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-CsPuu5xK.js → Tenant-D0gecLXl.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-DuaeOPjY.js → Terminal-BFRPJt-0.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-D-PMrFxO.js → TimelineRenderer-BobtChxX.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-BXZuiQPZ.js → Tokens-CifeZtHV.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-DgpTaHL3.js → Trigger-BHBvbBCf.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-Bn7lEGRY.js → Trust-6lvqjKYp.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-zz-8JAAQ.js → UkeySign-CqzMc-G5.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-DCzfQGTc.js → VideoEditing-OIiRG582.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-BiRHM_zB.js → Wallet-4MeKq0q_.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-QmPo2JwU.js → WebAuthn-eHBRjGQG.js} +5 -5
  91. package/src/assets/web-panel/assets/{WorkflowEditor-gL7SsPnY.js → WorkflowEditor-DlzYdEqW.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-BysvK4hk.js → chat-CBcjOzkX.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-CQq20vqN.js → colors-zgwsYQSa.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-CAHlOf1X.js → compact-item-Dcd9H5Bn.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-BeF3ESj_.js → createContext-DR1tO-8r.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-DYhpRtve.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-CiqnRf-U.js → hasIn-CtfbUH_p.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-Cp3IRTDK.js → index-5XaB_Tjg.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DKYbru3i.js → index-B3QUK1ks.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CCX0daFQ.js → index-BXfGHUz_.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CgkUkmEJ.js → index-BndPtS9D.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-zNkw0IY7.js → index-BoxowMYS.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-i9aJV9qk.js → index-C0kP88Pb.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BtWchYfW.js → index-C5XGvJb0.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BHpHGGmB.js → index-CPLLgPxA.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-qjaCk1Mj.js → index-CSQCHpDo.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CImCEo8S.js → index-CT7zIkqP.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Br5tGVbC.js → index-CaGNqkY0.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-xwtRrgVY.js → index-Cdhy5ckh.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CowbNBJs.js → index-CmVIM-m2.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CTp89vmg.js → index-CmzQzTY5.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-D7q5VH2n.js → index-Cur8LNNn.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CeIL3-nY.js → index-CwHgaYVH.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-jJhemX1R.js → index-D1GxtY-h.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DTPUVm71.js → index-D7ZOiIKb.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-QALafVsT.js → index-D8WPohye.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-ZBuJ6O6g.js → index-DA2-Bhy8.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-B5941vyo.js → index-DHEiuvhA.js} +1 -1
  119. package/src/assets/web-panel/assets/index-DPJXFIY7.js +1 -0
  120. package/src/assets/web-panel/assets/{index-BsnLkZjz.js → index-DSvcz0RO.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DHGtFwwR.js → index-DTx4FyLU.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BOiyW31p.js → index-DVpp9YSQ.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-B2AOvjgR.js → index-DWG98orp.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BfJabF_8.js → index-DWuCGhHa.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DBmGQHEz.js → index-DYPMJ5Mb.js} +3 -3
  126. package/src/assets/web-panel/assets/{index-B2xbtl_c.js → index-DeAi4CNt.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Bvkbj3x-.js → index-DfzOYmOj.js} +1 -1
  128. package/src/assets/web-panel/assets/index-DjBhR5M_.js +1 -0
  129. package/src/assets/web-panel/assets/{index-DXsXhR7p.js → index-DvPOpvvH.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-yFQWSRoW.js → index-J-ORW1i6.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-TdVEaJfk.js → index-JSfldpw4.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-CcccefJc.js → index-LN7Hkl1C.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-Dqkls2_6.js → index-dvF6C39V.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-BcVmt6u_.js → index-hTcre7U9.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-DXT7MKkD.js → index-oWOlF7CM.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-4a0Lmz_y.js → index-z8lrkcb-.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-BQR2HnKb.js → initDefaultProps-CVMtDrWZ.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-gAz6l-nZ.js → motion-Dye3IU8k.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-Cy5TN856.js → move-C251Zo34.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-BeT7VrGi.js → mtc-parser-BDiOORoQ.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-BLN3mlgK.js → omit-DTDA_RHv.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-DtwZ8u2d.js → pickAttrs-CqEUTPcT.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-ViMwQSa-.js → placementArrow-BOB8QWH3.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-dEL3u4E7.js → responsiveObserve-CZDXP1d9.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-l05us-Gz.js → slide-DPaRw3E9.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-Bk-Qn2Og.js → statusUtils-Ba9d7XZ7.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-Bn186qeY.js → styleChecker-mZKU3lvW.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-WP-ugR3H.js → useFlexGapSupport-VcauLq0M.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-1SvoeSCL.js → useFs-Cal9KRcx.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-CfNU8N3z.js → usePersonalDataHub-DISoRyQB.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-Bd2Ya101.js → vnode-B58C6w6B.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-Def_MeZv.js → zoom-BPlBAMKB.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/data/changelog.json +29 -3
  155. package/src/gateways/ws/llm-chat-protocol.js +12 -2
  156. package/src/gateways/ws/llm-creds.js +50 -22
  157. package/src/gateways/ws/ws-server.js +47 -0
  158. package/src/harness/jsonl-session-store.js +128 -5
  159. package/src/harness/prompt-compressor.js +18 -10
  160. package/src/harness/structured-handoff.js +151 -13
  161. package/src/lib/agent-session-export.js +20 -0
  162. package/src/lib/background-agent-supervisor.js +54 -0
  163. package/src/lib/coding-task-guidance.js +2 -1
  164. package/src/lib/context-memory-kernel/live-compaction.js +75 -12
  165. package/src/lib/read-file-loop-guard.js +124 -8
  166. package/src/lib/session-host-snapshot.js +3 -0
  167. package/src/lib/session-message-provenance.js +24 -5
  168. package/src/lib/session-tool-round.js +39 -0
  169. package/src/lib/session-transcript-history.js +2 -0
  170. package/src/lib/session-transcript-page.js +4 -1
  171. package/src/lib/session-transcript-structure.js +4 -0
  172. package/src/runtime/__tests__/message-roles.test.js +29 -0
  173. package/src/runtime/agent-core.js +115 -43
  174. package/src/runtime/headless-runner.js +191 -34
  175. package/src/runtime/headless-stream.js +140 -42
  176. package/src/runtime/message-roles.js +43 -0
  177. package/src/workers/background-agent-worker.js +146 -47
  178. package/src/assets/web-panel/assets/ChatBubbleRenderer-KX1OITf8.js +0 -1
  179. package/src/assets/web-panel/assets/MobileProjects-CTpVHJMa.js +0 -1
  180. package/src/assets/web-panel/assets/PdhVaultBrowser-DgNHa8b1.js +0 -7
  181. package/src/assets/web-panel/assets/Projects-O3uz76R1.js +0 -1
  182. package/src/assets/web-panel/assets/devWarning-D-Iugqxv.js +0 -1
  183. package/src/assets/web-panel/assets/index-B0Oz2_rQ.js +0 -1
  184. package/src/assets/web-panel/assets/index-DwoycEQa.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);
@@ -2292,6 +2274,11 @@ async function runAgentHeadlessStreamInWorkspace(
2292
2274
  ? () => null
2293
2275
  : jsonlFindLatestEvent);
2294
2276
  const store = {
2277
+ appendToolRoundsIfMessagesMatch:
2278
+ deps.appendToolRoundsIfMessagesMatch ||
2279
+ (hasInjectedSessionStore
2280
+ ? unavailableAuthorityCapability("appendToolRoundsIfMessagesMatch")
2281
+ : jsonlAppendToolRoundsIfMessagesMatch),
2295
2282
  sessionExists: deps.sessionExists || jsonlSessionExists,
2296
2283
  startSession: deps.startSession || jsonlStartSession,
2297
2284
  appendUserMessage: deps.appendUserMessage || jsonlAppendUserMessage,
@@ -3280,14 +3267,12 @@ async function runAgentHeadlessStreamInWorkspace(
3280
3267
  }
3281
3268
  }
3282
3269
 
3283
- // Resume-degenerate role sanitation (Claude Code 2.1.187 parity): when the
3284
- // replayed history ends with a bare `user` turn (the prior run produced no
3285
- // assistant response), the FIRST live prompt would make two adjacent `user`
3286
- // messages. Arm a one-shot flag consumed by the first model call so the merge
3287
- // fires exactly once — the live turn loop's intentional consecutive-`user`
3288
- // 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.
3289
3273
  let sanitizeRolesNextTurn =
3290
3274
  resumedMessages > 0 && messages[messages.length - 1]?.role === "user";
3275
+ let projectProviderMessages;
3291
3276
 
3292
3277
  if (
3293
3278
  options.taskWorklog === true ||
@@ -3778,6 +3763,63 @@ async function runAgentHeadlessStreamInWorkspace(
3778
3763
  };
3779
3764
  }
3780
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
+ };
3781
3823
  const loopOptionsBase = {
3782
3824
  ...(evolutionIngress === null ? {} : { evolutionIngress }),
3783
3825
  model,
@@ -3848,8 +3890,14 @@ async function runAgentHeadlessStreamInWorkspace(
3848
3890
  mcpCallLedger: mcpRecoveryRuntime.ledger,
3849
3891
  mcpDispatchAdmission: sessionHostLease?.admitMcpDispatch || null,
3850
3892
  getTaskWorklogContext: () => taskWorklog?.context() || null,
3851
- onBeforeCompaction: () =>
3852
- 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
+ },
3853
3901
  onCompaction: persist
3854
3902
  ? (stats, compacted, settlement = {}) => {
3855
3903
  sessionHostLease?.assert?.();
@@ -4449,6 +4497,7 @@ async function runAgentHeadlessStreamInWorkspace(
4449
4497
  continue;
4450
4498
  }
4451
4499
  if (parsed.compact) {
4500
+ if (!settleToolRoundsForHost("before-model")) break;
4452
4501
  updateWorklog((log) => log.record({ type: "before-compaction" }));
4453
4502
  const before = messages.length;
4454
4503
  const expectedMessages = [...messages];
@@ -5076,10 +5125,42 @@ async function runAgentHeadlessStreamInWorkspace(
5076
5125
  // fall through into the normal turn machinery with the correction prompt
5077
5126
  } else {
5078
5127
  const tag = kind === "positive" ? "认可" : "不满意";
5079
- messages.push({
5128
+ const feedbackMessage = {
5080
5129
  role: "user",
5081
5130
  content: `(用户反馈:对上一轮回复表示${tag}。请在后续回复中延续/修正此偏好。)`,
5082
- });
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);
5083
5164
  continue;
5084
5165
  }
5085
5166
  }
@@ -5357,6 +5438,8 @@ async function runAgentHeadlessStreamInWorkspace(
5357
5438
  let inputReceipt = null;
5358
5439
  let userEventId = null;
5359
5440
  if (persist) {
5441
+ if (!settleToolRoundsForHost("before-model", parsed.clientMessageId))
5442
+ break;
5360
5443
  try {
5361
5444
  if (parsed.clientMessageId) {
5362
5445
  if (!store.appendInputWithReceipt)
@@ -5451,11 +5534,12 @@ async function runAgentHeadlessStreamInWorkspace(
5451
5534
  ? AbortSignal.any([options.signal, currentAbort.signal])
5452
5535
  : currentAbort.signal;
5453
5536
 
5454
- // Consume the one-shot resume-degeneracy flag for THIS turn (see
5455
- // sanitizeRolesNextTurn) so the role merge fires exactly once, whether the
5456
- // model call completes or is interrupted.
5457
- const mergeRolesThisTurn = sanitizeRolesNextTurn;
5458
- 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
+ }
5459
5543
 
5460
5544
  let outcome;
5461
5545
  try {
@@ -5522,8 +5606,7 @@ async function runAgentHeadlessStreamInWorkspace(
5522
5606
  event.text.trim().length > 0 &&
5523
5607
  !event.text.trimStart().startsWith("/")),
5524
5608
  ),
5525
- // Resume-degenerate role merge for the first live model call only.
5526
- mergeRoles: mergeRolesThisTurn,
5609
+ projectProviderMessages,
5527
5610
  },
5528
5611
  {
5529
5612
  runLoop,
@@ -5640,9 +5723,21 @@ async function runAgentHeadlessStreamInWorkspace(
5640
5723
  // the array length unchanged. sanitizeToolPairs is idempotent on an
5641
5724
  // already-balanced array and leaves user/text turns untouched, so the
5642
5725
  // intentional dangling-user state above is preserved.
5726
+ const originalMessages = new Set(messages);
5643
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
+ }
5644
5738
  messages.length = 0;
5645
5739
  messages.push(...balanced);
5740
+ if (!settleToolRoundsForHost("after-model")) break;
5646
5741
  emit({
5647
5742
  type: "result",
5648
5743
  subtype: "interrupted",
@@ -5654,6 +5749,7 @@ async function runAgentHeadlessStreamInWorkspace(
5654
5749
  continue;
5655
5750
  }
5656
5751
  if (isAbort) break; // outer options.signal — caller is shutting down
5752
+ if (!settleToolRoundsForHost("after-model")) break;
5657
5753
  const transportDetails = transportErrorDetails(err);
5658
5754
  emit({
5659
5755
  type: "result",
@@ -5676,6 +5772,7 @@ async function runAgentHeadlessStreamInWorkspace(
5676
5772
  currentAbort = null;
5677
5773
 
5678
5774
  if (outcome.endReason === "user-input-pending") {
5775
+ if (!settleToolRoundsForHost("after-model")) break;
5679
5776
  emit({
5680
5777
  type: "result",
5681
5778
  subtype: "interrupted",
@@ -5738,9 +5835,9 @@ async function runAgentHeadlessStreamInWorkspace(
5738
5835
  }
5739
5836
 
5740
5837
  // Grow the conversation so the next turn has context.
5741
- messages.push({ role: "assistant", content: outcome.finalText });
5742
5838
  let assistantEventId = null;
5743
5839
  if (persist) {
5840
+ if (!settleToolRoundsForHost("after-model")) break;
5744
5841
  try {
5745
5842
  assistantEventId = transcriptMessageEventId(
5746
5843
  store.appendAssistantMessage(sessionId, outcome.finalText),
@@ -5764,6 +5861,7 @@ async function runAgentHeadlessStreamInWorkspace(
5764
5861
  }
5765
5862
  }
5766
5863
  }
5864
+ messages.push({ role: "assistant", content: outcome.finalText });
5767
5865
 
5768
5866
  const exhausted =
5769
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
@@ -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 v,P as u,J as S,U as n,R as a,S as y,K as C,Q as x,V as w,_ as B,b as s}from"./vendor-Bn1JzzAn.js";import{_ as k}from"./index-DBmGQHEz.js";import"./icons-DG5UD-6K.js";const M={__name:"ChatBubbleRenderer",props:{event:{type:Object,required:!0}},setup(c,{expose:d}){d();const t=c,r=s(()=>{const e=t.event.content||{};return e.text||e.body||e.message||e.title||JSON.stringify(e).slice(0,200)}),i=s(()=>{const e=t.event.content||{};return e.from||e.sender||e.senderName||t.event.actor||"(unknown)"}),l=s(()=>{const e=(t.event.actor||"").toLowerCase();return e.includes("self")||e==="me"||e.endsWith("_self")}),o=s(()=>{const e=t.event.source.adapter||"";return e.startsWith("messaging-qq")?"magenta":e==="wechat"?"green":"blue"}),m=s(()=>{if(!t.event.occurredAt)return"";try{const e=new Date(t.event.occurredAt),p=e.getFullYear(),f=String(e.getMonth()+1).padStart(2,"0"),g=String(e.getDate()).padStart(2,"0"),b=String(e.getHours()).padStart(2,"0"),h=String(e.getMinutes()).padStart(2,"0");return`${p}-${f}-${g} ${b}:${h}`}catch{return""}}),_={props:t,messageText:r,actorLabel:i,isMine:l,adapterColor:o,formattedTime:m,computed:s};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}},N={class:"bubble"},T={class:"meta"},R={class:"actor"},V={class:"time"},W={class:"body"};function q(c,d,t,r,i,l){const o=v("a-tag");return u(),S("div",{class:B(["chat-row",{mine:r.isMine}])},[n("div",N,[n("div",T,[n("span",R,a(r.actorLabel),1),n("span",V,a(r.formattedTime),1)]),n("div",W,a(r.messageText),1),t.event.source.adapter?(u(),y(o,{key:0,class:"src",color:r.adapterColor},{default:C(()=>[x(a(t.event.source.adapter),1)]),_:1},8,["color"])):w("v-if",!0)])],2)}const O=k(M,[["render",q],["__scopeId","data-v-49238629"],["__file","/tmp/cc-web-panel-JUM1WW/repo/packages/web-panel/src/components/pdh/renderers/ChatBubbleRenderer.vue"]]);export{O 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-DBmGQHEz.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"},k={class:"subtitle"},w={class:"explainer"};function T(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",k,t(e.t("mobileProjects.subtitle")),1),l(s,{message:e.t("mobileProjects.v02Banner"),type:"info","show-icon":"",class:"banner"},null,8,["message"]),o("div",w,[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",T],["__scopeId","data-v-9262cc45"],["__file","/tmp/cc-web-panel-JUM1WW/repo/packages/web-panel/src/views/MobileProjects.vue"]]);export{N as default};