@intutic/cli 2.2.0 → 2.4.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 (356) 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 +582 -21
  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/budgetLimits.d.ts +70 -0
  15. package/dist/commands/budgetLimits.d.ts.map +1 -0
  16. package/dist/commands/budgetLimits.js +223 -0
  17. package/dist/commands/budgetLimits.js.map +1 -0
  18. package/dist/commands/compliance.d.ts +122 -0
  19. package/dist/commands/compliance.d.ts.map +1 -0
  20. package/dist/commands/compliance.js +278 -0
  21. package/dist/commands/compliance.js.map +1 -0
  22. package/dist/commands/connect.d.ts +26 -1
  23. package/dist/commands/connect.d.ts.map +1 -1
  24. package/dist/commands/connect.js +109 -51
  25. package/dist/commands/connect.js.map +1 -1
  26. package/dist/commands/credentials.d.ts +6 -2
  27. package/dist/commands/credentials.d.ts.map +1 -1
  28. package/dist/commands/credentials.js +99 -10
  29. package/dist/commands/credentials.js.map +1 -1
  30. package/dist/commands/decision.d.ts +4 -4
  31. package/dist/commands/decision.js +4 -4
  32. package/dist/commands/disconnect.d.ts +4 -0
  33. package/dist/commands/disconnect.d.ts.map +1 -1
  34. package/dist/commands/disconnect.js +17 -3
  35. package/dist/commands/disconnect.js.map +1 -1
  36. package/dist/commands/doctor.d.ts +0 -1
  37. package/dist/commands/doctor.d.ts.map +1 -1
  38. package/dist/commands/doctor.js +0 -1
  39. package/dist/commands/doctor.js.map +1 -1
  40. package/dist/commands/enforce.d.ts +1 -1
  41. package/dist/commands/enforce.js +1 -1
  42. package/dist/commands/enterprise.d.ts +3 -2
  43. package/dist/commands/enterprise.d.ts.map +1 -1
  44. package/dist/commands/enterprise.js +11 -3
  45. package/dist/commands/enterprise.js.map +1 -1
  46. package/dist/commands/env.js +1 -1
  47. package/dist/commands/exec.d.ts +2 -3
  48. package/dist/commands/exec.d.ts.map +1 -1
  49. package/dist/commands/exec.js +4 -5
  50. package/dist/commands/exec.js.map +1 -1
  51. package/dist/commands/gateLiveness.d.ts +15 -0
  52. package/dist/commands/gateLiveness.d.ts.map +1 -0
  53. package/dist/commands/gateLiveness.js +34 -0
  54. package/dist/commands/gateLiveness.js.map +1 -0
  55. package/dist/commands/gateway.d.ts +14 -4
  56. package/dist/commands/gateway.d.ts.map +1 -1
  57. package/dist/commands/gateway.js +34 -4
  58. package/dist/commands/gateway.js.map +1 -1
  59. package/dist/commands/github.d.ts +20 -0
  60. package/dist/commands/github.d.ts.map +1 -0
  61. package/dist/commands/github.js +41 -0
  62. package/dist/commands/github.js.map +1 -0
  63. package/dist/commands/guardrails.d.ts +28 -2
  64. package/dist/commands/guardrails.d.ts.map +1 -1
  65. package/dist/commands/guardrails.js +233 -24
  66. package/dist/commands/guardrails.js.map +1 -1
  67. package/dist/commands/incidents.d.ts +32 -0
  68. package/dist/commands/incidents.d.ts.map +1 -0
  69. package/dist/commands/incidents.js +94 -0
  70. package/dist/commands/incidents.js.map +1 -0
  71. package/dist/commands/init.d.ts +1 -2
  72. package/dist/commands/init.d.ts.map +1 -1
  73. package/dist/commands/init.js +1 -2
  74. package/dist/commands/init.js.map +1 -1
  75. package/dist/commands/install-daemon.d.ts +1 -1
  76. package/dist/commands/install-daemon.js +2 -2
  77. package/dist/commands/integrity.d.ts +10 -2
  78. package/dist/commands/integrity.d.ts.map +1 -1
  79. package/dist/commands/integrity.js +3 -3
  80. package/dist/commands/integrity.js.map +1 -1
  81. package/dist/commands/inventory.d.ts +60 -0
  82. package/dist/commands/inventory.d.ts.map +1 -0
  83. package/dist/commands/inventory.js +141 -0
  84. package/dist/commands/inventory.js.map +1 -0
  85. package/dist/commands/judge.d.ts +1 -1
  86. package/dist/commands/judge.js +2 -2
  87. package/dist/commands/judge.js.map +1 -1
  88. package/dist/commands/login.d.ts +0 -1
  89. package/dist/commands/login.d.ts.map +1 -1
  90. package/dist/commands/login.js +0 -1
  91. package/dist/commands/login.js.map +1 -1
  92. package/dist/commands/logout.d.ts +0 -1
  93. package/dist/commands/logout.d.ts.map +1 -1
  94. package/dist/commands/logout.js +0 -1
  95. package/dist/commands/logout.js.map +1 -1
  96. package/dist/commands/mcp.d.ts +31 -0
  97. package/dist/commands/mcp.d.ts.map +1 -0
  98. package/dist/commands/mcp.js +65 -0
  99. package/dist/commands/mcp.js.map +1 -0
  100. package/dist/commands/notifications.d.ts +54 -0
  101. package/dist/commands/notifications.d.ts.map +1 -0
  102. package/dist/commands/notifications.js +151 -0
  103. package/dist/commands/notifications.js.map +1 -0
  104. package/dist/commands/org.d.ts +3 -3
  105. package/dist/commands/org.js +3 -3
  106. package/dist/commands/policy.d.ts +6 -1
  107. package/dist/commands/policy.d.ts.map +1 -1
  108. package/dist/commands/policy.js +77 -37
  109. package/dist/commands/policy.js.map +1 -1
  110. package/dist/commands/rollback.d.ts.map +1 -1
  111. package/dist/commands/rollback.js +3 -1
  112. package/dist/commands/rollback.js.map +1 -1
  113. package/dist/commands/routing.d.ts +1 -1
  114. package/dist/commands/routing.js +1 -1
  115. package/dist/commands/rules.d.ts +74 -0
  116. package/dist/commands/rules.d.ts.map +1 -0
  117. package/dist/commands/rules.js +283 -0
  118. package/dist/commands/rules.js.map +1 -0
  119. package/dist/commands/settings.d.ts +44 -0
  120. package/dist/commands/settings.d.ts.map +1 -0
  121. package/dist/commands/settings.js +110 -0
  122. package/dist/commands/settings.js.map +1 -0
  123. package/dist/commands/setup.d.ts +1 -1
  124. package/dist/commands/setup.js +1 -1
  125. package/dist/commands/siem.d.ts +53 -0
  126. package/dist/commands/siem.d.ts.map +1 -0
  127. package/dist/commands/siem.js +132 -0
  128. package/dist/commands/siem.js.map +1 -0
  129. package/dist/commands/skill.d.ts +5 -5
  130. package/dist/commands/skill.js +7 -7
  131. package/dist/commands/skill.js.map +1 -1
  132. package/dist/commands/status.d.ts +0 -1
  133. package/dist/commands/status.d.ts.map +1 -1
  134. package/dist/commands/status.js +2 -3
  135. package/dist/commands/status.js.map +1 -1
  136. package/dist/commands/syncContext.d.ts +0 -1
  137. package/dist/commands/syncContext.d.ts.map +1 -1
  138. package/dist/commands/syncContext.js +0 -1
  139. package/dist/commands/syncContext.js.map +1 -1
  140. package/dist/commands/team.d.ts +2 -2
  141. package/dist/commands/team.js +2 -2
  142. package/dist/commands/traces.d.ts +0 -3
  143. package/dist/commands/traces.d.ts.map +1 -1
  144. package/dist/commands/traces.js +0 -3
  145. package/dist/commands/traces.js.map +1 -1
  146. package/dist/commands/usage.d.ts +41 -0
  147. package/dist/commands/usage.d.ts.map +1 -0
  148. package/dist/commands/usage.js +129 -0
  149. package/dist/commands/usage.js.map +1 -0
  150. package/dist/commands/whoami.d.ts +0 -1
  151. package/dist/commands/whoami.d.ts.map +1 -1
  152. package/dist/commands/whoami.js +0 -1
  153. package/dist/commands/whoami.js.map +1 -1
  154. package/dist/config/keychain.d.ts +0 -1
  155. package/dist/config/keychain.d.ts.map +1 -1
  156. package/dist/config/keychain.js +0 -1
  157. package/dist/config/keychain.js.map +1 -1
  158. package/dist/config/paths.d.ts +0 -1
  159. package/dist/config/paths.d.ts.map +1 -1
  160. package/dist/config/paths.js +0 -1
  161. package/dist/config/paths.js.map +1 -1
  162. package/dist/config/store.d.ts +0 -1
  163. package/dist/config/store.d.ts.map +1 -1
  164. package/dist/config/store.js +0 -1
  165. package/dist/config/store.js.map +1 -1
  166. package/dist/harness/ag2.d.ts +1 -1
  167. package/dist/harness/ag2.js +1 -1
  168. package/dist/harness/agentFramework.d.ts +1 -1
  169. package/dist/harness/agentFramework.js +1 -1
  170. package/dist/harness/agenticOrchestrator.d.ts +1 -1
  171. package/dist/harness/agenticOrchestrator.js +2 -2
  172. package/dist/harness/agenticOrchestrator.js.map +1 -1
  173. package/dist/harness/agentsMd.d.ts +24 -0
  174. package/dist/harness/agentsMd.d.ts.map +1 -0
  175. package/dist/harness/agentsMd.js +28 -0
  176. package/dist/harness/agentsMd.js.map +1 -0
  177. package/dist/harness/aider.d.ts +3 -1
  178. package/dist/harness/aider.d.ts.map +1 -1
  179. package/dist/harness/aider.js +9 -7
  180. package/dist/harness/aider.js.map +1 -1
  181. package/dist/harness/antigravity.d.ts +23 -5
  182. package/dist/harness/antigravity.d.ts.map +1 -1
  183. package/dist/harness/antigravity.js +45 -55
  184. package/dist/harness/antigravity.js.map +1 -1
  185. package/dist/harness/autogen.d.ts +1 -1
  186. package/dist/harness/autogen.js +2 -2
  187. package/dist/harness/autogen.js.map +1 -1
  188. package/dist/harness/claudeCode.d.ts +22 -1
  189. package/dist/harness/claudeCode.d.ts.map +1 -1
  190. package/dist/harness/claudeCode.js +47 -3
  191. package/dist/harness/claudeCode.js.map +1 -1
  192. package/dist/harness/cline.d.ts.map +1 -1
  193. package/dist/harness/cline.js +14 -23
  194. package/dist/harness/cline.js.map +1 -1
  195. package/dist/harness/codex.d.ts +6 -1
  196. package/dist/harness/codex.d.ts.map +1 -1
  197. package/dist/harness/codex.js +23 -21
  198. package/dist/harness/codex.js.map +1 -1
  199. package/dist/harness/continue.d.ts +10 -4
  200. package/dist/harness/continue.d.ts.map +1 -1
  201. package/dist/harness/continue.js +22 -22
  202. package/dist/harness/continue.js.map +1 -1
  203. package/dist/harness/cursor.d.ts +5 -2
  204. package/dist/harness/cursor.d.ts.map +1 -1
  205. package/dist/harness/cursor.js +19 -23
  206. package/dist/harness/cursor.js.map +1 -1
  207. package/dist/harness/detector.d.ts +0 -1
  208. package/dist/harness/detector.d.ts.map +1 -1
  209. package/dist/harness/detector.js +0 -1
  210. package/dist/harness/detector.js.map +1 -1
  211. package/dist/harness/dsh.d.ts +5 -3
  212. package/dist/harness/dsh.d.ts.map +1 -1
  213. package/dist/harness/dsh.js +17 -29
  214. package/dist/harness/dsh.js.map +1 -1
  215. package/dist/harness/eve.d.ts +3 -4
  216. package/dist/harness/eve.d.ts.map +1 -1
  217. package/dist/harness/eve.js +3 -4
  218. package/dist/harness/eve.js.map +1 -1
  219. package/dist/harness/githubCopilot.d.ts +4 -1
  220. package/dist/harness/githubCopilot.d.ts.map +1 -1
  221. package/dist/harness/githubCopilot.js +12 -20
  222. package/dist/harness/githubCopilot.js.map +1 -1
  223. package/dist/harness/goose.d.ts +7 -3
  224. package/dist/harness/goose.d.ts.map +1 -1
  225. package/dist/harness/goose.js +18 -21
  226. package/dist/harness/goose.js.map +1 -1
  227. package/dist/harness/grok.d.ts +2 -2
  228. package/dist/harness/grok.d.ts.map +1 -1
  229. package/dist/harness/grok.js +13 -24
  230. package/dist/harness/grok.js.map +1 -1
  231. package/dist/harness/hermes.d.ts +6 -0
  232. package/dist/harness/hermes.d.ts.map +1 -1
  233. package/dist/harness/hermes.js +17 -16
  234. package/dist/harness/hermes.js.map +1 -1
  235. package/dist/harness/muse.d.ts +3 -7
  236. package/dist/harness/muse.d.ts.map +1 -1
  237. package/dist/harness/muse.js +15 -35
  238. package/dist/harness/muse.js.map +1 -1
  239. package/dist/harness/n8n.d.ts +13 -14
  240. package/dist/harness/n8n.d.ts.map +1 -1
  241. package/dist/harness/n8n.js +21 -181
  242. package/dist/harness/n8n.js.map +1 -1
  243. package/dist/harness/openWebUI.d.ts.map +1 -1
  244. package/dist/harness/openWebUI.js +5 -4
  245. package/dist/harness/openWebUI.js.map +1 -1
  246. package/dist/harness/openaiAgents.d.ts +1 -1
  247. package/dist/harness/openaiAgents.js +2 -2
  248. package/dist/harness/openaiAgents.js.map +1 -1
  249. package/dist/harness/openclaw.d.ts +8 -0
  250. package/dist/harness/openclaw.d.ts.map +1 -1
  251. package/dist/harness/openclaw.js +27 -12
  252. package/dist/harness/openclaw.js.map +1 -1
  253. package/dist/harness/opencode.d.ts +4 -5
  254. package/dist/harness/opencode.d.ts.map +1 -1
  255. package/dist/harness/opencode.js +15 -30
  256. package/dist/harness/opencode.js.map +1 -1
  257. package/dist/harness/openhands.d.ts +9 -3
  258. package/dist/harness/openhands.d.ts.map +1 -1
  259. package/dist/harness/openhands.js +30 -24
  260. package/dist/harness/openhands.js.map +1 -1
  261. package/dist/harness/pi.d.ts +7 -2
  262. package/dist/harness/pi.d.ts.map +1 -1
  263. package/dist/harness/pi.js +19 -18
  264. package/dist/harness/pi.js.map +1 -1
  265. package/dist/harness/rooCode.d.ts +12 -5
  266. package/dist/harness/rooCode.d.ts.map +1 -1
  267. package/dist/harness/rooCode.js +23 -39
  268. package/dist/harness/rooCode.js.map +1 -1
  269. package/dist/harness/rulesFiles.d.ts +53 -0
  270. package/dist/harness/rulesFiles.d.ts.map +1 -0
  271. package/dist/harness/rulesFiles.js +106 -0
  272. package/dist/harness/rulesFiles.js.map +1 -0
  273. package/dist/harness/smolagents.d.ts +2 -2
  274. package/dist/harness/smolagents.js +3 -3
  275. package/dist/harness/smolagents.js.map +1 -1
  276. package/dist/harness/types.d.ts +20 -6
  277. package/dist/harness/types.d.ts.map +1 -1
  278. package/dist/harness/types.js +1 -95
  279. package/dist/harness/types.js.map +1 -1
  280. package/dist/harness/windsurf.d.ts +6 -1
  281. package/dist/harness/windsurf.d.ts.map +1 -1
  282. package/dist/harness/windsurf.js +21 -24
  283. package/dist/harness/windsurf.js.map +1 -1
  284. package/dist/harness/xirp.d.ts +1 -2
  285. package/dist/harness/xirp.d.ts.map +1 -1
  286. package/dist/harness/xirp.js +2 -3
  287. package/dist/harness/xirp.js.map +1 -1
  288. package/dist/lib/api.d.ts +27 -1
  289. package/dist/lib/api.d.ts.map +1 -1
  290. package/dist/lib/api.js +55 -18
  291. package/dist/lib/api.js.map +1 -1
  292. package/dist/lib/ciscoScanner.d.ts +1 -1
  293. package/dist/lib/ciscoScanner.js +1 -1
  294. package/dist/lib/decisionsLogRefresh.d.ts.map +1 -1
  295. package/dist/lib/decisionsLogRefresh.js +6 -7
  296. package/dist/lib/decisionsLogRefresh.js.map +1 -1
  297. package/dist/lib/deviceReport.d.ts +15 -0
  298. package/dist/lib/deviceReport.d.ts.map +1 -1
  299. package/dist/lib/deviceReport.js +30 -0
  300. package/dist/lib/deviceReport.js.map +1 -1
  301. package/dist/lib/gitHooks.d.ts +0 -1
  302. package/dist/lib/gitHooks.d.ts.map +1 -1
  303. package/dist/lib/gitHooks.js +8 -9
  304. package/dist/lib/gitHooks.js.map +1 -1
  305. package/dist/lib/gracefulShutdown.d.ts +1 -1
  306. package/dist/lib/gracefulShutdown.js +1 -1
  307. package/dist/lib/hash.d.ts +0 -1
  308. package/dist/lib/hash.d.ts.map +1 -1
  309. package/dist/lib/hash.js +0 -1
  310. package/dist/lib/hash.js.map +1 -1
  311. package/dist/lib/inventory.d.ts +47 -0
  312. package/dist/lib/inventory.d.ts.map +1 -0
  313. package/dist/lib/inventory.js +106 -0
  314. package/dist/lib/inventory.js.map +1 -0
  315. package/dist/lib/logger.d.ts +0 -1
  316. package/dist/lib/logger.d.ts.map +1 -1
  317. package/dist/lib/logger.js +0 -1
  318. package/dist/lib/logger.js.map +1 -1
  319. package/dist/lib/mdmManifest.d.ts +30 -2
  320. package/dist/lib/mdmManifest.d.ts.map +1 -1
  321. package/dist/lib/mdmManifest.js +50 -2
  322. package/dist/lib/mdmManifest.js.map +1 -1
  323. package/dist/lib/onboarding.d.ts +0 -1
  324. package/dist/lib/onboarding.d.ts.map +1 -1
  325. package/dist/lib/onboarding.js +1 -2
  326. package/dist/lib/onboarding.js.map +1 -1
  327. package/dist/lib/policySnapshot.d.ts +3 -2
  328. package/dist/lib/policySnapshot.d.ts.map +1 -1
  329. package/dist/lib/policySnapshot.js +6 -3
  330. package/dist/lib/policySnapshot.js.map +1 -1
  331. package/dist/lib/process.d.ts +5 -1
  332. package/dist/lib/process.d.ts.map +1 -1
  333. package/dist/lib/process.js +13 -4
  334. package/dist/lib/process.js.map +1 -1
  335. package/dist/lib/providerProbe.d.ts +3 -3
  336. package/dist/lib/providerProbe.d.ts.map +1 -1
  337. package/dist/lib/providerProbe.js +15 -7
  338. package/dist/lib/providerProbe.js.map +1 -1
  339. package/dist/lib/sandbox/firecracker.d.ts +3 -3
  340. package/dist/lib/sandbox/firecracker.js +3 -3
  341. package/dist/lib/sandbox/index.d.ts +2 -2
  342. package/dist/lib/sandbox/index.js +2 -2
  343. package/dist/lib/sandbox/oci.d.ts +1 -1
  344. package/dist/lib/sandbox/oci.js +1 -1
  345. package/dist/lib/sandbox/types.d.ts +1 -1
  346. package/dist/lib/sandbox/types.js +1 -1
  347. package/dist/lib/sopFrontMatter.d.ts +1 -1
  348. package/dist/lib/sopFrontMatter.js +1 -1
  349. package/package.json +6 -5
  350. package/resources/sandbox/Dockerfile +1 -1
  351. package/resources/sandbox/entrypoint.sh +4 -4
  352. package/resources/sandbox/firecracker-launch.sh +1 -1
  353. package/dist/harness/base.d.ts +0 -24
  354. package/dist/harness/base.d.ts.map +0 -1
  355. package/dist/harness/base.js +0 -74
  356. 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')
