@x-otto/coding 0.0.1-alpha.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.
@@ -0,0 +1,3080 @@
1
+ import { Devtools } from "@x-otto/devtools";
2
+ import * as _$_x_otto_env0 from "@x-otto/env";
3
+ import { ResilienceConfig, ResilienceConfigOverride, UserIdentity, findWorkspaceRoot } from "@x-otto/env";
4
+ import { Api, AuthStore, IsModelUsable, Message, Model, ModelCatalogStore, ModelRegistry, ModelSpec, ProviderRegistry, WireProtocolRegistry, WorkflowSlot, apiCredentialId } from "@x-otto/ai";
5
+ import { Diagnoser, EditFileCallback, FailureSignalStore, HookRegistry, HookSpec, PermissionAuditLog, PermissionMode, PermissionPolicyRegistry } from "@x-otto/hooks";
6
+ import * as _$_x_otto_tools0 from "@x-otto/tools";
7
+ import { SandboxConfig, SandboxStrategy, ToolRegistry } from "@x-otto/tools";
8
+ import { LogLevel, Logger, attachLogListener } from "@x-otto/shared";
9
+ import { AutoMemory, FileStateManager, MemoryStore, OperationalLearningStore } from "@x-otto/memory";
10
+ import * as _$_x_otto_runtime0 from "@x-otto/runtime";
11
+ import { AgentJobRegistry, AgentJobStatus, AgentObservationSnapshot, AgentRuntime, AgentSession, AgentSession as AgentSession$1, AgentSessionInfo, AgentSessionInfo as AgentSessionInfo$1, AgentSessionJob, AgentSessionJob as AgentSessionJob$1, AgentSessionOptions, AgentSessionOptions as AgentSessionOptions$1, BackgroundProcess, Checkpoint, CheckpointData, CheckpointData as CheckpointData$1, FileEntrySnapshot, FileSnapshot, FleetMonitor, MemoryGovernor, MemoryPressureLevel, MemorySample, MemorySubsystem, PromptOptions, ReplayLevel, ResidencyGovernor, ResolvedSessionConfig, RestoreMode, SandboxRunner, SandboxToolCall, SandboxToolResult, SandboxUnavailableError, SessionPool, SessionPool as CodingSessionPool, SessionPoolOptions, TracebackView, captureFiles, createSessionStableInjectionHooks, defaultMaxToolTurnExtensions, deriveSessionTitle, globalAgentJobRegistry, globalAgentObservability, globalProcessRegistry, messagesFromSnapshot, reconstructMessages, resolveSessionTitle, restoreFiles } from "@x-otto/runtime";
12
+ import { AppendLog, LiveTap, StorageHost } from "@x-otto/persistence";
13
+ import { FrontendPort, ResidencyBudgetConfig } from "@x-otto/session-contract";
14
+ import { SkillProvider, SkillRegistry } from "@x-otto/skill";
15
+ import { AgentProfile, PromptManager, PromptPreset, PromptProviderOptions, SubAgentPromptContext } from "@x-otto/prompt";
16
+ import * as _$_x_otto_plugin0 from "@x-otto/plugin";
17
+ import { CommandRef, ContextMap, ContextMap as ContextMap$1, DiscoverPluginsOptions, DiscoveredPlugin, DiscoveredPlugin as DiscoveredPlugin$1, DispatchCaps, FeedbackProvider, FileProviderOptions, HIGH_RISK_CAPABILITIES, MonitorEvent, PLUGIN_MANIFEST_FILENAME, POINT, PluginContext, PluginContributes, PluginExecutableSurface, PluginFileViewerEntry, PluginI18nRegistry, PluginInputRegistry, PluginInputRegistry as PluginInputRegistry$1, PluginManifest, PluginModule, PluginRendererEntry, PluginServiceNotification, PluginTrustVerdict, PluginTrustVerdict as PluginTrustVerdict$1, PulseSurveyEntry, PulseSurveyRating, ResolvedAction, ResolvedAction as ResolvedAction$1, SessionIdleNotification, SigilEntry, SigilKind, SigilPrefix, SigilProvider, SigilSource, TranscriptMessage, createBuiltinHashtags, createFileProvider, createPluginInputRegistry, detectPluginExecutableSurface, discoverPlugins, dispatch, evaluatePluginTrust, grantPluginCapabilities, grantedPluginCapabilities, isPluginTrusted, parsePluginManifest, pluginTrustStorePath, readHighRiskCapabilities, resolveActions, sigilOf, trustPlugin, untrustPlugin } from "@x-otto/plugin";
18
+ import { ClaudeExecutableSurface, ClaudeHookBridgeDeps, ClaudeHooksConfig, ClaudeTrustVerdict, ExpandOptions, FileCommand, FileCommand as FileCommand$1, HookRunner, ProjectConfigGating, ProjectConfigTrustContext, WorkspaceTrustAction, WorkspaceTrustPromptDecision, claudeTrustStorePath, createClaudeHookBridgeHooks, defaultHookRunner, detectClaudeExecutableSurface, detectProjectConfigGating, discoverFileCommands, evaluateClaudeTrust, evaluateWorkspaceTrustPrompt, expandCommandBody, interpretPreToolUse, isProjectTrusted, isStrictProjectConfigEnabled, loadClaudeHooksConfig, matchesHookMatcher, parseClaudeHooks, parseDotMcpJson, resolveClaudeMcpServers, resolveProjectConfigTrusted, trustProject, untrustProject } from "@x-otto/claude-compat";
19
+ import { McpClient, McpManager, McpServerConfig } from "@x-otto/mcp";
20
+ import { SqliteSessionRepository } from "@x-otto/session";
21
+ import { OrchestrationPattern, Orchestrator, RunSessionOptions } from "@x-otto/orchestrator";
22
+ import * as _$_x_otto_setting0 from "@x-otto/setting";
23
+ import { InstalledPluginEntry, Setting, SettingsManager } from "@x-otto/setting";
24
+ import { AgentMessage, AgentTool, ClockPort, DescribeImagesPort, TraceEvent } from "@x-otto/agent";
25
+ import { NotificationChannel, NotificationDispatcher, NotificationKind, NotificationKind as NotificationKind$1, PresenceTracker } from "@x-otto/notification";
26
+ import * as _$_x_otto_workspace0 from "@x-otto/workspace";
27
+ import { WorkspaceRef } from "@x-otto/workspace";
28
+ import { WriteTodos } from "@x-otto/orchestration-contracts";
29
+ import { FireOwnership, SCHEDULE_LEASE_MIGRATIONS, ScheduleRegistry, ScheduleStore, ScheduleSubscriber, ScheduledTask, ScheduledTask as ScheduledTask$1, ScheduledTaskInput, SchedulerDeps, SchedulerService, SchedulerService as SchedulerService$1, createLocalFireOwnership, createRemoteFireOwnership, createRemoteScheduleStore, createScheduleStore } from "@x-otto/schedule";
30
+ import { ContentType, GitUpgradeCheckResult, InstallManager, InstallOptions, InstallProgress, InstallResult, InstallScope, InstallScope as InstallScope$1, InstallSourceMetadata, InstalledItem, ListInstalledOptions, LoadedRegistry, ParsedRegistry, PostInstallContext, PostInstallResult, ProgressPhase, RegistryClient, RegistryEntry, RegistrySourceConfig, ResolvedSource, SourceType, UninstallOptions, UninstallResult, UninstallTarget, UpgradeCheckOptions, UpgradeCheckResult, VersionInfo, builtinOfficialSource, checkArchiveBomb, checkGitUpgrades, checkUpgrades, cleanTempDir, createArchive, createTempDir, detectUninstallTarget, extractArchive, listInstalledItems, parseRegistry, scanInstalledVersions, uninstall, validateExtractedPaths } from "@x-otto/install";
31
+ import * as _$_x_otto_interchange0 from "@x-otto/interchange";
32
+ import { GrillAnswer, GrillQuestion, PluginInputRegistry as PluginInputRegistry$2, PluginPerfMetricResult, PluginPerfMetricResult as PluginPerfMetricResult$1, SigilResolver } from "@x-otto/interchange";
33
+
34
+ //#region src/plugin/plugin-health-tracker.d.ts
35
+ /** Plugin health tracker: crash/restart/hang detection + circuit breaker. */
36
+ interface PluginHealthStats {
37
+ pluginId: string;
38
+ /** interceptor hook 挂起超时累计次数(M1 写入点)。 */
39
+ hookTimeouts: number;
40
+ /** 代码式工具(PluginWorkerPool)挂起超时累计次数(collect-plugin-perf-metrics.ts 写入点)。 */
41
+ toolTimeouts: number;
42
+ /** 最近一次错误(加载/编译/工厂失败等,module-loader*.ts 写入点)。 */
43
+ lastError?: {
44
+ message: string;
45
+ timestamp: number;
46
+ };
47
+ /** 最近一次触发超时的 hook 名(诊断定位用)。 */
48
+ lastTimeoutHook?: string;
49
+ }
50
+ /** 插件健康度内存态单例存储:挂起/错误计数按 pluginId 聚合。不持久化跨进程(规则 5)。 */
51
+ declare class PluginHealthTracker {
52
+ private readonly stats;
53
+ private readonly clock;
54
+ constructor(clock?: () => number);
55
+ private ensure;
56
+ /** interceptor hook 挂起超时(M1 `onHookTimeout` 回调写入点)。 */
57
+ recordHookTimeout(pluginId: string, hookName: string): void;
58
+ /** 代码式工具(PluginWorkerPool)挂起超时(collect-plugin-perf-metrics.ts 写入点)。 */
59
+ recordToolTimeout(pluginId: string): void;
60
+ /** 插件加载/编译/工厂执行失败(module-loader*.ts 写入点)。 */
61
+ recordError(pluginId: string, message: string): void;
62
+ /** 查询单个插件的健康度快照;无记录时返回全零默认值(供 D4 面板"全零不展示"判定)。 */
63
+ query(pluginId: string): PluginHealthStats;
64
+ /** 全量快照(诊断/测试用途)。 */
65
+ all(): PluginHealthStats[];
66
+ clear(): void;
67
+ }
68
+ //#endregion
69
+ //#region src/app/sandbox-controller.d.ts
70
+ declare class SandboxController {
71
+ private readonly logger;
72
+ private strategy;
73
+ private pinned;
74
+ private settingSnapshot;
75
+ private networkAllowed;
76
+ private configuredWritablePaths;
77
+ private autoAllowBash;
78
+ constructor(logger: Logger);
79
+ /** 晚绑定读取面(bash 工具 provider)。 */
80
+ get current(): SandboxStrategy | null;
81
+ /** 当前生效的沙箱策略名(null = 无沙箱)。可观测面:测试/调试/CLI 状态展示。 */
82
+ get activeName(): string | null;
83
+ /** 沙箱是否启用(null=否 → sandbox-guard 即 no-op)。 */
84
+ get enabled(): boolean;
85
+ /** 当前沙箱网络策略(deny 时 networkAllowed=false)。 */
86
+ get isNetworkAllowed(): boolean;
87
+ /** 配置的额外可写路径(writable-roots 计算输入)。 */
88
+ get writablePaths(): readonly string[];
89
+ /** bash 沙箱越界自动放行开关(opt-in,默认 false)。见 SandboxConfig.autoAllowBashIfSandboxed。 */
90
+ get autoAllowBashIfSandboxed(): boolean;
91
+ private readonly bypassCommands;
92
+ /** 记录一个命令为「已批准绕过沙箱」(会话内持续,同命令不再重复问/拦)。 */
93
+ approveBypass(command: string): void;
94
+ /** 该命令是否已获批 bypass。 */
95
+ isBypassed(command: string | undefined): boolean;
96
+ /** options.sandbox 显式注入 → 立即构造并钉死(settings 不覆盖)。 */
97
+ pin(config: SandboxConfig): void;
98
+ /**
99
+ * settings.sandbox → 沙箱策略(load 与热更新走同一条路)。
100
+ *
101
+ * - options.sandbox 显式注入时钉死,settings 不覆盖(程序化优先);
102
+ * - 配置内容不变时幂等跳过(change 事件对任意配置变更都触发);
103
+ * - 替换/关闭时异步释放旧策略(seatbelt 临时 profile 文件)。
104
+ * wrap→child spawn 同 tick 同步完成,dispose 落在后续 tick,无竞争窗口。
105
+ */
106
+ applySetting(config: SandboxConfig | undefined): void;
107
+ /**
108
+ * 从 setting 解析沙箱配置(组合根策略下沉自此,不再留在 App)。
109
+ *
110
+ * - 显式 `setting.sandbox` → 原样尊重;
111
+ * - 无 sandbox + bypass 模式 → 无沙箱;
112
+ * - 无 sandbox + 非 bypass → 默认 on(network allow,writable 由策略约束)。
113
+ */
114
+ resolveConfig(setting: Setting): SandboxConfig | undefined;
115
+ dispose(): Promise<void>;
116
+ }
117
+ //#endregion
118
+ //#region src/app/mcp-controller.d.ts
119
+ /**
120
+ * 带来源元数据的有效 MCP server(RFC-081)。
121
+ * source 标识来自哪一层;pluginId 仅 plugin 层有值;managed 标记是否由插件托管。
122
+ */
123
+ interface EffectiveMcpServer extends McpServerConfig {
124
+ disabled?: boolean;
125
+ source: 'otto' | 'claude' | 'plugin';
126
+ pluginId?: string;
127
+ }
128
+ declare class McpController {
129
+ private readonly settings;
130
+ private readonly toolRegistry;
131
+ private readonly logger;
132
+ private readonly workspaceDir?;
133
+ /**
134
+ * RFC-230:统一重试/超时/退避配置——惰性 getter(同 `SessionConfigResolverDeps.
135
+ * getResilienceConfig` 模式)。`ensureManager()` 惰性创建 `McpManager`,真正调用
136
+ * 该 getter 的时机是运行时(首次连接 MCP server 时),此时 App 必然已 `start()`。
137
+ */
138
+ private readonly getResilienceConfig?;
139
+ private _manager;
140
+ /** 暴露内部 McpManager 供向后兼容。 */
141
+ get manager(): McpManager | null;
142
+ /** 暴露单个已连接的 McpClient 供插件面板调用 tool(RFC-081)。 */
143
+ getMcpClient(name: string): McpClient | undefined;
144
+ constructor(settings: SettingsManager, toolRegistry: ToolRegistry, logger: Logger, workspaceDir?: string | undefined,
145
+ /**
146
+ * RFC-230:统一重试/超时/退避配置——惰性 getter(同 `SessionConfigResolverDeps.
147
+ * getResilienceConfig` 模式)。`ensureManager()` 惰性创建 `McpManager`,真正调用
148
+ * 该 getter 的时机是运行时(首次连接 MCP server 时),此时 App 必然已 `start()`。
149
+ */
150
+
151
+ getResilienceConfig?: (() => _$_x_otto_env0.ResilienceConfig) | undefined);
152
+ /** 三源 MCP server 层(otto > claude > plugin)的统一取数——effectiveServers /
153
+ * listEffectiveServers 共用,消除两处重复的 source 解析(ARCH-083-04)。 */
154
+ private resolveServerLayers;
155
+ /**
156
+ * 有效 server 集 = settings.mcp_servers(otto,胜)合并 `.mcp.json`(claude)+ 插件
157
+ * `.mcp.json`(最低优先级)。优先级(高→低):otto > claude > plugin。
158
+ * 三者皆经各自信任门;`.mcp.json`/插件 server 为只读导入:不参与 setServerEnabled 落盘。
159
+ */
160
+ private effectiveServers;
161
+ /**
162
+ * 有效 server 集 + 来源元数据(RFC-081)。
163
+ * 保留每个 server 的 source/pluginId/managed 信息,供 extension-manager 和 panel runtime 使用。
164
+ * 与 effectiveServers() 返回相同 server 集,但结构不同(EffectiveMcpServer vs 扁平 McpServerConfig)。
165
+ */
166
+ listEffectiveServers(): Record<string, EffectiveMcpServer>;
167
+ /** 全量重投影 mcp__ 前缀工具:清旧 → 注册活 manager 的全部工具。 */
168
+ private syncTools;
169
+ /** 惰性创建 manager 并挂同步监听(启动全禁用时 manager 为 null,运行时启用某 server 时拉起)。 */
170
+ private ensureManager;
171
+ /**
172
+ * 连接全部启用的 MCP server 并重投影工具。返回本轮连接统计(RFC-150 D1:宿主层
173
+ * `App.start()` 据调用方是否 await 本方法决定阻塞/非阻塞语义——本方法自身行为不变,
174
+ * "非阻塞"是调用方 `void this.mcpController.start()` 不 await 的结果,不需要 controller
175
+ * 内部感知交互/headless 模式)。
176
+ */
177
+ start(): Promise<{
178
+ connected: number;
179
+ failed: number;
180
+ }>;
181
+ /**
182
+ * 运行时启用/禁用单个 MCP server:落盘 mcp_servers[name].disabled → 实时连/断 → 重投影工具。
183
+ * 启用:惰性拉起 manager 并 connect;禁用:disconnect(manager 留存)。未知 server 抛错。
184
+ */
185
+ setServerEnabled(name: string, enabled: boolean): Promise<void>;
186
+ /**
187
+ * 热重载——断当前全部、按最新 settings.mcp_servers 重连 enabled 的、重投影工具
188
+ * (不重启进程)。delegate 写了新 MCP server 配置 apply 后 /reload 即认到。
189
+ * syncTools 反应式重投影 → 主 toolRegistry 即时更新 → App.tools getter 下次读即见新工具。
190
+ */
191
+ reload(): Promise<void>;
192
+ stop(): Promise<void>;
193
+ }
194
+ //#endregion
195
+ //#region src/app/extension-manager.d.ts
196
+ /**
197
+ * extension-manager.ts —— 统一「可插拔项」管理(/extension 命令的后端)。
198
+ *
199
+ * 终局视角:把用户**为扩展 agent 能力而装的东西**收敛到单一管理面:
200
+ * - mcp MCP 服务器(实时连/断;落盘 mcp_servers[].disabled)
201
+ * - skill Skills(registry enable/disable,下一轮生效;落盘 disabled_skills)
202
+ * - agent 自定义声明式 agent(落盘 disabled_agents,下次 spawn 生效)
203
+ * - plugin 插件 bundle(RFC-044;禁用即其 skill/agent/command/mcp 贡献全部消失;落盘 disabled_plugins)
204
+ *
205
+ * 刻意**不**纳入引擎内部接线(hooks)与低层单工具(tools,归 /permissions 的 deny 策略管辖)——
206
+ * 它们不是「用户装的扩展」。新类别 = 新增一个 ExtensionProvider,命令/UI 零改动。
207
+ *
208
+ * 单一真源 = settings:每次切换都落盘对应 disabled_* / mcp_servers[].disabled。
209
+ */
210
+ type ExtensionCategory = 'mcp' | 'skill' | 'agent' | 'plugin';
211
+ /** 切换后何时生效(UI 据此提示)。 */
212
+ type ExtensionApplies = 'live' | 'next-turn';
213
+ interface ExtensionItem {
214
+ category: ExtensionCategory;
215
+ /** 类别内唯一 id(server 名 / skill 名 / agent 名)。 */
216
+ id: string;
217
+ name: string;
218
+ description: string;
219
+ enabled: boolean;
220
+ /** 附加状态行(如 MCP 'ready · 3 tools'、skill 来源)。 */
221
+ detail?: string;
222
+ applies: ExtensionApplies;
223
+ /** 是否不可单独切换(RFC-081:managed MCP server 必须通过卸载插件移除)。 */
224
+ readonly?: boolean;
225
+ /** 插件 scope(仅 plugin 类别有值;user / project / repository / builtin)。 */
226
+ scope?: string;
227
+ }
228
+ interface ExtensionManagerDeps {
229
+ settings: SettingsManager;
230
+ mcp: McpController;
231
+ skills: SkillRegistry | null;
232
+ /** 全量声明式 agent profile(含已禁用的,供面板列出可切换)。 */
233
+ getAgentProfiles: () => readonly AgentProfile[];
234
+ /** 列全部插件(含已禁用,RFC-044 bundle 启停);省略则不暴露 plugin 类别。 */
235
+ getPlugins?: () => readonly DiscoveredPlugin$1[];
236
+ /** RFC-085 M3:插件 disable 时 kill 关联子进程。 */
237
+ processRuntime?: _$_x_otto_runtime0.ProcessRuntime;
238
+ /**
239
+ * RFC-303 D4:插件 enable/disable 切换完成后的通知(落盘后调用,由 App 桥接为
240
+ * monitor 事件 `plugin.enabled`/`plugin.disabled`)。可选——不传则插件切换不对外
241
+ * 广播(仅影响依赖该事件的 monitor 插件,不影响切换本身)。
242
+ */
243
+ onPluginToggle?: (id: string, enabled: boolean) => void;
244
+ }
245
+ declare class ExtensionManager {
246
+ private readonly providers;
247
+ private readonly deps;
248
+ constructor(deps: ExtensionManagerDeps);
249
+ /** 全类别扁平列举(按 provider 注册序:mcp → skill → agent → plugin;skill/plugin 条件注册)。 */
250
+ list(): ExtensionItem[];
251
+ /** 切换某项启用态:路由到对应 provider(落盘 + 实时/下轮生效由 provider 负责)。 */
252
+ setEnabled(category: ExtensionCategory, id: string, enabled: boolean): Promise<void>;
253
+ }
254
+ //#endregion
255
+ //#region src/feedback/feedback-registry.d.ts
256
+ declare class FeedbackRegistry {
257
+ private provider;
258
+ private source;
259
+ /**
260
+ * 注册。同 source 幂等更新放行(reload 场景);跨 source 覆盖检查——已有其他插件
261
+ * 注册时,非同一 source 的二次注册被拒绝(同 `OAuthRegistry.register` 覆盖攻击防护)。
262
+ * 返回是否注册成功。
263
+ */
264
+ register(provider: FeedbackProvider, source: string): boolean;
265
+ /**
266
+ * 原子替换(同 `OAuthRegistry.replace` 模式)——插件 reload 场景"卸旧装新"在单次同步
267
+ * 调用内完成,不经过中间的空档态。不做跨 source 覆盖检查(调用方已确认是同一插件的
268
+ * reload)。
269
+ */
270
+ replace(provider: FeedbackProvider, source: string): void;
271
+ /**
272
+ * 卸载/禁用时清理(对应 `disabled_plugins` 切换、`/reload` 卸载分支)。仅当当前
273
+ * provider 的 source 与传入 source 匹配才清空——防止跨插件误清(如插件 A 卸载时
274
+ * 传入的 source 恰好不是当前占用者,不应清掉插件 B 的注册)。
275
+ */
276
+ unregister(source: string): void;
277
+ get(): FeedbackProvider | undefined;
278
+ reset(): void;
279
+ }
280
+ //#endregion
281
+ //#region src/input/sigil-resolver-registry.d.ts
282
+ declare class SigilResolverRegistry {
283
+ private readonly resolvers;
284
+ /**
285
+ * 注册一批 resolver(last-write-wins 按 id 覆盖——重载场景先 unregisterBySource 再
286
+ * register,正常不撞;跨 source 同 id 覆盖记 warn 由调用方装载器负责,这里保持纯粹)。
287
+ */
288
+ register(resolvers: readonly SigilResolver[], source: string): void;
289
+ /** 按 id 查 resolver(expand 管线消费)。 */
290
+ get(id: string): SigilResolver | undefined;
291
+ /** 注销某 source 的全部 resolver(插件 unload/reload 必调,R5)。 */
292
+ unregisterBySource(source: string): void;
293
+ /** 全量只读快照(诊断/测试用)。 */
294
+ getAll(): ReadonlyMap<string, SigilResolver>;
295
+ get size(): number;
296
+ }
297
+ //#endregion
298
+ //#region src/input/sigil-expand.d.ts
299
+ interface ExpandSigilChipsOptions {
300
+ /** action 型 chip 的 kind 前缀集合——命中即整体跳过(不查 resolver、原样保留)。 */
301
+ skipPrefixes?: ReadonlySet<string>;
302
+ /** 是否运行在与用户同机的 UI 宿主进程(TUI/cli = true,service = false)。缺省 true。 */
303
+ uiHost?: boolean;
304
+ /** 输出上限(字符),缺省 20_000。 */
305
+ maxOutput?: number;
306
+ /**
307
+ * chip 原文 → resolverId 的条目级查找(RFC-210 D2:插件声明式条目经 `entry.resolverId`
308
+ * 绑定 resolver,chip 的 kind 段是通用 'resource' 不含 resolver 信息)。返回非空 id 时
309
+ * 优先于 kind 直查。App 层接线为 `pluginInput` 按 value===chip 原文查条目取 resolverId。
310
+ */
311
+ lookupResolverId?: (rawChip: string) => string | undefined;
312
+ }
313
+ /**
314
+ * 统一展开出口。resolve 结果直接替换 chip 原文(resolver 自行负责围栏块包裹——收编的
315
+ * 内置 resolver 保留既有 `fenced()` 行为,插件 resolver 的输出经 truncate 后原样注入,
316
+ * 提示注入防护由 `input.resolver` capability 高危信任门承担,RFC-210 D3)。
317
+ */
318
+ declare function expandSigilChips(text: string, registry: SigilResolverRegistry, ctx: {
319
+ workspaceDir: string;
320
+ }, opts?: ExpandSigilChipsOptions): Promise<string>;
321
+ //#endregion
322
+ //#region src/session/model-resolver.d.ts
323
+ interface ModelResolverDeps {
324
+ settings: SettingsManager;
325
+ getModelRegistry: () => ModelRegistry;
326
+ defaultModel?: Model;
327
+ /** createApp({ modelId }) 在插件 provider 装载前可能尚未解析——start() 后由 tryResolve 补全。 */
328
+ explicitModelSpec?: ModelSpec;
329
+ /**
330
+ * provider 是否已认证(有凭证)——用于「配置模型不可用」时挑**可用**回退模型,而非 getAll()[0]
331
+ * (后者可能是未认证 provider 的模型,如 github-copilot 未登录)。缺省时退回 getAll()[0]。
332
+ */
333
+ hasCredential?: (provider: string) => Promise<boolean>;
334
+ /**
335
+ * 模型可用性安全闸。逐候选过此闸,拒绝未认证 / OAuth-429 风险的模型。
336
+ * 由 App 用 `createModelUsabilityGate(authStore)` 注入;缺省时退回 hasCredential-only 判定。
337
+ */
338
+ isModelUsable?: IsModelUsable;
339
+ /** 模型决策溯源日志(debug)——记录每次委派选了哪个模型、哪层决定、拒了谁。 */
340
+ logger?: Pick<Logger, 'debug'>;
341
+ }
342
+ //#endregion
343
+ //#region src/session/types.d.ts
344
+ /**
345
+ * coding 层自己的会话选项扩展,补齐 runtime 剔除的编码策略 carrier 字段
346
+ * (promptPreset / promptContext / slot)。runtime 的 AgentSession 从未消费这些字段;
347
+ * 它们仅在本 resolver 与 task-runner 之间传递——定义在此而非污染 runtime 类型。
348
+ *
349
+ * RFC-211 M1:从 session-config-resolver.ts 移出为公共契约类型(被 app/ 6 处消费,
350
+ * 不该定义在私有实现文件里)。`session-config-resolver.ts` 通过
351
+ * `export type { CodingSessionOptions } from './types'` 保持原有 import 路径向后兼容。
352
+ */
353
+ interface CodingSessionOptions extends Partial<AgentSessionOptions$1> {
354
+ promptPreset?: PromptPreset;
355
+ slot?: WorkflowSlot;
356
+ promptContext?: SubAgentPromptContext;
357
+ /** 显式模型 id(如 subagent 按能力选型)——优先于 slot,由 registry 解析为 Model。 */
358
+ modelId?: string;
359
+ /**
360
+ * 任务类别(task_delegate.category,如 search/quick/deep/critique/review)——
361
+ * 委派子会话据此走内置 category→slot 智能默认(search→flash/deep→pro),插于 slot 与 default 之间。
362
+ */
363
+ category?: string;
364
+ /**
365
+ * 本会话是否为委派/子代理(由 task-runner 注入 true)。决定是否对模型选择启用 usability
366
+ * gate + category 智能默认。主会话不设此项 → 尊重显式/配置模型原样(非目标)。
367
+ * 与 promptPreset==='subagent' 取或:覆盖「有 category 但无 agentName」的 main-preset 委派。
368
+ */
369
+ delegated?: boolean;
370
+ /**
371
+ * Phase 0(task_delegate/job 统一):只读子会话——从工具集剔除 READONLY_DENIED_TOOLS(文件改动工具)。
372
+ * 由 task_delegate(background) 经 task-runner 注入;改动型后台活走 /job(worktree 隔离 + diff 审计)。
373
+ * 详见 docs/design/task-delegate-job-unification.md。
374
+ */
375
+ readOnly?: boolean;
376
+ }
377
+ //#endregion
378
+ //#region src/session/session-config-resolver.d.ts
379
+ interface SessionConfigResolverDeps extends ModelResolverDeps {
380
+ promptManager: PromptManager;
381
+ /** app.tools 派生自 toolRegistry + defaultToolPreset(热更新可变)。 */
382
+ getTools: () => AgentTool[];
383
+ /** 声明式 agent 在 start() 才发现,getter 注入运行时状态。 */
384
+ getDeclarativeAgentProfiles: () => AgentProfile[];
385
+ /** app 级缺省 maxToolTurns 兜底。 */
386
+ maxToolTurns: number;
387
+ /** app 级缺省 maxToolTurnExtensions 兜底(createApp / CLI --max-tool-turn-extensions)。
388
+ * 未设时不强制,留给 depth/transient 缺省策略(defaultMaxToolTurnExtensions)兜底。 */
389
+ maxToolTurnExtensions?: number;
390
+ /** RFC-104 D3:app 级缺省 per-prompt output-token 预算(createApp / CLI --prompt-token-budget)。 */
391
+ promptOutputTokenBudget?: number;
392
+ /** RFC-104 D3:app 级缺省 per-prompt 墙钟预算 ms(createApp / CLI --prompt-time-budget)。 */
393
+ promptWallClockBudgetMs?: number;
394
+ /** RFC-204 D1/D3:app 级缺省会话成本软预算美元(createApp / CLI --session-cost-budget)。 */
395
+ sessionCostBudgetUSD?: number;
396
+ /** RFC-204 D4:app 级缺省早期停滞检测配置(createApp / CLI --no-stall-detection 等)。 */
397
+ stallDetection?: {
398
+ windowTurns?: number;
399
+ repeatThreshold?: number;
400
+ } | false;
401
+ workspaceDir: string;
402
+ /**
403
+ * workspace 逻辑标识(workspaceRef.id)——惰性 getter(而非静态字段)。
404
+ * 修复:`workspaceRef` 在 `App.start()` 才异步解析完成,而本 resolver 在 App 构造期
405
+ * 就已经 new 出来;若用静态字段在构造期固化,常规启动(无 `--id`)下该值永远是
406
+ * `undefined`(`workspaceRef.id` 解析完成后从未回填),导致会话 `workspaceId` 元数据
407
+ * 恒缺失、`/resume --workspace <id>` 过滤对内存态会话形同虚设。传 getter 即可在
408
+ * 每次 resolve() 时读到 `workspaceRef` 就绪后的真实 id(与 `getModelRegistry`/
409
+ * `getDeclarativeAgentProfiles` 同一惰性注入模式)。
410
+ */
411
+ getWorkspaceId?: () => string | undefined;
412
+ /**
413
+ * RFC-230:统一重试/超时/退避配置查询——惰性 getter(同 `getWorkspaceId` 模式),不让本
414
+ * resolver 直接依赖 `App` 类型(保持依赖方向:resolver 是被 App 组装的下游)。`resolve()`
415
+ * 在会话创建时被调用,此时 App 必然已 `start()`(`ensureSettingsLoaded()` 已完成),
416
+ * getter 调用安全。未注入时 `streamRetry`/`networkDisconnectRetry` 保持 undefined,
417
+ * runtime/agent 层各自回退到内部默认常量。
418
+ */
419
+ getResilienceConfig?: () => _$_x_otto_env0.ResilienceConfig;
420
+ /** 模型决策溯源日志(debug)——记录每次委派选了哪个模型、哪层决定、拒了谁。 */
421
+ logger?: Pick<Logger, 'debug'>;
422
+ /**
423
+ * RFC-181 D3/M3:图像委托描述端口(App 用 VisionDelegateService.describeImages 注入)。
424
+ * 缺省时会话按 M1 占位分支运行(主模型不支持视觉 → image block 降级为占位文本)。
425
+ */
426
+ describeImages?: DescribeImagesPort;
427
+ }
428
+ /**
429
+ * RFC-211 M1:session-config-resolver.ts 从 637 行拆分为薄编排层——模型选型下沉
430
+ * `ModelResolver`(model-resolver.ts)、工具解析下沉自由函数(tool-resolver.ts)、
431
+ * 公共类型下沉 `session/types.ts`。本类只保留 `readAgentSources`(模型选型与工具
432
+ * 解析共同的输入源,两块共同消费)与 `resolve()` 主流程编排。
433
+ *
434
+ * 纯搬迁纪律:拆分不改变任何字段优先级链、模型/工具解析结果,端到端行为逐字节保留。
435
+ */
436
+ declare class SessionConfigResolver {
437
+ private readonly deps;
438
+ private readonly modelResolver;
439
+ constructor(deps: SessionConfigResolverDeps);
440
+ private readAgentSources;
441
+ /**
442
+ * RFC-150 D2:活 session 工具重同步入口——供 `SessionToolsSyncCoordinator` 在 MCP 工具
443
+ * 变化(连接完成/断开)或 `/reload` 后,对声明式解析(无 `options.tools` 显式覆盖)的
444
+ * 活 session 重新计算工具集。委托 tool-resolver.ts 的自由函数,`readAgentSources` 在
445
+ * 此计算后传入(RFC-211 M1 拆分后的签名变化,见 tool-resolver.ts 注释)。
446
+ */
447
+ /**
448
+ * 持久化推理投入档解析(校验 + 迁移,与交互式 interactive-session-setup.ts 同规则):
449
+ * `minimal`(存量 Claude Code 最低档)迁移为 `low`;其余非法值忽略(返回 undefined →
450
+ * 调用方回退 'medium')。顶层会话据此尊重 settings.thinking_level,headless 与交互式统一。
451
+ */
452
+ private resolvePersistedThinkingLevel;
453
+ resolveToolsForResync(agentName: string | undefined, promptPreset: 'main' | 'subagent' | undefined, readOnly: boolean | undefined): AgentTool[];
454
+ resolveTools(explicitTools: AgentTool[] | undefined, agentToolNames: string[] | undefined, disallowedToolNames?: string[], allowSubagents?: boolean): AgentTool[];
455
+ /**
456
+ * ── Layer 3: Session config assembler ────────────────────────────────────
457
+ *
458
+ * 优先级(高 → 低):
459
+ * model: options.model > slot(model_slots) > settings.model > defaultModel
460
+ * slot: options.slot > agentConfig.slot > agentProfile.tier → slot
461
+ * tools: options.tools > agentConfig.tools 过滤 > agentProfile.tools 过滤 > 全量
462
+ * systemPrompt: options.systemPrompt/agent.systemPrompt append 到 base 之后(RFC-353 S1)
463
+ * maxToolTurns: options.maxToolTurns > agentConfig > agentProfile > App.maxToolTurns
464
+ * maxToolTurnExtensions:
465
+ * options > agentConfig.max_tool_turn_extensions > agentProfile.defaultMaxToolTurnExtensions
466
+ * > App.maxToolTurnExtensions > 缺省策略(depth>0||transient ? 0 : 3)
467
+ */
468
+ resolve(options: CodingSessionOptions): Promise<ResolvedSessionConfig & {
469
+ id?: string;
470
+ }>;
471
+ }
472
+ //#endregion
473
+ //#region src/hooks/agent-job-notification.d.ts
474
+ interface AgentJobNotification {
475
+ jobId: string;
476
+ title: string;
477
+ status: 'ready' | 'failed' | 'canceled';
478
+ /** 一句话摘要(diff 概况 / 失败原因)。 */
479
+ summary?: string;
480
+ /** 转录输出文件路径——供模型读全量输出(R2,对照 CC OUTPUT_FILE_TAG)。 */
481
+ outputPath?: string;
482
+ /** worktree 路径/分支——供模型定位作业产物去 review/apply(R2,对照 CC WORKTREE_TAG)。 */
483
+ worktree?: {
484
+ path: string;
485
+ branch?: string;
486
+ };
487
+ }
488
+ //#endregion
489
+ //#region src/app/applied-diff-store.d.ts
490
+ /** appliedDiffs 持久化存储接口(同步,简单文件系统实现)。 */
491
+ interface AppliedDiffStore {
492
+ save(jobId: string, diff: string): void;
493
+ load(jobId: string): string | undefined;
494
+ delete(jobId: string): void;
495
+ loadAll(): Array<{
496
+ jobId: string;
497
+ diff: string;
498
+ }>;
499
+ }
500
+ //#endregion
501
+ //#region src/app/agent-job-service.d.ts
502
+ /** Codex cloud-tasks 式应用结果(success/partial/error + 冲突/跳过路径)。 */
503
+ interface ApplyOutcome {
504
+ applied: boolean;
505
+ status: 'success' | 'partial' | 'error';
506
+ message: string;
507
+ conflictPaths: string[];
508
+ /** 该改动触及的治理禁区文件(空=未触)。手动 apply 仅警示;自主层须强制 L0。 */
509
+ forbiddenZone?: string[];
510
+ /** 该改动是否触及能力面(MCP/provider/声明式 agent)→ apply 后应热重载。 */
511
+ capabilityTouched?: boolean;
512
+ /**
513
+ * 主仓 HEAD 自 worktree 建立后是否已前进(review J6,提示性——真正的冲突判定仍是
514
+ * `applyDiff` 的 `git apply --check`)。冲突/apply 失败时附带此信号,帮助用户理解成因
515
+ * ("因为主仓在此期间被改过",而非 diff 本身有问题)。
516
+ */
517
+ repoDrifted?: boolean;
518
+ }
519
+ /** 一个 detached run 句柄(spawnDetachedRun 的子集;DI 便于测试)。promise 解析值带 `text`(没改文件时作结果摘要)。 */
520
+ interface JobRunHandle {
521
+ promise: Promise<unknown>;
522
+ abort(): void;
523
+ /** 向运行中的作业注入一条 user 消息("进 delegate 补充信息")。 */
524
+ steer?(text: string): void;
525
+ outputPath: string;
526
+ }
527
+ interface AgentJobServiceDeps {
528
+ /** 主仓根(worktree 的源 + apply 目标)。 */
529
+ repoRoot: string;
530
+ registry: AgentJobRegistry;
531
+ /** 完成通知注入(agent-job-notification 桥的 notify)。 */
532
+ notify: (sessionId: string, n: AgentJobNotification) => void;
533
+ /**
534
+ * 起一个 detached run,工具 root 在 workspaceDir(= worktree 路径,实现隔离)。
535
+ * app 层实现 = 构造 worktree-rooted 工具 + spawnDetachedRun。
536
+ */
537
+ spawnRun: (input: {
538
+ runId: string;
539
+ prompt: string;
540
+ outputPath: string;
541
+ workspaceDir: string; /** 作业撞到"需确认"挂起时回调(→ 置 needs_input)。 */
542
+ onAwaitingInput?: (reason: string) => void;
543
+ }) => JobRunHandle;
544
+ /** 作业转录文件路径(默认 tmp/job-<id>.log;注入便于测试)。 */
545
+ buildOutputPath: (jobId: string) => string;
546
+ /** 生成作业 id。 */
547
+ newJobId: () => string;
548
+ /** appliedDiffs 持久化存储(可选注入,未注入则纯内存)。 */
549
+ appliedDiffStore?: AppliedDiffStore;
550
+ /**
551
+ * worktree 清理失败上报(review J4,可选注入)。覆盖本服务直接调用的两处 removeWorktree
552
+ * (spawnRun 同步抛出的孤儿清理 + 显式 cleanupAgentJob);AgentJobRegistry 内部的
553
+ * removeWorktree 调用点另有独立注入(见 agent-job-registry.ts 的 onWorktreeCleanupError)。
554
+ */
555
+ onWorktreeCleanupError?: (op: 'worktree remove' | 'branch delete' | 'worktree prune', err: unknown) => void;
556
+ }
557
+ interface StartAgentJobInput {
558
+ title: string;
559
+ prompt: string;
560
+ sessionId: string;
561
+ /** 来源(缺省 user):user = 用户 /delegate;main = 主对话/模型起的(面板分组);
562
+ * plugin = 插件经 agent.dispatch 自主发起(RFC-287 R2,apply 永远走人手闸)。 */
563
+ origin?: 'user' | 'main' | 'plugin';
564
+ }
565
+ declare class AgentJobService {
566
+ private readonly deps;
567
+ private readonly ownedJobIds;
568
+ private readonly handles;
569
+ private readonly appliedDiffs;
570
+ constructor(deps: AgentJobServiceDeps);
571
+ /** 起一个 agent-session 作业(后台跑,立即返回作业记录)。 */
572
+ start(input: StartAgentJobInput): AgentSessionJob$1;
573
+ /**
574
+ * 向一个**运行中**的作业补充信息(进 delegate 对话)——经 Agent.steer 注入 user 消息,
575
+ * 作业下一个工具回合采纳。返回是否送达(作业不存在/已终态/句柄无 steer → false)。
576
+ */
577
+ supply(jobId: string, text: string): boolean;
578
+ /**
579
+ * App 级收尾:取消本服务起的、仍在跑的作业(abort detached run + removeWorktree)。
580
+ * registry.cancel 对已终态/已移除作业幂等 no-op,故无需剔除已完成 id。只动自己 owned 的,
581
+ * 不像 globalProcessRegistry.killAll 那样越界杀兄弟 App 的作业。
582
+ */
583
+ dispose(): void;
584
+ private onRunComplete;
585
+ private onRunFailed;
586
+ /** 把作业产物 apply 到主仓(带冲突检测;冲突不强改)。 */
587
+ apply(jobId: string): ApplyOutcome;
588
+ /**
589
+ * 撤销一次已 apply 的作业改动(反向 diff,check-first 不强撤)。
590
+ * 工作树自 apply 后漂移 → 返回 partial + 冲突路径,不强撤。撤成则该 diff 不再可 revert。
591
+ * 用 service 自存的 appliedDiffs(独立于注册表),故 applied 作业被驱逐后仍可撤。
592
+ */
593
+ revert(jobId: string): ApplyOutcome;
594
+ /** 取消作业(abort run + 清 worktree)。 */
595
+ cancel(jobId: string): void;
596
+ }
597
+ //#endregion
598
+ //#region src/hooks/tool-guidance.d.ts
599
+ declare function createToolGuidanceHook(toolRegistry: ToolRegistry, getPreset: () => 'minimal' | 'standard' | 'full'): HookSpec;
600
+ //#endregion
601
+ //#region src/hooks/lesson-injection.d.ts
602
+ /**
603
+ * `localLearningStore`(RFC-164 M164-1 D3):机器特定经验(scope='local')的独立 store。
604
+ *
605
+ * RFC-284 T2c 起,workspace lessons 优先由 T2b Core Pack artifact 注入,避免全量 150+
606
+ * 条原始 lesson 进入 stable prefix;若 artifact 尚未生成,则回退 legacy 全量注入以保持兼容。
607
+ * local pack 仍待后续里程碑落地,因此 local lessons 暂保留为独立 legacy block,不与可提交
608
+ * workspace pack 混合,避免破坏 RFC-164 local-only 语义。
609
+ */
610
+ declare function createLessonInjectionHooks(learningStore: OperationalLearningStore, promptManager: PromptManager, localLearningStore?: OperationalLearningStore): HookSpec[];
611
+ //#endregion
612
+ //#region src/hooks/skill-catalog-injection.d.ts
613
+ declare function createSkillCatalogInjectionHooks(registry: SkillRegistry): HookSpec[];
614
+ //#endregion
615
+ //#region src/hooks/session-learning.d.ts
616
+ /** RFC-036 编排器的最小结构契约(`createMemoryAutoExtractor` 的返回值即满足)。 */
617
+ interface MemoryAutoExtractor {
618
+ onIdle: (sessionId: string, messages: readonly Message[]) => Promise<unknown>;
619
+ reset: (sessionId: string) => void;
620
+ }
621
+ //#endregion
622
+ //#region src/skill-loop/candidate-reader.d.ts
623
+ /**
624
+ * 对外投影:**只有这些字段能离开本模块**。
625
+ * 即便插件在文件里塞了额外字段,zod 的 strip 行为加上本类型都保证它出不来。
626
+ */
627
+ interface CandidateBrief {
628
+ id: string;
629
+ taskSignature: string;
630
+ tags: string[];
631
+ sessionIds: string[];
632
+ size: number;
633
+ firstAt: number;
634
+ lastAt: number;
635
+ /** 用户拒绝时刻(冷却判定用;不进简报文本)。 */
636
+ dismissedAt?: number;
637
+ }
638
+ //#endregion
639
+ //#region src/hooks/skill-loop.d.ts
640
+ /**
641
+ * 归纳器插件 id —— **取自薄读取器的白名单**,不自己写字面量。
642
+ * 两处各写一份的话,改了白名单没改这里 = 通知发给 A、读候选读 B,静默失效。
643
+ */
644
+ declare const INDUCTOR_PLUGIN_ID: string;
645
+ /**
646
+ * workspaceRef 未就位时的兜底 —— **单源自 `@x-otto/workspace`**(同插件侧 storageDir 的兜底,
647
+ * 见 `plugin-module-manager.ts:57`)。读侧与写侧兜底必须同值,否则 workspaceRef 未就位时
648
+ * 读取器会去翻一个插件从没写过的目录。
649
+ */
650
+ declare const DEFAULT_WORKSPACE_KEY = "default";
651
+ //#endregion
652
+ //#region src/hooks/sandbox-guard.d.ts
653
+ /** ask 决策原因的哨兵前缀:cli 据此识别沙箱升级批准 → 记命令 bypass(M4 1b-2)。 */
654
+ declare const SANDBOX_ESCALATION_MARKER = "[sandbox-escalation]";
655
+ //#endregion
656
+ //#region src/session/task-runner.d.ts
657
+ interface TaskRunnerDeps {
658
+ logger: Logger;
659
+ getSession: (id: string) => AgentSession$1 | undefined;
660
+ createSession: (options: CodingSessionOptions) => Promise<AgentSession$1>;
661
+ removeSession: (id: string) => Promise<boolean>;
662
+ }
663
+ interface TaskRunner {
664
+ /**
665
+ * Orchestrator.runSession 注入体:创建/复用子会话 → prompt → 提取输出文本。
666
+ * 入参用 orchestrator 的单源契约 `RunSessionOptions`。
667
+ */
668
+ runSession: (options: RunSessionOptions) => Promise<{
669
+ text: string;
670
+ sessionId: string;
671
+ durationMs: number;
672
+ }>;
673
+ /** cancel → 中止任务(updateTask cancel / background cancel 同语义)。 */
674
+ abortTask: (taskId: string) => void;
675
+ }
676
+ declare function createTaskRunner(deps: TaskRunnerDeps): TaskRunner;
677
+ //#endregion
678
+ //#region src/agent/declarative-teams.d.ts
679
+ interface TeamRouteRule {
680
+ keywords: string[];
681
+ agentId: string;
682
+ }
683
+ interface TeamDeclaration {
684
+ name: string;
685
+ pattern: OrchestrationPattern;
686
+ /**
687
+ * 成员标识(解析为 SwarmAgentDef 由 app 负责)。
688
+ * M16e:成员可为 agent 名,或 `team:<子团队名>` 嵌套引用(原样保留,resolveTeam 判前缀递归)。
689
+ */
690
+ agentNames: string[];
691
+ pipeline?: string[];
692
+ supervisorId?: string;
693
+ entryAgentId?: string;
694
+ routerStrategy?: string;
695
+ /** M16e:声明式路由规则(router:rule 时接入 swarm RouterConfig.rules)。 */
696
+ rules?: TeamRouteRule[];
697
+ maxHandoffDepth?: number;
698
+ }
699
+ //#endregion
700
+ //#region src/agent/swarm-runtime.d.ts
701
+ type RunTeam = (team: string, input: string, signal?: AbortSignal, depth?: number) => Promise<{
702
+ success: boolean;
703
+ output?: string;
704
+ pattern?: string;
705
+ error?: string;
706
+ }>;
707
+ //#endregion
708
+ //#region src/app/model-catalog-manager.d.ts
709
+ /** refresh() 每个 provider 的结果。`skipped`/`failed` 绝不抛——回退静态/缓存。 */
710
+ interface ModelRefreshResult {
711
+ provider: string;
712
+ status: 'ok' | 'skipped' | 'failed';
713
+ added?: number;
714
+ kept?: number;
715
+ total?: number;
716
+ availableIds?: string[];
717
+ reason?: string;
718
+ }
719
+ declare class ModelCatalogManager {
720
+ private readonly modelRegistry;
721
+ private readonly authStore;
722
+ /** 实时拉取的模型列表落盘缓存(每次启动 hydrate + 刷新后写回)。 */
723
+ private readonly catalog;
724
+ /** 每个 mergeProvider 我们派生注册过的 model id(refresh 时剪掉已下线的,不碰静态种子)。 */
725
+ private readonly derivedModelIds;
726
+ constructor(modelRegistry: ModelRegistry, authStore: AuthStore, /** 可注入(测试用);默认真实落盘 store。 */
727
+
728
+ catalog?: ModelCatalogStore);
729
+ /**
730
+ * 启动时把上次落盘的模型缓存并回 registry(瞬时、离线可用)。返回缓存确认「账号可用」的 id 集合。
731
+ * 内置 JSON 仅作派生模板(种子),真实列表来自此缓存 / 随后的后台 refresh。
732
+ */
733
+ hydrate(): Promise<Set<string>>;
734
+ /**
735
+ * `refresh()` 并发去重(RFC-136 D1):飞书 `/model refresh` 是多用户群聊场景下可被
736
+ * 并发触发的入口,同一时刻只允许一次真实刷新在途——后到的调用直接复用同一个 Promise,
737
+ * 不重复发起网络请求,也避免 `derivedModelIds`/`ModelRegistry` 的并发写入竞态。
738
+ */
739
+ private refreshInFlight;
740
+ /**
741
+ * 从各**已认证 provider** 的 models 端点实时拉取可用模型并并入 registry + 落盘缓存。
742
+ * 按鉴权 provider(openai-codex/github-copilot/…)解析端点+头+并入目标——凭据 id ≠ 模型 provider。
743
+ * 未认证/无端点→skipped;拉取失败→failed(绝不抛,回退静态/缓存);成功→并入、缓存、回报 availableIds。
744
+ *
745
+ * 并发调用天然去重(见 `refreshInFlight`)——单发调用行为/返回值/错误语义不变。
746
+ */
747
+ refresh(): Promise<ModelRefreshResult[]>;
748
+ private doRefresh;
749
+ }
750
+ //#endregion
751
+ //#region src/session/session-tools-sync.d.ts
752
+ /** 单个 session 的重同步上下文——`resolveToolsForResync()` 的最小必要输入。 */
753
+ interface ResyncContext {
754
+ agentName: string | undefined;
755
+ promptPreset: 'main' | 'subagent' | undefined;
756
+ readOnly: boolean | undefined;
757
+ }
758
+ interface SessionToolsSyncCoordinatorDeps {
759
+ sessionConfigResolver: SessionConfigResolver;
760
+ /** 按 id 取活 session 实例(`App.getSession`/`SessionFacade.getSession`)。 */
761
+ getSession: (id: string) => AgentSession$1 | undefined;
762
+ /** 列出当前全部活 session id(`SessionPool.listSessions()` 的投影已足够,只取 id)。 */
763
+ listSessionIds: () => string[];
764
+ logger: Logger;
765
+ }
766
+ declare class SessionToolsSyncCoordinator {
767
+ private readonly deps;
768
+ private readonly contexts;
769
+ constructor(deps: SessionToolsSyncCoordinatorDeps);
770
+ /**
771
+ * 会话创建后调用——记录重同步所需的最小上下文。
772
+ * `hasExplicitTools=true`(调用方在 `CodingSessionOptions.tools` 显式传了固定工具集)时
773
+ * 不记录,该会话永不参与后续的全局工具重同步(规则 2)。
774
+ */
775
+ record(sessionId: string, ctx: ResyncContext & {
776
+ hasExplicitTools: boolean;
777
+ }): void;
778
+ /** session 销毁时调用,避免协调器持有失效 id。 */
779
+ forget(sessionId: string): void;
780
+ /**
781
+ * 对单个已记录 session 重算工具集(RFC-130 M131-2:`/model` 切换后 session.model 已变但
782
+ * tools 仍是创建时快照——须按新 model.supportsTools 刷新,否则 catalog-only 模型仍带 tools
783
+ * 进 provider 抛 CURSOR_TOOLS_NOT_SUPPORTED)。
784
+ */
785
+ resyncOne(sessionId: string): boolean;
786
+ /**
787
+ * 对全部已记录且仍存活的 session 重新计算工具集并整体替换 `session.tools` 引用。
788
+ * fail-soft:单个 session 重算失败不影响其余 session(记录 warn,不抛出——本身是
789
+ * 后台被动触发的同步动作,不应因一个 session 的边缘错误打断整体)。
790
+ *
791
+ * 返回实际完成重同步的 session 数(供调用方 toast/日志展示)。
792
+ */
793
+ resync(): number;
794
+ private resyncSession;
795
+ }
796
+ //#endregion
797
+ //#region src/types.d.ts
798
+ /**
799
+ * 存储宿主绑定:service 的 /api/storage 路由据此服务 RemotePersistence 客户端。
800
+ * token 为 Bearer 鉴权必选项(fail-closed:未配置宿主 404、token 不匹配 403)。
801
+ */
802
+ interface StorageHostBinding {
803
+ host: StorageHost;
804
+ token: string;
805
+ }
806
+ /**
807
+ * RFC-118 S1:存储/记忆集群分组(原 App 6 个独立 readonly 顶层字段,均由
808
+ * `buildStorageAndMemory()` 一次性装配产出——分组反映真实装配边界,不是为分组而分组)。
809
+ * 消费方从 `app.traceStore` 等顶层访问改为 `app.storage.traceStore`。
810
+ */
811
+ interface AppStorage {
812
+ readonly storageHost: StorageHostBinding | null;
813
+ readonly autoMemory: AutoMemory | null;
814
+ readonly memory?: MemorySubsystem;
815
+ readonly traceStore: AppendLog<TraceEvent>;
816
+ /** L3:trace 内存实时旁路——live 观测者订阅此拿实时 append,不绕磁盘 tail。 */
817
+ readonly traceLive: LiveTap<TraceEvent>;
818
+ readonly checkpointStore: AppendLog<CheckpointData$1>;
819
+ /**
820
+ * RFC-164 M164-2:是否配置了远端 memory 连接(`storage.remote.getAuth` + `storage.session.url`
821
+ * 均已提供,`buildMemoryStore` 因此构造了 `HttpMemoryStore`)。**与 `WorkspaceRef.backend`
822
+ * 无关**——后者描述 workspace *身份*是否绑定远端 workspace 服务(committed marker + 信任门,
823
+ * 团队协作场景),本字段描述的是"是否存在可连接的远端 memory 服务"这一独立技术前提。
824
+ * `/workspace memory-sync enable` 据此判断是否有意义(无此前提时 opt-in 写入 marker 但
825
+ * 静默无效果,R5 降级哲学)。
826
+ */
827
+ readonly remoteMemoryConfigured: boolean;
828
+ /**
829
+ * RFC-169 D3/重要事项规则 6:是否配置了远端 session(`--session-url`,`storage.session.url`
830
+ * 已提供)。语义比 `remoteMemoryConfigured` 更窄——只判断 session URL 是否配置,不要求
831
+ * `storage.remote.getAuth` 同时存在(schedule 只需要知道"走 file 还是走 http",不涉及
832
+ * memory 域的鉴权组合判断)。`setupScheduleService` 据此在本地 `createScheduleStore`/
833
+ * `createLocalFireOwnership` 与远程 `RemoteScheduleStore`/远程 `FireOwnership` 之间切换,
834
+ * 复用 session 现有的 `--session-url` 开关,不新增独立 schedule 专属 CLI flag。
835
+ */
836
+ readonly remoteSessionConfigured: boolean;
837
+ }
838
+ /**
839
+ * ServiceHostPort(RFC-074 R-SVCPORT):`@x-otto/service` 真正依赖的**窄宿主端口**——
840
+ * 仅 service 路由实际访问的 ~15 个 App 成员。service 此前 typed against 整个 `AppContext`
841
+ * (~28 成员,且被加宽来喂 service),把"App 全貌"与"service 所需"耦死。抽窄后 service
842
+ * 只看见它真用的面,App 经 `AppContext extends ServiceHostPort` 自动满足(零 app.ts 改动)。
843
+ * 新增 service 依赖必须显式登记到本端口(不再隐式从 AppContext 漏入)。
844
+ */
845
+ interface ServiceHostPort {
846
+ readonly workspaceDir: string;
847
+ /** RFC-148 M2:`modelRegistry` 类实例收窄为窄方法——service 只用 getAll/resolve。 */
848
+ getAllModels(): Model[];
849
+ resolveModel(spec: ModelSpec): Model;
850
+ /** RFC-148 M2:`providerRegistry` 类实例收窄为窄方法——service 只用 list。 */
851
+ listProviders(): Api[];
852
+ /** RFC-148 M2:`hookRegistry` 类实例收窄为窄方法——service 只用 register/unregister。 */
853
+ registerHook(spec: HookSpec): void;
854
+ unregisterHook(name: string): boolean;
855
+ readonly sessionManager: SessionPool;
856
+ readonly devtools: Devtools | null;
857
+ /** RFC-118 S1:存储/记忆集群分组(traceStore/storageHost/traceLive/checkpointStore/memory/autoMemory)。 */
858
+ readonly storage: AppStorage;
859
+ /** 扩展启停管理面(mcp/skill/agent/plugin bundle),供 service catalog 路由暴露。 */
860
+ readonly extensions: ExtensionManager;
861
+ /** #/@ sigil 条目注册表,供 service sigil 搜索路由暴露。 */
862
+ readonly pluginInput: PluginInputRegistry$2;
863
+ /**
864
+ * RFC-210 D7:@ 资源统一展开出口(提交时 chip → 实际内容),供 service expand 端点
865
+ * 暴露给非 TUI 前端。service 调用时须传 `{ uiHost: false }`——uiHostOnly resolver
866
+ * (@clipboard 这类读"UI 所在机器"本地资源的)跳过执行原样保留(信任边界,评审 B11)。
867
+ */
868
+ expandSigilChips(text: string, opts?: {
869
+ skipPrefixes?: ReadonlySet<string>;
870
+ uiHost?: boolean;
871
+ maxOutput?: number;
872
+ }): Promise<string>;
873
+ /**
874
+ * RFC-210 D5(M4):跨端渲染 toPayload 执行出口——对一条消息跑首个 matcher 命中的
875
+ * `ui.renderer` 插件贡献,产出 a2ui 组件树(JSON 数据);无命中/全部 fail-soft → null。
876
+ * 消费方:service EventBridge(消息下发前附加 a2ui block);TUI 侧宿主进程内直调。
877
+ */
878
+ resolveA2uiRendererPayload(message: unknown): Promise<_$_x_otto_interchange0.A2uiComponent[] | null>;
879
+ /**
880
+ * 当前活跃插件(应用 disabled_plugins),供 catalog 命令目录按 disabled 过滤。
881
+ * RFC-132 D3:返回值经拓扑排序(被依赖者排在依赖者之前),非 discoverPlugins 原始字母序;
882
+ * 无 dependsOn 声明的插件集合退化为字母序(向后兼容)。成环/缺失依赖的插件已被 fail-closed
883
+ * 剔除,不出现在返回值中。
884
+ */
885
+ activePlugins(): DiscoveredPlugin$1[];
886
+ /** 文件命令目录(otto/claude/插件三源,按信任+disabled 过滤)。供 service catalog 路由,
887
+ * 使 service 不必从 @x-otto/coding 直接 import discoverFileCommands 值(端口收口)。 */
888
+ listFileCommands(): FileCommand$1[];
889
+ /**
890
+ * RFC-105 D10/M105-8:插件贡献契约的 web-ui 消费面——状态栏条目/全局菜单/消息渲染器,
891
+ * 由 service catalog 路由暴露为 REST API,供 web-ui 客户端 fetch 渲染。
892
+ * 数据权威仍是 App(同 extensions/listFileCommands 模式,service 不持有副本)。
893
+ */
894
+ getPluginStatusItems(): Array<{
895
+ id: string;
896
+ text: string;
897
+ }>;
898
+ getGlobalMenuItems(): Array<{
899
+ id: string;
900
+ title: string;
901
+ command: {
902
+ type: string;
903
+ [key: string]: unknown;
904
+ };
905
+ }>;
906
+ getPluginRenderers(): Array<{
907
+ id: string;
908
+ pluginId: string;
909
+ matcher: {
910
+ role?: string;
911
+ toolName?: string;
912
+ contentType?: string;
913
+ };
914
+ }>;
915
+ /**
916
+ * RFC-206 M9 前置子任务②:插件状态栏代码式徽标 + 文件查看器候选,补齐 catalog 路由
917
+ * 新增的两个 REST 端点(`GET /plugin-status-widgets`/`GET /plugin-file-viewers`)。
918
+ *
919
+ * **只暴露可序列化的静态元数据,不含渲染函数本体**(执行期核实的真实架构约束,
920
+ * 已在 RFC-206 § 2.4 D8 记录:`RegisteredStatusWidget.render`/`RegisteredFileViewer.
921
+ * render` 是同步纯计算函数,依赖 TUI 特有的运行时上下文——`StatusWidgetContext` 含
922
+ * `providerUsage`/`columns` 等终端状态栏快照字段,`fileViewers` 的 render 签名含
923
+ * `columns` 终端列宽——这套"快照组装+安全调用+异常隔离+时长熔断"的执行面
924
+ * (`packages/tui/src/status-widget-registry.ts`)只存在于 `@x-otto/tui` 进程内,
925
+ * 函数本身无法跨 HTTP 边界序列化传输,service 也不具备重新实现这套 TUI 特有执行面
926
+ * 的正当性)。用途是"元数据展示"(如"这条消息有插件贡献的自定义渲染器可用"的提示),
927
+ * 不是真正在 web-ui 侧跑起来插件的渲染逻辑——与 `getPluginRenderers()` 的既有
928
+ * 元数据模式一致。
929
+ *
930
+ * 同步纪律(独立审核 P2 提醒):这两个内联窄类型是对 `RegisteredStatusWidget`/
931
+ * `RegisteredFileViewer`(`packages/coding/src/plugin/status-widget-loader.ts`/
932
+ * `file-viewer-loader.ts`)可序列化字段的手工镜像——若源类型未来新增其他可序列化
933
+ * 静态字段(非 render 函数),TypeScript 不会自动报错提醒同步,需要人工核对两处
934
+ * 定义是否仍然一致(已含 `order?: number`,与 `getPluginRenderers()` 同一模式)。
935
+ */
936
+ getPluginStatusWidgets(): Array<{
937
+ id: string;
938
+ pluginId: string;
939
+ tickMs?: number;
940
+ order?: number;
941
+ }>;
942
+ getPluginFileViewers(): Array<{
943
+ id: string;
944
+ pluginId: string;
945
+ label: string;
946
+ matcher: {
947
+ extensions?: string[];
948
+ filenames?: string[];
949
+ glob?: string[];
950
+ };
951
+ order?: number;
952
+ }>;
953
+ /**
954
+ * 调用 MCP server 上的指定 tool(RFC-081:供插件面板 usePluginData 使用,以及 catalog API)。
955
+ * @param serverName MCP server 名称(如 'plugin-browser-use')
956
+ * @param toolName 工具名(原始名,不带 mcp__ 前缀)
957
+ * @param params 工具参数
958
+ */
959
+ callMcpTool(serverName: string, toolName: string, params?: Record<string, unknown>): Promise<{
960
+ content: {
961
+ type: string;
962
+ text?: string;
963
+ }[];
964
+ isError?: boolean;
965
+ }>;
966
+ createSession(options?: CodingSessionOptions): Promise<AgentSession$1>;
967
+ getSession(id: string): AgentSession$1 | undefined;
968
+ getActiveSession(): AgentSession$1 | undefined;
969
+ listSessions(): AgentSessionInfo$1[];
970
+ /**
971
+ * RFC-233:用户自定义 `[@shortcut:name]` 文本快捷方式——TUI(进程内直调 App 同名方法)
972
+ * 与 web-ui(经 service catalog 路由 `/api/catalog/shortcuts`)共用同一套增删改逻辑
973
+ * 与校验规则,权威实现在 App,本接口只是窄方法转发(同 `listFileCommands` 端口收口
974
+ * 模式),service 不重新实现校验/持久化。
975
+ */
976
+ getShortcuts(): Array<{
977
+ name: string;
978
+ text: string;
979
+ }>;
980
+ /** 校验失败抛 `Error`(名称非法/重复、正文为空)——调用方决定如何呈现给用户。 */
981
+ saveShortcut(name: string, text: string, previousName?: string): Promise<void>;
982
+ deleteShortcut(name: string): Promise<void>;
983
+ /**
984
+ * RFC-209 §2.5/§3.1:Feedback 插件是否已装载(供 service catalog 路由的
985
+ * `GET /plugin-feedback/status` 判断,`feedbackRegistry.get()` 为 undefined 时
986
+ * 端点应返回 503 而非 500,见 RFC-209 §2.6 降级行为)。
987
+ */
988
+ isFeedbackAvailable(): boolean;
989
+ /**
990
+ * RFC-209 §2.5:满意度脉冲调查触发配置读取——窄方法封装(同 `listFileCommands` 端口
991
+ * 收口模式),service 的 `EventBridge` 不必直接依赖 `SettingsManager`/`Setting` 类型。
992
+ */
993
+ getPulseSurveyConfig(): {
994
+ enabled?: boolean;
995
+ probability?: number;
996
+ min_turn_gap?: number;
997
+ };
998
+ /**
999
+ * RFC-209 §2.5:满意度评分记录——web-ui 的 `POST /plugin-feedback/pulse-survey`
1000
+ * 端点调用,与 TUI 走同一个 `FeedbackRegistry`/同一个插件实现/同一份数据文件。
1001
+ * 插件未装载时静默丢弃(fail-soft,调用方应先检查 `isFeedbackAvailable()`)。
1002
+ */
1003
+ recordPulseSurvey(entry: _$_x_otto_plugin0.PulseSurveyEntry): void;
1004
+ /**
1005
+ * RFC-209 §2.5/重要事项规则7:两端共用的 issue URL 构造——**只允许调用本方法**,
1006
+ * 绝不暴露 `submitIssueViaGh`(gh CLI 通道仅供 TUI/CLI 本地进程调用,service 侧
1007
+ * 不持有该方法引用,物理上无法误调用)。插件未装载或未实现该方法时返回 undefined。
1008
+ */
1009
+ buildFeedbackIssueUrl(input: _$_x_otto_plugin0.FeedbackIssueInput): string | undefined;
1010
+ /**
1011
+ * RFC-348 M1:settings 写面经 ServiceHostPort 暴露——service 的 `PUT /api/setting`、
1012
+ * `POST /api/setting/mode`、`POST /api/setting/autonomy`、`POST /api/setting/thinking`
1013
+ * 四个端点调本方法,委托 `SettingsManager.update()` 持久化 + 触发 change 事件。
1014
+ *
1015
+ * 同 `getAllModels`/`resolveModel` 的窄方法范式:service 不直接持有 SettingsManager
1016
+ * 引用,经本端口透传。`overrides` 是 `Partial<Setting>`——调用方只传要改的字段。
1017
+ */
1018
+ updateSettings(overrides: Partial<_$_x_otto_setting0.Setting>): Promise<_$_x_otto_setting0.Setting>;
1019
+ }
1020
+ /**
1021
+ * RFC-172 M4/D4:会话归档导出结果。
1022
+ * 由 `App.exportSessionArchive()` 返回,供 CLI handler 消费。
1023
+ */
1024
+ interface SessionArchiveExport {
1025
+ /** 导出的 entry 总数(message + compaction)。 */
1026
+ entryCount: number;
1027
+ /** 导出文件的 sha256 hex(已通过读写校验验证一致)。 */
1028
+ checksum: string;
1029
+ /** 导出文件的绝对路径。 */
1030
+ path: string;
1031
+ }
1032
+ interface AppContext extends ServiceHostPort {
1033
+ readonly tools: AgentTool[];
1034
+ readonly settings: SettingsManager;
1035
+ readonly permissionRegistry: PermissionPolicyRegistry;
1036
+ readonly auditLog: PermissionAuditLog;
1037
+ readonly toolRegistry: ToolRegistry;
1038
+ readonly authStore: AuthStore;
1039
+ readonly logger: Logger;
1040
+ /** RFC-115:长驻进程内存自我感知(采样+分级+软降级/硬阈值回调晚绑定)。 */
1041
+ readonly memoryGovernor: MemoryGovernor;
1042
+ start(): Promise<void>;
1043
+ stop(): Promise<void>;
1044
+ removeSession(id: string): Promise<boolean>;
1045
+ forkSession(sourceId: string, newId?: string): Promise<AgentSession$1 | undefined>;
1046
+ /** 共享/私有一个会话(visibility 变更 → change_log → SSE broadcast)。 */
1047
+ shareSession(sessionId: string, opts: {
1048
+ visibility: 'private' | 'shared';
1049
+ }): Promise<void>;
1050
+ }
1051
+ interface AppOptions {
1052
+ /** true 时构建 Devtools 实例并转发匹配 logger.name 的结构化日志(app.ts:509 消费,非死字段)。 */
1053
+ inspect?: boolean;
1054
+ logger: {
1055
+ name: string;
1056
+ level: LogLevel;
1057
+ destination: string;
1058
+ };
1059
+ model?: Model;
1060
+ modelId?: string;
1061
+ modelRegistry?: ModelRegistry;
1062
+ authStore?: AuthStore;
1063
+ providerRegistry?: ProviderRegistry;
1064
+ hookRegistry?: HookRegistry;
1065
+ /**
1066
+ * RFC-230:统一重试/超时/退避配置的程序化注入入口(最高优先级,覆盖 settings/env/默认值)。
1067
+ * 经 `App.getResilienceConfig()` 只读查询实际生效值——该方法在 `ensureSettingsLoaded()`
1068
+ * 完成前调用会抛错(延迟冻结设计,见 RFC-230 §3 D5,settings 层需等配置文件加载完成才可用)。
1069
+ */
1070
+ resilience?: ResilienceConfigOverride;
1071
+ /** Agent 身份标识(可选。不填 = 单用户模式,向后兼容)。 */
1072
+ agentId?: string;
1073
+ /** 远端服务用户身份。提供时 session/memory/config 走 remote。 */
1074
+ userIdentity?: UserIdentity;
1075
+ workspaceDir?: string;
1076
+ /** 显式 workspace id(`--id` 覆盖,一目录多 workspace DevPod 模式)。 */
1077
+ workspaceId?: string;
1078
+ /**
1079
+ * 插件发现的 user-scope homedir 覆盖(缺省 = 真实 `os.homedir()`,生产行为不变)。
1080
+ * 供测试注入隔离路径——`discoverPlugins()` 的 user-scope 插件目录固定拼接自 homedir,
1081
+ * 若测试环境(本机)真实装有 user-scope 插件(如 `~/.otto/plugins/*`),断言"只应发现
1082
+ * 某个临时插件"的测试会被本机真实插件污染。测试注入独立临时目录即可隔离,不影响生产
1083
+ * (生产从不传此选项)。
1084
+ */
1085
+ pluginHomedir?: string;
1086
+ projectConfigPath?: string;
1087
+ /**
1088
+ * 是否交互(TUI)模式。缺省 false=headless(print/serve/sdk/测试)。
1089
+ * 项目配置信任门只在交互态生效——headless fail-open(对照 CC `--print` 跳过 securityCheck),
1090
+ * 保证脚本/CI/测试不被未信任仓库的高危键剔除或阻塞。
1091
+ */
1092
+ interactive?: boolean;
1093
+ /**
1094
+ * RFC-345:影子模式(零落盘会话)。缺省 false。
1095
+ *
1096
+ * 单一真源是 `@x-otto/env` 的 `isShadowModeEnabled()`(读 OTTO_SHADOW,受 §D1 白名单约束);
1097
+ * 本字段仅为 App 层显式感知提供入口(如 D5 可见性标识、D9 不参与 daemon 竞选),
1098
+ * 由 cli.ts 从同一 env 派生传入,二者恒一致。存储层的内存化选择不读本字段、
1099
+ * 而在白名单装配点直接查 `isShadowModeEnabled()`(避免开关有第二真源)。
1100
+ */
1101
+ shadow?: boolean;
1102
+ /**
1103
+ * 持久化分组配置:session/memory 各域选本地 dir 或 remote url;
1104
+ * host 开启本实例的存储服务端。缺省全内存(行为不变)。
1105
+ * archive 域已退场(session 派生视图,不再独立持久化)。
1106
+ */
1107
+ storage?: StorageOptions;
1108
+ maxSessions?: number;
1109
+ maxToolTurns?: number;
1110
+ /** app 级缺省「压缩续跑」扩展次数(CLI --max-tool-turn-extensions 透传)。未设时
1111
+ * 由会话层按 depth/transient 缺省(主会话 3 / 子 agent·瞬态 0)。 */
1112
+ maxToolTurnExtensions?: number;
1113
+ /** RFC-104 D3:app 级缺省 per-prompt 输出 token 预算(CLI --prompt-token-budget 透传)。 */
1114
+ promptOutputTokenBudget?: number;
1115
+ /** RFC-104 D3:app 级缺省 per-prompt 墙钟预算 ms(CLI --prompt-time-budget 换算后透传)。 */
1116
+ promptWallClockBudgetMs?: number;
1117
+ /** RFC-204 D1/D3:app 级缺省会话累计成本软预算美元(CLI --session-cost-budget 透传)。 */
1118
+ sessionCostBudgetUSD?: number;
1119
+ /** RFC-204 D4:app 级缺省早期停滞检测配置(CLI --no-stall-detection 等透传)。 */
1120
+ stallDetection?: {
1121
+ windowTurns?: number;
1122
+ repeatThreshold?: number;
1123
+ } | false;
1124
+ /** prompt 提供者配置,默认使用内置 prompts 目录 */
1125
+ prompt?: PromptProviderOptions;
1126
+ /**
1127
+ * skill 实现注入点(可选)。
1128
+ * 未提供时 skill 工具仍注册,但返回"功能未配置"提示。
1129
+ * 未来可注入基于 @x-otto/skill 的完整实现。
1130
+ */
1131
+ /**
1132
+ * 自动上下文管理器。注入后由引擎 pipeline 的 context-transform 阶段驱动
1133
+ * prune/compaction。未注入时 App 在已解析 model 的前提下用 stream-backed
1134
+ * summarize 构造默认 MemoryManager(生产默认开启循环内自动压缩)。
1135
+ */
1136
+ memory?: MemorySubsystem;
1137
+ /**
1138
+ * trace 落盘 store。app 级共享,per-session 以 sessionId 分流。未注入时 App
1139
+ * 默认构造 in-memory AppendLog(生产默认开启实时观测;可注入 file 后端做持久化/跨重启回溯)。
1140
+ * 经 app.storage.traceStore 暴露供 service/devtools tail(RFC-118 S1)。
1141
+ */
1142
+ traceStore?: AppendLog<TraceEvent>;
1143
+ /**
1144
+ * checkpoint 落盘 store。未注入时 App 默认构造 in-memory AppendLog;
1145
+ * 可注入 file 后端做持久化/跨重启回溯。经 app.storage.checkpointStore 暴露(RFC-118 S1)。
1146
+ */
1147
+ checkpointStore?: AppendLog<CheckpointData$1>;
1148
+ /**
1149
+ * 确定性时钟端口。缺省=真实系统时钟(行为不变);replay 由 trace 回灌。
1150
+ */
1151
+ clock?: ClockPort;
1152
+ skillProvider?: SkillProvider;
1153
+ /** LSP 工具 opt-in(go-to-definition/references/symbols/diagnostics/rename;需本机语言服务器)。 */
1154
+ lsp?: boolean;
1155
+ /**
1156
+ * bash OS 级沙箱配置。默认不启用(无沙箱,保持兼容)。
1157
+ * 启用后 bash 命令在 macOS Seatbelt / Linux Bubblewrap 沙箱内执行。
1158
+ */
1159
+ sandbox?: SandboxConfig;
1160
+ /**
1161
+ * RFC-164 M164-2 D6:workspace 记忆远端写入冲突时的通知回调——app 层接线到 TUI toast,
1162
+ * 让用户在冲突发生时能立即感知(子agent评审 F3)。不提供时冲突旁路文件仍写入,但无 toast 通知。
1163
+ */
1164
+ onMemoryConflict?: (path: string, conflictPath: string) => void;
1165
+ }
1166
+ type StorageLocation = {
1167
+ dir: string;
1168
+ } | {
1169
+ url: string;
1170
+ };
1171
+ /**
1172
+ * 持久化分组配置。
1173
+ *
1174
+ * url 语义:指向 RemotePersistence 线缆协议对端的 **namespace 根**,
1175
+ * 即另一实例 service 的 `http://host:port/api/storage/<namespace>`,
1176
+ * 各域常用 namespace:session→sessions。
1177
+ * 任一域使用 url 时必须提供 `remote.getAuth`(Bearer token,服务端 fail-closed)。
1178
+ *
1179
+ * knowledge/archive namespace 退场——memory=文件(.otto/),archive=session 派生视图。
1180
+ */
1181
+ interface StorageOptions {
1182
+ /** 会话快照存储。dir → 磁盘;url → remote。缺省内存。 */
1183
+ session?: StorageLocation;
1184
+ /** L1 知识(AGENTS.md sources)+ auto-memory。dir → 文件系统。缺省 workspaceDir/.otto/。 */
1185
+ memory?: StorageLocation;
1186
+ /**
1187
+ * @deprecated archive = session 派生视图,不再有独立持久化路径。
1188
+ * 此字段保留以避免已有配置的类型错误,但传入值会被忽略。
1189
+ */
1190
+ archive?: StorageLocation;
1191
+ /** 存储服务端(本实例充当 remote 对端宿主)。token 必选(fail-closed)。 */
1192
+ host?: {
1193
+ dir: string;
1194
+ token: string;
1195
+ namespaces?: string[];
1196
+ };
1197
+ /** remote 公共参数:任一域使用 url 时生效。 */
1198
+ remote?: {
1199
+ getAuth: () => Promise<{
1200
+ token: string;
1201
+ }>;
1202
+ fetch?: typeof globalThis.fetch;
1203
+ timeoutMs?: number;
1204
+ };
1205
+ }
1206
+ //#endregion
1207
+ //#region src/plugin/panel-backend-controller.d.ts
1208
+ type PanelBackendStatus = 'connecting' | 'ready' | 'crashed' | 'disabled';
1209
+ interface ResolveServerResult {
1210
+ ok: boolean;
1211
+ serverName?: string;
1212
+ reason?: string;
1213
+ }
1214
+ type StateListener = (params: Record<string, unknown>) => void;
1215
+ type StatusListener = (status: PanelBackendStatus) => void;
1216
+ /**
1217
+ * In-process backend handler(RFC-349 D1):插件不需要 MCP server 子进程时,
1218
+ * 宿主可直接在 App 主进程注册 backend methods。面板 `usePanelBackend().call()` 仍
1219
+ * 走同一条 `PanelBackendController.call()` 路径——区别只在于 call 被路由到
1220
+ * in-process handler 还是 MCP server 的 wire call。
1221
+ *
1222
+ * 用途:schedule 插件的 SchedulerService 依赖 `AgentJobService`/`sessionRef`/
1223
+ * `notifySubscriber`——这些只能存活在 App 主进程,无法搬到 MCP server 子进程。
1224
+ * 故 schedule 的 backend methods 注册为 in-process handler,不建 MCP server。
1225
+ */
1226
+ type InProcessBackendHandler = (method: string, params: Record<string, unknown>) => Promise<unknown>;
1227
+ interface PanelBackendControllerDeps {
1228
+ mcpController: McpController;
1229
+ getActivePlugins: () => readonly DiscoveredPlugin$1[];
1230
+ }
1231
+ declare class PanelBackendController {
1232
+ private readonly deps;
1233
+ private stateListeners;
1234
+ private statusListeners;
1235
+ /**
1236
+ * RFC-349 D1:in-process backend handlers——`pluginId → handler`。
1237
+ * 注册后 `call()` 优先走 in-process,不经过 MCP server。
1238
+ * `getStatus()` 对注册了 in-process handler 的插件恒返回 `'ready'`(无需子进程连接)。
1239
+ */
1240
+ private readonly inProcessHandlers;
1241
+ /**
1242
+ * 记录当前已订阅事件的 `McpManager` 实例引用(而非布尔位)——真实事故根因:
1243
+ * `McpController.reload()`(信任/授权插件高危能力后的热重载路径,见
1244
+ * `promptPluginTrust`→`reloadCapabilities`→`mcp.reload()`)会把 `_manager` 置 null 后
1245
+ * `new McpManager(...)` 重建一个全新实例。此前用布尔位 `subscribedNotifications` 把关,
1246
+ * 只在"全进程首次有面板消费方"时订阅一次,订阅的是当时那个 manager 实例——reload 换实例
1247
+ * 后,旧监听器绑在已经死掉的旧 manager 上,永远收不到新 manager 的 `server.connected`
1248
+ * 事件,导致已挂载面板在用户完成"信任/授权"操作、`getStatus()` 权威判定其实已经从
1249
+ * `disabled` 变为 `ready` 后,UI 因收不到 `notifyStatusChange` 通知而继续显示旧的
1250
+ * "面板后端不可用"(真实用户反馈:授权后重开详情页才刷新,不授权当场生效)。
1251
+ * 现改为记录已订阅的 manager 引用,每次 `ensureNotificationSubscription` 都比对当前
1252
+ * `mcpController.manager` 是否已变化,变化则对新实例重新订阅(旧实例的监听器随旧实例一起
1253
+ * 被 GC,不需要显式 `off`——`TypedEventEmitter` 无跨实例状态泄漏)。
1254
+ */
1255
+ private subscribedManager;
1256
+ constructor(deps: PanelBackendControllerDeps);
1257
+ /**
1258
+ * RFC-349 D1:注册 in-process backend handler。
1259
+ * 注册后该插件的 `call()` 直接走 handler,不经 MCP server。
1260
+ * 仍要求 manifest 声明 `panel.backend` capability(信任门不绕过)。
1261
+ */
1262
+ registerInProcessBackend(pluginId: string, handler: InProcessBackendHandler): void;
1263
+ /** RFC-349 D1:注销 in-process backend handler。 */
1264
+ unregisterInProcessBackend(pluginId: string): void;
1265
+ /**
1266
+ * 给定插件 id,解析出它可用于 backend 调用的 MCP server name。
1267
+ * fail-closed:capability 未声明/未授予 → `ok:false`;未找到匹配 server → `ok:false`。
1268
+ * RFC-349 D1:已注册 in-process handler 的插件跳过 MCP server 解析。
1269
+ */
1270
+ resolveServerForPlugin(pluginId: string): ResolveServerResult;
1271
+ /**
1272
+ * 面板发起的 `backend/*` 请求转发到对应插件的 MCP server 连接。
1273
+ *
1274
+ * `operationId`(可选):若该 method 支持取消(D6),调用方生成并随请求携带一个客户端侧
1275
+ * 操作 id(约定字段名 `__operationId`,`definePanelBackend` SDK 侧剥离后再校验业务
1276
+ * params,见 `panel-backend-sdk.ts` 文件头"操作 id 的归属"说明)——**必须由客户端先生成
1277
+ * 再发起请求**,而非等服务端返回后才知道 id,否则调用尚未返回时无法发起 cancel(真实
1278
+ * 时序约束,非任意设计选择)。
1279
+ */
1280
+ call(pluginId: string, method: string, params: Record<string, unknown>, opts?: {
1281
+ operationId?: string;
1282
+ signal?: AbortSignal;
1283
+ }): Promise<unknown>;
1284
+ /** 面板发起的 `backend/cancel(operationId)`——转发到对应插件的 MCP server。 */
1285
+ cancel(pluginId: string, operationId: string): Promise<void>;
1286
+ /**
1287
+ * 订阅该插件的 `backend/state` 推送(全量快照)。惰性订阅底层 `McpManager` 的
1288
+ * `server.notification` 事件(首次调用时才订阅,避免无消费者时空转)。
1289
+ */
1290
+ subscribeState(pluginId: string, cb: StateListener): () => void;
1291
+ /** 订阅该插件 backend 连接状态变化(四态,见文件头 getStatus 判定说明)。 */
1292
+ onStatusChange(pluginId: string, cb: StatusListener): () => void;
1293
+ /** 查询该插件当前的 backend 连接状态(四态,终局判定见文件头注释)。 */
1294
+ getStatus(pluginId: string): PanelBackendStatus;
1295
+ /**
1296
+ * `App.reloadCapabilities()` 完成后调用(RFC-165 D8 补充修复)——`promptPluginTrust`
1297
+ * 授权 `panel.backend` 能力走的正是这条热重载路径,但触发时机在**面板已挂载期间**
1298
+ * (用户在 disabled 态详情页里点击"信任",面板组件本身不会因此卸载重挂载)。仅让
1299
+ * `ensureNotificationSubscription` 在下次挂载时对新 manager 重新订阅还不够——已挂载面板
1300
+ * 绑定的监听器停留在旧 manager 上,reload 期间不会有任何契机重新调用
1301
+ * `ensureNotificationSubscription`。本方法主动完成两件事:① 重新对齐订阅到当前
1302
+ * manager 实例;② 对全部已注册 `statusListeners` 的插件重新查询 `getStatus()` 并推送,
1303
+ * 让已挂载面板的 `usePanelBackend()` 状态即时刷新(而不必等待用户手动关闭重开详情页)。
1304
+ */
1305
+ notifyReload(): void;
1306
+ /**
1307
+ * 惰性订阅 `McpManager` 的 `server.notification`/`server.connected`/`server.disconnected`
1308
+ * 事件——首次有面板消费方(subscribeState/onStatusChange)时才订阅。每次调用都比对当前
1309
+ * `mcpController.manager` 与已订阅实例是否相同(见 `subscribedManager` 字段头注释:
1310
+ * `McpController.reload()` 会重建全新 manager 实例),实例变化则对新实例重新订阅,
1311
+ * 保证 reload 后(如信任/授权插件高危能力触发的热重载)状态变化仍能正确通知到已挂载面板。
1312
+ */
1313
+ private ensureNotificationSubscription;
1314
+ private pluginIdForServer;
1315
+ }
1316
+ //#endregion
1317
+ //#region src/plugin/plugin-panel-manager.d.ts
1318
+ interface PanelRegistration {
1319
+ /** 面板唯一 id(格式 `pluginId:panelId`)。 */
1320
+ id: string;
1321
+ /** 插件 id。 */
1322
+ pluginId: string;
1323
+ /** 面板标题。 */
1324
+ title: string;
1325
+ /** 已编译组件的绝对路径(panels-dist/xxx.js)。 */
1326
+ modulePath: string;
1327
+ /** 导出名('default' 或具名)。 */
1328
+ exportName: string;
1329
+ }
1330
+ //#endregion
1331
+ //#region src/plugin/status-items.d.ts
1332
+ interface ResolvedStatusItem {
1333
+ id: string;
1334
+ text: string;
1335
+ }
1336
+ //#endregion
1337
+ //#region src/plugin/renderer-loader.d.ts
1338
+ /** 渲染函数签名(与 `@x-otto/tui renderMessageLines` 同构)。 */
1339
+ type PluginMessageRenderer = (message: unknown, columns: number) => string[];
1340
+ interface RegisteredRenderer {
1341
+ /** 全局唯一 id(`pluginId:rendererId`)。 */
1342
+ id: string;
1343
+ pluginId: string;
1344
+ matcher: PluginRendererEntry['matcher'];
1345
+ render: PluginMessageRenderer;
1346
+ }
1347
+ //#endregion
1348
+ //#region src/plugin/status-widget-loader.d.ts
1349
+ /** 徽标语义色(镜像 `@x-otto/tui badge-entry.ts BadgeColorKind`——本包对渲染层零依赖,
1350
+ * 跨包各自定义同构类型,装载调用方按结构赋值,同 `RegisteredRenderer` 既有纹理)。 */
1351
+ type StatusWidgetColorKind = 'warning' | 'inactive';
1352
+ /**
1353
+ * 宿主组装的只读快照(RFC-184 D2:v1 无事件订阅,widget 只消费此快照,不持有 TuiHandle)。
1354
+ * `providerUsage` 类型故意保持 `unknown`——真实快照组装与调用只发生在 `@x-otto/tui`
1355
+ * (见 `status-widget-registry.ts StatusWidgetContext`,那里用 TUI 实际持有的
1356
+ * `ProviderUsageBadgeItem` 精确类型);本接口是**装载模块的文档性契约类型**,供插件作者
1357
+ * 参考渲染函数签名,本包不构造该快照实例,收紧类型只会制造与 TUI 侧的跨包类型耦合而无实益。
1358
+ */
1359
+ interface StatusWidgetContext {
1360
+ nowMs: number;
1361
+ model: string;
1362
+ providerUsage: unknown;
1363
+ columns: number;
1364
+ }
1365
+ /** 插件状态栏徽标渲染函数签名。 */
1366
+ type PluginStatusWidgetRenderFn = (ctx: StatusWidgetContext) => {
1367
+ text: string;
1368
+ color?: StatusWidgetColorKind;
1369
+ } | null;
1370
+ interface RegisteredStatusWidget {
1371
+ /** 全局唯一 id(`pluginId:widgetId`)。 */
1372
+ id: string;
1373
+ pluginId: string;
1374
+ render: PluginStatusWidgetRenderFn;
1375
+ /** 宿主 clamp 前的原始声明值(clamp 逻辑在 `@x-otto/tui` 侧共享定时器实现,RFC-184 D4)。 */
1376
+ tickMs?: number;
1377
+ order?: number;
1378
+ }
1379
+ //#endregion
1380
+ //#region src/plugin/file-viewer-loader.d.ts
1381
+ /** 渲染函数签名(插件作者侧,`@x-otto/extension defineFileViewer` 薄包装同签名)。 */
1382
+ type PluginFileViewerRenderFn = (content: string, path: string, columns: number) => {
1383
+ lines: string[];
1384
+ wrapMode?: 'pre-wrap' | 'truncate';
1385
+ } | null;
1386
+ interface RegisteredFileViewer {
1387
+ /** 全局唯一 id(`pluginId:entryId`)。 */
1388
+ id: string;
1389
+ pluginId: string;
1390
+ label: string;
1391
+ matcher: PluginFileViewerEntry['matcher'];
1392
+ render: PluginFileViewerRenderFn;
1393
+ order?: number;
1394
+ }
1395
+ //#endregion
1396
+ //#region src/plugin/a2ui-component-loader.d.ts
1397
+ /** 插件 a2ui 组件渲染函数签名(与 `@x-otto/tui a2ui-renderer.ts` renderComponent 同构)。 */
1398
+ type PluginA2uiRenderFn = (component: unknown, columns: number, resolveChild: (id: string) => string[]) => string[];
1399
+ interface RegisteredA2uiComponent {
1400
+ /** 组件类型名(跨插件全局命名空间,供 tui 侧注册表按 type 查表)。 */
1401
+ type: string;
1402
+ pluginId: string;
1403
+ render: PluginA2uiRenderFn;
1404
+ }
1405
+ //#endregion
1406
+ //#region src/plugin/plugin-capability-quota.d.ts
1407
+ /**
1408
+ * per-plugin 的能力配额与会话白名单登记处。
1409
+ *
1410
+ * 生命周期:随宿主装配点存活;插件停止时 `reset(pluginId)` 清空(不保留跨启停的授权——
1411
+ * 插件重启后必须重新经 notify 获得 sessionId 授权,防"停用期间攒下的白名单"被复用)。
1412
+ */
1413
+ declare class PluginCapabilityQuota {
1414
+ private readonly now;
1415
+ private readonly states;
1416
+ constructor(now?: () => number);
1417
+ private stateOf;
1418
+ /**
1419
+ * 记录一次成功送出的 notify:授权该 sessionId 并开启新 epoch(重置 per-epoch 计数)。
1420
+ * 这是插件获得 `readTranscript` 访问权的**唯一**入口。
1421
+ */
1422
+ onNotifyDelivered(pluginId: string, sessionId: string): void;
1423
+ /** 该插件是否被授权读这个会话(未经 notify 下发 = 拒绝)。 */
1424
+ isSessionAuthorized(pluginId: string, sessionId: string): boolean;
1425
+ /** 消费一次 readTranscript 配额;返回 false 表示超限(调用方应拒绝并说明原因)。 */
1426
+ tryConsumeRead(pluginId: string): boolean;
1427
+ /** 消费一次 llm.complete 配额(epoch + 滑动小时窗双门)。 */
1428
+ tryConsumeLlm(pluginId: string): {
1429
+ ok: true;
1430
+ } | {
1431
+ ok: false;
1432
+ reason: 'epoch' | 'hourly';
1433
+ };
1434
+ /**
1435
+ * RFC-327 M3:消费一次 user.notify 配额;返回 false 表示超限(调用方应**静默丢弃**)。
1436
+ *
1437
+ * 用滑动小时窗而非 epoch——通知的正当触发源(schedule.tick、生命周期事件)不开 epoch,
1438
+ * 挂 epoch 会让定时服务永远发不出通知。
1439
+ */
1440
+ tryConsumeNotify(pluginId: string): boolean;
1441
+ /** 插件停止/卸载:清空全部授权与计数。 */
1442
+ reset(pluginId: string): void;
1443
+ }
1444
+ //#endregion
1445
+ //#region src/plugin/inquiry-center.d.ts
1446
+ /**
1447
+ * RFC-344 M2:宿主问询中心——两类人在环问询的统一队列与仲裁。
1448
+ *
1449
+ * **为什么需要它**(M1 核实的既有陷阱):`packages/tui/src/bootstrap/handle-modal.ts:324`
1450
+ * 的 `resolvers.questions` 是**单槽位**——第二个 `openModal({kind:'questions'})` 到来时
1451
+ * 直接覆盖前一个的 resolver,被覆盖的 Promise **永远不会 resolve**(调用方挂死)。
1452
+ *
1453
+ * 这在只有 agent grill 一个投递源时已经是漏洞(同会话连续 grill 会触发),只是不易暴露;
1454
+ * 新增插件问询作为第二个投递源后必然频繁命中。故本模块的核心不变式是:
1455
+ *
1456
+ * **同一时刻最多只有一个问询在飞(in-flight)。**
1457
+ *
1458
+ * 两类问询都必须入队(独立评审补充)——只拦插件侧无法建立该不变式,且会原样保留
1459
+ * `requestGrill` 的既有并发漏洞。
1460
+ *
1461
+ * **职责边界**:纯逻辑状态机,不碰 TUI、不做 IO、不读时钟以外的环境。
1462
+ * 时钟经 `now` 端口注入(确定性可测,对齐本仓 Clock 端口纪律)。
1463
+ */
1464
+ /** 问询来源——决定优先级与配额归属。 */
1465
+ type InquiryOrigin = {
1466
+ kind: 'session';
1467
+ sessionId: string;
1468
+ } | {
1469
+ kind: 'plugin';
1470
+ pluginId: string;
1471
+ };
1472
+ interface InquiryRequest {
1473
+ /** 宿主分配的唯一 id。 */
1474
+ id: string;
1475
+ origin: InquiryOrigin;
1476
+ /** 复用 grill 的问题结构(M1 D4:数据结构全复用)。 */
1477
+ question: Omit<GrillQuestion, 'id'>;
1478
+ }
1479
+ /** 已入队的问询——`enqueuedAt` 由中心用自己的时钟盖章,不接受调用方传入。 */
1480
+ interface QueuedInquiry extends InquiryRequest {
1481
+ /**
1482
+ * 入队时刻(epoch ms)。
1483
+ *
1484
+ * **必须由中心盖章而非调用方传入**:TTL 判定用的是中心的 `now` 端口,若时间戳来自
1485
+ * 另一个时钟(调用方的 `Date.now()`、测试里的固定值),两个时间源不一致会让问询
1486
+ * 一入队就被判超时(或永不超时)。单一时间源是 TTL 正确性的前提。
1487
+ */
1488
+ enqueuedAt: number;
1489
+ }
1490
+ /** 拒绝原因——调用方据此给出可诊断的失败,而非静默丢弃。 */
1491
+ type RejectReason = 'queue-full' | 'plugin-concurrency' | 'timeout' | 'shutdown';
1492
+ interface InquiryCenterOptions {
1493
+ /** 队列容量上限(含在飞的那一个)。超限拒绝**新**问询,不丢弃旧的——旧的可能已在用户眼前。 */
1494
+ maxPending?: number;
1495
+ /** 单个插件的并发问询上限——防止插件用连续发问霸占队列。 */
1496
+ maxPerPlugin?: number;
1497
+ /** 问询存活上限(ms)。超时按 R5 fail-closed 返回拒绝,**不是**返回推荐值。 */
1498
+ ttlMs?: number;
1499
+ now?: () => number;
1500
+ }
1501
+ interface EnqueueResult {
1502
+ /** 入队成功——调用方 await 此 Promise 拿最终答案。 */
1503
+ accepted: true;
1504
+ answer: Promise<GrillAnswer>;
1505
+ }
1506
+ interface RejectResult {
1507
+ accepted: false;
1508
+ reason: RejectReason;
1509
+ }
1510
+ /**
1511
+ * 队列 + 仲裁状态机。
1512
+ *
1513
+ * 生命周期:`enqueue` → (轮到时)`takeNext` 交给 UI → `settle` 收敛答案 → 自动派发下一个。
1514
+ * 调用方(宿主接线层)负责把 `takeNext` 的产物送进 `openModal`,并在 UI 回调里调 `settle`。
1515
+ */
1516
+ declare class InquiryCenter {
1517
+ private readonly queue;
1518
+ private inFlightId;
1519
+ private readonly maxPending;
1520
+ private readonly maxPerPlugin;
1521
+ private readonly ttlMs;
1522
+ private readonly now;
1523
+ constructor(options?: InquiryCenterOptions);
1524
+ /**
1525
+ * 入队一个问询。返回的 Promise 在用户作答、超时或被拒时收敛。
1526
+ *
1527
+ * **永不 reject**:拒绝经 `{accepted:false, reason}` 表达,超时/取消经 answer 的
1528
+ * `resolvedBy` 表达。调用方不需要 try/catch——人在环的"没答成"不是异常。
1529
+ */
1530
+ enqueue(request: InquiryRequest): EnqueueResult | RejectResult;
1531
+ /**
1532
+ * 等到轮到指定问询渲染。
1533
+ *
1534
+ * 调用方模式:`enqueue` 成功后 `await waitForTurn(id)`,返回 true 即可安全渲染
1535
+ * (此时它已是 in-flight),渲染完调 `settle`。返回 false 表示该问询已被 TTL 清理
1536
+ * 或 shutdown 收敛——调用方不应再渲染(它的 Promise 已被中心 resolve)。
1537
+ *
1538
+ * 为什么把等待放在中心而不是让调用方轮询:轮询逻辑写在每个调用点会各自跑偏
1539
+ * (漏判 TTL 清理、漏判 shutdown),而"谁该渲染"本就是仲裁者的职责。
1540
+ */
1541
+ waitForTurn(id: string, pollMs?: number): Promise<boolean>;
1542
+ /**
1543
+ * 取出下一个应渲染的问询——**同一时刻只有一个在飞**(核心不变式)。
1544
+ *
1545
+ * 已有在飞问询时返回 undefined:调用方不得强行再开一个,否则会命中
1546
+ * `resolvers.questions` 单槽位覆盖,让前一个 Promise 永远挂死。
1547
+ */
1548
+ takeNext(): QueuedInquiry | undefined;
1549
+ /**
1550
+ * 收敛一个问询的答案(用户作答 / Esc 取消 / UI 侧异常兜底)。
1551
+ *
1552
+ * 返回是否命中——重复 settle 同一 id 时返回 false(幂等,防 UI 层重复回调导致的双重收敛)。
1553
+ */
1554
+ settle(id: string, answer: GrillAnswer): boolean;
1555
+ /**
1556
+ * 释放槽位但**不经中心交付答案**——供"答案走自有通道"的调用方使用。
1557
+ *
1558
+ * 会话问询就是这种形态:它的答案经 `resolveAskUser` 直接回 AgentSession 的 grill gate,
1559
+ * 中心的 `answer` Promise 无人消费。此时若用 `settle(id, someAnswer)`,那个 answer
1560
+ * 参数是无意义的噪音,还会让读代码的人以为答案从这里走。
1561
+ *
1562
+ * 插件问询则相反——它**必须**用 `settle`,因为 `enqueue` 返回的 Promise 就是插件
1563
+ * 等待的那个。
1564
+ *
1565
+ * 幂等:重复调用或 id 不存在时返回 false。
1566
+ */
1567
+ release(id: string): boolean;
1568
+ /** 当前是否有问询正在渲染。 */
1569
+ get hasInFlight(): boolean;
1570
+ /** 队列长度(含在飞的那一个)——供诊断与测试。 */
1571
+ get size(): number;
1572
+ /**
1573
+ * 清理超时问询。
1574
+ *
1575
+ * **在飞的不清理**:它已经在用户眼前,用户可能正在读背景信息;由 UI 侧的取消/作答收敛。
1576
+ * 只清理还在排队、从未渲染过的——它们的等待是纯粹的机会成本。
1577
+ *
1578
+ * 超时按 R5 fail-closed:返回**拒绝**(`acceptedRecommendation:false`),
1579
+ * **不是** `auto_recommendation`,也**不是** `environment_headless`:
1580
+ * - `auto_recommendation`:推荐被采纳,回答者不是环境限制(不需问的场合)。
1581
+ * - `environment_headless`:环境不能问(headless),推荐被环境沉降。
1582
+ * - 超时是"能问但用户没答"——对插件必须保守(相当于没拿到批准)。
1583
+ * 这条区分是安全边界(M1 D3)。
1584
+ */
1585
+ private sweepExpired;
1586
+ /**
1587
+ * 停机:收敛全部待决问询。
1588
+ *
1589
+ * 与超时同样按 fail-closed 拒绝——宿主要关了,没人能回答了,
1590
+ * 此时返回推荐值等于替用户点头。
1591
+ */
1592
+ shutdown(): void;
1593
+ }
1594
+ //#endregion
1595
+ //#region src/plugin/plugin-schedule-subscriptions.d.ts
1596
+ /**
1597
+ * RFC-327 D2(M2):插件服务 schedule 订阅的宿主侧差量对账。
1598
+ *
1599
+ * 插件**声明**它要订阅什么(`PluginService.schedules`),宿主负责把声明与 core schedule
1600
+ * 的实际状态对账——新增缺失的、更新变化的、删除多余的。这样:
1601
+ * - 插件重载不会产生重复订阅(同 key 视为同一订阅);
1602
+ * - 插件 disable/uninstall 时由 services 轴的 `unregister` 触发 `revokeAll`,不依赖
1603
+ * 插件自己清理(它已经不在运行了);
1604
+ * - owner 由宿主从注册上下文推导,插件无法自报身份。
1605
+ *
1606
+ * **不拥有调度**:本模块只调用 core schedule 的 add/update/remove,cron 解析、持久化、
1607
+ * fire ownership、崩溃恢复全部仍归 core(R4 timer 单一真源)。
1608
+ */
1609
+ /** core schedule 侧的最小操作面——只取本模块真正需要的四个方法,不耦合完整 SchedulerService。 */
1610
+ interface ScheduleSubscriptionPort {
1611
+ list(): ScheduledTask$1[];
1612
+ add(input: {
1613
+ name: string;
1614
+ prompt: string;
1615
+ cronExpression: string;
1616
+ recurring: boolean;
1617
+ origin: 'user' | 'model';
1618
+ subscriber?: ScheduleSubscriber;
1619
+ }): ScheduledTask$1;
1620
+ update(id: string, patch: {
1621
+ name?: string;
1622
+ prompt?: string;
1623
+ cronExpression?: string;
1624
+ enabled?: boolean;
1625
+ }): boolean;
1626
+ remove(id: string): boolean;
1627
+ }
1628
+ //#endregion
1629
+ //#region src/plugin/plugin-service-pool.d.ts
1630
+ /** 宿主侧可被 service 经反向 RPC 调用的能力(method 白名单派发,不做动态转发)。 */
1631
+ interface ServiceHostBridge {
1632
+ /**
1633
+ * 派发 agent 作业。**R2 的 origin 强制不在本层**——本回调由宿主装配点提供,
1634
+ * 内部固定 `origin:'plugin'`(见 `plugin-module-manager.ts` 的 buildHostCapabilities
1635
+ * 与 `app.ts` 的 startPluginJob)。本池只负责把调用送过去,不复制安全逻辑(单一强制点)。
1636
+ */
1637
+ startJob?: (input: {
1638
+ title: string;
1639
+ prompt: string;
1640
+ }) => Promise<{
1641
+ jobId: string;
1642
+ }>;
1643
+ /**
1644
+ * RFC-318 M1:读取会话轨迹。**安全强制全在桥的实现里**(宿主装配点)——sessionId
1645
+ * 白名单、投影、secret 掩码、配额;本池只负责派发,不复制安全逻辑(单一强制点,
1646
+ * 同 startJob 的 origin 强制纪律)。
1647
+ */
1648
+ readTranscript?: (input: {
1649
+ sessionId: string;
1650
+ sinceIndex?: number;
1651
+ }) => Promise<{
1652
+ messages: readonly TranscriptMessage[];
1653
+ nextIndex: number;
1654
+ }>;
1655
+ /** RFC-318 M1:模型文本补全。配额(prompt/maxTokens/频率)同样在桥的实现里强制。 */
1656
+ complete?: (input: {
1657
+ prompt: string;
1658
+ maxTokens?: number;
1659
+ }) => Promise<string>;
1660
+ /**
1661
+ * RFC-327 M3:向用户推送非阻塞通知。**内容约束与限频全在桥的实现里**(长度上限、
1662
+ * 控制字符剥离、滑动窗口);本池只负责派发,不复制安全逻辑(单一强制点)。
1663
+ */
1664
+ notify?: (input: {
1665
+ level: 'info' | 'warning' | 'error';
1666
+ code: string;
1667
+ message: string;
1668
+ }) => Promise<void>;
1669
+ }
1670
+ interface ServiceStartInput {
1671
+ pluginId: string;
1672
+ serviceId: string;
1673
+ compiledPath: string;
1674
+ workspaceDir: string;
1675
+ workspaceKey: string;
1676
+ /** 工厂期 ctx(纯数据,同既有隔离路径)。 */
1677
+ factoryCtx: {
1678
+ pluginId: string;
1679
+ pluginDir: string;
1680
+ workspaceDir: string;
1681
+ };
1682
+ /** 该插件已被授予的 host 能力名(fail-closed:宿主算好后下发,worker 侧照此构造 ctx.host)。 */
1683
+ hostCapabilities: string[];
1684
+ /** RFC-303 M5:该插件 scoped storage 目录(`plugin-state/<pluginId>/<wsKey>`,宿主已 mkdir)。 */
1685
+ storageDir: string;
1686
+ /** RFC-303 M5:是否已声明 storage 能力(fail-closed:未声明不注入 ctx.storage)。 */
1687
+ hasStorageCapability: boolean;
1688
+ /** 反向 RPC 的宿主侧实现(按 pluginId 绑定,身份不取自消息内容)。 */
1689
+ bridge: ServiceHostBridge;
1690
+ }
1691
+ type ServiceStatus = 'starting' | 'running' | 'stopped' | 'failed';
1692
+ declare class PluginServicePool {
1693
+ private readonly services;
1694
+ /** 已启动的服务键(供 /extension 面板与测试观测)。 */
1695
+ get runningKeys(): string[];
1696
+ statusOf(pluginId: string, serviceId: string): ServiceStatus | undefined;
1697
+ restartsOf(pluginId: string, serviceId: string): number;
1698
+ /**
1699
+ * RFC-318 D9:向一个运行中的 service 推送事件通知(单向,无回执)。
1700
+ *
1701
+ * 返回是否真的送出——`false` 表示服务不存在或未处于 running(**不抛**:通知是尽力而为的
1702
+ * 旁路信号,宿主主循环不该因为某个插件没起来而出错)。调用方据此决定是否记账/降级。
1703
+ */
1704
+ notify(pluginId: string, serviceId: string, notification: PluginServiceNotification): boolean;
1705
+ /** 该插件当前处于 running 的 serviceId 列表(通知广播用:调用方无需知道插件的服务命名)。 */
1706
+ runningServiceIds(pluginId: string): string[];
1707
+ /** 启动一个常驻服务(幂等:同键已在跑则先停后启)。 */
1708
+ start(input: ServiceStartInput): Promise<{
1709
+ error?: string;
1710
+ }>;
1711
+ private spawnAndStart;
1712
+ /**
1713
+ * 反向 RPC 派发 + 生命周期消息处理。
1714
+ *
1715
+ * **身份鉴定(R1 在 RPC 层的对应物)**:`entry` 由 `key` 从连接(worker 实例)侧查得,
1716
+ * 能力桥 `entry.input.bridge` 是宿主装配时按该插件绑定的——**绝不读 msg 里的任何身份
1717
+ * 字段**。即便 worker 侧伪造消息内容,也只能调到自己那份 bridge。
1718
+ */
1719
+ private onWorkerMessage;
1720
+ /** method 白名单派发——未知 method 一律 error,不做动态转发(防能力面被反射式扩大)。 */
1721
+ private dispatchHostCall;
1722
+ /** 崩溃退避重启;超过上限标记 failed 永久停止。 */
1723
+ private scheduleRestart;
1724
+ /**
1725
+ * 停止一个服务:二阶停机——先请 worker 优雅 `stop()`,超时则强杀。
1726
+ *
1727
+ * 服务可能持有外部连接(DB/WebSocket),强杀会丢数据,故先给优雅窗口;但单个服务
1728
+ * 挂起不得拖死其余服务的卸载(对齐 onDeactivate 护城河纹理)。
1729
+ */
1730
+ stop(pluginId: string, serviceId: string): Promise<void>;
1731
+ /** 停止某插件的全部服务(插件禁用/卸载路径)。 */
1732
+ stopPlugin(pluginId: string): Promise<void>;
1733
+ /** 宿主停机:停全部服务并清理临时目录。 */
1734
+ dispose(): Promise<void>;
1735
+ }
1736
+ //#endregion
1737
+ //#region src/app/plugin-module-manager.d.ts
1738
+ /** PluginModuleManager 依赖面(M100 DI 范式:interface 声明依赖、不持 App 引用、可独立测)。 */
1739
+ interface PluginModuleManagerDeps {
1740
+ hookRegistry: HookRegistry;
1741
+ skillRegistry: SkillRegistry | null;
1742
+ /** RFC-105 D3:代码式 provider 工厂注册目标(可选——不传则 `providerFactories` 轴静默跳过)。 */
1743
+ providerRegistry?: ProviderRegistry;
1744
+ /** RFC-148 M3:代码式 provider 静态模型注册目标(可选——不传则 `codeProviderModels` 静默跳过)。 */
1745
+ modelRegistry?: ModelRegistry;
1746
+ /** RFC-148 D2:Wire 协议实现注册目标(可选——不传则 `wireProtocols` 轴静默跳过)。 */
1747
+ wireProtocolRegistry?: WireProtocolRegistry;
1748
+ /** RFC-122 D1 / RFC-130 M131-1:代码式 OAuth 工厂注册目标。 */
1749
+ authStore?: AuthStore;
1750
+ /** RFC-105 D4:代码式工具注册目标(可选——不传则 `tools` 轴静默跳过)。 */
1751
+ toolRegistry?: ToolRegistry;
1752
+ /** RFC-209 §2.3:Feedback 业务契约注册目标(可选——不传则 `feedbackProviders` 轴静默跳过)。 */
1753
+ feedbackRegistry?: FeedbackRegistry;
1754
+ /** RFC-210 D3:@ 资源 resolve 注册目标(可选——不传则 `sigilResolvers` 轴静默跳过)。 */
1755
+ sigilResolverRegistry?: SigilResolverRegistry;
1756
+ /** RFC-210 D3:@ 资源动态 provider 注册目标(可选——不传则 `sigilProviders` 轴静默跳过)。
1757
+ * registerProvider 返回注销函数,由本管理器持有供 reload/cleanup 撤销。 */
1758
+ pluginInput?: PluginInputRegistry$1;
1759
+ /** RFC-105 D9:是否对声明了 `tools` 能力的插件启用 worker 隔离加载(默认 true——隔离)。 */
1760
+ useIsolatedLoading?: boolean;
1761
+ /** RFC-153 D3:插件加载/编译/工厂失败的旁路通知(可选,不传则不记录健康度)。 */
1762
+ onPluginLoadError?: (pluginId: string, message: string) => void;
1763
+ workspaceDir: string;
1764
+ activePlugins: () => DiscoveredPlugin$1[];
1765
+ /**
1766
+ * RFC-287 D2:派发 agent 作业的宿主能力源(可选——不传则 `agent.dispatch` 能力面
1767
+ * 静默不可用,同其余可选 registry 的既有纹理)。惰性 getter 而非直接传服务实例:
1768
+ * `AgentJobService` 在 App 里是 lazy 构造(`app.ts` 的 `get agentJobs()`),构造期
1769
+ * 直接取值会提前实例化整条作业链。
1770
+ *
1771
+ * **安全契约(R2,本处是唯一强制点)**:本回调的入参不含 `origin`——`origin: 'plugin'`
1772
+ * 由 `buildHostCapabilities` 内部固定写入,插件无法influence;入参也不含
1773
+ * `skipPermissions`/`useWorktree`,插件无法借作业绕权限或直改主树。
1774
+ */
1775
+ startPluginJob?: (input: {
1776
+ pluginId: string;
1777
+ title: string;
1778
+ prompt: string;
1779
+ sessionId: string;
1780
+ }) => {
1781
+ id: string;
1782
+ };
1783
+ /** RFC-287 D2:插件作业归属的会话 id(活引用——`/resume` 换 session 后闭包读最新值)。 */
1784
+ getSessionId?: () => string | undefined;
1785
+ /**
1786
+ * RFC-318 M1:会话消息读取源(可选——不传则 `session.read` 能力静默不可用)。
1787
+ * 返回该会话的完整历史;投影/掩码/切片由 `buildHostCapabilities` 统一处理,本回调
1788
+ * 只负责"取原始数据",不承担安全职责(单一强制点原则)。
1789
+ */
1790
+ getSessionMessages?: (sessionId: string) => readonly Message[] | undefined;
1791
+ /**
1792
+ * RFC-318 M1:模型文本补全源(可选——不传则 `llm.complete` 能力静默不可用)。
1793
+ * 与 RFC-036 lesson 抽取共用同一 `createModelTextCaller` 形状(D10:两条抽取管线
1794
+ * 并存、各自独立调用,不合并)。
1795
+ */
1796
+ completeText?: (prompt: string, opts?: {
1797
+ maxTokens?: number;
1798
+ }) => Promise<string>;
1799
+ /**
1800
+ * RFC-327 M3:宿主 UI 通知出口(app 层接线到 TUI 活动流/toast)。
1801
+ * 缺省 → `user.notify` 能力不注入(fail-closed,同其他能力的"宿主未提供源"分支)。
1802
+ */
1803
+ notifyUser?: (input: {
1804
+ pluginId: string;
1805
+ level: 'info' | 'warning' | 'error';
1806
+ code: string;
1807
+ message: string;
1808
+ }) => void;
1809
+ /**
1810
+ * RFC-327 D2(M2):core schedule 订阅对账端口(惰性 getter)。
1811
+ * 缺省或返回 undefined → 跳过订阅对账(headless 无 scheduler 的既定边界)。
1812
+ */
1813
+ getSchedulePort?: () => ScheduleSubscriptionPort | undefined;
1814
+ /**
1815
+ * RFC-318 M1:受控能力的配额与会话白名单(可选——不传则内部自建实例)。
1816
+ * 由宿主装配点持有,使 `pool.notify` 的授权登记与能力调用的配额校验共用同一份状态。
1817
+ */
1818
+ capabilityQuota?: PluginCapabilityQuota;
1819
+ /** RFC-344 M3:阻塞式 user.ask 出口。缺省 → 能力不注入(fail-closed)。 */
1820
+ askUser?: (pluginId: string, input: Omit<GrillQuestion, 'id' | 'askedBy'>) => Promise<GrillAnswer>;
1821
+ /**
1822
+ * RFC-287 M3:常驻服务池(可选——不传则用全局单例;测试注入隔离实例)。
1823
+ * 缺省惰性取全局单例,避免不使用 services 的装配路径也被迫构造池。
1824
+ */
1825
+ servicePool?: PluginServicePool;
1826
+ /** RFC-287 M3:工作区稳定标识(service 是 per-workspace 一实例)。缺省 'default'。 */
1827
+ /** RFC-287 M3:工作区稳定标识(service 是 per-workspace 一实例)。缺省 'default'(storageDirFor 兜底);
1828
+ * RFC-303 M5 复用同一字段做 scoped persistence 的 workspaceKey 来源,惰性未就位时用 DEFAULT_WORKSPACE_KEY 兜底。 */
1829
+ getWorkspaceKey?: () => string | undefined;
1830
+ callMcpTool: (server: string, tool: string, params?: Record<string, unknown>) => Promise<{
1831
+ content: {
1832
+ type: string;
1833
+ text?: string;
1834
+ }[];
1835
+ isError?: boolean;
1836
+ }>;
1837
+ logger: Logger;
1838
+ }
1839
+ declare class PluginModuleManager {
1840
+ private readonly deps;
1841
+ /**
1842
+ * RFC-303 D5(M7):插件 → 贡献轴名快照缓存。
1843
+ * 只在插件 enabled 完成时刷新(reload 差量完成点),两次 enabled 间保持不变——
1844
+ * listActivePlugins 的 contributes 字段取此缓存,保证时序稳定(M7 文档"contributes
1845
+ * 时序稳定性"落地约束)。
1846
+ */
1847
+ private readonly contributesSnapshot;
1848
+ /** onDeactivate 超时护城河:对齐 hook emit 的既有模式(hook-registry.ts:207-227),
1849
+ * 防止单个插件的 onDeactivate 挂起拖死所有其他插件的卸载流程(RFC-151 D1)。 */
1850
+ private static readonly DEACTIVATE_TIMEOUT_MS;
1851
+ private readonly hooksAxis;
1852
+ private readonly monitorsAxis;
1853
+ private readonly feedbackAxis;
1854
+ private readonly sigilAxis;
1855
+ private readonly computedCommandsAxis;
1856
+ private readonly computedAgentsAxis;
1857
+ private readonly computedSkillsAxis;
1858
+ private readonly oauthProviderAxis;
1859
+ private readonly codeProviderAxis;
1860
+ private readonly wireProtocolAxis;
1861
+ private readonly toolsAxis;
1862
+ /** RFC-287 M3:services 常驻轴(唯一产物为长生命周期 worker 的轴)。 */
1863
+ private readonly servicesAxis;
1864
+ /** 装配顺序即注册/卸载顺序(纯搬迁纪律:与原内联代码轴出现顺序逐字节一致)。 */
1865
+ private readonly axisHandlers;
1866
+ /** 本进程内已触发的激活事件(RFC-105 D7)。`onStartup` 恒真,不需放入此集合。 */
1867
+ private readonly firedEvents;
1868
+ /** 上一轮因未匹配激活事件而被跳过代码模块加载的插件 id(供 `deferredPluginIds` 观测)。 */
1869
+ private deferredIds;
1870
+ /**
1871
+ * RFC-151 D1:已加载插件模块追踪表(key=pluginId)。`LoadedPluginModule` 本身不含 manifest,
1872
+ * 因此值类型同步保存 manifest 快照供 changed 判定(JSON.stringify 签名比对)。
1873
+ * reload() 中 removed/changed 插件在 unregister 循环之前调用 onDeactivate;
1874
+ * cleanup() 中对全部已加载插件调用 onDeactivate;处理后清理不再存活的条目。
1875
+ */
1876
+ private loadedModules;
1877
+ constructor(deps: PluginModuleManagerDeps);
1878
+ /** 上一轮 reload 中因懒激活被跳过代码模块加载的插件 id(骨架观测用,M105-6 前无真实触发源)。 */
1879
+ get deferredPluginIds(): ReadonlySet<string>;
1880
+ /**
1881
+ * RFC-303 D4:向全部已激活 monitor 派发宿主层事件(plugin 启停、settings 变更、tool 增减)。
1882
+ * 由宿主装配点(App)在对应事件发射时机调用;observer-only,R5 失败隔离由
1883
+ * MonitorsAxisHandler.dispatch 保证。引擎生命周期事件(turn.completed 等)仍走
1884
+ * HookTiming 派发(pluginMonitorsToSpecs),不经本通道。
1885
+ */
1886
+ emitMonitorEvent(event: MonitorEvent): Promise<void>;
1887
+ /**
1888
+ * M3:scheduler 就绪后对已启动 services 补跑 schedule 声明对账。
1889
+ * 委托 ServicesAxisHandler.reconcileAllSchedules()——详见该方法注释。
1890
+ */
1891
+ reconcileServiceSchedules(): void;
1892
+ /** 已激活 monitor 的插件 id 集合(观测/测试用)。 */
1893
+ get monitorPluginIds(): readonly string[];
1894
+ /**
1895
+ * 触发一个激活事件(如 `onCommand:foo`);若因此有插件从 deferred 转为可激活,
1896
+ * 对其重新执行一次完整 `reload()`(简单正确性优先于增量加载,插件数量级小)。
1897
+ * 真实触发点(RFC-124 P0-C):`onCommand:<name>`(interactive.ts 命令分发后)、
1898
+ * `onView:<panelId>`(extension-plugin.ts 打开插件面板时)、`onProvider:<api>`
1899
+ * (interactive-model.ts 模型切换后),均经 `App.firePluginActivationEvent()` 调用本方法。
1900
+ */
1901
+ activateOn(event: string, existingAgentNames: ReadonlySet<string>): Promise<AgentProfile[]>;
1902
+ /** computed 插件命令(FileCommand[])。供 cli 命令系统与 App.listFileCommands 并入。 */
1903
+ get commands(): FileCommand$1[];
1904
+ /**
1905
+ * RFC-151 D1:超时护城河 + try/catch 隔离调用单个插件的 onDeactivate。
1906
+ * 对齐 hook emit 的既有模式(hook-registry.ts:207-227):Promise.race + 5s 超时 +
1907
+ * unref() 防止定时器阻塞进程退出。挂起或抛错只 logger.warn,不阻塞其余插件。
1908
+ */
1909
+ private callOnDeactivate;
1910
+ /** 撤销全部轴上一轮的注册(cleanup() 进程退出路径用)。 */
1911
+ private unregisterAllAxes;
1912
+ /** RFC-216 D2:撤销**指定插件**在全部轴上一轮的注册(差量 reload 的 removed/changed 分支)。 */
1913
+ private unregisterPluginAxes;
1914
+ /**
1915
+ * RFC-216 D2:插件三维签名——unchanged 判定的唯一依据,任一维变化即 changed。
1916
+ * ① manifest 内容(JSON.stringify,复用 RFC-139 D2 已验证模式);
1917
+ * ② 信任裁决指纹(gated + pendingCapabilities 排序串)——能力刚被授予时 manifest 不变,
1918
+ * 但 register 的 fail-closed 分支结果不同,必须重装才能生效;
1919
+ * ③ plugin.ts / plugin.tsx 文件指纹(mtimeMs:size)——插件开发场景改代码不改 manifest。
1920
+ *
1921
+ * 指纹边界(RFC-216 对抗评审 P1):不追踪 plugin.ts 的传递依赖文件(import 的 src/*.ts)
1922
+ * 变更——对齐 RFC-150 D5「产物存在即用」的既有取舍(findPrebuiltOutfile 同样只比入口),
1923
+ * 生产环境代码变更应走 install/dev 路径,本判定不比现状差。
1924
+ */
1925
+ private pluginSignature;
1926
+ /**
1927
+ * 重载所有 active 插件的代码模块。先注销上轮 hook/skill(幂等 reload);对每个含 `plugin.ts` 的插件
1928
+ * 信任门后编译 + 进程内加载 → `module.hooks` 注册进引擎、`onActivate` 跑、computed 贡献并轴。失败 fail-soft
1929
+ * (loadPluginModule 内部 try/catch 返 null),不阻塞 reload。
1930
+ *
1931
+ * `existingAgentNames`=本轮已有声明式 agent 名(文件/otto/claude),用于 computed agents 去重(插件不夺名 R7,
1932
+ * 与 App.reloadPluginModules 等价:每插件按「原有名 + 早前插件已追加名」判重)。返回待追加进
1933
+ * App.declarativeAgentProfiles 的 computed agent profiles。
1934
+ */
1935
+ reload(existingAgentNames: ReadonlySet<string>): Promise<AgentProfile[]>;
1936
+ /** stop 清理:注销插件 hook + computed skill + provider + tools + firedEvents(防泄漏进 shared registry;provider 含 dispose)。 */
1937
+ cleanup(): Promise<void>;
1938
+ }
1939
+ //#endregion
1940
+ //#region src/app/plugin-provider-manager.d.ts
1941
+ /** PluginProviderManager 依赖面(同 PluginModuleManager 的 DI 范式,M100)。 */
1942
+ interface PluginProviderManagerDeps {
1943
+ providerRegistry: ProviderRegistry;
1944
+ authStore: AuthStore;
1945
+ modelRegistry: ModelRegistry;
1946
+ /** RFC-148 D3:声明式 provider 装载器(provider-loader.ts)惰性查表目标。 */
1947
+ wireProtocolRegistry: WireProtocolRegistry;
1948
+ activePlugins: () => DiscoveredPlugin$1[];
1949
+ /** RFC-124 C1/C2:信任门拒绝时的结构化告警(同 PluginModuleManagerDeps.logger 范式)。 */
1950
+ logger: Logger;
1951
+ }
1952
+ /**
1953
+ * 插件声明式 provider(`contributes.providers`)的加载/卸载单源(RFC-105 M105-2-03b)。
1954
+ *
1955
+ * 幂等 reload:每次调用先卸载上一轮已加载插件的 provider/model/envKey/descriptor,
1956
+ * 再对当前 `activePlugins()` 逐个装载——与 `PluginModuleManager.reload()` 同构(先注销后重注册,
1957
+ * 避免插件被禁用/卸载后残留僵尸 provider)。
1958
+ */
1959
+ declare class PluginProviderManager {
1960
+ private readonly deps;
1961
+ private loadedPluginIds;
1962
+ private previousSnapshot;
1963
+ constructor(deps: PluginProviderManagerDeps);
1964
+ /**
1965
+ * 幂等 reload:先卸载上一轮快照记录的全部插件 provider(保证禁用/卸载插件不残留僵尸),
1966
+ * 再对当前 `activePlugins()` 逐个装载并记录新快照。
1967
+ *
1968
+ * `pendingCapabilityPluginIds`(RFC-125 D5):因 `pendingCapabilities.includes('provider')`
1969
+ * 被跳过装载的插件 id 列表——不同于 `gated`(项目级未信任,需 `/trust plugin` 布尔信任),
1970
+ * 这批插件已通过布尔信任门(或天然 scope==='user'),只是高危能力尚未被显式授予
1971
+ * (`grantPluginCapabilities`)。此前该信号只留一条 `logger.warn`,从未传递到任何用户可见
1972
+ * 界面(见 RFC-125 §0.2/§0.4)——调用方据此列表在 `/model` 等界面呈现"待授权"提示。
1973
+ */
1974
+ reload(): Promise<{
1975
+ registered: number;
1976
+ rejected: number;
1977
+ pendingCapabilityPluginIds: string[];
1978
+ }>;
1979
+ /** 已加载声明式 provider 的插件 id 列表(观测用)。 */
1980
+ get activePluginIds(): readonly string[];
1981
+ /** stop 清理:卸载全部(防泄漏进 shared registry,同 PluginModuleManager.cleanup)。 */
1982
+ cleanup(): Promise<void>;
1983
+ }
1984
+ //#endregion
1985
+ //#region src/app/app.d.ts
1986
+ declare class App implements AppContext {
1987
+ readonly processOwnerId: string;
1988
+ /** 本 App 的进程归属 id(后台进程 register 时打的 owner 标;introspection/测试用)。 */
1989
+ get processOwner(): string;
1990
+ readonly settings: SettingsManager;
1991
+ readonly toolRegistry: ToolRegistry;
1992
+ readonly hookRegistry: HookRegistry;
1993
+ readonly providerRegistry: ProviderRegistry;
1994
+ /** RFC-148 D2b:Wire 协议实现注册表(key space = wireApi,与 providerRegistry 职责正交)。 */
1995
+ readonly wireProtocolRegistry: WireProtocolRegistry;
1996
+ /** App 持有 runtime 门面(contextSources/createSession/dispose 经此)。 */
1997
+ readonly agentRuntime: AgentRuntime;
1998
+ readonly codingSessionPool: SessionPool;
1999
+ readonly permissionRegistry: PermissionPolicyRegistry;
2000
+ readonly auditLog: PermissionAuditLog;
2001
+ readonly logger: Logger;
2002
+ /** 孤儿 trace 扫除(RFC-102 D3)依赖:关系化 repo 引用 + session 落盘根目录。 */
2003
+ sessionRepoRef?: {
2004
+ current?: SqliteSessionRepository;
2005
+ };
2006
+ sessionStorageDir?: string;
2007
+ /**
2008
+ * workspace 根目录——`workspaceRef` 就位后由 `ref.root` 派生,否则退回构造期
2009
+ * 传入值。L/R 形态下二者等价(start() 中 resolveLocal 把 workspaceDir 记入 ref.root);V 形态(无 root)
2010
+ * 当前零接线(设计保留在 RFC-034),此时退回到构造期传入值。
2011
+ */
2012
+ get workspaceDir(): string;
2013
+ private readonly _workspaceDir;
2014
+ /** 显式 workspace id(`--id` CLI flag),供 resolveLocal opts.id 覆盖。 */
2015
+ readonly _workspaceId?: string;
2016
+ /** 交互(TUI)态。仅交互态启用项目配置信任门(headless fail-open)。 */
2017
+ readonly _interactive: boolean;
2018
+ /**
2019
+ * RFC-345:影子模式(零落盘会话)。与 `@x-otto/env` 的 `isShadowModeEnabled()` 同源。
2020
+ * 供 App 层显式感知(D5 可见性标识 / D9 不参与 daemon 竞选);存储层内存化选择不读此
2021
+ * 字段,而在 §D1 白名单装配点直接查 env 函数——避免开关有第二真源。
2022
+ */
2023
+ readonly _shadow: boolean;
2024
+ /** 插件发现 user-scope homedir 覆盖(缺省用真实 `os.homedir()`,见 AppOptions.pluginHomedir 注释)。 */
2025
+ private readonly _pluginHomedir;
2026
+ /**
2027
+ * workspace 身份引用(resolve-or-create `.otto/workspace.json`,start() 中解析)。
2028
+ * 持 `key = ws_<id>`(持久化分区第一维)+ backend/root。供会话持久化分区 + memory 文件 scoping 消费。
2029
+ */
2030
+ workspaceRef?: WorkspaceRef;
2031
+ /**
2032
+ * start() 探测到本目录无 `.otto/workspace.json` 且处于交互态时置位——不自动创建 marker,
2033
+ * 等待 cli 层信任确认后调 `confirmWorkspaceInit()`(本次修复:防止 marker 缺失时静默生成新
2034
+ * 随机 id 导致 sessions.db 里旧会话因 workspace_key 对不上而"消失")。headless 态/`--id`
2035
+ * 显式给定/marker 已存在均不会置位(那些路径 start() 内直接完成解析,行为不变)。
2036
+ */
2037
+ pendingWorkspaceInit?: {
2038
+ root: string;
2039
+ };
2040
+ /**
2041
+ * start() 向上递归在**父级目录**(非当前目录)命中 `.otto/workspace.json` 时置位——
2042
+ * 不静默采用父级身份。等待 cli 层提示用户选择"使用上级 workspace"还是"在当前目录创建",
2043
+ * 防止 monorepo 子目录被意外吞入父 workspace。headless 态不触发(该路径 autoCreate 缺省
2044
+ * true,直接采用父级 marker,行为不变)。
2045
+ */
2046
+ parentWorkspaceExisted?: {
2047
+ parentRoot: string;
2048
+ currentRoot: string;
2049
+ marker: _$_x_otto_workspace0.WorkspaceMarker;
2050
+ };
2051
+ readonly maxSessions: number;
2052
+ readonly maxToolTurns: number;
2053
+ readonly maxToolTurnExtensions?: number;
2054
+ /** RFC-104 D3:app 级缺省 per-prompt 预算(CLI flags 透传)。 */
2055
+ readonly promptOutputTokenBudget?: number;
2056
+ readonly promptWallClockBudgetMs?: number;
2057
+ /** RFC-204 D1/D3:app 级缺省会话成本软预算美元(CLI flags 透传)。 */
2058
+ readonly sessionCostBudgetUSD?: number;
2059
+ /** RFC-204 D4:app 级缺省早期停滞检测配置(CLI flags 透传)。 */
2060
+ readonly stallDetection?: {
2061
+ windowTurns?: number;
2062
+ repeatThreshold?: number;
2063
+ } | false;
2064
+ readonly devtools: Devtools | null;
2065
+ /** 编辑文件面板回调。CLI 层在 startTui() 后将此属性接线到 tui.addEditedFile()。
2066
+ * hook 采用 getOnFileEdited 延迟求值——注册时 TUI 未就绪,emit 时通过此属性拿到回调。 */
2067
+ editFileCallback: EditFileCallback | undefined;
2068
+ readonly _editFilesDedup: Set<string>;
2069
+ /** RFC-118 S1:存储/记忆集群分组(memory/traceStore/checkpointStore 等 6 字段 + 远端配置标志)。 */
2070
+ readonly storage: AppStorage;
2071
+ /** 用户级记忆(~/.otto/memory,跨项目)。`#`=项目级,`/memory user`=用户级。
2072
+ * RFC-345 §D3:影子态用 overlay 包装——读穿透继承、写只进内存。 */
2073
+ readonly userMemory: AutoMemory;
2074
+ /** 一次性轻量模型补全(供 `#` 记忆 opt-in 智能命名等)。无模型时抛错由调用方兜底。 */
2075
+ readonly completeText: (prompt: string, opts?: {
2076
+ maxTokens?: number;
2077
+ signal?: AbortSignal;
2078
+ }) => Promise<string>;
2079
+ private readonly clock?;
2080
+ readonly fileStateManager: FileStateManager;
2081
+ readonly learningStore: OperationalLearningStore;
2082
+ /** 机器特定经验(scope='local',RFC-164 M164-1 D3),落 `.otto/local/lessons.json`,永不参与远端同步。 */
2083
+ readonly localLearningStore: OperationalLearningStore;
2084
+ /** 经验自动抽取编排器(接 session.idle;env OTTO_MEMORY_AUTO_EXTRACT 灰度开关,默认关)。 */
2085
+ readonly memoryAutoExtractor: MemoryAutoExtractor;
2086
+ readonly promptManager: PromptManager;
2087
+ readonly orchestrator: Orchestrator;
2088
+ runSession: ReturnType<typeof createTaskRunner>['runSession'];
2089
+ /** 会话级 Todo 存储(终局架构 review O2)——独立于 Orchestrator 持有。 */
2090
+ readonly writeTodos: WriteTodos;
2091
+ readonly sessionConfigResolver: SessionConfigResolver;
2092
+ readonly runTeam: RunTeam;
2093
+ readonly skillRegistry: SkillRegistry | null;
2094
+ /** RFC-138:插件 i18n 注册表(构造装配一次;/reload 经 CapabilityReloader 六轴重装)。 */
2095
+ readonly i18nRegistry: PluginI18nRegistry;
2096
+ /** RFC-125 D5:因 pendingCapabilities 含 provider 被跳过装载的插件 id(/extension 提示用)。 */
2097
+ _pendingProviderCapabilities: string[];
2098
+ /** 只读访问当前因待授权高危能力而被跳过的 provider 插件 id 列表(RFC-125 D5)。 */
2099
+ get pendingProviderCapabilities(): readonly string[];
2100
+ declarativeAgentProfiles: AgentProfile[];
2101
+ /** 统一可插拔项管理(/extension 命令后端:mcp / skill / agent 启停 + 落盘)。 */
2102
+ readonly extensions: ExtensionManager;
2103
+ /**
2104
+ * 插件输入注册表(#/@ sigil 条目,L1 数据权威单例)。
2105
+ * UI 表面通过 props 接收此引用。与 ExtensionManager 解耦——自有 register/unregisterBySource 生命周期。
2106
+ */
2107
+ readonly pluginInput: PluginInputRegistry$1;
2108
+ /**
2109
+ * @ 资源 resolve 注册表(RFC-210 D2):与 pluginInput(纯数据)平行的代码契约注册表。
2110
+ * 内置 resolver(file-range/@def;@changes/@git/@clipboard 已随 RFC-233 退役,@shortcut
2111
+ * 随 RFC-233 新增)在 buildPluginRegistrations 注册;插件 resolver 经 M3 sigil-loader
2112
+ * 装载(capability `input.resolver` 门控)。
2113
+ * 展开消费方:`expandSigilChips()`(cli 提交管线 / service expand 端点)。
2114
+ */
2115
+ readonly sigilResolvers: SigilResolverRegistry;
2116
+ /**
2117
+ * @ 资源统一展开出口(RFC-210 D2):扫描文本中全部 `[@kind:param]` chip 与
2118
+ * `@path:行范围`/`@def:符号` 引用,执行对应 resolver 替换为实际内容。
2119
+ * fail-soft:resolver 失败/超时 → chip 原样保留,不阻断提交。
2120
+ * opts.skipPrefixes:action 型 chip(如 @model)调用方声明式跳过;
2121
+ * opts.uiHost=false(service 场景):uiHostOnly resolver(@clipboard)跳过执行。
2122
+ */
2123
+ expandSigilChips(text: string, opts?: ExpandSigilChipsOptions): Promise<string>;
2124
+ /**
2125
+ * RFC-209 §2.3/§3.1:Feedback 业务契约宿主注册表(满意度评分记录/issue 提交)。
2126
+ * 核心层(interactive-events.ts 等)只通过本注册表接口调用具体插件实现(如
2127
+ * extensions/plugin-feedback),从不直接 import 插件代码(重要事项规则1)。
2128
+ */
2129
+ readonly feedbackRegistry: FeedbackRegistry;
2130
+ /**
2131
+ * RFC-233:用户自定义 `[@shortcut:name]` 文本快捷方式——单一权威门面,TUI(进程内
2132
+ * 直调)与 web-ui(经 service REST 路由调用同一方法)共用同一套增删改逻辑,避免
2133
+ * 两端各自实现一遍持久化/校验/sigil 条目刷新(重要事项规则同 draft/queue 数据模式,
2134
+ * 但走 App 门面而非各前端直接摸 settings)。
2135
+ */
2136
+ getShortcuts(): Array<{
2137
+ name: string;
2138
+ text: string;
2139
+ }>;
2140
+ /**
2141
+ * 新建或编辑(`previousName` 存在且与 `name` 不同时视为重命名——先删旧名再存新名,
2142
+ * 保持数组内相对顺序:重命名条目移到末尾,符合"最近编辑的排后面"直觉,同 draft 模式)。
2143
+ * 校验:`name` 非空、仅 `[A-Za-z0-9_-]`(chip 语法安全边界)、不与除自身外的既有名称重复;
2144
+ * `text` 非空。校验失败抛 `Error`(调用方——CLI handler / service 路由——各自决定
2145
+ * 如何呈现给用户,App 层不感知前端形态)。
2146
+ */
2147
+ saveShortcut(name: string, text: string, previousName?: string): Promise<void>;
2148
+ /** 删除指定名称的快捷方式(不存在则静默 no-op,对齐 draft handleDelete 的宽松语义)。 */
2149
+ deleteShortcut(name: string): Promise<void>;
2150
+ declarativeTeams: TeamDeclaration[];
2151
+ readonly mcpController: McpController;
2152
+ /** RFC-165 M3:插件面板后端控制器(backend facet 路由/门控/状态订阅)。 */
2153
+ readonly panelBackendController: PanelBackendController;
2154
+ /** @deprecated 内部重构为 McpController,保留 getter 兼容外部测试/示例。 */
2155
+ get mcpManager(): McpManager | null;
2156
+ disposed: boolean;
2157
+ ownedHookNames: string[];
2158
+ /** 跨会话失败信号(诊断原料)。tool isError 经 hook 记入;诊断据此提案。 */
2159
+ readonly failureSignals: FailureSignalStore;
2160
+ /** 诊断器——从复发硬信号生成改进提案(L1 只提不执行,去重防风暴)。/diagnose 消费。 */
2161
+ readonly diagnoser: Diagnoser;
2162
+ /** RFC-153 D3:插件健康度追踪(挂起/错误计数,内存态诊断原料,不跨进程持久化,规则 5)。
2163
+ * 三处写入点:M1 interceptor 超时(`onHookTimeout` 回调)、代码式工具超时
2164
+ * (`collect-plugin-perf-metrics.ts`)、插件加载/编译/工厂失败(`module-loader*.ts`)。
2165
+ * 读取点:`/extension` 详情面板(D4)。 */
2166
+ readonly pluginHealthTracker: PluginHealthTracker;
2167
+ /**
2168
+ * RFC-318 M1:受控能力(session.read / llm.complete)的配额与会话白名单。
2169
+ *
2170
+ * 必须是**单一实例**:`notifyPluginServices()` 在这里登记"某 sessionId 已下发给某插件",
2171
+ * `buildHostCapabilities` 的 readTranscript 闭包读同一份白名单——两处分家会让白名单
2172
+ * 恒空、读能力恒拒(fail-closed 方向安全,但功能全废)。
2173
+ */
2174
+ readonly pluginCapabilityQuota: PluginCapabilityQuota;
2175
+ /**
2176
+ * RFC-344 M2:人在环问询的统一队列与仲裁。
2177
+ *
2178
+ * 必须是**单一实例**:两类问询(agent grill 与插件 ask)共用 TUI 的
2179
+ * `resolvers.questions` 单槽位——分家会让"同一时刻只有一个问询在飞"的不变式失效,
2180
+ * 被覆盖的 Promise 永久挂死(见 `inquiry-center.ts` 头注释)。
2181
+ */
2182
+ readonly inquiryCenter: InquiryCenter;
2183
+ private userAskRenderer?;
2184
+ private userAskSeq;
2185
+ processRegistryUnsubs: Array<() => void>;
2186
+ private settingsLoaded;
2187
+ /** RFC-303 D4:settings.changed 事件桥接的上一次配置快照(首次 change 只快照不触发;
2188
+ * 逐键深比较只发变更键名,值不进入事件 payload——R8 脱敏)。 */
2189
+ private lastSettingsConfig;
2190
+ /**
2191
+ * RFC-230:统一重试/超时/退避配置。构造期只存程序化注入(`_resilienceOverride`),
2192
+ * 不在此计算最终值——`this.settings` 此时尚未 `load()`(settings 层配置永远读不到,
2193
+ * 见 RFC-230 §1.4 记录的 `workflowConfig` 同源时序 bug)。真正的合并求值延迟到
2194
+ * `ensureSettingsLoaded()` 完成后由 `freezeResilienceConfig()` 执行一次并冻结。
2195
+ */
2196
+ private readonly _resilienceOverride;
2197
+ private _resilienceConfig;
2198
+ defaultToolPreset: 'minimal' | 'standard' | 'full';
2199
+ private readonly permissionSync;
2200
+ readonly sandbox: SandboxController;
2201
+ /** RFC-115 M1:长驻进程内存自我感知(采样+分级)。M2/M3 后续接入降级/重启回调。 */
2202
+ readonly _memoryGovernor: MemoryGovernor;
2203
+ /** RFC-178 触发器 C:驻留收紧系数源(app-lifecycle 接分级信号;PersistenceSync 读系数)。 */
2204
+ readonly _residencyGovernor: ResidencyGovernor;
2205
+ /** RFC-196 M2:机器级进程群预算感知(10min 级 ps 枚举采样,独立于堆采样)。 */
2206
+ readonly _fleetMonitor: FleetMonitor;
2207
+ get tools(): AgentTool[];
2208
+ agentJobNotify?: (sessionId: string, n: AgentJobNotification) => void;
2209
+ agentJobServiceInstance?: AgentJobService;
2210
+ scheduleServiceInstance?: SchedulerService$1;
2211
+ /**
2212
+ * RFC-287 M4:生态检索实现(`capability_gap` 工具的数据源)。由 cli 层注入——
2213
+ * registry 客户端住在 cli 侧,coding 不反向依赖 cli。缺省 → 该工具不注册。
2214
+ */
2215
+ searchEcosystem?: _$_x_otto_tools0.SearchEcosystem;
2216
+ readonly notificationDispatcher: NotificationDispatcher;
2217
+ readonly presenceTracker: PresenceTracker;
2218
+ private followUpPendingProbe?;
2219
+ /** RFC-150 D2:活 session 工具重同步协调器(MCP 工具变化/`/reload` 后推送新工具集)。 */
2220
+ readonly toolsSyncCoordinator: SessionToolsSyncCoordinator;
2221
+ /** RFC-150 D1:MCP 非阻塞启动完成回调(交互模式晚绑定;已 settle 则闭包引用下一 tick 仍触发)。 */
2222
+ onMcpStartupSettled?: (result: {
2223
+ connected: number;
2224
+ failed: number;
2225
+ }) => void;
2226
+ /**
2227
+ * 竞态兜底:若 MCP 连接在宿主晚绑定回调**之前**就已完成(如 browser-use 单 server
2228
+ * 场景实测仅 ~114ms,可能快于 TUI 首帧渲染),先锁存结果;`setMcpStartupCallback` 内
2229
+ * 发现已有锁存值时立即补发一次,保证通知不会因为绑定时机竞态而静默丢失(RFC-150 规则 6)。
2230
+ */
2231
+ pendingMcpStartupResult?: {
2232
+ connected: number;
2233
+ failed: number;
2234
+ };
2235
+ /** 供宿主(cli 层)晚绑定 MCP 非阻塞启动完成回调(D1)。 */
2236
+ setMcpStartupCallback(cb: (result: {
2237
+ connected: number;
2238
+ failed: number;
2239
+ }) => void): void;
2240
+ /** RFC-148 M4:插件贡献查询域公共方法门面。 */
2241
+ private readonly pluginContributionsFacade;
2242
+ /**
2243
+ * 为给定 workspaceDir(= worktree 路径)组装工具集。委托 tool-wiring.ts(RFC-152 M4)。
2244
+ */
2245
+ buildToolsForWorkspace(workspaceDir: string): AgentTool[];
2246
+ /** 主会话已注册的 MCP 工具(`mcp__*`)。委托 tool-wiring.ts(RFC-152 M4)。 */
2247
+ private connectorTools;
2248
+ /** agent-session 作业服务(懒构造,确保 deps 就绪)。委托 app-agent-jobs.ts。 */
2249
+ get agentJobs(): AgentJobService;
2250
+ /** Wire schedule service(interactive setup 期构建)供 cron_* 工具消费。 */
2251
+ setScheduleService(scheduler: SchedulerService$1): void;
2252
+ /**
2253
+ * RFC-287 M4:晚绑定生态检索实现(供 `capability_gap` 工具)。对齐
2254
+ * `setScheduleService` 的晚绑定纹理——registry 客户端在 cli 层构造,coding 侧
2255
+ * 只持函数引用。注入的是**只读检索**,不含安装能力(R1:安装恒经用户信任门)。
2256
+ */
2257
+ setEcosystemSearch(search: _$_x_otto_tools0.SearchEcosystem): void;
2258
+ /**
2259
+ * RFC-115 M2:晚绑定内存压力回调——App 构造时活跃 session 尚不存在,interactive.ts 在
2260
+ * session 就绪后调用注入。onWarning 走 compactNow()(软降级),onCritical 交给调用方
2261
+ * (M3 弹 Dialog)。
2262
+ */
2263
+ get memoryGovernor(): MemoryGovernor;
2264
+ /** RFC-196 M2:进程群预算感知——CLI 层经此接 onBudgetExceeded TUI 通知。 */
2265
+ get fleetMonitor(): FleetMonitor;
2266
+ get modelRegistry(): ModelRegistry;
2267
+ get authStore(): AuthStore;
2268
+ /** 模型目录管理(实时拉取/落盘缓存/hydrate)。 */
2269
+ readonly modelCatalogManager: ModelCatalogManager;
2270
+ private readonly _modelRegistry;
2271
+ readonly _authStore: AuthStore;
2272
+ /** RFC-148 M2:ServiceHostPort 收窄——service 侧经窄方法消费,不再直捅 registry。
2273
+ * 委托 app-model-methods.ts(RFC-157 M2 T2.3,回收自已删除的 ModelFacade)。 */
2274
+ getAllModels(): Model[];
2275
+ resolveModel(spec: ModelSpec): Model;
2276
+ listProviders(): Api[];
2277
+ registerHook(spec: HookSpec): void;
2278
+ unregisterHook(name: string): boolean;
2279
+ /** 启动时把落盘模型缓存并回 registry。返回缓存确认「账号可用」的 id 集合。委托 app-model-methods.ts。 */
2280
+ hydrateModelCache(): Promise<Set<string>>;
2281
+ /** 会话级「账号可用模型」只读访问(cli --continue 据此保留恢复会话的集合)。 */
2282
+ getSessionAvailableModels(sessionId: string): string[];
2283
+ /** 实时拉取已认证 provider 的模型目录并入 registry + 落盘缓存。委托 ModelCatalogManager。 */
2284
+ refreshModels(): Promise<Array<{
2285
+ provider: string;
2286
+ status: 'ok' | 'skipped' | 'failed';
2287
+ added?: number;
2288
+ kept?: number;
2289
+ total?: number;
2290
+ availableIds?: string[];
2291
+ reason?: string;
2292
+ }>>;
2293
+ /**
2294
+ * 热重载能力——不重启进程认到 delegate 新加的 MCP / provider / 声明式 agent。
2295
+ * 编排逻辑已下沉到 CapabilityReloader(RFC-107 D4),此方法为薄调用兼容层。
2296
+ * 供 /reload 命令与 apply 后自动触发用。签名与返回值不变,消费方零感知。
2297
+ */
2298
+ reloadCapabilities(): Promise<{
2299
+ mcpTools: number;
2300
+ models: number;
2301
+ agents: number;
2302
+ teams: number; /** RFC-125 D5:因待授权高危能力被跳过的 provider 插件 id 列表(新增可选消费字段)。 */
2303
+ pendingProviderCapabilities: string[]; /** RFC-138 D6:本轮热重载装配的插件 i18n 字符串条目总数(第六轴)。 */
2304
+ i18nEntries: number;
2305
+ }>;
2306
+ /** RFC-150 D2:活 session 工具重同步(/reload 后调用)。委托 SessionToolsSyncCoordinator。 */
2307
+ syncSessionTools(): number;
2308
+ /** 单 session 工具重同步(`/model` 切换后按新 model.supportsTools 刷新 tools 快照)。 */
2309
+ syncSessionToolsFor(sessionId: string): boolean;
2310
+ /** 插件拓扑状态管理(RFC-152 M2):activePlugins()/diagnoseTopoSortIssues() 委托目标。 */
2311
+ private readonly pluginTopology;
2312
+ /** 插件代码模块(plugin.ts)的加载/接线/卸载——三段 computed 状态 + reload + cleanup(ARCH-083-01)。 */
2313
+ readonly pluginModuleManager: PluginModuleManager;
2314
+ /** 插件声明式 provider(`contributes.providers`)的加载/卸载单源(RFC-105 M105-2-03b)。 */
2315
+ readonly pluginProviderManager: PluginProviderManager;
2316
+ /** 五轴能力热重载编排器(RFC-107 D4)。 */
2317
+ private readonly capabilityReloader;
2318
+ /** computed 插件命令(FileCommand[])。供 cli 命令系统与 listFileCommands 并入。委托 PluginContributionsFacade。 */
2319
+ computedPluginCommands(): FileCommand$1[];
2320
+ get sessionManager(): SessionPool;
2321
+ /** RFC-325 M5:供 `otto doctor attach <pid>` 受控读取的只读聚合诊断入口。 */
2322
+ getResidencyDiagnostics(): _$_x_otto_runtime0.ResidencyDiagnostics;
2323
+ globalLogSubscription: ReturnType<typeof attachLogListener> | null;
2324
+ constructor(options: AppOptions);
2325
+ /** 委托 app-lifecycle.ts ensureReady helper。 */
2326
+ ensureSettingsLoaded(): Promise<void>;
2327
+ /**
2328
+ * RFC-230:合并四层配置源(程序化注入 > settings > env > 默认值)并冻结——只在
2329
+ * `ensureSettingsLoaded()` 完成后首次调用时真正计算,之后的调用是 no-op(幂等,
2330
+ * 应对 `ensureSettingsLoaded()` 可能被多处调用点重复触发,如 `createSession()`)。
2331
+ */
2332
+ private freezeResilienceConfig;
2333
+ /** RFC-323 M4:注入式驻留配置(settings > 默认;env 由常量层已处理,见下)。 */
2334
+ private _residencyConfig;
2335
+ /**
2336
+ * RFC-323 M4:把 .otto/config.json(otto 原生配置,非 Claude 的 settings.json)的
2337
+ * residency 配置冻结为注入对象。
2338
+ *
2339
+ * 优先级 env > settings > 默认的实现约定(D6b):session-contract 常量本身已是
2340
+ * `normalizeEnv(env, 默认)` 的结果——env 显式设置时常量即为 env 值。故此处**仅当对应
2341
+ * env 未设置时**才取 settings 值,交给 resolveResidencyBudget 与常量合并。env 已设则
2342
+ * 留空该字段 → resolveResidencyBudget 回退到常量(= env 值),保证 env 最高优先级。
2343
+ */
2344
+ private freezeResidencyConfig;
2345
+ /** RFC-323 M4:注入给 persistence-sync / memory 侧的驻留配置只读查询。 */
2346
+ getResidencyConfig(): ResidencyBudgetConfig | undefined;
2347
+ /**
2348
+ * RFC-230:统一重试/超时/退避配置只读查询 API——诊断命令(如未来的 `otto doctor`/
2349
+ * `/config show`)据此展示当前生效值。冻结前调用(即 `ensureSettingsLoaded()`/`start()`
2350
+ * 尚未完成时)显式抛错,而非静默返回只含 env+默认值的半成品配置——防止调用方误以为
2351
+ * 拿到的已经是最终生效值(这是 v1 草案 P0 缺陷的直接防呆,见 RFC-230 §3 D5)。
2352
+ */
2353
+ getResilienceConfig(): ResilienceConfig;
2354
+ /** 「始终允许」某工具(R8-B):ask→allow 幂等升级(deny 不动)。委托 app-permission-methods.ts
2355
+ * (RFC-157 M2 T2.3,回收自已删除的 PermissionFacade)。 */
2356
+ allowToolAlways(toolName: string, sessionId?: string): Promise<void>;
2357
+ /** 当前权限 mode。缺省 'auto'。委托 app-permission-methods.ts。 */
2358
+ getPermissionMode(): PermissionMode;
2359
+ /** 设置权限 mode:persist 落盘 → reload → change → permissionSync 重同步。委托 app-permission-methods.ts。 */
2360
+ setPermissionMode(next: PermissionMode): Promise<void>;
2361
+ /** 某会话的「始终允许」工具名快照(弹窗运行时授权,不含项目级基线)。委托 app-permission-methods.ts。 */
2362
+ getSessionAlwaysAllow(sessionId: string): string[];
2363
+ /**
2364
+ * bash 命令的「始终允许」两段前缀提取(如 `git status`,而非整个 bash 工具)。
2365
+ * 终局架构 review 2026-07-10 P1-5:转发 @x-otto/hooks 纯函数,前端不再直连引擎权限模块。
2366
+ */
2367
+ bashAlwaysAllowPrefix(command: string): string | null;
2368
+ /**
2369
+ * 校验一条 always-allow 字符串是否格式良好(`/permissions add` 落盘前的守门)。
2370
+ * 终局架构 review 2026-07-10 P1-5:转发 @x-otto/hooks 纯函数,前端不再直连引擎权限模块。
2371
+ */
2372
+ isWellFormedAllowEntry(entry: string): boolean;
2373
+ /** 移除一条项目级「始终允许」(/permissions remove):撤 registry + 抹持久化。返回是否命中。委托 app-permission-methods.ts。 */
2374
+ disallowToolAlways(toolName: string): Promise<boolean>;
2375
+ /** 清空某会话的「始终允许」(/permissions clear):撤销 registry + 抹掉持久化字段。委托 app-permission-methods.ts。 */
2376
+ clearSessionAlwaysAllow(sessionId: string): void;
2377
+ /**
2378
+ * 当前活跃插件(bundle 启停的统一发现点)。委托 PluginTopologyManager(RFC-152 M2)。
2379
+ * 应用 `disabled_plugins` 过滤——禁用插件不返回,其 skill/agent/command/mcp 贡献全部消失。
2380
+ * 各轴发现(skill/agent 经此注入;command 经 cli 调用此方法;mcp 控制器自带 settings 等价过滤)共用。
2381
+ */
2382
+ activePlugins(): DiscoveredPlugin$1[];
2383
+ /**
2384
+ * 插件拓扑排序 fail-closed 诊断。委托 PluginTopologyManager(RFC-152 M2)。
2385
+ * RFC-163 D5:签名改为 async(诊断内部追加缺失依赖自动补装尝试,见 PluginTopologyManager.diagnose)。
2386
+ * RFC-219 M1(对抗审核 F1 修复):传入 `this.settings`,使自动补装成功后能记录到
2387
+ * installed_plugins 清单(此前只落 symlink,导致清单与磁盘状态永久性不一致)。
2388
+ */
2389
+ diagnoseTopoSortIssues(): Promise<void>;
2390
+ /** ServiceHostPort:文件命令目录。委托 PluginContributionsFacade。 */
2391
+ listFileCommands(): FileCommand$1[];
2392
+ /** ServiceHostPort:调用 MCP server 上的指定 tool(RFC-081)。委托 PluginContributionsFacade。 */
2393
+ callMcpTool(serverName: string, toolName: string, params?: Record<string, unknown>): Promise<{
2394
+ content: {
2395
+ type: string;
2396
+ text?: string;
2397
+ }[];
2398
+ isError?: boolean;
2399
+ }>;
2400
+ /** RFC-081:TUI 插件面板列表。完整注释见 `PluginContributionsFacade.getPluginPanelRegistrations`。 */
2401
+ getPluginPanelRegistrations(): PanelRegistration[];
2402
+ /** RFC-105 D5:状态栏插件条目(/extension 详情页按 id 过滤用)。完整注释见 facade 同名方法。 */
2403
+ getPluginStatusItems(): ResolvedStatusItem[];
2404
+ /** RFC-105 D5:全局菜单插件贡献(/extension 列表页消费)。完整注释见 facade 同名方法。 */
2405
+ getGlobalMenuItems(): ResolvedAction$1[];
2406
+ /** RFC-105 D6:插件消息渲染器(/extension 详情页按 id 过滤用)。完整注释见 facade 同名方法。 */
2407
+ getPluginRenderers(): RegisteredRenderer[];
2408
+ /** RFC-184 D2/D3:插件状态栏代码式徽标(RFC-206 M9 前置子任务②新增公开代理方法——
2409
+ * facade 侧原已实现但此前未在 App 上公开,web-ui catalog 端点需要它)。完整注释见
2410
+ * facade 同名方法。 */
2411
+ getPluginStatusWidgets(): RegisteredStatusWidget[];
2412
+ /** RFC-187 D3/D4:插件文件查看器候选。完整注释见 facade 同名方法。 */
2413
+ getPluginFileViewers(): RegisteredFileViewer[];
2414
+ /** RFC-209 §2.5/§3.1:Feedback 插件是否已装载(ServiceHostPort 消费,见该接口同名方法注释)。 */
2415
+ isFeedbackAvailable(): boolean;
2416
+ /** RFC-209 §2.5:满意度脉冲调查触发配置读取(ServiceHostPort 消费,见该接口同名方法注释)。 */
2417
+ getPulseSurveyConfig(): {
2418
+ enabled?: boolean;
2419
+ probability?: number;
2420
+ min_turn_gap?: number;
2421
+ };
2422
+ /** RFC-209 §2.5:满意度评分记录(fail-soft,插件未装载时静默丢弃)。 */
2423
+ recordPulseSurvey(entry: _$_x_otto_plugin0.PulseSurveyEntry): void;
2424
+ /**
2425
+ * RFC-209 §2.5/重要事项规则7:两端共用的 issue URL 构造——**只调用 `buildIssueUrl`**,
2426
+ * 绝不引用 `submitIssueViaGh`(本方法体内物理上没有到达 gh CLI 调用路径的代码)。
2427
+ */
2428
+ buildFeedbackIssueUrl(input: _$_x_otto_plugin0.FeedbackIssueInput): string | undefined;
2429
+ /**
2430
+ * RFC-348 M1:ServiceHostPort settings 写面——委托 `SettingsManager.update()`。
2431
+ * service 的 settings route 四个写端点(PUT /、POST /mode、POST /autonomy、
2432
+ * POST /thinking)经本方法调 `settings.update()`,persist + change 事件语义不变。
2433
+ */
2434
+ updateSettings(overrides: Partial<_$_x_otto_setting0.Setting>): Promise<_$_x_otto_setting0.Setting>;
2435
+ /**
2436
+ * RFC-210 D5(M4):跨端渲染 toPayload 执行出口(ServiceHostPort 契约实现)。
2437
+ * 装载走 loadAllPluginA2uiRenderers(capability `a2ui.renderer` 三层信任门);
2438
+ * 执行 fail-soft(超时 2s/抛错 → 下一候选 → null 回退默认渲染)。
2439
+ * 每次调用重新装载列表的成本由 loadAllCompiledContributions 的 require cache 抵消
2440
+ * (模块首装后 require 命中缓存,只余 matcher 循环——与 renderers 轴 getPluginRenderers
2441
+ * 同款每调用重扫模式,插件启停后无需失效通知)。
2442
+ */
2443
+ resolveA2uiRendererPayload(message: unknown): Promise<_$_x_otto_interchange0.A2uiComponent[] | null>;
2444
+ /** RFC-131 T8:聚合插件 TUI 贡献(`TuiHandle.setPluginRegistrations` 统一入口)。完整注释见 `PluginContributionsFacade.getPluginRegistrations`。 */
2445
+ getPluginRegistrations(): Array<{
2446
+ pluginId: string;
2447
+ renderers?: RegisteredRenderer[];
2448
+ statusItems?: {
2449
+ id: string;
2450
+ text: string;
2451
+ }[];
2452
+ panels?: PanelRegistration[];
2453
+ a2uiComponents?: RegisteredA2uiComponent[];
2454
+ statusWidgets?: RegisteredStatusWidget[];
2455
+ fileViewers?: RegisteredFileViewer[];
2456
+ }>;
2457
+ /** RFC-105 D7:触发插件激活事件(匹配 activationEvents 的 deferred 插件执行完整 reload)。 */
2458
+ firePluginActivationEvent(event: string): Promise<void>;
2459
+ start(): Promise<void>;
2460
+ completeWorkspaceDependentStartup(): Promise<void>;
2461
+ needsWorkspaceInit(): boolean;
2462
+ confirmWorkspaceInit(): Promise<WorkspaceRef | undefined>;
2463
+ hasParentWorkspace(): boolean;
2464
+ adoptParentWorkspace(): Promise<WorkspaceRef | undefined>;
2465
+ createLocalWorkspace(): Promise<WorkspaceRef | undefined>;
2466
+ setWorkspaceMemorySyncEnabled(enabled: boolean): Promise<boolean>;
2467
+ sweepOrphanTraceFiles(): Promise<void>;
2468
+ stop(): Promise<void>;
2469
+ /** 委托 app-session-methods.ts(RFC-157 M2 T2.4,回收自已删除的 SessionFacade)。 */
2470
+ createSession(options?: CodingSessionOptions): Promise<AgentSession$1>;
2471
+ /** 注册一个通知交付通道(终端/带外/应用内)。前端接线入口。委托 app-notification-methods.ts。 */
2472
+ registerNotificationChannel(channel: NotificationChannel): void;
2473
+ /** 注册应用内通知通道(TUI NotificationCenter;透传原始 kind,视觉映射归 UI)。委托 app-notification-methods.ts。 */
2474
+ registerInAppNotificationChannel(push: (title: string, message: string, kind: NotificationKind$1) => void): void;
2475
+ /** RFC-344 M3:TUI 层设置/清除阻塞式问询渲染器。headless 不设置时 user.ask fail-closed。 */
2476
+ setUserAskRenderer(renderer: ((question: GrillQuestion) => Promise<GrillAnswer>) | undefined): void;
2477
+ private askPluginUser;
2478
+ /** TUI 可选在每次按键调用,喂更细的在场信号(默认已由 prompt.start 粗粒度喂入)。委托 app-notification-methods.ts。 */
2479
+ notifyUserInteraction(): void;
2480
+ /** DEC1004 焦点事件(opt-in OTTO_TUI_FOCUS=1)。TUI 解析 \x1b[I/\x1b[O 后调用。委托 app-notification-methods.ts。 */
2481
+ setTerminalFocus(focused: boolean): void;
2482
+ /** TUI 注入"有待跑 follow-up"探针(读 state.queued);有则抑制 turn_complete 通知。 */
2483
+ setFollowUpPendingProbe(probe: () => boolean): void;
2484
+ /**
2485
+ * RFC-318 D9:向全部运行中的 service 广播一条宿主事件通知。
2486
+ *
2487
+ * **这是 `session.read` 能力的授权入口**:每成功送达一次通知,就把该 sessionId 登记进
2488
+ * 目标插件的白名单并开启新配额 epoch。因此"插件能读哪个会话"完全由宿主的通知行为决定,
2489
+ * 插件无法自行扩大可读范围(RFC-318 R2)。
2490
+ *
2491
+ * 尽力而为:未运行/已停机的 service 直接跳过,不抛错——通知是旁路信号,不该让某个插件
2492
+ * 的状态影响宿主主循环。返回实际送达的 `<pluginId>:<serviceId>` 数量,供调用方记账。
2493
+ */
2494
+ notifyPluginServices(notification: SessionIdleNotification): number;
2495
+ /**
2496
+ * RFC-327 D2:向**指定**插件服务投递一次 schedule 到点通知。
2497
+ *
2498
+ * **与 `notifyPluginServices` 的关键区别(安全边界,不可合并)**:
2499
+ * 1. **定向而非广播**——只投给订阅该 schedule 的那一个 service,其他插件收不到;
2500
+ * 2. **不开会话授权 epoch**——`schedule.tick` 没有 sessionId,绝不调用
2501
+ * `onNotifyDelivered`。后者是插件获得 `readTranscript` 的唯一入口,若在此误调,
2502
+ * 定时任务将成为绕过"宿主决定插件能读哪个会话"(RFC-318 R2)的提权旁路。
2503
+ *
2504
+ * 服务要产生工作仍须自己走 capability-gated `startJob`——timer 触发不携带、也不授予
2505
+ * 任何额外能力。返回是否送达(服务未运行 = false,调度器据此记日志,不重试)。
2506
+ */
2507
+ notifyPluginServiceSchedule(subscriber: {
2508
+ pluginId: string;
2509
+ serviceId: string;
2510
+ }, tick: {
2511
+ scheduleId: string;
2512
+ occurrenceId: string;
2513
+ occurredAt: number;
2514
+ }): boolean;
2515
+ /** 委托 app-session-methods.ts。 */
2516
+ getSession(id: string): AgentSession$1 | undefined;
2517
+ /** 委托 app-session-methods.ts。 */
2518
+ shareSession(sessionId: string, opts: {
2519
+ visibility: 'private' | 'shared';
2520
+ }): Promise<void>;
2521
+ /** 委托 app-session-methods.ts。 */
2522
+ getActiveSession(): AgentSession$1 | undefined;
2523
+ /** 委托 app-session-methods.ts。 */
2524
+ listSessions(filter?: {
2525
+ workspaceId?: string;
2526
+ }): AgentSessionInfo$1[];
2527
+ /**
2528
+ * listSessions() 的超集——额外并入持久化后端已知但尚未加载进内存的会话。
2529
+ * 详见 app-session-methods.ts listAllSessions 的完整设计注释(RFC-146)。委托 app-session-methods.ts。
2530
+ */
2531
+ listAllSessions(filter?: {
2532
+ workspaceId?: string;
2533
+ }): Promise<AgentSessionInfo$1[]>;
2534
+ /** 委托 app-session-methods.ts。 */
2535
+ removeSession(id: string): Promise<boolean>;
2536
+ /** 委托 app-session-export.ts(RFC-199 M1 提取)。 */
2537
+ exportSessionArchive(sessionId: string, outPath: string): Promise<SessionArchiveExport>;
2538
+ /** 委托 app-session-methods.ts。 */
2539
+ archiveSession(id: string): Promise<boolean>;
2540
+ /** 委托 app-session-methods.ts。 */
2541
+ forkSession(sourceId: string, newId?: string): Promise<AgentSession$1 | undefined>;
2542
+ /**
2543
+ * 引擎 spawn 路径可见的声明式 agent——按 settings.disabled_agents 过滤(/extension 切换的真源)。
2544
+ * 每次调用重读 settings → 运行时切换下次 spawn 生效,无需重建。空禁用集时返回原数组(零开销)。
2545
+ */
2546
+ private getEnabledAgentProfiles;
2547
+ /** 工具注册表初始化。委托 tool-wiring.ts(RFC-152 M4)。 */
2548
+ private initToolRegistry;
2549
+ /** list_models 工具的目录——registry 全量 + 会话级可用集合 + usability gate 标记。委托 app-model-methods.ts。 */
2550
+ buildModelCatalog(sessionId?: string): Promise<Array<{
2551
+ id: string;
2552
+ provider: string;
2553
+ strengths: string[];
2554
+ available: boolean;
2555
+ usable: boolean;
2556
+ unusableReason?: string;
2557
+ }>>;
2558
+ /** 写会话级「账号可用模型」(随快照持久化,--continue 回灌)。委托 app-model-methods.ts。 */
2559
+ setSessionAvailableModels(sessionId: string, modelIds: readonly string[]): void;
2560
+ /** hook 注册装配。委托 tool-wiring.ts(RFC-152 M4)。 */
2561
+ private registerHooks;
2562
+ /** 当前生效的沙箱策略名(null = 无沙箱)。可观测面:测试/调试/CLI 状态展示。 */
2563
+ get activeSandbox(): string | null;
2564
+ /**
2565
+ * M4 1b-2:标记一个命令为「已批准绕过沙箱」(会话级)。
2566
+ * cli 在沙箱升级 ask 被用户批准时调用——该命令后续执行不再套沙箱(用户已审,
2567
+ * = Codex approval=escalated)。仅沙箱启用时有意义;未启用时无副作用。
2568
+ */
2569
+ approveSandboxBypass(command: string): void;
2570
+ ensureNotDisposed(): void;
2571
+ }
2572
+ declare function createApp(options: AppOptions): App;
2573
+ //#endregion
2574
+ //#region src/app/frontend-port-factory.d.ts
2575
+ /**
2576
+ * 构造 `FrontendPort` 实现(引擎侧唯一装配点)。前端宿主(进程内嵌入时 = 前端自己的
2577
+ * 装配入口,如 feishu-use bridge)调用一次,得到的端口对象即前端业务代码的全部消费面——
2578
+ * 不再需要 import 任何 `@x-otto/coding`/`@x-otto/runtime` 具体类型。
2579
+ *
2580
+ * 入参类型刻意用具体类 `App`(而非收窄接口 `AppContext`)——本工厂本身是引擎侧代码,
2581
+ * 职责正是把完整实现(`App` 的全部 public 成员,含未列入 `AppContext` 接口的
2582
+ * `i18nRegistry` 等)收窄成 `FrontendPort` 契约给前端消费。前端业务代码永远只接触
2583
+ * `createFrontendPort` 的返回值,不持有 `App` 本身。
2584
+ */
2585
+ declare function createFrontendPort(app: App): FrontendPort;
2586
+ //#endregion
2587
+ //#region src/input/builtin-resolvers.d.ts
2588
+ /** 只读 git 执行器(测试可注入)。返回 null 表示失败/非 git 仓。 */
2589
+ type GitRunner = (args: readonly string[], cwd: string) => string | null;
2590
+ interface BuiltinResolverDeps {
2591
+ /** 只读 git 执行器(测试注入)。 */
2592
+ gitRunner?: GitRunner;
2593
+ }
2594
+ /**
2595
+ * 构造两个内置 resolver:file-range / def(正则型引用,id 由 sigil-expand.ts
2596
+ * collectChips 固定映射)。
2597
+ */
2598
+ declare function createBuiltinResolvers(deps?: BuiltinResolverDeps): SigilResolver[];
2599
+ //#endregion
2600
+ //#region src/plugin/plugin-scoped-storage.d.ts
2601
+ /**
2602
+ * 清理某插件的全部 plugin-state(`otto extension purge <id>` 出口,RFC-303 D3/M6 接线)。
2603
+ * 只删除该插件的子目录,不影响其他插件;插件不存在/目录不存在时幂等成功。
2604
+ */
2605
+ declare function purgePluginState(pluginId: string): {
2606
+ removed: boolean;
2607
+ dir?: string;
2608
+ };
2609
+ //#endregion
2610
+ //#region src/plugin/mcp.d.ts
2611
+ /**
2612
+ * mcp.ts —— 插件 `.mcp.json` 解析(RFC-044 M044-02-07,并行 `resolveClaudeMcpServers`).
2613
+ *
2614
+ * 读各已发现插件目录 `<dir>/.mcp.json` 的 mcp_servers(回退兼容 mcpServers),作**最低优先级**合并进 McpController
2615
+ * (otto/claude 同名覆盖插件,R7)。`.mcp.json` = 可执行面(stdio server 启动即跑二进制),
2616
+ * 故项目级未信任插件(gated)跳过(RFC-044 R4);`contributes.mcp===false` 亦跳过。
2617
+ * 只读导入:插件 server 不参与 setServerEnabled 落盘。
2618
+ */
2619
+ interface ResolvePluginMcpOptions {
2620
+ workspaceDir: string;
2621
+ homedir: string;
2622
+ /** 被禁用插件 id(RFC-044 bundle 启停);转发给 discoverPlugins 过滤。 */
2623
+ disabled?: readonly string[];
2624
+ /** 缺省自动发现;可注入供测试。 */
2625
+ plugins?: DiscoveredPlugin$1[];
2626
+ }
2627
+ declare function resolvePluginMcpServers(opts: ResolvePluginMcpOptions): Record<string, McpServerConfig>;
2628
+ //#endregion
2629
+ //#region src/plugin/install-plugin.d.ts
2630
+ interface InstallPluginResult {
2631
+ /** 插件 id(来自包内 otto-plugin.json)。 */
2632
+ id: string;
2633
+ /** 解析到的包目录(软链目标)。 */
2634
+ packageDir: string;
2635
+ /** 安装位置 `<ottoDir>/plugins/<id>`(软链)。 */
2636
+ dir: string;
2637
+ /** 首次创建(true)还是刷新既有安装(false)。 */
2638
+ created: boolean;
2639
+ /**
2640
+ * RFC-150 D5:安装时编译产生的非致命警告(plugin.ts/面板编译失败)。空数组 = 编译
2641
+ * 全部成功或该插件无需编译内容(纯声明式插件)。调用方应向用户展示这些警告,不静默。
2642
+ */
2643
+ compileWarnings: string[];
2644
+ /**
2645
+ * 插件声明的版本号(来自 `otto-plugin.json` manifest,可选字段)(RFC-219 M1)。
2646
+ * 供调用方写入 `installed_plugins` 清单的 version 字段,供审计展示用途。
2647
+ */
2648
+ version?: string;
2649
+ }
2650
+ interface InstallPluginFromPackageOptions {
2651
+ /** 包名或包内路径(`createRequire` 可解析),如 `@x-otto/plugin-browser-use-mcp`。 */
2652
+ pkg: string;
2653
+ /** 插件根所在 otto 目录。默认 `OTTO_HOME`(用户级,自动受信任)。 */
2654
+ ottoDir?: string;
2655
+ /** 解析包的基准目录(默认 `process.cwd()`);缺失时回退宿主自身位置(workspace 依赖)。 */
2656
+ cwd?: string;
2657
+ }
2658
+ /**
2659
+ * 解析包目录(含 package.json 的目录)。优先级:① 从 `cwd` 解析(用户项目里
2660
+ * `npm install` 了某个 otto 插件包的真实依赖场景);② 从宿主自身位置解析(宿主
2661
+ * 对该包有真实 `package.json` 依赖声明的场景,如未来首方扩展改为显式依赖);
2662
+ * ③ workspace glob 扫描 fallback(本仓首方扩展的真实生效路径,不依赖 node_modules
2663
+ * 软链,见 `resolveViaWorkspaceGlob` 文档)。
2664
+ */
2665
+ declare function resolvePackageDir(pkg: string, cwd?: string): string | undefined;
2666
+ /**
2667
+ * 通用安装:软链包目录进 `<ottoDir>/plugins/<id>`。幂等——已指向同包的软链原样返回;
2668
+ * 既有(软链或我们之前物化的同 id 目录)则替换;目标是他物则拒绝覆盖。
2669
+ *
2670
+ * RFC-150 D5:软链就位后总是编译一次(`created:true`/`false` 均编译,非仅首装)——
2671
+ * 保证幂等调用后产物一定新鲜(如用户从旧版本升级、`plugin-dist/` 产物此前从未生成过的
2672
+ * 场景,仅在 `created:true` 时编译会遗漏这种情况)。单插件编译成本极低(实测 13-50ms),
2673
+ * install 本就是用户主动触发的非热路径动作,可接受。
2674
+ */
2675
+ declare function installPluginFromPackage(opts: InstallPluginFromPackageOptions): Promise<InstallPluginResult>;
2676
+ /**
2677
+ * 从本地目录安装插件(RFC-122 物理迁移:首方 provider 插件安装)。
2678
+ *
2679
+ * 把 `sourceDir`(包含 `otto-plugin.json` 的目录)symlink 到 `~/.otto/plugins/<id>`。
2680
+ * 已存在同 id 的旧安装会被替换;非插件目录会整体 throw。
2681
+ *
2682
+ * 用户级安装默认受信任(`~/.otto/plugins/` 不受 trust 门限制,同 `installPluginFromPackage`)。
2683
+ * RFC-150 D5:同 `installPluginFromPackage`,软链就位后总是编译一次。
2684
+ */
2685
+ declare function installPluginFromDir(sourceDir: string): Promise<InstallPluginResult>;
2686
+ //#endregion
2687
+ //#region src/plugin/installed-plugins-registry.d.ts
2688
+ /**
2689
+ * 新增或更新一个已安装插件条目(幂等:同 id 覆盖,不追加重复项)。
2690
+ * 返回新数组(不修改入参),符合 settings.persist 的不可变更新模式。
2691
+ */
2692
+ declare function upsertInstalledPluginEntry(entries: readonly InstalledPluginEntry[], entry: InstalledPluginEntry): InstalledPluginEntry[];
2693
+ /**
2694
+ * 移除一个已安装插件条目(卸载时调用)。id 不存在时返回原数组等价副本(不报错,幂等)。
2695
+ */
2696
+ declare function removeInstalledPluginEntry(entries: readonly InstalledPluginEntry[], id: string): InstalledPluginEntry[];
2697
+ /**
2698
+ * 记录一次插件安装到 `installed_plugins` 清单(RFC-219 M1 接线)。供 CLI `otto extension
2699
+ * install`(`pluginInstall`)与 TUI 安装路径(`runPluginInstall`)在
2700
+ * `installPluginFromPackage`/`installPluginFromDir` 成功返回后调用。
2701
+ *
2702
+ * 不在 `install-plugin.ts` 内部调用本函数——保持该模块"零 settings 依赖、宿主对具体插件
2703
+ * 零认知"的既有边界(RFC-148 框架层零厂商知识纪律),配置维护是调用方职责。
2704
+ */
2705
+ declare function recordPluginInstalled(settings: SettingsManager, entry: {
2706
+ id: string;
2707
+ source: InstalledPluginEntry['source'];
2708
+ sourceSpec: string;
2709
+ version?: string;
2710
+ scope: InstallScope$1;
2711
+ /**
2712
+ * 安装时声明的高危能力快照(RFC-219 D1c)。调用方在安装前已用
2713
+ * `readHighRiskCapabilities()` 计算过该值(用于信任确认弹窗),此处复用同一结果,
2714
+ * 不重新读盘。
2715
+ */
2716
+ capabilities?: string[];
2717
+ }, now?: () => number): Promise<void>;
2718
+ /**
2719
+ * 从 `installed_plugins` 清单移除一个条目,并清理该插件在 `disabled_plugins`/
2720
+ * `plugin_lifecycle.setupDone` 中的残留(卸载时调用)。供 `@x-otto/install` `uninstall()`
2721
+ * 的 plugin 分支在删除 symlink 成功后调用(见 packages/install/src/uninstaller.ts)。
2722
+ *
2723
+ * 这是 RFC-219 D1 规则1"引导修复的正向对应"——**用户主动卸载**是唯一允许清理这些
2724
+ * 配置残留的路径(区别于对不一致状态的"自动双向纠正",后者禁止)。三处残留一次性
2725
+ * 清理是本函数存在的意义:不清理会导致重装同 id 插件时误继承旧的禁用/setup 状态。
2726
+ */
2727
+ declare function recordPluginUninstalled(settings: SettingsManager, id: string): Promise<void>;
2728
+ /** 一致性告警的两种形态(RFC-219 D1:只告警,不自动修复)。 */
2729
+ type PluginConsistencyWarning = {
2730
+ kind: 'missing-on-disk';
2731
+ id: string;
2732
+ message: string;
2733
+ } | {
2734
+ kind: 'missing-in-registry';
2735
+ id: string;
2736
+ message: string;
2737
+ };
2738
+ /**
2739
+ * 比对"清单"(`installed_plugins`,逻辑记录)与"磁盘发现"(`discoverPlugins()` 结果,
2740
+ * 物化形态)——不一致时产出告警,不做任何修复动作。
2741
+ *
2742
+ * 只比对清单里 `scope: 'global'`(`@x-otto/install` `InstallScope` 词表,对应
2743
+ * `DiscoveredPlugin.scope: 'user'`——两套词表对同一概念命名不同,是仓库既有历史差异,
2744
+ * 非本模块引入,见 RFC-219 重要事项规则 1a)的条目,因为 `installed_plugins` 清单本身
2745
+ * 恒定路由 user 级配置存储(重要事项规则 5),不与 project/repository/builtin scope 的
2746
+ * 磁盘插件比对。
2747
+ */
2748
+ declare function checkPluginConsistency(discovered: readonly DiscoveredPlugin$1[], installed: readonly InstalledPluginEntry[]): PluginConsistencyWarning[];
2749
+ //#endregion
2750
+ //#region src/plugin/panel-compiler.d.ts
2751
+ interface CompilePanelsResult {
2752
+ /** 已产出的相对路径(如 `panels-dist/status.js`)。 */
2753
+ compiled: string[];
2754
+ /** 单个面板的编译错误(entry → message);不阻塞其余面板(fail-soft)。 */
2755
+ errors: {
2756
+ entry: string;
2757
+ message: string;
2758
+ }[];
2759
+ /** 无 `panels/` 目录或无 `*.tsx` → true。 */
2760
+ skipped: boolean;
2761
+ }
2762
+ /**
2763
+ * 编译插件目录下所有 `panels/*.tsx` → `panels-dist/*.js`。
2764
+ * fail-soft:单个面板编译失败记入 errors、继续其余;无面板目录/文件 → skipped。
2765
+ */
2766
+ declare function compilePluginPanels(pluginDir: string): CompilePanelsResult;
2767
+ //#endregion
2768
+ //#region src/plugin/module-loader.d.ts
2769
+ interface LoadedPluginModule {
2770
+ pluginId: string;
2771
+ module: PluginModule;
2772
+ /**
2773
+ * RFC-287 M3:编译产物绝对路径(`plugin-dist/plugin.cjs` 或既有预编译产物)。
2774
+ *
2775
+ * 只有 services 轴需要它——常驻服务跑在独立的 service worker 里,worker 必须能
2776
+ * `require()` 到同一份产物才能取到 `module.services`(函数体无法经 postMessage 传递)。
2777
+ * 其余轴消费的是已在本进程求值好的 `module` 对象,不需要路径。
2778
+ *
2779
+ * 隔离加载路径(`module-loader-isolated.ts`)同样回填此字段——那条路径的 services
2780
+ * 也要靠它启动服务 worker。
2781
+ */
2782
+ compiledPath?: string;
2783
+ }
2784
+ /**
2785
+ * 编译 `plugin.ts` → `plugin-dist/plugin.cjs`(esbuild,CJS)。无入口 → null。
2786
+ * `@x-otto/plugin` 经 shim 内联(仅 `definePlugin`);react/ink/jsonc-parser external(若被 import)。
2787
+ *
2788
+ * `@x-otto/ai`/`@x-otto/provider` **均不** external(provider 插件化收尾试验后订正,
2789
+ * 2026-07-09;RFC-140 T13 复核,2026-07-10):最初尝试把 `@x-otto/ai` external(同
2790
+ * react/ink),让首方代码式 provider 插件(如 GitHub Copilot)`import { createCopilotProvider }
2791
+ * from '@x-otto/ai'` 时复用宿主同一份实例,运行时走 Node 原生 `require('@x-otto/ai')` 解析。
2792
+ * 但 `@x-otto/ai` 是纯 ESM 包(`package.json` `"type": "module"`,只有 `"import"` 导出
2793
+ * 条件、无 `"require"`),CJS 插件产物用 `require()` 加载会直接抛
2794
+ * `ERR_PACKAGE_PATH_NOT_EXPORTED`(已用真实编译+加载复现)。react/ink 能 external 是
2795
+ * 因为它们本身双格式导出(CJS 兼容),@x-otto/ai 不是。修复:改回打包进插件产物(同其余
2796
+ * 非 react/ink 的 import),接受少量体积重复,换取零构建链改动。
2797
+ *
2798
+ * RFC-140 T13 复核(2026-07-10):`@x-otto/provider`(从 `@x-otto/ai` 拆出的 provider 插入点
2799
+ * 公开包,见 RFC-140 D4/D6)继承了同样的纯 ESM `exports` 写法,天然会踩同一个坑——
2800
+ * 原计划让 `module-loader.ts` external 掉 `@x-otto/provider`("provider 是独立公开包,
2801
+ * external 后走 Node 原生 require 解析、不再打包进每个插件产物")。**已实测复现此方案
2802
+ * 目前不可行**:给 `@x-otto/provider` 单独加 CJS 双格式输出后,它自身可被 `require()`,
2803
+ * 但其传递依赖 `@x-otto/shared`(纯 ESM,被全仓 ~20+ 个包依赖)在同一条 require 链上
2804
+ * 会炸同样的 `ERR_PACKAGE_PATH_NOT_EXPORTED`——问题没被解决,只是从"provider 不能
2805
+ * external"变成"provider 能 external 但 shared 不能"。给 `@x-otto/shared` 也补双格式
2806
+ * 输出是仓库级构建体系改造(影响 20+ 个包的发布产物形态),超出 M4 里程碑范围,需要
2807
+ * 独立 RFC 评估(非本次顺带做掉)。**结论:`@x-otto/provider` 继续打包进插件产物**
2808
+ * (现状不变,接受体积重复),T13 的 external 简化目标标记为阻塞、留待后续里程碑。
2809
+ *
2810
+ * 架构下沉后续(同批次):copilot 的定制协议实现(`createCopilotProvider`)已从
2811
+ * `@x-otto/provider` 进一步下沉至 `extensions/plugin-github-copilot/src/provider.ts`(厂商
2812
+ * 专属实现,唯一消费方是该插件自身)。插件现在 `import from './src/provider'`(同目录,
2813
+ * 随 esbuild 一起编译打包,不涉及跨包 external 问题),只有其复用的协议基座
2814
+ * (`buildChatCompletionsBody`/`streamChatCompletions`)从 `@x-otto/provider` 导入——因
2815
+ * `@x-otto/provider` 仍打包进产物(本节结论未变),这条路径不受影响。
2816
+ *
2817
+ * `jsonc-parser` external(同次收尾追加发现的第二个真实坑):`@x-otto/ai` 传递依赖
2818
+ * `@x-otto/shared`(`createLogger` 等),`@x-otto/shared` barrel 导出 `parseJsonc`(依赖
2819
+ * `jsonc-parser`,一个 UMD 包,内部工厂函数用 `require2("./impl/format")` 相对路径)。
2820
+ * esbuild 把该 UMD 工厂重新打包进 CJS bundle 时,工厂内部的 `require2` 调用点与其
2821
+ * "./impl/*" 相对路径的原始文件系统位置不再对应,运行时抛 `Cannot find module
2822
+ * './impl/format'`(已用真实编译+加载复现,与 provider 插件本身逻辑无关,是 esbuild
2823
+ * 对该特定 UMD 包的已知打包局限)。external 后运行时走 Node 原生 `require('jsonc-parser')`
2824
+ * 从插件目录的 node_modules 解析(该包体积小、无副作用,重复安装成本可忽略)。
2825
+ *
2826
+ * `pino`/`thread-stream` external(终局 review 发现的 P0 生产阻断修复,2026-07-09):
2827
+ * `@x-otto/shared` 的 `createLogger` 用 `pino.transport(...)` 做异步日志分发,pino 内部
2828
+ * 用 `worker_threads` 动态 `new Worker(path.join(__dirname, 'lib/worker.js'))` 加载
2829
+ * 自身的 worker 脚本——esbuild 把 pino 整体打包进单文件 CJS 产物后,这个相对路径不再
2830
+ * 对应任何真实文件,worker 线程创建静默失败但**不产生同步异常**(不会被 `requireModule()`
2831
+ * 的 try/catch 捕获),而是遗留悬空的 IPC handle(Socket/MessagePort)不会被垃圾回收,
2832
+ * 导致任何 `require()` 了本插件编译产物的宿主进程**无法自然退出**(已用真实子进程实测
2833
+ * 复现:仅 `require()` + 构造 provider 工厂,不调用任何网络请求,子进程即挂起直到被
2834
+ * SIGKILL——这不是"测试环境限定"问题,是 100% 复现的生产级 bug)。修复:把 `pino`
2835
+ * (及其内部依赖 `thread-stream`)external,运行时从插件目录的 node_modules 走 Node
2836
+ * 原生 require 解析——pino 自身的 `__dirname` 相对路径在真实文件系统位置下能正确解析,
2837
+ * worker 线程可正常创建、进程可自然退出(已实测三次复现验证:exit code 从被 kill
2838
+ * 的非正常终止变为稳定 0)。
2839
+ *
2840
+ * 产物用 `.cjs` 扩展名(RFC-130 M131-1 plugin-cursor 实测发现并修复):插件 `package.json`
2841
+ * 若声明 `"type":"module"`,`.js` 会被 Node 当 ESM 解析,`require()` 加载失败。
2842
+ */
2843
+ declare function compilePluginModule(pluginDir: string): Promise<string | null>;
2844
+ /**
2845
+ * 信任门后、主进程内加载插件代码模块(R10)。
2846
+ * - 无 plugin.ts → null(无代码入口,正常)。
2847
+ * - 项目级未信任 → null + warn(不编译/不执行,fail-closed R4/D3)。
2848
+ * - 编译 / require / 工厂任一失败 → null + warn(fail-soft,不崩主进程)。
2849
+ */
2850
+ declare function loadPluginModule(plugin: DiscoveredPlugin$1, ctx: PluginContext,
2851
+ /** RFC-153 D3:加载/编译/工厂失败的旁路通知(可选,宿主层注入),供
2852
+ * `PluginHealthTracker.recordError` 写入。不改变现有 fail-soft 返回 null 的控制流。 */
2853
+
2854
+ onLoadError?: (pluginId: string, message: string) => void): Promise<LoadedPluginModule | null>;
2855
+ //#endregion
2856
+ //#region src/plugin/collect-plugin-perf-metrics.d.ts
2857
+ /**
2858
+ * 采集所有已授权插件的性能指标——并发调用(`Promise.allSettled`),单个插件超时/
2859
+ * 报错不阻塞其他插件。手动触发(`/perf` 面板打开/刷新时调用),不做自动轮询
2860
+ * (见 RFC-116 D7,规避"监控自身造成性能问题"的自反风险)。
2861
+ */
2862
+ declare function collectPluginPerfMetrics(plugins: readonly DiscoveredPlugin$1[], /** 测试用注入点——生产路径不传,使用真实 `evaluatePluginTrust`。 */
2863
+
2864
+ evaluateTrust?: (p: DiscoveredPlugin$1) => PluginTrustVerdict$1,
2865
+ /** RFC-153 D3:代码式工具挂起超时的旁路通知(可选,宿主层注入)。只在真实超时(非
2866
+ * "no worker" 场景的 throw)时触发,供 `PluginHealthTracker.recordToolTimeout` 写入。 */
2867
+
2868
+ onToolTimeout?: (pluginId: string) => void): Promise<PluginPerfMetricResult$1[]>;
2869
+ //#endregion
2870
+ //#region src/plugin/plugin-log-writer.d.ts
2871
+ type PluginLogLevel = 'info' | 'warn' | 'error';
2872
+ interface PluginLogEntry {
2873
+ ts: number;
2874
+ level: PluginLogLevel;
2875
+ pluginId: string;
2876
+ msg: string;
2877
+ }
2878
+ //#endregion
2879
+ //#region src/plugin/read-plugin-log-tail.d.ts
2880
+ /** 面板默认展示的最近日志条数(规则 6:固定上限,非用户可调)。 */
2881
+ declare const PLUGIN_LOG_TAIL_LINES = 20;
2882
+ /**
2883
+ * 读取指定插件日志文件的最后 N 行,解析为结构化条目。fail-soft:
2884
+ * - 非法 pluginId(未过 kebab-case 校验)→ 空数组。
2885
+ * - 文件不存在(插件从未打过日志)→ 空数组(调用方据此展示"暂无日志"占位)。
2886
+ * - 单行 JSON 解析失败(如截断产生的半行残留,理论上不应发生但防御性处理)→ 跳过该行。
2887
+ */
2888
+ declare function readPluginLogTail(pluginId: string, maxLines?: number): PluginLogEntry[];
2889
+ //#endregion
2890
+ //#region src/plugin/contribution-host.d.ts
2891
+ /**
2892
+ * 构建「查看某扩展」的 context:内置键(谁在被看)+ 该插件声明的 context-key providers 求值(文件探针)。
2893
+ * `exists` 可注入以便单测。
2894
+ */
2895
+ declare function buildExtensionContext(plugin: DiscoveredPlugin$1 | undefined, builtin: Record<string, string | boolean>, exists?: (p: string) => boolean): ContextMap$1;
2896
+ /**
2897
+ * `script` 型 capability:运行**该插件**声明的命名脚本(`manifest.scripts[name]`,RFC-084 D8)。
2898
+ * 在插件目录内跑 shell 命令,等退出码。**信任门由调用方在装配 cap 时把关**(可执行面,RFC-082)。
2899
+ * 无该脚本 → 抛。
2900
+ */
2901
+ declare function runPluginScript(plugin: DiscoveredPlugin$1, name: string): Promise<void>;
2902
+ /**
2903
+ * `open` 型 capability:拉起外部目标。`chrome://` 无系统默认 handler → 特判用浏览器打开。
2904
+ * best-effort、detached、不阻塞;失败由调用方 toast(OQ3)。
2905
+ */
2906
+ declare function openTarget(target: string): void;
2907
+ //#endregion
2908
+ //#region src/plugin/plugin-cli-passthrough.d.ts
2909
+ /**
2910
+ * 解析插件声明的 CLI 可执行文件绝对路径。优先级:manifest 显式 `contributes.cli.bin`
2911
+ * (相对插件目录)→ 插件目录 `package.json` 的 `bin` 字段(字符串或对象取第一个 value)。
2912
+ *
2913
+ * **symlink 逃逸防御(D4)**:解析后的路径必须 `realpathSync` 归一化后校验落在
2914
+ * `plugin.dir` 的 realpath 内部——单纯 `resolve()+startsWith` 无法防御插件目录内一个
2915
+ * 指向目录外的符号链接。任一校验失败(不存在/不是文件/逃逸出插件目录)返回 `undefined`,
2916
+ * 调用方负责给出清晰错误文案(不得静默失败)。
2917
+ */
2918
+ declare function resolvePluginCliBin(plugin: DiscoveredPlugin$1): string | undefined;
2919
+ declare function buildPluginCliRegistry(plugins: readonly DiscoveredPlugin$1[], reservedNames: ReadonlySet<string>): Map<string, DiscoveredPlugin$1>;
2920
+ /**
2921
+ * 查询某个命令名是否因冲突被 `buildPluginCliRegistry` fail-closed 剔除(RFC-124 §10.2.2)。
2922
+ * 供调用方(`packages/cli/src/cli.ts tryDispatchPluginCli`)区分两种"命令名未在 registry
2923
+ * 中找到"的情形:① 压根没有插件声明该名字(应静默回退到既有的 prompt 处理路径);
2924
+ * ② 曾有 ≥2 个插件声明该名字但被 fail-closed(应向用户展示明确冲突诊断,而非静默把
2925
+ * 命令行参数当 prompt 发给 AI——那会让用户误以为打错了字,而非"命令名被占用")。
2926
+ * 返回冲突方插件 id 列表(≥2 项);无冲突(含"压根没人声明")返回 `undefined`。
2927
+ *
2928
+ * 复用 `groupCliCandidatesByName`——与 `buildPluginCliRegistry` 共用同一份分组逻辑,
2929
+ * 保证两个函数对"是否冲突"永远给出一致结论(注意:本函数调用会重复触发保留字命中的
2930
+ * warn 日志,因为 `groupCliCandidatesByName` 内部对每个插件都会 warn 一次;调用方
2931
+ * `tryDispatchPluginCli` 只在 `buildPluginCliRegistry` 未命中时才调用本函数,同一轮
2932
+ * CLI 调用内至多各触发一次,不构成刷屏)。
2933
+ */
2934
+ declare function findPluginCliNameConflict(plugins: readonly DiscoveredPlugin$1[], reservedNames: ReadonlySet<string>, name: string): string[] | undefined;
2935
+ /**
2936
+ * 透传执行:`spawn(binPath, args, {stdio:'inherit', cwd, env: buildAllowedEnv()})`,
2937
+ * 等待子进程退出并转发退出码。超时(默认 60s,可传参覆盖供测试用极短值验证)触发
2938
+ * `SIGTERM` 并 reject——防止插件 CLI 挂死(如等待不可达网络)导致父进程(otto CLI)
2939
+ * 无限期阻塞。
2940
+ */
2941
+ declare function spawnPluginCli(binPath: string, args: string[], cwd: string, timeoutMs?: number): Promise<number>;
2942
+ //#endregion
2943
+ //#region src/plugin/plugin-hooks.d.ts
2944
+ /** Plugin hook registration: lifecycle/shutdown/permission hooks. */
2945
+ /** 钩子执行上下文。 */
2946
+ interface HookContext {
2947
+ /** 插件安装目录的绝对路径。 */
2948
+ pluginDir: string;
2949
+ /** 插件 manifest id(kebab-case)。 */
2950
+ pluginId: string;
2951
+ /** 项目工作目录(项目级插件有值,全局插件为 undefined)。 */
2952
+ workspaceDir?: string;
2953
+ }
2954
+ /** 钩子执行结果。 */
2955
+ interface HookResult {
2956
+ success: boolean;
2957
+ hook: string;
2958
+ command: string;
2959
+ exitCode?: number | null;
2960
+ signal?: string | null;
2961
+ stdout?: string;
2962
+ stderr?: string;
2963
+ error?: string;
2964
+ timeout?: boolean;
2965
+ /** stdout 或 stderr 超过 4KB 上限被截断。 */
2966
+ truncated?: boolean;
2967
+ }
2968
+ /**
2969
+ * 执行 postinstall 钩子(异步,30s 超时)。
2970
+ *
2971
+ * 仅信任门通过后由 install flow 调用。执行前先经 `checkShellCommand` 安全检查(防御纵深)。
2972
+ * 非零退出或超时 → `HookResult.success = false`,但不抛异常。
2973
+ */
2974
+ declare function executePostInstall(ctx: HookContext, command: string): Promise<HookResult>;
2975
+ //#endregion
2976
+ //#region src/app/storage-wiring.d.ts
2977
+ /**
2978
+ * 构建 MemoryStore。
2979
+ *
2980
+ * 优先级:
2981
+ * 1. `storage.memory.dir` 显式目录 → FileSystemMemoryStore
2982
+ * 2. `identity.userId` 已配置(无论是否 R 形态)**或** R 形态(`sessionUrl` 已知,即便
2983
+ * 未登录)→ HttpMemoryStore(RFC-164 M164-2 扩展:user-scope 与 workspace-scope 独立
2984
+ * 判定,见类头注释与 `isWorkspaceSourceEnabled`)。
2985
+ * 3. `workspaceRoot` 存在 → FileSystemMemoryStore
2986
+ * 4. 无本地 root → undefined
2987
+ *
2988
+ * user-scope(~/.otto/AGENTS.md 等)需要 `identity.userId` 才生效;workspace-scope
2989
+ * (./.otto/MEMORY.md 等)需要 R 形态 opt-in(`getWorkspaceRef().memorySyncEnabled===true`)
2990
+ * 才生效——两者互不依赖,惰性 getter 使得 opt-in 状态可以在 App 构造完成后(`start()`
2991
+ * 解析完 workspaceRef)动态生效,不需要重建整个 store(RFC-164 M164-2 摸底阶段发现的
2992
+ * 时序断层修正:`workspaceRef` 要到 `start()` 才异步解析,构造期读不到)。
2993
+ */
2994
+ declare function buildMemoryStore(storage: StorageOptions | undefined, workspaceRoot: string | undefined, identity?: UserIdentity, getWorkspaceRef?: () => WorkspaceRef | undefined, onMemoryConflict?: (path: string, conflictPath: string) => void): MemoryStore | undefined;
2995
+ //#endregion
2996
+ //#region src/agent/task-output.d.ts
2997
+ /** 读作业输出末 N 行(O_NOFOLLOW;文件不存在/读失败 → 空串)。有界:只回末 N 行。 */
2998
+ declare function readTaskOutputTail(path: string, lines?: number): string;
2999
+ //#endregion
3000
+ //#region src/session/assistant-utils.d.ts
3001
+ declare function getLastAssistantText(messages: readonly AgentMessage[]): string;
3002
+ declare function getIncompleteSubagentReason(messages: readonly AgentMessage[]): string | null;
3003
+ //#endregion
3004
+ //#region src/skill-loop/loop-status.d.ts
3005
+ interface SkillLoopStatus {
3006
+ /** 插件是否已装(没装则下面全是 0,且该提示用户去装)。 */
3007
+ pluginInstalled: boolean;
3008
+ /** 已观测的 episode 总数。 */
3009
+ episodeCount: number;
3010
+ /** 其中成功轨迹数——只有成功的会参与聚簇。 */
3011
+ successCount: number;
3012
+ /** 候选簇总数。 */
3013
+ candidateCount: number;
3014
+ /** 当前可浮出的候选(未被拒绝或冷却已满)。 */
3015
+ pendingCount: number;
3016
+ /** 被拒绝且仍在冷却期内的候选数。 */
3017
+ coolingCount: number;
3018
+ /** 最近观测到的任务签名(最多 STATUS_SAMPLE_LIMIT 条,新→旧)。 */
3019
+ recentSignatures: string[];
3020
+ /** 待提案的候选摘要——用户最关心"接下来它会问我什么"。 */
3021
+ pending: CandidateBrief[];
3022
+ /** 距下一个候选成簇还差几条同类(null = 已有待提案,或无从估算)。 */
3023
+ nextProposalHint: string | null;
3024
+ }
3025
+ interface StatusInput {
3026
+ workspaceKey: string;
3027
+ now: number;
3028
+ /** 用户配的冷却天数(未配则用缺省)。 */
3029
+ cooldownDays?: number;
3030
+ /** 成簇门槛——用于估算"还差几条"。与插件侧 MIN_CLUSTER_SIZE 同值。 */
3031
+ minClusterSize?: number;
3032
+ /** 插件是否在活跃列表里。 */
3033
+ pluginInstalled: boolean;
3034
+ }
3035
+ /**
3036
+ * 汇总技能回路当前状态。
3037
+ *
3038
+ * 只读,不改任何东西——包括**不推进冷却、不消费候选**。用户查看状态不应产生副作用。
3039
+ */
3040
+ declare function readSkillLoopStatus(input: StatusInput): SkillLoopStatus;
3041
+ //#endregion
3042
+ //#region src/plugin/theme-preset-loader.d.ts
3043
+ /**
3044
+ * 装载层产出的主题预设条目(纯数据形状,不依赖 `@x-otto/tui` 的 `ThemePreset` 类型——
3045
+ * `@x-otto/coding` 不引入 UI 包依赖,同 `getPluginRegistrations()` 的既有跨包边界模式)。
3046
+ * CLI 层(同时依赖 coding + tui)负责把这份数据适配进 `ThemeRegistry.register()`。
3047
+ */
3048
+ interface PluginThemePresetEntry {
3049
+ /** 贡献该 preset 的插件 id。 */
3050
+ readonly pluginId: string;
3051
+ /** 插件内声明的短标识(未加前缀)。 */
3052
+ readonly localId: string;
3053
+ readonly label: string;
3054
+ readonly appearance: 'dark' | 'light';
3055
+ readonly colors: Record<string, string>;
3056
+ readonly markdown?: Record<string, unknown>;
3057
+ readonly meta?: {
3058
+ readonly author?: string;
3059
+ readonly description?: string;
3060
+ readonly version?: string;
3061
+ };
3062
+ }
3063
+ /**
3064
+ * 声明式轴:收集全部活跃插件的 `contributes.themePresets` → 带 pluginId 命名空间的
3065
+ * `PluginThemePresetEntry[]`(RFC-277 M5 spike)。
3066
+ *
3067
+ * fail-soft 边界(对齐 `collectPluginI18nEntries`/`collectPluginSigilEntries` 既有纪律):
3068
+ * - 项目级未信任插件(gated)整体跳过。
3069
+ * - 单插件声明超过 `MAX_THEME_PRESETS_PER_PLUGIN` 条 → 截断并 warn。
3070
+ * - localId 撞保留字 → 单条跳过并 warn(不影响该插件其余 preset)。
3071
+ *
3072
+ * 不做的事(RFC-277 D6/M5 边界):不做 marketplace/distribution;不做 registry 注册/卸载
3073
+ * (由 CLI 层调用方持有 `ThemeRegistry` 实例并调用 `register`/`unregisterBySource`);
3074
+ * 不做颜色安全格式的二次校验(schema 层 `themePresetColorsSchema`/`hexColor` 已 fail-closed,
3075
+ * 装载层信任 manifest 解析结果)。
3076
+ */
3077
+ declare function collectPluginThemePresets(plugins: readonly DiscoveredPlugin$1[]): PluginThemePresetEntry[];
3078
+ //#endregion
3079
+ export { AgentJobService, type AgentJobStatus, type AgentObservationSnapshot, AgentSession, type AgentSessionInfo, type AgentSessionJob, type AgentSessionOptions, App, type AppContext, type AppOptions, type ApplyOutcome, type BackgroundProcess, type BuiltinResolverDeps, type Checkpoint, type CheckpointData, type ClaudeExecutableSurface, type ClaudeHookBridgeDeps, type ClaudeHooksConfig, type ClaudeTrustVerdict, CodingSessionPool, type CommandRef, type CompilePanelsResult, type ContentType, type ContextMap, DEFAULT_WORKSPACE_KEY, type DiscoverPluginsOptions, type DiscoveredPlugin, type DispatchCaps, type ExpandOptions, type ExpandSigilChipsOptions, type ExtensionApplies, type ExtensionCategory, type ExtensionItem, ExtensionManager, type FileCommand, type FileEntrySnapshot, type FileProviderOptions, type FileSnapshot, type FireOwnership, type GitUpgradeCheckResult, HIGH_RISK_CAPABILITIES, type HookRunner, INDUCTOR_PLUGIN_ID, InstallManager, type InstallOptions, type InstallPluginFromPackageOptions, type InstallPluginResult, type InstallProgress, type InstallResult, type InstallScope, type InstallSourceMetadata, type InstalledItem, type ListInstalledOptions, type LoadedRegistry, type MemoryPressureLevel, type MemorySample, type NotificationKind, PLUGIN_LOG_TAIL_LINES, PLUGIN_MANIFEST_FILENAME, POINT, type ParsedRegistry, type PluginConsistencyWarning, type PluginContributes, type PluginExecutableSurface, type PluginHealthStats, type PluginInputRegistry, type PluginLogEntry, type PluginManifest, type PluginPerfMetricResult, type PluginThemePresetEntry, type PluginTrustVerdict, type PostInstallContext, type PostInstallResult, type ProgressPhase, type ProjectConfigGating, type ProjectConfigTrustContext, type PromptOptions, type PulseSurveyEntry, type PulseSurveyRating, RegistryClient, type RegistryEntry, type RegistrySourceConfig, type ReplayLevel, type ResolvedAction, type ResolvedSource, type RestoreMode, SANDBOX_ESCALATION_MARKER, SCHEDULE_LEASE_MIGRATIONS, type SandboxRunner, type SandboxToolCall, type SandboxToolResult, SandboxUnavailableError, ScheduleRegistry, type ScheduleStore, type ScheduledTask, type ScheduledTaskInput, type SchedulerDeps, SchedulerService, type ServiceHostPort, type SessionArchiveExport, type SessionPoolOptions, type SigilEntry, type SigilKind, type SigilPrefix, type SigilProvider, SigilResolverRegistry, type SigilSource, type SkillLoopStatus, type SourceType, type StorageHostBinding, type StorageLocation, type StorageOptions, type TracebackView, type UninstallOptions, type UninstallResult, type UninstallTarget, type UpgradeCheckOptions, type UpgradeCheckResult, type VersionInfo, type WorkspaceTrustAction, type WorkspaceTrustPromptDecision, apiCredentialId, buildExtensionContext, buildMemoryStore, buildPluginCliRegistry, builtinOfficialSource, captureFiles, checkArchiveBomb, checkGitUpgrades, checkPluginConsistency, checkUpgrades, claudeTrustStorePath, cleanTempDir, collectPluginPerfMetrics, collectPluginThemePresets, compilePluginModule, compilePluginPanels, createApp, createArchive, createBuiltinHashtags, createBuiltinResolvers, createClaudeHookBridgeHooks, createFileProvider, createFrontendPort, createLessonInjectionHooks, createLocalFireOwnership, createPluginInputRegistry, createRemoteFireOwnership, createRemoteScheduleStore, createScheduleStore, createSessionStableInjectionHooks, createSkillCatalogInjectionHooks, createTempDir, createToolGuidanceHook, defaultHookRunner, defaultMaxToolTurnExtensions, executePostInstall as defaultPostInstallExecutor, deriveSessionTitle, detectClaudeExecutableSurface, detectPluginExecutableSurface, detectProjectConfigGating, detectUninstallTarget, discoverFileCommands, discoverPlugins, dispatch, evaluateClaudeTrust, evaluatePluginTrust, evaluateWorkspaceTrustPrompt, expandCommandBody, expandSigilChips, extractArchive, findPluginCliNameConflict, findWorkspaceRoot, getIncompleteSubagentReason, getLastAssistantText, globalAgentJobRegistry, globalAgentObservability, globalProcessRegistry, grantPluginCapabilities, grantedPluginCapabilities, installPluginFromDir, installPluginFromPackage, interpretPreToolUse, isPluginTrusted, isProjectTrusted, isStrictProjectConfigEnabled, listInstalledItems, loadClaudeHooksConfig, loadPluginModule, matchesHookMatcher, messagesFromSnapshot, openTarget, parseClaudeHooks, parseDotMcpJson, parsePluginManifest, parseRegistry, pluginTrustStorePath, purgePluginState, readHighRiskCapabilities, readPluginLogTail, readSkillLoopStatus, readTaskOutputTail, reconstructMessages, recordPluginInstalled, recordPluginUninstalled, removeInstalledPluginEntry, resolveActions, resolveClaudeMcpServers, resolvePackageDir, resolvePluginCliBin, resolvePluginMcpServers, resolveProjectConfigTrusted, resolveSessionTitle, restoreFiles, runPluginScript, scanInstalledVersions, sigilOf, spawnPluginCli, trustPlugin, trustProject, uninstall, untrustPlugin, untrustProject, upsertInstalledPluginEntry, validateExtractedPaths };
3080
+ //# sourceMappingURL=index.d.ts.map