@intutic/cli 2.2.0 → 2.3.0

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 (344) hide show
  1. package/README.md +8 -8
  2. package/dist/cli.d.ts +0 -1
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +481 -19
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/apiCommand.d.ts +40 -0
  7. package/dist/commands/apiCommand.d.ts.map +1 -0
  8. package/dist/commands/apiCommand.js +88 -0
  9. package/dist/commands/apiCommand.js.map +1 -0
  10. package/dist/commands/budget.d.ts +4 -0
  11. package/dist/commands/budget.d.ts.map +1 -1
  12. package/dist/commands/budget.js +8 -0
  13. package/dist/commands/budget.js.map +1 -1
  14. package/dist/commands/compliance.d.ts +122 -0
  15. package/dist/commands/compliance.d.ts.map +1 -0
  16. package/dist/commands/compliance.js +278 -0
  17. package/dist/commands/compliance.js.map +1 -0
  18. package/dist/commands/connect.d.ts +26 -1
  19. package/dist/commands/connect.d.ts.map +1 -1
  20. package/dist/commands/connect.js +109 -51
  21. package/dist/commands/connect.js.map +1 -1
  22. package/dist/commands/credentials.d.ts +1 -1
  23. package/dist/commands/credentials.js +1 -1
  24. package/dist/commands/decision.d.ts +4 -4
  25. package/dist/commands/decision.js +4 -4
  26. package/dist/commands/disconnect.d.ts +4 -0
  27. package/dist/commands/disconnect.d.ts.map +1 -1
  28. package/dist/commands/disconnect.js +17 -3
  29. package/dist/commands/disconnect.js.map +1 -1
  30. package/dist/commands/doctor.d.ts +0 -1
  31. package/dist/commands/doctor.d.ts.map +1 -1
  32. package/dist/commands/doctor.js +0 -1
  33. package/dist/commands/doctor.js.map +1 -1
  34. package/dist/commands/enforce.d.ts +1 -1
  35. package/dist/commands/enforce.js +1 -1
  36. package/dist/commands/enterprise.d.ts +3 -2
  37. package/dist/commands/enterprise.d.ts.map +1 -1
  38. package/dist/commands/enterprise.js +11 -3
  39. package/dist/commands/enterprise.js.map +1 -1
  40. package/dist/commands/env.js +1 -1
  41. package/dist/commands/exec.d.ts +2 -3
  42. package/dist/commands/exec.d.ts.map +1 -1
  43. package/dist/commands/exec.js +4 -5
  44. package/dist/commands/exec.js.map +1 -1
  45. package/dist/commands/gateLiveness.d.ts +15 -0
  46. package/dist/commands/gateLiveness.d.ts.map +1 -0
  47. package/dist/commands/gateLiveness.js +34 -0
  48. package/dist/commands/gateLiveness.js.map +1 -0
  49. package/dist/commands/gateway.d.ts +14 -4
  50. package/dist/commands/gateway.d.ts.map +1 -1
  51. package/dist/commands/gateway.js +34 -4
  52. package/dist/commands/gateway.js.map +1 -1
  53. package/dist/commands/github.d.ts +20 -0
  54. package/dist/commands/github.d.ts.map +1 -0
  55. package/dist/commands/github.js +41 -0
  56. package/dist/commands/github.js.map +1 -0
  57. package/dist/commands/guardrails.d.ts +28 -2
  58. package/dist/commands/guardrails.d.ts.map +1 -1
  59. package/dist/commands/guardrails.js +233 -24
  60. package/dist/commands/guardrails.js.map +1 -1
  61. package/dist/commands/init.d.ts +1 -2
  62. package/dist/commands/init.d.ts.map +1 -1
  63. package/dist/commands/init.js +1 -2
  64. package/dist/commands/init.js.map +1 -1
  65. package/dist/commands/install-daemon.d.ts +1 -1
  66. package/dist/commands/install-daemon.js +2 -2
  67. package/dist/commands/integrity.d.ts +10 -2
  68. package/dist/commands/integrity.d.ts.map +1 -1
  69. package/dist/commands/integrity.js +3 -3
  70. package/dist/commands/integrity.js.map +1 -1
  71. package/dist/commands/inventory.d.ts +60 -0
  72. package/dist/commands/inventory.d.ts.map +1 -0
  73. package/dist/commands/inventory.js +141 -0
  74. package/dist/commands/inventory.js.map +1 -0
  75. package/dist/commands/judge.d.ts +1 -1
  76. package/dist/commands/judge.js +2 -2
  77. package/dist/commands/judge.js.map +1 -1
  78. package/dist/commands/login.d.ts +0 -1
  79. package/dist/commands/login.d.ts.map +1 -1
  80. package/dist/commands/login.js +0 -1
  81. package/dist/commands/login.js.map +1 -1
  82. package/dist/commands/logout.d.ts +0 -1
  83. package/dist/commands/logout.d.ts.map +1 -1
  84. package/dist/commands/logout.js +0 -1
  85. package/dist/commands/logout.js.map +1 -1
  86. package/dist/commands/mcp.d.ts +31 -0
  87. package/dist/commands/mcp.d.ts.map +1 -0
  88. package/dist/commands/mcp.js +65 -0
  89. package/dist/commands/mcp.js.map +1 -0
  90. package/dist/commands/notifications.d.ts +54 -0
  91. package/dist/commands/notifications.d.ts.map +1 -0
  92. package/dist/commands/notifications.js +151 -0
  93. package/dist/commands/notifications.js.map +1 -0
  94. package/dist/commands/org.d.ts +3 -3
  95. package/dist/commands/org.js +3 -3
  96. package/dist/commands/policy.d.ts +6 -1
  97. package/dist/commands/policy.d.ts.map +1 -1
  98. package/dist/commands/policy.js +77 -37
  99. package/dist/commands/policy.js.map +1 -1
  100. package/dist/commands/rollback.d.ts.map +1 -1
  101. package/dist/commands/rollback.js +3 -1
  102. package/dist/commands/rollback.js.map +1 -1
  103. package/dist/commands/routing.d.ts +1 -1
  104. package/dist/commands/routing.js +1 -1
  105. package/dist/commands/rules.d.ts +74 -0
  106. package/dist/commands/rules.d.ts.map +1 -0
  107. package/dist/commands/rules.js +283 -0
  108. package/dist/commands/rules.js.map +1 -0
  109. package/dist/commands/settings.d.ts +43 -0
  110. package/dist/commands/settings.d.ts.map +1 -0
  111. package/dist/commands/settings.js +108 -0
  112. package/dist/commands/settings.js.map +1 -0
  113. package/dist/commands/setup.d.ts +1 -1
  114. package/dist/commands/setup.js +1 -1
  115. package/dist/commands/siem.d.ts +53 -0
  116. package/dist/commands/siem.d.ts.map +1 -0
  117. package/dist/commands/siem.js +132 -0
  118. package/dist/commands/siem.js.map +1 -0
  119. package/dist/commands/skill.d.ts +5 -5
  120. package/dist/commands/skill.js +7 -7
  121. package/dist/commands/skill.js.map +1 -1
  122. package/dist/commands/status.d.ts +0 -1
  123. package/dist/commands/status.d.ts.map +1 -1
  124. package/dist/commands/status.js +2 -3
  125. package/dist/commands/status.js.map +1 -1
  126. package/dist/commands/syncContext.d.ts +0 -1
  127. package/dist/commands/syncContext.d.ts.map +1 -1
  128. package/dist/commands/syncContext.js +0 -1
  129. package/dist/commands/syncContext.js.map +1 -1
  130. package/dist/commands/team.d.ts +2 -2
  131. package/dist/commands/team.js +2 -2
  132. package/dist/commands/traces.d.ts +0 -3
  133. package/dist/commands/traces.d.ts.map +1 -1
  134. package/dist/commands/traces.js +0 -3
  135. package/dist/commands/traces.js.map +1 -1
  136. package/dist/commands/usage.d.ts +41 -0
  137. package/dist/commands/usage.d.ts.map +1 -0
  138. package/dist/commands/usage.js +129 -0
  139. package/dist/commands/usage.js.map +1 -0
  140. package/dist/commands/whoami.d.ts +0 -1
  141. package/dist/commands/whoami.d.ts.map +1 -1
  142. package/dist/commands/whoami.js +0 -1
  143. package/dist/commands/whoami.js.map +1 -1
  144. package/dist/config/keychain.d.ts +0 -1
  145. package/dist/config/keychain.d.ts.map +1 -1
  146. package/dist/config/keychain.js +0 -1
  147. package/dist/config/keychain.js.map +1 -1
  148. package/dist/config/paths.d.ts +0 -1
  149. package/dist/config/paths.d.ts.map +1 -1
  150. package/dist/config/paths.js +0 -1
  151. package/dist/config/paths.js.map +1 -1
  152. package/dist/config/store.d.ts +0 -1
  153. package/dist/config/store.d.ts.map +1 -1
  154. package/dist/config/store.js +0 -1
  155. package/dist/config/store.js.map +1 -1
  156. package/dist/harness/ag2.d.ts +1 -1
  157. package/dist/harness/ag2.js +1 -1
  158. package/dist/harness/agentFramework.d.ts +1 -1
  159. package/dist/harness/agentFramework.js +1 -1
  160. package/dist/harness/agenticOrchestrator.d.ts +1 -1
  161. package/dist/harness/agenticOrchestrator.js +2 -2
  162. package/dist/harness/agenticOrchestrator.js.map +1 -1
  163. package/dist/harness/agentsMd.d.ts +24 -0
  164. package/dist/harness/agentsMd.d.ts.map +1 -0
  165. package/dist/harness/agentsMd.js +28 -0
  166. package/dist/harness/agentsMd.js.map +1 -0
  167. package/dist/harness/aider.d.ts +3 -1
  168. package/dist/harness/aider.d.ts.map +1 -1
  169. package/dist/harness/aider.js +9 -7
  170. package/dist/harness/aider.js.map +1 -1
  171. package/dist/harness/antigravity.d.ts +23 -5
  172. package/dist/harness/antigravity.d.ts.map +1 -1
  173. package/dist/harness/antigravity.js +45 -55
  174. package/dist/harness/antigravity.js.map +1 -1
  175. package/dist/harness/autogen.d.ts +1 -1
  176. package/dist/harness/autogen.js +2 -2
  177. package/dist/harness/autogen.js.map +1 -1
  178. package/dist/harness/claudeCode.d.ts +22 -1
  179. package/dist/harness/claudeCode.d.ts.map +1 -1
  180. package/dist/harness/claudeCode.js +47 -3
  181. package/dist/harness/claudeCode.js.map +1 -1
  182. package/dist/harness/cline.d.ts.map +1 -1
  183. package/dist/harness/cline.js +14 -23
  184. package/dist/harness/cline.js.map +1 -1
  185. package/dist/harness/codex.d.ts +6 -1
  186. package/dist/harness/codex.d.ts.map +1 -1
  187. package/dist/harness/codex.js +23 -21
  188. package/dist/harness/codex.js.map +1 -1
  189. package/dist/harness/continue.d.ts +10 -4
  190. package/dist/harness/continue.d.ts.map +1 -1
  191. package/dist/harness/continue.js +22 -22
  192. package/dist/harness/continue.js.map +1 -1
  193. package/dist/harness/cursor.d.ts +5 -2
  194. package/dist/harness/cursor.d.ts.map +1 -1
  195. package/dist/harness/cursor.js +19 -23
  196. package/dist/harness/cursor.js.map +1 -1
  197. package/dist/harness/detector.d.ts +0 -1
  198. package/dist/harness/detector.d.ts.map +1 -1
  199. package/dist/harness/detector.js +0 -1
  200. package/dist/harness/detector.js.map +1 -1
  201. package/dist/harness/dsh.d.ts +5 -3
  202. package/dist/harness/dsh.d.ts.map +1 -1
  203. package/dist/harness/dsh.js +17 -29
  204. package/dist/harness/dsh.js.map +1 -1
  205. package/dist/harness/eve.d.ts +3 -4
  206. package/dist/harness/eve.d.ts.map +1 -1
  207. package/dist/harness/eve.js +3 -4
  208. package/dist/harness/eve.js.map +1 -1
  209. package/dist/harness/githubCopilot.d.ts +4 -1
  210. package/dist/harness/githubCopilot.d.ts.map +1 -1
  211. package/dist/harness/githubCopilot.js +12 -20
  212. package/dist/harness/githubCopilot.js.map +1 -1
  213. package/dist/harness/goose.d.ts +7 -3
  214. package/dist/harness/goose.d.ts.map +1 -1
  215. package/dist/harness/goose.js +18 -21
  216. package/dist/harness/goose.js.map +1 -1
  217. package/dist/harness/grok.d.ts +2 -2
  218. package/dist/harness/grok.d.ts.map +1 -1
  219. package/dist/harness/grok.js +13 -24
  220. package/dist/harness/grok.js.map +1 -1
  221. package/dist/harness/hermes.d.ts +6 -0
  222. package/dist/harness/hermes.d.ts.map +1 -1
  223. package/dist/harness/hermes.js +17 -16
  224. package/dist/harness/hermes.js.map +1 -1
  225. package/dist/harness/muse.d.ts +3 -7
  226. package/dist/harness/muse.d.ts.map +1 -1
  227. package/dist/harness/muse.js +15 -35
  228. package/dist/harness/muse.js.map +1 -1
  229. package/dist/harness/n8n.d.ts +13 -14
  230. package/dist/harness/n8n.d.ts.map +1 -1
  231. package/dist/harness/n8n.js +21 -181
  232. package/dist/harness/n8n.js.map +1 -1
  233. package/dist/harness/openWebUI.d.ts.map +1 -1
  234. package/dist/harness/openWebUI.js +5 -4
  235. package/dist/harness/openWebUI.js.map +1 -1
  236. package/dist/harness/openaiAgents.d.ts +1 -1
  237. package/dist/harness/openaiAgents.js +2 -2
  238. package/dist/harness/openaiAgents.js.map +1 -1
  239. package/dist/harness/openclaw.d.ts +8 -0
  240. package/dist/harness/openclaw.d.ts.map +1 -1
  241. package/dist/harness/openclaw.js +27 -12
  242. package/dist/harness/openclaw.js.map +1 -1
  243. package/dist/harness/opencode.d.ts +4 -5
  244. package/dist/harness/opencode.d.ts.map +1 -1
  245. package/dist/harness/opencode.js +15 -30
  246. package/dist/harness/opencode.js.map +1 -1
  247. package/dist/harness/openhands.d.ts +9 -3
  248. package/dist/harness/openhands.d.ts.map +1 -1
  249. package/dist/harness/openhands.js +30 -24
  250. package/dist/harness/openhands.js.map +1 -1
  251. package/dist/harness/pi.d.ts +7 -2
  252. package/dist/harness/pi.d.ts.map +1 -1
  253. package/dist/harness/pi.js +19 -18
  254. package/dist/harness/pi.js.map +1 -1
  255. package/dist/harness/rooCode.d.ts +12 -5
  256. package/dist/harness/rooCode.d.ts.map +1 -1
  257. package/dist/harness/rooCode.js +23 -39
  258. package/dist/harness/rooCode.js.map +1 -1
  259. package/dist/harness/rulesFiles.d.ts +53 -0
  260. package/dist/harness/rulesFiles.d.ts.map +1 -0
  261. package/dist/harness/rulesFiles.js +106 -0
  262. package/dist/harness/rulesFiles.js.map +1 -0
  263. package/dist/harness/smolagents.d.ts +2 -2
  264. package/dist/harness/smolagents.js +3 -3
  265. package/dist/harness/smolagents.js.map +1 -1
  266. package/dist/harness/types.d.ts +20 -6
  267. package/dist/harness/types.d.ts.map +1 -1
  268. package/dist/harness/types.js +1 -95
  269. package/dist/harness/types.js.map +1 -1
  270. package/dist/harness/windsurf.d.ts +6 -1
  271. package/dist/harness/windsurf.d.ts.map +1 -1
  272. package/dist/harness/windsurf.js +21 -24
  273. package/dist/harness/windsurf.js.map +1 -1
  274. package/dist/harness/xirp.d.ts +1 -2
  275. package/dist/harness/xirp.d.ts.map +1 -1
  276. package/dist/harness/xirp.js +2 -3
  277. package/dist/harness/xirp.js.map +1 -1
  278. package/dist/lib/api.d.ts +27 -1
  279. package/dist/lib/api.d.ts.map +1 -1
  280. package/dist/lib/api.js +55 -18
  281. package/dist/lib/api.js.map +1 -1
  282. package/dist/lib/ciscoScanner.d.ts +1 -1
  283. package/dist/lib/ciscoScanner.js +1 -1
  284. package/dist/lib/decisionsLogRefresh.d.ts.map +1 -1
  285. package/dist/lib/decisionsLogRefresh.js +6 -7
  286. package/dist/lib/decisionsLogRefresh.js.map +1 -1
  287. package/dist/lib/deviceReport.d.ts +15 -0
  288. package/dist/lib/deviceReport.d.ts.map +1 -1
  289. package/dist/lib/deviceReport.js +30 -0
  290. package/dist/lib/deviceReport.js.map +1 -1
  291. package/dist/lib/gitHooks.d.ts +0 -1
  292. package/dist/lib/gitHooks.d.ts.map +1 -1
  293. package/dist/lib/gitHooks.js +8 -9
  294. package/dist/lib/gitHooks.js.map +1 -1
  295. package/dist/lib/gracefulShutdown.d.ts +1 -1
  296. package/dist/lib/gracefulShutdown.js +1 -1
  297. package/dist/lib/hash.d.ts +0 -1
  298. package/dist/lib/hash.d.ts.map +1 -1
  299. package/dist/lib/hash.js +0 -1
  300. package/dist/lib/hash.js.map +1 -1
  301. package/dist/lib/inventory.d.ts +47 -0
  302. package/dist/lib/inventory.d.ts.map +1 -0
  303. package/dist/lib/inventory.js +106 -0
  304. package/dist/lib/inventory.js.map +1 -0
  305. package/dist/lib/logger.d.ts +0 -1
  306. package/dist/lib/logger.d.ts.map +1 -1
  307. package/dist/lib/logger.js +0 -1
  308. package/dist/lib/logger.js.map +1 -1
  309. package/dist/lib/mdmManifest.d.ts +30 -2
  310. package/dist/lib/mdmManifest.d.ts.map +1 -1
  311. package/dist/lib/mdmManifest.js +50 -2
  312. package/dist/lib/mdmManifest.js.map +1 -1
  313. package/dist/lib/onboarding.d.ts +0 -1
  314. package/dist/lib/onboarding.d.ts.map +1 -1
  315. package/dist/lib/onboarding.js +1 -2
  316. package/dist/lib/onboarding.js.map +1 -1
  317. package/dist/lib/policySnapshot.d.ts +3 -2
  318. package/dist/lib/policySnapshot.d.ts.map +1 -1
  319. package/dist/lib/policySnapshot.js +6 -3
  320. package/dist/lib/policySnapshot.js.map +1 -1
  321. package/dist/lib/process.d.ts +5 -1
  322. package/dist/lib/process.d.ts.map +1 -1
  323. package/dist/lib/process.js +13 -4
  324. package/dist/lib/process.js.map +1 -1
  325. package/dist/lib/providerProbe.d.ts +2 -2
  326. package/dist/lib/providerProbe.js +2 -2
  327. package/dist/lib/sandbox/firecracker.d.ts +3 -3
  328. package/dist/lib/sandbox/firecracker.js +3 -3
  329. package/dist/lib/sandbox/index.d.ts +2 -2
  330. package/dist/lib/sandbox/index.js +2 -2
  331. package/dist/lib/sandbox/oci.d.ts +1 -1
  332. package/dist/lib/sandbox/oci.js +1 -1
  333. package/dist/lib/sandbox/types.d.ts +1 -1
  334. package/dist/lib/sandbox/types.js +1 -1
  335. package/dist/lib/sopFrontMatter.d.ts +1 -1
  336. package/dist/lib/sopFrontMatter.js +1 -1
  337. package/package.json +6 -5
  338. package/resources/sandbox/Dockerfile +1 -1
  339. package/resources/sandbox/entrypoint.sh +4 -4
  340. package/resources/sandbox/firecracker-launch.sh +1 -1
  341. package/dist/harness/base.d.ts +0 -24
  342. package/dist/harness/base.d.ts.map +0 -1
  343. package/dist/harness/base.js +0 -74
  344. package/dist/harness/base.js.map +0 -1
