subconscious-cli 6.1.0 → 6.2.1
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 +52 -47
- package/bin/agent-data.js +37 -1
- package/bin/agent-help.js +12 -4
- package/bin/agent-install.js +19 -135
- package/bin/agents.js +6 -5
- package/bin/cli.js +2 -1
- package/bin/command-output.js +75 -0
- package/bin/models.js +12 -0
- 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/runbook/README.md +13 -2
- package/bin/runbook/claude-code/agent.json +6 -6
- package/bin/runbook/codex/agent.json +1 -0
- package/bin/runbook/copilot/agent.json +1 -0
- package/bin/runbook/cursor/agent.json +3 -2
- package/bin/runbook/deepseek-harness/agent.json +1 -0
- package/bin/runbook/opencode/agent.json +1 -0
- package/bin/runbook/pi/agent.json +1 -0
- package/bin/runbook/shared.json +1 -2
- package/bin/sessions.js +20 -50
- package/bin/tui.js +18 -8
- package/bin/update-check.js +30 -0
- package/bin/upgrade.js +3 -3
- package/bin/windows/agents.js +14 -47
- package/bin/windows/launch.js +1 -1
- package/bin/windows/process.js +1 -18
- package/package.json +2 -3
- package/bin/runbook/subconscious-code/agent.json +0 -156
- package/bin/runbook/subconscious-code/install.sh +0 -154
- package/bin/windows/install.js +0 -182
package/bin/runbook/README.md
CHANGED
|
@@ -8,7 +8,6 @@ the default gateway, model capabilities, and the settings every agent uses
|
|
|
8
8
|
|
|
9
9
|
| Agent | Launch | Setup |
|
|
10
10
|
| --- | --- | --- |
|
|
11
|
-
| `subconscious-code` (Marathon) | binary | `install.sh` (binary installer) |
|
|
12
11
|
| `claude-code` | binary | `install.sh` (leftover status/uninstall) |
|
|
13
12
|
| `codex` | `run.sh` | `install.sh` (hooks) |
|
|
14
13
|
| `opencode` | binary | `install.sh` (leftover status/uninstall) |
|
|
@@ -22,7 +21,7 @@ the default gateway, model capabilities, and the settings every agent uses
|
|
|
22
21
|
| Field | Read by |
|
|
23
22
|
| --- | --- |
|
|
24
23
|
| `id`, `command`, `aliases`, `name`, `description` | routing, `subc help`, the TUI menu |
|
|
25
|
-
| `install` | the
|
|
24
|
+
| `install` | the missing-agent message, agent help, and the upgrade warning (`minimum_version`); `{package}` fills in `commands` |
|
|
26
25
|
| `runbook` | which script launches the agent (none means the binary is run directly) and which setup actions exist |
|
|
27
26
|
| `help` | `subc <agent> help`; flags with a `help` text are added from `inputs` |
|
|
28
27
|
| `sessions`, `launch.resume`, `launch.handoff` | `subc sessions resume` |
|
|
@@ -32,6 +31,18 @@ the default gateway, model capabilities, and the settings every agent uses
|
|
|
32
31
|
| `config` | `cli-config` entries become `config_flag NAME=VALUE` (Codex `-c`) when `when` holds; other entries describe files the runbooks write |
|
|
33
32
|
| `capabilities`, `prerequisites` | the harness manifest only |
|
|
34
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
|
+
|
|
35
46
|
Values may use `{baseUrl}`, `{baseUrlV1}`, `{apiKey}`, `{model}`, `{prompt}`,
|
|
36
47
|
`{args}`, `{config}`, and `${NAME}` for another input or env entry.
|
|
37
48
|
`subc harness-manifest --json` prints every agent file with `${NAME}` replaced
|
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
"homepage": "https://docs.anthropic.com/en/docs/claude-code",
|
|
9
9
|
"install": {
|
|
10
10
|
"commands": {
|
|
11
|
-
"darwin": "
|
|
12
|
-
"linux": "
|
|
13
|
-
"win32": "
|
|
14
|
-
"fallback": "npm i -g {package}"
|
|
11
|
+
"darwin": "npm i -g {package}",
|
|
12
|
+
"linux": "npm i -g {package}",
|
|
13
|
+
"win32": "npm i -g {package}"
|
|
15
14
|
},
|
|
16
|
-
"
|
|
15
|
+
"url": "https://code.claude.com/docs/en/setup",
|
|
16
|
+
"method": "npm",
|
|
17
17
|
"package": "@anthropic-ai/claude-code",
|
|
18
18
|
"version": null,
|
|
19
|
-
"channel": "
|
|
19
|
+
"channel": "latest (unpinned)",
|
|
20
20
|
"minimum_version": "2.1.242",
|
|
21
21
|
"verified": true,
|
|
22
22
|
"note": "subc warns, and does not block, below minimum_version."
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
"command": "cursor",
|
|
4
4
|
"aliases": [],
|
|
5
5
|
"name": "Cursor",
|
|
6
|
-
"description": "Install Cursor conversation and compaction hooks, then finish model setup in Cursor Settings.",
|
|
6
|
+
"description": "Install Cursor conversation and compaction hooks in the Cursor desktop app and IDE, then finish model setup in Cursor Settings. The Cursor CLI is not supported.",
|
|
7
7
|
"protocol": "openai",
|
|
8
8
|
"homepage": "https://cursor.com",
|
|
9
9
|
"install": {
|
|
10
10
|
"commands": null,
|
|
11
|
+
"url": "https://cursor.com/download",
|
|
11
12
|
"method": "user",
|
|
12
13
|
"package": null,
|
|
13
14
|
"version": null,
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
},
|
|
23
24
|
"help": {
|
|
24
25
|
"usage": "subc [-p NAME] cursor [help|install|status|uninstall]",
|
|
25
|
-
"behavior": "Manages Cursor correlation hooks; model endpoint setup is completed in Cursor Settings.",
|
|
26
|
+
"behavior": "Manages Cursor correlation hooks in the Cursor desktop app and IDE; model endpoint setup is completed in Cursor Settings. The Cursor CLI is not supported.",
|
|
26
27
|
"options": [
|
|
27
28
|
["help", "Show this help"],
|
|
28
29
|
["install", "Install or update the Cursor hooks (default action)"],
|
package/bin/runbook/shared.json
CHANGED
package/bin/sessions.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { spawnSync } from 'node:child_process';
|
|
2
1
|
import fs from 'node:fs/promises';
|
|
3
2
|
import os from 'node:os';
|
|
4
3
|
import path from 'node:path';
|
|
@@ -6,7 +5,7 @@ import { AGENTS, agentById, agentCommandName } from './agent-data.js';
|
|
|
6
5
|
import { resolveAgent, runAgent } from './agents.js';
|
|
7
6
|
|
|
8
7
|
import { c } from './colors.js';
|
|
9
|
-
import {
|
|
8
|
+
import { runCommand } from './command-output.js';
|
|
10
9
|
|
|
11
10
|
const MAX_CANDIDATE_FILES = 160;
|
|
12
11
|
const MAX_READ_BYTES = 2 * 1024 * 1024;
|
|
@@ -231,14 +230,6 @@ function piMessages(records) {
|
|
|
231
230
|
});
|
|
232
231
|
}
|
|
233
232
|
|
|
234
|
-
function scMessages(records) {
|
|
235
|
-
return records.flatMap((record) => {
|
|
236
|
-
if (!['user', 'assistant'].includes(record.type)) return [];
|
|
237
|
-
const text = cleanText(record.text ?? record.content);
|
|
238
|
-
return text ? [{ role: record.type, text }] : [];
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
|
|
242
233
|
async function parseFileSession(entry, harness) {
|
|
243
234
|
const records = parseLines(await readBounded(entry.file, MAX_METADATA_BYTES));
|
|
244
235
|
if (!records.length) return null;
|
|
@@ -304,19 +295,6 @@ async function parseFileSession(entry, harness) {
|
|
|
304
295
|
});
|
|
305
296
|
}
|
|
306
297
|
|
|
307
|
-
if (harness === 'sc') {
|
|
308
|
-
const meta = records[0] || {};
|
|
309
|
-
const messages = scMessages(records);
|
|
310
|
-
const id = String(meta.id || filename).replace(/^session-/, '');
|
|
311
|
-
return sessionRecord(harness, id, {
|
|
312
|
-
title: messages.find((message) => message.role === 'user')?.text,
|
|
313
|
-
cwd: meta.cwd,
|
|
314
|
-
model: meta.model,
|
|
315
|
-
updated: entry.updated,
|
|
316
|
-
sourcePath: entry.file,
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
|
|
320
298
|
return null;
|
|
321
299
|
}
|
|
322
300
|
|
|
@@ -420,12 +398,11 @@ async function discoverCodexIndex(root, indexFile, max) {
|
|
|
420
398
|
);
|
|
421
399
|
}
|
|
422
400
|
|
|
423
|
-
function commandResult(execute, command, args, options = {}) {
|
|
424
|
-
const result = execute(command, args, {
|
|
425
|
-
|
|
426
|
-
|
|
401
|
+
async function commandResult(execute, command, args, options = {}) {
|
|
402
|
+
const result = await execute(command, args, {
|
|
403
|
+
timeout: options.timeout,
|
|
404
|
+
signal: options.signal,
|
|
427
405
|
env: { ...process.env, NO_COLOR: '1' },
|
|
428
|
-
maxBuffer: 4 * 1024 * 1024,
|
|
429
406
|
});
|
|
430
407
|
if (result.error || result.status !== 0) return '';
|
|
431
408
|
return String(result.stdout || '').trim();
|
|
@@ -443,18 +420,18 @@ function sqlString(value) {
|
|
|
443
420
|
return `'${String(value).replaceAll("'", "''")}'`;
|
|
444
421
|
}
|
|
445
422
|
|
|
446
|
-
function discoverOpenCodeSessions(execute, max) {
|
|
423
|
+
async function discoverOpenCodeSessions(execute, max, options = {}) {
|
|
447
424
|
const query = [
|
|
448
425
|
'select id, title, directory, time_created, time_updated, model',
|
|
449
426
|
'from session where time_archived is null',
|
|
450
427
|
`order by time_updated desc limit ${Math.max(1, Math.min(500, max))}`,
|
|
451
428
|
].join(' ');
|
|
452
|
-
const output = commandResult(
|
|
453
|
-
|
|
454
|
-
'
|
|
455
|
-
'json',
|
|
456
|
-
|
|
457
|
-
|
|
429
|
+
const output = await commandResult(
|
|
430
|
+
execute,
|
|
431
|
+
'opencode',
|
|
432
|
+
['db', '--format', 'json', query],
|
|
433
|
+
options,
|
|
434
|
+
);
|
|
458
435
|
if (!output) return [];
|
|
459
436
|
try {
|
|
460
437
|
return JSON.parse(output).map((record) =>
|
|
@@ -473,14 +450,11 @@ function discoverOpenCodeSessions(execute, max) {
|
|
|
473
450
|
export async function discoverSessions(options = {}) {
|
|
474
451
|
const home = options.home || os.homedir();
|
|
475
452
|
const max = options.max || 500;
|
|
476
|
-
const execute =
|
|
477
|
-
options.execute ||
|
|
478
|
-
(process.platform === 'win32' ? spawnWindowsSync : spawnSync);
|
|
453
|
+
const execute = options.execute || runCommand;
|
|
479
454
|
const roots = options.roots || {
|
|
480
455
|
claude: path.join(home, '.claude', 'projects'),
|
|
481
456
|
codex: path.join(home, '.codex', 'sessions'),
|
|
482
457
|
pi: path.join(home, '.pi', 'agent', 'sessions'),
|
|
483
|
-
sc: path.join(home, '.sc', 'sessions'),
|
|
484
458
|
};
|
|
485
459
|
const indexes =
|
|
486
460
|
options.indexes ||
|
|
@@ -498,9 +472,11 @@ export async function discoverSessions(options = {}) {
|
|
|
498
472
|
const groups = await Promise.all([
|
|
499
473
|
claude || discoverFileSessions(roots.claude, 'claude', max),
|
|
500
474
|
codex || discoverFileSessions(roots.codex, 'codex', max),
|
|
501
|
-
|
|
475
|
+
discoverOpenCodeSessions(execute, max, {
|
|
476
|
+
timeout: options.commandTimeoutMs,
|
|
477
|
+
signal: options.signal,
|
|
478
|
+
}),
|
|
502
479
|
discoverFileSessions(roots.pi, 'pi', max),
|
|
503
|
-
discoverFileSessions(roots.sc, 'sc', max),
|
|
504
480
|
]);
|
|
505
481
|
const seen = new Set();
|
|
506
482
|
return groups
|
|
@@ -523,7 +499,7 @@ async function openCodeMessages(session, execute) {
|
|
|
523
499
|
"and json_extract(part.data, '$.type') = 'text'",
|
|
524
500
|
'order by message.time_created asc, part.time_created asc',
|
|
525
501
|
].join(' ');
|
|
526
|
-
const output = commandResult(execute, 'opencode', [
|
|
502
|
+
const output = await commandResult(execute, 'opencode', [
|
|
527
503
|
'db',
|
|
528
504
|
'--format',
|
|
529
505
|
'json',
|
|
@@ -544,18 +520,13 @@ async function openCodeMessages(session, execute) {
|
|
|
544
520
|
|
|
545
521
|
export async function readSessionMessages(session, options = {}) {
|
|
546
522
|
if (session.harness === 'opencode') {
|
|
547
|
-
return openCodeMessages(
|
|
548
|
-
session,
|
|
549
|
-
options.execute ||
|
|
550
|
-
(process.platform === 'win32' ? spawnWindowsSync : spawnSync),
|
|
551
|
-
);
|
|
523
|
+
return openCodeMessages(session, options.execute || runCommand);
|
|
552
524
|
}
|
|
553
525
|
if (!session.sourcePath) return [];
|
|
554
526
|
const records = parseLines(await readBounded(session.sourcePath));
|
|
555
527
|
if (session.harness === 'claude') return claudeMessages(records);
|
|
556
528
|
if (session.harness === 'codex') return codexMessages(records);
|
|
557
529
|
if (session.harness === 'pi') return piMessages(records);
|
|
558
|
-
if (session.harness === 'sc') return scMessages(records);
|
|
559
530
|
return [];
|
|
560
531
|
}
|
|
561
532
|
|
|
@@ -695,8 +666,7 @@ export async function sessionsCommand(argv, options = {}) {
|
|
|
695
666
|
const harnessIndex = argv.indexOf('--harness');
|
|
696
667
|
const requestedHarness =
|
|
697
668
|
harnessIndex >= 0 ? argv[harnessIndex + 1] : session.harness;
|
|
698
|
-
const targetHarness =
|
|
699
|
-
requestedHarness === 'marathon' ? 'sc' : requestedHarness;
|
|
669
|
+
const targetHarness = requestedHarness;
|
|
700
670
|
const target = SESSION_HARNESSES[targetHarness];
|
|
701
671
|
if (!target) throw new Error(`Unknown destination harness: ${targetHarness}`);
|
|
702
672
|
|
package/bin/tui.js
CHANGED
|
@@ -411,6 +411,7 @@ function spawnAndWait(command, args, options = {}) {
|
|
|
411
411
|
stdio: options.stdio ?? 'inherit',
|
|
412
412
|
});
|
|
413
413
|
child.once('error', reject);
|
|
414
|
+
options.onSpawn?.();
|
|
414
415
|
child.once('exit', (code, signal) => {
|
|
415
416
|
if (signal) {
|
|
416
417
|
reject(new Error(`Subconscious TUI exited with signal ${signal}`));
|
|
@@ -458,13 +459,17 @@ async function runTuiOnce(options) {
|
|
|
458
459
|
}
|
|
459
460
|
};
|
|
460
461
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
462
|
+
// Remote work starts only once the TUI process exists, so nothing it does
|
|
463
|
+
// (a slow gateway, a stuck session probe) can delay the first frame.
|
|
464
|
+
let remote = Promise.resolve();
|
|
465
|
+
const startRemote = () => {
|
|
466
|
+
if (providedState) return;
|
|
467
|
+
remote = loadRemoteTuiUpdates(state, {
|
|
468
|
+
...options,
|
|
469
|
+
signal: controller.signal,
|
|
470
|
+
writePatch,
|
|
471
|
+
});
|
|
472
|
+
};
|
|
468
473
|
|
|
469
474
|
try {
|
|
470
475
|
// This state intentionally contains only display data. API keys are used
|
|
@@ -483,7 +488,12 @@ async function runTuiOnce(options) {
|
|
|
483
488
|
'--updates',
|
|
484
489
|
updatesPath,
|
|
485
490
|
],
|
|
486
|
-
{
|
|
491
|
+
{
|
|
492
|
+
cwd: executable.cwd,
|
|
493
|
+
spawn: options.spawn,
|
|
494
|
+
stdio: options.stdio,
|
|
495
|
+
onSpawn: startRemote,
|
|
496
|
+
},
|
|
487
497
|
);
|
|
488
498
|
controller.abort();
|
|
489
499
|
await remote.catch(() => {});
|
package/bin/update-check.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
2
3
|
import fs from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
3
5
|
import readline from 'node:readline';
|
|
4
6
|
import { fileURLToPath } from 'node:url';
|
|
5
7
|
import { LOGO_ART_SMALL_LINES } from './branding.js';
|
|
@@ -8,6 +10,9 @@ import { spawnWindows } from './windows/process.js';
|
|
|
8
10
|
|
|
9
11
|
export const PACKAGE_NAME = 'subconscious-cli';
|
|
10
12
|
export const UPDATE_CHECK_TIMEOUT_MS = 1500;
|
|
13
|
+
export const INSTALL_SCRIPT_URL =
|
|
14
|
+
'https://raw.githubusercontent.com/subconscious-systems/subconscious/main/scripts/install.sh';
|
|
15
|
+
|
|
11
16
|
const UPDATE_ACTIONS = ['Update now', 'Skip for now'];
|
|
12
17
|
const UPDATE_LOGO = LOGO_ART_SMALL_LINES;
|
|
13
18
|
|
|
@@ -18,10 +23,35 @@ function shellQuote(value) {
|
|
|
18
23
|
: `'${text.replaceAll("'", `'"'"'`)}'`;
|
|
19
24
|
}
|
|
20
25
|
|
|
26
|
+
/** The record scripts/install.sh leaves in the package it installed. */
|
|
27
|
+
function readCurlInstall(packageDir) {
|
|
28
|
+
try {
|
|
29
|
+
const record = JSON.parse(
|
|
30
|
+
readFileSync(path.join(packageDir, '.subc-install.json'), 'utf-8'),
|
|
31
|
+
);
|
|
32
|
+
return record?.method === 'curl' && typeof record.bin_dir === 'string'
|
|
33
|
+
? record
|
|
34
|
+
: null;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
21
40
|
export function detectInstallTarget(
|
|
22
41
|
here = fileURLToPath(import.meta.url),
|
|
23
42
|
platform = process.platform,
|
|
24
43
|
) {
|
|
44
|
+
const packageDir = path.resolve(path.dirname(here), '..');
|
|
45
|
+
const curl = platform !== 'win32' && readCurlInstall(packageDir);
|
|
46
|
+
if (curl) {
|
|
47
|
+
// Rerun the installer into the same directories it used before.
|
|
48
|
+
const display = `curl -fsSL ${INSTALL_SCRIPT_URL} | SUBC_INSTALL_DIR=${shellQuote(packageDir)} SUBC_BIN_DIR=${shellQuote(curl.bin_dir)} bash`;
|
|
49
|
+
return {
|
|
50
|
+
command: 'bash',
|
|
51
|
+
args: ['-c', `set -o pipefail; ${display}`],
|
|
52
|
+
display,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
25
55
|
const normalized = here.replace(/\\/g, '/');
|
|
26
56
|
if (normalized.includes('/.pnpm/') || normalized.includes('/pnpm/global/')) {
|
|
27
57
|
return {
|
package/bin/upgrade.js
CHANGED
|
@@ -85,16 +85,16 @@ function askYesNo(question) {
|
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
function runInstall(
|
|
88
|
+
function runInstall() {
|
|
89
|
+
const target = detectInstallTarget();
|
|
89
90
|
if (process.platform === 'win32') {
|
|
90
|
-
const target = detectInstallTarget();
|
|
91
91
|
return runWindows(target.command, target.args).then(
|
|
92
92
|
(code) => code === 0,
|
|
93
93
|
() => false,
|
|
94
94
|
);
|
|
95
95
|
}
|
|
96
96
|
return new Promise((resolve) => {
|
|
97
|
-
const child = spawn(command, {
|
|
97
|
+
const child = spawn(target.command, target.args, { stdio: 'inherit' });
|
|
98
98
|
child.on('error', () => resolve(false));
|
|
99
99
|
child.on('exit', (code) => resolve(code === 0));
|
|
100
100
|
});
|
package/bin/windows/agents.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import os from 'node:os';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
agentBinary,
|
|
5
|
+
agentCommandName,
|
|
6
|
+
agentInstallDirs,
|
|
7
|
+
installAdvice,
|
|
8
|
+
} from '../agent-data.js';
|
|
5
9
|
import { separatorIndex } from '../headless-args.js';
|
|
6
10
|
import { parseOptions } from './common.js';
|
|
7
|
-
import { installWindowsAgent, windowsInstallSpec } from './install.js';
|
|
8
11
|
import { executeWindowsLaunch, windowsLaunch } from './launch.js';
|
|
9
12
|
import {
|
|
10
13
|
readWindowsVersion,
|
|
@@ -16,21 +19,6 @@ import {
|
|
|
16
19
|
} from './process.js';
|
|
17
20
|
import { windowsSetup } from './setup.js';
|
|
18
21
|
|
|
19
|
-
const askInstall = (name) =>
|
|
20
|
-
new Promise((resolve) => {
|
|
21
|
-
const rl = readline.createInterface({
|
|
22
|
-
input: process.stdin,
|
|
23
|
-
output: process.stdout,
|
|
24
|
-
});
|
|
25
|
-
rl.question(
|
|
26
|
-
` ${name} isn't installed. Install it now? [Y/n] `,
|
|
27
|
-
(answer) => {
|
|
28
|
-
rl.close();
|
|
29
|
-
resolve(['', 'y', 'yes'].includes(answer.trim().toLowerCase()));
|
|
30
|
-
},
|
|
31
|
-
);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
22
|
export async function runWindowsAgent(agent, argv, dependencies) {
|
|
35
23
|
const {
|
|
36
24
|
profile,
|
|
@@ -54,10 +42,6 @@ export async function runWindowsAgent(agent, argv, dependencies) {
|
|
|
54
42
|
...(environment.PATH || '').split(';'),
|
|
55
43
|
...windowsBinDirs(environment),
|
|
56
44
|
]);
|
|
57
|
-
if (agent.id === 'subconscious-code' && parsed.action === 'install') {
|
|
58
|
-
if (args.length) throw new Error('Usage: subc marathon install');
|
|
59
|
-
return finish(await installWindowsAgent(agent.id, environment));
|
|
60
|
-
}
|
|
61
45
|
if (['status', 'uninstall'].includes(parsed.action)) {
|
|
62
46
|
return finish(
|
|
63
47
|
await windowsSetup(agent.id, parsed.action, args, environment),
|
|
@@ -110,31 +94,14 @@ export async function runWindowsAgent(agent, argv, dependencies) {
|
|
|
110
94
|
preferredDirs,
|
|
111
95
|
});
|
|
112
96
|
if (!executable) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
)
|
|
121
|
-
console.error(
|
|
122
|
-
`${agent.name} isn't installed. ${installer ? `Install it with: ${installer.display}` : 'Install it separately, then rerun subc.'}`,
|
|
123
|
-
);
|
|
124
|
-
return finish(127);
|
|
125
|
-
}
|
|
126
|
-
const installed = await installWindowsAgent(agent.id, environment);
|
|
127
|
-
if (installed) return finish(installed);
|
|
128
|
-
executable = resolveWindowsExecutable(bin, {
|
|
129
|
-
env: environment,
|
|
130
|
-
preferredDirs,
|
|
131
|
-
});
|
|
132
|
-
if (!executable) {
|
|
133
|
-
console.error(
|
|
134
|
-
`Installed ${agent.name}, but ${bin} was not found. Add its installation directory to PATH or restart your terminal.`,
|
|
135
|
-
);
|
|
136
|
-
return finish(127);
|
|
137
|
-
}
|
|
97
|
+
// subc never installs a third-party agent; it only says how.
|
|
98
|
+
const { command, url } = installAdvice(agent, 'win32');
|
|
99
|
+
console.error(
|
|
100
|
+
`${agent.name} isn't installed. subc doesn't install it. Install it yourself, then rerun subc ${agentCommandName(agent)}.`,
|
|
101
|
+
);
|
|
102
|
+
if (command) console.error(` Install it with: ${command}`);
|
|
103
|
+
console.error(` Official install page: ${url}`);
|
|
104
|
+
return finish(127);
|
|
138
105
|
}
|
|
139
106
|
if (agent.id === 'claude-code') {
|
|
140
107
|
const version = dependencies.parseClaudeVersion(
|
package/bin/windows/launch.js
CHANGED
|
@@ -14,7 +14,7 @@ import { modelIds, positiveInteger } from '../launch-values.js';
|
|
|
14
14
|
import { modelSupportsVision } from '../model-capabilities.js';
|
|
15
15
|
import { defaults, origin, value, writeJson } from './common.js';
|
|
16
16
|
|
|
17
|
-
const PLANNED = new Set(['claude-code', '
|
|
17
|
+
const PLANNED = new Set(['claude-code', 'pi', 'opencode']);
|
|
18
18
|
|
|
19
19
|
// Windows trims a configured gateway to its origin and gives every agent but
|
|
20
20
|
// Claude the gateway and key as SUBCONSCIOUS_*. Claude has always been given
|
package/bin/windows/process.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Windows process handling. Unix callers keep using their existing launch paths.
|
|
2
2
|
|
|
3
|
-
import { execFileSync, spawn
|
|
3
|
+
import { execFileSync, spawn } from 'node:child_process';
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import os from 'node:os';
|
|
6
6
|
import path from 'node:path';
|
|
@@ -189,23 +189,6 @@ export function spawnWindows(command, args, options = {}) {
|
|
|
189
189
|
});
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
export function spawnWindowsSync(command, args, options = {}) {
|
|
193
|
-
try {
|
|
194
|
-
const invocation = windowsInvocation(
|
|
195
|
-
command,
|
|
196
|
-
args,
|
|
197
|
-
options.env || process.env,
|
|
198
|
-
);
|
|
199
|
-
return spawnSync(invocation.command, invocation.args, {
|
|
200
|
-
...options,
|
|
201
|
-
env: invocation.env,
|
|
202
|
-
shell: false,
|
|
203
|
-
});
|
|
204
|
-
} catch (error) {
|
|
205
|
-
return { error, status: null, stdout: '', stderr: '' };
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
192
|
export function runWindows(command, args, options = {}) {
|
|
210
193
|
const { input, ...spawnOptions } = options;
|
|
211
194
|
return new Promise((resolve, reject) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "subconscious-cli",
|
|
3
|
-
"version": "6.1
|
|
3
|
+
"version": "6.2.1",
|
|
4
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"
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"build:tui": "node scripts/build-tui.js",
|
|
10
10
|
"build:tui:host": "node scripts/build-tui.js --host",
|
|
11
11
|
"test": "node --test",
|
|
12
|
-
"test:windows": "node --test test/windows.test.js test/models.test.js test/model-capabilities.test.js test/auth.test.js test/tui.test.js test/update-check.test.js test/sessions.test.js test/branding.test.js test/claude-version.test.js test/usage.test.js test/feedback.test.js test/release.test.js test/github-govuln-issue.test.js test/harness-manifest.test.js test/agent-files.test.js test/agent-launch.test.js",
|
|
12
|
+
"test:windows": "node --test test/windows.test.js test/models.test.js test/model-capabilities.test.js test/auth.test.js test/tui.test.js test/update-check.test.js test/sessions.test.js test/command-output.test.js test/branding.test.js test/claude-version.test.js test/usage.test.js test/feedback.test.js test/release.test.js test/github-govuln-issue.test.js test/harness-manifest.test.js test/agent-files.test.js test/agent-launch.test.js test/agent-install-policy.test.js",
|
|
13
13
|
"test:tui": "go -C tui test ./...",
|
|
14
14
|
"lint": "biome ci .",
|
|
15
15
|
"format": "biome check --write .",
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
"authentication",
|
|
38
38
|
"profiles",
|
|
39
39
|
"coding-agent",
|
|
40
|
-
"subconscious-code",
|
|
41
40
|
"claude-code",
|
|
42
41
|
"opencode",
|
|
43
42
|
"codex",
|