@aitherium/shell-cli 1.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.
- package/dist/auth.d.ts +68 -0
- package/dist/auth.js +288 -0
- package/dist/client.d.ts +116 -0
- package/dist/client.js +528 -0
- package/dist/command-registry.d.ts +71 -0
- package/dist/command-registry.js +223 -0
- package/dist/commands.d.ts +14 -0
- package/dist/commands.js +6785 -0
- package/dist/completions.d.ts +27 -0
- package/dist/completions.js +351 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.js +48 -0
- package/dist/gargbot.d.ts +11 -0
- package/dist/gargbot.js +230 -0
- package/dist/jobs.d.ts +65 -0
- package/dist/jobs.js +386 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +389 -0
- package/dist/notebooks.d.ts +19 -0
- package/dist/notebooks.js +685 -0
- package/dist/products.d.ts +12 -0
- package/dist/products.js +159 -0
- package/dist/renderer.d.ts +104 -0
- package/dist/renderer.js +1812 -0
- package/dist/repl.d.ts +16 -0
- package/dist/repl.js +1190 -0
- package/dist/session-store.d.ts +35 -0
- package/dist/session-store.js +153 -0
- package/dist/tunnel.d.ts +13 -0
- package/dist/tunnel.js +169 -0
- package/package.json +36 -0
package/dist/main.js
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Trust AitherOS self-signed TLS certs without disabling all verification.
|
|
3
|
+
// Prefer NODE_EXTRA_CA_CERTS (adds our CA to the trust chain) if available;
|
|
4
|
+
// only fall back to NODE_TLS_REJECT_UNAUTHORIZED=0 when no CA chain exists.
|
|
5
|
+
import { existsSync } from 'fs';
|
|
6
|
+
import { join, basename } from 'path';
|
|
7
|
+
const _caChainPaths = [
|
|
8
|
+
join(process.env.HOME || process.env.USERPROFILE || '', '.aither', 'tls', 'ca-chain.pem'),
|
|
9
|
+
join(process.env.AITHEROS_ROOT || '', 'Library', 'Data', 'tls', 'ca-chain.pem'),
|
|
10
|
+
'/app/AitherOS/Library/Data/tls/ca-chain.pem',
|
|
11
|
+
];
|
|
12
|
+
const _caChain = _caChainPaths.find(p => p && existsSync(p));
|
|
13
|
+
if (_caChain) {
|
|
14
|
+
process.env.NODE_EXTRA_CA_CERTS = _caChain;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
// No CA chain found — disable verification as last resort (suppress warning via env)
|
|
18
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* AitherShell CLI — interactive terminal for AitherOS.
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* aither-shell Interactive REPL
|
|
25
|
+
* aither-shell "question" One-shot mode
|
|
26
|
+
* aither-shell -c status Execute slash command and exit
|
|
27
|
+
* aither-shell -f "task" Forge dispatch and exit
|
|
28
|
+
* aither-shell --help Show help
|
|
29
|
+
*/
|
|
30
|
+
import chalk from 'chalk';
|
|
31
|
+
import { readFileSync } from 'fs';
|
|
32
|
+
import { extname } from 'path';
|
|
33
|
+
import { loadConfig } from './config.js';
|
|
34
|
+
import { GenesisClient } from './client.js';
|
|
35
|
+
import { renderBanner, createStreamRenderer } from './renderer.js';
|
|
36
|
+
import { startRepl } from './repl.js';
|
|
37
|
+
const VERSION = '1.1.0';
|
|
38
|
+
async function main() {
|
|
39
|
+
const args = process.argv.slice(2);
|
|
40
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
41
|
+
printUsage();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
45
|
+
console.log(`aither-shell ${VERSION}`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const config = loadConfig();
|
|
49
|
+
const client = new GenesisClient(config.genesisUrl);
|
|
50
|
+
// Wire auth token from config to client
|
|
51
|
+
if (config.authToken) {
|
|
52
|
+
client.setAuthToken(config.authToken, config.authUser?.tenant_id ?? null, config.authUser?.id ?? null);
|
|
53
|
+
}
|
|
54
|
+
// Handle --login and --key flags for non-interactive auth
|
|
55
|
+
const loginIdx = args.indexOf('--login');
|
|
56
|
+
const keyIdx = args.indexOf('--key');
|
|
57
|
+
if (keyIdx >= 0 && args[keyIdx + 1]) {
|
|
58
|
+
const { validateToken: valToken, buildProfile, setProfile } = await import('./auth.js');
|
|
59
|
+
const token = args[keyIdx + 1];
|
|
60
|
+
const user = await valToken(config.identityUrl, token);
|
|
61
|
+
if (user) {
|
|
62
|
+
const profile = buildProfile(config.identityUrl, config.genesisUrl, {
|
|
63
|
+
access_token: token, token_type: 'api_key', user,
|
|
64
|
+
});
|
|
65
|
+
setProfile('local', profile);
|
|
66
|
+
config.authToken = token;
|
|
67
|
+
config.authUser = profile.user;
|
|
68
|
+
client.setAuthToken(token, profile.user.tenant_id || null, profile.user.id || null);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
console.error(chalk.red('Invalid API key'));
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Parse creative flags (--will, --safety, --private, --effort) early
|
|
76
|
+
// so they apply to both runOneShot and positional one-shot chat.
|
|
77
|
+
for (let i = 0; i < args.length; i++) {
|
|
78
|
+
if ((args[i] === '--will' || args[i] === '--agent' || args[i] === '-a') && args[i + 1]) {
|
|
79
|
+
config.defaultAgent = args[i + 1];
|
|
80
|
+
}
|
|
81
|
+
else if ((args[i] === '--effort' || args[i] === '-e') && args[i + 1]) {
|
|
82
|
+
config.effort = Number(args[i + 1]);
|
|
83
|
+
}
|
|
84
|
+
else if ((args[i] === '--safety' || args[i] === '-s') && args[i + 1]) {
|
|
85
|
+
config.safetyLevel = args[i + 1];
|
|
86
|
+
}
|
|
87
|
+
else if (args[i] === '--private') {
|
|
88
|
+
config.privateMode = true;
|
|
89
|
+
}
|
|
90
|
+
else if ((args[i] === '--image' || args[i] === '-i') && args[i + 1]) {
|
|
91
|
+
const imgPath = args[++i];
|
|
92
|
+
try {
|
|
93
|
+
const buf = readFileSync(imgPath);
|
|
94
|
+
const ext = extname(imgPath).toLowerCase().replace('.', '');
|
|
95
|
+
const mimeMap = { jpg: 'jpeg', jpeg: 'jpeg', png: 'png', gif: 'gif', webp: 'webp', bmp: 'bmp' };
|
|
96
|
+
const mime = mimeMap[ext] || 'png';
|
|
97
|
+
const dataUrl = `data:image/${mime};base64,${buf.toString('base64')}`;
|
|
98
|
+
config.imageAttachments = config.imageAttachments || [];
|
|
99
|
+
config.imageAttachments.push(dataUrl);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
console.error(chalk.red(`Cannot read image: ${imgPath} — ${err.message}`));
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// If invoked as "aither-install" (binary name contains "install"), run install flow directly
|
|
108
|
+
const binaryName = process.argv[1] ? basename(process.argv[1]).toLowerCase() : '';
|
|
109
|
+
if (binaryName.includes('install') && !args.includes('-c') && !args.includes('--command')) {
|
|
110
|
+
const { getCommand } = await import('./commands.js');
|
|
111
|
+
const installCmd = getCommand('install');
|
|
112
|
+
if (installCmd) {
|
|
113
|
+
await installCmd.handler(client, args.join(' '), config);
|
|
114
|
+
process.exit(0);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Try non-interactive (flag-based) execution first
|
|
118
|
+
const handled = await runOneShot(client, config);
|
|
119
|
+
if (handled)
|
|
120
|
+
process.exit(0);
|
|
121
|
+
// Collect positional args (everything before first -- flag)
|
|
122
|
+
const positional = [];
|
|
123
|
+
for (const arg of args) {
|
|
124
|
+
if (arg.startsWith('-'))
|
|
125
|
+
break;
|
|
126
|
+
positional.push(arg);
|
|
127
|
+
}
|
|
128
|
+
if (positional.length > 0) {
|
|
129
|
+
await oneShotChat(client, config, positional.join(' '));
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
await showBanner(client, config);
|
|
133
|
+
await startRepl(client, config);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/* ── Banner with live status ────────────────────────────────── */
|
|
137
|
+
async function showBanner(client, config) {
|
|
138
|
+
const backend = await client.detectBackend();
|
|
139
|
+
// Propagate detected backend into config for downstream use
|
|
140
|
+
config.backendType = backend.type;
|
|
141
|
+
config.backendName = backend.name;
|
|
142
|
+
const genesisOnline = backend.type !== 'unknown';
|
|
143
|
+
let llm;
|
|
144
|
+
const serviceLines = [];
|
|
145
|
+
if (backend.type === 'genesis') {
|
|
146
|
+
// Genesis-specific status enrichment
|
|
147
|
+
try {
|
|
148
|
+
const statusData = await client.getStatus().catch(() => null);
|
|
149
|
+
const pain = statusData?.children_in_pain || [];
|
|
150
|
+
if (statusData) {
|
|
151
|
+
serviceLines.push({ name: 'Node', up: !pain.includes('Node') && !pain.includes('AitherNode') });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch { }
|
|
155
|
+
if (backend.generationReady === false) {
|
|
156
|
+
llm = 'BUSY (no slots)';
|
|
157
|
+
}
|
|
158
|
+
else if (backend.generationReady === true) {
|
|
159
|
+
llm = backend.slotsAvailable != null ? `LLM ready (${backend.slotsAvailable} slots)` : 'LLM ready';
|
|
160
|
+
}
|
|
161
|
+
else if (backend.llmBackend) {
|
|
162
|
+
llm = backend.llmBackend;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else if (backend.type === 'adk') {
|
|
166
|
+
llm = backend.llmBackend || undefined;
|
|
167
|
+
}
|
|
168
|
+
const host = (() => {
|
|
169
|
+
try {
|
|
170
|
+
return new URL(config.genesisUrl).host;
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return config.genesisUrl;
|
|
174
|
+
}
|
|
175
|
+
})();
|
|
176
|
+
const authUser = config.authUser?.display_name || config.authUser?.username;
|
|
177
|
+
renderBanner({
|
|
178
|
+
genesis: host,
|
|
179
|
+
genesisOnline,
|
|
180
|
+
services: backend.services,
|
|
181
|
+
agents: backend.agents,
|
|
182
|
+
llm,
|
|
183
|
+
user: authUser,
|
|
184
|
+
serviceLines,
|
|
185
|
+
backendType: backend.type,
|
|
186
|
+
backendName: backend.name,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
/* ── Non-interactive mode (flag-based) ────────────────────── */
|
|
190
|
+
async function runOneShot(client, config) {
|
|
191
|
+
const args = process.argv.slice(2);
|
|
192
|
+
// Parse flags
|
|
193
|
+
let command;
|
|
194
|
+
let forgeTask;
|
|
195
|
+
let agent;
|
|
196
|
+
let effort;
|
|
197
|
+
let safetyLevel;
|
|
198
|
+
let privateMode = false;
|
|
199
|
+
let chatMessage;
|
|
200
|
+
for (let i = 0; i < args.length; i++) {
|
|
201
|
+
const arg = args[i];
|
|
202
|
+
if ((arg === '--command' || arg === '-c') && args[i + 1]) {
|
|
203
|
+
// Collect command name + everything after it until next flag as args
|
|
204
|
+
// e.g. -c "run list scale" → command="run list scale"
|
|
205
|
+
// -c run list scale → command="run list scale"
|
|
206
|
+
const next = args[++i];
|
|
207
|
+
// If the next arg is already quoted (contains spaces), use it as-is
|
|
208
|
+
// Otherwise collect remaining non-flag args
|
|
209
|
+
if (next.includes(' ')) {
|
|
210
|
+
command = next;
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
const cmdParts = [next];
|
|
214
|
+
while (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
215
|
+
cmdParts.push(args[++i]);
|
|
216
|
+
}
|
|
217
|
+
command = cmdParts.join(' ');
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else if ((arg === '--forge' || arg === '-f') && args[i + 1]) {
|
|
221
|
+
forgeTask = args[++i];
|
|
222
|
+
}
|
|
223
|
+
else if ((arg === '--agent' || arg === '-a' || arg === '--will') && args[i + 1]) {
|
|
224
|
+
agent = args[++i];
|
|
225
|
+
}
|
|
226
|
+
else if ((arg === '--effort' || arg === '-e') && args[i + 1]) {
|
|
227
|
+
effort = Number(args[++i]);
|
|
228
|
+
}
|
|
229
|
+
else if ((arg === '--safety' || arg === '-s') && args[i + 1]) {
|
|
230
|
+
safetyLevel = args[++i];
|
|
231
|
+
}
|
|
232
|
+
else if (arg === '--private') {
|
|
233
|
+
privateMode = true;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// No flag-based one-shot arguments — return false to fall through
|
|
237
|
+
if (!command && !forgeTask)
|
|
238
|
+
return false;
|
|
239
|
+
// Override config agent if --agent was provided
|
|
240
|
+
if (agent)
|
|
241
|
+
config.defaultAgent = agent;
|
|
242
|
+
try {
|
|
243
|
+
if (command) {
|
|
244
|
+
// Execute slash command — split "run list scale" into name="run" cmdArgs="list scale"
|
|
245
|
+
const { getCommand } = await import('./commands.js');
|
|
246
|
+
const spaceIdx = command.indexOf(' ');
|
|
247
|
+
const cmdName = spaceIdx === -1 ? command : command.slice(0, spaceIdx);
|
|
248
|
+
const cmdArgs = spaceIdx === -1 ? '' : command.slice(spaceIdx + 1);
|
|
249
|
+
const cmd = getCommand(cmdName);
|
|
250
|
+
if (cmd) {
|
|
251
|
+
await cmd.handler(client, cmdArgs, config);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
console.error(chalk.red(`Unknown command: ${cmdName}`));
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
else if (forgeTask) {
|
|
259
|
+
// Dispatch via forge
|
|
260
|
+
const result = await client.forgeDispatch(forgeTask, {
|
|
261
|
+
agent: agent || config.defaultAgent,
|
|
262
|
+
effort,
|
|
263
|
+
});
|
|
264
|
+
const output = result?.response || result?.result || result?.output;
|
|
265
|
+
if (output) {
|
|
266
|
+
console.log(output);
|
|
267
|
+
}
|
|
268
|
+
else if (result?.error) {
|
|
269
|
+
console.error(chalk.red(`Error: ${result.error}`));
|
|
270
|
+
process.exit(1);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
console.log(JSON.stringify(result, null, 2));
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
/* ── One-shot chat (positional args) ─────────────────────── */
|
|
284
|
+
async function oneShotChat(client, config, message) {
|
|
285
|
+
const renderer = createStreamRenderer();
|
|
286
|
+
let failed = false;
|
|
287
|
+
try {
|
|
288
|
+
for await (const event of client.streamChat(message, {
|
|
289
|
+
agent: config.defaultAgent,
|
|
290
|
+
sessionId: config.sessionId,
|
|
291
|
+
model: config.model,
|
|
292
|
+
effort: config.effort,
|
|
293
|
+
safetyLevel: config.safetyLevel,
|
|
294
|
+
privateMode: config.privateMode,
|
|
295
|
+
attachments: config.imageAttachments,
|
|
296
|
+
})) {
|
|
297
|
+
renderer.onEvent(event);
|
|
298
|
+
}
|
|
299
|
+
renderer.finish();
|
|
300
|
+
}
|
|
301
|
+
catch (err) {
|
|
302
|
+
if (err.name === 'AbortError')
|
|
303
|
+
return;
|
|
304
|
+
failed = true;
|
|
305
|
+
const msg = err.message || 'unknown error';
|
|
306
|
+
if (msg.includes('took too long')) {
|
|
307
|
+
console.error(chalk.yellow(msg));
|
|
308
|
+
console.error(chalk.dim('Try: docker compose -f docker-compose.aitheros.yml --profile chat-full up -d'));
|
|
309
|
+
}
|
|
310
|
+
else if (msg.includes('Cannot connect') || msg.includes('ECONNREFUSED') || msg.includes('fetch failed')) {
|
|
311
|
+
console.error(chalk.red(`Backend not reachable at ${config.genesisUrl}`));
|
|
312
|
+
console.error(chalk.dim('Start Genesis: docker compose -f docker-compose.aitheros.yml --profile chat-minimal up -d'));
|
|
313
|
+
console.error(chalk.dim(' Or ADK: adk serve --identity <agent>'));
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
console.error(chalk.red(`Error: ${msg}`));
|
|
317
|
+
}
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
/* ── Help ───────────────────────────────────────────────────── */
|
|
322
|
+
function printUsage() {
|
|
323
|
+
console.log(`
|
|
324
|
+
${chalk.bold('aither')} \u2014 AitherOS interactive terminal
|
|
325
|
+
|
|
326
|
+
${chalk.bold('Usage:')}
|
|
327
|
+
aither Start interactive REPL
|
|
328
|
+
aither "message" One-shot: send, print, exit
|
|
329
|
+
aither -c <command> Execute a slash command and exit
|
|
330
|
+
aither -f <task> Forge dispatch and exit
|
|
331
|
+
aither --help Show this help
|
|
332
|
+
aither --version Show version
|
|
333
|
+
|
|
334
|
+
${chalk.bold('One-shot flags:')}
|
|
335
|
+
-c, --command <cmd> Execute slash command (status, agents, services, gaming, apps, etc.)
|
|
336
|
+
-f, --forge <task> Dispatch task via Forge
|
|
337
|
+
-a, --agent <name> Agent for chat/forge (default: aither)
|
|
338
|
+
--will <name> Alias for --agent (e.g. --will iris)
|
|
339
|
+
-e, --effort <N> Effort level 1-10 (higher = deeper/quality)
|
|
340
|
+
-s, --safety <level> Safety: unrestricted, casual, professional
|
|
341
|
+
--private Private mode (prompt hidden from logs/training)
|
|
342
|
+
-i, --image <path> Attach image for vision analysis (repeatable)
|
|
343
|
+
|
|
344
|
+
${chalk.bold('Quick actions:')}
|
|
345
|
+
aither -c gaming Toggle gaming mode (free VRAM for games)
|
|
346
|
+
aither -c "gaming on" Activate gaming mode
|
|
347
|
+
aither -c apps Show all AitherOS app statuses
|
|
348
|
+
aither -c "apps install desktop" Install AitherDesktop
|
|
349
|
+
aither -c "apps start veil" Start AitherVeil dashboard
|
|
350
|
+
|
|
351
|
+
${chalk.bold('Examples:')}
|
|
352
|
+
aither -c status Print system status and exit
|
|
353
|
+
aither -c agents List agents and exit
|
|
354
|
+
aither -f "refactor auth module" -a demiurge -e 7
|
|
355
|
+
aither "What services are running?"
|
|
356
|
+
aither --will iris "draw a cyberpunk cityscape"
|
|
357
|
+
aither --will iris -e 8 "masterpiece portrait, 8k"
|
|
358
|
+
aither --will iris --safety unrestricted --private "private prompt"
|
|
359
|
+
aither --will saga "tell me about the ancient ruins"
|
|
360
|
+
aither --image screenshot.png "what's in this image?"
|
|
361
|
+
aither -i photo.jpg -i diagram.png "compare these two"
|
|
362
|
+
|
|
363
|
+
${chalk.bold('Environment variables:')}
|
|
364
|
+
AITHER_API_URL Backend URL (Genesis or ADK server)
|
|
365
|
+
AITHER_GENESIS_URL Legacy alias for AITHER_API_URL
|
|
366
|
+
AITHER_AGENT Default agent (default: aither)
|
|
367
|
+
AITHER_MODEL LLM model override
|
|
368
|
+
|
|
369
|
+
${chalk.bold('Config file:')}
|
|
370
|
+
~/.aither/shell.yaml Optional (api_url, default_agent, model)
|
|
371
|
+
|
|
372
|
+
${chalk.bold('Interactive commands:')}
|
|
373
|
+
/help Show all commands /agents List agents
|
|
374
|
+
/status System status /services List services
|
|
375
|
+
/forge Dispatch to Forge /logs View logs
|
|
376
|
+
/gaming Toggle gaming mode /apps Manage AitherOS apps
|
|
377
|
+
/sessions List recent sessions /resume Resume a session
|
|
378
|
+
/model Show/set model /clear Clear screen
|
|
379
|
+
exit Quit
|
|
380
|
+
|
|
381
|
+
${chalk.bold('Routing:')}
|
|
382
|
+
@agent_name message Route to specific agent
|
|
383
|
+
message Route to default agent
|
|
384
|
+
`);
|
|
385
|
+
}
|
|
386
|
+
main().catch((err) => {
|
|
387
|
+
console.error(chalk.red(`Fatal: ${err.message}`));
|
|
388
|
+
process.exit(1);
|
|
389
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Notebook interactive TUI for AitherShell CLI.
|
|
3
|
+
*
|
|
4
|
+
* Provides a proper interactive notebook experience in the terminal:
|
|
5
|
+
* /nb list — Browse notebooks with status/effort/tags
|
|
6
|
+
* /nb open <id> — Open interactive session (cell-by-cell execution)
|
|
7
|
+
* /nb run <id> — Execute entire notebook (streaming output)
|
|
8
|
+
* /nb plan <prompt> — Create notebook from natural language
|
|
9
|
+
* /nb create <name> — Create empty notebook
|
|
10
|
+
* /nb templates — List available templates
|
|
11
|
+
* /nb sessions — List active sessions
|
|
12
|
+
*
|
|
13
|
+
* The interactive session (/nb open) renders cells with box-drawing
|
|
14
|
+
* characters, colored output, and supports Shift+Enter / Enter to
|
|
15
|
+
* execute cells one at a time.
|
|
16
|
+
*/
|
|
17
|
+
import type { GenesisClient } from './client.js';
|
|
18
|
+
import type { ShellConfig } from './config.js';
|
|
19
|
+
export declare function handleNotebook(client: GenesisClient, args: string, _config: ShellConfig): Promise<void>;
|