agentdev 0.1.9 → 0.1.10

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  BasicAgent
3
- } from "./chunk-5T4C2XRT.js";
4
- import "./chunk-A354ZCZF.js";
3
+ } from "./chunk-REOJZCSZ.js";
4
+ import "./chunk-3AR3JBW6.js";
5
5
  import "./chunk-BVF7RUXV.js";
6
6
  import "./chunk-EECW6PYP.js";
7
7
  import "./chunk-G5ECPY4K.js";
@@ -10,4 +10,4 @@ import "./chunk-BDS2QGZ5.js";
10
10
  export {
11
11
  BasicAgent
12
12
  };
13
- //# sourceMappingURL=BasicAgent-UWXLSZP2.js.map
13
+ //# sourceMappingURL=BasicAgent-R7DYGTHF.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ExplorerAgent
3
- } from "./chunk-QFHPUAUQ.js";
4
- import "./chunk-A354ZCZF.js";
3
+ } from "./chunk-72H6A6NB.js";
4
+ import "./chunk-3AR3JBW6.js";
5
5
  import "./chunk-BVF7RUXV.js";
6
6
  import "./chunk-EECW6PYP.js";
7
7
  import "./chunk-G5ECPY4K.js";
@@ -10,4 +10,4 @@ import "./chunk-BDS2QGZ5.js";
10
10
  export {
11
11
  ExplorerAgent
12
12
  };
13
- //# sourceMappingURL=ExplorerAgent-LCM3JQS4.js.map
13
+ //# sourceMappingURL=ExplorerAgent-DXY3OQ5U.js.map
@@ -1208,6 +1208,107 @@ var TemplateComposer = class _TemplateComposer {
1208
1208
  }
1209
1209
  };
1210
1210
 
1211
+ // src/skills/loader.ts
1212
+ import { readdir as readdir2, readFile as readFile3 } from "fs/promises";
1213
+ import { resolve as resolve3, isAbsolute, join as join2, normalize } from "path";
1214
+ import { existsSync as existsSync2 } from "fs";
1215
+ function parseSkillFrontmatter(content, path2) {
1216
+ if (!content.trimStart().startsWith("---")) {
1217
+ return null;
1218
+ }
1219
+ const frontmatterEnd = content.indexOf("---", 3);
1220
+ if (frontmatterEnd === -1) {
1221
+ return null;
1222
+ }
1223
+ const frontmatterStr = content.slice(3, frontmatterEnd).trim();
1224
+ const nameMatch = frontmatterStr.match(/^name:\s*(.+)$/m);
1225
+ const descriptionMatch = frontmatterStr.match(/^description:\s*(.+)$/m);
1226
+ if (!nameMatch || !descriptionMatch) {
1227
+ return null;
1228
+ }
1229
+ const name = nameMatch[1].trim();
1230
+ const description = descriptionMatch[1].trim();
1231
+ const cleanValue = (value) => {
1232
+ value = value.trim();
1233
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
1234
+ return value.slice(1, -1);
1235
+ }
1236
+ return value;
1237
+ };
1238
+ return {
1239
+ name: cleanValue(name),
1240
+ description: cleanValue(description),
1241
+ path: path2
1242
+ };
1243
+ }
1244
+ async function collectSkillFiles(dir, skillsDir) {
1245
+ const skillFiles = [];
1246
+ try {
1247
+ const entries = await readdir2(dir, { withFileTypes: true });
1248
+ for (const entry of entries) {
1249
+ const fullPath = join2(dir, entry.name);
1250
+ if (entry.isFile() && entry.name === "SKILL.md") {
1251
+ skillFiles.push(normalize(fullPath));
1252
+ } else if (entry.isDirectory() || entry.isSymbolicLink()) {
1253
+ let isLinkToDir = false;
1254
+ if (entry.isSymbolicLink()) {
1255
+ try {
1256
+ const stats = await readFileStats(fullPath);
1257
+ isLinkToDir = stats.isDirectory();
1258
+ } catch {
1259
+ continue;
1260
+ }
1261
+ }
1262
+ if (isLinkToDir || entry.isDirectory()) {
1263
+ const subFiles = await collectSkillFiles(fullPath, skillsDir);
1264
+ skillFiles.push(...subFiles);
1265
+ }
1266
+ }
1267
+ }
1268
+ } catch {
1269
+ }
1270
+ return skillFiles;
1271
+ }
1272
+ async function readFileStats(path2) {
1273
+ const { stat: stat4 } = await import("fs/promises");
1274
+ return stat4(path2);
1275
+ }
1276
+ async function discover(options = {}) {
1277
+ const { dir } = options;
1278
+ const skillsDir = resolveSkillsDir(dir);
1279
+ if (!existsSync2(skillsDir)) {
1280
+ return [];
1281
+ }
1282
+ const skills = [];
1283
+ try {
1284
+ const skillFiles = await collectSkillFiles(skillsDir, skillsDir);
1285
+ for (const fullPath of skillFiles) {
1286
+ try {
1287
+ const content = await readFile3(fullPath, "utf-8");
1288
+ const metadata = parseSkillFrontmatter(content, fullPath);
1289
+ if (metadata) {
1290
+ skills.push(metadata);
1291
+ }
1292
+ } catch {
1293
+ }
1294
+ }
1295
+ } catch {
1296
+ return [];
1297
+ }
1298
+ return skills;
1299
+ }
1300
+ function resolveSkillsDir(dir) {
1301
+ const cwd6 = process.cwd();
1302
+ if (dir) {
1303
+ if (isAbsolute(dir)) {
1304
+ return dir;
1305
+ }
1306
+ const resolved = resolve3(cwd6, dir);
1307
+ return resolved;
1308
+ }
1309
+ return resolve3(cwd6, ".agentdev", "skills");
1310
+ }
1311
+
1211
1312
  // src/core/lifecycle.ts
