@zhongqian97-code/ecode 0.5.55 → 0.5.57

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/index.js CHANGED
@@ -814,7 +814,7 @@ if (rawArgs[0] === "web") {
814
814
  webAutoApprove = true;
815
815
  }
816
816
  }
817
- const { buildServer, generateAccessToken } = await import("./web-XPP3PJJZ.js");
817
+ const { buildServer, generateAccessToken } = await import("./web-3CS3TO2E.js");
818
818
  const token = finalConfig.webToken ?? generateAccessToken();
819
819
  const manager = new SessionManager(finalConfig);
820
820
  const __webDirname = dirname(fileURLToPath(import.meta.url));
@@ -923,6 +923,10 @@ Node.js 16/18 \u8BF7\u4F7F\u7528 --web \u6216 --pipe \u6A21\u5F0F\u3002
923
923
  );
924
924
  process.exit(1);
925
925
  }
926
- const { App, React, render } = await import("./ui-5R3MFOW2.js");
927
- render(React.createElement(App, { config: finalConfig, version: VERSION, autoMode, registry, trustedSkillDirs, initialMessages }));
926
+ const { App, React, render, createStdinFilter } = await import("./ui-RG76L7OR.js");
927
+ const stdinFilter = process.stdin.isTTY ? createStdinFilter(process.stdin) : process.stdin;
928
+ render(
929
+ React.createElement(App, { config: finalConfig, version: VERSION, autoMode, registry, trustedSkillDirs, initialMessages, stdinFilter }),
930
+ { stdin: stdinFilter }
931
+ );
928
932
  }
@@ -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, useStdin } from "ink";
50
+ import { Box as Box6, Text as Text6, useInput as useInput2, useStdout } from "ink";
51
51
 
52
52
  // src/skills/executor.ts
53
53
  import { exec } from "child_process";
@@ -853,47 +853,26 @@ ${blocks.join("\n\n")}`;
853
853
  ${contextSection}` : contextSection;
854
854
  }
855
855
 
