@downcity/city 1.1.29 → 1.1.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -11
- package/bin/cli/Index.js +3 -3
- package/bin/cli/Index.js.map +1 -1
- package/bin/cli/agent/AgentChat.js +1 -1
- package/bin/cli/agent/AgentChat.js.map +1 -1
- package/bin/cli/agent/AgentManager.js +3 -3
- package/bin/cli/agent/AgentManager.js.map +1 -1
- package/bin/cli/agent/Init.js +6 -6
- package/bin/cli/agent/Init.js.map +1 -1
- package/bin/cli/agent/Restart.js +1 -1
- package/bin/cli/agent/Restart.js.map +1 -1
- package/bin/cli/agent/Run.d.ts.map +1 -1
- package/bin/cli/agent/Run.js +6 -7
- package/bin/cli/agent/Run.js.map +1 -1
- package/bin/cli/agent/Start.js +1 -1
- package/bin/cli/agent/Start.js.map +1 -1
- package/bin/cli/model/ModelSupport.d.ts +1 -1
- package/bin/cli/model/ModelSupport.d.ts.map +1 -1
- package/bin/cli/model/ModelSupport.js +1 -1
- package/bin/cli/model/ModelSupport.js.map +1 -1
- package/bin/cli/shared/Chat.d.ts +1 -1
- package/bin/cli/shared/Chat.js +1 -1
- package/bin/cli/shared/ChatManager.d.ts +1 -1
- package/bin/cli/shared/ChatManager.js +20 -20
- package/bin/cli/shared/ChatManager.js.map +1 -1
- package/bin/cli/shared/Config.js +1 -1
- package/bin/cli/shared/Config.js.map +1 -1
- package/bin/cli/shared/ManagedPluginActionCommands.d.ts +14 -0
- package/bin/cli/shared/ManagedPluginActionCommands.d.ts.map +1 -0
- package/bin/cli/shared/{PluginRuntimeActionCommands.js → ManagedPluginActionCommands.js} +11 -11
- package/bin/cli/shared/{PluginRuntimeActionCommands.js.map → ManagedPluginActionCommands.js.map} +1 -1
- package/bin/cli/shared/{PluginRuntimeRemote.d.ts → ManagedPluginRemote.d.ts} +6 -6
- package/bin/cli/shared/{PluginRuntimeRemote.d.ts.map → ManagedPluginRemote.d.ts.map} +1 -1
- package/bin/cli/shared/{PluginRuntimeRemote.js → ManagedPluginRemote.js} +14 -14
- package/bin/cli/shared/ManagedPluginRemote.js.map +1 -0
- package/bin/cli/shared/PluginScheduleCommand.js +1 -1
- package/bin/cli/shared/PluginScheduleCommand.js.map +1 -1
- package/bin/cli/shared/{PluginRuntimeSupport.d.ts → PluginTargetSupport.d.ts} +3 -3
- package/bin/cli/shared/PluginTargetSupport.d.ts.map +1 -0
- package/bin/cli/shared/{PluginRuntimeSupport.js → PluginTargetSupport.js} +3 -3
- package/bin/cli/shared/PluginTargetSupport.js.map +1 -0
- package/bin/cli/shared/Plugins.d.ts.map +1 -1
- package/bin/cli/shared/Plugins.js +23 -20
- package/bin/cli/shared/Plugins.js.map +1 -1
- package/bin/cli/shared/PortHints.js +1 -1
- package/bin/config/DowncitySchema.d.ts.map +1 -1
- package/bin/config/DowncitySchema.js +2 -8
- package/bin/config/DowncitySchema.js.map +1 -1
- package/bin/config/Paths.d.ts +2 -2
- package/bin/config/Paths.js +2 -2
- package/bin/control/AgentStatusApiRoutes.js +2 -2
- package/bin/control/AgentStatusApiRoutes.js.map +1 -1
- package/bin/control/ChannelAccountApiRoutes.js +6 -6
- package/bin/control/ControlGateway.js +2 -2
- package/bin/control/ControlGateway.js.map +1 -1
- package/bin/control/PluginApiRoutes.js +5 -5
- package/bin/control/PluginApiRoutes.js.map +1 -1
- package/bin/control/gateway/AgentCatalog.js +1 -1
- package/bin/control/gateway/AgentCatalog.js.map +1 -1
- package/bin/control/instant/InstantApiRoutes.d.ts +3 -3
- package/bin/control/instant/InstantApiRoutes.d.ts.map +1 -1
- package/bin/control/instant/InstantApiRoutes.js +5 -5
- package/bin/control/instant/InstantApiRoutes.js.map +1 -1
- package/bin/control/instant/{InstantSessionService.d.ts → InstantSessionRunner.d.ts} +7 -7
- package/bin/control/instant/InstantSessionRunner.d.ts.map +1 -0
- package/bin/control/instant/{InstantSessionService.js → InstantSessionRunner.js} +4 -4
- package/bin/control/instant/InstantSessionRunner.js.map +1 -0
- package/bin/http/auth/RoutePolicy.js +4 -4
- package/bin/http/auth/RoutePolicy.js.map +1 -1
- package/bin/process/daemon/Api.d.ts +2 -2
- package/bin/process/daemon/Api.js +1 -1
- package/bin/process/registry/AgentHostRuntime.js +1 -1
- package/package.json +2 -2
- package/src/cli/Index.ts +3 -3
- package/src/cli/agent/AgentChat.ts +1 -1
- package/src/cli/agent/AgentManager.ts +3 -3
- package/src/cli/agent/Init.ts +6 -6
- package/src/cli/agent/Restart.ts +1 -1
- package/src/cli/agent/Run.ts +6 -7
- package/src/cli/agent/Start.ts +1 -1
- package/src/cli/model/ModelSupport.ts +1 -1
- package/src/cli/shared/Chat.ts +1 -1
- package/src/cli/shared/ChatManager.ts +20 -20
- package/src/cli/shared/Config.ts +1 -1
- package/src/cli/shared/{PluginRuntimeActionCommands.ts → ManagedPluginActionCommands.ts} +10 -10
- package/src/cli/shared/{PluginRuntimeRemote.ts → ManagedPluginRemote.ts} +15 -15
- package/src/cli/shared/PluginScheduleCommand.ts +1 -1
- package/src/cli/shared/{PluginRuntimeSupport.ts → PluginTargetSupport.ts} +2 -2
- package/src/cli/shared/Plugins.ts +28 -24
- package/src/cli/shared/PortHints.ts +1 -1
- package/src/config/DowncitySchema.ts +2 -8
- package/src/config/Paths.ts +2 -2
- package/src/control/AgentStatusApiRoutes.ts +5 -5
- package/src/control/ChannelAccountApiRoutes.ts +6 -6
- package/src/control/ControlGateway.ts +2 -2
- package/src/control/PluginApiRoutes.ts +5 -5
- package/src/control/gateway/AgentCatalog.ts +1 -1
- package/src/control/instant/InstantApiRoutes.ts +8 -8
- package/src/control/instant/{InstantSessionService.ts → InstantSessionRunner.ts} +7 -7
- package/src/http/auth/RoutePolicy.ts +4 -4
- package/src/process/daemon/Api.ts +2 -2
- package/src/process/registry/AgentHostRuntime.ts +1 -1
- package/bin/cli/shared/PluginRuntimeActionCommands.d.ts +0 -14
- package/bin/cli/shared/PluginRuntimeActionCommands.d.ts.map +0 -1
- package/bin/cli/shared/PluginRuntimeRemote.js.map +0 -1
- package/bin/cli/shared/PluginRuntimeSupport.d.ts.map +0 -1
- package/bin/cli/shared/PluginRuntimeSupport.js.map +0 -1
- package/bin/control/instant/InstantSessionService.d.ts.map +0 -1
- package/bin/control/instant/InstantSessionService.js.map +0 -1
- package/bin/process/registry/PluginRuntime.d.ts +0 -24
- package/bin/process/registry/PluginRuntime.d.ts.map +0 -1
- package/bin/process/registry/PluginRuntime.js +0 -31
- package/bin/process/registry/PluginRuntime.js.map +0 -1
- package/src/process/registry/PluginRuntime.ts +0 -42
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `city chat` 交互式管理器。
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
|
-
* - 裸 `city chat` 进入 chat
|
|
5
|
+
* - 裸 `city chat` 进入 chat plugin 管理,而不是只输出静态 help。
|
|
6
6
|
* - chat channel account 属于 city 级配置,在这里通过“配置 channel”管理。
|
|
7
7
|
* - agent 只绑定 channel account,不在 agent 流程中维护密钥。
|
|
8
8
|
*/
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
import prompts from "prompts";
|
|
11
11
|
import type { PromptObject } from "prompts";
|
|
12
12
|
import {
|
|
13
|
-
|
|
13
|
+
ChatChannelAccountManager,
|
|
14
14
|
type ChatChannelAccountListItem,
|
|
15
15
|
} from "@downcity/agent";
|
|
16
16
|
import { emitCliBlock, emitCliList } from "./CliReporter.js";
|
|
17
|
-
import {
|
|
17
|
+
import { runManagedPluginControlCommand } from "./ManagedPluginRemote.js";
|
|
18
18
|
import type { StoredChannelAccountChannel } from "@downcity/agent";
|
|
19
19
|
import type {
|
|
20
20
|
ChatChannelAccountAction,
|
|
@@ -25,8 +25,8 @@ import { createAgentPlatformRuntime } from "@/process/registry/AgentHostRuntime.
|
|
|
25
25
|
|
|
26
26
|
const CHAT_CHANNELS: StoredChannelAccountChannel[] = ["telegram", "feishu", "qq"];
|
|
27
27
|
|
|
28
|
-
function
|
|
29
|
-
return new
|
|
28
|
+
function createChannelAccountManager(): ChatChannelAccountManager {
|
|
29
|
+
return new ChatChannelAccountManager(createAgentPlatformRuntime());
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
function isInteractiveTerminal(): boolean {
|
|
@@ -49,8 +49,8 @@ function formatCredentialSummary(account: ChatChannelAccountListItem): string {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
async function promptRootAction(): Promise<ChatManagerRootAction | null> {
|
|
52
|
-
const
|
|
53
|
-
const accounts = await
|
|
52
|
+
const manager = createChannelAccountManager();
|
|
53
|
+
const accounts = await manager.list();
|
|
54
54
|
const response = (await prompts({
|
|
55
55
|
type: "select",
|
|
56
56
|
name: "action",
|
|
@@ -94,8 +94,8 @@ async function promptRootAction(): Promise<ChatManagerRootAction | null> {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
async function promptChannelAccountAction(): Promise<ChatChannelAccountAction | null> {
|
|
97
|
-
const
|
|
98
|
-
const accounts = await
|
|
97
|
+
const manager = createChannelAccountManager();
|
|
98
|
+
const accounts = await manager.list();
|
|
99
99
|
const response = (await prompts({
|
|
100
100
|
type: "select",
|
|
101
101
|
name: "action",
|
|
@@ -139,8 +139,8 @@ async function promptChannelAccountAction(): Promise<ChatChannelAccountAction |
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
async function emitChannelAccountList(): Promise<void> {
|
|
142
|
-
const
|
|
143
|
-
const { items } = await
|
|
142
|
+
const manager = createChannelAccountManager();
|
|
143
|
+
const { items } = await manager.list();
|
|
144
144
|
if (items.length === 0) {
|
|
145
145
|
emitCliBlock({
|
|
146
146
|
tone: "info",
|
|
@@ -182,8 +182,8 @@ async function chooseChannel(): Promise<StoredChannelAccountChannel | null> {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
async function chooseAccount(): Promise<ChatChannelAccountListItem | null> {
|
|
185
|
-
const
|
|
186
|
-
const { items } = await
|
|
185
|
+
const manager = createChannelAccountManager();
|
|
186
|
+
const { items } = await manager.list();
|
|
187
187
|
if (items.length === 0) {
|
|
188
188
|
emitCliBlock({
|
|
189
189
|
tone: "info",
|
|
@@ -296,8 +296,8 @@ async function addChannelAccount(): Promise<void> {
|
|
|
296
296
|
initial: true,
|
|
297
297
|
})) as { probe?: boolean };
|
|
298
298
|
|
|
299
|
-
const
|
|
300
|
-
const result = await
|
|
299
|
+
const manager = createChannelAccountManager();
|
|
300
|
+
const result = await manager.create({
|
|
301
301
|
channel,
|
|
302
302
|
name,
|
|
303
303
|
botToken: input.botToken,
|
|
@@ -324,8 +324,8 @@ async function editChannelAccount(): Promise<void> {
|
|
|
324
324
|
channel: account.channel,
|
|
325
325
|
current: account,
|
|
326
326
|
});
|
|
327
|
-
const
|
|
328
|
-
await
|
|
327
|
+
const manager = createChannelAccountManager();
|
|
328
|
+
await manager.upsert({
|
|
329
329
|
id: account.id,
|
|
330
330
|
channel: account.channel,
|
|
331
331
|
name: String(input.name || account.name).trim(),
|
|
@@ -356,8 +356,8 @@ async function removeChannelAccount(): Promise<void> {
|
|
|
356
356
|
|
|
357
357
|
if (response.remove !== true) return;
|
|
358
358
|
|
|
359
|
-
const
|
|
360
|
-
|
|
359
|
+
const manager = createChannelAccountManager();
|
|
360
|
+
await manager.remove(account.id);
|
|
361
361
|
emitCliBlock({
|
|
362
362
|
tone: "success",
|
|
363
363
|
title: "Channel account removed",
|
|
@@ -403,7 +403,7 @@ async function runChannelAccountManager(): Promise<void> {
|
|
|
403
403
|
async function runChatLifecycleAction(
|
|
404
404
|
action: "start" | "stop" | "restart" | "status",
|
|
405
405
|
): Promise<void> {
|
|
406
|
-
await
|
|
406
|
+
await runManagedPluginControlCommand({
|
|
407
407
|
pluginName: "chat",
|
|
408
408
|
action,
|
|
409
409
|
options: {
|
package/src/cli/shared/Config.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { getDowncityJsonPath } from "@/config/Paths.js";
|
|
|
14
14
|
import { printResult } from "@/utils/cli/CliOutput.js";
|
|
15
15
|
import { aliasCommand } from "./Alias.js";
|
|
16
16
|
import { parseBoolean } from "./IndexSupport.js";
|
|
17
|
-
import { resolveProjectRoot } from "./
|
|
17
|
+
import { resolveProjectRoot } from "./PluginTargetSupport.js";
|
|
18
18
|
import type { DowncityConfig } from "@downcity/agent";
|
|
19
19
|
|
|
20
20
|
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 受 agent 托管的 plugin action CLI 注册器。
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
|
-
* -
|
|
5
|
+
* - 负责把需要运行中 agent 承载的 plugin actions 挂到 commander(`city <plugin> <action>`)。
|
|
6
6
|
* - 仅处理 CLI 参数映射与远程调用,不承载 plugin 状态机逻辑。
|
|
7
|
-
* -
|
|
7
|
+
* - 命令注册表与调度时间解析统一复用 agent 包实现,避免 city 维护第二套事实源。
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import type { Command } from "commander";
|
|
12
12
|
import {
|
|
13
13
|
callAgentTransport,
|
|
14
|
-
|
|
14
|
+
listManagedPlugins,
|
|
15
15
|
parseScheduledRunAtMsOrThrow,
|
|
16
16
|
} from "@downcity/agent";
|
|
17
17
|
import type { BasePlugin, PluginAction } from "@downcity/agent";
|
|
@@ -21,7 +21,7 @@ import type { PluginCommandResponse } from "@downcity/agent";
|
|
|
21
21
|
import type { PluginCliBaseOptions } from "@downcity/agent";
|
|
22
22
|
import { printResult } from "@/utils/cli/CliOutput.js";
|
|
23
23
|
import { parseBoolean, parsePort } from "./IndexSupport.js";
|
|
24
|
-
import {
|
|
24
|
+
import { runManagedPluginControlCommand } from "./ManagedPluginRemote.js";
|
|
25
25
|
|
|
26
26
|
const CHAT_PLUGIN_HELP_TEXT = [
|
|
27
27
|
"",
|
|
@@ -280,7 +280,7 @@ function registerPluginActionCommand(params: {
|
|
|
280
280
|
|
|
281
281
|
const remote = await callAgentTransport<PluginCommandResponse>({
|
|
282
282
|
projectRoot: resolveProjectRoot(bridgeOptions.path),
|
|
283
|
-
path: "/api/plugins/
|
|
283
|
+
path: "/api/plugins/command",
|
|
284
284
|
method: "POST",
|
|
285
285
|
host: bridgeOptions.host,
|
|
286
286
|
port: bridgeOptions.port,
|
|
@@ -383,7 +383,7 @@ function registerPluginLifecycleCommands(params: {
|
|
|
383
383
|
.description(item.description)
|
|
384
384
|
.helpOption("--help", "display help for command"),
|
|
385
385
|
).action(async (options: PluginCliBaseOptions) => {
|
|
386
|
-
await
|
|
386
|
+
await runManagedPluginControlCommand({
|
|
387
387
|
pluginName: params.plugin.name,
|
|
388
388
|
action: item.action,
|
|
389
389
|
options,
|
|
@@ -393,10 +393,10 @@ function registerPluginLifecycleCommands(params: {
|
|
|
393
393
|
}
|
|
394
394
|
|
|
395
395
|
/**
|
|
396
|
-
*
|
|
396
|
+
* 注册所有受 agent 托管的 plugin actions CLI 命令。
|
|
397
397
|
*/
|
|
398
|
-
export function
|
|
399
|
-
const plugins =
|
|
398
|
+
export function registerManagedPluginCommandsForCli(program: Command): void {
|
|
399
|
+
const plugins = listManagedPlugins();
|
|
400
400
|
for (const plugin of plugins) {
|
|
401
401
|
for (const [actionName, action] of Object.entries(plugin.actions)) {
|
|
402
402
|
registerPluginActionCommand({
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `city plugin` 运行态远程 Agent server 调用辅助。
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
|
-
* - 统一处理
|
|
5
|
+
* - 统一处理 list/control/command 三类需要访问 Agent server 的命令。
|
|
6
6
|
* - 这里不负责命令注册,只负责 transport 调用与结果输出。
|
|
7
7
|
*/
|
|
8
8
|
|
|
@@ -13,26 +13,26 @@ import type {
|
|
|
13
13
|
PluginCommandResponse,
|
|
14
14
|
PluginControlAction,
|
|
15
15
|
PluginControlResponse,
|
|
16
|
-
|
|
16
|
+
PluginStateListResponse,
|
|
17
17
|
} from "@downcity/agent";
|
|
18
18
|
import {
|
|
19
19
|
parseCommandPayload,
|
|
20
20
|
resolvePluginProjectRoot,
|
|
21
21
|
validateAgentProjectRoot,
|
|
22
|
-
} from "./
|
|
22
|
+
} from "./PluginTargetSupport.js";
|
|
23
23
|
|
|
24
24
|
const PLUGIN_COMMAND_TIMEOUT_MS = 120_000;
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* 执行 `plugin list
|
|
27
|
+
* 执行 `plugin list`。
|
|
28
28
|
*/
|
|
29
|
-
export async function
|
|
29
|
+
export async function runManagedPluginListCommand(options: PluginCliBaseOptions): Promise<void> {
|
|
30
30
|
const resolved = await resolvePluginProjectRoot(options);
|
|
31
31
|
if (!resolved.projectRoot) {
|
|
32
32
|
printResult({
|
|
33
33
|
asJson: options.json,
|
|
34
34
|
success: false,
|
|
35
|
-
title: "plugin
|
|
35
|
+
title: "plugin list failed",
|
|
36
36
|
payload: {
|
|
37
37
|
error: resolved.error || "Failed to resolve agent project path",
|
|
38
38
|
},
|
|
@@ -45,16 +45,16 @@ export async function runPluginRuntimeListCommand(options: PluginCliBaseOptions)
|
|
|
45
45
|
printResult({
|
|
46
46
|
asJson: options.json,
|
|
47
47
|
success: false,
|
|
48
|
-
title: "plugin
|
|
48
|
+
title: "plugin list failed",
|
|
49
49
|
payload: {
|
|
50
50
|
error: pathError,
|
|
51
51
|
},
|
|
52
52
|
});
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
|
-
const remote = await callAgentTransport<
|
|
55
|
+
const remote = await callAgentTransport<PluginStateListResponse>({
|
|
56
56
|
projectRoot,
|
|
57
|
-
path: "/api/plugins/
|
|
57
|
+
path: "/api/plugins/list",
|
|
58
58
|
method: "GET",
|
|
59
59
|
host: options.host,
|
|
60
60
|
port: options.port,
|
|
@@ -65,7 +65,7 @@ export async function runPluginRuntimeListCommand(options: PluginCliBaseOptions)
|
|
|
65
65
|
printResult({
|
|
66
66
|
asJson: options.json,
|
|
67
67
|
success: Boolean(remote.data.success),
|
|
68
|
-
title: remote.data.success ? "plugin
|
|
68
|
+
title: remote.data.success ? "plugin listed" : "plugin list failed",
|
|
69
69
|
payload: {
|
|
70
70
|
...(Array.isArray(remote.data.plugins) ? { plugins: remote.data.plugins } : {}),
|
|
71
71
|
...(remote.data.error ? { error: remote.data.error } : {}),
|
|
@@ -77,7 +77,7 @@ export async function runPluginRuntimeListCommand(options: PluginCliBaseOptions)
|
|
|
77
77
|
printResult({
|
|
78
78
|
asJson: options.json,
|
|
79
79
|
success: false,
|
|
80
|
-
title: "plugin
|
|
80
|
+
title: "plugin list failed",
|
|
81
81
|
payload: {
|
|
82
82
|
error: remote.error || "Unknown error",
|
|
83
83
|
},
|
|
@@ -87,7 +87,7 @@ export async function runPluginRuntimeListCommand(options: PluginCliBaseOptions)
|
|
|
87
87
|
/**
|
|
88
88
|
* 执行 `plugin status/start/stop/restart`。
|
|
89
89
|
*/
|
|
90
|
-
export async function
|
|
90
|
+
export async function runManagedPluginControlCommand(params: {
|
|
91
91
|
pluginName: string;
|
|
92
92
|
action: PluginControlAction;
|
|
93
93
|
options: PluginCliBaseOptions;
|
|
@@ -119,7 +119,7 @@ export async function runPluginRuntimeControlCommand(params: {
|
|
|
119
119
|
}
|
|
120
120
|
const remote = await callAgentTransport<PluginControlResponse>({
|
|
121
121
|
projectRoot,
|
|
122
|
-
path: "/api/plugins/
|
|
122
|
+
path: "/api/plugins/control",
|
|
123
123
|
method: "POST",
|
|
124
124
|
host: params.options.host,
|
|
125
125
|
port: params.options.port,
|
|
@@ -156,7 +156,7 @@ export async function runPluginRuntimeControlCommand(params: {
|
|
|
156
156
|
/**
|
|
157
157
|
* 执行 `plugin command` 桥接。
|
|
158
158
|
*/
|
|
159
|
-
export async function
|
|
159
|
+
export async function runManagedPluginCommandBridge(params: {
|
|
160
160
|
pluginName: string;
|
|
161
161
|
command: string;
|
|
162
162
|
payloadRaw?: string;
|
|
@@ -189,7 +189,7 @@ export async function runPluginRuntimeCommandBridge(params: {
|
|
|
189
189
|
}
|
|
190
190
|
const remote = await callAgentTransport<PluginCommandResponse>({
|
|
191
191
|
projectRoot,
|
|
192
|
-
path: "/api/plugins/
|
|
192
|
+
path: "/api/plugins/command",
|
|
193
193
|
method: "POST",
|
|
194
194
|
timeoutMs: PLUGIN_COMMAND_TIMEOUT_MS,
|
|
195
195
|
host: params.options.host,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `city plugin` 运行态命令共享辅助 + Agent 预检。
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
|
-
* - 统一承载 runtime
|
|
5
|
+
* - 统一承载 plugin runtime 命令的参数解析、目标 agent 路径解析与项目目录校验。
|
|
6
6
|
* - 提供 `checkAgentPreflight` 供 start/restart/status 等命令统一使用。
|
|
7
7
|
* - 保持 command 注册层只关注命令树,不再直接承载路径解析细节。
|
|
8
8
|
*/
|
|
@@ -164,7 +164,7 @@ export async function resolveProjectRootByAgentName(agentName: string): Promise<
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
/**
|
|
167
|
-
* 统一解析 runtime
|
|
167
|
+
* 统一解析 plugin runtime 命令目标路径(agent 优先于 path)。
|
|
168
168
|
*/
|
|
169
169
|
export async function resolvePluginProjectRoot(options: PluginCliBaseOptions): Promise<{
|
|
170
170
|
projectRoot?: string;
|
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
buildStaticPluginAvailability,
|
|
16
16
|
findBuiltinPlugin,
|
|
17
17
|
findStaticPluginView,
|
|
18
|
-
|
|
18
|
+
listLocalPlugins,
|
|
19
|
+
listManagedPlugins,
|
|
19
20
|
listStaticPluginViews,
|
|
20
21
|
runLocalPluginAction,
|
|
21
22
|
} from "@downcity/agent";
|
|
@@ -25,18 +26,18 @@ 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 "./
|
|
29
|
+
import { resolveProjectRoot } from "./PluginTargetSupport.js";
|
|
29
30
|
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} from "./
|
|
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: "
|
|
40
|
+
kind: "managed" | "local";
|
|
40
41
|
enabled: boolean;
|
|
41
42
|
available: boolean;
|
|
42
43
|
actionCount: number;
|
|
@@ -122,7 +123,7 @@ function truncateCell(input: string, width: number): string {
|
|
|
122
123
|
function renderPluginCatalogTable(rows: Array<{
|
|
123
124
|
name: string;
|
|
124
125
|
title: string;
|
|
125
|
-
kind: "
|
|
126
|
+
kind: "managed" | "local";
|
|
126
127
|
enabled: boolean;
|
|
127
128
|
available: boolean;
|
|
128
129
|
actionCount: number;
|
|
@@ -166,24 +167,27 @@ function renderPluginCatalogTable(rows: Array<{
|
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
function listStaticCatalogEntries(): StaticCatalogEntry[] {
|
|
169
|
-
const
|
|
170
|
+
const managedEntries = listManagedPlugins().map((plugin) => ({
|
|
170
171
|
name: plugin.name,
|
|
171
|
-
title:
|
|
172
|
-
kind: "
|
|
172
|
+
title: String(plugin.title || plugin.name || "").trim() || plugin.name,
|
|
173
|
+
kind: "managed" as const,
|
|
173
174
|
enabled: true,
|
|
174
175
|
available: true,
|
|
175
176
|
actionCount: Object.keys(plugin.actions || {}).length,
|
|
176
177
|
actions: Object.keys(plugin.actions || {}).sort((left, right) => left.localeCompare(right)),
|
|
177
178
|
hasSystem: typeof plugin.system === "function",
|
|
178
|
-
note: "
|
|
179
|
+
note: "Managed plugin. Use `city plugin start/stop/restart/status` with an agent target for live state.",
|
|
179
180
|
}));
|
|
180
181
|
|
|
181
|
-
const
|
|
182
|
+
const localNames = new Set(listLocalPlugins().map((plugin) => plugin.name));
|
|
183
|
+
const localEntries = listStaticPluginViews()
|
|
184
|
+
.filter((plugin) => localNames.has(plugin.name))
|
|
185
|
+
.map((plugin) => {
|
|
182
186
|
const availability = buildSafeStaticPluginAvailability(plugin.name);
|
|
183
187
|
return {
|
|
184
188
|
name: plugin.name,
|
|
185
189
|
title: plugin.title,
|
|
186
|
-
kind: "
|
|
190
|
+
kind: "local" as const,
|
|
187
191
|
enabled: availability.enabled,
|
|
188
192
|
available: availability.available,
|
|
189
193
|
actionCount: plugin.actions.length,
|
|
@@ -193,7 +197,7 @@ function listStaticCatalogEntries(): StaticCatalogEntry[] {
|
|
|
193
197
|
};
|
|
194
198
|
});
|
|
195
199
|
|
|
196
|
-
const merged = [...
|
|
200
|
+
const merged = [...managedEntries, ...localEntries];
|
|
197
201
|
const unique = new Map<string, StaticCatalogEntry>();
|
|
198
202
|
for (const entry of merged) {
|
|
199
203
|
if (!unique.has(entry.name)) {
|
|
@@ -609,7 +613,7 @@ export function registerPluginsCommand(program: Command): void {
|
|
|
609
613
|
|
|
610
614
|
plugin
|
|
611
615
|
.command("status <pluginName>")
|
|
612
|
-
.description("按 agent
|
|
616
|
+
.description("按 agent 目标查看托管 plugin 运行状态")
|
|
613
617
|
.option("--path <path>", "项目根目录(默认当前目录)", ".")
|
|
614
618
|
.option("--agent <name>", "agent 名称(从 managed agent registry 解析)")
|
|
615
619
|
.option("--host <host>", "Server host(覆盖自动解析)")
|
|
@@ -617,7 +621,7 @@ export function registerPluginsCommand(program: Command): void {
|
|
|
617
621
|
.option("--token <token>", "覆盖 Bearer Token(仅远程 HTTP 调用需要;默认本地走 IPC)")
|
|
618
622
|
.option("--json [enabled]", "以 JSON 输出", parseBoolean, true)
|
|
619
623
|
.action(async (pluginName: string, opts: PluginCliBaseOptions) => {
|
|
620
|
-
await
|
|
624
|
+
await runManagedPluginControlCommand({
|
|
621
625
|
pluginName,
|
|
622
626
|
action: "status",
|
|
623
627
|
options: opts,
|
|
@@ -626,7 +630,7 @@ export function registerPluginsCommand(program: Command): void {
|
|
|
626
630
|
|
|
627
631
|
plugin
|
|
628
632
|
.command("start <pluginName>")
|
|
629
|
-
.description("按 agent
|
|
633
|
+
.description("按 agent 目标启动托管 plugin")
|
|
630
634
|
.option("--path <path>", "项目根目录(默认当前目录)", ".")
|
|
631
635
|
.option("--agent <name>", "agent 名称(从 managed agent registry 解析)")
|
|
632
636
|
.option("--host <host>", "Server host(覆盖自动解析)")
|
|
@@ -634,7 +638,7 @@ export function registerPluginsCommand(program: Command): void {
|
|
|
634
638
|
.option("--token <token>", "覆盖 Bearer Token(仅远程 HTTP 调用需要;默认本地走 IPC)")
|
|
635
639
|
.option("--json [enabled]", "以 JSON 输出", parseBoolean, true)
|
|
636
640
|
.action(async (pluginName: string, opts: PluginCliBaseOptions) => {
|
|
637
|
-
await
|
|
641
|
+
await runManagedPluginControlCommand({
|
|
638
642
|
pluginName,
|
|
639
643
|
action: "start",
|
|
640
644
|
options: opts,
|
|
@@ -643,7 +647,7 @@ export function registerPluginsCommand(program: Command): void {
|
|
|
643
647
|
|
|
644
648
|
plugin
|
|
645
649
|
.command("stop <pluginName>")
|
|
646
|
-
.description("按 agent
|
|
650
|
+
.description("按 agent 目标停止托管 plugin")
|
|
647
651
|
.option("--path <path>", "项目根目录(默认当前目录)", ".")
|
|
648
652
|
.option("--agent <name>", "agent 名称(从 managed agent registry 解析)")
|
|
649
653
|
.option("--host <host>", "Server host(覆盖自动解析)")
|
|
@@ -651,7 +655,7 @@ export function registerPluginsCommand(program: Command): void {
|
|
|
651
655
|
.option("--token <token>", "覆盖 Bearer Token(仅远程 HTTP 调用需要;默认本地走 IPC)")
|
|
652
656
|
.option("--json [enabled]", "以 JSON 输出", parseBoolean, true)
|
|
653
657
|
.action(async (pluginName: string, opts: PluginCliBaseOptions) => {
|
|
654
|
-
await
|
|
658
|
+
await runManagedPluginControlCommand({
|
|
655
659
|
pluginName,
|
|
656
660
|
action: "stop",
|
|
657
661
|
options: opts,
|
|
@@ -660,7 +664,7 @@ export function registerPluginsCommand(program: Command): void {
|
|
|
660
664
|
|
|
661
665
|
plugin
|
|
662
666
|
.command("restart <pluginName>")
|
|
663
|
-
.description("按 agent
|
|
667
|
+
.description("按 agent 目标重启托管 plugin")
|
|
664
668
|
.option("--path <path>", "项目根目录(默认当前目录)", ".")
|
|
665
669
|
.option("--agent <name>", "agent 名称(从 managed agent registry 解析)")
|
|
666
670
|
.option("--host <host>", "Server host(覆盖自动解析)")
|
|
@@ -668,7 +672,7 @@ export function registerPluginsCommand(program: Command): void {
|
|
|
668
672
|
.option("--token <token>", "覆盖 Bearer Token(仅远程 HTTP 调用需要;默认本地走 IPC)")
|
|
669
673
|
.option("--json [enabled]", "以 JSON 输出", parseBoolean, true)
|
|
670
674
|
.action(async (pluginName: string, opts: PluginCliBaseOptions) => {
|
|
671
|
-
await
|
|
675
|
+
await runManagedPluginControlCommand({
|
|
672
676
|
pluginName,
|
|
673
677
|
action: "restart",
|
|
674
678
|
options: opts,
|
|
@@ -677,7 +681,7 @@ export function registerPluginsCommand(program: Command): void {
|
|
|
677
681
|
|
|
678
682
|
plugin
|
|
679
683
|
.command("command <pluginName> <command>")
|
|
680
|
-
.description("按 agent
|
|
684
|
+
.description("按 agent 目标转发托管 plugin command")
|
|
681
685
|
.option("--payload <json>", "可选 payload(JSON 字符串或普通字符串)")
|
|
682
686
|
.option("--path <path>", "项目根目录(默认当前目录)", ".")
|
|
683
687
|
.option("--agent <name>", "agent 名称(从 managed agent registry 解析)")
|
|
@@ -690,7 +694,7 @@ export function registerPluginsCommand(program: Command): void {
|
|
|
690
694
|
command: string,
|
|
691
695
|
opts: PluginCliBaseOptions & { payload?: string },
|
|
692
696
|
) => {
|
|
693
|
-
await
|
|
697
|
+
await runManagedPluginCommandBridge({
|
|
694
698
|
pluginName,
|
|
695
699
|
command,
|
|
696
700
|
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
|
|
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
|
-
|
|
123
|
+
plugins: {
|
|
124
124
|
type: "object",
|
|
125
125
|
additionalProperties: true,
|
|
126
126
|
properties: {
|
|
127
|
-
|
|
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,
|
package/src/config/Paths.ts
CHANGED
|
@@ -111,7 +111,7 @@ export function getDowncityMemoryDailyPath(cwd: string, date: string): string {
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
|
-
*
|
|
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 元信息目录(由
|
|
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
|
|
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:
|
|
97
|
+
let pluginsPayload: PluginStateListResponse;
|
|
98
98
|
try {
|
|
99
|
-
pluginsPayload = await fetchStatusJson<
|
|
100
|
-
new URL("/api/plugins/
|
|
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/
|
|
155
|
+
new URL("/api/plugins/command", baseUrl).toString(),
|
|
156
156
|
{
|
|
157
157
|
method: "POST",
|
|
158
158
|
headers: {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { Hono } from "hono";
|
|
10
|
-
import {
|
|
10
|
+
import { ChatChannelAccountManager } from "@downcity/agent";
|
|
11
11
|
import { createAgentPlatformRuntime } from "@/process/registry/AgentHostRuntime.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -15,11 +15,11 @@ import { createAgentPlatformRuntime } from "@/process/registry/AgentHostRuntime.
|
|
|
15
15
|
*/
|
|
16
16
|
export function registerPlatformChannelAccountRoutes(params: { app: Hono }): void {
|
|
17
17
|
const app = params.app;
|
|
18
|
-
const
|
|
18
|
+
const manager = new ChatChannelAccountManager(createAgentPlatformRuntime());
|
|
19
19
|
|
|
20
20
|
app.get("/api/ui/channel-accounts", async (c) => {
|
|
21
21
|
try {
|
|
22
|
-
const payload = await
|
|
22
|
+
const payload = await manager.list();
|
|
23
23
|
return c.json({
|
|
24
24
|
success: true,
|
|
25
25
|
...payload,
|
|
@@ -47,7 +47,7 @@ export function registerPlatformChannelAccountRoutes(params: { app: Hono }): voi
|
|
|
47
47
|
clearAppId?: boolean;
|
|
48
48
|
clearAppSecret?: boolean;
|
|
49
49
|
};
|
|
50
|
-
const payload = await
|
|
50
|
+
const payload = await manager.upsert({
|
|
51
51
|
id: String(body.id || "").trim(),
|
|
52
52
|
channel: String(body.channel || "").trim(),
|
|
53
53
|
name: String(body.name || "").trim(),
|
|
@@ -82,7 +82,7 @@ export function registerPlatformChannelAccountRoutes(params: { app: Hono }): voi
|
|
|
82
82
|
domain?: string;
|
|
83
83
|
sandbox?: boolean;
|
|
84
84
|
};
|
|
85
|
-
const payload = await
|
|
85
|
+
const payload = await manager.probe({
|
|
86
86
|
channel: String(body.channel || "").trim(),
|
|
87
87
|
botToken: body.botToken,
|
|
88
88
|
appId: body.appId,
|
|
@@ -108,7 +108,7 @@ export function registerPlatformChannelAccountRoutes(params: { app: Hono }): voi
|
|
|
108
108
|
if (!id) {
|
|
109
109
|
return c.json({ success: false, error: "Missing id" }, 400);
|
|
110
110
|
}
|
|
111
|
-
await
|
|
111
|
+
await manager.remove(id);
|
|
112
112
|
return c.json({
|
|
113
113
|
success: true,
|
|
114
114
|
id,
|
|
@@ -49,7 +49,7 @@ import type {
|
|
|
49
49
|
PlatformLocalModelsResponse,
|
|
50
50
|
} from "@downcity/agent";
|
|
51
51
|
import type { AgentProjectInitializationResult } from "@downcity/agent";
|
|
52
|
-
import {
|
|
52
|
+
import { listBuiltinPluginAuthPolicies } from "@downcity/agent";
|
|
53
53
|
import { AuthService } from "@/http/auth/AuthService.js";
|
|
54
54
|
import { registerAuthRoutes } from "@/http/auth/AuthRoutes.js";
|
|
55
55
|
import {
|
|
@@ -120,7 +120,7 @@ export class ControlGateway {
|
|
|
120
120
|
this.authService,
|
|
121
121
|
[
|
|
122
122
|
...CONTROL_PLANE_AUTH_ROUTE_POLICIES,
|
|
123
|
-
...
|
|
123
|
+
...listBuiltinPluginAuthPolicies(),
|
|
124
124
|
],
|
|
125
125
|
),
|
|
126
126
|
);
|