@@ -111,9 +110,9 @@ program
111
110
  const { runRollback } = await import('./commands/rollback.js');
112
111
  await runRollback(opts);
113
112
  });
114
- program
113
+ const budgetCmd = program
115
114
  .command('budget')
116
- .description('Check remaining daily/monthly budget and list active loops')
115
+ .description('Check remaining daily/monthly budget and list active loops; set workspace, key and member budgets')
117
116
  .option('--dev', 'Use local control plane (http://localhost:3001)')
118
117
  .option('--watch', 'Continuously print machine-local and workspace spend, one line per tick')
119
118
  .option('--interval <seconds>', 'Tick interval in seconds for --watch', String(5))
@@ -126,6 +125,68 @@ program
126
125
  const { runBudget } = await import('./commands/budget.js');
127
126
  await runBudget(opts);
128
127
  });
128
+ budgetCmd
129
+ .command('set')
130
+ .description("Set the workspace's daily and monthly caps, alert threshold and whether each cap refuses requests (OWNER, ADMIN)")
131
+ .option('--daily <usd>', 'Daily cap in USD (0: no daily cap; default: back to the $100 default)')
132
+ .option('--monthly <usd>', 'Monthly cap in USD (0: no monthly cap; default: back to the $500 default)')
133
+ .option('--threshold <pct>', 'Alert at this percentage of each cap')
134
+ .option('--daily-enforcement <mode>', 'hard (refuse what the day does not cover) or soft (alert only)')
135
+ .option('--monthly-enforcement <mode>', 'hard (refuse what the month does not cover) or soft (alert only)')
136
+ .option('--json', 'Output as JSON')
137
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
138
+ .action(async (_opts, cmd) => {
139
+ // optsWithGlobals: `budget` declares --dev too, and Commander gives a
140
+ // parent's option to the parent wherever it appears on the line.
141
+ const { runBudgetSet } = await import('./commands/budgetLimits.js');
142
+ await runBudgetSet(cmd.optsWithGlobals());
143
+ });
144
+ budgetCmd
145
+ .command('keys')
146
+ .description("Every virtual key's spend budgets, rate limit and spend today and this month")
147
+ .option('--json', 'Output as JSON')
148
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
149
+ .action(async (_opts, cmd) => {
150
+ const { runBudgetKeys } = await import('./commands/budgetLimits.js');
151
+ await runBudgetKeys(cmd.optsWithGlobals());
152
+ });
153
+ budgetCmd
154
+ .command('key <keyId>')
155
+ .description("Set a virtual key's spend budgets and rate limit (OWNER, ADMIN)")
156
+ .option('--daily <usd>', 'Day budget in USD, or none to remove it')
157
+ .option('--monthly <usd>', 'Month budget in USD, or none to remove it')
158
+ .option('--daily-enforcement <mode>', 'hard (refuse) or soft (alert only) for the day budget')
159
+ .option('--monthly-enforcement <mode>', 'hard (refuse) or soft (alert only) for the month budget')
160
+ .option('--rpm <n>', 'Requests per minute, or none to remove the limit')
161
+ .option('--tpm <n>', 'Tokens per minute, or none to remove the limit')
162
+ .option('--json', 'Output as JSON')
163
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
164
+ .action(async (keyId, _opts, cmd) => {
165
+ const { runBudgetKey } = await import('./commands/budgetLimits.js');
166
+ await runBudgetKey(keyId, cmd.optsWithGlobals());
167
+ });
168
+ budgetCmd
169
+ .command('members')
170
+ .description("The default member budget, and each member's budgets and spend (Biz Org+)")
171
+ .option('--json', 'Output as JSON')
172
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
173
+ .action(async (_opts, cmd) => {
174
+ const { runBudgetMembers } = await import('./commands/budgetLimits.js');
175
+ await runBudgetMembers(cmd.optsWithGlobals());
176
+ });
177
+ budgetCmd
178
+ .command('member <memberId>')
179
+ .description("Set a member's spend budgets, or the default member budget with `default` (OWNER, ADMIN; Biz Org+)")
180
+ .option('--daily <usd>', 'Day budget in USD, or none to remove it')
181
+ .option('--monthly <usd>', 'Month budget in USD, or none to remove it')
182
+ .option('--daily-enforcement <mode>', 'hard (refuse) or soft (alert only) for the day budget')
183
+ .option('--monthly-enforcement <mode>', 'hard (refuse) or soft (alert only) for the month budget')
184
+ .option('--json', 'Output as JSON')
185
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
186
+ .action(async (memberId, _opts, cmd) => {
187
+ const { runBudgetMember } = await import('./commands/budgetLimits.js');
188
+ await runBudgetMember(memberId, cmd.optsWithGlobals());
189
+ });
129
190
  program
