kode-sdk 2.7.0

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 (169) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +74 -0
  3. package/dist/core/agent/breakpoint-manager.d.ts +16 -0
  4. package/dist/core/agent/breakpoint-manager.js +36 -0
  5. package/dist/core/agent/message-queue.d.ts +26 -0
  6. package/dist/core/agent/message-queue.js +47 -0
  7. package/dist/core/agent/permission-manager.d.ts +9 -0
  8. package/dist/core/agent/permission-manager.js +32 -0
  9. package/dist/core/agent/todo-manager.d.ts +26 -0
  10. package/dist/core/agent/todo-manager.js +91 -0
  11. package/dist/core/agent/tool-runner.d.ts +9 -0
  12. package/dist/core/agent/tool-runner.js +45 -0
  13. package/dist/core/agent.d.ts +271 -0
  14. package/dist/core/agent.js +2334 -0
  15. package/dist/core/checkpointer.d.ts +96 -0
  16. package/dist/core/checkpointer.js +57 -0
  17. package/dist/core/checkpointers/file.d.ts +20 -0
  18. package/dist/core/checkpointers/file.js +153 -0
  19. package/dist/core/checkpointers/index.d.ts +3 -0
  20. package/dist/core/checkpointers/index.js +9 -0
  21. package/dist/core/checkpointers/redis.d.ts +35 -0
  22. package/dist/core/checkpointers/redis.js +113 -0
  23. package/dist/core/compression/ai-strategy.d.ts +53 -0
  24. package/dist/core/compression/ai-strategy.js +298 -0
  25. package/dist/core/compression/index.d.ts +12 -0
  26. package/dist/core/compression/index.js +27 -0
  27. package/dist/core/compression/prompts.d.ts +35 -0
  28. package/dist/core/compression/prompts.js +114 -0
  29. package/dist/core/compression/simple-strategy.d.ts +44 -0
  30. package/dist/core/compression/simple-strategy.js +240 -0
  31. package/dist/core/compression/token-estimator.d.ts +42 -0
  32. package/dist/core/compression/token-estimator.js +121 -0
  33. package/dist/core/compression/types.d.ts +140 -0
  34. package/dist/core/compression/types.js +9 -0
  35. package/dist/core/config.d.ts +10 -0
  36. package/dist/core/config.js +2 -0
  37. package/dist/core/context-manager.d.ts +115 -0
  38. package/dist/core/context-manager.js +107 -0
  39. package/dist/core/errors.d.ts +6 -0
  40. package/dist/core/errors.js +17 -0
  41. package/dist/core/events.d.ts +49 -0
  42. package/dist/core/events.js +312 -0
  43. package/dist/core/file-pool.d.ts +43 -0
  44. package/dist/core/file-pool.js +120 -0
  45. package/dist/core/hooks.d.ts +23 -0
  46. package/dist/core/hooks.js +71 -0
  47. package/dist/core/permission-modes.d.ts +31 -0
  48. package/dist/core/permission-modes.js +61 -0
  49. package/dist/core/pool.d.ts +31 -0
  50. package/dist/core/pool.js +87 -0
  51. package/dist/core/room.d.ts +15 -0
  52. package/dist/core/room.js +57 -0
  53. package/dist/core/scheduler.d.ts +33 -0
  54. package/dist/core/scheduler.js +58 -0
  55. package/dist/core/template.d.ts +69 -0
  56. package/dist/core/template.js +35 -0
  57. package/dist/core/time-bridge.d.ts +18 -0
  58. package/dist/core/time-bridge.js +100 -0
  59. package/dist/core/todo.d.ts +34 -0
  60. package/dist/core/todo.js +89 -0
  61. package/dist/core/types.d.ts +380 -0
  62. package/dist/core/types.js +3 -0
  63. package/dist/index.d.ts +51 -0
  64. package/dist/index.js +147 -0
  65. package/dist/infra/provider.d.ts +144 -0
  66. package/dist/infra/provider.js +294 -0
  67. package/dist/infra/sandbox-factory.d.ts +10 -0
  68. package/dist/infra/sandbox-factory.js +21 -0
  69. package/dist/infra/sandbox.d.ts +87 -0
  70. package/dist/infra/sandbox.js +255 -0
  71. package/dist/infra/store.d.ts +154 -0
  72. package/dist/infra/store.js +584 -0
  73. package/dist/skills/index.d.ts +12 -0
  74. package/dist/skills/index.js +36 -0
  75. package/dist/skills/injector.d.ts +29 -0
  76. package/dist/skills/injector.js +96 -0
  77. package/dist/skills/loader.d.ts +59 -0
  78. package/dist/skills/loader.js +215 -0
  79. package/dist/skills/manager.d.ts +85 -0
  80. package/dist/skills/manager.js +221 -0
  81. package/dist/skills/parser.d.ts +40 -0
  82. package/dist/skills/parser.js +107 -0
  83. package/dist/skills/types.d.ts +107 -0
  84. package/dist/skills/types.js +7 -0
  85. package/dist/skills/validator.d.ts +30 -0
  86. package/dist/skills/validator.js +121 -0
  87. package/dist/store.d.ts +1 -0
  88. package/dist/store.js +5 -0
  89. package/dist/tools/bash_kill/index.d.ts +1 -0
  90. package/dist/tools/bash_kill/index.js +35 -0
  91. package/dist/tools/bash_kill/prompt.d.ts +2 -0
  92. package/dist/tools/bash_kill/prompt.js +14 -0
  93. package/dist/tools/bash_logs/index.d.ts +1 -0
  94. package/dist/tools/bash_logs/index.js +40 -0
  95. package/dist/tools/bash_logs/prompt.d.ts +2 -0
  96. package/dist/tools/bash_logs/prompt.js +14 -0
  97. package/dist/tools/bash_run/index.d.ts +16 -0
  98. package/dist/tools/bash_run/index.js +61 -0
  99. package/dist/tools/bash_run/prompt.d.ts +2 -0
  100. package/dist/tools/bash_run/prompt.js +18 -0
  101. package/dist/tools/builtin.d.ts +9 -0
  102. package/dist/tools/builtin.js +27 -0
  103. package/dist/tools/define.d.ts +101 -0
  104. package/dist/tools/define.js +214 -0
  105. package/dist/tools/fs_edit/index.d.ts +1 -0
  106. package/dist/tools/fs_edit/index.js +62 -0
  107. package/dist/tools/fs_edit/prompt.d.ts +2 -0
  108. package/dist/tools/fs_edit/prompt.js +15 -0
  109. package/dist/tools/fs_glob/index.d.ts +1 -0
  110. package/dist/tools/fs_glob/index.js +60 -0
  111. package/dist/tools/fs_glob/prompt.d.ts +2 -0
  112. package/dist/tools/fs_glob/prompt.js +18 -0
  113. package/dist/tools/fs_grep/index.d.ts +1 -0
  114. package/dist/tools/fs_grep/index.js +66 -0
  115. package/dist/tools/fs_grep/prompt.d.ts +2 -0
  116. package/dist/tools/fs_grep/prompt.js +16 -0
  117. package/dist/tools/fs_multi_edit/index.d.ts +1 -0
  118. package/dist/tools/fs_multi_edit/index.js +106 -0
  119. package/dist/tools/fs_multi_edit/prompt.d.ts +2 -0
  120. package/dist/tools/fs_multi_edit/prompt.js +16 -0
  121. package/dist/tools/fs_read/index.d.ts +1 -0
  122. package/dist/tools/fs_read/index.js +40 -0
  123. package/dist/tools/fs_read/prompt.d.ts +2 -0
  124. package/dist/tools/fs_read/prompt.js +16 -0
  125. package/dist/tools/fs_rm/index.d.ts +1 -0
  126. package/dist/tools/fs_rm/index.js +41 -0
  127. package/dist/tools/fs_rm/prompt.d.ts +2 -0
  128. package/dist/tools/fs_rm/prompt.js +14 -0
  129. package/dist/tools/fs_write/index.d.ts +1 -0
  130. package/dist/tools/fs_write/index.js +40 -0
  131. package/dist/tools/fs_write/prompt.d.ts +2 -0
  132. package/dist/tools/fs_write/prompt.js +15 -0
  133. package/dist/tools/index.d.ts +9 -0
  134. package/dist/tools/index.js +56 -0
  135. package/dist/tools/mcp.d.ts +73 -0
  136. package/dist/tools/mcp.js +198 -0
  137. package/dist/tools/registry.d.ts +29 -0
  138. package/dist/tools/registry.js +26 -0
  139. package/dist/tools/skill_activate/index.d.ts +5 -0
  140. package/dist/tools/skill_activate/index.js +63 -0
  141. package/dist/tools/skill_list/index.d.ts +5 -0
  142. package/dist/tools/skill_list/index.js +48 -0
  143. package/dist/tools/skill_resource/index.d.ts +5 -0
  144. package/dist/tools/skill_resource/index.js +82 -0
  145. package/dist/tools/task_run/index.d.ts +7 -0
  146. package/dist/tools/task_run/index.js +60 -0
  147. package/dist/tools/task_run/prompt.d.ts +5 -0
  148. package/dist/tools/task_run/prompt.js +29 -0
  149. package/dist/tools/todo_read/index.d.ts +1 -0
  150. package/dist/tools/todo_read/index.js +29 -0
  151. package/dist/tools/todo_read/prompt.d.ts +2 -0
  152. package/dist/tools/todo_read/prompt.js +18 -0
  153. package/dist/tools/todo_write/index.d.ts +1 -0
  154. package/dist/tools/todo_write/index.js +42 -0
  155. package/dist/tools/todo_write/prompt.d.ts +2 -0
  156. package/dist/tools/todo_write/prompt.js +23 -0
  157. package/dist/tools/tool.d.ts +43 -0
  158. package/dist/tools/tool.js +104 -0
  159. package/dist/tools/toolkit.d.ts +69 -0
  160. package/dist/tools/toolkit.js +98 -0
  161. package/dist/tools/type-inference.d.ts +127 -0
  162. package/dist/tools/type-inference.js +207 -0
  163. package/dist/utils/agent-id.d.ts +1 -0
  164. package/dist/utils/agent-id.js +28 -0
  165. package/dist/utils/session-id.d.ts +21 -0
  166. package/dist/utils/session-id.js +64 -0
  167. package/dist/utils/unicode.d.ts +17 -0
  168. package/dist/utils/unicode.js +62 -0
  169. package/package.json +117 -0
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SkillsInjector = void 0;
4
+ /**
5
+ * Skills 系统提示注入器
6
+ *
7
+ * 将 Skills 元数据转换为 XML 格式并注入系统提示
8
+ */
9
+ class SkillsInjector {
10
+ /**
11
+ * 生成 available_skills XML
12
+ *
13
+ * 遵循 Agent Skills 规范的推荐格式
14
+ *
15
+ * @param skills - Skills 列表(仅需元数据)
16
+ * @returns XML 格式的系统提示片段
17
+ */
18
+ static toPromptXML(skills) {
19
+ if (skills.length === 0)
20
+ return '';
21
+ const skillsXml = skills
22
+ .map((skill) => {
23
+ const location = 'path' in skill ? `${skill.path}/SKILL.md` : '';
24
+ return ` <skill>
25
+ <name>${SkillsInjector.escapeXml(skill.name)}</name>
26
+ <description>${SkillsInjector.escapeXml(skill.description)}</description>${location ? `\n <location>${SkillsInjector.escapeXml(location)}</location>` : ''}
27
+ </skill>`;
28
+ })
29
+ .join('\n');
30
+ return `
31
+ <available_skills>
32
+ ${skillsXml}
33
+ </available_skills>
34
+
35
+ When a task matches a skill's description, use skill_activate to load its full instructions.
36
+ `;
37
+ }
38
+ /**
39
+ * 生成激活后的 skill_instructions XML
40
+ */
41
+ static toActivatedXML(skill) {
42
+ if (!skill.body) {
43
+ return `<skill_instructions name="${SkillsInjector.escapeXml(skill.name)}">
44
+ Skill body not loaded. Use skill_activate to load full content.
45
+ </skill_instructions>`;
46
+ }
47
+ let resourcesInfo = '';
48
+ if (skill.resources) {
49
+ const parts = [];
50
+ if (skill.resources.scripts?.length) {
51
+ parts.push(`Scripts: ${skill.resources.scripts.join(', ')}`);
52
+ }
53
+ if (skill.resources.references?.length) {
54
+ parts.push(`References: ${skill.resources.references.join(', ')}`);
55
+ }
56
+ if (skill.resources.assets?.length) {
57
+ parts.push(`Assets: ${skill.resources.assets.join(', ')}`);
58
+ }
59
+ if (parts.length > 0) {
60
+ resourcesInfo = `\n\n[Available Resources]\n${parts.join('\n')}`;
61
+ }
62
+ }
63
+ return `<skill_instructions name="${SkillsInjector.escapeXml(skill.name)}">
64
+ ${skill.body}${resourcesInfo}
65
+ </skill_instructions>`;
66
+ }
67
+ /**
68
+ * 转义 XML 特殊字符
69
+ */
70
+ static escapeXml(text) {
71
+ return text
72
+ .replace(/&/g, '&amp;')
73
+ .replace(/</g, '&lt;')
74
+ .replace(/>/g, '&gt;')
75
+ .replace(/"/g, '&quot;')
76
+ .replace(/'/g, '&apos;');
77
+ }
78
+ /**
79
+ * 生成 Skills 总结(用于上下文压缩)
80
+ */
81
+ static toSummary(skills) {
82
+ if (skills.length === 0)
83
+ return '';
84
+ const activated = skills.filter((s) => s.activatedAt);
85
+ const available = skills.filter((s) => !s.activatedAt);
86
+ let summary = '[Skills Status]\n';
87
+ if (activated.length > 0) {
88
+ summary += `Activated: ${activated.map((s) => s.name).join(', ')}\n`;
89
+ }
90
+ if (available.length > 0) {
91
+ summary += `Available: ${available.map((s) => s.name).join(', ')}\n`;
92
+ }
93
+ return summary;
94
+ }
95
+ }
96
+ exports.SkillsInjector = SkillsInjector;
@@ -0,0 +1,59 @@
1
+ import { Sandbox } from '../infra/sandbox';
2
+ import { Skill, SkillResources, SkillsConfig } from './types';
3
+ /**
4
+ * Skills 加载器
5
+ *
6
+ * 负责发现和加载 Skills
7
+ */
8
+ export declare class SkillsLoader {
9
+ private readonly sandbox;
10
+ private readonly parser;
11
+ private readonly validator;
12
+ constructor(sandbox: Sandbox);
13
+ /**
14
+ * 发现所有 Skills(仅加载元数据,不加载完整内容)
15
+ *
16
+ * 这是 Progressive Disclosure 的第一阶段:
17
+ * 只加载 name 和 description,用于注入系统提示
18
+ */
19
+ discover(config: SkillsConfig): Promise<Skill[]>;
20
+ /**
21
+ * 加载 Skill 元数据(不含完整正文)
22
+ */
23
+ loadMetadata(skillDir: string, config?: SkillsConfig): Promise<Skill | null>;
24
+ /**
25
+ * 加载完整 Skill 内容(包括正文和资源列表)
26
+ *
27
+ * 这是 Progressive Disclosure 的第二阶段:
28
+ * 当 Agent 激活 Skill 时,加载完整内容
29
+ */
30
+ loadFull(skillDir: string): Promise<Skill>;
31
+ /**
32
+ * 扫描 Skill 的资源目录
33
+ */
34
+ scanResources(skillDir: string): Promise<SkillResources>;
35
+ /**
36
+ * 加载资源文件内容
37
+ */
38
+ loadResource(skillDir: string, resourcePath: string): Promise<string>;
39
+ /**
40
+ * 查找包含 SKILL.md 的目录
41
+ */
42
+ private findSkillDirs;
43
+ /**
44
+ * 列出目录中的文件
45
+ */
46
+ private listFiles;
47
+ /**
48
+ * 列出目录中的文件,返回相对 skillDir 的路径(用于 skill_resource 的 resourcePath)
49
+ */
50
+ private listFilesRelative;
51
+ /**
52
+ * 检查路径是否存在
53
+ */
54
+ private pathExists;
55
+ /**
56
+ * 检查是否应该包含该 Skill
57
+ */
58
+ private shouldInclude;
59
+ }
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SkillsLoader = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const parser_1 = require("./parser");
9
+ const validator_1 = require("./validator");
10
+ /**
11
+ * Skills 加载器
12
+ *
13
+ * 负责发现和加载 Skills
14
+ */
15
+ class SkillsLoader {
16
+ constructor(sandbox) {
17
+ this.sandbox = sandbox;
18
+ this.parser = new parser_1.SkillsParser();
19
+ this.validator = new validator_1.SkillsValidator();
20
+ }
21
+ /**
22
+ * 发现所有 Skills(仅加载元数据,不加载完整内容)
23
+ *
24
+ * 这是 Progressive Disclosure 的第一阶段:
25
+ * 只加载 name 和 description,用于注入系统提示
26
+ */
27
+ async discover(config) {
28
+ const skills = [];
29
+ for (const searchPath of config.paths) {
30
+ try {
31
+ const resolvedPath = this.sandbox.fs.resolve(searchPath);
32
+ const exists = await this.pathExists(resolvedPath);
33
+ if (!exists)
34
+ continue;
35
+ const dirs = await this.findSkillDirs(resolvedPath);
36
+ for (const dir of dirs) {
37
+ try {
38
+ const skill = await this.loadMetadata(dir, config);
39
+ if (skill && this.shouldInclude(skill.name, config)) {
40
+ skills.push(skill);
41
+ }
42
+ }
43
+ catch (error) {
44
+ // 跳过无效的 Skill 目录,继续处理其他
45
+ console.warn(`[SkillsLoader] Failed to load skill from ${dir}:`, error);
46
+ }
47
+ }
48
+ }
49
+ catch (error) {
50
+ console.warn(`[SkillsLoader] Failed to scan path ${searchPath}:`, error);
51
+ }
52
+ }
53
+ return skills;
54
+ }
55
+ /**
56
+ * 加载 Skill 元数据(不含完整正文)
57
+ */
58
+ async loadMetadata(skillDir, config) {
59
+ const skillMdPath = path_1.default.join(skillDir, 'SKILL.md');
60
+ const exists = await this.pathExists(skillMdPath);
61
+ if (!exists) {
62
+ return null;
63
+ }
64
+ const content = await this.sandbox.fs.read(skillMdPath);
65
+ const { metadata } = this.parser.parse(content);
66
+ // 可选:验证格式
67
+ if (config?.validateOnLoad) {
68
+ const validation = this.validator.validate(metadata);
69
+ if (!validation.valid) {
70
+ throw new Error(`Skill validation failed: ${validation.errors.join(', ')}`);
71
+ }
72
+ }
73
+ return {
74
+ ...metadata,
75
+ path: skillDir,
76
+ loadedAt: Date.now(),
77
+ };
78
+ }
79
+ /**
80
+ * 加载完整 Skill 内容(包括正文和资源列表)
81
+ *
82
+ * 这是 Progressive Disclosure 的第二阶段:
83
+ * 当 Agent 激活 Skill 时,加载完整内容
84
+ */
85
+ async loadFull(skillDir) {
86
+ const skillMdPath = path_1.default.join(skillDir, 'SKILL.md');
87
+ const content = await this.sandbox.fs.read(skillMdPath);
88
+ const { metadata, body } = this.parser.parse(content);
89
+ const resources = await this.scanResources(skillDir);
90
+ return {
91
+ ...metadata,
92
+ path: skillDir,
93
+ body,
94
+ resources,
95
+ loadedAt: Date.now(),
96
+ };
97
+ }
98
+ /**
99
+ * 扫描 Skill 的资源目录
100
+ */
101
+ async scanResources(skillDir) {
102
+ const resources = {};
103
+ // 扫描 scripts/
104
+ const scriptsDir = path_1.default.join(skillDir, 'scripts');
105
+ if (await this.pathExists(scriptsDir)) {
106
+ resources.scripts = await this.listFilesRelative(skillDir, scriptsDir);
107
+ }
108
+ // 扫描 references/
109
+ const referencesDir = path_1.default.join(skillDir, 'references');
110
+ if (await this.pathExists(referencesDir)) {
111
+ resources.references = await this.listFilesRelative(skillDir, referencesDir);
112
+ }
113
+ // 扫描 assets/
114
+ const assetsDir = path_1.default.join(skillDir, 'assets');
115
+ if (await this.pathExists(assetsDir)) {
116
+ resources.assets = await this.listFilesRelative(skillDir, assetsDir);
117
+ }
118
+ return resources;
119
+ }
120
+ /**
121
+ * 加载资源文件内容
122
+ */
123
+ async loadResource(skillDir, resourcePath) {
124
+ const fullPath = path_1.default.join(skillDir, resourcePath);
125
+ // 安全检查:防止路径遍历
126
+ const resolvedFull = path_1.default.resolve(fullPath);
127
+ const resolvedSkill = path_1.default.resolve(skillDir);
128
+ if (!resolvedFull.startsWith(resolvedSkill + path_1.default.sep) && resolvedFull !== resolvedSkill) {
129
+ throw new Error('Path traversal not allowed');
130
+ }
131
+ return await this.sandbox.fs.read(fullPath);
132
+ }
133
+ /**
134
+ * 查找包含 SKILL.md 的目录
135
+ */
136
+ async findSkillDirs(searchPath) {
137
+ const skillDirs = [];
138
+ try {
139
+ // 使用 glob 查找所有 SKILL.md 文件
140
+ const pattern = '*/SKILL.md';
141
+ const matches = await this.sandbox.fs.glob(pattern, {
142
+ cwd: searchPath,
143
+ absolute: true,
144
+ });
145
+ for (const skillMdPath of matches) {
146
+ // 获取 SKILL.md 所在目录
147
+ const skillDir = path_1.default.dirname(skillMdPath);
148
+ skillDirs.push(skillDir);
149
+ }
150
+ }
151
+ catch {
152
+ // 搜索路径不存在或无法读取
153
+ }
154
+ return skillDirs;
155
+ }
156
+ /**
157
+ * 列出目录中的文件
158
+ */
159
+ async listFiles(dirPath) {
160
+ try {
161
+ // 使用 glob 列出目录中的文件
162
+ const pattern = '*';
163
+ const matches = await this.sandbox.fs.glob(pattern, {
164
+ cwd: dirPath,
165
+ absolute: false,
166
+ });
167
+ return matches;
168
+ }
169
+ catch {
170
+ return [];
171
+ }
172
+ }
173
+ /**
174
+ * 列出目录中的文件,返回相对 skillDir 的路径(用于 skill_resource 的 resourcePath)
175
+ */
176
+ async listFilesRelative(skillDir, dirPath) {
177
+ try {
178
+ const matches = await this.sandbox.fs.glob('*', {
179
+ cwd: dirPath,
180
+ absolute: true,
181
+ });
182
+ return matches.map((abs) => path_1.default.relative(skillDir, abs).split(path_1.default.sep).join('/'));
183
+ }
184
+ catch {
185
+ return [];
186
+ }
187
+ }
188
+ /**
189
+ * 检查路径是否存在
190
+ */
191
+ async pathExists(filePath) {
192
+ try {
193
+ await this.sandbox.fs.stat(filePath);
194
+ return true;
195
+ }
196
+ catch {
197
+ return false;
198
+ }
199
+ }
200
+ /**
201
+ * 检查是否应该包含该 Skill
202
+ */
203
+ shouldInclude(name, config) {
204
+ // 检查黑名单
205
+ if (config.exclude?.includes(name)) {
206
+ return false;
207
+ }
208
+ // 如果有白名单,只包含白名单中的
209
+ if (config.include && config.include.length > 0) {
210
+ return config.include.includes(name);
211
+ }
212
+ return true;
213
+ }
214
+ }
215
+ exports.SkillsLoader = SkillsLoader;
@@ -0,0 +1,85 @@
1
+ import { Sandbox } from '../infra/sandbox';
2
+ import { Store } from '../infra/store';
3
+ import { Skill, SkillMetadata, SkillsConfig, SkillActivation } from './types';
4
+ /**
5
+ * Skills 状态管理器
6
+ *
7
+ * 管理 Skills 的发现、激活和持久化状态
8
+ */
9
+ export declare class SkillsManager {
10
+ private readonly config;
11
+ private readonly sandbox;
12
+ private readonly store?;
13
+ private readonly agentId?;
14
+ private readonly discovered;
15
+ private readonly activated;
16
+ private readonly loader;
17
+ constructor(config: SkillsConfig, sandbox: Sandbox, store?: Store | undefined, agentId?: string | undefined);
18
+ /**
19
+ * 发现所有 Skills(仅加载元数据)
20
+ *
21
+ * 这是 Progressive Disclosure 的第一阶段
22
+ */
23
+ discover(): Promise<SkillMetadata[]>;
24
+ /**
25
+ * 激活 Skill(加载完整内容)
26
+ *
27
+ * 这是 Progressive Disclosure 的第二阶段
28
+ */
29
+ activate(name: string, activatedBy?: 'auto' | 'agent' | 'user'): Promise<Skill>;
30
+ /**
31
+ * 停用 Skill
32
+ */
33
+ deactivate(name: string): Promise<void>;
34
+ /**
35
+ * 批量自动激活 Skills
36
+ *
37
+ * 用于 Template 配置的 autoActivate Skills
38
+ * 静默失败:如果 Skill 不存在则跳过,不抛错
39
+ */
40
+ autoActivateSkills(names: string[]): Promise<Skill[]>;
41
+ /**
42
+ * 获取已发现的 Skills 列表
43
+ */
44
+ list(): Skill[];
45
+ /**
46
+ * 获取单个 Skill
47
+ */
48
+ get(name: string): Skill | undefined;
49
+ /**
50
+ * 检查 Skill 是否已激活
51
+ */
52
+ isActivated(name: string): boolean;
53
+ /**
54
+ * 获取已激活的 Skills
55
+ */
56
+ getActivated(): Skill[];
57
+ /**
58
+ * 获取 Skill 的激活信息
59
+ */
60
+ getActivation(name: string): SkillActivation | undefined;
61
+ /**
62
+ * 检查 Skill 是否来自可信来源
63
+ */
64
+ isTrusted(name: string): boolean;
65
+ /**
66
+ * 获取 Skill 声明的 allowed-tools
67
+ */
68
+ getAllowedTools(name: string): string[] | undefined;
69
+ /**
70
+ * 加载 Skill 的资源文件
71
+ */
72
+ loadResource(skillName: string, resourcePath: string): Promise<string>;
73
+ /**
74
+ * 持久化状态到 Store
75
+ */
76
+ persistState(): Promise<void>;
77
+ /**
78
+ * 从 Store 恢复状态(用于 Resume)
79
+ */
80
+ restoreState(): Promise<void>;
81
+ /**
82
+ * 获取 Skills 配置
83
+ */
84
+ getConfig(): SkillsConfig;
85
+ }
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SkillsManager = void 0;
4
+ const loader_1 = require("./loader");
5
+ /**
6
+ * Skills 状态管理器
7
+ *
8
+ * 管理 Skills 的发现、激活和持久化状态
9
+ */
10
+ class SkillsManager {
11
+ constructor(config, sandbox, store, agentId) {
12
+ this.config = config;
13
+ this.sandbox = sandbox;
14
+ this.store = store;
15
+ this.agentId = agentId;
16
+ this.discovered = new Map();
17
+ this.activated = new Map();
18
+ this.loader = new loader_1.SkillsLoader(sandbox);
19
+ }
20
+ /**
21
+ * 发现所有 Skills(仅加载元数据)
22
+ *
23
+ * 这是 Progressive Disclosure 的第一阶段
24
+ */
25
+ async discover() {
26
+ const skills = await this.loader.discover(this.config);
27
+ // Refresh discovery snapshot: remove skills that no longer exist on disk.
28
+ // Preserve previously loaded bodies/resources when possible.
29
+ const previous = new Map(this.discovered);
30
+ this.discovered.clear();
31
+ // Deduplicate by name while keeping later entries higher priority.
32
+ // This matters when multiple search paths contain the same skill name
33
+ // (e.g. bundled skills vs user-level overrides).
34
+ const unique = new Map();
35
+ for (const skill of skills) {
36
+ if (!skill?.name)
37
+ continue;
38
+ if (unique.has(skill.name)) {
39
+ // Move to the end to reflect "last wins" semantics.
40
+ unique.delete(skill.name);
41
+ console.warn(`[SkillsManager] Duplicate skill "${skill.name}" discovered; using the later one.`);
42
+ }
43
+ unique.set(skill.name, skill);
44
+ }
45
+ for (const skill of unique.values()) {
46
+ const prev = previous.get(skill.name);
47
+ if (prev) {
48
+ if (prev.body && !skill.body)
49
+ skill.body = prev.body;
50
+ if (prev.resources && !skill.resources)
51
+ skill.resources = prev.resources;
52
+ if (typeof prev.activatedAt === 'number')
53
+ skill.activatedAt = prev.activatedAt;
54
+ }
55
+ this.discovered.set(skill.name, skill);
56
+ }
57
+ return Array.from(unique.values());
58
+ }
59
+ /**
60
+ * 激活 Skill(加载完整内容)
61
+ *
62
+ * 这是 Progressive Disclosure 的第二阶段
63
+ */
64
+ async activate(name, activatedBy = 'agent') {
65
+ const skill = this.discovered.get(name);
66
+ if (!skill) {
67
+ throw new Error(`Skill not found: ${name}. Available skills: ${Array.from(this.discovered.keys()).join(', ')}`);
68
+ }
69
+ // 如果尚未加载完整内容,则加载
70
+ if (!skill.body) {
71
+ const fullSkill = await this.loader.loadFull(skill.path);
72
+ Object.assign(skill, fullSkill);
73
+ this.discovered.set(name, skill);
74
+ }
75
+ // 记录激活状态
76
+ skill.activatedAt = Date.now();
77
+ const activation = {
78
+ name,
79
+ activatedAt: skill.activatedAt,
80
+ activatedBy,
81
+ toolsGranted: skill.allowedTools,
82
+ };
83
+ this.activated.set(name, activation);
84
+ // 持久化状态
85
+ await this.persistState();
86
+ return skill;
87
+ }
88
+ /**
89
+ * 停用 Skill
90
+ */
91
+ async deactivate(name) {
92
+ this.activated.delete(name);
93
+ const skill = this.discovered.get(name);
94
+ if (skill) {
95
+ skill.activatedAt = undefined;
96
+ }
97
+ await this.persistState();
98
+ }
99
+ /**
100
+ * 批量自动激活 Skills
101
+ *
102
+ * 用于 Template 配置的 autoActivate Skills
103
+ * 静默失败:如果 Skill 不存在则跳过,不抛错
104
+ */
105
+ async autoActivateSkills(names) {
106
+ const activated = [];
107
+ for (const name of names) {
108
+ if (!this.discovered.has(name)) {
109
+ // 静默跳过不存在的 Skill
110
+ console.warn(`[SkillsManager] Skill "${name}" not found for auto-activation, skipping`);
111
+ continue;
112
+ }
113
+ if (this.isActivated(name)) {
114
+ // 已激活则跳过
115
+ const skill = this.discovered.get(name);
116
+ if (skill)
117
+ activated.push(skill);
118
+ continue;
119
+ }
120
+ try {
121
+ const skill = await this.activate(name, 'auto');
122
+ activated.push(skill);
123
+ }
124
+ catch (error) {
125
+ console.warn(`[SkillsManager] Failed to auto-activate skill "${name}":`, error);
126
+ }
127
+ }
128
+ return activated;
129
+ }
130
+ /**
131
+ * 获取已发现的 Skills 列表
132
+ */
133
+ list() {
134
+ return Array.from(this.discovered.values());
135
+ }
136
+ /**
137
+ * 获取单个 Skill
138
+ */
139
+ get(name) {
140
+ return this.discovered.get(name);
141
+ }
142
+ /**
143
+ * 检查 Skill 是否已激活
144
+ */
145
+ isActivated(name) {
146
+ return this.activated.has(name);
147
+ }
148
+ /**
149
+ * 获取已激活的 Skills
150
+ */
151
+ getActivated() {
152
+ return Array.from(this.activated.keys())
153
+ .map((name) => this.discovered.get(name))
154
+ .filter((s) => s !== undefined);
155
+ }
156
+ /**
157
+ * 获取 Skill 的激活信息
158
+ */
159
+ getActivation(name) {
160
+ return this.activated.get(name);
161
+ }
162
+ /**
163
+ * 检查 Skill 是否来自可信来源
164
+ */
165
+ isTrusted(name) {
166
+ if (!this.config.trusted || this.config.trusted.length === 0) {
167
+ return false;
168
+ }
169
+ return this.config.trusted.includes(name);
170
+ }
171
+ /**
172
+ * 获取 Skill 声明的 allowed-tools
173
+ */
174
+ getAllowedTools(name) {
175
+ return this.discovered.get(name)?.allowedTools;
176
+ }
177
+ /**
178
+ * 加载 Skill 的资源文件
179
+ */
180
+ async loadResource(skillName, resourcePath) {
181
+ const skill = this.discovered.get(skillName);
182
+ if (!skill) {
183
+ throw new Error(`Skill not found: ${skillName}`);
184
+ }
185
+ return await this.loader.loadResource(skill.path, resourcePath);
186
+ }
187
+ /**
188
+ * 持久化状态到 Store
189
+ */
190
+ async persistState() {
191
+ if (!this.store || !this.agentId)
192
+ return;
193
+ const state = {
194
+ discovered: Array.from(this.discovered.keys()),
195
+ activated: Array.from(this.activated.values()),
196
+ lastDiscoveryAt: Date.now(),
197
+ };
198
+ await this.store.saveSkillsState(this.agentId, state);
199
+ }
200
+ /**
201
+ * 从 Store 恢复状态(用于 Resume)
202
+ */
203
+ async restoreState() {
204
+ if (!this.store || !this.agentId)
205
+ return;
206
+ const state = await this.store.loadSkillsState(this.agentId);
207
+ if (!state)
208
+ return;
209
+ // 恢复激活状态
210
+ for (const activation of state.activated) {
211
+ this.activated.set(activation.name, activation);
212
+ }
213
+ }
214
+ /**
215
+ * 获取 Skills 配置
216
+ */
217
+ getConfig() {
218
+ return this.config;
219
+ }
220
+ }
221
+ exports.SkillsManager = SkillsManager;