subconscious-cli 6.0.1 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -0
- package/bin/agent-data.js +242 -0
- package/bin/agent-help.js +106 -0
- package/bin/agent-install.js +354 -0
- package/bin/agent-launch.js +199 -0
- package/bin/agent-spawn.js +137 -0
- package/bin/agents.js +236 -932
- package/bin/auth.js +9 -1
- package/bin/claude-picker.js +143 -0
- package/bin/cli.js +60 -1
- package/bin/clipboard-image.js +2 -0
- package/bin/feedback.js +14 -3
- package/bin/harness-manifest.js +286 -0
- package/bin/headless-args.js +35 -0
- package/bin/launch-values.js +25 -0
- package/bin/model-capabilities.js +10 -9
- package/bin/models.js +13 -13
- 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/opencode-provider.js +21 -0
- package/bin/profile-settings.js +129 -0
- package/bin/profiles.js +29 -424
- package/bin/runbook/README.md +66 -23
- package/bin/runbook/claude-code/agent.json +300 -0
- package/bin/runbook/claude-code/install.sh +9 -252
- package/bin/runbook/codex/agent.json +461 -0
- package/bin/runbook/codex/hooks-lib.sh +17 -4
- package/bin/runbook/codex/install.sh +0 -4
- package/bin/runbook/codex/run.sh +16 -235
- package/bin/runbook/copilot/agent.json +185 -0
- package/bin/runbook/copilot/install.sh +45 -63
- package/bin/runbook/cursor/agent.json +137 -0
- package/bin/runbook/cursor/install.sh +8 -35
- package/bin/runbook/deepseek-harness/agent.json +163 -0
- package/bin/runbook/deepseek-harness/run.sh +20 -59
- package/bin/runbook/image-window/index.ts +14 -0
- package/bin/runbook/image-window/window.d.ts +19 -0
- package/bin/runbook/image-window/window.js +140 -0
- package/bin/runbook/lib.sh +41 -0
- package/bin/runbook/opencode/agent.json +158 -0
- package/bin/runbook/opencode/install.sh +9 -183
- package/bin/runbook/opencode/opencode-plugin.d.ts +10 -3
- package/bin/runbook/opencode/subconscious-image-window.ts +24 -0
- package/bin/runbook/pi/agent.json +216 -0
- package/bin/runbook/pi/install.sh +18 -44
- package/bin/runbook/pi/run.sh +6 -18
- package/bin/runbook/pi/subconscious-compaction.ts +3 -1
- package/bin/runbook/shared.json +58 -0
- package/bin/runbook/subconscious-code/agent.json +156 -0
- package/bin/sessions.js +52 -22
- package/bin/tui.js +13 -0
- package/bin/update-check.js +5 -1
- package/bin/upgrade.js +24 -31
- package/bin/usage.js +21 -10
- package/bin/windows/agents.js +18 -17
- package/bin/windows/common.js +2 -28
- package/bin/windows/install.js +11 -17
- package/bin/windows/launch.js +252 -231
- package/bin/windows/process.js +12 -1
- package/bin/windows/setup.js +29 -9
- package/package.json +2 -3
- package/bin/registry.generated.json +0 -406
- package/bin/runbook/claude-code/run.sh +0 -254
- package/bin/runbook/model-capabilities.generated.sh +0 -9
- package/bin/runbook/opencode/provider.sh +0 -93
- package/bin/runbook/opencode/run.sh +0 -99
- package/bin/runbook/opencode/subconscious-compaction.ts +0 -100
- package/bin/runbook/subconscious-code/run.sh +0 -21
- package/bin/windows/claude.js +0 -100
package/bin/sessions.js
CHANGED
|
@@ -2,6 +2,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { AGENTS, agentById, agentCommandName } from './agent-data.js';
|
|
5
6
|
import { resolveAgent, runAgent } from './agents.js';
|
|
6
7
|
|
|
7
8
|
import { c } from './colors.js';
|
|
@@ -14,15 +15,25 @@ const MAX_INDEX_BYTES = 4 * 1024 * 1024;
|
|
|
14
15
|
const MAX_HANDOFF_MESSAGES = 24;
|
|
15
16
|
const MAX_HANDOFF_CHARS = 24_000;
|
|
16
17
|
const MAX_MESSAGE_CHARS = 4_000;
|
|
17
|
-
const SESSION_KEY_PATTERN =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
const SESSION_KEY_PATTERN = new RegExp(
|
|
19
|
+
`^(${AGENTS.filter((agent) => agent.sessions)
|
|
20
|
+
.map((agent) => agent.sessions.key)
|
|
21
|
+
.join('|')}):[-A-Za-z0-9._]+$`,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export const SESSION_HARNESSES = Object.freeze(
|
|
25
|
+
Object.fromEntries(
|
|
26
|
+
AGENTS.filter((agent) => agent.sessions).map((agent) => [
|
|
27
|
+
agent.sessions.key,
|
|
28
|
+
Object.freeze({
|
|
29
|
+
name: agent.name,
|
|
30
|
+
command: agentCommandName(agent),
|
|
31
|
+
portable: agent.sessions.portable,
|
|
32
|
+
agentId: agent.id,
|
|
33
|
+
}),
|
|
34
|
+
]),
|
|
35
|
+
),
|
|
36
|
+
);
|
|
26
37
|
|
|
27
38
|
function cleanText(value) {
|
|
28
39
|
return String(value || '')
|
|
@@ -56,7 +67,10 @@ function parseLines(text) {
|
|
|
56
67
|
for (const line of text.split('\n')) {
|
|
57
68
|
if (!line.trim()) continue;
|
|
58
69
|
try {
|
|
59
|
-
|
|
70
|
+
const record = JSON.parse(line);
|
|
71
|
+
if (record && typeof record === 'object' && !Array.isArray(record)) {
|
|
72
|
+
records.push(record);
|
|
73
|
+
}
|
|
60
74
|
} catch {
|
|
61
75
|
// Session writers can leave a partial final line after an interrupted run.
|
|
62
76
|
}
|
|
@@ -594,22 +608,38 @@ export function buildHandoffPrompt(session, messages) {
|
|
|
594
608
|
.join('\n\n');
|
|
595
609
|
}
|
|
596
610
|
|
|
611
|
+
function sessionLaunch(harness) {
|
|
612
|
+
return agentById(SESSION_HARNESSES[harness]?.agentId)?.launch ?? {};
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// One pass, so a prompt that mentions a placeholder is passed unchanged.
|
|
616
|
+
function fillWords(words, values) {
|
|
617
|
+
return words.map((word) =>
|
|
618
|
+
word.replace(/\{(sessionId|sessionFile|prompt)\}/g, (_, name) =>
|
|
619
|
+
String(values[name]),
|
|
620
|
+
),
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
|
|
597
624
|
export function nativeResumeArgs(session) {
|
|
598
|
-
|
|
599
|
-
if (
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
625
|
+
const { resume } = sessionLaunch(session.harness);
|
|
626
|
+
if (!resume)
|
|
627
|
+
throw new Error(
|
|
628
|
+
`Native resume is not supported for ${session.harnessName}.`,
|
|
629
|
+
);
|
|
630
|
+
return fillWords(resume, {
|
|
631
|
+
sessionId: session.id,
|
|
632
|
+
sessionFile: session.sourcePath || session.id,
|
|
633
|
+
});
|
|
605
634
|
}
|
|
606
635
|
|
|
607
636
|
export function handoffLaunchArgs(targetHarness, prompt) {
|
|
608
|
-
|
|
609
|
-
if (
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
637
|
+
const { handoff } = sessionLaunch(targetHarness);
|
|
638
|
+
if (!handoff)
|
|
639
|
+
throw new Error(
|
|
640
|
+
`${SESSION_HARNESSES[targetHarness]?.name || targetHarness} cannot start an interactive handoff yet.`,
|
|
641
|
+
);
|
|
642
|
+
return fillWords(handoff, { prompt });
|
|
613
643
|
}
|
|
614
644
|
|
|
615
645
|
function sessionByKey(sessions, key) {
|
package/bin/tui.js
CHANGED
|
@@ -422,6 +422,19 @@ function spawnAndWait(command, args, options = {}) {
|
|
|
422
422
|
}
|
|
423
423
|
|
|
424
424
|
export async function runTui(options = {}) {
|
|
425
|
+
for (;;) {
|
|
426
|
+
const result = await runTuiOnce(options);
|
|
427
|
+
if (result?.args?.length !== 2 || result.args[0] !== '-p') return result;
|
|
428
|
+
options = {
|
|
429
|
+
...options,
|
|
430
|
+
profileName: result.args[1],
|
|
431
|
+
profile: undefined,
|
|
432
|
+
state: undefined,
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
async function runTuiOnce(options) {
|
|
425
438
|
const executable = await resolveTuiExecutable(options);
|
|
426
439
|
if (!executable) return null;
|
|
427
440
|
|
package/bin/update-check.js
CHANGED
|
@@ -86,6 +86,10 @@ function parseVersion(version) {
|
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
export function isVersion(version) {
|
|
90
|
+
return parseVersion(version) !== null;
|
|
91
|
+
}
|
|
92
|
+
|
|
89
93
|
function comparePrerelease(a, b) {
|
|
90
94
|
if (!a.length && !b.length) return 0;
|
|
91
95
|
if (!a.length) return 1;
|
|
@@ -102,7 +106,7 @@ function comparePrerelease(a, b) {
|
|
|
102
106
|
return Math.sign(aNumber - bNumber);
|
|
103
107
|
if (aNumber !== null) return -1;
|
|
104
108
|
if (bNumber !== null) return 1;
|
|
105
|
-
return a[index]
|
|
109
|
+
return a[index] < b[index] ? -1 : 1;
|
|
106
110
|
}
|
|
107
111
|
return 0;
|
|
108
112
|
}
|
package/bin/upgrade.js
CHANGED
|
@@ -10,7 +10,11 @@ import fs from 'node:fs/promises';
|
|
|
10
10
|
import readline from 'node:readline';
|
|
11
11
|
import { fileURLToPath } from 'node:url';
|
|
12
12
|
import { c } from './colors.js';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
compareVersions,
|
|
15
|
+
detectInstallTarget,
|
|
16
|
+
isVersion,
|
|
17
|
+
} from './update-check.js';
|
|
14
18
|
import { runWindows } from './windows/process.js';
|
|
15
19
|
|
|
16
20
|
export const PACKAGE_NAME = 'subconscious-cli';
|
|
@@ -38,23 +42,6 @@ export async function currentCliVersion() {
|
|
|
38
42
|
return pkg.version;
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
export function compareVersions(a, b) {
|
|
42
|
-
const pa = String(a)
|
|
43
|
-
.split('.')
|
|
44
|
-
.map((part) => Number.parseInt(part, 10) || 0);
|
|
45
|
-
const pb = String(b)
|
|
46
|
-
.split('.')
|
|
47
|
-
.map((part) => Number.parseInt(part, 10) || 0);
|
|
48
|
-
const n = Math.max(pa.length, pb.length);
|
|
49
|
-
for (let i = 0; i < n; i++) {
|
|
50
|
-
const da = pa[i] || 0;
|
|
51
|
-
const db = pb[i] || 0;
|
|
52
|
-
if (da > db) return 1;
|
|
53
|
-
if (da < db) return -1;
|
|
54
|
-
}
|
|
55
|
-
return 0;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
45
|
export async function fetchLatestVersion(fetchImpl = fetch) {
|
|
59
46
|
const res = await fetchImpl(
|
|
60
47
|
`https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
|
|
@@ -121,13 +108,17 @@ export async function installLatest(options = {}) {
|
|
|
121
108
|
|
|
122
109
|
let latest;
|
|
123
110
|
try {
|
|
124
|
-
|
|
111
|
+
const version = await fetchLatest();
|
|
112
|
+
if (!isVersion(version)) {
|
|
113
|
+
throw new Error(`npm returned an invalid version (${version}).`);
|
|
114
|
+
}
|
|
115
|
+
latest = version;
|
|
125
116
|
} catch (error) {
|
|
126
117
|
console.error(` ${c.yellow}${error.message}${c.reset}`);
|
|
127
118
|
console.error(` ${c.dim}Installing @latest anyway.${c.reset}\n`);
|
|
128
119
|
}
|
|
129
120
|
|
|
130
|
-
if (latest && compareVersions(current, latest) >= 0) {
|
|
121
|
+
if (latest && isVersion(current) && compareVersions(current, latest) >= 0) {
|
|
131
122
|
console.log(
|
|
132
123
|
`\n ${c.green}Already up to date${c.reset} ${c.dim}(${current}).${c.reset}\n`,
|
|
133
124
|
);
|
|
@@ -153,18 +144,12 @@ export async function installLatest(options = {}) {
|
|
|
153
144
|
}
|
|
154
145
|
|
|
155
146
|
if (latest) {
|
|
147
|
+
const readVersion = options.readVersion || currentCliVersion;
|
|
148
|
+
let installedVersion;
|
|
156
149
|
try {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
console.error(
|
|
161
|
-
`\n ${c.red}Upgrade command completed, but this installation is still ${installedVersion}.${c.reset}`,
|
|
162
|
-
);
|
|
163
|
-
console.error(` Run the exact detected command manually:\n`);
|
|
164
|
-
console.error(` ${c.cyan}${command}${c.reset}\n`);
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
} catch {
|
|
150
|
+
installedVersion = await readVersion();
|
|
151
|
+
} catch {}
|
|
152
|
+
if (!isVersion(installedVersion)) {
|
|
168
153
|
console.error(
|
|
169
154
|
`\n ${c.red}Could not verify the updated CLI installation.${c.reset}`,
|
|
170
155
|
);
|
|
@@ -172,6 +157,14 @@ export async function installLatest(options = {}) {
|
|
|
172
157
|
console.error(` ${c.cyan}${command}${c.reset}\n`);
|
|
173
158
|
return false;
|
|
174
159
|
}
|
|
160
|
+
if (compareVersions(installedVersion, latest) < 0) {
|
|
161
|
+
console.error(
|
|
162
|
+
`\n ${c.red}Upgrade command completed, but this installation is still ${installedVersion}.${c.reset}`,
|
|
163
|
+
);
|
|
164
|
+
console.error(` Run the exact detected command manually:\n`);
|
|
165
|
+
console.error(` ${c.cyan}${command}${c.reset}\n`);
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
175
168
|
}
|
|
176
169
|
|
|
177
170
|
console.log(
|
package/bin/usage.js
CHANGED
|
@@ -9,19 +9,30 @@ import { printLoginUpgradeWarning } from './upgrade.js';
|
|
|
9
9
|
|
|
10
10
|
export const USAGE_API_PATH = '/api/v1/usage';
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
// Largest first: [size, suffix].
|
|
13
|
+
const TOKEN_UNITS = [
|
|
14
|
+
[1_000_000_000, 'B'],
|
|
15
|
+
[1_000_000, 'M'],
|
|
16
|
+
[1_000, 'K'],
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export function formatTokens(value, { sigFigs = 3 } = {}) {
|
|
13
20
|
const n = Number(value);
|
|
21
|
+
|
|
14
22
|
if (!Number.isFinite(n) || n < 0) return '0';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
|
|
24
|
+
let index = TOKEN_UNITS.findIndex(([size]) => n >= size);
|
|
25
|
+
if (index === -1) return n.toLocaleString('en-US');
|
|
26
|
+
|
|
27
|
+
// Number() also turns toPrecision's exponent form ("1.00e+3") back into 1000.
|
|
28
|
+
|
|
29
|
+
let scaled = Number((n / TOKEN_UNITS[index][0]).toPrecision(sigFigs));
|
|
30
|
+
// Rounding can reach the next unit: 999_500 is 1M, not 1000K.
|
|
31
|
+
if (scaled >= 1_000 && index > 0) {
|
|
32
|
+
index -= 1;
|
|
33
|
+
scaled = Number((n / TOKEN_UNITS[index][0]).toPrecision(sigFigs));
|
|
22
34
|
}
|
|
23
|
-
|
|
24
|
-
return n.toLocaleString('en-US');
|
|
35
|
+
return `${scaled}${TOKEN_UNITS[index][1]}`;
|
|
25
36
|
}
|
|
26
37
|
|
|
27
38
|
export function formatCurrency(value) {
|
package/bin/windows/agents.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import os from 'node:os';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import readline from 'node:readline';
|
|
4
|
+
import { agentBinary, agentInstallDirs } from '../agent-data.js';
|
|
5
|
+
import { separatorIndex } from '../headless-args.js';
|
|
4
6
|
import { parseOptions } from './common.js';
|
|
5
7
|
import { installWindowsAgent, windowsInstallSpec } from './install.js';
|
|
6
8
|
import { executeWindowsLaunch, windowsLaunch } from './launch.js';
|
|
@@ -41,18 +43,12 @@ export async function runWindowsAgent(agent, argv, dependencies) {
|
|
|
41
43
|
} = dependencies;
|
|
42
44
|
const parsed = parseAgentAction(agent, argv);
|
|
43
45
|
let args =
|
|
44
|
-
parsed.action
|
|
46
|
+
!['launch', 'headless'].includes(parsed.action) && parsed.action === argv[0]
|
|
45
47
|
? argv.slice(1)
|
|
46
48
|
: argv;
|
|
47
49
|
const environment = windowsEnv(profile?.values, process.env);
|
|
48
|
-
const preferredDirs = agent.
|
|
49
|
-
|
|
50
|
-
path.resolve(
|
|
51
|
-
environment[agent.runbook.installDirEnv] ||
|
|
52
|
-
path.join(os.homedir(), agent.runbook.installDir),
|
|
53
|
-
),
|
|
54
|
-
]
|
|
55
|
-
: [];
|
|
50
|
+
const preferredDirs = agentInstallDirs(agent, environment, os.homedir());
|
|
51
|
+
const bin = agentBinary(agent);
|
|
56
52
|
environment.PATH = windowsPath([
|
|
57
53
|
...preferredDirs,
|
|
58
54
|
...(environment.PATH || '').split(';'),
|
|
@@ -69,7 +65,7 @@ export async function runWindowsAgent(agent, argv, dependencies) {
|
|
|
69
65
|
}
|
|
70
66
|
|
|
71
67
|
// Honor -- after which all arguments belong to the underlying agent.
|
|
72
|
-
const boundary = args
|
|
68
|
+
const boundary = separatorIndex(args);
|
|
73
69
|
const tail = boundary < 0 ? [] : args.slice(boundary);
|
|
74
70
|
const extracted = extractModel(
|
|
75
71
|
boundary < 0 ? args : args.slice(0, boundary),
|
|
@@ -79,7 +75,7 @@ export async function runWindowsAgent(agent, argv, dependencies) {
|
|
|
79
75
|
let explicit = {};
|
|
80
76
|
if (parsed.action === 'install' || agent.id === 'claude-code') {
|
|
81
77
|
const handled = parseOptions(
|
|
82
|
-
boundary < 0 ? args : args.slice(0,
|
|
78
|
+
boundary < 0 ? args : args.slice(0, boundary),
|
|
83
79
|
{ '--api-key': 1, '--gateway-url': 1 },
|
|
84
80
|
);
|
|
85
81
|
explicit = handled.options;
|
|
@@ -106,9 +102,10 @@ export async function runWindowsAgent(agent, argv, dependencies) {
|
|
|
106
102
|
console.error(
|
|
107
103
|
`Configured model ${extracted.model} is not in the live catalog; using ${model}.`,
|
|
108
104
|
);
|
|
105
|
+
const headless = dependencies.headless ?? parsed.action === 'headless';
|
|
109
106
|
let executable;
|
|
110
|
-
if (parsed.action === 'launch') {
|
|
111
|
-
executable = resolveWindowsExecutable(
|
|
107
|
+
if (parsed.action === 'launch' || headless) {
|
|
108
|
+
executable = resolveWindowsExecutable(bin, {
|
|
112
109
|
env: environment,
|
|
113
110
|
preferredDirs,
|
|
114
111
|
});
|
|
@@ -116,6 +113,7 @@ export async function runWindowsAgent(agent, argv, dependencies) {
|
|
|
116
113
|
const installer = windowsInstallSpec(agent.id, environment);
|
|
117
114
|
if (
|
|
118
115
|
!installer ||
|
|
116
|
+
headless ||
|
|
119
117
|
!process.stdin.isTTY ||
|
|
120
118
|
!process.stdout.isTTY ||
|
|
121
119
|
!(await askInstall(agent.name))
|
|
@@ -127,13 +125,13 @@ export async function runWindowsAgent(agent, argv, dependencies) {
|
|
|
127
125
|
}
|
|
128
126
|
const installed = await installWindowsAgent(agent.id, environment);
|
|
129
127
|
if (installed) return finish(installed);
|
|
130
|
-
executable = resolveWindowsExecutable(
|
|
128
|
+
executable = resolveWindowsExecutable(bin, {
|
|
131
129
|
env: environment,
|
|
132
130
|
preferredDirs,
|
|
133
131
|
});
|
|
134
132
|
if (!executable) {
|
|
135
133
|
console.error(
|
|
136
|
-
`Installed ${agent.name}, but ${
|
|
134
|
+
`Installed ${agent.name}, but ${bin} was not found. Add its installation directory to PATH or restart your terminal.`,
|
|
137
135
|
);
|
|
138
136
|
return finish(127);
|
|
139
137
|
}
|
|
@@ -179,8 +177,11 @@ export async function runWindowsAgent(agent, argv, dependencies) {
|
|
|
179
177
|
}
|
|
180
178
|
}
|
|
181
179
|
const spec = await windowsLaunch(agent.id, args, env);
|
|
182
|
-
if (spec.command ===
|
|
183
|
-
|
|
180
|
+
if (spec.command === bin) spec.command = executable;
|
|
181
|
+
// Headless stdout belongs to the agent alone.
|
|
182
|
+
(headless ? console.error : console.log)(
|
|
183
|
+
` Launching ${agent.name} on Subconscious (${model})\n`,
|
|
184
|
+
);
|
|
184
185
|
return finish(await executeWindowsLaunch(spec, runWindows));
|
|
185
186
|
}
|
|
186
187
|
|
package/bin/windows/common.js
CHANGED
|
@@ -1,40 +1,14 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
3
2
|
import fs from 'node:fs/promises';
|
|
4
3
|
import path from 'node:path';
|
|
5
4
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
).defaults;
|
|
5
|
+
export { DEFAULTS as defaults } from '../agent-data.js';
|
|
6
|
+
export { modelIds, positiveInteger } from '../launch-values.js';
|
|
9
7
|
export const value = (env, key, fallback = '') => env[key]?.trim() || fallback;
|
|
10
8
|
export const origin = (url) =>
|
|
11
9
|
url
|
|
12
10
|
.replace(/\/+$/, '')
|
|
13
11
|
.replace(/\/v1(?:\/(?:messages|responses|chat\/completions))?$/, '');
|
|
14
|
-
export function positiveInteger(input, name) {
|
|
15
|
-
if (
|
|
16
|
-
!/^[1-9][0-9]*$/.test(String(input)) ||
|
|
17
|
-
!Number.isSafeInteger(Number(input))
|
|
18
|
-
)
|
|
19
|
-
throw new Error(`${name} must be a positive integer`);
|
|
20
|
-
return Number(input);
|
|
21
|
-
}
|
|
22
|
-
export function modelIds(env) {
|
|
23
|
-
const models = [
|
|
24
|
-
...new Set(
|
|
25
|
-
[
|
|
26
|
-
value(env, 'MODEL', defaults.model),
|
|
27
|
-
...value(env, 'SUBCONSCIOUS_MODELS', defaults.models.join('\n')).split(
|
|
28
|
-
/\r?\n/,
|
|
29
|
-
),
|
|
30
|
-
].filter(Boolean),
|
|
31
|
-
),
|
|
32
|
-
];
|
|
33
|
-
for (const model of models)
|
|
34
|
-
if (!/^[-A-Za-z0-9._:/+]+$/.test(model))
|
|
35
|
-
throw new Error(`Invalid model id: ${model}`);
|
|
36
|
-
return models;
|
|
37
|
-
}
|
|
38
12
|
export function parseOptions(argv, schema, { strict = false } = {}) {
|
|
39
13
|
const options = {},
|
|
40
14
|
rest = [];
|
package/bin/windows/install.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
3
2
|
import fs from 'node:fs/promises';
|
|
4
3
|
import os from 'node:os';
|
|
5
4
|
import path from 'node:path';
|
|
5
|
+
import { agentById, installCommands } from '../agent-data.js';
|
|
6
6
|
import { powershellCommand, runWindows } from './process.js';
|
|
7
7
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
);
|
|
11
|
-
const repository = 'subconscious-systems/subconscious-code';
|
|
8
|
+
const marathon = agentById('subconscious-code').install;
|
|
9
|
+
const repository = marathon.repository;
|
|
12
10
|
|
|
13
11
|
function npmInstall(command) {
|
|
14
12
|
const match = /^npm (?:i|install) -g ([@a-zA-Z0-9/._-]+)$/.exec(
|
|
@@ -18,8 +16,8 @@ function npmInstall(command) {
|
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
export function windowsInstallSpec(id, env = process.env) {
|
|
21
|
-
const install =
|
|
22
|
-
const command =
|
|
19
|
+
const install = installCommands(agentById(id)) || {};
|
|
20
|
+
const command = install.win32;
|
|
23
21
|
if (id === 'subconscious-code')
|
|
24
22
|
return { nativeRelease: true, display: 'subc marathon install' };
|
|
25
23
|
if (!command) return null; // Never fall back to a Linux installer.
|
|
@@ -40,22 +38,18 @@ export function windowsInstallSpec(id, env = process.env) {
|
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
export function windowsReleaseAsset(release, arch = process.arch) {
|
|
43
|
-
const target =
|
|
44
|
-
x64: 'x86_64-
|
|
45
|
-
|
|
46
|
-
}[arch];
|
|
41
|
+
const target = marathon.windows_targets.find((triple) =>
|
|
42
|
+
triple.startsWith({ x64: 'x86_64-', arm64: 'aarch64-' }[arch] ?? '-'),
|
|
43
|
+
);
|
|
47
44
|
if (!target)
|
|
48
45
|
throw new Error(
|
|
49
46
|
`Subconscious Code does not support Windows architecture ${arch}`,
|
|
50
47
|
);
|
|
51
48
|
// Pinned older releases are installed under the new executable name too.
|
|
52
49
|
// Never resolve or overwrite Windows' own sc.exe.
|
|
53
|
-
const names =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
`sc-${target}.zip`,
|
|
57
|
-
`sc-${target}.exe`,
|
|
58
|
-
];
|
|
50
|
+
const names = marathon.windows_assets.map((name) =>
|
|
51
|
+
name.replaceAll('{target}', target),
|
|
52
|
+
);
|
|
59
53
|
const asset = names
|
|
60
54
|
.map((name) => release.assets?.find((asset) => asset.name === name))
|
|
61
55
|
.find(Boolean);
|