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.
@@ -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 { defaults, value, origin, modelIds, positiveInteger, parseOptions, writeJson } from './common.js';
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(id, argv, env, { tempRoot = os.tmpdir() } = {}) {
19
- if (id === 'claude-code') return { command: 'claude', ...claudeNativeLaunch(argv, env) };
20
- const keyName = { codex: 'CODEX_API_KEY', opencode: 'OPENCODE_API_KEY', pi: 'PI_API_KEY', 'subconscious-code': 'SC_API_KEY', 'deepseek-harness': 'DEEPSEEK_HARNESS_API_KEY' }[id];
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 = { ...env, SUBCONSCIOUS_API_KEY: key, SUBCONSCIOUS_GATEWAY_URL: base };
42
+ const childEnv = {
43
+ ...env,
44
+ SUBCONSCIOUS_API_KEY: key,
45
+ SUBCONSCIOUS_GATEWAY_URL: base,
46
+ };
23
47
  if (id === 'subconscious-code') {
24
- return { command: 'marathon', args: argv, env: { ...childEnv, SC_API_KEY: key, SC_BASE_URL: `${base}/v1`, SC_DLR_URL: base, SC_DLR_ENABLED: 'true', SC_MODEL: model } };
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') return { command: 'pi', args: ['--provider', 'subconscious', '--model', model, ...argv], env: childEnv };
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(value(env, 'OPENCODE_CONTEXT_LIMIT', '5000000'), 'OPENCODE_CONTEXT_LIMIT');
29
- const output = positiveInteger(value(env, 'OPENCODE_OUTPUT_LIMIT', '65536'), 'OPENCODE_OUTPUT_LIMIT');
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({ baseUrl: base, model, modelIds: modelIds(env), context, output }),
77
+ buildOpenCodeConfig({
78
+ baseUrl: base,
79
+ model,
80
+ modelIds: modelIds(env),
81
+ context,
82
+ output,
83
+ }),
32
84
  );
33
- return { command: 'opencode', args: parseOptions(argv, {}).rest, env: childEnv };
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, { '--context-window': 1, '--max-context-window': 1, '--auto-compact-token-limit': 1, '--reasoning-effort': 1, '--subagents': true, '--external-tools': true });
37
- const context = positiveInteger(opts['--context-window'] || value(env, 'CODEX_CONTEXT_WINDOW', '5000000'), 'context-window');
38
- const maxContext = positiveInteger(opts['--max-context-window'] || value(env, 'CODEX_MAX_CONTEXT_WINDOW', String(context)), 'max-context-window');
39
- const compact = positiveInteger(opts['--auto-compact-token-limit'] || value(env, 'CODEX_AUTO_COMPACT_TOKEN_LIMIT', '4500000'), 'auto-compact-token-limit');
40
- const reasoning = opts['--reasoning-effort'] || value(env, 'CODEX_REASONING_EFFORT', 'max');
41
- if (!['none', 'low', 'medium', 'high', 'max'].includes(reasoning)) throw new Error('reasoning-effort must be none, low, medium, high, or max');
42
- const catalog = { models: modelIds(env).map(id => ({
43
- slug: id, display_name: id, description: `Subconscious model ${id}`,
44
- context_window: context, max_context_window: maxContext, auto_compact_token_limit: compact,
45
- effective_context_window_percent: 95, supported_reasoning_levels: [], shell_type: 'shell_command',
46
- visibility: 'list', supported_in_api: true, priority: 0,
47
- service_tiers: [{ id: 'priority', name: 'Priority', description: 'Route requests through the configured priority service tier' }],
48
- availability_nux: null, upgrade: null, base_instructions: 'You are Codex, a coding agent.',
49
- supports_reasoning_summaries: false, support_verbosity: false, default_verbosity: null,
50
- apply_patch_tool_type: 'freeform', truncation_policy: { mode: 'tokens', limit: 10000 },
51
- supports_parallel_tool_calls: true, experimental_supported_tools: [],
52
- ...(modelSupportsVision(id) ? { input_modalities: ['text', 'image'] } : {}),
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(value(env, 'MAX_CONCURRENT_SUBAGENTS', '4'), 'MAX_CONCURRENT_SUBAGENTS');
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, model_provider: 'subconscious', model_catalog_json: file, model_reasoning_effort: reasoning,
63
- web_search: 'disabled', 'model_providers.subconscious.name': 'Subconscious',
64
- 'model_providers.subconscious.base_url': `${base}/v1`, 'model_providers.subconscious.wire_api': 'responses',
65
- 'model_providers.subconscious.env_key': 'SUBCONSCIOUS_API_KEY', 'model_providers.subconscious.stream_idle_timeout_ms': 300000,
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 (!opts['--external-tools'] && value(env, 'CODEX_EXTERNAL_TOOLS', 'false') !== 'true') {
68
- Object.assign(config, { 'features.apps': false, 'features.plugins': false, 'apps._default.enabled': false });
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']) Object.assign(config, { 'features.multi_agent': true, 'agents.max_threads': threads, 'agents.max_depth': 1, 'agents.interrupt_message': true });
71
- const args = Object.entries(config).flatMap(([k, v]) => ['-c', `${k}=${JSON.stringify(v)}`]);
72
- return { command: opts['--subagents'] ? 'npx' : 'codex', args: [...(opts['--subagents'] ? ['-y', '@openai/codex@0.132.0'] : []), ...args, ...rest], env: childEnv, cleanup };
73
- } catch (error) { await cleanup(); throw error; }
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(value(env, 'DEEPSEEK_HARNESS_CONTEXT_WINDOW', '5000000'), 'DEEPSEEK_HARNESS_CONTEXT_WINDOW');
77
- const maxTokens = positiveInteger(value(env, 'DEEPSEEK_HARNESS_MAX_TOKENS', '65536'), 'DEEPSEEK_HARNESS_MAX_TOKENS');
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 { command: 'dsh', args: [...(mode === 'web' ? ['web'] : ['--profile', 'headless']), '--patch', file, ...rest], env: { ...childEnv, SUBCONSCIOUS_DSH_BASE_URL: `${base}/v1` }, cleanup };
88
- } catch (error) { await cleanup(); throw error; }
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 { return await run(spec.command, spec.args, { env: spec.env }); }
95
- finally { await spec.cleanup?.(); }
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
- import { readFileSync } from 'node:fs';
2
+
3
3
  import { randomUUID } from 'node:crypto';
4
- import { fileURLToPath } from 'node:url';
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: { on: (event: string, handler: (...args: any[]) => any) => void }) {
8
- for (const [eventName, phase] of [['session_before_compact', 'start'], ['session_compact', 'end']]) {
9
- pi.on(eventName, async (event: any, ctx: any) => {
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(readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'subconscious-windows.json'), 'utf8'));
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(`${url.replace(/\/+$/, '')}/v1/agent-hooks`, {
20
- method: 'POST', headers: { 'content-type': 'application/json', authorization: `Bearer ${key}`, 'x-subconscious-client': 'pi' },
21
- body: JSON.stringify({ event: 'conversation_compaction', conversation_id: session, phase, hook_event_name: eventName, dedupe_key: `${session}:${phase}:${randomUUID()}`, metadata: { reason: event?.reason, tokens_before: event?.preparation?.tokensBefore, from_extension: event?.fromExtension } }),
22
- signal: controller.signal,
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 { /* observational: never cancel or replace compaction */ }
26
- finally { clearTimeout(timer); }
77
+ } catch {
78
+ /* observational: never cancel or replace compaction */
79
+ } finally {
80
+ clearTimeout(timer);
81
+ }
27
82
  });
28
83
  }
29
84
  }