deepclause-sdk 0.1.1 → 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.
Files changed (122) hide show
  1. package/dist/agent.d.ts +12 -0
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +116 -9
  4. package/dist/agent.js.map +1 -1
  5. package/dist/cli/config.d.ts +24 -24
  6. package/dist/cli/repl.d.ts +21 -4
  7. package/dist/cli/repl.d.ts.map +1 -1
  8. package/dist/cli/repl.js +293 -44
  9. package/dist/cli/repl.js.map +1 -1
  10. package/dist/cli/run.d.ts.map +1 -1
  11. package/dist/cli/run.js +10 -0
  12. package/dist/cli/run.js.map +1 -1
  13. package/dist/prolog/loader.d.ts +32 -0
  14. package/dist/prolog/loader.d.ts.map +1 -1
  15. package/dist/prolog/loader.js +87 -0
  16. package/dist/prolog/loader.js.map +1 -1
  17. package/dist/prolog-src/deepclause_mi.pl +1028 -118
  18. package/dist/repl/agent.d.ts +15 -1
  19. package/dist/repl/agent.d.ts.map +1 -1
  20. package/dist/repl/agent.js +44 -5
  21. package/dist/repl/agent.js.map +1 -1
  22. package/dist/repl/backend.d.ts.map +1 -1
  23. package/dist/repl/backend.js +18 -5
  24. package/dist/repl/backend.js.map +1 -1
  25. package/dist/repl/harness-tools.d.ts +24 -2
  26. package/dist/repl/harness-tools.d.ts.map +1 -1
  27. package/dist/repl/harness-tools.js +14 -5
  28. package/dist/repl/harness-tools.js.map +1 -1
  29. package/dist/repl/index.d.ts +8 -0
  30. package/dist/repl/index.d.ts.map +1 -1
  31. package/dist/repl/index.js +1 -0
  32. package/dist/repl/index.js.map +1 -1
  33. package/dist/repl/render.d.ts +60 -3
  34. package/dist/repl/render.d.ts.map +1 -1
  35. package/dist/repl/render.js +114 -28
  36. package/dist/repl/render.js.map +1 -1
  37. package/dist/repl/session.d.ts +61 -4
  38. package/dist/repl/session.d.ts.map +1 -1
  39. package/dist/repl/session.js +174 -9
  40. package/dist/repl/session.js.map +1 -1
  41. package/dist/repl/status.d.ts +3 -1
  42. package/dist/repl/status.d.ts.map +1 -1
  43. package/dist/repl/status.js +4 -0
  44. package/dist/repl/status.js.map +1 -1
  45. package/dist/repl/tool-arguments.d.ts +36 -0
  46. package/dist/repl/tool-arguments.d.ts.map +1 -0
  47. package/dist/repl/tool-arguments.js +123 -0
  48. package/dist/repl/tool-arguments.js.map +1 -0
  49. package/dist/repl/toolset.d.ts +28 -1
  50. package/dist/repl/toolset.d.ts.map +1 -1
  51. package/dist/repl/toolset.js +52 -4
  52. package/dist/repl/toolset.js.map +1 -1
  53. package/dist/repl/tui/autocomplete.d.ts +19 -0
  54. package/dist/repl/tui/autocomplete.d.ts.map +1 -0
  55. package/dist/repl/tui/autocomplete.js +41 -0
  56. package/dist/repl/tui/autocomplete.js.map +1 -0
  57. package/dist/repl/tui/document.d.ts +51 -0
  58. package/dist/repl/tui/document.d.ts.map +1 -0
  59. package/dist/repl/tui/document.js +160 -0
  60. package/dist/repl/tui/document.js.map +1 -0
  61. package/dist/repl/tui/picker.d.ts +31 -0
  62. package/dist/repl/tui/picker.d.ts.map +1 -0
  63. package/dist/repl/tui/picker.js +43 -0
  64. package/dist/repl/tui/picker.js.map +1 -0
  65. package/dist/repl/tui/renderer.d.ts +98 -0
  66. package/dist/repl/tui/renderer.d.ts.map +1 -0
  67. package/dist/repl/tui/renderer.js +284 -0
  68. package/dist/repl/tui/renderer.js.map +1 -0
  69. package/dist/repl/tui/status-bar.d.ts +4 -2
  70. package/dist/repl/tui/status-bar.d.ts.map +1 -1
  71. package/dist/repl/tui/status-bar.js +80 -24
  72. package/dist/repl/tui/status-bar.js.map +1 -1
  73. package/dist/repl/tui/terminal.d.ts +28 -0
  74. package/dist/repl/tui/terminal.d.ts.map +1 -0
  75. package/dist/repl/tui/terminal.js +94 -0
  76. package/dist/repl/tui/terminal.js.map +1 -0
  77. package/dist/repl/tui/theme.d.ts +60 -0
  78. package/dist/repl/tui/theme.d.ts.map +1 -1
  79. package/dist/repl/tui/theme.js +142 -0
  80. package/dist/repl/tui/theme.js.map +1 -1
  81. package/dist/repl/tui/tool-pane.d.ts +68 -0
  82. package/dist/repl/tui/tool-pane.d.ts.map +1 -0
  83. package/dist/repl/tui/tool-pane.js +257 -0
  84. package/dist/repl/tui/tool-pane.js.map +1 -0
  85. package/dist/repl/tui/working-line.d.ts +23 -0
  86. package/dist/repl/tui/working-line.d.ts.map +1 -0
  87. package/dist/repl/tui/working-line.js +58 -0
  88. package/dist/repl/tui/working-line.js.map +1 -0
  89. package/dist/runner.d.ts +31 -0
  90. package/dist/runner.d.ts.map +1 -1
  91. package/dist/runner.js +192 -17
  92. package/dist/runner.js.map +1 -1
  93. package/dist/system/assets/docs/AGENT_PROMPT.md +925 -43
  94. package/dist/system/assets/docs/DML_AUTHORING.md +96 -17
  95. package/dist/system/assets/docs/DML_REFERENCE.md +620 -39
  96. package/dist/system/assets/docs/PROLOG_SNIPPETS.md +45 -1
  97. package/dist/system/assets/docs/TASK_PROMPT.md +2 -0
  98. package/dist/system/environment.d.ts +36 -0
  99. package/dist/system/environment.d.ts.map +1 -0
  100. package/dist/system/environment.js +81 -0
  101. package/dist/system/environment.js.map +1 -0
  102. package/dist/system/runtime/shell-manager.d.ts +40 -2
  103. package/dist/system/runtime/shell-manager.d.ts.map +1 -1
  104. package/dist/system/runtime/shell-manager.js +82 -16
  105. package/dist/system/runtime/shell-manager.js.map +1 -1
  106. package/dist/system/runtime/shell-tool-events.js +25 -1
  107. package/dist/system/runtime/shell-tool-events.js.map +1 -1
  108. package/dist/types.d.ts +27 -1
  109. package/dist/types.d.ts.map +1 -1
  110. package/package.json +4 -2
  111. package/src/prolog-src/deepclause_mi.pl +1028 -118
  112. package/dist/compaction.d.ts +0 -98
  113. package/dist/compaction.d.ts.map +0 -1
  114. package/dist/compaction.js +0 -471
  115. package/dist/compaction.js.map +0 -1
  116. package/dist/repl/tools.d.ts +0 -53
  117. package/dist/repl/tools.d.ts.map +0 -1
  118. package/dist/repl/tools.js +0 -307
  119. package/dist/repl/tools.js.map +0 -1
  120. package/dist/system/assets/compactors/default-loop-compactor.dml +0 -43
  121. package/dist/system/assets/compactors/default-session-compactor.dml +0 -30
  122. package/dist/system/assets/docs/META_PROMPT.md +0 -68
