subconscious-cli 4.0.5 → 4.0.7
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 +8 -3
- package/bin/agents.js +3 -0
- package/bin/branding.js +15 -20
- package/bin/cli.js +15 -3
- package/bin/colors.js +4 -3
- 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/profiles.js +15 -2
- package/bin/tui.js +195 -0
- package/bin/update-check.js +8 -8
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -31,9 +31,13 @@ subc pi
|
|
|
31
31
|
subc <agent> uninstall
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
Running `subc` with no arguments in a terminal opens the native Go TUI. Use
|
|
35
|
+
the arrow keys and Enter to launch agents or manage the active profile, `p` to
|
|
36
|
+
switch profiles, and `q` to quit. The menu includes dedicated **Create profile**,
|
|
37
|
+
**Set default model**, and **Update base URL** actions. Model and URL changes
|
|
38
|
+
are validated and saved to the active profile without leaving the TUI.
|
|
39
|
+
`subc help` and `subc --help` continue to print script-friendly command help.
|
|
40
|
+
Non-interactive `subc` also prints regular help.
|
|
37
41
|
|
|
38
42
|
Every command accepts `help` as a subcommand. These only read the selected
|
|
39
43
|
profile; they do not authenticate, install, configure, or launch anything:
|
|
@@ -135,6 +139,7 @@ DeepSeek Harness context and output settings used by the packaged runbook script
|
|
|
135
139
|
|
|
136
140
|
```bash
|
|
137
141
|
subc config # list every profile and its file path
|
|
142
|
+
subc -p staging config create # create a profile with default settings
|
|
138
143
|
subc -p staging config # print that path and env file
|
|
139
144
|
subc -p staging config --model subconscious/glm-5.2
|
|
140
145
|
subc config --gateway-url https://gateway.example
|
package/bin/agents.js
CHANGED
|
@@ -100,9 +100,12 @@ export function resolveAgent(name) {
|
|
|
100
100
|
|
|
101
101
|
export function agentList() {
|
|
102
102
|
return AGENTS.map((a) => ({
|
|
103
|
+
id: a.id,
|
|
103
104
|
name: a.name,
|
|
104
105
|
alias: a.command || a.id,
|
|
105
106
|
action: a.runbook?.mode === 'setup' ? 'Configure' : 'Launch',
|
|
107
|
+
description: a.description || '',
|
|
108
|
+
launch: a.runbook?.mode !== 'setup',
|
|
106
109
|
}));
|
|
107
110
|
}
|
|
108
111
|
|
package/bin/branding.js
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
import { BRAND_ORANGE, colorEnabled } from './colors.js';
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
'
|
|
8
|
-
'
|
|
9
|
-
'
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
14
|
-
'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
' ####### #######',
|
|
18
|
-
' ####### #######',
|
|
19
|
-
' ####### #######',
|
|
20
|
-
' ###### #####',
|
|
21
|
-
].join('\n');
|
|
3
|
+
// The compact terminal raster used by Subconscious Code. It preserves the
|
|
4
|
+
// proportions of logo.svg while remaining crisp in an 8-row terminal cell.
|
|
5
|
+
export const LOGO_GLYPH = '✻';
|
|
6
|
+
export const LOGO_ART_SMALL_LINES = [
|
|
7
|
+
' ███▄ ▄███',
|
|
8
|
+
' ████ ████',
|
|
9
|
+
' ██',
|
|
10
|
+
'▄██▄▄ ▄██▄ ▄▄██▄',
|
|
11
|
+
'▀███▀ ▀██▀ ▀███▀',
|
|
12
|
+
' ██',
|
|
13
|
+
' ████ ████',
|
|
14
|
+
' ███▀ ▀███',
|
|
15
|
+
];
|
|
16
|
+
export const LOGO_ART_SMALL = LOGO_ART_SMALL_LINES.join('\n');
|
|
22
17
|
|
|
23
18
|
const BOLD = '\x1b[1m';
|
|
24
19
|
const RESET = '\x1b[0m';
|
|
@@ -33,6 +28,6 @@ export function renderBanner(options = {}) {
|
|
|
33
28
|
// still get the same logo without ANSI styling.
|
|
34
29
|
if (!isTTY || term === 'dumb') return ` ${title}`;
|
|
35
30
|
|
|
36
|
-
const logo = color ? `${BRAND_ORANGE}${
|
|
31
|
+
const logo = color ? `${BRAND_ORANGE}${LOGO_ART_SMALL}${RESET}` : LOGO_ART_SMALL;
|
|
37
32
|
return `${logo}\n\n ${title}`;
|
|
38
33
|
}
|
package/bin/cli.js
CHANGED
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
} from './profiles.js';
|
|
42
42
|
import { resolveModelCatalog } from './models.js';
|
|
43
43
|
import { showUpdateNotice } from './update-check.js';
|
|
44
|
+
import { runTui } from './tui.js';
|
|
44
45
|
|
|
45
46
|
function isHelpArg(arg) {
|
|
46
47
|
return arg === 'help' || arg === '-h' || arg === '--help';
|
|
@@ -228,9 +229,20 @@ async function main() {
|
|
|
228
229
|
const update = await showUpdateNotice();
|
|
229
230
|
if (update?.action === 'updated' || update?.action === 'cancel') return;
|
|
230
231
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
232
|
+
let parsed = extractProfile(process.argv.slice(2));
|
|
233
|
+
let { args, profileName, profileExplicit } = parsed;
|
|
234
|
+
let command = args[0];
|
|
235
|
+
|
|
236
|
+
if (!command && process.stdin.isTTY === true && process.stdout.isTTY === true && process.env.TERM !== 'dumb') {
|
|
237
|
+
const selection = await runTui({ profileName });
|
|
238
|
+
if (!selection?.args?.length) return;
|
|
239
|
+
if (selection.baseUrl?.trim()) {
|
|
240
|
+
process.env.SUBCONSCIOUS_BASE_URL = selection.baseUrl.trim();
|
|
241
|
+
}
|
|
242
|
+
parsed = extractProfile(selection.args);
|
|
243
|
+
({ args, profileName, profileExplicit } = parsed);
|
|
244
|
+
command = args[0];
|
|
245
|
+
}
|
|
234
246
|
|
|
235
247
|
if (!command || command === '--help' || command === '-h' || (command === 'help' && !args[1])) {
|
|
236
248
|
printHelp();
|
package/bin/colors.js
CHANGED
|
@@ -14,7 +14,8 @@ const rgb = (red, green, blue) =>
|
|
|
14
14
|
colorEnabled ? `\x1b[38;2;${red};${green};${blue}m` : '';
|
|
15
15
|
const bgRgb = (red, green, blue) =>
|
|
16
16
|
colorEnabled ? `\x1b[48;2;${red};${green};${blue}m` : '';
|
|
17
|
-
|
|
17
|
+
// Match the Subconscious Code brand palette exactly (#FF5C27).
|
|
18
|
+
export const BRAND_ORANGE = '\x1b[38;2;255;92;39m';
|
|
18
19
|
|
|
19
20
|
export const c = {
|
|
20
21
|
reset: ansi(0),
|
|
@@ -27,8 +28,8 @@ export const c = {
|
|
|
27
28
|
magenta: ansi(35),
|
|
28
29
|
black: ansi(30),
|
|
29
30
|
orange: colorEnabled ? BRAND_ORANGE : '',
|
|
30
|
-
orangeSoft: rgb(
|
|
31
|
-
bgOrange: bgRgb(255, 92,
|
|
31
|
+
orangeSoft: rgb(184, 74, 30),
|
|
32
|
+
bgOrange: bgRgb(255, 92, 39),
|
|
32
33
|
underline: ansi(4),
|
|
33
34
|
inverse: ansi(7),
|
|
34
35
|
};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/bin/profiles.js
CHANGED
|
@@ -678,7 +678,7 @@ Usage:
|
|
|
678
678
|
subc -p NAME config
|
|
679
679
|
subc config edit [vim|nano]
|
|
680
680
|
subc -p NAME config edit [vim|nano]
|
|
681
|
-
subc config [show|path|list|delete]
|
|
681
|
+
subc config [show|path|list|create|delete]
|
|
682
682
|
[--gateway-url URL] [--api-key KEY] [--model MODEL]
|
|
683
683
|
|
|
684
684
|
subc config List every profile and its file path
|
|
@@ -687,6 +687,7 @@ Usage:
|
|
|
687
687
|
subc config edit vim Open the selected profile in vim
|
|
688
688
|
subc config edit nano Open the selected profile in nano
|
|
689
689
|
subc config path Print the selected profile path
|
|
690
|
+
subc -p NAME config create Create a new profile with default settings
|
|
690
691
|
subc -p NAME config delete Delete a non-default profile
|
|
691
692
|
`);
|
|
692
693
|
}
|
|
@@ -715,7 +716,7 @@ export async function configCommand(argv, profileName = DEFAULT_PROFILE, options
|
|
|
715
716
|
if (arg === 'help' || arg === '-h' || arg === '--help') {
|
|
716
717
|
printConfigHelp();
|
|
717
718
|
return;
|
|
718
|
-
} else if (['show', 'path', 'list', 'delete', 'edit', 'interactive'].includes(arg)) {
|
|
719
|
+
} else if (['show', 'path', 'list', 'create', 'delete', 'edit', 'interactive'].includes(arg)) {
|
|
719
720
|
action = arg === 'interactive' ? 'edit' : arg;
|
|
720
721
|
} else if (arg === '--gateway-url' || arg === '--api-key' || arg === '--model') {
|
|
721
722
|
const value = argv[++i];
|
|
@@ -754,6 +755,18 @@ export async function configCommand(argv, profileName = DEFAULT_PROFILE, options
|
|
|
754
755
|
return;
|
|
755
756
|
}
|
|
756
757
|
|
|
758
|
+
if (action === 'create') {
|
|
759
|
+
if (Object.keys(updates).length) {
|
|
760
|
+
throw new Error('config create cannot be combined with profile updates');
|
|
761
|
+
}
|
|
762
|
+
const existing = await loadProfile(profileName);
|
|
763
|
+
if (existing.exists) throw new Error(`Profile '${profileName}' already exists`);
|
|
764
|
+
const profile = await ensureProfile(profileName);
|
|
765
|
+
console.log(`Created profile '${profileName}'.`);
|
|
766
|
+
await printProfile(profile);
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
|
|
757
770
|
if (action === 'delete') {
|
|
758
771
|
if (profileName === DEFAULT_PROFILE) {
|
|
759
772
|
throw new Error('Refusing to delete the default profile; use subc logout to clear its key');
|
package/bin/tui.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
import { agentList } from './agents.js';
|
|
8
|
+
import { getApiKey } from './auth.js';
|
|
9
|
+
import { resolveModelCatalog } from './models.js';
|
|
10
|
+
import {
|
|
11
|
+
DEFAULT_PROFILE,
|
|
12
|
+
listProfiles,
|
|
13
|
+
loadProfile,
|
|
14
|
+
RUNBOOK_DEFAULTS,
|
|
15
|
+
SUPPORTED_MODELS as PACKAGED_MODELS,
|
|
16
|
+
} from './profiles.js';
|
|
17
|
+
|
|
18
|
+
const BIN_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const TUI_SOURCE_DIR = path.resolve(BIN_DIR, '../tui');
|
|
20
|
+
|
|
21
|
+
export function nativeTargetName(platform = process.platform, arch = process.arch) {
|
|
22
|
+
const goArch = { x64: 'amd64', arm64: 'arm64' }[arch];
|
|
23
|
+
if (!goArch || !['darwin', 'linux', 'win32'].includes(platform)) return null;
|
|
24
|
+
const goOS = platform === 'win32' ? 'windows' : platform;
|
|
25
|
+
const extension = platform === 'win32' ? '.exe' : '';
|
|
26
|
+
return `subc-tui-${goOS}-${goArch}${extension}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function isTuiResult(result) {
|
|
30
|
+
return (
|
|
31
|
+
result !== null &&
|
|
32
|
+
typeof result === 'object' &&
|
|
33
|
+
Array.isArray(result.args) &&
|
|
34
|
+
result.args.every((arg) => typeof arg === 'string') &&
|
|
35
|
+
(result.baseUrl === undefined || typeof result.baseUrl === 'string')
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function pathExists(file) {
|
|
40
|
+
try {
|
|
41
|
+
await fs.access(file);
|
|
42
|
+
return true;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function resolveTuiExecutable(options = {}) {
|
|
49
|
+
const override = options.binary || process.env.SUBC_TUI_BIN?.trim();
|
|
50
|
+
if (override) return { command: override, args: [], cwd: undefined };
|
|
51
|
+
|
|
52
|
+
const target = nativeTargetName(options.platform, options.arch);
|
|
53
|
+
if (target) {
|
|
54
|
+
const packaged = path.join(BIN_DIR, 'native', target);
|
|
55
|
+
if (await pathExists(packaged)) {
|
|
56
|
+
return { command: packaged, args: [], cwd: undefined };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Source checkouts can run the TUI without committing native build output.
|
|
61
|
+
// Published packages always contain a prebuilt platform binary.
|
|
62
|
+
if (await pathExists(path.join(TUI_SOURCE_DIR, 'go.mod'))) {
|
|
63
|
+
return {
|
|
64
|
+
command: 'go',
|
|
65
|
+
args: ['run', './cmd/subc-tui'],
|
|
66
|
+
cwd: TUI_SOURCE_DIR,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function selectedModelFor(profile) {
|
|
73
|
+
return (
|
|
74
|
+
process.env.SUBCONSCIOUS_MODEL?.trim() ||
|
|
75
|
+
profile.values.MODEL?.trim() ||
|
|
76
|
+
RUNBOOK_DEFAULTS.MODEL
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function gatewayFor(profile) {
|
|
81
|
+
return (
|
|
82
|
+
process.env.SUBCONSCIOUS_BASE_URL?.trim() ||
|
|
83
|
+
profile.values.GATEWAY_URL?.trim() ||
|
|
84
|
+
RUNBOOK_DEFAULTS.GATEWAY_URL
|
|
85
|
+
).replace(/\/+$/, '');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function packageVersion() {
|
|
89
|
+
const pkg = JSON.parse(
|
|
90
|
+
await fs.readFile(new URL('../package.json', import.meta.url), 'utf-8'),
|
|
91
|
+
);
|
|
92
|
+
return pkg.version;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function createTuiState(profileName = DEFAULT_PROFILE, options = {}) {
|
|
96
|
+
const activeProfile = options.profile || (await loadProfile(profileName));
|
|
97
|
+
const names = [...new Set([profileName, ...(await listProfiles())])].sort((a, b) => {
|
|
98
|
+
if (a === profileName) return -1;
|
|
99
|
+
if (b === profileName) return 1;
|
|
100
|
+
return a.localeCompare(b);
|
|
101
|
+
});
|
|
102
|
+
const profiles = await Promise.all(
|
|
103
|
+
names.map(async (name) => {
|
|
104
|
+
const profile = name === profileName ? activeProfile : await loadProfile(name);
|
|
105
|
+
const auth = await getApiKey(profile);
|
|
106
|
+
return {
|
|
107
|
+
name,
|
|
108
|
+
model: selectedModelFor(profile),
|
|
109
|
+
authenticated: Boolean(auth?.key),
|
|
110
|
+
};
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const auth = await getApiKey(activeProfile);
|
|
115
|
+
const selectedModel = selectedModelFor(activeProfile);
|
|
116
|
+
const gatewayUrl = gatewayFor(activeProfile);
|
|
117
|
+
const catalog = await resolveModelCatalog({
|
|
118
|
+
baseUrl: gatewayUrl,
|
|
119
|
+
apiKey: auth?.key,
|
|
120
|
+
selectedModel,
|
|
121
|
+
fallbackModels: PACKAGED_MODELS,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
version: await packageVersion(),
|
|
126
|
+
activeProfile: profileName,
|
|
127
|
+
profilePath: activeProfile.path,
|
|
128
|
+
profiles,
|
|
129
|
+
models: catalog.models,
|
|
130
|
+
selectedModel,
|
|
131
|
+
gatewayUrl,
|
|
132
|
+
savedGatewayUrl:
|
|
133
|
+
activeProfile.values.GATEWAY_URL?.trim().replace(/\/+$/, '') ||
|
|
134
|
+
RUNBOOK_DEFAULTS.GATEWAY_URL,
|
|
135
|
+
gatewayOverridden: Boolean(process.env.SUBCONSCIOUS_BASE_URL?.trim()),
|
|
136
|
+
modelError: catalog.error?.message || '',
|
|
137
|
+
agents: agentList().map((agent) => ({
|
|
138
|
+
command: agent.alias,
|
|
139
|
+
name: agent.name,
|
|
140
|
+
action: agent.action,
|
|
141
|
+
description: agent.description,
|
|
142
|
+
launch: agent.launch,
|
|
143
|
+
})),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function spawnAndWait(command, args, options = {}) {
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
const child = spawn(command, args, {
|
|
150
|
+
cwd: options.cwd,
|
|
151
|
+
env: process.env,
|
|
152
|
+
stdio: 'inherit',
|
|
153
|
+
});
|
|
154
|
+
child.once('error', reject);
|
|
155
|
+
child.once('exit', (code, signal) => {
|
|
156
|
+
if (signal) {
|
|
157
|
+
reject(new Error(`Subconscious TUI exited with signal ${signal}`));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
resolve(code ?? 1);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export async function runTui(options = {}) {
|
|
166
|
+
const executable = await resolveTuiExecutable(options);
|
|
167
|
+
if (!executable) return null;
|
|
168
|
+
|
|
169
|
+
const state = options.state || (await createTuiState(options.profileName, options));
|
|
170
|
+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'subc-tui-'));
|
|
171
|
+
const statePath = path.join(tempDir, 'state.json');
|
|
172
|
+
const resultPath = path.join(tempDir, 'result.json');
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
// This state intentionally contains only display data. API keys are used
|
|
176
|
+
// by the Node command engine and are never passed into the TUI process.
|
|
177
|
+
await fs.writeFile(statePath, `${JSON.stringify(state)}\n`, { mode: 0o600 });
|
|
178
|
+
const code = await spawnAndWait(
|
|
179
|
+
executable.command,
|
|
180
|
+
[...executable.args, '--state', statePath, '--result', resultPath],
|
|
181
|
+
{ cwd: executable.cwd },
|
|
182
|
+
);
|
|
183
|
+
if (code !== 0) throw new Error(`Subconscious TUI exited with status ${code}`);
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
const result = JSON.parse(await fs.readFile(resultPath, 'utf-8'));
|
|
187
|
+
return isTuiResult(result) ? result : null;
|
|
188
|
+
} catch (error) {
|
|
189
|
+
if (error.code === 'ENOENT') return null;
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
} finally {
|
|
193
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
194
|
+
}
|
|
195
|
+
}
|
package/bin/update-check.js
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
3
|
import readline from 'node:readline';
|
|
4
|
+
import { LOGO_ART_SMALL_LINES } from './branding.js';
|
|
4
5
|
import { c, colorEnabled } from './colors.js';
|
|
5
6
|
|
|
6
7
|
export const PACKAGE_NAME = 'subconscious-cli';
|
|
7
8
|
export const UPDATE_CHECK_TIMEOUT_MS = 1500;
|
|
8
9
|
const UPDATE_ACTIONS = ['Update now', 'Skip for now'];
|
|
9
|
-
const UPDATE_LOGO =
|
|
10
|
-
' ● ●',
|
|
11
|
-
' ╲ ╱ ',
|
|
12
|
-
'●─── ╳ ───●',
|
|
13
|
-
' ╱ ╲ ',
|
|
14
|
-
' ● ●',
|
|
15
|
-
];
|
|
10
|
+
const UPDATE_LOGO = LOGO_ART_SMALL_LINES;
|
|
16
11
|
|
|
17
12
|
function parseVersion(version) {
|
|
18
13
|
const match = String(version)
|
|
@@ -94,11 +89,16 @@ export async function fetchLatestVersion(options = {}) {
|
|
|
94
89
|
export function renderUpdateNotice(installedVersion, latestVersion) {
|
|
95
90
|
const logoWidth = Math.max(...UPDATE_LOGO.map((line) => line.length));
|
|
96
91
|
const textWidth = 24;
|
|
97
|
-
const gap = '
|
|
92
|
+
const gap = ' ';
|
|
98
93
|
const innerWidth = logoWidth + gap.length + textWidth + 2;
|
|
99
94
|
const border = `${c.orange}╭${'─'.repeat(innerWidth)}╮${c.reset}`;
|
|
100
95
|
const bottom = `${c.orange}╰${'─'.repeat(innerWidth)}╯${c.reset}`;
|
|
96
|
+
// Match SC's splash composition by bottom-aligning the copy beside the
|
|
97
|
+
// eight-row logo, with a two-cell gutter between the two columns.
|
|
101
98
|
const text = [
|
|
99
|
+
{ raw: '', value: '' },
|
|
100
|
+
{ raw: '', value: '' },
|
|
101
|
+
{ raw: '', value: '' },
|
|
102
102
|
{ raw: 'Subconscious CLI', value: `${c.orange}${c.bold}Subconscious CLI${c.reset}` },
|
|
103
103
|
{ raw: 'Update available', value: `${c.bold}Update available${c.reset}` },
|
|
104
104
|
{ raw: '', value: '' },
|
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "subconscious-cli",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.7",
|
|
4
4
|
"description": "CLI for Subconscious — run Claude Code, Codex, OpenCode, DeepSeek Harness, Cursor, Copilot, and Pi",
|
|
5
5
|
"bin": {
|
|
6
6
|
"subc": "bin/cli.js"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
|
-
"
|
|
9
|
+
"build:tui": "node scripts/build-tui.js",
|
|
10
|
+
"build:tui:host": "node scripts/build-tui.js --host",
|
|
11
|
+
"test": "node --test",
|
|
12
|
+
"test:tui": "go -C tui test ./...",
|
|
13
|
+
"prepack": "npm run build:tui"
|
|
10
14
|
},
|
|
11
15
|
"files": [
|
|
12
16
|
"bin"
|