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
@@ -0,0 +1,105 @@
1
+ /**
2
+ * `cc hub health` — focused unit tests for the --quick (minimal hub) path.
3
+ *
4
+ * Why this test exists: `cc hub health` defaults to the FULL hub because its
5
+ * job is to verify hub init wired every component (llm / kgSink / ragSink) —
6
+ * a minimal hub leaves those null on purpose, so reporting them as down would
7
+ * be a false negative, not a faster check. `--quick` opts into a vault-only
8
+ * probe on the minimal hub (skips the 77-adapter registry + sink wiring) and
9
+ * must mark the other components "not probed" rather than failing them. If
10
+ * that distinction regresses, `--quick` would either go slow again or start
11
+ * lying about component health. This suite is the canary.
12
+ *
13
+ * Uses the `_getHub` injection seam — no real vault / no spinner side effects.
14
+ */
15
+
16
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
17
+ import { _internal } from "../hub.js";
18
+
19
+ const { cmdHealth } = _internal;
20
+
21
+ let exitSpy, logSpy, out;
22
+
23
+ beforeEach(() => {
24
+ exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {});
25
+ out = [];
26
+ logSpy = vi.spyOn(console, "log").mockImplementation((...args) => {
27
+ out.push(args.join(" "));
28
+ });
29
+ });
30
+
31
+ afterEach(() => {
32
+ exitSpy.mockRestore();
33
+ logSpy.mockRestore();
34
+ });
35
+
36
+ function fullHub() {
37
+ return {
38
+ minimal: false,
39
+ vault: { db: {}, schemaVersion: () => 4 },
40
+ llm: { name: "ollama:qwen2.5", isLocal: true },
41
+ kgSink: {},
42
+ ragSink: {},
43
+ };
44
+ }
45
+
46
+ function minimalHub() {
47
+ return {
48
+ minimal: true,
49
+ vault: { db: {}, schemaVersion: () => 4 },
50
+ llm: null,
51
+ kgSink: null,
52
+ ragSink: null,
53
+ };
54
+ }
55
+
56
+ function parseJson() {
57
+ return JSON.parse(out.join("\n"));
58
+ }
59
+
60
+ describe("cc hub health — default (full) vs --quick (minimal)", () => {
61
+ it("default probes all four components with real ok states", async () => {
62
+ const stub = vi.fn(async () => fullHub());
63
+ await cmdHealth({ json: true, _getHub: stub });
64
+ const o = parseJson();
65
+ expect(stub).toHaveBeenCalledTimes(1);
66
+ expect(o.quick).toBe(false);
67
+ expect(o.vault.ok).toBe(true);
68
+ expect(o.vault.schemaVersion).toBe(4);
69
+ expect(o.llm).toEqual({ ok: true, isLocal: true, name: "ollama:qwen2.5" });
70
+ expect(o.kgSink).toEqual({ ok: true });
71
+ expect(o.ragSink).toEqual({ ok: true });
72
+ });
73
+
74
+ it("--quick reports vault only; llm/kgSink/ragSink marked not probed (NOT down)", async () => {
75
+ await cmdHealth({
76
+ json: true,
77
+ quick: true,
78
+ _getHub: async () => minimalHub(),
79
+ });
80
+ const o = parseJson();
81
+ expect(o.quick).toBe(true);
82
+ expect(o.vault.ok).toBe(true);
83
+ // The key correctness property: not-probed, never { ok: false }.
84
+ expect(o.llm).toEqual({ probed: false });
85
+ expect(o.kgSink).toEqual({ probed: false });
86
+ expect(o.ragSink).toEqual({ probed: false });
87
+ expect(o.llm.ok).toBeUndefined();
88
+ });
89
+
90
+ it("--quick human output notes the skipped components", async () => {
91
+ await cmdHealth({ quick: true, _getHub: async () => minimalHub() });
92
+ const text = out.join("\n");
93
+ expect(text).toMatch(/vault\s+schema=4/);
94
+ expect(text).toContain("not probed");
95
+ expect(text).toContain("--quick");
96
+ });
97
+
98
+ it("default human output lists llm/kgSink/ragSink", async () => {
99
+ await cmdHealth({ _getHub: async () => fullHub() });
100
+ const text = out.join("\n");
101
+ expect(text).toContain("llm");
102
+ expect(text).toContain("kgSink");
103
+ expect(text).toContain("ragSink");
104
+ });
105
+ });
@@ -0,0 +1,106 @@
1
+ /**
2
+ * `cc hub stats` — focused unit tests for the minimal-vs-full hub selection.
3
+ *
4
+ * Why this test exists: `cc hub stats` defaults to the MINIMAL hub so a quick
5
+ * "how many rows do I have" check doesn't pay to instantiate the full
6
+ * 77-adapter registry + KG/RAG sinks + email-account auto-load. The adapter
7
+ * list + resolved LLM are only built when the caller passes `--full` (or via
8
+ * the standalone `cc hub list-adapters`). If that wiring regresses, every
9
+ * `cc hub stats` call silently goes back to a slow full-hub init. This suite
10
+ * is the canary.
11
+ *
12
+ * Uses the `_getHub` injection seam — no real vault / no spinner side effects.
13
+ */
14
+
15
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
16
+ import { _internal } from "../hub.js";
17
+
18
+ const { cmdStats } = _internal;
19
+
20
+ let exitSpy, logSpy, jsonOut;
21
+
22
+ beforeEach(() => {
23
+ exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {});
24
+ jsonOut = [];
25
+ logSpy = vi.spyOn(console, "log").mockImplementation((...args) => {
26
+ jsonOut.push(args.join(" "));
27
+ });
28
+ });
29
+
30
+ afterEach(() => {
31
+ exitSpy.mockRestore();
32
+ logSpy.mockRestore();
33
+ });
34
+
35
+ function minimalHub() {
36
+ return {
37
+ minimal: true,
38
+ hubDir: "/tmp/hub",
39
+ vault: {
40
+ stats: () => ({ events: 3, persons: 1, places: 0, items: 6, topics: 2 }),
41
+ },
42
+ registry: null,
43
+ llm: null,
44
+ };
45
+ }
46
+
47
+ function fullHub() {
48
+ return {
49
+ minimal: false,
50
+ hubDir: "/tmp/hub",
51
+ vault: {
52
+ stats: () => ({ events: 3, persons: 1, places: 0, items: 6, topics: 2 }),
53
+ },
54
+ registry: {
55
+ list: () => [
56
+ { name: "wechat", version: "0.1.0" },
57
+ { name: "email-imap", version: "0.2.0" },
58
+ ],
59
+ },
60
+ llm: { name: "ollama:qwen2.5", isLocal: true },
61
+ };
62
+ }
63
+
64
+ function parseJson() {
65
+ return JSON.parse(jsonOut.join("\n"));
66
+ }
67
+
68
+ describe("cc hub stats — minimal vs full hub selection", () => {
69
+ it("default (no --full) builds the MINIMAL hub: null adapters, minimal flag", async () => {
70
+ const stub = vi.fn(async () => minimalHub());
71
+ await cmdStats({ json: true, _getHub: stub });
72
+ const out = parseJson();
73
+ expect(stub).toHaveBeenCalledTimes(1);
74
+ expect(out.minimal).toBe(true);
75
+ expect(out.adapters).toBeNull();
76
+ expect(out.llm).toBeNull();
77
+ expect(out.vault.items).toBe(6);
78
+ expect(out.hubDir).toBe("/tmp/hub");
79
+ });
80
+
81
+ it("--full builds the full hub: adapters listed, llm resolved, minimal false", async () => {
82
+ const stub = vi.fn(async () => fullHub());
83
+ await cmdStats({ json: true, full: true, _getHub: stub });
84
+ const out = parseJson();
85
+ expect(out.minimal).toBe(false);
86
+ expect(Array.isArray(out.adapters)).toBe(true);
87
+ expect(out.adapters).toHaveLength(2);
88
+ expect(out.llm).toEqual({ name: "ollama:qwen2.5", isLocal: true });
89
+ });
90
+
91
+ it("human (non-JSON) minimal output points to --full / list-adapters", async () => {
92
+ await cmdStats({ _getHub: async () => minimalHub() });
93
+ const text = jsonOut.join("\n");
94
+ expect(text).toMatch(/events:\s+3/);
95
+ expect(text).toContain("cc hub list-adapters");
96
+ expect(text).toContain("cc hub stats --full");
97
+ });
98
+
99
+ it("human full output lists adapter names + versions", async () => {
100
+ await cmdStats({ full: true, _getHub: async () => fullHub() });
101
+ const text = jsonOut.join("\n");
102
+ expect(text).toContain("adapters (2)");
103
+ expect(text).toContain("wechat");
104
+ expect(text).toContain("email-imap");
105
+ });
106
+ });
@@ -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 ora from "ora";
8
9
  import { logger } from "../lib/logger.js";
