@nodetool-ai/cli-chat 0.0.0-stage → 0.8.9-bootstrap.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -2
- package/dist/.nodetool-build-stamp +1 -0
- package/dist/ExecutionTree.d.ts +20 -0
- package/dist/ExecutionTree.d.ts.map +1 -0
- package/dist/ExecutionTree.js +100 -0
- package/dist/ExecutionTree.js.map +1 -0
- package/dist/agent-toolbelt.d.ts +15 -0
- package/dist/agent-toolbelt.d.ts.map +1 -0
- package/dist/agent-toolbelt.js +28 -0
- package/dist/agent-toolbelt.js.map +1 -0
- package/dist/app.d.ts +40 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +1070 -0
- package/dist/app.js.map +1 -0
- package/dist/bash-tool.d.ts +13 -0
- package/dist/bash-tool.d.ts.map +1 -0
- package/dist/bash-tool.js +85 -0
- package/dist/bash-tool.js.map +1 -0
- package/dist/chat-codeact.d.ts +93 -0
- package/dist/chat-codeact.d.ts.map +1 -0
- package/dist/chat-codeact.js +179 -0
- package/dist/chat-codeact.js.map +1 -0
- package/dist/chat-context.d.ts +18 -0
- package/dist/chat-context.d.ts.map +1 -0
- package/dist/chat-context.js +32 -0
- package/dist/chat-context.js.map +1 -0
- package/dist/chat-entry.d.ts +13 -0
- package/dist/chat-entry.d.ts.map +1 -0
- package/dist/chat-entry.js +233 -0
- package/dist/chat-entry.js.map +1 -0
- package/dist/chat-media.d.ts +3 -0
- package/dist/chat-media.d.ts.map +1 -0
- package/dist/chat-media.js +46 -0
- package/dist/chat-media.js.map +1 -0
- package/dist/chat-prompts.d.ts +20 -0
- package/dist/chat-prompts.d.ts.map +1 -0
- package/dist/chat-prompts.js +42 -0
- package/dist/chat-prompts.js.map +1 -0
- package/dist/chat-sessions.d.ts +25 -0
- package/dist/chat-sessions.d.ts.map +1 -0
- package/dist/chat-sessions.js +153 -0
- package/dist/chat-sessions.js.map +1 -0
- package/dist/commands/agent.d.ts +33 -0
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +516 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/tools.d.ts +11 -0
- package/dist/commands/tools.d.ts.map +1 -0
- package/dist/commands/tools.js +206 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/diagnose.d.ts +139 -0
- package/dist/diagnose.d.ts.map +1 -0
- package/dist/diagnose.js +435 -0
- package/dist/diagnose.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/markdown.d.ts +9 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +53 -0
- package/dist/markdown.js.map +1 -0
- package/dist/nodetool.d.ts +3 -0
- package/dist/nodetool.d.ts.map +1 -0
- package/dist/nodetool.js +4 -0
- package/dist/nodetool.js.map +1 -0
- package/dist/permission-gate.d.ts +55 -0
- package/dist/permission-gate.d.ts.map +1 -0
- package/dist/permission-gate.js +118 -0
- package/dist/permission-gate.js.map +1 -0
- package/dist/readline-input.d.ts +23 -0
- package/dist/readline-input.d.ts.map +1 -0
- package/dist/readline-input.js +210 -0
- package/dist/readline-input.js.map +1 -0
- package/dist/settings.d.ts +19 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +146 -0
- package/dist/settings.js.map +1 -0
- package/dist/stdin.d.ts +52 -0
- package/dist/stdin.d.ts.map +1 -0
- package/dist/stdin.js +363 -0
- package/dist/stdin.js.map +1 -0
- package/dist/terminal-clipboard.d.ts +3 -0
- package/dist/terminal-clipboard.d.ts.map +1 -0
- package/dist/terminal-clipboard.js +24 -0
- package/dist/terminal-clipboard.js.map +1 -0
- package/dist/terminal-mouse.d.ts +24 -0
- package/dist/terminal-mouse.d.ts.map +1 -0
- package/dist/terminal-mouse.js +84 -0
- package/dist/terminal-mouse.js.map +1 -0
- package/dist/terminal-screen.d.ts +41 -0
- package/dist/terminal-screen.d.ts.map +1 -0
- package/dist/terminal-screen.js +228 -0
- package/dist/terminal-screen.js.map +1 -0
- package/dist/tool-format.d.ts +54 -0
- package/dist/tool-format.d.ts.map +1 -0
- package/dist/tool-format.js +360 -0
- package/dist/tool-format.js.map +1 -0
- package/dist/useExecutionState.d.ts +44 -0
- package/dist/useExecutionState.d.ts.map +1 -0
- package/dist/useExecutionState.js +285 -0
- package/dist/useExecutionState.js.map +1 -0
- package/dist/websocket-client.d.ts +159 -0
- package/dist/websocket-client.d.ts.map +1 -0
- package/dist/websocket-client.js +677 -0
- package/dist/websocket-client.js.map +1 -0
- package/package.json +73 -4
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CLI's end of the one permission ladder.
|
|
3
|
+
*
|
|
4
|
+
* Every host builds the same `PermissionGateOptions` and hands it to the same
|
|
5
|
+
* `decidePermission` ladder (invariant I-1); what differs is who answers when
|
|
6
|
+
* the ladder asks. In a terminal that is the person who typed the command, so
|
|
7
|
+
* `requestApproval` prints the call on **stderr** — stdout carries the run's
|
|
8
|
+
* result and must stay parseable — and reads one line back.
|
|
9
|
+
*
|
|
10
|
+
* Behind a pipe there is nobody to ask. The run then takes the headless gate
|
|
11
|
+
* from `@nodetool-ai/agents`: `auto`, which the ladder lets through outright,
|
|
12
|
+
* with every escalation denied and named. The refusal is printed once up
|
|
13
|
+
* front rather than per call, so a user reading the transcript later knows why
|
|
14
|
+
* an escalated call was refused instead of inferring it from the denial.
|
|
15
|
+
*/
|
|
16
|
+
import { type PermissionGateOptions, type PermissionMode } from "@nodetool-ai/agents";
|
|
17
|
+
/** The modes `--permission-mode` accepts, in the order the help text lists. */
|
|
18
|
+
export declare const PERMISSION_MODE_NAMES: readonly ["default", "auto", "plan"];
|
|
19
|
+
/**
|
|
20
|
+
* Read a `--permission-mode` value, or throw naming what is accepted.
|
|
21
|
+
*
|
|
22
|
+
* An unrecognized mode is refused rather than falling back to a default: the
|
|
23
|
+
* flag is the user's only say over what the model may do, and a typo that
|
|
24
|
+
* silently ran `auto` would be the one failure this whole path exists to
|
|
25
|
+
* prevent.
|
|
26
|
+
*/
|
|
27
|
+
export declare function parsePermissionMode(value: string | undefined): PermissionMode | undefined;
|
|
28
|
+
export interface CliPermissionGateOptions {
|
|
29
|
+
/** Names this host in the refusal a headless run prints and returns. */
|
|
30
|
+
hostName: string;
|
|
31
|
+
/** The requested mode. Undefined resolves from whether anyone can answer. */
|
|
32
|
+
mode?: PermissionMode;
|
|
33
|
+
/** Whether a person is at the terminal to answer a prompt. */
|
|
34
|
+
interactive: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Where the notice and the prompts go, one line per call, no trailing
|
|
37
|
+
* newline. Defaults to stderr; `--json` routes it into the event stream so
|
|
38
|
+
* that stream stays one JSON object per line.
|
|
39
|
+
*/
|
|
40
|
+
write?: (text: string) => void;
|
|
41
|
+
/** Where an answer is read from. Defaults to stdin. */
|
|
42
|
+
input?: NodeJS.ReadableStream;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The gate a CLI run gates through: a terminal prompt, or the headless gate.
|
|
46
|
+
*
|
|
47
|
+
* `sessionAllow` is created here, once per run, and shared by reference with
|
|
48
|
+
* every loop the run starts — the belt, each delegated capability run, and the
|
|
49
|
+
* context every child reads its gate off. That sharing is what makes `a`
|
|
50
|
+
* ("allow for the rest of this session") outlive the call that answered it:
|
|
51
|
+
* the ladder records the tool name in this Set, and the next loop consults the
|
|
52
|
+
* same one rather than a copy.
|
|
53
|
+
*/
|
|
54
|
+
export declare function createCliPermissionGate(options: CliPermissionGateOptions): PermissionGateOptions;
|
|
55
|
+
//# sourceMappingURL=permission-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-gate.d.ts","sourceRoot":"","sources":["../src/permission-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAML,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAE7B,+EAA+E;AAC/E,eAAO,MAAM,qBAAqB,YAAI,SAAS,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAM1E;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,cAAc,GAAG,SAAS,CAQ5B;AAWD,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,8DAA8D;IAC9D,WAAW,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAC/B;AAuBD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,qBAAqB,CAgDvB"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CLI's end of the one permission ladder.
|
|
3
|
+
*
|
|
4
|
+
* Every host builds the same `PermissionGateOptions` and hands it to the same
|
|
5
|
+
* `decidePermission` ladder (invariant I-1); what differs is who answers when
|
|
6
|
+
* the ladder asks. In a terminal that is the person who typed the command, so
|
|
7
|
+
* `requestApproval` prints the call on **stderr** — stdout carries the run's
|
|
8
|
+
* result and must stay parseable — and reads one line back.
|
|
9
|
+
*
|
|
10
|
+
* Behind a pipe there is nobody to ask. The run then takes the headless gate
|
|
11
|
+
* from `@nodetool-ai/agents`: `auto`, which the ladder lets through outright,
|
|
12
|
+
* with every escalation denied and named. The refusal is printed once up
|
|
13
|
+
* front rather than per call, so a user reading the transcript later knows why
|
|
14
|
+
* an escalated call was refused instead of inferring it from the denial.
|
|
15
|
+
*/
|
|
16
|
+
import readline from "node:readline";
|
|
17
|
+
import { EXECUTE_CODE_TOOL_NAME, headlessDenialReason, headlessGate } from "@nodetool-ai/agents";
|
|
18
|
+
/** The modes `--permission-mode` accepts, in the order the help text lists. */
|
|
19
|
+
export const PERMISSION_MODE_NAMES = ["default", "auto", "plan"];
|
|
20
|
+
function isPermissionMode(value) {
|
|
21
|
+
return value === "default" || value === "auto" || value === "plan";
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read a `--permission-mode` value, or throw naming what is accepted.
|
|
25
|
+
*
|
|
26
|
+
* An unrecognized mode is refused rather than falling back to a default: the
|
|
27
|
+
* flag is the user's only say over what the model may do, and a typo that
|
|
28
|
+
* silently ran `auto` would be the one failure this whole path exists to
|
|
29
|
+
* prevent.
|
|
30
|
+
*/
|
|
31
|
+
export function parsePermissionMode(value) {
|
|
32
|
+
if (value === undefined)
|
|
33
|
+
return undefined;
|
|
34
|
+
const mode = value.trim().toLowerCase();
|
|
35
|
+
if (isPermissionMode(mode))
|
|
36
|
+
return mode;
|
|
37
|
+
throw new Error(`--permission-mode must be one of ${PERMISSION_MODE_NAMES.join(", ")} ` +
|
|
38
|
+
`(got "${value}")`);
|
|
39
|
+
}
|
|
40
|
+
/** What a single keystroke at the prompt means. */
|
|
41
|
+
const ANSWERS = {
|
|
42
|
+
y: "allow",
|
|
43
|
+
yes: "allow",
|
|
44
|
+
n: "deny",
|
|
45
|
+
no: "deny",
|
|
46
|
+
a: "allow_for_chat"
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Pull one line at a time from `input`, opening the reader on first use.
|
|
50
|
+
*
|
|
51
|
+
* Lazy because `agent run` reads a piped objective off stdin itself: opening
|
|
52
|
+
* a reader a headless run never prompts through would consume it.
|
|
53
|
+
*/
|
|
54
|
+
function lineReader(input) {
|
|
55
|
+
let lines = null;
|
|
56
|
+
return async () => {
|
|
57
|
+
if (lines === null) {
|
|
58
|
+
lines = readline
|
|
59
|
+
.createInterface({ input, terminal: false })[Symbol.asyncIterator]();
|
|
60
|
+
}
|
|
61
|
+
const next = await lines.next();
|
|
62
|
+
return next.done === true ? null : next.value;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The gate a CLI run gates through: a terminal prompt, or the headless gate.
|
|
67
|
+
*
|
|
68
|
+
* `sessionAllow` is created here, once per run, and shared by reference with
|
|
69
|
+
* every loop the run starts — the belt, each delegated capability run, and the
|
|
70
|
+
* context every child reads its gate off. That sharing is what makes `a`
|
|
71
|
+
* ("allow for the rest of this session") outlive the call that answered it:
|
|
72
|
+
* the ladder records the tool name in this Set, and the next loop consults the
|
|
73
|
+
* same one rather than a copy.
|
|
74
|
+
*/
|
|
75
|
+
export function createCliPermissionGate(options) {
|
|
76
|
+
const write = options.write ??
|
|
77
|
+
((text) => {
|
|
78
|
+
process.stderr.write(`${text}\n`);
|
|
79
|
+
});
|
|
80
|
+
const mode = options.mode ?? (options.interactive ? "default" : "auto");
|
|
81
|
+
if (!options.interactive || mode === "auto") {
|
|
82
|
+
// Once per run, not per call: the reason is the same every time, and a
|
|
83
|
+
// line repeated per denied call buries the calls themselves.
|
|
84
|
+
write(headlessDenialReason(options.hostName));
|
|
85
|
+
// The requested mode still governs the ladder — a piped `--permission-mode
|
|
86
|
+
// plan` blocks what plan mode blocks. Only the approver changes, and a
|
|
87
|
+
// host with no user denies (invariant I-4).
|
|
88
|
+
const gate = { ...headlessGate(options.hostName), mode };
|
|
89
|
+
// A code action that declares no `risk` reads as high, and in `auto` the
|
|
90
|
+
// ladder asks the approver for it. Nobody is there to ask: the person
|
|
91
|
+
// launched the command with the objective, which is the approval, the
|
|
92
|
+
// same way an MCP client shows its user the code before sending. What a
|
|
93
|
+
// run escalates on its own still reaches the approver and is denied.
|
|
94
|
+
gate.sessionAllow.add(EXECUTE_CODE_TOOL_NAME);
|
|
95
|
+
return gate;
|
|
96
|
+
}
|
|
97
|
+
const readLine = lineReader(options.input ?? process.stdin);
|
|
98
|
+
const askOnTerminal = async (request) => {
|
|
99
|
+
for (;;) {
|
|
100
|
+
write(`\n${request.message}\n ${request.toolName} (${request.category})` +
|
|
101
|
+
`\n allow? [y] yes [n] no [a] yes for the rest of this session`);
|
|
102
|
+
const line = await readLine();
|
|
103
|
+
// Stdin closed mid-run: there is no longer anyone to ask, so the answer
|
|
104
|
+
// is the one a host with no user gives.
|
|
105
|
+
if (line === null)
|
|
106
|
+
return "deny";
|
|
107
|
+
const answer = ANSWERS[line.trim().toLowerCase()];
|
|
108
|
+
if (answer !== undefined)
|
|
109
|
+
return answer;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
mode,
|
|
114
|
+
sessionAllow: new Set(),
|
|
115
|
+
requestApproval: askOnTerminal
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=permission-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-gate.js","sourceRoot":"","sources":["../src/permission-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { type Key } from "ink";
|
|
3
|
+
interface ReadlineInputProps {
|
|
4
|
+
value: string;
|
|
5
|
+
onChange: (value: string) => void;
|
|
6
|
+
onSubmit?: (value: string) => void;
|
|
7
|
+
focus?: boolean;
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
showCursor?: boolean;
|
|
10
|
+
width?: number;
|
|
11
|
+
maxRows?: number;
|
|
12
|
+
onHistory?: (direction: "up" | "down") => void;
|
|
13
|
+
onComplete?: (direction: "up" | "down" | "accept" | "submit") => void;
|
|
14
|
+
}
|
|
15
|
+
export interface EditorState {
|
|
16
|
+
readonly value: string;
|
|
17
|
+
readonly cursor: number;
|
|
18
|
+
}
|
|
19
|
+
/** Pure editing boundary shared by keyboard handling and terminal tests. */
|
|
20
|
+
export declare function editInput(state: EditorState, input: string, key: Partial<Key>): EditorState;
|
|
21
|
+
export default function ReadlineInput({ value, onChange, onSubmit, focus, placeholder, showCursor, width, maxRows, onHistory, onComplete }: ReadlineInputProps): React.ReactElement;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=readline-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readline-input.d.ts","sourceRoot":"","sources":["../src/readline-input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAMN,MAAM,OAAO,CAAC;AACf,OAAO,EAAkB,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAI/C,UAAU,kBAAkB;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;IAC/C,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,KAAK,IAAI,CAAC;CACvE;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAmCD,4EAA4E;AAC5E,wBAAgB,SAAS,CACvB,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,GAChB,WAAW,CA2Fb;AAED,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACpC,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,KAAY,EACZ,WAA6B,EAC7B,UAAiB,EACjB,KAAU,EACV,OAAW,EACX,SAAS,EACT,UAAU,EACX,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAgHzC"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
3
|
+
import { Text, useInput } from "ink";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { terminalLines, terminalText } from "./terminal-screen.js";
|
|
6
|
+
const graphemes = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
7
|
+
function previousBoundary(value, cursor) {
|
|
8
|
+
let previous = 0;
|
|
9
|
+
for (const segment of graphemes.segment(value)) {
|
|
10
|
+
if (segment.index >= cursor) {
|
|
11
|
+
break;
|
|
12
|
+
}
|
|
13
|
+
previous = segment.index;
|
|
14
|
+
}
|
|
15
|
+
return previous;
|
|
16
|
+
}
|
|
17
|
+
function nextBoundary(value, cursor) {
|
|
18
|
+
for (const segment of graphemes.segment(value)) {
|
|
19
|
+
if (segment.index > cursor) {
|
|
20
|
+
return segment.index;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return value.length;
|
|
24
|
+
}
|
|
25
|
+
/** Pure editing boundary shared by keyboard handling and terminal tests. */
|
|
26
|
+
export function editInput(state, input, key) {
|
|
27
|
+
const { value, cursor } = state;
|
|
28
|
+
const start = value.lastIndexOf("\n", cursor - 1) + 1;
|
|
29
|
+
const newline = value.indexOf("\n", cursor);
|
|
30
|
+
const end = newline < 0 ? value.length : newline;
|
|
31
|
+
const replace = (from, to, text = "") => ({
|
|
32
|
+
value: value.slice(0, from) + text + value.slice(to),
|
|
33
|
+
cursor: from + text.length
|
|
34
|
+
});
|
|
35
|
+
const left = () => key.meta || (key.ctrl && input === "w")
|
|
36
|
+
? (value.slice(0, cursor).match(/\S+\s*$/)?.index ?? 0)
|
|
37
|
+
: previousBoundary(value, cursor);
|
|
38
|
+
const right = () => key.meta
|
|
39
|
+
? cursor +
|
|
40
|
+
(value.slice(cursor).match(/^\s*\S+\s*/)?.[0].length ??
|
|
41
|
+
value.length - cursor)
|
|
42
|
+
: nextBoundary(value, cursor);
|
|
43
|
+
if ((key.ctrl && input === "a") || key.home) {
|
|
44
|
+
return { value, cursor: start };
|
|
45
|
+
}
|
|
46
|
+
if ((key.ctrl && input === "e") || key.end) {
|
|
47
|
+
return { value, cursor: end };
|
|
48
|
+
}
|
|
49
|
+
if (key.leftArrow || ((key.ctrl || key.meta) && input === "b")) {
|
|
50
|
+
return { value, cursor: left() };
|
|
51
|
+
}
|
|
52
|
+
if (key.rightArrow || ((key.ctrl || key.meta) && input === "f")) {
|
|
53
|
+
return { value, cursor: right() };
|
|
54
|
+
}
|
|
55
|
+
if (key.upArrow) {
|
|
56
|
+
const previousEnd = start - 1;
|
|
57
|
+
const previousStart = value.lastIndexOf("\n", previousEnd - 1) + 1;
|
|
58
|
+
return {
|
|
59
|
+
value,
|
|
60
|
+
cursor: start
|
|
61
|
+
? Math.min(previousStart + cursor - start, previousEnd)
|
|
62
|
+
: cursor
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (key.downArrow) {
|
|
66
|
+
const nextStart = end + 1;
|
|
67
|
+
const nextEnd = value.indexOf("\n", nextStart);
|
|
68
|
+
return {
|
|
69
|
+
value,
|
|
70
|
+
cursor: end < value.length
|
|
71
|
+
? Math.min(nextStart + cursor - start, nextEnd < 0 ? value.length : nextEnd)
|
|
72
|
+
: cursor
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Ink 6 reports the DEL byte emitted by Backspace in most terminals as
|
|
76
|
+
// `delete`. Keep Ctrl+D as the unambiguous forward-delete shortcut.
|
|
77
|
+
if (key.backspace ||
|
|
78
|
+
key.delete ||
|
|
79
|
+
(key.ctrl && (input === "h" || input === "w"))) {
|
|
80
|
+
return replace(left(), cursor);
|
|
81
|
+
}
|
|
82
|
+
if ((key.ctrl || key.meta) && input === "d") {
|
|
83
|
+
return replace(cursor, right());
|
|
84
|
+
}
|
|
85
|
+
if (key.ctrl && input === "u") {
|
|
86
|
+
return replace(start, cursor);
|
|
87
|
+
}
|
|
88
|
+
if (key.ctrl && input === "k") {
|
|
89
|
+
return replace(cursor, end === cursor ? Math.min(value.length, end + 1) : end);
|
|
90
|
+
}
|
|
91
|
+
if ((key.return && (key.meta || key.shift)) || (key.ctrl && input === "j")) {
|
|
92
|
+
return replace(cursor, cursor, "\n");
|
|
93
|
+
}
|
|
94
|
+
if (!key.ctrl &&
|
|
95
|
+
!key.meta &&
|
|
96
|
+
!key.escape &&
|
|
97
|
+
!key.tab &&
|
|
98
|
+
!key.return &&
|
|
99
|
+
input) {
|
|
100
|
+
// A paste is one insertion, never a sequence of submissions.
|
|
101
|
+
return replace(cursor, cursor, terminalText(input.replace(/\r\n?/g, "\n")));
|
|
102
|
+
}
|
|
103
|
+
return state;
|
|
104
|
+
}
|
|
105
|
+
export default function ReadlineInput({ value, onChange, onSubmit, focus = true, placeholder = "Ask NodeTool…", showCursor = true, width = 76, maxRows = 5, onHistory, onComplete }) {
|
|
106
|
+
const [editor, setEditor] = useState({
|
|
107
|
+
value,
|
|
108
|
+
cursor: value.length
|
|
109
|
+
});
|
|
110
|
+
const paste = useRef(null);
|
|
111
|
+
const current = value === editor.value ? editor : { value, cursor: value.length };
|
|
112
|
+
const handlerState = useRef({
|
|
113
|
+
current,
|
|
114
|
+
value,
|
|
115
|
+
onChange,
|
|
116
|
+
onSubmit,
|
|
117
|
+
onHistory,
|
|
118
|
+
onComplete
|
|
119
|
+
});
|
|
120
|
+
// Ink subscribes to useInput handlers in a passive effect. Keep the latest
|
|
121
|
+
// render's callbacks ready before it publishes the committed terminal frame.
|
|
122
|
+
useLayoutEffect(() => {
|
|
123
|
+
handlerState.current = {
|
|
124
|
+
current,
|
|
125
|
+
value,
|
|
126
|
+
onChange,
|
|
127
|
+
onSubmit,
|
|
128
|
+
onHistory,
|
|
129
|
+
onComplete
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
if (value !== editor.value) {
|
|
134
|
+
setEditor({ value, cursor: value.length });
|
|
135
|
+
}
|
|
136
|
+
}, [value, editor.value]);
|
|
137
|
+
const handleInput = useCallback((input, key) => {
|
|
138
|
+
const latest = handlerState.current;
|
|
139
|
+
if (input === "[200~") {
|
|
140
|
+
paste.current = "";
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (input === "[201~" && paste.current !== null) {
|
|
144
|
+
const next = editInput(latest.current, paste.current, {});
|
|
145
|
+
paste.current = null;
|
|
146
|
+
setEditor(next);
|
|
147
|
+
latest.onChange(next.value);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (paste.current !== null) {
|
|
151
|
+
paste.current += key.return
|
|
152
|
+
? "\n"
|
|
153
|
+
: key.ctrl && input === "j"
|
|
154
|
+
? "\n"
|
|
155
|
+
: key.ctrl || key.meta
|
|
156
|
+
? ""
|
|
157
|
+
: input;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (key.pageUp ||
|
|
161
|
+
key.pageDown ||
|
|
162
|
+
key.escape ||
|
|
163
|
+
(key.ctrl && (key.home || key.end))) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (latest.onComplete &&
|
|
167
|
+
(key.upArrow ||
|
|
168
|
+
key.downArrow ||
|
|
169
|
+
key.tab ||
|
|
170
|
+
(key.return && !key.meta && !key.shift))) {
|
|
171
|
+
latest.onComplete(key.upArrow
|
|
172
|
+
? "up"
|
|
173
|
+
: key.downArrow
|
|
174
|
+
? "down"
|
|
175
|
+
: key.return
|
|
176
|
+
? "submit"
|
|
177
|
+
: "accept");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if ((key.upArrow || key.downArrow) && !latest.value.includes("\n")) {
|
|
181
|
+
latest.onHistory?.(key.upArrow ? "up" : "down");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (key.return && !key.meta && !key.shift) {
|
|
185
|
+
latest.onSubmit?.(latest.value);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const next = editInput(latest.current, input, key);
|
|
189
|
+
setEditor(next);
|
|
190
|
+
if (next.value !== latest.value) {
|
|
191
|
+
latest.onChange(next.value);
|
|
192
|
+
}
|
|
193
|
+
}, []);
|
|
194
|
+
useInput(handleInput, { isActive: focus });
|
|
195
|
+
const cursorEnd = nextBoundary(value, current.cursor);
|
|
196
|
+
const cursorText = value.slice(current.cursor, cursorEnd);
|
|
197
|
+
const display = value
|
|
198
|
+
? value.slice(0, current.cursor) +
|
|
199
|
+
(focus && showCursor
|
|
200
|
+
? chalk.inverse(cursorText === "\n" || !cursorText ? " " : cursorText)
|
|
201
|
+
: cursorText) +
|
|
202
|
+
(cursorText === "\n" ? "\n" : "") +
|
|
203
|
+
value.slice(cursorEnd)
|
|
204
|
+
: chalk.dim(placeholder);
|
|
205
|
+
const lines = terminalLines(display, width);
|
|
206
|
+
const cursorLine = terminalLines(value.slice(0, current.cursor) + " ", width).length - 1;
|
|
207
|
+
const start = Math.max(0, cursorLine - maxRows + 1);
|
|
208
|
+
return _jsx(Text, { children: lines.slice(start, start + maxRows).join("\n") });
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=readline-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readline-input.js","sourceRoot":"","sources":["../src/readline-input.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface ChatSettings {
|
|
2
|
+
provider: string;
|
|
3
|
+
model: string;
|
|
4
|
+
enabledTools: string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Tools the chat turn is broken without, added to a settings file that predates
|
|
8
|
+
* them. The `nodetool.*` object model documents these namespaces, so a belt
|
|
9
|
+
* missing one turns a documented call into "tool not in this toolbelt" —
|
|
10
|
+
* which is what `nodetool.models.pick()` did until `find_model` landed here.
|
|
11
|
+
* They need no credential of their own: each resolves its provider from the
|
|
12
|
+
* model it is handed, or reports that none is configured.
|
|
13
|
+
*/
|
|
14
|
+
export declare const ALWAYS_ENABLED_TOOLS: readonly string[];
|
|
15
|
+
export declare const DEFAULT_SETTINGS: ChatSettings;
|
|
16
|
+
export declare function loadSettings(): Promise<ChatSettings>;
|
|
17
|
+
export declare function saveSettings(settings: Partial<ChatSettings>): Promise<void>;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAIA,UAAU,YAAY;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EA2CjD,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,YAiC9B,CAAC;AA4CF,wBAAsB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,CAQ1D;AAED,wBAAsB,YAAY,CAChC,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC,CAWf"}
|
package/dist/settings.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
4
|
+
/**
|
|
5
|
+
* Tools the chat turn is broken without, added to a settings file that predates
|
|
6
|
+
* them. The `nodetool.*` object model documents these namespaces, so a belt
|
|
7
|
+
* missing one turns a documented call into "tool not in this toolbelt" —
|
|
8
|
+
* which is what `nodetool.models.pick()` did until `find_model` landed here.
|
|
9
|
+
* They need no credential of their own: each resolves its provider from the
|
|
10
|
+
* model it is handed, or reports that none is configured.
|
|
11
|
+
*/
|
|
12
|
+
export const ALWAYS_ENABLED_TOOLS = [
|
|
13
|
+
// Local interactive chat only; the stdin and server belts never register it.
|
|
14
|
+
"bash",
|
|
15
|
+
// Documents.
|
|
16
|
+
"extract_pdf_text",
|
|
17
|
+
"convert_pdf_to_markdown",
|
|
18
|
+
"convert_document",
|
|
19
|
+
// Discovery: providers, models, node types.
|
|
20
|
+
"find_model",
|
|
21
|
+
"list_models",
|
|
22
|
+
"list_provider_models",
|
|
23
|
+
"search_nodes",
|
|
24
|
+
"get_node_info",
|
|
25
|
+
"list_nodes",
|
|
26
|
+
// Generation, and reading back what it produced.
|
|
27
|
+
"generate_image",
|
|
28
|
+
"edit_image",
|
|
29
|
+
"generate_video",
|
|
30
|
+
"animate_image",
|
|
31
|
+
"generate_video_from_references",
|
|
32
|
+
"generate_speech",
|
|
33
|
+
"transcribe_audio",
|
|
34
|
+
"read_media_bytes",
|
|
35
|
+
// Headless storyboard lifecycle.
|
|
36
|
+
"list_storyboards",
|
|
37
|
+
"create_storyboard",
|
|
38
|
+
"get_storyboard",
|
|
39
|
+
"edit_storyboard",
|
|
40
|
+
"get_storyboard_one_take",
|
|
41
|
+
"update_storyboard_one_take",
|
|
42
|
+
"render_storyboard_stills",
|
|
43
|
+
"render_storyboard_clips",
|
|
44
|
+
"revise_storyboard_clip",
|
|
45
|
+
"assemble_storyboard_timeline",
|
|
46
|
+
"extract_script_from_storyboard",
|
|
47
|
+
// Headless script lifecycle (also available for older saved settings).
|
|
48
|
+
"list_scripts",
|
|
49
|
+
"create_script",
|
|
50
|
+
"get_script",
|
|
51
|
+
"edit_script",
|
|
52
|
+
"voice_script_lines",
|
|
53
|
+
"assemble_script_timeline",
|
|
54
|
+
"derive_storyboard_from_script"
|
|
55
|
+
];
|
|
56
|
+
export const DEFAULT_SETTINGS = {
|
|
57
|
+
provider: detectDefaultProvider(),
|
|
58
|
+
model: detectDefaultModel(),
|
|
59
|
+
enabledTools: [
|
|
60
|
+
"read_file",
|
|
61
|
+
"write_file",
|
|
62
|
+
"edit_file",
|
|
63
|
+
"list_directory",
|
|
64
|
+
"glob",
|
|
65
|
+
"grep",
|
|
66
|
+
"download_file",
|
|
67
|
+
"http_request",
|
|
68
|
+
"browser",
|
|
69
|
+
"take_screenshot",
|
|
70
|
+
// NodeTool MCP tools
|
|
71
|
+
"list_workflows",
|
|
72
|
+
"get_workflow",
|
|
73
|
+
"create_workflow",
|
|
74
|
+
"run_workflow",
|
|
75
|
+
"validate_workflow",
|
|
76
|
+
"get_example_workflow",
|
|
77
|
+
"export_workflow_digraph",
|
|
78
|
+
"list_jobs",
|
|
79
|
+
"get_job",
|
|
80
|
+
"get_job_logs",
|
|
81
|
+
"start_background_job",
|
|
82
|
+
"list_assets",
|
|
83
|
+
"get_asset",
|
|
84
|
+
"asset_search",
|
|
85
|
+
"save_asset",
|
|
86
|
+
"read_asset",
|
|
87
|
+
...ALWAYS_ENABLED_TOOLS
|
|
88
|
+
]
|
|
89
|
+
};
|
|
90
|
+
function detectDefaultProvider() {
|
|
91
|
+
if (process.env["ANTHROPIC_API_KEY"])
|
|
92
|
+
return "anthropic";
|
|
93
|
+
if (process.env["OPENAI_API_KEY"])
|
|
94
|
+
return "openai";
|
|
95
|
+
if (process.env["GEMINI_API_KEY"])
|
|
96
|
+
return "gemini";
|
|
97
|
+
return "ollama"; // local fallback
|
|
98
|
+
}
|
|
99
|
+
function detectDefaultModel() {
|
|
100
|
+
const prov = detectDefaultProvider();
|
|
101
|
+
switch (prov) {
|
|
102
|
+
case "anthropic":
|
|
103
|
+
return "claude-sonnet-4-6";
|
|
104
|
+
case "openai":
|
|
105
|
+
return "gpt-4o";
|
|
106
|
+
case "gemini":
|
|
107
|
+
return "gemini-3.5-flash";
|
|
108
|
+
default:
|
|
109
|
+
return "llama3.2";
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const SETTINGS_DIR = join(homedir(), ".nodetool");
|
|
113
|
+
const SETTINGS_FILE = join(SETTINGS_DIR, "chat-settings.json");
|
|
114
|
+
/**
|
|
115
|
+
* Drop legacy fields from older settings files: agent-mode / planner toggles
|
|
116
|
+
* (the unified chat agent has no mode) and `workspace` (it now always defaults
|
|
117
|
+
* to the current directory and is never persisted).
|
|
118
|
+
*/
|
|
119
|
+
function migrateSettings(raw) {
|
|
120
|
+
const { agentMode: _dropMode, agentPlanner: _dropPlanner, workspace: _dropWorkspace, ...rest } = raw;
|
|
121
|
+
void _dropMode;
|
|
122
|
+
void _dropPlanner;
|
|
123
|
+
void _dropWorkspace;
|
|
124
|
+
return rest;
|
|
125
|
+
}
|
|
126
|
+
export async function loadSettings() {
|
|
127
|
+
try {
|
|
128
|
+
const content = await readFile(SETTINGS_FILE, "utf-8");
|
|
129
|
+
const parsed = JSON.parse(content);
|
|
130
|
+
return { ...DEFAULT_SETTINGS, ...migrateSettings(parsed) };
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return { ...DEFAULT_SETTINGS };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export async function saveSettings(settings) {
|
|
137
|
+
try {
|
|
138
|
+
await mkdir(SETTINGS_DIR, { recursive: true });
|
|
139
|
+
const current = await loadSettings();
|
|
140
|
+
await writeFile(SETTINGS_FILE, JSON.stringify({ ...current, ...settings }, null, 2));
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// ignore save errors silently
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"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"}
|