subconscious-cli 6.0.1 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +167 -43
  2. package/bin/agent-data.js +278 -0
  3. package/bin/agent-help.js +114 -0
  4. package/bin/agent-install.js +238 -0
  5. package/bin/agent-launch.js +199 -0
  6. package/bin/agent-spawn.js +137 -0
  7. package/bin/agents.js +236 -931
  8. package/bin/auth.js +9 -1
  9. package/bin/claude-picker.js +143 -0
  10. package/bin/cli.js +62 -2
  11. package/bin/clipboard-image.js +2 -0
  12. package/bin/feedback.js +14 -3
  13. package/bin/harness-manifest.js +286 -0
  14. package/bin/headless-args.js +35 -0
  15. package/bin/launch-values.js +25 -0
  16. package/bin/model-capabilities.js +10 -9
  17. package/bin/models.js +25 -13
  18. package/bin/native/subc-tui-darwin-amd64 +0 -0
  19. package/bin/native/subc-tui-darwin-arm64 +0 -0
  20. package/bin/native/subc-tui-linux-amd64 +0 -0
  21. package/bin/native/subc-tui-linux-arm64 +0 -0
  22. package/bin/native/subc-tui-windows-amd64.exe +0 -0
  23. package/bin/native/subc-tui-windows-arm64.exe +0 -0
  24. package/bin/opencode-provider.js +21 -0
  25. package/bin/profile-settings.js +129 -0
  26. package/bin/profiles.js +29 -424
  27. package/bin/runbook/README.md +77 -23
  28. package/bin/runbook/claude-code/agent.json +300 -0
  29. package/bin/runbook/claude-code/install.sh +9 -252
  30. package/bin/runbook/codex/agent.json +462 -0
  31. package/bin/runbook/codex/hooks-lib.sh +17 -4
  32. package/bin/runbook/codex/install.sh +0 -4
  33. package/bin/runbook/codex/run.sh +16 -235
  34. package/bin/runbook/copilot/agent.json +186 -0
  35. package/bin/runbook/copilot/install.sh +45 -63
  36. package/bin/runbook/cursor/agent.json +138 -0
  37. package/bin/runbook/cursor/install.sh +8 -35
  38. package/bin/runbook/deepseek-harness/agent.json +164 -0
  39. package/bin/runbook/deepseek-harness/run.sh +20 -59
  40. package/bin/runbook/image-window/index.ts +14 -0
  41. package/bin/runbook/image-window/window.d.ts +19 -0
  42. package/bin/runbook/image-window/window.js +140 -0
  43. package/bin/runbook/lib.sh +41 -0
  44. package/bin/runbook/opencode/agent.json +159 -0
  45. package/bin/runbook/opencode/install.sh +9 -183
  46. package/bin/runbook/opencode/opencode-plugin.d.ts +10 -3
  47. package/bin/runbook/opencode/subconscious-image-window.ts +24 -0
  48. package/bin/runbook/pi/agent.json +217 -0
  49. package/bin/runbook/pi/install.sh +18 -44
  50. package/bin/runbook/pi/run.sh +6 -18
  51. package/bin/runbook/pi/subconscious-compaction.ts +3 -1
  52. package/bin/runbook/shared.json +57 -0
  53. package/bin/sessions.js +53 -48
  54. package/bin/tui.js +13 -0
  55. package/bin/update-check.js +35 -1
  56. package/bin/upgrade.js +27 -34
  57. package/bin/usage.js +21 -10
  58. package/bin/windows/agents.js +28 -60
  59. package/bin/windows/common.js +2 -28
  60. package/bin/windows/launch.js +252 -231
  61. package/bin/windows/process.js +12 -1
  62. package/bin/windows/setup.js +29 -9
  63. package/package.json +2 -4
  64. package/bin/registry.generated.json +0 -406
  65. package/bin/runbook/claude-code/run.sh +0 -254
  66. package/bin/runbook/model-capabilities.generated.sh +0 -9
  67. package/bin/runbook/opencode/provider.sh +0 -93
  68. package/bin/runbook/opencode/run.sh +0 -99
  69. package/bin/runbook/opencode/subconscious-compaction.ts +0 -100
  70. package/bin/runbook/subconscious-code/install.sh +0 -154
  71. package/bin/runbook/subconscious-code/run.sh +0 -21
  72. package/bin/windows/claude.js +0 -100
  73. package/bin/windows/install.js +0 -188
package/bin/profiles.js CHANGED
@@ -7,23 +7,28 @@
7
7
  */
