chainlesschain 0.162.189 → 0.162.197

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 (317) hide show
  1. package/README.md +84 -11
  2. package/bin/chainlesschain.js +7 -52
  3. package/completions/_cc +209 -0
  4. package/completions/cc.bash +18 -0
  5. package/completions/cc.fish +13 -0
  6. package/completions/cc.ps1 +226 -0
  7. package/package.json +10 -2
  8. package/src/assets/web-panel/assets/{AIOps-DbZft8w0.js → AIOps-D3Gu1a5d.js} +1 -1
  9. package/src/assets/web-panel/assets/{ActionButton-DoOZpwfN.js → ActionButton-DrwAoKaz.js} +1 -1
  10. package/src/assets/web-panel/assets/{Analytics-B0J0KLTW.js → Analytics-C7Q-gd_3.js} +3 -3
  11. package/src/assets/web-panel/assets/{AppLayout-D9eIR0qq.js → AppLayout-DgBtae-n.js} +4 -4
  12. package/src/assets/web-panel/assets/{Artifacts-BnZXEVeo.js → Artifacts-pQ6LcA-W.js} +1 -1
  13. package/src/assets/web-panel/assets/{Audit-X1ce4Bjn.js → Audit-DK61tocB.js} +1 -1
  14. package/src/assets/web-panel/assets/{BackgroundAgents-BvWR-y5v.js → BackgroundAgents-BOKgDFRh.js} +1 -1
  15. package/src/assets/web-panel/assets/{Backup-BublSGEd.js → Backup-Bo9G4vTP.js} +1 -1
  16. package/src/assets/web-panel/assets/{BaseInput-CR_77Hso.js → BaseInput-Do_dE9_v.js} +1 -1
  17. package/src/assets/web-panel/assets/{Chat-DixW52tq.js → Chat-COVvZzOL.js} +6 -6
  18. package/src/assets/web-panel/assets/ChatBubbleRenderer-BUUyJ5QO.js +1 -0
  19. package/src/assets/web-panel/assets/{Checkbox-CCv1C87K.js → Checkbox-Z9MJMolt.js} +1 -1
  20. package/src/assets/web-panel/assets/{Codegen-B03Cc3dd.js → Codegen-BVzWKVbf.js} +1 -1
  21. package/src/assets/web-panel/assets/{Col-CA06-6pU.js → Col-C8MnYcbT.js} +1 -1
  22. package/src/assets/web-panel/assets/{Community-Bj881J52.js → Community-DQxqw15l.js} +1 -1
  23. package/src/assets/web-panel/assets/{Compact-UZLTPoaL.js → Compact-BAUmrh3y.js} +1 -1
  24. package/src/assets/web-panel/assets/{Compliance-kGwzRb_0.js → Compliance-jPAkQ3zK.js} +1 -1
  25. package/src/assets/web-panel/assets/{Cowork-KundoYM8.js → Cowork-BBQyxbh8.js} +2 -2
  26. package/src/assets/web-panel/assets/{Cron-BYZyoqDe.js → Cron-W5koq8Z5.js} +2 -2
  27. package/src/assets/web-panel/assets/{Crosschain-BhrrppBX.js → Crosschain-BQhnu5hS.js} +1 -1
  28. package/src/assets/web-panel/assets/{DID-CdC6EguZ.js → DID-DD7PlI18.js} +2 -2
  29. package/src/assets/web-panel/assets/{Dashboard-CcQx3J4y.js → Dashboard-w_ILuwKI.js} +2 -2
  30. package/src/assets/web-panel/assets/{Dropdown-BpijtEzQ.js → Dropdown-qiDUAyAo.js} +1 -1
  31. package/src/assets/web-panel/assets/{EmailListRenderer-DfZjeZTe.js → EmailListRenderer-PDeBcI5H.js} +1 -1
  32. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BFYSf69C.js → FamilyGuardDashboard-SuArscRM.js} +1 -1
  33. package/src/assets/web-panel/assets/{Federation-Okdi3pJm.js → Federation-BCovZaUn.js} +1 -1
  34. package/src/assets/web-panel/assets/{FormItemContext-mH-HebKW.js → FormItemContext-DjlFdVFk.js} +1 -1
  35. package/src/assets/web-panel/assets/{GenericCardRenderer-xivV69x7.js → GenericCardRenderer-DoEZ7fcS.js} +1 -1
  36. package/src/assets/web-panel/assets/{Git-1rh_YBwg.js → Git-CV0-6GPI.js} +2 -2
  37. package/src/assets/web-panel/assets/{Governance-eAXkNxdY.js → Governance-B_SFN50w.js} +1 -1
  38. package/src/assets/web-panel/assets/{Inference-CS6dMVTN.js → Inference-heI0Eo6k.js} +1 -1
  39. package/src/assets/web-panel/assets/{KnowledgeGraph-Bq_TnkvD.js → KnowledgeGraph-Cz5INS5p.js} +1 -1
  40. package/src/assets/web-panel/assets/{Logs-KchHtiHt.js → Logs-BSFxiHkg.js} +2 -2
  41. package/src/assets/web-panel/assets/MarkdownRenderer-1mNozZ8v.js +1 -0
  42. package/src/assets/web-panel/assets/{Marketplace-CsmGcX5X.js → Marketplace-0TWTpE7k.js} +1 -1
  43. package/src/assets/web-panel/assets/{McpTools-BaPFnnyz.js → McpTools-CV4-wBLm.js} +4 -4
  44. package/src/assets/web-panel/assets/{Memory-2m-sUUf7.js → Memory-x5bH5rw5.js} +2 -2
  45. package/src/assets/web-panel/assets/{MobileBridge-D5nVZBRu.js → MobileBridge-DaBmUu9G.js} +1 -1
  46. package/src/assets/web-panel/assets/{MobileProjects-Bo8MLZvT.js → MobileProjects-DqnoFPgR.js} +1 -1
  47. package/src/assets/web-panel/assets/{Mtc-3GDvamGa.js → Mtc-B_zKEBif.js} +4 -4
  48. package/src/assets/web-panel/assets/{MtcAudit-D2zGuZCH.js → MtcAudit-BCfKD2yg.js} +4 -4
  49. package/src/assets/web-panel/assets/{Multisig-BBVQ4t6t.js → Multisig-DgYfj6c_.js} +3 -3
  50. package/src/assets/web-panel/assets/{NLProgramming-BIOCyOGp.js → NLProgramming-Dz09lFUm.js} +1 -1
  51. package/src/assets/web-panel/assets/{Notes-DVwBGpzc.js → Notes-Cuj6ugBE.js} +3 -3
  52. package/src/assets/web-panel/assets/{NotificationSettings-BDnHfIfX.js → NotificationSettings-DK2WXjhg.js} +1 -1
  53. package/src/assets/web-panel/assets/{OrderTableRenderer-C7Ek20ag.js → OrderTableRenderer-D1IAOQoo.js} +1 -1
  54. package/src/assets/web-panel/assets/{Organization-D3SRKaa7.js → Organization-9fqnPvTw.js} +4 -4
  55. package/src/assets/web-panel/assets/{Overflow-C2B8ahyn.js → Overflow-n5xHkhow.js} +1 -1
  56. package/src/assets/web-panel/assets/{P2P-2iwQzG65.js → P2P-B5AUWwH-.js} +2 -2
  57. package/src/assets/web-panel/assets/{PdhVaultBrowser-CoPiWqMN.js → PdhVaultBrowser-CoUDV6dy.js} +4 -4
  58. package/src/assets/web-panel/assets/{Permissions-yV5XNXo5.js → Permissions-DPRmQf_H.js} +4 -4
  59. package/src/assets/web-panel/assets/{PersonalDataHub-uCDJhMUF.js → PersonalDataHub-B37bsbEN.js} +4 -4
  60. package/src/assets/web-panel/assets/{Pipeline-hN7ucMOA.js → Pipeline-CCAuPqu9.js} +1 -1
  61. package/src/assets/web-panel/assets/{Privacy-CgU0ptN4.js → Privacy-B81msZdv.js} +1 -1
  62. package/src/assets/web-panel/assets/{ProjectInit-CfYPiT6j.js → ProjectInit-B-Py2NbF.js} +2 -2
  63. package/src/assets/web-panel/assets/{ProjectSettings-B0A2C4nw.js → ProjectSettings-CYsneiRB.js} +2 -2
  64. package/src/assets/web-panel/assets/{Projects-BE5C0ajn.js → Projects-Y975Mh6R.js} +1 -1
  65. package/src/assets/web-panel/assets/{Providers-CstQPf8W.js → Providers-uO-10aP1.js} +1 -1
  66. package/src/assets/web-panel/assets/{QrScannerModal-Co3z_ynk.js → QrScannerModal-Bj_6gJ0l.js} +1 -1
  67. package/src/assets/web-panel/assets/{QuickAsk-DMTS6pQ6.js → QuickAsk-BgpBCMPE.js} +1 -1
  68. package/src/assets/web-panel/assets/{Recommend-ETw4odUa.js → Recommend-DhUW3YUA.js} +1 -1
  69. package/src/assets/web-panel/assets/RemoteSession-DdeyfbkA.js +5 -0
  70. package/src/assets/web-panel/assets/{Reputation-BTVqQgKq.js → Reputation-fxW421xd.js} +1 -1
  71. package/src/assets/web-panel/assets/{Row-CBKKwwtO.js → Row-De73w1og.js} +1 -1
  72. package/src/assets/web-panel/assets/{RssFeed-BHUQ438I.js → RssFeed-3US_Q_lj.js} +2 -2
  73. package/src/assets/web-panel/assets/{Search-B4NqeUsF.js → Search-DbZ_DU74.js} +1 -1
  74. package/src/assets/web-panel/assets/{Security-BRjoYG5_.js → Security-DoIU1vMF.js} +4 -4
  75. package/src/assets/web-panel/assets/{Services-CxQzu3p3.js → Services-DB_RGqpc.js} +2 -2
  76. package/src/assets/web-panel/assets/{Skeleton-BKzwwmWO.js → Skeleton-DnzLaayC.js} +1 -1
  77. package/src/assets/web-panel/assets/{Skills-DrsFcgth.js → Skills-VzVXHENF.js} +1 -1
  78. package/src/assets/web-panel/assets/{Sla-D21tmXCH.js → Sla-DMfvjCAI.js} +1 -1
  79. package/src/assets/web-panel/assets/{SpeechSettings-CjyjLfp8.js → SpeechSettings-DQQOYWbF.js} +1 -1
  80. package/src/assets/web-panel/assets/{SyncSettings-Cu45-tnx.js → SyncSettings-Bmx3FG1P.js} +2 -2
  81. package/src/assets/web-panel/assets/{Tasks-oMcILYOj.js → Tasks-DOQyfb-2.js} +1 -1
  82. package/src/assets/web-panel/assets/{Templates-Bh-Zcr5R.js → Templates-D6hTRT7c.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tenant-68ns63aI.js → Tenant-CTPQZAzs.js} +1 -1
  84. package/src/assets/web-panel/assets/{Terminal-BLJkFykE.js → Terminal-B7vII3oH.js} +2 -2
  85. package/src/assets/web-panel/assets/{TimelineRenderer-xcrJLq-O.js → TimelineRenderer-BkiFJeXV.js} +1 -1
  86. package/src/assets/web-panel/assets/{Tokens-C6PpFJtf.js → Tokens-BPPdQMNo.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trigger-BaKA7tdM.js → Trigger-BxG8JAEI.js} +1 -1
  88. package/src/assets/web-panel/assets/{Trust-BzhA57Jc.js → Trust-DHD7nMpM.js} +1 -1
  89. package/src/assets/web-panel/assets/{UkeySign-4_U3JkIR.js → UkeySign-B4BJpU47.js} +1 -1
  90. package/src/assets/web-panel/assets/{VideoEditing-162AANxX.js → VideoEditing-CRiGpFx2.js} +1 -1
  91. package/src/assets/web-panel/assets/{Wallet-B1viuql_.js → Wallet-BSDSNiem.js} +4 -4
  92. package/src/assets/web-panel/assets/{WebAuthn-ZVWazhCy.js → WebAuthn-DLTUh5Zv.js} +5 -5
  93. package/src/assets/web-panel/assets/WorkflowEditor-tW2MwjhD.js +1 -0
  94. package/src/assets/web-panel/assets/{chat-DmrHNuwq.js → chat-SgsLQ3FC.js} +1 -1
  95. package/src/assets/web-panel/assets/{colors-DAJ_M-PK.js → colors-BHjjLIKO.js} +1 -1
  96. package/src/assets/web-panel/assets/{compact-item-uIzmYwLs.js → compact-item-VceErdKq.js} +1 -1
  97. package/src/assets/web-panel/assets/{createContext-D_ZmuLwb.js → createContext-BZ332MYl.js} +1 -1
  98. package/src/assets/web-panel/assets/devWarning-DosMaL-k.js +1 -0
  99. package/src/assets/web-panel/assets/{hasIn-CDt_shTL.js → hasIn-CBTjJOjn.js} +1 -1
  100. package/src/assets/web-panel/assets/index-0O5ePnUq.js +1 -0
  101. package/src/assets/web-panel/assets/{index-rXdwUeE3.js → index-1n7xjKDU.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BAvSmJXW.js → index-29wVzi-k.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-C16fYKFD.js → index-B2u26AS3.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-C5WcdJH2.js → index-B40dQn0G.js} +3 -3
  105. package/src/assets/web-panel/assets/{index-CaelyMgF.js → index-B5KAGxNo.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-OzTxFIJP.js → index-BC1xuQgX.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CzXqvMuP.js → index-BETEjuNr.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-clSX4PEc.js → index-BOtvPdHt.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-saf3VNeP.js → index-BPXFLYdW.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DdUMcwRB.js → index-BQSmZGgs.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DfSSy9uy.js → index-BRWhLbWF.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-GcKOHD_c.js → index-BTlc-Bve.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BHvlm0In.js → index-BY1wexYG.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-Cvak6Oe2.js → index-BcUenmCX.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CKyd472S.js → index-BeiqkxJG.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DvFhhe6r.js → index-BhXZEUAc.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DBFmcaCQ.js → index-By5jBtkV.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-DqDSF2RW.js → index-CLc19alH.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DeGBoLQA.js → index-CMVvxIS8.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-FyplHuNt.js → index-C_B9rFQE.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CeUpKjvi.js → index-CaIS_TNX.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BRa4kJ_S.js → index-CawpdGTW.js} +1 -1
  123. package/src/assets/web-panel/assets/index-ChAzPigF.js +1 -0
  124. package/src/assets/web-panel/assets/{index-QsgfSZrV.js → index-CpumS98o.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BDF6EQBs.js → index-Cr4rjlW5.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-rS3gl_68.js → index-CrUgDQkf.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-D4n1lGTB.js → index-CtjLcCNU.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-ifxmu8SY.js → index-DUkVN794.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BTCXf1t-.js → index-D_SePDWj.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Bbxjfstq.js → index-DaCCy6lq.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-D9OE8B3d.js → index-DdefYBSw.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-CG0lY4h3.js → index-DePOeMDM.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-Bx4d6c1k.js → index-DgPvuIn2.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-Z8P4BexE.js → index-FJ3zC9LK.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-ByzGvpR9.js → index-_PHrIO4O.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-DwfvPe-j.js → index-fU7wNHDB.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-CcZ9xJI9.js → index-iYQNU9za.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-CbD_WW_6.js → index-vIXOpcjD.js} +1 -1
  139. package/src/assets/web-panel/assets/{initDefaultProps-pmfaD-aK.js → initDefaultProps-D1oZNz0D.js} +1 -1
  140. package/src/assets/web-panel/assets/{motion-CaQ2CpYF.js → motion-C8k6doMO.js} +1 -1
  141. package/src/assets/web-panel/assets/{move-CkKTqNbI.js → move-DJ4qSbYt.js} +1 -1
  142. package/src/assets/web-panel/assets/{mtc-parser-Dd4xsgRI.js → mtc-parser-CdpJD85j.js} +1 -1
  143. package/src/assets/web-panel/assets/{omit-BFuA5YEs.js → omit-B0V4slKA.js} +1 -1
  144. package/src/assets/web-panel/assets/{pickAttrs-DDfxOAJc.js → pickAttrs-Di5NiW1F.js} +1 -1
  145. package/src/assets/web-panel/assets/{placementArrow-Be595JCp.js → placementArrow-B5OMHgEM.js} +1 -1
  146. package/src/assets/web-panel/assets/{responsiveObserve-7byljUM3.js → responsiveObserve-C6U9IWql.js} +1 -1
  147. package/src/assets/web-panel/assets/{slide-CTWfOTaY.js → slide-BMyTH3rN.js} +1 -1
  148. package/src/assets/web-panel/assets/{statusUtils-CNZOuIxM.js → statusUtils-C7d6BG7Z.js} +1 -1
  149. package/src/assets/web-panel/assets/{styleChecker-DwOcBV78.js → styleChecker-CR50QnQy.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFlexGapSupport-B6MNwAO9.js → useFlexGapSupport-DBEeoMb8.js} +1 -1
  151. package/src/assets/web-panel/assets/{useFs-CzyQjH9r.js → useFs-3r099cjv.js} +1 -1
  152. package/src/assets/web-panel/assets/{usePersonalDataHub-Dxh3KiVA.js → usePersonalDataHub-C5IYNdTK.js} +1 -1
  153. package/src/assets/web-panel/assets/{vnode-DVfZiS5N.js → vnode-DmEOLRHf.js} +1 -1
  154. package/src/assets/web-panel/assets/{zoom-BYme7fbY.js → zoom-DnpUiVCB.js} +1 -1
  155. package/src/assets/web-panel/index.html +1 -1
  156. package/src/cli-help.js +181 -0
  157. package/src/command-help-index.json +181 -0
  158. package/src/command-manifest.json +1271 -175
  159. package/src/command-surface-policy.js +312 -0
  160. package/src/commands/agent.js +76 -33
  161. package/src/commands/artifacts.js +400 -2
  162. package/src/commands/background-session.js +41 -3
  163. package/src/commands/checkpoint-restore-recovery.js +1476 -0
  164. package/src/commands/checkpoint.js +947 -22
  165. package/src/commands/compact.js +101 -25
  166. package/src/commands/config.js +506 -20
  167. package/src/commands/doctor.js +4 -1
  168. package/src/commands/hub.js +1 -1
  169. package/src/commands/mcp.js +688 -24
  170. package/src/commands/pack.js +16 -2
  171. package/src/commands/plugin.js +20 -12
  172. package/src/commands/session-mcp-recovery.js +218 -0
  173. package/src/commands/session.js +470 -110
  174. package/src/commands/setup.js +36 -10
  175. package/src/commands/skill.js +181 -110
  176. package/src/commands/status.js +21 -5
  177. package/src/commands/update.js +68 -6
  178. package/src/constants.js +11 -0
  179. package/src/data/changelog.json +14 -1
  180. package/src/gateways/ws/action-protocol.js +10 -0
  181. package/src/gateways/ws/session-protocol.js +555 -27
  182. package/src/gateways/ws/ws-agent-handler.js +541 -14
  183. package/src/gateways/ws/ws-session-gateway.js +129 -22
  184. package/src/gateways/ws/ws-session-state.js +431 -0
  185. package/src/harness/background-task-manager.js +233 -36
  186. package/src/harness/jsonl-session-store.js +2551 -167
  187. package/src/harness/mcp-client.js +802 -61
  188. package/src/harness/prompt-compressor.js +227 -27
  189. package/src/harness/session-index.js +89 -38
  190. package/src/harness/session-list-index.js +254 -0
  191. package/src/harness/structured-handoff.js +410 -0
  192. package/src/lazy-dispatch.js +747 -84
  193. package/src/lib/__tests__/logger.test.js +50 -2
  194. package/src/lib/advisor-runtime.js +1047 -0
  195. package/src/lib/agent-core.js +1 -0
  196. package/src/lib/agent-sandbox.js +120 -26
  197. package/src/lib/agent-session-export.js +20 -0
  198. package/src/lib/agent-team/team-runner.js +230 -8
  199. package/src/lib/artifact-store.js +131 -8
  200. package/src/lib/background-agent-supervisor.js +185 -13
  201. package/src/lib/background-interaction-journal.js +37 -9
  202. package/src/lib/background-launch-profile.js +1058 -0
  203. package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
  204. package/src/lib/checkpoint-restore-orchestrator.js +987 -0
  205. package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
  206. package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
  207. package/src/lib/checkpoint-restore-recovery.js +884 -0
  208. package/src/lib/checkpoint-restore-retention.js +126 -0
  209. package/src/lib/checkpoint-restore-saga.js +5079 -0
  210. package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
  211. package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
  212. package/src/lib/checkpoint-store.js +1688 -97
  213. package/src/lib/checkpoint-timeline-authority.js +522 -0
  214. package/src/lib/checkpoint-timeline.js +642 -0
  215. package/src/lib/config-keys.js +18 -119
  216. package/src/lib/config-manager.js +446 -27
  217. package/src/lib/config-redaction.js +57 -0
  218. package/src/lib/config-schema.js +853 -0
  219. package/src/lib/cowork-mcp-tools.js +5 -0
  220. package/src/lib/cowork-task-runner.js +458 -63
  221. package/src/lib/delivery-coordinator.js +1234 -0
  222. package/src/lib/delivery-evidence.js +450 -0
  223. package/src/lib/doctor-checkup.js +199 -14
  224. package/src/lib/executable-path.js +34 -0
  225. package/src/lib/fatal-handler.js +16 -0
  226. package/src/lib/file-checkpoint.js +4909 -186
  227. package/src/lib/file-lines.js +125 -0
  228. package/src/lib/headless-config-command.js +16 -5
  229. package/src/lib/hook-runner.cjs +139 -38
  230. package/src/lib/hooks-v2-workspace-context.js +10 -0
  231. package/src/lib/impacted-gate-selector.js +424 -0
  232. package/src/lib/interaction-adapter.js +62 -0
  233. package/src/lib/jsonl-session-store.js +1 -35
  234. package/src/lib/logger.js +66 -14
  235. package/src/lib/mcp-call-ledger-store.js +1069 -0
  236. package/src/lib/mcp-call-ledger.js +747 -0
  237. package/src/lib/mcp-client.js +5 -0
  238. package/src/lib/mcp-conflict-scheduler.js +468 -0
  239. package/src/lib/mcp-effect-contract.js +102 -0
  240. package/src/lib/mcp-headers-helper-trust.js +145 -0
  241. package/src/lib/mcp-headers-helper.js +616 -0
  242. package/src/lib/mcp-host-recovery-runtime.js +131 -0
  243. package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
  244. package/src/lib/mcp-recovery-adjudication.js +443 -0
  245. package/src/lib/output-context.js +86 -0
  246. package/src/lib/packer/file-identity.js +170 -0
  247. package/src/lib/packer/index.js +3 -0
  248. package/src/lib/packer/native-update-state.js +277 -0
  249. package/src/lib/packer/pack-update-applier.js +1983 -136
  250. package/src/lib/packer/pack-update-checker.js +34 -0
  251. package/src/lib/packer/pack-update-downloader.js +875 -86
  252. package/src/lib/packer/pack-update-signature.js +86 -0
  253. package/src/lib/packer/pkg-config-generator.js +6 -0
  254. package/src/lib/paths.js +65 -10
  255. package/src/lib/plan-mode.js +831 -14
  256. package/src/lib/plan-persistence.js +540 -0
  257. package/src/lib/plugin-runtime/hooks.js +227 -69
  258. package/src/lib/plugin-runtime/plugin-options.js +189 -44
  259. package/src/lib/pr-automation-policy.js +146 -8
  260. package/src/lib/process-execution-broker/credential-agent.js +7 -0
  261. package/src/lib/process-execution-broker/index.js +53 -8
  262. package/src/lib/process-execution-broker/workspace-transaction.js +976 -73
  263. package/src/lib/project-instructions.js +165 -29
  264. package/src/lib/project-mcp-trust.js +67 -0
  265. package/src/lib/public-ide-capability-manifest.js +278 -0
  266. package/src/lib/public-ide-capability-validation.js +351 -0
  267. package/src/lib/secret-store.js +267 -43
  268. package/src/lib/secure-fs.js +1089 -0
  269. package/src/lib/security-audit.js +58 -0
  270. package/src/lib/service-manager.js +34 -13
  271. package/src/lib/session-budget-runtime.js +1452 -0
  272. package/src/lib/session-host-snapshot.js +388 -0
  273. package/src/lib/session-message-provenance.js +429 -0
  274. package/src/lib/session-projection.js +804 -0
  275. package/src/lib/session-resource-budget.js +1495 -0
  276. package/src/lib/settings-hooks.cjs +138 -22
  277. package/src/lib/settings-loader.cjs +25 -2
  278. package/src/lib/side-effect-ledger-store.js +45 -23
  279. package/src/lib/skill-execution-identity.js +217 -0
  280. package/src/lib/skill-loader.js +299 -18
  281. package/src/lib/sub-agent-context.js +236 -28
  282. package/src/lib/sub-agent-registry.js +5 -0
  283. package/src/lib/subagent-contract.js +94 -0
  284. package/src/lib/todo-manager.js +185 -18
  285. package/src/lib/todo-persistence.js +417 -0
  286. package/src/lib/turn-binding-store.js +41 -23
  287. package/src/lib/with-file-lock.js +25 -1
  288. package/src/lib/ws-chat-handler.js +21 -0
  289. package/src/program-base.js +18 -0
  290. package/src/repl/advisor-command.js +103 -0
  291. package/src/repl/agent-repl.js +2332 -154
  292. package/src/repl/btw-command.js +93 -10
  293. package/src/repl/clipboard-image.js +119 -0
  294. package/src/repl/config-summary.js +64 -108
  295. package/src/repl/prompt-editor.js +233 -0
  296. package/src/repl/prompt-interactions.js +404 -0
  297. package/src/repl/prompt-stash.js +354 -0
  298. package/src/repl/prompt-suggestions.js +312 -0
  299. package/src/repl/repl-keybindings.js +227 -0
  300. package/src/repl/session-recap.js +217 -0
  301. package/src/repl/slash-command-registry.js +25 -4
  302. package/src/repl/terminal-layout.js +88 -0
  303. package/src/runtime/agent-core.js +1264 -325
  304. package/src/runtime/coding-agent-contract-shared.cjs +13 -1
  305. package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
  306. package/src/runtime/diagnostics.js +32 -13
  307. package/src/runtime/headless-runner.js +298 -118
  308. package/src/runtime/headless-stream.js +353 -95
  309. package/src/runtime/mcp-config.js +148 -14
  310. package/src/runtime/status-diagnostics-lite.js +137 -0
  311. package/src/assets/web-panel/assets/ChatBubbleRenderer-DDHDpBBA.js +0 -1
  312. package/src/assets/web-panel/assets/MarkdownRenderer-TabqHW9B.js +0 -1
  313. package/src/assets/web-panel/assets/RemoteSession-B0rkE09d.js +0 -5
  314. package/src/assets/web-panel/assets/WorkflowEditor-tzdyUk-1.js +0 -1
  315. package/src/assets/web-panel/assets/devWarning-DIrncrV1.js +0 -1
  316. package/src/assets/web-panel/assets/index-D-Swwqld.js +0 -1
  317. package/src/assets/web-panel/assets/index-FMZAMKy8.js +0 -1
