@rind-ai/cli 0.6.1 → 0.7.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/bin/rind.js +2 -2
- package/lib/assistant-renderer.js +42 -15
- package/lib/cli-input-actions.js +133 -19
- package/lib/cli-output-controller.js +82 -94
- package/lib/cli-runtime-controller.js +155 -8
- package/lib/cli-state.js +2 -2
- package/lib/command-controller.js +34 -0
- package/lib/components/assistant-message.js +54 -21
- package/lib/composer-terminal.js +1 -1
- package/lib/event-controller.js +9 -11
- package/lib/frontend-cli-implementation.js +108 -18
- package/lib/ipc.js +186 -0
- package/lib/line-editor.js +29 -4
- package/lib/local-slash-commands.js +2 -0
- package/lib/markdown-lines.js +142 -0
- package/lib/one-shot-progress.js +145 -145
- package/lib/one-shot.js +3 -3
- package/lib/prompt-history-store.js +54 -0
- package/lib/question-menu-state.js +10 -0
- package/lib/rendering.js +466 -102
- package/lib/runtime-client.js +12 -13
- package/lib/runtime-protocol.js +5 -0
- package/lib/send.js +53 -0
- package/lib/task-monitor-controller.js +45 -45
- package/lib/terminal-key.js +47 -3
- package/lib/text-width.js +2 -19
- package/lib/tool-display.js +18 -23
- package/lib/tui/cursor.js +17 -8
- package/lib/tui/input-buffer.js +69 -28
- package/lib/tui/tui.js +128 -30
- package/lib/turn-controller.js +13 -4
- package/package.json +5 -5
- package/lib/frontend-cli.js +0 -5
package/bin/rind.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
+
import { ANSI_SEQUENCE } from "./text-width.js";
|
|
1
2
|
import { graphemes, textWidth } from "./text-width.js";
|
|
2
3
|
import {
|
|
3
4
|
codeOpenLabel,
|
|
5
|
+
consumeTableLine,
|
|
6
|
+
createTableState,
|
|
4
7
|
dim,
|
|
8
|
+
finishTableState,
|
|
5
9
|
isPlainLine,
|
|
6
|
-
|
|
7
|
-
parseTableRow,
|
|
8
|
-
renderInline,
|
|
10
|
+
renderTableBlock,
|
|
9
11
|
renderMarkdownishLine,
|
|
10
12
|
styled,
|
|
11
13
|
} from "./markdown-lines.js";
|
|
12
14
|
|
|
13
15
|
const CONTENT_PREFIX = " ";
|
|
14
|
-
const ANSI_SEQUENCE = /\x1b\[[0-?]*[ -/]*[@-~]/g;
|
|
15
16
|
|
|
16
17
|
export { CONTENT_PREFIX };
|
|
17
18
|
|
|
@@ -21,6 +22,7 @@ export class AssistantRenderer {
|
|
|
21
22
|
this.color = options.color ?? (Boolean(process.stdout.isTTY) && !process.env.NO_COLOR);
|
|
22
23
|
this.pending = "";
|
|
23
24
|
this.inCodeBlock = false;
|
|
25
|
+
this.tableState = createTableState();
|
|
24
26
|
this.lineOpen = false;
|
|
25
27
|
this.atLineStart = true;
|
|
26
28
|
this.visibleColumn = 0;
|
|
@@ -46,6 +48,12 @@ export class AssistantRenderer {
|
|
|
46
48
|
this.renderLine(this.pending, false);
|
|
47
49
|
this.pending = "";
|
|
48
50
|
}
|
|
51
|
+
const table = finishTableState(this.tableState);
|
|
52
|
+
if (table?.type === "flush") {
|
|
53
|
+
this.writeTable(table.rows);
|
|
54
|
+
} else if (table?.type === "flush_candidate") {
|
|
55
|
+
table.lines.forEach((line) => this.renderNormalLine(line, true));
|
|
56
|
+
}
|
|
49
57
|
if (this.lineOpen) {
|
|
50
58
|
this.writeText("\n");
|
|
51
59
|
this.lineOpen = false;
|
|
@@ -53,7 +61,7 @@ export class AssistantRenderer {
|
|
|
53
61
|
}
|
|
54
62
|
|
|
55
63
|
flushPlainPending() {
|
|
56
|
-
if (!this.pending || this.inCodeBlock || !isPlainLine(this.pending)) {
|
|
64
|
+
if (!this.pending || this.inCodeBlock || this.tableState.candidate.length || this.tableState.rows || !isPlainLine(this.pending)) {
|
|
57
65
|
return;
|
|
58
66
|
}
|
|
59
67
|
this.writePlain(this.pending, false);
|
|
@@ -61,10 +69,29 @@ export class AssistantRenderer {
|
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
renderLine(line, newline) {
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
const result = consumeTableLine(this.tableState, line, this.inCodeBlock);
|
|
73
|
+
if (result.type === "hold" || result.type === "append") {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (result.type === "start") {
|
|
77
|
+
result.lines?.forEach((candidate) => this.renderNormalLine(candidate, true));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (result.type === "flush") {
|
|
81
|
+
this.writeTable(result.rows);
|
|
82
|
+
if (result.line === undefined) return;
|
|
83
|
+
this.renderNormalLine(result.line, newline);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (result.type === "flush_candidate") {
|
|
87
|
+
result.lines.forEach((candidate) => this.renderNormalLine(candidate, true));
|
|
88
|
+
if (result.line !== undefined) this.renderNormalLine(result.line, newline);
|
|
66
89
|
return;
|
|
67
90
|
}
|
|
91
|
+
this.renderNormalLine(line, newline);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
renderNormalLine(line, newline) {
|
|
68
95
|
if (line.trim().startsWith("```")) {
|
|
69
96
|
this.renderCodeFence(line, newline);
|
|
70
97
|
return;
|
|
@@ -80,15 +107,15 @@ export class AssistantRenderer {
|
|
|
80
107
|
this.writeStyled(renderMarkdownishLine(line, this.color), newline);
|
|
81
108
|
}
|
|
82
109
|
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const rendered = cells.map((cell, index) =>
|
|
89
|
-
renderInline(cell, this.color, index === 0 ? "tableHeader" : "")
|
|
110
|
+
writeTable(rows) {
|
|
111
|
+
const table = renderTableBlock(
|
|
112
|
+
rows,
|
|
113
|
+
this.color,
|
|
114
|
+
Math.max(1, Math.floor(Number(this.columns ?? process.stdout.columns ?? 80) || 80) - CONTENT_PREFIX.length),
|
|
90
115
|
);
|
|
91
|
-
|
|
116
|
+
if (table) {
|
|
117
|
+
this.writeStyled(table, true);
|
|
118
|
+
}
|
|
92
119
|
}
|
|
93
120
|
|
|
94
121
|
renderCodeFence(line, newline) {
|
package/lib/cli-input-actions.js
CHANGED
|
@@ -18,14 +18,17 @@ export function createCliInputActions({
|
|
|
18
18
|
request,
|
|
19
19
|
output,
|
|
20
20
|
getTurnController,
|
|
21
|
+
getCommandController,
|
|
21
22
|
getTaskMonitor,
|
|
22
23
|
getLineInput,
|
|
23
24
|
pausePrompt,
|
|
24
25
|
resumePrompt,
|
|
25
26
|
handleSigint,
|
|
27
|
+
promptHistory = [],
|
|
28
|
+
onPromptHistory = () => {},
|
|
26
29
|
}) {
|
|
27
30
|
let cancelActiveInput = null;
|
|
28
|
-
const promptEditor = createLineEditor();
|
|
31
|
+
const promptEditor = createLineEditor("", { history: promptHistory });
|
|
29
32
|
|
|
30
33
|
function restoreInputText(text) {
|
|
31
34
|
state.input.prefill = String(text || "");
|
|
@@ -51,7 +54,7 @@ export function createCliInputActions({
|
|
|
51
54
|
return;
|
|
52
55
|
}
|
|
53
56
|
state.input.pending.splice(index, 1);
|
|
54
|
-
output.
|
|
57
|
+
output.writeUserInput(input);
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
async function retrievePendingInput(mode, session) {
|
|
@@ -90,6 +93,28 @@ export function createCliInputActions({
|
|
|
90
93
|
}
|
|
91
94
|
}
|
|
92
95
|
|
|
96
|
+
async function promotePendingFollowUp(session) {
|
|
97
|
+
const entry = [...state.input.pending].reverse().find((item) => item.mode === "follow_up");
|
|
98
|
+
if (!entry || state.input.retrievingModes.has("follow_up")) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
state.input.retrievingModes.add("follow_up");
|
|
102
|
+
try {
|
|
103
|
+
const result = await request(runtimeMethods.sessionPromoteFollowUp, { input_id: entry.inputId });
|
|
104
|
+
if (result?.accepted !== true || result?.mode !== "steering" || result?.input_id !== entry.inputId) {
|
|
105
|
+
throw new Error("Runtime did not confirm the follow-up promotion.");
|
|
106
|
+
}
|
|
107
|
+
entry.mode = "steering";
|
|
108
|
+
output.redraw();
|
|
109
|
+
} catch (error) {
|
|
110
|
+
if (state.runtime.status !== "closing") {
|
|
111
|
+
output.writeError(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
112
|
+
}
|
|
113
|
+
} finally {
|
|
114
|
+
state.input.retrievingModes.delete("follow_up");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
93
118
|
function clearPendingInputs() {
|
|
94
119
|
if (!state.input.pending.length) {
|
|
95
120
|
return;
|
|
@@ -178,7 +203,6 @@ export function createCliInputActions({
|
|
|
178
203
|
|
|
179
204
|
function askTtyInput(prompt, placeholder) {
|
|
180
205
|
return new Promise((resolve) => {
|
|
181
|
-
output.clearAssistantLineForInput();
|
|
182
206
|
const mode = placeholder && placeholder !== answerPlaceholderText() ? "prompt" : "line";
|
|
183
207
|
const initialInput = state.input.prefill;
|
|
184
208
|
const editor = mode === "prompt" ? promptEditor : createLineEditor(initialInput);
|
|
@@ -246,6 +270,14 @@ export function createCliInputActions({
|
|
|
246
270
|
handleTeamBlueprintInput(session, event);
|
|
247
271
|
return;
|
|
248
272
|
}
|
|
273
|
+
if (session.mode === "fork") {
|
|
274
|
+
handleForkInput(session, event);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (session.mode === "context-board") {
|
|
278
|
+
handleContextBoardInput(session, event);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
249
281
|
const key = event;
|
|
250
282
|
const matches = session.menuState ? syncSlashMenu(session) : [];
|
|
251
283
|
const menuKey = !key.ctrl && !key.alt && !key.shift && ["escape", "up", "down"].includes(key.name);
|
|
@@ -265,6 +297,10 @@ export function createCliInputActions({
|
|
|
265
297
|
void retrievePendingInput("steering", session);
|
|
266
298
|
return;
|
|
267
299
|
}
|
|
300
|
+
if (session.mode === "prompt" && key.alt && !key.ctrl && !key.shift && key.name === "right" && state.input.pending.some((item) => item.mode === "follow_up")) {
|
|
301
|
+
void promotePendingFollowUp(session);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
268
304
|
const result = session.editor.handleInput(key);
|
|
269
305
|
if (result === "submit") {
|
|
270
306
|
submitTtyInput(session);
|
|
@@ -281,7 +317,7 @@ export function createCliInputActions({
|
|
|
281
317
|
return;
|
|
282
318
|
}
|
|
283
319
|
const session = state.input.session;
|
|
284
|
-
if (!session || session.mode === "model" || session.mode === "theme" || session.mode === "sessions") {
|
|
320
|
+
if (!session || session.mode === "model" || session.mode === "theme" || session.mode === "sessions" || session.mode === "fork" || session.mode === "context-board") {
|
|
285
321
|
return;
|
|
286
322
|
}
|
|
287
323
|
if (session.mode === "question" && !session.questionState.isEditing()) {
|
|
@@ -307,7 +343,6 @@ export function createCliInputActions({
|
|
|
307
343
|
|
|
308
344
|
function askThemeMenu() {
|
|
309
345
|
return new Promise((resolve) => {
|
|
310
|
-
output.clearAssistantLineForInput();
|
|
311
346
|
const themeState = createThemeMenuState();
|
|
312
347
|
if (!themeState.items().length) {
|
|
313
348
|
resolve("");
|
|
@@ -339,18 +374,29 @@ export function createCliInputActions({
|
|
|
339
374
|
if (session.menuState) syncSlashMenu(session);
|
|
340
375
|
const command = session.menuState?.selectedCommand();
|
|
341
376
|
const value = command ? `/${command.name}` : session.editor.input();
|
|
342
|
-
if (session.mode === "prompt") session.editor
|
|
377
|
+
if (session.mode === "prompt") recordPromptHistory(session.editor, value);
|
|
343
378
|
completeTtyInput(session, value, session.mode === "prompt" && !state.turn.active, session.mode === "line" ? "\n" : "");
|
|
344
379
|
}
|
|
345
380
|
|
|
346
381
|
function queueTtyInput(session) {
|
|
347
382
|
const value = session.editor.input();
|
|
348
383
|
if (!value.trim()) return;
|
|
349
|
-
session.editor
|
|
384
|
+
recordPromptHistory(session.editor, value);
|
|
350
385
|
completeTtyInput(session, "", false);
|
|
351
386
|
getTurnController().submitFollowUp(value);
|
|
352
387
|
}
|
|
353
388
|
|
|
389
|
+
function recordPromptHistory(editor, value) {
|
|
390
|
+
const text = String(value || "").trim();
|
|
391
|
+
if (!text || text.startsWith("/")) {
|
|
392
|
+
editor.addToHistory("");
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
if (editor.addToHistory(text)) {
|
|
396
|
+
onPromptHistory(editor.getHistory());
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
354
400
|
function completeTtyInput(session, value, writeUser, lineText = "", displayValue = value) {
|
|
355
401
|
if (state.input.session !== session) return;
|
|
356
402
|
state.input.session = null;
|
|
@@ -366,7 +412,6 @@ export function createCliInputActions({
|
|
|
366
412
|
|
|
367
413
|
function askModelMenu(models, currentModel) {
|
|
368
414
|
return new Promise((resolve) => {
|
|
369
|
-
output.clearAssistantLineForInput();
|
|
370
415
|
const modelState = createModelMenuState(models, currentModel);
|
|
371
416
|
if (!modelState.items().length) {
|
|
372
417
|
resolve("");
|
|
@@ -382,7 +427,6 @@ export function createCliInputActions({
|
|
|
382
427
|
|
|
383
428
|
function askEffortMenu(currentEffort) {
|
|
384
429
|
return new Promise((resolve) => {
|
|
385
|
-
output.clearAssistantLineForInput();
|
|
386
430
|
const modelState = createModelMenuState(REASONING_EFFORTS.slice(), currentEffort);
|
|
387
431
|
const session = { mode: "model", inputText: "/effort", modelState, resolve };
|
|
388
432
|
state.input.session = session;
|
|
@@ -406,16 +450,17 @@ export function createCliInputActions({
|
|
|
406
450
|
|
|
407
451
|
function askQuestionMenu(event) {
|
|
408
452
|
return new Promise((resolve) => {
|
|
409
|
-
output.clearAssistantLineForInput();
|
|
410
453
|
const options = (Array.isArray(event.options) ? event.options : [])
|
|
411
454
|
.map((option) => ({ label: String(option?.label || "").trim(), description: String(option?.description || "").trim() }))
|
|
412
455
|
.filter((option) => option.label);
|
|
413
456
|
const questionState = createQuestionMenuState(options);
|
|
457
|
+
const editor = createLineEditor();
|
|
458
|
+
editor.setViewportWidth(process.stdout.columns || 80);
|
|
414
459
|
state.input.session = {
|
|
415
460
|
mode: "question",
|
|
416
461
|
question: String(event.question || "Input required"),
|
|
417
462
|
questionState,
|
|
418
|
-
editor
|
|
463
|
+
editor,
|
|
419
464
|
resolve,
|
|
420
465
|
};
|
|
421
466
|
state.input.active = true;
|
|
@@ -426,7 +471,6 @@ export function createCliInputActions({
|
|
|
426
471
|
|
|
427
472
|
function askSessionMenu(options, sessions, currentIndex) {
|
|
428
473
|
return new Promise((resolve) => {
|
|
429
|
-
output.clearAssistantLineForInput();
|
|
430
474
|
const choiceState = createChoiceMenuState(options, options[currentIndex] || "");
|
|
431
475
|
const session = { mode: "sessions", inputText: "/sessions", choiceState, sessions, resolve };
|
|
432
476
|
state.input.session = session;
|
|
@@ -438,7 +482,6 @@ export function createCliInputActions({
|
|
|
438
482
|
|
|
439
483
|
function askTeamBlueprint(blueprints) {
|
|
440
484
|
return new Promise((resolve) => {
|
|
441
|
-
output.clearAssistantLineForInput();
|
|
442
485
|
const items = (Array.isArray(blueprints) ? blueprints : []).map((item) => ({
|
|
443
486
|
id: String(item?.id || ""),
|
|
444
487
|
label: [item?.id, item?.name, item?.description].filter(Boolean).join(" · "),
|
|
@@ -459,9 +502,14 @@ export function createCliInputActions({
|
|
|
459
502
|
function handleQuestionInput(session, key) {
|
|
460
503
|
const modified = key.ctrl || key.alt || key.shift;
|
|
461
504
|
if (session.questionState.isEditing()) {
|
|
462
|
-
if (!modified && key.name === "
|
|
463
|
-
|
|
464
|
-
session.editor
|
|
505
|
+
if (!modified && (key.name === "up" || key.name === "down")) {
|
|
506
|
+
session.questionState.leaveEditing();
|
|
507
|
+
session.editor.setInput("");
|
|
508
|
+
if (session.questionState.handleNavigation(key)) output.redraw();
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
if (!modified && key.name === "escape") {
|
|
512
|
+
session.questionState.leaveEditing();
|
|
465
513
|
output.redraw();
|
|
466
514
|
return;
|
|
467
515
|
}
|
|
@@ -477,8 +525,6 @@ export function createCliInputActions({
|
|
|
477
525
|
}
|
|
478
526
|
if (!modified && (key.name === "enter" || key.name === "return" || key.name === "tab")) {
|
|
479
527
|
if (session.questionState.enterEditing()) {
|
|
480
|
-
session.editor = createLineEditor();
|
|
481
|
-
session.editor.setViewportWidth(process.stdout.columns || 80);
|
|
482
528
|
output.redraw();
|
|
483
529
|
return;
|
|
484
530
|
}
|
|
@@ -488,7 +534,6 @@ export function createCliInputActions({
|
|
|
488
534
|
}
|
|
489
535
|
if (!modified && key.name === "escape") return completeTtyInput(session, "", false);
|
|
490
536
|
if (!modified && session.questionState.handleNavigation(key)) {
|
|
491
|
-
session.editor = null;
|
|
492
537
|
output.redraw();
|
|
493
538
|
}
|
|
494
539
|
}
|
|
@@ -513,6 +558,49 @@ export function createCliInputActions({
|
|
|
513
558
|
if (!modified && session.choiceState.handleKey(key)) output.redraw();
|
|
514
559
|
}
|
|
515
560
|
|
|
561
|
+
function handleForkInput(session, key) {
|
|
562
|
+
const modified = key.ctrl || key.alt || key.shift;
|
|
563
|
+
if (!modified && (key.name === "enter" || key.name === "return")) {
|
|
564
|
+
completeTtyInput(session, session.items[session.choiceState.selectedIndex()] || null, false);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (!modified && key.name === "escape") return completeTtyInput(session, null, false);
|
|
568
|
+
if (!modified && session.choiceState.handleKey(key)) output.redraw();
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function askContextBoard(board) {
|
|
572
|
+
return new Promise((resolve) => {
|
|
573
|
+
const session = { mode: "context-board", inputText: "/context", board, pageIndex: 0, resolve };
|
|
574
|
+
state.input.session = session;
|
|
575
|
+
state.input.active = true;
|
|
576
|
+
cancelActiveInput = () => completeTtyInput(session, "", false);
|
|
577
|
+
output.redraw(true);
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function handleContextBoardInput(session, key) {
|
|
582
|
+
const modified = key.ctrl || key.alt || key.shift;
|
|
583
|
+
if (!modified && key.name === "escape") {
|
|
584
|
+
completeTtyInput(session, "", false);
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
if (!modified && (key.name === "tab" || key.name === "left" || key.name === "right")) {
|
|
588
|
+
session.pageIndex = (session.pageIndex + 1) % 2;
|
|
589
|
+
output.redraw();
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function askForkPointMenu(items) {
|
|
594
|
+
return new Promise((resolve) => {
|
|
595
|
+
const choiceState = createChoiceMenuState(items.map((item) => item.label), items[0].label);
|
|
596
|
+
const session = { mode: "fork", inputText: "/fork", choiceState, items, resolve };
|
|
597
|
+
state.input.session = session;
|
|
598
|
+
state.input.active = true;
|
|
599
|
+
cancelActiveInput = () => completeTtyInput(session, null, false);
|
|
600
|
+
output.redraw(true);
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
|
|
516
604
|
function syncSlashMenu(session) {
|
|
517
605
|
session.menuState.setInput(session.editor.input());
|
|
518
606
|
return session.menuState.matches();
|
|
@@ -529,6 +617,29 @@ export function createCliInputActions({
|
|
|
529
617
|
return typeof prompt === "function" ? prompt() : prompt;
|
|
530
618
|
}
|
|
531
619
|
|
|
620
|
+
// External input (rind send) enters the same path as a typed submit: echo
|
|
621
|
+
// only when a typed enter would echo, then command-first dispatch.
|
|
622
|
+
function dispatchExternal(text) {
|
|
623
|
+
const value = String(text || "");
|
|
624
|
+
if (!value.trim()) {
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
if (!state.turn.active && !value.startsWith("/")) {
|
|
628
|
+
output.writeUserInput(value, "send");
|
|
629
|
+
}
|
|
630
|
+
void getCommandController().handle(value)
|
|
631
|
+
.then((handled) => {
|
|
632
|
+
if (!handled) {
|
|
633
|
+
getTurnController().submit(value);
|
|
634
|
+
}
|
|
635
|
+
})
|
|
636
|
+
.catch((error) => {
|
|
637
|
+
if (state.runtime.status !== "closing") {
|
|
638
|
+
output.writeError(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
|
|
532
643
|
return {
|
|
533
644
|
ask,
|
|
534
645
|
answerQuestion,
|
|
@@ -538,11 +649,14 @@ export function createCliInputActions({
|
|
|
538
649
|
clearPendingInputs,
|
|
539
650
|
handleTerminalInput,
|
|
540
651
|
handleTerminalPaste,
|
|
652
|
+
dispatchExternal,
|
|
541
653
|
askModelMenu,
|
|
542
654
|
askEffortMenu,
|
|
543
655
|
askThemeMenu,
|
|
544
656
|
askSessionMenu,
|
|
545
657
|
askTeamBlueprint,
|
|
658
|
+
askForkPointMenu,
|
|
659
|
+
askContextBoard,
|
|
546
660
|
cancel: () => cancelActiveInput?.(),
|
|
547
661
|
};
|
|
548
662
|
}
|