codesavant 4.0.0 → 4.0.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/README.md +88 -456
  2. package/dist/cli.js +364 -297
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -43059,9 +43059,9 @@ var init_config = __esm(() => {
43059
43059
 
43060
43060
  // src/settings.ts
43061
43061
  import { existsSync as existsSync13 } from "fs";
43062
- import { mkdir as mkdir12, readFile as readFile19, writeFile as writeFile4 } from "fs/promises";
43063
- import { homedir as homedir8 } from "os";
43064
- import { join as join16 } from "path";
43062
+ import { mkdir as mkdir11, readFile as readFile19, writeFile as writeFile4 } from "fs/promises";
43063
+ import { homedir as homedir7 } from "os";
43064
+ import { join as join14 } from "path";
43065
43065
  async function loadSettings(path) {
43066
43066
  if (!existsSync13(path)) {
43067
43067
  return {};
@@ -43087,12 +43087,12 @@ async function loadUserSettings() {
43087
43087
  return loadSettings(USER_SETTINGS_PATH);
43088
43088
  }
43089
43089
  async function loadProjectSettings(cwd2 = process.cwd()) {
43090
- return loadSettings(join16(cwd2, PROJECT_SETTINGS_PATH));
43090
+ return loadSettings(join14(cwd2, PROJECT_SETTINGS_PATH));
43091
43091
  }
43092
- async function saveUserSettings(settings, homeDir = homedir8()) {
43093
- const settingsDir = join16(homeDir, ".codesavant");
43094
- const settingsPath = join16(settingsDir, "settings.json");
43095
- await mkdir12(settingsDir, { recursive: true });
43092
+ async function saveUserSettings(settings, homeDir = homedir7()) {
43093
+ const settingsDir = join14(homeDir, ".codesavant");
43094
+ const settingsPath = join14(settingsDir, "settings.json");
43095
+ await mkdir11(settingsDir, { recursive: true });
43096
43096
  const existing = await loadSettings(settingsPath);
43097
43097
  const merged = deepMerge(existing, settings);
43098
43098
  await writeFile4(settingsPath, JSON.stringify(merged, null, 2), {
@@ -43102,7 +43102,7 @@ async function saveUserSettings(settings, homeDir = homedir8()) {
43102
43102
  var USER_SETTINGS_PATH, PROJECT_SETTINGS_PATH = ".codesavant/settings.json", PartialConfigSchema;
43103
43103
  var init_settings = __esm(() => {
43104
43104
  init_config();
43105
- USER_SETTINGS_PATH = join16(homedir8(), ".codesavant", "settings.json");
43105
+ USER_SETTINGS_PATH = join14(homedir7(), ".codesavant", "settings.json");
43106
43106
  PartialConfigSchema = ConfigSchema.partial();
43107
43107
  });
43108
43108
 
@@ -45606,7 +45606,7 @@ var require_semver2 = __commonJS((exports, module) => {
45606
45606
  });
45607
45607
 
45608
45608
  // src/marketplace/types.ts
45609
- import { readFile as readFile24, mkdir as mkdir15 } from "fs/promises";
45609
+ import { readFile as readFile24, mkdir as mkdir14 } from "fs/promises";
45610
45610
  import { existsSync as existsSync15 } from "fs";
45611
45611
  import { dirname as dirname13 } from "path";
45612
45612
 
@@ -45643,7 +45643,7 @@ class InstallRecordStore {
45643
45643
  await this.save(existing.map((r) => r.slug === slug ? { ...r, pinned: false } : r));
45644
45644
  }
45645
45645
  async save(records) {
45646
- await mkdir15(dirname13(this.filePath), { recursive: true });
45646
+ await mkdir14(dirname13(this.filePath), { recursive: true });
45647
45647
  await atomicWriteFile(this.filePath, JSON.stringify(records, null, 2));
45648
45648
  }
45649
45649
  }
@@ -45693,9 +45693,9 @@ var init_types2 = __esm(() => {
45693
45693
 
45694
45694
  // src/marketplace/installer.ts
45695
45695
  import { createHash as createHash5, timingSafeEqual } from "crypto";
45696
- import { homedir as homedir11 } from "os";
45697
- import { join as join21, dirname as dirname14 } from "path";
45698
- import { mkdir as mkdir16 } from "fs/promises";
45696
+ import { homedir as homedir10 } from "os";
45697
+ import { join as join19, dirname as dirname14 } from "path";
45698
+ import { mkdir as mkdir15 } from "fs/promises";
45699
45699
  function normalizeContent(content) {
45700
45700
  return content.replace(/\r\n/g, `
45701
45701
  `);
@@ -45721,8 +45721,8 @@ class SkillInstaller {
45721
45721
  constructor(deps = {}) {
45722
45722
  this.fetchFn = deps.fetch ?? globalThis.fetch.bind(globalThis);
45723
45723
  this.writeFn = deps.atomicWrite ?? atomicWriteFile;
45724
- this.skillsDir = deps.skillsDir ?? join21(homedir11(), ".codesavant", "skills");
45725
- this.installStore = deps.installStore ?? new InstallRecordStore(join21(homedir11(), ".codesavant", "marketplace-installs.json"));
45724
+ this.skillsDir = deps.skillsDir ?? join19(homedir10(), ".codesavant", "skills");
45725
+ this.installStore = deps.installStore ?? new InstallRecordStore(join19(homedir10(), ".codesavant", "marketplace-installs.json"));
45726
45726
  this.localSkillChecker = deps.localSkillChecker;
45727
45727
  }
45728
45728
  async previewInstall(skill2) {
@@ -45756,8 +45756,8 @@ class SkillInstaller {
45756
45756
  if (!verifyHash(content, expectedHash)) {
45757
45757
  throw new HashMismatchError(expectedHash, hashContent(content));
45758
45758
  }
45759
- const targetPath = join21(this.skillsDir, skill2.slug, "SKILL.md");
45760
- await mkdir16(dirname14(targetPath), { recursive: true });
45759
+ const targetPath = join19(this.skillsDir, skill2.slug, "SKILL.md");
45760
+ await mkdir15(dirname14(targetPath), { recursive: true });
45761
45761
  await this.writeFn(targetPath, content);
45762
45762
  const record = {
45763
45763
  slug: skill2.slug,
@@ -46705,7 +46705,7 @@ async function hook(token, request2, route, parameters) {
46705
46705
  endpoint2.headers.authorization = withAuthorizationPrefix(token);
46706
46706
  return request2(endpoint2);
46707
46707
  }
46708
- var b64url = "(?:[a-zA-Z0-9_-]+)", sep2 = "\\.", jwtRE, isJWT, createTokenAuth = function createTokenAuth2(token) {
46708
+ var b64url = "(?:[a-zA-Z0-9_-]+)", sep = "\\.", jwtRE, isJWT, createTokenAuth = function createTokenAuth2(token) {
46709
46709
  if (!token) {
46710
46710
  throw new Error("[@octokit/auth-token] No token passed to createTokenAuth");
46711
46711
  }
@@ -46718,7 +46718,7 @@ var b64url = "(?:[a-zA-Z0-9_-]+)", sep2 = "\\.", jwtRE, isJWT, createTokenAuth =
46718
46718
  });
46719
46719
  };
46720
46720
  var init_dist_bundle4 = __esm(() => {
46721
- jwtRE = new RegExp(`^${b64url}${sep2}${b64url}${sep2}${b64url}$`);
46721
+ jwtRE = new RegExp(`^${b64url}${sep}${b64url}${sep}${b64url}$`);
46722
46722
  isJWT = jwtRE.test.bind(jwtRE);
46723
46723
  });
46724
46724
 
@@ -49964,8 +49964,8 @@ var require_light = __commonJS((exports, module) => {
49964
49964
  return this.Promise.resolve();
49965
49965
  }
49966
49966
  yieldLoop(t = 0) {
49967
- return new this.Promise(function(resolve12, reject) {
49968
- return setTimeout(resolve12, t);
49967
+ return new this.Promise(function(resolve11, reject) {
49968
+ return setTimeout(resolve11, t);
49969
49969
  });
49970
49970
  }
49971
49971
  computePenalty() {
@@ -50176,15 +50176,15 @@ var require_light = __commonJS((exports, module) => {
50176
50176
  return this._queue.length === 0;
50177
50177
  }
50178
50178
  async _tryToRun() {
50179
- var args, cb, error, reject, resolve12, returned, task2;
50179
+ var args, cb, error, reject, resolve11, returned, task2;
50180
50180
  if (this._running < 1 && this._queue.length > 0) {
50181
50181
  this._running++;
50182
- ({ task: task2, args, resolve: resolve12, reject } = this._queue.shift());
50182
+ ({ task: task2, args, resolve: resolve11, reject } = this._queue.shift());
50183
50183
  cb = await async function() {
50184
50184
  try {
50185
50185
  returned = await task2(...args);
50186
50186
  return function() {
50187
- return resolve12(returned);
50187
+ return resolve11(returned);
50188
50188
  };
50189
50189
  } catch (error1) {
50190
50190
  error = error1;
@@ -50199,13 +50199,13 @@ var require_light = __commonJS((exports, module) => {
50199
50199
  }
50200
50200
  }
50201
50201
  schedule(task2, ...args) {
50202
- var promise, reject, resolve12;
50203
- resolve12 = reject = null;
50202
+ var promise, reject, resolve11;
50203
+ resolve11 = reject = null;
50204
50204
  promise = new this.Promise(function(_resolve, _reject) {
50205
- resolve12 = _resolve;
50205
+ resolve11 = _resolve;
50206
50206
  return reject = _reject;
50207
50207
  });
50208
- this._queue.push({ task: task2, args, resolve: resolve12, reject });
50208
+ this._queue.push({ task: task2, args, resolve: resolve11, reject });
50209
50209
  this._tryToRun();
50210
50210
  return promise;
50211
50211
  }
@@ -50609,14 +50609,14 @@ var require_light = __commonJS((exports, module) => {
50609
50609
  counts = this._states.counts;
50610
50610
  return counts[0] + counts[1] + counts[2] + counts[3] === at;
50611
50611
  };
50612
- return new this.Promise((resolve12, reject) => {
50612
+ return new this.Promise((resolve11, reject) => {
50613
50613
  if (finished()) {
50614
- return resolve12();
50614
+ return resolve11();
50615
50615
  } else {
50616
50616
  return this.on("done", () => {
50617
50617
  if (finished()) {
50618
50618
  this.removeAllListeners("done");
50619
- return resolve12();
50619
+ return resolve11();
50620
50620
  }
50621
50621
  });
50622
50622
  }
@@ -50709,9 +50709,9 @@ var require_light = __commonJS((exports, module) => {
50709
50709
  options2 = parser$5.load(options2, this.jobDefaults);
50710
50710
  }
50711
50711
  task2 = (...args2) => {
50712
- return new this.Promise(function(resolve12, reject) {
50712
+ return new this.Promise(function(resolve11, reject) {
50713
50713
  return fn(...args2, function(...args3) {
50714
- return (args3[0] != null ? reject : resolve12)(args3);
50714
+ return (args3[0] != null ? reject : resolve11)(args3);
50715
50715
  });
50716
50716
  });
50717
50717
  };
@@ -51388,7 +51388,7 @@ function getCachedAuthentication(state, auth2) {
51388
51388
  return newScope === currentScope ? authentication : false;
51389
51389
  }
51390
51390
  async function wait(seconds) {
51391
- await new Promise((resolve12) => setTimeout(resolve12, seconds * 1000));
51391
+ await new Promise((resolve11) => setTimeout(resolve11, seconds * 1000));
51392
51392
  }
51393
51393
  async function waitForAccessToken(request2, clientId, clientType, verification) {
51394
51394
  try {
@@ -52302,7 +52302,7 @@ async function sendRequestWithRetries(state, request2, options2, createdAt, retr
52302
52302
  ++retries;
52303
52303
  const awaitTime = retries * 1000;
52304
52304
  state.log.warn(`[@octokit/auth-app] Retrying after 401 response to account for token replication delay (retry: ${retries}, wait: ${awaitTime / 1000}s)`);
52305
- await new Promise((resolve12) => setTimeout(resolve12, awaitTime));
52305
+ await new Promise((resolve11) => setTimeout(resolve11, awaitTime));
52306
52306
  return sendRequestWithRetries(state, request2, options2, createdAt, retries);
52307
52307
  }
52308
52308
  }
@@ -53675,19 +53675,19 @@ var init_dist_bundle14 = __esm(() => {
53675
53675
  });
53676
53676
 
53677
53677
  // src/marketplace/registry.ts
53678
- import { readFile as readFile26, mkdir as mkdir18 } from "fs/promises";
53678
+ import { readFile as readFile26, mkdir as mkdir17 } from "fs/promises";
53679
53679
  import { existsSync as existsSync16 } from "fs";
53680
- import { homedir as homedir12 } from "os";
53681
- import { join as join23, dirname as dirname15 } from "path";
53680
+ import { homedir as homedir11 } from "os";
53681
+ import { join as join21, dirname as dirname15 } from "path";
53682
53682
 
53683
53683
  class RegistryClient {
53684
53684
  octokit;
53685
53685
  cachePath;
53686
53686
  cacheTTLMs;
53687
- constructor(token, cacheTTLMs = 3600000, cacheDir = join23(homedir12(), ".codesavant"), octokitInstance) {
53687
+ constructor(token, cacheTTLMs = 3600000, cacheDir = join21(homedir11(), ".codesavant"), octokitInstance) {
53688
53688
  this.octokit = octokitInstance ?? new Octokit2({ auth: token });
53689
53689
  this.cacheTTLMs = cacheTTLMs;
53690
- this.cachePath = join23(cacheDir, "marketplace-cache.json");
53690
+ this.cachePath = join21(cacheDir, "marketplace-cache.json");
53691
53691
  }
53692
53692
  async search(query, tag) {
53693
53693
  const cacheKey = `${query}:${tag ?? ""}`;
@@ -53736,7 +53736,7 @@ class RegistryClient {
53736
53736
  }
53737
53737
  }
53738
53738
  async writeCache(cache4) {
53739
- await mkdir18(dirname15(this.cachePath), { recursive: true });
53739
+ await mkdir17(dirname15(this.cachePath), { recursive: true });
53740
53740
  await atomicWriteFile(this.cachePath, JSON.stringify(cache4, null, 2));
53741
53741
  }
53742
53742
  }
@@ -53757,13 +53757,13 @@ var exports_marketplace_server = {};
53757
53757
  __export(exports_marketplace_server, {
53758
53758
  startMarketplaceServer: () => startMarketplaceServer
53759
53759
  });
53760
- import { join as join26 } from "path";
53760
+ import { join as join24 } from "path";
53761
53761
  import { existsSync as existsSync19 } from "fs";
53762
- import { homedir as homedir15 } from "os";
53762
+ import { homedir as homedir14 } from "os";
53763
53763
  function startMarketplaceServer() {
53764
- const uiDistPath = join26(import.meta.dir, "..", "..", "dist", "marketplace-ui");
53765
- const hasUI = existsSync19(join26(uiDistPath, "index.html"));
53766
- const installStore = new InstallRecordStore(join26(homedir15(), ".codesavant", "marketplace-installs.json"));
53764
+ const uiDistPath = join24(import.meta.dir, "..", "..", "dist", "marketplace-ui");
53765
+ const hasUI = existsSync19(join24(uiDistPath, "index.html"));
53766
+ const installStore = new InstallRecordStore(join24(homedir14(), ".codesavant", "marketplace-installs.json"));
53767
53767
  const installer = new SkillInstaller({ installStore });
53768
53768
  const registry = new RegistryClient;
53769
53769
  const server = Bun.serve({
@@ -53775,11 +53775,11 @@ function startMarketplaceServer() {
53775
53775
  return ok ? undefined : new Response("WS upgrade failed", { status: 400 });
53776
53776
  }
53777
53777
  if (hasUI) {
53778
- const filePath = url.pathname === "/" || url.pathname === "" ? join26(uiDistPath, "index.html") : join26(uiDistPath, url.pathname);
53778
+ const filePath = url.pathname === "/" || url.pathname === "" ? join24(uiDistPath, "index.html") : join24(uiDistPath, url.pathname);
53779
53779
  if (existsSync19(filePath)) {
53780
53780
  return new Response(Bun.file(filePath));
53781
53781
  }
53782
- return new Response(Bun.file(join26(uiDistPath, "index.html")));
53782
+ return new Response(Bun.file(join24(uiDistPath, "index.html")));
53783
53783
  }
53784
53784
  return new Response(`<html><body><h1>CodeSavant Marketplace</h1><p>Web UI not found. Run: bun run build:marketplace</p></body></html>`, { headers: { "Content-Type": "text/html" } });
53785
53785
  },
@@ -53831,8 +53831,8 @@ var init_marketplace_server = __esm(() => {
53831
53831
  // src/cli.ts
53832
53832
  import { existsSync as existsSync20 } from "fs";
53833
53833
  import { readFile as readFile29 } from "fs/promises";
53834
- import { homedir as homedir16 } from "os";
53835
- import { join as join27 } from "path";
53834
+ import { homedir as homedir15 } from "os";
53835
+ import { join as join25 } from "path";
53836
53836
  import { parseArgs } from "util";
53837
53837
 
53838
53838
  // node_modules/ink/build/render.js
@@ -62429,13 +62429,37 @@ var PermissionConfigSchema = exports_external.object({
62429
62429
  var MAX_RAW_OUTPUT_LINES = 200;
62430
62430
  var MAX_STACK_LINES = 5;
62431
62431
  var ERROR_PATTERNS = [
62432
+ {
62433
+ type: "build_error",
62434
+ pattern: /ERROR in|Failed to compile|Build failed|esbuild.*error/i
62435
+ },
62436
+ {
62437
+ type: "port_conflict",
62438
+ pattern: /EADDRINUSE|address already in use|port.*already in use/i
62439
+ },
62440
+ {
62441
+ type: "network_error",
62442
+ pattern: /ECONNREFUSED|ETIMEDOUT|fetch failed|getaddrinfo.*ENOTFOUND/i
62443
+ },
62444
+ {
62445
+ type: "permission_error",
62446
+ pattern: /EACCES|Permission denied|sudo.*required/i
62447
+ },
62448
+ {
62449
+ type: "type_error",
62450
+ pattern: /error TS\d+|Type '.*' is not assignable|mypy.*error/i
62451
+ },
62452
+ {
62453
+ type: "dependency_error",
62454
+ pattern: /Module not found|No such file or directory.*node_modules|ImportError|ModuleNotFoundError/i
62455
+ },
62432
62456
  {
62433
62457
  type: "test_failure",
62434
- pattern: /FAIL|\u2717|\u2718|test.*failed|expect.*received|Expected:.*Received:/i
62458
+ pattern: /FAIL|\u2717|\u2718|test.*failed|expect.*received|Expected:.*Received:|FAILED|pytest.*error|cargo test.*FAILED|--- FAIL:/i
62435
62459
  },
62436
62460
  {
62437
62461
  type: "compile_error",
62438
- pattern: /error TS\d+|Cannot find module|SyntaxError.*\.tsx?/i
62462
+ pattern: /Cannot find module|SyntaxError.*\.tsx?|rustc.*error|javac.*error|gcc.*error|g\+\+.*error|go.*build.*error/i
62439
62463
  },
62440
62464
  {
62441
62465
  type: "lint_error",
@@ -62447,7 +62471,7 @@ var ERROR_PATTERNS = [
62447
62471
  },
62448
62472
  {
62449
62473
  type: "runtime_error",
62450
- pattern: /TypeError|ReferenceError|RangeError|at\s+\S+\s+\(/i
62474
+ pattern: /TypeError|ReferenceError|RangeError|NullPointerException|panic:|SIGSEGV|Traceback.*most recent|at\s+\S+\s+\(/i
62451
62475
  }
62452
62476
  ];
62453
62477
  var FILE_LINE_PATTERN = /(?:\()?([a-zA-Z0-9_\-./]+\.[a-zA-Z]+):(\d+)(?::\d+)?(?:\))?/;
@@ -62528,12 +62552,12 @@ function truncateRawOutput(output) {
62528
62552
  }
62529
62553
  // src/recovery/output-truncator.ts
62530
62554
  var DEFAULTS = {
62531
- maxLines: 100,
62555
+ maxLines: 300,
62532
62556
  headFraction: 0.3,
62533
62557
  tailFraction: 0.3,
62534
62558
  errorFraction: 0.4
62535
62559
  };
62536
- var ERROR_LINE_PATTERN = /error|Error|FAIL|failed|panic|exception|at\s+\S+\s+\(/i;
62560
+ var ERROR_LINE_PATTERN = /error|Error|FAIL|failed|panic|exception|at\s+\S+\s+\(|^ERROR in|^error\[|^\u2717|^\u00D7|^\s*\u25CF|^Caused by:|^thread .* panicked|Traceback|EACCES|EADDRINUSE|ECONNREFUSED|Module not found/i;
62537
62561
  function truncateOutput(output, options2) {
62538
62562
  if (output.length === 0) {
62539
62563
  return output;
@@ -62575,7 +62599,6 @@ var DESTRUCTIVE_VERBS = new Set([
62575
62599
  "rm",
62576
62600
  "rmdir",
62577
62601
  "del",
62578
- "mv",
62579
62602
  "chmod",
62580
62603
  "chown",
62581
62604
  "kill",
@@ -62588,7 +62611,14 @@ var DESTRUCTIVE_TWO_WORD = new Set([
62588
62611
  "git checkout --",
62589
62612
  "drop table",
62590
62613
  "truncate table",
62591
- "delete from"
62614
+ "delete from",
62615
+ "npm uninstall",
62616
+ "yarn remove",
62617
+ "bun remove",
62618
+ "pip uninstall",
62619
+ "docker rm",
62620
+ "docker rmi",
62621
+ "docker system"
62592
62622
  ]);
62593
62623
  var SAFE_CONTENT_COMMANDS = new Set([
62594
62624
  "echo",
@@ -63969,7 +63999,7 @@ class MemoryResolver {
63969
63999
  }
63970
64000
  }
63971
64001
  // src/agent.ts
63972
- import { join as join13 } from "path";
64002
+ import { join as join11 } from "path";
63973
64003
 
63974
64004
  // src/tools/ask-user.ts
63975
64005
  function validateQuestion(q, index) {
@@ -64209,85 +64239,9 @@ function getBackgroundTaskRegistry() {
64209
64239
  }
64210
64240
  return registryInstance;
64211
64241
  }
64212
- // src/safety/path-sandbox.ts
64213
- import { join as join11, resolve as resolve2, sep } from "path";
64214
- import { realpathSync } from "fs";
64215
- import { homedir as homedir5 } from "os";
64216
- function safeRealpath(inputPath) {
64217
- const absolute = resolve2(inputPath);
64218
- try {
64219
- return realpathSync(absolute);
64220
- } catch {
64221
- const parts = absolute.split(sep).filter(Boolean);
64222
- let existing = sep;
64223
- let remainingIndex = 0;
64224
- for (let i = 0;i < parts.length; i++) {
64225
- const candidate = join11(existing, parts[i]);
64226
- try {
64227
- existing = realpathSync(candidate);
64228
- remainingIndex = i + 1;
64229
- } catch {
64230
- remainingIndex = i;
64231
- break;
64232
- }
64233
- }
64234
- const remaining = parts.slice(remainingIndex).join(sep);
64235
- return remaining ? join11(existing, remaining) : existing;
64236
- }
64237
- }
64238
- function getAllowedPrefixes(cwd2) {
64239
- return [
64240
- safeRealpath(cwd2),
64241
- safeRealpath(resolve2(homedir5(), ".codesavant")),
64242
- safeRealpath(resolve2(homedir5(), ".config"))
64243
- ];
64244
- }
64245
- function isPathAllowed(inputPath, cwd2) {
64246
- const resolved = safeRealpath(inputPath);
64247
- const allowed = getAllowedPrefixes(cwd2);
64248
- return allowed.some((prefix) => resolved === prefix || resolved.startsWith(prefix + sep));
64249
- }
64250
- function validateCommandPaths(command, cwd2) {
64251
- const patterns = [
64252
- /(?:^|\s)(\/[^\s;|&"'`]+)/g,
64253
- /"(\/[^"]+)"/g,
64254
- /'(\/[^']+)'/g
64255
- ];
64256
- for (const pattern of patterns) {
64257
- let match;
64258
- while ((match = pattern.exec(command)) !== null) {
64259
- const extractedPath = match[1];
64260
- if (!isPathAllowed(extractedPath, cwd2)) {
64261
- const resolvedPath = safeRealpath(extractedPath);
64262
- return {
64263
- command,
64264
- violatingPath: resolvedPath,
64265
- reason: `Path "${resolvedPath}" is outside the project directory and known config directories`
64266
- };
64267
- }
64268
- }
64269
- }
64270
- return null;
64271
- }
64272
-
64273
- // src/safety/sandbox-logger.ts
64274
- import { appendFile as appendFile3, mkdir as mkdir9 } from "fs/promises";
64275
- import { join as join12 } from "path";
64276
- async function logSandboxViolation(violation, projectDir) {
64277
- const logDir = join12(projectDir, ".codesavant");
64278
- const logPath = join12(logDir, "sandbox.log");
64279
- await mkdir9(logDir, { recursive: true });
64280
- const entry = `[${new Date().toISOString()}] BLOCKED: ${violation.command}
64281
- Path: ${violation.violatingPath}
64282
- Reason: ${violation.reason}
64283
-
64284
- `;
64285
- await appendFile3(logPath, entry, "utf-8");
64286
- }
64287
-
64288
64242
  // src/tools/bash.ts
64289
64243
  var DEFAULT_TIMEOUT = 120000;
64290
- var MAX_OUTPUT_LENGTH = 50000;
64244
+ var MAX_OUTPUT_LENGTH = 200000;
64291
64245
  function parseGitCommand(command) {
64292
64246
  const trimmed = command.trim();
64293
64247
  const commitMatch = trimmed.match(/git\s+commit\s+.*-m\s+["']([^"']+)["']/);
@@ -64346,20 +64300,6 @@ async function executeBash(params, context) {
64346
64300
  };
64347
64301
  }
64348
64302
  }
64349
- const violation = validateCommandPaths(params.command, context.cwd);
64350
- if (violation) {
64351
- await logSandboxViolation(violation, context.cwd);
64352
- return {
64353
- success: false,
64354
- error: `Command blocked: ${violation.reason}
64355
-
64356
- Attempted command: ${violation.command}
64357
- Violating path: ${violation.violatingPath}
64358
-
64359
- To fix: Use paths within your project directory (${context.cwd})`,
64360
- durationMs: Date.now() - startTime
64361
- };
64362
- }
64363
64303
  if (isDestructiveCommand(params.command)) {
64364
64304
  return {
64365
64305
  success: false,
@@ -64370,10 +64310,15 @@ This command may cause data loss. Please confirm execution.`,
64370
64310
  durationMs: Date.now() - startTime
64371
64311
  };
64372
64312
  }
64373
- return new Promise((resolve3) => {
64313
+ const effectiveCwd = context.currentWorkingDir ?? context.cwd;
64314
+ const actualCommand = params.run_in_background ? params.command : `${params.command}
64315
+ __CODESAVANT_EXIT=$?
64316
+ echo "__CODESAVANT_CWD=$(pwd)"
64317
+ exit $__CODESAVANT_EXIT`;
64318
+ return new Promise((resolve2) => {
64374
64319
  try {
64375
- const proc = Bun.spawn(["bash", "-c", params.command], {
64376
- cwd: context.cwd,
64320
+ const proc = Bun.spawn(["bash", "-c", actualCommand], {
64321
+ cwd: effectiveCwd,
64377
64322
  env: { ...process.env },
64378
64323
  stdout: "pipe",
64379
64324
  stderr: "pipe"
@@ -64383,7 +64328,22 @@ This command may cause data loss. Please confirm execution.`,
64383
64328
  let timedOut = false;
64384
64329
  const timeoutId = setTimeout(() => {
64385
64330
  timedOut = true;
64386
- proc.kill();
64331
+ try {
64332
+ proc.kill();
64333
+ } catch {}
64334
+ let output = stdout;
64335
+ if (stderr) {
64336
+ output += (output ? `
64337
+ ` : "") + stderr;
64338
+ }
64339
+ output = output.trimEnd();
64340
+ output = truncateOutput(output, { maxLines: 100 });
64341
+ resolve2({
64342
+ success: false,
64343
+ error: `Command timed out after ${timeout}ms`,
64344
+ output: output || undefined,
64345
+ durationMs: Date.now() - startTime
64346
+ });
64387
64347
  }, timeout);
64388
64348
  if (params.run_in_background) {
64389
64349
  clearTimeout(timeoutId);
@@ -64393,7 +64353,7 @@ This command may cause data loss. Please confirm execution.`,
64393
64353
  command: params.command,
64394
64354
  proc
64395
64355
  });
64396
- resolve3({
64356
+ resolve2({
64397
64357
  success: true,
64398
64358
  output: `Started background process (PID: ${proc.pid}, Task ID: ${taskId})`,
64399
64359
  durationMs: Date.now() - startTime,
@@ -64428,6 +64388,8 @@ This command may cause data loss. Please confirm execution.`,
64428
64388
  await Promise.all([readStdout(), readStderr()]);
64429
64389
  const exitCode = await proc.exited;
64430
64390
  clearTimeout(timeoutId);
64391
+ if (timedOut)
64392
+ return;
64431
64393
  if (context.hookExecutor) {
64432
64394
  await context.hookExecutor.executeHooks("post_bash", {
64433
64395
  command: params.command,
@@ -64444,39 +64406,75 @@ This command may cause data loss. Please confirm execution.`,
64444
64406
  stderr
64445
64407
  });
64446
64408
  }
64447
- let output = stdout;
64448
- if (stderr) {
64449
- output += (output ? `
64450
- ` : "") + stderr;
64451
- }
64452
- output = output.trimEnd();
64453
- output = truncateOutput(output, { maxLines: 100 });
64454
- if (output.length > MAX_OUTPUT_LENGTH) {
64455
- output = `${output.slice(0, MAX_OUTPUT_LENGTH)}
64409
+ const cwdMatch = stdout.match(/__CODESAVANT_CWD=(.+)/);
64410
+ if (cwdMatch && exitCode === 0) {
64411
+ const newCwd = cwdMatch[1].trim();
64412
+ if (newCwd !== effectiveCwd) {
64413
+ context.previousWorkingDir = effectiveCwd;
64414
+ }
64415
+ context.currentWorkingDir = newCwd;
64416
+ }
64417
+ stdout = stdout.replace(/__CODESAVANT_CWD=.+\n?/, "");
64418
+ const parts = [];
64419
+ const trimmedStdout = stdout.trimEnd();
64420
+ const trimmedStderr = stderr.trimEnd();
64421
+ if (exitCode === 0) {
64422
+ let output = trimmedStdout;
64423
+ if (trimmedStderr) {
64424
+ output += (output ? `
64425
+ ` : "") + trimmedStderr;
64426
+ }
64427
+ output = output || "(no output)";
64428
+ output = truncateOutput(output, { maxLines: 300 });
64429
+ if (output.length > MAX_OUTPUT_LENGTH) {
64430
+ output = `${output.slice(0, MAX_OUTPUT_LENGTH)}
64456
64431
  ... (output truncated)`;
64457
- }
64458
- if (timedOut) {
64459
- resolve3({
64460
- success: false,
64461
- error: `Command timed out after ${timeout}ms`,
64462
- output: output || undefined,
64463
- durationMs: Date.now() - startTime
64432
+ }
64433
+ resolve2({
64434
+ success: true,
64435
+ output,
64436
+ durationMs: Date.now() - startTime,
64437
+ metadata: {
64438
+ exitCode,
64439
+ pid: proc.pid,
64440
+ stdout: trimmedStdout,
64441
+ stderr: trimmedStderr
64442
+ }
64464
64443
  });
64465
64444
  } else {
64466
- resolve3({
64467
- success: exitCode === 0,
64468
- output: output || (exitCode === 0 ? "(no output)" : undefined),
64469
- error: exitCode !== 0 ? `Exit code: ${exitCode}` : undefined,
64445
+ if (trimmedStdout) {
64446
+ parts.push(`[stdout]
64447
+ ${trimmedStdout}`);
64448
+ }
64449
+ if (trimmedStderr) {
64450
+ parts.push(`[stderr]
64451
+ ${trimmedStderr}`);
64452
+ }
64453
+ parts.push(`[exit code: ${exitCode}]`);
64454
+ let output = parts.join(`
64455
+
64456
+ `);
64457
+ output = truncateOutput(output, { maxLines: 300 });
64458
+ if (output.length > MAX_OUTPUT_LENGTH) {
64459
+ output = `${output.slice(0, MAX_OUTPUT_LENGTH)}
64460
+ ... (output truncated)`;
64461
+ }
64462
+ resolve2({
64463
+ success: false,
64464
+ output,
64465
+ error: `Exit code: ${exitCode}`,
64470
64466
  durationMs: Date.now() - startTime,
64471
64467
  metadata: {
64472
64468
  exitCode,
64473
- pid: proc.pid
64469
+ pid: proc.pid,
64470
+ stdout: trimmedStdout,
64471
+ stderr: trimmedStderr
64474
64472
  }
64475
64473
  });
64476
64474
  }
64477
64475
  })();
64478
64476
  } catch (error) {
64479
- resolve3({
64477
+ resolve2({
64480
64478
  success: false,
64481
64479
  error: error instanceof Error ? error.message : String(error),
64482
64480
  durationMs: Date.now() - startTime
@@ -64487,7 +64485,55 @@ This command may cause data loss. Please confirm execution.`,
64487
64485
  var bashTool = {
64488
64486
  definition: {
64489
64487
  name: "Bash",
64490
- description: "Execute shell commands",
64488
+ description: `Executes a bash command and returns its output.
64489
+
64490
+ The working directory persists between commands, but shell state (variables, aliases, functions) does not. Each command runs in a fresh bash shell from the persisted working directory.
64491
+
64492
+ IMPORTANT: Avoid using this tool to run cat, head, tail, grep, rg, find, sed, awk, or echo commands when a dedicated tool is available. Use the appropriate dedicated tool instead:
64493
+ - File search: Use Glob (NOT find or ls)
64494
+ - Content search: Use Grep (NOT grep or rg)
64495
+ - Read files: Use Read (NOT cat/head/tail)
64496
+ - Edit files: Use Edit (NOT sed/awk)
64497
+ - Write files: Use Write (NOT echo >/cat <<EOF)
64498
+
64499
+ # Command Best Practices
64500
+ - Always quote file paths that contain spaces with double quotes
64501
+ - Use && to chain dependent commands, not separate tool calls
64502
+ - Make independent tool calls in parallel when possible
64503
+ - Avoid unnecessary sleep commands \u2014 run commands directly or use run_in_background
64504
+ - You may specify a timeout in milliseconds (default 120000ms / 2 minutes)
64505
+ - Use run_in_background for long-running processes (servers, watchers)
64506
+
64507
+ # Git Safety
64508
+ - NEVER force push to main/master
64509
+ - Prefer new commits over amending existing commits
64510
+ - Stage specific files by name rather than using git add -A or git add .
64511
+ - NEVER skip hooks (--no-verify) unless explicitly asked
64512
+ - Pass commit messages via HEREDOC for proper formatting:
64513
+ git commit -m "$(cat <<'EOF'
64514
+ Commit message here.
64515
+ EOF
64516
+ )"
64517
+
64518
+ # Debugging Workflow
64519
+ When a command fails:
64520
+ 1. Read the error output \u2014 identify the file, line number, and error type
64521
+ 2. Use the Read tool to examine the relevant source file
64522
+ 3. Fix the root cause, not symptoms
64523
+ 4. Re-run the original command to verify the fix
64524
+ 5. If the fix creates new errors, address them before moving on
64525
+
64526
+ Do NOT:
64527
+ - Retry the same failing command expecting different results
64528
+ - Add try/catch or error suppression to hide errors
64529
+ - Skip failing tests \u2014 fix them
64530
+
64531
+ # Project Awareness
64532
+ - Node.js/React/Next.js: Check package.json scripts, use npm/yarn/bun as appropriate
64533
+ - Python: Check for venv, requirements.txt, pyproject.toml
64534
+ - Rust: Use cargo commands, check Cargo.toml
64535
+ - Go: Use go build/test, check go.mod
64536
+ - When build errors are unclear, read framework config files (tsconfig.json, vite.config.ts, etc.)`,
64491
64537
  parameters: [
64492
64538
  {
64493
64539
  name: "command",
@@ -64527,9 +64573,9 @@ defaultRegistry.register(bashTool);
64527
64573
  // src/tools/edit.ts
64528
64574
  init_atomic_write();
64529
64575
  import { readFile as readFile12 } from "fs/promises";
64530
- import { isAbsolute, normalize, resolve as resolve3 } from "path";
64576
+ import { isAbsolute, normalize, resolve as resolve2 } from "path";
64531
64577
  function validatePath(filePath, cwd2) {
64532
- const absolutePath = isAbsolute(filePath) ? normalize(filePath) : resolve3(cwd2, filePath);
64578
+ const absolutePath = isAbsolute(filePath) ? normalize(filePath) : resolve2(cwd2, filePath);
64533
64579
  if (absolutePath.includes("\x00")) {
64534
64580
  throw new Error("Invalid path: null bytes not allowed");
64535
64581
  }
@@ -64648,12 +64694,12 @@ var editTool = {
64648
64694
  defaultRegistry.register(editTool);
64649
64695
 
64650
64696
  // src/tools/glob.ts
64651
- import { isAbsolute as isAbsolute2, resolve as resolve4 } from "path";
64697
+ import { isAbsolute as isAbsolute2, resolve as resolve3 } from "path";
64652
64698
  var {Glob: Glob3 } = globalThis.Bun;
64653
64699
  async function executeGlob(params, context) {
64654
64700
  const startTime = Date.now();
64655
64701
  try {
64656
- const searchDir = params.path ? isAbsolute2(params.path) ? params.path : resolve4(context.cwd, params.path) : context.cwd;
64702
+ const searchDir = params.path ? isAbsolute2(params.path) ? params.path : resolve3(context.cwd, params.path) : context.cwd;
64657
64703
  if (searchDir.includes("\x00")) {
64658
64704
  throw new Error("Invalid path: null bytes not allowed");
64659
64705
  }
@@ -64711,12 +64757,12 @@ defaultRegistry.register(globTool);
64711
64757
 
64712
64758
  // src/tools/grep.ts
64713
64759
  import { readFile as readFile13 } from "fs/promises";
64714
- import { isAbsolute as isAbsolute3, resolve as resolve5 } from "path";
64760
+ import { isAbsolute as isAbsolute3, resolve as resolve4 } from "path";
64715
64761
  var {Glob: Glob4 } = globalThis.Bun;
64716
64762
  async function executeGrep(params, context) {
64717
64763
  const startTime = Date.now();
64718
64764
  try {
64719
- const searchPath = params.path ? isAbsolute3(params.path) ? params.path : resolve5(context.cwd, params.path) : context.cwd;
64765
+ const searchPath = params.path ? isAbsolute3(params.path) ? params.path : resolve4(context.cwd, params.path) : context.cwd;
64720
64766
  if (searchPath.includes("\x00")) {
64721
64767
  throw new Error("Invalid path: null bytes not allowed");
64722
64768
  }
@@ -64838,7 +64884,7 @@ var grepTool = {
64838
64884
  defaultRegistry.register(grepTool);
64839
64885
 
64840
64886
  // src/tools/lsp.ts
64841
- import { isAbsolute as isAbsolute4, resolve as resolve6 } from "path";
64887
+ import { isAbsolute as isAbsolute4, resolve as resolve5 } from "path";
64842
64888
 
64843
64889
  // src/lsp/manager.ts
64844
64890
  import { spawn } from "child_process";
@@ -64866,9 +64912,9 @@ class JsonRpcClient {
64866
64912
  const message = `Content-Length: ${Buffer.byteLength(body)}\r
64867
64913
  \r
64868
64914
  ${body}`;
64869
- return new Promise((resolve6, reject) => {
64915
+ return new Promise((resolve5, reject) => {
64870
64916
  this.pending.set(id, {
64871
- resolve: resolve6,
64917
+ resolve: resolve5,
64872
64918
  reject
64873
64919
  });
64874
64920
  this.config.write(message);
@@ -65197,7 +65243,7 @@ async function executeLsp(params, context) {
65197
65243
  }
65198
65244
  let resolvedPath;
65199
65245
  if (params.filePath) {
65200
- resolvedPath = isAbsolute4(params.filePath) ? params.filePath : resolve6(context.cwd, params.filePath);
65246
+ resolvedPath = isAbsolute4(params.filePath) ? params.filePath : resolve5(context.cwd, params.filePath);
65201
65247
  }
65202
65248
  if (mcpManager?.isServerConnected?.()) {
65203
65249
  try {
@@ -65393,9 +65439,9 @@ defaultRegistry.register(lspTool);
65393
65439
 
65394
65440
  // src/tools/notebook-edit.ts
65395
65441
  import { readFile as readFile14, writeFile as writeFile2 } from "fs/promises";
65396
- import { isAbsolute as isAbsolute5, normalize as normalize2, resolve as resolve7 } from "path";
65442
+ import { isAbsolute as isAbsolute5, normalize as normalize2, resolve as resolve6 } from "path";
65397
65443
  function validatePath2(filePath, cwd2) {
65398
- const absolutePath = isAbsolute5(filePath) ? normalize2(filePath) : resolve7(cwd2, filePath);
65444
+ const absolutePath = isAbsolute5(filePath) ? normalize2(filePath) : resolve6(cwd2, filePath);
65399
65445
  if (absolutePath.includes("\x00")) {
65400
65446
  throw new Error("Invalid path: null bytes not allowed");
65401
65447
  }
@@ -65638,7 +65684,7 @@ defaultRegistry.register(notebookEditTool);
65638
65684
 
65639
65685
  // src/tools/notebook-read.ts
65640
65686
  import { readFile as readFile15 } from "fs/promises";
65641
- import { isAbsolute as isAbsolute6, resolve as resolve8 } from "path";
65687
+ import { isAbsolute as isAbsolute6, resolve as resolve7 } from "path";
65642
65688
  async function executeNotebookRead(params, context) {
65643
65689
  const startTime = Date.now();
65644
65690
  if (!params.notebook_path) {
@@ -65648,7 +65694,7 @@ async function executeNotebookRead(params, context) {
65648
65694
  durationMs: Date.now() - startTime
65649
65695
  };
65650
65696
  }
65651
- const resolvedPath = isAbsolute6(params.notebook_path) ? params.notebook_path : resolve8(context.cwd, params.notebook_path);
65697
+ const resolvedPath = isAbsolute6(params.notebook_path) ? params.notebook_path : resolve7(context.cwd, params.notebook_path);
65652
65698
  try {
65653
65699
  const content = await readFile15(resolvedPath, "utf-8");
65654
65700
  const notebook = JSON.parse(content);
@@ -65878,9 +65924,9 @@ defaultRegistry.register(exitPlanModeTool);
65878
65924
 
65879
65925
  // src/tools/read.ts
65880
65926
  import { readFile as readFile16, stat as stat4 } from "fs/promises";
65881
- import { isAbsolute as isAbsolute7, normalize as normalize3, resolve as resolve9 } from "path";
65927
+ import { isAbsolute as isAbsolute7, normalize as normalize3, resolve as resolve8 } from "path";
65882
65928
  function validatePath3(filePath, cwd2) {
65883
- const absolutePath = isAbsolute7(filePath) ? normalize3(filePath) : resolve9(cwd2, filePath);
65929
+ const absolutePath = isAbsolute7(filePath) ? normalize3(filePath) : resolve8(cwd2, filePath);
65884
65930
  if (absolutePath.includes("\x00")) {
65885
65931
  throw new Error("Invalid path: null bytes not allowed");
65886
65932
  }
@@ -66784,7 +66830,7 @@ async function executeTaskOutput(params, _context) {
66784
66830
  }
66785
66831
  };
66786
66832
  }
66787
- await new Promise((resolve10) => setTimeout(resolve10, pollInterval));
66833
+ await new Promise((resolve9) => setTimeout(resolve9, pollInterval));
66788
66834
  elapsed += pollInterval;
66789
66835
  }
66790
66836
  return {
@@ -67350,10 +67396,10 @@ defaultRegistry.register(webSearchTool);
67350
67396
  // src/tools/write.ts
67351
67397
  init_atomic_write();
67352
67398
  import { existsSync as existsSync11 } from "fs";
67353
- import { mkdir as mkdir10 } from "fs/promises";
67354
- import { dirname as dirname10, isAbsolute as isAbsolute8, normalize as normalize4, resolve as resolve10 } from "path";
67399
+ import { mkdir as mkdir9 } from "fs/promises";
67400
+ import { dirname as dirname10, isAbsolute as isAbsolute8, normalize as normalize4, resolve as resolve9 } from "path";
67355
67401
  function validatePath4(filePath, cwd2) {
67356
- const absolutePath = isAbsolute8(filePath) ? normalize4(filePath) : resolve10(cwd2, filePath);
67402
+ const absolutePath = isAbsolute8(filePath) ? normalize4(filePath) : resolve9(cwd2, filePath);
67357
67403
  if (absolutePath.includes("\x00")) {
67358
67404
  throw new Error("Invalid path: null bytes not allowed");
67359
67405
  }
@@ -67378,7 +67424,7 @@ async function executeWrite(params, context) {
67378
67424
  }
67379
67425
  const dir = dirname10(filePath);
67380
67426
  if (!existsSync11(dir)) {
67381
- await mkdir10(dir, { recursive: true });
67427
+ await mkdir9(dir, { recursive: true });
67382
67428
  }
67383
67429
  await atomicWriteFile(filePath, params.content);
67384
67430
  if (context.hookExecutor) {
@@ -67869,19 +67915,19 @@ class SubagentSpawner {
67869
67915
  return true;
67870
67916
  }
67871
67917
  async waitForCompletion(agentId) {
67872
- return new Promise((resolve11, reject) => {
67918
+ return new Promise((resolve10, reject) => {
67873
67919
  const checkInterval = setInterval(() => {
67874
67920
  const result = this.getResult(agentId);
67875
67921
  if (result) {
67876
67922
  clearInterval(checkInterval);
67877
- resolve11(result);
67923
+ resolve10(result);
67878
67924
  }
67879
67925
  const status = this.getStatus(agentId);
67880
67926
  if (status?.status === "failed" || status?.status === "timeout") {
67881
67927
  clearInterval(checkInterval);
67882
67928
  const failedResult = this.getResult(agentId);
67883
67929
  if (failedResult) {
67884
- resolve11(failedResult);
67930
+ resolve10(failedResult);
67885
67931
  } else {
67886
67932
  reject(new Error(`Agent ${agentId} failed`));
67887
67933
  }
@@ -67996,14 +68042,14 @@ class SubagentSpawner {
67996
68042
  agentType: agent.config.type,
67997
68043
  agentId: agent.id
67998
68044
  });
67999
- return new Promise((resolve11) => {
68045
+ return new Promise((resolve10) => {
68000
68046
  setImmediate(() => {
68001
68047
  const output = `[${agent.config.type} agent]
68002
68048
  Prompt: ${agent.config.prompt.slice(0, 100)}${agent.config.prompt.length > 100 ? "..." : ""}
68003
68049
  Allowed tools: ${allowedTools.join(", ")}
68004
68050
 
68005
68051
  Execution completed.`;
68006
- resolve11({
68052
+ resolve10({
68007
68053
  success: true,
68008
68054
  output,
68009
68055
  durationMs: Date.now() - agent.startTime,
@@ -68391,7 +68437,7 @@ class Agent {
68391
68437
  this.unifiedSkillLoader = createUnifiedSkillLoader(this.context.cwd, this.trustStoreInstance);
68392
68438
  await this.unifiedSkillLoader.loadManifests();
68393
68439
  this.skillCreatorInstance = createSkillCreator(this.context.cwd, this.unifiedSkillLoader, this.trustStoreInstance);
68394
- const proposalStorePath = join13(this.context.cwd, ".codesavant", "pending-proposals.json");
68440
+ const proposalStorePath = join11(this.context.cwd, ".codesavant", "pending-proposals.json");
68395
68441
  const proposalStore = new ProposalStore(proposalStorePath);
68396
68442
  this.approvalGateInstance = createApprovalGate(this.skillCreatorInstance, this.trustStoreInstance, proposalStore);
68397
68443
  this.kitLoaderInstance = createKitLoader({
@@ -68971,8 +69017,8 @@ Blocking tool "${call.name}" executed. ${remainingCalls} subsequent tool call${r
68971
69017
  }
68972
69018
  async runBrainWriter() {
68973
69019
  try {
68974
- const globalDir = join13(this.context.homeDir, ".codesavant", "brain");
68975
- const projectDir = join13(this.context.cwd, ".codesavant", "memory");
69020
+ const globalDir = join11(this.context.homeDir, ".codesavant", "brain");
69021
+ const projectDir = join11(this.context.cwd, ".codesavant", "memory");
68976
69022
  const config = {
68977
69023
  globalDir,
68978
69024
  projectDir,
@@ -69105,9 +69151,9 @@ function createAgent(config, context) {
69105
69151
 
69106
69152
  // src/memory.ts
69107
69153
  import { existsSync as existsSync12 } from "fs";
69108
- import { mkdir as mkdir11, readFile as readFile18, writeFile as writeFile3 } from "fs/promises";
69109
- import { homedir as homedir6 } from "os";
69110
- import { dirname as dirname11, isAbsolute as isAbsolute9, join as join14, resolve as resolve11 } from "path";
69154
+ import { mkdir as mkdir10, readFile as readFile18, writeFile as writeFile3 } from "fs/promises";
69155
+ import { homedir as homedir5 } from "os";
69156
+ import { dirname as dirname11, isAbsolute as isAbsolute9, join as join12, resolve as resolve10 } from "path";
69111
69157
  var {Glob: Glob5 } = globalThis.Bun;
69112
69158
  var MANAGED_MEMORY_FILENAME = "MANAGED.md";
69113
69159
  var USER_MEMORY_FILENAME = "SAVANT.md";
@@ -69119,8 +69165,8 @@ class MemoryLoader {
69119
69165
  cwd;
69120
69166
  constructor(cwd2, config = {}) {
69121
69167
  this.cwd = cwd2;
69122
- this.userDir = config.userDir ?? join14(homedir6(), ".codesavant");
69123
- this.projectDir = config.projectDir ?? join14(cwd2, ".codesavant");
69168
+ this.userDir = config.userDir ?? join12(homedir5(), ".codesavant");
69169
+ this.projectDir = config.projectDir ?? join12(cwd2, ".codesavant");
69124
69170
  }
69125
69171
  getUserDir() {
69126
69172
  return this.userDir;
@@ -69131,9 +69177,9 @@ class MemoryLoader {
69131
69177
  async loadAll() {
69132
69178
  const entries = [];
69133
69179
  const levels = [
69134
- { level: "managed", path: join14(this.userDir, MANAGED_MEMORY_FILENAME) },
69135
- { level: "user", path: join14(this.userDir, USER_MEMORY_FILENAME) },
69136
- { level: "project", path: join14(this.projectDir, USER_MEMORY_FILENAME) }
69180
+ { level: "managed", path: join12(this.userDir, MANAGED_MEMORY_FILENAME) },
69181
+ { level: "user", path: join12(this.userDir, USER_MEMORY_FILENAME) },
69182
+ { level: "project", path: join12(this.projectDir, USER_MEMORY_FILENAME) }
69137
69183
  ];
69138
69184
  for (const { level, path } of levels) {
69139
69185
  if (existsSync12(path)) {
@@ -69148,7 +69194,7 @@ class MemoryLoader {
69148
69194
  return entries;
69149
69195
  }
69150
69196
  async loadWithImports(filePath, visited) {
69151
- const absolutePath = isAbsolute9(filePath) ? filePath : resolve11(this.cwd, filePath);
69197
+ const absolutePath = isAbsolute9(filePath) ? filePath : resolve10(this.cwd, filePath);
69152
69198
  if (visited.has(absolutePath)) {
69153
69199
  throw new Error(`Circular import detected: ${absolutePath}`);
69154
69200
  }
@@ -69175,7 +69221,7 @@ class MemoryLoader {
69175
69221
  } catch {}
69176
69222
  }
69177
69223
  } else {
69178
- const resolvedPath = isAbsolute9(importPath) ? importPath : resolve11(dir, importPath);
69224
+ const resolvedPath = isAbsolute9(importPath) ? importPath : resolve10(dir, importPath);
69179
69225
  if (existsSync12(resolvedPath)) {
69180
69226
  try {
69181
69227
  importedContent = await this.loadWithImports(resolvedPath, new Set(visited));
@@ -69200,7 +69246,7 @@ class MemoryLoader {
69200
69246
  const path = this.getPathForLevel(level);
69201
69247
  const dir = dirname11(path);
69202
69248
  if (!existsSync12(dir)) {
69203
- await mkdir11(dir, { recursive: true });
69249
+ await mkdir10(dir, { recursive: true });
69204
69250
  }
69205
69251
  await writeFile3(path, content, "utf-8");
69206
69252
  }
@@ -69221,9 +69267,9 @@ ${content}` : content;
69221
69267
  getPathForLevel(level) {
69222
69268
  switch (level) {
69223
69269
  case "user":
69224
- return join14(this.userDir, USER_MEMORY_FILENAME);
69270
+ return join12(this.userDir, USER_MEMORY_FILENAME);
69225
69271
  case "project":
69226
- return join14(this.projectDir, USER_MEMORY_FILENAME);
69272
+ return join12(this.projectDir, USER_MEMORY_FILENAME);
69227
69273
  case "managed":
69228
69274
  throw new Error("Cannot modify managed memory");
69229
69275
  }
@@ -69234,8 +69280,8 @@ function createMemoryLoader(cwd2, config) {
69234
69280
  }
69235
69281
 
69236
69282
  // src/context.ts
69237
- import { homedir as homedir7 } from "os";
69238
- import { join as join15 } from "path";
69283
+ import { homedir as homedir6 } from "os";
69284
+ import { join as join13 } from "path";
69239
69285
  var DEFAULT_SYSTEM_PROMPT = `You are CodeSavant, an AI-powered software engineering assistant.
69240
69286
 
69241
69287
  ## Communication Guidelines
@@ -69253,6 +69299,27 @@ You help developers with:
69253
69299
  - Executing commands and managing files
69254
69300
  - Solving technical problems
69255
69301
 
69302
+ ## Debugging & Error Recovery
69303
+
69304
+ When a command fails:
69305
+ 1. Read the error output carefully \u2014 identify the file, line, and error type
69306
+ 2. Read the relevant source file to understand context
69307
+ 3. Fix the root cause (not symptoms)
69308
+ 4. Re-run the original command to verify the fix
69309
+ 5. If the fix creates new errors, address them before moving on
69310
+
69311
+ Do NOT:
69312
+ - Retry the same command hoping for different results
69313
+ - Add try/catch or error suppression to hide errors
69314
+ - Skip failing tests \u2014 fix them
69315
+ - Assume an error is transient without evidence
69316
+
69317
+ When debugging build/test failures:
69318
+ - Check if dependencies are installed (node_modules, venv, etc.)
69319
+ - Check if the correct runtime version is available
69320
+ - Read framework config files when build errors are unclear
69321
+ - Run the build/test command the project actually uses (check package.json scripts, Makefile, etc.)
69322
+
69256
69323
  ## Environment`;
69257
69324
  async function buildContext(config) {
69258
69325
  const parts = [];
@@ -69263,13 +69330,13 @@ async function buildContext(config) {
69263
69330
  let memoryEntries = [];
69264
69331
  if (config.memory !== false) {
69265
69332
  const loader = createMemoryLoader(config.cwd, { userDir: config.userDir });
69266
- const userHome = config.userDir || homedir7();
69267
- const brainDir = config.brainDir || join15(userHome, ".codesavant", "brain");
69333
+ const userHome = config.userDir || homedir6();
69334
+ const brainDir = config.brainDir || join13(userHome, ".codesavant", "brain");
69268
69335
  let brainStore;
69269
69336
  try {
69270
69337
  brainStore = new BrainStore({
69271
69338
  globalDir: brainDir,
69272
- projectDir: join15(config.cwd, ".codesavant", "memory")
69339
+ projectDir: join13(config.cwd, ".codesavant", "memory")
69273
69340
  });
69274
69341
  } catch {}
69275
69342
  const resolver = new MemoryResolver({
@@ -69705,7 +69772,7 @@ class HttpTransport {
69705
69772
  }
69706
69773
  if (attempt < retryCount) {
69707
69774
  const delay = calculateBackoffDelay(attempt, baseDelay, DEFAULT_MAX_DELAY, true);
69708
- await new Promise((resolve12) => setTimeout(resolve12, delay));
69775
+ await new Promise((resolve11) => setTimeout(resolve11, delay));
69709
69776
  }
69710
69777
  }
69711
69778
  }
@@ -69794,7 +69861,7 @@ class SseTransport {
69794
69861
  break;
69795
69862
  }
69796
69863
  if (attempt < retryCount) {
69797
- await new Promise((resolve12) => setTimeout(resolve12, retryDelay));
69864
+ await new Promise((resolve11) => setTimeout(resolve11, retryDelay));
69798
69865
  }
69799
69866
  }
69800
69867
  }
@@ -69836,7 +69903,7 @@ class StdioTransport {
69836
69903
  if (this.connected) {
69837
69904
  return;
69838
69905
  }
69839
- return new Promise((resolve12, reject) => {
69906
+ return new Promise((resolve11, reject) => {
69840
69907
  try {
69841
69908
  this.process = spawn2(this.config.command, this.config.args ?? [], {
69842
69909
  cwd: this.config.cwd,
@@ -69869,7 +69936,7 @@ class StdioTransport {
69869
69936
  this.process?.stdout?.off("data", onFirstData);
69870
69937
  clearTimeout(readyTimeout);
69871
69938
  this.connected = true;
69872
- resolve12();
69939
+ resolve11();
69873
69940
  };
69874
69941
  this.process.stdout.once("data", onFirstData);
69875
69942
  const readyTimeout = setTimeout(() => {
@@ -69878,7 +69945,7 @@ class StdioTransport {
69878
69945
  return;
69879
69946
  if (this.process && !this.process.killed) {
69880
69947
  this.connected = true;
69881
- resolve12();
69948
+ resolve11();
69882
69949
  } else {
69883
69950
  reject(new Error("Process failed to start within timeout"));
69884
69951
  this.cleanup();
@@ -69906,7 +69973,7 @@ class StdioTransport {
69906
69973
  method,
69907
69974
  params: params ?? {}
69908
69975
  });
69909
- return new Promise((resolve12, reject) => {
69976
+ return new Promise((resolve11, reject) => {
69910
69977
  const timeout = setTimeout(() => {
69911
69978
  this.pendingRequests.delete(id);
69912
69979
  reject(new Error(`Request timeout: ${method}`));
@@ -69914,7 +69981,7 @@ class StdioTransport {
69914
69981
  this.pendingRequests.set(id, {
69915
69982
  resolve: (value) => {
69916
69983
  clearTimeout(timeout);
69917
- resolve12(value);
69984
+ resolve11(value);
69918
69985
  },
69919
69986
  reject: (error) => {
69920
69987
  clearTimeout(timeout);
@@ -70386,8 +70453,8 @@ class HookExecutor {
70386
70453
  stdout: "pipe",
70387
70454
  stderr: "pipe"
70388
70455
  });
70389
- const timeoutPromise = new Promise((resolve12) => {
70390
- setTimeout(() => resolve12("timeout"), timeout);
70456
+ const timeoutPromise = new Promise((resolve11) => {
70457
+ setTimeout(() => resolve11("timeout"), timeout);
70391
70458
  });
70392
70459
  const exitPromise = proc.exited.then(() => "completed");
70393
70460
  const race = await Promise.race([exitPromise, timeoutPromise]);
@@ -70466,7 +70533,7 @@ function createHookExecutor(config) {
70466
70533
  return new HookExecutor(config);
70467
70534
  }
70468
70535
  // src/index.ts
70469
- var VERSION = "3.4.1";
70536
+ var VERSION = "4.0.2";
70470
70537
 
70471
70538
  // src/notifications/notifier.ts
70472
70539
  import { randomUUID as randomUUID4 } from "crypto";
@@ -70980,10 +71047,10 @@ var jsx_dev_runtime4 = __toESM(require_jsx_dev_runtime(), 1);
70980
71047
  // src/onboarding/detection.ts
70981
71048
  init_settings();
70982
71049
  import { existsSync as existsSync14 } from "fs";
70983
- import { join as join17 } from "path";
71050
+ import { join as join15 } from "path";
70984
71051
  async function checkOnboardingNeeded(homeDir, requestedProvider) {
70985
- const settingsDir = join17(homeDir, ".codesavant");
70986
- const settingsPath = join17(settingsDir, "settings.json");
71052
+ const settingsDir = join15(homeDir, ".codesavant");
71053
+ const settingsPath = join15(settingsDir, "settings.json");
70987
71054
  if (!existsSync14(settingsDir)) {
70988
71055
  return {
70989
71056
  needsOnboarding: true,
@@ -71053,7 +71120,7 @@ function OnboardingOrchestrator({
71053
71120
  setApiKey(submittedApiKey);
71054
71121
  setStep("validation");
71055
71122
  setValidationStatus("validating");
71056
- await new Promise((resolve12) => setTimeout(resolve12, 500));
71123
+ await new Promise((resolve11) => setTimeout(resolve11, 500));
71057
71124
  if (submittedApiKey.length > 0) {
71058
71125
  setValidationStatus("success");
71059
71126
  } else {
@@ -71448,8 +71515,8 @@ async function* parseBedrockStream(response) {
71448
71515
  // src/providers/bedrock-auth.ts
71449
71516
  import { createHash as createHash4, createHmac } from "crypto";
71450
71517
  import { readFile as readFile20 } from "fs/promises";
71451
- import { homedir as homedir9 } from "os";
71452
- import { join as join18 } from "path";
71518
+ import { homedir as homedir8 } from "os";
71519
+ import { join as join16 } from "path";
71453
71520
  var defaultFileReader = async (path) => {
71454
71521
  try {
71455
71522
  return await readFile20(path, "utf-8");
@@ -71529,10 +71596,10 @@ function parseConfigFile(content) {
71529
71596
  return result;
71530
71597
  }
71531
71598
  function getCredentialsFilePath() {
71532
- return process.env.AWS_SHARED_CREDENTIALS_FILE || join18(homedir9(), ".aws", "credentials");
71599
+ return process.env.AWS_SHARED_CREDENTIALS_FILE || join16(homedir8(), ".aws", "credentials");
71533
71600
  }
71534
71601
  function getConfigFilePath() {
71535
- return process.env.AWS_CONFIG_FILE || join18(homedir9(), ".aws", "config");
71602
+ return process.env.AWS_CONFIG_FILE || join16(homedir8(), ".aws", "config");
71536
71603
  }
71537
71604
  function getProfileName(profile) {
71538
71605
  return profile || process.env.AWS_PROFILE || "default";
@@ -72098,7 +72165,7 @@ async function* parseOpenAIStreamWithTimeout(response, provider, chunkTimeout) {
72098
72165
  throw new Error(`Stream timeout: no data received for ${Math.round(timeSinceLastChunk / 1000)}s`);
72099
72166
  }
72100
72167
  const readPromise = reader.read();
72101
- const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12({ done: true, value: undefined }), Math.min(5000, chunkTimeout - timeSinceLastChunk)));
72168
+ const timeoutPromise = new Promise((resolve11) => setTimeout(() => resolve11({ done: true, value: undefined }), Math.min(5000, chunkTimeout - timeSinceLastChunk)));
72102
72169
  const { done, value } = await Promise.race([readPromise, timeoutPromise]);
72103
72170
  if (value) {
72104
72171
  lastChunkTime = Date.now();
@@ -72267,8 +72334,8 @@ var createDeepSeekProvider = createOpenAICompatProvider({
72267
72334
  });
72268
72335
  // src/providers/gemini-auth.ts
72269
72336
  import { readFile as readFile21 } from "fs/promises";
72270
- import { homedir as homedir10 } from "os";
72271
- import { join as join19 } from "path";
72337
+ import { homedir as homedir9 } from "os";
72338
+ import { join as join17 } from "path";
72272
72339
  var GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
72273
72340
  var GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
72274
72341
  var DEFAULT_SCOPE = "https://www.googleapis.com/auth/cloud-platform";
@@ -72400,7 +72467,7 @@ async function loadApplicationDefaultCredentials(_options) {
72400
72467
  return result;
72401
72468
  }
72402
72469
  }
72403
- const defaultPath = join19(homedir10(), ".config", "gcloud", "application_default_credentials.json");
72470
+ const defaultPath = join17(homedir9(), ".config", "gcloud", "application_default_credentials.json");
72404
72471
  return loadCredentialsFromPath(defaultPath);
72405
72472
  }
72406
72473
  async function loadCredentialsFromPath(path) {
@@ -73068,8 +73135,8 @@ function createRouter(config) {
73068
73135
  // src/repl-ink.tsx
73069
73136
  import { existsSync as existsSync17 } from "fs";
73070
73137
  import { readFile as readFile27 } from "fs/promises";
73071
- import { homedir as homedir13 } from "os";
73072
- import { join as join24 } from "path";
73138
+ import { homedir as homedir12 } from "os";
73139
+ import { join as join22 } from "path";
73073
73140
  var import_react34 = __toESM(require_react(), 1);
73074
73141
 
73075
73142
  // src/background-tasks.ts
@@ -73484,7 +73551,7 @@ class CommandRegistry {
73484
73551
  }
73485
73552
  }
73486
73553
  // src/commands/history.ts
73487
- import { readFile as readFile22, writeFile as writeFile6, mkdir as mkdir13 } from "fs/promises";
73554
+ import { readFile as readFile22, writeFile as writeFile6, mkdir as mkdir12 } from "fs/promises";
73488
73555
  import { dirname as dirname12 } from "path";
73489
73556
 
73490
73557
  class CommandHistory {
@@ -73507,7 +73574,7 @@ class CommandHistory {
73507
73574
  this.data = data;
73508
73575
  }
73509
73576
  try {
73510
- await mkdir13(dirname12(this.historyPath), { recursive: true });
73577
+ await mkdir12(dirname12(this.historyPath), { recursive: true });
73511
73578
  await writeFile6(this.historyPath, JSON.stringify(this.data, null, 2));
73512
73579
  } catch {}
73513
73580
  }
@@ -76200,22 +76267,22 @@ function generateSlug(prompt) {
76200
76267
  }
76201
76268
  // src/craft-orchestrator/persistence.ts
76202
76269
  init_atomic_write();
76203
- import { mkdir as mkdir14, readFile as readFile23, readdir as readdir5, unlink as unlink5, stat as stat5 } from "fs/promises";
76204
- import { join as join20 } from "path";
76270
+ import { mkdir as mkdir13, readFile as readFile23, readdir as readdir5, unlink as unlink5, stat as stat5 } from "fs/promises";
76271
+ import { join as join18 } from "path";
76205
76272
  class CraftPersistence {
76206
76273
  baseDir;
76207
76274
  constructor(baseDir) {
76208
- this.baseDir = baseDir ?? join20(process.cwd(), ".codesavant", "craft");
76275
+ this.baseDir = baseDir ?? join18(process.cwd(), ".codesavant", "craft");
76209
76276
  }
76210
76277
  async save(state) {
76211
- const slugDir = join20(this.baseDir, state.slug);
76212
- await mkdir14(slugDir, { recursive: true });
76213
- const filePath = join20(slugDir, "state.json");
76278
+ const slugDir = join18(this.baseDir, state.slug);
76279
+ await mkdir13(slugDir, { recursive: true });
76280
+ const filePath = join18(slugDir, "state.json");
76214
76281
  const content = JSON.stringify(state, null, 2);
76215
76282
  await atomicWriteFile(filePath, content);
76216
76283
  }
76217
76284
  async load(slug) {
76218
- const filePath = join20(this.baseDir, slug, "state.json");
76285
+ const filePath = join18(this.baseDir, slug, "state.json");
76219
76286
  try {
76220
76287
  const content = await readFile23(filePath, "utf-8");
76221
76288
  const data = JSON.parse(content);
@@ -76234,7 +76301,7 @@ class CraftPersistence {
76234
76301
  }
76235
76302
  }
76236
76303
  async clear(slug) {
76237
- const filePath = join20(this.baseDir, slug, "state.json");
76304
+ const filePath = join18(this.baseDir, slug, "state.json");
76238
76305
  try {
76239
76306
  await unlink5(filePath);
76240
76307
  } catch (error) {
@@ -76250,7 +76317,7 @@ class CraftPersistence {
76250
76317
  const sessions = [];
76251
76318
  for (const entry of entries) {
76252
76319
  if (entry.isDirectory()) {
76253
- const stateFile = join20(this.baseDir, entry.name, "state.json");
76320
+ const stateFile = join18(this.baseDir, entry.name, "state.json");
76254
76321
  try {
76255
76322
  await stat5(stateFile);
76256
76323
  sessions.push(entry.name);
@@ -76266,13 +76333,13 @@ class CraftPersistence {
76266
76333
  }
76267
76334
  }
76268
76335
  async saveResearchArtifact(slug, name, content) {
76269
- const slugDir = join20(this.baseDir, slug);
76270
- await mkdir14(slugDir, { recursive: true });
76271
- const filePath = join20(slugDir, name);
76336
+ const slugDir = join18(this.baseDir, slug);
76337
+ await mkdir13(slugDir, { recursive: true });
76338
+ const filePath = join18(slugDir, name);
76272
76339
  await atomicWriteFile(filePath, content);
76273
76340
  }
76274
76341
  async loadResearchArtifact(slug, name) {
76275
- const filePath = join20(this.baseDir, slug, name);
76342
+ const filePath = join18(this.baseDir, slug, name);
76276
76343
  try {
76277
76344
  return await readFile23(filePath, "utf-8");
76278
76345
  } catch (error) {
@@ -81708,8 +81775,8 @@ init_installer();
81708
81775
  init_dist_bundle14();
81709
81776
  var import_gray_matter6 = __toESM(require_gray_matter(), 1);
81710
81777
  import { createHash as createHash6 } from "crypto";
81711
- import { mkdir as mkdir17, writeFile as writeFile7, rm } from "fs/promises";
81712
- import { join as join22 } from "path";
81778
+ import { mkdir as mkdir16, writeFile as writeFile7, rm } from "fs/promises";
81779
+ import { join as join20 } from "path";
81713
81780
  import { tmpdir } from "os";
81714
81781
  function normalizeContent2(s) {
81715
81782
  return s.replace(/\r\n/g, `
@@ -81727,7 +81794,7 @@ class SkillPublisher {
81727
81794
  constructor(deps = {}) {
81728
81795
  this.octokit = deps.octokit;
81729
81796
  this.gitInstance = deps.git;
81730
- this.tempDir = deps.tempDir ?? join22(tmpdir(), `codesavant-publish-${Date.now()}`);
81797
+ this.tempDir = deps.tempDir ?? join20(tmpdir(), `codesavant-publish-${Date.now()}`);
81731
81798
  this.getGitConfigFn = deps.getGitConfig ?? this.defaultGetGitConfig.bind(this);
81732
81799
  }
81733
81800
  async buildPublishDraft(skillContent) {
@@ -81829,10 +81896,10 @@ class SkillPublisher {
81829
81896
  repo: repo.name,
81830
81897
  names: ["codesavant-skill", ...draft.tags]
81831
81898
  });
81832
- await mkdir17(this.tempDir, { recursive: true });
81833
- await writeFile7(join22(this.tempDir, "SKILL.md"), draft.skillContent, "utf-8");
81834
- await writeFile7(join22(this.tempDir, "manifest.json"), draft.manifestContent, "utf-8");
81835
- await writeFile7(join22(this.tempDir, "README.md"), draft.readmeContent, "utf-8");
81899
+ await mkdir16(this.tempDir, { recursive: true });
81900
+ await writeFile7(join20(this.tempDir, "SKILL.md"), draft.skillContent, "utf-8");
81901
+ await writeFile7(join20(this.tempDir, "manifest.json"), draft.manifestContent, "utf-8");
81902
+ await writeFile7(join20(this.tempDir, "README.md"), draft.readmeContent, "utf-8");
81836
81903
  const git = this.gitInstance ?? simpleGit(this.tempDir);
81837
81904
  await git.init();
81838
81905
  await git.addConfig("user.email", draft.authorEmail || "noreply@codesavant.dev");
@@ -82258,7 +82325,7 @@ async function handleCheckpointCommand(agent, args) {
82258
82325
  async function handleMemoryCommand(agent) {
82259
82326
  const session = agent.getSession();
82260
82327
  const cwd2 = session?.metadata.cwd ?? agent.getCwd();
82261
- const projectPath = join24(cwd2, ".codesavant", "SAVANT.md");
82328
+ const projectPath = join22(cwd2, ".codesavant", "SAVANT.md");
82262
82329
  if (existsSync17(projectPath)) {
82263
82330
  try {
82264
82331
  const content = await readFile27(projectPath, "utf-8");
@@ -82721,7 +82788,7 @@ function ReplInternal({
82721
82788
  const { theme: currentTheme, setTheme: setCurrentTheme } = useTheme();
82722
82789
  const backgroundTaskManager = import_react34.useMemo(() => createBackgroundTaskManager(), []);
82723
82790
  const commandRegistry = import_react34.useMemo(() => new CommandRegistry, []);
82724
- const commandHistory = import_react34.useMemo(() => new CommandHistory(join24(homedir13(), ".codesavant", "command-history.json")), []);
82791
+ const commandHistory = import_react34.useMemo(() => new CommandHistory(join22(homedir12(), ".codesavant", "command-history.json")), []);
82725
82792
  import_react34.useEffect(() => {
82726
82793
  async function initRegistry() {
82727
82794
  const builtinDescriptions = {
@@ -83356,7 +83423,7 @@ Enter number to review, or "skip" to exit:`
83356
83423
  localSkillChecker: agent.getUnifiedSkillLoader()
83357
83424
  }),
83358
83425
  versionManager: new VersionManager,
83359
- installStore: new InstallRecordStore(join24(homedir13(), ".codesavant", "marketplace-installs.json"))
83426
+ installStore: new InstallRecordStore(join22(homedir12(), ".codesavant", "marketplace-installs.json"))
83360
83427
  });
83361
83428
  setMessages((prev) => [
83362
83429
  ...prev,
@@ -83568,8 +83635,8 @@ Follow this skill's process for the user's request below.`
83568
83635
 
83569
83636
  `)
83570
83637
  }]);
83571
- return new Promise((resolve12) => {
83572
- setCraftQuestionResolve(() => resolve12);
83638
+ return new Promise((resolve11) => {
83639
+ setCraftQuestionResolve(() => resolve11);
83573
83640
  });
83574
83641
  },
83575
83642
  showRoadmap: (formatted) => {
@@ -83585,8 +83652,8 @@ Follow this skill's process for the user's request below.`
83585
83652
 
83586
83653
  Options: approve | feedback | abort`
83587
83654
  }]);
83588
- return new Promise((resolve12) => {
83589
- setCraftApproval({ request: request2, resolve: resolve12 });
83655
+ return new Promise((resolve11) => {
83656
+ setCraftApproval({ request: request2, resolve: resolve11 });
83590
83657
  });
83591
83658
  },
83592
83659
  getFeedback: async () => {
@@ -83594,8 +83661,8 @@ Options: approve | feedback | abort`
83594
83661
  role: "system",
83595
83662
  content: "Enter your feedback for the roadmap:"
83596
83663
  }]);
83597
- return new Promise((resolve12) => {
83598
- setCraftFeedbackResolve(() => resolve12);
83664
+ return new Promise((resolve11) => {
83665
+ setCraftFeedbackResolve(() => resolve11);
83599
83666
  });
83600
83667
  },
83601
83668
  showProgress: (message) => {
@@ -83613,8 +83680,8 @@ ${request2.content}
83613
83680
 
83614
83681
  Options: continue | pause | abort`
83615
83682
  }]);
83616
- return new Promise((resolve12) => {
83617
- setCraftCheckIn({ request: request2, resolve: resolve12 });
83683
+ return new Promise((resolve11) => {
83684
+ setCraftCheckIn({ request: request2, resolve: resolve11 });
83618
83685
  });
83619
83686
  }
83620
83687
  };
@@ -83957,11 +84024,11 @@ Run: /plugin publish ${skillFilePath}`
83957
84024
  }
83958
84025
  }, [pendingQuestion]);
83959
84026
  const questionHandler = import_react34.useCallback(async (question) => {
83960
- return new Promise((resolve12) => {
84027
+ return new Promise((resolve11) => {
83961
84028
  setPendingQuestion({
83962
84029
  question,
83963
84030
  resolve: (selectedIndices, labels) => {
83964
- resolve12({ selectedIndices, labels });
84031
+ resolve11({ selectedIndices, labels });
83965
84032
  }
83966
84033
  });
83967
84034
  });
@@ -84127,14 +84194,14 @@ function renderRepl(props) {
84127
84194
  import { randomUUID as randomUUID5 } from "crypto";
84128
84195
  import { existsSync as existsSync18 } from "fs";
84129
84196
  import {
84130
- appendFile as appendFile4,
84131
- mkdir as mkdir19,
84197
+ appendFile as appendFile3,
84198
+ mkdir as mkdir18,
84132
84199
  readdir as readdir6,
84133
84200
  readFile as readFile28,
84134
84201
  writeFile as writeFile8
84135
84202
  } from "fs/promises";
84136
- import { homedir as homedir14 } from "os";
84137
- import { join as join25 } from "path";
84203
+ import { homedir as homedir13 } from "os";
84204
+ import { join as join23 } from "path";
84138
84205
 
84139
84206
  // src/sessions/types.ts
84140
84207
  var SESSIONS_DIR = ".codesavant/sessions";
@@ -84160,7 +84227,7 @@ function generateSessionTitle(content) {
84160
84227
  class SessionStorage {
84161
84228
  baseDir;
84162
84229
  constructor(baseDir) {
84163
- this.baseDir = baseDir ?? join25(homedir14(), SESSIONS_DIR);
84230
+ this.baseDir = baseDir ?? join23(homedir13(), SESSIONS_DIR);
84164
84231
  }
84165
84232
  getBaseDir() {
84166
84233
  return this.baseDir;
@@ -84202,7 +84269,7 @@ class SessionStorage {
84202
84269
  const messagesPath = this.getMessagesPath(sessionId);
84203
84270
  const line = `${JSON.stringify(fullMessage)}
84204
84271
  `;
84205
- await appendFile4(messagesPath, line, "utf-8");
84272
+ await appendFile3(messagesPath, line, "utf-8");
84206
84273
  if (metadata) {
84207
84274
  metadata.updatedAt = Date.now();
84208
84275
  metadata.messageCount++;
@@ -84248,7 +84315,7 @@ class SessionStorage {
84248
84315
  const sessions = [];
84249
84316
  for (const file of metadataFiles) {
84250
84317
  try {
84251
- const content = await readFile28(join25(this.baseDir, file), "utf-8");
84318
+ const content = await readFile28(join23(this.baseDir, file), "utf-8");
84252
84319
  sessions.push(JSON.parse(content));
84253
84320
  } catch {}
84254
84321
  }
@@ -84277,14 +84344,14 @@ class SessionStorage {
84277
84344
  }
84278
84345
  async ensureDir() {
84279
84346
  if (!existsSync18(this.baseDir)) {
84280
- await mkdir19(this.baseDir, { recursive: true });
84347
+ await mkdir18(this.baseDir, { recursive: true });
84281
84348
  }
84282
84349
  }
84283
84350
  getMetadataPath(sessionId) {
84284
- return join25(this.baseDir, `${sessionId}.meta.json`);
84351
+ return join23(this.baseDir, `${sessionId}.meta.json`);
84285
84352
  }
84286
84353
  getMessagesPath(sessionId) {
84287
- return join25(this.baseDir, `${sessionId}.jsonl`);
84354
+ return join23(this.baseDir, `${sessionId}.jsonl`);
84288
84355
  }
84289
84356
  async getMetadata(sessionId) {
84290
84357
  const path2 = this.getMetadataPath(sessionId);
@@ -84507,7 +84574,7 @@ function validateOptions(options2) {
84507
84574
  }
84508
84575
  }
84509
84576
  async function loadHooksFromSettings(cwd2) {
84510
- const settingsPath = join27(cwd2, ".codesavant", "settings.json");
84577
+ const settingsPath = join25(cwd2, ".codesavant", "settings.json");
84511
84578
  if (!existsSync20(settingsPath)) {
84512
84579
  return {};
84513
84580
  }
@@ -84557,7 +84624,7 @@ async function main() {
84557
84624
  const mode = getExecutionMode(options2);
84558
84625
  if (mode === "interactive") {
84559
84626
  const requestedProvider = options2.provider;
84560
- const onboardingCheck = await checkOnboardingNeeded(homedir16(), requestedProvider);
84627
+ const onboardingCheck = await checkOnboardingNeeded(homedir15(), requestedProvider);
84561
84628
  if (onboardingCheck.needsOnboarding) {
84562
84629
  let configuredProviders = null;
84563
84630
  const { waitUntilExit: waitUntilExit2 } = render_default(import_react35.default.createElement(OnboardingOrchestrator, {
@@ -84701,7 +84768,7 @@ Warning: Provider "${onboardingCheck.missingProvider}" is not configured.`);
84701
84768
  console.error("[Compaction failed]", error instanceof Error ? error.message : String(error));
84702
84769
  }
84703
84770
  }
84704
- }, { cwd: options2.cwd, homeDir: homedir16(), sessionId });
84771
+ }, { cwd: options2.cwd, homeDir: homedir15(), sessionId });
84705
84772
  const context = await buildContext({
84706
84773
  cwd: options2.cwd,
84707
84774
  memory: true