@epoch-agent/protocol 0.8.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1464 -79
- package/dist/index.js +137 -12
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -169,6 +169,19 @@ interface PermissionDecision {
|
|
|
169
169
|
reason?: string;
|
|
170
170
|
/** deny=false 时是否需要弹出审批对话框(ask_user),deny=true 时为静默拒绝 */
|
|
171
171
|
requireApproval?: boolean;
|
|
172
|
+
/**
|
|
173
|
+
* 这次要问的这道题,**答复记不记得住**(2026-09-10)。只在
|
|
174
|
+
* `requireApproval` 为真时有意义。
|
|
175
|
+
*
|
|
176
|
+
* `false` = 引擎在这条路上不查审批缓存,所以「永久允许 / 本会话内始终允许」
|
|
177
|
+
* 写下来也不会被用上。引擎把它原样传成 {@link ApprovalRequest.rememberable},
|
|
178
|
+
* 宿主据此不画那两个出口。**不给 = 记得住**(改动前的行为)。
|
|
179
|
+
*
|
|
180
|
+
* ⚠️ 它是**一次判定**的属性,不是一个档位的属性:`bypass` 下走安全底线那条路的
|
|
181
|
+
* ask 查缓存(记得住),而规则表那条路不查(记不住)。所以宿主别去看档位名,
|
|
182
|
+
* 判据在 core 的 `PermissionManager.settleUnaskable()` 和 `checkRulesAndCache()` 上。
|
|
183
|
+
*/
|
|
184
|
+
rememberable?: boolean;
|
|
172
185
|
}
|
|
173
186
|
/** 上抛给宿主(TUI / CLI)做阻塞确认的审批请求 */
|
|
174
187
|
interface ApprovalRequest {
|
|
@@ -186,6 +199,24 @@ interface ApprovalRequest {
|
|
|
186
199
|
* 即两种降级都落在更保守的一侧。
|
|
187
200
|
*/
|
|
188
201
|
plan?: PlanProposal;
|
|
202
|
+
/**
|
|
203
|
+
* 「记住这次决定」这次有没有意义(2026-09-10)——
|
|
204
|
+
* {@link PermissionDecision.rememberable} 原样转发过来的那一格。
|
|
205
|
+
*
|
|
206
|
+
* `false` = 引擎在**这条判定路径**上不查审批缓存,所以 `allow-session` /
|
|
207
|
+
* `allow-always` 这两个出口写得进 `approvals.json`、却一次都不会被用上。
|
|
208
|
+
* 宿主该把那两个出口**整个不画**,并说出为什么:一个写下来就再也不生效的按钮,
|
|
209
|
+
* 比没有这个按钮更坏 —— 用户会以为自己设过边界了。
|
|
210
|
+
*
|
|
211
|
+
* **不给 = 记得住**(改动前的行为,四个出口照画)。
|
|
212
|
+
*
|
|
213
|
+
* ⚠️ **它不是一个档位的属性,宿主别自己去看档位名**:`bypass` 下走安全底线
|
|
214
|
+
* 那条路的 ask(危险命令)记得住,走规则表那条路的记不住。判据在
|
|
215
|
+
* `PermissionDecision.rememberable` 上。
|
|
216
|
+
*
|
|
217
|
+
* ⚠️ 它**不是**「这次能不能批准」:`allow-once` 和 `deny` 两个出口永远都在。
|
|
218
|
+
*/
|
|
219
|
+
rememberable?: boolean;
|
|
189
220
|
}
|
|
190
221
|
/**
|
|
191
222
|
* 宿主对审批请求的答复。
|
|
@@ -1616,6 +1647,143 @@ interface HostUser {
|
|
|
1616
1647
|
icon?: string;
|
|
1617
1648
|
}
|
|
1618
1649
|
|
|
1650
|
+
/**
|
|
1651
|
+
* 金额的**展示**口径 —— 全仓唯一一处把数字变成「一串带货币符号的字」的地方。
|
|
1652
|
+
*
|
|
1653
|
+
* ## 一条贯穿全仓的分界:**算术恒为美元,展示可换币种**
|
|
1654
|
+
*
|
|
1655
|
+
* | | 单位 | 谁定的 | 换不换 |
|
|
1656
|
+
* | --- | --- | --- | --- |
|
|
1657
|
+
* | 单价表、`micro-USD` 累加、闸门比较 | **美元** | 上游 provider 的挂牌价 | **不换** |
|
|
1658
|
+
* | `costUsd` / `maxCostUsd` / `maxBudgetUsd` / DB 里那几列 | **美元** | 契约 | **不换** |
|
|
1659
|
+
* | 用户**输进来**的那几格(设置页、`--max-budget-usd`、定时任务表单) | **美元** | 标签上逐字写着「(美元)」 | **不换** |
|
|
1660
|
+
* | 屏幕上印出来的每一串金额 | `display.currency` | 用户 | **这里换** |
|
|
1661
|
+
*
|
|
1662
|
+
* 换句话说,币种在这个仓里**只是一层皮**:它进不了任何一句算术,也进不了任何一个
|
|
1663
|
+
* 落盘字段。这是刻意的,理由有三条,每一条单独都足以否掉「让币种进算术」:
|
|
1664
|
+
*
|
|
1665
|
+
* 1. **上游单价本来就是美元计价的**(`core/src/provider/model-metadata.ts` 那张静态表、
|
|
1666
|
+
* 以及 OpenRouter 抓回来的那份,都是 USD / MTok)。让内部换成别的币种,等于在
|
|
1667
|
+
* 每一笔账上多乘一次汇率再除回来 —— 多两次浮点,换不到任何东西;
|
|
1668
|
+
* 2. **落盘和网线上的字段名带着 `Usd` 后缀**(`costUsd`、`max_budget_usd`、
|
|
1669
|
+
* `microUsd`)。让它们装别的币种,字段名当场变成假话,而**没有任何一处会红**;
|
|
1670
|
+
* 3. **汇率是会变的,账是不该变的。** 用户今天把 `rate` 从 7.1 改成 7.3,
|
|
1671
|
+
* 上个月那几段会话的**历史账**不该跟着动。只在展示时乘一次,这件事自动成立 ——
|
|
1672
|
+
* 而如果换算发生在落盘前,改一次汇率就意味着整本账从此自相矛盾。
|
|
1673
|
+
*
|
|
1674
|
+
* ## ⚠️ 汇率**不印在任何界面上**,这是产品决定,不是漏了
|
|
1675
|
+
*
|
|
1676
|
+
* 用户配了 `rate` 就是认了这个数,界面上再写一句「按 7.1 折算」是把一个他自己
|
|
1677
|
+
* 填的常量念回给他听。所以这个模块**只吐金额**,一个「≈」、一个汇率脚注都没有。
|
|
1678
|
+
*
|
|
1679
|
+
* 它的代价是知道的、也是可接受的:设置页里那格上限写着「(美元)」、填 5,
|
|
1680
|
+
* 侧栏那条比值却印成 `¥35.50` 的分母 —— 两个数对不上,而屏幕上没有一句话解释。
|
|
1681
|
+
* 换来的是**分子分母同币种**(见下面那条 ⚠️),那个更要紧:一条
|
|
1682
|
+
* `¥0.86 / $5.00` 的比值是**读不出意思**的,而 `5 → ¥35.50` 只是需要用户
|
|
1683
|
+
* 想一下他自己配的汇率。
|
|
1684
|
+
*
|
|
1685
|
+
* ## ⚠️ 一条比值里的两个数,必须一起换
|
|
1686
|
+
*
|
|
1687
|
+
* 侧栏那句「约 {spent} / {limit}」的分母是**配置值**(美元),分子是**实际花费**
|
|
1688
|
+
* (美元)。展示时两个都乘同一个 `rate`,比值本身不变。漏换任何一边,屏幕上就会
|
|
1689
|
+
* 出现一条混币种的比值 —— 那不是「精度问题」,是一句假话。
|
|
1690
|
+
*
|
|
1691
|
+
* ## 没配币种时,这个模块的输出**与 2026-09-13 之前逐字节相同**
|
|
1692
|
+
*
|
|
1693
|
+
* `currency` 缺席(**绝大多数用户**)走的是 `$` + `toFixed(digits)`,和它替换掉的
|
|
1694
|
+
* 那六处手写实现一个字符不差。这条是这次改动的安全绳,也是为什么全仓那些断言
|
|
1695
|
+
* `'$0.0000'` 的既有用例一条都不用改 —— 它们从此顺带钉住了「默认路径没被改坏」。
|
|
1696
|
+
*/
|
|
1697
|
+
/**
|
|
1698
|
+
* 支持的展示币种。**唯一真源** —— {@link Currency} 类型从它派生。
|
|
1699
|
+
*
|
|
1700
|
+
* ## ⚠️ 值域是封闭的:`USD` 和 `CNY`,没有第三个
|
|
1701
|
+
*
|
|
1702
|
+
* 判据逐条借 [i18n.ts](./i18n.ts) 上 `LANGS` 那一段,它在这儿是**原样成立**的,
|
|
1703
|
+
* 不是抄一个先例 —— 这个仓的界面只有中文和英文两份 catalog,而币种是跟着
|
|
1704
|
+
* 用户在哪儿、拿什么结账走的。为一个我们连界面语言都不提供的地区先把币种铺上,
|
|
1705
|
+
* 铺的是一张**没有任何用例盖得住**的表。
|
|
1706
|
+
*
|
|
1707
|
+
* 所以加第三个币种是**一次需要重新决策的改动**,不是补一行常量:
|
|
1708
|
+
*
|
|
1709
|
+
* | 得先答的 | 为什么不能顺手 |
|
|
1710
|
+
* | --- | --- |
|
|
1711
|
+
* | 小数位怎么办 | `JPY` / `KRW` 惯例是 0 位,而这里四档位数是**逐处判过**的(见 {@link formatMoney} 那张表),不是一个能按币种改的旋钮 |
|
|
1712
|
+
* | 符号摆前面还是后面 | 欧陆多数币种是 `12,34 €`,而这里的实现和全部文案都假设**符号在前** |
|
|
1713
|
+
* | 千分位和小数点 | `1.234,56` 那一套要整套数字格式化,不是加一个符号 |
|
|
1714
|
+
*
|
|
1715
|
+
* 换句话说:**今天加的不是「CNY」这一个值,是「展示币种可以不是美元」这件事**,
|
|
1716
|
+
* 而第二个值把这件事的全部机制都落地了。第三个值要付的是上面那张表。
|
|
1717
|
+
*
|
|
1718
|
+
* 根 `__tests__/money-currency.test.ts` 里钉着 `CURRENCIES.length === 2` ——
|
|
1719
|
+
* 那条用例的全部意义就是逼下一个人先读完这一段,而不是加完就走
|
|
1720
|
+
* (手法同 `LANGS` 那条 `LANGS.length === 2`)。
|
|
1721
|
+
*/
|
|
1722
|
+
declare const CURRENCIES: readonly ["USD", "CNY"];
|
|
1723
|
+
/** 展示币种。**封闭的两个值**,见 {@link CURRENCIES} */
|
|
1724
|
+
type Currency = (typeof CURRENCIES)[number];
|
|
1725
|
+
/** 是不是我们支持的币种。用户输入(配置文件)收窄用,同 i18n 的 `isLang()` */
|
|
1726
|
+
declare function isCurrency(value: string): value is Currency;
|
|
1727
|
+
/**
|
|
1728
|
+
* 展示币种 + 汇率。**两格都必填**,因为少任何一格这一份都没有意义:
|
|
1729
|
+
* 只有 `code` 换不出数,只有 `rate` 印不出符号。
|
|
1730
|
+
*
|
|
1731
|
+
* 写成一个对象而不是两个平行可选字段,就是为了让「要么都没有、要么都有」
|
|
1732
|
+
* 由**结构本身**保证,而不是靠一条 refine 和一句注释 —— 判据同
|
|
1733
|
+
* `WireConfigResponse.maxCostUsd` 那条「没配就没有这个键」。
|
|
1734
|
+
*/
|
|
1735
|
+
interface CurrencyDisplay {
|
|
1736
|
+
readonly code: Currency;
|
|
1737
|
+
/**
|
|
1738
|
+
* **1 美元 = 多少目标币**。必须为正。
|
|
1739
|
+
*
|
|
1740
|
+
* ⚠️ 方向别反了。反了不会红,只会让所有金额小两个数量级 —— 而「成本看起来
|
|
1741
|
+
* 很便宜」是这个仓里最不想要的那一类静默错误(同 `pricing.ts` 文件头那条
|
|
1742
|
+
* 「0 意味着免费,undefined 意味着不知道」的精神)。
|
|
1743
|
+
*
|
|
1744
|
+
* ⚠️ **没有默认值,也不去联网抓。** 一个写死在代码里的 `7.1` 会在第一个月就
|
|
1745
|
+
* 开始撒谎,而抓汇率意味着这个仓要多一个外部依赖、一条离线降级路径和一份缓存 ——
|
|
1746
|
+
* 判据同方案 42 §三那条范围闸门(「要一台我们运维的服务器 → 不做」)。
|
|
1747
|
+
* 用户自己填一个他认的数,是这件事唯一诚实的形态。
|
|
1748
|
+
*/
|
|
1749
|
+
readonly rate: number;
|
|
1750
|
+
}
|
|
1751
|
+
/**
|
|
1752
|
+
* 小数位。
|
|
1753
|
+
*
|
|
1754
|
+
* - 给数字 = 定死几位。调用点为什么各要各的,见 {@link formatMoney} 那张表;
|
|
1755
|
+
* - `'adaptive'` = 不到 0.01 时给四位,否则两位。
|
|
1756
|
+
*/
|
|
1757
|
+
type MoneyDigits = number | 'adaptive';
|
|
1758
|
+
interface FormatMoneyOptions {
|
|
1759
|
+
/** 缺席 = 美元原样印,**输出与这次改动之前逐字节相同**(见文件头最后一节) */
|
|
1760
|
+
currency?: CurrencyDisplay | undefined;
|
|
1761
|
+
/** 缺省 `'adaptive'` —— 那是 core 那份 `formatUsd` 的历史行为 */
|
|
1762
|
+
digits?: MoneyDigits;
|
|
1763
|
+
}
|
|
1764
|
+
/**
|
|
1765
|
+
* 把一笔**美元**金额印成给人看的一串字。
|
|
1766
|
+
*
|
|
1767
|
+
* @param usd 金额,单位恒为美元(见文件头那张表第一行)
|
|
1768
|
+
*
|
|
1769
|
+
* ## 各调用点的 `digits` 为什么不统一
|
|
1770
|
+
*
|
|
1771
|
+
* 收敛的是**符号和换算**,不是精度 —— 精度的差异是逐处判过的,收成一个数会
|
|
1772
|
+
* 当场弄坏其中几处:
|
|
1773
|
+
*
|
|
1774
|
+
* | 处 | 位数 | 判据 |
|
|
1775
|
+
* | --- | --- | --- |
|
|
1776
|
+
* | TUI `/cost`、web 花费页那一列 | 4 | 单轮成本常是 $0.003,两位会印成一个「免费」的假象 |
|
|
1777
|
+
* | 侧栏那条比值的分子 | 3 | 那一格答的是「离天花板多远」,不是「这一笔多少」 |
|
|
1778
|
+
* | TUI 状态栏「余」 | 2 | 同上,它是个余量不是账 |
|
|
1779
|
+
* | core 收尾摘要 / 闸门文案 | `'adaptive'` | 小额给四位,大额给两位 |
|
|
1780
|
+
*
|
|
1781
|
+
* ⚠️ **换币种不改位数。** `rate` 是 7 的时候「四位」印出来的有效数字确实比美元多
|
|
1782
|
+
* 一位,那是对的 —— 那一列存在的理由是让人竖着扫出哪一轮贵,而不是凑齐有效数字。
|
|
1783
|
+
* 真按币种调位数的话,同一个界面在两台机器上会有两种列宽,而没有任何用例盖得住。
|
|
1784
|
+
*/
|
|
1785
|
+
declare function formatMoney(usd: number, opts?: FormatMoneyOptions): string;
|
|
1786
|
+
|
|
1619
1787
|
/**
|
|
1620
1788
|
* 宿主自定义的侧栏菜单项(2026-09-02)—— **一个形状,两个键**(2026-09-07 拆开)。
|
|
1621
1789
|
*
|
|
@@ -2051,7 +2219,13 @@ interface EpochConfig {
|
|
|
2051
2219
|
enabled?: boolean;
|
|
2052
2220
|
/**
|
|
2053
2221
|
* 提示词占到上下文窗口的**几成**时开始压缩,`(0, 1]`。
|
|
2054
|
-
* 缺省 = core 的 `DEFAULT_COMPRESSION_THRESHOLD`(0.
|
|
2222
|
+
* 缺省 = core 的 `DEFAULT_COMPRESSION_THRESHOLD`(2026-09-11 起是 **0.8**,
|
|
2223
|
+
* 在那之前是 0.5),**默认值只有那一处** —— 这儿写出来的数只是给读文档的人,
|
|
2224
|
+
* 别照着它在代码里写第二份(判据在那个常量上)。
|
|
2225
|
+
*
|
|
2226
|
+
* ⚠️ 它是**软线**,管的是省钱:越线之后压不压还要过冷却期和熔断。
|
|
2227
|
+
* 「这一发还发得出去吗」是另一条硬线 {@link OVERSIZE_RATIO}(0.9,冷却期让路),
|
|
2228
|
+
* 两条别混成一条 —— 判据全文在 {@link isPromptOversize} 上那张表里。
|
|
2055
2229
|
*
|
|
2056
2230
|
* 判的是 {@link promptTokens}(非缓存 + 缓存命中 + 缓存写入),
|
|
2057
2231
|
* **不是** `usage.inputTokens`:缓存命中的那部分照样占窗口。
|
|
@@ -2059,6 +2233,54 @@ interface EpochConfig {
|
|
|
2059
2233
|
*/
|
|
2060
2234
|
threshold?: number;
|
|
2061
2235
|
};
|
|
2236
|
+
/**
|
|
2237
|
+
* 长期记忆的三个配额(`MEMORY.md` / `USER.md`,core 的 `memory/manager.ts`)。
|
|
2238
|
+
*
|
|
2239
|
+
* ## 这一段 2026-09-10 才有,而在它之前那三个数是**写死的**
|
|
2240
|
+
*
|
|
2241
|
+
* 原来 `defaultMemoryConfig()` 里躺着 `2200 / 1375` 两个字面量,
|
|
2242
|
+
* `MemoryManager` 的构造函数只收 `dbPath` / `memDir` —— 也就是说
|
|
2243
|
+
* **`MemoryConfig` 这个类型存在,但没有任何人给得出一个非默认值**。
|
|
2244
|
+
* 用户抱怨「记忆才两千字,而且设置里改不了」,说的是同一件事的两面。
|
|
2245
|
+
*
|
|
2246
|
+
* 那两个数是从 Hermes 抄的(`hermes_cli/config_defaults.py` 的
|
|
2247
|
+
* `memory_char_limit: 2200` / `user_char_limit: 1375`,注释写着「~800 tokens
|
|
2248
|
+
* at 2.75 chars/token」)。⚠️ **那个换算是按英文估的**:中文里 1 字符差不多
|
|
2249
|
+
* 就是 1 token,于是同样一份配额,中文用户实际拿到的空间只有英文用户的三分之一,
|
|
2250
|
+
* 而屏幕上两边印的是同一个数。
|
|
2251
|
+
*
|
|
2252
|
+
* ## ⚠️ 三个数里有两类,别按「都是上限」合并理解
|
|
2253
|
+
*
|
|
2254
|
+
* | 键 | 管的是 | 花不花每轮的 token |
|
|
2255
|
+
* | ----------------- | ------------------ | ---------------------------- |
|
|
2256
|
+
* | `memoryCharLimit` | **能存多少** | 不花(正文不进 prompt) |
|
|
2257
|
+
* | `userCharLimit` | **能存多少** | 不花 |
|
|
2258
|
+
* | `indexCharLimit` | **每轮固定花多少** | 花 —— 它就是那一笔开销本身 |
|
|
2259
|
+
*
|
|
2260
|
+
* 这条区分是 2026-09-10 那一轮结构改造带来的,在那之前它不成立:原来整个
|
|
2261
|
+
* 记忆库是**全量冻结注入 system prompt** 的,于是「存多少」和「每轮烧多少」
|
|
2262
|
+
* 是同一个数,两件事挤在一个旋钮上 —— 想多存就必须多烧,这正是那两个数
|
|
2263
|
+
* 一直不敢往上调的原因。现在 system prompt 里只有一份索引(每条一行:
|
|
2264
|
+
* id + 首行摘要 + 字数),正文靠 `memory` 工具的 `search` / `read` 按需取
|
|
2265
|
+
* (形状对齐 codex 的 `codex-rs/ext/memories`)。
|
|
2266
|
+
*
|
|
2267
|
+
* 所以调 `memoryCharLimit` 是**几乎免费**的,调 `indexCharLimit` 才是花钱的那个。
|
|
2268
|
+
* 把这两件事读反了会得出一个错的结论:「记忆库调大 = 每轮变贵」。
|
|
2269
|
+
*/
|
|
2270
|
+
memory?: {
|
|
2271
|
+
/** `MEMORY.md`(项目知识)能存多少字符。缺省见 core 的 `defaultMemoryConfig()` */
|
|
2272
|
+
memoryCharLimit?: number;
|
|
2273
|
+
/** `USER.md`(用户画像)能存多少字符 */
|
|
2274
|
+
userCharLimit?: number;
|
|
2275
|
+
/**
|
|
2276
|
+
* 注入 system prompt 的**索引块**字符上限 —— 这是三个数里唯一按轮计费的那个。
|
|
2277
|
+
*
|
|
2278
|
+
* 超了不是报错也不是静默截断:索引按「用得多的排前面」取到装不下为止,
|
|
2279
|
+
* 剩下的在块尾如实印一句「还有 N 条未列出」,并指向 `memory action=search`。
|
|
2280
|
+
* 静默丢掉是这里最不该干的事 —— 模型会以为它看到的就是全部。
|
|
2281
|
+
*/
|
|
2282
|
+
indexCharLimit?: number;
|
|
2283
|
+
};
|
|
2062
2284
|
/** 非交互(CI / 管道)下的策略。默认全空 = 一律拒绝 */
|
|
2063
2285
|
headless?: {
|
|
2064
2286
|
/** 预授权的工具名。只在 !stdin.isTTY 时生效 */
|
|
@@ -2211,6 +2433,18 @@ interface EpochConfig {
|
|
|
2211
2433
|
* warn 诊断然后回落 —— **不是报错退出**,配置写错不该让 agent 起不来。
|
|
2212
2434
|
*/
|
|
2213
2435
|
language?: Lang;
|
|
2436
|
+
/**
|
|
2437
|
+
* 屏幕上那些金额印成什么币种。**缺省 = 美元。**
|
|
2438
|
+
*
|
|
2439
|
+
* 它和 `language` 并排放在这一段是因为两者是同一类东西:**纯粹的显示偏好,
|
|
2440
|
+
* 一个字都进不了引擎**。金额的算术、落盘、闸门比较、以及用户输进来的
|
|
2441
|
+
* 每一格(`budget.maxCostUsd` 那些)**恒为美元** —— 判据全文在
|
|
2442
|
+
* [money.ts](./money.ts) 文件头那张表。
|
|
2443
|
+
*
|
|
2444
|
+
* `code` / `rate` 两格都必填(`rate` = 1 美元兑多少目标币),要么整段不配、
|
|
2445
|
+
* 要么两格都给:只给 `code` 会印出一个换了符号没换数的假读数。
|
|
2446
|
+
*/
|
|
2447
|
+
currency?: CurrencyDisplay;
|
|
2214
2448
|
};
|
|
2215
2449
|
/**
|
|
2216
2450
|
* 宿主品牌词标([决定 19](../../../design/web-ui/README.md))。**缺省 = 界面上什么都不显示。**
|
|
@@ -3526,6 +3760,19 @@ type AgentEvent =
|
|
|
3526
3760
|
* 「这一轮到底是谁答的」正是那时候用户最需要知道的一件事。
|
|
3527
3761
|
*/
|
|
3528
3762
|
model?: string;
|
|
3763
|
+
/**
|
|
3764
|
+
* 最后一次模型调用**要求**的那个模型(`GenerateOutput.requestedModel`)。
|
|
3765
|
+
*
|
|
3766
|
+
* 和上面的 {@link model} 是一对,宿主要的那个事实是**两者是否相等** ——
|
|
3767
|
+
* 不等 = 引擎降级了,相等 = 用户/命令自己挑的。
|
|
3768
|
+
*
|
|
3769
|
+
* ⚠️ **读侧不许拿 `model` 去和「当前配置/当前选择」比来代替这个判断。**
|
|
3770
|
+
* 那是一个按**此刻**的值,而这条断言是按**轮**的 —— 它会被拿去比对所有
|
|
3771
|
+
* 历史轮,于是用户在顶栏换一次模型,之前那些跑得好好的轮子集体变成
|
|
3772
|
+
* 「故障转移」。web 脚注那枚徽标栽过这一次,判据全文在
|
|
3773
|
+
* `core/src/provider/types.ts` 的 `GenerateOutput.requestedModel` 上。
|
|
3774
|
+
*/
|
|
3775
|
+
requestedModel?: string;
|
|
3529
3776
|
breach?: BudgetBreach;
|
|
3530
3777
|
}
|
|
3531
3778
|
/**
|
|
@@ -3634,7 +3881,72 @@ type NoticeCode =
|
|
|
3634
3881
|
* ⚠️ 走 `notice` 而不是 `text-delta`,判据同上面 `skill-learned` 那三条:
|
|
3635
3882
|
* 它不是模型说的话,塞进正文就会进历史、进落盘、下一轮再进模型。
|
|
3636
3883
|
*/
|
|
3637
|
-
| 'response-truncated'
|
|
3884
|
+
| 'response-truncated'
|
|
3885
|
+
/**
|
|
3886
|
+
* 这一条消息发出去之前,**上下文被自动压了一次**(2026-09-10)。
|
|
3887
|
+
*
|
|
3888
|
+
* ## 没有这一帧的话,用户看到的是「它忘了我们刚才聊的」
|
|
3889
|
+
*
|
|
3890
|
+
* 自动压缩是有损的:摘要替掉了早期几十轮的原文。屏幕上那段对话还在
|
|
3891
|
+
* (宿主回显的是自己那份记录),而模型手上只剩摘要 —— 于是它接下来那句
|
|
3892
|
+
* 「你之前说的那个方案」答得对不上,而**没有任何线索**说过发生了什么。
|
|
3893
|
+
* 这一帧就是那个线索,也是「为什么这一轮多花了一笔」的唯一出处。
|
|
3894
|
+
*
|
|
3895
|
+
* ⚠️ 走 `notice` 而不是 `text-delta`,判据同 `skill-learned`:它不是模型说的话,
|
|
3896
|
+
* 塞进正文就会进历史、进落盘、下一轮再进模型。
|
|
3897
|
+
*
|
|
3898
|
+
* ⚠️ **两个位置都发这一帧,语义相同**(都是「这一发之前压了」):
|
|
3899
|
+
* `AgentSession` 跑前那道(软线,压完写回会话历史)和 `AgentLoop` 送出前那道
|
|
3900
|
+
* (硬线,见 protocol 的 `isPromptOversize`)。不给它们分两档码是因为
|
|
3901
|
+
* 用户要知道的是同一件事,而「哪道闸判的」是我们的实现细节。
|
|
3902
|
+
*/
|
|
3903
|
+
| 'context-compacted'
|
|
3904
|
+
/**
|
|
3905
|
+
* 这个模型认不认图,**我们查不到,正在现问它本人**(2026-09-11)。
|
|
3906
|
+
*
|
|
3907
|
+
* ## 为什么这一次探测必须说出来
|
|
3908
|
+
*
|
|
3909
|
+
* 它是**用户没要求过的一次额外请求**:多一趟往返(约两秒)、多一笔约 225 token
|
|
3910
|
+
* 的账。屏幕上那段静默否则解释不了 —— 用户发了张图,等了两秒,什么都没有。
|
|
3911
|
+
*
|
|
3912
|
+
* 判据同上面几条:多花的钱和多等的时间,只要不是用户自己点的,就欠一句旁白。
|
|
3913
|
+
*
|
|
3914
|
+
* ⚠️ **一次探测最多两帧**(「正在问」+ 只在**认图**时补一句「确认认图」):
|
|
3915
|
+
* 不认图那一路后面紧跟着 `error` 帧,那句话已经把结论说全了,再发一帧确认
|
|
3916
|
+
* 就是同一件事说两遍。
|
|
3917
|
+
*
|
|
3918
|
+
* ⚠️ 每个型号**一辈子只探一次**(结论进 `~/.epoch/cache/model_probe.json`,
|
|
3919
|
+
* 认图存 30 天、不认图存 24 小时),所以这一帧天然罕见。要是它开始每轮都出现,
|
|
3920
|
+
* 说明缓存写不进去(只读的 home),那是个 bug,不是这一帧的问题。
|
|
3921
|
+
*/
|
|
3922
|
+
| 'image-probe'
|
|
3923
|
+
/**
|
|
3924
|
+
* **历史里**那几张图被摘掉了,因为此刻这个模型不认图(2026-09-12)。
|
|
3925
|
+
*
|
|
3926
|
+
* ## 和上面 `images-dropped`、和 `agent_run.images_unsupported` 三者的分工
|
|
3927
|
+
*
|
|
3928
|
+
* | | 图从哪来 | 谁判的 | 请求 | 钱 |
|
|
3929
|
+
* | --- | --- | --- | --- | --- |
|
|
3930
|
+
* | `images_unsupported`(`error` 帧) | **这一轮新发的** | 我们(闸门 1) | 不发 | 没花 |
|
|
3931
|
+
* | 这一条(`notice` 帧) | **历史里的** | 我们(装 history 时) | 照发 | 花了,但图不占 token |
|
|
3932
|
+
* | `images-dropped`(`notice` 帧) | 这一轮新发的 | **provider 的 warning** | 已发 | 花了 |
|
|
3933
|
+
*
|
|
3934
|
+
* 第一行是「你现在做的这件事做不了」,用户当场能改(换模型 / 去掉图);
|
|
3935
|
+
* 这一条是「你**以前**做的那件事,从现在起看不见了」—— 他此刻什么都没做,
|
|
3936
|
+
* 所以更需要一句旁白。
|
|
3937
|
+
*
|
|
3938
|
+
* ## 没有这一帧的话,这件事是彻底静默的
|
|
3939
|
+
*
|
|
3940
|
+
* 触发面是两个:`epoch --resume` 装一段贴过图的会话(启动路径上**没有任何
|
|
3941
|
+
* 能力检查**),以及 `/model` 切到一个能力**查不到**的型号
|
|
3942
|
+
* (`provider/selection.ts` 那条硬拒绝只挡查得到不认图的)。两条路上用户都
|
|
3943
|
+
* 没有再发图,于是屏幕上不会有任何东西提到图 —— 而模型接下来那句
|
|
3944
|
+
* 「你发的那张截图我看不到」会像是它在犯病。
|
|
3945
|
+
*
|
|
3946
|
+
* ⚠️ **一次 run 只发一帧**,判据逐字同 `images-dropped`:那几张历史图在这次
|
|
3947
|
+
* run 的每一轮都要重新摘一次,逐轮报的话一次多工具调用的对话会刷出十几行。
|
|
3948
|
+
*/
|
|
3949
|
+
| 'history-images-stripped';
|
|
3638
3950
|
type AgentEventType = AgentEvent['type'];
|
|
3639
3951
|
/** 取出某个具体事件的类型,例如 AgentEventOf<'tool-call'> */
|
|
3640
3952
|
type AgentEventOf<T extends AgentEventType> = Extract<AgentEvent, {
|
|
@@ -4441,6 +4753,32 @@ type TrustScope =
|
|
|
4441
4753
|
'directory'
|
|
4442
4754
|
/** 这个目录及其所有子目录 */
|
|
4443
4755
|
| 'directory-tree';
|
|
4756
|
+
/**
|
|
4757
|
+
* 一次授信授到哪一档(2026-09-11)。**两档是相加的:`exec` 蕴含 `read`。**
|
|
4758
|
+
*
|
|
4759
|
+
* ## 为什么拆
|
|
4760
|
+
*
|
|
4761
|
+
* 在它之前 `trusted` 是一个布尔,而那一个布尔后面挂着七样东西 —— 其中
|
|
4762
|
+
* `.epoch/hooks.json` 和 `.claude/settings.json` 的每一项都是一条要 spawn 子进程的
|
|
4763
|
+
* 命令(判据在 [core/hook/sources.ts](../../core/src/hook/sources.ts) 的文件头)。
|
|
4764
|
+
* 而用户被问到的那句话逐字是「本目录的项目指令会加载」(`trust_prompt.granted`),
|
|
4765
|
+
* **从来没提过 hook**。也就是说「往上下文里注入一段文本」和「在这台机器上执行
|
|
4766
|
+
* 任意命令」共用了同一次点击,而问话只描述了前者。这不是 UX 问题,是知情同意错位。
|
|
4767
|
+
*
|
|
4768
|
+
* | 档 | 放开什么 | 风险 |
|
|
4769
|
+
* | --- | --------------------------------------------------------------- | ---------- |
|
|
4770
|
+
* | `read` | 指令文件 / 技能 / 角色 / 命令 | 注入上下文 |
|
|
4771
|
+
* | `exec` | `hooks.json` / `.claude/settings*.json` / `policies/` / settings 的 allow 那一半 | 执行、放宽判定 |
|
|
4772
|
+
*
|
|
4773
|
+
* ## ⚠️ 两条边界,别把它当别的东西
|
|
4774
|
+
*
|
|
4775
|
+
* 1. **`exec` 不是权限档。** 它放开的是「这个仓库自带的 hook / policy 算不算数」,
|
|
4776
|
+
* 不是「这次操作要不要问用户」——[两套机制照旧正交](../../core/src/trust/gate.ts)。
|
|
4777
|
+
* 未授 `exec` 的目录里 agent 照样能跑 bash,只是仓库里那份 `hooks.json` 不生效;
|
|
4778
|
+
* 2. **`read` 不是「安全档」。** 一份 `AGENTS.md` 能指挥 agent 去做任何它有权限做的
|
|
4779
|
+
* 事,包括执行命令。拆开不是因为 `read` 无害,是因为**两者的问话不该合并成一次**。
|
|
4780
|
+
*/
|
|
4781
|
+
type TrustTier = 'read' | 'exec';
|
|
4444
4782
|
interface TrustRecord {
|
|
4445
4783
|
/** 绝对路径(已 resolve) */
|
|
4446
4784
|
path: string;
|
|
@@ -4455,12 +4793,77 @@ interface TrustRecord {
|
|
|
4455
4793
|
scope: TrustScope;
|
|
4456
4794
|
/** 记录时间戳(ms) */
|
|
4457
4795
|
decidedAt: number;
|
|
4796
|
+
/**
|
|
4797
|
+
* 执行类也授了吗({@link TrustTier})。`level: 'untrusted'` 时无意义。
|
|
4798
|
+
*
|
|
4799
|
+
* ⚠️ **缺省(`undefined`)= 没授**,而这一格正是存量记录的迁移:拆档之前写下的
|
|
4800
|
+
* 记录没有这一格,于是升级之后它们**只剩读类** —— 判据就是上面那张表下面那段:
|
|
4801
|
+
* 那些记录是在一句只说了「项目指令会加载」的问话下拿到的,把它们追认成执行类
|
|
4802
|
+
* 等于替用户补签一份他没看过的同意书。代价(老用户的项目 hook 会停)由
|
|
4803
|
+
* `trust_gate.exec_migrated` 那条诊断明说,不静默。
|
|
4804
|
+
*/
|
|
4805
|
+
exec?: boolean;
|
|
4806
|
+
/**
|
|
4807
|
+
* 授 `exec` 那一刻,执行类输入文件的内容指纹(见 core 的 `trust/exec-hash.ts`)。
|
|
4808
|
+
*
|
|
4809
|
+
* 对不上 = 那些文件在授信之后被改过 → `exec` 退回未授,重新问一次。
|
|
4810
|
+
* `exec` 为假时这一格不该存在。
|
|
4811
|
+
*
|
|
4812
|
+
* ## ⚠️ 这是对 [manager.ts](../../core/src/trust/manager.ts) 文件头「两条明确不做」
|
|
4813
|
+
* 第 2 条的一次**窄口推翻**,不是把它作废
|
|
4814
|
+
*
|
|
4815
|
+
* 那一条 2026-08-08 写着:记内容 hash「代价是『改一行 AGENTS.md 就被打断一次』,
|
|
4816
|
+
* 这个打断比它挡住的风险更贵」。**那个结论在读类上照旧成立,一个字不改** ——
|
|
4817
|
+
* 指令文件天天在动,为它记 hash 会把授信变成一件每天都要重做的事。
|
|
4818
|
+
*
|
|
4819
|
+
* 翻的只有执行类那一半,因为它的两项输入都变了:
|
|
4820
|
+
*
|
|
4821
|
+
* | | 读类(AGENTS.md) | 执行类(hooks.json / policies) |
|
|
4822
|
+
* | --- | ---------------------- | -------------------------------- |
|
|
4823
|
+
* | 改动频率 | 每天 | 几乎不动 |
|
|
4824
|
+
* | 改动后果 | 多一段文本 | **多一条会跑的命令** |
|
|
4825
|
+
*
|
|
4826
|
+
* 也就是说,同一个做法在这一侧的打断成本低一个量级、挡住的东西贵一个量级。
|
|
4827
|
+
* 参照物:codex 对 hook 记 `trusted_hash`(`codex-rs/config/src/hook_config.rs`),
|
|
4828
|
+
* 而它的 `AGENTS.md` 压根不过闸门 —— 同一条判据的两侧,它也是这么分的。
|
|
4829
|
+
*/
|
|
4830
|
+
execHash?: string;
|
|
4831
|
+
}
|
|
4832
|
+
/** {@link TrustManager.record} 的可选档位。不给 = 只授读类 */
|
|
4833
|
+
interface TrustGrant {
|
|
4834
|
+
/** 连执行类一起授。**调用方必须真的为这一档单独问过用户** */
|
|
4835
|
+
exec?: boolean;
|
|
4836
|
+
/** 授 `exec` 时一并记下的内容指纹 */
|
|
4837
|
+
execHash?: string;
|
|
4838
|
+
}
|
|
4839
|
+
/**
|
|
4840
|
+
* {@link TrustManager.checkExec} 的答案 —— **记录里写的,不含新鲜度校验**。
|
|
4841
|
+
*
|
|
4842
|
+
* 两格一起交出来是因为校验方(`core/src/trust/gate.ts`)需要拿 {@link hash} 去和
|
|
4843
|
+
* 现算的值比;拆成两次调用的话,两次之间可能命中**不同的记录**
|
|
4844
|
+
* (`bestRecord()` 是按最长匹配现算的),于是拿 A 记录的授信配上 B 记录的指纹。
|
|
4845
|
+
*/
|
|
4846
|
+
interface TrustExecGrant {
|
|
4847
|
+
/** 记录里授过执行类吗 */
|
|
4848
|
+
granted: boolean;
|
|
4849
|
+
/**
|
|
4850
|
+
* 授的时候记下的内容指纹。
|
|
4851
|
+
*
|
|
4852
|
+
* ⚠️ **`undefined` = 校验不了,而这一档照旧放行**(判据在 gate 的 `decide()` 上)。
|
|
4853
|
+
* 今天所有写入口都会带上它,所以这一档只可能来自手改 `trust.json`。
|
|
4854
|
+
*/
|
|
4855
|
+
hash?: string;
|
|
4458
4856
|
}
|
|
4459
4857
|
interface TrustManager {
|
|
4460
4858
|
/** 查某个目录的信任状态(含父目录的 directory-tree 继承) */
|
|
4461
4859
|
check(dir: string): TrustLevel;
|
|
4860
|
+
/**
|
|
4861
|
+
* 查某个目录的执行类授信(含继承)。**和 {@link check} 是两个问题**:
|
|
4862
|
+
* 这一个只在 `check()` 回 `'trusted'` 时才可能授过,反过来不成立。
|
|
4863
|
+
*/
|
|
4864
|
+
checkExec(dir: string): TrustExecGrant;
|
|
4462
4865
|
/** 记录一次决策 */
|
|
4463
|
-
record(dir: string, level: DecidedTrustLevel, scope: TrustScope): void;
|
|
4866
|
+
record(dir: string, level: DecidedTrustLevel, scope: TrustScope, grant?: TrustGrant): void;
|
|
4464
4867
|
list(): readonly TrustRecord[];
|
|
4465
4868
|
revoke(dir: string): void;
|
|
4466
4869
|
}
|
|
@@ -4662,6 +5065,37 @@ type EpochUserContent = string | EpochContentPart[];
|
|
|
4662
5065
|
* 那不是「用例过时了」,是你正在改模型的输入契约(判据见 {@link OMIT_LABEL})。
|
|
4663
5066
|
*/
|
|
4664
5067
|
declare function filePartSummary(part: EpochFilePart): string;
|
|
5068
|
+
/**
|
|
5069
|
+
* 历史里的图被**摘掉**之后留在原位的那一行(2026-09-12)。
|
|
5070
|
+
*
|
|
5071
|
+
* ## 它补的是一个静默的口子,不是「又一个占位符」
|
|
5072
|
+
*
|
|
5073
|
+
* 喂模型的历史里图片是 base64 部件(`session-store.loadHistory()` 把
|
|
5074
|
+
* `inlineImages` 写死成 true)。而「当前模型认不认图」那道闸门在
|
|
5075
|
+
* `core/agent/loop.ts` 上,读的是**这一轮用户新发的图**
|
|
5076
|
+
* (`imageParts(input.userMessage)`)—— 也就是说换到一个不认图的模型之后只要
|
|
5077
|
+
* 不再发新图,历史里那些图会原样发出去:provider 那侧要么 400、要么**一声不吭
|
|
5078
|
+
* 地吞掉**(后者实测存在,判据全文在 `core/provider/capability-probe.ts` 的
|
|
5079
|
+
* 文件头)。摘掉它们的是 `AgentLoop`,留下的那一行是这一个。
|
|
5080
|
+
*
|
|
5081
|
+
* ## 为什么不复用 `contentToText` 那个 `[图片 image/jpeg]`
|
|
5082
|
+
*
|
|
5083
|
+
* 那一个是**另一个消费者**的投影(`imagesCarriedAsParts: false`,喂压缩器 /
|
|
5084
|
+
* 审计 / `messages.content` 那一列),而且它有前科:图片真的送达之后,它成了
|
|
5085
|
+
* 「唯一还在撒谎的地方」(判据在 {@link ContentToTextOptions.imagesCarriedAsParts})。
|
|
5086
|
+
* 这一行要说的是另一件事 —— 图**确实没给它**,以及为什么。
|
|
5087
|
+
*
|
|
5088
|
+
* 措辞里带上「不支持」这半句,判据同 `agent/prompt.ts` 里那条
|
|
5089
|
+
* 「不支持那一档要说清后果,别笼统一句不支持」:只写「图片未附上」的话,
|
|
5090
|
+
* 模型会去猜是不是传坏了,然后建议用户重发一次 —— 而重发多少次都一样。
|
|
5091
|
+
*
|
|
5092
|
+
* ⚠️ **不给「你可以自己去读」这类下一步**,和 `OMIT_LABEL` 的 `binary` 那档
|
|
5093
|
+
* 不同:那一档有 `file_read` 真的能拿到内容,这一档模型没有任何办法看见像素。
|
|
5094
|
+
* 给一个不存在的出口,比不给更糟。
|
|
5095
|
+
*
|
|
5096
|
+
* 逐字冻住,理由同 {@link OMIT_LABEL}(进模型 prompt、进 eval 指纹、不进 catalog)。
|
|
5097
|
+
*/
|
|
5098
|
+
declare function imagePartOmittedSummary(part: EpochImagePart): string;
|
|
4665
5099
|
/**
|
|
4666
5100
|
* 引用的会话在纯文本投影里长什么样。**不吐那段会话的正文** —— 同 `filePartSummary`。
|
|
4667
5101
|
*
|
|
@@ -5019,6 +5453,46 @@ declare const MAX_SESSION_ATTACH_BYTES: number;
|
|
|
5019
5453
|
* 那时候用户其实不知道自己要哪一段,而 `session_search` 才是干这个的。
|
|
5020
5454
|
*/
|
|
5021
5455
|
declare const MAX_SESSION_REFS = 2;
|
|
5456
|
+
/**
|
|
5457
|
+
* 把一份读出来的文件收进预算,**切口落在行边界上**(2026-09-13)。
|
|
5458
|
+
*
|
|
5459
|
+
* ## 为什么两条产出路径必须共用这一个函数
|
|
5460
|
+
*
|
|
5461
|
+
* 附件有两条来路 —— 拖进输入框(`server/src/attachments.ts` 的 `readOne`)和
|
|
5462
|
+
* `@路径`(`core/src/context/mentions.ts` 的 `readOneFile`)。两边原来各写了一遍
|
|
5463
|
+
* `raw.slice(0, budget)`,注释里互相写着「判据逐字同对方」—— 那句话本身就是在说
|
|
5464
|
+
* 「这里会走散」。现在切法只有一处,两边各自只剩「读文件」和「装 part」。
|
|
5465
|
+
*
|
|
5466
|
+
* ## 为什么从字节切改成行边界
|
|
5467
|
+
*
|
|
5468
|
+
* 原来按字节硬切,代价有两个,都是**给模型的那一侧**才暴露:
|
|
5469
|
+
*
|
|
5470
|
+
* 1. **最后一行是残的。** 一份 CSV 被切在某个字段中间,模型读到的最后一条记录
|
|
5471
|
+
* 少了几列 —— 而它长得和一条完好的记录一模一样。它不会因此报错,会**把残行
|
|
5472
|
+
* 当成数据算进去**;
|
|
5473
|
+
* 2. **接不上。** 模型要接着读得调 `file_read`,而那个工具的 `offset` 单位是**行**。
|
|
5474
|
+
* 切在字节上的话,「我读到哪儿了」这个问题在两套单位之间没有答案,它只能
|
|
5475
|
+
* `offset=1` 从头再读一遍 —— 前 100 KB 在上下文里存两份。
|
|
5476
|
+
* 收在行边界之后,`filePartSummary` 数一下换行就能报出**准确的接续行号**。
|
|
5477
|
+
*
|
|
5478
|
+
* 切口**包含那个换行符**(`slice(0, at + 1)`):这样「正文里的换行数」正好等于
|
|
5479
|
+
* 「完整行数」,接续行号恒等于 `换行数 + 1`,两种分支都不用分情况讨论。
|
|
5480
|
+
*
|
|
5481
|
+
* ## 退回硬切的那一支
|
|
5482
|
+
*
|
|
5483
|
+
* 压缩过的 JSON、单行 CSV、minify 过的 js —— 前 100 KB 里可能一个换行都没有,
|
|
5484
|
+
* 或者只有很靠前的几个。退到行边界会丢掉大半,那时候硬切才是对的。
|
|
5485
|
+
* 阈值取「丢掉超过一半就不退」,判据逐字同 plugin-file 的 `truncateOutput`。
|
|
5486
|
+
*
|
|
5487
|
+
* 只解码 `budget` 这一段,不碰整个文件 —— 原来那句「比按字符数切省一次全量解码」
|
|
5488
|
+
* 说的是这件事,仍然成立(文件可能是 200 MB,这里最多摸 100 KB)。
|
|
5489
|
+
* 留下的那一段要**重新量一次字节**:退回行边界之后真正附上的比 `budget` 少,
|
|
5490
|
+
* 而 `truncatedTo` 既要印给用户看(KB)又要算占比,不能是个约数。
|
|
5491
|
+
*/
|
|
5492
|
+
declare function truncateToBudget(raw: Uint8Array, budget: number): {
|
|
5493
|
+
text: string;
|
|
5494
|
+
truncatedTo: number;
|
|
5495
|
+
};
|
|
5022
5496
|
/**
|
|
5023
5497
|
* 当前面里的一条消息。
|
|
5024
5498
|
*
|
|
@@ -5399,6 +5873,49 @@ declare function compressionThresholdTokens(contextLength: number, threshold: nu
|
|
|
5399
5873
|
* @param prompt 这一轮的提示词大小,取 {@link promptTokens}(**不是** `usage.inputTokens`)
|
|
5400
5874
|
*/
|
|
5401
5875
|
declare function isContextNearlyFull(prompt: number, contextLength: number, threshold: number): boolean;
|
|
5876
|
+
/**
|
|
5877
|
+
* {@link isPromptOversize} 那条硬线占窗口的比例。判据全文在那个函数上。
|
|
5878
|
+
*
|
|
5879
|
+
* 导出是因为用例要按它算边界值 —— 用例里另写一个 `0.9` 的话,调这个数的人
|
|
5880
|
+
* 不会看到任何东西变红。
|
|
5881
|
+
*/
|
|
5882
|
+
declare const OVERSIZE_RATIO = 0.9;
|
|
5883
|
+
/**
|
|
5884
|
+
* 「再发出去就要撞窗口了」的那条**硬线**(2026-09-10)。
|
|
5885
|
+
*
|
|
5886
|
+
* 和 {@link isContextNearlyFull} 是两条线,别混成一条 —— 它们回答的是两个问题:
|
|
5887
|
+
*
|
|
5888
|
+
* | 线 | 问的是 | 越线之后 |
|
|
5889
|
+
* | ------------------------- | -------------------- | ------------------------------------------ |
|
|
5890
|
+
* | `isContextNearlyFull` | 该压了吗(省钱) | 压一次,**冷却期和熔断说不压就不压** |
|
|
5891
|
+
* | 这一条(`OVERSIZE_RATIO`)| 这一发还发得出去吗 | 必须压,**冷却期让路**(判据见下) |
|
|
5892
|
+
*
|
|
5893
|
+
* ## 为什么非要第二条线
|
|
5894
|
+
*
|
|
5895
|
+
* 压缩器那两道闸(冷却期 5 轮、连续失败 3 次熔断)都是**省钱**用的,而它们
|
|
5896
|
+
* 「只会让压缩更晚发生」这条性质在软线上是安全的、在窗口边缘上不是:一个刚起的
|
|
5897
|
+
* 进程 `turnsSinceCompress` 是 0,于是 `--resume` 接回一段很长的会话之后,
|
|
5898
|
+
* **头 5 发请求一次都不压** —— 而第 1 发就是最大的那一发。撞上去的代价不是
|
|
5899
|
+
* 「多花一次钱」,是这段会话从此每条消息都 400(`classifyProviderError` 判
|
|
5900
|
+
* `1030` / `abort`,没有任何地方接住它去压一次重发),只有手动 `/compact` 能救。
|
|
5901
|
+
*
|
|
5902
|
+
* 所以这条线上的取舍反过来:**宁可白花一次摘要,也不要撞墙。**
|
|
5903
|
+
*
|
|
5904
|
+
* ## 0.9 是怎么定的
|
|
5905
|
+
*
|
|
5906
|
+
* 留一成给「量不准的那部分」:喂进来的数在第一发请求上是**估出来的**
|
|
5907
|
+
* (provider 还没报过任何数,见 `agent/run-estimate.ts`),而那个估算走的是
|
|
5908
|
+
* `o200k_base`,模型可能是 Claude / DeepSeek;这一轮跑起来之后还会插进任务通知和
|
|
5909
|
+
* 工具结果。定在 1.0 等于赌估算不偏,而它已知会偏。
|
|
5910
|
+
*
|
|
5911
|
+
* ⚠️ **它拦不住「元数据里的窗口本身是错的」**:`contextLength` 来自能力表
|
|
5912
|
+
* (`services.contextLength`),表错了这条线就画在错的地方。那一档只有 provider
|
|
5913
|
+
* 报回来的 400 说得清,今天仍然没人接(见上面那条「代价」)。
|
|
5914
|
+
*
|
|
5915
|
+
* @param prompt 这一发要送出去的提示词大小。实测值优先,第一发只有估算
|
|
5916
|
+
* @param contextLength 模型**真实**窗口,同 {@link isContextNearlyFull} 的那一格
|
|
5917
|
+
*/
|
|
5918
|
+
declare function isPromptOversize(prompt: number, contextLength: number): boolean;
|
|
5402
5919
|
/**
|
|
5403
5920
|
* 一共用了多少 token。
|
|
5404
5921
|
*
|
|
@@ -5569,6 +6086,32 @@ type WireHubEvent =
|
|
|
5569
6086
|
type: 'stream-reset';
|
|
5570
6087
|
reason: WireResetReason;
|
|
5571
6088
|
}
|
|
6089
|
+
/**
|
|
6090
|
+
* 这个会话的**后台任务清单变了**(方案 36 PR-3):起了一格、结束了一格,
|
|
6091
|
+
* 或者 `/resume` 把它们搬到了别的会话名下。
|
|
6092
|
+
*
|
|
6093
|
+
* ## 纯失效信号,**不带载荷**
|
|
6094
|
+
*
|
|
6095
|
+
* 没有 `total` / `running`,也没有那一格任务本身。收到它的客户端回去打
|
|
6096
|
+
* `GET /api/sessions/:id/tasks` 重取。
|
|
6097
|
+
*
|
|
6098
|
+
* 带 tally 的版本试过在纸上:侧栏那一行能少一次往返,代价是**同一件事有了两个
|
|
6099
|
+
* 真源** —— 这一帧上的两个数,和检视面板那份清单(`collectTasks` 的投影)。
|
|
6100
|
+
* 两者算的是同一批任务,但取样时刻差着一次往返,于是「侧栏说 3 在跑、面板里
|
|
6101
|
+
* 数出来 2 个」是一种可达状态,而没人说得清该信哪个。判据同 `server/src/index.ts`
|
|
6102
|
+
* 里 `observe` / `snapshot` 那一对(「转出去的就是浏览器收到的那条流,
|
|
6103
|
+
* 不是它们的复制品」)。
|
|
6104
|
+
*
|
|
6105
|
+
* ## 它**不管输出**
|
|
6106
|
+
*
|
|
6107
|
+
* 一格任务的输出长长了不发这一帧 —— 判据在 `infra/src/jobs.ts` 的 `notifyJobs`
|
|
6108
|
+
* 上(一个刷屏的 `pnpm dev` 一秒能推几百帧,而它们会把 512 格的全局环形缓冲
|
|
6109
|
+
* 冲干净,断线重连要续的那段真事件就没了)。所以检视面板那格输出尾巴今天
|
|
6110
|
+
* **仍然是快照**,那是另一件事,要做得给它自己的增量帧和每任务游标。
|
|
6111
|
+
*/
|
|
6112
|
+
| {
|
|
6113
|
+
type: 'tasks-changed';
|
|
6114
|
+
}
|
|
5572
6115
|
/**
|
|
5573
6116
|
* 这个会话被**冷却**了(方案 30 §2.3):同时活跃的会话超过上限,
|
|
5574
6117
|
* 它是最久没动过的那个,Hub 侧的状态已经释放。
|
|
@@ -5582,6 +6125,46 @@ type WireHubEvent =
|
|
|
5582
6125
|
*/
|
|
5583
6126
|
| {
|
|
5584
6127
|
type: 'session-cooled';
|
|
6128
|
+
}
|
|
6129
|
+
/**
|
|
6130
|
+
* **会话列表变了** —— 多了一段,或者少了一段(2026-09-11)。
|
|
6131
|
+
*
|
|
6132
|
+
* ## 它治的是「不是我建的那一段」
|
|
6133
|
+
*
|
|
6134
|
+
* 会话列表(`GET /api/sessions`)在这一帧之前**只在自己动手的时候才重取**:
|
|
6135
|
+
* 这个标签页建一段、删一段,它自己重拉。于是任何**别处**建出来的会话在屏幕上
|
|
6136
|
+
* 压根不存在,得刷新一次页面才出现。两种真实情况:
|
|
6137
|
+
*
|
|
6138
|
+
* - **嵌入宿主在后台建的一段**:即时通讯桥收到一条消息 → `POST /api/sessions`
|
|
6139
|
+
* → 那一段开始干活,而电脑上那个界面一无所知(2026-09-11 一个飞书宿主实测:
|
|
6140
|
+
* 用户在手机上发完消息,PC 上看不到那段对话,**重启应用才出现** ——
|
|
6141
|
+
* 「重启才出现」正是这一帧不存在的形状);
|
|
6142
|
+
* - **另一个标签页**建的一段。判据同 `approval-resolved` 那条
|
|
6143
|
+
* (「可能是另一个标签页答的」)。
|
|
6144
|
+
*
|
|
6145
|
+
* ## 纯失效信号,**不带载荷**
|
|
6146
|
+
*
|
|
6147
|
+
* 形状和理由逐字同 `tasks-changed`:收到它的客户端回去打 `GET /api/sessions`
|
|
6148
|
+
* 重取。带上那一行的话同一件事就有了两个真源(这一帧上的一份、那条端点回的
|
|
6149
|
+
* 一份),而那条端点答的是「**侧栏该列哪几段**」—— 它按 `?q=` 过滤、按 50 行
|
|
6150
|
+
* 封顶,也就是说这一帧带来的那一行**未必该出现在列表里**。
|
|
6151
|
+
*
|
|
6152
|
+
* ## ⚠️ 信封上那个 `sessionId` 是「哪一段变了」,**不是这一帧的收件人**
|
|
6153
|
+
*
|
|
6154
|
+
* 所以客户端**不许**按「是不是我正看着的那一段」把它过滤掉 —— 它说的恰好是
|
|
6155
|
+
* 一段你还不知道的会话。web 那一侧因此在分流之前就把它拦下来
|
|
6156
|
+
* (`reducer.ts` 的 `applyFrame`:别的会话的帧会进 `parked`,而 `parkFrame`
|
|
6157
|
+
* 只认 `session-state` / `session-cooled`,别的 Hub 事件在那儿被丢掉)。
|
|
6158
|
+
*
|
|
6159
|
+
* ## ⚠️ 覆盖不到的那一档:**标题改了不发这一帧**
|
|
6160
|
+
*
|
|
6161
|
+
* 它的两个产地都在「进出 Hub」这条路上(建会话、删会话那两条端点)。而改标题
|
|
6162
|
+
* (`PATCH /api/sessions/:id`)压根不经过 Hub,只动 DB —— 于是另一个标签页上
|
|
6163
|
+
* 那一行的标题仍然会过期到下一次重取。📮 那一档要治得给它自己的产地,
|
|
6164
|
+
* 别照着这一帧的名字想当然。
|
|
6165
|
+
*/
|
|
6166
|
+
| {
|
|
6167
|
+
type: 'sessions-changed';
|
|
5585
6168
|
};
|
|
5586
6169
|
/** 信封里能装的所有东西 */
|
|
5587
6170
|
type WireEvent = WireAgentEvent | WireHubEvent;
|
|
@@ -6324,6 +6907,43 @@ interface WireSessionWorkspace extends WireWorkspaceRef {
|
|
|
6324
6907
|
skippedInstructionFiles: readonly string[];
|
|
6325
6908
|
}
|
|
6326
6909
|
declare const WIRE_SESSION_WORKSPACE_FIELDS: WireFields<WireSessionWorkspace>;
|
|
6910
|
+
/**
|
|
6911
|
+
* 一个工作区里**被闸门挡着的东西有多少**(2026-09-11,方案 61 ②)。
|
|
6912
|
+
*
|
|
6913
|
+
* ## 这一份推翻了一句写在隔壁的话
|
|
6914
|
+
*
|
|
6915
|
+
* `wire-capability.ts` 的 `WireCapabilityProject.trusted` 上写着「不能写成
|
|
6916
|
+
* 『已屏蔽 N 个』—— 那个 N 根本不存在,谁也没数过」。那句话在当时是对的:
|
|
6917
|
+
* 闸门那一侧**连 `readdir` 都不做**。现在闸门的下限放宽到了「readdir 但不读
|
|
6918
|
+
* 任何文件内容」,N 真的被数出来了(core 的 `inventoryProjectExtensions`),
|
|
6919
|
+
* 而那句话的约束 —— 不许编一个没人数过的数 —— 一个字没松。
|
|
6920
|
+
*
|
|
6921
|
+
* ## ⚠️ 这份载荷里**没有一个字段装得下仓库作者写的散文**,那是故意的
|
|
6922
|
+
*
|
|
6923
|
+
* 只有个数和路径。没有技能的 `description`、没有 hook 的 `command`、
|
|
6924
|
+
* 没有角色名。判据在 core `trust/inventory.ts` 的文件头,一句话是:
|
|
6925
|
+
* 这份东西会被画在一个用户正要点「信任」的按钮旁边,而那是渲染一段攻击者
|
|
6926
|
+
* 可控的劝说词的**最坏时机**。
|
|
6927
|
+
*
|
|
6928
|
+
* 谁要往这里加一个字符串字段,先回答它是不是仓库作者能写的。
|
|
6929
|
+
*/
|
|
6930
|
+
interface WireProjectInventory {
|
|
6931
|
+
/** 读类:项目指令文件,**相对项目根**的路径 */
|
|
6932
|
+
instructionFiles: readonly string[];
|
|
6933
|
+
/** 读类:`.epoch/skills/` 下的技能个数 */
|
|
6934
|
+
skills: number;
|
|
6935
|
+
/** 读类:`.epoch/agents/` 下的角色个数 */
|
|
6936
|
+
roles: number;
|
|
6937
|
+
/** 读类:`.epoch/commands/` 下的命令个数 */
|
|
6938
|
+
commands: number;
|
|
6939
|
+
/** 执行类:存在的 hook 配置,相对路径(`.epoch/hooks.json` / `.claude/settings*.json`) */
|
|
6940
|
+
hookFiles: readonly string[];
|
|
6941
|
+
/** 执行类:`.epoch/policies/*.toml` 的份数 */
|
|
6942
|
+
policies: number;
|
|
6943
|
+
/** 执行类:存在的项目设置文件,相对路径 */
|
|
6944
|
+
settingsFiles: readonly string[];
|
|
6945
|
+
}
|
|
6946
|
+
declare const WIRE_PROJECT_INVENTORY_FIELDS: WireFields<WireProjectInventory>;
|
|
6327
6947
|
/**
|
|
6328
6948
|
* 引擎**自动压缩**的那条线 —— 三个数,决定 8 的第三个时刻(「快满了」)要的全部输入。
|
|
6329
6949
|
*
|
|
@@ -6534,6 +7154,27 @@ interface WireConfigResponse {
|
|
|
6534
7154
|
* 给一份将来会长歪的副本。
|
|
6535
7155
|
*/
|
|
6536
7156
|
maxCostUsd?: number;
|
|
7157
|
+
/**
|
|
7158
|
+
* 屏幕上那些金额印成什么币种 —— **没配就没有这个键**(2026-09-13)。
|
|
7159
|
+
*
|
|
7160
|
+
* 形状同 {@link maxCostUsd}:可选键,而「没有这个键」的语义是**用美元**
|
|
7161
|
+
* (绝大多数用户),不是「宿主没想好」。所以它也不在
|
|
7162
|
+
* `WIRE_CONFIG_RESPONSE_FIELDS` 那张必填表上。
|
|
7163
|
+
*
|
|
7164
|
+
* ## ⚠️ 下发的是 `{code, rate}`,而 `rate` **不许画到界面上**
|
|
7165
|
+
*
|
|
7166
|
+
* 浏览器要自己算(`costUsd × rate`),所以汇率必须上网线 —— 但它是**算料,
|
|
7167
|
+
* 不是读数**。界面上写一句「按 7.1 折算」是把用户自己填的常量念回给他听,
|
|
7168
|
+
* 判据全文在 [money.ts](./money.js) 文件头那一节。
|
|
7169
|
+
*
|
|
7170
|
+
* ## ⚠️ 它不改变网线上任何一个金额字段的单位
|
|
7171
|
+
*
|
|
7172
|
+
* `WireSessionSummary.costUsd`、`usage` 帧里的 `costUsd`、{@link maxCostUsd}
|
|
7173
|
+
* 本身 —— **全都还是美元**,一个都没跟着变。这一格只是告诉浏览器
|
|
7174
|
+
* 「印出来的时候乘这个数、换这个符号」。反过来(服务端先换算好再下发)
|
|
7175
|
+
* 会让 `costUsd` 这个名字当场变成假话,而**没有任何一处会红**。
|
|
7176
|
+
*/
|
|
7177
|
+
currency?: CurrencyDisplay;
|
|
6537
7178
|
/**
|
|
6538
7179
|
* 宿主品牌词标 —— **宿主没配就没有这个键**(决定 19)。
|
|
6539
7180
|
*
|
|
@@ -7304,8 +7945,30 @@ declare const WIRE_PATCH_SESSION_RESPONSE_FIELDS: WireFields<WirePatchSessionRes
|
|
|
7304
7945
|
interface EpochTurnFacts {
|
|
7305
7946
|
/** 这一轮的真实用量。provider 没上报就没有这一格 —— **不写 0** */
|
|
7306
7947
|
usage?: TokenUsage;
|
|
7307
|
-
/**
|
|
7948
|
+
/**
|
|
7949
|
+
* 这一轮**真正跑的**那个模型。
|
|
7950
|
+
*
|
|
7951
|
+
* ⚠️ 它和顶栏上那个不一样,**成因有四种,而只有后两种是故障**:
|
|
7952
|
+
* 用户 `/model` 换了、命令 frontmatter 的 `model:` 覆盖了、provider 失败降级、
|
|
7953
|
+
* 路由 404 同家换模型。
|
|
7954
|
+
*
|
|
7955
|
+
* 这句注释原来只列了后两种,而那正是一次真实缺陷的源头:web 脚注照着它
|
|
7956
|
+
* 把「这一格和配置里那个不等」读成了「降级了」,于是用户换一次模型就被告知
|
|
7957
|
+
* 出了故障。**要分辨是哪一种,看这一格和 {@link requestedModel} 这一对**,
|
|
7958
|
+
* 别拿它去和任何「当前模型」比。
|
|
7959
|
+
*/
|
|
7308
7960
|
model?: string;
|
|
7961
|
+
/**
|
|
7962
|
+
* 这一轮**开跑时要求**的那个模型 —— 和 {@link model} 是一对。
|
|
7963
|
+
*
|
|
7964
|
+
* 两格都在、且不等 = 这一轮真的降级了。两个值都**冻在这一轮里**,
|
|
7965
|
+
* 所以之后用户再换多少次模型都不影响这条断言,刷新之后也照样准。
|
|
7966
|
+
*
|
|
7967
|
+
* 缺席 = 不知道这一轮要的是谁(老库的行里没有这一列,引擎也可能一次模型
|
|
7968
|
+
* 调用都没发生)。那时读侧一律**什么都不画** —— 拿 {@link model} 自比恒相等,
|
|
7969
|
+
* 会被读成「确认没降级」,那是一个假事实。
|
|
7970
|
+
*/
|
|
7971
|
+
requestedModel?: string;
|
|
7309
7972
|
/** 这一轮从开跑到收尾的墙上时间。起点未知时没有这一格,不写 0 */
|
|
7310
7973
|
durationMs?: number;
|
|
7311
7974
|
/**
|
|
@@ -7392,8 +8055,57 @@ interface WireSendMessageRequest {
|
|
|
7392
8055
|
* 得到的交集仍然只读,用户挑了一个专家而什么都没发生。
|
|
7393
8056
|
*/
|
|
7394
8057
|
role?: string;
|
|
8058
|
+
/**
|
|
8059
|
+
* 这一条带上哪几个**已经传上去的**附件(2026-09-11)。
|
|
8060
|
+
*
|
|
8061
|
+
* ## ⚠️ 里面是**文件名**,不是路径 —— 这是这条链上最要紧的一处收窄
|
|
8062
|
+
*
|
|
8063
|
+
* 附件的字节先走 `POST /api/sessions/:id/attachments` 落进
|
|
8064
|
+
* `~/.epoch/attachments/<会话 id>/`,那一发回来一个 `name`(服务端净化 +
|
|
8065
|
+
* 去重之后的最终名字)。这里原样把那个 `name` 送回来。
|
|
8066
|
+
*
|
|
8067
|
+
* 收路径的版本得在服务端把 `..`、绝对路径、符号链接逐个挡一遍,而那是一张
|
|
8068
|
+
* **永远数不全的清单**。收名字之后路径由引擎算(`AttachmentControl.resolve`),
|
|
8069
|
+
* 浏览器就没有任何办法指向那个目录之外 —— 不是「我们挡住了已知的写法」,
|
|
8070
|
+
* 是值域里压根没有能跑出去的元素。
|
|
8071
|
+
*
|
|
8072
|
+
* 认不出来的名字**不是 400**:产出一个 `omitted: 'unreadable'` 的部件照常发出去,
|
|
8073
|
+
* 判据同下面那些失败档 —— 用户已经按了发送,为一个附件掉整条消息是更坏的交换,
|
|
8074
|
+
* 而收据会把这一条如实说出来。
|
|
8075
|
+
*
|
|
8076
|
+
* 缺席 = 这一条没有附件。**不写进下面那份必填清单**,同 `role`。
|
|
8077
|
+
*/
|
|
8078
|
+
attachments?: readonly string[];
|
|
7395
8079
|
}
|
|
7396
8080
|
declare const WIRE_SEND_MESSAGE_FIELDS: WireFields<WireSendMessageRequest>;
|
|
8081
|
+
/**
|
|
8082
|
+
* `POST /api/sessions/:id/attachments` 的回执(2026-09-11)。
|
|
8083
|
+
*
|
|
8084
|
+
* 请求体是**裸字节**(`application/octet-stream`),原始文件名走查询串
|
|
8085
|
+
* `?name=`。不用 multipart:这条路上只有一个文件、没有别的字段,
|
|
8086
|
+
* 而 multipart 要在服务端引一个解析器(或手写一个),换来的只是把一个
|
|
8087
|
+
* 查询参数搬进 body。
|
|
8088
|
+
*
|
|
8089
|
+
* ## ⚠️ 没有大小上限,这是拍过的决定
|
|
8090
|
+
*
|
|
8091
|
+
* 服务端**边收边写盘**(`streamBodyToFile`),峰值内存是一个 chunk,
|
|
8092
|
+
* 和文件多大无关。护栏是另外两道:认证(同别的 API),以及
|
|
8093
|
+
* `~/.epoch/attachments/` 那本 512MB 的总账(从最旧的会话删起)。
|
|
8094
|
+
* 判据全文在 core 的 `ATTACHMENT_MAX_TOTAL_BYTES` 和 server 的
|
|
8095
|
+
* `streamBodyToFile` 上 —— 两处都写着「这拦不住当前会话里传一个 2GB 的文件」。
|
|
8096
|
+
*/
|
|
8097
|
+
interface WireAttachmentUploadResponse {
|
|
8098
|
+
/**
|
|
8099
|
+
* 最终落盘的文件名。**可能和你传的不一样**(净化过、撞名加了 `-1`)。
|
|
8100
|
+
*
|
|
8101
|
+
* 发消息时把**这一个**放进 {@link WireSendMessageRequest.attachments},
|
|
8102
|
+
* 界面上那枚 chip 也该显示它 —— 显示原名的话,用户在会话目录里找不到那个文件。
|
|
8103
|
+
*/
|
|
8104
|
+
name: string;
|
|
8105
|
+
/** 真正落下去的字节数。界面拿它显示大小,也是「传完整了吗」的唯一凭据 */
|
|
8106
|
+
bytes: number;
|
|
8107
|
+
}
|
|
8108
|
+
declare const WIRE_ATTACHMENT_UPLOAD_FIELDS: WireFields<WireAttachmentUploadResponse>;
|
|
7397
8109
|
/**
|
|
7398
8110
|
* 立即 202,结果走 SSE。不是长轮询 —— 5 分钟的任务会撞上任何一层代理的超时。
|
|
7399
8111
|
*
|
|
@@ -8476,6 +9188,114 @@ type WirePickDirectoryResponse = {
|
|
|
8476
9188
|
} | {
|
|
8477
9189
|
canceled: true;
|
|
8478
9190
|
};
|
|
9191
|
+
/**
|
|
9192
|
+
* 「请弹一个授信对话框」——**门铃,不是开关**(方案 61)。
|
|
9193
|
+
*
|
|
9194
|
+
* ## ⚠️ 先读这一段:信任的写入口**没有**上网线
|
|
9195
|
+
*
|
|
9196
|
+
* 全仓最贵的那条纪律逐字还在(方案 42 PR-3,判据在 `wire-security.ts` 文件头):
|
|
9197
|
+
* 把信任的写入口搬到 HTTP 上,等于让浏览器决定「哪个目录里的文件能当指令读」。
|
|
9198
|
+
*
|
|
9199
|
+
* 这条端点**不是**那个写入口,两件事把它和写入口分开:
|
|
9200
|
+
*
|
|
9201
|
+
* 1. **载荷里没有 `level`,也没有 `scope`。** 浏览器表达不出「把 X 设成已信任」,
|
|
9202
|
+
* 它只能说「我想解锁 X,去问问用户」。档位和作用域由宿主的对话框决定;
|
|
9203
|
+
* 2. **服务端自己不落盘。** 它只调宿主注入的那个回调
|
|
9204
|
+
* (`CreateWebServerOptions.onTrustRequest`),落盘发生在宿主主进程里的
|
|
9205
|
+
* `runtime.trust.record()` —— 而那儿是可信代码,和 CLI 同一档。
|
|
9206
|
+
*
|
|
9207
|
+
* 形状照抄 `POST /api/workspaces/pick`:浏览器发起一个**它自己答不了**的请求,
|
|
9208
|
+
* 答案来自一个人在别处按的那一下。
|
|
9209
|
+
*
|
|
9210
|
+
* ## 200 不代表授信了
|
|
9211
|
+
*
|
|
9212
|
+
* 响应里**没有** `granted` 那一格,这是刻意的:这条端点在宿主把对话框**弹出来**
|
|
9213
|
+
* 之后(或者干脆在 resolve 时)就回 200,它不报告用户选了什么。
|
|
9214
|
+
* 要知道结果就重新取一次 `GET /api/sessions/:id/security`(或 capabilities)——
|
|
9215
|
+
* 那两份载荷里的 `trusted` / `execTrusted` 是唯一真源。
|
|
9216
|
+
*
|
|
9217
|
+
* 回一个 `granted` 的代价很具体:那个布尔和盘上的记录会各自演化(宿主的框可能
|
|
9218
|
+
* 开着不关、用户可能在 CLI 里同时改),而两者分叉时界面会信错的那一个。
|
|
9219
|
+
*/
|
|
9220
|
+
interface WireTrustRequestRequest {
|
|
9221
|
+
/**
|
|
9222
|
+
* 要解锁的目录(服务端绝对路径)。
|
|
9223
|
+
*
|
|
9224
|
+
* ⚠️ **服务端必须校验它**:只接受这个会话绑着的根、或者「已知工作区」清单里
|
|
9225
|
+
* 的某一行。不校验的话,一个页面就能让宿主弹出一个「要不要信任 `/`」的框 ——
|
|
9226
|
+
* 而对话框本身是可信的,被滥用的是「让谁出现在框里」这件事。
|
|
9227
|
+
*/
|
|
9228
|
+
root: string;
|
|
9229
|
+
/**
|
|
9230
|
+
* 想解锁哪一档 —— **提示,不是命令**(缺省 `read`)。
|
|
9231
|
+
*
|
|
9232
|
+
* 它只影响宿主对话框的默认落点:用户从技能页点进来那一下多半只想要读类,
|
|
9233
|
+
* 从「hook 没生效」那一处点进来才是执行类。宿主可以无视它。
|
|
9234
|
+
*/
|
|
9235
|
+
want?: 'read' | 'exec';
|
|
9236
|
+
}
|
|
9237
|
+
declare const WIRE_TRUST_REQUEST_FIELDS: WireFields<WireTrustRequestRequest>;
|
|
9238
|
+
/**
|
|
9239
|
+
* `POST /api/workspaces/trust-request` 的响应。
|
|
9240
|
+
*
|
|
9241
|
+
* **只有一格,而且它只说「问出去了」。** 别在这里加 `granted` —— 判据在上面。
|
|
9242
|
+
*/
|
|
9243
|
+
interface WireTrustRequestResponse {
|
|
9244
|
+
/** 宿主的回调被调起来了(对话框弹没弹、用户选了什么,这一格都不知道) */
|
|
9245
|
+
asked: true;
|
|
9246
|
+
}
|
|
9247
|
+
declare const WIRE_TRUST_REQUEST_RESPONSE_FIELDS: WireFields<WireTrustRequestResponse>;
|
|
9248
|
+
/**
|
|
9249
|
+
* 划掉一行**使用记录**。
|
|
9250
|
+
*
|
|
9251
|
+
* ## ⚠️ 它和信任没有关系,这一条是这条端点唯一容易读错的地方
|
|
9252
|
+
*
|
|
9253
|
+
* 划掉的只是「我最近在这儿干过活」。那个目录的信任判定一个字都不动 ——
|
|
9254
|
+
* 下次再绑回去,它照旧是已信任 / 已拒绝 / 未决定里原来那一档。
|
|
9255
|
+
* 撤销信任是**另一条路**(`epoch trust rm`,刻意不上网线)。
|
|
9256
|
+
*
|
|
9257
|
+
* 两件事在界面上挨着,但把它们串起来的代价很具体:用户清理一张堆满临时目录的
|
|
9258
|
+
* 列表时,会顺手把一个仓库的授信也删掉,而他以为自己只是在扫地。
|
|
9259
|
+
*
|
|
9260
|
+
* ## 所以它**可以**上网线,而信任不行
|
|
9261
|
+
*
|
|
9262
|
+
* 判据是「这一下最坏能造成什么」:信任的写入口决定「哪个目录里的文件能当指令读」,
|
|
9263
|
+
* 而这一条最坏就是让一行从一份「最近用过」的列表里消失 —— 那份列表本身
|
|
9264
|
+
* 不参与任何判定。
|
|
9265
|
+
*/
|
|
9266
|
+
interface WireForgetWorkspaceRequest {
|
|
9267
|
+
/** 要划掉的那一行(服务端绝对路径,逐字取自清单里的 `root`) */
|
|
9268
|
+
root: string;
|
|
9269
|
+
}
|
|
9270
|
+
declare const WIRE_FORGET_WORKSPACE_FIELDS: WireFields<WireForgetWorkspaceRequest>;
|
|
9271
|
+
/**
|
|
9272
|
+
* 划完之后的**整张清单**,而不是一个 `{ok:true}`。
|
|
9273
|
+
*
|
|
9274
|
+
* 回全量是刻意的:这一屏上那张卡的计数(「已知 N 个」)和表格是同一份数据的两处
|
|
9275
|
+
* 投影,让浏览器自己从本地数组里删一行再重算,等于把那个算术抄第二遍 ——
|
|
9276
|
+
* 而抄错的表现是删完之后卡上的数和表里的行数对不上,刷新一下又好了。
|
|
9277
|
+
*/
|
|
9278
|
+
interface WireForgetWorkspaceResponse {
|
|
9279
|
+
/** 划完之后剩下的行,顺序同 `GET /api/sessions/:id/security` 里那一份 */
|
|
9280
|
+
known: readonly WireKnownWorkspaceRef[];
|
|
9281
|
+
}
|
|
9282
|
+
/**
|
|
9283
|
+
* 上面那份响应里的一行。
|
|
9284
|
+
*
|
|
9285
|
+
* ⚠️ **它就是 `WireKnownWorkspace`**,只是 protocol 里这两个文件的依赖方向是
|
|
9286
|
+
* 单向的(`wire-security.ts` import 这儿,不反过来)。写成一个结构相同的别名
|
|
9287
|
+
* 而不是把类型搬过来:搬过去的话,安全中心那份载荷的定义会散在两个文件里。
|
|
9288
|
+
*/
|
|
9289
|
+
interface WireKnownWorkspaceRef {
|
|
9290
|
+
root: string;
|
|
9291
|
+
name: string;
|
|
9292
|
+
level: 'trusted' | 'untrusted' | 'unknown';
|
|
9293
|
+
trusted: boolean;
|
|
9294
|
+
current: boolean;
|
|
9295
|
+
exists: boolean;
|
|
9296
|
+
execTrusted: boolean;
|
|
9297
|
+
}
|
|
9298
|
+
declare const WIRE_FORGET_WORKSPACE_RESPONSE_FIELDS: WireFields<WireForgetWorkspaceResponse>;
|
|
8479
9299
|
/**
|
|
8480
9300
|
* `GET /api/sessions/:id/context` —— **这一段会话**此刻的预算构成。
|
|
8481
9301
|
*
|
|
@@ -8540,31 +9360,6 @@ interface WireCompactResponse {
|
|
|
8540
9360
|
}
|
|
8541
9361
|
declare const WIRE_COMPACT_FIELDS: WireFields<WireCompactResponse>;
|
|
8542
9362
|
|
|
8543
|
-
/**
|
|
8544
|
-
* 能力页的载荷契约 —— `GET /api/sessions/:id/capabilities`(方案 42 PR-1)。
|
|
8545
|
-
*
|
|
8546
|
-
* ## 为什么单开一个文件而不是塞进 `wire-rest.ts`
|
|
8547
|
-
*
|
|
8548
|
-
* 那个文件已经 788 行,早就压过了 CLAUDE.md 铁律 3 的 500 行线。往一个已经超标
|
|
8549
|
-
* 的文件里再加一百多行,等于把违规做实。这一份是**一个端点**的契约,边界清楚,
|
|
8550
|
-
* 单独成文件天然成立 —— 规矩、`wireFields` 那套工具、导出位置全部照 `wire-rest.ts`
|
|
8551
|
-
* 来,只是住在隔壁。
|
|
8552
|
-
*
|
|
8553
|
-
* ## 三屏为什么是**一个**端点
|
|
8554
|
-
*
|
|
8555
|
-
* 专家 / 技能 / 连接器在界面上是三个分栏,但它们是**同一次「我现在有什么」**:
|
|
8556
|
-
* 用户点进能力页就要看到全部三栏的计数(导航那一列上就印着数字),拆成三个端点
|
|
8557
|
-
* 的结果是首屏必然并发三发、而且三份数据可能来自三个不同的瞬间。
|
|
8558
|
-
*
|
|
8559
|
-
* ## 为什么挂在 `/sessions/:id/` 底下
|
|
8560
|
-
*
|
|
8561
|
-
* 今天这个进程里只有一个会话,所以「进程有哪些角色 / 技能」和「这个会话有哪些
|
|
8562
|
-
* 角色 / 技能」是同一份东西。**但它们不是同一个概念**:角色和技能里的「项目」
|
|
8563
|
-
* 那一层来自工作区(`<root>/.epoch/agents/`、`<root>/.epoch/skills/`),而工作区
|
|
8564
|
-
* 是**按会话**绑的(决定 18)。等方案 30 §6.3 的多会话工厂落地,同一个进程里的
|
|
8565
|
-
* 两个会话会看到两份不同的项目层 —— 那时候要改的是服务端的取数,**不是 URL**。
|
|
8566
|
-
* 现在就把 URL 定成会话作用域,是为了那一天不用再动一次前端。
|
|
8567
|
-
*/
|
|
8568
9363
|
/**
|
|
8569
9364
|
* 一个角色在网线上的样子。
|
|
8570
9365
|
*
|
|
@@ -8811,18 +9606,67 @@ interface WireMcpConnector {
|
|
|
8811
9606
|
source: 'user' | 'host' | 'plugin';
|
|
8812
9607
|
}
|
|
8813
9608
|
declare const WIRE_MCP_CONNECTOR_FIELDS: WireFields<WireMcpConnector>;
|
|
9609
|
+
/**
|
|
9610
|
+
* 两个布尔 → 三档 {@link WireMcpConnector.state}。**判序的唯一产地。**
|
|
9611
|
+
*
|
|
9612
|
+
* ⚠️ `needsLogin` **排在 `connected` 前面**:认证过不去的 server 也可能是
|
|
9613
|
+
* connected(连上了,但工具调用会被拒),那时该说的是「去登录」而不是
|
|
9614
|
+
* 「一切正常」。判序的完整理由在 {@link WireMcpConnector} 上那张表里。
|
|
9615
|
+
*
|
|
9616
|
+
* ## 为什么摘成一个函数住在 protocol(2026-09-11)
|
|
9617
|
+
*
|
|
9618
|
+
* 它原来是 `server/src/capability.ts` 的 `toWireMcp()` 里那个三元,而那时它只有
|
|
9619
|
+
* **一个**消费者,摘出来是纯开销。这一天长出了第二个:模型自述那一段
|
|
9620
|
+
* (`core/src/agent/self-index.ts`,取数在 `runtime/src/self-index.ts`)要回答
|
|
9621
|
+
* 「我连了哪几台、连上了吗」,而 runtime **不许 import server**。
|
|
9622
|
+
*
|
|
9623
|
+
* 于是只有两条路:在 runtime 里照抄一遍那个三元,或者摘到两边都够得着的地方。
|
|
9624
|
+
* 抄一遍的下场很具体 —— 两处判序走散之后,**能力页说「去登录」而模型说
|
|
9625
|
+
* 「一切正常」**,而两处都答得出「我判了」。这正是上面那段 ⚠️ 拦的那件事,
|
|
9626
|
+
* 只是换了个方向。
|
|
9627
|
+
*/
|
|
9628
|
+
declare function mcpConnectorState(server: {
|
|
9629
|
+
connected: boolean;
|
|
9630
|
+
needsLogin?: boolean;
|
|
9631
|
+
}): WireMcpConnector['state'];
|
|
8814
9632
|
/**
|
|
8815
9633
|
* 「项目」那一层的来源。角色和技能共用它 —— 两边读的是同一个工作区根,
|
|
8816
9634
|
* 也卡在同一道信任闸门上。
|
|
8817
9635
|
*
|
|
8818
9636
|
* ⚠️ `trusted` 为假时,角色和技能里**不会有** `project` 那一档,而且原因不是
|
|
8819
|
-
* 「过滤掉了」:`loader.ts`
|
|
8820
|
-
*
|
|
9637
|
+
* 「过滤掉了」:`loader.ts` 在不受信任时**连读都不读**。界面上那句话必须照实说。
|
|
9638
|
+
*
|
|
9639
|
+
* ## ⚠️ 2026-09-11:上面那句话原来还有半句,那半句被推翻了
|
|
9640
|
+
*
|
|
9641
|
+
* 原文是「不能写成『已屏蔽 N 个』—— 那个 N 根本不存在,谁也没数过」。
|
|
9642
|
+
* 现在 N 存在了:{@link inventory} 由 core 的 `inventoryProjectExtensions()` 数出来,
|
|
9643
|
+
* 它**只 readdir、不读任何文件内容**,所以「连读都不读」那半句照旧成立
|
|
9644
|
+
* (读的是目录项,不是文件)。
|
|
9645
|
+
*
|
|
9646
|
+
* 放宽的理由是宿主那条路:界面原来只能说「它的技能一个都没读」外加一条用户
|
|
9647
|
+
* 跑不了的命令,而「这个仓库里有 7 个技能、1 个 hooks.json」是把「要不要信任」
|
|
9648
|
+
* 从一道信仰题变成判断题的唯一材料。
|
|
9649
|
+
*
|
|
9650
|
+
* **但那句话的内核一个字没松**:不许编一个没人数过的数。谁要在这一屏写出一个
|
|
9651
|
+
* {@link inventory} 里没有的数字,先去把它数出来。
|
|
8821
9652
|
*/
|
|
8822
9653
|
interface WireCapabilityProject {
|
|
8823
9654
|
/** 工作区主根(服务端绝对路径)。没绑工作区就是 `null` */
|
|
8824
9655
|
root: string | null;
|
|
9656
|
+
/** 读类:指令文件 / 技能 / 角色 / 命令加载了吗 */
|
|
8825
9657
|
trusted: boolean;
|
|
9658
|
+
/**
|
|
9659
|
+
* 执行类:hook / 策略 / 项目设置生效了吗。
|
|
9660
|
+
*
|
|
9661
|
+
* 这一屏用不到它去过滤任何东西(技能和角色全在读类那一档),发它只为一件事:
|
|
9662
|
+
* 那块「未信任」的提示要说得出**这一次到底差哪一档** —— 一个只授了读类的
|
|
9663
|
+
* 工作区,它的技能明明列出来了,再说一句「这个工作区还没被信任」就是假话。
|
|
9664
|
+
*/
|
|
9665
|
+
execTrusted: boolean;
|
|
9666
|
+
/** 这个目录里有什么被挡着。**未信任时也是满的**,那正是它的用处 */
|
|
9667
|
+
inventory: WireProjectInventory;
|
|
9668
|
+
/** 宿主接了「请求授信」那条回调吗 —— 判据同 `WireSecurityWorkspace.trustRequest` */
|
|
9669
|
+
trustRequest: boolean;
|
|
8826
9670
|
}
|
|
8827
9671
|
declare const WIRE_CAPABILITY_PROJECT_FIELDS: WireFields<WireCapabilityProject>;
|
|
8828
9672
|
interface WireCapabilitiesResponse {
|
|
@@ -9056,8 +9900,10 @@ declare const WIRE_SKILL_BODY_FIELDS: WireFields<WireSkillBodyResponse>;
|
|
|
9056
9900
|
* 「是用户自己的机器」这个前提**不成立**;
|
|
9057
9901
|
* 3. 方案 42 PR-3 已经判过一次同形状的事(信任的写入口刻意不上网线)。
|
|
9058
9902
|
*
|
|
9059
|
-
*
|
|
9060
|
-
*
|
|
9903
|
+
* 所以浏览器在**这两条上**只能选,不能造 —— 它们的请求体里没有一个字节会变成
|
|
9904
|
+
* system prompt 里的字。要加上传,**别在这儿加一个 `content` 字段**:
|
|
9905
|
+
* 交字节那条路是单独一条端点,判据全文在 {@link WireSkillStageResponse} 上
|
|
9906
|
+
* (一句话:它落在扫描范围之外、吃一道 403、而且它一个技能都装不上)。
|
|
9061
9907
|
*/
|
|
9062
9908
|
type WireSkillImportForm = 'markdown' | 'skill-dir' | 'tree' | 'archive';
|
|
9063
9909
|
/** 整件事没成的原因。**单个技能坏掉不在其列** —— 那走 `skipped` */
|
|
@@ -9156,6 +10002,87 @@ interface WireSkillImportResponse {
|
|
|
9156
10002
|
reason: WireSkillImportFailure | null;
|
|
9157
10003
|
}
|
|
9158
10004
|
declare const WIRE_SKILL_IMPORT_FIELDS: WireFields<WireSkillImportResponse>;
|
|
10005
|
+
/**
|
|
10006
|
+
* 一份技能能以什么形态交上来。
|
|
10007
|
+
*
|
|
10008
|
+
* = 插件那张表({@link WIRE_PLUGIN_ARCHIVE_SUFFIXES})**再加一档 `.md`** ——
|
|
10009
|
+
* 「单独一份带 frontmatter 的 `.md`」是技能这条路自己就有的一种形态
|
|
10010
|
+
* (`SkillImportForm` 的 `markdown` 那一格),而插件没有对应物。
|
|
10011
|
+
*
|
|
10012
|
+
* ⚠️ 这张表**只在浏览器那一侧省一次空跑**(松手那一刻就说「这个不行」,
|
|
10013
|
+
* 而不是等 40MB 传完)。服务端不靠它判内容:解包交给 bsdtar 按**内容**认,
|
|
10014
|
+
* 「里面有没有技能」交给后面那一次预览。判据同 `plugin-drop.tsx` 文件头第二节。
|
|
10015
|
+
*/
|
|
10016
|
+
declare const WIRE_SKILL_DROP_SUFFIXES: readonly [".zip", ".tgz", ".tar.gz", ".md"];
|
|
10017
|
+
/** 一条路径 / 文件名收不收。**只看后缀**,口径逐字同 {@link isWirePluginArchiveName} */
|
|
10018
|
+
declare function isWireSkillDropName(name: string): boolean;
|
|
10019
|
+
/** 交上来那一发没成的三档,各对一个不同的下一步 */
|
|
10020
|
+
type WireSkillStageFailure =
|
|
10021
|
+
/** 后缀不在 {@link WIRE_SKILL_DROP_SUFFIXES} 里 —— 换个东西再拖 */
|
|
10022
|
+
'not-archive'
|
|
10023
|
+
/** 解不开 —— 这个包坏了,或者它压根不是个包 */
|
|
10024
|
+
| 'unpack-failed'
|
|
10025
|
+
/** 写不下去(盘满、没权限) */
|
|
10026
|
+
| 'write-failed';
|
|
10027
|
+
/**
|
|
10028
|
+
* `POST /api/skills/stage` —— 浏览器里那一份字节 → 服务端本机一条路径(2026-09-13)。
|
|
10029
|
+
*
|
|
10030
|
+
* ## ⚠️ 一、它答的是上面那两条端点上那句提示的**反面**
|
|
10031
|
+
*
|
|
10032
|
+
* 那一屏的输入框顶着一句「说的是运行 epoch 那台电脑,**不是你这台**」。那句话
|
|
10033
|
+
* 是真的、也必须在,但它把用户堵在原地 —— 他手里的技能就在**他这台**上。
|
|
10034
|
+
* 这条端点就是那条路:字节走网线过去落地、解开,回来一条服务端那台机器上的
|
|
10035
|
+
* 路径,接着走原来那两步(`import/preview` → `import`)。
|
|
10036
|
+
*
|
|
10037
|
+
* 于是它和那个输入框**并排,不是替代** —— 两条答的是两个不同的问题。
|
|
10038
|
+
*
|
|
10039
|
+
* ## ⚠️ 二、上面那段「浏览器只能选,不能造」为什么没被它推翻
|
|
10040
|
+
*
|
|
10041
|
+
* 三条,缺一条这个设计就不成立:
|
|
10042
|
+
*
|
|
10043
|
+
* 1. **落点在扫描范围之外。** 字节落进 `~/.epoch/skill-drops/`,而
|
|
10044
|
+
* `scanSkillDirs` 扫的是 `~/.epoch/skills/`。**传上来 ≠ 装上了** ——
|
|
10045
|
+
* 这一发结束时,system prompt 里一个字都没变;
|
|
10046
|
+
* 2. **给人的那道闸门一格没动。** 出口是一条路径,它下游接的就是原来那两条,
|
|
10047
|
+
* 连 `token` 那条防 TOCTOU 的缝都照旧。用户仍然要看过「将导入什么」那一屏
|
|
10048
|
+
* 才按得下确认;
|
|
10049
|
+
* 3. **它吃一道 403。** `epoch web --host 0.0.0.0` 那一档下这条端点**直接拒**
|
|
10050
|
+
* (口径逐字同 `POST /api/plugins/stage` 和 `POST /api/agent-roles`)。
|
|
10051
|
+
* 这一条是三条里最硬的:上面那段判据的第 2 句说的正是「那一档下『是用户
|
|
10052
|
+
* 自己的机器』这个前提不成立」,而不成立的时候我们就不收字节。
|
|
10053
|
+
*
|
|
10054
|
+
* ⚠️ 那道 403 在**读 body 之前**判,而这条端点上它比别处刻薄:body 上限是
|
|
10055
|
+
* 50 MiB,漏一格就是让 LAN 上的人一发一发地灌这台机器的内存。
|
|
10056
|
+
*
|
|
10057
|
+
* ## ⚠️ 三、它**一个技能都不装,也一个都不验**
|
|
10058
|
+
*
|
|
10059
|
+
* 出口只有「解开之后那条目录路径」(`.md` 那一档就是那个文件本身)。
|
|
10060
|
+
* **「里面有没有技能」这个问题这一层不答** —— 它由紧接着那一次
|
|
10061
|
+
* `import/preview` 答,而那一侧的答案好得多:它说得出「找到三份、其中一份
|
|
10062
|
+
* 名字不合法」。在这儿先判一道的下场是两处各判一半,而两处分叉的那天
|
|
10063
|
+
* 没有任何东西会红(同 `plugin-drop.tsx` 文件头那条「抄的,不是共用的」的教训)。
|
|
10064
|
+
*
|
|
10065
|
+
* ## ⚠️ 四、文件名走 query 上的 `?name=`,而它是这条路上唯一不可信的输入
|
|
10066
|
+
*
|
|
10067
|
+
* body 就是那份字节本身,所以**这一半没有请求体形状可写**,别以为是漏了。
|
|
10068
|
+
* 名字来自网线,一个 `../../.ssh/authorized_keys` 会让落点跑出 `skill-drops/` ——
|
|
10069
|
+
* 唯一那道收窄在 runtime 的 `safeBaseName`(和插件那条共用同一份)。
|
|
10070
|
+
*/
|
|
10071
|
+
interface WireSkillStageResponse {
|
|
10072
|
+
ok: boolean;
|
|
10073
|
+
/**
|
|
10074
|
+
* 成了 = 服务端本机一条绝对路径(解开的目录,或者那份 `.md`);没成 = `null`。
|
|
10075
|
+
*
|
|
10076
|
+
* ⚠️ **别把它填回那个路径输入框**:它落在 `~/.epoch/skill-drops/` 里,
|
|
10077
|
+
* 对用户来说是一个他没见过的地方,印出来只会让他以为自己填错了。
|
|
10078
|
+
* 拿到它直接开下一屏(预览),判据同 {@link WirePluginStageResponse.path}。
|
|
10079
|
+
*/
|
|
10080
|
+
path: string | null;
|
|
10081
|
+
/** 没成时那句为什么(服务端原话,界面原样上屏);成了是 `null` */
|
|
10082
|
+
detail: string | null;
|
|
10083
|
+
reason: WireSkillStageFailure | null;
|
|
10084
|
+
}
|
|
10085
|
+
declare const WIRE_SKILL_STAGE_FIELDS: WireFields<WireSkillStageResponse>;
|
|
9159
10086
|
/**
|
|
9160
10087
|
* 删不成的原因。**四档,各对一个不同的下一步**,判据同
|
|
9161
10088
|
* {@link WireSkillSummary.residency} 那三档:合成一个 `ok:false` 之后界面说得出
|
|
@@ -9356,8 +10283,9 @@ interface WireRoleAddResponse {
|
|
|
9356
10283
|
declare const WIRE_ROLE_ADD_RESPONSE_FIELDS: WireFields<WireRoleAddResponse>;
|
|
9357
10284
|
|
|
9358
10285
|
/**
|
|
9359
|
-
* 插件那一页的契约 ——
|
|
9360
|
-
* 2026-09-04 补,见下面第一节的**翻案**;上传 2026-09-08
|
|
10286
|
+
* 插件那一页的契约 —— 十四条端点(方案 59 §六 E2,2026-08-21;本地源与市场管理
|
|
10287
|
+
* 2026-09-04 补,见下面第一节的**翻案**;上传 2026-09-08 补,见第一节之二;
|
|
10288
|
+
* 落区 2026-09-11 补,见 {@link WirePluginStageRequest})。
|
|
9361
10289
|
*
|
|
9362
10290
|
* ```
|
|
9363
10291
|
* GET /api/plugins 装着的 + 市场里有什么 + 已加的市场 + pendingRestart + uploadEnabled
|
|
@@ -9372,6 +10300,8 @@ declare const WIRE_ROLE_ADD_RESPONSE_FIELDS: WireFields<WireRoleAddResponse>;
|
|
|
9372
10300
|
* POST /api/plugins/marketplaces/remove {name} → 移除一个市场
|
|
9373
10301
|
* POST /api/plugins/upload/preview {path} → 会打包哪些文件,一个字节都不发
|
|
9374
10302
|
* POST /api/plugins/upload {path, token} → 打包 + 交给宿主
|
|
10303
|
+
* POST /api/plugins/refresh {} → 让宿主重拉目录 + 回一份新列表
|
|
10304
|
+
* POST /api/plugins/stage {path} 或字节 → 落地 + 解包 + 验清单 → 一条目录路径
|
|
9375
10305
|
* ```
|
|
9376
10306
|
*
|
|
9377
10307
|
* 底座是 `EpochRuntime.plugins`(方案 59 PR-4 落的那一片,判据全文在
|
|
@@ -9471,11 +10401,21 @@ declare const WIRE_ROLE_ADD_RESPONSE_FIELDS: WireFields<WireRoleAddResponse>;
|
|
|
9471
10401
|
* 那几条单独点名 —— 而**它们仍然在 `files` 里面**(静默剔除会让用户以为发出去的
|
|
9472
10402
|
* 是全量,判据在 core `pack.ts` 的文件头第四节)。
|
|
9473
10403
|
*
|
|
9474
|
-
* # 二、⚠️
|
|
10404
|
+
* # 二、⚠️ 闸门:**绑在回环之外时那十三条 POST 一律 403**
|
|
9475
10405
|
*
|
|
9476
|
-
* > 这个数原来是「九条」,上传那两条 2026-09-08
|
|
10406
|
+
* > 这个数原来是「九条」,上传那两条 2026-09-08 加进来,刷新那一条 2026-09-10
|
|
10407
|
+
* > 加进来(判据在 {@link WirePluginRefreshResponse} 第三节:它让**宿主**发一次
|
|
10408
|
+
* > 出站请求,而这条路的前提是「网线另一头就是这台机器」)。**它们吃同一道闸,
|
|
9477
10409
|
* > 而且是这一整张表里最该吃的两条**:它们读这台机器上任意一条目录、把内容
|
|
9478
10410
|
* > **发到外面去**。放行的话,一个 LAN 上的人能指着 `~/.ssh` 说「上传它」。
|
|
10411
|
+
* >
|
|
10412
|
+
* > 落区那一条 2026-09-11 加进来({@link WirePluginStageRequest})。⚠️ 它最容易
|
|
10413
|
+
* > 被当成例外 —— 「字节是浏览器那台机器上的,又不读服务端的目录」。**但它落了盘,
|
|
10414
|
+
* > 而落下来的东西下一步就要被装,装进去的 `hooks.json` 起子进程。** 风险在落地
|
|
10415
|
+
* > 之后那一步,不在字节从哪儿来。⚠️ 它还有一条独占的理由:那道闸**必须在读
|
|
10416
|
+
* > 请求体之前**(`server/src/plugin.ts` 文件头第 4 条),而这一条的请求体是
|
|
10417
|
+
* > 几十 MB —— 别处漏一格是多解析一次 JSON,这儿漏一格是让 LAN 上的任何人
|
|
10418
|
+
* > 把这台机器的内存灌满。
|
|
9479
10419
|
*
|
|
9480
10420
|
* 判据同 [wire-agent-role.ts](./wire-agent-role.ts) 那道,但**这条路比它还远一格**,
|
|
9481
10421
|
* 四条:
|
|
@@ -9544,6 +10484,33 @@ declare const WIRE_ROLE_ADD_RESPONSE_FIELDS: WireFields<WireRoleAddResponse>;
|
|
|
9544
10484
|
* 界面据此说「这是一条软链 / 这是 clone 下来的」。
|
|
9545
10485
|
*/
|
|
9546
10486
|
type WirePluginSourceType = 'local' | 'git' | 'npm' | 'archive' | 'host';
|
|
10487
|
+
/**
|
|
10488
|
+
* 认得的压缩包后缀(2026-09-11,落区那一轮)。**全仓只有这一份。**
|
|
10489
|
+
*
|
|
10490
|
+
* ## ⚠️ 它摆在 protocol 里,是为了让浏览器和 core 用**同一张表**
|
|
10491
|
+
*
|
|
10492
|
+
* core 的 `resolveSource()` 靠这几个后缀把一条本地路径分成「目录」还是「压缩包」
|
|
10493
|
+
* (`plugin/source.ts` 的 `isArchiveUrl`,那儿写着「判的是后缀而不是它此刻是不是
|
|
10494
|
+
* 一个文件」);而落区在浏览器里松手的那一刻要当场答同一个问题 ——
|
|
10495
|
+
* 拖进来的这一个是压缩包,还是一个说不清的文件。
|
|
10496
|
+
*
|
|
10497
|
+
* 两边各写一份的表现最刻薄:浏览器放行了一个 `.tar.bz2`,字节发上去、落了盘,
|
|
10498
|
+
* 然后在服务端被判成「不认识」—— 一次本可以在松手那一刻就说清的拒绝,
|
|
10499
|
+
* 变成了一次几十 MB 的空跑。
|
|
10500
|
+
*
|
|
10501
|
+
* ⚠️ **不含 `.tar`**(不压缩的裸 tar)和 `.tar.bz2` / `.tar.xz`:这一份是
|
|
10502
|
+
* core 那条正则 `/\.(zip|tgz|tar\.gz)$/i` 的**原样搬家**,不是一次扩容。
|
|
10503
|
+
* 要加一档就两边一起验(`extractArchive` 交给 bsdtar,它认得比这张表多),
|
|
10504
|
+
* 而不是在这儿先放行。
|
|
10505
|
+
*/
|
|
10506
|
+
declare const WIRE_PLUGIN_ARCHIVE_SUFFIXES: readonly [".zip", ".tgz", ".tar.gz"];
|
|
10507
|
+
/**
|
|
10508
|
+
* 一条路径 / 文件名看起来是不是压缩包。**只看后缀**,不碰磁盘。
|
|
10509
|
+
*
|
|
10510
|
+
* ⚠️ 大小写不敏感(Windows 上一个 `FOO.ZIP` 很常见),而 `?` 后面的东西先切掉 ——
|
|
10511
|
+
* 同 core 那个 `isArchiveUrl`:这个函数在网线两侧都会被喂到带 query 的字符串。
|
|
10512
|
+
*/
|
|
10513
|
+
declare function isWirePluginArchiveName(name: string): boolean;
|
|
9547
10514
|
/**
|
|
9548
10515
|
* 那一条是**谁都能装**还是**只有我能装**(2026-09-08)。
|
|
9549
10516
|
*
|
|
@@ -9551,6 +10518,82 @@ type WirePluginSourceType = 'local' | 'git' | 'npm' | 'archive' | 'host';
|
|
|
9551
10518
|
* 判据在 core `MarketplaceEntry.visibility` 上:布尔表达不出这第三档。
|
|
9552
10519
|
*/
|
|
9553
10520
|
type WirePluginVisibility = 'private' | 'public';
|
|
10521
|
+
/**
|
|
10522
|
+
* 这一条在**市场那一侧**处在什么档口(2026-09-10)。
|
|
10523
|
+
*
|
|
10524
|
+
* 照抄 core 的 `MarketplaceStatus`,不是第二套枚举。`null` = 这个市场不报这个 ——
|
|
10525
|
+
* 一份 GitHub 上的开源目录没有「上架 / 审核」这回事,而印一句「已上架」是句假话。
|
|
10526
|
+
*
|
|
10527
|
+
* ⚠️ **它和 {@link WirePluginVisibility} 各答一半,界面上是两枚芯片不是一枚**:
|
|
10528
|
+
* 那一格答「谁装得到」,这一格答「这一条现在算不算数」。一个 `public` 且
|
|
10529
|
+
* `reviewing` 的条目上两句话同时成立。判据全文在 core 的 `EntrySchema.status` 上。
|
|
10530
|
+
*
|
|
10531
|
+
* ⚠️ **它不参与 {@link WirePluginHit.installable}**:目录是快照、会过时,
|
|
10532
|
+
* 拿一个会过时的档口去收掉安装入口,和 `updateAvailable` 那一格记的是同一笔账。
|
|
10533
|
+
*/
|
|
10534
|
+
type WirePluginStatus = 'listed' | 'reviewing' | 'rejected' | 'offline';
|
|
10535
|
+
/**
|
|
10536
|
+
* 上传那一屏上宿主问得出的那几格(2026-09-10 从两格放宽到七格)。
|
|
10537
|
+
*
|
|
10538
|
+
* 照抄 runtime 的 `PLUGIN_UPLOAD_FIELDS`,不是第二套名单 —— 而那一份的名字又逐字
|
|
10539
|
+
* 同 core 的 `MarketplaceEntry`(判据在它上面:这一屏收的东西最终会被宿主写进
|
|
10540
|
+
* 它自己那份目录,两边各起一套名字会逼出一张会错的映射表)。
|
|
10541
|
+
*
|
|
10542
|
+
* ⚠️ **`name` / `version` 不在里面**:那两格是从包里那份 `epoch-plugin.json` 读
|
|
10543
|
+
* 出来的**事实**,不是表单。给它们一个输入框等于让用户在上传界面上改一个包的
|
|
10544
|
+
* 身份,而真装的时候生效的仍旧是包里那一份。
|
|
10545
|
+
*/
|
|
10546
|
+
declare const WIRE_PLUGIN_UPLOAD_FORM_FIELDS: readonly ["displayName", "description", "category", "homepage", "icon", "visibility", "changelog"];
|
|
10547
|
+
/** {@link WIRE_PLUGIN_UPLOAD_FORM_FIELDS} 里的一格 */
|
|
10548
|
+
type WirePluginUploadFieldName = (typeof WIRE_PLUGIN_UPLOAD_FORM_FIELDS)[number];
|
|
10549
|
+
/**
|
|
10550
|
+
* 上传表单上一格在浏览器眼里的样子(2026-09-10)。
|
|
10551
|
+
*
|
|
10552
|
+
* ⚠️ **两格都恒有**(`value` 空串 = 宿主没预填,`editable` 恒是布尔)——
|
|
10553
|
+
* 口径同 `WirePluginsResponse.uploadOptions`:界面要的是结论,不是三种等价写法。
|
|
10554
|
+
*/
|
|
10555
|
+
interface WirePluginUploadField {
|
|
10556
|
+
/**
|
|
10557
|
+
* 预填的值。**宿主没给就是空串**。
|
|
10558
|
+
*
|
|
10559
|
+
* ⚠️ 它**不是从包里读出来的** —— 这一屏上从包里读出来的那几样(名字 / 版本 /
|
|
10560
|
+
* 描述 / 作者)是**印在上面的事实**,不是表单的默认值。判据在
|
|
10561
|
+
* `HostMarketplaces` 的 `PluginUploadField.value` 上。
|
|
10562
|
+
*/
|
|
10563
|
+
value: string;
|
|
10564
|
+
/**
|
|
10565
|
+
* 用户改得动吗。
|
|
10566
|
+
*
|
|
10567
|
+
* ⚠️ **`false` 时界面上那一格要画成印着值的只读格,而不是干脆不画** ——
|
|
10568
|
+
* 它是这一次上传真的会带上去的东西,用户有权在按下确认之前看见它
|
|
10569
|
+
* (同这一整屏「按下去之后会发生什么」的口径)。
|
|
10570
|
+
*
|
|
10571
|
+
* ⚠️ 而它**不是**靠界面上那个 `readonly` 属性兑现的:runtime 那一层会把
|
|
10572
|
+
* 锁死格子上用户传的值整个丢掉,换成宿主给的 `value`(判据在
|
|
10573
|
+
* `PluginUploadForm` 上那两条规矩)。少了那一半,改一次请求体就绕过去了。
|
|
10574
|
+
*/
|
|
10575
|
+
editable: boolean;
|
|
10576
|
+
}
|
|
10577
|
+
/**
|
|
10578
|
+
* 七格的形态表 —— **每个键恒有,不画的那几格是 `null`**。
|
|
10579
|
+
*
|
|
10580
|
+
* 判据在 `WirePluginsResponse.uploadOptions` 上(为什么是 `Record<>` 而不是一串
|
|
10581
|
+
* 可选键:加一格之后服务端当场编译不过,而漏一格没有任何东西会红)。
|
|
10582
|
+
*/
|
|
10583
|
+
type WirePluginUploadFields = Record<WirePluginUploadFieldName, WirePluginUploadField | null>;
|
|
10584
|
+
/**
|
|
10585
|
+
* 用户**填完之后**那一份(2026-09-10)—— 和上面那张形态表是两件事。
|
|
10586
|
+
*
|
|
10587
|
+
* 那一张答的是「这一屏该画成什么样」(服务端发下来),这一份答的是
|
|
10588
|
+
* 「用户填了什么」(浏览器发上去)。写成两个类型而不是复用一个:
|
|
10589
|
+
* 形态表上每一格是 `{value, editable}`,而这一份上每一格就是一个值。
|
|
10590
|
+
*
|
|
10591
|
+
* ⚠️ 除 `visibility` 之外全是字符串,判据在 `WIRE_PLUGIN_UPLOAD_FORM_FIELDS` 上
|
|
10592
|
+
* (它们最终会被宿主写进自己那份目录,而目录条目上那几格本来就是字符串)。
|
|
10593
|
+
*/
|
|
10594
|
+
type WirePluginUploadForm = {
|
|
10595
|
+
visibility?: WirePluginVisibility;
|
|
10596
|
+
} & Partial<Record<Exclude<WirePluginUploadFieldName, 'visibility'>, string>>;
|
|
9554
10597
|
/** 六类扩展物各贡献了几条。字段名照 core 的 `PluginCounts`,不自造映射 */
|
|
9555
10598
|
interface WirePluginCounts {
|
|
9556
10599
|
commands: number;
|
|
@@ -9565,6 +10608,27 @@ interface WirePluginCounts {
|
|
|
9565
10608
|
/** 装着的一个插件在浏览器眼里的样子 */
|
|
9566
10609
|
interface WirePluginEntry {
|
|
9567
10610
|
name: string;
|
|
10611
|
+
/**
|
|
10612
|
+
* **给人看的名字**(2026-09-11)。`null` = 说不出来,界面上就印 {@link name}。
|
|
10613
|
+
*
|
|
10614
|
+
* ## ⚠️ 它是**这一刻从目录里 join 出来的**,不是装的时候存下来的
|
|
10615
|
+
*
|
|
10616
|
+
* `plugins.json` 那条安装记录上没有这一格(那儿存的是身份和来源)。这一格由
|
|
10617
|
+
* `server/src/plugin.ts` 拿**市场那份快照**比出来 —— 和 {@link WirePluginHit.installed}
|
|
10618
|
+
* 恰好是同一次 join 的两个方向(那一格也在那一层算,判据在 `toWirePluginHit` 上)。
|
|
10619
|
+
*
|
|
10620
|
+
* ⚠️ **于是它会在这几种情况下变回 `null`,而那不是 bug**:这一条从本机目录装的
|
|
10621
|
+
* (压根没有市场)、装完之后那个市场被移除了、或者它在目录里下架了。
|
|
10622
|
+
* 口径同 `WirePluginHit.downloads` 上那条「目录是快照」—— 我们印的是
|
|
10623
|
+
* 「目录**现在**管它叫什么」,不是「装的那天它叫什么」。
|
|
10624
|
+
*
|
|
10625
|
+
* ## ⚠️ 有它的时候界面**照样要印 {@link name}**
|
|
10626
|
+
*
|
|
10627
|
+
* 判据逐字同 `WirePluginHit.displayName`:那一格是**显示名**,`name` 是**标识** ——
|
|
10628
|
+
* 而标识正是用户在命令里真要敲的前缀(`/queqi-geo:xxx`)和权限规则里会看见的
|
|
10629
|
+
* 那一个。只印显示名等于让「这个插件叫什么」在界面和命令行上是两个答案。
|
|
10630
|
+
*/
|
|
10631
|
+
displayName: string | null;
|
|
9568
10632
|
version: string;
|
|
9569
10633
|
/** 用户 / 宿主敲的那串来源,原样 */
|
|
9570
10634
|
source: string;
|
|
@@ -9686,20 +10750,47 @@ interface WirePluginHit {
|
|
|
9686
10750
|
homepage: string | null;
|
|
9687
10751
|
/** 公开还是私有。`null` = 这个市场不分这个,判据在 {@link WirePluginVisibility} 上 */
|
|
9688
10752
|
visibility: WirePluginVisibility | null;
|
|
10753
|
+
/**
|
|
10754
|
+
* 这一条在市场那一侧的档口(2026-09-10)。`null` = 这个市场不报这个。
|
|
10755
|
+
*
|
|
10756
|
+
* 判据全文在 {@link WirePluginStatus} 上。⚠️ 界面上它是**卡片左上角那枚徽标**,
|
|
10757
|
+
* 和右边那几枚中性芯片(作者 / 分类)刻意不同色 —— 它是这一条的**状态**,
|
|
10758
|
+
* 而那几枚是它的**属性**。
|
|
10759
|
+
*/
|
|
10760
|
+
status: WirePluginStatus | null;
|
|
9689
10761
|
/**
|
|
9690
10762
|
* **装着的那个比市场说的旧**(2026-09-08)。
|
|
9691
10763
|
*
|
|
9692
|
-
* ##
|
|
10764
|
+
* ## 🔴 2026-09-11 翻案:`false` 现在**收得掉**那枚更新按钮,条件是目录刷得动
|
|
9693
10765
|
*
|
|
9694
|
-
*
|
|
9695
|
-
*
|
|
10766
|
+
* 原来那条规矩是「`false` 什么都不减,别拿 `!updateAvailable` 去隐藏任何东西」,
|
|
10767
|
+
* 算的是这么一笔账:市场目录是**加市场那一刻的快照**(会过时,判据在 core
|
|
10768
|
+
* `MarketplaceEntry.version` 上那张两行的表),于是
|
|
9696
10769
|
*
|
|
9697
|
-
* - 说「有新版本」而其实没有 →
|
|
10770
|
+
* - 说「有新版本」而其实没有 → 用户点一下,更新回同一版。**烦,不坏**;
|
|
9698
10771
|
* - 说「已是最新」而其实有 → **一次真的更新被藏起来**。
|
|
9699
10772
|
*
|
|
9700
|
-
*
|
|
9701
|
-
*
|
|
9702
|
-
*
|
|
10773
|
+
* 两件事把这笔账翻了过来:
|
|
10774
|
+
*
|
|
10775
|
+
* 1. **目录不再是一份没人管的快照**(2026-09-10 的 `refresh` + 同轮加的
|
|
10776
|
+
* 「进插件页自动刷一遍」)。`refreshEnabled` 为真时,「市场说版本一样」
|
|
10777
|
+
* 这句话是**刚问来的**,上面第二条那个代价没有了;
|
|
10778
|
+
* 2. **「点一下回同一版」不是零成本。** 那一下走的是完整的 `preview` + `install`
|
|
10779
|
+
* 两发(`plugin-install.ts` 的 `createInstallFlow`),也就是**两次取包**——
|
|
10780
|
+
* 在一个按下载量记账的市场里,它是给一个什么都没变的操作记两笔
|
|
10781
|
+
* (2026-09-11 星云那侧的后台反馈:装一个插件下载数 +2)。
|
|
10782
|
+
*
|
|
10783
|
+
* 于是今天的规矩是:
|
|
10784
|
+
*
|
|
10785
|
+
* | | 市场那一行 | 装着那一行 |
|
|
10786
|
+
* | --- | --- | --- |
|
|
10787
|
+
* | `true` | 「已装上」换成一枚**更新按钮** | 多一句「有新版本」+ 一枚更新按钮 |
|
|
10788
|
+
* | `false`,目录**刷得动** | 「已装上」 | 那一枚**不画** |
|
|
10789
|
+
* | `false`,目录**刷不动** | 「已装上」 | 那一枚**照旧画**(快照会过时,而用户没办法让它不过时) |
|
|
10790
|
+
*
|
|
10791
|
+
* ⚠️ 最后一行是这条翻案的**边界**,别顺手抹平:`epoch web --plugins` 那种不给
|
|
10792
|
+
* `refresh` 回调的宿主就落在那一档,对它们收按钮才是原来那条判据说的
|
|
10793
|
+
* 「藏掉一次真的更新」。界面那一侧的落法在 `plugins.tsx` 的 `canUpdate` 上。
|
|
9703
10794
|
*
|
|
9704
10795
|
* ## `false` 有三种成因,而界面不需要分
|
|
9705
10796
|
*
|
|
@@ -9781,20 +10872,37 @@ interface WirePluginsResponse {
|
|
|
9781
10872
|
*/
|
|
9782
10873
|
uploadEnabled: boolean;
|
|
9783
10874
|
/**
|
|
9784
|
-
*
|
|
10875
|
+
* 上传那一屏上多问哪几格,**每一格长什么样**(2026-09-08 两个布尔 →
|
|
10876
|
+
* 2026-09-10 七格的形态表)。
|
|
9785
10877
|
*
|
|
9786
|
-
* ⚠️
|
|
9787
|
-
*
|
|
9788
|
-
* 一次就是把同一个默认值抄三遍。口径同 {@link uploadEnabled}。
|
|
10878
|
+
* ⚠️ **七个键恒有,不画的那几格是 `null`**:界面要的是「画不画 / 预填什么 /
|
|
10879
|
+
* 改不改得动」这三个结论,而缺席 / 空对象 / 显式 false 三种写法说的是同一件事
|
|
10880
|
+
* —— 让每一层各自 `??` 一次就是把同一个默认值抄三遍。口径同 {@link uploadEnabled}。
|
|
10881
|
+
*
|
|
10882
|
+
* ⚠️ 写成 `Record<>` 而不是一串可选键:{@link WirePluginUploadFields} 加一格
|
|
10883
|
+
* 之后**服务端当场编译不过**,而漏一格的表现只是屏幕上少一个输入框 ——
|
|
10884
|
+
* 没有任何东西会红。判据逐字同 web 那张 `STATE_LABEL`。
|
|
9789
10885
|
*
|
|
9790
10886
|
* ⚠️ 默认**都不问**:画一个「公开 / 私有」的选择就是在承诺「这个选择会被尊重」,
|
|
9791
10887
|
* 而一个没有公私概念的宿主只能忽略它 —— 那时界面上那一下是骗人的。
|
|
9792
10888
|
* 判据在 `HostMarketplaces.uploadOptions` 上。
|
|
9793
10889
|
*/
|
|
9794
|
-
uploadOptions:
|
|
9795
|
-
|
|
9796
|
-
|
|
9797
|
-
|
|
10890
|
+
uploadOptions: WirePluginUploadFields;
|
|
10891
|
+
/**
|
|
10892
|
+
* 宿主给了「去把目录重拉一遍」那个出口吗(2026-09-10)。
|
|
10893
|
+
* **界面上那枚「刷新」按钮画不画就看这一格。**
|
|
10894
|
+
*
|
|
10895
|
+
* ⚠️ 口径逐字同 {@link uploadEnabled}:发的是**服务端算好的结论**,
|
|
10896
|
+
* 不是把宿主那格回调在不在透上来让界面自己推。分叉的表现是一枚画出来了、
|
|
10897
|
+
* 按下去必然拿到 `refresh-unavailable` 的按钮。
|
|
10898
|
+
*
|
|
10899
|
+
* ⚠️ **默认 `false`**(宿主没给 `HostMarketplaces.refresh` 就是没有这条路),
|
|
10900
|
+
* 所以界面那一侧该按「不画」写默认分支。
|
|
10901
|
+
*
|
|
10902
|
+
* ⚠️ 它和 `lanExposed` 同样是**两格各答一半**:这一格答「这个部署有没有这条路」,
|
|
10903
|
+
* 那一格答「网线另一头是不是这台机器」。
|
|
10904
|
+
*/
|
|
10905
|
+
refreshEnabled: boolean;
|
|
9798
10906
|
}
|
|
9799
10907
|
declare const WIRE_PLUGINS_FIELDS: WireFields<WirePluginsResponse>;
|
|
9800
10908
|
/**
|
|
@@ -9860,6 +10968,71 @@ interface WirePluginLocalInstallRequest extends WirePluginLocalRequest {
|
|
|
9860
10968
|
token: string;
|
|
9861
10969
|
}
|
|
9862
10970
|
declare const WIRE_PLUGIN_LOCAL_INSTALL_FIELDS: WireFields<WirePluginLocalInstallRequest>;
|
|
10971
|
+
/**
|
|
10972
|
+
* `POST /api/plugins/stage` 的请求体 —— **JSON 那一种入口**(2026-09-11)。
|
|
10973
|
+
*
|
|
10974
|
+
* ## ⚠️ 这条端点有两种入口、一种出口,而出口是这一节的正题
|
|
10975
|
+
*
|
|
10976
|
+
* 出口永远是**一条已经验过的插件目录绝对路径**({@link WirePluginStageResponse.path})。
|
|
10977
|
+
* 于是它下游接的就是原来那四条(`install/local{,/preview}`、`upload{,/preview}`),
|
|
10978
|
+
* 一个字都不用改 —— 包括 runtime 那道「必须是绝对路径 + 必须解析成 `local`」的闸
|
|
10979
|
+
* (`resolveLocal`)。**那道闸永远看不到一个压缩包**,这是刻意的:
|
|
10980
|
+
* 把它放宽成「也收压缩包」的话,「装一个目录」和「装一个包」就在同一个形状上
|
|
10981
|
+
* 有了两种落地方式(软链 vs 解包拷贝),而界面上看不出区别。
|
|
10982
|
+
*
|
|
10983
|
+
* | 入口 | 收什么 | 解到哪儿 |
|
|
10984
|
+
* | ----------------------------- | ---------------------------- | ---------------------------- |
|
|
10985
|
+
* | `application/json`(这一条) | 本机一条**压缩包**绝对路径 | **它自己的同级目录** |
|
|
10986
|
+
* | `application/octet-stream` | 浏览器里拖 / 选的那一份字节 | `~/.epoch/plugin-drops/` 里 |
|
|
10987
|
+
*
|
|
10988
|
+
* ⚠️ **字节那一种没有请求体形状可写**(body 就是包本身),文件名走 query 上的
|
|
10989
|
+
* `name=`。所以这个 interface 只描述得了 JSON 那一半,别以为另一半是漏了。
|
|
10990
|
+
*
|
|
10991
|
+
* ## ⚠️ 它**一个字节都不删**,这是契约
|
|
10992
|
+
*
|
|
10993
|
+
* 用户交给我们的是他自己的文件。原包原地不动、解出来的目录留在它旁边,
|
|
10994
|
+
* 装完传完都不删;同名不覆盖,顺次 `-1` / `-2`。判据在
|
|
10995
|
+
* `infra/paths.ts` 的 `pluginDropsDir` 上(那儿还记了「为什么装完不能顺手清」)。
|
|
10996
|
+
*
|
|
10997
|
+
* ## 它吃**同一道** 403
|
|
10998
|
+
*
|
|
10999
|
+
* 字节是从浏览器那台机器来的没错,但落地之后装进去的 `hooks.json` / `mcp.json`
|
|
11000
|
+
* **会起子进程** —— 那正是下面第二节那道闸存在的全部理由。判据同
|
|
11001
|
+
* `install/local`:不因为「来源换了个方向」就换一套风险口径。
|
|
11002
|
+
*/
|
|
11003
|
+
interface WirePluginStageRequest {
|
|
11004
|
+
/** 本机上一条**绝对**路径,指向一个压缩包(后缀见 {@link WIRE_PLUGIN_ARCHIVE_SUFFIXES}) */
|
|
11005
|
+
path: string;
|
|
11006
|
+
}
|
|
11007
|
+
declare const WIRE_PLUGIN_STAGE_FIELDS: WireFields<WirePluginStageRequest>;
|
|
11008
|
+
/**
|
|
11009
|
+
* `POST /api/plugins/stage` 的回执。
|
|
11010
|
+
*
|
|
11011
|
+
* ⚠️ `path` 是**目录**不是包 —— 见 {@link WirePluginStageRequest} 第一节。
|
|
11012
|
+
* 界面拿到它之后原样递给 `install/local/preview` 或 `upload/preview`,
|
|
11013
|
+
* **自己不解析、不拼接、也不显示给用户当路径填回输入框**:那条路径落在
|
|
11014
|
+
* `~/.epoch/plugin-drops/` 里时,对用户来说是一个他没见过的地方,
|
|
11015
|
+
* 印出来只会让他以为自己填错了。
|
|
11016
|
+
*
|
|
11017
|
+
* `name` / `version` 读自解出来那份 `epoch-plugin.json`,给界面在跳转前
|
|
11018
|
+
* 说一句「认出来了,是 xxx」用。⚠️ 它们**不是**下一屏那份预览的替代品:
|
|
11019
|
+
* 那一屏才是这条路上给人的闸门(会起几个子进程、带几条 hook),
|
|
11020
|
+
* 判据逐字同 `plugin-add.tsx` 文件头第三节。
|
|
11021
|
+
*/
|
|
11022
|
+
interface WirePluginStageResponse {
|
|
11023
|
+
ok: boolean;
|
|
11024
|
+
/** 成了 = 一条插件目录绝对路径;没成 = `null` */
|
|
11025
|
+
path: string | null;
|
|
11026
|
+
/** 解出来那份清单里的名字。没成时 `null` */
|
|
11027
|
+
name: string | null;
|
|
11028
|
+
/** 同上 */
|
|
11029
|
+
version: string | null;
|
|
11030
|
+
/** 没成时那句给人看的话,**带得出下一步**。成了那一档是 `null` */
|
|
11031
|
+
detail: string | null;
|
|
11032
|
+
/** 没成是哪一档。成了那一档是 `null` */
|
|
11033
|
+
reason: WirePluginRefuseReason | null;
|
|
11034
|
+
}
|
|
11035
|
+
declare const WIRE_PLUGIN_STAGE_RESPONSE_FIELDS: WireFields<WirePluginStageResponse>;
|
|
9863
11036
|
/**
|
|
9864
11037
|
* `POST /api/plugins/marketplaces` 的请求体 —— 加一个市场。
|
|
9865
11038
|
*
|
|
@@ -9914,6 +11087,7 @@ declare const WIRE_PLUGIN_UPDATE_FIELDS: WireFields<WirePluginUpdateRequest>;
|
|
|
9914
11087
|
* | `nothing-to-do` | **不是出错**:软链装的插件一直是最新的 | 什么都不用做 |
|
|
9915
11088
|
* | `upload-unavailable` | **宿主没给上传出口**,这个部署没有这条路 | 没有(按钮本不该画)|
|
|
9916
11089
|
* | `upload-rejected` | **宿主收下了但说不行**(重名 / 无权限 / 待审核) | 看宿主那句 `detail` |
|
|
11090
|
+
* | `refresh-unavailable` | **宿主没给刷新出口**,这个部署没有这条路 | 没有(按钮本不该画)|
|
|
9917
11091
|
* | `failed` | 其余(拉不到 / 清单坏了 / 写记录时被抢先) | 看 `detail` |
|
|
9918
11092
|
*
|
|
9919
11093
|
* ⚠️ 上传那两档(2026-09-08)**都不能并进 `failed`**:`upload-unavailable` 和
|
|
@@ -9922,12 +11096,31 @@ declare const WIRE_PLUGIN_UPDATE_FIELDS: WireFields<WirePluginUpdateRequest>;
|
|
|
9922
11096
|
* `upload-rejected` 的下一步**在宿主那句话里**,而 `failed` 的下一步是「再试一次」。
|
|
9923
11097
|
* 合成一档的表现是界面拿「再试一次」去答「你没有这个市场的发布权限」。
|
|
9924
11098
|
*
|
|
11099
|
+
* ⚠️ `refresh-unavailable`(2026-09-10)和 `upload-unavailable` **同族但不同格**:
|
|
11100
|
+
* 两者都是「这个部署没有这条路」,而合成一档的话,一个只给了上传出口、没给刷新
|
|
11101
|
+
* 出口的宿主会看见一句指着上传的错话。⚠️ 它同样**不能并进 `failed`** ——
|
|
11102
|
+
* 收到它说明界面漏画了 `refreshEnabled` 那道判断,该按「我们的 bug」处置,
|
|
11103
|
+
* 而不是让用户去「再试一次」。
|
|
11104
|
+
*
|
|
9925
11105
|
* ⚠️ `not-local` **不能并进 `unknown-ref`**,尽管两者都是「你给的那串不对」:
|
|
9926
11106
|
* 前者的下一步是「把相对路径改成绝对路径」或「这东西得从市场装」,
|
|
9927
11107
|
* 后者是「换一条市场引用」。合成一档的表现是界面拿同一句话去答两个问题 ——
|
|
9928
11108
|
* 而这条路上最常见的一次输入错误恰恰就是把 `github:` 贴进了本地那个框。
|
|
9929
11109
|
*/
|
|
9930
|
-
type WirePluginRefuseReason = 'unknown-ref' | 'not-local'
|
|
11110
|
+
type WirePluginRefuseReason = 'unknown-ref' | 'not-local'
|
|
11111
|
+
/**
|
|
11112
|
+
* 落区那三档(2026-09-11)。⚠️ **三档而不是一档**,判据同上面 `not-local`
|
|
11113
|
+
* 为什么不并进 `unknown-ref`:三个的下一步互不相同,而用户在落区上最常撞的
|
|
11114
|
+
* 恰恰是第一档(把一个 `.tar.bz2` 或者一个单独的 `.md` 拖了进来)。
|
|
11115
|
+
*
|
|
11116
|
+
* - `not-archive` —— 后缀不在 {@link WIRE_PLUGIN_ARCHIVE_SUFFIXES} 里。
|
|
11117
|
+
* 下一步:换一个 zip,或者干脆把**文件夹**拖进来;
|
|
11118
|
+
* - `unpack-failed` —— 解不开(包坏了 / 不是真的压缩包 / 加密过)。
|
|
11119
|
+
* 下一步:在自己机器上先解一次看看;
|
|
11120
|
+
* - `not-plugin` —— 解开了,但里面没有 `epoch-plugin.json`。
|
|
11121
|
+
* 下一步:确认拖的是插件本身那一层,而不是装着它的那个上级目录。
|
|
11122
|
+
*/
|
|
11123
|
+
| 'not-archive' | 'unpack-failed' | 'not-plugin' | 'remote-disabled' | 'conflict' | 'stale-token' | 'not-installed' | 'nothing-to-do' | 'upload-unavailable' | 'refresh-unavailable' | 'upload-rejected' | 'failed';
|
|
9931
11124
|
/** 一次 hook 盘点:这个事件上有几条 */
|
|
9932
11125
|
interface WirePluginHookTally {
|
|
9933
11126
|
type: string;
|
|
@@ -9972,7 +11165,16 @@ interface WirePluginPreview {
|
|
|
9972
11165
|
ignoredBuckets: readonly string[];
|
|
9973
11166
|
/** 有没有 `tools/` 目录。第一版不跑 JS 工具,探出来只为了说一句话 */
|
|
9974
11167
|
hasJsTools: boolean;
|
|
9975
|
-
/**
|
|
11168
|
+
/**
|
|
11169
|
+
* 已经装过同名的了(**这次会被拒**)。没撞就是 `null`。
|
|
11170
|
+
*
|
|
11171
|
+
* ⚠️ **更新那条路上恒为 `null`,哪怕锁里确实有同名的那一条**(2026-09-10):
|
|
11172
|
+
* `update/preview` 要替换的就是它,它是被换掉的那一个、不是挡路的。
|
|
11173
|
+
* 这一格答的是「这次会不会被拒」,不是「锁里有没有同名的」——
|
|
11174
|
+
* 按后者读就会把一次**明明会成功**的更新画成一个点不动的按钮
|
|
11175
|
+
* (真宿主上撞到过:kdocs@2.5.7 → 2.5.8)。产地判据在 core 的
|
|
11176
|
+
* `InstallPreview.conflict` 上,界面因此**不需要**再按 install / update 分档。
|
|
11177
|
+
*/
|
|
9976
11178
|
conflict: {
|
|
9977
11179
|
name: string;
|
|
9978
11180
|
version: string;
|
|
@@ -10063,6 +11265,65 @@ interface WirePluginMarketplaceResponse {
|
|
|
10063
11265
|
detail: string | null;
|
|
10064
11266
|
}
|
|
10065
11267
|
declare const WIRE_PLUGIN_MARKETPLACE_RESPONSE_FIELDS: WireFields<WirePluginMarketplaceResponse>;
|
|
11268
|
+
/**
|
|
11269
|
+
* `POST /api/plugins/refresh` —— 「去把目录重拉一遍」。
|
|
11270
|
+
*
|
|
11271
|
+
* ## ⚠️ 一、**请求体是空的,而那是这条端点的性质本体**
|
|
11272
|
+
*
|
|
11273
|
+
* 这里没有 `source`、没有 `name`、没有 `url` —— 刷的是**宿主自己预置的那几个市场**,
|
|
11274
|
+
* 而「那几个是哪几个」是装配期就定死的(`HostMarketplaces.sources`)。
|
|
11275
|
+
* 收一格 `source` 的话,这条端点就退化成「给我一个地址我就去拉」——
|
|
11276
|
+
* 也就是一条由网线发起的任意出站请求,而那正是 `allowRemote` 默认关在防的东西。
|
|
11277
|
+
*
|
|
11278
|
+
* ## ⚠️ 二、真正去拉的**不是我们,是宿主**
|
|
11279
|
+
*
|
|
11280
|
+
* 这一发落到 `HostMarketplaces.refresh` 那个回调上(判据全文在 runtime 的
|
|
11281
|
+
* `PluginRefreshFn` 上)。epoch 一个网络请求都不发 —— 口径逐字同上传那条路:
|
|
11282
|
+
* 目录后面那台服务器要什么鉴权、走什么协议、失败怎么分档,四个答案全在宿主那侧。
|
|
11283
|
+
*
|
|
11284
|
+
* 宿主把新目录准备好之后,我们**重读一遍本机那份 `marketplaces.json`** 并把结论
|
|
11285
|
+
* 算进这一份回执 —— 于是界面在这一发 resolve 的那一刻就拿得到新列表,
|
|
11286
|
+
* 不需要轮询、也不需要我们去监听宿主发来的任何东西。
|
|
11287
|
+
*
|
|
11288
|
+
* ## ⚠️ 三、它吃第二节那道 403(LAN 那一档下拒)
|
|
11289
|
+
*
|
|
11290
|
+
* 判据同那十一条 POST:这一下会**让宿主发一次出站请求**,而「网线另一头是不是
|
|
11291
|
+
* 这台机器」是这条路成立的前提。⚠️ 于是那个数从「十一条」变成**十二条**。
|
|
11292
|
+
*/
|
|
11293
|
+
interface WirePluginRefreshResponse {
|
|
11294
|
+
/**
|
|
11295
|
+
* **`ok: true` 的意思是「这一遍跑完了」,不是「目录变了」。**
|
|
11296
|
+
*
|
|
11297
|
+
* ⚠️ 一次什么都没变的刷新照样是 `true` —— 那是一句真话(宿主那份目录就是没动过),
|
|
11298
|
+
* 而把它算成失败会让用户去查一个不存在的故障。「变没变」这件事界面**不说**:
|
|
11299
|
+
* 它拿到的是刷完之后的那一份,而那一份是不是和刚才一样,用户自己看得见。
|
|
11300
|
+
*/
|
|
11301
|
+
ok: boolean;
|
|
11302
|
+
/**
|
|
11303
|
+
* 刷完之后**重新读出来的那一份**(`GET /api/plugins` 的同一个形状)。
|
|
11304
|
+
*
|
|
11305
|
+
* ## ⚠️ 为什么整份回来,而不是让界面自己再打一发 `GET`
|
|
11306
|
+
*
|
|
11307
|
+
* 因为「即时」这件事是这一格给的:再打一发的话,两次请求之间那段时间里屏幕上
|
|
11308
|
+
* 是旧列表,而用户刚按过刷新 —— 那正是「点了半个反应」的形态。更要紧的是
|
|
11309
|
+
* 那两发之间**没有任何东西保证顺序**(一次慢的 refresh 后面跟一次快的 GET,
|
|
11310
|
+
* 拿到的是刷之前的快照,而屏幕会把它当成刷新的结果)。
|
|
11311
|
+
*
|
|
11312
|
+
* ⚠️ 没成那一档是 `null`:那时盘上那份一个字都没动,回一份「刷新后的列表」
|
|
11313
|
+
* 是句假话(界面该留着屏幕上原来那一份,判据在 web 那一侧的 `onRefreshed` 上)。
|
|
11314
|
+
*/
|
|
11315
|
+
plugins: WirePluginsResponse | null;
|
|
11316
|
+
/** 没成才有 */
|
|
11317
|
+
reason: WirePluginRefuseReason | null;
|
|
11318
|
+
/**
|
|
11319
|
+
* 没成才有。**服务端渲染好的一句人话**,界面原样上屏。
|
|
11320
|
+
*
|
|
11321
|
+
* ⚠️ 宿主那句拒绝原话优先(同 `PluginUploadFn` 那一条)——「你没有权限刷新这个
|
|
11322
|
+
* 市场」「后台正在维护」这类话我们一句都编不出来,而它们正是用户此刻要看的。
|
|
11323
|
+
*/
|
|
11324
|
+
detail: string | null;
|
|
11325
|
+
}
|
|
11326
|
+
declare const WIRE_PLUGIN_REFRESH_RESPONSE_FIELDS: WireFields<WirePluginRefreshResponse>;
|
|
10066
11327
|
/**
|
|
10067
11328
|
* `POST /api/plugins/upload/preview` 的请求体 —— **本机上一条目录**。
|
|
10068
11329
|
*
|
|
@@ -10090,15 +11351,29 @@ declare const WIRE_PLUGIN_UPLOAD_FIELDS: WireFields<WirePluginUploadRequest>;
|
|
|
10090
11351
|
interface WirePluginUploadConfirmRequest extends WirePluginUploadRequest {
|
|
10091
11352
|
token: string;
|
|
10092
11353
|
/**
|
|
10093
|
-
* 「公开还是私有」(2026-09-08)。**只在 `uploadOptions.visibility`
|
|
11354
|
+
* 「公开还是私有」(2026-09-08)。**只在 `uploadOptions.visibility` 非 `null`
|
|
11355
|
+
* 时才该发。**
|
|
10094
11356
|
*
|
|
10095
11357
|
* ⚠️ 发了也不一定算:runtime 那一层会把**宿主没声明要问的格子丢掉**
|
|
10096
11358
|
* (判据在 `PluginUploadForm` 上)—— 否则一个改了请求体的浏览器就能让宿主收到
|
|
10097
11359
|
* 一个它从没答应过要处理的值。也就是说这一格**在服务端是被收窄的,不是被信任的**。
|
|
11360
|
+
*
|
|
11361
|
+
* ⚠️ **2026-09-10 起还有第二道**:宿主把这一格标成 `editable: false` 时,
|
|
11362
|
+
* 用户传上来的这一份**同样被丢掉**,换成宿主自己给的 `value`。
|
|
11363
|
+
* 两道是同一条规矩的两半,全文在 `PluginUploadForm` 上。
|
|
10098
11364
|
*/
|
|
10099
11365
|
visibility?: WirePluginVisibility;
|
|
10100
|
-
/** 本版更新说明。同上,只在 `uploadOptions.changelog`
|
|
11366
|
+
/** 本版更新说明。同上,只在 `uploadOptions.changelog` 非 `null` 时才该发 */
|
|
10101
11367
|
changelog?: string;
|
|
11368
|
+
/**
|
|
11369
|
+
* 剩下那五格(2026-09-10)—— 逐格同上(只在对应那一格非 `null` 时才该发,
|
|
11370
|
+
* 而且发了也要过服务端那两道收窄)。名单在 {@link WIRE_PLUGIN_UPLOAD_FORM_FIELDS} 上。
|
|
11371
|
+
*/
|
|
11372
|
+
displayName?: string;
|
|
11373
|
+
description?: string;
|
|
11374
|
+
category?: string;
|
|
11375
|
+
homepage?: string;
|
|
11376
|
+
icon?: string;
|
|
10102
11377
|
}
|
|
10103
11378
|
declare const WIRE_PLUGIN_UPLOAD_CONFIRM_FIELDS: WireFields<WirePluginUploadConfirmRequest>;
|
|
10104
11379
|
/** 会被打进包里的一个文件 */
|
|
@@ -10793,6 +12068,34 @@ interface WireSecurityWorkspace extends WireSessionWorkspace {
|
|
|
10793
12068
|
* 后者是「把那个目录设成主根,或者把内容并进主根的约定文件」。
|
|
10794
12069
|
*/
|
|
10795
12070
|
unloadedExtraInstructionFiles: readonly string[];
|
|
12071
|
+
/**
|
|
12072
|
+
* **执行类**也授了吗(2026-09-11)。`trusted` 是读类那一档。
|
|
12073
|
+
*
|
|
12074
|
+
* 两格都要发,因为 `trusted: true` + `execTrusted: false` 是拆档之后**最常见**
|
|
12075
|
+
* 的一种状态(存量记录全在这儿),而界面上只有一个「已信任」的话,
|
|
12076
|
+
* 用户看到的是「已信任」配上「我的 hook 没跑」—— 一对无法自洽的事实。
|
|
12077
|
+
*/
|
|
12078
|
+
execTrusted: boolean;
|
|
12079
|
+
/**
|
|
12080
|
+
* 这个目录里有什么被挡着({@link WireProjectInventory})。
|
|
12081
|
+
*
|
|
12082
|
+
* **未信任时也是满的**,那正是它的用处:这一屏原来只能说「有东西没加载」,
|
|
12083
|
+
* 说不出有多少。
|
|
12084
|
+
*/
|
|
12085
|
+
inventory: WireProjectInventory;
|
|
12086
|
+
/**
|
|
12087
|
+
* 这个服务背后的宿主接了「请求授信」那条回调吗(方案 61 的门铃)。
|
|
12088
|
+
*
|
|
12089
|
+
* 为真时界面画一枚按钮(点它 = 请宿主弹自己的对话框),为假时画今天那块
|
|
12090
|
+
* 「复制 `epoch trust add`」。**不画灰按钮**(决定 20 ①:画一个点了没反应的
|
|
12091
|
+
* 菜单项,比不画更糟)。
|
|
12092
|
+
*
|
|
12093
|
+
* ⚠️ **它是进程级的事实,却在两份载荷上各出现一次**(这里和
|
|
12094
|
+
* `WireCapabilityProject.trustRequest`)。不抽成第三个端点是因为那要让这两屏
|
|
12095
|
+
* 各多打一发 GET,而「一次取齐」是这两份载荷共同的形状。两处**同源**——
|
|
12096
|
+
* server 从同一个 `CreateWebServerOptions.onTrustRequest` 是否存在算出来。
|
|
12097
|
+
*/
|
|
12098
|
+
trustRequest: boolean;
|
|
10796
12099
|
}
|
|
10797
12100
|
declare const WIRE_SECURITY_WORKSPACE_FIELDS: WireFields<WireSecurityWorkspace>;
|
|
10798
12101
|
/**
|
|
@@ -10815,6 +12118,35 @@ interface WireKnownWorkspace extends WireWorkspaceRef {
|
|
|
10815
12118
|
trusted: boolean;
|
|
10816
12119
|
/** 这个会话此刻绑在这儿 */
|
|
10817
12120
|
current: boolean;
|
|
12121
|
+
/**
|
|
12122
|
+
* 这个目录**现在还在盘上吗**(2026-09-11)。
|
|
12123
|
+
*
|
|
12124
|
+
* ## 为什么这一格非有不可
|
|
12125
|
+
*
|
|
12126
|
+
* 这份清单只增不减(`RecentWorkspaces.remember()` 是唯一的写口),于是跑过一阵
|
|
12127
|
+
* 之后它会塞满已经不存在的目录 —— 临时目录、删掉的项目、拔了的外置盘。
|
|
12128
|
+
* 实测一台开发机:**20 行里 16 行指向的目录已经没了**。
|
|
12129
|
+
*
|
|
12130
|
+
* 而界面在这一格出现之前**分不出它们**,于是那一屏把 16 行死路径和 4 行真目录
|
|
12131
|
+
* 并排画成同一种东西,还在上面那张卡上汇总成一句「18 个未信任」——
|
|
12132
|
+
* 读起来像 18 件待办,而其中绝大多数是清理,不是授信。
|
|
12133
|
+
*
|
|
12134
|
+
* ⚠️ **它不是「有没有权限读」**:`existsSync` 为假只说明那个路径现在不在。
|
|
12135
|
+
* 服务进程没权限看的目录也会报 false —— 两者对用户的下一步恰好相同
|
|
12136
|
+
* (这一行现在没用),所以不拆成两格。
|
|
12137
|
+
*
|
|
12138
|
+
* ⚠️ **别拿它当「该不该信任」的输入。** 信任一个还没 clone 下来的目录是合理
|
|
12139
|
+
* 用法(`epoch trust add` 那条路上明写着),这一格只影响**怎么显示**。
|
|
12140
|
+
*/
|
|
12141
|
+
exists: boolean;
|
|
12142
|
+
/**
|
|
12143
|
+
* 执行类也授了吗 —— 同 {@link WireSecurityWorkspace.execTrusted}。
|
|
12144
|
+
*
|
|
12145
|
+
* 逐行发它是因为「已信任」在拆档之后有两种,而这张表是**这台机器上**信任状态
|
|
12146
|
+
* 的唯一全貌:只印一个「已信任」的话,用户在这儿看到的和他在主根那一节看到的
|
|
12147
|
+
* 是两句对不上的话。
|
|
12148
|
+
*/
|
|
12149
|
+
execTrusted: boolean;
|
|
10818
12150
|
}
|
|
10819
12151
|
declare const WIRE_KNOWN_WORKSPACE_FIELDS: WireFields<WireKnownWorkspace>;
|
|
10820
12152
|
/**
|
|
@@ -10870,7 +12202,7 @@ type WireAuditOutcome = 'granted' | 'denied';
|
|
|
10870
12202
|
* | ------------------------ | ------------------------------------------------- |
|
|
10871
12203
|
* | `dangerous-command` | 安全底线:危险命令表命中 |
|
|
10872
12204
|
* | `sensitive-path` | 安全底线:敏感路径表命中 |
|
|
10873
|
-
* | `obfuscated` |
|
|
12205
|
+
* | `obfuscated` | 安全底线:命令含混淆构造,而这一轮问不出来 |
|
|
10874
12206
|
* | `rule-match` | 三张紧凑权限规则列表命中(就是上面那张表里的规则)|
|
|
10875
12207
|
* | `policy-rule` | `policies/*.toml` 的 `[[rule]]` 命中 |
|
|
10876
12208
|
* | `approval-cache` | 命中审批缓存 —— 用户以前批过 / 拒过 |
|
|
@@ -11187,12 +12519,14 @@ declare const WIRE_PERMISSION_SET_RESPONSE_FIELDS: WireFields<WirePermissionSetR
|
|
|
11187
12519
|
* 这是整份契约里最要紧的一个字段,理由见它自己的 JSDoc。
|
|
11188
12520
|
* ⚠️ 2026-08-31 起**哪几档由键决定**:只有 `SettingsFileSchema` 白名单里那两个
|
|
11189
12521
|
* 标量给得出 ④,其余可写键的 `writes` 里只有 ② 一档(`settingWriteLayers()`)
|
|
11190
|
-
* 3.
|
|
12522
|
+
* 3. **写完要重启进程 —— 除了 `model`**({@link WireSettingApply})。它 2026-09-13
|
|
12523
|
+
* 分叉成了 `new-session`:此后新开的会话用新值,正在跑的那些不变
|
|
11191
12524
|
*
|
|
11192
|
-
* ⚠️ 读响应里那些 `value`
|
|
11193
|
-
*
|
|
11194
|
-
*
|
|
11195
|
-
*
|
|
12525
|
+
* ⚠️ 读响应里那些 `value`,**`restart` 那一档写完不会变**,而那不是 bug:这个进程
|
|
12526
|
+
* 装配时读过一次配置就不再重读。界面在写完之后照旧印旧值、另说一句
|
|
12527
|
+
* 「已写进 X,重启后生效」,判据同 {@link WireSettingApply}。把行上那个值乐观地改成
|
|
12528
|
+
* 新值,就是这一屏存在的理由本身要消灭的那种撒谎 —— 而这一条对 `new-session`
|
|
12529
|
+
* 那一档**同样成立**(正在跑的会话按的仍是旧值),只是它下一次 `GET` 会真的变。
|
|
11196
12530
|
*
|
|
11197
12531
|
* ## 会话作用域,不是进程级的 `/api/settings`
|
|
11198
12532
|
*
|
|
@@ -11293,22 +12627,37 @@ declare const WIRE_SETTING_WRITE_LAYERS: readonly ["user", "projectLocal"];
|
|
|
11293
12627
|
type WireSettingWriteLayer = (typeof WIRE_SETTING_WRITE_LAYERS)[number] & WireSettingLayer;
|
|
11294
12628
|
declare function isWireSettingWriteLayer(value: unknown): value is WireSettingWriteLayer;
|
|
11295
12629
|
/**
|
|
11296
|
-
*
|
|
12630
|
+
* 写完要做什么它才生效。**两档,而且它们都是关于进程的话,不是关于会话的**。
|
|
12631
|
+
*
|
|
12632
|
+
* `loadConfig()` 在装配时跑一次,之后这个进程手上那份配置再也不重读。所以对
|
|
12633
|
+
* `restart` 那一档的键,落盘那一刻正在跑的会话不变、**新开一个会话也不变**、
|
|
12634
|
+
* 连 `GET` 回来的值都还是旧的 —— 于是「重启」的准确含义是重启 `epoch web`
|
|
12635
|
+
* 那个进程。这条必须说破,不说的话用户改完、新建一个会话、发现行为没变,
|
|
12636
|
+
* 然后对着一个没动静的界面发呆。
|
|
12637
|
+
*
|
|
12638
|
+
* ## ✅ `model` 2026-09-13 分叉出去了
|
|
11297
12639
|
*
|
|
11298
|
-
*
|
|
11299
|
-
*
|
|
11300
|
-
*
|
|
11301
|
-
* 的准确含义是重启 `epoch web` 那个进程 —— 这条必须说破,不说的话用户改完
|
|
11302
|
-
* `model`、新建一个会话、发现还是旧模型,然后对着一个没变的行为发呆。
|
|
12640
|
+
* 上一版这里写着「今天只有 `restart` 一档」,并且预告了这一天:「这个进程里已经
|
|
12641
|
+
* 有一条运行期换模型的路(`ModelControl`),哪天设置页接上它,`model` 就先变成
|
|
12642
|
+
* 另一档」。接上了,那一档叫 `new-session`。
|
|
11303
12643
|
*
|
|
11304
|
-
*
|
|
11305
|
-
*
|
|
12644
|
+
* ⚠️ **`model` 这一行的 `apply` 不是恒定的**:provider 层起不来的那台机器上它仍是
|
|
12645
|
+
* `restart`(那时这个进程一个会话都建不出来,「新开的会话会用它」是假话)。
|
|
12646
|
+
* 所以界面**必须照发下来的这一格画,不许照键名硬编码**。判据全文在 core 的
|
|
12647
|
+
* `config/write.ts` 的 `SettingApplyFacts.canOpenSessions` 上。
|
|
11306
12648
|
*
|
|
11307
|
-
*
|
|
11308
|
-
*
|
|
11309
|
-
*
|
|
12649
|
+
* **仍然不摆 `live` 那一档占位**,判据同下面 `plugin` 那一条:摆一档永远不会出现
|
|
12650
|
+
* 的值,等于告诉读代码的人「有些键改完当场就生效」,而那是假的。
|
|
12651
|
+
*
|
|
12652
|
+
* 它挂在**每一个(键, 层)**上而不是整份响应上 —— 这一天到了之后,那句话不再是
|
|
12653
|
+
* 一个预告而是一条正在成立的性质:同一份响应里 `model` 那行是 `new-session`、
|
|
12654
|
+
* `maxTurns` 那行是 `restart`。
|
|
11310
12655
|
*/
|
|
11311
|
-
type WireSettingApply =
|
|
12656
|
+
type WireSettingApply =
|
|
12657
|
+
/** 要重启 `epoch web` 那个进程 */
|
|
12658
|
+
'restart'
|
|
12659
|
+
/** **此后新开的会话**用新值;正在跑的那些不变,也不用重启 */
|
|
12660
|
+
| 'new-session';
|
|
11312
12661
|
/**
|
|
11313
12662
|
* 写进去了却仍然不生效的两种成因。**这是整份契约里最要紧的一个东西。**
|
|
11314
12663
|
*
|
|
@@ -11495,10 +12844,18 @@ declare const WIRE_SETTINGS_WRITE_REQUEST_FIELDS: WireFields<WireSettingsWriteRe
|
|
|
11495
12844
|
/**
|
|
11496
12845
|
* 写成功之后的回执。**它不是新的一行** —— 行还是旧的那一行。
|
|
11497
12846
|
*
|
|
11498
|
-
*
|
|
11499
|
-
*
|
|
11500
|
-
*
|
|
11501
|
-
*
|
|
12847
|
+
* 界面拿这份回执画的是**一句话**,而那句话按 {@link apply} 分两档:
|
|
12848
|
+
*
|
|
12849
|
+
* - `restart`:「已写进 ④ 项目本地(<path>);本进程仍在用 <旧值>,重启后生效」
|
|
12850
|
+
* - `new-session`:「已写进 ②(<path>);此后新开的会话用它,正在跑的这些不变」
|
|
12851
|
+
*
|
|
12852
|
+
* **两档都不许把那一行的值乐观地换成新的。** `restart` 那档的理由是老的
|
|
12853
|
+
* (进程没重读,行上那个值真的没变);`new-session` 那档的理由换了一个,
|
|
12854
|
+
* 而结论一样:那一行答的是「**这个进程**此刻按的是什么」,而正在跑的会话
|
|
12855
|
+
* 按的仍是旧值 —— 乐观地换掉就是替一屏正在生效的旧行为印了个新名字。
|
|
12856
|
+
*
|
|
12857
|
+
* 值真的变没变由下一次 `GET` 说(`model` 走 `new-session` 那一档时它会跟着动,
|
|
12858
|
+
* 判据在 {@link WireSettingApply})。
|
|
11502
12859
|
*/
|
|
11503
12860
|
interface WireSettingsWriteResponse {
|
|
11504
12861
|
key: string;
|
|
@@ -11721,6 +13078,34 @@ interface WireProviderOption {
|
|
|
11721
13078
|
* 不是发全的让浏览器自己截(那样 key 已经过了网线)。
|
|
11722
13079
|
*/
|
|
11723
13080
|
keyHint: string | null;
|
|
13081
|
+
/**
|
|
13082
|
+
* **这台机器此刻配的就是这一家**(2026-09-11)。十三家里最多一家是 `true`。
|
|
13083
|
+
*
|
|
13084
|
+
* ## 加它是为了让选择器「一展示就有清单」
|
|
13085
|
+
*
|
|
13086
|
+
* 改造前浏览器这一侧 `provider` 的初值是 `undefined`,于是打开顶栏那张菜单
|
|
13087
|
+
* 看到的是一句「挑一家」和一个空的模型下拉 —— 用户必须先在 provider 那一格
|
|
13088
|
+
* 上手动选中他**本来就在用的那一家**,才会发出第一发探测。多一步、而且那一步
|
|
13089
|
+
* 的信息量是零(答案只有一个)。
|
|
13090
|
+
*
|
|
13091
|
+
* 有了这一格,`useModelCatalog` 在 provider 单子回来的那一刻就能自动探它。
|
|
13092
|
+
*
|
|
13093
|
+
* ## ⚠️ 为什么不让浏览器自己去比对
|
|
13094
|
+
*
|
|
13095
|
+
* 浏览器手上确实有一个「此刻的模型」(`GET /api/config` 的
|
|
13096
|
+
* `WireProviderSummary`,以及会话那一份 `WireModelSelection`),拿它去和这张
|
|
13097
|
+
* 单子对一遍也能得出同样的结论 —— **但那是在下游重建一份判断**。
|
|
13098
|
+
* `config.ts` 的文件头逐字记着这个病(「被复制了三遍,加一个 provider 要改
|
|
13099
|
+
* 四处」)。服务端本来就知道答案(`ModelCatalogOptions.configured`),
|
|
13100
|
+
* 让它直接说出来。
|
|
13101
|
+
*
|
|
13102
|
+
* ## ⚠️ 它**不是**「选中态」
|
|
13103
|
+
*
|
|
13104
|
+
* 说的是「配置里写的是这一家」。用户在菜单里点到别家之后,界面的选中态跟着
|
|
13105
|
+
* 走,而这一格纹丝不动 —— 它到下一次 `GET /api/providers` 之前都不会变。
|
|
13106
|
+
* 拿它当受控组件的 `value` 会得到一个点不动的下拉。
|
|
13107
|
+
*/
|
|
13108
|
+
current: boolean;
|
|
11724
13109
|
}
|
|
11725
13110
|
declare const WIRE_PROVIDER_OPTION_FIELDS: WireFields<WireProviderOption>;
|
|
11726
13111
|
/** `GET /api/providers` 的响应 */
|
|
@@ -13232,4 +14617,4 @@ declare const SECRET_SERVICE = "epoch-agent";
|
|
|
13232
14617
|
*/
|
|
13233
14618
|
declare const MCP_DATA_KEY_NAME = "mcp-auth-data-key";
|
|
13234
14619
|
|
|
13235
|
-
export { ACTION_CONTEXTS, AGENT_ROLE_NAME_PATTERN, API_KEY_ENV_VARS, APPROVAL_OUTCOMES, type ActiveAgentRole, type AgentEvent, type AgentEventOf, type AgentEventType, type AgentRole, type AgentRoleScope, type AgentRoleSource, type ApprovalAnswer, type ApprovalOutcome, type ApprovalReply, type ApprovalRequest, type ArtifactKind, type AttributeValue, type Attributes, type BackgroundTaskInfo, type BackgroundTaskKind, type BackgroundTaskStatus, type BlankCard, type BlankGreeting, type BoundKey, type BudgetBreach, COMMAND_NAME_PATTERN, COMPLIANCE_ACTIONS, COMPLIANCE_CATEGORIES, type Catalogs, type ComplianceAction, type ComplianceCategory, type ContextBreakdown, type ContextSegment, type CustomCommandDef, type CustomCommandSource, DEFAULT_AGENT_ROLE, DEFAULT_LANG, type DecidedTrustLevel, type Diagnostic, DiagnosticSink, type DiagnosticStatus, type EpochConfig, type EpochContentPart, type EpochFilePart, type EpochHook, type EpochImagePart, type EpochMessage, type EpochMessageRole, type EpochPlugin, type EpochSessionPart, type EpochSkill, type EpochTextPart, type EpochTool, type EpochToolCall, type EpochToolResult, type EpochTurnFacts, type EpochUserContent, type ExpandedCommand, type FileOmitReason, type FinishReason, type FixableApproval, type FlatCatalog, GEN_AI, HEADLESS_INPUT_EVENT_TYPES, HEADLESS_INPUT_FORMATS, HEADLESS_OUTPUT_FORMATS, HEADLESS_PROTOCOL_VERSION, type HeadlessEnvelope, type HeadlessEvent, type HeadlessInit, type HeadlessInputEvent, type HeadlessInputEventType, type HeadlessInputFormat, type HeadlessLifecycleEvent, type HeadlessOutputFormat, type HeadlessResult, type HeadlessResultReason, type HookContext, type HookEvent, type HookHandler, type HookManager, type HookRegistration, type HookType, type HostText, type HostUser, type JsonSchema, KEY_ACTIONS, type KeyAction, type KeyChord, type KeyContext, type KeySequence, type KeybindingReport, type KeybindingSource, type KeybindingTable, LANGS, type Lang, type LocalizedDetail, type LogFn, MAX_ATTACH_BYTES, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_HEADER_CHARS, MAX_OPTIONS, MAX_QUESTIONS, MAX_SESSION_ATTACH_BYTES, MAX_SESSION_REFS, MCP_DATA_KEY_NAME, METRIC, MIN_OPTIONS, type MentionSet, type ModelRef, type ModelSelection, type ModelSelectionOrigin, NOOP_TELEMETRY, type NoticeCode, OPERATION_TYPES, type Operation, type OperationType, PERMISSION_LEVELS, PLAN_OUTCOMES, PROVIDER_INFOS, PROVIDER_TYPES, type PermissionDecision, type PermissionLevel, type PermissionManager, type PermissionRuleLists, type PlanApprovalOutcome, type PlanProposal, type PluginContext, type ProviderInfo, type ProviderType, type QuestionAnswer, type QuestionItem, type QuestionOption, type QuestionRequest, RESERVED_CHORDS, RESERVED_COMMAND_NAMES, type RejectReason, type RejectedKey, type RuleValue, SCHEDULE_DRAFT_TOOL, SCHEDULE_INTERVAL_MINUTES, SCHEDULE_RUN_STATUSES, SCHEDULE_TEMPLATES, SEARCH_API_KEY_ENV, SEARCH_PROVIDER_TYPES, SECRET_SERVICE, SEQUENCE_CONTEXTS, SESSION_MENTION_PREFIX, SESSION_REFERENCE_ERROR_CODES, SHELL_KINDS, SIDEBAR_MENU_MESSAGE_TYPE, SIMULTANEOUS_CONTEXTS, SYSTEM_NOTE_PREFIX, type ScheduleAllowlist, type ScheduleBackendKind, type ScheduleCycle, type ScheduleDefinition, type ScheduleDraft, type ScheduleDraftAllowlist, type ScheduleDraftCreate, type ScheduleDraftPermission, type ScheduleDraftUpdate, type SchedulePendingApproval, type SchedulePendingItem, type ScheduleRun, type ScheduleRunStatus, type ScheduleRunnerSpec, type ScheduleTemplate, type ScheduleTemplateId, type ScheduleTrigger, type ScheduleTriggerKind, type ScheduleWeekday, type ScheduleWideningKind, type SearchProviderType, type SecretBackendId, type SecretStore, type SelectionContext, type SelectionRejection, type SelectionWarning, type SessionAttachKind, type SessionAttachResult, type SessionOmitReason, type SessionSurfaceMessage, type SessionSurfaceView, type SetSelectionResult, type ShellKind, type SidebarMenuItem, type SidebarMenuMessage, type SpanLike, type SubToolCall, type SubToolCallResult, type Telemetry, type TokenUsage, type ToolAnnotations, type ToolArtifact, type ToolArtifactInput, type ToolContext, type ToolDefinition, ToolExposure, type ToolProvider, type ToolResult, type Translate, type TranslateVars, type TrustLevel, type TrustManager, type TrustRecord, type TrustScope, UNLIMITED_TURNS, type VerifyResult, WIRE_ABORT_FIELDS, WIRE_ABOUT_FIELDS, WIRE_AGENT_ROLE_FIELDS, WIRE_APPROVAL_CACHE_REVOKE_REQUEST_FIELDS, WIRE_APPROVAL_CACHE_REVOKE_RESPONSE_FIELDS, WIRE_APPROVAL_LIST_FIELDS, WIRE_APPROVAL_ROW_FIELDS, WIRE_ARTIFACTS_FIELDS, WIRE_AUDIT_LOG_FIELDS, WIRE_AUDIT_ROW_FIELDS, WIRE_AUTH_COOKIE, WIRE_AUTH_COOKIE_ATTRS, WIRE_AUTH_TOKEN_PARAM, WIRE_BACKGROUND_TASK_FIELDS, WIRE_BLOCKED_GOALS_FIELDS, WIRE_BLOCKED_GOAL_FIELDS, WIRE_BLOCKED_LEVEL_FIELDS, WIRE_BUILTIN_CONNECTOR_FIELDS, WIRE_CACHED_APPROVAL_FIELDS, WIRE_CAPABILITIES_FIELDS, WIRE_CAPABILITY_PROJECT_FIELDS, WIRE_CHECKPOINT_LIST_FIELDS, WIRE_CHECKPOINT_SUMMARY_FIELDS, WIRE_COMMANDS_FIELDS, WIRE_COMMAND_EXPANSION_FIELDS, WIRE_COMPACT_FIELDS, WIRE_COMPRESSION_LINE_FIELDS, WIRE_CONFIG_FIELDS, WIRE_CONTEXT_FIELDS, WIRE_CREATE_SESSION_FIELDS, WIRE_CREATE_WORKSPACE_FIELDS, WIRE_CREATE_WORKSPACE_RESPONSE_FIELDS, WIRE_CUSTOM_COMMAND_FIELDS, WIRE_DELETE_SESSION_FIELDS, WIRE_DIFF_FILE_FIELDS, WIRE_ERROR_FIELDS, WIRE_FILE_CANDIDATES_FIELDS, WIRE_FILE_CANDIDATE_FIELDS, WIRE_FILE_CHANGE_FIELDS, WIRE_FILE_OPEN_RESPONSE_FIELDS, WIRE_FILE_REFERENCE_FIELDS, WIRE_FILE_STAT_MAX, WIRE_FILE_STAT_OK_FIELDS, WIRE_FILE_STAT_REFUSED_FIELDS, WIRE_FILE_STAT_RESPONSE_FIELDS, WIRE_FILE_TEXT_RESPONSE_FIELDS, WIRE_GOAL_ACTIONS, WIRE_GOAL_BLOCK_FIELDS, WIRE_GOAL_CLEAR_FIELDS, WIRE_GOAL_CREATE_FIELDS, WIRE_GOAL_FIELDS, WIRE_GOAL_LIMITS_FIELDS, WIRE_GOAL_PHASES, WIRE_GOAL_REFUSALS, WIRE_GOAL_RESPONSE_FIELDS, WIRE_GOAL_WRITE_FIELDS, WIRE_HEALTH_FIELDS, WIRE_IMAGE_REFERENCE_FIELDS, WIRE_KNOWN_WORKSPACE_FIELDS, WIRE_LANG_PARAM, WIRE_MANAGED_LOCK_FIELDS, WIRE_MCP_ADD_FIELDS, WIRE_MCP_ADD_RESPONSE_FIELDS, WIRE_MCP_APPLY_ENTRY_FIELDS, WIRE_MCP_APPLY_RESPONSE_FIELDS, WIRE_MCP_CONFIG_APPLY_FIELDS, WIRE_MCP_CONFIG_FIELDS, WIRE_MCP_CONFIG_ISSUE_FIELDS, WIRE_MCP_CONFIG_SAVE_FIELDS, WIRE_MCP_CONFIG_SAVE_RESPONSE_FIELDS, WIRE_MCP_CONNECTOR_FIELDS, WIRE_MCP_RECONNECT_FIELDS, WIRE_MESSAGE_LIST_FIELDS, WIRE_MODEL_FIELDS, WIRE_MODEL_SELECTION_FIELDS, WIRE_MODEL_SET_FIELDS, WIRE_MODEL_SUGGESTIONS_FIELDS, WIRE_PATCH_SESSION_FIELDS, WIRE_PATCH_SESSION_RESPONSE_FIELDS, WIRE_PERMISSION_RULE_FIELDS, WIRE_PERMISSION_SET_REQUEST_FIELDS, WIRE_PERMISSION_SET_RESPONSE_FIELDS, WIRE_PERMISSION_SHADOW_FIELDS, WIRE_PERMISSION_STATE_FIELDS, WIRE_PERMISSION_STATUS_FIELDS, WIRE_PLAN_ACTIONS, WIRE_PLAN_FIELDS, WIRE_PLAN_MODE_REQUEST_FIELDS, WIRE_PLAN_MODE_RESPONSE_FIELDS, WIRE_PLAN_MODE_STATE_FIELDS, WIRE_PLUGINS_FIELDS, WIRE_PLUGIN_ACTION_FIELDS, WIRE_PLUGIN_INSTALL_FIELDS, WIRE_PLUGIN_LOCAL_FIELDS, WIRE_PLUGIN_LOCAL_INSTALL_FIELDS, WIRE_PLUGIN_MARKETPLACE_FIELDS, WIRE_PLUGIN_MARKETPLACE_RESPONSE_FIELDS, WIRE_PLUGIN_NAME_FIELDS, WIRE_PLUGIN_PREVIEW_FIELDS, WIRE_PLUGIN_PREVIEW_RESPONSE_FIELDS, WIRE_PLUGIN_UPDATE_FIELDS, WIRE_PLUGIN_UPLOAD_CONFIRM_FIELDS, WIRE_PLUGIN_UPLOAD_FIELDS, WIRE_PLUGIN_UPLOAD_PREVIEW_RESPONSE_FIELDS, WIRE_PLUGIN_UPLOAD_RESPONSE_FIELDS, WIRE_POLICY_DIR_FIELDS, WIRE_POLICY_STATUS_FIELDS, WIRE_PROVIDERS_FIELDS, WIRE_PROVIDER_KEY_FIELDS, WIRE_PROVIDER_MODELS_FIELDS, WIRE_PROVIDER_OPTION_FIELDS, WIRE_QUESTION_LIST_FIELDS, WIRE_QUESTION_ROW_FIELDS, WIRE_RESPOND_APPROVAL_FIELDS, WIRE_RESPOND_APPROVAL_RESPONSE_FIELDS, WIRE_RESPOND_QUESTION_FIELDS, WIRE_RESPOND_QUESTION_RESPONSE_FIELDS, WIRE_REWIND_FILE_PLAN_FIELDS, WIRE_REWIND_OUTCOME_FIELDS, WIRE_REWIND_PREVIEW_FIELDS, WIRE_REWIND_REQUEST_FIELDS, WIRE_REWIND_RESPONSE_FIELDS, WIRE_REWIND_SCOPES, WIRE_ROLE_ADD_FIELDS, WIRE_ROLE_ADD_RESPONSE_FIELDS, WIRE_SANDBOX_STATUS_FIELDS, WIRE_SCHEDULE_CAPABILITY_FIELDS, WIRE_SCHEDULE_CREATE_FIELDS, WIRE_SCHEDULE_DEFAULTS_FIELDS, WIRE_SCHEDULE_DELETE_FIELDS, WIRE_SCHEDULE_FIELDS, WIRE_SCHEDULE_FIX_FIELDS, WIRE_SCHEDULE_FIX_REQUEST_FIELDS, WIRE_SCHEDULE_ISSUE_CODES, WIRE_SCHEDULE_LIST_FIELDS, WIRE_SCHEDULE_PENDING_FIELDS, WIRE_SCHEDULE_RECORDING_FIELDS, WIRE_SCHEDULE_ROW_FIELDS, WIRE_SCHEDULE_RUNS_FIELDS, WIRE_SCHEDULE_RUN_FIELDS, WIRE_SCHEDULE_SAVE_FIELDS, WIRE_SECURITY_FIELDS, WIRE_SECURITY_WORKSPACE_FIELDS, WIRE_SEND_MESSAGE_FIELDS, WIRE_SEND_MESSAGE_RESPONSE_FIELDS, WIRE_SESSION_CANDIDATES_FIELDS, WIRE_SESSION_CANDIDATE_FIELDS, WIRE_SESSION_FINISH_FIELDS, WIRE_SESSION_LIST_FIELDS, WIRE_SESSION_REFERENCE_FIELDS, WIRE_SESSION_RESPONSE_FIELDS, WIRE_SESSION_SUMMARY_FIELDS, WIRE_SESSION_WORKSPACE_FIELDS, WIRE_SESSION_WORKSPACE_RESPONSE_FIELDS, WIRE_SETTINGS_FIELDS, WIRE_SETTINGS_WRITE_FIELDS, WIRE_SETTINGS_WRITE_REQUEST_FIELDS, WIRE_SETTING_ROW_FIELDS, WIRE_SETTING_STEP_FIELDS, WIRE_SETTING_WRITE_FIELDS, WIRE_SETTING_WRITE_LAYERS, WIRE_SKILL_BODY_FIELDS, WIRE_SKILL_FIELDS, WIRE_SKILL_IMPORT_FIELDS, WIRE_SKILL_IMPORT_PREVIEW_FIELDS, WIRE_SKILL_REMOVE_FIELDS, WIRE_TASKS_FIELDS, WIRE_TOOLS_FIELDS, WIRE_TOOL_GATE_FIELDS, WIRE_TOOL_ROW_FIELDS, WIRE_WORKSPACE_DIFF_FIELDS, WIRE_WORKSPACE_DIRS_FIELDS, WIRE_WORKSPACE_DIR_ENTRY_FIELDS, WIRE_WORKSPACE_REF_FIELDS, type WireAbortResponse, type WireAbout, type WireAgentEnvelope, type WireAgentEvent, type WireAgentRoleSummary, type WireApprovalCacheRevokeRequest, type WireApprovalCacheRevokeResponse, type WireApprovalListResponse, type WireApprovalRequest, type WireArtifactsResponse, type WireAuditCode, type WireAuditLog, type WireAuditOutcome, type WireAuditRow, type WireAuthDenyReason, type WireAuthDenyStatus, type WireAuthGuard, type WireAuthRequestView, type WireAuthVerdict, type WireBackgroundTask, type WireBindWorkspaceRequest, type WireBlockedGoal, type WireBlockedGoalsResponse, type WireBlockedLevel, type WireBuiltinConnector, type WireCachedApproval, type WireCachedDecision, type WireCapabilitiesResponse, type WireCapabilityProject, type WireCheckpointListResponse, type WireCheckpointSummary, type WireCommandExpansion, type WireCommandsResponse, type WireCompactRequest, type WireCompactResponse, type WireCompressionLine, type WireConfigResponse, type WireContextResponse, type WireCreateSessionRequest, type WireCreateSessionResponse, type WireCreateWorkspaceRequest, type WireCreateWorkspaceResponse, type WireCustomCommand, type WireDeleteSessionResponse, type WireDiffFile, type WireDiffNote, type WireDiffOmitReason, type WireDiffSource, type WireDiffStatus, type WireEnvelope, type WireErrorResponse, type WireEvent, type WireFields, type WireFileCandidate, type WireFileCandidatesResponse, type WireFileChange, type WireFileKind, type WireFileOpenRefusal, type WireFileOpenResponse, type WireFileReference, type WireFileRefusal, type WireFileStat, type WireFileStatOk, type WireFileStatRefused, type WireFileStatResponse, type WireFileTextResponse, type WireFixture, type WireFixtureCase, type WireGoal, type WireGoalBlock, type WireGoalClearResponse, type WireGoalCreateRequest, type WireGoalLimits, type WireGoalPhase, type WireGoalRefusal, type WireGoalResponse, type WireGoalUpdateRequest, type WireGoalWriteResponse, type WireHealthResponse, type WireHubEnvelope, type WireHubEvent, type WireImageReference, type WireKnownWorkspace, type WireManagedLock, type WireMcpAddRequest, type WireMcpAddResponse, type WireMcpApplyAction, type WireMcpApplyEntry, type WireMcpApplyResponse, type WireMcpConfigApplyRequest, type WireMcpConfigIssue, type WireMcpConfigResponse, type WireMcpConfigSaveRequest, type WireMcpConfigSaveResponse, type WireMcpConnector, type WireMcpReconnectResponse, type WireMessageListResponse, type WireModelCaveat, type WireModelProbeStatus, type WireModelRejection, type WireModelResponse, type WireModelSelection, type WireModelSetRequest, type WireModelSetResponse, type WireModelSource, type WireModelSuggestions, type WirePatchSessionRequest, type WirePatchSessionResponse, type WirePermissionRememberFailure, type WirePermissionRuleRow, type WirePermissionSetRequest, type WirePermissionSetResponse, type WirePermissionShadow, type WirePermissionState, type WirePermissionStatus, type WirePickDirectoryResponse, type WirePlanAction, type WirePlanModeRequest, type WirePlanModeResponse, type WirePlanModeState, type WirePlanResponse, type WirePluginActionResponse, type WirePluginCounts, type WirePluginEntry, type WirePluginHit, type WirePluginHookTally, type WirePluginInstallRequest, type WirePluginLocalInstallRequest, type WirePluginLocalRequest, type WirePluginMarketplace, type WirePluginMarketplaceRequest, type WirePluginMarketplaceResponse, type WirePluginNameRequest, type WirePluginPreview, type WirePluginPreviewRequest, type WirePluginPreviewResponse, type WirePluginRefuseReason, type WirePluginSourceType, type WirePluginUpdateRequest, type WirePluginUploadConfirmRequest, type WirePluginUploadFile, type WirePluginUploadPlan, type WirePluginUploadPreviewResponse, type WirePluginUploadRequest, type WirePluginUploadResponse, type WirePluginVisibility, type WirePluginsResponse, type WirePolicyDir, type WirePolicyStatus, type WireProviderKeyRequest, type WireProviderKeyResponse, type WireProviderModelsRequest, type WireProviderModelsResponse, type WireProviderOption, type WireProviderSummary, type WireProvidersResponse, type WireQuestionListResponse, type WireQuestionRequest, type WireReplayMessage, type WireResetReason, type WireRespondApprovalRequest, type WireRespondApprovalResponse, type WireRespondQuestionRequest, type WireRespondQuestionResponse, type WireRewindAction, type WireRewindDrift, type WireRewindFilePlan, type WireRewindOutcome, type WireRewindPreview, type WireRewindRequest, type WireRewindResponse, type WireRewindScope, type WireRoleAddRequest, type WireRoleAddResponse, type WireSandboxReason, type WireSandboxStatus, type WireScheduleCapability, type WireScheduleCreateRequest, type WireScheduleDefaults, type WireScheduleDeleteResponse, type WireScheduleFixRequest, type WireScheduleFixResponse, type WireScheduleIssue, type WireScheduleIssueCode, type WireScheduleListResponse, type WireSchedulePendingResponse, type WireScheduleRecordingResponse, type WireScheduleRegisterRefusal, type WireScheduleRegisterWarning, type WireScheduleRegistration, type WireScheduleResponse, type WireScheduleRow, type WireScheduleRunResponse, type WireScheduleRunsResponse, type WireScheduleSaveResponse, type WireScheduleUpdateRequest, type WireSecurityResponse, type WireSecurityWorkspace, type WireSendMessageRequest, type WireSendMessageResponse, type WireSessionCandidate, type WireSessionCandidatesResponse, type WireSessionFinish, type WireSessionListResponse, type WireSessionReference, type WireSessionResponse, type WireSessionSummary, type WireSessionWorkspace, type WireSessionWorkspaceResponse, type WireSettingApply, type WireSettingFutile, type WireSettingLayer, type WireSettingRow, type WireSettingStep, type WireSettingValue, type WireSettingValueKind, type WireSettingWrite, type WireSettingWriteLayer, type WireSettingsResponse, type WireSettingsWriteRequest, type WireSettingsWriteResponse, type WireSkillBodyResponse, type WireSkillImportConflict, type WireSkillImportEntry, type WireSkillImportFailure, type WireSkillImportForm, type WireSkillImportIssue, type WireSkillImportPreviewResponse, type WireSkillImportResponse, type WireSkillRemoveFailure, type WireSkillRemoveResponse, type WireSkillSummary, type WireSummaryWorkspace, type WireTaggedEvent, type WireTasksResponse, type WireToolGate, type WireToolGateAxis, type WireToolRow, type WireToolSummary, type WireToolVerdict, type WireToolsResponse, type WireTurnState, type WireWorkspaceBinding, type WireWorkspaceDiffResponse, type WireWorkspaceDirEntry, type WireWorkspaceDirsResponse, type WireWorkspaceRef, apiKeyEnvVar, assertNeverPart, assistantTurnText, attachSessionSurface, chordId, collectPendingApprovals, compressionThresholdTokens, conformsToWire, contentToText, diagnosticToLine, extractAllMentions, extractMentions, extractSessionMentions, filePartSummary, flattenCatalog, getProviderInfo, hasFailure, isApprovalOutcome, isContextNearlyFull, isHeadlessInputFormat, isHeadlessLifecycleEvent, isHeadlessOutputFormat, isKeyAction, isLang, isMentionableFilePath, isOperationType, isPermissionLevel, isPlanOutcome, isProviderType, isQuestionAnswerMap, isSearchProviderType, isValidAgentRoleName, isValidCommandName, isWireGoalPhase, isWireHubEvent, isWirePlanAction, isWireRewindScope, isWireSettingWriteLayer, makeTranslate, normalizeApproval, packSessionSurface, parseChord, parseModelRef, parseSequence, perAction, placeholdersOf, promptTokens, resolveHostText, sequenceId, sessionPartSummary, stripSystemNote, systemNote, tableOf, totalUsageTokens, translatorFor, turnDigest, unfixedRules, utf8ByteLength, wireFields };
|
|
14620
|
+
export { ACTION_CONTEXTS, AGENT_ROLE_NAME_PATTERN, API_KEY_ENV_VARS, APPROVAL_OUTCOMES, type ActiveAgentRole, type AgentEvent, type AgentEventOf, type AgentEventType, type AgentRole, type AgentRoleScope, type AgentRoleSource, type ApprovalAnswer, type ApprovalOutcome, type ApprovalReply, type ApprovalRequest, type ArtifactKind, type AttributeValue, type Attributes, type BackgroundTaskInfo, type BackgroundTaskKind, type BackgroundTaskStatus, type BlankCard, type BlankGreeting, type BoundKey, type BudgetBreach, COMMAND_NAME_PATTERN, COMPLIANCE_ACTIONS, COMPLIANCE_CATEGORIES, CURRENCIES, type Catalogs, type ComplianceAction, type ComplianceCategory, type ContextBreakdown, type ContextSegment, type Currency, type CurrencyDisplay, type CustomCommandDef, type CustomCommandSource, DEFAULT_AGENT_ROLE, DEFAULT_LANG, type DecidedTrustLevel, type Diagnostic, DiagnosticSink, type DiagnosticStatus, type EpochConfig, type EpochContentPart, type EpochFilePart, type EpochHook, type EpochImagePart, type EpochMessage, type EpochMessageRole, type EpochPlugin, type EpochSessionPart, type EpochSkill, type EpochTextPart, type EpochTool, type EpochToolCall, type EpochToolResult, type EpochTurnFacts, type EpochUserContent, type ExpandedCommand, type FileOmitReason, type FinishReason, type FixableApproval, type FlatCatalog, type FormatMoneyOptions, GEN_AI, HEADLESS_INPUT_EVENT_TYPES, HEADLESS_INPUT_FORMATS, HEADLESS_OUTPUT_FORMATS, HEADLESS_PROTOCOL_VERSION, type HeadlessEnvelope, type HeadlessEvent, type HeadlessInit, type HeadlessInputEvent, type HeadlessInputEventType, type HeadlessInputFormat, type HeadlessLifecycleEvent, type HeadlessOutputFormat, type HeadlessResult, type HeadlessResultReason, type HookContext, type HookEvent, type HookHandler, type HookManager, type HookRegistration, type HookType, type HostText, type HostUser, type JsonSchema, KEY_ACTIONS, type KeyAction, type KeyChord, type KeyContext, type KeySequence, type KeybindingReport, type KeybindingSource, type KeybindingTable, LANGS, type Lang, type LocalizedDetail, type LogFn, MAX_ATTACH_BYTES, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_HEADER_CHARS, MAX_OPTIONS, MAX_QUESTIONS, MAX_SESSION_ATTACH_BYTES, MAX_SESSION_REFS, MCP_DATA_KEY_NAME, METRIC, MIN_OPTIONS, type MentionSet, type ModelRef, type ModelSelection, type ModelSelectionOrigin, type MoneyDigits, NOOP_TELEMETRY, type NoticeCode, OPERATION_TYPES, OVERSIZE_RATIO, type Operation, type OperationType, PERMISSION_LEVELS, PLAN_OUTCOMES, PROVIDER_INFOS, PROVIDER_TYPES, type PermissionDecision, type PermissionLevel, type PermissionManager, type PermissionRuleLists, type PlanApprovalOutcome, type PlanProposal, type PluginContext, type ProviderInfo, type ProviderType, type QuestionAnswer, type QuestionItem, type QuestionOption, type QuestionRequest, RESERVED_CHORDS, RESERVED_COMMAND_NAMES, type RejectReason, type RejectedKey, type RuleValue, SCHEDULE_DRAFT_TOOL, SCHEDULE_INTERVAL_MINUTES, SCHEDULE_RUN_STATUSES, SCHEDULE_TEMPLATES, SEARCH_API_KEY_ENV, SEARCH_PROVIDER_TYPES, SECRET_SERVICE, SEQUENCE_CONTEXTS, SESSION_MENTION_PREFIX, SESSION_REFERENCE_ERROR_CODES, SHELL_KINDS, SIDEBAR_MENU_MESSAGE_TYPE, SIMULTANEOUS_CONTEXTS, SYSTEM_NOTE_PREFIX, type ScheduleAllowlist, type ScheduleBackendKind, type ScheduleCycle, type ScheduleDefinition, type ScheduleDraft, type ScheduleDraftAllowlist, type ScheduleDraftCreate, type ScheduleDraftPermission, type ScheduleDraftUpdate, type SchedulePendingApproval, type SchedulePendingItem, type ScheduleRun, type ScheduleRunStatus, type ScheduleRunnerSpec, type ScheduleTemplate, type ScheduleTemplateId, type ScheduleTrigger, type ScheduleTriggerKind, type ScheduleWeekday, type ScheduleWideningKind, type SearchProviderType, type SecretBackendId, type SecretStore, type SelectionContext, type SelectionRejection, type SelectionWarning, type SessionAttachKind, type SessionAttachResult, type SessionOmitReason, type SessionSurfaceMessage, type SessionSurfaceView, type SetSelectionResult, type ShellKind, type SidebarMenuItem, type SidebarMenuMessage, type SpanLike, type SubToolCall, type SubToolCallResult, type Telemetry, type TokenUsage, type ToolAnnotations, type ToolArtifact, type ToolArtifactInput, type ToolContext, type ToolDefinition, ToolExposure, type ToolProvider, type ToolResult, type Translate, type TranslateVars, type TrustExecGrant, type TrustGrant, type TrustLevel, type TrustManager, type TrustRecord, type TrustScope, type TrustTier, UNLIMITED_TURNS, type VerifyResult, WIRE_ABORT_FIELDS, WIRE_ABOUT_FIELDS, WIRE_AGENT_ROLE_FIELDS, WIRE_APPROVAL_CACHE_REVOKE_REQUEST_FIELDS, WIRE_APPROVAL_CACHE_REVOKE_RESPONSE_FIELDS, WIRE_APPROVAL_LIST_FIELDS, WIRE_APPROVAL_ROW_FIELDS, WIRE_ARTIFACTS_FIELDS, WIRE_ATTACHMENT_UPLOAD_FIELDS, WIRE_AUDIT_LOG_FIELDS, WIRE_AUDIT_ROW_FIELDS, WIRE_AUTH_COOKIE, WIRE_AUTH_COOKIE_ATTRS, WIRE_AUTH_TOKEN_PARAM, WIRE_BACKGROUND_TASK_FIELDS, WIRE_BLOCKED_GOALS_FIELDS, WIRE_BLOCKED_GOAL_FIELDS, WIRE_BLOCKED_LEVEL_FIELDS, WIRE_BUILTIN_CONNECTOR_FIELDS, WIRE_CACHED_APPROVAL_FIELDS, WIRE_CAPABILITIES_FIELDS, WIRE_CAPABILITY_PROJECT_FIELDS, WIRE_CHECKPOINT_LIST_FIELDS, WIRE_CHECKPOINT_SUMMARY_FIELDS, WIRE_COMMANDS_FIELDS, WIRE_COMMAND_EXPANSION_FIELDS, WIRE_COMPACT_FIELDS, WIRE_COMPRESSION_LINE_FIELDS, WIRE_CONFIG_FIELDS, WIRE_CONTEXT_FIELDS, WIRE_CREATE_SESSION_FIELDS, WIRE_CREATE_WORKSPACE_FIELDS, WIRE_CREATE_WORKSPACE_RESPONSE_FIELDS, WIRE_CUSTOM_COMMAND_FIELDS, WIRE_DELETE_SESSION_FIELDS, WIRE_DIFF_FILE_FIELDS, WIRE_ERROR_FIELDS, WIRE_FILE_CANDIDATES_FIELDS, WIRE_FILE_CANDIDATE_FIELDS, WIRE_FILE_CHANGE_FIELDS, WIRE_FILE_OPEN_RESPONSE_FIELDS, WIRE_FILE_REFERENCE_FIELDS, WIRE_FILE_STAT_MAX, WIRE_FILE_STAT_OK_FIELDS, WIRE_FILE_STAT_REFUSED_FIELDS, WIRE_FILE_STAT_RESPONSE_FIELDS, WIRE_FILE_TEXT_RESPONSE_FIELDS, WIRE_FORGET_WORKSPACE_FIELDS, WIRE_FORGET_WORKSPACE_RESPONSE_FIELDS, WIRE_GOAL_ACTIONS, WIRE_GOAL_BLOCK_FIELDS, WIRE_GOAL_CLEAR_FIELDS, WIRE_GOAL_CREATE_FIELDS, WIRE_GOAL_FIELDS, WIRE_GOAL_LIMITS_FIELDS, WIRE_GOAL_PHASES, WIRE_GOAL_REFUSALS, WIRE_GOAL_RESPONSE_FIELDS, WIRE_GOAL_WRITE_FIELDS, WIRE_HEALTH_FIELDS, WIRE_IMAGE_REFERENCE_FIELDS, WIRE_KNOWN_WORKSPACE_FIELDS, WIRE_LANG_PARAM, WIRE_MANAGED_LOCK_FIELDS, WIRE_MCP_ADD_FIELDS, WIRE_MCP_ADD_RESPONSE_FIELDS, WIRE_MCP_APPLY_ENTRY_FIELDS, WIRE_MCP_APPLY_RESPONSE_FIELDS, WIRE_MCP_CONFIG_APPLY_FIELDS, WIRE_MCP_CONFIG_FIELDS, WIRE_MCP_CONFIG_ISSUE_FIELDS, WIRE_MCP_CONFIG_SAVE_FIELDS, WIRE_MCP_CONFIG_SAVE_RESPONSE_FIELDS, WIRE_MCP_CONNECTOR_FIELDS, WIRE_MCP_RECONNECT_FIELDS, WIRE_MESSAGE_LIST_FIELDS, WIRE_MODEL_FIELDS, WIRE_MODEL_SELECTION_FIELDS, WIRE_MODEL_SET_FIELDS, WIRE_MODEL_SUGGESTIONS_FIELDS, WIRE_PATCH_SESSION_FIELDS, WIRE_PATCH_SESSION_RESPONSE_FIELDS, WIRE_PERMISSION_RULE_FIELDS, WIRE_PERMISSION_SET_REQUEST_FIELDS, WIRE_PERMISSION_SET_RESPONSE_FIELDS, WIRE_PERMISSION_SHADOW_FIELDS, WIRE_PERMISSION_STATE_FIELDS, WIRE_PERMISSION_STATUS_FIELDS, WIRE_PLAN_ACTIONS, WIRE_PLAN_FIELDS, WIRE_PLAN_MODE_REQUEST_FIELDS, WIRE_PLAN_MODE_RESPONSE_FIELDS, WIRE_PLAN_MODE_STATE_FIELDS, WIRE_PLUGINS_FIELDS, WIRE_PLUGIN_ACTION_FIELDS, WIRE_PLUGIN_ARCHIVE_SUFFIXES, WIRE_PLUGIN_INSTALL_FIELDS, WIRE_PLUGIN_LOCAL_FIELDS, WIRE_PLUGIN_LOCAL_INSTALL_FIELDS, WIRE_PLUGIN_MARKETPLACE_FIELDS, WIRE_PLUGIN_MARKETPLACE_RESPONSE_FIELDS, WIRE_PLUGIN_NAME_FIELDS, WIRE_PLUGIN_PREVIEW_FIELDS, WIRE_PLUGIN_PREVIEW_RESPONSE_FIELDS, WIRE_PLUGIN_REFRESH_RESPONSE_FIELDS, WIRE_PLUGIN_STAGE_FIELDS, WIRE_PLUGIN_STAGE_RESPONSE_FIELDS, WIRE_PLUGIN_UPDATE_FIELDS, WIRE_PLUGIN_UPLOAD_CONFIRM_FIELDS, WIRE_PLUGIN_UPLOAD_FIELDS, WIRE_PLUGIN_UPLOAD_FORM_FIELDS, WIRE_PLUGIN_UPLOAD_PREVIEW_RESPONSE_FIELDS, WIRE_PLUGIN_UPLOAD_RESPONSE_FIELDS, WIRE_POLICY_DIR_FIELDS, WIRE_POLICY_STATUS_FIELDS, WIRE_PROJECT_INVENTORY_FIELDS, WIRE_PROVIDERS_FIELDS, WIRE_PROVIDER_KEY_FIELDS, WIRE_PROVIDER_MODELS_FIELDS, WIRE_PROVIDER_OPTION_FIELDS, WIRE_QUESTION_LIST_FIELDS, WIRE_QUESTION_ROW_FIELDS, WIRE_RESPOND_APPROVAL_FIELDS, WIRE_RESPOND_APPROVAL_RESPONSE_FIELDS, WIRE_RESPOND_QUESTION_FIELDS, WIRE_RESPOND_QUESTION_RESPONSE_FIELDS, WIRE_REWIND_FILE_PLAN_FIELDS, WIRE_REWIND_OUTCOME_FIELDS, WIRE_REWIND_PREVIEW_FIELDS, WIRE_REWIND_REQUEST_FIELDS, WIRE_REWIND_RESPONSE_FIELDS, WIRE_REWIND_SCOPES, WIRE_ROLE_ADD_FIELDS, WIRE_ROLE_ADD_RESPONSE_FIELDS, WIRE_SANDBOX_STATUS_FIELDS, WIRE_SCHEDULE_CAPABILITY_FIELDS, WIRE_SCHEDULE_CREATE_FIELDS, WIRE_SCHEDULE_DEFAULTS_FIELDS, WIRE_SCHEDULE_DELETE_FIELDS, WIRE_SCHEDULE_FIELDS, WIRE_SCHEDULE_FIX_FIELDS, WIRE_SCHEDULE_FIX_REQUEST_FIELDS, WIRE_SCHEDULE_ISSUE_CODES, WIRE_SCHEDULE_LIST_FIELDS, WIRE_SCHEDULE_PENDING_FIELDS, WIRE_SCHEDULE_RECORDING_FIELDS, WIRE_SCHEDULE_ROW_FIELDS, WIRE_SCHEDULE_RUNS_FIELDS, WIRE_SCHEDULE_RUN_FIELDS, WIRE_SCHEDULE_SAVE_FIELDS, WIRE_SECURITY_FIELDS, WIRE_SECURITY_WORKSPACE_FIELDS, WIRE_SEND_MESSAGE_FIELDS, WIRE_SEND_MESSAGE_RESPONSE_FIELDS, WIRE_SESSION_CANDIDATES_FIELDS, WIRE_SESSION_CANDIDATE_FIELDS, WIRE_SESSION_FINISH_FIELDS, WIRE_SESSION_LIST_FIELDS, WIRE_SESSION_REFERENCE_FIELDS, WIRE_SESSION_RESPONSE_FIELDS, WIRE_SESSION_SUMMARY_FIELDS, WIRE_SESSION_WORKSPACE_FIELDS, WIRE_SESSION_WORKSPACE_RESPONSE_FIELDS, WIRE_SETTINGS_FIELDS, WIRE_SETTINGS_WRITE_FIELDS, WIRE_SETTINGS_WRITE_REQUEST_FIELDS, WIRE_SETTING_ROW_FIELDS, WIRE_SETTING_STEP_FIELDS, WIRE_SETTING_WRITE_FIELDS, WIRE_SETTING_WRITE_LAYERS, WIRE_SKILL_BODY_FIELDS, WIRE_SKILL_DROP_SUFFIXES, WIRE_SKILL_FIELDS, WIRE_SKILL_IMPORT_FIELDS, WIRE_SKILL_IMPORT_PREVIEW_FIELDS, WIRE_SKILL_REMOVE_FIELDS, WIRE_SKILL_STAGE_FIELDS, WIRE_TASKS_FIELDS, WIRE_TOOLS_FIELDS, WIRE_TOOL_GATE_FIELDS, WIRE_TOOL_ROW_FIELDS, WIRE_TRUST_REQUEST_FIELDS, WIRE_TRUST_REQUEST_RESPONSE_FIELDS, WIRE_WORKSPACE_DIFF_FIELDS, WIRE_WORKSPACE_DIRS_FIELDS, WIRE_WORKSPACE_DIR_ENTRY_FIELDS, WIRE_WORKSPACE_REF_FIELDS, type WireAbortResponse, type WireAbout, type WireAgentEnvelope, type WireAgentEvent, type WireAgentRoleSummary, type WireApprovalCacheRevokeRequest, type WireApprovalCacheRevokeResponse, type WireApprovalListResponse, type WireApprovalRequest, type WireArtifactsResponse, type WireAttachmentUploadResponse, type WireAuditCode, type WireAuditLog, type WireAuditOutcome, type WireAuditRow, type WireAuthDenyReason, type WireAuthDenyStatus, type WireAuthGuard, type WireAuthRequestView, type WireAuthVerdict, type WireBackgroundTask, type WireBindWorkspaceRequest, type WireBlockedGoal, type WireBlockedGoalsResponse, type WireBlockedLevel, type WireBuiltinConnector, type WireCachedApproval, type WireCachedDecision, type WireCapabilitiesResponse, type WireCapabilityProject, type WireCheckpointListResponse, type WireCheckpointSummary, type WireCommandExpansion, type WireCommandsResponse, type WireCompactRequest, type WireCompactResponse, type WireCompressionLine, type WireConfigResponse, type WireContextResponse, type WireCreateSessionRequest, type WireCreateSessionResponse, type WireCreateWorkspaceRequest, type WireCreateWorkspaceResponse, type WireCustomCommand, type WireDeleteSessionResponse, type WireDiffFile, type WireDiffNote, type WireDiffOmitReason, type WireDiffSource, type WireDiffStatus, type WireEnvelope, type WireErrorResponse, type WireEvent, type WireFields, type WireFileCandidate, type WireFileCandidatesResponse, type WireFileChange, type WireFileKind, type WireFileOpenRefusal, type WireFileOpenResponse, type WireFileReference, type WireFileRefusal, type WireFileStat, type WireFileStatOk, type WireFileStatRefused, type WireFileStatResponse, type WireFileTextResponse, type WireFixture, type WireFixtureCase, type WireForgetWorkspaceRequest, type WireForgetWorkspaceResponse, type WireGoal, type WireGoalBlock, type WireGoalClearResponse, type WireGoalCreateRequest, type WireGoalLimits, type WireGoalPhase, type WireGoalRefusal, type WireGoalResponse, type WireGoalUpdateRequest, type WireGoalWriteResponse, type WireHealthResponse, type WireHubEnvelope, type WireHubEvent, type WireImageReference, type WireKnownWorkspace, type WireKnownWorkspaceRef, type WireManagedLock, type WireMcpAddRequest, type WireMcpAddResponse, type WireMcpApplyAction, type WireMcpApplyEntry, type WireMcpApplyResponse, type WireMcpConfigApplyRequest, type WireMcpConfigIssue, type WireMcpConfigResponse, type WireMcpConfigSaveRequest, type WireMcpConfigSaveResponse, type WireMcpConnector, type WireMcpReconnectResponse, type WireMessageListResponse, type WireModelCaveat, type WireModelProbeStatus, type WireModelRejection, type WireModelResponse, type WireModelSelection, type WireModelSetRequest, type WireModelSetResponse, type WireModelSource, type WireModelSuggestions, type WirePatchSessionRequest, type WirePatchSessionResponse, type WirePermissionRememberFailure, type WirePermissionRuleRow, type WirePermissionSetRequest, type WirePermissionSetResponse, type WirePermissionShadow, type WirePermissionState, type WirePermissionStatus, type WirePickDirectoryResponse, type WirePlanAction, type WirePlanModeRequest, type WirePlanModeResponse, type WirePlanModeState, type WirePlanResponse, type WirePluginActionResponse, type WirePluginCounts, type WirePluginEntry, type WirePluginHit, type WirePluginHookTally, type WirePluginInstallRequest, type WirePluginLocalInstallRequest, type WirePluginLocalRequest, type WirePluginMarketplace, type WirePluginMarketplaceRequest, type WirePluginMarketplaceResponse, type WirePluginNameRequest, type WirePluginPreview, type WirePluginPreviewRequest, type WirePluginPreviewResponse, type WirePluginRefreshResponse, type WirePluginRefuseReason, type WirePluginSourceType, type WirePluginStageRequest, type WirePluginStageResponse, type WirePluginStatus, type WirePluginUpdateRequest, type WirePluginUploadConfirmRequest, type WirePluginUploadField, type WirePluginUploadFieldName, type WirePluginUploadFields, type WirePluginUploadFile, type WirePluginUploadForm, type WirePluginUploadPlan, type WirePluginUploadPreviewResponse, type WirePluginUploadRequest, type WirePluginUploadResponse, type WirePluginVisibility, type WirePluginsResponse, type WirePolicyDir, type WirePolicyStatus, type WireProjectInventory, type WireProviderKeyRequest, type WireProviderKeyResponse, type WireProviderModelsRequest, type WireProviderModelsResponse, type WireProviderOption, type WireProviderSummary, type WireProvidersResponse, type WireQuestionListResponse, type WireQuestionRequest, type WireReplayMessage, type WireResetReason, type WireRespondApprovalRequest, type WireRespondApprovalResponse, type WireRespondQuestionRequest, type WireRespondQuestionResponse, type WireRewindAction, type WireRewindDrift, type WireRewindFilePlan, type WireRewindOutcome, type WireRewindPreview, type WireRewindRequest, type WireRewindResponse, type WireRewindScope, type WireRoleAddRequest, type WireRoleAddResponse, type WireSandboxReason, type WireSandboxStatus, type WireScheduleCapability, type WireScheduleCreateRequest, type WireScheduleDefaults, type WireScheduleDeleteResponse, type WireScheduleFixRequest, type WireScheduleFixResponse, type WireScheduleIssue, type WireScheduleIssueCode, type WireScheduleListResponse, type WireSchedulePendingResponse, type WireScheduleRecordingResponse, type WireScheduleRegisterRefusal, type WireScheduleRegisterWarning, type WireScheduleRegistration, type WireScheduleResponse, type WireScheduleRow, type WireScheduleRunResponse, type WireScheduleRunsResponse, type WireScheduleSaveResponse, type WireScheduleUpdateRequest, type WireSecurityResponse, type WireSecurityWorkspace, type WireSendMessageRequest, type WireSendMessageResponse, type WireSessionCandidate, type WireSessionCandidatesResponse, type WireSessionFinish, type WireSessionListResponse, type WireSessionReference, type WireSessionResponse, type WireSessionSummary, type WireSessionWorkspace, type WireSessionWorkspaceResponse, type WireSettingApply, type WireSettingFutile, type WireSettingLayer, type WireSettingRow, type WireSettingStep, type WireSettingValue, type WireSettingValueKind, type WireSettingWrite, type WireSettingWriteLayer, type WireSettingsResponse, type WireSettingsWriteRequest, type WireSettingsWriteResponse, type WireSkillBodyResponse, type WireSkillImportConflict, type WireSkillImportEntry, type WireSkillImportFailure, type WireSkillImportForm, type WireSkillImportIssue, type WireSkillImportPreviewResponse, type WireSkillImportResponse, type WireSkillRemoveFailure, type WireSkillRemoveResponse, type WireSkillStageFailure, type WireSkillStageResponse, type WireSkillSummary, type WireSummaryWorkspace, type WireTaggedEvent, type WireTasksResponse, type WireToolGate, type WireToolGateAxis, type WireToolRow, type WireToolSummary, type WireToolVerdict, type WireToolsResponse, type WireTrustRequestRequest, type WireTrustRequestResponse, type WireTurnState, type WireWorkspaceBinding, type WireWorkspaceDiffResponse, type WireWorkspaceDirEntry, type WireWorkspaceDirsResponse, type WireWorkspaceRef, apiKeyEnvVar, assertNeverPart, assistantTurnText, attachSessionSurface, chordId, collectPendingApprovals, compressionThresholdTokens, conformsToWire, contentToText, diagnosticToLine, extractAllMentions, extractMentions, extractSessionMentions, filePartSummary, flattenCatalog, formatMoney, getProviderInfo, hasFailure, imagePartOmittedSummary, isApprovalOutcome, isContextNearlyFull, isCurrency, isHeadlessInputFormat, isHeadlessLifecycleEvent, isHeadlessOutputFormat, isKeyAction, isLang, isMentionableFilePath, isOperationType, isPermissionLevel, isPlanOutcome, isPromptOversize, isProviderType, isQuestionAnswerMap, isSearchProviderType, isValidAgentRoleName, isValidCommandName, isWireGoalPhase, isWireHubEvent, isWirePlanAction, isWirePluginArchiveName, isWireRewindScope, isWireSettingWriteLayer, isWireSkillDropName, makeTranslate, mcpConnectorState, normalizeApproval, packSessionSurface, parseChord, parseModelRef, parseSequence, perAction, placeholdersOf, promptTokens, resolveHostText, sequenceId, sessionPartSummary, stripSystemNote, systemNote, tableOf, totalUsageTokens, translatorFor, truncateToBudget, turnDigest, unfixedRules, utf8ByteLength, wireFields };
|