package/dist/cli.js CHANGED
@@ -5,7 +5,6 @@
5
5
  * AI governance control plane for developer workspaces.
6
6
  * Provides harness detection, config sync, and workspace management.
7
7
  *
8
- * LLD #8 — Sync Daemon / CLI
9
8
  * HLD §3.14 — Real-Time State Mirroring
10
9
  *
11
10
  * @module
@@ -41,7 +40,7 @@ program
41
40
  const { runInit } = await import('./commands/init.js');
42
41
  await runInit(opts);
43
42
  });
44
- // ── Cohort setup wizard (LLD #70) ────────────────────────────────────────
43
+ // ── Cohort setup wizard ──────────────────────────────────────────────────
45
44
  program
46
45
  .command('setup')
47
46
  .description('Guided setup: detect harnesses, configure a provider credential, and verify it')
@@ -257,7 +256,7 @@ policyCmd
257
256
  });
258
257
  policyCmd
259
258
  .command('install')
260
- .description('Validate and install a compiled WASM rule into the local proxy rules dir')
259
+ .description('Validate and install a compiled WASM rule (native or Rego) into the local proxy rules dir')
261
260
  .requiredOption('--wasm <path>', 'Path to compiled WASM rule binary')
262
261
  .option('--name <name>', 'Rule name (defaults to the file name)')
