@lydia-agent/core 0.1.0 → 0.1.2

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 (3) hide show
  1. package/dist/index.cjs +131 -118
  2. package/dist/index.js +131 -118
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -652,6 +652,8 @@ var StrategyRegistry = class {
652
652
  // User Home
653
653
  path.join(os.homedir(), ".lydia", "strategies", "default.yml"),
654
654
  // Package Built-in
655
+ path.resolve(__dirname, "../strategies/base-v1.yml"),
656
+ // Package Built-in (older path assumption)
655
657
  path.resolve(__dirname, "../../strategies/base-v1.yml"),
656
658
  // Package Built-in (dev/src)
657
659
  path.resolve(__dirname, "../../../strategies/base-v1.yml")
@@ -713,17 +715,20 @@ var StrategyRegistry = class {
713
715
 
714
716
  // src/strategy/approval-service.ts
715
717
  var os2 = __toESM(require("os"), 1);
716
- var path2 = __toESM(require("path"), 1);
718
+ var path3 = __toESM(require("path"), 1);
717
719
 
718
720
  // src/memory/manager.ts
719
721
  var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
720
722
  var import_node_events = require("events");
723
+ var fs2 = __toESM(require("fs"), 1);
724
+ var path2 = __toESM(require("path"), 1);
721
725
  var MemoryManager = class extends import_node_events.EventEmitter {
722
726
  db;
723
727
  checkpointTtlMs;
724
728
  observationFrameTtlMs;
725
729
  constructor(dbPath, options = {}) {
726
730
  super();
731
+ fs2.mkdirSync(path2.dirname(dbPath), { recursive: true });
727
732
  this.db = new import_better_sqlite3.default(dbPath);
728
733
  this.checkpointTtlMs = options.checkpointTtlMs ?? 24 * 60 * 60 * 1e3;
729
734
  this.observationFrameTtlMs = options.observationFrameTtlMs ?? 24 * 7 * 60 * 60 * 1e3;
@@ -1607,7 +1612,7 @@ var StrategyApprovalService = class {
1607
1612
  if (memoryManager) {
1608
1613
  this.memory = memoryManager;
1609
1614
  } else {
1610
- const dbPath = path2.join(os2.homedir(), ".lydia", "memory.db");
1615
+ const dbPath = path3.join(os2.homedir(), ".lydia", "memory.db");
1611
1616
  this.memory = new MemoryManager(dbPath);
1612
1617
  }
1613
1618
  this.configLoader = configLoader || new ConfigLoader();
@@ -1668,7 +1673,7 @@ var StrategyApprovalService = class {
1668
1673
  };
1669
1674
 
1670
1675
  // src/strategy/shadow-router.ts
1671
- var path3 = __toESM(require("path"), 1);
1676
+ var path4 = __toESM(require("path"), 1);
1672
1677
  var os3 = __toESM(require("os"), 1);
1673
1678
  var ShadowRouter = class {
1674
1679
  memory;
@@ -1678,7 +1683,7 @@ var ShadowRouter = class {
1678
1683
  if (memoryManager) {
1679
1684
  this.memory = memoryManager;
1680
1685
  } else {
1681
- const dbPath = path3.join(os3.homedir(), ".lydia", "memory.db");
1686
+ const dbPath = path4.join(os3.homedir(), ".lydia", "memory.db");
1682
1687
  this.memory = new MemoryManager(dbPath);
1683
1688
  }
1684
1689
  this.registry = strategyRegistry || new StrategyRegistry();
@@ -1949,39 +1954,39 @@ var StrategyReviewer = class {
1949
1954
  };
1950
1955
 
1951
1956
  // src/strategy/branch-manager.ts
1952
- var fs2 = __toESM(require("fs/promises"), 1);
1953
- var path4 = __toESM(require("path"), 1);
1957
+ var fs3 = __toESM(require("fs/promises"), 1);
1958
+ var path5 = __toESM(require("path"), 1);
1954
1959
  var os4 = __toESM(require("os"), 1);
1955
1960
  var import_yaml2 = require("yaml");
1956
1961
  var StrategyBranchManager = class {
1957
1962
  baseDir;
1958
1963
  constructor(baseDir) {
1959
- this.baseDir = baseDir || path4.join(os4.homedir(), ".lydia", "strategies");
1964
+ this.baseDir = baseDir || path5.join(os4.homedir(), ".lydia", "strategies");
1960
1965
  }
1961
1966
  async init() {
1962
- await fs2.mkdir(this.baseDir, { recursive: true });
1963
- await fs2.mkdir(path4.join(this.baseDir, "branches"), { recursive: true });
1964
- await fs2.mkdir(path4.join(this.baseDir, "archive"), { recursive: true });
1967
+ await fs3.mkdir(this.baseDir, { recursive: true });
1968
+ await fs3.mkdir(path5.join(this.baseDir, "branches"), { recursive: true });
1969
+ await fs3.mkdir(path5.join(this.baseDir, "archive"), { recursive: true });
1965
1970
  }
1966
1971
  async listBranches() {
1967
- const branchesDir = path4.join(this.baseDir, "branches");
1972
+ const branchesDir = path5.join(this.baseDir, "branches");
1968
1973
  try {
1969
- const entries = await fs2.readdir(branchesDir, { withFileTypes: true });
1974
+ const entries = await fs3.readdir(branchesDir, { withFileTypes: true });
1970
1975
  const branches = [];
1971
1976
  for (const entry of entries) {
1972
1977
  if (!entry.isDirectory()) continue;
1973
1978
  }
1974
- const files = await fs2.readdir(branchesDir);
1979
+ const files = await fs3.readdir(branchesDir);
1975
1980
  for (const file of files) {
1976
1981
  if (!file.endsWith(".yml")) continue;
1977
- const content = await fs2.readFile(path4.join(branchesDir, file), "utf-8");
1982
+ const content = await fs3.readFile(path5.join(branchesDir, file), "utf-8");
1978
1983
  try {
1979
1984
  const strategy = StrategySchema.parse((0, import_yaml2.parse)(content));
1980
1985
  branches.push({
1981
1986
  name: strategy.metadata.id,
1982
1987
  // ID is used as branch name effectively
1983
1988
  version: strategy.metadata.version,
1984
- path: path4.join(branchesDir, file),
1989
+ path: path5.join(branchesDir, file),
1985
1990
  parent: strategy.metadata.inheritFrom,
1986
1991
  createdAt: Date.now()
1987
1992
  // We might want to store this in metadata later
@@ -1997,8 +2002,8 @@ var StrategyBranchManager = class {
1997
2002
  }
1998
2003
  }
1999
2004
  async createBranch(sourceStrategy, newBranchName, modifications) {
2000
- const targetDir = path4.join(this.baseDir, "branches");
2001
- await fs2.mkdir(targetDir, { recursive: true });
2005
+ const targetDir = path5.join(this.baseDir, "branches");
2006
+ await fs3.mkdir(targetDir, { recursive: true });
2002
2007
  const newStrategy = {
2003
2008
  ...sourceStrategy,
2004
2009
  ...modifications,
@@ -2012,14 +2017,14 @@ var StrategyBranchManager = class {
2012
2017
  ...modifications.metadata
2013
2018
  }
2014
2019
  };
2015
- const filePath = path4.join(targetDir, `${newBranchName}.yml`);
2016
- await fs2.writeFile(filePath, (0, import_yaml2.stringify)(newStrategy), "utf-8");
2020
+ const filePath = path5.join(targetDir, `${newBranchName}.yml`);
2021
+ await fs3.writeFile(filePath, (0, import_yaml2.stringify)(newStrategy), "utf-8");
2017
2022
  return newStrategy;
2018
2023
  }
2019
2024
  async getBranch(branchName) {
2020
- const filePath = path4.join(this.baseDir, "branches", `${branchName}.yml`);
2025
+ const filePath = path5.join(this.baseDir, "branches", `${branchName}.yml`);
2021
2026
  try {
2022
- const content = await fs2.readFile(filePath, "utf-8");
2027
+ const content = await fs3.readFile(filePath, "utf-8");
2023
2028
  return StrategySchema.parse((0, import_yaml2.parse)(content));
2024
2029
  } catch {
2025
2030
  return null;
@@ -2030,12 +2035,12 @@ var StrategyBranchManager = class {
2030
2035
  if (!branch) throw new Error(`Branch ${branchName} not found`);
2031
2036
  const parentId = branch.metadata.inheritFrom;
2032
2037
  if (!parentId) throw new Error("Branch has no parent to merge into");
2033
- const files = await fs2.readdir(this.baseDir);
2038
+ const files = await fs3.readdir(this.baseDir);
2034
2039
  let parentFile = null;
2035
2040
  for (const file of files) {
2036
2041
  if (file === "branches" || file === "archive") continue;
2037
2042
  try {
2038
- const content = await fs2.readFile(path4.join(this.baseDir, file), "utf-8");
2043
+ const content = await fs3.readFile(path5.join(this.baseDir, file), "utf-8");
2039
2044
  const data = (0, import_yaml2.parse)(content);
2040
2045
  if (data.metadata?.id === parentId) {
2041
2046
  parentFile = file;
@@ -2047,18 +2052,18 @@ var StrategyBranchManager = class {
2047
2052
  if (!parentFile) {
2048
2053
  throw new Error(`Parent strategy ${parentId} not found in ${this.baseDir}`);
2049
2054
  }
2050
- const parentPath = path4.join(this.baseDir, parentFile);
2051
- await fs2.copyFile(parentPath, path4.join(this.baseDir, "archive", `${parentId}-${Date.now()}.bak.yml`));
2055
+ const parentPath = path5.join(this.baseDir, parentFile);
2056
+ await fs3.copyFile(parentPath, path5.join(this.baseDir, "archive", `${parentId}-${Date.now()}.bak.yml`));
2052
2057
  const start = Date.now();
2053
- const branchContent = await fs2.readFile(path4.join(this.baseDir, "branches", `${branchName}.yml`), "utf-8");
2054
- await fs2.writeFile(parentPath, branchContent, "utf-8");
2058
+ const branchContent = await fs3.readFile(path5.join(this.baseDir, "branches", `${branchName}.yml`), "utf-8");
2059
+ await fs3.writeFile(parentPath, branchContent, "utf-8");
2055
2060
  await this.archiveBranch(branchName);
2056
2061
  }
2057
2062
  async archiveBranch(branchName) {
2058
- const srcPath = path4.join(this.baseDir, "branches", `${branchName}.yml`);
2059
- const destPath = path4.join(this.baseDir, "archive", `${branchName}-${Date.now()}.yml`);
2063
+ const srcPath = path5.join(this.baseDir, "branches", `${branchName}.yml`);
2064
+ const destPath = path5.join(this.baseDir, "archive", `${branchName}-${Date.now()}.yml`);
2060
2065
  try {
2061
- await fs2.rename(srcPath, destPath);
2066
+ await fs3.rename(srcPath, destPath);
2062
2067
  } catch (e) {
2063
2068
  console.error(`Failed to archive branch ${branchName}:`, e);
2064
2069
  throw e;
@@ -2321,11 +2326,11 @@ var SkillRegistry = class {
2321
2326
  };
2322
2327
 
2323
2328
  // src/skills/loader.ts
2324
- var fs3 = __toESM(require("fs/promises"), 1);
2325
- var path5 = __toESM(require("path"), 1);
2329
+ var fs4 = __toESM(require("fs/promises"), 1);
2330
+ var path6 = __toESM(require("path"), 1);
2326
2331
  var os5 = __toESM(require("os"), 1);
2327
2332
  var import_node_url2 = require("url");
2328
- var __dirname2 = path5.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
2333
+ var __dirname2 = path6.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
2329
2334
  var SkillLoader = class {
2330
2335
  registry;
2331
2336
  /** Ordered list of directories to scan for skills */
@@ -2340,13 +2345,13 @@ var SkillLoader = class {
2340
2345
  getDirectories(extraDirs = []) {
2341
2346
  return [
2342
2347
  // 1. Built-in skills (relative to this file in dist/skills)
2343
- path5.resolve(__dirname2, "../../skills"),
2348
+ path6.resolve(__dirname2, "../../skills"),
2344
2349
  // 1.5 Built-in skills in source tree (dev mode)
2345
- path5.resolve(__dirname2, "../skills"),
2350
+ path6.resolve(__dirname2, "../skills"),
2346
2351
  // 2. User global skills
2347
- path5.join(os5.homedir(), ".lydia", "skills"),
2352
+ path6.join(os5.homedir(), ".lydia", "skills"),
2348
2353
  // 3. Project local skills
2349
- path5.join(process.cwd(), ".lydia", "skills"),
2354
+ path6.join(process.cwd(), ".lydia", "skills"),
2350
2355
  // 4. Extra directories from config
2351
2356
  ...extraDirs
2352
2357
  ];
@@ -2367,11 +2372,11 @@ var SkillLoader = class {
2367
2372
  */
2368
2373
  async loadMetadataFromDirectory(dirPath) {
2369
2374
  try {
2370
- const stats = await fs3.stat(dirPath);
2375
+ const stats = await fs4.stat(dirPath);
2371
2376
  if (!stats.isDirectory()) return;
2372
- const entries = await fs3.readdir(dirPath, { withFileTypes: true });
2377
+ const entries = await fs4.readdir(dirPath, { withFileTypes: true });
2373
2378
  for (const entry of entries) {
2374
- const fullPath = path5.join(dirPath, entry.name);
2379
+ const fullPath = path6.join(dirPath, entry.name);
2375
2380
  if (entry.isDirectory()) {
2376
2381
  await this.loadMetadataFromDirectory(fullPath);
2377
2382
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -2387,7 +2392,7 @@ var SkillLoader = class {
2387
2392
  */
2388
2393
  async loadSkillMeta(filePath) {
2389
2394
  try {
2390
- const content = await fs3.readFile(filePath, "utf-8");
2395
+ const content = await fs4.readFile(filePath, "utf-8");
2391
2396
  if (content.startsWith("---")) {
2392
2397
  const meta = SkillParser.parseMeta(content, filePath);
2393
2398
  this.registry.register(meta);
@@ -2408,7 +2413,7 @@ var SkillLoader = class {
2408
2413
  const meta = this.registry.get(name);
2409
2414
  if (!meta?.path) return null;
2410
2415
  try {
2411
- const fileContent = await fs3.readFile(meta.path, "utf-8");
2416
+ const fileContent = await fs4.readFile(meta.path, "utf-8");
2412
2417
  const skill = SkillParser.parse(fileContent, meta.path);
2413
2418
  return skill.content;
2414
2419
  } catch (error) {
@@ -2424,7 +2429,7 @@ var SkillLoader = class {
2424
2429
  const meta = this.registry.get(name);
2425
2430
  if (!meta?.path) return null;
2426
2431
  try {
2427
- const fileContent = await fs3.readFile(meta.path, "utf-8");
2432
+ const fileContent = await fs4.readFile(meta.path, "utf-8");
2428
2433
  return SkillParser.parse(fileContent, meta.path);
2429
2434
  } catch (error) {
2430
2435
  console.warn(`Failed to load full skill "${name}":`, error);
@@ -2437,7 +2442,7 @@ var SkillLoader = class {
2437
2442
  */
2438
2443
  async reloadSkillMeta(filePath) {
2439
2444
  try {
2440
- const content = await fs3.readFile(filePath, "utf-8");
2445
+ const content = await fs4.readFile(filePath, "utf-8");
2441
2446
  if (content.startsWith("---")) {
2442
2447
  const meta = SkillParser.parseMeta(content, filePath);
2443
2448
  this.registry.register(meta);
@@ -2452,9 +2457,9 @@ var SkillLoader = class {
2452
2457
 
2453
2458
  // src/skills/watcher.ts
2454
2459
  var import_node_events2 = require("events");
2455
- var fs4 = __toESM(require("fs"), 1);
2460
+ var fs5 = __toESM(require("fs"), 1);
2456
2461
  var fsPromises = __toESM(require("fs/promises"), 1);
2457
- var path6 = __toESM(require("path"), 1);
2462
+ var path7 = __toESM(require("path"), 1);
2458
2463
  var SkillWatcher = class extends import_node_events2.EventEmitter {
2459
2464
  constructor(directories, registry, loader, options) {
2460
2465
  super();
@@ -2464,7 +2469,7 @@ var SkillWatcher = class extends import_node_events2.EventEmitter {
2464
2469
  this.debounceMs = options?.debounceMs ?? 300;
2465
2470
  for (const skill of this.registry.list()) {
2466
2471
  if (skill.path) {
2467
- this.pathToName.set(path6.resolve(skill.path), skill.name);
2472
+ this.pathToName.set(path7.resolve(skill.path), skill.name);
2468
2473
  }
2469
2474
  }
2470
2475
  }
@@ -2503,12 +2508,12 @@ var SkillWatcher = class extends import_node_events2.EventEmitter {
2503
2508
  }
2504
2509
  watchDirectory(dirPath) {
2505
2510
  try {
2506
- if (!fs4.existsSync(dirPath) || !fs4.statSync(dirPath).isDirectory()) {
2511
+ if (!fs5.existsSync(dirPath) || !fs5.statSync(dirPath).isDirectory()) {
2507
2512
  return;
2508
2513
  }
2509
- const watcher = fs4.watch(dirPath, { recursive: true }, (eventType, filename) => {
2514
+ const watcher = fs5.watch(dirPath, { recursive: true }, (eventType, filename) => {
2510
2515
  if (!filename) return;
2511
- const fullPath = path6.resolve(dirPath, filename);
2516
+ const fullPath = path7.resolve(dirPath, filename);
2512
2517
  if (!filename.endsWith(".md")) return;
2513
2518
  this.handleFileChange(fullPath, eventType);
2514
2519
  });
@@ -2520,7 +2525,7 @@ var SkillWatcher = class extends import_node_events2.EventEmitter {
2520
2525
  }
2521
2526
  }
2522
2527
  handleFileChange(filePath, _eventType) {
2523
- const resolvedPath = path6.resolve(filePath);
2528
+ const resolvedPath = path7.resolve(filePath);
2524
2529
  const existingTimer = this.debounceTimers.get(resolvedPath);
2525
2530
  if (existingTimer) {
2526
2531
  clearTimeout(existingTimer);
@@ -2577,7 +2582,7 @@ var ShellServer = class {
2577
2582
  this.server = new import_server.Server(
2578
2583
  {
2579
2584
  name: "internal-shell",
2580
- version: "0.1.0"
2585
+ version: "0.1.2"
2581
2586
  },
2582
2587
  {
2583
2588
  capabilities: {
@@ -2644,18 +2649,18 @@ ${error.stderr || ""}`
2644
2649
  // src/mcp/servers/filesystem.ts
2645
2650
  var import_server2 = require("@modelcontextprotocol/sdk/server/index.js");
2646
2651
  var import_types4 = require("@modelcontextprotocol/sdk/types.js");
2647
- var fs5 = __toESM(require("fs/promises"), 1);
2648
- var path7 = __toESM(require("path"), 1);
2652
+ var fs6 = __toESM(require("fs/promises"), 1);
2653
+ var path8 = __toESM(require("path"), 1);
2649
2654
  var import_node_zlib = require("zlib");
2650
2655
  var FileSystemServer = class {
2651
2656
  server;
2652
2657
  allowedRootDir;
2653
2658
  constructor(allowedRootDir = process.cwd()) {
2654
- this.allowedRootDir = path7.resolve(allowedRootDir);
2659
+ this.allowedRootDir = path8.resolve(allowedRootDir);
2655
2660
  this.server = new import_server2.Server(
2656
2661
  {
2657
2662
  name: "internal-fs",
2658
- version: "0.1.0"
2663
+ version: "0.1.2"
2659
2664
  },
2660
2665
  {
2661
2666
  capabilities: {
@@ -2666,7 +2671,7 @@ var FileSystemServer = class {
2666
2671
  this.setupHandlers();
2667
2672
  }
2668
2673
  validatePath(requestedPath) {
2669
- const resolvedPath = path7.resolve(this.allowedRootDir, requestedPath);
2674
+ const resolvedPath = path8.resolve(this.allowedRootDir, requestedPath);
2670
2675
  const root = process.platform === "win32" ? this.allowedRootDir.toLowerCase() : this.allowedRootDir;
2671
2676
  const target = process.platform === "win32" ? resolvedPath.toLowerCase() : resolvedPath;
2672
2677
  if (!target.startsWith(root)) {
@@ -2788,22 +2793,22 @@ var FileSystemServer = class {
2788
2793
  switch (request.params.name) {
2789
2794
  case "fs_read_file": {
2790
2795
  const filePath = this.validatePath(args.path);
2791
- const content = await fs5.readFile(filePath, "utf-8");
2796
+ const content = await fs6.readFile(filePath, "utf-8");
2792
2797
  return {
2793
2798
  content: [{ type: "text", text: content }]
2794
2799
  };
2795
2800
  }
2796
2801
  case "fs_write_file": {
2797
2802
  const filePath = this.validatePath(args.path);
2798
- await fs5.mkdir(path7.dirname(filePath), { recursive: true });
2799
- await fs5.writeFile(filePath, args.content, "utf-8");
2803
+ await fs6.mkdir(path8.dirname(filePath), { recursive: true });
2804
+ await fs6.writeFile(filePath, args.content, "utf-8");
2800
2805
  return {
2801
2806
  content: [{ type: "text", text: `Successfully wrote to ${filePath}` }]
2802
2807
  };
2803
2808
  }
2804
2809
  case "fs_list_directory": {
2805
2810
  const dirPath = this.validatePath(args.path);
2806
- const entries = await fs5.readdir(dirPath, { withFileTypes: true });
2811
+ const entries = await fs6.readdir(dirPath, { withFileTypes: true });
2807
2812
  const list = entries.map((e) => `${e.isDirectory() ? "[DIR]" : "[FILE]"} ${e.name}`).join("\n");
2808
2813
  return {
2809
2814
  content: [{ type: "text", text: list }]
@@ -2814,8 +2819,8 @@ var FileSystemServer = class {
2814
2819
  const toPath = this.validatePath(args.to);
2815
2820
  const overwrite = Boolean(args.overwrite);
2816
2821
  await this.ensureDestWritable(toPath, overwrite);
2817
- await fs5.mkdir(path7.dirname(toPath), { recursive: true });
2818
- await fs5.copyFile(fromPath, toPath);
2822
+ await fs6.mkdir(path8.dirname(toPath), { recursive: true });
2823
+ await fs6.copyFile(fromPath, toPath);
2819
2824
  return {
2820
2825
  content: [{ type: "text", text: `Successfully copied ${fromPath} -> ${toPath}` }]
2821
2826
  };
@@ -2825,7 +2830,7 @@ var FileSystemServer = class {
2825
2830
  const toPath = this.validatePath(args.to);
2826
2831
  const overwrite = Boolean(args.overwrite);
2827
2832
  await this.ensureDestWritable(toPath, overwrite);
2828
- await fs5.mkdir(path7.dirname(toPath), { recursive: true });
2833
+ await fs6.mkdir(path8.dirname(toPath), { recursive: true });
2829
2834
  await this.moveFile(fromPath, toPath);
2830
2835
  return {
2831
2836
  content: [{ type: "text", text: `Successfully moved ${fromPath} -> ${toPath}` }]
@@ -2847,9 +2852,9 @@ var FileSystemServer = class {
2847
2852
  const overwrite = Boolean(args.overwrite);
2848
2853
  const maxBytes = Math.max(1024, Number(args.maxBytes) || 20 * 1024 * 1024);
2849
2854
  await this.ensureDestWritable(outputPath, overwrite);
2850
- await fs5.mkdir(path7.dirname(outputPath), { recursive: true });
2855
+ await fs6.mkdir(path8.dirname(outputPath), { recursive: true });
2851
2856
  const bundle = await this.createArchiveBundle(sourcePath, maxBytes);
2852
- await fs5.writeFile(outputPath, bundle.buffer);
2857
+ await fs6.writeFile(outputPath, bundle.buffer);
2853
2858
  return {
2854
2859
  content: [{ type: "text", text: `Successfully archived ${bundle.fileCount} file(s) to ${outputPath}` }]
2855
2860
  };
@@ -2859,7 +2864,7 @@ var FileSystemServer = class {
2859
2864
  const outputDir = this.validatePath(args.outputDir);
2860
2865
  const overwrite = Boolean(args.overwrite);
2861
2866
  const maxBytes = Math.max(1024, Number(args.maxBytes) || 20 * 1024 * 1024);
2862
- const archiveBuffer = await fs5.readFile(archivePath);
2867
+ const archiveBuffer = await fs6.readFile(archivePath);
2863
2868
  const bundle = this.parseArchiveBundle(archiveBuffer);
2864
2869
  const written = await this.extractArchiveBundle(bundle, outputDir, overwrite, maxBytes);
2865
2870
  return {
@@ -2879,11 +2884,11 @@ var FileSystemServer = class {
2879
2884
  }
2880
2885
  async ensureDestWritable(destPath, overwrite) {
2881
2886
  try {
2882
- await fs5.access(destPath);
2887
+ await fs6.access(destPath);
2883
2888
  if (!overwrite) {
2884
2889
  throw new Error(`Destination already exists: ${destPath}. Pass overwrite=true to replace.`);
2885
2890
  }
2886
- await fs5.rm(destPath, { recursive: true, force: true });
2891
+ await fs6.rm(destPath, { recursive: true, force: true });
2887
2892
  } catch (error) {
2888
2893
  if (error?.code === "ENOENT") return;
2889
2894
  throw error;
@@ -2891,11 +2896,11 @@ var FileSystemServer = class {
2891
2896
  }
2892
2897
  async moveFile(fromPath, toPath) {
2893
2898
  try {
2894
- await fs5.rename(fromPath, toPath);
2899
+ await fs6.rename(fromPath, toPath);
2895
2900
  } catch (error) {
2896
2901
  if (error?.code !== "EXDEV") throw error;
2897
- await fs5.copyFile(fromPath, toPath);
2898
- await fs5.unlink(fromPath);
2902
+ await fs6.copyFile(fromPath, toPath);
2903
+ await fs6.unlink(fromPath);
2899
2904
  }
2900
2905
  }
2901
2906
  async searchByName(basePath, pattern, maxResults) {
@@ -2905,10 +2910,10 @@ var FileSystemServer = class {
2905
2910
  while (queue.length > 0 && results.length < maxResults) {
2906
2911
  const current = queue.shift();
2907
2912
  if (!current) break;
2908
- const entries = await fs5.readdir(current, { withFileTypes: true });
2913
+ const entries = await fs6.readdir(current, { withFileTypes: true });
2909
2914
  for (const entry of entries) {
2910
- const fullPath = path7.join(current, entry.name);
2911
- const relative3 = path7.relative(this.allowedRootDir, fullPath) || ".";
2915
+ const fullPath = path8.join(current, entry.name);
2916
+ const relative3 = path8.relative(this.allowedRootDir, fullPath) || ".";
2912
2917
  if (matcher(entry.name)) {
2913
2918
  results.push(`${entry.isDirectory() ? "[DIR]" : "[FILE]"} ${relative3}`);
2914
2919
  if (results.length >= maxResults) break;
@@ -2932,11 +2937,11 @@ var FileSystemServer = class {
2932
2937
  return (name) => name.toLowerCase().includes(lowered);
2933
2938
  }
2934
2939
  async createArchiveBundle(sourcePath, maxBytes) {
2935
- const stat3 = await fs5.stat(sourcePath);
2940
+ const stat3 = await fs6.stat(sourcePath);
2936
2941
  const files = [];
2937
2942
  let totalBytes = 0;
2938
2943
  const readAndAppend = async (absolutePath, relativePath) => {
2939
- const data = await fs5.readFile(absolutePath);
2944
+ const data = await fs6.readFile(absolutePath);
2940
2945
  totalBytes += data.length;
2941
2946
  if (totalBytes > maxBytes) {
2942
2947
  throw new Error(`Archive exceeds maxBytes limit (${maxBytes}).`);
@@ -2949,28 +2954,28 @@ var FileSystemServer = class {
2949
2954
  });
2950
2955
  };
2951
2956
  if (stat3.isFile()) {
2952
- await readAndAppend(sourcePath, path7.basename(sourcePath));
2957
+ await readAndAppend(sourcePath, path8.basename(sourcePath));
2953
2958
  } else if (stat3.isDirectory()) {
2954
2959
  const queue = [sourcePath];
2955
2960
  while (queue.length > 0) {
2956
2961
  const current = queue.shift();
2957
2962
  if (!current) break;
2958
- const entries = await fs5.readdir(current, { withFileTypes: true });
2963
+ const entries = await fs6.readdir(current, { withFileTypes: true });
2959
2964
  for (const entry of entries) {
2960
- const fullPath = path7.join(current, entry.name);
2965
+ const fullPath = path8.join(current, entry.name);
2961
2966
  if (entry.isDirectory()) {
2962
2967
  queue.push(fullPath);
2963
2968
  continue;
2964
2969
  }
2965
2970
  if (!entry.isFile()) continue;
2966
- const relativePath = path7.relative(sourcePath, fullPath) || entry.name;
2971
+ const relativePath = path8.relative(sourcePath, fullPath) || entry.name;
2967
2972
  await readAndAppend(fullPath, relativePath.replace(/\\/g, "/"));
2968
2973
  }
2969
2974
  }
2970
2975
  } else {
2971
2976
  throw new Error("Only files and directories can be archived.");
2972
2977
  }
2973
- const sourceRelative = path7.relative(this.allowedRootDir, sourcePath).replace(/\\/g, "/");
2978
+ const sourceRelative = path8.relative(this.allowedRootDir, sourcePath).replace(/\\/g, "/");
2974
2979
  const bundle = {
2975
2980
  format: "lydia-archive-v1",
2976
2981
  source: sourceRelative || ".",
@@ -3003,13 +3008,13 @@ var FileSystemServer = class {
3003
3008
  let count = 0;
3004
3009
  for (const file of bundle.files) {
3005
3010
  const relPath = String(file.path || "").replace(/\\/g, "/");
3006
- if (!relPath || path7.isAbsolute(relPath) || relPath.includes("..")) {
3011
+ if (!relPath || path8.isAbsolute(relPath) || relPath.includes("..")) {
3007
3012
  throw new Error(`Unsafe archive entry path: ${relPath || "<empty>"}`);
3008
3013
  }
3009
- const targetPath = path7.resolve(outputDir, relPath);
3014
+ const targetPath = path8.resolve(outputDir, relPath);
3010
3015
  const safeOutputDir = process.platform === "win32" ? outputDir.toLowerCase() : outputDir;
3011
3016
  const safeTarget = process.platform === "win32" ? targetPath.toLowerCase() : targetPath;
3012
- if (!safeTarget.startsWith(safeOutputDir + path7.sep) && safeTarget !== safeOutputDir) {
3017
+ if (!safeTarget.startsWith(safeOutputDir + path8.sep) && safeTarget !== safeOutputDir) {
3013
3018
  throw new Error(`Archive entry escapes destination: ${relPath}`);
3014
3019
  }
3015
3020
  const data = this.decodeArchiveEntry(file);
@@ -3017,8 +3022,8 @@ var FileSystemServer = class {
3017
3022
  if (totalBytes > maxBytes) {
3018
3023
  throw new Error(`Unarchive exceeds maxBytes limit (${maxBytes}).`);
3019
3024
  }
3020
- await fs5.mkdir(path7.dirname(targetPath), { recursive: true });
3021
- await fs5.writeFile(targetPath, data);
3025
+ await fs6.mkdir(path8.dirname(targetPath), { recursive: true });
3026
+ await fs6.writeFile(targetPath, data);
3022
3027
  count += 1;
3023
3028
  }
3024
3029
  return count;
@@ -3038,22 +3043,22 @@ var FileSystemServer = class {
3038
3043
  }
3039
3044
  async prepareOutputDirectory(outputDir, overwrite) {
3040
3045
  try {
3041
- const stat3 = await fs5.stat(outputDir);
3046
+ const stat3 = await fs6.stat(outputDir);
3042
3047
  if (!stat3.isDirectory()) {
3043
3048
  throw new Error(`Output path is not a directory: ${outputDir}`);
3044
3049
  }
3045
3050
  if (!overwrite) {
3046
- const entries = await fs5.readdir(outputDir);
3051
+ const entries = await fs6.readdir(outputDir);
3047
3052
  if (entries.length > 0) {
3048
3053
  throw new Error(`Output directory is not empty: ${outputDir}. Pass overwrite=true to replace.`);
3049
3054
  }
3050
3055
  } else {
3051
- await fs5.rm(outputDir, { recursive: true, force: true });
3052
- await fs5.mkdir(outputDir, { recursive: true });
3056
+ await fs6.rm(outputDir, { recursive: true, force: true });
3057
+ await fs6.mkdir(outputDir, { recursive: true });
3053
3058
  }
3054
3059
  } catch (error) {
3055
3060
  if (error?.code === "ENOENT") {
3056
- await fs5.mkdir(outputDir, { recursive: true });
3061
+ await fs6.mkdir(outputDir, { recursive: true });
3057
3062
  return;
3058
3063
  }
3059
3064
  throw error;
@@ -3073,7 +3078,7 @@ var GitServer = class {
3073
3078
  this.server = new import_server3.Server(
3074
3079
  {
3075
3080
  name: "internal-git",
3076
- version: "0.1.0"
3081
+ version: "0.1.2"
3077
3082
  },
3078
3083
  {
3079
3084
  capabilities: {
@@ -3250,7 +3255,7 @@ var MemoryServer = class {
3250
3255
  this.server = new import_server4.Server(
3251
3256
  {
3252
3257
  name: "internal-memory",
3253
- version: "0.1.0"
3258
+ version: "0.1.2"
3254
3259
  },
3255
3260
  {
3256
3261
  capabilities: {
@@ -3376,7 +3381,7 @@ var InteractionServer = class extends import_node_events3.EventEmitter {
3376
3381
  constructor() {
3377
3382
  super();
3378
3383
  this.server = new import_server5.Server(
3379
- { name: "internal-interaction", version: "0.1.0" },
3384
+ { name: "internal-interaction", version: "0.1.2" },
3380
3385
  { capabilities: { tools: {} } }
3381
3386
  );
3382
3387
  this.setupHandlers();
@@ -3757,7 +3762,7 @@ var McpClientManager = class {
3757
3762
  const client = new import_client.Client(
3758
3763
  {
3759
3764
  name: "lydia-client",
3760
- version: "0.1.0"
3765
+ version: "0.1.2"
3761
3766
  },
3762
3767
  {
3763
3768
  capabilities: {
@@ -3865,7 +3870,7 @@ var McpClientManager = class {
3865
3870
  };
3866
3871
 
3867
3872
  // src/gate/risk.ts
3868
- var path8 = __toESM(require("path"), 1);
3873
+ var path9 = __toESM(require("path"), 1);
3869
3874
  var os6 = __toESM(require("os"), 1);
3870
3875
  var DEFAULT_USER_DATA_DIRS = [
3871
3876
  "~/.lydia",
@@ -3895,13 +3900,13 @@ var COMPUTER_USE_HIGH_RISK_ACTIONS = /* @__PURE__ */ new Set([
3895
3900
  ]);
3896
3901
  function expandHome(p) {
3897
3902
  if (p.startsWith("~/") || p === "~") {
3898
- return path8.join(os6.homedir(), p.slice(2));
3903
+ return path9.join(os6.homedir(), p.slice(2));
3899
3904
  }
3900
3905
  return p;
3901
3906
  }
3902
3907
  function normalizePath(p) {
3903
3908
  const expanded = expandHome(p);
3904
- const normalized = path8.resolve(expanded);
3909
+ const normalized = path9.resolve(expanded);
3905
3910
  return process.platform === "win32" ? normalized.toLowerCase() : normalized;
3906
3911
  }
3907
3912
  function buildProtectedDirs(config) {
@@ -3914,7 +3919,7 @@ function buildProtectedDirs(config) {
3914
3919
  }
3915
3920
  function isInProtectedDir(targetPath, protectedDirs) {
3916
3921
  const normalizedTarget = normalizePath(targetPath);
3917
- return protectedDirs.some((dir) => normalizedTarget === dir || normalizedTarget.startsWith(dir + path8.sep));
3922
+ return protectedDirs.some((dir) => normalizedTarget === dir || normalizedTarget.startsWith(dir + path9.sep));
3918
3923
  }
3919
3924
  function extractPathsFromCommand(command) {
3920
3925
  const paths = [];
@@ -3936,7 +3941,7 @@ function hasRelativePathTraversal(input) {
3936
3941
  return /(^|[\\\/])\.\.([\\\/]|$)/.test(input);
3937
3942
  }
3938
3943
  function isRelativePath(input) {
3939
- return !path8.isAbsolute(input);
3944
+ return !path9.isAbsolute(input);
3940
3945
  }
3941
3946
  function resolveCanonicalComputerUseAction(toolName) {
3942
3947
  const direct = resolveCanonicalComputerUseToolName(toolName);
@@ -4001,7 +4006,7 @@ function assessRisk(toolName, args, mcp, config) {
4001
4006
  return {
4002
4007
  level: "high",
4003
4008
  reason: `${opLabel} with relative path traversal`,
4004
- signature: `fs_write_rel:${normalizePath(path8.resolve(targetPath))}`,
4009
+ signature: `fs_write_rel:${normalizePath(path9.resolve(targetPath))}`,
4005
4010
  details: targetPath
4006
4011
  };
4007
4012
  }
@@ -4032,6 +4037,14 @@ function assessRisk(toolName, args, mcp, config) {
4032
4037
  if (toolName === "shell_execute") {
4033
4038
  const command = typeof args?.command === "string" ? args.command : "";
4034
4039
  if (command && (isDestructiveShellCommand(command) || isPermissionChangeCommand(command))) {
4040
+ if (isPermissionChangeCommand(command)) {
4041
+ return {
4042
+ level: "high",
4043
+ reason: "Permission change shell command",
4044
+ signature: `shell_permission:${command.toLowerCase().slice(0, 80)}`,
4045
+ details: command
4046
+ };
4047
+ }
4035
4048
  const targets = extractPathsFromCommand(command);
4036
4049
  const hasTraversal = hasRelativePathTraversal(command);
4037
4050
  if (targets.length === 0 || hasTraversal) {
@@ -4270,7 +4283,7 @@ var StrategyUpdateGate = class {
4270
4283
  };
4271
4284
 
4272
4285
  // src/gate/review-manager.ts
4273
- var path9 = __toESM(require("path"), 1);
4286
+ var path10 = __toESM(require("path"), 1);
4274
4287
  var os7 = __toESM(require("os"), 1);
4275
4288
  var ReviewManager = class {
4276
4289
  memory;
@@ -4279,7 +4292,7 @@ var ReviewManager = class {
4279
4292
  this.memory = memoryManager;
4280
4293
  return;
4281
4294
  }
4282
- const dbPath = path9.join(os7.homedir(), ".lydia", "memory.db");
4295
+ const dbPath = path10.join(os7.homedir(), ".lydia", "memory.db");
4283
4296
  this.memory = new MemoryManager(dbPath);
4284
4297
  }
4285
4298
  async init() {
@@ -4458,7 +4471,7 @@ ${this.originalPlan}
4458
4471
  };
4459
4472
 
4460
4473
  // src/replay/mcp.ts
4461
- var path10 = __toESM(require("path"), 1);
4474
+ var path11 = __toESM(require("path"), 1);
4462
4475
  var ReplayMcpClientManager = class extends McpClientManager {
4463
4476
  traces;
4464
4477
  callIndex = 0;
@@ -4613,12 +4626,12 @@ var ReplayMcpClientManager = class extends McpClientManager {
4613
4626
  const loweredPattern = rawPattern.toLowerCase();
4614
4627
  const names = /* @__PURE__ */ new Set();
4615
4628
  for (const storedPath of this.virtualFiles.keys()) {
4616
- const rel = path10.relative(normalized, storedPath);
4629
+ const rel = path11.relative(normalized, storedPath);
4617
4630
  if (rel.startsWith("..")) continue;
4618
4631
  const parts = rel.split("/").filter(Boolean);
4619
4632
  for (const part of parts) {
4620
4633
  if (part.toLowerCase().includes(loweredPattern)) {
4621
- names.add(`[FILE] ${path10.posix.join(path10.posix.relative(this.virtualRoot, normalized), rel)}`);
4634
+ names.add(`[FILE] ${path11.posix.join(path11.posix.relative(this.virtualRoot, normalized), rel)}`);
4622
4635
  break;
4623
4636
  }
4624
4637
  }
@@ -4646,12 +4659,12 @@ var ReplayMcpClientManager = class extends McpClientManager {
4646
4659
  createdAt: 0,
4647
4660
  totalBytes: sourceFile ? sourceFile.length : sourceEntries.reduce((acc, [, text]) => acc + text.length, 0),
4648
4661
  files: sourceFile ? [{
4649
- path: path10.posix.basename(source),
4662
+ path: path11.posix.basename(source),
4650
4663
  size: sourceFile.length,
4651
4664
  encoding: "base64",
4652
4665
  data: Buffer.from(sourceFile, "utf-8").toString("base64")
4653
4666
  }] : sourceEntries.map(([filePath, text]) => ({
4654
- path: path10.posix.relative(source, filePath),
4667
+ path: path11.posix.relative(source, filePath),
4655
4668
  size: text.length,
4656
4669
  encoding: "base64",
4657
4670
  data: Buffer.from(text, "utf-8").toString("base64")
@@ -4706,7 +4719,7 @@ var ReplayMcpClientManager = class extends McpClientManager {
4706
4719
  for (const item of parsed.files) {
4707
4720
  const rel = typeof item?.path === "string" ? item.path.replace(/\\/g, "/") : "";
4708
4721
  if (!rel || rel.includes("..") || rel.startsWith("/")) continue;
4709
- const target = this.normalizeFsPath(path10.posix.join(outputDir, rel));
4722
+ const target = this.normalizeFsPath(path11.posix.join(outputDir, rel));
4710
4723
  const base64 = typeof item?.data === "string" ? item.data : "";
4711
4724
  const text = base64 ? Buffer.from(base64, "base64").toString("utf-8") : "";
4712
4725
  this.virtualFiles.set(target, text);
@@ -4999,12 +5012,12 @@ var ReplayMcpClientManager = class extends McpClientManager {
4999
5012
  if (driveMatch) {
5000
5013
  const drive = driveMatch[1].toLowerCase();
5001
5014
  const rest = driveMatch[2] || "/";
5002
- return path10.posix.normalize(`/${drive}${rest}`);
5015
+ return path11.posix.normalize(`/${drive}${rest}`);
5003
5016
  }
5004
5017
  if (source.startsWith("/")) {
5005
- return path10.posix.normalize(source);
5018
+ return path11.posix.normalize(source);
5006
5019
  }
5007
- return path10.posix.normalize(path10.posix.join(this.virtualRoot, source));
5020
+ return path11.posix.normalize(path11.posix.join(this.virtualRoot, source));
5008
5021
  }
5009
5022
  listDirectoryEntries(directory) {
5010
5023
  const normalizedDir = this.normalizeFsPath(directory);
@@ -5195,7 +5208,7 @@ var StrategyEvaluator = class {
5195
5208
  };
5196
5209
 
5197
5210
  // src/replay/manager.ts
5198
- var path11 = __toESM(require("path"), 1);
5211
+ var path12 = __toESM(require("path"), 1);
5199
5212
  var os8 = __toESM(require("os"), 1);
5200
5213
  var ReplayManager = class {
5201
5214
  memoryManager;
@@ -5204,7 +5217,7 @@ var ReplayManager = class {
5204
5217
  if (memoryManager) {
5205
5218
  this.memoryManager = memoryManager;
5206
5219
  } else {
5207
- const dbPath = path11.join(os8.homedir(), ".lydia", "memory.db");
5220
+ const dbPath = path12.join(os8.homedir(), ".lydia", "memory.db");
5208
5221
  this.memoryManager = new MemoryManager(dbPath);
5209
5222
  }
5210
5223
  this.evaluator = new StrategyEvaluator();
@@ -5224,7 +5237,7 @@ var ReplayManager = class {
5224
5237
  const agent = new Agent(mockLLM);
5225
5238
  agent.mcpClientManager = mockMcp;
5226
5239
  agent.isInitialized = true;
5227
- const tempDb = path11.join(os8.tmpdir(), `lydia-replay-${Date.now()}-${episodeId}.db`);
5240
+ const tempDb = path12.join(os8.tmpdir(), `lydia-replay-${Date.now()}-${episodeId}.db`);
5228
5241
  agent.memoryManager = new MemoryManager(tempDb);
5229
5242
  try {
5230
5243
  const config = await agent.configLoader.load();
@@ -5544,7 +5557,7 @@ var FeedbackCollector = class {
5544
5557
  };
5545
5558
 
5546
5559
  // src/execution/agent.ts
5547
- var path12 = __toESM(require("path"), 1);
5560
+ var path13 = __toESM(require("path"), 1);
5548
5561
  var os9 = __toESM(require("os"), 1);
5549
5562
  var Agent = class extends import_node_events5.EventEmitter {
5550
5563
  llm;
@@ -5641,7 +5654,7 @@ var Agent = class extends import_node_events5.EventEmitter {
5641
5654
  await this.reviewManager.init();
5642
5655
  const config = await this.configLoader.load();
5643
5656
  this.config = config;
5644
- const dbPath = path12.join(os9.homedir(), ".lydia", "memory.db");
5657
+ const dbPath = path13.join(os9.homedir(), ".lydia", "memory.db");
5645
5658
  this.memoryManager = new MemoryManager(dbPath, {
5646
5659
  checkpointTtlMs: Math.max(1, config.memory?.checkpointTtlHours ?? 24) * 60 * 60 * 1e3,
5647
5660
  observationFrameTtlMs: Math.max(1, config.memory?.observationFrameTtlHours ?? 24 * 7) * 60 * 60 * 1e3