@intutic/cli 2.7.0 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -7
- package/dist/cli.js +188 -47
- package/dist/cli.js.map +1 -1
- package/dist/commands/apiCommand.d.ts +9 -0
- package/dist/commands/apiCommand.d.ts.map +1 -1
- package/dist/commands/apiCommand.js +21 -0
- package/dist/commands/apiCommand.js.map +1 -1
- package/dist/commands/budget.d.ts.map +1 -1
- package/dist/commands/budget.js +6 -7
- package/dist/commands/budget.js.map +1 -1
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +21 -62
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/doctor.d.ts +4 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +30 -14
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/exec.js +1 -1
- package/dist/commands/exec.js.map +1 -1
- package/dist/commands/guardrails.d.ts.map +1 -1
- package/dist/commands/guardrails.js +2 -18
- package/dist/commands/guardrails.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +5 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/keys.d.ts +40 -0
- package/dist/commands/keys.d.ts.map +1 -0
- package/dist/commands/keys.js +105 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/optimizer.d.ts +26 -0
- package/dist/commands/optimizer.d.ts.map +1 -0
- package/dist/commands/optimizer.js +54 -0
- package/dist/commands/optimizer.js.map +1 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +7 -2
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/skill.d.ts.map +1 -1
- package/dist/commands/skill.js +8 -9
- package/dist/commands/skill.js.map +1 -1
- package/dist/commands/sops.d.ts.map +1 -1
- package/dist/commands/sops.js +106 -27
- package/dist/commands/sops.js.map +1 -1
- package/dist/commands/status.js +2 -2
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/tasks.d.ts +36 -0
- package/dist/commands/tasks.d.ts.map +1 -0
- package/dist/commands/tasks.js +75 -0
- package/dist/commands/tasks.js.map +1 -0
- package/dist/config/paths.d.ts +17 -1
- package/dist/config/paths.d.ts.map +1 -1
- package/dist/config/paths.js +25 -4
- package/dist/config/paths.js.map +1 -1
- package/dist/lib/onboarding.d.ts.map +1 -1
- package/dist/lib/onboarding.js +4 -2
- package/dist/lib/onboarding.js.map +1 -1
- package/dist/lib/sopFrontMatter.d.ts +26 -0
- package/dist/lib/sopFrontMatter.d.ts.map +1 -1
- package/dist/lib/sopFrontMatter.js +23 -0
- package/dist/lib/sopFrontMatter.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @intutic/cli
|
|
2
2
|
|
|
3
|
-
> AI governance
|
|
3
|
+
> AI governance for developer workspaces.
|
|
4
4
|
|
|
5
5
|
Intutic intercepts agent-to-LLM traffic, enforces SOPs, detects anomalies, and tracks costs — all without changing how your team codes.
|
|
6
6
|
|
|
@@ -21,6 +21,7 @@ intutic start # Run the proxy standalone — no account needed
|
|
|
21
21
|
intutic traces list # See governance verdicts
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
<!-- UNRELEASED:cloud
|
|
24
25
|
**With a control plane:**
|
|
25
26
|
|
|
26
27
|
```bash
|
|
@@ -29,6 +30,7 @@ intutic init # Detect harnesses, record them for sync
|
|
|
29
30
|
intutic connect # Start sync daemon — writes harness rules and gates
|
|
30
31
|
intutic traces list # See governance verdicts
|
|
31
32
|
```
|
|
33
|
+
-->
|
|
32
34
|
|
|
33
35
|
## Commands
|
|
34
36
|
|
|
@@ -36,13 +38,17 @@ intutic traces list # See governance verdicts
|
|
|
36
38
|
|---------|-------------|
|
|
37
39
|
| `intutic init` | Initialize workspace — detect harnesses, record them in `~/.intutic/config.json` |
|
|
38
40
|
| `intutic start` | Start the proxy standalone — no account or control plane needed (`--port`, `--upstream-url`) |
|
|
41
|
+
| `intutic status` | Show workspace status — auth, harnesses, sync state |
|
|
42
|
+
| `intutic disconnect` | Undo `intutic connect` — restore the harness configs it changed, remove its services, log out (`--harness`, `--dry-run`, `--keep-login`) |
|
|
43
|
+
| `intutic doctor` | Diagnose workspace health — proxy, auth, daemon, configs, logs |
|
|
44
|
+
| `intutic traces list` | List execution traces (`--limit`, `--since`, `--action` with a control plane, `--verdict` without one, `--model`, `--json`) |
|
|
45
|
+
| `intutic traces inspect <id>` | Show full detail of a single trace |
|
|
46
|
+
<!-- UNRELEASED:cloud
|
|
39
47
|
| `intutic login` | Authenticate with control plane (`--api-key`, `--control-plane-url`, `--dev`) |
|
|
40
48
|
| `intutic logout` | Clear stored credentials |
|
|
41
|
-
| `intutic status` | Show workspace status — auth, harnesses, sync state |
|
|
42
49
|
| `intutic whoami` | Show current authenticated identity |
|
|
43
50
|
| `intutic connect` | Start sync daemon — bidirectional config sync (`--interval`) |
|
|
44
|
-
|
|
45
|
-
| `intutic traces inspect <id>` | Show full detail of a single trace |
|
|
51
|
+
-->
|
|
46
52
|
|
|
47
53
|
## Supported Harnesses
|
|
48
54
|
|
|
@@ -58,7 +64,7 @@ Intutic auto-detects and configures AI coding harnesses, among them:
|
|
|
58
64
|
| **n8n** | Running n8n instance (`N8N_URL`, default `http://localhost:5678`) | Workflow JSON file + external hook gate `~/.intutic/hooks/n8n-governance-hook.js` |
|
|
59
65
|
| **OpenClaw** | `~/.openclaw/` or `.openclaw/openclaw.json` | `AGENTS.md` section in its agent workspace + `~/.intutic/hooks/openclaw/intutic-governance.cjs` (plugin gate, listed in `~/.openclaw/openclaw.json`) |
|
|
60
66
|
| **Hermes** | `~/.hermes/` or `.hermes/config.yaml` | `AGENTS.md` section + `hooks.pre_tool_call` gate in `~/.hermes/config.yaml` |
|
|
61
|
-
| **OpenCode** | `.opencode/`, `opencode.json`, `~/.config/opencode/` or `opencode` on PATH | `AGENTS.md` + `.opencode/plugins/intutic-governance.js` (plugin gate) |
|
|
67
|
+
| **OpenCode** | `.opencode/`, `opencode.json`, `~/.config/opencode/` or `opencode` on PATH | `AGENTS.md` + `.opencode/plugins/intutic-governance.js` (plugin gate; OpenCode 2.x: `.opencode/plugins/intutic-governance/index.js`) |
|
|
62
68
|
|
|
63
69
|
## Trace Inspection
|
|
64
70
|
|
|
@@ -68,13 +74,16 @@ View governance verdicts directly from the terminal:
|
|
|
68
74
|
# List recent traces (last 24h)
|
|
69
75
|
intutic traces list
|
|
70
76
|
|
|
71
|
-
# Filter by enforcement action
|
|
77
|
+
# Filter by enforcement action (connected to a control plane)
|
|
72
78
|
intutic traces list --action KILL
|
|
73
79
|
|
|
80
|
+
# Filter by the proxy's verdict (standalone: `intutic start`, no login)
|
|
81
|
+
intutic traces list --verdict killed
|
|
82
|
+
|
|
74
83
|
# Filter by model and time window
|
|
75
84
|
intutic traces list --model claude-4 --since 7d
|
|
76
85
|
|
|
77
|
-
# JSON output for scripting
|
|
86
|
+
# JSON output for scripting (connected; standalone rows carry `.verdict`)
|
|
78
87
|
intutic traces list --json | jq '.traces[] | select(.enforcementAction == "HIJACK")'
|
|
79
88
|
|
|
80
89
|
# Inspect a specific trace
|
|
@@ -93,6 +102,7 @@ Credentials are stored at `~/.intutic/credentials.json` (mode `0600`).
|
|
|
93
102
|
| `INTUTIC_DEV` | `1` targets the local control plane (`http://localhost:3001`), like `--dev` |
|
|
94
103
|
| `INTUTIC_PROXY_URL` | Local proxy URL; its port is the proxy port (default `4000`) |
|
|
95
104
|
|
|
105
|
+
<!-- UNRELEASED:cloud
|
|
96
106
|
For non-interactive auth, use `intutic login --api-key vk_...`.
|
|
97
107
|
|
|
98
108
|
### Development Mode
|
|
@@ -104,6 +114,7 @@ intutic login --dev
|
|
|
104
114
|
intutic connect --dev
|
|
105
115
|
intutic traces list --dev
|
|
106
116
|
```
|
|
117
|
+
-->
|
|
107
118
|
|
|
108
119
|
## Documentation
|
|
109
120
|
|
package/dist/cli.js
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module
|
|
11
11
|
*/
|
|
12
|
-
import { Command } from 'commander';
|
|
12
|
+
import { Command, Option } from 'commander';
|
|
13
13
|
import { createRequire } from 'node:module';
|
|
14
|
+
import { CLOUD_RELEASED, CONTROL_PLANE_PRODUCT_RELEASED, HOSTED_CONTROL_PLANE_URL, SELF_HOST_RELEASED, } from '@intutic/shared-types';
|
|
14
15
|
import { DEFAULT_SANDBOX_IMAGE } from './lib/sandbox/image.js';
|
|
15
16
|
// Read the version from package.json rather than repeating it here. The literal
|
|
16
17
|
// that used to live below said 1.6.0 for three releases running, so
|
|
@@ -20,13 +21,37 @@ import { DEFAULT_SANDBOX_IMAGE } from './lib/sandbox/image.js';
|
|
|
20
21
|
// but JSON imports still need an assertion on older runtimes.
|
|
21
22
|
const { version } = createRequire(import.meta.url)('../package.json');
|
|
22
23
|
const program = new Command();
|
|
24
|
+
// Release flags (packages/shared-types/src/release.ts). A command that only
|
|
25
|
+
// works against a control plane, or only in the self-hosted distribution, is
|
|
26
|
+
// left out of help until that product is released. Hidden is all it is: the
|
|
27
|
+
// command still parses and runs, so staging and existing users are unaffected.
|
|
28
|
+
const needsControlPlane = { hidden: !CONTROL_PLANE_PRODUCT_RELEASED };
|
|
29
|
+
const needsSelfHost = { hidden: !SELF_HOST_RELEASED };
|
|
30
|
+
/** An option of a visible command that only does anything against a control plane. */
|
|
31
|
+
function controlPlaneOption(flags, description) {
|
|
32
|
+
const option = new Option(flags, description);
|
|
33
|
+
return CONTROL_PLANE_PRODUCT_RELEASED ? option : option.hideHelp();
|
|
34
|
+
}
|
|
35
|
+
// A command that needs a control plane, run with none configured, throws
|
|
36
|
+
// NoControlPlaneError (config/paths.ts) from an async action. Say that plainly
|
|
37
|
+
// rather than as an unhandled rejection with a stack; anything else still
|
|
38
|
+
// crashes as before.
|
|
39
|
+
process.on('unhandledRejection', (err) => {
|
|
40
|
+
if (err instanceof Error && err.name === 'NoControlPlaneError') {
|
|
41
|
+
console.error(err.message);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
throw err;
|
|
45
|
+
});
|
|
23
46
|
// Positional options: `--version` and `--help` belong to the program only when
|
|
24
47
|
// they come before a subcommand. Without this, commander matches program
|
|
25
48
|
// options anywhere on the line, so a subcommand option named `--version` would
|
|
26
49
|
// print the CLI version and exit before its command ever saw it.
|
|
27
50
|
program
|
|
28
51
|
.name('intutic')
|
|
29
|
-
.description(
|
|
52
|
+
.description(CONTROL_PLANE_PRODUCT_RELEASED
|
|
53
|
+
? 'Intutic CLI — AI governance control plane for developer workspaces'
|
|
54
|
+
: 'Intutic CLI — open-core AI governance for developer workspaces: a local proxy, gates and policy for coding agents')
|
|
30
55
|
.version(version)
|
|
31
56
|
.enablePositionalOptions();
|
|
32
57
|
program
|
|
@@ -49,7 +74,7 @@ program
|
|
|
49
74
|
await runSetup(opts);
|
|
50
75
|
});
|
|
51
76
|
const judgeCmd = program
|
|
52
|
-
.command('judge')
|
|
77
|
+
.command('judge', needsSelfHost)
|
|
53
78
|
.description('Configure the LLM-as-judge path');
|
|
54
79
|
judgeCmd
|
|
55
80
|
.command('configure')
|
|
@@ -60,7 +85,7 @@ judgeCmd
|
|
|
60
85
|
await runJudgeConfigure(opts);
|
|
61
86
|
});
|
|
62
87
|
program
|
|
63
|
-
.command('login')
|
|
88
|
+
.command('login', needsControlPlane)
|
|
64
89
|
.description('Authenticate with the Intutic control plane')
|
|
65
90
|
.option('--api-key <key>', 'Authenticate with an API key (vk_*)')
|
|
66
91
|
.option('--control-plane-url <url>', 'Control plane to log in to (e.g. a self-hosted one); saved for every later command')
|
|
@@ -80,7 +105,7 @@ program
|
|
|
80
105
|
await runDisconnect({ harness: opts.harness, dryRun: opts.dryRun, keepLogin: opts.keepLogin });
|
|
81
106
|
});
|
|
82
107
|
program
|
|
83
|
-
.command('logout')
|
|
108
|
+
.command('logout', needsControlPlane)
|
|
84
109
|
.description('Clear stored credentials')
|
|
85
110
|
.action(async () => {
|
|
86
111
|
const { runLogout } = await import('./commands/logout.js');
|
|
@@ -111,7 +136,9 @@ program
|
|
|
111
136
|
});
|
|
112
137
|
const budgetCmd = program
|
|
113
138
|
.command('budget')
|
|
114
|
-
.description(
|
|
139
|
+
.description(CONTROL_PLANE_PRODUCT_RELEASED
|
|
140
|
+
? 'Check remaining daily/monthly budget and list active loops; set workspace, key and member budgets'
|
|
141
|
+
: 'Check the local spending cap and what this machine has spent today')
|
|
115
142
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
116
143
|
.option('--watch', 'Continuously print machine-local and workspace spend, one line per tick')
|
|
117
144
|
.option('--interval <seconds>', 'Tick interval in seconds for --watch', String(5))
|
|
@@ -125,7 +152,7 @@ const budgetCmd = program
|
|
|
125
152
|
await runBudget(opts);
|
|
126
153
|
});
|
|
127
154
|
budgetCmd
|
|
128
|
-
.command('set')
|
|
155
|
+
.command('set', needsControlPlane)
|
|
129
156
|
.description("Set the workspace's daily and monthly caps, alert threshold and whether each cap refuses requests (OWNER, ADMIN)")
|
|
130
157
|
.option('--daily <usd>', 'Daily cap in USD (0: no daily cap; default: back to the $100 default)')
|
|
131
158
|
.option('--monthly <usd>', 'Monthly cap in USD (0: no monthly cap; default: back to the $500 default)')
|
|
@@ -141,7 +168,7 @@ budgetCmd
|
|
|
141
168
|
await runBudgetSet(cmd.optsWithGlobals());
|
|
142
169
|
});
|
|
143
170
|
budgetCmd
|
|
144
|
-
.command('keys')
|
|
171
|
+
.command('keys', needsControlPlane)
|
|
145
172
|
.description("Every virtual key's spend budgets, rate limit and spend today and this month")
|
|
146
173
|
.option('--json', 'Output as JSON')
|
|
147
174
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
@@ -150,7 +177,7 @@ budgetCmd
|
|
|
150
177
|
await runBudgetKeys(cmd.optsWithGlobals());
|
|
151
178
|
});
|
|
152
179
|
budgetCmd
|
|
153
|
-
.command('key <keyId>')
|
|
180
|
+
.command('key <keyId>', needsControlPlane)
|
|
154
181
|
.description("Set a virtual key's spend budgets and rate limit (OWNER, ADMIN)")
|
|
155
182
|
.option('--daily <usd>', 'Day budget in USD, or none to remove it')
|
|
156
183
|
.option('--monthly <usd>', 'Month budget in USD, or none to remove it')
|
|
@@ -165,7 +192,7 @@ budgetCmd
|
|
|
165
192
|
await runBudgetKey(keyId, cmd.optsWithGlobals());
|
|
166
193
|
});
|
|
167
194
|
budgetCmd
|
|
168
|
-
.command('members')
|
|
195
|
+
.command('members', needsControlPlane)
|
|
169
196
|
.description("The default member budget, and each member's budgets and spend (Biz Org+)")
|
|
170
197
|
.option('--json', 'Output as JSON')
|
|
171
198
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
@@ -174,7 +201,7 @@ budgetCmd
|
|
|
174
201
|
await runBudgetMembers(cmd.optsWithGlobals());
|
|
175
202
|
});
|
|
176
203
|
budgetCmd
|
|
177
|
-
.command('member <memberId>')
|
|
204
|
+
.command('member <memberId>', needsControlPlane)
|
|
178
205
|
.description("Set a member's spend budgets, or the default member budget with `default` (OWNER, ADMIN; Biz Org+)")
|
|
179
206
|
.option('--daily <usd>', 'Day budget in USD, or none to remove it')
|
|
180
207
|
.option('--monthly <usd>', 'Month budget in USD, or none to remove it')
|
|
@@ -187,7 +214,7 @@ budgetCmd
|
|
|
187
214
|
await runBudgetMember(memberId, cmd.optsWithGlobals());
|
|
188
215
|
});
|
|
189
216
|
program
|
|
190
|
-
.command('predict-cost')
|
|
217
|
+
.command('predict-cost', needsControlPlane)
|
|
191
218
|
.description('Pre-flight cost estimate for a prompt/task before it runs (requires `intutic login`). ' +
|
|
192
219
|
"Estimates output tokens from the workspace's recorded usage and prices them with the same " +
|
|
193
220
|
'rate table as every other cost figure the control plane reports.')
|
|
@@ -201,7 +228,7 @@ program
|
|
|
201
228
|
await runPredictCost(opts);
|
|
202
229
|
});
|
|
203
230
|
const sopsCmd = program
|
|
204
|
-
.command('sops')
|
|
231
|
+
.command('sops', needsControlPlane)
|
|
205
232
|
.description('Manage local and global SOP rules');
|
|
206
233
|
sopsCmd
|
|
207
234
|
.command('push <name>')
|
|
@@ -247,11 +274,35 @@ sopsCmd
|
|
|
247
274
|
const { runSopsOrgRm } = await import('./commands/sops.js');
|
|
248
275
|
await runSopsOrgRm(orgSopId, opts);
|
|
249
276
|
});
|
|
277
|
+
// ── SOP Optimizer approval mode ──────────────────────────────────────────
|
|
278
|
+
const optimizerCmd = program
|
|
279
|
+
.command('optimizer', needsControlPlane)
|
|
280
|
+
.description("Read and set the SOP Optimizer's approval mode (whether it may auto-apply strengthening proposals)");
|
|
281
|
+
optimizerCmd
|
|
282
|
+
.command('settings')
|
|
283
|
+
.description('Print the approval mode and the auto-apply threshold')
|
|
284
|
+
.option('--json', 'Output as JSON')
|
|
285
|
+
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
286
|
+
.action(async (opts) => {
|
|
287
|
+
const { runOptimizerSettings } = await import('./commands/optimizer.js');
|
|
288
|
+
await runOptimizerSettings(opts);
|
|
289
|
+
});
|
|
290
|
+
optimizerCmd
|
|
291
|
+
.command('set')
|
|
292
|
+
.description('Set the approval mode, and optionally the auto-apply threshold (OWNER, ADMIN)')
|
|
293
|
+
.requiredOption('--mode <mode>', 'manual (nothing is auto-applied) or auto')
|
|
294
|
+
.option('--auto-threshold <n>', 'Score from 0 to 1 a proposal needs to be auto-applied (default: keep the current one)')
|
|
295
|
+
.option('--json', 'Output as JSON')
|
|
296
|
+
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
297
|
+
.action(async (opts) => {
|
|
298
|
+
const { runOptimizerSet } = await import('./commands/optimizer.js');
|
|
299
|
+
await runOptimizerSet(opts);
|
|
300
|
+
});
|
|
250
301
|
const policyCmd = program
|
|
251
302
|
.command('policy')
|
|
252
|
-
.description('WASM rules and the policy snapshot');
|
|
303
|
+
.description(CONTROL_PLANE_PRODUCT_RELEASED ? 'WASM rules and the policy snapshot' : 'WASM rules: compile, test and install them locally');
|
|
253
304
|
policyCmd
|
|
254
|
-
.command('snapshot')
|
|
305
|
+
.command('snapshot', needsControlPlane)
|
|
255
306
|
.description('Compile workspace policy to ~/.intutic/hooks/policy-snapshot.rules — the file every gate reads.\n' +
|
|
256
307
|
'\n' +
|
|
257
308
|
' Does only that. \'intutic connect\' writes it too, but as one step of\n' +
|
|
@@ -274,10 +325,10 @@ policyCmd
|
|
|
274
325
|
.command('compile')
|
|
275
326
|
.description('Compile an AssemblyScript rule to WASM (wraps asc)')
|
|
276
327
|
.option('--src <path>', 'Rule source entry file (default: assembly/index.ts)')
|
|
277
|
-
.option('--out <path>',
|
|
328
|
+
.option('--out <path>', `Output .wasm path (default: build/rule.wasm${CONTROL_PLANE_PRODUCT_RELEASED ? ', or build/<candidate>.wasm with --candidate' : ''})`)
|
|
278
329
|
.option('--debug', 'Include debug info and source maps')
|
|
279
|
-
.
|
|
280
|
-
.
|
|
330
|
+
.addOption(controlPlaneOption('--candidate <id>', 'Compile a rule candidate from its source of record on the control plane (fetched and hash-verified; not with --src)'))
|
|
331
|
+
.addOption(controlPlaneOption('--upload', 'With --candidate: upload the bundle to the candidate with its source hash and print the gate results'))
|
|
281
332
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
282
333
|
.action(async (opts) => {
|
|
283
334
|
const { runPolicyCompile } = await import('./commands/policy.js');
|
|
@@ -301,7 +352,7 @@ policyCmd
|
|
|
301
352
|
await runPolicyListLocal();
|
|
302
353
|
});
|
|
303
354
|
policyCmd
|
|
304
|
-
.command('replay <ruleId>')
|
|
355
|
+
.command('replay <ruleId>', needsControlPlane)
|
|
305
356
|
.description("Replay a rule (installed or not) against this workspace's own recent traffic and report " +
|
|
306
357
|
'what it would have done, without touching enforcement.')
|
|
307
358
|
.option('--limit <n>', 'Max sampled contexts to replay against (default 500, capped at 5000)')
|
|
@@ -347,7 +398,7 @@ rulesCmd
|
|
|
347
398
|
// `intutic sops` is files on disk; this namespace is the cited guardrails
|
|
348
399
|
// extracted from policy documents and their shadow -> promote lifecycle.
|
|
349
400
|
const guardrailsCmd = program
|
|
350
|
-
.command('guardrails')
|
|
401
|
+
.command('guardrails', needsControlPlane)
|
|
351
402
|
.description('Policy documents, cited clauses and the guardrails compiled from them');
|
|
352
403
|
const guardrailsSourcesCmd = guardrailsCmd
|
|
353
404
|
.command('sources')
|
|
@@ -590,7 +641,7 @@ guardrailsCmd
|
|
|
590
641
|
await runGuardrailsPull(opts);
|
|
591
642
|
});
|
|
592
643
|
program
|
|
593
|
-
.command('whoami')
|
|
644
|
+
.command('whoami', needsControlPlane)
|
|
594
645
|
.description('Show current authenticated identity')
|
|
595
646
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
596
647
|
.action(async (opts) => {
|
|
@@ -633,7 +684,7 @@ for (const [action, desc] of [
|
|
|
633
684
|
});
|
|
634
685
|
}
|
|
635
686
|
enforceCmd
|
|
636
|
-
.command('report')
|
|
687
|
+
.command('report', needsControlPlane)
|
|
637
688
|
.description('Report locally recorded enforcement state (firewall/CA-trust/system-hooks) to the control plane. ' +
|
|
638
689
|
'No privilege needed — for when apply/remove ran elevated and could not reach stored credentials.')
|
|
639
690
|
.action(async () => {
|
|
@@ -646,7 +697,7 @@ enforceCmd
|
|
|
646
697
|
// tools/scripts/intutic-enterprise-install.sh, an unrelated air-gapped
|
|
647
698
|
// docker-compose installer. Does not touch the host firewall; see `enforce`.
|
|
648
699
|
const enterpriseCmd = program
|
|
649
|
-
.command('enterprise')
|
|
700
|
+
.command('enterprise', needsControlPlane)
|
|
650
701
|
.description('Enterprise fleet rollout: CA trust, Cursor system hooks, MDM manifests');
|
|
651
702
|
enterpriseCmd
|
|
652
703
|
.command('install')
|
|
@@ -685,7 +736,7 @@ envCmd
|
|
|
685
736
|
await runEnvClear();
|
|
686
737
|
});
|
|
687
738
|
program
|
|
688
|
-
.command('connect')
|
|
739
|
+
.command('connect', needsControlPlane)
|
|
689
740
|
.description('Start sync daemon — bidirectional config sync with control plane (requires an account)')
|
|
690
741
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
691
742
|
.option('--interval <ms>', 'Poll interval in milliseconds', '30000')
|
|
@@ -697,7 +748,7 @@ program
|
|
|
697
748
|
await runConnect(opts);
|
|
698
749
|
});
|
|
699
750
|
program
|
|
700
|
-
.command('sync-context')
|
|
751
|
+
.command('sync-context', needsControlPlane)
|
|
701
752
|
.description('Record the Git branch and commit in .intutic/git-context.json, which a running `intutic connect` reports')
|
|
702
753
|
.option('--git', 'Read the branch and commit from the repository (for any not given below)')
|
|
703
754
|
.option('--branch <name>', 'Current Git branch name')
|
|
@@ -707,7 +758,7 @@ program
|
|
|
707
758
|
await runSyncContext(opts);
|
|
708
759
|
});
|
|
709
760
|
program
|
|
710
|
-
.command('decisions-log-refresh')
|
|
761
|
+
.command('decisions-log-refresh', needsControlPlane)
|
|
711
762
|
.description('One-shot refresh of the governed decisions log (.intutic/DECISIONS.md, and the recent ' +
|
|
712
763
|
'entries in each governed harness\'s instructions file) — no-ops if decisionsLogEnabled is off. Invoked by the optional ' +
|
|
713
764
|
'post-merge Git hook `intutic init` installs; safe to run manually.')
|
|
@@ -809,7 +860,7 @@ traces
|
|
|
809
860
|
});
|
|
810
861
|
// ── Findings (detector_findings adjudication) ───────────────────────────────
|
|
811
862
|
const findings = program
|
|
812
|
-
.command('findings')
|
|
863
|
+
.command('findings', needsControlPlane)
|
|
813
864
|
.description('Query and adjudicate detector findings — the TP/FP labeling surface');
|
|
814
865
|
findings
|
|
815
866
|
.command('list')
|
|
@@ -856,7 +907,7 @@ findings
|
|
|
856
907
|
});
|
|
857
908
|
// ── Governance incidents ───────────────────────────────────────────────────
|
|
858
909
|
const incidentsCmd = program
|
|
859
|
-
.command('incidents')
|
|
910
|
+
.command('incidents', needsControlPlane)
|
|
860
911
|
.description('Governance incidents, as on Findings › Incidents (OWNER, ADMIN, EM)');
|
|
861
912
|
incidentsCmd
|
|
862
913
|
.command('list')
|
|
@@ -883,7 +934,7 @@ incidentsCmd
|
|
|
883
934
|
});
|
|
884
935
|
// ── Trace integrity ────────────────────────────────────────────────────────
|
|
885
936
|
const integrity = program
|
|
886
|
-
.command('integrity')
|
|
937
|
+
.command('integrity', needsControlPlane)
|
|
887
938
|
.description('Verify sealed trace roots — list, re-derive, walk the root chain, and walk the config snapshot chain');
|
|
888
939
|
integrity
|
|
889
940
|
.command('roots')
|
|
@@ -926,7 +977,7 @@ integrity
|
|
|
926
977
|
});
|
|
927
978
|
// ── Routing reports ─────────────────────────────────────────────────────────
|
|
928
979
|
const routing = program
|
|
929
|
-
.command('routing')
|
|
980
|
+
.command('routing', needsControlPlane)
|
|
930
981
|
.description('Read-only reports for the routing subsystem');
|
|
931
982
|
routing
|
|
932
983
|
.command('adoption-report')
|
|
@@ -965,7 +1016,7 @@ function defineDaemonInstall(cmd) {
|
|
|
965
1016
|
' Use \'intutic daemon stop\' or \'intutic daemon uninstall\'.')
|
|
966
1017
|
.option('--workspace-id <id>', 'Workspace ID (e.g. wk_xxxx) — required unless --proxy')
|
|
967
1018
|
.option('--api-key <key>', 'Workspace API key (e.g. vk_xxxx) — required unless --proxy')
|
|
968
|
-
.option('--control-plane-url <url>',
|
|
1019
|
+
.option('--control-plane-url <url>', `Control plane the daemon connects to (default: $INTUTIC_CONTROL_PLANE_URL, then a workspace set up with \`intutic init --dev\`, then the URL saved by \`intutic login\`${CLOUD_RELEASED ? `, then ${HOSTED_CONTROL_PLANE_URL}` : ''})`)
|
|
969
1020
|
.option('--binary-path <path>', 'Path to intutic CLI binary (defaults to current process); with --proxy, absolute path to intutic-proxy')
|
|
970
1021
|
.option('--dry-run', 'Print what would be done without writing files')
|
|
971
1022
|
.option('--system', 'Install as a system-level service (LaunchDaemon on macOS, systemd system unit on Linux)')
|
|
@@ -1098,7 +1149,7 @@ skillCmd
|
|
|
1098
1149
|
});
|
|
1099
1150
|
// ── Loop commands ──────────────────────────────────────────────────────────
|
|
1100
1151
|
const loopCmd = program
|
|
1101
|
-
.command('loop')
|
|
1152
|
+
.command('loop', needsControlPlane)
|
|
1102
1153
|
.description('Manage and execute recursive agent loops with budget limits');
|
|
1103
1154
|
loopCmd
|
|
1104
1155
|
.command('start')
|
|
@@ -1166,7 +1217,7 @@ loopCmd
|
|
|
1166
1217
|
// module doc for why `intutic loop review` was never the right command for
|
|
1167
1218
|
// this — it addresses a different id space (Loop Runs, not decisions).
|
|
1168
1219
|
const decisionCmd = program
|
|
1169
|
-
.command('decision')
|
|
1220
|
+
.command('decision', needsControlPlane)
|
|
1170
1221
|
.description('Approve or reject a decision (e.g. a review_before hold) held for human review');
|
|
1171
1222
|
decisionCmd
|
|
1172
1223
|
.command('approve <holdId>')
|
|
@@ -1192,7 +1243,7 @@ decisionCmd
|
|
|
1192
1243
|
// hand-written curl against services/control-plane/src/routes/gateways.ts —
|
|
1193
1244
|
// see commands/gateway.ts's module doc.
|
|
1194
1245
|
const gatewayCmd = program
|
|
1195
|
-
.command('gateway')
|
|
1246
|
+
.command('gateway', needsControlPlane)
|
|
1196
1247
|
.description('Manage self-hosted gateway registrations (Docker / Kubernetes / bare metal)');
|
|
1197
1248
|
gatewayCmd
|
|
1198
1249
|
.command('register')
|
|
@@ -1290,7 +1341,7 @@ gatewayCmd
|
|
|
1290
1341
|
// Provision a workspace's own upstream provider keys — the BYO-key wizard's
|
|
1291
1342
|
// API, previously dashboard-only. See commands/credentials.ts's module doc.
|
|
1292
1343
|
const credentialsCmd = program
|
|
1293
|
-
.command('credentials')
|
|
1344
|
+
.command('credentials', needsControlPlane)
|
|
1294
1345
|
.description('Manage this workspace\'s own upstream provider API keys (BYO-key)');
|
|
1295
1346
|
credentialsCmd
|
|
1296
1347
|
.command('list')
|
|
@@ -1334,7 +1385,7 @@ credentialsCmd
|
|
|
1334
1385
|
// "CLI mints, dashboard audits": this is the mint/inspect half. See
|
|
1335
1386
|
// commands/attenuate.ts's module doc.
|
|
1336
1387
|
const attenuateCmd = program
|
|
1337
|
-
.command('attenuate')
|
|
1388
|
+
.command('attenuate', needsControlPlane)
|
|
1338
1389
|
.description('Attenuate one of your API keys to a child key with narrower scopes (and an optional TTL)')
|
|
1339
1390
|
.option('--parent-key <keyId>', 'Parent API key ID to attenuate')
|
|
1340
1391
|
.option('--caps <scopes>', 'Comma-separated API key scopes for the child key (e.g. gateway:use,traces:read); each must be granted by the parent key')
|
|
@@ -1352,9 +1403,54 @@ attenuateCmd
|
|
|
1352
1403
|
const { runAttenuateChain } = await import('./commands/attenuate.js');
|
|
1353
1404
|
await runAttenuateChain(chainId, opts);
|
|
1354
1405
|
});
|
|
1406
|
+
// ── API keys and their scopes ────────────────────────────────────────────
|
|
1407
|
+
const keysCmd = program
|
|
1408
|
+
.command('keys', needsControlPlane)
|
|
1409
|
+
.description('List, create, re-scope and revoke your API keys');
|
|
1410
|
+
keysCmd
|
|
1411
|
+
.command('list')
|
|
1412
|
+
.description('List your API keys with their scopes and expiry')
|
|
1413
|
+
.option('--json', 'Output as JSON')
|
|
1414
|
+
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
1415
|
+
.action(async (opts) => {
|
|
1416
|
+
const { runKeysList } = await import('./commands/keys.js');
|
|
1417
|
+
await runKeysList(opts);
|
|
1418
|
+
});
|
|
1419
|
+
keysCmd
|
|
1420
|
+
.command('create')
|
|
1421
|
+
.description('Create an API key and print it once')
|
|
1422
|
+
.requiredOption('--label <label>', 'A name for the key')
|
|
1423
|
+
.option('--scopes <scopes>', 'Comma-separated API key scopes (default: *, everything your role allows)')
|
|
1424
|
+
.option('--expires-in-days <n>', 'Expire the key after this many days (1-365; default: never)')
|
|
1425
|
+
.option('--service-account', 'An automation key: exempt from the SSO idle-key check')
|
|
1426
|
+
.option('--json', 'Output as JSON')
|
|
1427
|
+
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
1428
|
+
.action(async (opts) => {
|
|
1429
|
+
const { runKeysCreate } = await import('./commands/keys.js');
|
|
1430
|
+
await runKeysCreate(opts);
|
|
1431
|
+
});
|
|
1432
|
+
keysCmd
|
|
1433
|
+
.command('update <keyId>')
|
|
1434
|
+
.description("Replace a key's scopes (OWNER, ADMIN)")
|
|
1435
|
+
.requiredOption('--scopes <scopes>', 'Comma-separated API key scopes the key will hold')
|
|
1436
|
+
.option('--json', 'Output as JSON')
|
|
1437
|
+
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
1438
|
+
.action(async (keyId, opts) => {
|
|
1439
|
+
const { runKeysUpdate } = await import('./commands/keys.js');
|
|
1440
|
+
await runKeysUpdate(keyId, opts);
|
|
1441
|
+
});
|
|
1442
|
+
keysCmd
|
|
1443
|
+
.command('revoke <keyId>')
|
|
1444
|
+
.description('Revoke one of your API keys')
|
|
1445
|
+
.option('--json', 'Output as JSON')
|
|
1446
|
+
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
1447
|
+
.action(async (keyId, opts) => {
|
|
1448
|
+
const { runKeysRevoke } = await import('./commands/keys.js');
|
|
1449
|
+
await runKeysRevoke(keyId, opts);
|
|
1450
|
+
});
|
|
1355
1451
|
// ── Org signup + team management ─────────────────────────────────────────
|
|
1356
1452
|
const orgCmd = program
|
|
1357
|
-
.command('org')
|
|
1453
|
+
.command('org', needsControlPlane)
|
|
1358
1454
|
.description('Create and manage orgs');
|
|
1359
1455
|
orgCmd
|
|
1360
1456
|
.command('create')
|
|
@@ -1369,7 +1465,7 @@ orgCmd
|
|
|
1369
1465
|
await runOrgCreate(opts);
|
|
1370
1466
|
});
|
|
1371
1467
|
const teamCmd = program
|
|
1372
|
-
.command('team')
|
|
1468
|
+
.command('team', needsControlPlane)
|
|
1373
1469
|
.description('Manage teams and workspaces under an org');
|
|
1374
1470
|
teamCmd
|
|
1375
1471
|
.command('list')
|
|
@@ -1418,7 +1514,7 @@ teamCmd
|
|
|
1418
1514
|
// route. Previously dashboard-only. See commands/apiCommand.ts for the shape
|
|
1419
1515
|
// they share.
|
|
1420
1516
|
const settingsCmd = program
|
|
1421
|
-
.command('settings')
|
|
1517
|
+
.command('settings', needsControlPlane)
|
|
1422
1518
|
.description('Read and change workspace settings (MCP policy, budgets, group policy, config content upload, ...)');
|
|
1423
1519
|
settingsCmd
|
|
1424
1520
|
.command('get [key]')
|
|
@@ -1440,7 +1536,7 @@ settingsCmd
|
|
|
1440
1536
|
await runSettingsSet(key, value, opts);
|
|
1441
1537
|
});
|
|
1442
1538
|
const mcpCmd = program
|
|
1443
|
-
.command('mcp')
|
|
1539
|
+
.command('mcp', needsControlPlane)
|
|
1444
1540
|
.description('Review the MCP servers the workspace\'s MCP proxies have seen, and decide on them');
|
|
1445
1541
|
mcpCmd
|
|
1446
1542
|
.command('list')
|
|
@@ -1481,7 +1577,7 @@ for (const [action, enabled, desc] of [
|
|
|
1481
1577
|
});
|
|
1482
1578
|
}
|
|
1483
1579
|
const notificationsCmd = program
|
|
1484
|
-
.command('notifications')
|
|
1580
|
+
.command('notifications', needsControlPlane)
|
|
1485
1581
|
.description('Manage notification rules: which events go to Slack, email, a webhook or PagerDuty');
|
|
1486
1582
|
function ruleOptions(cmd) {
|
|
1487
1583
|
return cmd
|
|
@@ -1543,7 +1639,7 @@ notificationsCmd
|
|
|
1543
1639
|
await runNotificationsRotateSecret(ruleId, opts);
|
|
1544
1640
|
});
|
|
1545
1641
|
const siemCmd = program
|
|
1546
|
-
.command('siem')
|
|
1642
|
+
.command('siem', needsControlPlane)
|
|
1547
1643
|
.description('Manage SIEM export destinations and the event sources each receives');
|
|
1548
1644
|
function destinationOptions(cmd) {
|
|
1549
1645
|
return cmd
|
|
@@ -1617,8 +1713,53 @@ siemCmd
|
|
|
1617
1713
|
const { runSiemRotateSecret } = await import('./commands/siem.js');
|
|
1618
1714
|
await runSiemRotateSecret(destinationId, opts);
|
|
1619
1715
|
});
|
|
1716
|
+
const tasksCmd = program
|
|
1717
|
+
.command('tasks', needsControlPlane)
|
|
1718
|
+
.description('Manage task-management connections (Jira Cloud, Linear, PagerDuty) that attach ticket context to sessions');
|
|
1719
|
+
tasksCmd
|
|
1720
|
+
.command('list')
|
|
1721
|
+
.description('List task-management connections (tokens are never returned)')
|
|
1722
|
+
.option('--json', 'Output as JSON')
|
|
1723
|
+
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
1724
|
+
.action(async (opts) => {
|
|
1725
|
+
const { runTasksList } = await import('./commands/tasks.js');
|
|
1726
|
+
await runTasksList(opts);
|
|
1727
|
+
});
|
|
1728
|
+
tasksCmd
|
|
1729
|
+
.command('add')
|
|
1730
|
+
.description('Connect Jira Cloud, Linear or PagerDuty; the API token is read from --token or --token-file, never echoed')
|
|
1731
|
+
.requiredOption('--provider <provider>', 'jira, linear or pagerduty')
|
|
1732
|
+
.requiredOption('--base-url <url>', 'The provider\'s base URL (e.g. https://acme.atlassian.net)')
|
|
1733
|
+
.requiredOption('--project-key <key>', 'Jira project key, Linear team key or PagerDuty service key')
|
|
1734
|
+
.option('--account-email <email>', 'Jira only (required): the Atlassian account the API token belongs to')
|
|
1735
|
+
.option('--token <token>', 'Provider API token')
|
|
1736
|
+
.option('--token-file <path>', 'Read the API token from a file')
|
|
1737
|
+
.option('--json', 'Output as JSON')
|
|
1738
|
+
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
1739
|
+
.action(async (opts) => {
|
|
1740
|
+
const { runTasksAdd } = await import('./commands/tasks.js');
|
|
1741
|
+
await runTasksAdd(opts);
|
|
1742
|
+
});
|
|
1743
|
+
tasksCmd
|
|
1744
|
+
.command('test <connectionId>')
|
|
1745
|
+
.description('Check that the provider still accepts a connection\'s stored credentials')
|
|
1746
|
+
.option('--json', 'Output as JSON')
|
|
1747
|
+
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
1748
|
+
.action(async (connectionId, opts) => {
|
|
1749
|
+
const { runTasksTest } = await import('./commands/tasks.js');
|
|
1750
|
+
await runTasksTest(connectionId, opts);
|
|
1751
|
+
});
|
|
1752
|
+
tasksCmd
|
|
1753
|
+
.command('remove <connectionId>')
|
|
1754
|
+
.description('Remove a task-management connection and its stored token')
|
|
1755
|
+
.option('--json', 'Output as JSON')
|
|
1756
|
+
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
1757
|
+
.action(async (connectionId, opts) => {
|
|
1758
|
+
const { runTasksRemove } = await import('./commands/tasks.js');
|
|
1759
|
+
await runTasksRemove(connectionId, opts);
|
|
1760
|
+
});
|
|
1620
1761
|
const complianceCmd = program
|
|
1621
|
-
.command('compliance')
|
|
1762
|
+
.command('compliance', needsControlPlane)
|
|
1622
1763
|
.description('Compliance framework reports and the evidence archive');
|
|
1623
1764
|
complianceCmd
|
|
1624
1765
|
.command('coverage <framework_id>')
|
|
@@ -1663,7 +1804,7 @@ complianceCmd
|
|
|
1663
1804
|
await runComplianceVerify(file, opts);
|
|
1664
1805
|
});
|
|
1665
1806
|
const usageCmd = program
|
|
1666
|
-
.command('usage')
|
|
1807
|
+
.command('usage', needsControlPlane)
|
|
1667
1808
|
.description('LLM usage across the fleet, by member, team, branch, commit or pull request');
|
|
1668
1809
|
for (const [view, handler, desc] of [
|
|
1669
1810
|
['members', 'runUsageMembers', 'Usage per member'],
|
|
@@ -1694,7 +1835,7 @@ usageCmd
|
|
|
1694
1835
|
await runUsagePullRequests(opts);
|
|
1695
1836
|
});
|
|
1696
1837
|
const githubWebhookCmd = program
|
|
1697
|
-
.command('github')
|
|
1838
|
+
.command('github', needsControlPlane)
|
|
1698
1839
|
.description('GitHub integration for cost per pull request')
|
|
1699
1840
|
.command('webhook')
|
|
1700
1841
|
.description('The pull-request webhook: payload URL and signing secret');
|
|
@@ -1717,7 +1858,7 @@ githubWebhookCmd
|
|
|
1717
1858
|
await runGithubWebhookRotateSecret(opts);
|
|
1718
1859
|
});
|
|
1719
1860
|
const inventoryCmd = program
|
|
1720
|
-
.command('inventory')
|
|
1861
|
+
.command('inventory', needsControlPlane)
|
|
1721
1862
|
.description('AI harnesses, MCP servers and skills on connected developer machines, governed or not');
|
|
1722
1863
|
inventoryCmd
|
|
1723
1864
|
.command('summary')
|
|
@@ -1779,7 +1920,7 @@ inventoryCmd
|
|
|
1779
1920
|
await runInventoryDisconnects(opts);
|
|
1780
1921
|
});
|
|
1781
1922
|
program
|
|
1782
|
-
.command('gate-liveness')
|
|
1923
|
+
.command('gate-liveness', needsControlPlane)
|
|
1783
1924
|
.description('Whether each installed harness\'s gate is reporting, and any open silent-gate alert')
|
|
1784
1925
|
.option('--json', 'Output as JSON')
|
|
1785
1926
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|