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.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Database from 'better-sqlite3';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import path21 from 'path';
|
|
3
|
+
import fs20 from 'fs';
|
|
4
4
|
import os6 from 'os';
|
|
5
5
|
import crypto3, { randomUUID, timingSafeEqual } from 'crypto';
|
|
6
6
|
import EventEmitter from 'events';
|
|
@@ -58,12 +58,12 @@ var init_audit_logger = __esm({
|
|
|
58
58
|
constructor(workspacePath, debugMode = false) {
|
|
59
59
|
this.workspacePath = workspacePath;
|
|
60
60
|
this.debugMode = debugMode;
|
|
61
|
-
const cascadeDir =
|
|
62
|
-
if (!
|
|
63
|
-
|
|
61
|
+
const cascadeDir = path21.join(workspacePath, ".cascade");
|
|
62
|
+
if (!fs20.existsSync(cascadeDir)) {
|
|
63
|
+
fs20.mkdirSync(cascadeDir, { recursive: true });
|
|
64
64
|
}
|
|
65
|
-
this.keyPath =
|
|
66
|
-
this.dbPath =
|
|
65
|
+
this.keyPath = path21.join(cascadeDir, "audit_log.key");
|
|
66
|
+
this.dbPath = path21.join(cascadeDir, "audit_log.db");
|
|
67
67
|
this.initEncryptionKey();
|
|
68
68
|
this.db = new Database(this.dbPath);
|
|
69
69
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -93,11 +93,11 @@ var init_audit_logger = __esm({
|
|
|
93
93
|
return crypto3.createHash("sha256").update(`${prevHash}|${timestamp}|${eventType}|${tierId}|${encryptedPayload}`).digest("hex");
|
|
94
94
|
}
|
|
95
95
|
initEncryptionKey() {
|
|
96
|
-
if (
|
|
97
|
-
this.encryptionKey =
|
|
96
|
+
if (fs20.existsSync(this.keyPath)) {
|
|
97
|
+
this.encryptionKey = fs20.readFileSync(this.keyPath);
|
|
98
98
|
} else {
|
|
99
99
|
this.encryptionKey = crypto3.randomBytes(32);
|
|
100
|
-
|
|
100
|
+
fs20.writeFileSync(this.keyPath, this.encryptionKey);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
encrypt(text) {
|
|
@@ -175,9 +175,9 @@ var init_audit_logger = __esm({
|
|
|
175
175
|
dumpDebugIfNeeded() {
|
|
176
176
|
if (!this.debugMode) return;
|
|
177
177
|
try {
|
|
178
|
-
const dumpPath =
|
|
178
|
+
const dumpPath = path21.join(os6.tmpdir(), "cascade_audit_logs_debug.json");
|
|
179
179
|
const entries = this.getAllLogs();
|
|
180
|
-
|
|
180
|
+
fs20.writeFileSync(dumpPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
181
181
|
} catch (err) {
|
|
182
182
|
console.error("Failed to dump debug audit logs", err);
|
|
183
183
|
}
|
|
@@ -190,7 +190,7 @@ var init_audit_logger = __esm({
|
|
|
190
190
|
});
|
|
191
191
|
|
|
192
192
|
// src/constants.ts
|
|
193
|
-
var CASCADE_VERSION = "0.
|
|
193
|
+
var CASCADE_VERSION = "0.18.0";
|
|
194
194
|
var CASCADE_CONFIG_DIR = ".cascade";
|
|
195
195
|
var CASCADE_MD_FILE = "CASCADE.md";
|
|
196
196
|
var CASCADE_IGNORE_FILE = ".cascadeignore";
|
|
@@ -202,6 +202,7 @@ var CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
|
|
|
202
202
|
var GLOBAL_CONFIG_DIR = ".cascade-ai";
|
|
203
203
|
var GLOBAL_DB_FILE = "memory.db";
|
|
204
204
|
var GLOBAL_KEYSTORE_FILE = "keystore.enc";
|
|
205
|
+
var GLOBAL_CREDENTIALS_FILE = "credentials.json";
|
|
205
206
|
var GLOBAL_RUNTIME_DB_FILE = "runtime.db";
|
|
206
207
|
var DEFAULT_DASHBOARD_PORT = 4891;
|
|
207
208
|
var DEFAULT_API_PORT = 4892;
|
|
@@ -2164,7 +2165,7 @@ function computeDelegationSavings(stats, t1Model) {
|
|
|
2164
2165
|
var DEFAULT_SNAPSHOT_URL = "https://raw.githubusercontent.com/Varun-SV/Cascade-AI/main/src/core/router/benchmark-data.json";
|
|
2165
2166
|
var OPENROUTER_MODELS_URL = "https://openrouter.ai/api/v1/models";
|
|
2166
2167
|
var FETCH_TIMEOUT_MS = 8e3;
|
|
2167
|
-
var DEFAULT_CACHE_FILE =
|
|
2168
|
+
var DEFAULT_CACHE_FILE = path21.join(os6.homedir(), GLOBAL_CONFIG_DIR, "benchmarks-cache.json");
|
|
2168
2169
|
function normalizeModelId(id) {
|
|
2169
2170
|
let s = id.toLowerCase();
|
|
2170
2171
|
const slash = s.lastIndexOf("/");
|
|
@@ -2309,7 +2310,7 @@ var LiveDataProvider = class {
|
|
|
2309
2310
|
}
|
|
2310
2311
|
async saveCache() {
|
|
2311
2312
|
try {
|
|
2312
|
-
await fs4.mkdir(
|
|
2313
|
+
await fs4.mkdir(path21.dirname(this.opts.cacheFile), { recursive: true });
|
|
2313
2314
|
const cache = {
|
|
2314
2315
|
fetchedAt: this.fetchedAt,
|
|
2315
2316
|
snapshot: this.snapshot ?? void 0,
|
|
@@ -4212,8 +4213,8 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : "") + textToolSuffix,
|
|
|
4212
4213
|
tierId: this.id,
|
|
4213
4214
|
sessionId: this.taskId,
|
|
4214
4215
|
requireApproval: false,
|
|
4215
|
-
saveSnapshot: async (
|
|
4216
|
-
this.store?.addFileSnapshot(this.taskId,
|
|
4216
|
+
saveSnapshot: async (path22, content) => {
|
|
4217
|
+
this.store?.addFileSnapshot(this.taskId, path22, content);
|
|
4217
4218
|
},
|
|
4218
4219
|
sendPeerSync: (to, syncType, content) => {
|
|
4219
4220
|
this.peerBus?.send(this.id, to, syncType, this.assignment?.subtaskId ?? "", content);
|
|
@@ -4383,7 +4384,7 @@ ${assignment.expectedOutput}`;
|
|
|
4383
4384
|
const { promisify: promisify4 } = await import('util');
|
|
4384
4385
|
const execAsync2 = promisify4(exec2);
|
|
4385
4386
|
for (const artifactPath of artifactPaths) {
|
|
4386
|
-
const absolutePath =
|
|
4387
|
+
const absolutePath = path21.resolve(process.cwd(), artifactPath);
|
|
4387
4388
|
try {
|
|
4388
4389
|
const stat = await fs4.stat(absolutePath);
|
|
4389
4390
|
if (!stat.isFile()) {
|
|
@@ -4404,7 +4405,7 @@ ${assignment.expectedOutput}`;
|
|
|
4404
4405
|
issues.push(`PDF artifact looks too small to be valid: ${artifactPath}`);
|
|
4405
4406
|
continue;
|
|
4406
4407
|
}
|
|
4407
|
-
const ext =
|
|
4408
|
+
const ext = path21.extname(absolutePath).toLowerCase();
|
|
4408
4409
|
try {
|
|
4409
4410
|
if (ext === ".ts" || ext === ".tsx") {
|
|
4410
4411
|
await execAsync2(`npx tsc --noEmit ${absolutePath}`, { timeout: 1e4 });
|
|
@@ -6486,16 +6487,16 @@ function resolveInWorkspace(workspaceRoot, input) {
|
|
|
6486
6487
|
if (typeof input !== "string" || input.length === 0) {
|
|
6487
6488
|
throw new WorkspaceSandboxError(String(input), workspaceRoot);
|
|
6488
6489
|
}
|
|
6489
|
-
const root =
|
|
6490
|
-
const abs =
|
|
6491
|
-
const rel =
|
|
6492
|
-
if (rel === "" || rel === ".") ; else if (rel.startsWith("..") ||
|
|
6490
|
+
const root = path21.resolve(workspaceRoot);
|
|
6491
|
+
const abs = path21.isAbsolute(input) ? path21.resolve(input) : path21.resolve(root, input);
|
|
6492
|
+
const rel = path21.relative(root, abs);
|
|
6493
|
+
if (rel === "" || rel === ".") ; else if (rel.startsWith("..") || path21.isAbsolute(rel)) {
|
|
6493
6494
|
throw new WorkspaceSandboxError(input, root);
|
|
6494
6495
|
}
|
|
6495
6496
|
try {
|
|
6496
|
-
const real =
|
|
6497
|
-
const realRel =
|
|
6498
|
-
if (realRel !== "" && realRel !== "." && (realRel.startsWith("..") ||
|
|
6497
|
+
const real = fs20.realpathSync(abs);
|
|
6498
|
+
const realRel = path21.relative(root, real);
|
|
6499
|
+
if (realRel !== "" && realRel !== "." && (realRel.startsWith("..") || path21.isAbsolute(realRel))) {
|
|
6499
6500
|
throw new WorkspaceSandboxError(input, root);
|
|
6500
6501
|
}
|
|
6501
6502
|
} catch (e) {
|
|
@@ -6556,7 +6557,7 @@ var FileWriteTool = class extends BaseTool {
|
|
|
6556
6557
|
} catch {
|
|
6557
6558
|
}
|
|
6558
6559
|
}
|
|
6559
|
-
await fs4.mkdir(
|
|
6560
|
+
await fs4.mkdir(path21.dirname(absPath), { recursive: true });
|
|
6560
6561
|
await fs4.writeFile(absPath, content, "utf-8");
|
|
6561
6562
|
return `Written ${content.length} characters to ${filePath}`;
|
|
6562
6563
|
}
|
|
@@ -7054,7 +7055,7 @@ var ImageAnalyzeTool = class extends BaseTool {
|
|
|
7054
7055
|
};
|
|
7055
7056
|
async function fileToImageAttachment(filePath) {
|
|
7056
7057
|
const data = await fs4.readFile(filePath);
|
|
7057
|
-
const ext =
|
|
7058
|
+
const ext = path21.extname(filePath).toLowerCase();
|
|
7058
7059
|
const mimeMap = {
|
|
7059
7060
|
".jpg": "image/jpeg",
|
|
7060
7061
|
".jpeg": "image/jpeg",
|
|
@@ -7088,14 +7089,14 @@ var PDFCreateTool = class extends BaseTool {
|
|
|
7088
7089
|
const filePath = input["path"];
|
|
7089
7090
|
const content = input["content"];
|
|
7090
7091
|
const title = input["title"];
|
|
7091
|
-
const dir =
|
|
7092
|
-
if (!
|
|
7093
|
-
|
|
7092
|
+
const dir = path21.dirname(filePath);
|
|
7093
|
+
if (!fs20.existsSync(dir)) {
|
|
7094
|
+
fs20.mkdirSync(dir, { recursive: true });
|
|
7094
7095
|
}
|
|
7095
7096
|
return new Promise((resolve, reject) => {
|
|
7096
7097
|
try {
|
|
7097
7098
|
const doc = new PDFDocument({ margin: 50 });
|
|
7098
|
-
const stream =
|
|
7099
|
+
const stream = fs20.createWriteStream(filePath);
|
|
7099
7100
|
doc.pipe(stream);
|
|
7100
7101
|
if (title) {
|
|
7101
7102
|
doc.info["Title"] = title;
|
|
@@ -7173,22 +7174,22 @@ var CodeInterpreterTool = class extends BaseTool {
|
|
|
7173
7174
|
}
|
|
7174
7175
|
cmdPrefix = NODE_CMD;
|
|
7175
7176
|
}
|
|
7176
|
-
const tmpDir =
|
|
7177
|
-
if (!
|
|
7178
|
-
|
|
7177
|
+
const tmpDir = path21.join(this.workspaceRoot, ".cascade", "tmp");
|
|
7178
|
+
if (!fs20.existsSync(tmpDir)) {
|
|
7179
|
+
fs20.mkdirSync(tmpDir, { recursive: true });
|
|
7179
7180
|
}
|
|
7180
7181
|
const extension = language === "python" ? "py" : "js";
|
|
7181
7182
|
const fileName = `intp_${randomUUID().slice(0, 8)}.${extension}`;
|
|
7182
|
-
const filePath =
|
|
7183
|
-
|
|
7183
|
+
const filePath = path21.join(tmpDir, fileName);
|
|
7184
|
+
fs20.writeFileSync(filePath, code, "utf-8");
|
|
7184
7185
|
const execArgs = [filePath, ...args];
|
|
7185
7186
|
return new Promise((resolve) => {
|
|
7186
7187
|
const startMs = Date.now();
|
|
7187
7188
|
execFile(cmdPrefix, execArgs, { cwd: this.workspaceRoot, timeout: 3e4 }, (error, stdout, stderr) => {
|
|
7188
7189
|
const duration = Date.now() - startMs;
|
|
7189
7190
|
try {
|
|
7190
|
-
if (
|
|
7191
|
-
|
|
7191
|
+
if (fs20.existsSync(filePath)) {
|
|
7192
|
+
fs20.unlinkSync(filePath);
|
|
7192
7193
|
}
|
|
7193
7194
|
} catch (cleanupErr) {
|
|
7194
7195
|
console.error(`Failed to cleanup interpreter script ${filePath}:`, cleanupErr);
|
|
@@ -7467,7 +7468,7 @@ var GlobTool = class extends BaseTool {
|
|
|
7467
7468
|
};
|
|
7468
7469
|
async execute(input, _options) {
|
|
7469
7470
|
const pattern = input["pattern"];
|
|
7470
|
-
const searchPath = input["path"] ?
|
|
7471
|
+
const searchPath = input["path"] ? path21.resolve(this.workspaceRoot, input["path"]) : this.workspaceRoot;
|
|
7471
7472
|
const matches = await glob(pattern, {
|
|
7472
7473
|
cwd: searchPath,
|
|
7473
7474
|
ignore: ["node_modules/**", ".git/**", "dist/**", "build/**"],
|
|
@@ -7480,7 +7481,7 @@ var GlobTool = class extends BaseTool {
|
|
|
7480
7481
|
const withMtime = await Promise.all(
|
|
7481
7482
|
matches.map(async (rel) => {
|
|
7482
7483
|
try {
|
|
7483
|
-
const stat = await fs4.stat(
|
|
7484
|
+
const stat = await fs4.stat(path21.join(searchPath, rel));
|
|
7484
7485
|
return { rel, mtime: stat.mtimeMs };
|
|
7485
7486
|
} catch {
|
|
7486
7487
|
return { rel, mtime: 0 };
|
|
@@ -7529,7 +7530,7 @@ var GrepTool = class extends BaseTool {
|
|
|
7529
7530
|
};
|
|
7530
7531
|
async execute(input, _options) {
|
|
7531
7532
|
const pattern = input["pattern"];
|
|
7532
|
-
const searchPath = input["path"] ?
|
|
7533
|
+
const searchPath = input["path"] ? path21.resolve(this.workspaceRoot, input["path"]) : this.workspaceRoot;
|
|
7533
7534
|
const globPattern = input["glob"];
|
|
7534
7535
|
const outputMode = input["output_mode"] ?? "content";
|
|
7535
7536
|
const context = input["context"] ?? 0;
|
|
@@ -7583,12 +7584,12 @@ var GrepTool = class extends BaseTool {
|
|
|
7583
7584
|
nodir: true
|
|
7584
7585
|
});
|
|
7585
7586
|
} catch {
|
|
7586
|
-
files = [
|
|
7587
|
+
files = [path21.relative(searchPath, searchPath) || "."];
|
|
7587
7588
|
}
|
|
7588
7589
|
const results = [];
|
|
7589
7590
|
let totalCount = 0;
|
|
7590
7591
|
for (const rel of files) {
|
|
7591
|
-
const abs =
|
|
7592
|
+
const abs = path21.join(searchPath, rel);
|
|
7592
7593
|
let content;
|
|
7593
7594
|
try {
|
|
7594
7595
|
content = await fs4.readFile(abs, "utf-8");
|
|
@@ -7950,10 +7951,10 @@ var ToolRegistry = class extends EventEmitter {
|
|
|
7950
7951
|
}
|
|
7951
7952
|
isIgnored(filePath) {
|
|
7952
7953
|
if (!filePath) return false;
|
|
7953
|
-
const abs =
|
|
7954
|
-
const rel =
|
|
7955
|
-
if (!rel || rel.startsWith("..") ||
|
|
7956
|
-
const posixRel = rel.split(
|
|
7954
|
+
const abs = path21.resolve(this.workspaceRoot, filePath);
|
|
7955
|
+
const rel = path21.relative(this.workspaceRoot, abs);
|
|
7956
|
+
if (!rel || rel.startsWith("..") || path21.isAbsolute(rel)) return true;
|
|
7957
|
+
const posixRel = rel.split(path21.sep).join("/");
|
|
7957
7958
|
return this.ignoreMatcher.ignores(posixRel);
|
|
7958
7959
|
}
|
|
7959
7960
|
};
|
|
@@ -8787,7 +8788,7 @@ var TaskAnalyzer = class {
|
|
|
8787
8788
|
analysisCache.clear();
|
|
8788
8789
|
}
|
|
8789
8790
|
};
|
|
8790
|
-
var DEFAULT_STATS_FILE =
|
|
8791
|
+
var DEFAULT_STATS_FILE = path21.join(os6.homedir(), ".cascade", "model-perf.json");
|
|
8791
8792
|
var ModelPerformanceTracker = class {
|
|
8792
8793
|
stats = /* @__PURE__ */ new Map();
|
|
8793
8794
|
featureStats = /* @__PURE__ */ new Map();
|
|
@@ -8819,7 +8820,7 @@ var ModelPerformanceTracker = class {
|
|
|
8819
8820
|
}
|
|
8820
8821
|
async save() {
|
|
8821
8822
|
try {
|
|
8822
|
-
await fs4.mkdir(
|
|
8823
|
+
await fs4.mkdir(path21.dirname(this.statsFile), { recursive: true });
|
|
8823
8824
|
const modelsObj = {};
|
|
8824
8825
|
const featuresObj = {};
|
|
8825
8826
|
for (const [key, stat] of this.stats) modelsObj[key] = stat;
|
|
@@ -9358,7 +9359,7 @@ Required capability: ${description.slice(0, 300)}`;
|
|
|
9358
9359
|
* any dangerous action, so a silently-reloaded tool can't act without approval. */
|
|
9359
9360
|
async loadPersistedTools() {
|
|
9360
9361
|
if (!this.workspacePath || !this.persistEnabled) return;
|
|
9361
|
-
const file =
|
|
9362
|
+
const file = path21.join(this.workspacePath, ".cascade", DYNAMIC_TOOLS_FILE);
|
|
9362
9363
|
try {
|
|
9363
9364
|
const raw = await fs4.readFile(file, "utf-8");
|
|
9364
9365
|
const specs = JSON.parse(raw);
|
|
@@ -9382,8 +9383,8 @@ Required capability: ${description.slice(0, 300)}`;
|
|
|
9382
9383
|
}
|
|
9383
9384
|
async persist() {
|
|
9384
9385
|
if (!this.workspacePath || !this.persistEnabled) return;
|
|
9385
|
-
const dir =
|
|
9386
|
-
const file =
|
|
9386
|
+
const dir = path21.join(this.workspacePath, ".cascade");
|
|
9387
|
+
const file = path21.join(dir, DYNAMIC_TOOLS_FILE);
|
|
9387
9388
|
try {
|
|
9388
9389
|
await fs4.mkdir(dir, { recursive: true });
|
|
9389
9390
|
await fs4.writeFile(file, JSON.stringify(Array.from(this.specs.values()), null, 2), "utf-8");
|
|
@@ -9403,12 +9404,12 @@ var WorldStateDB = class {
|
|
|
9403
9404
|
constructor(workspacePath, debugMode = false) {
|
|
9404
9405
|
this.workspacePath = workspacePath;
|
|
9405
9406
|
this.debugMode = debugMode;
|
|
9406
|
-
const cascadeDir =
|
|
9407
|
-
if (!
|
|
9408
|
-
|
|
9407
|
+
const cascadeDir = path21.join(workspacePath, ".cascade");
|
|
9408
|
+
if (!fs20.existsSync(cascadeDir)) {
|
|
9409
|
+
fs20.mkdirSync(cascadeDir, { recursive: true });
|
|
9409
9410
|
}
|
|
9410
|
-
this.keyPath =
|
|
9411
|
-
this.dbPath =
|
|
9411
|
+
this.keyPath = path21.join(cascadeDir, "world_state.key");
|
|
9412
|
+
this.dbPath = path21.join(cascadeDir, "world_state.db");
|
|
9412
9413
|
this.initEncryptionKey();
|
|
9413
9414
|
this.db = new Database(this.dbPath);
|
|
9414
9415
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -9438,11 +9439,11 @@ var WorldStateDB = class {
|
|
|
9438
9439
|
dbPath;
|
|
9439
9440
|
encryptionKey;
|
|
9440
9441
|
initEncryptionKey() {
|
|
9441
|
-
if (
|
|
9442
|
-
this.encryptionKey =
|
|
9442
|
+
if (fs20.existsSync(this.keyPath)) {
|
|
9443
|
+
this.encryptionKey = fs20.readFileSync(this.keyPath);
|
|
9443
9444
|
} else {
|
|
9444
9445
|
this.encryptionKey = crypto3.randomBytes(32);
|
|
9445
|
-
|
|
9446
|
+
fs20.writeFileSync(this.keyPath, this.encryptionKey);
|
|
9446
9447
|
}
|
|
9447
9448
|
}
|
|
9448
9449
|
encrypt(text) {
|
|
@@ -9583,6 +9584,22 @@ var WorldStateDB = class {
|
|
|
9583
9584
|
}
|
|
9584
9585
|
return selected.slice(0, limit).map((f) => `- ${f.entity} ${f.relation} ${f.value}`).join("\n");
|
|
9585
9586
|
}
|
|
9587
|
+
/**
|
|
9588
|
+
* Delete one fact by its (normalized) entity + relation key. Returns whether
|
|
9589
|
+
* a row was actually removed. Powers the desktop Knowledge tab's per-fact
|
|
9590
|
+
* delete — users can prune what the planner remembers about their project.
|
|
9591
|
+
*/
|
|
9592
|
+
deleteFact(entity, relation) {
|
|
9593
|
+
const e = normalizeKey(entity);
|
|
9594
|
+
const r = normalizeKey(relation);
|
|
9595
|
+
if (!e || !r) return false;
|
|
9596
|
+
const result = this.db.prepare("DELETE FROM facts WHERE entity = ? AND relation = ?").run(e, r);
|
|
9597
|
+
return result.changes > 0;
|
|
9598
|
+
}
|
|
9599
|
+
/** Delete every fact. Returns how many were removed. */
|
|
9600
|
+
clearFacts() {
|
|
9601
|
+
return this.db.prepare("DELETE FROM facts").run().changes;
|
|
9602
|
+
}
|
|
9586
9603
|
// ── Export / Import ──────────────────────────
|
|
9587
9604
|
//
|
|
9588
9605
|
// Knowledge travels DECRYPTED in the export bundle (a portable plaintext
|
|
@@ -9631,9 +9648,9 @@ var WorldStateDB = class {
|
|
|
9631
9648
|
dumpDebugIfNeeded() {
|
|
9632
9649
|
if (!this.debugMode) return;
|
|
9633
9650
|
try {
|
|
9634
|
-
const dumpPath =
|
|
9651
|
+
const dumpPath = path21.join(os6.tmpdir(), "cascade_world_state_debug.json");
|
|
9635
9652
|
const entries = this.getAllEntries();
|
|
9636
|
-
|
|
9653
|
+
fs20.writeFileSync(dumpPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
9637
9654
|
} catch (err) {
|
|
9638
9655
|
console.error("Failed to dump debug world state", err);
|
|
9639
9656
|
}
|
|
@@ -10543,7 +10560,7 @@ var Keystore = class {
|
|
|
10543
10560
|
const creds = await this.keytar.findCredentials(KEYTAR_SERVICE);
|
|
10544
10561
|
this.cache = Object.fromEntries(creds.map((c) => [c.account, c.password]));
|
|
10545
10562
|
this.backend = "keytar";
|
|
10546
|
-
if (password &&
|
|
10563
|
+
if (password && fs20.existsSync(this.storePath)) {
|
|
10547
10564
|
try {
|
|
10548
10565
|
const fileEntries = this.decryptFile(password);
|
|
10549
10566
|
for (const [k, v] of Object.entries(fileEntries)) {
|
|
@@ -10562,7 +10579,7 @@ var Keystore = class {
|
|
|
10562
10579
|
"Keystore unlock requires a password because the OS keychain (keytar) is not available on this system."
|
|
10563
10580
|
);
|
|
10564
10581
|
}
|
|
10565
|
-
if (!
|
|
10582
|
+
if (!fs20.existsSync(this.storePath)) {
|
|
10566
10583
|
const salt = crypto3.randomBytes(SALT_LEN);
|
|
10567
10584
|
this.masterKey = this.deriveKey(password, salt);
|
|
10568
10585
|
this.writeWithSalt({}, salt);
|
|
@@ -10576,7 +10593,7 @@ var Keystore = class {
|
|
|
10576
10593
|
}
|
|
10577
10594
|
/** Synchronous legacy unlock kept for AES-only environments. */
|
|
10578
10595
|
unlockSync(password) {
|
|
10579
|
-
if (!
|
|
10596
|
+
if (!fs20.existsSync(this.storePath)) {
|
|
10580
10597
|
const salt = crypto3.randomBytes(SALT_LEN);
|
|
10581
10598
|
this.masterKey = this.deriveKey(password, salt);
|
|
10582
10599
|
this.writeWithSalt({}, salt);
|
|
@@ -10634,7 +10651,7 @@ var Keystore = class {
|
|
|
10634
10651
|
}
|
|
10635
10652
|
}
|
|
10636
10653
|
decryptFile(password, knownSalt) {
|
|
10637
|
-
if (!
|
|
10654
|
+
if (!fs20.existsSync(this.storePath)) return {};
|
|
10638
10655
|
try {
|
|
10639
10656
|
const { salt, ciphertext, iv, tag } = this.readRaw();
|
|
10640
10657
|
const useSalt = knownSalt ?? salt;
|
|
@@ -10656,8 +10673,8 @@ var Keystore = class {
|
|
|
10656
10673
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
10657
10674
|
const tag = cipher.getAuthTag();
|
|
10658
10675
|
const out = Buffer.concat([raw.salt, iv, tag, ciphertext]);
|
|
10659
|
-
|
|
10660
|
-
|
|
10676
|
+
fs20.mkdirSync(path21.dirname(this.storePath), { recursive: true });
|
|
10677
|
+
fs20.writeFileSync(this.storePath, out, { mode: 384 });
|
|
10661
10678
|
}
|
|
10662
10679
|
writeWithSalt(data, salt) {
|
|
10663
10680
|
if (!this.masterKey) throw new Error("writeWithSalt called before masterKey was set");
|
|
@@ -10667,11 +10684,11 @@ var Keystore = class {
|
|
|
10667
10684
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
10668
10685
|
const tag = cipher.getAuthTag();
|
|
10669
10686
|
const out = Buffer.concat([salt, iv, tag, ciphertext]);
|
|
10670
|
-
|
|
10671
|
-
|
|
10687
|
+
fs20.mkdirSync(path21.dirname(this.storePath), { recursive: true });
|
|
10688
|
+
fs20.writeFileSync(this.storePath, out, { mode: 384 });
|
|
10672
10689
|
}
|
|
10673
10690
|
readRaw() {
|
|
10674
|
-
const buf =
|
|
10691
|
+
const buf = fs20.readFileSync(this.storePath);
|
|
10675
10692
|
let offset = 0;
|
|
10676
10693
|
const salt = buf.subarray(offset, offset + SALT_LEN);
|
|
10677
10694
|
offset += SALT_LEN;
|
|
@@ -10704,7 +10721,7 @@ var CascadeIgnore = class {
|
|
|
10704
10721
|
]);
|
|
10705
10722
|
}
|
|
10706
10723
|
async load(workspacePath) {
|
|
10707
|
-
const filePath =
|
|
10724
|
+
const filePath = path21.join(workspacePath, ".cascadeignore");
|
|
10708
10725
|
try {
|
|
10709
10726
|
const content = await fs4.readFile(filePath, "utf-8");
|
|
10710
10727
|
const lines = content.split("\n").filter((l) => l.trim() && !l.startsWith("#"));
|
|
@@ -10715,7 +10732,7 @@ var CascadeIgnore = class {
|
|
|
10715
10732
|
}
|
|
10716
10733
|
isIgnored(filePath, workspacePath) {
|
|
10717
10734
|
try {
|
|
10718
|
-
const relative = workspacePath ?
|
|
10735
|
+
const relative = workspacePath ? path21.relative(workspacePath, filePath) : filePath;
|
|
10719
10736
|
return this.ig.ignores(relative);
|
|
10720
10737
|
} catch {
|
|
10721
10738
|
return false;
|
|
@@ -10726,7 +10743,7 @@ var CascadeIgnore = class {
|
|
|
10726
10743
|
}
|
|
10727
10744
|
};
|
|
10728
10745
|
async function loadCascadeMd(workspacePath) {
|
|
10729
|
-
const filePath =
|
|
10746
|
+
const filePath = path21.join(workspacePath, "CASCADE.md");
|
|
10730
10747
|
try {
|
|
10731
10748
|
const raw = await fs4.readFile(filePath, "utf-8");
|
|
10732
10749
|
return parseCascadeMd(raw);
|
|
@@ -10757,7 +10774,7 @@ ${raw.trim()}`;
|
|
|
10757
10774
|
var MemoryStore = class _MemoryStore {
|
|
10758
10775
|
db;
|
|
10759
10776
|
constructor(dbPath) {
|
|
10760
|
-
|
|
10777
|
+
fs20.mkdirSync(path21.dirname(dbPath), { recursive: true });
|
|
10761
10778
|
try {
|
|
10762
10779
|
this.db = new Database(dbPath, { timeout: 5e3 });
|
|
10763
10780
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -11592,6 +11609,60 @@ Original error: ${err.message}`
|
|
|
11592
11609
|
};
|
|
11593
11610
|
}
|
|
11594
11611
|
};
|
|
11612
|
+
function credentialsPath(globalDir) {
|
|
11613
|
+
return path21.join(globalDir, GLOBAL_CREDENTIALS_FILE);
|
|
11614
|
+
}
|
|
11615
|
+
function providerKey(p) {
|
|
11616
|
+
if (p.type === "azure") {
|
|
11617
|
+
return `azure:${p.deploymentName ?? p.baseUrl ?? p.label ?? ""}`;
|
|
11618
|
+
}
|
|
11619
|
+
return p.type;
|
|
11620
|
+
}
|
|
11621
|
+
function isPersistable(p) {
|
|
11622
|
+
return Boolean(p.apiKey || p.authToken || p.type === "azure" || p.baseUrl);
|
|
11623
|
+
}
|
|
11624
|
+
function loadGlobalCredentials(globalDir) {
|
|
11625
|
+
try {
|
|
11626
|
+
const raw = fs20.readFileSync(credentialsPath(globalDir), "utf-8");
|
|
11627
|
+
const parsed = JSON.parse(raw);
|
|
11628
|
+
if (!Array.isArray(parsed.providers)) return [];
|
|
11629
|
+
return parsed.providers.filter(
|
|
11630
|
+
(p) => Boolean(p) && typeof p.type === "string"
|
|
11631
|
+
);
|
|
11632
|
+
} catch {
|
|
11633
|
+
return [];
|
|
11634
|
+
}
|
|
11635
|
+
}
|
|
11636
|
+
function saveGlobalCredentials(globalDir, providers) {
|
|
11637
|
+
const filePath = credentialsPath(globalDir);
|
|
11638
|
+
fs20.mkdirSync(globalDir, { recursive: true, mode: 448 });
|
|
11639
|
+
const body = { version: 1, providers: providers.filter(isPersistable) };
|
|
11640
|
+
const tmp = `${filePath}.tmp`;
|
|
11641
|
+
fs20.writeFileSync(tmp, JSON.stringify(body, null, 2), { encoding: "utf-8", mode: 384 });
|
|
11642
|
+
fs20.renameSync(tmp, filePath);
|
|
11643
|
+
try {
|
|
11644
|
+
fs20.chmodSync(filePath, 384);
|
|
11645
|
+
} catch {
|
|
11646
|
+
}
|
|
11647
|
+
}
|
|
11648
|
+
function mergeGlobalCredentials(workspaceProviders, globalProviders) {
|
|
11649
|
+
const merged = [...workspaceProviders];
|
|
11650
|
+
const byKey = new Map(merged.map((p) => [providerKey(p), p]));
|
|
11651
|
+
for (const g of globalProviders) {
|
|
11652
|
+
const existing = byKey.get(providerKey(g));
|
|
11653
|
+
if (!existing) {
|
|
11654
|
+
merged.push({ ...g });
|
|
11655
|
+
byKey.set(providerKey(g), merged[merged.length - 1]);
|
|
11656
|
+
continue;
|
|
11657
|
+
}
|
|
11658
|
+
if (!existing.apiKey && g.apiKey) existing.apiKey = g.apiKey;
|
|
11659
|
+
if (!existing.authToken && g.authToken) existing.authToken = g.authToken;
|
|
11660
|
+
if (!existing.baseUrl && g.baseUrl) existing.baseUrl = g.baseUrl;
|
|
11661
|
+
if (!existing.apiVersion && g.apiVersion) existing.apiVersion = g.apiVersion;
|
|
11662
|
+
if (!existing.label && g.label) existing.label = g.label;
|
|
11663
|
+
}
|
|
11664
|
+
return merged;
|
|
11665
|
+
}
|
|
11595
11666
|
|
|
11596
11667
|
// src/config/index.ts
|
|
11597
11668
|
var ConfigManager = class {
|
|
@@ -11602,18 +11673,20 @@ var ConfigManager = class {
|
|
|
11602
11673
|
cascadeMd = null;
|
|
11603
11674
|
workspacePath;
|
|
11604
11675
|
globalDir;
|
|
11605
|
-
|
|
11676
|
+
/** `globalDirOverride` exists for tests — never point it at the real home dir there. */
|
|
11677
|
+
constructor(workspacePath = process.cwd(), globalDirOverride) {
|
|
11606
11678
|
this.workspacePath = workspacePath;
|
|
11607
|
-
this.globalDir =
|
|
11679
|
+
this.globalDir = globalDirOverride ?? path21.join(os6.homedir(), GLOBAL_CONFIG_DIR);
|
|
11608
11680
|
}
|
|
11609
11681
|
async load() {
|
|
11610
11682
|
this.config = await this.loadConfig();
|
|
11611
11683
|
this.ignore = new CascadeIgnore();
|
|
11612
11684
|
await this.ignore.load(this.workspacePath);
|
|
11613
11685
|
this.cascadeMd = await loadCascadeMd(this.workspacePath);
|
|
11614
|
-
this.keystore = new Keystore(
|
|
11615
|
-
this.store = new MemoryStore(
|
|
11686
|
+
this.keystore = new Keystore(path21.join(this.globalDir, GLOBAL_KEYSTORE_FILE));
|
|
11687
|
+
this.store = new MemoryStore(path21.join(this.workspacePath, CASCADE_DB_FILE));
|
|
11616
11688
|
await this.injectEnvKeys();
|
|
11689
|
+
this.config.providers = mergeGlobalCredentials(this.config.providers, loadGlobalCredentials(this.globalDir));
|
|
11617
11690
|
await this.ensureDefaultIdentity();
|
|
11618
11691
|
}
|
|
11619
11692
|
getConfig() {
|
|
@@ -11635,9 +11708,14 @@ var ConfigManager = class {
|
|
|
11635
11708
|
return this.workspacePath;
|
|
11636
11709
|
}
|
|
11637
11710
|
async save() {
|
|
11638
|
-
const configPath =
|
|
11639
|
-
await fs4.mkdir(
|
|
11711
|
+
const configPath = path21.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
11712
|
+
await fs4.mkdir(path21.dirname(configPath), { recursive: true });
|
|
11640
11713
|
await fs4.writeFile(configPath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
11714
|
+
try {
|
|
11715
|
+
saveGlobalCredentials(this.globalDir, this.config.providers);
|
|
11716
|
+
} catch (err) {
|
|
11717
|
+
console.warn(`Failed to sync credentials to global store: ${err instanceof Error ? err.message : String(err)}`);
|
|
11718
|
+
}
|
|
11641
11719
|
}
|
|
11642
11720
|
async updateConfig(updates) {
|
|
11643
11721
|
this.config = validateConfig({ ...this.config, ...updates });
|
|
@@ -11660,7 +11738,7 @@ var ConfigManager = class {
|
|
|
11660
11738
|
return configProvider?.apiKey;
|
|
11661
11739
|
}
|
|
11662
11740
|
async loadConfig() {
|
|
11663
|
-
const configPath =
|
|
11741
|
+
const configPath = path21.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
11664
11742
|
try {
|
|
11665
11743
|
const raw = await fs4.readFile(configPath, "utf-8");
|
|
11666
11744
|
return validateConfig(JSON.parse(raw));
|
|
@@ -11767,6 +11845,11 @@ function authMiddleware(secret, required = true) {
|
|
|
11767
11845
|
}
|
|
11768
11846
|
const user = verifyToken(token, secret);
|
|
11769
11847
|
if (!user) {
|
|
11848
|
+
if (!required) {
|
|
11849
|
+
req.user = void 0;
|
|
11850
|
+
next();
|
|
11851
|
+
return;
|
|
11852
|
+
}
|
|
11770
11853
|
res.status(401).json({ error: "Invalid or expired token" });
|
|
11771
11854
|
return;
|
|
11772
11855
|
}
|
|
@@ -12075,7 +12158,7 @@ function aggregateCostStats(sessions, opts = {}) {
|
|
|
12075
12158
|
}
|
|
12076
12159
|
|
|
12077
12160
|
// src/dashboard/server.ts
|
|
12078
|
-
var __dirname$1 =
|
|
12161
|
+
var __dirname$1 = path21.dirname(fileURLToPath(import.meta.url));
|
|
12079
12162
|
var DashboardServer = class {
|
|
12080
12163
|
app;
|
|
12081
12164
|
httpServer;
|
|
@@ -12309,12 +12392,17 @@ var DashboardServer = class {
|
|
|
12309
12392
|
*/
|
|
12310
12393
|
persistConfig() {
|
|
12311
12394
|
try {
|
|
12312
|
-
const configPath =
|
|
12313
|
-
|
|
12314
|
-
|
|
12395
|
+
const configPath = path21.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
12396
|
+
fs20.mkdirSync(path21.dirname(configPath), { recursive: true });
|
|
12397
|
+
fs20.writeFileSync(configPath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
12315
12398
|
} catch (err) {
|
|
12316
12399
|
console.warn(`[dashboard] Failed to persist config: ${err instanceof Error ? err.message : String(err)}`);
|
|
12317
12400
|
}
|
|
12401
|
+
try {
|
|
12402
|
+
saveGlobalCredentials(path21.join(os6.homedir(), GLOBAL_CONFIG_DIR), this.config.providers ?? []);
|
|
12403
|
+
} catch (err) {
|
|
12404
|
+
console.warn(`[dashboard] Failed to sync global credentials: ${err instanceof Error ? err.message : String(err)}`);
|
|
12405
|
+
}
|
|
12318
12406
|
}
|
|
12319
12407
|
/**
|
|
12320
12408
|
* Produce a stable dashboard JWT signing secret.
|
|
@@ -12326,15 +12414,15 @@ var DashboardServer = class {
|
|
|
12326
12414
|
resolveDashboardSecret() {
|
|
12327
12415
|
const fromConfig = this.config.dashboard.secret ?? process.env["CASCADE_DASHBOARD_SECRET"];
|
|
12328
12416
|
if (fromConfig) return fromConfig;
|
|
12329
|
-
const secretPath =
|
|
12417
|
+
const secretPath = path21.join(this.workspacePath, CASCADE_DASHBOARD_SECRET_FILE);
|
|
12330
12418
|
try {
|
|
12331
|
-
if (
|
|
12332
|
-
const existing =
|
|
12419
|
+
if (fs20.existsSync(secretPath)) {
|
|
12420
|
+
const existing = fs20.readFileSync(secretPath, "utf-8").trim();
|
|
12333
12421
|
if (existing.length >= 16) return existing;
|
|
12334
12422
|
}
|
|
12335
12423
|
const generated = randomUUID();
|
|
12336
|
-
|
|
12337
|
-
|
|
12424
|
+
fs20.mkdirSync(path21.dirname(secretPath), { recursive: true });
|
|
12425
|
+
fs20.writeFileSync(secretPath, generated, { encoding: "utf-8", mode: 384 });
|
|
12338
12426
|
if (this.config.dashboard.auth) {
|
|
12339
12427
|
console.warn(
|
|
12340
12428
|
`Dashboard auth enabled with no secret configured; persisted a generated secret to ${secretPath}. Set CASCADE_DASHBOARD_SECRET or config.dashboard.secret to override.`
|
|
@@ -12361,7 +12449,7 @@ var DashboardServer = class {
|
|
|
12361
12449
|
// ── Setup ─────────────────────────────────────
|
|
12362
12450
|
getGlobalStore() {
|
|
12363
12451
|
if (!this.globalStore) {
|
|
12364
|
-
const globalDbPath =
|
|
12452
|
+
const globalDbPath = path21.join(os6.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
12365
12453
|
this.globalStore = new MemoryStore(globalDbPath);
|
|
12366
12454
|
}
|
|
12367
12455
|
return this.globalStore;
|
|
@@ -12630,12 +12718,12 @@ ${prompt}`;
|
|
|
12630
12718
|
}
|
|
12631
12719
|
}
|
|
12632
12720
|
watchRuntimeChanges() {
|
|
12633
|
-
const workspaceDbPath =
|
|
12634
|
-
const globalDbPath =
|
|
12721
|
+
const workspaceDbPath = path21.join(this.workspacePath, CASCADE_DB_FILE);
|
|
12722
|
+
const globalDbPath = path21.join(os6.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
12635
12723
|
const watchPaths = [workspaceDbPath, globalDbPath].filter((p, index, arr) => arr.indexOf(p) === index);
|
|
12636
12724
|
for (const watchPath of watchPaths) {
|
|
12637
|
-
if (!
|
|
12638
|
-
|
|
12725
|
+
if (!fs20.existsSync(watchPath)) continue;
|
|
12726
|
+
fs20.watchFile(watchPath, { interval: 3e3 }, () => {
|
|
12639
12727
|
this.throttledBroadcast(watchPath === globalDbPath ? "global" : "workspace");
|
|
12640
12728
|
});
|
|
12641
12729
|
}
|
|
@@ -12757,7 +12845,7 @@ ${prompt}`;
|
|
|
12757
12845
|
const sessionId = req.params.id;
|
|
12758
12846
|
this.store.deleteSession(sessionId);
|
|
12759
12847
|
this.store.deleteRuntimeSession(sessionId);
|
|
12760
|
-
const globalDbPath =
|
|
12848
|
+
const globalDbPath = path21.join(os6.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
12761
12849
|
const globalStore = new MemoryStore(globalDbPath);
|
|
12762
12850
|
try {
|
|
12763
12851
|
globalStore.deleteRuntimeSession(sessionId);
|
|
@@ -12850,7 +12938,7 @@ ${prompt}`;
|
|
|
12850
12938
|
});
|
|
12851
12939
|
this.app.delete("/api/sessions", auth, (req, res) => {
|
|
12852
12940
|
const body = req.body;
|
|
12853
|
-
const globalDbPath =
|
|
12941
|
+
const globalDbPath = path21.join(os6.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
12854
12942
|
if (body?.ids && Array.isArray(body.ids) && body.ids.length > 0) {
|
|
12855
12943
|
const globalStore = new MemoryStore(globalDbPath);
|
|
12856
12944
|
try {
|
|
@@ -12873,7 +12961,7 @@ ${prompt}`;
|
|
|
12873
12961
|
});
|
|
12874
12962
|
this.app.delete("/api/runtime", auth, (_req, res) => {
|
|
12875
12963
|
this.store.deleteAllRuntimeNodes();
|
|
12876
|
-
const globalDbPath =
|
|
12964
|
+
const globalDbPath = path21.join(os6.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
12877
12965
|
const globalStore = new MemoryStore(globalDbPath);
|
|
12878
12966
|
try {
|
|
12879
12967
|
globalStore.deleteAllRuntimeNodes();
|
|
@@ -12959,12 +13047,12 @@ ${prompt}`;
|
|
|
12959
13047
|
if (body["tierLimits"]) this.config.tierLimits = { ...this.config.tierLimits, ...body["tierLimits"] };
|
|
12960
13048
|
if (body["budget"]) this.config.budget = { ...this.config.budget, ...body["budget"] };
|
|
12961
13049
|
try {
|
|
12962
|
-
const configPath =
|
|
12963
|
-
const existing =
|
|
13050
|
+
const configPath = path21.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
13051
|
+
const existing = fs20.existsSync(configPath) ? JSON.parse(fs20.readFileSync(configPath, "utf-8")) : {};
|
|
12964
13052
|
const updated = { ...existing, tierLimits: this.config.tierLimits, budget: this.config.budget };
|
|
12965
13053
|
const tmp = configPath + ".tmp";
|
|
12966
|
-
|
|
12967
|
-
|
|
13054
|
+
fs20.writeFileSync(tmp, JSON.stringify(updated, null, 2), "utf-8");
|
|
13055
|
+
fs20.renameSync(tmp, configPath);
|
|
12968
13056
|
res.json({ ok: true });
|
|
12969
13057
|
} catch (err) {
|
|
12970
13058
|
res.status(500).json({ error: `Failed to save config: ${err instanceof Error ? err.message : String(err)}` });
|
|
@@ -12992,7 +13080,7 @@ ${prompt}`;
|
|
|
12992
13080
|
this.app.get("/api/runtime", auth, (req, res) => {
|
|
12993
13081
|
const scope = req.query["scope"] ?? "workspace";
|
|
12994
13082
|
if (scope === "global") {
|
|
12995
|
-
const globalDbPath =
|
|
13083
|
+
const globalDbPath = path21.join(os6.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
12996
13084
|
const globalStore = new MemoryStore(globalDbPath);
|
|
12997
13085
|
try {
|
|
12998
13086
|
res.json({
|
|
@@ -13227,6 +13315,48 @@ ${prompt}`;
|
|
|
13227
13315
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
13228
13316
|
}
|
|
13229
13317
|
});
|
|
13318
|
+
this.app.get("/api/knowledge", auth, (_req, res) => {
|
|
13319
|
+
try {
|
|
13320
|
+
const ws = new WorldStateDB(this.workspacePath);
|
|
13321
|
+
try {
|
|
13322
|
+
const facts = ws.getAllFacts();
|
|
13323
|
+
res.json({ total: facts.length, facts });
|
|
13324
|
+
} finally {
|
|
13325
|
+
ws.close();
|
|
13326
|
+
}
|
|
13327
|
+
} catch (err) {
|
|
13328
|
+
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
13329
|
+
}
|
|
13330
|
+
});
|
|
13331
|
+
this.app.delete("/api/knowledge/fact", auth, mutationLimiter, (req, res) => {
|
|
13332
|
+
const body = req.body;
|
|
13333
|
+
if (!body.entity || !body.relation) {
|
|
13334
|
+
res.status(400).json({ error: "entity and relation are required" });
|
|
13335
|
+
return;
|
|
13336
|
+
}
|
|
13337
|
+
try {
|
|
13338
|
+
const ws = new WorldStateDB(this.workspacePath);
|
|
13339
|
+
try {
|
|
13340
|
+
res.json({ ok: true, deleted: ws.deleteFact(body.entity, body.relation) });
|
|
13341
|
+
} finally {
|
|
13342
|
+
ws.close();
|
|
13343
|
+
}
|
|
13344
|
+
} catch (err) {
|
|
13345
|
+
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
13346
|
+
}
|
|
13347
|
+
});
|
|
13348
|
+
this.app.delete("/api/knowledge", auth, mutationLimiter, (_req, res) => {
|
|
13349
|
+
try {
|
|
13350
|
+
const ws = new WorldStateDB(this.workspacePath);
|
|
13351
|
+
try {
|
|
13352
|
+
res.json({ ok: true, deleted: ws.clearFacts() });
|
|
13353
|
+
} finally {
|
|
13354
|
+
ws.close();
|
|
13355
|
+
}
|
|
13356
|
+
} catch (err) {
|
|
13357
|
+
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
13358
|
+
}
|
|
13359
|
+
});
|
|
13230
13360
|
this.app.get("/api/audit-chain", auth, async (req, res) => {
|
|
13231
13361
|
try {
|
|
13232
13362
|
const limit = Math.min(500, Math.max(1, parseInt(req.query["limit"] || "200", 10) || 200));
|
|
@@ -13245,13 +13375,13 @@ ${prompt}`;
|
|
|
13245
13375
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
13246
13376
|
}
|
|
13247
13377
|
});
|
|
13248
|
-
const prodPath =
|
|
13249
|
-
const devPath =
|
|
13250
|
-
const webDistPath =
|
|
13251
|
-
if (
|
|
13378
|
+
const prodPath = path21.resolve(__dirname$1, "../web/dist");
|
|
13379
|
+
const devPath = path21.resolve(__dirname$1, "../../web/dist");
|
|
13380
|
+
const webDistPath = fs20.existsSync(prodPath) ? prodPath : devPath;
|
|
13381
|
+
if (fs20.existsSync(webDistPath)) {
|
|
13252
13382
|
this.app.use(express.static(webDistPath));
|
|
13253
13383
|
this.app.get("*", (_req, res) => {
|
|
13254
|
-
res.sendFile(
|
|
13384
|
+
res.sendFile(path21.join(webDistPath, "index.html"));
|
|
13255
13385
|
});
|
|
13256
13386
|
} else {
|
|
13257
13387
|
this.app.get("/", (_req, res) => {
|
|
@@ -13324,6 +13454,6 @@ var HooksRunner = class {
|
|
|
13324
13454
|
}
|
|
13325
13455
|
};
|
|
13326
13456
|
|
|
13327
|
-
export { AZURE_BASE_URL_TEMPLATE, AuditLogger, CASCADE_AUDIT_FILE, CASCADE_CONFIG_DIR, CASCADE_CONFIG_FILE, CASCADE_DASHBOARD_SECRET_FILE, CASCADE_DB_FILE, CASCADE_IGNORE_FILE, CASCADE_KEYSTORE_FILE, CASCADE_MD_FILE, CASCADE_VERSION, COMPLEXITY_T2_COUNT, Cascade, CascadeCancelledError, CascadeIgnore, CascadeRouter, CascadeToolError, ConfigManager, DEFAULT_API_PORT, DEFAULT_APPROVAL_REQUIRED, DEFAULT_AUTO_SUMMARIZE_AT, DEFAULT_CONTEXT_LIMIT, DEFAULT_DASHBOARD_PORT, DEFAULT_MAX_SESSION_MESSAGES, DEFAULT_RETENTION_DAYS, DEFAULT_THEME, DashboardServer, GLOBAL_CONFIG_DIR, GLOBAL_DB_FILE, GLOBAL_KEYSTORE_FILE, GLOBAL_RUNTIME_DB_FILE, HooksRunner, Keystore, LM_STUDIO_BASE_URL, MODELS, McpClient, MemoryStore, OLLAMA_BASE_URL, PROVIDER_DISPLAY_NAMES, T1Administrator, T1_MODEL_PRIORITY, T2Manager, T2_MODEL_PRIORITY, T3Worker, T3_MODEL_PRIORITY, THEME_NAMES, TOOL_NAMES, TaskScheduler, Telemetry, ToolRegistry, VISION_MODEL_PRIORITY, createCascade, nodeHttpFetch, preferIpv4Host, runCascade, streamCascade };
|
|
13457
|
+
export { AZURE_BASE_URL_TEMPLATE, AuditLogger, CASCADE_AUDIT_FILE, CASCADE_CONFIG_DIR, CASCADE_CONFIG_FILE, CASCADE_DASHBOARD_SECRET_FILE, CASCADE_DB_FILE, CASCADE_IGNORE_FILE, CASCADE_KEYSTORE_FILE, CASCADE_MD_FILE, CASCADE_VERSION, COMPLEXITY_T2_COUNT, Cascade, CascadeCancelledError, CascadeIgnore, CascadeRouter, CascadeToolError, ConfigManager, DEFAULT_API_PORT, DEFAULT_APPROVAL_REQUIRED, DEFAULT_AUTO_SUMMARIZE_AT, DEFAULT_CONTEXT_LIMIT, DEFAULT_DASHBOARD_PORT, DEFAULT_MAX_SESSION_MESSAGES, DEFAULT_RETENTION_DAYS, DEFAULT_THEME, DashboardServer, GLOBAL_CONFIG_DIR, GLOBAL_CREDENTIALS_FILE, GLOBAL_DB_FILE, GLOBAL_KEYSTORE_FILE, GLOBAL_RUNTIME_DB_FILE, HooksRunner, Keystore, LM_STUDIO_BASE_URL, MODELS, McpClient, MemoryStore, OLLAMA_BASE_URL, PROVIDER_DISPLAY_NAMES, T1Administrator, T1_MODEL_PRIORITY, T2Manager, T2_MODEL_PRIORITY, T3Worker, T3_MODEL_PRIORITY, THEME_NAMES, TOOL_NAMES, TaskScheduler, Telemetry, ToolRegistry, VISION_MODEL_PRIORITY, createCascade, nodeHttpFetch, preferIpv4Host, runCascade, streamCascade };
|
|
13328
13458
|
//# sourceMappingURL=index.js.map
|
|
13329
13459
|
//# sourceMappingURL=index.js.map
|