@lydia-agent/core 0.1.0 → 0.1.1

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