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/desktop-core.cjs
CHANGED
|
@@ -222595,7 +222595,7 @@ Anthropic.Models = Models2;
|
|
|
222595
222595
|
Anthropic.Beta = Beta;
|
|
222596
222596
|
|
|
222597
222597
|
// src/constants.ts
|
|
222598
|
-
var CASCADE_VERSION = "0.
|
|
222598
|
+
var CASCADE_VERSION = "0.16.0";
|
|
222599
222599
|
var CASCADE_CONFIG_DIR = ".cascade";
|
|
222600
222600
|
var CASCADE_MD_FILE = "CASCADE.md";
|
|
222601
222601
|
var CASCADE_IGNORE_FILE = ".cascadeignore";
|
|
@@ -253816,6 +253816,10 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
|
|
|
253816
253816
|
const worker = new T3Worker(this.router, this.toolRegistry, this.id);
|
|
253817
253817
|
if (this.store) worker.setStore(this.store, taskId);
|
|
253818
253818
|
worker.setPeerBus(this.t3PeerBus);
|
|
253819
|
+
if (this.permissionEscalator) worker.setPermissionEscalator(this.permissionEscalator);
|
|
253820
|
+
if (this.toolCreator) worker.setToolCreator(this.toolCreator);
|
|
253821
|
+
worker.on("log", (e3) => this.emit("log", e3));
|
|
253822
|
+
worker.on("tier:status", (e3) => this.emit("tier:status", e3));
|
|
253819
253823
|
worker.on("stream:token", (e3) => this.emit("stream:token", e3));
|
|
253820
253824
|
worker.on("tool:approval-request", (e3) => this.emit("tool:approval-request", {
|
|
253821
253825
|
...e3,
|
|
@@ -254164,12 +254168,14 @@ Board guidance (must be followed in the plan): ${decision.note}`,
|
|
|
254164
254168
|
status: "IN_PROGRESS"
|
|
254165
254169
|
});
|
|
254166
254170
|
const okBefore = okCount(allT2Results);
|
|
254171
|
+
const completedSummary = this.summarizeCompletedSections(allT2Results);
|
|
254172
|
+
const correctionContext = [systemContext, completedSummary].filter(Boolean).join("\n\n") || void 0;
|
|
254167
254173
|
const correctionPlan = await this.decomposeTask(`The previous execution plan failed to fully satisfy the original goal or encountered errors.
|
|
254168
254174
|
Review reason: ${reviewResult.reason}
|
|
254169
254175
|
|
|
254170
254176
|
Original goal: ${enrichedPrompt}
|
|
254171
254177
|
|
|
254172
|
-
Create a CORRECTION PLAN that contains only the new sections needed to fix the issues. Do not repeat successful sections
|
|
254178
|
+
Create a CORRECTION PLAN that contains only the new sections needed to fix the issues. Do not repeat successful sections.`, correctionContext);
|
|
254173
254179
|
const correctionResults = await this.dispatchT2Managers(correctionPlan.sections);
|
|
254174
254180
|
allT2Results = [...allT2Results, ...correctionResults];
|
|
254175
254181
|
if (okCount(allT2Results) <= okBefore) {
|
|
@@ -254272,6 +254278,15 @@ In 3-5 terse bullets, flag the most important RISKS, GAPS, or over-/under-decomp
|
|
|
254272
254278
|
return null;
|
|
254273
254279
|
}
|
|
254274
254280
|
}
|
|
254281
|
+
/** Structured, grounded summary of what's already done — used to keep
|
|
254282
|
+
* corrective replan passes from re-emitting completed sections. */
|
|
254283
|
+
summarizeCompletedSections(results) {
|
|
254284
|
+
const done = results.filter((r4) => r4.status === "COMPLETED" || r4.status === "PARTIAL");
|
|
254285
|
+
if (done.length === 0) return "";
|
|
254286
|
+
const lines = done.map((r4) => `- "${r4.sectionTitle}" [${r4.status}]: ${(r4.sectionSummary || "(no summary)").slice(0, 300)}`);
|
|
254287
|
+
return `ALREADY COMPLETED SECTIONS (do not redo these \u2014 plan only what's still missing):
|
|
254288
|
+
${lines.join("\n")}`;
|
|
254289
|
+
}
|
|
254275
254290
|
async decomposeTask(prompt, systemContext) {
|
|
254276
254291
|
const db = this.router.getWorldStateDB?.();
|
|
254277
254292
|
let worldStateContext = "";
|
|
@@ -254539,7 +254554,7 @@ Leave dependsOn empty for sections that can run immediately in parallel.`;
|
|
|
254539
254554
|
}
|
|
254540
254555
|
}
|
|
254541
254556
|
if (readyIds.length === 0) return;
|
|
254542
|
-
|
|
254557
|
+
const runOne = async (id) => {
|
|
254543
254558
|
resultMap.set(id, null);
|
|
254544
254559
|
const index = sections.findIndex((s3) => s3.sectionId === id);
|
|
254545
254560
|
const section = sections[index];
|
|
@@ -254579,7 +254594,14 @@ Leave dependsOn empty for sections that can run immediately in parallel.`;
|
|
|
254579
254594
|
for (const dependentId of adj.get(id) ?? /* @__PURE__ */ new Set()) {
|
|
254580
254595
|
inDegree.set(dependentId, Math.max(0, (inDegree.get(dependentId) ?? 1) - 1));
|
|
254581
254596
|
}
|
|
254582
|
-
}
|
|
254597
|
+
};
|
|
254598
|
+
if (this.router.getT3ExecutionMode?.() === "sequential") {
|
|
254599
|
+
for (const id of readyIds) {
|
|
254600
|
+
await runOne(id);
|
|
254601
|
+
}
|
|
254602
|
+
} else {
|
|
254603
|
+
await Promise.all(readyIds.map(runOne));
|
|
254604
|
+
}
|
|
254583
254605
|
if (Array.from(inDegree.values()).some((deg) => deg === 0) && resultMap.size < totalSections) {
|
|
254584
254606
|
await executeWave();
|
|
254585
254607
|
}
|
|
@@ -294549,6 +294571,13 @@ var PermissionEscalator = class extends EventEmitter__default.default {
|
|
|
294549
294571
|
* All T3 workers under the same T2 share cached decisions for the same tool.
|
|
294550
294572
|
*/
|
|
294551
294573
|
sessionCache = /* @__PURE__ */ new Map();
|
|
294574
|
+
/**
|
|
294575
|
+
* Task-wide cache keyed by `toolName` alone, for USER- and T1-level
|
|
294576
|
+
* "always" decisions — these are meant to cover every sibling T2/T3 in the
|
|
294577
|
+
* run, not just the one that happened to ask first (see PermissionDecision
|
|
294578
|
+
* doc comment: "task-wide for T1").
|
|
294579
|
+
*/
|
|
294580
|
+
taskWideCache = /* @__PURE__ */ new Map();
|
|
294552
294581
|
t2Evaluator;
|
|
294553
294582
|
t1Evaluator;
|
|
294554
294583
|
/** Pending user-decision resolvers keyed by request ID */
|
|
@@ -294577,6 +294606,15 @@ var PermissionEscalator = class extends EventEmitter__default.default {
|
|
|
294577
294606
|
* Returns a PermissionDecision from whichever tier was able to decide.
|
|
294578
294607
|
*/
|
|
294579
294608
|
async requestPermission(req) {
|
|
294609
|
+
if (!req.forceReprompt && this.taskWideCache.has(req.toolName)) {
|
|
294610
|
+
return {
|
|
294611
|
+
requestId: req.id,
|
|
294612
|
+
approved: this.taskWideCache.get(req.toolName),
|
|
294613
|
+
always: true,
|
|
294614
|
+
decidedBy: "T1",
|
|
294615
|
+
reasoning: "Cached from a previous task-wide decision in this session"
|
|
294616
|
+
};
|
|
294617
|
+
}
|
|
294580
294618
|
const cacheKey = `${req.parentT2Id}:${req.toolName}`;
|
|
294581
294619
|
if (!req.forceReprompt && this.sessionCache.has(cacheKey)) {
|
|
294582
294620
|
return {
|
|
@@ -294621,7 +294659,7 @@ var PermissionEscalator = class extends EventEmitter__default.default {
|
|
|
294621
294659
|
try {
|
|
294622
294660
|
const t1Decision = await this.t1Evaluator(req);
|
|
294623
294661
|
if (t1Decision !== null) {
|
|
294624
|
-
if (t1Decision.always) this.
|
|
294662
|
+
if (t1Decision.always) this.taskWideCache.set(req.toolName, t1Decision.approved);
|
|
294625
294663
|
return t1Decision;
|
|
294626
294664
|
}
|
|
294627
294665
|
} catch {
|
|
@@ -294651,7 +294689,7 @@ var PermissionEscalator = class extends EventEmitter__default.default {
|
|
|
294651
294689
|
const wrappedResolver = (decision) => {
|
|
294652
294690
|
if (timer) clearTimeout(timer);
|
|
294653
294691
|
if (decision.always) {
|
|
294654
|
-
this.
|
|
294692
|
+
this.taskWideCache.set(req.toolName, decision.approved);
|
|
294655
294693
|
}
|
|
294656
294694
|
resolve(decision);
|
|
294657
294695
|
};
|
|
@@ -299359,6 +299397,16 @@ var DashboardServer = class {
|
|
|
299359
299397
|
getSocket() {
|
|
299360
299398
|
return this.socket;
|
|
299361
299399
|
}
|
|
299400
|
+
/**
|
|
299401
|
+
* Rebind the workspace tasks execute in — e.g. the desktop app's Code view
|
|
299402
|
+
* opening a different project folder — without tearing down the socket
|
|
299403
|
+
* server (which would drop the port/auth token/connection mid-session).
|
|
299404
|
+
* The next `cascade:run` picks this up immediately since `this.workspacePath`
|
|
299405
|
+
* is read live per-run (see onCascadeRun below).
|
|
299406
|
+
*/
|
|
299407
|
+
setWorkspacePath(workspacePath) {
|
|
299408
|
+
this.workspacePath = workspacePath;
|
|
299409
|
+
}
|
|
299362
299410
|
/**
|
|
299363
299411
|
* Write the in-memory config back to the workspace config file so mutations
|
|
299364
299412
|
* made over the socket (Settings → Save) persist across restarts. Best-effort:
|
package/dist/index.cjs
CHANGED
|
@@ -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.16.0";
|
|
240
240
|
var CASCADE_CONFIG_DIR = ".cascade";
|
|
241
241
|
var CASCADE_MD_FILE = "CASCADE.md";
|
|
242
242
|
var CASCADE_IGNORE_FILE = ".cascadeignore";
|
|
@@ -5552,6 +5552,10 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
|
|
|
5552
5552
|
const worker = new T3Worker(this.router, this.toolRegistry, this.id);
|
|
5553
5553
|
if (this.store) worker.setStore(this.store, taskId);
|
|
5554
5554
|
worker.setPeerBus(this.t3PeerBus);
|
|
5555
|
+
if (this.permissionEscalator) worker.setPermissionEscalator(this.permissionEscalator);
|
|
5556
|
+
if (this.toolCreator) worker.setToolCreator(this.toolCreator);
|
|
5557
|
+
worker.on("log", (e) => this.emit("log", e));
|
|
5558
|
+
worker.on("tier:status", (e) => this.emit("tier:status", e));
|
|
5555
5559
|
worker.on("stream:token", (e) => this.emit("stream:token", e));
|
|
5556
5560
|
worker.on("tool:approval-request", (e) => this.emit("tool:approval-request", {
|
|
5557
5561
|
...e,
|
|
@@ -5900,12 +5904,14 @@ Board guidance (must be followed in the plan): ${decision.note}`,
|
|
|
5900
5904
|
status: "IN_PROGRESS"
|
|
5901
5905
|
});
|
|
5902
5906
|
const okBefore = okCount(allT2Results);
|
|
5907
|
+
const completedSummary = this.summarizeCompletedSections(allT2Results);
|
|
5908
|
+
const correctionContext = [systemContext, completedSummary].filter(Boolean).join("\n\n") || void 0;
|
|
5903
5909
|
const correctionPlan = await this.decomposeTask(`The previous execution plan failed to fully satisfy the original goal or encountered errors.
|
|
5904
5910
|
Review reason: ${reviewResult.reason}
|
|
5905
5911
|
|
|
5906
5912
|
Original goal: ${enrichedPrompt}
|
|
5907
5913
|
|
|
5908
|
-
Create a CORRECTION PLAN that contains only the new sections needed to fix the issues. Do not repeat successful sections
|
|
5914
|
+
Create a CORRECTION PLAN that contains only the new sections needed to fix the issues. Do not repeat successful sections.`, correctionContext);
|
|
5909
5915
|
const correctionResults = await this.dispatchT2Managers(correctionPlan.sections);
|
|
5910
5916
|
allT2Results = [...allT2Results, ...correctionResults];
|
|
5911
5917
|
if (okCount(allT2Results) <= okBefore) {
|
|
@@ -6008,6 +6014,15 @@ In 3-5 terse bullets, flag the most important RISKS, GAPS, or over-/under-decomp
|
|
|
6008
6014
|
return null;
|
|
6009
6015
|
}
|
|
6010
6016
|
}
|
|
6017
|
+
/** Structured, grounded summary of what's already done — used to keep
|
|
6018
|
+
* corrective replan passes from re-emitting completed sections. */
|
|
6019
|
+
summarizeCompletedSections(results) {
|
|
6020
|
+
const done = results.filter((r) => r.status === "COMPLETED" || r.status === "PARTIAL");
|
|
6021
|
+
if (done.length === 0) return "";
|
|
6022
|
+
const lines = done.map((r) => `- "${r.sectionTitle}" [${r.status}]: ${(r.sectionSummary || "(no summary)").slice(0, 300)}`);
|
|
6023
|
+
return `ALREADY COMPLETED SECTIONS (do not redo these \u2014 plan only what's still missing):
|
|
6024
|
+
${lines.join("\n")}`;
|
|
6025
|
+
}
|
|
6011
6026
|
async decomposeTask(prompt, systemContext) {
|
|
6012
6027
|
const db = this.router.getWorldStateDB?.();
|
|
6013
6028
|
let worldStateContext = "";
|
|
@@ -6275,7 +6290,7 @@ Leave dependsOn empty for sections that can run immediately in parallel.`;
|
|
|
6275
6290
|
}
|
|
6276
6291
|
}
|
|
6277
6292
|
if (readyIds.length === 0) return;
|
|
6278
|
-
|
|
6293
|
+
const runOne = async (id) => {
|
|
6279
6294
|
resultMap.set(id, null);
|
|
6280
6295
|
const index = sections.findIndex((s) => s.sectionId === id);
|
|
6281
6296
|
const section = sections[index];
|
|
@@ -6315,7 +6330,14 @@ Leave dependsOn empty for sections that can run immediately in parallel.`;
|
|
|
6315
6330
|
for (const dependentId of adj.get(id) ?? /* @__PURE__ */ new Set()) {
|
|
6316
6331
|
inDegree.set(dependentId, Math.max(0, (inDegree.get(dependentId) ?? 1) - 1));
|
|
6317
6332
|
}
|
|
6318
|
-
}
|
|
6333
|
+
};
|
|
6334
|
+
if (this.router.getT3ExecutionMode?.() === "sequential") {
|
|
6335
|
+
for (const id of readyIds) {
|
|
6336
|
+
await runOne(id);
|
|
6337
|
+
}
|
|
6338
|
+
} else {
|
|
6339
|
+
await Promise.all(readyIds.map(runOne));
|
|
6340
|
+
}
|
|
6319
6341
|
if (Array.from(inDegree.values()).some((deg) => deg === 0) && resultMap.size < totalSections) {
|
|
6320
6342
|
await executeWave();
|
|
6321
6343
|
}
|
|
@@ -8113,6 +8135,13 @@ var PermissionEscalator = class extends EventEmitter__default.default {
|
|
|
8113
8135
|
* All T3 workers under the same T2 share cached decisions for the same tool.
|
|
8114
8136
|
*/
|
|
8115
8137
|
sessionCache = /* @__PURE__ */ new Map();
|
|
8138
|
+
/**
|
|
8139
|
+
* Task-wide cache keyed by `toolName` alone, for USER- and T1-level
|
|
8140
|
+
* "always" decisions — these are meant to cover every sibling T2/T3 in the
|
|
8141
|
+
* run, not just the one that happened to ask first (see PermissionDecision
|
|
8142
|
+
* doc comment: "task-wide for T1").
|
|
8143
|
+
*/
|
|
8144
|
+
taskWideCache = /* @__PURE__ */ new Map();
|
|
8116
8145
|
t2Evaluator;
|
|
8117
8146
|
t1Evaluator;
|
|
8118
8147
|
/** Pending user-decision resolvers keyed by request ID */
|
|
@@ -8141,6 +8170,15 @@ var PermissionEscalator = class extends EventEmitter__default.default {
|
|
|
8141
8170
|
* Returns a PermissionDecision from whichever tier was able to decide.
|
|
8142
8171
|
*/
|
|
8143
8172
|
async requestPermission(req) {
|
|
8173
|
+
if (!req.forceReprompt && this.taskWideCache.has(req.toolName)) {
|
|
8174
|
+
return {
|
|
8175
|
+
requestId: req.id,
|
|
8176
|
+
approved: this.taskWideCache.get(req.toolName),
|
|
8177
|
+
always: true,
|
|
8178
|
+
decidedBy: "T1",
|
|
8179
|
+
reasoning: "Cached from a previous task-wide decision in this session"
|
|
8180
|
+
};
|
|
8181
|
+
}
|
|
8144
8182
|
const cacheKey = `${req.parentT2Id}:${req.toolName}`;
|
|
8145
8183
|
if (!req.forceReprompt && this.sessionCache.has(cacheKey)) {
|
|
8146
8184
|
return {
|
|
@@ -8185,7 +8223,7 @@ var PermissionEscalator = class extends EventEmitter__default.default {
|
|
|
8185
8223
|
try {
|
|
8186
8224
|
const t1Decision = await this.t1Evaluator(req);
|
|
8187
8225
|
if (t1Decision !== null) {
|
|
8188
|
-
if (t1Decision.always) this.
|
|
8226
|
+
if (t1Decision.always) this.taskWideCache.set(req.toolName, t1Decision.approved);
|
|
8189
8227
|
return t1Decision;
|
|
8190
8228
|
}
|
|
8191
8229
|
} catch {
|
|
@@ -8215,7 +8253,7 @@ var PermissionEscalator = class extends EventEmitter__default.default {
|
|
|
8215
8253
|
const wrappedResolver = (decision) => {
|
|
8216
8254
|
if (timer) clearTimeout(timer);
|
|
8217
8255
|
if (decision.always) {
|
|
8218
|
-
this.
|
|
8256
|
+
this.taskWideCache.set(req.toolName, decision.approved);
|
|
8219
8257
|
}
|
|
8220
8258
|
resolve(decision);
|
|
8221
8259
|
};
|
|
@@ -12134,6 +12172,16 @@ var DashboardServer = class {
|
|
|
12134
12172
|
getSocket() {
|
|
12135
12173
|
return this.socket;
|
|
12136
12174
|
}
|
|
12175
|
+
/**
|
|
12176
|
+
* Rebind the workspace tasks execute in — e.g. the desktop app's Code view
|
|
12177
|
+
* opening a different project folder — without tearing down the socket
|
|
12178
|
+
* server (which would drop the port/auth token/connection mid-session).
|
|
12179
|
+
* The next `cascade:run` picks this up immediately since `this.workspacePath`
|
|
12180
|
+
* is read live per-run (see onCascadeRun below).
|
|
12181
|
+
*/
|
|
12182
|
+
setWorkspacePath(workspacePath) {
|
|
12183
|
+
this.workspacePath = workspacePath;
|
|
12184
|
+
}
|
|
12137
12185
|
/**
|
|
12138
12186
|
* Write the in-memory config back to the workspace config file so mutations
|
|
12139
12187
|
* made over the socket (Settings → Save) persist across restarts. Best-effort:
|