@downcity/city 1.1.29 → 1.1.39

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.
Files changed (153) hide show
  1. package/README.md +5 -11
  2. package/bin/cli/Index.js +10 -5
  3. package/bin/cli/Index.js.map +1 -1
  4. package/bin/cli/agent/AgentChat.js +1 -1
  5. package/bin/cli/agent/AgentChat.js.map +1 -1
  6. package/bin/cli/agent/AgentManager.js +3 -3
  7. package/bin/cli/agent/AgentManager.js.map +1 -1
  8. package/bin/cli/agent/Init.d.ts.map +1 -1
  9. package/bin/cli/agent/Init.js +14 -14
  10. package/bin/cli/agent/Init.js.map +1 -1
  11. package/bin/cli/agent/Restart.js +1 -1
  12. package/bin/cli/agent/Restart.js.map +1 -1
  13. package/bin/cli/agent/Run.d.ts.map +1 -1
  14. package/bin/cli/agent/Run.js +12 -19
  15. package/bin/cli/agent/Run.js.map +1 -1
  16. package/bin/cli/agent/Start.js +1 -1
  17. package/bin/cli/agent/Start.js.map +1 -1
  18. package/bin/cli/control-plane/ControlPlaneProcess.d.ts.map +1 -1
  19. package/bin/cli/control-plane/ControlPlaneProcess.js +2 -3
  20. package/bin/cli/control-plane/ControlPlaneProcess.js.map +1 -1
  21. package/bin/cli/model/ModelSupport.d.ts +1 -1
  22. package/bin/cli/model/ModelSupport.d.ts.map +1 -1
  23. package/bin/cli/model/ModelSupport.js +1 -1
  24. package/bin/cli/model/ModelSupport.js.map +1 -1
  25. package/bin/cli/shared/Chat.d.ts +1 -1
  26. package/bin/cli/shared/Chat.js +1 -1
  27. package/bin/cli/shared/ChatAuth.d.ts.map +1 -1
  28. package/bin/cli/shared/ChatAuth.js +5 -7
  29. package/bin/cli/shared/ChatAuth.js.map +1 -1
  30. package/bin/cli/shared/ChatManager.d.ts +1 -1
  31. package/bin/cli/shared/ChatManager.d.ts.map +1 -1
  32. package/bin/cli/shared/ChatManager.js +20 -21
  33. package/bin/cli/shared/ChatManager.js.map +1 -1
  34. package/bin/cli/shared/Config.js +1 -1
  35. package/bin/cli/shared/Config.js.map +1 -1
  36. package/bin/cli/shared/ManagedPluginActionCommands.d.ts +15 -0
  37. package/bin/cli/shared/ManagedPluginActionCommands.d.ts.map +1 -0
  38. package/bin/cli/shared/{PluginRuntimeActionCommands.js → ManagedPluginActionCommands.js} +13 -12
  39. package/bin/cli/shared/ManagedPluginActionCommands.js.map +1 -0
  40. package/bin/cli/shared/{PluginRuntimeRemote.d.ts → ManagedPluginRemote.d.ts} +6 -6
  41. package/bin/cli/shared/{PluginRuntimeRemote.d.ts.map → ManagedPluginRemote.d.ts.map} +1 -1
  42. package/bin/cli/shared/{PluginRuntimeRemote.js → ManagedPluginRemote.js} +14 -14
  43. package/bin/cli/shared/ManagedPluginRemote.js.map +1 -0
  44. package/bin/cli/shared/PluginScheduleCommand.d.ts +3 -2
  45. package/bin/cli/shared/PluginScheduleCommand.d.ts.map +1 -1
  46. package/bin/cli/shared/PluginScheduleCommand.js +12 -11
  47. package/bin/cli/shared/PluginScheduleCommand.js.map +1 -1
  48. package/bin/cli/shared/{PluginRuntimeSupport.d.ts → PluginTargetSupport.d.ts} +7 -7
  49. package/bin/cli/shared/PluginTargetSupport.d.ts.map +1 -0
  50. package/bin/cli/shared/{PluginRuntimeSupport.js → PluginTargetSupport.js} +7 -8
  51. package/bin/cli/shared/{PluginRuntimeSupport.js.map → PluginTargetSupport.js.map} +1 -1
  52. package/bin/cli/shared/Plugins.d.ts.map +1 -1
  53. package/bin/cli/shared/Plugins.js +30 -21
  54. package/bin/cli/shared/Plugins.js.map +1 -1
  55. package/bin/cli/shared/PortHints.js +1 -1
  56. package/bin/config/DowncitySchema.d.ts.map +1 -1
  57. package/bin/config/DowncitySchema.js +2 -8
  58. package/bin/config/DowncitySchema.js.map +1 -1
  59. package/bin/config/Paths.d.ts +2 -2
  60. package/bin/config/Paths.js +2 -2
  61. package/bin/control/AgentStatusApiRoutes.js +2 -2
  62. package/bin/control/AgentStatusApiRoutes.js.map +1 -1
  63. package/bin/control/ChannelAccountApiRoutes.d.ts.map +1 -1
  64. package/bin/control/ChannelAccountApiRoutes.js +6 -7
  65. package/bin/control/ChannelAccountApiRoutes.js.map +1 -1
  66. package/bin/control/ControlGateway.d.ts.map +1 -1
  67. package/bin/control/ControlGateway.js +3 -2
  68. package/bin/control/ControlGateway.js.map +1 -1
  69. package/bin/control/PluginApiRoutes.d.ts.map +1 -1
  70. package/bin/control/PluginApiRoutes.js +38 -30
  71. package/bin/control/PluginApiRoutes.js.map +1 -1
  72. package/bin/control/gateway/AgentActions.d.ts.map +1 -1
  73. package/bin/control/gateway/AgentActions.js +16 -11
  74. package/bin/control/gateway/AgentActions.js.map +1 -1
  75. package/bin/control/gateway/AgentCatalog.js +1 -1
  76. package/bin/control/gateway/AgentCatalog.js.map +1 -1
  77. package/bin/control/instant/InstantApiRoutes.d.ts +3 -3
  78. package/bin/control/instant/InstantApiRoutes.d.ts.map +1 -1
  79. package/bin/control/instant/InstantApiRoutes.js +5 -5
  80. package/bin/control/instant/InstantApiRoutes.js.map +1 -1
  81. package/bin/control/instant/{InstantSessionService.d.ts → InstantSessionRunner.d.ts} +7 -7
  82. package/bin/control/instant/InstantSessionRunner.d.ts.map +1 -0
  83. package/bin/control/instant/{InstantSessionService.js → InstantSessionRunner.js} +4 -4
  84. package/bin/control/instant/InstantSessionRunner.js.map +1 -0
  85. package/bin/http/auth/RoutePolicy.js +4 -4
  86. package/bin/http/auth/RoutePolicy.js.map +1 -1
  87. package/bin/model/runtime/CreateRuntimeModel.d.ts +2 -10
  88. package/bin/model/runtime/CreateRuntimeModel.d.ts.map +1 -1
  89. package/bin/model/runtime/CreateRuntimeModel.js +1 -16
  90. package/bin/model/runtime/CreateRuntimeModel.js.map +1 -1
  91. package/bin/model/runtime/ExecutionModelBinding.d.ts +46 -0
  92. package/bin/model/runtime/ExecutionModelBinding.d.ts.map +1 -0
  93. package/bin/model/runtime/ExecutionModelBinding.js +96 -0
  94. package/bin/model/runtime/ExecutionModelBinding.js.map +1 -0
  95. package/bin/process/daemon/Api.d.ts +2 -2
  96. package/bin/process/daemon/Api.js +1 -1
  97. package/bin/process/registry/AgentHostRuntime.d.ts +1 -9
  98. package/bin/process/registry/AgentHostRuntime.d.ts.map +1 -1
  99. package/bin/process/registry/AgentHostRuntime.js +2 -156
  100. package/bin/process/registry/AgentHostRuntime.js.map +1 -1
  101. package/package.json +3 -2
  102. package/src/cli/Index.ts +13 -5
  103. package/src/cli/agent/AgentChat.ts +1 -1
  104. package/src/cli/agent/AgentManager.ts +3 -3
  105. package/src/cli/agent/Init.ts +15 -14
  106. package/src/cli/agent/Restart.ts +1 -1
  107. package/src/cli/agent/Run.ts +12 -18
  108. package/src/cli/agent/Start.ts +1 -1
  109. package/src/cli/control-plane/ControlPlaneProcess.ts +2 -3
  110. package/src/cli/model/ModelSupport.ts +1 -1
  111. package/src/cli/shared/Chat.ts +1 -1
  112. package/src/cli/shared/ChatAuth.ts +10 -11
  113. package/src/cli/shared/ChatManager.ts +21 -22
  114. package/src/cli/shared/Config.ts +1 -1
  115. package/src/cli/shared/{PluginRuntimeActionCommands.ts → ManagedPluginActionCommands.ts} +18 -15
  116. package/src/cli/shared/{PluginRuntimeRemote.ts → ManagedPluginRemote.ts} +15 -15
  117. package/src/cli/shared/PluginScheduleCommand.ts +12 -11
  118. package/src/cli/shared/{PluginRuntimeSupport.ts → PluginTargetSupport.ts} +8 -9
  119. package/src/cli/shared/Plugins.ts +38 -28
  120. package/src/cli/shared/PortHints.ts +1 -1
  121. package/src/config/DowncitySchema.ts +2 -8
  122. package/src/config/Paths.ts +2 -2
  123. package/src/control/AgentStatusApiRoutes.ts +5 -5
  124. package/src/control/ChannelAccountApiRoutes.ts +6 -7
  125. package/src/control/ControlGateway.ts +3 -2
  126. package/src/control/PluginApiRoutes.ts +42 -32
  127. package/src/control/gateway/AgentActions.ts +16 -11
  128. package/src/control/gateway/AgentCatalog.ts +1 -1
  129. package/src/control/instant/InstantApiRoutes.ts +8 -8
  130. package/src/control/instant/{InstantSessionService.ts → InstantSessionRunner.ts} +7 -7
  131. package/src/http/auth/RoutePolicy.ts +4 -4
  132. package/src/model/runtime/CreateRuntimeModel.ts +1 -26
  133. package/src/model/runtime/ExecutionModelBinding.ts +120 -0
  134. package/src/process/daemon/Api.ts +2 -2
  135. package/src/process/registry/AgentHostRuntime.ts +2 -164
  136. package/tsconfig.json +2 -1
  137. package/bin/cli/shared/PluginRuntimeActionCommands.d.ts +0 -14
  138. package/bin/cli/shared/PluginRuntimeActionCommands.d.ts.map +0 -1
  139. package/bin/cli/shared/PluginRuntimeActionCommands.js.map +0 -1
  140. package/bin/cli/shared/PluginRuntimeRemote.js.map +0 -1
  141. package/bin/cli/shared/PluginRuntimeSupport.d.ts.map +0 -1
  142. package/bin/control/instant/InstantSessionService.d.ts.map +0 -1
  143. package/bin/control/instant/InstantSessionService.js.map +0 -1
  144. package/bin/platform/chatAuthorization/Store.d.ts +0 -31
  145. package/bin/platform/chatAuthorization/Store.d.ts.map +0 -1
  146. package/bin/platform/chatAuthorization/Store.js +0 -145
  147. package/bin/platform/chatAuthorization/Store.js.map +0 -1
  148. package/bin/process/registry/PluginRuntime.d.ts +0 -24
  149. package/bin/process/registry/PluginRuntime.d.ts.map +0 -1
  150. package/bin/process/registry/PluginRuntime.js +0 -31
  151. package/bin/process/registry/PluginRuntime.js.map +0 -1
  152. package/src/platform/chatAuthorization/Store.ts +0 -181
  153. package/src/process/registry/PluginRuntime.ts +0 -42