@@ -0,0 +1,227 @@
1
+ /** Declarative, validated keybindings for interactive prompt actions. */
2
+
3
+ export const REPL_KEYBINDING_ACTIONS = Object.freeze([
4
+ "prompt.edit",
5
+ "prompt.stash",
6
+ "prompt.pop",
7
+ "session.recap",
8
+ "suggestions.toggle",
9
+ ]);
10
+
11
+ export const DEFAULT_REPL_KEYBINDINGS = Object.freeze({
12
+ "prompt.edit": Object.freeze(["ctrl+g"]),
13
+ "prompt.stash": Object.freeze(["alt+s"]),
14
+ "prompt.pop": Object.freeze(["alt+p"]),
15
+ "session.recap": Object.freeze(["alt+r"]),
16
+ "suggestions.toggle": Object.freeze(["alt+n"]),
17
+ });
18
+
19
+ const MODIFIER_ORDER = ["ctrl", "alt", "shift"];
20
+ const MODIFIER_ALIASES = new Map([
21
+ ["control", "ctrl"],
22
+ ["option", "alt"],
23
+ // Node's terminal keypress API reports an escape-prefixed Alt/Option key as
24
+ // `meta`; desktop Command/Windows keys are not reliably exposed to readline.
25
+ ["meta", "alt"],
26
+ ]);
27
+ const KEY_ALIASES = new Map([
28
+ ["return", "enter"],
29
+ ["esc", "escape"],
30
+ ["spacebar", "space"],
31
+ ]);
32
+ const SAFE_NAMED_KEYS = new Set([
33
+ "backspace",
34
+ "delete",
35
+ "down",
36
+ "end",
37
+ "enter",
38
+ "escape",
39
+ "home",
40
+ "insert",
41
+ "left",
42
+ "pageup",
43
+ "pagedown",
44
+ "right",
45
+ "space",
46
+ "tab",
47
+ "up",
48
+ ]);
49
+ const RESERVED_CHORDS = new Set([
50
+ "ctrl+c",
51
+ "ctrl+d",
52
+ "ctrl+q",
53
+ "ctrl+s",
54
+ "ctrl+z",
55
+ "enter",
56
+ "escape",
57
+ "shift+tab",
58
+ "tab",
59
+ ]);
60
+
61
+ export const REPL_KEYBINDINGS_JSON_SCHEMA = Object.freeze({
62
+ $schema: "https://json-schema.org/draft/2020-12/schema",
63
+ type: "object",
64
+ additionalProperties: false,
65
+ properties: Object.fromEntries(
66
+ REPL_KEYBINDING_ACTIONS.map((action) => [
67
+ action,
68
+ {
69
+ oneOf: [
70
+ { type: "string", minLength: 1 },
71
+ {
72
+ type: "array",
73
+ items: { type: "string", minLength: 1 },
74
+ uniqueItems: true,
75
+ },
76
+ { type: "null" },
77
+ ],
78
+ },
79
+ ]),
80
+ ),
81
+ });
82
+
83
+ export function normalizeKeyChord(value) {
84
+ const raw = String(value || "")
85
+ .trim()
86
+ .toLowerCase();
87
+ if (!raw) throw new Error("key chord is empty");
88
+ const parts = raw.split("+").map((part) => part.trim());
89
+ if (parts.some((part) => !part)) throw new Error(`invalid key chord: ${raw}`);
90
+ const modifiers = new Set();
91
+ let key = null;
92
+ for (const rawPart of parts) {
93
+ const part = MODIFIER_ALIASES.get(rawPart) || rawPart;
94
+ if (MODIFIER_ORDER.includes(part)) {
95
+ if (modifiers.has(part)) throw new Error(`duplicate modifier: ${part}`);
96
+ modifiers.add(part);
97
+ continue;
98
+ }
99
+ if (key !== null) throw new Error(`key chord has multiple keys: ${raw}`);
100
+ key = KEY_ALIASES.get(part) || part;
101
+ }
102
+ if (!key) throw new Error(`key chord has no key: ${raw}`);
103
+ if (!/^[a-z0-9]$/.test(key) && !/^f(?:[1-9]|1[0-2])$/.test(key)) {
104
+ if (!SAFE_NAMED_KEYS.has(key)) throw new Error(`unsupported key: ${key}`);
105
+ }
106
+ const chord = [
107
+ ...MODIFIER_ORDER.filter((modifier) => modifiers.has(modifier)),
108
+ key,
109
+ ].join("+");
110
+ if (RESERVED_CHORDS.has(chord)) {
111
+ throw new Error(`reserved terminal key chord: ${chord}`);
112
+ }
113
+ return chord;
114
+ }
115
+
116
+ function configuredKeybindings(settings = {}) {
117
+ if (settings.cli?.keybindings != null) return settings.cli.keybindings;
118
+ if (settings.keybindings != null) return settings.keybindings;
119
+ if (
120
+ settings &&
121
+ typeof settings === "object" &&
122
+ Object.keys(settings).some((key) => REPL_KEYBINDING_ACTIONS.includes(key))
123
+ ) {
124
+ return settings;
125
+ }
126
+ return {};
127
+ }
128
+
129
+ /**
130
+ * Compile settings to a chord -> action map. An explicit null/[] disables the
131
+ * default for that action. Invalid entries are reported and never installed.
132
+ */
133
+ export function validateReplKeybindings(settings = {}, options = {}) {
134
+ const configured = configuredKeybindings(settings);
135
+ const errors = [];
136
+ const actionBindings = {};
137
+ const includeDefaults = options.includeDefaults !== false;
138
+
139
+ if (
140
+ !configured ||
141
+ typeof configured !== "object" ||
142
+ Array.isArray(configured)
143
+ ) {
144
+ return {
145
+ valid: false,
146
+ errors: ["keybindings must be an object"],
147
+ bindings: new Map(),
148
+ actionBindings,
149
+ };
150
+ }
151
+ for (const key of Object.keys(configured)) {
152
+ if (!REPL_KEYBINDING_ACTIONS.includes(key)) {
153
+ errors.push(`unknown keybinding action: ${key}`);
154
+ }
155
+ }
156
+
157
+ const chordOwners = new Map();
158
+ for (const action of REPL_KEYBINDING_ACTIONS) {
159
+ const hasOverride = Object.prototype.hasOwnProperty.call(
160
+ configured,
161
+ action,
162
+ );
163
+ const raw = hasOverride
164
+ ? configured[action]
165
+ : includeDefaults
166
+ ? DEFAULT_REPL_KEYBINDINGS[action]
167
+ : [];
168
+ const values = raw == null ? [] : Array.isArray(raw) ? raw : [raw];
169
+ actionBindings[action] = [];
170
+ for (const value of values) {
171
+ let chord;
172
+ try {
173
+ chord = normalizeKeyChord(value);
174
+ } catch (error) {
175
+ errors.push(`${action}: ${error.message}`);
176
+ continue;
177
+ }
178
+ const owner = chordOwners.get(chord);
179
+ if (owner && owner !== action) {
180
+ errors.push(
181
+ `key chord ${chord} is assigned to both ${owner} and ${action}`,
182
+ );
183
+ continue;
184
+ }
185
+ chordOwners.set(chord, action);
186
+ if (!actionBindings[action].includes(chord)) {
187
+ actionBindings[action].push(chord);
188
+ }
189
+ }
190
+ }
191
+ return {
192
+ valid: errors.length === 0,
193
+ errors,
194
+ bindings: new Map(
195
+ [...chordOwners].map(([chord, action]) => [chord, action]),
196
+ ),
197
+ actionBindings,
198
+ };
199
+ }
200
+
201
+ export function keypressToChord(input, key = {}) {
202
+ let name = String(key.name || "").toLowerCase();
203
+ if (!name && typeof input === "string" && [...input].length === 1) {
204
+ name = input.toLowerCase();
205
+ }
206
+ name = KEY_ALIASES.get(name) || name;
207
+ if (name === " ") name = "space";
208
+ if (!name) return null;
209
+ const parts = [];
210
+ if (key.ctrl) parts.push("ctrl");
211
+ if (key.meta || key.alt) parts.push("alt");
212
+ if (key.shift) parts.push("shift");
213
+ parts.push(name);
214
+ try {
215
+ return normalizeKeyChord(parts.join("+"));
216
+ } catch {
217
+ return null;
218
+ }
219
+ }
220
+
221
+ export function matchReplKeybinding(compiled, input, key) {
222
+ const bindings =
223
+ compiled?.bindings instanceof Map ? compiled.bindings : compiled;
224
+ if (!(bindings instanceof Map)) return null;
225
+ const chord = keypressToChord(input, key);
226
+ return chord ? bindings.get(chord) || null : null;
227
+ }
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Lightweight `/recap` support for the interactive agent.
3
+ *
4
+ * The recap deliberately reads only the rebuildable session metadata sidecar
5
+ * and at most the newest matching transcript records through the store's
6
+ * reverse-reader. It never calls `readEvents()` or rebuilds the whole chat.
7
+ */
8
+ import {
9
+ findLatestEvent,
10
+ getJsonlSessionMetadata,
11
+ resolveSessionId,
12
+ } from "../harness/jsonl-session-store.js";
13
+
14
+ const DEFAULT_PREVIEW_CHARS = 180;
15
+
16
+ function safeLabel(value, maxChars = 200) {
17
+ return String(value || "")
18
+ .replace(/[\p{Cc}\p{Cf}]+/gu, " ")
19
+ .replace(/\s+/g, " ")
20
+ .trim()
21
+ .slice(0, maxChars);
22
+ }
23
+
24
+ function safeIso(value) {
25
+ const timestamp = Number(value);
26
+ if (!Number.isFinite(timestamp)) return "";
27
+ const date = new Date(timestamp);
28
+ return Number.isNaN(date.getTime()) ? "" : date.toISOString();
29
+ }
30
+
31
+ function flattenContent(content) {
32
+ if (typeof content === "string") return content;
33
+ if (!Array.isArray(content)) return "";
34
+ return content
35
+ .map((part) => {
36
+ if (typeof part === "string") return part;
37
+ return typeof part?.text === "string" ? part.text : "";
38
+ })
39
+ .join(" ");
40
+ }
41
+
42
+ export function recapPreview(content, maxChars = DEFAULT_PREVIEW_CHARS) {
43
+ const normalized = flattenContent(content)
44
+ .replace(/[\p{Cc}\p{Cf}]+/gu, " ")
45
+ .replace(/\s+/g, " ")
46
+ .trim();
47
+ const limit = Math.max(20, Number(maxChars) || DEFAULT_PREVIEW_CHARS);
48
+ return normalized.length > limit
49
+ ? `${normalized.slice(0, Math.max(1, limit - 1))}…`
50
+ : normalized;
51
+ }
52
+
53
+ function latestCheckpointTurns(event, previewChars) {
54
+ const messages = Array.isArray(event?.data?.messages)
55
+ ? event.data.messages
56
+ : [];
57
+ const turns = [];
58
+ for (
59
+ let index = messages.length - 1;
60
+ index >= 0 && turns.length < 2;
61
+ index--
62
+ ) {
63
+ const message = messages[index];
64
+ if (message?.role !== "user" && message?.role !== "assistant") continue;
65
+ const preview = recapPreview(message.content, previewChars);
66
+ if (preview) turns.push({ role: message.role, preview });
67
+ }
68
+ return turns.reverse();
69
+ }
70
+
71
+ function compactDetails(event, previewChars) {
72
+ if (!event) return null;
73
+ const data = event.data && typeof event.data === "object" ? event.data : {};
74
+ const numeric = (value) => {
75
+ if (value === null || value === undefined || value === "") return null;
76
+ return Number.isFinite(Number(value)) ? Number(value) : null;
77
+ };
78
+ return {
79
+ timestamp: safeIso(event.timestamp),
80
+ strategy: typeof data.strategy === "string" ? data.strategy : "",
81
+ originalMessages: numeric(data.originalMessages),
82
+ compressedMessages: numeric(data.compressedMessages),
83
+ savedTokens: numeric(data.saved),
84
+ summary: recapPreview(data.summary, previewChars),
85
+ turns: latestCheckpointTurns(event, previewChars),
86
+ };
87
+ }
88
+
89
+ function latestTurnDetails(event, previewChars) {
90
+ if (!event) return null;
91
+ const role =
92
+ event.type === "user_message"
93
+ ? "user"
94
+ : event.type === "assistant_message"
95
+ ? "assistant"
96
+ : "";
97
+ const preview = recapPreview(event.data?.content, previewChars);
98
+ if (!role || !preview) return null;
99
+ return {
100
+ role,
101
+ preview,
102
+ timestamp: safeIso(event.timestamp),
103
+ };
104
+ }
105
+
106
+ /**
107
+ * Build a bounded, provider-neutral recap projection.
108
+ *
109
+ * `store` is injectable to make the important no-full-transcript contract
110
+ * directly testable. The default store methods all use metadata/reverse IO.
111
+ */
112
+ export function buildSessionRecap(sessionId, options = {}) {
113
+ const store = {
114
+ resolveSessionId,
115
+ getJsonlSessionMetadata,
116
+ findLatestEvent,
117
+ ...(options.store || {}),
118
+ };
119
+ const previewChars = Math.max(
120
+ 20,
121
+ Number(options.previewChars) || DEFAULT_PREVIEW_CHARS,
122
+ );
123
+ const requestedId = String(sessionId || "").trim();
124
+ if (!requestedId) {
125
+ return { found: false, sessionId: "", reason: "session id is required" };
126
+ }
127
+
128
+ const resolvedId = store.resolveSessionId(requestedId);
129
+ if (!resolvedId) {
130
+ return {
131
+ found: false,
132
+ sessionId: requestedId,
133
+ reason: `session not found: ${requestedId}`,
134
+ };
135
+ }
136
+ const metadata = store.getJsonlSessionMetadata(resolvedId);
137
+ if (!metadata) {
138
+ return {
139
+ found: false,
140
+ sessionId: resolvedId,
141
+ reason: `session metadata unavailable: ${resolvedId}`,
142
+ };
143
+ }
144
+
145
+ const compact = store.findLatestEvent(resolvedId, "compact");
146
+ const latestTurn = store.findLatestEvent(resolvedId, [
147
+ "user_message",
148
+ "assistant_message",
149
+ ]);
150
+ return {
151
+ found: true,
152
+ sessionId: safeLabel(resolvedId, 200),
153
+ title: safeLabel(metadata.title, 200) || "Untitled",
154
+ provider: safeLabel(metadata.provider, 80),
155
+ model: safeLabel(metadata.model, 160),
156
+ messageCount: Math.max(0, Number(metadata.message_count) || 0),
157
+ createdAt: metadata.created_at || "",
158
+ updatedAt: metadata.updated_at || "",
159
+ checkpoint: compactDetails(compact, previewChars),
160
+ latestTurn: latestTurnDetails(latestTurn, previewChars),
161
+ source: "session-metadata+reverse-events",
162
+ };
163
+ }
164
+
165
+ export function renderSessionRecap(recap) {
166
+ if (!recap?.found) return recap?.reason || "Session recap unavailable.";
167
+ const identity = [safeLabel(recap.provider, 80), safeLabel(recap.model, 160)]
168
+ .filter(Boolean)
169
+ .join(" / ");
170
+ const lines = [
171
+ `Session recap: ${safeLabel(recap.title, 200) || "Untitled"}`,
172
+ `ID: ${safeLabel(recap.sessionId, 200)}`,
173
+ `Messages: ${recap.messageCount}`,
174
+ ];
175
+ if (identity) lines.push(`Model: ${identity}`);
176
+ if (recap.updatedAt) lines.push(`Updated: ${safeLabel(recap.updatedAt, 80)}`);
177
+
178
+ const checkpoint = recap.checkpoint;
179
+ if (checkpoint) {
180
+ const stats = [];
181
+ if (checkpoint.strategy) stats.push(checkpoint.strategy);
182
+ if (
183
+ checkpoint.originalMessages !== null &&
184
+ checkpoint.compressedMessages !== null
185
+ ) {
186
+ stats.push(
187
+ `${checkpoint.originalMessages} -> ${checkpoint.compressedMessages} messages`,
188
+ );
189
+ }
190
+ if (checkpoint.savedTokens !== null) {
191
+ stats.push(`${checkpoint.savedTokens} tokens saved`);
192
+ }
193
+ lines.push(`Checkpoint: ${stats.join(", ") || "available"}`);
194
+ if (checkpoint.summary) lines.push(`Summary: ${checkpoint.summary}`);
195
+ for (const turn of checkpoint.turns) {
196
+ lines.push(
197
+ `${turn.role === "user" ? "Checkpoint ask" : "Checkpoint reply"}: ${turn.preview}`,
198
+ );
199
+ }
200
+ } else {
201
+ lines.push("Checkpoint: none yet");
202
+ }
203
+
204
+ if (
205
+ recap.latestTurn &&
206
+ !checkpoint?.turns?.some(
207
+ (turn) =>
208
+ turn.role === recap.latestTurn.role &&
209
+ turn.preview === recap.latestTurn.preview,
210
+ )
211
+ ) {
212
+ lines.push(
213
+ `${recap.latestTurn.role === "user" ? "Latest ask" : "Latest reply"}: ${recap.latestTurn.preview}`,
214
+ );
215
+ }
216
+ return lines.join("\n");
217
+ }
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { formatBackgroundTasks } from "./tasks-status.js";
7
- import { runDoctorChecks } from "./doctor-status.js";
7
+ import { buildDoctorChecks, renderDoctor } from "./doctor-status.js";
8
8
 
