subconscious-cli 6.0.0 → 6.1.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.
Files changed (76) hide show
  1. package/README.md +135 -2
  2. package/bin/agent-data.js +242 -0
  3. package/bin/agent-help.js +106 -0
  4. package/bin/agent-install.js +354 -0
  5. package/bin/agent-launch.js +199 -0
  6. package/bin/agent-spawn.js +137 -0
  7. package/bin/agents.js +284 -840
  8. package/bin/auth.js +89 -33
  9. package/bin/branding.js +3 -1
  10. package/bin/claude-picker.js +143 -0
  11. package/bin/cli.js +87 -20
  12. package/bin/clipboard-image.js +24 -5
  13. package/bin/colors.js +1 -1
  14. package/bin/feedback.js +71 -21
  15. package/bin/harness-manifest.js +286 -0
  16. package/bin/headless-args.js +35 -0
  17. package/bin/launch-values.js +25 -0
  18. package/bin/model-capabilities.js +12 -8
  19. package/bin/models.js +35 -19
  20. package/bin/native/subc-tui-darwin-amd64 +0 -0
  21. package/bin/native/subc-tui-darwin-arm64 +0 -0
  22. package/bin/native/subc-tui-linux-amd64 +0 -0
  23. package/bin/native/subc-tui-linux-arm64 +0 -0
  24. package/bin/native/subc-tui-windows-amd64.exe +0 -0
  25. package/bin/native/subc-tui-windows-arm64.exe +0 -0
  26. package/bin/opencode-provider.js +48 -5
  27. package/bin/profile-settings.js +129 -0
  28. package/bin/profiles.js +136 -449
  29. package/bin/runbook/README.md +66 -23
  30. package/bin/runbook/claude-code/agent.json +300 -0
  31. package/bin/runbook/claude-code/install.sh +9 -252
  32. package/bin/runbook/codex/agent.json +461 -0
  33. package/bin/runbook/codex/hooks-lib.sh +17 -4
  34. package/bin/runbook/codex/install.sh +0 -4
  35. package/bin/runbook/codex/run.sh +16 -235
  36. package/bin/runbook/copilot/agent.json +185 -0
  37. package/bin/runbook/copilot/install.sh +45 -63
  38. package/bin/runbook/cursor/agent.json +137 -0
  39. package/bin/runbook/cursor/install.sh +8 -35
  40. package/bin/runbook/deepseek-harness/agent.json +163 -0
  41. package/bin/runbook/deepseek-harness/run.sh +20 -59
  42. package/bin/runbook/image-window/index.ts +14 -0
  43. package/bin/runbook/image-window/window.d.ts +19 -0
  44. package/bin/runbook/image-window/window.js +140 -0
  45. package/bin/runbook/lib.sh +41 -0
  46. package/bin/runbook/opencode/agent.json +158 -0
  47. package/bin/runbook/opencode/install.sh +9 -183
  48. package/bin/runbook/opencode/opencode-plugin.d.ts +16 -0
  49. package/bin/runbook/opencode/subconscious-image-window.ts +24 -0
  50. package/bin/runbook/pi/agent.json +216 -0
  51. package/bin/runbook/pi/install.sh +18 -44
  52. package/bin/runbook/pi/run.sh +6 -18
  53. package/bin/runbook/pi/subconscious-compaction.ts +71 -49
  54. package/bin/runbook/shared.json +58 -0
  55. package/bin/runbook/subconscious-code/agent.json +156 -0
  56. package/bin/sessions.js +173 -58
  57. package/bin/tui.js +104 -32
  58. package/bin/update-check.js +54 -21
  59. package/bin/upgrade.js +67 -43
  60. package/bin/usage.js +47 -24
  61. package/bin/windows/agents.js +141 -37
  62. package/bin/windows/common.js +36 -25
  63. package/bin/windows/install.js +116 -34
  64. package/bin/windows/launch.js +260 -77
  65. package/bin/windows/pi-compaction.ts +68 -13
  66. package/bin/windows/process.js +210 -57
  67. package/bin/windows/setup.js +251 -56
  68. package/package.json +9 -4
  69. package/bin/registry.generated.json +0 -406
  70. package/bin/runbook/claude-code/run.sh +0 -254
  71. package/bin/runbook/model-capabilities.generated.sh +0 -9
  72. package/bin/runbook/opencode/provider.sh +0 -93
  73. package/bin/runbook/opencode/run.sh +0 -99
  74. package/bin/runbook/opencode/subconscious-compaction.ts +0 -100
  75. package/bin/runbook/subconscious-code/run.sh +0 -21
  76. package/bin/windows/claude.js +0 -71