263
262
  .option('--priority <NN>', 'Evaluation priority — lower runs first', '100')
@@ -283,7 +282,39 @@ policyCmd
283
282
  const { runPolicyReplay } = await import('./commands/policy.js');
284
283
  await runPolicyReplay(ruleId, opts);
285
284
  });
286
- // Policy Clause Ledger (LLD #71). `intutic policy` is the WASM loop and
285
+ // Rego policies as rules: compiled with OPA and packaged with the metadata
286
+ // the proxies read (`intutic rules build`), tested through the same host
287
+ // (`intutic rules test`). Installing and uploading are the same as for any rule.
288
+ const rulesCmd = program
289
+ .command('rules')
290
+ .description('Build and test Rego policies as Intutic rules');
291
+ rulesCmd
292
+ .command('build')
293
+ .description('Compile Rego to a rule with OPA (opa build -t wasm) and package it with its entrypoint and risk tier.\n' +
294
+ '\n' +
295
+ ' Needs the opa binary on the PATH, or INTUTIC_OPA_BIN. Refuses a policy that\n' +
296
+ ' needs a builtin Intutic does not provide, naming it.')
297
+ .requiredOption('--rego <path>', 'Rego file or directory')
298
+ .requiredOption('--entrypoint <package/rule>', 'The rule to evaluate, e.g. intutic/shell/deny')
299
+ .option('--risk-tier <tier>', 'Default risk tier for its decisions: low | medium | high | critical')
300
+ .option('--out <path>', 'Output .wasm path (default: build/<entrypoint>.wasm)')
301
+ .action(async (opts) => {
302
+ const { runRulesBuild } = await import('./commands/rules.js');
303
+ await runRulesBuild(opts);
304
+ });
305
+ rulesCmd
306
+ .command('test <module>')
307
+ .description('Evaluate a Rego rule against sample inputs locally, through the same host the proxies use.\n' +
308
+ '\n' +
309
+ ' Each --input file holds one input document, or an array of\n' +
310
+ ' {"name", "input", "expect": "allow|deny|hold|reask"} cases. Exits 1 when a\n' +
311
+ ' case gets a decision other than the one it expects.')
312
+ .requiredOption('--input <file...>', 'JSON file(s) of inputs or cases')
313
+ .action(async (module, opts) => {
314
+ const { runRulesTest } = await import('./commands/rules.js');
315
+ await runRulesTest(module, opts);
316
+ });
317
+ // Policy Clause Ledger. `intutic policy` is the WASM loop and
287
318
  // `intutic sops` is files on disk; this namespace is the cited guardrails
