@aalis/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/app.d.ts +166 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +348 -0
- package/dist/app.js.map +1 -0
- package/dist/config.d.ts +174 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +377 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +31 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +36 -0
- package/dist/constants.js.map +1 -0
- package/dist/context.d.ts +328 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +521 -0
- package/dist/context.js.map +1 -0
- package/dist/disposable-chain.d.ts +31 -0
- package/dist/disposable-chain.d.ts.map +1 -0
- package/dist/disposable-chain.js +66 -0
- package/dist/disposable-chain.js.map +1 -0
- package/dist/events.d.ts +64 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +145 -0
- package/dist/events.js.map +1 -0
- package/dist/hooks.d.ts +49 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +102 -0
- package/dist/hooks.js.map +1 -0
- package/dist/i18n.d.ts +6 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +26 -0
- package/dist/i18n.js.map +1 -0
- package/dist/identity.d.ts +26 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +36 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +20 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +455 -0
- package/dist/init.js.map +1 -0
- package/dist/llm-router.d.ts.map +1 -0
- package/dist/llm-router.js +123 -0
- package/dist/llm-router.js.map +1 -0
- package/dist/logger.d.ts +76 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +187 -0
- package/dist/logger.js.map +1 -0
- package/dist/marketplace-bootstrap.d.ts +54 -0
- package/dist/marketplace-bootstrap.d.ts.map +1 -0
- package/dist/marketplace-bootstrap.js +132 -0
- package/dist/marketplace-bootstrap.js.map +1 -0
- package/dist/mixin-registry.d.ts +34 -0
- package/dist/mixin-registry.d.ts.map +1 -0
- package/dist/mixin-registry.js +60 -0
- package/dist/mixin-registry.js.map +1 -0
- package/dist/model-ref.d.ts +22 -0
- package/dist/model-ref.d.ts.map +1 -0
- package/dist/model-ref.js +46 -0
- package/dist/model-ref.js.map +1 -0
- package/dist/pending-buffer.d.ts +46 -0
- package/dist/pending-buffer.d.ts.map +1 -0
- package/dist/pending-buffer.js +131 -0
- package/dist/pending-buffer.js.map +1 -0
- package/dist/platform-registry.d.ts +40 -0
- package/dist/platform-registry.d.ts.map +1 -0
- package/dist/platform-registry.js +64 -0
- package/dist/platform-registry.js.map +1 -0
- package/dist/plugin-activation.d.ts +43 -0
- package/dist/plugin-activation.d.ts.map +1 -0
- package/dist/plugin-activation.js +172 -0
- package/dist/plugin-activation.js.map +1 -0
- package/dist/plugin-topology.d.ts +40 -0
- package/dist/plugin-topology.d.ts.map +1 -0
- package/dist/plugin-topology.js +126 -0
- package/dist/plugin-topology.js.map +1 -0
- package/dist/plugin.d.ts +184 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +549 -0
- package/dist/plugin.js.map +1 -0
- package/dist/providers.d.ts +85 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/providers.js +2 -0
- package/dist/providers.js.map +1 -0
- package/dist/semver-mini.d.ts +20 -0
- package/dist/semver-mini.d.ts.map +1 -0
- package/dist/semver-mini.js +94 -0
- package/dist/semver-mini.js.map +1 -0
- package/dist/service-helpers.d.ts +34 -0
- package/dist/service-helpers.d.ts.map +1 -0
- package/dist/service-helpers.js +68 -0
- package/dist/service-helpers.js.map +1 -0
- package/dist/service.d.ts +145 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +279 -0
- package/dist/service.js.map +1 -0
- package/dist/types/agent.d.ts +51 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +3 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/app.d.ts +74 -0
- package/dist/types/app.d.ts.map +1 -0
- package/dist/types/app.js +3 -0
- package/dist/types/app.js.map +1 -0
- package/dist/types/archive.d.ts +59 -0
- package/dist/types/archive.d.ts.map +1 -0
- package/dist/types/archive.js +16 -0
- package/dist/types/archive.js.map +1 -0
- package/dist/types/authority.d.ts +63 -0
- package/dist/types/authority.d.ts.map +1 -0
- package/dist/types/authority.js +3 -0
- package/dist/types/authority.js.map +1 -0
- package/dist/types/capabilities.d.ts +53 -0
- package/dist/types/capabilities.d.ts.map +1 -0
- package/dist/types/capabilities.js +87 -0
- package/dist/types/capabilities.js.map +1 -0
- package/dist/types/cli.d.ts +14 -0
- package/dist/types/cli.d.ts.map +1 -0
- package/dist/types/cli.js +3 -0
- package/dist/types/cli.js.map +1 -0
- package/dist/types/commands.d.ts +98 -0
- package/dist/types/commands.d.ts.map +1 -0
- package/dist/types/commands.js +3 -0
- package/dist/types/commands.js.map +1 -0
- package/dist/types/core.d.ts +117 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/types/core.js +6 -0
- package/dist/types/core.js.map +1 -0
- package/dist/types/disposable-service.d.ts +31 -0
- package/dist/types/disposable-service.d.ts.map +1 -0
- package/dist/types/disposable-service.js +3 -0
- package/dist/types/disposable-service.js.map +1 -0
- package/dist/types/embedding.d.ts +7 -0
- package/dist/types/embedding.d.ts.map +1 -0
- package/dist/types/embedding.js +3 -0
- package/dist/types/embedding.js.map +1 -0
- package/dist/types/flow-control.d.ts +51 -0
- package/dist/types/flow-control.d.ts.map +1 -0
- package/dist/types/flow-control.js +12 -0
- package/dist/types/flow-control.js.map +1 -0
- package/dist/types/gateway.d.ts +24 -0
- package/dist/types/gateway.d.ts.map +1 -0
- package/dist/types/gateway.js +15 -0
- package/dist/types/gateway.js.map +1 -0
- package/dist/types/hooks.d.ts +3 -0
- package/dist/types/hooks.d.ts.map +1 -0
- package/dist/types/hooks.js +18 -0
- package/dist/types/hooks.js.map +1 -0
- package/dist/types/image-recognition.d.ts +123 -0
- package/dist/types/image-recognition.d.ts.map +1 -0
- package/dist/types/image-recognition.js +31 -0
- package/dist/types/image-recognition.js.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +17 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/llm.d.ts +146 -0
- package/dist/types/llm.d.ts.map +1 -0
- package/dist/types/llm.js +27 -0
- package/dist/types/llm.js.map +1 -0
- package/dist/types/memory.d.ts +62 -0
- package/dist/types/memory.d.ts.map +1 -0
- package/dist/types/memory.js +22 -0
- package/dist/types/memory.js.map +1 -0
- package/dist/types/persona.d.ts +45 -0
- package/dist/types/persona.d.ts.map +1 -0
- package/dist/types/persona.js +3 -0
- package/dist/types/persona.js.map +1 -0
- package/dist/types/platform.d.ts +126 -0
- package/dist/types/platform.d.ts.map +1 -0
- package/dist/types/platform.js +5 -0
- package/dist/types/platform.js.map +1 -0
- package/dist/types/plugin.d.ts +84 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +24 -0
- package/dist/types/plugin.js.map +1 -0
- package/dist/types/service.d.ts +43 -0
- package/dist/types/service.d.ts.map +1 -0
- package/dist/types/service.js +38 -0
- package/dist/types/service.js.map +1 -0
- package/dist/types/services.d.ts +17 -0
- package/dist/types/services.d.ts.map +1 -0
- package/dist/types/services.js +41 -0
- package/dist/types/services.js.map +1 -0
- package/dist/types/session.d.ts +153 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +19 -0
- package/dist/types/session.js.map +1 -0
- package/dist/types/storage.d.ts +100 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +29 -0
- package/dist/types/storage.js.map +1 -0
- package/dist/types/tools.d.ts +39 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +3 -0
- package/dist/types/tools.js.map +1 -0
- package/dist/types/trigger-policy.d.ts +16 -0
- package/dist/types/trigger-policy.d.ts.map +1 -0
- package/dist/types/trigger-policy.js +6 -0
- package/dist/types/trigger-policy.js.map +1 -0
- package/dist/types/vectorstore.d.ts +23 -0
- package/dist/types/vectorstore.d.ts.map +1 -0
- package/dist/types/vectorstore.js +3 -0
- package/dist/types/vectorstore.js.map +1 -0
- package/dist/types/web-search.d.ts +88 -0
- package/dist/types/web-search.d.ts.map +1 -0
- package/dist/types/web-search.js +23 -0
- package/dist/types/web-search.js.map +1 -0
- package/dist/types/webui.d.ts +137 -0
- package/dist/types/webui.d.ts.map +1 -0
- package/dist/types/webui.js +3 -0
- package/dist/types/webui.js.map +1 -0
- package/package.json +22 -0
package/dist/context.js
ADDED
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import { ScopedConfigManager } from './config.js';
|
|
2
|
+
import { DisposableChain } from './disposable-chain.js';
|
|
3
|
+
import { emitServiceRegistered, validateProvide } from './service-helpers.js';
|
|
4
|
+
/**
|
|
5
|
+
* 上下文 (Context)
|
|
6
|
+
*
|
|
7
|
+
* 每个插件获得一个子 Context。所有通过子 Context 注册的副作用
|
|
8
|
+
* (事件监听、服务注册、工具注册) 在 dispose 时自动清理。
|
|
9
|
+
*
|
|
10
|
+
* 采用 fork / inject / provide / middleware 等术语,
|
|
11
|
+
* 但 Aalis 在此之上引入若干差异化机制:
|
|
12
|
+
* - **能力声明框架**:`provide` 时声明 `capabilities`,编译期类型字面量收敛 +
|
|
13
|
+
* dev 期 `probeCapability` 运行时校验声明与实现是否一致
|
|
14
|
+
* - **多提供者 + 能力匹配**:`getService` / `getAllServices` 支持按能力过滤,
|
|
15
|
+
* 服务可以并存多个实现
|
|
16
|
+
* - **`ScopedServiceContainer` + `ScopedConfigManager`**:`createScope()` 创建
|
|
17
|
+
* 读取 fallback、写入隔离的子作用域,用于会话/沙盒
|
|
18
|
+
* - **`whenService(name, cb)`**:服务就绪即触发的延迟订阅,回调可返回 cleanup
|
|
19
|
+
* 纳入 dispose 链
|
|
20
|
+
*/
|
|
21
|
+
export class Context {
|
|
22
|
+
id;
|
|
23
|
+
logger;
|
|
24
|
+
config;
|
|
25
|
+
hooks;
|
|
26
|
+
/**
|
|
27
|
+
* 开发模式开关——由 App 注入,子 Context 通过 fork/createScope 继承。
|
|
28
|
+
*
|
|
29
|
+
* - `true`(默认):`provide` 时按声明的能力跑探测器,暴露"声明与实现不符"
|
|
30
|
+
* - `false`(生产):跳过探测,节省热路径开销
|
|
31
|
+
*
|
|
32
|
+
* core 不读 `process.env`——是否 dev 由宿主决定。
|
|
33
|
+
*/
|
|
34
|
+
devMode;
|
|
35
|
+
_events;
|
|
36
|
+
_services;
|
|
37
|
+
_disposables;
|
|
38
|
+
_children = new Set();
|
|
39
|
+
_parent;
|
|
40
|
+
_disposed = false;
|
|
41
|
+
constructor(options) {
|
|
42
|
+
this.id = options.id;
|
|
43
|
+
this._events = options.events;
|
|
44
|
+
this._services = options.services;
|
|
45
|
+
this.hooks = options.hooks;
|
|
46
|
+
this.logger = options.logger;
|
|
47
|
+
this.config = options.config;
|
|
48
|
+
this._parent = options.parent;
|
|
49
|
+
this.devMode = options.devMode ?? options.parent?.devMode ?? true;
|
|
50
|
+
this._disposables = new DisposableChain(this.logger);
|
|
51
|
+
}
|
|
52
|
+
// ---- 子系统访问(供高级插件检查/包装用) ----
|
|
53
|
+
/**
|
|
54
|
+
* 底层服务容器实例。
|
|
55
|
+
*
|
|
56
|
+
* ⚠️ **@internal** —— 仅供 host 级巡视代码(如 plugin-activation 检查 provides
|
|
57
|
+
* 完整性)使用。
|
|
58
|
+
*
|
|
59
|
+
* **插件请勿直接使用**:
|
|
60
|
+
* - 枚举某服务的所有 entry(含 contextId / capabilities / priority):
|
|
61
|
+
* → 用公开 API `ctx.getServiceEntries(name)`
|
|
62
|
+
* - 获取服务实例:用 `ctx.getService()` / `ctx.getAllServices()`
|
|
63
|
+
* - 注册服务:用 `ctx.provide()`(会自动登记到 _disposables 链)
|
|
64
|
+
*/
|
|
65
|
+
get serviceContainer() {
|
|
66
|
+
return this._services;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 创建子上下文(通常为每个插件创建一个)
|
|
70
|
+
*/
|
|
71
|
+
fork(id) {
|
|
72
|
+
const child = new Context({
|
|
73
|
+
id,
|
|
74
|
+
events: this._events,
|
|
75
|
+
services: this._services,
|
|
76
|
+
hooks: this.hooks,
|
|
77
|
+
logger: this.logger.child(id),
|
|
78
|
+
config: this.config,
|
|
79
|
+
parent: this,
|
|
80
|
+
devMode: this.devMode,
|
|
81
|
+
});
|
|
82
|
+
this._children.add(child);
|
|
83
|
+
return child;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 创建隔离作用域的子上下文
|
|
87
|
+
*
|
|
88
|
+
* 与 fork() 的区别:fork() 共享同一个 ServiceContainer / ConfigManager;
|
|
89
|
+
* createScope() 同时创建:
|
|
90
|
+
* - **ScopedServiceContainer**(子容器):读 fallback、写不影响父级
|
|
91
|
+
* - **ScopedConfigManager**(cleanup-7 新增):同样 fallback + overlay 语义
|
|
92
|
+
*
|
|
93
|
+
* 适用于沙盒/会话隔离场景:
|
|
94
|
+
* - 沙盒内 `ctx.provide('agent', sandboxAgent)` 不会污染全局
|
|
95
|
+
* - 沙盒内 `ctx.getService('authority')` 仍能 fallback 到全局服务
|
|
96
|
+
* - 沙盒内 `ctx.config.set('logLevel', 'debug')` 仅作用于沙盒
|
|
97
|
+
* - 沙盒内 `ctx.config.setPluginConfig('llm.openai', { ... })` 给当前沙盒一份
|
|
98
|
+
* 临时 LLM 配置,dispose 后随作用域消失(写只进 overlay,save() 为内存
|
|
99
|
+
* 模式 no-op,磁盘不被污染)
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* const sandbox = ctx.createScope('sandbox-group-123');
|
|
103
|
+
* sandbox.provide('agent', myCustomAgent); // 仅此作用域可见
|
|
104
|
+
* sandbox.config.setPluginConfig('llm.openai', { temperature: 0.1 }); // 临时配置
|
|
105
|
+
* sandbox.getService('authority'); // fallback 到父级全局服务
|
|
106
|
+
*/
|
|
107
|
+
createScope(id) {
|
|
108
|
+
const scopedServices = this._services.createScope();
|
|
109
|
+
const scopedConfig = new ScopedConfigManager(this.config);
|
|
110
|
+
const child = new Context({
|
|
111
|
+
id,
|
|
112
|
+
events: this._events,
|
|
113
|
+
services: scopedServices,
|
|
114
|
+
hooks: this.hooks,
|
|
115
|
+
logger: this.logger.child(id),
|
|
116
|
+
config: scopedConfig,
|
|
117
|
+
parent: this,
|
|
118
|
+
devMode: this.devMode,
|
|
119
|
+
});
|
|
120
|
+
this._children.add(child);
|
|
121
|
+
return child;
|
|
122
|
+
}
|
|
123
|
+
// ---- 事件 ----
|
|
124
|
+
on(event, handler) {
|
|
125
|
+
const off = this._events.on(event, handler);
|
|
126
|
+
return this.trackDisposable(off);
|
|
127
|
+
}
|
|
128
|
+
once(event, handler) {
|
|
129
|
+
const off = this._events.once(event, handler);
|
|
130
|
+
return this.trackDisposable(off);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 把一个底层退订原语登记到 disposable 链,并返回**自移除**的退订函数:
|
|
134
|
+
* 调用方手动退订时,闭包不再滞留 _disposables(否则它持有 handler 引用直到
|
|
135
|
+
* ctx.dispose——审计 HIGH #2 的同类泄漏,统一所有注册 API 的退订语义)。
|
|
136
|
+
*/
|
|
137
|
+
trackDisposable(off) {
|
|
138
|
+
const dispose = () => {
|
|
139
|
+
this._disposables.remove(dispose);
|
|
140
|
+
off();
|
|
141
|
+
};
|
|
142
|
+
this._disposables.push(dispose);
|
|
143
|
+
return dispose;
|
|
144
|
+
}
|
|
145
|
+
emit(event, ...args) {
|
|
146
|
+
return this._events.emit(event, ...args);
|
|
147
|
+
}
|
|
148
|
+
// ---- 服务 (IoC + 能力声明) ----
|
|
149
|
+
/**
|
|
150
|
+
* 注册服务,返回 dispose 函数用于精确卸载该服务
|
|
151
|
+
*
|
|
152
|
+
* `capabilities` 参数按服务名获得强类型约束:
|
|
153
|
+
* - 已注册服务名(如 `'llm'`, `'memory'`)→ 仅允许对应 union 中的字面量
|
|
154
|
+
* - 未注册服务名 → 退回 `string`,保留动态扩展空间
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ctx.provide('llm', service, { capabilities: ['chat', 'tool_calling'] });
|
|
158
|
+
* // ^^^^^^ ^^^^^^^^^^^^^^
|
|
159
|
+
* // 类型安全,拼错 'tool_call' 会编译报错
|
|
160
|
+
*
|
|
161
|
+
* `entryId` 选项:覆盖默认 contextId(默认 = `this.id`)。用于一个 plugin 实例
|
|
162
|
+
* 需要按某种语义子粒度拆出多个 entry 的场景(典型:per-model LLM、per-path storage)。
|
|
163
|
+
* 约定:`entryId` 必须以 `this.id` 为前缀(以 `/` 分隔),以保证 plugin 卸载时
|
|
164
|
+
* `unregisterByContext(this.id)` 如需清理仍可多次调用;dispose 函数并不依赖这个约定,
|
|
165
|
+
* 但 dev 模式下会验证以避免 "entryId 与拥有者 plugin 脱联" 的 footgun。
|
|
166
|
+
*/
|
|
167
|
+
provide(name, instance, options) {
|
|
168
|
+
const caps = (options?.capabilities ?? []);
|
|
169
|
+
const entryId = options?.entryId ?? this.id;
|
|
170
|
+
if (this.devMode) {
|
|
171
|
+
validateProvide({
|
|
172
|
+
ctxId: this.id,
|
|
173
|
+
name,
|
|
174
|
+
instance,
|
|
175
|
+
capabilities: caps,
|
|
176
|
+
entryId,
|
|
177
|
+
explicitEntryId: options?.entryId !== undefined,
|
|
178
|
+
priority: options?.priority,
|
|
179
|
+
services: this._services,
|
|
180
|
+
logger: this.logger,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
const entry = this._services.register(name, instance, caps, options?.priority ?? 0, entryId, options?.label);
|
|
184
|
+
const dispose = () => {
|
|
185
|
+
// 自移除:调用方手动 dispose 后,闭包不再滞留 _disposables(否则它持有
|
|
186
|
+
// entry 引用,instance 无法 GC,多实例热替换场景累积僵尸——审计 HIGH #2)。
|
|
187
|
+
// ctx.dispose 经 DisposableChain.dispose 调用本函数时 remove 返回 false,无害。
|
|
188
|
+
this._disposables.remove(dispose);
|
|
189
|
+
const removed = this._services.unregisterEntry(name, entry);
|
|
190
|
+
if (removed) {
|
|
191
|
+
this._events.emit('service:unregistered', name).catch(err => {
|
|
192
|
+
this.logger.warn(`emit service:unregistered 失败 (${name}): ${err}`);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
this._disposables.push(dispose);
|
|
197
|
+
emitServiceRegistered(this._events, this.logger, name, caps);
|
|
198
|
+
this.logger.debug(`服务已注册: ${name}${caps.length ? ` [${caps.join(', ')}]` : ''}`);
|
|
199
|
+
return dispose;
|
|
200
|
+
}
|
|
201
|
+
getService(name, requiredCapabilities) {
|
|
202
|
+
return this._services.get(name, requiredCapabilities);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 检查服务是否可用
|
|
206
|
+
*/
|
|
207
|
+
hasService(name, requiredCapabilities) {
|
|
208
|
+
return this._services.has(name, requiredCapabilities);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* 获取服务的能力列表
|
|
212
|
+
*/
|
|
213
|
+
getServiceCapabilities(name) {
|
|
214
|
+
return this._services.getCapabilities(name);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* 列出所有已注册的服务名
|
|
218
|
+
*/
|
|
219
|
+
getServiceNames() {
|
|
220
|
+
return this._services.getServiceNames();
|
|
221
|
+
}
|
|
222
|
+
getAllServices(name, requiredCapabilities) {
|
|
223
|
+
return this._services.getAll(name, requiredCapabilities);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* 设置某服务的偏好 provider(按 contextId)
|
|
227
|
+
*
|
|
228
|
+
* 语义:「偏好 > 优先级 > 注册顺序」。偏好者总是 `getService(name)` 的第一返回值,
|
|
229
|
+
* 即使其 priority 数值低于 router 等其他 entry。
|
|
230
|
+
*
|
|
231
|
+
* 注:偏好可以提前于 entry 注册前设置——一旦目标 contextId 注册即刻生效。
|
|
232
|
+
* @returns 始终返回 true(偏好已记录)
|
|
233
|
+
*/
|
|
234
|
+
preferService(name, contextId) {
|
|
235
|
+
const ok = this._services.prefer(name, contextId);
|
|
236
|
+
if (ok) {
|
|
237
|
+
this.logger.debug(`服务偏好已设置: ${name} -> ${contextId}`);
|
|
238
|
+
this._events.emit('service:preference-changed', name).catch(err => {
|
|
239
|
+
this.logger.warn(`emit service:preference-changed 失败 (${name}): ${err}`);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
return ok;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* 清除某服务的偏好(恢复 priority + 注册顺序解析)
|
|
246
|
+
*/
|
|
247
|
+
unpreferService(name) {
|
|
248
|
+
const ok = this._services.unprefer(name);
|
|
249
|
+
if (ok) {
|
|
250
|
+
this.logger.debug(`服务偏好已清除: ${name}`);
|
|
251
|
+
this._events.emit('service:preference-changed', name).catch(err => {
|
|
252
|
+
this.logger.warn(`emit service:preference-changed 失败 (${name}): ${err}`);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
return ok;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* 读取某服务当前的偏好 contextId(无偏好返回 undefined)
|
|
259
|
+
*/
|
|
260
|
+
getPreferredService(name) {
|
|
261
|
+
return this._services.getPreferred(name);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* 获取某服务的全部 entry(含 priority),按「偏好 > 优先级 > 注册顺序」排序。
|
|
265
|
+
*
|
|
266
|
+
* 主要给管控类消费者(如 WebUI / CLI status 视图)枚举展示用。
|
|
267
|
+
* 业务消费者应优先使用 `getService` / `getAllServices`。
|
|
268
|
+
*/
|
|
269
|
+
getServiceEntries(name) {
|
|
270
|
+
return this._services.getEntries(name);
|
|
271
|
+
}
|
|
272
|
+
// biome-ignore lint/suspicious/noConfusingVoidType: cb 可隐式返回 void 或显式返回 cleanup
|
|
273
|
+
whenService(name, cb) {
|
|
274
|
+
let cleanup;
|
|
275
|
+
let disposed = false;
|
|
276
|
+
/** 当前已挂载的胜者实例;undefined = 未挂载 */
|
|
277
|
+
let attached;
|
|
278
|
+
const runCleanup = () => {
|
|
279
|
+
if (!cleanup)
|
|
280
|
+
return;
|
|
281
|
+
try {
|
|
282
|
+
cleanup();
|
|
283
|
+
}
|
|
284
|
+
catch (err) {
|
|
285
|
+
this.logger.warn(`whenService('${name}') cleanup 抛错(已忽略):`, err);
|
|
286
|
+
}
|
|
287
|
+
cleanup = undefined;
|
|
288
|
+
};
|
|
289
|
+
/**
|
|
290
|
+
* 对齐到容器当前胜者(核心不变量:attached === getService(name)):
|
|
291
|
+
* - 胜者未变(如败者 entry 上下线、同胜者重复事件)→ 不动,避免无谓 bounce
|
|
292
|
+
* - 胜者变了 → 先 cleanup 再用新实例重挂
|
|
293
|
+
* - 没有胜者了 → 只 cleanup 脱挂
|
|
294
|
+
* 不读事件 payload、只看容器当前态,天然对事件乱序/合并免疫。
|
|
295
|
+
*/
|
|
296
|
+
const sync = () => {
|
|
297
|
+
if (disposed)
|
|
298
|
+
return;
|
|
299
|
+
const winner = this._services.get(name);
|
|
300
|
+
if (winner === attached)
|
|
301
|
+
return;
|
|
302
|
+
runCleanup();
|
|
303
|
+
attached = winner;
|
|
304
|
+
if (winner === undefined)
|
|
305
|
+
return;
|
|
306
|
+
const ret = cb(winner);
|
|
307
|
+
// cb 执行期间可能同步触发了本 whenService 的 dispose(如 cb 内部链式
|
|
308
|
+
// 卸载)。此时不能把新 cleanup 挂上去——dispose 已跑过 runCleanup 且
|
|
309
|
+
// disposed=true,挂上的 cleanup 将永不执行(泄漏)。直接立即执行掉。
|
|
310
|
+
if (disposed) {
|
|
311
|
+
if (typeof ret === 'function') {
|
|
312
|
+
try {
|
|
313
|
+
ret();
|
|
314
|
+
}
|
|
315
|
+
catch (err) {
|
|
316
|
+
this.logger.warn(`whenService('${name}') cleanup 抛错(dispose 期间,已忽略):`, err);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (typeof ret === 'function')
|
|
322
|
+
cleanup = ret;
|
|
323
|
+
};
|
|
324
|
+
// 持续订阅 provider 上下线 + 偏好切换(不退订),ctx.dispose 时由 disposable 链清理。
|
|
325
|
+
const offReg = this.on('service:registered', (svcName) => {
|
|
326
|
+
if (svcName === name)
|
|
327
|
+
sync();
|
|
328
|
+
});
|
|
329
|
+
const offUnreg = this.on('service:unregistered', (svcName) => {
|
|
330
|
+
if (svcName === name)
|
|
331
|
+
sync();
|
|
332
|
+
});
|
|
333
|
+
const offPref = this.on('service:preference-changed', (svcName) => {
|
|
334
|
+
if (svcName === name)
|
|
335
|
+
sync();
|
|
336
|
+
});
|
|
337
|
+
// 立即检查:若已就绪则首挂。
|
|
338
|
+
sync();
|
|
339
|
+
const dispose = () => {
|
|
340
|
+
if (disposed)
|
|
341
|
+
return;
|
|
342
|
+
disposed = true;
|
|
343
|
+
this._disposables.remove(dispose); // 自移除,不滞留闭包(对称 provide)
|
|
344
|
+
offReg();
|
|
345
|
+
offUnreg();
|
|
346
|
+
offPref();
|
|
347
|
+
runCleanup();
|
|
348
|
+
attached = undefined;
|
|
349
|
+
};
|
|
350
|
+
this._disposables.push(dispose);
|
|
351
|
+
return dispose;
|
|
352
|
+
}
|
|
353
|
+
// ---- 中间件/钩子 ----
|
|
354
|
+
/**
|
|
355
|
+
* 注册命名生命周期事件 handler(中间件管道)
|
|
356
|
+
*
|
|
357
|
+
* 同一钩子键内的多个 handler 按 **注册顺序** 执行洋葱模型 (next 语义),
|
|
358
|
+
* 不再使用数字优先级。相位间的次序由调度方(如 plugin-gateway 的入站
|
|
359
|
+
* 多相位调度)显式表达。
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* // 在消息发送给 LLM 前添加额外指令
|
|
363
|
+
* ctx.middleware('agent:llm:before', async (data, next) => {
|
|
364
|
+
* data.messages.unshift({ role: 'system', content: '额外指令...' });
|
|
365
|
+
* await next();
|
|
366
|
+
* });
|
|
367
|
+
*
|
|
368
|
+
* // 命令命中后中断后续处理
|
|
369
|
+
* ctx.middleware('inbound:command', async (data, next) => {
|
|
370
|
+
* if (handled(data.message)) return; // 不调用 next = 中断
|
|
371
|
+
* await next();
|
|
372
|
+
* });
|
|
373
|
+
*/
|
|
374
|
+
middleware(hook, fn) {
|
|
375
|
+
return this.trackDisposable(this.hooks.register(hook, fn, this.id));
|
|
376
|
+
}
|
|
377
|
+
// ---- 生命周期 ----
|
|
378
|
+
get disposed() {
|
|
379
|
+
return this._disposed;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* 在当前 Context 内动态加载一个插件 module 作为"沙盒插件"。
|
|
383
|
+
*
|
|
384
|
+
* 与 `App.plugin(...)` / `PluginManager.register(...)` 的区别:
|
|
385
|
+
* - 不进入全局 `PluginManager`(不参与依赖追踪、softReload)
|
|
386
|
+
* - 创建一个 fork/createScope 子上下文,调用 `module.apply(child, config)`
|
|
387
|
+
* - 返回 dispose:调用即销毁该子上下文,对应子上下文里所有副作用一并清理
|
|
388
|
+
* - 父 ctx dispose 时也会级联销毁
|
|
389
|
+
*
|
|
390
|
+
* 典型场景:
|
|
391
|
+
* - 会话级动态工具/中间件
|
|
392
|
+
* - 沙盒(`createScope`)内挂载临时 mini 插件
|
|
393
|
+
* - 单元测试里组装最小可运行单元
|
|
394
|
+
*
|
|
395
|
+
* @param module 任意符合 `{ name, apply(ctx, config) }` 的对象
|
|
396
|
+
* @param config 传给 apply 的配置(默认 `{}`)
|
|
397
|
+
* @param options.scoped 是否使用 `createScope`(服务/配置隔离),默认 false 用 `fork`
|
|
398
|
+
* @returns dispose 函数;返回的 Promise 在 apply 完成后 resolve
|
|
399
|
+
*
|
|
400
|
+
* @example
|
|
401
|
+
* const off = await ctx.useModule({
|
|
402
|
+
* name: 'temp-mw',
|
|
403
|
+
* apply(c) {
|
|
404
|
+
* c.middleware('agent:input:before', async (data, next) => {
|
|
405
|
+
* data.message.content += ' [临时标记]';
|
|
406
|
+
* await next();
|
|
407
|
+
* });
|
|
408
|
+
* }
|
|
409
|
+
* });
|
|
410
|
+
* // ...
|
|
411
|
+
* off(); // 卸载临时中间件
|
|
412
|
+
*/
|
|
413
|
+
async useModule(module, config = {}, options) {
|
|
414
|
+
if (this._disposed) {
|
|
415
|
+
throw new Error(`Context "${this.id}" 已 dispose,无法 useModule`);
|
|
416
|
+
}
|
|
417
|
+
const childId = `${this.id}#${module.name}`;
|
|
418
|
+
const child = options?.scoped ? this.createScope(childId) : this.fork(childId);
|
|
419
|
+
try {
|
|
420
|
+
await module.apply(child, config);
|
|
421
|
+
}
|
|
422
|
+
catch (err) {
|
|
423
|
+
child.dispose();
|
|
424
|
+
throw err;
|
|
425
|
+
}
|
|
426
|
+
return () => child.dispose();
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* 注册一个在本 Context dispose 时执行的清理回调。
|
|
430
|
+
*
|
|
431
|
+
* 插件清理副作用的**唯一正确 API**:
|
|
432
|
+
* - 直接挂在 `_disposables` 链上,保证逆序执行
|
|
433
|
+
* - 在 `ctx.dispose()` 的任何路径上都会触发(app 停机 / bounce / unload /
|
|
434
|
+
* updatePluginConfig / softReload 级联 evict)
|
|
435
|
+
* - 沙盒 / fork 子上下文同样适用
|
|
436
|
+
*
|
|
437
|
+
* ⚠. 不要用 `ctx.on('app:stopping', ...)` 做资源清理——那只在 app 全局停机
|
|
438
|
+
* 时触发一次,**不会**在插件 bounce / hot reload 时触发,会造成旧连接、
|
|
439
|
+
* 旧定时器泄漏。全局停机不需要特别处理——`onDispose` 也会被触发。
|
|
440
|
+
*
|
|
441
|
+
* @example
|
|
442
|
+
* const conn = await connectExternal();
|
|
443
|
+
* ctx.onDispose(() => conn.close());
|
|
444
|
+
*
|
|
445
|
+
* @returns 取消该清理回调的函数(在 dispose 前调用可阻止执行)
|
|
446
|
+
*/
|
|
447
|
+
onDispose(fn) {
|
|
448
|
+
const wrapped = () => {
|
|
449
|
+
try {
|
|
450
|
+
const ret = fn();
|
|
451
|
+
if (ret && typeof ret.then === 'function') {
|
|
452
|
+
ret.catch(err => {
|
|
453
|
+
this.logger.debug('onDispose 异步清理抛错(已忽略):', err);
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
catch (err) {
|
|
458
|
+
this.logger.debug('onDispose 清理抛错(已忽略):', err);
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
this._disposables.push(wrapped);
|
|
462
|
+
return () => this._disposables.remove(wrapped);
|
|
463
|
+
}
|
|
464
|
+
/** @internal 当前 disposable 链长度(诊断 / 测试用:检测 provide/whenService 的闭包是否如期自移除)。 */
|
|
465
|
+
get disposableCount() {
|
|
466
|
+
return this._disposables.size;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* 销毁此上下文,清理所有副作用
|
|
470
|
+
*/
|
|
471
|
+
dispose() {
|
|
472
|
+
if (this._disposed)
|
|
473
|
+
return;
|
|
474
|
+
this._disposed = true;
|
|
475
|
+
// 先销毁子上下文(复制避免迭代中修改 Set)
|
|
476
|
+
const children = [...this._children];
|
|
477
|
+
for (const child of children) {
|
|
478
|
+
child.dispose();
|
|
479
|
+
}
|
|
480
|
+
this._children.clear();
|
|
481
|
+
// 记录此上下文注册的服务名,以便 dispose 后发射事件
|
|
482
|
+
const removedServices = this._services.unregisterByContext(this.id);
|
|
483
|
+
// 逆序执行清理(unregisterByContext 已整体移除服务,provide 的 dispose 会安全跳过)
|
|
484
|
+
this._disposables.dispose();
|
|
485
|
+
// 发射服务注销事件,让 App 的自动恢复监听器能响应
|
|
486
|
+
for (const svc of removedServices) {
|
|
487
|
+
this._events.emit('service:unregistered', svc).catch(err => {
|
|
488
|
+
this.logger.warn(`emit service:unregistered 失败 (${svc}): ${err}`);
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
// 清理该上下文注册的钩子
|
|
492
|
+
this.hooks.unregisterByContext(this.id);
|
|
493
|
+
// 服务自清理协议:任何服务实例若实现 `unregisterByPlugin(contextId)`,
|
|
494
|
+
// dispose 时统一通知它清理本上下文相关的注册项(如 plugin-tools 的
|
|
495
|
+
// ToolService、plugin-commands 的 CommandService)。
|
|
496
|
+
// core 不再硬编码任何具体服务名。
|
|
497
|
+
// 遍历该服务名下的**所有** entry 而非只通知胜者——败者实例(低优先级
|
|
498
|
+
// 并存 provider)也可能持有本上下文注册的条目。同名多 entry 可能指向
|
|
499
|
+
// 同一实例(per-model 拆粒度),按实例去重避免重复通知。
|
|
500
|
+
for (const name of this._services.getServiceNames()) {
|
|
501
|
+
const seen = new Set();
|
|
502
|
+
for (const entry of this._services.getEntries(name)) {
|
|
503
|
+
if (seen.has(entry.instance))
|
|
504
|
+
continue;
|
|
505
|
+
seen.add(entry.instance);
|
|
506
|
+
const svc = entry.instance;
|
|
507
|
+
try {
|
|
508
|
+
svc?.unregisterByPlugin?.(this.id);
|
|
509
|
+
}
|
|
510
|
+
catch (err) {
|
|
511
|
+
this.logger.warn(`服务 "${name}" 的 unregisterByPlugin 抛错:`, err);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
// 从父上下文中移除
|
|
516
|
+
if (this._parent) {
|
|
517
|
+
this._parent._children.delete(this);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Logger } from './logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* 一次性清理器链
|
|
4
|
+
*
|
|
5
|
+
* 用途:Context 及其他需要累积「注册 → 卸载」副作用的场景,提供:
|
|
6
|
+
* - `push(fn)` 追加清理函数
|
|
7
|
+
* - `remove(fn)` 精确移除单个清理函数(不执行)
|
|
8
|
+
* - `dispose()` 逆序调用所有清理函数并清空;期间任一抛错不影响其他
|
|
9
|
+
*
|
|
10
|
+
* 相比散落的 `this._disposables: (() => void)[]`,集中管理能避免
|
|
11
|
+
* 「忘记 push / 忘记清空 / 错误处理不一致」等低级 bug。
|
|
12
|
+
*/
|
|
13
|
+
export declare class DisposableChain {
|
|
14
|
+
private readonly logger?;
|
|
15
|
+
private _items;
|
|
16
|
+
private _disposed;
|
|
17
|
+
constructor(logger?: Logger | undefined);
|
|
18
|
+
/** 追加一个清理函数。dispose 后追加会立刻执行。 */
|
|
19
|
+
push(fn: () => void): void;
|
|
20
|
+
/** 精确移除单个 disposable(不执行)。用于缓冲项"取消"场景。 */
|
|
21
|
+
remove(fn: () => void): boolean;
|
|
22
|
+
get disposed(): boolean;
|
|
23
|
+
/** 当前登记的清理函数数量(诊断 / 测试用:可检测闭包是否如期自移除)。 */
|
|
24
|
+
get size(): number;
|
|
25
|
+
/**
|
|
26
|
+
* 逆序执行所有清理函数并清空。重复调用无效果。
|
|
27
|
+
* 单个函数抛错被 swallow(可选择通过 logger 记录 debug)。
|
|
28
|
+
*/
|
|
29
|
+
dispose(): void;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=disposable-chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disposable-chain.d.ts","sourceRoot":"","sources":["../src/disposable-chain.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;IAId,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAHpC,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,SAAS,CAAS;gBAEG,MAAM,CAAC,EAAE,MAAM,YAAA;IAE5C,iCAAiC;IACjC,IAAI,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IAY1B,0CAA0C;IAC1C,MAAM,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,OAAO;IAO/B,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,0CAA0C;IAC1C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI;CAYhB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 一次性清理器链
|
|
3
|
+
*
|
|
4
|
+
* 用途:Context 及其他需要累积「注册 → 卸载」副作用的场景,提供:
|
|
5
|
+
* - `push(fn)` 追加清理函数
|
|
6
|
+
* - `remove(fn)` 精确移除单个清理函数(不执行)
|
|
7
|
+
* - `dispose()` 逆序调用所有清理函数并清空;期间任一抛错不影响其他
|
|
8
|
+
*
|
|
9
|
+
* 相比散落的 `this._disposables: (() => void)[]`,集中管理能避免
|
|
10
|
+
* 「忘记 push / 忘记清空 / 错误处理不一致」等低级 bug。
|
|
11
|
+
*/
|
|
12
|
+
export class DisposableChain {
|
|
13
|
+
logger;
|
|
14
|
+
_items = [];
|
|
15
|
+
_disposed = false;
|
|
16
|
+
constructor(logger) {
|
|
17
|
+
this.logger = logger;
|
|
18
|
+
}
|
|
19
|
+
/** 追加一个清理函数。dispose 后追加会立刻执行。 */
|
|
20
|
+
push(fn) {
|
|
21
|
+
if (this._disposed) {
|
|
22
|
+
try {
|
|
23
|
+
fn();
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
this.logger?.warn(`DisposableChain: post-dispose 执行失败: ${err}`);
|
|
27
|
+
}
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
this._items.push(fn);
|
|
31
|
+
}
|
|
32
|
+
/** 精确移除单个 disposable(不执行)。用于缓冲项"取消"场景。 */
|
|
33
|
+
remove(fn) {
|
|
34
|
+
const idx = this._items.indexOf(fn);
|
|
35
|
+
if (idx < 0)
|
|
36
|
+
return false;
|
|
37
|
+
this._items.splice(idx, 1);
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
get disposed() {
|
|
41
|
+
return this._disposed;
|
|
42
|
+
}
|
|
43
|
+
/** 当前登记的清理函数数量(诊断 / 测试用:可检测闭包是否如期自移除)。 */
|
|
44
|
+
get size() {
|
|
45
|
+
return this._items.length;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 逆序执行所有清理函数并清空。重复调用无效果。
|
|
49
|
+
* 单个函数抛错被 swallow(可选择通过 logger 记录 debug)。
|
|
50
|
+
*/
|
|
51
|
+
dispose() {
|
|
52
|
+
if (this._disposed)
|
|
53
|
+
return;
|
|
54
|
+
this._disposed = true;
|
|
55
|
+
for (let i = this._items.length - 1; i >= 0; i--) {
|
|
56
|
+
try {
|
|
57
|
+
this._items[i]();
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
this.logger?.debug('DisposableChain: dispose 抛出,已忽略:', err);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
this._items = [];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=disposable-chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disposable-chain.js","sourceRoot":"","sources":["../src/disposable-chain.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,OAAO,eAAe;IAIG;IAHrB,MAAM,GAAmB,EAAE,CAAC;IAC5B,SAAS,GAAG,KAAK,CAAC;IAE1B,YAA6B,MAAe;QAAf,WAAM,GAAN,MAAM,CAAS;IAAG,CAAC;IAEhD,iCAAiC;IACjC,IAAI,CAAC,EAAc;QACjB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,IAAI,CAAC;gBACH,EAAE,EAAE,CAAC;YACP,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,uCAAuC,GAAG,EAAE,CAAC,CAAC;YAClE,CAAC;YACD,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvB,CAAC;IAED,0CAA0C;IAC1C,MAAM,CAAC,EAAc;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,GAAG,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QAC1B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,0CAA0C;IAC1C,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACjD,IAAI,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACnB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IACnB,CAAC;CACF"}
|