@zhongqian97-code/ecode 0.5.59 → 0.5.61
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/altScreen-I6W4LBRE.js +46 -0
- package/dist/{chunk-V3JQ7HAU.js → chunk-HC62ZZI6.js} +1 -1
- package/dist/{chunk-SIQQG6FT.js → chunk-LODP7T4D.js} +31 -1
- package/dist/{chunk-N3IDMSG5.js → chunk-ZNCND354.js} +1 -1
- package/dist/index.js +14 -21
- package/dist/{ui-STSJVDXD.js → ui-DFEOOA36.js} +279 -79
- package/dist/{web-3CS3TO2E.js → web-N7JFJIBC.js} +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const _ew=process.emitWarning.bind(process);process.emitWarning=function(w,...a){if((w?.message??w)?.includes?.('punycode'))return;_ew(w,...a);};
|
|
3
|
+
|
|
4
|
+
// src/ui/altScreen.ts
|
|
5
|
+
import { writeSync as fsWriteSync } from "fs";
|
|
6
|
+
var ENTER_ALT_SCREEN_SEQ = "\x1B[?1049h\x1B[H";
|
|
7
|
+
var EXIT_ALT_SCREEN_SEQ = "\x1B[?1049l";
|
|
8
|
+
var DISABLE_TERMINAL_MODES_SEQ = "\x1B[?1004l\x1B[?1002l\x1B[?1006l";
|
|
9
|
+
function installCrashCleanup(opts = {}) {
|
|
10
|
+
const writeSync = opts.writeSync ?? ((s) => {
|
|
11
|
+
try {
|
|
12
|
+
fsWriteSync(1, s);
|
|
13
|
+
} catch {
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
const signals = opts.signals ?? ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
17
|
+
let cleaned = false;
|
|
18
|
+
const cleanup = () => {
|
|
19
|
+
if (cleaned) return;
|
|
20
|
+
cleaned = true;
|
|
21
|
+
writeSync(DISABLE_TERMINAL_MODES_SEQ);
|
|
22
|
+
writeSync(EXIT_ALT_SCREEN_SEQ);
|
|
23
|
+
};
|
|
24
|
+
const onExit = () => {
|
|
25
|
+
cleanup();
|
|
26
|
+
};
|
|
27
|
+
process.on("exit", onExit);
|
|
28
|
+
const sigHandlers = signals.map((sig) => {
|
|
29
|
+
const h = () => {
|
|
30
|
+
cleanup();
|
|
31
|
+
process.exit(0);
|
|
32
|
+
};
|
|
33
|
+
process.on(sig, h);
|
|
34
|
+
return [sig, h];
|
|
35
|
+
});
|
|
36
|
+
return () => {
|
|
37
|
+
process.off("exit", onExit);
|
|
38
|
+
for (const [sig, h] of sigHandlers) process.off(sig, h);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
DISABLE_TERMINAL_MODES_SEQ,
|
|
43
|
+
ENTER_ALT_SCREEN_SEQ,
|
|
44
|
+
EXIT_ALT_SCREEN_SEQ,
|
|
45
|
+
installCrashCleanup
|
|
46
|
+
};
|
|
@@ -134,6 +134,33 @@ function saveConfig(partial) {
|
|
|
134
134
|
|
|
135
135
|
// src/providers/openai.ts
|
|
136
136
|
import OpenAI from "openai";
|
|
137
|
+
function trimToFirstJson(s) {
|
|
138
|
+
try {
|
|
139
|
+
JSON.parse(s);
|
|
140
|
+
return s;
|
|
141
|
+
} catch {
|
|
142
|
+
}
|
|
143
|
+
let depth = 0, inStr = false, esc = false;
|
|
144
|
+
for (let i = 0; i < s.length; i++) {
|
|
145
|
+
const c = s[i];
|
|
146
|
+
if (esc) {
|
|
147
|
+
esc = false;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (c === "\\" && inStr) {
|
|
151
|
+
esc = true;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (c === '"') {
|
|
155
|
+
inStr = !inStr;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (inStr) continue;
|
|
159
|
+
if (c === "{" || c === "[") depth++;
|
|
160
|
+
else if ((c === "}" || c === "]") && --depth === 0) return s.slice(0, i + 1);
|
|
161
|
+
}
|
|
162
|
+
return s;
|
|
163
|
+
}
|
|
137
164
|
function createOpenAIProvider(profile) {
|
|
138
165
|
const THINK_END = "</think>";
|
|
139
166
|
const openai = new OpenAI({
|
|
@@ -302,7 +329,10 @@ function createOpenAIProvider(profile) {
|
|
|
302
329
|
finishReason: choice.finish_reason,
|
|
303
330
|
// tcAccumulator 为空说明本轮没有工具调用,传 undefined 而非空数组,
|
|
304
331
|
// 让调用方用 if (chunk.toolCalls) 做简洁判断
|
|
305
|
-
toolCalls: tcAccumulator.size > 0 ? Array.from(tcAccumulator.values())
|
|
332
|
+
toolCalls: tcAccumulator.size > 0 ? Array.from(tcAccumulator.values()).map((tc) => ({
|
|
333
|
+
...tc,
|
|
334
|
+
arguments: trimToFirstJson(tc.arguments)
|
|
335
|
+
})) : void 0,
|
|
306
336
|
reasoning: reasoningAccumulator || void 0,
|
|
307
337
|
// reasoningDetails 仅在流中出现过结构化推理时返回(MiniMax 兼容)
|
|
308
338
|
reasoningDetails: reasoningDetailsAcc.size > 0 ? Array.from(reasoningDetailsAcc.values()) : void 0,
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
cmdSessionsInspect,
|
|
6
6
|
cmdSessionsList,
|
|
7
7
|
cmdSessionsReplay
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-ZNCND354.js";
|
|
9
9
|
import {
|
|
10
10
|
APPLY_PATCH_TOOL,
|
|
11
11
|
BASH_TOOL,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
todo,
|
|
34
34
|
webFetch,
|
|
35
35
|
writeFile
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-HC62ZZI6.js";
|
|
37
37
|
import {
|
|
38
38
|
createProvider,
|
|
39
39
|
createSessionMetadata,
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
resolveActiveProfile,
|
|
43
43
|
updateSessionMetadata,
|
|
44
44
|
writeSessionMetadata
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-LODP7T4D.js";
|
|
46
46
|
|
|
47
47
|
// src/index.ts
|
|
48
48
|
import { createRequire } from "module";
|
|
@@ -197,7 +197,12 @@ async function runPipe(prompt, llm, out = process.stdout, systemPrompt) {
|
|
|
197
197
|
});
|
|
198
198
|
for (const tc of toolCalls) {
|
|
199
199
|
emit(out, { type: "tool_call", id: tc.id, name: tc.name, arguments: tc.arguments });
|
|
200
|
-
|
|
200
|
+
let content;
|
|
201
|
+
try {
|
|
202
|
+
content = await executeToolCall(tc.name, tc.arguments);
|
|
203
|
+
} catch (err) {
|
|
204
|
+
content = `Tool error: ${String(err)}`;
|
|
205
|
+
}
|
|
201
206
|
emit(out, { type: "tool_result", toolCallId: tc.id, name: tc.name, content });
|
|
202
207
|
messages.push({ role: "tool", tool_call_id: tc.id, content });
|
|
203
208
|
}
|
|
@@ -814,7 +819,7 @@ if (rawArgs[0] === "web") {
|
|
|
814
819
|
webAutoApprove = true;
|
|
815
820
|
}
|
|
816
821
|
}
|
|
817
|
-
const { buildServer, generateAccessToken } = await import("./web-
|
|
822
|
+
const { buildServer, generateAccessToken } = await import("./web-N7JFJIBC.js");
|
|
818
823
|
const token = finalConfig.webToken ?? generateAccessToken();
|
|
819
824
|
const manager = new SessionManager(finalConfig);
|
|
820
825
|
const __webDirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -898,21 +903,9 @@ Press Ctrl+C to stop.
|
|
|
898
903
|
process.exit(0);
|
|
899
904
|
}
|
|
900
905
|
if (process.stdout.isTTY) {
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
process.on("SIGINT", () => {
|
|
905
|
-
exitAltScreen();
|
|
906
|
-
process.exit(0);
|
|
907
|
-
});
|
|
908
|
-
process.on("SIGTERM", () => {
|
|
909
|
-
exitAltScreen();
|
|
910
|
-
process.exit(0);
|
|
911
|
-
});
|
|
912
|
-
process.on("SIGHUP", () => {
|
|
913
|
-
exitAltScreen();
|
|
914
|
-
process.exit(0);
|
|
915
|
-
});
|
|
906
|
+
const { ENTER_ALT_SCREEN_SEQ, installCrashCleanup } = await import("./altScreen-I6W4LBRE.js");
|
|
907
|
+
process.stdout.write(ENTER_ALT_SCREEN_SEQ);
|
|
908
|
+
installCrashCleanup();
|
|
916
909
|
}
|
|
917
910
|
const [nodeMaj] = process.versions.node.split(".").map(Number);
|
|
918
911
|
if (nodeMaj < 20) {
|
|
@@ -923,7 +916,7 @@ Node.js 16/18 \u8BF7\u4F7F\u7528 --web \u6216 --pipe \u6A21\u5F0F\u3002
|
|
|
923
916
|
);
|
|
924
917
|
process.exit(1);
|
|
925
918
|
}
|
|
926
|
-
const { App, React, render, createStdinFilter } = await import("./ui-
|
|
919
|
+
const { App, React, render, createStdinFilter } = await import("./ui-DFEOOA36.js");
|
|
927
920
|
const stdinFilter = process.stdin.isTTY ? createStdinFilter(process.stdin) : process.stdin;
|
|
928
921
|
render(
|
|
929
922
|
React.createElement(App, { config: finalConfig, version: VERSION, autoMode, registry, trustedSkillDirs, initialMessages, stdinFilter }),
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
todo,
|
|
25
25
|
webFetch,
|
|
26
26
|
writeFile
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-HC62ZZI6.js";
|
|
28
28
|
import {
|
|
29
29
|
handleSkillInput,
|
|
30
30
|
loadJobs,
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
resolveActiveProfile,
|
|
40
40
|
updateSessionMetadata,
|
|
41
41
|
writeSessionMetadata
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-LODP7T4D.js";
|
|
43
43
|
|
|
44
44
|
// src/ui/index.ts
|
|
45
45
|
import { default as default2 } from "react";
|
|
@@ -47,7 +47,7 @@ import { render } from "ink";
|
|
|
47
47
|
|
|
48
48
|
// src/ui/App.tsx
|
|
49
49
|
import { useState as useState3, useCallback, useRef as useRef2, useEffect as useEffect3, useMemo } from "react";
|
|
50
|
-
import { Box as Box6, Text as Text6, useInput as useInput2, useStdout } from "ink";
|
|
50
|
+
import { Box as Box6, Text as Text6, useInput as useInput2, useStdout, measureElement } from "ink";
|
|
51
51
|
|
|
52
52
|
// src/skills/executor.ts
|
|
53
53
|
import { exec } from "child_process";
|
|
@@ -296,6 +296,7 @@ function messageToLines(msg, expandTools, terminalWidth) {
|
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
// src/ui/mouseSelection.ts
|
|
299
|
+
import stringWidth2 from "string-width";
|
|
299
300
|
function initialSelectionState() {
|
|
300
301
|
return { anchor: null, focus: null, dragging: false };
|
|
301
302
|
}
|
|
@@ -328,6 +329,21 @@ function isCellSelected(row, col, state) {
|
|
|
328
329
|
if (row === end.row) return col <= end.col;
|
|
329
330
|
return true;
|
|
330
331
|
}
|
|
332
|
+
function colToStringIndex(line, col, roundUp) {
|
|
333
|
+
if (col <= 0) return 0;
|
|
334
|
+
let w = 0;
|
|
335
|
+
let idx = 0;
|
|
336
|
+
for (const ch of line) {
|
|
337
|
+
const cw = stringWidth2(ch);
|
|
338
|
+
if (w >= col) return idx;
|
|
339
|
+
if (w + cw > col) {
|
|
340
|
+
return roundUp ? idx + ch.length : idx;
|
|
341
|
+
}
|
|
342
|
+
w += cw;
|
|
343
|
+
idx += ch.length;
|
|
344
|
+
}
|
|
345
|
+
return idx;
|
|
346
|
+
}
|
|
331
347
|
function extractSelectedText(lines, state) {
|
|
332
348
|
const norm = normalizeSelection(state);
|
|
333
349
|
if (!norm) return "";
|
|
@@ -335,9 +351,11 @@ function extractSelectedText(lines, state) {
|
|
|
335
351
|
const parts = [];
|
|
336
352
|
for (let r = start.row; r <= end.row; r++) {
|
|
337
353
|
const line = lines[r] ?? "";
|
|
338
|
-
const
|
|
339
|
-
const
|
|
340
|
-
|
|
354
|
+
const colStartVis = r === start.row ? start.col : 0;
|
|
355
|
+
const colEndVis = r === end.row ? end.col + 1 : Number.POSITIVE_INFINITY;
|
|
356
|
+
const idxStart = colToStringIndex(line, colStartVis, false);
|
|
357
|
+
const idxEnd = colToStringIndex(line, colEndVis, true);
|
|
358
|
+
parts.push(line.slice(idxStart, idxEnd));
|
|
341
359
|
}
|
|
342
360
|
return parts.join("\n");
|
|
343
361
|
}
|
|
@@ -403,6 +421,37 @@ function ConversationHistory({
|
|
|
403
421
|
// src/ui/Input.tsx
|
|
404
422
|
import { useState as useState2, useEffect as useEffect2, useRef, forwardRef, useImperativeHandle } from "react";
|
|
405
423
|
import { Box as Box3, Text as Text3, useInput } from "ink";
|
|
424
|
+
|
|
425
|
+
// src/ui/inputClick.ts
|
|
426
|
+
import stringWidth3 from "string-width";
|
|
427
|
+
var INPUT_PREFIX_WIDTH = 2;
|
|
428
|
+
function colToStringIndex2(line, col) {
|
|
429
|
+
if (col <= 0) return 0;
|
|
430
|
+
let w = 0;
|
|
431
|
+
let idx = 0;
|
|
432
|
+
for (const ch of line) {
|
|
433
|
+
const cw = stringWidth3(ch);
|
|
434
|
+
if (w + cw > col) break;
|
|
435
|
+
w += cw;
|
|
436
|
+
idx += ch.length;
|
|
437
|
+
}
|
|
438
|
+
return idx;
|
|
439
|
+
}
|
|
440
|
+
function clickToCursor(value, localRow, localCol) {
|
|
441
|
+
if (value.length === 0) return 0;
|
|
442
|
+
const lines = value.split("\n");
|
|
443
|
+
if (localRow < 0) return 0;
|
|
444
|
+
if (localRow >= lines.length) return value.length;
|
|
445
|
+
let pos = 0;
|
|
446
|
+
for (let i = 0; i < localRow; i++) {
|
|
447
|
+
pos += lines[i].length + 1;
|
|
448
|
+
}
|
|
449
|
+
const lineCol = Math.max(0, localCol - INPUT_PREFIX_WIDTH);
|
|
450
|
+
pos += colToStringIndex2(lines[localRow], lineCol);
|
|
451
|
+
return pos;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// src/ui/Input.tsx
|
|
406
455
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
407
456
|
var CURSOR_CHAR = "\u258C";
|
|
408
457
|
var BLINK_INTERVAL_MS = 530;
|
|
@@ -430,11 +479,14 @@ function wordForward(s, pos) {
|
|
|
430
479
|
var Input = forwardRef(function Input2({ isActive, onSubmit, onChange, placeholder }, ref) {
|
|
431
480
|
const [value, setValue] = useState2("");
|
|
432
481
|
const [cursorPos, setCursorPos] = useState2(0);
|
|
482
|
+
const [inputSel, setInputSel] = useState2(null);
|
|
433
483
|
const [cursorVisible, setCursorVisible] = useState2(true);
|
|
434
484
|
const valueRef = useRef(value);
|
|
435
485
|
valueRef.current = value;
|
|
436
486
|
const cursorPosRef = useRef(cursorPos);
|
|
437
487
|
cursorPosRef.current = cursorPos;
|
|
488
|
+
const inputSelRef = useRef(inputSel);
|
|
489
|
+
inputSelRef.current = inputSel;
|
|
438
490
|
const onChangeRef = useRef(onChange);
|
|
439
491
|
onChangeRef.current = onChange;
|
|
440
492
|
const onSubmitRef = useRef(onSubmit);
|
|
@@ -446,7 +498,42 @@ var Input = forwardRef(function Input2({ isActive, onSubmit, onChange, placehold
|
|
|
446
498
|
cursorPosRef.current = text.length;
|
|
447
499
|
setValue(text);
|
|
448
500
|
setCursorPos(text.length);
|
|
501
|
+
inputSelRef.current = null;
|
|
502
|
+
setInputSel(null);
|
|
449
503
|
(_a = onChangeRef.current) == null ? void 0 : _a.call(onChangeRef, text);
|
|
504
|
+
},
|
|
505
|
+
getValue() {
|
|
506
|
+
return valueRef.current;
|
|
507
|
+
},
|
|
508
|
+
setCursorByClick(line, col) {
|
|
509
|
+
const pos = clickToCursor(valueRef.current, line, col);
|
|
510
|
+
cursorPosRef.current = pos;
|
|
511
|
+
setCursorPos(pos);
|
|
512
|
+
},
|
|
513
|
+
startInputSelection(line, col) {
|
|
514
|
+
const pos = clickToCursor(valueRef.current, line, col);
|
|
515
|
+
const next = { anchor: pos, focus: pos };
|
|
516
|
+
inputSelRef.current = next;
|
|
517
|
+
setInputSel(next);
|
|
518
|
+
},
|
|
519
|
+
extendInputSelection(line, col) {
|
|
520
|
+
const cur = inputSelRef.current;
|
|
521
|
+
if (!cur) return;
|
|
522
|
+
const pos = clickToCursor(valueRef.current, line, col);
|
|
523
|
+
const next = { anchor: cur.anchor, focus: pos };
|
|
524
|
+
inputSelRef.current = next;
|
|
525
|
+
setInputSel(next);
|
|
526
|
+
},
|
|
527
|
+
getInputSelectionText() {
|
|
528
|
+
const cur = inputSelRef.current;
|
|
529
|
+
if (!cur || cur.anchor === cur.focus) return "";
|
|
530
|
+
const s = Math.min(cur.anchor, cur.focus);
|
|
531
|
+
const e = Math.max(cur.anchor, cur.focus);
|
|
532
|
+
return valueRef.current.slice(s, e);
|
|
533
|
+
},
|
|
534
|
+
clearInputSelection() {
|
|
535
|
+
inputSelRef.current = null;
|
|
536
|
+
setInputSel(null);
|
|
450
537
|
}
|
|
451
538
|
}));
|
|
452
539
|
useEffect2(() => {
|
|
@@ -474,6 +561,10 @@ var Input = forwardRef(function Input2({ isActive, onSubmit, onChange, placehold
|
|
|
474
561
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
475
562
|
const v = valueRef.current;
|
|
476
563
|
const pos = cursorPosRef.current;
|
|
564
|
+
if (inputSelRef.current) {
|
|
565
|
+
inputSelRef.current = null;
|
|
566
|
+
setInputSel(null);
|
|
567
|
+
}
|
|
477
568
|
if (key.return && key.shift) {
|
|
478
569
|
const newValue = v.slice(0, pos) + "\n" + v.slice(pos);
|
|
479
570
|
setValueSync(newValue);
|
|
@@ -601,9 +692,34 @@ var Input = forwardRef(function Input2({ isActive, onSubmit, onChange, placehold
|
|
|
601
692
|
}
|
|
602
693
|
remaining -= lineLen + 1;
|
|
603
694
|
}
|
|
695
|
+
const selMin = inputSel ? Math.min(inputSel.anchor, inputSel.focus) : null;
|
|
696
|
+
const selMax = inputSel ? Math.max(inputSel.anchor, inputSel.focus) : null;
|
|
697
|
+
const hasSel = selMin !== null && selMax !== null && selMin !== selMax;
|
|
604
698
|
return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: lines.map((line, idx) => {
|
|
605
699
|
const prefix = idx === 0 ? "> " : " ";
|
|
606
|
-
const showCursor = isActive && cursorVisible && idx === cursorLine;
|
|
700
|
+
const showCursor = isActive && cursorVisible && idx === cursorLine && !hasSel;
|
|
701
|
+
if (hasSel) {
|
|
702
|
+
let lineStartAbs = 0;
|
|
703
|
+
for (let i = 0; i < idx; i++) lineStartAbs += lines[i].length + 1;
|
|
704
|
+
const lineEndAbs = lineStartAbs + line.length;
|
|
705
|
+
const iStart = Math.max(lineStartAbs, selMin);
|
|
706
|
+
const iEnd = Math.min(lineEndAbs, selMax);
|
|
707
|
+
if (iStart >= iEnd) {
|
|
708
|
+
return /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
709
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", children: prefix }),
|
|
710
|
+
/* @__PURE__ */ jsx3(Text3, { children: line })
|
|
711
|
+
] }, idx);
|
|
712
|
+
}
|
|
713
|
+
const before2 = line.slice(0, iStart - lineStartAbs);
|
|
714
|
+
const selChunk = line.slice(iStart - lineStartAbs, iEnd - lineStartAbs);
|
|
715
|
+
const after2 = line.slice(iEnd - lineStartAbs);
|
|
716
|
+
return /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
717
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", children: prefix }),
|
|
718
|
+
before2 && /* @__PURE__ */ jsx3(Text3, { children: before2 }),
|
|
719
|
+
/* @__PURE__ */ jsx3(Text3, { inverse: true, children: selChunk || " " }),
|
|
720
|
+
after2 && /* @__PURE__ */ jsx3(Text3, { children: after2 })
|
|
721
|
+
] }, idx);
|
|
722
|
+
}
|
|
607
723
|
if (!showCursor) {
|
|
608
724
|
return /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
609
725
|
/* @__PURE__ */ jsx3(Text3, { color: "cyan", children: prefix }),
|
|
@@ -877,7 +993,7 @@ function computeVisibleWindow(totalLines, scrollOffset, historyMaxHeight) {
|
|
|
877
993
|
}
|
|
878
994
|
function mouseRowToLineIndex(opts) {
|
|
879
995
|
if (opts.visibleCount <= 0) return null;
|
|
880
|
-
const bottomRows = STATUS_BAR_ROWS + opts.skillAcRows + opts.fileAcRows + opts.selectedItemsRows + opts.inputRows;
|
|
996
|
+
const bottomRows = opts.bottomChromeRows ?? STATUS_BAR_ROWS + (opts.skillAcRows ?? 0) + (opts.fileAcRows ?? 0) + (opts.selectedItemsRows ?? 0) + (opts.inputRows ?? 1);
|
|
881
997
|
const innerBoxHeight = opts.terminalRows - bottomRows;
|
|
882
998
|
const chTopRow = innerBoxHeight - opts.visibleCount;
|
|
883
999
|
const chBottomRow = innerBoxHeight - 1;
|
|
@@ -2457,6 +2573,7 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
|
|
|
2457
2573
|
const inputHistoryRef = useRef2([]);
|
|
2458
2574
|
inputHistoryRef.current = inputHistory;
|
|
2459
2575
|
const historyIndexRef = useRef2(-1);
|
|
2576
|
+
const historyDraftRef = useRef2("");
|
|
2460
2577
|
const isNavigatingHistoryRef = useRef2(false);
|
|
2461
2578
|
const totalLines = useMemo(() => {
|
|
2462
2579
|
const visible = messages.filter((m) => m.role !== "system");
|
|
@@ -2473,10 +2590,8 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
|
|
|
2473
2590
|
historyMaxHeightRef.current = historyMaxHeight;
|
|
2474
2591
|
const selectionStateRef = useRef2(selectionState);
|
|
2475
2592
|
selectionStateRef.current = selectionState;
|
|
2593
|
+
const bottomChromeRef = useRef2(null);
|
|
2476
2594
|
const inputRowsRef = useRef2(1);
|
|
2477
|
-
const skillAcRowsRef = useRef2(0);
|
|
2478
|
-
const fileAcRowsRef = useRef2(0);
|
|
2479
|
-
const selectedItemsRowsRef = useRef2(0);
|
|
2480
2595
|
const terminalRowsRef = useRef2((stdout == null ? void 0 : stdout.rows) ?? 24);
|
|
2481
2596
|
terminalRowsRef.current = (stdout == null ? void 0 : stdout.rows) ?? 24;
|
|
2482
2597
|
const pendingConfirmRef = useRef2(null);
|
|
@@ -2541,16 +2656,28 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
|
|
|
2541
2656
|
automationManagerRef.current.stop();
|
|
2542
2657
|
};
|
|
2543
2658
|
}, []);
|
|
2659
|
+
const enableModesSeq = "\x1B[?1002h\x1B[?1006h\x1B[?1004h";
|
|
2544
2660
|
useEffect3(() => {
|
|
2545
2661
|
if (!stdout) return;
|
|
2546
|
-
stdout.write(
|
|
2662
|
+
stdout.write(enableModesSeq);
|
|
2547
2663
|
return () => {
|
|
2548
|
-
stdout.write("\x1B[?1002l\x1B[?1006l");
|
|
2664
|
+
stdout.write("\x1B[?1004l\x1B[?1002l\x1B[?1006l");
|
|
2549
2665
|
};
|
|
2550
2666
|
}, [stdout]);
|
|
2667
|
+
useEffect3(() => {
|
|
2668
|
+
if (!stdinFilter || !stdout) return;
|
|
2669
|
+
const onResumed = () => {
|
|
2670
|
+
stdout.write(enableModesSeq);
|
|
2671
|
+
};
|
|
2672
|
+
stdinFilter.on("resumed", onResumed);
|
|
2673
|
+
return () => {
|
|
2674
|
+
stdinFilter.off("resumed", onResumed);
|
|
2675
|
+
};
|
|
2676
|
+
}, [stdinFilter, stdout]);
|
|
2551
2677
|
useEffect3(() => {
|
|
2552
2678
|
if (!stdinFilter) return;
|
|
2553
2679
|
const onMouse = (e) => {
|
|
2680
|
+
var _a, _b, _c, _d, _e;
|
|
2554
2681
|
if (e.kind === "scroll") {
|
|
2555
2682
|
const step = Math.max(1, Math.floor(historyMaxHeightRef.current / 2));
|
|
2556
2683
|
if (e.direction === "up") {
|
|
@@ -2560,18 +2687,42 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
|
|
|
2560
2687
|
}
|
|
2561
2688
|
return;
|
|
2562
2689
|
}
|
|
2690
|
+
const tRows = terminalRowsRef.current;
|
|
2691
|
+
const inRows = inputRowsRef.current;
|
|
2692
|
+
const inputStartRow = tRows - inRows;
|
|
2693
|
+
if (e.row >= inputStartRow && e.row <= tRows - 1) {
|
|
2694
|
+
const localRow = e.row - inputStartRow;
|
|
2695
|
+
if (e.type === "leftDown") {
|
|
2696
|
+
(_a = inputRef.current) == null ? void 0 : _a.setCursorByClick(localRow, e.col);
|
|
2697
|
+
(_b = inputRef.current) == null ? void 0 : _b.startInputSelection(localRow, e.col);
|
|
2698
|
+
} else if (e.type === "leftDrag") {
|
|
2699
|
+
(_c = inputRef.current) == null ? void 0 : _c.extendInputSelection(localRow, e.col);
|
|
2700
|
+
} else if (e.type === "leftUp") {
|
|
2701
|
+
const text = ((_d = inputRef.current) == null ? void 0 : _d.getInputSelectionText()) ?? "";
|
|
2702
|
+
if (text.length > 0 && stdout) {
|
|
2703
|
+
const b64 = Buffer.from(text, "utf8").toString("base64");
|
|
2704
|
+
stdout.write(`\x1B]52;c;${b64}\x07`);
|
|
2705
|
+
} else {
|
|
2706
|
+
(_e = inputRef.current) == null ? void 0 : _e.clearInputSelection();
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
return;
|
|
2710
|
+
}
|
|
2563
2711
|
const window = computeVisibleWindow(
|
|
2564
2712
|
totalLinesRef.current,
|
|
2565
2713
|
scrollOffsetRef.current,
|
|
2566
2714
|
historyMaxHeightRef.current
|
|
2567
2715
|
);
|
|
2716
|
+
let bottomRows;
|
|
2717
|
+
if (bottomChromeRef.current) {
|
|
2718
|
+
const m = measureElement(bottomChromeRef.current);
|
|
2719
|
+
if (m && m.height > 0) bottomRows = m.height;
|
|
2720
|
+
}
|
|
2568
2721
|
const lineIdx = mouseRowToLineIndex({
|
|
2569
2722
|
mouseRow: e.row,
|
|
2570
|
-
terminalRows:
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
fileAcRows: fileAcRowsRef.current,
|
|
2574
|
-
selectedItemsRows: selectedItemsRowsRef.current,
|
|
2723
|
+
terminalRows: tRows,
|
|
2724
|
+
bottomChromeRows: bottomRows,
|
|
2725
|
+
inputRows: inRows,
|
|
2575
2726
|
visibleCount: window.visibleCount,
|
|
2576
2727
|
hasScrollIndicator: window.hasScrollIndicator
|
|
2577
2728
|
});
|
|
@@ -2614,7 +2765,7 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
|
|
|
2614
2765
|
};
|
|
2615
2766
|
}, [fileAcState.query]);
|
|
2616
2767
|
useInput2((input, key) => {
|
|
2617
|
-
var _a, _b, _c
|
|
2768
|
+
var _a, _b, _c;
|
|
2618
2769
|
if (key.escape && status === "thinking" && abortControllerRef.current) {
|
|
2619
2770
|
abortControllerRef.current.abort();
|
|
2620
2771
|
return;
|
|
@@ -2688,28 +2839,48 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
|
|
|
2688
2839
|
setScrollOffset((prev) => Math.min(prev + scrollStep, Math.max(0, totalLines - 1)));
|
|
2689
2840
|
return;
|
|
2690
2841
|
}
|
|
2691
|
-
|
|
2842
|
+
const currentInput = ((_c = inputRef.current) == null ? void 0 : _c.getValue()) ?? "";
|
|
2843
|
+
const inHistory = historyIndexRef.current >= 0;
|
|
2844
|
+
const canEnterHistory = currentInput === "" || inHistory;
|
|
2845
|
+
const navUp = () => {
|
|
2846
|
+
var _a2;
|
|
2692
2847
|
const history = inputHistoryRef.current;
|
|
2693
2848
|
const newIndex = Math.min(historyIndexRef.current + 1, history.length - 1);
|
|
2694
|
-
if (newIndex
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2849
|
+
if (newIndex < 0 || newIndex >= history.length) return;
|
|
2850
|
+
if (historyIndexRef.current === -1) historyDraftRef.current = currentInput;
|
|
2851
|
+
historyIndexRef.current = newIndex;
|
|
2852
|
+
isNavigatingHistoryRef.current = true;
|
|
2853
|
+
(_a2 = inputRef.current) == null ? void 0 : _a2.fill(history[newIndex]);
|
|
2854
|
+
};
|
|
2855
|
+
const navDown = () => {
|
|
2856
|
+
var _a2, _b2;
|
|
2702
2857
|
const history = inputHistoryRef.current;
|
|
2703
2858
|
if (historyIndexRef.current > 0) {
|
|
2704
2859
|
const newIndex = historyIndexRef.current - 1;
|
|
2705
2860
|
historyIndexRef.current = newIndex;
|
|
2706
2861
|
isNavigatingHistoryRef.current = true;
|
|
2707
|
-
(
|
|
2862
|
+
(_a2 = inputRef.current) == null ? void 0 : _a2.fill(history[newIndex]);
|
|
2708
2863
|
} else if (historyIndexRef.current === 0) {
|
|
2709
2864
|
historyIndexRef.current = -1;
|
|
2710
2865
|
isNavigatingHistoryRef.current = true;
|
|
2711
|
-
(
|
|
2866
|
+
(_b2 = inputRef.current) == null ? void 0 : _b2.fill(historyDraftRef.current);
|
|
2867
|
+
historyDraftRef.current = "";
|
|
2712
2868
|
}
|
|
2869
|
+
};
|
|
2870
|
+
if (canEnterHistory && key.upArrow) {
|
|
2871
|
+
navUp();
|
|
2872
|
+
return;
|
|
2873
|
+
}
|
|
2874
|
+
if (canEnterHistory && key.downArrow) {
|
|
2875
|
+
navDown();
|
|
2876
|
+
return;
|
|
2877
|
+
}
|
|
2878
|
+
if (key.ctrl && input === "p") {
|
|
2879
|
+
navUp();
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2882
|
+
if (key.ctrl && input === "n") {
|
|
2883
|
+
navDown();
|
|
2713
2884
|
return;
|
|
2714
2885
|
}
|
|
2715
2886
|
});
|
|
@@ -3054,9 +3225,6 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
|
|
|
3054
3225
|
const skillSuggestions = registry ? computeSuggestions(registry.list(), acState) : [];
|
|
3055
3226
|
const acOpen = isOpen(acState, skillSuggestions);
|
|
3056
3227
|
const facOpen = isOpen2(fileAcState, fileSuggestions);
|
|
3057
|
-
skillAcRowsRef.current = acOpen ? skillSuggestions.length + 2 : 0;
|
|
3058
|
-
fileAcRowsRef.current = facOpen ? fileSuggestions.length + 2 : 0;
|
|
3059
|
-
selectedItemsRowsRef.current = selectedItems.length > 0 ? 1 : 0;
|
|
3060
3228
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", height: "100%", children: [
|
|
3061
3229
|
/* @__PURE__ */ jsx6(Box6, { flexGrow: 1, flexDirection: "column", justifyContent: "flex-end", children: /* @__PURE__ */ jsx6(
|
|
3062
3230
|
ConversationHistory,
|
|
@@ -3069,46 +3237,48 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
|
|
|
3069
3237
|
selection: selectionState
|
|
3070
3238
|
}
|
|
3071
3239
|
) }),
|
|
3072
|
-
/* @__PURE__ */
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3240
|
+
/* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", ref: bottomChromeRef, children: [
|
|
3241
|
+
/* @__PURE__ */ jsx6(
|
|
3242
|
+
StatusBar,
|
|
3243
|
+
{
|
|
3244
|
+
status,
|
|
3245
|
+
toolName,
|
|
3246
|
+
confirmPrompt,
|
|
3247
|
+
version,
|
|
3248
|
+
tokenUsage
|
|
3249
|
+
}
|
|
3250
|
+
),
|
|
3251
|
+
/* @__PURE__ */ jsx6(
|
|
3252
|
+
SkillAutocomplete,
|
|
3253
|
+
{
|
|
3254
|
+
suggestions: skillSuggestions,
|
|
3255
|
+
selectedIndex: acState.selectedIndex,
|
|
3256
|
+
isOpen: acOpen
|
|
3257
|
+
}
|
|
3258
|
+
),
|
|
3259
|
+
/* @__PURE__ */ jsx6(
|
|
3260
|
+
FileAutocomplete,
|
|
3261
|
+
{
|
|
3262
|
+
suggestions: fileSuggestions,
|
|
3263
|
+
selectedIndex: fileAcState.selectedIndex,
|
|
3264
|
+
isOpen: facOpen
|
|
3265
|
+
}
|
|
3266
|
+
),
|
|
3267
|
+
selectedItems.length > 0 && /* @__PURE__ */ jsx6(Box6, { paddingLeft: 1, children: /* @__PURE__ */ jsxs6(Text6, { color: "cyan", dimColor: true, children: [
|
|
3268
|
+
"Selected: ",
|
|
3269
|
+
selectedItems.map((i) => i.label).join(", ")
|
|
3270
|
+
] }) }),
|
|
3271
|
+
/* @__PURE__ */ jsx6(
|
|
3272
|
+
Input_default,
|
|
3273
|
+
{
|
|
3274
|
+
ref: inputRef,
|
|
3275
|
+
isActive: isInputActive,
|
|
3276
|
+
onSubmit: handleSubmit,
|
|
3277
|
+
onChange: handleInputTextChange,
|
|
3278
|
+
placeholder: status === "awaiting_confirm" ? "y / n" : void 0
|
|
3279
|
+
}
|
|
3280
|
+
)
|
|
3281
|
+
] })
|
|
3112
3282
|
] });
|
|
3113
3283
|
}
|
|
3114
3284
|
|
|
@@ -3174,6 +3344,7 @@ function tokenizeStdin(input, pendingIn) {
|
|
|
3174
3344
|
let i = 0;
|
|
3175
3345
|
let keyboardOut = "";
|
|
3176
3346
|
const events = [];
|
|
3347
|
+
const focusEvents = [];
|
|
3177
3348
|
while (i < data.length) {
|
|
3178
3349
|
const ch = data[i];
|
|
3179
3350
|
if (ch !== "\x1B") {
|
|
@@ -3195,13 +3366,18 @@ function tokenizeStdin(input, pendingIn) {
|
|
|
3195
3366
|
i += mLen;
|
|
3196
3367
|
continue;
|
|
3197
3368
|
}
|
|
3369
|
+
if (tail.length >= 3 && tail[1] === "[" && (tail[2] === "I" || tail[2] === "O")) {
|
|
3370
|
+
focusEvents.push({ kind: "focus", focused: tail[2] === "I" });
|
|
3371
|
+
i += 3;
|
|
3372
|
+
continue;
|
|
3373
|
+
}
|
|
3198
3374
|
if (isMousePartial(tail) && tail.length < MAX_MOUSE_SEQ) {
|
|
3199
|
-
return { keyboard: keyboardOut, pending: tail, events };
|
|
3375
|
+
return { keyboard: keyboardOut, pending: tail, events, focusEvents };
|
|
3200
3376
|
}
|
|
3201
3377
|
keyboardOut += ch;
|
|
3202
3378
|
i++;
|
|
3203
3379
|
}
|
|
3204
|
-
return { keyboard: keyboardOut, pending: "", events };
|
|
3380
|
+
return { keyboard: keyboardOut, pending: "", events, focusEvents };
|
|
3205
3381
|
}
|
|
3206
3382
|
|
|
3207
3383
|
// src/ui/stdinFilter.ts
|
|
@@ -3209,12 +3385,22 @@ var StdinFilterImpl = class extends Transform {
|
|
|
3209
3385
|
isTTY;
|
|
3210
3386
|
source;
|
|
3211
3387
|
pending = "";
|
|
3212
|
-
|
|
3388
|
+
// 焦点状态——cc-haha 把 focus 作 signal 而非 mode switch(§5.4)。
|
|
3389
|
+
// CSI I/O 切换;任何字节到达时若为 false 由 failsafe 强制回 true。
|
|
3390
|
+
focused = true;
|
|
3391
|
+
// resume 检测:最近一次活动时间戳;间隔 > resumeIdleMs 算 SSH 重连 / tmux detach 回来。
|
|
3392
|
+
lastByteAt = 0;
|
|
3393
|
+
resumeIdleMs;
|
|
3394
|
+
constructor(source, opts = {}) {
|
|
3213
3395
|
super();
|
|
3214
3396
|
this.source = source;
|
|
3215
3397
|
this.isTTY = source.isTTY ?? false;
|
|
3398
|
+
this.resumeIdleMs = opts.resumeIdleMs ?? 5e3;
|
|
3216
3399
|
source.pipe(this);
|
|
3217
3400
|
}
|
|
3401
|
+
isFocused() {
|
|
3402
|
+
return this.focused;
|
|
3403
|
+
}
|
|
3218
3404
|
setRawMode(mode) {
|
|
3219
3405
|
var _a, _b;
|
|
3220
3406
|
(_b = (_a = this.source).setRawMode) == null ? void 0 : _b.call(_a, mode);
|
|
@@ -3229,9 +3415,23 @@ var StdinFilterImpl = class extends Transform {
|
|
|
3229
3415
|
}
|
|
3230
3416
|
_transform(chunk, _encoding, callback) {
|
|
3231
3417
|
const s = typeof chunk === "string" ? chunk : chunk.toString("binary");
|
|
3232
|
-
const
|
|
3418
|
+
const now = Date.now();
|
|
3419
|
+
if (this.lastByteAt > 0 && now - this.lastByteAt >= this.resumeIdleMs) {
|
|
3420
|
+
this.emit("resumed");
|
|
3421
|
+
}
|
|
3422
|
+
this.lastByteAt = now;
|
|
3423
|
+
const { keyboard, pending, events, focusEvents } = tokenizeStdin(s, this.pending);
|
|
3233
3424
|
this.pending = pending;
|
|
3425
|
+
for (const ev of focusEvents) {
|
|
3426
|
+
this.focused = ev.focused;
|
|
3427
|
+
this.emit("focus", ev);
|
|
3428
|
+
}
|
|
3234
3429
|
for (const ev of events) this.emit("mouse", ev);
|
|
3430
|
+
const hadNonFocusActivity = events.length > 0 || keyboard.length > 0;
|
|
3431
|
+
if (hadNonFocusActivity && !this.focused) {
|
|
3432
|
+
this.focused = true;
|
|
3433
|
+
this.emit("focus", { kind: "focus", focused: true });
|
|
3434
|
+
}
|
|
3235
3435
|
if (keyboard.length > 0) {
|
|
3236
3436
|
callback(null, Buffer.from(keyboard, "binary"));
|
|
3237
3437
|
} else {
|
|
@@ -3239,8 +3439,8 @@ var StdinFilterImpl = class extends Transform {
|
|
|
3239
3439
|
}
|
|
3240
3440
|
}
|
|
3241
3441
|
};
|
|
3242
|
-
function createStdinFilter(source) {
|
|
3243
|
-
return new StdinFilterImpl(source);
|
|
3442
|
+
function createStdinFilter(source, opts) {
|
|
3443
|
+
return new StdinFilterImpl(source, opts);
|
|
3244
3444
|
}
|
|
3245
3445
|
export {
|
|
3246
3446
|
App,
|
|
@@ -3,7 +3,7 @@ const _ew=process.emitWarning.bind(process);process.emitWarning=function(w,...a)
|
|
|
3
3
|
import {
|
|
4
4
|
cmdSessionsFork,
|
|
5
5
|
cmdSessionsReplay
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ZNCND354.js";
|
|
7
7
|
import {
|
|
8
8
|
handleSkillInput,
|
|
9
9
|
loadJobs,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
loadMessagesFromJsonl,
|
|
18
18
|
resolveActiveProfile,
|
|
19
19
|
saveConfig
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-LODP7T4D.js";
|
|
21
21
|
|
|
22
22
|
// src/web/server.ts
|
|
23
23
|
import Fastify from "fastify";
|