cascade-ai 0.15.2 → 0.16.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 +81 -9
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +81 -9
- package/dist/cli.js.map +1 -1
- package/dist/desktop-core.cjs +54 -6
- package/dist/index.cjs +54 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -4
- package/dist/index.d.ts +27 -4
- package/dist/index.js +54 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -58,7 +58,7 @@ var __export = (target, all) => {
|
|
|
58
58
|
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;
|
|
59
59
|
var init_constants = __esm({
|
|
60
60
|
"src/constants.ts"() {
|
|
61
|
-
CASCADE_VERSION = "0.
|
|
61
|
+
CASCADE_VERSION = "0.16.0";
|
|
62
62
|
CASCADE_CONFIG_FILE = ".cascade/config.json";
|
|
63
63
|
CASCADE_DB_FILE = ".cascade/memory.db";
|
|
64
64
|
CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
|
|
@@ -3179,6 +3179,11 @@ function validateConfig(raw) {
|
|
|
3179
3179
|
|
|
3180
3180
|
// src/config/index.ts
|
|
3181
3181
|
init_constants();
|
|
3182
|
+
var KEY_OPTIONAL_PROVIDER_TYPES = /* @__PURE__ */ new Set(["ollama", "openai-compatible"]);
|
|
3183
|
+
function hasUsableProvider(providers) {
|
|
3184
|
+
if (!providers?.length) return false;
|
|
3185
|
+
return providers.some((p) => KEY_OPTIONAL_PROVIDER_TYPES.has(p.type) || !!p.apiKey);
|
|
3186
|
+
}
|
|
3182
3187
|
var ConfigManager = class {
|
|
3183
3188
|
config;
|
|
3184
3189
|
keystore;
|
|
@@ -7467,6 +7472,10 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
|
|
|
7467
7472
|
const worker = new T3Worker(this.router, this.toolRegistry, this.id);
|
|
7468
7473
|
if (this.store) worker.setStore(this.store, taskId);
|
|
7469
7474
|
worker.setPeerBus(this.t3PeerBus);
|
|
7475
|
+
if (this.permissionEscalator) worker.setPermissionEscalator(this.permissionEscalator);
|
|
7476
|
+
if (this.toolCreator) worker.setToolCreator(this.toolCreator);
|
|
7477
|
+
worker.on("log", (e) => this.emit("log", e));
|
|
7478
|
+
worker.on("tier:status", (e) => this.emit("tier:status", e));
|
|
7470
7479
|
worker.on("stream:token", (e) => this.emit("stream:token", e));
|
|
7471
7480
|
worker.on("tool:approval-request", (e) => this.emit("tool:approval-request", {
|
|
7472
7481
|
...e,
|
|
@@ -7818,12 +7827,14 @@ Board guidance (must be followed in the plan): ${decision.note}`,
|
|
|
7818
7827
|
status: "IN_PROGRESS"
|
|
7819
7828
|
});
|
|
7820
7829
|
const okBefore = okCount(allT2Results);
|
|
7830
|
+
const completedSummary = this.summarizeCompletedSections(allT2Results);
|
|
7831
|
+
const correctionContext = [systemContext, completedSummary].filter(Boolean).join("\n\n") || void 0;
|
|
7821
7832
|
const correctionPlan = await this.decomposeTask(`The previous execution plan failed to fully satisfy the original goal or encountered errors.
|
|
7822
7833
|
Review reason: ${reviewResult.reason}
|
|
7823
7834
|
|
|
7824
7835
|
Original goal: ${enrichedPrompt}
|
|
7825
7836
|
|
|
7826
|
-
Create a CORRECTION PLAN that contains only the new sections needed to fix the issues. Do not repeat successful sections
|
|
7837
|
+
Create a CORRECTION PLAN that contains only the new sections needed to fix the issues. Do not repeat successful sections.`, correctionContext);
|
|
7827
7838
|
const correctionResults = await this.dispatchT2Managers(correctionPlan.sections);
|
|
7828
7839
|
allT2Results = [...allT2Results, ...correctionResults];
|
|
7829
7840
|
if (okCount(allT2Results) <= okBefore) {
|
|
@@ -7926,6 +7937,15 @@ In 3-5 terse bullets, flag the most important RISKS, GAPS, or over-/under-decomp
|
|
|
7926
7937
|
return null;
|
|
7927
7938
|
}
|
|
7928
7939
|
}
|
|
7940
|
+
/** Structured, grounded summary of what's already done — used to keep
|
|
7941
|
+
* corrective replan passes from re-emitting completed sections. */
|
|
7942
|
+
summarizeCompletedSections(results) {
|
|
7943
|
+
const done = results.filter((r) => r.status === "COMPLETED" || r.status === "PARTIAL");
|
|
7944
|
+
if (done.length === 0) return "";
|
|
7945
|
+
const lines = done.map((r) => `- "${r.sectionTitle}" [${r.status}]: ${(r.sectionSummary || "(no summary)").slice(0, 300)}`);
|
|
7946
|
+
return `ALREADY COMPLETED SECTIONS (do not redo these \u2014 plan only what's still missing):
|
|
7947
|
+
${lines.join("\n")}`;
|
|
7948
|
+
}
|
|
7929
7949
|
async decomposeTask(prompt, systemContext) {
|
|
7930
7950
|
const db = this.router.getWorldStateDB?.();
|
|
7931
7951
|
let worldStateContext = "";
|
|
@@ -8193,7 +8213,7 @@ Leave dependsOn empty for sections that can run immediately in parallel.`;
|
|
|
8193
8213
|
}
|
|
8194
8214
|
}
|
|
8195
8215
|
if (readyIds.length === 0) return;
|
|
8196
|
-
|
|
8216
|
+
const runOne = async (id) => {
|
|
8197
8217
|
resultMap.set(id, null);
|
|
8198
8218
|
const index = sections.findIndex((s) => s.sectionId === id);
|
|
8199
8219
|
const section = sections[index];
|
|
@@ -8233,7 +8253,14 @@ Leave dependsOn empty for sections that can run immediately in parallel.`;
|
|
|
8233
8253
|
for (const dependentId of adj.get(id) ?? /* @__PURE__ */ new Set()) {
|
|
8234
8254
|
inDegree.set(dependentId, Math.max(0, (inDegree.get(dependentId) ?? 1) - 1));
|
|
8235
8255
|
}
|
|
8236
|
-
}
|
|
8256
|
+
};
|
|
8257
|
+
if (this.router.getT3ExecutionMode?.() === "sequential") {
|
|
8258
|
+
for (const id of readyIds) {
|
|
8259
|
+
await runOne(id);
|
|
8260
|
+
}
|
|
8261
|
+
} else {
|
|
8262
|
+
await Promise.all(readyIds.map(runOne));
|
|
8263
|
+
}
|
|
8237
8264
|
if (Array.from(inDegree.values()).some((deg) => deg === 0) && resultMap.size < totalSections) {
|
|
8238
8265
|
await executeWave();
|
|
8239
8266
|
}
|
|
@@ -10037,6 +10064,13 @@ var PermissionEscalator = class extends EventEmitter {
|
|
|
10037
10064
|
* All T3 workers under the same T2 share cached decisions for the same tool.
|
|
10038
10065
|
*/
|
|
10039
10066
|
sessionCache = /* @__PURE__ */ new Map();
|
|
10067
|
+
/**
|
|
10068
|
+
* Task-wide cache keyed by `toolName` alone, for USER- and T1-level
|
|
10069
|
+
* "always" decisions — these are meant to cover every sibling T2/T3 in the
|
|
10070
|
+
* run, not just the one that happened to ask first (see PermissionDecision
|
|
10071
|
+
* doc comment: "task-wide for T1").
|
|
10072
|
+
*/
|
|
10073
|
+
taskWideCache = /* @__PURE__ */ new Map();
|
|
10040
10074
|
t2Evaluator;
|
|
10041
10075
|
t1Evaluator;
|
|
10042
10076
|
/** Pending user-decision resolvers keyed by request ID */
|
|
@@ -10065,6 +10099,15 @@ var PermissionEscalator = class extends EventEmitter {
|
|
|
10065
10099
|
* Returns a PermissionDecision from whichever tier was able to decide.
|
|
10066
10100
|
*/
|
|
10067
10101
|
async requestPermission(req) {
|
|
10102
|
+
if (!req.forceReprompt && this.taskWideCache.has(req.toolName)) {
|
|
10103
|
+
return {
|
|
10104
|
+
requestId: req.id,
|
|
10105
|
+
approved: this.taskWideCache.get(req.toolName),
|
|
10106
|
+
always: true,
|
|
10107
|
+
decidedBy: "T1",
|
|
10108
|
+
reasoning: "Cached from a previous task-wide decision in this session"
|
|
10109
|
+
};
|
|
10110
|
+
}
|
|
10068
10111
|
const cacheKey = `${req.parentT2Id}:${req.toolName}`;
|
|
10069
10112
|
if (!req.forceReprompt && this.sessionCache.has(cacheKey)) {
|
|
10070
10113
|
return {
|
|
@@ -10109,7 +10152,7 @@ var PermissionEscalator = class extends EventEmitter {
|
|
|
10109
10152
|
try {
|
|
10110
10153
|
const t1Decision = await this.t1Evaluator(req);
|
|
10111
10154
|
if (t1Decision !== null) {
|
|
10112
|
-
if (t1Decision.always) this.
|
|
10155
|
+
if (t1Decision.always) this.taskWideCache.set(req.toolName, t1Decision.approved);
|
|
10113
10156
|
return t1Decision;
|
|
10114
10157
|
}
|
|
10115
10158
|
} catch {
|
|
@@ -10139,7 +10182,7 @@ var PermissionEscalator = class extends EventEmitter {
|
|
|
10139
10182
|
const wrappedResolver = (decision) => {
|
|
10140
10183
|
if (timer) clearTimeout(timer);
|
|
10141
10184
|
if (decision.always) {
|
|
10142
|
-
this.
|
|
10185
|
+
this.taskWideCache.set(req.toolName, decision.approved);
|
|
10143
10186
|
}
|
|
10144
10187
|
resolve(decision);
|
|
10145
10188
|
};
|
|
@@ -15218,11 +15261,18 @@ function SetupWizard({ workspacePath, onComplete }) {
|
|
|
15218
15261
|
}
|
|
15219
15262
|
});
|
|
15220
15263
|
const currentEntry = state.entries[state.currentEntryIdx];
|
|
15264
|
+
const rejectIfBlank = useCallback((val, message) => {
|
|
15265
|
+
if (val.trim()) return false;
|
|
15266
|
+
dispatch({ type: "SET_ERROR", error: message });
|
|
15267
|
+
return true;
|
|
15268
|
+
}, []);
|
|
15221
15269
|
const handleFieldSubmit = useCallback((val) => {
|
|
15222
15270
|
if (!currentEntry) return;
|
|
15223
15271
|
if (currentEntry.type === "azure") {
|
|
15224
15272
|
if (fieldStage === "deploymentName") {
|
|
15273
|
+
if (rejectIfBlank(val, "Deployment name is required.")) return;
|
|
15225
15274
|
dispatch({ type: "SET_ENTRY_FIELD", field: "deploymentName", value: val });
|
|
15275
|
+
dispatch({ type: "SET_ERROR", error: "" });
|
|
15226
15276
|
setFieldBuffer("");
|
|
15227
15277
|
if (currentEntry.baseUrl && currentEntry.apiKey && currentEntry.apiVersion) {
|
|
15228
15278
|
setFieldStage("askMore");
|
|
@@ -15230,38 +15280,50 @@ function SetupWizard({ workspacePath, onComplete }) {
|
|
|
15230
15280
|
setFieldStage("baseUrl");
|
|
15231
15281
|
}
|
|
15232
15282
|
} else if (fieldStage === "baseUrl") {
|
|
15283
|
+
if (rejectIfBlank(val, "Azure endpoint URL is required.")) return;
|
|
15233
15284
|
dispatch({ type: "SET_ENTRY_FIELD", field: "baseUrl", value: val });
|
|
15285
|
+
dispatch({ type: "SET_ERROR", error: "" });
|
|
15234
15286
|
setFieldBuffer("");
|
|
15235
15287
|
setFieldStage("apiKey");
|
|
15236
15288
|
} else if (fieldStage === "apiKey") {
|
|
15289
|
+
if (rejectIfBlank(val, "API key is required.")) return;
|
|
15237
15290
|
dispatch({ type: "SET_ENTRY_FIELD", field: "apiKey", value: val });
|
|
15291
|
+
dispatch({ type: "SET_ERROR", error: "" });
|
|
15238
15292
|
setFieldBuffer("");
|
|
15239
15293
|
setFieldStage("apiVersion");
|
|
15240
15294
|
} else if (fieldStage === "apiVersion") {
|
|
15241
15295
|
dispatch({ type: "SET_ENTRY_FIELD", field: "apiVersion", value: val || "2024-08-01-preview" });
|
|
15296
|
+
dispatch({ type: "SET_ERROR", error: "" });
|
|
15242
15297
|
setFieldBuffer("");
|
|
15243
15298
|
setFieldStage("askMore");
|
|
15244
15299
|
}
|
|
15245
15300
|
} else if (currentEntry.type === "openai-compatible") {
|
|
15246
15301
|
if (fieldStage === "label") {
|
|
15247
15302
|
dispatch({ type: "SET_ENTRY_FIELD", field: "label", value: val || currentEntry.label });
|
|
15303
|
+
dispatch({ type: "SET_ERROR", error: "" });
|
|
15248
15304
|
setFieldBuffer("");
|
|
15249
15305
|
setFieldStage("baseUrl");
|
|
15250
15306
|
} else if (fieldStage === "baseUrl") {
|
|
15307
|
+
if (rejectIfBlank(val, "Base URL is required.")) return;
|
|
15251
15308
|
dispatch({ type: "SET_ENTRY_FIELD", field: "baseUrl", value: val });
|
|
15309
|
+
dispatch({ type: "SET_ERROR", error: "" });
|
|
15252
15310
|
setFieldBuffer("");
|
|
15253
15311
|
setFieldStage("apiKey");
|
|
15254
15312
|
} else if (fieldStage === "apiKey") {
|
|
15255
15313
|
dispatch({ type: "SET_ENTRY_FIELD", field: "apiKey", value: val });
|
|
15314
|
+
dispatch({ type: "SET_ERROR", error: "" });
|
|
15256
15315
|
setFieldBuffer("");
|
|
15257
15316
|
setFieldStage("askMore");
|
|
15258
15317
|
}
|
|
15259
15318
|
} else if (currentEntry.type === "ollama") {
|
|
15260
15319
|
dispatch({ type: "SET_ENTRY_FIELD", field: "baseUrl", value: val || "http://localhost:11434" });
|
|
15320
|
+
dispatch({ type: "SET_ERROR", error: "" });
|
|
15261
15321
|
setFieldBuffer("");
|
|
15262
15322
|
setFieldStage("askMore");
|
|
15263
15323
|
} else {
|
|
15324
|
+
if (rejectIfBlank(val, "API key is required.")) return;
|
|
15264
15325
|
dispatch({ type: "SET_ENTRY_FIELD", field: "apiKey", value: val });
|
|
15326
|
+
dispatch({ type: "SET_ERROR", error: "" });
|
|
15265
15327
|
setFieldBuffer("");
|
|
15266
15328
|
const nextEntry = state.entries[state.currentEntryIdx + 1];
|
|
15267
15329
|
if (nextEntry) {
|
|
@@ -15269,7 +15331,7 @@ function SetupWizard({ workspacePath, onComplete }) {
|
|
|
15269
15331
|
}
|
|
15270
15332
|
dispatch({ type: "NEXT_ENTRY" });
|
|
15271
15333
|
}
|
|
15272
|
-
}, [currentEntry, fieldStage]);
|
|
15334
|
+
}, [currentEntry, fieldStage, rejectIfBlank, state.entries, state.currentEntryIdx]);
|
|
15273
15335
|
if (state.step === "PROVIDER_SELECT") {
|
|
15274
15336
|
return /* @__PURE__ */ jsxs(Frame, { theme, phase: "keys", children: [
|
|
15275
15337
|
/* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
@@ -16204,6 +16266,16 @@ var DashboardServer = class {
|
|
|
16204
16266
|
getSocket() {
|
|
16205
16267
|
return this.socket;
|
|
16206
16268
|
}
|
|
16269
|
+
/**
|
|
16270
|
+
* Rebind the workspace tasks execute in — e.g. the desktop app's Code view
|
|
16271
|
+
* opening a different project folder — without tearing down the socket
|
|
16272
|
+
* server (which would drop the port/auth token/connection mid-session).
|
|
16273
|
+
* The next `cascade:run` picks this up immediately since `this.workspacePath`
|
|
16274
|
+
* is read live per-run (see onCascadeRun below).
|
|
16275
|
+
*/
|
|
16276
|
+
setWorkspacePath(workspacePath) {
|
|
16277
|
+
this.workspacePath = workspacePath;
|
|
16278
|
+
}
|
|
16207
16279
|
/**
|
|
16208
16280
|
* Write the in-memory config back to the workspace config file so mutations
|
|
16209
16281
|
* made over the socket (Settings → Save) persist across restarts. Best-effort:
|
|
@@ -17507,7 +17579,7 @@ async function startRepl(options) {
|
|
|
17507
17579
|
process.exit(1);
|
|
17508
17580
|
}
|
|
17509
17581
|
let config = cm.getConfig();
|
|
17510
|
-
const needsSetup = !config.providers
|
|
17582
|
+
const needsSetup = !hasUsableProvider(config.providers);
|
|
17511
17583
|
if (needsSetup) {
|
|
17512
17584
|
console.log(chalk9.magenta(" \u25C8 No providers configured \u2014 launching setup wizard\u2026"));
|
|
17513
17585
|
console.log();
|
|
@@ -17548,7 +17620,7 @@ async function runHeadless(prompt, options) {
|
|
|
17548
17620
|
process.exit(1);
|
|
17549
17621
|
}
|
|
17550
17622
|
const config = cm.getConfig();
|
|
17551
|
-
const needsSetup = !config.providers
|
|
17623
|
+
const needsSetup = !hasUsableProvider(config.providers);
|
|
17552
17624
|
if (needsSetup) {
|
|
17553
17625
|
console.error(chalk9.red("No providers configured. Run `cascade init` first."));
|
|
17554
17626
|
process.exit(1);
|