9
9
  export class SlashCommandRegistry {
10
10
  static _instance = null;
@@ -55,6 +55,28 @@ export class SlashCommandRegistry {
55
55
  _registerBuiltinCommands() {
56
56
  // All Claude Code parity commands
57
57
  const commands = [
58
+ [
59
+ "/advisor",
60
+ "Independent tool-free critic (on|off|once|status)",
61
+ async (args, { write, advisor, messages }) => {
62
+ if (!advisor) {
63
+ write("Advisor runtime is unavailable.");
64
+ return;
65
+ }
66
+ const { parseAdvisorCommand, executeAdvisorCommand } =
67
+ await import("./advisor-command.js");
68
+ const suffix = String(args || "").trim();
69
+ const parsed = parseAdvisorCommand(
70
+ `/advisor${suffix ? ` ${suffix}` : ""}`,
71
+ );
72
+ const result = await executeAdvisorCommand(parsed, {
73
+ runtime: advisor,
74
+ messages,
75
+ });
76
+ if (result?.guidance) advisor.queueGuidance(result.guidance);
77
+ write(result?.output || "Advisor command did not run.");
78
+ },
79
+ ],
58
80
  [
59
81
  "/bug",
60
82
  "Submit a bug report",
@@ -102,9 +124,8 @@ export class SlashCommandRegistry {
102
124
  [
103
125
  "/doctor",
104
126
  "Check system health",
105
- async (args, { write }) => {
106
- write("Running system diagnostics...");
107
- await runDoctorChecks(write);
127
+ (args, { write, doctorInput = {} }) => {
128
+ write(renderDoctor(buildDoctorChecks(doctorInput)));
108
129
  },
109
130
  ],
110
131
  [
@@ -0,0 +1,88 @@
1
+ /** Unicode-aware, ANSI-free layout helpers for small terminal surfaces. */
2
+
3
+ const graphemeSegmenter =
4
+ typeof Intl?.Segmenter === "function"
5
+ ? new Intl.Segmenter(undefined, { granularity: "grapheme" })
6
+ : null;
7
+
8
+ function graphemes(value) {
9
+ const text = String(value ?? "");
10
+ return graphemeSegmenter
11
+ ? [...graphemeSegmenter.segment(text)].map((part) => part.segment)
12
+ : [...text];
13
+ }
14
+
15
+ function isFullWidthCodePoint(codePoint) {
16
+ if (!Number.isInteger(codePoint)) return false;
17
+ return (
18
+ codePoint >= 0x1100 &&
19
+ (codePoint <= 0x115f ||
20
+ codePoint === 0x2329 ||
21
+ codePoint === 0x232a ||
22
+ (codePoint >= 0x2e80 && codePoint <= 0x3247 && codePoint !== 0x303f) ||
23
+ (codePoint >= 0x3250 && codePoint <= 0x4dbf) ||
24
+ (codePoint >= 0x4e00 && codePoint <= 0xa4c6) ||
25
+ (codePoint >= 0xa960 && codePoint <= 0xa97c) ||
26
+ (codePoint >= 0xac00 && codePoint <= 0xd7a3) ||
27
+ (codePoint >= 0xf900 && codePoint <= 0xfaff) ||
28
+ (codePoint >= 0xfe10 && codePoint <= 0xfe19) ||
29
+ (codePoint >= 0xfe30 && codePoint <= 0xfe6b) ||
30
+ (codePoint >= 0xff01 && codePoint <= 0xff60) ||
31
+ (codePoint >= 0xffe0 && codePoint <= 0xffe6) ||
32
+ (codePoint >= 0x1b000 && codePoint <= 0x1b2ff) ||
33
+ (codePoint >= 0x1f200 && codePoint <= 0x1f251) ||
34
+ (codePoint >= 0x20000 && codePoint <= 0x3fffd))
35
+ );
36
+ }
37
+
38
+ export function graphemeDisplayWidth(grapheme) {
39
+ const value = String(grapheme || "");
40
+ if (!value || /^[\p{Mark}\p{Cf}\p{Cc}]+$/u.test(value)) return 0;
41
+ if (/\p{Extended_Pictographic}/u.test(value)) return 2;
42
+ for (const character of value) {
43
+ if (isFullWidthCodePoint(character.codePointAt(0))) return 2;
44
+ }
45
+ return 1;
46
+ }
47
+
48
+ export function terminalDisplayWidth(value) {
49
+ return graphemes(value).reduce(
50
+ (width, grapheme) => width + graphemeDisplayWidth(grapheme),
51
+ 0,
52
+ );
53
+ }
54
+
55
+ /** Hard-wrap by grapheme without reversing RTL logical order. */
56
+ export function wrapTerminalText(value, columns = 80) {
57
+ const width = Math.max(8, Math.floor(Number(columns) || 80));
58
+ const output = [];
59
+ for (const sourceLine of String(value ?? "").split("\n")) {
60
+ if (!sourceLine) {
61
+ output.push("");
62
+ continue;
63
+ }
64
+ let line = "";
65
+ let lineWidth = 0;
66
+ for (const grapheme of graphemes(sourceLine)) {
67
+ const nextWidth = graphemeDisplayWidth(grapheme);
68
+ if (line && lineWidth + nextWidth > width) {
69
+ output.push(line);
70
+ line = "";
71
+ lineWidth = 0;
72
+ }
73
+ line += grapheme;
74
+ lineWidth += nextWidth;
75
+ }
76
+ output.push(line);
77
+ }
78
+ return output.join("\n");
79
+ }
80
+
81
+ /** Screen readers prefer stable logical lines; visual terminals hard-wrap. */
82
+ export function layoutTerminalText(
83
+ value,
84
+ { columns = 80, screenReader = false } = {},
85
+ ) {
86
+ const text = String(value ?? "").replace(/\r\n?/g, "\n");
87
+ return screenReader ? text : wrapTerminalText(text, columns);
88
+ }