cascade-ai 0.17.0 → 0.18.0
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/dist/cli.cjs +318 -185
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +315 -182
- package/dist/cli.js.map +1 -1
- package/dist/desktop-core.cjs +887 -756
- package/dist/index.cjs +243 -112
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.js +241 -111
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -9,8 +9,8 @@ var https = require('https');
|
|
|
9
9
|
var zlib = require('zlib');
|
|
10
10
|
var stream = require('stream');
|
|
11
11
|
var Database2 = require('better-sqlite3');
|
|
12
|
-
var
|
|
13
|
-
var
|
|
12
|
+
var path26 = require('path');
|
|
13
|
+
var fs24 = require('fs');
|
|
14
14
|
var os8 = require('os');
|
|
15
15
|
var crypto = require('crypto');
|
|
16
16
|
var ink = require('ink');
|
|
@@ -19,7 +19,7 @@ var React2 = require('react');
|
|
|
19
19
|
var chalk9 = require('chalk');
|
|
20
20
|
var dotenv = require('dotenv');
|
|
21
21
|
var url = require('url');
|
|
22
|
-
var
|
|
22
|
+
var fs10 = require('fs/promises');
|
|
23
23
|
var _ignoreModule = require('ignore');
|
|
24
24
|
var zod = require('zod');
|
|
25
25
|
var child_process = require('child_process');
|
|
@@ -73,14 +73,14 @@ var http__default = /*#__PURE__*/_interopDefault(http);
|
|
|
73
73
|
var https__default = /*#__PURE__*/_interopDefault(https);
|
|
74
74
|
var zlib__default = /*#__PURE__*/_interopDefault(zlib);
|
|
75
75
|
var Database2__default = /*#__PURE__*/_interopDefault(Database2);
|
|
76
|
-
var
|
|
77
|
-
var
|
|
76
|
+
var path26__default = /*#__PURE__*/_interopDefault(path26);
|
|
77
|
+
var fs24__default = /*#__PURE__*/_interopDefault(fs24);
|
|
78
78
|
var os8__default = /*#__PURE__*/_interopDefault(os8);
|
|
79
79
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
80
80
|
var React2__default = /*#__PURE__*/_interopDefault(React2);
|
|
81
81
|
var chalk9__default = /*#__PURE__*/_interopDefault(chalk9);
|
|
82
82
|
var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
|
|
83
|
-
var
|
|
83
|
+
var fs10__default = /*#__PURE__*/_interopDefault(fs10);
|
|
84
84
|
var _ignoreModule__namespace = /*#__PURE__*/_interopNamespace(_ignoreModule);
|
|
85
85
|
var EventEmitter__default = /*#__PURE__*/_interopDefault(EventEmitter);
|
|
86
86
|
var PDFDocument__default = /*#__PURE__*/_interopDefault(PDFDocument);
|
|
@@ -108,16 +108,17 @@ var __export = (target, all) => {
|
|
|
108
108
|
};
|
|
109
109
|
|
|
110
110
|
// src/constants.ts
|
|
111
|
-
var CASCADE_VERSION, CASCADE_CONFIG_FILE, CASCADE_DB_FILE, CASCADE_DASHBOARD_SECRET_FILE, GLOBAL_CONFIG_DIR, GLOBAL_DB_FILE, GLOBAL_KEYSTORE_FILE, GLOBAL_RUNTIME_DB_FILE, DEFAULT_DASHBOARD_PORT, DEFAULT_CONTEXT_LIMIT, DEFAULT_AUTO_SUMMARIZE_AT, MODELS, T1_MODEL_PRIORITY, T2_MODEL_PRIORITY, T3_MODEL_PRIORITY, VISION_MODEL_PRIORITY, COMPLEXITY_T2_COUNT, THEME_NAMES, DEFAULT_THEME, OLLAMA_BASE_URL, LM_STUDIO_BASE_URL, AZURE_BASE_URL_TEMPLATE, TOOL_NAMES, DEFAULT_APPROVAL_REQUIRED;
|
|
111
|
+
var CASCADE_VERSION, CASCADE_CONFIG_FILE, CASCADE_DB_FILE, CASCADE_DASHBOARD_SECRET_FILE, GLOBAL_CONFIG_DIR, GLOBAL_DB_FILE, GLOBAL_KEYSTORE_FILE, GLOBAL_CREDENTIALS_FILE, GLOBAL_RUNTIME_DB_FILE, DEFAULT_DASHBOARD_PORT, DEFAULT_CONTEXT_LIMIT, DEFAULT_AUTO_SUMMARIZE_AT, MODELS, T1_MODEL_PRIORITY, T2_MODEL_PRIORITY, T3_MODEL_PRIORITY, VISION_MODEL_PRIORITY, COMPLEXITY_T2_COUNT, THEME_NAMES, DEFAULT_THEME, OLLAMA_BASE_URL, LM_STUDIO_BASE_URL, AZURE_BASE_URL_TEMPLATE, TOOL_NAMES, DEFAULT_APPROVAL_REQUIRED;
|
|
112
112
|
var init_constants = __esm({
|
|
113
113
|
"src/constants.ts"() {
|
|
114
|
-
CASCADE_VERSION = "0.
|
|
114
|
+
CASCADE_VERSION = "0.18.0";
|
|
115
115
|
CASCADE_CONFIG_FILE = ".cascade/config.json";
|
|
116
116
|
CASCADE_DB_FILE = ".cascade/memory.db";
|
|
117
117
|
CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
|
|
118
118
|
GLOBAL_CONFIG_DIR = ".cascade-ai";
|
|
119
119
|
GLOBAL_DB_FILE = "memory.db";
|
|
120
120
|
GLOBAL_KEYSTORE_FILE = "keystore.enc";
|
|
121
|
+
GLOBAL_CREDENTIALS_FILE = "credentials.json";
|
|
121
122
|
GLOBAL_RUNTIME_DB_FILE = "runtime.db";
|
|
122
123
|
DEFAULT_DASHBOARD_PORT = 4891;
|
|
123
124
|
DEFAULT_CONTEXT_LIMIT = 2e5;
|
|
@@ -1632,12 +1633,12 @@ var init_audit_logger = __esm({
|
|
|
1632
1633
|
constructor(workspacePath, debugMode = false) {
|
|
1633
1634
|
this.workspacePath = workspacePath;
|
|
1634
1635
|
this.debugMode = debugMode;
|
|
1635
|
-
const cascadeDir =
|
|
1636
|
-
if (!
|
|
1637
|
-
|
|
1636
|
+
const cascadeDir = path26__default.default.join(workspacePath, ".cascade");
|
|
1637
|
+
if (!fs24__default.default.existsSync(cascadeDir)) {
|
|
1638
|
+
fs24__default.default.mkdirSync(cascadeDir, { recursive: true });
|
|
1638
1639
|
}
|
|
1639
|
-
this.keyPath =
|
|
1640
|
-
this.dbPath =
|
|
1640
|
+
this.keyPath = path26__default.default.join(cascadeDir, "audit_log.key");
|
|
1641
|
+
this.dbPath = path26__default.default.join(cascadeDir, "audit_log.db");
|
|
1641
1642
|
this.initEncryptionKey();
|
|
1642
1643
|
this.db = new Database2__default.default(this.dbPath);
|
|
1643
1644
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -1667,11 +1668,11 @@ var init_audit_logger = __esm({
|
|
|
1667
1668
|
return crypto__default.default.createHash("sha256").update(`${prevHash}|${timestamp}|${eventType}|${tierId}|${encryptedPayload}`).digest("hex");
|
|
1668
1669
|
}
|
|
1669
1670
|
initEncryptionKey() {
|
|
1670
|
-
if (
|
|
1671
|
-
this.encryptionKey =
|
|
1671
|
+
if (fs24__default.default.existsSync(this.keyPath)) {
|
|
1672
|
+
this.encryptionKey = fs24__default.default.readFileSync(this.keyPath);
|
|
1672
1673
|
} else {
|
|
1673
1674
|
this.encryptionKey = crypto__default.default.randomBytes(32);
|
|
1674
|
-
|
|
1675
|
+
fs24__default.default.writeFileSync(this.keyPath, this.encryptionKey);
|
|
1675
1676
|
}
|
|
1676
1677
|
}
|
|
1677
1678
|
encrypt(text) {
|
|
@@ -1749,9 +1750,9 @@ var init_audit_logger = __esm({
|
|
|
1749
1750
|
dumpDebugIfNeeded() {
|
|
1750
1751
|
if (!this.debugMode) return;
|
|
1751
1752
|
try {
|
|
1752
|
-
const dumpPath =
|
|
1753
|
+
const dumpPath = path26__default.default.join(os8__default.default.tmpdir(), "cascade_audit_logs_debug.json");
|
|
1753
1754
|
const entries = this.getAllLogs();
|
|
1754
|
-
|
|
1755
|
+
fs24__default.default.writeFileSync(dumpPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
1755
1756
|
} catch (err) {
|
|
1756
1757
|
console.error("Failed to dump debug audit logs", err);
|
|
1757
1758
|
}
|
|
@@ -1806,7 +1807,7 @@ var Keystore = class {
|
|
|
1806
1807
|
const creds = await this.keytar.findCredentials(KEYTAR_SERVICE);
|
|
1807
1808
|
this.cache = Object.fromEntries(creds.map((c) => [c.account, c.password]));
|
|
1808
1809
|
this.backend = "keytar";
|
|
1809
|
-
if (password &&
|
|
1810
|
+
if (password && fs24__default.default.existsSync(this.storePath)) {
|
|
1810
1811
|
try {
|
|
1811
1812
|
const fileEntries = this.decryptFile(password);
|
|
1812
1813
|
for (const [k, v] of Object.entries(fileEntries)) {
|
|
@@ -1825,7 +1826,7 @@ var Keystore = class {
|
|
|
1825
1826
|
"Keystore unlock requires a password because the OS keychain (keytar) is not available on this system."
|
|
1826
1827
|
);
|
|
1827
1828
|
}
|
|
1828
|
-
if (!
|
|
1829
|
+
if (!fs24__default.default.existsSync(this.storePath)) {
|
|
1829
1830
|
const salt = crypto__default.default.randomBytes(SALT_LEN);
|
|
1830
1831
|
this.masterKey = this.deriveKey(password, salt);
|
|
1831
1832
|
this.writeWithSalt({}, salt);
|
|
@@ -1839,7 +1840,7 @@ var Keystore = class {
|
|
|
1839
1840
|
}
|
|
1840
1841
|
/** Synchronous legacy unlock kept for AES-only environments. */
|
|
1841
1842
|
unlockSync(password) {
|
|
1842
|
-
if (!
|
|
1843
|
+
if (!fs24__default.default.existsSync(this.storePath)) {
|
|
1843
1844
|
const salt = crypto__default.default.randomBytes(SALT_LEN);
|
|
1844
1845
|
this.masterKey = this.deriveKey(password, salt);
|
|
1845
1846
|
this.writeWithSalt({}, salt);
|
|
@@ -1897,7 +1898,7 @@ var Keystore = class {
|
|
|
1897
1898
|
}
|
|
1898
1899
|
}
|
|
1899
1900
|
decryptFile(password, knownSalt) {
|
|
1900
|
-
if (!
|
|
1901
|
+
if (!fs24__default.default.existsSync(this.storePath)) return {};
|
|
1901
1902
|
try {
|
|
1902
1903
|
const { salt, ciphertext, iv, tag } = this.readRaw();
|
|
1903
1904
|
const useSalt = knownSalt ?? salt;
|
|
@@ -1919,8 +1920,8 @@ var Keystore = class {
|
|
|
1919
1920
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
1920
1921
|
const tag = cipher.getAuthTag();
|
|
1921
1922
|
const out = Buffer.concat([raw.salt, iv, tag, ciphertext]);
|
|
1922
|
-
|
|
1923
|
-
|
|
1923
|
+
fs24__default.default.mkdirSync(path26__default.default.dirname(this.storePath), { recursive: true });
|
|
1924
|
+
fs24__default.default.writeFileSync(this.storePath, out, { mode: 384 });
|
|
1924
1925
|
}
|
|
1925
1926
|
writeWithSalt(data, salt) {
|
|
1926
1927
|
if (!this.masterKey) throw new Error("writeWithSalt called before masterKey was set");
|
|
@@ -1930,11 +1931,11 @@ var Keystore = class {
|
|
|
1930
1931
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
1931
1932
|
const tag = cipher.getAuthTag();
|
|
1932
1933
|
const out = Buffer.concat([salt, iv, tag, ciphertext]);
|
|
1933
|
-
|
|
1934
|
-
|
|
1934
|
+
fs24__default.default.mkdirSync(path26__default.default.dirname(this.storePath), { recursive: true });
|
|
1935
|
+
fs24__default.default.writeFileSync(this.storePath, out, { mode: 384 });
|
|
1935
1936
|
}
|
|
1936
1937
|
readRaw() {
|
|
1937
|
-
const buf =
|
|
1938
|
+
const buf = fs24__default.default.readFileSync(this.storePath);
|
|
1938
1939
|
let offset = 0;
|
|
1939
1940
|
const salt = buf.subarray(offset, offset + SALT_LEN);
|
|
1940
1941
|
offset += SALT_LEN;
|
|
@@ -1967,9 +1968,9 @@ var CascadeIgnore = class {
|
|
|
1967
1968
|
]);
|
|
1968
1969
|
}
|
|
1969
1970
|
async load(workspacePath) {
|
|
1970
|
-
const filePath =
|
|
1971
|
+
const filePath = path26__default.default.join(workspacePath, ".cascadeignore");
|
|
1971
1972
|
try {
|
|
1972
|
-
const content = await
|
|
1973
|
+
const content = await fs10__default.default.readFile(filePath, "utf-8");
|
|
1973
1974
|
const lines = content.split("\n").filter((l) => l.trim() && !l.startsWith("#"));
|
|
1974
1975
|
this.ig.add(lines);
|
|
1975
1976
|
this.loaded = true;
|
|
@@ -1978,7 +1979,7 @@ var CascadeIgnore = class {
|
|
|
1978
1979
|
}
|
|
1979
1980
|
isIgnored(filePath, workspacePath) {
|
|
1980
1981
|
try {
|
|
1981
|
-
const relative = workspacePath ?
|
|
1982
|
+
const relative = workspacePath ? path26__default.default.relative(workspacePath, filePath) : filePath;
|
|
1982
1983
|
return this.ig.ignores(relative);
|
|
1983
1984
|
} catch {
|
|
1984
1985
|
return false;
|
|
@@ -1989,7 +1990,7 @@ var CascadeIgnore = class {
|
|
|
1989
1990
|
}
|
|
1990
1991
|
};
|
|
1991
1992
|
async function createDefaultIgnoreFile(workspacePath) {
|
|
1992
|
-
const filePath =
|
|
1993
|
+
const filePath = path26__default.default.join(workspacePath, ".cascadeignore");
|
|
1993
1994
|
const content = `# .cascadeignore \u2014 Files Cascade agents cannot read or modify
|
|
1994
1995
|
# Syntax identical to .gitignore
|
|
1995
1996
|
|
|
@@ -2016,12 +2017,12 @@ build/
|
|
|
2016
2017
|
.DS_Store
|
|
2017
2018
|
Thumbs.db
|
|
2018
2019
|
`;
|
|
2019
|
-
await
|
|
2020
|
+
await fs10__default.default.writeFile(filePath, content, "utf-8");
|
|
2020
2021
|
}
|
|
2021
2022
|
async function loadCascadeMd(workspacePath) {
|
|
2022
|
-
const filePath =
|
|
2023
|
+
const filePath = path26__default.default.join(workspacePath, "CASCADE.md");
|
|
2023
2024
|
try {
|
|
2024
|
-
const raw = await
|
|
2025
|
+
const raw = await fs10__default.default.readFile(filePath, "utf-8");
|
|
2025
2026
|
return parseCascadeMd(raw);
|
|
2026
2027
|
} catch {
|
|
2027
2028
|
return null;
|
|
@@ -2048,7 +2049,7 @@ ${raw.trim()}`;
|
|
|
2048
2049
|
return { raw, sections, systemPrompt };
|
|
2049
2050
|
}
|
|
2050
2051
|
async function createDefaultCascadeMd(workspacePath) {
|
|
2051
|
-
const filePath =
|
|
2052
|
+
const filePath = path26__default.default.join(workspacePath, "CASCADE.md");
|
|
2052
2053
|
const content = `# Cascade Project Instructions
|
|
2053
2054
|
|
|
2054
2055
|
This file contains project-specific instructions for the Cascade AI agent.
|
|
@@ -2078,12 +2079,12 @@ All tools are allowed unless specified otherwise.
|
|
|
2078
2079
|
|
|
2079
2080
|
List any areas the agent should not touch.
|
|
2080
2081
|
`;
|
|
2081
|
-
await
|
|
2082
|
+
await fs10__default.default.writeFile(filePath, content, "utf-8");
|
|
2082
2083
|
}
|
|
2083
2084
|
var MemoryStore = class _MemoryStore {
|
|
2084
2085
|
db;
|
|
2085
2086
|
constructor(dbPath) {
|
|
2086
|
-
|
|
2087
|
+
fs24__default.default.mkdirSync(path26__default.default.dirname(dbPath), { recursive: true });
|
|
2087
2088
|
try {
|
|
2088
2089
|
this.db = new Database2__default.default(dbPath, { timeout: 5e3 });
|
|
2089
2090
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -3230,6 +3231,63 @@ function validateConfig(raw) {
|
|
|
3230
3231
|
return result.data;
|
|
3231
3232
|
}
|
|
3232
3233
|
|
|
3234
|
+
// src/config/global-credentials.ts
|
|
3235
|
+
init_constants();
|
|
3236
|
+
function credentialsPath(globalDir) {
|
|
3237
|
+
return path26__default.default.join(globalDir, GLOBAL_CREDENTIALS_FILE);
|
|
3238
|
+
}
|
|
3239
|
+
function providerKey(p) {
|
|
3240
|
+
if (p.type === "azure") {
|
|
3241
|
+
return `azure:${p.deploymentName ?? p.baseUrl ?? p.label ?? ""}`;
|
|
3242
|
+
}
|
|
3243
|
+
return p.type;
|
|
3244
|
+
}
|
|
3245
|
+
function isPersistable(p) {
|
|
3246
|
+
return Boolean(p.apiKey || p.authToken || p.type === "azure" || p.baseUrl);
|
|
3247
|
+
}
|
|
3248
|
+
function loadGlobalCredentials(globalDir) {
|
|
3249
|
+
try {
|
|
3250
|
+
const raw = fs24__default.default.readFileSync(credentialsPath(globalDir), "utf-8");
|
|
3251
|
+
const parsed = JSON.parse(raw);
|
|
3252
|
+
if (!Array.isArray(parsed.providers)) return [];
|
|
3253
|
+
return parsed.providers.filter(
|
|
3254
|
+
(p) => Boolean(p) && typeof p.type === "string"
|
|
3255
|
+
);
|
|
3256
|
+
} catch {
|
|
3257
|
+
return [];
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
function saveGlobalCredentials(globalDir, providers) {
|
|
3261
|
+
const filePath = credentialsPath(globalDir);
|
|
3262
|
+
fs24__default.default.mkdirSync(globalDir, { recursive: true, mode: 448 });
|
|
3263
|
+
const body = { version: 1, providers: providers.filter(isPersistable) };
|
|
3264
|
+
const tmp = `${filePath}.tmp`;
|
|
3265
|
+
fs24__default.default.writeFileSync(tmp, JSON.stringify(body, null, 2), { encoding: "utf-8", mode: 384 });
|
|
3266
|
+
fs24__default.default.renameSync(tmp, filePath);
|
|
3267
|
+
try {
|
|
3268
|
+
fs24__default.default.chmodSync(filePath, 384);
|
|
3269
|
+
} catch {
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
function mergeGlobalCredentials(workspaceProviders, globalProviders) {
|
|
3273
|
+
const merged = [...workspaceProviders];
|
|
3274
|
+
const byKey = new Map(merged.map((p) => [providerKey(p), p]));
|
|
3275
|
+
for (const g of globalProviders) {
|
|
3276
|
+
const existing = byKey.get(providerKey(g));
|
|
3277
|
+
if (!existing) {
|
|
3278
|
+
merged.push({ ...g });
|
|
3279
|
+
byKey.set(providerKey(g), merged[merged.length - 1]);
|
|
3280
|
+
continue;
|
|
3281
|
+
}
|
|
3282
|
+
if (!existing.apiKey && g.apiKey) existing.apiKey = g.apiKey;
|
|
3283
|
+
if (!existing.authToken && g.authToken) existing.authToken = g.authToken;
|
|
3284
|
+
if (!existing.baseUrl && g.baseUrl) existing.baseUrl = g.baseUrl;
|
|
3285
|
+
if (!existing.apiVersion && g.apiVersion) existing.apiVersion = g.apiVersion;
|
|
3286
|
+
if (!existing.label && g.label) existing.label = g.label;
|
|
3287
|
+
}
|
|
3288
|
+
return merged;
|
|
3289
|
+
}
|
|
3290
|
+
|
|
3233
3291
|
// src/config/index.ts
|
|
3234
3292
|
init_constants();
|
|
3235
3293
|
var KEY_OPTIONAL_PROVIDER_TYPES = /* @__PURE__ */ new Set(["ollama", "openai-compatible"]);
|
|
@@ -3245,18 +3303,20 @@ var ConfigManager = class {
|
|
|
3245
3303
|
cascadeMd = null;
|
|
3246
3304
|
workspacePath;
|
|
3247
3305
|
globalDir;
|
|
3248
|
-
|
|
3306
|
+
/** `globalDirOverride` exists for tests — never point it at the real home dir there. */
|
|
3307
|
+
constructor(workspacePath = process.cwd(), globalDirOverride) {
|
|
3249
3308
|
this.workspacePath = workspacePath;
|
|
3250
|
-
this.globalDir =
|
|
3309
|
+
this.globalDir = globalDirOverride ?? path26__default.default.join(os8__default.default.homedir(), GLOBAL_CONFIG_DIR);
|
|
3251
3310
|
}
|
|
3252
3311
|
async load() {
|
|
3253
3312
|
this.config = await this.loadConfig();
|
|
3254
3313
|
this.ignore = new CascadeIgnore();
|
|
3255
3314
|
await this.ignore.load(this.workspacePath);
|
|
3256
3315
|
this.cascadeMd = await loadCascadeMd(this.workspacePath);
|
|
3257
|
-
this.keystore = new Keystore(
|
|
3258
|
-
this.store = new MemoryStore(
|
|
3316
|
+
this.keystore = new Keystore(path26__default.default.join(this.globalDir, GLOBAL_KEYSTORE_FILE));
|
|
3317
|
+
this.store = new MemoryStore(path26__default.default.join(this.workspacePath, CASCADE_DB_FILE));
|
|
3259
3318
|
await this.injectEnvKeys();
|
|
3319
|
+
this.config.providers = mergeGlobalCredentials(this.config.providers, loadGlobalCredentials(this.globalDir));
|
|
3260
3320
|
await this.ensureDefaultIdentity();
|
|
3261
3321
|
}
|
|
3262
3322
|
getConfig() {
|
|
@@ -3278,9 +3338,14 @@ var ConfigManager = class {
|
|
|
3278
3338
|
return this.workspacePath;
|
|
3279
3339
|
}
|
|
3280
3340
|
async save() {
|
|
3281
|
-
const configPath =
|
|
3282
|
-
await
|
|
3283
|
-
await
|
|
3341
|
+
const configPath = path26__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
3342
|
+
await fs10__default.default.mkdir(path26__default.default.dirname(configPath), { recursive: true });
|
|
3343
|
+
await fs10__default.default.writeFile(configPath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
3344
|
+
try {
|
|
3345
|
+
saveGlobalCredentials(this.globalDir, this.config.providers);
|
|
3346
|
+
} catch (err) {
|
|
3347
|
+
console.warn(`Failed to sync credentials to global store: ${err instanceof Error ? err.message : String(err)}`);
|
|
3348
|
+
}
|
|
3284
3349
|
}
|
|
3285
3350
|
async updateConfig(updates) {
|
|
3286
3351
|
this.config = validateConfig({ ...this.config, ...updates });
|
|
@@ -3303,9 +3368,9 @@ var ConfigManager = class {
|
|
|
3303
3368
|
return configProvider?.apiKey;
|
|
3304
3369
|
}
|
|
3305
3370
|
async loadConfig() {
|
|
3306
|
-
const configPath =
|
|
3371
|
+
const configPath = path26__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
3307
3372
|
try {
|
|
3308
|
-
const raw = await
|
|
3373
|
+
const raw = await fs10__default.default.readFile(configPath, "utf-8");
|
|
3309
3374
|
return validateConfig(JSON.parse(raw));
|
|
3310
3375
|
} catch (err) {
|
|
3311
3376
|
if (err.code === "ENOENT") {
|
|
@@ -4182,7 +4247,7 @@ init_constants();
|
|
|
4182
4247
|
var DEFAULT_SNAPSHOT_URL = "https://raw.githubusercontent.com/Varun-SV/Cascade-AI/main/src/core/router/benchmark-data.json";
|
|
4183
4248
|
var OPENROUTER_MODELS_URL = "https://openrouter.ai/api/v1/models";
|
|
4184
4249
|
var FETCH_TIMEOUT_MS = 8e3;
|
|
4185
|
-
var DEFAULT_CACHE_FILE =
|
|
4250
|
+
var DEFAULT_CACHE_FILE = path26__default.default.join(os8__default.default.homedir(), GLOBAL_CONFIG_DIR, "benchmarks-cache.json");
|
|
4186
4251
|
function normalizeModelId(id) {
|
|
4187
4252
|
let s = id.toLowerCase();
|
|
4188
4253
|
const slash = s.lastIndexOf("/");
|
|
@@ -4215,7 +4280,7 @@ var LiveDataProvider = class {
|
|
|
4215
4280
|
if (this.loaded) return;
|
|
4216
4281
|
this.loaded = true;
|
|
4217
4282
|
try {
|
|
4218
|
-
const raw = await
|
|
4283
|
+
const raw = await fs10__default.default.readFile(this.opts.cacheFile, "utf-8");
|
|
4219
4284
|
const cache = JSON.parse(raw);
|
|
4220
4285
|
if (cache.snapshot?.families) {
|
|
4221
4286
|
this.snapshot = cache.snapshot;
|
|
@@ -4327,14 +4392,14 @@ var LiveDataProvider = class {
|
|
|
4327
4392
|
}
|
|
4328
4393
|
async saveCache() {
|
|
4329
4394
|
try {
|
|
4330
|
-
await
|
|
4395
|
+
await fs10__default.default.mkdir(path26__default.default.dirname(this.opts.cacheFile), { recursive: true });
|
|
4331
4396
|
const cache = {
|
|
4332
4397
|
fetchedAt: this.fetchedAt,
|
|
4333
4398
|
snapshot: this.snapshot ?? void 0,
|
|
4334
4399
|
prices: Object.fromEntries(this.prices),
|
|
4335
4400
|
capabilities: Object.fromEntries(this.capabilities)
|
|
4336
4401
|
};
|
|
4337
|
-
await
|
|
4402
|
+
await fs10__default.default.writeFile(this.opts.cacheFile, JSON.stringify(cache, null, 2), "utf-8");
|
|
4338
4403
|
} catch {
|
|
4339
4404
|
}
|
|
4340
4405
|
}
|
|
@@ -6231,8 +6296,8 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : "") + textToolSuffix,
|
|
|
6231
6296
|
tierId: this.id,
|
|
6232
6297
|
sessionId: this.taskId,
|
|
6233
6298
|
requireApproval: false,
|
|
6234
|
-
saveSnapshot: async (
|
|
6235
|
-
this.store?.addFileSnapshot(this.taskId,
|
|
6299
|
+
saveSnapshot: async (path31, content) => {
|
|
6300
|
+
this.store?.addFileSnapshot(this.taskId, path31, content);
|
|
6236
6301
|
},
|
|
6237
6302
|
sendPeerSync: (to, syncType, content) => {
|
|
6238
6303
|
this.peerBus?.send(this.id, to, syncType, this.assignment?.subtaskId ?? "", content);
|
|
@@ -6402,9 +6467,9 @@ ${assignment.expectedOutput}`;
|
|
|
6402
6467
|
const { promisify: promisify4 } = await import('util');
|
|
6403
6468
|
const execAsync3 = promisify4(exec3);
|
|
6404
6469
|
for (const artifactPath of artifactPaths) {
|
|
6405
|
-
const absolutePath =
|
|
6470
|
+
const absolutePath = path26__default.default.resolve(process.cwd(), artifactPath);
|
|
6406
6471
|
try {
|
|
6407
|
-
const stat = await
|
|
6472
|
+
const stat = await fs10__default.default.stat(absolutePath);
|
|
6408
6473
|
if (!stat.isFile()) {
|
|
6409
6474
|
issues.push(`Expected artifact is not a file: ${artifactPath}`);
|
|
6410
6475
|
continue;
|
|
@@ -6414,7 +6479,7 @@ ${assignment.expectedOutput}`;
|
|
|
6414
6479
|
continue;
|
|
6415
6480
|
}
|
|
6416
6481
|
if (!/\.pdf$/i.test(artifactPath)) {
|
|
6417
|
-
const content = await
|
|
6482
|
+
const content = await fs10__default.default.readFile(absolutePath, "utf-8");
|
|
6418
6483
|
if (!content.trim()) {
|
|
6419
6484
|
issues.push(`Artifact content is empty: ${artifactPath}`);
|
|
6420
6485
|
continue;
|
|
@@ -6423,7 +6488,7 @@ ${assignment.expectedOutput}`;
|
|
|
6423
6488
|
issues.push(`PDF artifact looks too small to be valid: ${artifactPath}`);
|
|
6424
6489
|
continue;
|
|
6425
6490
|
}
|
|
6426
|
-
const ext =
|
|
6491
|
+
const ext = path26__default.default.extname(absolutePath).toLowerCase();
|
|
6427
6492
|
try {
|
|
6428
6493
|
if (ext === ".ts" || ext === ".tsx") {
|
|
6429
6494
|
await execAsync3(`npx tsc --noEmit ${absolutePath}`, { timeout: 1e4 });
|
|
@@ -8514,16 +8579,16 @@ function resolveInWorkspace(workspaceRoot, input) {
|
|
|
8514
8579
|
if (typeof input !== "string" || input.length === 0) {
|
|
8515
8580
|
throw new WorkspaceSandboxError(String(input), workspaceRoot);
|
|
8516
8581
|
}
|
|
8517
|
-
const root =
|
|
8518
|
-
const abs =
|
|
8519
|
-
const rel =
|
|
8520
|
-
if (rel === "" || rel === ".") ; else if (rel.startsWith("..") ||
|
|
8582
|
+
const root = path26__default.default.resolve(workspaceRoot);
|
|
8583
|
+
const abs = path26__default.default.isAbsolute(input) ? path26__default.default.resolve(input) : path26__default.default.resolve(root, input);
|
|
8584
|
+
const rel = path26__default.default.relative(root, abs);
|
|
8585
|
+
if (rel === "" || rel === ".") ; else if (rel.startsWith("..") || path26__default.default.isAbsolute(rel)) {
|
|
8521
8586
|
throw new WorkspaceSandboxError(input, root);
|
|
8522
8587
|
}
|
|
8523
8588
|
try {
|
|
8524
|
-
const real =
|
|
8525
|
-
const realRel =
|
|
8526
|
-
if (realRel !== "" && realRel !== "." && (realRel.startsWith("..") ||
|
|
8589
|
+
const real = fs24__default.default.realpathSync(abs);
|
|
8590
|
+
const realRel = path26__default.default.relative(root, real);
|
|
8591
|
+
if (realRel !== "" && realRel !== "." && (realRel.startsWith("..") || path26__default.default.isAbsolute(realRel))) {
|
|
8527
8592
|
throw new WorkspaceSandboxError(input, root);
|
|
8528
8593
|
}
|
|
8529
8594
|
} catch (e) {
|
|
@@ -8550,7 +8615,7 @@ var FileReadTool = class extends BaseTool {
|
|
|
8550
8615
|
const absPath = resolveInWorkspace(this.workspaceRoot, filePath);
|
|
8551
8616
|
const offset = input["offset"] ?? 1;
|
|
8552
8617
|
const limit = input["limit"];
|
|
8553
|
-
const content = await
|
|
8618
|
+
const content = await fs10__default.default.readFile(absPath, "utf-8");
|
|
8554
8619
|
const lines = content.split("\n");
|
|
8555
8620
|
const start = Math.max(0, offset - 1);
|
|
8556
8621
|
const end = limit ? start + limit : lines.length;
|
|
@@ -8579,13 +8644,13 @@ var FileWriteTool = class extends BaseTool {
|
|
|
8579
8644
|
const content = input["content"];
|
|
8580
8645
|
if (options.saveSnapshot) {
|
|
8581
8646
|
try {
|
|
8582
|
-
const oldContent = await
|
|
8647
|
+
const oldContent = await fs10__default.default.readFile(absPath, "utf-8");
|
|
8583
8648
|
await options.saveSnapshot(absPath, oldContent);
|
|
8584
8649
|
} catch {
|
|
8585
8650
|
}
|
|
8586
8651
|
}
|
|
8587
|
-
await
|
|
8588
|
-
await
|
|
8652
|
+
await fs10__default.default.mkdir(path26__default.default.dirname(absPath), { recursive: true });
|
|
8653
|
+
await fs10__default.default.writeFile(absPath, content, "utf-8");
|
|
8589
8654
|
return `Written ${content.length} characters to ${filePath}`;
|
|
8590
8655
|
}
|
|
8591
8656
|
};
|
|
@@ -8611,7 +8676,7 @@ var FileEditTool = class extends BaseTool {
|
|
|
8611
8676
|
const oldString = input["old_string"];
|
|
8612
8677
|
const newString = input["new_string"];
|
|
8613
8678
|
const replaceAll = input["replace_all"] ?? false;
|
|
8614
|
-
const rawContent = await
|
|
8679
|
+
const rawContent = await fs10__default.default.readFile(absPath, "utf-8");
|
|
8615
8680
|
if (options.saveSnapshot) {
|
|
8616
8681
|
await options.saveSnapshot(absPath, rawContent);
|
|
8617
8682
|
}
|
|
@@ -8623,7 +8688,7 @@ var FileEditTool = class extends BaseTool {
|
|
|
8623
8688
|
);
|
|
8624
8689
|
}
|
|
8625
8690
|
const updated = replaceAll ? content.split(normalizedOld).join(newString) : content.replace(normalizedOld, newString);
|
|
8626
|
-
await
|
|
8691
|
+
await fs10__default.default.writeFile(absPath, updated, "utf-8");
|
|
8627
8692
|
const count = replaceAll ? content.split(normalizedOld).length - 1 : 1;
|
|
8628
8693
|
return `Replaced ${count} occurrence(s) in ${filePath}`;
|
|
8629
8694
|
}
|
|
@@ -8646,12 +8711,12 @@ var FileDeleteTool = class extends BaseTool {
|
|
|
8646
8711
|
const absPath = resolveInWorkspace(this.workspaceRoot, filePath);
|
|
8647
8712
|
if (options.saveSnapshot) {
|
|
8648
8713
|
try {
|
|
8649
|
-
const oldContent = await
|
|
8714
|
+
const oldContent = await fs10__default.default.readFile(absPath, "utf-8");
|
|
8650
8715
|
await options.saveSnapshot(absPath, oldContent);
|
|
8651
8716
|
} catch {
|
|
8652
8717
|
}
|
|
8653
8718
|
}
|
|
8654
|
-
await
|
|
8719
|
+
await fs10__default.default.rm(absPath, { recursive: false });
|
|
8655
8720
|
return `Deleted ${filePath}`;
|
|
8656
8721
|
}
|
|
8657
8722
|
};
|
|
@@ -8668,7 +8733,7 @@ var FileListTool = class extends BaseTool {
|
|
|
8668
8733
|
async execute(input, _options) {
|
|
8669
8734
|
const inputPath = input["path"] || ".";
|
|
8670
8735
|
const absPath = resolveInWorkspace(this.workspaceRoot, inputPath);
|
|
8671
|
-
const entries = await
|
|
8736
|
+
const entries = await fs10__default.default.readdir(absPath, { withFileTypes: true });
|
|
8672
8737
|
return entries.map((e) => `${e.isDirectory() ? "[DIR] " : " "}${e.name}`).join("\n") || "(empty directory)";
|
|
8673
8738
|
}
|
|
8674
8739
|
};
|
|
@@ -9081,8 +9146,8 @@ var ImageAnalyzeTool = class extends BaseTool {
|
|
|
9081
9146
|
}
|
|
9082
9147
|
};
|
|
9083
9148
|
async function fileToImageAttachment(filePath) {
|
|
9084
|
-
const data = await
|
|
9085
|
-
const ext =
|
|
9149
|
+
const data = await fs10__default.default.readFile(filePath);
|
|
9150
|
+
const ext = path26__default.default.extname(filePath).toLowerCase();
|
|
9086
9151
|
const mimeMap = {
|
|
9087
9152
|
".jpg": "image/jpeg",
|
|
9088
9153
|
".jpeg": "image/jpeg",
|
|
@@ -9116,14 +9181,14 @@ var PDFCreateTool = class extends BaseTool {
|
|
|
9116
9181
|
const filePath = input["path"];
|
|
9117
9182
|
const content = input["content"];
|
|
9118
9183
|
const title = input["title"];
|
|
9119
|
-
const dir =
|
|
9120
|
-
if (!
|
|
9121
|
-
|
|
9184
|
+
const dir = path26__default.default.dirname(filePath);
|
|
9185
|
+
if (!fs24__default.default.existsSync(dir)) {
|
|
9186
|
+
fs24__default.default.mkdirSync(dir, { recursive: true });
|
|
9122
9187
|
}
|
|
9123
9188
|
return new Promise((resolve, reject) => {
|
|
9124
9189
|
try {
|
|
9125
9190
|
const doc = new PDFDocument__default.default({ margin: 50 });
|
|
9126
|
-
const stream =
|
|
9191
|
+
const stream = fs24__default.default.createWriteStream(filePath);
|
|
9127
9192
|
doc.pipe(stream);
|
|
9128
9193
|
if (title) {
|
|
9129
9194
|
doc.info["Title"] = title;
|
|
@@ -9201,22 +9266,22 @@ var CodeInterpreterTool = class extends BaseTool {
|
|
|
9201
9266
|
}
|
|
9202
9267
|
cmdPrefix = NODE_CMD;
|
|
9203
9268
|
}
|
|
9204
|
-
const tmpDir =
|
|
9205
|
-
if (!
|
|
9206
|
-
|
|
9269
|
+
const tmpDir = path26__default.default.join(this.workspaceRoot, ".cascade", "tmp");
|
|
9270
|
+
if (!fs24__default.default.existsSync(tmpDir)) {
|
|
9271
|
+
fs24__default.default.mkdirSync(tmpDir, { recursive: true });
|
|
9207
9272
|
}
|
|
9208
9273
|
const extension = language === "python" ? "py" : "js";
|
|
9209
9274
|
const fileName = `intp_${crypto.randomUUID().slice(0, 8)}.${extension}`;
|
|
9210
|
-
const filePath =
|
|
9211
|
-
|
|
9275
|
+
const filePath = path26__default.default.join(tmpDir, fileName);
|
|
9276
|
+
fs24__default.default.writeFileSync(filePath, code, "utf-8");
|
|
9212
9277
|
const execArgs = [filePath, ...args];
|
|
9213
9278
|
return new Promise((resolve) => {
|
|
9214
9279
|
const startMs = Date.now();
|
|
9215
9280
|
child_process.execFile(cmdPrefix, execArgs, { cwd: this.workspaceRoot, timeout: 3e4 }, (error, stdout, stderr) => {
|
|
9216
9281
|
const duration = Date.now() - startMs;
|
|
9217
9282
|
try {
|
|
9218
|
-
if (
|
|
9219
|
-
|
|
9283
|
+
if (fs24__default.default.existsSync(filePath)) {
|
|
9284
|
+
fs24__default.default.unlinkSync(filePath);
|
|
9220
9285
|
}
|
|
9221
9286
|
} catch (cleanupErr) {
|
|
9222
9287
|
console.error(`Failed to cleanup interpreter script ${filePath}:`, cleanupErr);
|
|
@@ -9495,7 +9560,7 @@ var GlobTool = class extends BaseTool {
|
|
|
9495
9560
|
};
|
|
9496
9561
|
async execute(input, _options) {
|
|
9497
9562
|
const pattern = input["pattern"];
|
|
9498
|
-
const searchPath = input["path"] ?
|
|
9563
|
+
const searchPath = input["path"] ? path26__default.default.resolve(this.workspaceRoot, input["path"]) : this.workspaceRoot;
|
|
9499
9564
|
const matches = await glob.glob(pattern, {
|
|
9500
9565
|
cwd: searchPath,
|
|
9501
9566
|
ignore: ["node_modules/**", ".git/**", "dist/**", "build/**"],
|
|
@@ -9508,7 +9573,7 @@ var GlobTool = class extends BaseTool {
|
|
|
9508
9573
|
const withMtime = await Promise.all(
|
|
9509
9574
|
matches.map(async (rel) => {
|
|
9510
9575
|
try {
|
|
9511
|
-
const stat = await
|
|
9576
|
+
const stat = await fs10__default.default.stat(path26__default.default.join(searchPath, rel));
|
|
9512
9577
|
return { rel, mtime: stat.mtimeMs };
|
|
9513
9578
|
} catch {
|
|
9514
9579
|
return { rel, mtime: 0 };
|
|
@@ -9557,7 +9622,7 @@ var GrepTool = class extends BaseTool {
|
|
|
9557
9622
|
};
|
|
9558
9623
|
async execute(input, _options) {
|
|
9559
9624
|
const pattern = input["pattern"];
|
|
9560
|
-
const searchPath = input["path"] ?
|
|
9625
|
+
const searchPath = input["path"] ? path26__default.default.resolve(this.workspaceRoot, input["path"]) : this.workspaceRoot;
|
|
9561
9626
|
const globPattern = input["glob"];
|
|
9562
9627
|
const outputMode = input["output_mode"] ?? "content";
|
|
9563
9628
|
const context = input["context"] ?? 0;
|
|
@@ -9611,15 +9676,15 @@ var GrepTool = class extends BaseTool {
|
|
|
9611
9676
|
nodir: true
|
|
9612
9677
|
});
|
|
9613
9678
|
} catch {
|
|
9614
|
-
files = [
|
|
9679
|
+
files = [path26__default.default.relative(searchPath, searchPath) || "."];
|
|
9615
9680
|
}
|
|
9616
9681
|
const results = [];
|
|
9617
9682
|
let totalCount = 0;
|
|
9618
9683
|
for (const rel of files) {
|
|
9619
|
-
const abs =
|
|
9684
|
+
const abs = path26__default.default.join(searchPath, rel);
|
|
9620
9685
|
let content;
|
|
9621
9686
|
try {
|
|
9622
|
-
content = await
|
|
9687
|
+
content = await fs10__default.default.readFile(abs, "utf-8");
|
|
9623
9688
|
} catch {
|
|
9624
9689
|
continue;
|
|
9625
9690
|
}
|
|
@@ -9978,10 +10043,10 @@ var ToolRegistry = class extends EventEmitter__default.default {
|
|
|
9978
10043
|
}
|
|
9979
10044
|
isIgnored(filePath) {
|
|
9980
10045
|
if (!filePath) return false;
|
|
9981
|
-
const abs =
|
|
9982
|
-
const rel =
|
|
9983
|
-
if (!rel || rel.startsWith("..") ||
|
|
9984
|
-
const posixRel = rel.split(
|
|
10046
|
+
const abs = path26__default.default.resolve(this.workspaceRoot, filePath);
|
|
10047
|
+
const rel = path26__default.default.relative(this.workspaceRoot, abs);
|
|
10048
|
+
if (!rel || rel.startsWith("..") || path26__default.default.isAbsolute(rel)) return true;
|
|
10049
|
+
const posixRel = rel.split(path26__default.default.sep).join("/");
|
|
9985
10050
|
return this.ignoreMatcher.ignores(posixRel);
|
|
9986
10051
|
}
|
|
9987
10052
|
};
|
|
@@ -10504,7 +10569,7 @@ var TaskAnalyzer = class {
|
|
|
10504
10569
|
analysisCache.clear();
|
|
10505
10570
|
}
|
|
10506
10571
|
};
|
|
10507
|
-
var DEFAULT_STATS_FILE =
|
|
10572
|
+
var DEFAULT_STATS_FILE = path26__default.default.join(os8__default.default.homedir(), ".cascade", "model-perf.json");
|
|
10508
10573
|
var ModelPerformanceTracker = class {
|
|
10509
10574
|
stats = /* @__PURE__ */ new Map();
|
|
10510
10575
|
featureStats = /* @__PURE__ */ new Map();
|
|
@@ -10517,7 +10582,7 @@ var ModelPerformanceTracker = class {
|
|
|
10517
10582
|
if (this.loaded) return;
|
|
10518
10583
|
this.loaded = true;
|
|
10519
10584
|
try {
|
|
10520
|
-
const raw = await
|
|
10585
|
+
const raw = await fs10__default.default.readFile(this.statsFile, "utf-8");
|
|
10521
10586
|
const parsed = JSON.parse(raw);
|
|
10522
10587
|
if (parsed.models) {
|
|
10523
10588
|
for (const [key, stat] of Object.entries(parsed.models)) this.stats.set(key, stat);
|
|
@@ -10536,12 +10601,12 @@ var ModelPerformanceTracker = class {
|
|
|
10536
10601
|
}
|
|
10537
10602
|
async save() {
|
|
10538
10603
|
try {
|
|
10539
|
-
await
|
|
10604
|
+
await fs10__default.default.mkdir(path26__default.default.dirname(this.statsFile), { recursive: true });
|
|
10540
10605
|
const modelsObj = {};
|
|
10541
10606
|
const featuresObj = {};
|
|
10542
10607
|
for (const [key, stat] of this.stats) modelsObj[key] = stat;
|
|
10543
10608
|
for (const [key, stat] of this.featureStats) featuresObj[key] = stat;
|
|
10544
|
-
await
|
|
10609
|
+
await fs10__default.default.writeFile(this.statsFile, JSON.stringify({ models: modelsObj, features: featuresObj }, null, 2), "utf-8");
|
|
10545
10610
|
} catch {
|
|
10546
10611
|
}
|
|
10547
10612
|
}
|
|
@@ -11075,9 +11140,9 @@ Required capability: ${description.slice(0, 300)}`;
|
|
|
11075
11140
|
* any dangerous action, so a silently-reloaded tool can't act without approval. */
|
|
11076
11141
|
async loadPersistedTools() {
|
|
11077
11142
|
if (!this.workspacePath || !this.persistEnabled) return;
|
|
11078
|
-
const file =
|
|
11143
|
+
const file = path26__default.default.join(this.workspacePath, ".cascade", DYNAMIC_TOOLS_FILE);
|
|
11079
11144
|
try {
|
|
11080
|
-
const raw = await
|
|
11145
|
+
const raw = await fs10__default.default.readFile(file, "utf-8");
|
|
11081
11146
|
const specs = JSON.parse(raw);
|
|
11082
11147
|
if (!Array.isArray(specs)) return;
|
|
11083
11148
|
let loaded = 0;
|
|
@@ -11099,11 +11164,11 @@ Required capability: ${description.slice(0, 300)}`;
|
|
|
11099
11164
|
}
|
|
11100
11165
|
async persist() {
|
|
11101
11166
|
if (!this.workspacePath || !this.persistEnabled) return;
|
|
11102
|
-
const dir =
|
|
11103
|
-
const file =
|
|
11167
|
+
const dir = path26__default.default.join(this.workspacePath, ".cascade");
|
|
11168
|
+
const file = path26__default.default.join(dir, DYNAMIC_TOOLS_FILE);
|
|
11104
11169
|
try {
|
|
11105
|
-
await
|
|
11106
|
-
await
|
|
11170
|
+
await fs10__default.default.mkdir(dir, { recursive: true });
|
|
11171
|
+
await fs10__default.default.writeFile(file, JSON.stringify(Array.from(this.specs.values()), null, 2), "utf-8");
|
|
11107
11172
|
} catch (err) {
|
|
11108
11173
|
this.log(`[tool-creator] Failed to persist tools: ${err instanceof Error ? err.message : String(err)}`);
|
|
11109
11174
|
}
|
|
@@ -11120,12 +11185,12 @@ var WorldStateDB = class {
|
|
|
11120
11185
|
constructor(workspacePath, debugMode = false) {
|
|
11121
11186
|
this.workspacePath = workspacePath;
|
|
11122
11187
|
this.debugMode = debugMode;
|
|
11123
|
-
const cascadeDir =
|
|
11124
|
-
if (!
|
|
11125
|
-
|
|
11188
|
+
const cascadeDir = path26__default.default.join(workspacePath, ".cascade");
|
|
11189
|
+
if (!fs24__default.default.existsSync(cascadeDir)) {
|
|
11190
|
+
fs24__default.default.mkdirSync(cascadeDir, { recursive: true });
|
|
11126
11191
|
}
|
|
11127
|
-
this.keyPath =
|
|
11128
|
-
this.dbPath =
|
|
11192
|
+
this.keyPath = path26__default.default.join(cascadeDir, "world_state.key");
|
|
11193
|
+
this.dbPath = path26__default.default.join(cascadeDir, "world_state.db");
|
|
11129
11194
|
this.initEncryptionKey();
|
|
11130
11195
|
this.db = new Database2__default.default(this.dbPath);
|
|
11131
11196
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -11155,11 +11220,11 @@ var WorldStateDB = class {
|
|
|
11155
11220
|
dbPath;
|
|
11156
11221
|
encryptionKey;
|
|
11157
11222
|
initEncryptionKey() {
|
|
11158
|
-
if (
|
|
11159
|
-
this.encryptionKey =
|
|
11223
|
+
if (fs24__default.default.existsSync(this.keyPath)) {
|
|
11224
|
+
this.encryptionKey = fs24__default.default.readFileSync(this.keyPath);
|
|
11160
11225
|
} else {
|
|
11161
11226
|
this.encryptionKey = crypto__default.default.randomBytes(32);
|
|
11162
|
-
|
|
11227
|
+
fs24__default.default.writeFileSync(this.keyPath, this.encryptionKey);
|
|
11163
11228
|
}
|
|
11164
11229
|
}
|
|
11165
11230
|
encrypt(text) {
|
|
@@ -11300,6 +11365,22 @@ var WorldStateDB = class {
|
|
|
11300
11365
|
}
|
|
11301
11366
|
return selected.slice(0, limit).map((f) => `- ${f.entity} ${f.relation} ${f.value}`).join("\n");
|
|
11302
11367
|
}
|
|
11368
|
+
/**
|
|
11369
|
+
* Delete one fact by its (normalized) entity + relation key. Returns whether
|
|
11370
|
+
* a row was actually removed. Powers the desktop Knowledge tab's per-fact
|
|
11371
|
+
* delete — users can prune what the planner remembers about their project.
|
|
11372
|
+
*/
|
|
11373
|
+
deleteFact(entity, relation) {
|
|
11374
|
+
const e = normalizeKey(entity);
|
|
11375
|
+
const r = normalizeKey(relation);
|
|
11376
|
+
if (!e || !r) return false;
|
|
11377
|
+
const result = this.db.prepare("DELETE FROM facts WHERE entity = ? AND relation = ?").run(e, r);
|
|
11378
|
+
return result.changes > 0;
|
|
11379
|
+
}
|
|
11380
|
+
/** Delete every fact. Returns how many were removed. */
|
|
11381
|
+
clearFacts() {
|
|
11382
|
+
return this.db.prepare("DELETE FROM facts").run().changes;
|
|
11383
|
+
}
|
|
11303
11384
|
// ── Export / Import ──────────────────────────
|
|
11304
11385
|
//
|
|
11305
11386
|
// Knowledge travels DECRYPTED in the export bundle (a portable plaintext
|
|
@@ -11348,9 +11429,9 @@ var WorldStateDB = class {
|
|
|
11348
11429
|
dumpDebugIfNeeded() {
|
|
11349
11430
|
if (!this.debugMode) return;
|
|
11350
11431
|
try {
|
|
11351
|
-
const dumpPath =
|
|
11432
|
+
const dumpPath = path26__default.default.join(os8__default.default.tmpdir(), "cascade_world_state_debug.json");
|
|
11352
11433
|
const entries = this.getAllEntries();
|
|
11353
|
-
|
|
11434
|
+
fs24__default.default.writeFileSync(dumpPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
11354
11435
|
} catch (err) {
|
|
11355
11436
|
console.error("Failed to dump debug world state", err);
|
|
11356
11437
|
}
|
|
@@ -13768,10 +13849,10 @@ function Repl({ config, workspacePath, themeName, initialPrompt, identityName, a
|
|
|
13768
13849
|
}
|
|
13769
13850
|
} catch {
|
|
13770
13851
|
}
|
|
13771
|
-
const configPath =
|
|
13852
|
+
const configPath = path26__default.default.join(workspacePath, ".cascade", "config.json");
|
|
13772
13853
|
try {
|
|
13773
|
-
await
|
|
13774
|
-
await
|
|
13854
|
+
await fs10__default.default.mkdir(path26__default.default.dirname(configPath), { recursive: true });
|
|
13855
|
+
await fs10__default.default.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
13775
13856
|
} catch (err) {
|
|
13776
13857
|
const msg = err instanceof Error ? err.message : String(err);
|
|
13777
13858
|
dispatch({
|
|
@@ -13822,9 +13903,9 @@ function Repl({ config, workspacePath, themeName, initialPrompt, identityName, a
|
|
|
13822
13903
|
if (msg.includes("non-text parts")) return;
|
|
13823
13904
|
originalLog(...args);
|
|
13824
13905
|
};
|
|
13825
|
-
const store = new MemoryStore(
|
|
13906
|
+
const store = new MemoryStore(path26__default.default.join(workspacePath, CASCADE_DB_FILE));
|
|
13826
13907
|
storeRef.current = store;
|
|
13827
|
-
globalStoreRef.current = new MemoryStore(
|
|
13908
|
+
globalStoreRef.current = new MemoryStore(path26__default.default.join(os8__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE));
|
|
13828
13909
|
const identityRows = store.listIdentities().map((i) => ({ id: i.id, name: i.name, isDefault: i.isDefault }));
|
|
13829
13910
|
setIdentities(identityRows);
|
|
13830
13911
|
let initialIdentityId = config.defaultIdentityId ?? identityRows.find((i) => i.isDefault)?.id ?? identityRows[0]?.id;
|
|
@@ -13887,14 +13968,14 @@ function Repl({ config, workspacePath, themeName, initialPrompt, identityName, a
|
|
|
13887
13968
|
onThemeChange: (name) => setTheme(getTheme(name)),
|
|
13888
13969
|
onExport: async (fmt) => {
|
|
13889
13970
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
13890
|
-
const exportPath =
|
|
13971
|
+
const exportPath = path26__default.default.join(workspacePath, `cascade-export-${stamp}.${fmt === "json" ? "json" : "md"}`);
|
|
13891
13972
|
if (fmt === "json") {
|
|
13892
|
-
await
|
|
13973
|
+
await fs10__default.default.writeFile(exportPath, JSON.stringify({ sessionId: sessionIdRef.current, messages: state.messages }, null, 2), "utf-8");
|
|
13893
13974
|
} else {
|
|
13894
13975
|
const markdown = state.messages.map((msg) => `## ${msg.role.toUpperCase()} \u2014 ${msg.timestamp}
|
|
13895
13976
|
|
|
13896
13977
|
${msg.content}`).join("\n\n");
|
|
13897
|
-
await
|
|
13978
|
+
await fs10__default.default.writeFile(exportPath, markdown, "utf-8");
|
|
13898
13979
|
}
|
|
13899
13980
|
},
|
|
13900
13981
|
onRollback: async () => {
|
|
@@ -13904,7 +13985,7 @@ ${msg.content}`).join("\n\n");
|
|
|
13904
13985
|
if (!snapshots.length) return "No file snapshots found for this session.";
|
|
13905
13986
|
for (const { filePath, content } of snapshots) {
|
|
13906
13987
|
try {
|
|
13907
|
-
await
|
|
13988
|
+
await fs10__default.default.writeFile(filePath, content, "utf-8");
|
|
13908
13989
|
} catch (err) {
|
|
13909
13990
|
console.error(`Restore failed: ${filePath}`, err);
|
|
13910
13991
|
}
|
|
@@ -14783,9 +14864,9 @@ function stringifySlashOutput(val) {
|
|
|
14783
14864
|
}
|
|
14784
14865
|
async function searchSessionsAndMessages(query, workspacePath) {
|
|
14785
14866
|
if (!query) return "Usage: /search <query>";
|
|
14786
|
-
const dbPath =
|
|
14867
|
+
const dbPath = path26__default.default.join(workspacePath, CASCADE_DB_FILE);
|
|
14787
14868
|
try {
|
|
14788
|
-
await
|
|
14869
|
+
await fs10__default.default.access(dbPath);
|
|
14789
14870
|
} catch {
|
|
14790
14871
|
return "No database found. Start a conversation first.";
|
|
14791
14872
|
}
|
|
@@ -14817,7 +14898,7 @@ async function searchSessionsAndMessages(query, workspacePath) {
|
|
|
14817
14898
|
async function diagnoseRuntime(config, workspacePath) {
|
|
14818
14899
|
const providers = config.providers.map((p) => `${p.type}${p.apiKey ? " (key set)" : " (no key)"}`).join("\n");
|
|
14819
14900
|
const models = [`T1: ${config.models.t1 ?? "default"}`, `T2: ${config.models.t2 ?? "default"}`, `T3: ${config.models.t3 ?? "default"}`].join("\n");
|
|
14820
|
-
const store = new MemoryStore(
|
|
14901
|
+
const store = new MemoryStore(path26__default.default.join(workspacePath, CASCADE_DB_FILE));
|
|
14821
14902
|
try {
|
|
14822
14903
|
const sessions = store.listSessions(void 0, 3);
|
|
14823
14904
|
return [
|
|
@@ -14836,7 +14917,7 @@ async function diagnoseRuntime(config, workspacePath) {
|
|
|
14836
14917
|
}
|
|
14837
14918
|
async function showRecentLogs(args, workspacePath) {
|
|
14838
14919
|
const limit = Number.parseInt(args[0] ?? "10", 10) || 10;
|
|
14839
|
-
const store = new MemoryStore(
|
|
14920
|
+
const store = new MemoryStore(path26__default.default.join(workspacePath, CASCADE_DB_FILE));
|
|
14840
14921
|
try {
|
|
14841
14922
|
const logs = store.listRuntimeNodeLogs(void 0, void 0, limit);
|
|
14842
14923
|
if (!logs.length) return "No recent runtime logs.";
|
|
@@ -14848,7 +14929,7 @@ async function showRecentLogs(args, workspacePath) {
|
|
|
14848
14929
|
async function loadSessionSnapshot(args, workspacePath) {
|
|
14849
14930
|
const sessionId = args[0];
|
|
14850
14931
|
if (!sessionId) return "Usage: /resume <sessionId>";
|
|
14851
|
-
const store = new MemoryStore(
|
|
14932
|
+
const store = new MemoryStore(path26__default.default.join(workspacePath, CASCADE_DB_FILE));
|
|
14852
14933
|
try {
|
|
14853
14934
|
const session = store.getSession(sessionId);
|
|
14854
14935
|
if (!session) return `Session not found: ${sessionId}`;
|
|
@@ -15268,10 +15349,10 @@ function SetupWizard({ workspacePath, onComplete }) {
|
|
|
15268
15349
|
...anyAuto ? { cascadeAuto: true } : {}
|
|
15269
15350
|
};
|
|
15270
15351
|
const config = CascadeConfigSchema.parse(rawConfig);
|
|
15271
|
-
const configDir =
|
|
15272
|
-
await
|
|
15273
|
-
const configPath =
|
|
15274
|
-
await
|
|
15352
|
+
const configDir = path26__default.default.join(workspacePath, ".cascade");
|
|
15353
|
+
await fs10__default.default.mkdir(configDir, { recursive: true });
|
|
15354
|
+
const configPath = path26__default.default.join(workspacePath, CASCADE_CONFIG_FILE);
|
|
15355
|
+
await fs10__default.default.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
15275
15356
|
savedConfigRef.current = config;
|
|
15276
15357
|
dispatchRef.current({ type: "GO_DONE" });
|
|
15277
15358
|
} catch (err) {
|
|
@@ -15611,14 +15692,14 @@ function printTelemetryBanner() {
|
|
|
15611
15692
|
async function initCommand(workspacePath = process.cwd()) {
|
|
15612
15693
|
const spin = ora__default.default({ text: "Initializing Cascade project\u2026", color: "magenta" }).start();
|
|
15613
15694
|
try {
|
|
15614
|
-
const configDir =
|
|
15615
|
-
await
|
|
15616
|
-
const mdPath =
|
|
15695
|
+
const configDir = path26__default.default.join(workspacePath, ".cascade");
|
|
15696
|
+
await fs10__default.default.mkdir(configDir, { recursive: true });
|
|
15697
|
+
const mdPath = path26__default.default.join(workspacePath, "CASCADE.md");
|
|
15617
15698
|
if (!await fileExists(mdPath)) {
|
|
15618
15699
|
await createDefaultCascadeMd(workspacePath);
|
|
15619
15700
|
spin.succeed(chalk9__default.default.green("Created CASCADE.md"));
|
|
15620
15701
|
}
|
|
15621
|
-
const ignorePath =
|
|
15702
|
+
const ignorePath = path26__default.default.join(workspacePath, ".cascadeignore");
|
|
15622
15703
|
if (!await fileExists(ignorePath)) {
|
|
15623
15704
|
await createDefaultIgnoreFile(workspacePath);
|
|
15624
15705
|
spin.succeed(chalk9__default.default.green("Created .cascadeignore"));
|
|
@@ -15627,7 +15708,7 @@ async function initCommand(workspacePath = process.cwd()) {
|
|
|
15627
15708
|
console.log();
|
|
15628
15709
|
console.log(chalk9__default.default.magenta(" \u25C8 Cascade AI \u2014 Project initialized"));
|
|
15629
15710
|
console.log();
|
|
15630
|
-
const configPath =
|
|
15711
|
+
const configPath = path26__default.default.join(workspacePath, CASCADE_CONFIG_FILE);
|
|
15631
15712
|
if (await fileExists(configPath)) {
|
|
15632
15713
|
console.log(chalk9__default.default.yellow(" .cascade/config.json already exists \u2014 launching wizard to reconfigure."));
|
|
15633
15714
|
console.log();
|
|
@@ -15646,7 +15727,7 @@ async function initCommand(workspacePath = process.cwd()) {
|
|
|
15646
15727
|
}
|
|
15647
15728
|
async function fileExists(p) {
|
|
15648
15729
|
try {
|
|
15649
|
-
await
|
|
15730
|
+
await fs10__default.default.access(p);
|
|
15650
15731
|
return true;
|
|
15651
15732
|
} catch {
|
|
15652
15733
|
return false;
|
|
@@ -15658,7 +15739,7 @@ init_constants();
|
|
|
15658
15739
|
var TOS_WARNING = "Reusing this subscription token outside its own CLI may violate the vendor\u2019s terms of service.";
|
|
15659
15740
|
async function readJson(file) {
|
|
15660
15741
|
try {
|
|
15661
|
-
const raw = await
|
|
15742
|
+
const raw = await fs10__default.default.readFile(file, "utf-8");
|
|
15662
15743
|
return JSON.parse(raw);
|
|
15663
15744
|
} catch {
|
|
15664
15745
|
return null;
|
|
@@ -15685,7 +15766,7 @@ function fromEnv(env) {
|
|
|
15685
15766
|
return out;
|
|
15686
15767
|
}
|
|
15687
15768
|
async function fromClaudeCode(home) {
|
|
15688
|
-
const file =
|
|
15769
|
+
const file = path26__default.default.join(home, ".claude", ".credentials.json");
|
|
15689
15770
|
const data = await readJson(file);
|
|
15690
15771
|
if (!data) return [];
|
|
15691
15772
|
const oauth = data["claudeAiOauth"];
|
|
@@ -15708,7 +15789,7 @@ async function fromClaudeCode(home) {
|
|
|
15708
15789
|
return [];
|
|
15709
15790
|
}
|
|
15710
15791
|
async function fromCodex(home) {
|
|
15711
|
-
const file =
|
|
15792
|
+
const file = path26__default.default.join(home, ".codex", "auth.json");
|
|
15712
15793
|
const data = await readJson(file);
|
|
15713
15794
|
if (!data) return [];
|
|
15714
15795
|
const apiKey = str(data["OPENAI_API_KEY"]);
|
|
@@ -15731,7 +15812,7 @@ async function fromCodex(home) {
|
|
|
15731
15812
|
return [];
|
|
15732
15813
|
}
|
|
15733
15814
|
async function fromGemini(home) {
|
|
15734
|
-
const file =
|
|
15815
|
+
const file = path26__default.default.join(home, ".gemini", "oauth_creds.json");
|
|
15735
15816
|
const data = await readJson(file);
|
|
15736
15817
|
const accessToken = str(data?.["access_token"]);
|
|
15737
15818
|
if (!accessToken) return [];
|
|
@@ -15747,7 +15828,7 @@ async function fromGemini(home) {
|
|
|
15747
15828
|
}
|
|
15748
15829
|
async function fromCopilot(home) {
|
|
15749
15830
|
for (const name of ["apps.json", "hosts.json"]) {
|
|
15750
|
-
const file =
|
|
15831
|
+
const file = path26__default.default.join(home, ".config", "github-copilot", name);
|
|
15751
15832
|
const data = await readJson(file);
|
|
15752
15833
|
if (!data) continue;
|
|
15753
15834
|
for (const value of Object.values(data)) {
|
|
@@ -15801,7 +15882,7 @@ async function doctorCommand() {
|
|
|
15801
15882
|
checks.push({
|
|
15802
15883
|
label: "Cascade config",
|
|
15803
15884
|
ok: true,
|
|
15804
|
-
detail: `Loaded ${
|
|
15885
|
+
detail: `Loaded ${path26__default.default.join(process.cwd(), CASCADE_CONFIG_FILE)}`
|
|
15805
15886
|
});
|
|
15806
15887
|
const providers = [
|
|
15807
15888
|
{ type: "anthropic", name: "Anthropic" },
|
|
@@ -15957,6 +16038,11 @@ function authMiddleware(secret, required = true) {
|
|
|
15957
16038
|
}
|
|
15958
16039
|
const user = verifyToken(token, secret);
|
|
15959
16040
|
if (!user) {
|
|
16041
|
+
if (!required) {
|
|
16042
|
+
req.user = void 0;
|
|
16043
|
+
next();
|
|
16044
|
+
return;
|
|
16045
|
+
}
|
|
15960
16046
|
res.status(401).json({ error: "Invalid or expired token" });
|
|
15961
16047
|
return;
|
|
15962
16048
|
}
|
|
@@ -16268,7 +16354,7 @@ function aggregateCostStats(sessions, opts = {}) {
|
|
|
16268
16354
|
}
|
|
16269
16355
|
|
|
16270
16356
|
// src/dashboard/server.ts
|
|
16271
|
-
var __dirname$1 =
|
|
16357
|
+
var __dirname$1 = path26__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href))));
|
|
16272
16358
|
var DashboardServer = class {
|
|
16273
16359
|
app;
|
|
16274
16360
|
httpServer;
|
|
@@ -16502,12 +16588,17 @@ var DashboardServer = class {
|
|
|
16502
16588
|
*/
|
|
16503
16589
|
persistConfig() {
|
|
16504
16590
|
try {
|
|
16505
|
-
const configPath =
|
|
16506
|
-
|
|
16507
|
-
|
|
16591
|
+
const configPath = path26__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
16592
|
+
fs24__default.default.mkdirSync(path26__default.default.dirname(configPath), { recursive: true });
|
|
16593
|
+
fs24__default.default.writeFileSync(configPath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
16508
16594
|
} catch (err) {
|
|
16509
16595
|
console.warn(`[dashboard] Failed to persist config: ${err instanceof Error ? err.message : String(err)}`);
|
|
16510
16596
|
}
|
|
16597
|
+
try {
|
|
16598
|
+
saveGlobalCredentials(path26__default.default.join(os8__default.default.homedir(), GLOBAL_CONFIG_DIR), this.config.providers ?? []);
|
|
16599
|
+
} catch (err) {
|
|
16600
|
+
console.warn(`[dashboard] Failed to sync global credentials: ${err instanceof Error ? err.message : String(err)}`);
|
|
16601
|
+
}
|
|
16511
16602
|
}
|
|
16512
16603
|
/**
|
|
16513
16604
|
* Produce a stable dashboard JWT signing secret.
|
|
@@ -16519,15 +16610,15 @@ var DashboardServer = class {
|
|
|
16519
16610
|
resolveDashboardSecret() {
|
|
16520
16611
|
const fromConfig = this.config.dashboard.secret ?? process.env["CASCADE_DASHBOARD_SECRET"];
|
|
16521
16612
|
if (fromConfig) return fromConfig;
|
|
16522
|
-
const secretPath =
|
|
16613
|
+
const secretPath = path26__default.default.join(this.workspacePath, CASCADE_DASHBOARD_SECRET_FILE);
|
|
16523
16614
|
try {
|
|
16524
|
-
if (
|
|
16525
|
-
const existing =
|
|
16615
|
+
if (fs24__default.default.existsSync(secretPath)) {
|
|
16616
|
+
const existing = fs24__default.default.readFileSync(secretPath, "utf-8").trim();
|
|
16526
16617
|
if (existing.length >= 16) return existing;
|
|
16527
16618
|
}
|
|
16528
16619
|
const generated = crypto.randomUUID();
|
|
16529
|
-
|
|
16530
|
-
|
|
16620
|
+
fs24__default.default.mkdirSync(path26__default.default.dirname(secretPath), { recursive: true });
|
|
16621
|
+
fs24__default.default.writeFileSync(secretPath, generated, { encoding: "utf-8", mode: 384 });
|
|
16531
16622
|
if (this.config.dashboard.auth) {
|
|
16532
16623
|
console.warn(
|
|
16533
16624
|
`Dashboard auth enabled with no secret configured; persisted a generated secret to ${secretPath}. Set CASCADE_DASHBOARD_SECRET or config.dashboard.secret to override.`
|
|
@@ -16554,7 +16645,7 @@ var DashboardServer = class {
|
|
|
16554
16645
|
// ── Setup ─────────────────────────────────────
|
|
16555
16646
|
getGlobalStore() {
|
|
16556
16647
|
if (!this.globalStore) {
|
|
16557
|
-
const globalDbPath =
|
|
16648
|
+
const globalDbPath = path26__default.default.join(os8__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
16558
16649
|
this.globalStore = new MemoryStore(globalDbPath);
|
|
16559
16650
|
}
|
|
16560
16651
|
return this.globalStore;
|
|
@@ -16823,12 +16914,12 @@ ${prompt}`;
|
|
|
16823
16914
|
}
|
|
16824
16915
|
}
|
|
16825
16916
|
watchRuntimeChanges() {
|
|
16826
|
-
const workspaceDbPath =
|
|
16827
|
-
const globalDbPath =
|
|
16917
|
+
const workspaceDbPath = path26__default.default.join(this.workspacePath, CASCADE_DB_FILE);
|
|
16918
|
+
const globalDbPath = path26__default.default.join(os8__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
16828
16919
|
const watchPaths = [workspaceDbPath, globalDbPath].filter((p, index, arr) => arr.indexOf(p) === index);
|
|
16829
16920
|
for (const watchPath of watchPaths) {
|
|
16830
|
-
if (!
|
|
16831
|
-
|
|
16921
|
+
if (!fs24__default.default.existsSync(watchPath)) continue;
|
|
16922
|
+
fs24__default.default.watchFile(watchPath, { interval: 3e3 }, () => {
|
|
16832
16923
|
this.throttledBroadcast(watchPath === globalDbPath ? "global" : "workspace");
|
|
16833
16924
|
});
|
|
16834
16925
|
}
|
|
@@ -16950,7 +17041,7 @@ ${prompt}`;
|
|
|
16950
17041
|
const sessionId = req.params.id;
|
|
16951
17042
|
this.store.deleteSession(sessionId);
|
|
16952
17043
|
this.store.deleteRuntimeSession(sessionId);
|
|
16953
|
-
const globalDbPath =
|
|
17044
|
+
const globalDbPath = path26__default.default.join(os8__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
16954
17045
|
const globalStore = new MemoryStore(globalDbPath);
|
|
16955
17046
|
try {
|
|
16956
17047
|
globalStore.deleteRuntimeSession(sessionId);
|
|
@@ -17043,7 +17134,7 @@ ${prompt}`;
|
|
|
17043
17134
|
});
|
|
17044
17135
|
this.app.delete("/api/sessions", auth, (req, res) => {
|
|
17045
17136
|
const body = req.body;
|
|
17046
|
-
const globalDbPath =
|
|
17137
|
+
const globalDbPath = path26__default.default.join(os8__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
17047
17138
|
if (body?.ids && Array.isArray(body.ids) && body.ids.length > 0) {
|
|
17048
17139
|
const globalStore = new MemoryStore(globalDbPath);
|
|
17049
17140
|
try {
|
|
@@ -17066,7 +17157,7 @@ ${prompt}`;
|
|
|
17066
17157
|
});
|
|
17067
17158
|
this.app.delete("/api/runtime", auth, (_req, res) => {
|
|
17068
17159
|
this.store.deleteAllRuntimeNodes();
|
|
17069
|
-
const globalDbPath =
|
|
17160
|
+
const globalDbPath = path26__default.default.join(os8__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
17070
17161
|
const globalStore = new MemoryStore(globalDbPath);
|
|
17071
17162
|
try {
|
|
17072
17163
|
globalStore.deleteAllRuntimeNodes();
|
|
@@ -17152,12 +17243,12 @@ ${prompt}`;
|
|
|
17152
17243
|
if (body["tierLimits"]) this.config.tierLimits = { ...this.config.tierLimits, ...body["tierLimits"] };
|
|
17153
17244
|
if (body["budget"]) this.config.budget = { ...this.config.budget, ...body["budget"] };
|
|
17154
17245
|
try {
|
|
17155
|
-
const configPath =
|
|
17156
|
-
const existing =
|
|
17246
|
+
const configPath = path26__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
17247
|
+
const existing = fs24__default.default.existsSync(configPath) ? JSON.parse(fs24__default.default.readFileSync(configPath, "utf-8")) : {};
|
|
17157
17248
|
const updated = { ...existing, tierLimits: this.config.tierLimits, budget: this.config.budget };
|
|
17158
17249
|
const tmp = configPath + ".tmp";
|
|
17159
|
-
|
|
17160
|
-
|
|
17250
|
+
fs24__default.default.writeFileSync(tmp, JSON.stringify(updated, null, 2), "utf-8");
|
|
17251
|
+
fs24__default.default.renameSync(tmp, configPath);
|
|
17161
17252
|
res.json({ ok: true });
|
|
17162
17253
|
} catch (err) {
|
|
17163
17254
|
res.status(500).json({ error: `Failed to save config: ${err instanceof Error ? err.message : String(err)}` });
|
|
@@ -17185,7 +17276,7 @@ ${prompt}`;
|
|
|
17185
17276
|
this.app.get("/api/runtime", auth, (req, res) => {
|
|
17186
17277
|
const scope = req.query["scope"] ?? "workspace";
|
|
17187
17278
|
if (scope === "global") {
|
|
17188
|
-
const globalDbPath =
|
|
17279
|
+
const globalDbPath = path26__default.default.join(os8__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
17189
17280
|
const globalStore = new MemoryStore(globalDbPath);
|
|
17190
17281
|
try {
|
|
17191
17282
|
res.json({
|
|
@@ -17420,6 +17511,48 @@ ${prompt}`;
|
|
|
17420
17511
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
17421
17512
|
}
|
|
17422
17513
|
});
|
|
17514
|
+
this.app.get("/api/knowledge", auth, (_req, res) => {
|
|
17515
|
+
try {
|
|
17516
|
+
const ws = new WorldStateDB(this.workspacePath);
|
|
17517
|
+
try {
|
|
17518
|
+
const facts = ws.getAllFacts();
|
|
17519
|
+
res.json({ total: facts.length, facts });
|
|
17520
|
+
} finally {
|
|
17521
|
+
ws.close();
|
|
17522
|
+
}
|
|
17523
|
+
} catch (err) {
|
|
17524
|
+
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
17525
|
+
}
|
|
17526
|
+
});
|
|
17527
|
+
this.app.delete("/api/knowledge/fact", auth, mutationLimiter, (req, res) => {
|
|
17528
|
+
const body = req.body;
|
|
17529
|
+
if (!body.entity || !body.relation) {
|
|
17530
|
+
res.status(400).json({ error: "entity and relation are required" });
|
|
17531
|
+
return;
|
|
17532
|
+
}
|
|
17533
|
+
try {
|
|
17534
|
+
const ws = new WorldStateDB(this.workspacePath);
|
|
17535
|
+
try {
|
|
17536
|
+
res.json({ ok: true, deleted: ws.deleteFact(body.entity, body.relation) });
|
|
17537
|
+
} finally {
|
|
17538
|
+
ws.close();
|
|
17539
|
+
}
|
|
17540
|
+
} catch (err) {
|
|
17541
|
+
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
17542
|
+
}
|
|
17543
|
+
});
|
|
17544
|
+
this.app.delete("/api/knowledge", auth, mutationLimiter, (_req, res) => {
|
|
17545
|
+
try {
|
|
17546
|
+
const ws = new WorldStateDB(this.workspacePath);
|
|
17547
|
+
try {
|
|
17548
|
+
res.json({ ok: true, deleted: ws.clearFacts() });
|
|
17549
|
+
} finally {
|
|
17550
|
+
ws.close();
|
|
17551
|
+
}
|
|
17552
|
+
} catch (err) {
|
|
17553
|
+
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
17554
|
+
}
|
|
17555
|
+
});
|
|
17423
17556
|
this.app.get("/api/audit-chain", auth, async (req, res) => {
|
|
17424
17557
|
try {
|
|
17425
17558
|
const limit = Math.min(500, Math.max(1, parseInt(req.query["limit"] || "200", 10) || 200));
|
|
@@ -17438,13 +17571,13 @@ ${prompt}`;
|
|
|
17438
17571
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
17439
17572
|
}
|
|
17440
17573
|
});
|
|
17441
|
-
const prodPath =
|
|
17442
|
-
const devPath =
|
|
17443
|
-
const webDistPath =
|
|
17444
|
-
if (
|
|
17574
|
+
const prodPath = path26__default.default.resolve(__dirname$1, "../web/dist");
|
|
17575
|
+
const devPath = path26__default.default.resolve(__dirname$1, "../../web/dist");
|
|
17576
|
+
const webDistPath = fs24__default.default.existsSync(prodPath) ? prodPath : devPath;
|
|
17577
|
+
if (fs24__default.default.existsSync(webDistPath)) {
|
|
17445
17578
|
this.app.use(express__default.default.static(webDistPath));
|
|
17446
17579
|
this.app.get("*", (_req, res) => {
|
|
17447
|
-
res.sendFile(
|
|
17580
|
+
res.sendFile(path26__default.default.join(webDistPath, "index.html"));
|
|
17448
17581
|
});
|
|
17449
17582
|
} else {
|
|
17450
17583
|
this.app.get("/", (_req, res) => {
|
|
@@ -17465,7 +17598,7 @@ init_constants();
|
|
|
17465
17598
|
async function dashboardCommand(config, workspacePath = process.cwd()) {
|
|
17466
17599
|
const port = config.dashboard.port ?? DEFAULT_DASHBOARD_PORT;
|
|
17467
17600
|
const spin = ora__default.default({ text: `Starting dashboard on port ${port}\u2026`, color: "magenta" }).start();
|
|
17468
|
-
const store = new MemoryStore(
|
|
17601
|
+
const store = new MemoryStore(path26__default.default.join(workspacePath, CASCADE_DB_FILE));
|
|
17469
17602
|
const server = new DashboardServer(config, store, workspacePath);
|
|
17470
17603
|
server.watchRuntimeChanges();
|
|
17471
17604
|
const gThis = globalThis;
|
|
@@ -17497,7 +17630,7 @@ init_constants();
|
|
|
17497
17630
|
function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
17498
17631
|
const identity = new commander.Command("identity").alias("id").description("Manage Cascade identities");
|
|
17499
17632
|
identity.command("list").description("List all available identities").action(() => {
|
|
17500
|
-
const store = new MemoryStore(
|
|
17633
|
+
const store = new MemoryStore(path26__default.default.join(workspacePath, CASCADE_DB_FILE));
|
|
17501
17634
|
try {
|
|
17502
17635
|
const identities = store.listIdentities();
|
|
17503
17636
|
console.log(chalk9__default.default.bold("\n Identities:"));
|
|
@@ -17517,7 +17650,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
17517
17650
|
}
|
|
17518
17651
|
});
|
|
17519
17652
|
identity.command("create <name>").description("Create a new identity").option("-d, --desc <text>", "Description of the identity").option("-s, --system <text>", "System prompt").option("--default", "Set as default identity").action((name, options) => {
|
|
17520
|
-
const store = new MemoryStore(
|
|
17653
|
+
const store = new MemoryStore(path26__default.default.join(workspacePath, CASCADE_DB_FILE));
|
|
17521
17654
|
try {
|
|
17522
17655
|
if (options.default) {
|
|
17523
17656
|
const existingDefault = store.getDefaultIdentity();
|
|
@@ -17543,7 +17676,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
17543
17676
|
}
|
|
17544
17677
|
});
|
|
17545
17678
|
identity.command("set-default <name>").description("Set an identity as default by name or ID").action((query) => {
|
|
17546
|
-
const store = new MemoryStore(
|
|
17679
|
+
const store = new MemoryStore(path26__default.default.join(workspacePath, CASCADE_DB_FILE));
|
|
17547
17680
|
try {
|
|
17548
17681
|
const identities = store.listIdentities();
|
|
17549
17682
|
const match = identities.find((i) => i.id === query || i.name.toLowerCase() === query.toLowerCase());
|
|
@@ -17671,11 +17804,11 @@ async function exportCommand(options = {}) {
|
|
|
17671
17804
|
let store;
|
|
17672
17805
|
try {
|
|
17673
17806
|
const workspacePath = options.workspacePath ?? process.cwd();
|
|
17674
|
-
const workspaceDbPath =
|
|
17675
|
-
const globalDbPath =
|
|
17807
|
+
const workspaceDbPath = path26__default.default.join(workspacePath, CASCADE_DB_FILE);
|
|
17808
|
+
const globalDbPath = path26__default.default.join(os8__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_DB_FILE);
|
|
17676
17809
|
let dbPath = globalDbPath;
|
|
17677
17810
|
try {
|
|
17678
|
-
await
|
|
17811
|
+
await fs10__default.default.access(workspaceDbPath);
|
|
17679
17812
|
dbPath = workspaceDbPath;
|
|
17680
17813
|
} catch {
|
|
17681
17814
|
}
|
|
@@ -17714,8 +17847,8 @@ async function exportCommand(options = {}) {
|
|
|
17714
17847
|
const ext = format === "json" ? ".json" : ".md";
|
|
17715
17848
|
const safeName = session.title.replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").slice(0, 60);
|
|
17716
17849
|
const defaultFile = `cascade-export-${safeName}${ext}`;
|
|
17717
|
-
const outPath = options.output ?
|
|
17718
|
-
await
|
|
17850
|
+
const outPath = options.output ? path26__default.default.resolve(options.output) : path26__default.default.join(process.cwd(), defaultFile);
|
|
17851
|
+
await fs10__default.default.writeFile(outPath, content, "utf-8");
|
|
17719
17852
|
spin.succeed(chalk9__default.default.green(`Exported to ${chalk9__default.default.white(outPath)}`));
|
|
17720
17853
|
const messageCount = Array.isArray(session.messages) ? session.messages.length : 0;
|
|
17721
17854
|
console.log();
|
|
@@ -17942,11 +18075,11 @@ async function statsCommand() {
|
|
|
17942
18075
|
dotenv__default.default.config();
|
|
17943
18076
|
function warnIfBuildIsStale() {
|
|
17944
18077
|
try {
|
|
17945
|
-
const here =
|
|
18078
|
+
const here = path26__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href))));
|
|
17946
18079
|
for (const rel of ["..", "../.."]) {
|
|
17947
|
-
const pkgPath =
|
|
17948
|
-
if (!
|
|
17949
|
-
const pkg = JSON.parse(
|
|
18080
|
+
const pkgPath = path26__default.default.join(here, rel, "package.json");
|
|
18081
|
+
if (!fs24__default.default.existsSync(pkgPath)) continue;
|
|
18082
|
+
const pkg = JSON.parse(fs24__default.default.readFileSync(pkgPath, "utf-8"));
|
|
17950
18083
|
if (pkg.name !== "cascade-ai") continue;
|
|
17951
18084
|
if (pkg.version && pkg.version !== CASCADE_VERSION) {
|
|
17952
18085
|
console.error(
|