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
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
// The models endpoint currently supplies IDs, not modality metadata. Keep
|
|
4
|
-
// explicit capabilities in the same registry used to generate the Unix lookup.
|
|
5
|
-
const { modelCapabilities = {} } = JSON.parse(
|
|
6
|
-
readFileSync(new URL('./registry.generated.json', import.meta.url), 'utf8'),
|
|
7
|
-
);
|
|
1
|
+
import { MODEL_CAPABILITIES } from './agent-data.js';
|
|
8
2
|
|
|
3
|
+
// The models endpoint supplies IDs, not modality metadata, so capabilities
|
|
4
|
+
// are listed by exact model ID: similarly named models inherit nothing.
|
|
9
5
|
export function modelSupportsVision(modelId) {
|
|
10
6
|
return (
|
|
11
|
-
Object.hasOwn(
|
|
12
|
-
|
|
7
|
+
Object.hasOwn(MODEL_CAPABILITIES, modelId) &&
|
|
8
|
+
MODEL_CAPABILITIES[modelId].vision === true
|
|
13
9
|
);
|
|
14
10
|
}
|
|
11
|
+
|
|
12
|
+
/** Vision model IDs, newline-separated, for the runbooks' shell lookup. */
|
|
13
|
+
export function visionModelList() {
|
|
14
|
+
return Object.keys(MODEL_CAPABILITIES).filter(modelSupportsVision).join('\n');
|
|
15
|
+
}
|
package/bin/models.js
CHANGED
|
@@ -106,26 +106,26 @@ export async function fetchGatewayModels({
|
|
|
106
106
|
};
|
|
107
107
|
controller.signal.addEventListener('abort', fail, { once: true });
|
|
108
108
|
});
|
|
109
|
-
const
|
|
110
|
-
fetchImpl(endpoint, {
|
|
109
|
+
const discover = async () => {
|
|
110
|
+
const response = await fetchImpl(endpoint, {
|
|
111
111
|
method: 'GET',
|
|
112
112
|
headers,
|
|
113
113
|
cache: 'no-store',
|
|
114
114
|
signal: controller.signal,
|
|
115
|
-
})
|
|
116
|
-
aborted,
|
|
117
|
-
]);
|
|
115
|
+
});
|
|
118
116
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
throw new Error(`Model discovery returned HTTP ${response.status}`);
|
|
119
|
+
}
|
|
122
120
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
121
|
+
const payload = await response.json();
|
|
122
|
+
if (!Array.isArray(payload?.data)) {
|
|
123
|
+
throw new Error('Model discovery returned an invalid response');
|
|
124
|
+
}
|
|
127
125
|
|
|
128
|
-
|
|
126
|
+
return normalizeModelIds(payload.data.map((model) => model?.id));
|
|
127
|
+
};
|
|
128
|
+
return await Promise.race([discover(), aborted]);
|
|
129
129
|
} catch (error) {
|
|
130
130
|
if (signal?.aborted) throw abortError('Model discovery was cancelled');
|
|
131
131
|
if (controller.signal.aborted) {
|
|
@@ -175,10 +175,22 @@ export async function resolveModelCatalog({
|
|
|
175
175
|
apiKey,
|
|
176
176
|
selectedModel,
|
|
177
177
|
fallbackModels = [],
|
|
178
|
+
pinnedModels,
|
|
178
179
|
fetchImpl = globalThis.fetch,
|
|
179
180
|
timeoutMs = DEFAULT_MODEL_FETCH_TIMEOUT_MS,
|
|
180
181
|
signal,
|
|
181
182
|
}) {
|
|
183
|
+
// A caller that names its catalog (a benchmark run, a CI job) needs the same
|
|
184
|
+
// models on every launch, whatever the gateway lists that day.
|
|
185
|
+
const pinned = pinnedModels?.split(/\r?\n/).filter((id) => id.trim());
|
|
186
|
+
if (pinned?.length) {
|
|
187
|
+
return {
|
|
188
|
+
models: normalizeModelIds(pinned, selectedModel),
|
|
189
|
+
source: 'pinned',
|
|
190
|
+
error: null,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
182
194
|
const key = apiKey?.trim() || '';
|
|
183
195
|
|
|
184
196
|
if (key) {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/bin/opencode-provider.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import { modelIds, positiveInteger } from './launch-values.js';
|
|
1
3
|
import { modelSupportsVision } from './model-capabilities.js';
|
|
2
4
|
|
|
3
5
|
export const OPENCODE_PROVIDER_ID = 'subconscious';
|
|
6
|
+
const OPENCODE_IMAGE_WINDOW_PLUGIN = fileURLToPath(
|
|
7
|
+
new URL('./runbook/opencode/subconscious-image-window.ts', import.meta.url),
|
|
8
|
+
);
|
|
4
9
|
export const OPENCODE_PROVIDER_NAME = 'Subconscious Gateway';
|
|
5
10
|
|
|
6
11
|
const ACRONYMS = new Set([
|
|
@@ -64,6 +69,8 @@ export function buildOpenCodeConfig({
|
|
|
64
69
|
return {
|
|
65
70
|
$schema: 'https://opencode.ai/config.json',
|
|
66
71
|
disabled_providers: ['subconscious-cli'],
|
|
72
|
+
// Trims each request to the newest 30 images before upload.
|
|
73
|
+
plugin: [OPENCODE_IMAGE_WINDOW_PLUGIN],
|
|
67
74
|
provider: {
|
|
68
75
|
[OPENCODE_PROVIDER_ID]: {
|
|
69
76
|
npm: '@ai-sdk/openai-compatible',
|
|
@@ -81,3 +88,17 @@ export function buildOpenCodeConfig({
|
|
|
81
88
|
model: `${OPENCODE_PROVIDER_ID}/${model}`,
|
|
82
89
|
};
|
|
83
90
|
}
|
|
91
|
+
|
|
92
|
+
/** The launch config for the env subc passes to OpenCode. */
|
|
93
|
+
export function openCodeConfigFromEnv(env) {
|
|
94
|
+
return buildOpenCodeConfig({
|
|
95
|
+
baseUrl: String(env.GATEWAY_URL ?? '').replace(/\/+$/, ''),
|
|
96
|
+
model: env.MODEL,
|
|
97
|
+
modelIds: modelIds(env),
|
|
98
|
+
context: positiveInteger(
|
|
99
|
+
env.OPENCODE_CONTEXT_LIMIT,
|
|
100
|
+
'OPENCODE_CONTEXT_LIMIT',
|
|
101
|
+
),
|
|
102
|
+
output: positiveInteger(env.OPENCODE_OUTPUT_LIMIT, 'OPENCODE_OUTPUT_LIMIT'),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AGENTS,
|
|
3
|
+
agentInputs,
|
|
4
|
+
DEFAULTS,
|
|
5
|
+
PACKAGED_MODELS,
|
|
6
|
+
resolveRefs,
|
|
7
|
+
SHARED_INPUTS,
|
|
8
|
+
staticLookup,
|
|
9
|
+
} from './agent-data.js';
|
|
10
|
+
|
|
11
|
+
export const SUPPORTED_MODELS = Object.freeze([...PACKAGED_MODELS]);
|
|
12
|
+
|
|
13
|
+
const TOKEN = /\{[A-Za-z][A-Za-z0-9]*\}/;
|
|
14
|
+
const shown = (input) => input.label && input.group !== 'shared';
|
|
15
|
+
|
|
16
|
+
function toSetting(input) {
|
|
17
|
+
const model = input.type === 'model';
|
|
18
|
+
const setting = {
|
|
19
|
+
key: input.name,
|
|
20
|
+
label: input.label,
|
|
21
|
+
description: input.description,
|
|
22
|
+
type: model ? 'choice' : input.type || 'text',
|
|
23
|
+
};
|
|
24
|
+
if (model) Object.assign(setting, { choices: SUPPORTED_MODELS, model });
|
|
25
|
+
if (input.choices) setting.choices = input.choices;
|
|
26
|
+
for (const field of ['min', 'max', 'required'])
|
|
27
|
+
if (input[field] !== undefined) setting[field] = input[field];
|
|
28
|
+
return Object.freeze(setting);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function group(id, label, inputs) {
|
|
32
|
+
return Object.freeze({
|
|
33
|
+
id,
|
|
34
|
+
label,
|
|
35
|
+
keys: inputs.map((input) => input.name),
|
|
36
|
+
settings: inputs.map(toSetting),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const PROFILE_SETTING_GROUPS = Object.freeze([
|
|
41
|
+
group(
|
|
42
|
+
'shared',
|
|
43
|
+
'Shared settings',
|
|
44
|
+
SHARED_INPUTS.filter((input) => input.group === 'shared'),
|
|
45
|
+
),
|
|
46
|
+
...AGENTS.map((agent) =>
|
|
47
|
+
group(agent.id, agent.name, agentInputs(agent).filter(shown)),
|
|
48
|
+
),
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
/** A default a profile can hold: literal, with references resolved. */
|
|
52
|
+
function profileDefault(input, lookup) {
|
|
53
|
+
if (input.type === 'secret' || input.default === undefined) return '';
|
|
54
|
+
const value = String(resolveRefs(input.default, lookup));
|
|
55
|
+
return TOKEN.test(value) ? '' : value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function agentDefaults(agent) {
|
|
59
|
+
const lookup = staticLookup(agent);
|
|
60
|
+
// A profile pins every default it holds, so inputs kept out of the
|
|
61
|
+
// template stay out of new and existing profiles.
|
|
62
|
+
return agentInputs(agent)
|
|
63
|
+
.filter((input) => input.label && input.template !== false)
|
|
64
|
+
.map((input) => [input.name, profileDefault(input, lookup)]);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const RUNBOOK_DEFAULTS = Object.freeze({
|
|
68
|
+
...Object.fromEntries(AGENTS.flatMap(agentDefaults)),
|
|
69
|
+
GATEWAY_URL: DEFAULTS.baseUrl,
|
|
70
|
+
API_KEY: '',
|
|
71
|
+
MODEL: DEFAULTS.model,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export function profileSettingsForAgent(agentId) {
|
|
75
|
+
const shared = PROFILE_SETTING_GROUPS.find((item) => item.id === 'shared');
|
|
76
|
+
const agent = PROFILE_SETTING_GROUPS.find((item) => item.id === agentId);
|
|
77
|
+
return [...(shared?.settings || []), ...(agent?.settings || [])];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function resolvedProfileValues(profile) {
|
|
81
|
+
return { ...RUNBOOK_DEFAULTS, ...(profile?.values || {}) };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function templateLine(input) {
|
|
85
|
+
const line = `${input.name}={${input.name}}`;
|
|
86
|
+
return input.comment ? [`# ${input.comment}`, line] : [line];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function agentSections() {
|
|
90
|
+
const written = new Set();
|
|
91
|
+
return AGENTS.flatMap((agent) => {
|
|
92
|
+
const inputs = agentInputs(agent).filter(
|
|
93
|
+
(input) =>
|
|
94
|
+
shown(input) &&
|
|
95
|
+
input.type !== 'secret' &&
|
|
96
|
+
input.template !== false &&
|
|
97
|
+
!written.has(input.name),
|
|
98
|
+
);
|
|
99
|
+
for (const input of inputs) written.add(input.name);
|
|
100
|
+
if (!inputs.length) return [];
|
|
101
|
+
return ['', `# ${agent.name}`, ...inputs.flatMap(templateLine)];
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** The new-profile file, with `{KEY}` where each value goes. */
|
|
106
|
+
export function profileTemplate() {
|
|
107
|
+
const keys = AGENTS.flatMap((agent) =>
|
|
108
|
+
agentInputs(agent).filter(
|
|
109
|
+
(input) => shown(input) && input.type === 'secret',
|
|
110
|
+
),
|
|
111
|
+
);
|
|
112
|
+
return [
|
|
113
|
+
'# Subconscious coding-agent profile',
|
|
114
|
+
'# Generated by subc. Extra KEY=value lines are passed through to launches.',
|
|
115
|
+
'',
|
|
116
|
+
'GATEWAY_URL={GATEWAY_URL}',
|
|
117
|
+
'API_KEY={API_KEY}',
|
|
118
|
+
'# Available models (MODEL=UNSET uses the first live catalog model):',
|
|
119
|
+
...SUPPORTED_MODELS.map((model) => `# ${model}`),
|
|
120
|
+
'MODEL={MODEL}',
|
|
121
|
+
'',
|
|
122
|
+
'# Optional per-agent keys. Leave blank to use API_KEY above.',
|
|
123
|
+
...keys.map((input) => `${input.name}={${input.name}}`),
|
|
124
|
+
...agentSections(),
|
|
125
|
+
'',
|
|
126
|
+
'# Extra KEY=value lines are passed through to launches.',
|
|
127
|
+
'',
|
|
128
|
+
].join('\n');
|
|
129
|
+
}
|