@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.js CHANGED
@@ -529,6 +529,8 @@ var StrategyRegistry = class {
529
529
  // User Home
530
530
  path.join(os.homedir(), ".lydia", "strategies", "default.yml"),
531
531
  // Package Built-in
532
+ path.resolve(__dirname2, "../strategies/base-v1.yml"),
533
+ // Package Built-in (older path assumption)
532
534
  path.resolve(__dirname2, "../../strategies/base-v1.yml"),
533
535
  // Package Built-in (dev/src)
534
536
  path.resolve(__dirname2, "../../../strategies/base-v1.yml")
@@ -590,17 +592,20 @@ var StrategyRegistry = class {
590
592
 
591
593
  // src/strategy/approval-service.ts
592
594
  import * as os2 from "os";
593
- import * as path2 from "path";
595
+ import * as path3 from "path";
594
596
 
595
597
  // src/memory/manager.ts
596
598
  import Database from "better-sqlite3";
597
599
  import { EventEmitter } from "events";
600
+ import * as fs2 from "fs";
601
+ import * as path2 from "path";
598
602
  var MemoryManager = class extends EventEmitter {
599
603
  db;
600
604
  checkpointTtlMs;
601
605
  observationFrameTtlMs;
602
606
  constructor(dbPath, options = {}) {
603
607
  super();
608
+ fs2.mkdirSync(path2.dirname(dbPath), { recursive: true });
604
609
  this.db = new Database(dbPath);
605
610
  this.checkpointTtlMs = options.checkpointTtlMs ?? 24 * 60 * 60 * 1e3;
606
611
  this.observationFrameTtlMs = options.observationFrameTtlMs ?? 24 * 7 * 60 * 60 * 1e3;
@@ -1484,7 +1489,7 @@ var StrategyApprovalService = class {
1484
1489
  if (memoryManager) {
1485
1490
  this.memory = memoryManager;
1486
1491
  } else {
1487
- const dbPath = path2.join(os2.homedir(), ".lydia", "memory.db");
1492
+ const dbPath = path3.join(os2.homedir(), ".lydia", "memory.db");
1488
1493
  this.memory = new MemoryManager(dbPath);
1489
1494
  }
1490
1495
  this.configLoader = configLoader || new ConfigLoader();
@@ -1545,7 +1550,7 @@ var StrategyApprovalService = class {
1545
1550
  };
1546
1551
 
1547
1552
  // src/strategy/shadow-router.ts
1548
- import * as path3 from "path";
1553
+ import * as path4 from "path";
1549
1554
  import * as os3 from "os";
1550
1555
  var ShadowRouter = class {
1551
1556
  memory;
@@ -1555,7 +1560,7 @@ var ShadowRouter = class {
1555
1560
  if (memoryManager) {
1556
1561
  this.memory = memoryManager;
1557
1562
  } else {
1558
- const dbPath = path3.join(os3.homedir(), ".lydia", "memory.db");
1563
+ const dbPath = path4.join(os3.homedir(), ".lydia", "memory.db");
1559
1564
  this.memory = new MemoryManager(dbPath);
1560
1565
  }
1561
1566
  this.registry = strategyRegistry || new StrategyRegistry();
@@ -1826,39 +1831,39 @@ var StrategyReviewer = class {
1826
1831
  };
1827
1832
 
1828
1833
  // src/strategy/branch-manager.ts
1829
- import * as fs2 from "fs/promises";
1830
- import * as path4 from "path";
1834
+ import * as fs3 from "fs/promises";
1835
+ import * as path5 from "path";
1831
1836
  import * as os4 from "os";
1832
1837
  import { parse as parseYaml2, stringify as stringifyYaml2 } from "yaml";
1833
1838
  var StrategyBranchManager = class {
1834
1839
  baseDir;
1835
1840
  constructor(baseDir) {
1836
- this.baseDir = baseDir || path4.join(os4.homedir(), ".lydia", "strategies");
1841
+ this.baseDir = baseDir || path5.join(os4.homedir(), ".lydia", "strategies");
1837
1842
  }
1838
1843
  async init() {
1839
- await fs2.mkdir(this.baseDir, { recursive: true });
1840
- await fs2.mkdir(path4.join(this.baseDir, "branches"), { recursive: true });
1841
- await fs2.mkdir(path4.join(this.baseDir, "archive"), { recursive: true });
1844
+ await fs3.mkdir(this.baseDir, { recursive: true });
1845
+ await fs3.mkdir(path5.join(this.baseDir, "branches"), { recursive: true });
1846
+ await fs3.mkdir(path5.join(this.baseDir, "archive"), { recursive: true });
1842
1847
  }
1843
1848
  async listBranches() {
1844
- const branchesDir = path4.join(this.baseDir, "branches");
1849
+ const branchesDir = path5.join(this.baseDir, "branches");
1845
1850
  try {
1846
- const entries = await fs2.readdir(branchesDir, { withFileTypes: true });
1851
+ const entries = await fs3.readdir(branchesDir, { withFileTypes: true });
1847
1852
  const branches = [];
1848
1853
  for (const entry of entries) {
1849
1854
  if (!entry.isDirectory()) continue;
1850
1855
  }
1851
- const files = await fs2.readdir(branchesDir);
1856
+ const files = await fs3.readdir(branchesDir);
1852
1857
  for (const file of files) {
1853
1858
  if (!file.endsWith(".yml")) continue;
1854
- const content = await fs2.readFile(path4.join(branchesDir, file), "utf-8");
1859
+ const content = await fs3.readFile(path5.join(branchesDir, file), "utf-8");
1855
1860
  try {
1856
1861
  const strategy = StrategySchema.parse(parseYaml2(content));
1857
1862
  branches.push({
1858
1863
  name: strategy.metadata.id,
1859
1864
  // ID is used as branch name effectively
1860
1865
  version: strategy.metadata.version,
1861
- path: path4.join(branchesDir, file),
1866
+ path: path5.join(branchesDir, file),
1862
1867
  parent: strategy.metadata.inheritFrom,
1863
1868
  createdAt: Date.now()
1864
1869
  // We might want to store this in metadata later
@@ -1874,8 +1879,8 @@ var StrategyBranchManager = class {
1874
1879
  }
1875
1880
  }
1876
1881
  async createBranch(sourceStrategy, newBranchName, modifications) {
1877
- const targetDir = path4.join(this.baseDir, "branches");
1878
- await fs2.mkdir(targetDir, { recursive: true });
1882
+ const targetDir = path5.join(this.baseDir, "branches");
1883
+ await fs3.mkdir(targetDir, { recursive: true });
1879
1884
  const newStrategy = {
1880
1885
  ...sourceStrategy,
1881
1886
  ...modifications,
@@ -1889,14 +1894,14 @@ var StrategyBranchManager = class {
1889
1894
  ...modifications.metadata
1890
1895
  }
1891
1896
  };
1892
- const filePath = path4.join(targetDir, `${newBranchName}.yml`);
1893
- await fs2.writeFile(filePath, stringifyYaml2(newStrategy), "utf-8");
1897
+ const filePath = path5.join(targetDir, `${newBranchName}.yml`);
1898
+ await fs3.writeFile(filePath, stringifyYaml2(newStrategy), "utf-8");
1894
1899
  return newStrategy;
1895
1900
  }
1896
1901
  async getBranch(branchName) {
1897
- const filePath = path4.join(this.baseDir, "branches", `${branchName}.yml`);
1902
+ const filePath = path5.join(this.baseDir, "branches", `${branchName}.yml`);
1898
1903
  try {
1899
- const content = await fs2.readFile(filePath, "utf-8");
1904
+ const content = await fs3.readFile(filePath, "utf-8");
1900
1905
  return StrategySchema.parse(parseYaml2(content));
1901
1906
  } catch {
1902
1907
  return null;
@@ -1907,12 +1912,12 @@ var StrategyBranchManager = class {
1907
1912
  if (!branch) throw new Error(`Branch ${branchName} not found`);
1908
1913
  const parentId = branch.metadata.inheritFrom;
1909
1914
  if (!parentId) throw new Error("Branch has no parent to merge into");
1910
- const files = await fs2.readdir(this.baseDir);
1915
+ const files = await fs3.readdir(this.baseDir);
1911
1916
  let parentFile = null;
1912
1917
  for (const file of files) {
1913
1918
  if (file === "branches" || file === "archive") continue;
1914
1919
  try {
1915
- const content = await fs2.readFile(path4.join(this.baseDir, file), "utf-8");
1920
+ const content = await fs3.readFile(path5.join(this.baseDir, file), "utf-8");
1916
1921
  const data = parseYaml2(content);
1917
1922
  if (data.metadata?.id === parentId) {
1918
1923
  parentFile = file;
@@ -1924,18 +1929,18 @@ var StrategyBranchManager = class {
1924
1929
  if (!parentFile) {
1925
1930
  throw new Error(`Parent strategy ${parentId} not found in ${this.baseDir}`);
1926
1931
  }
1927
- const parentPath = path4.join(this.baseDir, parentFile);
1928
- await fs2.copyFile(parentPath, path4.join(this.baseDir, "archive", `${parentId}-${Date.now()}.bak.yml`));
1932
+ const parentPath = path5.join(this.baseDir, parentFile);
1933
+ await fs3.copyFile(parentPath, path5.join(this.baseDir, "archive", `${parentId}-${Date.now()}.bak.yml`));
1929
1934
  const start = Date.now();
1930
- const branchContent = await fs2.readFile(path4.join(this.baseDir, "branches", `${branchName}.yml`), "utf-8");
1931
- await fs2.writeFile(parentPath, branchContent, "utf-8");
1935
+ const branchContent = await fs3.readFile(path5.join(this.baseDir, "branches", `${branchName}.yml`), "utf-8");
1936
+ await fs3.writeFile(parentPath, branchContent, "utf-8");
1932
1937
  await this.archiveBranch(branchName);
1933
1938
  }
1934
1939
  async archiveBranch(branchName) {
1935
- const srcPath = path4.join(this.baseDir, "branches", `${branchName}.yml`);
1936
- const destPath = path4.join(this.baseDir, "archive", `${branchName}-${Date.now()}.yml`);
1940
+ const srcPath = path5.join(this.baseDir, "branches", `${branchName}.yml`);
1941
+ const destPath = path5.join(this.baseDir, "archive", `${branchName}-${Date.now()}.yml`);
1937
1942
  try {
1938
- await fs2.rename(srcPath, destPath);
1943
+ await fs3.rename(srcPath, destPath);
1939
1944
  } catch (e) {
1940
1945
  console.error(`Failed to archive branch ${branchName}:`, e);
1941
1946
  throw e;
@@ -2198,11 +2203,11 @@ var SkillRegistry = class {
2198
2203
  };
2199
2204
 
2200
2205
  // src/skills/loader.ts
2201
- import * as fs3 from "fs/promises";
2202
- import * as path5 from "path";
2206
+ import * as fs4 from "fs/promises";
2207
+ import * as path6 from "path";
2203
2208
  import * as os5 from "os";
2204
2209
  import { fileURLToPath as fileURLToPath2 } from "url";
2205
- var __dirname3 = path5.dirname(fileURLToPath2(import.meta.url));
2210
+ var __dirname3 = path6.dirname(fileURLToPath2(import.meta.url));
2206
2211
  var SkillLoader = class {
2207
2212
  registry;
2208
2213
  /** Ordered list of directories to scan for skills */
@@ -2217,13 +2222,13 @@ var SkillLoader = class {
2217
2222
  getDirectories(extraDirs = []) {
2218
2223
  return [
2219
2224
  // 1. Built-in skills (relative to this file in dist/skills)
2220
- path5.resolve(__dirname3, "../../skills"),
2225
+ path6.resolve(__dirname3, "../../skills"),
2221
2226
  // 1.5 Built-in skills in source tree (dev mode)
2222
- path5.resolve(__dirname3, "../skills"),
2227
+ path6.resolve(__dirname3, "../skills"),
2223
2228
  // 2. User global skills
2224
- path5.join(os5.homedir(), ".lydia", "skills"),
2229
+ path6.join(os5.homedir(), ".lydia", "skills"),
2225
2230
  // 3. Project local skills
2226
- path5.join(process.cwd(), ".lydia", "skills"),
2231
+ path6.join(process.cwd(), ".lydia", "skills"),
2227
2232
  // 4. Extra directories from config
2228
2233
  ...extraDirs
2229
2234
  ];
@@ -2244,11 +2249,11 @@ var SkillLoader = class {
2244
2249
  */
2245
2250
  async loadMetadataFromDirectory(dirPath) {
2246
2251
  try {
2247
- const stats = await fs3.stat(dirPath);
2252
+ const stats = await fs4.stat(dirPath);
2248
2253
  if (!stats.isDirectory()) return;
2249
- const entries = await fs3.readdir(dirPath, { withFileTypes: true });
2254
+ const entries = await fs4.readdir(dirPath, { withFileTypes: true });
2250
2255
  for (const entry of entries) {
2251
- const fullPath = path5.join(dirPath, entry.name);
2256
+ const fullPath = path6.join(dirPath, entry.name);
2252
2257
  if (entry.isDirectory()) {
2253
2258
  await this.loadMetadataFromDirectory(fullPath);
2254
2259
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -2264,7 +2269,7 @@ var SkillLoader = class {
2264
2269
  */
2265
2270
  async loadSkillMeta(filePath) {
2266
2271
  try {
2267
- const content = await fs3.readFile(filePath, "utf-8");
2272
+ const content = await fs4.readFile(filePath, "utf-8");
2268
2273
  if (content.startsWith("---")) {
2269
2274
  const meta = SkillParser.parseMeta(content, filePath);
2270
2275
  this.registry.register(meta);
@@ -2285,7 +2290,7 @@ var SkillLoader = class {
2285
2290
  const meta = this.registry.get(name);
2286
2291
  if (!meta?.path) return null;
2287
2292
  try {
2288
- const fileContent = await fs3.readFile(meta.path, "utf-8");
2293
+ const fileContent = await fs4.readFile(meta.path, "utf-8");
2289
2294
  const skill = SkillParser.parse(fileContent, meta.path);
2290
2295
  return skill.content;
2291
2296
  } catch (error) {
@@ -2301,7 +2306,7 @@ var SkillLoader = class {
2301
2306
  const meta = this.registry.get(name);
2302
2307
  if (!meta?.path) return null;
2303
2308
  try {
2304
- const fileContent = await fs3.readFile(meta.path, "utf-8");
2309
+ const fileContent = await fs4.readFile(meta.path, "utf-8");
2305
2310
  return SkillParser.parse(fileContent, meta.path);
2306
2311
  } catch (error) {
2307
2312
  console.warn(`Failed to load full skill "${name}":`, error);
@@ -2314,7 +2319,7 @@ var SkillLoader = class {
2314
2319
  */
2315
2320
  async reloadSkillMeta(filePath) {
2316
2321
  try {
2317
- const content = await fs3.readFile(filePath, "utf-8");
2322
+ const content = await fs4.readFile(filePath, "utf-8");
2318
2323
  if (content.startsWith("---")) {
2319
2324
  const meta = SkillParser.parseMeta(content, filePath);
2320
2325
  this.registry.register(meta);
@@ -2329,9 +2334,9 @@ var SkillLoader = class {
2329
2334
 
2330
2335
  // src/skills/watcher.ts
2331
2336
  import { EventEmitter as EventEmitter2 } from "events";
2332
- import * as fs4 from "fs";
2337
+ import * as fs5 from "fs";
2333
2338
  import * as fsPromises from "fs/promises";
2334
- import * as path6 from "path";
2339
+ import * as path7 from "path";
2335
2340
  var SkillWatcher = class extends EventEmitter2 {
2336
2341
  constructor(directories, registry, loader, options) {
2337
2342
  super();
@@ -2341,7 +2346,7 @@ var SkillWatcher = class extends EventEmitter2 {
2341
2346
  this.debounceMs = options?.debounceMs ?? 300;
2342
2347
  for (const skill of this.registry.list()) {
2343
2348
  if (skill.path) {
2344
- this.pathToName.set(path6.resolve(skill.path), skill.name);
2349
+ this.pathToName.set(path7.resolve(skill.path), skill.name);
2345
2350
  }
2346
2351
  }
2347
2352
  }
@@ -2380,12 +2385,12 @@ var SkillWatcher = class extends EventEmitter2 {
2380
2385
  }
2381
2386
  watchDirectory(dirPath) {
2382
2387
  try {
2383
- if (!fs4.existsSync(dirPath) || !fs4.statSync(dirPath).isDirectory()) {
2388
+ if (!fs5.existsSync(dirPath) || !fs5.statSync(dirPath).isDirectory()) {
2384
2389
  return;
2385
2390
  }
2386
- const watcher = fs4.watch(dirPath, { recursive: true }, (eventType, filename) => {
2391
+ const watcher = fs5.watch(dirPath, { recursive: true }, (eventType, filename) => {
2387
2392
  if (!filename) return;
2388
- const fullPath = path6.resolve(dirPath, filename);
2393
+ const fullPath = path7.resolve(dirPath, filename);
2389
2394
  if (!filename.endsWith(".md")) return;
2390
2395
  this.handleFileChange(fullPath, eventType);
2391
2396
  });
@@ -2397,7 +2402,7 @@ var SkillWatcher = class extends EventEmitter2 {
2397
2402
  }
2398
2403
  }
2399
2404
  handleFileChange(filePath, _eventType) {
2400
- const resolvedPath = path6.resolve(filePath);
2405
+ const resolvedPath = path7.resolve(filePath);
2401
2406
  const existingTimer = this.debounceTimers.get(resolvedPath);
2402
2407
  if (existingTimer) {
2403
2408
  clearTimeout(existingTimer);
@@ -2454,7 +2459,7 @@ var ShellServer = class {
2454
2459
  this.server = new Server(
2455
2460
  {
2456
2461
  name: "internal-shell",
2457
- version: "0.1.0"
2462
+ version: "0.1.2"
2458
2463
  },
2459
2464
  {
2460
2465
  capabilities: {
@@ -2521,18 +2526,18 @@ ${error.stderr || ""}`
2521
2526
  // src/mcp/servers/filesystem.ts
2522
2527
  import { Server as Server2 } from "@modelcontextprotocol/sdk/server/index.js";
2523
2528
  import { CallToolRequestSchema as CallToolRequestSchema2, ListToolsRequestSchema as ListToolsRequestSchema2 } from "@modelcontextprotocol/sdk/types.js";
2524
- import * as fs5 from "fs/promises";
2525
- import * as path7 from "path";
2529
+ import * as fs6 from "fs/promises";
2530
+ import * as path8 from "path";
2526
2531
  import { gunzipSync, gzipSync } from "zlib";
2527
2532
  var FileSystemServer = class {
2528
2533
  server;
2529
2534
  allowedRootDir;
2530
2535
  constructor(allowedRootDir = process.cwd()) {
2531
- this.allowedRootDir = path7.resolve(allowedRootDir);
2536
+ this.allowedRootDir = path8.resolve(allowedRootDir);
2532
2537
  this.server = new Server2(
2533
2538
  {
2534
2539
  name: "internal-fs",
2535
- version: "0.1.0"
2540
+ version: "0.1.2"
2536
2541
  },
2537
2542
  {
2538
2543
  capabilities: {
@@ -2543,7 +2548,7 @@ var FileSystemServer = class {
2543
2548
  this.setupHandlers();
2544
2549
  }
2545
2550
  validatePath(requestedPath) {
2546
- const resolvedPath = path7.resolve(this.allowedRootDir, requestedPath);
2551
+ const resolvedPath = path8.resolve(this.allowedRootDir, requestedPath);
2547
2552
  const root = process.platform === "win32" ? this.allowedRootDir.toLowerCase() : this.allowedRootDir;
2548
2553
  const target = process.platform === "win32" ? resolvedPath.toLowerCase() : resolvedPath;
2549
2554
  if (!target.startsWith(root)) {
@@ -2665,22 +2670,22 @@ var FileSystemServer = class {
2665
2670
  switch (request.params.name) {
2666
2671
  case "fs_read_file": {
2667
2672
  const filePath = this.validatePath(args.path);
2668
- const content = await fs5.readFile(filePath, "utf-8");
2673
+ const content = await fs6.readFile(filePath, "utf-8");
2669
2674
  return {
2670
2675
  content: [{ type: "text", text: content }]
2671
2676
  };
2672
2677
  }
2673
2678
  case "fs_write_file": {
2674
2679
  const filePath = this.validatePath(args.path);
2675
- await fs5.mkdir(path7.dirname(filePath), { recursive: true });
2676
- await fs5.writeFile(filePath, args.content, "utf-8");
2680
+ await fs6.mkdir(path8.dirname(filePath), { recursive: true });
2681
+ await fs6.writeFile(filePath, args.content, "utf-8");
2677
2682
  return {
2678
2683
  content: [{ type: "text", text: `Successfully wrote to ${filePath}` }]
2679
2684
  };
2680
2685
  }
2681
2686
  case "fs_list_directory": {
2682
2687
  const dirPath = this.validatePath(args.path);
2683
- const entries = await fs5.readdir(dirPath, { withFileTypes: true });
2688
+ const entries = await fs6.readdir(dirPath, { withFileTypes: true });
2684
2689
  const list = entries.map((e) => `${e.isDirectory() ? "[DIR]" : "[FILE]"} ${e.name}`).join("\n");
2685
2690
  return {
2686
2691
  content: [{ type: "text", text: list }]
@@ -2691,8 +2696,8 @@ var FileSystemServer = class {
2691
2696
  const toPath = this.validatePath(args.to);
2692
2697
  const overwrite = Boolean(args.overwrite);
2693
2698
  await this.ensureDestWritable(toPath, overwrite);
2694
- await fs5.mkdir(path7.dirname(toPath), { recursive: true });
2695
- await fs5.copyFile(fromPath, toPath);
2699
+ await fs6.mkdir(path8.dirname(toPath), { recursive: true });
2700
+ await fs6.copyFile(fromPath, toPath);
2696
2701
  return {
2697
2702
  content: [{ type: "text", text: `Successfully copied ${fromPath} -> ${toPath}` }]
2698
2703
  };
@@ -2702,7 +2707,7 @@ var FileSystemServer = class {
2702
2707
  const toPath = this.validatePath(args.to);
2703
2708
  const overwrite = Boolean(args.overwrite);
2704
2709
  await this.ensureDestWritable(toPath, overwrite);
2705
- await fs5.mkdir(path7.dirname(toPath), { recursive: true });
2710
+ await fs6.mkdir(path8.dirname(toPath), { recursive: true });
2706
2711
  await this.moveFile(fromPath, toPath);
2707
2712
  return {
2708
2713
  content: [{ type: "text", text: `Successfully moved ${fromPath} -> ${toPath}` }]
@@ -2724,9 +2729,9 @@ var FileSystemServer = class {
2724
2729
  const overwrite = Boolean(args.overwrite);
2725
2730
  const maxBytes = Math.max(1024, Number(args.maxBytes) || 20 * 1024 * 1024);
2726
2731
  await this.ensureDestWritable(outputPath, overwrite);
2727
- await fs5.mkdir(path7.dirname(outputPath), { recursive: true });
2732
+ await fs6.mkdir(path8.dirname(outputPath), { recursive: true });
2728
2733
  const bundle = await this.createArchiveBundle(sourcePath, maxBytes);
2729
- await fs5.writeFile(outputPath, bundle.buffer);
2734
+ await fs6.writeFile(outputPath, bundle.buffer);
2730
2735
  return {
2731
2736
  content: [{ type: "text", text: `Successfully archived ${bundle.fileCount} file(s) to ${outputPath}` }]
2732
2737
  };
@@ -2736,7 +2741,7 @@ var FileSystemServer = class {
2736
2741
  const outputDir = this.validatePath(args.outputDir);
2737
2742
  const overwrite = Boolean(args.overwrite);
2738
2743
  const maxBytes = Math.max(1024, Number(args.maxBytes) || 20 * 1024 * 1024);
2739
- const archiveBuffer = await fs5.readFile(archivePath);
2744
+ const archiveBuffer = await fs6.readFile(archivePath);
2740
2745
  const bundle = this.parseArchiveBundle(archiveBuffer);
2741
2746
  const written = await this.extractArchiveBundle(bundle, outputDir, overwrite, maxBytes);
2742
2747
  return {
@@ -2756,11 +2761,11 @@ var FileSystemServer = class {
2756
2761
  }
2757
2762
  async ensureDestWritable(destPath, overwrite) {
2758
2763
  try {
2759
- await fs5.access(destPath);
2764
+ await fs6.access(destPath);
2760
2765
  if (!overwrite) {
2761
2766
  throw new Error(`Destination already exists: ${destPath}. Pass overwrite=true to replace.`);
2762
2767
  }
2763
- await fs5.rm(destPath, { recursive: true, force: true });
2768
+ await fs6.rm(destPath, { recursive: true, force: true });
2764
2769
  } catch (error) {
2765
2770
  if (error?.code === "ENOENT") return;
2766
2771
  throw error;
@@ -2768,11 +2773,11 @@ var FileSystemServer = class {
2768
2773
  }
2769
2774
  async moveFile(fromPath, toPath) {
2770
2775
  try {
2771
- await fs5.rename(fromPath, toPath);
2776
+ await fs6.rename(fromPath, toPath);
2772
2777
  } catch (error) {
2773
2778
  if (error?.code !== "EXDEV") throw error;
2774
- await fs5.copyFile(fromPath, toPath);
2775
- await fs5.unlink(fromPath);
2779
+ await fs6.copyFile(fromPath, toPath);
2780
+ await fs6.unlink(fromPath);
2776
2781
  }
2777
2782
  }
2778
2783
  async searchByName(basePath, pattern, maxResults) {
@@ -2782,10 +2787,10 @@ var FileSystemServer = class {
2782
2787
  while (queue.length > 0 && results.length < maxResults) {
2783
2788
  const current = queue.shift();
2784
2789
  if (!current) break;
2785
- const entries = await fs5.readdir(current, { withFileTypes: true });
2790
+ const entries = await fs6.readdir(current, { withFileTypes: true });
2786
2791
  for (const entry of entries) {
2787
- const fullPath = path7.join(current, entry.name);
2788
- const relative3 = path7.relative(this.allowedRootDir, fullPath) || ".";
2792
+ const fullPath = path8.join(current, entry.name);
2793
+ const relative3 = path8.relative(this.allowedRootDir, fullPath) || ".";
2789
2794
  if (matcher(entry.name)) {
2790
2795
  results.push(`${entry.isDirectory() ? "[DIR]" : "[FILE]"} ${relative3}`);
2791
2796
  if (results.length >= maxResults) break;
@@ -2809,11 +2814,11 @@ var FileSystemServer = class {
2809
2814
  return (name) => name.toLowerCase().includes(lowered);
2810
2815
  }
2811
2816
  async createArchiveBundle(sourcePath, maxBytes) {
2812
- const stat3 = await fs5.stat(sourcePath);
2817
+ const stat3 = await fs6.stat(sourcePath);
2813
2818
  const files = [];
2814
2819
  let totalBytes = 0;
2815
2820
  const readAndAppend = async (absolutePath, relativePath) => {
2816
- const data = await fs5.readFile(absolutePath);
2821
+ const data = await fs6.readFile(absolutePath);
2817
2822
  totalBytes += data.length;
2818
2823
  if (totalBytes > maxBytes) {
2819
2824
  throw new Error(`Archive exceeds maxBytes limit (${maxBytes}).`);
@@ -2826,28 +2831,28 @@ var FileSystemServer = class {
2826
2831
  });
2827
2832
  };
2828
2833
  if (stat3.isFile()) {
2829
- await readAndAppend(sourcePath, path7.basename(sourcePath));
2834
+ await readAndAppend(sourcePath, path8.basename(sourcePath));
2830
2835
  } else if (stat3.isDirectory()) {
2831
2836
  const queue = [sourcePath];
2832
2837
  while (queue.length > 0) {
2833
2838
  const current = queue.shift();
2834
2839
  if (!current) break;
2835
- const entries = await fs5.readdir(current, { withFileTypes: true });
2840
+ const entries = await fs6.readdir(current, { withFileTypes: true });
2836
2841
  for (const entry of entries) {
2837
- const fullPath = path7.join(current, entry.name);
2842
+ const fullPath = path8.join(current, entry.name);
2838
2843
  if (entry.isDirectory()) {
2839
2844
  queue.push(fullPath);
2840
2845
  continue;
2841
2846
  }
2842
2847
  if (!entry.isFile()) continue;
2843
- const relativePath = path7.relative(sourcePath, fullPath) || entry.name;
2848
+ const relativePath = path8.relative(sourcePath, fullPath) || entry.name;
2844
2849
  await readAndAppend(fullPath, relativePath.replace(/\\/g, "/"));
2845
2850
  }
2846
2851
  }
2847
2852
  } else {
2848
2853
  throw new Error("Only files and directories can be archived.");
2849
2854
  }
2850
- const sourceRelative = path7.relative(this.allowedRootDir, sourcePath).replace(/\\/g, "/");
2855
+ const sourceRelative = path8.relative(this.allowedRootDir, sourcePath).replace(/\\/g, "/");
2851
2856
  const bundle = {
2852
2857
  format: "lydia-archive-v1",
2853
2858
  source: sourceRelative || ".",
@@ -2880,13 +2885,13 @@ var FileSystemServer = class {
2880
2885
  let count = 0;
2881
2886
  for (const file of bundle.files) {
2882
2887
  const relPath = String(file.path || "").replace(/\\/g, "/");
2883
- if (!relPath || path7.isAbsolute(relPath) || relPath.includes("..")) {
2888
+ if (!relPath || path8.isAbsolute(relPath) || relPath.includes("..")) {
2884
2889
  throw new Error(`Unsafe archive entry path: ${relPath || "<empty>"}`);
2885
2890
  }
2886
- const targetPath = path7.resolve(outputDir, relPath);
2891
+ const targetPath = path8.resolve(outputDir, relPath);
2887
2892
  const safeOutputDir = process.platform === "win32" ? outputDir.toLowerCase() : outputDir;
2888
2893
  const safeTarget = process.platform === "win32" ? targetPath.toLowerCase() : targetPath;
2889
- if (!safeTarget.startsWith(safeOutputDir + path7.sep) && safeTarget !== safeOutputDir) {
2894
+ if (!safeTarget.startsWith(safeOutputDir + path8.sep) && safeTarget !== safeOutputDir) {
2890
2895
  throw new Error(`Archive entry escapes destination: ${relPath}`);
2891
2896
  }
2892
2897
  const data = this.decodeArchiveEntry(file);
@@ -2894,8 +2899,8 @@ var FileSystemServer = class {
2894
2899
  if (totalBytes > maxBytes) {
2895
2900
  throw new Error(`Unarchive exceeds maxBytes limit (${maxBytes}).`);
2896
2901
  }
2897
- await fs5.mkdir(path7.dirname(targetPath), { recursive: true });
2898
- await fs5.writeFile(targetPath, data);
2902
+ await fs6.mkdir(path8.dirname(targetPath), { recursive: true });
2903
+ await fs6.writeFile(targetPath, data);
2899
2904
  count += 1;
2900
2905
  }
2901
2906
  return count;
@@ -2915,22 +2920,22 @@ var FileSystemServer = class {
2915
2920
  }
2916
2921
  async prepareOutputDirectory(outputDir, overwrite) {
2917
2922
  try {
2918
- const stat3 = await fs5.stat(outputDir);
2923
+ const stat3 = await fs6.stat(outputDir);
2919
2924
  if (!stat3.isDirectory()) {
2920
2925
  throw new Error(`Output path is not a directory: ${outputDir}`);
2921
2926
  }
2922
2927
  if (!overwrite) {
2923
- const entries = await fs5.readdir(outputDir);
2928
+ const entries = await fs6.readdir(outputDir);
2924
2929
  if (entries.length > 0) {
2925
2930
  throw new Error(`Output directory is not empty: ${outputDir}. Pass overwrite=true to replace.`);
2926
2931
  }
2927
2932
  } else {
2928
- await fs5.rm(outputDir, { recursive: true, force: true });
2929
- await fs5.mkdir(outputDir, { recursive: true });
2933
+ await fs6.rm(outputDir, { recursive: true, force: true });
2934
+ await fs6.mkdir(outputDir, { recursive: true });
2930
2935
  }
2931
2936
  } catch (error) {
2932
2937
  if (error?.code === "ENOENT") {
2933
- await fs5.mkdir(outputDir, { recursive: true });
2938
+ await fs6.mkdir(outputDir, { recursive: true });
2934
2939
  return;
2935
2940
  }
2936
2941
  throw error;
@@ -2950,7 +2955,7 @@ var GitServer = class {
2950
2955
  this.server = new Server3(
2951
2956
  {
2952
2957
  name: "internal-git",
2953
- version: "0.1.0"
2958
+ version: "0.1.2"
2954
2959
  },
2955
2960
  {
2956
2961
  capabilities: {
@@ -3127,7 +3132,7 @@ var MemoryServer = class {
3127
3132
  this.server = new Server4(
3128
3133
  {
3129
3134
  name: "internal-memory",
3130
- version: "0.1.0"
3135
+ version: "0.1.2"
3131
3136
  },
3132
3137
  {
3133
3138
  capabilities: {
@@ -3253,7 +3258,7 @@ var InteractionServer = class extends EventEmitter3 {
3253
3258
  constructor() {
3254
3259
  super();
3255
3260
  this.server = new Server5(
3256
- { name: "internal-interaction", version: "0.1.0" },
3261
+ { name: "internal-interaction", version: "0.1.2" },
3257
3262
  { capabilities: { tools: {} } }
3258
3263
  );
3259
3264
  this.setupHandlers();
@@ -3634,7 +3639,7 @@ var McpClientManager = class {
3634
3639
  const client = new Client(
3635
3640
  {
3636
3641
  name: "lydia-client",
3637
- version: "0.1.0"
3642
+ version: "0.1.2"
3638
3643
  },
3639
3644
  {
3640
3645
  capabilities: {
@@ -3742,7 +3747,7 @@ var McpClientManager = class {
3742
3747
  };
3743
3748
 
3744
3749
  // src/gate/risk.ts
3745
- import * as path8 from "path";
3750
+ import * as path9 from "path";
3746
3751
  import * as os6 from "os";
3747
3752
  var DEFAULT_USER_DATA_DIRS = [
3748
3753
  "~/.lydia",
@@ -3772,13 +3777,13 @@ var COMPUTER_USE_HIGH_RISK_ACTIONS = /* @__PURE__ */ new Set([
3772
3777
  ]);
3773
3778
  function expandHome(p) {
3774
3779
  if (p.startsWith("~/") || p === "~") {
3775
- return path8.join(os6.homedir(), p.slice(2));
3780
+ return path9.join(os6.homedir(), p.slice(2));
3776
3781
  }
3777
3782
  return p;
3778
3783
  }
3779
3784
  function normalizePath(p) {
3780
3785
  const expanded = expandHome(p);
3781
- const normalized = path8.resolve(expanded);
3786
+ const normalized = path9.resolve(expanded);
3782
3787
  return process.platform === "win32" ? normalized.toLowerCase() : normalized;
3783
3788
  }
3784
3789
  function buildProtectedDirs(config) {
@@ -3791,7 +3796,7 @@ function buildProtectedDirs(config) {
3791
3796
  }
3792
3797
  function isInProtectedDir(targetPath, protectedDirs) {
3793
3798
  const normalizedTarget = normalizePath(targetPath);
3794
- return protectedDirs.some((dir) => normalizedTarget === dir || normalizedTarget.startsWith(dir + path8.sep));
3799
+ return protectedDirs.some((dir) => normalizedTarget === dir || normalizedTarget.startsWith(dir + path9.sep));
3795
3800
  }
3796
3801
  function extractPathsFromCommand(command) {
3797
3802
  const paths = [];
@@ -3813,7 +3818,7 @@ function hasRelativePathTraversal(input) {
3813
3818
  return /(^|[\\\/])\.\.([\\\/]|$)/.test(input);
3814
3819
  }
3815
3820
  function isRelativePath(input) {
3816
- return !path8.isAbsolute(input);
3821
+ return !path9.isAbsolute(input);
3817
3822
  }
3818
3823
  function resolveCanonicalComputerUseAction(toolName) {
3819
3824
  const direct = resolveCanonicalComputerUseToolName(toolName);
@@ -3878,7 +3883,7 @@ function assessRisk(toolName, args, mcp, config) {
3878
3883
  return {
3879
3884
  level: "high",
3880
3885
  reason: `${opLabel} with relative path traversal`,
3881
- signature: `fs_write_rel:${normalizePath(path8.resolve(targetPath))}`,
3886
+ signature: `fs_write_rel:${normalizePath(path9.resolve(targetPath))}`,
3882
3887
  details: targetPath
3883
3888
  };
3884
3889
  }
@@ -3909,6 +3914,14 @@ function assessRisk(toolName, args, mcp, config) {
3909
3914
  if (toolName === "shell_execute") {
3910
3915
  const command = typeof args?.command === "string" ? args.command : "";
3911
3916
  if (command && (isDestructiveShellCommand(command) || isPermissionChangeCommand(command))) {
3917
+ if (isPermissionChangeCommand(command)) {
3918
+ return {
3919
+ level: "high",
3920
+ reason: "Permission change shell command",
3921
+ signature: `shell_permission:${command.toLowerCase().slice(0, 80)}`,
3922
+ details: command
3923
+ };
3924
+ }
3912
3925
  const targets = extractPathsFromCommand(command);
3913
3926
  const hasTraversal = hasRelativePathTraversal(command);
3914
3927
  if (targets.length === 0 || hasTraversal) {
@@ -4147,7 +4160,7 @@ var StrategyUpdateGate = class {
4147
4160
  };
4148
4161
 
4149
4162
  // src/gate/review-manager.ts
4150
- import * as path9 from "path";
4163
+ import * as path10 from "path";
4151
4164
  import * as os7 from "os";
4152
4165
  var ReviewManager = class {
4153
4166
  memory;
@@ -4156,7 +4169,7 @@ var ReviewManager = class {
4156
4169
  this.memory = memoryManager;
4157
4170
  return;
4158
4171
  }
4159
- const dbPath = path9.join(os7.homedir(), ".lydia", "memory.db");
4172
+ const dbPath = path10.join(os7.homedir(), ".lydia", "memory.db");
4160
4173
  this.memory = new MemoryManager(dbPath);
4161
4174
  }
4162
4175
  async init() {
@@ -4335,7 +4348,7 @@ ${this.originalPlan}
4335
4348
  };
4336
4349
 
4337
4350
  // src/replay/mcp.ts
4338
- import * as path10 from "path";
4351
+ import * as path11 from "path";
4339
4352
  var ReplayMcpClientManager = class extends McpClientManager {
4340
4353
  traces;
4341
4354
  callIndex = 0;
@@ -4490,12 +4503,12 @@ var ReplayMcpClientManager = class extends McpClientManager {
4490
4503
  const loweredPattern = rawPattern.toLowerCase();
4491
4504
  const names = /* @__PURE__ */ new Set();
4492
4505
  for (const storedPath of this.virtualFiles.keys()) {
4493
- const rel = path10.relative(normalized, storedPath);
4506
+ const rel = path11.relative(normalized, storedPath);
4494
4507
  if (rel.startsWith("..")) continue;
4495
4508
  const parts = rel.split("/").filter(Boolean);
4496
4509
  for (const part of parts) {
4497
4510
  if (part.toLowerCase().includes(loweredPattern)) {
4498
- names.add(`[FILE] ${path10.posix.join(path10.posix.relative(this.virtualRoot, normalized), rel)}`);
4511
+ names.add(`[FILE] ${path11.posix.join(path11.posix.relative(this.virtualRoot, normalized), rel)}`);
4499
4512
  break;
4500
4513
  }
4501
4514
  }
@@ -4523,12 +4536,12 @@ var ReplayMcpClientManager = class extends McpClientManager {
4523
4536
  createdAt: 0,
4524
4537
  totalBytes: sourceFile ? sourceFile.length : sourceEntries.reduce((acc, [, text]) => acc + text.length, 0),
4525
4538
  files: sourceFile ? [{
4526
- path: path10.posix.basename(source),
4539
+ path: path11.posix.basename(source),
4527
4540
  size: sourceFile.length,
4528
4541
  encoding: "base64",
4529
4542
  data: Buffer.from(sourceFile, "utf-8").toString("base64")
4530
4543
  }] : sourceEntries.map(([filePath, text]) => ({
4531
- path: path10.posix.relative(source, filePath),
4544
+ path: path11.posix.relative(source, filePath),
4532
4545
  size: text.length,
4533
4546
  encoding: "base64",
4534
4547
  data: Buffer.from(text, "utf-8").toString("base64")
@@ -4583,7 +4596,7 @@ var ReplayMcpClientManager = class extends McpClientManager {
4583
4596
  for (const item of parsed.files) {
4584
4597
  const rel = typeof item?.path === "string" ? item.path.replace(/\\/g, "/") : "";
4585
4598
  if (!rel || rel.includes("..") || rel.startsWith("/")) continue;
4586
- const target = this.normalizeFsPath(path10.posix.join(outputDir, rel));
4599
+ const target = this.normalizeFsPath(path11.posix.join(outputDir, rel));
4587
4600
  const base64 = typeof item?.data === "string" ? item.data : "";
4588
4601
  const text = base64 ? Buffer.from(base64, "base64").toString("utf-8") : "";
4589
4602
  this.virtualFiles.set(target, text);
@@ -4876,12 +4889,12 @@ var ReplayMcpClientManager = class extends McpClientManager {
4876
4889
  if (driveMatch) {
4877
4890
  const drive = driveMatch[1].toLowerCase();
4878
4891
  const rest = driveMatch[2] || "/";
4879
- return path10.posix.normalize(`/${drive}${rest}`);
4892
+ return path11.posix.normalize(`/${drive}${rest}`);
4880
4893
  }
4881
4894
  if (source.startsWith("/")) {
4882
- return path10.posix.normalize(source);
4895
+ return path11.posix.normalize(source);
4883
4896
  }
4884
- return path10.posix.normalize(path10.posix.join(this.virtualRoot, source));
4897
+ return path11.posix.normalize(path11.posix.join(this.virtualRoot, source));
4885
4898
  }
4886
4899
  listDirectoryEntries(directory) {
4887
4900
  const normalizedDir = this.normalizeFsPath(directory);
@@ -5072,7 +5085,7 @@ var StrategyEvaluator = class {
5072
5085
  };
5073
5086
 
5074
5087
  // src/replay/manager.ts
5075
- import * as path11 from "path";
5088
+ import * as path12 from "path";
5076
5089
  import * as os8 from "os";
5077
5090
  var ReplayManager = class {
5078
5091
  memoryManager;
@@ -5081,7 +5094,7 @@ var ReplayManager = class {
5081
5094
  if (memoryManager) {
5082
5095
  this.memoryManager = memoryManager;
5083
5096
  } else {
5084
- const dbPath = path11.join(os8.homedir(), ".lydia", "memory.db");
5097
+ const dbPath = path12.join(os8.homedir(), ".lydia", "memory.db");
5085
5098
  this.memoryManager = new MemoryManager(dbPath);
5086
5099
  }
5087
5100
  this.evaluator = new StrategyEvaluator();
@@ -5101,7 +5114,7 @@ var ReplayManager = class {
5101
5114
  const agent = new Agent(mockLLM);
5102
5115
  agent.mcpClientManager = mockMcp;
5103
5116
  agent.isInitialized = true;
5104
- const tempDb = path11.join(os8.tmpdir(), `lydia-replay-${Date.now()}-${episodeId}.db`);
5117
+ const tempDb = path12.join(os8.tmpdir(), `lydia-replay-${Date.now()}-${episodeId}.db`);
5105
5118
  agent.memoryManager = new MemoryManager(tempDb);
5106
5119
  try {
5107
5120
  const config = await agent.configLoader.load();
@@ -5421,7 +5434,7 @@ var FeedbackCollector = class {
5421
5434
  };
5422
5435
 
5423
5436
  // src/execution/agent.ts
5424
- import * as path12 from "path";
5437
+ import * as path13 from "path";
5425
5438
  import * as os9 from "os";
5426
5439
  var Agent = class extends EventEmitter5 {
5427
5440
  llm;
@@ -5518,7 +5531,7 @@ var Agent = class extends EventEmitter5 {
5518
5531
  await this.reviewManager.init();
5519
5532
  const config = await this.configLoader.load();
5520
5533
  this.config = config;
5521
- const dbPath = path12.join(os9.homedir(), ".lydia", "memory.db");
5534
+ const dbPath = path13.join(os9.homedir(), ".lydia", "memory.db");
5522
5535
  this.memoryManager = new MemoryManager(dbPath, {
5523
5536
  checkpointTtlMs: Math.max(1, config.memory?.checkpointTtlHours ?? 24) * 60 * 60 * 1e3,
5524
5537
  observationFrameTtlMs: Math.max(1, config.memory?.observationFrameTtlHours ?? 24 * 7) * 60 * 60 * 1e3