subconscious-cli 6.0.1 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +167 -43
- package/bin/agent-data.js +278 -0
- package/bin/agent-help.js +114 -0
- package/bin/agent-install.js +238 -0
- package/bin/agent-launch.js +199 -0
- package/bin/agent-spawn.js +137 -0
- package/bin/agents.js +236 -931
- package/bin/auth.js +9 -1
- package/bin/claude-picker.js +143 -0
- package/bin/cli.js +62 -2
- 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 +25 -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 +77 -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 +462 -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 +186 -0
- package/bin/runbook/copilot/install.sh +45 -63
- package/bin/runbook/cursor/agent.json +138 -0
- package/bin/runbook/cursor/install.sh +8 -35
- package/bin/runbook/deepseek-harness/agent.json +164 -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 +159 -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 +217 -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 +57 -0
- package/bin/sessions.js +53 -48
- package/bin/tui.js +13 -0
- package/bin/update-check.js +35 -1
- package/bin/upgrade.js +27 -34
- package/bin/usage.js +21 -10
- package/bin/windows/agents.js +28 -60
- package/bin/windows/common.js +2 -28
- 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 -4
- 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/install.sh +0 -154
- package/bin/runbook/subconscious-code/run.sh +0 -21
- package/bin/windows/claude.js +0 -100
- package/bin/windows/install.js +0 -188
package/bin/windows/launch.js
CHANGED
|
@@ -2,256 +2,277 @@
|
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import {
|
|
6
|
-
import { buildOpenCodeConfig } from '../opencode-provider.js';
|
|
7
|
-
import { claudeNativeLaunch } from './claude.js';
|
|
5
|
+
import { agentById, agentKeyName } from '../agent-data.js';
|
|
8
6
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} from '
|
|
7
|
+
launchPlan,
|
|
8
|
+
resolveAgentEnv,
|
|
9
|
+
resolveInputs,
|
|
10
|
+
takeFlags,
|
|
11
|
+
} from '../agent-launch.js';
|
|
12
|
+
import { claudePickerSettings } from '../claude-picker.js';
|
|
13
|
+
import { modelIds, positiveInteger } from '../launch-values.js';
|
|
14
|
+
import { modelSupportsVision } from '../model-capabilities.js';
|
|
15
|
+
import { defaults, origin, value, writeJson } from './common.js';
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
const PLANNED = new Set(['claude-code', 'pi', 'opencode']);
|
|
18
|
+
|
|
19
|
+
// Windows trims a configured gateway to its origin and gives every agent but
|
|
20
|
+
// Claude the gateway and key as SUBCONSCIOUS_*. Claude has always been given
|
|
21
|
+
// the gateway as configured.
|
|
22
|
+
function windowsEnv(id, env) {
|
|
23
|
+
const model = value(env, 'MODEL', defaults.model);
|
|
24
|
+
const gateway = value(env, 'GATEWAY_URL', defaults.baseUrl);
|
|
25
|
+
if (id === 'claude-code')
|
|
26
|
+
return { ...env, MODEL: model, GATEWAY_URL: gateway };
|
|
27
|
+
const keyName = agentKeyName(agentById(id));
|
|
19
28
|
return {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
29
|
+
...env,
|
|
30
|
+
MODEL: model,
|
|
31
|
+
GATEWAY_URL: origin(gateway),
|
|
32
|
+
SUBCONSCIOUS_API_KEY: value(env, keyName, value(env, 'API_KEY')),
|
|
33
|
+
SUBCONSCIOUS_GATEWAY_URL: origin(gateway),
|
|
23
34
|
};
|
|
24
35
|
}
|
|
25
36
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
37
|
+
function claudeLaunch(agent, argv, env) {
|
|
38
|
+
const settings =
|
|
39
|
+
value(env, 'SUBC_CLAUDE_SETTINGS') ||
|
|
40
|
+
JSON.stringify(claudePickerSettings([env.MODEL], env.MODEL));
|
|
41
|
+
const plan = launchPlan(agent, {
|
|
42
|
+
env: { ...env, SUBC_CLAUDE_SETTINGS: settings },
|
|
43
|
+
args: argv,
|
|
44
|
+
});
|
|
45
|
+
if (!plan.env.ANTHROPIC_BASE_URL || !plan.env.ANTHROPIC_AUTH_TOKEN) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
'GATEWAY_URL and API_KEY are required to launch Claude Code',
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
positiveInteger(plan.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW, 'compact-window');
|
|
51
|
+
positiveInteger(
|
|
52
|
+
plan.env.CLAUDE_CODE_MAX_CONTEXT_TOKENS,
|
|
53
|
+
'max-context-tokens',
|
|
54
|
+
);
|
|
55
|
+
return plan;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function plannedLaunch(agent, argv, env) {
|
|
59
|
+
const plan =
|
|
60
|
+
agent.id === 'claude-code'
|
|
61
|
+
? claudeLaunch(agent, argv, env)
|
|
62
|
+
: launchPlan(agent, { env, args: argv });
|
|
63
|
+
return { command: plan.argv[0], args: plan.argv.slice(1), env: plan.env };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function codexCatalog(env, context, maxContext, compact) {
|
|
67
|
+
return {
|
|
68
|
+
models: modelIds(env).map((id) => ({
|
|
69
|
+
slug: id,
|
|
70
|
+
display_name: id,
|
|
71
|
+
description: `Subconscious model ${id}`,
|
|
72
|
+
context_window: context,
|
|
73
|
+
max_context_window: maxContext,
|
|
74
|
+
auto_compact_token_limit: compact,
|
|
75
|
+
effective_context_window_percent: 95,
|
|
76
|
+
supported_reasoning_levels: [],
|
|
77
|
+
shell_type: 'shell_command',
|
|
78
|
+
visibility: 'list',
|
|
79
|
+
supported_in_api: true,
|
|
80
|
+
priority: 0,
|
|
81
|
+
service_tiers: [
|
|
82
|
+
{
|
|
83
|
+
id: 'priority',
|
|
84
|
+
name: 'Priority',
|
|
85
|
+
description:
|
|
86
|
+
'Route requests through the configured priority service tier',
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
availability_nux: null,
|
|
90
|
+
upgrade: null,
|
|
91
|
+
base_instructions: 'You are Codex, a coding agent.',
|
|
92
|
+
supports_reasoning_summaries: false,
|
|
93
|
+
support_verbosity: false,
|
|
94
|
+
default_verbosity: null,
|
|
95
|
+
apply_patch_tool_type: 'freeform',
|
|
96
|
+
truncation_policy: { mode: 'tokens', limit: 10000 },
|
|
97
|
+
supports_parallel_tool_calls: true,
|
|
98
|
+
experimental_supported_tools: [],
|
|
99
|
+
// Codex assumes ['text', 'image'] when the field is missing.
|
|
100
|
+
input_modalities: modelSupportsVision(id) ? ['text', 'image'] : ['text'],
|
|
101
|
+
})),
|
|
46
102
|
};
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// --subagents is Windows-only: it runs a pinned older Codex instead.
|
|
106
|
+
function splitSubagents(argv) {
|
|
107
|
+
const boundary = argv.indexOf('--');
|
|
108
|
+
const head = boundary < 0 ? argv : argv.slice(0, boundary);
|
|
109
|
+
const tail = boundary < 0 ? [] : argv.slice(boundary);
|
|
110
|
+
for (const arg of head)
|
|
111
|
+
if (arg.startsWith('--subagents='))
|
|
112
|
+
throw new Error('--subagents does not take a value');
|
|
113
|
+
return {
|
|
114
|
+
subagents: head.includes('--subagents'),
|
|
115
|
+
words: [...head.filter((arg) => arg !== '--subagents'), ...tail],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function codexConfig(env, file) {
|
|
120
|
+
const config = {
|
|
121
|
+
model: env.MODEL,
|
|
122
|
+
model_provider: 'subconscious',
|
|
123
|
+
model_catalog_json: file,
|
|
124
|
+
model_reasoning_effort: env.CODEX_REASONING_EFFORT,
|
|
125
|
+
web_search: 'disabled',
|
|
126
|
+
'model_providers.subconscious.name': 'Subconscious',
|
|
127
|
+
'model_providers.subconscious.base_url': `${env.GATEWAY_URL}/v1`,
|
|
128
|
+
'model_providers.subconscious.wire_api': 'responses',
|
|
129
|
+
'model_providers.subconscious.env_key': 'SUBCONSCIOUS_API_KEY',
|
|
130
|
+
'model_providers.subconscious.stream_idle_timeout_ms': Number(
|
|
131
|
+
env.CODEX_STREAM_IDLE_TIMEOUT_MS,
|
|
132
|
+
),
|
|
133
|
+
};
|
|
134
|
+
if (env.CODEX_EXTERNAL_TOOLS !== 'true') {
|
|
135
|
+
Object.assign(config, {
|
|
136
|
+
'features.apps': false,
|
|
137
|
+
'features.plugins': false,
|
|
138
|
+
'apps._default.enabled': false,
|
|
139
|
+
});
|
|
60
140
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
'
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
141
|
+
return config;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function codexLaunch(agent, argv, env, tempRoot) {
|
|
145
|
+
const { subagents, words } = splitSubagents(argv);
|
|
146
|
+
// Windows Codex sets no subagent effort, and uses the subagent cap only
|
|
147
|
+
// with --subagents; otherwise those flags still reach Codex unchanged.
|
|
148
|
+
const { values, rest } = takeFlags(agent, words, {
|
|
149
|
+
skip: [
|
|
150
|
+
'CODEX_SUBAGENT_REASONING_EFFORT',
|
|
151
|
+
...(subagents ? [] : ['MAX_CONCURRENT_SUBAGENTS']),
|
|
152
|
+
],
|
|
153
|
+
});
|
|
154
|
+
const resolved = resolveAgentEnv(agent, resolveInputs(agent, env, values));
|
|
155
|
+
const context = positiveInteger(
|
|
156
|
+
resolved.CODEX_CONTEXT_WINDOW,
|
|
157
|
+
'context-window',
|
|
158
|
+
);
|
|
159
|
+
const maxContext = positiveInteger(
|
|
160
|
+
resolved.CODEX_MAX_CONTEXT_WINDOW,
|
|
161
|
+
'max-context-window',
|
|
162
|
+
);
|
|
163
|
+
const compact = positiveInteger(
|
|
164
|
+
resolved.CODEX_AUTO_COMPACT_TOKEN_LIMIT,
|
|
165
|
+
'auto-compact-token-limit',
|
|
166
|
+
);
|
|
167
|
+
const catalog = codexCatalog(resolved, context, maxContext, compact);
|
|
168
|
+
// Validate all flags before creating a temporary directory.
|
|
169
|
+
positiveInteger(resolved.CODEX_STREAM_IDLE_TIMEOUT_MS, 'stream-idle-timeout');
|
|
170
|
+
const threads = positiveInteger(
|
|
171
|
+
resolved.MAX_CONCURRENT_SUBAGENTS,
|
|
172
|
+
'MAX_CONCURRENT_SUBAGENTS',
|
|
173
|
+
);
|
|
174
|
+
const dir = await fs.mkdtemp(path.join(tempRoot, 'subc-codex-'));
|
|
175
|
+
const cleanup = () => fs.rm(dir, { recursive: true, force: true });
|
|
176
|
+
try {
|
|
177
|
+
const file = path.join(dir, 'models.json');
|
|
178
|
+
await writeJson(file, catalog);
|
|
179
|
+
const config = codexConfig(resolved, file);
|
|
180
|
+
if (subagents)
|
|
181
|
+
Object.assign(config, {
|
|
182
|
+
'features.multi_agent': true,
|
|
183
|
+
'agents.max_threads': threads,
|
|
184
|
+
'agents.max_depth': 1,
|
|
185
|
+
'agents.interrupt_message': true,
|
|
186
|
+
});
|
|
187
|
+
const args = Object.entries(config).flatMap(([k, v]) => [
|
|
188
|
+
'-c',
|
|
189
|
+
`${k}=${JSON.stringify(v)}`,
|
|
190
|
+
]);
|
|
85
191
|
return {
|
|
86
|
-
command: '
|
|
87
|
-
args:
|
|
88
|
-
|
|
192
|
+
command: subagents ? 'npx' : 'codex',
|
|
193
|
+
args: [
|
|
194
|
+
...(subagents ? ['-y', '@openai/codex@0.132.0'] : []),
|
|
195
|
+
...args,
|
|
196
|
+
...rest,
|
|
197
|
+
],
|
|
198
|
+
env: resolved,
|
|
199
|
+
cleanup,
|
|
89
200
|
};
|
|
201
|
+
} catch (error) {
|
|
202
|
+
await cleanup();
|
|
203
|
+
throw error;
|
|
90
204
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function dshOverlay(env, context, maxTokens) {
|
|
208
|
+
const models = modelIds(env)
|
|
209
|
+
.map(
|
|
210
|
+
(id) =>
|
|
211
|
+
` - id: '${id}'\n name: '${id}'\n${modelSupportsVision(id) ? ' input: [text, image]\n' : ''} contextWindow: ${context}\n maxTokens: ${maxTokens}`,
|
|
212
|
+
)
|
|
213
|
+
.join('\n');
|
|
214
|
+
return `- id: llm-pi-ai\n config:\n providers:\n subconscious:\n apiKeyEnv: SUBCONSCIOUS_API_KEY\n displayName: Subconscious Gateway\n api: openai-completions\n baseURL: !!js process.env.SUBCONSCIOUS_DSH_BASE_URL\n headers:\n x-subconscious-client: deepseek-harness\n compat:\n supportsDeveloperRole: false\n maxTokensField: max_tokens\n defaultContextWindow: ${context}\n defaultMaxTokens: ${maxTokens}\n models:\n${models}\n- id: agent-default-model\n config:\n provider: subconscious\n model: '${env.MODEL}'\n`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function dshLaunch(agent, argv, env, tempRoot) {
|
|
218
|
+
const headless = argv[0] === 'headless';
|
|
219
|
+
const plan = launchPlan(agent, {
|
|
220
|
+
env,
|
|
221
|
+
args: headless ? argv.slice(2) : argv,
|
|
222
|
+
prompt: headless ? argv[1] : undefined,
|
|
223
|
+
});
|
|
224
|
+
const context = positiveInteger(
|
|
225
|
+
plan.env.DEEPSEEK_HARNESS_CONTEXT_WINDOW,
|
|
226
|
+
'DEEPSEEK_HARNESS_CONTEXT_WINDOW',
|
|
227
|
+
);
|
|
228
|
+
const maxTokens = positiveInteger(
|
|
229
|
+
plan.env.DEEPSEEK_HARNESS_MAX_TOKENS,
|
|
230
|
+
'DEEPSEEK_HARNESS_MAX_TOKENS',
|
|
231
|
+
);
|
|
232
|
+
const text = dshOverlay(plan.env, context, maxTokens);
|
|
233
|
+
const dir = await fs.mkdtemp(path.join(tempRoot, 'subc-dsh-'));
|
|
234
|
+
const cleanup = () => fs.rm(dir, { recursive: true, force: true });
|
|
235
|
+
try {
|
|
236
|
+
const file = path.join(dir, 'subconscious.cordis.yml');
|
|
237
|
+
await fs.writeFile(file, text, { mode: 0o600, flag: 'wx' });
|
|
238
|
+
const argvWithFile = plan.argv.map((word, index) =>
|
|
239
|
+
index < plan.templateWords ? word.replaceAll('{tempFile}', file) : word,
|
|
113
240
|
);
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const catalog = {
|
|
121
|
-
models: modelIds(env).map((id) => ({
|
|
122
|
-
slug: id,
|
|
123
|
-
display_name: id,
|
|
124
|
-
description: `Subconscious model ${id}`,
|
|
125
|
-
context_window: context,
|
|
126
|
-
max_context_window: maxContext,
|
|
127
|
-
auto_compact_token_limit: compact,
|
|
128
|
-
effective_context_window_percent: 95,
|
|
129
|
-
supported_reasoning_levels: [],
|
|
130
|
-
shell_type: 'shell_command',
|
|
131
|
-
visibility: 'list',
|
|
132
|
-
supported_in_api: true,
|
|
133
|
-
priority: 0,
|
|
134
|
-
service_tiers: [
|
|
135
|
-
{
|
|
136
|
-
id: 'priority',
|
|
137
|
-
name: 'Priority',
|
|
138
|
-
description:
|
|
139
|
-
'Route requests through the configured priority service tier',
|
|
140
|
-
},
|
|
141
|
-
],
|
|
142
|
-
availability_nux: null,
|
|
143
|
-
upgrade: null,
|
|
144
|
-
base_instructions: 'You are Codex, a coding agent.',
|
|
145
|
-
supports_reasoning_summaries: false,
|
|
146
|
-
support_verbosity: false,
|
|
147
|
-
default_verbosity: null,
|
|
148
|
-
apply_patch_tool_type: 'freeform',
|
|
149
|
-
truncation_policy: { mode: 'tokens', limit: 10000 },
|
|
150
|
-
supports_parallel_tool_calls: true,
|
|
151
|
-
experimental_supported_tools: [],
|
|
152
|
-
...(modelSupportsVision(id)
|
|
153
|
-
? { input_modalities: ['text', 'image'] }
|
|
154
|
-
: {}),
|
|
155
|
-
})),
|
|
241
|
+
return {
|
|
242
|
+
command: argvWithFile[0],
|
|
243
|
+
args: argvWithFile.slice(1),
|
|
244
|
+
env: plan.env,
|
|
245
|
+
...(plan.input === undefined ? {} : { input: plan.input }),
|
|
246
|
+
cleanup,
|
|
156
247
|
};
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
'MAX_CONCURRENT_SUBAGENTS',
|
|
161
|
-
);
|
|
162
|
-
const dir = await fs.mkdtemp(path.join(tempRoot, 'subc-codex-'));
|
|
163
|
-
const cleanup = () => fs.rm(dir, { recursive: true, force: true });
|
|
164
|
-
try {
|
|
165
|
-
const file = path.join(dir, 'models.json');
|
|
166
|
-
await writeJson(file, catalog);
|
|
167
|
-
const config = {
|
|
168
|
-
model,
|
|
169
|
-
model_provider: 'subconscious',
|
|
170
|
-
model_catalog_json: file,
|
|
171
|
-
model_reasoning_effort: reasoning,
|
|
172
|
-
web_search: 'disabled',
|
|
173
|
-
'model_providers.subconscious.name': 'Subconscious',
|
|
174
|
-
'model_providers.subconscious.base_url': `${base}/v1`,
|
|
175
|
-
'model_providers.subconscious.wire_api': 'responses',
|
|
176
|
-
'model_providers.subconscious.env_key': 'SUBCONSCIOUS_API_KEY',
|
|
177
|
-
'model_providers.subconscious.stream_idle_timeout_ms': 300000,
|
|
178
|
-
};
|
|
179
|
-
if (
|
|
180
|
-
!opts['--external-tools'] &&
|
|
181
|
-
value(env, 'CODEX_EXTERNAL_TOOLS', 'false') !== 'true'
|
|
182
|
-
) {
|
|
183
|
-
Object.assign(config, {
|
|
184
|
-
'features.apps': false,
|
|
185
|
-
'features.plugins': false,
|
|
186
|
-
'apps._default.enabled': false,
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
if (opts['--subagents'])
|
|
190
|
-
Object.assign(config, {
|
|
191
|
-
'features.multi_agent': true,
|
|
192
|
-
'agents.max_threads': threads,
|
|
193
|
-
'agents.max_depth': 1,
|
|
194
|
-
'agents.interrupt_message': true,
|
|
195
|
-
});
|
|
196
|
-
const args = Object.entries(config).flatMap(([k, v]) => [
|
|
197
|
-
'-c',
|
|
198
|
-
`${k}=${JSON.stringify(v)}`,
|
|
199
|
-
]);
|
|
200
|
-
return {
|
|
201
|
-
command: opts['--subagents'] ? 'npx' : 'codex',
|
|
202
|
-
args: [
|
|
203
|
-
...(opts['--subagents'] ? ['-y', '@openai/codex@0.132.0'] : []),
|
|
204
|
-
...args,
|
|
205
|
-
...rest,
|
|
206
|
-
],
|
|
207
|
-
env: childEnv,
|
|
208
|
-
cleanup,
|
|
209
|
-
};
|
|
210
|
-
} catch (error) {
|
|
211
|
-
await cleanup();
|
|
212
|
-
throw error;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
if (id === 'deepseek-harness') {
|
|
216
|
-
const context = positiveInteger(
|
|
217
|
-
value(env, 'DEEPSEEK_HARNESS_CONTEXT_WINDOW', '5000000'),
|
|
218
|
-
'DEEPSEEK_HARNESS_CONTEXT_WINDOW',
|
|
219
|
-
);
|
|
220
|
-
const maxTokens = positiveInteger(
|
|
221
|
-
value(env, 'DEEPSEEK_HARNESS_MAX_TOKENS', '65536'),
|
|
222
|
-
'DEEPSEEK_HARNESS_MAX_TOKENS',
|
|
223
|
-
);
|
|
224
|
-
const models = modelIds(env);
|
|
225
|
-
const dir = await fs.mkdtemp(path.join(tempRoot, 'subc-dsh-'));
|
|
226
|
-
const cleanup = () => fs.rm(dir, { recursive: true, force: true });
|
|
227
|
-
try {
|
|
228
|
-
const file = path.join(dir, 'subconscious.cordis.yml');
|
|
229
|
-
const text = `- id: llm-pi-ai\n config:\n providers:\n subconscious:\n apiKeyEnv: SUBCONSCIOUS_API_KEY\n displayName: Subconscious Gateway\n api: openai-completions\n baseURL: !!js process.env.SUBCONSCIOUS_DSH_BASE_URL\n headers:\n x-subconscious-client: deepseek-harness\n compat:\n supportsDeveloperRole: false\n maxTokensField: max_tokens\n defaultContextWindow: ${context}\n defaultMaxTokens: ${maxTokens}\n models:\n${models.map((id) => ` - id: '${id}'\n name: '${id}'\n${modelSupportsVision(id) ? ' input: [text, image]\n' : ''} contextWindow: ${context}\n maxTokens: ${maxTokens}`).join('\n')}\n- id: agent-default-model\n config:\n provider: subconscious\n model: '${model}'\n`;
|
|
230
|
-
await fs.writeFile(file, text, { mode: 0o600, flag: 'wx' });
|
|
231
|
-
const mode = ['web', 'headless'].includes(argv[0]) ? argv[0] : 'web';
|
|
232
|
-
const rest = ['web', 'headless'].includes(argv[0]) ? argv.slice(1) : argv;
|
|
233
|
-
return {
|
|
234
|
-
command: 'dsh',
|
|
235
|
-
args: [
|
|
236
|
-
...(mode === 'web' ? ['web'] : ['--profile', 'headless']),
|
|
237
|
-
'--patch',
|
|
238
|
-
file,
|
|
239
|
-
...rest,
|
|
240
|
-
],
|
|
241
|
-
env: { ...childEnv, SUBCONSCIOUS_DSH_BASE_URL: `${base}/v1` },
|
|
242
|
-
cleanup,
|
|
243
|
-
};
|
|
244
|
-
} catch (error) {
|
|
245
|
-
await cleanup();
|
|
246
|
-
throw error;
|
|
247
|
-
}
|
|
248
|
+
} catch (error) {
|
|
249
|
+
await cleanup();
|
|
250
|
+
throw error;
|
|
248
251
|
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export async function windowsLaunch(
|
|
255
|
+
id,
|
|
256
|
+
argv,
|
|
257
|
+
env,
|
|
258
|
+
{ tempRoot = os.tmpdir() } = {},
|
|
259
|
+
) {
|
|
260
|
+
const agent = agentById(id);
|
|
261
|
+
const launchEnv = windowsEnv(id, env);
|
|
262
|
+
if (PLANNED.has(id)) return plannedLaunch(agent, argv, launchEnv);
|
|
263
|
+
if (id === 'codex') return codexLaunch(agent, argv, launchEnv, tempRoot);
|
|
264
|
+
if (id === 'deepseek-harness')
|
|
265
|
+
return dshLaunch(agent, argv, launchEnv, tempRoot);
|
|
249
266
|
throw new Error(`No native Windows launcher is available for ${id}`);
|
|
250
267
|
}
|
|
251
268
|
|
|
252
269
|
export async function executeWindowsLaunch(spec, run) {
|
|
253
270
|
try {
|
|
254
|
-
|
|
271
|
+
const options =
|
|
272
|
+
spec.input === undefined
|
|
273
|
+
? { env: spec.env }
|
|
274
|
+
: { env: spec.env, input: spec.input };
|
|
275
|
+
return await run(spec.command, spec.args, options);
|
|
255
276
|
} finally {
|
|
256
277
|
await spec.cleanup?.();
|
|
257
278
|
}
|
package/bin/windows/process.js
CHANGED
|
@@ -207,8 +207,19 @@ export function spawnWindowsSync(command, args, options = {}) {
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
export function runWindows(command, args, options = {}) {
|
|
210
|
+
const { input, ...spawnOptions } = options;
|
|
210
211
|
return new Promise((resolve, reject) => {
|
|
211
|
-
const child = spawnWindows(command, args, {
|
|
212
|
+
const child = spawnWindows(command, args, {
|
|
213
|
+
stdio: input === undefined ? 'inherit' : ['pipe', 'inherit', 'inherit'],
|
|
214
|
+
...spawnOptions,
|
|
215
|
+
});
|
|
216
|
+
if (input !== undefined) {
|
|
217
|
+
// EPIPE means the agent exited without reading; its exit code reports why.
|
|
218
|
+
child.stdin.on('error', (error) => {
|
|
219
|
+
if (error.code !== 'EPIPE') reject(error);
|
|
220
|
+
});
|
|
221
|
+
child.stdin.end(input);
|
|
222
|
+
}
|
|
212
223
|
const forward = (signal) => {
|
|
213
224
|
try {
|
|
214
225
|
child.kill(signal);
|
package/bin/windows/setup.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { agentById } from '../agent-data.js';
|
|
5
|
+
import { resolveInputs } from '../agent-launch.js';
|
|
4
6
|
import { modelSupportsVision } from '../model-capabilities.js';
|
|
5
7
|
import {
|
|
6
8
|
defaults,
|
|
@@ -118,10 +120,16 @@ export async function windowsSetup(
|
|
|
118
120
|
if (id === 'pi')
|
|
119
121
|
Object.assign(schema, { '--context-window': 1, '--max-tokens': 1 });
|
|
120
122
|
const { options } = parseOptions(argv, schema, { strict: true });
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
const agent = agentById(id);
|
|
124
|
+
const env = resolveInputs(
|
|
125
|
+
agent,
|
|
126
|
+
{
|
|
127
|
+
...environment,
|
|
128
|
+
...(options['--model'] ? { MODEL: options['--model'] } : {}),
|
|
129
|
+
},
|
|
130
|
+
{},
|
|
131
|
+
{ strict: false },
|
|
132
|
+
);
|
|
125
133
|
const gatewayUrl = origin(
|
|
126
134
|
options['--gateway-url'] || value(env, 'GATEWAY_URL', defaults.baseUrl),
|
|
127
135
|
);
|
|
@@ -179,12 +187,12 @@ export async function windowsSetup(
|
|
|
179
187
|
if (installing) {
|
|
180
188
|
const context = positiveInteger(
|
|
181
189
|
options['--max-input-tokens'] ||
|
|
182
|
-
value(env, 'COPILOT_MAX_INPUT_TOKENS'
|
|
190
|
+
value(env, 'COPILOT_MAX_INPUT_TOKENS'),
|
|
183
191
|
'max-input-tokens',
|
|
184
192
|
);
|
|
185
193
|
const maxTokens = positiveInteger(
|
|
186
194
|
options['--max-output-tokens'] ||
|
|
187
|
-
value(env, 'COPILOT_MAX_OUTPUT_TOKENS'
|
|
195
|
+
value(env, 'COPILOT_MAX_OUTPUT_TOKENS'),
|
|
188
196
|
'max-output-tokens',
|
|
189
197
|
);
|
|
190
198
|
providers.push({
|
|
@@ -262,15 +270,20 @@ export async function windowsSetup(
|
|
|
262
270
|
'extensions',
|
|
263
271
|
'subconscious-compaction.ts',
|
|
264
272
|
);
|
|
273
|
+
// Keeps requests at the newest 30 images; same files as the shell runbook.
|
|
274
|
+
const imageWindow = path.join(
|
|
275
|
+
dir,
|
|
276
|
+
'extensions',
|
|
277
|
+
'subconscious-image-window',
|
|
278
|
+
);
|
|
265
279
|
const config = path.join(dir, 'subconscious-windows.json');
|
|
266
280
|
if (installing) {
|
|
267
281
|
const context = positiveInteger(
|
|
268
|
-
options['--context-window'] ||
|
|
269
|
-
value(env, 'PI_CONTEXT_WINDOW', '5000000'),
|
|
282
|
+
options['--context-window'] || value(env, 'PI_CONTEXT_WINDOW'),
|
|
270
283
|
'context-window',
|
|
271
284
|
);
|
|
272
285
|
const maxTokens = positiveInteger(
|
|
273
|
-
options['--max-tokens'] || value(env, 'PI_MAX_TOKENS'
|
|
286
|
+
options['--max-tokens'] || value(env, 'PI_MAX_TOKENS'),
|
|
274
287
|
'max-tokens',
|
|
275
288
|
);
|
|
276
289
|
providers.subconscious = {
|
|
@@ -294,10 +307,17 @@ export async function windowsSetup(
|
|
|
294
307
|
new URL('./pi-compaction.ts', import.meta.url),
|
|
295
308
|
extension,
|
|
296
309
|
);
|
|
310
|
+
await fs.rm(imageWindow, { recursive: true, force: true });
|
|
311
|
+
await fs.cp(
|
|
312
|
+
new URL('../runbook/image-window', import.meta.url),
|
|
313
|
+
imageWindow,
|
|
314
|
+
{ recursive: true },
|
|
315
|
+
);
|
|
297
316
|
await writeJson(config, { gatewayUrl, apiKey });
|
|
298
317
|
} else {
|
|
299
318
|
delete providers.subconscious;
|
|
300
319
|
await fs.rm(extension, { force: true });
|
|
320
|
+
await fs.rm(imageWindow, { recursive: true, force: true });
|
|
301
321
|
await fs.rm(config, { force: true });
|
|
302
322
|
}
|
|
303
323
|
if (installing || (await exists(modelsFile)))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "subconscious-cli",
|
|
3
|
-
"version": "6.0
|
|
3
|
+
"version": "6.2.0",
|
|
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,9 +9,8 @@
|
|
|
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",
|
|
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 test/agent-install-policy.test.js",
|
|
13
13
|
"test:tui": "go -C tui test ./...",
|
|
14
|
-
"generate": "node scripts/generate-agents.js",
|
|
15
14
|
"lint": "biome ci .",
|
|
16
15
|
"format": "biome check --write .",
|
|
17
16
|
"typecheck": "tsc --noEmit",
|
|
@@ -38,7 +37,6 @@
|
|
|
38
37
|
"authentication",
|
|
39
38
|
"profiles",
|
|
40
39
|
"coding-agent",
|
|
41
|
-
"subconscious-code",
|
|
42
40
|
"claude-code",
|
|
43
41
|
"opencode",
|
|
44
42
|
"codex",
|