Binary file
Binary file
@@ -1,9 +1,24 @@
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
- const ACRONYMS = new Set(['gpt', 'oss', 'api', 'gguf', 'ggml', 'nomic', 'vl', 'it', 'mlx']);
11
+ const ACRONYMS = new Set([
12
+ 'gpt',
13
+ 'oss',
14
+ 'api',
15
+ 'gguf',
16
+ 'ggml',
17
+ 'nomic',
18
+ 'vl',
19
+ 'it',
20
+ 'mlx',
21
+ ]);
7
22
 
8
23
  function formatToken(token) {
9
24
  const lower = token.toLowerCase();
@@ -11,14 +26,17 @@ function formatToken(token) {
11
26
  if (/^\d+[bkmg]$/i.test(token)) return token.toUpperCase();
12
27
  if (/^q\d+$/i.test(token)) return token.toUpperCase();
13
28
  if (/^\d+\.\d+/.test(token)) return token;
14
- if (/^[a-z]\d+[a-z]$/i.test(token) || /^\d+[a-z]$/i.test(token)) return token.toUpperCase();
29
+ if (/^[a-z]\d+[a-z]$/i.test(token) || /^\d+[a-z]$/i.test(token))
30
+ return token.toUpperCase();
15
31
  return token.charAt(0).toUpperCase() + token.slice(1).toLowerCase();
16
32
  }
17
33
 
18
34
  /** Drop the subconscious/ prefix, then capitalize each dash-separated token. */
19
35
  export function opencodeModelDisplayName(modelId) {
20
36
  const text = String(modelId ?? '').trim();
21
- const slug = text.startsWith('subconscious/') ? text.slice('subconscious/'.length) : text;
37
+ const slug = text.startsWith('subconscious/')
38
+ ? text.slice('subconscious/'.length)
39
+ : text;
22
40
  return slug.split(/[-_]/).filter(Boolean).map(formatToken).join(' ');
23
41
  }
24
42
 
@@ -31,17 +49,28 @@ export function buildOpenCodeModels(modelIds, { context, output }) {
31
49
  tools: true,
32
50
  limit: { context, output },
33
51
  ...(modelSupportsVision(id)
34
- ? { attachment: true, modalities: { input: ['text', 'image'], output: ['text'] } }
52
+ ? {
53
+ attachment: true,
54
+ modalities: { input: ['text', 'image'], output: ['text'] },
55
+ }
35
56
  : {}),
36
57
  },
37
58
  ]),
38
59
  );
39
60
  }
40
61
 
41
- export function buildOpenCodeConfig({ baseUrl, model, modelIds, context, output }) {
62
+ export function buildOpenCodeConfig({
63
+ baseUrl,
64
+ model,
65
+ modelIds,
66
+ context,
67
+ output,
68
+ }) {
42
69
  return {
43
70
  $schema: 'https://opencode.ai/config.json',
44
71
  disabled_providers: ['subconscious-cli'],
72
+ // Trims each request to the newest 30 images before upload.
73
+ plugin: [OPENCODE_IMAGE_WINDOW_PLUGIN],
45
74
  provider: {
46
75
  [OPENCODE_PROVIDER_ID]: {
47
76
  npm: '@ai-sdk/openai-compatible',
@@ -59,3 +88,17 @@ export function buildOpenCodeConfig({ baseUrl, model, modelIds, context, output
59
88
  model: `${OPENCODE_PROVIDER_ID}/${model}`,
60
89
  };
61
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
+ }