@epoch-agent/core 0.2.0 → 0.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
- import { ToolProvider, EpochTool, EpochPlugin, ToolExposure, EpochSkill, HookType, EpochHook, PluginContext, QuestionRequest, QuestionAnswer, AgentRole, PermissionLevel, PermissionManager as PermissionManager$1, PlanProposal, ApprovalRequest, ApprovalReply, DiagnosticSink, AgentRoleSource, CustomCommandDef, ModelRef, ExpandedCommand, CustomCommandSource, BackgroundTaskInfo, ContextBreakdown, EpochMessage, AgentRoleScope, ToolArtifactInput, ToolArtifact, TrustLevel, TrustManager as TrustManager$1, TokenUsage, EpochConfig, BudgetBreach, ProviderType, JsonSchema, ModelSelection, EpochToolCall, Telemetry, HookManager as HookManager$1, EpochUserContent, EpochContentPart, AgentEvent, SelectionContext, SetSelectionResult, PermissionRuleLists, KeybindingTable, Diagnostic, KeybindingReport, FileOmitReason, SessionOmitReason, EpochToolResult, EpochTurnFacts, LocalizedDetail, OperationType, RuleValue, Operation, ApprovalOutcome, PermissionDecision, ScheduleTrigger, ScheduleAllowlist, ScheduleDefinition, ScheduleBackendKind, ScheduleRunStatus, ScheduleRun, SchedulePendingApproval, WireAgentEvent, WireAgentEnvelope, ScheduleRunnerSpec, HookEvent, LogFn, HookRegistration, HookHandler, HookContext, VerifyResult, Lang, EpochFilePart, EpochSessionPart, MentionSet, EpochImagePart, DecidedTrustLevel, TrustScope, TrustRecord } from '@epoch-agent/protocol';
2
- export { API_KEY_ENV_VARS, AgentEvent, AgentEventOf, AgentEventType, ApprovalAnswer, ApprovalOutcome, ApprovalReply, ApprovalRequest, BudgetBreach, DecidedTrustLevel, EpochConfig, EpochHook, EpochPlugin, EpochSkill, EpochTool, FinishReason, HookContext, HookEvent, HookHandler, HookRegistration, HookType, HookManager as IHookManager, PermissionManager as IPermissionManager, TrustManager as ITrustManager, JsonSchema, MAX_ATTACH_BYTES, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_ATTACH_BYTES, MAX_SESSION_REFS, OPERATION_TYPES, Operation, OperationType, PERMISSION_LEVELS, PLAN_OUTCOMES, PROVIDER_INFOS, PROVIDER_TYPES, PermissionDecision, PermissionLevel, PlanApprovalOutcome, PlanProposal, PluginContext, ProviderInfo, ProviderType, TokenUsage, ToolContext, ToolDefinition, ToolExposure, ToolResult, TrustLevel, TrustRecord, TrustScope, VerifyResult, apiKeyEnvVar, extractAllMentions, extractMentions, extractSessionMentions, getProviderInfo, isOperationType, isPermissionLevel, isPlanOutcome, isProviderType, normalizeApproval } from '@epoch-agent/protocol';
1
+ import { ToolProvider, EpochTool, EpochPlugin, ToolExposure, EpochSkill, HookType, EpochHook, PluginContext, QuestionRequest, QuestionAnswer, AgentRole, PermissionLevel, PermissionManager as PermissionManager$1, PlanProposal, ApprovalRequest, ApprovalReply, DiagnosticSink, AgentRoleSource, CustomCommandDef, ModelRef, ExpandedCommand, CustomCommandSource, BackgroundTaskInfo, ContextBreakdown, EpochMessage, AgentRoleScope, ComplianceCategory, ComplianceAction, ToolArtifactInput, ToolArtifact, TrustLevel, TrustManager as TrustManager$1, TokenUsage, EpochConfig, BudgetBreach, ProviderType, JsonSchema, ModelSelection, EpochToolCall, Telemetry, HookManager as HookManager$1, EpochUserContent, EpochContentPart, AgentEvent, SelectionContext, SetSelectionResult, PermissionRuleLists, KeybindingTable, Diagnostic, KeybindingReport, FileOmitReason, SessionOmitReason, EpochToolResult, EpochTurnFacts, LocalizedDetail, OperationType, RuleValue, Operation, ApprovalOutcome, PermissionDecision, ScheduleTrigger, ScheduleAllowlist, ScheduleDefinition, ScheduleBackendKind, ScheduleRunStatus, ScheduleRun, SchedulePendingApproval, WireAgentEvent, WireAgentEnvelope, ScheduleRunnerSpec, HookEvent, LogFn, HookRegistration, HookHandler, HookContext, VerifyResult, Lang, EpochFilePart, EpochSessionPart, MentionSet, EpochImagePart, DecidedTrustLevel, TrustScope, TrustRecord } from '@epoch-agent/protocol';
2
+ export { API_KEY_ENV_VARS, AgentEvent, AgentEventOf, AgentEventType, ApprovalAnswer, ApprovalOutcome, ApprovalReply, ApprovalRequest, BudgetBreach, COMPLIANCE_ACTIONS, COMPLIANCE_CATEGORIES, ComplianceAction, ComplianceCategory, DecidedTrustLevel, EpochConfig, EpochHook, EpochPlugin, EpochSkill, EpochTool, FinishReason, HookContext, HookEvent, HookHandler, HookRegistration, HookType, HookManager as IHookManager, PermissionManager as IPermissionManager, TrustManager as ITrustManager, JsonSchema, MAX_ATTACH_BYTES, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_ATTACH_BYTES, MAX_SESSION_REFS, OPERATION_TYPES, Operation, OperationType, PERMISSION_LEVELS, PLAN_OUTCOMES, PROVIDER_INFOS, PROVIDER_TYPES, PermissionDecision, PermissionLevel, PlanApprovalOutcome, PlanProposal, PluginContext, ProviderInfo, ProviderType, TokenUsage, ToolContext, ToolDefinition, ToolExposure, ToolResult, TrustLevel, TrustRecord, TrustScope, VerifyResult, apiKeyEnvVar, extractAllMentions, extractMentions, extractSessionMentions, getProviderInfo, isOperationType, isPermissionLevel, isPlanOutcome, isProviderType, normalizeApproval } from '@epoch-agent/protocol';
3
3
  import { IsolationBackend, SqliteDatabase, ParseIssue, ShellFlavor } from '@epoch-agent/infra';
4
- export { BubblewrapOptions, DangerMatch, IS_WINDOWS, IsolationBackend, IsolationOptions, LogLevel, SeatbeltOptions, WINDOWS_HIDE_FLAGS, buildBwrapArgs, buildProfile, checkDangerousCommand, checkObfuscation, createLogger, detectBackend, getDefaultShell, getPythonCommand, isInWorkspace, isReadOnlyCommand, isolate, maskApiKey, probeBubblewrap, probeSeatbelt, policiesDir as resolvePoliciesDir, setLogLevel } from '@epoch-agent/infra';
4
+ export { BubblewrapOptions, DangerMatch, IS_WINDOWS, IsolationBackend, IsolationOptions, LogLevel, SeatbeltOptions, WINDOWS_HIDE_FLAGS, buildBwrapArgs, buildProfile, checkDangerousCommand, checkObfuscation, createLogger, detectBackend, getDefaultShell, getPythonCommand, isInWorkspace, isReadOnlyCommand, isolate, maskApiKey, probeBubblewrap, probeSeatbelt, complianceDir as resolveComplianceDir, policiesDir as resolvePoliciesDir, setLogLevel } from '@epoch-agent/infra';
5
5
  import { z } from 'zod';
6
6
  import { existsSync } from 'node:fs';
7
7
 