130
191
  .command('predict-cost')
131
192
  .description('Pre-flight cost estimate for a prompt/task before it runs (requires `intutic login`). ' +
@@ -257,7 +318,7 @@ policyCmd
257
318
  });
258
319
  policyCmd
259
320
  .command('install')
260
- .description('Validate and install a compiled WASM rule into the local proxy rules dir')
321
+ .description('Validate and install a compiled WASM rule (native or Rego) into the local proxy rules dir')
261
322
  .requiredOption('--wasm <path>', 'Path to compiled WASM rule binary')
262
323
  .option('--name <name>', 'Rule name (defaults to the file name)')
263
324
  .option('--priority <NN>', 'Evaluation priority — lower runs first', '100')
@@ -283,7 +344,39 @@ policyCmd
283
344
  const { runPolicyReplay } = await import('./commands/policy.js');
284
345
  await runPolicyReplay(ruleId, opts);
285
346
  });
286
- // Policy Clause Ledger (LLD #71). `intutic policy` is the WASM loop and
347
+ // Rego policies as rules: compiled with OPA and packaged with the metadata
348
+ // the proxies read (`intutic rules build`), tested through the same host
349
+ // (`intutic rules test`). Installing and uploading are the same as for any rule.
350
+ const rulesCmd = program
351
+ .command('rules')
352
+ .description('Build and test Rego policies as Intutic rules');
353
+ rulesCmd
354
+ .command('build')
355
+ .description('Compile Rego to a rule with OPA (opa build -t wasm) and package it with its entrypoint and risk tier.\n' +
356
+ '\n' +
357
+ ' Needs the opa binary on the PATH, or INTUTIC_OPA_BIN. Refuses a policy that\n' +
358
+ ' needs a builtin Intutic does not provide, naming it.')
359
+ .requiredOption('--rego <path>', 'Rego file or directory')
360
+ .requiredOption('--entrypoint <package/rule>', 'The rule to evaluate, e.g. intutic/shell/deny')
361
+ .option('--risk-tier <tier>', 'Default risk tier for its decisions: low | medium | high | critical')
362
+ .option('--out <path>', 'Output .wasm path (default: build/<entrypoint>.wasm)')
363
+ .action(async (opts) => {
364
+ const { runRulesBuild } = await import('./commands/rules.js');
365
+ await runRulesBuild(opts);
366
+ });
367
+ rulesCmd
368
+ .command('test <module>')
369
+ .description('Evaluate a Rego rule against sample inputs locally, through the same host the proxies use.\n' +
370
+ '\n' +
371
+ ' Each --input file holds one input document, or an array of\n' +
372
+ ' {"name", "input", "expect": "allow|deny|hold|reask"} cases. Exits 1 when a\n' +
373
+ ' case gets a decision other than the one it expects.')
374
+ .requiredOption('--input <file...>', 'JSON file(s) of inputs or cases')
375
+ .action(async (module, opts) => {
376
+ const { runRulesTest } = await import('./commands/rules.js');
377
+ await runRulesTest(module, opts);
378
+ });
379
+ // Policy Clause Ledger. `intutic policy` is the WASM loop and
287
380
  // `intutic sops` is files on disk; this namespace is the cited guardrails
