@epoch-agent/tui 3.1.2 → 4.0.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/README.md +16 -9
- package/dist/index.js +21 -17
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -4,7 +4,8 @@ Ink 7 + React 19 的终端界面。
|
|
|
4
4
|
|
|
5
5
|
- ✅ **做**:组件、布局、键位、Markdown 渲染、斜杠命令
|
|
6
6
|
- ❌ **不做**:**不许 import [core](../core)**(`check:layers` 会红)、不 spawn 子进程、
|
|
7
|
-
|
|
7
|
+
**不碰用户文件**(唯一的写盘是 `EPOCH_DEBUG` 打开的调试日志,`src/debug.ts`
|
|
8
|
+
往系统临时目录追加 —— 2026-11-03 把上一版那句笼统的「不碰文件系统」改准)。
|
|
8
9
|
- **依赖**:[protocol](../protocol) + [view](../view) + `chalk` / `lowlight` /
|
|
9
10
|
`string-width` 等纯渲染库。`ink` 和 `react` 是 **peer**
|
|
10
11
|
|
|
@@ -254,22 +255,28 @@ Ink 的 `log-update` **只能擦除它上一帧写过的行数**。一旦动态
|
|
|
254
255
|
|
|
255
256
|
## `@` 补全:文件和会话两组
|
|
256
257
|
|
|
257
|
-
打 `@` 弹补全面板,**分两组**(方案 53 §1.3
|
|
258
|
+
打 `@` 弹补全面板,**分两组**(方案 53 §1.3;2026-11-05 起**会话在上**):
|
|
258
259
|
|
|
259
260
|
```
|
|
260
|
-
┌
|
|
261
|
-
│ packages/core/src/agent/loop.ts
|
|
262
|
-
├ 会话 ────────────────────────────
|
|
261
|
+
┌ 会话 ────────────────────────────
|
|
263
262
|
│ 接上后台任务的输出 12/03 · 42 条 · 本工作区
|
|
263
|
+
├ 文件 ────────────────────────────
|
|
264
|
+
│ packages/core/src/agent/loop.ts
|
|
264
265
|
└──────────────────────────────────
|
|
265
266
|
```
|
|
266
267
|
|
|
268
|
+
- **会话组**:`@` 一打就列出来,**不需要先知道 `@:` 这个前缀**(2026-11-05 之前
|
|
269
|
+
只有 `@:` 才出会话,而那件事只写在文档里)。选中补进去的是 **sessionId**
|
|
270
|
+
(落成 `@:id`)而不是标题 —— 标题里几乎一定有空白,而提及的抽取规则遇到空白
|
|
271
|
+
就断 —— 提交时那段会话的 **当前面**(模型当时还看得见的那些)作为一个独立
|
|
272
|
+
部件发出去
|
|
267
273
|
- **文件组**:子序列模糊匹配(`@c/a/loop` 命中 `packages/core/src/agent/loop.ts`),
|
|
268
274
|
Tab / Enter 补全路径,提交时**文件内容随消息一起发出去**,省掉
|
|
269
|
-
「模型调 `file_read` →
|
|
270
|
-
-
|
|
271
|
-
|
|
272
|
-
|
|
275
|
+
「模型调 `file_read` → 再等一轮」
|
|
276
|
+
- **`@:` 是缩窄**:打了它就只要会话,文件组整个不列。这是「我知道自己要哪段
|
|
277
|
+
对话」时省掉下半屏的写法,不是另一种语法 —— 落进文本的仍然是 `@:id`
|
|
278
|
+
- 会话组排上面的判据是**影响范围**:引用一段会话改变的是整场对话的前提,
|
|
279
|
+
一个文件是局部素材。`↑↓` 的高亮下标跨两组连着走(会话最后一条 → 文件第一条)
|
|
273
280
|
|
|
274
281
|
> ⚠️ **会话组只按 sessionId / cwd / 标题匹配,永远不搜转录文本**(方案 53 §5.2)。
|
|
275
282
|
> 这是**安全边界不是性能考虑**:面板边打边显示,能搜正文的话打 `@:密码` 就会在
|
package/dist/index.js
CHANGED
|
@@ -3519,27 +3519,20 @@ function FilePalette({
|
|
|
3519
3519
|
t("tui.palette.listing")
|
|
3520
3520
|
] }) });
|
|
3521
3521
|
}
|
|
3522
|
-
const
|
|
3523
|
-
|
|
3522
|
+
const fileStart = visibleWindowStart(
|
|
3523
|
+
matched.length,
|
|
3524
|
+
Math.max(0, selectedIndex - sessions.length),
|
|
3525
|
+
MAX_VISIBLE4
|
|
3526
|
+
);
|
|
3527
|
+
const visible = matched.slice(fileStart, fileStart + MAX_VISIBLE4);
|
|
3524
3528
|
const grouped = matched.length > 0 && sessions.length > 0;
|
|
3525
3529
|
return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", paddingX: 1, children: [
|
|
3526
|
-
grouped && /* @__PURE__ */ jsxs20(Text21, { color: dim9, dimColor: true, children: [
|
|
3527
|
-
" ",
|
|
3528
|
-
t("tui.palette.files_head")
|
|
3529
|
-
] }),
|
|
3530
|
-
visible.map((m, i) => {
|
|
3531
|
-
const selected = start + i === selectedIndex;
|
|
3532
|
-
return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "row", children: [
|
|
3533
|
-
/* @__PURE__ */ jsx22(Text21, { color: selected ? accent6 : dim9, children: selected ? "\u276F " : " " }),
|
|
3534
|
-
/* @__PURE__ */ jsx22(Text21, { color: selected ? accent6 : "#F8F8F2", bold: selected, children: highlight(m.item, m.positions) })
|
|
3535
|
-
] }, m.item);
|
|
3536
|
-
}),
|
|
3537
3530
|
grouped && /* @__PURE__ */ jsxs20(Text21, { color: dim9, dimColor: true, children: [
|
|
3538
3531
|
" ",
|
|
3539
3532
|
t("tui.palette.sessions_head")
|
|
3540
3533
|
] }),
|
|
3541
3534
|
sessions.map((m, i) => {
|
|
3542
|
-
const selected =
|
|
3535
|
+
const selected = i === selectedIndex;
|
|
3543
3536
|
return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "row", children: [
|
|
3544
3537
|
/* @__PURE__ */ jsx22(Text21, { color: selected ? accent6 : dim9, children: selected ? "\u276F " : " " }),
|
|
3545
3538
|
/* @__PURE__ */ jsx22(Text21, { color: selected ? accent6 : "#F8F8F2", bold: selected, children: m.item.title }),
|
|
@@ -3549,6 +3542,17 @@ function FilePalette({
|
|
|
3549
3542
|
] })
|
|
3550
3543
|
] }, m.item.id);
|
|
3551
3544
|
}),
|
|
3545
|
+
grouped && /* @__PURE__ */ jsxs20(Text21, { color: dim9, dimColor: true, children: [
|
|
3546
|
+
" ",
|
|
3547
|
+
t("tui.palette.files_head")
|
|
3548
|
+
] }),
|
|
3549
|
+
visible.map((m, i) => {
|
|
3550
|
+
const selected = sessions.length + fileStart + i === selectedIndex;
|
|
3551
|
+
return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "row", children: [
|
|
3552
|
+
/* @__PURE__ */ jsx22(Text21, { color: selected ? accent6 : dim9, children: selected ? "\u276F " : " " }),
|
|
3553
|
+
/* @__PURE__ */ jsx22(Text21, { color: selected ? accent6 : "#F8F8F2", bold: selected, children: highlight(m.item, m.positions) })
|
|
3554
|
+
] }, m.item);
|
|
3555
|
+
}),
|
|
3552
3556
|
/* @__PURE__ */ jsx22(Box20, { flexDirection: "row", children: /* @__PURE__ */ jsxs20(Text21, { color: dim9, dimColor: true, children: [
|
|
3553
3557
|
" ",
|
|
3554
3558
|
matched.length > MAX_VISIBLE4 ? t("tui.palette.total", { n: matched.length }) : "",
|
|
@@ -3681,10 +3685,10 @@ var InputBox = React11.forwardRef(function InputBox2({
|
|
|
3681
3685
|
}
|
|
3682
3686
|
if (action !== "complete" && action !== "submit") return false;
|
|
3683
3687
|
const index = fileIndexRef.current < total ? fileIndexRef.current : 0;
|
|
3684
|
-
const picked = index <
|
|
3685
|
-
const candidate = sessions[index
|
|
3688
|
+
const picked = index < sessions.length ? (() => {
|
|
3689
|
+
const candidate = sessions[index]?.item;
|
|
3686
3690
|
return candidate ? sessionInsertion(candidate) : void 0;
|
|
3687
|
-
})();
|
|
3691
|
+
})() : matches[index - sessions.length]?.item;
|
|
3688
3692
|
if (picked === void 0) return false;
|
|
3689
3693
|
const next = applyMention(curLines[row] ?? "", at, col, picked);
|
|
3690
3694
|
const lines2 = [...curLines];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epoch-agent/tui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "epoch-agent Ink TUI 界面",
|
|
6
6
|
"repository": {
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"mnemonist": "0",
|
|
30
30
|
"string-width": "8",
|
|
31
31
|
"strip-ansi": "7",
|
|
32
|
-
"@epoch-agent/protocol": "
|
|
33
|
-
"@epoch-agent/view": "
|
|
32
|
+
"@epoch-agent/protocol": "4.0.0",
|
|
33
|
+
"@epoch-agent/view": "4.0.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^26.1.2",
|