chainlesschain 0.162.101 → 0.162.103

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 (214) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -2
  3. package/scripts/postinstall.mjs +33 -3
  4. package/src/assets/web-panel/assets/{AIOps-NeD6mA1O.js → AIOps-BpJ5yCcV.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-Bhp7A7vO.js → ActionButton-B1uBfxnA.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-DgdI84Jy.js → Analytics-0ubw5quf.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-Qw29caa7.js → AppLayout-go-GyyM_.js} +4 -4
  8. package/src/assets/web-panel/assets/{Audit-DgkzhBjz.js → Audit-CdUfoUnM.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-CiWEQoW5.js → Backup-CBn0xtsa.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-BWNbkeDF.js → BaseInput-a9fqTkvL.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-CUcj4Vyd.js → Chat-D-d_IatD.js} +6 -6
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-bAMNCgEj.js → ChatBubbleRenderer-Co9h0SbA.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-B0uZTW8f.js → Checkbox-CiKEjtXm.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-BPk7b-Xa.js → Codegen-OQxW_9Z2.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-C2cV_dw4.js → Col-BZHXUEnZ.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-CDN6Yggb.js → Community-D3xno9fj.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-C4WPtW_V.js → Compact-D62jpZk_.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-BGUfeH-3.js → Compliance-D4jFTAcQ.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-CsnVgF-o.js → Cowork-BOU_wir4.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron--rGanASk.js → Cron-Cr9BlJA7.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-D_CLrd-0.js → Crosschain-L9M--CXb.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-iYkbVc8W.js → DID-xFu3-VWT.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-CuFMU98t.js → Dashboard--ax48T3j.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-BPSjv_Ye.js → Dropdown-CTOS8daR.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-DBmk7czO.js → EmailListRenderer-CNLSX81U.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BaCArN11.js → FamilyGuardDashboard-5EjFynBc.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-DsTV-8Ca.js → Federation-CoPyIWIu.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-C6fRr_6F.js → FormItemContext-BbzCNbYy.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-AfuZCfyv.js → GenericCardRenderer-8_9_uXY0.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-CAFIrGhb.js → Git-Bz_qlVPg.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-C-NaxDs4.js → Governance-7eepNCeD.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-BPfeNZP7.js → Inference-DlBx5l1g.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DDUBte_m.js → KnowledgeGraph-BPkc--rM.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-DWysA6JP.js → Logs-BQw4nPvS.js} +2 -2
  35. package/src/assets/web-panel/assets/{Marketplace-CAK68hXc.js → Marketplace-Cil3SdgN.js} +1 -1
  36. package/src/assets/web-panel/assets/{McpTools-CNmmoDAk.js → McpTools-Bnch7KrG.js} +3 -3
  37. package/src/assets/web-panel/assets/{Memory-D_KmFoui.js → Memory-assQ3Suc.js} +2 -2
  38. package/src/assets/web-panel/assets/{MobileBridge-CaY-6kjj.js → MobileBridge-D5mE8c-z.js} +2 -2
  39. package/src/assets/web-panel/assets/MobileProjects-C4MiDXw1.js +1 -0
  40. package/src/assets/web-panel/assets/{Mtc-YnLrtuXT.js → Mtc-CumojeLk.js} +5 -5
  41. package/src/assets/web-panel/assets/{MtcAudit-D38v836u.js → MtcAudit-3tTBc_fw.js} +4 -4
  42. package/src/assets/web-panel/assets/{Multisig-Dv3ad9S4.js → Multisig-Dl4IJBsl.js} +3 -3
  43. package/src/assets/web-panel/assets/{NLProgramming-MYTh2eWC.js → NLProgramming-DHN_cV9x.js} +1 -1
  44. package/src/assets/web-panel/assets/{Notes-DYO-0Hva.js → Notes-DeyTvwYk.js} +3 -3
  45. package/src/assets/web-panel/assets/{NotificationSettings-D39gOb3h.js → NotificationSettings-BUkj8mTj.js} +1 -1
  46. package/src/assets/web-panel/assets/{OrderTableRenderer-CXdO0z3I.js → OrderTableRenderer-BMpEXTki.js} +1 -1
  47. package/src/assets/web-panel/assets/{Organization-DOYTwQwt.js → Organization-B6Ogmkpz.js} +4 -4
  48. package/src/assets/web-panel/assets/{Overflow-Cm-go0yU.js → Overflow-DRUE-2Wz.js} +1 -1
  49. package/src/assets/web-panel/assets/{P2P-CakGtorw.js → P2P-CnMUkd64.js} +2 -2
  50. package/src/assets/web-panel/assets/{PdhVaultBrowser-BlmbHJnb.js → PdhVaultBrowser-B3nFxT3b.js} +4 -4
  51. package/src/assets/web-panel/assets/{Permissions-C_podo04.js → Permissions-CyG1FR7v.js} +4 -4
  52. package/src/assets/web-panel/assets/{PersonalDataHub-nBbehIKp.js → PersonalDataHub-BmN6YMb5.js} +3 -3
  53. package/src/assets/web-panel/assets/{Pipeline-CGzQUoKv.js → Pipeline-BZcamAnH.js} +1 -1
  54. package/src/assets/web-panel/assets/{Privacy-BuD-Dd9m.js → Privacy-D7_zsaY3.js} +1 -1
  55. package/src/assets/web-panel/assets/{ProjectInit-CLcFmGXU.js → ProjectInit-DNa7XQjg.js} +2 -2
  56. package/src/assets/web-panel/assets/{ProjectSettings-BxXTR0dH.js → ProjectSettings-KH2Dm09G.js} +2 -2
  57. package/src/assets/web-panel/assets/{Projects-DkpBjAfd.js → Projects-T-WqR3D6.js} +1 -1
  58. package/src/assets/web-panel/assets/{Providers-DwHK42ht.js → Providers-8GtQ6GgR.js} +1 -1
  59. package/src/assets/web-panel/assets/{QuickAsk-idJPKErk.js → QuickAsk-BuBM5Zpg.js} +1 -1
  60. package/src/assets/web-panel/assets/{Recommend-BvJj0Nu2.js → Recommend-DvH95W1b.js} +1 -1
  61. package/src/assets/web-panel/assets/{Reputation-BK9l4Rcf.js → Reputation-BHCpMEP6.js} +1 -1
  62. package/src/assets/web-panel/assets/{Row-rLxg7xk5.js → Row-BnMPysBm.js} +1 -1
  63. package/src/assets/web-panel/assets/{RssFeed-Cw6ZcHBY.js → RssFeed-C-T8B5VU.js} +3 -3
  64. package/src/assets/web-panel/assets/{Search-D8mKp506.js → Search-CioiZGkX.js} +1 -1
  65. package/src/assets/web-panel/assets/{Security-CXunojmQ.js → Security-zSApKqdd.js} +4 -4
  66. package/src/assets/web-panel/assets/{Services-BE5DgmPl.js → Services-CQh0UDXC.js} +2 -2
  67. package/src/assets/web-panel/assets/{Skeleton-CssL5wmE.js → Skeleton-C0dRaEVG.js} +1 -1
  68. package/src/assets/web-panel/assets/{Skills-zyS_1YrT.js → Skills-BgQRArsa.js} +1 -1
  69. package/src/assets/web-panel/assets/{Sla-DIVn2Roa.js → Sla-BNn7F3jc.js} +1 -1
  70. package/src/assets/web-panel/assets/{SpeechSettings-CjNdZWdj.js → SpeechSettings-kvVfKfqv.js} +1 -1
  71. package/src/assets/web-panel/assets/{SyncSettings-BCbu5WQT.js → SyncSettings-BwIkkX1E.js} +2 -2
  72. package/src/assets/web-panel/assets/{Tasks-BjFrgXge.js → Tasks-BkcvhBZw.js} +1 -1
  73. package/src/assets/web-panel/assets/{Templates-Cl4Y3lKN.js → Templates-COK0o2pL.js} +1 -1
  74. package/src/assets/web-panel/assets/{Tenant-k1T0F_eH.js → Tenant-DpK87fqo.js} +1 -1
  75. package/src/assets/web-panel/assets/{Terminal-i0tHF8fy.js → Terminal-2g2-XPT_.js} +2 -2
  76. package/src/assets/web-panel/assets/{TimelineRenderer-FmPaNyqK.js → TimelineRenderer-B4SJqyqf.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tokens-BUWEiyab.js → Tokens-C3iSR8fH.js} +1 -1
  78. package/src/assets/web-panel/assets/{Trigger-9srMXwpo.js → Trigger-D1Oo58Yo.js} +1 -1
  79. package/src/assets/web-panel/assets/{Trust-hmGor_R2.js → Trust-CUhy4DDc.js} +1 -1
  80. package/src/assets/web-panel/assets/{UkeySign-Dst7K10a.js → UkeySign-r-kTqSw8.js} +1 -1
  81. package/src/assets/web-panel/assets/{VideoEditing-D_utUv1u.js → VideoEditing-B8MyBfCX.js} +1 -1
  82. package/src/assets/web-panel/assets/{Wallet-BpYTTseI.js → Wallet-CquTfSv0.js} +4 -4
  83. package/src/assets/web-panel/assets/{WebAuthn-CEIw8QrF.js → WebAuthn-BC7TP1H3.js} +5 -5
  84. package/src/assets/web-panel/assets/{WorkflowEditor-Bkb4bUZ_.js → WorkflowEditor-CELBSNbP.js} +1 -1
  85. package/src/assets/web-panel/assets/{chat-CTqDgGRH.js → chat-d66mbO2i.js} +1 -1
  86. package/src/assets/web-panel/assets/{colors-CnJHVFLk.js → colors-D0WRCg20.js} +1 -1
  87. package/src/assets/web-panel/assets/{compact-item-D4-v0ahl.js → compact-item-4__-8TIi.js} +1 -1
  88. package/src/assets/web-panel/assets/{createContext-CYDbnHZX.js → createContext-Dqsf52js.js} +1 -1
  89. package/src/assets/web-panel/assets/devWarning-DUAmX0aE.js +1 -0
  90. package/src/assets/web-panel/assets/{hasIn-CbYwlEz5.js → hasIn-ClTZOS8I.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-DVKfa-z4.js → index-0Axwx1nN.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-Cl7-mbsb.js → index-81SaeU6t.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-CK8nROWH.js → index-B1TGSkBt.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-BygyTsjr.js → index-B3vrmn5v.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-B78d_-pR.js → index-BCOpbfAH.js} +1 -1
  96. package/src/assets/web-panel/assets/index-BLCwqv8j.js +1 -0
  97. package/src/assets/web-panel/assets/{index-YuO8gxKb.js → index-BNKECBZm.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-tmNsJzQU.js → index-BwozLU75.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-dKpwhR5x.js → index-C4_XhCJS.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BNz3yht2.js → index-C5l6tSky.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-4767GEls.js → index-CFwkeSun.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BCQ4kcL3.js → index-CGf3oqM0.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-xDe5BkjU.js → index-CJKyF-y8.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DjFQuno4.js → index-Cg8Qw3Jw.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-Dl_NdY39.js → index-Cops66s2.js} +3 -3
  106. package/src/assets/web-panel/assets/{index-D8MYVsVB.js → index-Ct5SJenr.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CY971z_9.js → index-CxoWS8hl.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CVc_5aBF.js → index-D-ya3Ohe.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-C4chfOjw.js → index-D68tyHYa.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BR4facv0.js → index-D9x6i7iV.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CxKdSB-p.js → index-DDLjwgva.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-B-hiXmVK.js → index-DORg0Hps.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BR0FfrCL.js → index-DQaGurrQ.js} +1 -1
  114. package/src/assets/web-panel/assets/index-Db5JRQ6E.js +1 -0
  115. package/src/assets/web-panel/assets/{index-5NXdAIZK.js → index-DbY1lv1z.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BOUSaCsn.js → index-Dm7CYK3j.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DxvFrsxl.js → index-DpLhC0nx.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-qNwkSspX.js → index-P4X9zSF2.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-OqmUv5QO.js → index-PAiWA2un.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-B8uhiRML.js → index-PMJ4tBAA.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CfshMjFN.js → index-Yi5Lr63I.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-wxz2s6uW.js → index-ZZpfHd4J.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DdRtpQFq.js → index-b7a5aEX9.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-C2fICr5d.js → index-e5zJLrJQ.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BGUOVPjO.js → index-fi2ikHoc.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-8cmtr1jC.js → index-jAPphbJL.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DMKNVIqJ.js → index-leuwRsbf.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CP-UKwu8.js → index-luisYDBz.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DaCCLe7i.js → index-we9-1IbF.js} +1 -1
  130. package/src/assets/web-panel/assets/{initDefaultProps-qCQgpAty.js → initDefaultProps-zqDf7qWv.js} +1 -1
  131. package/src/assets/web-panel/assets/{motion-SkVSGdwu.js → motion-DRqTooll.js} +1 -1
  132. package/src/assets/web-panel/assets/{move-BpWxaW_x.js → move-N8tkRqS4.js} +1 -1
  133. package/src/assets/web-panel/assets/{omit-DlZWM2H4.js → omit-Cy01f2vw.js} +1 -1
  134. package/src/assets/web-panel/assets/{pickAttrs-DobtUnVe.js → pickAttrs-C2ycNXNi.js} +1 -1
  135. package/src/assets/web-panel/assets/{placementArrow-CD6mYRZi.js → placementArrow-D60Xb1j9.js} +1 -1
  136. package/src/assets/web-panel/assets/{responsiveObserve-DvIIMTD_.js → responsiveObserve-BF8Y-1HQ.js} +1 -1
  137. package/src/assets/web-panel/assets/{slide-CVgyUfaA.js → slide-DDi6zYZf.js} +1 -1
  138. package/src/assets/web-panel/assets/{statusUtils-DrUDnjy_.js → statusUtils-CWPq6UzA.js} +1 -1
  139. package/src/assets/web-panel/assets/{styleChecker-BNYQS60m.js → styleChecker-D4zVyb4w.js} +1 -1
  140. package/src/assets/web-panel/assets/{useFlexGapSupport-DYv7Tvk0.js → useFlexGapSupport-BEMNO3oR.js} +1 -1
  141. package/src/assets/web-panel/assets/{useFs-DmAD2atJ.js → useFs-DBLO8VR7.js} +1 -1
  142. package/src/assets/web-panel/assets/{usePersonalDataHub-DbLVKA3I.js → usePersonalDataHub-C83ZIrPY.js} +1 -1
  143. package/src/assets/web-panel/assets/{vnode-C3WEt6_P.js → vnode-Dcfyve-7.js} +1 -1
  144. package/src/assets/web-panel/assets/{zoom-CRoSX_oZ.js → zoom-Dg6uoWSc.js} +1 -1
  145. package/src/assets/web-panel/index.html +1 -1
  146. package/src/commands/__tests__/hub-health.test.js +105 -0
  147. package/src/commands/__tests__/hub-stats.test.js +106 -0
  148. package/src/commands/a2a.js +2 -1
  149. package/src/commands/bi.js +4 -3
  150. package/src/commands/browse.js +3 -2
  151. package/src/commands/codegen.js +7 -6
  152. package/src/commands/collab.js +2 -1
  153. package/src/commands/crosschain.js +5 -4
  154. package/src/commands/dao.js +10 -10
  155. package/src/commands/dbevo.js +3 -2
  156. package/src/commands/economy.js +8 -6
  157. package/src/commands/evolution.js +10 -8
  158. package/src/commands/export.js +2 -1
  159. package/src/commands/federation.js +8 -7
  160. package/src/commands/fusion.js +4 -3
  161. package/src/commands/git.js +2 -1
  162. package/src/commands/governance.js +6 -5
  163. package/src/commands/hardening.js +3 -2
  164. package/src/commands/hmemory.js +2 -1
  165. package/src/commands/hub.js +111 -32
  166. package/src/commands/inference.js +9 -8
  167. package/src/commands/infra.js +9 -8
  168. package/src/commands/instinct.js +66 -0
  169. package/src/commands/learning.js +66 -0
  170. package/src/commands/marketplace.js +5 -4
  171. package/src/commands/matrix.js +2 -1
  172. package/src/commands/memory.js +66 -0
  173. package/src/commands/nlprog.js +4 -3
  174. package/src/commands/nostr.js +4 -3
  175. package/src/commands/note.js +2 -1
  176. package/src/commands/ops.js +3 -2
  177. package/src/commands/perception.js +6 -5
  178. package/src/commands/privacy.js +13 -12
  179. package/src/commands/quantization.js +3 -2
  180. package/src/commands/recommend.js +8 -7
  181. package/src/commands/reputation.js +4 -3
  182. package/src/commands/runtime.js +6 -5
  183. package/src/commands/sandbox.js +5 -4
  184. package/src/commands/session.js +2 -1
  185. package/src/commands/sla.js +6 -5
  186. package/src/commands/social.js +6 -5
  187. package/src/commands/stress.js +7 -6
  188. package/src/commands/sync.js +2 -1
  189. package/src/commands/tenant.js +3 -2
  190. package/src/commands/trust.js +7 -6
  191. package/src/commands/wallet.js +2 -1
  192. package/src/gateways/ws/personal-data-hub-protocol.js +16 -3
  193. package/src/lib/__tests__/agents.test.js +225 -0
  194. package/src/lib/__tests__/cowork-observe-html.test.js +141 -0
  195. package/src/lib/__tests__/logger.test.js +110 -0
  196. package/src/lib/__tests__/project-inventory.test.js +280 -0
  197. package/src/lib/__tests__/project-root.test.js +96 -0
  198. package/src/lib/__tests__/provider-stream.test.js +190 -0
  199. package/src/lib/cli-arg.js +41 -0
  200. package/src/lib/cli-numeric.js +12 -3
  201. package/src/lib/instinct-manager.js +64 -0
  202. package/src/lib/learning/learning-tables.js +83 -0
  203. package/src/lib/mcp-oauth.js +10 -2
  204. package/src/lib/memory-manager.js +67 -0
  205. package/src/lib/personal-data-hub-wiring.js +135 -7
  206. package/src/lib/plan-mode.js +3 -2
  207. package/src/repl/__tests__/mcp-prompt.test.js +155 -0
  208. package/src/repl/__tests__/slash-macro.test.js +81 -0
  209. package/src/runtime/__tests__/coding-agent-contract-shared.test.js +136 -0
  210. package/src/runtime/__tests__/coding-agent-events.test.js +263 -0
  211. package/src/assets/web-panel/assets/MobileProjects-DhDxrWze.js +0 -1
  212. package/src/assets/web-panel/assets/devWarning-OhxeajH6.js +0 -1
  213. package/src/assets/web-panel/assets/index-Bbtoi_47.js +0 -1
  214. package/src/assets/web-panel/assets/index-Cb8RWwaB.js +0 -1
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { Command } from "commander";
6
+ import { intArg, floatArg } from "../lib/cli-arg.js";
6
7
 