9
10
  import { bootstrap, shutdown } from "../runtime/bootstrap.js";
@@ -514,7 +515,7 @@ export function registerA2aCommand(program) {
514
515
  .description("Submit a V2 task (in-memory, with optional timeout)")
515
516
  .argument("<agentId>", "Agent ID")
516
517
  .argument("<input>", "Task input")
517
- .option("--timeout-ms <ms>", "Timeout in ms", parseInt)
518
+ .option("--timeout-ms <ms>", "Timeout in ms", intArg("--timeout-ms"))
518
519
  .option("--json", "Output as JSON")
519
520
  .action((agentId, input, options) => {
520
521
  const res = sendTaskV2(null, {
@@ -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 { logger } from "../lib/logger.js";
8
9
  import { parseJsonOption } from "../lib/parse-json-option.js";
9
10
  import { bootstrap, shutdown } from "../runtime/bootstrap.js";
@@ -180,7 +181,7 @@ export function registerBiCommand(program) {
180
181
  try {
181
182
  const data = parseJsonOption(options.data, "--data", []);
182
183
  const result = detectAnomaly(data, {
183
- threshold: parseFloat(options.threshold),
184
+ threshold: numericOption(options.threshold, { name: "--threshold", fallback: 2 }),
184
185
  });
185
186
 
186
187
  if (options.json) {
@@ -213,7 +214,7 @@ export function registerBiCommand(program) {
213
214
  .action(async (options) => {
214
215
  try {
215
216
  const data = parseJsonOption(options.data, "--data", []);
216
- const result = predictTrend(data, parseInt(options.periods));
217
+ const result = predictTrend(data, numericOption(options.periods, { name: "--periods", integer: true, min: 1, fallback: 3 }));
217
218
 
218
219
  if (options.json) {
219
220
  console.log(JSON.stringify(result, null, 2));
@@ -343,7 +344,7 @@ export function registerBiCommand(program) {
343
344
  const data = parseJsonOption(options.data, "--data", []);
344
345
  const threshold =
345
346
  options.threshold !== undefined
346
- ? parseFloat(options.threshold)
347
+ ? numericOption(options.threshold, { name: "--threshold" })
347
348
  : undefined;
348
349
  const result = detectAnomalyV2({
349
350
  data,
@@ -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 {
@@ -162,8 +163,8 @@ export function registerBrowseCommand(program) {
162
163
  try {
163
164
  const spinner = ora(`Taking screenshot of ${url}...`).start();
164
165
  const result = await takeScreenshot(url, options.output, {
165
- width: parseInt(options.width),
166
- height: parseInt(options.height),
166
+ width: numericOption(options.width, { name: "--width", integer: true, min: 1, fallback: 1280 }),
167
+ height: numericOption(options.height, { name: "--height", integer: true, min: 1, fallback: 720 }),
167
168
  fullPage: !!options.fullPage,
168
169
  });
169
170
  spinner.stop();
@@ -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
  SCAFFOLD_TEMPLATE,
@@ -117,8 +118,8 @@ export function registerCodegenCommand(program) {
117
118
  .option("-l, --language <lang>", "Programming language")
118
119
  .option("-f, --framework <fw>", "Framework used")
119
120
  .option("--code <code>", "Generated code")
120
- .option("--files <n>", "Files generated", parseInt)
121
- .option("--tokens <n>", "Tokens consumed", parseInt)
121
+ .option("--files <n>", "Files generated", intArg("--files"))
122
+ .option("--tokens <n>", "Tokens consumed", intArg("--tokens"))
122
123
  .option("-m, --metadata <json>", "Metadata JSON")
123
124
  .option("--json", "JSON output")
124
125
  .action((opts) => {
@@ -158,7 +159,7 @@ export function registerCodegenCommand(program) {
158
159
  .description("List code generations")
159
160
  .option("-l, --language <lang>", "Filter by language")
160
161
  .option("-f, --framework <fw>", "Filter by framework")
161
- .option("--limit <n>", "Max results", parseInt)
162
+ .option("--limit <n>", "Max results", intArg("--limit"))
162
163
  .option("--json", "JSON output")
163
164
  .action((opts) => {
164
165
  const db = _dbFromCtx(cg);
@@ -233,7 +234,7 @@ export function registerCodegenCommand(program) {
233
234
  cg.command("reviews")
234
235
  .description("List code reviews")
235
236
  .option("-l, --language <lang>", "Filter by language")
236
- .option("--limit <n>", "Max results", parseInt)
237
+ .option("--limit <n>", "Max results", intArg("--limit"))
237
238
  .option("--json", "JSON output")
238
239
  .action((opts) => {
239
240
  const db = _dbFromCtx(cg);
@@ -260,7 +261,7 @@ export function registerCodegenCommand(program) {
260
261
  )
261
262
  .requiredOption("-n, --name <name>", "Project name")
262
263
  .option("-o, --options <json>", "Options JSON")
263
- .option("--files <n>", "Files generated", parseInt)
264
+ .option("--files <n>", "Files generated", intArg("--files"))
264
265
  .option("--output <path>", "Output path")
265
266
  .option("--json", "JSON output")
266
267
  .action((opts) => {
@@ -297,7 +298,7 @@ export function registerCodegenCommand(program) {
297
298
  cg.command("scaffolds")
298
299
  .description("List scaffolds")
299
300
  .option("-t, --template <type>", "Filter by template")
300
- .option("--limit <n>", "Max results", parseInt)
301
+ .option("--limit <n>", "Max results", intArg("--limit"))
301
302
  .option("--json", "JSON output")
302
303
  .action((opts) => {
303
304
  const db = _dbFromCtx(cg);
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import fs from "fs";
9
+ import { intArg, floatArg } from "../lib/cli-arg.js";
9
10
  import chalk from "chalk";
10
11
  import { logger } from "../lib/logger.js";
11
12
  import { bootstrap, shutdown } from "../runtime/bootstrap.js";
@@ -421,7 +422,7 @@ export function registerCollabCommand(program) {
421
422
  collab
422
423
  .command("agents")
423
424
  .description("List agents with autonomy levels")
424
- .option("-l, --level <n>", "Filter by level 0..4", parseInt)
425
+ .option("-l, --level <n>", "Filter by level 0..4", intArg("--level"))
425
426
  .option("--limit <n>", "Maximum entries", parseInt, 50)
426
427
  .option("--json", "Output as JSON")
427
428
  .action(async (options) => {
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  import fs from "node:fs";
11
+ import { intArg, floatArg } from "../lib/cli-arg.js";
11
12
 
12
13
  import { Command } from "commander";
13
14
 
@@ -651,7 +652,7 @@ export function registerCrossChainCommand(program) {
651
652
  .option("-f, --from <chain>", "Filter by source chain")
652
653
  .option("-t, --to <chain>", "Filter by destination chain")
653
654
  .option("-s, --status <status>", "Filter by status")
654
- .option("--limit <n>", "Max results", parseInt)
655
+ .option("--limit <n>", "Max results", intArg("--limit"))
655
656
  .option("--json", "JSON output")
656
657
  .action((opts) => {
657
658
  const db = _dbFromCtx(cc);
@@ -677,7 +678,7 @@ export function registerCrossChainCommand(program) {
677
678
  .option("-a, --from-asset <asset>", "Source asset", "native")
678
679
  .option("-b, --to-asset <asset>", "Target asset", "native")
679
680
  .option("-c, --counterparty <address>", "Counterparty address")
680
- .option("-t, --timeout <ms>", "Timeout in ms", parseInt)
681
+ .option("-t, --timeout <ms>", "Timeout in ms", intArg("--timeout"))
681
682
  .option("--mtc", "On success, stage an MTC swap-init envelope")
682
683
  .option("--mtc-config-dir <dir>", "Override MTC config root")
683
684
  .option("--json", "JSON output")
@@ -779,7 +780,7 @@ export function registerCrossChainCommand(program) {
779
780
  .description("List swaps")
780
781
  .option("-f, --from <chain>", "Filter by source chain")
781
782
  .option("-s, --status <status>", "Filter by status")
782
- .option("--limit <n>", "Max results", parseInt)
783
+ .option("--limit <n>", "Max results", intArg("--limit"))
783
784
  .option("--json", "JSON output")
784
785
  .action((opts) => {
785
786
  const db = _dbFromCtx(cc);
@@ -871,7 +872,7 @@ export function registerCrossChainCommand(program) {
871
872
  .option("-f, --from <chain>", "Filter by source chain")
872
873
  .option("-t, --to <chain>", "Filter by destination chain")
873
874
  .option("-s, --status <status>", "Filter by status")
874
- .option("--limit <n>", "Max results", parseInt)
875
+ .option("--limit <n>", "Max results", intArg("--limit"))
875
876
  .option("--json", "JSON output")
876
877
  .action((opts) => {
877
878
  const db = _dbFromCtx(cc);
@@ -388,7 +388,7 @@ export function registerDaoCommand(program) {
388
388
  type: options.type,
389
389
  actions: parseJsonOption(options.actions, "--actions"),
390
390
  votingDurationMs: options.votingDuration
391
- ? parseInt(options.votingDuration)
391
+ ? numericOption(options.votingDuration, { name: "--voting-duration", integer: true, min: 0 })
392
392
  : undefined,
393
393
  });
394
394
 
@@ -457,8 +457,8 @@ export function registerDaoCommand(program) {
457
457
  proposalId,
458
458
  voterDid: options.voter,
459
459
  voteType: options.type,
460
- voteCount: parseInt(options.count),
461
- balance: options.balance ? parseFloat(options.balance) : undefined,
460
+ voteCount: numericOption(options.count, { name: "--count", integer: true, min: 1 }),
461
+ balance: options.balance ? numericOption(options.balance, { name: "--balance", min: 0 }) : undefined,
462
462
  });
463
463
 
464
464
  logger.success("Vote cast");
@@ -779,7 +779,7 @@ export function registerDaoCommand(program) {
779
779
  const db = ctx.db.getDatabase();
780
780
  ensureDAOv2Tables(db);
781
781
 
782
- const s = getGovernanceStatsV2(parseInt(options.members));
782
+ const s = getGovernanceStatsV2(numericOption(options.members, { name: "--members", integer: true, min: 0, fallback: 0 }));
783
783
  if (options.json) {
784
784
  console.log(JSON.stringify(s, null, 2));
785
785
  } else {
@@ -833,19 +833,19 @@ export function registerDaoCommand(program) {
833
833
  try {
834
834
  const updates = {};
835
835
  if (options.votingDuration)
836
- updates.votingDurationMs = parseInt(options.votingDuration);
836
+ updates.votingDurationMs = numericOption(options.votingDuration, { name: "--voting-duration", integer: true, min: 0 });
837
837
  if (options.quorumPercentage)
838
- updates.quorumPercentage = parseFloat(options.quorumPercentage);
838
+ updates.quorumPercentage = numericOption(options.quorumPercentage, { name: "--quorum-percentage", min: 0, max: 100 });
839
839
  if (options.timelockMs)
840
- updates.timelockMs = parseInt(options.timelockMs);
840
+ updates.timelockMs = numericOption(options.timelockMs, { name: "--timelock-ms", integer: true, min: 0 });
841
841
  if (options.quadraticEnabled !== undefined)
842
842
  updates.quadraticEnabled = options.quadraticEnabled === "true";
843
843
  if (options.maxDelegationDepth)
844
- updates.maxDelegationDepth = parseInt(options.maxDelegationDepth);
844
+ updates.maxDelegationDepth = numericOption(options.maxDelegationDepth, { name: "--max-delegation-depth", integer: true, min: 0 });
845
845
  if (options.proposalThreshold)
846
- updates.proposalThreshold = parseFloat(options.proposalThreshold);
846
+ updates.proposalThreshold = numericOption(options.proposalThreshold, { name: "--proposal-threshold", min: 0 });
847
847
  if (options.maxSingleAllocation)
848
- updates.maxSingleAllocation = parseFloat(options.maxSingleAllocation);
848
+ updates.maxSingleAllocation = numericOption(options.maxSingleAllocation, { name: "--max-single-allocation", min: 0 });
849
849
 
850
850
  const cfg = configureV2(updates);
851
851
  if (options.json) {
@@ -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
  MIGRATION_STATUS,
@@ -239,7 +240,7 @@ export function registerDbEvoCommand(program) {
239
240
  dbevo
240
241
  .command("history")
241
242
  .description("Show migration history")
242
- .option("--limit <n>", "Max results", parseInt)
243
+ .option("--limit <n>", "Max results", intArg("--limit"))
243
244
  .option("--json", "JSON output")
244
245
  .action((opts) => {
245
246
  const db = _dbFromCtx(dbevo);
@@ -340,7 +341,7 @@ export function registerDbEvoCommand(program) {
340
341
  dbevo
341
342
  .command("analyze")
342
343
  .description("Analyze slow queries and generate index suggestions")
343
- .option("--min-count <n>", "Min query count for suggestion", parseInt)
344
+ .option("--min-count <n>", "Min query count for suggestion", intArg("--min-count"))
344
345
  .option("--json", "JSON output")
345
346
  .action((opts) => {
346
347
  const db = _dbFromCtx(dbevo);
@@ -4,6 +4,8 @@
4
4
  */
5
5
 
6
6
  import chalk from "chalk";
7
+ import { intArg, floatArg } from "../lib/cli-arg.js";
8
+ import { numericOption } from "../lib/cli-numeric.js";
7
9
  import { logger } from "../lib/logger.js";
8
10
  import { parseJsonOption } from "../lib/parse-json-option.js";
9
11
  import { bootstrap, shutdown } from "../runtime/bootstrap.js";
@@ -166,7 +168,7 @@ export function registerEconomyCommand(program) {
166
168
  const db = ctx.db.getDatabase();
167
169
  ensureEconomyTables(db);
168
170
 
169
- const ch = openChannel(db, partyA, partyB, parseFloat(options.deposit));
171
+ const ch = openChannel(db, partyA, partyB, numericOption(options.deposit, { name: "--deposit", min: 0 }));
170
172
  logger.success("Channel opened");
171
173
  logger.log(` ${chalk.bold("ID:")} ${chalk.cyan(ch.id)}`);
172
174
  logger.log(` ${chalk.bold("Party A:")} ${ch.partyA} (${ch.balanceA})`);
@@ -501,9 +503,9 @@ export function registerEconomyCommand(program) {
501
503
  .argument("<from>", "From agent ID")
502
504
  .argument("<to>", "To agent ID")
503
505
  .argument("<service-id>", "Service ID")
504
- .option("--tokens <n>", "Token count (for per_token)", parseInt)
505
- .option("--minutes <n>", "Minute count (for per_minute)", parseFloat)
506
- .option("--calls <n>", "Call count (for per_call)", parseInt)
506
+ .option("--tokens <n>", "Token count (for per_token)", intArg("--tokens"))
507
+ .option("--minutes <n>", "Minute count (for per_minute)", floatArg("--minutes"))
508
+ .option("--calls <n>", "Call count (for per_call)", intArg("--calls"))
507
509
  .option("--json", "Output as JSON")
508
510
  .action(async (from, to, serviceId, options) => {
509
511
  try {
@@ -534,8 +536,8 @@ export function registerEconomyCommand(program) {
534
536
  .description("Open a two-sided channel (Phase 85)")
535
537
  .argument("<party-a>", "Party A ID")
536
538
  .argument("<party-b>", "Party B ID")
537
- .option("--deposit-a <n>", "Deposit from party A", parseFloat)
538
- .option("--deposit-b <n>", "Deposit from party B", parseFloat)
539
+ .option("--deposit-a <n>", "Deposit from party A", floatArg("--deposit-a"))
540
+ .option("--deposit-b <n>", "Deposit from party B", floatArg("--deposit-b"))
539
541
  .option("--json", "Output as JSON")
540
542
  .action(async (a, b, options) => {
541
543
  try {
@@ -4,6 +4,8 @@
4
4
  */
5
5
 
6
6
  import chalk from "chalk";
7
+ import { intArg, floatArg } from "../lib/cli-arg.js";
8
+ import { numericOption } from "../lib/cli-numeric.js";
7
9
  import ora from "ora";
8
10
  import { logger } from "../lib/logger.js";
9
11
  import { parseJsonOption } from "../lib/parse-json-option.js";
@@ -291,7 +293,7 @@ export function registerEvolutionCommand(program) {
291
293
  .command("growth")
292
294
  .description("Show growth log")
293
295
  .option("--type <filter>", "Filter by event type")
294
- .option("--limit <n>", "Limit entries", parseInt)
296
+ .option("--limit <n>", "Limit entries", intArg("--limit"))
295
297
  .option("--json", "Output as JSON")
296
298
  .action(async (options) => {
297
299
  try {
@@ -523,10 +525,10 @@ export function registerEvolutionCommand(program) {
523
525
  try {
524
526
  const r = trainIncrementalV2({
525
527
  strategy: options.strategy,
526
- dataSize: parseFloat(options.dataSize),
527
- lossBefore: parseFloat(options.lossBefore),
528
- lossAfter: parseFloat(options.lossAfter),
529
- durationMs: parseFloat(options.durationMs),
528
+ dataSize: numericOption(options.dataSize, { name: "--data-size", min: 0 }),
529
+ lossBefore: numericOption(options.lossBefore, { name: "--loss-before" }),
530
+ lossAfter: numericOption(options.lossAfter, { name: "--loss-after" }),
531
+ durationMs: numericOption(options.durationMs, { name: "--duration-ms", min: 0, fallback: 0 }),
530
532
  });
531
533
  if (options.json) console.log(JSON.stringify(r, null, 2));
532
534
  else {
@@ -650,7 +652,7 @@ export function registerEvolutionCommand(program) {
650
652
  .option("--json", "Output as JSON")
651
653
  .action((options) => {
652
654
  const horizon = options.horizonMs
653
- ? parseFloat(options.horizonMs)
655
+ ? numericOption(options.horizonMs, { name: "--horizon-ms", min: 0 })
654
656
  : undefined;
655
657
  const r = predictBehaviorV2({ timeHorizonMs: horizon });
656
658
  if (options.json) console.log(JSON.stringify(r, null, 2));
@@ -703,8 +705,8 @@ export function registerEvolutionCommand(program) {
703
705
  .option("--json", "Output as JSON")
704
706
  .action((options) => {
705
707
  const period = {};
706
- if (options.from) period.fromMs = parseFloat(options.from);
707
- if (options.to) period.toMs = parseFloat(options.to);
708
+ if (options.from) period.fromMs = numericOption(options.from, { name: "--from", min: 0 });
709
+ if (options.to) period.toMs = numericOption(options.to, { name: "--to", min: 0 });
708
710
  const list = getGrowthLogV2({
709
711
  milestoneType: options.type,
710
712
  period: Object.keys(period).length ? period : undefined,
@@ -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 { resolve } from "path";
9
10
  import { logger } from "../lib/logger.js";
@@ -72,7 +73,7 @@ export function registerExportCommand(program) {
72
73
  const exported = exportToMarkdown(db, outputDir, {
73
74
  category: options.category,
74
75
  tag: options.tag,
75
- limit: options.limit ? parseInt(options.limit) : undefined,
76
+ limit: options.limit ? numericOption(options.limit, { name: "--limit", integer: true, min: 1 }) : undefined,
76
77
  });
77
78
  spinner.stop();
78
79
 
@@ -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
  CIRCUIT_STATE,
@@ -109,8 +110,8 @@ export function registerFederationCommand(program) {
109
110
  "Failure threshold before tripping",
110
111
  parseInt,
111
112
  )
112
- .option("-s, --success-threshold <n>", "Success probes to close", parseInt)
113
- .option("-t, --open-timeout <ms>", "Open timeout in ms", parseInt)
113
+ .option("-s, --success-threshold <n>", "Success probes to close", intArg("--success-threshold"))
114
+ .option("-t, --open-timeout <ms>", "Open timeout in ms", intArg("--open-timeout"))
114
115
  .option("-m, --metadata <json>", "Metadata JSON")
115
116
  .option("--json", "JSON output")
116
117
  .action((nodeId, opts) => {
@@ -165,7 +166,7 @@ export function registerFederationCommand(program) {
165
166
  .command("breakers")
166
167
  .description("List circuit breakers")
167
168
  .option("-s, --state <state>", "Filter by state (closed/open/half_open)")
168
- .option("--limit <n>", "Max results", parseInt)
169
+ .option("--limit <n>", "Max results", intArg("--limit"))
169
170
  .option("--json", "JSON output")
170
171
  .action((opts) => {
171
172
  const db = _dbFromCtx(fed);
@@ -295,7 +296,7 @@ export function registerFederationCommand(program) {
295
296
  .option("-n, --node <id>", "Filter by node ID")
296
297
  .option("-t, --type <type>", "Filter by check type")
297
298
  .option("-s, --status <status>", "Filter by status")
298
- .option("--limit <n>", "Max results", parseInt)
299
+ .option("--limit <n>", "Max results", intArg("--limit"))
299
300
  .option("--json", "JSON output")
300
301
  .action((opts) => {
301
302
  const db = _dbFromCtx(fed);
@@ -337,9 +338,9 @@ export function registerFederationCommand(program) {
337
338
  fed
338
339
  .command("pool-init <node-id>")
339
340
  .description("Initialize a connection pool for a node")
340
- .option("--min <n>", "Min connections", parseInt)
341
- .option("--max <n>", "Max connections", parseInt)
342
- .option("--idle-timeout <ms>", "Idle timeout in ms", parseInt)
341
+ .option("--min <n>", "Min connections", intArg("--min"))
342
+ .option("--max <n>", "Max connections", intArg("--max"))
343
+ .option("--idle-timeout <ms>", "Idle timeout in ms", intArg("--idle-timeout"))
343
344
  .option("--json", "JSON output")
344
345
  .action((nodeId, opts) => {
345
346
  const result = initPool(nodeId, {