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/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import dnsCallback from 'dns';
|
|
2
2
|
import http, { createServer } from 'http';
|
|
3
3
|
import https from 'https';
|
|
4
4
|
import zlib from 'zlib';
|
|
@@ -7,8 +7,8 @@ import Anthropic from '@anthropic-ai/sdk';
|
|
|
7
7
|
import OpenAI, { AzureOpenAI } from 'openai';
|
|
8
8
|
import { HarmBlockThreshold, HarmCategory, GoogleGenAI } from '@google/genai';
|
|
9
9
|
import Database2 from 'better-sqlite3';
|
|
10
|
-
import
|
|
11
|
-
import
|
|
10
|
+
import path36, { dirname } from 'path';
|
|
11
|
+
import fs33, { mkdirSync, writeFileSync, existsSync, readFileSync, promises } from 'fs';
|
|
12
12
|
import os10 from 'os';
|
|
13
13
|
import crypto, { randomUUID, randomBytes, webcrypto, timingSafeEqual, createHash } from 'crypto';
|
|
14
14
|
import { render, Box, Text, useStdout, useApp, useInput, Static } from 'ink';
|
|
@@ -30,6 +30,7 @@ import { simpleGit } from 'simple-git';
|
|
|
30
30
|
import PDFDocument from 'pdfkit';
|
|
31
31
|
import dns2 from 'dns/promises';
|
|
32
32
|
import net from 'net';
|
|
33
|
+
import { Agent } from 'undici';
|
|
33
34
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
34
35
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
35
36
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
@@ -1795,7 +1796,7 @@ var CASCADE_VERSION, CASCADE_CONFIG_FILE, CASCADE_DB_FILE, CASCADE_DASHBOARD_SEC
|
|
|
1795
1796
|
var init_constants = __esm({
|
|
1796
1797
|
"src/constants.ts"() {
|
|
1797
1798
|
init_pricing();
|
|
1798
|
-
CASCADE_VERSION = "0.
|
|
1799
|
+
CASCADE_VERSION = "0.77.0";
|
|
1799
1800
|
CASCADE_CONFIG_FILE = ".cascade/config.json";
|
|
1800
1801
|
CASCADE_DB_FILE = ".cascade/memory.db";
|
|
1801
1802
|
CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
|
|
@@ -1808,64 +1809,88 @@ var init_constants = __esm({
|
|
|
1808
1809
|
DEFAULT_CONTEXT_LIMIT = 2e5;
|
|
1809
1810
|
DEFAULT_AUTO_SUMMARIZE_AT = 15e4;
|
|
1810
1811
|
MODELS = {
|
|
1811
|
-
// Anthropic
|
|
1812
|
-
"claude-
|
|
1813
|
-
id: "claude-
|
|
1814
|
-
name: "Claude
|
|
1812
|
+
// Anthropic — active Claude API models (2026-08-27).
|
|
1813
|
+
"claude-fable-5": {
|
|
1814
|
+
id: "claude-fable-5",
|
|
1815
|
+
name: "Claude Fable 5",
|
|
1815
1816
|
provider: "anthropic",
|
|
1816
|
-
contextWindow:
|
|
1817
|
+
contextWindow: 1e6,
|
|
1817
1818
|
isVisionCapable: true,
|
|
1818
|
-
inputCostPer1kTokens: 0.
|
|
1819
|
-
outputCostPer1kTokens: 0.
|
|
1820
|
-
maxOutputTokens:
|
|
1819
|
+
inputCostPer1kTokens: 0.01,
|
|
1820
|
+
outputCostPer1kTokens: 0.05,
|
|
1821
|
+
maxOutputTokens: 128e3,
|
|
1821
1822
|
supportsStreaming: true,
|
|
1822
1823
|
isLocal: false
|
|
1823
1824
|
},
|
|
1824
|
-
"claude-
|
|
1825
|
-
id: "claude-
|
|
1826
|
-
name: "Claude
|
|
1825
|
+
"claude-opus-5": {
|
|
1826
|
+
id: "claude-opus-5",
|
|
1827
|
+
name: "Claude Opus 5",
|
|
1827
1828
|
provider: "anthropic",
|
|
1828
|
-
contextWindow:
|
|
1829
|
+
contextWindow: 1e6,
|
|
1829
1830
|
isVisionCapable: true,
|
|
1830
|
-
inputCostPer1kTokens:
|
|
1831
|
-
outputCostPer1kTokens: 0.
|
|
1832
|
-
maxOutputTokens:
|
|
1831
|
+
inputCostPer1kTokens: 5e-3,
|
|
1832
|
+
outputCostPer1kTokens: 0.025,
|
|
1833
|
+
maxOutputTokens: 128e3,
|
|
1833
1834
|
supportsStreaming: true,
|
|
1834
1835
|
isLocal: false
|
|
1835
1836
|
},
|
|
1836
|
-
"claude-
|
|
1837
|
-
id: "claude-
|
|
1838
|
-
name: "Claude
|
|
1837
|
+
"claude-opus-4-8": {
|
|
1838
|
+
id: "claude-opus-4-8",
|
|
1839
|
+
name: "Claude Opus 4.8",
|
|
1839
1840
|
provider: "anthropic",
|
|
1840
|
-
contextWindow:
|
|
1841
|
+
contextWindow: 1e6,
|
|
1841
1842
|
isVisionCapable: true,
|
|
1842
|
-
inputCostPer1kTokens:
|
|
1843
|
-
outputCostPer1kTokens:
|
|
1844
|
-
maxOutputTokens:
|
|
1843
|
+
inputCostPer1kTokens: 5e-3,
|
|
1844
|
+
outputCostPer1kTokens: 0.025,
|
|
1845
|
+
maxOutputTokens: 128e3,
|
|
1845
1846
|
supportsStreaming: true,
|
|
1846
1847
|
isLocal: false
|
|
1847
1848
|
},
|
|
1848
|
-
"claude-
|
|
1849
|
-
id: "claude-
|
|
1850
|
-
name: "Claude
|
|
1849
|
+
"claude-opus-4-7": {
|
|
1850
|
+
id: "claude-opus-4-7",
|
|
1851
|
+
name: "Claude Opus 4.7",
|
|
1851
1852
|
provider: "anthropic",
|
|
1852
|
-
contextWindow:
|
|
1853
|
+
contextWindow: 1e6,
|
|
1853
1854
|
isVisionCapable: true,
|
|
1854
|
-
inputCostPer1kTokens:
|
|
1855
|
-
outputCostPer1kTokens:
|
|
1856
|
-
maxOutputTokens:
|
|
1855
|
+
inputCostPer1kTokens: 5e-3,
|
|
1856
|
+
outputCostPer1kTokens: 0.025,
|
|
1857
|
+
maxOutputTokens: 128e3,
|
|
1857
1858
|
supportsStreaming: true,
|
|
1858
1859
|
isLocal: false
|
|
1859
1860
|
},
|
|
1860
|
-
"claude-opus-4-
|
|
1861
|
-
id: "claude-opus-4-
|
|
1862
|
-
name: "Claude Opus 4.
|
|
1861
|
+
"claude-opus-4-6": {
|
|
1862
|
+
id: "claude-opus-4-6",
|
|
1863
|
+
name: "Claude Opus 4.6",
|
|
1864
|
+
provider: "anthropic",
|
|
1865
|
+
contextWindow: 1e6,
|
|
1866
|
+
isVisionCapable: true,
|
|
1867
|
+
inputCostPer1kTokens: 5e-3,
|
|
1868
|
+
outputCostPer1kTokens: 0.025,
|
|
1869
|
+
maxOutputTokens: 128e3,
|
|
1870
|
+
supportsStreaming: true,
|
|
1871
|
+
isLocal: false
|
|
1872
|
+
},
|
|
1873
|
+
"claude-opus-4-5": {
|
|
1874
|
+
id: "claude-opus-4-5-20251101",
|
|
1875
|
+
name: "Claude Opus 4.5",
|
|
1863
1876
|
provider: "anthropic",
|
|
1864
1877
|
contextWindow: 2e5,
|
|
1865
1878
|
isVisionCapable: true,
|
|
1866
|
-
inputCostPer1kTokens:
|
|
1867
|
-
outputCostPer1kTokens: 0.
|
|
1868
|
-
maxOutputTokens:
|
|
1879
|
+
inputCostPer1kTokens: 5e-3,
|
|
1880
|
+
outputCostPer1kTokens: 0.025,
|
|
1881
|
+
maxOutputTokens: 64e3,
|
|
1882
|
+
supportsStreaming: true,
|
|
1883
|
+
isLocal: false
|
|
1884
|
+
},
|
|
1885
|
+
"claude-sonnet-5": {
|
|
1886
|
+
id: "claude-sonnet-5",
|
|
1887
|
+
name: "Claude Sonnet 5",
|
|
1888
|
+
provider: "anthropic",
|
|
1889
|
+
contextWindow: 1e6,
|
|
1890
|
+
isVisionCapable: true,
|
|
1891
|
+
inputCostPer1kTokens: 2e-3,
|
|
1892
|
+
outputCostPer1kTokens: 0.01,
|
|
1893
|
+
maxOutputTokens: 128e3,
|
|
1869
1894
|
supportsStreaming: true,
|
|
1870
1895
|
isLocal: false
|
|
1871
1896
|
},
|
|
@@ -1873,76 +1898,135 @@ var init_constants = __esm({
|
|
|
1873
1898
|
id: "claude-sonnet-4-6",
|
|
1874
1899
|
name: "Claude Sonnet 4.6",
|
|
1875
1900
|
provider: "anthropic",
|
|
1901
|
+
contextWindow: 1e6,
|
|
1902
|
+
isVisionCapable: true,
|
|
1903
|
+
inputCostPer1kTokens: 3e-3,
|
|
1904
|
+
outputCostPer1kTokens: 0.015,
|
|
1905
|
+
maxOutputTokens: 64e3,
|
|
1906
|
+
supportsStreaming: true,
|
|
1907
|
+
isLocal: false
|
|
1908
|
+
},
|
|
1909
|
+
"claude-sonnet-4-5": {
|
|
1910
|
+
id: "claude-sonnet-4-5-20250929",
|
|
1911
|
+
name: "Claude Sonnet 4.5",
|
|
1912
|
+
provider: "anthropic",
|
|
1876
1913
|
contextWindow: 2e5,
|
|
1877
1914
|
isVisionCapable: true,
|
|
1878
1915
|
inputCostPer1kTokens: 3e-3,
|
|
1879
1916
|
outputCostPer1kTokens: 0.015,
|
|
1880
|
-
maxOutputTokens:
|
|
1917
|
+
maxOutputTokens: 64e3,
|
|
1881
1918
|
supportsStreaming: true,
|
|
1882
1919
|
isLocal: false
|
|
1883
1920
|
},
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1921
|
+
"claude-haiku-4-5": {
|
|
1922
|
+
id: "claude-haiku-4-5-20251001",
|
|
1923
|
+
name: "Claude Haiku 4.5",
|
|
1924
|
+
provider: "anthropic",
|
|
1925
|
+
contextWindow: 2e5,
|
|
1926
|
+
isVisionCapable: true,
|
|
1927
|
+
inputCostPer1kTokens: 1e-3,
|
|
1928
|
+
outputCostPer1kTokens: 5e-3,
|
|
1929
|
+
maxOutputTokens: 64e3,
|
|
1930
|
+
supportsStreaming: true,
|
|
1931
|
+
isLocal: false
|
|
1932
|
+
},
|
|
1933
|
+
// OpenAI — active chat-capable models used by Cascade's Chat Completions path.
|
|
1934
|
+
"gpt-5.6-sol": {
|
|
1935
|
+
id: "gpt-5.6-sol",
|
|
1936
|
+
name: "GPT-5.6 Sol",
|
|
1888
1937
|
provider: "openai",
|
|
1889
|
-
contextWindow:
|
|
1938
|
+
contextWindow: 105e4,
|
|
1939
|
+
isVisionCapable: true,
|
|
1940
|
+
inputCostPer1kTokens: 4e-3,
|
|
1941
|
+
outputCostPer1kTokens: 0.02,
|
|
1942
|
+
maxOutputTokens: 128e3,
|
|
1943
|
+
supportsStreaming: true,
|
|
1944
|
+
isLocal: false
|
|
1945
|
+
},
|
|
1946
|
+
"gpt-5.6-terra": {
|
|
1947
|
+
id: "gpt-5.6-terra",
|
|
1948
|
+
name: "GPT-5.6 Terra",
|
|
1949
|
+
provider: "openai",
|
|
1950
|
+
contextWindow: 105e4,
|
|
1951
|
+
isVisionCapable: true,
|
|
1952
|
+
inputCostPer1kTokens: 2e-3,
|
|
1953
|
+
outputCostPer1kTokens: 0.012,
|
|
1954
|
+
maxOutputTokens: 128e3,
|
|
1955
|
+
supportsStreaming: true,
|
|
1956
|
+
isLocal: false
|
|
1957
|
+
},
|
|
1958
|
+
"gpt-5.6-luna": {
|
|
1959
|
+
id: "gpt-5.6-luna",
|
|
1960
|
+
name: "GPT-5.6 Luna",
|
|
1961
|
+
provider: "openai",
|
|
1962
|
+
contextWindow: 105e4,
|
|
1963
|
+
isVisionCapable: true,
|
|
1964
|
+
inputCostPer1kTokens: 2e-4,
|
|
1965
|
+
outputCostPer1kTokens: 12e-4,
|
|
1966
|
+
maxOutputTokens: 128e3,
|
|
1967
|
+
supportsStreaming: true,
|
|
1968
|
+
isLocal: false
|
|
1969
|
+
},
|
|
1970
|
+
"gpt-5.5": {
|
|
1971
|
+
id: "gpt-5.5",
|
|
1972
|
+
name: "GPT-5.5",
|
|
1973
|
+
provider: "openai",
|
|
1974
|
+
contextWindow: 105e4,
|
|
1890
1975
|
isVisionCapable: true,
|
|
1891
1976
|
inputCostPer1kTokens: 5e-3,
|
|
1892
|
-
outputCostPer1kTokens: 0.
|
|
1893
|
-
maxOutputTokens:
|
|
1977
|
+
outputCostPer1kTokens: 0.03,
|
|
1978
|
+
maxOutputTokens: 128e3,
|
|
1894
1979
|
supportsStreaming: true,
|
|
1895
1980
|
isLocal: false
|
|
1896
1981
|
},
|
|
1897
|
-
"gpt-
|
|
1898
|
-
id: "gpt-
|
|
1899
|
-
name: "GPT-
|
|
1982
|
+
"gpt-5.4": {
|
|
1983
|
+
id: "gpt-5.4",
|
|
1984
|
+
name: "GPT-5.4",
|
|
1900
1985
|
provider: "openai",
|
|
1901
|
-
contextWindow:
|
|
1986
|
+
contextWindow: 105e4,
|
|
1902
1987
|
isVisionCapable: true,
|
|
1903
|
-
inputCostPer1kTokens:
|
|
1904
|
-
outputCostPer1kTokens:
|
|
1905
|
-
maxOutputTokens:
|
|
1988
|
+
inputCostPer1kTokens: 25e-4,
|
|
1989
|
+
outputCostPer1kTokens: 0.015,
|
|
1990
|
+
maxOutputTokens: 128e3,
|
|
1906
1991
|
supportsStreaming: true,
|
|
1907
1992
|
isLocal: false
|
|
1908
1993
|
},
|
|
1909
|
-
"gpt-4
|
|
1910
|
-
id: "gpt-4
|
|
1911
|
-
name: "GPT-4
|
|
1994
|
+
"gpt-5.4-mini": {
|
|
1995
|
+
id: "gpt-5.4-mini",
|
|
1996
|
+
name: "GPT-5.4 Mini",
|
|
1912
1997
|
provider: "openai",
|
|
1913
|
-
contextWindow:
|
|
1998
|
+
contextWindow: 4e5,
|
|
1914
1999
|
isVisionCapable: true,
|
|
1915
|
-
inputCostPer1kTokens:
|
|
1916
|
-
outputCostPer1kTokens:
|
|
1917
|
-
maxOutputTokens:
|
|
2000
|
+
inputCostPer1kTokens: 75e-5,
|
|
2001
|
+
outputCostPer1kTokens: 45e-4,
|
|
2002
|
+
maxOutputTokens: 128e3,
|
|
1918
2003
|
supportsStreaming: true,
|
|
1919
2004
|
isLocal: false
|
|
1920
2005
|
},
|
|
1921
|
-
"gpt-4
|
|
1922
|
-
id: "gpt-4
|
|
1923
|
-
name: "GPT-4
|
|
2006
|
+
"gpt-5.4-nano": {
|
|
2007
|
+
id: "gpt-5.4-nano",
|
|
2008
|
+
name: "GPT-5.4 Nano",
|
|
1924
2009
|
provider: "openai",
|
|
1925
|
-
contextWindow:
|
|
2010
|
+
contextWindow: 4e5,
|
|
1926
2011
|
isVisionCapable: true,
|
|
1927
|
-
inputCostPer1kTokens:
|
|
1928
|
-
outputCostPer1kTokens:
|
|
1929
|
-
maxOutputTokens:
|
|
2012
|
+
inputCostPer1kTokens: 2e-4,
|
|
2013
|
+
outputCostPer1kTokens: 125e-5,
|
|
2014
|
+
maxOutputTokens: 128e3,
|
|
1930
2015
|
supportsStreaming: true,
|
|
1931
2016
|
isLocal: false
|
|
1932
2017
|
},
|
|
1933
|
-
"gpt-
|
|
1934
|
-
id: "gpt-
|
|
1935
|
-
name: "GPT-
|
|
2018
|
+
"gpt-5.2": {
|
|
2019
|
+
id: "gpt-5.2",
|
|
2020
|
+
name: "GPT-5.2",
|
|
1936
2021
|
provider: "openai",
|
|
1937
|
-
contextWindow:
|
|
2022
|
+
contextWindow: 4e5,
|
|
1938
2023
|
isVisionCapable: true,
|
|
1939
|
-
inputCostPer1kTokens:
|
|
1940
|
-
outputCostPer1kTokens:
|
|
1941
|
-
maxOutputTokens:
|
|
2024
|
+
inputCostPer1kTokens: 175e-5,
|
|
2025
|
+
outputCostPer1kTokens: 0.014,
|
|
2026
|
+
maxOutputTokens: 128e3,
|
|
1942
2027
|
supportsStreaming: true,
|
|
1943
2028
|
isLocal: false
|
|
1944
2029
|
},
|
|
1945
|
-
// GPT-5 family (offline baseline pricing; the live fetch keeps it current).
|
|
1946
2030
|
"gpt-5": {
|
|
1947
2031
|
id: "gpt-5",
|
|
1948
2032
|
name: "GPT-5",
|
|
@@ -1979,79 +2063,149 @@ var init_constants = __esm({
|
|
|
1979
2063
|
supportsStreaming: true,
|
|
1980
2064
|
isLocal: false
|
|
1981
2065
|
},
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
"gpt-5.5": {
|
|
1986
|
-
id: "gpt-5.5",
|
|
1987
|
-
name: "GPT-5.5",
|
|
2066
|
+
"gpt-4.1": {
|
|
2067
|
+
id: "gpt-4.1",
|
|
2068
|
+
name: "GPT-4.1",
|
|
1988
2069
|
provider: "openai",
|
|
1989
|
-
contextWindow:
|
|
2070
|
+
contextWindow: 1047576,
|
|
1990
2071
|
isVisionCapable: true,
|
|
1991
|
-
inputCostPer1kTokens:
|
|
1992
|
-
outputCostPer1kTokens:
|
|
1993
|
-
maxOutputTokens:
|
|
2072
|
+
inputCostPer1kTokens: 2e-3,
|
|
2073
|
+
outputCostPer1kTokens: 8e-3,
|
|
2074
|
+
maxOutputTokens: 32768,
|
|
1994
2075
|
supportsStreaming: true,
|
|
1995
2076
|
isLocal: false
|
|
1996
2077
|
},
|
|
1997
|
-
"gpt-
|
|
1998
|
-
id: "gpt-
|
|
1999
|
-
name: "GPT-
|
|
2078
|
+
"gpt-4.1-mini": {
|
|
2079
|
+
id: "gpt-4.1-mini",
|
|
2080
|
+
name: "GPT-4.1 Mini",
|
|
2000
2081
|
provider: "openai",
|
|
2001
|
-
contextWindow:
|
|
2082
|
+
contextWindow: 1047576,
|
|
2002
2083
|
isVisionCapable: true,
|
|
2003
|
-
inputCostPer1kTokens:
|
|
2084
|
+
inputCostPer1kTokens: 4e-4,
|
|
2085
|
+
outputCostPer1kTokens: 16e-4,
|
|
2086
|
+
maxOutputTokens: 32768,
|
|
2087
|
+
supportsStreaming: true,
|
|
2088
|
+
isLocal: false
|
|
2089
|
+
},
|
|
2090
|
+
"gpt-4.1-nano": {
|
|
2091
|
+
id: "gpt-4.1-nano",
|
|
2092
|
+
name: "GPT-4.1 Nano",
|
|
2093
|
+
provider: "openai",
|
|
2094
|
+
contextWindow: 1047576,
|
|
2095
|
+
isVisionCapable: true,
|
|
2096
|
+
inputCostPer1kTokens: 1e-4,
|
|
2097
|
+
outputCostPer1kTokens: 4e-4,
|
|
2098
|
+
maxOutputTokens: 32768,
|
|
2099
|
+
supportsStreaming: true,
|
|
2100
|
+
isLocal: false
|
|
2101
|
+
},
|
|
2102
|
+
"gpt-4o": {
|
|
2103
|
+
id: "gpt-4o",
|
|
2104
|
+
name: "GPT-4o",
|
|
2105
|
+
provider: "openai",
|
|
2106
|
+
contextWindow: 128e3,
|
|
2107
|
+
isVisionCapable: true,
|
|
2108
|
+
inputCostPer1kTokens: 25e-4,
|
|
2004
2109
|
outputCostPer1kTokens: 0.01,
|
|
2005
|
-
maxOutputTokens:
|
|
2110
|
+
maxOutputTokens: 16e3,
|
|
2006
2111
|
supportsStreaming: true,
|
|
2007
2112
|
isLocal: false
|
|
2008
2113
|
},
|
|
2009
|
-
"gpt-
|
|
2010
|
-
id: "gpt-
|
|
2011
|
-
name: "GPT-
|
|
2114
|
+
"gpt-4o-mini": {
|
|
2115
|
+
id: "gpt-4o-mini",
|
|
2116
|
+
name: "GPT-4o Mini",
|
|
2012
2117
|
provider: "openai",
|
|
2013
|
-
contextWindow:
|
|
2118
|
+
contextWindow: 128e3,
|
|
2014
2119
|
isVisionCapable: true,
|
|
2015
|
-
inputCostPer1kTokens:
|
|
2016
|
-
outputCostPer1kTokens:
|
|
2017
|
-
maxOutputTokens:
|
|
2120
|
+
inputCostPer1kTokens: 15e-5,
|
|
2121
|
+
outputCostPer1kTokens: 6e-4,
|
|
2122
|
+
maxOutputTokens: 16e3,
|
|
2018
2123
|
supportsStreaming: true,
|
|
2019
2124
|
isLocal: false
|
|
2020
2125
|
},
|
|
2021
|
-
// Google
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2126
|
+
// Google Gemini — active GA + preview chat models. Gemini 2.0/1.5 are no
|
|
2127
|
+
// longer advertised because the Gemini API shut those generations down.
|
|
2128
|
+
"gemini-3.7-flash": {
|
|
2129
|
+
id: "gemini-3.7-flash",
|
|
2130
|
+
name: "Gemini 3.7 Flash",
|
|
2025
2131
|
provider: "gemini",
|
|
2026
|
-
contextWindow:
|
|
2132
|
+
contextWindow: 1048576,
|
|
2027
2133
|
isVisionCapable: true,
|
|
2028
|
-
inputCostPer1kTokens:
|
|
2029
|
-
outputCostPer1kTokens:
|
|
2030
|
-
maxOutputTokens:
|
|
2134
|
+
inputCostPer1kTokens: 75e-5,
|
|
2135
|
+
outputCostPer1kTokens: 375e-5,
|
|
2136
|
+
maxOutputTokens: 65536,
|
|
2031
2137
|
supportsStreaming: true,
|
|
2032
2138
|
isLocal: false
|
|
2033
2139
|
},
|
|
2034
|
-
"gemini-
|
|
2035
|
-
id: "gemini-
|
|
2036
|
-
name: "Gemini
|
|
2140
|
+
"gemini-3.6-flash": {
|
|
2141
|
+
id: "gemini-3.6-flash",
|
|
2142
|
+
name: "Gemini 3.6 Flash",
|
|
2037
2143
|
provider: "gemini",
|
|
2038
|
-
contextWindow:
|
|
2144
|
+
contextWindow: 1048576,
|
|
2039
2145
|
isVisionCapable: true,
|
|
2040
|
-
inputCostPer1kTokens:
|
|
2041
|
-
outputCostPer1kTokens:
|
|
2042
|
-
maxOutputTokens:
|
|
2146
|
+
inputCostPer1kTokens: 75e-5,
|
|
2147
|
+
outputCostPer1kTokens: 375e-5,
|
|
2148
|
+
maxOutputTokens: 65536,
|
|
2043
2149
|
supportsStreaming: true,
|
|
2044
2150
|
isLocal: false
|
|
2045
2151
|
},
|
|
2046
|
-
"gemini-
|
|
2047
|
-
id: "gemini-
|
|
2048
|
-
name: "Gemini
|
|
2152
|
+
"gemini-3.5-flash": {
|
|
2153
|
+
id: "gemini-3.5-flash",
|
|
2154
|
+
name: "Gemini 3.5 Flash",
|
|
2049
2155
|
provider: "gemini",
|
|
2050
|
-
contextWindow:
|
|
2156
|
+
contextWindow: 1048576,
|
|
2051
2157
|
isVisionCapable: true,
|
|
2052
|
-
inputCostPer1kTokens:
|
|
2053
|
-
outputCostPer1kTokens:
|
|
2054
|
-
maxOutputTokens:
|
|
2158
|
+
inputCostPer1kTokens: 15e-4,
|
|
2159
|
+
outputCostPer1kTokens: 9e-3,
|
|
2160
|
+
maxOutputTokens: 65536,
|
|
2161
|
+
supportsStreaming: true,
|
|
2162
|
+
isLocal: false
|
|
2163
|
+
},
|
|
2164
|
+
"gemini-3.5-flash-lite": {
|
|
2165
|
+
id: "gemini-3.5-flash-lite",
|
|
2166
|
+
name: "Gemini 3.5 Flash-Lite",
|
|
2167
|
+
provider: "gemini",
|
|
2168
|
+
contextWindow: 1048576,
|
|
2169
|
+
isVisionCapable: true,
|
|
2170
|
+
inputCostPer1kTokens: 3e-4,
|
|
2171
|
+
outputCostPer1kTokens: 25e-4,
|
|
2172
|
+
maxOutputTokens: 65536,
|
|
2173
|
+
supportsStreaming: true,
|
|
2174
|
+
isLocal: false
|
|
2175
|
+
},
|
|
2176
|
+
"gemini-3.1-flash-lite": {
|
|
2177
|
+
id: "gemini-3.1-flash-lite",
|
|
2178
|
+
name: "Gemini 3.1 Flash-Lite",
|
|
2179
|
+
provider: "gemini",
|
|
2180
|
+
contextWindow: 1048576,
|
|
2181
|
+
isVisionCapable: true,
|
|
2182
|
+
inputCostPer1kTokens: 25e-5,
|
|
2183
|
+
outputCostPer1kTokens: 15e-4,
|
|
2184
|
+
maxOutputTokens: 65536,
|
|
2185
|
+
supportsStreaming: true,
|
|
2186
|
+
isLocal: false
|
|
2187
|
+
},
|
|
2188
|
+
"gemini-3.1-pro-preview": {
|
|
2189
|
+
id: "gemini-3.1-pro-preview",
|
|
2190
|
+
name: "Gemini 3.1 Pro Preview",
|
|
2191
|
+
provider: "gemini",
|
|
2192
|
+
contextWindow: 1048576,
|
|
2193
|
+
isVisionCapable: true,
|
|
2194
|
+
inputCostPer1kTokens: 2e-3,
|
|
2195
|
+
outputCostPer1kTokens: 0.012,
|
|
2196
|
+
maxOutputTokens: 65536,
|
|
2197
|
+
supportsStreaming: true,
|
|
2198
|
+
isLocal: false
|
|
2199
|
+
},
|
|
2200
|
+
"gemini-3-flash-preview": {
|
|
2201
|
+
id: "gemini-3-flash-preview",
|
|
2202
|
+
name: "Gemini 3 Flash Preview",
|
|
2203
|
+
provider: "gemini",
|
|
2204
|
+
contextWindow: 1048576,
|
|
2205
|
+
isVisionCapable: true,
|
|
2206
|
+
inputCostPer1kTokens: 5e-4,
|
|
2207
|
+
outputCostPer1kTokens: 3e-3,
|
|
2208
|
+
maxOutputTokens: 65536,
|
|
2055
2209
|
supportsStreaming: true,
|
|
2056
2210
|
isLocal: false
|
|
2057
2211
|
},
|
|
@@ -2059,7 +2213,7 @@ var init_constants = __esm({
|
|
|
2059
2213
|
id: "gemini-2.5-pro",
|
|
2060
2214
|
name: "Gemini 2.5 Pro",
|
|
2061
2215
|
provider: "gemini",
|
|
2062
|
-
contextWindow:
|
|
2216
|
+
contextWindow: 1048576,
|
|
2063
2217
|
isVisionCapable: true,
|
|
2064
2218
|
inputCostPer1kTokens: 125e-5,
|
|
2065
2219
|
outputCostPer1kTokens: 0.01,
|
|
@@ -2071,10 +2225,22 @@ var init_constants = __esm({
|
|
|
2071
2225
|
id: "gemini-2.5-flash",
|
|
2072
2226
|
name: "Gemini 2.5 Flash",
|
|
2073
2227
|
provider: "gemini",
|
|
2074
|
-
contextWindow:
|
|
2228
|
+
contextWindow: 1048576,
|
|
2075
2229
|
isVisionCapable: true,
|
|
2076
|
-
inputCostPer1kTokens:
|
|
2077
|
-
outputCostPer1kTokens:
|
|
2230
|
+
inputCostPer1kTokens: 3e-4,
|
|
2231
|
+
outputCostPer1kTokens: 25e-4,
|
|
2232
|
+
maxOutputTokens: 65536,
|
|
2233
|
+
supportsStreaming: true,
|
|
2234
|
+
isLocal: false
|
|
2235
|
+
},
|
|
2236
|
+
"gemini-2.5-flash-lite": {
|
|
2237
|
+
id: "gemini-2.5-flash-lite",
|
|
2238
|
+
name: "Gemini 2.5 Flash-Lite",
|
|
2239
|
+
provider: "gemini",
|
|
2240
|
+
contextWindow: 1048576,
|
|
2241
|
+
isVisionCapable: true,
|
|
2242
|
+
inputCostPer1kTokens: 1e-4,
|
|
2243
|
+
outputCostPer1kTokens: 4e-4,
|
|
2078
2244
|
maxOutputTokens: 65536,
|
|
2079
2245
|
supportsStreaming: true,
|
|
2080
2246
|
isLocal: false
|
|
@@ -2144,43 +2310,57 @@ var init_constants = __esm({
|
|
|
2144
2310
|
_m.pricingUnknown = false;
|
|
2145
2311
|
}
|
|
2146
2312
|
T1_MODEL_PRIORITY = [
|
|
2313
|
+
"gpt-5.6-sol",
|
|
2314
|
+
"claude-fable-5",
|
|
2315
|
+
"claude-opus-5",
|
|
2147
2316
|
"gpt-5.5",
|
|
2148
2317
|
"gpt-5.4",
|
|
2318
|
+
"gemini-3.1-pro-preview",
|
|
2319
|
+
"claude-opus-4-8",
|
|
2320
|
+
"claude-sonnet-5",
|
|
2321
|
+
"gemini-3.7-flash",
|
|
2322
|
+
"gpt-5.2",
|
|
2149
2323
|
"gpt-5",
|
|
2150
|
-
"claude-opus-4",
|
|
2151
|
-
"claude-sonnet-4",
|
|
2152
2324
|
"gemini-2.5-pro",
|
|
2153
2325
|
"gpt-4.1",
|
|
2154
|
-
"gpt-4o"
|
|
2155
|
-
"gemini-1.5-pro"
|
|
2326
|
+
"gpt-4o"
|
|
2156
2327
|
];
|
|
2157
2328
|
T2_MODEL_PRIORITY = [
|
|
2329
|
+
"gpt-5.6-terra",
|
|
2330
|
+
"claude-sonnet-5",
|
|
2331
|
+
"gemini-3.7-flash",
|
|
2332
|
+
"gemini-3.6-flash",
|
|
2158
2333
|
"gpt-5.4-mini",
|
|
2159
2334
|
"gpt-5-mini",
|
|
2160
|
-
"claude-sonnet-4",
|
|
2335
|
+
"claude-sonnet-4-6",
|
|
2161
2336
|
"claude-haiku-4-5",
|
|
2162
|
-
"
|
|
2337
|
+
"gemini-3.5-flash",
|
|
2163
2338
|
"gemini-2.5-flash",
|
|
2164
2339
|
"gpt-4.1-mini",
|
|
2165
2340
|
"gpt-4o-mini",
|
|
2166
|
-
"gemini-2.0-flash",
|
|
2167
2341
|
"llama3:70b"
|
|
2168
2342
|
];
|
|
2169
2343
|
T3_MODEL_PRIORITY = [
|
|
2344
|
+
"gpt-5.6-luna",
|
|
2345
|
+
"gpt-5.4-nano",
|
|
2346
|
+
"gemini-3.5-flash-lite",
|
|
2347
|
+
"gemini-3.1-flash-lite",
|
|
2348
|
+
"claude-haiku-4-5",
|
|
2170
2349
|
"gpt-5-nano",
|
|
2350
|
+
"gemini-2.5-flash-lite",
|
|
2171
2351
|
"llama3.2:3b",
|
|
2172
2352
|
"mistral:7b",
|
|
2173
|
-
"claude-haiku-4-5",
|
|
2174
|
-
"claude-haiku-3-5",
|
|
2175
2353
|
"gpt-4.1-nano",
|
|
2176
2354
|
"gpt-4o-mini",
|
|
2177
|
-
"gemini-2.5-flash"
|
|
2178
|
-
"gemini-2.0-flash"
|
|
2355
|
+
"gemini-2.5-flash"
|
|
2179
2356
|
];
|
|
2180
2357
|
VISION_MODEL_PRIORITY = [
|
|
2181
|
-
"
|
|
2358
|
+
"gpt-5.6-sol",
|
|
2359
|
+
"claude-fable-5",
|
|
2360
|
+
"claude-sonnet-5",
|
|
2361
|
+
"gemini-3.7-flash",
|
|
2182
2362
|
"gpt-4o",
|
|
2183
|
-
"gemini-2.
|
|
2363
|
+
"gemini-2.5-flash",
|
|
2184
2364
|
"llava"
|
|
2185
2365
|
];
|
|
2186
2366
|
COMPLEXITY_T2_COUNT = {
|
|
@@ -2237,8 +2417,8 @@ function normalizeEndpoint(url) {
|
|
|
2237
2417
|
if (!raw) return "";
|
|
2238
2418
|
try {
|
|
2239
2419
|
const u = new URL(raw);
|
|
2240
|
-
const
|
|
2241
|
-
return `${u.protocol}//${u.host.toLowerCase()}${
|
|
2420
|
+
const path41 = stripTrailingSlashes(`${u.pathname}${u.search}`);
|
|
2421
|
+
return `${u.protocol}//${u.host.toLowerCase()}${path41}`;
|
|
2242
2422
|
} catch {
|
|
2243
2423
|
return raw.toLowerCase();
|
|
2244
2424
|
}
|
|
@@ -2370,7 +2550,7 @@ var CLIENT_VERSION_SEGMENT, REDIRECT_STATUSES, NULL_BODY_STATUSES, MAX_REDIRECTS
|
|
|
2370
2550
|
var init_net = __esm({
|
|
2371
2551
|
"src/utils/net.ts"() {
|
|
2372
2552
|
try {
|
|
2373
|
-
|
|
2553
|
+
dnsCallback.setDefaultResultOrder("ipv4first");
|
|
2374
2554
|
} catch {
|
|
2375
2555
|
}
|
|
2376
2556
|
CLIENT_VERSION_SEGMENT = {
|
|
@@ -3102,6 +3282,56 @@ var init_openai = __esm({
|
|
|
3102
3282
|
}
|
|
3103
3283
|
});
|
|
3104
3284
|
|
|
3285
|
+
// src/providers/cloud-model-catalog.json
|
|
3286
|
+
var cloud_model_catalog_default;
|
|
3287
|
+
var init_cloud_model_catalog = __esm({
|
|
3288
|
+
"src/providers/cloud-model-catalog.json"() {
|
|
3289
|
+
cloud_model_catalog_default = {
|
|
3290
|
+
schemaVersion: 1,
|
|
3291
|
+
verifiedAt: "2026-08-27",
|
|
3292
|
+
scope: "GA and Preview text/chat models that Cascade can route through its maintained cloud providers. Retired, shutdown, realtime/audio-only, embedding, image-only, video-only, and access-restricted models are excluded.",
|
|
3293
|
+
note: "Capabilities belong to the canonical model. Pricing deliberately does not live here: Cascade resolves price by model x provider x region in core/router/pricing-data.json. A model exposed by multiple providers may therefore have different prices without duplicating its capability profile.",
|
|
3294
|
+
models: [
|
|
3295
|
+
{ id: "gpt-5.6-sol", name: "GPT-5.6 Sol", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3296
|
+
{ id: "gpt-5.6-terra", name: "GPT-5.6 Terra", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3297
|
+
{ id: "gpt-5.6-luna", name: "GPT-5.6 Luna", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3298
|
+
{ id: "gpt-5.5", name: "GPT-5.5", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3299
|
+
{ id: "gpt-5.4", name: "GPT-5.4", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 105e4, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3300
|
+
{ id: "gpt-5.4-mini", name: "GPT-5.4 Mini", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3301
|
+
{ id: "gpt-5.4-nano", name: "GPT-5.4 Nano", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3302
|
+
{ id: "gpt-5", name: "GPT-5", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3303
|
+
{ id: "gpt-5-mini", name: "GPT-5 Mini", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3304
|
+
{ id: "gpt-5-nano", name: "GPT-5 Nano", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 4e5, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3305
|
+
{ id: "gpt-4.1", name: "GPT-4.1", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 1047576, maxOutputTokens: 32768, vision: true, toolUse: true },
|
|
3306
|
+
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 1047576, maxOutputTokens: 32768, vision: true, toolUse: true },
|
|
3307
|
+
{ id: "gpt-4.1-nano", name: "GPT-4.1 Nano", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 1047576, maxOutputTokens: 32768, vision: true, toolUse: true },
|
|
3308
|
+
{ id: "gpt-4o", name: "GPT-4o", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 128e3, maxOutputTokens: 16384, vision: true, toolUse: true },
|
|
3309
|
+
{ id: "gpt-4o-mini", name: "GPT-4o Mini", providers: ["openai", "azure"], lifecycle: "ga", contextWindow: 128e3, maxOutputTokens: 16384, vision: true, toolUse: true },
|
|
3310
|
+
{ id: "claude-fable-5", name: "Claude Fable 5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3311
|
+
{ id: "claude-opus-5", name: "Claude Opus 5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3312
|
+
{ id: "claude-opus-4-8", name: "Claude Opus 4.8", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3313
|
+
{ id: "claude-opus-4-7", name: "Claude Opus 4.7", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3314
|
+
{ id: "claude-opus-4-6", name: "Claude Opus 4.6", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, vision: true, toolUse: true },
|
|
3315
|
+
{ id: "claude-opus-4-5-20251101", name: "Claude Opus 4.5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 2e5, vision: true, toolUse: true },
|
|
3316
|
+
{ id: "claude-sonnet-5", name: "Claude Sonnet 5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3317
|
+
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", providers: ["anthropic"], lifecycle: "ga", contextWindow: 1e6, maxOutputTokens: 128e3, vision: true, toolUse: true },
|
|
3318
|
+
{ id: "claude-sonnet-4-5-20250929", name: "Claude Sonnet 4.5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 2e5, vision: true, toolUse: true },
|
|
3319
|
+
{ id: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5", providers: ["anthropic"], lifecycle: "ga", contextWindow: 2e5, maxOutputTokens: 64e3, vision: true, toolUse: true },
|
|
3320
|
+
{ id: "gemini-3.7-flash", name: "Gemini 3.7 Flash", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
3321
|
+
{ id: "gemini-3.6-flash", name: "Gemini 3.6 Flash", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
3322
|
+
{ id: "gemini-3.5-flash", name: "Gemini 3.5 Flash", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
3323
|
+
{ id: "gemini-3.5-flash-lite", name: "Gemini 3.5 Flash-Lite", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
3324
|
+
{ id: "gemini-3.1-flash-lite", name: "Gemini 3.1 Flash-Lite", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
3325
|
+
{ id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro", providers: ["gemini"], lifecycle: "preview", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
3326
|
+
{ id: "gemini-3-flash-preview", name: "Gemini 3 Flash", providers: ["gemini"], lifecycle: "preview", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
3327
|
+
{ id: "gemini-2.5-pro", name: "Gemini 2.5 Pro", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
3328
|
+
{ id: "gemini-2.5-flash", name: "Gemini 2.5 Flash", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true },
|
|
3329
|
+
{ id: "gemini-2.5-flash-lite", name: "Gemini 2.5 Flash-Lite", providers: ["gemini"], lifecycle: "ga", contextWindow: 1048576, maxOutputTokens: 65536, vision: true, toolUse: true }
|
|
3330
|
+
]
|
|
3331
|
+
};
|
|
3332
|
+
}
|
|
3333
|
+
});
|
|
3334
|
+
|
|
3105
3335
|
// src/providers/azure.ts
|
|
3106
3336
|
var azure_exports = {};
|
|
3107
3337
|
__export(azure_exports, {
|
|
@@ -3110,36 +3340,81 @@ __export(azure_exports, {
|
|
|
3110
3340
|
azureModelForDeployment: () => azureModelForDeployment,
|
|
3111
3341
|
inferAzureBaseModel: () => inferAzureBaseModel
|
|
3112
3342
|
});
|
|
3343
|
+
function compactModelId(id) {
|
|
3344
|
+
return id.toLowerCase().replace(/[^a-z0-9.]/g, "");
|
|
3345
|
+
}
|
|
3346
|
+
function catalogEntry(id) {
|
|
3347
|
+
const n = id.toLowerCase();
|
|
3348
|
+
return CLOUD_MODELS.find((m) => m.id.toLowerCase() === n);
|
|
3349
|
+
}
|
|
3113
3350
|
function inferAzureBaseModel(deploymentName) {
|
|
3114
3351
|
const n = deploymentName.toLowerCase();
|
|
3115
|
-
|
|
3352
|
+
const compact = compactModelId(n);
|
|
3353
|
+
const hasBareGpt56Alias = compact.includes("gpt5.6");
|
|
3354
|
+
for (const model of AZURE_CATALOG) {
|
|
3355
|
+
if (hasBareGpt56Alias && model.id === "gpt-5") continue;
|
|
3356
|
+
if (n.includes(model.id.toLowerCase()) || compact.includes(compactModelId(model.id))) {
|
|
3357
|
+
return model.id;
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
if (hasBareGpt56Alias) return "gpt-5.6-sol";
|
|
3361
|
+
const gpt5At = compact.indexOf("gpt5");
|
|
3362
|
+
if (gpt5At !== -1) {
|
|
3363
|
+
const suffix = compact.slice(gpt5At + "gpt5".length);
|
|
3364
|
+
if (suffix.includes("nano")) return "gpt-5-nano";
|
|
3365
|
+
if (suffix.includes("mini")) return "gpt-5-mini";
|
|
3366
|
+
return "gpt-5";
|
|
3367
|
+
}
|
|
3368
|
+
if (compact.includes("gpt4.1nano")) return "gpt-4.1-nano";
|
|
3369
|
+
if (compact.includes("gpt4.1mini")) return "gpt-4.1-mini";
|
|
3370
|
+
if (compact.includes("gpt4.1")) return "gpt-4.1";
|
|
3371
|
+
if (compact.includes("gpt4omini")) return "gpt-4o-mini";
|
|
3372
|
+
if (compact.includes("gpt4o")) return "gpt-4o";
|
|
3116
3373
|
return null;
|
|
3117
3374
|
}
|
|
3375
|
+
function catalogModelInfo(baseModelId) {
|
|
3376
|
+
const entry = catalogEntry(baseModelId);
|
|
3377
|
+
if (!entry?.contextWindow) return void 0;
|
|
3378
|
+
return {
|
|
3379
|
+
id: entry.id,
|
|
3380
|
+
name: entry.name,
|
|
3381
|
+
provider: "openai",
|
|
3382
|
+
contextWindow: entry.contextWindow,
|
|
3383
|
+
isVisionCapable: entry.vision ?? false,
|
|
3384
|
+
inputCostPer1kTokens: 0,
|
|
3385
|
+
outputCostPer1kTokens: 0,
|
|
3386
|
+
maxOutputTokens: entry.maxOutputTokens ?? 16e3,
|
|
3387
|
+
supportsStreaming: true,
|
|
3388
|
+
isLocal: false,
|
|
3389
|
+
supportsToolUse: entry.toolUse ?? true,
|
|
3390
|
+
pricingUnknown: true
|
|
3391
|
+
};
|
|
3392
|
+
}
|
|
3118
3393
|
function azureModelForDeployment(cfg) {
|
|
3119
3394
|
if (cfg.type !== "azure" || !cfg.deploymentName?.trim()) return null;
|
|
3120
3395
|
const id = cfg.deploymentName.trim();
|
|
3121
3396
|
const name = cfg.label?.trim() || id;
|
|
3122
3397
|
const baseModelId = cfg.model?.trim() || inferAzureBaseModel(id) || void 0;
|
|
3123
|
-
const base = baseModelId ? MODELS[baseModelId] : void 0;
|
|
3124
|
-
if (base) {
|
|
3398
|
+
const base = baseModelId ? MODELS[baseModelId] ?? catalogModelInfo(baseModelId) : void 0;
|
|
3399
|
+
if (base && baseModelId) {
|
|
3125
3400
|
const azurePrice = resolvePricing(
|
|
3126
3401
|
{ id, provider: "azure", isLocal: false, baseModelId },
|
|
3127
3402
|
{ region: cfg.region }
|
|
3128
3403
|
);
|
|
3404
|
+
const exactAzurePrice = !azurePrice.unknown && !azurePrice.estimatedFromProvider;
|
|
3405
|
+
const nativeToolsOnThisTransport = /^gpt-5\.6-(?:sol|terra|luna)$/i.test(baseModelId) ? false : base.supportsToolUse ?? true;
|
|
3129
3406
|
return {
|
|
3130
3407
|
...base,
|
|
3131
3408
|
id,
|
|
3132
|
-
// callable deployment name
|
|
3133
3409
|
name,
|
|
3134
3410
|
provider: "azure",
|
|
3135
3411
|
baseModelId,
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
...azurePrice.unknown ? {} : {
|
|
3412
|
+
supportsToolUse: nativeToolsOnThisTransport,
|
|
3413
|
+
...!azurePrice.unknown ? {
|
|
3139
3414
|
inputCostPer1kTokens: azurePrice.input,
|
|
3140
3415
|
outputCostPer1kTokens: azurePrice.output,
|
|
3141
|
-
pricingUnknown:
|
|
3142
|
-
}
|
|
3416
|
+
pricingUnknown: !exactAzurePrice
|
|
3417
|
+
} : { pricingUnknown: true }
|
|
3143
3418
|
};
|
|
3144
3419
|
}
|
|
3145
3420
|
return {
|
|
@@ -3154,39 +3429,34 @@ function azureModelForDeployment(cfg) {
|
|
|
3154
3429
|
maxOutputTokens: 16e3,
|
|
3155
3430
|
supportsStreaming: true,
|
|
3156
3431
|
isLocal: false,
|
|
3157
|
-
supportsToolUse: true
|
|
3432
|
+
supportsToolUse: true,
|
|
3433
|
+
pricingUnknown: true
|
|
3158
3434
|
};
|
|
3159
3435
|
}
|
|
3160
|
-
|
|
3436
|
+
function stripTrailingSlashes3(value) {
|
|
3437
|
+
let end = value.length;
|
|
3438
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) end--;
|
|
3439
|
+
return value.slice(0, end);
|
|
3440
|
+
}
|
|
3441
|
+
var DEFAULT_AZURE_API_VERSION, CLOUD_MODELS, AZURE_CATALOG, AZURE_BASE_MODELS, AzureOpenAIProvider;
|
|
3161
3442
|
var init_azure = __esm({
|
|
3162
3443
|
"src/providers/azure.ts"() {
|
|
3163
3444
|
init_constants();
|
|
3164
3445
|
init_openai();
|
|
3165
3446
|
init_pricing();
|
|
3447
|
+
init_cloud_model_catalog();
|
|
3166
3448
|
DEFAULT_AZURE_API_VERSION = "2024-12-01-preview";
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
[/gpt-?5\.4/, "gpt-5.4"],
|
|
3171
|
-
[/gpt-?5.*nano/, "gpt-5-nano"],
|
|
3172
|
-
[/gpt-?5.*mini/, "gpt-5-mini"],
|
|
3173
|
-
[/gpt-?5/, "gpt-5"],
|
|
3174
|
-
[/gpt-?4\.1-nano/, "gpt-4.1-nano"],
|
|
3175
|
-
[/gpt-?4\.1-mini/, "gpt-4.1-mini"],
|
|
3176
|
-
[/gpt-?4\.1/, "gpt-4.1"],
|
|
3177
|
-
[/gpt-?4o-mini/, "gpt-4o-mini"],
|
|
3178
|
-
[/gpt-?4o/, "gpt-4o"]
|
|
3179
|
-
];
|
|
3180
|
-
AZURE_BASE_MODELS = AZURE_BASE_MODEL_RULES.map(([, id]) => id);
|
|
3449
|
+
CLOUD_MODELS = cloud_model_catalog_default.models;
|
|
3450
|
+
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));
|
|
3451
|
+
AZURE_BASE_MODELS = AZURE_CATALOG.map((m) => m.id);
|
|
3181
3452
|
AzureOpenAIProvider = class extends OpenAIProvider {
|
|
3182
3453
|
constructor(config, model) {
|
|
3183
3454
|
const rawUrl = config.baseUrl ?? AZURE_BASE_URL_TEMPLATE.replace("{resource}", "YOUR_RESOURCE");
|
|
3184
|
-
const endpoint = rawUrl
|
|
3455
|
+
const endpoint = stripTrailingSlashes3(rawUrl);
|
|
3185
3456
|
super(
|
|
3186
3457
|
{
|
|
3187
3458
|
...config,
|
|
3188
3459
|
baseUrl: endpoint
|
|
3189
|
-
// Kept for superclass compatibility if it reads it
|
|
3190
3460
|
},
|
|
3191
3461
|
model
|
|
3192
3462
|
);
|
|
@@ -4170,16 +4440,16 @@ var require_isarray = __commonJS({
|
|
|
4170
4440
|
}
|
|
4171
4441
|
});
|
|
4172
4442
|
|
|
4173
|
-
// node_modules/
|
|
4443
|
+
// node_modules/readable-stream/lib/internal/streams/stream.js
|
|
4174
4444
|
var require_stream = __commonJS({
|
|
4175
|
-
"node_modules/
|
|
4445
|
+
"node_modules/readable-stream/lib/internal/streams/stream.js"(exports, module) {
|
|
4176
4446
|
module.exports = __require("stream");
|
|
4177
4447
|
}
|
|
4178
4448
|
});
|
|
4179
4449
|
|
|
4180
|
-
// node_modules/
|
|
4450
|
+
// node_modules/readable-stream/node_modules/safe-buffer/index.js
|
|
4181
4451
|
var require_safe_buffer = __commonJS({
|
|
4182
|
-
"node_modules/
|
|
4452
|
+
"node_modules/readable-stream/node_modules/safe-buffer/index.js"(exports, module) {
|
|
4183
4453
|
var buffer = __require("buffer");
|
|
4184
4454
|
var Buffer2 = buffer.Buffer;
|
|
4185
4455
|
function copyProps(src, dst) {
|
|
@@ -4297,7 +4567,7 @@ var require_util = __commonJS({
|
|
|
4297
4567
|
typeof arg === "undefined";
|
|
4298
4568
|
}
|
|
4299
4569
|
exports.isPrimitive = isPrimitive;
|
|
4300
|
-
exports.isBuffer = Buffer.isBuffer;
|
|
4570
|
+
exports.isBuffer = __require("buffer").Buffer.isBuffer;
|
|
4301
4571
|
function objectToString(o) {
|
|
4302
4572
|
return Object.prototype.toString.call(o);
|
|
4303
4573
|
}
|
|
@@ -4350,9 +4620,9 @@ var require_inherits = __commonJS({
|
|
|
4350
4620
|
}
|
|
4351
4621
|
});
|
|
4352
4622
|
|
|
4353
|
-
// node_modules/
|
|
4623
|
+
// node_modules/readable-stream/lib/internal/streams/BufferList.js
|
|
4354
4624
|
var require_BufferList = __commonJS({
|
|
4355
|
-
"node_modules/
|
|
4625
|
+
"node_modules/readable-stream/lib/internal/streams/BufferList.js"(exports, module) {
|
|
4356
4626
|
function _classCallCheck(instance, Constructor) {
|
|
4357
4627
|
if (!(instance instanceof Constructor)) {
|
|
4358
4628
|
throw new TypeError("Cannot call a class as a function");
|
|
@@ -4427,9 +4697,9 @@ var require_BufferList = __commonJS({
|
|
|
4427
4697
|
}
|
|
4428
4698
|
});
|
|
4429
4699
|
|
|
4430
|
-
// node_modules/
|
|
4700
|
+
// node_modules/readable-stream/lib/internal/streams/destroy.js
|
|
4431
4701
|
var require_destroy = __commonJS({
|
|
4432
|
-
"node_modules/
|
|
4702
|
+
"node_modules/readable-stream/lib/internal/streams/destroy.js"(exports, module) {
|
|
4433
4703
|
var pna = require_process_nextick_args();
|
|
4434
4704
|
function destroy(err, cb) {
|
|
4435
4705
|
var _this = this;
|
|
@@ -4502,9 +4772,9 @@ var require_node = __commonJS({
|
|
|
4502
4772
|
}
|
|
4503
4773
|
});
|
|
4504
4774
|
|
|
4505
|
-
// node_modules/
|
|
4775
|
+
// node_modules/readable-stream/lib/_stream_writable.js
|
|
4506
4776
|
var require_stream_writable = __commonJS({
|
|
4507
|
-
"node_modules/
|
|
4777
|
+
"node_modules/readable-stream/lib/_stream_writable.js"(exports, module) {
|
|
4508
4778
|
var pna = require_process_nextick_args();
|
|
4509
4779
|
module.exports = Writable;
|
|
4510
4780
|
function CorkedRequest(state) {
|
|
@@ -4941,9 +5211,9 @@ var require_stream_writable = __commonJS({
|
|
|
4941
5211
|
}
|
|
4942
5212
|
});
|
|
4943
5213
|
|
|
4944
|
-
// node_modules/
|
|
5214
|
+
// node_modules/readable-stream/lib/_stream_duplex.js
|
|
4945
5215
|
var require_stream_duplex = __commonJS({
|
|
4946
|
-
"node_modules/
|
|
5216
|
+
"node_modules/readable-stream/lib/_stream_duplex.js"(exports, module) {
|
|
4947
5217
|
var pna = require_process_nextick_args();
|
|
4948
5218
|
var objectKeys = Object.keys || function(obj) {
|
|
4949
5219
|
var keys2 = [];
|
|
@@ -5017,10 +5287,67 @@ var require_stream_duplex = __commonJS({
|
|
|
5017
5287
|
}
|
|
5018
5288
|
});
|
|
5019
5289
|
|
|
5020
|
-
// node_modules/
|
|
5290
|
+
// node_modules/string_decoder/node_modules/safe-buffer/index.js
|
|
5291
|
+
var require_safe_buffer2 = __commonJS({
|
|
5292
|
+
"node_modules/string_decoder/node_modules/safe-buffer/index.js"(exports, module) {
|
|
5293
|
+
var buffer = __require("buffer");
|
|
5294
|
+
var Buffer2 = buffer.Buffer;
|
|
5295
|
+
function copyProps(src, dst) {
|
|
5296
|
+
for (var key in src) {
|
|
5297
|
+
dst[key] = src[key];
|
|
5298
|
+
}
|
|
5299
|
+
}
|
|
5300
|
+
if (Buffer2.from && Buffer2.alloc && Buffer2.allocUnsafe && Buffer2.allocUnsafeSlow) {
|
|
5301
|
+
module.exports = buffer;
|
|
5302
|
+
} else {
|
|
5303
|
+
copyProps(buffer, exports);
|
|
5304
|
+
exports.Buffer = SafeBuffer;
|
|
5305
|
+
}
|
|
5306
|
+
function SafeBuffer(arg, encodingOrOffset, length) {
|
|
5307
|
+
return Buffer2(arg, encodingOrOffset, length);
|
|
5308
|
+
}
|
|
5309
|
+
copyProps(Buffer2, SafeBuffer);
|
|
5310
|
+
SafeBuffer.from = function(arg, encodingOrOffset, length) {
|
|
5311
|
+
if (typeof arg === "number") {
|
|
5312
|
+
throw new TypeError("Argument must not be a number");
|
|
5313
|
+
}
|
|
5314
|
+
return Buffer2(arg, encodingOrOffset, length);
|
|
5315
|
+
};
|
|
5316
|
+
SafeBuffer.alloc = function(size, fill, encoding) {
|
|
5317
|
+
if (typeof size !== "number") {
|
|
5318
|
+
throw new TypeError("Argument must be a number");
|
|
5319
|
+
}
|
|
5320
|
+
var buf = Buffer2(size);
|
|
5321
|
+
if (fill !== void 0) {
|
|
5322
|
+
if (typeof encoding === "string") {
|
|
5323
|
+
buf.fill(fill, encoding);
|
|
5324
|
+
} else {
|
|
5325
|
+
buf.fill(fill);
|
|
5326
|
+
}
|
|
5327
|
+
} else {
|
|
5328
|
+
buf.fill(0);
|
|
5329
|
+
}
|
|
5330
|
+
return buf;
|
|
5331
|
+
};
|
|
5332
|
+
SafeBuffer.allocUnsafe = function(size) {
|
|
5333
|
+
if (typeof size !== "number") {
|
|
5334
|
+
throw new TypeError("Argument must be a number");
|
|
5335
|
+
}
|
|
5336
|
+
return Buffer2(size);
|
|
5337
|
+
};
|
|
5338
|
+
SafeBuffer.allocUnsafeSlow = function(size) {
|
|
5339
|
+
if (typeof size !== "number") {
|
|
5340
|
+
throw new TypeError("Argument must be a number");
|
|
5341
|
+
}
|
|
5342
|
+
return buffer.SlowBuffer(size);
|
|
5343
|
+
};
|
|
5344
|
+
}
|
|
5345
|
+
});
|
|
5346
|
+
|
|
5347
|
+
// node_modules/string_decoder/lib/string_decoder.js
|
|
5021
5348
|
var require_string_decoder = __commonJS({
|
|
5022
|
-
"node_modules/
|
|
5023
|
-
var Buffer2 =
|
|
5349
|
+
"node_modules/string_decoder/lib/string_decoder.js"(exports) {
|
|
5350
|
+
var Buffer2 = require_safe_buffer2().Buffer;
|
|
5024
5351
|
var isEncoding = Buffer2.isEncoding || function(encoding) {
|
|
5025
5352
|
encoding = "" + encoding;
|
|
5026
5353
|
switch (encoding && encoding.toLowerCase()) {
|
|
@@ -5254,9 +5581,9 @@ var require_string_decoder = __commonJS({
|
|
|
5254
5581
|
}
|
|
5255
5582
|
});
|
|
5256
5583
|
|
|
5257
|
-
// node_modules/
|
|
5584
|
+
// node_modules/readable-stream/lib/_stream_readable.js
|
|
5258
5585
|
var require_stream_readable = __commonJS({
|
|
5259
|
-
"node_modules/
|
|
5586
|
+
"node_modules/readable-stream/lib/_stream_readable.js"(exports, module) {
|
|
5260
5587
|
var pna = require_process_nextick_args();
|
|
5261
5588
|
module.exports = Readable2;
|
|
5262
5589
|
var isArray = require_isarray();
|
|
@@ -5939,9 +6266,9 @@ var require_stream_readable = __commonJS({
|
|
|
5939
6266
|
}
|
|
5940
6267
|
});
|
|
5941
6268
|
|
|
5942
|
-
// node_modules/
|
|
6269
|
+
// node_modules/readable-stream/lib/_stream_transform.js
|
|
5943
6270
|
var require_stream_transform = __commonJS({
|
|
5944
|
-
"node_modules/
|
|
6271
|
+
"node_modules/readable-stream/lib/_stream_transform.js"(exports, module) {
|
|
5945
6272
|
module.exports = Transform;
|
|
5946
6273
|
var Duplex = require_stream_duplex();
|
|
5947
6274
|
var util = Object.create(require_util());
|
|
@@ -6038,9 +6365,9 @@ var require_stream_transform = __commonJS({
|
|
|
6038
6365
|
}
|
|
6039
6366
|
});
|
|
6040
6367
|
|
|
6041
|
-
// node_modules/
|
|
6368
|
+
// node_modules/readable-stream/lib/_stream_passthrough.js
|
|
6042
6369
|
var require_stream_passthrough = __commonJS({
|
|
6043
|
-
"node_modules/
|
|
6370
|
+
"node_modules/readable-stream/lib/_stream_passthrough.js"(exports, module) {
|
|
6044
6371
|
module.exports = PassThrough;
|
|
6045
6372
|
var Transform = require_stream_transform();
|
|
6046
6373
|
var util = Object.create(require_util());
|
|
@@ -6056,9 +6383,9 @@ var require_stream_passthrough = __commonJS({
|
|
|
6056
6383
|
}
|
|
6057
6384
|
});
|
|
6058
6385
|
|
|
6059
|
-
// node_modules/
|
|
6386
|
+
// node_modules/readable-stream/readable.js
|
|
6060
6387
|
var require_readable = __commonJS({
|
|
6061
|
-
"node_modules/
|
|
6388
|
+
"node_modules/readable-stream/readable.js"(exports, module) {
|
|
6062
6389
|
var Stream = __require("stream");
|
|
6063
6390
|
if (process.env.READABLE_STREAM === "disable" && Stream) {
|
|
6064
6391
|
module.exports = Stream;
|
|
@@ -6967,8 +7294,8 @@ var require_utils = __commonJS({
|
|
|
6967
7294
|
var result = transform[inputType][outputType](input);
|
|
6968
7295
|
return result;
|
|
6969
7296
|
};
|
|
6970
|
-
exports.resolve = function(
|
|
6971
|
-
var parts =
|
|
7297
|
+
exports.resolve = function(path41) {
|
|
7298
|
+
var parts = path41.split("/");
|
|
6972
7299
|
var result = [];
|
|
6973
7300
|
for (var index = 0; index < parts.length; index++) {
|
|
6974
7301
|
var part = parts[index];
|
|
@@ -12783,18 +13110,18 @@ var require_object = __commonJS({
|
|
|
12783
13110
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
12784
13111
|
this.files[name] = object;
|
|
12785
13112
|
};
|
|
12786
|
-
var parentFolder = function(
|
|
12787
|
-
if (
|
|
12788
|
-
|
|
13113
|
+
var parentFolder = function(path41) {
|
|
13114
|
+
if (path41.slice(-1) === "/") {
|
|
13115
|
+
path41 = path41.substring(0, path41.length - 1);
|
|
12789
13116
|
}
|
|
12790
|
-
var lastSlash =
|
|
12791
|
-
return lastSlash > 0 ?
|
|
13117
|
+
var lastSlash = path41.lastIndexOf("/");
|
|
13118
|
+
return lastSlash > 0 ? path41.substring(0, lastSlash) : "";
|
|
12792
13119
|
};
|
|
12793
|
-
var forceTrailingSlash = function(
|
|
12794
|
-
if (
|
|
12795
|
-
|
|
13120
|
+
var forceTrailingSlash = function(path41) {
|
|
13121
|
+
if (path41.slice(-1) !== "/") {
|
|
13122
|
+
path41 += "/";
|
|
12796
13123
|
}
|
|
12797
|
-
return
|
|
13124
|
+
return path41;
|
|
12798
13125
|
};
|
|
12799
13126
|
var folderAdd = function(name, createFolders) {
|
|
12800
13127
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -13793,12 +14120,12 @@ var init_audit_logger = __esm({
|
|
|
13793
14120
|
constructor(workspacePath, debugMode = false) {
|
|
13794
14121
|
this.workspacePath = workspacePath;
|
|
13795
14122
|
this.debugMode = debugMode;
|
|
13796
|
-
const cascadeDir =
|
|
13797
|
-
if (!
|
|
13798
|
-
|
|
14123
|
+
const cascadeDir = path36.join(workspacePath, ".cascade");
|
|
14124
|
+
if (!fs33.existsSync(cascadeDir)) {
|
|
14125
|
+
fs33.mkdirSync(cascadeDir, { recursive: true });
|
|
13799
14126
|
}
|
|
13800
|
-
this.keyPath =
|
|
13801
|
-
this.dbPath =
|
|
14127
|
+
this.keyPath = path36.join(cascadeDir, "audit_log.key");
|
|
14128
|
+
this.dbPath = path36.join(cascadeDir, "audit_log.db");
|
|
13802
14129
|
this.initEncryptionKey();
|
|
13803
14130
|
this.db = new Database2(this.dbPath);
|
|
13804
14131
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -13828,11 +14155,11 @@ var init_audit_logger = __esm({
|
|
|
13828
14155
|
return crypto.createHash("sha256").update(`${prevHash}|${timestamp}|${eventType}|${tierId}|${encryptedPayload}`).digest("hex");
|
|
13829
14156
|
}
|
|
13830
14157
|
initEncryptionKey() {
|
|
13831
|
-
if (
|
|
13832
|
-
this.encryptionKey =
|
|
14158
|
+
if (fs33.existsSync(this.keyPath)) {
|
|
14159
|
+
this.encryptionKey = fs33.readFileSync(this.keyPath);
|
|
13833
14160
|
} else {
|
|
13834
14161
|
this.encryptionKey = crypto.randomBytes(32);
|
|
13835
|
-
|
|
14162
|
+
fs33.writeFileSync(this.keyPath, this.encryptionKey);
|
|
13836
14163
|
}
|
|
13837
14164
|
}
|
|
13838
14165
|
encrypt(text) {
|
|
@@ -13910,9 +14237,9 @@ var init_audit_logger = __esm({
|
|
|
13910
14237
|
dumpDebugIfNeeded() {
|
|
13911
14238
|
if (!this.debugMode) return;
|
|
13912
14239
|
try {
|
|
13913
|
-
const dumpPath =
|
|
14240
|
+
const dumpPath = path36.join(os10.tmpdir(), "cascade_audit_logs_debug.json");
|
|
13914
14241
|
const entries = this.getAllLogs();
|
|
13915
|
-
|
|
14242
|
+
fs33.writeFileSync(dumpPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
13916
14243
|
} catch (err) {
|
|
13917
14244
|
console.error("Failed to dump debug audit logs", err);
|
|
13918
14245
|
}
|
|
@@ -13967,7 +14294,7 @@ var Keystore = class {
|
|
|
13967
14294
|
const creds = await this.keytar.findCredentials(KEYTAR_SERVICE);
|
|
13968
14295
|
this.cache = Object.fromEntries(creds.map((c) => [c.account, c.password]));
|
|
13969
14296
|
this.backend = "keytar";
|
|
13970
|
-
if (password &&
|
|
14297
|
+
if (password && fs33.existsSync(this.storePath)) {
|
|
13971
14298
|
try {
|
|
13972
14299
|
const fileEntries = this.decryptFile(password);
|
|
13973
14300
|
for (const [k, v] of Object.entries(fileEntries)) {
|
|
@@ -13986,7 +14313,7 @@ var Keystore = class {
|
|
|
13986
14313
|
"Keystore unlock requires a password because the OS keychain (keytar) is not available on this system."
|
|
13987
14314
|
);
|
|
13988
14315
|
}
|
|
13989
|
-
if (!
|
|
14316
|
+
if (!fs33.existsSync(this.storePath)) {
|
|
13990
14317
|
const salt = crypto.randomBytes(SALT_LEN);
|
|
13991
14318
|
this.masterKey = this.deriveKey(password, salt);
|
|
13992
14319
|
this.writeWithSalt({}, salt);
|
|
@@ -14000,7 +14327,7 @@ var Keystore = class {
|
|
|
14000
14327
|
}
|
|
14001
14328
|
/** Synchronous legacy unlock kept for AES-only environments. */
|
|
14002
14329
|
unlockSync(password) {
|
|
14003
|
-
if (!
|
|
14330
|
+
if (!fs33.existsSync(this.storePath)) {
|
|
14004
14331
|
const salt = crypto.randomBytes(SALT_LEN);
|
|
14005
14332
|
this.masterKey = this.deriveKey(password, salt);
|
|
14006
14333
|
this.writeWithSalt({}, salt);
|
|
@@ -14058,7 +14385,7 @@ var Keystore = class {
|
|
|
14058
14385
|
}
|
|
14059
14386
|
}
|
|
14060
14387
|
decryptFile(password, knownSalt) {
|
|
14061
|
-
if (!
|
|
14388
|
+
if (!fs33.existsSync(this.storePath)) return {};
|
|
14062
14389
|
try {
|
|
14063
14390
|
const { salt, ciphertext, iv, tag } = this.readRaw();
|
|
14064
14391
|
const useSalt = knownSalt ?? salt;
|
|
@@ -14080,8 +14407,8 @@ var Keystore = class {
|
|
|
14080
14407
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
14081
14408
|
const tag = cipher.getAuthTag();
|
|
14082
14409
|
const out = Buffer.concat([raw.salt, iv, tag, ciphertext]);
|
|
14083
|
-
|
|
14084
|
-
|
|
14410
|
+
fs33.mkdirSync(path36.dirname(this.storePath), { recursive: true });
|
|
14411
|
+
fs33.writeFileSync(this.storePath, out, { mode: 384 });
|
|
14085
14412
|
}
|
|
14086
14413
|
writeWithSalt(data, salt) {
|
|
14087
14414
|
if (!this.masterKey) throw new Error("writeWithSalt called before masterKey was set");
|
|
@@ -14091,11 +14418,11 @@ var Keystore = class {
|
|
|
14091
14418
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
14092
14419
|
const tag = cipher.getAuthTag();
|
|
14093
14420
|
const out = Buffer.concat([salt, iv, tag, ciphertext]);
|
|
14094
|
-
|
|
14095
|
-
|
|
14421
|
+
fs33.mkdirSync(path36.dirname(this.storePath), { recursive: true });
|
|
14422
|
+
fs33.writeFileSync(this.storePath, out, { mode: 384 });
|
|
14096
14423
|
}
|
|
14097
14424
|
readRaw() {
|
|
14098
|
-
const buf =
|
|
14425
|
+
const buf = fs33.readFileSync(this.storePath);
|
|
14099
14426
|
let offset = 0;
|
|
14100
14427
|
const salt = buf.subarray(offset, offset + SALT_LEN);
|
|
14101
14428
|
offset += SALT_LEN;
|
|
@@ -14128,7 +14455,7 @@ var CascadeIgnore = class {
|
|
|
14128
14455
|
]);
|
|
14129
14456
|
}
|
|
14130
14457
|
async load(workspacePath) {
|
|
14131
|
-
const filePath =
|
|
14458
|
+
const filePath = path36.join(workspacePath, ".cascadeignore");
|
|
14132
14459
|
try {
|
|
14133
14460
|
const content = await fs11.readFile(filePath, "utf-8");
|
|
14134
14461
|
const lines = content.split("\n").filter((l) => l.trim() && !l.startsWith("#"));
|
|
@@ -14139,7 +14466,7 @@ var CascadeIgnore = class {
|
|
|
14139
14466
|
}
|
|
14140
14467
|
isIgnored(filePath, workspacePath) {
|
|
14141
14468
|
try {
|
|
14142
|
-
const relative = workspacePath ?
|
|
14469
|
+
const relative = workspacePath ? path36.relative(workspacePath, filePath) : filePath;
|
|
14143
14470
|
return this.ig.ignores(relative);
|
|
14144
14471
|
} catch {
|
|
14145
14472
|
return false;
|
|
@@ -14150,7 +14477,7 @@ var CascadeIgnore = class {
|
|
|
14150
14477
|
}
|
|
14151
14478
|
};
|
|
14152
14479
|
async function createDefaultIgnoreFile(workspacePath) {
|
|
14153
|
-
const filePath =
|
|
14480
|
+
const filePath = path36.join(workspacePath, ".cascadeignore");
|
|
14154
14481
|
const content = `# .cascadeignore \u2014 Files Cascade agents cannot read or modify
|
|
14155
14482
|
# Syntax identical to .gitignore
|
|
14156
14483
|
|
|
@@ -14180,7 +14507,7 @@ Thumbs.db
|
|
|
14180
14507
|
await fs11.writeFile(filePath, content, "utf-8");
|
|
14181
14508
|
}
|
|
14182
14509
|
async function loadCascadeMd(workspacePath) {
|
|
14183
|
-
const filePath =
|
|
14510
|
+
const filePath = path36.join(workspacePath, "CASCADE.md");
|
|
14184
14511
|
try {
|
|
14185
14512
|
const raw = await fs11.readFile(filePath, "utf-8");
|
|
14186
14513
|
return parseCascadeMd(raw);
|
|
@@ -14209,7 +14536,7 @@ ${raw.trim()}`;
|
|
|
14209
14536
|
return { raw, sections, systemPrompt };
|
|
14210
14537
|
}
|
|
14211
14538
|
async function createDefaultCascadeMd(workspacePath) {
|
|
14212
|
-
const filePath =
|
|
14539
|
+
const filePath = path36.join(workspacePath, "CASCADE.md");
|
|
14213
14540
|
const content = `# Cascade Project Instructions
|
|
14214
14541
|
|
|
14215
14542
|
This file contains project-specific instructions for the Cascade AI agent.
|
|
@@ -14244,7 +14571,7 @@ List any areas the agent should not touch.
|
|
|
14244
14571
|
var MemoryStore = class _MemoryStore {
|
|
14245
14572
|
db;
|
|
14246
14573
|
constructor(dbPath) {
|
|
14247
|
-
|
|
14574
|
+
fs33.mkdirSync(path36.dirname(dbPath), { recursive: true });
|
|
14248
14575
|
try {
|
|
14249
14576
|
this.db = new Database2(dbPath, { timeout: 5e3 });
|
|
14250
14577
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -15142,7 +15469,18 @@ var WebSearchConfigSchema = z.object({
|
|
|
15142
15469
|
/** Tavily API key — get one at https://tavily.com */
|
|
15143
15470
|
tavilyApiKey: z.string().optional(),
|
|
15144
15471
|
/** Max results per search (default 5) */
|
|
15145
|
-
maxResults: z.number().default(5)
|
|
15472
|
+
maxResults: z.number().default(5),
|
|
15473
|
+
/**
|
|
15474
|
+
* Send `searxngUrl` through the SSRF guard. Off for a local run, where the
|
|
15475
|
+
* URL is the machine owner's own config and a self-hosted SearXNG is
|
|
15476
|
+
* routinely on a private address; on for a host that accepts it from a
|
|
15477
|
+
* request. See `src/tools/web-search.ts`.
|
|
15478
|
+
*
|
|
15479
|
+
* It has to be named HERE, not just on the TypeScript interfaces: the config
|
|
15480
|
+
* passes through `CascadeConfigSchema.parse()` on its way into a run, and
|
|
15481
|
+
* zod drops every key this object does not declare.
|
|
15482
|
+
*/
|
|
15483
|
+
guardSearxngUrl: z.boolean().optional()
|
|
15146
15484
|
});
|
|
15147
15485
|
var ToolsConfigSchema = z.object({
|
|
15148
15486
|
shellAllowlist: z.array(z.string()).default([]),
|
|
@@ -15551,7 +15889,7 @@ function credentialEndpointsConflict(type, rowEndpoint, credentialEndpoint) {
|
|
|
15551
15889
|
|
|
15552
15890
|
// src/config/global-credentials.ts
|
|
15553
15891
|
function credentialsPath(globalDir2) {
|
|
15554
|
-
return
|
|
15892
|
+
return path36.join(globalDir2, GLOBAL_CREDENTIALS_FILE);
|
|
15555
15893
|
}
|
|
15556
15894
|
function providerKey(p) {
|
|
15557
15895
|
return p.type;
|
|
@@ -15581,7 +15919,7 @@ function isPersistable(p) {
|
|
|
15581
15919
|
}
|
|
15582
15920
|
function loadGlobalCredentials(globalDir2) {
|
|
15583
15921
|
try {
|
|
15584
|
-
const raw =
|
|
15922
|
+
const raw = fs33.readFileSync(credentialsPath(globalDir2), "utf-8");
|
|
15585
15923
|
const parsed = JSON.parse(raw);
|
|
15586
15924
|
if (!Array.isArray(parsed.providers)) return [];
|
|
15587
15925
|
return parsed.providers.filter(
|
|
@@ -15593,13 +15931,13 @@ function loadGlobalCredentials(globalDir2) {
|
|
|
15593
15931
|
}
|
|
15594
15932
|
function saveGlobalCredentials(globalDir2, providers) {
|
|
15595
15933
|
const filePath = credentialsPath(globalDir2);
|
|
15596
|
-
|
|
15934
|
+
fs33.mkdirSync(globalDir2, { recursive: true, mode: 448 });
|
|
15597
15935
|
const body = { version: 1, providers: providers.filter(isPersistable) };
|
|
15598
15936
|
const tmp = `${filePath}.tmp`;
|
|
15599
|
-
|
|
15600
|
-
|
|
15937
|
+
fs33.writeFileSync(tmp, JSON.stringify(body, null, 2), { encoding: "utf-8", mode: 384 });
|
|
15938
|
+
fs33.renameSync(tmp, filePath);
|
|
15601
15939
|
try {
|
|
15602
|
-
|
|
15940
|
+
fs33.chmodSync(filePath, 384);
|
|
15603
15941
|
} catch {
|
|
15604
15942
|
}
|
|
15605
15943
|
}
|
|
@@ -16004,7 +16342,7 @@ var ConfigManager = class {
|
|
|
16004
16342
|
/** `globalDirOverride` exists for tests — never point it at the real home dir there. */
|
|
16005
16343
|
constructor(workspacePath = process.cwd(), globalDirOverride) {
|
|
16006
16344
|
this.workspacePath = workspacePath;
|
|
16007
|
-
this.globalDir = globalDirOverride ??
|
|
16345
|
+
this.globalDir = globalDirOverride ?? path36.join(os10.homedir(), GLOBAL_CONFIG_DIR);
|
|
16008
16346
|
}
|
|
16009
16347
|
async load() {
|
|
16010
16348
|
this.config = await this.loadConfig();
|
|
@@ -16018,8 +16356,8 @@ var ConfigManager = class {
|
|
|
16018
16356
|
this.ignore = new CascadeIgnore();
|
|
16019
16357
|
await this.ignore.load(this.workspacePath);
|
|
16020
16358
|
this.cascadeMd = await loadCascadeMd(this.workspacePath);
|
|
16021
|
-
this.keystore = new Keystore(
|
|
16022
|
-
this.store = new MemoryStore(
|
|
16359
|
+
this.keystore = new Keystore(path36.join(this.globalDir, GLOBAL_KEYSTORE_FILE));
|
|
16360
|
+
this.store = new MemoryStore(path36.join(this.workspacePath, CASCADE_DB_FILE));
|
|
16023
16361
|
const globalRevoked = stripRevokedCredentials(loadGlobalCredentials(this.globalDir));
|
|
16024
16362
|
const globalCreds = filterRetiredCredentials(globalRevoked.kept);
|
|
16025
16363
|
if (globalRevoked.removed > 0) this.revokedCredentials += globalRevoked.removed;
|
|
@@ -16092,8 +16430,8 @@ var ConfigManager = class {
|
|
|
16092
16430
|
* never reached the disk (see `commitSettings`).
|
|
16093
16431
|
*/
|
|
16094
16432
|
async save(config = this.config) {
|
|
16095
|
-
const configPath =
|
|
16096
|
-
await fs11.mkdir(
|
|
16433
|
+
const configPath = path36.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
16434
|
+
await fs11.mkdir(path36.dirname(configPath), { recursive: true });
|
|
16097
16435
|
await fs11.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
16098
16436
|
try {
|
|
16099
16437
|
saveGlobalCredentials(this.globalDir, config.providers);
|
|
@@ -16143,7 +16481,7 @@ var ConfigManager = class {
|
|
|
16143
16481
|
this.revokedCredentials = 0;
|
|
16144
16482
|
this.revokedPins = [];
|
|
16145
16483
|
this.revokedNotice = void 0;
|
|
16146
|
-
const configPath =
|
|
16484
|
+
const configPath = path36.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
16147
16485
|
try {
|
|
16148
16486
|
const raw = await fs11.readFile(configPath, "utf-8");
|
|
16149
16487
|
const parsed = JSON.parse(raw);
|
|
@@ -16237,7 +16575,7 @@ var ConfigManager = class {
|
|
|
16237
16575
|
return onResource;
|
|
16238
16576
|
}
|
|
16239
16577
|
async persistClearedPins(tiers) {
|
|
16240
|
-
const configPath =
|
|
16578
|
+
const configPath = path36.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
16241
16579
|
try {
|
|
16242
16580
|
const raw = JSON.parse(await fs11.readFile(configPath, "utf-8"));
|
|
16243
16581
|
const models = raw["models"];
|
|
@@ -17961,7 +18299,7 @@ init_pricing();
|
|
|
17961
18299
|
var DEFAULT_SNAPSHOT_URL = "https://raw.githubusercontent.com/Varun-SV/Cascade-AI/main/src/core/router/benchmark-data.json";
|
|
17962
18300
|
var OPENROUTER_MODELS_URL = "https://openrouter.ai/api/v1/models";
|
|
17963
18301
|
var FETCH_TIMEOUT_MS = 8e3;
|
|
17964
|
-
var DEFAULT_CACHE_FILE =
|
|
18302
|
+
var DEFAULT_CACHE_FILE = path36.join(os10.homedir(), GLOBAL_CONFIG_DIR, "benchmarks-cache.json");
|
|
17965
18303
|
function normalizeModelId2(id) {
|
|
17966
18304
|
let s = id.toLowerCase();
|
|
17967
18305
|
const slash = s.lastIndexOf("/");
|
|
@@ -18108,7 +18446,7 @@ var LiveDataProvider = class {
|
|
|
18108
18446
|
}
|
|
18109
18447
|
async saveCache() {
|
|
18110
18448
|
try {
|
|
18111
|
-
await fs11.mkdir(
|
|
18449
|
+
await fs11.mkdir(path36.dirname(this.opts.cacheFile), { recursive: true });
|
|
18112
18450
|
const cache = {
|
|
18113
18451
|
fetchedAt: this.fetchedAt,
|
|
18114
18452
|
snapshot: this.snapshot ?? void 0,
|
|
@@ -18215,9 +18553,15 @@ var FAMILY_BENCHMARKS = {
|
|
|
18215
18553
|
"claude-opus": { code: 95, analysis: 92, creative: 90, data: 88 },
|
|
18216
18554
|
"claude-sonnet": { code: 93, analysis: 88, creative: 87, data: 85 },
|
|
18217
18555
|
"claude-haiku": { code: 80, analysis: 75, creative: 76, data: 72 },
|
|
18218
|
-
// OpenAI GPT-5 family
|
|
18219
|
-
//
|
|
18220
|
-
//
|
|
18556
|
+
// OpenAI GPT-5 family. GPT-5.6 is split by durable capability tier instead
|
|
18557
|
+
// of being folded into generic gpt-5: Sol, Terra and Luna have materially
|
|
18558
|
+
// different benchmark/cost envelopes and should compete independently.
|
|
18559
|
+
// Scores are the committed normalized snapshot; provenance is in
|
|
18560
|
+
// scripts/benchmarks/sources/openai-gpt-5.6-2026-08.json.
|
|
18561
|
+
"gpt-5.6-sol": { code: 100, analysis: 98, creative: 88, data: 88 },
|
|
18562
|
+
"gpt-5.6-terra": { code: 97, analysis: 92, creative: 82, data: 85 },
|
|
18563
|
+
"gpt-5.6-luna": { code: 93, analysis: 85, creative: 74, data: 60 },
|
|
18564
|
+
// Older GPT-5 point releases remain distinct where public data supports it.
|
|
18221
18565
|
"gpt-5.5": { code: 97, analysis: 96, creative: 94, data: 95 },
|
|
18222
18566
|
"gpt-5.4": { code: 94, analysis: 94, creative: 92, data: 92 },
|
|
18223
18567
|
"gpt-5.4-mini": { code: 86, analysis: 85, creative: 85, data: 83 },
|
|
@@ -18253,13 +18597,19 @@ var FAMILY_BENCHMARKS = {
|
|
|
18253
18597
|
"llama-small": { code: 55, analysis: 56, creative: 60, data: 54 }
|
|
18254
18598
|
};
|
|
18255
18599
|
var FAMILY_MATCHERS = [
|
|
18600
|
+
[/fable/i, "claude-opus"],
|
|
18256
18601
|
[/opus/i, "claude-opus"],
|
|
18257
18602
|
[/sonnet/i, "claude-sonnet"],
|
|
18258
18603
|
[/haiku/i, "claude-haiku"],
|
|
18259
|
-
// GPT-5 family — ordered most-specific first.
|
|
18260
|
-
//
|
|
18261
|
-
//
|
|
18604
|
+
// GPT-5 family — ordered most-specific first. GPT-5.6 durable tiers carry
|
|
18605
|
+
// their own profiles. 5.4 Nano intentionally maps to the nano class rather
|
|
18606
|
+
// than being swallowed by the generic 5.4 rule.
|
|
18607
|
+
[/gpt-?5\.6.*sol/i, "gpt-5.6-sol"],
|
|
18608
|
+
[/gpt-?5\.6.*terra/i, "gpt-5.6-terra"],
|
|
18609
|
+
[/gpt-?5\.6.*luna/i, "gpt-5.6-luna"],
|
|
18610
|
+
[/gpt-?5\.6(?:\s|$)/i, "gpt-5.6-sol"],
|
|
18262
18611
|
[/gpt-?5\.5/i, "gpt-5.5"],
|
|
18612
|
+
[/gpt-?5\.4.*nano/i, "gpt-5-nano"],
|
|
18263
18613
|
[/gpt-?5\.4.*mini/i, "gpt-5.4-mini"],
|
|
18264
18614
|
[/gpt-?5\.4/i, "gpt-5.4"],
|
|
18265
18615
|
[/gpt-?5.*nano/i, "gpt-5-nano"],
|
|
@@ -21319,8 +21669,8 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : "") + textToolSuffix,
|
|
|
21319
21669
|
// Media generation can run for a minute; without this a cancelled run
|
|
21320
21670
|
// still pays for an image nobody will see.
|
|
21321
21671
|
...this.signal ? { signal: this.signal } : {},
|
|
21322
|
-
saveSnapshot: async (
|
|
21323
|
-
this.store?.addFileSnapshot(this.taskId,
|
|
21672
|
+
saveSnapshot: async (path41, content) => {
|
|
21673
|
+
this.store?.addFileSnapshot(this.taskId, path41, content);
|
|
21324
21674
|
},
|
|
21325
21675
|
sendPeerSync: (to, syncType, content) => {
|
|
21326
21676
|
this.peerBus?.send(this.id, to, syncType, this.assignment?.subtaskId ?? "", content);
|
|
@@ -21523,7 +21873,7 @@ ${assignment.expectedOutput}`;
|
|
|
21523
21873
|
const { promisify: promisify4 } = await import('util');
|
|
21524
21874
|
const execFileAsync2 = promisify4(execFile3);
|
|
21525
21875
|
for (const artifactPath of artifactPaths) {
|
|
21526
|
-
const absolutePath =
|
|
21876
|
+
const absolutePath = path36.resolve(this.artifactRoot(), artifactPath);
|
|
21527
21877
|
try {
|
|
21528
21878
|
const stat = await fs11.stat(absolutePath);
|
|
21529
21879
|
if (!stat.isFile()) {
|
|
@@ -21558,7 +21908,7 @@ ${assignment.expectedOutput}`;
|
|
|
21558
21908
|
issues.push(`PDF artifact looks too small to be valid: ${artifactPath}`);
|
|
21559
21909
|
continue;
|
|
21560
21910
|
}
|
|
21561
|
-
const ext =
|
|
21911
|
+
const ext = path36.extname(absolutePath).toLowerCase();
|
|
21562
21912
|
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;
|
|
21563
21913
|
if (check) {
|
|
21564
21914
|
try {
|
|
@@ -21650,7 +22000,7 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
|
|
|
21650
22000
|
async checkAcceptance(assignment) {
|
|
21651
22001
|
const criteria = assignment.acceptance ?? [];
|
|
21652
22002
|
if (!criteria.length) return [];
|
|
21653
|
-
const resolve2 = (target) =>
|
|
22003
|
+
const resolve2 = (target) => path36.resolve(this.artifactRoot(), target);
|
|
21654
22004
|
const workerCanWriteFiles = canProduceFiles(this.tools.map((t) => t.name));
|
|
21655
22005
|
return evaluateAcceptance(criteria, assignment.files ?? [], {
|
|
21656
22006
|
stat: async (target) => {
|
|
@@ -24961,16 +25311,16 @@ function resolveInWorkspace(workspaceRoot, input) {
|
|
|
24961
25311
|
if (typeof input !== "string" || input.length === 0) {
|
|
24962
25312
|
throw new WorkspaceSandboxError(String(input), workspaceRoot);
|
|
24963
25313
|
}
|
|
24964
|
-
const root =
|
|
24965
|
-
const abs =
|
|
24966
|
-
const rel =
|
|
24967
|
-
if (rel === "" || rel === ".") ; else if (rel.startsWith("..") ||
|
|
25314
|
+
const root = path36.resolve(workspaceRoot);
|
|
25315
|
+
const abs = path36.isAbsolute(input) ? path36.resolve(input) : path36.resolve(root, input);
|
|
25316
|
+
const rel = path36.relative(root, abs);
|
|
25317
|
+
if (rel === "" || rel === ".") ; else if (rel.startsWith("..") || path36.isAbsolute(rel)) {
|
|
24968
25318
|
throw new WorkspaceSandboxError(input, root);
|
|
24969
25319
|
}
|
|
24970
25320
|
try {
|
|
24971
|
-
const real =
|
|
24972
|
-
const realRel =
|
|
24973
|
-
if (realRel !== "" && realRel !== "." && (realRel.startsWith("..") ||
|
|
25321
|
+
const real = fs33.realpathSync(abs);
|
|
25322
|
+
const realRel = path36.relative(root, real);
|
|
25323
|
+
if (realRel !== "" && realRel !== "." && (realRel.startsWith("..") || path36.isAbsolute(realRel))) {
|
|
24974
25324
|
throw new WorkspaceSandboxError(input, root);
|
|
24975
25325
|
}
|
|
24976
25326
|
} catch (e) {
|
|
@@ -25519,9 +25869,9 @@ async function animatePptx(bytes, scheme) {
|
|
|
25519
25869
|
const zip = await import_jszip.default.loadAsync(bytes);
|
|
25520
25870
|
const slidePaths = Object.keys(zip.files).filter((n) => /^ppt\/slides\/slide\d+\.xml$/.test(n));
|
|
25521
25871
|
if (slidePaths.length === 0) return bytes;
|
|
25522
|
-
for (const
|
|
25523
|
-
const xml = await zip.file(
|
|
25524
|
-
zip.file(
|
|
25872
|
+
for (const path41 of slidePaths) {
|
|
25873
|
+
const xml = await zip.file(path41).async("string");
|
|
25874
|
+
zip.file(path41, animateSlideXml(xml, scheme));
|
|
25525
25875
|
}
|
|
25526
25876
|
return await zip.generateAsync({ type: "uint8array", compression: "DEFLATE" });
|
|
25527
25877
|
} catch {
|
|
@@ -25902,7 +26252,7 @@ var GenerateDocumentTool = class extends BaseTool {
|
|
|
25902
26252
|
}
|
|
25903
26253
|
}
|
|
25904
26254
|
const bytes = await renderDocument(ext, content, { name: filePath, loadImageBytes });
|
|
25905
|
-
await fs11.mkdir(
|
|
26255
|
+
await fs11.mkdir(path36.dirname(absPath), { recursive: true });
|
|
25906
26256
|
await fs11.writeFile(absPath, bytes);
|
|
25907
26257
|
const charts = countCharts(content);
|
|
25908
26258
|
return [
|
|
@@ -26123,7 +26473,7 @@ var FileWriteTool = class extends BaseTool {
|
|
|
26123
26473
|
} catch {
|
|
26124
26474
|
}
|
|
26125
26475
|
}
|
|
26126
|
-
await fs11.mkdir(
|
|
26476
|
+
await fs11.mkdir(path36.dirname(absPath), { recursive: true });
|
|
26127
26477
|
await fs11.writeFile(absPath, content, "utf-8");
|
|
26128
26478
|
return `Written ${content.length} characters to ${filePath}`;
|
|
26129
26479
|
}
|
|
@@ -26481,12 +26831,10 @@ ${data.description}`;
|
|
|
26481
26831
|
}
|
|
26482
26832
|
}
|
|
26483
26833
|
};
|
|
26484
|
-
|
|
26485
|
-
// src/tools/browser.ts
|
|
26486
26834
|
var BROWSER_LAUNCH_TIMEOUT_MS = 15e3;
|
|
26487
26835
|
var BrowserTool = class extends BaseTool {
|
|
26488
26836
|
name = "browser";
|
|
26489
|
-
description = "Control a browser: navigate to URLs, click elements, fill forms, take screenshots.
|
|
26837
|
+
description = "Control a browser: navigate to URLs, click elements, fill forms, take screenshots. Screenshots are saved to a file for image_analyze to read.";
|
|
26490
26838
|
inputSchema = {
|
|
26491
26839
|
type: "object",
|
|
26492
26840
|
properties: {
|
|
@@ -26553,7 +26901,14 @@ var BrowserTool = class extends BaseTool {
|
|
|
26553
26901
|
}
|
|
26554
26902
|
case "screenshot": {
|
|
26555
26903
|
const buf = await page2.screenshot({ type: "png" });
|
|
26556
|
-
|
|
26904
|
+
const rel = path36.join(".cascade", "screenshots", `screenshot-${Date.now()}-${randomUUID().slice(0, 8)}.png`);
|
|
26905
|
+
const abs = resolveInWorkspace(this.workspaceRoot, rel);
|
|
26906
|
+
await fs11.mkdir(path36.dirname(abs), { recursive: true });
|
|
26907
|
+
await fs11.writeFile(abs, buf);
|
|
26908
|
+
return [
|
|
26909
|
+
`Screenshot saved to ${abs} (${Math.round(buf.byteLength / 1024)} KB).`,
|
|
26910
|
+
`Call image_analyze with that path to see what is on it \u2014 that needs a vision-capable model.`
|
|
26911
|
+
].join(" ");
|
|
26557
26912
|
}
|
|
26558
26913
|
case "evaluate": {
|
|
26559
26914
|
const result = await page2.evaluate(input["script"]);
|
|
@@ -26621,7 +26976,7 @@ var ImageAnalyzeTool = class extends BaseTool {
|
|
|
26621
26976
|
};
|
|
26622
26977
|
async function fileToImageAttachment(filePath) {
|
|
26623
26978
|
const data = await fs11.readFile(filePath);
|
|
26624
|
-
const ext =
|
|
26979
|
+
const ext = path36.extname(filePath).toLowerCase();
|
|
26625
26980
|
const mimeMap = {
|
|
26626
26981
|
".jpg": "image/jpeg",
|
|
26627
26982
|
".jpeg": "image/jpeg",
|
|
@@ -26655,14 +27010,14 @@ var PDFCreateTool = class extends BaseTool {
|
|
|
26655
27010
|
const filePath = input["path"];
|
|
26656
27011
|
const content = input["content"];
|
|
26657
27012
|
const title = input["title"];
|
|
26658
|
-
const dir =
|
|
26659
|
-
if (!
|
|
26660
|
-
|
|
27013
|
+
const dir = path36.dirname(filePath);
|
|
27014
|
+
if (!fs33.existsSync(dir)) {
|
|
27015
|
+
fs33.mkdirSync(dir, { recursive: true });
|
|
26661
27016
|
}
|
|
26662
27017
|
return new Promise((resolve2, reject) => {
|
|
26663
27018
|
try {
|
|
26664
27019
|
const doc = new PDFDocument({ margin: 50 });
|
|
26665
|
-
const stream =
|
|
27020
|
+
const stream = fs33.createWriteStream(filePath);
|
|
26666
27021
|
doc.pipe(stream);
|
|
26667
27022
|
if (title) {
|
|
26668
27023
|
doc.info["Title"] = title;
|
|
@@ -26740,22 +27095,22 @@ var CodeInterpreterTool = class extends BaseTool {
|
|
|
26740
27095
|
}
|
|
26741
27096
|
cmdPrefix = NODE_CMD;
|
|
26742
27097
|
}
|
|
26743
|
-
const tmpDir =
|
|
26744
|
-
if (!
|
|
26745
|
-
|
|
27098
|
+
const tmpDir = path36.join(this.workspaceRoot, ".cascade", "tmp");
|
|
27099
|
+
if (!fs33.existsSync(tmpDir)) {
|
|
27100
|
+
fs33.mkdirSync(tmpDir, { recursive: true });
|
|
26746
27101
|
}
|
|
26747
27102
|
const extension = language === "python" ? "py" : "js";
|
|
26748
27103
|
const fileName = `intp_${randomUUID().slice(0, 8)}.${extension}`;
|
|
26749
|
-
const filePath =
|
|
26750
|
-
|
|
27104
|
+
const filePath = path36.join(tmpDir, fileName);
|
|
27105
|
+
fs33.writeFileSync(filePath, code, "utf-8");
|
|
26751
27106
|
const execArgs = [filePath, ...args];
|
|
26752
27107
|
return new Promise((resolve2) => {
|
|
26753
27108
|
const startMs = Date.now();
|
|
26754
27109
|
execFile(cmdPrefix, execArgs, { cwd: this.workspaceRoot, timeout: 3e4 }, (error, stdout, stderr) => {
|
|
26755
27110
|
const duration = Date.now() - startMs;
|
|
26756
27111
|
try {
|
|
26757
|
-
if (
|
|
26758
|
-
|
|
27112
|
+
if (fs33.existsSync(filePath)) {
|
|
27113
|
+
fs33.unlinkSync(filePath);
|
|
26759
27114
|
}
|
|
26760
27115
|
} catch (cleanupErr) {
|
|
26761
27116
|
console.error(`Failed to cleanup interpreter script ${filePath}:`, cleanupErr);
|
|
@@ -26835,18 +27190,178 @@ ${formatted}`;
|
|
|
26835
27190
|
return `Unknown action: ${action}`;
|
|
26836
27191
|
}
|
|
26837
27192
|
};
|
|
27193
|
+
var SsrfBlockedError = class extends Error {
|
|
27194
|
+
constructor(message) {
|
|
27195
|
+
super(message);
|
|
27196
|
+
this.name = "SsrfBlockedError";
|
|
27197
|
+
}
|
|
27198
|
+
};
|
|
27199
|
+
var ALLOWED_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
27200
|
+
var MAX_REDIRECTS2 = 5;
|
|
27201
|
+
function allowLocal() {
|
|
27202
|
+
return process.env["CASCADE_ALLOW_LOCAL_FETCH"] === "1";
|
|
27203
|
+
}
|
|
27204
|
+
function isPrivateAddress(ip) {
|
|
27205
|
+
const type = net.isIP(ip);
|
|
27206
|
+
if (type === 4) return isPrivateIPv4(ip);
|
|
27207
|
+
if (type === 6) return isPrivateIPv6(ip);
|
|
27208
|
+
return true;
|
|
27209
|
+
}
|
|
27210
|
+
function isPrivateIPv4(ip) {
|
|
27211
|
+
const parts = ip.split(".").map((p) => Number(p));
|
|
27212
|
+
if (parts.length !== 4 || parts.some((p) => Number.isNaN(p) || p < 0 || p > 255)) return true;
|
|
27213
|
+
const [a, b] = parts;
|
|
27214
|
+
if (a === 0) return true;
|
|
27215
|
+
if (a === 10) return true;
|
|
27216
|
+
if (a === 127) return true;
|
|
27217
|
+
if (a === 169 && b === 254) return true;
|
|
27218
|
+
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
27219
|
+
if (a === 192 && b === 168) return true;
|
|
27220
|
+
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
27221
|
+
if (a >= 224) return true;
|
|
27222
|
+
return false;
|
|
27223
|
+
}
|
|
27224
|
+
function ipv6Groups(ip) {
|
|
27225
|
+
let s = ip.toLowerCase().replace(/^\[|\]$/g, "");
|
|
27226
|
+
const zone = s.indexOf("%");
|
|
27227
|
+
if (zone !== -1) s = s.slice(0, zone);
|
|
27228
|
+
const dotted = /^(.*:)(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(s);
|
|
27229
|
+
if (dotted) {
|
|
27230
|
+
const o = [dotted[2], dotted[3], dotted[4], dotted[5]].map((p) => Number(p));
|
|
27231
|
+
if (o.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return null;
|
|
27232
|
+
s = `${dotted[1]}${(o[0] << 8 | o[1]).toString(16)}:${(o[2] << 8 | o[3]).toString(16)}`;
|
|
27233
|
+
}
|
|
27234
|
+
const halves = s.split("::");
|
|
27235
|
+
if (halves.length > 2) return null;
|
|
27236
|
+
const split = (part) => part ? part.split(":") : [];
|
|
27237
|
+
const head = split(halves[0] ?? "");
|
|
27238
|
+
const tail = halves.length === 2 ? split(halves[1] ?? "") : [];
|
|
27239
|
+
const zeros = halves.length === 2 ? 8 - head.length - tail.length : 0;
|
|
27240
|
+
if (zeros < 0) return null;
|
|
27241
|
+
const groups = [...head, ...Array(zeros).fill("0"), ...tail];
|
|
27242
|
+
if (groups.length !== 8) return null;
|
|
27243
|
+
const out = [];
|
|
27244
|
+
for (const g of groups) {
|
|
27245
|
+
if (!/^[0-9a-f]{1,4}$/.test(g)) return null;
|
|
27246
|
+
out.push(parseInt(g, 16));
|
|
27247
|
+
}
|
|
27248
|
+
return out;
|
|
27249
|
+
}
|
|
27250
|
+
function embeddedIPv4(g) {
|
|
27251
|
+
const quad = (hi, lo) => `${hi >> 8}.${hi & 255}.${lo >> 8}.${lo & 255}`;
|
|
27252
|
+
const leadingZero = (n) => g.slice(0, n).every((x) => x === 0);
|
|
27253
|
+
if (leadingZero(5) && g[5] === 65535) return quad(g[6], g[7]);
|
|
27254
|
+
if (leadingZero(6)) return quad(g[6], g[7]);
|
|
27255
|
+
if (g[0] === 100 && g[1] === 65435) {
|
|
27256
|
+
if (g[2] === 1) {
|
|
27257
|
+
return quad(g[3], (g[4] & 255) << 8 | g[5] >> 8);
|
|
27258
|
+
}
|
|
27259
|
+
if (g[2] === 0 && g[3] === 0 && g[4] === 0 && g[5] === 0) return quad(g[6], g[7]);
|
|
27260
|
+
return null;
|
|
27261
|
+
}
|
|
27262
|
+
if (g[0] === 8194) return quad(g[1], g[2]);
|
|
27263
|
+
return null;
|
|
27264
|
+
}
|
|
27265
|
+
function isPrivateIPv6(ip) {
|
|
27266
|
+
const g = ipv6Groups(ip);
|
|
27267
|
+
if (!g) return true;
|
|
27268
|
+
const v4 = embeddedIPv4(g);
|
|
27269
|
+
if (v4) return isPrivateIPv4(v4);
|
|
27270
|
+
if (g[0] === 100 && g[1] === 65435) return true;
|
|
27271
|
+
if (g.every((x) => x === 0)) return true;
|
|
27272
|
+
if (leading7Zero(g) && g[7] === 1) return true;
|
|
27273
|
+
if ((g[0] & 65472) === 65152) return true;
|
|
27274
|
+
if ((g[0] & 65024) === 64512) return true;
|
|
27275
|
+
if ((g[0] & 65280) === 65280) return true;
|
|
27276
|
+
return false;
|
|
27277
|
+
}
|
|
27278
|
+
function leading7Zero(g) {
|
|
27279
|
+
return g.slice(0, 7).every((x) => x === 0);
|
|
27280
|
+
}
|
|
27281
|
+
async function assertPublicUrl(rawUrl) {
|
|
27282
|
+
let url;
|
|
27283
|
+
try {
|
|
27284
|
+
url = new URL(rawUrl);
|
|
27285
|
+
} catch {
|
|
27286
|
+
throw new SsrfBlockedError(`Invalid URL: ${rawUrl}`);
|
|
27287
|
+
}
|
|
27288
|
+
if (!ALLOWED_PROTOCOLS.has(url.protocol)) {
|
|
27289
|
+
throw new SsrfBlockedError(`Blocked URL scheme "${url.protocol}" \u2014 only http and https are allowed.`);
|
|
27290
|
+
}
|
|
27291
|
+
if (allowLocal()) return url;
|
|
27292
|
+
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
27293
|
+
if (net.isIP(host)) {
|
|
27294
|
+
if (isPrivateAddress(host)) {
|
|
27295
|
+
throw new SsrfBlockedError(`Blocked request to non-public address ${host}.`);
|
|
27296
|
+
}
|
|
27297
|
+
return url;
|
|
27298
|
+
}
|
|
27299
|
+
if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) {
|
|
27300
|
+
throw new SsrfBlockedError(`Blocked request to local hostname "${host}".`);
|
|
27301
|
+
}
|
|
27302
|
+
let addresses;
|
|
27303
|
+
try {
|
|
27304
|
+
const records = await dns2.lookup(host, { all: true });
|
|
27305
|
+
addresses = records.map((r) => r.address);
|
|
27306
|
+
} catch {
|
|
27307
|
+
throw new SsrfBlockedError(`Could not resolve host "${host}".`);
|
|
27308
|
+
}
|
|
27309
|
+
if (addresses.length === 0 || addresses.some((addr) => isPrivateAddress(addr))) {
|
|
27310
|
+
throw new SsrfBlockedError(`Blocked request to "${host}" \u2014 resolves to a non-public address.`);
|
|
27311
|
+
}
|
|
27312
|
+
return url;
|
|
27313
|
+
}
|
|
27314
|
+
var ssrfAgent = new Agent({
|
|
27315
|
+
connect: {
|
|
27316
|
+
lookup(hostname, options, callback) {
|
|
27317
|
+
if (allowLocal()) {
|
|
27318
|
+
dnsCallback.lookup(hostname, options, callback);
|
|
27319
|
+
return;
|
|
27320
|
+
}
|
|
27321
|
+
dnsCallback.lookup(hostname, { ...options, all: true }, (err, addresses) => {
|
|
27322
|
+
if (err) return callback(err, "", 0);
|
|
27323
|
+
const list = Array.isArray(addresses) ? addresses : [addresses];
|
|
27324
|
+
const bad = list.find((a) => isPrivateAddress(a.address));
|
|
27325
|
+
if (bad) {
|
|
27326
|
+
return callback(
|
|
27327
|
+
new SsrfBlockedError(`Blocked connection to "${hostname}" \u2014 resolved to non-public address ${bad.address}.`),
|
|
27328
|
+
"",
|
|
27329
|
+
0
|
|
27330
|
+
);
|
|
27331
|
+
}
|
|
27332
|
+
if (options.all) return callback(null, list);
|
|
27333
|
+
const first = list[0];
|
|
27334
|
+
return callback(null, first.address, first.family);
|
|
27335
|
+
});
|
|
27336
|
+
}
|
|
27337
|
+
}
|
|
27338
|
+
});
|
|
27339
|
+
async function safeFetch(rawUrl, init = {}) {
|
|
27340
|
+
let currentUrl = (await assertPublicUrl(rawUrl)).toString();
|
|
27341
|
+
for (let i = 0; i <= MAX_REDIRECTS2; i++) {
|
|
27342
|
+
const resp = await fetch(currentUrl, { ...init, redirect: "manual", dispatcher: ssrfAgent });
|
|
27343
|
+
if (resp.status < 300 || resp.status >= 400) return resp;
|
|
27344
|
+
const location = resp.headers.get("location");
|
|
27345
|
+
if (!location) return resp;
|
|
27346
|
+
const next = new URL(location, currentUrl);
|
|
27347
|
+
await assertPublicUrl(next.toString());
|
|
27348
|
+
currentUrl = next.toString();
|
|
27349
|
+
}
|
|
27350
|
+
throw new SsrfBlockedError(`Too many redirects (>${MAX_REDIRECTS2}).`);
|
|
27351
|
+
}
|
|
26838
27352
|
|
|
26839
27353
|
// src/tools/web-search.ts
|
|
26840
|
-
async function searchSearXNG(query, baseUrl, maxResults) {
|
|
27354
|
+
async function searchSearXNG(query, baseUrl, maxResults, guardUrl = false) {
|
|
26841
27355
|
const url = new URL("/search", baseUrl);
|
|
26842
27356
|
url.searchParams.set("q", query);
|
|
26843
27357
|
url.searchParams.set("format", "json");
|
|
26844
27358
|
url.searchParams.set("categories", "general");
|
|
26845
27359
|
url.searchParams.set("engines", "google,bing,duckduckgo");
|
|
26846
|
-
const
|
|
27360
|
+
const init = {
|
|
26847
27361
|
headers: { "User-Agent": "Cascade-AI/1.0 WebSearchTool" },
|
|
26848
27362
|
signal: AbortSignal.timeout(1e4)
|
|
26849
|
-
}
|
|
27363
|
+
};
|
|
27364
|
+
const resp = guardUrl ? await safeFetch(url.toString(), init) : await fetch(url.toString(), init);
|
|
26850
27365
|
if (!resp.ok) {
|
|
26851
27366
|
throw new Error(`SearXNG returned HTTP ${resp.status}`);
|
|
26852
27367
|
}
|
|
@@ -26975,7 +27490,11 @@ var WebSearchTool = class extends BaseTool {
|
|
|
26975
27490
|
searxngUrl: config.searxngUrl ?? process.env["SEARXNG_URL"],
|
|
26976
27491
|
braveApiKey: config.braveApiKey ?? process.env["BRAVE_SEARCH_API_KEY"],
|
|
26977
27492
|
tavilyApiKey: config.tavilyApiKey ?? process.env["TAVILY_API_KEY"],
|
|
26978
|
-
maxResults: config.maxResults ?? 5
|
|
27493
|
+
maxResults: config.maxResults ?? 5,
|
|
27494
|
+
// Note this reads only from `config`, never from the environment: the
|
|
27495
|
+
// guard tracks the trustworthiness of the URL the host passed in, and an
|
|
27496
|
+
// env var says nothing about that.
|
|
27497
|
+
guardSearxngUrl: config.guardSearxngUrl ?? false
|
|
26979
27498
|
};
|
|
26980
27499
|
}
|
|
26981
27500
|
async execute(input, _options) {
|
|
@@ -26990,7 +27509,7 @@ var WebSearchTool = class extends BaseTool {
|
|
|
26990
27509
|
let anyBackendReachable = false;
|
|
26991
27510
|
if (this.config.searxngUrl) {
|
|
26992
27511
|
try {
|
|
26993
|
-
results = await searchSearXNG(query, this.config.searxngUrl, maxResults);
|
|
27512
|
+
results = await searchSearXNG(query, this.config.searxngUrl, maxResults, this.config.guardSearxngUrl);
|
|
26994
27513
|
anyBackendReachable = true;
|
|
26995
27514
|
if (results.length > 0) return this.formatResults(query, results);
|
|
26996
27515
|
errors.push("SearXNG: returned 0 results");
|
|
@@ -27067,7 +27586,7 @@ var GlobTool = class extends BaseTool {
|
|
|
27067
27586
|
};
|
|
27068
27587
|
async execute(input, _options) {
|
|
27069
27588
|
const pattern = input["pattern"];
|
|
27070
|
-
const searchPath = input["path"] ?
|
|
27589
|
+
const searchPath = input["path"] ? path36.resolve(this.workspaceRoot, input["path"]) : this.workspaceRoot;
|
|
27071
27590
|
const matches = await glob(pattern, {
|
|
27072
27591
|
cwd: searchPath,
|
|
27073
27592
|
ignore: ["node_modules/**", ".git/**", "dist/**", "build/**"],
|
|
@@ -27080,7 +27599,7 @@ var GlobTool = class extends BaseTool {
|
|
|
27080
27599
|
const withMtime = await Promise.all(
|
|
27081
27600
|
matches.map(async (rel) => {
|
|
27082
27601
|
try {
|
|
27083
|
-
const stat = await fs11.stat(
|
|
27602
|
+
const stat = await fs11.stat(path36.join(searchPath, rel));
|
|
27084
27603
|
return { rel, mtime: stat.mtimeMs };
|
|
27085
27604
|
} catch {
|
|
27086
27605
|
return { rel, mtime: 0 };
|
|
@@ -27129,7 +27648,7 @@ var GrepTool = class extends BaseTool {
|
|
|
27129
27648
|
};
|
|
27130
27649
|
async execute(input, _options) {
|
|
27131
27650
|
const pattern = input["pattern"];
|
|
27132
|
-
const searchPath = input["path"] ?
|
|
27651
|
+
const searchPath = input["path"] ? path36.resolve(this.workspaceRoot, input["path"]) : this.workspaceRoot;
|
|
27133
27652
|
const globPattern = input["glob"];
|
|
27134
27653
|
const outputMode = input["output_mode"] ?? "content";
|
|
27135
27654
|
const context = input["context"] ?? 0;
|
|
@@ -27183,12 +27702,12 @@ var GrepTool = class extends BaseTool {
|
|
|
27183
27702
|
nodir: true
|
|
27184
27703
|
});
|
|
27185
27704
|
} catch {
|
|
27186
|
-
files = [
|
|
27705
|
+
files = [path36.relative(searchPath, searchPath) || "."];
|
|
27187
27706
|
}
|
|
27188
27707
|
const results = [];
|
|
27189
27708
|
let totalCount = 0;
|
|
27190
27709
|
for (const rel of files) {
|
|
27191
|
-
const abs =
|
|
27710
|
+
const abs = path36.join(searchPath, rel);
|
|
27192
27711
|
let content;
|
|
27193
27712
|
try {
|
|
27194
27713
|
content = await fs11.readFile(abs, "utf-8");
|
|
@@ -27229,92 +27748,6 @@ Total: ${totalCount} matches`);
|
|
|
27229
27748
|
return results.join("\n");
|
|
27230
27749
|
}
|
|
27231
27750
|
};
|
|
27232
|
-
var SsrfBlockedError = class extends Error {
|
|
27233
|
-
constructor(message) {
|
|
27234
|
-
super(message);
|
|
27235
|
-
this.name = "SsrfBlockedError";
|
|
27236
|
-
}
|
|
27237
|
-
};
|
|
27238
|
-
var ALLOWED_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
27239
|
-
var MAX_REDIRECTS2 = 5;
|
|
27240
|
-
function allowLocal() {
|
|
27241
|
-
return process.env["CASCADE_ALLOW_LOCAL_FETCH"] === "1";
|
|
27242
|
-
}
|
|
27243
|
-
function isPrivateAddress(ip) {
|
|
27244
|
-
const type = net.isIP(ip);
|
|
27245
|
-
if (type === 4) return isPrivateIPv4(ip);
|
|
27246
|
-
if (type === 6) return isPrivateIPv6(ip);
|
|
27247
|
-
return true;
|
|
27248
|
-
}
|
|
27249
|
-
function isPrivateIPv4(ip) {
|
|
27250
|
-
const parts = ip.split(".").map((p) => Number(p));
|
|
27251
|
-
if (parts.length !== 4 || parts.some((p) => Number.isNaN(p) || p < 0 || p > 255)) return true;
|
|
27252
|
-
const [a, b] = parts;
|
|
27253
|
-
if (a === 0) return true;
|
|
27254
|
-
if (a === 10) return true;
|
|
27255
|
-
if (a === 127) return true;
|
|
27256
|
-
if (a === 169 && b === 254) return true;
|
|
27257
|
-
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
27258
|
-
if (a === 192 && b === 168) return true;
|
|
27259
|
-
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
27260
|
-
if (a >= 224) return true;
|
|
27261
|
-
return false;
|
|
27262
|
-
}
|
|
27263
|
-
function isPrivateIPv6(ip) {
|
|
27264
|
-
const lower = ip.toLowerCase().replace(/^\[|\]$/g, "");
|
|
27265
|
-
if (lower === "::1" || lower === "::") return true;
|
|
27266
|
-
if (lower.startsWith("fe80")) return true;
|
|
27267
|
-
if (lower.startsWith("fc") || lower.startsWith("fd")) return true;
|
|
27268
|
-
const mapped = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(lower);
|
|
27269
|
-
if (mapped) return isPrivateIPv4(mapped[1]);
|
|
27270
|
-
return false;
|
|
27271
|
-
}
|
|
27272
|
-
async function assertPublicUrl(rawUrl) {
|
|
27273
|
-
let url;
|
|
27274
|
-
try {
|
|
27275
|
-
url = new URL(rawUrl);
|
|
27276
|
-
} catch {
|
|
27277
|
-
throw new SsrfBlockedError(`Invalid URL: ${rawUrl}`);
|
|
27278
|
-
}
|
|
27279
|
-
if (!ALLOWED_PROTOCOLS.has(url.protocol)) {
|
|
27280
|
-
throw new SsrfBlockedError(`Blocked URL scheme "${url.protocol}" \u2014 only http and https are allowed.`);
|
|
27281
|
-
}
|
|
27282
|
-
if (allowLocal()) return url;
|
|
27283
|
-
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
27284
|
-
if (net.isIP(host)) {
|
|
27285
|
-
if (isPrivateAddress(host)) {
|
|
27286
|
-
throw new SsrfBlockedError(`Blocked request to non-public address ${host}.`);
|
|
27287
|
-
}
|
|
27288
|
-
return url;
|
|
27289
|
-
}
|
|
27290
|
-
if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) {
|
|
27291
|
-
throw new SsrfBlockedError(`Blocked request to local hostname "${host}".`);
|
|
27292
|
-
}
|
|
27293
|
-
let addresses;
|
|
27294
|
-
try {
|
|
27295
|
-
const records = await dns2.lookup(host, { all: true });
|
|
27296
|
-
addresses = records.map((r) => r.address);
|
|
27297
|
-
} catch {
|
|
27298
|
-
throw new SsrfBlockedError(`Could not resolve host "${host}".`);
|
|
27299
|
-
}
|
|
27300
|
-
if (addresses.length === 0 || addresses.some((addr) => isPrivateAddress(addr))) {
|
|
27301
|
-
throw new SsrfBlockedError(`Blocked request to "${host}" \u2014 resolves to a non-public address.`);
|
|
27302
|
-
}
|
|
27303
|
-
return url;
|
|
27304
|
-
}
|
|
27305
|
-
async function safeFetch(rawUrl, init = {}) {
|
|
27306
|
-
let currentUrl = (await assertPublicUrl(rawUrl)).toString();
|
|
27307
|
-
for (let i = 0; i <= MAX_REDIRECTS2; i++) {
|
|
27308
|
-
const resp = await fetch(currentUrl, { ...init, redirect: "manual" });
|
|
27309
|
-
if (resp.status < 300 || resp.status >= 400) return resp;
|
|
27310
|
-
const location = resp.headers.get("location");
|
|
27311
|
-
if (!location) return resp;
|
|
27312
|
-
const next = new URL(location, currentUrl);
|
|
27313
|
-
await assertPublicUrl(next.toString());
|
|
27314
|
-
currentUrl = next.toString();
|
|
27315
|
-
}
|
|
27316
|
-
throw new SsrfBlockedError(`Too many redirects (>${MAX_REDIRECTS2}).`);
|
|
27317
|
-
}
|
|
27318
27751
|
|
|
27319
27752
|
// src/tools/web-fetch.ts
|
|
27320
27753
|
var MAX_CHARS = 5e4;
|
|
@@ -27587,10 +28020,10 @@ var ToolRegistry = class extends EventEmitter {
|
|
|
27587
28020
|
}
|
|
27588
28021
|
isIgnored(filePath) {
|
|
27589
28022
|
if (!filePath) return false;
|
|
27590
|
-
const abs =
|
|
27591
|
-
const rel =
|
|
27592
|
-
if (!rel || rel.startsWith("..") ||
|
|
27593
|
-
const posixRel = rel.split(
|
|
28023
|
+
const abs = path36.resolve(this.workspaceRoot, filePath);
|
|
28024
|
+
const rel = path36.relative(this.workspaceRoot, abs);
|
|
28025
|
+
if (!rel || rel.startsWith("..") || path36.isAbsolute(rel)) return true;
|
|
28026
|
+
const posixRel = rel.split(path36.sep).join("/");
|
|
27594
28027
|
return this.ignoreMatcher.ignores(posixRel);
|
|
27595
28028
|
}
|
|
27596
28029
|
};
|
|
@@ -27824,22 +28257,22 @@ var FileMcpOAuthStore = class {
|
|
|
27824
28257
|
filePath;
|
|
27825
28258
|
load() {
|
|
27826
28259
|
try {
|
|
27827
|
-
return JSON.parse(
|
|
28260
|
+
return JSON.parse(fs33.readFileSync(this.filePath, "utf-8"));
|
|
27828
28261
|
} catch {
|
|
27829
28262
|
return void 0;
|
|
27830
28263
|
}
|
|
27831
28264
|
}
|
|
27832
28265
|
save(state) {
|
|
27833
|
-
|
|
27834
|
-
|
|
28266
|
+
fs33.mkdirSync(path36.dirname(this.filePath), { recursive: true, mode: 448 });
|
|
28267
|
+
fs33.writeFileSync(this.filePath, JSON.stringify(state, null, 2), { mode: 384 });
|
|
27835
28268
|
try {
|
|
27836
|
-
|
|
28269
|
+
fs33.chmodSync(this.filePath, 384);
|
|
27837
28270
|
} catch {
|
|
27838
28271
|
}
|
|
27839
28272
|
}
|
|
27840
28273
|
clear() {
|
|
27841
28274
|
try {
|
|
27842
|
-
|
|
28275
|
+
fs33.rmSync(this.filePath);
|
|
27843
28276
|
} catch {
|
|
27844
28277
|
}
|
|
27845
28278
|
}
|
|
@@ -28659,7 +29092,7 @@ var TaskAnalyzer = class {
|
|
|
28659
29092
|
|
|
28660
29093
|
// src/core/router/model-performance-tracker.ts
|
|
28661
29094
|
init_pricing();
|
|
28662
|
-
var DEFAULT_STATS_FILE =
|
|
29095
|
+
var DEFAULT_STATS_FILE = path36.join(os10.homedir(), ".cascade", "model-perf.json");
|
|
28663
29096
|
var ModelPerformanceTracker = class _ModelPerformanceTracker {
|
|
28664
29097
|
stats = /* @__PURE__ */ new Map();
|
|
28665
29098
|
featureStats = /* @__PURE__ */ new Map();
|
|
@@ -28699,7 +29132,7 @@ var ModelPerformanceTracker = class _ModelPerformanceTracker {
|
|
|
28699
29132
|
async save() {
|
|
28700
29133
|
if (this.readOnly) return;
|
|
28701
29134
|
try {
|
|
28702
|
-
await fs11.mkdir(
|
|
29135
|
+
await fs11.mkdir(path36.dirname(this.statsFile), { recursive: true });
|
|
28703
29136
|
const modelsObj = {};
|
|
28704
29137
|
const featuresObj = {};
|
|
28705
29138
|
for (const [key, stat] of this.stats) modelsObj[key] = stat;
|
|
@@ -29332,7 +29765,7 @@ Required capability: ${description.slice(0, 300)}`;
|
|
|
29332
29765
|
* any dangerous action, so a silently-reloaded tool can't act without approval. */
|
|
29333
29766
|
async loadPersistedTools() {
|
|
29334
29767
|
if (!this.workspacePath || !this.persistEnabled) return;
|
|
29335
|
-
const file =
|
|
29768
|
+
const file = path36.join(this.workspacePath, ".cascade", DYNAMIC_TOOLS_FILE);
|
|
29336
29769
|
try {
|
|
29337
29770
|
const raw = await fs11.readFile(file, "utf-8");
|
|
29338
29771
|
const specs = JSON.parse(raw);
|
|
@@ -29356,8 +29789,8 @@ Required capability: ${description.slice(0, 300)}`;
|
|
|
29356
29789
|
}
|
|
29357
29790
|
async persist() {
|
|
29358
29791
|
if (!this.workspacePath || !this.persistEnabled) return;
|
|
29359
|
-
const dir =
|
|
29360
|
-
const file =
|
|
29792
|
+
const dir = path36.join(this.workspacePath, ".cascade");
|
|
29793
|
+
const file = path36.join(dir, DYNAMIC_TOOLS_FILE);
|
|
29361
29794
|
try {
|
|
29362
29795
|
await fs11.mkdir(dir, { recursive: true });
|
|
29363
29796
|
await fs11.writeFile(file, JSON.stringify(Array.from(this.specs.values()), null, 2), "utf-8");
|
|
@@ -29377,12 +29810,12 @@ var WorldStateDB = class {
|
|
|
29377
29810
|
constructor(workspacePath, debugMode = false) {
|
|
29378
29811
|
this.workspacePath = workspacePath;
|
|
29379
29812
|
this.debugMode = debugMode;
|
|
29380
|
-
const cascadeDir =
|
|
29381
|
-
if (!
|
|
29382
|
-
|
|
29813
|
+
const cascadeDir = path36.join(workspacePath, ".cascade");
|
|
29814
|
+
if (!fs33.existsSync(cascadeDir)) {
|
|
29815
|
+
fs33.mkdirSync(cascadeDir, { recursive: true });
|
|
29383
29816
|
}
|
|
29384
|
-
this.keyPath =
|
|
29385
|
-
this.dbPath =
|
|
29817
|
+
this.keyPath = path36.join(cascadeDir, "world_state.key");
|
|
29818
|
+
this.dbPath = path36.join(cascadeDir, "world_state.db");
|
|
29386
29819
|
this.initEncryptionKey();
|
|
29387
29820
|
this.db = new Database2(this.dbPath);
|
|
29388
29821
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -29439,11 +29872,11 @@ var WorldStateDB = class {
|
|
|
29439
29872
|
).run(e, r, row.encrypted_value, row.source_worker, row.timestamp, validTo, change);
|
|
29440
29873
|
}
|
|
29441
29874
|
initEncryptionKey() {
|
|
29442
|
-
if (
|
|
29443
|
-
this.encryptionKey =
|
|
29875
|
+
if (fs33.existsSync(this.keyPath)) {
|
|
29876
|
+
this.encryptionKey = fs33.readFileSync(this.keyPath);
|
|
29444
29877
|
} else {
|
|
29445
29878
|
this.encryptionKey = crypto.randomBytes(32);
|
|
29446
|
-
|
|
29879
|
+
fs33.writeFileSync(this.keyPath, this.encryptionKey);
|
|
29447
29880
|
}
|
|
29448
29881
|
}
|
|
29449
29882
|
encrypt(text) {
|
|
@@ -29729,9 +30162,9 @@ var WorldStateDB = class {
|
|
|
29729
30162
|
dumpDebugIfNeeded() {
|
|
29730
30163
|
if (!this.debugMode) return;
|
|
29731
30164
|
try {
|
|
29732
|
-
const dumpPath =
|
|
30165
|
+
const dumpPath = path36.join(os10.tmpdir(), "cascade_world_state_debug.json");
|
|
29733
30166
|
const entries = this.getAllEntries();
|
|
29734
|
-
|
|
30167
|
+
fs33.writeFileSync(dumpPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
29735
30168
|
} catch (err) {
|
|
29736
30169
|
console.error("Failed to dump debug world state", err);
|
|
29737
30170
|
}
|
|
@@ -29788,7 +30221,7 @@ var ResumeStore = class {
|
|
|
29788
30221
|
createdAt: checkpoint.createdAt ?? new Date(timestamp).toISOString()
|
|
29789
30222
|
};
|
|
29790
30223
|
await promises.mkdir(this.dir, { recursive: true });
|
|
29791
|
-
const finalPath =
|
|
30224
|
+
const finalPath = path36.join(this.dir, `${timestamp}-${safeId(record.taskId)}.json`);
|
|
29792
30225
|
const tempPath = `${finalPath}.${process.pid}.tmp`;
|
|
29793
30226
|
await promises.writeFile(tempPath, JSON.stringify(record, null, 2), "utf-8");
|
|
29794
30227
|
await promises.rename(tempPath, finalPath);
|
|
@@ -29811,7 +30244,7 @@ var ResumeStore = class {
|
|
|
29811
30244
|
const checkpoints = [];
|
|
29812
30245
|
for (const candidate of candidates2) {
|
|
29813
30246
|
try {
|
|
29814
|
-
const raw = await promises.readFile(
|
|
30247
|
+
const raw = await promises.readFile(path36.join(this.dir, candidate.name), "utf-8");
|
|
29815
30248
|
const parsed = JSON.parse(raw);
|
|
29816
30249
|
if (isCheckpoint(parsed)) checkpoints.push(parsed);
|
|
29817
30250
|
} catch {
|
|
@@ -29850,7 +30283,7 @@ var ResumeStore = class {
|
|
|
29850
30283
|
const source = entries.find((name) => FILE_PATTERN.exec(name)?.[2] === wanted);
|
|
29851
30284
|
if (!source) return null;
|
|
29852
30285
|
const claimId = `${this.now()}-${safeId(target.taskId)}`;
|
|
29853
|
-
await promises.rename(
|
|
30286
|
+
await promises.rename(path36.join(this.dir, source), path36.join(this.dir, `${claimId}${CLAIM_SUFFIX}`));
|
|
29854
30287
|
return { checkpoint: target, claimId };
|
|
29855
30288
|
} catch {
|
|
29856
30289
|
return null;
|
|
@@ -29860,8 +30293,8 @@ var ResumeStore = class {
|
|
|
29860
30293
|
async release(claimId) {
|
|
29861
30294
|
try {
|
|
29862
30295
|
await promises.rename(
|
|
29863
|
-
|
|
29864
|
-
|
|
30296
|
+
path36.join(this.dir, `${claimId}${CLAIM_SUFFIX}`),
|
|
30297
|
+
path36.join(this.dir, `${claimId}.json`)
|
|
29865
30298
|
);
|
|
29866
30299
|
} catch {
|
|
29867
30300
|
}
|
|
@@ -29869,7 +30302,7 @@ var ResumeStore = class {
|
|
|
29869
30302
|
/** Discard a claim for good — the resumed run has taken ownership. */
|
|
29870
30303
|
async settle(claimId) {
|
|
29871
30304
|
try {
|
|
29872
|
-
await promises.rm(
|
|
30305
|
+
await promises.rm(path36.join(this.dir, `${claimId}${CLAIM_SUFFIX}`), { force: true });
|
|
29873
30306
|
} catch {
|
|
29874
30307
|
}
|
|
29875
30308
|
}
|
|
@@ -29898,8 +30331,8 @@ var ResumeStore = class {
|
|
|
29898
30331
|
const stamp2 = Number(/^(\d+)-/.exec(name)?.[1]);
|
|
29899
30332
|
if (!Number.isFinite(stamp2) || stamp2 >= cutoff) continue;
|
|
29900
30333
|
await promises.rename(
|
|
29901
|
-
|
|
29902
|
-
|
|
30334
|
+
path36.join(this.dir, name),
|
|
30335
|
+
path36.join(this.dir, `${name.slice(0, -CLAIM_SUFFIX.length)}.json`)
|
|
29903
30336
|
);
|
|
29904
30337
|
reclaimed++;
|
|
29905
30338
|
}
|
|
@@ -29915,7 +30348,7 @@ var ResumeStore = class {
|
|
|
29915
30348
|
await Promise.all(entries.map(async (name) => {
|
|
29916
30349
|
const match = FILE_PATTERN.exec(name);
|
|
29917
30350
|
if (match?.[2] === wanted) {
|
|
29918
|
-
await promises.rm(
|
|
30351
|
+
await promises.rm(path36.join(this.dir, name), { force: true });
|
|
29919
30352
|
}
|
|
29920
30353
|
}));
|
|
29921
30354
|
} catch {
|
|
@@ -29930,7 +30363,7 @@ var ResumeStore = class {
|
|
|
29930
30363
|
const doomed = files.filter((f, index) => f.timestamp < cutoff || index >= this.maxCheckpoints);
|
|
29931
30364
|
const staleTemps = entries.filter((name) => name.endsWith(".tmp")).filter((name) => (Number(FILE_PATTERN.exec(name.replace(/\.\d+\.tmp$/, ".json"))?.[1]) || 0) < cutoff);
|
|
29932
30365
|
await Promise.all([...doomed.map((f) => f.name), ...staleTemps].map(
|
|
29933
|
-
(name) => promises.rm(
|
|
30366
|
+
(name) => promises.rm(path36.join(this.dir, name), { force: true })
|
|
29934
30367
|
));
|
|
29935
30368
|
} catch {
|
|
29936
30369
|
}
|
|
@@ -30307,7 +30740,7 @@ var WorkspaceIndex = class {
|
|
|
30307
30740
|
isIgnored;
|
|
30308
30741
|
chunker;
|
|
30309
30742
|
constructor(opts) {
|
|
30310
|
-
this.root =
|
|
30743
|
+
this.root = path36.resolve(opts.root);
|
|
30311
30744
|
this.db = opts.db;
|
|
30312
30745
|
this.namespace = opts.namespace ?? "code";
|
|
30313
30746
|
this.extensions = new Set((opts.extensions ?? DEFAULT_EXTENSIONS).map((e) => e.replace(/^\./, "").toLowerCase()));
|
|
@@ -30339,14 +30772,14 @@ var WorkspaceIndex = class {
|
|
|
30339
30772
|
return;
|
|
30340
30773
|
}
|
|
30341
30774
|
for (const entry of entries) {
|
|
30342
|
-
const abs =
|
|
30775
|
+
const abs = path36.join(dir, entry.name);
|
|
30343
30776
|
if (entry.isDirectory()) {
|
|
30344
30777
|
if (HARD_SKIP_DIRS.has(entry.name) || this.isIgnored(abs)) continue;
|
|
30345
30778
|
await walk(abs);
|
|
30346
30779
|
} else if (entry.isFile()) {
|
|
30347
|
-
const ext =
|
|
30780
|
+
const ext = path36.extname(entry.name).slice(1).toLowerCase();
|
|
30348
30781
|
if (!this.extensions.has(ext) || this.isIgnored(abs)) continue;
|
|
30349
|
-
out.push(
|
|
30782
|
+
out.push(path36.relative(this.root, abs));
|
|
30350
30783
|
}
|
|
30351
30784
|
}
|
|
30352
30785
|
};
|
|
@@ -30376,7 +30809,7 @@ var WorkspaceIndex = class {
|
|
|
30376
30809
|
const entries = [];
|
|
30377
30810
|
for (const rel of rels) {
|
|
30378
30811
|
try {
|
|
30379
|
-
const abs =
|
|
30812
|
+
const abs = path36.join(this.root, rel);
|
|
30380
30813
|
const stat = await fs11.stat(abs);
|
|
30381
30814
|
if (stat.size > this.maxFileBytes) continue;
|
|
30382
30815
|
const buf = await fs11.readFile(abs);
|
|
@@ -30866,13 +31299,13 @@ var Cascade = class _Cascade extends EventEmitter {
|
|
|
30866
31299
|
this.toolRegistry = new ToolRegistry(this.config.tools, workspacePath);
|
|
30867
31300
|
try {
|
|
30868
31301
|
this.router.setDeadModelStore(new DeadModelStore(
|
|
30869
|
-
fileDeadModelPersistence(
|
|
31302
|
+
fileDeadModelPersistence(path36.join(workspacePath, ".cascade", "dead-models.json"))
|
|
30870
31303
|
));
|
|
30871
31304
|
} catch {
|
|
30872
31305
|
}
|
|
30873
31306
|
try {
|
|
30874
31307
|
this.resumeStore = new ResumeStore({
|
|
30875
|
-
dir:
|
|
31308
|
+
dir: path36.join(workspacePath, ".cascade", "resume")
|
|
30876
31309
|
});
|
|
30877
31310
|
} catch {
|
|
30878
31311
|
}
|
|
@@ -30960,8 +31393,8 @@ var Cascade = class _Cascade extends EventEmitter {
|
|
|
30960
31393
|
this.emit("log", { level: "warn", message: "Code index enabled but no embeddings-capable provider is configured \u2014 skipping." });
|
|
30961
31394
|
return;
|
|
30962
31395
|
}
|
|
30963
|
-
const dbPath = ci.dbPath ||
|
|
30964
|
-
|
|
31396
|
+
const dbPath = ci.dbPath || path36.join(this.workspacePath, ".cascade", "code-index.db");
|
|
31397
|
+
fs33.mkdirSync(path36.dirname(dbPath), { recursive: true });
|
|
30965
31398
|
const db = new Database2(dbPath);
|
|
30966
31399
|
db.pragma("journal_mode = WAL");
|
|
30967
31400
|
const complete = chatCompleterFromProviders(this.config.providers);
|
|
@@ -32429,14 +32862,14 @@ ${finalOutput}` : ""
|
|
|
32429
32862
|
init_constants();
|
|
32430
32863
|
var CLOUD_SESSION_FILE = "cloud-session.json";
|
|
32431
32864
|
function globalDir(homeDir = os10.homedir()) {
|
|
32432
|
-
return
|
|
32865
|
+
return path36.join(homeDir, GLOBAL_CONFIG_DIR);
|
|
32433
32866
|
}
|
|
32434
32867
|
function cloudSessionPath(dir = globalDir()) {
|
|
32435
|
-
return
|
|
32868
|
+
return path36.join(dir, CLOUD_SESSION_FILE);
|
|
32436
32869
|
}
|
|
32437
32870
|
function loadCloudSession(dir = globalDir()) {
|
|
32438
32871
|
try {
|
|
32439
|
-
const raw =
|
|
32872
|
+
const raw = fs33.readFileSync(cloudSessionPath(dir), "utf-8");
|
|
32440
32873
|
const parsed = JSON.parse(raw);
|
|
32441
32874
|
if (!parsed?.refreshToken || !parsed?.serverUrl) return null;
|
|
32442
32875
|
return parsed;
|
|
@@ -32445,17 +32878,17 @@ function loadCloudSession(dir = globalDir()) {
|
|
|
32445
32878
|
}
|
|
32446
32879
|
}
|
|
32447
32880
|
function saveCloudSession(session, dir = globalDir()) {
|
|
32448
|
-
|
|
32881
|
+
fs33.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
32449
32882
|
const file = cloudSessionPath(dir);
|
|
32450
|
-
|
|
32883
|
+
fs33.writeFileSync(file, JSON.stringify(session, null, 2), { mode: 384 });
|
|
32451
32884
|
try {
|
|
32452
|
-
|
|
32885
|
+
fs33.chmodSync(file, 384);
|
|
32453
32886
|
} catch {
|
|
32454
32887
|
}
|
|
32455
32888
|
}
|
|
32456
32889
|
function clearCloudSession(dir = globalDir()) {
|
|
32457
32890
|
try {
|
|
32458
|
-
|
|
32891
|
+
fs33.rmSync(cloudSessionPath(dir));
|
|
32459
32892
|
} catch {
|
|
32460
32893
|
}
|
|
32461
32894
|
}
|
|
@@ -32627,16 +33060,16 @@ var CloudClient = class _CloudClient {
|
|
|
32627
33060
|
return (await this.refresh()).accessToken;
|
|
32628
33061
|
}
|
|
32629
33062
|
/** Authenticated request that refreshes once on a 401 (e.g. server-side revoke). */
|
|
32630
|
-
async authed(
|
|
32631
|
-
const call = (token) => fetch(this.url(
|
|
33063
|
+
async authed(path41, init = {}) {
|
|
33064
|
+
const call = (token) => fetch(this.url(path41), { ...init, headers: { ...init.headers ?? {}, Authorization: `Bearer ${token}` } });
|
|
32632
33065
|
let res = await call(await this.accessToken());
|
|
32633
33066
|
if (res.status === 401) res = await call((await this.refresh()).accessToken);
|
|
32634
33067
|
if (!res.ok) throw new Error(`Request failed (${res.status}).`);
|
|
32635
33068
|
const text = await res.text();
|
|
32636
33069
|
return text ? JSON.parse(text) : {};
|
|
32637
33070
|
}
|
|
32638
|
-
authedGet(
|
|
32639
|
-
return this.authed(
|
|
33071
|
+
authedGet(path41) {
|
|
33072
|
+
return this.authed(path41);
|
|
32640
33073
|
}
|
|
32641
33074
|
async fetchMe(token) {
|
|
32642
33075
|
const res = await fetch(this.url("/api/me"), { headers: { Authorization: `Bearer ${token}` } });
|
|
@@ -34410,9 +34843,9 @@ function Repl({ config, workspacePath, themeName, initialPrompt, identityName, s
|
|
|
34410
34843
|
}
|
|
34411
34844
|
} catch {
|
|
34412
34845
|
}
|
|
34413
|
-
const configPath =
|
|
34846
|
+
const configPath = path36.join(workspacePath, ".cascade", "config.json");
|
|
34414
34847
|
try {
|
|
34415
|
-
await fs11.mkdir(
|
|
34848
|
+
await fs11.mkdir(path36.dirname(configPath), { recursive: true });
|
|
34416
34849
|
await fs11.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
34417
34850
|
} catch (err) {
|
|
34418
34851
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -34464,9 +34897,9 @@ function Repl({ config, workspacePath, themeName, initialPrompt, identityName, s
|
|
|
34464
34897
|
if (msg.includes("non-text parts")) return;
|
|
34465
34898
|
originalLog(...args);
|
|
34466
34899
|
};
|
|
34467
|
-
const store = new MemoryStore(
|
|
34900
|
+
const store = new MemoryStore(path36.join(workspacePath, CASCADE_DB_FILE));
|
|
34468
34901
|
storeRef.current = store;
|
|
34469
|
-
globalStoreRef.current = new MemoryStore(
|
|
34902
|
+
globalStoreRef.current = new MemoryStore(path36.join(os10.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE));
|
|
34470
34903
|
const identityRows = store.listIdentities().map((i) => ({ id: i.id, name: i.name, isDefault: i.isDefault }));
|
|
34471
34904
|
setIdentities(identityRows);
|
|
34472
34905
|
let initialIdentityId = config.defaultIdentityId ?? identityRows.find((i) => i.isDefault)?.id ?? identityRows[0]?.id;
|
|
@@ -34546,7 +34979,7 @@ function Repl({ config, workspacePath, themeName, initialPrompt, identityName, s
|
|
|
34546
34979
|
onThemeChange: (name) => setTheme(getTheme(name)),
|
|
34547
34980
|
onExport: async (fmt) => {
|
|
34548
34981
|
const stamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
34549
|
-
const exportPath =
|
|
34982
|
+
const exportPath = path36.join(workspacePath, `cascade-export-${stamp2}.${fmt === "json" ? "json" : "md"}`);
|
|
34550
34983
|
if (fmt === "json") {
|
|
34551
34984
|
await fs11.writeFile(exportPath, JSON.stringify({ sessionId: sessionIdRef.current, messages: state.messages }, null, 2), "utf-8");
|
|
34552
34985
|
} else {
|
|
@@ -35466,7 +35899,7 @@ function stringifySlashOutput(val) {
|
|
|
35466
35899
|
}
|
|
35467
35900
|
async function searchSessionsAndMessages(query, workspacePath) {
|
|
35468
35901
|
if (!query) return "Usage: /search <query>";
|
|
35469
|
-
const dbPath =
|
|
35902
|
+
const dbPath = path36.join(workspacePath, CASCADE_DB_FILE);
|
|
35470
35903
|
try {
|
|
35471
35904
|
await fs11.access(dbPath);
|
|
35472
35905
|
} catch {
|
|
@@ -35500,7 +35933,7 @@ async function searchSessionsAndMessages(query, workspacePath) {
|
|
|
35500
35933
|
async function diagnoseRuntime(config, workspacePath) {
|
|
35501
35934
|
const providers = config.providers.map((p) => `${p.type}${p.apiKey ? " (key set)" : " (no key)"}`).join("\n");
|
|
35502
35935
|
const models = [`T1: ${config.models.t1 ?? "default"}`, `T2: ${config.models.t2 ?? "default"}`, `T3: ${config.models.t3 ?? "default"}`].join("\n");
|
|
35503
|
-
const store = new MemoryStore(
|
|
35936
|
+
const store = new MemoryStore(path36.join(workspacePath, CASCADE_DB_FILE));
|
|
35504
35937
|
try {
|
|
35505
35938
|
const sessions2 = store.listSessions(void 0, 3);
|
|
35506
35939
|
return [
|
|
@@ -35519,7 +35952,7 @@ async function diagnoseRuntime(config, workspacePath) {
|
|
|
35519
35952
|
}
|
|
35520
35953
|
async function showRecentLogs(args, workspacePath) {
|
|
35521
35954
|
const limit = Number.parseInt(args[0] ?? "10", 10) || 10;
|
|
35522
|
-
const store = new MemoryStore(
|
|
35955
|
+
const store = new MemoryStore(path36.join(workspacePath, CASCADE_DB_FILE));
|
|
35523
35956
|
try {
|
|
35524
35957
|
const logs = store.listRuntimeNodeLogs(void 0, void 0, limit);
|
|
35525
35958
|
if (!logs.length) return "No recent runtime logs.";
|
|
@@ -35531,7 +35964,7 @@ async function showRecentLogs(args, workspacePath) {
|
|
|
35531
35964
|
async function loadSessionSnapshot(args, workspacePath) {
|
|
35532
35965
|
const sessionId = args[0];
|
|
35533
35966
|
if (!sessionId) return "Usage: /resume <sessionId>";
|
|
35534
|
-
const store = new MemoryStore(
|
|
35967
|
+
const store = new MemoryStore(path36.join(workspacePath, CASCADE_DB_FILE));
|
|
35535
35968
|
try {
|
|
35536
35969
|
const session = store.getSession(sessionId);
|
|
35537
35970
|
if (!session) return `Session not found: ${sessionId}`;
|
|
@@ -35951,9 +36384,9 @@ function SetupWizard({ workspacePath, onComplete }) {
|
|
|
35951
36384
|
...anyAuto ? { cascadeAuto: true } : {}
|
|
35952
36385
|
};
|
|
35953
36386
|
const config = CascadeConfigSchema.parse(rawConfig);
|
|
35954
|
-
const configDir =
|
|
36387
|
+
const configDir = path36.join(workspacePath, ".cascade");
|
|
35955
36388
|
await fs11.mkdir(configDir, { recursive: true });
|
|
35956
|
-
const configPath =
|
|
36389
|
+
const configPath = path36.join(workspacePath, CASCADE_CONFIG_FILE);
|
|
35957
36390
|
await fs11.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
35958
36391
|
savedConfigRef.current = config;
|
|
35959
36392
|
dispatchRef.current({ type: "GO_DONE" });
|
|
@@ -36294,14 +36727,14 @@ function printTelemetryBanner() {
|
|
|
36294
36727
|
async function initCommand(workspacePath = process.cwd()) {
|
|
36295
36728
|
const spin = ora({ text: "Initializing Cascade project\u2026", color: "magenta" }).start();
|
|
36296
36729
|
try {
|
|
36297
|
-
const configDir =
|
|
36730
|
+
const configDir = path36.join(workspacePath, ".cascade");
|
|
36298
36731
|
await fs11.mkdir(configDir, { recursive: true });
|
|
36299
|
-
const mdPath =
|
|
36732
|
+
const mdPath = path36.join(workspacePath, "CASCADE.md");
|
|
36300
36733
|
if (!await fileExists(mdPath)) {
|
|
36301
36734
|
await createDefaultCascadeMd(workspacePath);
|
|
36302
36735
|
spin.succeed(chalk8.green("Created CASCADE.md"));
|
|
36303
36736
|
}
|
|
36304
|
-
const ignorePath =
|
|
36737
|
+
const ignorePath = path36.join(workspacePath, ".cascadeignore");
|
|
36305
36738
|
if (!await fileExists(ignorePath)) {
|
|
36306
36739
|
await createDefaultIgnoreFile(workspacePath);
|
|
36307
36740
|
spin.succeed(chalk8.green("Created .cascadeignore"));
|
|
@@ -36310,7 +36743,7 @@ async function initCommand(workspacePath = process.cwd()) {
|
|
|
36310
36743
|
console.log();
|
|
36311
36744
|
console.log(chalk8.magenta(" \u25C8 Cascade AI \u2014 Project initialized"));
|
|
36312
36745
|
console.log();
|
|
36313
|
-
const configPath =
|
|
36746
|
+
const configPath = path36.join(workspacePath, CASCADE_CONFIG_FILE);
|
|
36314
36747
|
if (await fileExists(configPath)) {
|
|
36315
36748
|
console.log(chalk8.yellow(" .cascade/config.json already exists \u2014 launching wizard to reconfigure."));
|
|
36316
36749
|
console.log();
|
|
@@ -36461,8 +36894,8 @@ function fromEnv(env) {
|
|
|
36461
36894
|
return out;
|
|
36462
36895
|
}
|
|
36463
36896
|
async function fromClaudeCode(home, env) {
|
|
36464
|
-
const dir = str(env["CLAUDE_CONFIG_DIR"]) ??
|
|
36465
|
-
const file =
|
|
36897
|
+
const dir = str(env["CLAUDE_CONFIG_DIR"]) ?? path36.join(home, ".claude");
|
|
36898
|
+
const file = path36.join(dir, ".credentials.json");
|
|
36466
36899
|
const data = await readJson(file);
|
|
36467
36900
|
if (!data) return [];
|
|
36468
36901
|
const found = [];
|
|
@@ -36486,7 +36919,7 @@ async function fromClaudeCode(home, env) {
|
|
|
36486
36919
|
return found;
|
|
36487
36920
|
}
|
|
36488
36921
|
async function fromCodex(home) {
|
|
36489
|
-
const file =
|
|
36922
|
+
const file = path36.join(home, ".codex", "auth.json");
|
|
36490
36923
|
const data = await readJson(file);
|
|
36491
36924
|
if (!data) return [];
|
|
36492
36925
|
const apiKey = str(data["OPENAI_API_KEY"]);
|
|
@@ -36509,7 +36942,7 @@ async function fromCodex(home) {
|
|
|
36509
36942
|
return [];
|
|
36510
36943
|
}
|
|
36511
36944
|
async function fromGemini(home) {
|
|
36512
|
-
const file =
|
|
36945
|
+
const file = path36.join(home, ".gemini", "oauth_creds.json");
|
|
36513
36946
|
const data = await readJson(file);
|
|
36514
36947
|
const accessToken = str(data?.["access_token"]);
|
|
36515
36948
|
if (!accessToken) return [];
|
|
@@ -36525,7 +36958,7 @@ async function fromGemini(home) {
|
|
|
36525
36958
|
}
|
|
36526
36959
|
async function fromCopilot(home) {
|
|
36527
36960
|
for (const name of ["apps.json", "hosts.json"]) {
|
|
36528
|
-
const file =
|
|
36961
|
+
const file = path36.join(home, ".config", "github-copilot", name);
|
|
36529
36962
|
const data = await readJson(file);
|
|
36530
36963
|
if (!data) continue;
|
|
36531
36964
|
for (const value of Object.values(data)) {
|
|
@@ -36826,7 +37259,7 @@ async function doctorCommand() {
|
|
|
36826
37259
|
checks.push({
|
|
36827
37260
|
label: "Cascade config",
|
|
36828
37261
|
ok: true,
|
|
36829
|
-
detail: `Loaded ${
|
|
37262
|
+
detail: `Loaded ${path36.join(process.cwd(), CASCADE_CONFIG_FILE)}`
|
|
36830
37263
|
});
|
|
36831
37264
|
const providers = [
|
|
36832
37265
|
{ type: "anthropic", name: "Anthropic" },
|
|
@@ -36936,7 +37369,7 @@ async function checkEndpoint(url) {
|
|
|
36936
37369
|
}
|
|
36937
37370
|
}
|
|
36938
37371
|
async function indexCommand(dirPath) {
|
|
36939
|
-
const workspace =
|
|
37372
|
+
const workspace = path36.resolve(dirPath || process.cwd());
|
|
36940
37373
|
const cm = new ConfigManager(workspace);
|
|
36941
37374
|
await cm.load();
|
|
36942
37375
|
const config = cm.getConfig();
|
|
@@ -36947,8 +37380,8 @@ async function indexCommand(dirPath) {
|
|
|
36947
37380
|
process.exitCode = 1;
|
|
36948
37381
|
return;
|
|
36949
37382
|
}
|
|
36950
|
-
const dbPath = config.codeIndex?.dbPath ||
|
|
36951
|
-
|
|
37383
|
+
const dbPath = config.codeIndex?.dbPath || path36.join(workspace, ".cascade", "code-index.db");
|
|
37384
|
+
fs33.mkdirSync(path36.dirname(dbPath), { recursive: true });
|
|
36952
37385
|
const db = new Database2(dbPath);
|
|
36953
37386
|
db.pragma("journal_mode = WAL");
|
|
36954
37387
|
const complete = chatCompleterFromProviders(config.providers);
|
|
@@ -37480,7 +37913,7 @@ function openBrowser2(url) {
|
|
|
37480
37913
|
}
|
|
37481
37914
|
function storePathFor(name) {
|
|
37482
37915
|
const safe = name.replace(/[^a-z0-9._-]/gi, "_").slice(0, 64) || "server";
|
|
37483
|
-
return
|
|
37916
|
+
return path36.join(os10.homedir(), ".cascade-ai", "mcp-oauth", `${safe}.json`);
|
|
37484
37917
|
}
|
|
37485
37918
|
function defaultName(url) {
|
|
37486
37919
|
try {
|
|
@@ -37867,8 +38300,8 @@ function replaceInPlace(target, source) {
|
|
|
37867
38300
|
}
|
|
37868
38301
|
function writeConfigFile(configPath, config) {
|
|
37869
38302
|
try {
|
|
37870
|
-
|
|
37871
|
-
|
|
38303
|
+
fs33.mkdirSync(path36.dirname(configPath), { recursive: true });
|
|
38304
|
+
fs33.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
37872
38305
|
return { ok: true };
|
|
37873
38306
|
} catch (err) {
|
|
37874
38307
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
@@ -38284,7 +38717,7 @@ function aggregateCostStats(sessions2, opts = {}) {
|
|
|
38284
38717
|
}
|
|
38285
38718
|
|
|
38286
38719
|
// src/dashboard/server.ts
|
|
38287
|
-
var __dirname$1 =
|
|
38720
|
+
var __dirname$1 = path36.dirname(fileURLToPath(import.meta.url));
|
|
38288
38721
|
var ORPHANED_ESCALATION_GRACE_MS = 3e4;
|
|
38289
38722
|
var MASK = "***";
|
|
38290
38723
|
function masked(key, value) {
|
|
@@ -38603,7 +39036,7 @@ var DashboardServer = class {
|
|
|
38603
39036
|
* silently and still typecheck.
|
|
38604
39037
|
*/
|
|
38605
39038
|
persistConfig(config) {
|
|
38606
|
-
const result = writeConfigFile(
|
|
39039
|
+
const result = writeConfigFile(path36.join(this.workspacePath, CASCADE_CONFIG_FILE), config);
|
|
38607
39040
|
if (!result.ok) console.warn(`[dashboard] Failed to persist config: ${result.error}`);
|
|
38608
39041
|
return result;
|
|
38609
39042
|
}
|
|
@@ -38622,7 +39055,7 @@ var DashboardServer = class {
|
|
|
38622
39055
|
*/
|
|
38623
39056
|
syncGlobalCredentials() {
|
|
38624
39057
|
try {
|
|
38625
|
-
saveGlobalCredentials(
|
|
39058
|
+
saveGlobalCredentials(path36.join(os10.homedir(), GLOBAL_CONFIG_DIR), this.config.providers ?? []);
|
|
38626
39059
|
} catch (err) {
|
|
38627
39060
|
console.warn(`[dashboard] Failed to sync global credentials: ${err instanceof Error ? err.message : String(err)}`);
|
|
38628
39061
|
}
|
|
@@ -38637,15 +39070,15 @@ var DashboardServer = class {
|
|
|
38637
39070
|
resolveDashboardSecret() {
|
|
38638
39071
|
const fromConfig = this.config.dashboard.secret ?? process.env["CASCADE_DASHBOARD_SECRET"];
|
|
38639
39072
|
if (fromConfig) return fromConfig;
|
|
38640
|
-
const secretPath =
|
|
39073
|
+
const secretPath = path36.join(this.workspacePath, CASCADE_DASHBOARD_SECRET_FILE);
|
|
38641
39074
|
try {
|
|
38642
|
-
if (
|
|
38643
|
-
const existing =
|
|
39075
|
+
if (fs33.existsSync(secretPath)) {
|
|
39076
|
+
const existing = fs33.readFileSync(secretPath, "utf-8").trim();
|
|
38644
39077
|
if (existing.length >= 16) return existing;
|
|
38645
39078
|
}
|
|
38646
39079
|
const generated = randomUUID();
|
|
38647
|
-
|
|
38648
|
-
|
|
39080
|
+
fs33.mkdirSync(path36.dirname(secretPath), { recursive: true });
|
|
39081
|
+
fs33.writeFileSync(secretPath, generated, { encoding: "utf-8", mode: 384 });
|
|
38649
39082
|
if (this.config.dashboard.auth) {
|
|
38650
39083
|
console.warn(
|
|
38651
39084
|
`Dashboard auth enabled with no secret configured; persisted a generated secret to ${secretPath}. Set CASCADE_DASHBOARD_SECRET or config.dashboard.secret to override.`
|
|
@@ -38672,7 +39105,7 @@ var DashboardServer = class {
|
|
|
38672
39105
|
// ── Setup ─────────────────────────────────────
|
|
38673
39106
|
getGlobalStore() {
|
|
38674
39107
|
if (!this.globalStore) {
|
|
38675
|
-
const globalDbPath =
|
|
39108
|
+
const globalDbPath = path36.join(os10.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
38676
39109
|
this.globalStore = new MemoryStore(globalDbPath);
|
|
38677
39110
|
}
|
|
38678
39111
|
return this.globalStore;
|
|
@@ -39052,12 +39485,12 @@ ${prompt}`;
|
|
|
39052
39485
|
}
|
|
39053
39486
|
}
|
|
39054
39487
|
watchRuntimeChanges() {
|
|
39055
|
-
const workspaceDbPath =
|
|
39056
|
-
const globalDbPath =
|
|
39488
|
+
const workspaceDbPath = path36.join(this.workspacePath, CASCADE_DB_FILE);
|
|
39489
|
+
const globalDbPath = path36.join(os10.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
39057
39490
|
const watchPaths = [workspaceDbPath, globalDbPath].filter((p, index, arr) => arr.indexOf(p) === index);
|
|
39058
39491
|
for (const watchPath of watchPaths) {
|
|
39059
|
-
if (!
|
|
39060
|
-
|
|
39492
|
+
if (!fs33.existsSync(watchPath)) continue;
|
|
39493
|
+
fs33.watchFile(watchPath, { interval: 3e3 }, () => {
|
|
39061
39494
|
this.throttledBroadcast(watchPath === globalDbPath ? "global" : "workspace");
|
|
39062
39495
|
});
|
|
39063
39496
|
}
|
|
@@ -39179,7 +39612,7 @@ ${prompt}`;
|
|
|
39179
39612
|
const sessionId = req.params.id;
|
|
39180
39613
|
this.store.deleteSession(sessionId);
|
|
39181
39614
|
this.store.deleteRuntimeSession(sessionId);
|
|
39182
|
-
const globalDbPath =
|
|
39615
|
+
const globalDbPath = path36.join(os10.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
39183
39616
|
const globalStore = new MemoryStore(globalDbPath);
|
|
39184
39617
|
try {
|
|
39185
39618
|
globalStore.deleteRuntimeSession(sessionId);
|
|
@@ -39272,7 +39705,7 @@ ${prompt}`;
|
|
|
39272
39705
|
});
|
|
39273
39706
|
this.app.delete("/api/sessions", auth2, (req, res) => {
|
|
39274
39707
|
const body = req.body;
|
|
39275
|
-
const globalDbPath =
|
|
39708
|
+
const globalDbPath = path36.join(os10.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
39276
39709
|
if (body?.ids && Array.isArray(body.ids) && body.ids.length > 0) {
|
|
39277
39710
|
const globalStore = new MemoryStore(globalDbPath);
|
|
39278
39711
|
try {
|
|
@@ -39295,7 +39728,7 @@ ${prompt}`;
|
|
|
39295
39728
|
});
|
|
39296
39729
|
this.app.delete("/api/runtime", auth2, (_req, res) => {
|
|
39297
39730
|
this.store.deleteAllRuntimeNodes();
|
|
39298
|
-
const globalDbPath =
|
|
39731
|
+
const globalDbPath = path36.join(os10.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
39299
39732
|
const globalStore = new MemoryStore(globalDbPath);
|
|
39300
39733
|
try {
|
|
39301
39734
|
globalStore.deleteAllRuntimeNodes();
|
|
@@ -39380,12 +39813,12 @@ ${prompt}`;
|
|
|
39380
39813
|
if (body["tierLimits"]) this.config.tierLimits = { ...this.config.tierLimits, ...body["tierLimits"] };
|
|
39381
39814
|
if (body["budget"]) this.config.budget = { ...this.config.budget, ...body["budget"] };
|
|
39382
39815
|
try {
|
|
39383
|
-
const configPath =
|
|
39384
|
-
const existing =
|
|
39816
|
+
const configPath = path36.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
39817
|
+
const existing = fs33.existsSync(configPath) ? JSON.parse(fs33.readFileSync(configPath, "utf-8")) : {};
|
|
39385
39818
|
const updated = { ...existing, tierLimits: this.config.tierLimits, budget: this.config.budget };
|
|
39386
39819
|
const tmp = configPath + ".tmp";
|
|
39387
|
-
|
|
39388
|
-
|
|
39820
|
+
fs33.writeFileSync(tmp, JSON.stringify(updated, null, 2), "utf-8");
|
|
39821
|
+
fs33.renameSync(tmp, configPath);
|
|
39389
39822
|
res.json({ ok: true });
|
|
39390
39823
|
} catch (err) {
|
|
39391
39824
|
res.status(500).json({ error: `Failed to save config: ${err instanceof Error ? err.message : String(err)}` });
|
|
@@ -39413,7 +39846,7 @@ ${prompt}`;
|
|
|
39413
39846
|
this.app.get("/api/runtime", auth2, (req, res) => {
|
|
39414
39847
|
const scope = req.query["scope"] ?? "workspace";
|
|
39415
39848
|
if (scope === "global") {
|
|
39416
|
-
const globalDbPath =
|
|
39849
|
+
const globalDbPath = path36.join(os10.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_RUNTIME_DB_FILE);
|
|
39417
39850
|
const globalStore = new MemoryStore(globalDbPath);
|
|
39418
39851
|
try {
|
|
39419
39852
|
res.json({
|
|
@@ -39754,13 +40187,13 @@ ${prompt}`;
|
|
|
39754
40187
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
39755
40188
|
}
|
|
39756
40189
|
});
|
|
39757
|
-
const prodPath =
|
|
39758
|
-
const devPath =
|
|
39759
|
-
const webDistPath =
|
|
39760
|
-
if (
|
|
40190
|
+
const prodPath = path36.resolve(__dirname$1, "../web/dist");
|
|
40191
|
+
const devPath = path36.resolve(__dirname$1, "../../web/dist");
|
|
40192
|
+
const webDistPath = fs33.existsSync(prodPath) ? prodPath : devPath;
|
|
40193
|
+
if (fs33.existsSync(webDistPath)) {
|
|
39761
40194
|
this.app.use(express.static(webDistPath));
|
|
39762
40195
|
this.app.get("*", (_req, res) => {
|
|
39763
|
-
res.sendFile(
|
|
40196
|
+
res.sendFile(path36.join(webDistPath, "index.html"));
|
|
39764
40197
|
});
|
|
39765
40198
|
} else {
|
|
39766
40199
|
this.app.get("/", (_req, res) => {
|
|
@@ -39781,7 +40214,7 @@ init_constants();
|
|
|
39781
40214
|
async function dashboardCommand(config, workspacePath = process.cwd()) {
|
|
39782
40215
|
const port = config.dashboard.port ?? DEFAULT_DASHBOARD_PORT;
|
|
39783
40216
|
const spin = ora({ text: `Starting dashboard on port ${port}\u2026`, color: "magenta" }).start();
|
|
39784
|
-
const store = new MemoryStore(
|
|
40217
|
+
const store = new MemoryStore(path36.join(workspacePath, CASCADE_DB_FILE));
|
|
39785
40218
|
const server = new DashboardServer(config, store, workspacePath);
|
|
39786
40219
|
server.watchRuntimeChanges();
|
|
39787
40220
|
const gThis = globalThis;
|
|
@@ -39813,7 +40246,7 @@ init_constants();
|
|
|
39813
40246
|
function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
39814
40247
|
const identity = new Command("identity").alias("id").description("Manage Cascade identities");
|
|
39815
40248
|
identity.command("list").description("List all available identities").action(() => {
|
|
39816
|
-
const store = new MemoryStore(
|
|
40249
|
+
const store = new MemoryStore(path36.join(workspacePath, CASCADE_DB_FILE));
|
|
39817
40250
|
try {
|
|
39818
40251
|
const identities = store.listIdentities();
|
|
39819
40252
|
console.log(chalk8.bold("\n Identities:"));
|
|
@@ -39833,7 +40266,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
39833
40266
|
}
|
|
39834
40267
|
});
|
|
39835
40268
|
identity.command("create <name>").description("Create a new identity").option("-d, --desc <text>", "Description of the identity").option("-s, --system <text>", "System prompt").option("--default", "Set as default identity").action((name, options) => {
|
|
39836
|
-
const store = new MemoryStore(
|
|
40269
|
+
const store = new MemoryStore(path36.join(workspacePath, CASCADE_DB_FILE));
|
|
39837
40270
|
try {
|
|
39838
40271
|
if (options.default) {
|
|
39839
40272
|
const existingDefault = store.getDefaultIdentity();
|
|
@@ -39859,7 +40292,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
39859
40292
|
}
|
|
39860
40293
|
});
|
|
39861
40294
|
identity.command("set-default <name>").description("Set an identity as default by name or ID").action((query) => {
|
|
39862
|
-
const store = new MemoryStore(
|
|
40295
|
+
const store = new MemoryStore(path36.join(workspacePath, CASCADE_DB_FILE));
|
|
39863
40296
|
try {
|
|
39864
40297
|
const identities = store.listIdentities();
|
|
39865
40298
|
const match = identities.find((i) => i.id === query || i.name.toLowerCase() === query.toLowerCase());
|
|
@@ -40008,8 +40441,8 @@ async function exportCommand(options = {}) {
|
|
|
40008
40441
|
let store;
|
|
40009
40442
|
try {
|
|
40010
40443
|
const workspacePath = options.workspacePath ?? process.cwd();
|
|
40011
|
-
const workspaceDbPath =
|
|
40012
|
-
const globalDbPath =
|
|
40444
|
+
const workspaceDbPath = path36.join(workspacePath, CASCADE_DB_FILE);
|
|
40445
|
+
const globalDbPath = path36.join(os10.homedir(), GLOBAL_CONFIG_DIR, GLOBAL_DB_FILE);
|
|
40013
40446
|
let dbPath = globalDbPath;
|
|
40014
40447
|
try {
|
|
40015
40448
|
await fs11.access(workspaceDbPath);
|
|
@@ -40051,7 +40484,7 @@ async function exportCommand(options = {}) {
|
|
|
40051
40484
|
const ext = format === "json" ? ".json" : ".md";
|
|
40052
40485
|
const safeName = session.title.replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").slice(0, 60);
|
|
40053
40486
|
const defaultFile = `cascade-export-${safeName}${ext}`;
|
|
40054
|
-
const outPath = options.output ?
|
|
40487
|
+
const outPath = options.output ? path36.resolve(options.output) : path36.join(process.cwd(), defaultFile);
|
|
40055
40488
|
await fs11.writeFile(outPath, content, "utf-8");
|
|
40056
40489
|
spin.succeed(chalk8.green(`Exported to ${chalk8.white(outPath)}`));
|
|
40057
40490
|
const messageCount = Array.isArray(session.messages) ? session.messages.length : 0;
|
|
@@ -40191,7 +40624,7 @@ var SHOW_CURSOR = "\x1B[?25h";
|
|
|
40191
40624
|
function writeNow(stdout, text) {
|
|
40192
40625
|
if (typeof stdout.fd === "number") {
|
|
40193
40626
|
try {
|
|
40194
|
-
|
|
40627
|
+
fs33.writeSync(stdout.fd, text);
|
|
40195
40628
|
return;
|
|
40196
40629
|
} catch {
|
|
40197
40630
|
}
|
|
@@ -40214,11 +40647,11 @@ function restoreTerminal(stdin, stdout) {
|
|
|
40214
40647
|
dotenv.config();
|
|
40215
40648
|
function warnIfBuildIsStale() {
|
|
40216
40649
|
try {
|
|
40217
|
-
const here =
|
|
40650
|
+
const here = path36.dirname(fileURLToPath(import.meta.url));
|
|
40218
40651
|
for (const rel of ["..", "../.."]) {
|
|
40219
|
-
const pkgPath =
|
|
40220
|
-
if (!
|
|
40221
|
-
const pkg = JSON.parse(
|
|
40652
|
+
const pkgPath = path36.join(here, rel, "package.json");
|
|
40653
|
+
if (!fs33.existsSync(pkgPath)) continue;
|
|
40654
|
+
const pkg = JSON.parse(fs33.readFileSync(pkgPath, "utf-8"));
|
|
40222
40655
|
if (pkg.name !== "cascade-ai") continue;
|
|
40223
40656
|
if (pkg.version && pkg.version !== CASCADE_VERSION) {
|
|
40224
40657
|
console.error(
|