@@ -8,9 +8,10 @@
8
8
  */
9
9
  import type { Command } from 'commander';
10
10
  import { type HarnessRepl } from '../repl/index.js';
11
- import { ReplRenderer } from '../repl/render.js';
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 {
@@ -52,6 +53,8 @@ export interface ReplCliOptions {
52
53
  tools?: string;
53
54
  noTools?: boolean;
54
55
  sandbox?: boolean;
56
+ /** Refuse to start unless the effective shell backend is a sandbox. */
57
+ requireSandbox?: boolean;
55
58
  noAsk?: boolean;
56
59
  answer?: string;
57
60
  interactiveInput?: boolean;
@@ -83,6 +86,11 @@ export type ReplInput = {
83
86
  } | {
84
87
  kind: 'model';
85
88
  model?: string;
89
+ } | {
90
+ kind: 'reasoning';
91
+ level?: string;
92
+ } | {
93
+ kind: 'show-reasoning';
86
94
  } | {
87
95
  kind: 'export';
88
96
  path?: string;
@@ -139,7 +147,7 @@ export declare function classifyReplInput(line: string): ReplInput;
139
147
  /** Run one goal and render its solutions. Returns a process exit code. */
140
148
  export declare function runGoalWithRenderer(repl: HarnessRepl, goal: string, options: {
141
149
  first?: boolean;
142
- renderer: ReplRenderer;
150
+ renderer: ReplEventRenderer;
143
151
  signal?: AbortSignal;
144
152
  }): Promise<number>;
145
153
  /**
@@ -151,7 +159,8 @@ export declare function runGoalWithRenderer(repl: HarnessRepl, goal: string, opt
151
159
  export declare function buildCliOnInput(options: ReplCliOptions): ((prompt: string, choices?: string[]) => Promise<string | undefined>) | undefined;
152
160
  export interface ReplRuntime {
153
161
  repl: HarnessRepl;
154
- renderer: ReplRenderer;
162
+ /** String renderer for plain/json output, or the TUI's component renderer. */
163
+ renderer: ReplEventRenderer;
155
164
  workspace: string;
156
165
  promptPrefix: string;
157
166
  toolset: ReplToolset;
@@ -163,6 +172,14 @@ export interface ReplRuntime {
163
172
  /** Active model capabilities (pi backend), used by the status bar. */
164
173
  contextWindow?: number;
165
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;
166
183
  thinkingLevel?: string;
167
184
  /** Session id of this run. */
168
185
  sessionId: string;
@@ -196,7 +213,7 @@ export declare function dispatchReplInput(runtime: ReplRuntime, input: ReplInput
196
213
  exportPath?: string;
197
214
  signal?: AbortSignal;
198
215
  }): Promise<boolean>;
199
- export declare function runInteractiveGoal(repl: HarnessRepl, renderer: ReplRenderer, goal: string, options: ReplCliOptions, ask: (query: string) => Promise<string | null>, signal?: AbortSignal): Promise<void>;
216
+ export declare function runInteractiveGoal(repl: HarnessRepl, renderer: ReplEventRenderer, goal: string, options: ReplCliOptions, ask: (query: string) => Promise<string | null>, signal?: AbortSignal): Promise<void>;
200
217
  /**
201
218
  * Interactive TUI for the REPL: a scrolling transcript, a fixed editor, and a
202
219
  * fixed status bar below the input. It reuses `ReplRenderer` (rich mode) for all
@@ -1 +1 @@
1
- {"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/cli/repl.ts"],"names":[],"mappings":"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"}
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,15 +14,22 @@ 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, ProcessTerminal, Spacer, TuiMainScreen, matchesKey } from '@earendil-works/pi-tui';
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';
32
+ import { takeStartupPrologMessages } from '../prolog/loader.js';
26
33
  import { createPiImageBackend } from '../repl/imagegen.js';
27
34
  import { EnvModelResolver, PiModelResolver } from '../repl/model-resolver.js';
28
35
  import { parseModelId, resolveModelSlotConfig } from '../system/config/model-slots.js';
@@ -112,6 +119,12 @@ export function classifyReplInput(line) {
112
119
  return { kind: 'export', path: arg || undefined };
113
120
  case 'model':
114
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' };
115
128
  case 'freeze':
116
129
  return { kind: 'freeze' };
117
130
  case 'unfreeze':
@@ -294,6 +307,13 @@ export async function createReplRuntime(options) {
294
307
  }
295
308
  },
296
309
  });
310
+ // The CLI counterpart of `:- require_sandbox.`: enforce it without editing the
311
+ // harness, for CI and for a run you do not want to be quietly unsandboxed.
312
+ if (options.requireSandbox && !toolset.environment.sandboxed) {
313
+ throw new Error(`--require-sandbox: the effective shell backend is ${toolset.environment.backendLabel}, `
314
+ + 'which is not sandboxed. Install bubblewrap (Linux), grant sandbox-exec (macOS), '
315
+ + 'or run with --sandbox (AgentVM).');
316
+ }
297
317
  const backendKind = options.backend ?? config.backend?.kind ?? 'pi';
298
318
  let llmBackend;
299
319
  let harnessModel = resolved.model;
@@ -429,6 +449,7 @@ export async function createReplRuntime(options) {
429
449
  maxModelCalls: options.maxModelCalls ?? config.repl.maxModelCalls,
430
450
  tools: toolset.tools,
431
451
  hostToolsCatalog: toolset.catalog,
452
+ executionBackend: toolset.environment.kind,
432
453
  llmBackend,
433
454
  judgeSelection,
434
455
  imageBackend,
@@ -475,6 +496,10 @@ export async function createReplRuntime(options) {
475
496
  backend: backendKind,
476
497
  contextWindow,
477
498
  reasoning,
499
+ reasoningMode: options.showReasoning ?? config.repl.showReasoning,
500
+ modelResolver,
501
+ llmBackend,
502
+ setThinkingLevel: (level) => statusTracker.setThinkingLevel(level),
478
503
  thinkingLevel,
479
504
  sessionId: repl.session.getSessionId(),
480
505
  harnessName,
@@ -765,23 +790,23 @@ async function executeLoad(runtime, files) {
765
790
  return 1;
766
791
  }
767
792
  runtime.renderer.writeLine(`loaded ${file}`);
793
+ for (const warning of result.warnings ?? []) {
794
+ runtime.renderer.writeErrorLine(`warning: ${warning}`);
795
+ }
768
796
  }
769
797
  return 0;
770
798
  }
771
799
  /** Non-interactive mode: read classified inputs line by line until EOF. */
772
800
  /**
773
- * Route Ctrl-C to the active turn. While a turn is running the first Ctrl-C
774
- * aborts it (the session then saves the harness to a temp file); a Ctrl-C while
775
- * idle exits.
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.
776
805
  */
777
- function installSigint(runtime, holder, rl, onExit) {
806
+ function installSigint(holder, rl, onExit) {
778
807
  const handler = () => {
779
- if (holder.turn) {
780
- holder.turn.abort(new Error('cancelled by user'));
781
- runtime.renderer.writeErrorLine('(cancelling current turn… press Ctrl-C again to exit)');
782
- }
783
- else if (onExit) {
784
- // Save the harness before exiting (Ctrl-C while idle).
808
+ holder.turn?.abort(new Error('cancelled by user'));
809
+ if (onExit) {
785
810
  void onExit().finally(() => process.exit(130));
786
811
  }
787
812
  else {
@@ -799,7 +824,7 @@ async function runNonInteractive(runtime, options, onExit) {
799
824
  let exitCode = 0;
800
825
  const rl = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });
801
826
  const holder = { turn: null };
802
- const removeSigint = installSigint(runtime, holder, rl, onExit);
827
+ const removeSigint = installSigint(holder, rl, onExit);
803
828
  try {
804
829
  for await (const line of rl) {
805
830
  const input = classifyReplInput(line);
@@ -869,7 +894,7 @@ async function runInteractive(runtime, options, onExit) {
869
894
  return answer === null ? undefined : answer;
870
895
  });
871
896
  const holder = { turn: null };
872
- const removeSigint = installSigint(runtime, holder, rl, onExit);
897
+ const removeSigint = installSigint(holder, rl, onExit);
873
898
  try {
874
899
  while (true) {
875
900
  const line = await ask(promptPrefix);
@@ -964,10 +989,33 @@ export async function runInteractiveGoal(repl, renderer, goal, options, ask, sig
964
989
  * input prompts never fight the main prompt for stdin.
965
990
  */
966
991
  export async function runTui(runtime, options, onExit, loaded = []) {
967
- const terminal = new ProcessTerminal();
968
- const tui = new TuiMainScreen(terminal);
969
- const transcript = new TranscriptComponent();
970
- const sink = new LineSink(transcript);
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;
971
1019
  const runState = { running: false, steerable: false };
972
1020
  /** Lines typed during a goal query, consumed by the solution pager. */
973
1021
  const bufferedInput = [];
@@ -981,12 +1029,14 @@ export async function runTui(runtime, options, onExit, loaded = []) {
981
1029
  isRunning: () => runState.running,
982
1030
  });
983
1031
  transcript.onChange = () => tui.requestRender();
984
- // Redirect the renderer into the transcript (including error lines).
985
- runtime.renderer.setSink((text) => sink.write(text), (text) => sink.write(text));
986
- runtime.renderer.setImageSink((lines) => transcript.appendImageLines(lines));
987
- runtime.renderer.setWidth(terminal.columns);
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.
988
1036
  const onResize = () => {
989
- runtime.renderer.setWidth(terminal.columns);
1037
+ terminal.refreshSize();
1038
+ renderer.setWidth(terminal.columns);
1039
+ tui.invalidate();
990
1040
  tui.requestRender();
991
1041
  };
992
1042
  process.stdout.on('resize', onResize);
@@ -1015,7 +1065,9 @@ export async function runTui(runtime, options, onExit, loaded = []) {
1015
1065
  }
1016
1066
  else if (activePrompt === runtime.promptPrefix) {
1017
1067
  // A user turn: separate it from the previous output and from the
1018
- // 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?.();
1019
1071
  if (transcript.getLines().length > 0)
1020
1072
  transcript.append('');
1021
1073
  transcript.append(text, 'user');
@@ -1026,6 +1078,7 @@ export async function runTui(runtime, options, onExit, loaded = []) {
1026
1078
  else if (text.trim()) {
1027
1079
  // No pending ask means a turn is running.
1028
1080
  if (runState.steerable) {
1081
+ runtime.renderer.endTextBlock?.();
1029
1082
  transcript.append(text, 'steer');
1030
1083
  runtime.repl.steer(text);
1031
1084
  }
@@ -1047,6 +1100,7 @@ export async function runTui(runtime, options, onExit, loaded = []) {
1047
1100
  };
1048
1101
  const createEditor = () => {
1049
1102
  editor = new PromptEditor(tui, editorTheme());
1103
+ editor.setAutocompleteProvider(createReplAutocomplete(runtime.workspace));
1050
1104
  editor.onSubmit = handleSubmit;
1051
1105
  editorContainer.clear();
1052
1106
  editorContainer.addChild(editor);
@@ -1085,40 +1139,206 @@ export async function runTui(runtime, options, onExit, loaded = []) {
1085
1139
  const answer = await ask(`${prompt}${suffix}`, true);
1086
1140
  return answer === null ? undefined : answer;
1087
1141
  });
1088
- const cancelTurn = () => {
1089
- if (holder.turn) {
1090
- holder.turn.abort(new Error('cancelled by user'));
1091
- transcript.append('(cancelling current turn… press Ctrl-C again to exit)');
1092
- tui.requestRender();
1093
- return;
1094
- }
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'));
1095
1154
  void (onExit ? onExit() : Promise.resolve()).finally(() => {
1096
1155
  tui.stop();
1097
1156
  process.exit(130);
1098
1157
  });
1099
1158
  };
1100
- // Ctrl-C aborts the current turn; Ctrl-D (on an empty editor) exits. Use pi's
1101
- // key matcher so kitty/meta key encodings are recognized, not just raw bytes.
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.
1102
1163
  tui.addInputListener((data) => {
1103
1164
  if (matchesKey(data, 'ctrl+c')) {
1104
- cancelTurn();
1165
+ exitRepl();
1105
1166
  return { consume: true };
1106
1167
  }
1107
1168
  if (matchesKey(data, 'ctrl+d') && !holder.turn && (editor?.getText().length ?? 0) === 0) {
1108
- cancelTurn();
1169
+ exitRepl();
1109
1170
  return { consume: true };
1110
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
+ }
1111
1186
  return undefined;
1112
1187
  });
1113
- // Fallback for terminals/raw-mode setups that deliver SIGINT instead of \x03.
1114
- process.on('SIGINT', cancelTurn);
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);
1115
1191
  createEditor();
1116
1192
  for (const line of runtime.inputHistory)
1117
1193
  editor?.addToHistory(line);
1118
- tui.addChild(transcript);
1119
- tui.addChild(new Spacer(1));
1120
- tui.addChild(editorContainer);
1121
- tui.addChild(statusBar);
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
+ ]));
1122
1342
  tui.start();
1123
1343
  await printBanner(runtime, loaded);
1124
1344
  tui.requestRender();
@@ -1130,6 +1350,20 @@ export async function runTui(runtime, options, onExit, loaded = []) {
1130
1350
  const input = classifyReplInput(line);
1131
1351
  if (input.kind === 'halt')
1132
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
+ }
1133
1367
  const controller = new AbortController();
1134
1368
  holder.turn = controller;
1135
1369
  runState.running = true;
@@ -1159,8 +1393,9 @@ export async function runTui(runtime, options, onExit, loaded = []) {
1159
1393
  }
1160
1394
  finally {
1161
1395
  tui.stop();
1162
- process.off('SIGINT', cancelTurn);
1396
+ process.off('SIGINT', exitRepl);
1163
1397
  process.stdout.off('resize', onResize);
1398
+ working.stop();
1164
1399
  // Restore stdout so the exit footer and any later output are visible.
1165
1400
  runtime.renderer.setSink((text) => process.stdout.write(text), (text) => process.stderr.write(text));
1166
1401
  }
@@ -1171,6 +1406,17 @@ export async function startRepl(options) {
1171
1406
  let runtime;
1172
1407
  try {
1173
1408
  runtime = await createReplRuntime(options);
1409
+ // Diagnostics from loading the runtime itself, rendered once and through the
1410
+ // renderer. Before this they were printed by Emscripten straight to the
1411
+ // terminal, in the middle of whatever the UI was drawing.
1412
+ for (const message of takeStartupPrologMessages()) {
1413
+ runtime.renderer.render({
1414
+ type: message.channel === 'stdout' ? 'output' : 'log',
1415
+ content: message.text,
1416
+ level: message.level,
1417
+ channel: message.channel,
1418
+ });
1419
+ }
1174
1420
  }
1175
1421
  catch (error) {
1176
1422
  process.stderr.write(`ERROR: ${error.message}\n`);
@@ -1216,7 +1462,7 @@ export async function startRepl(options) {
1216
1462
  if (goals.length > 0) {
1217
1463
  let exitCode = 0;
1218
1464
  const controller = new AbortController();
1219
- const removeSigint = installSigint(runtime, { turn: controller });
1465
+ const removeSigint = installSigint({ turn: controller });
1220
1466
  try {
1221
1467
  for (const goal of goals) {
1222
1468
  if (controller.signal.aborted)
@@ -1306,6 +1552,7 @@ export function registerReplCommand(program) {
1306
1552
  .option('--tools <list>', 'comma-separated capability host tools (default: bash)')
1307
1553
  .option('--no-tools', 'register no capability host tools')
1308
1554
  .option('--sandbox', 'run shell tools in AgentVM')
1555
+ .option('--require-sandbox', 'refuse to run unless the shell is sandboxed (bwrap/AgentVM/sandbox-exec)')
1309
1556
  .option('--no-ask', 'make ask_user / input/2 fail instead of prompting')
1310
1557
  .option('--image-model <provider:id>', 'image model for generation (default: first available)')
1311
1558
  .option('--no-open', 'do not hand images to the OS viewer on terminals without inline images')
@@ -1329,6 +1576,7 @@ export function registerReplCommand(program) {
1329
1576
  goal: options.goal,
1330
1577
  load: options.load,
1331
1578
  session: options.session,
1579
+ harness: options.harness,
1332
1580
  first: options.first,
1333
1581
  plain: options.plain,
1334
1582
  json: options.json,
@@ -1349,6 +1597,7 @@ export function registerReplCommand(program) {
1349
1597
  tools: typeof options.tools === 'string' ? options.tools : undefined,
1350
1598
  noTools: options.tools === false,
1351
1599
  sandbox: options.sandbox,
1600
+ requireSandbox: options.requireSandbox,
1352
1601
  noAsk: options.ask === false,
1353
1602
  imageModel: options.imageModel,
1354
1603
  open: options.open,