@causyne/agent 1.10.1 → 1.10.6
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 +6 -0
- package/docs/THIRD_PARTY_NOTICES.md +11 -17
- package/package.json +3 -10
- package/src/cliMode.js +51 -16
- package/src/commands.js +19 -4
- package/src/entrypoint.js +24 -0
- package/src/sandbox.js +17 -39
- package/src/tui/ask.js +2 -2
- package/src/tui/banner.js +56 -11
- package/src/tui/dialogs.js +14 -6
- package/src/tui/home.js +1 -1
- package/src/tui/invocation.js +2 -0
- package/src/tui/keys.js +11 -0
- package/src/tui/prompt.js +26 -18
- package/src/tui/theme.js +26 -24
- package/src/utils/inquirer.js +0 -12
package/README.md
CHANGED
|
@@ -12,6 +12,12 @@ documentation is intentionally concise while the project is evolving.
|
|
|
12
12
|
|
|
13
13
|
Learn more at [causyne.com](https://causyne.com/).
|
|
14
14
|
|
|
15
|
+
## Contact
|
|
16
|
+
|
|
17
|
+
- General inquiries and business communication: [contact@causyne.com](mailto:contact@causyne.com)
|
|
18
|
+
- Product support and troubleshooting: [help@causyne.com](mailto:help@causyne.com)
|
|
19
|
+
- Partnerships and direct founder communication: [ikbal@causyne.com](mailto:ikbal@causyne.com)
|
|
20
|
+
|
|
15
21
|
## Development
|
|
16
22
|
|
|
17
23
|
Node.js 24 or newer is required.
|
|
@@ -9,23 +9,17 @@ license identifiers:
|
|
|
9
9
|
|
|
10
10
|
| License expression | Lockfile package entries |
|
|
11
11
|
| --- | ---: |
|
|
12
|
-
|
|
|
13
|
-
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
development dependencies account for the differing views of the graph.
|
|
24
|
-
|
|
25
|
-
The direct runtime dependencies are `@babel/parser`, `acorn-walk`, `commander`,
|
|
26
|
-
`duck-duck-scrape`, `googlethis`, and `inquirer`. Direct
|
|
27
|
-
development dependencies are `@types/node`, `acorn`, and `typescript`. Exact
|
|
28
|
-
versions and integrity hashes are recorded in `package-lock.json`.
|
|
12
|
+
| Apache-2.0 | 21 |
|
|
13
|
+
| MIT | 9 |
|
|
14
|
+
|
|
15
|
+
The lockfile contained 30 dependency entries in total. Three are production
|
|
16
|
+
entries; development and platform-specific optional entries account for the
|
|
17
|
+
rest. npm's audit metadata reported 12 installed packages.
|
|
18
|
+
|
|
19
|
+
The direct runtime dependencies are `acorn-walk` and `commander`. Direct
|
|
20
|
+
development dependencies are `@babel/parser`, `@types/node`, `acorn`, and
|
|
21
|
+
`typescript`. Exact versions and integrity hashes are recorded in
|
|
22
|
+
`package-lock.json`.
|
|
29
23
|
|
|
30
24
|
No dependency in the reviewed main lockfile was marked with an install script.
|
|
31
25
|
Optional capability dependencies are installed only after approval into a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@causyne/agent",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.6",
|
|
4
4
|
"description": "Agentic AI for software, tools, and computer workflows",
|
|
5
5
|
"main": "bin/causyne.js",
|
|
6
6
|
"type": "module",
|
|
@@ -49,19 +49,12 @@
|
|
|
49
49
|
"bugs": {
|
|
50
50
|
"url": "https://github.com/ikbal-causyne/causyne-agent/issues"
|
|
51
51
|
},
|
|
52
|
-
"overrides": {
|
|
53
|
-
"form-data": "^4.0.0",
|
|
54
|
-
"axios": "^1.20.0"
|
|
55
|
-
},
|
|
56
52
|
"dependencies": {
|
|
57
|
-
"@babel/parser": "^8.0.4",
|
|
58
53
|
"acorn-walk": "^8.3.5",
|
|
59
|
-
"commander": "^11.1.0"
|
|
60
|
-
"duck-duck-scrape": "^2.2.7",
|
|
61
|
-
"googlethis": "^1.8.0",
|
|
62
|
-
"inquirer": "^9.2.12"
|
|
54
|
+
"commander": "^11.1.0"
|
|
63
55
|
},
|
|
64
56
|
"devDependencies": {
|
|
57
|
+
"@babel/parser": "^8.0.7",
|
|
65
58
|
"@types/node": "^22.20.2",
|
|
66
59
|
"acorn": "^8.18.0",
|
|
67
60
|
"typescript": "^7.0.2"
|
package/src/cliMode.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AgentLoop } from './agentLoop.js';
|
|
2
2
|
import { loadConfig, saveConfig } from './config.js';
|
|
3
|
-
import inquirer from './utils/inquirer.js';
|
|
4
3
|
import readline from 'readline';
|
|
5
4
|
import { ChatPrompt, isInteractive } from './tui/prompt.js';
|
|
6
5
|
import { handleInput, listCommands, isCommandInput } from './commands.js';
|
|
@@ -12,6 +11,7 @@ import { wrapBlock } from './tui/text.js';
|
|
|
12
11
|
import { getPackageVersion } from './version.js';
|
|
13
12
|
import { resolveCharPool } from './contextManager.js';
|
|
14
13
|
import { PRIMARY_ACTIONS, homeStatusLine, homeHint, moreLayer, configureInPrompt, mcpPicker, PROVIDERS } from './tui/home.js';
|
|
14
|
+
import { SelectLayer } from './tui/dialogs.js';
|
|
15
15
|
import { askSelect, askText, askConfirm } from './tui/ask.js';
|
|
16
16
|
import { renderReport } from './reporting.js';
|
|
17
17
|
import { grantAlways } from './approvalGrants.js';
|
|
@@ -78,7 +78,7 @@ function makeApprovalHandler(conn, dialogs = null) {
|
|
|
78
78
|
conn.stopSpinner();
|
|
79
79
|
|
|
80
80
|
// An interactive session asks in a panel that shows the risk, the arguments
|
|
81
|
-
// and a scrollable diff in one frame. The
|
|
81
|
+
// and a scrollable diff in one frame. The plain fallback asks the same
|
|
82
82
|
// question in the scrollback, which is all a non-TTY session can do.
|
|
83
83
|
if (dialogs && detail) {
|
|
84
84
|
// Loops only for "Allow always" → Cancel: backing out of the standing
|
|
@@ -100,7 +100,11 @@ function makeApprovalHandler(conn, dialogs = null) {
|
|
|
100
100
|
// The text says exactly what is being given up and for how long.
|
|
101
101
|
const confirmed = await dialogs.confirm(
|
|
102
102
|
`Allow ${bold(detail.tool)} to run WITHOUT asking, for the rest of this session?\n`
|
|
103
|
-
+ ` This lasts until Causyne restarts. Undo it any time with /approvals clear
|
|
103
|
+
+ ` This lasts until Causyne restarts. Undo it any time with /approvals clear.`,
|
|
104
|
+
// Reaching this question already required moving onto Allow always
|
|
105
|
+
// and pressing Enter. A second Enter is therefore an explicit second
|
|
106
|
+
// confirmation, rather than a reflex approval on the first dialog.
|
|
107
|
+
{ defaultAnswer: true }
|
|
104
108
|
);
|
|
105
109
|
if (confirmed) break;
|
|
106
110
|
// Cancelled: ask again rather than denying something they never rejected.
|
|
@@ -139,7 +143,7 @@ function makeApprovalHandler(conn, dialogs = null) {
|
|
|
139
143
|
|
|
140
144
|
// No live region to draw a panel into (a piped session, or raw mode
|
|
141
145
|
// refused). askConfirm degrades to readline on its own, so this path keeps
|
|
142
|
-
// the same wording as the panel instead of
|
|
146
|
+
// the same wording as the panel instead of a second prompt framework's.
|
|
143
147
|
const approved = await askConfirm(message);
|
|
144
148
|
|
|
145
149
|
if (conn.pendingApprovals) conn.pendingApprovals.delete(toolCallId);
|
|
@@ -322,7 +326,7 @@ export async function chatMode({ home = false } = {}) {
|
|
|
322
326
|
// The prompt owns the keyboard so the chat can offer history, completion and
|
|
323
327
|
// typing while a turn runs. It is skipped when stdin is not a terminal (piped
|
|
324
328
|
// input, CI) or when CAUSYNE_SIMPLE_INPUT=1, and any failure to take raw mode
|
|
325
|
-
// falls back to the
|
|
329
|
+
// falls back to the plain readline path below — a better editor must never be the
|
|
326
330
|
// reason chat refuses to start.
|
|
327
331
|
let prompt = null;
|
|
328
332
|
if (isInteractive()) {
|
|
@@ -349,8 +353,8 @@ export async function chatMode({ home = false } = {}) {
|
|
|
349
353
|
root: process.cwd(),
|
|
350
354
|
commands: listCommands('terminal'),
|
|
351
355
|
// The rule for "is this a command" lives in commands.js and is handed
|
|
352
|
-
// down rather than reimplemented, so the prompt
|
|
353
|
-
//
|
|
356
|
+
// down rather than reimplemented, so the prompt keeps `/usage` out of
|
|
357
|
+
// the conversation instead of drawing it as something the user said.
|
|
354
358
|
isCommand: isCommandInput,
|
|
355
359
|
surface,
|
|
356
360
|
onInterrupt: () => loop.abort(),
|
|
@@ -367,9 +371,9 @@ export async function chatMode({ home = false } = {}) {
|
|
|
367
371
|
// one that was asked for.
|
|
368
372
|
if (surface) prompt.draw();
|
|
369
373
|
|
|
370
|
-
// Ask for approval in the prompt's own panel, not
|
|
374
|
+
// Ask for approval in the prompt's own panel, not a competing reader.
|
|
371
375
|
//
|
|
372
|
-
//
|
|
376
|
+
// A second prompt reader would take stdin while this prompt already holds it in
|
|
373
377
|
// raw mode: the two contend, and the question can land on a half-drawn
|
|
374
378
|
// prompt. The panel shows the risk, the arguments and a scrollable diff in
|
|
375
379
|
// one frame, and dismissing it denies.
|
|
@@ -394,12 +398,11 @@ export async function chatMode({ home = false } = {}) {
|
|
|
394
398
|
|
|
395
399
|
const readTask = async () => {
|
|
396
400
|
if (prompt) return prompt.read();
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
return task;
|
|
401
|
+
// The shared question helper already provides the same plain-readline
|
|
402
|
+
// fallback when a terminal cannot host the live TUI. Keeping a second
|
|
403
|
+
// prompt framework here pulled a large, unused transitive graph into every
|
|
404
|
+
// installation and made the fallback look different from the main CLI.
|
|
405
|
+
return askText({ title: 'You' });
|
|
403
406
|
};
|
|
404
407
|
|
|
405
408
|
const finish = () => { if (prompt) prompt.stop(); };
|
|
@@ -456,6 +459,38 @@ export async function chatMode({ home = false } = {}) {
|
|
|
456
459
|
continue;
|
|
457
460
|
}
|
|
458
461
|
|
|
462
|
+
if (commandResult.effect === 'pick-session' && prompt) {
|
|
463
|
+
const active = commandResult.active;
|
|
464
|
+
prompt.openLayer(new SelectLayer({
|
|
465
|
+
title: 'Sessions',
|
|
466
|
+
emptyText: 'No sessions yet',
|
|
467
|
+
items: (commandResult.items || []).map((session) => ({
|
|
468
|
+
id: session.id,
|
|
469
|
+
label: `${session.id === active ? `${GLYPHS.bullet} ` : ''}${session.title}`,
|
|
470
|
+
description: `${session.messageCount} messages ${GLYPHS.dot} ${session.workspace || 'no workspace'}`,
|
|
471
|
+
value: session
|
|
472
|
+
})),
|
|
473
|
+
onPick: (item) => {
|
|
474
|
+
if (item) prompt.deliver(`/sessions switch ${item.value.id}`);
|
|
475
|
+
}
|
|
476
|
+
}));
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (commandResult.effect === 'pick-mcp' && prompt) {
|
|
481
|
+
const { empty } = await mcpPicker(prompt, (server) => {
|
|
482
|
+
const verb = server.granted ? 'revoke' : 'grant';
|
|
483
|
+
prompt.deliver(`/mcp ${verb} ${server.name}`);
|
|
484
|
+
});
|
|
485
|
+
if (empty) prompt.showText('MCP servers', commandResult.output);
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
if (commandResult.effect === 'dialog' && prompt) {
|
|
490
|
+
prompt.showText(commandResult.title, commandResult.output, { danger: !commandResult.ok });
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
|
|
459
494
|
// A skill was invoked: it becomes part of the REQUEST, not terminal output.
|
|
460
495
|
//
|
|
461
496
|
// This is the whole point. `/skills <id>` used to print the file and call
|
|
@@ -568,7 +603,7 @@ export async function interactiveConfig(options) {
|
|
|
568
603
|
return;
|
|
569
604
|
}
|
|
570
605
|
|
|
571
|
-
// Asked in the product's own panels rather than
|
|
606
|
+
// Asked in the product's own panels rather than a second prompt framework.
|
|
572
607
|
//
|
|
573
608
|
// These were the last two surfaces on a second design system — different
|
|
574
609
|
// colours, different glyphs, no NO_COLOR handling, and a list widget nothing
|
package/src/commands.js
CHANGED
|
@@ -47,6 +47,7 @@ export const COMMANDS = [
|
|
|
47
47
|
scope: 'local',
|
|
48
48
|
usage: '/help [command]',
|
|
49
49
|
description: 'List the available commands',
|
|
50
|
+
dialogTitle: 'Commands',
|
|
50
51
|
run: (argv, ctx) => {
|
|
51
52
|
const [wanted] = argv;
|
|
52
53
|
if (wanted) {
|
|
@@ -335,6 +336,7 @@ export const COMMANDS = [
|
|
|
335
336
|
scope: 'local',
|
|
336
337
|
usage: '/checkpoints [count]',
|
|
337
338
|
description: 'List recent undo checkpoints',
|
|
339
|
+
dialogTitle: 'Checkpoints',
|
|
338
340
|
run: (argv) => ok(buildCheckpointsText(parseInt(argv[0], 10) || 15))
|
|
339
341
|
},
|
|
340
342
|
|
|
@@ -344,6 +346,7 @@ export const COMMANDS = [
|
|
|
344
346
|
scope: 'local',
|
|
345
347
|
usage: '/context',
|
|
346
348
|
description: 'Show what fills the context window',
|
|
349
|
+
dialogTitle: 'Context',
|
|
347
350
|
run: () => ok(buildContextText())
|
|
348
351
|
},
|
|
349
352
|
|
|
@@ -353,6 +356,7 @@ export const COMMANDS = [
|
|
|
353
356
|
scope: 'local',
|
|
354
357
|
usage: '/usage',
|
|
355
358
|
description: 'Show token usage and estimated cost',
|
|
359
|
+
dialogTitle: 'Usage',
|
|
356
360
|
run: async () => ok(await buildUsageText())
|
|
357
361
|
},
|
|
358
362
|
|
|
@@ -362,6 +366,7 @@ export const COMMANDS = [
|
|
|
362
366
|
scope: 'local',
|
|
363
367
|
usage: '/cortex [list | forget <id> | forget-here]',
|
|
364
368
|
description: 'Inspect what the agent has learned, and forget any of it',
|
|
369
|
+
dialogTitle: 'Cortex',
|
|
365
370
|
// A memory store you cannot read is not a memory, it is a black box that
|
|
366
371
|
// occasionally changes the agent's behaviour. Section 4 asks for intelligent
|
|
367
372
|
// safety rather than opacity, and section 10 layer 5 asks for a trail a
|
|
@@ -426,6 +431,7 @@ export const COMMANDS = [
|
|
|
426
431
|
scope: 'local',
|
|
427
432
|
usage: '/sessions [switch <id> | delete <id>]',
|
|
428
433
|
description: 'List chat sessions, or switch to one',
|
|
434
|
+
dialogTitle: 'Sessions',
|
|
429
435
|
// Sessions replaced ONE global chat_history.json that every directory read.
|
|
430
436
|
// A session you cannot list or switch to is not a session, so this ships
|
|
431
437
|
// with the store rather than after it.
|
|
@@ -462,7 +468,8 @@ export const COMMANDS = [
|
|
|
462
468
|
return ok(
|
|
463
469
|
`${rows.length} session${rows.length === 1 ? '' : 's'} (* = active):\n`
|
|
464
470
|
+ lines.join('\n')
|
|
465
|
-
+ '\n\nSwitch with /sessions switch <id>. A new directory always starts a new session.'
|
|
471
|
+
+ '\n\nSwitch with /sessions switch <id>. A new directory always starts a new session.',
|
|
472
|
+
{ effect: 'pick-session', items: rows, active }
|
|
466
473
|
);
|
|
467
474
|
}
|
|
468
475
|
},
|
|
@@ -472,6 +479,7 @@ export const COMMANDS = [
|
|
|
472
479
|
scope: 'local',
|
|
473
480
|
usage: '/approvals [clear]',
|
|
474
481
|
description: 'List tools granted "Allow always", or revoke them',
|
|
482
|
+
dialogTitle: 'Approvals',
|
|
475
483
|
// A standing grant with no way to see or revoke it is a trap, not a
|
|
476
484
|
// convenience. This is the way out, and the confirm dialog that grants one
|
|
477
485
|
// names this command so the user is told about it at the moment it matters.
|
|
@@ -541,6 +549,7 @@ export const COMMANDS = [
|
|
|
541
549
|
scope: 'local',
|
|
542
550
|
usage: '/model [provider/model | model]',
|
|
543
551
|
description: 'Show or change the model in use',
|
|
552
|
+
dialogTitle: 'Model',
|
|
544
553
|
run: (argv) => {
|
|
545
554
|
const config = loadConfig();
|
|
546
555
|
if (argv.length === 0) {
|
|
@@ -567,6 +576,7 @@ export const COMMANDS = [
|
|
|
567
576
|
scope: 'local',
|
|
568
577
|
usage: '/mcp [add <name> <cmd…> | add <name> --url <url> | remove|grant|revoke <name>]',
|
|
569
578
|
description: 'Manage MCP servers: list, add, remove, grant, revoke',
|
|
579
|
+
dialogTitle: 'MCP servers',
|
|
570
580
|
run: (argv) => {
|
|
571
581
|
const [action, serverName, ...rest] = argv;
|
|
572
582
|
|
|
@@ -622,7 +632,7 @@ export const COMMANDS = [
|
|
|
622
632
|
|
|
623
633
|
const servers = serverStatus();
|
|
624
634
|
if (servers.length === 0) {
|
|
625
|
-
return ok('No MCP servers are configured.\n\nAdd one with:\n mcp add <name> <command> [args…]\n mcp add <name> --url <https://…>\n\n(prefix with / in chat, or `causyne-agent mcp …` in a terminal)');
|
|
635
|
+
return ok('No MCP servers are configured.\n\nAdd one with:\n mcp add <name> <command> [args…]\n mcp add <name> --url <https://…>\n\n(prefix with / in chat, or `causyne-agent mcp …` in a terminal)', { effect: 'pick-mcp' });
|
|
626
636
|
}
|
|
627
637
|
const lines = ['MCP servers', ''];
|
|
628
638
|
for (const server of servers) {
|
|
@@ -632,7 +642,7 @@ export const COMMANDS = [
|
|
|
632
642
|
}
|
|
633
643
|
lines.push('');
|
|
634
644
|
lines.push(' mcp grant <name> to enable, mcp remove <name> to delete.');
|
|
635
|
-
return ok(lines.join('\n'));
|
|
645
|
+
return ok(lines.join('\n'), { effect: 'pick-mcp' });
|
|
636
646
|
}
|
|
637
647
|
},
|
|
638
648
|
|
|
@@ -703,6 +713,7 @@ export const COMMANDS = [
|
|
|
703
713
|
scope: 'local',
|
|
704
714
|
usage: '/status',
|
|
705
715
|
description: 'Show the current provider, autonomy mode and workspace scope',
|
|
716
|
+
dialogTitle: 'Status',
|
|
706
717
|
// One builder, shared with `causyne status`, so status output cannot drift.
|
|
707
718
|
run: (argv, ctx) => ok(buildStatusText({ loop: ctx.loop || null }))
|
|
708
719
|
},
|
|
@@ -791,7 +802,11 @@ export async function runCommand(name, argv = [], ctx = {}) {
|
|
|
791
802
|
}
|
|
792
803
|
|
|
793
804
|
try {
|
|
794
|
-
|
|
805
|
+
const result = await command.run(argv, { ...ctx, surface });
|
|
806
|
+
if (command.dialogTitle && result && !result.effect) {
|
|
807
|
+
return { ...result, effect: 'dialog', title: command.dialogTitle };
|
|
808
|
+
}
|
|
809
|
+
return result;
|
|
795
810
|
} catch (e) {
|
|
796
811
|
return fail(`/${command.name} failed: ${e.message}`);
|
|
797
812
|
}
|
package/src/entrypoint.js
CHANGED
|
@@ -5,6 +5,29 @@ import { runSelfUpdate } from './autoUpdate.js';
|
|
|
5
5
|
import { printContextReport, printUsageReport, printCheckpoints, printUndo, buildStatusText, printReport } from './reporting.js';
|
|
6
6
|
import { runCommand } from './commands.js';
|
|
7
7
|
import { resolveInvocation } from './tui/invocation.js';
|
|
8
|
+
import { resolveUserPath } from './utils/paths.js';
|
|
9
|
+
|
|
10
|
+
function requestedWorkingDirectory(argv = []) {
|
|
11
|
+
const tokens = Array.isArray(argv) ? argv.slice(2) : [];
|
|
12
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
13
|
+
const token = String(tokens[index]);
|
|
14
|
+
if (token === '--') break;
|
|
15
|
+
if (token === '-C' || token === '--cwd') return tokens[index + 1] || '';
|
|
16
|
+
if (token.startsWith('--cwd=')) return token.slice('--cwd='.length);
|
|
17
|
+
if (!token.startsWith('-')) break;
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function applyRequestedWorkingDirectory(argv) {
|
|
23
|
+
const requested = requestedWorkingDirectory(argv);
|
|
24
|
+
if (requested === null) return;
|
|
25
|
+
if (!requested) throw new Error('The --cwd option requires a directory.');
|
|
26
|
+
const resolved = resolveUserPath(requested);
|
|
27
|
+
process.chdir(resolved);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
applyRequestedWorkingDirectory(process.argv);
|
|
8
31
|
|
|
9
32
|
// The old flag remains parseable only to explain its retirement.
|
|
10
33
|
function announceDevEmulator(requested) {
|
|
@@ -42,6 +65,7 @@ program
|
|
|
42
65
|
// "Usage: causyne-agent" reasonably concludes they ran the wrong thing.
|
|
43
66
|
.name('causyne')
|
|
44
67
|
.description('Causyne — Local desktop AI harness (alias: causyne-agent)')
|
|
68
|
+
.option('-C, --cwd <directory>', 'Use this directory as the workspace')
|
|
45
69
|
.version(pkgVersion);
|
|
46
70
|
|
|
47
71
|
program
|
package/src/sandbox.js
CHANGED
|
@@ -96,13 +96,10 @@ const INTERPRETER_INVOCATION = /(^|\s)(sh|bash|zsh|ksh|dash|fish|eval|xargs|ssh|
|
|
|
96
96
|
/**
|
|
97
97
|
* Credential stores and key material.
|
|
98
98
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* human in the loop rather than a wall, so these are not blocked — touching one
|
|
104
|
-
* is classified 'extreme', which always requires explicit approval in every
|
|
105
|
-
* autonomy mode, including Mode C.
|
|
99
|
+
* A user may deliberately select a workspace that contains credential material.
|
|
100
|
+
* These paths are not silently trusted just because they sit below that root:
|
|
101
|
+
* touching one is classified 'extreme', which always requires explicit approval
|
|
102
|
+
* in every autonomy mode, including Mode C.
|
|
106
103
|
*/
|
|
107
104
|
const CREDENTIAL_PATHS = [
|
|
108
105
|
/(^|\/)\.ssh(\/|$)/,
|
|
@@ -168,22 +165,17 @@ function redirectsIntoSensitiveTarget(maskedCommand) {
|
|
|
168
165
|
}
|
|
169
166
|
|
|
170
167
|
export class Sandbox {
|
|
171
|
-
constructor() {
|
|
168
|
+
constructor({ workspaceRoot = process.cwd() } = {}) {
|
|
172
169
|
this.config = loadConfig();
|
|
173
|
-
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
path.join(home, 'Projects'),
|
|
183
|
-
path.join(home, 'CausyneWorkspace'),
|
|
184
|
-
path.join(home, 'Causyne'),
|
|
185
|
-
home // Fallback: allow home dir itself (covers edge cases like ~/scripts, ~/.config)
|
|
186
|
-
];
|
|
170
|
+
|
|
171
|
+
// The launch directory is the workspace. A previous default advertised
|
|
172
|
+
// Desktop, Documents, Downloads, ~/Causyne and the whole home directory as
|
|
173
|
+
// equally valid roots. That made the model drift into the agent's own source
|
|
174
|
+
// even when the user launched it from another project, while also making the
|
|
175
|
+
// sandbox effectively home-wide. Explicit runtime grants can still use
|
|
176
|
+
// updateWorkspacePaths(), but stale config never overrides the folder the
|
|
177
|
+
// user selected for this invocation.
|
|
178
|
+
this.workspacePaths = [path.resolve(workspaceRoot)];
|
|
187
179
|
|
|
188
180
|
// Developer emulator mode (hardened, secret-gated — see devMode.js) grants
|
|
189
181
|
// full local access for agent development on a Fast-tier emulator. It cannot
|
|
@@ -243,9 +235,9 @@ export class Sandbox {
|
|
|
243
235
|
}
|
|
244
236
|
}
|
|
245
237
|
|
|
246
|
-
// L4:
|
|
247
|
-
// gets a human in the loop rather than
|
|
248
|
-
// level Mode C cannot auto-approve.
|
|
238
|
+
// L4: when an explicitly selected workspace contains credential material,
|
|
239
|
+
// it gets a human in the loop rather than silent access. 'extreme' is the
|
|
240
|
+
// one risk level Mode C cannot auto-approve.
|
|
249
241
|
for (const p of pathsToCheck) {
|
|
250
242
|
if (typeof p === 'string' && isCredentialPath(p)) {
|
|
251
243
|
return { allowed: true, risk: 'extreme', reason: `Touches credential material: ${p}` };
|
|
@@ -352,20 +344,6 @@ export class Sandbox {
|
|
|
352
344
|
return false;
|
|
353
345
|
}
|
|
354
346
|
|
|
355
|
-
// V7 Ultimate Self-Preservation: Block access to the agent's own source code
|
|
356
|
-
// The AGI cannot read, modify, or delete causyne-agent itself.
|
|
357
|
-
const agentBinOrScript = process.argv[1] || '';
|
|
358
|
-
let agentRoot = '';
|
|
359
|
-
if (agentBinOrScript && agentBinOrScript.includes('causyne-agent')) {
|
|
360
|
-
const idx = agentBinOrScript.lastIndexOf('causyne-agent');
|
|
361
|
-
agentRoot = path.resolve(agentBinOrScript.slice(0, idx + 'causyne-agent'.length));
|
|
362
|
-
} else if (typeof __dirname !== 'undefined') {
|
|
363
|
-
agentRoot = path.resolve(__dirname, '..');
|
|
364
|
-
}
|
|
365
|
-
if (agentRoot && resolved.startsWith(agentRoot) && resolved !== path.resolve(os.homedir())) {
|
|
366
|
-
return false;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
347
|
// V6: Override workspace limits if grantAllAccess is active
|
|
370
348
|
if (this.grantAllAccess) {
|
|
371
349
|
return true;
|
package/src/tui/ask.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
//
|
|
3
3
|
// `causyne config` and `causyne pair` run with no chat session behind them, so
|
|
4
4
|
// there is no live region for a dialog to draw into. That is why they were the
|
|
5
|
-
// last two surfaces still on
|
|
6
|
-
//
|
|
5
|
+
// last two surfaces still on a second prompt framework, with its own colours,
|
|
6
|
+
// glyphs, NO_COLOR handling, and list
|
|
7
7
|
// widget that looks nothing like the picker the same user sees inside `causyne`.
|
|
8
8
|
//
|
|
9
9
|
// The fix is NOT a second app shell. That was tried once: screen.js, layout.js,
|
package/src/tui/banner.js
CHANGED
|
@@ -23,9 +23,44 @@ const WORDMARK = [
|
|
|
23
23
|
' ████ █ █ ███ ████ █ █ █ █████'
|
|
24
24
|
];
|
|
25
25
|
|
|
26
|
-
// A terminal
|
|
27
|
-
//
|
|
28
|
-
|
|
26
|
+
// A compact terminal rendering of the six-part Causyne aperture. The shape is
|
|
27
|
+
// sampled from the canonical SVG rather than invented as a second logo. Its
|
|
28
|
+
// upper-right blade carries the signal green; the other blades use the neutral
|
|
29
|
+
// brand ink. Each row remains ordinary terminal text and degrades to #/+ ASCII.
|
|
30
|
+
const LOGO_SEGMENTS = [
|
|
31
|
+
[['ink', ' ███▓']],
|
|
32
|
+
[['ink', ' ▓███'], ['accent', '███'], ['ink', '▓']],
|
|
33
|
+
[['ink', '▓███ ▓▓'], ['accent', '██'], ['ink', '▓']],
|
|
34
|
+
[['ink', '▓██ ▓██▓']],
|
|
35
|
+
[['ink', '▓███▓ ███▓']],
|
|
36
|
+
[['ink', ' ███████▓']],
|
|
37
|
+
[['ink', ' ▓███']]
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
function logoRows(unicode) {
|
|
41
|
+
return LOGO_SEGMENTS.map((segments) => segments.map(([role, text]) => {
|
|
42
|
+
const rendered = unicode
|
|
43
|
+
? text
|
|
44
|
+
: text.replace(/[█▓]/g, role === 'accent' ? '+' : '#');
|
|
45
|
+
return paint(role, rendered);
|
|
46
|
+
}).join(''));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function brandArt(width, unicode) {
|
|
50
|
+
if (!unicode || width < 64) {
|
|
51
|
+
const logo = logoRows(false);
|
|
52
|
+
logo[2] = `${padEnd(logo[2], 12)}${bold(paint('ink', 'CAUSYNE AGENT'))}`;
|
|
53
|
+
return logo;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const logo = logoRows(true);
|
|
57
|
+
return logo.map((line, index) => {
|
|
58
|
+
const word = WORDMARK[index - 1];
|
|
59
|
+
return word === undefined
|
|
60
|
+
? line
|
|
61
|
+
: `${padEnd(line, 10)} ${paint('ink', word)}`;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
29
64
|
|
|
30
65
|
/**
|
|
31
66
|
* The banner rows.
|
|
@@ -35,10 +70,9 @@ const WORDMARK_PLAIN = ['C A U S Y N E'];
|
|
|
35
70
|
* never be exercised at all.
|
|
36
71
|
*/
|
|
37
72
|
export function wordmark(width = 80, { unicode = HAS_UNICODE } = {}) {
|
|
38
|
-
const
|
|
39
|
-
const rows = art.map((line) => paint('accent', line));
|
|
73
|
+
const rows = brandArt(width, unicode);
|
|
40
74
|
rows.push('');
|
|
41
|
-
rows.push(dim('Causyne
|
|
75
|
+
rows.push(dim('Causyne Agent'));
|
|
42
76
|
return rows;
|
|
43
77
|
}
|
|
44
78
|
|
|
@@ -60,8 +94,8 @@ export function wordmark(width = 80, { unicode = HAS_UNICODE } = {}) {
|
|
|
60
94
|
* header that wraps is worse than a header that is tall.
|
|
61
95
|
*/
|
|
62
96
|
export function sessionBanner(info = {}, width = 80, { unicode = HAS_UNICODE } = {}) {
|
|
63
|
-
|
|
64
|
-
|
|
97
|
+
let art = brandArt(width, unicode);
|
|
98
|
+
let artWidth = Math.max(...art.map(visibleWidth));
|
|
65
99
|
|
|
66
100
|
const facts = [];
|
|
67
101
|
if (info.version) facts.push([bold(paint('accent', 'Causyne')), dim(info.version)]);
|
|
@@ -78,11 +112,22 @@ export function sessionBanner(info = {}, width = 80, { unicode = HAS_UNICODE } =
|
|
|
78
112
|
// deferred-wrap state: the cursor sits past the last column, and the next
|
|
79
113
|
// write decides whether that becomes a wrap. Measured on an 80-column pty,
|
|
80
114
|
// the workspace row came back at exactly 80 while every other row was 79.
|
|
81
|
-
|
|
115
|
+
let room = width - artWidth - GAP - 1;
|
|
116
|
+
|
|
117
|
+
// A coloured 80-column terminal can render the full block wordmark, but it
|
|
118
|
+
// leaves too little room for the session facts beside it. Stacking those
|
|
119
|
+
// facts made startup 16 rows tall and overflowed short terminals. Prefer the
|
|
120
|
+
// compact ASCII aperture in that case: identity and facts remain one object,
|
|
121
|
+
// and the first prompt still fits without scrolling the banner away.
|
|
122
|
+
if (room < 24 && unicode && width >= 64) {
|
|
123
|
+
art = brandArt(width, false);
|
|
124
|
+
artWidth = Math.max(...art.map(visibleWidth));
|
|
125
|
+
room = width - artWidth - GAP - 1;
|
|
126
|
+
}
|
|
82
127
|
|
|
83
128
|
// Not enough width for two columns: stack, rather than wrap either one.
|
|
84
129
|
if (room < 24) {
|
|
85
|
-
return art
|
|
130
|
+
return art
|
|
86
131
|
.concat([''], facts.map(([left, right]) =>
|
|
87
132
|
truncate(right ? `${left} ${right}` : left, width - 1, GLYPHS.ellipsis)));
|
|
88
133
|
}
|
|
@@ -90,7 +135,7 @@ export function sessionBanner(info = {}, width = 80, { unicode = HAS_UNICODE } =
|
|
|
90
135
|
const rows = [];
|
|
91
136
|
const height = Math.max(art.length, facts.length);
|
|
92
137
|
for (let index = 0; index < height; index++) {
|
|
93
|
-
const artLine = art[index] === undefined ? '' :
|
|
138
|
+
const artLine = art[index] === undefined ? '' : art[index];
|
|
94
139
|
const fact = facts[index];
|
|
95
140
|
const left = padEnd(artLine, artWidth) + ' '.repeat(GAP);
|
|
96
141
|
if (!fact) { rows.push(artLine); continue; }
|
package/src/tui/dialogs.js
CHANGED
|
@@ -299,9 +299,9 @@ export class TextLayer extends Layer {
|
|
|
299
299
|
* how dangerous is this, what exactly will it do, and what will change on disk.
|
|
300
300
|
* The diff scrolls, so a 400-line rewrite is inspectable rather than truncated.
|
|
301
301
|
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
302
|
+
* The highlighted default is Reject. `y` and `n` remain explicit shortcuts;
|
|
303
|
+
* arrows choose a visible option and Enter commits it. A reflex Enter therefore
|
|
304
|
+
* denies, while an intentional move to either Allow option works consistently.
|
|
305
305
|
*/
|
|
306
306
|
export class ApprovalLayer extends Layer {
|
|
307
307
|
constructor(options = {}) {
|
|
@@ -495,7 +495,10 @@ export class ConfirmLayer extends Layer {
|
|
|
495
495
|
super({ width: options.width || 60, height: options.height || 8, ...options });
|
|
496
496
|
this.message = options.message || 'Are you sure?';
|
|
497
497
|
this.onAnswer = options.onAnswer || null;
|
|
498
|
-
this.
|
|
498
|
+
this.defaultAnswer = options.defaultAnswer === true;
|
|
499
|
+
this.footer = this.defaultAnswer
|
|
500
|
+
? `enter confirm ${GLYPHS.dot} y yes ${GLYPHS.dot} n no ${GLYPHS.dot} esc cancel`
|
|
501
|
+
: `enter cancel ${GLYPHS.dot} y yes ${GLYPHS.dot} n no ${GLYPHS.dot} esc cancel`;
|
|
499
502
|
this.settled = false;
|
|
500
503
|
}
|
|
501
504
|
|
|
@@ -523,10 +526,15 @@ export class ConfirmLayer extends Layer {
|
|
|
523
526
|
|
|
524
527
|
key(event) {
|
|
525
528
|
if (!event) return null;
|
|
526
|
-
//
|
|
527
|
-
//
|
|
529
|
+
// `y` is always an explicit approval. Enter follows the default selected by
|
|
530
|
+
// the caller: false for ordinary destructive confirmations, true only for
|
|
531
|
+
// the second step after the user has already selected Allow always.
|
|
528
532
|
if (isChar(event, 'y')) { this.answer(true); return 'close'; }
|
|
529
533
|
if (isChar(event, 'n') || event.name === 'escape') { this.answer(false); return 'close'; }
|
|
534
|
+
if (event.name === 'enter' || event.name === 'return') {
|
|
535
|
+
this.answer(this.defaultAnswer);
|
|
536
|
+
return 'close';
|
|
537
|
+
}
|
|
530
538
|
return 'handled';
|
|
531
539
|
}
|
|
532
540
|
}
|
package/src/tui/home.js
CHANGED
|
@@ -207,7 +207,7 @@ export async function mcpPicker(prompt, onAction) {
|
|
|
207
207
|
items: rows.map((server) => ({
|
|
208
208
|
id: server.name,
|
|
209
209
|
label: server.name,
|
|
210
|
-
description: `${server.granted ? 'granted' : 'not granted'}${server.
|
|
210
|
+
description: `${server.granted ? 'granted' : 'not granted'}${server.target ? ` ${GLYPHS.dot} ${server.target}` : ''}`,
|
|
211
211
|
category: server.granted ? 'granted' : 'available',
|
|
212
212
|
value: server
|
|
213
213
|
})),
|
package/src/tui/invocation.js
CHANGED
package/src/tui/keys.js
CHANGED
|
@@ -273,6 +273,17 @@ export class KeyDecoder {
|
|
|
273
273
|
} else if (final === 'u') {
|
|
274
274
|
// Kitty keyboard protocol: ESC [ codepoint ; modifiers u
|
|
275
275
|
const codepoint = numbers[0];
|
|
276
|
+
const controlName = {
|
|
277
|
+
9: 'tab',
|
|
278
|
+
10: 'enter',
|
|
279
|
+
13: 'enter',
|
|
280
|
+
27: 'escape',
|
|
281
|
+
127: 'backspace'
|
|
282
|
+
}[codepoint];
|
|
283
|
+
if (controlName) {
|
|
284
|
+
events.push(applyModifier(makeKey(controlName, { sequence }), numbers[1]));
|
|
285
|
+
return sequence.length;
|
|
286
|
+
}
|
|
276
287
|
if (Number.isFinite(codepoint) && codepoint >= 32) {
|
|
277
288
|
const character = String.fromCodePoint(codepoint);
|
|
278
289
|
const key = applyModifier(
|
package/src/tui/prompt.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// * ESC INTERRUPTS — wired to the AgentLoop.abort() that already existed and
|
|
13
13
|
// was only reachable by typing /stop after the turn had finished.
|
|
14
14
|
// * FAIL OPEN — if raw mode is unavailable (piped stdin, a CI runner, an
|
|
15
|
-
// unusual terminal) the caller falls back to
|
|
15
|
+
// unusual terminal) the caller falls back to plain readline. A fancy editor must
|
|
16
16
|
// never be the reason chat does not start.
|
|
17
17
|
//
|
|
18
18
|
// Pure Node. No dependency, no shell.
|
|
@@ -23,10 +23,10 @@ import { PromptHistory } from './history.js';
|
|
|
23
23
|
import { FileIndex, suggest, applyCompletion, renderPicker, MAX_VISIBLE } from './completion.js';
|
|
24
24
|
import { paint, dim, bold, GLYPHS, terminalWidth, HAS_COLOR } from './theme.js';
|
|
25
25
|
import { barBlock, GUTTER } from './block.js';
|
|
26
|
-
import { visibleWidth, truncate, wrapBlock, shortenHome } from './text.js';
|
|
26
|
+
import { visibleWidth, truncate, wrapBlock, shortenHome, safeDisplay } from './text.js';
|
|
27
27
|
import { pickExample, fitHints } from './banner.js';
|
|
28
28
|
import { panelRows } from './overlay.js';
|
|
29
|
-
import { commandPalette, skillPicker, ApprovalLayer, ConfirmLayer, HomeLayer } from './dialogs.js';
|
|
29
|
+
import { commandPalette, skillPicker, ApprovalLayer, ConfirmLayer, HomeLayer, TextLayer } from './dialogs.js';
|
|
30
30
|
import { describeTool } from './toolDisplay.js';
|
|
31
31
|
|
|
32
32
|
const CTRL_C_WINDOW_MS = 2000;
|
|
@@ -419,6 +419,19 @@ export class ChatPrompt {
|
|
|
419
419
|
}));
|
|
420
420
|
}
|
|
421
421
|
|
|
422
|
+
/** Show local command output inside the live region, never in chat scrollback. */
|
|
423
|
+
showText(title, text, options = {}) {
|
|
424
|
+
const panelWidth = Math.max(28, Math.min(this.width() - 2, options.width || 76));
|
|
425
|
+
const contentWidth = Math.max(12, panelWidth - 4);
|
|
426
|
+
const lines = wrapBlock(safeDisplay(String(text == null ? '' : text)), contentWidth);
|
|
427
|
+
return this.openLayer(new TextLayer({
|
|
428
|
+
title: String(title || 'Details'),
|
|
429
|
+
lines: options.danger ? lines.map((line) => paint('danger', line)) : lines,
|
|
430
|
+
width: panelWidth,
|
|
431
|
+
height: options.height || 20
|
|
432
|
+
}));
|
|
433
|
+
}
|
|
434
|
+
|
|
422
435
|
/**
|
|
423
436
|
* Ask for approval of a tool call: risk, arguments and a scrollable diff.
|
|
424
437
|
*
|
|
@@ -444,12 +457,15 @@ export class ChatPrompt {
|
|
|
444
457
|
}
|
|
445
458
|
|
|
446
459
|
/** A plain yes/no, for the questions that are not tool approvals. */
|
|
447
|
-
confirm(message) {
|
|
460
|
+
confirm(message, options = {}) {
|
|
448
461
|
return new Promise((resolve) => {
|
|
449
462
|
let settled = false;
|
|
450
463
|
const settle = (answer) => { if (!settled) { settled = true; resolve(Boolean(answer)); } };
|
|
451
|
-
const layer = new ConfirmLayer({
|
|
452
|
-
|
|
464
|
+
const layer = new ConfirmLayer({
|
|
465
|
+
message,
|
|
466
|
+
defaultAnswer: options.defaultAnswer === true,
|
|
467
|
+
onAnswer: settle
|
|
468
|
+
});
|
|
453
469
|
this.openLayer(layer);
|
|
454
470
|
});
|
|
455
471
|
}
|
|
@@ -546,19 +562,11 @@ export class ChatPrompt {
|
|
|
546
562
|
return;
|
|
547
563
|
}
|
|
548
564
|
|
|
549
|
-
// A
|
|
550
|
-
//
|
|
551
|
-
//
|
|
552
|
-
//
|
|
553
|
-
// rendered exactly like a sentence you had sent to the model — the command
|
|
554
|
-
// did run, and its output appeared underneath, but the transcript showed a
|
|
555
|
-
// conversation turn that never happened. opencode draws an invocation here,
|
|
556
|
-
// not a message, and the difference is the whole reason a command line
|
|
557
|
-
// exists.
|
|
565
|
+
// A command is control input, not conversation. Its handler decides whether
|
|
566
|
+
// to open a picker, show a text dialog, or perform an action. Keeping the
|
|
567
|
+
// invocation out of the transcript preserves the boundary between local UI
|
|
568
|
+
// and messages that were actually sent to the model.
|
|
558
569
|
if (this.isCommand(text)) {
|
|
559
|
-
this.commit('command', (width) => [
|
|
560
|
-
`${paint('accent', GLYPHS.arrow)} ${bold(truncate(text, Math.max(8, width - 3), GLYPHS.ellipsis))}`
|
|
561
|
-
]);
|
|
562
570
|
const settle = this.waiter;
|
|
563
571
|
this.waiter = null;
|
|
564
572
|
if (settle) settle(text);
|
package/src/tui/theme.js
CHANGED
|
@@ -90,52 +90,54 @@ export const HAS_UNICODE = HAS_COLOR
|
|
|
90
90
|
// Roles, not colours. A caller asking for `danger` should never care whether
|
|
91
91
|
// that is truecolor crimson or plain ANSI red.
|
|
92
92
|
const DARK_PALETTE = {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
// Causyne brand palette from the canonical site/logo reference:
|
|
94
|
+
// signal #b6e06f, text #e9edf2, muted #8d96a4, line #272c35,
|
|
95
|
+
// panel #161920 and background #0f1115.
|
|
96
|
+
accent: [182, 224, 111],
|
|
97
|
+
agent: [182, 224, 111],
|
|
98
|
+
user: [154, 199, 86],
|
|
99
|
+
success: [182, 224, 111],
|
|
97
100
|
warn: [230, 190, 90],
|
|
98
101
|
danger: [235, 110, 110],
|
|
99
|
-
muted: [
|
|
100
|
-
ink: [
|
|
101
|
-
rule: [
|
|
102
|
-
// The scroll rail
|
|
102
|
+
muted: [141, 150, 164],
|
|
103
|
+
ink: [233, 237, 242],
|
|
104
|
+
rule: [ 39, 44, 53],
|
|
105
|
+
// The scroll rail uses a deliberately darker brand green than the accent.
|
|
103
106
|
//
|
|
104
107
|
// The rail is orientation, not information you act on — it says where you are
|
|
105
108
|
// while you read something else, so it must be legible without competing with
|
|
106
|
-
// the transcript for attention.
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
scroll: [ 58, 110, 170],
|
|
109
|
+
// the transcript for attention. Dark enough to recede, while remaining part
|
|
110
|
+
// of the same graphite-and-signal-green visual system as the rest of the CLI.
|
|
111
|
+
scroll: [ 99, 125, 63],
|
|
110
112
|
// Background roles. opencode fills its input surface with theme
|
|
111
113
|
// backgroundElement and marks it with a left border in the agent's colour
|
|
112
114
|
// (component/prompt/index.tsx: border={["left"]} + backgroundColor). These are
|
|
113
115
|
// that fill: one step off the terminal's own background, never a block of
|
|
114
116
|
// colour that fights the text sitting on it.
|
|
115
|
-
surface: [
|
|
116
|
-
surfaceHi:[
|
|
117
|
+
surface: [ 22, 25, 32],
|
|
118
|
+
surfaceHi:[ 27, 31, 39]
|
|
117
119
|
};
|
|
118
120
|
|
|
119
121
|
const LIGHT_PALETTE = {
|
|
120
|
-
accent: [
|
|
121
|
-
agent: [
|
|
122
|
-
user: [
|
|
123
|
-
success: [
|
|
122
|
+
accent: [ 91, 130, 29],
|
|
123
|
+
agent: [ 91, 130, 29],
|
|
124
|
+
user: [ 74, 112, 26],
|
|
125
|
+
success: [ 74, 112, 26],
|
|
124
126
|
warn: [155, 110, 0],
|
|
125
127
|
danger: [185, 40, 40],
|
|
126
|
-
muted: [
|
|
127
|
-
ink: [
|
|
128
|
-
rule: [
|
|
129
|
-
scroll: [
|
|
128
|
+
muted: [105, 112, 123],
|
|
129
|
+
ink: [ 58, 63, 71],
|
|
130
|
+
rule: [198, 203, 211],
|
|
131
|
+
scroll: [ 91, 130, 29],
|
|
130
132
|
surface: [242, 244, 247],
|
|
131
133
|
surfaceHi:[232, 235, 240]
|
|
132
134
|
};
|
|
133
135
|
|
|
134
136
|
// Fallback for 16-colour terminals: the closest base ANSI code per role.
|
|
135
137
|
const BASIC_CODES = {
|
|
136
|
-
accent:
|
|
138
|
+
accent: 92, agent: 92, user: 32, success: 92,
|
|
137
139
|
warn: 33, danger: 31, muted: 90, ink: 39, rule: 90,
|
|
138
|
-
scroll:
|
|
140
|
+
scroll: 32,
|
|
139
141
|
surface: 39, surfaceHi: 39
|
|
140
142
|
};
|
|
141
143
|
|
package/src/utils/inquirer.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import rawInquirer from 'inquirer';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const inquirer = rawInquirer?.prompt
|
|
5
|
-
? rawInquirer
|
|
6
|
-
: (rawInquirer?.default?.prompt
|
|
7
|
-
? rawInquirer.default
|
|
8
|
-
: (rawInquirer?.default?.default?.prompt
|
|
9
|
-
? rawInquirer.default.default
|
|
10
|
-
: rawInquirer));
|
|
11
|
-
|
|
12
|
-
export default inquirer;
|