@epoch-agent/core 0.7.1 → 0.9.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 +28 -0
- package/dist/index.d.ts +1044 -53
- package/dist/index.js +1394 -391
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1369,6 +1369,16 @@ interface MemorySearchResult {
|
|
|
1369
1369
|
score: number;
|
|
1370
1370
|
similarity?: number;
|
|
1371
1371
|
}
|
|
1372
|
+
/** {@link MemoryManager.read} 的结果。**认不出的 id 单独一栏**,不是静默丢掉 */
|
|
1373
|
+
interface MemoryReadResult {
|
|
1374
|
+
found: Array<{
|
|
1375
|
+
id: string;
|
|
1376
|
+
target: MemoryTarget;
|
|
1377
|
+
content: string;
|
|
1378
|
+
}>;
|
|
1379
|
+
/** 索引里没有这个 id。多半是模型自己编了一个,或者引用了上个会话的索引 */
|
|
1380
|
+
missing: string[];
|
|
1381
|
+
}
|
|
1372
1382
|
/** 数据库中的记忆条目 */
|
|
1373
1383
|
interface MemoryEntry {
|
|
1374
1384
|
id: string;
|
|
@@ -1382,8 +1392,15 @@ interface MemoryEntry {
|
|
|
1382
1392
|
lastAccessedAt: Date;
|
|
1383
1393
|
}
|
|
1384
1394
|
interface MemoryConfig {
|
|
1395
|
+
/** `MEMORY.md` 能存多少字符。**存储**配额,不进 prompt,抬它几乎不花钱 */
|
|
1385
1396
|
memoryCharLimit: number;
|
|
1397
|
+
/** `USER.md` 能存多少字符。同上 */
|
|
1386
1398
|
userCharLimit: number;
|
|
1399
|
+
/**
|
|
1400
|
+
* 索引块进 system prompt 的字符上限 —— 三个数里**唯一按轮计费**的那个。
|
|
1401
|
+
* 对照表在 protocol 的 `EpochConfig.memory` 上。
|
|
1402
|
+
*/
|
|
1403
|
+
indexCharLimit: number;
|
|
1387
1404
|
}
|
|
1388
1405
|
interface MemoryManager$1 {
|
|
1389
1406
|
/** 会话启动:加载文件 → 去重 → 注入扫描 → 冻结快照 → 返回 system prompt 块 */
|
|
@@ -1397,9 +1414,15 @@ interface MemoryManager$1 {
|
|
|
1397
1414
|
search(query: string, limit?: number): Promise<MemorySearchResult[]>;
|
|
1398
1415
|
keywordSearch(query: string, limit?: number): Promise<MemorySearchResult[]>;
|
|
1399
1416
|
semanticSearch(query: string, limit?: number): Promise<MemorySearchResult[]>;
|
|
1417
|
+
/** 按索引里的短 id 取全文。索引块印的 id 就是这里认的那一套 */
|
|
1418
|
+
read(ids: readonly string[]): Promise<MemoryReadResult>;
|
|
1400
1419
|
add(target: MemoryTarget, content: string): Promise<MemoryWriteResult>;
|
|
1401
1420
|
replace(target: MemoryTarget, oldText: string, content: string): Promise<MemoryWriteResult>;
|
|
1402
|
-
|
|
1421
|
+
/**
|
|
1422
|
+
* 删一条。`ref` 是**全文**或索引里那个**短 id**。
|
|
1423
|
+
* 返回删没删掉 —— 报「已删除」而其实一条没动,会让模型以为腾出了地方。
|
|
1424
|
+
*/
|
|
1425
|
+
remove(target: MemoryTarget, ref: string): Promise<boolean>;
|
|
1403
1426
|
getBudget(): {
|
|
1404
1427
|
memory: BudgetInfo;
|
|
1405
1428
|
user: BudgetInfo;
|
|
@@ -1412,10 +1435,29 @@ interface MemoryManager$1 {
|
|
|
1412
1435
|
/**
|
|
1413
1436
|
* memory 工具 — 让 LLM 显式读写长期记忆。
|
|
1414
1437
|
*
|
|
1415
|
-
* MemoryManager.sync() 不自动写入(见 manager.ts
|
|
1438
|
+
* MemoryManager.sync() 不自动写入(见 manager.ts),记忆的产生完全依赖
|
|
1416
1439
|
* 本工具被调用。没有它,MemoryManager 只能读不能写。
|
|
1417
1440
|
*
|
|
1418
|
-
*
|
|
1441
|
+
* ---
|
|
1442
|
+
*
|
|
1443
|
+
* # ⚠️ 改这个文件里的 `description` / `parameters` = 34 段 eval 录像作废
|
|
1444
|
+
*
|
|
1445
|
+
* 工具定义(名字 / 描述 / 参数)进 eval 的新鲜度指纹
|
|
1446
|
+
* (`evals/harness/fingerprint.ts`,那个文件头说得很清楚为什么必须进)。
|
|
1447
|
+
* 于是这里改一个字,`pnpm eval` 全红,而 pre-push 会跑它。
|
|
1448
|
+
*
|
|
1449
|
+
* **2026-09-10 那一轮是明知代价改的**:`read` 这个 action 是记忆结构改造
|
|
1450
|
+
* (正文不再全量进 prompt,见 `memory/manager.ts` 文件头)**必需**的另一半 ——
|
|
1451
|
+
* 没有它,索引块里那些 id 一个也取不回全文,那不是「少一个便利」,
|
|
1452
|
+
* 是把记忆变成只有摘要。
|
|
1453
|
+
*
|
|
1454
|
+
* 收账走 `evals/README.md` 里那条**「只重贴指纹」的窄例外**(它成立的前提是
|
|
1455
|
+
* 「改的是工具表增量、system prompt 没动」,而这一轮 system prompt 那一侧
|
|
1456
|
+
* 恰好没动 —— 空库的索引块是空串,判据在 `manager.ts` 文件头最后一节)。
|
|
1457
|
+
* 例外带**举证义务**:拿真 key 对最可能被干扰的那几条 eval 录活体,
|
|
1458
|
+
* 数 `memory` 在 `toolCalls` 里出现几次,必须是 0。
|
|
1459
|
+
*
|
|
1460
|
+
* ⚠️ 下次再想在这儿加一句话之前先问:**非说在工具描述里不可吗**。
|
|
1419
1461
|
*/
|
|
1420
1462
|
|
|
1421
1463
|
declare function createMemoryTool(memory: MemoryManager$1): EpochTool;
|
|
@@ -2856,17 +2898,27 @@ interface SkillSystem$1 {
|
|
|
2856
2898
|
*
|
|
2857
2899
|
* ## 三、输出**不自己截**
|
|
2858
2900
|
*
|
|
2859
|
-
* 一份 `SKILL.md`
|
|
2860
|
-
*
|
|
2861
|
-
*
|
|
2862
|
-
*
|
|
2863
|
-
*
|
|
2864
|
-
* >
|
|
2865
|
-
* >
|
|
2866
|
-
* >
|
|
2867
|
-
* >
|
|
2868
|
-
* >
|
|
2869
|
-
* >
|
|
2901
|
+
* 一份 `SKILL.md` 轻易超过工具输出预算(`agent/output-budget.ts` 的
|
|
2902
|
+
* `MAX_TOOL_OUTPUT`),而截一半的操作说明比没有更坏 —— 模型会照着前半截把事做完。
|
|
2903
|
+
* 所以这里既不分页也不摘要,正文原样交出去,豁免由工具定义上的
|
|
2904
|
+
* `governsOwnOutput: true` 负责(判据在 `EpochTool.governsOwnOutput` 上)。
|
|
2905
|
+
*
|
|
2906
|
+
* > ⚠️ **2026-09-08:这一段上一次「核过」核错了,而正文被静默截到 2000 字符
|
|
2907
|
+
* > 一直在发生。** 原话是「✅ 2026-08-27 核过:那一格已经是
|
|
2908
|
+
* > `new Set([SKILL_VIEW_TOOL])` 了」——**名字确实对上了,但那个集合没有人用**。
|
|
2909
|
+
* > 它唯一的读者是 `message-utils.ts` 的 `truncateToolOutput()`,而那个函数
|
|
2910
|
+
* > **全仓没有一处生产调用方**:活路径是 `ToolExecutor` 自己那一刀
|
|
2911
|
+
* > (`agent/tool-executor.ts`),它当时不认任何豁免。
|
|
2912
|
+
* > 钉着那个集合的用例直接调那个死函数,所以**它一直是绿的**。
|
|
2913
|
+
* >
|
|
2914
|
+
* > 这一轮的处置是把豁免搬到**执行那一处**能看见的地方(工具定义上),
|
|
2915
|
+
* > 并把那份第二实现(`truncateToolOutput` / `PROTECTED_TOOLS` /
|
|
2916
|
+
* > `TOOL_OUTPUT_MAX_CHARS`)整个删掉 —— 留着它就是留着「下一次又有人把修复
|
|
2917
|
+
* > 接到死函数上」的入口。
|
|
2918
|
+
* >
|
|
2919
|
+
* > **那笔账的形状比上一次记的更值钱**:上一次记的是「一个豁免名单和一个工具名
|
|
2920
|
+
* > 分两处写,走散了不会红」;真正的教训是**核一个豁免要核到它的读者**,
|
|
2921
|
+
* > 光核「名字对不对得上」是核了一半 —— 而对不上和没人用,症状完全一样。
|
|
2870
2922
|
*
|
|
2871
2923
|
* ## 四、`openWorldHint: false` —— 正文**不包** `<tool_output untrusted="true">`
|
|
2872
2924
|
*
|
|
@@ -2914,10 +2966,14 @@ interface SkillSystem$1 {
|
|
|
2914
2966
|
*/
|
|
2915
2967
|
|
|
2916
2968
|
/**
|
|
2917
|
-
* 工具名。**这是同构位置的真源** ——
|
|
2969
|
+
* 工具名。**这是同构位置的真源** —— 另外两处认它:
|
|
2918
2970
|
* `permission/operation-type.ts` 的 `INTERNAL_TOOLS`、`docs/TOOLS.md` 顶上那张表
|
|
2919
|
-
* (这两处由根 `__tests__/tool-registration.test.ts`
|
|
2920
|
-
*
|
|
2971
|
+
* (这两处由根 `__tests__/tool-registration.test.ts` 守着)。
|
|
2972
|
+
*
|
|
2973
|
+
* ⚠️ **2026-09-08 少了一处**:原来还列着 `agent/message-utils.ts` 的
|
|
2974
|
+
* `PROTECTED_TOOLS`(截断豁免名单)。那个名单整个删了,豁免改成下面工具定义上的
|
|
2975
|
+
* `governsOwnOutput: true` —— **同一个对象上的一个字段,不再是异地的一份名字**,
|
|
2976
|
+
* 所以这类「两处走散」从此在这一格上不可能发生。判据全文在文件头第三节。
|
|
2921
2977
|
*
|
|
2922
2978
|
* ⚠️ **下面 `name:` 那一格写的是字面量,不是这个常量,别「顺手」统一** ——
|
|
2923
2979
|
* `.husky/commit-msg` 那道模型门禁认的是 `name: '<snake_case>',` **这一行本身**
|
|
@@ -3140,6 +3196,8 @@ declare function createToolSearchTool(deps: ToolSearchDeps): EpochTool;
|
|
|
3140
3196
|
/**
|
|
3141
3197
|
* Tracker 类型定义 — 会话级 TODO 管理。
|
|
3142
3198
|
*/
|
|
3199
|
+
/** TODO 状态的值域 */
|
|
3200
|
+
type TodoStatus = 'pending' | 'in_progress' | 'completed' | 'cancelled';
|
|
3143
3201
|
/** TODO 项 */
|
|
3144
3202
|
interface TodoItem {
|
|
3145
3203
|
/** 6 位 hex 短 ID */
|
|
@@ -3147,7 +3205,7 @@ interface TodoItem {
|
|
|
3147
3205
|
/** 任务描述 */
|
|
3148
3206
|
content: string;
|
|
3149
3207
|
/** 任务状态 */
|
|
3150
|
-
status:
|
|
3208
|
+
status: TodoStatus;
|
|
3151
3209
|
/**
|
|
3152
3210
|
* 放弃这件事的理由。**只有 `cancelled` 那一档会有**,而且**可以没有**。
|
|
3153
3211
|
*
|
|
@@ -3201,6 +3259,14 @@ declare class TrackerDB {
|
|
|
3201
3259
|
constructor(dbPath: string);
|
|
3202
3260
|
/** 按会话 ID 获取所有 TODO */
|
|
3203
3261
|
listBySession(sessionId: string): TodoItem[];
|
|
3262
|
+
/**
|
|
3263
|
+
* 这个会话还有多少没做完({@link isOpenTodo} 那一档)。
|
|
3264
|
+
*
|
|
3265
|
+
* ⚠️ 为什么在 SQL 里数、不 `listBySession()` 再 filter:整个列表可能上千条,
|
|
3266
|
+
* 而这道闸门在**每一轮收工**都会问一次 —— 多拉一个数组比多跑一个 `COUNT(*)`
|
|
3267
|
+
* 贵一个数量级,而且这个数只进一句提示语,用不上任何一行正文。
|
|
3268
|
+
*/
|
|
3269
|
+
countOpen(sessionId: string): number;
|
|
3204
3270
|
/** 全量替换会话的 TODO 列表(事务:DELETE + INSERT 批量) */
|
|
3205
3271
|
replaceAll(sessionId: string, todos: TodoItem[]): void;
|
|
3206
3272
|
/** 释放连接(引用计数归零才真正关闭) */
|
|
@@ -4430,7 +4496,8 @@ declare function loadPlugins(opts: PluginLoadOptions): PluginArtifacts;
|
|
|
4430
4496
|
*
|
|
4431
4497
|
* 插件名会**变成命名空间前缀**(`/my-toolkit:review`、角色 `my-toolkit:reviewer`),
|
|
4432
4498
|
* 所以它必须同时是合法的命令名片段、合法的角色名、以及合法的目录名。
|
|
4433
|
-
*
|
|
4499
|
+
* {@link PLUGIN_NAME_PATTERN}:`[a-z0-9]` 开头,中间允许连字符和下划线
|
|
4500
|
+
* (下划线 2026-09-08 加的,判据在那个常量上)。
|
|
4434
4501
|
* 特别地**不允许 `:`** —— 允许了就能构造出 `a:b` 这种名字,装完之后
|
|
4435
4502
|
* `/a:b:c` 到底是哪个插件的哪条命令要靠猜。
|
|
4436
4503
|
*
|
|
@@ -4443,11 +4510,46 @@ declare const PLUGIN_MANIFEST_FILE = "epoch-plugin.json";
|
|
|
4443
4510
|
/**
|
|
4444
4511
|
* 插件名的合法形状。理由见文件头 —— 它同时是命令前缀、角色前缀和目录名。
|
|
4445
4512
|
*
|
|
4446
|
-
*
|
|
4447
|
-
*
|
|
4513
|
+
* ## ⚠️ 2026-09-08 加宽了:多认一个下划线
|
|
4514
|
+
*
|
|
4515
|
+
* 原来是 `^[a-z0-9][a-z0-9-]*$`,注释写着「和 `AGENT_ROLE_NAME_PATTERN` 逐字相同
|
|
4516
|
+
* 不是巧合:角色名是三者里最严的那个」。**那句话现在不成立了,而加宽是有外因的**:
|
|
4517
|
+
* 嵌入宿主那一侧的插件标识(盘古的 `plugin_key`)允许下划线,而**那个标识必须和
|
|
4518
|
+
* 这个名字是同一个字符串** —— 市场目录里的条目名、包里 `epoch-plugin.json` 的
|
|
4519
|
+
* `name`、宿主用来判「这一条装了没有」的键,三者是同一个东西。
|
|
4520
|
+
* 不加宽的话,一个叫 `my_shop_helper` 的插件在这套体系里**根本装不进来**。
|
|
4521
|
+
*
|
|
4522
|
+
* ## 逐条核过下游三处,`_` 全是安全的(不是「应该没事」)
|
|
4523
|
+
*
|
|
4524
|
+
* | 拼出来的东西 | 谁在判 | `_` 合法吗 |
|
|
4525
|
+
* | ----------------------- | ---------------------------------------------- | ---------- |
|
|
4526
|
+
* | 命令 `/my_plugin:review`| **没人判形状** —— 名字取自文件名,按空白切分 | ✅ |
|
|
4527
|
+
* | 角色 `my_plugin:review` | 复合名带 `:`,本来就过不了那张正则,**不重判** | ✅ |
|
|
4528
|
+
* | 工具 `mcp__my_plugin__x`| provider 那条 `^[a-zA-Z0-9_-]{1,128}$` | ✅(含 `_`)|
|
|
4529
|
+
* | 目录 `plugins/my_plugin`| 文件系统 | ✅ |
|
|
4530
|
+
*
|
|
4531
|
+
* 第三行原来是 `plugin-mcp-servers.ts` 里「前半截白拿」那条判据的依据(它引的是
|
|
4532
|
+
* 「两张正则逐字相同」)—— 那个文件头已经跟着改了:白拿的理由现在是
|
|
4533
|
+
* **provider 的正则本身含 `_`**,而不是「和角色名同宽」。
|
|
4534
|
+
*
|
|
4535
|
+
* ⚠️ **开头那一位没动**(照旧 `[a-z0-9]`):加宽只加中间那一段,这样任何一个
|
|
4536
|
+
* 今天合法的名字明天照样合法。⚠️ **`.` 和路径分隔符仍然不许**(判据见文件头:
|
|
4537
|
+
* 这个名字会被直接 `join(pluginsDir, name)`),**`:` 也仍然不许**。
|
|
4448
4538
|
*/
|
|
4449
4539
|
declare const PLUGIN_NAME_PATTERN: RegExp;
|
|
4450
4540
|
declare function isValidPluginName(name: string): boolean;
|
|
4541
|
+
/**
|
|
4542
|
+
* 「谁写的」。
|
|
4543
|
+
*
|
|
4544
|
+
* ⚠️ **导出它,因为市场目录的条目上也有一格 author**(`marketplace.ts` 的
|
|
4545
|
+
* `EntrySchema`)。两处各写一份 zod 的话,它们分家的那天没有任何东西会红 ——
|
|
4546
|
+
* 而分家的表现是一份在清单里合法的 author 在市场目录里被 `parseLenient` 静默丢掉。
|
|
4547
|
+
*/
|
|
4548
|
+
declare const PluginAuthorSchema: z.ZodObject<{
|
|
4549
|
+
name: z.ZodString;
|
|
4550
|
+
email: z.ZodOptional<z.ZodString>;
|
|
4551
|
+
url: z.ZodOptional<z.ZodString>;
|
|
4552
|
+
}, z.core.$strip>;
|
|
4451
4553
|
declare const ManifestSchema: z.ZodObject<{
|
|
4452
4554
|
name: z.ZodString;
|
|
4453
4555
|
version: z.ZodString;
|
|
@@ -4461,6 +4563,7 @@ declare const ManifestSchema: z.ZodObject<{
|
|
|
4461
4563
|
homepage: z.ZodOptional<z.ZodString>;
|
|
4462
4564
|
keywords: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
4463
4565
|
}, z.core.$strip>;
|
|
4566
|
+
type PluginAuthor = z.infer<typeof PluginAuthorSchema>;
|
|
4464
4567
|
type PluginManifest = z.infer<typeof ManifestSchema>;
|
|
4465
4568
|
interface ManifestReadOutcome {
|
|
4466
4569
|
/** 校验通过的清单;缺席表示这个目录不是一个可用的插件 */
|
|
@@ -4533,6 +4636,214 @@ declare function checkEpochVersion(range: string | undefined, current: string):
|
|
|
4533
4636
|
*/
|
|
4534
4637
|
declare function currentEpochVersion(): string;
|
|
4535
4638
|
|
|
4639
|
+
/**
|
|
4640
|
+
* 压缩包解包 —— zip 和 tar.gz 都交给系统的 `tar`(方案 32 的第三、四种来源)。
|
|
4641
|
+
*
|
|
4642
|
+
* ## 为什么是 `tar` 而不是一个 npm 依赖
|
|
4643
|
+
*
|
|
4644
|
+
* 当前支持的两个平台上,系统自带的 `tar` **都是 bsdtar,都认 zip**:
|
|
4645
|
+
*
|
|
4646
|
+
* - macOS 自带 bsdtar(`/usr/bin/tar`)
|
|
4647
|
+
* - Windows 10 1803 起自带 `C:\Windows\System32\tar.exe`,同样是 bsdtar
|
|
4648
|
+
*
|
|
4649
|
+
* ## ⚠️ Windows 上必须**指名**那个 bsdtar,不能赌 `PATH`(2026-08-12 修的 bug)
|
|
4650
|
+
*
|
|
4651
|
+
* 上面那句「Windows 上 tar 是 bsdtar」只对**干净的** `PATH` 成立。任何装了
|
|
4652
|
+
* Git for Windows / MSYS2 的机器上,`PATH` 里 `/usr/bin` 排在 `System32`
|
|
4653
|
+
* 前面,`tar` 解析到的是 **GNU tar** —— 而 GNU tar 不吃 Windows 路径:
|
|
4654
|
+
*
|
|
4655
|
+
* - `-f C:\...\x.tgz` 被当成 `host:path` 的远程归档:
|
|
4656
|
+
* `tar (child): Cannot connect to C: resolve failed`
|
|
4657
|
+
* - 连 `-C C:\...\dest` 都会被它按 POSIX 路径 + 反斜杠转义处理掉
|
|
4658
|
+
*
|
|
4659
|
+
* **`--force-local` 解决不了**:GNU tar 认它,而 bsdtar 直接
|
|
4660
|
+
* `Option --force-local is not supported` —— 一个 flag 服务不了两边。
|
|
4661
|
+
* 所以走 {@link resolveTar}:Windows 上指名 `%SystemRoot%\System32\tar.exe`,
|
|
4662
|
+
* 找不到才回落到 `PATH`。这条和 infra 的 `resolveRipgrep()` 是同一个形状 ——
|
|
4663
|
+
* **别让一个外部二进制的身份取决于用户的 PATH 顺序。**
|
|
4664
|
+
*
|
|
4665
|
+
* 换成 JS 实现要自己解 zip 的中央目录 + inflate,再加一份 tar 解析 —— 三百行
|
|
4666
|
+
* 安全敏感的解析代码(路径穿越、zip slip、符号链接逃逸都得自己防),
|
|
4667
|
+
* 而 bsdtar 早就把这些处理完了。多引一个 npm 包则是往一条**会下载并解压
|
|
4668
|
+
* 网络内容**的路径上再加一个供应链面,方向反了。
|
|
4669
|
+
*
|
|
4670
|
+
* `unzip` 不用是因为 Windows 上没有它。
|
|
4671
|
+
*
|
|
4672
|
+
* ## 单根目录会被自动摊平
|
|
4673
|
+
*
|
|
4674
|
+
* GitHub 的 zip 裹一层 `repo-main/`,npm 的 tarball 裹一层 `package/` ——
|
|
4675
|
+
* 两者都不该出现在插件目录里。与其让调用方各猜一个 `--strip-components`,
|
|
4676
|
+
* 不如解完之后看一眼:**清单不在顶层、而顶层恰好只有一个目录**,就把那一层
|
|
4677
|
+
* 提上来。判据是「清单在哪」而不是「有几个条目」,所以一个本来就把
|
|
4678
|
+
* `epoch-plugin.json` 放在顶层、旁边还有一个 `commands/` 的正常包不会被误摊。
|
|
4679
|
+
*/
|
|
4680
|
+
type ExtractOutcome = {
|
|
4681
|
+
ok: true;
|
|
4682
|
+
} | {
|
|
4683
|
+
ok: false;
|
|
4684
|
+
reason: string;
|
|
4685
|
+
};
|
|
4686
|
+
/**
|
|
4687
|
+
* 解一个压缩包到 `dest`(目录必须已存在),然后按需摊平单根目录。
|
|
4688
|
+
*
|
|
4689
|
+
* `tar` 的 `-x` 对 zip 和 tar.gz 是同一条命令 —— bsdtar 按内容自动识别格式,
|
|
4690
|
+
* 不用我们先判后缀(后缀本来也不可信,URL 上写什么都行)。
|
|
4691
|
+
*/
|
|
4692
|
+
/**
|
|
4693
|
+
* 用哪个 `tar`。见文件头那条 ⚠️ —— Windows 上指名系统自带的 bsdtar。
|
|
4694
|
+
*
|
|
4695
|
+
* 用 `%SystemRoot%` 而不是写死 `C:\Windows`:系统盘不一定是 C,而这个环境变量
|
|
4696
|
+
* 是 Windows 自己维护的。取不到再退回字面量,那时候我们已经在猜了,猜一个
|
|
4697
|
+
* 比不猜好 —— 后面还有一层「找不到就回落 PATH」兜着。
|
|
4698
|
+
*/
|
|
4699
|
+
declare function resolveTar(): string;
|
|
4700
|
+
declare function extractArchive(archive: string, dest: string): Promise<ExtractOutcome>;
|
|
4701
|
+
|
|
4702
|
+
/**
|
|
4703
|
+
* 插件打包 —— 一条本地插件目录 → 一个 `.zip`。
|
|
4704
|
+
*
|
|
4705
|
+
* 这是 [archive.ts](./archive.ts) 的**反方向**:那一份把下载来的包解开,这一份
|
|
4706
|
+
* 把用户自己写的插件裹起来交出去。两边共用 {@link resolveTar},所以「用哪个 tar」
|
|
4707
|
+
* 只有一个答案(Windows 上 `PATH` 顺序那个坑记在那个文件头)。
|
|
4708
|
+
*
|
|
4709
|
+
* ```
|
|
4710
|
+
* planPack('/Users/me/my-plugin') → 会打包哪 12 个文件、一共多大、有没有可疑的
|
|
4711
|
+
* packPlugin(plan, mkdtempSync(…)) → /tmp/…/my-plugin-1.0.0.zip
|
|
4712
|
+
* ```
|
|
4713
|
+
*
|
|
4714
|
+
* ## ⚠️ 零、格式是 **zip**,而 2026-09-08 从 `.tar.gz` 改过来的
|
|
4715
|
+
*
|
|
4716
|
+
* 改的原因是外部约束:嵌入宿主的插件仓库(盘古那套)**只收 `.zip`**,
|
|
4717
|
+
* 传别的格式当场被拒。
|
|
4718
|
+
*
|
|
4719
|
+
* 当初选 tar.gz 的理由是「GNU tar 写不出 zip,只有 bsdtar 能」—— 那个顾虑
|
|
4720
|
+
* **不成立**,因为这个项目**只支持 Windows 和 macOS**(README 第一节明写
|
|
4721
|
+
* 「Linux 暂不支持」),而**两个平台自带的都是 bsdtar**。同一条事实也是
|
|
4722
|
+
* `archive.ts` 敢用 `tar -xf` 解 zip 的依据 —— 也就是说「读」那一侧早就在
|
|
4723
|
+
* 依赖它了,「写」这一侧跟着它走才是一致的。
|
|
4724
|
+
*
|
|
4725
|
+
* 落法是 `--format zip`(**不是**靠后缀猜):bsdtar 按 `-f` 的后缀选格式这件事
|
|
4726
|
+
* 不是它的契约,显式给格式才是。本机实测过:`tar -c -f x.zip --format zip` 出来的
|
|
4727
|
+
* 是真 zip(`file(1)` 认、`unzip -l` 也认)—— 后者要紧,因为**解包那一侧可能不是
|
|
4728
|
+
* 我们**(宿主的服务端拿 Python / Java 去解)。
|
|
4729
|
+
*
|
|
4730
|
+
* ## 一、⚠️ 分成两段,是因为**上传是不可逆的对外发布**
|
|
4731
|
+
*
|
|
4732
|
+
* 装一个插件出了错还能卸掉;把一个目录发到别人的服务器上**收不回来**。所以这条路
|
|
4733
|
+
* 上给人的那道闸门不是「确认吗」,而是**「这些文件会离开这台机器」的那一份清单**——
|
|
4734
|
+
* `planPack` 存在的全部理由就是让那份清单在按下去之前拿得到。
|
|
4735
|
+
*
|
|
4736
|
+
* ## 二、⚠️ 喂给 `tar` 的就是 {@link PackPlan.files},**不是一套 `--exclude` 规则**
|
|
4737
|
+
*
|
|
4738
|
+
* 两个理由,第二个是正题:
|
|
4739
|
+
*
|
|
4740
|
+
* 1. `--exclude` 的 glob 语义 GNU tar 和 bsdtar **不一致**(`.git` 这个模式对上
|
|
4741
|
+
* `./.git` 两边表现不同),把排除项建在它上面等于把一条安全相关的判断交给
|
|
4742
|
+
* 「用户机器上装没装 Git for Windows」;
|
|
4743
|
+
* 2. **用户看到的那一份和真发出去的那一份,在构造上必须是同一份。** 走两套规则
|
|
4744
|
+
* (预览走 fs 遍历、打包走 tar 的 glob)的话,它们分叉的那天没有任何东西会红 ——
|
|
4745
|
+
* 而分叉的表现是「预览里没有的东西被发出去了」。
|
|
4746
|
+
*
|
|
4747
|
+
* 所以 `-T <清单文件>`:清单由 {@link planPack} 产出,`packPlugin` 只是把它抄给 tar。
|
|
4748
|
+
*
|
|
4749
|
+
* ## 三、⚠️ 软链**不打包**,而且要说出来
|
|
4750
|
+
*
|
|
4751
|
+
* 一条指向 `~/.ssh/id_rsa` 的软链,tar 默认存的是「链接目标那串字符」而不是内容 ——
|
|
4752
|
+
* 发出去无害但读起来莫名其妙;而真要跟着解引用又是一次**目录外的读取**。
|
|
4753
|
+
* 两头都不选:跳过它,然后在 {@link PackPlan.skippedLinks} 里报出来。
|
|
4754
|
+
* 静默跳过的表现是「解开的包比原目录少东西,而没人说过为什么」。
|
|
4755
|
+
*
|
|
4756
|
+
* ## 四、⚠️ 看起来像密钥的文件**照打**,只是警告
|
|
4757
|
+
*
|
|
4758
|
+
* 处置口径同 `hooks.json` / `mcp.json` 那两行(在安装预览里带警示色、但不拦):
|
|
4759
|
+
* 静默剔除会让用户以为发出去的是全量,而那正是他之后据以判断「要不要重新发一版」
|
|
4760
|
+
* 的依据。说一句、让他自己决定 —— 判据同「拿不准时说拿不准,不猜一个」。
|
|
4761
|
+
*/
|
|
4762
|
+
|
|
4763
|
+
/**
|
|
4764
|
+
* 一律不打包的顶层 / 任意层目录名。
|
|
4765
|
+
*
|
|
4766
|
+
* 四个都是「本机产物」而不是插件内容:`.git` 里有完整历史(常常比插件大两个
|
|
4767
|
+
* 数量级,而且带着作者的邮箱和别的分支),`node_modules` 是装出来的,
|
|
4768
|
+
* `.DS_Store` 是 Finder 写的,`__pycache__` 是 CPython 写的字节码缓存。
|
|
4769
|
+
*
|
|
4770
|
+
* ⚠️ 最后一个 2026-09-09 加的,而它不只是「省点体积」:`.pyc` 里钉着**生成它的
|
|
4771
|
+
* 那个解释器版本**(`cpython-311`),发到一台跑 3.13 的机器上是死重量。
|
|
4772
|
+
* 名字这一格可以按字面判,因为 `__pycache__` 是 CPython 保留的目录名(PEP 3147),
|
|
4773
|
+
* 不会是用户自己的东西 —— 虚拟环境那一档不成立,所以它走 {@link isVirtualenv}。
|
|
4774
|
+
*/
|
|
4775
|
+
declare const PACK_EXCLUDES: readonly string[];
|
|
4776
|
+
/** 默认容量上限。超了拒 —— 一个 2GB 的包交给宿主回调不是「慢一点」,是把它打挂 */
|
|
4777
|
+
declare const PACK_MAX_BYTES: number;
|
|
4778
|
+
declare const PACK_MAX_FILES = 2000;
|
|
4779
|
+
interface PackLimits {
|
|
4780
|
+
maxBytes?: number;
|
|
4781
|
+
maxFiles?: number;
|
|
4782
|
+
}
|
|
4783
|
+
/** 会被打进包里的一个文件 */
|
|
4784
|
+
interface PackFile {
|
|
4785
|
+
/** 相对插件根,**永远用 `/` 分隔** —— 它要写进 tar 的清单文件 */
|
|
4786
|
+
path: string;
|
|
4787
|
+
bytes: number;
|
|
4788
|
+
/**
|
|
4789
|
+
* 落在 token 里,用来判「预览之后这个目录又被改过」。
|
|
4790
|
+
*
|
|
4791
|
+
* 只看大小不够:改一个字符的 `hooks.json` 完全可能字节数不变,而那一改正是
|
|
4792
|
+
* 「你确认的和真发出去的是两份」里最要紧的一种。
|
|
4793
|
+
*/
|
|
4794
|
+
mtimeMs: number;
|
|
4795
|
+
}
|
|
4796
|
+
/** 「会打包什么」。这份东西**同时**是给人看的那一屏和喂给 tar 的清单 */
|
|
4797
|
+
interface PackPlan {
|
|
4798
|
+
/** 插件根的绝对路径 */
|
|
4799
|
+
dir: string;
|
|
4800
|
+
manifest: PluginManifest;
|
|
4801
|
+
/** 按路径排过序 —— 屏幕上要稳定,token 也要稳定 */
|
|
4802
|
+
files: readonly PackFile[];
|
|
4803
|
+
totalBytes: number;
|
|
4804
|
+
/** 名字看起来像密钥的那几条(**在 `files` 里面**,只是被点名了),见文件头第四节 */
|
|
4805
|
+
suspicious: readonly string[];
|
|
4806
|
+
/** 跳过的软链(**不在 `files` 里**),见文件头第三节 */
|
|
4807
|
+
skippedLinks: readonly string[];
|
|
4808
|
+
}
|
|
4809
|
+
type PackPlanOutcome = {
|
|
4810
|
+
ok: true;
|
|
4811
|
+
plan: PackPlan;
|
|
4812
|
+
} | {
|
|
4813
|
+
ok: false;
|
|
4814
|
+
reason: string;
|
|
4815
|
+
};
|
|
4816
|
+
type PackOutcome = {
|
|
4817
|
+
ok: true;
|
|
4818
|
+
archivePath: string;
|
|
4819
|
+
bytes: number;
|
|
4820
|
+
} | {
|
|
4821
|
+
ok: false;
|
|
4822
|
+
reason: string;
|
|
4823
|
+
};
|
|
4824
|
+
/**
|
|
4825
|
+
* 会打包什么。**纯遍历,一个字节都不写、一个子进程都不起。**
|
|
4826
|
+
*
|
|
4827
|
+
* @param dir 插件根的绝对路径(里面得有 `epoch-plugin.json`)
|
|
4828
|
+
*/
|
|
4829
|
+
declare function planPack(dir: string, limits?: PackLimits): PackPlanOutcome;
|
|
4830
|
+
/**
|
|
4831
|
+
* 打好的包叫什么。`<name>-<version>.zip` —— 两格都已经过了清单校验。
|
|
4832
|
+
*
|
|
4833
|
+
* ⚠️ 这个名字**会被宿主原样用作上传的文件名**(盘古那侧按后缀判「只收 .zip」),
|
|
4834
|
+
* 所以后缀不是装饰。判据见文件头第零节。
|
|
4835
|
+
*/
|
|
4836
|
+
declare function packFileName(manifest: PluginManifest): string;
|
|
4837
|
+
/**
|
|
4838
|
+
* 照着 {@link PackPlan} 打一个包。
|
|
4839
|
+
*
|
|
4840
|
+
* ⚠️ **`destDir` 必须在 `plan.dir` 外面。** 同 `install.ts` 的 `withDownloadDir`
|
|
4841
|
+
* 记的那个坑:一个躺在插件目录旁边的压缩包会被下一次 `planPack` 数进去,
|
|
4842
|
+
* 而解包那一侧的 `flattenSingleRoot` 也会因此判断失准。这一条**在这里挡住**,
|
|
4843
|
+
* 不靠调用方记得。
|
|
4844
|
+
*/
|
|
4845
|
+
declare function packPlugin(plan: PackPlan, destDir: string): Promise<PackOutcome>;
|
|
4846
|
+
|
|
4536
4847
|
/**
|
|
4537
4848
|
* 「这个插件里有什么」—— 扫一个插件目录,数出**六类**扩展物(方案 32,
|
|
4538
4849
|
* 方案 44 PR-3 补上第六类 MCP server)。
|
|
@@ -4705,16 +5016,22 @@ declare function scanPluginDir(dir: string, pluginName: string): PluginInventory
|
|
|
4705
5016
|
/**
|
|
4706
5017
|
* 插件是从哪装来的。
|
|
4707
5018
|
*
|
|
4708
|
-
* `marketplace`
|
|
5019
|
+
* `marketplace` 不是第六种传输方式 —— 它最终仍然落到这五种之一,
|
|
4709
5020
|
* 记成独立一档是为了 `epoch plugin list` 能说出「这是从哪个市场装的」,
|
|
4710
5021
|
* 以及 `update` 时知道该回哪个市场重新解析 `source`。
|
|
5022
|
+
*
|
|
5023
|
+
* ⚠️ `host` 是 2026-09-08 加的第五档:**字节由宿主去取**(它有登录会话,
|
|
5024
|
+
* 我们没有)。判据在 `source.ts` 的 `host:` 那一支上。
|
|
5025
|
+
* 它是一档**真的传输方式**而不是 `archive` 的变体:`archive` 那一档的字节
|
|
5026
|
+
* 我们自己下,这一档我们一个网络请求都不发。
|
|
4711
5027
|
*/
|
|
4712
|
-
type PluginSourceType = 'local' | 'git' | 'npm' | 'archive';
|
|
5028
|
+
type PluginSourceType = 'local' | 'git' | 'npm' | 'archive' | 'host';
|
|
4713
5029
|
declare const RecordSchema$1: z.ZodObject<{
|
|
4714
5030
|
name: z.ZodString;
|
|
4715
5031
|
version: z.ZodString;
|
|
4716
5032
|
source: z.ZodString;
|
|
4717
5033
|
sourceType: z.ZodEnum<{
|
|
5034
|
+
host: "host";
|
|
4718
5035
|
local: "local";
|
|
4719
5036
|
git: "git";
|
|
4720
5037
|
npm: "npm";
|
|
@@ -4781,10 +5098,30 @@ interface ResolvedSource {
|
|
|
4781
5098
|
type: PluginSourceType;
|
|
4782
5099
|
/** 用户敲的原文,原样进记录 —— `epoch plugin update` 要照它重来一遍 */
|
|
4783
5100
|
raw: string;
|
|
4784
|
-
/**
|
|
5101
|
+
/**
|
|
5102
|
+
* git 用 clone 地址、npm 用包名、archive 用 URL **或一条本地压缩包路径**、
|
|
5103
|
+
* local 用绝对路径、host 用**宿主自己认得的那串**(我们不解析它)。
|
|
5104
|
+
*/
|
|
4785
5105
|
target: string;
|
|
4786
5106
|
/** archive 专用:`#sha256=…` 里那串十六进制(小写) */
|
|
4787
5107
|
sha256?: string;
|
|
5108
|
+
/**
|
|
5109
|
+
* archive 专用:`target` 是**本机一个压缩包文件**,不是一条 URL(2026-09-08)。
|
|
5110
|
+
*
|
|
5111
|
+
* ## ⚠️ 为什么它是 `archive` 的一格,而不是 `local` 的一格
|
|
5112
|
+
*
|
|
5113
|
+
* `local` 的语义是「**软链**到用户的源码目录,改完重启即生效」——
|
|
5114
|
+
* 那是写插件时用的。一个 `.zip` 文件软链过去之后,
|
|
5115
|
+
* `readPluginManifest` 会去一个**文件**里找 `epoch-plugin.json`,
|
|
5116
|
+
* 读不出来,而报错是「这个目录不是 epoch 插件」(指着一个 zip)。
|
|
5117
|
+
*
|
|
5118
|
+
* 2026-09-08 之前 `resolveSource('/tmp/x.zip')` 正是落到 `local` 那一支的 ——
|
|
5119
|
+
* 也就是说「装一个本地压缩包」这件事**做不到,而且报错指向错的地方**。
|
|
5120
|
+
*
|
|
5121
|
+
* 归到 `archive` 是因为落地方式一致(解包 + 拷贝,不是软链),
|
|
5122
|
+
* 差别只在「字节从哪来」:一条 URL 要下载,这一档直接读文件。
|
|
5123
|
+
*/
|
|
5124
|
+
localFile?: true;
|
|
4788
5125
|
/**
|
|
4789
5126
|
* git 专用:插件在仓库里的子目录,来自 `#subdir=…`。
|
|
4790
5127
|
*
|
|
@@ -4800,22 +5137,42 @@ interface ResolvedSource {
|
|
|
4800
5137
|
* 判定顺序有讲究:`git+https://` 必须排在裸 `https://` 前面,
|
|
4801
5138
|
* 而 `.zip` 结尾的 https 必须排在「其余 https 一律当 git」前面 —— 否则
|
|
4802
5139
|
* `https://x/plugin.zip` 会被 clone。
|
|
5140
|
+
*
|
|
5141
|
+
* ## ⚠️ 一条 https 地址**没有压缩包后缀就会被 clone**,这不是 bug 是这张表的形状
|
|
5142
|
+
*
|
|
5143
|
+
* `isArchiveUrl` 去掉 query 之后要求 `.zip` / `.tgz` / `.tar.gz` 结尾。所以一条
|
|
5144
|
+
* **下载端点**形态的地址(`https://host/api/download?version_id=9`)会落到最后
|
|
5145
|
+
* 那一支、被当成 git 仓库去 clone —— 而报错是一句 git 的话,跟「这是个 zip」
|
|
5146
|
+
* 毫无关系。
|
|
5147
|
+
*
|
|
5148
|
+
* 这一条 2026-09-08 撞到过(盘古的 `download_url` 正是这个形状)。**处置不是
|
|
5149
|
+
* 放宽后缀判断**(那会把一条真的 git 地址判成压缩包),而是让宿主用
|
|
5150
|
+
* `host:` 那一档 —— 那条路上地址由宿主自己认、字节也由宿主自己取。
|
|
4803
5151
|
*/
|
|
4804
5152
|
declare function resolveSource(raw: string): ResolvedSource | undefined;
|
|
4805
5153
|
|
|
4806
5154
|
/**
|
|
4807
|
-
* 插件安装 ——
|
|
5155
|
+
* 插件安装 —— 六种 source 到 `~/.epoch/plugins/<name>/`(方案 32,后两行 2026-09-08)。
|
|
4808
5156
|
*
|
|
4809
|
-
* | 形式 | 落地方式
|
|
4810
|
-
* | ------------------------------------- |
|
|
4811
|
-
* | `./local/path
|
|
4812
|
-
* | `github:owner/repo` / `git+https://…` | `git clone --depth 1`
|
|
4813
|
-
* | `npm:package-name` | `npm pack` + 解包
|
|
4814
|
-
* | `https://…/plugin.zip` | 下载 + 解压,可选 `#sha256=…`
|
|
5157
|
+
* | 形式 | 落地方式 | 谁去取字节 |
|
|
5158
|
+
* | ------------------------------------- | ------------------------------- | ---------- |
|
|
5159
|
+
* | `./local/path`(目录) | **软链**(开发插件时用) | — |
|
|
5160
|
+
* | `github:owner/repo` / `git+https://…` | `git clone --depth 1` | 我们 |
|
|
5161
|
+
* | `npm:package-name` | `npm pack` + 解包 | 我们 |
|
|
5162
|
+
* | `https://…/plugin.zip` | 下载 + 解压,可选 `#sha256=…` | 我们 |
|
|
5163
|
+
* | `./local/plugin.zip`(**文件**) | 直接解压 | — |
|
|
5164
|
+
* | `host:<宿主自己的编码>` | 解压 | **宿主** |
|
|
4815
5165
|
*
|
|
4816
5166
|
* 「用户敲的那串 → 上面哪一行」的解析在 [source.ts](./source.ts):它是这条链上
|
|
4817
5167
|
* 唯一的纯函数,也是参数注入的唯一闸门,所以单独一个文件、单独一张用例表。
|
|
4818
5168
|
*
|
|
5169
|
+
* ## ⚠️ 最后一行是这张表上唯一一档「**我们不发网络请求**」
|
|
5170
|
+
*
|
|
5171
|
+
* 有些包要登录会话才下得到(嵌入宿主的私有插件仓库),而这一层的下载是一次
|
|
5172
|
+
* **裸 fetch,一个凭据都不带** —— 那是刻意的立场(判据在 `marketplace.ts` 文件头
|
|
5173
|
+
* 「为什么不直接支持鉴权」)。`host:` 把取字节整个交给宿主:它有会话、
|
|
5174
|
+
* 它自己校验摘要,交回来一个本地包。判据在 {@link InstallOptions.fetchFromHost} 上。
|
|
5175
|
+
*
|
|
4819
5176
|
* ## 装到临时目录、验完再搬过去
|
|
4820
5177
|
*
|
|
4821
5178
|
* 每一种来源都先落到 `~/.epoch/plugins/.staging-<uuid>/`,读清单、校验名字、
|
|
@@ -4840,6 +5197,20 @@ declare function resolveSource(raw: string): ResolvedSource | undefined;
|
|
|
4840
5197
|
*
|
|
4841
5198
|
* 不是「警告之后照装」。带 `#sha256=` 的 URL 说明用户在乎可重现性,
|
|
4842
5199
|
* 而一个内容变了的压缩包和一个被替换掉的压缩包,在这一层是同一件事。
|
|
5200
|
+
*
|
|
5201
|
+
* ## ⚠️ 装这一下**没有对应的模型工具**,而那是判断不是缺口
|
|
5202
|
+
*
|
|
5203
|
+
* 装一个插件会往用户机器上落下 `hooks.json`(每一条都是会 spawn 的 shell 命令)
|
|
5204
|
+
* 和 `mcp.json`(stdio 那档同样起子进程),而整条安装链上给人的闸门就是
|
|
5205
|
+
* {@link InstallOptions.confirm} 那一屏 —— **把安装交给模型等于让被审批的一方
|
|
5206
|
+
* 自己按下确认**。判据同 `tools/builtin/skill-write.ts` 第三节对 `delete` 的处置。
|
|
5207
|
+
*
|
|
5208
|
+
* 这条判断的家原来在 `tools/builtin/plugin-author.ts` 的文件头上,而那个文件
|
|
5209
|
+
* 2026-09-10 整个删了(`plugin_validate` / `plugin_pack` 移除,模型侧现在一个
|
|
5210
|
+
* 插件工具都没有)—— 搬到这儿是因为**它和那两个工具在不在没关系**:只要这条
|
|
5211
|
+
* 安装链还在,「要不要给模型一个 `plugin_install`」就还会被问一次。
|
|
5212
|
+
* ⚠️ 想加的时候要答的问题是**「模型给用户装了一条 hook,他从哪儿知道」**,
|
|
5213
|
+
* 而不是「能力层已经有这个函数了」。
|
|
4843
5214
|
*/
|
|
4844
5215
|
|
|
4845
5216
|
interface InstallOptions {
|
|
@@ -4874,13 +5245,49 @@ interface InstallOptions {
|
|
|
4874
5245
|
confirm?: (preview: InstallPreview) => Promise<boolean>;
|
|
4875
5246
|
/** 进度提示(clone / 下载)。不给就静默 —— 库不替宿主决定往哪儿写 */
|
|
4876
5247
|
onProgress?: (message: string) => void;
|
|
5248
|
+
/**
|
|
5249
|
+
* 取一个 `host:` 来源的包 —— **由宿主去下,我们一个网络请求都不发**(2026-09-08)。
|
|
5250
|
+
*
|
|
5251
|
+
* `source.target` 是宿主写在自己那份市场目录里的那串(我们不解析它,
|
|
5252
|
+
* 判据在 `source.ts` 的 `host:` 那一支上);宿主拿它去自己的接口下包、
|
|
5253
|
+
* **自己校验摘要**,然后把一个本地压缩包的路径交回来。
|
|
5254
|
+
*
|
|
5255
|
+
* ⚠️ **不给它 = `host:` 那一档装不了**(`fetchInto` 回一句拒绝)。
|
|
5256
|
+
* 这不是降级路径:那些包我们压根没有凭据去取,
|
|
5257
|
+
* 硬造一次裸 fetch 只会拿到一个 401 的 HTML 然后当成压缩包解。
|
|
5258
|
+
*
|
|
5259
|
+
* ⚠️ **摘要校验在宿主那一侧,这一层不重做**:我们看不见那份目录里的 sha256
|
|
5260
|
+
* (它是宿主的私有编码的一部分),而两处各校一次的话,
|
|
5261
|
+
* 「谁没校」这个问题会有两个答案。宿主那侧不校就是宿主的漏 —— 它的文档该写这条。
|
|
5262
|
+
*/
|
|
5263
|
+
fetchFromHost?: (input: {
|
|
5264
|
+
/** `host:` 后面那串,原样 */
|
|
5265
|
+
target: string;
|
|
5266
|
+
/** 我们准备好的一个**空临时目录**,包放这儿。用完由我们清掉 */
|
|
5267
|
+
destDir: string;
|
|
5268
|
+
}) => Promise<{
|
|
5269
|
+
ok: true;
|
|
5270
|
+
archivePath: string;
|
|
5271
|
+
} | {
|
|
5272
|
+
ok: false;
|
|
5273
|
+
reason?: string;
|
|
5274
|
+
}>;
|
|
4877
5275
|
}
|
|
4878
5276
|
/** 安装前预览(§2.8)。宿主拿它画那张「将安装什么」的表 */
|
|
4879
5277
|
interface InstallPreview {
|
|
4880
5278
|
manifest: PluginManifest;
|
|
4881
5279
|
source: ResolvedSource;
|
|
4882
5280
|
inventory: PluginInventory;
|
|
4883
|
-
/**
|
|
5281
|
+
/**
|
|
5282
|
+
* 已经装过的同名插件;有值时这次安装会被拒(验收 #8)。
|
|
5283
|
+
*
|
|
5284
|
+
* ⚠️ **`replace` 命中的那一条不算**(2026-09-10):`epoch plugin update` 走的
|
|
5285
|
+
* 就是「同名重装一遍」,那条记录是**被替换的那一个**,不是挡路的。判据在
|
|
5286
|
+
* {@link InstallOptions.replace} 上(「所以同名不是冲突」那句从一开始就写着)。
|
|
5287
|
+
*
|
|
5288
|
+
* 这一格是**结论**不是事实 —— 它答的是「这次会不会被拒」,不是「锁里有没有
|
|
5289
|
+
* 同名的」。写成后者的代价见 `runInstall` 里算它那两行上的注释。
|
|
5290
|
+
*/
|
|
4884
5291
|
conflict?: PluginRecord;
|
|
4885
5292
|
/**
|
|
4886
5293
|
* 清单里的 `epochVersion` 和当前引擎不匹配:**装得上,但加载器会跳过它**。
|
|
@@ -5062,18 +5469,51 @@ declare function updatePlugin(name: string, opts: InstallOptions): Promise<Insta
|
|
|
5062
5469
|
/**
|
|
5063
5470
|
* 插件市场 —— 加市场 / 搜 / 从市场装(方案 32)。
|
|
5064
5471
|
*
|
|
5065
|
-
* 市场 = **一个 `epoch-marketplace.json
|
|
5472
|
+
* 市场 = **一个 `epoch-marketplace.json`**,没有服务端、没有账号:
|
|
5066
5473
|
*
|
|
5067
5474
|
* ```json
|
|
5068
5475
|
* {
|
|
5069
5476
|
* "name": "acme",
|
|
5070
5477
|
* "owner": { "name": "Acme Inc." },
|
|
5478
|
+
* "display": { "fields": ["status", "downloads", "author"] },
|
|
5071
5479
|
* "plugins": [
|
|
5072
|
-
* {
|
|
5480
|
+
* {
|
|
5481
|
+
* "name": "toolkit",
|
|
5482
|
+
* "description": "…",
|
|
5483
|
+
* "source": "./plugins/toolkit",
|
|
5484
|
+
* "category": "dev",
|
|
5485
|
+
* "author": { "name": "张三" },
|
|
5486
|
+
* "status": "listed",
|
|
5487
|
+
* "downloads": 1240,
|
|
5488
|
+
* "likes": 87
|
|
5489
|
+
* }
|
|
5073
5490
|
* ]
|
|
5074
5491
|
* }
|
|
5075
5492
|
* ```
|
|
5076
5493
|
*
|
|
5494
|
+
* ⚠️ `downloads` / `likes` 是**市场那一侧数的**,而且**冻在加市场那一刻**
|
|
5495
|
+
* (目录是快照,见下面第二节)—— 判据在那两格自己的注释上。
|
|
5496
|
+
*
|
|
5497
|
+
* ## 顶上那格 `display`:**市场自己说印哪几格**(2026-09-10)
|
|
5498
|
+
*
|
|
5499
|
+
* 在它之前,「印不印作者」这件事只有一个开关 —— **填没填**。于是一个既想在自己
|
|
5500
|
+
* 后台记着作者、又不想在这套界面上印它的市场,没有任何写法表达得出来。
|
|
5501
|
+
*
|
|
5502
|
+
* `display.fields` 是一张**白名单**,只管徽标 / 元信息那一档(名单和「为什么承重
|
|
5503
|
+
* 的那几格一格都不在里面」在 {@link MARKETPLACE_DISPLAY_FIELDS} 上)。
|
|
5504
|
+
* ⚠️ **整格不写 = 照旧「填了就画」** —— 存量目录一个字都不用改,
|
|
5505
|
+
* 判据在 `DisplaySchema.fields` 上那张三行的表。
|
|
5506
|
+
*
|
|
5507
|
+
* ## ⚠️ 「没有上传接口」这句话 2026-09-08 改了半句
|
|
5508
|
+
*
|
|
5509
|
+
* 原话是「没有服务端、没有账号、**没有上传接口**、没有审核」。改的是第三句 ——
|
|
5510
|
+
* 而**改的是主语不是事实**:**我们**仍然没有服务端、没有上传接口,一个字节都不收。
|
|
5511
|
+
* 变的是嵌入宿主那一侧多了一条出口(`HostMarketplaces.upload` 那个回调),
|
|
5512
|
+
* epoch 只负责把一条本地目录打成 `.tar.gz` 交给它([pack.ts](./pack.ts))。
|
|
5513
|
+
*
|
|
5514
|
+
* 于是目录条目上多了一格 `author` —— 一个用户上传的市场里,「清单是谁放的」
|
|
5515
|
+
* (`owner`)和「这一条是谁写的」(`author`)从第二条开始就不相等了。
|
|
5516
|
+
*
|
|
5077
5517
|
* ## 目录是**缓存下来的**,不是每次现拉
|
|
5078
5518
|
*
|
|
5079
5519
|
* `epoch plugin search` 要能在飞机上跑。加市场那一刻把整份目录存进
|
|
@@ -5104,6 +5544,55 @@ declare const EntrySchema: z.ZodObject<{
|
|
|
5104
5544
|
source: z.ZodString;
|
|
5105
5545
|
category: z.ZodOptional<z.ZodString>;
|
|
5106
5546
|
keywords: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
5547
|
+
author: z.ZodOptional<z.ZodObject<{
|
|
5548
|
+
name: z.ZodString;
|
|
5549
|
+
email: z.ZodOptional<z.ZodString>;
|
|
5550
|
+
url: z.ZodOptional<z.ZodString>;
|
|
5551
|
+
}, z.core.$strip>>;
|
|
5552
|
+
downloads: z.ZodOptional<z.ZodNumber>;
|
|
5553
|
+
likes: z.ZodOptional<z.ZodNumber>;
|
|
5554
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
5555
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
5556
|
+
version: z.ZodOptional<z.ZodString>;
|
|
5557
|
+
changelog: z.ZodOptional<z.ZodString>;
|
|
5558
|
+
size: z.ZodOptional<z.ZodNumber>;
|
|
5559
|
+
homepage: z.ZodOptional<z.ZodString>;
|
|
5560
|
+
visibility: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
|
|
5561
|
+
private: "private";
|
|
5562
|
+
public: "public";
|
|
5563
|
+
}>>>;
|
|
5564
|
+
status: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
|
|
5565
|
+
rejected: "rejected";
|
|
5566
|
+
listed: "listed";
|
|
5567
|
+
reviewing: "reviewing";
|
|
5568
|
+
offline: "offline";
|
|
5569
|
+
}>>>;
|
|
5570
|
+
}, z.core.$strip>;
|
|
5571
|
+
/**
|
|
5572
|
+
* 市场说了算的那几格「要不要印在屏幕上」(2026-09-10)。
|
|
5573
|
+
*
|
|
5574
|
+
* ## ⚠️ 这张名单里**一格承重的都没有**,那是它的定义不是巧合
|
|
5575
|
+
*
|
|
5576
|
+
* 缺席的那几格各有各的理由,而它们都不是「忘了列」:
|
|
5577
|
+
*
|
|
5578
|
+
* | 没进名单 | 为什么它不许被藏起来 |
|
|
5579
|
+
* | ------------ | -------------------------------------------------------------- |
|
|
5580
|
+
* | `name` | 它是标识 —— 藏了之后这一条在屏幕上没有名字 |
|
|
5581
|
+
* | `source` | 装它要靠它,而且 `search()` 拿它判「本地还是要 clone」 |
|
|
5582
|
+
* | `version` | `updateAvailable` 是拿它比出来的 —— 藏它 = **藏掉一次真的更新** |
|
|
5583
|
+
* | `description`| 卡片的正题;藏了之后一屏卡片全是空的 |
|
|
5584
|
+
* | `keywords` | 它压根不上屏,它是检索面 |
|
|
5585
|
+
* | `displayName`| 「给人看的名字」是身份不是徽标 —— 藏它只会退回那串机器标识 |
|
|
5586
|
+
*
|
|
5587
|
+
* 也就是说这张名单管的**只有徽标 / 元信息那一档**:一格藏没了,屏幕上少一枚芯片,
|
|
5588
|
+
* 别的一个字都不动。这条性质是这个功能能成立的全部前提 —— 一张能藏掉 `source`
|
|
5589
|
+
* 的名单会让一份合法的目录变得装不了东西,而报错会指着一个和它无关的地方。
|
|
5590
|
+
*/
|
|
5591
|
+
declare const MARKETPLACE_DISPLAY_FIELDS: readonly ["status", "downloads", "likes", "author", "category", "visibility", "icon", "homepage", "size"];
|
|
5592
|
+
/** {@link MARKETPLACE_DISPLAY_FIELDS} 里的一格 */
|
|
5593
|
+
type MarketplaceDisplayField = (typeof MARKETPLACE_DISPLAY_FIELDS)[number];
|
|
5594
|
+
declare const DisplaySchema: z.ZodObject<{
|
|
5595
|
+
fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
5107
5596
|
}, z.core.$strip>;
|
|
5108
5597
|
declare const CatalogSchema: z.ZodObject<{
|
|
5109
5598
|
name: z.ZodString;
|
|
@@ -5112,12 +5601,38 @@ declare const CatalogSchema: z.ZodObject<{
|
|
|
5112
5601
|
name: z.ZodString;
|
|
5113
5602
|
url: z.ZodOptional<z.ZodString>;
|
|
5114
5603
|
}, z.core.$strip>>;
|
|
5604
|
+
display: z.ZodOptional<z.ZodObject<{
|
|
5605
|
+
fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
5606
|
+
}, z.core.$strip>>;
|
|
5115
5607
|
plugins: z.ZodArray<z.ZodObject<{
|
|
5116
5608
|
name: z.ZodString;
|
|
5117
5609
|
description: z.ZodOptional<z.ZodString>;
|
|
5118
5610
|
source: z.ZodString;
|
|
5119
5611
|
category: z.ZodOptional<z.ZodString>;
|
|
5120
5612
|
keywords: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
5613
|
+
author: z.ZodOptional<z.ZodObject<{
|
|
5614
|
+
name: z.ZodString;
|
|
5615
|
+
email: z.ZodOptional<z.ZodString>;
|
|
5616
|
+
url: z.ZodOptional<z.ZodString>;
|
|
5617
|
+
}, z.core.$strip>>;
|
|
5618
|
+
downloads: z.ZodOptional<z.ZodNumber>;
|
|
5619
|
+
likes: z.ZodOptional<z.ZodNumber>;
|
|
5620
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
5621
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
5622
|
+
version: z.ZodOptional<z.ZodString>;
|
|
5623
|
+
changelog: z.ZodOptional<z.ZodString>;
|
|
5624
|
+
size: z.ZodOptional<z.ZodNumber>;
|
|
5625
|
+
homepage: z.ZodOptional<z.ZodString>;
|
|
5626
|
+
visibility: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
|
|
5627
|
+
private: "private";
|
|
5628
|
+
public: "public";
|
|
5629
|
+
}>>>;
|
|
5630
|
+
status: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
|
|
5631
|
+
rejected: "rejected";
|
|
5632
|
+
listed: "listed";
|
|
5633
|
+
reviewing: "reviewing";
|
|
5634
|
+
offline: "offline";
|
|
5635
|
+
}>>>;
|
|
5121
5636
|
}, z.core.$strip>>;
|
|
5122
5637
|
}, z.core.$strip>;
|
|
5123
5638
|
declare const RecordSchema: z.ZodObject<{
|
|
@@ -5131,18 +5646,67 @@ declare const RecordSchema: z.ZodObject<{
|
|
|
5131
5646
|
name: z.ZodString;
|
|
5132
5647
|
url: z.ZodOptional<z.ZodString>;
|
|
5133
5648
|
}, z.core.$strip>>;
|
|
5649
|
+
display: z.ZodOptional<z.ZodObject<{
|
|
5650
|
+
fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
5651
|
+
}, z.core.$strip>>;
|
|
5134
5652
|
plugins: z.ZodArray<z.ZodObject<{
|
|
5135
5653
|
name: z.ZodString;
|
|
5136
5654
|
description: z.ZodOptional<z.ZodString>;
|
|
5137
5655
|
source: z.ZodString;
|
|
5138
5656
|
category: z.ZodOptional<z.ZodString>;
|
|
5139
5657
|
keywords: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
5658
|
+
author: z.ZodOptional<z.ZodObject<{
|
|
5659
|
+
name: z.ZodString;
|
|
5660
|
+
email: z.ZodOptional<z.ZodString>;
|
|
5661
|
+
url: z.ZodOptional<z.ZodString>;
|
|
5662
|
+
}, z.core.$strip>>;
|
|
5663
|
+
downloads: z.ZodOptional<z.ZodNumber>;
|
|
5664
|
+
likes: z.ZodOptional<z.ZodNumber>;
|
|
5665
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
5666
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
5667
|
+
version: z.ZodOptional<z.ZodString>;
|
|
5668
|
+
changelog: z.ZodOptional<z.ZodString>;
|
|
5669
|
+
size: z.ZodOptional<z.ZodNumber>;
|
|
5670
|
+
homepage: z.ZodOptional<z.ZodString>;
|
|
5671
|
+
visibility: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
|
|
5672
|
+
private: "private";
|
|
5673
|
+
public: "public";
|
|
5674
|
+
}>>>;
|
|
5675
|
+
status: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
|
|
5676
|
+
rejected: "rejected";
|
|
5677
|
+
listed: "listed";
|
|
5678
|
+
reviewing: "reviewing";
|
|
5679
|
+
offline: "offline";
|
|
5680
|
+
}>>>;
|
|
5140
5681
|
}, z.core.$strip>>;
|
|
5141
5682
|
}, z.core.$strip>;
|
|
5142
5683
|
}, z.core.$strip>;
|
|
5143
5684
|
type MarketplaceEntry = z.infer<typeof EntrySchema>;
|
|
5144
5685
|
type MarketplaceCatalog = z.infer<typeof CatalogSchema>;
|
|
5145
5686
|
type MarketplaceRecord = z.infer<typeof RecordSchema>;
|
|
5687
|
+
/** 这一条在市场那一侧的档口,见 `EntrySchema.status` 上那张四行的表 */
|
|
5688
|
+
type MarketplaceStatus = NonNullable<MarketplaceEntry['status']>;
|
|
5689
|
+
type MarketplaceDisplay = z.infer<typeof DisplaySchema>;
|
|
5690
|
+
/**
|
|
5691
|
+
* 按目录自己声明的白名单,把**没被选中的展示格抹掉**(2026-09-10)。
|
|
5692
|
+
*
|
|
5693
|
+
* ## ⚠️ 它是「抹掉」不是「打个标记」,而那是这个功能唯一说得通的做法
|
|
5694
|
+
*
|
|
5695
|
+
* 另一条路是把 `display` 原样发到每一层去,让 CLI / 网线 / 浏览器各自判一次
|
|
5696
|
+
* 「这一格该不该画」。那条路上「这一格印不印」会有**三个**能推出答案的地方,
|
|
5697
|
+
* 而它们分叉的那天表现是:同一份目录在 `epoch plugin search` 里印着作者、
|
|
5698
|
+
* 在浏览器上不印。判据同 `PluginSearchHit.installable` 为什么不把 `allowRemote`
|
|
5699
|
+
* 透出去 —— **一个问题只该有一个答案**。
|
|
5700
|
+
*
|
|
5701
|
+
* 抹掉之后,下游那一整条链路上现成的规矩(「有就画、没有整格不画」)一个字都不用改,
|
|
5702
|
+
* 而**新增的分支数是零**。这也正是它被放在 {@link searchMarketplaces} 里的理由:
|
|
5703
|
+
* 那是「市场里有什么」这个问题在全仓唯一的出口,CLI / TUI / 网线三条路都从它出来。
|
|
5704
|
+
*
|
|
5705
|
+
* ⚠️ **不碰装那条路**(`resolveMarketplaceRef` 读的是原始记录,不经过这儿):
|
|
5706
|
+
* 一份目录该印什么和它装不装得上是两件事,判据在 {@link MARKETPLACE_DISPLAY_FIELDS}
|
|
5707
|
+
* 那张表上。
|
|
5708
|
+
*/
|
|
5709
|
+
declare function projectEntryForDisplay(entry: MarketplaceEntry, display: MarketplaceDisplay | undefined): MarketplaceEntry;
|
|
5146
5710
|
interface MarketplaceOptions {
|
|
5147
5711
|
/** `marketplacesPath(homeDir)` */
|
|
5148
5712
|
statePath: string;
|
|
@@ -5970,9 +6534,10 @@ interface SystemPromptParams {
|
|
|
5970
6534
|
*
|
|
5971
6535
|
* ## ⚠️ 删了它**不等于** system prompt 不再依赖工具表
|
|
5972
6536
|
*
|
|
5973
|
-
* `PromptBuilder.projectBlock()`
|
|
6537
|
+
* `PromptBuilder.projectBlock()` 里还有五个按工具存在与否开的策略块
|
|
5974
6538
|
* (`isOpenWorldTool` / `enter_plan_mode` / `lsp_diagnostics` /
|
|
5975
|
-
* `ask_user_question
|
|
6539
|
+
* `ask_user_question` / `todo`,五个是 2026-09-08 才算齐的)——
|
|
6540
|
+
* 所以 `loop.ts` 那条**工具名指纹**照样是必须的 ——
|
|
5976
6541
|
* 工具表变了 system prompt 仍然可能要跟着变,只是依赖变少了。
|
|
5977
6542
|
* 判据和一条会红的门禁在 `__tests__/prompt-tool-prose.test.ts`。
|
|
5978
6543
|
*/
|
|
@@ -7247,6 +7812,19 @@ interface GenerateInput {
|
|
|
7247
7812
|
* SDK 只负责单次「请求 → 拿到 tool-call 或文本」。
|
|
7248
7813
|
*/
|
|
7249
7814
|
maxSteps?: number;
|
|
7815
|
+
/**
|
|
7816
|
+
* 中止这一次出站请求,原样交给 AI SDK 的 `abortSignal`。
|
|
7817
|
+
*
|
|
7818
|
+
* ⚠️ **这一格以前整个不存在**,而它的缺席不是「少一个便利功能」:
|
|
7819
|
+
* 一次请求发出去之后没有任何东西能停下它,于是模型进复读环时用户按停止
|
|
7820
|
+
* 没有反应,`repetition-detector` 判出来之后也只能停止读取、出站请求照跑。
|
|
7821
|
+
* 判据全文在 `agent/types.ts` 的 `ProviderGenerateInput.signal` 上。
|
|
7822
|
+
*
|
|
7823
|
+
* 重试那一层**刻意不管它**:signal 一旦 abort,`streamText` 抛的是
|
|
7824
|
+
* `AbortError`,而重试的判据是「这家挂了要不要换一家」—— 用户按了停止
|
|
7825
|
+
* 之后换一家再发一次是最不该做的事。
|
|
7826
|
+
*/
|
|
7827
|
+
signal?: AbortSignal;
|
|
7250
7828
|
/**
|
|
7251
7829
|
* 这一次用哪个 provider(方案 19)。不给 = 配置里的主 provider。
|
|
7252
7830
|
*
|
|
@@ -7436,6 +8014,23 @@ interface ProviderGenerateInput {
|
|
|
7436
8014
|
system?: string;
|
|
7437
8015
|
maxTokens?: number;
|
|
7438
8016
|
maxSteps?: number;
|
|
8017
|
+
/**
|
|
8018
|
+
* 中止这一次**出站请求**。
|
|
8019
|
+
*
|
|
8020
|
+
* ## 为什么必须到这一层
|
|
8021
|
+
*
|
|
8022
|
+
* `RunInput.signal` 一直存在,但 `AgentLoop` 只在**轮次之间**看它,
|
|
8023
|
+
* 这一格以前压根不存在 —— 于是一次请求发出去之后就没有任何东西能停下它。
|
|
8024
|
+
* 后果有两个,都实测过:
|
|
8025
|
+
* 1. 模型进了复读环,用户按停止**没有反应**,得等它把整个输出预算
|
|
8026
|
+
* (某些模型这一格是 384K)吐完或者 provider 自己断;
|
|
8027
|
+
* 2. `repetition-detector` 判出复读之后 `break` 出去只是「我们不再读」,
|
|
8028
|
+
* 出站请求还在跑、token 还在计 —— 检测器等于白做。
|
|
8029
|
+
*
|
|
8030
|
+
* 真 `AbortSignal`(不是 `RunInput.signal` 那个只要 `aborted` 布尔的鸭子类型):
|
|
8031
|
+
* 它要原样交给 AI SDK 的 `abortSignal`,那边需要 `addEventListener`。
|
|
8032
|
+
*/
|
|
8033
|
+
signal?: AbortSignal;
|
|
7439
8034
|
}
|
|
7440
8035
|
interface ProviderGenerateOutput {
|
|
7441
8036
|
text: string;
|
|
@@ -7481,6 +8076,17 @@ interface ProviderGenerateOutput {
|
|
|
7481
8076
|
* 缺席规则同 `usage`:一条都没有时整个缺席,不是空数组。
|
|
7482
8077
|
*/
|
|
7483
8078
|
warnings?: ProviderWarning[];
|
|
8079
|
+
/**
|
|
8080
|
+
* `finishReason === 'looping'` 时给用户看的那句话里要填的数
|
|
8081
|
+
* (「最后 N 个字符里只有约 X% 的片段不重复」)。
|
|
8082
|
+
*
|
|
8083
|
+
* 为什么要一格而不是让循环自己算:判定发生在 `turn.ts`,它掐掉之后
|
|
8084
|
+
* 检测器就跟着那次请求一起没了,循环手上只有已经产出的那段文本 ——
|
|
8085
|
+
* 而那段文本的比例**不等于**开火那一刻窗口里的比例(窗口只看尾巴)。
|
|
8086
|
+
*
|
|
8087
|
+
* 其余 finishReason 下缺席(缺席规则同 `usage`)。
|
|
8088
|
+
*/
|
|
8089
|
+
loopingInfo?: string;
|
|
7484
8090
|
}
|
|
7485
8091
|
/** AgentLoop 需要的 provider 能力 */
|
|
7486
8092
|
interface AgentProvider {
|
|
@@ -7959,6 +8565,33 @@ interface AgentConfig {
|
|
|
7959
8565
|
* 会红的门禁:`runtime/__tests__/compliance-wiring.test.ts`。
|
|
7960
8566
|
*/
|
|
7961
8567
|
compliance?: ComplianceEngine;
|
|
8568
|
+
/**
|
|
8569
|
+
* 「这个会话还有多少项 TODO 没做完」的读点(2026-09-08,收工闸门那一半)。
|
|
8570
|
+
*
|
|
8571
|
+
* 给了之后,模型不再调工具、清单里还有没做完的条目时,循环会注一句
|
|
8572
|
+
* 「还有 N 项没做完」把它踢回去(每 run 最多一次)。不给 = 没有这道闸门,
|
|
8573
|
+
* 行为与改动前逐字节相同 —— 插入宿主和全部既有用例走的都是那一条。
|
|
8574
|
+
*
|
|
8575
|
+
* ## 给**函数**不给数,理由同 `approvedPlan` / `role`
|
|
8576
|
+
*
|
|
8577
|
+
* 这个数在一次 run 里**每一步都在变**(模型每做完一条就 `todo` 替换一次),
|
|
8578
|
+
* 快照等于永远拿到「run 开始那一刻」的清单 —— 而那一刻常常还没落任何条目。
|
|
8579
|
+
* 真正该读它的是「模型想收工的那一轮」,只有现问才拿得到。
|
|
8580
|
+
*
|
|
8581
|
+
* ## `sessionId` 走入参,不走闭包
|
|
8582
|
+
*
|
|
8583
|
+
* 子 agent 是**另一个** sessionId(`delegate_task` 派出去的那个任务自己记一笔,
|
|
8584
|
+
* 见 `tools/builtin/delegate.ts`)。闭包的话,派活的父会话有清单、子任务那一侧
|
|
8585
|
+
* 读到的也是**父的**清单 —— 而子任务确实只被派了几件事,它若拿「父还有 97
|
|
8586
|
+
* 件事没完」来给自己收工,就是最糟的一种假结案。判据同
|
|
8587
|
+
* `backgroundTasks` 那句(闭包会把「这个会话」和「读到的会话」劈开)。
|
|
8588
|
+
*
|
|
8589
|
+
* ⚠️ **装配层的每一处 `new AgentLoop` 都要填**,子 agent 那条也要 ——
|
|
8590
|
+
* 漏填一处的表现是「主会话被闸门护住了、派出去的子任务照样做 3 个就收工」,
|
|
8591
|
+
* 而这两条路在今天都会被批成行径是「智能体偷懒」。会红的门禁:
|
|
8592
|
+
* `runtime/__tests__/todo-gate-wiring.test.ts`。
|
|
8593
|
+
*/
|
|
8594
|
+
pendingTodos?: (sessionId: string) => number;
|
|
7962
8595
|
}
|
|
7963
8596
|
/** 历史里的一条。`parts` 存在时 `content` 是它的文本投影(见 EpochMessage) */
|
|
7964
8597
|
interface HistoryEntry {
|
|
@@ -9082,6 +9715,29 @@ declare function formatUsd(usd: number): string;
|
|
|
9082
9715
|
* 可选维度加完仍是 0 就不写进结果 —— 保住「0 是真的零,undefined 是不知道」:
|
|
9083
9716
|
* 两轮都没缓存命中,累计里就不该冒出一个 `cacheHitTokens: 0` 让人以为
|
|
9084
9717
|
* 这个 provider 支持缓存只是没命中。
|
|
9718
|
+
*
|
|
9719
|
+
* ## ⚠️ `totalTokens` **不是**可加的维度,别照着上面三项写
|
|
9720
|
+
*
|
|
9721
|
+
* 上面三项缺席当 0 加是对的(0 是加法的单位元);`totalTokens` 不是,它是一个
|
|
9722
|
+
* **总量**。`(a.totalTokens ?? 0) + (b.totalTokens ?? 0)` 在「一边报了、另一边
|
|
9723
|
+
* 没报」时收到的只有报了的那一份,而 `inputTokens` / `outputTokens` 两侧是加全
|
|
9724
|
+
* 了的 —— 于是这份累计**自相矛盾**:`totalTokens < promptTokens + outputTokens`。
|
|
9725
|
+
*
|
|
9726
|
+
* 这一档不是假想:`toTokenUsage` 明确放行了「两个总量都在、`totalTokens` 缺席」
|
|
9727
|
+
* 的 usage(OpenAI 兼容端点不带 `stream_options` 的那一家就这样),而同一段会话
|
|
9728
|
+
* 里换 provider(降级、或压缩那一发走别的模型)就会把两种 usage 加到一起。
|
|
9729
|
+
*
|
|
9730
|
+
* 症状有两层,**第二层不是显示问题**:
|
|
9731
|
+
*
|
|
9732
|
+
* 1. 屏幕上「共 X token」比旁边 `↑ + ↓` 还小(两处都读 `totalUsageTokens()`,
|
|
9733
|
+
* 而它优先信 `totalTokens`);
|
|
9734
|
+
* 2. `budget.maxTokens` 那道闸门读的是同一个数(`budget-guard.ts` 的
|
|
9735
|
+
* `sessionBreach()`),偏小 = **上限拦不住**,多跑的那几轮是真花钱的。
|
|
9736
|
+
*
|
|
9737
|
+
* 所以没报的那一侧按我们自己的口径折算一份(`totalUsageTokens()` 的兜底那一支,
|
|
9738
|
+
* 对那一侧来说是精确值),再相加。两边都没报时仍然整个不写 —— 那时
|
|
9739
|
+
* `totalUsageTokens()` 自己算出来的和这里能算出来的是同一个数,凭空多一个字段
|
|
9740
|
+
* 只会让「provider 报过」和「我们替它算的」变得分不出来。
|
|
9085
9741
|
*/
|
|
9086
9742
|
declare function addUsage(a: TokenUsage, b: TokenUsage): TokenUsage;
|
|
9087
9743
|
/**
|
|
@@ -9698,6 +10354,19 @@ declare function hasProviderCredentials(homeDir?: string): boolean;
|
|
|
9698
10354
|
* 所以丢弃也不会动到用户文件)。
|
|
9699
10355
|
*/
|
|
9700
10356
|
|
|
10357
|
+
/**
|
|
10358
|
+
* 自动压缩的内置阈值 —— 提示词占到上下文窗口的几成时开始压。
|
|
10359
|
+
*
|
|
10360
|
+
* **默认值的单一真源就是这一行**(本文件头那句话对它同样成立)。
|
|
10361
|
+
* `ContextCompressor` 直接 `new` 出来、没给 `threshold` 时也回落到它,
|
|
10362
|
+
* 走的是 import 而不是在那边再写一个 `0.5` —— 两处各写一份的话,
|
|
10363
|
+
* 调了这个数之后「配置里读到的默认值」和「引擎真的在用的默认值」会分叉,
|
|
10364
|
+
* 而设置页印的恰好是前者。
|
|
10365
|
+
*
|
|
10366
|
+
* ⚠️ 改这个数对**所有没配过这个键的人**生效,是一次用户能感知的行为变更
|
|
10367
|
+
* (压缩来得更早或更晚),要写 changeset。
|
|
10368
|
+
*/
|
|
10369
|
+
declare const DEFAULT_COMPRESSION_THRESHOLD = 0.5;
|
|
9701
10370
|
declare const EpochConfigSchema: z.ZodObject<{
|
|
9702
10371
|
provider: z.ZodPrefault<z.ZodObject<{
|
|
9703
10372
|
type: z.ZodDefault<z.ZodEnum<{
|
|
@@ -9803,6 +10472,11 @@ declare const EpochConfigSchema: z.ZodObject<{
|
|
|
9803
10472
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
9804
10473
|
threshold: z.ZodDefault<z.ZodNumber>;
|
|
9805
10474
|
}, z.core.$strip>>;
|
|
10475
|
+
memory: z.ZodPrefault<z.ZodObject<{
|
|
10476
|
+
memoryCharLimit: z.ZodDefault<z.ZodInt>;
|
|
10477
|
+
userCharLimit: z.ZodDefault<z.ZodInt>;
|
|
10478
|
+
indexCharLimit: z.ZodDefault<z.ZodInt>;
|
|
10479
|
+
}, z.core.$strip>>;
|
|
9806
10480
|
artifacts: z.ZodPrefault<z.ZodObject<{
|
|
9807
10481
|
maxAgeDays: z.ZodDefault<z.ZodInt>;
|
|
9808
10482
|
maxTotalBytes: z.ZodDefault<z.ZodInt>;
|
|
@@ -10149,7 +10823,7 @@ declare function isSettingWriteLayer(value: string): value is SettingWriteLayer;
|
|
|
10149
10823
|
* 安全中心指两件事(「新会话从哪一档起」vs「这个会话此刻哪一档」),
|
|
10150
10824
|
* 而那正是决定 20 ④ 拆开的那个歧义 —— 记住上一次那一档没有把这个歧义请回来。
|
|
10151
10825
|
*/
|
|
10152
|
-
declare const SETTING_WRITE_KEYS: readonly ["model", "maxTurns", "models.utility", "fallback.model", "contextLength", "compression.enabled", "compression.threshold", "budget.maxCostUsd", "budget.maxTokens", "budget.warnAtPercent", "budget.onUnknownPricing", "permission"];
|
|
10826
|
+
declare const SETTING_WRITE_KEYS: readonly ["model", "maxTurns", "models.utility", "fallback.model", "contextLength", "compression.enabled", "compression.threshold", "memory.memoryCharLimit", "memory.userCharLimit", "memory.indexCharLimit", "budget.maxCostUsd", "budget.maxTokens", "budget.warnAtPercent", "budget.onUnknownPricing", "permission"];
|
|
10153
10827
|
type SettingWriteKey = (typeof SETTING_WRITE_KEYS)[number];
|
|
10154
10828
|
/** 这个键写得进去吗。名单就是 {@link SETTING_WRITE_KEYS} 本身,别在别处抄一份字面量 */
|
|
10155
10829
|
declare function isWritableSettingKey(value: string): value is SettingWriteKey;
|
|
@@ -10473,24 +11147,107 @@ declare function loadKeybindings({ path, defaults }: LoadKeybindingsOptions): Lo
|
|
|
10473
11147
|
/**
|
|
10474
11148
|
* 记忆管理器 — 文件驱动 + SQLite 索引双存储。
|
|
10475
11149
|
*
|
|
10476
|
-
* 参考 Hermes tools/memory_tool.py(1240 行)。
|
|
10477
11150
|
* 核心设计:
|
|
10478
11151
|
* 1. MEMORY.md / USER.md 文件是主存储
|
|
10479
11152
|
* 2. SQLite 是搜索索引(FTS5 + sqlite-vec)
|
|
10480
11153
|
* 3. 会话级冻结快照,保护 prompt cache
|
|
10481
11154
|
* 4. 字符配额 + 超限压缩提示(而非直接拒绝)
|
|
10482
11155
|
* 5. 注入检测
|
|
11156
|
+
*
|
|
11157
|
+
* ---
|
|
11158
|
+
*
|
|
11159
|
+
* # 2026-09-10:进 prompt 的从「全文」换成「索引」
|
|
11160
|
+
*
|
|
11161
|
+
* ## 改之前是什么样,以及为什么它把两件事焊死了
|
|
11162
|
+
*
|
|
11163
|
+
* 原来 `initialize()` 把**整个记忆库的正文**渲染进 system prompt(`renderBlock()`
|
|
11164
|
+
* 把每一条 `§` 拼起来)。参考的是 Hermes(`tools/memory_tool.py`,它今天仍是
|
|
11165
|
+
* 这个形状)。后果是「能存多少」和「每轮烧多少 token」**是同一个数**:
|
|
11166
|
+
* 想多记一点,就得每一轮都为它付钱。
|
|
11167
|
+
*
|
|
11168
|
+
* 于是那两个配额被钉在 `2200 / 1375`(连数字都是从 Hermes 抄的)好几个月,
|
|
11169
|
+
* 而用户的原话是「memory 好像只有 2000 字,太少了」。在旧结构下这个抱怨
|
|
11170
|
+
* **没有便宜的解法** —— 调大就是每轮变贵。
|
|
11171
|
+
*
|
|
11172
|
+
* ## 改之后:目录进 prompt,正文按需取
|
|
11173
|
+
*
|
|
11174
|
+
* 形状对齐 codex(`codex-rs/ext/memories/`):那边 `~/.codex/memories/` 里的
|
|
11175
|
+
* 文件数量不设上限,进 developer instructions 的只有一份摘要(它那个常量叫
|
|
11176
|
+
* `MEMORY_TOOL_DEVELOPER_INSTRUCTIONS_SUMMARY_TOKEN_LIMIT`,2500 tokens),
|
|
11177
|
+
* 正文靠 `memories.list` / `read` / `search` 三个工具按需取。
|
|
11178
|
+
*
|
|
11179
|
+
* epoch 这边**检索那一半本来就修好了**,所以这一轮做的比看上去小:
|
|
11180
|
+
*
|
|
11181
|
+
* - `search()` 是真的 BM25(FTS5,见 `db.ts`)
|
|
11182
|
+
* - `prefetch()` 每轮拿用户输入检索一次,塞进 `<memory-recall>`
|
|
11183
|
+
* (`agent/prompt.ts`,走 messages 那一侧)
|
|
11184
|
+
*
|
|
11185
|
+
* 缺的只有两样,这一轮补上:**system prompt 里换成索引**({@link renderIndexBlock}),
|
|
11186
|
+
* 以及**一个能按 id 取全文的动作**({@link read})。
|
|
11187
|
+
*
|
|
11188
|
+
* ## ⚠️ 空库时索引块必须是**空串**,这不是优化
|
|
11189
|
+
*
|
|
11190
|
+
* `agent/prompt.ts` 把这个块 push 进 system prompt,而 system prompt 全文进
|
|
11191
|
+
* eval 的新鲜度指纹(`evals/harness/fingerprint.ts`)。空库渲染成空串,
|
|
11192
|
+
* 是 34 段录像在这一轮里**不因为 system prompt 而**作废的唯一原因
|
|
11193
|
+
* (工具描述那一侧另算,见 `tools/builtin/memory.ts`)。
|
|
11194
|
+
* 改这个函数时先想一遍「库是空的时候它返回什么」。
|
|
10483
11195
|
*/
|
|
10484
11196
|
|
|
10485
11197
|
declare class MemoryManager {
|
|
10486
11198
|
private db;
|
|
10487
11199
|
private config;
|
|
10488
11200
|
private memDir;
|
|
10489
|
-
/**
|
|
11201
|
+
/**
|
|
11202
|
+
* 冻结快照 —— 会话初始化时构建,整个会话不变 [Hermes]。
|
|
11203
|
+
*
|
|
11204
|
+
* ⚠️ **2026-09-10 起它装的是索引不是正文**(文件头那一节)。冻结这件事没变,
|
|
11205
|
+
* 变的是冻的是什么:冻正文是为了保 prefix cache,冻索引除了保 cache 还多一层
|
|
11206
|
+
* 作用 —— 模型手上那份 id 表在一个会话里不会动,于是它引用 `m:a3f1c2` 时
|
|
11207
|
+
* 指的一定是它当初看到的那一条。
|
|
11208
|
+
*/
|
|
10490
11209
|
private snapshot;
|
|
11210
|
+
/**
|
|
11211
|
+
* 短 id → 条目。**这一份是活的,不跟着快照冻**。
|
|
11212
|
+
*
|
|
11213
|
+
* 两者不同步是刻意的:快照冻住「模型看得到的目录」,这一份答「这个 id 现在
|
|
11214
|
+
* 还指着什么」。会话中途新写的条目立刻 `read` 得到(它不在冻结的索引里,
|
|
11215
|
+
* 但模型刚写完自己知道 id);被改掉的条目老 id 会落进
|
|
11216
|
+
* {@link MemoryReadResult.missing} —— 那是实话,那条内容确实不在了。
|
|
11217
|
+
*
|
|
11218
|
+
* id 从**内容哈希**来而不是从位置来,正是为了这里:删掉第 3 条不会让第 4 条
|
|
11219
|
+
* 之后所有 id 集体平移,而那种平移会让模型手上那份索引静默指错条目。
|
|
11220
|
+
*/
|
|
11221
|
+
private ids;
|
|
11222
|
+
/** 上面那张表的反向索引(`target\0content` → id),渲染索引时按内容反查用 */
|
|
11223
|
+
private idByContent;
|
|
10491
11224
|
/** 当前会话是否已初始化 */
|
|
10492
11225
|
private initialized;
|
|
10493
|
-
/**
|
|
11226
|
+
/**
|
|
11227
|
+
* 本轮 consolidation **白撞**次数。撞满 {@link MAX_CONSOLIDATION_FAILURES_PER_TURN}
|
|
11228
|
+
* 就不再给指引,改成一句「别再试了」。
|
|
11229
|
+
*
|
|
11230
|
+
* ## ⚠️ 它数的是「白撞了几次」,不是「试了几次」
|
|
11231
|
+
*
|
|
11232
|
+
* 这个区别就是用户 2026-09-10 那张截图:
|
|
11233
|
+
*
|
|
11234
|
+
* > 记忆库满了(3 次合并机会已用完),但关键信息已经落在 RUNBOOK.md 里
|
|
11235
|
+
*
|
|
11236
|
+
* 一个**谨慎**的模型会一条条腾地方 —— 删一条、试一下够不够、不够再删一条。
|
|
11237
|
+
* 而原来只有 `add` / `replace` **成功**时才重置,`remove` 成功不重置,于是:
|
|
11238
|
+
*
|
|
11239
|
+
* ```
|
|
11240
|
+
* add(失败1) → remove → add(失败2) → remove → add(失败3) → remove → add(失败4) → 叫停
|
|
11241
|
+
* ```
|
|
11242
|
+
*
|
|
11243
|
+
* 它每一步都在真的腾空间,却被记成四次失败,最后被自己的安全阀打死。
|
|
11244
|
+
* **越谨慎越容易撞**:一次性删五条的反而没事。上限本身是对的
|
|
11245
|
+
* (防模型无限重试同一个 `add`),错的是口径。
|
|
11246
|
+
*
|
|
11247
|
+
* 所以**任何一次让库变小 / 变整齐的操作都重置它**:`add` 成功、`replace`
|
|
11248
|
+
* 成功、`remove` 成功。剩下那一档 —— 反复 `add` 同一个装不下的东西而中间
|
|
11249
|
+
* 什么都没干 —— 才是它要拦的。
|
|
11250
|
+
*/
|
|
10494
11251
|
private consolidationFailures;
|
|
10495
11252
|
/** 上次审查发现的问题(由 MemoryReviewer 写入) */
|
|
10496
11253
|
reviewIssues: Array<{
|
|
@@ -10499,12 +11256,33 @@ declare class MemoryManager {
|
|
|
10499
11256
|
message: string;
|
|
10500
11257
|
suggestion?: string;
|
|
10501
11258
|
}>;
|
|
10502
|
-
|
|
11259
|
+
/**
|
|
11260
|
+
* @param config 三个配额,来自 `EpochConfig.memory`(runtime 的 `services.ts` 递进来)。
|
|
11261
|
+
* **按字段合并到默认值上**,不是整份替换 —— 用户只在 yaml 里写了
|
|
11262
|
+
* `memoryCharLimit` 时,另外两个该回落到内置默认,而不是变成 `undefined`
|
|
11263
|
+
* 然后在 `getBudget()` 里算出 `NaN%`。
|
|
11264
|
+
*
|
|
11265
|
+
* 不给 = 三个都走默认(真源在 `config/schema.ts`)。2026-09-10 之前这个参数
|
|
11266
|
+
* 压根不存在,于是 `MemoryConfig` 这个类型有、却没有任何人给得出非默认值 ——
|
|
11267
|
+
* 用户抱怨的「设置里改不了」就是这一格。
|
|
11268
|
+
*/
|
|
11269
|
+
constructor(dbPath?: string, memDir?: string, config?: Partial<MemoryConfig>);
|
|
10503
11270
|
initialize(_sessionId: string): Promise<string>;
|
|
10504
11271
|
prefetch(userQuery: string): Promise<string>;
|
|
10505
11272
|
sync(_userMessage: string, _assistantResponse: string): Promise<void>;
|
|
10506
11273
|
finalize(): Promise<void>;
|
|
10507
11274
|
reloadFromDisk(): Promise<void>;
|
|
11275
|
+
/**
|
|
11276
|
+
* 重建 短 id → 条目 的映射。
|
|
11277
|
+
*
|
|
11278
|
+
* id = `<前缀>:<内容 sha256 的前 N 位十六进制>`。前缀 `m` / `u` 分开两个库,
|
|
11279
|
+
* 于是**同一份内容同时存在两个库里也不会撞**(那是合法状态:「用户用 pnpm」
|
|
11280
|
+
* 既可以是画像也可以是项目知识)。
|
|
11281
|
+
*
|
|
11282
|
+
* 冲突时按 4 位一档加长,而**只加长撞上的那一个** —— 全表统一加长的话,
|
|
11283
|
+
* 加一条新记忆可能让**所有**老 id 变样,而模型手上那份索引是冻结的。
|
|
11284
|
+
*/
|
|
11285
|
+
private assignIds;
|
|
10508
11286
|
/**
|
|
10509
11287
|
* 把某个 target 的内容同步成 `desired`,**保留仍存在条目的元数据**。
|
|
10510
11288
|
*
|
|
@@ -10512,6 +11290,14 @@ declare class MemoryManager {
|
|
|
10512
11290
|
* accessCount / createdAt 全部归零,schema 里那几个字段等于白设。
|
|
10513
11291
|
*/
|
|
10514
11292
|
private syncTarget;
|
|
11293
|
+
/**
|
|
11294
|
+
* 落盘。**顺带重建 id 表** —— 这个方法是 add / replace / remove 三条写路径
|
|
11295
|
+
* 唯一的汇合点,挂在这儿就不会出现「新加了一条记忆,同一轮里 `read` 不到」。
|
|
11296
|
+
*
|
|
11297
|
+
* ⚠️ 重建的是 {@link ids}(活的),**不动 {@link snapshot}**(冻的)。
|
|
11298
|
+
* 顺手把快照也刷了的话,一次写记忆就会改掉 system prompt ——
|
|
11299
|
+
* prefix cache 当场作废,而那正是快照冻结要挡的事。
|
|
11300
|
+
*/
|
|
10515
11301
|
flushToDisk(): Promise<void>;
|
|
10516
11302
|
/** 渲染成可被 readFile 原样解析回来的格式(多行条目也不会散) */
|
|
10517
11303
|
private renderFile;
|
|
@@ -10521,9 +11307,28 @@ declare class MemoryManager {
|
|
|
10521
11307
|
* score 是真实的 BM25 相关度(越大越相关),原来恒为 1——
|
|
10522
11308
|
* 上层拿它排序等于没排。命中的条目会记一次访问,
|
|
10523
11309
|
* 让 accessCount 真的反映使用情况。
|
|
11310
|
+
*
|
|
11311
|
+
* ⚠️ **返回的 `id` 是索引里那个短 id,不是 DB 的 UUID**(2026-09-10 改)。
|
|
11312
|
+
* 这一条上层看得见:模型拿搜索结果去 `read` / 对照索引时,两处的 id 必须是
|
|
11313
|
+
* 同一套词。发 UUID 出去等于给了它一个在别处一次也用不上的标识符 ——
|
|
11314
|
+
* 而它会照着用,然后 `read` 一律 `missing`。
|
|
11315
|
+
*
|
|
11316
|
+
* 短 id 反查不到时(`assignIds()` 还没跑过)**回落到 UUID 而不是丢掉这一条**:
|
|
11317
|
+
* 少一条搜索结果是静默的错误答案,多一个认不出的 id 只是一次 `missing`。
|
|
10524
11318
|
*/
|
|
10525
11319
|
search(query: string, limit?: number): Promise<MemorySearchResult[]>;
|
|
10526
11320
|
keywordSearch(query: string, limit?: number): Promise<MemorySearchResult[]>;
|
|
11321
|
+
/**
|
|
11322
|
+
* 按索引里的短 id 取全文(2026-09-10 新增,见文件头)。
|
|
11323
|
+
*
|
|
11324
|
+
* ⚠️ **认不出的 id 走 `missing` 而不是被跳过。** 模型会编 id(或者引用上个会话
|
|
11325
|
+
* 那份索引里的),静默少返回一条的话它拿到的是一份看起来完整、实际缺一块的
|
|
11326
|
+
* 答案,而它没有任何办法发现这件事。
|
|
11327
|
+
*
|
|
11328
|
+
* 命中的条目记一次访问 —— 于是「被 read 过」也算热度,下一个会话的索引里
|
|
11329
|
+
* 它更靠前(判据在 {@link renderIndexBlock} 的排序那一段)。
|
|
11330
|
+
*/
|
|
11331
|
+
read(ids: readonly string[]): Promise<MemoryReadResult>;
|
|
10527
11332
|
/** 获取所有条目(供后台审查使用) */
|
|
10528
11333
|
getAllEntries(): Array<{
|
|
10529
11334
|
content: string;
|
|
@@ -10538,7 +11343,43 @@ declare class MemoryManager {
|
|
|
10538
11343
|
semanticSearch(query: string, limit?: number): Promise<MemorySearchResult[]>;
|
|
10539
11344
|
add(target: MemoryTarget, content: string): Promise<MemoryWriteResult>;
|
|
10540
11345
|
replace(target: MemoryTarget, oldText: string, content: string): Promise<MemoryWriteResult>;
|
|
10541
|
-
|
|
11346
|
+
/**
|
|
11347
|
+
* 删一条。`oldText` 可以是**全文**,也可以是索引里那个**短 id**(见 {@link locate})。
|
|
11348
|
+
*
|
|
11349
|
+
* 返回删没删掉 —— 原来固定返回 `void`,于是「id 拼错了」和「真的删了」
|
|
11350
|
+
* 在调用方那里长得一模一样,模型会以为腾出了地方然后继续撞墙。
|
|
11351
|
+
*/
|
|
11352
|
+
remove(target: MemoryTarget, oldText: string): Promise<boolean>;
|
|
11353
|
+
/**
|
|
11354
|
+
* 按「全文」或「索引里的短 id」定位一条记忆。
|
|
11355
|
+
*
|
|
11356
|
+
* ## 为什么要认 id(2026-09-10)
|
|
11357
|
+
*
|
|
11358
|
+
* 索引化之后,模型在 prompt 里看到的只有**首行摘要**(截断到 80 字符),
|
|
11359
|
+
* 而 `replace` / `remove` 原来走的是 `WHERE content = ?` —— **全文精确相等**。
|
|
11360
|
+
* 两者对不上:**我们只发布了摘要,却要求全文**。于是「照着屏幕上看得见的
|
|
11361
|
+
* 东西去合并」这条最自然的路径必然 `Entry not found`。
|
|
11362
|
+
*
|
|
11363
|
+
* ⚠️ **它不是一个「不修就必死」的回归,别照那个力度去理解。** 2026-09-10
|
|
11364
|
+
* 拿真 key 打过 A/B(3 个场景 × 改动前后 × 各 3 发,DeepSeek):**不认 id 的
|
|
11365
|
+
* 那一侧也 9/9 成功** —— 模型会自己先 `read` 一遍拿全文,之后全文匹配就成立了。
|
|
11366
|
+
* `read` 和索引是同一轮加的,所以那条死路从来没有以「不可恢复」的形态存在过。
|
|
11367
|
+
*
|
|
11368
|
+
* 认 id 的价值是把它从「先 read 再匹配」缩成「一步」,并且让**只看索引**
|
|
11369
|
+
* 这条路径也成立。这是补齐操作面,不是抢救。
|
|
11370
|
+
*
|
|
11371
|
+
* ⚠️ 先试 id 再试全文,顺序不能反:一条内容恰好长得像 `m:abc123` 的记忆
|
|
11372
|
+
* 理论上存在,但那时按 id 解释才是**模型的本意**(它手上的 id 就长这样)。
|
|
11373
|
+
*/
|
|
11374
|
+
private locate;
|
|
11375
|
+
/**
|
|
11376
|
+
* 「没找到」时**告诉模型下一步干什么**,而不是只说没找到。
|
|
11377
|
+
*
|
|
11378
|
+
* 一句光秃秃的 `Entry not found` 会让模型原地重试同一个错的 `old_text`,
|
|
11379
|
+
* 而它重试几次就撞上 consolidation 上限。绝大多数情况下它错在
|
|
11380
|
+
* **拿索引里的摘要当全文**,所以这句话要直接点破那一点。
|
|
11381
|
+
*/
|
|
11382
|
+
private notFoundHint;
|
|
10542
11383
|
getBudget(): {
|
|
10543
11384
|
memory: BudgetInfo;
|
|
10544
11385
|
user: BudgetInfo;
|
|
@@ -10559,11 +11400,53 @@ declare class MemoryManager {
|
|
|
10559
11400
|
* 项目约定来说并不宽裕,原来的做法会把合法长条目直接吞掉。
|
|
10560
11401
|
*/
|
|
10561
11402
|
private scanInjection;
|
|
10562
|
-
/**
|
|
10563
|
-
|
|
10564
|
-
|
|
10565
|
-
|
|
11403
|
+
/**
|
|
11404
|
+
* 一条条目在索引里长什么样。摘要取**首行**并截断到
|
|
11405
|
+
* {@link INDEX_SUMMARY_CHARS}。
|
|
11406
|
+
*
|
|
11407
|
+
* 取首行而不是前 N 字符:条目是「一条一个事实」,第一行基本就是那句结论,
|
|
11408
|
+
* 而横跨换行去截会把下一行的开头黏上来,读起来像一句破句。
|
|
11409
|
+
*/
|
|
11410
|
+
private indexEntries;
|
|
11411
|
+
/**
|
|
11412
|
+
* 渲染进 system prompt 的**索引块**(2026-09-10 起替代原来的全文块)。
|
|
11413
|
+
*
|
|
11414
|
+
* ## 空库返回空串 —— 这一条是硬约束
|
|
11415
|
+
*
|
|
11416
|
+
* 判据在文件头最后一节:这个块的返回值进 system prompt,而 system prompt
|
|
11417
|
+
* 全文进 eval 新鲜度指纹。改这个函数时先答「库是空的时候它返回什么」。
|
|
11418
|
+
*
|
|
11419
|
+
* ## 装不下的时候丢谁
|
|
11420
|
+
*
|
|
11421
|
+
* 按「用得多的留下」排(`accessCount` 降序,同票看 `lastAccessedAt`),
|
|
11422
|
+
* 取到装不下为止 —— 那两个字段 `db.ts` 一直在维护,而 `search()` 命中时会
|
|
11423
|
+
* `markAccessed()`,所以「用得多」是真的使用情况,不是猜的。
|
|
11424
|
+
*
|
|
11425
|
+
* ⚠️ **挑完之后按 position 重排再印**。挑选顺序是「谁重要」,展示顺序是
|
|
11426
|
+
* 「文件里的顺序」—— 两者混成一个的话,用户在 `MEMORY.md` 里看到的顺序和
|
|
11427
|
+
* 模型看到的顺序不一样,而排查「模型为什么没用那条记忆」时人是对着文件看的。
|
|
11428
|
+
*
|
|
11429
|
+
* ⚠️ 被挤掉的部分**在块尾如实说有几条**,并指向 `search`。静默截断是这里
|
|
11430
|
+
* 最不该干的事:模型会把「我看到的」当成「全部」,然后理直气壮地说
|
|
11431
|
+
* 「记忆里没有这件事」。
|
|
11432
|
+
*/
|
|
11433
|
+
private renderIndexBlock;
|
|
11434
|
+
/** 索引里的一行:`m:a1b2c3 摘要 (412 chars)` */
|
|
11435
|
+
private indexLine;
|
|
10566
11436
|
/** 构建超限压缩提示 [Hermes] */
|
|
11437
|
+
/**
|
|
11438
|
+
* 配额满时交给模型的指引。
|
|
11439
|
+
*
|
|
11440
|
+
* ## ⚠️ 这段话必须给出一条**在索引架构下真的走得通**的操作序列
|
|
11441
|
+
*
|
|
11442
|
+
* 上一版写的是「use replace() to combine or shorten existing entries」外加一个
|
|
11443
|
+
* 抄全文的例子。索引化之后那是一条**死路**:模型手上只有摘要,`old_text` 拼不出来
|
|
11444
|
+
* (判据全文在 {@link locate})。它照着做 → `Entry not found` → 重试 → 撞上
|
|
11445
|
+
* {@link MAX_CONSOLIDATION_FAILURES_PER_TURN} → 只好说「记忆库满了,合并机会用完」。
|
|
11446
|
+
*
|
|
11447
|
+
* 所以现在给的是**按 id 走**的三步,并且把最近几条 id 直接列出来 ——
|
|
11448
|
+
* 让模型不必先去猜、也不必多跑一趟 `search`。
|
|
11449
|
+
*/
|
|
10567
11450
|
private buildConsolidateHint;
|
|
10568
11451
|
}
|
|
10569
11452
|
|
|
@@ -12188,8 +13071,8 @@ declare const MAX_AUDIT_ENTRIES = 500;
|
|
|
12188
13071
|
*
|
|
12189
13072
|
* | 级别 | 意图 |
|
|
12190
13073
|
* | ------------- | -------------------------------------------------- |
|
|
12191
|
-
* | `bypass` | 全放行 —— 但**挡不住第 1
|
|
12192
|
-
* | `auto` | 信任 agent
|
|
13074
|
+
* | `bypass` | 全放行 —— 但**挡不住第 1 层那两条 deny**,那层在前面 |
|
|
13075
|
+
* | `auto` | 信任 agent:这一档自己不拦,边界全在第 1 层 |
|
|
12193
13076
|
* | `plan` | 只读:写入 / 命令 / 网络 / 执行代码一律拒 |
|
|
12194
13077
|
* | `acceptEdits` | 工作区内读写免确认,工作区外和写命令确认 |
|
|
12195
13078
|
* | `default` | 只读操作免确认,其余一律确认 |
|
|
@@ -12380,7 +13263,9 @@ declare function matchRuleLists(rules: CompiledRules, operation: Operation, flav
|
|
|
12380
13263
|
*
|
|
12381
13264
|
* check() 分三层,顺序即安全语义:
|
|
12382
13265
|
* 1. 安全底线(危险命令 / 敏感路径 / 混淆构造)—— 任何级别、任何模式都生效,
|
|
12383
|
-
* **不可**被 headless
|
|
13266
|
+
* **不可**被 headless 预授权覆盖。⚠️ 前两条直接 deny;第三条是「要人确认」,
|
|
13267
|
+
* 而「问」在 `bypass` 和非交互下问不出来 —— 那两种现场怎么塌成一个结论,
|
|
13268
|
+
* 判据全文在 {@link PermissionManager.settleUnaskable} 上
|
|
12384
13269
|
* 2. 策略规则 + 审批缓存 + 权限级别 —— 得出 allow / deny / ask_user
|
|
12385
13270
|
* 3. headless 预授权 —— 只能把 ask_user 变成放行,
|
|
12386
13271
|
* 永远不能把第 1、2 层的 deny 变成放行
|
|
@@ -12577,6 +13462,111 @@ declare class PermissionManager implements PermissionManager$1 {
|
|
|
12577
13462
|
check(operation: Operation): PermissionDecision;
|
|
12578
13463
|
/** 三层判定的本体。**每个出口都必须带原因码**,见文件头 */
|
|
12579
13464
|
private decide;
|
|
13465
|
+
/**
|
|
13466
|
+
* 安全底线里那条「要人确认」的判定 —— **问不出来的时候它塌成什么**(2026-09-10)。
|
|
13467
|
+
*
|
|
13468
|
+
* 返回 null = 问得出来,照原样弹给用户。
|
|
13469
|
+
*
|
|
13470
|
+
* ## 这一层要守的不变量:**「不问」这一档下没有任何东西可以塌成「问」**
|
|
13471
|
+
*
|
|
13472
|
+
* 两家参照实现都把它写成纪律,而 epoch 此前只守住了一半:
|
|
13473
|
+
*
|
|
13474
|
+
* - Hermes 靠顺序 —— `approval_floors.py` 的 docstring 第一句是
|
|
13475
|
+
* 「decisions that never reach a prompt」,floor 里只有 hardline 灾难命令、
|
|
13476
|
+
* `sudo -S` 灌密码、用户自己写的 deny 规则,**一个 ask 形状的出口都没有**;
|
|
13477
|
+
* 所有会弹的判定都排在 `_yolo_active()` 检查之后(`tools/approval.py`)。
|
|
13478
|
+
* - Codex 靠显式塌缩 —— `exec_policy.rs` 的原话是「We prefer to prompt the user
|
|
13479
|
+
* rather than outright forbid the command, but if the user has explicitly
|
|
13480
|
+
* disabled prompts, we must forbid the command」,落地成
|
|
13481
|
+
* `AskForApproval::Never => Decision::Forbidden`,另有 `prompt_is_rejected_by_policy`
|
|
13482
|
+
* 把**任何**要弹的东西在那一档下变成一句拒绝。
|
|
13483
|
+
*
|
|
13484
|
+
* 这个方法此前只有第 3 条(非交互),判据挂在「**有没有人可问**」上,漏了
|
|
13485
|
+
* 「**用户说了别问我**」—— 而这两件事在语义上是同一件。落地的后果是屏幕上
|
|
13486
|
+
* 那句「跳过全部检查 · 什么都不问」是假话:实测 `echo "$(date)"`、`node -e`、
|
|
13487
|
+
* `python3 -c` 在 `bypass` 档下照旧弹框。
|
|
13488
|
+
*
|
|
13489
|
+
* ## 四条的顺序不能换,每一条各有各的理由
|
|
13490
|
+
*
|
|
13491
|
+
* 1. **`plan` → 拒绝。** 那一档是只读的,「问一句就能干」这回事在它里面不存在。
|
|
13492
|
+
* ⚠️ 这一条修的是一个**旧洞**:底线那一层跑在档位判定前面,所以在这之前
|
|
13493
|
+
* plan 模式下一条判不了的命令会弹给用户,用户点「允许」它就真跑了 ——
|
|
13494
|
+
* 而 `checkPlan()` 那句「plan 模式禁止写入和命令执行」压根没机会说话。
|
|
13495
|
+
*
|
|
13496
|
+
* 2. **`bypass` + `obfuscated` → 放行。** 排在缓存前面,于是「`bypass` 整段不查
|
|
13497
|
+
* 审批缓存」({@link checkRulesAndCache} 那一节)对**规则那条路**逐字仍然成立。
|
|
13498
|
+
*
|
|
13499
|
+
* ⚠️ **认码,不是认「所有 ask 形状的底线」**(2026-09-10 用户拍的):
|
|
13500
|
+
* `dangerous-command`(tier-2,危险但可恢复)在这一档下**照旧问**。
|
|
13501
|
+
* 用户的原话是「除了那种真的非常危险的操作,和无法判断的才会……停下来找
|
|
13502
|
+
* 用户」,而他随后选定的两档形状是:**危险的问一句(点了就能干活)、
|
|
13503
|
+
* 判不了的不问**。所以这一支只塌 `obfuscated`。
|
|
13504
|
+
*
|
|
13505
|
+
* ⚠️ 塌向「放行」而不是 Codex 的「拒绝」:这条判定的原话是「静态检查无法
|
|
13506
|
+
* 判定其真实行为,需人工确认」—— 它是一句「我判不了」,不是一句「这危险」,
|
|
13507
|
+
* 而 `bypass` 的字面意思正是「别拿你判不了的事来问我」。这一档下**逐字就是
|
|
13508
|
+
* Hermes 的 yolo**(它的 floor 只有 hardline,判不了那一族住在 Tier-2、
|
|
13509
|
+
* 被 yolo 整段跳过)。
|
|
13510
|
+
*
|
|
13511
|
+
* ⚠️ **代价说清楚**:`bypass` + 提示注入 + `$(…)` 拼命令名这条路由此打通。
|
|
13512
|
+
* Hermes 在 `tools/approval.py` 那句 `# this and bypass every approval check
|
|
13513
|
+
* (prompt-injection escalation path)` 上承认的是同一个敞口。不接受的人该做的是
|
|
13514
|
+
* **别用这一档**,而不是让这一档偷偷弹框 —— 一个说了「不问」却还在问的开关,
|
|
13515
|
+
* 会让用户学会闭眼点「允许」,那比敞口更坏。
|
|
13516
|
+
*
|
|
13517
|
+
* 3. **用户以前对这一条明确答过 → 照他的答复。** 这是另一个缺陷:审批缓存躺在
|
|
13518
|
+
* 这一层**后面**,所以一条判不了 / tier-2 危险的命令上点一百次「永久允许」,
|
|
13519
|
+
* 第一百零一次照样弹 —— 那个出口在这一族上是**画着但不通**的。
|
|
13520
|
+
*
|
|
13521
|
+
* ⚠️ 这里查缓存**不受 `approvalCacheActive()` 约束**(那条只管规则那条路):
|
|
13522
|
+
* 走到这儿说明这一刻真的要弹窗,而缓存的定义就是「弹窗答案的记忆」。
|
|
13523
|
+
* 2026-08-17 那条判据(`bypass` 下缓存的 deny 不该拦住任何东西)没有被翻 ——
|
|
13524
|
+
* 它说的是**档位本来就放行**的操作,而这一支下面的操作档位从来不放行。
|
|
13525
|
+
*
|
|
13526
|
+
* 这不是「让缓存绕过黑名单」:绕不过的是 deny 形状的那两条(灾难级危险命令、
|
|
13527
|
+
* 敏感路径),它们在 `hard.requireApproval` 为假时压根走不到这儿。
|
|
13528
|
+
*
|
|
13529
|
+
* 4. **非交互 → 拒绝**(原有行为,一字未动)。它排在最后:前面几条各自都是
|
|
13530
|
+
* 「这道题已经有答案了」,而这一条说的是「没人可答」。
|
|
13531
|
+
*/
|
|
13532
|
+
private settleUnaskable;
|
|
13533
|
+
/**
|
|
13534
|
+
* **规则那条路**上会不会查审批缓存(2026-08-17 的判据:`bypass` 整段不查,
|
|
13535
|
+
* 全文在 {@link checkRulesAndCache} 上)。
|
|
13536
|
+
*
|
|
13537
|
+
* ⚠️ **它不是「这个档位记不记得住」**:安全底线那条路({@link settleUnaskable})
|
|
13538
|
+
* 在任何档位下都查缓存。宿主要知道的是**这一次问的这道题**记不记得住,
|
|
13539
|
+
* 那个答案在 `PermissionDecision.rememberable` 上,由 {@link rememberFlag} 打。
|
|
13540
|
+
*/
|
|
13541
|
+
approvalCacheActive(): boolean;
|
|
13542
|
+
/**
|
|
13543
|
+
* 给规则表那条路上的 ask 打「记不记得住」这一格。
|
|
13544
|
+
*
|
|
13545
|
+
* 只在**记不住**的时候产出这个键:`{ rememberable: undefined }` 和「没有这个键」
|
|
13546
|
+
* 在 JSON / wire 上是两回事(后者会被编成一个 null),而协议那边写的是
|
|
13547
|
+
* **不给 = 记得住**。
|
|
13548
|
+
*
|
|
13549
|
+
* 走到这儿的 ask 是规则表判的,所以它和 {@link approvalCacheActive} 同一个答案;
|
|
13550
|
+
* 底线那条路不经过这里(它的答复一律记得住)。
|
|
13551
|
+
*/
|
|
13552
|
+
private rememberFlag;
|
|
13553
|
+
/**
|
|
13554
|
+
* 审批缓存那一格 —— **全类唯一一处查它的地方**。
|
|
13555
|
+
*
|
|
13556
|
+
* 两个调用方({@link checkRulesAndCache} 的第 2 层、{@link settleUnaskable} 的
|
|
13557
|
+
* 第 2 条)必须用同一套 key,否则「批过的那一条」在其中一条路上永远命不中;
|
|
13558
|
+
* 而那种分叉两边各自都自洽,没有任何检查抓得到。
|
|
13559
|
+
*
|
|
13560
|
+
* key 用「工具名 + 目标」:按类别做 key 会让拒绝一次 `code_exec` 连坐到
|
|
13561
|
+
* terminal 和所有 MCP 工具。
|
|
13562
|
+
*
|
|
13563
|
+
* ⚠️ **它自己不认档位。** 「`bypass` 不查缓存」那条判据只管**规则那条路**,
|
|
13564
|
+
* 所以那道闸在 {@link checkRulesAndCache} 的调用点上(`approvalCacheActive()`),
|
|
13565
|
+
* 不在这里 —— {@link settleUnaskable} 那条路必须在任何档位下都查得到,
|
|
13566
|
+
* 判据在它的第 3 条上。搬进来的后果是「问过一次的 tier-2 命令在 `bypass` 下
|
|
13567
|
+
* 永远问不完」。
|
|
13568
|
+
*/
|
|
13569
|
+
private cachedDecision;
|
|
12580
13570
|
/**
|
|
12581
13571
|
* 策略规则 + 紧凑权限规则 + 审批缓存。返回 null 表示三者都没定论,
|
|
12582
13572
|
* 交给权限级别判。
|
|
@@ -12600,8 +13590,9 @@ declare class PermissionManager implements PermissionManager$1 {
|
|
|
12600
13590
|
* 档下对一条命令点了「拒绝」,`tool-executor` 把那一下写成
|
|
12601
13591
|
* `recordApproval(…, 'deny')`;随后切到 `bypass` 再敲同一条,屏幕上回的是
|
|
12602
13592
|
* 「操作被拦截 [权限]: 已缓存拒绝」。而三处真源都说它该过:
|
|
12603
|
-
* [docs/PERMISSIONS.md](../../../../docs/PERMISSIONS.md)
|
|
12604
|
-
*
|
|
13593
|
+
* [docs/PERMISSIONS.md](../../../../docs/PERMISSIONS.md) 的档位表(当时写的是
|
|
13594
|
+
* 「允许一切」,2026-09-10 改成「不问你任何事」)、
|
|
13595
|
+
* [by-level.ts](./by-level.ts) 那张五档表写「全放行 —— 但挡不住第 1 层那两条 deny」、
|
|
12605
13596
|
* 方案 46 §七 写「`bypass` 之下危险命令表是**唯一还在岗的东西**」。
|
|
12606
13597
|
*
|
|
12607
13598
|
* 这一档下**没有被放松的东西**:第 1 层安全底线(危险命令表 / 敏感路径 /
|
|
@@ -14295,8 +15286,8 @@ declare const PolicyRuleSchema: z.ZodObject<{
|
|
|
14295
15286
|
command_prefix: z.ZodOptional<z.ZodString>;
|
|
14296
15287
|
target_pattern: z.ZodOptional<z.ZodString>;
|
|
14297
15288
|
decision: z.ZodEnum<{
|
|
14298
|
-
deny: "deny";
|
|
14299
15289
|
allow: "allow";
|
|
15290
|
+
deny: "deny";
|
|
14300
15291
|
ask_user: "ask_user";
|
|
14301
15292
|
}>;
|
|
14302
15293
|
deny_message: z.ZodOptional<z.ZodString>;
|
|
@@ -16651,4 +17642,4 @@ declare function resolveCodeModeWorker(baseDir: string, exists?: typeof existsSy
|
|
|
16651
17642
|
*/
|
|
16652
17643
|
declare function codeModeWorkerPath(): string | undefined;
|
|
16653
17644
|
|
|
16654
|
-
export { AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, type AcquireResult, type AgentConfig, AgentLoop, type AgentProvider, type AgentSite, type AgentSiteRef, type AppendMessageInput, ApprovalCache, type ApprovalDecision, type ApprovalScope, type ArtifactOpenRefusal, type ArtifactRetention, type AskQuestionDeps, BLOCKED_TOOLS, type BackendOptions, type BackendOutcome, type BackgroundTaskSource, type BaseOrigin, type BaseSlot, type BeginTurnInput, type BreakdownInput, BudgetGuard, type BudgetGuardOptions, type BudgetInfo, type BudgetLevel, type BudgetOptions, type BudgetStatus, BudgetStore, type BudgetStoreOptions, type BuildFireArgvInput, type BuildIndexOptions, CHECKPOINT_MAX_TOTAL_BYTES, CLAUDE_EVENT_NAMES, CLAUDE_TOOL_NAMES, CODE_MODE_LIMITS, CODE_MODE_SDK_TAG, CONFIG_KEYS, CURRENT_CONFIG_VERSION, type CachedApproval, type CachedDecision, type CheckpointCapture, type CheckpointFile, CheckpointManager, type CheckpointManagerOptions, type CheckpointManifest, CheckpointStore, type CheckpointStoreOptions, type CheckpointSummary, type ClaudeHooksParseOptions, type CodeModeLimits, type CodeRequest, type CodeResult, CodeSandbox, type CommandHookConfig, type CommandHookResult, type CommandLoadOutcome, type CommandLoadSummary, type CommandResult, type CommandRunner, type CompactionResult, type CompiledRules, type ComplianceDirSpec, type ComplianceDirsSummary, ComplianceEngine, type ComplianceEngineInput, type ComplianceGate, type ComplianceHit, type ComplianceRule, type ComplianceRuleSource, type ComplianceSettings, type ComplianceVerdict, type CompressConfig, type CompressResult, type ConfigMigration, type ConfigOrigins, ContextCompressor, type ContextEngine, type CreateScheduleInput, type CreateSessionInput, DEFAULT_COMPLIANCE_ACTIONS, DEFAULT_COMPLIANCE_SETTINGS, DEFAULT_GOAL_MAX_ROUNDS, DEFAULT_MAX_HOLD_CHARS, type DelegateArgs, type DelegateConfig, DelegateManager, type DelegateTaskResult, type DiagnoseOptions, type DiscoverOutcome, type DiscoveredFile, type DoctorReport, type DraftParse, EMPTY_RULES, EPOCH_DISK_LEDGER, EpochConfigSchema, type ExpandOptions, FTS_TABLES, FTS_TRIGGERS, type FallbackEvent, type FileSlots, type FileSourceKind, type ForkInput, type FrontmatterParse, type FrontmatterSplit, type FtsHealth, type FtsReclaim, type FtsSpace, type FtsTableHealth, GOAL_BLOCK_CODES, type GateAxis, type GateVerdict, type GenerateInput, type GenerateOutput, type Goal, type GoalBlockReason, type GoalClear, type GoalPhase, type GoalPromptView, type GoalRefusal, type GoalRoundResult, GoalService, GoalStore, type GoalToolDeps, type GoalWrite, HEADLESS_AUDIT_CODES, type HeadlessPolicy, type HookConfigEntry, HookManager, type HookManagerOptions, type HookMatcher, type HookSourceKind, type HookSourceStatus, type HookSourcesOptions, type HookSourcesSummary, type HooksParseOutcome, type MemoryManager$1 as IMemoryManager, INSTRUCTION_BUDGET_CHARS, INSTRUCTION_FILES, type SessionManager$1 as ISessionManager, type SkillSystem$1 as ISkillSystem, ImageLoadError, type ImageSize, type ImportDecision, type ImportGate, type ImportNode, type ImportSkipReason, ImportTrustStore, type InstallOptions, type InstallOutcome, type InstallPreview, type InstructionScan, type InstructionSource, type IsolationReason, type IsolationReport, type JsonSchemaDocument, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, type LayerOutcome, type LayerScalars, type LayerStatus, type LearningContext, type LearningResult, type LearningSkipReason, type LexiconLoadOutcome, type LifecycleOutcome, type ListCandidatesInput, type ListSessionsInput, type ListSessionsOutput, type LoadCommandsOptions, type LoadConfigOptions, type LoadKeybindingsOptions, type LoadKeybindingsResult, type LoadRolesOptions, type LoadedPlugin, type LockHolder, MARKETPLACE_FILE, MAX_AUDIT_ENTRIES, MAX_COMMAND_DEPTH, MAX_GOAL_MAX_ROUNDS, MAX_IMPORT_DEPTH, MAX_OBJECTIVE_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, type ManagedPolicy, ManagedPolicyError, type ManagedSettings, ManagedSettingsSchema, type MarketplaceCatalog, type MarketplaceEntry, type MarketplaceOutcome, type MarketplaceRecord, type MemoryConfig, type MemoryEntry, MemoryManager, MemoryReviewer, type MemorySearchResult, type MemoryTarget, type MemoryWriteResult, type MentionPart, type MentionResolution, type Message, type MessageHit, type MessageRecord, type MessageSurface, type ModelCapability, ModelFailureTracker, type ModelMetaEntry, type ModelPricing, type MultimodalPolicy, NOMINAL_TOTAL_BYTES, NO_REVEALED_TOOLS, type NonInteractiveProbe, type OsTaskSnapshot, type OutputGuard, PERMISSION_AUDIT_CODES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_NAME_PATTERN, PLUGIN_ROOT_ENV, PLUGIN_ROOT_TOKEN, POLICY_DECISIONS, PROJECT_AGENTS_SUBDIR, PROVIDER_NO_CREDENTIAL, type PermissionAuditCode, type PermissionAuditEntry, type PermissionAuditOutcome, type PermissionAuditScope, type PermissionAuditSnapshot, PermissionManager, type PersistedBudget, type PersistedPart, type PlanApprovalFn, type PlanEnterResult, type PlanModeDeps, PlanModeState, type PlanSettlement, type PluginArtifacts, type PluginCommandDir, type PluginCounts, type PluginHookFile, type PluginInventory, type PluginLoadOptions, type PluginManifest, type PluginPathRef, type PluginRecord, type PluginSettingsFile, type PluginSourceType, type PluginStateReadOutcome, PluginStore, type PolicyDirSpec, type PolicyDirsSummary, type PolicyLoadOutcome, type PolicyRule, PolicyRuleSchema, type ProjectContext, ProviderError, ProviderRouter, type ProviderStreamChunk, type ProviderToolCall$1 as ProviderToolCall, type ProviderWarning, type PruneResult, type QuestionAskFn, RECORDING_KEEP_RUNS, RECORDING_MAX_BYTES, ROLE_FRONTMATTER_SCHEMA, RUN_CODE_TOOL, type ReadMessagesInput, type ReadMessagesOutput, type RecentWorkspace, RecentWorkspaces, type RecordRunInput, type RecorderOptions, type RecoveryAction, type RegisterInput, type RegisterOutcome, type RegistrarOptions, type RegistrationPatch, type RepairOutcome, type ResolveMentionsOptions, type ResolveReferenceInput, type ResolveSettingsOptions, type ResolvedCompression, type ResolvedReference, type ResolvedSource, type ResponseFormat, type RestorePartsOptions, type ReviewIssue, type RewindAction, type RewindDrift, type RewindFilePlan, type RewindOptions, type RewindOutcome, type RewindPreview, type RoleCreateFailure, type RoleCreateInput, type RoleCreateOptions, type RoleCreateOutcome, type RoleLoadOutcome, type RoleLoadSummary, type RoleMergeNotice, type RoleMergeResult, type RoleScope, type RuleMatch, type RuleSuggestion, type RuleVerdict, type RunCodeFailure, type RunCodeInput, type RunCodeOutcome, type RunCodeToolDeps, type RunEstimateInput, type RunInput, type RunResult, SANDBOX_COVERS, SANDBOX_EXCLUDES, SCALAR_KEYS, SCHEDULE_DEFAULTS, SCHEDULE_DEFAULT_ALLOWLIST, SCHEDULE_ISSUE_CODES, SCHTASKS_FOLDER, SESSION_MESSAGES_READ_TOOL, SESSION_MESSAGES_SEARCH_TOOL, SESSION_QUERY_TOOLS, SESSION_SEARCH_TOOL, SESSION_TRACE_TOOL, SETTINGS_LAYER_ORDER, SETTING_WRITE_APPLY, SETTING_WRITE_KEYS, SETTING_WRITE_LAYERS, SKILL_CREATE_TOOL, SKILL_EDIT_TOOL, SKILL_PATCH_TOOL, SKILL_VIEW_TOOL, SKILL_WRITE_FILE_TOOL, SLASH_COMMANDS_DIAG_MODULE, type ScalarKey, type ScanInstructionsOptions, type ScheduleArgvRefusal, type ScheduleArgvResult, type ScheduleArgvWarning, type ScheduleBackend, type ScheduleCliEntry, type ScheduleDraftDeps, type ScheduleDrift, type ScheduleDriftKind, type ScheduleInstallForm, type ScheduleIssue, type ScheduleIssueCode, type ScheduleLock, ScheduleRecorder, ScheduleRegistrar, ScheduleStore, type ScheduleValidation, type SchemaExport, type SearchHit, type SearchInput, type SearchMessagesInput, type SearchMessagesOutput, type SearchOutput, type SearchSessionsInput, type SelectionDeps, type Session, type SessionCandidate, type SessionHit, SessionManager, type SessionMentionDeps, type SessionMeta, SessionQueries, SessionReferences, type SessionSearchDeps, type SessionStats, type SessionSurface, type SessionTrace, type SessionVisibility, type SessionVisibilityInput, type SettingApply, type SettingChain, type SettingFutile, type SettingLayer, type SettingStep, type SettingValue, type SettingValueKind, type SettingWriteFailure, type SettingWriteKey, type SettingWriteLayer, type SettingWriteOutcome, type SettingWriteRequest, type SettingWriteTarget, type SettingWriteTargetsOptions, type SettingsFile, SettingsFileError, SettingsFileSchema, type SettingsLayer, type SettingsResolution, type ShadowFinding, type ShadowKind, type Skill, type SkillDirSource, type SkillDirSpec, type SkillDirsSummary, type SkillImportConflict, type SkillImportDone, type SkillImportEntry, type SkillImportFailure, type SkillImportForm, type SkillImportOptions, type SkillImportPreview, type SkillImportResult, type SkillIndexEntry, type SkillIndexOptions, type SkillIndexResidency, type SkillIndexStats, SkillLearner, type SkillLearningProvider, type SkillMeta, type SkillStats, SkillSystem, type SkillSystemOptions, type SkillViewDeps, type SkillWriteDeps, type SubAgentRunner, type SubTask, type SubToolCaller, type SummarizeOutput, type SurfaceMessage, type SystemPromptParams, type SystemPromptSegments, TOOL_SEARCH_TOOL, TaskNoticeTracker, type TodoItem, type ToolCall, type ToolConflict, type ToolGate, type ToolNameFidelity, type ToolNameLookup, ToolRegistry, type ToolRevealState, type ToolScope, type ToolSearchDeps, type ToolTableCost, type TraceInput, type TraceNode, TrackerDB, type TrustDecision, type TrustGate, type TrustGateOptions, TrustManager, type TurnRecord, type TurnTiming, type UpdateScheduleInput, type UtilityModelInfo, type ValidateScheduleInput, type VersionCheck, Workspace, type WorkspaceFiles, type WorkspaceIssue, type WorkspaceIssueKind, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, checkEpochVersion, checkFtsHealth, checkShadowing, classifyProviderError, clearModelCache, coalesceRecording, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createRoleFile, createRoleScope, createRunCodeTool, createScheduleDraftTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, defaultModelOf, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, draftCommandLine, draftWidening, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, hasPromptCaching, hasProviderCredentials, imageFromBase64, imageFromPath, imagePartTokens, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mentionsPluginRoot, mergeHeadlessPolicy, mergeRoles, mergeSchedulePatch, microsToUsd, modelListCandidates, needsAllowlist, nextFallbackModel, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, openArtifact, originOf, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelList, parseRoleDefinition, parseScheduleDraft, parseSkillFrontmatter, parseTrigger, pendingImageTokens, persistParts, persistToolResults, persistedUsage, previewSkillImport, pruneArtifacts, pruneRecordings, pruneSchedules, readImageSize, readMarketplaces, readPluginManifest, readPluginRecords, readProviderKeyEnv, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeSessionArtifacts, renderImportTree, renderProjectContext, renderSdkDeclaration, repairSchedules, resolveArtifactRetention, resolveCodeModeWorker, resolveComplianceDirs, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, substitutePluginRoot, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writeSettingValue };
|
|
17645
|
+
export { AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, type AcquireResult, type AgentConfig, AgentLoop, type AgentProvider, type AgentSite, type AgentSiteRef, type AppendMessageInput, ApprovalCache, type ApprovalDecision, type ApprovalScope, type ArtifactOpenRefusal, type ArtifactRetention, type AskQuestionDeps, BLOCKED_TOOLS, type BackendOptions, type BackendOutcome, type BackgroundTaskSource, type BaseOrigin, type BaseSlot, type BeginTurnInput, type BreakdownInput, BudgetGuard, type BudgetGuardOptions, type BudgetInfo, type BudgetLevel, type BudgetOptions, type BudgetStatus, BudgetStore, type BudgetStoreOptions, type BuildFireArgvInput, type BuildIndexOptions, CHECKPOINT_MAX_TOTAL_BYTES, CLAUDE_EVENT_NAMES, CLAUDE_TOOL_NAMES, CODE_MODE_LIMITS, CODE_MODE_SDK_TAG, CONFIG_KEYS, CURRENT_CONFIG_VERSION, type CachedApproval, type CachedDecision, type CheckpointCapture, type CheckpointFile, CheckpointManager, type CheckpointManagerOptions, type CheckpointManifest, CheckpointStore, type CheckpointStoreOptions, type CheckpointSummary, type ClaudeHooksParseOptions, type CodeModeLimits, type CodeRequest, type CodeResult, CodeSandbox, type CommandHookConfig, type CommandHookResult, type CommandLoadOutcome, type CommandLoadSummary, type CommandResult, type CommandRunner, type CompactionResult, type CompiledRules, type ComplianceDirSpec, type ComplianceDirsSummary, ComplianceEngine, type ComplianceEngineInput, type ComplianceGate, type ComplianceHit, type ComplianceRule, type ComplianceRuleSource, type ComplianceSettings, type ComplianceVerdict, type CompressConfig, type CompressResult, type ConfigMigration, type ConfigOrigins, ContextCompressor, type ContextEngine, type CreateScheduleInput, type CreateSessionInput, DEFAULT_COMPLIANCE_ACTIONS, DEFAULT_COMPLIANCE_SETTINGS, DEFAULT_COMPRESSION_THRESHOLD, DEFAULT_GOAL_MAX_ROUNDS, DEFAULT_MAX_HOLD_CHARS, type DelegateArgs, type DelegateConfig, DelegateManager, type DelegateTaskResult, type DiagnoseOptions, type DiscoverOutcome, type DiscoveredFile, type DoctorReport, type DraftParse, EMPTY_RULES, EPOCH_DISK_LEDGER, EpochConfigSchema, type ExpandOptions, type ExtractOutcome, FTS_TABLES, FTS_TRIGGERS, type FallbackEvent, type FileSlots, type FileSourceKind, type ForkInput, type FrontmatterParse, type FrontmatterSplit, type FtsHealth, type FtsReclaim, type FtsSpace, type FtsTableHealth, GOAL_BLOCK_CODES, type GateAxis, type GateVerdict, type GenerateInput, type GenerateOutput, type Goal, type GoalBlockReason, type GoalClear, type GoalPhase, type GoalPromptView, type GoalRefusal, type GoalRoundResult, GoalService, GoalStore, type GoalToolDeps, type GoalWrite, HEADLESS_AUDIT_CODES, type HeadlessPolicy, type HookConfigEntry, HookManager, type HookManagerOptions, type HookMatcher, type HookSourceKind, type HookSourceStatus, type HookSourcesOptions, type HookSourcesSummary, type HooksParseOutcome, type MemoryManager$1 as IMemoryManager, INSTRUCTION_BUDGET_CHARS, INSTRUCTION_FILES, type SessionManager$1 as ISessionManager, type SkillSystem$1 as ISkillSystem, ImageLoadError, type ImageSize, type ImportDecision, type ImportGate, type ImportNode, type ImportSkipReason, ImportTrustStore, type InstallOptions, type InstallOutcome, type InstallPreview, type InstructionScan, type InstructionSource, type IsolationReason, type IsolationReport, type JsonSchemaDocument, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, type LayerOutcome, type LayerScalars, type LayerStatus, type LearningContext, type LearningResult, type LearningSkipReason, type LexiconLoadOutcome, type LifecycleOutcome, type ListCandidatesInput, type ListSessionsInput, type ListSessionsOutput, type LoadCommandsOptions, type LoadConfigOptions, type LoadKeybindingsOptions, type LoadKeybindingsResult, type LoadRolesOptions, type LoadedPlugin, type LockHolder, MARKETPLACE_DISPLAY_FIELDS, MARKETPLACE_FILE, MAX_AUDIT_ENTRIES, MAX_COMMAND_DEPTH, MAX_GOAL_MAX_ROUNDS, MAX_IMPORT_DEPTH, MAX_OBJECTIVE_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, type ManagedPolicy, ManagedPolicyError, type ManagedSettings, ManagedSettingsSchema, type MarketplaceCatalog, type MarketplaceDisplay, type MarketplaceDisplayField, type MarketplaceEntry, type MarketplaceOutcome, type MarketplaceRecord, type MarketplaceStatus, type MemoryConfig, type MemoryEntry, MemoryManager, MemoryReviewer, type MemorySearchResult, type MemoryTarget, type MemoryWriteResult, type MentionPart, type MentionResolution, type Message, type MessageHit, type MessageRecord, type MessageSurface, type ModelCapability, ModelFailureTracker, type ModelMetaEntry, type ModelPricing, type MultimodalPolicy, NOMINAL_TOTAL_BYTES, NO_REVEALED_TOOLS, type NonInteractiveProbe, type OsTaskSnapshot, type OutputGuard, PACK_EXCLUDES, PACK_MAX_BYTES, PACK_MAX_FILES, PERMISSION_AUDIT_CODES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_NAME_PATTERN, PLUGIN_ROOT_ENV, PLUGIN_ROOT_TOKEN, POLICY_DECISIONS, PROJECT_AGENTS_SUBDIR, PROVIDER_NO_CREDENTIAL, type PackFile, type PackLimits, type PackOutcome, type PackPlan, type PackPlanOutcome, type PermissionAuditCode, type PermissionAuditEntry, type PermissionAuditOutcome, type PermissionAuditScope, type PermissionAuditSnapshot, PermissionManager, type PersistedBudget, type PersistedPart, type PlanApprovalFn, type PlanEnterResult, type PlanModeDeps, PlanModeState, type PlanSettlement, type PluginArtifacts, type PluginAuthor, PluginAuthorSchema, type PluginCommandDir, type PluginCounts, type PluginHookFile, type PluginInventory, type PluginLoadOptions, type PluginManifest, type PluginPathRef, type PluginRecord, type PluginSettingsFile, type PluginSourceType, type PluginStateReadOutcome, PluginStore, type PolicyDirSpec, type PolicyDirsSummary, type PolicyLoadOutcome, type PolicyRule, PolicyRuleSchema, type ProjectContext, ProviderError, ProviderRouter, type ProviderStreamChunk, type ProviderToolCall$1 as ProviderToolCall, type ProviderWarning, type PruneResult, type QuestionAskFn, RECORDING_KEEP_RUNS, RECORDING_MAX_BYTES, ROLE_FRONTMATTER_SCHEMA, RUN_CODE_TOOL, type ReadMessagesInput, type ReadMessagesOutput, type RecentWorkspace, RecentWorkspaces, type RecordRunInput, type RecorderOptions, type RecoveryAction, type RegisterInput, type RegisterOutcome, type RegistrarOptions, type RegistrationPatch, type RepairOutcome, type ResolveMentionsOptions, type ResolveReferenceInput, type ResolveSettingsOptions, type ResolvedCompression, type ResolvedReference, type ResolvedSource, type ResponseFormat, type RestorePartsOptions, type ReviewIssue, type RewindAction, type RewindDrift, type RewindFilePlan, type RewindOptions, type RewindOutcome, type RewindPreview, type RoleCreateFailure, type RoleCreateInput, type RoleCreateOptions, type RoleCreateOutcome, type RoleLoadOutcome, type RoleLoadSummary, type RoleMergeNotice, type RoleMergeResult, type RoleScope, type RuleMatch, type RuleSuggestion, type RuleVerdict, type RunCodeFailure, type RunCodeInput, type RunCodeOutcome, type RunCodeToolDeps, type RunEstimateInput, type RunInput, type RunResult, SANDBOX_COVERS, SANDBOX_EXCLUDES, SCALAR_KEYS, SCHEDULE_DEFAULTS, SCHEDULE_DEFAULT_ALLOWLIST, SCHEDULE_ISSUE_CODES, SCHTASKS_FOLDER, SESSION_MESSAGES_READ_TOOL, SESSION_MESSAGES_SEARCH_TOOL, SESSION_QUERY_TOOLS, SESSION_SEARCH_TOOL, SESSION_TRACE_TOOL, SETTINGS_LAYER_ORDER, SETTING_WRITE_APPLY, SETTING_WRITE_KEYS, SETTING_WRITE_LAYERS, SKILL_CREATE_TOOL, SKILL_EDIT_TOOL, SKILL_PATCH_TOOL, SKILL_VIEW_TOOL, SKILL_WRITE_FILE_TOOL, SLASH_COMMANDS_DIAG_MODULE, type ScalarKey, type ScanInstructionsOptions, type ScheduleArgvRefusal, type ScheduleArgvResult, type ScheduleArgvWarning, type ScheduleBackend, type ScheduleCliEntry, type ScheduleDraftDeps, type ScheduleDrift, type ScheduleDriftKind, type ScheduleInstallForm, type ScheduleIssue, type ScheduleIssueCode, type ScheduleLock, ScheduleRecorder, ScheduleRegistrar, ScheduleStore, type ScheduleValidation, type SchemaExport, type SearchHit, type SearchInput, type SearchMessagesInput, type SearchMessagesOutput, type SearchOutput, type SearchSessionsInput, type SelectionDeps, type Session, type SessionCandidate, type SessionHit, SessionManager, type SessionMentionDeps, type SessionMeta, SessionQueries, SessionReferences, type SessionSearchDeps, type SessionStats, type SessionSurface, type SessionTrace, type SessionVisibility, type SessionVisibilityInput, type SettingApply, type SettingChain, type SettingFutile, type SettingLayer, type SettingStep, type SettingValue, type SettingValueKind, type SettingWriteFailure, type SettingWriteKey, type SettingWriteLayer, type SettingWriteOutcome, type SettingWriteRequest, type SettingWriteTarget, type SettingWriteTargetsOptions, type SettingsFile, SettingsFileError, SettingsFileSchema, type SettingsLayer, type SettingsResolution, type ShadowFinding, type ShadowKind, type Skill, type SkillDirSource, type SkillDirSpec, type SkillDirsSummary, type SkillImportConflict, type SkillImportDone, type SkillImportEntry, type SkillImportFailure, type SkillImportForm, type SkillImportOptions, type SkillImportPreview, type SkillImportResult, type SkillIndexEntry, type SkillIndexOptions, type SkillIndexResidency, type SkillIndexStats, SkillLearner, type SkillLearningProvider, type SkillMeta, type SkillStats, SkillSystem, type SkillSystemOptions, type SkillViewDeps, type SkillWriteDeps, type SubAgentRunner, type SubTask, type SubToolCaller, type SummarizeOutput, type SurfaceMessage, type SystemPromptParams, type SystemPromptSegments, TOOL_SEARCH_TOOL, TaskNoticeTracker, type TodoItem, type ToolCall, type ToolConflict, type ToolGate, type ToolNameFidelity, type ToolNameLookup, ToolRegistry, type ToolRevealState, type ToolScope, type ToolSearchDeps, type ToolTableCost, type TraceInput, type TraceNode, TrackerDB, type TrustDecision, type TrustGate, type TrustGateOptions, TrustManager, type TurnRecord, type TurnTiming, type UpdateScheduleInput, type UtilityModelInfo, type ValidateScheduleInput, type VersionCheck, Workspace, type WorkspaceFiles, type WorkspaceIssue, type WorkspaceIssueKind, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, checkEpochVersion, checkFtsHealth, checkShadowing, classifyProviderError, clearModelCache, coalesceRecording, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createRoleFile, createRoleScope, createRunCodeTool, createScheduleDraftTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, defaultModelOf, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, draftCommandLine, draftWidening, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, extractArchive, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, hasPromptCaching, hasProviderCredentials, imageFromBase64, imageFromPath, imagePartTokens, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mentionsPluginRoot, mergeHeadlessPolicy, mergeRoles, mergeSchedulePatch, microsToUsd, modelListCandidates, needsAllowlist, nextFallbackModel, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, openArtifact, originOf, packFileName, packPlugin, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelList, parseRoleDefinition, parseScheduleDraft, parseSkillFrontmatter, parseTrigger, pendingImageTokens, persistParts, persistToolResults, persistedUsage, planPack, previewSkillImport, projectEntryForDisplay, pruneArtifacts, pruneRecordings, pruneSchedules, readImageSize, readMarketplaces, readPluginManifest, readPluginRecords, readProviderKeyEnv, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeSessionArtifacts, renderImportTree, renderProjectContext, renderSdkDeclaration, repairSchedules, resolveArtifactRetention, resolveCodeModeWorker, resolveComplianceDirs, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveTar, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, substitutePluginRoot, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writeSettingValue };
|