@intutic/cli 1.10.1 → 2.1.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/dist/cli.js +120 -128
- package/dist/cli.js.map +1 -1
- package/dist/commands/attenuate.d.ts.map +1 -1
- package/dist/commands/attenuate.js +4 -2
- package/dist/commands/attenuate.js.map +1 -1
- package/dist/commands/budget.d.ts.map +1 -1
- package/dist/commands/budget.js +2 -2
- package/dist/commands/budget.js.map +1 -1
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +20 -9
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/doctor.d.ts +19 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +33 -41
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/enforce.d.ts +10 -0
- package/dist/commands/enforce.d.ts.map +1 -1
- package/dist/commands/enforce.js +36 -0
- package/dist/commands/enforce.js.map +1 -1
- package/dist/commands/exec.d.ts +7 -8
- package/dist/commands/exec.d.ts.map +1 -1
- package/dist/commands/exec.js +59 -60
- package/dist/commands/exec.js.map +1 -1
- package/dist/commands/gateway.d.ts.map +1 -1
- package/dist/commands/gateway.js +3 -1
- package/dist/commands/gateway.js.map +1 -1
- package/dist/commands/guardrails.d.ts.map +1 -1
- package/dist/commands/guardrails.js +18 -1
- package/dist/commands/guardrails.js.map +1 -1
- package/dist/commands/init.d.ts +5 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +36 -22
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install-daemon.d.ts +1 -1
- package/dist/commands/install-daemon.d.ts.map +1 -1
- package/dist/commands/install-daemon.js +5 -3
- package/dist/commands/install-daemon.js.map +1 -1
- package/dist/commands/integrity.d.ts +31 -2
- package/dist/commands/integrity.d.ts.map +1 -1
- package/dist/commands/integrity.js +109 -3
- package/dist/commands/integrity.js.map +1 -1
- package/dist/commands/judge.d.ts +8 -4
- package/dist/commands/judge.d.ts.map +1 -1
- package/dist/commands/judge.js +41 -21
- package/dist/commands/judge.js.map +1 -1
- package/dist/commands/login.d.ts +1 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +16 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/setup.d.ts +1 -2
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +11 -68
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/skill.d.ts +1 -0
- package/dist/commands/skill.d.ts.map +1 -1
- package/dist/commands/skill.js +17 -3
- package/dist/commands/skill.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +5 -1
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/syncContext.d.ts.map +1 -1
- package/dist/commands/syncContext.js +15 -5
- package/dist/commands/syncContext.js.map +1 -1
- package/dist/config/paths.d.ts +25 -3
- package/dist/config/paths.d.ts.map +1 -1
- package/dist/config/paths.js +47 -7
- package/dist/config/paths.js.map +1 -1
- package/dist/harness/agentFramework.d.ts +25 -0
- package/dist/harness/agentFramework.d.ts.map +1 -0
- package/dist/harness/agentFramework.js +37 -0
- package/dist/harness/agentFramework.js.map +1 -0
- package/dist/harness/agentcore.d.ts +6 -3
- package/dist/harness/agentcore.d.ts.map +1 -1
- package/dist/harness/agentcore.js +7 -4
- package/dist/harness/agentcore.js.map +1 -1
- package/dist/harness/aiSdkHarness.d.ts +1 -1
- package/dist/harness/aiSdkHarness.js +1 -1
- package/dist/harness/aiSdkWorkflow.d.ts +1 -1
- package/dist/harness/aiSdkWorkflow.d.ts.map +1 -1
- package/dist/harness/aiSdkWorkflow.js +5 -3
- package/dist/harness/aiSdkWorkflow.js.map +1 -1
- package/dist/harness/aider.d.ts +4 -3
- package/dist/harness/aider.d.ts.map +1 -1
- package/dist/harness/aider.js +7 -6
- package/dist/harness/aider.js.map +1 -1
- package/dist/harness/antigravity.d.ts +4 -2
- package/dist/harness/antigravity.d.ts.map +1 -1
- package/dist/harness/antigravity.js +14 -12
- package/dist/harness/antigravity.js.map +1 -1
- package/dist/harness/cline.d.ts +10 -4
- package/dist/harness/cline.d.ts.map +1 -1
- package/dist/harness/cline.js +39 -32
- package/dist/harness/cline.js.map +1 -1
- package/dist/harness/codex.d.ts +10 -4
- package/dist/harness/codex.d.ts.map +1 -1
- package/dist/harness/codex.js +28 -26
- package/dist/harness/codex.js.map +1 -1
- package/dist/harness/continue.d.ts +8 -5
- package/dist/harness/continue.d.ts.map +1 -1
- package/dist/harness/continue.js +27 -63
- package/dist/harness/continue.js.map +1 -1
- package/dist/harness/detector.d.ts +1 -1
- package/dist/harness/detector.d.ts.map +1 -1
- package/dist/harness/detector.js +3 -1
- package/dist/harness/detector.js.map +1 -1
- package/dist/harness/dsh.d.ts +2 -2
- package/dist/harness/dsh.js +3 -3
- package/dist/harness/dsh.js.map +1 -1
- package/dist/harness/eve.d.ts +1 -1
- package/dist/harness/eve.js +1 -1
- package/dist/harness/githubCopilot.d.ts +4 -2
- package/dist/harness/githubCopilot.d.ts.map +1 -1
- package/dist/harness/githubCopilot.js +10 -2
- package/dist/harness/githubCopilot.js.map +1 -1
- package/dist/harness/jsSdkGatedAdapter.d.ts.map +1 -1
- package/dist/harness/jsSdkGatedAdapter.js +4 -3
- package/dist/harness/jsSdkGatedAdapter.js.map +1 -1
- package/dist/harness/langgraph.js +4 -4
- package/dist/harness/langgraph.js.map +1 -1
- package/dist/harness/n8n.d.ts +5 -2
- package/dist/harness/n8n.d.ts.map +1 -1
- package/dist/harness/n8n.js +12 -3
- package/dist/harness/n8n.js.map +1 -1
- package/dist/harness/openWebUI.d.ts +7 -2
- package/dist/harness/openWebUI.d.ts.map +1 -1
- package/dist/harness/openWebUI.js +15 -4
- package/dist/harness/openWebUI.js.map +1 -1
- package/dist/harness/opencode.d.ts +3 -2
- package/dist/harness/opencode.d.ts.map +1 -1
- package/dist/harness/opencode.js +3 -2
- package/dist/harness/opencode.js.map +1 -1
- package/dist/harness/openhands.d.ts +3 -2
- package/dist/harness/openhands.d.ts.map +1 -1
- package/dist/harness/openhands.js +27 -26
- package/dist/harness/openhands.js.map +1 -1
- package/dist/harness/rooCode.d.ts +6 -5
- package/dist/harness/rooCode.d.ts.map +1 -1
- package/dist/harness/rooCode.js +9 -12
- package/dist/harness/rooCode.js.map +1 -1
- package/dist/harness/sdkGatedAdapter.d.ts.map +1 -1
- package/dist/harness/sdkGatedAdapter.js +4 -3
- package/dist/harness/sdkGatedAdapter.js.map +1 -1
- package/dist/harness/trueforge.js +2 -2
- package/dist/harness/trueforge.js.map +1 -1
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js +3 -0
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/windsurf.d.ts +4 -2
- package/dist/harness/windsurf.d.ts.map +1 -1
- package/dist/harness/windsurf.js +12 -5
- package/dist/harness/windsurf.js.map +1 -1
- package/dist/lib/localProxy.d.ts +19 -0
- package/dist/lib/localProxy.d.ts.map +1 -0
- package/dist/lib/localProxy.js +33 -0
- package/dist/lib/localProxy.js.map +1 -0
- package/dist/lib/onboarding.d.ts +1 -1
- package/dist/lib/onboarding.d.ts.map +1 -1
- package/dist/lib/onboarding.js +21 -27
- package/dist/lib/onboarding.js.map +1 -1
- package/dist/lib/sandbox/image.d.ts +27 -0
- package/dist/lib/sandbox/image.d.ts.map +1 -0
- package/dist/lib/sandbox/image.js +54 -0
- package/dist/lib/sandbox/image.js.map +1 -0
- package/dist/lib/sandbox/oci.d.ts +1 -0
- package/dist/lib/sandbox/oci.d.ts.map +1 -1
- package/dist/lib/sandbox/oci.js +4 -0
- package/dist/lib/sandbox/oci.js.map +1 -1
- package/dist/lib/sandbox/types.d.ts +5 -0
- package/dist/lib/sandbox/types.d.ts.map +1 -1
- package/package.json +6 -5
- package/resources/sandbox/Dockerfile +30 -0
- package/resources/sandbox/entrypoint.sh +108 -0
- package/resources/sandbox/firecracker-launch.sh +120 -0
- package/dist/harness/vscodeSettingsWriter.d.ts +0 -40
- package/dist/harness/vscodeSettingsWriter.d.ts.map +0 -1
- package/dist/harness/vscodeSettingsWriter.js +0 -116
- package/dist/harness/vscodeSettingsWriter.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { Command } from 'commander';
|
|
14
14
|
import { createRequire } from 'node:module';
|
|
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
|
|
17
18
|
// `intutic --version` reported a version the user did not have — and any check
|
|
@@ -20,14 +21,22 @@ import { createRequire } from 'node:module';
|
|
|
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
|
+
// Positional options: `--version` and `--help` belong to the program only when
|
|
25
|
+
// they come before a subcommand. Without this, commander matches program
|
|
26
|
+
// options anywhere on the line, so `intutic policy rollback <id> --version 2`
|
|
27
|
+
// printed the CLI version and exited before `policy rollback` ever saw its own
|
|
28
|
+
// required `--version`.
|
|
23
29
|
program
|
|
24
30
|
.name('intutic')
|
|
25
31
|
.description('Intutic CLI — AI governance control plane for developer workspaces')
|
|
26
|
-
.version(version)
|
|
32
|
+
.version(version)
|
|
33
|
+
.enablePositionalOptions();
|
|
27
34
|
program
|
|
28
35
|
.command('init')
|
|
29
|
-
.description('Initialize workspace — detect harnesses
|
|
36
|
+
.description('Initialize workspace — detect harnesses and record them in ~/.intutic/config.json')
|
|
30
37
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
38
|
+
.option('--git-hooks', 'Install the Intutic Git hooks without asking')
|
|
39
|
+
.option('--no-git-hooks', 'Skip the Git hooks without asking (the default when stdin is not a terminal)')
|
|
31
40
|
.action(async (opts) => {
|
|
32
41
|
const { runInit } = await import('./commands/init.js');
|
|
33
42
|
await runInit(opts);
|
|
@@ -35,7 +44,7 @@ program
|
|
|
35
44
|
// ── Cohort setup wizard (LLD #70) ────────────────────────────────────────
|
|
36
45
|
program
|
|
37
46
|
.command('setup')
|
|
38
|
-
.description('Guided setup: detect harnesses, configure a provider credential, verify it
|
|
47
|
+
.description('Guided setup: detect harnesses, configure a provider credential, and verify it')
|
|
39
48
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
40
49
|
.action(async (opts) => {
|
|
41
50
|
const { runSetup } = await import('./commands/setup.js');
|
|
@@ -46,7 +55,7 @@ const judgeCmd = program
|
|
|
46
55
|
.description('Configure the LLM-as-judge path');
|
|
47
56
|
judgeCmd
|
|
48
57
|
.command('configure')
|
|
49
|
-
.description('Generate local artifacts (litellm_config.yaml, env, Helm values) for an on-prem judge — never a remote API call')
|
|
58
|
+
.description('Generate local artifacts (litellm_config.yaml, env, Helm values) for an on-prem judge on a self-hosted model — never a remote API call')
|
|
50
59
|
.option('--out <path>', 'Where to write litellm_config.yaml', './litellm_config.yaml')
|
|
51
60
|
.action(async (opts) => {
|
|
52
61
|
const { runJudgeConfigure } = await import('./commands/judge.js');
|
|
@@ -56,6 +65,7 @@ program
|
|
|
56
65
|
.command('login')
|
|
57
66
|
.description('Authenticate with the Intutic control plane')
|
|
58
67
|
.option('--api-key <key>', 'Authenticate with an API key (vk_*)')
|
|
68
|
+
.option('--control-plane-url <url>', 'Control plane to log in to (e.g. a self-hosted one); saved for every later command')
|
|
59
69
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
60
70
|
.action(async (opts) => {
|
|
61
71
|
const { runLogin } = await import('./commands/login.js');
|
|
@@ -108,9 +118,9 @@ program
|
|
|
108
118
|
});
|
|
109
119
|
program
|
|
110
120
|
.command('predict-cost')
|
|
111
|
-
.description('Pre-flight cost estimate for a prompt/task before it runs (
|
|
112
|
-
|
|
113
|
-
'every other cost figure
|
|
121
|
+
.description('Pre-flight cost estimate for a prompt/task before it runs (requires `intutic login`). ' +
|
|
122
|
+
"Estimates output tokens from the workspace's recorded usage and prices them with the same " +
|
|
123
|
+
'rate table as every other cost figure the control plane reports.')
|
|
114
124
|
.requiredOption('--model <model>', 'Model to estimate against (e.g. claude-sonnet-4-5)')
|
|
115
125
|
.option('--task-type <type>', 'Task type used to pick the baseline bucket', 'coding')
|
|
116
126
|
.option('--tokens <n>', 'Input token count (mutually exclusive with --file)')
|
|
@@ -128,7 +138,7 @@ sopsCmd
|
|
|
128
138
|
.command('push <name>')
|
|
129
139
|
.description('Push a local offline SOP folder to the central workspace')
|
|
130
140
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
131
|
-
.option('--org', "Push as an org-wide floor
|
|
141
|
+
.option('--org', "Push as an org-wide floor instead of a workspace SOP -- applies to every workspace under the caller's org, in addition to that workspace's own SOPs")
|
|
132
142
|
.action(async (name, opts) => {
|
|
133
143
|
const { runSopsPush } = await import('./commands/sops.js');
|
|
134
144
|
await runSopsPush(name, opts);
|
|
@@ -152,7 +162,7 @@ sopsCmd
|
|
|
152
162
|
});
|
|
153
163
|
sopsCmd
|
|
154
164
|
.command('org-list')
|
|
155
|
-
.description("List org-wide SOP floors for the caller's own org
|
|
165
|
+
.description("List org-wide SOP floors for the caller's own org")
|
|
156
166
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
157
167
|
.action(async (opts) => {
|
|
158
168
|
const { runSopsOrgList } = await import('./commands/sops.js');
|
|
@@ -349,7 +359,7 @@ guardrailsCmd
|
|
|
349
359
|
.command('list')
|
|
350
360
|
.description('List guardrails with their status and shadow evidence')
|
|
351
361
|
.option('--status <status>', 'PROPOSED | SHADOW | ENFORCING | REJECTED | RETIRED')
|
|
352
|
-
.option('--target <target>', 'hook_rule | sop_front_matter | wasm_rule')
|
|
362
|
+
.option('--target <target>', 'hook_rule | sop_front_matter | wasm_rule | workspace_setting')
|
|
353
363
|
.option('--doc <docId>', 'Only guardrails cited from this document')
|
|
354
364
|
.option('--limit <n>', 'Max rows (default 50, capped at 200)')
|
|
355
365
|
.option('--json', 'Output as JSON')
|
|
@@ -378,8 +388,8 @@ guardrailsCmd
|
|
|
378
388
|
});
|
|
379
389
|
guardrailsCmd
|
|
380
390
|
.command('promote <guardrailId>')
|
|
381
|
-
.description('Promote a shadow guardrail to enforcing once the server says it is ready')
|
|
382
|
-
.option('--acknowledge-no-traffic', 'Promote a rule that no observed traffic exercised')
|
|
391
|
+
.description('Promote a shadow guardrail to enforcing once the server says it is ready (an egress allow list is applied from proposed)')
|
|
392
|
+
.option('--acknowledge-no-traffic', 'Promote a rule that no observed traffic exercised, or apply an egress allow list, which has no shadow evidence')
|
|
383
393
|
.option('--json', 'Output as JSON')
|
|
384
394
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
385
395
|
.action(async (guardrailId, opts) => {
|
|
@@ -475,7 +485,7 @@ program
|
|
|
475
485
|
program
|
|
476
486
|
.command('start')
|
|
477
487
|
.description('Start the proxy standalone — no account or control plane needed')
|
|
478
|
-
.option('--port <port>', 'Proxy port
|
|
488
|
+
.option('--port <port>', 'Proxy port (default: the port of $INTUTIC_PROXY_URL, else 4000)')
|
|
479
489
|
.option('--valkey-port <port>', 'Valkey port', '6379')
|
|
480
490
|
.option('--upstream-url <url>', 'Upstream LLM provider base URL')
|
|
481
491
|
.action(async (opts) => {
|
|
@@ -531,7 +541,7 @@ enterpriseCmd
|
|
|
531
541
|
.option('--mdm-output-dir <dir>', 'Directory to write generated MDM manifests to', './intutic-mdm')
|
|
532
542
|
.option('--skip-ca', 'Skip system-wide CA trust installation')
|
|
533
543
|
.option('--skip-hooks', 'Skip system-level Cursor hooks installation')
|
|
534
|
-
.option('--dev', '
|
|
544
|
+
.option('--dev', 'Send the device enforcement report to the local control plane (http://localhost:3001)')
|
|
535
545
|
.option('--cli-binary-path <path>', 'Absolute path to the intutic CLI binary on TARGET machines, embedded in the firewall-deployment manifests (default: /usr/local/bin/intutic — override if your fleet installs elsewhere)')
|
|
536
546
|
.action(async (opts) => {
|
|
537
547
|
const { runEnterpriseInstall } = await import('./commands/enterprise.js');
|
|
@@ -542,7 +552,7 @@ const envCmd = program
|
|
|
542
552
|
.description('Persist or clear the proxy base-URL environment variables');
|
|
543
553
|
envCmd
|
|
544
554
|
.command('persist')
|
|
545
|
-
.description('Write ANTHROPIC_BASE_URL / OPENAI_BASE_URL at the OS level so
|
|
555
|
+
.description('Write ANTHROPIC_BASE_URL / OPENAI_BASE_URL at the OS level so new shells and apps pick them up.\n' +
|
|
546
556
|
' macOS: launchctl setenv Linux: ~/.bashrc Windows: setx\n' +
|
|
547
557
|
'\n' +
|
|
548
558
|
' Opt-in on purpose: on macOS this reaches every GUI app you launch afterwards.\n' +
|
|
@@ -573,8 +583,8 @@ program
|
|
|
573
583
|
});
|
|
574
584
|
program
|
|
575
585
|
.command('sync-context')
|
|
576
|
-
.description('
|
|
577
|
-
.option('--git', '
|
|
586
|
+
.description('Record the Git branch and commit in .intutic/git-context.json, which a running `intutic connect` reports')
|
|
587
|
+
.option('--git', 'Read the branch and commit from the repository (for any not given below)')
|
|
578
588
|
.option('--branch <name>', 'Current Git branch name')
|
|
579
589
|
.option('--commit <hash>', 'Current Git commit SHA')
|
|
580
590
|
.action(async (opts) => {
|
|
@@ -585,7 +595,7 @@ program
|
|
|
585
595
|
.command('decisions-log-refresh')
|
|
586
596
|
.description('One-shot refresh of the governed decisions log (.intutic/DECISIONS.md + the claude-code ' +
|
|
587
597
|
'harness config section) — no-ops if decisionsLogEnabled is off. Invoked by the optional ' +
|
|
588
|
-
'post-merge hook
|
|
598
|
+
'post-merge Git hook `intutic init` installs; safe to run manually.')
|
|
589
599
|
.action(async () => {
|
|
590
600
|
const { refreshDecisionsLog } = await import('./lib/decisionsLogRefresh.js');
|
|
591
601
|
const result = await refreshDecisionsLog(process.cwd());
|
|
@@ -602,7 +612,7 @@ program
|
|
|
602
612
|
// (LLD #63 §6): cap-drop, no-new-privileges, read-only rootfs, resource caps,
|
|
603
613
|
// and a default-deny egress firewall the agent cannot undo.
|
|
604
614
|
.option('--sandbox [kind]', 'Run the agent in an isolated sandbox (kind: oci | firecracker; default oci)')
|
|
605
|
-
.option('--sandbox-image <image>', 'Sandbox image (must contain the agent + nftables + capsh)',
|
|
615
|
+
.option('--sandbox-image <image>', 'Sandbox image (must contain the agent + nftables + capsh); the default is built locally on first use', DEFAULT_SANDBOX_IMAGE)
|
|
606
616
|
.option('--sandbox-memory <size>', 'Sandbox memory cap (e.g. 2g)', '2g')
|
|
607
617
|
.option('--sandbox-cpus <n>', 'Sandbox CPU cap', '2')
|
|
608
618
|
.option('--sandbox-pids <n>', 'Sandbox max process count', '512')
|
|
@@ -658,7 +668,7 @@ const findings = program
|
|
|
658
668
|
findings
|
|
659
669
|
.command('list')
|
|
660
670
|
.description('List detector findings for the workspace')
|
|
661
|
-
.option('--unadjudicated',
|
|
671
|
+
.option('--unadjudicated', 'Only show findings nobody has ruled on yet (default: all findings)')
|
|
662
672
|
.option('--detector <id>', 'Filter by detector_id (e.g. response_injection:override-instructions)')
|
|
663
673
|
.option('--limit <n>', 'Max rows to return (default: 100, max: 500)')
|
|
664
674
|
.option('--json', 'Output as JSON instead of table')
|
|
@@ -690,8 +700,8 @@ findings
|
|
|
690
700
|
findings
|
|
691
701
|
.command('echo-report')
|
|
692
702
|
.description('Response-injection echo measurement report — per-pattern false-positive rate')
|
|
693
|
-
.option('--since <date>', 'ISO date — window start (
|
|
694
|
-
.option('--until <date>', 'ISO date — window end (
|
|
703
|
+
.option('--since <date>', 'ISO date — window start (default: 7 days before --until)')
|
|
704
|
+
.option('--until <date>', 'ISO date — window end (default: now)')
|
|
695
705
|
.option('--json', 'Output as JSON instead of table')
|
|
696
706
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
697
707
|
.action(async (opts) => {
|
|
@@ -715,6 +725,7 @@ integrity
|
|
|
715
725
|
integrity
|
|
716
726
|
.command('verify <root_id>')
|
|
717
727
|
.description('Re-derive a root from the live traces and check its signature (exit 1 on mismatch)')
|
|
728
|
+
.option('--against <file>', 'Also compare with the copy of this root mirrored to your own bucket (BYOC)')
|
|
718
729
|
.option('--json', 'Output as JSON instead of a report')
|
|
719
730
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
720
731
|
.action(async (rootId, opts) => {
|
|
@@ -747,7 +758,7 @@ const routing = program
|
|
|
747
758
|
routing
|
|
748
759
|
.command('adoption-report')
|
|
749
760
|
.description('Mirror-test adoption report for one candidate model — win/loss/tie, fault-rate delta, ' +
|
|
750
|
-
'cost delta, latency delta
|
|
761
|
+
'cost delta, latency delta. ' +
|
|
751
762
|
'A reported signal for human review, not an automatic gate.')
|
|
752
763
|
.requiredOption('--candidate-model <model>', 'The mirror-tested candidate model to report on')
|
|
753
764
|
.option('--json', 'Output as JSON instead of a report')
|
|
@@ -760,80 +771,93 @@ routing
|
|
|
760
771
|
const daemon = program
|
|
761
772
|
.command('daemon')
|
|
762
773
|
.description('Manage the Intutic sync-daemon, MCP daemon and standalone proxy system services (LaunchAgent / systemd)');
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
774
|
+
// `install` and `uninstall` are also reachable as the top-level shortcuts
|
|
775
|
+
// `intutic install-daemon` / `intutic uninstall-daemon`. A commander alias only
|
|
776
|
+
// renames a command within its own parent, so each verb is defined once here
|
|
777
|
+
// and registered in both places. The shortcuts used to be separate copies, and
|
|
778
|
+
// they drifted: `install-daemon` had no --mcp, --proxy or proxy options and
|
|
779
|
+
// demanded a workspace and key even for the standalone proxy, while the docs
|
|
780
|
+
// called it a shortcut for `daemon install`.
|
|
781
|
+
function defineDaemonInstall(cmd) {
|
|
782
|
+
return cmd
|
|
783
|
+
.description('Install sync-daemon as a system service (auto-starts on login, restarts on any exit).\n' +
|
|
784
|
+
' macOS: ~/Library/LaunchAgents/ai.intutic.sync-daemon.plist (KeepAlive: true)\n' +
|
|
785
|
+
' Linux: ~/.config/systemd/user/intutic-sync-daemon.service (Restart=always)\n' +
|
|
786
|
+
'\n' +
|
|
787
|
+
' --proxy installs the standalone intutic-proxy binary instead (no workspace or key needed):\n' +
|
|
788
|
+
' macOS: ~/Library/LaunchAgents/ai.intutic.proxy.plist\n' +
|
|
789
|
+
' Linux: ~/.config/systemd/user/intutic-proxy.service\n' +
|
|
790
|
+
'\n' +
|
|
791
|
+
' The service restarts whenever its process exits, so killing the process does not stop it.\n' +
|
|
792
|
+
' Use \'intutic daemon stop\' or \'intutic daemon uninstall\'.')
|
|
793
|
+
.option('--workspace-id <id>', 'Workspace ID (e.g. wk_xxxx) — required unless --proxy')
|
|
794
|
+
.option('--api-key <key>', 'Workspace API key (e.g. vk_xxxx) — required unless --proxy')
|
|
795
|
+
.option('--control-plane-url <url>', 'Control plane the daemon connects to (default: $INTUTIC_CONTROL_PLANE_URL, then the URL saved by `intutic login`, then https://api.intutic.ai)')
|
|
796
|
+
.option('--binary-path <path>', 'Path to intutic CLI binary (defaults to current process); with --proxy, absolute path to intutic-proxy')
|
|
797
|
+
.option('--dry-run', 'Print what would be done without writing files')
|
|
798
|
+
.option('--system', 'Install as a system-level service (LaunchDaemon on macOS, systemd system unit on Linux)')
|
|
799
|
+
.option('--mcp', 'Install the MCP proxy daemon instead of the sync-daemon')
|
|
800
|
+
.option('--proxy', 'Install the standalone intutic-proxy binary as a service')
|
|
801
|
+
.option('--port <port>', 'With --proxy: proxy listen port (default: the port of $INTUTIC_PROXY_URL, else 4000)')
|
|
802
|
+
.option('--valkey-url <url>', 'With --proxy: Valkey URL to attach to; omit to run standalone (INTUTIC_STANDALONE=1)')
|
|
803
|
+
.option('--upstream-url <url>', 'With --proxy: upstream LLM provider base URL')
|
|
804
|
+
.action(async (opts, cmd) => {
|
|
805
|
+
if (opts.proxy) {
|
|
806
|
+
// The standalone proxy has no control plane, so no workspace or key.
|
|
807
|
+
// Its unit carries the same environment `intutic start` sets, fixed at
|
|
808
|
+
// install time rather than probed at launch.
|
|
809
|
+
const { installProxyService } = await import('./commands/install-daemon.js');
|
|
810
|
+
await installProxyService({
|
|
811
|
+
port: opts.port,
|
|
812
|
+
valkeyUrl: opts.valkeyUrl,
|
|
813
|
+
upstreamUrl: opts.upstreamUrl,
|
|
814
|
+
binaryPath: opts.binaryPath,
|
|
815
|
+
dryRun: opts.dryRun,
|
|
816
|
+
system: opts.system,
|
|
817
|
+
});
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
// Required for the two daemons; commander's `requiredOption` cannot express
|
|
821
|
+
// "unless --proxy", so the check lives here with the same wording.
|
|
822
|
+
if (!opts.workspaceId)
|
|
823
|
+
cmd.error("error: required option '--workspace-id <id>' not specified");
|
|
824
|
+
if (!opts.apiKey)
|
|
825
|
+
cmd.error("error: required option '--api-key <key>' not specified");
|
|
826
|
+
// `installMcpDaemon` and `buildMcpPlist` were written, tested and exported,
|
|
827
|
+
// and then nothing called them: every route into install-daemon.ts landed
|
|
828
|
+
// on `installDaemon`, so the MCP proxy daemon could not be installed by any
|
|
829
|
+
// command the CLI offered. This flag is that missing route.
|
|
830
|
+
const { installDaemon, installMcpDaemon } = await import('./commands/install-daemon.js');
|
|
831
|
+
const install = opts.mcp ? installMcpDaemon : installDaemon;
|
|
832
|
+
await install({
|
|
833
|
+
workspaceId: opts.workspaceId,
|
|
834
|
+
apiKey: opts.apiKey,
|
|
835
|
+
controlPlaneUrl: opts.controlPlaneUrl,
|
|
797
836
|
binaryPath: opts.binaryPath,
|
|
798
837
|
dryRun: opts.dryRun,
|
|
799
838
|
system: opts.system,
|
|
800
839
|
});
|
|
801
|
-
return;
|
|
802
|
-
}
|
|
803
|
-
// Required for the two daemons; commander's `requiredOption` cannot express
|
|
804
|
-
// "unless --proxy", so the check lives here with the same wording.
|
|
805
|
-
if (!opts.workspaceId)
|
|
806
|
-
cmd.error("error: required option '--workspace-id <id>' not specified");
|
|
807
|
-
if (!opts.apiKey)
|
|
808
|
-
cmd.error("error: required option '--api-key <key>' not specified");
|
|
809
|
-
// `installMcpDaemon` and `buildMcpPlist` were written, tested and exported,
|
|
810
|
-
// and then nothing called them: every route into install-daemon.ts landed
|
|
811
|
-
// on `installDaemon`, so the MCP proxy daemon could not be installed by any
|
|
812
|
-
// command the CLI offered (TD-153). This flag is that missing route.
|
|
813
|
-
const { installDaemon, installMcpDaemon } = await import('./commands/install-daemon.js');
|
|
814
|
-
const install = opts.mcp ? installMcpDaemon : installDaemon;
|
|
815
|
-
await install({
|
|
816
|
-
workspaceId: opts.workspaceId,
|
|
817
|
-
apiKey: opts.apiKey,
|
|
818
|
-
controlPlaneUrl: opts.controlPlaneUrl,
|
|
819
|
-
binaryPath: opts.binaryPath,
|
|
820
|
-
dryRun: opts.dryRun,
|
|
821
|
-
system: opts.system,
|
|
822
840
|
});
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
}
|
|
841
|
+
}
|
|
842
|
+
function defineDaemonUninstall(cmd) {
|
|
843
|
+
return cmd
|
|
844
|
+
.description('Remove the sync-daemon system service and stop it permanently.')
|
|
845
|
+
.option('--dry-run', 'Print what would be done without writing files')
|
|
846
|
+
.option('--system', 'Uninstall the system-level service')
|
|
847
|
+
.option('--mcp', 'Uninstall the MCP proxy daemon instead of the sync-daemon')
|
|
848
|
+
.option('--proxy', 'Uninstall the standalone intutic-proxy service instead of the sync-daemon')
|
|
849
|
+
.action(async (opts) => {
|
|
850
|
+
const { uninstallDaemon, uninstallMcpDaemon, uninstallProxyService } = await import('./commands/install-daemon.js');
|
|
851
|
+
const uninstall = opts.proxy ? uninstallProxyService : opts.mcp ? uninstallMcpDaemon : uninstallDaemon;
|
|
852
|
+
await uninstall({ dryRun: opts.dryRun, system: opts.system });
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
defineDaemonInstall(daemon.command('install'));
|
|
856
|
+
defineDaemonUninstall(daemon.command('uninstall'));
|
|
857
|
+
defineDaemonInstall(program.command('install-daemon'))
|
|
858
|
+
.summary("Shortcut for 'intutic daemon install'");
|
|
859
|
+
defineDaemonUninstall(program.command('uninstall-daemon'))
|
|
860
|
+
.summary("Shortcut for 'intutic daemon uninstall'");
|
|
837
861
|
daemon
|
|
838
862
|
.command('status')
|
|
839
863
|
.description('Show sync-daemon system service status (or the standalone proxy service with --proxy).')
|
|
@@ -870,39 +894,6 @@ daemon
|
|
|
870
894
|
const { daemonStart, proxyServiceStart, mcpDaemonStart } = await import('./commands/install-daemon.js');
|
|
871
895
|
await (opts.proxy ? proxyServiceStart() : opts.mcp ? mcpDaemonStart() : daemonStart());
|
|
872
896
|
});
|
|
873
|
-
// Top-level shortcuts (for discoverability)
|
|
874
|
-
program
|
|
875
|
-
.command('install-daemon', { hidden: false })
|
|
876
|
-
.description('Shortcut for \'intutic daemon install\' — install sync-daemon as system service')
|
|
877
|
-
.requiredOption('--workspace-id <id>', 'Workspace ID')
|
|
878
|
-
.requiredOption('--api-key <key>', 'Workspace API key')
|
|
879
|
-
.option('--control-plane-url <url>', 'Control plane URL', 'https://api.intutic.ai')
|
|
880
|
-
.option('--binary-path <path>', 'Path to intutic CLI binary')
|
|
881
|
-
.option('--dry-run', 'Print what would be done without writing files')
|
|
882
|
-
.option('--system', 'Install as a system-level service')
|
|
883
|
-
.action(async (opts) => {
|
|
884
|
-
const { installDaemon } = await import('./commands/install-daemon.js');
|
|
885
|
-
await installDaemon({
|
|
886
|
-
workspaceId: opts.workspaceId,
|
|
887
|
-
apiKey: opts.apiKey,
|
|
888
|
-
controlPlaneUrl: opts.controlPlaneUrl,
|
|
889
|
-
binaryPath: opts.binaryPath,
|
|
890
|
-
dryRun: opts.dryRun,
|
|
891
|
-
system: opts.system,
|
|
892
|
-
});
|
|
893
|
-
});
|
|
894
|
-
program
|
|
895
|
-
.command('uninstall-daemon', { hidden: false })
|
|
896
|
-
.description('Shortcut for \'intutic daemon uninstall\'')
|
|
897
|
-
.option('--dry-run', 'Print what would be done without writing files')
|
|
898
|
-
.option('--system', 'Uninstall the system-level service')
|
|
899
|
-
.option('--mcp', 'Uninstall the MCP proxy daemon instead of the sync-daemon')
|
|
900
|
-
.option('--proxy', 'Uninstall the standalone intutic-proxy service instead of the sync-daemon')
|
|
901
|
-
.action(async (opts) => {
|
|
902
|
-
const { uninstallDaemon, uninstallMcpDaemon, uninstallProxyService } = await import('./commands/install-daemon.js');
|
|
903
|
-
const uninstall = opts.proxy ? uninstallProxyService : opts.mcp ? uninstallMcpDaemon : uninstallDaemon;
|
|
904
|
-
await uninstall({ dryRun: opts.dryRun, system: opts.system });
|
|
905
|
-
});
|
|
906
897
|
// ── Skill commands ─────────────────────────────────────────────────────────
|
|
907
898
|
const skillCmd = program
|
|
908
899
|
.command('skill')
|
|
@@ -920,9 +911,10 @@ skillCmd
|
|
|
920
911
|
.option('--sarif', 'Output findings as a SARIF 2.1.0 document (for GitHub Code Scanning / CI interop) instead of the human-readable report')
|
|
921
912
|
.option('--engine <engine>', "Scanning engine: 'native' (default, always runs) or 'cisco' to also run the opt-in Cisco " +
|
|
922
913
|
"skill-scanner integration (requires the 'skill-scanner' binary on PATH — pipx install cisco-ai-skill-scanner)", 'native')
|
|
914
|
+
.option('--exit-zero', 'Exit 0 even when there are findings (by default findings exit 1)')
|
|
923
915
|
.action(async (opts) => {
|
|
924
916
|
const { runSkillAudit } = await import('./commands/skill.js');
|
|
925
|
-
await runSkillAudit({ sarif: opts.sarif, engine: opts.engine });
|
|
917
|
+
await runSkillAudit({ sarif: opts.sarif, engine: opts.engine, exitZero: opts.exitZero });
|
|
926
918
|
});
|
|
927
919
|
skillCmd
|
|
928
920
|
.command('scan-staged')
|
|
@@ -969,7 +961,7 @@ loopCmd
|
|
|
969
961
|
.option('--approve', 'Release the hold; the run resumes')
|
|
970
962
|
.option('--reject', 'Refuse the hold; the run is killed')
|
|
971
963
|
.option('--note <note>', 'Why, recorded against the run')
|
|
972
|
-
.option('--dev', '
|
|
964
|
+
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
973
965
|
.action(async (loopRunId, opts) => {
|
|
974
966
|
const { runLoopReview } = await import('./commands/skill.js');
|
|
975
967
|
await runLoopReview(loopRunId, opts);
|
|
@@ -1154,7 +1146,7 @@ const attenuateCmd = program
|
|
|
1154
1146
|
.description('Attenuate an API key to a narrower child key (capability subset + optional TTL)')
|
|
1155
1147
|
.option('--parent-key <keyId>', 'Parent API key ID to attenuate')
|
|
1156
1148
|
.option('--caps <caps>', 'Comma-separated capability subset to grant the child key')
|
|
1157
|
-
.option('--ttl <seconds>', 'Child key TTL in seconds (
|
|
1149
|
+
.option('--ttl <seconds>', 'Child key TTL in whole seconds, 60 to 86400 (default 14400)')
|
|
1158
1150
|
.option('--dev', 'Use local control plane (http://localhost:3001)')
|
|
1159
1151
|
.action(async (opts) => {
|
|
1160
1152
|
const { runAttenuate } = await import('./commands/attenuate.js');
|