berry-agent 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +96 -0
- package/dist/.api-emit.stamp +1 -0
- package/dist/.build-meta.json +6 -0
- package/dist/agent/events.js +1 -0
- package/dist/agent/index.js +2 -0
- package/dist/agent/loop.js +139 -0
- package/dist/agent/queue.js +119 -0
- package/dist/agent/stream.js +62 -0
- package/dist/agent/tools-batch.js +221 -0
- package/dist/agent/types.js +8 -0
- package/dist/api/berry-agent-llm.d.ts +18 -0
- package/dist/api/berry-agent.d.ts +9 -0
- package/dist/api/surface.json +1632 -0
- package/dist/api/tsconfig.paths.json +12 -0
- package/dist/api/typebox-compile.d.ts +2 -0
- package/dist/api/typebox-value.d.ts +2 -0
- package/dist/api/typebox.d.ts +2 -0
- package/dist/browser/cdp.js +256 -0
- package/dist/browser/codes.js +31 -0
- package/dist/browser/discover.js +107 -0
- package/dist/browser/engine.js +169 -0
- package/dist/browser/index.js +17 -0
- package/dist/browser/install.js +342 -0
- package/dist/browser/page.js +321 -0
- package/dist/browser/service.js +158 -0
- package/dist/browser/tools.js +198 -0
- package/dist/browser/types.js +81 -0
- package/dist/channels/ask-queue.js +82 -0
- package/dist/channels/commands.js +129 -0
- package/dist/channels/engine/cell.js +143 -0
- package/dist/channels/engine/diff.js +143 -0
- package/dist/channels/engine/engine.js +416 -0
- package/dist/channels/engine/index.js +8 -0
- package/dist/channels/engine/input-keys.js +86 -0
- package/dist/channels/engine/input.js +596 -0
- package/dist/channels/engine/memory-io.js +71 -0
- package/dist/channels/engine/process-io.js +38 -0
- package/dist/channels/engine/types.js +17 -0
- package/dist/channels/engine/width.js +122 -0
- package/dist/channels/index.js +15 -0
- package/dist/channels/registry.js +56 -0
- package/dist/channels/sdk/admit.js +29 -0
- package/dist/channels/sdk/backend.js +102 -0
- package/dist/channels/sdk/cursor.js +56 -0
- package/dist/channels/sdk/index.js +20 -0
- package/dist/channels/sdk/jsonl.js +208 -0
- package/dist/channels/sdk/protocol.js +24 -0
- package/dist/channels/sdk/schema.js +91 -0
- package/dist/channels/sdk/wire-core.js +446 -0
- package/dist/channels/service.js +169 -0
- package/dist/channels/tui/autocomplete/autocomplete.js +42 -0
- package/dist/channels/tui/autocomplete/file-mentions.js +106 -0
- package/dist/channels/tui/autocomplete/popup.js +148 -0
- package/dist/channels/tui/autocomplete/provider.js +7 -0
- package/dist/channels/tui/autocomplete/token.js +68 -0
- package/dist/channels/tui/backend/ansi-rows.js +211 -0
- package/dist/channels/tui/backend/main-screen.js +207 -0
- package/dist/channels/tui/backend/osc.js +91 -0
- package/dist/channels/tui/backend/transcript.js +230 -0
- package/dist/channels/tui/backend/tui-backend.js +915 -0
- package/dist/channels/tui/editor/editor-model.js +543 -0
- package/dist/channels/tui/editor/editor-view.js +140 -0
- package/dist/channels/tui/editor/editor.js +275 -0
- package/dist/channels/tui/editor/undo-stack.js +35 -0
- package/dist/channels/tui/editor/visual-lines.js +126 -0
- package/dist/channels/tui/editor/word-nav.js +106 -0
- package/dist/channels/tui/history/history-viewer.js +403 -0
- package/dist/channels/tui/index.js +3 -0
- package/dist/channels/tui/layout.js +167 -0
- package/dist/channels/tui/markdown/blocks.js +111 -0
- package/dist/channels/tui/markdown/inline.js +75 -0
- package/dist/channels/tui/markdown/markdown.js +182 -0
- package/dist/channels/tui/memory/memory-viewer.js +540 -0
- package/dist/channels/tui/overlay/alt-screen.js +105 -0
- package/dist/channels/tui/overlay/overlay.js +57 -0
- package/dist/channels/tui/overlay/select-confirm.js +156 -0
- package/dist/channels/tui/panels/todo-panel.js +54 -0
- package/dist/channels/tui/panels/tool-progress-panel.js +93 -0
- package/dist/channels/tui/scroll/scroll-view.js +254 -0
- package/dist/channels/tui/status/status-line.js +76 -0
- package/dist/channels/tui/text.js +38 -0
- package/dist/channels/tui/theme.js +41 -0
- package/dist/channels/types.js +11 -0
- package/dist/channels/ui-core.js +209 -0
- package/dist/checkpoint/capture.js +45 -0
- package/dist/checkpoint/codes.js +33 -0
- package/dist/checkpoint/command.js +82 -0
- package/dist/checkpoint/gate.js +48 -0
- package/dist/checkpoint/index.js +20 -0
- package/dist/checkpoint/restore.js +172 -0
- package/dist/checkpoint/store.js +247 -0
- package/dist/checkpoint/types.js +4 -0
- package/dist/checkpoint/walk.js +146 -0
- package/dist/compaction/ccr-tools.js +112 -0
- package/dist/compaction/ccr.js +84 -0
- package/dist/compaction/codes.js +21 -0
- package/dist/compaction/index.js +18 -0
- package/dist/compaction/policy.js +200 -0
- package/dist/compaction/service.js +422 -0
- package/dist/compaction/slots.js +121 -0
- package/dist/compaction/types.js +10 -0
- package/dist/context/codes.js +40 -0
- package/dist/context/events.js +160 -0
- package/dist/context/index.js +13 -0
- package/dist/context/logger.js +136 -0
- package/dist/context/scope.js +182 -0
- package/dist/context/workspace.js +104 -0
- package/dist/contracts/agent-events.d.ts +73 -0
- package/dist/contracts/agent-events.js +16 -0
- package/dist/contracts/api.d.ts +249 -0
- package/dist/contracts/api.js +299 -0
- package/dist/contracts/approval.d.ts +37 -0
- package/dist/contracts/approval.js +9 -0
- package/dist/contracts/env-ref.d.ts +41 -0
- package/dist/contracts/env-ref.js +32 -0
- package/dist/contracts/errors.d.ts +56 -0
- package/dist/contracts/errors.js +266 -0
- package/dist/contracts/events.d.ts +70 -0
- package/dist/contracts/events.js +329 -0
- package/dist/contracts/index.d.ts +32 -0
- package/dist/contracts/index.js +26 -0
- package/dist/contracts/llm.d.ts +275 -0
- package/dist/contracts/llm.js +12 -0
- package/dist/contracts/messages.d.ts +63 -0
- package/dist/contracts/messages.js +65 -0
- package/dist/contracts/redact.d.ts +46 -0
- package/dist/contracts/redact.js +223 -0
- package/dist/contracts/tools.d.ts +197 -0
- package/dist/contracts/tools.js +33 -0
- package/dist/contracts/types.d.ts +302 -0
- package/dist/contracts/types.js +50 -0
- package/dist/contracts/ui.d.ts +122 -0
- package/dist/contracts/ui.js +15 -0
- package/dist/conversation/agent-service.js +61 -0
- package/dist/conversation/approval-wiring.js +82 -0
- package/dist/conversation/backoff.js +38 -0
- package/dist/conversation/codes.js +47 -0
- package/dist/conversation/control-tools.js +102 -0
- package/dist/conversation/control.js +210 -0
- package/dist/conversation/driver.js +922 -0
- package/dist/conversation/index.js +12 -0
- package/dist/conversation/model-visible.js +169 -0
- package/dist/conversation/open-tools.js +126 -0
- package/dist/conversation/reseed.js +132 -0
- package/dist/conversation/sessions.js +215 -0
- package/dist/conversation/todo.js +203 -0
- package/dist/conversation/types.js +35 -0
- package/dist/conversation/wiring.js +204 -0
- package/dist/credentials/codes.js +59 -0
- package/dist/credentials/commands.js +186 -0
- package/dist/credentials/env-ref.js +34 -0
- package/dist/credentials/index.js +28 -0
- package/dist/credentials/migration.js +18 -0
- package/dist/credentials/oauth.js +266 -0
- package/dist/credentials/refresh.js +152 -0
- package/dist/credentials/secrets.js +118 -0
- package/dist/credentials/types.js +30 -0
- package/dist/exec/bash.js +279 -0
- package/dist/exec/codes.js +37 -0
- package/dist/exec/env.js +99 -0
- package/dist/exec/environment.js +39 -0
- package/dist/exec/git-guard.js +623 -0
- package/dist/exec/index.js +24 -0
- package/dist/exec/registry.js +120 -0
- package/dist/exec/spawn.js +281 -0
- package/dist/exec/tail.js +77 -0
- package/dist/exec/types.js +5 -0
- package/dist/goal/codes.js +33 -0
- package/dist/goal/command.js +175 -0
- package/dist/goal/fold.js +121 -0
- package/dist/goal/gates.js +122 -0
- package/dist/goal/index.js +22 -0
- package/dist/goal/migration.js +48 -0
- package/dist/goal/service.js +501 -0
- package/dist/goal/todo-tool.js +174 -0
- package/dist/goal/types.js +1 -0
- package/dist/goal/update-tool.js +46 -0
- package/dist/host/approval-cmd.js +276 -0
- package/dist/host/assembly.js +1146 -0
- package/dist/host/boot-failures.js +104 -0
- package/dist/host/budget-advisory.js +74 -0
- package/dist/host/budget-broadcast.js +50 -0
- package/dist/host/builtins.js +54 -0
- package/dist/host/cli.js +544 -0
- package/dist/host/codes.js +120 -0
- package/dist/host/config-schema.js +195 -0
- package/dist/host/conversation-stack.js +654 -0
- package/dist/host/core-plugins.js +1685 -0
- package/dist/host/credentials-cmd.js +42 -0
- package/dist/host/disclosure.js +30 -0
- package/dist/host/dispatch.js +105 -0
- package/dist/host/doors-cmd.js +154 -0
- package/dist/host/dump-config.js +44 -0
- package/dist/host/hook-dispatch-guard.js +27 -0
- package/dist/host/import-gate.js +153 -0
- package/dist/host/index.js +54 -0
- package/dist/host/issue-session.js +241 -0
- package/dist/host/loader.js +372 -0
- package/dist/host/main.js +161 -0
- package/dist/host/manifest.js +381 -0
- package/dist/host/mcp-entry.js +53 -0
- package/dist/host/plugin-boot.js +952 -0
- package/dist/host/plugin-context.js +672 -0
- package/dist/host/plugin-install.js +480 -0
- package/dist/host/plugin-reload.js +124 -0
- package/dist/host/plugin-store.js +462 -0
- package/dist/host/plugin-tools.js +359 -0
- package/dist/host/plugin-uninstall.js +257 -0
- package/dist/host/plugins-cmd.js +302 -0
- package/dist/host/plugins-command.js +130 -0
- package/dist/host/plugins-config.js +195 -0
- package/dist/host/prompt-sections.js +133 -0
- package/dist/host/run-entry.js +544 -0
- package/dist/host/runtime.js +209 -0
- package/dist/host/scheduler-tick.js +294 -0
- package/dist/host/serve-daemon.js +501 -0
- package/dist/host/serve-entry.js +279 -0
- package/dist/host/session-anchor.js +41 -0
- package/dist/host/sessions-cmd.js +219 -0
- package/dist/host/sessions-face.js +47 -0
- package/dist/host/settings-store.js +112 -0
- package/dist/host/signals.js +69 -0
- package/dist/host/single-instance.js +105 -0
- package/dist/host/subagent-factory.js +291 -0
- package/dist/host/testkit/harness.js +283 -0
- package/dist/host/testkit/index.js +14 -0
- package/dist/host/testkit/matrix.js +302 -0
- package/dist/host/tool-policy-store.js +177 -0
- package/dist/host/triggers.js +212 -0
- package/dist/host/tui-entry.js +216 -0
- package/dist/host/webui-bridge.js +165 -0
- package/dist/issue/codes.js +38 -0
- package/dist/issue/filter.js +146 -0
- package/dist/issue/github.js +116 -0
- package/dist/issue/index.js +17 -0
- package/dist/issue/mount.js +70 -0
- package/dist/issue/poll.js +58 -0
- package/dist/issue/service.js +341 -0
- package/dist/issue/tools.js +70 -0
- package/dist/issue/types.js +34 -0
- package/dist/issue/webhook.js +126 -0
- package/dist/llm/codes.js +77 -0
- package/dist/llm/complete.js +196 -0
- package/dist/llm/events.js +15 -0
- package/dist/llm/index.js +24 -0
- package/dist/llm/inflight.js +65 -0
- package/dist/llm/model-id.js +58 -0
- package/dist/llm/provider-face.d.ts +32 -0
- package/dist/llm/provider-face.js +34 -0
- package/dist/llm/recovery.js +146 -0
- package/dist/llm/runtime.js +46 -0
- package/dist/llm/stream-fn.js +147 -0
- package/dist/lsp/codes.js +31 -0
- package/dist/lsp/connection.js +147 -0
- package/dist/lsp/frame.js +110 -0
- package/dist/lsp/index.js +16 -0
- package/dist/lsp/inject.js +58 -0
- package/dist/lsp/instance.js +264 -0
- package/dist/lsp/service.js +522 -0
- package/dist/lsp/tools.js +53 -0
- package/dist/lsp/types.js +201 -0
- package/dist/mcp/bridge.js +222 -0
- package/dist/mcp/codes.js +21 -0
- package/dist/mcp/index.js +19 -0
- package/dist/mcp/jsonrpc.js +230 -0
- package/dist/mcp/service.js +125 -0
- package/dist/mcp/tools.js +145 -0
- package/dist/mcp/types.js +108 -0
- package/dist/memory/cite.js +131 -0
- package/dist/memory/codes.js +50 -0
- package/dist/memory/command.js +71 -0
- package/dist/memory/consolidate.js +219 -0
- package/dist/memory/cycle.js +109 -0
- package/dist/memory/dao.js +878 -0
- package/dist/memory/diff.js +238 -0
- package/dist/memory/extract.js +181 -0
- package/dist/memory/fts.js +58 -0
- package/dist/memory/index.js +42 -0
- package/dist/memory/inject.js +354 -0
- package/dist/memory/merge.js +178 -0
- package/dist/memory/migration.js +132 -0
- package/dist/memory/pollution.js +59 -0
- package/dist/memory/port.js +385 -0
- package/dist/memory/review.js +201 -0
- package/dist/memory/scan.js +89 -0
- package/dist/memory/tools.js +508 -0
- package/dist/memory/types.js +140 -0
- package/dist/obs/codes.js +38 -0
- package/dist/obs/db.js +115 -0
- package/dist/obs/index.js +20 -0
- package/dist/obs/rollup.js +61 -0
- package/dist/obs/service.js +363 -0
- package/dist/obs/session-tools.js +282 -0
- package/dist/obs/session-view.js +225 -0
- package/dist/obs/tool.js +97 -0
- package/dist/obs/types.js +1 -0
- package/dist/persist/audit.js +63 -0
- package/dist/persist/aux.js +39 -0
- package/dist/persist/codes.js +35 -0
- package/dist/persist/index.js +30 -0
- package/dist/persist/load-history.js +50 -0
- package/dist/persist/migrations.js +37 -0
- package/dist/persist/paths.js +108 -0
- package/dist/persist/persistence.js +229 -0
- package/dist/persist/schema.js +99 -0
- package/dist/persist/secret-box.js +95 -0
- package/dist/persist/store.js +706 -0
- package/dist/persist/write-behind.js +238 -0
- package/dist/safety/approval.js +171 -0
- package/dist/safety/bwrap.js +123 -0
- package/dist/safety/codes.js +57 -0
- package/dist/safety/danger.js +505 -0
- package/dist/safety/gate.js +226 -0
- package/dist/safety/index.js +24 -0
- package/dist/safety/presets.js +73 -0
- package/dist/safety/roots.js +139 -0
- package/dist/safety/sandbox.js +214 -0
- package/dist/safety/seatbelt.js +88 -0
- package/dist/safety/sensitive.js +34 -0
- package/dist/safety/tool-policy.js +203 -0
- package/dist/safety/types.js +13 -0
- package/dist/scheduler/codes.js +54 -0
- package/dist/scheduler/cron-backend.js +135 -0
- package/dist/scheduler/engine.js +280 -0
- package/dist/scheduler/gates.js +60 -0
- package/dist/scheduler/index.js +25 -0
- package/dist/scheduler/migration.js +22 -0
- package/dist/scheduler/runner.js +171 -0
- package/dist/scheduler/schedule.js +193 -0
- package/dist/scheduler/service.js +283 -0
- package/dist/scheduler/tick.js +139 -0
- package/dist/scheduler/types.js +1 -0
- package/dist/sdk/http.js +865 -0
- package/dist/sdk/index.js +22 -0
- package/dist/sdk/mcp.js +289 -0
- package/dist/sdk/plugin-route-registry.js +126 -0
- package/dist/sdk/plugin-routes.js +149 -0
- package/dist/sdk/security.js +116 -0
- package/dist/sdk/types.js +32 -0
- package/dist/session/budget.js +159 -0
- package/dist/session/codes.js +40 -0
- package/dist/session/derive.js +180 -0
- package/dist/session/event-data.js +1 -0
- package/dist/session/fork.js +72 -0
- package/dist/session/import-gates.js +148 -0
- package/dist/session/index.js +18 -0
- package/dist/session/recover.js +103 -0
- package/dist/session/session.js +279 -0
- package/dist/session/snapshot.js +107 -0
- package/dist/skills/agents.js +242 -0
- package/dist/skills/codes.js +51 -0
- package/dist/skills/discovery.js +266 -0
- package/dist/skills/frontmatter.js +215 -0
- package/dist/skills/index.js +28 -0
- package/dist/skills/load.js +118 -0
- package/dist/skills/manage.js +201 -0
- package/dist/skills/registry.js +138 -0
- package/dist/skills/render.js +124 -0
- package/dist/skills/sections.js +171 -0
- package/dist/skills/types.js +21 -0
- package/dist/subagent/codes.js +50 -0
- package/dist/subagent/declarative.js +55 -0
- package/dist/subagent/index.js +19 -0
- package/dist/subagent/notify.js +51 -0
- package/dist/subagent/provide.js +7 -0
- package/dist/subagent/registry.js +149 -0
- package/dist/subagent/service.js +338 -0
- package/dist/subagent/surface.js +44 -0
- package/dist/subagent/tool.js +153 -0
- package/dist/subagent/types.js +25 -0
- package/dist/tools/apply-patch.js +164 -0
- package/dist/tools/codes.js +109 -0
- package/dist/tools/fs.js +501 -0
- package/dist/tools/index.js +17 -0
- package/dist/tools/observed.js +99 -0
- package/dist/tools/pipeline.js +176 -0
- package/dist/tools/protected-read.js +54 -0
- package/dist/tools/registry.js +250 -0
- package/dist/tools/search.js +451 -0
- package/dist/tools/worktree.js +327 -0
- package/dist/web/codes.js +37 -0
- package/dist/web/gate.js +43 -0
- package/dist/web/hygiene.js +195 -0
- package/dist/web/index.js +16 -0
- package/dist/web/service.js +207 -0
- package/dist/web/ssrf-guard.js +44 -0
- package/dist/web/tool.js +76 -0
- package/dist/web/types.js +10 -0
- package/dist/webui/assets/index-B-t2O8gh.js +22 -0
- package/dist/webui/assets/index-DOlgSZ9Q.css +2 -0
- package/dist/webui/index.html +14 -0
- package/dist/webui/index.js +14 -0
- package/dist/webui/server.js +549 -0
- package/dist/webui/types.js +38 -0
- package/examples/README.md +26 -0
- package/examples/minimal-code-plugin/entry.js +43 -0
- package/examples/minimal-code-plugin/package.json +12 -0
- package/examples/pure-skill-pack/package.json +14 -0
- package/examples/pure-skill-pack/skills/markdown-table/SKILL.md +32 -0
- package/package.json +86 -0
|
@@ -0,0 +1,1685 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* host/core-plugins — core: 官方件注册表单源(批 19a 装载态集成)。
|
|
3
|
+
*
|
|
4
|
+
* 16 件权威清单 = 02 篇 §4.1 core: 行(skills/memory/subagent/exec/mcp/
|
|
5
|
+
* web/browser/lsp/checkpoint/scheduler/goal/obs/webui/sdk/issue +
|
|
6
|
+
* credentials〔c-3 增席 #16——02 §4.1 #28 席〕)——v1 全量
|
|
7
|
+
* 带上默认启用,经同一插件装载面(第一方禁私有车道:对象直调 apply 零
|
|
8
|
+
* jiti 零 import 门禁,03 §1.4 官方引用形)。本件逐件入册(批 19a 起,
|
|
9
|
+
* 每纵切笔入册一批——**批 19e 齐 15 件**,此销账注记兑现:exec/web/
|
|
10
|
+
* skills/memory/subagent/scheduler〔19a/19b/19c-1/2〕→ goal/checkpoint
|
|
11
|
+
* 〔19c-3/4〕→ mcp/browser/lsp〔19d〕→ sdk/webui/obs/issue〔19e〕→
|
|
12
|
+
* credentials〔c-3 件席占位〕)。
|
|
13
|
+
*
|
|
14
|
+
* **apply 壳归宿主侧**(与磁盘件「件自持入口文件」分道):件保持纯库
|
|
15
|
+
* 不 import host(DAG 单向不破——host 是装配根有权 import 各件公开面),
|
|
16
|
+
* 装配逻辑(何时 provide 何服务/注册何工具)属宿主裁决权面(判据面与
|
|
17
|
+
* 接口面之分——02 篇理念节)。ctx 真身在 host 侧直用 PluginContext 类型
|
|
18
|
+
* narrow(零跨件窄面重复——与磁盘件的 unknown 契约面不同,本侧无漂移面)。
|
|
19
|
+
*
|
|
20
|
+
* 会话级 deps(档位/审批/工作区)经服务面工厂形求值:装载期固定构造会
|
|
21
|
+
* 丢会话面(批 19a 定形——ExecToolService 契约见 conversation/types.ts)。
|
|
22
|
+
*/
|
|
23
|
+
import { execFile } from 'node:child_process';
|
|
24
|
+
import { createHash } from 'node:crypto';
|
|
25
|
+
import { homedir } from 'node:os';
|
|
26
|
+
import * as fsp from 'node:fs/promises';
|
|
27
|
+
import { join } from 'node:path';
|
|
28
|
+
import { BaseError } from '../contracts/index.js';
|
|
29
|
+
import { getEventTypeMeta } from '../contracts/index.js';
|
|
30
|
+
import { canonicalWorkspaceRoot } from '../context/index.js';
|
|
31
|
+
import { createMcpService, normalizeMcpConfig } from '../mcp/index.js';
|
|
32
|
+
import { createLspService, normalizeLspSettings } from '../lsp/index.js';
|
|
33
|
+
import { createBrowserService, defaultDownloadFace, defaultWsFace, installBrowserEngine, normalizeBrowserConfig, } from '../browser/index.js';
|
|
34
|
+
import { createCapture, createCheckpointGate, openCheckpointStore, runRewindCommand, REWIND_USAGE, } from '../checkpoint/index.js';
|
|
35
|
+
import { createBashTool, createSpawnPipeline, buildChildEnv } from '../exec/index.js';
|
|
36
|
+
import { createGoalService, createGoalTodoTool, createGoalUpdateTool, runGoalCommand, GOAL_USAGE, } from '../goal/index.js';
|
|
37
|
+
import { createDangerGate, createSandboxService, DANGER_V1_ACTIONS, normalizeDangerMandate } from '../safety/index.js';
|
|
38
|
+
import { createOsCronRegistrar, createProcessRunnerFactory, createSchedulerEngine, createSchedulerService, runTickCommand, TICK_USAGE, } from '../scheduler/index.js';
|
|
39
|
+
import { createSchedulerTickRunner } from './scheduler-tick.js';
|
|
40
|
+
import { createFetchTool, createInFlightGate, createWebFetchService, DEFAULT_WEB_LIMITS } from '../web/index.js';
|
|
41
|
+
import { createLoadSkillTool, createSkillManageTool, createSkillsRegistry, createStandardLayers, renderAvailableSkills, } from '../skills/index.js';
|
|
42
|
+
import { briefBaseline, buildCoreBrief, createCiteRecorder, createDiffTracker, createImmediateExtractor, createLastAssistantTextCache, createMemoryCycle, createMemoryDao, createMemoryTools, diffInjectionMessage, ensureDiffRole, ensureFtsIndex, ensureRecallRole, faceOf, MEMORY_DIFF_EVENT_META, MEMORY_EXPORT_USAGE, MEMORY_IMPORT_USAGE, recallForQuery, recallInjectionMessage, runMemoryExportCommand, runMemoryImportCommand, } from '../memory/index.js';
|
|
43
|
+
import { collectAgentDefs, createAgentLayerProvider, createStandardAgentLayers } from '../skills/index.js';
|
|
44
|
+
import { createAgentTool, materializeDeclarativeSubagents, JOBS_SERVICE_NAME } from '../subagent/index.js';
|
|
45
|
+
// 批 19e HTTP 面族四件(sdk/webui/issue/obs——core 15 件齐册)
|
|
46
|
+
import { createSdkHttpFace } from '../sdk/index.js';
|
|
47
|
+
import { createObsQueryTool, createObsService } from '../obs/index.js';
|
|
48
|
+
import { createGithubBackend, createIssueService, mountIssueWebhook, normalizeIssueConfig } from '../issue/index.js';
|
|
49
|
+
import { createWorktreeService } from '../tools/index.js';
|
|
50
|
+
// c 批 credentials 件(c-3 席占位入册 / c-5 人面命令注册——03 §10.9)
|
|
51
|
+
import { CREDENTIALS_USAGE, parseCredentialsArgv, runCredentialsCommand, runDeviceCodeFlow, resolveOAuthFlow, createRefreshChain, } from '../credentials/index.js';
|
|
52
|
+
/**
|
|
53
|
+
* core:exec——spawn 管道装载期自持(进程级单例:登记簿/孤儿清扫随管道
|
|
54
|
+
* 同生命周期)+ 'exec' 服务面供给(会话装配期工厂形——exec 禁用 = bash
|
|
55
|
+
* 静默缺席,对话本体仍通)。bash 工具件经 openTools 既有消费位拾取
|
|
56
|
+
* (scope.tryGet 诚实缺席律),不走 ctx.tools.register 散装注册(双路
|
|
57
|
+
* 会撞名——装载面单路执法)。
|
|
58
|
+
*
|
|
59
|
+
* 'exec-pipeline' 第二供给位(批 19d):SpawnPipeline 真身——三桥(mcp/
|
|
60
|
+
* browser/lsp)子进程「spawn 管道 + 登记簿同册」的单源(04 §11 spawn
|
|
61
|
+
* 管道注释明文「三桥共用」)。exec 件禁用 = 管道缺席 = 三桥 spawn 主闸
|
|
62
|
+
* 缺席零装载(诚实缺席——单册单源不旁路自建)。
|
|
63
|
+
*
|
|
64
|
+
* c-4 注入腿拾取:apply 期经共享根 tryGet('credentials-env-ref') 取凭证
|
|
65
|
+
* 引用形展开器(plugin-boot 席位接线——与 ctx.secrets 席位门同一双条件;
|
|
66
|
+
* 03 §10.9 注入腿)——MCP/LSP server config env 的 `@credentials:<name>`
|
|
67
|
+
* 在 spawn 时刻单点展开。
|
|
68
|
+
*
|
|
69
|
+
* 工厂形(批 19b-1 deps 聚落律同款):沙箱服务持 dataDir——敏感件读集
|
|
70
|
+
* 单源注入(04 §7 读侧 carve-out 的 profile 腿,2026-09-08 P0①)。
|
|
71
|
+
* dataDir null(:memory: 诊断形)= 无敏感集(confine 零读 deny 行)。
|
|
72
|
+
*/
|
|
73
|
+
function makeExecPlugin(deps) {
|
|
74
|
+
return {
|
|
75
|
+
name: 'exec',
|
|
76
|
+
async apply(ctx) {
|
|
77
|
+
const context = ctx;
|
|
78
|
+
// 管道/沙箱服务进程级单例:spawn 登记簿与后端链探测缓存(probe 有
|
|
79
|
+
// spawn 开销——单例缓存一次)均无会话态;沙箱后端链缺省平台链
|
|
80
|
+
// (macOS seatbelt / Linux bwrap——safety 单源)。
|
|
81
|
+
// 凭证引用形展开器(c-4 注入腿):plugin-boot 席位在场时供入共享根
|
|
82
|
+
// (先于 loadPlugins 全程——装载序无关拾取);缺席 = undefined = 引用形
|
|
83
|
+
// fail-loud(CREDENTIALS_NOT_FOUND——拒以字面值注入,席位缺席律)
|
|
84
|
+
const pipeline = createSpawnPipeline({
|
|
85
|
+
resolveEnvRef: context.tryGet('credentials-env-ref'),
|
|
86
|
+
});
|
|
87
|
+
const sandboxService = createSandboxService({
|
|
88
|
+
// dataDir null = 诊断形无敏感集(skills 工厂同款条件展开形)
|
|
89
|
+
...(deps.dataDir !== null ? { dataDir: deps.dataDir } : {}),
|
|
90
|
+
});
|
|
91
|
+
context.provide('exec-pipeline', pipeline);
|
|
92
|
+
const service = {
|
|
93
|
+
// 会话装配期工厂:进程级单例闭包自持 + 会话级 deps(档位/审批/工作
|
|
94
|
+
// 区)由消费位注入求值——结构契约单源在 conversation/types.ts;
|
|
95
|
+
// deps.sandboxService 显式在场时胜出(测试/宿主覆盖位——展开序在后)
|
|
96
|
+
createBashTool: (deps2) => createBashTool({ pipeline, sandboxService, ...deps2 }),
|
|
97
|
+
};
|
|
98
|
+
context.provide('exec', service);
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* core:web——fetch 工具(effect 'read',经 ctx.tools.register 散装注册走
|
|
104
|
+
* bootTools 重放消费腿)+ 'web-fetch' 服务面供给(02 §4.1 席 18「ctx.fetch」
|
|
105
|
+
* 词面落形:服务名带域防裸名撞位)+ 'web-gate' 在飞门单例供给(03 §10.3
|
|
106
|
+
* browser 件共享同一实例——装配根经共享根传实例的装载面形态)。归因 sink
|
|
107
|
+
* 缺省 no-op(观测面挂账归 obs 纵切笔——sink 不绑架数据面)。
|
|
108
|
+
*/
|
|
109
|
+
const webPlugin = {
|
|
110
|
+
name: 'web',
|
|
111
|
+
async apply(ctx) {
|
|
112
|
+
const context = ctx;
|
|
113
|
+
// 在飞门单例(容量缺省单源 DEFAULT_WEB_LIMITS.maxConcurrent = 4——fetch
|
|
114
|
+
// 工具/服务面/browser 导航三消费位同一实例)
|
|
115
|
+
const gate = createInFlightGate(DEFAULT_WEB_LIMITS.maxConcurrent);
|
|
116
|
+
const service = createWebFetchService({ gate });
|
|
117
|
+
context.provide('web-fetch', service);
|
|
118
|
+
context.provide('web-gate', gate);
|
|
119
|
+
// 工具注册(boot 全局层——openTools 会话装配重放走真三段管道)
|
|
120
|
+
return context.tools.register(createFetchTool(service));
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* core:skills——技能注册表装载(06 §11 渐进披露装载态兑现):标准六位层
|
|
125
|
+
* 构造 + 全量 refresh 落快照 + 'skills' 服务面供给(插件 tryGet 消费)+
|
|
126
|
+
* skill_manage 管理工具 + load_skill 装载工具(boot 全局层散装注册——
|
|
127
|
+
* bootTools 重放消费腿;06 §11.5(a) 按需拉取模)+ 'skills/manifest'
|
|
128
|
+
* 提示词段(每请求物化——registry 快照变化即生效,06 §11.3 渐进披露的
|
|
129
|
+
* 「披露清单」半边;装载半边 = load_skill 具名通道 / read FS 通道归
|
|
130
|
+
* agent 工具面)。
|
|
131
|
+
*
|
|
132
|
+
* 磁盘件技能目录载荷层(06 §11.4 位 4)不在此 apply——装载序结构性晚到
|
|
133
|
+
* (synthesizePlan core 行先入 plan,磁盘件 manifest.skills 此刻未激活),
|
|
134
|
+
* 补注册编舞(摘 factory → 位 4 逐插件插入 → factory 重挂保序)落 assembly
|
|
135
|
+
* boot 后段(2026-09-08 批 19 skills 销账笔兑现——06 §11.3 插件层压出厂层)。
|
|
136
|
+
*
|
|
137
|
+
* skills_change 事件桥不在此(ctx.emit 域名律强制 `core:skills/` 前缀
|
|
138
|
+
* ——全局词结构性不可达):桥落 assembly boot 后段(宿主侧
|
|
139
|
+
* dispatch.emit 直发——03 §3.4 汇流点同形)。
|
|
140
|
+
*/
|
|
141
|
+
function makeSkillsPlugin(deps) {
|
|
142
|
+
return {
|
|
143
|
+
name: 'skills',
|
|
144
|
+
async apply(ctx) {
|
|
145
|
+
const context = ctx;
|
|
146
|
+
// 标准六位层(project/user/跨库/出厂——插件层装载收口后于 assembly 补
|
|
147
|
+
// 注册见上注;dataDir null 跳过 user 层;cwd/homeDir 缺省真跑形)
|
|
148
|
+
const registry = createSkillsRegistry();
|
|
149
|
+
const layers = createStandardLayers({
|
|
150
|
+
...(deps.cwd !== undefined ? { cwd: deps.cwd } : {}),
|
|
151
|
+
...(deps.dataDir !== null ? { dataDir: deps.dataDir } : {}),
|
|
152
|
+
...(deps.homeDir !== undefined ? { homeDir: deps.homeDir } : {}),
|
|
153
|
+
});
|
|
154
|
+
for (const layer of layers)
|
|
155
|
+
registry.registerProvider(layer);
|
|
156
|
+
await registry.refresh(); // 装载期落首版快照(诊断 warn 不杀装载)
|
|
157
|
+
context.provide('skills', registry);
|
|
158
|
+
// skill_manage:workspaceRoot = canonical 工作区根(create 落点锚);
|
|
159
|
+
// 可写面 = project `.agents/skills`(06 §11 用户/跨库层只读——写点
|
|
160
|
+
// 前置断言面在件内)
|
|
161
|
+
const workspaceRoot = () => canonicalWorkspaceRoot();
|
|
162
|
+
const disposeManageTool = context.tools.register(createSkillManageTool({
|
|
163
|
+
registry,
|
|
164
|
+
workspaceRoot,
|
|
165
|
+
writableRoots: () => [join(workspaceRoot(), '.agents', 'skills')],
|
|
166
|
+
}));
|
|
167
|
+
// load_skill:按需拉取模装载工具(06 §11.5(a) 具名通道——只读无审批对)
|
|
168
|
+
const disposeLoadTool = context.tools.register(createLoadSkillTool({ registry }));
|
|
169
|
+
// 披露清单段:builder 每请求物化时重取快照(PromptSectionBuilder
|
|
170
|
+
// 求值即取——refresh 后变化自然生效)
|
|
171
|
+
const disposeSection = context.prompts.registerSection('skills/manifest', () => renderAvailableSkills(registry.list()).text);
|
|
172
|
+
return () => {
|
|
173
|
+
disposeSection();
|
|
174
|
+
disposeLoadTool();
|
|
175
|
+
disposeManageTool();
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* 当轮 query 取数(06 §294——recall 注入腿消费位):durable 日志尾扫最后一条
|
|
182
|
+
* user/message 的 string content(非 string 形〔parts 数组〕不作 query——宁缺
|
|
183
|
+
* 毋滥)。从 durable 日志取而非 LLM batch 尾扫:diff handler 先注入的 user 形
|
|
184
|
+
* 消息会污染 batch 尾扫判据(注入序依赖)。fetchEvents 缺席/读失败/扫到头 →
|
|
185
|
+
* null(零 query 即零注入)。
|
|
186
|
+
*/
|
|
187
|
+
function lastUserQueryText(fetchEvents, sessionId) {
|
|
188
|
+
if (fetchEvents === undefined)
|
|
189
|
+
return null;
|
|
190
|
+
try {
|
|
191
|
+
const events = fetchEvents(sessionId);
|
|
192
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
193
|
+
const event = events[i];
|
|
194
|
+
if (event.type !== 'user/message')
|
|
195
|
+
continue;
|
|
196
|
+
const content = event.data?.content;
|
|
197
|
+
return typeof content === 'string' ? content : null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* core:memory(批 19b-2)——06 篇记忆面全环装载:DAO(宿主库同库——05 §6.4
|
|
207
|
+
* 迁移链已由 runtime 机械聚合)+ 九工具散装注册(boot 全局层)+ 'memory/core'
|
|
208
|
+
* 常驻简报段(每请求物化)+ session/event 三消费腿(即时提取/引用记录/周期
|
|
209
|
+
* 计数——03 §146 活体镜像的汇入点,发射位在 Persistence.onDurableEvent 桥)+
|
|
210
|
+
* run 终态 due→fire(06 §5 计数挂件拍点 = 会话空闲即审)+ 激活期 FTS 对账 +
|
|
211
|
+
* memory/diff 词汇注册(不可逆装配面)+ memory-export/import 两命令 +
|
|
212
|
+
* 'memory' 服务面供给。
|
|
213
|
+
*
|
|
214
|
+
* 路 2(recallForQuery 按需检索)已接线(批 19 销账笔——06 §6 路 2 消费腿:
|
|
215
|
+
* minScore 水位旋钮缺省不设位〔拍板维持〕——检索路本身在场);diff 发射位
|
|
216
|
+
* (sessions.appendEventFor 绑会话闭包)与 diff/recall 两注入腿
|
|
217
|
+
* (context_transform 瀑布——06 §328 注入序 diff 先 recall 后)同批收口。
|
|
218
|
+
*
|
|
219
|
+
* 降级梯:sqlite 缺席 = 件整体零装载(主闸);llm/fetchEvents 缺席 = 周期腿
|
|
220
|
+
* 缺席(即时提取仍通);ftsSearch/ftsMaintenance/notify 各自缺席各腿静默降级;
|
|
221
|
+
* sessions 服务缺席 = 差分降级只渲染不落账(mirror 不锁步)。
|
|
222
|
+
*/
|
|
223
|
+
function makeMemoryPlugin(deps) {
|
|
224
|
+
return {
|
|
225
|
+
name: 'memory',
|
|
226
|
+
async apply(ctx) {
|
|
227
|
+
const context = ctx;
|
|
228
|
+
const db = deps.sqlite?.();
|
|
229
|
+
if (db === undefined)
|
|
230
|
+
return; // 主闸——库座缺席零装载(诚实缺席律)
|
|
231
|
+
const warn = (message) => console.error(message);
|
|
232
|
+
const now = () => Date.now();
|
|
233
|
+
// owner 并集(06 §3/§6):global + project:<canonical 根 sha256 前 16 hex>。
|
|
234
|
+
// 哈希公式属装配侧约定(spec 只钉根语义未钉公式——同根同键跨会话稳定
|
|
235
|
+
// 即要求;dao 侧 regex 容 8-64 hex)
|
|
236
|
+
const workspaceRoot = () => canonicalWorkspaceRoot(deps.cwd);
|
|
237
|
+
const projectKey = `project:${createHash('sha256').update(workspaceRoot()).digest('hex').slice(0, 16)}`;
|
|
238
|
+
const ownerKeys = ['global', projectKey];
|
|
239
|
+
const dao = createMemoryDao({ db, now, warn });
|
|
240
|
+
// 激活期 FTS 对账(06 §10——抽样缺缝全量重建;维护 seam 缺席跳过)
|
|
241
|
+
if (deps.ftsMaintenance !== undefined) {
|
|
242
|
+
ensureFtsIndex({ face: deps.ftsMaintenance, warn });
|
|
243
|
+
}
|
|
244
|
+
// 工具面九件(boot 全局层散装注册——bootTools 会话装配重放消费腿)
|
|
245
|
+
const memoryToolDefs = createMemoryTools({
|
|
246
|
+
dao,
|
|
247
|
+
ownerKeys,
|
|
248
|
+
...(deps.ftsSearch !== undefined ? { sessionFts: deps.ftsSearch } : {}),
|
|
249
|
+
});
|
|
250
|
+
const disposeMemoryTools = memoryToolDefs.map((def) => context.tools.register(def));
|
|
251
|
+
// 周期路在场判(llm + fetchEvents 双在场才建——缺一即周期腿整体缺席)
|
|
252
|
+
const cycle = deps.llm !== undefined && deps.fetchEvents !== undefined
|
|
253
|
+
? createMemoryCycle({ dao, llm: deps.llm(), fetchEvents: deps.fetchEvents, warn })
|
|
254
|
+
: undefined;
|
|
255
|
+
// per-session 最近 assistant 文本回看缓存(§4 即时路第二动作——2026-09-08
|
|
256
|
+
// 消化批;同一 session/event 消费点内喂入零新事件通道,LRU 帽族同 §6 epochs)
|
|
257
|
+
const lastAssistant = createLastAssistantTextCache();
|
|
258
|
+
// 即时提取(isSessionPolluted 与周期路共享同源追踪器——周期腿缺席时
|
|
259
|
+
// 无污染判定源,提取不滤 = 保守多提取,不丢纠正信号)
|
|
260
|
+
const extractor = createImmediateExtractor({
|
|
261
|
+
dao,
|
|
262
|
+
...(cycle !== undefined ? { isSessionPolluted: (id) => cycle.pollution.isPolluted(id) } : {}),
|
|
263
|
+
// 回看位(§4 即时路第二动作——2026-09-08 消化批):同会话紧邻前一条
|
|
264
|
+
// assistant 文本(负效用回写消费;喂入腿在下方 session/event 消费点内)
|
|
265
|
+
lastAssistantText: lastAssistant.get,
|
|
266
|
+
warn,
|
|
267
|
+
});
|
|
268
|
+
const cite = createCiteRecorder({ dao, warn });
|
|
269
|
+
// session/event 三消费腿(03 §146——user/message→即时提取;assistant/
|
|
270
|
+
// message→引用记录(件内自滤)+ 回看缓存喂入(§4 第二动作——空文本面
|
|
271
|
+
// 同覆写,「紧邻前一条」语义忠实);全事件→周期计数(件内自滤 turn/end +
|
|
272
|
+
// tool/call)。surfaceOp 遮蔽指令不进消费面(surface 事件滤除)。
|
|
273
|
+
// 观察者异常隔离双保险:dispatch.emit 监听器互隔离 + 发射侧 try/catch)
|
|
274
|
+
const disposeHook = context.on('session/event', (data) => {
|
|
275
|
+
const { sessionId, event } = data;
|
|
276
|
+
if (event.surfaceOp !== undefined)
|
|
277
|
+
return;
|
|
278
|
+
if (event.type === 'user/message') {
|
|
279
|
+
extractor.onUserMessage(sessionId, event.seq, event.data);
|
|
280
|
+
}
|
|
281
|
+
else if (event.type === 'assistant/message') {
|
|
282
|
+
lastAssistant.observe(sessionId, event.data);
|
|
283
|
+
}
|
|
284
|
+
cite.onEvent(sessionId, event.type, event.data);
|
|
285
|
+
cycle?.onDurableEvent(sessionId, event);
|
|
286
|
+
});
|
|
287
|
+
// run 终态 due→fire(06 §5——会话空闲即审拍点;只 fire 本会话:他会话
|
|
288
|
+
// 各在其自身 settle 拍点 fire。inFlight 单飞锁 + fire 永不抛归件内)
|
|
289
|
+
const agent = context.tryGet('agent');
|
|
290
|
+
const disposeSettle = agent?.onRunSettled((event) => {
|
|
291
|
+
if (cycle !== undefined && cycle.dueSessions().includes(event.sessionId)) {
|
|
292
|
+
void cycle.fire(event.sessionId);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
// 常驻简报段(每请求物化——06 §6 路 1;cache 经济批 ca-2 定形:volatile
|
|
296
|
+
// 声明 + 每会话懒冻结两律合用——03 §2.5 既有宿主段归类基线②)。简报含
|
|
297
|
+
// O1 批时效词面(freshnessLabel 随 nowMs 派生——inject.ts),跨日/TTL
|
|
298
|
+
// 阈值穿越即代内漂移:缺省承诺稳定面下日界一过即 warn 噪声 + 前缀失效
|
|
299
|
+
// ——两律合用取两全:
|
|
300
|
+
// - volatile 声明 = 跨请求可变诚实化(免漂移 warn + 物化位恒段区尾
|
|
301
|
+
// ——豁免多会话宿主下交替物化的跨会话锚噪声);
|
|
302
|
+
// - 每会话懒冻结 = 会话内字节恒定兑现缓存价值:首请求物化即冻结该会话
|
|
303
|
+
// 简报文本,时效词面取冻结时点值(跨会话各自冻结;会话内记忆变更经
|
|
304
|
+
// memory/diff 瞬态注入腿呈现——06 §6 差分通道,简报本体不追新);
|
|
305
|
+
// sessionId 缺席形〔诊断直物化〕活体物化不冻结。冻结缓存帽 256 会话
|
|
306
|
+
// 逐最旧为兜底位(装载代内闭包——/reload 换代新实例自然重置;批 19
|
|
307
|
+
// 「简报每会话冻结管道改造」挂账随本笔兑销);主摘除腿 = 会话收口
|
|
308
|
+
// 经宿主订阅面摘条目(发现 ⑯——收口后复续首物化重冻结取新值,见下)
|
|
309
|
+
const briefFreezeCache = new Map();
|
|
310
|
+
// 收口摘除订阅(发现 ⑯):retire 成功路摘该会话冻结条目——下次 open
|
|
311
|
+
// 复续首物化重冻结(收口后的记忆变更不困在旧冻结里)。订阅位缺席形
|
|
312
|
+
// (测试替身)无此腿——帽 256 FIFO 兜底仍在
|
|
313
|
+
deps.subscribeSessionRetire?.((sessionId) => briefFreezeCache.delete(sessionId));
|
|
314
|
+
const disposeBrief = context.prompts.registerSection('memory/core', (sessionId) => {
|
|
315
|
+
// sessionId 缺席 = 诊断直物化形——无会话身份可冻结,活体物化
|
|
316
|
+
if (sessionId === undefined)
|
|
317
|
+
return buildCoreBrief({ dao, now, ownerKeys });
|
|
318
|
+
const frozen = briefFreezeCache.get(sessionId);
|
|
319
|
+
if (frozen !== undefined)
|
|
320
|
+
return frozen;
|
|
321
|
+
const brief = buildCoreBrief({ dao, now, ownerKeys });
|
|
322
|
+
// 帽 256 逐最旧(Map 插入序 = 首冻结序)
|
|
323
|
+
if (briefFreezeCache.size >= 256) {
|
|
324
|
+
const oldest = briefFreezeCache.keys().next().value;
|
|
325
|
+
if (oldest !== undefined)
|
|
326
|
+
briefFreezeCache.delete(oldest);
|
|
327
|
+
}
|
|
328
|
+
briefFreezeCache.set(sessionId, brief);
|
|
329
|
+
return brief;
|
|
330
|
+
}, {
|
|
331
|
+
volatile: {
|
|
332
|
+
reason: '简报时效词面与懒基线随会话/时间自然变化(03 §2.5 归类基线②——每会话懒冻结兜会话内稳定)',
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
// memory/diff 词汇注册(不可逆装配面——06 §329 装载面作用域化注册)。
|
|
336
|
+
// 注册表进程级单例(contracts/events 模块态):同进程多次装配(测试多例
|
|
337
|
+
// /热重启形)同 owner 已在场 = 幂等跳过;异 owner 在场则注册动词保持
|
|
338
|
+
// 响亮冲突(PLUGIN_EVENT_TYPE_CONFLICT 拒收语义不软化——03 §2.7 指派)
|
|
339
|
+
if (getEventTypeMeta(MEMORY_DIFF_EVENT_META.type)?.owner !== MEMORY_DIFF_EVENT_META.owner) {
|
|
340
|
+
context.events.registerSessionEventType(MEMORY_DIFF_EVENT_META);
|
|
341
|
+
}
|
|
342
|
+
// —— memory/diff 发射位 + 两注入腿(批 19 销账笔——06 §6 三件收口)——
|
|
343
|
+
// sessions 服务活引用(03 §4.4 appendEvent 最小面;tryGet 诚实缺席:
|
|
344
|
+
// 服务缺席 = 差分降级只渲染不落账——mirror 不锁步)。基线纪元采 sync 懒立
|
|
345
|
+
// (件内自述语义零变):纪元首请求即事实上的重建时点边界——boot//reload/
|
|
346
|
+
// /new 三态自然覆盖(新进程/新装配/新会话首请求重立基线),显式
|
|
347
|
+
// materialize 挂点不接(PromptSectionRegistry 每请求重跑 builder——挂其
|
|
348
|
+
// 内即每请求重立纪元,差分恒零)
|
|
349
|
+
const sessions = context.tryGet('sessions');
|
|
350
|
+
// 绑会话发射位:DiffAppendEvent seam 无 sessionId 参(词面独立律),
|
|
351
|
+
// handler 调用时点置 appendSession + try/finally 清位(waterfall 串行 +
|
|
352
|
+
// JS 单线程零竞态);会话无活体驱动 → 抛错让 diff.ts commit() 捕获降级
|
|
353
|
+
// (appendEventFor 的 undefined 语义——本拍不落账不锁步,非致命)
|
|
354
|
+
let appendSession;
|
|
355
|
+
const diffTracker = createDiffTracker({
|
|
356
|
+
face: () => faceOf(briefBaseline(dao, now(), ownerKeys)),
|
|
357
|
+
...(sessions !== undefined
|
|
358
|
+
? {
|
|
359
|
+
appendEvent: (type, data) => {
|
|
360
|
+
const append = sessions.appendEventFor(appendSession);
|
|
361
|
+
if (append === undefined) {
|
|
362
|
+
throw new Error(`会话 ${appendSession} 无活体驱动——差分落账本拍降级`);
|
|
363
|
+
}
|
|
364
|
+
append(type, data);
|
|
365
|
+
},
|
|
366
|
+
}
|
|
367
|
+
: {}),
|
|
368
|
+
...(deps.fetchEvents !== undefined ? { fetchEvents: deps.fetchEvents } : {}),
|
|
369
|
+
warn,
|
|
370
|
+
});
|
|
371
|
+
// 注入角色两枚(幂等注册——进程级角色注册表多次装配常态)
|
|
372
|
+
ensureDiffRole();
|
|
373
|
+
ensureRecallRole();
|
|
374
|
+
// 注入序(06 §328):diff handler 注册先于 recall——权威修正先于查询提示
|
|
375
|
+
// 进请求尾;todo 恒最后(驱动侧瀑布后追加——05 §1.1)。两腿体内 try/catch
|
|
376
|
+
// 全包 warn 放行(铁律 3——注入失败不影响会话主路径);每 handler 每请求
|
|
377
|
+
// 至多一条(零差分/零命中 = 零注入不打扰请求面)
|
|
378
|
+
const disposeDiffInject = context.on('context_transform', (data, next) => {
|
|
379
|
+
const payload = data;
|
|
380
|
+
try {
|
|
381
|
+
appendSession = payload.sessionId;
|
|
382
|
+
let entries;
|
|
383
|
+
try {
|
|
384
|
+
entries = diffTracker.sync(payload.sessionId);
|
|
385
|
+
}
|
|
386
|
+
finally {
|
|
387
|
+
appendSession = undefined;
|
|
388
|
+
}
|
|
389
|
+
const text = diffTracker.renderInjection(entries);
|
|
390
|
+
if (text !== null) {
|
|
391
|
+
const message = diffInjectionMessage(text, Date.now());
|
|
392
|
+
if (message !== null)
|
|
393
|
+
payload.messages.push(message);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
catch (err) {
|
|
397
|
+
warn(`[memory] 差分注入腿尽力而为止步:${err instanceof Error ? err.message : String(err)}`);
|
|
398
|
+
}
|
|
399
|
+
return next(payload);
|
|
400
|
+
});
|
|
401
|
+
const disposeRecallInject = context.on('context_transform', (data, next) => {
|
|
402
|
+
const payload = data;
|
|
403
|
+
try {
|
|
404
|
+
const query = lastUserQueryText(deps.fetchEvents, payload.sessionId);
|
|
405
|
+
if (query !== null) {
|
|
406
|
+
// minScore 不设位 = 水位旋钮缺省关(06 §6 拍板——检索路本身在场)
|
|
407
|
+
const injection = recallForQuery({ dao, now, ownerKeys, sessionId: payload.sessionId }, query);
|
|
408
|
+
if (injection !== null) {
|
|
409
|
+
const message = recallInjectionMessage(injection.text, Date.now());
|
|
410
|
+
if (message !== null)
|
|
411
|
+
payload.messages.push(message);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
catch (err) {
|
|
416
|
+
warn(`[memory] 检索注入腿尽力而为止步:${err instanceof Error ? err.message : String(err)}`);
|
|
417
|
+
}
|
|
418
|
+
return next(payload);
|
|
419
|
+
});
|
|
420
|
+
// 命令两件(结算文本 = 人读面,经 notify 归因 'memory' 投递;BaseError
|
|
421
|
+
// 面已在命令内折文本,非 BaseError 兜底折呈不炸通道)
|
|
422
|
+
const runCommand = async (run) => {
|
|
423
|
+
try {
|
|
424
|
+
deps.notify?.('memory', await run());
|
|
425
|
+
}
|
|
426
|
+
catch (err) {
|
|
427
|
+
deps.notify?.('memory', err instanceof Error ? err.message : String(err));
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
const disposeExport = context.channels.registerCommand('memory-export', (args) => runCommand(() => runMemoryExportCommand(args.argv, {
|
|
431
|
+
dao,
|
|
432
|
+
writableRoots: () => (deps.dataDir !== null ? [deps.dataDir, workspaceRoot()] : [workspaceRoot()]),
|
|
433
|
+
ownerRoots: () => ({ [projectKey]: workspaceRoot() }),
|
|
434
|
+
now,
|
|
435
|
+
})), MEMORY_EXPORT_USAGE);
|
|
436
|
+
const disposeImport = context.channels.registerCommand('memory-import', (args) => runCommand(() => runMemoryImportCommand(args.argv, { dao })), MEMORY_IMPORT_USAGE);
|
|
437
|
+
// 服务面:dao/cycle(既有消费面)+ 管理面材料位(mm 批——装配根 boot 后
|
|
438
|
+
// 经 TuiBackend.setMemoryScreen 后置注入 /memory 副屏:ownerKeys 呈现过滤
|
|
439
|
+
// 面 + runExport = /memory-export 处理器同一装配闭包〔真身同一函数〕)
|
|
440
|
+
context.provide('memory', {
|
|
441
|
+
dao,
|
|
442
|
+
cycle: cycle ?? null,
|
|
443
|
+
ownerKeys,
|
|
444
|
+
runExport: (argv) => runMemoryExportCommand(argv, {
|
|
445
|
+
dao,
|
|
446
|
+
writableRoots: () => (deps.dataDir !== null ? [deps.dataDir, workspaceRoot()] : [workspaceRoot()]),
|
|
447
|
+
ownerRoots: () => ({ [projectKey]: workspaceRoot() }),
|
|
448
|
+
now,
|
|
449
|
+
}),
|
|
450
|
+
});
|
|
451
|
+
return () => {
|
|
452
|
+
disposeRecallInject();
|
|
453
|
+
disposeDiffInject();
|
|
454
|
+
disposeSettle?.();
|
|
455
|
+
disposeHook();
|
|
456
|
+
disposeImport();
|
|
457
|
+
disposeExport();
|
|
458
|
+
disposeBrief();
|
|
459
|
+
for (const dispose of disposeMemoryTools.reverse())
|
|
460
|
+
dispose();
|
|
461
|
+
};
|
|
462
|
+
},
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* core:subagent(批 19c-1)——委派面装载态兑现:通用 `agent` 工具(boot
|
|
467
|
+
* 全局层散装注册——执行时会话语境解析,toolCtx.sessionId → 深度/父面
|
|
468
|
+
* 枚举)+ 声明式子代理腿(agents 层发现 [skills/agents.ts 解析层镜像律]
|
|
469
|
+
* → materializeDeclarativeSubagents 物化 named provider + `agent_<name>`
|
|
470
|
+
* 静态工具——前缀保留字闸豁免 core:subagent 域,plugin-context 注记条款)。
|
|
471
|
+
*
|
|
472
|
+
* in-process 真工厂本体在 assembly 根(subagent-factory.ts——真工厂需
|
|
473
|
+
* ConversationStack 真身,件内不可达);本 apply 只消费 service 面 +
|
|
474
|
+
* sessionContext 解析闭包(deps 两新位)。缺席 = 件整体零装载。
|
|
475
|
+
*
|
|
476
|
+
* 两阶段物化(RP5——③ §6.3 兑现注):标准层在 apply 内物化(boot 窗内、
|
|
477
|
+
* durable 世代行工具账全);插件层经 resync 钩子在装载收口后物化(活体
|
|
478
|
+
* 工具账在、durable 世代行缺席 = core:mcp 异步工具同一诚实边界)。disposer
|
|
479
|
+
* 两撤(provider 位 + 工具位)——/reload 重放 boot 时撞名修复的撤位律。
|
|
480
|
+
*/
|
|
481
|
+
function makeSubagentPlugin(deps) {
|
|
482
|
+
return {
|
|
483
|
+
name: 'subagent',
|
|
484
|
+
async apply(ctx, _config, host) {
|
|
485
|
+
const context = ctx;
|
|
486
|
+
const service = deps.subagents;
|
|
487
|
+
if (service === undefined)
|
|
488
|
+
return; // 缺席零装载(诚实缺席律——assembly 未接线形)
|
|
489
|
+
const warn = (message) => console.error(message);
|
|
490
|
+
// 工具 deps:boot 全局层形只携 sessionContext(执行时解析——静态位
|
|
491
|
+
// 全缺席;两源俱缺席时 resolveToolContext 诚实拒)
|
|
492
|
+
const toolDeps = {
|
|
493
|
+
service,
|
|
494
|
+
...(deps.subagentSessionContext !== undefined ? { sessionContext: deps.subagentSessionContext } : {}),
|
|
495
|
+
};
|
|
496
|
+
const disposeAgent = context.tools.register(createAgentTool(toolDeps));
|
|
497
|
+
// 声明式腿:标准层发现(project/user/跨库——dataDir null 跳 user 层,
|
|
498
|
+
// 同 skills 律)→ 坏文件诊断 warn(不炸装配——skills 纪律镜像)→
|
|
499
|
+
// def 物化(named provider 注册 + 静态工具族)。owner 显式
|
|
500
|
+
// 'core:subagent'(物化执行方归因——plugin-boot 物化回调同律;层来源
|
|
501
|
+
// 分域在发现层 id 表达)
|
|
502
|
+
const layers = createStandardAgentLayers({
|
|
503
|
+
...(deps.cwd !== undefined ? { cwd: deps.cwd } : {}),
|
|
504
|
+
...(deps.dataDir !== null ? { dataDir: deps.dataDir } : {}),
|
|
505
|
+
...(deps.homeDir !== undefined ? { homeDir: deps.homeDir } : {}),
|
|
506
|
+
});
|
|
507
|
+
const collection = await collectAgentDefs(layers);
|
|
508
|
+
for (const diagnostic of collection.diagnostics) {
|
|
509
|
+
warn(`[subagent] ${diagnostic.type}:${diagnostic.message}(${diagnostic.path})`);
|
|
510
|
+
}
|
|
511
|
+
const materialized = materializeDeclarativeSubagents(collection.defs, service, toolDeps, {
|
|
512
|
+
owner: 'core:subagent',
|
|
513
|
+
});
|
|
514
|
+
const disposeDeclarative = materialized.tools.map((tool) => context.tools.register(tool));
|
|
515
|
+
// ── 插件层物化钩子(RP5):assembly 在装载收口后调(boot 尾/reapply);
|
|
516
|
+
// 重入先全摘旧代(reload 换代对称——provider 位 + 工具位两撤,首跑
|
|
517
|
+
// 零层幂等)。层 id `plugin:<id>` 分域(与标准层结构性不撞——skills
|
|
518
|
+
// resync 同律);插件层间 first-wins = 装载序(collectAgentDefs 单源);
|
|
519
|
+
// 跨层撞标准层名走注册面拒 → warn 降级逐 def 隔离(不炸 resync)。
|
|
520
|
+
let pluginPhaseDisposers = [];
|
|
521
|
+
const resyncPluginAgentLayers = async (rows) => {
|
|
522
|
+
for (const dispose of pluginPhaseDisposers.reverse())
|
|
523
|
+
dispose();
|
|
524
|
+
pluginPhaseDisposers = [];
|
|
525
|
+
if (rows.length === 0)
|
|
526
|
+
return;
|
|
527
|
+
const providers = rows.map((row) => createAgentLayerProvider({ id: `plugin:${row.id}`, roots: [...row.agentDirs] }));
|
|
528
|
+
const pluginCollection = await collectAgentDefs(providers);
|
|
529
|
+
for (const diagnostic of pluginCollection.diagnostics) {
|
|
530
|
+
warn(`[subagent] ${diagnostic.type}:${diagnostic.message}(${diagnostic.path})`);
|
|
531
|
+
}
|
|
532
|
+
for (const def of pluginCollection.defs) {
|
|
533
|
+
try {
|
|
534
|
+
const phase = materializeDeclarativeSubagents([def], service, toolDeps, { owner: 'core:subagent' });
|
|
535
|
+
const disposeTools = [];
|
|
536
|
+
try {
|
|
537
|
+
for (const tool of phase.tools) {
|
|
538
|
+
// 注册经宿主回调窗(core:mcp 后窗通道同律——resync 时点在装载
|
|
539
|
+
// 窗收口后,直调必撞 PLUGIN_WINDOW_CLOSED;窗语义全保留:owner
|
|
540
|
+
// 覆写/工具名账/撞名闸照走。host 缺席〔测试替身〕维持直调)
|
|
541
|
+
const restore = host?.openHostCallback?.();
|
|
542
|
+
try {
|
|
543
|
+
disposeTools.push(context.tools.register(tool));
|
|
544
|
+
}
|
|
545
|
+
finally {
|
|
546
|
+
restore?.();
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
catch (err) {
|
|
551
|
+
// 整体拒 + 回滚(c2bb147 注销器律):工具位部分注册回卷 + provider 位回卷
|
|
552
|
+
for (const dispose of disposeTools.reverse())
|
|
553
|
+
dispose();
|
|
554
|
+
phase.dispose();
|
|
555
|
+
throw err;
|
|
556
|
+
}
|
|
557
|
+
pluginPhaseDisposers.push(...disposeTools, phase.dispose);
|
|
558
|
+
}
|
|
559
|
+
catch (err) {
|
|
560
|
+
warn(`[subagent] 插件子代理「${def.name}」物化拒:${err instanceof Error ? err.message : String(err)}`);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
deps.subagentLayerResyncSink?.(resyncPluginAgentLayers);
|
|
565
|
+
return () => {
|
|
566
|
+
for (const dispose of pluginPhaseDisposers.reverse())
|
|
567
|
+
dispose(); // 插件层两撤
|
|
568
|
+
for (const dispose of disposeDeclarative.reverse())
|
|
569
|
+
dispose(); // 标准层工具位撤
|
|
570
|
+
materialized.dispose(); // 标准层 provider 位撤(/reload 重放撞名修复——RP5 撤位律)
|
|
571
|
+
disposeAgent();
|
|
572
|
+
};
|
|
573
|
+
},
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* core:scheduler(批 19c-2)——04 §12 调度条装载态兑现:jobs 表六动词服务面
|
|
578
|
+
* (/tick 与 CLI 对等单源)+ GoalJobsFace 第五槽 + 进程内挂钟引擎 + /tick
|
|
579
|
+
* 命令注册(输出经 deps.notify 归因 'tick')。
|
|
580
|
+
*
|
|
581
|
+
* 引擎**构造不自启**:启钟/停钟编舞(含重启补推进拍点)归宿主入口——TUI/
|
|
582
|
+
* serve 长驻形经 startSchedulerClock 起钟、诊断形/测试装载不起钟(未起跑的
|
|
583
|
+
* 引擎全惰性:poke/排轮均守 running 位;manual fireNow 直通不依赖钟)。
|
|
584
|
+
*
|
|
585
|
+
* 批 20c 编舞接线三笔兑现(19c-2 挂账销账):① GateFacts 宿主三源收集
|
|
586
|
+
* (deps.schedulerGateFacts——装配根闭包单源)② 真 bin 出厂(deps.
|
|
587
|
+
* schedulerBinCommand——runner spawn 与 cron 行命令段单源;缺席
|
|
588
|
+
* 'berry-agent' PATH 名解析,bin 缺席诚实归 spawn_failed)③ cron 乙案开启位
|
|
589
|
+
* (deps.schedulerCronEnabled——true 时装配 OS cron 注册器 + 装载期既有启用
|
|
590
|
+
* 行对账回填〔per-row try/catch——once 形/不可表达形不炸装载〕)。
|
|
591
|
+
*
|
|
592
|
+
* 主闸 = sqlite seam(同 memory 律):缺席 = 件整体零装载(诚实缺席律)。
|
|
593
|
+
*/
|
|
594
|
+
function makeSchedulerPlugin(deps) {
|
|
595
|
+
return {
|
|
596
|
+
name: 'scheduler',
|
|
597
|
+
async apply(ctx) {
|
|
598
|
+
const context = ctx;
|
|
599
|
+
const db = deps.sqlite?.();
|
|
600
|
+
if (db === undefined)
|
|
601
|
+
return; // 主闸——库座缺席零装载(诚实缺席律)
|
|
602
|
+
const warn = (message) => console.error(message);
|
|
603
|
+
const now = () => new Date().toISOString();
|
|
604
|
+
// 真 bin 单源(批 20c):runner spawn 命令与 cron 行命令段共用——装配根
|
|
605
|
+
// 解析 env BERRY_AGENT_BIN 注入;缺席 'berry-agent' PATH 名解析
|
|
606
|
+
const binCommand = deps.schedulerBinCommand ?? 'berry-agent';
|
|
607
|
+
// cron 乙案开启位(批 20c):env BERRY_AGENT_CRON=1 显式置值即人面授权链
|
|
608
|
+
// 的 env 形(写系统 crontab 的授权凭据)——authorize 恒 true 的凭据在
|
|
609
|
+
// 装配根的 env 判定本身,此处不再二次盘问;缺席 = 纯进程内挂钟。
|
|
610
|
+
// execCrontab 注入位 = 测试接缝(缺省 spawnSync 真身——测试注假件零真
|
|
611
|
+
// 系统写)
|
|
612
|
+
const cron = deps.schedulerCronEnabled === true
|
|
613
|
+
? createOsCronRegistrar({
|
|
614
|
+
command: binCommand,
|
|
615
|
+
authorize: () => true,
|
|
616
|
+
...(deps.schedulerCronExec !== undefined ? { execCrontab: deps.schedulerCronExec } : {}),
|
|
617
|
+
})
|
|
618
|
+
: undefined;
|
|
619
|
+
const { service, dao, goalJobs } = createSchedulerService({
|
|
620
|
+
db,
|
|
621
|
+
now,
|
|
622
|
+
warn,
|
|
623
|
+
...(cron !== undefined ? { cronRegistrar: cron } : {}),
|
|
624
|
+
});
|
|
625
|
+
const engine = createSchedulerEngine({
|
|
626
|
+
dao,
|
|
627
|
+
// 引擎 runner 两形(04 §12 无人值守执行链定形注①):
|
|
628
|
+
// - 宿主 stack 在场(生产恒真——assembly 单源注入)= 甲案进程内推进
|
|
629
|
+
// (scheduler-tick:fire 不 spawn——经 conversation-stack 起 headless
|
|
630
|
+
// run + builtin 行程序化分派零模型;kill = interrupt 协作中止);
|
|
631
|
+
// - stack 缺席 = 测试替身形降级 process runner(spawn 子进程形——
|
|
632
|
+
// 乙案 OS cron 触发腿的执行入口,run --read-only --tick)
|
|
633
|
+
...(deps.conversationStack !== undefined
|
|
634
|
+
? {
|
|
635
|
+
runner: createSchedulerTickRunner({
|
|
636
|
+
stack: deps.conversationStack,
|
|
637
|
+
// 分派处理器 fire 时动态解析(装载序无关——goal/issue 可后装)
|
|
638
|
+
resolveGoal: () => context.tryGet('goal')?.service,
|
|
639
|
+
// u-3 唤醒起跑前池检腿(04 §5 定形注③第二形态——goal 件停靠投影)
|
|
640
|
+
resolveGoalPark: () => context.tryGet('goal')?.parkIfBudgetExhausted,
|
|
641
|
+
resolveIssuePoll: () => context.tryGet('issue'),
|
|
642
|
+
now,
|
|
643
|
+
warn,
|
|
644
|
+
}),
|
|
645
|
+
}
|
|
646
|
+
: {
|
|
647
|
+
runner: createProcessRunnerFactory({
|
|
648
|
+
// 子进程 env 走 exec 白名单基座(deny-by-default 同律——
|
|
649
|
+
// PATH/locale 最小集,零宿主环境继承)
|
|
650
|
+
env: buildChildEnv(),
|
|
651
|
+
command: binCommand,
|
|
652
|
+
}),
|
|
653
|
+
}),
|
|
654
|
+
now,
|
|
655
|
+
warn,
|
|
656
|
+
...(deps.schedulerGateFacts !== undefined ? { gateFacts: deps.schedulerGateFacts } : {}),
|
|
657
|
+
});
|
|
658
|
+
// cron 对账回填(批 20c):装载期既有启用行逐行补注册 OS 面——addJob/
|
|
659
|
+
// addBuiltinJob 的 insertRow 不挂 OS(开启 env 前已 enabled 的行不在
|
|
660
|
+
// crontab),开面即对账;per-row try/catch warn——once 形/不可表达形/
|
|
661
|
+
// win32 不炸装载(进程内挂钟仍辖该行)
|
|
662
|
+
if (cron !== undefined) {
|
|
663
|
+
for (const row of service.listJobs()) {
|
|
664
|
+
if (!row.enabled)
|
|
665
|
+
continue;
|
|
666
|
+
try {
|
|
667
|
+
cron.register(row);
|
|
668
|
+
}
|
|
669
|
+
catch (error) {
|
|
670
|
+
warn(`scheduler cron 对账跳过「${row.name}」:${error instanceof Error ? error.message : String(error)}`);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
// /tick 命令(argv → 人读文本——runTickCommand 错误已折文本不抛;
|
|
675
|
+
// 输出面经 notify 归因 'tick',缺席静默命令仍注册)
|
|
676
|
+
const disposeTick = context.channels.registerCommand('tick', async (args) => {
|
|
677
|
+
const text = await runTickCommand(args.argv, { service, engine });
|
|
678
|
+
deps.notify?.('tick', text);
|
|
679
|
+
}, TICK_USAGE);
|
|
680
|
+
context.provide('scheduler', { service, goalJobs, engine, dao });
|
|
681
|
+
// 迟到序对称腿(04 §12 第五槽双序合法):goal 件先装载(注册表序倒置
|
|
682
|
+
// 或本件单件复活)时此处补接线;先行腿在 goal 件 apply 内 tryGet 本面。
|
|
683
|
+
// 附着者回卷律——本腿 attach 则本腿 detach(goal 件先行腿自理对称)
|
|
684
|
+
let attachedGoal;
|
|
685
|
+
const goalEarly = context.tryGet('goal');
|
|
686
|
+
if (goalEarly !== undefined) {
|
|
687
|
+
await goalEarly.service.attachGoalJobsFace(goalJobs);
|
|
688
|
+
attachedGoal = goalEarly.service;
|
|
689
|
+
}
|
|
690
|
+
return () => {
|
|
691
|
+
attachedGoal?.detachGoalJobsFace();
|
|
692
|
+
disposeTick();
|
|
693
|
+
};
|
|
694
|
+
},
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* 宿主入口钟表编舞面(批 20c——引擎构造不自启的消费位):长驻形入口
|
|
699
|
+
* (TUI/serve/daemon)装载后调本函数起钟,停钟挂运行时 closer(drain 序 =
|
|
700
|
+
* 注册序)。**必须挂 closer**:engine 定时器走真身 setTimeout 非 unref——
|
|
701
|
+
* 不停钟会把进程拖活到 60s belt 定时器(shutdown 返回后进程不退)。
|
|
702
|
+
* 诊断形(dump-config/run/测试装载)不调即不起钟(全惰性)。
|
|
703
|
+
*
|
|
704
|
+
* @param scope 装配产物共享根(tryGet 'scheduler'——件缺席/禁用时 no-op:
|
|
705
|
+
* 起钟属长驻编舞非正确性前提,诚实零动作)
|
|
706
|
+
* @param runtime 运行时(registerCloser 挂停钟腿)
|
|
707
|
+
* @returns 是否起钟(件在场且已 start——测试观察面;件缺席 false)
|
|
708
|
+
*/
|
|
709
|
+
export function startSchedulerClock(scope, runtime) {
|
|
710
|
+
const face = scope.tryGet('scheduler');
|
|
711
|
+
if (face === undefined)
|
|
712
|
+
return false; // 件缺席/禁用——no-op(长驻编舞非正确性前提)
|
|
713
|
+
face.engine.start(); // 重启补推进(missed 静默 advance)+ 排首轮轮询
|
|
714
|
+
runtime.registerCloser({
|
|
715
|
+
label: 'scheduler-engine',
|
|
716
|
+
fn: () => face.engine.stop(), // 只摘轮询定时器(在飞自然收场——engine 头注)
|
|
717
|
+
});
|
|
718
|
+
return true;
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* core:goal(批 19c-3)——03 §10.5 计划态机器装载态兑现:GoalService 全环
|
|
722
|
+
* (goals 表族 v3 已由宿主聚合;件内闭包消费)+ goal_update 终态申报工具
|
|
723
|
+
* (boot 全局层——执行时会话解析包装:toolCtx.sessionId 先落可变格再入
|
|
724
|
+
* 件,多会话共享一 def)+ /goal 命令(输出经 notify 归因 'goal')+ 挂钟
|
|
725
|
+
* 迟到注入先行腿(tryGet scheduler 面——注册表序 scheduler 先装载即挂即
|
|
726
|
+
* 用;倒置序对称腿在 scheduler 件内)+ 'goal' 服务面供给(todoFactory +
|
|
727
|
+
* service 宿主投影〔s 批补注②——写动词不进投影〕)。
|
|
728
|
+
*
|
|
729
|
+
* gates v1 接线形:workspaceRoot 真值 + exec seam 诚实缺席(GateExecSeam
|
|
730
|
+
* 零绑定——03 §10.5 s 批补注①:todo 申报位 hasCommandExec 判据拒 + 评测位
|
|
731
|
+
* fail-closed 双拦,真接线随「exec 判据门真接线」立题批)+ lsp seam 接线真
|
|
732
|
+
* 诊断面(批 19d 回补——queryDiagnostics 窄面,lsp 件缺席即缺席
|
|
733
|
+
* fail-closed);todo 换装 commandGateStatus 活查双位合取(f-1 已接线——
|
|
734
|
+
* 申报位 seam→双位两档全拒文案分档)+ hasCommandExec/hasLsp 双在场判据。
|
|
735
|
+
*
|
|
736
|
+
* 驱动侧接线三件(批 #99 兑现——预算刹停腿由 inert 转执法):本件装载
|
|
737
|
+
* agent_pre_step 复验监听(waterfall 链——budgetExceeded 现判置 stop,驱动
|
|
738
|
+
* 发射位在 driver.ts);轮间沉淀 complete 单发(deps.goalSummarizer 注入
|
|
739
|
+
* GoalService——缺席确定性回退)与 recordTurn 记账腿(驱动 onRunSettled 窗
|
|
740
|
+
* 扫回执 → 组合根闭包 recordTurn——三入口统一经驱动层,本件不再自带挂点)。
|
|
741
|
+
*
|
|
742
|
+
* 主闸双位 = sqlite seam + goalSession face(同 memory 律):任一缺席 = 件
|
|
743
|
+
* 整体零装载(诚实缺席律)。
|
|
744
|
+
*/
|
|
745
|
+
function makeGoalPlugin(deps) {
|
|
746
|
+
return {
|
|
747
|
+
name: 'goal',
|
|
748
|
+
async apply(ctx) {
|
|
749
|
+
const context = ctx;
|
|
750
|
+
const db = deps.sqlite?.();
|
|
751
|
+
const sessionFace = deps.goalSession;
|
|
752
|
+
if (db === undefined || sessionFace === undefined)
|
|
753
|
+
return; // 主闸双位
|
|
754
|
+
const warn = (message) => console.error(message);
|
|
755
|
+
const now = () => new Date().toISOString();
|
|
756
|
+
// lsp 诊断查询窄面(批 19d hasLsp 回补——注册表序 lsp 必居本件前,
|
|
757
|
+
// tryGet 序内前件;lsp 件缺席/disabled = GateLspSeam 缺席 = diagnostics
|
|
758
|
+
// gate 申报即拒 fail-closed〔03 §10.5〕,todoFactory hasLsp 同源)
|
|
759
|
+
const lsp = context.tryGet('lsp');
|
|
760
|
+
// exec seam 诚实缺席(03 §10.5 s 批补注①):GateExecSeam v1 零绑定——
|
|
761
|
+
// 单一声明位供 gates 评测面与 todo 申报位(hasCommandExec)同源;真接线
|
|
762
|
+
// (绑真 exec 三段管道:守门/审批对/落账)随「exec 判据门真接线」立题批
|
|
763
|
+
const gateExec = undefined;
|
|
764
|
+
const service = createGoalService({
|
|
765
|
+
db,
|
|
766
|
+
now,
|
|
767
|
+
warn,
|
|
768
|
+
session: sessionFace,
|
|
769
|
+
// 判据门 v1 接线形:files 源真 stat;exec 诚实缺席 = 该源申报即拒 +
|
|
770
|
+
// 评测恒 fail;lsp seam 接线真诊断面(queryDiagnostics——词面独立律
|
|
771
|
+
// 适配在装配侧收口,goal 席 DAG 无 lsp 边)
|
|
772
|
+
gates: {
|
|
773
|
+
workspaceRoot: canonicalWorkspaceRoot(deps.cwd),
|
|
774
|
+
...(gateExec !== undefined ? { exec: gateExec } : {}),
|
|
775
|
+
...(lsp !== undefined ? { lsp: { queryDiagnostics: (files) => lsp.queryDiagnostics(files) } } : {}),
|
|
776
|
+
},
|
|
777
|
+
// 沉淀摘要窄面(批 #99——缺席 = depositFor 确定性回退,零 LLM 保底)
|
|
778
|
+
...(deps.goalSummarizer !== undefined ? { summarizer: deps.goalSummarizer } : {}),
|
|
779
|
+
});
|
|
780
|
+
// 全环捕获位单发(s 批——生产恒缺席;e2e rig lifecycle 通道,见
|
|
781
|
+
// CorePluginHostDeps.goalServiceSink 注)
|
|
782
|
+
deps.goalServiceSink?.(service);
|
|
783
|
+
// goal_update:boot 全局层 + 执行时会话解析包装(deps.getSessionId 是
|
|
784
|
+
// 工厂期闭包——包装在 execute 前以 toolCtx.sessionId 落格)
|
|
785
|
+
let currentSessionId = '';
|
|
786
|
+
const updateDef = createGoalUpdateTool({ service, getSessionId: () => currentSessionId });
|
|
787
|
+
const goalUpdate = {
|
|
788
|
+
...updateDef,
|
|
789
|
+
execute: (args, toolCtx) => {
|
|
790
|
+
if (toolCtx.sessionId !== undefined)
|
|
791
|
+
currentSessionId = toolCtx.sessionId;
|
|
792
|
+
return updateDef.execute(args, toolCtx);
|
|
793
|
+
},
|
|
794
|
+
};
|
|
795
|
+
const disposeUpdate = context.tools.register(goalUpdate);
|
|
796
|
+
// /goal 命令(argv → 人读文本——守卫错已折文本不抛;eventsFor 与
|
|
797
|
+
// service.session 同源读面;输出面经 notify 归因 'goal')。sessionId
|
|
798
|
+
// 透传(U10 定形注③——goal 锚 = 命令发起会话;缺席仅 create 受影响
|
|
799
|
+
// 〔诚实拒〕,观察动词不辖)
|
|
800
|
+
const disposeGoal = context.channels.registerCommand('goal', async (args) => {
|
|
801
|
+
const text = await runGoalCommand(args.argv, { service, eventsFor: (sid) => sessionFace.events(sid) }, args.sessionId);
|
|
802
|
+
deps.notify?.('goal', text);
|
|
803
|
+
}, GOAL_USAGE);
|
|
804
|
+
// 挂钟迟到注入先行腿(scheduler 先装载 = 即挂即用;disposer 对称回卷)
|
|
805
|
+
const sched = context.tryGet('scheduler');
|
|
806
|
+
if (sched !== undefined)
|
|
807
|
+
await service.attachGoalJobsFace(sched.goalJobs);
|
|
808
|
+
// agent_pre_step 预算复验腿(批 #99——04 §5 双轨第二腿):驱动每模型
|
|
809
|
+
// 请求前发射 waterfall(driver.ts onPreModelRequest),本监听现判
|
|
810
|
+
// budgetExceeded——已超帽即置 stop 刹停本 turn(零 dangling turn;run
|
|
811
|
+
// 收场 stopReason 'stop' → completed)。与起跑位预验同判据双保险
|
|
812
|
+
const offPreStep = context.on('agent_pre_step', (value, next) => {
|
|
813
|
+
const input = value;
|
|
814
|
+
const goalScope = service.goalScopeFor(input.sessionId);
|
|
815
|
+
if (goalScope !== undefined && service.budgetExceeded(goalScope.goalId)) {
|
|
816
|
+
input.stop = { reason: 'goal 前台预算帽已到(budgetExceeded 复验刹停)' };
|
|
817
|
+
}
|
|
818
|
+
return next(input);
|
|
819
|
+
});
|
|
820
|
+
// —— u-3 停靠化编舞(04 §5 定形注③「goal 停靠化律」码面兑现)——
|
|
821
|
+
// 预算语境两形态(记账刹停〔含 budgetExceeded 复验〕、唤醒起跑前池检
|
|
822
|
+
// 拒)改停靠-唤醒:service.parkForBudget(disable 挂钟行 + 会话落
|
|
823
|
+
// session/paused + 幂等登记)+ 广播件登记(恢复时 enable 复活 + submit
|
|
824
|
+
// 唤醒——§12 唤醒判定链同链)。防环不靠边沿靠 driver 三帽:唤醒轮若
|
|
825
|
+
// 复超帽,收口现判再停靠复登记,canAfford 仍真再唤醒,第 4 次
|
|
826
|
+
// backgroundWake 拒收 wake-refused → 摘登记 warn 人工(挂钟行保持
|
|
827
|
+
// disabled)。非预算语境维持既有:停滞硬停(人工 /goal wake)与
|
|
828
|
+
// wake_budget 拒收(warn 不硬停)两形态皆非停靠。
|
|
829
|
+
const broadcast = deps.budgetBroadcast;
|
|
830
|
+
const stack = deps.conversationStack;
|
|
831
|
+
/** 唤醒消息文本(durable user/message 载体——issue 面 WAKE_MESSAGE 同律) */
|
|
832
|
+
const GOAL_WAKE_MESSAGE = '后台预算日池已恢复(budget_extended)——goal 挂钟唤醒,请继续推进当前目标,完成后按 goal_update 纪律收口。';
|
|
833
|
+
/** goal 停靠项登记表(goalId → 广播 entry——复停靠同键换新防泄漏) */
|
|
834
|
+
const wakeEntries = new Map();
|
|
835
|
+
/** 广播唤醒编舞:摘双侧登记 → submit(backgroundWake 吃三帽防环)→ 收口分诊 */
|
|
836
|
+
const wakeGoalFromPark = (goalId, sessionId) => {
|
|
837
|
+
const entry = wakeEntries.get(goalId);
|
|
838
|
+
if (entry !== undefined) {
|
|
839
|
+
broadcast?.unregister(entry);
|
|
840
|
+
wakeEntries.delete(goalId);
|
|
841
|
+
}
|
|
842
|
+
service.unparkForBudget(goalId); // service 侧登记同笔摘(再停靠时复登记)
|
|
843
|
+
if (stack === undefined)
|
|
844
|
+
return; // 测试替身形无提交面——durable 停靠在,人工道 /goal wake
|
|
845
|
+
const run = stack.submitText(sessionId, GOAL_WAKE_MESSAGE, {
|
|
846
|
+
source: 'budget-extended',
|
|
847
|
+
backgroundWake: true,
|
|
848
|
+
});
|
|
849
|
+
if (run === undefined) {
|
|
850
|
+
console.error(`[goal] 广播唤醒提交失败:会话 ${sessionId} 无驱动在册——停靠保持,人工道 /goal wake`);
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
void run.then(async (receipt) => {
|
|
854
|
+
// 再停靠检查先行:onRunSettled 收口现判(同步先于本 receipt)若已
|
|
855
|
+
// 复停靠(又超帽),挂钟行保持 disabled 不复活——复登记已由收口位完成
|
|
856
|
+
if (service.isParkedForBudget(goalId))
|
|
857
|
+
return;
|
|
858
|
+
// wake-refused 收口(三帽兜底——鲸鱼任务诚实边界):自动唤醒路尽,
|
|
859
|
+
// 挂钟行保持 disabled + 摘登记 + warn 人工路径(issue 面同律)
|
|
860
|
+
if (receipt.status === 'wake-refused') {
|
|
861
|
+
service.unparkForBudget(goalId);
|
|
862
|
+
console.error(`[goal] 连续后台唤醒超帽(04 §4 maxConsecutiveWakes=3):goal「${goalId}」停自动唤醒——挂钟保持停摆,/goal wake 手动复位或提帽`);
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
// 正常收口:复活挂钟行(下轮 due 经 §12 唤醒判定链自然重入)
|
|
866
|
+
await service.reviveClock(goalId);
|
|
867
|
+
});
|
|
868
|
+
};
|
|
869
|
+
/** 预算停靠编舞包装:service 三动作 + 广播登记(复停靠同键换新) */
|
|
870
|
+
const parkGoalForBudget = async (goalId) => {
|
|
871
|
+
const landed = await service.parkForBudget(goalId);
|
|
872
|
+
if (!landed)
|
|
873
|
+
return false; // 终态/幂等复入——无新登记面
|
|
874
|
+
if (broadcast !== undefined) {
|
|
875
|
+
const prior = wakeEntries.get(goalId);
|
|
876
|
+
if (prior !== undefined)
|
|
877
|
+
broadcast.unregister(prior); // 旧 entry 防泄漏(复停靠换新)
|
|
878
|
+
const row = service.get(goalId);
|
|
879
|
+
if (row !== undefined && row.status === 'active') {
|
|
880
|
+
const entry = {
|
|
881
|
+
wake: () => wakeGoalFromPark(goalId, row.sessionId),
|
|
882
|
+
};
|
|
883
|
+
wakeEntries.set(goalId, entry);
|
|
884
|
+
broadcast.register(entry);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
return true;
|
|
888
|
+
};
|
|
889
|
+
/** 池检投影(GoalFace.parkIfBudgetExhausted 真身——scheduler tick 池检腿消费):
|
|
890
|
+
* 查池(04 §5 background 档)+ 停靠内聚单动词;stack 缺席恒 false(测试替身形零降级) */
|
|
891
|
+
const parkIfBudgetExhausted = async (goalId) => {
|
|
892
|
+
if (stack === undefined)
|
|
893
|
+
return false;
|
|
894
|
+
if (stack.llm.canAfford('background'))
|
|
895
|
+
return false; // 可负担——正常起跑
|
|
896
|
+
return parkGoalForBudget(goalId); // 日池尽——改停靠-唤醒(gated 零跑由 tick 侧收场)
|
|
897
|
+
};
|
|
898
|
+
// run 收口现判停靠位(04 §5 定形注②「触发形态非穷尽」判据式):记账
|
|
899
|
+
// 刹停(run 完成记账超帽)与复验刹停(agent_pre_step stop → completed)
|
|
900
|
+
// 两形态同收口位一网打尽——goal 域会话 run 终态即现判 budgetExceeded
|
|
901
|
+
const agent = context.tryGet('agent');
|
|
902
|
+
const offSettlePark = agent?.onRunSettled((event) => {
|
|
903
|
+
const scope = service.goalScopeFor(event.sessionId);
|
|
904
|
+
if (scope === undefined)
|
|
905
|
+
return; // 非 goal 域会话不辖
|
|
906
|
+
if (!service.budgetExceeded(scope.goalId))
|
|
907
|
+
return; // 未超帽——正常收口
|
|
908
|
+
void parkGoalForBudget(scope.goalId);
|
|
909
|
+
});
|
|
910
|
+
// provide 投影律(03 §10.5 s 批补注②——danger 先例同律):service 腿按
|
|
911
|
+
// 宿主消费面白名单运行时投影(六法——非仅类型收窄);写动词
|
|
912
|
+
// (approve/activate/complete/abandon/park 族)不进投影——人面 /goal 与
|
|
913
|
+
// 模型工具 goal_update/todo 在本件闭包消费全量 service,插件道 tryGet
|
|
914
|
+
// 只见投影(写动词的插件可连性就此闭合——ΔA⇏ΔC 判据面执法)
|
|
915
|
+
const hostServiceFace = {
|
|
916
|
+
wake: (goalId, opts) => service.wake(goalId, opts),
|
|
917
|
+
goalScopeFor: (sessionId) => service.goalScopeFor(sessionId),
|
|
918
|
+
depositFor: (sessionId) => service.depositFor(sessionId),
|
|
919
|
+
recordTurn: (goalId, opts) => service.recordTurn(goalId, opts),
|
|
920
|
+
attachGoalJobsFace: (face) => service.attachGoalJobsFace(face),
|
|
921
|
+
detachGoalJobsFace: () => service.detachGoalJobsFace(),
|
|
922
|
+
};
|
|
923
|
+
context.provide('goal', {
|
|
924
|
+
service: hostServiceFace,
|
|
925
|
+
parkIfBudgetExhausted,
|
|
926
|
+
todoFactory: (todoDeps) => createGoalTodoTool({
|
|
927
|
+
...todoDeps,
|
|
928
|
+
// f-1 批接线活查——执行期按当前 goal 行求值双位合取(申报位 seam→
|
|
929
|
+
// 双位两档全拒 + 文案分档指路;旧「恒 false 接线形」挂账就此销账)
|
|
930
|
+
commandGateStatus: (goalId) => service.commandGateStatus(goalId),
|
|
931
|
+
// s 批补注①——exec seam 在场判据(诚实缺席律,hasLsp 同律镜像):
|
|
932
|
+
// 与 gates.exec 同源单声明位(gateExec),真接线两处同笔翻真
|
|
933
|
+
hasCommandExec: gateExec !== undefined,
|
|
934
|
+
hasLsp: lsp !== undefined, // 批 19d 回补——真诊断面在场否(申报面 fail-closed 判据)
|
|
935
|
+
}),
|
|
936
|
+
});
|
|
937
|
+
return () => {
|
|
938
|
+
offSettlePark?.();
|
|
939
|
+
offPreStep();
|
|
940
|
+
// 停靠项广播登记逐摘(件卸载——广播件宿主生命周期不随件回卷,登记面须自清)
|
|
941
|
+
if (broadcast !== undefined)
|
|
942
|
+
for (const entry of wakeEntries.values())
|
|
943
|
+
broadcast.unregister(entry);
|
|
944
|
+
wakeEntries.clear();
|
|
945
|
+
if (sched !== undefined)
|
|
946
|
+
service.detachGoalJobsFace();
|
|
947
|
+
disposeGoal();
|
|
948
|
+
disposeUpdate();
|
|
949
|
+
};
|
|
950
|
+
},
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* core:checkpoint——工作区快照/回退件(批 19c-4 装载态入册,05 §5.3):
|
|
955
|
+
* 守门监听(插件钩子正门 ctx.on('tools_pre_execute') waterfall——03 §2.4
|
|
956
|
+
* 不私开管道接缝)+ /rewind 命令(两段事务用户呈现面——argv → 人读文本,
|
|
957
|
+
* /goal 同族;发起会话 = 焦点会话)。
|
|
958
|
+
*
|
|
959
|
+
* 装配序注记(装载态实况 vs 15d 落码时假设):safety 守门行自 19a 起 per-
|
|
960
|
+
* session 于 open-tools 装配位注册(会话 open 晚于 boot),本行装载期注册
|
|
961
|
+
* 必居其前——waterfall 注册序即执行序。序差无害:safety 拦截/让棒后的
|
|
962
|
+
* 已拍快照 = 状态未变仍有效(gate.ts 头注容忍条款对本形适用;被拦 run 的
|
|
963
|
+
* 白拍由 per-workspace 保留帽 10 收敛)。钩子消费点 5s 钟与本件 10 万文件
|
|
964
|
+
* walk 帽是两道各自真实的预算线——谁先触谁执法(超时按管线失败 fail-closed
|
|
965
|
+
* 传播,03 §3.4)。
|
|
966
|
+
*
|
|
967
|
+
* 主闸三位 = dataDir + checkpointSession + checkpointFork(任一缺席 = 件
|
|
968
|
+
* 整体零装载诚实缺席律——纯 :memory: 诊断形/测试替身形快照特性整体缺席,
|
|
969
|
+
* 对话本体仍通)。gate 单实例跨会话共享游标(per-session Map——「同一
|
|
970
|
+
* dispatch 生命周期内复用一个实例」)。
|
|
971
|
+
*
|
|
972
|
+
* adopt 切前台编舞 v1 未落(restore 回执的新会话 id 先经命令输出面呈报
|
|
973
|
+
* ——焦点切换是 channels/host 的事随 TUI adopt 命令立题,本件零越界;
|
|
974
|
+
* 05 §5.3 命令面条款。原注指向已飞的 run 入口批,2026-09-11 勘正)。
|
|
975
|
+
*/
|
|
976
|
+
function makeCheckpointPlugin(deps) {
|
|
977
|
+
return {
|
|
978
|
+
name: 'checkpoint',
|
|
979
|
+
async apply(ctx) {
|
|
980
|
+
const context = ctx;
|
|
981
|
+
const dataDir = deps.dataDir;
|
|
982
|
+
const sessionFace = deps.checkpointSession;
|
|
983
|
+
const forkFace = deps.checkpointFork;
|
|
984
|
+
if (dataDir === null || sessionFace === undefined || forkFace === undefined)
|
|
985
|
+
return; // 主闸三位
|
|
986
|
+
const warn = (message) => console.error(message);
|
|
987
|
+
const store = openCheckpointStore(dataDir);
|
|
988
|
+
const capture = createCapture(store);
|
|
989
|
+
// 装载态可见性面(批 19e——issue 件 capabilities 预检 'checkpoint'
|
|
990
|
+
// 探测位:在场判据纯 provide,无消费面扩展——store 即本件真身服务的
|
|
991
|
+
// 最小可见面)
|
|
992
|
+
context.provide('checkpoint', { store });
|
|
993
|
+
// 守门监听(effect:'write' + 会话边界推进判据——per-run 一 manifest;
|
|
994
|
+
// 类型适配在边界收口:PluginHookHandler unknown 面与 GateInput 收窄一处)
|
|
995
|
+
const gate = createCheckpointGate({ capture, session: sessionFace, warn });
|
|
996
|
+
const offGate = context.on('tools_pre_execute', (value, next) => gate(value, (v) => next(v)));
|
|
997
|
+
// /rewind 命令(守卫错已折文本不抛;发起会话 = 焦点会话〔channels.
|
|
998
|
+
// focusedId〕缺席诚实拒;保底快照归属发起会话〔invokingSessionId——
|
|
999
|
+
// 15d deps 既有位装配侧接线〕;输出面经 notify 归因 'checkpoint')
|
|
1000
|
+
const disposeRewind = context.channels.registerCommand('rewind', async (args) => {
|
|
1001
|
+
const sessionId = deps.focusSessionId?.();
|
|
1002
|
+
if (sessionId === undefined || sessionId === '') {
|
|
1003
|
+
deps.notify?.('checkpoint', `当前无焦点会话——/rewind 需在会话上下文执行。\n${REWIND_USAGE}`);
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
const text = await runRewindCommand(args.argv, {
|
|
1007
|
+
store,
|
|
1008
|
+
session: sessionFace,
|
|
1009
|
+
fork: forkFace,
|
|
1010
|
+
sessionId,
|
|
1011
|
+
invokingSessionId: sessionId,
|
|
1012
|
+
});
|
|
1013
|
+
deps.notify?.('checkpoint', text);
|
|
1014
|
+
}, REWIND_USAGE);
|
|
1015
|
+
return () => {
|
|
1016
|
+
disposeRewind();
|
|
1017
|
+
offGate();
|
|
1018
|
+
};
|
|
1019
|
+
},
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* core:sdk(批 19e——03 §10.6 件身份 = 对外被调用面插件承载位):HTTP
|
|
1024
|
+
* 传输适配 + MCP server 包装的件承载真身供给。协议核与 channels 通道核
|
|
1025
|
+
* 同体(件承载的是传输/包装层);stdio JSONL 归宿主 serve 子命令不依赖
|
|
1026
|
+
* 件装载态(F16——零行为耦合)。
|
|
1027
|
+
*
|
|
1028
|
+
* 主闸 = sdkFaceFactory seam(装配根注入 createSdkHttpFace——缺席 = 件
|
|
1029
|
+
* 零装载:测试替身形/诊断形)。件只 provide 'sdk-http-face' kit(面工厂
|
|
1030
|
+
* 单源供给位);开面/监听/披露编舞归宿主入口(07 §5:daemon 形态必开
|
|
1031
|
+
* HTTP 面,件被禁用时 daemon 拒启退 2 由入口执法——「装载在场 ≠ 开面
|
|
1032
|
+
* 监听」消歧律同 webui)。
|
|
1033
|
+
*/
|
|
1034
|
+
function makeSdkPlugin(deps) {
|
|
1035
|
+
return {
|
|
1036
|
+
name: 'sdk',
|
|
1037
|
+
async apply(ctx) {
|
|
1038
|
+
const context = ctx;
|
|
1039
|
+
const createFace = deps.sdkFaceFactory;
|
|
1040
|
+
if (createFace === undefined)
|
|
1041
|
+
return; // 主闸——面工厂 seam 缺席零装载
|
|
1042
|
+
// U5-2:受理器随 kit 透传(三入口开面消费位——snapshot/attachFace;
|
|
1043
|
+
// fork 绑定真源在 bootPlugins,两腿同真身)。缺席形 = 测试替身(kit
|
|
1044
|
+
// 不含该位——开面方 optional 链消费)
|
|
1045
|
+
context.provide('sdk-http-face', {
|
|
1046
|
+
createFace,
|
|
1047
|
+
...(deps.sdkPluginRoutes !== undefined ? { pluginRoutes: deps.sdkPluginRoutes } : {}),
|
|
1048
|
+
});
|
|
1049
|
+
},
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* core:webui(批 19e——03 §10.4 + 07 §4.2 两件禁用语义族兑现):Web 通
|
|
1054
|
+
* 道路由族的挂载 kit 供给。件零自持 node:http 监听(全库唯一监听族住
|
|
1055
|
+
* core:sdk 面)——「装载在场 ⇒ 面开时路由已注册(惰性零监听);件禁用
|
|
1056
|
+
* ⇒ /api/* 404 而面仍在(/v1/* 在场);面未开 ⇒ 全然无监听」。
|
|
1057
|
+
*
|
|
1058
|
+
* 主闸 = webuiFaceMount seam(装配根闭包 = mountWebuiOnFace 同签名)。
|
|
1059
|
+
* kit 晚绑:面开面晚于装载(入口在 assembleHostStack 之后开面),件
|
|
1060
|
+
* apply 期只 provide kit 不触面——webui claim 桥晚绑同款先例。
|
|
1061
|
+
*/
|
|
1062
|
+
function makeWebuiPlugin(deps) {
|
|
1063
|
+
return {
|
|
1064
|
+
name: 'webui',
|
|
1065
|
+
async apply(ctx) {
|
|
1066
|
+
const context = ctx;
|
|
1067
|
+
const mountOnFace = deps.webuiFaceMount;
|
|
1068
|
+
if (mountOnFace === undefined)
|
|
1069
|
+
return; // 主闸——挂载闭包 seam 缺席零装载
|
|
1070
|
+
context.provide('webui-face-mount', { mountOnFace });
|
|
1071
|
+
},
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* alerts 单条归一(批 19e——03 §10.8 坏规则降级律:告警只通知不执法,
|
|
1076
|
+
* 坏条 warn 跳过不整件失败——与 mcp/browser 的 config 坏形响亮拒行级
|
|
1077
|
+
* 失败分立两律,彼系能力/安全承载面)。
|
|
1078
|
+
*/
|
|
1079
|
+
function normalizeObsAlerts(raw, warn) {
|
|
1080
|
+
if (raw === undefined || raw === null)
|
|
1081
|
+
return [];
|
|
1082
|
+
if (!Array.isArray(raw)) {
|
|
1083
|
+
warn('[obs] config.alerts 须为数组——告警面按空装载(坏形降级律,摄取/查询面不受累)');
|
|
1084
|
+
return [];
|
|
1085
|
+
}
|
|
1086
|
+
const rules = [];
|
|
1087
|
+
raw.forEach((item, index) => {
|
|
1088
|
+
const candidate = item;
|
|
1089
|
+
const kindOk = candidate?.kind === 'token_spend_hourly';
|
|
1090
|
+
const threshold = candidate?.thresholdTokens;
|
|
1091
|
+
const thresholdOk = typeof threshold === 'number' && Number.isFinite(threshold) && threshold > 0;
|
|
1092
|
+
const cooldown = candidate?.cooldownMs;
|
|
1093
|
+
const cooldownOk = cooldown === undefined || (typeof cooldown === 'number' && Number.isFinite(cooldown) && cooldown >= 0);
|
|
1094
|
+
if (kindOk && thresholdOk && cooldownOk) {
|
|
1095
|
+
rules.push({
|
|
1096
|
+
kind: 'token_spend_hourly',
|
|
1097
|
+
thresholdTokens: threshold,
|
|
1098
|
+
...(cooldown !== undefined ? { cooldownMs: cooldown } : {}),
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
else {
|
|
1102
|
+
warn(`[obs] config.alerts[${index}] 坏形跳过(kind/thresholdTokens/cooldownMs 形不符——03 §10.8 坏规则降级律)`);
|
|
1103
|
+
}
|
|
1104
|
+
});
|
|
1105
|
+
return rules;
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* core:obs(批 19e——03 §10.8 观测面装载态):rollup 自管库 + obs_query
|
|
1109
|
+
* 只读工具 + 告警(只通知不执法)。主闸 = dataDir + obsEvents seam 双位
|
|
1110
|
+
* (库座/事件源缺席零装载——诚实缺席律)。
|
|
1111
|
+
*
|
|
1112
|
+
* 自管库路径 `<dataDir>/data/obs/rollup.db`(父目录代建/WAL/0600 归
|
|
1113
|
+
* rollup 开库链——OBS_DB_OPEN_FAILED 构造即抛由装载面行级降级跳件,其
|
|
1114
|
+
* 余 core 件不受累)。装载即首拍 refresh(连接即当下——水位−1h 重叠窗
|
|
1115
|
+
* 幂等,不等挂钟首拍);notify/audience seam 缺席 = 告警腿静默降级非主
|
|
1116
|
+
* 闸(摄取/查询面仍通)。
|
|
1117
|
+
*/
|
|
1118
|
+
function makeObsPlugin(deps) {
|
|
1119
|
+
return {
|
|
1120
|
+
name: 'obs',
|
|
1121
|
+
async apply(ctx, config) {
|
|
1122
|
+
const context = ctx;
|
|
1123
|
+
const dataDir = deps.dataDir;
|
|
1124
|
+
const events = deps.obsEvents;
|
|
1125
|
+
if (dataDir === null || events === undefined)
|
|
1126
|
+
return; // 主闸双位
|
|
1127
|
+
const warn = (message) => console.error(message);
|
|
1128
|
+
const alerts = normalizeObsAlerts(config?.alerts, warn);
|
|
1129
|
+
const service = createObsService({
|
|
1130
|
+
dbPath: join(dataDir, 'data', 'obs', 'rollup.db'),
|
|
1131
|
+
events,
|
|
1132
|
+
notify: deps.obsNotify ?? { notify: () => undefined },
|
|
1133
|
+
audience: deps.obsAudience ?? { hasAudience: () => false },
|
|
1134
|
+
...(alerts.length > 0 ? { alerts } : {}),
|
|
1135
|
+
warn,
|
|
1136
|
+
});
|
|
1137
|
+
service.refresh(); // 首拍即摄取
|
|
1138
|
+
const disposeTool = context.tools.register(createObsQueryTool(service));
|
|
1139
|
+
context.provide('obs', service);
|
|
1140
|
+
return () => {
|
|
1141
|
+
disposeTool();
|
|
1142
|
+
service.dispose();
|
|
1143
|
+
};
|
|
1144
|
+
},
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
/* ---------------- 危险闸装配位三件(04 §13——/danger 呈现与 push 执行腿) ---------------- */
|
|
1148
|
+
/** /danger 用法文案(命令注册面 description——两动词一闸面) */
|
|
1149
|
+
const DANGER_CMD_USAGE = '用法:/danger approve [ttlDays](缺省 30 天)签发危险闸 consent;/danger status 查看闸状态五呈';
|
|
1150
|
+
/**
|
|
1151
|
+
* push 执行腿(04 §13 create/push 执行面——宿主 spawn 真身)。token 经
|
|
1152
|
+
* `GIT_CONFIG_COUNT`/`GIT_CONFIG_KEY_0`/`GIT_CONFIG_VALUE_0` env 注入
|
|
1153
|
+
* `http.https://github.com/.extraheader`(`AUTHORIZATION: basic base64(
|
|
1154
|
+
* x-access-token:token)`)——明文只进子进程环境,argv/日志恒不见值(凭据
|
|
1155
|
+
* 纪律:值永不呈现)。URL 锚钉 https://github.com/——不污染其他远域。
|
|
1156
|
+
*/
|
|
1157
|
+
function dangerPushBranch(req) {
|
|
1158
|
+
const header = `AUTHORIZATION: basic ${Buffer.from(`x-access-token:${req.token}`).toString('base64')}`;
|
|
1159
|
+
return new Promise((resolve, reject) => {
|
|
1160
|
+
execFile('git', ['push', 'origin', req.branch], {
|
|
1161
|
+
cwd: req.worktreePath,
|
|
1162
|
+
env: {
|
|
1163
|
+
...process.env,
|
|
1164
|
+
GIT_CONFIG_COUNT: '1',
|
|
1165
|
+
GIT_CONFIG_KEY_0: 'http.https://github.com/.extraheader',
|
|
1166
|
+
GIT_CONFIG_VALUE_0: header,
|
|
1167
|
+
},
|
|
1168
|
+
}, (err, _stdout, stderr) => {
|
|
1169
|
+
if (err !== null) {
|
|
1170
|
+
const tail = stderr.length > 500 ? `…${stderr.slice(-500)}` : stderr;
|
|
1171
|
+
reject(new Error(`git push 失败(分支 ${req.branch}):${tail}`));
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
resolve();
|
|
1175
|
+
});
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
/** /danger status 五呈中文文案(cap.used null = 链坏不可派生——如实呈现) */
|
|
1179
|
+
function renderDangerStatus(s) {
|
|
1180
|
+
const consentText = s.consent.state === 'valid'
|
|
1181
|
+
? `有效(到期 ${new Date(s.consent.expiresAt ?? 0).toISOString()})`
|
|
1182
|
+
: s.consent.state === 'absent'
|
|
1183
|
+
? '缺席(须 /danger approve 签发)'
|
|
1184
|
+
: s.consent.state === 'expired'
|
|
1185
|
+
? '已过期(重跑 /danger approve 重签)'
|
|
1186
|
+
: '配置漂移(mandate 变过——重跑 /danger approve 重签)';
|
|
1187
|
+
const haltText = s.halt.tripped
|
|
1188
|
+
? `在场(kill switch 拉闸——首触发 ${s.halt.firstFiredAt ?? '未知时间'},删 HALT 文件恢复)`
|
|
1189
|
+
: '不在场';
|
|
1190
|
+
const capText = s.cap.used === null
|
|
1191
|
+
? '不可派生(账本链坏)'
|
|
1192
|
+
: `当日 ${s.cap.used}/${s.cap.max}(UTC ${s.cap.day}——allow-succeeded 计数)`;
|
|
1193
|
+
return [
|
|
1194
|
+
`危险闸状态(consumer ${s.consumer}):`,
|
|
1195
|
+
`- mandate 哈希:${s.mandateHash}`,
|
|
1196
|
+
`- 值域:actions [${s.mandate.actions.join(', ')}] × targets [${s.mandate.targets.join(', ')}] × 日帽 ${s.mandate.maxPerDay}`,
|
|
1197
|
+
`- consent:${consentText}`,
|
|
1198
|
+
`- HALT:${haltText}`,
|
|
1199
|
+
`- 日帽:${capText}`,
|
|
1200
|
+
`- 账本:${s.ledger.total} 笔(链${s.ledger.healthy ? '健康' : '损坏——DANGER_LEDGER_CORRUPT 拒续写'})`,
|
|
1201
|
+
].join('\n');
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* core:issue(批 19e——03 §10.7 无人值守编排件装载态):件是既有件的
|
|
1205
|
+
* 组合消费方——scheduler 挂钟(tryGet 'scheduler')+ Job 注册表(tryGet
|
|
1206
|
+
* 'jobs'——assembly provideJobsService 共享根,JobRegistry 真身结构可赋
|
|
1207
|
+
* IssueJobsFace)+ goal/exec/checkpoint capabilities(apply 期 tryGet 探
|
|
1208
|
+
* 测注入——预检语义在入队不在装载)+ store_state 水位(deps 直传真身)
|
|
1209
|
+
* + worktree 工具族(件内真身构造——canonical 工作区根锚)+ env 凭证双
|
|
1210
|
+
* 词面(token/webhook secret——凭证盒未立前 env 载体先行)。
|
|
1211
|
+
*
|
|
1212
|
+
* 主闸链(任一缺席 = 件零装载——诚实缺席律):config 在场(缺省无编排
|
|
1213
|
+
* 面)→ GitHub token → session seam(成熟度缺口 #5——headless 会话真工厂
|
|
1214
|
+
* createIssueSessionFactory 装配根已接线)→ scheduler/jobs 前件 → state/
|
|
1215
|
+
* budget seam。config 在场但坏形 = 响亮拒 ISSUE_CONFIG_INVALID 行级装载失败
|
|
1216
|
+
* (/reload 时刻可修——mcp/browser 同律)。
|
|
1217
|
+
*/
|
|
1218
|
+
function makeIssuePlugin(deps) {
|
|
1219
|
+
return {
|
|
1220
|
+
name: 'issue',
|
|
1221
|
+
async apply(ctx, config) {
|
|
1222
|
+
const context = ctx;
|
|
1223
|
+
if (config === undefined || config === null)
|
|
1224
|
+
return; // 主闸一——缺省无编排面零装载
|
|
1225
|
+
const token = deps.issueGithubToken;
|
|
1226
|
+
if (token === undefined || token === '')
|
|
1227
|
+
return; // 主闸二——数据源凭证缺席零装载
|
|
1228
|
+
const session = deps.issueSession;
|
|
1229
|
+
if (session === undefined)
|
|
1230
|
+
return; // 主闸三——起会面未接线零装载(装配根常在——缺席即诊断形)
|
|
1231
|
+
const sched = context.tryGet('scheduler');
|
|
1232
|
+
const jobs = context.tryGet(JOBS_SERVICE_NAME);
|
|
1233
|
+
const state = deps.issueState;
|
|
1234
|
+
const budget = deps.issueBudget;
|
|
1235
|
+
if (sched === undefined || jobs === undefined || state === undefined || budget === undefined) {
|
|
1236
|
+
return; // 主闸四——前件/装配 seam 缺席零装载
|
|
1237
|
+
}
|
|
1238
|
+
const normalized = normalizeIssueConfig(config);
|
|
1239
|
+
if (!normalized.ok) {
|
|
1240
|
+
// 显式配置坏形响亮拒(行级装载失败——与主闸缺席的静默零装载分立两档)
|
|
1241
|
+
throw new BaseError('ISSUE_CONFIG_INVALID', `[ISSUE_CONFIG_INVALID] ${normalized.message}`);
|
|
1242
|
+
}
|
|
1243
|
+
const warn = (message) => console.error(message);
|
|
1244
|
+
// scheduler 适配(IssueSchedulerFace ← SchedulerService:builtin 行登记
|
|
1245
|
+
// + enabled 显式——轮询是件的主通道非用户手动任务,pi-tick
|
|
1246
|
+
// default-disabled 缺省不适用本行)
|
|
1247
|
+
const schedulerFace = {
|
|
1248
|
+
registerPollJob: (req) => sched.service.addBuiltinJob({ ...req, builtin: true, enabled: true }),
|
|
1249
|
+
removePollJob: (name) => void sched.service.removeJob(name),
|
|
1250
|
+
};
|
|
1251
|
+
// capabilities 探测(goal/exec/checkpoint 三名——注册表序保前件先装;
|
|
1252
|
+
// 探测缺席不阻装载:入队期预检拒 fail-ask 回执缺口〔03 §10.7 批 16 定形〕)
|
|
1253
|
+
const capabilities = [
|
|
1254
|
+
context.tryGet('goal') !== undefined ? 'goal' : undefined,
|
|
1255
|
+
context.tryGet('exec') !== undefined ? 'exec' : undefined,
|
|
1256
|
+
context.tryGet('checkpoint') !== undefined ? 'checkpoint' : undefined,
|
|
1257
|
+
].filter((name) => name !== undefined);
|
|
1258
|
+
const webhookSecret = deps.issueWebhookSecret ?? '';
|
|
1259
|
+
// 后端单真身(服务取数面与危险闸 create-pr 执行腿共用——同 token 同折叠律)
|
|
1260
|
+
const backend = createGithubBackend({ token });
|
|
1261
|
+
// 危险闸(04 §13——auto 档交付腿的预授权执法):dataDir 在场即组机制件
|
|
1262
|
+
// (memory 诊断形 null 零闸——service auto 档维持「闸缺席转人审」原语
|
|
1263
|
+
// 义,fail-closed)。mandate 原料全部来自 normalize 后的用户配置层
|
|
1264
|
+
// (repos 原样 + maxDeliveriesPerDay)——装配期冻结只读注入,闸侧取
|
|
1265
|
+
// 规范化哈希作 consent 绑定面。
|
|
1266
|
+
const dangerDataDir = deps.dataDir;
|
|
1267
|
+
let danger;
|
|
1268
|
+
let disposeDangerCmd;
|
|
1269
|
+
if (dangerDataDir !== null) {
|
|
1270
|
+
// mandate 经 normalizeDangerMandate 归一装配(DangerMandate「normalize 产物」
|
|
1271
|
+
// 契约兑现——原料虽经 normalizeIssueConfig 预归一,装配位仍走归一器兜底:
|
|
1272
|
+
// 第三方消费件接入时此位即唯一入口;坏形折 ISSUE_CONFIG_INVALID 行级失败)
|
|
1273
|
+
const mandate = normalizeDangerMandate({
|
|
1274
|
+
actions: DANGER_V1_ACTIONS,
|
|
1275
|
+
targets: normalized.config.repos,
|
|
1276
|
+
maxPerDay: normalized.config.maxDeliveriesPerDay,
|
|
1277
|
+
});
|
|
1278
|
+
if (!mandate.ok) {
|
|
1279
|
+
throw new BaseError('ISSUE_CONFIG_INVALID', `[ISSUE_CONFIG_INVALID] ${mandate.message}`);
|
|
1280
|
+
}
|
|
1281
|
+
const gate = createDangerGate({
|
|
1282
|
+
consumerId: 'core:issue',
|
|
1283
|
+
mandate: mandate.mandate,
|
|
1284
|
+
dataDir: dangerDataDir,
|
|
1285
|
+
warn,
|
|
1286
|
+
});
|
|
1287
|
+
// deliver = 闸包裹的执行腿(SSRF 批装配位包裹同款先例——消费件只见
|
|
1288
|
+
// 窄面不见裸腿):push = 宿主 spawn git push(token 经 GIT_CONFIG_*
|
|
1289
|
+
// env 注入,argv/日志恒不见值);create-pr = backend.createPullRequest
|
|
1290
|
+
// (REST POST /repos/:o/:r/pulls——postComment 同形 fetch-only 扩法)。
|
|
1291
|
+
const dangerFace = {
|
|
1292
|
+
async deliver(req) {
|
|
1293
|
+
if (req.kind === 'push') {
|
|
1294
|
+
await gate.runGuarded({ action: 'push', target: req.repo, detail: `branch=${req.branch}` }, () => dangerPushBranch({ token, worktreePath: req.worktreePath, branch: req.branch }));
|
|
1295
|
+
return {};
|
|
1296
|
+
}
|
|
1297
|
+
const pr = await gate.runGuarded({ action: 'create-pr', target: req.repo, detail: `head=${req.branch}→${req.base ?? 'main'}` }, () => backend.createPullRequest({
|
|
1298
|
+
repo: req.repo,
|
|
1299
|
+
title: req.title ?? req.branch,
|
|
1300
|
+
body: req.body ?? '',
|
|
1301
|
+
head: req.branch,
|
|
1302
|
+
base: req.base ?? 'main',
|
|
1303
|
+
}));
|
|
1304
|
+
return { prNumber: pr.number, prUrl: pr.htmlUrl };
|
|
1305
|
+
},
|
|
1306
|
+
approve: (ttlDays) => gate.approve(ttlDays),
|
|
1307
|
+
status: () => gate.status(),
|
|
1308
|
+
};
|
|
1309
|
+
danger = dangerFace;
|
|
1310
|
+
// /danger 人面动词(04 §13:机制宿主有、人面动词件承载——/credentials
|
|
1311
|
+
// 同款先例。approve = consent 唯写面;status = 运维五呈单命令面)
|
|
1312
|
+
disposeDangerCmd = context.channels.registerCommand('danger', async (args) => {
|
|
1313
|
+
const verb = args.argv[0];
|
|
1314
|
+
if (verb === 'approve') {
|
|
1315
|
+
let ttlDays;
|
|
1316
|
+
if (args.argv.length > 1) {
|
|
1317
|
+
const n = Number(args.argv[1]);
|
|
1318
|
+
if (!Number.isInteger(n) || n < 1 || n > 3650) {
|
|
1319
|
+
deps.notify?.('issue', `/danger approve ttlDays 须 1..3650 正整数(得 ${args.argv[1]})`);
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
ttlDays = n;
|
|
1323
|
+
}
|
|
1324
|
+
const result = await dangerFace.approve(ttlDays);
|
|
1325
|
+
deps.notify?.('issue', result.ok
|
|
1326
|
+
? `危险闸 consent 已签发(${new Date(result.expiresAt).toISOString()} 到期——绑当前 mandate 哈希,配置漂移即失效)`
|
|
1327
|
+
: `危险闸 consent 签发失败:${result.message}`);
|
|
1328
|
+
}
|
|
1329
|
+
else if (verb === 'status') {
|
|
1330
|
+
deps.notify?.('issue', renderDangerStatus(await dangerFace.status()));
|
|
1331
|
+
}
|
|
1332
|
+
else {
|
|
1333
|
+
deps.notify?.('issue', `未知动词——${DANGER_CMD_USAGE}`);
|
|
1334
|
+
}
|
|
1335
|
+
}, DANGER_CMD_USAGE);
|
|
1336
|
+
}
|
|
1337
|
+
const service = createIssueService({
|
|
1338
|
+
config: normalized.config,
|
|
1339
|
+
backend,
|
|
1340
|
+
jobs,
|
|
1341
|
+
scheduler: schedulerFace,
|
|
1342
|
+
state,
|
|
1343
|
+
worktree: createWorktreeService({ repoRoot: canonicalWorkspaceRoot(deps.cwd) }),
|
|
1344
|
+
session,
|
|
1345
|
+
budget,
|
|
1346
|
+
capabilities,
|
|
1347
|
+
...(danger !== undefined ? { danger } : {}),
|
|
1348
|
+
...(webhookSecret !== '' ? { webhookSecret } : {}),
|
|
1349
|
+
warn,
|
|
1350
|
+
});
|
|
1351
|
+
service.start();
|
|
1352
|
+
context.provide('issue', service);
|
|
1353
|
+
// webhook 挂点 kit(18a-4' mountIssueWebhook 的宿主消费位——serve/
|
|
1354
|
+
// daemon 开面后 tryGet 本面挂路由;secret 缺席 = kit 仍在而守卫 400
|
|
1355
|
+
// 形:面开而未启用,与「面未开 ⇒ 通道不在场」分立)
|
|
1356
|
+
context.provide('issue-webhook-mount', {
|
|
1357
|
+
mount: (face) => mountIssueWebhook({ secret: webhookSecret, config: normalized.config, enqueue: (issue) => service.enqueue(issue) }, face),
|
|
1358
|
+
});
|
|
1359
|
+
return () => {
|
|
1360
|
+
service.stop();
|
|
1361
|
+
disposeDangerCmd?.();
|
|
1362
|
+
};
|
|
1363
|
+
},
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* 插件件作用域 → 三桥 ScopeFace 适配(批 19d 共用 helper):ctx 不暴露
|
|
1368
|
+
* 件作用域本体(effect 是唯一回卷正门),isDisposed 真源 = 回卷翻旗
|
|
1369
|
+
* disposer 自持闭包。回卷序:本 disposer 最先注册(LIFO 末位执行)——
|
|
1370
|
+
* 各桥 service 经本面登记的 shutdown effect 先收口、翻旗殿后。
|
|
1371
|
+
* 结构兼容 McpScopeFace/LspScopeFace/BrowserScopeFace(三面同构)。
|
|
1372
|
+
*/
|
|
1373
|
+
function scopeFaceOf(context) {
|
|
1374
|
+
let disposed = false;
|
|
1375
|
+
context.effect(() => () => {
|
|
1376
|
+
disposed = true;
|
|
1377
|
+
});
|
|
1378
|
+
return {
|
|
1379
|
+
effect: (register) => context.effect(register),
|
|
1380
|
+
get isDisposed() {
|
|
1381
|
+
return disposed;
|
|
1382
|
+
},
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* /browser 命令 usage(人面文案位——产品名合法域)。
|
|
1387
|
+
*/
|
|
1388
|
+
const BROWSER_CMD_USAGE = '/browser install——下载 Chromium for Testing 引擎到数据目录(发现序③;约 150MB,下载域白名单钉 Chromium for Testing 官方两域,摘要账本 TOFU 锚定)';
|
|
1389
|
+
/**
|
|
1390
|
+
* core:mcp(批 19d)——03 §10.1 装载态兑现:服务编排(装配后异步发现零
|
|
1391
|
+
* 阻塞——config 缺省 servers 空 = 行惰性无害零 spawn)+ 工具面全局合计
|
|
1392
|
+
* 定形态(≤20 原生注册 / >20 目录降级——重铺归 service 内部)+ 回卷绑
|
|
1393
|
+
* 件作用域(LIFO = stdin.end 协议化告别 → 宽限 → 树杀,service 自登记)。
|
|
1394
|
+
*
|
|
1395
|
+
* spawn 主闸 = 'exec-pipeline'(exec 件供给——04 §11「spawn 管道 + 登记
|
|
1396
|
+
* 簿同册」单源;exec 禁用 = 本件零装载诚实缺席)。config 线 = apply 第二
|
|
1397
|
+
* 参(enabled.yaml core:mcp 行 config 整值替换;坏形 normalizeMcpConfig
|
|
1398
|
+
* 响亮拒 MCP_CONFIG_INVALID → 行级装载失败,/reload 时刻可修)。
|
|
1399
|
+
* 'mcp' 服务面供给(liveServers 观测面)。
|
|
1400
|
+
*/
|
|
1401
|
+
function makeMcpPlugin(deps) {
|
|
1402
|
+
return {
|
|
1403
|
+
name: 'mcp',
|
|
1404
|
+
async apply(ctx, config, host) {
|
|
1405
|
+
const context = ctx;
|
|
1406
|
+
const pipeline = context.tryGet('exec-pipeline');
|
|
1407
|
+
if (pipeline === undefined)
|
|
1408
|
+
return; // 主闸——exec 管道缺席零装载(诚实缺席律)
|
|
1409
|
+
const servers = normalizeMcpConfig(config?.servers);
|
|
1410
|
+
const service = createMcpService({
|
|
1411
|
+
spawn: pipeline,
|
|
1412
|
+
// 注册闭包经宿主面开窗(2026-09-13 真模型四轮 C 组——03 §2.1 官方件
|
|
1413
|
+
// 异步续段通道/§10.1 连接语义定形注):resurface 全部到达时点(discover
|
|
1414
|
+
// 续段/运行期 onDown 撤桥重铺)均在装载窗收口后——直调 ctx.tools.register
|
|
1415
|
+
// 100% 撞 PLUGIN_WINDOW_CLOSED(真装配 MCP 工具注册恒败;单测 FakeRegistry
|
|
1416
|
+
// 无窗闸绕过故绿)。经 host.openHostCallback 开本插件回调窗再注册——窗
|
|
1417
|
+
// 语义与钩子/工具执行期同律,注册链全语义保留(owner 覆写 core:mcp/
|
|
1418
|
+
// 工具名账/复合名撞名闸照走)。host 缺席(直调形/测试替身)维持直调。
|
|
1419
|
+
registry: {
|
|
1420
|
+
register: (def) => {
|
|
1421
|
+
const restore = host?.openHostCallback?.();
|
|
1422
|
+
try {
|
|
1423
|
+
return context.tools.register(def);
|
|
1424
|
+
}
|
|
1425
|
+
finally {
|
|
1426
|
+
restore?.();
|
|
1427
|
+
}
|
|
1428
|
+
},
|
|
1429
|
+
},
|
|
1430
|
+
scope: scopeFaceOf(context),
|
|
1431
|
+
notify: (message) => deps.notify?.('mcp', message),
|
|
1432
|
+
...(deps.version !== undefined ? { clientVersion: deps.version } : {}),
|
|
1433
|
+
});
|
|
1434
|
+
service.apply(servers); // 零阻塞——发现后台跑(fire-and-forget 收口归 service 内部)
|
|
1435
|
+
context.provide('mcp', service);
|
|
1436
|
+
},
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* core:browser(批 19d)——03 §10.3 装载态兑现:编排件(惰性首用——apply
|
|
1441
|
+
* 零 spawn 零连接,扫掠链 unref 不阻退出)+ 工具面十件 + /browser install
|
|
1442
|
+
* 命令(下载原语不进模型工具面——人面显式命令;装载零网络,fetch 只在
|
|
1443
|
+
* 命令调用时发生)。
|
|
1444
|
+
*
|
|
1445
|
+
* 主闸三位 = 'exec-pipeline'(引擎 spawn 同册)+ 'web-fetch'(navigate 卫生
|
|
1446
|
+
* 单源——SSRF 红线与在飞门同一实例,web 件缺席 = 红线缺席 = 本件不装
|
|
1447
|
+
* fail-closed)+ dataDir 真值(纯 :memory: 诊断形零装载——引擎目录/截图
|
|
1448
|
+
* 落点/安装账本皆无归属地)。config 坏形 normalizeBrowserConfig 响亮拒
|
|
1449
|
+
* BROWSER_CONFIG_INVALID → 行级装载失败。
|
|
1450
|
+
*/
|
|
1451
|
+
function makeBrowserPlugin(deps) {
|
|
1452
|
+
return {
|
|
1453
|
+
name: 'browser',
|
|
1454
|
+
async apply(ctx, config) {
|
|
1455
|
+
const context = ctx;
|
|
1456
|
+
const pipeline = context.tryGet('exec-pipeline');
|
|
1457
|
+
const web = context.tryGet('web-fetch');
|
|
1458
|
+
const dataDir = deps.dataDir;
|
|
1459
|
+
if (pipeline === undefined || web === undefined || dataDir === null)
|
|
1460
|
+
return; // 主闸三位
|
|
1461
|
+
const browserConfig = normalizeBrowserConfig(config);
|
|
1462
|
+
const service = createBrowserService({
|
|
1463
|
+
spawn: pipeline,
|
|
1464
|
+
ws: defaultWsFace(),
|
|
1465
|
+
fs: fsp, // BrowserFsFace 结构兼容 node:fs/promises 子面(compat 互证)
|
|
1466
|
+
readEnv: (name) => process.env[name],
|
|
1467
|
+
platform: process.platform,
|
|
1468
|
+
homeDir: deps.homeDir ?? homedir(),
|
|
1469
|
+
dataDir,
|
|
1470
|
+
config: browserConfig,
|
|
1471
|
+
web,
|
|
1472
|
+
notify: (message) => deps.notify?.('browser', message),
|
|
1473
|
+
register: { register: (def) => context.tools.register(def) },
|
|
1474
|
+
scope: scopeFaceOf(context),
|
|
1475
|
+
});
|
|
1476
|
+
service.apply(); // 云端占位通知 + 工具面注册 + 扫掠链起——零 spawn
|
|
1477
|
+
// /browser install(下载原语——域白名单/TOFU 账本执法归 install 件;
|
|
1478
|
+
// 结果与错误均折人读文本经 notify 归因 'browser' 投递)
|
|
1479
|
+
context.channels.registerCommand('browser', async (args) => {
|
|
1480
|
+
if (args.argv[0] !== 'install') {
|
|
1481
|
+
deps.notify?.('browser', `未知动词——${BROWSER_CMD_USAGE}`);
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
try {
|
|
1485
|
+
const result = await installBrowserEngine({
|
|
1486
|
+
fs: fsp,
|
|
1487
|
+
download: defaultDownloadFace(),
|
|
1488
|
+
platform: process.platform,
|
|
1489
|
+
arch: process.arch,
|
|
1490
|
+
dataDir,
|
|
1491
|
+
});
|
|
1492
|
+
deps.notify?.('browser', `已安装 Chromium for Testing ${result.version}:${result.executablePath}`);
|
|
1493
|
+
}
|
|
1494
|
+
catch (err) {
|
|
1495
|
+
deps.notify?.('browser', err instanceof Error ? err.message : String(err));
|
|
1496
|
+
}
|
|
1497
|
+
}, BROWSER_CMD_USAGE);
|
|
1498
|
+
context.provide('browser', service);
|
|
1499
|
+
},
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* core:lsp(批 19d)——03 §10.2 装载态兑现:静态四件先注册(注册不依赖
|
|
1504
|
+
* 服务器在线——与 MCP「装配后异步发现」的结构性差异)+ 惰性 per-(server,
|
|
1505
|
+
* rootUri) 实例 + 诊断注入器挂线(service 内部经 events 窄面挂
|
|
1506
|
+
* tools_post_execute waterfall——本侧适配面把 ctx.on 路由给它:词主表
|
|
1507
|
+
* mode=waterfall 自动走 onWaterfall 腿 + 5s 钩子钟;注入器内层竞速钟
|
|
1508
|
+
* 3500ms 硬帽先触即收,两道预算线谁先触谁执法,checkpoint 同论证)。
|
|
1509
|
+
*
|
|
1510
|
+
* 主闸 = 'exec-pipeline'(spawn 同册)。config 线 = apply 第二参
|
|
1511
|
+
* ({servers, diagnostics_timeout_ms} 整值替换;坏形 normalizeLspSettings
|
|
1512
|
+
* 响亮拒 LSP_CONFIG_INVALID → 行级装载失败,/reload 时刻可修——03 §10.2
|
|
1513
|
+
* config 坏形条,2026-09-13 f-2 批立)。
|
|
1514
|
+
* rootUri 锚 = canonical 工作区根(canonicalWorkspaceRoot——rootPath 位)
|
|
1515
|
+
* 。'lsp' 服务面供给(goal 件 gates 消费 queryDiagnostics 窄面)。
|
|
1516
|
+
*/
|
|
1517
|
+
function makeLspPlugin(deps) {
|
|
1518
|
+
return {
|
|
1519
|
+
name: 'lsp',
|
|
1520
|
+
async apply(ctx, config) {
|
|
1521
|
+
const context = ctx;
|
|
1522
|
+
const pipeline = context.tryGet('exec-pipeline');
|
|
1523
|
+
if (pipeline === undefined)
|
|
1524
|
+
return; // 主闸——exec 管道缺席零装载(诚实缺席律)
|
|
1525
|
+
const service = createLspService({
|
|
1526
|
+
spawn: pipeline,
|
|
1527
|
+
registry: { register: (def) => context.tools.register(def) },
|
|
1528
|
+
scope: scopeFaceOf(context),
|
|
1529
|
+
events: {
|
|
1530
|
+
onWaterfall: (name, listener) => context.on(name, (value, next) => listener(value, (v) => next(v))),
|
|
1531
|
+
},
|
|
1532
|
+
fs: fsp, // LspFsFace 结构兼容 node:fs/promises 子面(readFile/realpath)
|
|
1533
|
+
rootPath: canonicalWorkspaceRoot(deps.cwd),
|
|
1534
|
+
notify: (message) => deps.notify?.('lsp', message),
|
|
1535
|
+
});
|
|
1536
|
+
// 装载期归一(f-2 批立——坏形行级装载失败,不再走运行期降级语义)
|
|
1537
|
+
service.apply(normalizeLspSettings(config));
|
|
1538
|
+
context.provide('lsp', service);
|
|
1539
|
+
},
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* core:credentials(c-3——03 §10.9 件席):件身份 = 判据面独立件,执法面
|
|
1544
|
+
* 三分他处——存储链 c-2 迁移聚合(runtime HOST_MIGRATION_TAIL);读写
|
|
1545
|
+
* 执法件 secrets.ts(host 装配序 plugin-boot createContext 逐插件 fork
|
|
1546
|
+
* 绑定——非本 apply 职责:服务面绑定携插件身份,宿主装配位是唯一正口);
|
|
1547
|
+
* 人面命令(c-5——本 apply 注册 /credentials add|list|rm,纯逻辑底座
|
|
1548
|
+
* commands.ts 单源);oauth 流随 c-6 入本 apply。
|
|
1549
|
+
*
|
|
1550
|
+
* 本 apply 承载两位:装载计数(披露面「件在场」)+ 禁用位语义
|
|
1551
|
+
* (enabled.yaml 禁 core:credentials ⇒ 计划行 disabled ⇒ plugin-boot 侧
|
|
1552
|
+
* secrets 面整体缺席——诚实缺席律,判据在装配位不在件内)。
|
|
1553
|
+
*/
|
|
1554
|
+
function makeCredentialsPlugin(deps) {
|
|
1555
|
+
return {
|
|
1556
|
+
name: 'credentials',
|
|
1557
|
+
async apply(ctx) {
|
|
1558
|
+
const context = ctx;
|
|
1559
|
+
const store = deps.credentialsStore;
|
|
1560
|
+
if (store === undefined)
|
|
1561
|
+
return; // 主闸——存储 seam 缺席 = 人面命令零注册(空闲占席维持)
|
|
1562
|
+
const oauth = deps.credentialsOAuth;
|
|
1563
|
+
// oauth 动词执行腿(c-6——03 §10.9 oauth 案):流解析 → invoke(宿主
|
|
1564
|
+
// 回调窗包裹——窗内插件 ctx.secrets.set 写自域)→ 完成回执。token 只在
|
|
1565
|
+
// io 返回值内存过手(宿主不落值、回执永不呈值——模型可见性铁律同源)
|
|
1566
|
+
const runOAuth = async (pluginId, name) => {
|
|
1567
|
+
if (oauth === undefined) {
|
|
1568
|
+
deps.notify?.('credentials', 'oauth 流面未装配(运行时承载——CLI/零装配面不可用;TUI 面须流注册表在场)。');
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
const resolved = resolveOAuthFlow(oauth.registry, pluginId, name);
|
|
1572
|
+
if (resolved.flow === undefined) {
|
|
1573
|
+
deps.notify?.('credentials', resolved.message);
|
|
1574
|
+
return;
|
|
1575
|
+
}
|
|
1576
|
+
const flow = resolved.flow;
|
|
1577
|
+
try {
|
|
1578
|
+
await flow.invoke({
|
|
1579
|
+
runDeviceCode: () => runDeviceCodeFlow(flow.def, {
|
|
1580
|
+
fetchFn: oauth.fetchFn,
|
|
1581
|
+
present: (text) => deps.notify?.('credentials', text), // 用户呈现面(user_code/验证页)
|
|
1582
|
+
now: () => Date.now(),
|
|
1583
|
+
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
1584
|
+
}),
|
|
1585
|
+
});
|
|
1586
|
+
deps.notify?.('credentials', `oauth 授权流完成——凭证由插件 ${pluginId} 写入自域(plugin:${pluginId}/${flow.def.name});/credentials list 查看。`);
|
|
1587
|
+
}
|
|
1588
|
+
catch (err) {
|
|
1589
|
+
// 守卫错折文本不炸通道(命令面是用户面——DENIED/EXPIRED/FLOW_FAILED 码直呈)
|
|
1590
|
+
deps.notify?.('credentials', err instanceof BaseError ? `${err.code}:${err.message}` : err instanceof Error ? err.message : String(err));
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1593
|
+
// 命令结算文本 = 人读面,经 notify 归因 'credentials' 投递(memory 件
|
|
1594
|
+
// runCommand 同形);非 BaseError 兜底折呈不炸通道
|
|
1595
|
+
const runCommand = (run) => {
|
|
1596
|
+
try {
|
|
1597
|
+
deps.notify?.('credentials', run());
|
|
1598
|
+
}
|
|
1599
|
+
catch (err) {
|
|
1600
|
+
deps.notify?.('credentials', err instanceof Error ? err.message : String(err));
|
|
1601
|
+
}
|
|
1602
|
+
};
|
|
1603
|
+
const dispose = context.channels.registerCommand('credentials', async (args) => {
|
|
1604
|
+
const parsed = parseCredentialsArgv(args.argv);
|
|
1605
|
+
if (!parsed.ok) {
|
|
1606
|
+
deps.notify?.('credentials', parsed.message);
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
// oauth 动词先行分流(异步执行腿——dance 轮询分钟级长 await,命令
|
|
1610
|
+
// 分派无超时面合法承载)
|
|
1611
|
+
if (parsed.sub.sub === 'oauth') {
|
|
1612
|
+
await runOAuth(parsed.sub.pluginId, parsed.sub.name);
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
runCommand(() => runCredentialsCommand(parsed.sub, {
|
|
1616
|
+
store,
|
|
1617
|
+
...(deps.credentialsOnChanged !== undefined ? { onCredentialChanged: deps.credentialsOnChanged } : {}),
|
|
1618
|
+
}).text);
|
|
1619
|
+
}, CREDENTIALS_USAGE);
|
|
1620
|
+
// 刷新链(c-6):受局面在场即起(件内自持挂钟 intervalMs 缺省 60s;
|
|
1621
|
+
// 0 = 不自驱——测试手动 tick;dispose 位停钟——装载代内生命周期)
|
|
1622
|
+
let chainStop;
|
|
1623
|
+
if (oauth !== undefined) {
|
|
1624
|
+
const chain = createRefreshChain({
|
|
1625
|
+
store,
|
|
1626
|
+
registry: oauth.registry,
|
|
1627
|
+
fetchFn: oauth.fetchFn,
|
|
1628
|
+
now: () => Date.now(),
|
|
1629
|
+
notify: (message) => deps.notify?.('credentials', message), // 三振告警(用户面)
|
|
1630
|
+
warn: (message) => oauth.warn?.(message), // 单败 warn(日志面——缺省丢弃,三振腿恒在场)
|
|
1631
|
+
...(deps.credentialsOnChanged !== undefined ? { onCredentialChanged: deps.credentialsOnChanged } : {}),
|
|
1632
|
+
});
|
|
1633
|
+
const intervalMs = oauth.intervalMs ?? 60_000;
|
|
1634
|
+
if (intervalMs > 0)
|
|
1635
|
+
chain.start(intervalMs);
|
|
1636
|
+
chainStop = () => chain.stop();
|
|
1637
|
+
}
|
|
1638
|
+
return () => {
|
|
1639
|
+
chainStop?.();
|
|
1640
|
+
dispose();
|
|
1641
|
+
};
|
|
1642
|
+
},
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
/**
|
|
1646
|
+
* core: 官方件注册表工厂(assembly.ts 缺省注入源——`options.corePlugins ??
|
|
1647
|
+
* createCorePlugins(deps)`;测试注入面/诊断命令经 options 覆盖)。
|
|
1648
|
+
* deps 聚落律(07 §7.4 #1):宿主真身需求逐笔入 CorePluginHostDeps
|
|
1649
|
+
* (dataDir 首位——批 19b-1;memory 数据面六位——批 19b-2;subagent
|
|
1650
|
+
* 委派面两位——批 19c-1;调度闸事实位——批 19c-2;goal 会话读面——批
|
|
1651
|
+
* 19c-3;checkpoint 语境/fork 两 seam + 焦点会话位——批 19c-4;宿主
|
|
1652
|
+
* 版本位——批 19d;HTTP 面族十位〔sdk 面工厂/webui 挂载 kit/obs 三
|
|
1653
|
+
* seam/issue 五位〕——批 19e)。
|
|
1654
|
+
*
|
|
1655
|
+
* 注册表序 = tryGet 前件序(core 行对象直调按序 apply,序内后件可见前件
|
|
1656
|
+
* provide 面):exec/web 双首件(三桥 spawn/卫生消费源)→ …… → 三桥
|
|
1657
|
+
* (批 19d——mcp/browser/lsp 依次)→ goal(gates lsp seam 消费 lsp
|
|
1658
|
+
* provide 面——必居其后)→ checkpoint → sdk/webui(面族两件——kit
|
|
1659
|
+
* 供给零件间依赖)→ obs(数据面自足)→ issue 居末(组合消费方:tryGet
|
|
1660
|
+
* scheduler/jobs 前件 + goal/exec/checkpoint capabilities 探测——必居
|
|
1661
|
+
* 四前件之后)。02 §4.1 core 表序是件册清单非装载序——装载序按依赖闭
|
|
1662
|
+
* 包排(批 19d 注记)。批 19e 起 15 件齐册——批 19a 头注「入册齐 15 件
|
|
1663
|
+
* 时本注记销账」兑现;c-3 增席 #16 credentials(件席占位——secrets 面
|
|
1664
|
+
* 绑定在 plugin-boot 装配位,与注册表序无依赖关系,居末)。
|
|
1665
|
+
*/
|
|
1666
|
+
export function createCorePlugins(deps) {
|
|
1667
|
+
return [
|
|
1668
|
+
makeExecPlugin(deps),
|
|
1669
|
+
webPlugin,
|
|
1670
|
+
makeSkillsPlugin(deps),
|
|
1671
|
+
makeMemoryPlugin(deps),
|
|
1672
|
+
makeSubagentPlugin(deps),
|
|
1673
|
+
makeSchedulerPlugin(deps),
|
|
1674
|
+
makeMcpPlugin(deps),
|
|
1675
|
+
makeBrowserPlugin(deps),
|
|
1676
|
+
makeLspPlugin(deps),
|
|
1677
|
+
makeGoalPlugin(deps),
|
|
1678
|
+
makeCheckpointPlugin(deps),
|
|
1679
|
+
makeSdkPlugin(deps),
|
|
1680
|
+
makeWebuiPlugin(deps),
|
|
1681
|
+
makeObsPlugin(deps),
|
|
1682
|
+
makeIssuePlugin(deps),
|
|
1683
|
+
makeCredentialsPlugin(deps),
|
|
1684
|
+
];
|
|
1685
|
+
}
|