856
- // src/ui/mouseInput.ts
857
- var SGR_MOUSE_RE = /^\x1b\[<(\d+);\d+;\d+[Mm]/;
858
- var SGR_FULL_RE = /^\x1b\[<(\d+);(\d+);(\d+)([Mm])/;
859
- function mouseEventLength(data) {
860
- const s = typeof data === "string" ? data : data.toString("binary");
861
- if (!s) return 0;
862
- const sgrMatch = SGR_MOUSE_RE.exec(s);
863
- if (sgrMatch) return sgrMatch[0].length;
864
- if (s.length >= 6 && s.charCodeAt(0) === 27 && s[1] === "[" && s[2] === "M") return 6;
865
- return 0;
866
- }
867
- function parseMouseScroll(data) {
868
- const s = typeof data === "string" ? data : data.toString("binary");
869
- if (!s) return null;
870
- const sgrMatch = SGR_MOUSE_RE.exec(s);
871
- if (sgrMatch) {
872
- const cb = parseInt(sgrMatch[1], 10);
873
- if (cb === 64) return { direction: "up" };
874
- if (cb === 65) return { direction: "down" };
875
- return null;
876
- }
877
- if (s.length >= 6 && s.charCodeAt(0) === 27 && s[1] === "[" && s[2] === "M") {
878
- const buttonByte = s.charCodeAt(3);
879
- if (buttonByte === 96) return { direction: "up" };
880
- if (buttonByte === 97) return { direction: "down" };
881
- return null;
882
- }
883
- return null;
884
- }
885
- function parseMouseSelectionEvent(data) {
886
- const s = typeof data === "string" ? data : data.toString("binary");
887
- const m = SGR_FULL_RE.exec(s);
888
- if (!m) return null;
889
- const cb = parseInt(m[1], 10);
890
- const col = parseInt(m[2], 10) - 1;
891
- const row = parseInt(m[3], 10) - 1;
892
- const isRelease = m[4] === "m";
893
- if (isRelease && cb === 0) return { type: "leftUp", col, row };
894
- if (!isRelease && cb === 0) return { type: "leftDown", col, row };
895
- if (!isRelease && cb === 32) return { type: "leftDrag", col, row };
896
- return null;
856
+ // src/ui/mouseCoords.ts
857
+ var STATUS_BAR_ROWS = 1;
858
+ function computeVisibleWindow(totalLines, scrollOffset, historyMaxHeight) {
859
+ const end = Math.max(0, Math.min(totalLines, totalLines - scrollOffset));
860
+ const initialStart = Math.max(0, end - historyMaxHeight);
861
+ const hasScrollIndicator = initialStart > 0 && historyMaxHeight > 1;
862
+ const start = hasScrollIndicator ? Math.max(0, end - (historyMaxHeight - 1)) : initialStart;
863
+ const visibleCount = (hasScrollIndicator ? 1 : 0) + (end - start);
864
+ return { start, end, visibleCount, hasScrollIndicator };
865
+ }
866
+ function mouseRowToLineIndex(opts) {
867
+ if (opts.visibleCount <= 0) return null;
868
+ const bottomRows = STATUS_BAR_ROWS + opts.skillAcRows + opts.fileAcRows + opts.selectedItemsRows + opts.inputRows;
869
+ const innerBoxHeight = opts.terminalRows - bottomRows;
870
+ const chTopRow = innerBoxHeight - opts.visibleCount;
871
+ const chBottomRow = innerBoxHeight - 1;
872
+ if (opts.mouseRow < chTopRow || opts.mouseRow > chBottomRow) return null;
873
+ const indicatorOffset = opts.hasScrollIndicator ? 1 : 0;
874
+ if (opts.mouseRow < chTopRow + indicatorOffset) return null;
875
+ return opts.mouseRow - chTopRow - indicatorOffset;
897
876
  }
898
877
 
899
878
  // src/ui/App.tsx
@@ -2446,9 +2425,8 @@ function formatMetaAlignOutput(result, model) {
2446
2425
  );
2447
2426
  return lines.join("\n");
2448
2427
  }
2449
- function App({ config, version, autoMode = false, registry, trustedSkillDirs = [], initialMessages = [], llmClient }) {
2428
+ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [], initialMessages = [], llmClient, stdinFilter }) {
2450
2429
  const { stdout } = useStdout();
2451
- const { stdin } = useStdin();
2452
2430
  const historyMaxHeight = Math.max(5, ((stdout == null ? void 0 : stdout.rows) ?? 24) - 4);
2453
2431
  const [messages, setMessages] = useState3(initialMessages);
2454
2432
  const [status, setStatus] = useState3("idle");
@@ -2483,6 +2461,12 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
2483
2461
  historyMaxHeightRef.current = historyMaxHeight;
2484
2462
  const selectionStateRef = useRef2(selectionState);
2485
2463
  selectionStateRef.current = selectionState;
2464
+ const inputRowsRef = useRef2(1);
2465
+ const skillAcRowsRef = useRef2(0);
2466
+ const fileAcRowsRef = useRef2(0);
2467
+ const selectedItemsRowsRef = useRef2(0);
2468
+ const terminalRowsRef = useRef2((stdout == null ? void 0 : stdout.rows) ?? 24);
2469
+ terminalRowsRef.current = (stdout == null ? void 0 : stdout.rows) ?? 24;
2486
2470
  const pendingConfirmRef = useRef2(null);
2487
2471
  const abortControllerRef = useRef2(null);
2488
2472
  const llmRef = useRef2(llmClient ?? createProvider(resolveActiveProfile(config)));
@@ -2546,60 +2530,56 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
2546
2530
  };
2547
2531
  }, []);