288
381
  // extracted from policy documents and their shadow -> promote lifecycle.
289
382
  const guardrailsCmd = program
@@ -369,6 +462,7 @@ guardrailsCmd
369
462
  .description('List guardrails with their status and shadow evidence')
370
463
  .option('--status <status>', 'PROPOSED | SHADOW | ENFORCING | REJECTED | RETIRED')
371
464
  .option('--target <target>', 'hook_rule | sop_front_matter | wasm_rule | workspace_setting')
465
+ .option('--provenance <provenance>', 'extracted | authored')
372
466
  .option('--doc <docId>', 'Only guardrails cited from this document')
373
467
  .option('--limit <n>', 'Max rows (default 50, capped at 200)')
374
468
  .option('--json', 'Output as JSON')
@@ -386,6 +480,51 @@ guardrailsCmd
386
480
  const { runGuardrailsShow } = await import('./commands/guardrails.js');
387
481
  await runGuardrailsShow(guardrailId, opts);
388
482
  });
483
+ /** The IR flags `guardrails create` and `guardrails update` share; a file (`--file`) is the alternative. */
484
+ function guardrailIrOptions(cmd) {
485
+ return cmd
486
+ .option('--file <path>', 'YAML or JSON: a bare IR, or { name, description, ir }')
487
+ .option('--name <name>', 'One-line label (at most 80 characters)')
488
+ .option('--description <text>', 'What the rule is for; shown where an extracted guardrail shows its quote')
489
+ .option('--kind <kind>', 'hook_rule | deny_tools | review_before | requires_before | forbid_after | max_calls | forbid_with | wasm_predicate | allowed_models | egress_allow')
490
+ .option('--title <title>', 'hook_rule, wasm_predicate: the title in the block message')
491
+ .option('--tools <list>', 'hook_rule, deny_tools: comma-separated tool names')
492
+ .option('--tokens <list>', 'review_before: comma-separated tool or action tokens')
493
+ .option('--arg-contains <literal>', 'hook_rule: fire only when the input contains this (repeatable)', (v, prev = []) => [...prev, v])
494
+ .option('--arg-not-contains <literal>', 'hook_rule: fire only when the input does not contain this (repeatable)', (v, prev = []) => [...prev, v])
495
+ .option('--first <token>', 'requires_before, forbid_after: the first token')
496
+ .option('--then <token>', 'requires_before, forbid_after: the second token')
497
+ .option('--token <token>', 'max_calls, forbid_with: the token')
498
+ .option('--limit <n>', 'max_calls: the most calls allowed')
499
+ .option('--taint <taint>', 'forbid_with: secrets() | pii()')
500
+ .option('--roles <list>', 'Comma-separated roles the rule applies to (default: everyone)')
501
+ .option('--models <list>', 'allowed_models: comma-separated model ids')
502
+ .option('--hosts <list>', 'egress_allow: comma-separated hosts, suffixes or IPv4 CIDRs')
503
+ .option('--rationale <text>', 'wasm_predicate: why it re-asks')
504
+ .option('--predicate <json>', 'wasm_predicate: the predicate as JSON')
505
+ .option('--json', 'Output as JSON')
506
+ .option('--dev', 'Use local control plane (http://localhost:3001)');
507
+ }
508
+ guardrailIrOptions(guardrailsCmd.command('create').description('Author a guardrail directly: the same IR and checks as an extracted one, created PROPOSED')).action(async (opts) => {
509
+ const { runGuardrailsCreate } = await import('./commands/guardrails.js');
510
+ await runGuardrailsCreate(opts);
511
+ });
512
+ guardrailIrOptions(guardrailsCmd
513
+ .command('update <guardrailId>')
514
+ .description('Edit an authored guardrail: a name or description in place; a changed IR creates the next version, PROPOSED with no evidence')
515
+ .option('--clear-description', 'Remove the description')).action(async (guardrailId, opts) => {
516
+ const { runGuardrailsUpdate } = await import('./commands/guardrails.js');
517
+ await runGuardrailsUpdate(guardrailId, opts);
518
+ });
519
+ guardrailsCmd
520
+ .command('delete <guardrailId>')
521
+ .description('Retire an authored guardrail and undo what it wrote; its history is kept')
522
+ .option('--json', 'Output as JSON')
523
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
524
+ .action(async (guardrailId, opts) => {
525
+ const { runGuardrailsDelete } = await import('./commands/guardrails.js');
526
+ await runGuardrailsDelete(guardrailId, opts);
527
+ });
389
528
  guardrailsCmd
