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.cjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var Database2 = require('better-sqlite3');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var path28 = require('path');
|
|
5
|
+
var fs27 = require('fs');
|
|
6
6
|
var os6 = require('os');
|
|
7
7
|
var crypto = require('crypto');
|
|
8
8
|
var EventEmitter = require('events');
|
|
9
9
|
var glob = require('glob');
|
|
10
10
|
var Anthropic = require('@anthropic-ai/sdk');
|
|
11
|
-
var
|
|
11
|
+
var dnsCallback = require('dns');
|
|
12
12
|
var http = require('http');
|
|
13
13
|
var https = require('https');
|
|
14
14
|
var zlib = require('zlib');
|
|
@@ -24,6 +24,7 @@ var simpleGit = require('simple-git');
|
|
|
24
24
|
var PDFDocument = require('pdfkit');
|
|
25
25
|
var dns2 = require('dns/promises');
|
|
26
26
|
var net = require('net');
|
|
27
|
+
var undici = require('undici');
|
|
27
28
|
var index_js = require('@modelcontextprotocol/sdk/client/index.js');
|
|
28
29
|
var stdio_js = require('@modelcontextprotocol/sdk/client/stdio.js');
|
|
29
30
|
var streamableHttp_js = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
|
|
@@ -61,13 +62,13 @@ function _interopNamespace(e) {
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
var Database2__default = /*#__PURE__*/_interopDefault(Database2);
|
|
64
|
-
var
|
|
65
|
-
var
|
|
65
|
+
var path28__default = /*#__PURE__*/_interopDefault(path28);
|
|
66
|
+
var fs27__default = /*#__PURE__*/_interopDefault(fs27);
|
|
66
67
|
var os6__default = /*#__PURE__*/_interopDefault(os6);
|
|
67
68
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
68
69
|
var EventEmitter__default = /*#__PURE__*/_interopDefault(EventEmitter);
|
|
69
70
|
var Anthropic__default = /*#__PURE__*/_interopDefault(Anthropic);
|
|
70
|
-
var
|
|
71
|
+
var dnsCallback__default = /*#__PURE__*/_interopDefault(dnsCallback);
|
|
71
72
|
var http__default = /*#__PURE__*/_interopDefault(http);
|
|
72
73
|
var https__default = /*#__PURE__*/_interopDefault(https);
|
|
73
74
|
var zlib__default = /*#__PURE__*/_interopDefault(zlib);
|
|
@@ -178,16 +179,16 @@ var require_isarray = __commonJS({
|
|
|
178
179
|
}
|
|
179
180
|
});
|
|
180
181
|
|
|
181
|
-
// node_modules/
|
|
182
|
+
// node_modules/readable-stream/lib/internal/streams/stream.js
|
|
182
183
|
var require_stream = __commonJS({
|
|
183
|
-
"node_modules/
|
|
184
|
+
"node_modules/readable-stream/lib/internal/streams/stream.js"(exports, module) {
|
|
184
185
|
module.exports = __require("stream");
|
|
185
186
|
}
|
|
186
187
|
});
|
|
187
188
|
|
|
188
|
-
// node_modules/
|
|
189
|
+
// node_modules/readable-stream/node_modules/safe-buffer/index.js
|
|
189
190
|
var require_safe_buffer = __commonJS({
|
|
190
|
-
"node_modules/
|
|
191
|
+
"node_modules/readable-stream/node_modules/safe-buffer/index.js"(exports, module) {
|
|
191
192
|
var buffer = __require("buffer");
|
|
192
193
|
var Buffer2 = buffer.Buffer;
|
|
193
194
|
function copyProps(src, dst) {
|
|
@@ -305,7 +306,7 @@ var require_util = __commonJS({
|
|
|
305
306
|
typeof arg === "undefined";
|
|
306
307
|
}
|
|
307
308
|
exports.isPrimitive = isPrimitive;
|
|
308
|
-
exports.isBuffer = Buffer.isBuffer;
|
|
309
|
+
exports.isBuffer = __require("buffer").Buffer.isBuffer;
|
|
309
310
|
function objectToString(o) {
|
|
310
311
|
return Object.prototype.toString.call(o);
|
|
311
312
|
}
|
|
@@ -358,9 +359,9 @@ var require_inherits = __commonJS({
|
|
|
358
359
|
}
|
|
359
360
|
});
|
|
360
361
|
|
|
361
|
-
// node_modules/
|
|
362
|
+
// node_modules/readable-stream/lib/internal/streams/BufferList.js
|
|
362
363
|
var require_BufferList = __commonJS({
|
|
363
|
-
"node_modules/
|
|
364
|
+
"node_modules/readable-stream/lib/internal/streams/BufferList.js"(exports, module) {
|
|
364
365
|
function _classCallCheck(instance, Constructor) {
|
|
365
366
|
if (!(instance instanceof Constructor)) {
|
|
366
367
|
throw new TypeError("Cannot call a class as a function");
|
|
@@ -435,9 +436,9 @@ var require_BufferList = __commonJS({
|
|
|
435
436
|
}
|
|
436
437
|
});
|
|
437
438
|
|
|
438
|
-
// node_modules/
|
|
439
|
+
// node_modules/readable-stream/lib/internal/streams/destroy.js
|
|
439
440
|
var require_destroy = __commonJS({
|
|
440
|
-
"node_modules/
|
|
441
|
+
"node_modules/readable-stream/lib/internal/streams/destroy.js"(exports, module) {
|
|
441
442
|
var pna = require_process_nextick_args();
|
|
442
443
|
function destroy(err, cb) {
|
|
443
444
|
var _this = this;
|
|
@@ -510,9 +511,9 @@ var require_node = __commonJS({
|
|
|
510
511
|
}
|
|
511
512
|
});
|
|
512
513
|
|
|
513
|
-
// node_modules/
|
|
514
|
+
// node_modules/readable-stream/lib/_stream_writable.js
|
|
514
515
|
var require_stream_writable = __commonJS({
|
|
515
|
-
"node_modules/
|
|
516
|
+
"node_modules/readable-stream/lib/_stream_writable.js"(exports, module) {
|
|
516
517
|
var pna = require_process_nextick_args();
|
|
517
518
|
module.exports = Writable;
|
|
518
519
|
function CorkedRequest(state) {
|
|
@@ -949,9 +950,9 @@ var require_stream_writable = __commonJS({
|
|
|
949
950
|
}
|
|
950
951
|
});
|
|
951
952
|
|
|
952
|
-
// node_modules/
|
|
953
|
+
// node_modules/readable-stream/lib/_stream_duplex.js
|
|
953
954
|
var require_stream_duplex = __commonJS({
|
|
954
|
-
"node_modules/
|
|
955
|
+
"node_modules/readable-stream/lib/_stream_duplex.js"(exports, module) {
|
|
955
956
|
var pna = require_process_nextick_args();
|
|
956
957
|
var objectKeys = Object.keys || function(obj) {
|
|
957
958
|
var keys2 = [];
|
|
@@ -1025,10 +1026,67 @@ var require_stream_duplex = __commonJS({
|
|
|
1025
1026
|
}
|
|
1026
1027
|
});
|
|
1027
1028
|
|
|
1028
|
-
// node_modules/
|
|
1029
|
+
// node_modules/string_decoder/node_modules/safe-buffer/index.js
|
|
1030
|
+
var require_safe_buffer2 = __commonJS({
|
|
1031
|
+
"node_modules/string_decoder/node_modules/safe-buffer/index.js"(exports, module) {
|
|
1032
|
+
var buffer = __require("buffer");
|
|
1033
|
+
var Buffer2 = buffer.Buffer;
|
|
1034
|
+
function copyProps(src, dst) {
|
|
1035
|
+
for (var key in src) {
|
|
1036
|
+
dst[key] = src[key];
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
if (Buffer2.from && Buffer2.alloc && Buffer2.allocUnsafe && Buffer2.allocUnsafeSlow) {
|
|
1040
|
+
module.exports = buffer;
|
|
1041
|
+
} else {
|
|
1042
|
+
copyProps(buffer, exports);
|
|
1043
|
+
exports.Buffer = SafeBuffer;
|
|
1044
|
+
}
|
|
1045
|
+
function SafeBuffer(arg, encodingOrOffset, length) {
|
|
1046
|
+
return Buffer2(arg, encodingOrOffset, length);
|
|
1047
|
+
}
|
|
1048
|
+
copyProps(Buffer2, SafeBuffer);
|
|
1049
|
+
SafeBuffer.from = function(arg, encodingOrOffset, length) {
|
|
1050
|
+
if (typeof arg === "number") {
|
|
1051
|
+
throw new TypeError("Argument must not be a number");
|
|
1052
|
+
}
|
|
1053
|
+
return Buffer2(arg, encodingOrOffset, length);
|
|
1054
|
+
};
|
|
1055
|
+
SafeBuffer.alloc = function(size, fill, encoding) {
|
|
1056
|
+
if (typeof size !== "number") {
|
|
1057
|
+
throw new TypeError("Argument must be a number");
|
|
1058
|
+
}
|
|
1059
|
+
var buf = Buffer2(size);
|
|
1060
|
+
if (fill !== void 0) {
|
|
1061
|
+
if (typeof encoding === "string") {
|
|
1062
|
+
buf.fill(fill, encoding);
|
|
1063
|
+
} else {
|
|
1064
|
+
buf.fill(fill);
|
|
1065
|
+
}
|
|
1066
|
+
} else {
|
|
1067
|
+
buf.fill(0);
|
|
1068
|
+
}
|
|
1069
|
+
return buf;
|
|
1070
|
+
};
|
|
1071
|
+
SafeBuffer.allocUnsafe = function(size) {
|
|
1072
|
+
if (typeof size !== "number") {
|
|
1073
|
+
throw new TypeError("Argument must be a number");
|
|
1074
|
+
}
|
|
1075
|
+
return Buffer2(size);
|
|
1076
|
+
};
|
|
1077
|
+
SafeBuffer.allocUnsafeSlow = function(size) {
|
|
1078
|
+
if (typeof size !== "number") {
|
|
1079
|
+
throw new TypeError("Argument must be a number");
|
|
1080
|
+
}
|
|
1081
|
+
return buffer.SlowBuffer(size);
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
// node_modules/string_decoder/lib/string_decoder.js
|
|
1029
1087
|
var require_string_decoder = __commonJS({
|
|
1030
|
-
"node_modules/
|
|
1031
|
-
var Buffer2 =
|
|
1088
|
+
"node_modules/string_decoder/lib/string_decoder.js"(exports) {
|
|
1089
|
+
var Buffer2 = require_safe_buffer2().Buffer;
|
|
1032
1090
|
var isEncoding = Buffer2.isEncoding || function(encoding) {
|
|
1033
1091
|
encoding = "" + encoding;
|
|
1034
1092
|
switch (encoding && encoding.toLowerCase()) {
|
|
@@ -1262,9 +1320,9 @@ var require_string_decoder = __commonJS({
|
|
|
1262
1320
|
}
|
|
1263
1321
|
});
|
|
1264
1322
|
|
|
1265
|
-
// node_modules/
|
|
1323
|
+
// node_modules/readable-stream/lib/_stream_readable.js
|
|
1266
1324
|
var require_stream_readable = __commonJS({
|
|
1267
|
-
"node_modules/
|
|
1325
|
+
"node_modules/readable-stream/lib/_stream_readable.js"(exports, module) {
|
|
1268
1326
|
var pna = require_process_nextick_args();
|
|
1269
1327
|
module.exports = Readable2;
|
|
1270
1328
|
var isArray = require_isarray();
|
|
@@ -1947,9 +2005,9 @@ var require_stream_readable = __commonJS({
|
|
|
1947
2005
|
}
|
|
1948
2006
|
});
|
|
1949
2007
|
|
|
1950
|
-
// node_modules/
|
|
2008
|
+
// node_modules/readable-stream/lib/_stream_transform.js
|
|
1951
2009
|
var require_stream_transform = __commonJS({
|
|
1952
|
-
"node_modules/
|
|
2010
|
+
"node_modules/readable-stream/lib/_stream_transform.js"(exports, module) {
|
|
1953
2011
|
module.exports = Transform;
|
|
1954
2012
|
var Duplex = require_stream_duplex();
|
|
1955
2013
|
var util = Object.create(require_util());
|
|
@@ -2046,9 +2104,9 @@ var require_stream_transform = __commonJS({
|
|
|
2046
2104
|
}
|
|
2047
2105
|
});
|
|
2048
2106
|
|
|
2049
|
-
// node_modules/
|
|
2107
|
+
// node_modules/readable-stream/lib/_stream_passthrough.js
|
|
2050
2108
|
var require_stream_passthrough = __commonJS({
|
|
2051
|
-
"node_modules/
|
|
2109
|
+
"node_modules/readable-stream/lib/_stream_passthrough.js"(exports, module) {
|
|
2052
2110
|
module.exports = PassThrough;
|
|
2053
2111
|
var Transform = require_stream_transform();
|
|
2054
2112
|
var util = Object.create(require_util());
|
|
@@ -2064,9 +2122,9 @@ var require_stream_passthrough = __commonJS({
|
|
|
2064
2122
|
}
|
|
2065
2123
|
});
|
|
2066
2124
|
|
|
2067
|
-
// node_modules/
|
|
2125
|
+
// node_modules/readable-stream/readable.js
|
|
2068
2126
|
var require_readable = __commonJS({
|
|
2069
|
-
"node_modules/
|
|
2127
|
+
"node_modules/readable-stream/readable.js"(exports, module) {
|
|
2070
2128
|
var Stream = __require("stream");
|
|
2071
2129
|
if (process.env.READABLE_STREAM === "disable" && Stream) {
|
|
2072
2130
|
module.exports = Stream;
|
|
@@ -2975,8 +3033,8 @@ var require_utils = __commonJS({
|
|
|
2975
3033
|
var result = transform[inputType][outputType](input);
|
|
2976
3034
|
return result;
|
|
2977
3035
|
};
|
|
2978
|
-
exports.resolve = function(
|
|
2979
|
-
var parts =
|
|
3036
|
+
exports.resolve = function(path30) {
|
|
3037
|
+
var parts = path30.split("/");
|
|
2980
3038
|
var result = [];
|
|
2981
3039
|
for (var index = 0; index < parts.length; index++) {
|
|
2982
3040
|
var part = parts[index];
|
|
@@ -8791,18 +8849,18 @@ var require_object = __commonJS({
|
|
|
8791
8849
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
8792
8850
|
this.files[name] = object;
|
|
8793
8851
|
};
|
|
8794
|
-
var parentFolder = function(
|
|
8795
|
-
if (
|
|
8796
|
-
|
|
8852
|
+
var parentFolder = function(path30) {
|
|
8853
|
+
if (path30.slice(-1) === "/") {
|
|
8854
|
+
path30 = path30.substring(0, path30.length - 1);
|
|
8797
8855
|
}
|
|
8798
|
-
var lastSlash =
|
|
8799
|
-
return lastSlash > 0 ?
|
|
8856
|
+
var lastSlash = path30.lastIndexOf("/");
|
|
8857
|
+
return lastSlash > 0 ? path30.substring(0, lastSlash) : "";
|
|
8800
8858
|
};
|
|
8801
|
-
var forceTrailingSlash = function(
|
|
8802
|
-
if (
|
|
8803
|
-
|
|
8859
|
+
var forceTrailingSlash = function(path30) {
|
|
8860
|
+
if (path30.slice(-1) !== "/") {
|
|
8861
|
+
path30 += "/";
|
|
8804
8862
|
}
|
|
8805
|
-
return
|
|
8863
|
+
return path30;
|
|
8806
8864
|
};
|
|
8807
8865
|
var folderAdd = function(name, createFolders) {
|
|
8808
8866
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -9801,12 +9859,12 @@ var init_audit_logger = __esm({
|
|
|
9801
9859
|
constructor(workspacePath, debugMode = false) {
|
|
9802
9860
|
this.workspacePath = workspacePath;
|
|
9803
9861
|
this.debugMode = debugMode;
|
|
9804
|
-
const cascadeDir =
|
|
9805
|
-
if (!
|
|
9806
|
-
|
|
9862
|
+
const cascadeDir = path28__default.default.join(workspacePath, ".cascade");
|
|
9863
|
+
if (!fs27__default.default.existsSync(cascadeDir)) {
|
|
9864
|
+
fs27__default.default.mkdirSync(cascadeDir, { recursive: true });
|
|
9807
9865
|
}
|
|
9808
|
-
this.keyPath =
|
|
9809
|
-
this.dbPath =
|
|
9866
|
+
this.keyPath = path28__default.default.join(cascadeDir, "audit_log.key");
|
|
9867
|
+
this.dbPath = path28__default.default.join(cascadeDir, "audit_log.db");
|
|
9810
9868
|
this.initEncryptionKey();
|
|
9811
9869
|
this.db = new Database2__default.default(this.dbPath);
|
|
9812
9870
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -9836,11 +9894,11 @@ var init_audit_logger = __esm({
|
|
|
9836
9894
|
return crypto__default.default.createHash("sha256").update(`${prevHash}|${timestamp}|${eventType}|${tierId}|${encryptedPayload}`).digest("hex");
|
|
9837
9895
|
}
|
|
9838
9896
|
initEncryptionKey() {
|
|
9839
|
-
if (
|
|
9840
|
-
this.encryptionKey =
|
|
9897
|
+
if (fs27__default.default.existsSync(this.keyPath)) {
|
|
9898
|
+
this.encryptionKey = fs27__default.default.readFileSync(this.keyPath);
|
|
9841
9899
|
} else {
|
|
9842
9900
|
this.encryptionKey = crypto__default.default.randomBytes(32);
|
|
9843
|
-
|
|
9901
|
+
fs27__default.default.writeFileSync(this.keyPath, this.encryptionKey);
|
|
9844
9902
|
}
|
|
9845
9903
|
}
|
|
9846
9904
|
encrypt(text) {
|
|
@@ -9918,9 +9976,9 @@ var init_audit_logger = __esm({
|
|
|
9918
9976
|
dumpDebugIfNeeded() {
|
|
9919
9977
|
if (!this.debugMode) return;
|
|
9920
9978
|
try {
|
|
9921
|
-
const dumpPath =
|
|
9979
|
+
const dumpPath = path28__default.default.join(os6__default.default.tmpdir(), "cascade_audit_logs_debug.json");
|
|
9922
9980
|
const entries = this.getAllLogs();
|
|
9923
|
-
|
|
9981
|
+
fs27__default.default.writeFileSync(dumpPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
9924
9982
|
} catch (err) {
|
|
9925
9983
|
console.error("Failed to dump debug audit logs", err);
|
|
9926
9984
|
}
|
|
@@ -11611,7 +11669,7 @@ function reconcilePrice(model, live) {
|
|
|
11611
11669
|
}
|
|
11612
11670
|
|
|
11613
11671
|
// src/constants.ts
|
|
11614
|
-
var CASCADE_VERSION = "0.
|
|
11672
|
+
var CASCADE_VERSION = "0.77.0";
|
|
11615
11673
|
var CASCADE_CONFIG_DIR = ".cascade";
|
|
11616
11674
|
var CASCADE_MD_FILE = "CASCADE.md";
|
|
11617
11675
|
var CASCADE_IGNORE_FILE = ".cascadeignore";
|
|
@@ -11632,64 +11690,88 @@ var DEFAULT_AUTO_SUMMARIZE_AT = 15e4;
|
|
|
11632
11690
|
var DEFAULT_MAX_SESSION_MESSAGES = 1e3;
|
|
11633
11691
|
var DEFAULT_RETENTION_DAYS = 90;
|
|
11634
11692
|
var MODELS = {
|
|
11635
|
-
// Anthropic
|
|
11636
|
-
"claude-
|
|
11637
|
-
id: "claude-
|
|
11638
|
-
name: "Claude
|
|
11693
|
+
// Anthropic — active Claude API models (2026-08-27).
|
|
11694
|
+
"claude-fable-5": {
|
|
11695
|
+
id: "claude-fable-5",
|
|
11696
|
+
name: "Claude Fable 5",
|
|
11639
11697
|
provider: "anthropic",
|
|
11640
|
-
contextWindow:
|
|
11698
|
+
contextWindow: 1e6,
|
|
11641
11699
|
isVisionCapable: true,
|
|
11642
|
-
inputCostPer1kTokens: 0.
|
|
11643
|
-
outputCostPer1kTokens: 0.
|
|
11644
|
-
maxOutputTokens:
|
|
11700
|
+
inputCostPer1kTokens: 0.01,
|
|
11701
|
+
outputCostPer1kTokens: 0.05,
|
|
11702
|
+
maxOutputTokens: 128e3,
|
|
11645
11703
|
supportsStreaming: true,
|
|
11646
11704
|
isLocal: false
|
|
11647
11705
|
},
|
|
11648
|
-
"claude-
|
|
11649
|
-
id: "claude-
|
|
11650
|
-
name: "Claude
|
|
11706
|
+
"claude-opus-5": {
|
|
11707
|
+
id: "claude-opus-5",
|
|
11708
|
+
name: "Claude Opus 5",
|
|
11651
11709
|
provider: "anthropic",
|
|
11652
|
-
contextWindow:
|
|
11710
|
+
contextWindow: 1e6,
|
|
11653
11711
|
isVisionCapable: true,
|
|
11654
|
-
inputCostPer1kTokens:
|
|
11655
|
-
outputCostPer1kTokens: 0.
|
|
11656
|
-
maxOutputTokens:
|
|
11712
|
+
inputCostPer1kTokens: 5e-3,
|
|
11713
|
+
outputCostPer1kTokens: 0.025,
|
|
11714
|
+
maxOutputTokens: 128e3,
|
|
11657
11715
|
supportsStreaming: true,
|
|
11658
11716
|
isLocal: false
|
|
11659
11717
|
},
|
|
11660
|
-
"claude-
|
|
11661
|
-
id: "claude-
|
|
11662
|
-
name: "Claude
|
|
11718
|
+
"claude-opus-4-8": {
|
|
11719
|
+
id: "claude-opus-4-8",
|
|
11720
|
+
name: "Claude Opus 4.8",
|
|
11663
11721
|
provider: "anthropic",
|
|
11664
|
-
contextWindow:
|
|
11722
|
+
contextWindow: 1e6,
|
|
11665
11723
|
isVisionCapable: true,
|
|
11666
|
-
inputCostPer1kTokens:
|
|
11667
|
-
outputCostPer1kTokens:
|
|
11668
|
-
maxOutputTokens:
|
|
11724
|
+
inputCostPer1kTokens: 5e-3,
|
|
11725
|
+
outputCostPer1kTokens: 0.025,
|
|
11726
|
+
maxOutputTokens: 128e3,
|
|
11669
11727
|
supportsStreaming: true,
|
|
11670
11728
|
isLocal: false
|
|
11671
11729
|
},
|
|
11672
|
-
"claude-
|
|
11673
|
-
id: "claude-
|
|
11674
|
-
name: "Claude
|
|
11730
|
+
"claude-opus-4-7": {
|
|
11731
|
+
id: "claude-opus-4-7",
|
|
11732
|
+
name: "Claude Opus 4.7",
|
|
11675
11733
|
provider: "anthropic",
|
|
11676
|
-
contextWindow:
|
|
11734
|
+
contextWindow: 1e6,
|
|
11677
11735
|
isVisionCapable: true,
|
|
11678
|
-
inputCostPer1kTokens:
|
|
11679
|
-
outputCostPer1kTokens:
|
|
11680
|
-
maxOutputTokens:
|
|
11736
|
+
inputCostPer1kTokens: 5e-3,
|
|
11737
|
+
outputCostPer1kTokens: 0.025,
|
|
11738
|
+
maxOutputTokens: 128e3,
|
|
11681
11739
|
supportsStreaming: true,
|
|
11682
11740
|
isLocal: false
|
|
11683
11741
|
},
|
|
11684
|
-
"claude-opus-4-
|
|
11685
|
-
id: "claude-opus-4-
|
|
11686
|
-
name: "Claude Opus 4.
|
|
11742
|
+
"claude-opus-4-6": {
|
|
11743
|
+
id: "claude-opus-4-6",
|
|
11744
|
+
name: "Claude Opus 4.6",
|
|
11745
|
+
provider: "anthropic",
|
|
11746
|
+
contextWindow: 1e6,
|
|
11747
|
+
isVisionCapable: true,
|
|
11748
|
+
inputCostPer1kTokens: 5e-3,
|
|
11749
|
+
outputCostPer1kTokens: 0.025,
|
|
11750
|
+
maxOutputTokens: 128e3,
|
|
11751
|
+
supportsStreaming: true,
|
|
11752
|
+
isLocal: false
|
|
11753
|
+
},
|
|
11754
|
+
"claude-opus-4-5": {
|
|
11755
|
+
id: "claude-opus-4-5-20251101",
|
|
11756
|
+
name: "Claude Opus 4.5",
|
|
11687
11757
|
provider: "anthropic",
|
|
11688
11758
|
contextWindow: 2e5,
|
|
11689
11759
|
isVisionCapable: true,
|
|
11690
|
-
inputCostPer1kTokens:
|
|
11691
|
-
outputCostPer1kTokens: 0.
|
|
11692
|
-
maxOutputTokens:
|
|
11760
|
+
inputCostPer1kTokens: 5e-3,
|
|
11761
|
+
outputCostPer1kTokens: 0.025,
|
|
11762
|
+
maxOutputTokens: 64e3,
|
|
11763
|
+
supportsStreaming: true,
|
|
11764
|
+
isLocal: false
|
|
11765
|
+
},
|
|
11766
|
+
"claude-sonnet-5": {
|
|
11767
|
+
id: "claude-sonnet-5",
|
|
11768
|
+
name: "Claude Sonnet 5",
|
|
11769
|
+
provider: "anthropic",
|
|
11770
|
+
contextWindow: 1e6,
|
|
11771
|
+
isVisionCapable: true,
|
|
11772
|
+
inputCostPer1kTokens: 2e-3,
|
|
11773
|
+
outputCostPer1kTokens: 0.01,
|
|
11774
|
+
maxOutputTokens: 128e3,
|
|
11693
11775
|
supportsStreaming: true,
|
|
11694
11776
|
isLocal: false
|
|
11695
11777
|
},
|
|
@@ -11697,76 +11779,135 @@ var MODELS = {
|
|
|
11697
11779
|
id: "claude-sonnet-4-6",
|
|
11698
11780
|
name: "Claude Sonnet 4.6",
|
|
11699
11781
|
provider: "anthropic",
|
|
11782
|
+
contextWindow: 1e6,
|
|
11783
|
+
isVisionCapable: true,
|
|
11784
|
+
inputCostPer1kTokens: 3e-3,
|
|
11785
|
+
outputCostPer1kTokens: 0.015,
|
|
11786
|
+
maxOutputTokens: 64e3,
|
|
11787
|
+
supportsStreaming: true,
|
|
11788
|
+
isLocal: false
|
|
11789
|
+
},
|
|
11790
|
+
"claude-sonnet-4-5": {
|
|
11791
|
+
id: "claude-sonnet-4-5-20250929",
|
|
11792
|
+
name: "Claude Sonnet 4.5",
|
|
11793
|
+
provider: "anthropic",
|
|
11700
11794
|
contextWindow: 2e5,
|
|
11701
11795
|
isVisionCapable: true,
|
|
11702
11796
|
inputCostPer1kTokens: 3e-3,
|
|
11703
11797
|
outputCostPer1kTokens: 0.015,
|
|
11704
|
-
maxOutputTokens:
|
|
11798
|
+
maxOutputTokens: 64e3,
|
|
11705
11799
|
supportsStreaming: true,
|
|
11706
11800
|
isLocal: false
|
|
11707
11801
|
},
|
|
11708
|
-
|
|
11709
|
-
|
|
11710
|
-
|
|
11711
|
-
|
|
11802
|
+
"claude-haiku-4-5": {
|
|
11803
|
+
id: "claude-haiku-4-5-20251001",
|
|
11804
|
+
name: "Claude Haiku 4.5",
|
|
11805
|
+
provider: "anthropic",
|
|
11806
|
+
contextWindow: 2e5,
|
|
11807
|
+
isVisionCapable: true,
|
|
11808
|
+
inputCostPer1kTokens: 1e-3,
|
|
11809
|
+
outputCostPer1kTokens: 5e-3,
|
|
11810
|
+
maxOutputTokens: 64e3,
|
|
11811
|
+
supportsStreaming: true,
|
|
11812
|
+
isLocal: false
|
|
11813
|
+
},
|
|
11814
|
+
// OpenAI — active chat-capable models used by Cascade's Chat Completions path.
|
|
11815
|
+
"gpt-5.6-sol": {
|
|
11816
|
+
id: "gpt-5.6-sol",
|
|
11817
|
+
name: "GPT-5.6 Sol",
|
|
11712
11818
|
provider: "openai",
|
|
11713
|
-
contextWindow:
|
|
11819
|
+
contextWindow: 105e4,
|
|
11820
|
+
isVisionCapable: true,
|
|
11821
|
+
inputCostPer1kTokens: 4e-3,
|
|
11822
|
+
outputCostPer1kTokens: 0.02,
|
|
11823
|
+
maxOutputTokens: 128e3,
|
|
11824
|
+
supportsStreaming: true,
|
|
11825
|
+
isLocal: false
|
|
11826
|
+
},
|
|
11827
|
+
"gpt-5.6-terra": {
|
|
11828
|
+
id: "gpt-5.6-terra",
|
|
11829
|
+
name: "GPT-5.6 Terra",
|
|
11830
|
+
provider: "openai",
|
|
11831
|
+
contextWindow: 105e4,
|
|
11832
|
+
isVisionCapable: true,
|
|
11833
|
+
inputCostPer1kTokens: 2e-3,
|
|
11834
|
+
outputCostPer1kTokens: 0.012,
|
|
11835
|
+
maxOutputTokens: 128e3,
|
|
11836
|
+
supportsStreaming: true,
|
|
11837
|
+
isLocal: false
|
|
11838
|
+
},
|
|
11839
|
+
"gpt-5.6-luna": {
|
|
11840
|
+
id: "gpt-5.6-luna",
|
|
11841
|
+
name: "GPT-5.6 Luna",
|
|
11842
|
+
provider: "openai",
|
|
11843
|
+
contextWindow: 105e4,
|
|
11844
|
+
isVisionCapable: true,
|
|
11845
|
+
inputCostPer1kTokens: 2e-4,
|
|
11846
|
+
outputCostPer1kTokens: 12e-4,
|
|
11847
|
+
maxOutputTokens: 128e3,
|
|
11848
|
+
supportsStreaming: true,
|
|
11849
|
+
isLocal: false
|
|
11850
|
+
},
|
|
11851
|
+
"gpt-5.5": {
|
|
11852
|
+
id: "gpt-5.5",
|
|
11853
|
+
name: "GPT-5.5",
|
|
11854
|
+
provider: "openai",
|
|
11855
|
+
contextWindow: 105e4,
|
|
11714
11856
|
isVisionCapable: true,
|
|
11715
11857
|
inputCostPer1kTokens: 5e-3,
|
|
11716
|
-
outputCostPer1kTokens: 0.
|
|
11717
|
-
maxOutputTokens:
|
|
11858
|
+
outputCostPer1kTokens: 0.03,
|
|
11859
|
+
maxOutputTokens: 128e3,
|
|
11718
11860
|
supportsStreaming: true,
|
|
11719
11861
|
isLocal: false
|
|
11720
11862
|
},
|
|
11721
|
-
"gpt-
|
|
11722
|
-
id: "gpt-
|
|
11723
|
-
name: "GPT-
|
|
11863
|
+
"gpt-5.4": {
|
|
11864
|
+
id: "gpt-5.4",
|
|
11865
|
+
name: "GPT-5.4",
|
|
11724
11866
|
provider: "openai",
|
|
11725
|
-
contextWindow:
|
|
11867
|
+
contextWindow: 105e4,
|
|
11726
11868
|
isVisionCapable: true,
|
|
11727
|
-
inputCostPer1kTokens:
|
|
11728
|
-
outputCostPer1kTokens:
|
|
11729
|
-
maxOutputTokens:
|
|
11869
|
+
inputCostPer1kTokens: 25e-4,
|
|
11870
|
+
outputCostPer1kTokens: 0.015,
|
|
11871
|
+
maxOutputTokens: 128e3,
|
|
11730
11872
|
supportsStreaming: true,
|
|
11731
11873
|
isLocal: false
|
|
11732
11874
|
},
|
|
11733
|
-
"gpt-4
|
|
11734
|
-
id: "gpt-4
|
|
11735
|
-
name: "GPT-4
|
|
11875
|
+
"gpt-5.4-mini": {
|
|
11876
|
+
id: "gpt-5.4-mini",
|
|
11877
|
+
name: "GPT-5.4 Mini",
|
|
11736
11878
|
provider: "openai",
|
|
11737
|
-
contextWindow:
|
|
11879
|
+
contextWindow: 4e5,
|
|
11738
11880
|
isVisionCapable: true,
|
|
11739
|
-
inputCostPer1kTokens:
|
|
11740
|
-
outputCostPer1kTokens:
|
|
11741
|
-
maxOutputTokens:
|
|
11881
|
+
inputCostPer1kTokens: 75e-5,
|
|
11882
|
+
outputCostPer1kTokens: 45e-4,
|
|
11883
|
+
maxOutputTokens: 128e3,
|
|
11742
11884
|
supportsStreaming: true,
|
|
11743
11885
|
isLocal: false
|
|
11744
11886
|
},
|
|
11745
|
-
"gpt-4
|
|
11746
|
-
id: "gpt-4
|
|
11747
|
-
name: "GPT-4
|
|
11887
|
+
"gpt-5.4-nano": {
|
|
11888
|
+
id: "gpt-5.4-nano",
|
|
11889
|
+
name: "GPT-5.4 Nano",
|
|
11748
11890
|
provider: "openai",
|
|
11749
|
-
contextWindow:
|
|
11891
|
+
contextWindow: 4e5,
|
|
11750
11892
|
isVisionCapable: true,
|
|
11751
|
-
inputCostPer1kTokens:
|
|
11752
|
-
outputCostPer1kTokens:
|
|
11753
|
-
maxOutputTokens:
|
|
11893
|
+
inputCostPer1kTokens: 2e-4,
|
|
11894
|
+
outputCostPer1kTokens: 125e-5,
|
|
11895
|
+
maxOutputTokens: 128e3,
|
|
11754
11896
|
supportsStreaming: true,
|
|
11755
11897
|
isLocal: false
|
|
11756
11898
|
},
|
|
11757
|
-
"gpt-
|
|
11758
|
-
id: "gpt-
|
|
11759
|
-
name: "GPT-
|
|
11899
|
+
"gpt-5.2": {
|
|
11900
|
+
id: "gpt-5.2",
|
|
11901
|
+
name: "GPT-5.2",
|
|
11760
11902
|
provider: "openai",
|
|
11761
|
-
contextWindow:
|
|
11903
|
+
contextWindow: 4e5,
|
|
11762
11904
|
isVisionCapable: true,
|
|
11763
|
-
inputCostPer1kTokens:
|
|
11764
|
-
outputCostPer1kTokens:
|
|
11765
|
-
maxOutputTokens:
|
|
11905
|
+
inputCostPer1kTokens: 175e-5,
|
|
11906
|
+
outputCostPer1kTokens: 0.014,
|
|
11907
|
+
maxOutputTokens: 128e3,
|
|
11766
11908
|
supportsStreaming: true,
|
|
11767
11909
|
isLocal: false
|
|
11768
11910
|
},
|
|
11769
|
-
// GPT-5 family (offline baseline pricing; the live fetch keeps it current).
|
|
11770
11911
|
"gpt-5": {
|
|
11771
11912
|
id: "gpt-5",
|
|
11772
11913
|
name: "GPT-5",
|
|
@@ -11803,79 +11944,149 @@ var MODELS = {
|
|
|
11803
11944
|
supportsStreaming: true,
|
|
11804
11945
|
isLocal: false
|
|
11805
11946
|
},
|
|
11806
|
-
|
|
11807
|
-
|
|
11808
|
-
|
|
11809
|
-
"gpt-5.5": {
|
|
11810
|
-
id: "gpt-5.5",
|
|
11811
|
-
name: "GPT-5.5",
|
|
11947
|
+
"gpt-4.1": {
|
|
11948
|
+
id: "gpt-4.1",
|
|
11949
|
+
name: "GPT-4.1",
|
|
11812
11950
|
provider: "openai",
|
|
11813
|
-
contextWindow:
|
|
11951
|
+
contextWindow: 1047576,
|
|
11814
11952
|
isVisionCapable: true,
|
|
11815
|
-
inputCostPer1kTokens:
|
|
11816
|
-
outputCostPer1kTokens:
|
|
11817
|
-
maxOutputTokens:
|
|
11953
|
+
inputCostPer1kTokens: 2e-3,
|
|
11954
|
+
outputCostPer1kTokens: 8e-3,
|
|
11955
|
+
maxOutputTokens: 32768,
|
|
11818
11956
|
supportsStreaming: true,
|
|
11819
11957
|
isLocal: false
|
|
11820
11958
|
},
|
|
11821
|
-
"gpt-
|
|
11822
|
-
id: "gpt-
|
|
11823
|
-
name: "GPT-
|
|
11959
|
+
"gpt-4.1-mini": {
|
|
11960
|
+
id: "gpt-4.1-mini",
|
|
11961
|
+
name: "GPT-4.1 Mini",
|
|
11824
11962
|
provider: "openai",
|
|
11825
|
-
contextWindow:
|
|
11963
|
+
contextWindow: 1047576,
|
|
11826
11964
|
isVisionCapable: true,
|
|
11827
|
-
inputCostPer1kTokens:
|
|
11965
|
+
inputCostPer1kTokens: 4e-4,
|
|
11966
|
+
outputCostPer1kTokens: 16e-4,
|
|
11967
|
+
maxOutputTokens: 32768,
|
|
11968
|
+
supportsStreaming: true,
|
|
11969
|
+
isLocal: false
|
|
11970
|
+
},
|
|
11971
|
+
"gpt-4.1-nano": {
|
|
11972
|
+
id: "gpt-4.1-nano",
|
|
11973
|
+
name: "GPT-4.1 Nano",
|
|
11974
|
+
provider: "openai",
|
|
11975
|
+
contextWindow: 1047576,
|
|
11976
|
+
isVisionCapable: true,
|
|
11977
|
+
inputCostPer1kTokens: 1e-4,
|
|
11978
|
+
outputCostPer1kTokens: 4e-4,
|
|
11979
|
+
maxOutputTokens: 32768,
|
|
11980
|
+
supportsStreaming: true,
|
|
11981
|
+
isLocal: false
|
|
11982
|
+
},
|
|
11983
|
+
"gpt-4o": {
|
|
11984
|
+
id: "gpt-4o",
|
|
11985
|
+
name: "GPT-4o",
|
|
11986
|
+
provider: "openai",
|
|
11987
|
+
contextWindow: 128e3,
|
|
11988
|
+
isVisionCapable: true,
|
|
11989
|
+
inputCostPer1kTokens: 25e-4,
|
|
11828
11990
|
outputCostPer1kTokens: 0.01,
|
|
11829
|
-
maxOutputTokens:
|
|
11991
|
+
maxOutputTokens: 16e3,
|
|
11830
11992
|
supportsStreaming: true,
|
|
11831
11993
|
isLocal: false
|
|
11832
11994
|
},
|
|
11833
|
-
"gpt-
|
|
11834
|
-
id: "gpt-
|
|
11835
|
-
name: "GPT-
|
|
11995
|
+
"gpt-4o-mini": {
|
|
11996
|
+
id: "gpt-4o-mini",
|
|
11997
|
+
name: "GPT-4o Mini",
|
|
11836
11998
|
provider: "openai",
|
|
11837
|
-
contextWindow:
|
|
11999
|
+
contextWindow: 128e3,
|
|
11838
12000
|
isVisionCapable: true,
|
|
11839
|
-
inputCostPer1kTokens:
|
|
11840
|
-
outputCostPer1kTokens:
|
|
11841
|
-
maxOutputTokens:
|
|
12001
|
+
inputCostPer1kTokens: 15e-5,
|
|
12002
|
+
outputCostPer1kTokens: 6e-4,
|
|
12003
|
+
maxOutputTokens: 16e3,
|
|
11842
12004
|
supportsStreaming: true,
|
|
11843
12005
|
isLocal: false
|
|
11844
12006
|
},
|
|
11845
|
-
// Google
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
12007
|
+
// Google Gemini — active GA + preview chat models. Gemini 2.0/1.5 are no
|
|
12008
|
+
// longer advertised because the Gemini API shut those generations down.
|
|
12009
|
+
"gemini-3.7-flash": {
|
|
12010
|
+
id: "gemini-3.7-flash",
|
|
12011
|
+
name: "Gemini 3.7 Flash",
|
|
11849
12012
|
provider: "gemini",
|
|
11850
|
-
contextWindow:
|
|
12013
|
+
contextWindow: 1048576,
|
|
11851
12014
|
isVisionCapable: true,
|
|
11852
|
-
inputCostPer1kTokens:
|
|
11853
|
-
outputCostPer1kTokens:
|
|
11854
|
-
maxOutputTokens:
|
|
12015
|
+
inputCostPer1kTokens: 75e-5,
|
|
12016
|
+
outputCostPer1kTokens: 375e-5,
|
|
12017
|
+
maxOutputTokens: 65536,
|
|
11855
12018
|
supportsStreaming: true,
|
|
11856
12019
|
isLocal: false
|
|
11857
12020
|
},
|
|
11858
|
-
"gemini-
|
|
11859
|
-
id: "gemini-
|
|
11860
|
-
name: "Gemini
|
|
12021
|
+
"gemini-3.6-flash": {
|
|
12022
|
+
id: "gemini-3.6-flash",
|
|
12023
|
+
name: "Gemini 3.6 Flash",
|
|
11861
12024
|
provider: "gemini",
|
|
11862
|
-
contextWindow:
|
|
12025
|
+
contextWindow: 1048576,
|
|
11863
12026
|
isVisionCapable: true,
|
|
11864
|
-
inputCostPer1kTokens:
|
|
11865
|
-
outputCostPer1kTokens:
|
|
11866
|
-
maxOutputTokens:
|
|
12027
|
+
inputCostPer1kTokens: 75e-5,
|
|
12028
|
+
outputCostPer1kTokens: 375e-5,
|
|
12029
|
+
maxOutputTokens: 65536,
|
|
11867
12030
|
supportsStreaming: true,
|
|
11868
12031
|
isLocal: false
|
|
11869
12032
|
},
|
|
11870
|
-
"gemini-
|
|
11871
|
-
id: "gemini-
|
|
11872
|
-
name: "Gemini
|
|
12033
|
+
"gemini-3.5-flash": {
|
|
12034
|
+
id: "gemini-3.5-flash",
|
|
12035
|
+
name: "Gemini 3.5 Flash",
|
|
11873
12036
|
provider: "gemini",
|
|
11874
|
-
contextWindow:
|
|
12037
|
+
contextWindow: 1048576,
|
|
11875
12038
|
isVisionCapable: true,
|
|
11876
|
-
inputCostPer1kTokens:
|
|
11877
|
-
outputCostPer1kTokens:
|
|
11878
|
-
maxOutputTokens:
|
|
12039
|
+
inputCostPer1kTokens: 15e-4,
|
|
12040
|
+
outputCostPer1kTokens: 9e-3,
|
|
12041
|
+
maxOutputTokens: 65536,
|
|
12042
|
+
supportsStreaming: true,
|
|
12043
|
+
isLocal: false
|
|
12044
|
+
},
|
|
12045
|
+
"gemini-3.5-flash-lite": {
|
|
12046
|
+
id: "gemini-3.5-flash-lite",
|
|
12047
|
+
name: "Gemini 3.5 Flash-Lite",
|
|
12048
|
+
provider: "gemini",
|
|
12049
|
+
contextWindow: 1048576,
|
|
12050
|
+
isVisionCapable: true,
|
|
12051
|
+
inputCostPer1kTokens: 3e-4,
|
|
12052
|
+
outputCostPer1kTokens: 25e-4,
|
|
12053
|
+
maxOutputTokens: 65536,
|
|
12054
|
+
supportsStreaming: true,
|
|
12055
|
+
isLocal: false
|
|
12056
|
+
},
|
|
12057
|
+
"gemini-3.1-flash-lite": {
|
|
12058
|
+
id: "gemini-3.1-flash-lite",
|
|
12059
|
+
name: "Gemini 3.1 Flash-Lite",
|
|
12060
|
+
provider: "gemini",
|
|
12061
|
+
contextWindow: 1048576,
|
|
12062
|
+
isVisionCapable: true,
|
|
12063
|
+
inputCostPer1kTokens: 25e-5,
|
|
12064
|
+
outputCostPer1kTokens: 15e-4,
|
|
12065
|
+
maxOutputTokens: 65536,
|
|
12066
|
+
supportsStreaming: true,
|
|
12067
|
+
isLocal: false
|
|
12068
|
+
},
|
|
12069
|
+
"gemini-3.1-pro-preview": {
|
|
12070
|
+
id: "gemini-3.1-pro-preview",
|
|
12071
|
+
name: "Gemini 3.1 Pro Preview",
|
|
12072
|
+
provider: "gemini",
|
|
12073
|
+
contextWindow: 1048576,
|
|
12074
|
+
isVisionCapable: true,
|
|
12075
|
+
inputCostPer1kTokens: 2e-3,
|
|
12076
|
+
outputCostPer1kTokens: 0.012,
|
|
12077
|
+
maxOutputTokens: 65536,
|
|
12078
|
+
supportsStreaming: true,
|
|
12079
|
+
isLocal: false
|
|
12080
|
+
},
|
|
12081
|
+
"gemini-3-flash-preview": {
|
|
12082
|
+
id: "gemini-3-flash-preview",
|
|
12083
|
+
name: "Gemini 3 Flash Preview",
|
|
12084
|
+
provider: "gemini",
|
|
12085
|
+
contextWindow: 1048576,
|
|
12086
|
+
isVisionCapable: true,
|
|
12087
|
+
inputCostPer1kTokens: 5e-4,
|
|
12088
|
+
outputCostPer1kTokens: 3e-3,
|
|
12089
|
+
maxOutputTokens: 65536,
|
|
11879
12090
|
supportsStreaming: true,
|
|
11880
12091
|
isLocal: false
|
|
11881
12092
|
},
|
|
@@ -11883,7 +12094,7 @@ var MODELS = {
|
|
|
11883
12094
|
id: "gemini-2.5-pro",
|
|
11884
12095
|
name: "Gemini 2.5 Pro",
|
|
11885
12096
|
provider: "gemini",
|
|
11886
|
-
contextWindow:
|
|
12097
|
+
contextWindow: 1048576,
|
|
11887
12098
|
isVisionCapable: true,
|
|
11888
12099
|
inputCostPer1kTokens: 125e-5,
|
|
11889
12100
|
outputCostPer1kTokens: 0.01,
|
|
@@ -11895,10 +12106,22 @@ var MODELS = {
|
|
|
11895
12106
|
id: "gemini-2.5-flash",
|
|
11896
12107
|
name: "Gemini 2.5 Flash",
|
|
11897
12108
|
provider: "gemini",
|
|
11898
|
-
contextWindow:
|
|
12109
|
+
contextWindow: 1048576,
|
|
11899
12110
|
isVisionCapable: true,
|
|
11900
|
-
inputCostPer1kTokens:
|
|
11901
|
-
outputCostPer1kTokens:
|
|
12111
|
+
inputCostPer1kTokens: 3e-4,
|
|
12112
|
+
outputCostPer1kTokens: 25e-4,
|
|
12113
|
+
maxOutputTokens: 65536,
|
|
12114
|
+
supportsStreaming: true,
|
|
12115
|
+
isLocal: false
|
|
12116
|
+
},
|
|
12117
|
+
"gemini-2.5-flash-lite": {
|
|
12118
|
+
id: "gemini-2.5-flash-lite",
|
|
12119
|
+
name: "Gemini 2.5 Flash-Lite",
|
|
12120
|
+
provider: "gemini",
|
|
12121
|
+
contextWindow: 1048576,
|
|
12122
|
+
isVisionCapable: true,
|
|
12123
|
+
inputCostPer1kTokens: 1e-4,
|
|
12124
|
+
outputCostPer1kTokens: 4e-4,
|
|
11902
12125
|
maxOutputTokens: 65536,
|
|
11903
12126
|
supportsStreaming: true,
|
|
11904
12127
|
isLocal: false
|
|
@@ -11968,43 +12191,57 @@ for (const _m of Object.values(MODELS)) {
|
|
|
11968
12191
|
_m.pricingUnknown = false;
|
|
11969
12192
|
}
|
|
11970
12193
|
var T1_MODEL_PRIORITY = [
|
|
12194
|
+
"gpt-5.6-sol",
|
|
12195
|
+
"claude-fable-5",
|
|
12196
|
+
"claude-opus-5",
|
|
11971
12197
|
"gpt-5.5",
|
|
11972
12198
|
"gpt-5.4",
|
|
12199
|
+
"gemini-3.1-pro-preview",
|
|
12200
|
+
"claude-opus-4-8",
|
|
12201
|
+
"claude-sonnet-5",
|
|
12202
|
+
"gemini-3.7-flash",
|
|
12203
|
+
"gpt-5.2",
|
|
11973
12204
|
"gpt-5",
|
|
11974
|
-
"claude-opus-4",
|
|
11975
|
-
"claude-sonnet-4",
|
|
11976
12205
|
"gemini-2.5-pro",
|
|
11977
12206
|
"gpt-4.1",
|
|
11978
|
-
"gpt-4o"
|
|
11979
|
-
"gemini-1.5-pro"
|
|
12207
|
+
"gpt-4o"
|
|
11980
12208
|
];
|
|
11981
12209
|
var T2_MODEL_PRIORITY = [
|
|
12210
|
+
"gpt-5.6-terra",
|
|
12211
|
+
"claude-sonnet-5",
|
|
12212
|
+
"gemini-3.7-flash",
|
|
12213
|
+
"gemini-3.6-flash",
|
|
11982
12214
|
"gpt-5.4-mini",
|
|
11983
12215
|
"gpt-5-mini",
|
|
11984
|
-
"claude-sonnet-4",
|
|
12216
|
+
"claude-sonnet-4-6",
|
|
11985
12217
|
"claude-haiku-4-5",
|
|
11986
|
-
"
|
|
12218
|
+
"gemini-3.5-flash",
|
|
11987
12219
|
"gemini-2.5-flash",
|
|
11988
12220
|
"gpt-4.1-mini",
|
|
11989
12221
|
"gpt-4o-mini",
|
|
11990
|
-
"gemini-2.0-flash",
|
|
11991
12222
|
"llama3:70b"
|
|
11992
12223
|
];
|
|
11993
12224
|
var T3_MODEL_PRIORITY = [
|
|
12225
|
+
"gpt-5.6-luna",
|
|
12226
|
+
"gpt-5.4-nano",
|
|
12227
|
+
"gemini-3.5-flash-lite",
|
|
12228
|
+
"gemini-3.1-flash-lite",
|
|
12229
|
+
"claude-haiku-4-5",
|
|
11994
12230
|
"gpt-5-nano",
|
|
12231
|
+
"gemini-2.5-flash-lite",
|
|
11995
12232
|
"llama3.2:3b",
|
|
11996
12233
|
"mistral:7b",
|
|
11997
|
-
"claude-haiku-4-5",
|
|
11998
|
-
"claude-haiku-3-5",
|
|
11999
12234
|
"gpt-4.1-nano",
|
|
12000
12235
|
"gpt-4o-mini",
|
|
12001
|
-
"gemini-2.5-flash"
|
|
12002
|
-
"gemini-2.0-flash"
|
|
12236
|
+
"gemini-2.5-flash"
|
|
12003
12237
|
];
|
|
12004
12238
|
var VISION_MODEL_PRIORITY = [
|
|
12005
|
-
"
|
|
12239
|
+
"gpt-5.6-sol",
|
|
12240
|
+
"claude-fable-5",
|
|
12241
|
+
"claude-sonnet-5",
|
|
12242
|
+
"gemini-3.7-flash",
|
|
12006
12243
|
"gpt-4o",
|
|
12007
|
-
"gemini-2.
|
|
12244
|
+
"gemini-2.5-flash",
|
|
12008
12245
|
"llava"
|
|
12009
12246
|
];
|
|
12010
12247
|
var COMPLEXITY_T2_COUNT = {
|
|
@@ -12185,7 +12422,7 @@ function isChatModel(id, methods) {
|
|
|
12185
12422
|
return !NON_CHAT.test(id);
|
|
12186
12423
|
}
|
|
12187
12424
|
try {
|
|
12188
|
-
|
|
12425
|
+
dnsCallback__default.default.setDefaultResultOrder("ipv4first");
|
|
12189
12426
|
} catch {
|
|
12190
12427
|
}
|
|
12191
12428
|
function preferIpv4Host(url) {
|
|
@@ -12201,8 +12438,8 @@ function normalizeEndpoint(url) {
|
|
|
12201
12438
|
if (!raw) return "";
|
|
12202
12439
|
try {
|
|
12203
12440
|
const u = new URL(raw);
|
|
12204
|
-
const
|
|
12205
|
-
return `${u.protocol}//${u.host.toLowerCase()}${
|
|
12441
|
+
const path30 = stripTrailingSlashes(`${u.pathname}${u.search}`);
|
|
12442
|
+
return `${u.protocol}//${u.host.toLowerCase()}${path30}`;
|
|
12206
12443
|
} catch {
|
|
12207
12444
|
return raw.toLowerCase();
|
|
12208
12445
|
}
|
|
@@ -12869,52 +13106,127 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
12869
13106
|
}
|
|
12870
13107
|
};
|
|
12871
13108
|
|
|
13109
|
+
// src/providers/cloud-model-catalog.json
|
|
13110
|
+
var cloud_model_catalog_default = {
|
|
13111
|
+
models: [
|
|
13112
|
+
{ id: "gpt-5.6-sol", name: "GPT-5.6 Sol", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13113
|
+
{ id: "gpt-5.6-terra", name: "GPT-5.6 Terra", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13114
|
+
{ id: "gpt-5.6-luna", name: "GPT-5.6 Luna", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13115
|
+
{ id: "gpt-5.5", name: "GPT-5.5", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13116
|
+
{ id: "gpt-5.4", name: "GPT-5.4", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13117
|
+
{ id: "gpt-5.4-mini", name: "GPT-5.4 Mini", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13118
|
+
{ id: "gpt-5.4-nano", name: "GPT-5.4 Nano", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13119
|
+
{ id: "gpt-5", name: "GPT-5", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13120
|
+
{ id: "gpt-5-mini", name: "GPT-5 Mini", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13121
|
+
{ id: "gpt-5-nano", name: "GPT-5 Nano", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13122
|
+
{ id: "gpt-4.1", name: "GPT-4.1", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 1047576, maxOutputTokens: 32768, vision: true, toolUse: true },
|
|
13123
|
+
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 1047576, maxOutputTokens: 32768, vision: true, toolUse: true },
|
|
13124
|
+
{ id: "gpt-4.1-nano", name: "GPT-4.1 Nano", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 1047576, maxOutputTokens: 32768, vision: true, toolUse: true },
|
|
13125
|
+
{ id: "gpt-4o", name: "GPT-4o", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 128e3, maxOutputTokens: 16384, vision: true, toolUse: true },
|
|
13126
|
+
{ id: "gpt-4o-mini", name: "GPT-4o Mini", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 128e3, maxOutputTokens: 16384, vision: true, toolUse: true },
|
|
13127
|
+
{ id: "claude-fable-5", name: "Claude Fable 5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13128
|
+
{ id: "claude-opus-5", name: "Claude Opus 5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13129
|
+
{ id: "claude-opus-4-8", name: "Claude Opus 4.8", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13130
|
+
{ id: "claude-opus-4-7", name: "Claude Opus 4.7", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13131
|
+
{ id: "claude-opus-4-6", name: "Claude Opus 4.6", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, vision: true, toolUse: true },
|
|
13132
|
+
{ id: "claude-opus-4-5-20251101", name: "Claude Opus 4.5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 2e5, vision: true, toolUse: true },
|
|
13133
|
+
{ id: "claude-sonnet-5", name: "Claude Sonnet 5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13134
|
+
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
13135
|
+
{ id: "claude-sonnet-4-5-20250929", name: "Claude Sonnet 4.5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 2e5, vision: true, toolUse: true },
|
|
13136
|
+
{ id: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 2e5, maxOutputTokens: 64e3, vision: true, toolUse: true },
|
|
13137
|
+
{ id: "gemini-3.7-flash", name: "Gemini 3.7 Flash", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13138
|
+
{ id: "gemini-3.6-flash", name: "Gemini 3.6 Flash", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13139
|
+
{ id: "gemini-3.5-flash", name: "Gemini 3.5 Flash", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13140
|
+
{ id: "gemini-3.5-flash-lite", name: "Gemini 3.5 Flash-Lite", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13141
|
+
{ id: "gemini-3.1-flash-lite", name: "Gemini 3.1 Flash-Lite", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13142
|
+
{ id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro", providers: ["gemini"], lifecycle: "preview", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13143
|
+
{ id: "gemini-3-flash-preview", name: "Gemini 3 Flash", providers: ["gemini"], lifecycle: "preview", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13144
|
+
{ id: "gemini-2.5-pro", name: "Gemini 2.5 Pro", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13145
|
+
{ id: "gemini-2.5-flash", name: "Gemini 2.5 Flash", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
13146
|
+
{ id: "gemini-2.5-flash-lite", name: "Gemini 2.5 Flash-Lite", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true }
|
|
13147
|
+
]
|
|
13148
|
+
};
|
|
13149
|
+
|
|
12872
13150
|
// src/providers/azure.ts
|
|
12873
13151
|
var DEFAULT_AZURE_API_VERSION = "2024-12-01-preview";
|
|
12874
|
-
var
|
|
12875
|
-
|
|
12876
|
-
|
|
12877
|
-
|
|
12878
|
-
[/
|
|
12879
|
-
|
|
12880
|
-
|
|
12881
|
-
|
|
12882
|
-
|
|
12883
|
-
|
|
12884
|
-
[/gpt-?4o-mini/, "gpt-4o-mini"],
|
|
12885
|
-
[/gpt-?4o/, "gpt-4o"]
|
|
12886
|
-
];
|
|
12887
|
-
var AZURE_BASE_MODELS = AZURE_BASE_MODEL_RULES.map(([, id]) => id);
|
|
13152
|
+
var CLOUD_MODELS = cloud_model_catalog_default.models;
|
|
13153
|
+
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));
|
|
13154
|
+
var AZURE_BASE_MODELS = AZURE_CATALOG.map((m) => m.id);
|
|
13155
|
+
function compactModelId(id) {
|
|
13156
|
+
return id.toLowerCase().replace(/[^a-z0-9.]/g, "");
|
|
13157
|
+
}
|
|
13158
|
+
function catalogEntry(id) {
|
|
13159
|
+
const n = id.toLowerCase();
|
|
13160
|
+
return CLOUD_MODELS.find((m) => m.id.toLowerCase() === n);
|
|
13161
|
+
}
|
|
12888
13162
|
function inferAzureBaseModel(deploymentName) {
|
|
12889
13163
|
const n = deploymentName.toLowerCase();
|
|
12890
|
-
|
|
13164
|
+
const compact = compactModelId(n);
|
|
13165
|
+
const hasBareGpt56Alias = compact.includes("gpt5.6");
|
|
13166
|
+
for (const model of AZURE_CATALOG) {
|
|
13167
|
+
if (hasBareGpt56Alias && model.id === "gpt-5") continue;
|
|
13168
|
+
if (n.includes(model.id.toLowerCase()) || compact.includes(compactModelId(model.id))) {
|
|
13169
|
+
return model.id;
|
|
13170
|
+
}
|
|
13171
|
+
}
|
|
13172
|
+
if (hasBareGpt56Alias) return "gpt-5.6-sol";
|
|
13173
|
+
const gpt5At = compact.indexOf("gpt5");
|
|
13174
|
+
if (gpt5At !== -1) {
|
|
13175
|
+
const suffix = compact.slice(gpt5At + "gpt5".length);
|
|
13176
|
+
if (suffix.includes("nano")) return "gpt-5-nano";
|
|
13177
|
+
if (suffix.includes("mini")) return "gpt-5-mini";
|
|
13178
|
+
return "gpt-5";
|
|
13179
|
+
}
|
|
13180
|
+
if (compact.includes("gpt4.1nano")) return "gpt-4.1-nano";
|
|
13181
|
+
if (compact.includes("gpt4.1mini")) return "gpt-4.1-mini";
|
|
13182
|
+
if (compact.includes("gpt4.1")) return "gpt-4.1";
|
|
13183
|
+
if (compact.includes("gpt4omini")) return "gpt-4o-mini";
|
|
13184
|
+
if (compact.includes("gpt4o")) return "gpt-4o";
|
|
12891
13185
|
return null;
|
|
12892
13186
|
}
|
|
13187
|
+
function catalogModelInfo(baseModelId) {
|
|
13188
|
+
const entry = catalogEntry(baseModelId);
|
|
13189
|
+
if (!entry?.contextWindow) return void 0;
|
|
13190
|
+
return {
|
|
13191
|
+
id: entry.id,
|
|
13192
|
+
name: entry.name,
|
|
13193
|
+
provider: "openai",
|
|
13194
|
+
contextWindow: entry.contextWindow,
|
|
13195
|
+
isVisionCapable: entry.vision ?? false,
|
|
13196
|
+
inputCostPer1kTokens: 0,
|
|
13197
|
+
outputCostPer1kTokens: 0,
|
|
13198
|
+
maxOutputTokens: entry.maxOutputTokens ?? 16e3,
|
|
13199
|
+
supportsStreaming: true,
|
|
13200
|
+
isLocal: false,
|
|
13201
|
+
supportsToolUse: entry.toolUse ?? true,
|
|
13202
|
+
pricingUnknown: true
|
|
13203
|
+
};
|
|
13204
|
+
}
|
|
12893
13205
|
function azureModelForDeployment(cfg) {
|
|
12894
13206
|
if (cfg.type !== "azure" || !cfg.deploymentName?.trim()) return null;
|
|
12895
13207
|
const id = cfg.deploymentName.trim();
|
|
12896
13208
|
const name = cfg.label?.trim() || id;
|
|
12897
13209
|
const baseModelId = cfg.model?.trim() || inferAzureBaseModel(id) || void 0;
|
|
12898
|
-
const base = baseModelId ? MODELS[baseModelId] : void 0;
|
|
12899
|
-
if (base) {
|
|
13210
|
+
const base = baseModelId ? MODELS[baseModelId] ?? catalogModelInfo(baseModelId) : void 0;
|
|
13211
|
+
if (base && baseModelId) {
|
|
12900
13212
|
const azurePrice = resolvePricing(
|
|
12901
13213
|
{ id, provider: "azure", isLocal: false, baseModelId },
|
|
12902
13214
|
{ region: cfg.region }
|
|
12903
13215
|
);
|
|
13216
|
+
const exactAzurePrice = !azurePrice.unknown && !azurePrice.estimatedFromProvider;
|
|
13217
|
+
const nativeToolsOnThisTransport = /^gpt-5\.6-(?:sol|terra|luna)$/i.test(baseModelId) ? false : base.supportsToolUse ?? true;
|
|
12904
13218
|
return {
|
|
12905
13219
|
...base,
|
|
12906
13220
|
id,
|
|
12907
|
-
// callable deployment name
|
|
12908
13221
|
name,
|
|
12909
13222
|
provider: "azure",
|
|
12910
13223
|
baseModelId,
|
|
12911
|
-
|
|
12912
|
-
|
|
12913
|
-
...azurePrice.unknown ? {} : {
|
|
13224
|
+
supportsToolUse: nativeToolsOnThisTransport,
|
|
13225
|
+
...!azurePrice.unknown ? {
|
|
12914
13226
|
inputCostPer1kTokens: azurePrice.input,
|
|
12915
13227
|
outputCostPer1kTokens: azurePrice.output,
|
|
12916
|
-
pricingUnknown:
|
|
12917
|
-
}
|
|
13228
|
+
pricingUnknown: !exactAzurePrice
|
|
13229
|
+
} : { pricingUnknown: true }
|
|
12918
13230
|
};
|
|
12919
13231
|
}
|
|
12920
13232
|
return {
|
|
@@ -12929,18 +13241,23 @@ function azureModelForDeployment(cfg) {
|
|
|
12929
13241
|
maxOutputTokens: 16e3,
|
|
12930
13242
|
supportsStreaming: true,
|
|
12931
13243
|
isLocal: false,
|
|
12932
|
-
supportsToolUse: true
|
|
13244
|
+
supportsToolUse: true,
|
|
13245
|
+
pricingUnknown: true
|
|
12933
13246
|
};
|
|
12934
13247
|
}
|
|
13248
|
+
function stripTrailingSlashes3(value) {
|
|
13249
|
+
let end = value.length;
|
|
13250
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) end--;
|
|
13251
|
+
return value.slice(0, end);
|
|
13252
|
+
}
|
|
12935
13253
|
var AzureOpenAIProvider = class extends OpenAIProvider {
|
|
12936
13254
|
constructor(config, model) {
|
|
12937
13255
|
const rawUrl = config.baseUrl ?? AZURE_BASE_URL_TEMPLATE.replace("{resource}", "YOUR_RESOURCE");
|
|
12938
|
-
const endpoint = rawUrl
|
|
13256
|
+
const endpoint = stripTrailingSlashes3(rawUrl);
|
|
12939
13257
|
super(
|
|
12940
13258
|
{
|
|
12941
13259
|
...config,
|
|
12942
13260
|
baseUrl: endpoint
|
|
12943
|
-
// Kept for superclass compatibility if it reads it
|
|
12944
13261
|
},
|
|
12945
13262
|
model
|
|
12946
13263
|
);
|
|
@@ -14632,13 +14949,13 @@ var DeadModelStore = class {
|
|
|
14632
14949
|
function fileDeadModelPersistence(filePath) {
|
|
14633
14950
|
return {
|
|
14634
14951
|
load() {
|
|
14635
|
-
if (!
|
|
14636
|
-
const raw = JSON.parse(
|
|
14952
|
+
if (!fs27.existsSync(filePath)) return [];
|
|
14953
|
+
const raw = JSON.parse(fs27.readFileSync(filePath, "utf-8"));
|
|
14637
14954
|
return Array.isArray(raw) ? raw : [];
|
|
14638
14955
|
},
|
|
14639
14956
|
save(records) {
|
|
14640
|
-
|
|
14641
|
-
|
|
14957
|
+
fs27.mkdirSync(path28.dirname(filePath), { recursive: true });
|
|
14958
|
+
fs27.writeFileSync(filePath, JSON.stringify(records, null, 2));
|
|
14642
14959
|
}
|
|
14643
14960
|
};
|
|
14644
14961
|
}
|
|
@@ -14683,7 +15000,7 @@ var Keystore = class {
|
|
|
14683
15000
|
const creds = await this.keytar.findCredentials(KEYTAR_SERVICE);
|
|
14684
15001
|
this.cache = Object.fromEntries(creds.map((c) => [c.account, c.password]));
|
|
14685
15002
|
this.backend = "keytar";
|
|
14686
|
-
if (password &&
|
|
15003
|
+
if (password && fs27__default.default.existsSync(this.storePath)) {
|
|
14687
15004
|
try {
|
|
14688
15005
|
const fileEntries = this.decryptFile(password);
|
|
14689
15006
|
for (const [k, v] of Object.entries(fileEntries)) {
|
|
@@ -14702,7 +15019,7 @@ var Keystore = class {
|
|
|
14702
15019
|
"Keystore unlock requires a password because the OS keychain (keytar) is not available on this system."
|
|
14703
15020
|
);
|
|
14704
15021
|
}
|
|
14705
|
-
if (!
|
|
15022
|
+
if (!fs27__default.default.existsSync(this.storePath)) {
|
|
14706
15023
|
const salt = crypto__default.default.randomBytes(SALT_LEN);
|
|
14707
15024
|
this.masterKey = this.deriveKey(password, salt);
|
|
14708
15025
|
this.writeWithSalt({}, salt);
|
|
@@ -14716,7 +15033,7 @@ var Keystore = class {
|
|
|
14716
15033
|
}
|
|
14717
15034
|
/** Synchronous legacy unlock kept for AES-only environments. */
|
|
14718
15035
|
unlockSync(password) {
|
|
14719
|
-
if (!
|
|
15036
|
+
if (!fs27__default.default.existsSync(this.storePath)) {
|
|
14720
15037
|
const salt = crypto__default.default.randomBytes(SALT_LEN);
|
|
14721
15038
|
this.masterKey = this.deriveKey(password, salt);
|
|
14722
15039
|
this.writeWithSalt({}, salt);
|
|
@@ -14774,7 +15091,7 @@ var Keystore = class {
|
|
|
14774
15091
|
}
|
|
14775
15092
|
}
|
|
14776
15093
|
decryptFile(password, knownSalt) {
|
|
14777
|
-
if (!
|
|
15094
|
+
if (!fs27__default.default.existsSync(this.storePath)) return {};
|
|
14778
15095
|
try {
|
|
14779
15096
|
const { salt, ciphertext, iv, tag } = this.readRaw();
|
|
14780
15097
|
const useSalt = knownSalt ?? salt;
|
|
@@ -14796,8 +15113,8 @@ var Keystore = class {
|
|
|
14796
15113
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
14797
15114
|
const tag = cipher.getAuthTag();
|
|
14798
15115
|
const out = Buffer.concat([raw.salt, iv, tag, ciphertext]);
|
|
14799
|
-
|
|
14800
|
-
|
|
15116
|
+
fs27__default.default.mkdirSync(path28__default.default.dirname(this.storePath), { recursive: true });
|
|
15117
|
+
fs27__default.default.writeFileSync(this.storePath, out, { mode: 384 });
|
|
14801
15118
|
}
|
|
14802
15119
|
writeWithSalt(data, salt) {
|
|
14803
15120
|
if (!this.masterKey) throw new Error("writeWithSalt called before masterKey was set");
|
|
@@ -14807,11 +15124,11 @@ var Keystore = class {
|
|
|
14807
15124
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
14808
15125
|
const tag = cipher.getAuthTag();
|
|
14809
15126
|
const out = Buffer.concat([salt, iv, tag, ciphertext]);
|
|
14810
|
-
|
|
14811
|
-
|
|
15127
|
+
fs27__default.default.mkdirSync(path28__default.default.dirname(this.storePath), { recursive: true });
|
|
15128
|
+
fs27__default.default.writeFileSync(this.storePath, out, { mode: 384 });
|
|
14812
15129
|
}
|
|
14813
15130
|
readRaw() {
|
|
14814
|
-
const buf =
|
|
15131
|
+
const buf = fs27__default.default.readFileSync(this.storePath);
|
|
14815
15132
|
let offset = 0;
|
|
14816
15133
|
const salt = buf.subarray(offset, offset + SALT_LEN);
|
|
14817
15134
|
offset += SALT_LEN;
|
|
@@ -14844,7 +15161,7 @@ var CascadeIgnore = class {
|
|
|
14844
15161
|
]);
|
|
14845
15162
|
}
|
|
14846
15163
|
async load(workspacePath) {
|
|
14847
|
-
const filePath =
|
|
15164
|
+
const filePath = path28__default.default.join(workspacePath, ".cascadeignore");
|
|
14848
15165
|
try {
|
|
14849
15166
|
const content = await fs11__default.default.readFile(filePath, "utf-8");
|
|
14850
15167
|
const lines = content.split("\n").filter((l) => l.trim() && !l.startsWith("#"));
|
|
@@ -14855,7 +15172,7 @@ var CascadeIgnore = class {
|
|
|
14855
15172
|
}
|
|
14856
15173
|
isIgnored(filePath, workspacePath) {
|
|
14857
15174
|
try {
|
|
14858
|
-
const relative = workspacePath ?
|
|
15175
|
+
const relative = workspacePath ? path28__default.default.relative(workspacePath, filePath) : filePath;
|
|
14859
15176
|
return this.ig.ignores(relative);
|
|
14860
15177
|
} catch {
|
|
14861
15178
|
return false;
|
|
@@ -14866,7 +15183,7 @@ var CascadeIgnore = class {
|
|
|
14866
15183
|
}
|
|
14867
15184
|
};
|
|
14868
15185
|
async function loadCascadeMd(workspacePath) {
|
|
14869
|
-
const filePath =
|
|
15186
|
+
const filePath = path28__default.default.join(workspacePath, "CASCADE.md");
|
|
14870
15187
|
try {
|
|
14871
15188
|
const raw = await fs11__default.default.readFile(filePath, "utf-8");
|
|
14872
15189
|
return parseCascadeMd(raw);
|
|
@@ -14897,7 +15214,7 @@ ${raw.trim()}`;
|
|
|
14897
15214
|
var MemoryStore = class _MemoryStore {
|
|
14898
15215
|
db;
|
|
14899
15216
|
constructor(dbPath) {
|
|
14900
|
-
|
|
15217
|
+
fs27__default.default.mkdirSync(path28__default.default.dirname(dbPath), { recursive: true });
|
|
14901
15218
|
try {
|
|
14902
15219
|
this.db = new Database2__default.default(dbPath, { timeout: 5e3 });
|
|
14903
15220
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -15795,7 +16112,18 @@ var WebSearchConfigSchema = zod.z.object({
|
|
|
15795
16112
|
/** Tavily API key — get one at https://tavily.com */
|
|
15796
16113
|
tavilyApiKey: zod.z.string().optional(),
|
|
15797
16114
|
/** Max results per search (default 5) */
|
|
15798
|
-
maxResults: zod.z.number().default(5)
|
|
16115
|
+
maxResults: zod.z.number().default(5),
|
|
16116
|
+
/**
|
|
16117
|
+
* Send `searxngUrl` through the SSRF guard. Off for a local run, where the
|
|
16118
|
+
* URL is the machine owner's own config and a self-hosted SearXNG is
|
|
16119
|
+
* routinely on a private address; on for a host that accepts it from a
|
|
16120
|
+
* request. See `src/tools/web-search.ts`.
|
|
16121
|
+
*
|
|
16122
|
+
* It has to be named HERE, not just on the TypeScript interfaces: the config
|
|
16123
|
+
* passes through `CascadeConfigSchema.parse()` on its way into a run, and
|
|
16124
|
+
* zod drops every key this object does not declare.
|
|
16125
|
+
*/
|
|
16126
|
+
guardSearxngUrl: zod.z.boolean().optional()
|
|
15799
16127
|
});
|
|
15800
16128
|
var ToolsConfigSchema = zod.z.object({
|
|
15801
16129
|
shellAllowlist: zod.z.array(zod.z.string()).default([]),
|
|
@@ -16199,7 +16527,7 @@ function credentialEndpointsConflict(type, rowEndpoint, credentialEndpoint) {
|
|
|
16199
16527
|
|
|
16200
16528
|
// src/config/global-credentials.ts
|
|
16201
16529
|
function credentialsPath(globalDir2) {
|
|
16202
|
-
return
|
|
16530
|
+
return path28__default.default.join(globalDir2, GLOBAL_CREDENTIALS_FILE);
|
|
16203
16531
|
}
|
|
16204
16532
|
function providerKey(p) {
|
|
16205
16533
|
return p.type;
|
|
@@ -16229,7 +16557,7 @@ function isPersistable(p) {
|
|
|
16229
16557
|
}
|
|
16230
16558
|
function loadGlobalCredentials(globalDir2) {
|
|
16231
16559
|
try {
|
|
16232
|
-
const raw =
|
|
16560
|
+
const raw = fs27__default.default.readFileSync(credentialsPath(globalDir2), "utf-8");
|
|
16233
16561
|
const parsed = JSON.parse(raw);
|
|
16234
16562
|
if (!Array.isArray(parsed.providers)) return [];
|
|
16235
16563
|
return parsed.providers.filter(
|
|
@@ -16241,13 +16569,13 @@ function loadGlobalCredentials(globalDir2) {
|
|
|
16241
16569
|
}
|
|
16242
16570
|
function saveGlobalCredentials(globalDir2, providers) {
|
|
16243
16571
|
const filePath = credentialsPath(globalDir2);
|
|
16244
|
-
|
|
16572
|
+
fs27__default.default.mkdirSync(globalDir2, { recursive: true, mode: 448 });
|
|
16245
16573
|
const body = { version: 1, providers: providers.filter(isPersistable) };
|
|
16246
16574
|
const tmp = `${filePath}.tmp`;
|
|
16247
|
-
|
|
16248
|
-
|
|
16575
|
+
fs27__default.default.writeFileSync(tmp, JSON.stringify(body, null, 2), { encoding: "utf-8", mode: 384 });
|
|
16576
|
+
fs27__default.default.renameSync(tmp, filePath);
|
|
16249
16577
|
try {
|
|
16250
|
-
|
|
16578
|
+
fs27__default.default.chmodSync(filePath, 384);
|
|
16251
16579
|
} catch {
|
|
16252
16580
|
}
|
|
16253
16581
|
}
|
|
@@ -16648,7 +16976,7 @@ var ConfigManager = class {
|
|
|
16648
16976
|
/** `globalDirOverride` exists for tests — never point it at the real home dir there. */
|
|
16649
16977
|
constructor(workspacePath = process.cwd(), globalDirOverride) {
|
|
16650
16978
|
this.workspacePath = workspacePath;
|
|
16651
|
-
this.globalDir = globalDirOverride ??
|
|
16979
|
+
this.globalDir = globalDirOverride ?? path28__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR);
|
|
16652
16980
|
}
|
|
16653
16981
|
async load() {
|
|
16654
16982
|
this.config = await this.loadConfig();
|
|
@@ -16662,8 +16990,8 @@ var ConfigManager = class {
|
|
|
16662
16990
|
this.ignore = new CascadeIgnore();
|
|
16663
16991
|
await this.ignore.load(this.workspacePath);
|
|
16664
16992
|
this.cascadeMd = await loadCascadeMd(this.workspacePath);
|
|
16665
|
-
this.keystore = new Keystore(
|
|
16666
|
-
this.store = new MemoryStore(
|
|
16993
|
+
this.keystore = new Keystore(path28__default.default.join(this.globalDir, GLOBAL_KEYSTORE_FILE));
|
|
16994
|
+
this.store = new MemoryStore(path28__default.default.join(this.workspacePath, CASCADE_DB_FILE));
|
|
16667
16995
|
const globalRevoked = stripRevokedCredentials(loadGlobalCredentials(this.globalDir));
|
|
16668
16996
|
const globalCreds = filterRetiredCredentials(globalRevoked.kept);
|
|
16669
16997
|
if (globalRevoked.removed > 0) this.revokedCredentials += globalRevoked.removed;
|
|
@@ -16736,8 +17064,8 @@ var ConfigManager = class {
|
|
|
16736
17064
|
* never reached the disk (see `commitSettings`).
|
|
16737
17065
|
*/
|
|
16738
17066
|
async save(config = this.config) {
|
|
16739
|
-
const configPath =
|
|
16740
|
-
await fs11__default.default.mkdir(
|
|
17067
|
+
const configPath = path28__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
17068
|
+
await fs11__default.default.mkdir(path28__default.default.dirname(configPath), { recursive: true });
|
|
16741
17069
|
await fs11__default.default.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
16742
17070
|
try {
|
|
16743
17071
|
saveGlobalCredentials(this.globalDir, config.providers);
|
|
@@ -16787,7 +17115,7 @@ var ConfigManager = class {
|
|
|
16787
17115
|
this.revokedCredentials = 0;
|
|
16788
17116
|
this.revokedPins = [];
|
|
16789
17117
|
this.revokedNotice = void 0;
|
|
16790
|
-
const configPath =
|
|
17118
|
+
const configPath = path28__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
16791
17119
|
try {
|
|
16792
17120
|
const raw = await fs11__default.default.readFile(configPath, "utf-8");
|
|
16793
17121
|
const parsed = JSON.parse(raw);
|
|
@@ -16881,7 +17209,7 @@ var ConfigManager = class {
|
|
|
16881
17209
|
return onResource;
|
|
16882
17210
|
}
|
|
16883
17211
|
async persistClearedPins(tiers) {
|
|
16884
|
-
const configPath =
|
|
17212
|
+
const configPath = path28__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
16885
17213
|
try {
|
|
16886
17214
|
const raw = JSON.parse(await fs11__default.default.readFile(configPath, "utf-8"));
|
|
16887
17215
|
const models = raw["models"];
|
|
@@ -17475,7 +17803,7 @@ function computeDelegationSavings(stats, t1Model) {
|
|
|
17475
17803
|
var DEFAULT_SNAPSHOT_URL = "https://raw.githubusercontent.com/Varun-SV/Cascade-AI/main/src/core/router/benchmark-data.json";
|
|
17476
17804
|
var OPENROUTER_MODELS_URL = "https://openrouter.ai/api/v1/models";
|
|
17477
17805
|
var FETCH_TIMEOUT_MS = 8e3;
|
|
17478
|
-
var DEFAULT_CACHE_FILE =
|
|
17806
|
+
var DEFAULT_CACHE_FILE = path28__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, "benchmarks-cache.json");
|
|
17479
17807
|
function normalizeModelId2(id) {
|
|
17480
17808
|
let s = id.toLowerCase();
|
|
17481
17809
|
const slash = s.lastIndexOf("/");
|
|
@@ -17622,7 +17950,7 @@ var LiveDataProvider = class {
|
|
|
17622
17950
|
}
|
|
17623
17951
|
async saveCache() {
|
|
17624
17952
|
try {
|
|
17625
|
-
await fs11__default.default.mkdir(
|
|
17953
|
+
await fs11__default.default.mkdir(path28__default.default.dirname(this.opts.cacheFile), { recursive: true });
|
|
17626
17954
|
const cache = {
|
|
17627
17955
|
fetchedAt: this.fetchedAt,
|
|
17628
17956
|
snapshot: this.snapshot ?? void 0,
|
|
@@ -17729,9 +18057,15 @@ var FAMILY_BENCHMARKS = {
|
|
|
17729
18057
|
"claude-opus": { code: 95, analysis: 92, creative: 90, data: 88 },
|
|
17730
18058
|
"claude-sonnet": { code: 93, analysis: 88, creative: 87, data: 85 },
|
|
17731
18059
|
"claude-haiku": { code: 80, analysis: 75, creative: 76, data: 72 },
|
|
17732
|
-
// OpenAI GPT-5 family
|
|
17733
|
-
//
|
|
17734
|
-
//
|
|
18060
|
+
// OpenAI GPT-5 family. GPT-5.6 is split by durable capability tier instead
|
|
18061
|
+
// of being folded into generic gpt-5: Sol, Terra and Luna have materially
|
|
18062
|
+
// different benchmark/cost envelopes and should compete independently.
|
|
18063
|
+
// Scores are the committed normalized snapshot; provenance is in
|
|
18064
|
+
// scripts/benchmarks/sources/openai-gpt-5.6-2026-08.json.
|
|
18065
|
+
"gpt-5.6-sol": { code: 100, analysis: 98, creative: 88, data: 88 },
|
|
18066
|
+
"gpt-5.6-terra": { code: 97, analysis: 92, creative: 82, data: 85 },
|
|
18067
|
+
"gpt-5.6-luna": { code: 93, analysis: 85, creative: 74, data: 60 },
|
|
18068
|
+
// Older GPT-5 point releases remain distinct where public data supports it.
|
|
17735
18069
|
"gpt-5.5": { code: 97, analysis: 96, creative: 94, data: 95 },
|
|
17736
18070
|
"gpt-5.4": { code: 94, analysis: 94, creative: 92, data: 92 },
|
|
17737
18071
|
"gpt-5.4-mini": { code: 86, analysis: 85, creative: 85, data: 83 },
|
|
@@ -17767,13 +18101,19 @@ var FAMILY_BENCHMARKS = {
|
|
|
17767
18101
|
"llama-small": { code: 55, analysis: 56, creative: 60, data: 54 }
|
|
17768
18102
|
};
|
|
17769
18103
|
var FAMILY_MATCHERS = [
|
|
18104
|
+
[/fable/i, "claude-opus"],
|
|
17770
18105
|
[/opus/i, "claude-opus"],
|
|
17771
18106
|
[/sonnet/i, "claude-sonnet"],
|
|
17772
18107
|
[/haiku/i, "claude-haiku"],
|
|
17773
|
-
// GPT-5 family — ordered most-specific first.
|
|
17774
|
-
//
|
|
17775
|
-
//
|
|
18108
|
+
// GPT-5 family — ordered most-specific first. GPT-5.6 durable tiers carry
|
|
18109
|
+
// their own profiles. 5.4 Nano intentionally maps to the nano class rather
|
|
18110
|
+
// than being swallowed by the generic 5.4 rule.
|
|
18111
|
+
[/gpt-?5\.6.*sol/i, "gpt-5.6-sol"],
|
|
18112
|
+
[/gpt-?5\.6.*terra/i, "gpt-5.6-terra"],
|
|
18113
|
+
[/gpt-?5\.6.*luna/i, "gpt-5.6-luna"],
|
|
18114
|
+
[/gpt-?5\.6(?:\s|$)/i, "gpt-5.6-sol"],
|
|
17776
18115
|
[/gpt-?5\.5/i, "gpt-5.5"],
|
|
18116
|
+
[/gpt-?5\.4.*nano/i, "gpt-5-nano"],
|
|
17777
18117
|
[/gpt-?5\.4.*mini/i, "gpt-5.4-mini"],
|
|
17778
18118
|
[/gpt-?5\.4/i, "gpt-5.4"],
|
|
17779
18119
|
[/gpt-?5.*nano/i, "gpt-5-nano"],
|
|
@@ -20832,8 +21172,8 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : "") + textToolSuffix,
|
|
|
20832
21172
|
// Media generation can run for a minute; without this a cancelled run
|
|
20833
21173
|
// still pays for an image nobody will see.
|
|
20834
21174
|
...this.signal ? { signal: this.signal } : {},
|
|
20835
|
-
saveSnapshot: async (
|
|
20836
|
-
this.store?.addFileSnapshot(this.taskId,
|
|
21175
|
+
saveSnapshot: async (path30, content) => {
|
|
21176
|
+
this.store?.addFileSnapshot(this.taskId, path30, content);
|
|
20837
21177
|
},
|
|
20838
21178
|
sendPeerSync: (to, syncType, content) => {
|
|
20839
21179
|
this.peerBus?.send(this.id, to, syncType, this.assignment?.subtaskId ?? "", content);
|
|
@@ -21036,7 +21376,7 @@ ${assignment.expectedOutput}`;
|
|
|
21036
21376
|
const { promisify: promisify4 } = await import('util');
|
|
21037
21377
|
const execFileAsync3 = promisify4(execFile4);
|
|
21038
21378
|
for (const artifactPath of artifactPaths) {
|
|
21039
|
-
const absolutePath =
|
|
21379
|
+
const absolutePath = path28__default.default.resolve(this.artifactRoot(), artifactPath);
|
|
21040
21380
|
try {
|
|
21041
21381
|
const stat = await fs11__default.default.stat(absolutePath);
|
|
21042
21382
|
if (!stat.isFile()) {
|
|
@@ -21071,7 +21411,7 @@ ${assignment.expectedOutput}`;
|
|
|
21071
21411
|
issues.push(`PDF artifact looks too small to be valid: ${artifactPath}`);
|
|
21072
21412
|
continue;
|
|
21073
21413
|
}
|
|
21074
|
-
const ext =
|
|
21414
|
+
const ext = path28__default.default.extname(absolutePath).toLowerCase();
|
|
21075
21415
|
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;
|
|
21076
21416
|
if (check) {
|
|
21077
21417
|
try {
|
|
@@ -21163,7 +21503,7 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
|
|
|
21163
21503
|
async checkAcceptance(assignment) {
|
|
21164
21504
|
const criteria = assignment.acceptance ?? [];
|
|
21165
21505
|
if (!criteria.length) return [];
|
|
21166
|
-
const resolve2 = (target) =>
|
|
21506
|
+
const resolve2 = (target) => path28__default.default.resolve(this.artifactRoot(), target);
|
|
21167
21507
|
const workerCanWriteFiles = canProduceFiles(this.tools.map((t) => t.name));
|
|
21168
21508
|
return evaluateAcceptance(criteria, assignment.files ?? [], {
|
|
21169
21509
|
stat: async (target) => {
|
|
@@ -24467,16 +24807,16 @@ function resolveInWorkspace(workspaceRoot, input) {
|
|
|
24467
24807
|
if (typeof input !== "string" || input.length === 0) {
|
|
24468
24808
|
throw new WorkspaceSandboxError(String(input), workspaceRoot);
|
|
24469
24809
|
}
|
|
24470
|
-
const root =
|
|
24471
|
-
const abs =
|
|
24472
|
-
const rel =
|
|
24473
|
-
if (rel === "" || rel === ".") ; else if (rel.startsWith("..") ||
|
|
24810
|
+
const root = path28__default.default.resolve(workspaceRoot);
|
|
24811
|
+
const abs = path28__default.default.isAbsolute(input) ? path28__default.default.resolve(input) : path28__default.default.resolve(root, input);
|
|
24812
|
+
const rel = path28__default.default.relative(root, abs);
|
|
24813
|
+
if (rel === "" || rel === ".") ; else if (rel.startsWith("..") || path28__default.default.isAbsolute(rel)) {
|
|
24474
24814
|
throw new WorkspaceSandboxError(input, root);
|
|
24475
24815
|
}
|
|
24476
24816
|
try {
|
|
24477
|
-
const real =
|
|
24478
|
-
const realRel =
|
|
24479
|
-
if (realRel !== "" && realRel !== "." && (realRel.startsWith("..") ||
|
|
24817
|
+
const real = fs27__default.default.realpathSync(abs);
|
|
24818
|
+
const realRel = path28__default.default.relative(root, real);
|
|
24819
|
+
if (realRel !== "" && realRel !== "." && (realRel.startsWith("..") || path28__default.default.isAbsolute(realRel))) {
|
|
24480
24820
|
throw new WorkspaceSandboxError(input, root);
|
|
24481
24821
|
}
|
|
24482
24822
|
} catch (e) {
|
|
@@ -25025,9 +25365,9 @@ async function animatePptx(bytes, scheme) {
|
|
|
25025
25365
|
const zip = await import_jszip.default.loadAsync(bytes);
|
|
25026
25366
|
const slidePaths = Object.keys(zip.files).filter((n) => /^ppt\/slides\/slide\d+\.xml$/.test(n));
|
|
25027
25367
|
if (slidePaths.length === 0) return bytes;
|
|
25028
|
-
for (const
|
|
25029
|
-
const xml = await zip.file(
|
|
25030
|
-
zip.file(
|
|
25368
|
+
for (const path30 of slidePaths) {
|
|
25369
|
+
const xml = await zip.file(path30).async("string");
|
|
25370
|
+
zip.file(path30, animateSlideXml(xml, scheme));
|
|
25031
25371
|
}
|
|
25032
25372
|
return await zip.generateAsync({ type: "uint8array", compression: "DEFLATE" });
|
|
25033
25373
|
} catch {
|
|
@@ -25413,7 +25753,7 @@ var GenerateDocumentTool = class extends BaseTool {
|
|
|
25413
25753
|
}
|
|
25414
25754
|
}
|
|
25415
25755
|
const bytes = await renderDocument(ext, content, { name: filePath, loadImageBytes });
|
|
25416
|
-
await fs11__default.default.mkdir(
|
|
25756
|
+
await fs11__default.default.mkdir(path28__default.default.dirname(absPath), { recursive: true });
|
|
25417
25757
|
await fs11__default.default.writeFile(absPath, bytes);
|
|
25418
25758
|
const charts = countCharts(content);
|
|
25419
25759
|
return [
|
|
@@ -25631,7 +25971,7 @@ var FileWriteTool = class extends BaseTool {
|
|
|
25631
25971
|
} catch {
|
|
25632
25972
|
}
|
|
25633
25973
|
}
|
|
25634
|
-
await fs11__default.default.mkdir(
|
|
25974
|
+
await fs11__default.default.mkdir(path28__default.default.dirname(absPath), { recursive: true });
|
|
25635
25975
|
await fs11__default.default.writeFile(absPath, content, "utf-8");
|
|
25636
25976
|
return `Written ${content.length} characters to ${filePath}`;
|
|
25637
25977
|
}
|
|
@@ -25989,12 +26329,10 @@ ${data.description}`;
|
|
|
25989
26329
|
}
|
|
25990
26330
|
}
|
|
25991
26331
|
};
|
|
25992
|
-
|
|
25993
|
-
// src/tools/browser.ts
|
|
25994
26332
|
var BROWSER_LAUNCH_TIMEOUT_MS = 15e3;
|
|
25995
26333
|
var BrowserTool = class extends BaseTool {
|
|
25996
26334
|
name = "browser";
|
|
25997
|
-
description = "Control a browser: navigate to URLs, click elements, fill forms, take screenshots.
|
|
26335
|
+
description = "Control a browser: navigate to URLs, click elements, fill forms, take screenshots. Screenshots are saved to a file for image_analyze to read.";
|
|
25998
26336
|
inputSchema = {
|
|
25999
26337
|
type: "object",
|
|
26000
26338
|
properties: {
|
|
@@ -26061,7 +26399,14 @@ var BrowserTool = class extends BaseTool {
|
|
|
26061
26399
|
}
|
|
26062
26400
|
case "screenshot": {
|
|
26063
26401
|
const buf = await page2.screenshot({ type: "png" });
|
|
26064
|
-
|
|
26402
|
+
const rel = path28__default.default.join(".cascade", "screenshots", `screenshot-${Date.now()}-${crypto.randomUUID().slice(0, 8)}.png`);
|
|
26403
|
+
const abs = resolveInWorkspace(this.workspaceRoot, rel);
|
|
26404
|
+
await fs11__default.default.mkdir(path28__default.default.dirname(abs), { recursive: true });
|
|
26405
|
+
await fs11__default.default.writeFile(abs, buf);
|
|
26406
|
+
return [
|
|
26407
|
+
`Screenshot saved to ${abs} (${Math.round(buf.byteLength / 1024)} KB).`,
|
|
26408
|
+
`Call image_analyze with that path to see what is on it \u2014 that needs a vision-capable model.`
|
|
26409
|
+
].join(" ");
|
|
26065
26410
|
}
|
|
26066
26411
|
case "evaluate": {
|
|
26067
26412
|
const result = await page2.evaluate(input["script"]);
|
|
@@ -26129,7 +26474,7 @@ var ImageAnalyzeTool = class extends BaseTool {
|
|
|
26129
26474
|
};
|
|
26130
26475
|
async function fileToImageAttachment(filePath) {
|
|
26131
26476
|
const data = await fs11__default.default.readFile(filePath);
|
|
26132
|
-
const ext =
|
|
26477
|
+
const ext = path28__default.default.extname(filePath).toLowerCase();
|
|
26133
26478
|
const mimeMap = {
|
|
26134
26479
|
".jpg": "image/jpeg",
|
|
26135
26480
|
".jpeg": "image/jpeg",
|
|
@@ -26163,14 +26508,14 @@ var PDFCreateTool = class extends BaseTool {
|
|
|
26163
26508
|
const filePath = input["path"];
|
|
26164
26509
|
const content = input["content"];
|
|
26165
26510
|
const title = input["title"];
|
|
26166
|
-
const dir =
|
|
26167
|
-
if (!
|
|
26168
|
-
|
|
26511
|
+
const dir = path28__default.default.dirname(filePath);
|
|
26512
|
+
if (!fs27__default.default.existsSync(dir)) {
|
|
26513
|
+
fs27__default.default.mkdirSync(dir, { recursive: true });
|
|
26169
26514
|
}
|
|
26170
26515
|
return new Promise((resolve2, reject) => {
|
|
26171
26516
|
try {
|
|
26172
26517
|
const doc = new PDFDocument__default.default({ margin: 50 });
|
|
26173
|
-
const stream =
|
|
26518
|
+
const stream = fs27__default.default.createWriteStream(filePath);
|
|
26174
26519
|
doc.pipe(stream);
|
|
26175
26520
|
if (title) {
|
|
26176
26521
|
doc.info["Title"] = title;
|
|
@@ -26248,22 +26593,22 @@ var CodeInterpreterTool = class extends BaseTool {
|
|
|
26248
26593
|
}
|
|
26249
26594
|
cmdPrefix = NODE_CMD;
|
|
26250
26595
|
}
|
|
26251
|
-
const tmpDir =
|
|
26252
|
-
if (!
|
|
26253
|
-
|
|
26596
|
+
const tmpDir = path28__default.default.join(this.workspaceRoot, ".cascade", "tmp");
|
|
26597
|
+
if (!fs27__default.default.existsSync(tmpDir)) {
|
|
26598
|
+
fs27__default.default.mkdirSync(tmpDir, { recursive: true });
|
|
26254
26599
|
}
|
|
26255
26600
|
const extension = language === "python" ? "py" : "js";
|
|
26256
26601
|
const fileName = `intp_${crypto.randomUUID().slice(0, 8)}.${extension}`;
|
|
26257
|
-
const filePath =
|
|
26258
|
-
|
|
26602
|
+
const filePath = path28__default.default.join(tmpDir, fileName);
|
|
26603
|
+
fs27__default.default.writeFileSync(filePath, code, "utf-8");
|
|
26259
26604
|
const execArgs = [filePath, ...args];
|
|
26260
26605
|
return new Promise((resolve2) => {
|
|
26261
26606
|
const startMs = Date.now();
|
|
26262
26607
|
child_process.execFile(cmdPrefix, execArgs, { cwd: this.workspaceRoot, timeout: 3e4 }, (error, stdout, stderr) => {
|
|
26263
26608
|
const duration = Date.now() - startMs;
|
|
26264
26609
|
try {
|
|
26265
|
-
if (
|
|
26266
|
-
|
|
26610
|
+
if (fs27__default.default.existsSync(filePath)) {
|
|
26611
|
+
fs27__default.default.unlinkSync(filePath);
|
|
26267
26612
|
}
|
|
26268
26613
|
} catch (cleanupErr) {
|
|
26269
26614
|
console.error(`Failed to cleanup interpreter script ${filePath}:`, cleanupErr);
|
|
@@ -26343,18 +26688,178 @@ ${formatted}`;
|
|
|
26343
26688
|
return `Unknown action: ${action}`;
|
|
26344
26689
|
}
|
|
26345
26690
|
};
|
|
26691
|
+
var SsrfBlockedError = class extends Error {
|
|
26692
|
+
constructor(message) {
|
|
26693
|
+
super(message);
|
|
26694
|
+
this.name = "SsrfBlockedError";
|
|
26695
|
+
}
|
|
26696
|
+
};
|
|
26697
|
+
var ALLOWED_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
26698
|
+
var MAX_REDIRECTS2 = 5;
|
|
26699
|
+
function allowLocal() {
|
|
26700
|
+
return process.env["CASCADE_ALLOW_LOCAL_FETCH"] === "1";
|
|
26701
|
+
}
|
|
26702
|
+
function isPrivateAddress(ip) {
|
|
26703
|
+
const type = net__default.default.isIP(ip);
|
|
26704
|
+
if (type === 4) return isPrivateIPv4(ip);
|
|
26705
|
+
if (type === 6) return isPrivateIPv6(ip);
|
|
26706
|
+
return true;
|
|
26707
|
+
}
|
|
26708
|
+
function isPrivateIPv4(ip) {
|
|
26709
|
+
const parts = ip.split(".").map((p) => Number(p));
|
|
26710
|
+
if (parts.length !== 4 || parts.some((p) => Number.isNaN(p) || p < 0 || p > 255)) return true;
|
|
26711
|
+
const [a, b] = parts;
|
|
26712
|
+
if (a === 0) return true;
|
|
26713
|
+
if (a === 10) return true;
|
|
26714
|
+
if (a === 127) return true;
|
|
26715
|
+
if (a === 169 && b === 254) return true;
|
|
26716
|
+
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
26717
|
+
if (a === 192 && b === 168) return true;
|
|
26718
|
+
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
26719
|
+
if (a >= 224) return true;
|
|
26720
|
+
return false;
|
|
26721
|
+
}
|
|
26722
|
+
function ipv6Groups(ip) {
|
|
26723
|
+
let s = ip.toLowerCase().replace(/^\[|\]$/g, "");
|
|
26724
|
+
const zone = s.indexOf("%");
|
|
26725
|
+
if (zone !== -1) s = s.slice(0, zone);
|
|
26726
|
+
const dotted = /^(.*:)(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(s);
|
|
26727
|
+
if (dotted) {
|
|
26728
|
+
const o = [dotted[2], dotted[3], dotted[4], dotted[5]].map((p) => Number(p));
|
|
26729
|
+
if (o.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return null;
|
|
26730
|
+
s = `${dotted[1]}${(o[0] << 8 | o[1]).toString(16)}:${(o[2] << 8 | o[3]).toString(16)}`;
|
|
26731
|
+
}
|
|
26732
|
+
const halves = s.split("::");
|
|
26733
|
+
if (halves.length > 2) return null;
|
|
26734
|
+
const split = (part) => part ? part.split(":") : [];
|
|
26735
|
+
const head = split(halves[0] ?? "");
|
|
26736
|
+
const tail = halves.length === 2 ? split(halves[1] ?? "") : [];
|
|
26737
|
+
const zeros = halves.length === 2 ? 8 - head.length - tail.length : 0;
|
|
26738
|
+
if (zeros < 0) return null;
|
|
26739
|
+
const groups = [...head, ...Array(zeros).fill("0"), ...tail];
|
|
26740
|
+
if (groups.length !== 8) return null;
|
|
26741
|
+
const out = [];
|
|
26742
|
+
for (const g of groups) {
|
|
26743
|
+
if (!/^[0-9a-f]{1,4}$/.test(g)) return null;
|
|
26744
|
+
out.push(parseInt(g, 16));
|
|
26745
|
+
}
|
|
26746
|
+
return out;
|
|
26747
|
+
}
|
|
26748
|
+
function embeddedIPv4(g) {
|
|
26749
|
+
const quad = (hi, lo) => `${hi >> 8}.${hi & 255}.${lo >> 8}.${lo & 255}`;
|
|
26750
|
+
const leadingZero = (n) => g.slice(0, n).every((x) => x === 0);
|
|
26751
|
+
if (leadingZero(5) && g[5] === 65535) return quad(g[6], g[7]);
|
|
26752
|
+
if (leadingZero(6)) return quad(g[6], g[7]);
|
|
26753
|
+
if (g[0] === 100 && g[1] === 65435) {
|
|
26754
|
+
if (g[2] === 1) {
|
|
26755
|
+
return quad(g[3], (g[4] & 255) << 8 | g[5] >> 8);
|
|
26756
|
+
}
|
|
26757
|
+
if (g[2] === 0 && g[3] === 0 && g[4] === 0 && g[5] === 0) return quad(g[6], g[7]);
|
|
26758
|
+
return null;
|
|
26759
|
+
}
|
|
26760
|
+
if (g[0] === 8194) return quad(g[1], g[2]);
|
|
26761
|
+
return null;
|
|
26762
|
+
}
|
|
26763
|
+
function isPrivateIPv6(ip) {
|
|
26764
|
+
const g = ipv6Groups(ip);
|
|
26765
|
+
if (!g) return true;
|
|
26766
|
+
const v4 = embeddedIPv4(g);
|
|
26767
|
+
if (v4) return isPrivateIPv4(v4);
|
|
26768
|
+
if (g[0] === 100 && g[1] === 65435) return true;
|
|
26769
|
+
if (g.every((x) => x === 0)) return true;
|
|
26770
|
+
if (leading7Zero(g) && g[7] === 1) return true;
|
|
26771
|
+
if ((g[0] & 65472) === 65152) return true;
|
|
26772
|
+
if ((g[0] & 65024) === 64512) return true;
|
|
26773
|
+
if ((g[0] & 65280) === 65280) return true;
|
|
26774
|
+
return false;
|
|
26775
|
+
}
|
|
26776
|
+
function leading7Zero(g) {
|
|
26777
|
+
return g.slice(0, 7).every((x) => x === 0);
|
|
26778
|
+
}
|
|
26779
|
+
async function assertPublicUrl(rawUrl) {
|
|
26780
|
+
let url;
|
|
26781
|
+
try {
|
|
26782
|
+
url = new URL(rawUrl);
|
|
26783
|
+
} catch {
|
|
26784
|
+
throw new SsrfBlockedError(`Invalid URL: ${rawUrl}`);
|
|
26785
|
+
}
|
|
26786
|
+
if (!ALLOWED_PROTOCOLS.has(url.protocol)) {
|
|
26787
|
+
throw new SsrfBlockedError(`Blocked URL scheme "${url.protocol}" \u2014 only http and https are allowed.`);
|
|
26788
|
+
}
|
|
26789
|
+
if (allowLocal()) return url;
|
|
26790
|
+
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
26791
|
+
if (net__default.default.isIP(host)) {
|
|
26792
|
+
if (isPrivateAddress(host)) {
|
|
26793
|
+
throw new SsrfBlockedError(`Blocked request to non-public address ${host}.`);
|
|
26794
|
+
}
|
|
26795
|
+
return url;
|
|
26796
|
+
}
|
|
26797
|
+
if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) {
|
|
26798
|
+
throw new SsrfBlockedError(`Blocked request to local hostname "${host}".`);
|
|
26799
|
+
}
|
|
26800
|
+
let addresses;
|
|
26801
|
+
try {
|
|
26802
|
+
const records = await dns2__default.default.lookup(host, { all: true });
|
|
26803
|
+
addresses = records.map((r) => r.address);
|
|
26804
|
+
} catch {
|
|
26805
|
+
throw new SsrfBlockedError(`Could not resolve host "${host}".`);
|
|
26806
|
+
}
|
|
26807
|
+
if (addresses.length === 0 || addresses.some((addr) => isPrivateAddress(addr))) {
|
|
26808
|
+
throw new SsrfBlockedError(`Blocked request to "${host}" \u2014 resolves to a non-public address.`);
|
|
26809
|
+
}
|
|
26810
|
+
return url;
|
|
26811
|
+
}
|
|
26812
|
+
var ssrfAgent = new undici.Agent({
|
|
26813
|
+
connect: {
|
|
26814
|
+
lookup(hostname, options, callback) {
|
|
26815
|
+
if (allowLocal()) {
|
|
26816
|
+
dnsCallback__default.default.lookup(hostname, options, callback);
|
|
26817
|
+
return;
|
|
26818
|
+
}
|
|
26819
|
+
dnsCallback__default.default.lookup(hostname, { ...options, all: true }, (err, addresses) => {
|
|
26820
|
+
if (err) return callback(err, "", 0);
|
|
26821
|
+
const list = Array.isArray(addresses) ? addresses : [addresses];
|
|
26822
|
+
const bad = list.find((a) => isPrivateAddress(a.address));
|
|
26823
|
+
if (bad) {
|
|
26824
|
+
return callback(
|
|
26825
|
+
new SsrfBlockedError(`Blocked connection to "${hostname}" \u2014 resolved to non-public address ${bad.address}.`),
|
|
26826
|
+
"",
|
|
26827
|
+
0
|
|
26828
|
+
);
|
|
26829
|
+
}
|
|
26830
|
+
if (options.all) return callback(null, list);
|
|
26831
|
+
const first = list[0];
|
|
26832
|
+
return callback(null, first.address, first.family);
|
|
26833
|
+
});
|
|
26834
|
+
}
|
|
26835
|
+
}
|
|
26836
|
+
});
|
|
26837
|
+
async function safeFetch(rawUrl, init = {}) {
|
|
26838
|
+
let currentUrl = (await assertPublicUrl(rawUrl)).toString();
|
|
26839
|
+
for (let i = 0; i <= MAX_REDIRECTS2; i++) {
|
|
26840
|
+
const resp = await fetch(currentUrl, { ...init, redirect: "manual", dispatcher: ssrfAgent });
|
|
26841
|
+
if (resp.status < 300 || resp.status >= 400) return resp;
|
|
26842
|
+
const location = resp.headers.get("location");
|
|
26843
|
+
if (!location) return resp;
|
|
26844
|
+
const next = new URL(location, currentUrl);
|
|
26845
|
+
await assertPublicUrl(next.toString());
|
|
26846
|
+
currentUrl = next.toString();
|
|
26847
|
+
}
|
|
26848
|
+
throw new SsrfBlockedError(`Too many redirects (>${MAX_REDIRECTS2}).`);
|
|
26849
|
+
}
|
|
26346
26850
|
|
|
26347
26851
|
// src/tools/web-search.ts
|
|
26348
|
-
async function searchSearXNG(query, baseUrl, maxResults) {
|
|
26852
|
+
async function searchSearXNG(query, baseUrl, maxResults, guardUrl = false) {
|
|
26349
26853
|
const url = new URL("/search", baseUrl);
|
|
26350
26854
|
url.searchParams.set("q", query);
|
|
26351
26855
|
url.searchParams.set("format", "json");
|
|
26352
26856
|
url.searchParams.set("categories", "general");
|
|
26353
26857
|
url.searchParams.set("engines", "google,bing,duckduckgo");
|
|
26354
|
-
const
|
|
26858
|
+
const init = {
|
|
26355
26859
|
headers: { "User-Agent": "Cascade-AI/1.0 WebSearchTool" },
|
|
26356
26860
|
signal: AbortSignal.timeout(1e4)
|
|
26357
|
-
}
|
|
26861
|
+
};
|
|
26862
|
+
const resp = guardUrl ? await safeFetch(url.toString(), init) : await fetch(url.toString(), init);
|
|
26358
26863
|
if (!resp.ok) {
|
|
26359
26864
|
throw new Error(`SearXNG returned HTTP ${resp.status}`);
|
|
26360
26865
|
}
|
|
@@ -26483,7 +26988,11 @@ var WebSearchTool = class extends BaseTool {
|
|
|
26483
26988
|
searxngUrl: config.searxngUrl ?? process.env["SEARXNG_URL"],
|
|
26484
26989
|
braveApiKey: config.braveApiKey ?? process.env["BRAVE_SEARCH_API_KEY"],
|
|
26485
26990
|
tavilyApiKey: config.tavilyApiKey ?? process.env["TAVILY_API_KEY"],
|
|
26486
|
-
maxResults: config.maxResults ?? 5
|
|
26991
|
+
maxResults: config.maxResults ?? 5,
|
|
26992
|
+
// Note this reads only from `config`, never from the environment: the
|
|
26993
|
+
// guard tracks the trustworthiness of the URL the host passed in, and an
|
|
26994
|
+
// env var says nothing about that.
|
|
26995
|
+
guardSearxngUrl: config.guardSearxngUrl ?? false
|
|
26487
26996
|
};
|
|
26488
26997
|
}
|
|
26489
26998
|
async execute(input, _options) {
|
|
@@ -26498,7 +27007,7 @@ var WebSearchTool = class extends BaseTool {
|
|
|
26498
27007
|
let anyBackendReachable = false;
|
|
26499
27008
|
if (this.config.searxngUrl) {
|
|
26500
27009
|
try {
|
|
26501
|
-
results = await searchSearXNG(query, this.config.searxngUrl, maxResults);
|
|
27010
|
+
results = await searchSearXNG(query, this.config.searxngUrl, maxResults, this.config.guardSearxngUrl);
|
|
26502
27011
|
anyBackendReachable = true;
|
|
26503
27012
|
if (results.length > 0) return this.formatResults(query, results);
|
|
26504
27013
|
errors.push("SearXNG: returned 0 results");
|
|
@@ -26575,7 +27084,7 @@ var GlobTool = class extends BaseTool {
|
|
|
26575
27084
|
};
|
|
26576
27085
|
async execute(input, _options) {
|
|
26577
27086
|
const pattern = input["pattern"];
|
|
26578
|
-
const searchPath = input["path"] ?
|
|
27087
|
+
const searchPath = input["path"] ? path28__default.default.resolve(this.workspaceRoot, input["path"]) : this.workspaceRoot;
|
|
26579
27088
|
const matches = await glob.glob(pattern, {
|
|
26580
27089
|
cwd: searchPath,
|
|
26581
27090
|
ignore: ["node_modules/**", ".git/**", "dist/**", "build/**"],
|
|
@@ -26588,7 +27097,7 @@ var GlobTool = class extends BaseTool {
|
|
|
26588
27097
|
const withMtime = await Promise.all(
|
|
26589
27098
|
matches.map(async (rel) => {
|
|
26590
27099
|
try {
|
|
26591
|
-
const stat = await fs11__default.default.stat(
|
|
27100
|
+
const stat = await fs11__default.default.stat(path28__default.default.join(searchPath, rel));
|
|
26592
27101
|
return { rel, mtime: stat.mtimeMs };
|
|
26593
27102
|
} catch {
|
|
26594
27103
|
return { rel, mtime: 0 };
|
|
@@ -26637,7 +27146,7 @@ var GrepTool = class extends BaseTool {
|
|
|
26637
27146
|
};
|
|
26638
27147
|
async execute(input, _options) {
|
|
26639
27148
|
const pattern = input["pattern"];
|
|
26640
|
-
const searchPath = input["path"] ?
|
|
27149
|
+
const searchPath = input["path"] ? path28__default.default.resolve(this.workspaceRoot, input["path"]) : this.workspaceRoot;
|
|
26641
27150
|
const globPattern = input["glob"];
|
|
26642
27151
|
const outputMode = input["output_mode"] ?? "content";
|
|
26643
27152
|
const context = input["context"] ?? 0;
|
|
@@ -26691,12 +27200,12 @@ var GrepTool = class extends BaseTool {
|
|
|
26691
27200
|
nodir: true
|
|
26692
27201
|
});
|
|
26693
27202
|
} catch {
|
|
26694
|
-
files = [
|
|
27203
|
+
files = [path28__default.default.relative(searchPath, searchPath) || "."];
|
|
26695
27204
|
}
|
|
26696
27205
|
const results = [];
|
|
26697
27206
|
let totalCount = 0;
|
|
26698
27207
|
for (const rel of files) {
|
|
26699
|
-
const abs =
|
|
27208
|
+
const abs = path28__default.default.join(searchPath, rel);
|
|
26700
27209
|
let content;
|
|
26701
27210
|
try {
|
|
26702
27211
|
content = await fs11__default.default.readFile(abs, "utf-8");
|
|
@@ -26737,92 +27246,6 @@ Total: ${totalCount} matches`);
|
|
|
26737
27246
|
return results.join("\n");
|
|
26738
27247
|
}
|
|
26739
27248
|
};
|
|
26740
|
-
var SsrfBlockedError = class extends Error {
|
|
26741
|
-
constructor(message) {
|
|
26742
|
-
super(message);
|
|
26743
|
-
this.name = "SsrfBlockedError";
|
|
26744
|
-
}
|
|
26745
|
-
};
|
|
26746
|
-
var ALLOWED_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
26747
|
-
var MAX_REDIRECTS2 = 5;
|
|
26748
|
-
function allowLocal() {
|
|
26749
|
-
return process.env["CASCADE_ALLOW_LOCAL_FETCH"] === "1";
|
|
26750
|
-
}
|
|
26751
|
-
function isPrivateAddress(ip) {
|
|
26752
|
-
const type = net__default.default.isIP(ip);
|
|
26753
|
-
if (type === 4) return isPrivateIPv4(ip);
|
|
26754
|
-
if (type === 6) return isPrivateIPv6(ip);
|
|
26755
|
-
return true;
|
|
26756
|
-
}
|
|
26757
|
-
function isPrivateIPv4(ip) {
|
|
26758
|
-
const parts = ip.split(".").map((p) => Number(p));
|
|
26759
|
-
if (parts.length !== 4 || parts.some((p) => Number.isNaN(p) || p < 0 || p > 255)) return true;
|
|
26760
|
-
const [a, b] = parts;
|
|
26761
|
-
if (a === 0) return true;
|
|
26762
|
-
if (a === 10) return true;
|
|
26763
|
-
if (a === 127) return true;
|
|
26764
|
-
if (a === 169 && b === 254) return true;
|
|
26765
|
-
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
26766
|
-
if (a === 192 && b === 168) return true;
|
|
26767
|
-
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
26768
|
-
if (a >= 224) return true;
|
|
26769
|
-
return false;
|
|
26770
|
-
}
|
|
26771
|
-
function isPrivateIPv6(ip) {
|
|
26772
|
-
const lower = ip.toLowerCase().replace(/^\[|\]$/g, "");
|
|
26773
|
-
if (lower === "::1" || lower === "::") return true;
|
|
26774
|
-
if (lower.startsWith("fe80")) return true;
|
|
26775
|
-
if (lower.startsWith("fc") || lower.startsWith("fd")) return true;
|
|
26776
|
-
const mapped = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(lower);
|
|
26777
|
-
if (mapped) return isPrivateIPv4(mapped[1]);
|
|
26778
|
-
return false;
|
|
26779
|
-
}
|
|
26780
|
-
async function assertPublicUrl(rawUrl) {
|
|
26781
|
-
let url;
|
|
26782
|
-
try {
|
|
26783
|
-
url = new URL(rawUrl);
|
|
26784
|
-
} catch {
|
|
26785
|
-
throw new SsrfBlockedError(`Invalid URL: ${rawUrl}`);
|
|
26786
|
-
}
|
|
26787
|
-
if (!ALLOWED_PROTOCOLS.has(url.protocol)) {
|
|
26788
|
-
throw new SsrfBlockedError(`Blocked URL scheme "${url.protocol}" \u2014 only http and https are allowed.`);
|
|
26789
|
-
}
|
|
26790
|
-
if (allowLocal()) return url;
|
|
26791
|
-
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
26792
|
-
if (net__default.default.isIP(host)) {
|
|
26793
|
-
if (isPrivateAddress(host)) {
|
|
26794
|
-
throw new SsrfBlockedError(`Blocked request to non-public address ${host}.`);
|
|
26795
|
-
}
|
|
26796
|
-
return url;
|
|
26797
|
-
}
|
|
26798
|
-
if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) {
|
|
26799
|
-
throw new SsrfBlockedError(`Blocked request to local hostname "${host}".`);
|
|
26800
|
-
}
|
|
26801
|
-
let addresses;
|
|
26802
|
-
try {
|
|
26803
|
-
const records = await dns2__default.default.lookup(host, { all: true });
|
|
26804
|
-
addresses = records.map((r) => r.address);
|
|
26805
|
-
} catch {
|
|
26806
|
-
throw new SsrfBlockedError(`Could not resolve host "${host}".`);
|
|
26807
|
-
}
|
|
26808
|
-
if (addresses.length === 0 || addresses.some((addr) => isPrivateAddress(addr))) {
|
|
26809
|
-
throw new SsrfBlockedError(`Blocked request to "${host}" \u2014 resolves to a non-public address.`);
|
|
26810
|
-
}
|
|
26811
|
-
return url;
|
|
26812
|
-
}
|
|
26813
|
-
async function safeFetch(rawUrl, init = {}) {
|
|
26814
|
-
let currentUrl = (await assertPublicUrl(rawUrl)).toString();
|
|
26815
|
-
for (let i = 0; i <= MAX_REDIRECTS2; i++) {
|
|
26816
|
-
const resp = await fetch(currentUrl, { ...init, redirect: "manual" });
|
|
26817
|
-
if (resp.status < 300 || resp.status >= 400) return resp;
|
|
26818
|
-
const location = resp.headers.get("location");
|
|
26819
|
-
if (!location) return resp;
|
|
26820
|
-
const next = new URL(location, currentUrl);
|
|
26821
|
-
await assertPublicUrl(next.toString());
|
|
26822
|
-
currentUrl = next.toString();
|
|
26823
|
-
}
|
|
26824
|
-
throw new SsrfBlockedError(`Too many redirects (>${MAX_REDIRECTS2}).`);
|
|
26825
|
-
}
|
|
26826
27249
|
|
|
26827
27250
|
// src/tools/web-fetch.ts
|
|
26828
27251
|
var MAX_CHARS = 5e4;
|
|
@@ -27095,10 +27518,10 @@ var ToolRegistry = class extends EventEmitter__default.default {
|
|
|
27095
27518
|
}
|
|
27096
27519
|
isIgnored(filePath) {
|
|
27097
27520
|
if (!filePath) return false;
|
|
27098
|
-
const abs =
|
|
27099
|
-
const rel =
|
|
27100
|
-
if (!rel || rel.startsWith("..") ||
|
|
27101
|
-
const posixRel = rel.split(
|
|
27521
|
+
const abs = path28__default.default.resolve(this.workspaceRoot, filePath);
|
|
27522
|
+
const rel = path28__default.default.relative(this.workspaceRoot, abs);
|
|
27523
|
+
if (!rel || rel.startsWith("..") || path28__default.default.isAbsolute(rel)) return true;
|
|
27524
|
+
const posixRel = rel.split(path28__default.default.sep).join("/");
|
|
27102
27525
|
return this.ignoreMatcher.ignores(posixRel);
|
|
27103
27526
|
}
|
|
27104
27527
|
};
|
|
@@ -27332,22 +27755,22 @@ var FileMcpOAuthStore = class {
|
|
|
27332
27755
|
filePath;
|
|
27333
27756
|
load() {
|
|
27334
27757
|
try {
|
|
27335
|
-
return JSON.parse(
|
|
27758
|
+
return JSON.parse(fs27__default.default.readFileSync(this.filePath, "utf-8"));
|
|
27336
27759
|
} catch {
|
|
27337
27760
|
return void 0;
|
|
27338
27761
|
}
|
|
27339
27762
|
}
|
|
27340
27763
|
save(state) {
|
|
27341
|
-
|
|
27342
|
-
|
|
27764
|
+
fs27__default.default.mkdirSync(path28__default.default.dirname(this.filePath), { recursive: true, mode: 448 });
|
|
27765
|
+
fs27__default.default.writeFileSync(this.filePath, JSON.stringify(state, null, 2), { mode: 384 });
|
|
27343
27766
|
try {
|
|
27344
|
-
|
|
27767
|
+
fs27__default.default.chmodSync(this.filePath, 384);
|
|
27345
27768
|
} catch {
|
|
27346
27769
|
}
|
|
27347
27770
|
}
|
|
27348
27771
|
clear() {
|
|
27349
27772
|
try {
|
|
27350
|
-
|
|
27773
|
+
fs27__default.default.rmSync(this.filePath);
|
|
27351
27774
|
} catch {
|
|
27352
27775
|
}
|
|
27353
27776
|
}
|
|
@@ -28185,7 +28608,7 @@ var TaskAnalyzer = class {
|
|
|
28185
28608
|
analysisCache.clear();
|
|
28186
28609
|
}
|
|
28187
28610
|
};
|
|
28188
|
-
var DEFAULT_STATS_FILE =
|
|
28611
|
+
var DEFAULT_STATS_FILE = path28__default.default.join(os6__default.default.homedir(), ".cascade", "model-perf.json");
|
|
28189
28612
|
var ModelPerformanceTracker = class _ModelPerformanceTracker {
|
|
28190
28613
|
stats = /* @__PURE__ */ new Map();
|
|
28191
28614
|
featureStats = /* @__PURE__ */ new Map();
|
|
@@ -28225,7 +28648,7 @@ var ModelPerformanceTracker = class _ModelPerformanceTracker {
|
|
|
28225
28648
|
async save() {
|
|
28226
28649
|
if (this.readOnly) return;
|
|
28227
28650
|
try {
|
|
28228
|
-
await fs11__default.default.mkdir(
|
|
28651
|
+
await fs11__default.default.mkdir(path28__default.default.dirname(this.statsFile), { recursive: true });
|
|
28229
28652
|
const modelsObj = {};
|
|
28230
28653
|
const featuresObj = {};
|
|
28231
28654
|
for (const [key, stat] of this.stats) modelsObj[key] = stat;
|
|
@@ -28858,7 +29281,7 @@ Required capability: ${description.slice(0, 300)}`;
|
|
|
28858
29281
|
* any dangerous action, so a silently-reloaded tool can't act without approval. */
|
|
28859
29282
|
async loadPersistedTools() {
|
|
28860
29283
|
if (!this.workspacePath || !this.persistEnabled) return;
|
|
28861
|
-
const file =
|
|
29284
|
+
const file = path28__default.default.join(this.workspacePath, ".cascade", DYNAMIC_TOOLS_FILE);
|
|
28862
29285
|
try {
|
|
28863
29286
|
const raw = await fs11__default.default.readFile(file, "utf-8");
|
|
28864
29287
|
const specs = JSON.parse(raw);
|
|
@@ -28882,8 +29305,8 @@ Required capability: ${description.slice(0, 300)}`;
|
|
|
28882
29305
|
}
|
|
28883
29306
|
async persist() {
|
|
28884
29307
|
if (!this.workspacePath || !this.persistEnabled) return;
|
|
28885
|
-
const dir =
|
|
28886
|
-
const file =
|
|
29308
|
+
const dir = path28__default.default.join(this.workspacePath, ".cascade");
|
|
29309
|
+
const file = path28__default.default.join(dir, DYNAMIC_TOOLS_FILE);
|
|
28887
29310
|
try {
|
|
28888
29311
|
await fs11__default.default.mkdir(dir, { recursive: true });
|
|
28889
29312
|
await fs11__default.default.writeFile(file, JSON.stringify(Array.from(this.specs.values()), null, 2), "utf-8");
|
|
@@ -28903,12 +29326,12 @@ var WorldStateDB = class {
|
|
|
28903
29326
|
constructor(workspacePath, debugMode = false) {
|
|
28904
29327
|
this.workspacePath = workspacePath;
|
|
28905
29328
|
this.debugMode = debugMode;
|
|
28906
|
-
const cascadeDir =
|
|
28907
|
-
if (!
|
|
28908
|
-
|
|
29329
|
+
const cascadeDir = path28__default.default.join(workspacePath, ".cascade");
|
|
29330
|
+
if (!fs27__default.default.existsSync(cascadeDir)) {
|
|
29331
|
+
fs27__default.default.mkdirSync(cascadeDir, { recursive: true });
|
|
28909
29332
|
}
|
|
28910
|
-
this.keyPath =
|
|
28911
|
-
this.dbPath =
|
|
29333
|
+
this.keyPath = path28__default.default.join(cascadeDir, "world_state.key");
|
|
29334
|
+
this.dbPath = path28__default.default.join(cascadeDir, "world_state.db");
|
|
28912
29335
|
this.initEncryptionKey();
|
|
28913
29336
|
this.db = new Database2__default.default(this.dbPath);
|
|
28914
29337
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -28965,11 +29388,11 @@ var WorldStateDB = class {
|
|
|
28965
29388
|
).run(e, r, row.encrypted_value, row.source_worker, row.timestamp, validTo, change);
|
|
28966
29389
|
}
|
|
28967
29390
|
initEncryptionKey() {
|
|
28968
|
-
if (
|
|
28969
|
-
this.encryptionKey =
|
|
29391
|
+
if (fs27__default.default.existsSync(this.keyPath)) {
|
|
29392
|
+
this.encryptionKey = fs27__default.default.readFileSync(this.keyPath);
|
|
28970
29393
|
} else {
|
|
28971
29394
|
this.encryptionKey = crypto__default.default.randomBytes(32);
|
|
28972
|
-
|
|
29395
|
+
fs27__default.default.writeFileSync(this.keyPath, this.encryptionKey);
|
|
28973
29396
|
}
|
|
28974
29397
|
}
|
|
28975
29398
|
encrypt(text) {
|
|
@@ -29255,9 +29678,9 @@ var WorldStateDB = class {
|
|
|
29255
29678
|
dumpDebugIfNeeded() {
|
|
29256
29679
|
if (!this.debugMode) return;
|
|
29257
29680
|
try {
|
|
29258
|
-
const dumpPath =
|
|
29681
|
+
const dumpPath = path28__default.default.join(os6__default.default.tmpdir(), "cascade_world_state_debug.json");
|
|
29259
29682
|
const entries = this.getAllEntries();
|
|
29260
|
-
|
|
29683
|
+
fs27__default.default.writeFileSync(dumpPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
29261
29684
|
} catch (err) {
|
|
29262
29685
|
console.error("Failed to dump debug world state", err);
|
|
29263
29686
|
}
|
|
@@ -29313,11 +29736,11 @@ var ResumeStore = class {
|
|
|
29313
29736
|
version: RESUME_SCHEMA_VERSION,
|
|
29314
29737
|
createdAt: checkpoint.createdAt ?? new Date(timestamp).toISOString()
|
|
29315
29738
|
};
|
|
29316
|
-
await
|
|
29317
|
-
const finalPath =
|
|
29739
|
+
await fs27.promises.mkdir(this.dir, { recursive: true });
|
|
29740
|
+
const finalPath = path28__default.default.join(this.dir, `${timestamp}-${safeId(record.taskId)}.json`);
|
|
29318
29741
|
const tempPath = `${finalPath}.${process.pid}.tmp`;
|
|
29319
|
-
await
|
|
29320
|
-
await
|
|
29742
|
+
await fs27.promises.writeFile(tempPath, JSON.stringify(record, null, 2), "utf-8");
|
|
29743
|
+
await fs27.promises.rename(tempPath, finalPath);
|
|
29321
29744
|
await this.prune();
|
|
29322
29745
|
return true;
|
|
29323
29746
|
} catch {
|
|
@@ -29328,7 +29751,7 @@ var ResumeStore = class {
|
|
|
29328
29751
|
async list() {
|
|
29329
29752
|
let entries;
|
|
29330
29753
|
try {
|
|
29331
|
-
entries = await
|
|
29754
|
+
entries = await fs27.promises.readdir(this.dir);
|
|
29332
29755
|
} catch {
|
|
29333
29756
|
return [];
|
|
29334
29757
|
}
|
|
@@ -29337,7 +29760,7 @@ var ResumeStore = class {
|
|
|
29337
29760
|
const checkpoints = [];
|
|
29338
29761
|
for (const candidate of candidates) {
|
|
29339
29762
|
try {
|
|
29340
|
-
const raw = await
|
|
29763
|
+
const raw = await fs27.promises.readFile(path28__default.default.join(this.dir, candidate.name), "utf-8");
|
|
29341
29764
|
const parsed = JSON.parse(raw);
|
|
29342
29765
|
if (isCheckpoint(parsed)) checkpoints.push(parsed);
|
|
29343
29766
|
} catch {
|
|
@@ -29371,12 +29794,12 @@ var ResumeStore = class {
|
|
|
29371
29794
|
const target = taskId ? all.find((c) => c.taskId === taskId) : all[0];
|
|
29372
29795
|
if (!target) return null;
|
|
29373
29796
|
try {
|
|
29374
|
-
const entries = await
|
|
29797
|
+
const entries = await fs27.promises.readdir(this.dir);
|
|
29375
29798
|
const wanted = safeId(target.taskId);
|
|
29376
29799
|
const source = entries.find((name) => FILE_PATTERN.exec(name)?.[2] === wanted);
|
|
29377
29800
|
if (!source) return null;
|
|
29378
29801
|
const claimId = `${this.now()}-${safeId(target.taskId)}`;
|
|
29379
|
-
await
|
|
29802
|
+
await fs27.promises.rename(path28__default.default.join(this.dir, source), path28__default.default.join(this.dir, `${claimId}${CLAIM_SUFFIX}`));
|
|
29380
29803
|
return { checkpoint: target, claimId };
|
|
29381
29804
|
} catch {
|
|
29382
29805
|
return null;
|
|
@@ -29385,9 +29808,9 @@ var ResumeStore = class {
|
|
|
29385
29808
|
/** Give a claim back, so the work stays recoverable after a failed start. */
|
|
29386
29809
|
async release(claimId) {
|
|
29387
29810
|
try {
|
|
29388
|
-
await
|
|
29389
|
-
|
|
29390
|
-
|
|
29811
|
+
await fs27.promises.rename(
|
|
29812
|
+
path28__default.default.join(this.dir, `${claimId}${CLAIM_SUFFIX}`),
|
|
29813
|
+
path28__default.default.join(this.dir, `${claimId}.json`)
|
|
29391
29814
|
);
|
|
29392
29815
|
} catch {
|
|
29393
29816
|
}
|
|
@@ -29395,7 +29818,7 @@ var ResumeStore = class {
|
|
|
29395
29818
|
/** Discard a claim for good — the resumed run has taken ownership. */
|
|
29396
29819
|
async settle(claimId) {
|
|
29397
29820
|
try {
|
|
29398
|
-
await
|
|
29821
|
+
await fs27.promises.rm(path28__default.default.join(this.dir, `${claimId}${CLAIM_SUFFIX}`), { force: true });
|
|
29399
29822
|
} catch {
|
|
29400
29823
|
}
|
|
29401
29824
|
}
|
|
@@ -29417,15 +29840,15 @@ var ResumeStore = class {
|
|
|
29417
29840
|
async reclaimStale() {
|
|
29418
29841
|
let reclaimed = 0;
|
|
29419
29842
|
try {
|
|
29420
|
-
const entries = await
|
|
29843
|
+
const entries = await fs27.promises.readdir(this.dir);
|
|
29421
29844
|
const cutoff = this.now() - this.claimTimeoutMs;
|
|
29422
29845
|
for (const name of entries) {
|
|
29423
29846
|
if (!name.endsWith(CLAIM_SUFFIX)) continue;
|
|
29424
29847
|
const stamp2 = Number(/^(\d+)-/.exec(name)?.[1]);
|
|
29425
29848
|
if (!Number.isFinite(stamp2) || stamp2 >= cutoff) continue;
|
|
29426
|
-
await
|
|
29427
|
-
|
|
29428
|
-
|
|
29849
|
+
await fs27.promises.rename(
|
|
29850
|
+
path28__default.default.join(this.dir, name),
|
|
29851
|
+
path28__default.default.join(this.dir, `${name.slice(0, -CLAIM_SUFFIX.length)}.json`)
|
|
29429
29852
|
);
|
|
29430
29853
|
reclaimed++;
|
|
29431
29854
|
}
|
|
@@ -29436,12 +29859,12 @@ var ResumeStore = class {
|
|
|
29436
29859
|
/** Remove every checkpoint for a task id. */
|
|
29437
29860
|
async delete(taskId) {
|
|
29438
29861
|
try {
|
|
29439
|
-
const entries = await
|
|
29862
|
+
const entries = await fs27.promises.readdir(this.dir);
|
|
29440
29863
|
const wanted = safeId(taskId);
|
|
29441
29864
|
await Promise.all(entries.map(async (name) => {
|
|
29442
29865
|
const match = FILE_PATTERN.exec(name);
|
|
29443
29866
|
if (match?.[2] === wanted) {
|
|
29444
|
-
await
|
|
29867
|
+
await fs27.promises.rm(path28__default.default.join(this.dir, name), { force: true });
|
|
29445
29868
|
}
|
|
29446
29869
|
}));
|
|
29447
29870
|
} catch {
|
|
@@ -29450,13 +29873,13 @@ var ResumeStore = class {
|
|
|
29450
29873
|
/** Drop expired checkpoints, then any beyond the newest `maxCheckpoints`. */
|
|
29451
29874
|
async prune() {
|
|
29452
29875
|
try {
|
|
29453
|
-
const entries = await
|
|
29876
|
+
const entries = await fs27.promises.readdir(this.dir);
|
|
29454
29877
|
const cutoff = this.now() - this.maxAgeMs;
|
|
29455
29878
|
const files = entries.map((name) => ({ name, match: FILE_PATTERN.exec(name) })).filter((e) => e.match !== null).map((e) => ({ name: e.name, timestamp: Number(e.match[1]) })).sort((a, b) => b.timestamp - a.timestamp);
|
|
29456
29879
|
const doomed = files.filter((f, index) => f.timestamp < cutoff || index >= this.maxCheckpoints);
|
|
29457
29880
|
const staleTemps = entries.filter((name) => name.endsWith(".tmp")).filter((name) => (Number(FILE_PATTERN.exec(name.replace(/\.\d+\.tmp$/, ".json"))?.[1]) || 0) < cutoff);
|
|
29458
29881
|
await Promise.all([...doomed.map((f) => f.name), ...staleTemps].map(
|
|
29459
|
-
(name) =>
|
|
29882
|
+
(name) => fs27.promises.rm(path28__default.default.join(this.dir, name), { force: true })
|
|
29460
29883
|
));
|
|
29461
29884
|
} catch {
|
|
29462
29885
|
}
|
|
@@ -29833,7 +30256,7 @@ var WorkspaceIndex = class {
|
|
|
29833
30256
|
isIgnored;
|
|
29834
30257
|
chunker;
|
|
29835
30258
|
constructor(opts) {
|
|
29836
|
-
this.root =
|
|
30259
|
+
this.root = path28__default.default.resolve(opts.root);
|
|
29837
30260
|
this.db = opts.db;
|
|
29838
30261
|
this.namespace = opts.namespace ?? "code";
|
|
29839
30262
|
this.extensions = new Set((opts.extensions ?? DEFAULT_EXTENSIONS).map((e) => e.replace(/^\./, "").toLowerCase()));
|
|
@@ -29865,14 +30288,14 @@ var WorkspaceIndex = class {
|
|
|
29865
30288
|
return;
|
|
29866
30289
|
}
|
|
29867
30290
|
for (const entry of entries) {
|
|
29868
|
-
const abs =
|
|
30291
|
+
const abs = path28__default.default.join(dir, entry.name);
|
|
29869
30292
|
if (entry.isDirectory()) {
|
|
29870
30293
|
if (HARD_SKIP_DIRS.has(entry.name) || this.isIgnored(abs)) continue;
|
|
29871
30294
|
await walk(abs);
|
|
29872
30295
|
} else if (entry.isFile()) {
|
|
29873
|
-
const ext =
|
|
30296
|
+
const ext = path28__default.default.extname(entry.name).slice(1).toLowerCase();
|
|
29874
30297
|
if (!this.extensions.has(ext) || this.isIgnored(abs)) continue;
|
|
29875
|
-
out.push(
|
|
30298
|
+
out.push(path28__default.default.relative(this.root, abs));
|
|
29876
30299
|
}
|
|
29877
30300
|
}
|
|
29878
30301
|
};
|
|
@@ -29902,7 +30325,7 @@ var WorkspaceIndex = class {
|
|
|
29902
30325
|
const entries = [];
|
|
29903
30326
|
for (const rel of rels) {
|
|
29904
30327
|
try {
|
|
29905
|
-
const abs =
|
|
30328
|
+
const abs = path28__default.default.join(this.root, rel);
|
|
29906
30329
|
const stat = await fs11__default.default.stat(abs);
|
|
29907
30330
|
if (stat.size > this.maxFileBytes) continue;
|
|
29908
30331
|
const buf = await fs11__default.default.readFile(abs);
|
|
@@ -30392,13 +30815,13 @@ var Cascade = class _Cascade extends EventEmitter__default.default {
|
|
|
30392
30815
|
this.toolRegistry = new ToolRegistry(this.config.tools, workspacePath);
|
|
30393
30816
|
try {
|
|
30394
30817
|
this.router.setDeadModelStore(new DeadModelStore(
|
|
30395
|
-
fileDeadModelPersistence(
|
|
30818
|
+
fileDeadModelPersistence(path28__default.default.join(workspacePath, ".cascade", "dead-models.json"))
|
|
30396
30819
|
));
|
|
30397
30820
|
} catch {
|
|
30398
30821
|
}
|
|
30399
30822
|
try {
|
|
30400
30823
|
this.resumeStore = new ResumeStore({
|
|
30401
|
-
dir:
|
|
30824
|
+
dir: path28__default.default.join(workspacePath, ".cascade", "resume")
|
|
30402
30825
|
});
|
|
30403
30826
|
} catch {
|
|
30404
30827
|
}
|
|
@@ -30486,8 +30909,8 @@ var Cascade = class _Cascade extends EventEmitter__default.default {
|
|
|
30486
30909
|
this.emit("log", { level: "warn", message: "Code index enabled but no embeddings-capable provider is configured \u2014 skipping." });
|
|
30487
30910
|
return;
|
|
30488
30911
|
}
|
|
30489
|
-
const dbPath = ci.dbPath ||
|
|
30490
|
-
|
|
30912
|
+
const dbPath = ci.dbPath || path28__default.default.join(this.workspacePath, ".cascade", "code-index.db");
|
|
30913
|
+
fs27__default.default.mkdirSync(path28__default.default.dirname(dbPath), { recursive: true });
|
|
30491
30914
|
const db = new Database2__default.default(dbPath);
|
|
30492
30915
|
db.pragma("journal_mode = WAL");
|
|
30493
30916
|
const complete = chatCompleterFromProviders(this.config.providers);
|
|
@@ -32261,8 +32684,8 @@ function replaceInPlace(target, source) {
|
|
|
32261
32684
|
}
|
|
32262
32685
|
function writeConfigFile(configPath, config) {
|
|
32263
32686
|
try {
|
|
32264
|
-
|
|
32265
|
-
|
|
32687
|
+
fs27__default.default.mkdirSync(path28__default.default.dirname(configPath), { recursive: true });
|
|
32688
|
+
fs27__default.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
32266
32689
|
return { ok: true };
|
|
32267
32690
|
} catch (err) {
|
|
32268
32691
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
@@ -32672,7 +33095,7 @@ function aggregateCostStats(sessions, opts = {}) {
|
|
|
32672
33095
|
}
|
|
32673
33096
|
|
|
32674
33097
|
// src/dashboard/server.ts
|
|
32675
|
-
var __dirname$1 =
|
|
33098
|
+
var __dirname$1 = path28__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
32676
33099
|
var ORPHANED_ESCALATION_GRACE_MS = 3e4;
|
|
32677
33100
|
var MASK = "***";
|
|
32678
33101
|
function masked(key, value) {
|
|
@@ -32991,7 +33414,7 @@ var DashboardServer = class {
|
|
|
32991
33414
|
* silently and still typecheck.
|
|
32992
33415
|
*/
|
|
32993
33416
|
persistConfig(config) {
|
|
32994
|
-
const result = writeConfigFile(
|
|
33417
|
+
const result = writeConfigFile(path28__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE), config);
|
|
32995
33418
|
if (!result.ok) console.warn(`[dashboard] Failed to persist config: ${result.error}`);
|
|
32996
33419
|
return result;
|
|
32997
33420
|
}
|
|
@@ -33010,7 +33433,7 @@ var DashboardServer = class {
|
|
|
33010
33433
|
*/
|
|
33011
33434
|
syncGlobalCredentials() {
|
|
33012
33435
|
try {
|
|
33013
|
-
saveGlobalCredentials(
|
|
33436
|
+
saveGlobalCredentials(path28__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR), this.config.providers ?? []);
|
|
33014
33437
|
} catch (err) {
|
|
33015
33438
|
console.warn(`[dashboard] Failed to sync global credentials: ${err instanceof Error ? err.message : String(err)}`);
|
|
33016
33439
|
}
|
|
@@ -33025,15 +33448,15 @@ var DashboardServer = class {
|
|
|
33025
33448
|
resolveDashboardSecret() {
|
|
33026
33449
|
const fromConfig = this.config.dashboard.secret ?? process.env["CASCADE_DASHBOARD_SECRET"];
|
|
33027
33450
|
if (fromConfig) return fromConfig;
|
|
33028
|
-
const secretPath =
|
|
33451
|
+
const secretPath = path28__default.default.join(this.workspacePath, CASCADE_DASHBOARD_SECRET_FILE);
|
|
33029
33452
|
try {
|
|
33030
|
-
if (
|
|
33031
|
-
const existing =
|
|
33453
|
+
if (fs27__default.default.existsSync(secretPath)) {
|
|
33454
|
+
const existing = fs27__default.default.readFileSync(secretPath, "utf-8").trim();
|
|
33032
33455
|
if (existing.length >= 16) return existing;
|
|
33033
33456
|
}
|
|
33034
33457
|
const generated = crypto.randomUUID();
|
|
33035
|
-
|
|
33036
|
-
|
|
33458
|
+
fs27__default.default.mkdirSync(path28__default.default.dirname(secretPath), { recursive: true });
|
|
33459
|
+
fs27__default.default.writeFileSync(secretPath, generated, { encoding: "utf-8", mode: 384 });
|
|
33037
33460
|
if (this.config.dashboard.auth) {
|
|
33038
33461
|
console.warn(
|
|
33039
33462
|
`Dashboard auth enabled with no secret configured; persisted a generated secret to ${secretPath}. Set CASCADE_DASHBOARD_SECRET or config.dashboard.secret to override.`
|
|
@@ -33060,7 +33483,7 @@ var DashboardServer = class {
|
|
|
33060
33483
|
// ── Setup ─────────────────────────────────────
|
|
33061
33484
|
getGlobalStore() {
|
|
33062
33485
|
if (!this.globalStore) {
|
|
33063
|
-
const globalDbPath =
|
|
33486
|
+
const globalDbPath = path28__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
33064
33487
|
this.globalStore = new MemoryStore(globalDbPath);
|
|
33065
33488
|
}
|
|
33066
33489
|
return this.globalStore;
|
|
@@ -33440,12 +33863,12 @@ ${prompt}`;
|
|
|
33440
33863
|
}
|
|
33441
33864
|
}
|
|
33442
33865
|
watchRuntimeChanges() {
|
|
33443
|
-
const workspaceDbPath =
|
|
33444
|
-
const globalDbPath =
|
|
33866
|
+
const workspaceDbPath = path28__default.default.join(this.workspacePath, CASCADE_DB_FILE);
|
|
33867
|
+
const globalDbPath = path28__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
33445
33868
|
const watchPaths = [workspaceDbPath, globalDbPath].filter((p, index, arr) => arr.indexOf(p) === index);
|
|
33446
33869
|
for (const watchPath of watchPaths) {
|
|
33447
|
-
if (!
|
|
33448
|
-
|
|
33870
|
+
if (!fs27__default.default.existsSync(watchPath)) continue;
|
|
33871
|
+
fs27__default.default.watchFile(watchPath, { interval: 3e3 }, () => {
|
|
33449
33872
|
this.throttledBroadcast(watchPath === globalDbPath ? "global" : "workspace");
|
|
33450
33873
|
});
|
|
33451
33874
|
}
|
|
@@ -33567,7 +33990,7 @@ ${prompt}`;
|
|
|
33567
33990
|
const sessionId = req.params.id;
|
|
33568
33991
|
this.store.deleteSession(sessionId);
|
|
33569
33992
|
this.store.deleteRuntimeSession(sessionId);
|
|
33570
|
-
const globalDbPath =
|
|
33993
|
+
const globalDbPath = path28__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
33571
33994
|
const globalStore = new MemoryStore(globalDbPath);
|
|
33572
33995
|
try {
|
|
33573
33996
|
globalStore.deleteRuntimeSession(sessionId);
|
|
@@ -33660,7 +34083,7 @@ ${prompt}`;
|
|
|
33660
34083
|
});
|
|
33661
34084
|
this.app.delete("/api/sessions", auth2, (req, res) => {
|
|
33662
34085
|
const body = req.body;
|
|
33663
|
-
const globalDbPath =
|
|
34086
|
+
const globalDbPath = path28__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
33664
34087
|
if (body?.ids && Array.isArray(body.ids) && body.ids.length > 0) {
|
|
33665
34088
|
const globalStore = new MemoryStore(globalDbPath);
|
|
33666
34089
|
try {
|
|
@@ -33683,7 +34106,7 @@ ${prompt}`;
|
|
|
33683
34106
|
});
|
|
33684
34107
|
this.app.delete("/api/runtime", auth2, (_req, res) => {
|
|
33685
34108
|
this.store.deleteAllRuntimeNodes();
|
|
33686
|
-
const globalDbPath =
|
|
34109
|
+
const globalDbPath = path28__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
33687
34110
|
const globalStore = new MemoryStore(globalDbPath);
|
|
33688
34111
|
try {
|
|
33689
34112
|
globalStore.deleteAllRuntimeNodes();
|
|
@@ -33768,12 +34191,12 @@ ${prompt}`;
|
|
|
33768
34191
|
if (body["tierLimits"]) this.config.tierLimits = { ...this.config.tierLimits, ...body["tierLimits"] };
|
|
33769
34192
|
if (body["budget"]) this.config.budget = { ...this.config.budget, ...body["budget"] };
|
|
33770
34193
|
try {
|
|
33771
|
-
const configPath =
|
|
33772
|
-
const existing =
|
|
34194
|
+
const configPath = path28__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
34195
|
+
const existing = fs27__default.default.existsSync(configPath) ? JSON.parse(fs27__default.default.readFileSync(configPath, "utf-8")) : {};
|
|
33773
34196
|
const updated = { ...existing, tierLimits: this.config.tierLimits, budget: this.config.budget };
|
|
33774
34197
|
const tmp = configPath + ".tmp";
|
|
33775
|
-
|
|
33776
|
-
|
|
34198
|
+
fs27__default.default.writeFileSync(tmp, JSON.stringify(updated, null, 2), "utf-8");
|
|
34199
|
+
fs27__default.default.renameSync(tmp, configPath);
|
|
33777
34200
|
res.json({ ok: true });
|
|
33778
34201
|
} catch (err) {
|
|
33779
34202
|
res.status(500).json({ error: `Failed to save config: ${err instanceof Error ? err.message : String(err)}` });
|
|
@@ -33801,7 +34224,7 @@ ${prompt}`;
|
|
|
33801
34224
|
this.app.get("/api/runtime", auth2, (req, res) => {
|
|
33802
34225
|
const scope = req.query["scope"] ?? "workspace";
|
|
33803
34226
|
if (scope === "global") {
|
|
33804
|
-
const globalDbPath =
|
|
34227
|
+
const globalDbPath = path28__default.default.join(os6__default.default.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
33805
34228
|
const globalStore = new MemoryStore(globalDbPath);
|
|
33806
34229
|
try {
|
|
33807
34230
|
res.json({
|
|
@@ -34142,13 +34565,13 @@ ${prompt}`;
|
|
|
34142
34565
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
34143
34566
|
}
|
|
34144
34567
|
});
|
|
34145
|
-
const prodPath =
|
|
34146
|
-
const devPath =
|
|
34147
|
-
const webDistPath =
|
|
34148
|
-
if (
|
|
34568
|
+
const prodPath = path28__default.default.resolve(__dirname$1, "../web/dist");
|
|
34569
|
+
const devPath = path28__default.default.resolve(__dirname$1, "../../web/dist");
|
|
34570
|
+
const webDistPath = fs27__default.default.existsSync(prodPath) ? prodPath : devPath;
|
|
34571
|
+
if (fs27__default.default.existsSync(webDistPath)) {
|
|
34149
34572
|
this.app.use(express__default.default.static(webDistPath));
|
|
34150
34573
|
this.app.get("*", (_req, res) => {
|
|
34151
|
-
res.sendFile(
|
|
34574
|
+
res.sendFile(path28__default.default.join(webDistPath, "index.html"));
|
|
34152
34575
|
});
|
|
34153
34576
|
} else {
|
|
34154
34577
|
this.app.get("/", (_req, res) => {
|
|
@@ -34335,14 +34758,14 @@ function planRetrieval(ctx) {
|
|
|
34335
34758
|
}
|
|
34336
34759
|
var CLOUD_SESSION_FILE = "cloud-session.json";
|
|
34337
34760
|
function globalDir(homeDir = os6__default.default.homedir()) {
|
|
34338
|
-
return
|
|
34761
|
+
return path28__default.default.join(homeDir, GLOBAL_CONFIG_DIR);
|
|
34339
34762
|
}
|
|
34340
34763
|
function cloudSessionPath(dir = globalDir()) {
|
|
34341
|
-
return
|
|
34764
|
+
return path28__default.default.join(dir, CLOUD_SESSION_FILE);
|
|
34342
34765
|
}
|
|
34343
34766
|
function loadCloudSession(dir = globalDir()) {
|
|
34344
34767
|
try {
|
|
34345
|
-
const raw =
|
|
34768
|
+
const raw = fs27__default.default.readFileSync(cloudSessionPath(dir), "utf-8");
|
|
34346
34769
|
const parsed = JSON.parse(raw);
|
|
34347
34770
|
if (!parsed?.refreshToken || !parsed?.serverUrl) return null;
|
|
34348
34771
|
return parsed;
|
|
@@ -34351,17 +34774,17 @@ function loadCloudSession(dir = globalDir()) {
|
|
|
34351
34774
|
}
|
|
34352
34775
|
}
|
|
34353
34776
|
function saveCloudSession(session, dir = globalDir()) {
|
|
34354
|
-
|
|
34777
|
+
fs27__default.default.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
34355
34778
|
const file = cloudSessionPath(dir);
|
|
34356
|
-
|
|
34779
|
+
fs27__default.default.writeFileSync(file, JSON.stringify(session, null, 2), { mode: 384 });
|
|
34357
34780
|
try {
|
|
34358
|
-
|
|
34781
|
+
fs27__default.default.chmodSync(file, 384);
|
|
34359
34782
|
} catch {
|
|
34360
34783
|
}
|
|
34361
34784
|
}
|
|
34362
34785
|
function clearCloudSession(dir = globalDir()) {
|
|
34363
34786
|
try {
|
|
34364
|
-
|
|
34787
|
+
fs27__default.default.rmSync(cloudSessionPath(dir));
|
|
34365
34788
|
} catch {
|
|
34366
34789
|
}
|
|
34367
34790
|
}
|
|
@@ -34533,16 +34956,16 @@ var CloudClient = class _CloudClient {
|
|
|
34533
34956
|
return (await this.refresh()).accessToken;
|
|
34534
34957
|
}
|
|
34535
34958
|
/** Authenticated request that refreshes once on a 401 (e.g. server-side revoke). */
|
|
34536
|
-
async authed(
|
|
34537
|
-
const call = (token) => fetch(this.url(
|
|
34959
|
+
async authed(path30, init = {}) {
|
|
34960
|
+
const call = (token) => fetch(this.url(path30), { ...init, headers: { ...init.headers ?? {}, Authorization: `Bearer ${token}` } });
|
|
34538
34961
|
let res = await call(await this.accessToken());
|
|
34539
34962
|
if (res.status === 401) res = await call((await this.refresh()).accessToken);
|
|
34540
34963
|
if (!res.ok) throw new Error(`Request failed (${res.status}).`);
|
|
34541
34964
|
const text = await res.text();
|
|
34542
34965
|
return text ? JSON.parse(text) : {};
|
|
34543
34966
|
}
|
|
34544
|
-
authedGet(
|
|
34545
|
-
return this.authed(
|
|
34967
|
+
authedGet(path30) {
|
|
34968
|
+
return this.authed(path30);
|
|
34546
34969
|
}
|
|
34547
34970
|
async fetchMe(token) {
|
|
34548
34971
|
const res = await fetch(this.url("/api/me"), { headers: { Authorization: `Bearer ${token}` } });
|
|
@@ -34923,6 +35346,7 @@ exports.CHARS_PER_TOKEN = CHARS_PER_TOKEN2;
|
|
|
34923
35346
|
exports.COMPLEXITY_T2_COUNT = COMPLEXITY_T2_COUNT;
|
|
34924
35347
|
exports.Cascade = Cascade;
|
|
34925
35348
|
exports.CascadeCancelledError = CascadeCancelledError;
|
|
35349
|
+
exports.CascadeConfigSchema = CascadeConfigSchema;
|
|
34926
35350
|
exports.CascadeIgnore = CascadeIgnore;
|
|
34927
35351
|
exports.CascadeRouter = CascadeRouter;
|
|
34928
35352
|
exports.CascadeToolError = CascadeToolError;
|