2548
2532
  useEffect3(() => {
2549
- if (!stdout || !stdin) return;
2533
+ if (!stdout) return;
2550
2534
  stdout.write("\x1B[?1002h\x1B[?1006h");
2551
- const origRead = stdin.read.bind(stdin);
2552
- stdin.read = function(size) {
2553
- const chunk = origRead(size);
2554
- if (chunk === null) return null;
2555
- const isStr = typeof chunk === "string";
2556
- let s = isStr ? chunk : chunk.toString("binary");
2557
- let mouseLen;
2558
- while ((mouseLen = mouseEventLength(s)) > 0) {
2559
- const mouseStr = s.slice(0, mouseLen);
2560
- const scroll = parseMouseScroll(mouseStr);
2561
- if (scroll) {
2562
- const step = Math.max(1, Math.floor(historyMaxHeightRef.current / 2));
2563
- if (scroll.direction === "up") {
2564
- setScrollOffset((prev) => Math.min(prev + step, Math.max(0, totalLinesRef.current - 1)));
2565
- } else {
2566
- setScrollOffset((prev) => Math.max(0, prev - step));
2567
- }
2568
- }
2569
- const sel = parseMouseSelectionEvent(mouseStr);
2570
- if (sel) {
2571
- const totalL = totalLinesRef.current;
2572
- const scrollOff = scrollOffsetRef.current;
2573
- const histH = historyMaxHeightRef.current;
2574
- const visibleCount = Math.min(Math.max(0, totalL - scrollOff), histH);
2575
- const contentStartRow = histH - visibleCount;
2576
- const lineIdx = sel.row - contentStartRow;
2577
- if (lineIdx >= 0 && lineIdx < visibleCount) {
2578
- const pt = { row: lineIdx, col: sel.col };
2579
- if (sel.type === "leftDown") setSelectionState(startSelection(selectionStateRef.current, pt));
2580
- else if (sel.type === "leftDrag") setSelectionState(updateSelection(selectionStateRef.current, pt));
2581
- else if (sel.type === "leftUp") setSelectionState(finishSelection(selectionStateRef.current, pt));
2582
- }
2535
+ return () => {
2536
+ stdout.write("\x1B[?1002l\x1B[?1006l");
2537
+ };
2538
+ }, [stdout]);
2539
+ useEffect3(() => {
2540
+ if (!stdinFilter) return;
2541
+ const onMouse = (e) => {
2542
+ if (e.kind === "scroll") {
2543
+ const step = Math.max(1, Math.floor(historyMaxHeightRef.current / 2));
2544
+ if (e.direction === "up") {
2545
+ setScrollOffset((prev) => Math.min(prev + step, Math.max(0, totalLinesRef.current - 1)));
2546
+ } else {
2547
+ setScrollOffset((prev) => Math.max(0, prev - step));
2583
2548
  }
2584
- s = s.slice(mouseLen);
2549
+ return;
2585
2550
  }
2586
- if (s.length === 0) return null;
2587
- return isStr ? s : Buffer.from(s, "binary");
2551
+ const window = computeVisibleWindow(
2552
+ totalLinesRef.current,
2553
+ scrollOffsetRef.current,
2554
+ historyMaxHeightRef.current
2555
+ );
2556
+ const lineIdx = mouseRowToLineIndex({
2557
+ mouseRow: e.row,
2558
+ terminalRows: terminalRowsRef.current,
2559
+ inputRows: inputRowsRef.current,
2560
+ skillAcRows: skillAcRowsRef.current,
2561
+ fileAcRows: fileAcRowsRef.current,
2562
+ selectedItemsRows: selectedItemsRowsRef.current,
2563
+ visibleCount: window.visibleCount,
2564
+ hasScrollIndicator: window.hasScrollIndicator
2565
+ });
2566
+ if (lineIdx === null) return;
2567
+ const pt = { row: lineIdx, col: e.col };
2568
+ if (e.type === "leftDown") setSelectionState(startSelection(selectionStateRef.current, pt));
2569
+ else if (e.type === "leftDrag") setSelectionState(updateSelection(selectionStateRef.current, pt));
2570
+ else if (e.type === "leftUp") setSelectionState(finishSelection(selectionStateRef.current, pt));
2588
2571
  };
2572
+ stdinFilter.on("mouse", onMouse);
2589
2573
  return () => {
2590
- stdin.read = origRead;
2591
- stdout.write("\x1B[?1002l\x1B[?1006l");
2574
+ stdinFilter.off("mouse", onMouse);
2592
2575
  };
2593
- }, [stdout, stdin]);
2576
+ }, [stdinFilter]);
2594
2577
  useEffect3(() => {
2595
2578
  if (selectionState.dragging || !selectionState.anchor || !selectionState.focus) return;
2596
2579
  const visible = messages.filter((m) => m.role !== "system");
2597
2580
  const allLines = visible.flatMap((msg) => messageToLines(msg, expandTools, (stdout == null ? void 0 : stdout.columns) ?? 0));
2598
- const totalL = allLines.length;
2599
- const end = Math.max(0, Math.min(totalL, totalL - scrollOffset));
2600
- const histH = historyMaxHeight;
2601
- const start = Math.max(0, end - histH);
2602
- const lineTexts = allLines.slice(start, end).map((l) => l.text);
2581
+ const window = computeVisibleWindow(allLines.length, scrollOffset, historyMaxHeight);
2582
+ const lineTexts = allLines.slice(window.start, window.end).map((l) => l.text);
2603
2583
  const text = extractSelectedText(lineTexts, selectionState);
2604
2584
  if (text && stdout) {
2605
2585
  const b64 = Buffer.from(text, "utf8").toString("base64");
@@ -3053,6 +3033,7 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
3053
3033
  } else {
3054
3034
  historyIndexRef.current = -1;
3055
3035
  }
3036
+ inputRowsRef.current = Math.max(1, text.split("\n").length);
3056
3037
  if (status !== "awaiting_confirm") {
3057
3038
  setAcState((prev) => handleInputChange(prev, text));
3058
3039
  setFileAcState((prev) => handleInputChange2(prev, text));
@@ -3060,6 +3041,10 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
3060
3041
  }, [status]);
3061
3042
  const skillSuggestions = registry ? computeSuggestions(registry.list(), acState) : [];
3062
3043
  const acOpen = isOpen(acState, skillSuggestions);
3044
+ const facOpen = isOpen2(fileAcState, fileSuggestions);
3045
+ skillAcRowsRef.current = acOpen ? skillSuggestions.length + 2 : 0;
3046
+ fileAcRowsRef.current = facOpen ? fileSuggestions.length + 2 : 0;
3047
+ selectedItemsRowsRef.current = selectedItems.length > 0 ? 1 : 0;
3063
3048
  return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", height: "100%", children: [
3064
3049
  /* @__PURE__ */ jsx6(Box6, { flexGrow: 1, flexDirection: "column", justifyContent: "flex-end", children: /* @__PURE__ */ jsx6(
3065
3050
  ConversationHistory,
@@ -3095,7 +3080,7 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
3095
3080
  {
3096
3081
  suggestions: fileSuggestions,
3097
3082
  selectedIndex: fileAcState.selectedIndex,
3098
- isOpen: isOpen2(fileAcState, fileSuggestions)
3083
+ isOpen: facOpen
3099
3084
  }
3100
3085
  ),
3101
3086
  selectedItems.length > 0 && /* @__PURE__ */ jsx6(Box6, { paddingLeft: 1, children: /* @__PURE__ */ jsxs6(Text6, { color: "cyan", dimColor: true, children: [
@@ -3114,8 +3099,140 @@ function App({ config, version, autoMode = false, registry, trustedSkillDirs = [
3114
3099
  )
3115
3100
  ] });
3116
3101
  }
3102
+
3103
+ // src/ui/stdinFilter.ts
3104
+ import { Transform } from "stream";
3105
+
3106
+ // src/ui/mouseInput.ts
3107
+ var SGR_MOUSE_RE = /^\x1b\[<(\d+);\d+;\d+[Mm]/;
3108
+ var SGR_FULL_RE = /^\x1b\[<(\d+);(\d+);(\d+)([Mm])/;
3109
+ function mouseEventLength(data) {
3110
+ const s = typeof data === "string" ? data : data.toString("binary");
3111
+ if (!s) return 0;
3112
+ const sgrMatch = SGR_MOUSE_RE.exec(s);
3113
+ if (sgrMatch) return sgrMatch[0].length;
3114
+ if (s.length >= 6 && s.charCodeAt(0) === 27 && s[1] === "[" && s[2] === "M") return 6;
3115
+ return 0;
3116
+ }
3117
+ function parseMouseScroll(data) {
3118
+ const s = typeof data === "string" ? data : data.toString("binary");
3119
+ if (!s) return null;
3120
+ const sgrMatch = SGR_MOUSE_RE.exec(s);
3121
+ if (sgrMatch) {
3122
+ const cb = parseInt(sgrMatch[1], 10);
3123
+ if (cb === 64) return { direction: "up" };
3124
+ if (cb === 65) return { direction: "down" };
3125
+ return null;
3126
+ }
3127
+ if (s.length >= 6 && s.charCodeAt(0) === 27 && s[1] === "[" && s[2] === "M") {
3128
+ const buttonByte = s.charCodeAt(3);
3129
+ if (buttonByte === 96) return { direction: "up" };
3130
+ if (buttonByte === 97) return { direction: "down" };
3131
+ return null;
3132
+ }
3133
+ return null;
3134
+ }
3135
+ function parseMouseSelectionEvent(data) {
3136
+ const s = typeof data === "string" ? data : data.toString("binary");
3137
+ const m = SGR_FULL_RE.exec(s);
3138
+ if (!m) return null;
3139
+ const cb = parseInt(m[1], 10);
3140
+ const col = parseInt(m[2], 10) - 1;
3141
+ const row = parseInt(m[3], 10) - 1;
3142
+ const isRelease = m[4] === "m";
3143
+ if (isRelease && cb === 0) return { type: "leftUp", col, row };
3144
+ if (!isRelease && cb === 0) return { type: "leftDown", col, row };
3145
+ if (!isRelease && cb === 32) return { type: "leftDrag", col, row };
3146
+ return null;
3147
+ }
3148
+
3149
+ // src/ui/stdinTokenizer.ts
3150
+ var MAX_MOUSE_SEQ = 32;
3151
+ function isMousePartial(s) {
3152
+ if (!s.startsWith("\x1B")) return false;
3153
+ if (s.length === 1) return false;
3154
+ if (s[1] !== "[") return false;
3155
+ if (s.length === 2) return false;
3156
+ if (s[2] === "<") return true;
3157
+ if (s[2] === "M" && s.length < 6) return true;
3158
+ return false;
3159
+ }
3160
+ function tokenizeStdin(input, pendingIn) {
3161
+ const data = pendingIn + input;
3162
+ let i = 0;
3163
+ let keyboardOut = "";
3164
+ const events = [];
3165
+ while (i < data.length) {
3166
+ const ch = data[i];
3167
+ if (ch !== "\x1B") {
3168
+ keyboardOut += ch;
3169
+ i++;
3170
+ continue;
3171
+ }
3172
+ const tail = data.slice(i);
3173
+ const mLen = mouseEventLength(tail);
3174
+ if (mLen > 0) {
3175
+ const seq = tail.slice(0, mLen);
3176
+ const scroll = parseMouseScroll(seq);
3177
+ if (scroll) {
3178
+ events.push({ kind: "scroll", direction: scroll.direction });
3179
+ } else {
3180
+ const sel = parseMouseSelectionEvent(seq);
3181
+ if (sel) events.push({ kind: "select", type: sel.type, col: sel.col, row: sel.row });
3182
+ }
3183
+ i += mLen;
3184
+ continue;
3185
+ }
3186
+ if (isMousePartial(tail) && tail.length < MAX_MOUSE_SEQ) {
3187
+ return { keyboard: keyboardOut, pending: tail, events };
3188
+ }
3189
+ keyboardOut += ch;
3190
+ i++;
3191
+ }
3192
+ return { keyboard: keyboardOut, pending: "", events };
3193
+ }
3194
+
3195
+ // src/ui/stdinFilter.ts
3196
+ var StdinFilterImpl = class extends Transform {
3197
+ isTTY;
3198
+ source;
3199
+ pending = "";
3200
+ constructor(source) {
3201
+ super();
3202
+ this.source = source;
3203
+ this.isTTY = source.isTTY ?? false;
3204
+ source.pipe(this);
3205
+ }
3206
+ setRawMode(mode) {
3207
+ var _a, _b;
3208
+ (_b = (_a = this.source).setRawMode) == null ? void 0 : _b.call(_a, mode);
3209
+ }
3210
+ ref() {
3211
+ var _a, _b;
3212
+ (_b = (_a = this.source).ref) == null ? void 0 : _b.call(_a);
3213
+ }
3214
+ unref() {
3215
+ var _a, _b;
3216
+ (_b = (_a = this.source).unref) == null ? void 0 : _b.call(_a);
3217
+ }
3218
+ _transform(chunk, _encoding, callback) {
3219
+ const s = typeof chunk === "string" ? chunk : chunk.toString("binary");
3220
+ const { keyboard, pending, events } = tokenizeStdin(s, this.pending);
3221
+ this.pending = pending;
3222
+ for (const ev of events) this.emit("mouse", ev);
3223
+ if (keyboard.length > 0) {
3224
+ callback(null, Buffer.from(keyboard, "binary"));
3225
+ } else {
3226
+ callback();
3227
+ }
3228
+ }
3229
+ };
3230
+ function createStdinFilter(source) {
3231
+ return new StdinFilterImpl(source);
3232
+ }
3117
3233
  export {
3118
3234
  App,
3119
3235
  default2 as React,
3236
+ createStdinFilter,
3120
3237
  render
3121
3238
  };
@@ -221,6 +221,15 @@ function generateAdminHtml(version) {
221
221
  font-size: 12px;
222
222
  overflow: hidden;
223
223
  margin: 4px 0;
224
+ /* #messages \u662F flex column \u5BB9\u5668\uFF0Cflex item \u9ED8\u8BA4 flex-shrink:1\u3002
225
+ * .tool-box \u6709 overflow:hidden \u4F1A\u8BA9 min-height \u9ED8\u8BA4\u5F52 0\uFF08CSS Flexbox \u89C4\u8303\uFF09\uFF0C
226
+ * \u7D2F\u79EF\u591A\u4E2A tool-box \u65F6\u6574\u5217\u88AB\u6324\u538B\uFF0Cbody \u88AB\u88C1\u6389\u5BFC\u81F4"\u6846\u9AD8\u5EA6\u53D8\u6210\u4E00\u6761\u7EBF"\u3002
227
+ * flex-shrink:0 \u5F3A\u5236\u4FDD\u7559\u81EA\u7136\u9AD8\u5EA6\uFF0C\u7531 #messages \u7684 overflow-y:auto \u6EDA\u52A8\u3002 */
228
+ flex-shrink: 0;
229
+ }
230
+ .thinking-block,
231
+ .msg {
232
+ flex-shrink: 0;
224
233
  }
225
234
  .tool-box-header {
226
235
  background: #21262d;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhongqian97-code/ecode",
3
- "version": "0.5.55",
3
+ "version": "0.5.57",
4
4
  "description": "A minimal Claude Code clone with REPL interface and bash tool calling",
5
5
  "type": "module",
6
6
  "author": "zhongqian97-code",