390
529
  .command('approve-shadow <guardrailId>')
391
530
  .description('Ship a proposed guardrail in shadow: it reports, never blocks')
@@ -501,7 +640,7 @@ program
501
640
  const { runStart } = await import('./commands/start.js');
502
641
  await runStart(opts);
503
642
  });
504
- // L2 mandatory egress firewall (LLD #63 §5). Makes the governing proxy
643
+ // L2 mandatory egress firewall. Makes the governing proxy
505
644
  // non-optional: default-deny host egress to everything except the proxy, DNS,
506
645
  // and declared infra. apply/remove need root; generate/status do not.
507
646
  const enforceCmd = program
@@ -602,8 +741,8 @@ program
602
741
  });
603
742
  program
604
743
  .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 ' +
744
+ .description('One-shot refresh of the governed decisions log (.intutic/DECISIONS.md, and the recent ' +
745
+ 'entries in each governed harness\'s instructions file) — no-ops if decisionsLogEnabled is off. Invoked by the optional ' +
607
746
  'post-merge Git hook `intutic init` installs; safe to run manually.')
608
747
  .action(async () => {
609
748
  const { refreshDecisionsLog } = await import('./lib/decisionsLogRefresh.js');
@@ -617,8 +756,8 @@ program
617
756
  .command('exec')
618
757
  .description('Execute a command wrapped with Intutic proxy environment variables')
619
758
  .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,
759
+ // Run the agent inside an isolated sandbox whose ONLY egress is the proxy:
760
+ // cap-drop, no-new-privileges, read-only rootfs, resource caps,
622
761
  // and a default-deny egress firewall the agent cannot undo.
623
762
  .option('--sandbox [kind]', 'Run the agent in an isolated sandbox (kind: oci | firecracker; default oci)')
624
763
  .option('--sandbox-image <image>', 'Sandbox image (must contain the agent + nftables + capsh); the default is built locally on first use', DEFAULT_SANDBOX_IMAGE)
@@ -717,6 +856,33 @@ findings
717
856
  const { runFindingsEchoReport } = await import('./commands/findings.js');
718
857
  await runFindingsEchoReport(opts);
719
858
  });
859
+ // ── Governance incidents ───────────────────────────────────────────────────
860
+ const incidentsCmd = program
861
+ .command('incidents')
862
+ .description('Governance incidents, as on Findings › Incidents (OWNER, ADMIN, EM)');
863
+ incidentsCmd
864
+ .command('list')
865
+ .description('Incidents ranked by review priority, filtered by status, severity and type')
866
+ .option('--status <status>', 'Only incidents with this status: OPEN, RESOLVED or AUTO_RESOLVED')
867
+ .option('--severity <severity>', 'Only incidents of this severity: CRITICAL, HIGH, MEDIUM or LOW')
868
+ .option('--type <type>', 'Only incidents of this type, e.g. SCOPE_VIOLATION, WASM_RULE_REFUSED or SYSTEM_ANOMALY')
869
+ .option('--page <n>', 'The page to show (default 1)')
870
+ .option('--limit <n>', 'Incidents per page (default 20, at most 100)')
871
+ .option('--json', 'Output as JSON')
872
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
873
+ .action(async (opts) => {
874
+ const { runIncidentsList } = await import('./commands/incidents.js');
875
+ await runIncidentsList(opts);
876
+ });
877
+ incidentsCmd
878
+ .command('show <incidentId>')
879
+ .description('One incident in full, with its escalation details')
880
+ .option('--json', 'Output as JSON')
881
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
882
+ .action(async (incidentId, opts) => {
883
+ const { runIncidentsShow } = await import('./commands/incidents.js');
884
+ await runIncidentsShow(incidentId, opts);
885
+ });
720
886
  // ── Trace integrity ────────────────────────────────────────────────────────
721
887
  const integrity = program
722
888
  .command('integrity')
@@ -874,8 +1040,8 @@ daemon
874
1040
  .option('--mcp', 'Show the MCP proxy daemon instead of the sync-daemon')
875
1041
  .action(async (opts) => {
876
1042
  // `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).
1043
+ // reachability test widened to the status/stop/start verbs (the same
1044
+ // exported-but-unreachable shape, one more time).
879
1045
  const { daemonStatus, proxyServiceStatus, mcpDaemonStatus } = await import('./commands/install-daemon.js');
880
1046
  await (opts.proxy ? proxyServiceStatus() : opts.mcp ? mcpDaemonStatus() : daemonStatus());
881
1047
  });
@@ -886,8 +1052,8 @@ daemon
886
1052
  .option('--mcp', 'Stop the MCP proxy daemon instead of the sync-daemon')
887
1053
  .action(async (opts) => {
888
1054
  // `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).
1055
+ // reachability test widened to the status/stop/start verbs (the same
1056
+ // exported-but-unreachable shape, one more time).
891
1057
  const { daemonStop, proxyServiceStop, mcpDaemonStop } = await import('./commands/install-daemon.js');
892
1058
  await (opts.proxy ? proxyServiceStop() : opts.mcp ? mcpDaemonStop() : daemonStop());
893
1059
  });
@@ -898,8 +1064,8 @@ daemon
898
1064
  .option('--mcp', 'Start the MCP proxy daemon instead of the sync-daemon')
899
1065
  .action(async (opts) => {
900
1066
  // `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).
1067
+ // reachability test widened to the status/stop/start verbs (the same
1068
+ // exported-but-unreachable shape, one more time).
903
1069
  const { daemonStart, proxyServiceStart, mcpDaemonStart } = await import('./commands/install-daemon.js');
904
1070
  await (opts.proxy ? proxyServiceStart() : opts.mcp ? mcpDaemonStart() : daemonStart());
905
1071
  });
@@ -1022,7 +1188,7 @@ decisionCmd
1022
1188
  const { runDecisionReject } = await import('./commands/decision.js');
1023
1189
  await runDecisionReject(holdId, opts);
