subconscious-cli 4.0.13 → 4.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -10
- package/bin/agents.js +211 -48
- package/bin/cli.js +7 -6
- package/bin/native/subc-tui-darwin-amd64 +0 -0
- package/bin/native/subc-tui-darwin-arm64 +0 -0
- package/bin/native/subc-tui-linux-amd64 +0 -0
- package/bin/native/subc-tui-linux-arm64 +0 -0
- package/bin/native/subc-tui-windows-amd64.exe +0 -0
- package/bin/native/subc-tui-windows-arm64.exe +0 -0
- package/bin/profiles.js +33 -8
- package/bin/registry.generated.json +43 -0
- package/bin/runbook/README.md +2 -1
- package/bin/runbook/claude-code/install.sh +43 -6
- package/bin/runbook/claude-code/run.sh +89 -7
- package/bin/runbook/subconscious-code/install.sh +147 -0
- package/bin/runbook/subconscious-code/run.sh +21 -0
- package/bin/tui.js +6 -8
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ Log in to Subconscious, then run coding agents against the Subconscious gateway.
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install -g subconscious-cli
|
|
9
9
|
subc login
|
|
10
|
+
subc sc
|
|
10
11
|
subc claude
|
|
11
12
|
```
|
|
12
13
|
|
|
@@ -21,7 +22,7 @@ never block the requested command. Set `SUBC_DISABLE_UPDATE_CHECK=1` to suppress
|
|
|
21
22
|
the check in offline automation.
|
|
22
23
|
|
|
23
24
|
Login creates both the saved credential and a ready-to-use `default` profile,
|
|
24
|
-
so Claude Code, Codex, OpenCode, and DeepSeek Harness can launch immediately.
|
|
25
|
+
so Subconscious Code, Claude Code, Codex, OpenCode, and DeepSeek Harness can launch immediately.
|
|
25
26
|
Persistent editor and Pi integrations are installed per agent:
|
|
26
27
|
|
|
27
28
|
```bash
|
|
@@ -52,6 +53,7 @@ profile; they do not authenticate, install, configure, or launch anything:
|
|
|
52
53
|
|
|
53
54
|
```bash
|
|
54
55
|
subc claude help
|
|
56
|
+
subc sc help
|
|
55
57
|
subc codex help
|
|
56
58
|
subc cursor help
|
|
57
59
|
subc config help
|
|
@@ -66,6 +68,7 @@ gateway environment applied for that process. Arguments pass through as usual:
|
|
|
66
68
|
|
|
67
69
|
```bash
|
|
68
70
|
subc claude --continue
|
|
71
|
+
subc sc -- -p "fix the tests"
|
|
69
72
|
subc codex exec "write a test"
|
|
70
73
|
subc opencode
|
|
71
74
|
subc pi
|
|
@@ -78,6 +81,7 @@ The packaged integrations live in `cli/bin/runbook`.
|
|
|
78
81
|
|
|
79
82
|
| Command | Behavior |
|
|
80
83
|
| --- | --- |
|
|
84
|
+
| `subc sc` | Launch Subconscious Code with the active gateway, key, model, and DLR transport |
|
|
81
85
|
| `subc claude` | Launch Claude Code with the runbook environment, context limits, subagent limits, and OTEL usage reporting |
|
|
82
86
|
| `subc codex` | Launch Codex with the runbook provider, temporary model catalog, and surgically merged compaction hooks |
|
|
83
87
|
| `subc opencode` | Launch OpenCode with the runbook provider, client header, and context/output limits |
|
|
@@ -86,11 +90,16 @@ The packaged integrations live in `cli/bin/runbook`.
|
|
|
86
90
|
| `subc pi` | Refresh the Pi provider from the live catalog, then launch |
|
|
87
91
|
| `subc dsh` | Launch the DeepSeek Harness Web UI with a temporary provider populated from the live catalog |
|
|
88
92
|
|
|
89
|
-
If Claude Code, Codex, OpenCode, or DeepSeek Harness is missing, an interactive terminal offers
|
|
93
|
+
If Subconscious Code, Claude Code, Codex, OpenCode, or DeepSeek Harness is missing, an interactive terminal offers
|
|
90
94
|
to install it before launching. Pi refreshes its Subconscious provider on every
|
|
91
95
|
`subc pi` launch while preserving all other providers in `models.json`; its
|
|
92
96
|
executable must already be installed.
|
|
93
97
|
|
|
98
|
+
`subc sc install` downloads and checksum-verifies the latest static Linux release
|
|
99
|
+
from `subconscious-systems/subconscious-code`. The upstream release currently
|
|
100
|
+
publishes x86_64 and ARM64 Linux assets. On macOS, the installer uses Cargo to
|
|
101
|
+
build the tagged release until Darwin assets are published.
|
|
102
|
+
|
|
94
103
|
`subc codex` disables Codex apps and plugin tools for that launch by default so
|
|
95
104
|
requests remain below the gateway's 128-tool limit. Core coding tools remain
|
|
96
105
|
available. Use `subc codex --external-tools` to opt back in when targeting a
|
|
@@ -145,7 +154,7 @@ rewritten. Run a one-shot task with `subc dsh headless "PROMPT"`.
|
|
|
145
154
|
```
|
|
146
155
|
|
|
147
156
|
The file is mode `600` and contains the shared gateway URL, API key, model,
|
|
148
|
-
optional per-agent key overrides, and all Claude/Codex/OpenCode/Pi/Copilot/
|
|
157
|
+
optional per-agent key overrides, and all Subconscious Code/Claude/Codex/OpenCode/Pi/Copilot/
|
|
149
158
|
DeepSeek Harness context and output settings used by the packaged runbook scripts.
|
|
150
159
|
|
|
151
160
|
```bash
|
|
@@ -153,8 +162,9 @@ subc config # list every profile and its file path
|
|
|
153
162
|
subc -p staging config create # create a profile with default settings
|
|
154
163
|
subc -p staging config # print that path and env file
|
|
155
164
|
subc -p staging config --model subconscious/glm-5.2
|
|
165
|
+
subc -p staging config --model UNSET
|
|
156
166
|
subc -p staging config --subagent-model subconscious/deepseek-v4-flash-marathon
|
|
157
|
-
subc -p staging config --subagent-model
|
|
167
|
+
subc -p staging config --subagent-model UNSET
|
|
158
168
|
subc config --gateway-url https://gateway.example
|
|
159
169
|
subc config path
|
|
160
170
|
subc config edit # open the selected profile in $VISUAL, $EDITOR, vim, or nano
|
|
@@ -170,9 +180,12 @@ Subconscious-injected defaults; resolved login identity (`GATEWAY_URL`,
|
|
|
170
180
|
In scripts and CI, keep using `subc config --gateway-url`, `--api-key`,
|
|
171
181
|
`--model`, and `--subagent-model`.
|
|
172
182
|
|
|
183
|
+
Use `UNSET` to clear the profile default so launches use the first model in
|
|
184
|
+
the live catalog (gateway priority order).
|
|
185
|
+
|
|
173
186
|
The subagent setting controls `CLAUDE_CODE_SUBAGENT_MODEL` for Claude Code.
|
|
174
|
-
Use `
|
|
175
|
-
|
|
187
|
+
Use `UNSET` to clear the override so subagents automatically follow the
|
|
188
|
+
profile's default model.
|
|
176
189
|
|
|
177
190
|
Each agent section can hold its own API key. An agent-specific key takes
|
|
178
191
|
precedence over the shared profile key and can be used on its own, so profiles
|
|
@@ -224,11 +237,15 @@ list. The selected profile model is listed first only while the gateway still
|
|
|
224
237
|
advertises it.
|
|
225
238
|
OpenCode rebuilds its isolated runtime provider on every `subc opencode` launch,
|
|
226
239
|
so models left in older OpenCode configuration files do not leak into the list.
|
|
227
|
-
If a saved profile default has been removed, launches use the first
|
|
228
|
-
an explicit `--model` or `SUBCONSCIOUS_MODEL` override is always
|
|
240
|
+
If a saved profile default is UNSET or has been removed, launches use the first
|
|
241
|
+
live model; an explicit `--model` or `SUBCONSCIOUS_MODEL` override is always
|
|
242
|
+
preserved.
|
|
229
243
|
Claude Code exposes four native Opus/Sonnet/Haiku/Fable picker slots plus one
|
|
230
|
-
custom model option
|
|
231
|
-
|
|
244
|
+
custom model option. The CLI remaps those aliases to the live catalog, then
|
|
245
|
+
replaces the built-in `/model` lineup (`modelPicker.replaceBuiltInOptions`) and
|
|
246
|
+
allowlists only those models (`availableModels`) so Anthropic Fable and
|
|
247
|
+
ungranted slugs do not appear. Any other model can still be selected with
|
|
248
|
+
`subc claude --model MODEL`. Cursor requires adding
|
|
232
249
|
the printed model IDs in its OpenAI API Key Override settings. Use the printed
|
|
233
250
|
`/v1` Base URL in Cursor Settings; the profile itself stores the gateway origin
|
|
234
251
|
so correlation hooks can post to `/v1/agent-hooks`.
|
package/bin/agents.js
CHANGED
|
@@ -20,8 +20,16 @@ import readline from 'node:readline';
|
|
|
20
20
|
import { fileURLToPath } from 'node:url';
|
|
21
21
|
import { c } from './colors.js';
|
|
22
22
|
import { getApiKey } from './auth.js';
|
|
23
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
isUnsetSetting,
|
|
25
|
+
profileSettingsForAgent,
|
|
26
|
+
resolvedModelSetting,
|
|
27
|
+
resolvedProfileValues,
|
|
28
|
+
} from './profiles.js';
|
|
24
29
|
import { isLiveModelSource, PUBLIC_CATALOG_FALLBACK_MESSAGE, resolveModelCatalog } from './models.js';
|
|
30
|
+
import { compareVersions } from './update-check.js';
|
|
31
|
+
|
|
32
|
+
export const MIN_CLAUDE_CODE_VERSION = '2.1.242';
|
|
25
33
|
|
|
26
34
|
// --- Registry (single source of truth, generated copy shipped in the package).
|
|
27
35
|
const registry = JSON.parse(
|
|
@@ -156,6 +164,17 @@ export function parseAgentAction(agent, argv = []) {
|
|
|
156
164
|
}
|
|
157
165
|
|
|
158
166
|
const AGENT_HELP = {
|
|
167
|
+
'subconscious-code': {
|
|
168
|
+
usage: 'subc [-p NAME] sc [help|install] [Subconscious Code arguments...]',
|
|
169
|
+
behavior:
|
|
170
|
+
'Launches the native Subconscious coding agent with the selected profile gateway, credential, and model.',
|
|
171
|
+
options: [
|
|
172
|
+
['help', 'Show this help'],
|
|
173
|
+
['install', 'Install the latest Linux release, or build from source on macOS'],
|
|
174
|
+
['--model MODEL', 'Override the profile model for this launch'],
|
|
175
|
+
['ARGS...', 'Pass arguments directly to Subconscious Code'],
|
|
176
|
+
],
|
|
177
|
+
},
|
|
159
178
|
'claude-code': {
|
|
160
179
|
usage: 'subc [-p NAME] claude [help|status|uninstall] [Claude arguments...]',
|
|
161
180
|
behavior:
|
|
@@ -258,6 +277,12 @@ function displayProfileValue(setting, value, values) {
|
|
|
258
277
|
if (value) return '(set)';
|
|
259
278
|
return setting.key !== 'API_KEY' && values.API_KEY ? '(shared key)' : '(not set)';
|
|
260
279
|
}
|
|
280
|
+
if (
|
|
281
|
+
!value &&
|
|
282
|
+
(setting.key === 'MODEL' || setting.key === 'CLAUDE_CODE_SUBAGENT_MODEL')
|
|
283
|
+
) {
|
|
284
|
+
return 'UNSET';
|
|
285
|
+
}
|
|
261
286
|
return value || '(auto)';
|
|
262
287
|
}
|
|
263
288
|
|
|
@@ -295,9 +320,10 @@ export function printAgentHelp(agent, profile) {
|
|
|
295
320
|
);
|
|
296
321
|
const actions = agentSetupActions(agent);
|
|
297
322
|
if (actions.includes('install')) {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
323
|
+
const installDescription = agent.runbook?.binaryInstallScript
|
|
324
|
+
? 'Install the agent binary with'
|
|
325
|
+
: 'Install the persistent integration with';
|
|
326
|
+
console.log(` ${installDescription} ${c.cyan}subc ${command} install${c.reset}.`);
|
|
301
327
|
}
|
|
302
328
|
if (actions.includes('uninstall')) {
|
|
303
329
|
console.log(
|
|
@@ -325,28 +351,40 @@ function buildContext(apiKey, model, profile) {
|
|
|
325
351
|
/**
|
|
326
352
|
* Pull a `--model <value>` / `--model=<value>` flag out of the passthrough
|
|
327
353
|
* args (so it sets the Subconscious model rather than reaching the agent).
|
|
328
|
-
* Falls back to SUBCONSCIOUS_MODEL, then the
|
|
354
|
+
* Falls back to SUBCONSCIOUS_MODEL, then the profile MODEL. UNSET or a blank
|
|
355
|
+
* profile model means "use the first live catalog entry" (gateway priority).
|
|
329
356
|
*/
|
|
330
|
-
function extractModel(argv, profile) {
|
|
331
|
-
const environmentModel = process.env.SUBCONSCIOUS_MODEL
|
|
332
|
-
const profileModel = profile?.values?.MODEL
|
|
333
|
-
let model = environmentModel || profileModel ||
|
|
334
|
-
let modelSource = environmentModel ? 'environment' : profileModel ? 'profile' : '
|
|
357
|
+
export function extractModel(argv, profile) {
|
|
358
|
+
const environmentModel = resolvedModelSetting(process.env.SUBCONSCIOUS_MODEL);
|
|
359
|
+
const profileModel = resolvedModelSetting(profile?.values?.MODEL);
|
|
360
|
+
let model = environmentModel || profileModel || '';
|
|
361
|
+
let modelSource = environmentModel ? 'environment' : profileModel ? 'profile' : 'catalog';
|
|
335
362
|
const rest = [];
|
|
336
363
|
for (let i = 0; i < argv.length; i++) {
|
|
337
364
|
const a = argv[i];
|
|
338
365
|
if (a === '--model') {
|
|
339
366
|
const v = argv[i + 1];
|
|
340
367
|
if (v && !v.startsWith('-')) {
|
|
341
|
-
|
|
342
|
-
|
|
368
|
+
if (isUnsetSetting(v)) {
|
|
369
|
+
model = '';
|
|
370
|
+
modelSource = 'catalog';
|
|
371
|
+
} else {
|
|
372
|
+
model = v;
|
|
373
|
+
modelSource = 'command';
|
|
374
|
+
}
|
|
343
375
|
i++;
|
|
344
376
|
}
|
|
345
377
|
continue;
|
|
346
378
|
}
|
|
347
379
|
if (a.startsWith('--model=')) {
|
|
348
|
-
|
|
349
|
-
|
|
380
|
+
const v = a.slice('--model='.length);
|
|
381
|
+
if (isUnsetSetting(v)) {
|
|
382
|
+
model = '';
|
|
383
|
+
modelSource = 'catalog';
|
|
384
|
+
} else {
|
|
385
|
+
model = v;
|
|
386
|
+
modelSource = 'command';
|
|
387
|
+
}
|
|
350
388
|
continue;
|
|
351
389
|
}
|
|
352
390
|
rest.push(a);
|
|
@@ -371,6 +409,7 @@ function candidateBinDirs() {
|
|
|
371
409
|
if (home) dirs.push(path.join(home, '.local', 'bin'));
|
|
372
410
|
} else {
|
|
373
411
|
dirs.push(path.join(home, '.local', 'bin'));
|
|
412
|
+
dirs.push(path.join(home, '.cargo', 'bin'));
|
|
374
413
|
dirs.push('/opt/homebrew/bin');
|
|
375
414
|
dirs.push('/usr/local/bin');
|
|
376
415
|
}
|
|
@@ -445,10 +484,25 @@ function askYesNo(question) {
|
|
|
445
484
|
});
|
|
446
485
|
}
|
|
447
486
|
|
|
448
|
-
|
|
449
|
-
|
|
487
|
+
function waitForEnter(prompt) {
|
|
488
|
+
return new Promise((resolve) => {
|
|
489
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
490
|
+
rl.question(prompt, () => {
|
|
491
|
+
rl.close();
|
|
492
|
+
resolve();
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/** Run the agent's packaged binary installer, or its shell install command. */
|
|
498
|
+
function runInstaller(agent, install = agent.install, usePackagedScript = true) {
|
|
450
499
|
return new Promise((resolve) => {
|
|
451
|
-
const
|
|
500
|
+
const installScript = usePackagedScript && agent.runbook?.binaryInstallScript;
|
|
501
|
+
const child = installScript
|
|
502
|
+
? spawn('bash', [runbookScriptPath(agent, installScript), 'install'], {
|
|
503
|
+
stdio: 'inherit',
|
|
504
|
+
})
|
|
505
|
+
: spawn(install, { shell: true, stdio: 'inherit' });
|
|
452
506
|
child.on('error', () => resolve(false));
|
|
453
507
|
child.on('exit', (code) => resolve(code === 0));
|
|
454
508
|
});
|
|
@@ -508,14 +562,14 @@ async function ensureInstalled(agent) {
|
|
|
508
562
|
}
|
|
509
563
|
|
|
510
564
|
console.error(`\n ${c.dim}Running ${c.reset}${c.cyan}${agent.install}${c.reset}\n`);
|
|
511
|
-
let installed = await runInstaller(agent
|
|
565
|
+
let installed = await runInstaller(agent);
|
|
512
566
|
|
|
513
567
|
// Primary failed and a fallback exists — try it once.
|
|
514
568
|
if (!installed && agent.installFallback) {
|
|
515
569
|
console.error(
|
|
516
570
|
`\n ${c.dim}That didn't work. Trying the fallback: ${c.reset}${c.cyan}${agent.installFallback}${c.reset}\n`,
|
|
517
571
|
);
|
|
518
|
-
installed = await runInstaller(agent.installFallback);
|
|
572
|
+
installed = await runInstaller(agent, agent.installFallback, false);
|
|
519
573
|
}
|
|
520
574
|
|
|
521
575
|
if (!installed) {
|
|
@@ -536,6 +590,51 @@ async function ensureInstalled(agent) {
|
|
|
536
590
|
process.exit(0);
|
|
537
591
|
}
|
|
538
592
|
|
|
593
|
+
export function parseClaudeVersion(text) {
|
|
594
|
+
const match = String(text ?? '').match(/v?(\d+\.\d+\.\d+)/);
|
|
595
|
+
return match?.[1] ?? null;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
export function claudeVersionNeedsUpgrade(installed, minimum = MIN_CLAUDE_CODE_VERSION) {
|
|
599
|
+
return Boolean(installed && minimum && compareVersions(installed, minimum) < 0);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export function readClaudeVersion(bin, binDir, options = {}) {
|
|
603
|
+
const execFile = options.execFileSync || execFileSync;
|
|
604
|
+
try {
|
|
605
|
+
const stdout = execFile(bin, ['--version'], {
|
|
606
|
+
encoding: 'utf-8',
|
|
607
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
608
|
+
env: { ...process.env, PATH: augmentPath([binDir, ...candidateBinDirs()].filter(Boolean)) },
|
|
609
|
+
timeout: options.timeoutMs ?? 3000,
|
|
610
|
+
});
|
|
611
|
+
return parseClaudeVersion(typeof stdout === 'string' ? stdout : stdout?.toString?.());
|
|
612
|
+
} catch {
|
|
613
|
+
return null;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
async function ensureClaudeCompatible(agent, binDir) {
|
|
618
|
+
if (agent.id !== 'claude-code') return;
|
|
619
|
+
const version = readClaudeVersion(agent.bin, binDir);
|
|
620
|
+
if (!claudeVersionNeedsUpgrade(version)) return;
|
|
621
|
+
|
|
622
|
+
console.error(
|
|
623
|
+
`\n Minimum supported Claude Code version is ${MIN_CLAUDE_CODE_VERSION}. Your version is ${version}. Upgrade to get the best experience.\n`,
|
|
624
|
+
);
|
|
625
|
+
console.error(` Upgrade it with:`);
|
|
626
|
+
console.error(` ${c.cyan}${agent.install}${c.reset}`);
|
|
627
|
+
if (agent.installFallback) {
|
|
628
|
+
console.error(` or`);
|
|
629
|
+
console.error(` ${c.cyan}${agent.installFallback}${c.reset}`);
|
|
630
|
+
}
|
|
631
|
+
console.error('');
|
|
632
|
+
if (process.stdin.isTTY === true && process.stdout.isTTY === true) {
|
|
633
|
+
await waitForEnter(` ${c.dim}Press Enter to continue.${c.reset} `);
|
|
634
|
+
console.error('');
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
539
638
|
/** Resolve and validate a script inside the packaged runbook directory. */
|
|
540
639
|
function runbookScriptPath(agent, relativeScript = agent.runbook.script) {
|
|
541
640
|
const script = path.resolve(RUNBOOK_DIR, relativeScript);
|
|
@@ -639,21 +738,48 @@ const CLAUDE_MODEL_PICKER_KEYS = [
|
|
|
639
738
|
'ANTHROPIC_CUSTOM_MODEL_OPTION_DESCRIPTION',
|
|
640
739
|
];
|
|
641
740
|
|
|
741
|
+
const CLAUDE_MODEL_PICKER_ID_KEYS = [
|
|
742
|
+
'ANTHROPIC_DEFAULT_OPUS_MODEL',
|
|
743
|
+
'ANTHROPIC_DEFAULT_SONNET_MODEL',
|
|
744
|
+
'ANTHROPIC_DEFAULT_HAIKU_MODEL',
|
|
745
|
+
'ANTHROPIC_DEFAULT_FABLE_MODEL',
|
|
746
|
+
'ANTHROPIC_CUSTOM_MODEL_OPTION',
|
|
747
|
+
];
|
|
748
|
+
|
|
749
|
+
function uniqueCatalogModels(models, fallbackModel) {
|
|
750
|
+
const unique = [];
|
|
751
|
+
for (const model of models) {
|
|
752
|
+
if (model && !unique.includes(model)) unique.push(model);
|
|
753
|
+
}
|
|
754
|
+
if (unique.length === 0 && fallbackModel) unique.push(fallbackModel);
|
|
755
|
+
return unique;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
export function claudePickerSettings(models, fallbackModel) {
|
|
759
|
+
const unique = uniqueCatalogModels(models, fallbackModel);
|
|
760
|
+
return {
|
|
761
|
+
availableModels: unique,
|
|
762
|
+
modelPicker: {
|
|
763
|
+
replaceBuiltInOptions: true,
|
|
764
|
+
options: unique.map((model) => ({
|
|
765
|
+
model,
|
|
766
|
+
label: model,
|
|
767
|
+
description: `Subconscious model ${model}`,
|
|
768
|
+
})),
|
|
769
|
+
},
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
642
773
|
function claudeModelPickerEnv(agent, ctx, models) {
|
|
643
774
|
if (agent.id !== 'claude-code') return {};
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
const pickerModels = [];
|
|
653
|
-
for (const model of [...models, ...configuredModels]) {
|
|
654
|
-
if (model && !pickerModels.includes(model)) pickerModels.push(model);
|
|
655
|
-
}
|
|
656
|
-
while (pickerModels.length < 3) pickerModels.push(pickerModels.at(-1) || ctx.model);
|
|
775
|
+
// Only the live catalog belongs in Claude's picker. Packaged registry slots
|
|
776
|
+
// (Haiku → DeepSeek, etc.) must not be unioned back in — that advertised
|
|
777
|
+
// models the key cannot call.
|
|
778
|
+
//
|
|
779
|
+
// Pad through Fable so the built-in `fable` alias cannot resolve to Anthropic
|
|
780
|
+
// Fable 5. The /model menu itself is replaced via claudePickerSettings.
|
|
781
|
+
const pickerModels = uniqueCatalogModels(models, ctx.model);
|
|
782
|
+
while (pickerModels.length < 4) pickerModels.push(pickerModels.at(-1) || ctx.model);
|
|
657
783
|
|
|
658
784
|
const roles = ['OPUS', 'SONNET', 'HAIKU', 'FABLE'];
|
|
659
785
|
const env = {};
|
|
@@ -676,6 +802,27 @@ function claudeModelPickerEnv(agent, ctx, models) {
|
|
|
676
802
|
);
|
|
677
803
|
}
|
|
678
804
|
|
|
805
|
+
function applyClaudePickerCatalog(env, picker, models) {
|
|
806
|
+
if (Object.keys(picker).length === 0) return env;
|
|
807
|
+
const allowed = new Set(models);
|
|
808
|
+
|
|
809
|
+
for (const key of CLAUDE_MODEL_PICKER_KEYS) {
|
|
810
|
+
if (!picker[key]) {
|
|
811
|
+
delete env[key];
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
for (const key of CLAUDE_MODEL_PICKER_ID_KEYS) {
|
|
816
|
+
if (!picker[key] || !env[key] || allowed.has(env[key])) continue;
|
|
817
|
+
env[key] = picker[key];
|
|
818
|
+
const nameKey = `${key}_NAME`;
|
|
819
|
+
const descriptionKey = `${key}_DESCRIPTION`;
|
|
820
|
+
if (picker[nameKey]) env[nameKey] = picker[nameKey];
|
|
821
|
+
if (picker[descriptionKey]) env[descriptionKey] = picker[descriptionKey];
|
|
822
|
+
}
|
|
823
|
+
return env;
|
|
824
|
+
}
|
|
825
|
+
|
|
679
826
|
export function runbookEnv(
|
|
680
827
|
apiKey,
|
|
681
828
|
model,
|
|
@@ -687,18 +834,29 @@ export function runbookEnv(
|
|
|
687
834
|
const ctx = buildContext(apiKey, model, profile);
|
|
688
835
|
const extraDirs = [binDir, ...candidateBinDirs()].filter(Boolean);
|
|
689
836
|
const specificApiKey = agentApiKeySetting(agent)?.key;
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
837
|
+
const picker = claudeModelPickerEnv(agent, ctx, models);
|
|
838
|
+
return applyClaudePickerCatalog(
|
|
839
|
+
{
|
|
840
|
+
...picker,
|
|
841
|
+
...(profile?.values || {}),
|
|
842
|
+
...process.env,
|
|
843
|
+
GATEWAY_URL: ctx.baseUrl,
|
|
844
|
+
API_KEY: apiKey,
|
|
845
|
+
...(specificApiKey ? { [specificApiKey]: apiKey } : {}),
|
|
846
|
+
MODEL: model,
|
|
847
|
+
SUBCONSCIOUS_MODELS: models.join('\n'),
|
|
848
|
+
...(agent.id === 'claude-code'
|
|
849
|
+
? {
|
|
850
|
+
SUBC_CLAUDE_SETTINGS: JSON.stringify(claudePickerSettings(models, model)),
|
|
851
|
+
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY: '0',
|
|
852
|
+
}
|
|
853
|
+
: {}),
|
|
854
|
+
SUBC_ENV_FILE: os.devNull,
|
|
855
|
+
PATH: augmentPath(extraDirs),
|
|
856
|
+
},
|
|
857
|
+
picker,
|
|
858
|
+
models,
|
|
859
|
+
);
|
|
702
860
|
}
|
|
703
861
|
|
|
704
862
|
async function resolvedModelsForLaunch(profile, apiKey, selectedModel) {
|
|
@@ -721,16 +879,20 @@ async function resolvedModelsForLaunch(profile, apiKey, selectedModel) {
|
|
|
721
879
|
}
|
|
722
880
|
|
|
723
881
|
export function selectLaunchModel(requestedModel, modelSource, catalog) {
|
|
882
|
+
const first = catalog.models[0] || requestedModel || DEFAULTS.model;
|
|
883
|
+
if (modelSource === 'catalog' || !requestedModel) {
|
|
884
|
+
return first;
|
|
885
|
+
}
|
|
724
886
|
const useLiveDefault =
|
|
725
887
|
isLiveModelSource(catalog.source) &&
|
|
726
888
|
catalog.models.length > 0 &&
|
|
727
889
|
!catalog.models.includes(requestedModel) &&
|
|
728
890
|
(modelSource === 'profile' || modelSource === 'default');
|
|
729
|
-
return useLiveDefault ?
|
|
891
|
+
return useLiveDefault ? first : requestedModel;
|
|
730
892
|
}
|
|
731
893
|
|
|
732
894
|
async function runRunbookSetup(agent, argv, profile, relativeScript = agent.runbook.script) {
|
|
733
|
-
if (isSetupWithoutAuth(argv)) {
|
|
895
|
+
if (isSetupWithoutAuth(argv) || agent.runbook?.setupNeedsAuth === false) {
|
|
734
896
|
return spawnRunbook(agent, argv, {
|
|
735
897
|
...(profile?.values || {}),
|
|
736
898
|
...process.env,
|
|
@@ -743,7 +905,7 @@ async function runRunbookSetup(agent, argv, profile, relativeScript = agent.runb
|
|
|
743
905
|
if (!apiKey) return 1;
|
|
744
906
|
const catalog = await resolvedModelsForLaunch(profile, apiKey, requestedModel);
|
|
745
907
|
const model = selectLaunchModel(requestedModel, modelSource, catalog);
|
|
746
|
-
if (model !== requestedModel) {
|
|
908
|
+
if (requestedModel && model !== requestedModel) {
|
|
747
909
|
console.error(
|
|
748
910
|
` ${c.yellow}Configured model ${requestedModel} is not in the live catalog; using ${model}.${c.reset}\n`,
|
|
749
911
|
);
|
|
@@ -810,9 +972,10 @@ export async function runAgent(agent, argv, options = {}) {
|
|
|
810
972
|
if (!apiKey) return 1;
|
|
811
973
|
|
|
812
974
|
const binDir = await ensureInstalled(agent);
|
|
975
|
+
await ensureClaudeCompatible(agent, binDir);
|
|
813
976
|
const catalog = await resolvedModelsForLaunch(profile, apiKey, requestedModel);
|
|
814
977
|
const model = selectLaunchModel(requestedModel, modelSource, catalog);
|
|
815
|
-
if (model !== requestedModel) {
|
|
978
|
+
if (requestedModel && model !== requestedModel) {
|
|
816
979
|
console.error(
|
|
817
980
|
` ${c.yellow}Configured model ${requestedModel} is not in the live catalog; using ${model}.${c.reset}\n`,
|
|
818
981
|
);
|
package/bin/cli.js
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
loadProfile,
|
|
35
35
|
modelsCommand,
|
|
36
36
|
printConfigHelp,
|
|
37
|
+
resolvedModelSetting,
|
|
37
38
|
RUNBOOK_DEFAULTS,
|
|
38
39
|
SUPPORTED_MODELS as PACKAGED_MODELS,
|
|
39
40
|
updateUrlCommand,
|
|
@@ -74,7 +75,7 @@ function printHelp() {
|
|
|
74
75
|
${agents}
|
|
75
76
|
|
|
76
77
|
${c.bold}Options${c.reset}
|
|
77
|
-
${c.dim}--model <id>${c.reset} Model to use (
|
|
78
|
+
${c.dim}--model <id>${c.reset} Model to use (profile MODEL, or first live catalog model if UNSET)
|
|
78
79
|
${c.dim}-p, --profile${c.reset} Select a profile (default: default)
|
|
79
80
|
${c.dim}-h, --help${c.reset} Show this help
|
|
80
81
|
${c.dim}-v, --version${c.reset} Show version
|
|
@@ -154,7 +155,8 @@ Usage:
|
|
|
154
155
|
subc models
|
|
155
156
|
subc models help
|
|
156
157
|
|
|
157
|
-
List available Subconscious models.
|
|
158
|
+
List available Subconscious models. The default is the profile MODEL,
|
|
159
|
+
or the first live catalog model if MODEL is UNSET.
|
|
158
160
|
`,
|
|
159
161
|
};
|
|
160
162
|
|
|
@@ -309,10 +311,9 @@ async function main() {
|
|
|
309
311
|
}
|
|
310
312
|
const profile = await loadProfile(profileName);
|
|
311
313
|
const auth = await getApiKey(profile);
|
|
312
|
-
const selectedModel =
|
|
313
|
-
process.env.SUBCONSCIOUS_MODEL
|
|
314
|
-
|
|
315
|
-
RUNBOOK_DEFAULTS.MODEL;
|
|
314
|
+
const selectedModel = resolvedModelSetting(
|
|
315
|
+
process.env.SUBCONSCIOUS_MODEL || profile.values.MODEL,
|
|
316
|
+
);
|
|
316
317
|
const baseUrl =
|
|
317
318
|
process.env.SUBCONSCIOUS_BASE_URL?.trim() ||
|
|
318
319
|
profile.values.GATEWAY_URL?.trim() ||
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/bin/profiles.js
CHANGED
|
@@ -38,6 +38,7 @@ export const RUNBOOK_DEFAULTS = {
|
|
|
38
38
|
GATEWAY_URL: registry.defaults.baseUrl,
|
|
39
39
|
API_KEY: '',
|
|
40
40
|
MODEL: registry.defaults.model,
|
|
41
|
+
SC_API_KEY: '',
|
|
41
42
|
CLAUDE_CODE_SUBAGENT_MODEL: '',
|
|
42
43
|
CLAUDE_GATEWAY_URL: '',
|
|
43
44
|
CLAUDE_CODE_API_KEY: '',
|
|
@@ -84,14 +85,21 @@ const SETTINGS = {
|
|
|
84
85
|
MODEL: {
|
|
85
86
|
key: 'MODEL',
|
|
86
87
|
label: 'Default model',
|
|
87
|
-
description:
|
|
88
|
+
description:
|
|
89
|
+
'Initial model used by coding-agent launches and setup. UNSET uses the first live catalog model.',
|
|
88
90
|
type: 'choice',
|
|
89
91
|
choices: SUPPORTED_MODELS,
|
|
90
92
|
},
|
|
93
|
+
SC_API_KEY: {
|
|
94
|
+
key: 'SC_API_KEY',
|
|
95
|
+
label: 'Subconscious Code API key',
|
|
96
|
+
description: 'Subconscious Code credential override; blank uses API_KEY.',
|
|
97
|
+
type: 'secret',
|
|
98
|
+
},
|
|
91
99
|
CLAUDE_CODE_SUBAGENT_MODEL: {
|
|
92
100
|
key: 'CLAUDE_CODE_SUBAGENT_MODEL',
|
|
93
101
|
label: 'Subagent model',
|
|
94
|
-
description: 'Model used by Claude Code subagents
|
|
102
|
+
description: 'Model used by Claude Code subagents. UNSET follows the default model.',
|
|
95
103
|
type: 'choice',
|
|
96
104
|
choices: SUPPORTED_MODELS,
|
|
97
105
|
},
|
|
@@ -273,6 +281,7 @@ const SETTINGS = {
|
|
|
273
281
|
};
|
|
274
282
|
|
|
275
283
|
const AGENT_SETTING_KEYS = {
|
|
284
|
+
'subconscious-code': ['SC_API_KEY'],
|
|
276
285
|
'claude-code': [
|
|
277
286
|
'CLAUDE_GATEWAY_URL',
|
|
278
287
|
'CLAUDE_CODE_API_KEY',
|
|
@@ -340,11 +349,12 @@ function profileTemplate() {
|
|
|
340
349
|
|
|
341
350
|
GATEWAY_URL={GATEWAY_URL}
|
|
342
351
|
API_KEY={API_KEY}
|
|
343
|
-
# Available models:
|
|
352
|
+
# Available models (MODEL=UNSET uses the first live catalog model):
|
|
344
353
|
${modelComments}
|
|
345
354
|
MODEL={MODEL}
|
|
346
355
|
|
|
347
356
|
# Optional per-agent keys. Leave blank to use API_KEY above.
|
|
357
|
+
SC_API_KEY={SC_API_KEY}
|
|
348
358
|
CLAUDE_CODE_API_KEY={CLAUDE_CODE_API_KEY}
|
|
349
359
|
CODEX_API_KEY={CODEX_API_KEY}
|
|
350
360
|
OPENCODE_API_KEY={OPENCODE_API_KEY}
|
|
@@ -356,7 +366,7 @@ DEEPSEEK_HARNESS_API_KEY={DEEPSEEK_HARNESS_API_KEY}
|
|
|
356
366
|
# Claude Code
|
|
357
367
|
# Leave CLAUDE_GATEWAY_URL blank to use GATEWAY_URL above.
|
|
358
368
|
CLAUDE_GATEWAY_URL={CLAUDE_GATEWAY_URL}
|
|
359
|
-
#
|
|
369
|
+
# CLAUDE_CODE_SUBAGENT_MODEL=UNSET follows MODEL above.
|
|
360
370
|
CLAUDE_CODE_SUBAGENT_MODEL={CLAUDE_CODE_SUBAGENT_MODEL}
|
|
361
371
|
CLAUDE_CODE_AUTO_COMPACT_WINDOW={CLAUDE_CODE_AUTO_COMPACT_WINDOW}
|
|
362
372
|
CLAUDE_CODE_MAX_CONTEXT_TOKENS={CLAUDE_CODE_MAX_CONTEXT_TOKENS}
|
|
@@ -600,6 +610,16 @@ async function printProfile(profile) {
|
|
|
600
610
|
console.log();
|
|
601
611
|
}
|
|
602
612
|
|
|
613
|
+
export function isUnsetSetting(value) {
|
|
614
|
+
const normalized = String(value ?? '').trim().toUpperCase();
|
|
615
|
+
return normalized === 'UNSET' || normalized === 'FOLLOW-GATEWAY' || normalized === 'FOLLOW-DEFAULT';
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
export function resolvedModelSetting(value) {
|
|
619
|
+
const trimmed = String(value ?? '').trim();
|
|
620
|
+
return isUnsetSetting(trimmed) ? '' : trimmed;
|
|
621
|
+
}
|
|
622
|
+
|
|
603
623
|
export function validateSettingValue(setting, value) {
|
|
604
624
|
if (!value) {
|
|
605
625
|
if (setting.required) return `${setting.label} cannot be blank`;
|
|
@@ -691,8 +711,9 @@ Usage:
|
|
|
691
711
|
subc config edit [vim|nano]
|
|
692
712
|
subc -p NAME config edit [vim|nano]
|
|
693
713
|
subc config [show|path|list|create|delete]
|
|
694
|
-
[--gateway-url URL] [--api-key KEY]
|
|
695
|
-
[--
|
|
714
|
+
[--gateway-url URL] [--api-key KEY]
|
|
715
|
+
[--model MODEL|UNSET]
|
|
716
|
+
[--subagent-model MODEL|UNSET]
|
|
696
717
|
|
|
697
718
|
subc config List every profile and its file path
|
|
698
719
|
subc -p NAME config Print that profile's path and env file
|
|
@@ -702,6 +723,9 @@ Usage:
|
|
|
702
723
|
subc config path Print the selected profile path
|
|
703
724
|
subc -p NAME config create Create a new profile with default settings
|
|
704
725
|
subc -p NAME config delete Delete a non-default profile
|
|
726
|
+
|
|
727
|
+
--model UNSET Clear MODEL so launches use the first live catalog model
|
|
728
|
+
--subagent-model UNSET Clear the Claude subagent override so it follows MODEL
|
|
705
729
|
`);
|
|
706
730
|
}
|
|
707
731
|
|
|
@@ -745,7 +769,8 @@ export async function configCommand(argv, profileName = DEFAULT_PROFILE, options
|
|
|
745
769
|
'--model': 'MODEL',
|
|
746
770
|
'--subagent-model': 'CLAUDE_CODE_SUBAGENT_MODEL',
|
|
747
771
|
}[arg];
|
|
748
|
-
updates[key] =
|
|
772
|
+
updates[key] =
|
|
773
|
+
(arg === '--model' || arg === '--subagent-model') && isUnsetSetting(value) ? '' : value;
|
|
749
774
|
} else if (action === 'edit' && ALLOWED_EDITORS.has(arg)) {
|
|
750
775
|
if (editor) throw new Error('Specify only one editor (vim or nano)');
|
|
751
776
|
editor = arg;
|
|
@@ -813,7 +838,7 @@ export async function configCommand(argv, profileName = DEFAULT_PROFILE, options
|
|
|
813
838
|
}
|
|
814
839
|
|
|
815
840
|
export function modelsCommand(models = SUPPORTED_MODELS, options = {}) {
|
|
816
|
-
const selectedModel = options.selectedModel || registry.defaults.model;
|
|
841
|
+
const selectedModel = options.selectedModel || models[0] || registry.defaults.model;
|
|
817
842
|
console.log(`\n ${c.bold}Available models${c.reset}\n`);
|
|
818
843
|
for (const model of models) {
|
|
819
844
|
const suffix = model === selectedModel ? ` ${c.dim}(default)${c.reset}` : '';
|
|
@@ -13,6 +13,49 @@
|
|
|
13
13
|
"platformUrl": "https://subconscious.dev/platform"
|
|
14
14
|
},
|
|
15
15
|
"agents": [
|
|
16
|
+
{
|
|
17
|
+
"id": "subconscious-code",
|
|
18
|
+
"command": "sc",
|
|
19
|
+
"name": "Subconscious Code",
|
|
20
|
+
"aliases": [
|
|
21
|
+
"subconscious-code"
|
|
22
|
+
],
|
|
23
|
+
"description": "Launch the native Subconscious coding agent with the active profile, gateway, and model.",
|
|
24
|
+
"framework": "Subconscious Code",
|
|
25
|
+
"language": "rust",
|
|
26
|
+
"category": "coding-agent",
|
|
27
|
+
"tags": [
|
|
28
|
+
"local",
|
|
29
|
+
"cli",
|
|
30
|
+
"agents"
|
|
31
|
+
],
|
|
32
|
+
"protocol": "openai",
|
|
33
|
+
"homepage": "https://github.com/subconscious-systems/subconscious-code",
|
|
34
|
+
"bin": "sc",
|
|
35
|
+
"install": {
|
|
36
|
+
"darwin": "cargo install --locked --git https://github.com/subconscious-systems/subconscious-code --bin sc rc-cli",
|
|
37
|
+
"linux": "subc sc install",
|
|
38
|
+
"fallback": "cargo install --locked --git https://github.com/subconscious-systems/subconscious-code --bin sc rc-cli"
|
|
39
|
+
},
|
|
40
|
+
"runbook": {
|
|
41
|
+
"mode": "launch",
|
|
42
|
+
"script": "subconscious-code/run.sh",
|
|
43
|
+
"setupScript": "subconscious-code/install.sh",
|
|
44
|
+
"binaryInstallScript": "subconscious-code/install.sh",
|
|
45
|
+
"setupActions": [
|
|
46
|
+
"install"
|
|
47
|
+
],
|
|
48
|
+
"setupNeedsAuth": false
|
|
49
|
+
},
|
|
50
|
+
"launch": "sc",
|
|
51
|
+
"env": {
|
|
52
|
+
"SC_BASE_URL": "{baseUrlV1}",
|
|
53
|
+
"SC_DLR_URL": "{baseUrl}",
|
|
54
|
+
"SC_DLR_ENABLED": "true",
|
|
55
|
+
"SC_API_KEY": "{apiKey}",
|
|
56
|
+
"SC_MODEL": "{model}"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
16
59
|
{
|
|
17
60
|
"id": "claude-code",
|
|
18
61
|
"command": "claude",
|
package/bin/runbook/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Coding-agent integrations
|
|
2
2
|
|
|
3
3
|
These scripts are part of `subc`. They launch or surgically install Claude Code,
|
|
4
|
-
Codex, OpenCode, DeepSeek Harness, Cursor, Copilot, and Pi against the
|
|
4
|
+
Subconscious Code, Codex, OpenCode, DeepSeek Harness, Cursor, Copilot, and Pi against the
|
|
5
5
|
Subconscious gateway.
|
|
6
6
|
|
|
7
7
|
`subc` reads `~/.subconscious/profiles/<name>.env` and injects those values into
|
|
@@ -10,6 +10,7 @@ directly, `SUBC_ENV_FILE` (or `cli/bin/runbook/.env`) can supply the same keys.
|
|
|
10
10
|
|
|
11
11
|
Included integrations:
|
|
12
12
|
|
|
13
|
+
- `subconscious-code/install.sh` and `run.sh`
|
|
13
14
|
- `claude-code/install.sh` and `run.sh`
|
|
14
15
|
- `codex/install.sh`, `run.sh`, `hook.sh`, `hooks.json`, and `hooks-lib.sh`
|
|
15
16
|
- `opencode/install.sh`, `run.sh`, and `subconscious-compaction.ts`
|
|
@@ -62,9 +62,6 @@ DEFAULT_COMPACT_WINDOW="1000000"
|
|
|
62
62
|
DEFAULT_MAX_CONTEXT_TOKENS="3000000"
|
|
63
63
|
DEFAULT_MAX_CONCURRENT_SUBAGENTS="4"
|
|
64
64
|
DEFAULT_MAX_SUBAGENT_SPAWN_DEPTH="1"
|
|
65
|
-
DEFAULT_OPUS_MODEL="subconscious/glm-5.2"
|
|
66
|
-
DEFAULT_SONNET_MODEL="subconscious/tim-qwen3.6-27b"
|
|
67
|
-
DEFAULT_HAIKU_MODEL="subconscious/deepseek-v4-flash-marathon"
|
|
68
65
|
|
|
69
66
|
GATEWAY_URL="${GATEWAY_URL:-}"
|
|
70
67
|
API_KEY="${CLAUDE_CODE_API_KEY:-${API_KEY:-}}"
|
|
@@ -73,15 +70,55 @@ COMPACT_WINDOW="${CLAUDE_CODE_AUTO_COMPACT_WINDOW:-${COMPACT_WINDOW:-$DEFAULT_CO
|
|
|
73
70
|
MAX_CONTEXT_TOKENS="${CLAUDE_CODE_MAX_CONTEXT_TOKENS:-${MAX_CONTEXT_TOKENS:-$DEFAULT_MAX_CONTEXT_TOKENS}}"
|
|
74
71
|
MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS:-$DEFAULT_MAX_CONCURRENT_SUBAGENTS}"
|
|
75
72
|
MAX_SUBAGENT_SPAWN_DEPTH="${MAX_SUBAGENT_SPAWN_DEPTH:-$DEFAULT_MAX_SUBAGENT_SPAWN_DEPTH}"
|
|
73
|
+
|
|
74
|
+
PICKER_MODELS=()
|
|
75
|
+
if [[ -n "${SUBCONSCIOUS_MODELS:-}" ]]; then
|
|
76
|
+
while IFS= read -r picker_model; do
|
|
77
|
+
[[ -n "$picker_model" ]] && PICKER_MODELS+=("$picker_model")
|
|
78
|
+
done <<< "$SUBCONSCIOUS_MODELS"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
picker_model_at() {
|
|
82
|
+
local index="$1"
|
|
83
|
+
local count="${#PICKER_MODELS[@]}"
|
|
84
|
+
if [[ "$count" -eq 0 ]]; then
|
|
85
|
+
printf '%s' "$MODEL"
|
|
86
|
+
return
|
|
87
|
+
fi
|
|
88
|
+
if [[ "$index" -ge "$count" ]]; then
|
|
89
|
+
index=$((count - 1))
|
|
90
|
+
fi
|
|
91
|
+
printf '%s' "${PICKER_MODELS[$index]}"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
in_picker_catalog() {
|
|
95
|
+
local candidate="$1" existing
|
|
96
|
+
[[ -z "$candidate" ]] && return 1
|
|
97
|
+
[[ "${#PICKER_MODELS[@]}" -eq 0 ]] && return 0
|
|
98
|
+
for existing in "${PICKER_MODELS[@]}"; do
|
|
99
|
+
[[ "$existing" == "$candidate" ]] && return 0
|
|
100
|
+
done
|
|
101
|
+
return 1
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if [[ "${#PICKER_MODELS[@]}" -gt 0 ]]; then
|
|
105
|
+
in_picker_catalog "${ANTHROPIC_DEFAULT_OPUS_MODEL:-}" || ANTHROPIC_DEFAULT_OPUS_MODEL=""
|
|
106
|
+
in_picker_catalog "${ANTHROPIC_DEFAULT_SONNET_MODEL:-}" || ANTHROPIC_DEFAULT_SONNET_MODEL=""
|
|
107
|
+
in_picker_catalog "${ANTHROPIC_DEFAULT_HAIKU_MODEL:-}" || ANTHROPIC_DEFAULT_HAIKU_MODEL=""
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
DEFAULT_OPUS_MODEL="$(picker_model_at 0)"
|
|
111
|
+
DEFAULT_SONNET_MODEL="$(picker_model_at 1)"
|
|
112
|
+
DEFAULT_HAIKU_MODEL="$(picker_model_at 2)"
|
|
76
113
|
OPUS_MODEL="${ANTHROPIC_DEFAULT_OPUS_MODEL:-$DEFAULT_OPUS_MODEL}"
|
|
77
114
|
OPUS_MODEL_NAME="${ANTHROPIC_DEFAULT_OPUS_MODEL_NAME:-$OPUS_MODEL}"
|
|
78
|
-
OPUS_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION:-Subconscious
|
|
115
|
+
OPUS_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION:-Subconscious model ${OPUS_MODEL}}"
|
|
79
116
|
SONNET_MODEL="${ANTHROPIC_DEFAULT_SONNET_MODEL:-$DEFAULT_SONNET_MODEL}"
|
|
80
117
|
SONNET_MODEL_NAME="${ANTHROPIC_DEFAULT_SONNET_MODEL_NAME:-$SONNET_MODEL}"
|
|
81
|
-
SONNET_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION:-Subconscious
|
|
118
|
+
SONNET_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION:-Subconscious model ${SONNET_MODEL}}"
|
|
82
119
|
HAIKU_MODEL="${ANTHROPIC_DEFAULT_HAIKU_MODEL:-$DEFAULT_HAIKU_MODEL}"
|
|
83
120
|
HAIKU_MODEL_NAME="${ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME:-$HAIKU_MODEL}"
|
|
84
|
-
HAIKU_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION:-Subconscious
|
|
121
|
+
HAIKU_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION:-Subconscious model ${HAIKU_MODEL}}"
|
|
85
122
|
COMMAND="install"
|
|
86
123
|
|
|
87
124
|
usage() {
|
|
@@ -30,9 +30,6 @@ DEFAULT_COMPACT_WINDOW="1000000"
|
|
|
30
30
|
DEFAULT_MAX_CONTEXT_TOKENS="3000000"
|
|
31
31
|
DEFAULT_MAX_CONCURRENT_SUBAGENTS="4"
|
|
32
32
|
DEFAULT_MAX_SUBAGENT_SPAWN_DEPTH="1"
|
|
33
|
-
DEFAULT_OPUS_MODEL="subconscious/glm-5.2"
|
|
34
|
-
DEFAULT_SONNET_MODEL="subconscious/tim-qwen3.6-27b"
|
|
35
|
-
DEFAULT_HAIKU_MODEL="subconscious/deepseek-v4-flash-marathon"
|
|
36
33
|
|
|
37
34
|
GATEWAY_URL="${GATEWAY_URL:-}"
|
|
38
35
|
API_KEY="${CLAUDE_CODE_API_KEY:-${API_KEY:-}}"
|
|
@@ -41,15 +38,94 @@ COMPACT_WINDOW="${CLAUDE_CODE_AUTO_COMPACT_WINDOW:-${COMPACT_WINDOW:-$DEFAULT_CO
|
|
|
41
38
|
MAX_CONTEXT_TOKENS="${CLAUDE_CODE_MAX_CONTEXT_TOKENS:-${MAX_CONTEXT_TOKENS:-$DEFAULT_MAX_CONTEXT_TOKENS}}"
|
|
42
39
|
MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS:-$DEFAULT_MAX_CONCURRENT_SUBAGENTS}"
|
|
43
40
|
MAX_SUBAGENT_SPAWN_DEPTH="${MAX_SUBAGENT_SPAWN_DEPTH:-$DEFAULT_MAX_SUBAGENT_SPAWN_DEPTH}"
|
|
41
|
+
|
|
42
|
+
# Claude's Opus/Sonnet/Haiku/Fable/custom slots must follow the live catalog
|
|
43
|
+
# (SUBCONSCIOUS_MODELS). Packaged DeepSeek/GLM defaults are not a capability.
|
|
44
|
+
PICKER_MODELS=()
|
|
45
|
+
if [[ -n "${SUBCONSCIOUS_MODELS:-}" ]]; then
|
|
46
|
+
while IFS= read -r picker_model; do
|
|
47
|
+
[[ -n "$picker_model" ]] && PICKER_MODELS+=("$picker_model")
|
|
48
|
+
done <<< "$SUBCONSCIOUS_MODELS"
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
picker_model_at() {
|
|
52
|
+
local index="$1"
|
|
53
|
+
local count="${#PICKER_MODELS[@]}"
|
|
54
|
+
if [[ "$count" -eq 0 ]]; then
|
|
55
|
+
printf '%s' "$MODEL"
|
|
56
|
+
return
|
|
57
|
+
fi
|
|
58
|
+
if [[ "$index" -ge "$count" ]]; then
|
|
59
|
+
index=$((count - 1))
|
|
60
|
+
fi
|
|
61
|
+
printf '%s' "${PICKER_MODELS[$index]}"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
in_picker_catalog() {
|
|
65
|
+
local candidate="$1" existing
|
|
66
|
+
[[ -z "$candidate" ]] && return 1
|
|
67
|
+
[[ "${#PICKER_MODELS[@]}" -eq 0 ]] && return 0
|
|
68
|
+
for existing in "${PICKER_MODELS[@]}"; do
|
|
69
|
+
[[ "$existing" == "$candidate" ]] && return 0
|
|
70
|
+
done
|
|
71
|
+
return 1
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if [[ "${#PICKER_MODELS[@]}" -gt 0 ]]; then
|
|
75
|
+
in_picker_catalog "${ANTHROPIC_DEFAULT_OPUS_MODEL:-}" || ANTHROPIC_DEFAULT_OPUS_MODEL=""
|
|
76
|
+
in_picker_catalog "${ANTHROPIC_DEFAULT_SONNET_MODEL:-}" || ANTHROPIC_DEFAULT_SONNET_MODEL=""
|
|
77
|
+
in_picker_catalog "${ANTHROPIC_DEFAULT_HAIKU_MODEL:-}" || ANTHROPIC_DEFAULT_HAIKU_MODEL=""
|
|
78
|
+
in_picker_catalog "${ANTHROPIC_DEFAULT_FABLE_MODEL:-}" || unset ANTHROPIC_DEFAULT_FABLE_MODEL ANTHROPIC_DEFAULT_FABLE_MODEL_NAME ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION
|
|
79
|
+
if [[ "${#PICKER_MODELS[@]}" -lt 5 ]] || ! in_picker_catalog "${ANTHROPIC_CUSTOM_MODEL_OPTION:-}"; then
|
|
80
|
+
unset ANTHROPIC_CUSTOM_MODEL_OPTION ANTHROPIC_CUSTOM_MODEL_OPTION_NAME ANTHROPIC_CUSTOM_MODEL_OPTION_DESCRIPTION
|
|
81
|
+
fi
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
DEFAULT_OPUS_MODEL="$(picker_model_at 0)"
|
|
85
|
+
DEFAULT_SONNET_MODEL="$(picker_model_at 1)"
|
|
86
|
+
DEFAULT_HAIKU_MODEL="$(picker_model_at 2)"
|
|
87
|
+
DEFAULT_FABLE_MODEL="$(picker_model_at 3)"
|
|
44
88
|
OPUS_MODEL="${ANTHROPIC_DEFAULT_OPUS_MODEL:-$DEFAULT_OPUS_MODEL}"
|
|
45
89
|
OPUS_MODEL_NAME="${ANTHROPIC_DEFAULT_OPUS_MODEL_NAME:-$OPUS_MODEL}"
|
|
46
|
-
OPUS_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION:-Subconscious
|
|
90
|
+
OPUS_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION:-Subconscious model ${OPUS_MODEL}}"
|
|
47
91
|
SONNET_MODEL="${ANTHROPIC_DEFAULT_SONNET_MODEL:-$DEFAULT_SONNET_MODEL}"
|
|
48
92
|
SONNET_MODEL_NAME="${ANTHROPIC_DEFAULT_SONNET_MODEL_NAME:-$SONNET_MODEL}"
|
|
49
|
-
SONNET_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION:-Subconscious
|
|
93
|
+
SONNET_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION:-Subconscious model ${SONNET_MODEL}}"
|
|
50
94
|
HAIKU_MODEL="${ANTHROPIC_DEFAULT_HAIKU_MODEL:-$DEFAULT_HAIKU_MODEL}"
|
|
51
95
|
HAIKU_MODEL_NAME="${ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME:-$HAIKU_MODEL}"
|
|
52
|
-
HAIKU_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION:-Subconscious
|
|
96
|
+
HAIKU_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION:-Subconscious model ${HAIKU_MODEL}}"
|
|
97
|
+
FABLE_MODEL="${ANTHROPIC_DEFAULT_FABLE_MODEL:-$DEFAULT_FABLE_MODEL}"
|
|
98
|
+
FABLE_MODEL_NAME="${ANTHROPIC_DEFAULT_FABLE_MODEL_NAME:-$FABLE_MODEL}"
|
|
99
|
+
FABLE_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION:-Subconscious model ${FABLE_MODEL}}"
|
|
100
|
+
|
|
101
|
+
# Model IDs are already restricted to [-A-Za-z0-9._:/+], so they are JSON-safe.
|
|
102
|
+
build_claude_picker_settings() {
|
|
103
|
+
local ids=() model_id first options allowlist
|
|
104
|
+
if [[ "${#PICKER_MODELS[@]}" -gt 0 ]]; then
|
|
105
|
+
ids=("${PICKER_MODELS[@]}")
|
|
106
|
+
else
|
|
107
|
+
ids=("$MODEL")
|
|
108
|
+
fi
|
|
109
|
+
options=""
|
|
110
|
+
allowlist=""
|
|
111
|
+
first=1
|
|
112
|
+
for model_id in "${ids[@]}"; do
|
|
113
|
+
[[ -n "$model_id" ]] || continue
|
|
114
|
+
if [[ "$first" -eq 1 ]]; then
|
|
115
|
+
first=0
|
|
116
|
+
else
|
|
117
|
+
options="${options},"
|
|
118
|
+
allowlist="${allowlist},"
|
|
119
|
+
fi
|
|
120
|
+
options="${options}{\"model\":\"${model_id}\",\"label\":\"${model_id}\",\"description\":\"Subconscious model ${model_id}\"}"
|
|
121
|
+
allowlist="${allowlist}\"${model_id}\""
|
|
122
|
+
done
|
|
123
|
+
printf '{"availableModels":[%s],"modelPicker":{"replaceBuiltInOptions":true,"options":[%s]}}' "$allowlist" "$options"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if [[ -z "${SUBC_CLAUDE_SETTINGS:-}" ]]; then
|
|
127
|
+
SUBC_CLAUDE_SETTINGS="$(build_claude_picker_settings)"
|
|
128
|
+
fi
|
|
53
129
|
|
|
54
130
|
usage() {
|
|
55
131
|
cat <<'EOF'
|
|
@@ -136,6 +212,10 @@ export ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_SONNET_MO
|
|
|
136
212
|
export ANTHROPIC_DEFAULT_HAIKU_MODEL="${ANTHROPIC_DEFAULT_HAIKU_MODEL:-$HAIKU_MODEL}"
|
|
137
213
|
export ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="${ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME:-$HAIKU_MODEL_NAME}"
|
|
138
214
|
export ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION:-$HAIKU_MODEL_DESCRIPTION}"
|
|
215
|
+
export ANTHROPIC_DEFAULT_FABLE_MODEL="${ANTHROPIC_DEFAULT_FABLE_MODEL:-$FABLE_MODEL}"
|
|
216
|
+
export ANTHROPIC_DEFAULT_FABLE_MODEL_NAME="${ANTHROPIC_DEFAULT_FABLE_MODEL_NAME:-$FABLE_MODEL_NAME}"
|
|
217
|
+
export ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION:-$FABLE_MODEL_DESCRIPTION}"
|
|
218
|
+
export CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY="${CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY:-0}"
|
|
139
219
|
export CLAUDE_CODE_SUBAGENT_MODEL="${CLAUDE_CODE_SUBAGENT_MODEL:-$MODEL}"
|
|
140
220
|
export CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS}"
|
|
141
221
|
export CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH="${MAX_SUBAGENT_SPAWN_DEPTH}"
|
|
@@ -164,4 +244,6 @@ if [[ "${BASH_SOURCE[0]:-$0}" != "${0}" ]]; then
|
|
|
164
244
|
fi
|
|
165
245
|
|
|
166
246
|
# If executed, launch claude with any passed-through args.
|
|
167
|
-
|
|
247
|
+
# --settings is additional JSON: it replaces the built-in Fable/Opus lineup
|
|
248
|
+
# with the live catalog and allowlists only those models.
|
|
249
|
+
exec claude --settings "${SUBC_CLAUDE_SETTINGS}" ${PASSTHRU[@]+"${PASSTHRU[@]}"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Install Subconscious Code. Tagged releases currently contain static Linux
|
|
3
|
+
# binaries; macOS builds from the tagged source until Darwin assets are added.
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
REPOSITORY="subconscious-systems/subconscious-code"
|
|
8
|
+
REPOSITORY_URL="https://github.com/${REPOSITORY}"
|
|
9
|
+
INSTALL_DIR="${SC_INSTALL_DIR:-${HOME}/.local/bin}"
|
|
10
|
+
|
|
11
|
+
usage() {
|
|
12
|
+
cat <<'EOF'
|
|
13
|
+
Usage: subc sc install
|
|
14
|
+
|
|
15
|
+
Install the latest Subconscious Code release. Linux downloads and verifies the
|
|
16
|
+
published static binary. macOS builds the release from source with Cargo.
|
|
17
|
+
EOF
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
case "${1:-install}" in
|
|
21
|
+
install) ;;
|
|
22
|
+
help|-h|--help)
|
|
23
|
+
usage
|
|
24
|
+
exit 0
|
|
25
|
+
;;
|
|
26
|
+
*)
|
|
27
|
+
echo "error: unsupported Subconscious Code setup action: $1" >&2
|
|
28
|
+
usage >&2
|
|
29
|
+
exit 2
|
|
30
|
+
;;
|
|
31
|
+
esac
|
|
32
|
+
|
|
33
|
+
release_tag() {
|
|
34
|
+
if [[ -n "${SC_CODE_VERSION:-}" ]]; then
|
|
35
|
+
printf '%s\n' "${SC_CODE_VERSION#v}"
|
|
36
|
+
return
|
|
37
|
+
fi
|
|
38
|
+
if command -v gh >/dev/null 2>&1; then
|
|
39
|
+
local tag
|
|
40
|
+
tag="$(gh release view --repo "$REPOSITORY" --json tagName --jq '.tagName' 2>/dev/null || true)"
|
|
41
|
+
if [[ -n "$tag" ]]; then
|
|
42
|
+
printf '%s\n' "${tag#v}"
|
|
43
|
+
return
|
|
44
|
+
fi
|
|
45
|
+
fi
|
|
46
|
+
if command -v curl >/dev/null 2>&1; then
|
|
47
|
+
local tag
|
|
48
|
+
tag="$(curl -fsSL "https://api.github.com/repos/${REPOSITORY}/releases/latest" 2>/dev/null \
|
|
49
|
+
| sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
|
|
50
|
+
| head -n 1 || true)"
|
|
51
|
+
if [[ -n "$tag" ]]; then
|
|
52
|
+
printf '%s\n' "${tag#v}"
|
|
53
|
+
return
|
|
54
|
+
fi
|
|
55
|
+
fi
|
|
56
|
+
return 1
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
install_from_source() {
|
|
60
|
+
if ! command -v cargo >/dev/null 2>&1; then
|
|
61
|
+
echo "error: macOS installation currently requires Cargo (Rust 1.89 or newer)" >&2
|
|
62
|
+
echo "Install Rust from https://rustup.rs, then run: subc sc install" >&2
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
local version="${1:-}"
|
|
67
|
+
local args=(install --locked --git "$REPOSITORY_URL" --bin sc)
|
|
68
|
+
if [[ -n "$version" ]]; then
|
|
69
|
+
args+=(--tag "v${version}")
|
|
70
|
+
echo "Building Subconscious Code v${version} from source..."
|
|
71
|
+
else
|
|
72
|
+
echo "No published release is visible yet; building Subconscious Code from the default branch..."
|
|
73
|
+
fi
|
|
74
|
+
args+=(rc-cli)
|
|
75
|
+
CARGO_NET_GIT_FETCH_WITH_CLI=true cargo "${args[@]}"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
platform="$(uname -s)"
|
|
79
|
+
version="$(release_tag || true)"
|
|
80
|
+
|
|
81
|
+
if [[ "$platform" == "Darwin" ]]; then
|
|
82
|
+
install_from_source "$version"
|
|
83
|
+
exit 0
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
if [[ "$platform" != "Linux" ]]; then
|
|
87
|
+
echo "error: Subconscious Code automatic installation supports Linux and macOS" >&2
|
|
88
|
+
exit 1
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
if [[ -z "$version" ]]; then
|
|
92
|
+
echo "error: no published Subconscious Code release is available yet" >&2
|
|
93
|
+
echo "The release may still be building. Retry subc sc install after it finishes." >&2
|
|
94
|
+
exit 1
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
case "$(uname -m)" in
|
|
98
|
+
x86_64|amd64) target="x86_64-unknown-linux-musl" ;;
|
|
99
|
+
aarch64|arm64) target="aarch64-unknown-linux-musl" ;;
|
|
100
|
+
*)
|
|
101
|
+
echo "error: unsupported Linux architecture: $(uname -m)" >&2
|
|
102
|
+
exit 1
|
|
103
|
+
;;
|
|
104
|
+
esac
|
|
105
|
+
|
|
106
|
+
asset="sc-${target}.tar.gz"
|
|
107
|
+
checksum="${asset}.sha256"
|
|
108
|
+
work_dir="$(mktemp -d "${TMPDIR:-/tmp}/subc-sc-install.XXXXXX")"
|
|
109
|
+
cleanup() {
|
|
110
|
+
rm -f "$work_dir/$asset" "$work_dir/$checksum" "$work_dir/sc"
|
|
111
|
+
rmdir "$work_dir" 2>/dev/null || true
|
|
112
|
+
}
|
|
113
|
+
trap cleanup EXIT HUP INT TERM
|
|
114
|
+
|
|
115
|
+
echo "Downloading Subconscious Code v${version} for ${target}..."
|
|
116
|
+
if command -v gh >/dev/null 2>&1 \
|
|
117
|
+
&& gh release view "v${version}" --repo "$REPOSITORY" >/dev/null 2>&1; then
|
|
118
|
+
gh release download "v${version}" --repo "$REPOSITORY" \
|
|
119
|
+
--pattern "$asset" --pattern "$checksum" --dir "$work_dir"
|
|
120
|
+
else
|
|
121
|
+
command -v curl >/dev/null 2>&1 || {
|
|
122
|
+
echo "error: curl is required to download Subconscious Code" >&2
|
|
123
|
+
exit 1
|
|
124
|
+
}
|
|
125
|
+
release_url="${REPOSITORY_URL}/releases/download/v${version}"
|
|
126
|
+
curl -fL "${release_url}/${asset}" -o "$work_dir/$asset"
|
|
127
|
+
curl -fL "${release_url}/${checksum}" -o "$work_dir/$checksum"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
131
|
+
(cd "$work_dir" && sha256sum --check "$checksum")
|
|
132
|
+
elif command -v shasum >/dev/null 2>&1; then
|
|
133
|
+
expected="$(awk '{print $1}' "$work_dir/$checksum")"
|
|
134
|
+
actual="$(shasum -a 256 "$work_dir/$asset" | awk '{print $1}')"
|
|
135
|
+
[[ "$actual" == "$expected" ]] || {
|
|
136
|
+
echo "error: Subconscious Code checksum verification failed" >&2
|
|
137
|
+
exit 1
|
|
138
|
+
}
|
|
139
|
+
else
|
|
140
|
+
echo "error: sha256sum or shasum is required to verify the download" >&2
|
|
141
|
+
exit 1
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
tar -xzf "$work_dir/$asset" -C "$work_dir" sc
|
|
145
|
+
mkdir -p "$INSTALL_DIR"
|
|
146
|
+
install -m 0755 "$work_dir/sc" "$INSTALL_DIR/sc"
|
|
147
|
+
echo "Installed Subconscious Code v${version} to $INSTALL_DIR/sc"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Launch Subconscious Code without changing ~/.sc or project settings.
|
|
3
|
+
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
GATEWAY_URL="${GATEWAY_URL:-}"
|
|
7
|
+
API_KEY="${SC_API_KEY:-${API_KEY:-}}"
|
|
8
|
+
MODEL="${MODEL:-subconscious/glm-5.2}"
|
|
9
|
+
|
|
10
|
+
if [[ -z "$GATEWAY_URL" || -z "$API_KEY" ]]; then
|
|
11
|
+
echo "error: GATEWAY_URL and API_KEY are required to launch Subconscious Code" >&2
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
export SC_API_KEY="$API_KEY"
|
|
16
|
+
export SC_BASE_URL="${GATEWAY_URL%/}/v1"
|
|
17
|
+
export SC_DLR_URL="${GATEWAY_URL%/}"
|
|
18
|
+
export SC_DLR_ENABLED=true
|
|
19
|
+
export SC_MODEL="$MODEL"
|
|
20
|
+
|
|
21
|
+
exec sc "$@"
|
package/bin/tui.js
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
DEFAULT_PROFILE,
|
|
12
12
|
listProfiles,
|
|
13
13
|
loadProfile,
|
|
14
|
+
resolvedModelSetting,
|
|
14
15
|
RUNBOOK_DEFAULTS,
|
|
15
16
|
SUPPORTED_MODELS as PACKAGED_MODELS,
|
|
16
17
|
} from './profiles.js';
|
|
@@ -70,15 +71,11 @@ export async function resolveTuiExecutable(options = {}) {
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
function selectedModelFor(profile) {
|
|
73
|
-
return (
|
|
74
|
-
process.env.SUBCONSCIOUS_MODEL?.trim() ||
|
|
75
|
-
profile.values.MODEL?.trim() ||
|
|
76
|
-
RUNBOOK_DEFAULTS.MODEL
|
|
77
|
-
);
|
|
74
|
+
return resolvedModelSetting(process.env.SUBCONSCIOUS_MODEL || profile.values.MODEL);
|
|
78
75
|
}
|
|
79
76
|
|
|
80
77
|
function subagentModelFor(profile) {
|
|
81
|
-
return profile.values.CLAUDE_CODE_SUBAGENT_MODEL
|
|
78
|
+
return resolvedModelSetting(profile.values.CLAUDE_CODE_SUBAGENT_MODEL);
|
|
82
79
|
}
|
|
83
80
|
|
|
84
81
|
function gatewayFor(profile) {
|
|
@@ -117,14 +114,15 @@ export async function createTuiState(profileName = DEFAULT_PROFILE, options = {}
|
|
|
117
114
|
);
|
|
118
115
|
|
|
119
116
|
const auth = await getApiKey(activeProfile);
|
|
120
|
-
const
|
|
117
|
+
const requestedModel = selectedModelFor(activeProfile);
|
|
121
118
|
const gatewayUrl = gatewayFor(activeProfile);
|
|
122
119
|
const catalog = await resolveModelCatalog({
|
|
123
120
|
baseUrl: gatewayUrl,
|
|
124
121
|
apiKey: auth?.key,
|
|
125
|
-
selectedModel,
|
|
122
|
+
selectedModel: requestedModel,
|
|
126
123
|
fallbackModels: PACKAGED_MODELS,
|
|
127
124
|
});
|
|
125
|
+
const selectedModel = requestedModel;
|
|
128
126
|
|
|
129
127
|
return {
|
|
130
128
|
version: await packageVersion(),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "subconscious-cli",
|
|
3
|
-
"version": "4.0.
|
|
4
|
-
"description": "CLI for Subconscious — run Claude Code, Codex, OpenCode, DeepSeek Harness, Cursor, Copilot, and Pi",
|
|
3
|
+
"version": "4.0.15",
|
|
4
|
+
"description": "CLI for Subconscious — run Subconscious Code, Claude Code, Codex, OpenCode, DeepSeek Harness, Cursor, Copilot, and Pi",
|
|
5
5
|
"bin": {
|
|
6
6
|
"subc": "bin/cli.js"
|
|
7
7
|
},
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"authentication",
|
|
34
34
|
"profiles",
|
|
35
35
|
"coding-agent",
|
|
36
|
+
"subconscious-code",
|
|
36
37
|
"claude-code",
|
|
37
38
|
"opencode",
|
|
38
39
|
"codex",
|