288
319
  // extracted from policy documents and their shadow -> promote lifecycle.
289
320
  const guardrailsCmd = program
@@ -369,6 +400,7 @@ guardrailsCmd
369
400
  .description('List guardrails with their status and shadow evidence')
370
401
  .option('--status <status>', 'PROPOSED | SHADOW | ENFORCING | REJECTED | RETIRED')
371
402
  .option('--target <target>', 'hook_rule | sop_front_matter | wasm_rule | workspace_setting')
403
+ .option('--provenance <provenance>', 'extracted | authored')
372
404
  .option('--doc <docId>', 'Only guardrails cited from this document')
373
405
  .option('--limit <n>', 'Max rows (default 50, capped at 200)')
374
406
  .option('--json', 'Output as JSON')
@@ -386,6 +418,51 @@ guardrailsCmd
386
418
  const { runGuardrailsShow } = await import('./commands/guardrails.js');
387
419
  await runGuardrailsShow(guardrailId, opts);
388
420
  });
421
+ /** The IR flags `guardrails create` and `guardrails update` share; a file (`--file`) is the alternative. */
422
+ function guardrailIrOptions(cmd) {
423
+ return cmd
424
+ .option('--file <path>', 'YAML or JSON: a bare IR, or { name, description, ir }')
425
+ .option('--name <name>', 'One-line label (at most 80 characters)')
426
+ .option('--description <text>', 'What the rule is for; shown where an extracted guardrail shows its quote')
427
+ .option('--kind <kind>', 'hook_rule | deny_tools | review_before | requires_before | forbid_after | max_calls | forbid_with | wasm_predicate | allowed_models | egress_allow')
428
+ .option('--title <title>', 'hook_rule, wasm_predicate: the title in the block message')
429
+ .option('--tools <list>', 'hook_rule, deny_tools: comma-separated tool names')
430
+ .option('--tokens <list>', 'review_before: comma-separated tool or action tokens')
431
+ .option('--arg-contains <literal>', 'hook_rule: fire only when the input contains this (repeatable)', (v, prev = []) => [...prev, v])
432
+ .option('--arg-not-contains <literal>', 'hook_rule: fire only when the input does not contain this (repeatable)', (v, prev = []) => [...prev, v])
433
+ .option('--first <token>', 'requires_before, forbid_after: the first token')
434
+ .option('--then <token>', 'requires_before, forbid_after: the second token')
435
+ .option('--token <token>', 'max_calls, forbid_with: the token')
436
+ .option('--limit <n>', 'max_calls: the most calls allowed')
437
+ .option('--taint <taint>', 'forbid_with: secrets() | pii()')
438
+ .option('--roles <list>', 'Comma-separated roles the rule applies to (default: everyone)')
439
+ .option('--models <list>', 'allowed_models: comma-separated model ids')
440
+ .option('--hosts <list>', 'egress_allow: comma-separated hosts, suffixes or IPv4 CIDRs')
441
+ .option('--rationale <text>', 'wasm_predicate: why it re-asks')
442
+ .option('--predicate <json>', 'wasm_predicate: the predicate as JSON')
443
+ .option('--json', 'Output as JSON')
444
+ .option('--dev', 'Use local control plane (http://localhost:3001)');
445
+ }
446
+ guardrailIrOptions(guardrailsCmd.command('create').description('Author a guardrail directly: the same IR and checks as an extracted one, created PROPOSED')).action(async (opts) => {
447
+ const { runGuardrailsCreate } = await import('./commands/guardrails.js');
448
+ await runGuardrailsCreate(opts);
449
+ });
450
+ guardrailIrOptions(guardrailsCmd
451
+ .command('update <guardrailId>')
452
+ .description('Edit an authored guardrail: a name or description in place; a changed IR creates the next version, PROPOSED with no evidence')
453
+ .option('--clear-description', 'Remove the description')).action(async (guardrailId, opts) => {
454
+ const { runGuardrailsUpdate } = await import('./commands/guardrails.js');
455
+ await runGuardrailsUpdate(guardrailId, opts);
456
+ });
457
+ guardrailsCmd
458
+ .command('delete <guardrailId>')
459
+ .description('Retire an authored guardrail and undo what it wrote; its history is kept')
460
+ .option('--json', 'Output as JSON')
461
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
462
+ .action(async (guardrailId, opts) => {
463
+ const { runGuardrailsDelete } = await import('./commands/guardrails.js');
464
+ await runGuardrailsDelete(guardrailId, opts);
465
+ });
389
466
  guardrailsCmd
