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.
- package/README.md +1 -1
- package/package.json +2 -2
- package/scripts/postinstall.mjs +33 -3
- package/src/assets/web-panel/assets/{AIOps-NeD6mA1O.js → AIOps-BpJ5yCcV.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Bhp7A7vO.js → ActionButton-B1uBfxnA.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DgdI84Jy.js → Analytics-0ubw5quf.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-Qw29caa7.js → AppLayout-go-GyyM_.js} +4 -4
- package/src/assets/web-panel/assets/{Audit-DgkzhBjz.js → Audit-CdUfoUnM.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CiWEQoW5.js → Backup-CBn0xtsa.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BWNbkeDF.js → BaseInput-a9fqTkvL.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CUcj4Vyd.js → Chat-D-d_IatD.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-bAMNCgEj.js → ChatBubbleRenderer-Co9h0SbA.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-B0uZTW8f.js → Checkbox-CiKEjtXm.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BPk7b-Xa.js → Codegen-OQxW_9Z2.js} +1 -1
- package/src/assets/web-panel/assets/{Col-C2cV_dw4.js → Col-BZHXUEnZ.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CDN6Yggb.js → Community-D3xno9fj.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-C4WPtW_V.js → Compact-D62jpZk_.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BGUfeH-3.js → Compliance-D4jFTAcQ.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CsnVgF-o.js → Cowork-BOU_wir4.js} +3 -3
- package/src/assets/web-panel/assets/{Cron--rGanASk.js → Cron-Cr9BlJA7.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-D_CLrd-0.js → Crosschain-L9M--CXb.js} +1 -1
- package/src/assets/web-panel/assets/{DID-iYkbVc8W.js → DID-xFu3-VWT.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CuFMU98t.js → Dashboard--ax48T3j.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BPSjv_Ye.js → Dropdown-CTOS8daR.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DBmk7czO.js → EmailListRenderer-CNLSX81U.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BaCArN11.js → FamilyGuardDashboard-5EjFynBc.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DsTV-8Ca.js → Federation-CoPyIWIu.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-C6fRr_6F.js → FormItemContext-BbzCNbYy.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-AfuZCfyv.js → GenericCardRenderer-8_9_uXY0.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CAFIrGhb.js → Git-Bz_qlVPg.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C-NaxDs4.js → Governance-7eepNCeD.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BPfeNZP7.js → Inference-DlBx5l1g.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DDUBte_m.js → KnowledgeGraph-BPkc--rM.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DWysA6JP.js → Logs-BQw4nPvS.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-CAK68hXc.js → Marketplace-Cil3SdgN.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CNmmoDAk.js → McpTools-Bnch7KrG.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-D_KmFoui.js → Memory-assQ3Suc.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CaY-6kjj.js → MobileBridge-D5mE8c-z.js} +2 -2
- package/src/assets/web-panel/assets/MobileProjects-C4MiDXw1.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-YnLrtuXT.js → Mtc-CumojeLk.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-D38v836u.js → MtcAudit-3tTBc_fw.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-Dv3ad9S4.js → Multisig-Dl4IJBsl.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-MYTh2eWC.js → NLProgramming-DHN_cV9x.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DYO-0Hva.js → Notes-DeyTvwYk.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-D39gOb3h.js → NotificationSettings-BUkj8mTj.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CXdO0z3I.js → OrderTableRenderer-BMpEXTki.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DOYTwQwt.js → Organization-B6Ogmkpz.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Cm-go0yU.js → Overflow-DRUE-2Wz.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CakGtorw.js → P2P-CnMUkd64.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BlmbHJnb.js → PdhVaultBrowser-B3nFxT3b.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-C_podo04.js → Permissions-CyG1FR7v.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-nBbehIKp.js → PersonalDataHub-BmN6YMb5.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-CGzQUoKv.js → Pipeline-BZcamAnH.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BuD-Dd9m.js → Privacy-D7_zsaY3.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CLcFmGXU.js → ProjectInit-DNa7XQjg.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BxXTR0dH.js → ProjectSettings-KH2Dm09G.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DkpBjAfd.js → Projects-T-WqR3D6.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DwHK42ht.js → Providers-8GtQ6GgR.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-idJPKErk.js → QuickAsk-BuBM5Zpg.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BvJj0Nu2.js → Recommend-DvH95W1b.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-BK9l4Rcf.js → Reputation-BHCpMEP6.js} +1 -1
- package/src/assets/web-panel/assets/{Row-rLxg7xk5.js → Row-BnMPysBm.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Cw6ZcHBY.js → RssFeed-C-T8B5VU.js} +3 -3
- package/src/assets/web-panel/assets/{Search-D8mKp506.js → Search-CioiZGkX.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CXunojmQ.js → Security-zSApKqdd.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BE5DgmPl.js → Services-CQh0UDXC.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CssL5wmE.js → Skeleton-C0dRaEVG.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-zyS_1YrT.js → Skills-BgQRArsa.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DIVn2Roa.js → Sla-BNn7F3jc.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CjNdZWdj.js → SpeechSettings-kvVfKfqv.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BCbu5WQT.js → SyncSettings-BwIkkX1E.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BjFrgXge.js → Tasks-BkcvhBZw.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Cl4Y3lKN.js → Templates-COK0o2pL.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-k1T0F_eH.js → Tenant-DpK87fqo.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-i0tHF8fy.js → Terminal-2g2-XPT_.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-FmPaNyqK.js → TimelineRenderer-B4SJqyqf.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BUWEiyab.js → Tokens-C3iSR8fH.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-9srMXwpo.js → Trigger-D1Oo58Yo.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-hmGor_R2.js → Trust-CUhy4DDc.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Dst7K10a.js → UkeySign-r-kTqSw8.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-D_utUv1u.js → VideoEditing-B8MyBfCX.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BpYTTseI.js → Wallet-CquTfSv0.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CEIw8QrF.js → WebAuthn-BC7TP1H3.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-Bkb4bUZ_.js → WorkflowEditor-CELBSNbP.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CTqDgGRH.js → chat-d66mbO2i.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CnJHVFLk.js → colors-D0WRCg20.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-D4-v0ahl.js → compact-item-4__-8TIi.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CYDbnHZX.js → createContext-Dqsf52js.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DUAmX0aE.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CbYwlEz5.js → hasIn-ClTZOS8I.js} +1 -1
- package/src/assets/web-panel/assets/{index-DVKfa-z4.js → index-0Axwx1nN.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cl7-mbsb.js → index-81SaeU6t.js} +1 -1
- package/src/assets/web-panel/assets/{index-CK8nROWH.js → index-B1TGSkBt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BygyTsjr.js → index-B3vrmn5v.js} +1 -1
- package/src/assets/web-panel/assets/{index-B78d_-pR.js → index-BCOpbfAH.js} +1 -1
- package/src/assets/web-panel/assets/index-BLCwqv8j.js +1 -0
- package/src/assets/web-panel/assets/{index-YuO8gxKb.js → index-BNKECBZm.js} +1 -1
- package/src/assets/web-panel/assets/{index-tmNsJzQU.js → index-BwozLU75.js} +1 -1
- package/src/assets/web-panel/assets/{index-dKpwhR5x.js → index-C4_XhCJS.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNz3yht2.js → index-C5l6tSky.js} +1 -1
- package/src/assets/web-panel/assets/{index-4767GEls.js → index-CFwkeSun.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCQ4kcL3.js → index-CGf3oqM0.js} +1 -1
- package/src/assets/web-panel/assets/{index-xDe5BkjU.js → index-CJKyF-y8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjFQuno4.js → index-Cg8Qw3Jw.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dl_NdY39.js → index-Cops66s2.js} +3 -3
- package/src/assets/web-panel/assets/{index-D8MYVsVB.js → index-Ct5SJenr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CY971z_9.js → index-CxoWS8hl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVc_5aBF.js → index-D-ya3Ohe.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4chfOjw.js → index-D68tyHYa.js} +1 -1
- package/src/assets/web-panel/assets/{index-BR4facv0.js → index-D9x6i7iV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CxKdSB-p.js → index-DDLjwgva.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-hiXmVK.js → index-DORg0Hps.js} +1 -1
- package/src/assets/web-panel/assets/{index-BR0FfrCL.js → index-DQaGurrQ.js} +1 -1
- package/src/assets/web-panel/assets/index-Db5JRQ6E.js +1 -0
- package/src/assets/web-panel/assets/{index-5NXdAIZK.js → index-DbY1lv1z.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOUSaCsn.js → index-Dm7CYK3j.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxvFrsxl.js → index-DpLhC0nx.js} +1 -1
- package/src/assets/web-panel/assets/{index-qNwkSspX.js → index-P4X9zSF2.js} +1 -1
- package/src/assets/web-panel/assets/{index-OqmUv5QO.js → index-PAiWA2un.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8uhiRML.js → index-PMJ4tBAA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfshMjFN.js → index-Yi5Lr63I.js} +1 -1
- package/src/assets/web-panel/assets/{index-wxz2s6uW.js → index-ZZpfHd4J.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdRtpQFq.js → index-b7a5aEX9.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2fICr5d.js → index-e5zJLrJQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGUOVPjO.js → index-fi2ikHoc.js} +1 -1
- package/src/assets/web-panel/assets/{index-8cmtr1jC.js → index-jAPphbJL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMKNVIqJ.js → index-leuwRsbf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CP-UKwu8.js → index-luisYDBz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaCCLe7i.js → index-we9-1IbF.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-qCQgpAty.js → initDefaultProps-zqDf7qWv.js} +1 -1
- package/src/assets/web-panel/assets/{motion-SkVSGdwu.js → motion-DRqTooll.js} +1 -1
- package/src/assets/web-panel/assets/{move-BpWxaW_x.js → move-N8tkRqS4.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DlZWM2H4.js → omit-Cy01f2vw.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DobtUnVe.js → pickAttrs-C2ycNXNi.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CD6mYRZi.js → placementArrow-D60Xb1j9.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DvIIMTD_.js → responsiveObserve-BF8Y-1HQ.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CVgyUfaA.js → slide-DDi6zYZf.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DrUDnjy_.js → statusUtils-CWPq6UzA.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BNYQS60m.js → styleChecker-D4zVyb4w.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DYv7Tvk0.js → useFlexGapSupport-BEMNO3oR.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DmAD2atJ.js → useFs-DBLO8VR7.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DbLVKA3I.js → usePersonalDataHub-C83ZIrPY.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C3WEt6_P.js → vnode-Dcfyve-7.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CRoSX_oZ.js → zoom-Dg6uoWSc.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/__tests__/hub-health.test.js +105 -0
- package/src/commands/__tests__/hub-stats.test.js +106 -0
- package/src/commands/a2a.js +2 -1
- package/src/commands/bi.js +4 -3
- package/src/commands/browse.js +3 -2
- package/src/commands/codegen.js +7 -6
- package/src/commands/collab.js +2 -1
- package/src/commands/crosschain.js +5 -4
- package/src/commands/dao.js +10 -10
- package/src/commands/dbevo.js +3 -2
- package/src/commands/economy.js +8 -6
- package/src/commands/evolution.js +10 -8
- package/src/commands/export.js +2 -1
- package/src/commands/federation.js +8 -7
- package/src/commands/fusion.js +4 -3
- package/src/commands/git.js +2 -1
- package/src/commands/governance.js +6 -5
- package/src/commands/hardening.js +3 -2
- package/src/commands/hmemory.js +2 -1
- package/src/commands/hub.js +111 -32
- package/src/commands/inference.js +9 -8
- package/src/commands/infra.js +9 -8
- package/src/commands/instinct.js +66 -0
- package/src/commands/learning.js +66 -0
- package/src/commands/marketplace.js +5 -4
- package/src/commands/matrix.js +2 -1
- package/src/commands/memory.js +66 -0
- package/src/commands/nlprog.js +4 -3
- package/src/commands/nostr.js +4 -3
- package/src/commands/note.js +2 -1
- package/src/commands/ops.js +3 -2
- package/src/commands/perception.js +6 -5
- package/src/commands/privacy.js +13 -12
- package/src/commands/quantization.js +3 -2
- package/src/commands/recommend.js +8 -7
- package/src/commands/reputation.js +4 -3
- package/src/commands/runtime.js +6 -5
- package/src/commands/sandbox.js +5 -4
- package/src/commands/session.js +2 -1
- package/src/commands/sla.js +6 -5
- package/src/commands/social.js +6 -5
- package/src/commands/stress.js +7 -6
- package/src/commands/sync.js +2 -1
- package/src/commands/tenant.js +3 -2
- package/src/commands/trust.js +7 -6
- package/src/commands/wallet.js +2 -1
- package/src/gateways/ws/personal-data-hub-protocol.js +16 -3
- package/src/lib/__tests__/agents.test.js +225 -0
- package/src/lib/__tests__/cowork-observe-html.test.js +141 -0
- package/src/lib/__tests__/logger.test.js +110 -0
- package/src/lib/__tests__/project-inventory.test.js +280 -0
- package/src/lib/__tests__/project-root.test.js +96 -0
- package/src/lib/__tests__/provider-stream.test.js +190 -0
- package/src/lib/cli-arg.js +41 -0
- package/src/lib/cli-numeric.js +12 -3
- package/src/lib/instinct-manager.js +64 -0
- package/src/lib/learning/learning-tables.js +83 -0
- package/src/lib/mcp-oauth.js +10 -2
- package/src/lib/memory-manager.js +67 -0
- package/src/lib/personal-data-hub-wiring.js +135 -7
- package/src/lib/plan-mode.js +3 -2
- package/src/repl/__tests__/mcp-prompt.test.js +155 -0
- package/src/repl/__tests__/slash-macro.test.js +81 -0
- package/src/runtime/__tests__/coding-agent-contract-shared.test.js +136 -0
- package/src/runtime/__tests__/coding-agent-events.test.js +263 -0
- package/src/assets/web-panel/assets/MobileProjects-DhDxrWze.js +0 -1
- package/src/assets/web-panel/assets/devWarning-OhxeajH6.js +0 -1
- package/src/assets/web-panel/assets/index-Bbtoi_47.js +0 -1
- package/src/assets/web-panel/assets/index-Cb8RWwaB.js +0 -1
package/src/commands/session.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import fs from "fs";
|
|
7
|
+
import { numericOption } from "../lib/cli-numeric.js";
|
|
7
8
|
import path from "path";
|
|
8
9
|
import chalk from "chalk";
|
|
9
10
|
import { logger } from "../lib/logger.js";
|
|
@@ -187,7 +188,7 @@ export function registerSessionCommand(program) {
|
|
|
187
188
|
|
|
188
189
|
let messages = sess.messages;
|
|
189
190
|
if (options.limit) {
|
|
190
|
-
messages = messages.slice(-
|
|
191
|
+
messages = messages.slice(-numericOption(options.limit, { name: "--limit", integer: true, min: 1 }));
|
|
191
192
|
}
|
|
192
193
|
|
|
193
194
|
for (const msg of messages) {
|
package/src/commands/sla.js
CHANGED
|
@@ -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 { bootstrap, shutdown } from "../runtime/bootstrap.js";
|
|
9
10
|
import {
|
|
@@ -80,7 +81,7 @@ export function registerSlaCommand(program) {
|
|
|
80
81
|
.command("create <org-id>")
|
|
81
82
|
.description("Create a new SLA contract")
|
|
82
83
|
.option("-t, --tier <tier>", "SLA tier (gold|silver|bronze)", "silver")
|
|
83
|
-
.option("-d, --duration <ms>", "Contract duration in ms",
|
|
84
|
+
.option("-d, --duration <ms>", "Contract duration in ms", intArg("--duration"))
|
|
84
85
|
.option("-f, --fee <amount>", "Monthly fee", parseFloat, 0)
|
|
85
86
|
.option("--json", "Output as JSON")
|
|
86
87
|
.action(async (orgId, options) => {
|
|
@@ -336,8 +337,8 @@ export function registerSlaCommand(program) {
|
|
|
336
337
|
sla
|
|
337
338
|
.command("report <sla-id>")
|
|
338
339
|
.description("Generate an SLA compliance report")
|
|
339
|
-
.option("--start <ms>", "Start of window (ms since epoch)",
|
|
340
|
-
.option("--end <ms>", "End of window (ms since epoch)",
|
|
340
|
+
.option("--start <ms>", "Start of window (ms since epoch)", intArg("--start"))
|
|
341
|
+
.option("--end <ms>", "End of window (ms since epoch)", intArg("--end"))
|
|
341
342
|
.option("--json", "Output as JSON")
|
|
342
343
|
.action(async (slaId, options) => {
|
|
343
344
|
try {
|
|
@@ -460,8 +461,8 @@ export function registerSlaCommand(program) {
|
|
|
460
461
|
.command("create-v2 <org-id>")
|
|
461
462
|
.description("Create a V2 SLA contract (enforces per-org active cap)")
|
|
462
463
|
.option("-t, --tier <tier>", "gold|silver|bronze", "silver")
|
|
463
|
-
.option("-d, --duration <ms>", "Contract duration in ms",
|
|
464
|
-
.option("-f, --fee <amount>", "Monthly fee",
|
|
464
|
+
.option("-d, --duration <ms>", "Contract duration in ms", intArg("--duration"))
|
|
465
|
+
.option("-f, --fee <amount>", "Monthly fee", floatArg("--fee"))
|
|
465
466
|
.option("--json", "Output as JSON")
|
|
466
467
|
.action(async (orgId, options) => {
|
|
467
468
|
try {
|
package/src/commands/social.js
CHANGED
|
@@ -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";
|
|
@@ -475,7 +476,7 @@ export function registerSocialCommand(program) {
|
|
|
475
476
|
ensureSocialTables(db);
|
|
476
477
|
|
|
477
478
|
const messages = getChatMessages(threadId, {
|
|
478
|
-
limit:
|
|
479
|
+
limit: numericOption(options.limit, { name: "--limit", integer: true, min: 1, fallback: 50 }),
|
|
479
480
|
});
|
|
480
481
|
if (options.json) {
|
|
481
482
|
console.log(JSON.stringify(messages, null, 2));
|
|
@@ -966,10 +967,10 @@ export function registerSocialCommand(program) {
|
|
|
966
967
|
directed: !!options.directed,
|
|
967
968
|
edgeTypes: _splitEdgeTypes(options.edgeTypes),
|
|
968
969
|
weights: {
|
|
969
|
-
degree:
|
|
970
|
-
closeness:
|
|
971
|
-
betweenness:
|
|
972
|
-
eigenvector:
|
|
970
|
+
degree: numericOption(options.wDegree, { name: "--w-degree", fallback: 0.25 }),
|
|
971
|
+
closeness: numericOption(options.wCloseness, { name: "--w-closeness", fallback: 0.25 }),
|
|
972
|
+
betweenness: numericOption(options.wBetweenness, { name: "--w-betweenness", fallback: 0.25 }),
|
|
973
|
+
eigenvector: numericOption(options.wEigenvector, { name: "--w-eigenvector", fallback: 0.25 }),
|
|
973
974
|
},
|
|
974
975
|
});
|
|
975
976
|
if (options.json) console.log(JSON.stringify(scores, null, 2));
|
package/src/commands/stress.js
CHANGED
|
@@ -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 { bootstrap, shutdown } from "../runtime/bootstrap.js";
|
|
9
10
|
import {
|
|
@@ -58,9 +59,9 @@ export function registerStressCommand(program) {
|
|
|
58
59
|
"Load level (light|medium|heavy|extreme)",
|
|
59
60
|
"medium",
|
|
60
61
|
)
|
|
61
|
-
.option("-c, --concurrency <n>", "Override concurrency",
|
|
62
|
-
.option("-r, --rps <n>", "Override requests per second",
|
|
63
|
-
.option("-d, --duration <ms>", "Override duration in ms",
|
|
62
|
+
.option("-c, --concurrency <n>", "Override concurrency", intArg("--concurrency"))
|
|
63
|
+
.option("-r, --rps <n>", "Override requests per second", intArg("--rps"))
|
|
64
|
+
.option("-d, --duration <ms>", "Override duration in ms", intArg("--duration"))
|
|
64
65
|
.option("--json", "Output as JSON")
|
|
65
66
|
.action(async (options) => {
|
|
66
67
|
try {
|
|
@@ -354,9 +355,9 @@ export function registerStressCommand(program) {
|
|
|
354
355
|
"Load level (light|medium|heavy|extreme)",
|
|
355
356
|
"medium",
|
|
356
357
|
)
|
|
357
|
-
.option("-c, --concurrency <n>", "Override concurrency",
|
|
358
|
-
.option("-r, --rps <n>", "Override requests per second",
|
|
359
|
-
.option("-d, --duration <ms>", "Override duration in ms",
|
|
358
|
+
.option("-c, --concurrency <n>", "Override concurrency", intArg("--concurrency"))
|
|
359
|
+
.option("-r, --rps <n>", "Override requests per second", intArg("--rps"))
|
|
360
|
+
.option("-d, --duration <ms>", "Override duration in ms", intArg("--duration"))
|
|
360
361
|
.option("--json", "Output as JSON")
|
|
361
362
|
.action(async (options) => {
|
|
362
363
|
try {
|
package/src/commands/sync.js
CHANGED
|
@@ -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";
|
|
@@ -220,7 +221,7 @@ export function registerSyncCommand(program) {
|
|
|
220
221
|
process.exit(1);
|
|
221
222
|
}
|
|
222
223
|
const db = ctx.db.getDatabase();
|
|
223
|
-
const entries = getSyncLog(db, { limit:
|
|
224
|
+
const entries = getSyncLog(db, { limit: numericOption(options.limit, { name: "--limit", integer: true, min: 1, fallback: 20 }) });
|
|
224
225
|
|
|
225
226
|
if (options.json) {
|
|
226
227
|
console.log(JSON.stringify(entries, null, 2));
|
package/src/commands/tenant.js
CHANGED
|
@@ -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 { parseJsonOption } from "../lib/parse-json-option.js";
|
|
@@ -380,8 +381,8 @@ export function registerTenantCommand(program) {
|
|
|
380
381
|
.command("subscribe <tenant-id>")
|
|
381
382
|
.description("Start a new subscription (cancels any prior active one)")
|
|
382
383
|
.requiredOption("-p, --plan <plan>", "Plan id")
|
|
383
|
-
.option("-a, --amount <n>", "Override amount",
|
|
384
|
-
.option("-d, --duration-ms <ms>", "Duration in ms (default 30d)",
|
|
384
|
+
.option("-a, --amount <n>", "Override amount", floatArg("--amount"))
|
|
385
|
+
.option("-d, --duration-ms <ms>", "Duration in ms (default 30d)", intArg("--duration-ms"))
|
|
385
386
|
.option("--json", "Output as JSON")
|
|
386
387
|
.action(async (tenantId, options) => {
|
|
387
388
|
try {
|
package/src/commands/trust.js
CHANGED
|
@@ -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
|
TRUST_ANCHOR,
|
|
@@ -163,7 +164,7 @@ export function registerTrustCommand(program) {
|
|
|
163
164
|
.description("List attestations")
|
|
164
165
|
.option("-a, --anchor <type>", "Filter by anchor")
|
|
165
166
|
.option("-s, --status <status>", "Filter by status")
|
|
166
|
-
.option("--limit <n>", "Max results",
|
|
167
|
+
.option("--limit <n>", "Max results", intArg("--limit"))
|
|
167
168
|
.option("--json", "JSON output")
|
|
168
169
|
.action((opts) => {
|
|
169
170
|
const db = _dbFromCtx(tr);
|
|
@@ -186,7 +187,7 @@ export function registerTrustCommand(program) {
|
|
|
186
187
|
tr.command("interop-test <algorithm>")
|
|
187
188
|
.description("Run PQC interoperability test")
|
|
188
189
|
.option("-p, --peer <id>", "Peer identifier")
|
|
189
|
-
.option("-l, --latency <ms>", "Latency in ms",
|
|
190
|
+
.option("-l, --latency <ms>", "Latency in ms", intArg("--latency"))
|
|
190
191
|
.option("--json", "JSON output")
|
|
191
192
|
.action((algorithm, opts) => {
|
|
192
193
|
const db = _dbFromCtx(tr);
|
|
@@ -207,7 +208,7 @@ export function registerTrustCommand(program) {
|
|
|
207
208
|
tr.command("interop-tests")
|
|
208
209
|
.description("List PQC interop tests")
|
|
209
210
|
.option("-a, --algorithm <algo>", "Filter by algorithm")
|
|
210
|
-
.option("--limit <n>", "Max results",
|
|
211
|
+
.option("--limit <n>", "Max results", intArg("--limit"))
|
|
211
212
|
.option("--json", "JSON output")
|
|
212
213
|
.action((opts) => {
|
|
213
214
|
const db = _dbFromCtx(tr);
|
|
@@ -229,7 +230,7 @@ export function registerTrustCommand(program) {
|
|
|
229
230
|
tr.command("sat-send <payload>")
|
|
230
231
|
.description("Send satellite message")
|
|
231
232
|
.option("-p, --provider <name>", "Provider (iridium/starlink/beidou)")
|
|
232
|
-
.option("-r, --priority <n>", "Priority (1-10)",
|
|
233
|
+
.option("-r, --priority <n>", "Priority (1-10)", intArg("--priority"))
|
|
233
234
|
.option("--json", "JSON output")
|
|
234
235
|
.action((payload, opts) => {
|
|
235
236
|
const db = _dbFromCtx(tr);
|
|
@@ -277,7 +278,7 @@ export function registerTrustCommand(program) {
|
|
|
277
278
|
.description("List satellite messages")
|
|
278
279
|
.option("-p, --provider <name>", "Filter by provider")
|
|
279
280
|
.option("-s, --status <status>", "Filter by status")
|
|
280
|
-
.option("--limit <n>", "Max results",
|
|
281
|
+
.option("--limit <n>", "Max results", intArg("--limit"))
|
|
281
282
|
.option("--json", "JSON output")
|
|
282
283
|
.action((opts) => {
|
|
283
284
|
const db = _dbFromCtx(tr);
|
|
@@ -346,7 +347,7 @@ export function registerTrustCommand(program) {
|
|
|
346
347
|
tr.command("hsm-devices")
|
|
347
348
|
.description("List HSM devices")
|
|
348
349
|
.option("-v, --vendor <name>", "Filter by vendor")
|
|
349
|
-
.option("--limit <n>", "Max results",
|
|
350
|
+
.option("--limit <n>", "Max results", intArg("--limit"))
|
|
350
351
|
.option("--json", "JSON output")
|
|
351
352
|
.action((opts) => {
|
|
352
353
|
const db = _dbFromCtx(tr);
|
package/src/commands/wallet.js
CHANGED
|
@@ -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 { bootstrap, shutdown } from "../runtime/bootstrap.js";
|
|
9
10
|
import {
|
|
@@ -386,7 +387,7 @@ export function registerWalletCommand(program) {
|
|
|
386
387
|
const db = ctx.db.getDatabase();
|
|
387
388
|
const txns = getTransactions(db, {
|
|
388
389
|
address: options.address,
|
|
389
|
-
limit:
|
|
390
|
+
limit: numericOption(options.limit, { name: "--limit", integer: true, min: 1, fallback: 20 }),
|
|
390
391
|
});
|
|
391
392
|
|
|
392
393
|
if (options.json) {
|
|
@@ -30,9 +30,22 @@ import {
|
|
|
30
30
|
writeFileSync,
|
|
31
31
|
} from "node:fs";
|
|
32
32
|
import { join } from "node:path";
|
|
33
|
-
import
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
// Lazily import the pdh package the first time the system-data-android
|
|
34
|
+
// ingest topic is actually used. This module is pulled in by the
|
|
35
|
+
// agent/chat/serve/ui runtime chain at startup (ws-server →
|
|
36
|
+
// message-dispatcher → here), so a top-level static import would force the
|
|
37
|
+
// whole pdh graph to load on every `cc` invocation — and a partial/corrupt
|
|
38
|
+
// pdh install would brick unrelated commands. See the matching rationale in
|
|
39
|
+
// personal-data-hub-wiring.js.
|
|
40
|
+
let _ingestSnapshotFn = null;
|
|
41
|
+
async function ingestSystemDataAndroidSnapshot(hub, snapshot) {
|
|
42
|
+
if (!_ingestSnapshotFn) {
|
|
43
|
+
const pdhMod = await import("@chainlesschain/personal-data-hub");
|
|
44
|
+
const pdhPkg = pdhMod.default || pdhMod;
|
|
45
|
+
_ingestSnapshotFn = pdhPkg.ingestSystemDataAndroidSnapshot;
|
|
46
|
+
}
|
|
47
|
+
return _ingestSnapshotFn(hub, snapshot);
|
|
48
|
+
}
|
|
36
49
|
|
|
37
50
|
/**
|
|
38
51
|
* If the caller didn't pass `inputPath`, try to pull a snapshot for
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* agents tests — user-defined subagent discovery (.claude/agents/*.md), the
|
|
5
|
+
* Claude-Code parity layer, previously untested. Covers normalizeTools,
|
|
6
|
+
* parseAgentFile (frontmatter + body=systemPrompt, defaults, bad YAML),
|
|
7
|
+
* discoverAgents (path-derived names with `:`, frontmatter name override,
|
|
8
|
+
* project-shadows-personal precedence, sorting) and getAgent (colon/slash/
|
|
9
|
+
* leading-slash lookup). In-memory fake fs over POSIX paths via the deps seam;
|
|
10
|
+
* no `.git` present so projectRootBase resolves to null (cwd+home dirs only).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { describe, it, expect } from "vitest";
|
|
14
|
+
import pathDefault from "path";
|
|
15
|
+
import {
|
|
16
|
+
normalizeTools,
|
|
17
|
+
parseAgentFile,
|
|
18
|
+
discoverAgents,
|
|
19
|
+
getAgent,
|
|
20
|
+
} from "../agents.js";
|
|
21
|
+
|
|
22
|
+
const P = pathDefault.posix;
|
|
23
|
+
|
|
24
|
+
function makeFs(files) {
|
|
25
|
+
const contents = new Map(Object.entries(files));
|
|
26
|
+
const fileSet = new Set(contents.keys());
|
|
27
|
+
const dirSet = new Set(["/"]);
|
|
28
|
+
for (const f of fileSet) {
|
|
29
|
+
let d = P.dirname(f);
|
|
30
|
+
while (d && !dirSet.has(d)) {
|
|
31
|
+
dirSet.add(d);
|
|
32
|
+
d = P.dirname(d);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const childrenOf = (dir) => {
|
|
36
|
+
const out = new Map();
|
|
37
|
+
for (const f of fileSet)
|
|
38
|
+
if (P.dirname(f) === dir) out.set(P.basename(f), false);
|
|
39
|
+
for (const d of dirSet)
|
|
40
|
+
if (d !== "/" && P.dirname(d) === dir) out.set(P.basename(d), true);
|
|
41
|
+
return out;
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
readFileSync(p) {
|
|
45
|
+
if (!fileSet.has(p)) {
|
|
46
|
+
const e = new Error("ENOENT");
|
|
47
|
+
e.code = "ENOENT";
|
|
48
|
+
throw e;
|
|
49
|
+
}
|
|
50
|
+
return contents.get(p);
|
|
51
|
+
},
|
|
52
|
+
existsSync(p) {
|
|
53
|
+
return fileSet.has(p) || dirSet.has(p);
|
|
54
|
+
},
|
|
55
|
+
statSync(p) {
|
|
56
|
+
if (!fileSet.has(p) && !dirSet.has(p)) {
|
|
57
|
+
const e = new Error("ENOENT");
|
|
58
|
+
e.code = "ENOENT";
|
|
59
|
+
throw e;
|
|
60
|
+
}
|
|
61
|
+
const isDir = dirSet.has(p);
|
|
62
|
+
return { isDirectory: () => isDir, isFile: () => !isDir };
|
|
63
|
+
},
|
|
64
|
+
readdirSync(p, opts) {
|
|
65
|
+
if (!dirSet.has(p)) {
|
|
66
|
+
const e = new Error("ENOENT");
|
|
67
|
+
e.code = "ENOENT";
|
|
68
|
+
throw e;
|
|
69
|
+
}
|
|
70
|
+
const kids = childrenOf(p);
|
|
71
|
+
if (opts && opts.withFileTypes) {
|
|
72
|
+
return [...kids].map(([name, isDir]) => ({
|
|
73
|
+
name,
|
|
74
|
+
isDirectory: () => isDir,
|
|
75
|
+
isFile: () => !isDir,
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
return [...kids.keys()];
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const discover = (files, home = "/home/u") =>
|
|
84
|
+
discoverAgents("/proj", { deps: { fs: makeFs(files), path: P }, home });
|
|
85
|
+
|
|
86
|
+
// --------------------------------------------------------------------------- //
|
|
87
|
+
// normalizeTools
|
|
88
|
+
// --------------------------------------------------------------------------- //
|
|
89
|
+
describe("normalizeTools", () => {
|
|
90
|
+
it("returns null for null/undefined", () => {
|
|
91
|
+
expect(normalizeTools(null)).toBe(null);
|
|
92
|
+
expect(normalizeTools(undefined)).toBe(null);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("splits a comma/space string into a trimmed list", () => {
|
|
96
|
+
expect(normalizeTools("read, write, run")).toEqual([
|
|
97
|
+
"read",
|
|
98
|
+
"write",
|
|
99
|
+
"run",
|
|
100
|
+
]);
|
|
101
|
+
expect(normalizeTools("a b c")).toEqual(["a", "b", "c"]);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("normalizes an array, dropping empties", () => {
|
|
105
|
+
expect(normalizeTools(["read", "", " write "])).toEqual(["read", "write"]);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("returns null when nothing remains", () => {
|
|
109
|
+
expect(normalizeTools("")).toBe(null);
|
|
110
|
+
expect(normalizeTools([" ", ""])).toBe(null);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// --------------------------------------------------------------------------- //
|
|
115
|
+
// parseAgentFile
|
|
116
|
+
// --------------------------------------------------------------------------- //
|
|
117
|
+
describe("parseAgentFile", () => {
|
|
118
|
+
const parse = (content, opts) =>
|
|
119
|
+
parseAgentFile("/a.md", "project", {
|
|
120
|
+
deps: { fs: makeFs({ "/a.md": content }) },
|
|
121
|
+
...opts,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("returns null when the file cannot be read", () => {
|
|
125
|
+
expect(
|
|
126
|
+
parseAgentFile("/missing.md", "project", { deps: { fs: makeFs({}) } }),
|
|
127
|
+
).toBe(null);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("uses the whole body as systemPrompt when there is no frontmatter", () => {
|
|
131
|
+
const a = parse("You are a helpful agent.");
|
|
132
|
+
expect(a.systemPrompt).toBe("You are a helpful agent.");
|
|
133
|
+
expect(a.name).toBe(null);
|
|
134
|
+
expect(a.description).toBe("");
|
|
135
|
+
expect(a.tools).toBe(null);
|
|
136
|
+
expect(a.model).toBe(null);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("parses frontmatter metadata and trims the body", () => {
|
|
140
|
+
const a = parse(
|
|
141
|
+
"---\nname: sec\ndescription: security review\ntools: read, grep\nmodel: opus\n---\n\nReview for vulns.\n",
|
|
142
|
+
);
|
|
143
|
+
expect(a.name).toBe("sec");
|
|
144
|
+
expect(a.description).toBe("security review");
|
|
145
|
+
expect(a.tools).toEqual(["read", "grep"]);
|
|
146
|
+
expect(a.model).toBe("opus");
|
|
147
|
+
expect(a.systemPrompt).toBe("Review for vulns.");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("accepts a YAML array for tools", () => {
|
|
151
|
+
const a = parse("---\ntools:\n - read\n - write\n---\nbody");
|
|
152
|
+
expect(a.tools).toEqual(["read", "write"]);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("falls back to defaults on invalid YAML frontmatter", () => {
|
|
156
|
+
const a = parse("---\n: : bad : yaml :\n---\nthe body");
|
|
157
|
+
expect(a.name).toBe(null);
|
|
158
|
+
expect(a.systemPrompt).toBe("the body");
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// --------------------------------------------------------------------------- //
|
|
163
|
+
// discoverAgents
|
|
164
|
+
// --------------------------------------------------------------------------- //
|
|
165
|
+
describe("discoverAgents", () => {
|
|
166
|
+
it("derives names from the path with ':' for nesting", () => {
|
|
167
|
+
const agents = discover({
|
|
168
|
+
"/proj/.claude/agents/reviewer.md": "Review.",
|
|
169
|
+
"/proj/.claude/agents/sec/audit.md": "Audit.",
|
|
170
|
+
});
|
|
171
|
+
const names = agents.map((a) => a.name);
|
|
172
|
+
expect(names).toEqual(["reviewer", "sec:audit"]); // sorted
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("lets frontmatter name override the path-derived name", () => {
|
|
176
|
+
const agents = discover({
|
|
177
|
+
"/proj/.claude/agents/x.md": "---\nname: custom\n---\nbody",
|
|
178
|
+
});
|
|
179
|
+
expect(agents[0].name).toBe("custom");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("project scope shadows personal on a name clash", () => {
|
|
183
|
+
const agents = discover({
|
|
184
|
+
"/proj/.claude/agents/reviewer.md": "PROJECT version.",
|
|
185
|
+
"/home/u/.claude/agents/reviewer.md": "PERSONAL version.",
|
|
186
|
+
"/home/u/.claude/agents/helper.md": "Helper.",
|
|
187
|
+
});
|
|
188
|
+
const reviewer = agents.find((a) => a.name === "reviewer");
|
|
189
|
+
expect(reviewer.scope).toBe("project");
|
|
190
|
+
expect(reviewer.systemPrompt).toBe("PROJECT version.");
|
|
191
|
+
// personal-only agent still discovered
|
|
192
|
+
expect(agents.find((a) => a.name === "helper").scope).toBe("personal");
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("returns [] when no agent dirs exist", () => {
|
|
196
|
+
expect(discover({ "/proj/readme.md": "x" })).toEqual([]);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// --------------------------------------------------------------------------- //
|
|
201
|
+
// getAgent
|
|
202
|
+
// --------------------------------------------------------------------------- //
|
|
203
|
+
describe("getAgent", () => {
|
|
204
|
+
const files = {
|
|
205
|
+
"/proj/.claude/agents/sec/audit.md": "---\ndescription: d\n---\nAudit.",
|
|
206
|
+
};
|
|
207
|
+
const get = (name) =>
|
|
208
|
+
getAgent(name, "/proj", {
|
|
209
|
+
deps: { fs: makeFs(files), path: P },
|
|
210
|
+
home: "/home/u",
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("looks up by colon name", () => {
|
|
214
|
+
expect(get("sec:audit")?.description).toBe("d");
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("accepts slash and leading-slash forms", () => {
|
|
218
|
+
expect(get("sec/audit")?.name).toBe("sec:audit");
|
|
219
|
+
expect(get("/sec/audit")?.name).toBe("sec:audit");
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("returns null for an unknown agent", () => {
|
|
223
|
+
expect(get("nope")).toBe(null);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* cowork-observe-html buildHtml tests (previously untested).
|
|
5
|
+
*
|
|
6
|
+
* buildHtml renders a static dashboard from an aggregate snapshot and embeds
|
|
7
|
+
* user-controlled data (template names, failure summaries, schedule fields) into
|
|
8
|
+
* HTML and into an inline <script> JSON blob. The escaping is the security
|
|
9
|
+
* boundary — these tests pin XSS safety (HTML entity escaping + JSON
|
|
10
|
+
* script-breakout escaping) plus the structural rendering / empty states.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { describe, it, expect } from "vitest";
|
|
14
|
+
import { buildHtml } from "../cowork-observe-html.js";
|
|
15
|
+
|
|
16
|
+
describe("buildHtml — document shape", () => {
|
|
17
|
+
it("emits a full HTML document with UTF-8 charset", () => {
|
|
18
|
+
const html = buildHtml({});
|
|
19
|
+
expect(html.startsWith("<!DOCTYPE html>")).toBe(true);
|
|
20
|
+
expect(html).toContain('<meta charset="UTF-8">');
|
|
21
|
+
expect(html).toContain("Cowork Observe");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("does not throw on null/undefined data", () => {
|
|
25
|
+
expect(() => buildHtml(null)).not.toThrow();
|
|
26
|
+
expect(() => buildHtml(undefined)).not.toThrow();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("renders empty-state messages when there is no data", () => {
|
|
30
|
+
const html = buildHtml({});
|
|
31
|
+
expect(html).toContain("No template runs in window.");
|
|
32
|
+
expect(html).toContain("No failures in window");
|
|
33
|
+
expect(html).toContain("No upcoming triggers.");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("renders summary stat cards", () => {
|
|
37
|
+
const html = buildHtml({
|
|
38
|
+
tasks: { total: 42, successRate: 0.876, failed: 5, avgTokens: 1200 },
|
|
39
|
+
schedules: { active: 3 },
|
|
40
|
+
});
|
|
41
|
+
expect(html).toContain(">42<"); // total
|
|
42
|
+
expect(html).toContain(">88%<"); // successRate rounded
|
|
43
|
+
expect(html).toContain(">3<"); // active schedules
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("buildHtml — table rendering", () => {
|
|
48
|
+
it("renders template rows with success-rate percentage", () => {
|
|
49
|
+
const html = buildHtml({
|
|
50
|
+
templates: [
|
|
51
|
+
{ templateName: "build", runs: 9, successRate: 0.5, avgTokens: 100 },
|
|
52
|
+
],
|
|
53
|
+
});
|
|
54
|
+
expect(html).toContain("<td>build</td>");
|
|
55
|
+
expect(html).toContain("<td>50%</td>");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("caps template rows at 10", () => {
|
|
59
|
+
const templates = Array.from({ length: 15 }, (_, i) => ({
|
|
60
|
+
templateName: `t${i}`,
|
|
61
|
+
runs: i,
|
|
62
|
+
successRate: 1,
|
|
63
|
+
avgTokens: 0,
|
|
64
|
+
}));
|
|
65
|
+
const html = buildHtml({ templates });
|
|
66
|
+
expect(html).toContain("<td>t9</td>");
|
|
67
|
+
expect(html).not.toContain("<td>t10</td>"); // 11th dropped
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("truncates failure summary to 80 chars", () => {
|
|
71
|
+
const long = "x".repeat(200);
|
|
72
|
+
const html = buildHtml({
|
|
73
|
+
failures: [
|
|
74
|
+
{
|
|
75
|
+
templateId: "f",
|
|
76
|
+
failureCount: 2,
|
|
77
|
+
commonSummaries: [{ summary: long }],
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
// the visible table cell is truncated to 80 (the raw 200-char string still
|
|
82
|
+
// lives untruncated inside the embedded JSON blob, so scope to the <td>).
|
|
83
|
+
expect(html).toContain("<td>" + "x".repeat(80) + "</td>");
|
|
84
|
+
expect(html).not.toContain("<td>" + "x".repeat(81));
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe("buildHtml — XSS safety", () => {
|
|
89
|
+
it("HTML-escapes user-controlled template names", () => {
|
|
90
|
+
const html = buildHtml({
|
|
91
|
+
templates: [
|
|
92
|
+
{
|
|
93
|
+
templateName: "<script>alert(1)</script>",
|
|
94
|
+
runs: 1,
|
|
95
|
+
successRate: 1,
|
|
96
|
+
avgTokens: 0,
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
});
|
|
100
|
+
expect(html).toContain("<script>alert(1)</script>");
|
|
101
|
+
// the raw payload must not appear inside a table cell
|
|
102
|
+
expect(html).not.toContain("<td><script>alert(1)</script></td>");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("HTML-escapes failure summaries and schedule fields", () => {
|
|
106
|
+
const html = buildHtml({
|
|
107
|
+
failures: [
|
|
108
|
+
{
|
|
109
|
+
templateName: "<b>x</b>",
|
|
110
|
+
failureCount: 1,
|
|
111
|
+
commonSummaries: [{ summary: "a&b\"c'" }],
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
schedules: {
|
|
115
|
+
nextTriggers: [
|
|
116
|
+
{ at: "<i>t</i>", cron: "* * * * *", scheduleId: "s<1>" },
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
expect(html).toContain("<b>x</b>");
|
|
121
|
+
expect(html).toContain("a&b"c'");
|
|
122
|
+
expect(html).toContain("<i>t</i>");
|
|
123
|
+
expect(html).toContain("s<1>");
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("escapes a </script> breakout in the embedded JSON blob", () => {
|
|
127
|
+
const html = buildHtml({
|
|
128
|
+
tasks: { note: "</script><img src=x onerror=alert(1)>" },
|
|
129
|
+
});
|
|
130
|
+
// the inline JSON must not contain a raw closing script tag
|
|
131
|
+
expect(html).toContain("\\u003c/script");
|
|
132
|
+
expect(html).not.toContain("</script><img");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("escapes <, > and & in the embedded JSON blob", () => {
|
|
136
|
+
const html = buildHtml({ x: "<a> & <b>" });
|
|
137
|
+
expect(html).toContain("\\u003ca\\u003e \\u0026 \\u003cb\\u003e");
|
|
138
|
+
// the script assignment line itself carries the escaped form
|
|
139
|
+
expect(html).toContain("window.__COWORK_OBSERVE__ =");
|
|
140
|
+
});
|
|
141
|
+
});
|