@epoch-agent/tui 4.0.0 → 4.1.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/dist/index.d.ts +127 -160
- package/dist/index.js +12 -25
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -271,18 +271,16 @@ type TuiHistoryItem = TuiHistoryItemWithoutId & {
|
|
|
271
271
|
*
|
|
272
272
|
* 命令拿到的是一组回调(`SlashCommandContext`),自己不碰 React 状态,
|
|
273
273
|
* 也不 import 任何 core 的东西 —— tui 只依赖 protocol,凡是需要引擎能力的
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
* 这样命令实现是纯函数式的,可以直接对着一个假的 context 单测,
|
|
277
|
-
* 不用把整个 Ink 树跑起来。
|
|
274
|
+
* 都由宿主在 `renderApp({ host })` 时注入。于是命令是纯函数式的,对着一个假的
|
|
275
|
+
* context 就能单测,不用把整棵 Ink 树跑起来。
|
|
278
276
|
*/
|
|
279
277
|
|
|
280
278
|
/**
|
|
281
|
-
* `/goal`
|
|
279
|
+
* `/goal` 一次子命令的结果。
|
|
282
280
|
*
|
|
283
281
|
* `message` 是**宿主已经渲染好的一句话**,TUI 原样印出来 —— 判据见
|
|
284
282
|
* {@link HostActions.goals} 上那段 ⚠️。`ok` 只决定印成 info 还是 warning:
|
|
285
|
-
*
|
|
283
|
+
* 拒绝的理由在 `message` 里,因为「下一步该敲什么」逐条不同
|
|
286
284
|
* (`busy` 要先 `/goal clear`,`no-goal` 要先建一个)。
|
|
287
285
|
*/
|
|
288
286
|
interface GoalActionResult {
|
|
@@ -290,14 +288,13 @@ interface GoalActionResult {
|
|
|
290
288
|
message: string;
|
|
291
289
|
}
|
|
292
290
|
/**
|
|
293
|
-
*
|
|
291
|
+
* 这个进程记下的**一条弹窗答案**(审批缓存)。
|
|
294
292
|
*
|
|
295
|
-
* core 的 `CachedApproval`
|
|
296
|
-
*
|
|
297
|
-
* 等于让两边偷偷连在一起,而这一份的作用正是让漂移在编译期就红。
|
|
293
|
+
* core 的 `CachedApproval` 的**结构性镜像**:`tui` 不许 import core,直接绑
|
|
294
|
+
* core 的类型等于让两边偷偷连在一起,而抄这一份的作用正是让漂移在编译期就红。
|
|
298
295
|
*
|
|
299
296
|
* ⚠️ **`decision` 只有三档,没有 `allow-once`** —— 那一档压根不入缓存
|
|
300
|
-
*
|
|
297
|
+
* (真源是 core 的 `CachedDecision`)。写成联合而不是 `string`,是为了让
|
|
301
298
|
* 「三档各印一句人话」那张表在漏一档时当场红,而不是在屏幕上留一个空白格。
|
|
302
299
|
*/
|
|
303
300
|
interface CachedApprovalInfo {
|
|
@@ -317,15 +314,13 @@ interface CachedApprovalInfo {
|
|
|
317
314
|
createdAt: number;
|
|
318
315
|
}
|
|
319
316
|
/**
|
|
320
|
-
*
|
|
321
|
-
* 而且只有一种算错 ——
|
|
317
|
+
* 一次撤销为什么没成。**刻意不收成一个布尔**:两者在屏幕上是两句完全不同的话。
|
|
322
318
|
*
|
|
323
|
-
* - `no-permission-layer
|
|
319
|
+
* - `no-permission-layer`:权限层没起来,这一节压根不适用,下一步是 `/diagnostics`;
|
|
324
320
|
* - `unknown-id`:那条决定已经不在表里了。**不当错误报** —— 用户要的结果已经成立
|
|
325
321
|
* (同 web 那一侧的判据)。
|
|
326
322
|
*
|
|
327
|
-
*
|
|
328
|
-
* 宿主那一层不该替它决定措辞。
|
|
323
|
+
* 回的是**码而不是句子**:措辞在 `tui.permissions.*` 里由 TUI 挑,宿主不该替它决定。
|
|
329
324
|
*/
|
|
330
325
|
type ApprovalRevokeReason = 'no-permission-layer' | 'unknown-id';
|
|
331
326
|
/** 宿主(tui-entry)注入的引擎能力。全部可选:缺哪个对应命令就报「不可用」而不是崩 */
|
|
@@ -354,25 +349,22 @@ interface HostActions {
|
|
|
354
349
|
* provider 类型 / API key 提示,用于 /model。
|
|
355
350
|
*
|
|
356
351
|
* 回 `null` = provider 没起来。**每次调都要重新问宿主**,别缓存:
|
|
357
|
-
*
|
|
352
|
+
* `/model` 能换 provider,缓存下来就会显示启动时那家。
|
|
358
353
|
*/
|
|
359
354
|
getProviderInfo?: () => {
|
|
360
355
|
provider: string;
|
|
361
356
|
apiKeyHint: string;
|
|
362
357
|
} | null;
|
|
363
358
|
/**
|
|
364
|
-
*
|
|
359
|
+
* 换模型。`'reset'` = 回到配置里那个。
|
|
365
360
|
*
|
|
366
|
-
* 返回的是 core 的判定结果原样透传,**不在这里翻译成 boolean
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
* 判据全在 core,这里只负责把结果显示出来 —— 少一处会和引擎漂移的地方。
|
|
361
|
+
* 返回的是 core 的判定结果原样透传,**不在这里翻译成 boolean**:三种拒绝
|
|
362
|
+
* (没凭据 / 不认图片 / 窗口装不下)各有各的下一步,收成一个 false 之后
|
|
363
|
+
* UI 只能编一句笼统的话。
|
|
370
364
|
*
|
|
371
|
-
* `ctx`
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
* - `hasImages` —— 宿主有(会话历史里的 image part),TUI 只看得见
|
|
375
|
-
* 还没发出去的那几张
|
|
365
|
+
* `ctx` 是**两边各知道一半**的会话事实,两边都填、在宿主那侧合并:
|
|
366
|
+
* `usedTokens` 只有 TUI 有(`SessionStats.lastInputTokens`),`hasImages`
|
|
367
|
+
* 只有宿主有(会话历史里的 image part,TUI 只看得见还没发出去的那几张)。
|
|
376
368
|
*/
|
|
377
369
|
setModel?: (ref: ModelRef | 'reset', ctx?: SelectionContext) => SetSelectionResult;
|
|
378
370
|
/**
|
|
@@ -386,7 +378,7 @@ interface HostActions {
|
|
|
386
378
|
contextLength: number;
|
|
387
379
|
};
|
|
388
380
|
/**
|
|
389
|
-
*
|
|
381
|
+
* 取走引擎在这一轮里攒下的模型提示,取完即清。
|
|
390
382
|
*
|
|
391
383
|
* 目前只有一句:某个模型连续失败到了阈值,本会话不再自动降级重试它。
|
|
392
384
|
* 这件事必须**说出来**,否则用户看到的只是「回答忽然换了个味道」,
|
|
@@ -418,24 +410,23 @@ interface HostActions {
|
|
|
418
410
|
*/
|
|
419
411
|
supportsImages?: () => boolean;
|
|
420
412
|
/**
|
|
421
|
-
* 把一条自定义斜杠命令展开成一次 turn
|
|
413
|
+
* 把一条自定义斜杠命令展开成一次 turn 的输入。
|
|
422
414
|
*
|
|
423
|
-
* 插值(`$ARGUMENTS` / `$1
|
|
415
|
+
* 插值(`$ARGUMENTS` / `$1`)要用 tokenizer,而那住在 infra ——
|
|
424
416
|
* tui 只依赖 protocol,够不着。所以展开在宿主侧做,TUI 拿到的是结果。
|
|
425
417
|
*
|
|
426
|
-
* 认不出这个命令名时回 `undefined
|
|
427
|
-
* 除非表在这中间被换掉了)。
|
|
418
|
+
* 认不出这个命令名时回 `undefined`(命令表本来就是宿主给的,除非中途被换掉)。
|
|
428
419
|
*/
|
|
429
420
|
expandCommand?: (name: string, args: string) => ExpandedCommand | undefined;
|
|
430
421
|
/**
|
|
431
|
-
* 工作区文件清单,`@`
|
|
422
|
+
* 工作区文件清单,`@` 补全的候选。
|
|
432
423
|
*
|
|
433
424
|
* 由宿主提供:它要跑 `git ls-files` / 走目录,而 tui 只依赖 protocol。
|
|
434
425
|
* 异步是因为第一次可能要几十毫秒 —— 不该阻塞首帧。
|
|
435
426
|
*/
|
|
436
427
|
listWorkspaceFiles?: () => Promise<readonly string[]>;
|
|
437
428
|
/**
|
|
438
|
-
* 把 `@路径`
|
|
429
|
+
* 把 `@路径` 解析成带内容的附件部件。
|
|
439
430
|
*
|
|
440
431
|
* **必须由宿主做**,不只是因为 tui 读不了文件:这条路要过工作区边界判定和
|
|
441
432
|
* 权限判定,而两者都在引擎那一侧。TUI 自己 `readFileSync` 等于给 `@`
|
|
@@ -447,43 +438,39 @@ interface HostActions {
|
|
|
447
438
|
notices: string[];
|
|
448
439
|
};
|
|
449
440
|
/**
|
|
450
|
-
* `@:`
|
|
441
|
+
* `@:` 补全面板里的会话候选。
|
|
451
442
|
*
|
|
452
443
|
* ## ⚠️ 这个形状里**没有转录文本,而且不许加**
|
|
453
444
|
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
* 演示)。
|
|
445
|
+
* 面板只按 id / cwd / 标题匹配、永远不搜转录文本,**这是安全边界不是性能考虑**:
|
|
446
|
+
* 面板边打边显示,搜正文的话打 `@:密码` 就会在屏幕上列出所有提到过密码的会话
|
|
447
|
+
* —— 而这块屏幕可能正被别人看着(结对、录屏、演示)。
|
|
458
448
|
*
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
* (首条消息的前几十字)同理不许出现在这里。
|
|
449
|
+
* 因为转录文本一个字都不会到达 TUI,这条边界是**结构性**的:TUI 里再怎么改
|
|
450
|
+
* 过滤也搜不出正文。`sessions.preview` 那一列同理不许出现在这里。
|
|
462
451
|
*
|
|
463
|
-
* 异步 + 带 query
|
|
464
|
-
*
|
|
452
|
+
* 异步 + 带 query:可读性判定在引擎侧,过滤本身在宿主的 SQL 里做 ——
|
|
453
|
+
* TUI 拿到的已经是「这次能看的这几条」。
|
|
465
454
|
*/
|
|
466
455
|
listSessionCandidates?: (query: string, limit: number) => Promise<readonly SessionCandidateView[]>;
|
|
467
456
|
/**
|
|
468
|
-
*
|
|
457
|
+
* 当前的后台任务表。
|
|
469
458
|
*
|
|
470
459
|
* 同步返回:它只是读一张内存里的表,而状态栏每两秒要问一次 —— 异步的话
|
|
471
460
|
* 每次都要过一遍微任务队列,还得处理「上一次还没回来」的竞态。
|
|
472
461
|
*/
|
|
473
462
|
listBackgroundTasks?: () => readonly BackgroundTaskInfo[];
|
|
474
463
|
/**
|
|
475
|
-
*
|
|
476
|
-
*
|
|
464
|
+
* 用户自配的状态栏那一段。没配时**宿主不注入这一项**,状态栏据此决定画不画
|
|
465
|
+
* —— 而不是画一段空的、留个洞。
|
|
477
466
|
*
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
* 状态栏是装饰,不能因为一条命令卡住就让整个 UI 等;也不该由 TUI 来管
|
|
482
|
-
* 「谁去关那个定时器」。
|
|
467
|
+
* 同步返回、且**不保证是最新的**(宿主给上一次跑完的值,顺便判断要不要在后台
|
|
468
|
+
* 再跑一次)。理由写在 [cli/src/statusline.ts](../../../cli/src/statusline.ts)
|
|
469
|
+
* 的文件头:状态栏是装饰,不能因为一条命令卡住就让整个 UI 等。
|
|
483
470
|
*/
|
|
484
471
|
readStatusLine?: () => string | null;
|
|
485
472
|
/**
|
|
486
|
-
* 跑一条**用户手打**的命令(`!ls -la
|
|
473
|
+
* 跑一条**用户手打**的命令(`!ls -la`)。
|
|
487
474
|
*
|
|
488
475
|
* `approve` 由 TUI 提供:宿主判定要确认时回调它,TUI 弹出和模型那条路
|
|
489
476
|
* **完全相同**的确认框。判定本身在引擎侧 —— `!` 不是免检通道。
|
|
@@ -493,28 +480,28 @@ interface HostActions {
|
|
|
493
480
|
ok: boolean;
|
|
494
481
|
blocked?: boolean;
|
|
495
482
|
}>;
|
|
496
|
-
/**
|
|
483
|
+
/** 写一条记忆(`#记一下`)。`target` 决定用户级还是项目级 */
|
|
497
484
|
writeMemory?: (content: string, target: 'user' | 'memory', approve: (request: ApprovalRequest) => Promise<ApprovalOutcome>) => Promise<{
|
|
498
485
|
output: string;
|
|
499
486
|
ok: boolean;
|
|
500
487
|
blocked?: boolean;
|
|
501
488
|
}>;
|
|
502
489
|
/**
|
|
503
|
-
* 把 `!`
|
|
490
|
+
* 把 `!` 跑出来的输出记进**模型的**上下文。
|
|
504
491
|
*
|
|
505
492
|
* TUI 自己的历史不是模型的上下文 —— 不接这一条的话,用户看得见输出而模型
|
|
506
493
|
* 看不见,而「你看一下这个命令的输出」正是 `!` 存在的意义。
|
|
507
494
|
*/
|
|
508
495
|
noteToSession?: (text: string) => void;
|
|
509
496
|
/**
|
|
510
|
-
*
|
|
497
|
+
* 当前上下文预算的构成。
|
|
511
498
|
*
|
|
512
499
|
* **每次调都要重新问**:历史每轮都在长。缓存下来 `/context` 会一直显示
|
|
513
500
|
* 第一次看的那个数。
|
|
514
501
|
*/
|
|
515
502
|
getContextBreakdown?: () => ContextBreakdown | null;
|
|
516
503
|
/**
|
|
517
|
-
*
|
|
504
|
+
* 已加载的技能。
|
|
518
505
|
*
|
|
519
506
|
* `scope` 要露出来:用户看见一条不认识的技能,第一个问题是「这哪来的」——
|
|
520
507
|
* 同 `/help` 把内置命令和自定义命令分两段列的理由。
|
|
@@ -524,17 +511,16 @@ interface HostActions {
|
|
|
524
511
|
description: string;
|
|
525
512
|
category: string;
|
|
526
513
|
/**
|
|
527
|
-
*
|
|
528
|
-
*
|
|
514
|
+
* 后两种来源的技能名一律带前缀:`plugin` 是 `<插件名>:<名字>`,`host` 是
|
|
515
|
+
* 嵌入宿主 ship 的目录。
|
|
529
516
|
*
|
|
530
|
-
* ⚠️ 这个联合是**抄**的(tui 不许 import core
|
|
517
|
+
* ⚠️ 这个联合是**抄**的(tui 不许 import core),靠 `cli/src/tui-host.ts`
|
|
531
518
|
* 那一行装配去撞真源 —— 真源加一格而这里不加,那一行当场编译不过。
|
|
532
|
-
* 方案 44 就是这么被逮到的。
|
|
533
519
|
*/
|
|
534
520
|
scope: 'user' | 'project' | 'plugin' | 'host';
|
|
535
521
|
}>;
|
|
536
522
|
/**
|
|
537
|
-
* 可派给子 agent
|
|
523
|
+
* 可派给子 agent 的角色表。
|
|
538
524
|
*
|
|
539
525
|
* `tools` 是**声明值**,实际生效的还要和当时的工具表取交集 ——
|
|
540
526
|
* 显示时要说明这一点,否则用户会以为角色能用一个已经被卸载的工具。
|
|
@@ -558,7 +544,7 @@ interface HostActions {
|
|
|
558
544
|
error?: string;
|
|
559
545
|
}>;
|
|
560
546
|
/**
|
|
561
|
-
*
|
|
547
|
+
* 已装插件一览。
|
|
562
548
|
*
|
|
563
549
|
* **停用的和加载失败的都要在里面** —— 这条命令一半的价值就在那儿:
|
|
564
550
|
* 一个因为 `epochVersion` 不满足而没加载的插件,在别处的唯一痕迹是启动时
|
|
@@ -611,12 +597,11 @@ interface HostActions {
|
|
|
611
597
|
message?: string;
|
|
612
598
|
}>;
|
|
613
599
|
/**
|
|
614
|
-
*
|
|
600
|
+
* 工作区**有没有**未提交的改动(回退面板那句 `git stash` 提示)。
|
|
615
601
|
*
|
|
616
|
-
* 和 `gitDiff` 分开而不是拿它的 `text`
|
|
617
|
-
*
|
|
618
|
-
*
|
|
619
|
-
* 新文件也算**,而 `git diff HEAD` 看不见它们。
|
|
602
|
+
* 和 `gitDiff` 分开而不是拿它的 `text` 判空:这里要的只是一个布尔和一个计数,
|
|
603
|
+
* 而 `git diff HEAD` 在大仓库上会把几 MB 补丁读进内存。口径也不同:这里走
|
|
604
|
+
* `git status --porcelain`,**未跟踪的新文件也算**,而 `git diff HEAD` 看不见。
|
|
620
605
|
*
|
|
621
606
|
* 不是 git 仓库、git 不在 PATH 时回 `ok: false` —— 那时**什么都不提示**,
|
|
622
607
|
* 而不是提示「工作区是干净的」:我们只是不知道。
|
|
@@ -627,34 +612,32 @@ interface HostActions {
|
|
|
627
612
|
count: number;
|
|
628
613
|
}>;
|
|
629
614
|
/**
|
|
630
|
-
*
|
|
615
|
+
* 检查点与回退。`/rewind` 和 Esc Esc 共用这一份能力。
|
|
631
616
|
*
|
|
632
617
|
* 缺它时那条命令不注册、那个键位不武装 —— 判据见 {@link CheckpointActions}。
|
|
633
618
|
*/
|
|
634
619
|
checkpoints?: CheckpointActions;
|
|
635
620
|
/**
|
|
636
|
-
* 当前生效的键位一览(`/keybindings
|
|
621
|
+
* 当前生效的键位一览(`/keybindings`)。
|
|
637
622
|
*
|
|
638
623
|
* ## ⚠️ 回的是**渲染好的一整块文本**,不是结构
|
|
639
624
|
*
|
|
640
|
-
*
|
|
641
|
-
*
|
|
642
|
-
* 都是文案** —— 分组标题、来源标注、被拒绝的理由各一句。
|
|
625
|
+
* 判据同 {@link HostActions.goals}:`tui` 够不着 `t()`,写进来的中文永远是中文,
|
|
626
|
+
* 而这条命令**通篇都是文案**(分组标题、来源标注、被拒绝的理由各一句)。
|
|
643
627
|
*
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
* `KeybindingReport
|
|
647
|
-
* 结果,从它反推来源只能靠猜。
|
|
628
|
+
* 另一半理由是**事实来源全在宿主那边**:哪条是用户改的、哪条被保留键拒了、
|
|
629
|
+
* 哪条撞了谁,只有加载期(`core/src/config/keybindings.ts` 的
|
|
630
|
+
* `KeybindingReport`)知道;TUI 手上那张表是消解完冲突之后的结果,反推只能靠猜。
|
|
648
631
|
*
|
|
649
632
|
* 宿主没接就**压根不注册**这条命令(同 `/rewind` 的判据)—— 一条只会回
|
|
650
633
|
* 「不可用」的键位清单没有存在的意义。
|
|
651
634
|
*/
|
|
652
635
|
keybindings?: () => string;
|
|
653
636
|
/**
|
|
654
|
-
* 让这台终端能发 Shift+Enter(`/terminal-setup
|
|
637
|
+
* 让这台终端能发 Shift+Enter(`/terminal-setup`)。
|
|
655
638
|
*
|
|
656
639
|
* 和 {@link HostActions.goals} 同一类:回的是**宿主渲染好的一整块文本**,
|
|
657
|
-
* `ok: false`
|
|
640
|
+
* `ok: false` 只是「这次没写成」(认不出的终端、备份失败……),理由在
|
|
658
641
|
* `message` 里。TUI 只负责把 `args` 原样带过去、把结果印出来。
|
|
659
642
|
*
|
|
660
643
|
* 宿主没接就**压根不注册**这条命令(同 `/keybindings` 的判据)。
|
|
@@ -675,7 +658,7 @@ interface HostActions {
|
|
|
675
658
|
messages: number;
|
|
676
659
|
}>;
|
|
677
660
|
/**
|
|
678
|
-
* 手动压一次上下文(`/compact
|
|
661
|
+
* 手动压一次上下文(`/compact`)。
|
|
679
662
|
*
|
|
680
663
|
* `instruction` 是「这次帮我留住什么」。**压缩是一次真实的 LLM 请求**,
|
|
681
664
|
* 所以这条命令会花钱 —— 结果里带上压缩前后的条数,让用户看得见换来了什么。
|
|
@@ -716,7 +699,7 @@ interface HostActions {
|
|
|
716
699
|
snippet: string;
|
|
717
700
|
}>;
|
|
718
701
|
/**
|
|
719
|
-
* 当前生效的权限规则 + 遮蔽情况(`/permissions
|
|
702
|
+
* 当前生效的权限规则 + 遮蔽情况(`/permissions`)。
|
|
720
703
|
*
|
|
721
704
|
* `layer` 是**来源层**,这条命令存在的一半意义就在它身上 —— 用户查权限问题时
|
|
722
705
|
* 的第一个问题永远是「这条 deny 是谁加的、我该去改哪个文件」。
|
|
@@ -732,44 +715,41 @@ interface HostActions {
|
|
|
732
715
|
kind: string;
|
|
733
716
|
message: string;
|
|
734
717
|
}>;
|
|
735
|
-
/**
|
|
718
|
+
/** 企业托管策略。这台机器上没有托管文件时 `present: false` */
|
|
736
719
|
managed: ManagedInfo;
|
|
737
720
|
/**
|
|
738
|
-
*
|
|
739
|
-
*
|
|
740
|
-
*
|
|
721
|
+
* 这个进程记下的弹窗答案(审批缓存)。**和 `rules` 不是一回事**:那一张是
|
|
722
|
+
* 配置文件里的策略(能提交进 git),这一张是本机这一程的记忆;判定时**规则的
|
|
723
|
+
* deny 排在缓存前面**,所以屏幕上这两者必须分得开。
|
|
741
724
|
*
|
|
742
|
-
* ⚠️ **必填,不是可选。**
|
|
743
|
-
*
|
|
744
|
-
*
|
|
745
|
-
* 而不是等用户敲 `/permissions` 时才发现少了一节。
|
|
725
|
+
* ⚠️ **必填,不是可选。** 它和 {@link HostActions.revokeApproval} 是一条纵线
|
|
726
|
+
* 的两头,而「列得出来、撤不掉」和「宿主忘了接」在屏幕上长得一样(都是那一节
|
|
727
|
+
* 不出现)—— 必填让漏接的宿主在**编译期**就红。
|
|
746
728
|
*
|
|
747
729
|
* 权限层没起来时是**空表**而不是抛错:没有权限层就等于什么都没记过。
|
|
748
730
|
*/
|
|
749
731
|
approvals: readonly CachedApprovalInfo[];
|
|
750
732
|
};
|
|
751
733
|
/**
|
|
752
|
-
*
|
|
734
|
+
* 撤销**一条**缓存的审批决定。
|
|
753
735
|
*
|
|
754
|
-
* ⚠️
|
|
755
|
-
* (core 的 `checkRulesAndCache`),这一发一个字都不动它们 ——
|
|
756
|
-
* 撤销缓存的 deny ≠ 撤销规则的 deny,界面上必须说得清这一点,
|
|
736
|
+
* ⚠️ **它撤的只是缓存那一层**:两张规则表的 `deny` 排在缓存**前面**
|
|
737
|
+
* (core 的 `checkRulesAndCache`),这一发一个字都不动它们 —— 界面上必须说清,
|
|
757
738
|
* 不然用户点了「撤销」发现还是被拦,比压根没有这个入口更坏。
|
|
758
739
|
*
|
|
759
740
|
* ⚠️ **撤销是把那道题还给用户,不是替他答成「允许」**:撤完之后同一个操作会
|
|
760
741
|
* 重新弹窗。撤成放行的话,一次误点的代价会从「这个工具问不到」变成
|
|
761
|
-
*
|
|
742
|
+
* 「这个目标以后都不问了」。
|
|
762
743
|
*
|
|
763
|
-
* ⚠️ **没有「全清」那一档**(core
|
|
764
|
-
*
|
|
765
|
-
* 于是「收回一个误点」的代价变成「后面每一次都重新问一遍」。
|
|
744
|
+
* ⚠️ **没有「全清」那一档**(core 的 `ApprovalCache.clear()` 一直都在,刻意
|
|
745
|
+
* 不转出来):那一下会连用户攒了一整程的「总是允许」一起清掉。
|
|
766
746
|
*/
|
|
767
747
|
revokeApproval?: (id: string) => {
|
|
768
748
|
ok: boolean;
|
|
769
749
|
reason?: ApprovalRevokeReason;
|
|
770
750
|
};
|
|
771
751
|
/**
|
|
772
|
-
* Plan
|
|
752
|
+
* Plan 模式 —— 用户主动那一半。
|
|
773
753
|
*
|
|
774
754
|
* **出口处那次审批不在这里**:它走的是既有的 `approval-request` 链
|
|
775
755
|
* (`exit_plan_mode` 工具发起),TUI 接的还是 `run.requestApproval` 那一个队列。
|
|
@@ -787,33 +767,28 @@ interface HostActions {
|
|
|
787
767
|
/** 主动退出,返回恢复到的级别;本来就不在模式里时回 null */
|
|
788
768
|
leave: () => string | null;
|
|
789
769
|
/**
|
|
790
|
-
* 当前生效的那份**已批准**计划;没有就是 null
|
|
770
|
+
* 当前生效的那份**已批准**计划;没有就是 null。
|
|
791
771
|
*
|
|
792
|
-
* `/plan`
|
|
793
|
-
*
|
|
794
|
-
*
|
|
772
|
+
* `/plan` 拿它回答「我刚才批的那份计划是什么」。`--resume` 之后尤其要紧:
|
|
773
|
+
* 屏幕上是空的(卡片是上一个进程画的),而模型手上那份还在 —— 没有这个出口,
|
|
774
|
+
* 用户无从知道自己接回来的会话正照着哪份纲跑。
|
|
795
775
|
*
|
|
796
776
|
* 可选:老宿主没实现时 `/plan` 少说一段,不该因此报「不可用」。
|
|
797
777
|
*/
|
|
798
778
|
approvedPlan?: () => string | null;
|
|
799
779
|
};
|
|
800
780
|
/**
|
|
801
|
-
*
|
|
802
|
-
*
|
|
803
|
-
* ## ⚠️ 为什么这一组回的是**渲染好的字符串**,而别的能力回结构
|
|
781
|
+
* 长任务的目标 —— `/goal` 命令族的全部数据源。
|
|
804
782
|
*
|
|
805
|
-
*
|
|
806
|
-
* 回一句已经拼好的话。判据是 **i18n**:
|
|
783
|
+
* ## ⚠️ 这一组回的是**渲染好的字符串**,不是结构
|
|
807
784
|
*
|
|
808
|
-
*
|
|
809
|
-
* `@epoch-agent/infra` 的 `t()
|
|
810
|
-
*
|
|
811
|
-
*
|
|
785
|
+
* 判据是 **i18n**:`tui` 只依赖 protocol(见 `packages/tui/README.md` 的依赖表),
|
|
786
|
+
* 够不着 `@epoch-agent/infra` 的 `t()`,写进来的中文永远只有中文,而这一片
|
|
787
|
+
* 全是新增的用户可见文案,硬编码等于给 i18n 那条棘轮
|
|
788
|
+
* (`scripts/i18n-scan.mjs`,只许降不许升)再添一笔债。
|
|
812
789
|
*
|
|
813
790
|
* 所以措辞归宿主:cli 那侧用 `t()` 从 `locales/{zh,en}.yaml` 的 `goal.*` 取,
|
|
814
|
-
* TUI
|
|
815
|
-
* `listPlugins` / `ManagedInfo` 早就是「宿主算好的展示形状」(见本文件
|
|
816
|
-
* import 那几行上的注释)。
|
|
791
|
+
* TUI 只负责**解析子命令**和**把结果印出来**。
|
|
817
792
|
*
|
|
818
793
|
* 整组可选:宿主没接(会话库起不来)时 `/goal` 压根不注册。
|
|
819
794
|
*/
|
|
@@ -844,18 +819,18 @@ interface HostActions {
|
|
|
844
819
|
/**
|
|
845
820
|
* 卡住时那一行开机提示;没卡住(或没有目标)时 null。
|
|
846
821
|
*
|
|
847
|
-
* 宿主(`tui-entry`)把它接在 `startupNotices`
|
|
848
|
-
*
|
|
849
|
-
*
|
|
822
|
+
* 宿主(`tui-entry`)把它接在 `startupNotices` 后面:一个无人值守跑到一半
|
|
823
|
+
* 卡住的任务,人回来打开 TUI 时**第一屏就该看见**卡在哪,而不是要先想起来
|
|
824
|
+
* 敲一条命令。
|
|
850
825
|
*/
|
|
851
826
|
blockedNotice: () => string | null;
|
|
852
827
|
};
|
|
853
828
|
/**
|
|
854
|
-
* 把一次「永久允许」渲染成可提交进 git
|
|
829
|
+
* 把一次「永久允许」渲染成可提交进 git 的规则字符串。
|
|
855
830
|
*
|
|
856
|
-
*
|
|
857
|
-
*
|
|
858
|
-
*
|
|
831
|
+
* 审批缓存是**本机的**、换台机器就没了;规则是能提交、全队生效的 —— 这一条
|
|
832
|
+
* 就是两者之间那座桥。反推不出有意义的规则时回 `null`(宿主据此不显示提示,
|
|
833
|
+
* 而不是显示一条死规则)。
|
|
859
834
|
*/
|
|
860
835
|
suggestRule?: (request: ApprovalRequest) => {
|
|
861
836
|
rule: string;
|
|
@@ -866,7 +841,7 @@ interface HostActions {
|
|
|
866
841
|
interface PickerBase {
|
|
867
842
|
title: string;
|
|
868
843
|
/**
|
|
869
|
-
*
|
|
844
|
+
* 副标题。结构化提问拿它放「第 2/4 问 · 缓存后端」——
|
|
870
845
|
* 四个问题逐个走完时,用户必须看得出「还有几个」,否则第二个弹窗出现的那一刻
|
|
871
846
|
* 他会以为自己刚才点错了。
|
|
872
847
|
*/
|
|
@@ -874,7 +849,7 @@ interface PickerBase {
|
|
|
874
849
|
options: Array<SelectOption<string>>;
|
|
875
850
|
initialIndex?: number;
|
|
876
851
|
/**
|
|
877
|
-
*
|
|
852
|
+
* 在列表末尾自动追加一个「其他…」,选中后就地敲字。
|
|
878
853
|
*
|
|
879
854
|
* **由宿主提供而不是让调用方自己加一个选项**:那样每个调用方都得记得加,
|
|
880
855
|
* 忘了的表现是用户答不上来只能按 Esc —— 而 Esc 的语义是「跳过」,
|
|
@@ -890,7 +865,7 @@ interface SinglePickerRequest extends PickerBase {
|
|
|
890
865
|
/** 选中的 label;用户走自由输入时是他打的原文 */
|
|
891
866
|
onPick: (value: string) => void;
|
|
892
867
|
}
|
|
893
|
-
/**
|
|
868
|
+
/** 多选。答案是数组,一项都没勾时是空数组 —— 那也是个合法答案 */
|
|
894
869
|
interface MultiPickerRequest extends PickerBase {
|
|
895
870
|
multiSelect: true;
|
|
896
871
|
onPick: (values: string[]) => void;
|
|
@@ -899,12 +874,11 @@ interface MultiPickerRequest extends PickerBase {
|
|
|
899
874
|
* 选择框请求。
|
|
900
875
|
*
|
|
901
876
|
* 做成判别联合而不是「`onPick: (v: string | string[]) => void` 一把抓」:
|
|
902
|
-
*
|
|
903
|
-
*
|
|
904
|
-
* 这件事在**声明处**就定死,回调的入参类型跟着自动收窄。
|
|
877
|
+
* 后者会让每个既有调用方都得在回调里先 `Array.isArray` 一次,而它们压根不可能
|
|
878
|
+
* 收到数组。判别符让「这个框是几选」在**声明处**就定死,回调入参跟着自动收窄。
|
|
905
879
|
*/
|
|
906
880
|
type PickerRequest = SinglePickerRequest | MultiPickerRequest;
|
|
907
|
-
/**
|
|
881
|
+
/** 提交一条消息时的额外约束:自定义命令可以收窄这一轮的工具表 */
|
|
908
882
|
interface SubmitOptions {
|
|
909
883
|
/**
|
|
910
884
|
* 这一轮对模型可见的工具白名单。不给 = 不收窄。
|
|
@@ -914,7 +888,7 @@ interface SubmitOptions {
|
|
|
914
888
|
*/
|
|
915
889
|
allowedTools?: readonly string[];
|
|
916
890
|
/**
|
|
917
|
-
* 只在这一轮生效的模型(命令 frontmatter 的 `model
|
|
891
|
+
* 只在这一轮生效的模型(命令 frontmatter 的 `model:`)。
|
|
918
892
|
*
|
|
919
893
|
* 和 `allowedTools` 同一个形状、同一条理由:解析(含 `utility` 关键字)在
|
|
920
894
|
* 引擎侧做完了,TUI 只负责把它原样带到 `onRun`,还原也在那一侧无条件发生。
|
|
@@ -939,15 +913,15 @@ interface SlashCommandContext {
|
|
|
939
913
|
/** 弹选择框 */
|
|
940
914
|
pick: (req: PickerRequest) => void;
|
|
941
915
|
/**
|
|
942
|
-
*
|
|
916
|
+
* 打开回退面板。
|
|
943
917
|
*
|
|
944
918
|
* **没有走 `pick`**:那个是「从一组固定选项里选一个」,而回退是一台状态机 ——
|
|
945
919
|
* 选检查点 → 逐个勾要覆盖的冲突文件 → 选范围 → 对话那半再确认一次不可撤销。
|
|
946
920
|
* 用一串嵌套的 `pick` 拼出来,等于把「默认一个冲突都不覆盖」这条安全判定
|
|
947
921
|
* 摊在四层回调里。
|
|
948
922
|
*
|
|
949
|
-
*
|
|
950
|
-
*
|
|
923
|
+
* 面板的开关状态住在 `App`,命令只按门铃;Esc Esc 按的是同一个门铃 ——
|
|
924
|
+
* **一个面板,两个入口**。
|
|
951
925
|
*/
|
|
952
926
|
openRewind: () => void;
|
|
953
927
|
/**
|
|
@@ -959,11 +933,11 @@ interface SlashCommandContext {
|
|
|
959
933
|
*/
|
|
960
934
|
approve: (request: ApprovalRequest) => Promise<ApprovalOutcome>;
|
|
961
935
|
/**
|
|
962
|
-
*
|
|
936
|
+
* 把一段文本当成用户消息发出去(自定义命令走这条)。
|
|
963
937
|
*
|
|
964
938
|
* 内置命令一个都不用它 —— 它们是「在 TUI 里做一件事」,而自定义命令是
|
|
965
|
-
*
|
|
966
|
-
*
|
|
939
|
+
* 「替用户敲一段话」。两者共用同一个注册表但走不同的出口:命令**不是**新的
|
|
940
|
+
* agent 类型,就是一次预置的 turn。
|
|
967
941
|
*/
|
|
968
942
|
submitPrompt: (text: string, opts?: SubmitOptions) => void;
|
|
969
943
|
/** 宿主能力 */
|
|
@@ -998,7 +972,7 @@ interface SlashCommand {
|
|
|
998
972
|
/** 别名,同样不带斜杠 */
|
|
999
973
|
aliases?: string[];
|
|
1000
974
|
/**
|
|
1001
|
-
* 给人看的称呼(自定义命令 frontmatter 的 `displayName
|
|
975
|
+
* 给人看的称呼(自定义命令 frontmatter 的 `displayName`)。
|
|
1002
976
|
* 内置命令不写。
|
|
1003
977
|
*
|
|
1004
978
|
* ⚠️ 终端里**左列照旧印 `/name`** —— 那是用户真要敲的东西,换成称呼等于让他
|
|
@@ -1023,8 +997,8 @@ interface SlashCommand {
|
|
|
1023
997
|
* 判据只看**宿主注入了哪些能力**,因为那是唯一「这台机器上到底有没有这个东西」
|
|
1024
998
|
* 的真源。缺能力时报一句「不可用」和压根不出现,是两件不同的事:
|
|
1025
999
|
* 前者适合「本该有、这次没起来」(`/tools` 在 provider 挂掉时仍该在),
|
|
1026
|
-
*
|
|
1027
|
-
*
|
|
1000
|
+
* 后者适合「这个版本就没有这个功能」—— 注册了它就会出现在 `/help` 和补全
|
|
1001
|
+
* 面板里,那是在承诺一个不存在的功能。
|
|
1028
1002
|
*/
|
|
1029
1003
|
available?: (host: HostActions) => boolean;
|
|
1030
1004
|
/**
|
|
@@ -1074,9 +1048,9 @@ interface ConfirmationRequest {
|
|
|
1074
1048
|
* 跑一轮的入口。
|
|
1075
1049
|
*
|
|
1076
1050
|
* 入参是 `EpochUserContent`(`string | 部件数组`)而不是 `string`:Ctrl+V 粘进来的
|
|
1077
|
-
*
|
|
1078
|
-
*
|
|
1079
|
-
*
|
|
1051
|
+
* 图片必须跟着这一次提交走到引擎。历史项、队列、debug 日志全都只要文本,它们统一走
|
|
1052
|
+
* `contentToDisplayText()` 取投影(**宿主那一份**,走 catalog;protocol 的
|
|
1053
|
+
* `contentToText()` 是给模型的)。
|
|
1080
1054
|
*/
|
|
1081
1055
|
type RunFn = (message: EpochUserContent, opts: {
|
|
1082
1056
|
signal: AbortSignal;
|
|
@@ -1090,26 +1064,20 @@ interface AppProps {
|
|
|
1090
1064
|
onExit?: () => void;
|
|
1091
1065
|
/** 宿主注入的引擎能力,供斜杠命令使用 */
|
|
1092
1066
|
host?: HostActions;
|
|
1093
|
-
/**
|
|
1067
|
+
/** 宿主加载好的自定义斜杠命令。不给就只有内置那几条 */
|
|
1094
1068
|
customCommands?: readonly CustomCommandDef[];
|
|
1095
1069
|
/**
|
|
1096
|
-
*
|
|
1097
|
-
*
|
|
1098
|
-
* 由 `cli/src/tui-entry.ts` 调),tui 只消费。
|
|
1070
|
+
* 生效的键位表。**必须是已经校验过的那一份** —— 读盘 / zod / 保留键 / 冲突检测都在宿主
|
|
1071
|
+
* 那一侧(`core/src/config/keybindings.ts`,由 `cli/src/tui-entry.ts` 调),tui 只消费。
|
|
1099
1072
|
*
|
|
1100
|
-
*
|
|
1101
|
-
* 行为与今天逐键一致。
|
|
1073
|
+
* 不给就是默认表,也就是「用户没配过」和「宿主不支持配」走同一条路。
|
|
1102
1074
|
*/
|
|
1103
1075
|
keybindings?: KeybindingTable;
|
|
1104
1076
|
/**
|
|
1105
|
-
* Vim
|
|
1106
|
-
* 之前逐字节一致(#13)。
|
|
1077
|
+
* Vim 模式。**默认关** —— 关着时输入框的行为与引入之前逐字节一致。
|
|
1107
1078
|
*
|
|
1108
|
-
*
|
|
1109
|
-
*
|
|
1110
|
-
* `core/src/config/keybindings.ts`、把结果递进来的是 `cli/src/tui-entry.ts` ——
|
|
1111
|
-
* PR-3 这一轮两个文件都归别的分支,所以只留了这个入口。接上那半只有两处一行的
|
|
1112
|
-
* 改动,交接写在 `docs/verify/VERIFY_RECORD-31-keybindings.md` 的 PR-3 那一章。
|
|
1079
|
+
* 开关的家在 `~/.epoch/keybindings.json`(键位是个人偏好,只有用户级),读它的是
|
|
1080
|
+
* `core/src/config/keybindings.ts`,递进来的是 `cli/src/tui-entry.ts`。
|
|
1113
1081
|
*/
|
|
1114
1082
|
vimMode?: boolean;
|
|
1115
1083
|
}
|
|
@@ -1375,12 +1343,11 @@ declare function Banner({ width }: BannerProps): React__default.ReactElement;
|
|
|
1375
1343
|
* 注册表。顺序即 /help 和补全面板的展示顺序。
|
|
1376
1344
|
*
|
|
1377
1345
|
* 按用途分了段:会话 → 引擎内省 → 仓库 → 回退 → 开关。后面几个分组住在各自的
|
|
1378
|
-
*
|
|
1346
|
+
* 文件里 —— 这个文件再加几条就会破行数硬线。
|
|
1379
1347
|
*
|
|
1380
|
-
* ⚠️
|
|
1381
|
-
* `useSlashCommands`
|
|
1382
|
-
*
|
|
1383
|
-
* 不代表自定义命令就可以占用它的名字,否则升个版就撞名了。
|
|
1348
|
+
* ⚠️ 这份表是**全集**,不是「这台机器上能用的」:按宿主能力过滤发生在
|
|
1349
|
+
* `useSlashCommands` 合并那一步(`availableCommands()`)。而保留名检查要的正是全集
|
|
1350
|
+
* —— 一条命令这次没注册,不代表自定义命令就可以占用它的名字,否则升个版就撞名了。
|
|
1384
1351
|
*/
|
|
1385
1352
|
declare const BUILTIN_COMMANDS: readonly SlashCommand[];
|
|
1386
1353
|
|
|
@@ -1413,7 +1380,7 @@ declare function findCommand(commands: readonly SlashCommand[], name: string): S
|
|
|
1413
1380
|
* `/` 单独一个字符时列出全部命令(用户刚敲下斜杠,正等着看有什么可用)。
|
|
1414
1381
|
* 已经带了参数(有空格)时不再补全 —— 那时候用户在填参数,不该再弹列表。
|
|
1415
1382
|
*
|
|
1416
|
-
* 称呼(`displayName
|
|
1383
|
+
* 称呼(`displayName`)也按前缀认:插件命令的名字是
|
|
1417
1384
|
* `aione:bailing_daily_report` 这种,用户记得住的是「百灵投放日报」,打 `/百灵`
|
|
1418
1385
|
* 该找得到它。⚠️ 同样是**前缀**不是子串,判据和名字那一支一致 —— 子串的话
|
|
1419
1386
|
* `/c` 会捞出所有称呼里带个 c 的命令。web 那一份(`composer/commands.tsx`)逐字镜像。
|
package/dist/index.js
CHANGED
|
@@ -6733,17 +6733,13 @@ export {
|
|
|
6733
6733
|
/**
|
|
6734
6734
|
* InputBox — 自绘多行输入框,code-point 级光标,带斜杠命令补全。
|
|
6735
6735
|
*
|
|
6736
|
-
* 光标是自绘的反色块,不是终端硬件光标:
|
|
6737
|
-
*
|
|
6738
|
-
*
|
|
6739
|
-
*
|
|
6740
|
-
* 这里用 Ink 原生的 <Text inverse>(而不是 chalk.inverse 拼 ANSI 字符串):
|
|
6741
|
-
* chalk 有自己一套颜色能力探测,在非交互/被重定向的环境里会直接不输出转义序列,
|
|
6742
|
-
* 光标就又没了;走 Ink 的着色管线则和其余 UI 保持一致。
|
|
6736
|
+
* 光标是自绘的反色块,不是终端硬件光标:ink 7 的 <Text> 没有 terminalCursorPosition
|
|
6737
|
+
* 这类 prop,写上去会被静默忽略。而用 <Text inverse> 而不是 chalk.inverse 拼 ANSI
|
|
6738
|
+
* 字符串,是因为 chalk 自己有颜色能力探测,非交互 / 被重定向的环境里不输出转义序列。
|
|
6743
6739
|
*
|
|
6744
6740
|
* 补全面板的键盘状态**必须**长在这里,不能提到 App:面板可见时 ↑↓ 要用来选命令,
|
|
6745
|
-
*
|
|
6746
|
-
*
|
|
6741
|
+
* 不可见时才是翻输入历史。只有握着 text buffer 的一方判得对,拆两处就会出现
|
|
6742
|
+
* 「两个 useInput 各消费一次同一个按键」。
|
|
6747
6743
|
*
|
|
6748
6744
|
* @license Apache-2.0 (adapted from google-gemini/gemini-cli)
|
|
6749
6745
|
* Copyright 2025 Google LLC
|
|
@@ -6780,29 +6776,20 @@ export {
|
|
|
6780
6776
|
/**
|
|
6781
6777
|
* App — Ink TUI 根组件,状态来自 Context。
|
|
6782
6778
|
*
|
|
6783
|
-
*
|
|
6784
|
-
*
|
|
6785
|
-
* 屏幕,擦除范围就对不上,屏幕上会残留重复行。所以:
|
|
6779
|
+
* 布局的关键约束(花屏的根因):Ink 的 log-update 只能擦除它上一帧写过的行数,一旦动态帧
|
|
6780
|
+
* 比终端还高、内容滚出屏幕,擦除范围就对不上,屏幕上会残留重复行。所以:
|
|
6786
6781
|
* - Banner 和已完成历史必须放进 <Static>(只打印一次、向上滚走、不参与重绘);
|
|
6787
6782
|
* - 只有 pending 区留在动态帧里,且必须按 availableHeight 限高。
|
|
6788
6783
|
* 对齐 Gemini CLI 的 MainContent / DefaultAppLayout。
|
|
6789
6784
|
*
|
|
6790
6785
|
* 这个文件只做**装配和键位**:一轮对话怎么跑在 useAgentRun,斜杠命令怎么执行在
|
|
6791
|
-
* useSlashCommands
|
|
6792
|
-
*
|
|
6793
|
-
* ## ⚠️ 这个文件大 —— **往这儿加东西之前先问一句能不能摘成 hook**
|
|
6786
|
+
* useSlashCommands —— 两件事挤回一个 handleSubmit 的话,改一处必然碰另一处。
|
|
6794
6787
|
*
|
|
6795
|
-
*
|
|
6796
|
-
* `hooks/use-rewind.ts`(形状同 `use-slash-commands`),净增收到 52 行;
|
|
6797
|
-
* 方案 31 PR-2 加序列时净增 **14 行**(状态机整台在
|
|
6798
|
-
* `keybindings/use-key-sequences.ts`,而 Esc Esc 那段特例反而删掉了)。
|
|
6799
|
-
* 真要把它拆小得动键位和布局那两块,那是独立的一件事,别顺手夹在别的 PR 里做。
|
|
6800
|
-
* 这条判据原来只写在方案 27 的 md 里,随那份 md 删除搬来。
|
|
6788
|
+
* ## ⚠️ 往这儿加东西之前先问一句能不能摘成 hook
|
|
6801
6789
|
*
|
|
6802
|
-
*
|
|
6803
|
-
*
|
|
6804
|
-
*
|
|
6805
|
-
* 上面那条「先摘 hook」是这个文件自己的纪律,不是在还谁的债。
|
|
6790
|
+
* 「先摘 hook」是这个文件自己的纪律,不是在还债:摘出去净增的行数比塞进来少得多(回退那台
|
|
6791
|
+
* 状态机在 `hooks/use-rewind.ts`,序列整台在 `keybindings/use-key-sequences.ts`)。真要把它
|
|
6792
|
+
* 拆小得动键位和布局那两块,那是独立的一件事,别顺手夹在别的 PR 里做。
|
|
6806
6793
|
*
|
|
6807
6794
|
* @license Apache-2.0 (adapted from google-gemini/gemini-cli DefaultAppLayout)
|
|
6808
6795
|
* Copyright 2025 Google LLC
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epoch-agent/tui",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.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": "4.
|
|
33
|
-
"@epoch-agent/view": "4.
|
|
32
|
+
"@epoch-agent/protocol": "4.1.0",
|
|
33
|
+
"@epoch-agent/view": "4.1.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^26.1.2",
|