subconscious-cli 6.0.0 → 6.0.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 +16 -2
- package/bin/agents.js +210 -70
- package/bin/auth.js +80 -32
- package/bin/branding.js +3 -1
- package/bin/cli.js +28 -20
- package/bin/clipboard-image.js +22 -5
- package/bin/colors.js +1 -1
- package/bin/feedback.js +57 -18
- package/bin/model-capabilities.js +4 -1
- package/bin/models.js +22 -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/opencode-provider.js +27 -5
- package/bin/profiles.js +126 -44
- package/bin/registry.generated.json +1 -1
- package/bin/runbook/opencode/opencode-plugin.d.ts +9 -0
- package/bin/runbook/opencode/subconscious-compaction.ts +26 -26
- package/bin/runbook/pi/subconscious-compaction.ts +69 -49
- package/bin/sessions.js +126 -41
- package/bin/tui.js +91 -32
- package/bin/update-check.js +49 -20
- package/bin/upgrade.js +49 -18
- package/bin/usage.js +26 -14
- package/bin/windows/agents.js +135 -32
- package/bin/windows/claude.js +43 -14
- package/bin/windows/common.js +56 -19
- package/bin/windows/install.js +120 -32
- package/bin/windows/launch.js +211 -49
- package/bin/windows/pi-compaction.ts +68 -13
- package/bin/windows/process.js +198 -56
- package/bin/windows/setup.js +231 -56
- package/package.json +9 -3
package/bin/windows/launch.js
CHANGED
|
@@ -2,10 +2,18 @@
|
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import { claudeNativeLaunch } from './claude.js';
|
|
6
|
-
import { buildOpenCodeConfig } from '../opencode-provider.js';
|
|
7
5
|
import { modelSupportsVision } from '../model-capabilities.js';
|
|
8
|
-
import {
|
|
6
|
+
import { buildOpenCodeConfig } from '../opencode-provider.js';
|
|
7
|
+
import { claudeNativeLaunch } from './claude.js';
|
|
8
|
+
import {
|
|
9
|
+
defaults,
|
|
10
|
+
modelIds,
|
|
11
|
+
origin,
|
|
12
|
+
parseOptions,
|
|
13
|
+
positiveInteger,
|
|
14
|
+
value,
|
|
15
|
+
writeJson,
|
|
16
|
+
} from './common.js';
|
|
9
17
|
|
|
10
18
|
function connection(env, keyName) {
|
|
11
19
|
return {
|
|
@@ -15,82 +23,236 @@ function connection(env, keyName) {
|
|
|
15
23
|
};
|
|
16
24
|
}
|
|
17
25
|
|
|
18
|
-
export async function windowsLaunch(
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
export async function windowsLaunch(
|
|
27
|
+
id,
|
|
28
|
+
argv,
|
|
29
|
+
env,
|
|
30
|
+
{ tempRoot = os.tmpdir() } = {},
|
|
31
|
+
) {
|
|
32
|
+
if (id === 'claude-code')
|
|
33
|
+
return { command: 'claude', ...claudeNativeLaunch(argv, env) };
|
|
34
|
+
const keyName = {
|
|
35
|
+
codex: 'CODEX_API_KEY',
|
|
36
|
+
opencode: 'OPENCODE_API_KEY',
|
|
37
|
+
pi: 'PI_API_KEY',
|
|
38
|
+
'subconscious-code': 'SC_API_KEY',
|
|
39
|
+
'deepseek-harness': 'DEEPSEEK_HARNESS_API_KEY',
|
|
40
|
+
}[id];
|
|
21
41
|
const { model, base, key } = connection(env, keyName);
|
|
22
|
-
const childEnv = {
|
|
42
|
+
const childEnv = {
|
|
43
|
+
...env,
|
|
44
|
+
SUBCONSCIOUS_API_KEY: key,
|
|
45
|
+
SUBCONSCIOUS_GATEWAY_URL: base,
|
|
46
|
+
};
|
|
23
47
|
if (id === 'subconscious-code') {
|
|
24
|
-
return {
|
|
48
|
+
return {
|
|
49
|
+
command: 'marathon',
|
|
50
|
+
args: argv,
|
|
51
|
+
env: {
|
|
52
|
+
...childEnv,
|
|
53
|
+
SC_API_KEY: key,
|
|
54
|
+
SC_BASE_URL: `${base}/v1`,
|
|
55
|
+
SC_DLR_URL: base,
|
|
56
|
+
SC_DLR_ENABLED: 'true',
|
|
57
|
+
SC_MODEL: model,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
25
60
|
}
|
|
26
|
-
if (id === 'pi')
|
|
61
|
+
if (id === 'pi')
|
|
62
|
+
return {
|
|
63
|
+
command: 'pi',
|
|
64
|
+
args: ['--provider', 'subconscious', '--model', model, ...argv],
|
|
65
|
+
env: childEnv,
|
|
66
|
+
};
|
|
27
67
|
if (id === 'opencode') {
|
|
28
|
-
const context = positiveInteger(
|
|
29
|
-
|
|
68
|
+
const context = positiveInteger(
|
|
69
|
+
value(env, 'OPENCODE_CONTEXT_LIMIT', '5000000'),
|
|
70
|
+
'OPENCODE_CONTEXT_LIMIT',
|
|
71
|
+
);
|
|
72
|
+
const output = positiveInteger(
|
|
73
|
+
value(env, 'OPENCODE_OUTPUT_LIMIT', '65536'),
|
|
74
|
+
'OPENCODE_OUTPUT_LIMIT',
|
|
75
|
+
);
|
|
30
76
|
childEnv.OPENCODE_CONFIG_CONTENT = JSON.stringify(
|
|
31
|
-
buildOpenCodeConfig({
|
|
77
|
+
buildOpenCodeConfig({
|
|
78
|
+
baseUrl: base,
|
|
79
|
+
model,
|
|
80
|
+
modelIds: modelIds(env),
|
|
81
|
+
context,
|
|
82
|
+
output,
|
|
83
|
+
}),
|
|
32
84
|
);
|
|
33
|
-
return {
|
|
85
|
+
return {
|
|
86
|
+
command: 'opencode',
|
|
87
|
+
args: parseOptions(argv, {}).rest,
|
|
88
|
+
env: childEnv,
|
|
89
|
+
};
|
|
34
90
|
}
|
|
35
91
|
if (id === 'codex') {
|
|
36
|
-
const { options: opts, rest } = parseOptions(argv, {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
92
|
+
const { options: opts, rest } = parseOptions(argv, {
|
|
93
|
+
'--context-window': 1,
|
|
94
|
+
'--max-context-window': 1,
|
|
95
|
+
'--auto-compact-token-limit': 1,
|
|
96
|
+
'--reasoning-effort': 1,
|
|
97
|
+
'--subagents': true,
|
|
98
|
+
'--external-tools': true,
|
|
99
|
+
});
|
|
100
|
+
const context = positiveInteger(
|
|
101
|
+
opts['--context-window'] || value(env, 'CODEX_CONTEXT_WINDOW', '5000000'),
|
|
102
|
+
'context-window',
|
|
103
|
+
);
|
|
104
|
+
const maxContext = positiveInteger(
|
|
105
|
+
opts['--max-context-window'] ||
|
|
106
|
+
value(env, 'CODEX_MAX_CONTEXT_WINDOW', String(context)),
|
|
107
|
+
'max-context-window',
|
|
108
|
+
);
|
|
109
|
+
const compact = positiveInteger(
|
|
110
|
+
opts['--auto-compact-token-limit'] ||
|
|
111
|
+
value(env, 'CODEX_AUTO_COMPACT_TOKEN_LIMIT', '4500000'),
|
|
112
|
+
'auto-compact-token-limit',
|
|
113
|
+
);
|
|
114
|
+
const reasoning =
|
|
115
|
+
opts['--reasoning-effort'] || value(env, 'CODEX_REASONING_EFFORT', 'max');
|
|
116
|
+
if (!['none', 'low', 'medium', 'high', 'max'].includes(reasoning))
|
|
117
|
+
throw new Error(
|
|
118
|
+
'reasoning-effort must be none, low, medium, high, or max',
|
|
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
|
+
})),
|
|
156
|
+
};
|
|
54
157
|
// Validate all flags before creating a temporary directory.
|
|
55
|
-
const threads = positiveInteger(
|
|
158
|
+
const threads = positiveInteger(
|
|
159
|
+
value(env, 'MAX_CONCURRENT_SUBAGENTS', '4'),
|
|
160
|
+
'MAX_CONCURRENT_SUBAGENTS',
|
|
161
|
+
);
|
|
56
162
|
const dir = await fs.mkdtemp(path.join(tempRoot, 'subc-codex-'));
|
|
57
163
|
const cleanup = () => fs.rm(dir, { recursive: true, force: true });
|
|
58
164
|
try {
|
|
59
165
|
const file = path.join(dir, 'models.json');
|
|
60
166
|
await writeJson(file, catalog);
|
|
61
167
|
const config = {
|
|
62
|
-
model,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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,
|
|
66
178
|
};
|
|
67
|
-
if (
|
|
68
|
-
|
|
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
|
+
});
|
|
69
188
|
}
|
|
70
|
-
if (opts['--subagents'])
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
+
}
|
|
74
214
|
}
|
|
75
215
|
if (id === 'deepseek-harness') {
|
|
76
|
-
const context = positiveInteger(
|
|
77
|
-
|
|
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
|
+
);
|
|
78
224
|
const models = modelIds(env);
|
|
79
225
|
const dir = await fs.mkdtemp(path.join(tempRoot, 'subc-dsh-'));
|
|
80
226
|
const cleanup = () => fs.rm(dir, { recursive: true, force: true });
|
|
81
227
|
try {
|
|
82
228
|
const file = path.join(dir, 'subconscious.cordis.yml');
|
|
83
|
-
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`;
|
|
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`;
|
|
84
230
|
await fs.writeFile(file, text, { mode: 0o600, flag: 'wx' });
|
|
85
231
|
const mode = ['web', 'headless'].includes(argv[0]) ? argv[0] : 'web';
|
|
86
232
|
const rest = ['web', 'headless'].includes(argv[0]) ? argv.slice(1) : argv;
|
|
87
|
-
return {
|
|
88
|
-
|
|
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
|
+
}
|
|
89
248
|
}
|
|
90
249
|
throw new Error(`No native Windows launcher is available for ${id}`);
|
|
91
250
|
}
|
|
92
251
|
|
|
93
252
|
export async function executeWindowsLaunch(spec, run) {
|
|
94
|
-
try {
|
|
95
|
-
|
|
253
|
+
try {
|
|
254
|
+
return await run(spec.command, spec.args, { env: spec.env });
|
|
255
|
+
} finally {
|
|
256
|
+
await spec.cleanup?.();
|
|
257
|
+
}
|
|
96
258
|
}
|
|
@@ -1,29 +1,84 @@
|
|
|
1
1
|
// Windows-only Pi extension. Loaded config is relative to this installed file.
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
|
-
import {
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
5
|
import { dirname, join } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
type PiCompactEvent = {
|
|
9
|
+
reason?: unknown;
|
|
10
|
+
preparation?: { tokensBefore?: unknown };
|
|
11
|
+
fromExtension?: unknown;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type PiContext = {
|
|
15
|
+
sessionManager?: { getSessionId?: () => string | undefined };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type WindowsPiConfig = {
|
|
19
|
+
gatewayUrl?: string;
|
|
20
|
+
apiKey?: string;
|
|
21
|
+
};
|
|
6
22
|
|
|
7
|
-
export default function (pi: {
|
|
8
|
-
|
|
9
|
-
|
|
23
|
+
export default function (pi: {
|
|
24
|
+
on: (
|
|
25
|
+
event: string,
|
|
26
|
+
handler: (event: PiCompactEvent, ctx: PiContext) => Promise<void>,
|
|
27
|
+
) => void;
|
|
28
|
+
}) {
|
|
29
|
+
for (const [eventName, phase] of [
|
|
30
|
+
['session_before_compact', 'start'],
|
|
31
|
+
['session_compact', 'end'],
|
|
32
|
+
] as const) {
|
|
33
|
+
pi.on(eventName, async (event, ctx) => {
|
|
10
34
|
const session = ctx?.sessionManager?.getSessionId?.();
|
|
11
35
|
if (!session) return;
|
|
12
36
|
const controller = new AbortController();
|
|
13
37
|
const timer = setTimeout(() => controller.abort(), 1500);
|
|
14
38
|
try {
|
|
15
|
-
const config = JSON.parse(
|
|
39
|
+
const config = JSON.parse(
|
|
40
|
+
readFileSync(
|
|
41
|
+
join(
|
|
42
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
43
|
+
'..',
|
|
44
|
+
'subconscious-windows.json',
|
|
45
|
+
),
|
|
46
|
+
'utf8',
|
|
47
|
+
),
|
|
48
|
+
) as WindowsPiConfig;
|
|
16
49
|
const url = process.env.SUBCONSCIOUS_GATEWAY_URL || config.gatewayUrl;
|
|
17
50
|
const key = process.env.SUBCONSCIOUS_API_KEY || config.apiKey;
|
|
18
51
|
if (!url || !key) return;
|
|
19
|
-
const response = await fetch(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
52
|
+
const response = await fetch(
|
|
53
|
+
`${url.replace(/\/+$/, '')}/v1/agent-hooks`,
|
|
54
|
+
{
|
|
55
|
+
method: 'POST',
|
|
56
|
+
headers: {
|
|
57
|
+
'content-type': 'application/json',
|
|
58
|
+
authorization: `Bearer ${key}`,
|
|
59
|
+
'x-subconscious-client': 'pi',
|
|
60
|
+
},
|
|
61
|
+
body: JSON.stringify({
|
|
62
|
+
event: 'conversation_compaction',
|
|
63
|
+
conversation_id: session,
|
|
64
|
+
phase,
|
|
65
|
+
hook_event_name: eventName,
|
|
66
|
+
dedupe_key: `${session}:${phase}:${randomUUID()}`,
|
|
67
|
+
metadata: {
|
|
68
|
+
reason: event?.reason,
|
|
69
|
+
tokens_before: event?.preparation?.tokensBefore,
|
|
70
|
+
from_extension: event?.fromExtension,
|
|
71
|
+
},
|
|
72
|
+
}),
|
|
73
|
+
signal: controller.signal,
|
|
74
|
+
},
|
|
75
|
+
);
|
|
24
76
|
await response.body?.cancel();
|
|
25
|
-
} catch {
|
|
26
|
-
|
|
77
|
+
} catch {
|
|
78
|
+
/* observational: never cancel or replace compaction */
|
|
79
|
+
} finally {
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
}
|
|
27
82
|
});
|
|
28
83
|
}
|
|
29
84
|
}
|