@downcity/plugins 1.0.57 → 1.0.59
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/bin/BuiltinPlugins.d.ts.map +1 -1
- package/bin/BuiltinPlugins.js +0 -2
- package/bin/BuiltinPlugins.js.map +1 -1
- package/bin/auth/types/AuthPlugin.d.ts +12 -16
- package/bin/auth/types/AuthPlugin.d.ts.map +1 -1
- package/bin/auth/types/AuthPlugin.js +9 -13
- package/bin/auth/types/AuthPlugin.js.map +1 -1
- package/bin/chat/ChatPlugin.d.ts +37 -6
- package/bin/chat/ChatPlugin.d.ts.map +1 -1
- package/bin/chat/ChatPlugin.js +58 -80
- package/bin/chat/ChatPlugin.js.map +1 -1
- package/bin/chat/Index.d.ts +4 -1
- package/bin/chat/Index.d.ts.map +1 -1
- package/bin/chat/Index.js +2 -1
- package/bin/chat/Index.js.map +1 -1
- package/bin/chat/channels/Configuration.d.ts +1 -1
- package/bin/chat/channels/Configuration.js +1 -1
- package/bin/chat/channels/RuntimeChannel.d.ts +145 -0
- package/bin/chat/channels/RuntimeChannel.d.ts.map +1 -0
- package/bin/chat/channels/RuntimeChannel.js +148 -0
- package/bin/chat/channels/RuntimeChannel.js.map +1 -0
- package/bin/chat/runtime/ChatAuthorizationRuntime.d.ts +22 -0
- package/bin/chat/runtime/ChatAuthorizationRuntime.d.ts.map +1 -0
- package/bin/chat/runtime/ChatAuthorizationRuntime.js +189 -0
- package/bin/chat/runtime/ChatAuthorizationRuntime.js.map +1 -0
- package/bin/chat/runtime/ChatChannelActions.d.ts.map +1 -1
- package/bin/chat/runtime/ChatChannelActions.js +19 -9
- package/bin/chat/runtime/ChatChannelActions.js.map +1 -1
- package/bin/chat/runtime/ChatChannelConfig.d.ts +2 -18
- package/bin/chat/runtime/ChatChannelConfig.d.ts.map +1 -1
- package/bin/chat/runtime/ChatChannelConfig.js +2 -73
- package/bin/chat/runtime/ChatChannelConfig.js.map +1 -1
- package/bin/chat/runtime/ChatChannelCore.d.ts +22 -1
- package/bin/chat/runtime/ChatChannelCore.d.ts.map +1 -1
- package/bin/chat/runtime/ChatChannelCore.js +5 -5
- package/bin/chat/runtime/ChatChannelCore.js.map +1 -1
- package/bin/chat/runtime/ChatPluginActionRegistry.js +1 -1
- package/bin/chat/runtime/ChatPluginActionRegistry.js.map +1 -1
- package/bin/chat/runtime/PluginPoints.d.ts +3 -3
- package/bin/chat/runtime/PluginPoints.js +3 -3
- package/bin/chat/types/ChannelStatus.d.ts +1 -1
- package/bin/chat/types/ChatPluginOptions.d.ts +76 -0
- package/bin/chat/types/ChatPluginOptions.d.ts.map +1 -0
- package/bin/chat/types/ChatPluginOptions.js +10 -0
- package/bin/chat/types/ChatPluginOptions.js.map +1 -0
- package/bin/index.d.ts +4 -3
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +2 -2
- package/bin/index.js.map +1 -1
- package/bin/skill/Action.d.ts.map +1 -1
- package/bin/skill/Action.js +2 -2
- package/bin/skill/Action.js.map +1 -1
- package/bin/skill/Command.js +5 -5
- package/bin/skill/Command.js.map +1 -1
- package/bin/skill/Plugin.js +1 -1
- package/bin/skill/Plugin.js.map +1 -1
- package/bin/skill/runtime/Discovery.d.ts +4 -4
- package/bin/skill/runtime/Discovery.d.ts.map +1 -1
- package/bin/skill/runtime/Discovery.js +5 -5
- package/bin/skill/runtime/Discovery.js.map +1 -1
- package/bin/skill/runtime/Paths.d.ts +1 -5
- package/bin/skill/runtime/Paths.d.ts.map +1 -1
- package/bin/skill/runtime/Paths.js +1 -9
- package/bin/skill/runtime/Paths.js.map +1 -1
- package/bin/skill/runtime/Prompt.d.ts +2 -2
- package/bin/skill/runtime/Prompt.d.ts.map +1 -1
- package/bin/skill/runtime/Prompt.js +3 -3
- package/bin/skill/runtime/Prompt.js.map +1 -1
- package/bin/skill/runtime/Store.d.ts +2 -2
- package/bin/skill/runtime/Store.d.ts.map +1 -1
- package/bin/skill/runtime/Store.js.map +1 -1
- package/bin/skill/runtime/SystemProvider.js +4 -4
- package/bin/skill/runtime/SystemProvider.js.map +1 -1
- package/bin/skill/runtime/Types.d.ts +3 -3
- package/bin/skill/runtime/Types.d.ts.map +1 -1
- package/bin/skill/types/{ClaudeSkill.d.ts → SkillDefinition.d.ts} +4 -4
- package/bin/skill/types/SkillDefinition.d.ts.map +1 -0
- package/bin/skill/types/{ClaudeSkill.js → SkillDefinition.js} +2 -2
- package/bin/skill/types/SkillDefinition.js.map +1 -0
- package/bin/skill/types/SkillPlugin.d.ts +2 -2
- package/bin/skill/types/SkillPlugin.d.ts.map +1 -1
- package/bin/web/Plugin.js +1 -1
- package/bin/web/Plugin.js.map +1 -1
- package/bin/web/runtime/Install.js +2 -2
- package/bin/web/runtime/Install.js.map +1 -1
- package/bin/web/types/WebPlugin.d.ts +2 -1
- package/bin/web/types/WebPlugin.d.ts.map +1 -1
- package/bin/workboard/Plugin.d.ts +23 -3
- package/bin/workboard/Plugin.d.ts.map +1 -1
- package/bin/workboard/Plugin.js +66 -85
- package/bin/workboard/Plugin.js.map +1 -1
- package/package.json +1 -1
- package/src/BuiltinPlugins.ts +0 -2
- package/src/auth/types/AuthPlugin.ts +12 -17
- package/src/chat/ChatPlugin.ts +92 -89
- package/src/chat/Index.ts +18 -1
- package/src/chat/channels/Configuration.ts +1 -1
- package/src/chat/channels/RuntimeChannel.ts +264 -0
- package/src/chat/runtime/ChatAuthorizationRuntime.ts +229 -0
- package/src/chat/runtime/ChatChannelActions.ts +24 -9
- package/src/chat/runtime/ChatChannelConfig.ts +2 -100
- package/src/chat/runtime/ChatChannelCore.ts +20 -8
- package/src/chat/runtime/ChatPluginActionRegistry.ts +1 -1
- package/src/chat/runtime/PluginPoints.ts +3 -3
- package/src/chat/types/ChannelStatus.ts +1 -1
- package/src/chat/types/ChatPluginOptions.ts +79 -0
- package/src/index.ts +17 -6
- package/src/skill/Action.ts +10 -7
- package/src/skill/Command.ts +5 -5
- package/src/skill/Plugin.ts +1 -1
- package/src/skill/runtime/Discovery.ts +14 -11
- package/src/skill/runtime/Paths.ts +1 -13
- package/src/skill/runtime/Prompt.ts +5 -5
- package/src/skill/runtime/Store.ts +6 -3
- package/src/skill/runtime/SystemProvider.ts +4 -4
- package/src/skill/runtime/Types.ts +3 -3
- package/src/skill/types/{ClaudeSkill.ts → SkillDefinition.ts} +3 -3
- package/src/skill/types/SkillPlugin.ts +2 -2
- package/src/web/Plugin.ts +1 -1
- package/src/web/runtime/Install.ts +3 -3
- package/src/web/types/WebPlugin.ts +2 -2
- package/src/workboard/Plugin.ts +80 -95
- package/bin/auth/Plugin.d.ts +0 -17
- package/bin/auth/Plugin.d.ts.map +0 -1
- package/bin/auth/Plugin.js +0 -199
- package/bin/auth/Plugin.js.map +0 -1
- package/bin/chat/ChatPluginTypes.d.ts +0 -122
- package/bin/chat/ChatPluginTypes.d.ts.map +0 -1
- package/bin/chat/ChatPluginTypes.js +0 -10
- package/bin/chat/ChatPluginTypes.js.map +0 -1
- package/bin/skill/types/ClaudeSkill.d.ts.map +0 -1
- package/bin/skill/types/ClaudeSkill.js.map +0 -1
- package/src/auth/Plugin.ts +0 -237
- package/src/chat/ChatPluginTypes.ts +0 -126
|
@@ -15,16 +15,30 @@ import { getStoredChannelAccountSync } from "@/chat/accounts/Store.js";
|
|
|
15
15
|
|
|
16
16
|
const CHAT_CHANNEL_NAMES: ChatChannelName[] = ["telegram", "feishu", "qq"];
|
|
17
17
|
|
|
18
|
-
type ChatRuntimeBindings = {
|
|
18
|
+
export type ChatRuntimeBindings = {
|
|
19
19
|
getChannelAccountId?(context: AgentContext, channel: ChatChannelName): string;
|
|
20
20
|
resolveChannelAccount?(
|
|
21
21
|
context: AgentContext,
|
|
22
22
|
channel: ChatChannelName,
|
|
23
23
|
): StoredChannelAccount | null;
|
|
24
24
|
isChannelEnabled?(context: AgentContext, channel: ChatChannelName): boolean;
|
|
25
|
+
applyChannelRuntimePatch?(params: {
|
|
26
|
+
/**
|
|
27
|
+
* 目标渠道。
|
|
28
|
+
*/
|
|
29
|
+
channel: ChatChannelName;
|
|
30
|
+
/**
|
|
31
|
+
* 是否启用该渠道。
|
|
32
|
+
*/
|
|
33
|
+
enabled?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* 绑定的账号池记录 ID;传入 null 表示清空绑定。
|
|
36
|
+
*/
|
|
37
|
+
channelAccountId?: string | null;
|
|
38
|
+
}): void;
|
|
25
39
|
};
|
|
26
40
|
|
|
27
|
-
function resolveChatPluginBindings(
|
|
41
|
+
export function resolveChatPluginBindings(
|
|
28
42
|
context: AgentContext,
|
|
29
43
|
): ChatRuntimeBindings | null {
|
|
30
44
|
const candidate = context.agent?.pluginInstances?.get?.("chat") as
|
|
@@ -78,10 +92,7 @@ export function resolveChannelAccountId(
|
|
|
78
92
|
const plugin = resolveChatPluginBindings(context);
|
|
79
93
|
const explicit = String(plugin?.getChannelAccountId?.(context, channel) || "").trim();
|
|
80
94
|
if (explicit) return explicit;
|
|
81
|
-
|
|
82
|
-
| { channelAccountId?: unknown }
|
|
83
|
-
| undefined;
|
|
84
|
-
return String(config?.channelAccountId || "").trim();
|
|
95
|
+
return "";
|
|
85
96
|
}
|
|
86
97
|
|
|
87
98
|
/**
|
|
@@ -89,7 +100,8 @@ export function resolveChannelAccountId(
|
|
|
89
100
|
*
|
|
90
101
|
* 关键点(中文)
|
|
91
102
|
* - 优先使用 ChatPlugin 实例上的显式解析逻辑。
|
|
92
|
-
* -
|
|
103
|
+
* - 若实例只提供 channelAccountId,再从默认全局账号池读取对应账号。
|
|
104
|
+
* - 不再从 downcity.json 隐式推断运行时账号。
|
|
93
105
|
*/
|
|
94
106
|
export function resolveChannelAccount(
|
|
95
107
|
context: AgentContext,
|
|
@@ -132,7 +144,7 @@ export function isChatChannelEnabled(
|
|
|
132
144
|
if (typeof plugin?.isChannelEnabled === "function") {
|
|
133
145
|
return plugin.isChannelEnabled(context, channel);
|
|
134
146
|
}
|
|
135
|
-
return
|
|
147
|
+
return false;
|
|
136
148
|
}
|
|
137
149
|
|
|
138
150
|
/**
|
|
@@ -198,7 +198,7 @@ export function createChatPluginActions(params: {
|
|
|
198
198
|
},
|
|
199
199
|
configure: {
|
|
200
200
|
command: {
|
|
201
|
-
description: "更新 chat
|
|
201
|
+
description: "更新 chat 渠道运行态参数(可选立即重载)",
|
|
202
202
|
configure(command: Command) {
|
|
203
203
|
command
|
|
204
204
|
.requiredOption("--channel <name>", "指定渠道(telegram|feishu|qq)")
|
|
@@ -56,7 +56,7 @@ export const CHAT_PLUGIN_POINTS = {
|
|
|
56
56
|
*
|
|
57
57
|
* 说明(中文)
|
|
58
58
|
* - 仅做副作用记录,不返回值。
|
|
59
|
-
* -
|
|
59
|
+
* - ChatPlugin 内置授权能力会使用该点记录主体快照。
|
|
60
60
|
*/
|
|
61
61
|
observePrincipal: "chat.observePrincipal",
|
|
62
62
|
/**
|
|
@@ -64,7 +64,7 @@ export const CHAT_PLUGIN_POINTS = {
|
|
|
64
64
|
*
|
|
65
65
|
* 说明(中文)
|
|
66
66
|
* - 由 chat plugin runtime 在 ingress 阶段显式调用。
|
|
67
|
-
* -
|
|
67
|
+
* - ChatPlugin 内置授权能力会使用该点执行角色与权限判定。
|
|
68
68
|
*/
|
|
69
69
|
authorizeIncoming: "chat.authorizeIncoming",
|
|
70
70
|
/**
|
|
@@ -72,7 +72,7 @@ export const CHAT_PLUGIN_POINTS = {
|
|
|
72
72
|
*
|
|
73
73
|
* 说明(中文)
|
|
74
74
|
* - 主要用于在 history / queue metadata 中补齐授权上下文。
|
|
75
|
-
* -
|
|
75
|
+
* - ChatPlugin 内置授权能力会使用该点补齐用户角色。
|
|
76
76
|
*/
|
|
77
77
|
resolveUserRole: "chat.resolveUserRole",
|
|
78
78
|
} as const;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatPlugin SDK / runtime 配置类型。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - ChatPlugin 只接收 queue 行为与 channels 列表。
|
|
6
|
+
* - 每个 channel 对象自己负责 env / 凭据 / 账号池绑定解析。
|
|
7
|
+
* - 这样 ChatPlugin 不再理解 Telegram、Feishu、QQ 的具体配置字段。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
|
|
11
|
+
import type { StoredChannelAccount } from "@downcity/agent/internal/types/platform/Store.js";
|
|
12
|
+
import type { ChatChannelName } from "@/chat/types/ChannelStatus.js";
|
|
13
|
+
import type { ChatQueueWorkerConfig } from "@/chat/types/ChatQueueWorker.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Chat channel 运行态 patch。
|
|
17
|
+
*/
|
|
18
|
+
export interface ChatChannelRuntimePatch {
|
|
19
|
+
/**
|
|
20
|
+
* 是否启用该 channel。
|
|
21
|
+
*/
|
|
22
|
+
enabled?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* 绑定的账号池记录 ID。
|
|
25
|
+
*
|
|
26
|
+
* 说明(中文)
|
|
27
|
+
* - 传入字符串表示绑定到该账号池记录。
|
|
28
|
+
* - 传入 `null` 表示清空账号池绑定。
|
|
29
|
+
*/
|
|
30
|
+
channelAccountId?: string | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Chat channel 对象协议。
|
|
35
|
+
*/
|
|
36
|
+
export interface ChatChannel {
|
|
37
|
+
/**
|
|
38
|
+
* channel 名称。
|
|
39
|
+
*/
|
|
40
|
+
readonly name: ChatChannelName;
|
|
41
|
+
/**
|
|
42
|
+
* 当前 channel 是否启用。
|
|
43
|
+
*/
|
|
44
|
+
isEnabled(context: AgentContext): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* 当前 channel 绑定的账号池记录 ID。
|
|
47
|
+
*/
|
|
48
|
+
getChannelAccountId(context: AgentContext): string;
|
|
49
|
+
/**
|
|
50
|
+
* 解析当前 channel 的运行态账号。
|
|
51
|
+
*/
|
|
52
|
+
getAccount(context: AgentContext): StoredChannelAccount | null;
|
|
53
|
+
/**
|
|
54
|
+
* 应用运行态配置 patch。
|
|
55
|
+
*/
|
|
56
|
+
applyRuntimePatch(patch: ChatChannelRuntimePatch): void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* ChatPlugin 显式构造参数。
|
|
61
|
+
*/
|
|
62
|
+
export interface ChatPluginOptions {
|
|
63
|
+
/**
|
|
64
|
+
* Chat queue worker 运行配置。
|
|
65
|
+
*
|
|
66
|
+
* 说明(中文)
|
|
67
|
+
* - 可用于不同 client 定制并发、突发合并等行为。
|
|
68
|
+
* - 这是 queue 行为的唯一运行配置入口。
|
|
69
|
+
*/
|
|
70
|
+
queue?: Partial<ChatQueueWorkerConfig>;
|
|
71
|
+
/**
|
|
72
|
+
* 当前 agent 持有的 chat channels。
|
|
73
|
+
*
|
|
74
|
+
* 说明(中文)
|
|
75
|
+
* - 每个 channel 对象自己负责 env、凭据与账号池绑定解析。
|
|
76
|
+
* - 未传入时不启用任何 chat channel。
|
|
77
|
+
*/
|
|
78
|
+
channels?: ChatChannel[];
|
|
79
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -13,9 +13,13 @@ export {
|
|
|
13
13
|
} from "./BuiltinPlugins.js";
|
|
14
14
|
export type { BuiltinPluginClass } from "./BuiltinPlugins.js";
|
|
15
15
|
export { ChatPlugin } from "./chat/ChatPlugin.js";
|
|
16
|
+
export {
|
|
17
|
+
FeishuChannel,
|
|
18
|
+
QqChannel,
|
|
19
|
+
TelegramChannel,
|
|
20
|
+
} from "./chat/channels/RuntimeChannel.js";
|
|
16
21
|
export { ImagePlugin } from "./image/ImagePlugin.js";
|
|
17
22
|
export { ChatChannelAccountManager } from "./chat/accounts/ChannelAccountManager.js";
|
|
18
|
-
export { ChatAuthorizationPlugin } from "./auth/Plugin.js";
|
|
19
23
|
export { SkillPlugin } from "./skill/Plugin.js";
|
|
20
24
|
export { WebPlugin } from "./web/Plugin.js";
|
|
21
25
|
export { AsrPlugin } from "./asr/Plugin.js";
|
|
@@ -28,8 +32,9 @@ export {
|
|
|
28
32
|
} from "./auth/runtime/AuthorizationConfig.js";
|
|
29
33
|
export { resolveAuthorizedUserRole } from "./auth/runtime/AuthorizationPolicy.js";
|
|
30
34
|
export {
|
|
35
|
+
CHAT_AUTHORIZATION_ACTIONS,
|
|
31
36
|
CHAT_AUTHORIZATION_CHANNELS,
|
|
32
|
-
|
|
37
|
+
CHAT_AUTHORIZATION_POINTS,
|
|
33
38
|
createDefaultChatAuthorizationRoles,
|
|
34
39
|
isChatAuthorizationChannel,
|
|
35
40
|
} from "./auth/types/AuthPlugin.js";
|
|
@@ -38,11 +43,17 @@ export type {
|
|
|
38
43
|
ChatChannelAccountListItem,
|
|
39
44
|
} from "./chat/types/ChannelAccount.js";
|
|
40
45
|
export type {
|
|
41
|
-
|
|
46
|
+
BaseChatChannelOptions,
|
|
47
|
+
ChatChannelEnv,
|
|
48
|
+
FeishuChannelOptions,
|
|
49
|
+
QqChannelOptions,
|
|
50
|
+
TelegramChannelOptions,
|
|
51
|
+
} from "./chat/channels/RuntimeChannel.js";
|
|
52
|
+
export type {
|
|
53
|
+
ChatChannel,
|
|
54
|
+
ChatChannelRuntimePatch,
|
|
42
55
|
ChatPluginOptions,
|
|
43
|
-
|
|
44
|
-
ChatPluginTelegramOptions,
|
|
45
|
-
} from "./chat/ChatPluginTypes.js";
|
|
56
|
+
} from "./chat/types/ChatPluginOptions.js";
|
|
46
57
|
export type {
|
|
47
58
|
AsrPluginInput,
|
|
48
59
|
AsrPluginOptions,
|
package/src/skill/Action.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
import fs from "fs-extra";
|
|
10
10
|
import path from "node:path";
|
|
11
|
-
import {
|
|
12
|
-
import type {
|
|
11
|
+
import { discoverSkillsSync } from "@/skill/runtime/Discovery.js";
|
|
12
|
+
import type { SkillDefinition } from "@/skill/types/SkillDefinition.js";
|
|
13
13
|
import type { JsonValue } from "@downcity/agent/internal/types/common/Json.js";
|
|
14
14
|
import type {
|
|
15
15
|
SkillListResponse,
|
|
@@ -30,7 +30,7 @@ function normalizeAllowedTools(input: JsonValue | undefined): string[] {
|
|
|
30
30
|
return Array.from(new Set(values));
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function toSkillSummary(skill:
|
|
33
|
+
function toSkillSummary(skill: SkillDefinition): SkillSummary {
|
|
34
34
|
return {
|
|
35
35
|
id: skill.id,
|
|
36
36
|
name: skill.name,
|
|
@@ -41,7 +41,10 @@ function toSkillSummary(skill: ClaudeSkill): SkillSummary {
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
function findSkillExact(
|
|
44
|
+
function findSkillExact(
|
|
45
|
+
skills: SkillDefinition[],
|
|
46
|
+
name: string,
|
|
47
|
+
): SkillDefinition | null {
|
|
45
48
|
const q = String(name || "").trim().toLowerCase();
|
|
46
49
|
if (!q) return null;
|
|
47
50
|
|
|
@@ -52,7 +55,7 @@ function findSkillExact(skills: ClaudeSkill[], name: string): ClaudeSkill | null
|
|
|
52
55
|
);
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
function findSkill(skills:
|
|
58
|
+
function findSkill(skills: SkillDefinition[], name: string): SkillDefinition | null {
|
|
56
59
|
const q = String(name || "").trim().toLowerCase();
|
|
57
60
|
if (!q) return null;
|
|
58
61
|
|
|
@@ -67,9 +70,9 @@ function findSkill(skills: ClaudeSkill[], name: string): ClaudeSkill | null {
|
|
|
67
70
|
function getSkills(
|
|
68
71
|
projectRoot: string,
|
|
69
72
|
options?: SkillPluginOptions | null,
|
|
70
|
-
):
|
|
73
|
+
): SkillDefinition[] {
|
|
71
74
|
const root = path.resolve(projectRoot);
|
|
72
|
-
return
|
|
75
|
+
return discoverSkillsSync(root, options);
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
/**
|
package/src/skill/Command.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { execa } from "execa";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { discoverSkillsSync } from "@/skill/runtime/Discovery.js";
|
|
12
|
+
import { getSkillSearchRoots } from "@/skill/runtime/Paths.js";
|
|
13
13
|
|
|
14
14
|
async function runNpxSkills(args: string[], opts?: { yes?: boolean }): Promise<number> {
|
|
15
15
|
const yes = opts?.yes !== false;
|
|
@@ -57,7 +57,7 @@ export async function skillInstallCommand(
|
|
|
57
57
|
if (!s) throw new Error("Missing spec");
|
|
58
58
|
|
|
59
59
|
const args: string[] = ["add", s];
|
|
60
|
-
const agent = String(options.agent || "
|
|
60
|
+
const agent = String(options.agent || "").trim();
|
|
61
61
|
if (agent) args.push("--agent", agent);
|
|
62
62
|
|
|
63
63
|
const yes = options.yes !== false;
|
|
@@ -74,8 +74,8 @@ export async function skillInstallCommand(
|
|
|
74
74
|
*/
|
|
75
75
|
export async function skillListCommand(cwd: string = "."): Promise<void> {
|
|
76
76
|
const projectRoot = path.resolve(String(cwd || "."));
|
|
77
|
-
const roots =
|
|
78
|
-
const skills =
|
|
77
|
+
const roots = getSkillSearchRoots(projectRoot);
|
|
78
|
+
const skills = discoverSkillsSync(projectRoot);
|
|
79
79
|
|
|
80
80
|
console.log("Skill roots:");
|
|
81
81
|
for (const root of roots) console.log(`- [${root.source}] ${root.display}`);
|
package/src/skill/Plugin.ts
CHANGED
|
@@ -166,7 +166,7 @@ function createSkillPluginDefinition(options: SkillPluginOptions): Plugin {
|
|
|
166
166
|
.argument("<spec>")
|
|
167
167
|
.option("-g, --global", "全局安装(默认 true)", true)
|
|
168
168
|
.option("-y, --yes", "跳过确认(默认 true)", true)
|
|
169
|
-
.option("--agent <agent>", "指定 agent"
|
|
169
|
+
.option("--agent <agent>", "指定 agent");
|
|
170
170
|
},
|
|
171
171
|
mapInput({ args, opts }): SkillPluginInstallPayload {
|
|
172
172
|
const spec = String(args[0] || "").trim();
|
|
@@ -12,15 +12,18 @@ import path from "path";
|
|
|
12
12
|
import type { Dirent, Stats } from "node:fs";
|
|
13
13
|
import { resolveSkillPluginOptions } from "../Config.js";
|
|
14
14
|
import { parseFrontMatter } from "./Frontmatter.js";
|
|
15
|
-
import {
|
|
16
|
-
import type {
|
|
15
|
+
import { getSkillSearchRoots } from "./Paths.js";
|
|
16
|
+
import type { SkillDefinition } from "@/skill/types/SkillDefinition.js";
|
|
17
17
|
import type {
|
|
18
18
|
SkillPluginIgnoreRule,
|
|
19
19
|
SkillPluginOptions,
|
|
20
20
|
} from "@/skill/types/SkillPlugin.js";
|
|
21
21
|
import type { JsonObject, JsonValue } from "@downcity/agent/internal/types/common/Json.js";
|
|
22
22
|
|
|
23
|
-
function matchesIgnoreRule(
|
|
23
|
+
function matchesIgnoreRule(
|
|
24
|
+
skill: SkillDefinition,
|
|
25
|
+
rule: SkillPluginIgnoreRule,
|
|
26
|
+
): boolean {
|
|
24
27
|
if (typeof rule === "string") {
|
|
25
28
|
const value = rule.trim().toLowerCase();
|
|
26
29
|
if (!value) return false;
|
|
@@ -41,7 +44,7 @@ function matchesIgnoreRule(skill: ClaudeSkill, rule: SkillPluginIgnoreRule): boo
|
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
function shouldIgnoreSkill(
|
|
44
|
-
skill:
|
|
47
|
+
skill: SkillDefinition,
|
|
45
48
|
rules: SkillPluginIgnoreRule[],
|
|
46
49
|
): boolean {
|
|
47
50
|
for (const rule of rules) {
|
|
@@ -51,7 +54,7 @@ function shouldIgnoreSkill(
|
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
/**
|
|
54
|
-
*
|
|
57
|
+
* 扫描并发现本地 skills。
|
|
55
58
|
*
|
|
56
59
|
* 关键点(中文)
|
|
57
60
|
* - skills 的扫描根目录与 projectRoot 强相关(默认 `.agents/skills`)
|
|
@@ -61,19 +64,19 @@ function shouldIgnoreSkill(
|
|
|
61
64
|
* 发现技能算法(中文)
|
|
62
65
|
* 1) 计算扫描根目录列表
|
|
63
66
|
* 2) 逐目录读取 `SKILL.md` 与 frontmatter
|
|
64
|
-
* 3) 按 id 去重并构造
|
|
67
|
+
* 3) 按 id 去重并构造 SkillDefinition
|
|
65
68
|
* 4) 最终按 name 排序,保证输出稳定
|
|
66
69
|
*/
|
|
67
|
-
export function
|
|
70
|
+
export function discoverSkillsSync(
|
|
68
71
|
projectRoot: string,
|
|
69
72
|
options?: SkillPluginOptions | null,
|
|
70
|
-
):
|
|
73
|
+
): SkillDefinition[] {
|
|
71
74
|
const root = String(projectRoot || "").trim();
|
|
72
75
|
if (!root) return [];
|
|
73
76
|
const resolvedOptions = resolveSkillPluginOptions(options);
|
|
74
|
-
const roots =
|
|
77
|
+
const roots = getSkillSearchRoots(root, resolvedOptions);
|
|
75
78
|
|
|
76
|
-
const outById = new Map<string,
|
|
79
|
+
const outById = new Map<string, SkillDefinition>();
|
|
77
80
|
|
|
78
81
|
for (const r of roots) {
|
|
79
82
|
const sourceRoot = r.resolved;
|
|
@@ -146,7 +149,7 @@ export function discoverClaudeSkillsSync(
|
|
|
146
149
|
const allowedTools =
|
|
147
150
|
meta?.["allowed-tools"] ?? meta?.allowedTools ?? meta?.allowed_tools;
|
|
148
151
|
|
|
149
|
-
const skill:
|
|
152
|
+
const skill: SkillDefinition = {
|
|
150
153
|
id,
|
|
151
154
|
name,
|
|
152
155
|
description,
|
|
@@ -36,7 +36,7 @@ function resolveSkillRootPath(projectRoot: string, raw: string): string {
|
|
|
36
36
|
: path.resolve(projectRoot, expanded);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
export function
|
|
39
|
+
export function getSkillSearchRoots(
|
|
40
40
|
projectRoot: string,
|
|
41
41
|
options?: SkillPluginOptions | null,
|
|
42
42
|
): SkillRoot[] {
|
|
@@ -105,15 +105,3 @@ export function getClaudeSkillSearchRoots(
|
|
|
105
105
|
|
|
106
106
|
return Array.from(byResolved.values()).sort((a, b) => a.priority - b.priority);
|
|
107
107
|
}
|
|
108
|
-
|
|
109
|
-
// Back-compat(内部仅用于 prompt 展示):保留旧 API 形状,避免外部 import 立刻断裂。
|
|
110
|
-
export function getClaudeSkillSearchPaths(
|
|
111
|
-
projectRoot: string,
|
|
112
|
-
options?: SkillPluginOptions | null,
|
|
113
|
-
): { raw: string[]; resolved: string[] } {
|
|
114
|
-
const roots = getClaudeSkillSearchRoots(projectRoot, options);
|
|
115
|
-
return {
|
|
116
|
-
raw: roots.map((r) => r.display),
|
|
117
|
-
resolved: roots.map((r) => r.resolved),
|
|
118
|
-
};
|
|
119
|
-
}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* - 仅做字符串渲染,不做文件 IO。
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
import type {
|
|
10
|
+
import { getSkillSearchRoots } from "./Paths.js";
|
|
11
|
+
import type { SkillDefinition } from "@/skill/types/SkillDefinition.js";
|
|
12
12
|
import type { SkillPluginOptions } from "@/skill/types/SkillPlugin.js";
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -18,12 +18,12 @@ import type { SkillPluginOptions } from "@/skill/types/SkillPlugin.js";
|
|
|
18
18
|
* - 为控制 token 成本,最多展示前 40 个 skill。
|
|
19
19
|
* - roots 会按扫描顺序输出,便于排查冲突覆盖。
|
|
20
20
|
*/
|
|
21
|
-
export function
|
|
21
|
+
export function renderSkillsPromptSection(
|
|
22
22
|
projectRoot: string,
|
|
23
23
|
options: SkillPluginOptions | null | undefined,
|
|
24
|
-
skills:
|
|
24
|
+
skills: SkillDefinition[],
|
|
25
25
|
): string {
|
|
26
|
-
const roots =
|
|
26
|
+
const roots = getSkillSearchRoots(projectRoot, options);
|
|
27
27
|
|
|
28
28
|
const skillsSection =
|
|
29
29
|
skills.length > 0
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - core 不负责也不感知 skill/memory 业务状态
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type {
|
|
9
|
+
import type { SkillDefinition } from "@/skill/types/SkillDefinition.js";
|
|
10
10
|
import type {
|
|
11
11
|
SessionSkillStateInternal,
|
|
12
12
|
SessionSkillStateSnapshot,
|
|
@@ -50,9 +50,12 @@ function getOrCreateState(sessionId: string): SessionSkillStateInternal {
|
|
|
50
50
|
* 算法(中文)
|
|
51
51
|
* - 以 id 归一化后整体替换,避免残留脏状态。
|
|
52
52
|
*/
|
|
53
|
-
export function setSessionAvailableSkills(
|
|
53
|
+
export function setSessionAvailableSkills(
|
|
54
|
+
sessionId: string,
|
|
55
|
+
skills: SkillDefinition[],
|
|
56
|
+
): void {
|
|
54
57
|
const state = getOrCreateState(sessionId);
|
|
55
|
-
const next = new Map<string,
|
|
58
|
+
const next = new Map<string, SkillDefinition>();
|
|
56
59
|
|
|
57
60
|
for (const skill of Array.isArray(skills) ? skills : []) {
|
|
58
61
|
const id = String(skill?.id || "").trim();
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { getSessionRunContext } from "@downcity/agent/internal/executor/SessionRunScope.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { discoverSkillsSync } from "./Discovery.js";
|
|
12
|
+
import { renderSkillsPromptSection } from "./Prompt.js";
|
|
13
13
|
import { setSessionAvailableSkills } from "./Store.js";
|
|
14
14
|
import type { SkillPluginOptions } from "@/skill/types/SkillPlugin.js";
|
|
15
15
|
|
|
@@ -35,7 +35,7 @@ export async function buildSkillsSystemText(
|
|
|
35
35
|
runtime: SkillSystemRuntime,
|
|
36
36
|
): Promise<string> {
|
|
37
37
|
const sessionId = getCurrentSessionId();
|
|
38
|
-
const discoveredSkills =
|
|
38
|
+
const discoveredSkills = discoverSkillsSync(
|
|
39
39
|
runtime.rootPath,
|
|
40
40
|
runtime.options,
|
|
41
41
|
);
|
|
@@ -44,7 +44,7 @@ export async function buildSkillsSystemText(
|
|
|
44
44
|
setSessionAvailableSkills(sessionId, discoveredSkills);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
return
|
|
47
|
+
return renderSkillsPromptSection(
|
|
48
48
|
runtime.rootPath,
|
|
49
49
|
runtime.options,
|
|
50
50
|
discoveredSkills,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SkillDefinition } from "@/skill/types/SkillDefinition.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Session skills state 对外快照。
|
|
@@ -9,7 +9,7 @@ import type { ClaudeSkill } from "@/skill/types/ClaudeSkill.js";
|
|
|
9
9
|
*/
|
|
10
10
|
export type SessionSkillStateSnapshot = {
|
|
11
11
|
sessionId: string;
|
|
12
|
-
allSkills:
|
|
12
|
+
allSkills: SkillDefinition[];
|
|
13
13
|
updatedAt: number;
|
|
14
14
|
};
|
|
15
15
|
|
|
@@ -17,6 +17,6 @@ export type SessionSkillStateSnapshot = {
|
|
|
17
17
|
* Session skills state 内部结构。
|
|
18
18
|
*/
|
|
19
19
|
export type SessionSkillStateInternal = {
|
|
20
|
-
allSkillsById: Map<string,
|
|
20
|
+
allSkillsById: Map<string, SkillDefinition>;
|
|
21
21
|
updatedAt: number;
|
|
22
22
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Skill 定义模型。
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
5
|
* - skill 最小单元目录为 `<root>/<skill-id>/SKILL.md`。
|
|
@@ -11,9 +11,9 @@ import type { SkillRootSource } from "@/skill/types/SkillRoot.js";
|
|
|
11
11
|
import type { JsonValue } from "@downcity/agent/internal/types/common/Json.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* 可被 agent 发现与读取的 skill 定义。
|
|
15
15
|
*/
|
|
16
|
-
export interface
|
|
16
|
+
export interface SkillDefinition {
|
|
17
17
|
/**
|
|
18
18
|
* skill 稳定标识。
|
|
19
19
|
*
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - 该文件只描述插件协议,不承载发现、安装或 system 组装逻辑。
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type {
|
|
10
|
+
import type { SkillDefinition } from "@/skill/types/SkillDefinition.js";
|
|
11
11
|
import type { SkillRootSource } from "@/skill/types/SkillRoot.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -80,7 +80,7 @@ export type SkillPluginLookupPayload = {
|
|
|
80
80
|
export type SkillPluginIgnoreRule =
|
|
81
81
|
| string
|
|
82
82
|
| RegExp
|
|
83
|
-
| ((skill:
|
|
83
|
+
| ((skill: SkillDefinition) => boolean);
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
86
|
* SkillPlugin 构造参数。
|
package/src/web/Plugin.ts
CHANGED
|
@@ -145,7 +145,7 @@ export class WebPlugin extends BasePlugin {
|
|
|
145
145
|
.option("--target <target>", "web-access、agent-browser 或 all")
|
|
146
146
|
.option("--scope <scope>", "安装位置:user 或 project")
|
|
147
147
|
.option("-y, --yes", "跳过确认(默认 true)", true)
|
|
148
|
-
.option("--agent <agent>", "skill installer 目标 agent"
|
|
148
|
+
.option("--agent <agent>", "skill installer 目标 agent");
|
|
149
149
|
},
|
|
150
150
|
mapInput({ opts }): JsonObject {
|
|
151
151
|
return {
|
|
@@ -145,7 +145,7 @@ async function install_skill(params: {
|
|
|
145
145
|
spec: string;
|
|
146
146
|
scope: WebPluginInstallScope;
|
|
147
147
|
yes: boolean;
|
|
148
|
-
agent
|
|
148
|
+
agent?: string;
|
|
149
149
|
steps: WebPluginInstallStep[];
|
|
150
150
|
}): Promise<void> {
|
|
151
151
|
await skillInstallCommand(params.spec, {
|
|
@@ -207,7 +207,7 @@ export async function installWebPluginTargets(params: {
|
|
|
207
207
|
const target = resolve_install_target(payload.target);
|
|
208
208
|
const scope = resolve_install_scope(payload.scope);
|
|
209
209
|
const yes = read_boolean(payload.yes) ?? true;
|
|
210
|
-
const agent = read_string(payload.agent)
|
|
210
|
+
const agent = read_string(payload.agent);
|
|
211
211
|
const targets =
|
|
212
212
|
target === "all" ? (["web-access", "agent-browser"] as const) : ([target] as const);
|
|
213
213
|
const steps: WebPluginInstallStep[] = [];
|
|
@@ -233,7 +233,7 @@ export async function installWebPluginTargets(params: {
|
|
|
233
233
|
return {
|
|
234
234
|
target,
|
|
235
235
|
scope,
|
|
236
|
-
agent,
|
|
236
|
+
...(agent ? { agent } : {}),
|
|
237
237
|
steps: serialize_steps(steps),
|
|
238
238
|
nextAction:
|
|
239
239
|
"Use SkillPlugin lookup/list to inspect installed skills, then let the agent choose the concrete web path during task execution.",
|
|
@@ -54,7 +54,8 @@ export interface WebPluginInstallPayload {
|
|
|
54
54
|
* skill installer 的目标 agent 名称。
|
|
55
55
|
*
|
|
56
56
|
* 说明(中文)
|
|
57
|
-
* -
|
|
57
|
+
* - 留空时不向底层 skill installer 传递 `--agent`。
|
|
58
|
+
* - 只有需要显式指定 installer 目标时才传入。
|
|
58
59
|
*/
|
|
59
60
|
agent?: string;
|
|
60
61
|
/**
|
|
@@ -62,4 +63,3 @@ export interface WebPluginInstallPayload {
|
|
|
62
63
|
*/
|
|
63
64
|
[key: string]: JsonValue | undefined;
|
|
64
65
|
}
|
|
65
|
-
|