@@ -2729,7 +2729,23 @@ interface SkillSystem$1 {
2729
2729
  create(name: string, content: string, category?: string): Promise<string>;
2730
2730
  edit(name: string, content: string): Promise<void>;
2731
2731
  patch(name: string, oldString: string, newString: string, filePath?: string): Promise<void>;
2732
- delete(name: string, absorbedInto?: string): Promise<void>;
2732
+ /**
2733
+ * 删掉一个技能 —— **整个技能目录,递归删,没有回收站**。
2734
+ *
2735
+ * 回的是**刚被删掉的那个绝对路径**(`<技能目录>/<分类>/<名字>`)。
2736
+ * 2026-09-01 从 `Promise<void>` 改的,为的是让调用方能把「我到底销毁了什么」
2737
+ * 原样说给用户听 —— 一个不可撤销的动作,回执上只有一个技能名说不清楚
2738
+ * (同名的东西在盘上可能不止一处,而这一层知道是哪一处)。
2739
+ *
2740
+ * ⚠️ 项目级 / 插件 / 宿主那三档会**抛**(`requireWritable`),不是回一个
2741
+ * 布尔:拒绝的理由各不相同,而每一条都带着「那该去哪儿改」。
2742
+ *
2743
+ * ⚠️ **2026-09-01 之前这个方法零生产调用者**(唯一的调用点 `maintain()`
2744
+ * 是死代码,判据在 {@link SkillStats} 上)。今天它有一个:web 能力页技能那一栏
2745
+ * 的「删除」(`POST /api/skills/remove`)。所以往这儿加自动触发的调用点之前,
2746
+ * 先读 {@link SkillStats} 那一段 —— 那是这个方法上一次差点变成静默数据丢失。
2747
+ */
2748
+ delete(name: string, absorbedInto?: string): Promise<string>;
2733
2749
  writeFile(name: string, filePath: string, content: string): Promise<void>;
2734
2750
  removeFile(name: string, filePath: string): Promise<void>;
2735
2751
  invalidateCache(): void;
@@ -2825,7 +2841,7 @@ interface SkillSystem$1 {
2825
2841
  * 加一个 `only` 或者一个 `role`。** 会红的用例:`core/__tests__/skill-in-prompt.test.ts`
2826
2842
  * 里「被收窄过的角色照样读得到白名单外那条技能的正文」。
2827
2843
  *
2828
- * 顺带一条**不是劈叉**的东西:下面 {@link available} 在名字打错时会把全量技能名
2844
+ * 顺带一条**不是劈叉**的东西:下面 {@link describeAvailableSkills} 在名字打错时会把全量技能名
2829
2845
  * (≤20 个)列给一个被收窄过的子 agent。既然这个工具本来就对全量开放,那份清单
2830
2846
  * 和政策**是一致的** —— 它是一笔预算上的小漏(打错那一次多花几十个 token),
2831
2847
  * 不是边界上的漏。不修,理由记在 protocol 那一段末尾。
@@ -2870,6 +2886,116 @@ interface SkillViewDeps {
2870
2886
  */
2871
2887
  declare function createSkillViewTool(deps: SkillViewDeps): EpochTool;
2872
2888
 
2889
+ /**
2890
+ * `skill_create` / `skill_edit` / `skill_patch` / `skill_write_file` ——
2891
+ * 模型**写**技能的那四条路(2026-09-02)。
2892
+ *
2893
+ * ## 这四个名字在此之前是**假话**
2894
+ *
2895
+ * `SkillSystem` 上六个写方法(`create` / `edit` / `patch` / `delete` /
2896
+ * `writeFile` / `removeFile`)从引入那天起就在,而**一个生产调用者都没有**:
2897
+ * 人侧那条路只有「导入一整个文件夹」和「删掉一个」两条(`SkillControl`),
2898
+ * 模型侧只有只读的 `skill_view`。
2899
+ *
2900
+ * 要紧的是仓库里已经在**按这几个名字说话**:
2901
+ *
2902
+ * | 原话在哪 | 说了什么 |
2903
+ * | ---------------------------------------------------------- | ---------------------------------------------- |
2904
+ * | [import-source.ts](../../skill/import-source.ts) 文件头 | 白名单和 `skill_write_file` 是同一份,否则导入会变成一条绕过它的路 |
2905
+ * | [manager.ts](../../skill/manager.ts) `requireWritable()` | 少了 `host` 那一支,`skill_edit` 会往一个 .app 包里写文件 |
2906
+ * | [docs/TOOLS.md](../../../../../docs/TOOLS.md) | 「`skill_edit` 之类会被拒,读取从来不在被拒之列」 |
2907
+ *
2908
+ * `git log --all -S"name: 'skill_write_file'"`(含另两个名字)在**全部历史里零
2909
+ * 命中** —— 那三段话指着的是空气。第一段最贵:它是一条**安全断言**,而白名单
2910
+ * 确实写在 `writeFile()` 里、只是没有任何一条路走得到它,于是「两处必须是同一份」
2911
+ * 长期只有一处是活的。这个文件把那三段话变成真的。
2912
+ *
2913
+ * ## ⚠️ 一、`create` 那一格的名字**必须自己校验**,别指望下一层
2914
+ *
2915
+ * `SkillSystem.create()` 的落点是 `join(skillsDir, category, name)` —— 一个
2916
+ * `name: '../../..'` 直接写到技能目录外面去。这一层校验是为了给一句说得清的话,
2917
+ * **真闸门在 `create()` 自己身上**(同一轮补的):判据是「断言要落在会说谎的
2918
+ * 那一层」,而会说谎的是产地不是门面 —— 哪天有第二个调用方(`SkillLearner`
2919
+ * 已经是一个)它照样得被挡住。
2920
+ *
2921
+ * ⚠️ 反过来,`edit` / `patch` / `write_file` 那三个的 `name` **不校验字符集**,
2922
+ * 那不是漏了:它们收的是一个**查询键**,落点由 `SkillSystem` 自己在它扫出来的
2923
+ * 那张表里查(判据逐字同 `SkillControl.remove` 上那句「它收的是技能名,不是
2924
+ * 路径」)。在这儿加一道字符集检查只会把一个合法的既有技能挡在门外 ——
2925
+ * 手写的 `SKILL.md` 里 `name:` 爱写什么写什么,那是用户的文件。
2926
+ *
2927
+ * ## ⚠️ 二、frontmatter 的 `name:` 必须和参数里那个**一模一样**
2928
+ *
2929
+ * 索引里那个名字是 `parsed.fm.name ?? dirName`([scan.ts](../../skill/scan.ts)),
2930
+ * 也就是说**正文能改掉自己的名字**。不查这一条的表现极其难认:
2931
+ *
2932
+ * ```
2933
+ * skill_create(name: 'deploy', content: '---\nname: foo\n…') → 成功
2934
+ * skill_edit(name: 'deploy', …) → skill "deploy" not found
2935
+ * ```
2936
+ *
2937
+ * 目录叫 `deploy`、索引里叫 `foo`,两个名字都是真的,而模型手上那个不管用。
2938
+ * 所以这一层要求 frontmatter 里**写着** `name:` 且和参数相等 —— 顺带把
2939
+ * `description` 一起要过来(缺了它这条技能在 `<available_skills>` 里是一行
2940
+ * 「名字 + 空」,渐进披露的前半截当场失效,而**没有任何地方会报**)。
2941
+ *
2942
+ * ## 三、`delete` / `remove_file` 这一轮**不做**,那是决定不是欠账
2943
+ *
2944
+ * 删一个技能已经有人侧那条路(能力页 → `SkillControl.remove`,2026-09-01 加的)。
2945
+ * 不可撤销的动作先不交给模型,判据同 `SkillControl` 文件头那条「一个只能进不能
2946
+ * 出的写口不是更安全」的**反面**:那句话说的是**用户**得有出路,而用户有了。
2947
+ *
2948
+ * ⚠️ 想加的时候要答的是「模型删错一个用户手写的技能,他从哪儿知道」——
2949
+ * 而不是「能力层已经有这个方法了」。
2950
+ *
2951
+ * ## 四、错误话术为什么是英文
2952
+ *
2953
+ * 判据逐字同 [skill-view.ts](./skill-view.js) 第七节。⚠️ 但**下一层抛出来的那
2954
+ * 几句是中文的**(`requireWritable()` 走 `t('skill_load.readonly_*')`),这里
2955
+ * **原样转发不改写** —— 那三句话里带着「去哪儿改」的路径,是模型下一步唯一的
2956
+ * 依据,翻一遍只会把它译丢。
2957
+ */
2958
+
2959
+ /**
2960
+ * 四个工具名。**这是同构位置的真源** —— 另外两处认它们:
2961
+ * `permission/operation-type.ts` 的 `FILE_WRITE_TOOLS`、`docs/TOOLS.md` 顶上那张表
2962
+ * (两处由根 `__tests__/tool-registration.test.ts` 守着)。
2963
+ *
2964
+ * ⚠️ **下面 `name:` 那几格写的是字面量,不是这些常量,别「顺手」统一** ——
2965
+ * 判据全文在 `SKILL_VIEW_TOOL` 的 JSDoc 上(`.husky/commit-msg` 那道模型门禁
2966
+ * 认的是 `name: '<snake_case>',` 这一行本身)。走散由
2967
+ * `skill-write-tools.test.ts` 里那组 `expect(tool.name).toBe(…)` 钉着。
2968
+ */
2969
+ declare const SKILL_CREATE_TOOL = "skill_create";
2970
+ declare const SKILL_EDIT_TOOL = "skill_edit";
2971
+ declare const SKILL_PATCH_TOOL = "skill_patch";
2972
+ declare const SKILL_WRITE_FILE_TOOL = "skill_write_file";
2973
+ /**
2974
+ * 这四个工具要 `SkillSystem` 的哪几样。
2975
+ *
2976
+ * ⚠️ **`view` 和 `body` 都不在这里,那是刻意的。** 前者会 `matchCount++`
2977
+ * (那本账记的是「模型用过它」,一次写前的确认不该算成一次命中,判据在
2978
+ * `skill-view.ts` 文件头第一节);后者压根不该有第二个调用方。
2979
+ * 写工具**不读正文** —— 要读就调 `skill_view`,那一次计数是诚实的。
2980
+ *
2981
+ * `list` 在,只为了名字写错时给一份清单({@link describeAvailableSkills})。
2982
+ */
2983
+ interface SkillWriteDeps {
2984
+ skills: Pick<SkillSystem$1, 'create' | 'edit' | 'patch' | 'writeFile' | 'list'>;
2985
+ }
2986
+ /**
2987
+ * 建那四个写工具。
2988
+ *
2989
+ * **`SkillSystem` 在就全部注册,不管当下有没有技能** —— 判据逐字同
2990
+ * `createSkillViewTool`(技能表会在会话中途变),而这四个里 `skill_create`
2991
+ * 更是「零技能」那一档下唯一有意义的动作。
2992
+ *
2993
+ * 交出一个数组而不是四个 `createXxxTool`:装配层那一侧是一行
2994
+ * `registry.registerTools(...)`,而分成四个导出等于让「新加一个写工具」变成
2995
+ * 一次要改两个文件的改动,且漏接的表现是那个工具静默不存在。
2996
+ */
2997
+ declare function createSkillWriteTools(deps: SkillWriteDeps): EpochTool[];
2998
+
2873
2999
  /**
2874
3000
  * `tool_search` —— 把 `ToolExposure.Deferred` 那条路接上的另一半。
2875
3001
  *
@@ -4054,7 +4180,8 @@ interface SkillDirsSummary {
4054
4180
  * 算出这一次该扫哪些技能目录。
4055
4181
  *
4056
4182
  * 用户级那一份**永远在列**,哪怕目录还不存在 —— `SkillSystem` 会把它建出来,
4057
- * 因为它同时是写入目标(`skill_manager` 工具和 `SkillLearner` 都往那儿写)。
4183
+ * 因为它同时是写入目标(`SkillLearner`,以及 2026-09-02 起模型那四个写工具 ——
4184
+ * `skill_create` / `skill_edit` / `skill_patch` / `skill_write_file` —— 都往那儿写)。
4058
4185
  */
4059
4186
  declare function resolveSkillDirs(opts: ResolveSkillDirsOptions): SkillDirsSummary;
4060
4187
 
@@ -5638,6 +5765,32 @@ interface SystemPromptParams {
5638
5765
  * 逐字节相同 —— 这一条同时是 eval 那批指纹不因这次改动作废的原因。
5639
5766
  */
5640
5767
  skillIndex?: string;
5768
+ /**
5769
+ * **这一轮会用哪个模型,以及它认不认图**(2026-09-02)。
5770
+ *
5771
+ * 判据全文(用户报的那个现场、以及为什么这是「契约断了」而不是模型撒谎)
5772
+ * 在 `AgentProvider.modelId` 上,这儿不抄第二遍。一句话:
5773
+ * `## 规则` 里那条「照实说」的判据是**用户屏幕上有**,而模型的上下文里没有。
5774
+ *
5775
+ * ## ⚠️ 两格必须一起给,不许拆成两个可选字段
5776
+ *
5777
+ * 拆开的话就会出现「知道型号但不知道认不认图」那一档,而那一档的表现正是
5778
+ * 这一轮要修的病的一半:模型说得出自己是 `…-vision-exp`,却仍旧不知道
5779
+ * 能不能收图,于是继续猜。两格出自同一次现读(router 的 `getSelection()`
5780
+ * 和 `getCapability()`),本来就不该分家 —— 判据同 `AgentSite` 的
5781
+ * 「`workDir` 和 `projectContext` 两样必须一起给」。
5782
+ *
5783
+ * **不给 = `## 环境` 里那两行整个不出现 = 2026-09-02 之前逐字节相同。**
5784
+ * ⚠️ 这一条是公开 API(`buildSystemPrompt()` 嵌入宿主直接拿它当 system
5785
+ * prompt 用),所以它是**可选**的 —— 但可选的代价要说清:不给它的宿主,
5786
+ * 它的模型照旧答不出自己是谁、也照旧会把图片能力说错。
5787
+ */
5788
+ model?: {
5789
+ /** 型号原文。**照实印**,不美化不缩写 —— 用户拿它去对界面顶栏那一行 */
5790
+ id: string;
5791
+ /** 认不认图。来自 provider 自己,不是配置项 */
5792
+ supportsImages: boolean;
5793
+ };
5641
5794
  }
5642
5795
  /**
5643
5796
  * system prompt 的**分段**形态(方案 25 §2.5 的 `/context` 要它)。
@@ -5861,6 +6014,184 @@ type NudgeResult = {
5861
6014
  directive: string;
5862
6015
  };
5863
6016
 
6017
+ /**
6018
+ * 内容合规过滤 —— 类型与契约。
6019
+ *
6020
+ * ## 这一层要补的是哪个洞
6021
+ *
6022
+ * 改动前引擎里唯一和「内容不合规」有关的东西是
6023
+ * [loop.ts](../agent/loop.ts) 里那句 `result.finishReason === 'content-filter'` ——
6024
+ * 那是**别人家**的判定:provider 拒答之后我们做善后。换一家不做审核的 provider
6025
+ * (或者一个本地模型),那句判断永远不成立,于是我们对输出内容**一条约束都没有**。
6026
+ *
6027
+ * 这里做的是我们自己的那一道:本地词表 + 正则,离线、零成本、可审计。
6028
+ *
6029
+ * ## 它明确做不到什么(写出来而不是留着)
6030
+ *
6031
+ * 1. **判不了语义。** 换一种说法就绕过去了。这是词表方案的天花板,不是 bug ——
6032
+ * 要判语义得叫模型,那是每轮多一次请求 + 联网,不是这一层的定位。
6033
+ * 2. **管不到工具入参。** 模型把违规内容写进 `file_write` 的 `content` 里就绕过了
6034
+ * 文本通道。这一格是知情的取舍(拦一次 `file_write` 的误伤代价太大),
6035
+ * 开关留在 `scope.toolArgs`,默认关。
6036
+ * 3. **管不到工具 / 联网读回来的内容。** 本轮口径就是只拦模型输出和用户输入。
6037
+ */
6038
+
6039
+ /**
6040
+ * 一条规则。
6041
+ *
6042
+ * `kind` 决定它跑在哪份文本上,这个分叉是**有判据的**,别合并:
6043
+ *
6044
+ * - `term` 跑在**归一化后**的文本上 —— 变体绕过(全角 / 零宽 / 分隔符 / leet)
6045
+ * 全靠那一步,跑原文等于没做;
6046
+ * - `regex` 跑在**原文**上 —— 归一化里的 leet 映射会把数字改成字母
6047
+ * (`3 → e`),身份证 / 手机号那类数字正则在归一化文本上一条都匹配不到。
6048
+ */
6049
+ interface ComplianceRule {
6050
+ /** 诊断和遥测里指认这一条用的名字,形如 `builtin:sexual:3` / `sexual.txt:12` */
6051
+ id: string;
6052
+ category: ComplianceCategory;
6053
+ kind: 'term' | 'regex';
6054
+ /** `term` 是归一化后的词条;`regex` 是正则源码 */
6055
+ pattern: string;
6056
+ source: ComplianceRuleSource;
6057
+ }
6058
+ /** 规则从哪儿来。用户级和项目级分开是因为诊断要按来源报条数 */
6059
+ type ComplianceRuleSource = 'builtin' | 'user' | 'project';
6060
+ /** 一次命中。`start` / `end` 是**原文**的 UTF-16 下标,`mask` 要按它打回原文 */
6061
+ interface ComplianceHit {
6062
+ ruleId: string;
6063
+ category: ComplianceCategory;
6064
+ action: Exclude<ComplianceAction, 'off'>;
6065
+ start: number;
6066
+ end: number;
6067
+ }
6068
+ /**
6069
+ * 一段文本的判定结果。**没有任何命中时返回 `undefined`,不是一个 hits 为空的对象** ——
6070
+ * 「干净」和「命中了但都是 warn」是两回事,后者要进遥测。
6071
+ */
6072
+ interface ComplianceVerdict {
6073
+ /** 全部命中里最严厉的那个动作 */
6074
+ action: Exclude<ComplianceAction, 'off'>;
6075
+ /** 命中的类别,去重、按 {@link COMPLIANCE_CATEGORIES} 的顺序 */
6076
+ categories: ComplianceCategory[];
6077
+ hits: ComplianceHit[];
6078
+ }
6079
+ /**
6080
+ * 流式输出的闸门。一次模型请求配一个,**有状态**。
6081
+ *
6082
+ * 为什么不是一个纯函数 `filter(text)`:流式输出是一串增量,而
6083
+ * 「这个词被切成了两个 delta」和「这句话还没说完」都只有攒起来才判得了。
6084
+ * 一个纯函数版本的表现是:违规词跨 chunk 就漏,或者每个 chunk 重复判前面所有内容。
6085
+ *
6086
+ * 契约里最重要的一条:**`push()` 回什么,宿主就看见什么**。回空串意味着这一段
6087
+ * 还压在缓冲区里(或者已经被拦下),调用方不许自己拿原始 delta 兜底。
6088
+ */
6089
+ interface OutputGuard {
6090
+ /**
6091
+ * 吃一段增量,回**可以放出去**的那截。
6092
+ *
6093
+ * 已经判定 `block` 之后一律回空串 —— 拦下之后模型还在吐的那些不该再出现。
6094
+ */
6095
+ push(delta: string): string;
6096
+ /** 流结束:把还压着的那点吐出来(同样可能是空串) */
6097
+ flush(): string;
6098
+ /** 迄今为止的判定;一次都没命中时是 `undefined` */
6099
+ verdict(): ComplianceVerdict | undefined;
6100
+ /** 迄今为止**放出去**的全文 = 该进上下文历史的那一份 */
6101
+ released(): string;
6102
+ }
6103
+ /** 生效配置。真源是 `config.compliance`,这里只是 core 内部的形状 */
6104
+ interface ComplianceSettings {
6105
+ enabled: boolean;
6106
+ scope: {
6107
+ /**
6108
+ * 模型输出(含 reasoning)。**缺省 `false`** —— 判据在 settings.ts 上:
6109
+ * 它是误伤和流式延迟的大头,而本轮要管的是输入侧。关掉时 `turn.ts` 里
6110
+ * 那个 `guard` 整个缺席,模型的每个 delta 原样直通。
6111
+ */
6112
+ output: boolean;
6113
+ /** 用户输入。**缺省 `true`,这一侧是这一层的主战场** */
6114
+ input: boolean;
6115
+ /** 模型生成的工具入参。默认关,见本文件开头第 2 条 */
6116
+ toolArgs: boolean;
6117
+ };
6118
+ /**
6119
+ * 跳过代码。**默认开,而且这一格是这层能不能用的关键**:
6120
+ * 这是个写代码的 agent,输出里一半是代码,不跳的话第一天就会有人
6121
+ * 因为一个叫 `sex` 的字段被断线。
6122
+ */
6123
+ skipCodeBlocks: boolean;
6124
+ /** 缓冲区超过这么多字符就强制判一次,别为了等一个句号把整段憋住 */
6125
+ maxHoldChars: number;
6126
+ actions: Record<ComplianceCategory, ComplianceAction>;
6127
+ }
6128
+
6129
+ /**
6130
+ * 合规引擎 —— 对外唯一的门面。
6131
+ *
6132
+ * 装配层建一个,`AgentLoop` 拿着它。两个出口:
6133
+ *
6134
+ * - {@link ComplianceEngine.outputGuard} 给模型输出用(流式,有状态,一轮一个)
6135
+ * - {@link ComplianceEngine.checkInput} 给用户输入用(一次性)
6136
+ *
6137
+ * ## 「这一档没开」一律回 `undefined`,不回一个空壳
6138
+ *
6139
+ * 关掉合规、或者只关输入那一侧时,出口回 `undefined`,调用方走的是**改动前
6140
+ * 那条路**(`turn.ts` 里 `guard` 缺席的分支)。回一个「什么都不拦的 guard」
6141
+ * 看着更整齐,代价是热路径上每个 delta 都要多走一层字符串拼接 ——
6142
+ * 而不开这个功能的用户不该为它付任何代价(同 `NOOP_TELEMETRY` 那条判据)。
6143
+ */
6144
+
6145
+ interface ComplianceEngineInput {
6146
+ /** 生效配置。不给用默认(默认是**开**的,判据在 settings.ts) */
6147
+ settings?: ComplianceSettings;
6148
+ /**
6149
+ * 用户 / 项目词库加载出来的规则。**追加**在内置种子表之后,不替换 ——
6150
+ * 挂一份自己的词库不该让内置那一份失效(那是「以为收紧了,其实放开了」)。
6151
+ */
6152
+ rules?: readonly ComplianceRule[];
6153
+ /** 用户额外的豁免词,追加在内置豁免表之后 */
6154
+ exempt?: readonly string[];
6155
+ }
6156
+ declare class ComplianceEngine {
6157
+ readonly settings: ComplianceSettings;
6158
+ private readonly matcher;
6159
+ private readonly host;
6160
+ /** 按来源分的条数,给启动诊断报「内置 M + 用户 K」 */
6161
+ readonly counts: Readonly<Record<ComplianceRuleSource, number>>;
6162
+ constructor(input?: ComplianceEngineInput);
6163
+ /** 真正编译进 matcher 的条数(`off` 的类别不算),给诊断 */
6164
+ get activeRuleCount(): number;
6165
+ /**
6166
+ * 模型输出的闸门。**一次模型请求一个** —— 它有状态(缓冲区、围栏块状态、
6167
+ * 命中累积),复用一个会把上一轮的判定带到下一轮。
6168
+ */
6169
+ outputGuard(): OutputGuard | undefined;
6170
+ /**
6171
+ * 用户输入的闸门。
6172
+ *
6173
+ * 干净时回 `undefined` —— 调用方据此完全不碰原文(连一次赋值都不做),
6174
+ * 「没命中」和「命中了但都是 warn」由此分得开。
6175
+ */
6176
+ checkInput(text: string): ComplianceGate | undefined;
6177
+ /**
6178
+ * 判一段完整文本,**不看 `scope`**。
6179
+ *
6180
+ * 只有一个调用方:`epoch compliance check`(自检口)。它必须绕开 `scope` ——
6181
+ * 缺省配置里 `scope.output` 是关的,而自检要回答的是「这段话在这份词表下
6182
+ * 算什么」,不是「它此刻走的那条通道开没开」。通道状态由 `status` 单独印。
6183
+ *
6184
+ * 走的是**同一个 guard**:输入侧、输出侧、自检口三处两套判据的分叉,
6185
+ * 正是这类功能最难查的那种问题(自检说会拦、真跑不拦)。
6186
+ */
6187
+ inspect(text: string): ComplianceGate | undefined;
6188
+ }
6189
+ /** 一次判定的结果。`text` 是打码后的那份(`block` 时它是半截,调用方不该用) */
6190
+ interface ComplianceGate {
6191
+ text: string;
6192
+ verdict: ComplianceVerdict;
6193
+ }
6194
+
5864
6195
  /**
5865
6196
  * artifact 目录的清理策略。
5866
6197
  *
@@ -6977,6 +7308,27 @@ interface ProviderGenerateOutput {
6977
7308
  * (即改造前的行为)。
6978
7309
  */
6979
7310
  model?: string;
7311
+ /**
7312
+ * provider 对这一次请求的抱怨(2026-09-01)。
7313
+ *
7314
+ * ## 这一格原来**不在这个接口上**,而那正是 bug 的一环
7315
+ *
7316
+ * `provider/types.ts` 的 `GenerateOutput.warnings` 一直有,router 也一直在填。
7317
+ * 但循环只认这个**倒置**接口,而它没有这一格 —— 于是那条 warning 在**类型层**
7318
+ * 就到不了循环:runtime / server / web 一路上没人读,不是因为谁忘了接,
7319
+ * 是因为它压根没穿过这道墙。
7320
+ *
7321
+ * 后果实测过:`@ai-sdk/deepseek@3.0.20` 静默丢弃用户发的图片,SDK 报了
7322
+ * warning、router 收成了 `ProviderWarning`,然后就断在这里。用户看到的是
7323
+ * 模型对着一张不存在的图说「我只看到一个占位符」,屏幕上一个字的提示都没有。
7324
+ *
7325
+ * 循环今天只用它判一件事(`droppedUserContentParts`:图片有没有被丢),
7326
+ * 但**接出来的是整份**而不是一个布尔 —— 判据同上面 `usage` 那一段:
7327
+ * 只接自己此刻要的那一格,等于给下一个消费者准备一次同样的穿墙工程。
7328
+ *
7329
+ * 缺席规则同 `usage`:一条都没有时整个缺席,不是空数组。
7330
+ */
7331
+ warnings?: ProviderWarning[];
6980
7332
  }
6981
7333
  /** AgentLoop 需要的 provider 能力 */
6982
7334
  interface AgentProvider {
@@ -6995,6 +7347,44 @@ interface AgentProvider {
6995
7347
  capabilities?: {
6996
7348
  supportsImages: boolean;
6997
7349
  };
7350
+ /**
7351
+ * **此刻这一轮会用哪个模型**(2026-09-02)。
7352
+ *
7353
+ * ## 为什么加它:上面那句「AgentLoop 不知道 model id」原来是**设计**,
7354
+ * ## 这一轮它变成了 bug
7355
+ *
7356
+ * 用户报的现场:问「你能识图吗」,跑在 `deepseek-v4-flash-vision-exp`
7357
+ * (一个认图的模型)上的 agent 答「我没有视觉识别能力,接收不到像素」,
7358
+ * 并且推荐用户去跑 tesseract OCR。接着问「你是什么模型」,它答不出来。
7359
+ *
7360
+ * 两句都不是模型在撒谎 —— **是提示词和运行时的契约断了**:
7361
+ *
7362
+ * - `## 规则` 里写着「用户直接问底层是什么模型:照实说(界面上本来就印着
7363
+ * 模型名)」。那条规则的判据是**用户屏幕上有**,可它约束的是模型的嘴,
7364
+ * 而模型的上下文里一个字都没有。于是它只有两种落法,两种都坏:编一个
7365
+ * 型号(更坏),或者像那次一样让用户「去看你自己的屏幕」;
7366
+ * - `supportsImages` 这个事实运行时**一直知道**(就在上面那一格,
7367
+ * 2026-09-01 那轮刚把三处启动快照改成现读),但它从来没进过 system prompt。
7368
+ * 模型只能猜自己的模态,而它猜错的方向是保守 —— **在这一格,保守等于把
7369
+ * 一个出厂就有的功能关掉**。
7370
+ *
7371
+ * ## 和 `capabilities` 并排,不塞进它里面
7372
+ *
7373
+ * `capabilities` 答的是「这个模型能干什么」,这一格答的是「它是谁」——
7374
+ * 两个问题。塞进去的话,下一个人给 `capabilities` 加第二种能力时,
7375
+ * 会拿到一个既装能力又装身份的袋子。
7376
+ *
7377
+ * ## ⚠️ 它必须是**取值器**,别填成一个字符串常量
7378
+ *
7379
+ * 装配层(`runtime/services.ts` 的 `providerBridge`)用 `get modelId()`
7380
+ * 现问 router 的 `getSelection().model`。填成常量的后果和
7381
+ * `capabilities` 那次一模一样:`/model` 换过之后 prompt 里写着旧型号,
7382
+ * 而这一次撒谎的是「你是谁」这句话本身。
7383
+ *
7384
+ * **不给 = `## 环境` 里那两行整个不出现**,也就是这一轮之前逐字节相同 ——
7385
+ * 脚本化的假 provider(用例里那些)没有「模型」这个概念,不该逼它们编一个。
7386
+ */
7387
+ readonly modelId?: string;
6998
7388
  }
6999
7389
  /** 学习上下文 */
7000
7390
  interface LearningContext$1 {
@@ -7395,6 +7785,21 @@ interface AgentConfig {
7395
7785
  * core 不 import plugin-terminal(分层不允许),所以这条线由装配层接。
7396
7786
  */
7397
7787
  backgroundTasks?: BackgroundTaskSource;
7788
+ /**
7789
+ * 内容合规闸门(core 的 `compliance/`)。给了就在两处生效:
7790
+ * 模型输出(`agent/turn.ts` 那个唯一出口)和用户输入(发请求之前)。
7791
+ *
7792
+ * **不给 = 完全没有这一层**,行为与改动前逐字节相同 —— 嵌入宿主和全部
7793
+ * 既有用例走的都是那一条。开关(哪一侧生效、每个类别哪一档)在引擎里,
7794
+ * 不在这儿:循环只问它「有没有闸门」和「判定是什么」,不参与判定。
7795
+ *
7796
+ * ⚠️ **装配层的每一处 `new AgentLoop` 都要填**,子 agent 那条也要:
7797
+ * 子 agent 的输出和主会话的输出一样会到用户眼前(`delegate_task` 的结果
7798
+ * 原样进上下文、也进界面),漏填一处的表现是「主会话拦住了、派出去的子任务
7799
+ * 原样吐出来」,而那正是最难发现的一种漏:屏幕上两边看着都在工作。
7800
+ * 会红的门禁:`runtime/__tests__/compliance-wiring.test.ts`。
7801
+ */
7802
+ compliance?: ComplianceEngine;
7398
7803
  }
7399
7804
  /** 历史里的一条。`parts` 存在时 `content` 是它的文本投影(见 EpochMessage) */
7400
7805
  interface HistoryEntry {
@@ -7488,7 +7893,6 @@ declare class AgentLoop {
7488
7893
  private readonly hooks;
7489
7894
  private readonly prompt;
7490
7895
  private readonly toolExecutor;
7491
- private readonly multimodal;
7492
7896
  /**
7493
7897
  * 工具表的来源。**构造时归一化,内部只认这一个真源**:
7494
7898
  * 给了 `toolProvider` 就用它,只给数组就折成一个永不变的 provider,
@@ -7515,6 +7919,49 @@ declare class AgentLoop {
7515
7919
  private learnedSkills;
7516
7920
  constructor(config: AgentConfig);
7517
7921
  abort(): void;
7922
+ /**
7923
+ * 多模态策略的**现读出口**:尺寸上限来自 config,`supportsImages` 来自
7924
+ * provider 自己(见 {@link AgentProvider.capabilities})。
7925
+ * **不给就是 false** —— 降级是安全的那一侧。
7926
+ *
7927
+ * **每次现问一遍,不是构造时算一次**(2026-09-01 还的账)。判据同
7928
+ * `workDir` / `toolProvider` 那两个取值器:一段会话里模型会中途换
7929
+ * (`/model`、命令 frontmatter 的 `model:`、失败降级到别家),而快照答不出
7930
+ * 那一次。原来这一格是构造时的布尔快照,两个方向都错得很具体:
7931
+ *
7932
+ * - 换到认图的模型之后,发图仍然被闸门 1 判死(「已取消本次请求」);
7933
+ * - 换到不认图的模型之后,带图历史照旧发出去 —— provider 报 400,
7934
+ * **而且已经计费**。第二个方向才是贵的那一头。
7935
+ *
7936
+ * 每轮多一次对象构造 + 一次 `getCapability` 查找(静态表 / 进程内记忆化的
7937
+ * 磁盘缓存)。相对一次模型调用,这个量级不值得为它留一个会说谎的快照。
7938
+ */
7939
+ private multimodal;
7940
+ /**
7941
+ * 「这一轮会用哪个模型、它认不认图」——**给 system prompt 用的那一份**
7942
+ * (2026-09-02)。判据全文在 `AgentProvider.modelId` 上。
7943
+ *
7944
+ * 挨着 {@link AgentLoop.multimodal} 放,因为它俩读的是同一个倒置接口的相邻
7945
+ * 两格、而且**现读的理由逐字相同**(模型会在一段会话里中途换)。
7946
+ *
7947
+ * ⚠️ **`modelId` 缺席时整个回 `undefined`,不回一个只有 `supportsImages`
7948
+ * 的半份**:`SystemPromptParams.model` 那一格明写着两格必须一起给 ——
7949
+ * 「说得出型号却不知道认不认图」正是这一轮要修的病的一半。
7950
+ */
7951
+ private modelInfo;
7952
+ /**
7953
+ * 把一次合规命中记进遥测。
7954
+ *
7955
+ * ⚠️ **一条命中一个计数点,属性里只有类别 / 档位 / 通道** ——
7956
+ * 命中的原文和命中的是哪条词条都不进去。判据在
7957
+ * [telemetry/sanitize.ts](../telemetry/sanitize.ts) 开头:把违规内容抄一遍
7958
+ * 送进遥测,是我们自己把它带出了这台机器。看板上要的是「哪一类在涨」,
7959
+ * 不是「涨的是哪句话」。
7960
+ *
7961
+ * `warn` 档**也记** —— 那一档存在的全部意义就是「先看数据再决定要不要拦」,
7962
+ * 不记的话它和 `off` 没区别。
7963
+ */
7964
+ private reportCompliance;
7518
7965
  /**
7519
7966
  * 这一轮该按什么价记账(方案 19)。
7520
7967
  *
@@ -7701,6 +8148,9 @@ declare function refreshOpenRouterMetadata(homeDir: string): Promise<void>;
7701
8148
  /**
7702
8149
  * 获取模型的 Capability。
7703
8150
  * 优先级:静态配置 > 磁盘缓存 > 默认值 [Hermes]
8151
+ *
8152
+ * **「优先」是逐格的,不是整条记录的**(2026-09-01 改):静态表里没写单价的
8153
+ * 条目,单价回落到磁盘缓存那一份。见下面静态分支里的判据。
7704
8154
  */
7705
8155
  declare function getCapability(modelId: string, homeDir: string): ModelCapability;
7706
8156
  /**
@@ -9196,6 +9646,30 @@ declare const EpochConfigSchema: z.ZodObject<{
9196
9646
  warn: "warn";
9197
9647
  }>>;
9198
9648
  }, z.core.$strip>>;
9649
+ compliance: z.ZodOptional<z.ZodObject<{
9650
+ enabled: z.ZodOptional<z.ZodBoolean>;
9651
+ scope: z.ZodOptional<z.ZodObject<{
9652
+ output: z.ZodOptional<z.ZodBoolean>;
9653
+ input: z.ZodOptional<z.ZodBoolean>;
9654
+ toolArgs: z.ZodOptional<z.ZodBoolean>;
9655
+ }, z.core.$strip>>;
9656
+ skipCodeBlocks: z.ZodOptional<z.ZodBoolean>;
9657
+ maxHoldChars: z.ZodOptional<z.ZodInt>;
9658
+ actions: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
9659
+ sexual: "sexual";
9660
+ political: "political";
9661
+ hate: "hate";
9662
+ violence: "violence";
9663
+ illegal: "illegal";
9664
+ self_harm: "self_harm";
9665
+ privacy: "privacy";
9666
+ }> & z.core.$partial, z.ZodEnum<{
9667
+ block: "block";
9668
+ mask: "mask";
9669
+ warn: "warn";
9670
+ off: "off";
9671
+ }>>>;
9672
+ }, z.core.$strip>>;
9199
9673
  headless: z.ZodOptional<z.ZodObject<{
9200
9674
  allowTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
9201
9675
  allowOperations: z.ZodOptional<z.ZodArray<z.ZodEnum<{
@@ -9239,6 +9713,11 @@ declare const EpochConfigSchema: z.ZodObject<{
9239
9713
  }>>;
9240
9714
  }, z.core.$strip>>;
9241
9715
  brand: z.ZodOptional<z.ZodString>;
9716
+ sidebarMenu: z.ZodOptional<z.ZodArray<z.ZodObject<{
9717
+ id: z.ZodString;
9718
+ label: z.ZodString;
9719
+ icon: z.ZodOptional<z.ZodString>;
9720
+ }, z.core.$strip>>>;
9242
9721
  }, z.core.$strip>;
9243
9722
  /**
9244
9723
  * 全默认配置 —— 从 schema 派生,不是第二份字面量。
@@ -9321,30 +9800,61 @@ interface ConfigMigration {
9321
9800
  *
9322
9801
  * 见 {@link SettingApply}。
9323
9802
  *
9324
- * ## 二、能写的键只有 `SettingsFileSchema` 里那两个标量
9803
+ * ## 二、**两张名单,不是一张** —— 2026-08-31 拆开的
9804
+ *
9805
+ * 这一节上一版写着「能写的键只有 `SettingsFileSchema` 里那两个标量」,于是
9806
+ * `contextLength` / `budget.*` / `fallback.*` / `compression.*` 在设置页上
9807
+ * **一个写控件都没有**。那句话把两个不同的问题合成了一个答案,而它们的答案
9808
+ * 本来就不一样:
9809
+ *
9810
+ * | 问的是 | 名单 | 判据在哪 |
9811
+ * | ---------------------------------------- | ----------------------------- | -------- |
9812
+ * | **别人的仓库**能不能定这个键(③④⑤∞) | `SettingsFileSchema` | [sources.ts](./sources.ts) 文件头 |
9813
+ * | **这张界面**能不能替你改你自己的用户级配置 | {@link SETTING_WRITE_KEYS} | 这儿 |
9814
+ *
9815
+ * 第一张名单守的是「一个仓库不该能悄悄改坏你的会话」,逐条判据(`permission`
9816
+ * 级别、`shell`、`hooks` / `provider`、以及 2026-08-16 真走了一遍的
9817
+ * `compression`)**一条都没变、一个键都没加**。第二张名单答的是另一件事 ——
9818
+ * 写的是 `~/.epoch/config.yaml`,你自己的文件,「仓库作者拿它能干什么」在那儿
9819
+ * 根本不成立。上一版拿第一张名单的理由挡了第二件事,那一步是错的。
9820
+ *
9821
+ * ⚠️ **2026-08-31 晚:`permission` 进了第二张名单,而第一张名单一个字没动。**
9822
+ * 这一对正是上面那张表想说的事,所以值得当例子记在这儿:一个仓库写
9823
+ * `permission: bypass` 是隐式提权(`sources.ts` 文件头那条判据**照旧成立**,
9824
+ * 别顺手把它加进 {@link SettingsFileSchema});而你自己改自己那台机器的默认档,
9825
+ * 和它是两件事。触发它的是底栏那张菜单 —— 换一次档就记住一次
9826
+ * (runtime 的 `SessionPermissions.setLevel`,那儿有「谁改的算数」那张表)。
9827
+ *
9828
+ * 全仓唯一一条**同时**在「第一张名单明确拒绝」和「第二张名单收下」两边的键。
9829
+ * 下一个人拿它当先例之前先读清楚:拒的是**别人**替你定,收的是**你**替自己定。
9830
+ *
9831
+ * 拆开之后**可写层跟着键分叉**({@link settingWriteLayers}):
9832
+ *
9833
+ * - 两张名单都在的(`model` / `maxTurns`)→ ② 用户级 + ④ 项目本地
9834
+ * - 只在第二张名单里的 → **只有 ② 用户级**。往 ④ 写一个 ③④ 压根不认的键,
9835
+ * 得到的是 `.epoch/settings.local.json` 里一条启动诊断报「未知配置项」的死键
9325
9836
  *
9326
- * `model` / `maxTurns`({@link SCALAR_KEYS})。`permissions` 也在
9327
- * `SettingsFileSchema` 里,但它**不走这条路**:三张列表走并集不走覆盖,
9328
- * 「加一条规则」和「把一个值改成另一个值」是两种动作、两种界面、两种确认,
9837
+ * `permissions` 在第一张名单里、**两张都不该给它写控件**:三张列表走并集不走
9838
+ * 覆盖,「加一条规则」和「把一个值改成另一个值」是两种动作、两种界面、两种确认,
9329
9839
  * 而它的来源标注早就在安全中心那一屏上了(`PermissionsControl.rules()`)。
9840
+ * `fallback.providers` 同理 —— 它是一条**有序的链**,不是一个标量。
9330
9841
  *
9331
- * 别的键(`contextLength` / `budget.*` / `fallback.*` / `compression.*`)
9332
- * **一层都写不进**:③④⑤∞ 碰不到它们(判据在 [sources.ts](./sources.ts) 文件头,
9333
- * 逐条说了为什么排除 `permission` 级别、`shell`、`hooks` / `provider`、
9334
- * 以及 2026-08-16 那次真按判据走了一遍的 `compression`),而只写 ② 用户级的话
9335
- * 这一层就要能改 `~/.epoch/config.yaml` 里的**任意**键 —— 那是另一件事,
9336
- * 它得先回答「provider 那一段里的 key 怎么办」。
9337
- *
9338
- * ⚠️ **还有一道更硬的墙,别只记住上面那条判据**:{@link writeUserYaml}
9339
- * `spliceTopLevel()` 只认**不带缩进**的顶层 `key:`。也就是说哪怕哪天真把一个
9340
- * 嵌套键(`compression.enabled` / `budget.maxCostUsd` 这种)放进了白名单,
9341
- * 写请求也只会得到 `unwritable-file` —— 而且是在**回读那一步**才失败的,
9342
- * 前面的手术已经把一行 `compression.enabled: false` 追加到了文件末尾。
9343
- * 那一行在 yaml 里是个**顶层键,名字里带一个点**,不是 `compression` 段下的
9344
- * `enabled`:解析出来根本不是用户要的那个东西,所以回读必然否掉它、整个不写。
9345
- * 结果是对的(不写),过程是巧合 —— 真要收嵌套键,`spliceTopLevel` 得先会
9346
- * 「找到 `compression:` 那一段、在段内按缩进改一行、段不存在就整段追加」,
9347
- * 而那是一次真正的 yaml 手术,不是给正则多加一个字符。
9842
+ * 那个「只写 用户级就要能改任意键、得先回答 provider 段里的 key 怎么办」的
9843
+ * 顾虑,答案就是**这张名单本身**:可写的键是列举出来的,`provider` 那一段
9844
+ * 一个字段都不在里面。凭据要的是脱敏 + 「换一个」,那是另一件事、另一个界面。
9845
+ *
9846
+ * ⚠️ **嵌套键的 yaml 手术**:上一版这里写着「`spliceTopLevel()` 只认不带缩进的
9847
+ * 顶层 `key:`,所以嵌套键哪怕进了名单也只会得到 `unwritable-file`」。那道墙
9848
+ * 2026-08-31 拆了 —— 但**不是**给正则多加一个字符:段内改一行走的是 infra 的
9849
+ * `setSectionField()`,也就是 `epoch config set` / `epoch model` 写同一个文件时
9850
+ * 用的那一份(判据逐字同它自己的文件头:同一个文件的读写策略只能有一份)。
9851
+ * 回读那一步跟着长出了嵌套版({@link onlyChangedNested}),验的东西一样多:
9852
+ * 目标字段落到了想要的值、**别的顶层键**一个不多一个不少、**同段里别的字段**
9853
+ * 也一个都没动。少验最后一件,一次 `budget.maxTokens` 就可能把隔壁的
9854
+ * `maxCostUsd` 顺手漂掉。
9855
+ *
9856
+ * 名单里**最多只吃一层点**(`budget.maxCostUsd` ✅,`a.b.c` ❌):两层的手术是
9857
+ * 另一个形状,而今天没有一个键需要它。写进去的话,那是一个没有用户的分支。
9348
9858
  *
9349
9859
  * ## 三、这一轮**没有删键**
9350
9860
  *
@@ -9404,8 +9914,58 @@ interface ConfigMigration {
9404
9914
  declare const SETTING_WRITE_LAYERS: readonly ["user", "projectLocal"];
9405
9915
  type SettingWriteLayer = (typeof SETTING_WRITE_LAYERS)[number];
9406
9916
  declare function isSettingWriteLayer(value: string): value is SettingWriteLayer;
9407
- /** 这个键写得进去吗。名单就是 {@link SCALAR_KEYS} 本身,别在别处抄一份字面量 */
9408
- declare function isWritableSettingKey(value: string): value is ScalarKey;
9917
+ /**
9918
+ * **这张界面能替用户写的键**,和「③④⑤∞ 能覆盖哪些键」是两张名单(文件头第二节)。
9919
+ *
9920
+ * 数组顺序无所谓 —— 界面上那些行的顺序由 runtime 的 `SETTING_ROWS` 定。
9921
+ * 这张表回答的只有一件事:这个键,这条路写不写得进去。
9922
+ *
9923
+ * ## 收进来的判据:**它是不是一个标量旋钮**
9924
+ *
9925
+ * 「改一个值」这条路上能画出来的只有一个输入框加一次保存。于是收的是标量、
9926
+ * 拒的是别的形状 —— 两个被拒的都不是遗漏:
9927
+ *
9928
+ * - **`permissions`** 是三张列表、走并集不走覆盖,入口在安全中心(文件头第二节)
9929
+ * - **`fallback.providers`** 是一条**有序的链**。「往链尾加一家」和「把整条链换成
9930
+ * 另一条」是两种动作,而一个输入框只画得出后者 —— 用户敲错一个字就把降级
9931
+ * 整条清空了,而这个键存在的理由正是「主 provider 挂了还有下家」。
9932
+ * 它照旧在设置页上**读**得到(`fallback.providers` 那一行印着整条链),
9933
+ * 只是没有铅笔
9934
+ *
9935
+ * `provider` 那一段(含 `apiKey`)**一个字段都不在这儿**,这就是文件头第二节
9936
+ * 那个「provider 段里的 key 怎么办」的答案:可写的键是列举出来的。
9937
+ *
9938
+ * ⚠️ 加键要**同时**回答两件事,缺一件别加:这个键写进用户级 yaml 之后,
9939
+ * 用户在界面上看到的会不会是真的;以及它的值域从哪儿摘({@link VALUE_SCHEMA},
9940
+ * 那张表漏一格当场编译不过)。
9941
+ *
9942
+ * ⚠️ 第一件事上一版写的是「`SETTING_ROWS` 里有这一行吗」,那是把**要求**和
9943
+ * **它当时唯一的满足方式**写成了一句话。2026-08-31 晚 `permission` 进来时分开了:
9944
+ * 要求是「用户在界面上看得见这个值、而且看到的是真的」,`SETTING_ROWS`(设置页
9945
+ * 那张表)只是其中一条路。`permission` 走的是另一条 —— 安全中心那一屏的
9946
+ * **「默认」那一行**(`WirePermissionStatus.configured` / `configuredLayer`),
9947
+ * 那一行 2026-08-17 就在了。它**刻意不进 `SETTING_ROWS`**:同一个词在设置页和
9948
+ * 安全中心指两件事(「新会话从哪一档起」vs「这个会话此刻哪一档」),
9949
+ * 而那正是决定 20 ④ 拆开的那个歧义 —— 记住上一次那一档没有把这个歧义请回来。
9950
+ */
9951
+ declare const SETTING_WRITE_KEYS: readonly ["model", "maxTurns", "models.utility", "fallback.model", "contextLength", "compression.enabled", "compression.threshold", "budget.maxCostUsd", "budget.maxTokens", "budget.warnAtPercent", "budget.onUnknownPricing", "permission"];
9952
+ type SettingWriteKey = (typeof SETTING_WRITE_KEYS)[number];
9953
+ /** 这个键写得进去吗。名单就是 {@link SETTING_WRITE_KEYS} 本身,别在别处抄一份字面量 */
9954
+ declare function isWritableSettingKey(value: string): value is SettingWriteKey;
9955
+ /**
9956
+ * 这个键写得进哪几层,**低 → 高**;写不进去回空数组。
9957
+ *
9958
+ * 分叉的判据是**第一张名单**(`SettingsFileSchema` 的标量键,也就是
9959
+ * {@link SCALAR_KEYS}):只有那几个键 ③④ 才认得,于是也只有它们往
9960
+ * ④ 项目本地写才有意义。别的键往 ④ 写,落地是一条 `.epoch/settings.local.json`
9961
+ * 里的死键 —— 启动诊断报「未知配置项」,而界面刚说过「已写进 ④」。
9962
+ *
9963
+ * ⚠️ 这里**不收 `overridable` 参数**,尽管调用方手上正好有一个同义的布尔。
9964
+ * 收了就是同一个问题的两个答案,而它们分叉的那天,界面画出的档位和
9965
+ * {@link writeSettingValue} 真的接受的层会对不上 —— 那是一次「按了保存、
9966
+ * 回一个 400」。这条路上只有一个真源:键本身。
9967
+ */
9968
+ declare function settingWriteLayers(key: string): readonly SettingWriteLayer[];
9409
9969
  /**
9410
9970
  * 写完要做什么它才生效。
9411
9971
  *
@@ -9478,10 +10038,13 @@ interface SettingWriteTarget {
9478
10038
  apply: SettingApply;
9479
10039
  }
9480
10040
  interface SettingWriteTargetsOptions {
10041
+ /**
10042
+ * 这一行的键。**可写层由它一个人决定**({@link settingWriteLayers})——
10043
+ * 上一版这里收的是一个 `overridable: boolean`,判据见那个函数的 ⚠️。
10044
+ */
10045
+ key: string;
9481
10046
  /** 这一行现在赢在哪一层(`SettingChain.layer`) */
9482
10047
  winner: SettingLayer;
9483
- /** 这个键在不在白名单里(`SettingsFileSchema` 说了算,等价于 `EffectiveSetting.overridable`) */
9484
- overridable: boolean;
9485
10048
  /** 每一个可写层要写的那个文件,见 {@link SettingWriteTarget.path} */
9486
10049
  paths: Readonly<Record<SettingWriteLayer, string>>;
9487
10050
  /**
@@ -9500,7 +10063,9 @@ interface SettingWriteTargetsOptions {
9500
10063
  * 三种「一层都写不了」的情况回空数组,界面据此不画写控件(决定 20 ①:画一个点了
9501
10064
  * 没反应的控件比不画更糟):
9502
10065
  *
9503
- * 1. 这个键不在白名单里(`overridable` 为假)—— ③④⑤∞ 碰不到它,见文件头第二节
10066
+ * 1. 这个键不在 {@link SETTING_WRITE_KEYS} 里 —— 见文件头第二节。注意这里说的
10067
+ * **不再是**「不在 `SettingsFileSchema` 白名单里」:那张名单管的是项目级能不能
10068
+ * 覆盖,两者 2026-08-31 拆开了
9504
10069
  * 2. 赢的那一层是 `managed` —— 企业托管压过一切,写什么都不生效,而那一行上
9505
10070
  * 已经有一句专门的话了(`managed_locked`)
9506
10071
  * 3. 赢的那一层排不出序号(`unknown`)—— 说不出会不会被压回去,见 {@link layerRank}
@@ -9541,6 +10106,38 @@ interface SettingWriteRequest {
9541
10106
  /** 还没校验的值。校验在这一层做,见 {@link VALUE_SCHEMA} */
9542
10107
  value: unknown;
9543
10108
  }
10109
+ /**
10110
+ * 界面该给这个键画哪种输入控件 —— **从 {@link VALUE_SCHEMA} 上认,不另立一张表**。
10111
+ *
10112
+ * ## 为什么这件事必须由引擎说,而不是界面自己看值
10113
+ *
10114
+ * 界面原来的判法是「看这一行现在的值是什么类型」(`config.tsx` 的
10115
+ * `valueKindOf()`),而那条判据有一个前提:**这一行一定有值**。
10116
+ * 两张名单拆开之前,可写的两个键都有 `.default()`,前提恒成立。
10117
+ * 现在不成立了 —— `budget.*` 四行**一个默认值都没有**(`.optional()`,
10118
+ * 缺省就是「没有上限」),于是那四行在屏幕上是「未设置」,链条上也是空的。
10119
+ * 界面按老判据会一律当字符串处理,把 `"10"` 发给一个 `z.number()`,
10120
+ * 换来一次 `bad-value` —— 也就是「有铅笔、点了保存、永远存不上」。
10121
+ *
10122
+ * 所以类型跟着行一起发下去(`WireSettingRow.valueKind`)。这**不违反**
10123
+ * `WireSettingValue` 上那条「别再发一个 `kind` 字段」:那条禁的是「值的类型
10124
+ * 已经能从值本身看出来时,再发一份」。前提死了,禁令跟着失效,而
10125
+ * 把死掉的前提留在原地才是真的坏。
10126
+ *
10127
+ * `enum` 归 `string`,另外由 {@link settingValueChoices} 把候选发下去 ——
10128
+ * 界面据此画分段器而不是输入框,而候选**照旧只有 schema 一个来源**。
10129
+ */
10130
+ type SettingValueKind = 'string' | 'number' | 'boolean';
10131
+ declare function settingValueKind(key: string): SettingValueKind | null;
10132
+ /**
10133
+ * 这个键只有这几个值可选(`budget.onUnknownPricing` 的 `block` / `warn`)——
10134
+ * 不是枚举就回 `null`。
10135
+ *
10136
+ * 候选**从 schema 上读**(`ZodEnum.options`)。在界面那边写死一份
10137
+ * `['block', 'warn']` 的话,schema 哪天多一档,界面会继续只画两个按钮,
10138
+ * 而那一档在文档里是存在的。
10139
+ */
10140
+ declare function settingValueChoices(key: string): readonly string[] | null;
9544
10141
  /**
9545
10142
  * 校验 + 落盘。**同步** —— 一次小文件的读-改-写,异步化只会让调用方多一处
9546
10143
  * 要 await 的地方,而这一层的每一个兄弟(`TrustManager.save()` /
@@ -13345,6 +13942,148 @@ interface PolicyDirsSummary {
13345
13942
  */
13346
13943
  declare function resolvePolicyDirs(opts: ResolvePolicyDirsOptions): PolicyDirsSummary;
13347
13944
 
13945
+ /**
13946
+ * 词库加载 —— 一行一条的纯文本。
13947
+ *
13948
+ * ## 为什么不是 TOML / YAML
13949
+ *
13950
+ * 合规词库在现实里就是**一行一个词的文本文件**(监管口径的词表、开源词库、
13951
+ * 甲方给的清单都是这个形状)。要求用户把上万行词包成 `[[rule]]` 才能用,
13952
+ * 等于要求他先写个转换脚本 —— 而那个脚本就是这层功能的实际门槛。
13953
+ *
13954
+ * ## 类别靠**文件名**,不靠文件里的字段
13955
+ *
13956
+ * ```
13957
+ * ~/.epoch/compliance/sexual.txt 色情类词条,一行一条
13958
+ * ~/.epoch/compliance/political.regex.txt 涉政类正则,一行一条
13959
+ * ~/.epoch/compliance/exempt.txt 豁免词(全类别通用)
13960
+ * ```
13961
+ *
13962
+ * 文件名 = 类别名 = 内置种子表的文件名(`lexicon/<类别>.ts`)。三者同名让
13963
+ * 「我该往哪个文件加词」只有一个答案。文件名不认识时**报出来而不是静默跳过**:
13964
+ * 一个拼成 `sexual.text` 的文件静默不加载,表现是「词加了但没生效」,
13965
+ * 而用户没有任何办法发现这件事。
13966
+ */
13967
+
13968
+ /** 加载结果。`exempt` 单开一格:它不是规则,是规则的反面 */
13969
+ interface LexiconLoadOutcome {
13970
+ rules: ComplianceRule[];
13971
+ exempt: string[];
13972
+ issues: ParseIssue[];
13973
+ }
13974
+ /**
13975
+ * 从目录加载词库。
13976
+ *
13977
+ * @param dir 词库目录
13978
+ * @param source 这批规则的来源,进 `ComplianceRule.source`(诊断按来源报条数)
13979
+ * @param diags 给了就把问题按「一个问题一行」追加进去
13980
+ */
13981
+ declare function loadLexiconFiles(dir: string, source: 'user' | 'project', diags?: DiagnosticSink): Omit<LexiconLoadOutcome, 'issues'>;
13982
+ /** 同 `loadLexiconFiles`,但把 issues 一起返回(调用方要自己呈现时用) */
13983
+ declare function loadLexiconDir(dir: string, source: 'user' | 'project'): LexiconLoadOutcome;
13984
+
13985
+ /**
13986
+ * 合规词库的来源解析 —— 两级目录 + 工作区信任闸门。
13987
+ *
13988
+ * ```
13989
+ * ~/.epoch/compliance/*.txt 用户级,无闸门(是用户自己的机器)
13990
+ * <项目根>/.epoch/compliance/*.txt 项目级,**过工作区信任闸门,且没有例外**
13991
+ * ```
13992
+ *
13993
+ * 形状和 [policy/sources.ts](../policy/sources.ts) 一致,闸门也在同一档。
13994
+ * 但这里的**理由和策略规则相反**,别照抄那段注释:
13995
+ *
13996
+ * - 策略规则未信任时整份不加载,丢掉的是「这个仓库想额外放行的那些」——
13997
+ * 丢掉是往安全的方向偏;
13998
+ * - 合规词库未信任时整份不加载,丢掉的是「这个仓库想额外**拦下**的那些」——
13999
+ * 丢掉是往宽松的方向偏。
14000
+ *
14001
+ * 那为什么还是不加载?因为一个没看过的仓库里的一份词表,能做的不只是「多拦几个词」:
14002
+ * 它可以把大量常用词写进 `exempt.txt`,**把内置那份拦不下来的东西一条条豁免掉**。
14003
+ * 也就是说项目级这一份**有能力放松**合规,于是它和 hook 同档 —— 未信任就不读。
14004
+ * 用户级那份不设闸门是因为那是用户自己写的。
14005
+ */
14006
+
14007
+ /** 一个参与扫描的词库目录 */
14008
+ interface ComplianceDirSpec {
14009
+ dir: string;
14010
+ source: 'user' | 'project';
14011
+ }
14012
+ interface ResolveComplianceDirsOptions {
14013
+ /** 用户级目录(`resolveComplianceDir(homeDir)`) */
14014
+ userDir: string;
14015
+ /** 项目根目录。不给就不加载项目级词库 */
14016
+ projectRoot?: string;
14017
+ /**
14018
+ * 工作区是否受信任。**必传**,没有默认值 ——
14019
+ * 给个 `= true` 的默认参数就等于「忘了传的人自动获得信任」。
14020
+ */
14021
+ trusted: boolean;
14022
+ /** 给了就把取舍写进启动诊断 */
14023
+ diags?: DiagnosticSink;
14024
+ }
14025
+ interface ComplianceDirsSummary {
14026
+ /** 该扫的目录,用户级在前 */
14027
+ dirs: ComplianceDirSpec[];
14028
+ /** 项目词库因为工作区不受信任而没加载(且那个目录确实存在) */
14029
+ projectSkipped: boolean;
14030
+ /** 被跳过的那个目录。`projectSkipped` 为假时缺席 —— 它是 `epoch trust add` 的参数 */
14031
+ skippedDir?: string;
14032
+ }
14033
+ /**
14034
+ * 算出这一次该扫哪些词库目录。
14035
+ *
14036
+ * 用户级那一份**永远在列**,哪怕目录还不存在 —— loader 自己会处理
14037
+ * 「目录不存在 = 没有词条」,而在这里判存在只会让「刚建好目录就该生效」
14038
+ * 变成一个取决于调用顺序的问题。
14039
+ */
14040
+ declare function resolveComplianceDirs(opts: ResolveComplianceDirsOptions): ComplianceDirsSummary;
14041
+
14042
+ /**
14043
+ * 生效配置的默认值。
14044
+ *
14045
+ * 真源是 `config.compliance`(zod schema 在 core/src/config/schema.ts),
14046
+ * 这里的常量是那份 schema 的默认值来源 —— 两处各写一遍默认值,
14047
+ * 迟早有一处是旧的。
14048
+ */
14049
+
14050
+ /** 缓冲区上限。超过它就强制判一次,别为了等一个句号把整段憋住 */
14051
+ declare const DEFAULT_MAX_HOLD_CHARS = 400;
14052
+ /**
14053
+ * 类别 → 默认动作。
14054
+ *
14055
+ * 每一格的理由写在对应的种子表文件头里(`lexicon/<类别>.ts`),
14056
+ * 那里是唯一该讲「为什么是这一档」的地方。这里只有结论。
14057
+ */
14058
+ declare const DEFAULT_COMPLIANCE_ACTIONS: Readonly<Record<ComplianceCategory, ComplianceAction>>;
14059
+ /**
14060
+ * 默认**开**,但**只拦输入侧**。
14061
+ *
14062
+ * ## `enabled: true` —— 这是产品要求,不是可选增强
14063
+ *
14064
+ * 默认关等于「装了但没生效」,而那种状态和没做这个功能在外部看起来一模一样。
14065
+ *
14066
+ * ## `scope.output: false` —— 2026-09-01 定的口径
14067
+ *
14068
+ * 要管的是**用户输入侧**:把违规内容送进模型的那一下。模型输出那一侧
14069
+ * **默认不管** —— 代码全在(`outputGuard()`、`turn.ts` 那个唯一出口、
14070
+ * 句子级 holdback 都留着),一行配置就能开,但缺省是关的。
14071
+ *
14072
+ * 两条理由,都是量出来的,不是偏好:
14073
+ *
14074
+ * 1. **输出侧是风险大头。** 它误伤的后果是 `block` 档**直接终止这一轮回答**,
14075
+ * 而模型输出里一半是代码和技术叙述 —— 语料实测抓到过「端**口交**给内核分配」
14076
+ * 「一**台独**立的状态机」这种命中(判据在 `lexicon/exempt.ts` 和
14077
+ * docs/verify/VERIFY_RECORD-compliance.md 的语料那一节)。输入侧的量小得多,
14078
+ * 而且是用户自己刚敲进去的那一句 —— 拦错了他当场看得见、改一下就能重发。
14079
+ * 2. **输出侧要收流式延迟。** 句子级 holdback 是「攒到句末才放」,
14080
+ * 每个用户每一轮都在付这个代价。关掉之后 `turn.ts` 里那个 `guard` 缺席,
14081
+ * 模型的每个 delta **原样直通**,逐字节等于没有这一层。
14082
+ *
14083
+ * 要开:`compliance.scope.output: true`。
14084
+ */
14085
+ declare const DEFAULT_COMPLIANCE_SETTINGS: ComplianceSettings;
14086
+
13348
14087
  /**
13349
14088
  * Command Hook 子进程执行器。
13350
14089
  *
@@ -13945,10 +14684,28 @@ declare class SkillSystem implements SkillSystem$1 {
13945
14684
  getNames(): string[];
13946
14685
  /** 获取技能目录路径 */
13947
14686
  getSkillsDir(): string;
14687
+ /**
14688
+ * 新建一个用户级技能。
14689
+ *
14690
+ * ## ⚠️ 落点必须**留在技能目录里面**,而这一道闸在这儿不在门面上
14691
+ *
14692
+ * `name` / `category` 原样变成两段路径,所以一个 `name: '../../..'` 会写到
14693
+ * 技能目录外面去。2026-09-02 之前这里一个字都不查 —— 那时唯一的调用方是
14694
+ * `SkillLearner`(名字是它自己生成的),所以看不出来;模型侧那四个写工具
14695
+ * (`skill_create` …)一接上,这一格就变成一条真的路。
14696
+ *
14697
+ * 门面那一层(`tools/builtin/skill-write.ts`)另有一条**字符集**检查,为的是
14698
+ * 给模型一句说得清的话。⚠️ **那一条不是这一条的替代**:判据是「断言要落在会
14699
+ * 说谎的那一层」—— 会说谎的是这个产地,而它今天已经有两个调用方了。
14700
+ *
14701
+ * 用「resolve 之后还在不在里面」而不是再抄一遍那条正则:两处各一份正则迟早
14702
+ * 只改一处,而路径包含判定对**所有**逃逸写法(`..`、绝对路径、分隔符、
14703
+ * Windows 的 `C:\`)都是对的。
14704
+ */
13948
14705
  create(name: string, content: string, category?: string): Promise<string>;
13949
14706
  edit(name: string, content: string): Promise<void>;
13950
14707
  patch(name: string, oldString: string, newString: string, filePath?: string): Promise<void>;
13951
- delete(name: string, _absorbedInto?: string): Promise<void>;
14708
+ delete(name: string, _absorbedInto?: string): Promise<string>;
13952
14709
  writeFile(name: string, filePath: string, content: string): Promise<void>;
13953
14710
  removeFile(name: string, filePath: string): Promise<void>;
13954
14711
  /**
@@ -14720,12 +15477,38 @@ type ArtifactOpenRefusal = 'not-in-artifacts-dir' | 'extension-not-allowed' | 'l
14720
15477
  */
14721
15478
  declare function artifactOpenRefusal(path: string, homeDir?: string): ArtifactOpenRefusal | undefined;
14722
15479
  /**
14723
- * 算出「用什么命令打开」,**不含副作用**,好让用例在三个平台上都能断言 argv
15480
+ * 三平台「交给系统默认应用」的 argv —— **这一份只管命令,一道闸都不含**。
15481
+ *
15482
+ * 抽出来是因为 2026-09-02 起有了第二个调用方(Web UI 那条「用默认应用打开」,
15483
+ * 在 `runtime/src/file-open.ts`)。**抽的是命令表,不是判断**:那一侧的闸
15484
+ * 完全不同(工作区边界 + Office/PDF 白名单 + 同机),而这张表上的三条结论
15485
+ * 是同一批实测得出的,两处各抄一份的话,Windows 那条改一次只会改到一边。
15486
+ *
15487
+ * ⚠️ **三平台一律不经 shell**(`shell: false` 是 `spawn` 的默认值,调用方别自己开):
15488
+ * Windows 上 `cmd /c start` 是命令注入口,`explorer.exe` 静默失败。
15489
+ * 判据全文见 docs/verify/VERIFY_RECORD-10-windows.md 第七章 (d)。
15490
+ *
15491
+ * ⚠️ **它本身不安全,也不打算安全**:`open` / `xdg-open` /
15492
+ * `rundll32 url.dll,FileProtocolHandler` 本质都是 ShellExecute —— 喂给它一个
15493
+ * `.vbs` 就是执行脚本。**安全性质全部在调用方那两道闸上**(见文件头)。
14724
15494
  *
14725
15495
  * `platform` 显式传入而不是直接读 `process.platform`:否则 Windows 分支只有
14726
15496
  * Windows 机器跑得到,而它恰恰是三条里最容易出事的那条
14727
15497
  * (同 `browserLaunchArgv()` 的理由)。
14728
15498
  *
15499
+ * @param abs **必须**是已经过闸的绝对路径。这一份不 `resolve`、不校验、不拒绝
15500
+ */
15501
+ declare function systemOpenArgv(abs: string, platform?: NodeJS.Platform): {
15502
+ command: string;
15503
+ args: string[];
15504
+ };
15505
+ /**
15506
+ * 算出「用什么命令打开这个 **artifact**」,**不含副作用**,好让用例在三个平台上
15507
+ * 都能断言 argv。
15508
+ *
15509
+ * 命令那一半在 {@link systemOpenArgv};这一份是它**外面那两道闸**
15510
+ * (必须在 artifacts 目录里 / 必须是图片)。
15511
+ *
14729
15512
  * @returns `null` 表示这个路径压根不该被打开
14730
15513
  */
14731
15514
  declare function artifactLaunchArgv(path: string, platform?: NodeJS.Platform, homeDir?: string): {
@@ -15403,4 +16186,4 @@ declare function resolveCodeModeWorker(baseDir: string, exists?: typeof existsSy
15403
16186
  */
15404
16187
  declare function codeModeWorkerPath(): string | undefined;
15405
16188
 
15406
- export { AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, type AcquireResult, type AgentConfig, AgentLoop, type AgentProvider, type AgentSite, type AgentSiteRef, type AppendMessageInput, ApprovalCache, type ApprovalDecision, type ApprovalScope, type ArtifactOpenRefusal, type ArtifactRetention, type AskQuestionDeps, BLOCKED_TOOLS, type BackendOptions, type BackendOutcome, type BackgroundTaskSource, type BaseOrigin, type BaseSlot, type BeginTurnInput, type BreakdownInput, BudgetGuard, type BudgetGuardOptions, type BudgetInfo, type BudgetLevel, type BudgetOptions, type BudgetStatus, BudgetStore, type BudgetStoreOptions, type BuildFireArgvInput, type BuildIndexOptions, CHECKPOINT_MAX_TOTAL_BYTES, CLAUDE_EVENT_NAMES, CLAUDE_TOOL_NAMES, CODE_MODE_LIMITS, CODE_MODE_SDK_TAG, CONFIG_KEYS, CURRENT_CONFIG_VERSION, type CachedApproval, type CachedDecision, type CheckpointCapture, type CheckpointFile, CheckpointManager, type CheckpointManagerOptions, type CheckpointManifest, CheckpointStore, type CheckpointStoreOptions, type CheckpointSummary, type ClaudeHooksParseOptions, type CodeModeLimits, type CodeRequest, type CodeResult, CodeSandbox, type CommandHookConfig, type CommandHookResult, type CommandLoadOutcome, type CommandLoadSummary, type CommandResult, type CommandRunner, type CompactionResult, type CompiledRules, type CompressConfig, type CompressResult, type ConfigMigration, type ConfigOrigins, ContextCompressor, type ContextEngine, type CreateScheduleInput, type CreateSessionInput, DEFAULT_GOAL_MAX_ROUNDS, type DelegateArgs, type DelegateConfig, DelegateManager, type DelegateTaskResult, type DiagnoseOptions, type DiscoverOutcome, type DiscoveredFile, type DoctorReport, EMPTY_RULES, EPOCH_DISK_LEDGER, EpochConfigSchema, type ExpandOptions, FTS_TABLES, FTS_TRIGGERS, type FallbackEvent, type FileSlots, type FileSourceKind, type ForkInput, type FrontmatterParse, type FrontmatterSplit, type FtsHealth, type FtsReclaim, type FtsSpace, type FtsTableHealth, GOAL_BLOCK_CODES, type GateAxis, type GateVerdict, type GenerateInput, type GenerateOutput, type Goal, type GoalBlockReason, type GoalClear, type GoalPhase, type GoalPromptView, type GoalRefusal, type GoalRoundResult, GoalService, GoalStore, type GoalToolDeps, type GoalWrite, HEADLESS_AUDIT_CODES, type HeadlessPolicy, type HookConfigEntry, HookManager, type HookManagerOptions, type HookMatcher, type HookSourceKind, type HookSourceStatus, type HookSourcesOptions, type HookSourcesSummary, type HooksParseOutcome, type MemoryManager$1 as IMemoryManager, INSTRUCTION_BUDGET_CHARS, INSTRUCTION_FILES, type SessionManager$1 as ISessionManager, type SkillSystem$1 as ISkillSystem, ImageLoadError, type ImageSize, type ImportDecision, type ImportGate, type ImportNode, type ImportSkipReason, ImportTrustStore, type InstallOptions, type InstallOutcome, type InstallPreview, type InstructionScan, type InstructionSource, type IsolationReason, type IsolationReport, type JsonSchemaDocument, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, type LayerOutcome, type LayerScalars, type LayerStatus, type LearningContext, type LearningResult, type LearningSkipReason, type LifecycleOutcome, type ListCandidatesInput, type ListSessionsInput, type ListSessionsOutput, type LoadCommandsOptions, type LoadConfigOptions, type LoadKeybindingsOptions, type LoadKeybindingsResult, type LoadRolesOptions, type LoadedPlugin, type LockHolder, MARKETPLACE_FILE, MAX_AUDIT_ENTRIES, MAX_COMMAND_DEPTH, MAX_GOAL_MAX_ROUNDS, MAX_IMPORT_DEPTH, MAX_OBJECTIVE_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, type ManagedPolicy, ManagedPolicyError, type ManagedSettings, ManagedSettingsSchema, type MarketplaceCatalog, type MarketplaceEntry, type MarketplaceOutcome, type MarketplaceRecord, type MemoryConfig, type MemoryEntry, MemoryManager, MemoryReviewer, type MemorySearchResult, type MemoryTarget, type MemoryWriteResult, type MentionPart, type MentionResolution, type Message, type MessageHit, type MessageRecord, type MessageSurface, type ModelCapability, ModelFailureTracker, type ModelMetaEntry, type ModelPricing, type MultimodalPolicy, NOMINAL_TOTAL_BYTES, NO_REVEALED_TOOLS, type NonInteractiveProbe, type OsTaskSnapshot, PERMISSION_AUDIT_CODES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_NAME_PATTERN, POLICY_DECISIONS, PROJECT_AGENTS_SUBDIR, PROVIDER_NO_CREDENTIAL, type PermissionAuditCode, type PermissionAuditEntry, type PermissionAuditOutcome, type PermissionAuditScope, type PermissionAuditSnapshot, PermissionManager, type PersistedBudget, type PersistedPart, type PlanApprovalFn, type PlanEnterResult, type PlanModeDeps, PlanModeState, type PlanSettlement, type PluginArtifacts, type PluginCommandDir, type PluginCounts, type PluginHookFile, type PluginInventory, type PluginLoadOptions, type PluginManifest, type PluginPathRef, type PluginRecord, type PluginSettingsFile, type PluginSourceType, type PluginStateReadOutcome, PluginStore, type PolicyDirSpec, type PolicyDirsSummary, type PolicyLoadOutcome, type PolicyRule, PolicyRuleSchema, type ProjectContext, ProviderError, ProviderRouter, type ProviderStreamChunk, type ProviderToolCall$1 as ProviderToolCall, type ProviderWarning, type PruneResult, type QuestionAskFn, RECORDING_KEEP_RUNS, RECORDING_MAX_BYTES, ROLE_FRONTMATTER_SCHEMA, RUN_CODE_TOOL, type ReadMessagesInput, type ReadMessagesOutput, type RecentWorkspace, RecentWorkspaces, type RecordRunInput, type RecorderOptions, type RecoveryAction, type RegisterInput, type RegisterOutcome, type RegistrarOptions, type RegistrationPatch, type RepairOutcome, type ResolveMentionsOptions, type ResolveReferenceInput, type ResolveSettingsOptions, type ResolvedCompression, type ResolvedReference, type ResolvedSource, type ResponseFormat, type RestorePartsOptions, type ReviewIssue, type RewindAction, type RewindDrift, type RewindFilePlan, type RewindOptions, type RewindOutcome, type RewindPreview, type RoleCreateFailure, type RoleCreateInput, type RoleCreateOptions, type RoleCreateOutcome, type RoleLoadOutcome, type RoleLoadSummary, type RoleMergeNotice, type RoleMergeResult, type RoleScope, type RuleMatch, type RuleSuggestion, type RuleVerdict, type RunCodeFailure, type RunCodeInput, type RunCodeOutcome, type RunCodeToolDeps, type RunEstimateInput, type RunInput, type RunResult, SANDBOX_COVERS, SANDBOX_EXCLUDES, SCALAR_KEYS, SCHEDULE_DEFAULTS, SCHEDULE_DEFAULT_ALLOWLIST, SCHEDULE_ISSUE_CODES, SCHTASKS_FOLDER, SESSION_MESSAGES_READ_TOOL, SESSION_MESSAGES_SEARCH_TOOL, SESSION_QUERY_TOOLS, SESSION_SEARCH_TOOL, SESSION_TRACE_TOOL, SETTINGS_LAYER_ORDER, SETTING_WRITE_APPLY, SETTING_WRITE_LAYERS, SKILL_VIEW_TOOL, SLASH_COMMANDS_DIAG_MODULE, type ScalarKey, type ScanInstructionsOptions, type ScheduleArgvRefusal, type ScheduleArgvResult, type ScheduleArgvWarning, type ScheduleBackend, type ScheduleCliEntry, type ScheduleDrift, type ScheduleDriftKind, type ScheduleInstallForm, type ScheduleIssue, type ScheduleIssueCode, type ScheduleLock, ScheduleRecorder, ScheduleRegistrar, ScheduleStore, type ScheduleValidation, type SchemaExport, type SearchHit, type SearchInput, type SearchMessagesInput, type SearchMessagesOutput, type SearchOutput, type SearchSessionsInput, type SelectionDeps, type Session, type SessionCandidate, type SessionHit, SessionManager, type SessionMentionDeps, type SessionMeta, SessionQueries, SessionReferences, type SessionSearchDeps, type SessionStats, type SessionSurface, type SessionTrace, type SessionVisibility, type SessionVisibilityInput, type SettingApply, type SettingChain, type SettingFutile, type SettingLayer, type SettingStep, type SettingValue, type SettingWriteFailure, type SettingWriteLayer, type SettingWriteOutcome, type SettingWriteRequest, type SettingWriteTarget, type SettingWriteTargetsOptions, type SettingsFile, SettingsFileError, SettingsFileSchema, type SettingsLayer, type SettingsResolution, type ShadowFinding, type ShadowKind, type Skill, type SkillDirSource, type SkillDirSpec, type SkillDirsSummary, type SkillImportConflict, type SkillImportDone, type SkillImportEntry, type SkillImportFailure, type SkillImportForm, type SkillImportOptions, type SkillImportPreview, type SkillImportResult, type SkillIndexEntry, type SkillIndexOptions, type SkillIndexResidency, type SkillIndexStats, SkillLearner, type SkillLearningProvider, type SkillMeta, type SkillStats, SkillSystem, type SkillSystemOptions, type SkillViewDeps, type SubAgentRunner, type SubTask, type SubToolCaller, type SummarizeOutput, type SurfaceMessage, type SystemPromptParams, type SystemPromptSegments, TOOL_SEARCH_TOOL, TaskNoticeTracker, type TodoItem, type ToolCall, type ToolConflict, type ToolGate, type ToolNameFidelity, type ToolNameLookup, ToolRegistry, type ToolRevealState, type ToolScope, type ToolSearchDeps, type ToolTableCost, type TraceInput, type TraceNode, TrackerDB, type TrustDecision, type TrustGate, type TrustGateOptions, TrustManager, type TurnRecord, type TurnTiming, type UpdateScheduleInput, type UtilityModelInfo, type ValidateScheduleInput, type VersionCheck, Workspace, type WorkspaceFiles, type WorkspaceIssue, type WorkspaceIssueKind, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, checkEpochVersion, checkFtsHealth, checkShadowing, classifyProviderError, clearModelCache, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createRoleFile, createRoleScope, createRunCodeTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, defaultModelOf, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, hasPromptCaching, hasProviderCredentials, imageFromBase64, imageFromPath, imagePartTokens, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mergeHeadlessPolicy, mergeRoles, microsToUsd, modelListCandidates, needsAllowlist, nextFallbackModel, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, openArtifact, originOf, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelList, parseRoleDefinition, parseSkillFrontmatter, pendingImageTokens, persistParts, persistToolResults, previewSkillImport, pruneArtifacts, pruneRecordings, pruneSchedules, readImageSize, readMarketplaces, readPluginManifest, readPluginRecords, readProviderKeyEnv, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeSessionArtifacts, renderImportTree, renderProjectContext, renderSdkDeclaration, repairSchedules, resolveArtifactRetention, resolveCodeModeWorker, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setImportGate, setPluginEnabled, setTrustGate, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, suggestRuleFromApproval, systemPromptSegments, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writeSettingValue };
16189
+ export { AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, type AcquireResult, type AgentConfig, AgentLoop, type AgentProvider, type AgentSite, type AgentSiteRef, type AppendMessageInput, ApprovalCache, type ApprovalDecision, type ApprovalScope, type ArtifactOpenRefusal, type ArtifactRetention, type AskQuestionDeps, BLOCKED_TOOLS, type BackendOptions, type BackendOutcome, type BackgroundTaskSource, type BaseOrigin, type BaseSlot, type BeginTurnInput, type BreakdownInput, BudgetGuard, type BudgetGuardOptions, type BudgetInfo, type BudgetLevel, type BudgetOptions, type BudgetStatus, BudgetStore, type BudgetStoreOptions, type BuildFireArgvInput, type BuildIndexOptions, CHECKPOINT_MAX_TOTAL_BYTES, CLAUDE_EVENT_NAMES, CLAUDE_TOOL_NAMES, CODE_MODE_LIMITS, CODE_MODE_SDK_TAG, CONFIG_KEYS, CURRENT_CONFIG_VERSION, type CachedApproval, type CachedDecision, type CheckpointCapture, type CheckpointFile, CheckpointManager, type CheckpointManagerOptions, type CheckpointManifest, CheckpointStore, type CheckpointStoreOptions, type CheckpointSummary, type ClaudeHooksParseOptions, type CodeModeLimits, type CodeRequest, type CodeResult, CodeSandbox, type CommandHookConfig, type CommandHookResult, type CommandLoadOutcome, type CommandLoadSummary, type CommandResult, type CommandRunner, type CompactionResult, type CompiledRules, type ComplianceDirSpec, type ComplianceDirsSummary, ComplianceEngine, type ComplianceEngineInput, type ComplianceGate, type ComplianceHit, type ComplianceRule, type ComplianceRuleSource, type ComplianceSettings, type ComplianceVerdict, type CompressConfig, type CompressResult, type ConfigMigration, type ConfigOrigins, ContextCompressor, type ContextEngine, type CreateScheduleInput, type CreateSessionInput, DEFAULT_COMPLIANCE_ACTIONS, DEFAULT_COMPLIANCE_SETTINGS, DEFAULT_GOAL_MAX_ROUNDS, DEFAULT_MAX_HOLD_CHARS, type DelegateArgs, type DelegateConfig, DelegateManager, type DelegateTaskResult, type DiagnoseOptions, type DiscoverOutcome, type DiscoveredFile, type DoctorReport, EMPTY_RULES, EPOCH_DISK_LEDGER, EpochConfigSchema, type ExpandOptions, FTS_TABLES, FTS_TRIGGERS, type FallbackEvent, type FileSlots, type FileSourceKind, type ForkInput, type FrontmatterParse, type FrontmatterSplit, type FtsHealth, type FtsReclaim, type FtsSpace, type FtsTableHealth, GOAL_BLOCK_CODES, type GateAxis, type GateVerdict, type GenerateInput, type GenerateOutput, type Goal, type GoalBlockReason, type GoalClear, type GoalPhase, type GoalPromptView, type GoalRefusal, type GoalRoundResult, GoalService, GoalStore, type GoalToolDeps, type GoalWrite, HEADLESS_AUDIT_CODES, type HeadlessPolicy, type HookConfigEntry, HookManager, type HookManagerOptions, type HookMatcher, type HookSourceKind, type HookSourceStatus, type HookSourcesOptions, type HookSourcesSummary, type HooksParseOutcome, type MemoryManager$1 as IMemoryManager, INSTRUCTION_BUDGET_CHARS, INSTRUCTION_FILES, type SessionManager$1 as ISessionManager, type SkillSystem$1 as ISkillSystem, ImageLoadError, type ImageSize, type ImportDecision, type ImportGate, type ImportNode, type ImportSkipReason, ImportTrustStore, type InstallOptions, type InstallOutcome, type InstallPreview, type InstructionScan, type InstructionSource, type IsolationReason, type IsolationReport, type JsonSchemaDocument, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, type LayerOutcome, type LayerScalars, type LayerStatus, type LearningContext, type LearningResult, type LearningSkipReason, type LexiconLoadOutcome, type LifecycleOutcome, type ListCandidatesInput, type ListSessionsInput, type ListSessionsOutput, type LoadCommandsOptions, type LoadConfigOptions, type LoadKeybindingsOptions, type LoadKeybindingsResult, type LoadRolesOptions, type LoadedPlugin, type LockHolder, MARKETPLACE_FILE, MAX_AUDIT_ENTRIES, MAX_COMMAND_DEPTH, MAX_GOAL_MAX_ROUNDS, MAX_IMPORT_DEPTH, MAX_OBJECTIVE_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, type ManagedPolicy, ManagedPolicyError, type ManagedSettings, ManagedSettingsSchema, type MarketplaceCatalog, type MarketplaceEntry, type MarketplaceOutcome, type MarketplaceRecord, type MemoryConfig, type MemoryEntry, MemoryManager, MemoryReviewer, type MemorySearchResult, type MemoryTarget, type MemoryWriteResult, type MentionPart, type MentionResolution, type Message, type MessageHit, type MessageRecord, type MessageSurface, type ModelCapability, ModelFailureTracker, type ModelMetaEntry, type ModelPricing, type MultimodalPolicy, NOMINAL_TOTAL_BYTES, NO_REVEALED_TOOLS, type NonInteractiveProbe, type OsTaskSnapshot, type OutputGuard, PERMISSION_AUDIT_CODES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_NAME_PATTERN, POLICY_DECISIONS, PROJECT_AGENTS_SUBDIR, PROVIDER_NO_CREDENTIAL, type PermissionAuditCode, type PermissionAuditEntry, type PermissionAuditOutcome, type PermissionAuditScope, type PermissionAuditSnapshot, PermissionManager, type PersistedBudget, type PersistedPart, type PlanApprovalFn, type PlanEnterResult, type PlanModeDeps, PlanModeState, type PlanSettlement, type PluginArtifacts, type PluginCommandDir, type PluginCounts, type PluginHookFile, type PluginInventory, type PluginLoadOptions, type PluginManifest, type PluginPathRef, type PluginRecord, type PluginSettingsFile, type PluginSourceType, type PluginStateReadOutcome, PluginStore, type PolicyDirSpec, type PolicyDirsSummary, type PolicyLoadOutcome, type PolicyRule, PolicyRuleSchema, type ProjectContext, ProviderError, ProviderRouter, type ProviderStreamChunk, type ProviderToolCall$1 as ProviderToolCall, type ProviderWarning, type PruneResult, type QuestionAskFn, RECORDING_KEEP_RUNS, RECORDING_MAX_BYTES, ROLE_FRONTMATTER_SCHEMA, RUN_CODE_TOOL, type ReadMessagesInput, type ReadMessagesOutput, type RecentWorkspace, RecentWorkspaces, type RecordRunInput, type RecorderOptions, type RecoveryAction, type RegisterInput, type RegisterOutcome, type RegistrarOptions, type RegistrationPatch, type RepairOutcome, type ResolveMentionsOptions, type ResolveReferenceInput, type ResolveSettingsOptions, type ResolvedCompression, type ResolvedReference, type ResolvedSource, type ResponseFormat, type RestorePartsOptions, type ReviewIssue, type RewindAction, type RewindDrift, type RewindFilePlan, type RewindOptions, type RewindOutcome, type RewindPreview, type RoleCreateFailure, type RoleCreateInput, type RoleCreateOptions, type RoleCreateOutcome, type RoleLoadOutcome, type RoleLoadSummary, type RoleMergeNotice, type RoleMergeResult, type RoleScope, type RuleMatch, type RuleSuggestion, type RuleVerdict, type RunCodeFailure, type RunCodeInput, type RunCodeOutcome, type RunCodeToolDeps, type RunEstimateInput, type RunInput, type RunResult, SANDBOX_COVERS, SANDBOX_EXCLUDES, SCALAR_KEYS, SCHEDULE_DEFAULTS, SCHEDULE_DEFAULT_ALLOWLIST, SCHEDULE_ISSUE_CODES, SCHTASKS_FOLDER, SESSION_MESSAGES_READ_TOOL, SESSION_MESSAGES_SEARCH_TOOL, SESSION_QUERY_TOOLS, SESSION_SEARCH_TOOL, SESSION_TRACE_TOOL, SETTINGS_LAYER_ORDER, SETTING_WRITE_APPLY, SETTING_WRITE_KEYS, SETTING_WRITE_LAYERS, SKILL_CREATE_TOOL, SKILL_EDIT_TOOL, SKILL_PATCH_TOOL, SKILL_VIEW_TOOL, SKILL_WRITE_FILE_TOOL, SLASH_COMMANDS_DIAG_MODULE, type ScalarKey, type ScanInstructionsOptions, type ScheduleArgvRefusal, type ScheduleArgvResult, type ScheduleArgvWarning, type ScheduleBackend, type ScheduleCliEntry, type ScheduleDrift, type ScheduleDriftKind, type ScheduleInstallForm, type ScheduleIssue, type ScheduleIssueCode, type ScheduleLock, ScheduleRecorder, ScheduleRegistrar, ScheduleStore, type ScheduleValidation, type SchemaExport, type SearchHit, type SearchInput, type SearchMessagesInput, type SearchMessagesOutput, type SearchOutput, type SearchSessionsInput, type SelectionDeps, type Session, type SessionCandidate, type SessionHit, SessionManager, type SessionMentionDeps, type SessionMeta, SessionQueries, SessionReferences, type SessionSearchDeps, type SessionStats, type SessionSurface, type SessionTrace, type SessionVisibility, type SessionVisibilityInput, type SettingApply, type SettingChain, type SettingFutile, type SettingLayer, type SettingStep, type SettingValue, type SettingValueKind, type SettingWriteFailure, type SettingWriteKey, type SettingWriteLayer, type SettingWriteOutcome, type SettingWriteRequest, type SettingWriteTarget, type SettingWriteTargetsOptions, type SettingsFile, SettingsFileError, SettingsFileSchema, type SettingsLayer, type SettingsResolution, type ShadowFinding, type ShadowKind, type Skill, type SkillDirSource, type SkillDirSpec, type SkillDirsSummary, type SkillImportConflict, type SkillImportDone, type SkillImportEntry, type SkillImportFailure, type SkillImportForm, type SkillImportOptions, type SkillImportPreview, type SkillImportResult, type SkillIndexEntry, type SkillIndexOptions, type SkillIndexResidency, type SkillIndexStats, SkillLearner, type SkillLearningProvider, type SkillMeta, type SkillStats, SkillSystem, type SkillSystemOptions, type SkillViewDeps, type SkillWriteDeps, type SubAgentRunner, type SubTask, type SubToolCaller, type SummarizeOutput, type SurfaceMessage, type SystemPromptParams, type SystemPromptSegments, TOOL_SEARCH_TOOL, TaskNoticeTracker, type TodoItem, type ToolCall, type ToolConflict, type ToolGate, type ToolNameFidelity, type ToolNameLookup, ToolRegistry, type ToolRevealState, type ToolScope, type ToolSearchDeps, type ToolTableCost, type TraceInput, type TraceNode, TrackerDB, type TrustDecision, type TrustGate, type TrustGateOptions, TrustManager, type TurnRecord, type TurnTiming, type UpdateScheduleInput, type UtilityModelInfo, type ValidateScheduleInput, type VersionCheck, Workspace, type WorkspaceFiles, type WorkspaceIssue, type WorkspaceIssueKind, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, checkEpochVersion, checkFtsHealth, checkShadowing, classifyProviderError, clearModelCache, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createRoleFile, createRoleScope, createRunCodeTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, defaultModelOf, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, hasPromptCaching, hasProviderCredentials, imageFromBase64, imageFromPath, imagePartTokens, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mergeHeadlessPolicy, mergeRoles, microsToUsd, modelListCandidates, needsAllowlist, nextFallbackModel, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, openArtifact, originOf, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelList, parseRoleDefinition, parseSkillFrontmatter, pendingImageTokens, persistParts, persistToolResults, previewSkillImport, pruneArtifacts, pruneRecordings, pruneSchedules, readImageSize, readMarketplaces, readPluginManifest, readPluginRecords, readProviderKeyEnv, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeSessionArtifacts, renderImportTree, renderProjectContext, renderSdkDeclaration, repairSchedules, resolveArtifactRetention, resolveCodeModeWorker, resolveComplianceDirs, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writeSettingValue };