1212
1313
  var CoreLifecycle = /* @__PURE__ */ ((CoreLifecycle2) => {
1213
1314
  CoreLifecycle2["AgentInitiate"] = "AgentInitiate";
@@ -1364,21 +1465,21 @@ function getDecoratorMetadata(target) {
1364
1465
 
1365
1466
  // src/core/feature.ts
1366
1467
  import { fileURLToPath as fileURLToPath2 } from "url";
1367
- import { dirname as dirname2, join as join2 } from "path";
1368
- import { existsSync as existsSync2, readFileSync } from "fs";
1468
+ import { dirname as dirname3, join as join3 } from "path";
1469
+ import { existsSync as existsSync3, readFileSync } from "fs";
1369
1470
  function getPackageInfoFromSource(source) {
1370
1471
  if (!source) {
1371
1472
  return null;
1372
1473
  }
1373
1474
  try {
1374
1475
  const filePath = source.startsWith("file://") ? fileURLToPath2(source) : source;
1375
- const featureDir = dirname2(filePath);
1476
+ const featureDir = dirname3(filePath);
1376
1477
  let currentDir = featureDir;
1377
1478
  const root = process.platform === "win32" ? currentDir.split(/[/\\]/)[0] : "";
1378
1479
  while (currentDir && currentDir !== root) {
1379
1480
  try {
1380
- const packageJsonPath = join2(currentDir, "package.json");
1381
- if (!existsSync2(packageJsonPath)) {
1481
+ const packageJsonPath = join3(currentDir, "package.json");
1482
+ if (!existsSync3(packageJsonPath)) {
1382
1483
  throw new Error("Not found");
1383
1484
  }
1384
1485
  const content = readFileSync(packageJsonPath, "utf-8");
@@ -1389,7 +1490,7 @@ function getPackageInfoFromSource(source) {
1389
1490
  root: currentDir
1390
1491
  };
1391
1492
  } catch {
1392
- const parentDir = dirname2(currentDir);
1493
+ const parentDir = dirname3(currentDir);
1393
1494
  if (parentDir === currentDir) {
1394
1495
  break;
1395
1496
  }
@@ -1403,13 +1504,13 @@ function getPackageInfoFromSource(source) {
1403
1504
  }
1404
1505
 
1405
1506
  // src/mcp/config.ts
1406
- import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync } from "fs";
1507
+ import { existsSync as existsSync4, readFileSync as readFileSync2, readdirSync } from "fs";
1407
1508
  import { basename } from "path";
1408
1509
  import { cwd as cwd2 } from "process";
1409
- import { isAbsolute, join as join3, resolve as resolve3 } from "path";
1510
+ import { isAbsolute as isAbsolute2, join as join4, resolve as resolve4 } from "path";
1410
1511
  function readConfigFile(configPath) {
1411
1512
  try {
1412
- if (!existsSync3(configPath)) {
1513
+ if (!existsSync4(configPath)) {
1413
1514
  return void 0;
1414
1515
  }
1415
1516
  const content = readFileSync2(configPath, "utf-8");
@@ -1464,21 +1565,21 @@ function normalizeToMCPConfig(value, fallbackServerId) {
1464
1565
  return void 0;
1465
1566
  }
1466
1567
  function getDefaultMCPConfigDir(rootDir = cwd2()) {
1467
- return join3(rootDir, ".agentdev", "mcps");
1568
+ return join4(rootDir, ".agentdev", "mcps");
1468
1569
  }
1469
1570
  function loadMCPConfigFromInput(input, rootDir = cwd2()) {
1470
1571
  let configPath;
1471
1572
  let fallbackServerId = "default";
1472
- if (isAbsolute(input)) {
1573
+ if (isAbsolute2(input)) {
1473
1574
  configPath = input;
1474
1575
  } else if (input.includes("/") || input.includes("\\")) {
1475
- configPath = resolve3(rootDir, input);
1576
+ configPath = resolve4(rootDir, input);
1476
1577
  fallbackServerId = basename(configPath, ".json");
1477
1578
  } else {
1478
- configPath = join3(getDefaultMCPConfigDir(rootDir), `${input}.json`);
1579
+ configPath = join4(getDefaultMCPConfigDir(rootDir), `${input}.json`);
1479
1580
  fallbackServerId = input;
1480
1581
  }
1481
- if (!existsSync3(configPath)) {
1582
+ if (!existsSync4(configPath)) {
1482
1583
  console.warn(`[MCP] Config file does not exist: ${configPath}`);
1483
1584
  return void 0;
1484
1585
  }
@@ -1486,7 +1587,7 @@ function loadMCPConfigFromInput(input, rootDir = cwd2()) {
1486
1587
  }
1487
1588
  function loadAllMCPConfigs(rootDir = cwd2(), options = {}) {
1488
1589
  const configDir = getDefaultMCPConfigDir(rootDir);
1489
- if (!existsSync3(configDir)) {
1590
+ if (!existsSync4(configDir)) {
1490
1591
  return void 0;
1491
1592
  }
1492
1593
  const excludedServers = new Set(options.excludeServers ?? []);
@@ -1496,7 +1597,7 @@ function loadAllMCPConfigs(rootDir = cwd2(), options = {}) {
1496
1597
  if (!entry.isFile() || !entry.name.endsWith(".json")) {
1497
1598
  continue;
1498
1599
  }
1499
- const configPath = join3(configDir, entry.name);
1600
+ const configPath = join4(configDir, entry.name);
1500
1601
  const config = readConfigFile(configPath);
1501
1602
  if (!config) {
1502
1603
  continue;
@@ -2248,9 +2349,9 @@ async function mountMCPToolsFromConfig(config, options = {}) {
2248
2349
 
2249
2350
  // src/features/mcp/index.ts
2250
2351
  import { fileURLToPath as fileURLToPath3 } from "url";
2251
- import { dirname as dirname3 } from "path";
2352
+ import { dirname as dirname4 } from "path";
2252
2353
  var __filename2 = fileURLToPath3(import.meta.url);
2253
- var __dirname = dirname3(__filename2);
2354
+ var __dirname = dirname4(__filename2);
2254
2355
  var MCPFeature = class {
2255
2356
  name = "mcp";
2256
2357
  dependencies = [];
@@ -2348,8 +2449,8 @@ var MCPFeature = class {
2348
2449
 
2349
2450
  // src/features/audit/index.ts
2350
2451
  import { fileURLToPath as fileURLToPath4 } from "url";
2351
- import { existsSync as existsSync4 } from "fs";
2352
- import { resolve as resolve4, dirname as dirname4 } from "path";
2452
+ import { existsSync as existsSync5 } from "fs";
2453
+ import { resolve as resolve5, dirname as dirname5 } from "path";
2353
2454
  import OpenAI from "openai";
2354
2455
  import Database from "better-sqlite3";
2355
2456
  import { mkdir as mkdirAsync } from "fs/promises";
@@ -2402,7 +2503,7 @@ var AuditFeature = class {
2402
2503
  dbPath: config.dbPath ?? ".agentdev/audit/audit.db",
2403
2504
  cacheTtlDays: config.cacheTtlDays ?? 0
2404
2505
  };
2405
- this.dbPath = resolve4(process.cwd(), this.config.dbPath);
2506
+ this.dbPath = resolve5(config.workspaceDir ?? process.cwd(), this.config.dbPath);
2406
2507
  this.client = new OpenAI({
2407
2508
  baseURL: `${this.config.baseUrl}/v1`,
2408
2509
  apiKey: "audit-key"
@@ -2543,8 +2644,8 @@ ${command}
2543
2644
  */
2544
2645
  async initDatabase() {
2545
2646
  try {
2546
- const dbDir = dirname4(this.dbPath);
2547
- if (!existsSync4(dbDir)) {
2647
+ const dbDir = dirname5(this.dbPath);
2648
+ if (!existsSync5(dbDir)) {
2548
2649
  await mkdirAsync(dbDir, { recursive: true });
2549
2650
  this.logger?.info("[AuditFeature] Created database directory", { dbDir });
2550
2651
  }
@@ -2694,10 +2795,10 @@ __decorateClass([
2694
2795
 
2695
2796
  // src/features/audio-feedback/index.ts
2696
2797
  import { fileURLToPath as fileURLToPath5 } from "url";
2697
- import { dirname as dirname5, join as join5 } from "path";
2798
+ import { dirname as dirname6, join as join6 } from "path";
2698
2799
  import soundPlay from "sound-play";
2699
2800
  var __filename3 = fileURLToPath5(import.meta.url);
2700
- var __dirname2 = dirname5(__filename3);
2801
+ var __dirname2 = dirname6(__filename3);
2701
2802
  var AudioFeedbackFeature = class {
2702
2803
  name = "audio-feedback";
2703
2804
  dependencies = [];
@@ -2713,7 +2814,7 @@ var AudioFeedbackFeature = class {
2713
2814
  logger;
2714
2815
  constructor(config = {}) {
2715
2816
  this.config = {
2716
- audioPath: config.audioPath ?? join5(__dirname2, "media", "success.mp3"),
2817
+ audioPath: config.audioPath ?? join6(__dirname2, "media", "success.mp3"),
2717
2818
  enabled: config.enabled ?? true,
2718
2819
  volume: config.volume ?? 0.5
2719
2820
  };
@@ -2793,19 +2894,19 @@ __decorateClass([
2793
2894
 
2794
2895
  // src/features/memory/index.ts
2795
2896
  import { fileURLToPath as fileURLToPath6 } from "url";
2796
- import { readFileSync as readFileSync3, existsSync as existsSync5 } from "fs";
2797
- import { resolve as resolve5 } from "path";
2897
+ import { readFileSync as readFileSync3, existsSync as existsSync6 } from "fs";
2898
+ import { resolve as resolve6 } from "path";
2798
2899
  var MemoryFeature = class {
2799
2900
  name = "memory";
2800
2901
  dependencies = [];
2801
2902
  source = fileURLToPath6(import.meta.url).replace(/\\\\/g, "/");
2802
2903
  description = "\u81EA\u52A8\u8BFB\u53D6\u5E76\u6CE8\u5165\u9879\u76EE CLAUDE.md \u6587\u4EF6\u4F5C\u4E3A\u7CFB\u7EDF\u63D0\u793A\u8BCD\u3002";
2803
2904
  filename;
2804
- workspaceDir;
2905
+ sourceRoot;
2805
2906
  _packageInfo = null;
2806
2907
  constructor(config = {}) {
2807
2908
  this.filename = config.filename ?? "CLAUDE.md";
2808
- this.workspaceDir = config.workspaceDir ?? process.cwd();
2909
+ this.sourceRoot = config.resourceRoot ?? config.workspaceDir ?? process.cwd();
2809
2910
  }
2810
2911
  /**
2811
2912
  * 获取包信息(统一打包方案)
@@ -2827,9 +2928,9 @@ var MemoryFeature = class {
2827
2928
  if (!ctx.isFirstCall) {
2828
2929
  return;
2829
2930
  }
2830
- const cwd6 = this.workspaceDir;
2831
- const filePath = resolve5(cwd6, this.filename);
2832
- if (!existsSync5(filePath)) {
2931
+ const cwd6 = this.sourceRoot;
2932
+ const filePath = resolve6(cwd6, this.filename);
2933
+ if (!existsSync6(filePath)) {
2833
2934
  return;
2834
2935
  }
2835
2936
  const content = readFileSync3(filePath, "utf-8");
@@ -2852,107 +2953,6 @@ __decorateClass([
2852
2953
  CallStart
2853
2954
  ], MemoryFeature.prototype, "injectCLAUDEContent", 1);
2854
2955
 
2855
- // src/skills/loader.ts
2856
- import { readdir as readdir2, readFile as readFile3 } from "fs/promises";
2857
- import { resolve as resolve6, isAbsolute as isAbsolute2, join as join6, normalize } from "path";
2858
- import { existsSync as existsSync6 } from "fs";
2859
- function parseSkillFrontmatter(content, path2) {
2860
- if (!content.trimStart().startsWith("---")) {
2861
- return null;
2862
- }
2863
- const frontmatterEnd = content.indexOf("---", 3);
2864
- if (frontmatterEnd === -1) {
2865
- return null;
2866
- }
2867
- const frontmatterStr = content.slice(3, frontmatterEnd).trim();
2868
- const nameMatch = frontmatterStr.match(/^name:\s*(.+)$/m);
2869
- const descriptionMatch = frontmatterStr.match(/^description:\s*(.+)$/m);
2870
- if (!nameMatch || !descriptionMatch) {
2871
- return null;
2872
- }
2873
- const name = nameMatch[1].trim();
2874
- const description = descriptionMatch[1].trim();
2875
- const cleanValue = (value) => {
2876
- value = value.trim();
2877
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
2878
- return value.slice(1, -1);
2879
- }
2880
- return value;
2881
- };
2882
- return {
2883
- name: cleanValue(name),
2884
- description: cleanValue(description),
2885
- path: path2
2886
- };
2887
- }
2888
- async function collectSkillFiles(dir, skillsDir) {
2889
- const skillFiles = [];
2890
- try {
2891
- const entries = await readdir2(dir, { withFileTypes: true });
2892
- for (const entry of entries) {
2893
- const fullPath = join6(dir, entry.name);
2894
- if (entry.isFile() && entry.name === "SKILL.md") {
2895
- skillFiles.push(normalize(fullPath));
2896
- } else if (entry.isDirectory() || entry.isSymbolicLink()) {
2897
- let isLinkToDir = false;
2898
- if (entry.isSymbolicLink()) {
2899
- try {
2900
- const stats = await readFileStats(fullPath);
2901
- isLinkToDir = stats.isDirectory();
2902
- } catch {
2903
- continue;
2904
- }
2905
- }
2906
- if (isLinkToDir || entry.isDirectory()) {
2907
- const subFiles = await collectSkillFiles(fullPath, skillsDir);
2908
- skillFiles.push(...subFiles);
2909
- }
2910
- }
2911
- }
2912
- } catch {
2913
- }
2914
- return skillFiles;
2915
- }
2916
- async function readFileStats(path2) {
2917
- const { stat: stat4 } = await import("fs/promises");
2918
- return stat4(path2);
2919
- }
2920
- async function discover(options = {}) {
2921
- const { dir } = options;
2922
- const skillsDir = resolveSkillsDir(dir);
2923
- if (!existsSync6(skillsDir)) {
2924
- return [];
2925
- }
2926
- const skills = [];
2927
- try {
2928
- const skillFiles = await collectSkillFiles(skillsDir, skillsDir);
2929
- for (const fullPath of skillFiles) {
2930
- try {
2931
- const content = await readFile3(fullPath, "utf-8");
2932
- const metadata = parseSkillFrontmatter(content, fullPath);
2933
- if (metadata) {
2934
- skills.push(metadata);
2935
- }
2936
- } catch {
2937
- }
2938
- }
2939
- } catch {
2940
- return [];
2941
- }
2942
- return skills;
2943
- }
2944
- function resolveSkillsDir(dir) {
2945
- const cwd6 = process.cwd();
2946
- if (dir) {
2947
- if (isAbsolute2(dir)) {
2948
- return dir;
2949
- }
2950
- const resolved = resolve6(cwd6, dir);
2951
- return resolved;
2952
- }
2953
- return resolve6(cwd6, ".agentdev", "skills");
2954
- }
2955
-
2956
2956
  // src/features/skill/index.ts
2957
2957
  import { fileURLToPath as fileURLToPath7 } from "url";
2958
2958
  import { dirname as dirname8 } from "path";
@@ -3021,6 +3021,7 @@ var SkillFeature = class {
3021
3021
  description = "\u53D1\u73B0\u672C\u5730 skills\uFF0C\u5E76\u63D0\u4F9B invoke_skill \u5DE5\u5177\u4E0E\u6280\u80FD\u6570\u636E\u6E90\u3002";
3022
3022
  skillsDir;
3023
3023
  skills = [];
3024
+ featureSkills = [];
3024
3025
  /**
3025
3026
  * 缓存包信息
3026
3027
  */
@@ -3072,6 +3073,14 @@ var SkillFeature = class {
3072
3073
  if (this.skillsDir) {
3073
3074
  this.skills = await discover({ dir: this.skillsDir });
3074
3075
  }
3076
+ if (this.featureSkills.length > 0) {
3077
+ const userSkillNames = new Set(this.skills.map((s) => s.name));
3078
+ for (const s of this.featureSkills) {
3079
+ if (!userSkillNames.has(s.name)) {
3080
+ this.skills.push(s);
3081
+ }
3082
+ }
3083
+ }
3075
3084
  DataSourceRegistry.register({
3076
3085
  name: "skills",
3077
3086
  getData: () => this.skills,
@@ -3086,6 +3095,13 @@ var SkillFeature = class {
3086
3095
  }
3087
3096
  });
3088
3097
  }
3098
+ /**
3099
+ * 注入来自其他 Feature 的 skills
3100
+ * 由 Agent 在 onInitiate 之前调用
3101
+ */
3102
+ addFeatureSkills(skills) {
3103
+ this.featureSkills = skills;
3104
+ }
3089
3105
  /**
3090
3106
  * 获取已加载的 Skills
3091
3107
  */
@@ -3616,7 +3632,8 @@ var PluginCompatFeature = class {
3616
3632
  if (!this.enabled) {
3617
3633
  return;
3618
3634
  }
3619
- this.pluginRoots = config?.pluginRoots ?? [resolve9(process.cwd(), ".agentdev/plugins")];
3635
+ const resourceRoot = config?.resourceRoot ?? ctx.config?.projectRoot ?? ctx.config?.workspaceDir ?? process.cwd();
3636
+ this.pluginRoots = config?.pluginRoots ?? [resolve9(resourceRoot, ".agentdev/plugins")];
3620
3637
  await this.loadPlugins();
3621
3638
  this.diagnostics.printReport();
3622
3639
  }
@@ -3903,7 +3920,8 @@ var QQBotFeature = class {
3903
3920
  clientSecret: this.config.clientSecret
3904
3921
  };
3905
3922
  }
3906
- const defaultConfigPath = join9(process.cwd(), ".agentdev", "qqbot.config.json");
3923
+ const configRoot = this.config.resourceRoot ?? this.config.workspaceDir ?? process.cwd();
3924
+ const defaultConfigPath = join9(configRoot, ".agentdev", "qqbot.config.json");
3907
3925
  const configPath = this.config.configPath || defaultConfigPath;
3908
3926
  const fileConfig = loadConfigFromFile(configPath);
3909
3927
  if (!fileConfig || !fileConfig.appId || !fileConfig.clientSecret) {
@@ -3970,12 +3988,13 @@ var execAsync = promisify(exec);
3970
3988
  var GIT_BASH = "C:/Program Files/Git/bin/bash.exe";
3971
3989
  async function runShellCommand(command, options = {}) {
3972
3990
  const workspaceDir = options.workspaceDir || process.cwd();
3991
+ const workdir = options.workdir || workspaceDir;
3973
3992
  const resourceRoot = options.resourceRoot || process.cwd();
3974
3993
  const bashrcPath = resolve10(resourceRoot, ".agentdev/bashrc");
3975
3994
  console.log(`[shell] ${command}`);
3976
3995
  try {
3977
3996
  const bashCommand = `"${GIT_BASH}" --rcfile "${bashrcPath}" -i -c "${command.replace(/"/g, '\\"')}"`;
3978
- const { stdout, stderr } = await execAsync(bashCommand, { cwd: workspaceDir });
3997
+ const { stdout, stderr } = await execAsync(bashCommand, { cwd: workdir });
3979
3998
  const cleanStderr = stderr?.split("\n").filter((line) => !line.includes("process group") && !line.includes("job control")).join("\n") || "";
3980
3999
  return {
3981
4000
  stdout: stdout || "",
@@ -5140,14 +5159,17 @@ var ShellFeature = class {
5140
5159
  bashDescription;
5141
5160
  _packageInfo = null;
5142
5161
  workspaceDir;
5162
+ workdir;
5143
5163
  resourceRoot;
5144
5164
  constructor(config = {}) {
5145
5165
  this.workspaceDir = config.workspaceDir || process.cwd();
5166
+ this.workdir = config.workdir || this.workspaceDir;
5146
5167
  this.resourceRoot = config.resourceRoot || process.cwd();
5147
5168
  }
5148
5169
  async run(command) {
5149
5170
  return runShellCommand(command, {
5150
5171
  workspaceDir: this.workspaceDir,
5172
+ workdir: this.workdir,
5151
5173
  resourceRoot: this.resourceRoot
5152
5174
  });
5153
5175
  }
@@ -5176,9 +5198,9 @@ var ShellFeature = class {
5176
5198
  */
5177
5199
  getTools() {
5178
5200
  return [
5179
- createSafeTrashDeleteTool(this.workspaceDir),
5180
- createSafeTrashListTool(this.workspaceDir),
5181
- createSafeTrashRestoreTool(this.workspaceDir)
5201
+ createSafeTrashDeleteTool(this.workdir),
5202
+ createSafeTrashListTool(this.workdir),
5203
+ createSafeTrashRestoreTool(this.workdir)
5182
5204
  ];
5183
5205
  }
5184
5206
  /**
@@ -5195,6 +5217,7 @@ var ShellFeature = class {
5195
5217
  }
5196
5218
  return [createShellCommandTool(this.bashDescription, {
5197
5219
  workspaceDir: this.workspaceDir,
5220
+ workdir: this.workdir,
5198
5221
  resourceRoot: this.resourceRoot
5199
5222
  })];
5200
5223
  }
@@ -6393,8 +6416,8 @@ var __dirname6 = dirname15(fileURLToPath13(import.meta.url));
6393
6416
  var DEFAULT_VOICE = "zf_xiaobei";
6394
6417
  var DEFAULT_LANG = "zh";
6395
6418
  var DEFAULT_SPEED = 1.2;
6396
- function getDefaultPythonPath() {
6397
- const projectRoot2 = process.cwd();
6419
+ function getDefaultPythonPath(workspaceDir) {
6420
+ const projectRoot2 = workspaceDir ?? process.cwd();
6398
6421
  const venvPython = process.platform === "win32" ? join17(projectRoot2, ".venv", "Scripts", "python.exe") : join17(projectRoot2, ".venv", "bin", "python");
6399
6422
  if (existsSync9(venvPython)) {
6400
6423
  console.log(`[TTSFeature] Using project Python: ${venvPython}`);
@@ -6418,14 +6441,14 @@ var TTSFeature = class {
6418
6441
  lastUtteranceId: null,
6419
6442
  totalUtterances: 0
6420
6443
  };
6421
- const projectRoot2 = process.cwd();
6444
+ const projectRoot2 = config.workspaceDir ?? process.cwd();
6422
6445
  const defaultOutputDir = join17(projectRoot2, ".agentdev", "tts");
6423
6446
  const outputDir = config.output?.outputDir || defaultOutputDir;
6424
6447
  if (!existsSync9(outputDir)) {
6425
6448
  mkdirSync2(outputDir, { recursive: true });
6426
6449
  }
6427
6450
  this.config = {
6428
- pythonPath: config.pythonPath ?? getDefaultPythonPath(),
6451
+ pythonPath: config.pythonPath ?? getDefaultPythonPath(config.workspaceDir),
6429
6452
  pythonArgs: config.pythonArgs,
6430
6453
  checkPythonEnv: config.checkPythonEnv ?? true,
6431
6454
  outputDir,
@@ -7964,8 +7987,8 @@ var DEFAULT_BASE_URL2 = "http://localhost:7575";
7964
7987
  var DEFAULT_MODEL2 = "Qwen3.5-4B-Q5_K_M";
7965
7988
  var DEFAULT_ADVANCED_BASE_URL = "http://localhost:7577";
7966
7989
  var DEFAULT_ADVANCED_MODEL = "Qwen3.5-9B-Q4_K_M";
7967
- function getDefaultPythonPath2() {
7968
- const projectRoot2 = process.cwd();
7990
+ function getDefaultPythonPath2(workspaceDir) {
7991
+ const projectRoot2 = workspaceDir ?? process.cwd();
7969
7992
  const venvPython = process.platform === "win32" ? join20(projectRoot2, ".venv", "Scripts", "python.exe") : join20(projectRoot2, ".venv", "bin", "python");
7970
7993
  if (existsSync11(venvPython)) {
7971
7994
  console.log(`[VisualFeature] Using project Python: ${venvPython}`);
@@ -8005,7 +8028,7 @@ var VisualFeature = class {
8005
8028
  model: config.model ?? DEFAULT_MODEL2,
8006
8029
  advancedBaseUrl: config.advancedVision?.baseUrl ?? DEFAULT_ADVANCED_BASE_URL,
8007
8030
  advancedModel: config.advancedVision?.model ?? DEFAULT_ADVANCED_MODEL,
8008
- pythonPath: config.pythonPath ?? getDefaultPythonPath2(),
8031
+ pythonPath: config.pythonPath ?? getDefaultPythonPath2(config.workspaceDir),
8009
8032
  pythonArgs: config.pythonArgs,
8010
8033
  enableWindowInfo: config.enableWindowInfo ?? true,
8011
8034
  checkPythonEnv: config.checkPythonEnv ?? true
@@ -10919,6 +10942,11 @@ var UsageStats = class {
10919
10942
  }
10920
10943
  };
10921
10944
 
10945
+ // src/core/agent.ts
10946
+ import { existsSync as existsSync13 } from "fs";
10947
+ import { dirname as dirname21, join as join24 } from "path";
10948
+ import { fileURLToPath as fileURLToPath20 } from "url";
10949
+
10922
10950
  // src/core/agent/hooks-executor.ts
10923
10951
  var hookLogger = createLogger("agent.forward-hook");
10924
10952
  async function executeHook(agent, hookFn, options) {
@@ -12047,14 +12075,14 @@ var AgentBase = class {
12047
12075
  if (factory) return factory();
12048
12076
  switch (type) {
12049
12077
  case "ExplorerAgent": {
12050
- const { ExplorerAgent } = await import("./ExplorerAgent-LCM3JQS4.js");
12078
+ const { ExplorerAgent } = await import("./ExplorerAgent-DXY3OQ5U.js");
12051
12079
  return new ExplorerAgent({
12052
12080
  llm: this.llm
12053
12081
  });
12054
12082
  }
12055
12083
  case "BasicAgent":
12056
12084
  default: {
12057
- const { BasicAgent } = await import("./BasicAgent-UWXLSZP2.js");
12085
+ const { BasicAgent } = await import("./BasicAgent-R7DYGTHF.js");
12058
12086
  return new BasicAgent({
12059
12087
  llm: this.llm,
12060
12088
  tools: this.tools.getAll().slice(0, 3)
@@ -12191,6 +12219,13 @@ var AgentBase = class {
12191
12219
  */
12192
12220
  async ensureFeatureTools() {
12193
12221
  if (this.featureToolsReady) return;
12222
+ const featureSkills = await this.collectFeatureSkills();
12223
+ if (featureSkills.length > 0) {
12224
+ const skillFeature = this.features.get("skill");
12225
+ if (skillFeature?.addFeatureSkills) {
12226
+ skillFeature.addFeatureSkills(featureSkills);
12227
+ }
12228
+ }
12194
12229
  for (const [name, feature] of this.features) {
12195
12230
  const featureLogger = createLogger(`feature.${name}`, {
12196
12231
  agentId: this.agentId,
@@ -12245,6 +12280,29 @@ var AgentBase = class {
12245
12280
  this.featureToolsReady = true;
12246
12281
  this.pushInspectorSnapshot();
12247
12282
  }
12283
+ /**
12284
+ * 收集所有 Feature 自带的 skills
12285
+ * 约定:Feature 目录下存在 skills/ 目录则自动发现
12286
+ */
12287
+ async collectFeatureSkills() {
12288
+ const collected = [];
12289
+ for (const [name, feature] of this.features) {
12290
+ if (name === "skill") continue;
12291
+ if (!feature.source) continue;
12292
+ const filePath = feature.source.startsWith("file://") ? fileURLToPath20(feature.source) : feature.source;
12293
+ const featureDir = dirname21(filePath);
12294
+ const candidate1 = join24(featureDir, "skills");
12295
+ const pkgInfo = feature.getPackageInfo?.();
12296
+ const candidate2 = pkgInfo ? join24(pkgInfo.root, "skills") : null;
12297
+ const skillsDir = existsSync13(candidate1) ? candidate1 : candidate2 && existsSync13(candidate2) ? candidate2 : null;
12298
+ if (!skillsDir) continue;
12299
+ const found = await discover({ dir: skillsDir });
12300
+ if (found.length > 0) {
12301
+ collected.push(...found);
12302
+ }
12303
+ }
12304
+ return collected;
12305
+ }
12248
12306
  // ========== 内部方法 ==========
12249
12307
  /**
12250
12308
  * 解析相对路径(处理 ./ 和 ../)
@@ -12523,6 +12581,7 @@ export {
12523
12581
  DataSourceRegistry,
12524
12582
  createListRenderer,
12525
12583
  TemplateComposer,
12584
+ discover,
12526
12585
  Decision,
12527
12586
  CallStart,
12528
12587
  CallFinish,
@@ -12550,7 +12609,6 @@ export {
12550
12609
  AuditFeature,
12551
12610
  AudioFeedbackFeature,
12552
12611
  MemoryFeature,
12553
- discover,
12554
12612
  SkillFeature,
12555
12613
  PluginCompatFeature,
12556
12614
  QQBotFeature,
@@ -12575,4 +12633,4 @@ export {
12575
12633
  createLLM,
12576
12634
  AgentBase
12577
12635
  };
12578
- //# sourceMappingURL=chunk-A354ZCZF.js.map
12636
+ //# sourceMappingURL=chunk-3AR3JBW6.js.map