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,1146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* host/assembly — 宿主装配序公共段(批 12f-3;07 §5 dump-config `:memory:`
|
|
3
|
+
* 同构纪律的码面承载件——纪律原文:「禁 fork 诊断侧门——不许为『只打印不
|
|
4
|
+
* 落库』写第二条装配路径,必须复用同一运行时装配入口」)。
|
|
5
|
+
*
|
|
6
|
+
* 从 tui-entry 抽出装配序前段(TUI 入口与 dump-config / plugins list 诊断
|
|
7
|
+
* 命令**同一合成代码路径**——本件是唯一装配序真源,诊断命令只换运行时形
|
|
8
|
+
* 〔memory 同构诊断形:真数据目录读侧 + 主库 :memory: + 不占活跃标记〕,
|
|
9
|
+
* 不换代码路径):pluginCounts 披露匣 → 运行时组装(单活跃机 + 开库
|
|
10
|
+
* fail-loud)→ logger(--debug 让位律)→ 共享根作用域/事件总线 →
|
|
11
|
+
* conversation 栈五层 → 插件装载(enabled.yaml 读侧 + core: 注册表 +
|
|
12
|
+
* 装载管线全跑)→ 披露匣回写。
|
|
13
|
+
*
|
|
14
|
+
* 失败三档归一 {ok:false}(不抛——呈报面归调用方):
|
|
15
|
+
* - 运行时组装失败(单活跃机拒入/开库失败)= 干净退出档退 1(运行时未
|
|
16
|
+
* 建成,无资源待收——不写 crash.log);
|
|
17
|
+
* - 启用清单损坏 PLUGIN_ROW_INVALID = 用户可自修配置错退 1(同干净退出
|
|
18
|
+
* 档——message 已含修复指引;运行时先收口再返回);
|
|
19
|
+
* - 意外异常 = 崩溃取证档(crash.log 已在收口前写入——memory 形内建跳过;
|
|
20
|
+
* crashed: true 供调用方区分文案前缀,不再重复取证)。
|
|
21
|
+
*/
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
import { parse as parseYaml } from 'yaml';
|
|
24
|
+
import { BaseError, parseEventSource } from '../contracts/index.js';
|
|
25
|
+
import { EventDispatch, LogLevelState, Scope, canonicalWorkspaceRoot, createLogger } from '../context/index.js';
|
|
26
|
+
import { SUBAGENT_RESERVE_THRESHOLD } from '../llm/index.js';
|
|
27
|
+
import { llmTextOf } from '../memory/index.js';
|
|
28
|
+
import { DEFAULT_SUBAGENT_PROVIDER, createJobRegistry, createSubagentService, provideJobsService, } from '../subagent/index.js';
|
|
29
|
+
import { createDirProvider } from '../skills/index.js';
|
|
30
|
+
import { createSsrfGuardedFetch } from '../web/index.js';
|
|
31
|
+
import { appendToolPolicyEntry, readToolPolicy } from './tool-policy-store.js';
|
|
32
|
+
import { readHostSettings } from './settings-store.js';
|
|
33
|
+
import { APPROVAL_USAGE, parseApprovalArgv, runApprovalCommand } from './approval-cmd.js';
|
|
34
|
+
import { createCorePlugins } from './core-plugins.js';
|
|
35
|
+
import { createSessionsFace } from './sessions-face.js';
|
|
36
|
+
import { createConversationStack } from './conversation-stack.js';
|
|
37
|
+
import { SESSION_LIFECYCLE_EVENT } from '../conversation/index.js';
|
|
38
|
+
import { AGENT_SERVICE_NAME } from '../conversation/index.js';
|
|
39
|
+
import { createHookDispatchGuard } from './hook-dispatch-guard.js';
|
|
40
|
+
import { enabledYamlPath, parseEnabledRows } from './manifest.js';
|
|
41
|
+
import { bootPlugins, defaultFs, readEnabledRows } from './plugin-boot.js';
|
|
42
|
+
import { createPluginReloader, emptyRollbackReceipt, rollbackFromReport } from './plugin-reload.js';
|
|
43
|
+
import { PLUGINS_CMD_USAGE, runPluginsCommand } from './plugins-command.js';
|
|
44
|
+
import { runPluginConfigForm } from './plugins-config.js';
|
|
45
|
+
import { DOORS_USAGE, parseDoorsArgv, runDoorsCommand } from './doors-cmd.js';
|
|
46
|
+
import { createDefaultSpawnRunner, createPluginLifecycleTools } from './plugin-tools.js';
|
|
47
|
+
import { createPluginStoreFs } from './plugin-store.js';
|
|
48
|
+
import { createHostRuntime } from './runtime.js';
|
|
49
|
+
import { createIssueSessionFactory } from './issue-session.js';
|
|
50
|
+
import { createBudgetBroadcast } from './budget-broadcast.js';
|
|
51
|
+
import { createDelegationSessionTracker, createInProcessSubagentProvider } from './subagent-factory.js';
|
|
52
|
+
import { budgetAdvisoryMessage } from './budget-advisory.js';
|
|
53
|
+
import { TRIGGER_JOB_PARALLEL_LIMIT, TriggerRegistry, createTriggerStarterFactory } from './triggers.js';
|
|
54
|
+
// 批 19e HTTP 面族接线:sdk 面工厂(件承载真身)+ issue 并行帽常量 +
|
|
55
|
+
// webui 挂载闭包(assembly→webui-bridge→serve-entry→assembly 系声明式
|
|
56
|
+
// 函数引用环——顶层零副作用,boot 后才调值,ESM live binding 安全)
|
|
57
|
+
import { createSdkHttpFace } from '../sdk/index.js';
|
|
58
|
+
import { createPluginRouteRegistry } from '../sdk/index.js';
|
|
59
|
+
import { ISSUE_GITHUB_TOKEN_NAME, ISSUE_PARALLEL_LIMIT_DEFAULT, ISSUE_WEBHOOK_SECRET_NAME } from '../issue/index.js';
|
|
60
|
+
import { HOST_NAMESPACE, createOAuthFlowRegistry } from '../credentials/index.js';
|
|
61
|
+
// 进程级 durable 审计流面(05 §9 audit_events——U3 批 U3-5 载体真接线)
|
|
62
|
+
import { createAuditFace, createLoadHistoryFace } from '../persist/index.js';
|
|
63
|
+
import { mountWebuiOnFace } from './webui-bridge.js';
|
|
64
|
+
/** 宿主装配序主入口(async——装载管线内含 jiti ESM 求值) */
|
|
65
|
+
export async function assembleHostStack(options) {
|
|
66
|
+
// —— 装载披露计数匣(pluginsProvider 先于运行时组装接线——披露段每请求重算读匣)——
|
|
67
|
+
const pluginCounts = { total: 0, enabled: 0, failed: 0 };
|
|
68
|
+
// —— 共享根作用域与事件总线(提前位——批 19b-2:session/event 活体镜像桥
|
|
69
|
+
// 须在运行时组装期注入 Persistence.onDurableEvent,作用域/总线先于运行时建;
|
|
70
|
+
// 对话栈与插件装载仍同根同源)——
|
|
71
|
+
const scope = Scope.createRoot();
|
|
72
|
+
const dispatch = new EventDispatch();
|
|
73
|
+
// 钩子派发段 guard(03 §3.4 执法形——cache 经济批 ca-3):全局单实例深度
|
|
74
|
+
// 计数;两窄面分路注入——enter/exit 随 bootPlugins 透传插件 ctx(钩子派发
|
|
75
|
+
// 两腿开合)、只读面随 conversation-stack 注入 llm 双入口前置查
|
|
76
|
+
// (LLM_CALL_IN_HOOK)。同一真身保证「谁开窗谁可见」跨插件嵌套正确
|
|
77
|
+
const hookDispatchGuard = createHookDispatchGuard();
|
|
78
|
+
let runtime;
|
|
79
|
+
try {
|
|
80
|
+
// —— 运行时组装(单活跃机 + 开库 fail-loud——干净退出档,非崩溃取证档)——
|
|
81
|
+
try {
|
|
82
|
+
runtime = createHostRuntime({
|
|
83
|
+
...options.runtime,
|
|
84
|
+
pluginsProvider: () => ({ ...pluginCounts }),
|
|
85
|
+
// session/event 活体镜像桥(03 §146——批 19b-2):durable append →
|
|
86
|
+
// dispatch.emit。isRegistered 守卫 = 纯诊断形(noPlugins)词汇未注册
|
|
87
|
+
// 零发射(41 词表在 bootPlugins 预注册——不装载即不注册);观察者
|
|
88
|
+
// 异常隔离双保险(Persistence 发射侧 try/catch + dispatch 监听器互
|
|
89
|
+
// 隔离)。onDurableEvent 属装配根专属位——调用方旋钮透传不含此键
|
|
90
|
+
persistence: {
|
|
91
|
+
...options.runtime.persistence,
|
|
92
|
+
onDurableEvent: (payload) => {
|
|
93
|
+
if (!dispatch.isRegistered('session/event'))
|
|
94
|
+
return;
|
|
95
|
+
void dispatch.emit('session/event', payload);
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
return {
|
|
102
|
+
ok: false,
|
|
103
|
+
exitCode: 1,
|
|
104
|
+
message: `启动失败:${err instanceof Error ? err.message : String(err)}`,
|
|
105
|
+
crashed: false,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
options.onRuntime?.(runtime);
|
|
109
|
+
// —— logger 装配:env 解析 + --debug 提级让位律(env 已设时让位)——
|
|
110
|
+
const env = options.env ?? process.env;
|
|
111
|
+
const logState = LogLevelState.fromEnv(env.BERRY_AGENT_LOG_LEVEL);
|
|
112
|
+
if (options.debug && env.BERRY_AGENT_LOG_LEVEL === undefined)
|
|
113
|
+
logState.setGlobalLevel('debug');
|
|
114
|
+
const logger = createLogger('host', logState);
|
|
115
|
+
// —— 跨会话工具策略表装配期载入(04 §9 粘性第 3 款定形块读侧律——
|
|
116
|
+
// dataDir 在场即真读〔含同构诊断形:报告真实装载会走到的路〕;纯 memory
|
|
117
|
+
// 形 dataDir null 双缺〔无归属地〕。坏形 warn 降级 + 回写拒在 store 内执法;
|
|
118
|
+
// 旧 allowlist.json 升格读入在 store 内执法——2026-09-11 审批分档批)——
|
|
119
|
+
const dataDir = runtime.dataDir;
|
|
120
|
+
const toolPolicyLoad = dataDir !== null ? readToolPolicy(dataDir, { warn: (m) => logger.warn(m) }) : null;
|
|
121
|
+
// —— settings.json 持久缺省层(04 §9 ⑥ ap-3——§8 解析链第四层执法位:
|
|
122
|
+
// 工具参数 > 会话策略 > CLI 旗标(逐次) > 本文件 > 代码常量。持久位
|
|
123
|
+
// 只填 gaps:CLI 显式位在场即胜、本层不覆盖〔下方条件透传〕。dataDir
|
|
124
|
+
// 在场即真读;坏形 warn 降级视同缺席〔配置层坏形取缺省非 fail-stop 面,
|
|
125
|
+
// 与策略表坏形拒写分立——彼为用户资产写前校验、此为读侧降级〕)——
|
|
126
|
+
const settingsLoad = dataDir !== null ? readHostSettings(dataDir, { warn: (m) => logger.warn(m) }) : null;
|
|
127
|
+
const settingsMode = settingsLoad?.settings.sandboxMode;
|
|
128
|
+
const settingsPolicy = settingsLoad?.settings.approvalPolicy;
|
|
129
|
+
// —— 进程级 durable 审计流载体(05 §9 audit_events——U3 批 U3-5 真接线):
|
|
130
|
+
// 单写者 = 本装配根(boot plugin/opens 幂等 diff + 触发器/凭证/人面三
|
|
131
|
+
// 受理 seam + 高危面动词 auditSink——插件面零写入位);:memory: 诊断形
|
|
132
|
+
// 同构接线(载体即内存库——durable 性诚实于载体)
|
|
133
|
+
const audit = createAuditFace(runtime.persistence.store.connection);
|
|
134
|
+
// —— 装载史世代面(05 §9 load_generations——装载史批 h-3 写点接线):
|
|
135
|
+
// boot 完成尾落行、/reload reapply 尾换代(写点收在 bootPlugins 完成尾
|
|
136
|
+
// ——双点单写点同源);:memory: 诊断形同构接线(载体即内存库——durable
|
|
137
|
+
// 性诚实于载体,audit 同律)
|
|
138
|
+
const loadHistory = createLoadHistoryFace(runtime.persistence.store.connection);
|
|
139
|
+
// —— 插件道路由受理器(U5-2——03 §2.2 第十三面/§10.6 时序缝定形):
|
|
140
|
+
// host-owned 单真身(受理与挂载两时点解耦的账);受理恰一笔审计落
|
|
141
|
+
// capability/used(05 §1.1——method+path 全路径归因键,拒路径零审计)。
|
|
142
|
+
// 消费两路:bootPlugins fork 绑定(装载序受理入账)+ 三入口开面
|
|
143
|
+
// snapshot replay / attachFace 晚注册(kit 经 core:sdk 件透传——见
|
|
144
|
+
// CorePluginHostDeps.sdkPluginRoutes);:memory: 诊断形同构接线
|
|
145
|
+
const pluginRoutes = createPluginRouteRegistry({
|
|
146
|
+
onCapabilityUsed: (record) => audit.append('capability/used', { ...record }),
|
|
147
|
+
});
|
|
148
|
+
// —— 共享根作用域与事件总线已前移运行时组装之前(批 19b-2 活体镜像桥位)——
|
|
149
|
+
// 装载柄前置声明(批 19a 消费腿闭包晚绑定:stack 先建、boot 后跑,会话
|
|
150
|
+
// 首开/请求组装时闭包经此引用取已定型产物——boot.tools 全局层定义重放
|
|
151
|
+
// 与 promptSections 物化两条消费腿同法);/reload 换代 = 重新赋值本变量
|
|
152
|
+
// (取值器每请求重取——热重载换入面结构性预埋,03 §5.7)
|
|
153
|
+
let boot;
|
|
154
|
+
// 卸载换代槽(/reload 批——03 §5.7):bootPlugins 每代改写槽内 current,
|
|
155
|
+
// 下方一次性 closer 读槽——shutdown 恒跑最新代回卷,reload 换代不累积
|
|
156
|
+
// 重复 closer(closer 数组无摘除面,间接层替代)
|
|
157
|
+
const pluginUnloadRef = {
|
|
158
|
+
current: null,
|
|
159
|
+
};
|
|
160
|
+
// boot 重跑闭包(try 内定型——全部 seam 真身闭包捕获;/reload reapply 与
|
|
161
|
+
// 首次 boot 同一函数 = 同一装载面,无第二装配序)
|
|
162
|
+
// pluginFile 第二参(eco-3a——03 §7 不变式 4 单源保证):reapply 恒单参
|
|
163
|
+
// 调用即 pluginFile undefined = 试件行换代消失;类型可选 + 调用点唯一性
|
|
164
|
+
let runBoot;
|
|
165
|
+
// 最近真用户消息时刻(批 20c——scheduler GateFacts lastUserMessageAt 宿主
|
|
166
|
+
// 源):boot 后 session/event 监听器更新(user/channel 真人输入才计——
|
|
167
|
+
// schedule/subagent-settled/compaction/plugin 注入不计数);null = 无近期
|
|
168
|
+
// 消息(recent_user_msg 门放行)
|
|
169
|
+
let lastUserMessageAt = null;
|
|
170
|
+
// —— 插件生命周期模型工具族(03 §5.6——task #89 笔三):宿主固定八件
|
|
171
|
+
// 恒挂载,boot 全局层并入(effect:'write' 五件经守门管道审批对自动执法);
|
|
172
|
+
// report 取值器 = 换代闭包(boot 后定型、/reload 后即新代投影);审计
|
|
173
|
+
// sink 与 TUI 命令面同一包装(进程内单写者 audit face——落账失败 warn
|
|
174
|
+
// 不阻塞主流程,行编辑已生效不回滚);spawn = execFile 真身(npm/git 装
|
|
175
|
+
// 机走进程外——07 §5 用户显式动作族不进 exec 沙箱体系,与 CLI 同面);
|
|
176
|
+
// events_query 两窄面 = 同实例 persistence(flushFirst + queryEvents);
|
|
177
|
+
// db = store.sqlite()(卸载预检域面查询——宿主固定件正当消费)。纯
|
|
178
|
+
// memory 形 dataDir null 时 conversation-stack 不消费 bootTools——本族
|
|
179
|
+
// 自然缺席(memory 形工具整面缺席同律)。persistence 先收 const——下方
|
|
180
|
+
// 闭包取值(let runtime 的流窄化不进闭包)
|
|
181
|
+
const persistence = runtime.persistence;
|
|
182
|
+
const pluginLifecycleTools = createPluginLifecycleTools({
|
|
183
|
+
dataDir,
|
|
184
|
+
fs: createPluginStoreFs(),
|
|
185
|
+
auditSink: (type, payload) => {
|
|
186
|
+
try {
|
|
187
|
+
audit.append(type, payload);
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
logger.warn(`生命周期审计落账失败(${type}):${err instanceof Error ? err.message : String(err)}——主流程不受影响`);
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
spawn: createDefaultSpawnRunner(),
|
|
194
|
+
env,
|
|
195
|
+
report: () => boot?.report,
|
|
196
|
+
flush: () => persistence.flush(),
|
|
197
|
+
queryEvents: (filter) => persistence.store.queryEvents(filter),
|
|
198
|
+
db: persistence.store.sqlite(),
|
|
199
|
+
});
|
|
200
|
+
// 单会话收口订阅槽(2026-09-13 复盘发现 ⑯——memory 件简报冻结缓存收口
|
|
201
|
+
// 摘除):stack retire 观察 → 当前代 feed;core 件订阅 → 覆写槽。末位
|
|
202
|
+
// 覆写语义:/reload 换代 boot 重跑、新 memory 件重订阅即顶替旧代 feed
|
|
203
|
+
// (旧代缓存随旧件废弃,无累积无泄漏——槽消费懒取时点恒当前代)
|
|
204
|
+
let sessionRetireFeed;
|
|
205
|
+
const stack = createConversationStack({
|
|
206
|
+
runtime,
|
|
207
|
+
scope,
|
|
208
|
+
dispatch,
|
|
209
|
+
// 钩子派发段只读面(ca-3——llm 双入口 LLM_CALL_IN_HOOK 前置查)
|
|
210
|
+
hookDispatchGuard,
|
|
211
|
+
...(options.providers !== undefined ? { providers: options.providers } : {}),
|
|
212
|
+
...(options.model !== undefined ? { model: options.model } : {}),
|
|
213
|
+
...(options.env !== undefined ? { env: options.env } : {}),
|
|
214
|
+
...(options.sandboxMode !== undefined ? { sandboxMode: options.sandboxMode } : {}),
|
|
215
|
+
// 第四层 gaps 填充(ap-3):CLI 显式位缺席时 settings.json 持久缺省
|
|
216
|
+
// 补位——两旋钮同律;settings 亦缺席 = 组合根代码常量缺省
|
|
217
|
+
...(options.sandboxMode === undefined && settingsMode !== undefined
|
|
218
|
+
? { sandboxMode: () => settingsMode }
|
|
219
|
+
: {}),
|
|
220
|
+
...(options.approvalPolicy !== undefined ? { approvalPolicy: options.approvalPolicy } : {}),
|
|
221
|
+
...(options.approvalPolicy === undefined && settingsPolicy !== undefined
|
|
222
|
+
? { approvalPolicy: settingsPolicy }
|
|
223
|
+
: {}),
|
|
224
|
+
// 装载工具定义重放取值器(会话装配时点 boot 已定型——noPlugins/装载
|
|
225
|
+
// 失败形 boot.tools 为空注册表,取值器返回 [] 零打扰);插件生命周期
|
|
226
|
+
// 模型工具族八件恒并入宿主全局面(03 §5.6——先于插件注册面,插件侧
|
|
227
|
+
// 撞名即装载失败 fail-loud)
|
|
228
|
+
bootTools: () => [...(boot?.tools.definitions() ?? []), ...pluginLifecycleTools],
|
|
229
|
+
// 插件提示词段物化取值器(每请求组装时重取——03 §2.5 注册即生效面;
|
|
230
|
+
// sessionId 透传 materialize → builder〔cache 经济批 ca-2——每会话懒
|
|
231
|
+
// 冻结类段消费〕)
|
|
232
|
+
pluginSections: (sessionId) => boot?.promptSections.materialize(sessionId) ?? '',
|
|
233
|
+
// 审批 always 回写透传(04 §9 定形块写侧律——闭包 dataDir 接 store
|
|
234
|
+
// 文件写;坏形期拒写在 store 内执法,healthy 载入才接线)
|
|
235
|
+
...(toolPolicyLoad !== null
|
|
236
|
+
? {
|
|
237
|
+
toolPolicy: toolPolicyLoad.entries,
|
|
238
|
+
...(dataDir !== null && toolPolicyLoad.healthy
|
|
239
|
+
? { persistToolPolicy: (draft) => void appendToolPolicyEntry(dataDir, draft) }
|
|
240
|
+
: {}),
|
|
241
|
+
}
|
|
242
|
+
: {}),
|
|
243
|
+
// goal 段升格锚(批 19c-3——03 §10.5 组合根闭包):lazy 共享根取面
|
|
244
|
+
// (stack 先建 boot 后跑——goal 件未装载 = undefined,fold 退化
|
|
245
|
+
// run-scoped 现行为;goalScopeFor 调用面 = 驱动每请求 fold)
|
|
246
|
+
goalScopeFor: (sessionId) => scope.tryGet('goal')?.service.goalScopeFor(sessionId),
|
|
247
|
+
// goal 轮间沉淀取值器(批 #99——04 §3.7):depositFor 同步返缓存/回退
|
|
248
|
+
// (指纹缓存单发在 goal 件内——同指纹零 LLM),goal 未装载 = null 零注入
|
|
249
|
+
goalDeposit: (sessionId) => scope.tryGet('goal')?.service.depositFor(sessionId) ?? null,
|
|
250
|
+
// 预算预警取值器(批 H——04 §5 三档软着陆 + 2026-09-13 修复批 run 级
|
|
251
|
+
// 后台性判据):origin 会话级两判('trigger' headless root / 'delegation'
|
|
252
|
+
// 子代理)+ backgroundLane run 级声明位(tick 用户行/goal 挂钟行/run
|
|
253
|
+
// --background 的 conversation 会话后台 run)——前台 run 恒 null 零注入,
|
|
254
|
+
// 文案分族铸造在 host/budget-advisory 纯函数族(投影读面 =
|
|
255
|
+
// stack.llm.backgroundUsage 与 canAfford 同账)
|
|
256
|
+
budgetAdvisory: (sessionId, backgroundLane) => {
|
|
257
|
+
const origin = stack.manager.listActive().find((row) => row.sessionId === sessionId)?.origin;
|
|
258
|
+
return budgetAdvisoryMessage(stack.llm.backgroundUsage(), origin, backgroundLane);
|
|
259
|
+
},
|
|
260
|
+
// goal 前台记账腿(批 #99——04 §5 双轨 + 三入口统一):run settled 链
|
|
261
|
+
// 回执(窗扫 assistant/message 计数 + userInitiated 归因)→ recordTurn;
|
|
262
|
+
// braked 即 warn 呈现;钩内异常驱动 noteRunSettled 自防炸兜底
|
|
263
|
+
onRunSettled: (sessionId, receipt) => {
|
|
264
|
+
const face = scope.tryGet('goal');
|
|
265
|
+
const goalScope = face?.service.goalScopeFor(sessionId);
|
|
266
|
+
if (face === undefined || goalScope === undefined)
|
|
267
|
+
return;
|
|
268
|
+
const turn = face.service.recordTurn(goalScope.goalId, {
|
|
269
|
+
userInitiated: receipt.userInitiated,
|
|
270
|
+
messages: receipt.assistantMessages,
|
|
271
|
+
});
|
|
272
|
+
if (turn.braked) {
|
|
273
|
+
logger.warn(`goal「${goalScope.goalId}」前台预算帽已到(已用 ${turn.used}/${turn.cap ?? '∞'} 轮)——recordTurn 刹停(后续 agent_pre_step 复验拒新请求)`);
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
// 单会话收口观察穿线(发现 ⑯):manager retire 成功路 → 当前代订阅 feed
|
|
277
|
+
onSessionRetired: (sessionId) => sessionRetireFeed?.(sessionId),
|
|
278
|
+
// 跨树观测门检接线(e2-4——03 §4.6 第五枚 sessions.observe-cross 工具
|
|
279
|
+
// 腿;开门制扩展批 2026-09-09 授予面接线):模型道门检输入 = doors 段
|
|
280
|
+
// 单独(活体读——受理时点现读现判,撤位即收回;插件道订阅走 plugin-context
|
|
281
|
+
// 分立判定位不经本 seam);onCapabilityUsed = 开门后逐次审计(05 §1.1
|
|
282
|
+
// 键 = 动词名 + 目标会话 id——工具腿载荷原形透传)
|
|
283
|
+
observeCross: {
|
|
284
|
+
getOpens: () => readDoorsSegmentLive(dataDir),
|
|
285
|
+
onCapabilityUsed: (record) => void audit.append('capability/used', { ...record }),
|
|
286
|
+
},
|
|
287
|
+
// 跨会话操控门检接线(e4-3——03 §4.6 第六枚 sessions.control-cross
|
|
288
|
+
// 双面同门;开门制扩展批 2026-09-09 授予面接线):getOpensFor = caller
|
|
289
|
+
// 感知合成(03 §4.6 双源并集律——createControlOpensFor 单源;受理器门检
|
|
290
|
+
// 位逐次现读现判);onCapabilityUsed = 门开后逐次审计(05 §1.1
|
|
291
|
+
// ControlUsedRecord——动词名 + 目标会话 id + 双道归因键原形透传)
|
|
292
|
+
controlCross: {
|
|
293
|
+
getOpensFor: createControlOpensFor(dataDir),
|
|
294
|
+
onCapabilityUsed: (record) => void audit.append('capability/used', { ...record }),
|
|
295
|
+
},
|
|
296
|
+
warn: (message) => logger.warn(message),
|
|
297
|
+
});
|
|
298
|
+
// —— 'sessions' 服务面(03 §4.4 appendEvent 最小面——批 19 销账笔):活引用
|
|
299
|
+
// driverOf(调用时点解析——/new 热切换安全);无活体驱动 = undefined 降级
|
|
300
|
+
// (消费方 core:memory 差分落账腿捕获降级——mirror 不锁步);二道闸(核心
|
|
301
|
+
// 词拒写 + 未注册词拒写)闭包内执法。boot 前位——memory 件 apply 时
|
|
302
|
+
// tryGet('sessions') 已在场;完整只读四件 + 受理制写两腿归后续批
|
|
303
|
+
scope.provide('sessions', createSessionsFace({ driverOf: (sessionId) => stack.driverOf(sessionId) }));
|
|
304
|
+
// —— Job 注册表 + 触发器注册表(C 批 C-3——第十一动词宿主侧真源):
|
|
305
|
+
// job_settled 总线词先注册(活体事件发射前置——04 §10 内存直推不落库,
|
|
306
|
+
// 幂等跳过已注册词)→ Job 注册表(trigger kind 自登 + 缺省并行帽 4)→
|
|
307
|
+
// 服务面 provide(插件 tryGet('jobs') 消费)→ 触发器注册表(starter 真身
|
|
308
|
+
// 工厂注入——活体开门读取源:/reload 撤位后 fire 复检现判现拒)——
|
|
309
|
+
const jobs = createJobRegistry({
|
|
310
|
+
parallelLimits: { trigger: TRIGGER_JOB_PARALLEL_LIMIT, issue: ISSUE_PARALLEL_LIMIT_DEFAULT },
|
|
311
|
+
emit: (event) => dispatch.emit('job_settled', event),
|
|
312
|
+
warn: (message) => logger.warn(message),
|
|
313
|
+
});
|
|
314
|
+
jobs.registerKind('trigger');
|
|
315
|
+
provideJobsService(scope, jobs);
|
|
316
|
+
const readOpens = (pluginId) => readTriggerOpensLive(dataDir, pluginId);
|
|
317
|
+
const triggers = new TriggerRegistry({
|
|
318
|
+
getOpens: readOpens,
|
|
319
|
+
makeStarter: createTriggerStarterFactory({
|
|
320
|
+
stack,
|
|
321
|
+
jobs,
|
|
322
|
+
getOpens: readOpens,
|
|
323
|
+
workspaceRoot: () => canonicalWorkspaceRoot(),
|
|
324
|
+
warn: (message) => logger.warn(message),
|
|
325
|
+
// capability/used 逐次落账(triggers.start-run 腿——C 批挂账 U3-5 兑现;
|
|
326
|
+
// core: 豁免门检照记——豁免免的是门不是账)
|
|
327
|
+
onCapabilityUsed: (pluginId, triggerName) => audit.append('capability/used', { pluginId, capability: 'triggers.start-run', triggerName }),
|
|
328
|
+
}),
|
|
329
|
+
});
|
|
330
|
+
// —— 子代理委派机器(D 批 D-2——第十二动词宿主侧真源):kind 'subagent'
|
|
331
|
+
// 构造自登(与 trigger 同表分立——词汇注册表纪律);程序化注册面
|
|
332
|
+
// (ctx.agent.registerSubagentProvider 受局面)两闸执法在件内。通知面
|
|
333
|
+
// 桥(批 19c-1 兑现——结算走 submitText source='subagent-settled'
|
|
334
|
+
// backgroundWave 后台唤醒族〔唤醒预算防「父派子→子结算→父再派」自激励
|
|
335
|
+
// 环〕;审批挂起走父驱动 notifySubagentApprovalPending 恰一条幂等面);
|
|
336
|
+
// 结算钩子 onSettled(goal foldDelegation 喂入 seam)挂 19c-3+ goal 笔
|
|
337
|
+
const subagents = createSubagentService({
|
|
338
|
+
registry: jobs,
|
|
339
|
+
// 单父扇出帽旋钮面(RP2——04 §10 扇出帽段:env BERRY_AGENT_MAX_CONCURRENT_
|
|
340
|
+
// SUBAGENTS > 缺省 8;坏形 fail-loud 启动当场红)
|
|
341
|
+
env,
|
|
342
|
+
notify: {
|
|
343
|
+
notifySettled: ({ parentSessionId, content }) => {
|
|
344
|
+
const run = stack.submitText(parentSessionId, content, {
|
|
345
|
+
source: 'subagent-settled',
|
|
346
|
+
backgroundWake: true,
|
|
347
|
+
});
|
|
348
|
+
if (run === undefined) {
|
|
349
|
+
logger.warn(`子代理结算通知无处投递(父会话 ${parentSessionId} 无活体驱动)——注册表条目仍终态`);
|
|
350
|
+
return Promise.resolve();
|
|
351
|
+
}
|
|
352
|
+
return run;
|
|
353
|
+
},
|
|
354
|
+
notifyApprovalPending: ({ parentSessionId, jobName, approvalId, toolName, reason }) => {
|
|
355
|
+
const driver = stack.driverOf(parentSessionId);
|
|
356
|
+
if (driver === undefined) {
|
|
357
|
+
logger.warn(`子代理审批挂起通知无处投递(父会话 ${parentSessionId} 无活体驱动;Job ${jobName})——审批仍挂起待答`);
|
|
358
|
+
return Promise.resolve();
|
|
359
|
+
}
|
|
360
|
+
return driver.notifySubagentApprovalPending({
|
|
361
|
+
jobName,
|
|
362
|
+
approvalId,
|
|
363
|
+
toolName,
|
|
364
|
+
...(reason !== undefined ? { reason } : {}),
|
|
365
|
+
});
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
warn: (message) => logger.warn(message),
|
|
369
|
+
});
|
|
370
|
+
// —— oauth 流注册表(c-6——03 §10.9 oauth 案):host-owned 单真身
|
|
371
|
+
// (createJobRegistry 同形先例——纯内存装载代内生命周期),三消费位共
|
|
372
|
+
// 用同表:plugin-boot fork 绑定(ctx.secrets.registerOAuthFlow 注册面)+
|
|
373
|
+
// core:credentials 人面动词(/credentials oauth 解析腿)+ 刷新链巡检面。
|
|
374
|
+
// SSRF 守卫 fetch(2026-09-09 守卫批——挂账收口):web 卫生单源包裹真身
|
|
375
|
+
// fetch(协议白名单 + 字面/DNS 私网拒 + redirect 钉 manual 不跟随)——
|
|
376
|
+
// credentials 件无 web 边(loop 只认 StreamFn 同律),守卫属宿主裁决权
|
|
377
|
+
// 装配位注入;人面发起腿与刷新链腿共用同守卫实例
|
|
378
|
+
const oauthFlows = createOAuthFlowRegistry();
|
|
379
|
+
const oauthFetch = createSsrfGuardedFetch(fetch);
|
|
380
|
+
// in-process 真工厂注册(批 19c-1 兑现):委派深度登记表(boot 全局层
|
|
381
|
+
// 工具执行时语境真源)+ DEFAULT_SUBAGENT_PROVIDER 位接线(声明式 def
|
|
382
|
+
// bound provider late-binding 同位解析)
|
|
383
|
+
const delegationSessions = createDelegationSessionTracker();
|
|
384
|
+
subagents.registerProvider(DEFAULT_SUBAGENT_PROVIDER, createInProcessSubagentProvider({
|
|
385
|
+
stack,
|
|
386
|
+
tracker: delegationSessions,
|
|
387
|
+
warn: (message) => logger.warn(message),
|
|
388
|
+
// reserve 线判定(批 H——04 §5 非交互子代理 90% 线强停):投影读面与
|
|
389
|
+
// 预警三档同账(backgroundUsage 单源),阈值常量 SUBAGENT_RESERVE_THRESHOLD
|
|
390
|
+
reserveBreached: () => stack.llm.backgroundUsage().ratio >= SUBAGENT_RESERVE_THRESHOLD,
|
|
391
|
+
// skills 键解析位(⑤ 批——06 §11.6 skills 键存在性执法的装配位单
|
|
392
|
+
// 真身):scope 晚绑取用与 resyncPluginSkillLayers/closer 同形(换代
|
|
393
|
+
// 自适——/reload 重挂 core:skills 即换新 registry 实例);--no-plugins
|
|
394
|
+
// 或 core:skills 缺席形 tryGet undefined → skills 键 spawn 拒
|
|
395
|
+
//(fail-closed 同 requires 语义,不静默丢注入)
|
|
396
|
+
resolveSkill: (name) => scope.tryGet('skills')?.get(name),
|
|
397
|
+
}));
|
|
398
|
+
// boot 全局层工具执行时语境解析闭包(批 19c-1——深度登记表 ?? 根 1;
|
|
399
|
+
// 父面枚举 = 活体驱动 toolNames 快照,纯对话形 undefined 不可枚举):
|
|
400
|
+
// 两消费位同源单闭包——core:subagent 件 deps 位与程序化腿物化 toolDeps
|
|
401
|
+
// (遗漏审计批 G——注册即派生消费腿与声明式腿同语境同形)
|
|
402
|
+
const subagentSessionContext = (sessionId) => {
|
|
403
|
+
const depth = delegationSessions.depthOf(sessionId) ?? 1;
|
|
404
|
+
const toolNames = stack.driverOf(sessionId)?.toolNames;
|
|
405
|
+
return { depth, ...(toolNames !== undefined ? { availableTools: toolNames } : {}) };
|
|
406
|
+
};
|
|
407
|
+
// 插件层物化钩子槽(RP5 物化腿——runBoot 内 core:subagent apply 经 sink
|
|
408
|
+
// 覆写本槽〔末位胜出——/reload 换代重挂〕;resyncPluginAgentLayers 于
|
|
409
|
+
// 装载收口后经此取钩子喂 activated 行的 agentDirs 投影)
|
|
410
|
+
let subagentLayerResyncHook;
|
|
411
|
+
// —— memory 件 LLM seam 适配器(批 19b-2——词面独立律:memory 席 DAG 无
|
|
412
|
+
// llm 边,LlmService→MemoryLlmFace 的适配归装配根)。UserMessage.timestamp
|
|
413
|
+
// 必填位适配器补(契约无时钟缺省);priority 缺省 'background'(周期路属
|
|
414
|
+
// 后台道——04 §5 预算闸门执法位);result 结构超集直返(AssistantMessage
|
|
415
|
+
// ⊇ {content},文本面提取 llmTextOf 在件内)——
|
|
416
|
+
const runtimeNow = runtime; // let 联合型收窄入 const(闭包捕获用——直接捕 runtime 联合型不进闭包)
|
|
417
|
+
const memoryLlm = {
|
|
418
|
+
complete: (req) => stack.llm.complete({
|
|
419
|
+
...(req.systemPrompt !== undefined ? { systemPrompt: req.systemPrompt } : {}),
|
|
420
|
+
messages: req.messages.map((m) => ({ role: 'user', content: m.content, timestamp: Date.now() })),
|
|
421
|
+
priority: req.priority ?? 'background',
|
|
422
|
+
}),
|
|
423
|
+
canAfford: (priority) => stack.llm.canAfford(priority),
|
|
424
|
+
};
|
|
425
|
+
// —— goal 件摘要 seam 适配器(批 #99——词面独立律同上:goal 席 DAG 无 llm
|
|
426
|
+
// 边,LlmService→GoalSummarizerFace 适配归装配根):04 §3.7 轮间沉淀
|
|
427
|
+
// complete 单发;priority 恒 'background'(周期道预算闸门执法位——沉淀属
|
|
428
|
+
// 后台道非用户可见请求);结果文本面提取 llmTextOf(memory 件单源复用)
|
|
429
|
+
// + maxChars 截断(超帽截断归实现侧——GoalSummarizerFace 契约)。
|
|
430
|
+
const goalSummarizer = {
|
|
431
|
+
complete: async (req) => {
|
|
432
|
+
const result = await stack.llm.complete({
|
|
433
|
+
messages: [{ role: 'user', content: req.prompt, timestamp: Date.now() }],
|
|
434
|
+
priority: 'background',
|
|
435
|
+
});
|
|
436
|
+
return { text: llmTextOf(result.message.content).slice(0, req.maxChars) };
|
|
437
|
+
},
|
|
438
|
+
};
|
|
439
|
+
// —— issue 凭证迁移(c-5——03 §10.9「env 与库优先级」兑现):插件凭证
|
|
440
|
+
// 库优先(host 域两名 github-token / issue-webhook-secret——/credentials
|
|
441
|
+
// add 录入即生效,词面收编入盒)、env 过渡载体回落(既有装机不破——
|
|
442
|
+
// BERRY_AGENT_GITHUB_TOKEN / BERRY_AGENT_ISSUE_WEBHOOK_SECRET 19e 词面
|
|
443
|
+
// 维持);密钥腐坏 PERSIST_SECRET_UNREADABLE fail-loud 既有律维持(store
|
|
444
|
+
// 读抛即装配失败档——不静默降级 env)
|
|
445
|
+
const issueToken = runtimeNow.persistence.store.getCredential(HOST_NAMESPACE, ISSUE_GITHUB_TOKEN_NAME)?.apiKey ??
|
|
446
|
+
(env.BERRY_AGENT_GITHUB_TOKEN !== '' ? env.BERRY_AGENT_GITHUB_TOKEN : undefined);
|
|
447
|
+
const issueSecret = runtimeNow.persistence.store.getCredential(HOST_NAMESPACE, ISSUE_WEBHOOK_SECRET_NAME)?.apiKey ??
|
|
448
|
+
(env.BERRY_AGENT_ISSUE_WEBHOOK_SECRET !== '' ? env.BERRY_AGENT_ISSUE_WEBHOOK_SECRET : undefined);
|
|
449
|
+
// —— 宿主级 budget-extended 广播件(u-3——04 §5 定形注①:canAfford 恢复
|
|
450
|
+
// watcher 自 issue 会话工厂私有升格宿主件,装配根单真身三停靠面同播
|
|
451
|
+
// [issue 停靠项 / goal 停靠项 / 会话级停靠项];电平判语义不变——有停靠
|
|
452
|
+
// 项且 canAfford 恢复即触发,恢复判据覆盖日池翻转与提额两形)。
|
|
453
|
+
// canAfford 窄面与 issue 工厂同源单点(stack.llm.canAfford('background'))
|
|
454
|
+
const budgetBroadcast = createBudgetBroadcast({
|
|
455
|
+
canAfford: () => stack.llm.canAfford('background'),
|
|
456
|
+
});
|
|
457
|
+
runtime.registerCloser({
|
|
458
|
+
label: 'budget-broadcast',
|
|
459
|
+
fn: () => Promise.resolve(budgetBroadcast.dispose()),
|
|
460
|
+
});
|
|
461
|
+
// —— issue headless 会话真工厂(成熟度缺口 #5——04 §5 停靠/唤醒腿的
|
|
462
|
+
// 生产承载;subagent-factory 同族 in-process 形):canAfford 窄面注入
|
|
463
|
+
// background 档日池判(词面独立律——工厂不自持预算知识);warn 走宿主
|
|
464
|
+
// logger;广播件注入(唤醒 watcher 升格宿主件后工厂只持登记面)。closer
|
|
465
|
+
// 注册序即 drain 序(注册序串行):conversation-manager closer 先拆全部
|
|
466
|
+
// 驱动(在飞 run 协作中止 → runRound 自然收口 failed『run 被外部中止』),
|
|
467
|
+
// 本 closer 后到——停靠项 resolve paused(retain 语义:worktree/授予全
|
|
468
|
+
// 保留归 orphanScan 重入),dismantle 幂等双跑无害
|
|
469
|
+
const issueSessionFactory = createIssueSessionFactory({
|
|
470
|
+
stack,
|
|
471
|
+
canAfford: () => stack.llm.canAfford('background'),
|
|
472
|
+
warn: (message) => logger.warn(message),
|
|
473
|
+
broadcast: budgetBroadcast,
|
|
474
|
+
});
|
|
475
|
+
runtime.registerCloser({ label: 'issue-session-face', fn: () => Promise.resolve(issueSessionFactory.dispose()) });
|
|
476
|
+
// —— session/lifecycle 活体词预注册(e2-4——04 §6 会话活体广播):插件
|
|
477
|
+
// 装载期订阅(ctx.events.subscribeSessionLifecycle)先于首会话起跑——驱动
|
|
478
|
+
// 构造器自举够不着 boot 时点,装配根预注册兜底(job_settled 同律;驱动
|
|
479
|
+
// 自举幂等跳过已注册词,独立装配形双源不撞)
|
|
480
|
+
if (!dispatch.isRegistered(SESSION_LIFECYCLE_EVENT)) {
|
|
481
|
+
dispatch.registerEventNames([SESSION_LIFECYCLE_EVENT]);
|
|
482
|
+
}
|
|
483
|
+
// —— 插件装载:启用清单损坏 fail-loud 属启动失败档(用户可自修配置错——
|
|
484
|
+
// 干净退出不写 crash.log);余装载失败走行级隔离不入本档 ——
|
|
485
|
+
try {
|
|
486
|
+
// 卸载换代槽的一次性 closer(注册序位 = 原 plugin-boot 直注册位:
|
|
487
|
+
// conversation 栈之后 = 插件卸载晚于对话栈拆解;fn 读槽恒跑最新代)
|
|
488
|
+
runtime.registerCloser({
|
|
489
|
+
label: 'plugin-unload',
|
|
490
|
+
fn: async () => {
|
|
491
|
+
await pluginUnloadRef.current?.();
|
|
492
|
+
},
|
|
493
|
+
});
|
|
494
|
+
// boot 重跑闭包定型(seam 真身全闭包捕获——/reload reapply 与首次
|
|
495
|
+
// boot 同一函数同一装配面);noPlugins 经参传入:救援环律(07 §5
|
|
496
|
+
// 「/reload 读盘不受旗标影响」)——reload 恒以 false 形调用(旗标
|
|
497
|
+
// 只管启动期短路,人面显式 reload 即显式装载请求)。rt = narrowed
|
|
498
|
+
// 承接(let runtime 在闭包内失窄化——直线位 const 固化)
|
|
499
|
+
const rt = runtime;
|
|
500
|
+
runBoot = (noPluginsFlag, pluginFile) => bootPlugins({
|
|
501
|
+
runtime: rt,
|
|
502
|
+
scope,
|
|
503
|
+
dispatch,
|
|
504
|
+
// 钩子派发段 guard 开合面(ca-3——全部插件 ctx 钩子派发两腿开合同
|
|
505
|
+
// 一全局深度计数;只读面已随 stack 注入 llm 双入口,ctx.ui 窗判
|
|
506
|
+
// 消费同一真身只读位〔ix-2〕)
|
|
507
|
+
hookDispatchGuard,
|
|
508
|
+
// ctx.ui 消费腿通道核窄面(ix-2——07 §4.3 消费腿条款):ChannelsService
|
|
509
|
+
// 七原语结构适配闭包(notify 首参空位——核层 void 该位恒扇出语义;
|
|
510
|
+
// hasSession 锚时效真源)。fork 级联共享单真身。
|
|
511
|
+
channelsUi: {
|
|
512
|
+
notify: (message, opts) => stack.channels.notify('', message, opts),
|
|
513
|
+
confirm: (sid, message, opts) => stack.channels.confirm(sid, message, opts),
|
|
514
|
+
select: (sid, message, choices, opts) => stack.channels.select(sid, message, choices, opts),
|
|
515
|
+
input: (sid, message, opts) => stack.channels.input(sid, message, opts),
|
|
516
|
+
setStatus: (sid, status) => stack.channels.setStatus(sid, status),
|
|
517
|
+
setWidget: (sid, node) => stack.channels.setWidget(sid, node),
|
|
518
|
+
hasAudience: () => stack.channels.hasAudience(),
|
|
519
|
+
hasSession: (sid) => stack.channels.hasSession(sid),
|
|
520
|
+
},
|
|
521
|
+
// ctx.ui 降档 warn 出口(setStatus/setWidget 无锚 no-op 一行的呈现位)
|
|
522
|
+
uiWarn: (message) => logger.warn(message),
|
|
523
|
+
commands: stack.channels.commands,
|
|
524
|
+
llm: stack.llmRuntime,
|
|
525
|
+
triggers, // ctx.triggers.register 受局面(C 批——缺席时该动词响亮缺位)
|
|
526
|
+
subagents, // ctx.agent.registerSubagentProvider 受局面(D 批 D-2——同上)
|
|
527
|
+
// 程序化子代理物化 toolDeps(消费腿——遗漏审计批 G:注册即派生的
|
|
528
|
+
// 装配链接线;bootPlugins 内以 toolRegistry 铸造物化回调透传动词层)
|
|
529
|
+
subagentToolDeps: { service: subagents, sessionContext: subagentSessionContext },
|
|
530
|
+
// Job 归属围栏收口腿(Job 消费面批桥二——04 §10 定形):卸载 closer 序
|
|
531
|
+
// 对 activated 逐插件 closeOwner(owner = 插件 id 的收口执法位)
|
|
532
|
+
jobs,
|
|
533
|
+
// 界面后端注册面受局面(U3 批 U3-4——ctx.channels.registerUiBackend
|
|
534
|
+
// 委派 ChannelsService 插件域腿;门检 channels.ui-backend 前置在动词内)
|
|
535
|
+
uiBackends: stack.channels,
|
|
536
|
+
// 会话血缘判定面(e2-4——ctx.events.subscribeSessionLifecycle tree 档
|
|
537
|
+
// 过滤受局面):真身 = 会话维视图 isSameTree(05 §9 parent_id 链单源)
|
|
538
|
+
sessionLineage: { isSameTree: (a, b) => stack.sessionView.isSameTree(a, b) },
|
|
539
|
+
// 跨会话操控受理器真身(e4-3——ctx.get("sessions-control") fork 绑定
|
|
540
|
+
// 位):plugin-boot 逐插件 bindControlForPlugin 铸 caller 闭包(插件
|
|
541
|
+
// 道归因 plugin:<id>——传入面无 caller 位,伪造结构性不存在)
|
|
542
|
+
sessionsControl: stack.sessionsControl,
|
|
543
|
+
// 进程级 doors 段活体取值器(开门制扩展批 2026-09-09——observe-cross
|
|
544
|
+
// 专属分立判定位消费:订阅 all 档门检行 opens ∥ doors 并判)
|
|
545
|
+
crossDoors: () => readDoorsSegmentLive(dataDir),
|
|
546
|
+
// 压缩席位容器(U4-3——ctx.get("compaction") fork 绑定位):真身 =
|
|
547
|
+
// conversation-stack 装配的 createCompactionSlots 单真身(服务三 seam
|
|
548
|
+
// 中 getConfig/getProvider 两容器位已在 stack 内接线;此处逐插件
|
|
549
|
+
// bindForPlugin 绑窗真源 + fork.effect 卸载回收兜底)
|
|
550
|
+
compaction: stack.compactionSlots,
|
|
551
|
+
// 插件道路由受理器(U5-2——fork 绑定位:窗/门真源绑本插件 handle +
|
|
552
|
+
// fork.effect 卸载回收兜底;席位判 core:sdk 行在场在 plugin-boot)
|
|
553
|
+
sdkRoutes: pluginRoutes,
|
|
554
|
+
// 插件凭证面装配位(c-3——store = persistence.store 凭证投影真身直传
|
|
555
|
+
// 〔词面独立律 compat 面,对拍测试互证〕;core:credentials 席在场判在
|
|
556
|
+
// plugin-boot;oauthRegistry = c-6 流注册表真身——fork 绑定成
|
|
557
|
+
// registerOAuthFlow 面;两审计 seam 真接线(c-3 挂账 U3-5 兑现——
|
|
558
|
+
// 05 §1.1):越域读命中 → capability/used〔seam 载荷原形——含
|
|
559
|
+
// namespace/name 归因键〕、oauth 流写/轮换 → credentials/changed)
|
|
560
|
+
secrets: {
|
|
561
|
+
store: runtimeNow.persistence.store,
|
|
562
|
+
oauthRegistry: oauthFlows,
|
|
563
|
+
onCapabilityUsed: (payload) => audit.append('capability/used', { ...payload }),
|
|
564
|
+
onCredentialChanged: (payload) => audit.append('credentials/changed', { ...payload }),
|
|
565
|
+
},
|
|
566
|
+
// 进程级审计流面(U3 批 U3-5——auditSink 透传 + boot plugin/opens 幂等 diff)
|
|
567
|
+
audit,
|
|
568
|
+
// 装载史世代面(装载史批 h-3——boot 完成尾落行 + reapply 尾换代同点)
|
|
569
|
+
loadHistory,
|
|
570
|
+
noPlugins: noPluginsFlag,
|
|
571
|
+
// 快速试件(eco-3a——启动期一次性注入;reapply 单参调用时 undefined)
|
|
572
|
+
...(pluginFile !== undefined ? { pluginFile } : {}),
|
|
573
|
+
// 卸载换代槽(03 §5.7——本代卸载序改写槽,上方一次性 closer 读槽)
|
|
574
|
+
unloadRef: pluginUnloadRef,
|
|
575
|
+
version: options.version,
|
|
576
|
+
// core: 官方件注册表缺省单源(批 19a——测试注入面/诊断覆盖经 options;
|
|
577
|
+
// 工厂形升级批 19b-1:dataDir 等宿主真身经 CorePluginHostDeps 入件;
|
|
578
|
+
// 16 件逐纵切笔入册,见 core-plugins.ts)
|
|
579
|
+
corePlugins: options.corePlugins ??
|
|
580
|
+
createCorePlugins({
|
|
581
|
+
dataDir: rt.dataDir,
|
|
582
|
+
// memory 件数据面(批 19b-2——sqlite 主闸恒接线;fts 双 seam 同
|
|
583
|
+
// Store 直传——词面独立律 compat 面,对拍测试互证)
|
|
584
|
+
sqlite: () => runtimeNow.persistence.store.sqlite(),
|
|
585
|
+
// 单会话收口订阅面(发现 ⑯):memory 件简报冻结缓存收口摘除
|
|
586
|
+
// ——末位覆写(/reload 换代新件重订阅即顶替旧代 feed)
|
|
587
|
+
subscribeSessionRetire: (feed) => {
|
|
588
|
+
sessionRetireFeed = feed;
|
|
589
|
+
},
|
|
590
|
+
// 活体日志优先(write-behind 在飞事件不落盘——driver 在场时读
|
|
591
|
+
// 内存面零缺口);驱动已收口的外部会话兜底落盘读
|
|
592
|
+
fetchEvents: (sessionId) => stack.driverOf(sessionId)?.session.events() ??
|
|
593
|
+
runtimeNow.persistence.loadSession(sessionId).log.events(),
|
|
594
|
+
ftsSearch: rt.persistence.store,
|
|
595
|
+
ftsMaintenance: rt.persistence.store,
|
|
596
|
+
llm: () => memoryLlm,
|
|
597
|
+
// 命令输出面(source = 归因字面——调用件自报:memory-export/import
|
|
598
|
+
// 归因 'memory'、/tick 归因 'tick';sessionId 位呈现侧路由后端自决)
|
|
599
|
+
notify: (source, message) => stack.channels.notify(source, message),
|
|
600
|
+
// 子代理委派面两位(批 19c-1):service 真身 + boot 全局层工具
|
|
601
|
+
// 执行时语境解析闭包(上方提取位——程序化腿物化 toolDeps 同源)
|
|
602
|
+
subagents,
|
|
603
|
+
subagentSessionContext,
|
|
604
|
+
// 插件层物化钩子接收位(RP5 物化腿——03 §6.3 兑现):core:subagent
|
|
605
|
+
// apply 换代重挂即覆写本槽(末位胜出——同 subscribeSessionRetire
|
|
606
|
+
// 律);resyncPluginAgentLayers 装载收口后经此取钩子喂 activated 行
|
|
607
|
+
subagentLayerResyncSink: (hook) => {
|
|
608
|
+
subagentLayerResyncHook = hook;
|
|
609
|
+
},
|
|
610
|
+
// goal 会话日志读面(批 19c-3——goal 件主闸二):活体日志优先
|
|
611
|
+
// (driver 在场读内存面),驱动已收口的外部会话兜底落盘读;
|
|
612
|
+
// 长度经 events() 视图取长(O(1)——内部数组直视图非拷贝)
|
|
613
|
+
goalSession: {
|
|
614
|
+
events: (sessionId) => stack.driverOf(sessionId)?.session.events() ??
|
|
615
|
+
runtimeNow.persistence.loadSession(sessionId).log.events(),
|
|
616
|
+
length: (sessionId) => {
|
|
617
|
+
const log = stack.driverOf(sessionId)?.session ?? runtimeNow.persistence.loadSession(sessionId).log;
|
|
618
|
+
return log.events().length;
|
|
619
|
+
},
|
|
620
|
+
// u-3 停靠词落笔真身(04 §5 定形注②③):幂等开驱动(冷会话
|
|
621
|
+
// 落词前置——goal 停靠可在无在飞驱动时发生〔scheduler 池检
|
|
622
|
+
// 形〕)+ session/paused 词落账(word 已随本批入册核心词表)
|
|
623
|
+
appendPaused: (sessionId) => {
|
|
624
|
+
const driver = stack.driverOf(sessionId) ?? stack.manager.open(sessionId).driver;
|
|
625
|
+
driver.session.append('session/paused', { reason: 'budget' });
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
// goal 沉淀摘要窄面(批 #99——上方适配器真身;缺席律不适用:
|
|
629
|
+
// 适配器零依赖构造恒在场,goal 件内 summarizer 缺席走确定性回退)
|
|
630
|
+
goalSummarizer,
|
|
631
|
+
// 全环捕获位透传(s 批——生产恒缺席;e2e rig lifecycle 通道)
|
|
632
|
+
...(options.goalServiceSink !== undefined ? { goalServiceSink: options.goalServiceSink } : {}),
|
|
633
|
+
// checkpoint 两 seam + 焦点会话位(批 19c-4——05 §5.3 词面独立律):
|
|
634
|
+
// 语境面 contextOf 活体日志优先(lastClosedBoundary 单源)+ 行
|
|
635
|
+
// workspaceRoot 锚经公开列表面反查(sessions.fork 同法——不为内部
|
|
636
|
+
// 取值开新读口);fork 面 = SessionManager.fork 直赋(05 §5.0 判别
|
|
637
|
+
// 子集形;箭头包装保 this 绑定);焦点会话 = channels.focusedId
|
|
638
|
+
// (/rewind 发起会话真源)
|
|
639
|
+
checkpointSession: {
|
|
640
|
+
contextOf: (sessionId) => {
|
|
641
|
+
const row = runtimeNow.persistence.listSessions().find((r) => r.id === sessionId);
|
|
642
|
+
if (row === undefined)
|
|
643
|
+
return undefined;
|
|
644
|
+
const log = stack.driverOf(sessionId)?.session ?? runtimeNow.persistence.loadSession(sessionId).log;
|
|
645
|
+
return { lastClosedBoundary: log.lastClosedBoundary(), workspaceRoot: row.workspaceRoot ?? '' };
|
|
646
|
+
},
|
|
647
|
+
},
|
|
648
|
+
checkpointFork: {
|
|
649
|
+
fork: (sourceSessionId, options) => stack.manager.fork(sourceSessionId, options),
|
|
650
|
+
},
|
|
651
|
+
focusSessionId: () => stack.channels.focusedId ?? undefined,
|
|
652
|
+
// 宿主版本(批 19d——mcp 件 initialize 握手 clientInfo.version
|
|
653
|
+
// 披露「对齐 package.json」单源位:装配选项 version 同源)
|
|
654
|
+
version: options.version,
|
|
655
|
+
// —— HTTP 面族十位(批 19e——sdk/webui/obs/issue 件装载态接线)——
|
|
656
|
+
// sdk 面工厂真身(core:sdk 件承载位:daemon/serve/TUI 开面消费
|
|
657
|
+
// 件在场 kit;stdio 不依赖件装载态——F16)
|
|
658
|
+
sdkFaceFactory: createSdkHttpFace,
|
|
659
|
+
// 插件道路由受理器(U5-2——kit 透传位:三入口经 core:sdk 件
|
|
660
|
+
// kit 'sdk-http-face' 消费 snapshot/attachFace;件禁用 ⇒ kit
|
|
661
|
+
// 缺席 ⇒ daemon 拒启/TUI·前台 warn 不开面 ⇒ 受理账无人 replay
|
|
662
|
+
// ——「sdk 禁 ⇒ 面亡 ⇒ 路由全灭」语义族闭环)
|
|
663
|
+
sdkPluginRoutes: pluginRoutes,
|
|
664
|
+
// webui 挂载闭包(core:webui 件 kit——面级 handle + 可选
|
|
665
|
+
// staticDir;开面晚于装载的晚绑形,件 apply 期只透传闭包)
|
|
666
|
+
webuiFaceMount: (face, mountOptions) => mountWebuiOnFace({
|
|
667
|
+
stack,
|
|
668
|
+
face,
|
|
669
|
+
...(mountOptions?.staticDir !== undefined ? { staticDir: mountOptions.staticDir } : {}),
|
|
670
|
+
}),
|
|
671
|
+
// obs 三 seam:事件源 = Store 真身直传(结构兼容 ObsEventsFace——
|
|
672
|
+
// 05 §3.4 宿主面消费位);notify 走 channels 会话作用域(归因
|
|
673
|
+
// 'obs'——呈现侧路由后端自决);audience = channels 观众探针
|
|
674
|
+
obsEvents: runtimeNow.persistence.store,
|
|
675
|
+
obsNotify: {
|
|
676
|
+
notify: (message, opts) => stack.channels.notify('obs', message, opts),
|
|
677
|
+
},
|
|
678
|
+
obsAudience: { hasAudience: () => stack.channels.hasAudience() },
|
|
679
|
+
// issue 五位:state = store_state 三法真身直传(不自建账本——
|
|
680
|
+
// 宪章二);budget = 04 §5 日池判适配(background 档——停靠不
|
|
681
|
+
// 落终态语义归件内);token/secret = 凭证库优先 env 回落(c-5
|
|
682
|
+
// 迁移——03 §10.9 优先级律,上方闭包单源);session = headless
|
|
683
|
+
// 会话真工厂(成熟度缺口 #5——主闸三起会面接线,生产面件装载
|
|
684
|
+
// 解锁)
|
|
685
|
+
issueState: runtimeNow.persistence.store,
|
|
686
|
+
issueBudget: {
|
|
687
|
+
canAffordIssue: () => stack.llm.canAfford('background')
|
|
688
|
+
? { ok: true }
|
|
689
|
+
: { ok: false, reason: '当日后台预算池尽(04 §5 停靠待唤醒——不落终态)' },
|
|
690
|
+
},
|
|
691
|
+
issueSession: issueSessionFactory,
|
|
692
|
+
...(issueToken !== undefined && issueToken !== '' ? { issueGithubToken: issueToken } : {}),
|
|
693
|
+
...(issueSecret !== undefined && issueSecret !== '' ? { issueWebhookSecret: issueSecret } : {}),
|
|
694
|
+
// —— credentials 人面命令两 seam(c-5——03 §10.9 写入面)——
|
|
695
|
+
// store = persist 真身直传(CredentialsCommandStore 四法投影,
|
|
696
|
+
// 词面独立律 compat 面);审计 seam 真接线(c-5 挂账 U3-5 兑现——
|
|
697
|
+
// 人面 add/rm 成功即落 credentials/changed,值恒不入载荷)
|
|
698
|
+
credentialsStore: runtimeNow.persistence.store,
|
|
699
|
+
credentialsOnChanged: (payload) => audit.append('credentials/changed', { ...payload }),
|
|
700
|
+
// —— oauth 流受局面(c-6——03 §10.9 oauth 案):注册表同真身 +
|
|
701
|
+
// SSRF 守卫包裹 fetch(web 卫生单源——上方 oauthFetch 单源)+
|
|
702
|
+
// 刷新链 60s 自驱缺省 + 单败 warn 走宿主 logger
|
|
703
|
+
credentialsOAuth: {
|
|
704
|
+
registry: oauthFlows,
|
|
705
|
+
fetchFn: oauthFetch,
|
|
706
|
+
warn: (message) => logger.warn(message),
|
|
707
|
+
},
|
|
708
|
+
// —— scheduler 编舞接线(批 20c 三位 + u-2 进程内推进一位)——
|
|
709
|
+
// 宿主对话栈(u-2——04 §12 定形注①):生产恒注入——引擎 runner
|
|
710
|
+
// 换进程内实装(scheduler-tick:fire 不 spawn,经 stack 起
|
|
711
|
+
// headless run + builtin 行程序化分派);e2e 回归锁锁死此形
|
|
712
|
+
conversationStack: stack,
|
|
713
|
+
// 宿主级 budget-extended 广播件(u-3——04 §5 定形注①升格):
|
|
714
|
+
// goal 停靠项登记面(生产恒注入;与 issue 工厂共享同一真身——
|
|
715
|
+
// 三停靠面同播单源)
|
|
716
|
+
budgetBroadcast,
|
|
717
|
+
// GateFacts 宿主三源收集闭包:行启停位 + 宿主在飞(anyRunning)+
|
|
718
|
+
// 最近真用户消息(boot 后监听器维护)+ 行上次触发(JobRow 自带
|
|
719
|
+
// lastFireAt 列)+ 当日后台预算(04 §5 canAfford)
|
|
720
|
+
schedulerGateFacts: (row) => ({
|
|
721
|
+
enabled: row.enabled,
|
|
722
|
+
agentBusy: stack.manager.anyRunning(),
|
|
723
|
+
lastUserMessageAt,
|
|
724
|
+
lastFireAt: row.lastFireAt,
|
|
725
|
+
canAfford: stack.llm.canAfford('background'),
|
|
726
|
+
}),
|
|
727
|
+
// 真 bin 出厂(BERRY_AGENT_BIN env 载体——缺席 'berry-agent'
|
|
728
|
+
// PATH 名解析归件内缺省)
|
|
729
|
+
...(env.BERRY_AGENT_BIN !== undefined && env.BERRY_AGENT_BIN !== ''
|
|
730
|
+
? { schedulerBinCommand: env.BERRY_AGENT_BIN }
|
|
731
|
+
: {}),
|
|
732
|
+
// cron 乙案开启位(BERRY_AGENT_CRON=1 显式置值 = 人面授权链的
|
|
733
|
+
// env 形——授权凭据即显式置值本身)
|
|
734
|
+
...(env.BERRY_AGENT_CRON === '1' ? { schedulerCronEnabled: true } : {}),
|
|
735
|
+
}),
|
|
736
|
+
warn: (message) => logger.warn(message),
|
|
737
|
+
});
|
|
738
|
+
boot = await runBoot(options.noPlugins === true, options.pluginFile);
|
|
739
|
+
}
|
|
740
|
+
catch (err) {
|
|
741
|
+
await runtime.shutdown(); // 已建资源先收口(幂等六步照走)
|
|
742
|
+
if (err instanceof BaseError && err.code === 'PLUGIN_ROW_INVALID') {
|
|
743
|
+
return {
|
|
744
|
+
ok: false,
|
|
745
|
+
exitCode: 1,
|
|
746
|
+
message: `启动失败:${err.message}`,
|
|
747
|
+
crashed: false,
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
throw err; // 余异常走下方崩溃取证档
|
|
751
|
+
}
|
|
752
|
+
Object.assign(pluginCounts, boot.counts); // 披露匣回写(disclosure 后续请求即见)
|
|
753
|
+
// —— skills 桥 + 插件技能层重同步编舞(批 19 skills 销账 + /reload 批抽
|
|
754
|
+
// 可重跑):首次 boot 后与每轮 /reload 换入后同函数调用——桥挂接( WeakSet
|
|
755
|
+
// 防同 registry 重挂)+ 旧代 plugin: 层清场 + 新代层补注册。core:skills
|
|
756
|
+
// 禁用档 tryGet 诚实缺席 → 零桥零层(缺席即未装载语义)。
|
|
757
|
+
//
|
|
758
|
+
// skills_change 事件桥(批 19b-1——03 §3.4 通知面汇流点):registry
|
|
759
|
+
// refresh 快照变化 → 全局词 skills_change 发射(41 钩子词已在 bootPlugins
|
|
760
|
+
// 预注册——dispatch.emit 直用)。桥落宿主侧不落件内:ctx.emit 域名律强制
|
|
761
|
+
// `core:skills/` 前缀——全局词对插件结构性不可达(域名律防插件伪造全局
|
|
762
|
+
// 事件,官方件同受束——宿主侧 dispatch 才是正口)。
|
|
763
|
+
//
|
|
764
|
+
// 磁盘件技能目录载荷层补注册(批 19 skills 销账——06 §11.4 位 4 / 03
|
|
765
|
+
// §6.1「mount 即注册」):core:skills 先装(synthesizePlan core 行先入
|
|
766
|
+
// plan)时磁盘件 manifest.skills 尚未激活——件内 apply 构造 pluginLayers
|
|
767
|
+
// 结构性空缺,装载收口后于此补注册。序位执法(06 §11.3 注册序即优先序
|
|
768
|
+
// ——插件层压出厂层):摘 factory → 位 4 逐插件插入 → factory 原实例重挂
|
|
769
|
+
// 末位。/reload 换代对称(03 §6.2 技能层摘除):旧代 plugin: 前缀层先全
|
|
770
|
+
// 摘再插新代(首跑零层清场幂等)。refresh 落新快照(披露段每请求物化
|
|
771
|
+
// 即生效)+ 桥发射 skills_change(providers 变化可观测)。per-provider
|
|
772
|
+
// 独立 realpath 去重集:与标准层目录交集仅病态形(装机树 vs 工作区/家/
|
|
773
|
+
// 出厂根构造性不相交),重叠时 first-wins + collision 诊断兜底。
|
|
774
|
+
const wiredSkillRegistries = new WeakSet();
|
|
775
|
+
const resyncPluginSkillLayers = async (handle) => {
|
|
776
|
+
const registry = scope.tryGet('skills');
|
|
777
|
+
if (registry === undefined)
|
|
778
|
+
return;
|
|
779
|
+
if (!wiredSkillRegistries.has(registry)) {
|
|
780
|
+
wiredSkillRegistries.add(registry);
|
|
781
|
+
registry.onChange(() => {
|
|
782
|
+
// 载荷 = 现行 provider id 清单(06 §11.3——消费面 = 渐进披露清单重物化)
|
|
783
|
+
void dispatch.emit('skills_change', { providers: registry.providerIds() });
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
// 旧代层清场(plugin: 前缀全摘——reload 换代对称;首跑零层幂等)
|
|
787
|
+
for (const id of registry.providerIds()) {
|
|
788
|
+
if (id.startsWith('plugin:'))
|
|
789
|
+
registry.unregisterProvider(id);
|
|
790
|
+
}
|
|
791
|
+
const pluginRows = handle.report.activated.filter((row) => row.skillDirs.length > 0);
|
|
792
|
+
if (pluginRows.length > 0) {
|
|
793
|
+
const factory = registry.getProvider('factory');
|
|
794
|
+
registry.unregisterProvider('factory'); // 位 4 让位(原实例重挂见下)
|
|
795
|
+
for (const row of pluginRows) {
|
|
796
|
+
// plugin: 前缀 = 与标准层 id 结构性不撞
|
|
797
|
+
registry.registerProvider(createDirProvider({ id: `plugin:${row.id}`, roots: [...row.skillDirs] }));
|
|
798
|
+
}
|
|
799
|
+
if (factory !== undefined)
|
|
800
|
+
registry.registerProvider(factory); // 出厂层重挂末位(序保真)
|
|
801
|
+
}
|
|
802
|
+
await registry.refresh();
|
|
803
|
+
};
|
|
804
|
+
// 卸载对称 closer(一次性注册晚绑 tryGet——换代自适;序在 plugin-unload
|
|
805
|
+
// 后 = 插件 disposer 先回卷;core:skills 禁用档 fn 内缺席零操作)
|
|
806
|
+
runtime.registerCloser({
|
|
807
|
+
label: 'skills-plugin-layers',
|
|
808
|
+
fn: async () => {
|
|
809
|
+
const registry = scope.tryGet('skills');
|
|
810
|
+
if (registry === undefined)
|
|
811
|
+
return;
|
|
812
|
+
for (const id of registry.providerIds()) {
|
|
813
|
+
if (id.startsWith('plugin:'))
|
|
814
|
+
registry.unregisterProvider(id);
|
|
815
|
+
}
|
|
816
|
+
await registry.refresh();
|
|
817
|
+
},
|
|
818
|
+
});
|
|
819
|
+
await resyncPluginSkillLayers(boot);
|
|
820
|
+
// —— 插件声明子代理层重同步(RP5 物化腿——03 §6.3 兑现注):镜像 skills
|
|
821
|
+
// resync 时序位(boot 装载收口后首调 + /reload reapply 内重调)。钩子真身
|
|
822
|
+
// 在 core:subagent apply 闭包(物化/撤位/后窗注册全在彼——assembly 只编排
|
|
823
|
+
// 时序与喂 activated 行);行滤 agentDirs > 0 投影为 SubagentPluginLayerRow。
|
|
824
|
+
// 无独立 closer:件级 disposer(apply 返)即卸载对称位——provider 位 +
|
|
825
|
+
// 工具位两撤。
|
|
826
|
+
const resyncPluginAgentLayers = async (handle) => {
|
|
827
|
+
const rows = handle.report.activated
|
|
828
|
+
.filter((row) => row.agentDirs.length > 0)
|
|
829
|
+
.map((row) => ({ id: row.id, agentDirs: [...row.agentDirs] }));
|
|
830
|
+
await subagentLayerResyncHook?.(rows);
|
|
831
|
+
};
|
|
832
|
+
await resyncPluginAgentLayers(boot);
|
|
833
|
+
// —— session/event 用户消息追踪(批 20c——GateFacts lastUserMessageAt 宿主
|
|
834
|
+
// 源维护):真用户输入(user/channel:*)才更新最近时刻——schedule(挂钟
|
|
835
|
+
// 触发的 user/message 非人语)/subagent-settled/compaction/plugin 注入不
|
|
836
|
+
// 计数(不打扰礼仪门只认真人)。词汇在 bootPlugins 注册(41 词表)——
|
|
837
|
+
// noPlugins 纯诊断形不注册即不挂(此时 scheduler 件亦未装载无消费面);
|
|
838
|
+
// dispatch.on 词未注册 fail-loud,故 isRegistered 守卫前置(同 session/
|
|
839
|
+
// event 桥律)。监听器随 dispatch 进程级生命周期——不设卸载 closer ——
|
|
840
|
+
if (dispatch.isRegistered('session/event')) {
|
|
841
|
+
dispatch.on('session/event', (payload) => {
|
|
842
|
+
const { event } = payload;
|
|
843
|
+
if (event.type !== 'user/message')
|
|
844
|
+
return;
|
|
845
|
+
// source 归因解析(闭集读侧判据):user/channel = 真人输入;余类注入不计
|
|
846
|
+
const parsed = parseEventSource(String(event.data.source ?? 'user'));
|
|
847
|
+
if (parsed.kind !== 'user' && parsed.kind !== 'channel')
|
|
848
|
+
return;
|
|
849
|
+
// event.time = ms epoch(05 §1.1)→ ISO UTC(GateFacts 时基同构)
|
|
850
|
+
lastUserMessageAt = new Date(event.time).toISOString();
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
// —— /reload 编舞接线(03 §5.7——本批):busy 判据 = manager 级任一 run
|
|
854
|
+
// 在飞(anyRunning 读面);run 收场 = ctx.agent onRunSettled 订阅(多会话
|
|
855
|
+
// 信封位在回调外——reloader 只消费「settled 边界到了」事实);回执走
|
|
856
|
+
// channels.notify(归因 'reload'——与 'tick'/'credentials' 同律)。
|
|
857
|
+
// reapply = runBoot(false) + 换代写回(boot 变量/pluginCounts 披露匣/
|
|
858
|
+
// skills 层重同步——闭包晚绑取值器下一请求即见新代);救援环律在
|
|
859
|
+
// runBoot 参位已注(旗标只管启动期)。
|
|
860
|
+
const reloadReport = (text) => {
|
|
861
|
+
void stack.channels.notify('reload', text);
|
|
862
|
+
};
|
|
863
|
+
const reloader = createPluginReloader({
|
|
864
|
+
// 档①预检:与装载读侧同一函数(单源——预检过装载必过清单面)
|
|
865
|
+
preflight: () => void readEnabledRows(dataDir, defaultFs()),
|
|
866
|
+
// 回卷旧代:换代槽当前代(noPlugins 首启形槽空 = no-op);对象面经
|
|
867
|
+
// rollbackFromReport 适配(failed → id 清单——error 细节走 boot-failures)
|
|
868
|
+
rollback: async () => {
|
|
869
|
+
const unload = pluginUnloadRef.current;
|
|
870
|
+
if (unload === null)
|
|
871
|
+
return emptyRollbackReceipt();
|
|
872
|
+
return rollbackFromReport(await unload());
|
|
873
|
+
},
|
|
874
|
+
// 换入新代:runBoot + 三处换代写回(boot 定位/披露匣/skills 层)。
|
|
875
|
+
// 单参调用(pluginFile 不传)= 03 §7 不变式 4 的机器落点:全量重载后
|
|
876
|
+
// --plugin-file 试件行不再合成(换代面恒真实装载形)。
|
|
877
|
+
reapply: async () => {
|
|
878
|
+
const previous = boot; // 换代前旧代(工具面 diff 基线——03 §2.8 通道真值)
|
|
879
|
+
const handle = await runBoot(false);
|
|
880
|
+
boot = handle;
|
|
881
|
+
Object.assign(pluginCounts, handle.counts);
|
|
882
|
+
await resyncPluginSkillLayers(handle);
|
|
883
|
+
await resyncPluginAgentLayers(handle);
|
|
884
|
+
// 新代工具面 diff(03 §2.8 定形——/reload 回执呈现新代 activated[].tools
|
|
885
|
+
// 对前代 diff):基线 = 旧代 activated 全体工具名并集;新代逐插件取
|
|
886
|
+
// 差集、非空才呈现(不造噪声)。首启 noPlugins 短路形 previous 为空代
|
|
887
|
+
// → 基线空集 = 新代工具全量呈新增(诚实形)。模型通道动作时点
|
|
888
|
+
// addedToolNames 恒诚实空执法不变——真值只经本回执走人面。
|
|
889
|
+
const previousTools = new Set();
|
|
890
|
+
if (previous !== undefined) {
|
|
891
|
+
for (const a of previous.report.activated)
|
|
892
|
+
for (const t of previous.toolsOf(a.id))
|
|
893
|
+
previousTools.add(t);
|
|
894
|
+
}
|
|
895
|
+
const addedTools = handle.report.activated
|
|
896
|
+
.map((a) => ({ pluginId: a.id, tools: handle.toolsOf(a.id).filter((t) => !previousTools.has(t)) }))
|
|
897
|
+
.filter((entry) => entry.tools.length > 0);
|
|
898
|
+
return {
|
|
899
|
+
total: handle.counts.total,
|
|
900
|
+
enabled: handle.counts.enabled,
|
|
901
|
+
failed: handle.counts.failed,
|
|
902
|
+
// 行级失败附错误文本(obs-a——03 §5.7② 呈现三面之③;report.failed
|
|
903
|
+
// 三键结构满足即透传,与 plugins list 失败分区同源同形)
|
|
904
|
+
failures: handle.report.failed.map((f) => ({ id: f.id, code: f.code, message: f.message })),
|
|
905
|
+
addedTools,
|
|
906
|
+
};
|
|
907
|
+
},
|
|
908
|
+
isBusy: () => stack.manager.anyRunning(),
|
|
909
|
+
onRunSettled: (handler) => {
|
|
910
|
+
const agentService = scope.tryGet(AGENT_SERVICE_NAME);
|
|
911
|
+
if (agentService === undefined)
|
|
912
|
+
return () => undefined; // 结构性不可达(栈内先建)——防御位
|
|
913
|
+
return agentService.onRunSettled(() => handler());
|
|
914
|
+
},
|
|
915
|
+
report: reloadReport,
|
|
916
|
+
warn: (message) => logger.warn(message),
|
|
917
|
+
});
|
|
918
|
+
// TUI 命令面注册(03 §5.7 词面权威;fire-and-forget——回执走 notify,
|
|
919
|
+
// handler 不 await 编舞〔busy 期排队等 run 收场,await 会卡输入流〕)
|
|
920
|
+
stack.channels.commands.register('reload', async () => reloader.request(), '重载插件装载态(会话运行中自动排队,run 收场后执行)');
|
|
921
|
+
// —— /plugins TUI 命令面(03 §5.8 三面同源之 TUI 面——task #88 笔二):
|
|
922
|
+
// 宿主级命令直注册(与 /reload 同位——非插件自带命令,不随换代卸除);
|
|
923
|
+
// 纯逻辑件单源(plugins-command.ts——argv 解析/前置两查/回执文本),
|
|
924
|
+
// 装配面只接线四 seam:行编辑 fs、进程内 audit face(落账失败 warn 不
|
|
925
|
+
// 阻塞——行编辑已生效)、成功尾自动链 reloader(03 §5.2)、内存装载
|
|
926
|
+
// 报告取值器(list 读面——换代取值器闭包,/reload 后即新代投影)。
|
|
927
|
+
// 回执经 notify 归因 'plugins'(与 'reload'/'tick'/'credentials' 同律)。
|
|
928
|
+
// config 表单腿(ix-3b/c):问询走本会话 ask 通道(args.sessionId 绑定
|
|
929
|
+
// ——表单需会话锚,缺席诚实拒);secret 写凭证盒 + credentials/changed
|
|
930
|
+
// 审计与 c-5 人面同律(值恒不入载荷)。
|
|
931
|
+
stack.channels.commands.register('plugins', async (args) => {
|
|
932
|
+
const outcome = await runPluginsCommand(args.argv, {
|
|
933
|
+
dataDir,
|
|
934
|
+
fs: createPluginStoreFs(),
|
|
935
|
+
auditSink: (type, payload) => {
|
|
936
|
+
try {
|
|
937
|
+
audit.append(type, payload);
|
|
938
|
+
}
|
|
939
|
+
catch (err) {
|
|
940
|
+
logger.warn(`生命周期审计落账失败(${type}):${err instanceof Error ? err.message : String(err)}——主流程不受影响(行编辑已生效)`);
|
|
941
|
+
}
|
|
942
|
+
},
|
|
943
|
+
requestReload: () => void reloader.request(),
|
|
944
|
+
report: () => boot?.report,
|
|
945
|
+
configForm: dataDir === null
|
|
946
|
+
? undefined // 纯 memory 形在命令层已拒(此位结构性不达——防御缺省)
|
|
947
|
+
: (id) => {
|
|
948
|
+
if (args.sessionId === undefined) {
|
|
949
|
+
return Promise.resolve({
|
|
950
|
+
ok: false,
|
|
951
|
+
text: 'config 表单需会话锚(此命令面无发起会话——问询无法投递)——TUI 会话内执行 /plugins config',
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
const sessionId = args.sessionId;
|
|
955
|
+
return runPluginConfigForm(id, {
|
|
956
|
+
dataDir,
|
|
957
|
+
fs: createPluginStoreFs(),
|
|
958
|
+
configFaceOf: (pluginId) => boot?.configFaceOf(pluginId),
|
|
959
|
+
ask: {
|
|
960
|
+
select: (message, choices, opts) => stack.channels.select(sessionId, message, choices, opts),
|
|
961
|
+
input: (message, opts) => stack.channels.input(sessionId, message, opts),
|
|
962
|
+
},
|
|
963
|
+
getCredential: (namespace, name) => runtimeNow.persistence.store.getCredential(namespace, name),
|
|
964
|
+
setCredential: (namespace, name, entry) => runtimeNow.persistence.store.setCredential(namespace, name, entry),
|
|
965
|
+
onCredentialChanged: (payload) => audit.append('credentials/changed', { ...payload }),
|
|
966
|
+
requestReload: () => void reloader.request(),
|
|
967
|
+
});
|
|
968
|
+
},
|
|
969
|
+
});
|
|
970
|
+
void stack.channels.notify('plugins', outcome.text);
|
|
971
|
+
}, PLUGINS_CMD_USAGE);
|
|
972
|
+
// —— /doors TUI 命令面(03 §4.6 doors 段编辑腿的人面动词——g-2;07 §5
|
|
973
|
+
// 定名:写动词 TUI 专属,CLI 面只读 list):宿主级直注册(与 /reload、
|
|
974
|
+
// /plugins 同位——机制宿主有,不随插件换代卸除);纯逻辑件单源
|
|
975
|
+
// (doors-cmd.ts——argv 解析/段编辑/回执文本)。写动词成功真变更尾落
|
|
976
|
+
// doors/updated(origin 'tui-cmd'——recordDoorsDiff boot 序 'boot-diff'
|
|
977
|
+
// 位的编辑道姊妹位;落账失败 warn 不阻塞——段编辑已生效);不自动链
|
|
978
|
+
// /reload(与 /plugins 成功尾自动链分立——g-1 门检输入 = 活体源,写回
|
|
979
|
+
// 即门即时生效,reload 只刷新装载面快照/审计基线,回执已两时点诚实
|
|
980
|
+
// 陈述)。回执经 notify 归因 'doors'(与 'plugins' 同律)。
|
|
981
|
+
stack.channels.commands.register('doors', async (args) => {
|
|
982
|
+
const parsed = parseDoorsArgv(args.argv);
|
|
983
|
+
if (!parsed.ok) {
|
|
984
|
+
void stack.channels.notify('doors', parsed.message);
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
const outcome = runDoorsCommand(parsed.sub, {
|
|
988
|
+
dataDir,
|
|
989
|
+
fs: createPluginStoreFs(),
|
|
990
|
+
onDoorsUpdated: (doors) => {
|
|
991
|
+
try {
|
|
992
|
+
audit.append('doors/updated', { doors: [...doors], origin: 'tui-cmd' });
|
|
993
|
+
}
|
|
994
|
+
catch (err) {
|
|
995
|
+
logger.warn(`doors 审计落账失败:${err instanceof Error ? err.message : String(err)}——主流程不受影响(段编辑已生效)`);
|
|
996
|
+
}
|
|
997
|
+
},
|
|
998
|
+
});
|
|
999
|
+
void stack.channels.notify('doors', outcome.text);
|
|
1000
|
+
}, DOORS_USAGE);
|
|
1001
|
+
// —— /approval TUI 命令面(04 §9 定形块⑤⑥——ap-3):宿主级直注册
|
|
1002
|
+
// (与 /reload、/plugins、/doors 同位——机制宿主有,不随插件换代卸除);
|
|
1003
|
+
// 纯逻辑件单源(approval-cmd.ts——四动词 status/entries/explain/preset)。
|
|
1004
|
+
// status 面 = 装配期四层解析胜者快照(来源标注由入口注入:CLI 层
|
|
1005
|
+
// sandboxModeSource/approvalPolicySource;settings/缺省层本装配根自证);
|
|
1006
|
+
// preset 写盘成功尾落 preset/applied 审计恰一笔(05 §1.1——落账失败
|
|
1007
|
+
// warn 不阻塞,写盘已生效;CLI --preset 逐次形零审计——不经本面)。
|
|
1008
|
+
// 回执经 notify 归因 'approval'(与 'doors' 同律)。
|
|
1009
|
+
const effectiveMode = options.sandboxMode !== undefined
|
|
1010
|
+
? options.sandboxMode()
|
|
1011
|
+
: settingsMode !== undefined
|
|
1012
|
+
? settingsMode
|
|
1013
|
+
: 'workspace-write';
|
|
1014
|
+
const modeSource = options.sandboxModeSource ??
|
|
1015
|
+
(options.sandboxMode !== undefined
|
|
1016
|
+
? 'CLI 旗标(逐次)'
|
|
1017
|
+
: settingsMode !== undefined
|
|
1018
|
+
? 'settings.json(持久缺省)'
|
|
1019
|
+
: '缺省(代码常量)');
|
|
1020
|
+
const effectivePolicy = options.approvalPolicy ?? settingsPolicy ?? 'ask';
|
|
1021
|
+
const policySource = options.approvalPolicySource ??
|
|
1022
|
+
(options.approvalPolicy !== undefined
|
|
1023
|
+
? 'CLI --preset/旗标(逐次)'
|
|
1024
|
+
: settingsPolicy !== undefined
|
|
1025
|
+
? 'settings.json(持久缺省)'
|
|
1026
|
+
: '缺省(代码常量)');
|
|
1027
|
+
stack.channels.commands.register('approval', async (args) => {
|
|
1028
|
+
const parsed = parseApprovalArgv(args.argv);
|
|
1029
|
+
if (!parsed.ok) {
|
|
1030
|
+
void stack.channels.notify('approval', parsed.message);
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
const outcome = runApprovalCommand(parsed.sub, {
|
|
1034
|
+
dataDir,
|
|
1035
|
+
status: { mode: effectiveMode, policy: effectivePolicy, modeSource, policySource },
|
|
1036
|
+
workspace: () => canonicalWorkspaceRoot(),
|
|
1037
|
+
onPresetApplied: (preset, sandboxMode, approvalPolicy, appended) => {
|
|
1038
|
+
try {
|
|
1039
|
+
audit.append('preset/applied', { preset, sandboxMode, approvalPolicy, appended });
|
|
1040
|
+
}
|
|
1041
|
+
catch (err) {
|
|
1042
|
+
logger.warn(`preset 审计落账失败:${err instanceof Error ? err.message : String(err)}——主流程不受影响(写盘已生效)`);
|
|
1043
|
+
}
|
|
1044
|
+
},
|
|
1045
|
+
});
|
|
1046
|
+
void stack.channels.notify('approval', outcome.text);
|
|
1047
|
+
}, APPROVAL_USAGE);
|
|
1048
|
+
return { ok: true, runtime, logger, dispatch, scope, stack, boot, pluginCounts, reloader };
|
|
1049
|
+
}
|
|
1050
|
+
catch (err) {
|
|
1051
|
+
// 意外异常 = 崩溃取证档:crash.log 先写(memory 形内建跳过)→ 资源收口 → 归一失败档
|
|
1052
|
+
runtime?.writeCrashLog(err);
|
|
1053
|
+
await runtime?.shutdown();
|
|
1054
|
+
return {
|
|
1055
|
+
ok: false,
|
|
1056
|
+
exitCode: 1,
|
|
1057
|
+
message: err instanceof Error ? err.message : String(err),
|
|
1058
|
+
crashed: true,
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* 触发器开门授予集活体读取(F10 定形——注册闸与 fire 复检共用源):每次
|
|
1064
|
+
* 现读 enabled.yaml 现解析,/reload 撤位后下一次判即拒。
|
|
1065
|
+
*
|
|
1066
|
+
* **fail-closed 全失败档一律空集**(文件缺席/不可读/坏 yaml/行校验败/行被
|
|
1067
|
+
* 禁用/id 未装载)——与 boot 读侧 fail-loud(PLUGIN_ROW_INVALID 拒启)分立
|
|
1068
|
+
* 两律:boot 拦的是启动期配置错;此处拦的是运行期判面,**宁拒不误放**
|
|
1069
|
+
* (memory 形 dataDir null 亦空集——core: 官方件直开豁免不经本面)。
|
|
1070
|
+
*/
|
|
1071
|
+
export function readTriggerOpensLive(dataDir, pluginId) {
|
|
1072
|
+
if (dataDir === null)
|
|
1073
|
+
return new Set();
|
|
1074
|
+
let text;
|
|
1075
|
+
try {
|
|
1076
|
+
text = readFileSync(enabledYamlPath(dataDir), 'utf8');
|
|
1077
|
+
}
|
|
1078
|
+
catch {
|
|
1079
|
+
return new Set(); // 缺席/不可读 = 全默认关
|
|
1080
|
+
}
|
|
1081
|
+
let doc;
|
|
1082
|
+
try {
|
|
1083
|
+
doc = parseYaml(text);
|
|
1084
|
+
}
|
|
1085
|
+
catch {
|
|
1086
|
+
return new Set(); // 坏 yaml 宁拒不误放(启动期已 fail-loud——此处防御运行期二次写坏)
|
|
1087
|
+
}
|
|
1088
|
+
const result = parseEnabledRows(doc);
|
|
1089
|
+
if (!result.ok)
|
|
1090
|
+
return new Set();
|
|
1091
|
+
const row = result.rows.find((r) => r.id === pluginId);
|
|
1092
|
+
if (row === undefined || row.disabled === true)
|
|
1093
|
+
return new Set();
|
|
1094
|
+
return new Set(row.opens ?? []);
|
|
1095
|
+
}
|
|
1096
|
+
/**
|
|
1097
|
+
* 进程级 doors 段活体读取(开门制扩展批 2026-09-09——03 §4.6 双源并集律第二
|
|
1098
|
+
* 源的运行期取值面):每次现读 enabled.yaml 现解析顶层 doors 段,受理时点
|
|
1099
|
+
* 现读现判(撤位即收回——readTriggerOpensLive 同律同位)。消费位两路:模型
|
|
1100
|
+
* 道两工具族门检输入(observeCross seam)+ 操控受理器 caller 感知合成的
|
|
1101
|
+
* doors 支路(controlCross seam 插件道并集项/模型道单独项)。
|
|
1102
|
+
*
|
|
1103
|
+
* **fail-closed 全失败档一律空集**(文件缺席/不可读/坏 yaml/段校验败——与
|
|
1104
|
+
* readTriggerOpensLive 同律:boot 读侧 fail-loud 拦启动期配置错,此处拦运行
|
|
1105
|
+
* 期判面宁拒不误放;memory 形 dataDir null 亦空集)。
|
|
1106
|
+
*/
|
|
1107
|
+
export function readDoorsSegmentLive(dataDir) {
|
|
1108
|
+
if (dataDir === null)
|
|
1109
|
+
return new Set();
|
|
1110
|
+
let text;
|
|
1111
|
+
try {
|
|
1112
|
+
text = readFileSync(enabledYamlPath(dataDir), 'utf8');
|
|
1113
|
+
}
|
|
1114
|
+
catch {
|
|
1115
|
+
return new Set(); // 缺席/不可读 = 段缺席 = 该源空集
|
|
1116
|
+
}
|
|
1117
|
+
let doc;
|
|
1118
|
+
try {
|
|
1119
|
+
doc = parseYaml(text);
|
|
1120
|
+
}
|
|
1121
|
+
catch {
|
|
1122
|
+
return new Set(); // 坏 yaml 宁拒不误放
|
|
1123
|
+
}
|
|
1124
|
+
const result = parseEnabledRows(doc);
|
|
1125
|
+
if (!result.ok)
|
|
1126
|
+
return new Set();
|
|
1127
|
+
return new Set(result.doors);
|
|
1128
|
+
}
|
|
1129
|
+
/** 双源并集(caller 感知合成的插件道支路——纯局部集,不改写两源只读集) */
|
|
1130
|
+
function unionOpens(a, b) {
|
|
1131
|
+
const out = new Set(a);
|
|
1132
|
+
for (const value of b)
|
|
1133
|
+
out.add(value);
|
|
1134
|
+
return out;
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* caller 感知合成取值器工厂(开门制扩展批 2026-09-09——03 §4.6 双源并集律的
|
|
1138
|
+
* 装配单源):插件道 caller = doors 段活体 ∪ 该插件行 opens 活体并集
|
|
1139
|
+
* (readTriggerOpensLive 同源——源①无插件 id 锚的结构性缺位由此补齐)、模型
|
|
1140
|
+
* 道 caller = doors 段单独。逐次现读现判(撤位即收回)。
|
|
1141
|
+
*/
|
|
1142
|
+
export function createControlOpensFor(dataDir) {
|
|
1143
|
+
return (caller) => caller.kind === 'plugin'
|
|
1144
|
+
? unionOpens(readDoorsSegmentLive(dataDir), readTriggerOpensLive(dataDir, caller.pluginId))
|
|
1145
|
+
: readDoorsSegmentLive(dataDir);
|
|
1146
|
+
}
|