1024
1190
  });
1025
- // ── Gateway commands (LLD #66) ───────────────────────────────────────────
1191
+ // ── Gateway commands ─────────────────────────────────────────────────────
1026
1192
  //
1027
1193
  // Self-hosted gateway registration/management. Previously reachable only by
1028
1194
  // hand-written curl against services/control-plane/src/routes/gateways.ts —
@@ -1080,6 +1246,15 @@ gatewayCmd
1080
1246
  const gatewayConfigCmd = gatewayCmd
1081
1247
  .command('config')
1082
1248
  .description('Manage a gateway\'s remote config (requireVk, requireProvisionedKey)');
1249
+ gatewayConfigCmd
1250
+ .command('get <gateway_id>')
1251
+ .description('Show the config values set on a gateway and their version')
1252
+ .option('--json', 'Output as JSON')
1253
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1254
+ .action(async (gatewayId, opts) => {
1255
+ const { runGatewayConfigGet } = await import('./commands/gateway.js');
1256
+ await runGatewayConfigGet(gatewayId, opts);
1257
+ });
1083
1258
  gatewayConfigCmd
1084
1259
  .command('set <gateway_id>')
1085
1260
  .description('Update one or both config flags on a gateway')
@@ -1112,7 +1287,7 @@ gatewayCmd
1112
1287
  const { runGatewayResolve } = await import('./commands/gateway.js');
1113
1288
  await runGatewayResolve(opts);
1114
1289
  });
1115
- // ── Provider credentials (LLD #64 §4, LLD #67) ───────────────────────────
1290
+ // ── Provider credentials ─────────────────────────────────────────────────
1116
1291
  //
1117
1292
  // Provision a workspace's own upstream provider keys — the BYO-key wizard's
1118
1293
  // API, previously dashboard-only. See commands/credentials.ts's module doc.
@@ -1132,6 +1307,7 @@ credentialsCmd
1132
1307
  .command('set <provider>')
1133
1308
  .description('Provision or rotate a provider credential (e.g. --field apiKey=sk-ant-...)')
1134
1309
  .option('--field <key=value>', 'A credential field; repeat for multi-field providers', (v, prev) => [...prev, v], [])
1310
+ .option('--field-file <key=path>', 'A credential field read from a file (e.g. a service-account JSON key)', (v, prev) => [...prev, v], [])
1135
1311
  .option('--json', 'Output as JSON')
1136
1312
  .option('--dev', 'Use local control plane (http://localhost:3001)')
1137
1313
  .action(async (provider, opts) => {
@@ -1146,7 +1322,16 @@ credentialsCmd
1146
1322
  const { runCredentialsUnset } = await import('./commands/credentials.js');
1147
1323
  await runCredentialsUnset(provider, opts);
1148
1324
  });
1149
- // ── DCT Token Attenuation (LLD #19 §2.1, HLD §5.6 Patent Family A) ───────
1325
+ credentialsCmd
1326
+ .command('models <provider>')
1327
+ .description('The models a provider credential can reach, as recorded when it was last checked')
1328
+ .option('--json', 'Output as JSON')
1329
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1330
+ .action(async (provider, opts) => {
1331
+ const { runCredentialsModels } = await import('./commands/credentials.js');
1332
+ await runCredentialsModels(provider, opts);
1333
+ });
1334
+ // ── DCT Token Attenuation (HLD §5.6 Patent Family A) ─────────────────────
1150
1335
  //
1151
1336
  // "CLI mints, dashboard audits": this is the mint/inspect half. See
1152
1337
  // commands/attenuate.ts's module doc.
@@ -1169,7 +1354,7 @@ attenuateCmd
1169
1354
  const { runAttenuateChain } = await import('./commands/attenuate.js');
1170
1355
  await runAttenuateChain(chainId, opts);
1171
1356
  });
1172
- // ── Org signup + team management (LLD #65) ───────────────────────────────
1357
+ // ── Org signup + team management ─────────────────────────────────────────
1173
1358
  const orgCmd = program
1174
1359
  .command('org')
1175
1360
  .description('Create and manage orgs');
@@ -1228,5 +1413,381 @@ teamCmd
1228
1413
  const { runTeamCreateWorkspace } = await import('./commands/team.js');
1229
1414
  await runTeamCreateWorkspace(teamId, opts);
1230
1415
  });
