@shareai-lab/kode-sdk 2.7.2 → 2.7.4

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.
@@ -14,6 +14,7 @@ export declare class SkillsManager {
14
14
  private skillsDir;
15
15
  private cache;
16
16
  private allowedSkills?;
17
+ private skillsDisabled;
17
18
  constructor(skillsDir?: string, allowedSkills?: string[]);
18
19
  /**
19
20
  * 扫描skills目录(支持热更新)
@@ -30,10 +31,13 @@ export declare class SkillsManager {
30
31
  loadSkillContent(skillName: string): Promise<SkillContent | null>;
31
32
  /**
32
33
  * 递归扫描目录,查找所有SKILL.md
34
+ * 返回格式: { skillMdPath: string, folderName: string }[]
33
35
  */
34
36
  private scanDirectory;
35
37
  /**
36
38
  * 解析SKILL.md,提取元数据
39
+ * @param skillMdPath SKILL.md文件的完整路径
40
+ * @param folderName 技能文件夹名称(作为技能标识符)
37
41
  */
38
42
  private parseSkillMetadata;
39
43
  /**
@@ -51,17 +51,35 @@ const logger_1 = require("../../utils/logger");
51
51
  class SkillsManager {
52
52
  constructor(skillsDir, allowedSkills) {
53
53
  this.cache = new Map();
54
+ this.skillsDisabled = false;
54
55
  // 优先使用传入的路径,其次使用环境变量,最后使用默认路径
55
- // 默认路径:程序当前工作目录下的 skills/
56
+ // 默认路径:程序当前工作目录下的 .skills/
56
57
  const envSkillsDir = process.env.SKILLS_DIR;
57
- const defaultSkillsDir = path.join(process.cwd(), 'skills');
58
+ const defaultSkillsDir = path.join(process.cwd(), '.skills');
58
59
  this.skillsDir = path.resolve(skillsDir ||
59
60
  envSkillsDir ||
60
61
  defaultSkillsDir);
61
62
  // 设置允许加载的 skills 白名单
62
- this.allowedSkills = allowedSkills;
63
+ // 特殊处理:
64
+ // 1. 如果白名单包含 "/*/",则完全禁用技能功能
65
+ // 2. 如果白名单包含"*",则视为未设置白名单(加载所有技能)
66
+ if (allowedSkills && allowedSkills.length === 1 && allowedSkills[0] === '/*/') {
67
+ this.skillsDisabled = true;
68
+ this.allowedSkills = [];
69
+ logger_1.logger.log(`[SkillsManager] Skills disabled (whitelist is "/*/")`);
70
+ }
71
+ else if (allowedSkills && allowedSkills.length === 1 && allowedSkills[0] === '*') {
72
+ this.allowedSkills = undefined;
73
+ logger_1.logger.log(`[SkillsManager] Whitelist contains "*", loading all skills`);
74
+ }
75
+ else {
76
+ this.allowedSkills = allowedSkills;
77
+ }
63
78
  logger_1.logger.log(`[SkillsManager] Initialized with skills directory: ${this.skillsDir}`);
64
- if (this.allowedSkills) {
79
+ if (this.skillsDisabled) {
80
+ logger_1.logger.log(`[SkillsManager] Skills feature is disabled`);
81
+ }
82
+ else if (this.allowedSkills) {
65
83
  logger_1.logger.log(`[SkillsManager] Allowed skills whitelist: ${this.allowedSkills.join(', ')}`);
66
84
  }
67
85
  }
@@ -70,6 +88,11 @@ class SkillsManager {
70
88
  * 每次调用时重新扫描,确保读取最新数据
71
89
  */
72
90
  async scan() {
91
+ // 如果技能功能被禁用,直接返回空数组
92
+ if (this.skillsDisabled) {
93
+ logger_1.logger.log(`[SkillsManager] Skills disabled, skipping scan`);
94
+ return [];
95
+ }
73
96
  // 清空缓存
74
97
  this.cache.clear();
75
98
  try {
@@ -83,7 +106,7 @@ class SkillsManager {
83
106
  const entries = await this.scanDirectory(this.skillsDir);
84
107
  // 提取每个skill的元数据
85
108
  for (const entry of entries) {
86
- const metadata = await this.parseSkillMetadata(entry);
109
+ const metadata = await this.parseSkillMetadata(entry.skillMdPath, entry.folderName);
87
110
  if (metadata) {
88
111
  // 如果设置了白名单,只加载白名单中的 skills
89
112
  if (this.allowedSkills) {
@@ -147,9 +170,10 @@ class SkillsManager {
147
170
  }
148
171
  /**
149
172
  * 递归扫描目录,查找所有SKILL.md
173
+ * 返回格式: { skillMdPath: string, folderName: string }[]
150
174
  */
151
175
  async scanDirectory(dir) {
152
- const skillFiles = [];
176
+ const skills = [];
153
177
  try {
154
178
  const entries = await fs.readdir(dir, { withFileTypes: true });
155
179
  for (const entry of entries) {
@@ -158,12 +182,13 @@ class SkillsManager {
158
182
  // 检查是否有SKILL.md
159
183
  const skillMdPath = path.join(fullPath, 'SKILL.md');
160
184
  if (await this.fileExists(skillMdPath)) {
161
- skillFiles.push(skillMdPath);
185
+ // 返回SKILL.md路径和文件夹名称
186
+ skills.push({ skillMdPath, folderName: entry.name });
162
187
  }
163
188
  else {
164
189
  // 递归扫描子目录
165
190
  const subSkills = await this.scanDirectory(fullPath);
166
- skillFiles.push(...subSkills);
191
+ skills.push(...subSkills);
167
192
  }
168
193
  }
169
194
  }
@@ -171,12 +196,14 @@ class SkillsManager {
171
196
  catch (error) {
172
197
  logger_1.logger.warn(`[SkillsManager] Error reading directory ${dir}:`, error.message);
173
198
  }
174
- return skillFiles;
199
+ return skills;
175
200
  }
176
201
  /**
177
202
  * 解析SKILL.md,提取元数据
203
+ * @param skillMdPath SKILL.md文件的完整路径
204
+ * @param folderName 技能文件夹名称(作为技能标识符)
178
205
  */
179
- async parseSkillMetadata(skillMdPath) {
206
+ async parseSkillMetadata(skillMdPath, folderName) {
180
207
  try {
181
208
  const content = await fs.readFile(skillMdPath, 'utf-8');
182
209
  // 提取YAML frontmatter
@@ -186,14 +213,10 @@ class SkillsManager {
186
213
  return null;
187
214
  }
188
215
  const yaml = match[1];
189
- const nameMatch = yaml.match(/^name:\s*(.+)$/m);
190
216
  const descMatch = yaml.match(/^description:\s*(.+)$/m);
191
- if (!nameMatch) {
192
- logger_1.logger.warn(`[SkillsManager] Invalid SKILL.md (missing name): ${skillMdPath}`);
193
- return null;
194
- }
217
+ // 使用文件夹名称作为技能标识符,而不是从YAML中读取name
195
218
  return {
196
- name: nameMatch[1].trim(),
219
+ name: folderName,
197
220
  description: descMatch ? descMatch[1].trim() : '',
198
221
  path: skillMdPath,
199
222
  baseDir: path.dirname(skillMdPath),
@@ -59,6 +59,8 @@ export interface SkillInfo {
59
59
  path: string;
60
60
  /** 技能根目录 */
61
61
  baseDir: string;
62
+ /** 文件夹名称(技能目录名) */
63
+ folderName: string;
62
64
  /** 创建时间 */
63
65
  createdAt?: string;
64
66
  /** 更新时间 */
@@ -115,6 +117,16 @@ export interface ArchivedSkillInfo {
115
117
  archivedName: string;
116
118
  /** archived目录中的完整路径 */
117
119
  archivedPath: string;
120
+ /** 文件夹名称(归档目录名) */
121
+ folderName: string;
118
122
  /** 归档时间 */
119
123
  archivedAt: string;
124
+ /** 技能名称(从SKILL.md解析) */
125
+ name?: string;
126
+ /** 技能描述(从SKILL.md解析) */
127
+ description?: string;
128
+ /** 许可证(从SKILL.md解析) */
129
+ license?: string;
130
+ /** 其他元数据 */
131
+ metadata?: Record<string, string>;
120
132
  }
@@ -18,7 +18,7 @@ export type ContentBlock = {
18
18
  tool_use_id: string;
19
19
  content: any;
20
20
  is_error?: boolean;
21
- } | ReasoningContentBlock | ImageContentBlock | AudioContentBlock | FileContentBlock;
21
+ } | ReasoningContentBlock | ImageContentBlock | AudioContentBlock | VideoContentBlock | FileContentBlock;
22
22
  export type ReasoningContentBlock = {
23
23
  type: 'reasoning';
24
24
  reasoning: string;
@@ -40,6 +40,14 @@ export type AudioContentBlock = {
40
40
  mime_type?: string;
41
41
  meta?: Record<string, any>;
42
42
  };
43
+ export type VideoContentBlock = {
44
+ type: 'video';
45
+ url?: string;
46
+ file_id?: string;
47
+ base64?: string;
48
+ mime_type?: string;
49
+ meta?: Record<string, any>;
50
+ };
43
51
  export type FileContentBlock = {
44
52
  type: 'file';
45
53
  url?: string;
package/dist/index.d.ts CHANGED
@@ -27,6 +27,8 @@ export { PostgresStore } from './infra/db/postgres/postgres-store';
27
27
  export { Sandbox, LocalSandbox, SandboxKind } from './infra/sandbox';
28
28
  export { E2BSandbox, E2BFS, E2BTemplateBuilder } from './infra/e2b';
29
29
  export type { E2BSandboxOptions, E2BTemplateConfig } from './infra/e2b';
30
+ export { OpenSandbox, OpenSandboxFS } from './infra/opensandbox';
31
+ export type { OpenSandboxOptions, OpenSandboxWatchMode } from './infra/opensandbox';
30
32
  export { ModelProvider, ModelConfig, ModelResponse, ModelStreamChunk, AnthropicProvider, OpenAIProvider, GeminiProvider, } from './infra/provider';
31
33
  export { SandboxFactory } from './infra/sandbox-factory';
32
34
  export { FsRead } from './tools/fs_read';
package/dist/index.js CHANGED
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.BashLogs = exports.BashRun = exports.FsMultiEdit = exports.FsGrep = exports.FsGlob = exports.FsEdit = exports.FsWrite = exports.FsRead = exports.SandboxFactory = exports.GeminiProvider = exports.OpenAIProvider = exports.AnthropicProvider = exports.E2BTemplateBuilder = exports.E2BFS = exports.E2BSandbox = exports.LocalSandbox = exports.PostgresStore = exports.SqliteStore = exports.createExtendedStore = exports.createStore = exports.JSONStore = exports.ProviderCapabilityError = exports.UnsupportedProviderError = exports.UnsupportedContentBlockError = exports.MultimodalValidationError = exports.ResumeError = exports.PermissionModeRegistry = exports.permissionModes = exports.ToolRunner = exports.TodoManager = exports.MessageQueue = exports.PermissionManager = exports.BreakpointManager = exports.SandboxFileManager = exports.OperationStatus = exports.OperationType = exports.OperationQueue = exports.SkillsManagementManager = exports.SkillsManager = exports.TimeBridge = exports.TodoService = exports.AgentTemplateRegistry = exports.FilePool = exports.ContextManager = exports.HookManager = exports.EventBus = exports.Scheduler = exports.Room = exports.AgentPool = exports.Agent = void 0;
18
- exports.generateAgentId = exports.extendSchema = exports.mergeSchemas = exports.SchemaBuilder = exports.patterns = exports.schema = exports.inferFromExample = exports.createScriptsTool = exports.createSkillsTool = exports.toolMethod = exports.ToolKit = exports.disconnectAllMCP = exports.disconnectMCP = exports.getMCPTools = exports.tools = exports.tool = exports.extractTools = exports.defineTools = exports.defineTool = exports.globalToolRegistry = exports.ToolRegistry = exports.builtin = exports.TodoWrite = exports.TodoRead = exports.createTaskRunTool = exports.BashKill = void 0;
17
+ exports.FsMultiEdit = exports.FsGrep = exports.FsGlob = exports.FsEdit = exports.FsWrite = exports.FsRead = exports.SandboxFactory = exports.GeminiProvider = exports.OpenAIProvider = exports.AnthropicProvider = exports.OpenSandboxFS = exports.OpenSandbox = exports.E2BTemplateBuilder = exports.E2BFS = exports.E2BSandbox = exports.LocalSandbox = exports.PostgresStore = exports.SqliteStore = exports.createExtendedStore = exports.createStore = exports.JSONStore = exports.ProviderCapabilityError = exports.UnsupportedProviderError = exports.UnsupportedContentBlockError = exports.MultimodalValidationError = exports.ResumeError = exports.PermissionModeRegistry = exports.permissionModes = exports.ToolRunner = exports.TodoManager = exports.MessageQueue = exports.PermissionManager = exports.BreakpointManager = exports.SandboxFileManager = exports.OperationStatus = exports.OperationType = exports.OperationQueue = exports.SkillsManagementManager = exports.SkillsManager = exports.TimeBridge = exports.TodoService = exports.AgentTemplateRegistry = exports.FilePool = exports.ContextManager = exports.HookManager = exports.EventBus = exports.Scheduler = exports.Room = exports.AgentPool = exports.Agent = void 0;
18
+ exports.generateAgentId = exports.extendSchema = exports.mergeSchemas = exports.SchemaBuilder = exports.patterns = exports.schema = exports.inferFromExample = exports.createScriptsTool = exports.createSkillsTool = exports.toolMethod = exports.ToolKit = exports.disconnectAllMCP = exports.disconnectMCP = exports.getMCPTools = exports.tools = exports.tool = exports.extractTools = exports.defineTools = exports.defineTool = exports.globalToolRegistry = exports.ToolRegistry = exports.builtin = exports.TodoWrite = exports.TodoRead = exports.createTaskRunTool = exports.BashKill = exports.BashLogs = exports.BashRun = void 0;
19
19
  // Core
20
20
  var agent_1 = require("./core/agent");
21
21
  Object.defineProperty(exports, "Agent", { enumerable: true, get: function () { return agent_1.Agent; } });
@@ -84,6 +84,9 @@ var e2b_1 = require("./infra/e2b");
84
84
  Object.defineProperty(exports, "E2BSandbox", { enumerable: true, get: function () { return e2b_1.E2BSandbox; } });
85
85
  Object.defineProperty(exports, "E2BFS", { enumerable: true, get: function () { return e2b_1.E2BFS; } });
86
86
  Object.defineProperty(exports, "E2BTemplateBuilder", { enumerable: true, get: function () { return e2b_1.E2BTemplateBuilder; } });
87
+ var opensandbox_1 = require("./infra/opensandbox");
88
+ Object.defineProperty(exports, "OpenSandbox", { enumerable: true, get: function () { return opensandbox_1.OpenSandbox; } });
89
+ Object.defineProperty(exports, "OpenSandboxFS", { enumerable: true, get: function () { return opensandbox_1.OpenSandboxFS; } });
87
90
  var provider_1 = require("./infra/provider");
88
91
  Object.defineProperty(exports, "AnthropicProvider", { enumerable: true, get: function () { return provider_1.AnthropicProvider; } });
89
92
  Object.defineProperty(exports, "OpenAIProvider", { enumerable: true, get: function () { return provider_1.OpenAIProvider; } });
@@ -0,0 +1,3 @@
1
+ export { OpenSandbox } from './opensandbox-sandbox';
2
+ export { OpenSandboxFS } from './opensandbox-fs';
3
+ export type { OpenSandboxOptions, OpenSandboxWatchMode } from './types';
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpenSandboxFS = exports.OpenSandbox = void 0;
4
+ var opensandbox_sandbox_1 = require("./opensandbox-sandbox");
5
+ Object.defineProperty(exports, "OpenSandbox", { enumerable: true, get: function () { return opensandbox_sandbox_1.OpenSandbox; } });
6
+ var opensandbox_fs_1 = require("./opensandbox-fs");
7
+ Object.defineProperty(exports, "OpenSandboxFS", { enumerable: true, get: function () { return opensandbox_fs_1.OpenSandboxFS; } });
@@ -0,0 +1,27 @@
1
+ import type { Sandbox as OpenSandboxClient } from '@alibaba-group/opensandbox';
2
+ import { SandboxFS } from '../sandbox';
3
+ export interface OpenSandboxFSHost {
4
+ workDir: string;
5
+ getOpenSandbox(): OpenSandboxClient;
6
+ }
7
+ export declare class OpenSandboxFS implements SandboxFS {
8
+ private readonly host;
9
+ constructor(host: OpenSandboxFSHost);
10
+ resolve(p: string): string;
11
+ isInside(_p: string): boolean;
12
+ read(p: string): Promise<string>;
13
+ write(p: string, content: string): Promise<void>;
14
+ temp(name?: string): string;
15
+ stat(p: string): Promise<{
16
+ mtimeMs: number;
17
+ }>;
18
+ glob(pattern: string, opts?: {
19
+ cwd?: string;
20
+ ignore?: string[];
21
+ dot?: boolean;
22
+ absolute?: boolean;
23
+ }): Promise<string[]>;
24
+ private hasDotPath;
25
+ private toTimestamp;
26
+ private matchGlob;
27
+ }
@@ -0,0 +1,113 @@
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.OpenSandboxFS = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const minimatch_1 = require("minimatch");
9
+ class OpenSandboxFS {
10
+ constructor(host) {
11
+ this.host = host;
12
+ }
13
+ resolve(p) {
14
+ if (path_1.default.posix.isAbsolute(p))
15
+ return path_1.default.posix.normalize(p);
16
+ return path_1.default.posix.normalize(path_1.default.posix.join(this.host.workDir, p));
17
+ }
18
+ isInside(_p) {
19
+ // OpenSandbox runtime is already isolated at container/sandbox level.
20
+ return true;
21
+ }
22
+ async read(p) {
23
+ const sandbox = this.host.getOpenSandbox();
24
+ const resolved = this.resolve(p);
25
+ return await sandbox.files.readFile(resolved);
26
+ }
27
+ async write(p, content) {
28
+ const sandbox = this.host.getOpenSandbox();
29
+ const resolved = this.resolve(p);
30
+ const dir = path_1.default.posix.dirname(resolved);
31
+ if (dir && dir !== '/') {
32
+ await sandbox.files.createDirectories([{ path: dir, mode: 0o755 }]).catch(() => undefined);
33
+ }
34
+ await sandbox.files.writeFiles([{ path: resolved, data: content }]);
35
+ }
36
+ temp(name) {
37
+ const tempName = name || `temp-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
38
+ return path_1.default.posix.join('/tmp', tempName);
39
+ }
40
+ async stat(p) {
41
+ const sandbox = this.host.getOpenSandbox();
42
+ const resolved = this.resolve(p);
43
+ const info = await sandbox.files.getFileInfo([resolved]);
44
+ const fileInfo = info[resolved] || Object.values(info)[0];
45
+ if (!fileInfo) {
46
+ throw new Error(`File not found: ${resolved}`);
47
+ }
48
+ const mtime = this.toTimestamp(fileInfo.modifiedAt ??
49
+ fileInfo.modified_at ??
50
+ fileInfo.mtime ??
51
+ fileInfo.updatedAt);
52
+ return { mtimeMs: mtime ?? Date.now() };
53
+ }
54
+ async glob(pattern, opts) {
55
+ const sandbox = this.host.getOpenSandbox();
56
+ const searchRoot = opts?.cwd ? this.resolve(opts.cwd) : this.host.workDir;
57
+ const items = await sandbox.files.search({
58
+ path: searchRoot,
59
+ pattern,
60
+ });
61
+ const includeDot = opts?.dot ?? false;
62
+ const ignore = opts?.ignore || [];
63
+ const matched = items
64
+ .map((item) => this.resolve(String(item.path || '')))
65
+ .filter((entry) => {
66
+ if (!entry)
67
+ return false;
68
+ if (!includeDot && this.hasDotPath(entry))
69
+ return false;
70
+ if (ignore.length === 0)
71
+ return true;
72
+ const relToRoot = path_1.default.posix.relative(searchRoot, entry);
73
+ const relToWorkDir = path_1.default.posix.relative(this.host.workDir, entry);
74
+ return !ignore.some((rule) => {
75
+ return (this.matchGlob(rule, relToRoot) ||
76
+ this.matchGlob(rule, relToWorkDir) ||
77
+ this.matchGlob(rule, entry));
78
+ });
79
+ });
80
+ if (opts?.absolute) {
81
+ return matched;
82
+ }
83
+ return matched.map((entry) => path_1.default.posix.relative(this.host.workDir, entry));
84
+ }
85
+ hasDotPath(entry) {
86
+ const normalized = entry.replace(/\\/g, '/');
87
+ return normalized.split('/').some((seg) => seg.startsWith('.') && seg.length > 1);
88
+ }
89
+ toTimestamp(value) {
90
+ if (value == null)
91
+ return undefined;
92
+ if (typeof value === 'number' && Number.isFinite(value))
93
+ return value;
94
+ if (value instanceof Date)
95
+ return value.getTime();
96
+ if (typeof value === 'string') {
97
+ const parsed = Date.parse(value);
98
+ if (Number.isFinite(parsed))
99
+ return parsed;
100
+ }
101
+ return undefined;
102
+ }
103
+ matchGlob(pattern, target) {
104
+ const normalizedPattern = pattern.replace(/\\/g, '/');
105
+ const normalizedTarget = target.replace(/\\/g, '/');
106
+ return (0, minimatch_1.minimatch)(normalizedTarget, normalizedPattern, {
107
+ dot: true,
108
+ nocase: false,
109
+ matchBase: false,
110
+ });
111
+ }
112
+ }
113
+ exports.OpenSandboxFS = OpenSandboxFS;
@@ -0,0 +1,35 @@
1
+ import { Sandbox as OpenSandboxClient } from '@alibaba-group/opensandbox';
2
+ import { Sandbox, SandboxExecResult, SandboxKind } from '../sandbox';
3
+ import { OpenSandboxFS } from './opensandbox-fs';
4
+ import { OpenSandboxOptions } from './types';
5
+ export declare class OpenSandbox implements Sandbox {
6
+ kind: SandboxKind;
7
+ workDir: string;
8
+ fs: OpenSandboxFS;
9
+ private sandbox;
10
+ private readonly options;
11
+ private readonly watchers;
12
+ private readonly watchMode;
13
+ private readonly pollIntervalMs;
14
+ private readonly disposeAction;
15
+ constructor(options: OpenSandboxOptions);
16
+ init(): Promise<void>;
17
+ getOpenSandbox(): OpenSandboxClient;
18
+ getSandboxId(): string | undefined;
19
+ isRunning(): Promise<boolean>;
20
+ exec(cmd: string, opts?: {
21
+ timeoutMs?: number;
22
+ }): Promise<SandboxExecResult>;
23
+ watchFiles(paths: string[], listener: (event: {
24
+ path: string;
25
+ mtimeMs: number;
26
+ }) => void): Promise<string>;
27
+ unwatchFiles(id: string): void;
28
+ dispose(): Promise<void>;
29
+ private buildConnectionConfig;
30
+ private pollWatcher;
31
+ private safeMtime;
32
+ private resolveExecTimeoutMs;
33
+ private startPollingWatcher;
34
+ private startNativeWatcher;
35
+ }