390
467
  .command('approve-shadow <guardrailId>')
391
468
  .description('Ship a proposed guardrail in shadow: it reports, never blocks')
@@ -501,7 +578,7 @@ program
501
578
  const { runStart } = await import('./commands/start.js');
502
579
  await runStart(opts);
503
580
  });
504
- // L2 mandatory egress firewall (LLD #63 §5). Makes the governing proxy
581
+ // L2 mandatory egress firewall. Makes the governing proxy
505
582
  // non-optional: default-deny host egress to everything except the proxy, DNS,
506
583
  // and declared infra. apply/remove need root; generate/status do not.
507
584
  const enforceCmd = program
@@ -602,8 +679,8 @@ program
602
679
  });
603
680
  program
604
681
  .command('decisions-log-refresh')
605
- .description('One-shot refresh of the governed decisions log (.intutic/DECISIONS.md + the claude-code ' +
606
- 'harness config section) — no-ops if decisionsLogEnabled is off. Invoked by the optional ' +
682
+ .description('One-shot refresh of the governed decisions log (.intutic/DECISIONS.md, and the recent ' +
683
+ 'entries in each governed harness\'s instructions file) — no-ops if decisionsLogEnabled is off. Invoked by the optional ' +
607
684
  'post-merge Git hook `intutic init` installs; safe to run manually.')
608
685
  .action(async () => {
609
686
  const { refreshDecisionsLog } = await import('./lib/decisionsLogRefresh.js');
@@ -617,8 +694,8 @@ program
617
694
  .command('exec')
618
695
  .description('Execute a command wrapped with Intutic proxy environment variables')
619
696
  .argument('[command...]', 'Command and arguments to execute (e.g. -- claude)')
620
- // Run the agent inside an isolated sandbox whose ONLY egress is the proxy
621
- // (LLD #63 §6): cap-drop, no-new-privileges, read-only rootfs, resource caps,
697
+ // Run the agent inside an isolated sandbox whose ONLY egress is the proxy:
698
+ // cap-drop, no-new-privileges, read-only rootfs, resource caps,
622
699
  // and a default-deny egress firewall the agent cannot undo.
623
700
  .option('--sandbox [kind]', 'Run the agent in an isolated sandbox (kind: oci | firecracker; default oci)')
624
701
  .option('--sandbox-image <image>', 'Sandbox image (must contain the agent + nftables + capsh); the default is built locally on first use', DEFAULT_SANDBOX_IMAGE)
@@ -874,8 +951,8 @@ daemon
874
951
  .option('--mcp', 'Show the MCP proxy daemon instead of the sync-daemon')
875
952
  .action(async (opts) => {
876
953
  // `mcpDaemonStatus` was exported and never called by any command until the
877
- // reachability test widened to the status/stop/start verbs (TD-153's
878
- // shape, one more time).
954
+ // reachability test widened to the status/stop/start verbs (the same
955
+ // exported-but-unreachable shape, one more time).
879
956
  const { daemonStatus, proxyServiceStatus, mcpDaemonStatus } = await import('./commands/install-daemon.js');
880
957
  await (opts.proxy ? proxyServiceStatus() : opts.mcp ? mcpDaemonStatus() : daemonStatus());
881
958
  });
@@ -886,8 +963,8 @@ daemon
886
963
  .option('--mcp', 'Stop the MCP proxy daemon instead of the sync-daemon')
887
964
  .action(async (opts) => {
888
965
  // `mcpDaemonStop` was exported and never called by any command until the
889
- // reachability test widened to the status/stop/start verbs (TD-153's
890
- // shape, one more time).
966
+ // reachability test widened to the status/stop/start verbs (the same
967
+ // exported-but-unreachable shape, one more time).
891
968
  const { daemonStop, proxyServiceStop, mcpDaemonStop } = await import('./commands/install-daemon.js');
892
969
  await (opts.proxy ? proxyServiceStop() : opts.mcp ? mcpDaemonStop() : daemonStop());
893
970
  });
@@ -898,8 +975,8 @@ daemon
898
975
  .option('--mcp', 'Start the MCP proxy daemon instead of the sync-daemon')
899
976
  .action(async (opts) => {
900
977
  // `mcpDaemonStart` was exported and never called by any command until the
901
- // reachability test widened to the status/stop/start verbs (TD-153's
902
- // shape, one more time).
978
+ // reachability test widened to the status/stop/start verbs (the same
979
+ // exported-but-unreachable shape, one more time).
903
980
  const { daemonStart, proxyServiceStart, mcpDaemonStart } = await import('./commands/install-daemon.js');
904
981
  await (opts.proxy ? proxyServiceStart() : opts.mcp ? mcpDaemonStart() : daemonStart());
905
982
  });
@@ -1022,7 +1099,7 @@ decisionCmd
1022
1099
  const { runDecisionReject } = await import('./commands/decision.js');
1023
1100
  await runDecisionReject(holdId, opts);
1024
1101
  });
1025
- // ── Gateway commands (LLD #66) ───────────────────────────────────────────
1102
+ // ── Gateway commands ─────────────────────────────────────────────────────
1026
1103
  //
1027
1104
  // Self-hosted gateway registration/management. Previously reachable only by
1028
1105
  // hand-written curl against services/control-plane/src/routes/gateways.ts —
@@ -1080,6 +1157,15 @@ gatewayCmd
1080
1157
  const gatewayConfigCmd = gatewayCmd
1081
1158
  .command('config')
1082
1159
  .description('Manage a gateway\'s remote config (requireVk, requireProvisionedKey)');
1160
+ gatewayConfigCmd
1161
+ .command('get <gateway_id>')
1162
+ .description('Show the config values set on a gateway and their version')
1163
+ .option('--json', 'Output as JSON')
1164
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1165
+ .action(async (gatewayId, opts) => {
1166
+ const { runGatewayConfigGet } = await import('./commands/gateway.js');
1167
+ await runGatewayConfigGet(gatewayId, opts);
1168
+ });
1083
1169
  gatewayConfigCmd
1084
1170
  .command('set <gateway_id>')
1085
1171
  .description('Update one or both config flags on a gateway')
@@ -1112,7 +1198,7 @@ gatewayCmd
1112
1198
  const { runGatewayResolve } = await import('./commands/gateway.js');
1113
1199
  await runGatewayResolve(opts);
1114
1200
  });
