@intutic/cli 2.8.0 → 2.9.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.
- package/README.md +20 -10
- package/dist/cli.js +100 -51
- package/dist/cli.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 +2 -26
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +5 -54
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/disconnect.d.ts +7 -4
- package/dist/commands/disconnect.d.ts.map +1 -1
- package/dist/commands/disconnect.js +28 -15
- package/dist/commands/disconnect.js.map +1 -1
- package/dist/commands/doctor.d.ts +14 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +84 -19
- 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/gates.d.ts +26 -0
- package/dist/commands/gates.d.ts.map +1 -0
- package/dist/commands/gates.js +121 -0
- package/dist/commands/gates.js.map +1 -0
- package/dist/commands/init.d.ts +6 -3
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +35 -5
- package/dist/commands/init.js.map +1 -1
- 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/start.d.ts +10 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +74 -1
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +15 -5
- package/dist/commands/status.js.map +1 -1
- 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/harness/aider.d.ts.map +1 -1
- package/dist/harness/aider.js +3 -2
- package/dist/harness/aider.js.map +1 -1
- package/dist/harness/codex.d.ts.map +1 -1
- package/dist/harness/codex.js +3 -2
- package/dist/harness/codex.js.map +1 -1
- package/dist/harness/continue.d.ts.map +1 -1
- package/dist/harness/continue.js +4 -1
- package/dist/harness/continue.js.map +1 -1
- package/dist/harness/dsh.d.ts.map +1 -1
- package/dist/harness/dsh.js +2 -2
- package/dist/harness/dsh.js.map +1 -1
- package/dist/harness/goose.d.ts.map +1 -1
- package/dist/harness/goose.js +2 -2
- package/dist/harness/goose.js.map +1 -1
- package/dist/harness/grok.d.ts.map +1 -1
- package/dist/harness/grok.js +2 -2
- package/dist/harness/grok.js.map +1 -1
- package/dist/harness/hermes.d.ts.map +1 -1
- package/dist/harness/hermes.js +2 -2
- package/dist/harness/hermes.js.map +1 -1
- package/dist/harness/openhands.d.ts.map +1 -1
- package/dist/harness/openhands.js +5 -3
- package/dist/harness/openhands.js.map +1 -1
- package/dist/harness/pi.d.ts.map +1 -1
- package/dist/harness/pi.js +2 -2
- package/dist/harness/pi.js.map +1 -1
- package/dist/harness/types.d.ts +15 -4
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/windsurf.d.ts.map +1 -1
- package/dist/harness/windsurf.js +2 -2
- package/dist/harness/windsurf.js.map +1 -1
- package/dist/harness/writeHarnessConfigs.d.ts +41 -0
- package/dist/harness/writeHarnessConfigs.d.ts.map +1 -0
- package/dist/harness/writeHarnessConfigs.js +69 -0
- package/dist/harness/writeHarnessConfigs.js.map +1 -0
- package/dist/lib/gitHooks.d.ts.map +1 -1
- package/dist/lib/gitHooks.js +10 -7
- package/dist/lib/gitHooks.js.map +1 -1
- package/dist/lib/localGates.d.ts +62 -0
- package/dist/lib/localGates.d.ts.map +1 -0
- package/dist/lib/localGates.js +145 -0
- package/dist/lib/localGates.js.map +1 -0
- 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/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
|
|
|
@@ -17,10 +17,13 @@ npx @intutic/cli init
|
|
|
17
17
|
**5 minutes to your first governance verdict:**
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
+
intutic init # Detect harnesses, record them in ~/.intutic/config.json
|
|
21
|
+
intutic gates install # Write each harness's gate and rules file from .intutic/sops/
|
|
20
22
|
intutic start # Run the proxy standalone — no account needed
|
|
21
23
|
intutic traces list # See governance verdicts
|
|
22
24
|
```
|
|
23
25
|
|
|
26
|
+
<!-- UNRELEASED:cloud
|
|
24
27
|
**With a control plane:**
|
|
25
28
|
|
|
26
29
|
```bash
|
|
@@ -29,22 +32,27 @@ intutic init # Detect harnesses, record them for sync
|
|
|
29
32
|
intutic connect # Start sync daemon — writes harness rules and gates
|
|
30
33
|
intutic traces list # See governance verdicts
|
|
31
34
|
```
|
|
35
|
+
-->
|
|
32
36
|
|
|
33
37
|
## Commands
|
|
34
38
|
|
|
35
39
|
| Command | Description |
|
|
36
40
|
|---------|-------------|
|
|
37
|
-
| `intutic init` | Initialize workspace — detect harnesses, record them in `~/.intutic/config.json` |
|
|
38
|
-
| `intutic
|
|
39
|
-
| `intutic
|
|
40
|
-
| `intutic logout` | Clear stored credentials |
|
|
41
|
+
| `intutic init` | Initialize workspace — detect harnesses, record them in `~/.intutic/config.json`, and offer to install the gates (`--gates`, `--no-gates`) |
|
|
42
|
+
| `intutic gates install` | Write each recorded harness's gate and rules file from local SOPs (`.intutic/sops/`), with no control plane (`--harness`, `--route` to also write proxy routing while the proxy runs, `--dry-run`, `--workspace`) |
|
|
43
|
+
| `intutic start` | Start the proxy standalone — no account or control plane needed; refreshes the installed gates when `.intutic/sops/` changes (`--port`, `--upstream-url`, `--no-gates`) |
|
|
41
44
|
| `intutic status` | Show workspace status — auth, harnesses, sync state |
|
|
42
|
-
| `intutic
|
|
43
|
-
| `intutic connect` | Start sync daemon — bidirectional config sync (`--interval`) |
|
|
44
|
-
| `intutic disconnect` | Undo `intutic connect` — restore the harness configs it changed, remove its services, log out (`--harness`, `--dry-run`, `--keep-login`) |
|
|
45
|
+
| `intutic disconnect` | Undo `intutic gates install` — restore the harness configs it changed (`--harness`, `--dry-run`, `--keep-login`) |
|
|
45
46
|
| `intutic doctor` | Diagnose workspace health — proxy, auth, daemon, configs, logs |
|
|
46
47
|
| `intutic traces list` | List execution traces (`--limit`, `--since`, `--action` with a control plane, `--verdict` without one, `--model`, `--json`) |
|
|
47
48
|
| `intutic traces inspect <id>` | Show full detail of a single trace |
|
|
49
|
+
<!-- UNRELEASED:cloud
|
|
50
|
+
| `intutic login` | Authenticate with control plane (`--api-key`, `--control-plane-url`, `--dev`) |
|
|
51
|
+
| `intutic logout` | Clear stored credentials |
|
|
52
|
+
| `intutic whoami` | Show current authenticated identity |
|
|
53
|
+
| `intutic connect` | Start sync daemon — bidirectional config sync (`--interval`) |
|
|
54
|
+
| `intutic disconnect` | Also undoes `intutic connect`: removes its services and logs out unless `--keep-login` |
|
|
55
|
+
-->
|
|
48
56
|
|
|
49
57
|
## Supported Harnesses
|
|
50
58
|
|
|
@@ -56,7 +64,7 @@ Intutic auto-detects and configures AI coding harnesses, among them:
|
|
|
56
64
|
| **Cursor** | `.cursor/` or `.cursorrules` in the workspace, or `~/.cursor/` | `.cursor/rules/intutic-governance.mdc` + gate in `.cursor/hooks.json` |
|
|
57
65
|
| **Aider** | `.aider.conf.yml` in the workspace | `.intutic/aider-sops.md`, loaded by `read:` in `.aider.conf.yml` |
|
|
58
66
|
| **Antigravity** | `~/.gemini/antigravity*/`, `.agents/hooks.json`, `.gemini/` in the workspace, or `antigravity` / `gemini` on PATH | `GEMINI.md` section + `PreToolUse` gate in `~/.gemini/config/hooks.json` (Gemini CLI: `BeforeTool` gate in `~/.gemini/settings.json`) |
|
|
59
|
-
| **Codex** | `codex` on PATH, or `CODEX_HOME` set | `AGENTS.md` section + gate in `.codex/hooks.json`; proxy routing in `~/.codex/config.toml` |
|
|
67
|
+
| **Codex** | `codex` on PATH, or `CODEX_HOME` set | `AGENTS.md` section + gate in `.codex/hooks.json`; proxy routing in `~/.codex/config.toml` (with `--route`) |
|
|
60
68
|
| **n8n** | Running n8n instance (`N8N_URL`, default `http://localhost:5678`) | Workflow JSON file + external hook gate `~/.intutic/hooks/n8n-governance-hook.js` |
|
|
61
69
|
| **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`) |
|
|
62
70
|
| **Hermes** | `~/.hermes/` or `.hermes/config.yaml` | `AGENTS.md` section + `hooks.pre_tool_call` gate in `~/.hermes/config.yaml` |
|
|
@@ -94,10 +102,11 @@ Credentials are stored at `~/.intutic/credentials.json` (mode `0600`).
|
|
|
94
102
|
|
|
95
103
|
| Variable | Description |
|
|
96
104
|
|----------|-------------|
|
|
97
|
-
| `INTUTIC_CONTROL_PLANE_URL` | Control plane URL for this shell (overrides the one
|
|
105
|
+
| `INTUTIC_CONTROL_PLANE_URL` | Control plane URL for this shell (overrides the one a control-plane login saved) |
|
|
98
106
|
| `INTUTIC_DEV` | `1` targets the local control plane (`http://localhost:3001`), like `--dev` |
|
|
99
107
|
| `INTUTIC_PROXY_URL` | Local proxy URL; its port is the proxy port (default `4000`) |
|
|
100
108
|
|
|
109
|
+
<!-- UNRELEASED:cloud
|
|
101
110
|
For non-interactive auth, use `intutic login --api-key vk_...`.
|
|
102
111
|
|
|
103
112
|
### Development Mode
|
|
@@ -109,6 +118,7 @@ intutic login --dev
|
|
|
109
118
|
intutic connect --dev
|
|
110
119
|
intutic traces list --dev
|
|
111
120
|
```
|
|
121
|
+
-->
|
|
112
122
|
|
|
113
123
|
## Documentation
|
|
114
124
|
|
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
|
|
@@ -35,6 +60,8 @@ program
|
|
|
35
60
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
36
61
|
.option('--git-hooks', 'Install the Intutic Git hooks without asking')
|
|
37
62
|
.option('--no-git-hooks', 'Skip the Git hooks without asking (the default when stdin is not a terminal)')
|
|
63
|
+
.option('--gates', 'Install the harness gates (`intutic gates install`) without asking')
|
|
64
|
+
.option('--no-gates', 'Skip the harness gates without asking (the default when stdin is not a terminal)')
|
|
38
65
|
.action(async (opts) => {
|
|
39
66
|
const { runInit } = await import('./commands/init.js');
|
|
40
67
|
await runInit(opts);
|
|
@@ -49,7 +76,7 @@ program
|
|
|
49
76
|
await runSetup(opts);
|
|
50
77
|
});
|
|
51
78
|
const judgeCmd = program
|
|
52
|
-
.command('judge')
|
|
79
|
+
.command('judge', needsSelfHost)
|
|
53
80
|
.description('Configure the LLM-as-judge path');
|
|
54
81
|
judgeCmd
|
|
55
82
|
.command('configure')
|
|
@@ -60,7 +87,7 @@ judgeCmd
|
|
|
60
87
|
await runJudgeConfigure(opts);
|
|
61
88
|
});
|
|
62
89
|
program
|
|
63
|
-
.command('login')
|
|
90
|
+
.command('login', needsControlPlane)
|
|
64
91
|
.description('Authenticate with the Intutic control plane')
|
|
65
92
|
.option('--api-key <key>', 'Authenticate with an API key (vk_*)')
|
|
66
93
|
.option('--control-plane-url <url>', 'Control plane to log in to (e.g. a self-hosted one); saved for every later command')
|
|
@@ -71,7 +98,7 @@ program
|
|
|
71
98
|
});
|
|
72
99
|
program
|
|
73
100
|
.command('disconnect')
|
|
74
|
-
.description('Undo intutic connect: restore every harness config
|
|
101
|
+
.description('Undo intutic connect or intutic gates install: restore every harness config they changed, remove the gates and services, and log out')
|
|
75
102
|
.option('--harness <id>', 'Disconnect one harness only (credentials and services stay)')
|
|
76
103
|
.option('--dry-run', 'Print exactly what would change, and change nothing')
|
|
77
104
|
.option('--keep-login', 'Keep the stored credentials')
|
|
@@ -80,7 +107,7 @@ program
|
|
|
80
107
|
await runDisconnect({ harness: opts.harness, dryRun: opts.dryRun, keepLogin: opts.keepLogin });
|
|
81
108
|
});
|
|
82
109
|
program
|
|
83
|
-
.command('logout')
|
|
110
|
+
.command('logout', needsControlPlane)
|
|
84
111
|
.description('Clear stored credentials')
|
|
85
112
|
.action(async () => {
|
|
86
113
|
const { runLogout } = await import('./commands/logout.js');
|
|
@@ -111,7 +138,9 @@ program
|
|
|
111
138
|
});
|
|
112
139
|
const budgetCmd = program
|
|
113
140
|
.command('budget')
|
|
114
|
-
.description(
|
|
141
|
+
.description(CONTROL_PLANE_PRODUCT_RELEASED
|
|
142
|
+
? 'Check remaining daily/monthly budget and list active loops; set workspace, key and member budgets'
|
|
143
|
+
: 'Check the local spending cap and what this machine has spent today')
|
|
115
144
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
116
145
|
.option('--watch', 'Continuously print machine-local and workspace spend, one line per tick')
|
|
117
146
|
.option('--interval <seconds>', 'Tick interval in seconds for --watch', String(5))
|
|
@@ -125,7 +154,7 @@ const budgetCmd = program
|
|
|
125
154
|
await runBudget(opts);
|
|
126
155
|
});
|
|
127
156
|
budgetCmd
|
|
128
|
-
.command('set')
|
|
157
|
+
.command('set', needsControlPlane)
|
|
129
158
|
.description("Set the workspace's daily and monthly caps, alert threshold and whether each cap refuses requests (OWNER, ADMIN)")
|
|
130
159
|
.option('--daily <usd>', 'Daily cap in USD (0: no daily cap; default: back to the $100 default)')
|
|
131
160
|
.option('--monthly <usd>', 'Monthly cap in USD (0: no monthly cap; default: back to the $500 default)')
|
|
@@ -141,7 +170,7 @@ budgetCmd
|
|
|
141
170
|
await runBudgetSet(cmd.optsWithGlobals());
|
|
142
171
|
});
|
|
143
172
|
budgetCmd
|
|
144
|
-
.command('keys')
|
|
173
|
+
.command('keys', needsControlPlane)
|
|
145
174
|
.description("Every virtual key's spend budgets, rate limit and spend today and this month")
|
|
146
175
|
.option('--json', 'Output as JSON')
|
|
147
176
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
@@ -150,7 +179,7 @@ budgetCmd
|
|
|
150
179
|
await runBudgetKeys(cmd.optsWithGlobals());
|
|
151
180
|
});
|
|
152
181
|
budgetCmd
|
|
153
|
-
.command('key <keyId>')
|
|
182
|
+
.command('key <keyId>', needsControlPlane)
|
|
154
183
|
.description("Set a virtual key's spend budgets and rate limit (OWNER, ADMIN)")
|
|
155
184
|
.option('--daily <usd>', 'Day budget in USD, or none to remove it')
|
|
156
185
|
.option('--monthly <usd>', 'Month budget in USD, or none to remove it')
|
|
@@ -165,7 +194,7 @@ budgetCmd
|
|
|
165
194
|
await runBudgetKey(keyId, cmd.optsWithGlobals());
|
|
166
195
|
});
|
|
167
196
|
budgetCmd
|
|
168
|
-
.command('members')
|
|
197
|
+
.command('members', needsControlPlane)
|
|
169
198
|
.description("The default member budget, and each member's budgets and spend (Biz Org+)")
|
|
170
199
|
.option('--json', 'Output as JSON')
|
|
171
200
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
@@ -174,7 +203,7 @@ budgetCmd
|
|
|
174
203
|
await runBudgetMembers(cmd.optsWithGlobals());
|
|
175
204
|
});
|
|
176
205
|
budgetCmd
|
|
177
|
-
.command('member <memberId>')
|
|
206
|
+
.command('member <memberId>', needsControlPlane)
|
|
178
207
|
.description("Set a member's spend budgets, or the default member budget with `default` (OWNER, ADMIN; Biz Org+)")
|
|
179
208
|
.option('--daily <usd>', 'Day budget in USD, or none to remove it')
|
|
180
209
|
.option('--monthly <usd>', 'Month budget in USD, or none to remove it')
|
|
@@ -187,7 +216,7 @@ budgetCmd
|
|
|
187
216
|
await runBudgetMember(memberId, cmd.optsWithGlobals());
|
|
188
217
|
});
|
|
189
218
|
program
|
|
190
|
-
.command('predict-cost')
|
|
219
|
+
.command('predict-cost', needsControlPlane)
|
|
191
220
|
.description('Pre-flight cost estimate for a prompt/task before it runs (requires `intutic login`). ' +
|
|
192
221
|
"Estimates output tokens from the workspace's recorded usage and prices them with the same " +
|
|
193
222
|
'rate table as every other cost figure the control plane reports.')
|
|
@@ -201,7 +230,7 @@ program
|
|
|
201
230
|
await runPredictCost(opts);
|
|
202
231
|
});
|
|
203
232
|
const sopsCmd = program
|
|
204
|
-
.command('sops')
|
|
233
|
+
.command('sops', needsControlPlane)
|
|
205
234
|
.description('Manage local and global SOP rules');
|
|
206
235
|
sopsCmd
|
|
207
236
|
.command('push <name>')
|
|
@@ -249,7 +278,7 @@ sopsCmd
|
|
|
249
278
|
});
|
|
250
279
|
// ── SOP Optimizer approval mode ──────────────────────────────────────────
|
|
251
280
|
const optimizerCmd = program
|
|
252
|
-
.command('optimizer')
|
|
281
|
+
.command('optimizer', needsControlPlane)
|
|
253
282
|
.description("Read and set the SOP Optimizer's approval mode (whether it may auto-apply strengthening proposals)");
|
|
254
283
|
optimizerCmd
|
|
255
284
|
.command('settings')
|
|
@@ -273,9 +302,9 @@ optimizerCmd
|
|
|
273
302
|
});
|
|
274
303
|
const policyCmd = program
|
|
275
304
|
.command('policy')
|
|
276
|
-
.description('WASM rules and the policy snapshot');
|
|
305
|
+
.description(CONTROL_PLANE_PRODUCT_RELEASED ? 'WASM rules and the policy snapshot' : 'WASM rules: compile, test and install them locally');
|
|
277
306
|
policyCmd
|
|
278
|
-
.command('snapshot')
|
|
307
|
+
.command('snapshot', needsControlPlane)
|
|
279
308
|
.description('Compile workspace policy to ~/.intutic/hooks/policy-snapshot.rules — the file every gate reads.\n' +
|
|
280
309
|
'\n' +
|
|
281
310
|
' Does only that. \'intutic connect\' writes it too, but as one step of\n' +
|
|
@@ -298,10 +327,10 @@ policyCmd
|
|
|
298
327
|
.command('compile')
|
|
299
328
|
.description('Compile an AssemblyScript rule to WASM (wraps asc)')
|
|
300
329
|
.option('--src <path>', 'Rule source entry file (default: assembly/index.ts)')
|
|
301
|
-
.option('--out <path>',
|
|
330
|
+
.option('--out <path>', `Output .wasm path (default: build/rule.wasm${CONTROL_PLANE_PRODUCT_RELEASED ? ', or build/<candidate>.wasm with --candidate' : ''})`)
|
|
302
331
|
.option('--debug', 'Include debug info and source maps')
|
|
303
|
-
.
|
|
304
|
-
.
|
|
332
|
+
.addOption(controlPlaneOption('--candidate <id>', 'Compile a rule candidate from its source of record on the control plane (fetched and hash-verified; not with --src)'))
|
|
333
|
+
.addOption(controlPlaneOption('--upload', 'With --candidate: upload the bundle to the candidate with its source hash and print the gate results'))
|
|
305
334
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
306
335
|
.action(async (opts) => {
|
|
307
336
|
const { runPolicyCompile } = await import('./commands/policy.js');
|
|
@@ -325,7 +354,7 @@ policyCmd
|
|
|
325
354
|
await runPolicyListLocal();
|
|
326
355
|
});
|
|
327
356
|
policyCmd
|
|
328
|
-
.command('replay <ruleId>')
|
|
357
|
+
.command('replay <ruleId>', needsControlPlane)
|
|
329
358
|
.description("Replay a rule (installed or not) against this workspace's own recent traffic and report " +
|
|
330
359
|
'what it would have done, without touching enforcement.')
|
|
331
360
|
.option('--limit <n>', 'Max sampled contexts to replay against (default 500, capped at 5000)')
|
|
@@ -371,7 +400,7 @@ rulesCmd
|
|
|
371
400
|
// `intutic sops` is files on disk; this namespace is the cited guardrails
|
|
372
401
|
// extracted from policy documents and their shadow -> promote lifecycle.
|
|
373
402
|
const guardrailsCmd = program
|
|
374
|
-
.command('guardrails')
|
|
403
|
+
.command('guardrails', needsControlPlane)
|
|
375
404
|
.description('Policy documents, cited clauses and the guardrails compiled from them');
|
|
376
405
|
const guardrailsSourcesCmd = guardrailsCmd
|
|
377
406
|
.command('sources')
|
|
@@ -614,7 +643,7 @@ guardrailsCmd
|
|
|
614
643
|
await runGuardrailsPull(opts);
|
|
615
644
|
});
|
|
616
645
|
program
|
|
617
|
-
.command('whoami')
|
|
646
|
+
.command('whoami', needsControlPlane)
|
|
618
647
|
.description('Show current authenticated identity')
|
|
619
648
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
620
649
|
.action(async (opts) => {
|
|
@@ -627,10 +656,30 @@ program
|
|
|
627
656
|
.option('--port <port>', 'Proxy port (default: the port of $INTUTIC_PROXY_URL, else 4000)')
|
|
628
657
|
.option('--valkey-port <port>', 'Valkey port', '6379')
|
|
629
658
|
.option('--upstream-url <url>', 'Upstream LLM provider base URL')
|
|
659
|
+
.option('--no-gates', 'Do not refresh the local gates (`intutic gates install`) or watch .intutic/sops while the proxy runs')
|
|
630
660
|
.action(async (opts) => {
|
|
631
661
|
const { runStart } = await import('./commands/start.js');
|
|
632
662
|
await runStart(opts);
|
|
633
663
|
});
|
|
664
|
+
const gatesCmd = program
|
|
665
|
+
.command('gates')
|
|
666
|
+
.description('Harness hook gates and rules files, without a control plane');
|
|
667
|
+
gatesCmd
|
|
668
|
+
.command('install')
|
|
669
|
+
.description('Install the tool-call gate and rules file for each recorded harness, from this machine alone: ' +
|
|
670
|
+
'the built-in protections, the local .intutic/sops, and review_before: tokens (refused, as nothing can approve a hold)')
|
|
671
|
+
.option('--harness <id>', 'Only this harness (it must be recorded by `intutic init`, or pass --add)')
|
|
672
|
+
.option('--add', 'With --harness: record the harness in ~/.intutic/config.json if it is not')
|
|
673
|
+
.option('--route', "Also point the harnesses' LLM traffic at the local proxy, which must then be running (e.g. `intutic daemon install --proxy`)")
|
|
674
|
+
.option('--dry-run', 'Print what would be written, and write nothing')
|
|
675
|
+
.option('--workspace <path>', 'Workspace to write into (default: the one `intutic init` recorded)')
|
|
676
|
+
.action(async (opts) => {
|
|
677
|
+
// The writers log each file at info, as JSON; the command prints its own
|
|
678
|
+
// list. Warnings (a file left alone because it does not parse) still show.
|
|
679
|
+
process.env.LOG_LEVEL ??= 'warn';
|
|
680
|
+
const { runGatesInstall } = await import('./commands/gates.js');
|
|
681
|
+
await runGatesInstall(opts);
|
|
682
|
+
});
|
|
634
683
|
// L2 mandatory egress firewall. Makes the governing proxy
|
|
635
684
|
// non-optional: default-deny host egress to everything except the proxy, DNS,
|
|
636
685
|
// and declared infra. apply/remove need root; generate/status do not.
|
|
@@ -657,7 +706,7 @@ for (const [action, desc] of [
|
|
|
657
706
|
});
|
|
658
707
|
}
|
|
659
708
|
enforceCmd
|
|
660
|
-
.command('report')
|
|
709
|
+
.command('report', needsControlPlane)
|
|
661
710
|
.description('Report locally recorded enforcement state (firewall/CA-trust/system-hooks) to the control plane. ' +
|
|
662
711
|
'No privilege needed — for when apply/remove ran elevated and could not reach stored credentials.')
|
|
663
712
|
.action(async () => {
|
|
@@ -670,7 +719,7 @@ enforceCmd
|
|
|
670
719
|
// tools/scripts/intutic-enterprise-install.sh, an unrelated air-gapped
|
|
671
720
|
// docker-compose installer. Does not touch the host firewall; see `enforce`.
|
|
672
721
|
const enterpriseCmd = program
|
|
673
|
-
.command('enterprise')
|
|
722
|
+
.command('enterprise', needsControlPlane)
|
|
674
723
|
.description('Enterprise fleet rollout: CA trust, Cursor system hooks, MDM manifests');
|
|
675
724
|
enterpriseCmd
|
|
676
725
|
.command('install')
|
|
@@ -709,7 +758,7 @@ envCmd
|
|
|
709
758
|
await runEnvClear();
|
|
710
759
|
});
|
|
711
760
|
program
|
|
712
|
-
.command('connect')
|
|
761
|
+
.command('connect', needsControlPlane)
|
|
713
762
|
.description('Start sync daemon — bidirectional config sync with control plane (requires an account)')
|
|
714
763
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
715
764
|
.option('--interval <ms>', 'Poll interval in milliseconds', '30000')
|
|
@@ -721,7 +770,7 @@ program
|
|
|
721
770
|
await runConnect(opts);
|
|
722
771
|
});
|
|
723
772
|
program
|
|
724
|
-
.command('sync-context')
|
|
773
|
+
.command('sync-context', needsControlPlane)
|
|
725
774
|
.description('Record the Git branch and commit in .intutic/git-context.json, which a running `intutic connect` reports')
|
|
726
775
|
.option('--git', 'Read the branch and commit from the repository (for any not given below)')
|
|
727
776
|
.option('--branch <name>', 'Current Git branch name')
|
|
@@ -731,7 +780,7 @@ program
|
|
|
731
780
|
await runSyncContext(opts);
|
|
732
781
|
});
|
|
733
782
|
program
|
|
734
|
-
.command('decisions-log-refresh')
|
|
783
|
+
.command('decisions-log-refresh', needsControlPlane)
|
|
735
784
|
.description('One-shot refresh of the governed decisions log (.intutic/DECISIONS.md, and the recent ' +
|
|
736
785
|
'entries in each governed harness\'s instructions file) — no-ops if decisionsLogEnabled is off. Invoked by the optional ' +
|
|
737
786
|
'post-merge Git hook `intutic init` installs; safe to run manually.')
|
|
@@ -833,7 +882,7 @@ traces
|
|
|
833
882
|
});
|
|
834
883
|
// ── Findings (detector_findings adjudication) ───────────────────────────────
|
|
835
884
|
const findings = program
|
|
836
|
-
.command('findings')
|
|
885
|
+
.command('findings', needsControlPlane)
|
|
837
886
|
.description('Query and adjudicate detector findings — the TP/FP labeling surface');
|
|
838
887
|
findings
|
|
839
888
|
.command('list')
|
|
@@ -880,7 +929,7 @@ findings
|
|
|
880
929
|
});
|
|
881
930
|
// ── Governance incidents ───────────────────────────────────────────────────
|
|
882
931
|
const incidentsCmd = program
|
|
883
|
-
.command('incidents')
|
|
932
|
+
.command('incidents', needsControlPlane)
|
|
884
933
|
.description('Governance incidents, as on Findings › Incidents (OWNER, ADMIN, EM)');
|
|
885
934
|
incidentsCmd
|
|
886
935
|
.command('list')
|
|
@@ -907,7 +956,7 @@ incidentsCmd
|
|
|
907
956
|
});
|
|
908
957
|
// ── Trace integrity ────────────────────────────────────────────────────────
|
|
909
958
|
const integrity = program
|
|
910
|
-
.command('integrity')
|
|
959
|
+
.command('integrity', needsControlPlane)
|
|
911
960
|
.description('Verify sealed trace roots — list, re-derive, walk the root chain, and walk the config snapshot chain');
|
|
912
961
|
integrity
|
|
913
962
|
.command('roots')
|
|
@@ -950,7 +999,7 @@ integrity
|
|
|
950
999
|
});
|
|
951
1000
|
// ── Routing reports ─────────────────────────────────────────────────────────
|
|
952
1001
|
const routing = program
|
|
953
|
-
.command('routing')
|
|
1002
|
+
.command('routing', needsControlPlane)
|
|
954
1003
|
.description('Read-only reports for the routing subsystem');
|
|
955
1004
|
routing
|
|
956
1005
|
.command('adoption-report')
|
|
@@ -989,7 +1038,7 @@ function defineDaemonInstall(cmd) {
|
|
|
989
1038
|
' Use \'intutic daemon stop\' or \'intutic daemon uninstall\'.')
|
|
990
1039
|
.option('--workspace-id <id>', 'Workspace ID (e.g. wk_xxxx) — required unless --proxy')
|
|
991
1040
|
.option('--api-key <key>', 'Workspace API key (e.g. vk_xxxx) — required unless --proxy')
|
|
992
|
-
.
|
|
1041
|
+
.addOption(controlPlaneOption('--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}` : ''})`))
|
|
993
1042
|
.option('--binary-path <path>', 'Path to intutic CLI binary (defaults to current process); with --proxy, absolute path to intutic-proxy')
|
|
994
1043
|
.option('--dry-run', 'Print what would be done without writing files')
|
|
995
1044
|
.option('--system', 'Install as a system-level service (LaunchDaemon on macOS, systemd system unit on Linux)')
|
|
@@ -1122,7 +1171,7 @@ skillCmd
|
|
|
1122
1171
|
});
|
|
1123
1172
|
// ── Loop commands ──────────────────────────────────────────────────────────
|
|
1124
1173
|
const loopCmd = program
|
|
1125
|
-
.command('loop')
|
|
1174
|
+
.command('loop', needsControlPlane)
|
|
1126
1175
|
.description('Manage and execute recursive agent loops with budget limits');
|
|
1127
1176
|
loopCmd
|
|
1128
1177
|
.command('start')
|
|
@@ -1190,7 +1239,7 @@ loopCmd
|
|
|
1190
1239
|
// module doc for why `intutic loop review` was never the right command for
|
|
1191
1240
|
// this — it addresses a different id space (Loop Runs, not decisions).
|
|
1192
1241
|
const decisionCmd = program
|
|
1193
|
-
.command('decision')
|
|
1242
|
+
.command('decision', needsControlPlane)
|
|
1194
1243
|
.description('Approve or reject a decision (e.g. a review_before hold) held for human review');
|
|
1195
1244
|
decisionCmd
|
|
1196
1245
|
.command('approve <holdId>')
|
|
@@ -1216,7 +1265,7 @@ decisionCmd
|
|
|
1216
1265
|
// hand-written curl against services/control-plane/src/routes/gateways.ts —
|
|
1217
1266
|
// see commands/gateway.ts's module doc.
|
|
1218
1267
|
const gatewayCmd = program
|
|
1219
|
-
.command('gateway')
|
|
1268
|
+
.command('gateway', needsControlPlane)
|
|
1220
1269
|
.description('Manage self-hosted gateway registrations (Docker / Kubernetes / bare metal)');
|
|
1221
1270
|
gatewayCmd
|
|
1222
1271
|
.command('register')
|
|
@@ -1314,7 +1363,7 @@ gatewayCmd
|
|
|
1314
1363
|
// Provision a workspace's own upstream provider keys — the BYO-key wizard's
|
|
1315
1364
|
// API, previously dashboard-only. See commands/credentials.ts's module doc.
|
|
1316
1365
|
const credentialsCmd = program
|
|
1317
|
-
.command('credentials')
|
|
1366
|
+
.command('credentials', needsControlPlane)
|
|
1318
1367
|
.description('Manage this workspace\'s own upstream provider API keys (BYO-key)');
|
|
1319
1368
|
credentialsCmd
|
|
1320
1369
|
.command('list')
|
|
@@ -1358,7 +1407,7 @@ credentialsCmd
|
|
|
1358
1407
|
// "CLI mints, dashboard audits": this is the mint/inspect half. See
|
|
1359
1408
|
// commands/attenuate.ts's module doc.
|
|
1360
1409
|
const attenuateCmd = program
|
|
1361
|
-
.command('attenuate')
|
|
1410
|
+
.command('attenuate', needsControlPlane)
|
|
1362
1411
|
.description('Attenuate one of your API keys to a child key with narrower scopes (and an optional TTL)')
|
|
1363
1412
|
.option('--parent-key <keyId>', 'Parent API key ID to attenuate')
|
|
1364
1413
|
.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')
|
|
@@ -1378,7 +1427,7 @@ attenuateCmd
|
|
|
1378
1427
|
});
|
|
1379
1428
|
// ── API keys and their scopes ────────────────────────────────────────────
|
|
1380
1429
|
const keysCmd = program
|
|
1381
|
-
.command('keys')
|
|
1430
|
+
.command('keys', needsControlPlane)
|
|
1382
1431
|
.description('List, create, re-scope and revoke your API keys');
|
|
1383
1432
|
keysCmd
|
|
1384
1433
|
.command('list')
|
|
@@ -1423,7 +1472,7 @@ keysCmd
|
|
|
1423
1472
|
});
|
|
1424
1473
|
// ── Org signup + team management ─────────────────────────────────────────
|
|
1425
1474
|
const orgCmd = program
|
|
1426
|
-
.command('org')
|
|
1475
|
+
.command('org', needsControlPlane)
|
|
1427
1476
|
.description('Create and manage orgs');
|
|
1428
1477
|
orgCmd
|
|
1429
1478
|
.command('create')
|
|
@@ -1438,7 +1487,7 @@ orgCmd
|
|
|
1438
1487
|
await runOrgCreate(opts);
|
|
1439
1488
|
});
|
|
1440
1489
|
const teamCmd = program
|
|
1441
|
-
.command('team')
|
|
1490
|
+
.command('team', needsControlPlane)
|
|
1442
1491
|
.description('Manage teams and workspaces under an org');
|
|
1443
1492
|
teamCmd
|
|
1444
1493
|
.command('list')
|
|
@@ -1487,7 +1536,7 @@ teamCmd
|
|
|
1487
1536
|
// route. Previously dashboard-only. See commands/apiCommand.ts for the shape
|
|
1488
1537
|
// they share.
|
|
1489
1538
|
const settingsCmd = program
|
|
1490
|
-
.command('settings')
|
|
1539
|
+
.command('settings', needsControlPlane)
|
|
1491
1540
|
.description('Read and change workspace settings (MCP policy, budgets, group policy, config content upload, ...)');
|
|
1492
1541
|
settingsCmd
|
|
1493
1542
|
.command('get [key]')
|
|
@@ -1509,7 +1558,7 @@ settingsCmd
|
|
|
1509
1558
|
await runSettingsSet(key, value, opts);
|
|
1510
1559
|
});
|
|
1511
1560
|
const mcpCmd = program
|
|
1512
|
-
.command('mcp')
|
|
1561
|
+
.command('mcp', needsControlPlane)
|
|
1513
1562
|
.description('Review the MCP servers the workspace\'s MCP proxies have seen, and decide on them');
|
|
1514
1563
|
mcpCmd
|
|
1515
1564
|
.command('list')
|
|
@@ -1550,7 +1599,7 @@ for (const [action, enabled, desc] of [
|
|
|
1550
1599
|
});
|
|
1551
1600
|
}
|
|
1552
1601
|
const notificationsCmd = program
|
|
1553
|
-
.command('notifications')
|
|
1602
|
+
.command('notifications', needsControlPlane)
|
|
1554
1603
|
.description('Manage notification rules: which events go to Slack, email, a webhook or PagerDuty');
|
|
1555
1604
|
function ruleOptions(cmd) {
|
|
1556
1605
|
return cmd
|
|
@@ -1612,7 +1661,7 @@ notificationsCmd
|
|
|
1612
1661
|
await runNotificationsRotateSecret(ruleId, opts);
|
|
1613
1662
|
});
|
|
1614
1663
|
const siemCmd = program
|
|
1615
|
-
.command('siem')
|
|
1664
|
+
.command('siem', needsControlPlane)
|
|
1616
1665
|
.description('Manage SIEM export destinations and the event sources each receives');
|
|
1617
1666
|
function destinationOptions(cmd) {
|
|
1618
1667
|
return cmd
|
|
@@ -1687,7 +1736,7 @@ siemCmd
|
|
|
1687
1736
|
await runSiemRotateSecret(destinationId, opts);
|
|
1688
1737
|
});
|
|
1689
1738
|
const tasksCmd = program
|
|
1690
|
-
.command('tasks')
|
|
1739
|
+
.command('tasks', needsControlPlane)
|
|
1691
1740
|
.description('Manage task-management connections (Jira Cloud, Linear, PagerDuty) that attach ticket context to sessions');
|
|
1692
1741
|
tasksCmd
|
|
1693
1742
|
.command('list')
|
|
@@ -1732,7 +1781,7 @@ tasksCmd
|
|
|
1732
1781
|
await runTasksRemove(connectionId, opts);
|
|
1733
1782
|
});
|
|
1734
1783
|
const complianceCmd = program
|
|
1735
|
-
.command('compliance')
|
|
1784
|
+
.command('compliance', needsControlPlane)
|
|
1736
1785
|
.description('Compliance framework reports and the evidence archive');
|
|
1737
1786
|
complianceCmd
|
|
1738
1787
|
.command('coverage <framework_id>')
|
|
@@ -1777,7 +1826,7 @@ complianceCmd
|
|
|
1777
1826
|
await runComplianceVerify(file, opts);
|
|
1778
1827
|
});
|
|
1779
1828
|
const usageCmd = program
|
|
1780
|
-
.command('usage')
|
|
1829
|
+
.command('usage', needsControlPlane)
|
|
1781
1830
|
.description('LLM usage across the fleet, by member, team, branch, commit or pull request');
|
|
1782
1831
|
for (const [view, handler, desc] of [
|
|
1783
1832
|
['members', 'runUsageMembers', 'Usage per member'],
|
|
@@ -1808,7 +1857,7 @@ usageCmd
|
|
|
1808
1857
|
await runUsagePullRequests(opts);
|
|
1809
1858
|
});
|
|
1810
1859
|
const githubWebhookCmd = program
|
|
1811
|
-
.command('github')
|
|
1860
|
+
.command('github', needsControlPlane)
|
|
1812
1861
|
.description('GitHub integration for cost per pull request')
|
|
1813
1862
|
.command('webhook')
|
|
1814
1863
|
.description('The pull-request webhook: payload URL and signing secret');
|
|
@@ -1831,7 +1880,7 @@ githubWebhookCmd
|
|
|
1831
1880
|
await runGithubWebhookRotateSecret(opts);
|
|
1832
1881
|
});
|
|
1833
1882
|
const inventoryCmd = program
|
|
1834
|
-
.command('inventory')
|
|
1883
|
+
.command('inventory', needsControlPlane)
|
|
1835
1884
|
.description('AI harnesses, MCP servers and skills on connected developer machines, governed or not');
|
|
1836
1885
|
inventoryCmd
|
|
1837
1886
|
.command('summary')
|
|
@@ -1893,7 +1942,7 @@ inventoryCmd
|
|
|
1893
1942
|
await runInventoryDisconnects(opts);
|
|
1894
1943
|
});
|
|
1895
1944
|
program
|
|
1896
|
-
.command('gate-liveness')
|
|
1945
|
+
.command('gate-liveness', needsControlPlane)
|
|
1897
1946
|
.description('Whether each installed harness\'s gate is reporting, and any open silent-gate alert')
|
|
1898
1947
|
.option('--json', 'Output as JSON')
|
|
1899
1948
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|