8
8
 
9
9
  import { execFileSync, spawn } from 'node:child_process';
10
- import { readFileSync } from 'node:fs';
11
10
  import fs from 'node:fs/promises';
12
11
  import os from 'node:os';
13
12
  import path from 'node:path';
14
13
  import { c } from './colors.js';
15
14
  import { PUBLIC_CATALOG_FALLBACK_MESSAGE } from './models.js';
16
- import { runWindows, windowsEditor } from './windows/process.js';
15
+ import {
16
+ profileTemplate,
17
+ RUNBOOK_DEFAULTS,
18
+ SUPPORTED_MODELS,
19
+ } from './profile-settings.js';
20
+
21
+ export {
22
+ PROFILE_SETTING_GROUPS,
23
+ profileSettingsForAgent,
24
+ RUNBOOK_DEFAULTS,
25
+ resolvedProfileValues,
26
+ SUPPORTED_MODELS,
27
+ } from './profile-settings.js';
17
28
 
18
- const registry = JSON.parse(
19
- readFileSync(new URL('./registry.generated.json', import.meta.url), 'utf-8'),
20
- );
29
+ import { runWindows, windowsEditor } from './windows/process.js';
21
30
 
22
31
  export const DEFAULT_PROFILE = 'default';
23
- export const SUPPORTED_MODELS =
24
- Array.isArray(registry.defaults.models) && registry.defaults.models.length
25
- ? registry.defaults.models
26
- : [registry.defaults.model];
27
32
  const PREVIOUS_DEFAULT_GATEWAYS = new Set([
28
33
  'https://api.subconscious.dev',
29
34
  'https://api.subconscious.dev/',
@@ -35,416 +40,6 @@ const LEGACY_PROFILES_DIR = CONFIG_OVERRIDE
35
40
  ? null
36
41
  : path.join(os.homedir(), '.subcon', 'profiles');
37
42
 
38
- export const RUNBOOK_DEFAULTS = {
39
- GATEWAY_URL: registry.defaults.baseUrl,
40
- API_KEY: '',
41
- MODEL: registry.defaults.model,
42
- SC_API_KEY: '',
43
- CLAUDE_CODE_SUBAGENT_MODEL: '',
44
- CLAUDE_GATEWAY_URL: '',
45
- CLAUDE_CODE_API_KEY: '',
46
- CODEX_API_KEY: '',
47
- OPENCODE_API_KEY: '',
48
- CURSOR_API_KEY: '',
49
- COPILOT_API_KEY: '',
50
- PI_API_KEY: '',
51
- DEEPSEEK_HARNESS_API_KEY: '',
52
- CLAUDE_CODE_AUTO_COMPACT_WINDOW: '1000000',
53
- CLAUDE_CODE_MAX_CONTEXT_TOKENS: '3000000',
54
- MAX_CONCURRENT_SUBAGENTS: '4',
55
- MAX_SUBAGENT_SPAWN_DEPTH: '1',
56
- CODEX_CONTEXT_WINDOW: '5000000',
57
- CODEX_MAX_CONTEXT_WINDOW: '5000000',
58
- CODEX_AUTO_COMPACT_TOKEN_LIMIT: '4500000',
59
- CODEX_REASONING_EFFORT: 'max',
60
- CODEX_EXTERNAL_TOOLS: 'false',
61
- OPENCODE_CONTEXT_LIMIT: '5000000',
62
- OPENCODE_OUTPUT_LIMIT: '65536',
63
- PI_CONTEXT_WINDOW: '5000000',
64
- PI_MAX_TOKENS: '65536',
65
- DEEPSEEK_HARNESS_CONTEXT_WINDOW: '5000000',
66
- DEEPSEEK_HARNESS_MAX_TOKENS: '65536',
67
- COPILOT_MAX_INPUT_TOKENS: '5000000',
68
- COPILOT_MAX_OUTPUT_TOKENS: '65536',
69
- VSCODE_APP: '',
70
- };
71
-
72
- const SETTINGS = {
73
- GATEWAY_URL: {
74
- key: 'GATEWAY_URL',
75
- label: 'Gateway URL',
76
- description: 'Subconscious gateway origin shared by every integration.',
77
- type: 'url',
78
- required: true,
79
- },
80
- PLATFORM_URL: {
81
- key: 'PLATFORM_URL',
82
- label: 'Platform URL',
83
- description: 'Subconscious platform origin for login, whoami, and usage.',
84
- type: 'url',
85
- },
86
- API_KEY: {
87
- key: 'API_KEY',
88
- label: 'Shared API key',
89
- description: 'Default credential used when an agent-specific key is blank.',
90
- type: 'secret',
91
- },
92
- MODEL: {
93
- key: 'MODEL',
94
- label: 'Default model',
95
- description:
96
- 'Initial model used by coding-agent launches and setup. UNSET uses the first live catalog model.',
97
- type: 'choice',
98
- choices: SUPPORTED_MODELS,
99
- },
100
- SC_API_KEY: {
101
- key: 'SC_API_KEY',
102
- label: 'Subconscious Code API key',
103
- description: 'Subconscious Code credential override; blank uses API_KEY.',
104
- type: 'secret',
105
- },
106
- CLAUDE_CODE_SUBAGENT_MODEL: {
107
- key: 'CLAUDE_CODE_SUBAGENT_MODEL',
108
- label: 'Subagent model',
109
- description:
110
- 'Model used by Claude Code subagents. UNSET follows the default model.',
111
- type: 'choice',
112
- choices: SUPPORTED_MODELS,
113
- },
114
- CLAUDE_GATEWAY_URL: {
115
- key: 'CLAUDE_GATEWAY_URL',
116
- label: 'Claude gateway override',
117
- description: 'Optional Claude-only gateway origin; blank uses GATEWAY_URL.',
118
- type: 'url',
119
- },
120
- CLAUDE_CODE_API_KEY: {
121
- key: 'CLAUDE_CODE_API_KEY',
122
- label: 'Claude API key',
123
- description: 'Claude-specific credential override; blank uses API_KEY.',
124
- type: 'secret',
125
- },
126
- CLAUDE_CODE_AUTO_COMPACT_WINDOW: {
127
- key: 'CLAUDE_CODE_AUTO_COMPACT_WINDOW',
128
- label: 'Auto-compact window',
129
- description: 'Claude token window before compaction (100000–1000000).',
130
- type: 'integer',
131
- min: 100000,
132
- max: 1000000,
133
- },
134
- CLAUDE_CODE_MAX_CONTEXT_TOKENS: {
135
- key: 'CLAUDE_CODE_MAX_CONTEXT_TOKENS',
136
- label: 'Maximum context tokens',
137
- description: 'Maximum context advertised to Claude Code.',
138
- type: 'integer',
139
- min: 1,
140
- },
141
- MAX_CONCURRENT_SUBAGENTS: {
142
- key: 'MAX_CONCURRENT_SUBAGENTS',
143
- label: 'Concurrent subagents',
144
- description: 'Maximum concurrent Claude/Codex subagent threads.',
145
- type: 'integer',
146
- min: 1,
147
- },
148
- CODEX_SUBAGENT_REASONING_EFFORT: {
149
- key: 'CODEX_SUBAGENT_REASONING_EFFORT',
150
- label: 'Subagent reasoning effort',
151
- description:
152
- 'Effort for Codex subagents, set separately from the parent: a marathon model at max thinks for minutes without emitting a token, and a subagent turn is one uninterrupted think, so inheriting max makes every delegated subtask look like a hang.',
153
- type: 'text',
154
- },
155
- CODEX_MULTI_AGENT_VERSION: {
156
- key: 'CODEX_MULTI_AGENT_VERSION',
157
- label: 'Codex multi-agent version',
158
- description:
159
- 'Which subagent implementation Codex offers: v2 gives the collaboration tools. Leave empty to turn subagents off entirely.',
160
- type: 'text',
161
- },
162
- CODEX_STREAM_IDLE_TIMEOUT_MS: {
163
- key: 'CODEX_STREAM_IDLE_TIMEOUT_MS',
164
- label: 'Stream idle timeout (ms)',
165
- description:
166
- 'How long Codex waits on a silent stream before giving up. Needs to exceed the longest think the model will take.',
167
- type: 'integer',
168
- min: 1,
169
- },
170
- MAX_SUBAGENT_SPAWN_DEPTH: {
171
- key: 'MAX_SUBAGENT_SPAWN_DEPTH',
172
- label: 'Subagent spawn depth',
173
- description: 'Maximum Claude subagent nesting depth.',
174
- type: 'integer',
175
- min: 0,
176
- },
177
- CODEX_API_KEY: {
178
- key: 'CODEX_API_KEY',
179
- label: 'Codex API key',
180
- description: 'Codex-specific credential override; blank uses API_KEY.',
181
- type: 'secret',
182
- },
183
- CODEX_CONTEXT_WINDOW: {
184
- key: 'CODEX_CONTEXT_WINDOW',
185
- label: 'Context window',
186
- description: 'Context window written into the Codex model catalog.',
187
- type: 'integer',
188
- min: 1,
189
- },
190
- CODEX_MAX_CONTEXT_WINDOW: {
191
- key: 'CODEX_MAX_CONTEXT_WINDOW',
192
- label: 'Maximum context window',
193
- description: 'Maximum context window written into the Codex catalog.',
194
- type: 'integer',
195
- min: 1,
196
- },
197
- CODEX_AUTO_COMPACT_TOKEN_LIMIT: {
198
- key: 'CODEX_AUTO_COMPACT_TOKEN_LIMIT',
199
- label: 'Auto-compact token limit',
200
- description: 'Codex token threshold that triggers automatic compaction.',
201
- type: 'integer',
202
- min: 1,
203
- },
204
- CODEX_REASONING_EFFORT: {
205
- key: 'CODEX_REASONING_EFFORT',
206
- label: 'Reasoning effort',
207
- description: 'Default Codex reasoning effort.',
208
- type: 'choice',
209
- choices: ['none', 'low', 'medium', 'high', 'max'],
210
- },
211
- CODEX_EXTERNAL_TOOLS: {
212
- key: 'CODEX_EXTERNAL_TOOLS',
213
- label: 'External tools',
214
- description:
215
- 'Enable Codex apps/plugins; may exceed the gateway tool limit.',
216
- type: 'choice',
217
- choices: ['false', 'true'],
218
- },
219
- OPENCODE_API_KEY: {
220
- key: 'OPENCODE_API_KEY',
221
- label: 'OpenCode API key',
222
- description: 'OpenCode-specific credential override; blank uses API_KEY.',
223
- type: 'secret',
224
- },
225
- OPENCODE_CONTEXT_LIMIT: {
226
- key: 'OPENCODE_CONTEXT_LIMIT',
227
- label: 'Context limit',
228
- description: 'OpenCode provider context limit used for compaction.',
229
- type: 'integer',
230
- min: 1,
231
- },
232
- OPENCODE_OUTPUT_LIMIT: {
233
- key: 'OPENCODE_OUTPUT_LIMIT',
234
- label: 'Output limit',
235
- description: 'Maximum output tokens advertised to OpenCode.',
236
- type: 'integer',
237
- min: 1,
238
- },
239
- CURSOR_API_KEY: {
240
- key: 'CURSOR_API_KEY',
241
- label: 'Cursor hook API key',
242
- description: 'Cursor hook credential override; blank uses API_KEY.',
243
- type: 'secret',
244
- },
245
- COPILOT_API_KEY: {
246
- key: 'COPILOT_API_KEY',
247
- label: 'Copilot hook API key',
248
- description: 'Copilot hook credential override; blank uses API_KEY.',
249
- type: 'secret',
250
- },
251
- COPILOT_MAX_INPUT_TOKENS: {
252
- key: 'COPILOT_MAX_INPUT_TOKENS',
253
- label: 'Maximum input tokens',
254
- description: 'Input-token capacity advertised to VS Code.',
255
- type: 'integer',
256
- min: 1,
257
- },
258
- COPILOT_MAX_OUTPUT_TOKENS: {
259
- key: 'COPILOT_MAX_OUTPUT_TOKENS',
260
- label: 'Maximum output tokens',
261
- description: 'Output-token capacity advertised to VS Code.',
262
- type: 'integer',
263
- min: 1,
264
- },
265
- VSCODE_APP: {
266
- key: 'VSCODE_APP',
267
- label: 'VS Code application',
268
- description: 'Optional application override; blank enables auto-detection.',
269
- type: 'choice',
270
- choices: ['', 'Code', 'Code - Insiders', 'VSCodium'],
271
- },
272
- PI_API_KEY: {
273
- key: 'PI_API_KEY',
274
- label: 'Pi API key',
275
- description: 'Pi-specific credential override; blank uses API_KEY.',
276
- type: 'secret',
277
- },
278
- PI_CONTEXT_WINDOW: {
279
- key: 'PI_CONTEXT_WINDOW',
280
- label: 'Context window',
281
- description: 'Pi context window used to determine compaction.',
282
- type: 'integer',
283
- min: 1,
284
- },
285
- PI_MAX_TOKENS: {
286
- key: 'PI_MAX_TOKENS',
287
- label: 'Maximum output tokens',
288
- description: 'Maximum output tokens advertised to Pi.',
289
- type: 'integer',
290
- min: 1,
291
- },
292
- DEEPSEEK_HARNESS_API_KEY: {
293
- key: 'DEEPSEEK_HARNESS_API_KEY',
294
- label: 'DeepSeek Harness API key',
295
- description: 'DeepSeek Harness credential override; blank uses API_KEY.',
296
- type: 'secret',
297
- },
298
- DEEPSEEK_HARNESS_CONTEXT_WINDOW: {
299
- key: 'DEEPSEEK_HARNESS_CONTEXT_WINDOW',
300
- label: 'Context window',
301
- description: 'Context capacity advertised to DeepSeek Harness.',
302
- type: 'integer',
303
- min: 1,
304
- },
305
- DEEPSEEK_HARNESS_MAX_TOKENS: {
306
- key: 'DEEPSEEK_HARNESS_MAX_TOKENS',
307
- label: 'Maximum output tokens',
308
- description: 'Output capacity advertised to DeepSeek Harness.',
309
- type: 'integer',
310
- min: 1,
311
- },
312
- };
313
-
314
- const AGENT_SETTING_KEYS = {
315
- 'subconscious-code': ['SC_API_KEY'],
316
- 'claude-code': [
317
- 'CLAUDE_GATEWAY_URL',
318
- 'CLAUDE_CODE_API_KEY',
319
- 'CLAUDE_CODE_SUBAGENT_MODEL',
320
- 'CLAUDE_CODE_AUTO_COMPACT_WINDOW',
321
- 'CLAUDE_CODE_MAX_CONTEXT_TOKENS',
322
- 'MAX_CONCURRENT_SUBAGENTS',
323
- 'MAX_SUBAGENT_SPAWN_DEPTH',
324
- ],
325
- codex: [
326
- 'CODEX_API_KEY',
327
- 'CODEX_CONTEXT_WINDOW',
328
- 'CODEX_MAX_CONTEXT_WINDOW',
329
- 'CODEX_AUTO_COMPACT_TOKEN_LIMIT',
330
- 'CODEX_REASONING_EFFORT',
331
- 'CODEX_EXTERNAL_TOOLS',
332
- 'CODEX_STREAM_IDLE_TIMEOUT_MS',
333
- 'CODEX_MULTI_AGENT_VERSION',
334
- 'CODEX_SUBAGENT_REASONING_EFFORT',
335
- 'MAX_CONCURRENT_SUBAGENTS',
336
- ],
337
- opencode: [
338
- 'OPENCODE_API_KEY',
339
- 'OPENCODE_CONTEXT_LIMIT',
340
- 'OPENCODE_OUTPUT_LIMIT',
341
- ],
342
- cursor: ['CURSOR_API_KEY'],
343
- copilot: [
344
- 'COPILOT_API_KEY',
345
- 'COPILOT_MAX_INPUT_TOKENS',
346
- 'COPILOT_MAX_OUTPUT_TOKENS',
347
- 'VSCODE_APP',
348
- ],
349
- pi: ['PI_API_KEY', 'PI_CONTEXT_WINDOW', 'PI_MAX_TOKENS'],
350
- 'deepseek-harness': [
351
- 'DEEPSEEK_HARNESS_API_KEY',
352
- 'DEEPSEEK_HARNESS_CONTEXT_WINDOW',
353
- 'DEEPSEEK_HARNESS_MAX_TOKENS',
354
- ],
355
- };
356
-
357
- const GROUP_KEYS = [
358
- {
359
- id: 'shared',
360
- label: 'Shared settings',
361
- keys: ['GATEWAY_URL', 'API_KEY', 'MODEL'],
362
- },
363
- ...registry.agents
364
- .filter((agent) => agent.cli !== false)
365
- .map((agent) => ({
366
- id: agent.id,
367
- label: agent.name,
368
- keys: AGENT_SETTING_KEYS[agent.id] || [],
369
- })),
370
- ];
371
-
372
- export const PROFILE_SETTING_GROUPS = GROUP_KEYS.map((group) => ({
373
- ...group,
374
- settings: group.keys.map((key) => SETTINGS[key]),
375
- }));
376
-
377
- export function profileSettingsForAgent(agentId) {
378
- const shared = PROFILE_SETTING_GROUPS.find((group) => group.id === 'shared');
379
- const agent = PROFILE_SETTING_GROUPS.find((group) => group.id === agentId);
380
- return [...(shared?.settings || []), ...(agent?.settings || [])];
381
- }
382
-
383
- export function resolvedProfileValues(profile) {
384
- return { ...RUNBOOK_DEFAULTS, ...(profile?.values || {}) };
385
- }
386
-
387
- function profileTemplate() {
388
- const modelComments = SUPPORTED_MODELS.map((model) => `# ${model}`).join(
389
- '\n',
390
- );
391
- return `# Subconscious coding-agent profile
392
- # Generated by subc. Extra KEY=value lines are passed through to launches.
393
-
394
- GATEWAY_URL={GATEWAY_URL}
395
- API_KEY={API_KEY}
396
- # Available models (MODEL=UNSET uses the first live catalog model):
397
- ${modelComments}
398
- MODEL={MODEL}
399
-
400
- # Optional per-agent keys. Leave blank to use API_KEY above.
401
- SC_API_KEY={SC_API_KEY}
402
- CLAUDE_CODE_API_KEY={CLAUDE_CODE_API_KEY}
403
- CODEX_API_KEY={CODEX_API_KEY}
404
- OPENCODE_API_KEY={OPENCODE_API_KEY}
405
- CURSOR_API_KEY={CURSOR_API_KEY}
406
- COPILOT_API_KEY={COPILOT_API_KEY}
407
- PI_API_KEY={PI_API_KEY}
408
- DEEPSEEK_HARNESS_API_KEY={DEEPSEEK_HARNESS_API_KEY}
409
-
410
- # Claude Code
411
- # Leave CLAUDE_GATEWAY_URL blank to use GATEWAY_URL above.
412
- CLAUDE_GATEWAY_URL={CLAUDE_GATEWAY_URL}
413
- # CLAUDE_CODE_SUBAGENT_MODEL=UNSET follows MODEL above.
414
- CLAUDE_CODE_SUBAGENT_MODEL={CLAUDE_CODE_SUBAGENT_MODEL}
415
- CLAUDE_CODE_AUTO_COMPACT_WINDOW={CLAUDE_CODE_AUTO_COMPACT_WINDOW}
416
- CLAUDE_CODE_MAX_CONTEXT_TOKENS={CLAUDE_CODE_MAX_CONTEXT_TOKENS}
417
- MAX_CONCURRENT_SUBAGENTS={MAX_CONCURRENT_SUBAGENTS}
418
- MAX_SUBAGENT_SPAWN_DEPTH={MAX_SUBAGENT_SPAWN_DEPTH}
419
-
420
- # Codex
421
- CODEX_CONTEXT_WINDOW={CODEX_CONTEXT_WINDOW}
422
- CODEX_MAX_CONTEXT_WINDOW={CODEX_MAX_CONTEXT_WINDOW}
423
- CODEX_AUTO_COMPACT_TOKEN_LIMIT={CODEX_AUTO_COMPACT_TOKEN_LIMIT}
424
- CODEX_REASONING_EFFORT={CODEX_REASONING_EFFORT}
425
- CODEX_EXTERNAL_TOOLS={CODEX_EXTERNAL_TOOLS}
426
-
427
- # OpenCode
428
- OPENCODE_CONTEXT_LIMIT={OPENCODE_CONTEXT_LIMIT}
429
- OPENCODE_OUTPUT_LIMIT={OPENCODE_OUTPUT_LIMIT}
430
-
431
- # Pi
432
- PI_CONTEXT_WINDOW={PI_CONTEXT_WINDOW}
433
- PI_MAX_TOKENS={PI_MAX_TOKENS}
434
-
435
- # DeepSeek Harness
436
- DEEPSEEK_HARNESS_CONTEXT_WINDOW={DEEPSEEK_HARNESS_CONTEXT_WINDOW}
437
- DEEPSEEK_HARNESS_MAX_TOKENS={DEEPSEEK_HARNESS_MAX_TOKENS}
438
-
439
- # GitHub Copilot
440
- COPILOT_MAX_INPUT_TOKENS={COPILOT_MAX_INPUT_TOKENS}
441
- COPILOT_MAX_OUTPUT_TOKENS={COPILOT_MAX_OUTPUT_TOKENS}
442
- VSCODE_APP={VSCODE_APP}
443
-
444
- # Extra KEY=value lines are passed through to launches.
445
- `;
446
- }
447
-
448
43
  export function validateProfileName(name) {
449
44
  if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(name)) {
450
45
  throw new Error(
@@ -616,11 +211,21 @@ export async function clearProfileApiKey(name = DEFAULT_PROFILE) {
616
211
  return true;
617
212
  }
618
213
 
619
- function isSecretKey(key) {
214
+ // PI_MAX_TOKENS=65536 is a budget, not a credential. Anything else under a
215
+ // *_TOKENS name, such as a key pasted onto the wrong line, stays redacted.
216
+ function isTokenBudget(key, value) {
217
+ return (
218
+ /_TOKENS$|_TOKEN_LIMIT$/i.test(key) &&
219
+ /^\d+$/.test(value) &&
220
+ Number.isSafeInteger(Number(value))
221
+ );
222
+ }
223
+
224
+ function isSecretKey(key, value) {
620
225
  const upper = key.toUpperCase();
621
226
  return (
622
227
  upper.endsWith('API_KEY') ||
623
- upper.includes('TOKEN') ||
228
+ (upper.includes('TOKEN') && !isTokenBudget(key, value)) ||
624
229
  upper.includes('SECRET') ||
625
230
  upper.includes('PASSWORD') ||
626
231
  upper.includes('AUTH')
@@ -628,7 +233,7 @@ function isSecretKey(key) {
628
233
  }
629
234
 
630
235
  function redact(key, value) {
631
- if (!isSecretKey(key) || !value) return value;
236
+ if (!value || !isSecretKey(key, value)) return value;
632
237
  return value.length <= 8
633
238
  ? '********'
634
239
  : `${value.slice(0, 4)}…${value.slice(-4)}`;
@@ -641,7 +246,7 @@ function redactEnvLine(line) {
641
246
  if (!match) return line;
642
247
  const [, prefix, key, raw] = match;
643
248
  const value = decodeValue(raw);
644
- if (!isSecretKey(key) || !value) return line;
249
+ if (!value || !isSecretKey(key, value)) return line;
645
250
  return `${prefix}${key}=${redact(key, value)}`;
646
251
  }
647
252
 
@@ -950,7 +555,7 @@ export async function configCommand(
950
555
 
951
556
  export function modelsCommand(models = SUPPORTED_MODELS, options = {}) {
952
557
  const selectedModel =
953
- options.selectedModel || models[0] || registry.defaults.model;
558
+ options.selectedModel || models[0] || RUNBOOK_DEFAULTS.MODEL;
954
559
  console.log(`\n ${c.bold}Available models${c.reset}\n`);
955
560
  for (const model of models) {
956
561
  const suffix =
@@ -1,25 +1,79 @@
1
1
  # Coding-agent integrations
2
2
 
3
- These scripts are part of `subc`. They launch or surgically install Claude Code,
4
- Subconscious Code, Codex, OpenCode, DeepSeek Harness, Cursor, Copilot, and Pi against the
5
- Subconscious gateway.
6
-
7
- `subc` reads `~/.subconscious/profiles/<name>.env` and injects those values into
8
- the scripts, so users do not need a sibling `.env` file. When a script is run
9
- directly, `SUBC_ENV_FILE` (or `bin/runbook/.env`) can supply the same keys.
10
-
11
- Included integrations:
12
-
13
- - `subconscious-code/install.sh` and `run.sh`
14
- - `claude-code/install.sh` and `run.sh`
15
- - `codex/install.sh`, `run.sh`, `hook.sh`, `hooks.json`, and `hooks-lib.sh`
16
- - `opencode/install.sh`, `run.sh`, and `subconscious-compaction.ts`
17
- - `cursor/install.sh`, `hook.sh`, and `hooks.json`
18
- - `copilot/install.sh`, `hook.sh`, and `hooks.json`
19
- - `pi/install.sh`, `run.sh`, and `subconscious-compaction.ts`
20
- - `deepseek-harness/run.sh`
21
-
22
- Each CLI-enabled entry in `agents/registry.json` points here with a `runbook`
23
- block. Persistent writes are merge/unmerge only: they never replace a user's
24
- `config.toml`, `opencode.json`, `models.json`, `hooks.json`, or VS Code
25
- provider list.
3
+ Each directory here is one agent. Its `agent.json` is the only place that
4
+ agent's data is written; the code reads it at runtime. `shared.json` lists the
5
+ agents in menu order and holds what is truly shared: the packaged model list,
6
+ the default gateway, model capabilities, and the settings every agent uses
7
+ (`GATEWAY_URL`, `API_KEY`, `MODEL`, `MAX_CONCURRENT_SUBAGENTS`).
8
+
9
+ | Agent | Launch | Setup |
10
+ | --- | --- | --- |
11
+ | `claude-code` | binary | `install.sh` (leftover status/uninstall) |
12
+ | `codex` | `run.sh` | `install.sh` (hooks) |
13
+ | `opencode` | binary | `install.sh` (leftover status/uninstall) |
14
+ | `cursor` | none | `install.sh` (hooks) |
15
+ | `copilot` | none | `install.sh` (provider and hooks) |
16
+ | `pi` | `run.sh` | `install.sh` (provider and extensions) |
17
+ | `deepseek-harness` | `run.sh` | none |
18
+
19
+ ## What `agent.json` holds and who reads it
20
+
21
+ | Field | Read by |
22
+ | --- | --- |
23
+ | `id`, `command`, `aliases`, `name`, `description` | routing, `subc help`, the TUI menu |
24
+ | `install` | the missing-agent message, agent help, and the upgrade warning (`minimum_version`); `{package}` fills in `commands` |
25
+ | `runbook` | which script launches the agent (none means the binary is run directly) and which setup actions exist |
26
+ | `help` | `subc <agent> help`; flags with a `help` text are added from `inputs` |
27
+ | `sessions`, `launch.resume`, `launch.handoff` | `subc sessions resume` |
28
+ | `launch.argv`, `launch.headless_argv`, `headless_stdin`, `headless_platforms` | every launch: subc builds the full argv and stdin from these |
29
+ | `inputs` | profile settings and the TUI (`label`, `type`, `min`, `max`, `choices`), the new-profile template, launch flags (`flag`), and defaults (`default`, `aliases`, `keep_empty`) |
30
+ | `env` | the env subc gives the agent: the first set `override`, otherwise `value` |
31
+ | `config` | `cli-config` entries become `config_flag NAME=VALUE` (Codex `-c`) when `when` holds; other entries describe files the runbooks write |
32
+ | `capabilities`, `prerequisites` | the harness manifest only |
33
+
34
+ ## Install data is display-only
35
+
36
+ subc never installs an agent. When an agent's binary is missing, subc prints
37
+ `install.commands` for the current OS and `install.url`, then exits with
38
+ status 127. Windows never shows the Linux command. Rules for `install`, checked
39
+ by `bin/agent-data.js` and `test/agent-install-policy.test.js`:
40
+
41
+ - `url` is required: an `https://` link to the vendor's official install page.
42
+ - `commands` is `null`, or an object keyed by `darwin`, `linux`, and `win32`.
43
+ - A command is one the user can paste, such as `npm i -g {package}`. It never
44
+ pipes a downloaded script into a shell.
45
+
46
+ Values may use `{baseUrl}`, `{baseUrlV1}`, `{apiKey}`, `{model}`, `{prompt}`,
47
+ `{args}`, `{config}`, and `${NAME}` for another input or env entry.
48
+ `subc harness-manifest --json` prints every agent file with `${NAME}` replaced
49
+ by its default, so readers such as bench-runner parse JSON instead of these
50
+ scripts.
51
+
52
+ ## The runbook contract
53
+
54
+ subc starts a runbook as `bash run.sh ARGV...`, where `ARGV` is the agent's
55
+ complete command line. The env already holds every input with its default,
56
+ every `env` entry, `SUBC_MODEL_IDS` (launch model first, then the catalog),
57
+ and `SUBC_VISION_MODELS`. A runbook does its own work, such as writing a
58
+ temporary file, and ends with `subc_exec` from `lib.sh`, which replaces a
59
+ `{tempFile}` placeholder in the template words and execs the agent. A runbook
60
+ declares no defaults, flags, or argv of its own.
61
+
62
+ Setup scripts (`install.sh`) get the same inputs and keep their own
63
+ `install|status|uninstall` command line.
64
+
65
+ ## Adding or changing an agent
66
+
67
+ 1. Create `bin/runbook/<id>/agent.json` (copy the closest agent) and add the
68
+ id to `shared.json`.
69
+ 2. Add `run.sh` only if the launch must do work subc cannot express as data,
70
+ such as writing a file; otherwise leave `runbook.script` out.
71
+ 3. Run `npm test`. `test/agent-files.test.js` validates every agent file and
72
+ renders each launch template.
73
+
74
+ To change a default, flag, env value, argv, or help text, edit the agent file.
75
+ The launcher, profiles, help, Windows launcher, and manifest all read it. The
76
+ contents of files a runbook writes (the Codex catalog, Pi's provider, the
77
+ DeepSeek Harness overlay, Copilot's provider) live in that script, and on
78
+ Windows in `bin/windows/launch.js` and `bin/windows/setup.js`, whose Codex
79
+ `-c` list also differs from the one in `agent.json`.