1115
- // ── Provider credentials (LLD #64 §4, LLD #67) ───────────────────────────
1201
+ // ── Provider credentials ─────────────────────────────────────────────────
1116
1202
  //
1117
1203
  // Provision a workspace's own upstream provider keys — the BYO-key wizard's
1118
1204
  // API, previously dashboard-only. See commands/credentials.ts's module doc.
@@ -1146,7 +1232,7 @@ credentialsCmd
1146
1232
  const { runCredentialsUnset } = await import('./commands/credentials.js');
1147
1233
  await runCredentialsUnset(provider, opts);
1148
1234
  });
1149
- // ── DCT Token Attenuation (LLD #19 §2.1, HLD §5.6 Patent Family A) ───────
1235
+ // ── DCT Token Attenuation (HLD §5.6 Patent Family A) ─────────────────────
1150
1236
  //
1151
1237
  // "CLI mints, dashboard audits": this is the mint/inspect half. See
1152
1238
  // commands/attenuate.ts's module doc.
@@ -1169,7 +1255,7 @@ attenuateCmd
1169
1255
  const { runAttenuateChain } = await import('./commands/attenuate.js');
1170
1256
  await runAttenuateChain(chainId, opts);
1171
1257
  });
1172
- // ── Org signup + team management (LLD #65) ───────────────────────────────
1258
+ // ── Org signup + team management ─────────────────────────────────────────
1173
1259
  const orgCmd = program
1174
1260
  .command('org')
1175
1261
  .description('Create and manage orgs');
@@ -1228,5 +1314,381 @@ teamCmd
1228
1314
  const { runTeamCreateWorkspace } = await import('./commands/team.js');
1229
1315
  await runTeamCreateWorkspace(teamId, opts);
1230
1316
  });