@@ -13,30 +13,31 @@ import type { Command } from "commander";
13
13
  import prompts from "prompts";
14
14
  import {
15
15
  buildStaticPluginAvailability,
16
- findBuiltinPlugin,
17
- findStaticPluginView,
18
- listRegisteredPlugins,
19
- listStaticPluginViews,
16
+ findPluginByName,
17
+ listPluginViews,
18
+ listPluginsWithLifecycle,
19
+ listPluginsWithoutLifecycle,
20
20
  runLocalPluginAction,
21
21
  } from "@downcity/agent";
22
+ import { createBuiltinPlugins } from "@downcity/plugins";
22
23
  import { printResult } from "@/utils/cli/CliOutput.js";
23
24
  import type { JsonValue } from "@downcity/agent";
24
25
  import { getDowncityJsonPath } from "@/config/Paths.js";
25
26
  import type { PluginCliBaseOptions } from "@downcity/agent";
26
27
  import { emitCliBlock } from "./CliReporter.js";
27
28
  import { parseBoolean, parsePort } from "./IndexSupport.js";
28
- import { resolveProjectRoot } from "./PluginRuntimeSupport.js";
29
+ import { resolveProjectRoot } from "./PluginTargetSupport.js";
29
30
  import {
30
- runPluginRuntimeCommandBridge,
31
- runPluginRuntimeControlCommand,
32
- } from "./PluginRuntimeRemote.js";
31
+ runManagedPluginCommandBridge,
32
+ runManagedPluginControlCommand,
33
+ } from "./ManagedPluginRemote.js";
33
34
  import { registerPluginScheduleCommands } from "./PluginScheduleCommand.js";
