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/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var Database = require('better-sqlite3');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var path21 = require('path');
|
|
5
|
+
var fs20 = require('fs');
|
|
6
6
|
var os6 = require('os');
|
|
7
7
|
var crypto3 = require('crypto');
|
|
8
8
|
var EventEmitter = require('events');
|
|
@@ -58,8 +58,8 @@ function _interopNamespace(e) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
var Database__default = /*#__PURE__*/_interopDefault(Database);
|
|
61
|
-
var
|
|
62
|
-
var
|
|
61
|
+
var path21__default = /*#__PURE__*/_interopDefault(path21);
|
|
62
|
+
var fs20__default = /*#__PURE__*/_interopDefault(fs20);
|
|
63
63
|
var os6__default = /*#__PURE__*/_interopDefault(os6);
|
|
64
64
|
var crypto3__default = /*#__PURE__*/_interopDefault(crypto3);
|
|
65
65
|
var EventEmitter__default = /*#__PURE__*/_interopDefault(EventEmitter);
|
|
@@ -104,12 +104,12 @@ var init_audit_logger = __esm({
|
|
|
104
104
|
constructor(workspacePath, debugMode = false) {
|
|
105
105
|
this.workspacePath = workspacePath;
|
|
106
106
|
this.debugMode = debugMode;
|
|
107
|
-
const cascadeDir =
|
|
108
|
-
if (!
|
|
109
|
-
|
|
107
|
+
const cascadeDir = path21__default.default.join(workspacePath, ".cascade");
|
|
108
|
+
if (!fs20__default.default.existsSync(cascadeDir)) {
|
|
109
|
+
fs20__default.default.mkdirSync(cascadeDir, { recursive: true });
|
|
110
110
|
}
|
|
111
|
-
this.keyPath =
|
|
112
|
-
this.dbPath =
|
|
111
|
+
this.keyPath = path21__default.default.join(cascadeDir, "audit_log.key");
|
|
112
|
+
this.dbPath = path21__default.default.join(cascadeDir, "audit_log.db");
|
|
113
113
|
this.initEncryptionKey();
|
|
114
114
|
this.db = new Database__default.default(this.dbPath);
|
|
115
115
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -139,11 +139,11 @@ var init_audit_logger = __esm({
|
|
|
139
139
|
return crypto3__default.default.createHash("sha256").update(`${prevHash}|${timestamp}|${eventType}|${tierId}|${encryptedPayload}`).digest("hex");
|
|
140
140
|
}
|
|
141
141
|
initEncryptionKey() {
|
|
142
|
-
if (
|
|
143
|
-
this.encryptionKey =
|
|
142
|
+
if (fs20__default.default.existsSync(this.keyPath)) {
|
|
143
|
+
this.encryptionKey = fs20__default.default.readFileSync(this.keyPath);
|
|
144
144
|
} else {
|
|
145
145
|
this.encryptionKey = crypto3__default.default.randomBytes(32);
|
|
146
|
-
|
|
146
|
+
fs20__default.default.writeFileSync(this.keyPath, this.encryptionKey);
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
encrypt(text) {
|
|
@@ -221,9 +221,9 @@ var init_audit_logger = __esm({
|
|
|
221
221
|
dumpDebugIfNeeded() {
|
|
222
222
|
if (!this.debugMode) return;
|
|
223
223
|
try {
|
|
224
|
-
const dumpPath =
|
|
224
|
+
const dumpPath = path21__default.default.join(os6__default.default.tmpdir(), "cascade_audit_logs_debug.json");
|
|
225
225
|
const entries = this.getAllLogs();
|
|
226
|
-
|
|
226
|
+
fs20__default.default.writeFileSync(dumpPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
227
227
|
} catch (err) {
|
|
228
228
|
console.error("Failed to dump debug audit logs", err);
|
|
229
229
|
}
|
|
@@ -236,7 +236,7 @@ var init_audit_logger = __esm({
|
|
|
236
236
|
});
|
|
237
237
|
|
|
238
238
|
// src/constants.ts
|
|
239
|
-
var CASCADE_VERSION = "0.
|
|
239
|
+
var CASCADE_VERSION = "0.18.0";
|
|
240
240
|
var CASCADE_CONFIG_DIR = ".cascade";
|
|
241
241
|
var CASCADE_MD_FILE = "CASCADE.md";
|
|
242
242
|
var CASCADE_IGNORE_FILE = ".cascadeignore";
|
|
@@ -248,6 +248,7 @@ var CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
|
|
|
248
248
|
var GLOBAL_CONFIG_DIR = ".cascade-ai";
|
|
249
249
|
var GLOBAL_DB_FILE = "memory.db";
|
|
250
250
|
var GLOBAL_KEYSTORE_FILE = "keystore.enc";
|
|
251
|
+
var GLOBAL_CREDENTIALS_FILE = "credentials.json";
|
|
251
252
|
var GLOBAL_RUNTIME_DB_FILE = "runtime.db";
|
|
252
253
|
var DEFAULT_DASHBOARD_PORT = 4891;
|
|
253
254
|
var DEFAULT_API_PORT = 4892;
|
|
@@ -2210,7 +2211,7 @@ function computeDelegationSavings(stats, t1Model) {
|
|
|
2210
2211
|
var DEFAULT_SNAPSHOT_URL = "https://raw.githubusercontent.com/Varun-SV/Cascade-AI/main/src/core/router/benchmark-data.json";
|
|
2211
2212
|
var OPENROUTER_MODELS_URL = "https://openrouter.ai/api/v1/models";
|
|
2212
2213
|
var FETCH_TIMEOUT_MS = 8e3;
|
|
2213
|
-
var DEFAULT_CACHE_FILE =
|
|
2214
|
+
var DEFAULT_CACHE_FILE = path21__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, "benchmarks-cache.json");
|
|
2214
2215
|
function normalizeModelId(id) {
|
|
2215
2216
|
let s = id.toLowerCase();
|
|
2216
2217
|
const slash = s.lastIndexOf("/");
|
|
@@ -2355,7 +2356,7 @@ var LiveDataProvider = class {
|
|
|
2355
2356
|
}
|
|
2356
2357
|
async saveCache() {
|
|
2357
2358
|
try {
|
|
2358
|
-
await fs4__default.default.mkdir(
|
|
2359
|
+
await fs4__default.default.mkdir(path21__default.default.dirname(this.opts.cacheFile), { recursive: true });
|
|
2359
2360
|
const cache = {
|
|
2360
2361
|
fetchedAt: this.fetchedAt,
|
|
2361
2362
|
snapshot: this.snapshot ?? void 0,
|
|
@@ -4258,8 +4259,8 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : "") + textToolSuffix,
|
|
|
4258
4259
|
tierId: this.id,
|
|
4259
4260
|
sessionId: this.taskId,
|
|
4260
4261
|
requireApproval: false,
|
|
4261
|
-
saveSnapshot: async (
|
|
4262
|
-
this.store?.addFileSnapshot(this.taskId,
|
|
4262
|
+
saveSnapshot: async (path22, content) => {
|
|
4263
|
+
this.store?.addFileSnapshot(this.taskId, path22, content);
|
|
4263
4264
|
},
|
|
4264
4265
|
sendPeerSync: (to, syncType, content) => {
|
|
4265
4266
|
this.peerBus?.send(this.id, to, syncType, this.assignment?.subtaskId ?? "", content);
|
|
@@ -4429,7 +4430,7 @@ ${assignment.expectedOutput}`;
|
|
|
4429
4430
|
const { promisify: promisify4 } = await import('util');
|
|
4430
4431
|
const execAsync2 = promisify4(exec2);
|
|
4431
4432
|
for (const artifactPath of artifactPaths) {
|
|
4432
|
-
const absolutePath =
|
|
4433
|
+
const absolutePath = path21__default.default.resolve(process.cwd(), artifactPath);
|
|
4433
4434
|
try {
|
|
4434
4435
|
const stat = await fs4__default.default.stat(absolutePath);
|
|
4435
4436
|
if (!stat.isFile()) {
|
|
@@ -4450,7 +4451,7 @@ ${assignment.expectedOutput}`;
|
|
|
4450
4451
|
issues.push(`PDF artifact looks too small to be valid: ${artifactPath}`);
|
|
4451
4452
|
continue;
|
|
4452
4453
|
}
|
|
4453
|
-
const ext =
|
|
4454
|
+
const ext = path21__default.default.extname(absolutePath).toLowerCase();
|
|
4454
4455
|
try {
|
|
4455
4456
|
if (ext === ".ts" || ext === ".tsx") {
|
|
4456
4457
|
await execAsync2(`npx tsc --noEmit ${absolutePath}`, { timeout: 1e4 });
|
|
@@ -6532,16 +6533,16 @@ function resolveInWorkspace(workspaceRoot, input) {
|
|
|
6532
6533
|
if (typeof input !== "string" || input.length === 0) {
|
|
6533
6534
|
throw new WorkspaceSandboxError(String(input), workspaceRoot);
|
|
6534
6535
|
}
|
|
6535
|
-
const root =
|
|
6536
|
-
const abs =
|
|
6537
|
-
const rel =
|
|
6538
|
-
if (rel === "" || rel === ".") ; else if (rel.startsWith("..") ||
|
|
6536
|
+
const root = path21__default.default.resolve(workspaceRoot);
|
|
6537
|
+
const abs = path21__default.default.isAbsolute(input) ? path21__default.default.resolve(input) : path21__default.default.resolve(root, input);
|
|
6538
|
+
const rel = path21__default.default.relative(root, abs);
|
|
6539
|
+
if (rel === "" || rel === ".") ; else if (rel.startsWith("..") || path21__default.default.isAbsolute(rel)) {
|
|
6539
6540
|
throw new WorkspaceSandboxError(input, root);
|
|
6540
6541
|
}
|
|
6541
6542
|
try {
|
|
6542
|
-
const real =
|
|
6543
|
-
const realRel =
|
|
6544
|
-
if (realRel !== "" && realRel !== "." && (realRel.startsWith("..") ||
|
|
6543
|
+
const real = fs20__default.default.realpathSync(abs);
|
|
6544
|
+
const realRel = path21__default.default.relative(root, real);
|
|
6545
|
+
if (realRel !== "" && realRel !== "." && (realRel.startsWith("..") || path21__default.default.isAbsolute(realRel))) {
|
|
6545
6546
|
throw new WorkspaceSandboxError(input, root);
|
|
6546
6547
|
}
|
|
6547
6548
|
} catch (e) {
|
|
@@ -6602,7 +6603,7 @@ var FileWriteTool = class extends BaseTool {
|
|
|
6602
6603
|
} catch {
|
|
6603
6604
|
}
|
|
6604
6605
|
}
|
|
6605
|
-
await fs4__default.default.mkdir(
|
|
6606
|
+
await fs4__default.default.mkdir(path21__default.default.dirname(absPath), { recursive: true });
|
|
6606
6607
|
await fs4__default.default.writeFile(absPath, content, "utf-8");
|
|
6607
6608
|
return `Written ${content.length} characters to ${filePath}`;
|
|
6608
6609
|
}
|
|
@@ -7100,7 +7101,7 @@ var ImageAnalyzeTool = class extends BaseTool {
|
|
|
7100
7101
|
};
|
|
7101
7102
|
async function fileToImageAttachment(filePath) {
|
|
7102
7103
|
const data = await fs4__default.default.readFile(filePath);
|
|
7103
|
-
const ext =
|
|
7104
|
+
const ext = path21__default.default.extname(filePath).toLowerCase();
|
|
7104
7105
|
const mimeMap = {
|
|
7105
7106
|
".jpg": "image/jpeg",
|
|
7106
7107
|
".jpeg": "image/jpeg",
|
|
@@ -7134,14 +7135,14 @@ var PDFCreateTool = class extends BaseTool {
|
|
|
7134
7135
|
const filePath = input["path"];
|
|
7135
7136
|
const content = input["content"];
|
|
7136
7137
|
const title = input["title"];
|
|
7137
|
-
const dir =
|
|
7138
|
-
if (!
|
|
7139
|
-
|
|
7138
|
+
const dir = path21__default.default.dirname(filePath);
|
|
7139
|
+
if (!fs20__default.default.existsSync(dir)) {
|
|
7140
|
+
fs20__default.default.mkdirSync(dir, { recursive: true });
|
|
7140
7141
|
}
|
|
7141
7142
|
return new Promise((resolve, reject) => {
|
|
7142
7143
|
try {
|
|
7143
7144
|
const doc = new PDFDocument__default.default({ margin: 50 });
|
|
7144
|
-
const stream =
|
|
7145
|
+
const stream = fs20__default.default.createWriteStream(filePath);
|
|
7145
7146
|
doc.pipe(stream);
|
|
7146
7147
|
if (title) {
|
|
7147
7148
|
doc.info["Title"] = title;
|
|
@@ -7219,22 +7220,22 @@ var CodeInterpreterTool = class extends BaseTool {
|
|
|
7219
7220
|
}
|
|
7220
7221
|
cmdPrefix = NODE_CMD;
|
|
7221
7222
|
}
|
|
7222
|
-
const tmpDir =
|
|
7223
|
-
if (!
|
|
7224
|
-
|
|
7223
|
+
const tmpDir = path21__default.default.join(this.workspaceRoot, ".cascade", "tmp");
|
|
7224
|
+
if (!fs20__default.default.existsSync(tmpDir)) {
|
|
7225
|
+
fs20__default.default.mkdirSync(tmpDir, { recursive: true });
|
|
7225
7226
|
}
|
|
7226
7227
|
const extension = language === "python" ? "py" : "js";
|
|
7227
7228
|
const fileName = `intp_${crypto3.randomUUID().slice(0, 8)}.${extension}`;
|
|
7228
|
-
const filePath =
|
|
7229
|
-
|
|
7229
|
+
const filePath = path21__default.default.join(tmpDir, fileName);
|
|
7230
|
+
fs20__default.default.writeFileSync(filePath, code, "utf-8");
|
|
7230
7231
|
const execArgs = [filePath, ...args];
|
|
7231
7232
|
return new Promise((resolve) => {
|
|
7232
7233
|
const startMs = Date.now();
|
|
7233
7234
|
child_process.execFile(cmdPrefix, execArgs, { cwd: this.workspaceRoot, timeout: 3e4 }, (error, stdout, stderr) => {
|
|
7234
7235
|
const duration = Date.now() - startMs;
|
|
7235
7236
|
try {
|
|
7236
|
-
if (
|
|
7237
|
-
|
|
7237
|
+
if (fs20__default.default.existsSync(filePath)) {
|
|
7238
|
+
fs20__default.default.unlinkSync(filePath);
|
|
7238
7239
|
}
|
|
7239
7240
|
} catch (cleanupErr) {
|
|
7240
7241
|
console.error(`Failed to cleanup interpreter script ${filePath}:`, cleanupErr);
|
|
@@ -7513,7 +7514,7 @@ var GlobTool = class extends BaseTool {
|
|
|
7513
7514
|
};
|
|
7514
7515
|
async execute(input, _options) {
|
|
7515
7516
|
const pattern = input["pattern"];
|
|
7516
|
-
const searchPath = input["path"] ?
|
|
7517
|
+
const searchPath = input["path"] ? path21__default.default.resolve(this.workspaceRoot, input["path"]) : this.workspaceRoot;
|
|
7517
7518
|
const matches = await glob.glob(pattern, {
|
|
7518
7519
|
cwd: searchPath,
|
|
7519
7520
|
ignore: ["node_modules/**", ".git/**", "dist/**", "build/**"],
|
|
@@ -7526,7 +7527,7 @@ var GlobTool = class extends BaseTool {
|
|
|
7526
7527
|
const withMtime = await Promise.all(
|
|
7527
7528
|
matches.map(async (rel) => {
|
|
7528
7529
|
try {
|
|
7529
|
-
const stat = await fs4__default.default.stat(
|
|
7530
|
+
const stat = await fs4__default.default.stat(path21__default.default.join(searchPath, rel));
|
|
7530
7531
|
return { rel, mtime: stat.mtimeMs };
|
|
7531
7532
|
} catch {
|
|
7532
7533
|
return { rel, mtime: 0 };
|
|
@@ -7575,7 +7576,7 @@ var GrepTool = class extends BaseTool {
|
|
|
7575
7576
|
};
|
|
7576
7577
|
async execute(input, _options) {
|
|
7577
7578
|
const pattern = input["pattern"];
|
|
7578
|
-
const searchPath = input["path"] ?
|
|
7579
|
+
const searchPath = input["path"] ? path21__default.default.resolve(this.workspaceRoot, input["path"]) : this.workspaceRoot;
|
|
7579
7580
|
const globPattern = input["glob"];
|
|
7580
7581
|
const outputMode = input["output_mode"] ?? "content";
|
|
7581
7582
|
const context = input["context"] ?? 0;
|
|
@@ -7629,12 +7630,12 @@ var GrepTool = class extends BaseTool {
|
|
|
7629
7630
|
nodir: true
|
|
7630
7631
|
});
|
|
7631
7632
|
} catch {
|
|
7632
|
-
files = [
|
|
7633
|
+
files = [path21__default.default.relative(searchPath, searchPath) || "."];
|
|
7633
7634
|
}
|
|
7634
7635
|
const results = [];
|
|
7635
7636
|
let totalCount = 0;
|
|
7636
7637
|
for (const rel of files) {
|
|
7637
|
-
const abs =
|
|
7638
|
+
const abs = path21__default.default.join(searchPath, rel);
|
|
7638
7639
|
let content;
|
|
7639
7640
|
try {
|
|
7640
7641
|
content = await fs4__default.default.readFile(abs, "utf-8");
|
|
@@ -7996,10 +7997,10 @@ var ToolRegistry = class extends EventEmitter__default.default {
|
|
|
7996
7997
|
}
|
|
7997
7998
|
isIgnored(filePath) {
|
|
7998
7999
|
if (!filePath) return false;
|
|
7999
|
-
const abs =
|
|
8000
|
-
const rel =
|
|
8001
|
-
if (!rel || rel.startsWith("..") ||
|
|
8002
|
-
const posixRel = rel.split(
|
|
8000
|
+
const abs = path21__default.default.resolve(this.workspaceRoot, filePath);
|
|
8001
|
+
const rel = path21__default.default.relative(this.workspaceRoot, abs);
|
|
8002
|
+
if (!rel || rel.startsWith("..") || path21__default.default.isAbsolute(rel)) return true;
|
|
8003
|
+
const posixRel = rel.split(path21__default.default.sep).join("/");
|
|
8003
8004
|
return this.ignoreMatcher.ignores(posixRel);
|
|
8004
8005
|
}
|
|
8005
8006
|
};
|
|
@@ -8833,7 +8834,7 @@ var TaskAnalyzer = class {
|
|
|
8833
8834
|
analysisCache.clear();
|
|
8834
8835
|
}
|
|
8835
8836
|
};
|
|
8836
|
-
var DEFAULT_STATS_FILE =
|
|
8837
|
+
var DEFAULT_STATS_FILE = path21__default.default.join(os6__default.default.homedir(), ".cascade", "model-perf.json");
|
|
8837
8838
|
var ModelPerformanceTracker = class {
|
|
8838
8839
|
stats = /* @__PURE__ */ new Map();
|
|
8839
8840
|
featureStats = /* @__PURE__ */ new Map();
|
|
@@ -8865,7 +8866,7 @@ var ModelPerformanceTracker = class {
|
|
|
8865
8866
|
}
|
|
8866
8867
|
async save() {
|
|
8867
8868
|
try {
|
|
8868
|
-
await fs4__default.default.mkdir(
|
|
8869
|
+
await fs4__default.default.mkdir(path21__default.default.dirname(this.statsFile), { recursive: true });
|
|
8869
8870
|
const modelsObj = {};
|
|
8870
8871
|
const featuresObj = {};
|
|
8871
8872
|
for (const [key, stat] of this.stats) modelsObj[key] = stat;
|
|
@@ -9404,7 +9405,7 @@ Required capability: ${description.slice(0, 300)}`;
|
|
|
9404
9405
|
* any dangerous action, so a silently-reloaded tool can't act without approval. */
|
|
9405
9406
|
async loadPersistedTools() {
|
|
9406
9407
|
if (!this.workspacePath || !this.persistEnabled) return;
|
|
9407
|
-
const file =
|
|
9408
|
+
const file = path21__default.default.join(this.workspacePath, ".cascade", DYNAMIC_TOOLS_FILE);
|
|
9408
9409
|
try {
|
|
9409
9410
|
const raw = await fs4__default.default.readFile(file, "utf-8");
|
|
9410
9411
|
const specs = JSON.parse(raw);
|
|
@@ -9428,8 +9429,8 @@ Required capability: ${description.slice(0, 300)}`;
|
|
|
9428
9429
|
}
|
|
9429
9430
|
async persist() {
|
|
9430
9431
|
if (!this.workspacePath || !this.persistEnabled) return;
|
|
9431
|
-
const dir =
|
|
9432
|
-
const file =
|
|
9432
|
+
const dir = path21__default.default.join(this.workspacePath, ".cascade");
|
|
9433
|
+
const file = path21__default.default.join(dir, DYNAMIC_TOOLS_FILE);
|
|
9433
9434
|
try {
|
|
9434
9435
|
await fs4__default.default.mkdir(dir, { recursive: true });
|
|
9435
9436
|
await fs4__default.default.writeFile(file, JSON.stringify(Array.from(this.specs.values()), null, 2), "utf-8");
|
|
@@ -9449,12 +9450,12 @@ var WorldStateDB = class {
|
|
|
9449
9450
|
constructor(workspacePath, debugMode = false) {
|
|
9450
9451
|
this.workspacePath = workspacePath;
|
|
9451
9452
|
this.debugMode = debugMode;
|
|
9452
|
-
const cascadeDir =
|
|
9453
|
-
if (!
|
|
9454
|
-
|
|
9453
|
+
const cascadeDir = path21__default.default.join(workspacePath, ".cascade");
|
|
9454
|
+
if (!fs20__default.default.existsSync(cascadeDir)) {
|
|
9455
|
+
fs20__default.default.mkdirSync(cascadeDir, { recursive: true });
|
|
9455
9456
|
}
|
|
9456
|
-
this.keyPath =
|
|
9457
|
-
this.dbPath =
|
|
9457
|
+
this.keyPath = path21__default.default.join(cascadeDir, "world_state.key");
|
|
9458
|
+
this.dbPath = path21__default.default.join(cascadeDir, "world_state.db");
|
|
9458
9459
|
this.initEncryptionKey();
|
|
9459
9460
|
this.db = new Database__default.default(this.dbPath);
|
|
9460
9461
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -9484,11 +9485,11 @@ var WorldStateDB = class {
|
|
|
9484
9485
|
dbPath;
|
|
9485
9486
|
encryptionKey;
|
|
9486
9487
|
initEncryptionKey() {
|
|
9487
|
-
if (
|
|
9488
|
-
this.encryptionKey =
|
|
9488
|
+
if (fs20__default.default.existsSync(this.keyPath)) {
|
|
9489
|
+
this.encryptionKey = fs20__default.default.readFileSync(this.keyPath);
|
|
9489
9490
|
} else {
|
|
9490
9491
|
this.encryptionKey = crypto3__default.default.randomBytes(32);
|
|
9491
|
-
|
|
9492
|
+
fs20__default.default.writeFileSync(this.keyPath, this.encryptionKey);
|
|
9492
9493
|
}
|
|
9493
9494
|
}
|
|
9494
9495
|
encrypt(text) {
|
|
@@ -9629,6 +9630,22 @@ var WorldStateDB = class {
|
|
|
9629
9630
|
}
|
|
9630
9631
|
return selected.slice(0, limit).map((f) => `- ${f.entity} ${f.relation} ${f.value}`).join("\n");
|
|
9631
9632
|
}
|
|
9633
|
+
/**
|
|
9634
|
+
* Delete one fact by its (normalized) entity + relation key. Returns whether
|
|
9635
|
+
* a row was actually removed. Powers the desktop Knowledge tab's per-fact
|
|
9636
|
+
* delete — users can prune what the planner remembers about their project.
|
|
9637
|
+
*/
|
|
9638
|
+
deleteFact(entity, relation) {
|
|
9639
|
+
const e = normalizeKey(entity);
|
|
9640
|
+
const r = normalizeKey(relation);
|
|
9641
|
+
if (!e || !r) return false;
|
|
9642
|
+
const result = this.db.prepare("DELETE FROM facts WHERE entity = ? AND relation = ?").run(e, r);
|
|
9643
|
+
return result.changes > 0;
|
|
9644
|
+
}
|
|
9645
|
+
/** Delete every fact. Returns how many were removed. */
|
|
9646
|
+
clearFacts() {
|
|
9647
|
+
return this.db.prepare("DELETE FROM facts").run().changes;
|
|
9648
|
+
}
|
|
9632
9649
|
// ── Export / Import ──────────────────────────
|
|
9633
9650
|
//
|
|
9634
9651
|
// Knowledge travels DECRYPTED in the export bundle (a portable plaintext
|
|
@@ -9677,9 +9694,9 @@ var WorldStateDB = class {
|
|
|
9677
9694
|
dumpDebugIfNeeded() {
|
|
9678
9695
|
if (!this.debugMode) return;
|
|
9679
9696
|
try {
|
|
9680
|
-
const dumpPath =
|
|
9697
|
+
const dumpPath = path21__default.default.join(os6__default.default.tmpdir(), "cascade_world_state_debug.json");
|
|
9681
9698
|
const entries = this.getAllEntries();
|
|
9682
|
-
|
|
9699
|
+
fs20__default.default.writeFileSync(dumpPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
9683
9700
|
} catch (err) {
|
|
9684
9701
|
console.error("Failed to dump debug world state", err);
|
|
9685
9702
|
}
|
|
@@ -10589,7 +10606,7 @@ var Keystore = class {
|
|
|
10589
10606
|
const creds = await this.keytar.findCredentials(KEYTAR_SERVICE);
|
|
10590
10607
|
this.cache = Object.fromEntries(creds.map((c) => [c.account, c.password]));
|
|
10591
10608
|
this.backend = "keytar";
|
|
10592
|
-
if (password &&
|
|
10609
|
+
if (password && fs20__default.default.existsSync(this.storePath)) {
|
|
10593
10610
|
try {
|
|
10594
10611
|
const fileEntries = this.decryptFile(password);
|
|
10595
10612
|
for (const [k, v] of Object.entries(fileEntries)) {
|
|
@@ -10608,7 +10625,7 @@ var Keystore = class {
|
|
|
10608
10625
|
"Keystore unlock requires a password because the OS keychain (keytar) is not available on this system."
|
|
10609
10626
|
);
|
|
10610
10627
|
}
|
|
10611
|
-
if (!
|
|
10628
|
+
if (!fs20__default.default.existsSync(this.storePath)) {
|
|
10612
10629
|
const salt = crypto3__default.default.randomBytes(SALT_LEN);
|
|
10613
10630
|
this.masterKey = this.deriveKey(password, salt);
|
|
10614
10631
|
this.writeWithSalt({}, salt);
|
|
@@ -10622,7 +10639,7 @@ var Keystore = class {
|
|
|
10622
10639
|
}
|
|
10623
10640
|
/** Synchronous legacy unlock kept for AES-only environments. */
|
|
10624
10641
|
unlockSync(password) {
|
|
10625
|
-
if (!
|
|
10642
|
+
if (!fs20__default.default.existsSync(this.storePath)) {
|
|
10626
10643
|
const salt = crypto3__default.default.randomBytes(SALT_LEN);
|
|
10627
10644
|
this.masterKey = this.deriveKey(password, salt);
|
|
10628
10645
|
this.writeWithSalt({}, salt);
|
|
@@ -10680,7 +10697,7 @@ var Keystore = class {
|
|
|
10680
10697
|
}
|
|
10681
10698
|
}
|
|
10682
10699
|
decryptFile(password, knownSalt) {
|
|
10683
|
-
if (!
|
|
10700
|
+
if (!fs20__default.default.existsSync(this.storePath)) return {};
|
|
10684
10701
|
try {
|
|
10685
10702
|
const { salt, ciphertext, iv, tag } = this.readRaw();
|
|
10686
10703
|
const useSalt = knownSalt ?? salt;
|
|
@@ -10702,8 +10719,8 @@ var Keystore = class {
|
|
|
10702
10719
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
10703
10720
|
const tag = cipher.getAuthTag();
|
|
10704
10721
|
const out = Buffer.concat([raw.salt, iv, tag, ciphertext]);
|
|
10705
|
-
|
|
10706
|
-
|
|
10722
|
+
fs20__default.default.mkdirSync(path21__default.default.dirname(this.storePath), { recursive: true });
|
|
10723
|
+
fs20__default.default.writeFileSync(this.storePath, out, { mode: 384 });
|
|
10707
10724
|
}
|
|
10708
10725
|
writeWithSalt(data, salt) {
|
|
10709
10726
|
if (!this.masterKey) throw new Error("writeWithSalt called before masterKey was set");
|
|
@@ -10713,11 +10730,11 @@ var Keystore = class {
|
|
|
10713
10730
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
10714
10731
|
const tag = cipher.getAuthTag();
|
|
10715
10732
|
const out = Buffer.concat([salt, iv, tag, ciphertext]);
|
|
10716
|
-
|
|
10717
|
-
|
|
10733
|
+
fs20__default.default.mkdirSync(path21__default.default.dirname(this.storePath), { recursive: true });
|
|
10734
|
+
fs20__default.default.writeFileSync(this.storePath, out, { mode: 384 });
|
|
10718
10735
|
}
|
|
10719
10736
|
readRaw() {
|
|
10720
|
-
const buf =
|
|
10737
|
+
const buf = fs20__default.default.readFileSync(this.storePath);
|
|
10721
10738
|
let offset = 0;
|
|
10722
10739
|
const salt = buf.subarray(offset, offset + SALT_LEN);
|
|
10723
10740
|
offset += SALT_LEN;
|
|
@@ -10750,7 +10767,7 @@ var CascadeIgnore = class {
|
|
|
10750
10767
|
]);
|
|
10751
10768
|
}
|
|
10752
10769
|
async load(workspacePath) {
|
|
10753
|
-
const filePath =
|
|
10770
|
+
const filePath = path21__default.default.join(workspacePath, ".cascadeignore");
|
|
10754
10771
|
try {
|
|
10755
10772
|
const content = await fs4__default.default.readFile(filePath, "utf-8");
|
|
10756
10773
|
const lines = content.split("\n").filter((l) => l.trim() && !l.startsWith("#"));
|
|
@@ -10761,7 +10778,7 @@ var CascadeIgnore = class {
|
|
|
10761
10778
|
}
|
|
10762
10779
|
isIgnored(filePath, workspacePath) {
|
|
10763
10780
|
try {
|
|
10764
|
-
const relative = workspacePath ?
|
|
10781
|
+
const relative = workspacePath ? path21__default.default.relative(workspacePath, filePath) : filePath;
|
|
10765
10782
|
return this.ig.ignores(relative);
|
|
10766
10783
|
} catch {
|
|
10767
10784
|
return false;
|
|
@@ -10772,7 +10789,7 @@ var CascadeIgnore = class {
|
|
|
10772
10789
|
}
|
|
10773
10790
|
};
|
|
10774
10791
|
async function loadCascadeMd(workspacePath) {
|
|
10775
|
-
const filePath =
|
|
10792
|
+
const filePath = path21__default.default.join(workspacePath, "CASCADE.md");
|
|
10776
10793
|
try {
|
|
10777
10794
|
const raw = await fs4__default.default.readFile(filePath, "utf-8");
|
|
10778
10795
|
return parseCascadeMd(raw);
|
|
@@ -10803,7 +10820,7 @@ ${raw.trim()}`;
|
|
|
10803
10820
|
var MemoryStore = class _MemoryStore {
|
|
10804
10821
|
db;
|
|
10805
10822
|
constructor(dbPath) {
|
|
10806
|
-
|
|
10823
|
+
fs20__default.default.mkdirSync(path21__default.default.dirname(dbPath), { recursive: true });
|
|
10807
10824
|
try {
|
|
10808
10825
|
this.db = new Database__default.default(dbPath, { timeout: 5e3 });
|
|
10809
10826
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -11638,6 +11655,60 @@ Original error: ${err.message}`
|
|
|
11638
11655
|
};
|
|
11639
11656
|
}
|
|
11640
11657
|
};
|
|
11658
|
+
function credentialsPath(globalDir) {
|
|
11659
|
+
return path21__default.default.join(globalDir, GLOBAL_CREDENTIALS_FILE);
|
|
11660
|
+
}
|
|
11661
|
+
function providerKey(p) {
|
|
11662
|
+
if (p.type === "azure") {
|
|
11663
|
+
return `azure:${p.deploymentName ?? p.baseUrl ?? p.label ?? ""}`;
|
|
11664
|
+
}
|
|
11665
|
+
return p.type;
|
|
11666
|
+
}
|
|
11667
|
+
function isPersistable(p) {
|
|
11668
|
+
return Boolean(p.apiKey || p.authToken || p.type === "azure" || p.baseUrl);
|
|
11669
|
+
}
|
|
11670
|
+
function loadGlobalCredentials(globalDir) {
|
|
11671
|
+
try {
|
|
11672
|
+
const raw = fs20__default.default.readFileSync(credentialsPath(globalDir), "utf-8");
|
|
11673
|
+
const parsed = JSON.parse(raw);
|
|
11674
|
+
if (!Array.isArray(parsed.providers)) return [];
|
|
11675
|
+
return parsed.providers.filter(
|
|
11676
|
+
(p) => Boolean(p) && typeof p.type === "string"
|
|
11677
|
+
);
|
|
11678
|
+
} catch {
|
|
11679
|
+
return [];
|
|
11680
|
+
}
|
|
11681
|
+
}
|
|
11682
|
+
function saveGlobalCredentials(globalDir, providers) {
|
|
11683
|
+
const filePath = credentialsPath(globalDir);
|
|
11684
|
+
fs20__default.default.mkdirSync(globalDir, { recursive: true, mode: 448 });
|
|
11685
|
+
const body = { version: 1, providers: providers.filter(isPersistable) };
|
|
11686
|
+
const tmp = `${filePath}.tmp`;
|
|
11687
|
+
fs20__default.default.writeFileSync(tmp, JSON.stringify(body, null, 2), { encoding: "utf-8", mode: 384 });
|
|
11688
|
+
fs20__default.default.renameSync(tmp, filePath);
|
|
11689
|
+
try {
|
|
11690
|
+
fs20__default.default.chmodSync(filePath, 384);
|
|
11691
|
+
} catch {
|
|
11692
|
+
}
|
|
11693
|
+
}
|
|
11694
|
+
function mergeGlobalCredentials(workspaceProviders, globalProviders) {
|
|
11695
|
+
const merged = [...workspaceProviders];
|
|
11696
|
+
const byKey = new Map(merged.map((p) => [providerKey(p), p]));
|
|
11697
|
+
for (const g of globalProviders) {
|
|
11698
|
+
const existing = byKey.get(providerKey(g));
|
|
11699
|
+
if (!existing) {
|
|
11700
|
+
merged.push({ ...g });
|
|
11701
|
+
byKey.set(providerKey(g), merged[merged.length - 1]);
|
|
11702
|
+
continue;
|
|
11703
|
+
}
|
|
11704
|
+
if (!existing.apiKey && g.apiKey) existing.apiKey = g.apiKey;
|
|
11705
|
+
if (!existing.authToken && g.authToken) existing.authToken = g.authToken;
|
|
11706
|
+
if (!existing.baseUrl && g.baseUrl) existing.baseUrl = g.baseUrl;
|
|
11707
|
+
if (!existing.apiVersion && g.apiVersion) existing.apiVersion = g.apiVersion;
|
|
11708
|
+
if (!existing.label && g.label) existing.label = g.label;
|
|
11709
|
+
}
|
|
11710
|
+
return merged;
|
|
11711
|
+
}
|
|
11641
11712
|
|
|
11642
11713
|
// src/config/index.ts
|
|
11643
11714
|
var ConfigManager = class {
|
|
@@ -11648,18 +11719,20 @@ var ConfigManager = class {
|
|
|
11648
11719
|
cascadeMd = null;
|
|
11649
11720
|
workspacePath;
|
|
11650
11721
|
globalDir;
|
|
11651
|
-
|
|
11722
|
+
/** `globalDirOverride` exists for tests — never point it at the real home dir there. */
|
|
11723
|
+
constructor(workspacePath = process.cwd(), globalDirOverride) {
|
|
11652
11724
|
this.workspacePath = workspacePath;
|
|
11653
|
-
this.globalDir =
|
|
11725
|
+
this.globalDir = globalDirOverride ?? path21__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR);
|
|
11654
11726
|
}
|
|
11655
11727
|
async load() {
|
|
11656
11728
|
this.config = await this.loadConfig();
|
|
11657
11729
|
this.ignore = new CascadeIgnore();
|
|
11658
11730
|
await this.ignore.load(this.workspacePath);
|
|
11659
11731
|
this.cascadeMd = await loadCascadeMd(this.workspacePath);
|
|
11660
|
-
this.keystore = new Keystore(
|
|
11661
|
-
this.store = new MemoryStore(
|
|
11732
|
+
this.keystore = new Keystore(path21__default.default.join(this.globalDir, GLOBAL_KEYSTORE_FILE));
|
|
11733
|
+
this.store = new MemoryStore(path21__default.default.join(this.workspacePath, CASCADE_DB_FILE));
|
|
11662
11734
|
await this.injectEnvKeys();
|
|
11735
|
+
this.config.providers = mergeGlobalCredentials(this.config.providers, loadGlobalCredentials(this.globalDir));
|
|
11663
11736
|
await this.ensureDefaultIdentity();
|
|
11664
11737
|
}
|
|
11665
11738
|
getConfig() {
|
|
@@ -11681,9 +11754,14 @@ var ConfigManager = class {
|
|
|
11681
11754
|
return this.workspacePath;
|
|
11682
11755
|
}
|
|
11683
11756
|
async save() {
|
|
11684
|
-
const configPath =
|
|
11685
|
-
await fs4__default.default.mkdir(
|
|
11757
|
+
const configPath = path21__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
11758
|
+
await fs4__default.default.mkdir(path21__default.default.dirname(configPath), { recursive: true });
|
|
11686
11759
|
await fs4__default.default.writeFile(configPath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
11760
|
+
try {
|
|
11761
|
+
saveGlobalCredentials(this.globalDir, this.config.providers);
|
|
11762
|
+
} catch (err) {
|
|
11763
|
+
console.warn(`Failed to sync credentials to global store: ${err instanceof Error ? err.message : String(err)}`);
|
|
11764
|
+
}
|
|
11687
11765
|
}
|
|
11688
11766
|
async updateConfig(updates) {
|
|
11689
11767
|
this.config = validateConfig({ ...this.config, ...updates });
|
|
@@ -11706,7 +11784,7 @@ var ConfigManager = class {
|
|
|
11706
11784
|
return configProvider?.apiKey;
|
|
11707
11785
|
}
|
|
11708
11786
|
async loadConfig() {
|
|
11709
|
-
const configPath =
|
|
11787
|
+
const configPath = path21__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
11710
11788
|
try {
|
|
11711
11789
|
const raw = await fs4__default.default.readFile(configPath, "utf-8");
|
|
11712
11790
|
return validateConfig(JSON.parse(raw));
|
|
@@ -11813,6 +11891,11 @@ function authMiddleware(secret, required = true) {
|
|
|
11813
11891
|
}
|
|
11814
11892
|
const user = verifyToken(token, secret);
|
|
11815
11893
|
if (!user) {
|
|
11894
|
+
if (!required) {
|
|
11895
|
+
req.user = void 0;
|
|
11896
|
+
next();
|
|
11897
|
+
return;
|
|
11898
|
+
}
|
|
11816
11899
|
res.status(401).json({ error: "Invalid or expired token" });
|
|
11817
11900
|
return;
|
|
11818
11901
|
}
|
|
@@ -12121,7 +12204,7 @@ function aggregateCostStats(sessions, opts = {}) {
|
|
|
12121
12204
|
}
|
|
12122
12205
|
|
|
12123
12206
|
// src/dashboard/server.ts
|
|
12124
|
-
var __dirname$1 =
|
|
12207
|
+
var __dirname$1 = path21__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
12125
12208
|
var DashboardServer = class {
|
|
12126
12209
|
app;
|
|
12127
12210
|
httpServer;
|
|
@@ -12355,12 +12438,17 @@ var DashboardServer = class {
|
|
|
12355
12438
|
*/
|
|
12356
12439
|
persistConfig() {
|
|
12357
12440
|
try {
|
|
12358
|
-
const configPath =
|
|
12359
|
-
|
|
12360
|
-
|
|
12441
|
+
const configPath = path21__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
12442
|
+
fs20__default.default.mkdirSync(path21__default.default.dirname(configPath), { recursive: true });
|
|
12443
|
+
fs20__default.default.writeFileSync(configPath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
12361
12444
|
} catch (err) {
|
|
12362
12445
|
console.warn(`[dashboard] Failed to persist config: ${err instanceof Error ? err.message : String(err)}`);
|
|
12363
12446
|
}
|
|
12447
|
+
try {
|
|
12448
|
+
saveGlobalCredentials(path21__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR), this.config.providers ?? []);
|
|
12449
|
+
} catch (err) {
|
|
12450
|
+
console.warn(`[dashboard] Failed to sync global credentials: ${err instanceof Error ? err.message : String(err)}`);
|
|
12451
|
+
}
|
|
12364
12452
|
}
|
|
12365
12453
|
/**
|
|
12366
12454
|
* Produce a stable dashboard JWT signing secret.
|
|
@@ -12372,15 +12460,15 @@ var DashboardServer = class {
|
|
|
12372
12460
|
resolveDashboardSecret() {
|
|
12373
12461
|
const fromConfig = this.config.dashboard.secret ?? process.env["CASCADE_DASHBOARD_SECRET"];
|
|
12374
12462
|
if (fromConfig) return fromConfig;
|
|
12375
|
-
const secretPath =
|
|
12463
|
+
const secretPath = path21__default.default.join(this.workspacePath, CASCADE_DASHBOARD_SECRET_FILE);
|
|
12376
12464
|
try {
|
|
12377
|
-
if (
|
|
12378
|
-
const existing =
|
|
12465
|
+
if (fs20__default.default.existsSync(secretPath)) {
|
|
12466
|
+
const existing = fs20__default.default.readFileSync(secretPath, "utf-8").trim();
|
|
12379
12467
|
if (existing.length >= 16) return existing;
|
|
12380
12468
|
}
|
|
12381
12469
|
const generated = crypto3.randomUUID();
|
|
12382
|
-
|
|
12383
|
-
|
|
12470
|
+
fs20__default.default.mkdirSync(path21__default.default.dirname(secretPath), { recursive: true });
|
|
12471
|
+
fs20__default.default.writeFileSync(secretPath, generated, { encoding: "utf-8", mode: 384 });
|
|
12384
12472
|
if (this.config.dashboard.auth) {
|
|
12385
12473
|
console.warn(
|
|
12386
12474
|
`Dashboard auth enabled with no secret configured; persisted a generated secret to ${secretPath}. Set CASCADE_DASHBOARD_SECRET or config.dashboard.secret to override.`
|
|
@@ -12407,7 +12495,7 @@ var DashboardServer = class {
|
|
|
12407
12495
|
// ── Setup ─────────────────────────────────────
|
|
12408
12496
|
getGlobalStore() {
|
|
12409
12497
|
if (!this.globalStore) {
|
|
12410
|
-
const globalDbPath =
|
|
12498
|
+
const globalDbPath = path21__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
12411
12499
|
this.globalStore = new MemoryStore(globalDbPath);
|
|
12412
12500
|
}
|
|
12413
12501
|
return this.globalStore;
|
|
@@ -12676,12 +12764,12 @@ ${prompt}`;
|
|
|
12676
12764
|
}
|
|
12677
12765
|
}
|
|
12678
12766
|
watchRuntimeChanges() {
|
|
12679
|
-
const workspaceDbPath =
|
|
12680
|
-
const globalDbPath =
|
|
12767
|
+
const workspaceDbPath = path21__default.default.join(this.workspacePath, CASCADE_DB_FILE);
|
|
12768
|
+
const globalDbPath = path21__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
12681
12769
|
const watchPaths = [workspaceDbPath, globalDbPath].filter((p, index, arr) => arr.indexOf(p) === index);
|
|
12682
12770
|
for (const watchPath of watchPaths) {
|
|
12683
|
-
if (!
|
|
12684
|
-
|
|
12771
|
+
if (!fs20__default.default.existsSync(watchPath)) continue;
|
|
12772
|
+
fs20__default.default.watchFile(watchPath, { interval: 3e3 }, () => {
|
|
12685
12773
|
this.throttledBroadcast(watchPath === globalDbPath ? "global" : "workspace");
|
|
12686
12774
|
});
|
|
12687
12775
|
}
|
|
@@ -12803,7 +12891,7 @@ ${prompt}`;
|
|
|
12803
12891
|
const sessionId = req.params.id;
|
|
12804
12892
|
this.store.deleteSession(sessionId);
|
|
12805
12893
|
this.store.deleteRuntimeSession(sessionId);
|
|
12806
|
-
const globalDbPath =
|
|
12894
|
+
const globalDbPath = path21__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
12807
12895
|
const globalStore = new MemoryStore(globalDbPath);
|
|
12808
12896
|
try {
|
|
12809
12897
|
globalStore.deleteRuntimeSession(sessionId);
|
|
@@ -12896,7 +12984,7 @@ ${prompt}`;
|
|
|
12896
12984
|
});
|
|
12897
12985
|
this.app.delete("/api/sessions", auth, (req, res) => {
|
|
12898
12986
|
const body = req.body;
|
|
12899
|
-
const globalDbPath =
|
|
12987
|
+
const globalDbPath = path21__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
12900
12988
|
if (body?.ids && Array.isArray(body.ids) && body.ids.length > 0) {
|
|
12901
12989
|
const globalStore = new MemoryStore(globalDbPath);
|
|
12902
12990
|
try {
|
|
@@ -12919,7 +13007,7 @@ ${prompt}`;
|
|
|
12919
13007
|
});
|
|
12920
13008
|
this.app.delete("/api/runtime", auth, (_req, res) => {
|
|
12921
13009
|
this.store.deleteAllRuntimeNodes();
|
|
12922
|
-
const globalDbPath =
|
|
13010
|
+
const globalDbPath = path21__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
12923
13011
|
const globalStore = new MemoryStore(globalDbPath);
|
|
12924
13012
|
try {
|
|
12925
13013
|
globalStore.deleteAllRuntimeNodes();
|
|
@@ -13005,12 +13093,12 @@ ${prompt}`;
|
|
|
13005
13093
|
if (body["tierLimits"]) this.config.tierLimits = { ...this.config.tierLimits, ...body["tierLimits"] };
|
|
13006
13094
|
if (body["budget"]) this.config.budget = { ...this.config.budget, ...body["budget"] };
|
|
13007
13095
|
try {
|
|
13008
|
-
const configPath =
|
|
13009
|
-
const existing =
|
|
13096
|
+
const configPath = path21__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
13097
|
+
const existing = fs20__default.default.existsSync(configPath) ? JSON.parse(fs20__default.default.readFileSync(configPath, "utf-8")) : {};
|
|
13010
13098
|
const updated = { ...existing, tierLimits: this.config.tierLimits, budget: this.config.budget };
|
|
13011
13099
|
const tmp = configPath + ".tmp";
|
|
13012
|
-
|
|
13013
|
-
|
|
13100
|
+
fs20__default.default.writeFileSync(tmp, JSON.stringify(updated, null, 2), "utf-8");
|
|
13101
|
+
fs20__default.default.renameSync(tmp, configPath);
|
|
13014
13102
|
res.json({ ok: true });
|
|
13015
13103
|
} catch (err) {
|
|
13016
13104
|
res.status(500).json({ error: `Failed to save config: ${err instanceof Error ? err.message : String(err)}` });
|
|
@@ -13038,7 +13126,7 @@ ${prompt}`;
|
|
|
13038
13126
|
this.app.get("/api/runtime", auth, (req, res) => {
|
|
13039
13127
|
const scope = req.query["scope"] ?? "workspace";
|
|
13040
13128
|
if (scope === "global") {
|
|
13041
|
-
const globalDbPath =
|
|
13129
|
+
const globalDbPath = path21__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
13042
13130
|
const globalStore = new MemoryStore(globalDbPath);
|
|
13043
13131
|
try {
|
|
13044
13132
|
res.json({
|
|
@@ -13273,6 +13361,48 @@ ${prompt}`;
|
|
|
13273
13361
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
13274
13362
|
}
|
|
13275
13363
|
});
|
|
13364
|
+
this.app.get("/api/knowledge", auth, (_req, res) => {
|
|
13365
|
+
try {
|
|
13366
|
+
const ws = new WorldStateDB(this.workspacePath);
|
|
13367
|
+
try {
|
|
13368
|
+
const facts = ws.getAllFacts();
|
|
13369
|
+
res.json({ total: facts.length, facts });
|
|
13370
|
+
} finally {
|
|
13371
|
+
ws.close();
|
|
13372
|
+
}
|
|
13373
|
+
} catch (err) {
|
|
13374
|
+
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
13375
|
+
}
|
|
13376
|
+
});
|
|
13377
|
+
this.app.delete("/api/knowledge/fact", auth, mutationLimiter, (req, res) => {
|
|
13378
|
+
const body = req.body;
|
|
13379
|
+
if (!body.entity || !body.relation) {
|
|
13380
|
+
res.status(400).json({ error: "entity and relation are required" });
|
|
13381
|
+
return;
|
|
13382
|
+
}
|
|
13383
|
+
try {
|
|
13384
|
+
const ws = new WorldStateDB(this.workspacePath);
|
|
13385
|
+
try {
|
|
13386
|
+
res.json({ ok: true, deleted: ws.deleteFact(body.entity, body.relation) });
|
|
13387
|
+
} finally {
|
|
13388
|
+
ws.close();
|
|
13389
|
+
}
|
|
13390
|
+
} catch (err) {
|
|
13391
|
+
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
13392
|
+
}
|
|
13393
|
+
});
|
|
13394
|
+
this.app.delete("/api/knowledge", auth, mutationLimiter, (_req, res) => {
|
|
13395
|
+
try {
|
|
13396
|
+
const ws = new WorldStateDB(this.workspacePath);
|
|
13397
|
+
try {
|
|
13398
|
+
res.json({ ok: true, deleted: ws.clearFacts() });
|
|
13399
|
+
} finally {
|
|
13400
|
+
ws.close();
|
|
13401
|
+
}
|
|
13402
|
+
} catch (err) {
|
|
13403
|
+
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
13404
|
+
}
|
|
13405
|
+
});
|
|
13276
13406
|
this.app.get("/api/audit-chain", auth, async (req, res) => {
|
|
13277
13407
|
try {
|
|
13278
13408
|
const limit = Math.min(500, Math.max(1, parseInt(req.query["limit"] || "200", 10) || 200));
|
|
@@ -13291,13 +13421,13 @@ ${prompt}`;
|
|
|
13291
13421
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
13292
13422
|
}
|
|
13293
13423
|
});
|
|
13294
|
-
const prodPath =
|
|
13295
|
-
const devPath =
|
|
13296
|
-
const webDistPath =
|
|
13297
|
-
if (
|
|
13424
|
+
const prodPath = path21__default.default.resolve(__dirname$1, "../web/dist");
|
|
13425
|
+
const devPath = path21__default.default.resolve(__dirname$1, "../../web/dist");
|
|
13426
|
+
const webDistPath = fs20__default.default.existsSync(prodPath) ? prodPath : devPath;
|
|
13427
|
+
if (fs20__default.default.existsSync(webDistPath)) {
|
|
13298
13428
|
this.app.use(express__default.default.static(webDistPath));
|
|
13299
13429
|
this.app.get("*", (_req, res) => {
|
|
13300
|
-
res.sendFile(
|
|
13430
|
+
res.sendFile(path21__default.default.join(webDistPath, "index.html"));
|
|
13301
13431
|
});
|
|
13302
13432
|
} else {
|
|
13303
13433
|
this.app.get("/", (_req, res) => {
|
|
@@ -13398,6 +13528,7 @@ exports.DEFAULT_RETENTION_DAYS = DEFAULT_RETENTION_DAYS;
|
|
|
13398
13528
|
exports.DEFAULT_THEME = DEFAULT_THEME;
|
|
13399
13529
|
exports.DashboardServer = DashboardServer;
|
|
13400
13530
|
exports.GLOBAL_CONFIG_DIR = GLOBAL_CONFIG_DIR;
|
|
13531
|
+
exports.GLOBAL_CREDENTIALS_FILE = GLOBAL_CREDENTIALS_FILE;
|
|
13401
13532
|
exports.GLOBAL_DB_FILE = GLOBAL_DB_FILE;
|
|
13402
13533
|
exports.GLOBAL_KEYSTORE_FILE = GLOBAL_KEYSTORE_FILE;
|
|
13403
13534
|
exports.GLOBAL_RUNTIME_DB_FILE = GLOBAL_RUNTIME_DB_FILE;
|