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