1317
+ // ── Operator commands ────────────────────────────────────────────────────
1318
+ //
1319
+ // Workspace settings, the MCP server registry, notification rules, SIEM
1320
+ // destinations and the fleet reports, each over its existing control-plane
1321
+ // route. Previously dashboard-only. See commands/apiCommand.ts for the shape
1322
+ // they share.
1323
+ const settingsCmd = program
1324
+ .command('settings')
1325
+ .description('Read and change workspace settings (MCP policy, budgets, group policy, config content upload, ...)');
1326
+ settingsCmd
1327
+ .command('get [key]')
1328
+ .description('Print every workspace setting, or one')
1329
+ .option('--json', 'Output as JSON')
1330
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1331
+ .action(async (key, opts) => {
1332
+ const { runSettingsGet } = await import('./commands/settings.js');
1333
+ await runSettingsGet(key, opts);
1334
+ });
1335
+ settingsCmd
1336
+ .command('set <key> [value]')
1337
+ .description('Change one setting; the value is JSON when it parses as JSON, else a string')
1338
+ .option('--file <path>', 'Read the value from a JSON file instead')
1339
+ .option('--json', 'Output as JSON')
1340
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1341
+ .action(async (key, value, opts) => {
1342
+ const { runSettingsSet } = await import('./commands/settings.js');
1343
+ await runSettingsSet(key, value, opts);
1344
+ });
1345
+ const mcpCmd = program
1346
+ .command('mcp')
1347
+ .description('Review the MCP servers the workspace\'s MCP proxies have seen, and decide on them');
1348
+ mcpCmd
1349
+ .command('list')
1350
+ .description('Every MCP server seen, its status and tools, and the registry\'s default policy')
1351
+ .option('--json', 'Output as JSON')
1352
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1353
+ .action(async (opts) => {
1354
+ const { runMcpList } = await import('./commands/mcp.js');
1355
+ await runMcpList(opts);
1356
+ });
1357
+ for (const [action, desc] of [
1358
+ ['approve', 'Approve an MCP server; MCP proxies let it run'],
1359
+ ['block', 'Block an MCP server; MCP proxies refuse it'],
1360
+ ['reset', 'Return an MCP server to the approval queue'],
1361
+ ]) {
1362
+ mcpCmd
1363
+ .command(`${action} <server_id>`)
1364
+ .description(desc)
1365
+ .option('--json', 'Output as JSON')
1366
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1367
+ .action(async (serverId, opts) => {
1368
+ const { runMcpDecide } = await import('./commands/mcp.js');
1369
+ await runMcpDecide(action, serverId, opts);
1370
+ });
1371
+ }
1372
+ for (const [action, enabled, desc] of [
1373
+ ['enable-tool', true, 'Switch one tool of an MCP server back on'],
1374
+ ['disable-tool', false, 'Switch one tool of an MCP server off; MCP proxies refuse calls to it'],
1375
+ ]) {
1376
+ mcpCmd
1377
+ .command(`${action} <server_id> <tool>`)
1378
+ .description(desc)
1379
+ .option('--json', 'Output as JSON')
1380
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1381
+ .action(async (serverId, tool, opts) => {
1382
+ const { runMcpTool } = await import('./commands/mcp.js');
1383
+ await runMcpTool(serverId, tool, enabled, opts);
1384
+ });
1385
+ }
1386
+ const notificationsCmd = program
1387
+ .command('notifications')
1388
+ .description('Manage notification rules: which events go to Slack, email, a webhook or PagerDuty');
1389
+ function ruleOptions(cmd) {
1390
+ return cmd
1391
+ .option('--slack-channel <id>', 'Slack channel ID, for the slack channel')
1392
+ .option('--email <addresses>', 'Comma-separated recipients (up to 20), for the email channel')
1393
+ .option('--webhook-url <url>', 'HTTPS URL, for the webhook channel')
1394
+ .option('--pagerduty-key <key>', 'Routing key, for the pagerduty channel')
1395
+ .option('--severity <list>', 'Only events of these comma-separated severities')
1396
+ .option('--harness <list>', 'Only events from these comma-separated harnesses')
1397
+ .option('--user <ids>', 'Only events from these comma-separated user ids')
1398
+ .option('--cooldown <minutes>', 'Minimum minutes between two notifications of this rule (1-1440)')
1399
+ .option('--json', 'Output as JSON')
1400
+ .option('--dev', 'Use local control plane (http://localhost:3001)');
1401
+ }
1402
+ notificationsCmd
1403
+ .command('list')
1404
+ .description('List notification rules')
1405
+ .option('--json', 'Output as JSON')
1406
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1407
+ .action(async (opts) => {
1408
+ const { runNotificationsList } = await import('./commands/notifications.js');
1409
+ await runNotificationsList(opts);
1410
+ });
1411
+ ruleOptions(notificationsCmd
1412
+ .command('create')
1413
+ .description('Create a notification rule; a webhook rule prints its signing secret once')
1414
+ .requiredOption('--event <type>', 'Event type, e.g. incident.created or mcp.server.candidate')
1415
+ .requiredOption('--channel <channel>', 'slack, email, webhook or pagerduty')
1416
+ .option('--disabled', 'Create the rule switched off')).action(async (opts) => {
1417
+ const { runNotificationsCreate } = await import('./commands/notifications.js');
1418
+ await runNotificationsCreate(opts);
1419
+ });
1420
+ ruleOptions(notificationsCmd
1421
+ .command('update <rule_id>')
1422
+ .description('Change a notification rule; only the fields given change')
1423
+ .option('--event <type>', 'Event type')
1424
+ .option('--channel <channel>', 'slack, email, webhook or pagerduty')
1425
+ .option('--enable', 'Switch the rule on')
1426
+ .option('--disable', 'Switch the rule off')).action(async (ruleId, opts) => {
1427
+ const { runNotificationsUpdate } = await import('./commands/notifications.js');
1428
+ await runNotificationsUpdate(ruleId, opts);
1429
+ });
1430
+ notificationsCmd
1431
+ .command('delete <rule_id>')
1432
+ .description('Delete a notification rule')
1433
+ .option('--json', 'Output as JSON')
1434
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1435
+ .action(async (ruleId, opts) => {
1436
+ const { runNotificationsDelete } = await import('./commands/notifications.js');
1437
+ await runNotificationsDelete(ruleId, opts);
1438
+ });
1439
+ notificationsCmd
1440
+ .command('rotate-secret <rule_id>')
1441
+ .description('Replace a webhook rule\'s signing secret and print the new one once')
1442
+ .option('--json', 'Output as JSON')
1443
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1444
+ .action(async (ruleId, opts) => {
1445
+ const { runNotificationsRotateSecret } = await import('./commands/notifications.js');
1446
+ await runNotificationsRotateSecret(ruleId, opts);
1447
+ });
1448
+ const siemCmd = program
1449
+ .command('siem')
1450
+ .description('Manage SIEM export destinations and the event sources each receives');
1451
+ function destinationOptions(cmd) {
1452
+ return cmd
1453
+ .option('--sources <list>', 'Comma-separated event sources this destination receives (see `intutic siem sources`)')
1454
+ .option('--default-sources', 'Receive the default set: every source except the opt-in ones')
1455
+ .option('--batch-size <n>', 'Events per delivery batch')
1456
+ .option('--flush-interval-ms <ms>', 'Longest wait before a partial batch is sent')
1457
+ .option('--json', 'Output as JSON')
1458
+ .option('--dev', 'Use local control plane (http://localhost:3001)');
1459
+ }
1460
+ siemCmd
1461
+ .command('list')
1462
+ .description('List SIEM destinations (credentials masked)')
1463
+ .option('--json', 'Output as JSON')
1464
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1465
+ .action(async (opts) => {
1466
+ const { runSiemList } = await import('./commands/siem.js');
1467
+ await runSiemList(opts);
1468
+ });
1469
+ siemCmd
1470
+ .command('show <destination_id>')
1471
+ .description('Show one SIEM destination (credentials masked)')
1472
+ .option('--json', 'Output as JSON')
1473
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1474
+ .action(async (destinationId, opts) => {
1475
+ const { runSiemShow } = await import('./commands/siem.js');
1476
+ await runSiemShow(destinationId, opts);
1477
+ });
1478
+ siemCmd
1479
+ .command('sources')
1480
+ .description('List the event sources a destination can receive, and which are opt-in')
1481
+ .option('--json', 'Output as JSON')
1482
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1483
+ .action(async (opts) => {
1484
+ const { runSiemSources } = await import('./commands/siem.js');
1485
+ await runSiemSources(opts);
1486
+ });
1487
+ destinationOptions(siemCmd
1488
+ .command('create')
1489
+ .description('Create a SIEM destination; a webhook destination prints its signing secret once')
1490
+ .requiredOption('--name <name>', 'Display name')
1491
+ .requiredOption('--type <adapter>', 'syslog_cef, webhook_https, splunk_hec, datadog_logs, gcs or s3')
1492
+ .requiredOption('--config <path>', 'JSON file with the adapter settings and credentials')).action(async (opts) => {
1493
+ const { runSiemCreate } = await import('./commands/siem.js');
1494
+ await runSiemCreate(opts);
1495
+ });
1496
+ destinationOptions(siemCmd
1497
+ .command('update <destination_id>')
1498
+ .description('Change a SIEM destination; only the fields given change')
1499
+ .option('--name <name>', 'Display name')
1500
+ .option('--config <path>', 'JSON file with the new adapter settings; a secret left out or left masked keeps its stored value')
1501
+ .option('--enable', 'Turn a deactivated destination back on')).action(async (destinationId, opts) => {
1502
+ const { runSiemUpdate } = await import('./commands/siem.js');
1503
+ await runSiemUpdate(destinationId, opts);
1504
+ });
1505
+ siemCmd
1506
+ .command('delete <destination_id>')
1507
+ .description('Deactivate a SIEM destination; it stops receiving events and stays listed')
1508
+ .option('--json', 'Output as JSON')
1509
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1510
+ .action(async (destinationId, opts) => {
1511
+ const { runSiemDelete } = await import('./commands/siem.js');
1512
+ await runSiemDelete(destinationId, opts);
1513
+ });
1514
+ siemCmd
1515
+ .command('rotate-secret <destination_id>')
1516
+ .description('Replace a webhook destination\'s signing secret and print the new one once')
1517
+ .option('--json', 'Output as JSON')
1518
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1519
+ .action(async (destinationId, opts) => {
1520
+ const { runSiemRotateSecret } = await import('./commands/siem.js');
1521
+ await runSiemRotateSecret(destinationId, opts);
1522
+ });
1523
+ const complianceCmd = program
1524
+ .command('compliance')
1525
+ .description('Compliance framework reports and the evidence archive');
1526
+ complianceCmd
1527
+ .command('coverage <framework_id>')
1528
+ .description('Coverage of eu_ai_act, iso_42001, nist_ai_rmf or mitre_atlas from the latest probe results')
1529
+ .option('--format <format>', 'Download the report: json, md, csv or pdf')
1530
+ .option('--out <path>', 'Write the report to this file instead of stdout')
1531
+ .option('--json', 'Output as JSON')
1532
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1533
+ .action(async (frameworkId, opts) => {
1534
+ const { runComplianceCoverage } = await import('./commands/compliance.js');
1535
+ await runComplianceCoverage(frameworkId, opts);
1536
+ });
1537
+ complianceCmd
1538
+ .command('collect')
1539
+ .description('Run a fresh evidence collection and seal it into an archive (OWNER, ADMIN)')
1540
+ .option('--from <date>', 'Start of the evidence period, ISO 8601 (default: 90 days before --to)')
1541
+ .option('--to <date>', 'End of the evidence period, ISO 8601 (default: now)')
1542
+ .option('--out <path>', 'Also write the archive to this file')
1543
+ .option('--json', 'Output as JSON')
1544
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1545
+ .action(async (opts) => {
1546
+ const { runComplianceCollect } = await import('./commands/compliance.js');
1547
+ await runComplianceCollect(opts);
1548
+ });
1549
+ complianceCmd
1550
+ .command('download <run_id>')
1551
+ .description('Download a stored evidence archive (OWNER, ADMIN)')
1552
+ .option('--out <path>', 'Write the archive to this file instead of stdout')
1553
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1554
+ .action(async (runId, opts) => {
1555
+ const { runComplianceDownload } = await import('./commands/compliance.js');
1556
+ await runComplianceDownload(runId, opts);
1557
+ });
1558
+ complianceCmd
1559
+ .command('verify <file>')
1560
+ .description('Check an evidence archive\'s hashes and signature offline')
1561
+ .option('--jwks <path>', 'The published signing keys, saved from /.well-known/intutic-trace-signing.json (default: fetch them)')
1562
+ .option('--json', 'Output as JSON')
1563
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1564
+ .action(async (file, opts) => {
1565
+ const { runComplianceVerify } = await import('./commands/compliance.js');
1566
+ await runComplianceVerify(file, opts);
1567
+ });
1568
+ const usageCmd = program
1569
+ .command('usage')
1570
+ .description('LLM usage across the fleet, by member, team, branch, commit or pull request');
1571
+ for (const [view, handler, desc] of [
1572
+ ['members', 'runUsageMembers', 'Usage per member'],
1573
+ ['teams', 'runUsageTeams', 'Usage per team (SCIM group)'],
1574
+ ['branches', 'runUsageBranches', 'Usage per repository and branch'],
1575
+ ['commits', 'runUsageCommits', 'Usage per HEAD commit'],
1576
+ ]) {
1577
+ usageCmd
1578
+ .command(view)
1579
+ .description(desc)
1580
+ .option('--period <period>', 'daily (today) or monthly (this month)', 'monthly')
1581
+ .option('--json', 'Output as JSON')
1582
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1583
+ .action(async (opts) => {
1584
+ const usage = await import('./commands/usage.js');
1585
+ await usage[handler](opts);
1586
+ });
1587
+ }
1588
+ usageCmd
1589
+ .command('pull-requests')
1590
+ .description('Usage per GitHub pull request')
1591
+ .option('--period <period>', 'daily (today) or monthly (this month)', 'monthly')
1592
+ .option('--refresh', 'Look the branches up on GitHub first (OWNER, ADMIN, EM)')
1593
+ .option('--json', 'Output as JSON')
1594
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1595
+ .action(async (opts) => {
1596
+ const { runUsagePullRequests } = await import('./commands/usage.js');
1597
+ await runUsagePullRequests(opts);
1598
+ });
1599
+ const githubWebhookCmd = program
1600
+ .command('github')
1601
+ .description('GitHub integration for cost per pull request')
1602
+ .command('webhook')
1603
+ .description('The pull-request webhook: payload URL and signing secret');
1604
+ githubWebhookCmd
1605
+ .command('show')
1606
+ .description('Show the payload URL and when the secret was made')
1607
+ .option('--json', 'Output as JSON')
1608
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1609
+ .action(async (opts) => {
1610
+ const { runGithubWebhookShow } = await import('./commands/github.js');
1611
+ await runGithubWebhookShow(opts);
1612
+ });
1613
+ githubWebhookCmd
1614
+ .command('rotate-secret')
1615
+ .description('Make the webhook, or replace its secret (printed once)')
1616
+ .option('--json', 'Output as JSON')
1617
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1618
+ .action(async (opts) => {
1619
+ const { runGithubWebhookRotateSecret } = await import('./commands/github.js');
1620
+ await runGithubWebhookRotateSecret(opts);
1621
+ });
1622
+ const inventoryCmd = program
1623
+ .command('inventory')
1624
+ .description('AI harnesses, MCP servers and skills on connected developer machines, governed or not');
1625
+ inventoryCmd
1626
+ .command('summary')
1627
+ .description('Counts of machines, harnesses, MCP servers and skills, and how many are ungoverned')
1628
+ .option('--json', 'Output as JSON')
1629
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1630
+ .action(async (opts) => {
1631
+ const { runInventorySummary } = await import('./commands/inventory.js');
1632
+ await runInventorySummary(opts);
1633
+ });
1634
+ inventoryCmd
1635
+ .command('devices')
1636
+ .description('Every machine that reports, with its id (what --device takes), counts and last report')
1637
+ .option('--json', 'Output as JSON')
1638
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1639
+ .action(async (opts) => {
1640
+ const { runInventoryDevices } = await import('./commands/inventory.js');
1641
+ await runInventoryDevices(opts);
1642
+ });
1643
+ for (const [view, handler, desc] of [
1644
+ ['harnesses', 'runInventoryHarnesses', 'Harnesses by machine, with gate state and status'],
1645
+ ['mcp-servers', 'runInventoryMcpServers', 'MCP servers by machine, wrapped by the MCP proxy or not'],
1646
+ ]) {
1647
+ inventoryCmd
1648
+ .command(view)
1649
+ .description(desc)
1650
+ .option('--status <status>', 'Only rows with this status')
1651
+ .option('--harness <harness>', 'Only rows for this harness')
1652
+ .option('--device <device_id>', 'Only rows from this machine')
1653
+ .option('--search <text>', 'Only rows whose name or hostname contains this text')
1654
+ .option('--csv', 'Download as CSV, the same file the dashboard exports')
1655
+ .option('--out <path>', 'With --csv: write to this file instead of stdout')
1656
+ .option('--json', 'Output as JSON')
1657
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1658
+ .action(async (opts) => {
1659
+ const inventory = await import('./commands/inventory.js');
1660
+ await inventory[handler](opts);
1661
+ });
1662
+ }
1663
+ inventoryCmd
1664
+ .command('skills')
1665
+ .description('Skill bundles by machine, with their content scan result')
1666
+ .option('--device <device_id>', 'Only rows from this machine')
1667
+ .option('--search <text>', 'Only rows whose name or hostname contains this text')
1668
+ .option('--json', 'Output as JSON')
1669
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1670
+ .action(async (opts) => {
1671
+ const { runInventorySkills } = await import('./commands/inventory.js');
1672
+ await runInventorySkills(opts);
1673
+ });
1674
+ inventoryCmd
1675
+ .command('disconnects')
1676
+ .description('Machines that ran `intutic disconnect`, newest first: what they disconnected, who and when')
1677
+ .option('--limit <n>', 'At most this many (default 100, at most 500)')
1678
+ .option('--json', 'Output as JSON')
1679
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1680
+ .action(async (opts) => {
1681
+ const { runInventoryDisconnects } = await import('./commands/inventory.js');
1682
+ await runInventoryDisconnects(opts);
1683
+ });
1684
+ program
1685
+ .command('gate-liveness')
1686
+ .description('Whether each installed harness\'s gate is reporting, and any open silent-gate alert')
1687
+ .option('--json', 'Output as JSON')
1688
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1689
+ .action(async (opts) => {
1690
+ const { runGateLiveness } = await import('./commands/gateLiveness.js');
1691
+ await runGateLiveness(opts);
1692
+ });
1231
1693
  program.parse();
1232
1694
  //# sourceMappingURL=cli.js.map