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.
- package/README.md +88 -456
- package/dist/cli.js +364 -297
- 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
|
|
43063
|
-
import { homedir as
|
|
43064
|
-
import { join as
|
|
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(
|
|
43090
|
+
return loadSettings(join14(cwd2, PROJECT_SETTINGS_PATH));
|
|
43091
43091
|
}
|
|
43092
|
-
async function saveUserSettings(settings, homeDir =
|
|
43093
|
-
const settingsDir =
|
|
43094
|
-
const settingsPath =
|
|
43095
|
-
await
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
45697
|
-
import { join as
|
|
45698
|
-
import { mkdir as
|
|
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 ??
|
|
45725
|
-
this.installStore = deps.installStore ?? new InstallRecordStore(
|
|
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 =
|
|
45760
|
-
await
|
|
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_-]+)",
|
|
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}${
|
|
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(
|
|
49968
|
-
return setTimeout(
|
|
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,
|
|
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:
|
|
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
|
|
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,
|
|
50203
|
-
|
|
50202
|
+
var promise, reject, resolve11;
|
|
50203
|
+
resolve11 = reject = null;
|
|
50204
50204
|
promise = new this.Promise(function(_resolve, _reject) {
|
|
50205
|
-
|
|
50205
|
+
resolve11 = _resolve;
|
|
50206
50206
|
return reject = _reject;
|
|
50207
50207
|
});
|
|
50208
|
-
this._queue.push({ task: task2, args, resolve:
|
|
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((
|
|
50612
|
+
return new this.Promise((resolve11, reject) => {
|
|
50613
50613
|
if (finished()) {
|
|
50614
|
-
return
|
|
50614
|
+
return resolve11();
|
|
50615
50615
|
} else {
|
|
50616
50616
|
return this.on("done", () => {
|
|
50617
50617
|
if (finished()) {
|
|
50618
50618
|
this.removeAllListeners("done");
|
|
50619
|
-
return
|
|
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(
|
|
50712
|
+
return new this.Promise(function(resolve11, reject) {
|
|
50713
50713
|
return fn(...args2, function(...args3) {
|
|
50714
|
-
return (args3[0] != null ? reject :
|
|
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((
|
|
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((
|
|
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
|
|
53678
|
+
import { readFile as readFile26, mkdir as mkdir17 } from "fs/promises";
|
|
53679
53679
|
import { existsSync as existsSync16 } from "fs";
|
|
53680
|
-
import { homedir as
|
|
53681
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
53760
|
+
import { join as join24 } from "path";
|
|
53761
53761
|
import { existsSync as existsSync19 } from "fs";
|
|
53762
|
-
import { homedir as
|
|
53762
|
+
import { homedir as homedir14 } from "os";
|
|
53763
53763
|
function startMarketplaceServer() {
|
|
53764
|
-
const uiDistPath =
|
|
53765
|
-
const hasUI = existsSync19(
|
|
53766
|
-
const installStore = new InstallRecordStore(
|
|
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 === "" ?
|
|
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(
|
|
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
|
|
53835
|
-
import { join as
|
|
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: /
|
|
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:
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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",
|
|
64376
|
-
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
64448
|
-
if (
|
|
64449
|
-
|
|
64450
|
-
|
|
64451
|
-
|
|
64452
|
-
|
|
64453
|
-
|
|
64454
|
-
|
|
64455
|
-
|
|
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
|
-
|
|
64459
|
-
|
|
64460
|
-
|
|
64461
|
-
|
|
64462
|
-
|
|
64463
|
-
|
|
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
|
-
|
|
64467
|
-
|
|
64468
|
-
|
|
64469
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
64576
|
+
import { isAbsolute, normalize, resolve as resolve2 } from "path";
|
|
64531
64577
|
function validatePath(filePath, cwd2) {
|
|
64532
|
-
const absolutePath = isAbsolute(filePath) ? normalize(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
|
|
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 :
|
|
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
|
|
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 :
|
|
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
|
|
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((
|
|
64915
|
+
return new Promise((resolve5, reject) => {
|
|
64870
64916
|
this.pending.set(id, {
|
|
64871
|
-
resolve:
|
|
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 :
|
|
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
|
|
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) :
|
|
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
|
|
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 :
|
|
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
|
|
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) :
|
|
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((
|
|
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
|
|
67354
|
-
import { dirname as dirname10, isAbsolute as isAbsolute8, normalize as normalize4, resolve as
|
|
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) :
|
|
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
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
68975
|
-
const projectDir =
|
|
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
|
|
69109
|
-
import { homedir as
|
|
69110
|
-
import { dirname as dirname11, isAbsolute as isAbsolute9, join as
|
|
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 ??
|
|
69123
|
-
this.projectDir = config.projectDir ??
|
|
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:
|
|
69135
|
-
{ level: "user", path:
|
|
69136
|
-
{ level: "project", path:
|
|
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 :
|
|
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 :
|
|
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
|
|
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
|
|
69270
|
+
return join12(this.userDir, USER_MEMORY_FILENAME);
|
|
69225
69271
|
case "project":
|
|
69226
|
-
return
|
|
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
|
|
69238
|
-
import { join as
|
|
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 ||
|
|
69267
|
-
const brainDir = config.brainDir ||
|
|
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:
|
|
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((
|
|
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((
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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((
|
|
70390
|
-
setTimeout(() =>
|
|
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 = "
|
|
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
|
|
71050
|
+
import { join as join15 } from "path";
|
|
70984
71051
|
async function checkOnboardingNeeded(homeDir, requestedProvider) {
|
|
70985
|
-
const settingsDir =
|
|
70986
|
-
const settingsPath =
|
|
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((
|
|
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
|
|
71452
|
-
import { join as
|
|
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 ||
|
|
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 ||
|
|
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((
|
|
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
|
|
72271
|
-
import { join as
|
|
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 =
|
|
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
|
|
73072
|
-
import { join as
|
|
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
|
|
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
|
|
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
|
|
76204
|
-
import { join as
|
|
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 ??
|
|
76275
|
+
this.baseDir = baseDir ?? join18(process.cwd(), ".codesavant", "craft");
|
|
76209
76276
|
}
|
|
76210
76277
|
async save(state) {
|
|
76211
|
-
const slugDir =
|
|
76212
|
-
await
|
|
76213
|
-
const filePath =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
76270
|
-
await
|
|
76271
|
-
const filePath =
|
|
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 =
|
|
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
|
|
81712
|
-
import { join as
|
|
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 ??
|
|
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
|
|
81833
|
-
await writeFile7(
|
|
81834
|
-
await writeFile7(
|
|
81835
|
-
await writeFile7(
|
|
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 =
|
|
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(
|
|
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(
|
|
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((
|
|
83572
|
-
setCraftQuestionResolve(() =>
|
|
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((
|
|
83589
|
-
setCraftApproval({ request: request2, resolve:
|
|
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((
|
|
83598
|
-
setCraftFeedbackResolve(() =>
|
|
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((
|
|
83617
|
-
setCraftCheckIn({ request: request2, resolve:
|
|
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((
|
|
84027
|
+
return new Promise((resolve11) => {
|
|
83961
84028
|
setPendingQuestion({
|
|
83962
84029
|
question,
|
|
83963
84030
|
resolve: (selectedIndices, labels) => {
|
|
83964
|
-
|
|
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
|
|
84131
|
-
mkdir as
|
|
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
|
|
84137
|
-
import { join as
|
|
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 ??
|
|
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
|
|
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(
|
|
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
|
|
84347
|
+
await mkdir18(this.baseDir, { recursive: true });
|
|
84281
84348
|
}
|
|
84282
84349
|
}
|
|
84283
84350
|
getMetadataPath(sessionId) {
|
|
84284
|
-
return
|
|
84351
|
+
return join23(this.baseDir, `${sessionId}.meta.json`);
|
|
84285
84352
|
}
|
|
84286
84353
|
getMessagesPath(sessionId) {
|
|
84287
|
-
return
|
|
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 =
|
|
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(
|
|
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:
|
|
84771
|
+
}, { cwd: options2.cwd, homeDir: homedir15(), sessionId });
|
|
84705
84772
|
const context = await buildContext({
|
|
84706
84773
|
cwd: options2.cwd,
|
|
84707
84774
|
memory: true
|