deepclause-sdk 0.1.2 → 0.1.3
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/cli/repl.d.ts +19 -4
- package/dist/cli/repl.d.ts.map +1 -1
- package/dist/cli/repl.js +267 -44
- package/dist/cli/repl.js.map +1 -1
- package/dist/repl/backend.d.ts.map +1 -1
- package/dist/repl/backend.js +18 -5
- package/dist/repl/backend.js.map +1 -1
- package/dist/repl/render.d.ts +52 -2
- package/dist/repl/render.d.ts.map +1 -1
- package/dist/repl/render.js +33 -12
- package/dist/repl/render.js.map +1 -1
- package/dist/repl/status.d.ts +3 -1
- package/dist/repl/status.d.ts.map +1 -1
- package/dist/repl/status.js +4 -0
- package/dist/repl/status.js.map +1 -1
- package/dist/repl/tui/autocomplete.d.ts +19 -0
- package/dist/repl/tui/autocomplete.d.ts.map +1 -0
- package/dist/repl/tui/autocomplete.js +41 -0
- package/dist/repl/tui/autocomplete.js.map +1 -0
- package/dist/repl/tui/document.d.ts +51 -0
- package/dist/repl/tui/document.d.ts.map +1 -0
- package/dist/repl/tui/document.js +160 -0
- package/dist/repl/tui/document.js.map +1 -0
- package/dist/repl/tui/picker.d.ts +31 -0
- package/dist/repl/tui/picker.d.ts.map +1 -0
- package/dist/repl/tui/picker.js +43 -0
- package/dist/repl/tui/picker.js.map +1 -0
- package/dist/repl/tui/renderer.d.ts +98 -0
- package/dist/repl/tui/renderer.d.ts.map +1 -0
- package/dist/repl/tui/renderer.js +284 -0
- package/dist/repl/tui/renderer.js.map +1 -0
- package/dist/repl/tui/status-bar.d.ts +4 -2
- package/dist/repl/tui/status-bar.d.ts.map +1 -1
- package/dist/repl/tui/status-bar.js +80 -24
- package/dist/repl/tui/status-bar.js.map +1 -1
- package/dist/repl/tui/terminal.d.ts +28 -0
- package/dist/repl/tui/terminal.d.ts.map +1 -0
- package/dist/repl/tui/terminal.js +94 -0
- package/dist/repl/tui/terminal.js.map +1 -0
- package/dist/repl/tui/theme.d.ts +60 -0
- package/dist/repl/tui/theme.d.ts.map +1 -1
- package/dist/repl/tui/theme.js +142 -0
- package/dist/repl/tui/theme.js.map +1 -1
- package/dist/repl/tui/tool-pane.d.ts +68 -0
- package/dist/repl/tui/tool-pane.d.ts.map +1 -0
- package/dist/repl/tui/tool-pane.js +257 -0
- package/dist/repl/tui/tool-pane.js.map +1 -0
- package/dist/repl/tui/working-line.d.ts +23 -0
- package/dist/repl/tui/working-line.d.ts.map +1 -0
- package/dist/repl/tui/working-line.js +58 -0
- package/dist/repl/tui/working-line.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/repl.d.ts
CHANGED
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { Command } from 'commander';
|
|
10
10
|
import { type HarnessRepl } from '../repl/index.js';
|
|
11
|
-
import {
|
|
11
|
+
import { type ReplEventRenderer } from '../repl/render.js';
|
|
12
12
|
import { type ReplStatusSnapshot } from '../repl/status.js';
|
|
13
13
|
import { type ReplToolset } from '../repl/toolset.js';
|
|
14
|
+
import { type ModelResolver } from '../repl/model-resolver.js';
|
|
14
15
|
import type { ImageBackend } from '../types.js';
|
|
15
16
|
import { type DiagramMode, type GraphicsMode } from '../visualize/index.js';
|
|
16
17
|
export interface ReplCliOptions {
|
|
@@ -85,6 +86,11 @@ export type ReplInput = {
|
|
|
85
86
|
} | {
|
|
86
87
|
kind: 'model';
|
|
87
88
|
model?: string;
|
|
89
|
+
} | {
|
|
90
|
+
kind: 'reasoning';
|
|
91
|
+
level?: string;
|
|
92
|
+
} | {
|
|
93
|
+
kind: 'show-reasoning';
|
|
88
94
|
} | {
|
|
89
95
|
kind: 'export';
|
|
90
96
|
path?: string;
|
|
@@ -141,7 +147,7 @@ export declare function classifyReplInput(line: string): ReplInput;
|
|
|
141
147
|
/** Run one goal and render its solutions. Returns a process exit code. */
|
|
142
148
|
export declare function runGoalWithRenderer(repl: HarnessRepl, goal: string, options: {
|
|
143
149
|
first?: boolean;
|
|
144
|
-
renderer:
|
|
150
|
+
renderer: ReplEventRenderer;
|
|
145
151
|
signal?: AbortSignal;
|
|
146
152
|
}): Promise<number>;
|
|
147
153
|
/**
|
|
@@ -153,7 +159,8 @@ export declare function runGoalWithRenderer(repl: HarnessRepl, goal: string, opt
|
|
|
153
159
|
export declare function buildCliOnInput(options: ReplCliOptions): ((prompt: string, choices?: string[]) => Promise<string | undefined>) | undefined;
|
|
154
160
|
export interface ReplRuntime {
|
|
155
161
|
repl: HarnessRepl;
|
|
156
|
-
renderer
|
|
162
|
+
/** String renderer for plain/json output, or the TUI's component renderer. */
|
|
163
|
+
renderer: ReplEventRenderer;
|
|
157
164
|
workspace: string;
|
|
158
165
|
promptPrefix: string;
|
|
159
166
|
toolset: ReplToolset;
|
|
@@ -165,6 +172,14 @@ export interface ReplRuntime {
|
|
|
165
172
|
/** Active model capabilities (pi backend), used by the status bar. */
|
|
166
173
|
contextWindow?: number;
|
|
167
174
|
reasoning: boolean;
|
|
175
|
+
/** How much model reasoning the renderer shows (the picker changes this live). */
|
|
176
|
+
reasoningMode: 'off' | 'summary' | 'full';
|
|
177
|
+
/** Models this session can switch to, for the model picker. */
|
|
178
|
+
modelResolver?: ModelResolver;
|
|
179
|
+
/** The backend, so a picker can change the reasoning level live. */
|
|
180
|
+
llmBackend?: import('../types.js').LLMBackend;
|
|
181
|
+
/** Set the reasoning level shown in the status bar. */
|
|
182
|
+
setThinkingLevel?: (level: string | undefined) => void;
|
|
168
183
|
thinkingLevel?: string;
|
|
169
184
|
/** Session id of this run. */
|
|
170
185
|
sessionId: string;
|
|
@@ -198,7 +213,7 @@ export declare function dispatchReplInput(runtime: ReplRuntime, input: ReplInput
|
|
|
198
213
|
exportPath?: string;
|
|
199
214
|
signal?: AbortSignal;
|
|
200
215
|
}): Promise<boolean>;
|
|
201
|
-
export declare function runInteractiveGoal(repl: HarnessRepl, renderer:
|
|
216
|
+
export declare function runInteractiveGoal(repl: HarnessRepl, renderer: ReplEventRenderer, goal: string, options: ReplCliOptions, ask: (query: string) => Promise<string | null>, signal?: AbortSignal): Promise<void>;
|
|
202
217
|
/**
|
|
203
218
|
* Interactive TUI for the REPL: a scrolling transcript, a fixed editor, and a
|
|
204
219
|
* fixed status bar below the input. It reuses `ReplRenderer` (rich mode) for all
|
package/dist/cli/repl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/cli/repl.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGvE,OAAO,
|
|
1
|
+
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/cli/repl.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/repl.js
CHANGED
|
@@ -14,14 +14,20 @@ import { createHarnessRepl } from '../repl/index.js';
|
|
|
14
14
|
import { HistoryStore } from '../repl/history.js';
|
|
15
15
|
import { resolveReplJudgeSelection } from '../repl/judge.js';
|
|
16
16
|
import { ReplRenderer } from '../repl/render.js';
|
|
17
|
+
import { TranscriptDocument } from '../repl/tui/document.js';
|
|
18
|
+
import { ChoicePicker } from '../repl/tui/picker.js';
|
|
19
|
+
import { TuiRenderer } from '../repl/tui/renderer.js';
|
|
20
|
+
import { WorkingLine } from '../repl/tui/working-line.js';
|
|
21
|
+
import { createReplAutocomplete } from '../repl/tui/autocomplete.js';
|
|
22
|
+
import { initTuiTheme, scrollbarStyles } from '../repl/tui/theme.js';
|
|
23
|
+
import { SizedTerminal } from '../repl/tui/terminal.js';
|
|
17
24
|
import { ReplStatusTracker } from '../repl/status.js';
|
|
18
|
-
import { LineSink, TranscriptComponent } from '../repl/tui/transcript.js';
|
|
19
25
|
import { StatusBarComponent } from '../repl/tui/status-bar.js';
|
|
20
|
-
import { Container,
|
|
26
|
+
import { Container, ScrollView, Spacer, TuiAltScreen, VStack, matchesKey, } from '@earendil-works/pi-tui';
|
|
21
27
|
import { editorTheme, formatInputAnswer } from '../repl/tui/theme.js';
|
|
22
28
|
import { PromptEditor } from '../repl/tui/editor.js';
|
|
23
29
|
import { loadProjectContext } from '../repl/project-context.js';
|
|
24
|
-
import { createPiBackend } from '../repl/backend.js';
|
|
30
|
+
import { createPiBackend, THINKING_LEVELS } from '../repl/backend.js';
|
|
25
31
|
import { createReplToolset } from '../repl/toolset.js';
|
|
26
32
|
import { takeStartupPrologMessages } from '../prolog/loader.js';
|
|
27
33
|
import { createPiImageBackend } from '../repl/imagegen.js';
|
|
@@ -113,6 +119,12 @@ export function classifyReplInput(line) {
|
|
|
113
119
|
return { kind: 'export', path: arg || undefined };
|
|
114
120
|
case 'model':
|
|
115
121
|
return { kind: 'model', model: arg || undefined };
|
|
122
|
+
case 'reasoning':
|
|
123
|
+
case 'reasoning-level':
|
|
124
|
+
return { kind: 'reasoning', level: arg || undefined };
|
|
125
|
+
case 'show-reasoning':
|
|
126
|
+
case 'reasoning-summary':
|
|
127
|
+
return { kind: 'show-reasoning' };
|
|
116
128
|
case 'freeze':
|
|
117
129
|
return { kind: 'freeze' };
|
|
118
130
|
case 'unfreeze':
|
|
@@ -484,6 +496,10 @@ export async function createReplRuntime(options) {
|
|
|
484
496
|
backend: backendKind,
|
|
485
497
|
contextWindow,
|
|
486
498
|
reasoning,
|
|
499
|
+
reasoningMode: options.showReasoning ?? config.repl.showReasoning,
|
|
500
|
+
modelResolver,
|
|
501
|
+
llmBackend,
|
|
502
|
+
setThinkingLevel: (level) => statusTracker.setThinkingLevel(level),
|
|
487
503
|
thinkingLevel,
|
|
488
504
|
sessionId: repl.session.getSessionId(),
|
|
489
505
|
harnessName,
|
|
@@ -782,18 +798,15 @@ async function executeLoad(runtime, files) {
|
|
|
782
798
|
}
|
|
783
799
|
/** Non-interactive mode: read classified inputs line by line until EOF. */
|
|
784
800
|
/**
|
|
785
|
-
*
|
|
786
|
-
*
|
|
787
|
-
*
|
|
801
|
+
* Ctrl-C exits, in every mode: this is the plain/readline path, where there is no
|
|
802
|
+
* raw key to distinguish Escape from an editing sequence, so the TUI's
|
|
803
|
+
* "Esc interrupts, Ctrl-C exits" cannot be mirrored exactly. A running turn is
|
|
804
|
+
* aborted first, so nothing keeps writing after the UI is gone.
|
|
788
805
|
*/
|
|
789
|
-
function installSigint(
|
|
806
|
+
function installSigint(holder, rl, onExit) {
|
|
790
807
|
const handler = () => {
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
runtime.renderer.writeErrorLine('(cancelling current turn… press Ctrl-C again to exit)');
|
|
794
|
-
}
|
|
795
|
-
else if (onExit) {
|
|
796
|
-
// Save the harness before exiting (Ctrl-C while idle).
|
|
808
|
+
holder.turn?.abort(new Error('cancelled by user'));
|
|
809
|
+
if (onExit) {
|
|
797
810
|
void onExit().finally(() => process.exit(130));
|
|
798
811
|
}
|
|
799
812
|
else {
|
|
@@ -811,7 +824,7 @@ async function runNonInteractive(runtime, options, onExit) {
|
|
|
811
824
|
let exitCode = 0;
|
|
812
825
|
const rl = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
813
826
|
const holder = { turn: null };
|
|
814
|
-
const removeSigint = installSigint(
|
|
827
|
+
const removeSigint = installSigint(holder, rl, onExit);
|
|
815
828
|
try {
|
|
816
829
|
for await (const line of rl) {
|
|
817
830
|
const input = classifyReplInput(line);
|
|
@@ -881,7 +894,7 @@ async function runInteractive(runtime, options, onExit) {
|
|
|
881
894
|
return answer === null ? undefined : answer;
|
|
882
895
|
});
|
|
883
896
|
const holder = { turn: null };
|
|
884
|
-
const removeSigint = installSigint(
|
|
897
|
+
const removeSigint = installSigint(holder, rl, onExit);
|
|
885
898
|
try {
|
|
886
899
|
while (true) {
|
|
887
900
|
const line = await ask(promptPrefix);
|
|
@@ -976,10 +989,33 @@ export async function runInteractiveGoal(repl, renderer, goal, options, ask, sig
|
|
|
976
989
|
* input prompts never fight the main prompt for stdin.
|
|
977
990
|
*/
|
|
978
991
|
export async function runTui(runtime, options, onExit, loaded = []) {
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
const
|
|
992
|
+
initTuiTheme();
|
|
993
|
+
// Sized, because pi-tui falls back to a hard 24 rows when the stream reports no
|
|
994
|
+
// size, which leaves the bottom of a taller terminal untouched.
|
|
995
|
+
const terminal = new SizedTerminal();
|
|
996
|
+
// Fullscreen: an application-owned viewport (ScrollView) with the editor and
|
|
997
|
+
// status bar pinned in a dock. In this mode pi-tui hands scrolling, mouse wheel,
|
|
998
|
+
// text selection and search to the viewport, and reassigns layout on resize —
|
|
999
|
+
// which is what makes the transcript scroll inside the app and the input box
|
|
1000
|
+
// behave when the terminal changes size.
|
|
1001
|
+
const tui = new TuiAltScreen(terminal, undefined, undefined, {
|
|
1002
|
+
mouse: true,
|
|
1003
|
+
wheelScrollLines: 'auto',
|
|
1004
|
+
copyOnSelect: true,
|
|
1005
|
+
});
|
|
1006
|
+
const document = new TranscriptDocument();
|
|
1007
|
+
const transcript = document;
|
|
1008
|
+
// The TUI renders components rather than lines: tool calls become panes and
|
|
1009
|
+
// streamed text becomes markdown. There is no external sink to wire.
|
|
1010
|
+
const working = new WorkingLine(tui);
|
|
1011
|
+
const renderer = new TuiRenderer({
|
|
1012
|
+
document,
|
|
1013
|
+
onWorking: (label) => {
|
|
1014
|
+
working.set(label);
|
|
1015
|
+
tui.requestRender();
|
|
1016
|
+
},
|
|
1017
|
+
});
|
|
1018
|
+
runtime.renderer = renderer;
|
|
983
1019
|
const runState = { running: false, steerable: false };
|
|
984
1020
|
/** Lines typed during a goal query, consumed by the solution pager. */
|
|
985
1021
|
const bufferedInput = [];
|
|
@@ -993,12 +1029,14 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
993
1029
|
isRunning: () => runState.running,
|
|
994
1030
|
});
|
|
995
1031
|
transcript.onChange = () => tui.requestRender();
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1032
|
+
renderer.setImageSink((lines) => document.appendImageLines(lines));
|
|
1033
|
+
renderer.setWidth(terminal.columns);
|
|
1034
|
+
// pi-tui re-renders on resize but does not invalidate the component tree, and a
|
|
1035
|
+
// component that caches by width (a tool pane, markdown) would draw stale lines.
|
|
1000
1036
|
const onResize = () => {
|
|
1001
|
-
|
|
1037
|
+
terminal.refreshSize();
|
|
1038
|
+
renderer.setWidth(terminal.columns);
|
|
1039
|
+
tui.invalidate();
|
|
1002
1040
|
tui.requestRender();
|
|
1003
1041
|
};
|
|
1004
1042
|
process.stdout.on('resize', onResize);
|
|
@@ -1027,7 +1065,9 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
1027
1065
|
}
|
|
1028
1066
|
else if (activePrompt === runtime.promptPrefix) {
|
|
1029
1067
|
// A user turn: separate it from the previous output and from the
|
|
1030
|
-
// response that follows; render it as a pi-style blue block.
|
|
1068
|
+
// response that follows; render it as a pi-style blue block. The previous
|
|
1069
|
+
// turn's text block is closed first, so the new response starts below this.
|
|
1070
|
+
runtime.renderer.endTextBlock?.();
|
|
1031
1071
|
if (transcript.getLines().length > 0)
|
|
1032
1072
|
transcript.append('');
|
|
1033
1073
|
transcript.append(text, 'user');
|
|
@@ -1038,6 +1078,7 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
1038
1078
|
else if (text.trim()) {
|
|
1039
1079
|
// No pending ask means a turn is running.
|
|
1040
1080
|
if (runState.steerable) {
|
|
1081
|
+
runtime.renderer.endTextBlock?.();
|
|
1041
1082
|
transcript.append(text, 'steer');
|
|
1042
1083
|
runtime.repl.steer(text);
|
|
1043
1084
|
}
|
|
@@ -1059,6 +1100,7 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
1059
1100
|
};
|
|
1060
1101
|
const createEditor = () => {
|
|
1061
1102
|
editor = new PromptEditor(tui, editorTheme());
|
|
1103
|
+
editor.setAutocompleteProvider(createReplAutocomplete(runtime.workspace));
|
|
1062
1104
|
editor.onSubmit = handleSubmit;
|
|
1063
1105
|
editorContainer.clear();
|
|
1064
1106
|
editorContainer.addChild(editor);
|
|
@@ -1097,40 +1139,206 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
1097
1139
|
const answer = await ask(`${prompt}${suffix}`, true);
|
|
1098
1140
|
return answer === null ? undefined : answer;
|
|
1099
1141
|
});
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1142
|
+
/** Interrupt the running turn, if any. Returns whether there was one. */
|
|
1143
|
+
const interruptTurn = () => {
|
|
1144
|
+
if (!holder.turn)
|
|
1145
|
+
return false;
|
|
1146
|
+
holder.turn.abort(new Error('cancelled by user'));
|
|
1147
|
+
transcript.append('(interrupted — Ctrl-C exits)');
|
|
1148
|
+
tui.requestRender();
|
|
1149
|
+
return true;
|
|
1150
|
+
};
|
|
1151
|
+
/** Leave the REPL, aborting anything still running so nothing outlives the UI. */
|
|
1152
|
+
const exitRepl = () => {
|
|
1153
|
+
holder.turn?.abort(new Error('cancelled by user'));
|
|
1107
1154
|
void (onExit ? onExit() : Promise.resolve()).finally(() => {
|
|
1108
1155
|
tui.stop();
|
|
1109
1156
|
process.exit(130);
|
|
1110
1157
|
});
|
|
1111
1158
|
};
|
|
1112
|
-
// Ctrl-C
|
|
1113
|
-
//
|
|
1159
|
+
// Esc interrupts, Ctrl-C exits, Ctrl-D (on an empty editor) exits. Escape is
|
|
1160
|
+
// left alone while a completion list or an overlay owns it, so it keeps its
|
|
1161
|
+
// usual meaning there. Use pi's key matcher so kitty/meta encodings are
|
|
1162
|
+
// recognized, not just raw bytes.
|
|
1114
1163
|
tui.addInputListener((data) => {
|
|
1115
1164
|
if (matchesKey(data, 'ctrl+c')) {
|
|
1116
|
-
|
|
1165
|
+
exitRepl();
|
|
1117
1166
|
return { consume: true };
|
|
1118
1167
|
}
|
|
1119
1168
|
if (matchesKey(data, 'ctrl+d') && !holder.turn && (editor?.getText().length ?? 0) === 0) {
|
|
1120
|
-
|
|
1169
|
+
exitRepl();
|
|
1121
1170
|
return { consume: true };
|
|
1122
1171
|
}
|
|
1172
|
+
if (matchesKey(data, 'escape')
|
|
1173
|
+
&& !tui.hasOverlay()
|
|
1174
|
+
&& !(editor?.isShowingAutocomplete() ?? false)) {
|
|
1175
|
+
if (interruptTurn())
|
|
1176
|
+
return { consume: true };
|
|
1177
|
+
return undefined;
|
|
1178
|
+
}
|
|
1179
|
+
// ctrl+o expands or collapses the most recent tool call, the way pi reveals
|
|
1180
|
+
// full tool output on demand.
|
|
1181
|
+
if (matchesKey(data, 'ctrl+o')) {
|
|
1182
|
+
if (renderer.toggleLastPane())
|
|
1183
|
+
return { consume: true };
|
|
1184
|
+
return undefined;
|
|
1185
|
+
}
|
|
1123
1186
|
return undefined;
|
|
1124
1187
|
});
|
|
1125
|
-
// Fallback for terminals/raw-mode setups that deliver SIGINT instead of \x03
|
|
1126
|
-
|
|
1188
|
+
// Fallback for terminals/raw-mode setups that deliver SIGINT instead of \x03:
|
|
1189
|
+
// the terminal's own Ctrl-C, which now exits.
|
|
1190
|
+
process.on('SIGINT', exitRepl);
|
|
1127
1191
|
createEditor();
|
|
1128
1192
|
for (const line of runtime.inputHistory)
|
|
1129
1193
|
editor?.addToHistory(line);
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1194
|
+
/**
|
|
1195
|
+
* Show a chooser over the transcript and resolve when it closes.
|
|
1196
|
+
*
|
|
1197
|
+
* The overlay owns input while it is up (pi-tui routes keys to the focused
|
|
1198
|
+
* overlay), so the editor does not see the keys the list is using.
|
|
1199
|
+
*/
|
|
1200
|
+
const choose = (build) => {
|
|
1201
|
+
return new Promise((resolve) => {
|
|
1202
|
+
let handle;
|
|
1203
|
+
const done = (picked) => {
|
|
1204
|
+
handle?.hide();
|
|
1205
|
+
if (editor)
|
|
1206
|
+
tui.setFocus(editor);
|
|
1207
|
+
tui.requestRender();
|
|
1208
|
+
resolve(picked);
|
|
1209
|
+
};
|
|
1210
|
+
const picker = build(done);
|
|
1211
|
+
handle = tui.showOverlay(picker, {
|
|
1212
|
+
anchor: 'center',
|
|
1213
|
+
width: '70%',
|
|
1214
|
+
maxHeight: picker.contentHeight + 2,
|
|
1215
|
+
});
|
|
1216
|
+
});
|
|
1217
|
+
};
|
|
1218
|
+
const pickReasoningMode = async () => {
|
|
1219
|
+
const modes = ['off', 'summary', 'full'];
|
|
1220
|
+
const picked = await choose((done) => new ChoicePicker({
|
|
1221
|
+
title: 'Reasoning',
|
|
1222
|
+
hint: 'How much of the model\'s thinking to show in the transcript',
|
|
1223
|
+
current: runtime.reasoningMode,
|
|
1224
|
+
items: [
|
|
1225
|
+
{ value: 'off', label: 'off', description: 'hide reasoning entirely' },
|
|
1226
|
+
{ value: 'summary', label: 'summary', description: 'a bounded preview' },
|
|
1227
|
+
{ value: 'full', label: 'full', description: 'everything the model emits' },
|
|
1228
|
+
].filter((item) => modes.includes(item.value)),
|
|
1229
|
+
onSelect: (item) => done(item.value),
|
|
1230
|
+
onCancel: () => done(),
|
|
1231
|
+
}));
|
|
1232
|
+
if (!picked)
|
|
1233
|
+
return;
|
|
1234
|
+
const mode = picked;
|
|
1235
|
+
runtime.reasoningMode = mode;
|
|
1236
|
+
runtime.renderer.setReasoningMode?.(mode);
|
|
1237
|
+
await persistSetting({ repl: { showReasoning: mode } }, 'reasoning display');
|
|
1238
|
+
renderer.writeLine(`reasoning display: ${mode}`);
|
|
1239
|
+
};
|
|
1240
|
+
/**
|
|
1241
|
+
* The model's reasoning level (its thinking effort), as opposed to how much of
|
|
1242
|
+
* that reasoning is displayed — `/show-reasoning` is the other one.
|
|
1243
|
+
*/
|
|
1244
|
+
/**
|
|
1245
|
+
* Persist a setting, but never let that failure stop it applying.
|
|
1246
|
+
*
|
|
1247
|
+
* `updateConfig` requires an existing config file (`deepclause init`), and a
|
|
1248
|
+
* picker that threw before applying the change left the selection doing nothing at
|
|
1249
|
+
* all — which read as "I cannot adjust the reasoning".
|
|
1250
|
+
*/
|
|
1251
|
+
const persistSetting = async (patch, label) => {
|
|
1252
|
+
try {
|
|
1253
|
+
await updateConfig(runtime.workspace, patch);
|
|
1254
|
+
}
|
|
1255
|
+
catch (error) {
|
|
1256
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1257
|
+
renderer.writeLine(`${label} applied to this session, but not saved: ${message.split('\n')[0]}`);
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
const pickReasoningLevel = async (level) => {
|
|
1261
|
+
const backend = runtime.llmBackend;
|
|
1262
|
+
const supported = (backend?.supportedThinkingLevels?.() ?? THINKING_LEVELS.slice());
|
|
1263
|
+
const apply = async (chosen) => {
|
|
1264
|
+
backend?.setThinkingLevel?.(chosen);
|
|
1265
|
+
runtime.thinkingLevel = chosen;
|
|
1266
|
+
runtime.setThinkingLevel?.(chosen);
|
|
1267
|
+
await persistSetting({ backend: { kind: 'pi', thinkingLevel: chosen } }, 'reasoning level');
|
|
1268
|
+
renderer.writeLine(`reasoning level: ${chosen}`);
|
|
1269
|
+
};
|
|
1270
|
+
if (level) {
|
|
1271
|
+
if (!supported.includes(level)) {
|
|
1272
|
+
renderer.writeLine(`unknown reasoning level '${level}'; supported: ${supported.join(', ')}`);
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
await apply(level);
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
const chosen = await choose((done) => new ChoicePicker({
|
|
1279
|
+
title: 'Reasoning level',
|
|
1280
|
+
hint: 'How hard the model is asked to think (not how much is shown)',
|
|
1281
|
+
current: runtime.thinkingLevel,
|
|
1282
|
+
items: supported.map((value) => ({
|
|
1283
|
+
value,
|
|
1284
|
+
label: value,
|
|
1285
|
+
description: value === 'off' ? 'no reasoning requested' : undefined,
|
|
1286
|
+
})),
|
|
1287
|
+
onSelect: (item) => done(item.value),
|
|
1288
|
+
onCancel: () => done(),
|
|
1289
|
+
}));
|
|
1290
|
+
if (chosen)
|
|
1291
|
+
await apply(chosen);
|
|
1292
|
+
};
|
|
1293
|
+
const pickModel = async () => {
|
|
1294
|
+
const catalog = runtime.modelResolver?.catalog() ?? [];
|
|
1295
|
+
if (catalog.length === 0) {
|
|
1296
|
+
renderer.writeLine(`model: ${runtime.model} (no catalog to choose from; set one in config)`);
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
const current = runtime.model.includes(':') ? runtime.model : undefined;
|
|
1300
|
+
const picked = await choose((done) => new ChoicePicker({
|
|
1301
|
+
title: 'Model',
|
|
1302
|
+
hint: 'The default for this workspace (applies to the next session)',
|
|
1303
|
+
current,
|
|
1304
|
+
items: catalog.map((entry) => ({
|
|
1305
|
+
value: entry.model,
|
|
1306
|
+
label: entry.model,
|
|
1307
|
+
description: entry.inputCost !== undefined
|
|
1308
|
+
? `$${entry.inputCost}/$${entry.outputCost ?? '?'} per 1M in/out`
|
|
1309
|
+
: (entry.contextWindow ? `${Math.round(entry.contextWindow / 1000)}k context` : undefined),
|
|
1310
|
+
})),
|
|
1311
|
+
onSelect: (item) => done(item.value),
|
|
1312
|
+
onCancel: () => done(),
|
|
1313
|
+
}));
|
|
1314
|
+
if (!picked)
|
|
1315
|
+
return;
|
|
1316
|
+
await persistSetting({ backend: { kind: 'pi', model: picked } }, 'model');
|
|
1317
|
+
renderer.writeLine(`default model set to ${picked} (takes effect on the next start)`);
|
|
1318
|
+
};
|
|
1319
|
+
// Transcript grows and scrolls; everything below it stays put.
|
|
1320
|
+
const scroll = new ScrollView(document, {
|
|
1321
|
+
follow: 'end',
|
|
1322
|
+
primary: true,
|
|
1323
|
+
scrollbar: 'auto',
|
|
1324
|
+
scrollbarTrackStyle: scrollbarStyles.track,
|
|
1325
|
+
scrollbarThumbStyle: scrollbarStyles.thumb,
|
|
1326
|
+
});
|
|
1327
|
+
// Margins: a blank row above the transcript and one between it and the editor, so
|
|
1328
|
+
// the first and last line of output are not jammed against the chrome. Fixed
|
|
1329
|
+
// spacers rather than padding inside the scroll view: they do not scroll away and
|
|
1330
|
+
// do not consume scrollback.
|
|
1331
|
+
const dock = new VStack([
|
|
1332
|
+
{ component: working, basis: 'auto', grow: 0, shrink: 1, minSize: 0 },
|
|
1333
|
+
{ component: new Spacer(1), basis: 'auto', grow: 0, shrink: 1, minSize: 1 },
|
|
1334
|
+
{ component: editorContainer, basis: 'auto', grow: 0, shrink: 1, minSize: 1 },
|
|
1335
|
+
{ component: statusBar, basis: 'auto', grow: 0, shrink: 1, minSize: 1 },
|
|
1336
|
+
]);
|
|
1337
|
+
tui.setLayoutRoot(new VStack([
|
|
1338
|
+
{ component: new Spacer(1), basis: 'auto', grow: 0, shrink: 1, minSize: 1 },
|
|
1339
|
+
{ component: scroll, basis: 0, grow: 1, shrink: 1, minSize: 1 },
|
|
1340
|
+
{ component: dock, basis: 'auto', grow: 0, shrink: 1, minSize: 1 },
|
|
1341
|
+
]));
|
|
1134
1342
|
tui.start();
|
|
1135
1343
|
await printBanner(runtime, loaded);
|
|
1136
1344
|
tui.requestRender();
|
|
@@ -1142,6 +1350,20 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
1142
1350
|
const input = classifyReplInput(line);
|
|
1143
1351
|
if (input.kind === 'halt')
|
|
1144
1352
|
break;
|
|
1353
|
+
// The pickers are overlays over the transcript, so they need the TUI and are
|
|
1354
|
+
// handled here rather than in the command dispatcher the readline path shares.
|
|
1355
|
+
if (input.kind === 'model' && !input.model) {
|
|
1356
|
+
await pickModel();
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1359
|
+
if (input.kind === 'reasoning') {
|
|
1360
|
+
await pickReasoningLevel(input.level);
|
|
1361
|
+
continue;
|
|
1362
|
+
}
|
|
1363
|
+
if (input.kind === 'show-reasoning') {
|
|
1364
|
+
await pickReasoningMode();
|
|
1365
|
+
continue;
|
|
1366
|
+
}
|
|
1145
1367
|
const controller = new AbortController();
|
|
1146
1368
|
holder.turn = controller;
|
|
1147
1369
|
runState.running = true;
|
|
@@ -1171,8 +1393,9 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
1171
1393
|
}
|
|
1172
1394
|
finally {
|
|
1173
1395
|
tui.stop();
|
|
1174
|
-
process.off('SIGINT',
|
|
1396
|
+
process.off('SIGINT', exitRepl);
|
|
1175
1397
|
process.stdout.off('resize', onResize);
|
|
1398
|
+
working.stop();
|
|
1176
1399
|
// Restore stdout so the exit footer and any later output are visible.
|
|
1177
1400
|
runtime.renderer.setSink((text) => process.stdout.write(text), (text) => process.stderr.write(text));
|
|
1178
1401
|
}
|
|
@@ -1239,7 +1462,7 @@ export async function startRepl(options) {
|
|
|
1239
1462
|
if (goals.length > 0) {
|
|
1240
1463
|
let exitCode = 0;
|
|
1241
1464
|
const controller = new AbortController();
|
|
1242
|
-
const removeSigint = installSigint(
|
|
1465
|
+
const removeSigint = installSigint({ turn: controller });
|
|
1243
1466
|
try {
|
|
1244
1467
|
for (const goal of goals) {
|
|
1245
1468
|
if (controller.signal.aborted)
|