7
8
  import {
8
9
  PROTOCOL,
@@ -145,7 +146,7 @@ export function registerFusionCommand(program) {
145
146
  fu.command("messages")
146
147
  .description("List unified messages")
147
148
  .option("-p, --protocol <name>", "Filter by protocol")
148
- .option("--limit <n>", "Max results", parseInt)
149
+ .option("--limit <n>", "Max results", intArg("--limit"))
149
150
  .option("--json", "JSON output")
150
151
  .action((opts) => {
151
152
  const db = _dbFromCtx(fu);
@@ -203,7 +204,7 @@ export function registerFusionCommand(program) {
203
204
 
204
205
  fu.command("identities")
205
206
  .description("List identity mappings")
206
- .option("--limit <n>", "Max results", parseInt)
207
+ .option("--limit <n>", "Max results", intArg("--limit"))
207
208
  .option("--json", "JSON output")
208
209
  .action((opts) => {
209
210
  const db = _dbFromCtx(fu);
@@ -269,7 +270,7 @@ export function registerFusionCommand(program) {
269
270
  fu.command("quality-scores")
270
271
  .description("List quality scores")
271
272
  .option("-l, --level <level>", "Filter by quality level")
272
- .option("--limit <n>", "Max results", parseInt)
273
+ .option("--limit <n>", "Max results", intArg("--limit"))
273
274
  .option("--json", "JSON output")
274
275
  .action((opts) => {
275
276
  const db = _dbFromCtx(fu);
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import chalk from "chalk";
7
+ import { numericOption } from "../lib/cli-numeric.js";
7
8
  import { resolve } from "path";
8
9
  import { logger } from "../lib/logger.js";
9
10
  import {
@@ -165,7 +166,7 @@ export function registerGitCommand(program) {
165
166
  }
166
167
 
167
168
  const analysis = gitHistoryAnalyze(dir);
168
- const recentLog = gitLog(dir, parseInt(options.limit));
169
+ const recentLog = gitLog(dir, numericOption(options.limit, { name: "--limit", integer: true, min: 1, fallback: 10 }));
169
170
 
170
171
  if (options.json) {
171
172
  console.log(
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import chalk from "chalk";
9
+ import { intArg, floatArg } from "../lib/cli-arg.js";
9
10
  import { logger } from "../lib/logger.js";
10
11
  import { parseJsonOption } from "../lib/parse-json-option.js";
11
12
  import { bootstrap, shutdown } from "../runtime/bootstrap.js";
@@ -290,8 +291,8 @@ export function registerGovernanceCommand(program) {
290
291
  gov
291
292
  .command("close <proposal-id>")
292
293
  .description("Close voting — auto-resolves to passed/rejected")
293
- .option("-q, --quorum <n>", "Quorum threshold (0-1)", parseFloat)
294
- .option("-t, --threshold <n>", "Pass threshold (0-1)", parseFloat)
294
+ .option("-q, --quorum <n>", "Quorum threshold (0-1)", floatArg("--quorum"))
295
+ .option("-t, --threshold <n>", "Pass threshold (0-1)", floatArg("--threshold"))
295
296
  .option(
296
297
  "-n, --total-voters <n>",
297
298
  "Total eligible voters (for quorum)",
@@ -402,9 +403,9 @@ export function registerGovernanceCommand(program) {
402
403
  gov
403
404
  .command("tally <proposal-id>")
404
405
  .description("Show vote tally with quorum/threshold check")
405
- .option("-q, --quorum <n>", "Quorum threshold (0-1)", parseFloat)
406
- .option("-t, --threshold <n>", "Pass threshold (0-1)", parseFloat)
407
- .option("-n, --total-voters <n>", "Total eligible voters", parseInt)
406
+ .option("-q, --quorum <n>", "Quorum threshold (0-1)", floatArg("--quorum"))
407
+ .option("-t, --threshold <n>", "Pass threshold (0-1)", floatArg("--threshold"))
408
+ .option("-n, --total-voters <n>", "Total eligible voters", intArg("--total-voters"))
408
409
  .option("--json", "Output as JSON")
409
410
  .action(async (proposalId, options) => {
410
411
  try {
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import chalk from "chalk";
7
+ import { intArg, floatArg } from "../lib/cli-arg.js";
7
8
  import { logger } from "../lib/logger.js";
8
9
  import { parseJsonOption } from "../lib/parse-json-option.js";
9
10
  import { bootstrap, shutdown } from "../runtime/bootstrap.js";
@@ -556,8 +557,8 @@ export function registerHardeningCommand(program) {
556
557
  hardening
557
558
  .command("complete-audit <audit-id>")
558
559
  .description("Complete a RUNNING audit")
559
- .option("-p, --passed <n>", "Passed check count", parseInt)
560
- .option("-f, --failed <n>", "Failed check count", parseInt)
560
+ .option("-p, --passed <n>", "Passed check count", intArg("--passed"))
561
+ .option("-f, --failed <n>", "Failed check count", intArg("--failed"))
561
562
  .option("-w, --warning-threshold <n>", "Score threshold for WARNING (0–1)")
562
563
  .option("--json", "JSON output")
563
564
  .action(async (auditId, opts) => {
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import chalk from "chalk";
7
+ import { numericOption } from "../lib/cli-numeric.js";
7
8
  import ora from "ora";
8
9
  import { logger } from "../lib/logger.js";
9
10
  import { bootstrap, shutdown } from "../runtime/bootstrap.js";
@@ -661,7 +662,7 @@ export function registerHmemoryCommand(program) {
661
662
  maxAge: parseFloat(options.maxAge) || 720,
662
663
  threshold:
663
664
  options.threshold !== undefined
664
- ? parseFloat(options.threshold)
665
+ ? numericOption(options.threshold, { name: "--threshold", min: 0, max: 1 })
665
666
  : undefined,
666
667
  });
667
668
  if (options.json) console.log(JSON.stringify(result, null, 2));
@@ -173,12 +173,28 @@ async function cmdRetrieveContext(question, options) {
173
173
 
174
174
  async function cmdStats(options) {
175
175
  try {
176
- const hub = await getHub();
176
+ // Default to the minimal hub: stats' core payload (vault row counts +
177
+ // hubDir) only needs the vault, so the full 77-adapter registry + KG/RAG
178
+ // sinks + email-account auto-load is wasted work for a quick `cc hub
179
+ // stats`. Pass --full to also list registered adapters and the resolved
180
+ // LLM, which require the full hub init. (The adapter list is also
181
+ // available standalone via `cc hub list-adapters`.) getHubMinimal()
182
+ // transparently returns the full hub if one was already built this
183
+ // process, so --full is only needed on a cold stats call. Tests stub
184
+ // via _getHub.
185
+ const wantFull = options.full === true;
186
+ const hub = options._getHub
187
+ ? await options._getHub()
188
+ : wantFull
189
+ ? await getHub()
190
+ : await getHubMinimal();
191
+ const adapters = hub.registry ? hub.registry.list() : null;
177
192
  const out = {
178
193
  vault: hub.vault.stats(),
179
- adapters: hub.registry.list(),
194
+ adapters,
180
195
  hubDir: hub.hubDir,
181
196
  llm: hub.llm ? { name: hub.llm.name, isLocal: hub.llm.isLocal } : null,
197
+ minimal: !!hub.minimal,
182
198
  };
183
199
  if (options.json) {
184
200
  printJson(out);
@@ -190,9 +206,17 @@ async function cmdStats(options) {
190
206
  logger.log(` places: ${v.places}`);
191
207
  logger.log(` items: ${v.items}`);
192
208
  logger.log(` topics: ${v.topics}`);
193
- logger.log(chalk.bold(`\nadapters (${out.adapters.length}):`));
194
- for (const a of out.adapters) {
195
- logger.log(` ${chalk.cyan(a.name)} v${a.version}`);
209
+ if (out.adapters) {
210
+ logger.log(chalk.bold(`\nadapters (${out.adapters.length}):`));
211
+ for (const a of out.adapters) {
212
+ logger.log(` ${chalk.cyan(a.name)} v${a.version}`);
213
+ }
214
+ } else {
215
+ logger.log(
216
+ chalk.gray(
217
+ "\nadapters: (run `cc hub stats --full` or `cc hub list-adapters`)",
218
+ ),
219
+ );
196
220
  }
197
221
  logger.log(chalk.gray(`\nhubDir: ${out.hubDir}`));
198
222
  if (out.llm) {
@@ -200,6 +224,8 @@ async function cmdStats(options) {
200
224
  ? chalk.green("[local]")
201
225
  : chalk.yellow("[remote]");
202
226
  logger.log(chalk.gray(`llm: ${out.llm.name} ${tag}`));
227
+ } else if (out.minimal) {
228
+ logger.log(chalk.gray("llm: (run `cc hub stats --full` to resolve)"));
203
229
  } else {
204
230
  logger.log(chalk.yellow("llm: (none)"));
205
231
  }
@@ -213,18 +239,39 @@ async function cmdStats(options) {
213
239
 
214
240
  async function cmdHealth(options) {
215
241
  try {
216
- const hub = await getHub();
242
+ // Full hub is the default: health's whole job is verifying that hub init
243
+ // wired every component (llm / kgSink / ragSink), which a minimal hub
244
+ // deliberately leaves null — reporting those as ✗ would be a false
245
+ // negative, not a faster check. `--quick` opts into a vault-only probe
246
+ // on the minimal hub (skips the 77-adapter registry + sink wiring) for
247
+ // when you just need "is the vault openable / what schema". Tests stub
248
+ // via _getHub.
249
+ const quick = options.quick === true;
250
+ const hub = options._getHub
251
+ ? await options._getHub()
252
+ : quick
253
+ ? await getHubMinimal()
254
+ : await getHub();
217
255
  const out = {
256
+ quick,
218
257
  vault: {
219
258
  ok: !!hub.vault.db,
220
259
  schemaVersion: hub.vault.schemaVersion(),
221
260
  },
222
- llm: hub.llm
223
- ? { ok: true, isLocal: hub.llm.isLocal, name: hub.llm.name }
224
- : { ok: false, reason: "LLM unavailable" },
225
- kgSink: { ok: !!hub.kgSink },
226
- ragSink: { ok: !!hub.ragSink },
227
261
  };
262
+ if (quick) {
263
+ // Minimal hub intentionally has no llm / kgSink / ragSink — mark them
264
+ // "not probed" rather than reporting a misleading down state.
265
+ out.llm = { probed: false };
266
+ out.kgSink = { probed: false };
267
+ out.ragSink = { probed: false };
268
+ } else {
269
+ out.llm = hub.llm
270
+ ? { ok: true, isLocal: hub.llm.isLocal, name: hub.llm.name }
271
+ : { ok: false, reason: "LLM unavailable" };
272
+ out.kgSink = { ok: !!hub.kgSink };
273
+ out.ragSink = { ok: !!hub.ragSink };
274
+ }
228
275
  if (options.json) {
229
276
  printJson(out);
230
277
  } else {
@@ -232,17 +279,25 @@ async function cmdHealth(options) {
232
279
  logger.log(
233
280
  `${mark(out.vault.ok)} vault schema=${out.vault.schemaVersion}`,
234
281
  );
235
- logger.log(
236
- `${mark(out.llm.ok)} llm ${out.llm.name || out.llm.reason}${
237
- out.llm.ok
238
- ? out.llm.isLocal
239
- ? chalk.green(" [local]")
240
- : chalk.yellow(" [remote]")
241
- : ""
242
- }`,
243
- );
244
- logger.log(`${mark(out.kgSink.ok)} kgSink`);
245
- logger.log(`${mark(out.ragSink.ok)} ragSink`);
282
+ if (quick) {
283
+ logger.log(
284
+ chalk.gray(
285
+ llm / kgSink / ragSink not probed (run without --quick)",
286
+ ),
287
+ );
288
+ } else {
289
+ logger.log(
290
+ `${mark(out.llm.ok)} llm ${out.llm.name || out.llm.reason}${
291
+ out.llm.ok
292
+ ? out.llm.isLocal
293
+ ? chalk.green(" [local]")
294
+ : chalk.yellow(" [remote]")
295
+ : ""
296
+ }`,
297
+ );
298
+ logger.log(`${mark(out.kgSink.ok)} kgSink`);
299
+ logger.log(`${mark(out.ragSink.ok)} ragSink`);
300
+ }
246
301
  }
247
302
  } catch (err) {
248
303
  fail(null, err, options.json);
@@ -468,7 +523,11 @@ async function cmdRederive(options) {
468
523
 
469
524
  async function cmdQueryEvents(options) {
470
525
  try {
471
- const hub = await getHub();
526
+ // Read-only vault query — needs no adapters / sinks / llm. Minimal hub
527
+ // skips the 77-adapter registry build (and is crash-resilient to a
528
+ // partial pdh install). getHubMinimal() returns the full hub if one was
529
+ // already built this process, so the vault instance is identical.
530
+ const hub = await getHubMinimal();
472
531
  const q = {};
473
532
  if (options.subtype) q.subtype = options.subtype;
474
533
  if (options.since) q.since = Number(options.since);
@@ -528,7 +587,8 @@ function importEventsInto(vault, events) {
528
587
  imported += 1;
529
588
  } catch (e) {
530
589
  failed += 1;
531
- if (errors.length < 10) errors.push({ id: ev && ev.id, error: e.message });
590
+ if (errors.length < 10)
591
+ errors.push({ id: ev && ev.id, error: e.message });
532
592
  }
533
593
  }
534
594
  return { ok: failed === 0, imported, failed, errors };
@@ -536,7 +596,8 @@ function importEventsInto(vault, events) {
536
596
 
537
597
  async function cmdExportEvents(options) {
538
598
  try {
539
- const hub = await (options._getHub || getHub)();
599
+ // Vault-only raw-event export no adapters needed, use the minimal hub.
600
+ const hub = await (options._getHub || getHubMinimal)();
540
601
  const all = exportAllEvents(hub.vault);
541
602
  if (options.output) {
542
603
  require("fs").writeFileSync(options.output, JSON.stringify(all), "utf-8");
@@ -566,7 +627,8 @@ async function cmdImportEvents(options) {
566
627
  if (!Array.isArray(events)) {
567
628
  throw new Error("import-events: expected a JSON array of events");
568
629
  }
569
- const hub = await (options._getHub || getHub)();
630
+ // Vault-only idempotent upsert no adapters needed, use the minimal hub.
631
+ const hub = await (options._getHub || getHubMinimal)();
570
632
  const result = importEventsInto(hub.vault, events);
571
633
  if (options.json) {
572
634
  jsonAndExit(result);
@@ -585,7 +647,8 @@ async function cmdImportEvents(options) {
585
647
  // (Android LocalCcRunner.searchEvents calls this; CI smoke too).
586
648
  async function cmdSearchEvents(options) {
587
649
  try {
588
- const hub = await getHub();
650
+ // Read-only vault FTS search — vault-only, use the minimal hub.
651
+ const hub = await getHubMinimal();
589
652
  const q = {};
590
653
  if (options.q) q.q = String(options.q);
591
654
  if (options.adapter) q.adapter = options.adapter;
@@ -628,7 +691,8 @@ async function cmdSearchEvents(options) {
628
691
 
629
692
  async function cmdFacetCounts(options) {
630
693
  try {
631
- const hub = await getHub();
694
+ // Read-only vault facet aggregation — vault-only, use the minimal hub.
695
+ const hub = await getHubMinimal();
632
696
  const q = {};
633
697
  if (options.q) q.q = String(options.q);
634
698
  if (options.since) q.since = Number(options.since);
@@ -657,7 +721,8 @@ async function cmdFacetCounts(options) {
657
721
 
658
722
  async function cmdRecentAudit(options) {
659
723
  try {
660
- const hub = await getHub();
724
+ // Read-only vault audit log query — vault-only, use the minimal hub.
725
+ const hub = await getHubMinimal();
661
726
  const q = {};
662
727
  if (options.since) q.since = Number(options.since);
663
728
  if (options.action) q.action = options.action;
@@ -722,7 +787,8 @@ async function cmdEventDetail(eventId, options) {
722
787
  process.exit(1);
723
788
  }
724
789
  try {
725
- const hub = await getHub();
790
+ // Read-only single-event lookup — vault-only, use the minimal hub.
791
+ const hub = await getHubMinimal();
726
792
  const event = hub.vault.getEvent(eventId);
727
793
  if (!event) {
728
794
  const result = { found: false, eventId };
@@ -774,7 +840,8 @@ async function cmdExport(options) {
774
840
  try {
775
841
  const fs = await import("node:fs");
776
842
  const path = await import("node:path");
777
- const hub = await getHub();
843
+ // Vault-file snapshot copy — vault-only, use the minimal hub.
844
+ const hub = await getHubMinimal();
778
845
  const src = hub.vault.path;
779
846
  if (!src) throw new Error("vault path unavailable (hub not initialized?)");
780
847
 
@@ -2606,14 +2673,24 @@ export function registerHubCommand(program) {
2606
2673
 
2607
2674
  hub
2608
2675
  .command("stats")
2609
- .description("Vault row counts + registered adapter list + hub paths")
2676
+ .description(
2677
+ "Vault row counts + hub paths (use --full to also list adapters + LLM)",
2678
+ )
2610
2679
  .option("--json", "Output JSON")
2680
+ .option(
2681
+ "--full",
2682
+ "Include registered adapter list + resolved LLM (loads the full hub)",
2683
+ )
2611
2684
  .action(cmdStats);
2612
2685
 
2613
2686
  hub
2614
2687
  .command("health")
2615
2688
  .description("Component health: vault / llm / kgSink / ragSink")
2616
2689
  .option("--json", "Output JSON")
2690
+ .option(
2691
+ "--quick",
2692
+ "Vault-only probe via the minimal hub (skips llm/kgSink/ragSink wiring)",
2693
+ )
2617
2694
  .action(cmdHealth);
2618
2695
 
2619
2696
  hub
@@ -3175,6 +3252,8 @@ export function registerHubCommand(program) {
3175
3252
  export const _internal = {
3176
3253
  cmdAsk,
3177
3254
  cmdRetrieveContext,
3255
+ cmdStats,
3256
+ cmdHealth,
3178
3257
  parsePositiveInt,
3179
3258
  cmdAIChatList,
3180
3259
  cmdAIChatLogin,
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { Command } from "commander";
6
+ import { intArg, floatArg } from "../lib/cli-arg.js";
6
7
 
7
8
  import {
8
9
  NODE_STATUS,
@@ -95,7 +96,7 @@ export function registerInferenceCommand(program) {
95
96
  .description("Register inference node")
96
97
  .option("-e, --endpoint <url>", "Node endpoint URL")
97
98
  .option("-c, --capabilities <list>", "Comma-separated capabilities")
98
- .option("-g, --gpu <mb>", "GPU memory in MB", parseInt)
99
+ .option("-g, --gpu <mb>", "GPU memory in MB", intArg("--gpu"))
99
100
  .option("--json", "JSON output")
100
101
  .action((nodeId, opts) => {
101
102
  const db = _dbFromCtx(inf);
@@ -176,7 +177,7 @@ export function registerInferenceCommand(program) {
176
177
  .description("List inference nodes")
177
178
  .option("-s, --status <status>", "Filter by status")
178
179
  .option("-c, --capability <cap>", "Filter by capability")
179
- .option("--limit <n>", "Max results", parseInt)
180
+ .option("--limit <n>", "Max results", intArg("--limit"))
180
181
  .option("--json", "JSON output")
181
182
  .action((opts) => {
182
183
  const db = _dbFromCtx(inf);
@@ -200,7 +201,7 @@ export function registerInferenceCommand(program) {
200
201
  .command("submit <model>")
201
202
  .description("Submit inference task")
202
203
  .option("-i, --input <text>", "Input data")
203
- .option("-p, --priority <n>", "Priority (1-10)", parseInt)
204
+ .option("-p, --priority <n>", "Priority (1-10)", intArg("--priority"))
204
205
  .option("-m, --mode <mode>", "Privacy mode (standard/encrypted/federated)")
205
206
  .option("--json", "JSON output")
206
207
  .action((model, opts) => {
@@ -223,7 +224,7 @@ export function registerInferenceCommand(program) {
223
224
  .command("complete <task-id>")
224
225
  .description("Mark task as complete")
225
226
  .option("-o, --output <text>", "Task output")
226
- .option("-d, --duration <ms>", "Duration in ms", parseInt)
227
+ .option("-d, --duration <ms>", "Duration in ms", intArg("--duration"))
227
228
  .option("--json", "JSON output")
228
229
  .action((taskId, opts) => {
229
230
  const db = _dbFromCtx(inf);
@@ -279,7 +280,7 @@ export function registerInferenceCommand(program) {
279
280
  .option("-s, --status <status>", "Filter by status")
280
281
  .option("-m, --model <model>", "Filter by model")
281
282
  .option("-p, --privacy <mode>", "Filter by privacy mode")
282
- .option("--limit <n>", "Max results", parseInt)
283
+ .option("--limit <n>", "Max results", intArg("--limit"))
283
284
  .option("--json", "JSON output")
284
285
  .action((opts) => {
285
286
  const db = _dbFromCtx(inf);
@@ -437,7 +438,7 @@ export function registerInferenceCommand(program) {
437
438
  .command("submit-v2 <model>")
438
439
  .description("Submit task (V2, creates queued no assignment)")
439
440
  .option("-i, --input <text>", "Input data")
440
- .option("-p, --priority <n>", "Priority (1-10)", parseInt)
441
+ .option("-p, --priority <n>", "Priority (1-10)", intArg("--priority"))
441
442
  .option("-m, --mode <mode>", "Privacy mode")
442
443
  .option("--json", "JSON output")
443
444
  .action((model, opts) => {
@@ -501,7 +502,7 @@ export function registerInferenceCommand(program) {
501
502
  .command("complete-v2 <task-id>")
502
503
  .description("Complete running task (running → complete)")
503
504
  .option("-o, --output <text>", "Task output")
504
- .option("-d, --duration <ms>", "Duration in ms", parseInt)
505
+ .option("-d, --duration <ms>", "Duration in ms", intArg("--duration"))
505
506
  .option("--json", "JSON output")
506
507
  .action((taskId, opts) => {
507
508
  const db = _dbFromCtx(inf);
@@ -543,7 +544,7 @@ export function registerInferenceCommand(program) {
543
544
  .command("set-task-status <task-id> <status>")
544
545
  .description("Generic state-machine-guarded task status setter")
545
546
  .option("-o, --output <text>", "Patch: output")
546
- .option("-d, --duration <ms>", "Patch: durationMs", parseInt)
547
+ .option("-d, --duration <ms>", "Patch: durationMs", intArg("--duration"))
547
548
  .option("-e, --error <text>", "Patch: errorMessage")
548
549
  .option("--json", "JSON output")
549
550
  .action((taskId, status, opts) => {
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { Command } from "commander";
6
+ import { intArg, floatArg } from "../lib/cli-arg.js";
6
7
 
7
8
  import {
8
9
  DEAL_STATUS,
@@ -115,8 +116,8 @@ export function registerInfraCommand(program) {
115
116
  .requiredOption("-c, --cid <cid>", "Content CID")
116
117
  .requiredOption("-s, --size <bytes>", "Size in bytes", parseInt)
117
118
  .option("-m, --miner <id>", "Miner ID")
118
- .option("-p, --price <fil>", "Price in FIL", parseFloat)
119
- .option("-d, --duration <epochs>", "Duration in epochs", parseInt)
119
+ .option("-p, --price <fil>", "Price in FIL", floatArg("--price"))
120
+ .option("-d, --duration <epochs>", "Duration in epochs", intArg("--duration"))
120
121
  .option("--json", "JSON output")
121
122
  .action((opts) => {
122
123
  const db = _dbFromCtx(inf);
@@ -180,7 +181,7 @@ export function registerInfraCommand(program) {
180
181
  .command("deals")
181
182
  .description("List storage deals")
182
183
  .option("-s, --status <status>", "Filter by status")
183
- .option("--limit <n>", "Max results", parseInt)
184
+ .option("--limit <n>", "Max results", intArg("--limit"))
184
185
  .option("--json", "JSON output")
185
186
  .action((opts) => {
186
187
  const db = _dbFromCtx(inf);
@@ -205,7 +206,7 @@ export function registerInfraCommand(program) {
205
206
  .requiredOption("-c, --cid <cid>", "Content CID")
206
207
  .option("-p, --parent <cid>", "Parent CID")
207
208
  .option("-d, --dag <json>", "DAG structure")
208
- .option("-n, --peers <n>", "Peer count", parseInt)
209
+ .option("-n, --peers <n>", "Peer count", intArg("--peers"))
209
210
  .option("--json", "JSON output")
210
211
  .action((opts) => {
211
212
  const db = _dbFromCtx(inf);
@@ -242,7 +243,7 @@ export function registerInfraCommand(program) {
242
243
  .command("versions")
243
244
  .description("List content versions")
244
245
  .option("-c, --cid <cid>", "Filter by content CID")
245
- .option("--limit <n>", "Max results", parseInt)
246
+ .option("--limit <n>", "Max results", intArg("--limit"))
246
247
  .option("--json", "JSON output")
247
248
  .action((opts) => {
248
249
  const db = _dbFromCtx(inf);
@@ -282,8 +283,8 @@ export function registerInfraCommand(program) {
282
283
  "Route type (tor/domain_front/mesh_ble/mesh_wifi/direct)",
283
284
  )
284
285
  .option("-e, --endpoint <url>", "Endpoint URL")
285
- .option("-l, --latency <ms>", "Latency in ms", parseInt)
286
- .option("-r, --reliability <0-1>", "Reliability score", parseFloat)
286
+ .option("-l, --latency <ms>", "Latency in ms", intArg("--latency"))
287
+ .option("-r, --reliability <0-1>", "Reliability score", floatArg("--reliability"))
287
288
  .option("--json", "JSON output")
288
289
  .action((opts) => {
289
290
  const db = _dbFromCtx(inf);
@@ -346,7 +347,7 @@ export function registerInfraCommand(program) {
346
347
  .description("List anti-censorship routes")
347
348
  .option("-t, --type <type>", "Filter by route type")
348
349
  .option("-s, --status <status>", "Filter by status")
349
- .option("--limit <n>", "Max results", parseInt)
350
+ .option("--limit <n>", "Max results", intArg("--limit"))
350
351
  .option("--json", "JSON output")
351
352
  .action((opts) => {
352
353
  const db = _dbFromCtx(inf);
@@ -9,6 +9,8 @@ import { bootstrap, shutdown } from "../runtime/bootstrap.js";
9
9
  import {
10
10
  getInstincts,
11
11
  getStrongInstincts,
12
+ exportInstincts,
13
+ importInstincts,
12
14
  resetInstincts,
13
15
  deleteInstinct,
14
16
  decayInstincts,
@@ -104,6 +106,70 @@ export function registerInstinctCommand(program) {
104
106
  }
105
107
  });
106
108
 
109
+ // instinct export — §8.3 cross-device backup: full dump of the instincts table
110
+ instinct
111
+ .command("export")
112
+ .description("Export all instincts as JSON (module 101 §8.3 backup)")
113
+ .option("--output <file>", "Write JSON array to file (default: stdout)")
114
+ .option("--json", "Output JSON ({ok,count} with --output; array otherwise)")
115
+ .action(async (options) => {
116
+ try {
117
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
118
+ if (!ctx.db) {
119
+ logger.error("Database not available");
120
+ process.exit(1);
121
+ }
122
+ const rows = exportInstincts(ctx.db.getDatabase());
123
+ if (options.output) {
124
+ const fs = await import("fs");
125
+ fs.writeFileSync(options.output, JSON.stringify(rows), "utf-8");
126
+ if (options.json) {
127
+ console.log(JSON.stringify({ ok: true, count: rows.length, output: options.output }));
128
+ } else {
129
+ logger.log(`exported ${rows.length} instincts → ${options.output}`);
130
+ }
131
+ } else {
132
+ console.log(JSON.stringify(rows));
133
+ }
134
+ await shutdown();
135
+ } catch (err) {
136
+ logger.error(`instinct export failed: ${err.message}`);
137
+ process.exit(1);
138
+ }
139
+ });
140
+
141
+ // instinct import — §8.3 restore: idempotent upsert by id from a JSON-array file
142
+ instinct
143
+ .command("import")
144
+ .description("Import instincts from a JSON array file (idempotent upsert by id; §8.3)")
145
+ .requiredOption("--input <file>", "JSON array of instincts to import")
146
+ .option("--json", "Output JSON result")
147
+ .action(async (options) => {
148
+ try {
149
+ const fs = await import("fs");
150
+ const rows = JSON.parse(fs.readFileSync(options.input, "utf-8"));
151
+ if (!Array.isArray(rows)) {
152
+ throw new Error("import: expected a JSON array of instincts");
153
+ }
154
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
155
+ if (!ctx.db) {
156
+ logger.error("Database not available");
157
+ process.exit(1);
158
+ }
159
+ const result = importInstincts(ctx.db.getDatabase(), rows);
160
+ if (options.json) {
161
+ console.log(JSON.stringify(result));
162
+ } else {
163
+ logger.log(`imported ${result.imported}, failed ${result.failed}`);
164
+ }
165
+ await shutdown();
166
+ if (!result.ok) process.exitCode = 1;
167
+ } catch (err) {
168
+ logger.error(`instinct import failed: ${err.message}`);
169
+ process.exit(1);
170
+ }
171
+ });
172
+
107
173
  // instinct categories
108
174
  instinct
109
175
  .command("categories")