1416
+ // ── Operator commands ────────────────────────────────────────────────────
1417
+ //
1418
+ // Workspace settings, the MCP server registry, notification rules, SIEM
1419
+ // destinations and the fleet reports, each over its existing control-plane
1420
+ // route. Previously dashboard-only. See commands/apiCommand.ts for the shape
1421
+ // they share.
1422
+ const settingsCmd = program
1423
+ .command('settings')
1424
+ .description('Read and change workspace settings (MCP policy, budgets, group policy, config content upload, ...)');
1425
+ settingsCmd
1426
+ .command('get [key]')
1427
+ .description('Print every workspace setting, or one')
1428
+ .option('--json', 'Output as JSON')
1429
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1430
+ .action(async (key, opts) => {
1431
+ const { runSettingsGet } = await import('./commands/settings.js');
1432
+ await runSettingsGet(key, opts);
1433
+ });
1434
+ settingsCmd
1435
+ .command('set <key> [value]')
1436
+ .description('Change one setting; the value is JSON when it parses as JSON, else a string')
1437
+ .option('--file <path>', 'Read the value from a JSON file instead')
1438
+ .option('--json', 'Output as JSON')
1439
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1440
+ .action(async (key, value, opts) => {
1441
+ const { runSettingsSet } = await import('./commands/settings.js');
1442
+ await runSettingsSet(key, value, opts);
1443
+ });
1444
+ const mcpCmd = program
1445
+ .command('mcp')
1446
+ .description('Review the MCP servers the workspace\'s MCP proxies have seen, and decide on them');
1447
+ mcpCmd
1448
+ .command('list')
1449
+ .description('Every MCP server seen, its status and tools, and the registry\'s default policy')
1450
+ .option('--json', 'Output as JSON')
1451
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1452
+ .action(async (opts) => {
1453
+ const { runMcpList } = await import('./commands/mcp.js');
1454
+ await runMcpList(opts);
1455
+ });
1456
+ for (const [action, desc] of [
1457
+ ['approve', 'Approve an MCP server; MCP proxies let it run'],
1458
+ ['block', 'Block an MCP server; MCP proxies refuse it'],
1459
+ ['reset', 'Return an MCP server to the approval queue'],
1460
+ ]) {
1461
+ mcpCmd
1462
+ .command(`${action} <server_id>`)
1463
+ .description(desc)
1464
+ .option('--json', 'Output as JSON')
1465
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1466
+ .action(async (serverId, opts) => {
1467
+ const { runMcpDecide } = await import('./commands/mcp.js');
1468
+ await runMcpDecide(action, serverId, opts);
1469
+ });
1470
+ }
1471
+ for (const [action, enabled, desc] of [
1472
+ ['enable-tool', true, 'Switch one tool of an MCP server back on'],
1473
+ ['disable-tool', false, 'Switch one tool of an MCP server off; MCP proxies refuse calls to it'],
1474
+ ]) {
1475
+ mcpCmd
1476
+ .command(`${action} <server_id> <tool>`)
1477
+ .description(desc)
1478
+ .option('--json', 'Output as JSON')
1479
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1480
+ .action(async (serverId, tool, opts) => {
1481
+ const { runMcpTool } = await import('./commands/mcp.js');
1482
+ await runMcpTool(serverId, tool, enabled, opts);
1483
+ });
1484
+ }
1485
+ const notificationsCmd = program
1486
+ .command('notifications')
1487
+ .description('Manage notification rules: which events go to Slack, email, a webhook or PagerDuty');
1488
+ function ruleOptions(cmd) {
1489
+ return cmd
1490
+ .option('--slack-channel <id>', 'Slack channel ID, for the slack channel')
1491
+ .option('--email <addresses>', 'Comma-separated recipients (up to 20), for the email channel')
1492
+ .option('--webhook-url <url>', 'HTTPS URL, for the webhook channel')
1493
+ .option('--pagerduty-key <key>', 'Routing key, for the pagerduty channel')
1494
+ .option('--severity <list>', 'Only events of these comma-separated severities')
1495
+ .option('--harness <list>', 'Only events from these comma-separated harnesses')
1496
+ .option('--user <ids>', 'Only events from these comma-separated user ids')
1497
+ .option('--cooldown <minutes>', 'Minimum minutes between two notifications of this rule (1-1440)')
1498
+ .option('--json', 'Output as JSON')
1499
+ .option('--dev', 'Use local control plane (http://localhost:3001)');
1500
+ }
1501
+ notificationsCmd
1502
+ .command('list')
1503
+ .description('List notification rules')
1504
+ .option('--json', 'Output as JSON')
1505
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1506
+ .action(async (opts) => {
1507
+ const { runNotificationsList } = await import('./commands/notifications.js');
1508
+ await runNotificationsList(opts);
1509
+ });
1510
+ ruleOptions(notificationsCmd
1511
+ .command('create')
1512
+ .description('Create a notification rule; a webhook rule prints its signing secret once')
1513
+ .requiredOption('--event <type>', 'Event type, e.g. incident.created or mcp.server.candidate')
1514
+ .requiredOption('--channel <channel>', 'slack, email, webhook or pagerduty')
1515
+ .option('--disabled', 'Create the rule switched off')).action(async (opts) => {
1516
+ const { runNotificationsCreate } = await import('./commands/notifications.js');
1517
+ await runNotificationsCreate(opts);
1518
+ });
1519
+ ruleOptions(notificationsCmd
1520
+ .command('update <rule_id>')
1521
+ .description('Change a notification rule; only the fields given change')
1522
+ .option('--event <type>', 'Event type')
1523
+ .option('--channel <channel>', 'slack, email, webhook or pagerduty')
1524
+ .option('--enable', 'Switch the rule on')
1525
+ .option('--disable', 'Switch the rule off')).action(async (ruleId, opts) => {
1526
+ const { runNotificationsUpdate } = await import('./commands/notifications.js');
1527
+ await runNotificationsUpdate(ruleId, opts);
1528
+ });
1529
+ notificationsCmd
1530
+ .command('delete <rule_id>')
1531
+ .description('Delete a notification rule')
1532
+ .option('--json', 'Output as JSON')
1533
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1534
+ .action(async (ruleId, opts) => {
1535
+ const { runNotificationsDelete } = await import('./commands/notifications.js');
1536
+ await runNotificationsDelete(ruleId, opts);
1537
+ });
1538
+ notificationsCmd
1539
+ .command('rotate-secret <rule_id>')
1540
+ .description('Replace a webhook rule\'s signing secret and print the new one once')
1541
+ .option('--json', 'Output as JSON')
1542
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1543
+ .action(async (ruleId, opts) => {
1544
+ const { runNotificationsRotateSecret } = await import('./commands/notifications.js');
1545
+ await runNotificationsRotateSecret(ruleId, opts);
1546
+ });
1547
+ const siemCmd = program
1548
+ .command('siem')
1549
+ .description('Manage SIEM export destinations and the event sources each receives');
1550
+ function destinationOptions(cmd) {
1551
+ return cmd
1552
+ .option('--sources <list>', 'Comma-separated event sources this destination receives (see `intutic siem sources`)')
1553
+ .option('--default-sources', 'Receive the default set: every source except the opt-in ones')
1554
+ .option('--batch-size <n>', 'Events per delivery batch')
1555
+ .option('--flush-interval-ms <ms>', 'Longest wait before a partial batch is sent')
1556
+ .option('--json', 'Output as JSON')
1557
+ .option('--dev', 'Use local control plane (http://localhost:3001)');
1558
+ }
1559
+ siemCmd
1560
+ .command('list')
1561
+ .description('List SIEM destinations (credentials masked)')
1562
+ .option('--json', 'Output as JSON')
1563
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1564
+ .action(async (opts) => {
1565
+ const { runSiemList } = await import('./commands/siem.js');
1566
+ await runSiemList(opts);
1567
+ });
1568
+ siemCmd
1569
+ .command('show <destination_id>')
1570
+ .description('Show one SIEM destination (credentials masked)')
1571
+ .option('--json', 'Output as JSON')
1572
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1573
+ .action(async (destinationId, opts) => {
1574
+ const { runSiemShow } = await import('./commands/siem.js');
1575
+ await runSiemShow(destinationId, opts);
1576
+ });
1577
+ siemCmd
1578
+ .command('sources')
1579
+ .description('List the event sources a destination can receive, and which are opt-in')
1580
+ .option('--json', 'Output as JSON')
1581
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1582
+ .action(async (opts) => {
1583
+ const { runSiemSources } = await import('./commands/siem.js');
1584
+ await runSiemSources(opts);
1585
+ });
1586
+ destinationOptions(siemCmd
1587
+ .command('create')
1588
+ .description('Create a SIEM destination; a webhook destination prints its signing secret once')
1589
+ .requiredOption('--name <name>', 'Display name')
1590
+ .requiredOption('--type <adapter>', 'syslog_cef, webhook_https, splunk_hec, datadog_logs, gcs or s3')
1591
+ .requiredOption('--config <path>', 'JSON file with the adapter settings and credentials')).action(async (opts) => {
1592
+ const { runSiemCreate } = await import('./commands/siem.js');
1593
+ await runSiemCreate(opts);
1594
+ });
1595
+ destinationOptions(siemCmd
1596
+ .command('update <destination_id>')
1597
+ .description('Change a SIEM destination; only the fields given change')
1598
+ .option('--name <name>', 'Display name')
1599
+ .option('--config <path>', 'JSON file with the new adapter settings; a secret left out or left masked keeps its stored value')
1600
+ .option('--enable', 'Turn a deactivated destination back on')).action(async (destinationId, opts) => {
1601
+ const { runSiemUpdate } = await import('./commands/siem.js');
1602
+ await runSiemUpdate(destinationId, opts);
1603
+ });
1604
+ siemCmd
1605
+ .command('delete <destination_id>')
1606
+ .description('Deactivate a SIEM destination; it stops receiving events and stays listed')
1607
+ .option('--json', 'Output as JSON')
1608
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1609
+ .action(async (destinationId, opts) => {
1610
+ const { runSiemDelete } = await import('./commands/siem.js');
1611
+ await runSiemDelete(destinationId, opts);
1612
+ });
1613
+ siemCmd
1614
+ .command('rotate-secret <destination_id>')
1615
+ .description('Replace a webhook destination\'s signing secret and print the new one once')
1616
+ .option('--json', 'Output as JSON')
1617
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1618
+ .action(async (destinationId, opts) => {
1619
+ const { runSiemRotateSecret } = await import('./commands/siem.js');
1620
+ await runSiemRotateSecret(destinationId, opts);
1621
+ });
1622
+ const complianceCmd = program
1623
+ .command('compliance')
1624
+ .description('Compliance framework reports and the evidence archive');
1625
+ complianceCmd
1626
+ .command('coverage <framework_id>')
1627
+ .description('Coverage of eu_ai_act, iso_42001, nist_ai_rmf or mitre_atlas from the latest probe results')
1628
+ .option('--format <format>', 'Download the report: json, md, csv or pdf')
1629
+ .option('--out <path>', 'Write the report to this file instead of stdout')
1630
+ .option('--json', 'Output as JSON')
1631
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1632
+ .action(async (frameworkId, opts) => {
1633
+ const { runComplianceCoverage } = await import('./commands/compliance.js');
1634
+ await runComplianceCoverage(frameworkId, opts);
1635
+ });
1636
+ complianceCmd
1637
+ .command('collect')
1638
+ .description('Run a fresh evidence collection and seal it into an archive (OWNER, ADMIN)')
1639
+ .option('--from <date>', 'Start of the evidence period, ISO 8601 (default: 90 days before --to)')
1640
+ .option('--to <date>', 'End of the evidence period, ISO 8601 (default: now)')
1641
+ .option('--out <path>', 'Also write the archive to this file')
1642
+ .option('--json', 'Output as JSON')
1643
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1644
+ .action(async (opts) => {
1645
+ const { runComplianceCollect } = await import('./commands/compliance.js');
1646
+ await runComplianceCollect(opts);
1647
+ });
1648
+ complianceCmd
1649
+ .command('download <run_id>')
1650
+ .description('Download a stored evidence archive (OWNER, ADMIN)')
1651
+ .option('--out <path>', 'Write the archive to this file instead of stdout')
1652
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1653
+ .action(async (runId, opts) => {
1654
+ const { runComplianceDownload } = await import('./commands/compliance.js');
1655
+ await runComplianceDownload(runId, opts);
1656
+ });
1657
+ complianceCmd
1658
+ .command('verify <file>')
1659
+ .description('Check an evidence archive\'s hashes and signature offline')
1660
+ .option('--jwks <path>', 'The published signing keys, saved from /.well-known/intutic-trace-signing.json (default: fetch them)')
1661
+ .option('--json', 'Output as JSON')
1662
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1663
+ .action(async (file, opts) => {
1664
+ const { runComplianceVerify } = await import('./commands/compliance.js');
1665
+ await runComplianceVerify(file, opts);
1666
+ });
1667
+ const usageCmd = program
1668
+ .command('usage')
1669
+ .description('LLM usage across the fleet, by member, team, branch, commit or pull request');
1670
+ for (const [view, handler, desc] of [
1671
+ ['members', 'runUsageMembers', 'Usage per member'],
1672
+ ['teams', 'runUsageTeams', 'Usage per team (SCIM group)'],
1673
+ ['branches', 'runUsageBranches', 'Usage per repository and branch'],
1674
+ ['commits', 'runUsageCommits', 'Usage per HEAD commit'],
1675
+ ]) {
1676
+ usageCmd
1677
+ .command(view)
1678
+ .description(desc)
1679
+ .option('--period <period>', 'daily (today) or monthly (this month)', 'monthly')
1680
+ .option('--json', 'Output as JSON')
1681
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1682
+ .action(async (opts) => {
1683
+ const usage = await import('./commands/usage.js');
1684
+ await usage[handler](opts);
1685
+ });
1686
+ }
1687
+ usageCmd
1688
+ .command('pull-requests')
1689
+ .description('Usage per GitHub pull request')
1690
+ .option('--period <period>', 'daily (today) or monthly (this month)', 'monthly')
1691
+ .option('--refresh', 'Look the branches up on GitHub first (OWNER, ADMIN, EM)')
1692
+ .option('--json', 'Output as JSON')
1693
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1694
+ .action(async (opts) => {
1695
+ const { runUsagePullRequests } = await import('./commands/usage.js');
1696
+ await runUsagePullRequests(opts);
1697
+ });
1698
+ const githubWebhookCmd = program
1699
+ .command('github')
1700
+ .description('GitHub integration for cost per pull request')
1701
+ .command('webhook')
1702
+ .description('The pull-request webhook: payload URL and signing secret');
1703
+ githubWebhookCmd
1704
+ .command('show')
1705
+ .description('Show the payload URL and when the secret was made')
1706
+ .option('--json', 'Output as JSON')
1707
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1708
+ .action(async (opts) => {
1709
+ const { runGithubWebhookShow } = await import('./commands/github.js');
1710
+ await runGithubWebhookShow(opts);
1711
+ });
1712
+ githubWebhookCmd
1713
+ .command('rotate-secret')
1714
+ .description('Make the webhook, or replace its secret (printed once)')
1715
+ .option('--json', 'Output as JSON')
1716
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1717
+ .action(async (opts) => {
1718
+ const { runGithubWebhookRotateSecret } = await import('./commands/github.js');
1719
+ await runGithubWebhookRotateSecret(opts);
1720
+ });
1721
+ const inventoryCmd = program
1722
+ .command('inventory')
1723
+ .description('AI harnesses, MCP servers and skills on connected developer machines, governed or not');
1724
+ inventoryCmd
1725
+ .command('summary')
1726
+ .description('Counts of machines, harnesses, MCP servers and skills, and how many are ungoverned')
1727
+ .option('--json', 'Output as JSON')
1728
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1729
+ .action(async (opts) => {
1730
+ const { runInventorySummary } = await import('./commands/inventory.js');
1731
+ await runInventorySummary(opts);
1732
+ });
1733
+ inventoryCmd
1734
+ .command('devices')
1735
+ .description('Every machine that reports, with its id (what --device takes), counts and last report')
1736
+ .option('--json', 'Output as JSON')
1737
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1738
+ .action(async (opts) => {
1739
+ const { runInventoryDevices } = await import('./commands/inventory.js');
1740
+ await runInventoryDevices(opts);
1741
+ });
1742
+ for (const [view, handler, desc] of [
1743
+ ['harnesses', 'runInventoryHarnesses', 'Harnesses by machine, with gate state and status'],
1744
+ ['mcp-servers', 'runInventoryMcpServers', 'MCP servers by machine, wrapped by the MCP proxy or not'],
1745
+ ]) {
1746
+ inventoryCmd
1747
+ .command(view)
1748
+ .description(desc)
1749
+ .option('--status <status>', 'Only rows with this status')
1750
+ .option('--harness <harness>', 'Only rows for this harness')
1751
+ .option('--device <device_id>', 'Only rows from this machine')
1752
+ .option('--search <text>', 'Only rows whose name or hostname contains this text')
1753
+ .option('--csv', 'Download as CSV, the same file the dashboard exports')
1754
+ .option('--out <path>', 'With --csv: write to this file instead of stdout')
1755
+ .option('--json', 'Output as JSON')
1756
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1757
+ .action(async (opts) => {
1758
+ const inventory = await import('./commands/inventory.js');
1759
+ await inventory[handler](opts);
1760
+ });
1761
+ }
1762
+ inventoryCmd
1763
+ .command('skills')
1764
+ .description('Skill bundles by machine, with their content scan result')
1765
+ .option('--device <device_id>', 'Only rows from this machine')
1766
+ .option('--search <text>', 'Only rows whose name or hostname contains this text')
1767
+ .option('--json', 'Output as JSON')
1768
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1769
+ .action(async (opts) => {
1770
+ const { runInventorySkills } = await import('./commands/inventory.js');
1771
+ await runInventorySkills(opts);
1772
+ });
1773
+ inventoryCmd
1774
+ .command('disconnects')
1775
+ .description('Machines that ran `intutic disconnect`, newest first: what they disconnected, who and when')
1776
+ .option('--limit <n>', 'At most this many (default 100, at most 500)')
1777
+ .option('--json', 'Output as JSON')
1778
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1779
+ .action(async (opts) => {
1780
+ const { runInventoryDisconnects } = await import('./commands/inventory.js');
1781
+ await runInventoryDisconnects(opts);
1782
+ });
1783
+ program
1784
+ .command('gate-liveness')
1785
+ .description('Whether each installed harness\'s gate is reporting, and any open silent-gate alert')
1786
+ .option('--json', 'Output as JSON')
1787
+ .option('--dev', 'Use local control plane (http://localhost:3001)')
1788
+ .action(async (opts) => {
1789
+ const { runGateLiveness } = await import('./commands/gateLiveness.js');
1790
+ await runGateLiveness(opts);
1791
+ });
1231
1792
  program.parse();
1232
1793
  //# sourceMappingURL=cli.js.map