@intutic/cli 0.1.1 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/dist/cli.js +376 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/benchmark.d.ts +31 -0
  4. package/dist/commands/benchmark.d.ts.map +1 -0
  5. package/dist/commands/benchmark.js +211 -0
  6. package/dist/commands/benchmark.js.map +1 -0
  7. package/dist/commands/connect.d.ts +8 -6
  8. package/dist/commands/connect.d.ts.map +1 -1
  9. package/dist/commands/connect.js +414 -80
  10. package/dist/commands/connect.js.map +1 -1
  11. package/dist/commands/enterprise-install.d.ts +36 -0
  12. package/dist/commands/enterprise-install.d.ts.map +1 -0
  13. package/dist/commands/enterprise-install.js +289 -0
  14. package/dist/commands/enterprise-install.js.map +1 -0
  15. package/dist/commands/eval.d.ts +13 -0
  16. package/dist/commands/eval.d.ts.map +1 -0
  17. package/dist/commands/eval.js +67 -0
  18. package/dist/commands/eval.js.map +1 -0
  19. package/dist/commands/exec.d.ts +34 -0
  20. package/dist/commands/exec.d.ts.map +1 -0
  21. package/dist/commands/exec.js +114 -0
  22. package/dist/commands/exec.js.map +1 -0
  23. package/dist/commands/exec.test.d.ts +2 -0
  24. package/dist/commands/exec.test.d.ts.map +1 -0
  25. package/dist/commands/exec.test.js +29 -0
  26. package/dist/commands/exec.test.js.map +1 -0
  27. package/dist/commands/export.d.ts +21 -0
  28. package/dist/commands/export.d.ts.map +1 -0
  29. package/dist/commands/export.js +116 -0
  30. package/dist/commands/export.js.map +1 -0
  31. package/dist/commands/init.d.ts.map +1 -1
  32. package/dist/commands/init.js +28 -2
  33. package/dist/commands/init.js.map +1 -1
  34. package/dist/commands/install-daemon.d.ts +61 -0
  35. package/dist/commands/install-daemon.d.ts.map +1 -0
  36. package/dist/commands/install-daemon.js +691 -0
  37. package/dist/commands/install-daemon.js.map +1 -0
  38. package/dist/commands/install-daemon.test.d.ts +2 -0
  39. package/dist/commands/install-daemon.test.d.ts.map +1 -0
  40. package/dist/commands/install-daemon.test.js +93 -0
  41. package/dist/commands/install-daemon.test.js.map +1 -0
  42. package/dist/commands/login.js +2 -2
  43. package/dist/commands/login.js.map +1 -1
  44. package/dist/commands/logout.js +1 -1
  45. package/dist/commands/logout.js.map +1 -1
  46. package/dist/commands/mdm.d.ts +23 -0
  47. package/dist/commands/mdm.d.ts.map +1 -0
  48. package/dist/commands/mdm.js +134 -0
  49. package/dist/commands/mdm.js.map +1 -0
  50. package/dist/commands/skill.d.ts +27 -0
  51. package/dist/commands/skill.d.ts.map +1 -0
  52. package/dist/commands/skill.js +289 -0
  53. package/dist/commands/skill.js.map +1 -0
  54. package/dist/commands/sop-audit.d.ts +17 -0
  55. package/dist/commands/sop-audit.d.ts.map +1 -0
  56. package/dist/commands/sop-audit.js +136 -0
  57. package/dist/commands/sop-audit.js.map +1 -0
  58. package/dist/commands/status.d.ts.map +1 -1
  59. package/dist/commands/status.js +53 -1
  60. package/dist/commands/status.js.map +1 -1
  61. package/dist/commands/syncContext.d.ts +18 -0
  62. package/dist/commands/syncContext.d.ts.map +1 -0
  63. package/dist/commands/syncContext.js +37 -0
  64. package/dist/commands/syncContext.js.map +1 -0
  65. package/dist/commands/traces.d.ts +13 -0
  66. package/dist/commands/traces.d.ts.map +1 -1
  67. package/dist/commands/traces.js +96 -2
  68. package/dist/commands/traces.js.map +1 -1
  69. package/dist/commands/whoami.js +1 -1
  70. package/dist/commands/whoami.js.map +1 -1
  71. package/dist/config/keychain.d.ts +28 -0
  72. package/dist/config/keychain.d.ts.map +1 -0
  73. package/dist/config/keychain.js +99 -0
  74. package/dist/config/keychain.js.map +1 -0
  75. package/dist/config/store.d.ts +3 -3
  76. package/dist/config/store.d.ts.map +1 -1
  77. package/dist/config/store.js +30 -6
  78. package/dist/config/store.js.map +1 -1
  79. package/dist/harness/aider.d.ts +4 -3
  80. package/dist/harness/aider.d.ts.map +1 -1
  81. package/dist/harness/aider.js +13 -27
  82. package/dist/harness/aider.js.map +1 -1
  83. package/dist/harness/claudeDesktop.d.ts +18 -0
  84. package/dist/harness/claudeDesktop.d.ts.map +1 -0
  85. package/dist/harness/claudeDesktop.js +69 -0
  86. package/dist/harness/claudeDesktop.js.map +1 -0
  87. package/dist/harness/cline.d.ts +13 -0
  88. package/dist/harness/cline.d.ts.map +1 -0
  89. package/dist/harness/cline.js +75 -0
  90. package/dist/harness/cline.js.map +1 -0
  91. package/dist/harness/codex.d.ts +4 -4
  92. package/dist/harness/codex.d.ts.map +1 -1
  93. package/dist/harness/codex.js +33 -21
  94. package/dist/harness/codex.js.map +1 -1
  95. package/dist/harness/continue.d.ts +14 -0
  96. package/dist/harness/continue.d.ts.map +1 -0
  97. package/dist/harness/continue.js +97 -0
  98. package/dist/harness/continue.js.map +1 -0
  99. package/dist/harness/cursor.d.ts +13 -1
  100. package/dist/harness/cursor.d.ts.map +1 -1
  101. package/dist/harness/cursor.js +59 -3
  102. package/dist/harness/cursor.js.map +1 -1
  103. package/dist/harness/detector.d.ts +1 -1
  104. package/dist/harness/detector.d.ts.map +1 -1
  105. package/dist/harness/detector.js +13 -1
  106. package/dist/harness/detector.js.map +1 -1
  107. package/dist/harness/goose.d.ts +13 -0
  108. package/dist/harness/goose.d.ts.map +1 -0
  109. package/dist/harness/goose.js +45 -0
  110. package/dist/harness/goose.js.map +1 -0
  111. package/dist/harness/n8n.d.ts +8 -4
  112. package/dist/harness/n8n.d.ts.map +1 -1
  113. package/dist/harness/n8n.js +108 -13
  114. package/dist/harness/n8n.js.map +1 -1
  115. package/dist/harness/openWebUI.d.ts +13 -0
  116. package/dist/harness/openWebUI.d.ts.map +1 -0
  117. package/dist/harness/openWebUI.js +25 -0
  118. package/dist/harness/openWebUI.js.map +1 -0
  119. package/dist/harness/openhands.d.ts +3 -3
  120. package/dist/harness/openhands.d.ts.map +1 -1
  121. package/dist/harness/openhands.js +13 -9
  122. package/dist/harness/openhands.js.map +1 -1
  123. package/dist/harness/rooCode.d.ts +14 -0
  124. package/dist/harness/rooCode.d.ts.map +1 -0
  125. package/dist/harness/rooCode.js +77 -0
  126. package/dist/harness/rooCode.js.map +1 -0
  127. package/dist/harness/types.d.ts.map +1 -1
  128. package/dist/harness/types.js +6 -0
  129. package/dist/harness/types.js.map +1 -1
  130. package/dist/harness/vscodeSettingsWriter.d.ts +40 -0
  131. package/dist/harness/vscodeSettingsWriter.d.ts.map +1 -0
  132. package/dist/harness/vscodeSettingsWriter.js +116 -0
  133. package/dist/harness/vscodeSettingsWriter.js.map +1 -0
  134. package/dist/harness/windsurf.d.ts +13 -1
  135. package/dist/harness/windsurf.d.ts.map +1 -1
  136. package/dist/harness/windsurf.js +58 -3
  137. package/dist/harness/windsurf.js.map +1 -1
  138. package/dist/lib/api.d.ts +2 -0
  139. package/dist/lib/api.d.ts.map +1 -1
  140. package/dist/lib/api.js +71 -1
  141. package/dist/lib/api.js.map +1 -1
  142. package/dist/lib/envInjector.d.ts +24 -0
  143. package/dist/lib/envInjector.d.ts.map +1 -0
  144. package/dist/lib/envInjector.js +146 -0
  145. package/dist/lib/envInjector.js.map +1 -0
  146. package/dist/lib/envInjector.test.d.ts +2 -0
  147. package/dist/lib/envInjector.test.d.ts.map +1 -0
  148. package/dist/lib/envInjector.test.js +32 -0
  149. package/dist/lib/envInjector.test.js.map +1 -0
  150. package/dist/lib/gitHooks.d.ts +19 -0
  151. package/dist/lib/gitHooks.d.ts.map +1 -0
  152. package/dist/lib/gitHooks.js +58 -0
  153. package/dist/lib/gitHooks.js.map +1 -0
  154. package/dist/lib/onboarding.d.ts +17 -0
  155. package/dist/lib/onboarding.d.ts.map +1 -0
  156. package/dist/lib/onboarding.js +164 -0
  157. package/dist/lib/onboarding.js.map +1 -0
  158. package/dist/lib/process.d.ts +53 -0
  159. package/dist/lib/process.d.ts.map +1 -0
  160. package/dist/lib/process.js +181 -0
  161. package/dist/lib/process.js.map +1 -0
  162. package/dist/lib/process.test.d.ts +2 -0
  163. package/dist/lib/process.test.d.ts.map +1 -0
  164. package/dist/lib/process.test.js +44 -0
  165. package/dist/lib/process.test.js.map +1 -0
  166. package/package.json +22 -33
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enterprise-install.d.ts","sourceRoot":"","sources":["../../src/commands/enterprise-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA+OH;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDhB"}
@@ -0,0 +1,289 @@
1
+ /**
2
+ * enterprise-install.ts — `intutic enterprise-install` CLI command.
3
+ *
4
+ * Requires elevated privileges (sudo on macOS/Linux, admin on Windows).
5
+ * Writes system-level governance hooks that survive user-level tampering:
6
+ *
7
+ * macOS:
8
+ * - /etc/cursor/hooks.json (system Cursor hooks)
9
+ * - System keychain CA trust entry for Intutic proxy CA cert
10
+ * - MDM configuration profile generator
11
+ *
12
+ * Linux:
13
+ * - /etc/cursor/hooks.json
14
+ * - /usr/local/share/ca-certificates/intutic-ca.crt + update-ca-certificates
15
+ *
16
+ * Windows:
17
+ * - certutil -addstore Root intutic-ca.crt
18
+ * - HKLM registry-based Cursor hooks (via PowerShell)
19
+ *
20
+ * Usage: sudo intutic enterprise-install
21
+ *
22
+ * LLD #14 — Phase 3 cross-harness defence
23
+ * @module
24
+ */
25
+ import { writeFile, mkdir, readFile } from 'node:fs/promises';
26
+ import { execFile } from 'node:child_process';
27
+ import { promisify } from 'node:util';
28
+ import { join } from 'node:path';
29
+ import { homedir } from 'node:os';
30
+ import { newIso } from '@intutic/id';
31
+ import { createLogger } from '@intutic/logger';
32
+ import { writeCursorHooks } from '@intutic/sync-daemon/harness/cursorHooks';
33
+ const log = createLogger('enterprise-install');
34
+ const execFileAsync = promisify(execFile);
35
+ /** Check if running with root/admin privileges. */
36
+ function isElevated() {
37
+ if (process.platform === 'win32') {
38
+ // On Windows, check if we have admin rights (heuristic)
39
+ return process.env.USERNAME === 'Administrator' || process.env.IS_ADMIN === '1';
40
+ }
41
+ return process.getuid?.() === 0;
42
+ }
43
+ /** Platform-specific system Cursor hooks path. */
44
+ function systemCursorHooksPath() {
45
+ if (process.platform === 'darwin') {
46
+ return '/Library/Application Support/Cursor/hooks.json';
47
+ }
48
+ return '/etc/cursor/hooks.json';
49
+ }
50
+ /** Platform-specific CA injection command. */
51
+ async function injectCaCert(caCertPath) {
52
+ switch (process.platform) {
53
+ case 'darwin':
54
+ await execFileAsync('security', [
55
+ 'add-trusted-cert', '-d', '-r', 'trustRoot',
56
+ '-k', '/Library/Keychains/System.keychain',
57
+ caCertPath,
58
+ ]);
59
+ log.info({ action: 'ca_injected', platform: 'darwin' }, 'CA cert added to macOS System Keychain');
60
+ break;
61
+ case 'linux': {
62
+ const destCert = '/usr/local/share/ca-certificates/intutic-ca.crt';
63
+ const content = await readFile(caCertPath, 'utf-8');
64
+ await writeFile(destCert, content, 'utf-8');
65
+ await execFileAsync('update-ca-certificates');
66
+ log.info({ action: 'ca_injected', platform: 'linux' }, 'CA cert added via update-ca-certificates');
67
+ break;
68
+ }
69
+ case 'win32':
70
+ await execFileAsync('certutil', ['-addstore', 'Root', caCertPath]);
71
+ log.info({ action: 'ca_injected', platform: 'win32' }, 'CA cert added to Windows Root store');
72
+ break;
73
+ default:
74
+ log.warn({ action: 'ca_inject_skipped', platform: process.platform }, 'CA injection not supported on this platform');
75
+ }
76
+ }
77
+ /** Write system-level Cursor hooks.json (requires root). */
78
+ async function writeSystemCursorHooks(proxyUrl, workspaceRoot) {
79
+ const systemPath = systemCursorHooksPath();
80
+ await mkdir(systemPath.substring(0, systemPath.lastIndexOf('/')), { recursive: true });
81
+ // Delegate to cursorHooks.ts with writeSystemLevel=true
82
+ await writeCursorHooks(workspaceRoot, proxyUrl, '', true);
83
+ log.info({ action: 'system_cursor_hooks_written', path: systemPath }, 'System-level Cursor hooks written');
84
+ }
85
+ /** Generate MDM deployment manifest for Cursor. */
86
+ async function generateMdmManifest(proxyUrl, outputDir) {
87
+ await mkdir(outputDir, { recursive: true });
88
+ // Cursor hooks MDM manifest (JSON — deployable via Jamf, Intune, Chef)
89
+ const cursorManifest = {
90
+ _comment: 'Intutic Governance — Cursor system-level hooks.json for MDM deployment',
91
+ _generated: newIso(),
92
+ target_path: systemCursorHooksPath(),
93
+ content: {
94
+ failClosed: true,
95
+ hooks: {
96
+ beforeShellExecution: {
97
+ command: 'node /opt/intutic/hooks/pre-tool-check.js',
98
+ failClosed: true,
99
+ },
100
+ beforeMCPExecution: {
101
+ command: 'node /opt/intutic/hooks/pre-tool-check.js',
102
+ failClosed: true,
103
+ },
104
+ beforeFileEdit: {
105
+ command: 'node /opt/intutic/hooks/pre-tool-check.js',
106
+ failClosed: true,
107
+ },
108
+ },
109
+ },
110
+ deployment: {
111
+ jamf: 'Deploy as Extension Attribute with file target_path',
112
+ intune: 'Custom Configuration Profile > Files > target_path',
113
+ chef: 'cookbook: intutic-governance, recipe: cursor_hooks',
114
+ },
115
+ };
116
+ await writeFile(join(outputDir, 'cursor-hooks-manifest.json'), JSON.stringify(cursorManifest, null, 2), 'utf-8');
117
+ // Windsurf proxy settings MDM manifest
118
+ const windsurfManifest = {
119
+ _comment: 'Intutic Governance — Windsurf proxy settings for MDM deployment',
120
+ _generated: newIso(),
121
+ target_path: `${homedir()}/.codeium/windsurf/settings.json`,
122
+ note: 'User-level path — deploy per user via login script or MDM user config',
123
+ content: {
124
+ 'http.proxy': 'http://127.0.0.1:8877',
125
+ 'http.proxyStrictSSL': false,
126
+ 'codeium.proxy': 'http://127.0.0.1:8877',
127
+ },
128
+ };
129
+ await writeFile(join(outputDir, 'windsurf-proxy-manifest.json'), JSON.stringify(windsurfManifest, null, 2), 'utf-8');
130
+ // macOS MDM configuration profile for CA trust + proxy
131
+ const mobileconfig = `<?xml version="1.0" encoding="UTF-8"?>
132
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
133
+ <!-- Intutic Governance Proxy MDM Configuration Profile -->
134
+ <!-- Deploy via Jamf, Apple Business Manager, or profiles install -->
135
+ <!-- Generated: ${newIso()} -->
136
+ <plist version="1.0">
137
+ <dict>
138
+ <key>PayloadContent</key>
139
+ <array>
140
+ <dict>
141
+ <!-- CA Trust payload -->
142
+ <key>PayloadType</key>
143
+ <string>com.apple.security.root</string>
144
+ <key>PayloadIdentifier</key>
145
+ <string>ai.intutic.governance.ca</string>
146
+ <key>PayloadDisplayName</key>
147
+ <string>Intutic Governance Proxy CA</string>
148
+ <key>PayloadDescription</key>
149
+ <string>Trusts the Intutic local CA for AI traffic governance</string>
150
+ <key>PayloadVersion</key>
151
+ <integer>1</integer>
152
+ <key>PayloadUUID</key>
153
+ <string>4E89D13A-B6C2-4F1D-9E2A-7F3C5A8B2E6D</string>
154
+ </dict>
155
+ <dict>
156
+ <!-- System-wide HTTP proxy for Windsurf Cascade AI traffic -->
157
+ <key>PayloadType</key>
158
+ <string>com.apple.proxy.http</string>
159
+ <key>PayloadIdentifier</key>
160
+ <string>ai.intutic.governance.proxy</string>
161
+ <key>PayloadDisplayName</key>
162
+ <string>Intutic AI Governance Proxy</string>
163
+ <key>Enabled</key>
164
+ <true/>
165
+ <key>Server</key>
166
+ <string>127.0.0.1</string>
167
+ <key>Port</key>
168
+ <integer>8877</integer>
169
+ <key>ProxyType</key>
170
+ <string>HTTP</string>
171
+ </dict>
172
+ </array>
173
+ <key>PayloadDisplayName</key>
174
+ <string>Intutic AI Governance Proxy Configuration</string>
175
+ <key>PayloadIdentifier</key>
176
+ <string>ai.intutic.governance</string>
177
+ <key>PayloadType</key>
178
+ <string>Configuration</string>
179
+ <key>PayloadVersion</key>
180
+ <integer>1</integer>
181
+ <key>PayloadUUID</key>
182
+ <string>8A1C3F5E-D2B4-4A6C-8E0F-1D3B5A7C9E2F</string>
183
+ </dict>
184
+ </plist>`;
185
+ await writeFile(join(outputDir, 'intutic-governance.mobileconfig'), mobileconfig, 'utf-8');
186
+ log.info({ action: 'mdm_manifests_generated', outputDir }, 'MDM deployment manifests generated');
187
+ }
188
+ /** Generate pf (macOS) and iptables (Linux) firewall rules templates. */
189
+ async function generateFirewallTemplates(outputDir) {
190
+ await mkdir(outputDir, { recursive: true });
191
+ // pf.conf template (macOS)
192
+ const pfConf = `# Intutic PF Firewall redirection rules for macOS
193
+ # Redirects direct outbound traffic to AI providers to the local Intutic proxy (port 4000).
194
+ # To load: sudo pfctl -f ${join(outputDir, 'pf.conf')}
195
+
196
+ # AI Provider hostnames
197
+ ai_hosts = "{ api.anthropic.com, api.openai.com, api2.cursor.sh, openrouter.ai, api.mistral.ai, api.cohere.com, api.together.xyz, generativelanguage.googleapis.com }"
198
+
199
+ # Redirection rule: redirect outbound HTTPS traffic to these hosts to localhost:4000
200
+ # To avoid loop, do not redirect traffic originating from the local proxy process itself (exclude user running the proxy)
201
+ # Update 'intutic' to the user/UID running the proxy if needed.
202
+ # rdr pass on lo0 proto tcp from any to $ai_hosts port 443 -> 127.0.0.1 port 4000 user intutic
203
+ rdr pass on lo0 proto tcp from any to $ai_hosts port 443 -> 127.0.0.1 port 4000
204
+ rdr pass on en0 proto tcp from any to $ai_hosts port 443 -> 127.0.0.1 port 4000
205
+ rdr pass on en1 proto tcp from any to $ai_hosts port 443 -> 127.0.0.1 port 4000
206
+ `;
207
+ await writeFile(join(outputDir, 'pf.conf'), pfConf, 'utf-8');
208
+ // iptables.rules template (Linux)
209
+ const iptablesRules = `# Intutic iptables redirection rules for Linux
210
+ # Redirects direct outbound HTTPS traffic to AI providers to the local Intutic proxy (port 4000).
211
+ # Load with: sudo iptables-restore < ${join(outputDir, 'iptables.rules')}
212
+
213
+ *nat
214
+ :PREROUTING ACCEPT [0:0]
215
+ :INPUT ACCEPT [0:0]
216
+ :OUTPUT ACCEPT [0:0]
217
+ :POSTROUTING ACCEPT [0:0]
218
+
219
+ # Create INTUTIC chain
220
+ -N INTUTIC
221
+
222
+ # Redirect to local proxy port 4000
223
+ -A INTUTIC -p tcp --dport 443 -j REDIRECT --to-ports 4000
224
+
225
+ # Intercept AI providers in OUTPUT chain (for local client processes)
226
+ # Skip traffic originating from the proxy itself to prevent routing loop.
227
+ # Assuming the proxy runs under a group 'intutic' or user 'intutic'.
228
+ # Replace 'intutic' with the username/group running the proxy.
229
+ -A OUTPUT -p tcp -m owner --uid-owner intutic -j ACCEPT
230
+ -A OUTPUT -d api.anthropic.com -p tcp --dport 443 -j INTUTIC
231
+ -A OUTPUT -d api.openai.com -p tcp --dport 443 -j INTUTIC
232
+ -A OUTPUT -d api2.cursor.sh -p tcp --dport 443 -j INTUTIC
233
+ -A OUTPUT -d openrouter.ai -p tcp --dport 443 -j INTUTIC
234
+ -A OUTPUT -d api.mistral.ai -p tcp --dport 443 -j INTUTIC
235
+ -A OUTPUT -d api.cohere.com -p tcp --dport 443 -j INTUTIC
236
+ -A OUTPUT -d api.together.xyz -p tcp --dport 443 -j INTUTIC
237
+ -A OUTPUT -d generativelanguage.googleapis.com -p tcp --dport 443 -j INTUTIC
238
+
239
+ COMMIT
240
+ `;
241
+ await writeFile(join(outputDir, 'iptables.rules'), iptablesRules, 'utf-8');
242
+ log.info({ action: 'firewall_templates_generated', outputDir }, 'Firewall redirection templates generated');
243
+ }
244
+ /**
245
+ * Main enterprise-install entry point.
246
+ * Called by the `intutic enterprise-install` CLI command.
247
+ */
248
+ export async function enterpriseInstall(options) {
249
+ const { proxyUrl, workspaceRoot = process.cwd(), mdmOutputDir = join(process.cwd(), 'tools', 'cli', 'resources', 'mdm'), firewallOutputDir = join(process.cwd(), 'tools', 'cli', 'resources', 'firewall'), generateMdmOnly = false, } = options;
250
+ // Always generate MDM and firewall manifests (no privileges needed)
251
+ await generateMdmManifest(proxyUrl, mdmOutputDir);
252
+ await generateFirewallTemplates(firewallOutputDir);
253
+ if (generateMdmOnly) {
254
+ log.info('MDM and firewall templates generated. Use --generate-mdm-only to skip privilege-requiring steps.');
255
+ return;
256
+ }
257
+ if (!isElevated()) {
258
+ log.error('enterprise-install requires root/admin privileges. Run with sudo.');
259
+ console.error('\n❌ Error: intutic enterprise-install requires root privileges.\n Run: sudo intutic enterprise-install\n');
260
+ process.exit(1);
261
+ }
262
+ // Write system-level Cursor hooks
263
+ await writeSystemCursorHooks(proxyUrl, workspaceRoot);
264
+ // Inject CA cert into system trust store
265
+ const caCertPath = join(homedir(), '.intutic', 'ca.crt');
266
+ try {
267
+ await readFile(caCertPath);
268
+ await injectCaCert(caCertPath);
269
+ }
270
+ catch {
271
+ log.warn({ action: 'ca_cert_missing', path: caCertPath }, 'CA cert not found — run `intutic init` first to generate it, then re-run enterprise-install');
272
+ }
273
+ log.info({ action: 'enterprise_install_complete', proxyUrl }, 'Enterprise install complete. Deploy MDM manifests and firewall rules from the generated output directories.');
274
+ console.log(`
275
+ ✅ Intutic Enterprise Install Complete
276
+
277
+ System-level Cursor hooks: ${systemCursorHooksPath()}
278
+ CA cert injected into system trust store
279
+ MDM manifests written to: ${mdmOutputDir}
280
+ Firewall rules written to: ${firewallOutputDir}
281
+
282
+ Next steps:
283
+ 1. Deploy intutic-governance.mobileconfig via Jamf/Apple Business Manager
284
+ 2. Deploy cursor-hooks-manifest.json via your MDM solution
285
+ 3. Load firewall redirection rules (e.g. pfctl or iptables) from: ${firewallOutputDir}
286
+ 4. Start the Intutic proxy: intutic proxy start
287
+ `);
288
+ }
289
+ //# sourceMappingURL=enterprise-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enterprise-install.js","sourceRoot":"","sources":["../../src/commands/enterprise-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAA;AAE3E,MAAM,GAAG,GAAG,YAAY,CAAC,oBAAoB,CAAC,CAAA;AAC9C,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAEzC,mDAAmD;AACnD,SAAS,UAAU;IACjB,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,wDAAwD;QACxD,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAA;IACjF,CAAC;IACD,OAAO,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,CAAA;AACjC,CAAC;AAED,kDAAkD;AAClD,SAAS,qBAAqB;IAC5B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,gDAAgD,CAAA;IACzD,CAAC;IACD,OAAO,wBAAwB,CAAA;AACjC,CAAC;AAED,8CAA8C;AAC9C,KAAK,UAAU,YAAY,CAAC,UAAkB;IAC5C,QAAQ,OAAO,CAAC,QAAQ,EAAE,CAAC;QACzB,KAAK,QAAQ;YACX,MAAM,aAAa,CAAC,UAAU,EAAE;gBAC9B,kBAAkB,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW;gBAC3C,IAAI,EAAE,oCAAoC;gBAC1C,UAAU;aACX,CAAC,CAAA;YACF,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,wCAAwC,CAAC,CAAA;YACjG,MAAK;QAEP,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,QAAQ,GAAG,iDAAiD,CAAA;YAClE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;YACnD,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;YAC3C,MAAM,aAAa,CAAC,wBAAwB,CAAC,CAAA;YAC7C,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,0CAA0C,CAAC,CAAA;YAClG,MAAK;QACP,CAAC;QAED,KAAK,OAAO;YACV,MAAM,aAAa,CAAC,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAA;YAClE,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,qCAAqC,CAAC,CAAA;YAC7F,MAAK;QAEP;YACE,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,6CAA6C,CAAC,CAAA;IACxH,CAAC;AACH,CAAC;AAED,4DAA4D;AAC5D,KAAK,UAAU,sBAAsB,CAAC,QAAgB,EAAE,aAAqB;IAC3E,MAAM,UAAU,GAAG,qBAAqB,EAAE,CAAA;IAC1C,MAAM,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACtF,wDAAwD;IACxD,MAAM,gBAAgB,CAAC,aAAa,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,CAAC,CAAA;IACzD,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,6BAA6B,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,mCAAmC,CAAC,CAAA;AAC5G,CAAC;AAED,mDAAmD;AACnD,KAAK,UAAU,mBAAmB,CAAC,QAAgB,EAAE,SAAiB;IACpE,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE3C,uEAAuE;IACvE,MAAM,cAAc,GAAG;QACrB,QAAQ,EAAE,wEAAwE;QAClF,UAAU,EAAE,MAAM,EAAE;QACpB,WAAW,EAAE,qBAAqB,EAAE;QACpC,OAAO,EAAE;YACP,UAAU,EAAE,IAAI;YAChB,KAAK,EAAE;gBACL,oBAAoB,EAAE;oBACpB,OAAO,EAAE,2CAA2C;oBACpD,UAAU,EAAE,IAAI;iBACjB;gBACD,kBAAkB,EAAE;oBAClB,OAAO,EAAE,2CAA2C;oBACpD,UAAU,EAAE,IAAI;iBACjB;gBACD,cAAc,EAAE;oBACd,OAAO,EAAE,2CAA2C;oBACpD,UAAU,EAAE,IAAI;iBACjB;aACF;SACF;QACD,UAAU,EAAE;YACV,IAAI,EAAE,qDAAqD;YAC3D,MAAM,EAAE,oDAAoD;YAC5D,IAAI,EAAE,oDAAoD;SAC3D;KACF,CAAA;IACD,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,4BAA4B,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAA;IAEhH,uCAAuC;IACvC,MAAM,gBAAgB,GAAG;QACvB,QAAQ,EAAE,iEAAiE;QAC3E,UAAU,EAAE,MAAM,EAAE;QACpB,WAAW,EAAE,GAAG,OAAO,EAAE,kCAAkC;QAC3D,IAAI,EAAE,uEAAuE;QAC7E,OAAO,EAAE;YACP,YAAY,EAAE,uBAAuB;YACrC,qBAAqB,EAAE,KAAK;YAC5B,eAAe,EAAE,uBAAuB;SACzC;KACF,CAAA;IACD,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,8BAA8B,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAA;IAEpH,uDAAuD;IACvD,MAAM,YAAY,GAAG;;;;kBAIL,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAiDjB,CAAA;IACP,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,iCAAiC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,CAAA;IAE1F,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,yBAAyB,EAAE,SAAS,EAAE,EAAE,oCAAoC,CAAC,CAAA;AAClG,CAAC;AAED,yEAAyE;AACzE,KAAK,UAAU,yBAAyB,CAAC,SAAiB;IACxD,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE3C,2BAA2B;IAC3B,MAAM,MAAM,GAAG;;2BAEU,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC;;;;;;;;;;;;CAYpD,CAAA;IACC,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;IAE5D,kCAAkC;IAClC,MAAM,aAAa,GAAG;;uCAEe,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BvE,CAAA;IACC,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,CAAA;IAE1E,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,8BAA8B,EAAE,SAAS,EAAE,EAAE,0CAA0C,CAAC,CAAA;AAC7G,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAMvC;IACC,MAAM,EACJ,QAAQ,EACR,aAAa,GAAG,OAAO,CAAC,GAAG,EAAE,EAC7B,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,CAAC,EACtE,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,CAAC,EAChF,eAAe,GAAG,KAAK,GACxB,GAAG,OAAO,CAAA;IAEX,oEAAoE;IACpE,MAAM,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;IACjD,MAAM,yBAAyB,CAAC,iBAAiB,CAAC,CAAA;IAElD,IAAI,eAAe,EAAE,CAAC;QACpB,GAAG,CAAC,IAAI,CAAC,kGAAkG,CAAC,CAAA;QAC5G,OAAM;IACR,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QAClB,GAAG,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAA;QAC9E,OAAO,CAAC,KAAK,CAAC,4GAA4G,CAAC,CAAA;QAC3H,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,kCAAkC;IAClC,MAAM,sBAAsB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAA;IAErD,yCAAyC;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;IACxD,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAA;QAC1B,MAAM,YAAY,CAAC,UAAU,CAAC,CAAA;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,CAAC,IAAI,CACN,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,UAAU,EAAE,EAC/C,6FAA6F,CAC9F,CAAA;IACH,CAAC;IAED,GAAG,CAAC,IAAI,CACN,EAAE,MAAM,EAAE,6BAA6B,EAAE,QAAQ,EAAE,EACnD,6GAA6G,CAC9G,CAAA;IACD,OAAO,CAAC,GAAG,CAAC;;;6BAGe,qBAAqB,EAAE;;4BAExB,YAAY;6BACX,iBAAiB;;;;;sEAKwB,iBAAiB;;CAEtF,CAAC,CAAA;AACF,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * `intutic eval` — Run evaluator sandbox evaluations from CLI.
3
+ *
4
+ * Calls POST /api/v1/evaluator/runs to trigger and poll results.
5
+ *
6
+ * E6 — Evaluator Sandbox / CLI
7
+ * @module
8
+ */
9
+ export declare function runEval(opts: {
10
+ dataset: string;
11
+ dev?: boolean;
12
+ }): Promise<void>;
13
+ //# sourceMappingURL=eval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval.d.ts","sourceRoot":"","sources":["../../src/commands/eval.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DrF"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `intutic eval` — Run evaluator sandbox evaluations from CLI.
3
+ *
4
+ * Calls POST /api/v1/evaluator/runs to trigger and poll results.
5
+ *
6
+ * E6 — Evaluator Sandbox / CLI
7
+ * @module
8
+ */
9
+ import { log } from '../lib/logger.js';
10
+ import { loadCredentials } from '../config/store.js';
11
+ import { resolveControlPlaneUrl } from '../config/paths.js';
12
+ import { createApiClient } from '../lib/api.js';
13
+ export async function runEval(opts) {
14
+ const creds = await loadCredentials();
15
+ if (!creds) {
16
+ log.error('Not authenticated. Run `intutic login` first.');
17
+ process.exit(1);
18
+ }
19
+ const controlPlaneUrl = resolveControlPlaneUrl(opts.dev);
20
+ const client = createApiClient(controlPlaneUrl, creds.apiKey);
21
+ try {
22
+ log.info(`Triggering evaluation run for dataset: ${opts.dataset}...`);
23
+ const { runId } = await client.post('/api/v1/evaluator/runs', {
24
+ datasetId: opts.dataset,
25
+ triggeredBy: 'manual',
26
+ });
27
+ log.success(`Run created: ${runId}. Polling status...`);
28
+ // Poll until complete
29
+ let attempts = 0;
30
+ const maxAttempts = 150; // ~5 minutes max
31
+ while (attempts < maxAttempts) {
32
+ const { run } = await client.get(`/api/v1/evaluator/runs/${runId}`);
33
+ if (run.status === 'completed') {
34
+ log.header('Evaluation Run Complete');
35
+ log.field('Run ID', run.runId);
36
+ log.field('Dataset ID', run.datasetId);
37
+ log.field('Status', run.status);
38
+ log.field('Pass Rate', run.passRate ? `${(parseFloat(run.passRate) * 100).toFixed(1)}%` : 'N/A');
39
+ log.field('Average Similarity', run.avgScore ? parseFloat(run.avgScore).toFixed(4) : 'N/A');
40
+ log.field('Weakening Detected', run.weakeningDetected ? 'YES' : 'NO');
41
+ log.field('Deploy Guard', run.deployApproved ? 'APPROVED' : 'BLOCKED');
42
+ if (!run.deployApproved) {
43
+ log.error('Evaluation failed deploy guard check.');
44
+ process.exit(1);
45
+ }
46
+ else {
47
+ log.success('Evaluation passed all checks.');
48
+ process.exit(0);
49
+ }
50
+ }
51
+ else if (run.status === 'failed') {
52
+ log.error(`Evaluation run failed: ${run.errorMessage || 'Unknown error'}`);
53
+ process.exit(1);
54
+ }
55
+ // Still running or pending
56
+ attempts++;
57
+ await new Promise((resolve) => setTimeout(resolve, 2000));
58
+ }
59
+ log.error('Evaluation timed out waiting for completion.');
60
+ process.exit(1);
61
+ }
62
+ catch (err) {
63
+ log.error(`Failed to execute evaluation: ${err.message || String(err)}`);
64
+ process.exit(1);
65
+ }
66
+ }
67
+ //# sourceMappingURL=eval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval.js","sourceRoot":"","sources":["../../src/commands/eval.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `intutic exec` — Subprocess wrapper with proxy env var injection.
3
+ *
4
+ * Spawns a child process with all Intutic proxy environment variables
5
+ * pre-injected, routing LLM traffic through the local governance proxy.
6
+ *
7
+ * Covers competing SDK env var conventions:
8
+ * - OPENAI_API_BASE (LiteLLM, LangChain, CrewAI, ADK, Aider)
9
+ * - OPENAI_BASE_URL (OpenAI Python SDK v1+, Pydantic-AI, Agent SDK)
10
+ * - OPENAI_API_BASE_URL (OpenWebUI)
11
+ * - OPENAI_HOST (Goose)
12
+ * - ANTHROPIC_BASE_URL (Claude Code, Anthropic SDK — host only)
13
+ * - ANTHROPIC_API_KEY (Claude Code)
14
+ * - OPENAI_API_KEY (all OpenAI-compatible tools)
15
+ * - INTUTIC_API_KEY (Intutic-native tools)
16
+ *
17
+ * LLD #8 — Sync Daemon / CLI
18
+ * @module
19
+ */
20
+ /**
21
+ * Build the proxy environment variables for a child process.
22
+ *
23
+ * @param apiKey - Intutic API key (intk_...)
24
+ * @param devMode - If true, use localhost:4000; otherwise use remote proxy
25
+ * @returns Record of env vars to inject
26
+ */
27
+ export declare function buildProxyEnv(apiKey: string, devMode: boolean): Record<string, string>;
28
+ /**
29
+ * Execute a command with Intutic proxy environment variables injected.
30
+ *
31
+ * @param commandAndArgs - Array of command + arguments (e.g. ['claude'] or ['python', 'main.py'])
32
+ */
33
+ export declare function runExec(commandAndArgs: string[]): Promise<void>;
34
+ //# sourceMappingURL=exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/commands/exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA2BtF;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDrE"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * `intutic exec` — Subprocess wrapper with proxy env var injection.
3
+ *
4
+ * Spawns a child process with all Intutic proxy environment variables
5
+ * pre-injected, routing LLM traffic through the local governance proxy.
6
+ *
7
+ * Covers competing SDK env var conventions:
8
+ * - OPENAI_API_BASE (LiteLLM, LangChain, CrewAI, ADK, Aider)
9
+ * - OPENAI_BASE_URL (OpenAI Python SDK v1+, Pydantic-AI, Agent SDK)
10
+ * - OPENAI_API_BASE_URL (OpenWebUI)
11
+ * - OPENAI_HOST (Goose)
12
+ * - ANTHROPIC_BASE_URL (Claude Code, Anthropic SDK — host only)
13
+ * - ANTHROPIC_API_KEY (Claude Code)
14
+ * - OPENAI_API_KEY (all OpenAI-compatible tools)
15
+ * - INTUTIC_API_KEY (Intutic-native tools)
16
+ *
17
+ * LLD #8 — Sync Daemon / CLI
18
+ * @module
19
+ */
20
+ import { spawn } from 'node:child_process';
21
+ import { loadCredentials, loadConfig } from '../config/store.js';
22
+ import { log } from '../lib/logger.js';
23
+ import pc from 'picocolors';
24
+ /**
25
+ * Build the proxy environment variables for a child process.
26
+ *
27
+ * @param apiKey - Intutic API key (intk_...)
28
+ * @param devMode - If true, use localhost:4000; otherwise use remote proxy
29
+ * @returns Record of env vars to inject
30
+ */
31
+ export function buildProxyEnv(apiKey, devMode) {
32
+ const proxyUrl = devMode
33
+ ? 'http://localhost:4000/v1'
34
+ : 'https://proxy.intutic.ai/v1';
35
+ // Host-only URL (no /v1) — used by Claude Code and Goose
36
+ const proxyHost = devMode
37
+ ? 'http://localhost:4000'
38
+ : 'https://proxy.intutic.ai';
39
+ return {
40
+ // OpenAI-compatible (covers LiteLLM, LangChain, CrewAI, ADK, Aider)
41
+ OPENAI_API_BASE: proxyUrl,
42
+ // OpenAI SDK v1+ (covers Python SDK, Pydantic-AI, Agent SDK)
43
+ OPENAI_BASE_URL: proxyUrl,
44
+ // OpenWebUI (uses its own unique env var name)
45
+ OPENAI_API_BASE_URL: proxyUrl,
46
+ // Goose (uses OPENAI_HOST, not OPENAI_API_BASE)
47
+ OPENAI_HOST: proxyHost,
48
+ // All OpenAI-compatible API keys
49
+ OPENAI_API_KEY: apiKey,
50
+ // Anthropic SDK / Claude Code (host only — appends /v1/messages itself)
51
+ ANTHROPIC_BASE_URL: proxyHost,
52
+ ANTHROPIC_API_KEY: apiKey,
53
+ // Intutic-native
54
+ INTUTIC_API_KEY: apiKey,
55
+ };
56
+ }
57
+ /**
58
+ * Execute a command with Intutic proxy environment variables injected.
59
+ *
60
+ * @param commandAndArgs - Array of command + arguments (e.g. ['claude'] or ['python', 'main.py'])
61
+ */
62
+ export async function runExec(commandAndArgs) {
63
+ if (commandAndArgs.length === 0) {
64
+ log.error('No command specified.');
65
+ log.dim('Usage: intutic exec -- <command> [args...]');
66
+ log.dim('Example: intutic exec -- claude');
67
+ log.dim('Example: intutic exec -- aider --model openai/gpt-4o');
68
+ log.dim('Example: intutic exec -- python my_agent.py');
69
+ process.exit(1);
70
+ }
71
+ // Load credentials
72
+ const creds = await loadCredentials();
73
+ if (!creds) {
74
+ log.error('Not authenticated. Run `intutic login` first.');
75
+ process.exit(1);
76
+ }
77
+ // Load config for dev mode
78
+ const config = loadConfig();
79
+ const devMode = config?.devMode ?? process.env.INTUTIC_DEV === '1';
80
+ // Build env
81
+ const proxyEnv = buildProxyEnv(creds.apiKey, devMode);
82
+ const childEnv = { ...process.env, ...proxyEnv };
83
+ const [exe, ...args] = commandAndArgs;
84
+ // Print info
85
+ log.info(`Launching: ${pc.bold(exe)} ${args.join(' ')}`);
86
+ log.dim(`Proxy: ${proxyEnv.OPENAI_API_BASE}`);
87
+ log.dim(`API Key: ${creds.apiKey.slice(0, 8)}...${creds.apiKey.slice(-4)}`);
88
+ console.log('');
89
+ // Spawn the child process with inherited stdio (full interactivity)
90
+ const child = spawn(exe, args, {
91
+ stdio: 'inherit',
92
+ env: childEnv,
93
+ shell: process.platform === 'win32', // Use shell on Windows for PATH resolution
94
+ });
95
+ child.on('error', (err) => {
96
+ if (err.code === 'ENOENT') {
97
+ log.error(`Command not found: ${exe}`);
98
+ log.dim('Make sure the command is installed and in your PATH.');
99
+ }
100
+ else {
101
+ log.error(`Failed to start: ${err.message}`);
102
+ }
103
+ process.exit(127);
104
+ });
105
+ child.on('exit', (code, signal) => {
106
+ if (signal) {
107
+ process.kill(process.pid, signal);
108
+ }
109
+ else {
110
+ process.exit(code ?? 0);
111
+ }
112
+ });
113
+ }
114
+ //# sourceMappingURL=exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/commands/exec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=exec.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.test.d.ts","sourceRoot":"","sources":["../../src/commands/exec.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { buildProxyEnv } from './exec.js';
3
+ describe('Subprocess Exec Env Builder', () => {
4
+ it('correctly maps proxy URLs in dev mode', () => {
5
+ const apiKey = 'intk_test12345';
6
+ const env = buildProxyEnv(apiKey, true);
7
+ expect(env.OPENAI_API_BASE).toBe('http://localhost:4000/v1');
8
+ expect(env.OPENAI_BASE_URL).toBe('http://localhost:4000/v1');
9
+ expect(env.OPENAI_API_BASE_URL).toBe('http://localhost:4000/v1');
10
+ expect(env.OPENAI_HOST).toBe('http://localhost:4000');
11
+ expect(env.ANTHROPIC_BASE_URL).toBe('http://localhost:4000');
12
+ expect(env.OPENAI_API_KEY).toBe(apiKey);
13
+ expect(env.ANTHROPIC_API_KEY).toBe(apiKey);
14
+ expect(env.INTUTIC_API_KEY).toBe(apiKey);
15
+ });
16
+ it('correctly maps proxy URLs in production mode', () => {
17
+ const apiKey = 'intk_prod98765';
18
+ const env = buildProxyEnv(apiKey, false);
19
+ expect(env.OPENAI_API_BASE).toBe('https://proxy.intutic.ai/v1');
20
+ expect(env.OPENAI_BASE_URL).toBe('https://proxy.intutic.ai/v1');
21
+ expect(env.OPENAI_API_BASE_URL).toBe('https://proxy.intutic.ai/v1');
22
+ expect(env.OPENAI_HOST).toBe('https://proxy.intutic.ai');
23
+ expect(env.ANTHROPIC_BASE_URL).toBe('https://proxy.intutic.ai');
24
+ expect(env.OPENAI_API_KEY).toBe(apiKey);
25
+ expect(env.ANTHROPIC_API_KEY).toBe(apiKey);
26
+ expect(env.INTUTIC_API_KEY).toBe(apiKey);
27
+ });
28
+ });
29
+ //# sourceMappingURL=exec.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.test.js","sourceRoot":"","sources":["../../src/commands/exec.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAEzC,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;IAC3C,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,MAAM,GAAG,gBAAgB,CAAA;QAC/B,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QAEvC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;QAC5D,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;QAC5D,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;QAChE,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;QACrD,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;QAE5D,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACvC,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC1C,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAC1C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,MAAM,GAAG,gBAAgB,CAAA;QAC/B,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QAExC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;QAC/D,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;QAC/D,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;QACnE,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;QACxD,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;QAE/D,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACvC,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC1C,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAC1C,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * `intutic export` — Manage warehouse exports from the CLI.
3
+ *
4
+ * E4 — Data Warehouse Export / CLI
5
+ * @module
6
+ */
7
+ export declare function runExportConfig(opts: {
8
+ provider?: 'gcs' | 's3';
9
+ bucket?: string;
10
+ prefix?: string;
11
+ credentials?: string;
12
+ region?: string;
13
+ format?: 'csv' | 'parquet' | 'ndjson';
14
+ dev?: boolean;
15
+ }): Promise<void>;
16
+ export declare function runExportStatus(opts: {
17
+ triggerTarget?: string;
18
+ format?: 'csv' | 'parquet' | 'ndjson';
19
+ dev?: boolean;
20
+ }): Promise<void>;
21
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,QAAQ,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAA;IACrC,GAAG,CAAC,EAAE,OAAO,CAAA;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDhB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,MAAM,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAA;IACrC,GAAG,CAAC,EAAE,OAAO,CAAA;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDhB"}