34
35
  import { setCityPluginEnabled } from "@/platform/PluginLifecycle.js";
35
36
 
36
37
  type StaticCatalogEntry = {
37
38
  name: string;
38
39
  title: string;
39
- kind: "runtime" | "extension";
40
+ kind: "managed" | "local";
40
41
  enabled: boolean;
41
42
  available: boolean;
42
43
  actionCount: number;
@@ -45,6 +46,10 @@ type StaticCatalogEntry = {
45
46
  note?: string;
46
47
  };
47
48
 
49
+ function createPluginCatalog() {
50
+ return createBuiltinPlugins();
51
+ }
52
+
48
53
  async function resolvePluginProjectRoot(options: PluginCliBaseOptions): Promise<{
49
54
  projectRoot?: string;
50
55
  error?: string;
@@ -79,6 +84,7 @@ function buildSafeStaticPluginAvailability(pluginName: string): {
79
84
  } {
80
85
  try {
81
86
  const availability = buildStaticPluginAvailability({
87
+ plugins: createPluginCatalog(),
82
88
  pluginName,
83
89
  });
84
90
  const normalizedReasons = availability.reasons.map((reason) => {
@@ -122,7 +128,7 @@ function truncateCell(input: string, width: number): string {
122
128
  function renderPluginCatalogTable(rows: Array<{
123
129
  name: string;
124
130
  title: string;
125
- kind: "runtime" | "extension";
131
+ kind: "managed" | "local";
126
132
  enabled: boolean;
127
133
  available: boolean;
128
134
  actionCount: number;
@@ -166,24 +172,27 @@ function renderPluginCatalogTable(rows: Array<{
166
172
  }
167
173
 
168
174
  function listStaticCatalogEntries(): StaticCatalogEntry[] {
169
- const runtimeEntries = listRegisteredPlugins().map((plugin) => ({
175
+ const plugins = createPluginCatalog();
176
+ const managedEntries = listPluginsWithLifecycle(plugins).map((plugin) => ({
170
177
  name: plugin.name,
171
- title: `${plugin.name} runtime plugin`,
172
- kind: "runtime" as const,
178
+ title: String(plugin.title || plugin.name || "").trim() || plugin.name,
179
+ kind: "managed" as const,
173
180
  enabled: true,
174
181
  available: true,
175
182
  actionCount: Object.keys(plugin.actions || {}).length,
176
183
  actions: Object.keys(plugin.actions || {}).sort((left, right) => left.localeCompare(right)),
177
184
  hasSystem: typeof plugin.system === "function",
178
- note: "Runtime plugin. Use `city plugin start/stop/restart/status` with an agent target for live state.",
185
+ note: "Managed plugin. Use `city plugin start/stop/restart/status` with an agent target for live state.",
179
186
  }));
180
187
 
181
- const extensionEntries = listStaticPluginViews().map((plugin) => {
188
+ const localPlugins = listPluginsWithoutLifecycle(plugins);
189
+ const localEntries = listPluginViews(localPlugins)
190
+ .map((plugin) => {
182
191
  const availability = buildSafeStaticPluginAvailability(plugin.name);
183
192
  return {
184
193
  name: plugin.name,
185
194
  title: plugin.title,
186
- kind: "extension" as const,
195
+ kind: "local" as const,
187
196
  enabled: availability.enabled,
188
197
  available: availability.available,
189
198
  actionCount: plugin.actions.length,
@@ -193,7 +202,7 @@ function listStaticCatalogEntries(): StaticCatalogEntry[] {
193
202
  };
194
203
  });
195
204
 
196
- const merged = [...runtimeEntries, ...extensionEntries];
205
+ const merged = [...managedEntries, ...localEntries];
197
206
  const unique = new Map<string, StaticCatalogEntry>();
198
207
  for (const entry of merged) {
199
208
  if (!unique.has(entry.name)) {
@@ -416,7 +425,7 @@ async function runPluginLifecycleCommand(params: {
416
425
  enabled: boolean;
417
426
  asJson?: boolean;
418
427
  }): Promise<void> {
419
- const plugin = findBuiltinPlugin(params.pluginName);
428
+ const plugin = findPluginByName(createPluginCatalog(), params.pluginName);
420
429
  if (!plugin) {
421
430
  printResult({
422
431
  asJson: params.asJson === true,
@@ -552,6 +561,7 @@ async function runPluginActionCommand(params: {
552
561
 
553
562
  const payload = parseCommandPayload(params.payload);
554
563
  const local = await runLocalPluginAction({
564
+ plugins: createPluginCatalog(),
555
565
  projectRoot: resolved.projectRoot,
556
566
  pluginName: params.pluginName,
557
567
  actionName: params.actionName,
@@ -609,7 +619,7 @@ export function registerPluginsCommand(program: Command): void {
609
619
 
610
620
  plugin
611
621
  .command("status <pluginName>")
612
- .description("按 agent 目标查看 runtime plugin 运行状态")
622
+ .description("按 agent 目标查看托管 plugin 运行状态")
613
623
  .option("--path <path>", "项目根目录(默认当前目录)", ".")
614
624
  .option("--agent <name>", "agent 名称(从 managed agent registry 解析)")
615
625
  .option("--host <host>", "Server host(覆盖自动解析)")
@@ -617,7 +627,7 @@ export function registerPluginsCommand(program: Command): void {
617
627
  .option("--token <token>", "覆盖 Bearer Token(仅远程 HTTP 调用需要;默认本地走 IPC)")
618
628
  .option("--json [enabled]", "以 JSON 输出", parseBoolean, true)
619
629
  .action(async (pluginName: string, opts: PluginCliBaseOptions) => {
620
- await runPluginRuntimeControlCommand({
630
+ await runManagedPluginControlCommand({
621
631
  pluginName,
622
632
  action: "status",
623
633
  options: opts,
@@ -626,7 +636,7 @@ export function registerPluginsCommand(program: Command): void {
626
636
 
627
637
  plugin
628
638
  .command("start <pluginName>")
629
- .description("按 agent 目标启动 runtime plugin")
639
+ .description("按 agent 目标启动托管 plugin")
630
640
  .option("--path <path>", "项目根目录(默认当前目录)", ".")
631
641
  .option("--agent <name>", "agent 名称(从 managed agent registry 解析)")
632
642
  .option("--host <host>", "Server host(覆盖自动解析)")
@@ -634,7 +644,7 @@ export function registerPluginsCommand(program: Command): void {
634
644
  .option("--token <token>", "覆盖 Bearer Token(仅远程 HTTP 调用需要;默认本地走 IPC)")
635
645
  .option("--json [enabled]", "以 JSON 输出", parseBoolean, true)
636
646
  .action(async (pluginName: string, opts: PluginCliBaseOptions) => {
637
- await runPluginRuntimeControlCommand({
647
+ await runManagedPluginControlCommand({
638
648
  pluginName,
639
649
  action: "start",
640
650
  options: opts,
@@ -643,7 +653,7 @@ export function registerPluginsCommand(program: Command): void {
643
653
 
644
654
  plugin
645
655
  .command("stop <pluginName>")
646
- .description("按 agent 目标停止 runtime plugin")
656
+ .description("按 agent 目标停止托管 plugin")
647
657
  .option("--path <path>", "项目根目录(默认当前目录)", ".")
648
658
  .option("--agent <name>", "agent 名称(从 managed agent registry 解析)")
649
659
  .option("--host <host>", "Server host(覆盖自动解析)")
@@ -651,7 +661,7 @@ export function registerPluginsCommand(program: Command): void {
651
661
  .option("--token <token>", "覆盖 Bearer Token(仅远程 HTTP 调用需要;默认本地走 IPC)")
652
662
  .option("--json [enabled]", "以 JSON 输出", parseBoolean, true)
653
663
  .action(async (pluginName: string, opts: PluginCliBaseOptions) => {
654
- await runPluginRuntimeControlCommand({
664
+ await runManagedPluginControlCommand({
655
665
  pluginName,
656
666
  action: "stop",
657
667
  options: opts,
@@ -660,7 +670,7 @@ export function registerPluginsCommand(program: Command): void {
660
670
 
661
671
  plugin
662
672
  .command("restart <pluginName>")
663
- .description("按 agent 目标重启 runtime plugin")
673
+ .description("按 agent 目标重启托管 plugin")
664
674
  .option("--path <path>", "项目根目录(默认当前目录)", ".")
665
675
  .option("--agent <name>", "agent 名称(从 managed agent registry 解析)")
666
676
  .option("--host <host>", "Server host(覆盖自动解析)")
@@ -668,7 +678,7 @@ export function registerPluginsCommand(program: Command): void {
668
678
  .option("--token <token>", "覆盖 Bearer Token(仅远程 HTTP 调用需要;默认本地走 IPC)")
669
679
  .option("--json [enabled]", "以 JSON 输出", parseBoolean, true)
670
680
  .action(async (pluginName: string, opts: PluginCliBaseOptions) => {
671
- await runPluginRuntimeControlCommand({
681
+ await runManagedPluginControlCommand({
672
682
  pluginName,
673
683
  action: "restart",
674
684
  options: opts,
@@ -677,7 +687,7 @@ export function registerPluginsCommand(program: Command): void {
677
687
 
678
688
  plugin
679
689
  .command("command <pluginName> <command>")
680
- .description("按 agent 目标转发 runtime plugin command")
690
+ .description("按 agent 目标转发托管 plugin command")
681
691
  .option("--payload <json>", "可选 payload(JSON 字符串或普通字符串)")
682
692
  .option("--path <path>", "项目根目录(默认当前目录)", ".")
683
693
  .option("--agent <name>", "agent 名称(从 managed agent registry 解析)")
@@ -690,7 +700,7 @@ export function registerPluginsCommand(program: Command): void {
690
700
  command: string,
691
701
  opts: PluginCliBaseOptions & { payload?: string },
692
702
  ) => {
693
- await runPluginRuntimeCommandBridge({
703
+ await runManagedPluginCommandBridge({
694
704
  pluginName,
695
705
  command,
696
706
  payloadRaw: opts.payload,
@@ -23,7 +23,7 @@ export function buildRuntimePortFacts(): Array<{
23
23
  },
24
24
  {
25
25
  label: "Usage",
26
- value: "Runtime API / plugin endpoints (health, runtime plugin, task, extension plugin)",
26
+ value: "Runtime API / plugin endpoints (health, plugin runtime, task, extension plugin)",
27
27
  },
28
28
  ];
29
29
  }
@@ -120,11 +120,11 @@ export const DOWNCITY_JSON_SCHEMA: JsonObject = {
120
120
  },
121
121
  },
122
122
  },
123
- services: {
123
+ plugins: {
124
124
  type: "object",
125
125
  additionalProperties: true,
126
126
  properties: {
127
- skills: {
127
+ skill: {
128
128
  type: "object",
129
129
  additionalProperties: true,
130
130
  properties: {
@@ -187,12 +187,6 @@ export const DOWNCITY_JSON_SCHEMA: JsonObject = {
187
187
  },
188
188
  },
189
189
  },
190
- },
191
- },
192
- plugins: {
193
- type: "object",
194
- additionalProperties: true,
195
- properties: {
196
190
  asr: {
197
191
  type: "object",
198
192
  additionalProperties: true,
@@ -111,7 +111,7 @@ export function getDowncityMemoryDailyPath(cwd: string, date: string): string {
111
111
  }
112
112
 
113
113
  /**
114
- * Service Schedule JSONL 路径。
114
+ * Plugin Schedule JSONL 路径。
115
115
  *
116
116
  * 关键点(中文)
117
117
  * - 调度任务属于项目 runtime 本地状态,因此放在项目 `.downcity/` 下。
@@ -226,7 +226,7 @@ export function getDowncityDebugDirPath(cwd: string): string {
226
226
  }
227
227
 
228
228
  /**
229
- * Chat 元信息目录(由 services/chat 维护)。
229
+ * Chat 元信息目录(由 chat plugin runtime 维护)。
230
230
  *
231
231
  * 关键点(中文)
232
232
  * - 该目录存放 `sessionId -> chat` 的最近映射快照
@@ -19,7 +19,7 @@ type AgentStatusPayload = {
19
19
  reason?: string;
20
20
  };
21
21
 
22
- type PluginRuntimeListResponse = {
22
+ type PluginStateListResponse = {
23
23
  success?: boolean;
24
24
  plugins?: Array<{
25
25
  name?: unknown;
@@ -94,10 +94,10 @@ async function probeSelectedAgentStatus(
94
94
  };
95
95
  }
96
96
 
97
- let pluginsPayload: PluginRuntimeListResponse;
97
+ let pluginsPayload: PluginStateListResponse;
98
98
  try {
99
- pluginsPayload = await fetchStatusJson<PluginRuntimeListResponse>(
100
- new URL("/api/plugins/runtime/list", baseUrl).toString(),
99
+ pluginsPayload = await fetchStatusJson<PluginStateListResponse>(
100
+ new URL("/api/plugins/list", baseUrl).toString(),
101
101
  );
102
102
  } catch (error) {
103
103
  return {
@@ -152,7 +152,7 @@ async function probeSelectedAgentStatus(
152
152
 
153
153
  try {
154
154
  await fetchStatusJson<ChatStatusResponse>(
155
- new URL("/api/plugins/runtime/command", baseUrl).toString(),
155
+ new URL("/api/plugins/command", baseUrl).toString(),
156
156
  {
157
157
  method: "POST",
158
158
  headers: {
@@ -7,19 +7,18 @@
7
7
  */
8
8
 
9
9
  import type { Hono } from "hono";
10
- import { ChatChannelAccountService } from "@downcity/agent";
11
- import { createAgentPlatformRuntime } from "@/process/registry/AgentHostRuntime.js";
10
+ import { ChatChannelAccountManager } from "@downcity/plugins";
12
11
 
13
12
  /**
14
13
  * 注册 Channel Account API 路由。
15
14
  */
16
15
  export function registerPlatformChannelAccountRoutes(params: { app: Hono }): void {
17
16
  const app = params.app;
18
- const service = new ChatChannelAccountService(createAgentPlatformRuntime());
17
+ const manager = new ChatChannelAccountManager();
19
18
 
20
19
  app.get("/api/ui/channel-accounts", async (c) => {
21
20
  try {
22
- const payload = await service.list();
21
+ const payload = await manager.list();
23
22
  return c.json({
24
23
  success: true,
25
24
  ...payload,
@@ -47,7 +46,7 @@ export function registerPlatformChannelAccountRoutes(params: { app: Hono }): voi
47
46
  clearAppId?: boolean;
48
47
  clearAppSecret?: boolean;
49
48
  };
50
- const payload = await service.upsert({
49
+ const payload = await manager.upsert({
51
50
  id: String(body.id || "").trim(),
52
51
  channel: String(body.channel || "").trim(),
53
52
  name: String(body.name || "").trim(),
@@ -82,7 +81,7 @@ export function registerPlatformChannelAccountRoutes(params: { app: Hono }): voi
82
81
  domain?: string;
83
82
  sandbox?: boolean;
84
83
  };
85
- const payload = await service.probe({
84
+ const payload = await manager.probe({
86
85
  channel: String(body.channel || "").trim(),
87
86
  botToken: body.botToken,
88
87
  appId: body.appId,
@@ -108,7 +107,7 @@ export function registerPlatformChannelAccountRoutes(params: { app: Hono }): voi
108
107
  if (!id) {
109
108
  return c.json({ success: false, error: "Missing id" }, 400);
110
109
  }
111
- await service.remove(id);
110
+ await manager.remove(id);
112
111
  return c.json({
113
112
  success: true,
114
113
  id,
@@ -40,6 +40,7 @@ import {
40
40
  buildPlatformUpstreamUrl,
41
41
  forwardPlatformRequest,
42
42
  } from "@/control/gateway/Proxy.js";
43
+ import { listPluginAuthPolicies } from "@downcity/agent";
43
44
  import type {
44
45
  PlatformAgentOption,
45
46
  PlatformAgentsResponse,
@@ -49,7 +50,7 @@ import type {
49
50
  PlatformLocalModelsResponse,
50
51
  } from "@downcity/agent";
51
52
  import type { AgentProjectInitializationResult } from "@downcity/agent";
52
- import { listBuiltinPluginRuntimeAuthPolicies } from "@downcity/agent";
53
+ import { createBuiltinPlugins } from "@downcity/plugins";
53
54
  import { AuthService } from "@/http/auth/AuthService.js";
54
55
  import { registerAuthRoutes } from "@/http/auth/AuthRoutes.js";
55
56
  import {
@@ -120,7 +121,7 @@ export class ControlGateway {
120
121
  this.authService,
121
122
  [
122
123
  ...CONTROL_PLANE_AUTH_ROUTE_POLICIES,
123
- ...listBuiltinPluginRuntimeAuthPolicies(),
124
+ ...listPluginAuthPolicies(createBuiltinPlugins()),
124
125
  ],
125
126
  ),
126
127
  );
@@ -9,15 +9,17 @@
9
9
 
10
10
  import type { Hono } from "hono";
11
11
  import {
12
- findBuiltinPlugin,
13
- listStaticPluginViews,
12
+ findPluginByName,
13
+ listPluginViews,
14
14
  runLocalPluginAction,
15
15
  } from "@downcity/agent";
16
+ import { createBuiltinPlugins } from "@downcity/plugins";
16
17
  import type { PlatformAgentOption } from "@downcity/agent";
17
18
  import type {
18
19
  PluginActionResult,
19
20
  PluginAction,
20
21
  PluginAvailability,
22
+ Plugin,
21
23
  PluginSetupDefinition,
22
24
  PluginUsageDefinition,
23
25
  PluginView,
@@ -75,8 +77,12 @@ function getErrorMessage(error: unknown): string {
75
77
  return String(error);
76
78
  }
77
79
 
80
+ function createPluginCatalog() {
81
+ return createBuiltinPlugins();
82
+ }
83
+
78
84
  function buildPluginActionConfig(
79
- plugin: ReturnType<typeof findBuiltinPlugin>,
85
+ plugin: Plugin | null,
80
86
  ): PluginActionConfigItem[] {
81
87
  if (!plugin) return [];
82
88
  const actions = (plugin.actions || {}) as Record<string, PluginAction>;
@@ -94,19 +100,19 @@ function buildPluginConfigMap(): Map<string, {
94
100
  setup?: PluginSetupDefinition;
95
101
  usage?: PluginUsageDefinition;
96
102
  }> {
103
+ const plugins = createPluginCatalog();
97
104
  return new Map(
98
- listStaticPluginViews().map((view) => [
99
- view.name,
100
- {
101
- actions: buildPluginActionConfig(findBuiltinPlugin(view.name)),
102
- ...(findBuiltinPlugin(view.name)?.setup
103
- ? { setup: findBuiltinPlugin(view.name)?.setup }
104
- : {}),
105
- ...(findBuiltinPlugin(view.name)?.usage
106
- ? { usage: findBuiltinPlugin(view.name)?.usage }
107
- : {}),
108
- },
109
- ] as const),
105
+ listPluginViews(plugins).map((view) => {
106
+ const plugin = findPluginByName(plugins, view.name);
107
+ return [
108
+ view.name,
109
+ {
110
+ actions: buildPluginActionConfig(plugin),
111
+ ...(plugin?.setup ? { setup: plugin.setup } : {}),
112
+ ...(plugin?.usage ? { usage: plugin.usage } : {}),
113
+ },
114
+ ] as const;
115
+ }),
110
116
  );
111
117
  }
112
118
 
@@ -114,16 +120,18 @@ function buildGlobalPluginConfigMap(): Map<string, {
114
120
  actions: PluginActionConfigItem[];
115
121
  setup?: PluginSetupDefinition;
116
122
  }> {
123
+ const plugins = createPluginCatalog();
117
124
  return new Map(
118
- listStaticPluginViews().map((view) => [
119
- view.name,
120
- {
121
- actions: buildPluginActionConfig(findBuiltinPlugin(view.name)),
122
- ...(findBuiltinPlugin(view.name)?.setup
123
- ? { setup: findBuiltinPlugin(view.name)?.setup }
124
- : {}),
125
- },
126
- ] as const),
125
+ listPluginViews(plugins).map((view) => {
126
+ const plugin = findPluginByName(plugins, view.name);
127
+ return [
128
+ view.name,
129
+ {
130
+ actions: buildPluginActionConfig(plugin),
131
+ ...(plugin?.setup ? { setup: plugin.setup } : {}),
132
+ },
133
+ ] as const;
134
+ }),
127
135
  );
128
136
  }
129
137
 
@@ -132,7 +140,7 @@ function buildGlobalPluginPayload(): PluginUiResponse {
132
140
  return {
133
141
  success: true,
134
142
  runtimeConnected: false,
135
- plugins: listStaticPluginViews().map((view) => ({
143
+ plugins: listPluginViews(createPluginCatalog()).map((view) => ({
136
144
  ...view,
137
145
  availability: {
138
146
  enabled: isCityPluginEnabled(view.name),
@@ -157,7 +165,7 @@ function buildAgentPluginPayload(params?: {
157
165
  success: true,
158
166
  runtimeConnected: params?.runtimeConnected === true,
159
167
  ...(reason ? { runtimeError: reason } : {}),
160
- plugins: listStaticPluginViews().map((view) => ({
168
+ plugins: listPluginViews(createPluginCatalog()).map((view) => ({
161
169
  ...view,
162
170
  availability: {
163
171
  enabled: isCityPluginEnabled(view.name),
@@ -213,7 +221,7 @@ async function loadPluginViews(
213
221
  baseUrl: string,
214
222
  authHeaders?: RuntimeForwardAuthHeaders,
215
223
  ): Promise<PluginView[]> {
216
- const listUrl = new URL("/api/plugins/list", baseUrl).toString();
224
+ const listUrl = new URL("/api/plugins/catalog", baseUrl).toString();
217
225
  const payload = await fetchJson<PluginListResponse>(listUrl, {
218
226
  headers: buildRuntimeRequestHeaders({ authHeaders }),
219
227
  });
@@ -221,7 +229,7 @@ async function loadPluginViews(
221
229
  return plugins.sort((a, b) => a.name.localeCompare(b.name));
222
230
  }
223
231
 
224
- async function loadRuntimePluginAvailability(
232
+ async function loadAgentPluginAvailability(
225
233
  baseUrl: string,
226
234
  pluginName: string,
227
235
  authHeaders?: RuntimeForwardAuthHeaders,
@@ -245,7 +253,7 @@ async function loadRuntimePluginAvailability(
245
253
  return payload.availability;
246
254
  }
247
255
 
248
- async function buildRuntimePluginPayload(
256
+ async function buildAgentPluginPayloadFromRuntime(
249
257
  selectedAgent: PlatformAgentOption,
250
258
  authHeaders?: RuntimeForwardAuthHeaders,
251
259
  ): Promise<PluginUiResponse> {
@@ -256,7 +264,7 @@ async function buildRuntimePluginPayload(
256
264
  pluginViews.map(async (view) => {
257
265
  return {
258
266
  ...view,
259
- availability: await loadRuntimePluginAvailability(
267
+ availability: await loadAgentPluginAvailability(
260
268
  baseUrl,
261
269
  view.name,
262
270
  authHeaders,
@@ -282,7 +290,8 @@ async function runGlobalPluginAction(input: {
282
290
  }): Promise<PluginActionResult<JsonValue>> {
283
291
  const pluginName = String(input.pluginName || "").trim();
284
292
  const actionName = String(input.actionName || "").trim();
285
- const plugin = findBuiltinPlugin(pluginName);
293
+ const plugins = createPluginCatalog();
294
+ const plugin = findPluginByName(plugins, pluginName);
286
295
  if (!plugin) {
287
296
  return {
288
297
  success: false,
@@ -320,6 +329,7 @@ async function runGlobalPluginAction(input: {
320
329
  }
321
330
 
322
331
  return runLocalPluginAction({
332
+ plugins,
323
333
  projectRoot,
324
334
  pluginName: plugin.name,
325
335
  actionName,
@@ -367,7 +377,7 @@ export function registerPlatformPluginRoutes(params: {
367
377
 
368
378
  try {
369
379
  return c.json(
370
- await buildRuntimePluginPayload(
380
+ await buildAgentPluginPayloadFromRuntime(
371
381
  selectedAgent,
372
382
  readRuntimeForwardAuthHeaders(c.req.raw),
373
383
  ),
@@ -18,7 +18,6 @@ import {
18
18
  } from "@/process/daemon/Manager.js";
19
19
  import { buildRunArgsFromOptions } from "@/process/daemon/CliArgs.js";
20
20
  import {
21
- ensureRuntimeExecutionBindingReady,
22
21
  initializeAgentProject,
23
22
  isAgentProjectInitialized,
24
23
  } from "@downcity/agent";
@@ -33,7 +32,10 @@ import type { AgentProjectInitializationResult } from "@downcity/agent";
33
32
  import type {
34
33
  ExecutionBindingConfig,
35
34
  } from "@downcity/agent";
36
- import { createAgentPlatformRuntime } from "@/process/registry/AgentHostRuntime.js";
35
+ import {
36
+ assertPlatformModelReady,
37
+ assertProjectExecutionModelReady,
38
+ } from "@/model/runtime/ExecutionModelBinding.js";
37
39
 
38
40
  function resolveExecutionInput(params: {
39
41
  modelId?: unknown;
@@ -70,16 +72,17 @@ export async function initializePlatformAgentProject(params: {
70
72
  modelId?: unknown;
71
73
  forceOverwriteShipJson?: unknown;
72
74
  }): Promise<AgentProjectInitializationResult> {
75
+ const execution = resolveExecutionInput({
76
+ modelId: params.modelId,
77
+ });
78
+ assertPlatformModelReady(execution.modelId);
73
79
  return initializeAgentProject(
74
80
  {
75
81
  projectRoot: params.projectRoot,
76
82
  agentName: String(params.agentName || "").trim() || undefined,
77
- execution: resolveExecutionInput({
78
- modelId: params.modelId,
79
- }),
83
+ execution,
80
84
  forceOverwriteShipJson: params.forceOverwriteShipJson === true,
81
85
  },
82
- createAgentPlatformRuntime(),
83
86
  );
84
87
  }
85
88
 
@@ -103,6 +106,7 @@ export async function updatePlatformAgentExecution(params: {
103
106
  if (!modelId) {
104
107
  throw new Error("modelId is required");
105
108
  }
109
+ assertPlatformModelReady(modelId);
106
110
  ship.execution = {
107
111
  type: "api",
108
112
  modelId,
@@ -270,16 +274,17 @@ export async function startManagedAgentByProjectRoot(params: {
270
274
  `Project not ready: ${normalizedRoot}. Required files: PROFILE.md and downcity.json`,
271
275
  );
272
276
  }
277
+ const execution = resolveExecutionInput({
278
+ modelId: params.initialization?.modelId,
279
+ });
280
+ assertPlatformModelReady(execution.modelId);
273
281
  await initializeAgentProject(
274
282
  {
275
283
  projectRoot: normalizedRoot,
276
284
  agentName: String(params.initialization?.agentName || "").trim() || undefined,
277
- execution: resolveExecutionInput({
278
- modelId: params.initialization?.modelId,
279
- }),
285
+ execution,
280
286
  forceOverwriteShipJson: params.initialization?.forceOverwriteShipJson === true,
281
287
  },
282
- createAgentPlatformRuntime(),
283
288
  );
284
289
  } else {
285
290
  const profilePath = getProfileMdPath(normalizedRoot);
@@ -291,7 +296,7 @@ export async function startManagedAgentByProjectRoot(params: {
291
296
  }
292
297
  }
293
298
 
294
- ensureRuntimeExecutionBindingReady(normalizedRoot, createAgentPlatformRuntime());
299
+ assertProjectExecutionModelReady(normalizedRoot);
295
300
  const args = await buildRunArgsFromOptions(normalizedRoot, {});
296
301
  const started = await startDaemonProcess({
297
302
  projectRoot: normalizedRoot,
@@ -119,7 +119,7 @@ async function resolveAgentChatProfiles(params: {
119
119
  statusText?: string;
120
120
  }>> {
121
121
  try {
122
- const upstreamUrl = new URL("/api/plugins/runtime/command", params.baseUrl).toString();
122
+ const upstreamUrl = new URL("/api/plugins/command", params.baseUrl).toString();
123
123
  const response = await fetch(upstreamUrl, {
124
124
  method: "POST",
125
125
  headers: {