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.
- package/LICENSE +201 -0
- package/README.md +74 -0
- package/dist/core/agent/breakpoint-manager.d.ts +16 -0
- package/dist/core/agent/breakpoint-manager.js +36 -0
- package/dist/core/agent/message-queue.d.ts +26 -0
- package/dist/core/agent/message-queue.js +47 -0
- package/dist/core/agent/permission-manager.d.ts +9 -0
- package/dist/core/agent/permission-manager.js +32 -0
- package/dist/core/agent/todo-manager.d.ts +26 -0
- package/dist/core/agent/todo-manager.js +91 -0
- package/dist/core/agent/tool-runner.d.ts +9 -0
- package/dist/core/agent/tool-runner.js +45 -0
- package/dist/core/agent.d.ts +271 -0
- package/dist/core/agent.js +2334 -0
- package/dist/core/checkpointer.d.ts +96 -0
- package/dist/core/checkpointer.js +57 -0
- package/dist/core/checkpointers/file.d.ts +20 -0
- package/dist/core/checkpointers/file.js +153 -0
- package/dist/core/checkpointers/index.d.ts +3 -0
- package/dist/core/checkpointers/index.js +9 -0
- package/dist/core/checkpointers/redis.d.ts +35 -0
- package/dist/core/checkpointers/redis.js +113 -0
- package/dist/core/compression/ai-strategy.d.ts +53 -0
- package/dist/core/compression/ai-strategy.js +298 -0
- package/dist/core/compression/index.d.ts +12 -0
- package/dist/core/compression/index.js +27 -0
- package/dist/core/compression/prompts.d.ts +35 -0
- package/dist/core/compression/prompts.js +114 -0
- package/dist/core/compression/simple-strategy.d.ts +44 -0
- package/dist/core/compression/simple-strategy.js +240 -0
- package/dist/core/compression/token-estimator.d.ts +42 -0
- package/dist/core/compression/token-estimator.js +121 -0
- package/dist/core/compression/types.d.ts +140 -0
- package/dist/core/compression/types.js +9 -0
- package/dist/core/config.d.ts +10 -0
- package/dist/core/config.js +2 -0
- package/dist/core/context-manager.d.ts +115 -0
- package/dist/core/context-manager.js +107 -0
- package/dist/core/errors.d.ts +6 -0
- package/dist/core/errors.js +17 -0
- package/dist/core/events.d.ts +49 -0
- package/dist/core/events.js +312 -0
- package/dist/core/file-pool.d.ts +43 -0
- package/dist/core/file-pool.js +120 -0
- package/dist/core/hooks.d.ts +23 -0
- package/dist/core/hooks.js +71 -0
- package/dist/core/permission-modes.d.ts +31 -0
- package/dist/core/permission-modes.js +61 -0
- package/dist/core/pool.d.ts +31 -0
- package/dist/core/pool.js +87 -0
- package/dist/core/room.d.ts +15 -0
- package/dist/core/room.js +57 -0
- package/dist/core/scheduler.d.ts +33 -0
- package/dist/core/scheduler.js +58 -0
- package/dist/core/template.d.ts +69 -0
- package/dist/core/template.js +35 -0
- package/dist/core/time-bridge.d.ts +18 -0
- package/dist/core/time-bridge.js +100 -0
- package/dist/core/todo.d.ts +34 -0
- package/dist/core/todo.js +89 -0
- package/dist/core/types.d.ts +380 -0
- package/dist/core/types.js +3 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +147 -0
- package/dist/infra/provider.d.ts +144 -0
- package/dist/infra/provider.js +294 -0
- package/dist/infra/sandbox-factory.d.ts +10 -0
- package/dist/infra/sandbox-factory.js +21 -0
- package/dist/infra/sandbox.d.ts +87 -0
- package/dist/infra/sandbox.js +255 -0
- package/dist/infra/store.d.ts +154 -0
- package/dist/infra/store.js +584 -0
- package/dist/skills/index.d.ts +12 -0
- package/dist/skills/index.js +36 -0
- package/dist/skills/injector.d.ts +29 -0
- package/dist/skills/injector.js +96 -0
- package/dist/skills/loader.d.ts +59 -0
- package/dist/skills/loader.js +215 -0
- package/dist/skills/manager.d.ts +85 -0
- package/dist/skills/manager.js +221 -0
- package/dist/skills/parser.d.ts +40 -0
- package/dist/skills/parser.js +107 -0
- package/dist/skills/types.d.ts +107 -0
- package/dist/skills/types.js +7 -0
- package/dist/skills/validator.d.ts +30 -0
- package/dist/skills/validator.js +121 -0
- package/dist/store.d.ts +1 -0
- package/dist/store.js +5 -0
- package/dist/tools/bash_kill/index.d.ts +1 -0
- package/dist/tools/bash_kill/index.js +35 -0
- package/dist/tools/bash_kill/prompt.d.ts +2 -0
- package/dist/tools/bash_kill/prompt.js +14 -0
- package/dist/tools/bash_logs/index.d.ts +1 -0
- package/dist/tools/bash_logs/index.js +40 -0
- package/dist/tools/bash_logs/prompt.d.ts +2 -0
- package/dist/tools/bash_logs/prompt.js +14 -0
- package/dist/tools/bash_run/index.d.ts +16 -0
- package/dist/tools/bash_run/index.js +61 -0
- package/dist/tools/bash_run/prompt.d.ts +2 -0
- package/dist/tools/bash_run/prompt.js +18 -0
- package/dist/tools/builtin.d.ts +9 -0
- package/dist/tools/builtin.js +27 -0
- package/dist/tools/define.d.ts +101 -0
- package/dist/tools/define.js +214 -0
- package/dist/tools/fs_edit/index.d.ts +1 -0
- package/dist/tools/fs_edit/index.js +62 -0
- package/dist/tools/fs_edit/prompt.d.ts +2 -0
- package/dist/tools/fs_edit/prompt.js +15 -0
- package/dist/tools/fs_glob/index.d.ts +1 -0
- package/dist/tools/fs_glob/index.js +60 -0
- package/dist/tools/fs_glob/prompt.d.ts +2 -0
- package/dist/tools/fs_glob/prompt.js +18 -0
- package/dist/tools/fs_grep/index.d.ts +1 -0
- package/dist/tools/fs_grep/index.js +66 -0
- package/dist/tools/fs_grep/prompt.d.ts +2 -0
- package/dist/tools/fs_grep/prompt.js +16 -0
- package/dist/tools/fs_multi_edit/index.d.ts +1 -0
- package/dist/tools/fs_multi_edit/index.js +106 -0
- package/dist/tools/fs_multi_edit/prompt.d.ts +2 -0
- package/dist/tools/fs_multi_edit/prompt.js +16 -0
- package/dist/tools/fs_read/index.d.ts +1 -0
- package/dist/tools/fs_read/index.js +40 -0
- package/dist/tools/fs_read/prompt.d.ts +2 -0
- package/dist/tools/fs_read/prompt.js +16 -0
- package/dist/tools/fs_rm/index.d.ts +1 -0
- package/dist/tools/fs_rm/index.js +41 -0
- package/dist/tools/fs_rm/prompt.d.ts +2 -0
- package/dist/tools/fs_rm/prompt.js +14 -0
- package/dist/tools/fs_write/index.d.ts +1 -0
- package/dist/tools/fs_write/index.js +40 -0
- package/dist/tools/fs_write/prompt.d.ts +2 -0
- package/dist/tools/fs_write/prompt.js +15 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.js +56 -0
- package/dist/tools/mcp.d.ts +73 -0
- package/dist/tools/mcp.js +198 -0
- package/dist/tools/registry.d.ts +29 -0
- package/dist/tools/registry.js +26 -0
- package/dist/tools/skill_activate/index.d.ts +5 -0
- package/dist/tools/skill_activate/index.js +63 -0
- package/dist/tools/skill_list/index.d.ts +5 -0
- package/dist/tools/skill_list/index.js +48 -0
- package/dist/tools/skill_resource/index.d.ts +5 -0
- package/dist/tools/skill_resource/index.js +82 -0
- package/dist/tools/task_run/index.d.ts +7 -0
- package/dist/tools/task_run/index.js +60 -0
- package/dist/tools/task_run/prompt.d.ts +5 -0
- package/dist/tools/task_run/prompt.js +29 -0
- package/dist/tools/todo_read/index.d.ts +1 -0
- package/dist/tools/todo_read/index.js +29 -0
- package/dist/tools/todo_read/prompt.d.ts +2 -0
- package/dist/tools/todo_read/prompt.js +18 -0
- package/dist/tools/todo_write/index.d.ts +1 -0
- package/dist/tools/todo_write/index.js +42 -0
- package/dist/tools/todo_write/prompt.d.ts +2 -0
- package/dist/tools/todo_write/prompt.js +23 -0
- package/dist/tools/tool.d.ts +43 -0
- package/dist/tools/tool.js +104 -0
- package/dist/tools/toolkit.d.ts +69 -0
- package/dist/tools/toolkit.js +98 -0
- package/dist/tools/type-inference.d.ts +127 -0
- package/dist/tools/type-inference.js +207 -0
- package/dist/utils/agent-id.d.ts +1 -0
- package/dist/utils/agent-id.js +28 -0
- package/dist/utils/session-id.d.ts +21 -0
- package/dist/utils/session-id.js +64 -0
- package/dist/utils/unicode.d.ts +17 -0
- package/dist/utils/unicode.js +62 -0
- package/package.json +117 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { SkillMetadata, SkillParseResult } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* SKILL.md 文件解析器
|
|
4
|
+
*
|
|
5
|
+
* 解析包含 YAML frontmatter 和 Markdown 正文的 SKILL.md 文件
|
|
6
|
+
*/
|
|
7
|
+
export declare class SkillsParser {
|
|
8
|
+
/**
|
|
9
|
+
* 解析 SKILL.md 文件内容
|
|
10
|
+
*
|
|
11
|
+
* @param content - SKILL.md 文件的完整内容
|
|
12
|
+
* @returns 解析后的元数据和正文
|
|
13
|
+
* @throws 如果格式无效
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const parser = new SkillsParser();
|
|
18
|
+
* const result = parser.parse(`---
|
|
19
|
+
* name: my-skill
|
|
20
|
+
* description: A helpful skill
|
|
21
|
+
* ---
|
|
22
|
+
*
|
|
23
|
+
* # My Skill
|
|
24
|
+
*
|
|
25
|
+
* Instructions here...
|
|
26
|
+
* `);
|
|
27
|
+
* console.log(result.metadata.name); // 'my-skill'
|
|
28
|
+
* console.log(result.body); // '# My Skill\n\nInstructions here...'
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
parse(content: string): SkillParseResult;
|
|
32
|
+
/**
|
|
33
|
+
* 检查内容是否是有效的 SKILL.md 格式(不抛出异常)
|
|
34
|
+
*/
|
|
35
|
+
isValid(content: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* 仅提取元数据(不解析完整正文,用于快速发现)
|
|
38
|
+
*/
|
|
39
|
+
parseMetadataOnly(content: string): SkillMetadata;
|
|
40
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
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.SkillsParser = void 0;
|
|
7
|
+
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
8
|
+
/**
|
|
9
|
+
* SKILL.md 文件解析器
|
|
10
|
+
*
|
|
11
|
+
* 解析包含 YAML frontmatter 和 Markdown 正文的 SKILL.md 文件
|
|
12
|
+
*/
|
|
13
|
+
class SkillsParser {
|
|
14
|
+
/**
|
|
15
|
+
* 解析 SKILL.md 文件内容
|
|
16
|
+
*
|
|
17
|
+
* @param content - SKILL.md 文件的完整内容
|
|
18
|
+
* @returns 解析后的元数据和正文
|
|
19
|
+
* @throws 如果格式无效
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const parser = new SkillsParser();
|
|
24
|
+
* const result = parser.parse(`---
|
|
25
|
+
* name: my-skill
|
|
26
|
+
* description: A helpful skill
|
|
27
|
+
* ---
|
|
28
|
+
*
|
|
29
|
+
* # My Skill
|
|
30
|
+
*
|
|
31
|
+
* Instructions here...
|
|
32
|
+
* `);
|
|
33
|
+
* console.log(result.metadata.name); // 'my-skill'
|
|
34
|
+
* console.log(result.body); // '# My Skill\n\nInstructions here...'
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
parse(content) {
|
|
38
|
+
// 匹配 YAML frontmatter: ---\n...\n---\n
|
|
39
|
+
const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
|
|
40
|
+
const match = content.match(frontmatterRegex);
|
|
41
|
+
if (!match) {
|
|
42
|
+
throw new Error('Invalid SKILL.md format: missing YAML frontmatter. ' +
|
|
43
|
+
'File must start with --- followed by YAML content and another ---');
|
|
44
|
+
}
|
|
45
|
+
const [, frontmatterYaml, body] = match;
|
|
46
|
+
let frontmatter;
|
|
47
|
+
try {
|
|
48
|
+
frontmatter = js_yaml_1.default.load(frontmatterYaml);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
throw new Error(`Invalid YAML frontmatter: ${error.message}`);
|
|
52
|
+
}
|
|
53
|
+
if (!frontmatter || typeof frontmatter !== 'object') {
|
|
54
|
+
throw new Error('Invalid YAML frontmatter: must be an object');
|
|
55
|
+
}
|
|
56
|
+
// 验证必需字段
|
|
57
|
+
if (!frontmatter.name || typeof frontmatter.name !== 'string') {
|
|
58
|
+
throw new Error('Invalid SKILL.md: missing or invalid "name" field');
|
|
59
|
+
}
|
|
60
|
+
if (!frontmatter.description || typeof frontmatter.description !== 'string') {
|
|
61
|
+
throw new Error('Invalid SKILL.md: missing or invalid "description" field');
|
|
62
|
+
}
|
|
63
|
+
// 解析 allowed-tools(支持字符串和数组格式)
|
|
64
|
+
let allowedTools;
|
|
65
|
+
if (frontmatter['allowed-tools']) {
|
|
66
|
+
const raw = frontmatter['allowed-tools'];
|
|
67
|
+
if (typeof raw === 'string') {
|
|
68
|
+
// 解析空格分隔的工具列表,如 "Bash(git:*) Bash(jq:*) Read"
|
|
69
|
+
allowedTools = raw.split(/\s+/).filter(Boolean);
|
|
70
|
+
}
|
|
71
|
+
else if (Array.isArray(raw)) {
|
|
72
|
+
allowedTools = raw.map(String);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const metadata = {
|
|
76
|
+
name: frontmatter.name,
|
|
77
|
+
description: frontmatter.description,
|
|
78
|
+
license: frontmatter.license,
|
|
79
|
+
compatibility: frontmatter.compatibility,
|
|
80
|
+
allowedTools,
|
|
81
|
+
metadata: frontmatter.metadata,
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
metadata,
|
|
85
|
+
body: body.trim(),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 检查内容是否是有效的 SKILL.md 格式(不抛出异常)
|
|
90
|
+
*/
|
|
91
|
+
isValid(content) {
|
|
92
|
+
try {
|
|
93
|
+
this.parse(content);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 仅提取元数据(不解析完整正文,用于快速发现)
|
|
102
|
+
*/
|
|
103
|
+
parseMetadataOnly(content) {
|
|
104
|
+
return this.parse(content).metadata;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
exports.SkillsParser = SkillsParser;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Skills 类型定义
|
|
3
|
+
*
|
|
4
|
+
* 基于 Agent Skills 开放标准 (https://agentskills.io)
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* SKILL.md frontmatter 元数据
|
|
8
|
+
*/
|
|
9
|
+
export interface SkillMetadata {
|
|
10
|
+
/** 技能名称,必需,1-64 字符,kebab-case 格式 */
|
|
11
|
+
name: string;
|
|
12
|
+
/** 技能描述,必需,1-1024 字符 */
|
|
13
|
+
description: string;
|
|
14
|
+
/** 许可证,如 "Apache-2.0" */
|
|
15
|
+
license?: string;
|
|
16
|
+
/** 兼容性说明,如 "claude-3.5-sonnet, gpt-4" */
|
|
17
|
+
compatibility?: string;
|
|
18
|
+
/** 允许使用的工具列表 */
|
|
19
|
+
allowedTools?: string[];
|
|
20
|
+
/** 自定义元数据 */
|
|
21
|
+
metadata?: Record<string, any>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Skill 资源目录
|
|
25
|
+
*/
|
|
26
|
+
export interface SkillResources {
|
|
27
|
+
/** 可执行脚本文件列表 */
|
|
28
|
+
scripts?: string[];
|
|
29
|
+
/** 参考文档列表 */
|
|
30
|
+
references?: string[];
|
|
31
|
+
/** 资源文件列表(模板、图标等) */
|
|
32
|
+
assets?: string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 完整 Skill 定义
|
|
36
|
+
*/
|
|
37
|
+
export interface Skill extends SkillMetadata {
|
|
38
|
+
/** Skill 目录绝对路径 */
|
|
39
|
+
path: string;
|
|
40
|
+
/** SKILL.md Markdown 内容(激活后加载) */
|
|
41
|
+
body?: string;
|
|
42
|
+
/** 资源目录内容 */
|
|
43
|
+
resources?: SkillResources;
|
|
44
|
+
/** 解析时间戳 */
|
|
45
|
+
loadedAt?: number;
|
|
46
|
+
/** 激活时间戳 */
|
|
47
|
+
activatedAt?: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Skills 配置
|
|
51
|
+
*/
|
|
52
|
+
export interface SkillsConfig {
|
|
53
|
+
/** Skills 搜索路径列表 */
|
|
54
|
+
paths: string[];
|
|
55
|
+
/** 白名单:只加载这些 Skills */
|
|
56
|
+
include?: string[];
|
|
57
|
+
/** 黑名单:排除这些 Skills */
|
|
58
|
+
exclude?: string[];
|
|
59
|
+
/** 可信来源:允许执行脚本的 Skills */
|
|
60
|
+
trusted?: string[];
|
|
61
|
+
/** 是否在加载时验证格式 */
|
|
62
|
+
validateOnLoad?: boolean;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Skill 激活记录
|
|
66
|
+
*/
|
|
67
|
+
export interface SkillActivation {
|
|
68
|
+
/** Skill 名称 */
|
|
69
|
+
name: string;
|
|
70
|
+
/** 激活时间戳 */
|
|
71
|
+
activatedAt: number;
|
|
72
|
+
/** 激活来源 */
|
|
73
|
+
activatedBy: 'auto' | 'agent' | 'user';
|
|
74
|
+
/** 被授权的工具列表 */
|
|
75
|
+
toolsGranted?: string[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Skills 运行时状态(用于持久化)
|
|
79
|
+
*/
|
|
80
|
+
export interface SkillsState {
|
|
81
|
+
/** 已发现的 Skill 名称列表 */
|
|
82
|
+
discovered: string[];
|
|
83
|
+
/** 已激活的 Skills */
|
|
84
|
+
activated: SkillActivation[];
|
|
85
|
+
/** 最后发现时间 */
|
|
86
|
+
lastDiscoveryAt: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Skill 解析结果
|
|
90
|
+
*/
|
|
91
|
+
export interface SkillParseResult {
|
|
92
|
+
/** 元数据 */
|
|
93
|
+
metadata: SkillMetadata;
|
|
94
|
+
/** Markdown 正文 */
|
|
95
|
+
body: string;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Skill 验证结果
|
|
99
|
+
*/
|
|
100
|
+
export interface SkillValidationResult {
|
|
101
|
+
/** 是否有效 */
|
|
102
|
+
valid: boolean;
|
|
103
|
+
/** 错误列表 */
|
|
104
|
+
errors: string[];
|
|
105
|
+
/** 警告列表 */
|
|
106
|
+
warnings?: string[];
|
|
107
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { SkillMetadata, SkillValidationResult, Skill } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Skill 格式验证器
|
|
4
|
+
*
|
|
5
|
+
* 根据 Agent Skills 规范验证 Skill 的格式和内容
|
|
6
|
+
*/
|
|
7
|
+
export declare class SkillsValidator {
|
|
8
|
+
/** name 字段的正则表达式:kebab-case,1-64 字符 */
|
|
9
|
+
private static readonly NAME_PATTERN;
|
|
10
|
+
/** name 最大长度 */
|
|
11
|
+
private static readonly NAME_MAX_LENGTH;
|
|
12
|
+
/** description 最大长度 */
|
|
13
|
+
private static readonly DESCRIPTION_MAX_LENGTH;
|
|
14
|
+
/**
|
|
15
|
+
* 验证 Skill 元数据
|
|
16
|
+
*/
|
|
17
|
+
validate(skill: Partial<SkillMetadata>): SkillValidationResult;
|
|
18
|
+
/**
|
|
19
|
+
* 验证完整 Skill(包括路径)
|
|
20
|
+
*/
|
|
21
|
+
validateFull(skill: Partial<Skill>): SkillValidationResult;
|
|
22
|
+
/**
|
|
23
|
+
* 验证 Skill 名称是否与目录名匹配
|
|
24
|
+
*/
|
|
25
|
+
validateNameMatchesDirectory(skillName: string, directoryPath: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* 快速检查是否有效
|
|
28
|
+
*/
|
|
29
|
+
isValid(skill: Partial<SkillMetadata>): boolean;
|
|
30
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SkillsValidator = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Skill 格式验证器
|
|
6
|
+
*
|
|
7
|
+
* 根据 Agent Skills 规范验证 Skill 的格式和内容
|
|
8
|
+
*/
|
|
9
|
+
class SkillsValidator {
|
|
10
|
+
/**
|
|
11
|
+
* 验证 Skill 元数据
|
|
12
|
+
*/
|
|
13
|
+
validate(skill) {
|
|
14
|
+
const errors = [];
|
|
15
|
+
const warnings = [];
|
|
16
|
+
// 验证 name
|
|
17
|
+
if (!skill.name) {
|
|
18
|
+
errors.push('Missing required field: name');
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
if (typeof skill.name !== 'string') {
|
|
22
|
+
errors.push('Field "name" must be a string');
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
if (skill.name.length > SkillsValidator.NAME_MAX_LENGTH) {
|
|
26
|
+
errors.push(`Field "name" exceeds maximum length of ${SkillsValidator.NAME_MAX_LENGTH} characters`);
|
|
27
|
+
}
|
|
28
|
+
if (!SkillsValidator.NAME_PATTERN.test(skill.name)) {
|
|
29
|
+
errors.push('Field "name" must be kebab-case (lowercase alphanumeric with hyphens, ' +
|
|
30
|
+
'e.g., "my-skill-name"). Cannot start or end with hyphen.');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// 验证 description
|
|
35
|
+
if (!skill.description) {
|
|
36
|
+
errors.push('Missing required field: description');
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
if (typeof skill.description !== 'string') {
|
|
40
|
+
errors.push('Field "description" must be a string');
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
if (skill.description.length === 0) {
|
|
44
|
+
errors.push('Field "description" cannot be empty');
|
|
45
|
+
}
|
|
46
|
+
if (skill.description.length > SkillsValidator.DESCRIPTION_MAX_LENGTH) {
|
|
47
|
+
errors.push(`Field "description" exceeds maximum length of ${SkillsValidator.DESCRIPTION_MAX_LENGTH} characters`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// 验证可选字段
|
|
52
|
+
if (skill.license !== undefined && typeof skill.license !== 'string') {
|
|
53
|
+
errors.push('Field "license" must be a string');
|
|
54
|
+
}
|
|
55
|
+
if (skill.compatibility !== undefined && typeof skill.compatibility !== 'string') {
|
|
56
|
+
errors.push('Field "compatibility" must be a string');
|
|
57
|
+
}
|
|
58
|
+
if (skill.allowedTools !== undefined) {
|
|
59
|
+
if (!Array.isArray(skill.allowedTools)) {
|
|
60
|
+
errors.push('Field "allowedTools" must be an array of strings');
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
for (let i = 0; i < skill.allowedTools.length; i++) {
|
|
64
|
+
if (typeof skill.allowedTools[i] !== 'string') {
|
|
65
|
+
errors.push(`Field "allowedTools[${i}]" must be a string`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (skill.metadata !== undefined) {
|
|
71
|
+
if (typeof skill.metadata !== 'object' || skill.metadata === null || Array.isArray(skill.metadata)) {
|
|
72
|
+
errors.push('Field "metadata" must be an object');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// 警告:描述过短
|
|
76
|
+
if (skill.description && skill.description.length < 20) {
|
|
77
|
+
warnings.push('Description is very short. Consider providing more detail for better skill matching.');
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
valid: errors.length === 0,
|
|
81
|
+
errors,
|
|
82
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 验证完整 Skill(包括路径)
|
|
87
|
+
*/
|
|
88
|
+
validateFull(skill) {
|
|
89
|
+
const baseResult = this.validate(skill);
|
|
90
|
+
if (!skill.path) {
|
|
91
|
+
baseResult.errors.push('Missing required field: path');
|
|
92
|
+
baseResult.valid = false;
|
|
93
|
+
}
|
|
94
|
+
else if (typeof skill.path !== 'string') {
|
|
95
|
+
baseResult.errors.push('Field "path" must be a string');
|
|
96
|
+
baseResult.valid = false;
|
|
97
|
+
}
|
|
98
|
+
return baseResult;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 验证 Skill 名称是否与目录名匹配
|
|
102
|
+
*/
|
|
103
|
+
validateNameMatchesDirectory(skillName, directoryPath) {
|
|
104
|
+
const path = require('path');
|
|
105
|
+
const dirName = path.basename(directoryPath);
|
|
106
|
+
return skillName === dirName;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 快速检查是否有效
|
|
110
|
+
*/
|
|
111
|
+
isValid(skill) {
|
|
112
|
+
return this.validate(skill).valid;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.SkillsValidator = SkillsValidator;
|
|
116
|
+
/** name 字段的正则表达式:kebab-case,1-64 字符 */
|
|
117
|
+
SkillsValidator.NAME_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
118
|
+
/** name 最大长度 */
|
|
119
|
+
SkillsValidator.NAME_MAX_LENGTH = 64;
|
|
120
|
+
/** description 最大长度 */
|
|
121
|
+
SkillsValidator.DESCRIPTION_MAX_LENGTH = 1024;
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Store, JSONStore, HistoryWindow, CompressionRecord, RecoveredFile, } from './infra/store';
|
package/dist/store.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BashKill: import("..").ToolInstance;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BashKill = void 0;
|
|
4
|
+
const tool_1 = require("../tool");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const prompt_1 = require("./prompt");
|
|
7
|
+
const bash_run_1 = require("../bash_run");
|
|
8
|
+
exports.BashKill = (0, tool_1.tool)({
|
|
9
|
+
name: 'bash_kill',
|
|
10
|
+
description: prompt_1.DESCRIPTION,
|
|
11
|
+
parameters: zod_1.z.object({
|
|
12
|
+
shell_id: zod_1.z.string().describe('Shell ID from bash_run'),
|
|
13
|
+
}),
|
|
14
|
+
async execute(args) {
|
|
15
|
+
const { shell_id } = args;
|
|
16
|
+
const proc = bash_run_1.processes.get(shell_id);
|
|
17
|
+
if (!proc) {
|
|
18
|
+
return {
|
|
19
|
+
ok: false,
|
|
20
|
+
error: `Shell not found: ${shell_id}`,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
bash_run_1.processes.delete(shell_id);
|
|
24
|
+
return {
|
|
25
|
+
ok: true,
|
|
26
|
+
shell_id,
|
|
27
|
+
message: `Killed shell ${shell_id}`,
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
metadata: {
|
|
31
|
+
readonly: false,
|
|
32
|
+
version: '1.0',
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
exports.BashKill.prompt = prompt_1.PROMPT;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const DESCRIPTION = "Kill a background bash shell";
|
|
2
|
+
export declare const PROMPT = "Terminate a long-running background bash session identified by shell_id.\n\nGuidelines:\n- Use this to clean up stuck processes.\n- Provide the shell_id from bash_run to terminate that specific process.\n- Once killed, the process cannot be restarted or accessed.\n\nSafety/Limitations:\n- Only background processes started in the current session can be killed.\n- Force termination may leave incomplete work or locks.";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROMPT = exports.DESCRIPTION = void 0;
|
|
4
|
+
exports.DESCRIPTION = 'Kill a background bash shell';
|
|
5
|
+
exports.PROMPT = `Terminate a long-running background bash session identified by shell_id.
|
|
6
|
+
|
|
7
|
+
Guidelines:
|
|
8
|
+
- Use this to clean up stuck processes.
|
|
9
|
+
- Provide the shell_id from bash_run to terminate that specific process.
|
|
10
|
+
- Once killed, the process cannot be restarted or accessed.
|
|
11
|
+
|
|
12
|
+
Safety/Limitations:
|
|
13
|
+
- Only background processes started in the current session can be killed.
|
|
14
|
+
- Force termination may leave incomplete work or locks.`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BashLogs: import("..").ToolInstance;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BashLogs = void 0;
|
|
4
|
+
const tool_1 = require("../tool");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const prompt_1 = require("./prompt");
|
|
7
|
+
const bash_run_1 = require("../bash_run");
|
|
8
|
+
exports.BashLogs = (0, tool_1.tool)({
|
|
9
|
+
name: 'bash_logs',
|
|
10
|
+
description: prompt_1.DESCRIPTION,
|
|
11
|
+
parameters: zod_1.z.object({
|
|
12
|
+
shell_id: zod_1.z.string().describe('Shell ID from bash_run'),
|
|
13
|
+
}),
|
|
14
|
+
async execute(args) {
|
|
15
|
+
const { shell_id } = args;
|
|
16
|
+
const proc = bash_run_1.processes.get(shell_id);
|
|
17
|
+
if (!proc) {
|
|
18
|
+
return {
|
|
19
|
+
ok: false,
|
|
20
|
+
error: `Shell not found: ${shell_id}`,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const isRunning = proc.code === undefined;
|
|
24
|
+
const status = isRunning ? 'running' : `completed (exit code ${proc.code})`;
|
|
25
|
+
const output = [proc.stdout, proc.stderr].filter(Boolean).join('\n').trim();
|
|
26
|
+
return {
|
|
27
|
+
ok: true,
|
|
28
|
+
shell_id,
|
|
29
|
+
status,
|
|
30
|
+
running: isRunning,
|
|
31
|
+
code: proc.code,
|
|
32
|
+
output: output || '(no output yet)',
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
metadata: {
|
|
36
|
+
readonly: true,
|
|
37
|
+
version: '1.0',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
exports.BashLogs.prompt = prompt_1.PROMPT;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const DESCRIPTION = "Get output from a background bash shell";
|
|
2
|
+
export declare const PROMPT = "Fetch stdout/stderr from a background bash session started via bash_run with \"background\": true.\n\nGuidelines:\n- Provide the shell_id returned by bash_run to retrieve incremental logs.\n- Check the status to see if the process is still running or completed.\n- Output includes both stdout and stderr streams.\n\nSafety/Limitations:\n- Only processes started in the current session are accessible.\n- Process history is not persisted across SDK restarts.";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROMPT = exports.DESCRIPTION = void 0;
|
|
4
|
+
exports.DESCRIPTION = 'Get output from a background bash shell';
|
|
5
|
+
exports.PROMPT = `Fetch stdout/stderr from a background bash session started via bash_run with "background": true.
|
|
6
|
+
|
|
7
|
+
Guidelines:
|
|
8
|
+
- Provide the shell_id returned by bash_run to retrieve incremental logs.
|
|
9
|
+
- Check the status to see if the process is still running or completed.
|
|
10
|
+
- Output includes both stdout and stderr streams.
|
|
11
|
+
|
|
12
|
+
Safety/Limitations:
|
|
13
|
+
- Only processes started in the current session are accessible.
|
|
14
|
+
- Process history is not persisted across SDK restarts.`;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface BashProcess {
|
|
2
|
+
id: string;
|
|
3
|
+
cmd: string;
|
|
4
|
+
startTime: number;
|
|
5
|
+
promise: Promise<{
|
|
6
|
+
code: number;
|
|
7
|
+
stdout: string;
|
|
8
|
+
stderr: string;
|
|
9
|
+
}>;
|
|
10
|
+
stdout: string;
|
|
11
|
+
stderr: string;
|
|
12
|
+
code?: number;
|
|
13
|
+
}
|
|
14
|
+
declare const processes: Map<string, BashProcess>;
|
|
15
|
+
export declare const BashRun: import("..").ToolInstance;
|
|
16
|
+
export { processes };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processes = exports.BashRun = void 0;
|
|
4
|
+
const tool_1 = require("../tool");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const type_inference_1 = require("../type-inference");
|
|
7
|
+
const prompt_1 = require("./prompt");
|
|
8
|
+
const processes = new Map();
|
|
9
|
+
exports.processes = processes;
|
|
10
|
+
exports.BashRun = (0, tool_1.tool)({
|
|
11
|
+
name: 'bash_run',
|
|
12
|
+
description: prompt_1.DESCRIPTION,
|
|
13
|
+
parameters: zod_1.z.object({
|
|
14
|
+
cmd: zod_1.z.string().describe('Command to execute'),
|
|
15
|
+
timeout_ms: type_inference_1.patterns.optionalNumber('Timeout in milliseconds (default: 120000)'),
|
|
16
|
+
background: zod_1.z.boolean().optional().describe('Run in background and return shell_id'),
|
|
17
|
+
}),
|
|
18
|
+
async execute(args, ctx) {
|
|
19
|
+
const { cmd, timeout_ms = 120000, background = false } = args;
|
|
20
|
+
if (background) {
|
|
21
|
+
const id = `shell-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
22
|
+
const promise = ctx.sandbox.exec(cmd, { timeoutMs: timeout_ms });
|
|
23
|
+
const proc = {
|
|
24
|
+
id,
|
|
25
|
+
cmd,
|
|
26
|
+
startTime: Date.now(),
|
|
27
|
+
promise,
|
|
28
|
+
stdout: '',
|
|
29
|
+
stderr: '',
|
|
30
|
+
};
|
|
31
|
+
processes.set(id, proc);
|
|
32
|
+
promise.then((result) => {
|
|
33
|
+
proc.code = result.code;
|
|
34
|
+
proc.stdout = result.stdout;
|
|
35
|
+
proc.stderr = result.stderr;
|
|
36
|
+
}).catch((error) => {
|
|
37
|
+
proc.code = -1;
|
|
38
|
+
proc.stderr = error?.message || String(error);
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
background: true,
|
|
42
|
+
shell_id: id,
|
|
43
|
+
message: `Background shell started: ${id}`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const result = await ctx.sandbox.exec(cmd, { timeoutMs: timeout_ms });
|
|
48
|
+
const output = [result.stdout, result.stderr].filter(Boolean).join('\n').trim();
|
|
49
|
+
return {
|
|
50
|
+
background: false,
|
|
51
|
+
code: result.code,
|
|
52
|
+
output: output || '(no output)',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
metadata: {
|
|
57
|
+
readonly: false,
|
|
58
|
+
version: '1.0',
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
exports.BashRun.prompt = prompt_1.PROMPT;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const DESCRIPTION = "Execute a bash command";
|
|
2
|
+
export declare const PROMPT = "Execute shell commands inside the sandbox environment.\n\nGuidelines:\n- Commands run with the sandbox's working directory and limited privileges.\n- Capture output responsibly; large outputs are truncated and saved to temp files.\n- Respect project policies: use fs_read for inspections where possible.\n- Request approval when running high-impact commands if required by policy.\n- Set \"background\" to true to run long-running processes and poll with bash_logs.\n\nSafety/Limitations:\n- Commands are sandboxed and cannot escape the workspace.\n- Dangerous commands may be blocked for security.\n- Timeout defaults to 120 seconds but can be configured.\n- Background processes must be explicitly killed with bash_kill.";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROMPT = exports.DESCRIPTION = void 0;
|
|
4
|
+
exports.DESCRIPTION = 'Execute a bash command';
|
|
5
|
+
exports.PROMPT = `Execute shell commands inside the sandbox environment.
|
|
6
|
+
|
|
7
|
+
Guidelines:
|
|
8
|
+
- Commands run with the sandbox's working directory and limited privileges.
|
|
9
|
+
- Capture output responsibly; large outputs are truncated and saved to temp files.
|
|
10
|
+
- Respect project policies: use fs_read for inspections where possible.
|
|
11
|
+
- Request approval when running high-impact commands if required by policy.
|
|
12
|
+
- Set "background" to true to run long-running processes and poll with bash_logs.
|
|
13
|
+
|
|
14
|
+
Safety/Limitations:
|
|
15
|
+
- Commands are sandboxed and cannot escape the workspace.
|
|
16
|
+
- Dangerous commands may be blocked for security.
|
|
17
|
+
- Timeout defaults to 120 seconds but can be configured.
|
|
18
|
+
- Background processes must be explicitly killed with bash_kill.`;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ToolInstance } from './registry';
|
|
2
|
+
import { AgentTemplate } from './task_run';
|
|
3
|
+
export declare const builtin: {
|
|
4
|
+
fs: () => ToolInstance[];
|
|
5
|
+
bash: () => ToolInstance[];
|
|
6
|
+
todo: () => ToolInstance[];
|
|
7
|
+
task: (templates?: AgentTemplate[]) => ToolInstance | null;
|
|
8
|
+
};
|
|
9
|
+
export { AgentTemplate };
|