cascade-ai 0.76.0 → 0.77.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/README.md +2 -2
- package/dist/cli.cjs +948 -515
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +931 -498
- package/dist/cli.js.map +1 -1
- package/dist/desktop-core.cjs +24340 -3171
- package/dist/index.cjs +899 -475
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1139 -16
- package/dist/index.d.ts +1139 -16
- package/dist/index.js +882 -459
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/web/dist/assets/index-DoU1RNKq.js +246 -0
- package/web/dist/assets/react-DmRRAgLv.js +1 -0
- package/web/dist/assets/{reactflow-Clz8xC7C.js → reactflow-CkXCC9kc.js} +2 -2
- package/web/dist/assets/{socketio-BcxXcwBL.js → socketio-SYmKJpIj.js} +1 -1
- package/web/dist/index.html +3 -3
- package/web/dist/assets/index-DFRrUnoJ.js +0 -246
- package/web/dist/assets/react-BP1N17hq.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import Database2 from 'better-sqlite3';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import path28, { dirname } from 'path';
|
|
3
|
+
import fs27, { promises, mkdirSync, writeFileSync, existsSync, readFileSync } from 'fs';
|
|
4
4
|
import os6 from 'os';
|
|
5
5
|
import crypto, { randomUUID, randomBytes, createHash, timingSafeEqual, webcrypto } from 'crypto';
|
|
6
6
|
import EventEmitter, { setMaxListeners } from 'events';
|
|
7
7
|
import { glob } from 'glob';
|
|
8
8
|
import Anthropic from '@anthropic-ai/sdk';
|
|
9
|
-
import
|
|
9
|
+
import dnsCallback from 'dns';
|
|
10
10
|
import http, { createServer } from 'http';
|
|
11
11
|
import https from 'https';
|
|
12
12
|
import zlib from 'zlib';
|
|
@@ -23,6 +23,7 @@ import { simpleGit } from 'simple-git';
|
|
|
23
23
|
import PDFDocument from 'pdfkit';
|
|
24
24
|
import dns2 from 'dns/promises';
|
|
25
25
|
import net from 'net';
|
|
26
|
+
import { Agent } from 'undici';
|
|
26
27
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
27
28
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
28
29
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
@@ -132,16 +133,16 @@ var require_isarray = __commonJS({
|
|
|
132
133
|
}
|
|
133
134
|
});
|
|
134
135
|
|
|
135
|
-
// node_modules/
|
|
136
|
+
// node_modules/readable-stream/lib/internal/streams/stream.js
|
|
136
137
|
var require_stream = __commonJS({
|
|
137
|
-
"node_modules/
|
|
138
|
+
"node_modules/readable-stream/lib/internal/streams/stream.js"(exports, module) {
|
|
138
139
|
module.exports = __require("stream");
|
|
139
140
|
}
|
|
140
141
|
});
|
|
141
142
|
|
|
142
|
-
// node_modules/
|
|
143
|
+
// node_modules/readable-stream/node_modules/safe-buffer/index.js
|
|
143
144
|
var require_safe_buffer = __commonJS({
|
|
144
|
-
"node_modules/
|
|
145
|
+
"node_modules/readable-stream/node_modules/safe-buffer/index.js"(exports, module) {
|
|
145
146
|
var buffer = __require("buffer");
|
|
146
147
|
var Buffer2 = buffer.Buffer;
|
|
147
148
|
function copyProps(src, dst) {
|
|
@@ -259,7 +260,7 @@ var require_util = __commonJS({
|
|
|
259
260
|
typeof arg === "undefined";
|
|
260
261
|
}
|
|
261
262
|
exports.isPrimitive = isPrimitive;
|
|
262
|
-
exports.isBuffer = Buffer.isBuffer;
|
|
263
|
+
exports.isBuffer = __require("buffer").Buffer.isBuffer;
|
|
263
264
|
function objectToString(o) {
|
|
264
265
|
return Object.prototype.toString.call(o);
|
|
265
266
|
}
|
|
@@ -312,9 +313,9 @@ var require_inherits = __commonJS({
|
|
|
312
313
|
}
|
|
313
314
|
});
|
|
314
315
|
|
|
315
|
-
// node_modules/
|
|
316
|
+
// node_modules/readable-stream/lib/internal/streams/BufferList.js
|
|
316
317
|
var require_BufferList = __commonJS({
|
|
317
|
-
"node_modules/
|
|
318
|
+
"node_modules/readable-stream/lib/internal/streams/BufferList.js"(exports, module) {
|
|
318
319
|
function _classCallCheck(instance, Constructor) {
|
|
319
320
|
if (!(instance instanceof Constructor)) {
|
|
320
321
|
throw new TypeError("Cannot call a class as a function");
|
|
@@ -389,9 +390,9 @@ var require_BufferList = __commonJS({
|
|
|
389
390
|
}
|
|
390
391
|
});
|
|
391
392
|
|
|
392
|
-
// node_modules/
|
|
393
|
+
// node_modules/readable-stream/lib/internal/streams/destroy.js
|
|
393
394
|
var require_destroy = __commonJS({
|
|
394
|
-
"node_modules/
|
|
395
|
+
"node_modules/readable-stream/lib/internal/streams/destroy.js"(exports, module) {
|
|
395
396
|
var pna = require_process_nextick_args();
|
|
396
397
|
function destroy(err, cb) {
|
|
397
398
|
var _this = this;
|
|
@@ -464,9 +465,9 @@ var require_node = __commonJS({
|
|
|
464
465
|
}
|
|
465
466
|
});
|
|
466
467
|
|
|
467
|
-
// node_modules/
|
|
468
|
+
// node_modules/readable-stream/lib/_stream_writable.js
|
|
468
469
|
var require_stream_writable = __commonJS({
|
|
469
|
-
"node_modules/
|
|
470
|
+
"node_modules/readable-stream/lib/_stream_writable.js"(exports, module) {
|
|
470
471
|
var pna = require_process_nextick_args();
|
|
471
472
|
module.exports = Writable;
|
|
472
473
|
function CorkedRequest(state) {
|
|
@@ -903,9 +904,9 @@ var require_stream_writable = __commonJS({
|
|
|
903
904
|
}
|
|
904
905
|
});
|
|
905
906
|
|
|
906
|
-
// node_modules/
|
|
907
|
+
// node_modules/readable-stream/lib/_stream_duplex.js
|
|
907
908
|
var require_stream_duplex = __commonJS({
|
|
908
|
-
"node_modules/
|
|
909
|
+
"node_modules/readable-stream/lib/_stream_duplex.js"(exports, module) {
|
|
909
910
|
var pna = require_process_nextick_args();
|
|
910
911
|
var objectKeys = Object.keys || function(obj) {
|
|
911
912
|
var keys2 = [];
|
|
@@ -979,10 +980,67 @@ var require_stream_duplex = __commonJS({
|
|
|
979
980
|
}
|
|
980
981
|
});
|
|
981
982
|
|
|
982
|
-
// node_modules/
|
|
983
|
+
// node_modules/string_decoder/node_modules/safe-buffer/index.js
|
|
984
|
+
var require_safe_buffer2 = __commonJS({
|
|
985
|
+
"node_modules/string_decoder/node_modules/safe-buffer/index.js"(exports, module) {
|
|
986
|
+
var buffer = __require("buffer");
|
|
987
|
+
var Buffer2 = buffer.Buffer;
|
|
988
|
+
function copyProps(src, dst) {
|
|
989
|
+
for (var key in src) {
|
|
990
|
+
dst[key] = src[key];
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
if (Buffer2.from && Buffer2.alloc && Buffer2.allocUnsafe && Buffer2.allocUnsafeSlow) {
|
|
994
|
+
module.exports = buffer;
|
|
995
|
+
} else {
|
|
996
|
+
copyProps(buffer, exports);
|
|
997
|
+
exports.Buffer = SafeBuffer;
|
|
998
|
+
}
|
|
999
|
+
function SafeBuffer(arg, encodingOrOffset, length) {
|
|
1000
|
+
return Buffer2(arg, encodingOrOffset, length);
|
|
1001
|
+
}
|
|
1002
|
+
copyProps(Buffer2, SafeBuffer);
|
|
1003
|
+
SafeBuffer.from = function(arg, encodingOrOffset, length) {
|
|
1004
|
+
if (typeof arg === "number") {
|
|
1005
|
+
throw new TypeError("Argument must not be a number");
|
|
1006
|
+
}
|
|
1007
|
+
return Buffer2(arg, encodingOrOffset, length);
|
|
1008
|
+
};
|
|
1009
|
+
SafeBuffer.alloc = function(size, fill, encoding) {
|
|
1010
|
+
if (typeof size !== "number") {
|
|
1011
|
+
throw new TypeError("Argument must be a number");
|
|
1012
|
+
}
|
|
1013
|
+
var buf = Buffer2(size);
|
|
1014
|
+
if (fill !== void 0) {
|
|
1015
|
+
if (typeof encoding === "string") {
|
|
1016
|
+
buf.fill(fill, encoding);
|
|
1017
|
+
} else {
|
|
1018
|
+
buf.fill(fill);
|
|
1019
|
+
}
|
|
1020
|
+
} else {
|
|
1021
|
+
buf.fill(0);
|
|
1022
|
+
}
|
|
1023
|
+
return buf;
|
|
1024
|
+
};
|
|
1025
|
+
SafeBuffer.allocUnsafe = function(size) {
|
|
1026
|
+
if (typeof size !== "number") {
|
|
1027
|
+
throw new TypeError("Argument must be a number");
|
|
1028
|
+
}
|
|
1029
|
+
return Buffer2(size);
|
|
1030
|
+
};
|
|
1031
|
+
SafeBuffer.allocUnsafeSlow = function(size) {
|
|
1032
|
+
if (typeof size !== "number") {
|
|
1033
|
+
throw new TypeError("Argument must be a number");
|
|
1034
|
+
}
|
|
1035
|
+
return buffer.SlowBuffer(size);
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
});
|
|
1039
|
+
|
|
1040
|
+
// node_modules/string_decoder/lib/string_decoder.js
|
|
983
1041
|
var require_string_decoder = __commonJS({
|
|
984
|
-
"node_modules/
|
|
985
|
-
var Buffer2 =
|
|
1042
|
+
"node_modules/string_decoder/lib/string_decoder.js"(exports) {
|
|
1043
|
+
var Buffer2 = require_safe_buffer2().Buffer;
|
|
986
1044
|
var isEncoding = Buffer2.isEncoding || function(encoding) {
|
|
987
1045
|
encoding = "" + encoding;
|
|
988
1046
|
switch (encoding && encoding.toLowerCase()) {
|
|
@@ -1216,9 +1274,9 @@ var require_string_decoder = __commonJS({
|
|
|
1216
1274
|
}
|
|
1217
1275
|
});
|
|
1218
1276
|
|
|
1219
|
-
// node_modules/
|
|
1277
|
+
// node_modules/readable-stream/lib/_stream_readable.js
|
|
1220
1278
|
var require_stream_readable = __commonJS({
|
|
1221
|
-
"node_modules/
|
|
1279
|
+
"node_modules/readable-stream/lib/_stream_readable.js"(exports, module) {
|
|
1222
1280
|
var pna = require_process_nextick_args();
|
|
1223
1281
|
module.exports = Readable2;
|
|
1224
1282
|
var isArray = require_isarray();
|
|
@@ -1901,9 +1959,9 @@ var require_stream_readable = __commonJS({
|
|
|
1901
1959
|
}
|
|
1902
1960
|
});
|
|
1903
1961
|
|
|
1904
|
-
// node_modules/
|
|
1962
|
+
// node_modules/readable-stream/lib/_stream_transform.js
|
|
1905
1963
|
var require_stream_transform = __commonJS({
|
|
1906
|
-
"node_modules/
|
|
1964
|
+
"node_modules/readable-stream/lib/_stream_transform.js"(exports, module) {
|
|
1907
1965
|
module.exports = Transform;
|
|
1908
1966
|
var Duplex = require_stream_duplex();
|
|
1909
1967
|
var util = Object.create(require_util());
|
|
@@ -2000,9 +2058,9 @@ var require_stream_transform = __commonJS({
|
|
|
2000
2058
|
}
|
|
2001
2059
|
});
|
|
2002
2060
|
|
|
2003
|
-
// node_modules/
|
|
2061
|
+
// node_modules/readable-stream/lib/_stream_passthrough.js
|
|
2004
2062
|
var require_stream_passthrough = __commonJS({
|
|
2005
|
-
"node_modules/
|
|
2063
|
+
"node_modules/readable-stream/lib/_stream_passthrough.js"(exports, module) {
|
|
2006
2064
|
module.exports = PassThrough;
|
|
2007
2065
|
var Transform = require_stream_transform();
|
|
2008
2066
|
var util = Object.create(require_util());
|
|
@@ -2018,9 +2076,9 @@ var require_stream_passthrough = __commonJS({
|
|
|
2018
2076
|
}
|
|
2019
2077
|
});
|
|
2020
2078
|
|
|
2021
|
-
// node_modules/
|
|
2079
|
+
// node_modules/readable-stream/readable.js
|
|
2022
2080
|
var require_readable = __commonJS({
|
|
2023
|
-
"node_modules/
|
|
2081
|
+
"node_modules/readable-stream/readable.js"(exports, module) {
|
|
2024
2082
|
var Stream = __require("stream");
|
|
2025
2083
|
if (process.env.READABLE_STREAM === "disable" && Stream) {
|
|
2026
2084
|
module.exports = Stream;
|
|
@@ -2929,8 +2987,8 @@ var require_utils = __commonJS({
|
|
|
2929
2987
|
var result = transform[inputType][outputType](input);
|
|
2930
2988
|
return result;
|
|
2931
2989
|
};
|
|
2932
|
-
exports.resolve = function(
|
|
2933
|
-
var parts =
|
|
2990
|
+
exports.resolve = function(path30) {
|
|
2991
|
+
var parts = path30.split("/");
|
|
2934
2992
|
var result = [];
|
|
2935
2993
|
for (var index = 0; index < parts.length; index++) {
|
|
2936
2994
|
var part = parts[index];
|
|
@@ -8745,18 +8803,18 @@ var require_object = __commonJS({
|
|
|
8745
8803
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
8746
8804
|
this.files[name] = object;
|
|
8747
8805
|
};
|
|
8748
|
-
var parentFolder = function(
|
|
8749
|
-
if (
|
|
8750
|
-
|
|
8806
|
+
var parentFolder = function(path30) {
|
|
8807
|
+
if (path30.slice(-1) === "/") {
|
|
8808
|
+
path30 = path30.substring(0, path30.length - 1);
|
|
8751
8809
|
}
|
|
8752
|
-
var lastSlash =
|
|
8753
|
-
return lastSlash > 0 ?
|
|
8810
|
+
var lastSlash = path30.lastIndexOf("/");
|
|
8811
|
+
return lastSlash > 0 ? path30.substring(0, lastSlash) : "";
|
|
8754
8812
|
};
|
|
8755
|
-
var forceTrailingSlash = function(
|
|
8756
|
-
if (
|
|
8757
|
-
|
|
8813
|
+
var forceTrailingSlash = function(path30) {
|
|
8814
|
+
if (path30.slice(-1) !== "/") {
|
|
8815
|
+
path30 += "/";
|
|
8758
8816
|
}
|
|
8759
|
-
return
|
|
8817
|
+
return path30;
|
|
8760
8818
|
};
|
|
8761
8819
|
var folderAdd = function(name, createFolders) {
|
|
8762
8820
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -9755,12 +9813,12 @@ var init_audit_logger = __esm({
|
|
|
9755
9813
|
constructor(workspacePath, debugMode = false) {
|
|
9756
9814
|
this.workspacePath = workspacePath;
|
|
9757
9815
|
this.debugMode = debugMode;
|
|
9758
|
-
const cascadeDir =
|
|
9759
|
-
if (!
|
|
9760
|
-
|
|
9816
|
+
const cascadeDir = path28.join(workspacePath, ".cascade");
|
|
9817
|
+
if (!fs27.existsSync(cascadeDir)) {
|
|
9818
|
+
fs27.mkdirSync(cascadeDir, { recursive: true });
|
|
9761
9819
|
}
|
|
9762
|
-
this.keyPath =
|
|
9763
|
-
this.dbPath =
|
|
9820
|
+
this.keyPath = path28.join(cascadeDir, "audit_log.key");
|
|
9821
|
+
this.dbPath = path28.join(cascadeDir, "audit_log.db");
|
|
9764
9822
|
this.initEncryptionKey();
|
|
9765
9823
|
this.db = new Database2(this.dbPath);
|
|
9766
9824
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -9790,11 +9848,11 @@ var init_audit_logger = __esm({
|
|
|
9790
9848
|
return crypto.createHash("sha256").update(`${prevHash}|${timestamp}|${eventType}|${tierId}|${encryptedPayload}`).digest("hex");
|
|
9791
9849
|
}
|
|
9792
9850
|
initEncryptionKey() {
|
|
9793
|
-
if (
|
|
9794
|
-
this.encryptionKey =
|
|
9851
|
+
if (fs27.existsSync(this.keyPath)) {
|
|
9852
|
+
this.encryptionKey = fs27.readFileSync(this.keyPath);
|
|
9795
9853
|
} else {
|
|
9796
9854
|
this.encryptionKey = crypto.randomBytes(32);
|
|
9797
|
-
|
|
9855
|
+
fs27.writeFileSync(this.keyPath, this.encryptionKey);
|
|
9798
9856
|
}
|
|
9799
9857
|
}
|
|
9800
9858
|
encrypt(text) {
|
|
@@ -9872,9 +9930,9 @@ var init_audit_logger = __esm({
|
|
|
9872
9930
|
dumpDebugIfNeeded() {
|
|
9873
9931
|
if (!this.debugMode) return;
|
|
9874
9932
|
try {
|
|
9875
|
-
const dumpPath =
|
|
9933
|
+
const dumpPath = path28.join(os6.tmpdir(), "cascade_audit_logs_debug.json");
|
|
9876
9934
|
const entries = this.getAllLogs();
|
|
9877
|
-
|
|
9935
|
+
fs27.writeFileSync(dumpPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
9878
9936
|
} catch (err) {
|
|
9879
9937
|
console.error("Failed to dump debug audit logs", err);
|
|
9880
9938
|
}
|
|
@@ -11565,7 +11623,7 @@ function reconcilePrice(model, live) {
|
|
|
11565
11623
|
}
|
|
11566
11624
|
|
|
11567
11625
|
// src/constants.ts
|
|
11568
|
-
var CASCADE_VERSION = "0.
|
|
11626
|
+
var CASCADE_VERSION = "0.77.0";
|
|
11569
11627
|
var CASCADE_CONFIG_DIR = ".cascade";
|
|
11570
11628
|
var CASCADE_MD_FILE = "CASCADE.md";
|
|
11571
11629
|
var CASCADE_IGNORE_FILE = ".cascadeignore";
|
|
@@ -11586,64 +11644,88 @@ var DEFAULT_AUTO_SUMMARIZE_AT = 15e4;
|
|
|
11586
11644
|
var DEFAULT_MAX_SESSION_MESSAGES = 1e3;
|
|
11587
11645
|
var DEFAULT_RETENTION_DAYS = 90;
|
|
11588
11646
|
var MODELS = {
|
|
11589
|
-
// Anthropic
|
|
11590
|
-
"claude-
|
|
11591
|
-
id: "claude-
|
|
11592
|
-
name: "Claude
|
|
11647
|
+
// Anthropic — active Claude API models (2026-08-27).
|
|
11648
|
+
"claude-fable-5": {
|
|
11649
|
+
id: "claude-fable-5",
|
|
11650
|
+
name: "Claude Fable 5",
|
|
11593
11651
|
provider: "anthropic",
|
|
11594
|
-
contextWindow:
|
|
11652
|
+
contextWindow: 1e6,
|
|
11595
11653
|
isVisionCapable: true,
|
|
11596
|
-
inputCostPer1kTokens: 0.
|
|
11597
|
-
outputCostPer1kTokens: 0.
|
|
11598
|
-
maxOutputTokens:
|
|
11654
|
+
inputCostPer1kTokens: 0.01,
|
|
11655
|
+
outputCostPer1kTokens: 0.05,
|
|
11656
|
+
maxOutputTokens: 128e3,
|
|
11599
11657
|
supportsStreaming: true,
|
|
11600
11658
|
isLocal: false
|
|
11601
11659
|
},
|
|
11602
|
-
"claude-
|
|
11603
|
-
id: "claude-
|
|
11604
|
-
name: "Claude
|
|
11660
|
+
"claude-opus-5": {
|
|
11661
|
+
id: "claude-opus-5",
|
|
11662
|
+
name: "Claude Opus 5",
|
|
11605
11663
|
provider: "anthropic",
|
|
11606
|
-
contextWindow:
|
|
11664
|
+
contextWindow: 1e6,
|
|
11607
11665
|
isVisionCapable: true,
|
|
11608
|
-
inputCostPer1kTokens:
|
|
11609
|
-
outputCostPer1kTokens: 0.
|
|
11610
|
-
maxOutputTokens:
|
|
11666
|
+
inputCostPer1kTokens: 5e-3,
|
|
11667
|
+
outputCostPer1kTokens: 0.025,
|
|
11668
|
+
maxOutputTokens: 128e3,
|
|
11611
11669
|
supportsStreaming: true,
|
|
11612
11670
|
isLocal: false
|
|
11613
11671
|
},
|
|
11614
|
-
"claude-
|
|
11615
|
-
id: "claude-
|
|
11616
|
-
name: "Claude
|
|
11672
|
+
"claude-opus-4-8": {
|
|
11673
|
+
id: "claude-opus-4-8",
|
|
11674
|
+
name: "Claude Opus 4.8",
|
|
11617
11675
|
provider: "anthropic",
|
|
11618
|
-
contextWindow:
|
|
11676
|
+
contextWindow: 1e6,
|
|
11619
11677
|
isVisionCapable: true,
|
|
11620
|
-
inputCostPer1kTokens:
|
|
11621
|
-
outputCostPer1kTokens:
|
|
11622
|
-
maxOutputTokens:
|
|
11678
|
+
inputCostPer1kTokens: 5e-3,
|
|
11679
|
+
outputCostPer1kTokens: 0.025,
|
|
11680
|
+
maxOutputTokens: 128e3,
|
|
11623
11681
|
supportsStreaming: true,
|
|
11624
11682
|
isLocal: false
|
|
11625
11683
|
},
|
|
11626
|
-
"claude-
|
|
11627
|
-
id: "claude-
|
|
11628
|
-
name: "Claude
|
|
11684
|
+
"claude-opus-4-7": {
|
|
11685
|
+
id: "claude-opus-4-7",
|
|
11686
|
+
name: "Claude Opus 4.7",
|
|
11629
11687
|
provider: "anthropic",
|
|
11630
|
-
contextWindow:
|
|
11688
|
+
contextWindow: 1e6,
|
|
11631
11689
|
isVisionCapable: true,
|
|
11632
|
-
inputCostPer1kTokens:
|
|
11633
|
-
outputCostPer1kTokens:
|
|
11634
|
-
maxOutputTokens:
|
|
11690
|
+
inputCostPer1kTokens: 5e-3,
|
|
11691
|
+
outputCostPer1kTokens: 0.025,
|
|
11692
|
+
maxOutputTokens: 128e3,
|
|
11635
11693
|
supportsStreaming: true,
|
|
11636
11694
|
isLocal: false
|
|
11637
11695
|
},
|
|
11638
|
-
"claude-opus-4-
|
|
11639
|
-
id: "claude-opus-4-
|
|
11640
|
-
name: "Claude Opus 4.
|
|
11696
|
+
"claude-opus-4-6": {
|
|
11697
|
+
id: "claude-opus-4-6",
|
|
11698
|
+
name: "Claude Opus 4.6",
|
|
11699
|
+
provider: "anthropic",
|
|
11700
|
+
contextWindow: 1e6,
|
|
11701
|
+
isVisionCapable: true,
|
|
11702
|
+
inputCostPer1kTokens: 5e-3,
|
|
11703
|
+
outputCostPer1kTokens: 0.025,
|
|
11704
|
+
maxOutputTokens: 128e3,
|
|
11705
|
+
supportsStreaming: true,
|
|
11706
|
+
isLocal: false
|
|
11707
|
+
},
|
|
11708
|
+
"claude-opus-4-5": {
|
|
11709
|
+
id: "claude-opus-4-5-20251101",
|
|
11710
|
+
name: "Claude Opus 4.5",
|
|
11641
11711
|
provider: "anthropic",
|
|
11642
11712
|
contextWindow: 2e5,
|
|
11643
11713
|
isVisionCapable: true,
|
|
11644
|
-
inputCostPer1kTokens:
|
|
11645
|
-
outputCostPer1kTokens: 0.
|
|
11646
|
-
maxOutputTokens:
|
|
11714
|
+
inputCostPer1kTokens: 5e-3,
|
|
11715
|
+
outputCostPer1kTokens: 0.025,
|
|
11716
|
+
maxOutputTokens: 64e3,
|
|
11717
|
+
supportsStreaming: true,
|
|
11718
|
+
isLocal: false
|
|
11719
|
+
},
|
|
11720
|
+
"claude-sonnet-5": {
|
|
11721
|
+
id: "claude-sonnet-5",
|
|
11722
|
+
name: "Claude Sonnet 5",
|
|
11723
|
+
provider: "anthropic",
|
|
11724
|
+
contextWindow: 1e6,
|
|
11725
|
+
isVisionCapable: true,
|
|
11726
|
+
inputCostPer1kTokens: 2e-3,
|
|
11727
|
+
outputCostPer1kTokens: 0.01,
|
|
11728
|
+
maxOutputTokens: 128e3,
|
|
11647
11729
|
supportsStreaming: true,
|
|
11648
11730
|
isLocal: false
|
|
11649
11731
|
},
|
|
@@ -11651,76 +11733,135 @@ var MODELS = {
|
|
|
11651
11733
|
id: "claude-sonnet-4-6",
|
|
11652
11734
|
name: "Claude Sonnet 4.6",
|
|
11653
11735
|
provider: "anthropic",
|
|
11736
|
+
contextWindow: 1e6,
|
|
11737
|
+
isVisionCapable: true,
|
|
11738
|
+
inputCostPer1kTokens: 3e-3,
|
|
11739
|
+
outputCostPer1kTokens: 0.015,
|
|
11740
|
+
maxOutputTokens: 64e3,
|
|
11741
|
+
supportsStreaming: true,
|
|
11742
|
+
isLocal: false
|
|
11743
|
+
},
|
|
11744
|
+
"claude-sonnet-4-5": {
|
|
11745
|
+
id: "claude-sonnet-4-5-20250929",
|
|
11746
|
+
name: "Claude Sonnet 4.5",
|
|
11747
|
+
provider: "anthropic",
|
|
11654
11748
|
contextWindow: 2e5,
|
|
11655
11749
|
isVisionCapable: true,
|
|
11656
11750
|
inputCostPer1kTokens: 3e-3,
|
|
11657
11751
|
outputCostPer1kTokens: 0.015,
|
|
11658
|
-
maxOutputTokens:
|
|
11752
|
+
maxOutputTokens: 64e3,
|
|
11659
11753
|
supportsStreaming: true,
|
|
11660
11754
|
isLocal: false
|
|
11661
11755
|
},
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
|
|
11665
|
-
|
|
11756
|
+
"claude-haiku-4-5": {
|
|
11757
|
+
id: "claude-haiku-4-5-20251001",
|
|
11758
|
+
name: "Claude Haiku 4.5",
|
|
11759
|
+
provider: "anthropic",
|
|
11760
|
+
contextWindow: 2e5,
|
|
11761
|
+
isVisionCapable: true,
|
|
11762
|
+
inputCostPer1kTokens: 1e-3,
|
|
11763
|
+
outputCostPer1kTokens: 5e-3,
|
|
11764
|
+
maxOutputTokens: 64e3,
|
|
11765
|
+
supportsStreaming: true,
|
|
11766
|
+
isLocal: false
|
|
11767
|
+
},
|
|
11768
|
+
// OpenAI — active chat-capable models used by Cascade's Chat Completions path.
|
|
11769
|
+
"gpt-5.6-sol": {
|
|
11770
|
+
id: "gpt-5.6-sol",
|
|
11771
|
+
name: "GPT-5.6 Sol",
|
|
11666
11772
|
provider: "openai",
|
|
11667
|
-
contextWindow:
|
|
11773
|
+
contextWindow: 105e4,
|
|
11774
|
+
isVisionCapable: true,
|
|
11775
|
+
inputCostPer1kTokens: 4e-3,
|
|
11776
|
+
outputCostPer1kTokens: 0.02,
|
|
11777
|
+
maxOutputTokens: 128e3,
|
|
11778
|
+
supportsStreaming: true,
|
|
11779
|
+
isLocal: false
|
|
11780
|
+
},
|
|
11781
|
+
"gpt-5.6-terra": {
|
|
11782
|
+
id: "gpt-5.6-terra",
|
|
11783
|
+
name: "GPT-5.6 Terra",
|
|
11784
|
+
provider: "openai",
|
|
11785
|
+
contextWindow: 105e4,
|
|
11786
|
+
isVisionCapable: true,
|
|
11787
|
+
inputCostPer1kTokens: 2e-3,
|
|
11788
|
+
outputCostPer1kTokens: 0.012,
|
|
11789
|
+
maxOutputTokens: 128e3,
|
|
11790
|
+
supportsStreaming: true,
|
|
11791
|
+
isLocal: false
|
|
11792
|
+
},
|
|
11793
|
+
"gpt-5.6-luna": {
|
|
11794
|
+
id: "gpt-5.6-luna",
|
|
11795
|
+
name: "GPT-5.6 Luna",
|
|
11796
|
+
provider: "openai",
|
|
11797
|
+
contextWindow: 105e4,
|
|
11798
|
+
isVisionCapable: true,
|
|
11799
|
+
inputCostPer1kTokens: 2e-4,
|
|
11800
|
+
outputCostPer1kTokens: 12e-4,
|
|
11801
|
+
maxOutputTokens: 128e3,
|
|
11802
|
+
supportsStreaming: true,
|
|
11803
|
+
isLocal: false
|
|
11804
|
+
},
|
|
11805
|
+
"gpt-5.5": {
|
|
11806
|
+
id: "gpt-5.5",
|
|
11807
|
+
name: "GPT-5.5",
|
|
11808
|
+
provider: "openai",
|
|
11809
|
+
contextWindow: 105e4,
|
|
11668
11810
|
isVisionCapable: true,
|
|
11669
11811
|
inputCostPer1kTokens: 5e-3,
|
|
11670
|
-
outputCostPer1kTokens: 0.
|
|
11671
|
-
maxOutputTokens:
|
|
11812
|
+
outputCostPer1kTokens: 0.03,
|
|
11813
|
+
maxOutputTokens: 128e3,
|
|
11672
11814
|
supportsStreaming: true,
|
|
11673
11815
|
isLocal: false
|
|
11674
11816
|
},
|
|
11675
|
-
"gpt-
|
|
11676
|
-
id: "gpt-
|
|
11677
|
-
name: "GPT-
|
|
11817
|
+
"gpt-5.4": {
|
|
11818
|
+
id: "gpt-5.4",
|
|
11819
|
+
name: "GPT-5.4",
|
|
11678
11820
|
provider: "openai",
|
|
11679
|
-
contextWindow:
|
|
11821
|
+
contextWindow: 105e4,
|
|
11680
11822
|
isVisionCapable: true,
|
|
11681
|
-
inputCostPer1kTokens:
|
|
11682
|
-
outputCostPer1kTokens:
|
|
11683
|
-
maxOutputTokens:
|
|
11823
|
+
inputCostPer1kTokens: 25e-4,
|
|
11824
|
+
outputCostPer1kTokens: 0.015,
|
|
11825
|
+
maxOutputTokens: 128e3,
|
|
11684
11826
|
supportsStreaming: true,
|
|
11685
11827
|
isLocal: false
|
|
11686
11828
|
},
|
|
11687
|
-
"gpt-4
|
|
11688
|
-
id: "gpt-4
|
|
11689
|
-
name: "GPT-4
|
|
11829
|
+
"gpt-5.4-mini": {
|
|
11830
|
+
id: "gpt-5.4-mini",
|
|
11831
|
+
name: "GPT-5.4 Mini",
|
|
11690
11832
|
provider: "openai",
|
|
11691
|
-
contextWindow:
|
|
11833
|
+
contextWindow: 4e5,
|
|
11692
11834
|
isVisionCapable: true,
|
|
11693
|
-
inputCostPer1kTokens:
|
|
11694
|
-
outputCostPer1kTokens:
|
|
11695
|
-
maxOutputTokens:
|
|
11835
|
+
inputCostPer1kTokens: 75e-5,
|
|
11836
|
+
outputCostPer1kTokens: 45e-4,
|
|
11837
|
+
maxOutputTokens: 128e3,
|
|
11696
11838
|
supportsStreaming: true,
|
|
11697
11839
|
isLocal: false
|
|
11698
11840
|
},
|
|
11699
|
-
"gpt-4
|
|
11700
|
-
id: "gpt-4
|
|
11701
|
-
name: "GPT-4
|
|
11841
|
+
"gpt-5.4-nano": {
|
|
11842
|
+
id: "gpt-5.4-nano",
|
|
11843
|
+
name: "GPT-5.4 Nano",
|
|
11702
11844
|
provider: "openai",
|
|
11703
|
-
contextWindow:
|
|
11845
|
+
contextWindow: 4e5,
|
|
11704
11846
|
isVisionCapable: true,
|
|
11705
|
-
inputCostPer1kTokens:
|
|
11706
|
-
outputCostPer1kTokens:
|
|
11707
|
-
maxOutputTokens:
|
|
11847
|
+
inputCostPer1kTokens: 2e-4,
|
|
11848
|
+
outputCostPer1kTokens: 125e-5,
|
|
11849
|
+
maxOutputTokens: 128e3,
|
|
11708
11850
|
supportsStreaming: true,
|
|
11709
11851
|
isLocal: false
|
|
11710
11852
|
},
|
|
11711
|
-
"gpt-
|
|
11712
|
-
id: "gpt-
|
|
11713
|
-
name: "GPT-
|
|
11853
|
+
"gpt-5.2": {
|
|
11854
|
+
id: "gpt-5.2",
|
|
11855
|
+
name: "GPT-5.2",
|
|
11714
11856
|
provider: "openai",
|
|
11715
|
-
contextWindow:
|
|
11857
|
+
contextWindow: 4e5,
|
|
11716
11858
|
isVisionCapable: true,
|
|
11717
|
-
inputCostPer1kTokens:
|
|
11718
|
-
outputCostPer1kTokens:
|
|
11719
|
-
maxOutputTokens:
|
|
11859
|
+
inputCostPer1kTokens: 175e-5,
|
|
11860
|
+
outputCostPer1kTokens: 0.014,
|
|
11861
|
+
maxOutputTokens: 128e3,
|
|
11720
11862
|
supportsStreaming: true,
|
|
11721
11863
|
isLocal: false
|
|
11722
11864
|
},
|
|
11723
|
-
// GPT-5 family (offline baseline pricing; the live fetch keeps it current).
|
|
11724
11865
|
"gpt-5": {
|
|
11725
11866
|
id: "gpt-5",
|
|
11726
11867
|
name: "GPT-5",
|
|
@@ -11757,79 +11898,149 @@ var MODELS = {
|
|
|
11757
11898
|
supportsStreaming: true,
|
|
11758
11899
|
isLocal: false
|
|
11759
11900
|
},
|
|
11760
|
-
|
|
11761
|
-
|
|
11762
|
-
|
|
11763
|
-
"gpt-5.5": {
|
|
11764
|
-
id: "gpt-5.5",
|
|
11765
|
-
name: "GPT-5.5",
|
|
11901
|
+
"gpt-4.1": {
|
|
11902
|
+
id: "gpt-4.1",
|
|
11903
|
+
name: "GPT-4.1",
|
|
11766
11904
|
provider: "openai",
|
|
11767
|
-
contextWindow:
|
|
11905
|
+
contextWindow: 1047576,
|
|
11768
11906
|
isVisionCapable: true,
|
|
11769
|
-
inputCostPer1kTokens:
|
|
11770
|
-
outputCostPer1kTokens:
|
|
11771
|
-
maxOutputTokens:
|
|
11907
|
+
inputCostPer1kTokens: 2e-3,
|
|
11908
|
+
outputCostPer1kTokens: 8e-3,
|
|
11909
|
+
maxOutputTokens: 32768,
|
|
11772
11910
|
supportsStreaming: true,
|
|
11773
11911
|
isLocal: false
|
|
11774
11912
|
},
|
|
11775
|
-
"gpt-
|
|
11776
|
-
id: "gpt-
|
|
11777
|
-
name: "GPT-
|
|
11913
|
+
"gpt-4.1-mini": {
|
|
11914
|
+
id: "gpt-4.1-mini",
|
|
11915
|
+
name: "GPT-4.1 Mini",
|
|
11778
11916
|
provider: "openai",
|
|
11779
|
-
contextWindow:
|
|
11917
|
+
contextWindow: 1047576,
|
|
11780
11918
|
isVisionCapable: true,
|
|
11781
|
-
inputCostPer1kTokens:
|
|
11919
|
+
inputCostPer1kTokens: 4e-4,
|
|
11920
|
+
outputCostPer1kTokens: 16e-4,
|
|
11921
|
+
maxOutputTokens: 32768,
|
|
11922
|
+
supportsStreaming: true,
|
|
11923
|
+
isLocal: false
|
|
11924
|
+
},
|
|
11925
|
+
"gpt-4.1-nano": {
|
|
11926
|
+
id: "gpt-4.1-nano",
|
|
11927
|
+
name: "GPT-4.1 Nano",
|
|
11928
|
+
provider: "openai",
|
|
11929
|
+
contextWindow: 1047576,
|
|
11930
|
+
isVisionCapable: true,
|
|
11931
|
+
inputCostPer1kTokens: 1e-4,
|
|
11932
|
+
outputCostPer1kTokens: 4e-4,
|
|
11933
|
+
maxOutputTokens: 32768,
|
|
11934
|
+
supportsStreaming: true,
|
|
11935
|
+
isLocal: false
|
|
11936
|
+
},
|
|
11937
|
+
"gpt-4o": {
|
|
11938
|
+
id: "gpt-4o",
|
|
11939
|
+
name: "GPT-4o",
|
|
11940
|
+
provider: "openai",
|
|
11941
|
+
contextWindow: 128e3,
|
|
11942
|
+
isVisionCapable: true,
|
|
11943
|
+
inputCostPer1kTokens: 25e-4,
|
|
11782
11944
|
outputCostPer1kTokens: 0.01,
|
|
11783
|
-
maxOutputTokens:
|
|
11945
|
+
maxOutputTokens: 16e3,
|
|
11784
11946
|
supportsStreaming: true,
|
|
11785
11947
|
isLocal: false
|
|
11786
11948
|
},
|
|
11787
|
-
"gpt-
|
|
11788
|
-
id: "gpt-
|
|
11789
|
-
name: "GPT-
|
|
11949
|
+
"gpt-4o-mini": {
|
|
11950
|
+
id: "gpt-4o-mini",
|
|
11951
|
+
name: "GPT-4o Mini",
|
|
11790
11952
|
provider: "openai",
|
|
11791
|
-
contextWindow:
|
|
11953
|
+
contextWindow: 128e3,
|
|
11792
11954
|
isVisionCapable: true,
|
|
11793
|
-
inputCostPer1kTokens:
|
|
11794
|
-
outputCostPer1kTokens:
|
|
11795
|
-
maxOutputTokens:
|
|
11955
|
+
inputCostPer1kTokens: 15e-5,
|
|
11956
|
+
outputCostPer1kTokens: 6e-4,
|
|
11957
|
+
maxOutputTokens: 16e3,
|
|
11796
11958
|
supportsStreaming: true,
|
|
11797
11959
|
isLocal: false
|
|
11798
11960
|
},
|
|
11799
|
-
// Google
|
|
11800
|
-
|
|
11801
|
-
|
|
11802
|
-
|
|
11961
|
+
// Google Gemini — active GA + preview chat models. Gemini 2.0/1.5 are no
|
|
11962
|
+
// longer advertised because the Gemini API shut those generations down.
|
|
11963
|
+
"gemini-3.7-flash": {
|
|
11964
|
+
id: "gemini-3.7-flash",
|
|
11965
|
+
name: "Gemini 3.7 Flash",
|
|
11803
11966
|
provider: "gemini",
|
|
11804
|
-
contextWindow:
|
|
11967
|
+
contextWindow: 1048576,
|
|
11805
11968
|
isVisionCapable: true,
|
|
11806
|
-
inputCostPer1kTokens:
|
|
11807
|
-
outputCostPer1kTokens:
|
|
11808
|
-
maxOutputTokens:
|
|
11969
|
+
inputCostPer1kTokens: 75e-5,
|
|
11970
|
+
outputCostPer1kTokens: 375e-5,
|
|
11971
|
+
maxOutputTokens: 65536,
|
|
11809
11972
|
supportsStreaming: true,
|
|
11810
11973
|
isLocal: false
|
|
11811
11974
|
},
|
|
11812
|
-
"gemini-
|
|
11813
|
-
id: "gemini-
|
|
11814
|
-
name: "Gemini
|
|
11975
|
+
"gemini-3.6-flash": {
|
|
11976
|
+
id: "gemini-3.6-flash",
|
|
11977
|
+
name: "Gemini 3.6 Flash",
|
|
11815
11978
|
provider: "gemini",
|
|
11816
|
-
contextWindow:
|
|
11979
|
+
contextWindow: 1048576,
|
|
11817
11980
|
isVisionCapable: true,
|
|
11818
|
-
inputCostPer1kTokens:
|
|
11819
|
-
outputCostPer1kTokens:
|
|
11820
|
-
maxOutputTokens:
|
|
11981
|
+
inputCostPer1kTokens: 75e-5,
|
|
11982
|
+
outputCostPer1kTokens: 375e-5,
|
|
11983
|
+
maxOutputTokens: 65536,
|
|
11821
11984
|
supportsStreaming: true,
|
|
11822
11985
|
isLocal: false
|
|
11823
11986
|
},
|
|
11824
|
-
"gemini-
|
|
11825
|
-
id: "gemini-
|
|
11826
|
-
name: "Gemini
|
|
11987
|
+
"gemini-3.5-flash": {
|
|
11988
|
+
id: "gemini-3.5-flash",
|
|
11989
|
+
name: "Gemini 3.5 Flash",
|
|
11827
11990
|
provider: "gemini",
|
|
11828
|
-
contextWindow:
|
|
11991
|
+
contextWindow: 1048576,
|
|
11829
11992
|
isVisionCapable: true,
|
|
11830
|
-
inputCostPer1kTokens:
|
|
11831
|
-
outputCostPer1kTokens:
|
|
11832
|
-
maxOutputTokens:
|
|
11993
|
+
inputCostPer1kTokens: 15e-4,
|
|
11994
|
+
outputCostPer1kTokens: 9e-3,
|
|
11995
|
+
maxOutputTokens: 65536,
|
|
11996
|
+
supportsStreaming: true,
|
|
11997
|
+
isLocal: false
|
|
11998
|
+
},
|
|
11999
|
+
"gemini-3.5-flash-lite": {
|
|
12000
|
+
id: "gemini-3.5-flash-lite",
|
|
12001
|
+
name: "Gemini 3.5 Flash-Lite",
|
|
12002
|
+
provider: "gemini",
|
|
12003
|
+
contextWindow: 1048576,
|
|
12004
|
+
isVisionCapable: true,
|
|
12005
|
+
inputCostPer1kTokens: 3e-4,
|
|
12006
|
+
outputCostPer1kTokens: 25e-4,
|
|
12007
|
+
maxOutputTokens: 65536,
|
|
12008
|
+
supportsStreaming: true,
|
|
12009
|
+
isLocal: false
|
|
12010
|
+
},
|
|
12011
|
+
"gemini-3.1-flash-lite": {
|
|
12012
|
+
id: "gemini-3.1-flash-lite",
|
|
12013
|
+
name: "Gemini 3.1 Flash-Lite",
|
|
12014
|
+
provider: "gemini",
|
|
12015
|
+
contextWindow: 1048576,
|
|
12016
|
+
isVisionCapable: true,
|
|
12017
|
+
inputCostPer1kTokens: 25e-5,
|
|
12018
|
+
outputCostPer1kTokens: 15e-4,
|
|
12019
|
+
maxOutputTokens: 65536,
|
|
12020
|
+
supportsStreaming: true,
|
|
12021
|
+
isLocal: false
|
|
12022
|
+
},
|
|
12023
|
+
"gemini-3.1-pro-preview": {
|
|
12024
|
+
id: "gemini-3.1-pro-preview",
|
|
12025
|
+
name: "Gemini 3.1 Pro Preview",
|
|
12026
|
+
provider: "gemini",
|
|
12027
|
+
contextWindow: 1048576,
|
|
12028
|
+
isVisionCapable: true,
|
|
12029
|
+
inputCostPer1kTokens: 2e-3,
|
|
12030
|
+
outputCostPer1kTokens: 0.012,
|
|
12031
|
+
maxOutputTokens: 65536,
|
|
12032
|
+
supportsStreaming: true,
|
|
12033
|
+
isLocal: false
|
|
12034
|
+
},
|
|
12035
|
+
"gemini-3-flash-preview": {
|
|
12036
|
+
id: "gemini-3-flash-preview",
|
|
12037
|
+
name: "Gemini 3 Flash Preview",
|
|
12038
|
+
provider: "gemini",
|
|
12039
|
+
contextWindow: 1048576,
|
|
12040
|
+
isVisionCapable: true,
|
|
12041
|
+
inputCostPer1kTokens: 5e-4,
|
|
12042
|
+
outputCostPer1kTokens: 3e-3,
|
|
12043
|
+
maxOutputTokens: 65536,
|
|
11833
12044
|
supportsStreaming: true,
|
|
11834
12045
|
isLocal: false
|
|
11835
12046
|
},
|
|
@@ -11837,7 +12048,7 @@ var MODELS = {
|
|
|
11837
12048
|
id: "gemini-2.5-pro",
|
|
11838
12049
|
name: "Gemini 2.5 Pro",
|
|
11839
12050
|
provider: "gemini",
|
|
11840
|
-
contextWindow:
|
|
12051
|
+
contextWindow: 1048576,
|
|
11841
12052
|
isVisionCapable: true,
|
|
11842
12053
|
inputCostPer1kTokens: 125e-5,
|
|
11843
12054
|
outputCostPer1kTokens: 0.01,
|
|
@@ -11849,10 +12060,22 @@ var MODELS = {
|
|
|
11849
12060
|
id: "gemini-2.5-flash",
|
|
11850
12061
|
name: "Gemini 2.5 Flash",
|
|
11851
12062
|
provider: "gemini",
|
|
11852
|
-
contextWindow:
|
|
12063
|
+
contextWindow: 1048576,
|
|
11853
12064
|
isVisionCapable: true,
|
|
11854
|
-
inputCostPer1kTokens:
|
|
11855
|
-
outputCostPer1kTokens:
|
|
12065
|
+
inputCostPer1kTokens: 3e-4,
|
|
12066
|
+
outputCostPer1kTokens: 25e-4,
|
|
12067
|
+
maxOutputTokens: 65536,
|
|
12068
|
+
supportsStreaming: true,
|
|
12069
|
+
isLocal: false
|
|
12070
|
+
},
|
|
12071
|
+
"gemini-2.5-flash-lite": {
|
|
12072
|
+
id: "gemini-2.5-flash-lite",
|
|
12073
|
+
name: "Gemini 2.5 Flash-Lite",
|
|
12074
|
+
provider: "gemini",
|
|
12075
|
+
contextWindow: 1048576,
|
|
12076
|
+
isVisionCapable: true,
|
|
12077
|
+
inputCostPer1kTokens: 1e-4,
|
|
12078
|
+
outputCostPer1kTokens: 4e-4,
|
|
11856
12079
|
maxOutputTokens: 65536,
|
|
11857
12080
|
supportsStreaming: true,
|
|
11858
12081
|
isLocal: false
|
|
@@ -11922,43 +12145,57 @@ for (const _m of Object.values(MODELS)) {
|
|
|
11922
12145
|
_m.pricingUnknown = false;
|
|
11923
12146
|
}
|
|
11924
12147
|
var T1_MODEL_PRIORITY = [
|
|
12148
|
+
"gpt-5.6-sol",
|
|
12149
|
+
"claude-fable-5",
|
|
12150
|
+
"claude-opus-5",
|
|
11925
12151
|
"gpt-5.5",
|
|
11926
12152
|
"gpt-5.4",
|
|
12153
|
+
"gemini-3.1-pro-preview",
|
|
12154
|
+
"claude-opus-4-8",
|
|
12155
|
+
"claude-sonnet-5",
|
|
12156
|
+
"gemini-3.7-flash",
|
|
12157
|
+
"gpt-5.2",
|
|
11927
12158
|
"gpt-5",
|
|
11928
|
-
"claude-opus-4",
|
|
11929
|
-
"claude-sonnet-4",
|
|
11930
12159
|
"gemini-2.5-pro",
|
|
11931
12160
|
"gpt-4.1",
|
|
11932
|
-
"gpt-4o"
|
|
11933
|
-
"gemini-1.5-pro"
|
|
12161
|
+
"gpt-4o"
|
|
11934
12162
|
];
|
|
11935
12163
|
var T2_MODEL_PRIORITY = [
|
|
12164
|
+
"gpt-5.6-terra",
|
|
12165
|
+
"claude-sonnet-5",
|
|
12166
|
+
"gemini-3.7-flash",
|
|
12167
|
+
"gemini-3.6-flash",
|
|
11936
12168
|
"gpt-5.4-mini",
|
|
11937
12169
|
"gpt-5-mini",
|
|
11938
|
-
"claude-sonnet-4",
|
|
12170
|
+
"claude-sonnet-4-6",
|
|
11939
12171
|
"claude-haiku-4-5",
|
|
11940
|
-
"
|
|
12172
|
+
"gemini-3.5-flash",
|
|
11941
12173
|
"gemini-2.5-flash",
|
|
11942
12174
|
"gpt-4.1-mini",
|
|
11943
12175
|
"gpt-4o-mini",
|
|
11944
|
-
"gemini-2.0-flash",
|
|
11945
12176
|
"llama3:70b"
|
|
11946
12177
|
];
|
|
11947
12178
|
var T3_MODEL_PRIORITY = [
|
|
12179
|
+
"gpt-5.6-luna",
|
|
12180
|
+
"gpt-5.4-nano",
|
|
12181
|
+
"gemini-3.5-flash-lite",
|
|
12182
|
+
"gemini-3.1-flash-lite",
|
|
12183
|
+
"claude-haiku-4-5",
|
|
11948
12184
|
"gpt-5-nano",
|
|
12185
|
+
"gemini-2.5-flash-lite",
|
|
11949
12186
|
"llama3.2:3b",
|
|
11950
12187
|
"mistral:7b",
|
|
11951
|
-
"claude-haiku-4-5",
|
|
11952
|
-
"claude-haiku-3-5",
|
|
11953
12188
|
"gpt-4.1-nano",
|
|
11954
12189
|
"gpt-4o-mini",
|
|
11955
|
-
"gemini-2.5-flash"
|
|
11956
|
-
"gemini-2.0-flash"
|
|
12190
|
+
"gemini-2.5-flash"
|
|
11957
12191
|
];
|
|
11958
12192
|
var VISION_MODEL_PRIORITY = [
|
|
11959
|
-
"
|
|
12193
|
+
"gpt-5.6-sol",
|
|
12194
|
+
"claude-fable-5",
|
|
12195
|
+
"claude-sonnet-5",
|
|
12196
|
+
"gemini-3.7-flash",
|
|
11960
12197
|
"gpt-4o",
|
|
11961
|
-
"gemini-2.
|
|
12198
|
+
"gemini-2.5-flash",
|
|
11962
12199
|
"llava"
|
|
11963
12200
|
];
|
|
11964
12201
|
var COMPLEXITY_T2_COUNT = {
|
|
@@ -12139,7 +12376,7 @@ function isChatModel(id, methods) {
|
|
|
12139
12376
|
return !NON_CHAT.test(id);
|
|
12140
12377
|
}
|
|
12141
12378
|
try {
|
|
12142
|
-
|
|
12379
|
+
dnsCallback.setDefaultResultOrder("ipv4first");
|
|
12143
12380
|
} catch {
|
|
12144
12381
|
}
|
|
12145
12382
|
function preferIpv4Host(url) {
|
|
@@ -12155,8 +12392,8 @@ function normalizeEndpoint(url) {
|
|
|
12155
12392
|
if (!raw) return "";
|
|
12156
12393
|
try {
|
|
12157
12394
|
const u = new URL(raw);
|
|
12158
|
-
const
|
|
12159
|
-
return `${u.protocol}//${u.host.toLowerCase()}${
|
|
12395
|
+
const path30 = stripTrailingSlashes(`${u.pathname}${u.search}`);
|
|
12396
|
+
return `${u.protocol}//${u.host.toLowerCase()}${path30}`;
|
|
12160
12397
|
} catch {
|
|
12161
12398
|
return raw.toLowerCase();
|
|
12162
12399
|
}
|
|
@@ -12823,52 +13060,127 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
12823
13060
|
}
|
|
12824
13061
|
};
|
|
12825
13062
|
|
|
13063
|
+
// src/providers/cloud-model-catalog.json
|
|
13064
|
+
var cloud_model_catalog_default = {
|
|
13065
|
+
models: [
|
|
13066
|
+
{ id: "gpt-5.6-sol", name: "GPT-5.6 Sol", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13067
|
+
{ id: "gpt-5.6-terra", name: "GPT-5.6 Terra", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13068
|
+
{ id: "gpt-5.6-luna", name: "GPT-5.6 Luna", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13069
|
+
{ id: "gpt-5.5", name: "GPT-5.5", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13070
|
+
{ id: "gpt-5.4", name: "GPT-5.4", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13071
|
+
{ id: "gpt-5.4-mini", name: "GPT-5.4 Mini", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13072
|
+
{ id: "gpt-5.4-nano", name: "GPT-5.4 Nano", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13073
|
+
{ id: "gpt-5", name: "GPT-5", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13074
|
+
{ id: "gpt-5-mini", name: "GPT-5 Mini", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13075
|
+
{ id: "gpt-5-nano", name: "GPT-5 Nano", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13076
|
+
{ id: "gpt-4.1", name: "GPT-4.1", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 1047576, maxOutputTokens: 32768, vision: true, toolUse: true },
|
|
13077
|
+
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 1047576, maxOutputTokens: 32768, vision: true, toolUse: true },
|
|
13078
|
+
{ id: "gpt-4.1-nano", name: "GPT-4.1 Nano", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 1047576, maxOutputTokens: 32768, vision: true, toolUse: true },
|
|
13079
|
+
{ id: "gpt-4o", name: "GPT-4o", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 128e3, maxOutputTokens: 16384, vision: true, toolUse: true },
|
|
13080
|
+
{ id: "gpt-4o-mini", name: "GPT-4o Mini", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 128e3, maxOutputTokens: 16384, vision: true, toolUse: true },
|
|
13081
|
+
{ id: "claude-fable-5", name: "Claude Fable 5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13082
|
+
{ id: "claude-opus-5", name: "Claude Opus 5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13083
|
+
{ id: "claude-opus-4-8", name: "Claude Opus 4.8", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13084
|
+
{ id: "claude-opus-4-7", name: "Claude Opus 4.7", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13085
|
+
{ id: "claude-opus-4-6", name: "Claude Opus 4.6", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, vision: true, toolUse: true },
|
|
13086
|
+
{ id: "claude-opus-4-5-20251101", name: "Claude Opus 4.5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 2e5, vision: true, toolUse: true },
|
|
13087
|
+
{ id: "claude-sonnet-5", name: "Claude Sonnet 5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13088
|
+
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13089
|
+
{ id: "claude-sonnet-4-5-20250929", name: "Claude Sonnet 4.5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 2e5, vision: true, toolUse: true },
|
|
13090
|
+
{ id: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 2e5, maxOutputTokens: 64e3, vision: true, toolUse: true },
|
|
13091
|
+
{ id: "gemini-3.7-flash", name: "Gemini 3.7 Flash", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13092
|
+
{ id: "gemini-3.6-flash", name: "Gemini 3.6 Flash", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13093
|
+
{ id: "gemini-3.5-flash", name: "Gemini 3.5 Flash", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13094
|
+
{ id: "gemini-3.5-flash-lite", name: "Gemini 3.5 Flash-Lite", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13095
|
+
{ id: "gemini-3.1-flash-lite", name: "Gemini 3.1 Flash-Lite", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13096
|
+
{ id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro", providers: ["gemini"], lifecycle: "preview", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13097
|
+
{ id: "gemini-3-flash-preview", name: "Gemini 3 Flash", providers: ["gemini"], lifecycle: "preview", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13098
|
+
{ id: "gemini-2.5-pro", name: "Gemini 2.5 Pro", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13099
|
+
{ id: "gemini-2.5-flash", name: "Gemini 2.5 Flash", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13100
|
+
{ id: "gemini-2.5-flash-lite", name: "Gemini 2.5 Flash-Lite", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true }
|
|
13101
|
+
]
|
|
13102
|
+
};
|
|
13103
|
+
|
|
12826
13104
|
// src/providers/azure.ts
|
|
12827
13105
|
var DEFAULT_AZURE_API_VERSION = "2024-12-01-preview";
|
|
12828
|
-
var
|
|
12829
|
-
|
|
12830
|
-
|
|
12831
|
-
|
|
12832
|
-
[/
|
|
12833
|
-
|
|
12834
|
-
|
|
12835
|
-
|
|
12836
|
-
|
|
12837
|
-
|
|
12838
|
-
[/gpt-?4o-mini/, "gpt-4o-mini"],
|
|
12839
|
-
[/gpt-?4o/, "gpt-4o"]
|
|
12840
|
-
];
|
|
12841
|
-
var AZURE_BASE_MODELS = AZURE_BASE_MODEL_RULES.map(([, id]) => id);
|
|
13106
|
+
var CLOUD_MODELS = cloud_model_catalog_default.models;
|
|
13107
|
+
var AZURE_CATALOG = CLOUD_MODELS.filter((m) => m.providers.includes("azure")).slice().sort((a, b) => b.id.length - a.id.length || a.id.localeCompare(b.id));
|
|
13108
|
+
var AZURE_BASE_MODELS = AZURE_CATALOG.map((m) => m.id);
|
|
13109
|
+
function compactModelId(id) {
|
|
13110
|
+
return id.toLowerCase().replace(/[^a-z0-9.]/g, "");
|
|
13111
|
+
}
|
|
13112
|
+
function catalogEntry(id) {
|
|
13113
|
+
const n = id.toLowerCase();
|
|
13114
|
+
return CLOUD_MODELS.find((m) => m.id.toLowerCase() === n);
|
|
13115
|
+
}
|
|
12842
13116
|
function inferAzureBaseModel(deploymentName) {
|
|
12843
13117
|
const n = deploymentName.toLowerCase();
|
|
12844
|
-
|
|
13118
|
+
const compact = compactModelId(n);
|
|
13119
|
+
const hasBareGpt56Alias = compact.includes("gpt5.6");
|
|
13120
|
+
for (const model of AZURE_CATALOG) {
|
|
13121
|
+
if (hasBareGpt56Alias && model.id === "gpt-5") continue;
|
|
13122
|
+
if (n.includes(model.id.toLowerCase()) || compact.includes(compactModelId(model.id))) {
|
|
13123
|
+
return model.id;
|
|
13124
|
+
}
|
|
13125
|
+
}
|
|
13126
|
+
if (hasBareGpt56Alias) return "gpt-5.6-sol";
|
|
13127
|
+
const gpt5At = compact.indexOf("gpt5");
|
|
13128
|
+
if (gpt5At !== -1) {
|
|
13129
|
+
const suffix = compact.slice(gpt5At + "gpt5".length);
|
|
13130
|
+
if (suffix.includes("nano")) return "gpt-5-nano";
|
|
13131
|
+
if (suffix.includes("mini")) return "gpt-5-mini";
|
|
13132
|
+
return "gpt-5";
|
|
13133
|
+
}
|
|
13134
|
+
if (compact.includes("gpt4.1nano")) return "gpt-4.1-nano";
|
|
13135
|
+
if (compact.includes("gpt4.1mini")) return "gpt-4.1-mini";
|
|
13136
|
+
if (compact.includes("gpt4.1")) return "gpt-4.1";
|
|
13137
|
+
if (compact.includes("gpt4omini")) return "gpt-4o-mini";
|
|
13138
|
+
if (compact.includes("gpt4o")) return "gpt-4o";
|
|
12845
13139
|
return null;
|
|
12846
13140
|
}
|
|
13141
|
+
function catalogModelInfo(baseModelId) {
|
|
13142
|
+
const entry = catalogEntry(baseModelId);
|
|
13143
|
+
if (!entry?.contextWindow) return void 0;
|
|
13144
|
+
return {
|
|
13145
|
+
id: entry.id,
|
|
13146
|
+
name: entry.name,
|
|
13147
|
+
provider: "openai",
|
|
13148
|
+
contextWindow: entry.contextWindow,
|
|
13149
|
+
isVisionCapable: entry.vision ?? false,
|
|
13150
|
+
inputCostPer1kTokens: 0,
|
|
13151
|
+
outputCostPer1kTokens: 0,
|
|
13152
|
+
maxOutputTokens: entry.maxOutputTokens ?? 16e3,
|
|
13153
|
+
supportsStreaming: true,
|
|
13154
|
+
isLocal: false,
|
|
13155
|
+
supportsToolUse: entry.toolUse ?? true,
|
|
13156
|
+
pricingUnknown: true
|
|
13157
|
+
};
|
|
13158
|
+
}
|
|
12847
13159
|
function azureModelForDeployment(cfg) {
|
|
12848
13160
|
if (cfg.type !== "azure" || !cfg.deploymentName?.trim()) return null;
|
|
12849
13161
|
const id = cfg.deploymentName.trim();
|
|
12850
13162
|
const name = cfg.label?.trim() || id;
|
|
12851
13163
|
const baseModelId = cfg.model?.trim() || inferAzureBaseModel(id) || void 0;
|
|
12852
|
-
const base = baseModelId ? MODELS[baseModelId] : void 0;
|
|
12853
|
-
if (base) {
|
|
13164
|
+
const base = baseModelId ? MODELS[baseModelId] ?? catalogModelInfo(baseModelId) : void 0;
|
|
13165
|
+
if (base && baseModelId) {
|
|
12854
13166
|
const azurePrice = resolvePricing(
|
|
12855
13167
|
{ id, provider: "azure", isLocal: false, baseModelId },
|
|
12856
13168
|
{ region: cfg.region }
|
|
12857
13169
|
);
|
|
13170
|
+
const exactAzurePrice = !azurePrice.unknown && !azurePrice.estimatedFromProvider;
|
|
13171
|
+
const nativeToolsOnThisTransport = /^gpt-5\.6-(?:sol|terra|luna)$/i.test(baseModelId) ? false : base.supportsToolUse ?? true;
|
|
12858
13172
|
return {
|
|
12859
13173
|
...base,
|
|
12860
13174
|
id,
|
|
12861
|
-
// callable deployment name
|
|
12862
13175
|
name,
|
|
12863
13176
|
provider: "azure",
|
|
12864
13177
|
baseModelId,
|
|
12865
|
-
|
|
12866
|
-
|
|
12867
|
-
...azurePrice.unknown ? {} : {
|
|
13178
|
+
supportsToolUse: nativeToolsOnThisTransport,
|
|
13179
|
+
...!azurePrice.unknown ? {
|
|
12868
13180
|
inputCostPer1kTokens: azurePrice.input,
|
|
12869
13181
|
outputCostPer1kTokens: azurePrice.output,
|
|
12870
|
-
pricingUnknown:
|
|
12871
|
-
}
|
|
13182
|
+
pricingUnknown: !exactAzurePrice
|
|
13183
|
+
} : { pricingUnknown: true }
|
|
12872
13184
|
};
|
|
12873
13185
|
}
|
|
12874
13186
|
return {
|
|
@@ -12883,18 +13195,23 @@ function azureModelForDeployment(cfg) {
|
|
|
12883
13195
|
maxOutputTokens: 16e3,
|
|
12884
13196
|
supportsStreaming: true,
|
|
12885
13197
|
isLocal: false,
|
|
12886
|
-
supportsToolUse: true
|
|
13198
|
+
supportsToolUse: true,
|
|
13199
|
+
pricingUnknown: true
|
|
12887
13200
|
};
|
|
12888
13201
|
}
|
|
13202
|
+
function stripTrailingSlashes3(value) {
|
|
13203
|
+
let end = value.length;
|
|
13204
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) end--;
|
|
13205
|
+
return value.slice(0, end);
|
|
13206
|
+
}
|
|
12889
13207
|
var AzureOpenAIProvider = class extends OpenAIProvider {
|
|
12890
13208
|
constructor(config, model) {
|
|
12891
13209
|
const rawUrl = config.baseUrl ?? AZURE_BASE_URL_TEMPLATE.replace("{resource}", "YOUR_RESOURCE");
|
|
12892
|
-
const endpoint = rawUrl
|
|
13210
|
+
const endpoint = stripTrailingSlashes3(rawUrl);
|
|
12893
13211
|
super(
|
|
12894
13212
|
{
|
|
12895
13213
|
...config,
|
|
12896
13214
|
baseUrl: endpoint
|
|
12897
|
-
// Kept for superclass compatibility if it reads it
|
|
12898
13215
|
},
|
|
12899
13216
|
model
|
|
12900
13217
|
);
|
|
@@ -14637,7 +14954,7 @@ var Keystore = class {
|
|
|
14637
14954
|
const creds = await this.keytar.findCredentials(KEYTAR_SERVICE);
|
|
14638
14955
|
this.cache = Object.fromEntries(creds.map((c) => [c.account, c.password]));
|
|
14639
14956
|
this.backend = "keytar";
|
|
14640
|
-
if (password &&
|
|
14957
|
+
if (password && fs27.existsSync(this.storePath)) {
|
|
14641
14958
|
try {
|
|
14642
14959
|
const fileEntries = this.decryptFile(password);
|
|
14643
14960
|
for (const [k, v] of Object.entries(fileEntries)) {
|
|
@@ -14656,7 +14973,7 @@ var Keystore = class {
|
|
|
14656
14973
|
"Keystore unlock requires a password because the OS keychain (keytar) is not available on this system."
|
|
14657
14974
|
);
|
|
14658
14975
|
}
|
|
14659
|
-
if (!
|
|
14976
|
+
if (!fs27.existsSync(this.storePath)) {
|
|
14660
14977
|
const salt = crypto.randomBytes(SALT_LEN);
|
|
14661
14978
|
this.masterKey = this.deriveKey(password, salt);
|
|
14662
14979
|
this.writeWithSalt({}, salt);
|
|
@@ -14670,7 +14987,7 @@ var Keystore = class {
|
|
|
14670
14987
|
}
|
|
14671
14988
|
/** Synchronous legacy unlock kept for AES-only environments. */
|
|
14672
14989
|
unlockSync(password) {
|
|
14673
|
-
if (!
|
|
14990
|
+
if (!fs27.existsSync(this.storePath)) {
|
|
14674
14991
|
const salt = crypto.randomBytes(SALT_LEN);
|
|
14675
14992
|
this.masterKey = this.deriveKey(password, salt);
|
|
14676
14993
|
this.writeWithSalt({}, salt);
|
|
@@ -14728,7 +15045,7 @@ var Keystore = class {
|
|
|
14728
15045
|
}
|
|
14729
15046
|
}
|
|
14730
15047
|
decryptFile(password, knownSalt) {
|
|
14731
|
-
if (!
|
|
15048
|
+
if (!fs27.existsSync(this.storePath)) return {};
|
|
14732
15049
|
try {
|
|
14733
15050
|
const { salt, ciphertext, iv, tag } = this.readRaw();
|
|
14734
15051
|
const useSalt = knownSalt ?? salt;
|
|
@@ -14750,8 +15067,8 @@ var Keystore = class {
|
|
|
14750
15067
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
14751
15068
|
const tag = cipher.getAuthTag();
|
|
14752
15069
|
const out = Buffer.concat([raw.salt, iv, tag, ciphertext]);
|
|
14753
|
-
|
|
14754
|
-
|
|
15070
|
+
fs27.mkdirSync(path28.dirname(this.storePath), { recursive: true });
|
|
15071
|
+
fs27.writeFileSync(this.storePath, out, { mode: 384 });
|
|
14755
15072
|
}
|
|
14756
15073
|
writeWithSalt(data, salt) {
|
|
14757
15074
|
if (!this.masterKey) throw new Error("writeWithSalt called before masterKey was set");
|
|
@@ -14761,11 +15078,11 @@ var Keystore = class {
|
|
|
14761
15078
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
14762
15079
|
const tag = cipher.getAuthTag();
|
|
14763
15080
|
const out = Buffer.concat([salt, iv, tag, ciphertext]);
|
|
14764
|
-
|
|
14765
|
-
|
|
15081
|
+
fs27.mkdirSync(path28.dirname(this.storePath), { recursive: true });
|
|
15082
|
+
fs27.writeFileSync(this.storePath, out, { mode: 384 });
|
|
14766
15083
|
}
|
|
14767
15084
|
readRaw() {
|
|
14768
|
-
const buf =
|
|
15085
|
+
const buf = fs27.readFileSync(this.storePath);
|
|
14769
15086
|
let offset = 0;
|
|
14770
15087
|
const salt = buf.subarray(offset, offset + SALT_LEN);
|
|
14771
15088
|
offset += SALT_LEN;
|
|
@@ -14798,7 +15115,7 @@ var CascadeIgnore = class {
|
|
|
14798
15115
|
]);
|
|
14799
15116
|
}
|
|
14800
15117
|
async load(workspacePath) {
|
|
14801
|
-
const filePath =
|
|
15118
|
+
const filePath = path28.join(workspacePath, ".cascadeignore");
|
|
14802
15119
|
try {
|
|
14803
15120
|
const content = await fs11.readFile(filePath, "utf-8");
|
|
14804
15121
|
const lines = content.split("\n").filter((l) => l.trim() && !l.startsWith("#"));
|
|
@@ -14809,7 +15126,7 @@ var CascadeIgnore = class {
|
|
|
14809
15126
|
}
|
|
14810
15127
|
isIgnored(filePath, workspacePath) {
|
|
14811
15128
|
try {
|
|
14812
|
-
const relative = workspacePath ?
|
|
15129
|
+
const relative = workspacePath ? path28.relative(workspacePath, filePath) : filePath;
|
|
14813
15130
|
return this.ig.ignores(relative);
|
|
14814
15131
|
} catch {
|
|
14815
15132
|
return false;
|
|
@@ -14820,7 +15137,7 @@ var CascadeIgnore = class {
|
|
|
14820
15137
|
}
|
|
14821
15138
|
};
|
|
14822
15139
|
async function loadCascadeMd(workspacePath) {
|
|
14823
|
-
const filePath =
|
|
15140
|
+
const filePath = path28.join(workspacePath, "CASCADE.md");
|
|
14824
15141
|
try {
|
|
14825
15142
|
const raw = await fs11.readFile(filePath, "utf-8");
|
|
14826
15143
|
return parseCascadeMd(raw);
|
|
@@ -14851,7 +15168,7 @@ ${raw.trim()}`;
|
|
|
14851
15168
|
var MemoryStore = class _MemoryStore {
|
|
14852
15169
|
db;
|
|
14853
15170
|
constructor(dbPath) {
|
|
14854
|
-
|
|
15171
|
+
fs27.mkdirSync(path28.dirname(dbPath), { recursive: true });
|
|
14855
15172
|
try {
|
|
14856
15173
|
this.db = new Database2(dbPath, { timeout: 5e3 });
|
|
14857
15174
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -15749,7 +16066,18 @@ var WebSearchConfigSchema = z.object({
|
|
|
15749
16066
|
/** Tavily API key — get one at https://tavily.com */
|
|
15750
16067
|
tavilyApiKey: z.string().optional(),
|
|
15751
16068
|
/** Max results per search (default 5) */
|
|
15752
|
-
maxResults: z.number().default(5)
|
|
16069
|
+
maxResults: z.number().default(5),
|
|
16070
|
+
/**
|
|
16071
|
+
* Send `searxngUrl` through the SSRF guard. Off for a local run, where the
|
|
16072
|
+
* URL is the machine owner's own config and a self-hosted SearXNG is
|
|
16073
|
+
* routinely on a private address; on for a host that accepts it from a
|
|
16074
|
+
* request. See `src/tools/web-search.ts`.
|
|
16075
|
+
*
|
|
16076
|
+
* It has to be named HERE, not just on the TypeScript interfaces: the config
|
|
16077
|
+
* passes through `CascadeConfigSchema.parse()` on its way into a run, and
|
|
16078
|
+
* zod drops every key this object does not declare.
|
|
16079
|
+
*/
|
|
16080
|
+
guardSearxngUrl: z.boolean().optional()
|
|
15753
16081
|
});
|
|
15754
16082
|
var ToolsConfigSchema = z.object({
|
|
15755
16083
|
shellAllowlist: z.array(z.string()).default([]),
|
|
@@ -16153,7 +16481,7 @@ function credentialEndpointsConflict(type, rowEndpoint, credentialEndpoint) {
|
|
|
16153
16481
|
|
|
16154
16482
|
// src/config/global-credentials.ts
|
|
16155
16483
|
function credentialsPath(globalDir2) {
|
|
16156
|
-
return
|
|
16484
|
+
return path28.join(globalDir2, GLOBAL_CREDENTIALS_FILE);
|
|
16157
16485
|
}
|
|
16158
16486
|
function providerKey(p) {
|
|
16159
16487
|
return p.type;
|
|
@@ -16183,7 +16511,7 @@ function isPersistable(p) {
|
|
|
16183
16511
|
}
|
|
16184
16512
|
function loadGlobalCredentials(globalDir2) {
|
|
16185
16513
|
try {
|
|
16186
|
-
const raw =
|
|
16514
|
+
const raw = fs27.readFileSync(credentialsPath(globalDir2), "utf-8");
|
|
16187
16515
|
const parsed = JSON.parse(raw);
|
|
16188
16516
|
if (!Array.isArray(parsed.providers)) return [];
|
|
16189
16517
|
return parsed.providers.filter(
|
|
@@ -16195,13 +16523,13 @@ function loadGlobalCredentials(globalDir2) {
|
|
|
16195
16523
|
}
|
|
16196
16524
|
function saveGlobalCredentials(globalDir2, providers) {
|
|
16197
16525
|
const filePath = credentialsPath(globalDir2);
|
|
16198
|
-
|
|
16526
|
+
fs27.mkdirSync(globalDir2, { recursive: true, mode: 448 });
|
|
16199
16527
|
const body = { version: 1, providers: providers.filter(isPersistable) };
|
|
16200
16528
|
const tmp = `${filePath}.tmp`;
|
|
16201
|
-
|
|
16202
|
-
|
|
16529
|
+
fs27.writeFileSync(tmp, JSON.stringify(body, null, 2), { encoding: "utf-8", mode: 384 });
|
|
16530
|
+
fs27.renameSync(tmp, filePath);
|
|
16203
16531
|
try {
|
|
16204
|
-
|
|
16532
|
+
fs27.chmodSync(filePath, 384);
|
|
16205
16533
|
} catch {
|
|
16206
16534
|
}
|
|
16207
16535
|
}
|
|
@@ -16602,7 +16930,7 @@ var ConfigManager = class {
|
|
|
16602
16930
|
/** `globalDirOverride` exists for tests — never point it at the real home dir there. */
|
|
16603
16931
|
constructor(workspacePath = process.cwd(), globalDirOverride) {
|
|
16604
16932
|
this.workspacePath = workspacePath;
|
|
16605
|
-
this.globalDir = globalDirOverride ??
|
|
16933
|
+
this.globalDir = globalDirOverride ?? path28.join(os6.homedir(), GLOBAL_CONFIG_DIR);
|
|
16606
16934
|
}
|
|
16607
16935
|
async load() {
|
|
16608
16936
|
this.config = await this.loadConfig();
|
|
@@ -16616,8 +16944,8 @@ var ConfigManager = class {
|
|
|
16616
16944
|
this.ignore = new CascadeIgnore();
|
|
16617
16945
|
await this.ignore.load(this.workspacePath);
|
|
16618
16946
|
this.cascadeMd = await loadCascadeMd(this.workspacePath);
|
|
16619
|
-
this.keystore = new Keystore(
|
|
16620
|
-
this.store = new MemoryStore(
|
|
16947
|
+
this.keystore = new Keystore(path28.join(this.globalDir, GLOBAL_KEYSTORE_FILE));
|
|
16948
|
+
this.store = new MemoryStore(path28.join(this.workspacePath, CASCADE_DB_FILE));
|
|
16621
16949
|
const globalRevoked = stripRevokedCredentials(loadGlobalCredentials(this.globalDir));
|
|
16622
16950
|
const globalCreds = filterRetiredCredentials(globalRevoked.kept);
|
|
16623
16951
|
if (globalRevoked.removed > 0) this.revokedCredentials += globalRevoked.removed;
|
|
@@ -16690,8 +17018,8 @@ var ConfigManager = class {
|
|
|
16690
17018
|
* never reached the disk (see `commitSettings`).
|
|
16691
17019
|
*/
|
|
16692
17020
|
async save(config = this.config) {
|
|
16693
|
-
const configPath =
|
|
16694
|
-
await fs11.mkdir(
|
|
17021
|
+
const configPath = path28.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
17022
|
+
await fs11.mkdir(path28.dirname(configPath), { recursive: true });
|
|
16695
17023
|
await fs11.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
16696
17024
|
try {
|
|
16697
17025
|
saveGlobalCredentials(this.globalDir, config.providers);
|
|
@@ -16741,7 +17069,7 @@ var ConfigManager = class {
|
|
|
16741
17069
|
this.revokedCredentials = 0;
|
|
16742
17070
|
this.revokedPins = [];
|
|
16743
17071
|
this.revokedNotice = void 0;
|
|
16744
|
-
const configPath =
|
|
17072
|
+
const configPath = path28.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
16745
17073
|
try {
|
|
16746
17074
|
const raw = await fs11.readFile(configPath, "utf-8");
|
|
16747
17075
|
const parsed = JSON.parse(raw);
|
|
@@ -16835,7 +17163,7 @@ var ConfigManager = class {
|
|
|
16835
17163
|
return onResource;
|
|
16836
17164
|
}
|
|
16837
17165
|
async persistClearedPins(tiers) {
|
|
16838
|
-
const configPath =
|
|
17166
|
+
const configPath = path28.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
16839
17167
|
try {
|
|
16840
17168
|
const raw = JSON.parse(await fs11.readFile(configPath, "utf-8"));
|
|
16841
17169
|
const models = raw["models"];
|
|
@@ -17429,7 +17757,7 @@ function computeDelegationSavings(stats, t1Model) {
|
|
|
17429
17757
|
var DEFAULT_SNAPSHOT_URL = "https://raw.githubusercontent.com/Varun-SV/Cascade-AI/main/src/core/router/benchmark-data.json";
|
|
17430
17758
|
var OPENROUTER_MODELS_URL = "https://openrouter.ai/api/v1/models";
|
|
17431
17759
|
var FETCH_TIMEOUT_MS = 8e3;
|
|
17432
|
-
var DEFAULT_CACHE_FILE =
|
|
17760
|
+
var DEFAULT_CACHE_FILE = path28.join(os6.homedir(), GLOBAL_CONFIG_DIR, "benchmarks-cache.json");
|
|
17433
17761
|
function normalizeModelId2(id) {
|
|
17434
17762
|
let s = id.toLowerCase();
|
|
17435
17763
|
const slash = s.lastIndexOf("/");
|
|
@@ -17576,7 +17904,7 @@ var LiveDataProvider = class {
|
|
|
17576
17904
|
}
|
|
17577
17905
|
async saveCache() {
|
|
17578
17906
|
try {
|
|
17579
|
-
await fs11.mkdir(
|
|
17907
|
+
await fs11.mkdir(path28.dirname(this.opts.cacheFile), { recursive: true });
|
|
17580
17908
|
const cache = {
|
|
17581
17909
|
fetchedAt: this.fetchedAt,
|
|
17582
17910
|
snapshot: this.snapshot ?? void 0,
|
|
@@ -17683,9 +18011,15 @@ var FAMILY_BENCHMARKS = {
|
|
|
17683
18011
|
"claude-opus": { code: 95, analysis: 92, creative: 90, data: 88 },
|
|
17684
18012
|
"claude-sonnet": { code: 93, analysis: 88, creative: 87, data: 85 },
|
|
17685
18013
|
"claude-haiku": { code: 80, analysis: 75, creative: 76, data: 72 },
|
|
17686
|
-
// OpenAI GPT-5 family
|
|
17687
|
-
//
|
|
17688
|
-
//
|
|
18014
|
+
// OpenAI GPT-5 family. GPT-5.6 is split by durable capability tier instead
|
|
18015
|
+
// of being folded into generic gpt-5: Sol, Terra and Luna have materially
|
|
18016
|
+
// different benchmark/cost envelopes and should compete independently.
|
|
18017
|
+
// Scores are the committed normalized snapshot; provenance is in
|
|
18018
|
+
// scripts/benchmarks/sources/openai-gpt-5.6-2026-08.json.
|
|
18019
|
+
"gpt-5.6-sol": { code: 100, analysis: 98, creative: 88, data: 88 },
|
|
18020
|
+
"gpt-5.6-terra": { code: 97, analysis: 92, creative: 82, data: 85 },
|
|
18021
|
+
"gpt-5.6-luna": { code: 93, analysis: 85, creative: 74, data: 60 },
|
|
18022
|
+
// Older GPT-5 point releases remain distinct where public data supports it.
|
|
17689
18023
|
"gpt-5.5": { code: 97, analysis: 96, creative: 94, data: 95 },
|
|
17690
18024
|
"gpt-5.4": { code: 94, analysis: 94, creative: 92, data: 92 },
|
|
17691
18025
|
"gpt-5.4-mini": { code: 86, analysis: 85, creative: 85, data: 83 },
|
|
@@ -17721,13 +18055,19 @@ var FAMILY_BENCHMARKS = {
|
|
|
17721
18055
|
"llama-small": { code: 55, analysis: 56, creative: 60, data: 54 }
|
|
17722
18056
|
};
|
|
17723
18057
|
var FAMILY_MATCHERS = [
|
|
18058
|
+
[/fable/i, "claude-opus"],
|
|
17724
18059
|
[/opus/i, "claude-opus"],
|
|
17725
18060
|
[/sonnet/i, "claude-sonnet"],
|
|
17726
18061
|
[/haiku/i, "claude-haiku"],
|
|
17727
|
-
// GPT-5 family — ordered most-specific first.
|
|
17728
|
-
//
|
|
17729
|
-
//
|
|
18062
|
+
// GPT-5 family — ordered most-specific first. GPT-5.6 durable tiers carry
|
|
18063
|
+
// their own profiles. 5.4 Nano intentionally maps to the nano class rather
|
|
18064
|
+
// than being swallowed by the generic 5.4 rule.
|
|
18065
|
+
[/gpt-?5\.6.*sol/i, "gpt-5.6-sol"],
|
|
18066
|
+
[/gpt-?5\.6.*terra/i, "gpt-5.6-terra"],
|
|
18067
|
+
[/gpt-?5\.6.*luna/i, "gpt-5.6-luna"],
|
|
18068
|
+
[/gpt-?5\.6(?:\s|$)/i, "gpt-5.6-sol"],
|
|
17730
18069
|
[/gpt-?5\.5/i, "gpt-5.5"],
|
|
18070
|
+
[/gpt-?5\.4.*nano/i, "gpt-5-nano"],
|
|
17731
18071
|
[/gpt-?5\.4.*mini/i, "gpt-5.4-mini"],
|
|
17732
18072
|
[/gpt-?5\.4/i, "gpt-5.4"],
|
|
17733
18073
|
[/gpt-?5.*nano/i, "gpt-5-nano"],
|
|
@@ -20786,8 +21126,8 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : "") + textToolSuffix,
|
|
|
20786
21126
|
// Media generation can run for a minute; without this a cancelled run
|
|
20787
21127
|
// still pays for an image nobody will see.
|
|
20788
21128
|
...this.signal ? { signal: this.signal } : {},
|
|
20789
|
-
saveSnapshot: async (
|
|
20790
|
-
this.store?.addFileSnapshot(this.taskId,
|
|
21129
|
+
saveSnapshot: async (path30, content) => {
|
|
21130
|
+
this.store?.addFileSnapshot(this.taskId, path30, content);
|
|
20791
21131
|
},
|
|
20792
21132
|
sendPeerSync: (to, syncType, content) => {
|
|
20793
21133
|
this.peerBus?.send(this.id, to, syncType, this.assignment?.subtaskId ?? "", content);
|
|
@@ -20990,7 +21330,7 @@ ${assignment.expectedOutput}`;
|
|
|
20990
21330
|
const { promisify: promisify4 } = await import('util');
|
|
20991
21331
|
const execFileAsync3 = promisify4(execFile4);
|
|
20992
21332
|
for (const artifactPath of artifactPaths) {
|
|
20993
|
-
const absolutePath =
|
|
21333
|
+
const absolutePath = path28.resolve(this.artifactRoot(), artifactPath);
|
|
20994
21334
|
try {
|
|
20995
21335
|
const stat = await fs11.stat(absolutePath);
|
|
20996
21336
|
if (!stat.isFile()) {
|
|
@@ -21025,7 +21365,7 @@ ${assignment.expectedOutput}`;
|
|
|
21025
21365
|
issues.push(`PDF artifact looks too small to be valid: ${artifactPath}`);
|
|
21026
21366
|
continue;
|
|
21027
21367
|
}
|
|
21028
|
-
const ext =
|
|
21368
|
+
const ext = path28.extname(absolutePath).toLowerCase();
|
|
21029
21369
|
const check = ext === ".ts" || ext === ".tsx" ? { cmd: "npx", args: ["tsc", "--noEmit", absolutePath] } : ext === ".js" || ext === ".jsx" ? { cmd: process.execPath, args: ["--check", absolutePath] } : ext === ".py" ? { cmd: "python", args: ["-m", "py_compile", absolutePath] } : null;
|
|
21030
21370
|
if (check) {
|
|
21031
21371
|
try {
|
|
@@ -21117,7 +21457,7 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
|
|
|
21117
21457
|
async checkAcceptance(assignment) {
|
|
21118
21458
|
const criteria = assignment.acceptance ?? [];
|
|
21119
21459
|
if (!criteria.length) return [];
|
|
21120
|
-
const resolve2 = (target) =>
|
|
21460
|
+
const resolve2 = (target) => path28.resolve(this.artifactRoot(), target);
|
|
21121
21461
|
const workerCanWriteFiles = canProduceFiles(this.tools.map((t) => t.name));
|
|
21122
21462
|
return evaluateAcceptance(criteria, assignment.files ?? [], {
|
|
21123
21463
|
stat: async (target) => {
|
|
@@ -24421,16 +24761,16 @@ function resolveInWorkspace(workspaceRoot, input) {
|
|
|
24421
24761
|
if (typeof input !== "string" || input.length === 0) {
|
|
24422
24762
|
throw new WorkspaceSandboxError(String(input), workspaceRoot);
|
|
24423
24763
|
}
|
|
24424
|
-
const root =
|
|
24425
|
-
const abs =
|
|
24426
|
-
const rel =
|
|
24427
|
-
if (rel === "" || rel === ".") ; else if (rel.startsWith("..") ||
|
|
24764
|
+
const root = path28.resolve(workspaceRoot);
|
|
24765
|
+
const abs = path28.isAbsolute(input) ? path28.resolve(input) : path28.resolve(root, input);
|
|
24766
|
+
const rel = path28.relative(root, abs);
|
|
24767
|
+
if (rel === "" || rel === ".") ; else if (rel.startsWith("..") || path28.isAbsolute(rel)) {
|
|
24428
24768
|
throw new WorkspaceSandboxError(input, root);
|
|
24429
24769
|
}
|
|
24430
24770
|
try {
|
|
24431
|
-
const real =
|
|
24432
|
-
const realRel =
|
|
24433
|
-
if (realRel !== "" && realRel !== "." && (realRel.startsWith("..") ||
|
|
24771
|
+
const real = fs27.realpathSync(abs);
|
|
24772
|
+
const realRel = path28.relative(root, real);
|
|
24773
|
+
if (realRel !== "" && realRel !== "." && (realRel.startsWith("..") || path28.isAbsolute(realRel))) {
|
|
24434
24774
|
throw new WorkspaceSandboxError(input, root);
|
|
24435
24775
|
}
|
|
24436
24776
|
} catch (e) {
|
|
@@ -24979,9 +25319,9 @@ async function animatePptx(bytes, scheme) {
|
|
|
24979
25319
|
const zip = await import_jszip.default.loadAsync(bytes);
|
|
24980
25320
|
const slidePaths = Object.keys(zip.files).filter((n) => /^ppt\/slides\/slide\d+\.xml$/.test(n));
|
|
24981
25321
|
if (slidePaths.length === 0) return bytes;
|
|
24982
|
-
for (const
|
|
24983
|
-
const xml = await zip.file(
|
|
24984
|
-
zip.file(
|
|
25322
|
+
for (const path30 of slidePaths) {
|
|
25323
|
+
const xml = await zip.file(path30).async("string");
|
|
25324
|
+
zip.file(path30, animateSlideXml(xml, scheme));
|
|
24985
25325
|
}
|
|
24986
25326
|
return await zip.generateAsync({ type: "uint8array", compression: "DEFLATE" });
|
|
24987
25327
|
} catch {
|
|
@@ -25367,7 +25707,7 @@ var GenerateDocumentTool = class extends BaseTool {
|
|
|
25367
25707
|
}
|
|
25368
25708
|
}
|
|
25369
25709
|
const bytes = await renderDocument(ext, content, { name: filePath, loadImageBytes });
|
|
25370
|
-
await fs11.mkdir(
|
|
25710
|
+
await fs11.mkdir(path28.dirname(absPath), { recursive: true });
|
|
25371
25711
|
await fs11.writeFile(absPath, bytes);
|
|
25372
25712
|
const charts = countCharts(content);
|
|
25373
25713
|
return [
|
|
@@ -25585,7 +25925,7 @@ var FileWriteTool = class extends BaseTool {
|
|
|
25585
25925
|
} catch {
|
|
25586
25926
|
}
|
|
25587
25927
|
}
|
|
25588
|
-
await fs11.mkdir(
|
|
25928
|
+
await fs11.mkdir(path28.dirname(absPath), { recursive: true });
|
|
25589
25929
|
await fs11.writeFile(absPath, content, "utf-8");
|
|
25590
25930
|
return `Written ${content.length} characters to ${filePath}`;
|
|
25591
25931
|
}
|
|
@@ -25943,12 +26283,10 @@ ${data.description}`;
|
|
|
25943
26283
|
}
|
|
25944
26284
|
}
|
|
25945
26285
|
};
|
|
25946
|
-
|
|
25947
|
-
// src/tools/browser.ts
|
|
25948
26286
|
var BROWSER_LAUNCH_TIMEOUT_MS = 15e3;
|
|
25949
26287
|
var BrowserTool = class extends BaseTool {
|
|
25950
26288
|
name = "browser";
|
|
25951
|
-
description = "Control a browser: navigate to URLs, click elements, fill forms, take screenshots.
|
|
26289
|
+
description = "Control a browser: navigate to URLs, click elements, fill forms, take screenshots. Screenshots are saved to a file for image_analyze to read.";
|
|
25952
26290
|
inputSchema = {
|
|
25953
26291
|
type: "object",
|
|
25954
26292
|
properties: {
|
|
@@ -26015,7 +26353,14 @@ var BrowserTool = class extends BaseTool {
|
|
|
26015
26353
|
}
|
|
26016
26354
|
case "screenshot": {
|
|
26017
26355
|
const buf = await page2.screenshot({ type: "png" });
|
|
26018
|
-
|
|
26356
|
+
const rel = path28.join(".cascade", "screenshots", `screenshot-${Date.now()}-${randomUUID().slice(0, 8)}.png`);
|
|
26357
|
+
const abs = resolveInWorkspace(this.workspaceRoot, rel);
|
|
26358
|
+
await fs11.mkdir(path28.dirname(abs), { recursive: true });
|
|
26359
|
+
await fs11.writeFile(abs, buf);
|
|
26360
|
+
return [
|
|
26361
|
+
`Screenshot saved to ${abs} (${Math.round(buf.byteLength / 1024)} KB).`,
|
|
26362
|
+
`Call image_analyze with that path to see what is on it \u2014 that needs a vision-capable model.`
|
|
26363
|
+
].join(" ");
|
|
26019
26364
|
}
|
|
26020
26365
|
case "evaluate": {
|
|
26021
26366
|
const result = await page2.evaluate(input["script"]);
|
|
@@ -26083,7 +26428,7 @@ var ImageAnalyzeTool = class extends BaseTool {
|
|
|
26083
26428
|
};
|
|
26084
26429
|
async function fileToImageAttachment(filePath) {
|
|
26085
26430
|
const data = await fs11.readFile(filePath);
|
|
26086
|
-
const ext =
|
|
26431
|
+
const ext = path28.extname(filePath).toLowerCase();
|
|
26087
26432
|
const mimeMap = {
|
|
26088
26433
|
".jpg": "image/jpeg",
|
|
26089
26434
|
".jpeg": "image/jpeg",
|
|
@@ -26117,14 +26462,14 @@ var PDFCreateTool = class extends BaseTool {
|
|
|
26117
26462
|
const filePath = input["path"];
|
|
26118
26463
|
const content = input["content"];
|
|
26119
26464
|
const title = input["title"];
|
|
26120
|
-
const dir =
|
|
26121
|
-
if (!
|
|
26122
|
-
|
|
26465
|
+
const dir = path28.dirname(filePath);
|
|
26466
|
+
if (!fs27.existsSync(dir)) {
|
|
26467
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
26123
26468
|
}
|
|
26124
26469
|
return new Promise((resolve2, reject) => {
|
|
26125
26470
|
try {
|
|
26126
26471
|
const doc = new PDFDocument({ margin: 50 });
|
|
26127
|
-
const stream =
|
|
26472
|
+
const stream = fs27.createWriteStream(filePath);
|
|
26128
26473
|
doc.pipe(stream);
|
|
26129
26474
|
if (title) {
|
|
26130
26475
|
doc.info["Title"] = title;
|
|
@@ -26202,22 +26547,22 @@ var CodeInterpreterTool = class extends BaseTool {
|
|
|
26202
26547
|
}
|
|
26203
26548
|
cmdPrefix = NODE_CMD;
|
|
26204
26549
|
}
|
|
26205
|
-
const tmpDir =
|
|
26206
|
-
if (!
|
|
26207
|
-
|
|
26550
|
+
const tmpDir = path28.join(this.workspaceRoot, ".cascade", "tmp");
|
|
26551
|
+
if (!fs27.existsSync(tmpDir)) {
|
|
26552
|
+
fs27.mkdirSync(tmpDir, { recursive: true });
|
|
26208
26553
|
}
|
|
26209
26554
|
const extension = language === "python" ? "py" : "js";
|
|
26210
26555
|
const fileName = `intp_${randomUUID().slice(0, 8)}.${extension}`;
|
|
26211
|
-
const filePath =
|
|
26212
|
-
|
|
26556
|
+
const filePath = path28.join(tmpDir, fileName);
|
|
26557
|
+
fs27.writeFileSync(filePath, code, "utf-8");
|
|
26213
26558
|
const execArgs = [filePath, ...args];
|
|
26214
26559
|
return new Promise((resolve2) => {
|
|
26215
26560
|
const startMs = Date.now();
|
|
26216
26561
|
execFile(cmdPrefix, execArgs, { cwd: this.workspaceRoot, timeout: 3e4 }, (error, stdout, stderr) => {
|
|
26217
26562
|
const duration = Date.now() - startMs;
|
|
26218
26563
|
try {
|
|
26219
|
-
if (
|
|
26220
|
-
|
|
26564
|
+
if (fs27.existsSync(filePath)) {
|
|
26565
|
+
fs27.unlinkSync(filePath);
|
|
26221
26566
|
}
|
|
26222
26567
|
} catch (cleanupErr) {
|
|
26223
26568
|
console.error(`Failed to cleanup interpreter script ${filePath}:`, cleanupErr);
|
|
@@ -26297,18 +26642,178 @@ ${formatted}`;
|
|
|
26297
26642
|
return `Unknown action: ${action}`;
|
|
26298
26643
|
}
|
|
26299
26644
|
};
|
|
26645
|
+
var SsrfBlockedError = class extends Error {
|
|
26646
|
+
constructor(message) {
|
|
26647
|
+
super(message);
|
|
26648
|
+
this.name = "SsrfBlockedError";
|
|
26649
|
+
}
|
|
26650
|
+
};
|
|
26651
|
+
var ALLOWED_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
26652
|
+
var MAX_REDIRECTS2 = 5;
|
|
26653
|
+
function allowLocal() {
|
|
26654
|
+
return process.env["CASCADE_ALLOW_LOCAL_FETCH"] === "1";
|
|
26655
|
+
}
|
|
26656
|
+
function isPrivateAddress(ip) {
|
|
26657
|
+
const type = net.isIP(ip);
|
|
26658
|
+
if (type === 4) return isPrivateIPv4(ip);
|
|
26659
|
+
if (type === 6) return isPrivateIPv6(ip);
|
|
26660
|
+
return true;
|
|
26661
|
+
}
|
|
26662
|
+
function isPrivateIPv4(ip) {
|
|
26663
|
+
const parts = ip.split(".").map((p) => Number(p));
|
|
26664
|
+
if (parts.length !== 4 || parts.some((p) => Number.isNaN(p) || p < 0 || p > 255)) return true;
|
|
26665
|
+
const [a, b] = parts;
|
|
26666
|
+
if (a === 0) return true;
|
|
26667
|
+
if (a === 10) return true;
|
|
26668
|
+
if (a === 127) return true;
|
|
26669
|
+
if (a === 169 && b === 254) return true;
|
|
26670
|
+
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
26671
|
+
if (a === 192 && b === 168) return true;
|
|
26672
|
+
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
26673
|
+
if (a >= 224) return true;
|
|
26674
|
+
return false;
|
|
26675
|
+
}
|
|
26676
|
+
function ipv6Groups(ip) {
|
|
26677
|
+
let s = ip.toLowerCase().replace(/^\[|\]$/g, "");
|
|
26678
|
+
const zone = s.indexOf("%");
|
|
26679
|
+
if (zone !== -1) s = s.slice(0, zone);
|
|
26680
|
+
const dotted = /^(.*:)(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(s);
|
|
26681
|
+
if (dotted) {
|
|
26682
|
+
const o = [dotted[2], dotted[3], dotted[4], dotted[5]].map((p) => Number(p));
|
|
26683
|
+
if (o.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return null;
|
|
26684
|
+
s = `${dotted[1]}${(o[0] << 8 | o[1]).toString(16)}:${(o[2] << 8 | o[3]).toString(16)}`;
|
|
26685
|
+
}
|
|
26686
|
+
const halves = s.split("::");
|
|
26687
|
+
if (halves.length > 2) return null;
|
|
26688
|
+
const split = (part) => part ? part.split(":") : [];
|
|
26689
|
+
const head = split(halves[0] ?? "");
|
|
26690
|
+
const tail = halves.length === 2 ? split(halves[1] ?? "") : [];
|
|
26691
|
+
const zeros = halves.length === 2 ? 8 - head.length - tail.length : 0;
|
|
26692
|
+
if (zeros < 0) return null;
|
|
26693
|
+
const groups = [...head, ...Array(zeros).fill("0"), ...tail];
|
|
26694
|
+
if (groups.length !== 8) return null;
|
|
26695
|
+
const out = [];
|
|
26696
|
+
for (const g of groups) {
|
|
26697
|
+
if (!/^[0-9a-f]{1,4}$/.test(g)) return null;
|
|
26698
|
+
out.push(parseInt(g, 16));
|
|
26699
|
+
}
|
|
26700
|
+
return out;
|
|
26701
|
+
}
|
|
26702
|
+
function embeddedIPv4(g) {
|
|
26703
|
+
const quad = (hi, lo) => `${hi >> 8}.${hi & 255}.${lo >> 8}.${lo & 255}`;
|
|
26704
|
+
const leadingZero = (n) => g.slice(0, n).every((x) => x === 0);
|
|
26705
|
+
if (leadingZero(5) && g[5] === 65535) return quad(g[6], g[7]);
|
|
26706
|
+
if (leadingZero(6)) return quad(g[6], g[7]);
|
|
26707
|
+
if (g[0] === 100 && g[1] === 65435) {
|
|
26708
|
+
if (g[2] === 1) {
|
|
26709
|
+
return quad(g[3], (g[4] & 255) << 8 | g[5] >> 8);
|
|
26710
|
+
}
|
|
26711
|
+
if (g[2] === 0 && g[3] === 0 && g[4] === 0 && g[5] === 0) return quad(g[6], g[7]);
|
|
26712
|
+
return null;
|
|
26713
|
+
}
|
|
26714
|
+
if (g[0] === 8194) return quad(g[1], g[2]);
|
|
26715
|
+
return null;
|
|
26716
|
+
}
|
|
26717
|
+
function isPrivateIPv6(ip) {
|
|
26718
|
+
const g = ipv6Groups(ip);
|
|
26719
|
+
if (!g) return true;
|
|
26720
|
+
const v4 = embeddedIPv4(g);
|
|
26721
|
+
if (v4) return isPrivateIPv4(v4);
|
|
26722
|
+
if (g[0] === 100 && g[1] === 65435) return true;
|
|
26723
|
+
if (g.every((x) => x === 0)) return true;
|
|
26724
|
+
if (leading7Zero(g) && g[7] === 1) return true;
|
|
26725
|
+
if ((g[0] & 65472) === 65152) return true;
|
|
26726
|
+
if ((g[0] & 65024) === 64512) return true;
|
|
26727
|
+
if ((g[0] & 65280) === 65280) return true;
|
|
26728
|
+
return false;
|
|
26729
|
+
}
|
|
26730
|
+
function leading7Zero(g) {
|
|
26731
|
+
return g.slice(0, 7).every((x) => x === 0);
|
|
26732
|
+
}
|
|
26733
|
+
async function assertPublicUrl(rawUrl) {
|
|
26734
|
+
let url;
|
|
26735
|
+
try {
|
|
26736
|
+
url = new URL(rawUrl);
|
|
26737
|
+
} catch {
|
|
26738
|
+
throw new SsrfBlockedError(`Invalid URL: ${rawUrl}`);
|
|
26739
|
+
}
|
|
26740
|
+
if (!ALLOWED_PROTOCOLS.has(url.protocol)) {
|
|
26741
|
+
throw new SsrfBlockedError(`Blocked URL scheme "${url.protocol}" \u2014 only http and https are allowed.`);
|
|
26742
|
+
}
|
|
26743
|
+
if (allowLocal()) return url;
|
|
26744
|
+
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
26745
|
+
if (net.isIP(host)) {
|
|
26746
|
+
if (isPrivateAddress(host)) {
|
|
26747
|
+
throw new SsrfBlockedError(`Blocked request to non-public address ${host}.`);
|
|
26748
|
+
}
|
|
26749
|
+
return url;
|
|
26750
|
+
}
|
|
26751
|
+
if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) {
|
|
26752
|
+
throw new SsrfBlockedError(`Blocked request to local hostname "${host}".`);
|
|
26753
|
+
}
|
|
26754
|
+
let addresses;
|
|
26755
|
+
try {
|
|
26756
|
+
const records = await dns2.lookup(host, { all: true });
|
|
26757
|
+
addresses = records.map((r) => r.address);
|
|
26758
|
+
} catch {
|
|
26759
|
+
throw new SsrfBlockedError(`Could not resolve host "${host}".`);
|
|
26760
|
+
}
|
|
26761
|
+
if (addresses.length === 0 || addresses.some((addr) => isPrivateAddress(addr))) {
|
|
26762
|
+
throw new SsrfBlockedError(`Blocked request to "${host}" \u2014 resolves to a non-public address.`);
|
|
26763
|
+
}
|
|
26764
|
+
return url;
|
|
26765
|
+
}
|
|
26766
|
+
var ssrfAgent = new Agent({
|
|
26767
|
+
connect: {
|
|
26768
|
+
lookup(hostname, options, callback) {
|
|
26769
|
+
if (allowLocal()) {
|
|
26770
|
+
dnsCallback.lookup(hostname, options, callback);
|
|
26771
|
+
return;
|
|
26772
|
+
}
|
|
26773
|
+
dnsCallback.lookup(hostname, { ...options, all: true }, (err, addresses) => {
|
|
26774
|
+
if (err) return callback(err, "", 0);
|
|
26775
|
+
const list = Array.isArray(addresses) ? addresses : [addresses];
|
|
26776
|
+
const bad = list.find((a) => isPrivateAddress(a.address));
|
|
26777
|
+
if (bad) {
|
|
26778
|
+
return callback(
|
|
26779
|
+
new SsrfBlockedError(`Blocked connection to "${hostname}" \u2014 resolved to non-public address ${bad.address}.`),
|
|
26780
|
+
"",
|
|
26781
|
+
0
|
|
26782
|
+
);
|
|
26783
|
+
}
|
|
26784
|
+
if (options.all) return callback(null, list);
|
|
26785
|
+
const first = list[0];
|
|
26786
|
+
return callback(null, first.address, first.family);
|
|
26787
|
+
});
|
|
26788
|
+
}
|
|
26789
|
+
}
|
|
26790
|
+
});
|
|
26791
|
+
async function safeFetch(rawUrl, init = {}) {
|
|
26792
|
+
let currentUrl = (await assertPublicUrl(rawUrl)).toString();
|
|
26793
|
+
for (let i = 0; i <= MAX_REDIRECTS2; i++) {
|
|
26794
|
+
const resp = await fetch(currentUrl, { ...init, redirect: "manual", dispatcher: ssrfAgent });
|
|
26795
|
+
if (resp.status < 300 || resp.status >= 400) return resp;
|
|
26796
|
+
const location = resp.headers.get("location");
|
|
26797
|
+
if (!location) return resp;
|
|
26798
|
+
const next = new URL(location, currentUrl);
|
|
26799
|
+
await assertPublicUrl(next.toString());
|
|
26800
|
+
currentUrl = next.toString();
|
|
26801
|
+
}
|
|
26802
|
+
throw new SsrfBlockedError(`Too many redirects (>${MAX_REDIRECTS2}).`);
|
|
26803
|
+
}
|
|
26300
26804
|
|
|
26301
26805
|
// src/tools/web-search.ts
|
|
26302
|
-
async function searchSearXNG(query, baseUrl, maxResults) {
|
|
26806
|
+
async function searchSearXNG(query, baseUrl, maxResults, guardUrl = false) {
|
|
26303
26807
|
const url = new URL("/search", baseUrl);
|
|
26304
26808
|
url.searchParams.set("q", query);
|
|
26305
26809
|
url.searchParams.set("format", "json");
|
|
26306
26810
|
url.searchParams.set("categories", "general");
|
|
26307
26811
|
url.searchParams.set("engines", "google,bing,duckduckgo");
|
|
26308
|
-
const
|
|
26812
|
+
const init = {
|
|
26309
26813
|
headers: { "User-Agent": "Cascade-AI/1.0 WebSearchTool" },
|
|
26310
26814
|
signal: AbortSignal.timeout(1e4)
|
|
26311
|
-
}
|
|
26815
|
+
};
|
|
26816
|
+
const resp = guardUrl ? await safeFetch(url.toString(), init) : await fetch(url.toString(), init);
|
|
26312
26817
|
if (!resp.ok) {
|
|
26313
26818
|
throw new Error(`SearXNG returned HTTP ${resp.status}`);
|
|
26314
26819
|
}
|
|
@@ -26437,7 +26942,11 @@ var WebSearchTool = class extends BaseTool {
|
|
|
26437
26942
|
searxngUrl: config.searxngUrl ?? process.env["SEARXNG_URL"],
|
|
26438
26943
|
braveApiKey: config.braveApiKey ?? process.env["BRAVE_SEARCH_API_KEY"],
|
|
26439
26944
|
tavilyApiKey: config.tavilyApiKey ?? process.env["TAVILY_API_KEY"],
|
|
26440
|
-
maxResults: config.maxResults ?? 5
|
|
26945
|
+
maxResults: config.maxResults ?? 5,
|
|
26946
|
+
// Note this reads only from `config`, never from the environment: the
|
|
26947
|
+
// guard tracks the trustworthiness of the URL the host passed in, and an
|
|
26948
|
+
// env var says nothing about that.
|
|
26949
|
+
guardSearxngUrl: config.guardSearxngUrl ?? false
|
|
26441
26950
|
};
|
|
26442
26951
|
}
|
|
26443
26952
|
async execute(input, _options) {
|
|
@@ -26452,7 +26961,7 @@ var WebSearchTool = class extends BaseTool {
|
|
|
26452
26961
|
let anyBackendReachable = false;
|
|
26453
26962
|
if (this.config.searxngUrl) {
|
|
26454
26963
|
try {
|
|
26455
|
-
results = await searchSearXNG(query, this.config.searxngUrl, maxResults);
|
|
26964
|
+
results = await searchSearXNG(query, this.config.searxngUrl, maxResults, this.config.guardSearxngUrl);
|
|
26456
26965
|
anyBackendReachable = true;
|
|
26457
26966
|
if (results.length > 0) return this.formatResults(query, results);
|
|
26458
26967
|
errors.push("SearXNG: returned 0 results");
|
|
@@ -26529,7 +27038,7 @@ var GlobTool = class extends BaseTool {
|
|
|
26529
27038
|
};
|
|
26530
27039
|
async execute(input, _options) {
|
|
26531
27040
|
const pattern = input["pattern"];
|
|
26532
|
-
const searchPath = input["path"] ?
|
|
27041
|
+
const searchPath = input["path"] ? path28.resolve(this.workspaceRoot, input["path"]) : this.workspaceRoot;
|
|
26533
27042
|
const matches = await glob(pattern, {
|
|
26534
27043
|
cwd: searchPath,
|
|
26535
27044
|
ignore: ["node_modules/**", ".git/**", "dist/**", "build/**"],
|
|
@@ -26542,7 +27051,7 @@ var GlobTool = class extends BaseTool {
|
|
|
26542
27051
|
const withMtime = await Promise.all(
|
|
26543
27052
|
matches.map(async (rel) => {
|
|
26544
27053
|
try {
|
|
26545
|
-
const stat = await fs11.stat(
|
|
27054
|
+
const stat = await fs11.stat(path28.join(searchPath, rel));
|
|
26546
27055
|
return { rel, mtime: stat.mtimeMs };
|
|
26547
27056
|
} catch {
|
|
26548
27057
|
return { rel, mtime: 0 };
|
|
@@ -26591,7 +27100,7 @@ var GrepTool = class extends BaseTool {
|
|
|
26591
27100
|
};
|
|
26592
27101
|
async execute(input, _options) {
|
|
26593
27102
|
const pattern = input["pattern"];
|
|
26594
|
-
const searchPath = input["path"] ?
|
|
27103
|
+
const searchPath = input["path"] ? path28.resolve(this.workspaceRoot, input["path"]) : this.workspaceRoot;
|
|
26595
27104
|
const globPattern = input["glob"];
|
|
26596
27105
|
const outputMode = input["output_mode"] ?? "content";
|
|
26597
27106
|
const context = input["context"] ?? 0;
|
|
@@ -26645,12 +27154,12 @@ var GrepTool = class extends BaseTool {
|
|
|
26645
27154
|
nodir: true
|
|
26646
27155
|
});
|
|
26647
27156
|
} catch {
|
|
26648
|
-
files = [
|
|
27157
|
+
files = [path28.relative(searchPath, searchPath) || "."];
|
|
26649
27158
|
}
|
|
26650
27159
|
const results = [];
|
|
26651
27160
|
let totalCount = 0;
|
|
26652
27161
|
for (const rel of files) {
|
|
26653
|
-
const abs =
|
|
27162
|
+
const abs = path28.join(searchPath, rel);
|
|
26654
27163
|
let content;
|
|
26655
27164
|
try {
|
|
26656
27165
|
content = await fs11.readFile(abs, "utf-8");
|
|
@@ -26691,92 +27200,6 @@ Total: ${totalCount} matches`);
|
|
|
26691
27200
|
return results.join("\n");
|
|
26692
27201
|
}
|
|
26693
27202
|
};
|
|
26694
|
-
var SsrfBlockedError = class extends Error {
|
|
26695
|
-
constructor(message) {
|
|
26696
|
-
super(message);
|
|
26697
|
-
this.name = "SsrfBlockedError";
|
|
26698
|
-
}
|
|
26699
|
-
};
|
|
26700
|
-
var ALLOWED_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
26701
|
-
var MAX_REDIRECTS2 = 5;
|
|
26702
|
-
function allowLocal() {
|
|
26703
|
-
return process.env["CASCADE_ALLOW_LOCAL_FETCH"] === "1";
|
|
26704
|
-
}
|
|
26705
|
-
function isPrivateAddress(ip) {
|
|
26706
|
-
const type = net.isIP(ip);
|
|
26707
|
-
if (type === 4) return isPrivateIPv4(ip);
|
|
26708
|
-
if (type === 6) return isPrivateIPv6(ip);
|
|
26709
|
-
return true;
|
|
26710
|
-
}
|
|
26711
|
-
function isPrivateIPv4(ip) {
|
|
26712
|
-
const parts = ip.split(".").map((p) => Number(p));
|
|
26713
|
-
if (parts.length !== 4 || parts.some((p) => Number.isNaN(p) || p < 0 || p > 255)) return true;
|
|
26714
|
-
const [a, b] = parts;
|
|
26715
|
-
if (a === 0) return true;
|
|
26716
|
-
if (a === 10) return true;
|
|
26717
|
-
if (a === 127) return true;
|
|
26718
|
-
if (a === 169 && b === 254) return true;
|
|
26719
|
-
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
26720
|
-
if (a === 192 && b === 168) return true;
|
|
26721
|
-
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
26722
|
-
if (a >= 224) return true;
|
|
26723
|
-
return false;
|
|
26724
|
-
}
|
|
26725
|
-
function isPrivateIPv6(ip) {
|
|
26726
|
-
const lower = ip.toLowerCase().replace(/^\[|\]$/g, "");
|
|
26727
|
-
if (lower === "::1" || lower === "::") return true;
|
|
26728
|
-
if (lower.startsWith("fe80")) return true;
|
|
26729
|
-
if (lower.startsWith("fc") || lower.startsWith("fd")) return true;
|
|
26730
|
-
const mapped = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(lower);
|
|
26731
|
-
if (mapped) return isPrivateIPv4(mapped[1]);
|
|
26732
|
-
return false;
|
|
26733
|
-
}
|
|
26734
|
-
async function assertPublicUrl(rawUrl) {
|
|
26735
|
-
let url;
|
|
26736
|
-
try {
|
|
26737
|
-
url = new URL(rawUrl);
|
|
26738
|
-
} catch {
|
|
26739
|
-
throw new SsrfBlockedError(`Invalid URL: ${rawUrl}`);
|
|
26740
|
-
}
|
|
26741
|
-
if (!ALLOWED_PROTOCOLS.has(url.protocol)) {
|
|
26742
|
-
throw new SsrfBlockedError(`Blocked URL scheme "${url.protocol}" \u2014 only http and https are allowed.`);
|
|
26743
|
-
}
|
|
26744
|
-
if (allowLocal()) return url;
|
|
26745
|
-
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
26746
|
-
if (net.isIP(host)) {
|
|
26747
|
-
if (isPrivateAddress(host)) {
|
|
26748
|
-
throw new SsrfBlockedError(`Blocked request to non-public address ${host}.`);
|
|
26749
|
-
}
|
|
26750
|
-
return url;
|
|
26751
|
-
}
|
|
26752
|
-
if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) {
|
|
26753
|
-
throw new SsrfBlockedError(`Blocked request to local hostname "${host}".`);
|
|
26754
|
-
}
|
|
26755
|
-
let addresses;
|
|
26756
|
-
try {
|
|
26757
|
-
const records = await dns2.lookup(host, { all: true });
|
|
26758
|
-
addresses = records.map((r) => r.address);
|
|
26759
|
-
} catch {
|
|
26760
|
-
throw new SsrfBlockedError(`Could not resolve host "${host}".`);
|
|
26761
|
-
}
|
|
26762
|
-
if (addresses.length === 0 || addresses.some((addr) => isPrivateAddress(addr))) {
|
|
26763
|
-
throw new SsrfBlockedError(`Blocked request to "${host}" \u2014 resolves to a non-public address.`);
|
|
26764
|
-
}
|
|
26765
|
-
return url;
|
|
26766
|
-
}
|
|
26767
|
-
async function safeFetch(rawUrl, init = {}) {
|
|
26768
|
-
let currentUrl = (await assertPublicUrl(rawUrl)).toString();
|
|
26769
|
-
for (let i = 0; i <= MAX_REDIRECTS2; i++) {
|
|
26770
|
-
const resp = await fetch(currentUrl, { ...init, redirect: "manual" });
|
|
26771
|
-
if (resp.status < 300 || resp.status >= 400) return resp;
|
|
26772
|
-
const location = resp.headers.get("location");
|
|
26773
|
-
if (!location) return resp;
|
|
26774
|
-
const next = new URL(location, currentUrl);
|
|
26775
|
-
await assertPublicUrl(next.toString());
|
|
26776
|
-
currentUrl = next.toString();
|
|
26777
|
-
}
|
|
26778
|
-
throw new SsrfBlockedError(`Too many redirects (>${MAX_REDIRECTS2}).`);
|
|
26779
|
-
}
|
|
26780
27203
|
|
|
26781
27204
|
// src/tools/web-fetch.ts
|
|
26782
27205
|
var MAX_CHARS = 5e4;
|
|
@@ -27049,10 +27472,10 @@ var ToolRegistry = class extends EventEmitter {
|
|
|
27049
27472
|
}
|
|
27050
27473
|
isIgnored(filePath) {
|
|
27051
27474
|
if (!filePath) return false;
|
|
27052
|
-
const abs =
|
|
27053
|
-
const rel =
|
|
27054
|
-
if (!rel || rel.startsWith("..") ||
|
|
27055
|
-
const posixRel = rel.split(
|
|
27475
|
+
const abs = path28.resolve(this.workspaceRoot, filePath);
|
|
27476
|
+
const rel = path28.relative(this.workspaceRoot, abs);
|
|
27477
|
+
if (!rel || rel.startsWith("..") || path28.isAbsolute(rel)) return true;
|
|
27478
|
+
const posixRel = rel.split(path28.sep).join("/");
|
|
27056
27479
|
return this.ignoreMatcher.ignores(posixRel);
|
|
27057
27480
|
}
|
|
27058
27481
|
};
|
|
@@ -27286,22 +27709,22 @@ var FileMcpOAuthStore = class {
|
|
|
27286
27709
|
filePath;
|
|
27287
27710
|
load() {
|
|
27288
27711
|
try {
|
|
27289
|
-
return JSON.parse(
|
|
27712
|
+
return JSON.parse(fs27.readFileSync(this.filePath, "utf-8"));
|
|
27290
27713
|
} catch {
|
|
27291
27714
|
return void 0;
|
|
27292
27715
|
}
|
|
27293
27716
|
}
|
|
27294
27717
|
save(state) {
|
|
27295
|
-
|
|
27296
|
-
|
|
27718
|
+
fs27.mkdirSync(path28.dirname(this.filePath), { recursive: true, mode: 448 });
|
|
27719
|
+
fs27.writeFileSync(this.filePath, JSON.stringify(state, null, 2), { mode: 384 });
|
|
27297
27720
|
try {
|
|
27298
|
-
|
|
27721
|
+
fs27.chmodSync(this.filePath, 384);
|
|
27299
27722
|
} catch {
|
|
27300
27723
|
}
|
|
27301
27724
|
}
|
|
27302
27725
|
clear() {
|
|
27303
27726
|
try {
|
|
27304
|
-
|
|
27727
|
+
fs27.rmSync(this.filePath);
|
|
27305
27728
|
} catch {
|
|
27306
27729
|
}
|
|
27307
27730
|
}
|
|
@@ -28139,7 +28562,7 @@ var TaskAnalyzer = class {
|
|
|
28139
28562
|
analysisCache.clear();
|
|
28140
28563
|
}
|
|
28141
28564
|
};
|
|
28142
|
-
var DEFAULT_STATS_FILE =
|
|
28565
|
+
var DEFAULT_STATS_FILE = path28.join(os6.homedir(), ".cascade", "model-perf.json");
|
|
28143
28566
|
var ModelPerformanceTracker = class _ModelPerformanceTracker {
|
|
28144
28567
|
stats = /* @__PURE__ */ new Map();
|
|
28145
28568
|
featureStats = /* @__PURE__ */ new Map();
|
|
@@ -28179,7 +28602,7 @@ var ModelPerformanceTracker = class _ModelPerformanceTracker {
|
|
|
28179
28602
|
async save() {
|
|
28180
28603
|
if (this.readOnly) return;
|
|
28181
28604
|
try {
|
|
28182
|
-
await fs11.mkdir(
|
|
28605
|
+
await fs11.mkdir(path28.dirname(this.statsFile), { recursive: true });
|
|
28183
28606
|
const modelsObj = {};
|
|
28184
28607
|
const featuresObj = {};
|
|
28185
28608
|
for (const [key, stat] of this.stats) modelsObj[key] = stat;
|
|
@@ -28812,7 +29235,7 @@ Required capability: ${description.slice(0, 300)}`;
|
|
|
28812
29235
|
* any dangerous action, so a silently-reloaded tool can't act without approval. */
|
|
28813
29236
|
async loadPersistedTools() {
|
|
28814
29237
|
if (!this.workspacePath || !this.persistEnabled) return;
|
|
28815
|
-
const file =
|
|
29238
|
+
const file = path28.join(this.workspacePath, ".cascade", DYNAMIC_TOOLS_FILE);
|
|
28816
29239
|
try {
|
|
28817
29240
|
const raw = await fs11.readFile(file, "utf-8");
|
|
28818
29241
|
const specs = JSON.parse(raw);
|
|
@@ -28836,8 +29259,8 @@ Required capability: ${description.slice(0, 300)}`;
|
|
|
28836
29259
|
}
|
|
28837
29260
|
async persist() {
|
|
28838
29261
|
if (!this.workspacePath || !this.persistEnabled) return;
|
|
28839
|
-
const dir =
|
|
28840
|
-
const file =
|
|
29262
|
+
const dir = path28.join(this.workspacePath, ".cascade");
|
|
29263
|
+
const file = path28.join(dir, DYNAMIC_TOOLS_FILE);
|
|
28841
29264
|
try {
|
|
28842
29265
|
await fs11.mkdir(dir, { recursive: true });
|
|
28843
29266
|
await fs11.writeFile(file, JSON.stringify(Array.from(this.specs.values()), null, 2), "utf-8");
|
|
@@ -28857,12 +29280,12 @@ var WorldStateDB = class {
|
|
|
28857
29280
|
constructor(workspacePath, debugMode = false) {
|
|
28858
29281
|
this.workspacePath = workspacePath;
|
|
28859
29282
|
this.debugMode = debugMode;
|
|
28860
|
-
const cascadeDir =
|
|
28861
|
-
if (!
|
|
28862
|
-
|
|
29283
|
+
const cascadeDir = path28.join(workspacePath, ".cascade");
|
|
29284
|
+
if (!fs27.existsSync(cascadeDir)) {
|
|
29285
|
+
fs27.mkdirSync(cascadeDir, { recursive: true });
|
|
28863
29286
|
}
|
|
28864
|
-
this.keyPath =
|
|
28865
|
-
this.dbPath =
|
|
29287
|
+
this.keyPath = path28.join(cascadeDir, "world_state.key");
|
|
29288
|
+
this.dbPath = path28.join(cascadeDir, "world_state.db");
|
|
28866
29289
|
this.initEncryptionKey();
|
|
28867
29290
|
this.db = new Database2(this.dbPath);
|
|
28868
29291
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -28919,11 +29342,11 @@ var WorldStateDB = class {
|
|
|
28919
29342
|
).run(e, r, row.encrypted_value, row.source_worker, row.timestamp, validTo, change);
|
|
28920
29343
|
}
|
|
28921
29344
|
initEncryptionKey() {
|
|
28922
|
-
if (
|
|
28923
|
-
this.encryptionKey =
|
|
29345
|
+
if (fs27.existsSync(this.keyPath)) {
|
|
29346
|
+
this.encryptionKey = fs27.readFileSync(this.keyPath);
|
|
28924
29347
|
} else {
|
|
28925
29348
|
this.encryptionKey = crypto.randomBytes(32);
|
|
28926
|
-
|
|
29349
|
+
fs27.writeFileSync(this.keyPath, this.encryptionKey);
|
|
28927
29350
|
}
|
|
28928
29351
|
}
|
|
28929
29352
|
encrypt(text) {
|
|
@@ -29209,9 +29632,9 @@ var WorldStateDB = class {
|
|
|
29209
29632
|
dumpDebugIfNeeded() {
|
|
29210
29633
|
if (!this.debugMode) return;
|
|
29211
29634
|
try {
|
|
29212
|
-
const dumpPath =
|
|
29635
|
+
const dumpPath = path28.join(os6.tmpdir(), "cascade_world_state_debug.json");
|
|
29213
29636
|
const entries = this.getAllEntries();
|
|
29214
|
-
|
|
29637
|
+
fs27.writeFileSync(dumpPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
29215
29638
|
} catch (err) {
|
|
29216
29639
|
console.error("Failed to dump debug world state", err);
|
|
29217
29640
|
}
|
|
@@ -29268,7 +29691,7 @@ var ResumeStore = class {
|
|
|
29268
29691
|
createdAt: checkpoint.createdAt ?? new Date(timestamp).toISOString()
|
|
29269
29692
|
};
|
|
29270
29693
|
await promises.mkdir(this.dir, { recursive: true });
|
|
29271
|
-
const finalPath =
|
|
29694
|
+
const finalPath = path28.join(this.dir, `${timestamp}-${safeId(record.taskId)}.json`);
|
|
29272
29695
|
const tempPath = `${finalPath}.${process.pid}.tmp`;
|
|
29273
29696
|
await promises.writeFile(tempPath, JSON.stringify(record, null, 2), "utf-8");
|
|
29274
29697
|
await promises.rename(tempPath, finalPath);
|
|
@@ -29291,7 +29714,7 @@ var ResumeStore = class {
|
|
|
29291
29714
|
const checkpoints = [];
|
|
29292
29715
|
for (const candidate of candidates) {
|
|
29293
29716
|
try {
|
|
29294
|
-
const raw = await promises.readFile(
|
|
29717
|
+
const raw = await promises.readFile(path28.join(this.dir, candidate.name), "utf-8");
|
|
29295
29718
|
const parsed = JSON.parse(raw);
|
|
29296
29719
|
if (isCheckpoint(parsed)) checkpoints.push(parsed);
|
|
29297
29720
|
} catch {
|
|
@@ -29330,7 +29753,7 @@ var ResumeStore = class {
|
|
|
29330
29753
|
const source = entries.find((name) => FILE_PATTERN.exec(name)?.[2] === wanted);
|
|
29331
29754
|
if (!source) return null;
|
|
29332
29755
|
const claimId = `${this.now()}-${safeId(target.taskId)}`;
|
|
29333
|
-
await promises.rename(
|
|
29756
|
+
await promises.rename(path28.join(this.dir, source), path28.join(this.dir, `${claimId}${CLAIM_SUFFIX}`));
|
|
29334
29757
|
return { checkpoint: target, claimId };
|
|
29335
29758
|
} catch {
|
|
29336
29759
|
return null;
|
|
@@ -29340,8 +29763,8 @@ var ResumeStore = class {
|
|
|
29340
29763
|
async release(claimId) {
|
|
29341
29764
|
try {
|
|
29342
29765
|
await promises.rename(
|
|
29343
|
-
|
|
29344
|
-
|
|
29766
|
+
path28.join(this.dir, `${claimId}${CLAIM_SUFFIX}`),
|
|
29767
|
+
path28.join(this.dir, `${claimId}.json`)
|
|
29345
29768
|
);
|
|
29346
29769
|
} catch {
|
|
29347
29770
|
}
|
|
@@ -29349,7 +29772,7 @@ var ResumeStore = class {
|
|
|
29349
29772
|
/** Discard a claim for good — the resumed run has taken ownership. */
|
|
29350
29773
|
async settle(claimId) {
|
|
29351
29774
|
try {
|
|
29352
|
-
await promises.rm(
|
|
29775
|
+
await promises.rm(path28.join(this.dir, `${claimId}${CLAIM_SUFFIX}`), { force: true });
|
|
29353
29776
|
} catch {
|
|
29354
29777
|
}
|
|
29355
29778
|
}
|
|
@@ -29378,8 +29801,8 @@ var ResumeStore = class {
|
|
|
29378
29801
|
const stamp2 = Number(/^(\d+)-/.exec(name)?.[1]);
|
|
29379
29802
|
if (!Number.isFinite(stamp2) || stamp2 >= cutoff) continue;
|
|
29380
29803
|
await promises.rename(
|
|
29381
|
-
|
|
29382
|
-
|
|
29804
|
+
path28.join(this.dir, name),
|
|
29805
|
+
path28.join(this.dir, `${name.slice(0, -CLAIM_SUFFIX.length)}.json`)
|
|
29383
29806
|
);
|
|
29384
29807
|
reclaimed++;
|
|
29385
29808
|
}
|
|
@@ -29395,7 +29818,7 @@ var ResumeStore = class {
|
|
|
29395
29818
|
await Promise.all(entries.map(async (name) => {
|
|
29396
29819
|
const match = FILE_PATTERN.exec(name);
|
|
29397
29820
|
if (match?.[2] === wanted) {
|
|
29398
|
-
await promises.rm(
|
|
29821
|
+
await promises.rm(path28.join(this.dir, name), { force: true });
|
|
29399
29822
|
}
|
|
29400
29823
|
}));
|
|
29401
29824
|
} catch {
|
|
@@ -29410,7 +29833,7 @@ var ResumeStore = class {
|
|
|
29410
29833
|
const doomed = files.filter((f, index) => f.timestamp < cutoff || index >= this.maxCheckpoints);
|
|
29411
29834
|
const staleTemps = entries.filter((name) => name.endsWith(".tmp")).filter((name) => (Number(FILE_PATTERN.exec(name.replace(/\.\d+\.tmp$/, ".json"))?.[1]) || 0) < cutoff);
|
|
29412
29835
|
await Promise.all([...doomed.map((f) => f.name), ...staleTemps].map(
|
|
29413
|
-
(name) => promises.rm(
|
|
29836
|
+
(name) => promises.rm(path28.join(this.dir, name), { force: true })
|
|
29414
29837
|
));
|
|
29415
29838
|
} catch {
|
|
29416
29839
|
}
|
|
@@ -29787,7 +30210,7 @@ var WorkspaceIndex = class {
|
|
|
29787
30210
|
isIgnored;
|
|
29788
30211
|
chunker;
|
|
29789
30212
|
constructor(opts) {
|
|
29790
|
-
this.root =
|
|
30213
|
+
this.root = path28.resolve(opts.root);
|
|
29791
30214
|
this.db = opts.db;
|
|
29792
30215
|
this.namespace = opts.namespace ?? "code";
|
|
29793
30216
|
this.extensions = new Set((opts.extensions ?? DEFAULT_EXTENSIONS).map((e) => e.replace(/^\./, "").toLowerCase()));
|
|
@@ -29819,14 +30242,14 @@ var WorkspaceIndex = class {
|
|
|
29819
30242
|
return;
|
|
29820
30243
|
}
|
|
29821
30244
|
for (const entry of entries) {
|
|
29822
|
-
const abs =
|
|
30245
|
+
const abs = path28.join(dir, entry.name);
|
|
29823
30246
|
if (entry.isDirectory()) {
|
|
29824
30247
|
if (HARD_SKIP_DIRS.has(entry.name) || this.isIgnored(abs)) continue;
|
|
29825
30248
|
await walk(abs);
|
|
29826
30249
|
} else if (entry.isFile()) {
|
|
29827
|
-
const ext =
|
|
30250
|
+
const ext = path28.extname(entry.name).slice(1).toLowerCase();
|
|
29828
30251
|
if (!this.extensions.has(ext) || this.isIgnored(abs)) continue;
|
|
29829
|
-
out.push(
|
|
30252
|
+
out.push(path28.relative(this.root, abs));
|
|
29830
30253
|
}
|
|
29831
30254
|
}
|
|
29832
30255
|
};
|
|
@@ -29856,7 +30279,7 @@ var WorkspaceIndex = class {
|
|
|
29856
30279
|
const entries = [];
|
|
29857
30280
|
for (const rel of rels) {
|
|
29858
30281
|
try {
|
|
29859
|
-
const abs =
|
|
30282
|
+
const abs = path28.join(this.root, rel);
|
|
29860
30283
|
const stat = await fs11.stat(abs);
|
|
29861
30284
|
if (stat.size > this.maxFileBytes) continue;
|
|
29862
30285
|
const buf = await fs11.readFile(abs);
|
|
@@ -30346,13 +30769,13 @@ var Cascade = class _Cascade extends EventEmitter {
|
|
|
30346
30769
|
this.toolRegistry = new ToolRegistry(this.config.tools, workspacePath);
|
|
30347
30770
|
try {
|
|
30348
30771
|
this.router.setDeadModelStore(new DeadModelStore(
|
|
30349
|
-
fileDeadModelPersistence(
|
|
30772
|
+
fileDeadModelPersistence(path28.join(workspacePath, ".cascade", "dead-models.json"))
|
|
30350
30773
|
));
|
|
30351
30774
|
} catch {
|
|
30352
30775
|
}
|
|
30353
30776
|
try {
|
|
30354
30777
|
this.resumeStore = new ResumeStore({
|
|
30355
|
-
dir:
|
|
30778
|
+
dir: path28.join(workspacePath, ".cascade", "resume")
|
|
30356
30779
|
});
|
|
30357
30780
|
} catch {
|
|
30358
30781
|
}
|
|
@@ -30440,8 +30863,8 @@ var Cascade = class _Cascade extends EventEmitter {
|
|
|
30440
30863
|
this.emit("log", { level: "warn", message: "Code index enabled but no embeddings-capable provider is configured \u2014 skipping." });
|
|
30441
30864
|
return;
|
|
30442
30865
|
}
|
|
30443
|
-
const dbPath = ci.dbPath ||
|
|
30444
|
-
|
|
30866
|
+
const dbPath = ci.dbPath || path28.join(this.workspacePath, ".cascade", "code-index.db");
|
|
30867
|
+
fs27.mkdirSync(path28.dirname(dbPath), { recursive: true });
|
|
30445
30868
|
const db = new Database2(dbPath);
|
|
30446
30869
|
db.pragma("journal_mode = WAL");
|
|
30447
30870
|
const complete = chatCompleterFromProviders(this.config.providers);
|
|
@@ -32215,8 +32638,8 @@ function replaceInPlace(target, source) {
|
|
|
32215
32638
|
}
|
|
32216
32639
|
function writeConfigFile(configPath, config) {
|
|
32217
32640
|
try {
|
|
32218
|
-
|
|
32219
|
-
|
|
32641
|
+
fs27.mkdirSync(path28.dirname(configPath), { recursive: true });
|
|
32642
|
+
fs27.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
32220
32643
|
return { ok: true };
|
|
32221
32644
|
} catch (err) {
|
|
32222
32645
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
@@ -32626,7 +33049,7 @@ function aggregateCostStats(sessions, opts = {}) {
|
|
|
32626
33049
|
}
|
|
32627
33050
|
|
|
32628
33051
|
// src/dashboard/server.ts
|
|
32629
|
-
var __dirname$1 =
|
|
33052
|
+
var __dirname$1 = path28.dirname(fileURLToPath(import.meta.url));
|
|
32630
33053
|
var ORPHANED_ESCALATION_GRACE_MS = 3e4;
|
|
32631
33054
|
var MASK = "***";
|
|
32632
33055
|
function masked(key, value) {
|
|
@@ -32945,7 +33368,7 @@ var DashboardServer = class {
|
|
|
32945
33368
|
* silently and still typecheck.
|
|
32946
33369
|
*/
|
|
32947
33370
|
persistConfig(config) {
|
|
32948
|
-
const result = writeConfigFile(
|
|
33371
|
+
const result = writeConfigFile(path28.join(this.workspacePath, CASCADE_CONFIG_FILE), config);
|
|
32949
33372
|
if (!result.ok) console.warn(`[dashboard] Failed to persist config: ${result.error}`);
|
|
32950
33373
|
return result;
|
|
32951
33374
|
}
|
|
@@ -32964,7 +33387,7 @@ var DashboardServer = class {
|
|
|
32964
33387
|
*/
|
|
32965
33388
|
syncGlobalCredentials() {
|
|
32966
33389
|
try {
|
|
32967
|
-
saveGlobalCredentials(
|
|
33390
|
+
saveGlobalCredentials(path28.join(os6.homedir(), GLOBAL_CONFIG_DIR), this.config.providers ?? []);
|
|
32968
33391
|
} catch (err) {
|
|
32969
33392
|
console.warn(`[dashboard] Failed to sync global credentials: ${err instanceof Error ? err.message : String(err)}`);
|
|
32970
33393
|
}
|
|
@@ -32979,15 +33402,15 @@ var DashboardServer = class {
|
|
|
32979
33402
|
resolveDashboardSecret() {
|
|
32980
33403
|
const fromConfig = this.config.dashboard.secret ?? process.env["CASCADE_DASHBOARD_SECRET"];
|
|
32981
33404
|
if (fromConfig) return fromConfig;
|
|
32982
|
-
const secretPath =
|
|
33405
|
+
const secretPath = path28.join(this.workspacePath, CASCADE_DASHBOARD_SECRET_FILE);
|
|
32983
33406
|
try {
|
|
32984
|
-
if (
|
|
32985
|
-
const existing =
|
|
33407
|
+
if (fs27.existsSync(secretPath)) {
|
|
33408
|
+
const existing = fs27.readFileSync(secretPath, "utf-8").trim();
|
|
32986
33409
|
if (existing.length >= 16) return existing;
|
|
32987
33410
|
}
|
|
32988
33411
|
const generated = randomUUID();
|
|
32989
|
-
|
|
32990
|
-
|
|
33412
|
+
fs27.mkdirSync(path28.dirname(secretPath), { recursive: true });
|
|
33413
|
+
fs27.writeFileSync(secretPath, generated, { encoding: "utf-8", mode: 384 });
|
|
32991
33414
|
if (this.config.dashboard.auth) {
|
|
32992
33415
|
console.warn(
|
|
32993
33416
|
`Dashboard auth enabled with no secret configured; persisted a generated secret to ${secretPath}. Set CASCADE_DASHBOARD_SECRET or config.dashboard.secret to override.`
|
|
@@ -33014,7 +33437,7 @@ var DashboardServer = class {
|
|
|
33014
33437
|
// ── Setup ─────────────────────────────────────
|
|
33015
33438
|
getGlobalStore() {
|
|
33016
33439
|
if (!this.globalStore) {
|
|
33017
|
-
const globalDbPath =
|
|
33440
|
+
const globalDbPath = path28.join(os6.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
33018
33441
|
this.globalStore = new MemoryStore(globalDbPath);
|
|
33019
33442
|
}
|
|
33020
33443
|
return this.globalStore;
|
|
@@ -33394,12 +33817,12 @@ ${prompt}`;
|
|
|
33394
33817
|
}
|
|
33395
33818
|
}
|
|
33396
33819
|
watchRuntimeChanges() {
|
|
33397
|
-
const workspaceDbPath =
|
|
33398
|
-
const globalDbPath =
|
|
33820
|
+
const workspaceDbPath = path28.join(this.workspacePath, CASCADE_DB_FILE);
|
|
33821
|
+
const globalDbPath = path28.join(os6.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
33399
33822
|
const watchPaths = [workspaceDbPath, globalDbPath].filter((p, index, arr) => arr.indexOf(p) === index);
|
|
33400
33823
|
for (const watchPath of watchPaths) {
|
|
33401
|
-
if (!
|
|
33402
|
-
|
|
33824
|
+
if (!fs27.existsSync(watchPath)) continue;
|
|
33825
|
+
fs27.watchFile(watchPath, { interval: 3e3 }, () => {
|
|
33403
33826
|
this.throttledBroadcast(watchPath === globalDbPath ? "global" : "workspace");
|
|
33404
33827
|
});
|
|
33405
33828
|
}
|
|
@@ -33521,7 +33944,7 @@ ${prompt}`;
|
|
|
33521
33944
|
const sessionId = req.params.id;
|
|
33522
33945
|
this.store.deleteSession(sessionId);
|
|
33523
33946
|
this.store.deleteRuntimeSession(sessionId);
|
|
33524
|
-
const globalDbPath =
|
|
33947
|
+
const globalDbPath = path28.join(os6.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
33525
33948
|
const globalStore = new MemoryStore(globalDbPath);
|
|
33526
33949
|
try {
|
|
33527
33950
|
globalStore.deleteRuntimeSession(sessionId);
|
|
@@ -33614,7 +34037,7 @@ ${prompt}`;
|
|
|
33614
34037
|
});
|
|
33615
34038
|
this.app.delete("/api/sessions", auth2, (req, res) => {
|
|
33616
34039
|
const body = req.body;
|
|
33617
|
-
const globalDbPath =
|
|
34040
|
+
const globalDbPath = path28.join(os6.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
33618
34041
|
if (body?.ids && Array.isArray(body.ids) && body.ids.length > 0) {
|
|
33619
34042
|
const globalStore = new MemoryStore(globalDbPath);
|
|
33620
34043
|
try {
|
|
@@ -33637,7 +34060,7 @@ ${prompt}`;
|
|
|
33637
34060
|
});
|
|
33638
34061
|
this.app.delete("/api/runtime", auth2, (_req, res) => {
|
|
33639
34062
|
this.store.deleteAllRuntimeNodes();
|
|
33640
|
-
const globalDbPath =
|
|
34063
|
+
const globalDbPath = path28.join(os6.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
33641
34064
|
const globalStore = new MemoryStore(globalDbPath);
|
|
33642
34065
|
try {
|
|
33643
34066
|
globalStore.deleteAllRuntimeNodes();
|
|
@@ -33722,12 +34145,12 @@ ${prompt}`;
|
|
|
33722
34145
|
if (body["tierLimits"]) this.config.tierLimits = { ...this.config.tierLimits, ...body["tierLimits"] };
|
|
33723
34146
|
if (body["budget"]) this.config.budget = { ...this.config.budget, ...body["budget"] };
|
|
33724
34147
|
try {
|
|
33725
|
-
const configPath =
|
|
33726
|
-
const existing =
|
|
34148
|
+
const configPath = path28.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
34149
|
+
const existing = fs27.existsSync(configPath) ? JSON.parse(fs27.readFileSync(configPath, "utf-8")) : {};
|
|
33727
34150
|
const updated = { ...existing, tierLimits: this.config.tierLimits, budget: this.config.budget };
|
|
33728
34151
|
const tmp = configPath + ".tmp";
|
|
33729
|
-
|
|
33730
|
-
|
|
34152
|
+
fs27.writeFileSync(tmp, JSON.stringify(updated, null, 2), "utf-8");
|
|
34153
|
+
fs27.renameSync(tmp, configPath);
|
|
33731
34154
|
res.json({ ok: true });
|
|
33732
34155
|
} catch (err) {
|
|
33733
34156
|
res.status(500).json({ error: `Failed to save config: ${err instanceof Error ? err.message : String(err)}` });
|
|
@@ -33755,7 +34178,7 @@ ${prompt}`;
|
|
|
33755
34178
|
this.app.get("/api/runtime", auth2, (req, res) => {
|
|
33756
34179
|
const scope = req.query["scope"] ?? "workspace";
|
|
33757
34180
|
if (scope === "global") {
|
|
33758
|
-
const globalDbPath =
|
|
34181
|
+
const globalDbPath = path28.join(os6.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
33759
34182
|
const globalStore = new MemoryStore(globalDbPath);
|
|
33760
34183
|
try {
|
|
33761
34184
|
res.json({
|
|
@@ -34096,13 +34519,13 @@ ${prompt}`;
|
|
|
34096
34519
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
34097
34520
|
}
|
|
34098
34521
|
});
|
|
34099
|
-
const prodPath =
|
|
34100
|
-
const devPath =
|
|
34101
|
-
const webDistPath =
|
|
34102
|
-
if (
|
|
34522
|
+
const prodPath = path28.resolve(__dirname$1, "../web/dist");
|
|
34523
|
+
const devPath = path28.resolve(__dirname$1, "../../web/dist");
|
|
34524
|
+
const webDistPath = fs27.existsSync(prodPath) ? prodPath : devPath;
|
|
34525
|
+
if (fs27.existsSync(webDistPath)) {
|
|
34103
34526
|
this.app.use(express.static(webDistPath));
|
|
34104
34527
|
this.app.get("*", (_req, res) => {
|
|
34105
|
-
res.sendFile(
|
|
34528
|
+
res.sendFile(path28.join(webDistPath, "index.html"));
|
|
34106
34529
|
});
|
|
34107
34530
|
} else {
|
|
34108
34531
|
this.app.get("/", (_req, res) => {
|
|
@@ -34289,14 +34712,14 @@ function planRetrieval(ctx) {
|
|
|
34289
34712
|
}
|
|
34290
34713
|
var CLOUD_SESSION_FILE = "cloud-session.json";
|
|
34291
34714
|
function globalDir(homeDir = os6.homedir()) {
|
|
34292
|
-
return
|
|
34715
|
+
return path28.join(homeDir, GLOBAL_CONFIG_DIR);
|
|
34293
34716
|
}
|
|
34294
34717
|
function cloudSessionPath(dir = globalDir()) {
|
|
34295
|
-
return
|
|
34718
|
+
return path28.join(dir, CLOUD_SESSION_FILE);
|
|
34296
34719
|
}
|
|
34297
34720
|
function loadCloudSession(dir = globalDir()) {
|
|
34298
34721
|
try {
|
|
34299
|
-
const raw =
|
|
34722
|
+
const raw = fs27.readFileSync(cloudSessionPath(dir), "utf-8");
|
|
34300
34723
|
const parsed = JSON.parse(raw);
|
|
34301
34724
|
if (!parsed?.refreshToken || !parsed?.serverUrl) return null;
|
|
34302
34725
|
return parsed;
|
|
@@ -34305,17 +34728,17 @@ function loadCloudSession(dir = globalDir()) {
|
|
|
34305
34728
|
}
|
|
34306
34729
|
}
|
|
34307
34730
|
function saveCloudSession(session, dir = globalDir()) {
|
|
34308
|
-
|
|
34731
|
+
fs27.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
34309
34732
|
const file = cloudSessionPath(dir);
|
|
34310
|
-
|
|
34733
|
+
fs27.writeFileSync(file, JSON.stringify(session, null, 2), { mode: 384 });
|
|
34311
34734
|
try {
|
|
34312
|
-
|
|
34735
|
+
fs27.chmodSync(file, 384);
|
|
34313
34736
|
} catch {
|
|
34314
34737
|
}
|
|
34315
34738
|
}
|
|
34316
34739
|
function clearCloudSession(dir = globalDir()) {
|
|
34317
34740
|
try {
|
|
34318
|
-
|
|
34741
|
+
fs27.rmSync(cloudSessionPath(dir));
|
|
34319
34742
|
} catch {
|
|
34320
34743
|
}
|
|
34321
34744
|
}
|
|
@@ -34487,16 +34910,16 @@ var CloudClient = class _CloudClient {
|
|
|
34487
34910
|
return (await this.refresh()).accessToken;
|
|
34488
34911
|
}
|
|
34489
34912
|
/** Authenticated request that refreshes once on a 401 (e.g. server-side revoke). */
|
|
34490
|
-
async authed(
|
|
34491
|
-
const call = (token) => fetch(this.url(
|
|
34913
|
+
async authed(path30, init = {}) {
|
|
34914
|
+
const call = (token) => fetch(this.url(path30), { ...init, headers: { ...init.headers ?? {}, Authorization: `Bearer ${token}` } });
|
|
34492
34915
|
let res = await call(await this.accessToken());
|
|
34493
34916
|
if (res.status === 401) res = await call((await this.refresh()).accessToken);
|
|
34494
34917
|
if (!res.ok) throw new Error(`Request failed (${res.status}).`);
|
|
34495
34918
|
const text = await res.text();
|
|
34496
34919
|
return text ? JSON.parse(text) : {};
|
|
34497
34920
|
}
|
|
34498
|
-
authedGet(
|
|
34499
|
-
return this.authed(
|
|
34921
|
+
authedGet(path30) {
|
|
34922
|
+
return this.authed(path30);
|
|
34500
34923
|
}
|
|
34501
34924
|
async fetchMe(token) {
|
|
34502
34925
|
const res = await fetch(this.url("/api/me"), { headers: { Authorization: `Bearer ${token}` } });
|
|
@@ -34861,6 +35284,6 @@ function applySyncBundle(bundle, config, cleanup) {
|
|
|
34861
35284
|
return next;
|
|
34862
35285
|
}
|
|
34863
35286
|
|
|
34864
|
-
export { AZURE_BASE_MODELS, 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, CHARS_PER_TOKEN2 as CHARS_PER_TOKEN, COMPLEXITY_T2_COUNT, Cascade, CascadeCancelledError, CascadeIgnore, CascadeRouter, CascadeToolError, CloudClient, CodeSearchTool, ConfigManager, CurrentPageTool, DEFAULT_API_PORT, DEFAULT_APPROVAL_REQUIRED, DEFAULT_AUTO_SUMMARIZE_AT, DEFAULT_CLOUD_URL, DEFAULT_CONTEXT_LIMIT, DEFAULT_DASHBOARD_PORT, DEFAULT_MAX_SESSION_MESSAGES, DEFAULT_RETENTION_DAYS, DEFAULT_THEME, DOCUMENT_MIME, DashboardServer, DependencyScheduler, FileMcpOAuthStore, GLOBAL_CONFIG_DIR, GLOBAL_CREDENTIALS_FILE, GLOBAL_DB_FILE, GLOBAL_KEYSTORE_FILE, GLOBAL_RUNTIME_DB_FILE, GenerateDocumentTool, GraphRetriever, GraphSearchTool, HooksRunner, Keystore, LLMReranker, LM_STUDIO_BASE_URL, MAX_PAGE_TEXT_CHARS, MCP_TOOL_PREFIX, MODELS, McpClient, McpOAuthProvider, MemoryStore, OLLAMA_BASE_URL, OpenAICompatibleEmbedder, PROVIDER_DISPLAY_NAMES, RESUME_SCHEMA_VERSION, ResumeStore, Retriever, SqliteVectorStore, T1Administrator, T1_MODEL_PRIORITY, T2Manager, T2_MODEL_PRIORITY, T3Worker, T3_MODEL_PRIORITY, THEME_NAMES, TOOL_NAMES, TaskGraphValidationError, TaskScheduler, Telemetry, ToolRegistry, VISION_MODEL_PRIORITY, WorkspaceIndex, applyEndpointEdit, applyProviderApiKey, applyProviderCredential, applySettingsCredentials, applySettingsPayload, applySyncBundle, azureModelForDeployment, beginMcpOAuth, buildDocumentTools, buildManifest, buildSessionTranscript, bytesToBase64, cagCharBudget, chartKind, chartToTableRows, chatCompleterFromProviders, chunkCode, chunkText2 as chunkText, commitSettings, compileSectionGraph, compileSubtaskGraph, compileTaskGraph, completeMcpOAuth, connectMcpWithLoopbackOAuth, createCascade, credentialDispositionForEdit, credentialEndpointIdentity, decryptJSON as decryptSyncBlob, diffManifest, disambiguateMcpServerNames, discoverMcpAuthServer, discoverMcpTools, distillSessionFacts, embedderFromProviders, encryptJSON as encryptSyncBlob, endpointFromSettingsPayload, evaluateAcceptance, explainRefusal, extractCharts, failures, fileExt, fileOAuthProvider, gatherSyncBundle, hasDefaultEndpoint, hasProviderCredential, hasUsableProvider, hashContent, heuristicCodeChunker, inferAzureBaseModel, inlineRuns, isDocumentFormat, isMcpToolName, matchImageLine, mcpServerPrefix, mcpToolName, nodeHttpFetch, normalizeEndpoint, parseBlocks, parseChartSpec, parseDelimited, parseRankOrder, parseSlide, planRetrieval, preferIpv4Host, priorAzureRow, reciprocalRankFusion, refreshMcpToken, removeMcpServerDenials, renderDocument, renderDocx, renderPptx, renderXlsx, runCascade, sameAzureEndpoint, sameCredentialEndpoint, sameEndpoint, sessionWorthRemembering, settingsSnapshot, sniffImage, splitSlides, streamCascade, stripInline, summarizeCompleted, undecided, uniqueMcpServerName };
|
|
35287
|
+
export { AZURE_BASE_MODELS, 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, CHARS_PER_TOKEN2 as CHARS_PER_TOKEN, COMPLEXITY_T2_COUNT, Cascade, CascadeCancelledError, CascadeConfigSchema, CascadeIgnore, CascadeRouter, CascadeToolError, CloudClient, CodeSearchTool, ConfigManager, CurrentPageTool, DEFAULT_API_PORT, DEFAULT_APPROVAL_REQUIRED, DEFAULT_AUTO_SUMMARIZE_AT, DEFAULT_CLOUD_URL, DEFAULT_CONTEXT_LIMIT, DEFAULT_DASHBOARD_PORT, DEFAULT_MAX_SESSION_MESSAGES, DEFAULT_RETENTION_DAYS, DEFAULT_THEME, DOCUMENT_MIME, DashboardServer, DependencyScheduler, FileMcpOAuthStore, GLOBAL_CONFIG_DIR, GLOBAL_CREDENTIALS_FILE, GLOBAL_DB_FILE, GLOBAL_KEYSTORE_FILE, GLOBAL_RUNTIME_DB_FILE, GenerateDocumentTool, GraphRetriever, GraphSearchTool, HooksRunner, Keystore, LLMReranker, LM_STUDIO_BASE_URL, MAX_PAGE_TEXT_CHARS, MCP_TOOL_PREFIX, MODELS, McpClient, McpOAuthProvider, MemoryStore, OLLAMA_BASE_URL, OpenAICompatibleEmbedder, PROVIDER_DISPLAY_NAMES, RESUME_SCHEMA_VERSION, ResumeStore, Retriever, SqliteVectorStore, T1Administrator, T1_MODEL_PRIORITY, T2Manager, T2_MODEL_PRIORITY, T3Worker, T3_MODEL_PRIORITY, THEME_NAMES, TOOL_NAMES, TaskGraphValidationError, TaskScheduler, Telemetry, ToolRegistry, VISION_MODEL_PRIORITY, WorkspaceIndex, applyEndpointEdit, applyProviderApiKey, applyProviderCredential, applySettingsCredentials, applySettingsPayload, applySyncBundle, azureModelForDeployment, beginMcpOAuth, buildDocumentTools, buildManifest, buildSessionTranscript, bytesToBase64, cagCharBudget, chartKind, chartToTableRows, chatCompleterFromProviders, chunkCode, chunkText2 as chunkText, commitSettings, compileSectionGraph, compileSubtaskGraph, compileTaskGraph, completeMcpOAuth, connectMcpWithLoopbackOAuth, createCascade, credentialDispositionForEdit, credentialEndpointIdentity, decryptJSON as decryptSyncBlob, diffManifest, disambiguateMcpServerNames, discoverMcpAuthServer, discoverMcpTools, distillSessionFacts, embedderFromProviders, encryptJSON as encryptSyncBlob, endpointFromSettingsPayload, evaluateAcceptance, explainRefusal, extractCharts, failures, fileExt, fileOAuthProvider, gatherSyncBundle, hasDefaultEndpoint, hasProviderCredential, hasUsableProvider, hashContent, heuristicCodeChunker, inferAzureBaseModel, inlineRuns, isDocumentFormat, isMcpToolName, matchImageLine, mcpServerPrefix, mcpToolName, nodeHttpFetch, normalizeEndpoint, parseBlocks, parseChartSpec, parseDelimited, parseRankOrder, parseSlide, planRetrieval, preferIpv4Host, priorAzureRow, reciprocalRankFusion, refreshMcpToken, removeMcpServerDenials, renderDocument, renderDocx, renderPptx, renderXlsx, runCascade, sameAzureEndpoint, sameCredentialEndpoint, sameEndpoint, sessionWorthRemembering, settingsSnapshot, sniffImage, splitSlides, streamCascade, stripInline, summarizeCompleted, undecided, uniqueMcpServerName };
|
|
34865
35288
|
//# sourceMappingURL=index.js.map
|
|
34866
35289
|
//# sourceMappingURL=index.js.map
|