@qredence/fleet 0.5.10 → 0.6.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/CHANGELOG.md +22 -0
- package/dist/web/client/assets/agent-activity-CwMDU7aP.js +1 -0
- package/dist/web/client/assets/artifacts-panel-CJ75gQub.js +1 -0
- package/dist/web/client/assets/chat-Ci2cEQrR.js +52 -0
- package/dist/web/client/assets/{chat-command-palette-DfYSPPXI.js → chat-command-palette-CkISHfKE.js} +1 -1
- package/dist/web/client/assets/{citations-BQ_pr_9_.js → citations-C_tPOJE_.js} +1 -1
- package/dist/web/client/assets/{command-DPfiaYUL.js → command-_WjnervL.js} +1 -1
- package/dist/web/client/assets/fleet-message-queue-BCno4XP-.js +1 -0
- package/dist/web/client/assets/{fleet-pi-tool-renderer-AJoMbXBa.js → fleet-pi-tool-renderer-BEDIO3al.js} +4 -4
- package/dist/web/client/assets/fleet-reasoning-panel-CbkO7u-v.js +1 -0
- package/dist/web/client/assets/{fleet-subagent-list-BnRnrWKS.js → fleet-subagent-list-iKUtLJKZ.js} +1 -1
- package/dist/web/client/assets/fleet-tool-timeline-C8heL7ae.js +1 -0
- package/dist/web/client/assets/{fork-picker-dialog-CkcSekBl.js → fork-picker-dialog-ByBOGVsa.js} +1 -1
- package/dist/web/client/assets/globals-B_I1Eq1u.css +2 -0
- package/dist/web/client/assets/horizontal-resize-CwoDojST.js +1 -0
- package/dist/web/client/assets/{index-DlnHLDpx.js → index-DJ1fFbQu.js} +3 -3
- package/dist/web/client/assets/input-group-Tb5TYbzi.js +1 -0
- package/dist/web/client/assets/{ipython-tool-BrMePqD-.js → ipython-tool-ldJ9F1Cw.js} +1 -1
- package/dist/web/client/assets/model-selector-list-Ch05B2nZ.js +1 -0
- package/dist/web/client/assets/{openui-renderer-DwYFJdbe.js → openui-renderer-Bf60nxNi.js} +4 -4
- package/dist/web/client/assets/pencil-DcUwsKLn.js +1 -0
- package/dist/web/client/assets/prompt-input-qPIXZ-Rb.js +1 -0
- package/dist/web/client/assets/prompt-suggestions-Cc--lSNR.js +1 -0
- package/dist/web/client/assets/{provider-label-BCJh04J5.js → provider-label-DDLRnZyC.js} +1 -1
- package/dist/web/client/assets/repl-panel-DsPX04Xr.js +1 -0
- package/dist/web/client/assets/{resources-panel-Bo8dfUdm.js → resources-panel-D867-goy.js} +1 -1
- package/dist/web/client/assets/right-panel-registry-Dp8yX-oL.js +2 -0
- package/dist/web/client/assets/routes-DpgMJZ5n.js +16 -0
- package/dist/web/client/assets/safe-storage-s25GrfpH.js +1 -0
- package/dist/web/client/assets/session-insights-panel-YnaXvTpi.js +1 -0
- package/dist/web/client/assets/settings-dialog-YJkvt5EB.js +2 -0
- package/dist/web/client/assets/skeleton-loaders-C9vHwAYV.js +1 -0
- package/dist/web/client/assets/{subagent-chat-panel-DseoO31p.js → subagent-chat-panel-Yujplxpb.js} +1 -1
- package/dist/web/client/assets/subagent-transcript-CnI-mqN0.js +1 -0
- package/dist/web/client/assets/subagents-panel-CjXEdimj.js +1 -0
- package/dist/web/client/assets/{surfaces-cW-gp56p.js → surfaces-DI-U-_2a.js} +1 -1
- package/dist/web/client/assets/tool-result-DfnPN0FQ.js +4 -0
- package/dist/web/client/assets/ui-preferences-CImQGZm_.js +1 -0
- package/dist/web/client/assets/virtualized-turn-list--Vynre4D.js +6 -0
- package/dist/web/client/assets/{workspace-panel-DI1W3ce9.js → workspace-panel-CPPIznT9.js} +1 -1
- package/dist/web/client/bundle-budget.json +6 -6
- package/dist/web/server/{_tanstack-start-manifest_v-Cdx6hy2i-I7A5YJRU.js → _tanstack-start-manifest_v-DS_CSIFQ-WB3VTKF3.js} +15 -13
- package/dist/web/server/{agent-activity-B-JMvecd-SLE3GGY2.js → agent-activity-CS2rbF_C-A3R26CYH.js} +2 -2
- package/dist/web/server/{artifacts-panel-DLMK1O8P-42T45JMA.js → artifacts-panel-CaKrX2XC-R37I4BHF.js} +12 -12
- package/dist/web/server/{chat-command-palette-CdYwoTMe-4LBAZF7K.js → chat-command-palette-7gbqEnm9-6XICQZN7.js} +4 -4
- package/dist/web/server/{chunk-EBCYJSBR.js → chunk-7SD2ZSEA.js} +3 -3
- package/dist/web/server/{chunk-6AW2XFTZ.js → chunk-BBBS5AS7.js} +194 -10
- package/dist/web/server/{chunk-EOVMHQ2H.js → chunk-CNXJN5HN.js} +7 -7
- package/dist/web/server/{chunk-XKKXXG6N.js → chunk-DI7XRK2H.js} +2 -2
- package/dist/web/server/{chunk-KNJUSMBT.js → chunk-DZ2IC3FH.js} +2 -2
- package/dist/web/server/{chunk-K5ESTT4A.js → chunk-EAE2QXRK.js} +11 -3
- package/dist/web/server/{chunk-VHBFU4TG.js → chunk-EH4BZ6QM.js} +123 -16
- package/dist/web/server/{chunk-54II5QXQ.js → chunk-ETTDO4UO.js} +6 -3
- package/dist/web/server/{chunk-EHNIN245.js → chunk-GETSIVNU.js} +5 -5
- package/dist/web/server/{chunk-X2R5YPQZ.js → chunk-IJPCV6DH.js} +3 -2
- package/dist/web/server/{chunk-AJJ2S5FF.js → chunk-JQDLJ7KI.js} +20 -20
- package/dist/web/server/{chunk-M564UIEY.js → chunk-KELEYPVK.js} +8 -8
- package/dist/web/server/{chunk-OB5OSYJK.js → chunk-LXJD6IGW.js} +53 -29
- package/dist/web/server/chunk-M5RSPNYN.js +22 -0
- package/dist/web/server/{chunk-2TRF62K5.js → chunk-N6NOTURM.js} +3 -3
- package/dist/web/server/{chunk-5XX7RKJ6.js → chunk-NXJ32VFR.js} +5 -5
- package/dist/web/server/{chunk-P7H2OPKF.js → chunk-PIOFZUOU.js} +9 -1
- package/dist/web/server/chunk-PTCKOR23.js +39 -0
- package/dist/web/server/chunk-SZJUXVWG.js +40 -0
- package/dist/web/server/{chunk-TCH3U26B.js → chunk-TWYHHG5N.js} +2 -10
- package/dist/web/server/{chunk-FED63ZHU.js → chunk-WHBVQJ4K.js} +11 -6
- package/dist/web/server/{chunk-ANL4B775.js → chunk-XLNCWZMZ.js} +2 -2
- package/dist/web/server/{chunk-GM32R7JW.js → chunk-YKVGQBZA.js} +10 -8
- package/dist/web/server/{chunk-NRDG2ISJ.js → chunk-YNUWKMNQ.js} +59 -52
- package/dist/web/server/{chunk-3PIUR75R.js → chunk-YXXRP3NS.js} +9 -9
- package/dist/web/server/fleet-message-queue-BS-cZ56r-GLZXUKDF.js +152 -0
- package/dist/web/server/{fleet-pi-tool-renderer-RIeVlM9J-D6MISCQC.js → fleet-pi-tool-renderer-umKunT3K-O4GBH35V.js} +5 -5
- package/dist/web/server/{fleet-reasoning-panel-D_K48UOT-GN2PA6KT.js → fleet-reasoning-panel-BxC2COxi-GPLMQSTT.js} +9 -9
- package/dist/web/server/{fleet-subagent-list-5luKtpds-3OTVFHJQ.js → fleet-subagent-list-CpSYzCIq-JDH2LHSS.js} +1 -1
- package/dist/web/server/{fleet-tool-timeline-DwRqQgOj-HUFLGMDV.js → fleet-tool-timeline-IB36_PB2-XJENTO6I.js} +1 -1
- package/dist/web/server/{fork-picker-dialog-B9yGc8Au-IL63F2DN.js → fork-picker-dialog-DlINz9UQ-UWIXFDJX.js} +3 -3
- package/dist/web/server/{model-selector-list-cb2-ewoA-KIVU6LD3.js → model-selector-list-jBTZc2Mu-OXJOS5NA.js} +7 -7
- package/dist/web/server/{openui-renderer-Czy5Vo2L-BLXPJD65.js → openui-renderer-Biyyjhjn-SJOEKPTJ.js} +4 -4
- package/dist/web/server/{prompt-suggestions-BOmHi4-J-C563CHFU.js → prompt-suggestions-D4AEEY7K-RZSP7PWV.js} +3 -3
- package/dist/web/server/{repl-panel-yyxhwe4c-7U6HXYPS.js → repl-panel-D5KsoJik-BQKO53JO.js} +9 -9
- package/dist/web/server/{resources-panel-j4fAIi9g-5C267IXV.js → resources-panel-CE5pD4vy-V5FXBTYC.js} +2 -2
- package/dist/web/server/{router-CgSWrAYc-5UBYSZTJ.js → router-DWALoX_M-I5CBL7FQ.js} +1461 -515
- package/dist/web/server/{routes-CP_BBhD0-BAWQYGKY.js → routes-BBVirYfL-5WXMOT7M.js} +908 -566
- package/dist/web/server/server.js +2 -2
- package/dist/web/server/{session-insights-panel-BHZyKDTo-LRMAMA3O.js → session-insights-panel-CUhdgvRt-VB2HUCQP.js} +4 -4
- package/dist/web/server/{settings-dialog-CxHe8nym-KKXDPTIW.js → settings-dialog-DndPbM-v-RFNXXEAN.js} +902 -575
- package/dist/web/server/{subagent-chat-panel-DlSsM59d-DBW7DI3T.js → subagent-chat-panel-C0RpnXav-J7VYO7QY.js} +11 -11
- package/dist/web/server/{subagents-panel-Txzk8oDb-NRKLASYN.js → subagents-panel-jDqIn9Nh-YEV6QLUY.js} +13 -13
- package/dist/web/server/{workspace-panel-BOs-58Cv-SWQBMZSB.js → workspace-panel-CX_Vo6As-EWO6AMPI.js} +5 -4
- package/package.json +1 -1
- package/dist/web/client/assets/agent-activity-CDcDNVC6.js +0 -1
- package/dist/web/client/assets/artifacts-panel-CObI-DMt.js +0 -1
- package/dist/web/client/assets/chat-C8XDWWXz.js +0 -52
- package/dist/web/client/assets/fleet-message-queue-zWM5-y18.js +0 -1
- package/dist/web/client/assets/fleet-reasoning-panel-MtbSdoCv.js +0 -1
- package/dist/web/client/assets/fleet-tool-timeline-COzPrwr8.js +0 -1
- package/dist/web/client/assets/generative-text-renderer-CDKHv-v_.js +0 -6
- package/dist/web/client/assets/globals-DisQPFtV.css +0 -2
- package/dist/web/client/assets/horizontal-resize-Bl3AyBJg.js +0 -1
- package/dist/web/client/assets/input-group-BFDsCVS9.js +0 -1
- package/dist/web/client/assets/model-selector-list-DQaPFUYt.js +0 -1
- package/dist/web/client/assets/prompt-input-DZ4cho_e.js +0 -1
- package/dist/web/client/assets/prompt-suggestions-CXM6knMK.js +0 -1
- package/dist/web/client/assets/repl-panel-BDQ5MEgV.js +0 -1
- package/dist/web/client/assets/right-panel-registry-VVRPktV3.js +0 -2
- package/dist/web/client/assets/routes-DAikUNzO.js +0 -16
- package/dist/web/client/assets/session-insights-panel-CQdT90Op.js +0 -1
- package/dist/web/client/assets/settings-dialog-DS64KmwC.js +0 -1
- package/dist/web/client/assets/skeleton-loaders-DjGv9LLA.js +0 -1
- package/dist/web/client/assets/subagent-transcript-cxVKYnh9.js +0 -1
- package/dist/web/client/assets/subagents-panel-CHC96I68.js +0 -1
- package/dist/web/client/assets/tool-result-Baj3CdL_.js +0 -4
- package/dist/web/client/assets/ui-preferences-DUEFuJFj.js +0 -1
- package/dist/web/server/chunk-QK4CHLVV.js +0 -17
- package/dist/web/server/fleet-message-queue-BxycG26e-2XLOTCLP.js +0 -75
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ChatMcpDeleteRequestSchema,
|
|
3
|
+
ChatMcpOAuthLoginRequestSchema,
|
|
4
|
+
ChatMcpUpsertRequestSchema,
|
|
2
5
|
ChatModelsDiscoverRequestSchema,
|
|
3
6
|
ChatProviderOAuthLoginRequestSchema,
|
|
4
7
|
ChatProviderRemoveRequestSchema,
|
|
@@ -12,18 +15,21 @@ import {
|
|
|
12
15
|
domAnimation,
|
|
13
16
|
initAnalytics,
|
|
14
17
|
isServer
|
|
15
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-EH4BZ6QM.js";
|
|
16
19
|
import {
|
|
17
20
|
DEFAULT_UI_PREFERENCES,
|
|
18
21
|
isModelPatternEnabled,
|
|
19
22
|
readUiPreferences
|
|
20
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-ETTDO4UO.js";
|
|
21
24
|
import {
|
|
22
25
|
Toaster
|
|
23
26
|
} from "./chunk-KOUEJ3NU.js";
|
|
24
27
|
import {
|
|
28
|
+
fallbackSessionLabel,
|
|
29
|
+
meaningfulSessionLabel,
|
|
25
30
|
redactSessionLabelSecrets
|
|
26
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-PTCKOR23.js";
|
|
32
|
+
import "./chunk-SZJUXVWG.js";
|
|
27
33
|
import "./chunk-TNL4YV63.js";
|
|
28
34
|
import {
|
|
29
35
|
drag,
|
|
@@ -36,7 +42,7 @@ import {
|
|
|
36
42
|
CardHeader,
|
|
37
43
|
CardTitle,
|
|
38
44
|
validateAndNormalizeOpenUIHtmlArtifact
|
|
39
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-EAE2QXRK.js";
|
|
40
46
|
import {
|
|
41
47
|
ChatNewRequestSchema,
|
|
42
48
|
ChatOpenUIArtifactUpsertRequestSchema,
|
|
@@ -54,8 +60,9 @@ import {
|
|
|
54
60
|
ProjectRenameRequestSchema,
|
|
55
61
|
SessionIdSchema,
|
|
56
62
|
UploadedAttachmentSchema,
|
|
63
|
+
ZodError,
|
|
57
64
|
external_exports
|
|
58
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-YNUWKMNQ.js";
|
|
59
66
|
import {
|
|
60
67
|
KNOWN_PROVIDERS,
|
|
61
68
|
OPENAI_CHAT_COMPLETIONS_PROVIDER_ID,
|
|
@@ -89,7 +96,7 @@ import "./chunk-JDCCC7A7.js";
|
|
|
89
96
|
import "./chunk-L547YHC4.js";
|
|
90
97
|
import "./chunk-MLKGABMK.js";
|
|
91
98
|
|
|
92
|
-
// web/app/dist/server/assets/router-
|
|
99
|
+
// web/app/dist/server/assets/router-DWALoX_M.js
|
|
93
100
|
import { useEffect, useLayoutEffect } from "react";
|
|
94
101
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
95
102
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
@@ -123,7 +130,8 @@ function NotFoundPage({ title = "404", description = "The requested page could n
|
|
|
123
130
|
})
|
|
124
131
|
});
|
|
125
132
|
}
|
|
126
|
-
var globals_default = "/assets/globals-
|
|
133
|
+
var globals_default = "/assets/globals-B_I1Eq1u.css";
|
|
134
|
+
var inter_latin_wght_normal_default = "/assets/inter-latin-wght-normal-Dx4kXJAl.woff2";
|
|
127
135
|
function makeQueryClient() {
|
|
128
136
|
return new QueryClient({ defaultOptions: { queries: {
|
|
129
137
|
staleTime: 6e4,
|
|
@@ -137,7 +145,7 @@ function getQueryClient() {
|
|
|
137
145
|
if (!browserQueryClient) browserQueryClient = makeQueryClient();
|
|
138
146
|
return browserQueryClient;
|
|
139
147
|
}
|
|
140
|
-
var Route$
|
|
148
|
+
var Route$29 = createRootRoute({
|
|
141
149
|
head: () => ({
|
|
142
150
|
meta: [
|
|
143
151
|
{ charSet: "utf-8" },
|
|
@@ -152,6 +160,13 @@ var Route$27 = createRootRoute({
|
|
|
152
160
|
rel: "stylesheet",
|
|
153
161
|
href: globals_default
|
|
154
162
|
},
|
|
163
|
+
{
|
|
164
|
+
rel: "preload",
|
|
165
|
+
href: inter_latin_wght_normal_default,
|
|
166
|
+
as: "font",
|
|
167
|
+
type: "font/woff2",
|
|
168
|
+
crossOrigin: "anonymous"
|
|
169
|
+
},
|
|
155
170
|
{
|
|
156
171
|
rel: "icon",
|
|
157
172
|
href: "/favicon-dark.svg",
|
|
@@ -200,8 +215,8 @@ function RootDocument({ children }) {
|
|
|
200
215
|
] })]
|
|
201
216
|
});
|
|
202
217
|
}
|
|
203
|
-
var $$splitComponentImporter = () => import("./routes-
|
|
204
|
-
var Route$
|
|
218
|
+
var $$splitComponentImporter = () => import("./routes-BBVirYfL-5WXMOT7M.js");
|
|
219
|
+
var Route$28 = createFileRoute("/")({ component: lazyRouteComponent($$splitComponentImporter, "component") });
|
|
205
220
|
var ManagedAttachmentValidationError = class extends Error {
|
|
206
221
|
status;
|
|
207
222
|
constructor(message, status) {
|
|
@@ -1950,6 +1965,34 @@ var defaultPersistence = {
|
|
|
1950
1965
|
};
|
|
1951
1966
|
var TOKEN_TTL_MS = 6e5;
|
|
1952
1967
|
var MAX_DIRECTORY_ENTRIES = 200;
|
|
1968
|
+
var SENSITIVE_HOME_DIRECTORY_NAMES = [
|
|
1969
|
+
".ssh",
|
|
1970
|
+
".gnupg",
|
|
1971
|
+
".aws",
|
|
1972
|
+
".pki",
|
|
1973
|
+
".docker",
|
|
1974
|
+
".kube",
|
|
1975
|
+
".azure",
|
|
1976
|
+
".gcloud",
|
|
1977
|
+
".gsutil",
|
|
1978
|
+
".password-store",
|
|
1979
|
+
".config/gh"
|
|
1980
|
+
];
|
|
1981
|
+
function isSameOrWithin(candidate, ancestor) {
|
|
1982
|
+
return candidate === ancestor || candidate.startsWith(`${ancestor}${sep}`);
|
|
1983
|
+
}
|
|
1984
|
+
async function assertAllowedProjectDirectory(canonical) {
|
|
1985
|
+
if (dirname(canonical) === canonical) throw new Error("Project path must not be a filesystem root");
|
|
1986
|
+
const home = await realpath(homedir()).catch(() => homedir());
|
|
1987
|
+
if (canonical === home) throw new Error("Project path must not be the home directory");
|
|
1988
|
+
for (const name of SENSITIVE_HOME_DIRECTORY_NAMES) if (isSameOrWithin(canonical, join(home, name))) throw new Error("Project path must not be a credentials directory");
|
|
1989
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
1990
|
+
if (xdgConfigHome && isAbsolute(xdgConfigHome)) {
|
|
1991
|
+
const canonicalConfigHome = await realpath(xdgConfigHome).catch(() => resolve(xdgConfigHome));
|
|
1992
|
+
if (isSameOrWithin(canonical, join(canonicalConfigHome, "gh"))) throw new Error("Project path must not be a credentials directory");
|
|
1993
|
+
}
|
|
1994
|
+
if (isSameOrWithin(canonical, await realpath("/etc").catch(() => "/etc"))) throw new Error("Project path must not be a system directory");
|
|
1995
|
+
}
|
|
1953
1996
|
var ProjectRegistryPersistenceError = class extends Error {
|
|
1954
1997
|
constructor(operation, cause) {
|
|
1955
1998
|
super(`Could not ${operation}. Please try again.`, { cause });
|
|
@@ -2047,6 +2090,7 @@ var ProjectRegistry = class {
|
|
|
2047
2090
|
if (!candidate || !isAbsolute(candidate)) throw new Error("Project path must be absolute");
|
|
2048
2091
|
const canonical = await realpath(candidate);
|
|
2049
2092
|
if (!(await stat(canonical)).isDirectory()) throw new Error("Project path must be a directory");
|
|
2093
|
+
await assertAllowedProjectDirectory(canonical);
|
|
2050
2094
|
return canonical;
|
|
2051
2095
|
}
|
|
2052
2096
|
#findByPath(canonicalPath) {
|
|
@@ -2167,7 +2211,7 @@ var ProjectRegistry = class {
|
|
|
2167
2211
|
if (options.token) {
|
|
2168
2212
|
const token = this.#directoryTokens.get(options.token);
|
|
2169
2213
|
if (!token || token.expiresAt < Date.now()) throw new Error("Directory token expired");
|
|
2170
|
-
path = token.path;
|
|
2214
|
+
path = await this.#canonicalDirectory(token.path);
|
|
2171
2215
|
} else path = await this.#canonicalDirectory(options.path ?? this.#initialPath);
|
|
2172
2216
|
const entries = await readdir(path, { withFileTypes: true });
|
|
2173
2217
|
const directories = [];
|
|
@@ -4689,6 +4733,13 @@ function fallbackSessionPath(connectionState, cwd) {
|
|
|
4689
4733
|
const sessionDir = connectionState.sessionDir ?? sessionDirectoryForCwd(cwd);
|
|
4690
4734
|
return resolve(sessionDir, `${connectionState.sessionId}.jsonl`);
|
|
4691
4735
|
}
|
|
4736
|
+
var SessionExportPathError = class extends Error {
|
|
4737
|
+
status = 400;
|
|
4738
|
+
constructor() {
|
|
4739
|
+
super("Export path must stay inside the session project directory");
|
|
4740
|
+
this.name = "SessionExportPathError";
|
|
4741
|
+
}
|
|
4742
|
+
};
|
|
4692
4743
|
function findSessionTreeEntry(nodes, entryId) {
|
|
4693
4744
|
for (const node of nodes) {
|
|
4694
4745
|
if (node.entry.id === entryId) return node.entry;
|
|
@@ -5094,10 +5145,7 @@ var PrimeBridge = class {
|
|
|
5094
5145
|
async resumeSessionById(sessionId, requestedProjectId, options) {
|
|
5095
5146
|
const live = this.#sessions.get(sessionId);
|
|
5096
5147
|
if (live) {
|
|
5097
|
-
if (requestedProjectId && live.projectId !== requestedProjectId)
|
|
5098
|
-
const forkedId = await this.forkSessionIntoProject(sessionId, requestedProjectId);
|
|
5099
|
-
return this.#requireSession(forkedId);
|
|
5100
|
-
}
|
|
5148
|
+
if (requestedProjectId && live.projectId !== requestedProjectId) return void 0;
|
|
5101
5149
|
return live;
|
|
5102
5150
|
}
|
|
5103
5151
|
const match = (await this.#sessionLister()).find((info) => info.sessionId === sessionId || info.id === sessionId);
|
|
@@ -5110,10 +5158,7 @@ var PrimeBridge = class {
|
|
|
5110
5158
|
if (isSessionNotResumableError(error)) return void 0;
|
|
5111
5159
|
throw error;
|
|
5112
5160
|
}
|
|
5113
|
-
if (requestedProjectId && resumed.projectId !== requestedProjectId)
|
|
5114
|
-
const forkedId = await this.forkSessionIntoProject(resumed.sessionId, requestedProjectId);
|
|
5115
|
-
return this.#requireSession(forkedId);
|
|
5116
|
-
}
|
|
5161
|
+
if (requestedProjectId && resumed.projectId !== requestedProjectId) return void 0;
|
|
5117
5162
|
return resumed;
|
|
5118
5163
|
}
|
|
5119
5164
|
async listSessions(cwd) {
|
|
@@ -5586,9 +5631,14 @@ var PrimeBridge = class {
|
|
|
5586
5631
|
async followUp(sessionId, text) {
|
|
5587
5632
|
await this.#requireSession(sessionId).connection.followUp(text);
|
|
5588
5633
|
}
|
|
5589
|
-
async
|
|
5634
|
+
async mutateQueuedMessage(sessionId, lane, index, expectedText, mutation) {
|
|
5590
5635
|
const session = this.#requireSession(sessionId);
|
|
5591
|
-
const
|
|
5636
|
+
const upstreamMutation = mutation.type === "delete" ? { type: "delete" } : {
|
|
5637
|
+
type: "replace",
|
|
5638
|
+
text: mutation.text,
|
|
5639
|
+
lane: mutation.lane ?? lane
|
|
5640
|
+
};
|
|
5641
|
+
const status = await session.connection.mutateQueuedMessage(lane, index, expectedText, upstreamMutation);
|
|
5592
5642
|
const queue = await session.connection.getQueue();
|
|
5593
5643
|
return {
|
|
5594
5644
|
status,
|
|
@@ -5598,6 +5648,9 @@ var PrimeBridge = class {
|
|
|
5598
5648
|
}
|
|
5599
5649
|
};
|
|
5600
5650
|
}
|
|
5651
|
+
async deleteQueuedMessage(sessionId, lane, index, expectedText) {
|
|
5652
|
+
return this.mutateQueuedMessage(sessionId, lane, index, expectedText, { type: "delete" });
|
|
5653
|
+
}
|
|
5601
5654
|
async abort(sessionId) {
|
|
5602
5655
|
const session = this.#requireSession(sessionId);
|
|
5603
5656
|
this.#dialogs.cancelAll(sessionId, "user-abort");
|
|
@@ -5714,15 +5767,43 @@ var PrimeBridge = class {
|
|
|
5714
5767
|
/** /export — write the session to HTML (default) or JSONL (path ends with .jsonl). */
|
|
5715
5768
|
async exportSession(sessionId, outputPath) {
|
|
5716
5769
|
const session = this.#requireSession(sessionId);
|
|
5770
|
+
const confinedPath = await this.#confineExportPath(session, outputPath);
|
|
5717
5771
|
if (outputPath?.endsWith(".jsonl")) return {
|
|
5718
|
-
path: await session.connection.exportToJsonl(
|
|
5772
|
+
path: await session.connection.exportToJsonl(confinedPath),
|
|
5719
5773
|
format: "jsonl"
|
|
5720
5774
|
};
|
|
5721
5775
|
return {
|
|
5722
|
-
path: await session.connection.exportToHtml(
|
|
5776
|
+
path: await session.connection.exportToHtml(confinedPath),
|
|
5723
5777
|
format: "html"
|
|
5724
5778
|
};
|
|
5725
5779
|
}
|
|
5780
|
+
/**
|
|
5781
|
+
* Confine an explicit /export path inside the session's project directory
|
|
5782
|
+
* (the connection's live cwd). Absolute paths and `..` escapes that leave
|
|
5783
|
+
* the directory throw a 400-status error; an omitted path passes through
|
|
5784
|
+
* untouched so the default export location is unchanged.
|
|
5785
|
+
*/
|
|
5786
|
+
async #confineExportPath(session, outputPath) {
|
|
5787
|
+
if (outputPath === void 0) return void 0;
|
|
5788
|
+
const { cwd } = await session.connection.getState();
|
|
5789
|
+
const root2 = resolve(cwd);
|
|
5790
|
+
const canonicalRoot = await realpath(root2).catch(() => root2);
|
|
5791
|
+
const candidate = resolve(root2, outputPath);
|
|
5792
|
+
const existingCandidate = await realpath(candidate).catch(() => void 0);
|
|
5793
|
+
if (existingCandidate && existingCandidate !== canonicalRoot && !existingCandidate.startsWith(`${canonicalRoot}${sep}`)) throw new SessionExportPathError();
|
|
5794
|
+
let ancestor = dirname(candidate);
|
|
5795
|
+
while (true) {
|
|
5796
|
+
const resolvedAncestor = await realpath(ancestor).catch(() => void 0);
|
|
5797
|
+
if (resolvedAncestor) {
|
|
5798
|
+
if (resolvedAncestor !== canonicalRoot && !resolvedAncestor.startsWith(`${canonicalRoot}${sep}`)) throw new SessionExportPathError();
|
|
5799
|
+
break;
|
|
5800
|
+
}
|
|
5801
|
+
const parent = dirname(ancestor);
|
|
5802
|
+
if (parent === ancestor) throw new SessionExportPathError();
|
|
5803
|
+
ancestor = parent;
|
|
5804
|
+
}
|
|
5805
|
+
return candidate;
|
|
5806
|
+
}
|
|
5726
5807
|
/** /reload — re-scan keybindings, extensions, skills, prompts, themes. */
|
|
5727
5808
|
async reloadResources(_sessionId) {
|
|
5728
5809
|
await Promise.all([...this.#sessions.values()].map((session) => session.connection.reload?.()));
|
|
@@ -5815,9 +5896,9 @@ var PrimeBridge = class {
|
|
|
5815
5896
|
}
|
|
5816
5897
|
/** Fork the complete persisted history into another registered project. */
|
|
5817
5898
|
async forkSessionIntoProject(sessionId, targetProjectId) {
|
|
5899
|
+
const targetCwd = await getPrimeConfig().projectRegistry.cwdForProject(targetProjectId);
|
|
5818
5900
|
const source = this.#sessions.get(sessionId) ?? await this.resumeSessionById(sessionId);
|
|
5819
5901
|
if (!source) throw new Error(`Unknown session: ${sessionId}`);
|
|
5820
|
-
const targetCwd = await getPrimeConfig().projectRegistry.cwdForProject(targetProjectId);
|
|
5821
5902
|
await source.connection.waitForIdle();
|
|
5822
5903
|
const sourceState = await source.connection.getState();
|
|
5823
5904
|
const sourcePath = sourceState.sessionFile;
|
|
@@ -5838,7 +5919,7 @@ var PrimeBridge = class {
|
|
|
5838
5919
|
await copyManagedPlanPresentationsForFork(source, forked, (await this.getMessages(forked.sessionId)).length);
|
|
5839
5920
|
forked.mapperState.presentation = source.mapperState.presentation;
|
|
5840
5921
|
this.#persistPresentation(forked.sessionId, forked.sessionPath, forked.mapperState.presentation);
|
|
5841
|
-
return forked.sessionId;
|
|
5922
|
+
return this.#requireProjectSession(forked.sessionId, targetProjectId).sessionId;
|
|
5842
5923
|
}
|
|
5843
5924
|
/** Reads message history from a live session, or from the JSONL transcript for a cold session. */
|
|
5844
5925
|
async getMessages(sessionId) {
|
|
@@ -5880,6 +5961,17 @@ var PrimeBridge = class {
|
|
|
5880
5961
|
if (!session) throw new Error(`Unknown session: ${sessionId}`);
|
|
5881
5962
|
return session;
|
|
5882
5963
|
}
|
|
5964
|
+
/**
|
|
5965
|
+
* Project-membership gate over the bridge's session records. Returns the
|
|
5966
|
+
* live session only when its project linkage matches the caller-asserted
|
|
5967
|
+
* project, and throws `Unknown session` otherwise so foreign sessions are
|
|
5968
|
+
* indistinguishable from missing ones.
|
|
5969
|
+
*/
|
|
5970
|
+
#requireProjectSession(sessionId, projectId) {
|
|
5971
|
+
const session = this.#requireSession(sessionId);
|
|
5972
|
+
if (session.projectId !== projectId) throw new Error(`Unknown session: ${sessionId}`);
|
|
5973
|
+
return session;
|
|
5974
|
+
}
|
|
5883
5975
|
};
|
|
5884
5976
|
var globalStore = globalThis;
|
|
5885
5977
|
function getBridge() {
|
|
@@ -5890,7 +5982,20 @@ function getBridge() {
|
|
|
5890
5982
|
});
|
|
5891
5983
|
return globalStore.__primeBridge;
|
|
5892
5984
|
}
|
|
5985
|
+
function isLoopbackHostname(hostname) {
|
|
5986
|
+
const host = hostname.toLowerCase().replace(/\.$/, "");
|
|
5987
|
+
if (host === "localhost") return true;
|
|
5988
|
+
const bare = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
5989
|
+
const mapped = bare.startsWith("::ffff:") ? bare.slice(7) : bare;
|
|
5990
|
+
if (mapped === "::1" || mapped === "0:0:0:0:0:0:0:1") return true;
|
|
5991
|
+
if (mapped.startsWith("127.")) {
|
|
5992
|
+
const parts = mapped.split(".");
|
|
5993
|
+
if (parts.length === 4 && parts.every((p) => /^\d{1,3}$/.test(p) && Number(p) <= 255)) return true;
|
|
5994
|
+
}
|
|
5995
|
+
return false;
|
|
5996
|
+
}
|
|
5893
5997
|
function getResponseStatus(error) {
|
|
5998
|
+
if (error instanceof ZodError || error instanceof Error && error.name === "ZodError") return 422;
|
|
5894
5999
|
if (error && typeof error === "object" && "status" in error) {
|
|
5895
6000
|
const status = error.status;
|
|
5896
6001
|
if (typeof status === "number" && status >= 400 && status < 600) return status;
|
|
@@ -5907,8 +6012,14 @@ function getErrorMessage(error) {
|
|
|
5907
6012
|
}
|
|
5908
6013
|
}
|
|
5909
6014
|
function safeErrorMessage(error) {
|
|
5910
|
-
|
|
6015
|
+
const message = getErrorMessage(error);
|
|
6016
|
+
return SECRET_PATTERNS.reduce((scrubbed, [pattern, replacement]) => scrubbed.replace(pattern, replacement), message.replace(/(['"])(\/(?!\/)[^'"\n]*|[A-Za-z]:\\[^'"\n]*)\1/g, "$1[local path]$1").replace(/(^|[\s'"(])\/(?!\/)[^'"\s)]+/g, "$1[local path]").replace(/[A-Za-z]:\\[^'"\s)]+/g, "[local path]"));
|
|
5911
6017
|
}
|
|
6018
|
+
var SECRET_PATTERNS = [
|
|
6019
|
+
[/\b(bearer\s+)[A-Za-z0-9\-._~+/=]{8,}/gi, "$1[redacted]"],
|
|
6020
|
+
[/(api[_-]?key\s*[:=]\s*)["']?[^"'\s;,]+["']?/gi, "$1[redacted]"],
|
|
6021
|
+
[/\bkey(\s*=\s*)[^"'\s;&,]+/gi, "key$1[redacted]"]
|
|
6022
|
+
];
|
|
5912
6023
|
var DAEMON_DISCONNECT_PATTERNS = [/cannot send daemon command/i, /daemon is not connected/i];
|
|
5913
6024
|
function isDaemonDisconnectError(error) {
|
|
5914
6025
|
const message = getErrorMessage(error);
|
|
@@ -5928,14 +6039,43 @@ function chatErrorEnvelope(error) {
|
|
|
5928
6039
|
message: safeErrorMessage(error)
|
|
5929
6040
|
};
|
|
5930
6041
|
}
|
|
5931
|
-
function
|
|
6042
|
+
function isOriginAllowed(request) {
|
|
6043
|
+
const origin = request.headers.get("origin");
|
|
6044
|
+
if (!origin) return true;
|
|
6045
|
+
let originUrl;
|
|
6046
|
+
try {
|
|
6047
|
+
originUrl = new URL(origin);
|
|
6048
|
+
} catch {
|
|
6049
|
+
return false;
|
|
6050
|
+
}
|
|
6051
|
+
if (isLoopbackHostname(originUrl.hostname)) return true;
|
|
6052
|
+
try {
|
|
6053
|
+
return originUrl.host.toLowerCase() === new URL(request.url).host.toLowerCase();
|
|
6054
|
+
} catch {
|
|
6055
|
+
return true;
|
|
6056
|
+
}
|
|
6057
|
+
}
|
|
6058
|
+
function wrapApiHandler(handler, request) {
|
|
6059
|
+
if (request && request.method.toUpperCase() !== "GET" && !isOriginAllowed(request)) return Promise.resolve(Response.json({
|
|
6060
|
+
code: "UNKNOWN_ERROR",
|
|
6061
|
+
message: "Cross-origin request rejected."
|
|
6062
|
+
}, { status: 403 }));
|
|
5932
6063
|
return handler().catch((error) => {
|
|
5933
6064
|
const envelope = chatErrorEnvelope(error);
|
|
5934
|
-
if (envelope.code === "NETWORK_DISCONNECTED") process.stderr.write(`[api] daemon transport failure: ${
|
|
6065
|
+
if (envelope.code === "NETWORK_DISCONNECTED") process.stderr.write(`[api] daemon transport failure: ${safeErrorMessage(error)}
|
|
5935
6066
|
`);
|
|
5936
6067
|
return Response.json(envelope, { status: getResponseStatus(error) });
|
|
5937
6068
|
});
|
|
5938
6069
|
}
|
|
6070
|
+
async function requireProjectSession(session) {
|
|
6071
|
+
if (!session?.projectId) return false;
|
|
6072
|
+
try {
|
|
6073
|
+
await getPrimeConfig().projectRegistry.get(session.projectId);
|
|
6074
|
+
} catch {
|
|
6075
|
+
return false;
|
|
6076
|
+
}
|
|
6077
|
+
return true;
|
|
6078
|
+
}
|
|
5939
6079
|
function resolveChatStreamingBehavior(streamingBehavior) {
|
|
5940
6080
|
return streamingBehavior ?? "steer";
|
|
5941
6081
|
}
|
|
@@ -5944,7 +6084,8 @@ function chooseChatStartId(mapperState, streamingBehavior, sessionIsStreaming =
|
|
|
5944
6084
|
return crypto.randomUUID();
|
|
5945
6085
|
}
|
|
5946
6086
|
async function handleChatChildPost(bridge, parentSessionId, childId, message, streamingBehavior) {
|
|
5947
|
-
|
|
6087
|
+
const session = bridge.getSession(parentSessionId) ?? await bridge.resumeSessionById(parentSessionId, void 0, {});
|
|
6088
|
+
if (!session || !await requireProjectSession(session)) return Response.json({ message: `Unknown session: ${parentSessionId}` }, { status: 404 });
|
|
5948
6089
|
const encoder = new TextEncoder();
|
|
5949
6090
|
const stream = new ReadableStream({ start(controller) {
|
|
5950
6091
|
let closed = false;
|
|
@@ -6032,7 +6173,7 @@ function handleChatPost(request) {
|
|
|
6032
6173
|
if (process.env.PRIME_BRIDGE_DEBUG === "1") process.stderr.write(`[chat] received session=${targetSessionId.slice(0, 8)} bytes=${message.length}
|
|
6033
6174
|
`);
|
|
6034
6175
|
const session = bridge.getSession(targetSessionId) ?? await bridge.resumeSessionById(targetSessionId, void 0, { openUI });
|
|
6035
|
-
if (!session) return Response.json({ message: `Unknown session: ${targetSessionId}` }, { status: 404 });
|
|
6176
|
+
if (!session || !await requireProjectSession(session)) return Response.json({ message: `Unknown session: ${targetSessionId}` }, { status: 404 });
|
|
6036
6177
|
const uploadAttachments = (body.attachments ?? []).filter((attachment) => attachment.kind === "upload");
|
|
6037
6178
|
let uploadInspections;
|
|
6038
6179
|
try {
|
|
@@ -6186,7 +6327,7 @@ ${attachmentContext.join("\n\n")}` : message;
|
|
|
6186
6327
|
Connection: "keep-alive",
|
|
6187
6328
|
"X-Accel-Buffering": "no"
|
|
6188
6329
|
} });
|
|
6189
|
-
});
|
|
6330
|
+
}, request);
|
|
6190
6331
|
}
|
|
6191
6332
|
var BodySchema$3 = external_exports.object({
|
|
6192
6333
|
sessionId: SessionIdSchema.optional(),
|
|
@@ -6199,6 +6340,7 @@ function handleChatAbortPost(request) {
|
|
|
6199
6340
|
const sessionId = body.sessionId;
|
|
6200
6341
|
if (!sessionId) return Response.json({ message: "abort requires sessionId" }, { status: 400 });
|
|
6201
6342
|
const bridge = getBridge();
|
|
6343
|
+
if (!await requireProjectSession(bridge.getSession(sessionId) ?? await bridge.resumeSessionById(sessionId))) return Response.json({ message: `Unknown session: ${sessionId}` }, { status: 404 });
|
|
6202
6344
|
if (body.childId) {
|
|
6203
6345
|
if (!await bridge.abortRlmChild(sessionId, body.childId)) return Response.json({ message: `No active subagent turn: ${body.childId}` }, { status: 404 });
|
|
6204
6346
|
return Response.json({
|
|
@@ -6212,13 +6354,33 @@ function handleChatAbortPost(request) {
|
|
|
6212
6354
|
ok: true,
|
|
6213
6355
|
sessionId
|
|
6214
6356
|
});
|
|
6215
|
-
});
|
|
6357
|
+
}, request);
|
|
6216
6358
|
}
|
|
6217
6359
|
var AttachmentIdSchema = external_exports.uuid();
|
|
6218
6360
|
var ATTACHMENT_WRITE_CONCURRENCY = 8;
|
|
6361
|
+
function isSafeRasterImage(mimeType, data) {
|
|
6362
|
+
if (mimeType === "image/png") return data.length >= 8 && data.subarray(0, 8).every((byte, index) => byte === [
|
|
6363
|
+
137,
|
|
6364
|
+
80,
|
|
6365
|
+
78,
|
|
6366
|
+
71,
|
|
6367
|
+
13,
|
|
6368
|
+
10,
|
|
6369
|
+
26,
|
|
6370
|
+
10
|
|
6371
|
+
][index]);
|
|
6372
|
+
if (mimeType === "image/jpeg") return data.length >= 3 && data[0] === 255 && data[1] === 216 && data[2] === 255;
|
|
6373
|
+
if (mimeType === "image/gif") {
|
|
6374
|
+
const header = new TextDecoder().decode(data.subarray(0, 6));
|
|
6375
|
+
return header === "GIF87a" || header === "GIF89a";
|
|
6376
|
+
}
|
|
6377
|
+
return mimeType === "image/webp" && data.length >= 12 && new TextDecoder().decode(data.subarray(0, 4)) === "RIFF" && new TextDecoder().decode(data.subarray(8, 12)) === "WEBP";
|
|
6378
|
+
}
|
|
6219
6379
|
async function resolveSession(sessionId) {
|
|
6220
6380
|
const bridge = getBridge();
|
|
6221
|
-
|
|
6381
|
+
const session = bridge.getSession(sessionId) ?? await bridge.resumeSessionById(sessionId);
|
|
6382
|
+
if (!await requireProjectSession(session)) return void 0;
|
|
6383
|
+
return session;
|
|
6222
6384
|
}
|
|
6223
6385
|
function handleChatAttachmentsPost(request) {
|
|
6224
6386
|
return wrapApiHandler(async () => {
|
|
@@ -6241,7 +6403,7 @@ function handleChatAttachmentsPost(request) {
|
|
|
6241
6403
|
}
|
|
6242
6404
|
const attachments = settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
6243
6405
|
return Response.json({ attachments });
|
|
6244
|
-
});
|
|
6406
|
+
}, request);
|
|
6245
6407
|
}
|
|
6246
6408
|
function handleChatAttachmentGet(request) {
|
|
6247
6409
|
return wrapApiHandler(async () => {
|
|
@@ -6252,18 +6414,19 @@ function handleChatAttachmentGet(request) {
|
|
|
6252
6414
|
if (!session) return Response.json({ message: `Unknown session: ${sessionId}` }, { status: 404 });
|
|
6253
6415
|
const attachment = await readManagedAttachment(session, attachmentId).catch(() => void 0);
|
|
6254
6416
|
if (!attachment) return Response.json({ message: "Attachment not found" }, { status: 404 });
|
|
6417
|
+
const safeRasterImage = isSafeRasterImage(attachment.metadata.mimeType, attachment.data);
|
|
6255
6418
|
return new Response(attachment.data, { headers: {
|
|
6256
|
-
"Content-Type": attachment.metadata.mimeType,
|
|
6257
|
-
"Content-Disposition": `
|
|
6419
|
+
"Content-Type": safeRasterImage ? attachment.metadata.mimeType : "application/octet-stream",
|
|
6420
|
+
...safeRasterImage ? {} : { "Content-Disposition": `attachment; filename*=UTF-8''${encodeURIComponent(attachment.metadata.name)}` },
|
|
6258
6421
|
"Cache-Control": "private, no-store",
|
|
6259
6422
|
"X-Content-Type-Options": "nosniff"
|
|
6260
6423
|
} });
|
|
6261
|
-
});
|
|
6424
|
+
}, request);
|
|
6262
6425
|
}
|
|
6263
6426
|
var BodySchema$2 = external_exports.object({
|
|
6264
6427
|
sessionId: SessionIdSchema,
|
|
6265
6428
|
command: external_exports.string(),
|
|
6266
|
-
args: external_exports.string().optional()
|
|
6429
|
+
args: external_exports.string().max(1024).optional()
|
|
6267
6430
|
});
|
|
6268
6431
|
function handleChatCommandPost(request) {
|
|
6269
6432
|
return wrapApiHandler(async () => {
|
|
@@ -6338,7 +6501,7 @@ function handleChatCommandPost(request) {
|
|
|
6338
6501
|
default:
|
|
6339
6502
|
return Response.json({ message: `Unknown slash command: /${body.command}` }, { status: 404 });
|
|
6340
6503
|
}
|
|
6341
|
-
});
|
|
6504
|
+
}, request);
|
|
6342
6505
|
}
|
|
6343
6506
|
async function cwdForRequest(request) {
|
|
6344
6507
|
const projectIdParam = new URL(request.url).searchParams.get("projectId");
|
|
@@ -6556,7 +6719,7 @@ function handleChatCommandsGet(request) {
|
|
|
6556
6719
|
],
|
|
6557
6720
|
diagnostics
|
|
6558
6721
|
});
|
|
6559
|
-
});
|
|
6722
|
+
}, request);
|
|
6560
6723
|
}
|
|
6561
6724
|
function shouldReplaySseEvent(event, pendingQuestionIds) {
|
|
6562
6725
|
if (!pendingQuestionIds) return true;
|
|
@@ -6705,7 +6868,10 @@ function handleChatEventsGet(request) {
|
|
|
6705
6868
|
const childId = SessionIdSchema.safeParse(childIdParam);
|
|
6706
6869
|
if (!parentSessionId.success || !childId.success) return Response.json({ message: "Invalid subagent stream identifiers" }, { status: 400 });
|
|
6707
6870
|
if (streamGenerationParam !== null && !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(streamGenerationParam)) return Response.json({ message: "Invalid child stream generation" }, { status: 400 });
|
|
6708
|
-
const
|
|
6871
|
+
const bridge = getBridge();
|
|
6872
|
+
const parent = bridge.getSession(parentSessionId.data) ?? await bridge.resumeSessionById(parentSessionId.data);
|
|
6873
|
+
if (!parent || !await requireProjectSession(parent)) return Response.json({ message: "Unknown live subagent stream" }, { status: 404 });
|
|
6874
|
+
const childStream = await bridge.openRlmChildStream(parentSessionId.data, childId.data, {
|
|
6709
6875
|
...streamGenerationParam ? { streamGeneration: streamGenerationParam } : {},
|
|
6710
6876
|
lastEventId: lastEventIdFor(request, url)
|
|
6711
6877
|
});
|
|
@@ -6725,367 +6891,13 @@ function handleChatEventsGet(request) {
|
|
|
6725
6891
|
if (!sessionIdParam) return Response.json({ message: "SSE requires ?sessionId=" }, { status: 400 });
|
|
6726
6892
|
const sessionId = SessionIdSchema.safeParse(sessionIdParam);
|
|
6727
6893
|
if (!sessionId.success) return Response.json({ message: "Invalid session identifier" }, { status: 400 });
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
sessionId: SessionIdSchema,
|
|
6733
|
-
model: external_exports.object({
|
|
6734
|
-
provider: external_exports.string(),
|
|
6735
|
-
id: external_exports.string()
|
|
6736
|
-
})
|
|
6737
|
-
});
|
|
6738
|
-
function handleChatModelPost(request) {
|
|
6739
|
-
return wrapApiHandler(async () => {
|
|
6740
|
-
const raw = await request.json().catch(() => ({}));
|
|
6741
|
-
const body = BodySchema$1.parse(raw);
|
|
6742
|
-
await getBridge().setModel(body.sessionId, {
|
|
6743
|
-
provider: body.model.provider,
|
|
6744
|
-
id: body.model.id
|
|
6745
|
-
});
|
|
6746
|
-
return Response.json({ ok: true });
|
|
6747
|
-
});
|
|
6748
|
-
}
|
|
6749
|
-
function toPatternCandidate(model) {
|
|
6750
|
-
return {
|
|
6751
|
-
id: model.id,
|
|
6752
|
-
name: model.name,
|
|
6753
|
-
provider: model.provider,
|
|
6754
|
-
modelId: model.id,
|
|
6755
|
-
key: `${model.provider}/${model.id}`
|
|
6756
|
-
};
|
|
6757
|
-
}
|
|
6758
|
-
function handleChatModelsGet(request) {
|
|
6759
|
-
return wrapApiHandler(async () => {
|
|
6760
|
-
const config = getPrimeConfig();
|
|
6761
|
-
const cwd = await cwdForRequest(request);
|
|
6762
|
-
const settings = config.settingsFor(cwd);
|
|
6763
|
-
const registry = config.modelRegistry;
|
|
6764
|
-
const scope = new URL(request.url).searchParams.get("scope") === "all" ? "all" : "enabled";
|
|
6765
|
-
let models = registry.getAll();
|
|
6766
|
-
if (scope === "enabled") {
|
|
6767
|
-
models = models.filter((model) => registry.hasConfiguredAuth(model));
|
|
6768
|
-
const patterns = settings.getEnabledModels();
|
|
6769
|
-
if (patterns !== void 0) models = models.filter((model) => isModelPatternEnabled(toPatternCandidate(model), patterns));
|
|
6770
|
-
}
|
|
6771
|
-
const diagnostics = [];
|
|
6772
|
-
const defaultProvider = settings.getDefaultProvider();
|
|
6773
|
-
const defaultModel = settings.getDefaultModel();
|
|
6774
|
-
const defaultThinkingLevel = settings.getDefaultThinkingLevel();
|
|
6775
|
-
const selectedModelKey = defaultProvider && defaultModel ? `${defaultProvider}/${defaultModel}` : void 0;
|
|
6776
|
-
return Response.json({
|
|
6777
|
-
models: models.map((m) => {
|
|
6778
|
-
const thinkingLevels = getSupportedThinkingLevels(m);
|
|
6779
|
-
const fallback = m.reasoning ? "medium" : "off";
|
|
6780
|
-
return {
|
|
6781
|
-
key: `${m.provider}/${m.id}`,
|
|
6782
|
-
provider: m.provider,
|
|
6783
|
-
id: m.id,
|
|
6784
|
-
name: m.name,
|
|
6785
|
-
reasoning: m.reasoning,
|
|
6786
|
-
input: m.input,
|
|
6787
|
-
contextWindow: m.contextWindow,
|
|
6788
|
-
maxTokens: m.maxTokens,
|
|
6789
|
-
available: registry.hasConfiguredAuth(m),
|
|
6790
|
-
thinkingLevels,
|
|
6791
|
-
defaultThinkingLevel: thinkingLevels.includes(fallback) ? fallback : thinkingLevels[0] ?? "off"
|
|
6792
|
-
};
|
|
6793
|
-
}),
|
|
6794
|
-
...selectedModelKey ? { selectedModelKey } : {},
|
|
6795
|
-
...defaultProvider ? { defaultProvider } : {},
|
|
6796
|
-
...defaultModel ? { defaultModel } : {},
|
|
6797
|
-
...defaultThinkingLevel ? { defaultThinkingLevel } : {},
|
|
6798
|
-
diagnostics
|
|
6799
|
-
});
|
|
6800
|
-
});
|
|
6801
|
-
}
|
|
6802
|
-
function storedApiForCustomProvider(api) {
|
|
6803
|
-
return api === "google-genai" ? "google-generative-ai" : api;
|
|
6804
|
-
}
|
|
6805
|
-
function uiApiForCustomProvider(value) {
|
|
6806
|
-
if (value === "google-generative-ai") return "google-genai";
|
|
6807
|
-
return isPiCustomProviderApi(value) ? value : void 0;
|
|
6808
|
-
}
|
|
6809
|
-
function envVarNameForManagedProvider(providerId) {
|
|
6810
|
-
if (providerId === "openai-chat-completions") return "OPENAI_CHAT_COMPLETIONS_API_KEY";
|
|
6811
|
-
const slug = providerId.slice(providerId.indexOf("+") + 1).toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
6812
|
-
return isOccProviderId(providerId) ? `OPENAI_CHAT_COMPLETIONS_${slug}_API_KEY` : `CUSTOM_${slug}_API_KEY`;
|
|
6813
|
-
}
|
|
6814
|
-
function readModelsJson(filePath) {
|
|
6815
|
-
try {
|
|
6816
|
-
if (!existsSync(filePath)) return {};
|
|
6817
|
-
return parseModelsJson(readFileSync(filePath, "utf-8"));
|
|
6818
|
-
} catch {
|
|
6819
|
-
return {};
|
|
6820
|
-
}
|
|
6821
|
-
}
|
|
6822
|
-
function stripJsonComments(input) {
|
|
6823
|
-
return input.replace(/"(?:\\.|[^"\\])*"|\/\/[^\n]*/g, (match) => match[0] === '"' ? match : "").replace(/"(?:\\.|[^"\\])*"|,(\s*[}\]])/g, (match, tail) => tail ?? (match[0] === '"' ? match : ""));
|
|
6824
|
-
}
|
|
6825
|
-
function parseModelsJson(raw) {
|
|
6826
|
-
const parsed = JSON.parse(stripJsonComments(raw));
|
|
6827
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("models.json must contain an object");
|
|
6828
|
-
return parsed;
|
|
6829
|
-
}
|
|
6830
|
-
function readModelsJsonForWrite(filePath) {
|
|
6831
|
-
if (!existsSync(filePath)) return {};
|
|
6832
|
-
try {
|
|
6833
|
-
return parseModelsJson(readFileSync(filePath, "utf-8"));
|
|
6834
|
-
} catch (error) {
|
|
6835
|
-
throw new Error(`Refusing to update models.json because it could not be parsed: ${error instanceof Error ? error.message : error}`);
|
|
6836
|
-
}
|
|
6837
|
-
}
|
|
6838
|
-
function mergeModelDefinitions(existing, incoming) {
|
|
6839
|
-
const existingById = new Map((existing ?? []).map((model) => [model.id, model]));
|
|
6840
|
-
const seen = /* @__PURE__ */ new Set();
|
|
6841
|
-
return incoming.flatMap((model) => {
|
|
6842
|
-
if (seen.has(model.id)) return [];
|
|
6843
|
-
seen.add(model.id);
|
|
6844
|
-
return [{
|
|
6845
|
-
...existingById.get(model.id),
|
|
6846
|
-
...model
|
|
6847
|
-
}];
|
|
6848
|
-
});
|
|
6849
|
-
}
|
|
6850
|
-
function listCustomProviders(filePath) {
|
|
6851
|
-
return readModelsJson(filePath).providers ?? {};
|
|
6852
|
-
}
|
|
6853
|
-
function writeModelsJson(filePath, data) {
|
|
6854
|
-
mkdirSync(dirname(filePath), {
|
|
6855
|
-
recursive: true,
|
|
6856
|
-
mode: 448
|
|
6857
|
-
});
|
|
6858
|
-
const serialized = `${JSON.stringify(data, null, " ")}
|
|
6859
|
-
`;
|
|
6860
|
-
const tmpPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
6861
|
-
writeFileSync(tmpPath, serialized, "utf-8");
|
|
6862
|
-
renameSync(tmpPath, filePath);
|
|
6863
|
-
}
|
|
6864
|
-
function upsertCustomProvider(filePath, providerId, input) {
|
|
6865
|
-
const data = readModelsJsonForWrite(filePath);
|
|
6866
|
-
const providers = { ...data.providers ?? {} };
|
|
6867
|
-
const existing = providers[providerId] ?? {};
|
|
6868
|
-
providers[providerId] = {
|
|
6869
|
-
...existing,
|
|
6870
|
-
name: input.name ?? existing.name,
|
|
6871
|
-
baseUrl: input.baseUrl,
|
|
6872
|
-
api: storedApiForCustomProvider(input.api),
|
|
6873
|
-
apiKey: input.apiKey,
|
|
6874
|
-
models: mergeModelDefinitions(existing.models, input.models)
|
|
6875
|
-
};
|
|
6876
|
-
writeModelsJson(filePath, {
|
|
6877
|
-
...data,
|
|
6878
|
-
providers
|
|
6879
|
-
});
|
|
6880
|
-
}
|
|
6881
|
-
function addCustomProviderModelIds(filePath, providerId, modelIds) {
|
|
6882
|
-
const data = readModelsJsonForWrite(filePath);
|
|
6883
|
-
const providers = { ...data.providers ?? {} };
|
|
6884
|
-
const existing = providers[providerId];
|
|
6885
|
-
if (!existing) return;
|
|
6886
|
-
providers[providerId] = {
|
|
6887
|
-
...existing,
|
|
6888
|
-
models: mergeModelDefinitions(existing.models, [...existing.models ?? [], ...modelIds.map((id) => ({ id }))])
|
|
6889
|
-
};
|
|
6890
|
-
writeModelsJson(filePath, {
|
|
6891
|
-
...data,
|
|
6892
|
-
providers
|
|
6893
|
-
});
|
|
6894
|
-
}
|
|
6895
|
-
function removeCustomProvider(filePath, providerId) {
|
|
6896
|
-
const data = readModelsJsonForWrite(filePath);
|
|
6897
|
-
const providers = data.providers;
|
|
6898
|
-
if (!providers || !(providerId in providers)) return;
|
|
6899
|
-
const next = { ...providers };
|
|
6900
|
-
delete next[providerId];
|
|
6901
|
-
writeModelsJson(filePath, {
|
|
6902
|
-
...data,
|
|
6903
|
-
providers: next
|
|
6904
|
-
});
|
|
6905
|
-
}
|
|
6906
|
-
function isDiscoverableEntry(entry) {
|
|
6907
|
-
const baseUrl = entry?.baseUrl;
|
|
6908
|
-
if (!baseUrl) return false;
|
|
6909
|
-
const api = uiApiForCustomProvider(entry?.api);
|
|
6910
|
-
if (api && !isOccFamilyApi(api)) return false;
|
|
6911
|
-
if (entry?.api && !api) return false;
|
|
6912
|
-
try {
|
|
6913
|
-
const parsed = new URL(baseUrl);
|
|
6914
|
-
return parsed.protocol === "https:" || parsed.protocol === "http:";
|
|
6915
|
-
} catch {
|
|
6916
|
-
return false;
|
|
6917
|
-
}
|
|
6918
|
-
}
|
|
6919
|
-
function openAiModelsUrl(baseUrl) {
|
|
6920
|
-
const parsed = new URL(baseUrl);
|
|
6921
|
-
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") throw new Error("model discovery requires an http(s) URL");
|
|
6922
|
-
const path = parsed.pathname.replace(/\/+$/, "");
|
|
6923
|
-
parsed.pathname = path.endsWith("/v1") ? `${path}/models` : `${path}/v1/models`;
|
|
6924
|
-
parsed.search = "";
|
|
6925
|
-
parsed.hash = "";
|
|
6926
|
-
return parsed;
|
|
6927
|
-
}
|
|
6928
|
-
function handleChatModelsDiscoverPost(request) {
|
|
6929
|
-
return wrapApiHandler(async () => {
|
|
6930
|
-
const raw = await request.json().catch(() => ({}));
|
|
6931
|
-
const body = ChatModelsDiscoverRequestSchema.parse(raw);
|
|
6932
|
-
const config = getPrimeConfig();
|
|
6933
|
-
const apiKey = await config.modelRegistry.getApiKeyForProvider(body.providerId);
|
|
6934
|
-
if (!apiKey) return Response.json({
|
|
6935
|
-
providerId: body.providerId,
|
|
6936
|
-
models: []
|
|
6937
|
-
});
|
|
6938
|
-
const provider = body.providerId;
|
|
6939
|
-
const entry = listCustomProviders(`${config.agentDir}/models.json`)[provider];
|
|
6940
|
-
const api = uiApiForCustomProvider(entry?.api);
|
|
6941
|
-
if (entry?.api && !api || api && !isOccFamilyApi(api)) return Response.json({
|
|
6942
|
-
providerId: provider,
|
|
6943
|
-
models: []
|
|
6944
|
-
});
|
|
6945
|
-
const baseUrl = entry?.baseUrl;
|
|
6946
|
-
if (!baseUrl) return Response.json({
|
|
6947
|
-
providerId: provider,
|
|
6948
|
-
models: []
|
|
6949
|
-
});
|
|
6950
|
-
try {
|
|
6951
|
-
const modelsUrl = openAiModelsUrl(baseUrl);
|
|
6952
|
-
const response = await fetch(modelsUrl, {
|
|
6953
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
6954
|
-
signal: AbortSignal.timeout(1e4)
|
|
6955
|
-
});
|
|
6956
|
-
if (!response.ok) return Response.json({
|
|
6957
|
-
providerId: provider,
|
|
6958
|
-
models: []
|
|
6959
|
-
});
|
|
6960
|
-
const models = ((await response.json()).data ?? []).map((m) => ({
|
|
6961
|
-
key: `${provider}/${m.id}`,
|
|
6962
|
-
provider,
|
|
6963
|
-
id: m.id,
|
|
6964
|
-
name: m.id,
|
|
6965
|
-
reasoning: false,
|
|
6966
|
-
input: ["text"],
|
|
6967
|
-
available: true,
|
|
6968
|
-
defaultThinkingLevel: "off",
|
|
6969
|
-
thinkingLevels: ["off"]
|
|
6970
|
-
}));
|
|
6971
|
-
if (models.length > 0) {
|
|
6972
|
-
addCustomProviderModelIds(`${config.agentDir}/models.json`, provider, models.map((model) => model.id));
|
|
6973
|
-
config.reloadAuth();
|
|
6974
|
-
}
|
|
6975
|
-
return Response.json({
|
|
6976
|
-
providerId: provider,
|
|
6977
|
-
models
|
|
6978
|
-
});
|
|
6979
|
-
} catch {
|
|
6980
|
-
return Response.json({
|
|
6981
|
-
providerId: provider,
|
|
6982
|
-
models: []
|
|
6983
|
-
});
|
|
6894
|
+
{
|
|
6895
|
+
const bridge = getBridge();
|
|
6896
|
+
const session = bridge.getSession(sessionId.data) ?? await bridge.resumeSessionById(sessionId.data);
|
|
6897
|
+
if (!session || !await requireProjectSession(session)) return Response.json({ message: `Unknown session: ${sessionId.data}` }, { status: 404 });
|
|
6984
6898
|
}
|
|
6985
|
-
|
|
6986
|
-
}
|
|
6987
|
-
function toThinkingLevel(level) {
|
|
6988
|
-
return level;
|
|
6989
|
-
}
|
|
6990
|
-
function handleChatNewPost(request) {
|
|
6991
|
-
return wrapApiHandler(async () => {
|
|
6992
|
-
const bridge = getBridge();
|
|
6993
|
-
const registry = getPrimeConfig().projectRegistry;
|
|
6994
|
-
const raw = await request.json().catch(() => ({}));
|
|
6995
|
-
const body = ChatNewRequestSchema.parse(raw);
|
|
6996
|
-
const projectId = body.projectId ?? await registry.projectIdForCwd(getPrimeConfig().defaultCwd) ?? (await registry.register(getPrimeConfig().defaultCwd)).projectId;
|
|
6997
|
-
const project = await registry.get(projectId);
|
|
6998
|
-
bridge.ensureKernelReady(project.canonicalPath).catch(() => {
|
|
6999
|
-
});
|
|
7000
|
-
const session = await bridge.createSession({
|
|
7001
|
-
cwd: project.canonicalPath,
|
|
7002
|
-
projectId,
|
|
7003
|
-
thinkingLevel: toThinkingLevel(body.thinkingLevel),
|
|
7004
|
-
mode: body.mode,
|
|
7005
|
-
openUI: body.openUI
|
|
7006
|
-
});
|
|
7007
|
-
if (body.model) {
|
|
7008
|
-
await bridge.setModel(session.sessionId, body.model);
|
|
7009
|
-
const thinking = body.model.thinkingLevel ?? body.thinkingLevel;
|
|
7010
|
-
if (thinking) await session.connection.setThinkingLevel(toThinkingLevel(thinking));
|
|
7011
|
-
}
|
|
7012
|
-
return Response.json({
|
|
7013
|
-
session: {
|
|
7014
|
-
sessionId: session.sessionId,
|
|
7015
|
-
projectId
|
|
7016
|
-
},
|
|
7017
|
-
messages: [],
|
|
7018
|
-
planPresentations: [],
|
|
7019
|
-
presentation: bridge.getPresentation(session.sessionId)
|
|
7020
|
-
});
|
|
7021
|
-
});
|
|
7022
|
-
}
|
|
7023
|
-
function record(value) {
|
|
7024
|
-
return typeof value === "object" && value !== null ? value : void 0;
|
|
7025
|
-
}
|
|
7026
|
-
function artifactIndexFor(artifact) {
|
|
7027
|
-
const input = record(artifact.input);
|
|
7028
|
-
return typeof input?.artifactIndex === "number" ? input.artifactIndex : void 0;
|
|
7029
|
-
}
|
|
7030
|
-
function handleChatOpenUIArtifactPut(request) {
|
|
7031
|
-
return wrapApiHandler(async () => {
|
|
7032
|
-
const raw = await request.json().catch(() => ({}));
|
|
7033
|
-
const parsed = ChatOpenUIArtifactUpsertRequestSchema.safeParse(raw);
|
|
7034
|
-
if (!parsed.success) return Response.json({ message: "Invalid OpenUI artifact request." }, { status: 400 });
|
|
7035
|
-
const body = parsed.data;
|
|
7036
|
-
const validation = validateAndNormalizeOpenUIHtmlArtifact(body.artifact);
|
|
7037
|
-
if (!validation.ok) return Response.json({ message: validation.reason }, { status: validation.status ?? 400 });
|
|
7038
|
-
const bridge = getBridge();
|
|
7039
|
-
const session = bridge.getSession(body.sessionId) ?? await bridge.resumeSessionById(body.sessionId);
|
|
7040
|
-
if (!session) return Response.json({ message: `Unknown session: ${body.sessionId}` }, { status: 404 });
|
|
7041
|
-
const messages = await bridge.getMessages(session.sessionId);
|
|
7042
|
-
const incomingId = body.assistantMessageId;
|
|
7043
|
-
const exact = messages.find((message) => message.role === "assistant" && message.id === incomingId);
|
|
7044
|
-
const existing = bridge.getPresentation(session.sessionId).artifactRuns.flatMap((run) => run.artifacts).filter((artifact2) => artifact2.kind === "openui-html").find((artifact2) => artifactIndexFor(artifact2) === body.artifactIndex && (record(artifact2.input)?.clientMessageId === incomingId || artifact2.sourceMessageId === incomingId));
|
|
7045
|
-
const fallback = existing ? void 0 : [...messages].reverse().find((message) => message.role === "assistant");
|
|
7046
|
-
const assistantMessageId = exact?.id ?? existing?.sourceMessageId ?? fallback?.id;
|
|
7047
|
-
if (!assistantMessageId) return Response.json({ message: "Unable to associate OpenUI artifact with an assistant message." }, { status: 409 });
|
|
7048
|
-
const artifact = {
|
|
7049
|
-
id: stablePresentationId(`${assistantMessageId}:openui-html:${body.artifactIndex}`),
|
|
7050
|
-
runId: stablePresentationId(`${assistantMessageId}:openui`),
|
|
7051
|
-
sourceMessageId: assistantMessageId,
|
|
7052
|
-
kind: "openui-html",
|
|
7053
|
-
title: validation.value.title,
|
|
7054
|
-
status: "success",
|
|
7055
|
-
input: {
|
|
7056
|
-
clientMessageId: incomingId,
|
|
7057
|
-
artifactIndex: body.artifactIndex
|
|
7058
|
-
},
|
|
7059
|
-
output: validation.value,
|
|
7060
|
-
timestamp: Date.now()
|
|
7061
|
-
};
|
|
7062
|
-
const presentation = await bridge.upsertPresentationArtifact(session.sessionId, artifact);
|
|
7063
|
-
return Response.json({
|
|
7064
|
-
artifact,
|
|
7065
|
-
presentation
|
|
7066
|
-
});
|
|
7067
|
-
});
|
|
7068
|
-
}
|
|
7069
|
-
function handleChatPlanPresentationPut(request) {
|
|
7070
|
-
return wrapApiHandler(async () => {
|
|
7071
|
-
const body = ChatPlanPresentationUpsertRequestSchema.parse(await request.json().catch(() => ({})));
|
|
7072
|
-
const bridge = getBridge();
|
|
7073
|
-
const session = bridge.getSession(body.sessionId) ?? await bridge.resumeSessionById(body.sessionId);
|
|
7074
|
-
if (!session) return Response.json({ message: `Unknown session: ${body.sessionId}` }, { status: 404 });
|
|
7075
|
-
const messages = await bridge.getMessages(body.sessionId);
|
|
7076
|
-
const incomingId = body.presentation.assistantMessageId;
|
|
7077
|
-
const known = messages.find((message) => message.id === incomingId && message.role === "assistant");
|
|
7078
|
-
const existing = (await loadManagedPlanPresentations(session)).find((item) => item.assistantMessageId === incomingId || item.clientMessageId === incomingId);
|
|
7079
|
-
const fallback = existing ? void 0 : [...messages].reverse().find((message) => message.role === "assistant");
|
|
7080
|
-
const assistantMessageId = known?.id ?? existing?.assistantMessageId ?? fallback?.id;
|
|
7081
|
-
if (!assistantMessageId) return Response.json({ message: "Unable to associate Plan presentation with an assistant message" }, { status: 409 });
|
|
7082
|
-
const clientMessageId = incomingId !== assistantMessageId ? existing?.clientMessageId ?? incomingId : existing?.clientMessageId;
|
|
7083
|
-
return Response.json({ presentation: await upsertManagedPlanPresentation(session, {
|
|
7084
|
-
...body.presentation,
|
|
7085
|
-
assistantMessageId,
|
|
7086
|
-
...clientMessageId ? { clientMessageId } : {}
|
|
7087
|
-
}) });
|
|
7088
|
-
});
|
|
6899
|
+
return createSseResponse(request, getBridge(), { sessionId: sessionId.data }, lastEventIdFor(request, url));
|
|
6900
|
+
}, request);
|
|
7089
6901
|
}
|
|
7090
6902
|
var PRIME_BUTTERFLY_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 178 178" aria-hidden="true"><path fill="currentColor" d="m 123.322,84.092671 c -0.192,0.0065 -0.43,0.0147 -0.74,0.0147 l -0.018,-0.0247 c -0.873,0.1977 -1.958,0.1266 -3.067,0.0537 -3.29,-0.216 -6.799,-0.4465 -5.635,6.2824 0.259,1.4822 -1.538,1.8465 -2.73,1.9082 -3.384,0.1853 -6.78,0.2594 -10.171,0.1915 -0.641,-0.0106 -1.2979,-0.5506 -1.8904,-1.0388 -0.1022,-0.0844 -0.2034,-0.1673 -0.3016,-0.2457 -0.1052,-0.0865 0.2898,-1.2042 0.4942,-1.2166 3.3078,-0.1931 4.5068,-2.4361 5.7028,-4.6724 0.603,-1.1253 1.204,-2.2488 2.072,-3.1088 7.856,-7.7874 15.878,-15.4265 25.054,-21.7008 0.895,-0.6114 1.989,-1.1733 2.73,-0.1111 0.571,0.8205 0.036,1.2854 -0.512,1.7627 -0.24,0.2088 -0.482,0.4199 -0.637,0.6642 -0.554,0.8792 -1.538,1.5273 -2.514,2.1717 -1.92,1.2655 -3.82,2.5172 -2.408,5.4798 1.225,2.5651 0.129,3.0202 -1.555,3.7198 l -0.069,0.0287 c -0.72,0.3021 -1.458,0.5764 -2.194,0.8506 -1.568,0.5835 -3.134,1.1662 -4.537,2.0149 -1.408,0.8522 -2.081,2.5134 0.222,3.4954 5.033,2.1428 18.064,-1.2784 20.608,-5.9965 2.377,-4.4147 5.931,-7.6891 9.481,-10.9611 1.992,-1.836 3.984,-3.6712 5.767,-5.7067 3.844,-4.3849 8.344,-8.1939 12.846,-12.005 2.239,-1.8944 4.478,-3.78938 6.637,-5.75588 1.624,-1.48207 2.297,-3.43353 1.026,-5.56412 -1.267,-2.118215 -3.416,-2.402287 -5.435,-1.926802 -13.309,3.130982 -26.166,7.355122 -37.585,15.241302 -18.23,12.5919 -36.4911,25.1406 -54.9002,37.4669 -6.2743,4.2056 -10.0723,2.1491 -12.1657,-5.1318 -4.6502,-16.1676 -11.4681,-30.2664 -31.0569,-32.4587 -7.1574,-0.8028 -12.4066,3.6807 -11.3692,10.7949 0.5249,3.6065 0.0495,7.003 -1.6858,10.3872 -0.3827,0.7472 -0.7689,1.4947 -1.1556,2.243 -2.672,5.1706 -5.3671,10.3857 -7.0394,15.8885 -0.1399,0.4602 -0.3002,0.9444 -0.4654,1.4437 -1.4909,4.5052 -3.3862,10.2323 5.659,10.5492 0.3705,0.0123 1.0808,0.944799 0.9943,1.290699 -0.1976,0.8213 -0.5991,1.797 -1.2413,2.2725 -8.6705,6.3917 -15.79706,14.1294 -18.860151,24.5971 -1.550066,5.2865 -0.524909,10.7765 3.989391,14.8705 3.22984,2.928 7.35516,4.625 10.97396,2.162 3.3009,-2.247 6.9232,-3.754 10.538,-5.259 3.1819,-1.324 6.358,-2.646 9.3041,-4.468 0.7101,-0.439 1.5727,-0.841 2.4456,-1.248 2.4138,-1.1228 4.9063,-2.2843 4.4709,-4.3841 -0.6854,-3.2908 -4.1623,-6.3418 -7.0586,-8.7384 -2.8716,-2.3769 -10.1897,-18.3411 -9.3189,-22.176099 1.2193,-5.3704 3.9645,-10.0201 6.7125,-14.6744 2.3458,-3.9731 4.6935,-7.9497 6.0956,-12.3806 0.5804,-1.828 2.8037,-2.8284 4.9466,-2.0997 1.4543,0.4928 1.2068,1.8278 0.9762,3.0715 -0.0063,0.0344 -0.0127,0.0685 -0.019,0.1027 -0.8688,4.7802 -1.721,9.566 -2.5733,14.3517 -0.4261,2.3924 -0.8521,4.7847 -1.2803,7.1762 -0.2717,1.5316 0.2038,2.7544 1.7909,3.0631 3.0569,0.599 2.989,1.9762 1.6119,4.341499 -1.4636,2.5072 -1.6674,5.5703 -0.0309,7.8861 1.6427,2.3282 4.3908,2.8161 7.1821,1.4204 1.7415,-0.8646 3.094,-0.0927 3.0755,1.6612 -0.1112,9.3688 3.8103,7.2561 8.584,3.1681 0.439,-0.3763 1.0373,-0.5846 1.6152,-0.7857 0.1048,-0.0366 0.2091,-0.0728 0.3116,-0.1098 0.4529,-0.1616 0.9062,-0.3224 1.3595,-0.4833 8.986,-3.1884 17.9603,-6.3725 23.0334,-15.573099 0.392,-0.7187 1.6783,-1.0669 2.6795,-1.3377 0.057,-0.0154 0.113,-0.0307 0.1681,-0.0456 5.8013,-1.5766 11.7248,-1.6001 17.6438,-1.6237 4.445,-0.0176 8.888,-0.0352 13.277,-0.7107 4.329,-0.667 9.047,-3.1928 9.084,-7.3736 0.035,-3.3707 -2.546,-3.1612 -5.123,-2.9519 -1.115,0.0906 -2.231,0.1811 -3.134,-0.0185 -0.182,-0.0381 -0.375,-0.0316 -0.686,-0.0209 z"/><path fill="currentColor" d="m 55.1325,131.29447 c -1.0745,7.1515 1.6551,13.2715 12.8266,13.1915 h -0.0062 c 9.5413,-0.389 20.3365,-6.164 30.8838,-13.5492 6.9653,-4.8787 12.9873,-10.0236 16.8903,-17.6253 2.872,-5.5889 1.395,-10.0723 -2.933,-13.993799 -1.908,-1.7291 -3.73,-1.9205 -5.867,0.1667 -7.5842,7.423099 -17.0261,11.474299 -26.7218,15.550099 -2.4706,1.0393 -5.2847,1.5582 -8.1187,2.0809 -7.5511,1.3924 -15.2431,2.8103 -16.954,14.1791 z"/></svg>`;
|
|
7091
6903
|
function escapeHtml(value) {
|
|
@@ -7214,10 +7026,10 @@ var decode$1 = (s) => atob(s);
|
|
|
7214
7026
|
var CLIENT_ID$2 = decode$1("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
|
|
7215
7027
|
var AUTHORIZE_URL$1 = "https://claude.ai/oauth/authorize";
|
|
7216
7028
|
var TOKEN_URL$1 = "https://platform.claude.com/v1/oauth/token";
|
|
7217
|
-
var CALLBACK_HOST$
|
|
7029
|
+
var CALLBACK_HOST$2 = process.env.PI_OAUTH_CALLBACK_HOST || "127.0.0.1";
|
|
7218
7030
|
var CALLBACK_PORT = 53692;
|
|
7219
|
-
var CALLBACK_PATH = "/callback";
|
|
7220
|
-
var REDIRECT_URI$1 = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
7031
|
+
var CALLBACK_PATH$1 = "/callback";
|
|
7032
|
+
var REDIRECT_URI$1 = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH$1}`;
|
|
7221
7033
|
var SCOPES = "org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload";
|
|
7222
7034
|
async function getNodeApis() {
|
|
7223
7035
|
if (nodeApis) return nodeApis;
|
|
@@ -7267,7 +7079,7 @@ function formatErrorDetails(error) {
|
|
|
7267
7079
|
}
|
|
7268
7080
|
return String(error);
|
|
7269
7081
|
}
|
|
7270
|
-
async function startCallbackServer(expectedState) {
|
|
7082
|
+
async function startCallbackServer$1(expectedState) {
|
|
7271
7083
|
const { createServer } = await getNodeApis();
|
|
7272
7084
|
return new Promise((resolve2, reject) => {
|
|
7273
7085
|
let settleWait;
|
|
@@ -7282,7 +7094,7 @@ async function startCallbackServer(expectedState) {
|
|
|
7282
7094
|
const server = createServer((req, res) => {
|
|
7283
7095
|
try {
|
|
7284
7096
|
const url = new URL(req.url || "", "http://localhost");
|
|
7285
|
-
if (url.pathname !== CALLBACK_PATH) {
|
|
7097
|
+
if (url.pathname !== CALLBACK_PATH$1) {
|
|
7286
7098
|
res.writeHead(404, { "Content-Type": "text/html; charset=utf-8" });
|
|
7287
7099
|
res.end(oauthErrorHtml("Callback route not found."));
|
|
7288
7100
|
return;
|
|
@@ -7319,7 +7131,7 @@ async function startCallbackServer(expectedState) {
|
|
|
7319
7131
|
server.on("error", (err) => {
|
|
7320
7132
|
reject(err);
|
|
7321
7133
|
});
|
|
7322
|
-
server.listen(CALLBACK_PORT, CALLBACK_HOST$
|
|
7134
|
+
server.listen(CALLBACK_PORT, CALLBACK_HOST$2, () => {
|
|
7323
7135
|
resolve2({
|
|
7324
7136
|
server,
|
|
7325
7137
|
redirectUri: REDIRECT_URI$1,
|
|
@@ -7373,7 +7185,7 @@ async function exchangeAuthorizationCode$1(code, state, verifier, redirectUri) {
|
|
|
7373
7185
|
}
|
|
7374
7186
|
async function loginAnthropic(options) {
|
|
7375
7187
|
const { verifier, challenge } = await generatePKCE();
|
|
7376
|
-
const server = await startCallbackServer(verifier);
|
|
7188
|
+
const server = await startCallbackServer$1(verifier);
|
|
7377
7189
|
let code;
|
|
7378
7190
|
let state;
|
|
7379
7191
|
let redirectUriForExchange = REDIRECT_URI$1;
|
|
@@ -34448,7 +34260,7 @@ function getGitHubCopilotBaseUrl(token, enterpriseDomain) {
|
|
|
34448
34260
|
if (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;
|
|
34449
34261
|
return "https://api.individual.githubcopilot.com";
|
|
34450
34262
|
}
|
|
34451
|
-
async function fetchJson(url, init) {
|
|
34263
|
+
async function fetchJson$1(url, init) {
|
|
34452
34264
|
const response = await fetch(url, init);
|
|
34453
34265
|
if (!response.ok) {
|
|
34454
34266
|
const text = await response.text();
|
|
@@ -34457,7 +34269,7 @@ async function fetchJson(url, init) {
|
|
|
34457
34269
|
return response.json();
|
|
34458
34270
|
}
|
|
34459
34271
|
async function startDeviceFlow(domain) {
|
|
34460
|
-
const data = await fetchJson(getUrls(domain).deviceCodeUrl, {
|
|
34272
|
+
const data = await fetchJson$1(getUrls(domain).deviceCodeUrl, {
|
|
34461
34273
|
method: "POST",
|
|
34462
34274
|
headers: {
|
|
34463
34275
|
Accept: "application/json",
|
|
@@ -34507,7 +34319,7 @@ async function pollForGitHubAccessToken(domain, deviceCode, intervalSeconds, exp
|
|
|
34507
34319
|
if (signal?.aborted) throw new Error("Login cancelled");
|
|
34508
34320
|
const remainingMs = deadline - Date.now();
|
|
34509
34321
|
await abortableSleep(Math.min(Math.ceil(intervalMs * intervalMultiplier), remainingMs), signal);
|
|
34510
|
-
const raw = await fetchJson(urls.accessTokenUrl, {
|
|
34322
|
+
const raw = await fetchJson$1(urls.accessTokenUrl, {
|
|
34511
34323
|
method: "POST",
|
|
34512
34324
|
headers: {
|
|
34513
34325
|
Accept: "application/json",
|
|
@@ -34538,7 +34350,7 @@ async function pollForGitHubAccessToken(domain, deviceCode, intervalSeconds, exp
|
|
|
34538
34350
|
throw new Error("Device flow timed out");
|
|
34539
34351
|
}
|
|
34540
34352
|
async function refreshGitHubCopilotToken(refreshToken, enterpriseDomain) {
|
|
34541
|
-
const raw = await fetchJson(getUrls(enterpriseDomain || "github.com").copilotTokenUrl, { headers: {
|
|
34353
|
+
const raw = await fetchJson$1(getUrls(enterpriseDomain || "github.com").copilotTokenUrl, { headers: {
|
|
34542
34354
|
Accept: "application/json",
|
|
34543
34355
|
Authorization: `Bearer ${refreshToken}`,
|
|
34544
34356
|
...COPILOT_HEADERS
|
|
@@ -34638,7 +34450,7 @@ if (typeof process !== "undefined" && (process.versions?.node || process.version
|
|
|
34638
34450
|
_http = m;
|
|
34639
34451
|
});
|
|
34640
34452
|
}
|
|
34641
|
-
var CALLBACK_HOST = process.env.PI_OAUTH_CALLBACK_HOST || "127.0.0.1";
|
|
34453
|
+
var CALLBACK_HOST$1 = process.env.PI_OAUTH_CALLBACK_HOST || "127.0.0.1";
|
|
34642
34454
|
var CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
34643
34455
|
var AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize";
|
|
34644
34456
|
var TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
@@ -34820,7 +34632,7 @@ function startLocalOAuthServer(state) {
|
|
|
34820
34632
|
}
|
|
34821
34633
|
});
|
|
34822
34634
|
return new Promise((resolve2) => {
|
|
34823
|
-
server.listen(1455, CALLBACK_HOST, () => {
|
|
34635
|
+
server.listen(1455, CALLBACK_HOST$1, () => {
|
|
34824
34636
|
resolve2({
|
|
34825
34637
|
close: () => server.close(),
|
|
34826
34638
|
cancelWait: () => {
|
|
@@ -34946,9 +34758,652 @@ var oauthProviderRegistry = new Map([
|
|
|
34946
34758
|
function getOAuthProvider(id) {
|
|
34947
34759
|
return oauthProviderRegistry.get(id);
|
|
34948
34760
|
}
|
|
34761
|
+
function registerOAuthProvider(provider) {
|
|
34762
|
+
oauthProviderRegistry.set(provider.id, provider);
|
|
34763
|
+
}
|
|
34949
34764
|
function getOAuthProviders() {
|
|
34950
34765
|
return Array.from(oauthProviderRegistry.values());
|
|
34951
34766
|
}
|
|
34767
|
+
var CALLBACK_HOST = process.env.PI_OAUTH_CALLBACK_HOST || "127.0.0.1";
|
|
34768
|
+
var CALLBACK_PORT_BASE = Number(process.env.PI_MCP_OAUTH_CALLBACK_PORT || 53700);
|
|
34769
|
+
var CALLBACK_PORT_COUNT = 10;
|
|
34770
|
+
var CALLBACK_PATH = "/callback";
|
|
34771
|
+
var CALLBACK_PORTS = Array.from({ length: CALLBACK_PORT_COUNT }, (_, i) => CALLBACK_PORT_BASE + i);
|
|
34772
|
+
var redirectUriFor = (port) => `http://localhost:${port}${CALLBACK_PATH}`;
|
|
34773
|
+
var ALL_REDIRECT_URIS = CALLBACK_PORTS.map(redirectUriFor);
|
|
34774
|
+
var TOKEN_EXPIRY_BUFFER_MS = 3e5;
|
|
34775
|
+
function validatedHttpsUrl(value, name) {
|
|
34776
|
+
let url;
|
|
34777
|
+
try {
|
|
34778
|
+
url = new URL(value);
|
|
34779
|
+
} catch {
|
|
34780
|
+
throw new Error(`${name} must be an absolute HTTPS URL`);
|
|
34781
|
+
}
|
|
34782
|
+
if (url.protocol !== "https:" || url.username || url.password || url.hash) throw new Error(`${name} must be an absolute HTTPS URL without credentials or a fragment`);
|
|
34783
|
+
return url;
|
|
34784
|
+
}
|
|
34785
|
+
function canonicalResource(url) {
|
|
34786
|
+
if (url.pathname === "/" && !url.search) return url.origin;
|
|
34787
|
+
return `${url.origin}${url.pathname}${url.search}`;
|
|
34788
|
+
}
|
|
34789
|
+
function authorizationServerMetadataUrls(issuer) {
|
|
34790
|
+
const url = validatedHttpsUrl(issuer, "Authorization server issuer");
|
|
34791
|
+
if (url.search) throw new Error("Authorization server issuer must not contain a query string");
|
|
34792
|
+
const path = url.pathname === "/" ? "" : url.pathname.replace(/\/$/, "");
|
|
34793
|
+
return [new URL(`/.well-known/oauth-authorization-server${path}`, url.origin).toString(), new URL(`${path}/.well-known/openid-configuration`, url.origin).toString()];
|
|
34794
|
+
}
|
|
34795
|
+
async function fetchResponse(url, init) {
|
|
34796
|
+
return fetch(url, {
|
|
34797
|
+
...init,
|
|
34798
|
+
redirect: "error"
|
|
34799
|
+
});
|
|
34800
|
+
}
|
|
34801
|
+
async function fetchJson(url, init) {
|
|
34802
|
+
const res = await fetchResponse(url, init);
|
|
34803
|
+
if (!res.ok) throw new Error(`${init?.method ?? "GET"} ${url} failed: ${res.status}`);
|
|
34804
|
+
return res.json();
|
|
34805
|
+
}
|
|
34806
|
+
function authorizationServerMetadata(value, issuer, requireExactIssuer) {
|
|
34807
|
+
if (!value || typeof value !== "object") throw new Error(`Authorization server metadata for ${issuer} is invalid`);
|
|
34808
|
+
const metadata = value;
|
|
34809
|
+
if (typeof metadata.issuer !== "string") throw new Error(`Authorization server metadata for ${issuer} is missing its issuer`);
|
|
34810
|
+
if (requireExactIssuer) {
|
|
34811
|
+
if (metadata.issuer !== issuer) throw new Error(`Authorization server metadata issuer does not exactly match ${issuer}`);
|
|
34812
|
+
} else {
|
|
34813
|
+
const advertisedIssuer = validatedHttpsUrl(metadata.issuer, "Authorization server metadata issuer");
|
|
34814
|
+
if (advertisedIssuer.origin !== new URL(issuer).origin || advertisedIssuer.search) throw new Error(`Origin authorization server metadata issuer must stay on ${new URL(issuer).origin}`);
|
|
34815
|
+
}
|
|
34816
|
+
if (typeof metadata.authorization_endpoint !== "string" || typeof metadata.token_endpoint !== "string") throw new Error(`Authorization server metadata for ${issuer} is missing required endpoints`);
|
|
34817
|
+
validatedHttpsUrl(metadata.authorization_endpoint, "Authorization endpoint");
|
|
34818
|
+
validatedHttpsUrl(metadata.token_endpoint, "Token endpoint");
|
|
34819
|
+
if (metadata.registration_endpoint) validatedHttpsUrl(metadata.registration_endpoint, "Registration endpoint");
|
|
34820
|
+
return metadata;
|
|
34821
|
+
}
|
|
34822
|
+
async function jsonMetadata(response, url) {
|
|
34823
|
+
if (response.status !== 200) throw new Error(`GET ${url} failed: ${response.status}`);
|
|
34824
|
+
if (response.headers.get("content-type")?.split(";", 1)[0].trim().toLowerCase() !== "application/json") throw new Error(`GET ${url} did not return application/json`);
|
|
34825
|
+
return response.json();
|
|
34826
|
+
}
|
|
34827
|
+
async function discoverAuthorizationServer(issuer, requireExactIssuer) {
|
|
34828
|
+
const candidates = authorizationServerMetadataUrls(issuer);
|
|
34829
|
+
let lastError;
|
|
34830
|
+
for (const candidate of candidates) try {
|
|
34831
|
+
const response = await fetchResponse(candidate);
|
|
34832
|
+
if (response.status === 404) continue;
|
|
34833
|
+
return authorizationServerMetadata(await jsonMetadata(response, candidate), issuer, requireExactIssuer);
|
|
34834
|
+
} catch (error) {
|
|
34835
|
+
lastError = error;
|
|
34836
|
+
}
|
|
34837
|
+
throw new Error(`Could not discover OAuth metadata for ${issuer}. Tried ${candidates.join(", ")}. Last error: ${String(lastError)}`);
|
|
34838
|
+
}
|
|
34839
|
+
function randomState() {
|
|
34840
|
+
const bytes = /* @__PURE__ */ new Uint8Array(32);
|
|
34841
|
+
crypto.getRandomValues(bytes);
|
|
34842
|
+
return btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
34843
|
+
}
|
|
34844
|
+
function resourceMetadata(value, resource) {
|
|
34845
|
+
if (!value || typeof value !== "object") throw new Error("Protected-resource metadata is invalid");
|
|
34846
|
+
const metadata = value;
|
|
34847
|
+
if (metadata.resource !== resource) throw new Error(`Protected-resource metadata resource does not exactly match ${resource}`);
|
|
34848
|
+
if (!Array.isArray(metadata.authorization_servers) || metadata.authorization_servers.length === 0) throw new Error("Protected-resource metadata has no authorization_servers");
|
|
34849
|
+
for (const issuer of metadata.authorization_servers) {
|
|
34850
|
+
if (typeof issuer !== "string") throw new Error("Protected-resource metadata has an invalid authorization server");
|
|
34851
|
+
validatedHttpsUrl(issuer, "Authorization server issuer");
|
|
34852
|
+
}
|
|
34853
|
+
return metadata;
|
|
34854
|
+
}
|
|
34855
|
+
function resourceMetadataUrl(resource) {
|
|
34856
|
+
const path = resource.pathname === "/" ? "" : resource.pathname;
|
|
34857
|
+
return `${resource.origin}/.well-known/oauth-protected-resource${path}${resource.search}`;
|
|
34858
|
+
}
|
|
34859
|
+
function headerResourceMetadata(value) {
|
|
34860
|
+
const match = value?.match(/(?:^|[,\s])resource_metadata\s*=\s*"((?:[^"\\]|\\.)*)"/i);
|
|
34861
|
+
if (!match) return void 0;
|
|
34862
|
+
return match[1].replace(/\\(.)/g, "$1");
|
|
34863
|
+
}
|
|
34864
|
+
async function tryProtectedResourceMetadata(url) {
|
|
34865
|
+
const resource = validatedHttpsUrl(url, "MCP endpoint");
|
|
34866
|
+
let headerUrl;
|
|
34867
|
+
try {
|
|
34868
|
+
const response2 = await fetchResponse(resource.toString());
|
|
34869
|
+
headerUrl = headerResourceMetadata(response2.headers.get("www-authenticate"));
|
|
34870
|
+
await response2.body?.cancel();
|
|
34871
|
+
} catch {
|
|
34872
|
+
}
|
|
34873
|
+
const candidate = headerUrl ? validatedHttpsUrl(headerUrl, "resource_metadata").toString() : resourceMetadataUrl(resource);
|
|
34874
|
+
const response = await fetchResponse(candidate);
|
|
34875
|
+
if (response.status === 404 && !headerUrl) return void 0;
|
|
34876
|
+
return resourceMetadata(await jsonMetadata(response, candidate), canonicalResource(resource));
|
|
34877
|
+
}
|
|
34878
|
+
async function discover(url) {
|
|
34879
|
+
const protectedResource = await tryProtectedResourceMetadata(url);
|
|
34880
|
+
if (protectedResource) {
|
|
34881
|
+
const issuer2 = protectedResource.authorization_servers[0];
|
|
34882
|
+
return {
|
|
34883
|
+
metadata: await discoverAuthorizationServer(issuer2, true),
|
|
34884
|
+
resource: protectedResource.resource,
|
|
34885
|
+
issuer: issuer2
|
|
34886
|
+
};
|
|
34887
|
+
}
|
|
34888
|
+
const issuer = validatedHttpsUrl(url, "MCP endpoint").origin;
|
|
34889
|
+
return { metadata: await discoverAuthorizationServer(issuer, false) };
|
|
34890
|
+
}
|
|
34891
|
+
async function registerClient(registrationEndpoint, label) {
|
|
34892
|
+
validatedHttpsUrl(registrationEndpoint, "Registration endpoint");
|
|
34893
|
+
const data = await fetchJson(registrationEndpoint, {
|
|
34894
|
+
method: "POST",
|
|
34895
|
+
headers: { "Content-Type": "application/json" },
|
|
34896
|
+
body: JSON.stringify({
|
|
34897
|
+
client_name: label,
|
|
34898
|
+
redirect_uris: ALL_REDIRECT_URIS,
|
|
34899
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
34900
|
+
response_types: ["code"],
|
|
34901
|
+
token_endpoint_auth_method: "none"
|
|
34902
|
+
})
|
|
34903
|
+
});
|
|
34904
|
+
if (typeof data.client_id !== "string" || !data.client_id) throw new Error(`Dynamic client registration at ${registrationEndpoint} returned no client_id`);
|
|
34905
|
+
return data.client_id;
|
|
34906
|
+
}
|
|
34907
|
+
async function startCallbackServer(label) {
|
|
34908
|
+
const { createServer } = await import("node:http");
|
|
34909
|
+
let settle;
|
|
34910
|
+
const waitPromise = new Promise((resolve2) => {
|
|
34911
|
+
let settled = false;
|
|
34912
|
+
settle = (value) => {
|
|
34913
|
+
if (!settled) {
|
|
34914
|
+
settled = true;
|
|
34915
|
+
resolve2(value);
|
|
34916
|
+
}
|
|
34917
|
+
};
|
|
34918
|
+
});
|
|
34919
|
+
const handler = (req, res) => {
|
|
34920
|
+
const url = new URL(req.url || "", "http://localhost");
|
|
34921
|
+
if (url.pathname !== CALLBACK_PATH) {
|
|
34922
|
+
res.writeHead(404, { "Content-Type": "text/html; charset=utf-8" });
|
|
34923
|
+
res.end(oauthErrorHtml("Callback route not found."));
|
|
34924
|
+
return;
|
|
34925
|
+
}
|
|
34926
|
+
const error = url.searchParams.get("error");
|
|
34927
|
+
const code = url.searchParams.get("code");
|
|
34928
|
+
const state = url.searchParams.get("state");
|
|
34929
|
+
res.writeHead(error || !code ? 400 : 200, { "Content-Type": "text/html; charset=utf-8" });
|
|
34930
|
+
if (error) {
|
|
34931
|
+
res.end(oauthErrorHtml(`${label} authentication failed.`, `Error: ${error}`));
|
|
34932
|
+
settle?.(null);
|
|
34933
|
+
return;
|
|
34934
|
+
}
|
|
34935
|
+
if (!code || !state) {
|
|
34936
|
+
res.end(oauthErrorHtml("Missing code or state parameter."));
|
|
34937
|
+
settle?.(null);
|
|
34938
|
+
return;
|
|
34939
|
+
}
|
|
34940
|
+
res.end(oauthSuccessHtml(`${label} authentication completed. You can close this window.`));
|
|
34941
|
+
settle?.({
|
|
34942
|
+
code,
|
|
34943
|
+
state
|
|
34944
|
+
});
|
|
34945
|
+
};
|
|
34946
|
+
let lastError;
|
|
34947
|
+
for (const port of CALLBACK_PORTS) {
|
|
34948
|
+
const server = createServer(handler);
|
|
34949
|
+
let bindErr;
|
|
34950
|
+
server.on("error", (err) => bindErr?.(err));
|
|
34951
|
+
try {
|
|
34952
|
+
if (await new Promise((resolve2) => {
|
|
34953
|
+
bindErr = () => resolve2(false);
|
|
34954
|
+
server.listen(port, CALLBACK_HOST, () => {
|
|
34955
|
+
bindErr = void 0;
|
|
34956
|
+
resolve2(true);
|
|
34957
|
+
});
|
|
34958
|
+
})) return {
|
|
34959
|
+
server,
|
|
34960
|
+
redirectUri: redirectUriFor(port),
|
|
34961
|
+
cancel: () => settle?.(null),
|
|
34962
|
+
waitForCode: () => waitPromise
|
|
34963
|
+
};
|
|
34964
|
+
lastError = `port ${port} in use`;
|
|
34965
|
+
server.close();
|
|
34966
|
+
} catch (err) {
|
|
34967
|
+
lastError = err;
|
|
34968
|
+
server.close();
|
|
34969
|
+
}
|
|
34970
|
+
}
|
|
34971
|
+
throw new Error(`Could not start the OAuth callback server: ports ${CALLBACK_PORT_BASE}-${CALLBACK_PORT_BASE + CALLBACK_PORT_COUNT - 1} are all in use. Close other login attempts and retry. (${String(lastError)})`);
|
|
34972
|
+
}
|
|
34973
|
+
function parseRedirectInput(input, expectedState) {
|
|
34974
|
+
const value = input.trim();
|
|
34975
|
+
let code;
|
|
34976
|
+
let state;
|
|
34977
|
+
try {
|
|
34978
|
+
const url = new URL(value);
|
|
34979
|
+
code = url.searchParams.get("code") ?? void 0;
|
|
34980
|
+
state = url.searchParams.get("state") ?? void 0;
|
|
34981
|
+
} catch {
|
|
34982
|
+
const params = new URLSearchParams(value);
|
|
34983
|
+
code = params.get("code") ?? value;
|
|
34984
|
+
state = params.get("state") ?? void 0;
|
|
34985
|
+
}
|
|
34986
|
+
if (state && state !== expectedState) throw new Error("OAuth state mismatch");
|
|
34987
|
+
if (!code) throw new Error("Missing authorization code");
|
|
34988
|
+
return {
|
|
34989
|
+
code,
|
|
34990
|
+
state: state ?? expectedState
|
|
34991
|
+
};
|
|
34992
|
+
}
|
|
34993
|
+
async function exchangeToken(tokenEndpoint, params) {
|
|
34994
|
+
validatedHttpsUrl(tokenEndpoint, "Token endpoint");
|
|
34995
|
+
const res = await fetchResponse(tokenEndpoint, {
|
|
34996
|
+
method: "POST",
|
|
34997
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
34998
|
+
body: new URLSearchParams(params).toString()
|
|
34999
|
+
});
|
|
35000
|
+
const text = await res.text();
|
|
35001
|
+
if (!res.ok) throw new Error(`Token request to ${tokenEndpoint} failed: ${res.status}`);
|
|
35002
|
+
let token;
|
|
35003
|
+
try {
|
|
35004
|
+
token = JSON.parse(text);
|
|
35005
|
+
} catch {
|
|
35006
|
+
throw new Error(`Token request to ${tokenEndpoint} returned invalid JSON`);
|
|
35007
|
+
}
|
|
35008
|
+
if (!token || typeof token !== "object" || typeof token.access_token !== "string") throw new Error(`Token request to ${tokenEndpoint} returned no access_token`);
|
|
35009
|
+
const result = token;
|
|
35010
|
+
if (!result.access_token) throw new Error(`Token request to ${tokenEndpoint} returned no access_token`);
|
|
35011
|
+
if (result.refresh_token !== void 0 && typeof result.refresh_token !== "string") throw new Error(`Token request to ${tokenEndpoint} returned an invalid refresh_token`);
|
|
35012
|
+
if (result.expires_in !== void 0 && (typeof result.expires_in !== "number" || !Number.isFinite(result.expires_in))) throw new Error(`Token request to ${tokenEndpoint} returned an invalid expires_in`);
|
|
35013
|
+
return result;
|
|
35014
|
+
}
|
|
35015
|
+
function toCredentials(token, tokenEndpoint, clientId, endpoint, resource, issuer, previousRefresh) {
|
|
35016
|
+
return {
|
|
35017
|
+
access: token.access_token,
|
|
35018
|
+
refresh: token.refresh_token ?? previousRefresh ?? "",
|
|
35019
|
+
expires: token.expires_in ? Date.now() + token.expires_in * 1e3 - TOKEN_EXPIRY_BUFFER_MS : Date.now() + 36e5 - TOKEN_EXPIRY_BUFFER_MS,
|
|
35020
|
+
tokenEndpoint,
|
|
35021
|
+
clientId,
|
|
35022
|
+
endpoint,
|
|
35023
|
+
resource,
|
|
35024
|
+
issuer
|
|
35025
|
+
};
|
|
35026
|
+
}
|
|
35027
|
+
function createMcpOAuthProvider(config) {
|
|
35028
|
+
const label = config.label ?? config.server;
|
|
35029
|
+
async function login(callbacks) {
|
|
35030
|
+
const discovery = await discover(config.url);
|
|
35031
|
+
const { metadata: meta } = discovery;
|
|
35032
|
+
callbacks.onProgress?.(`Discovered ${discovery.issuer ?? meta.issuer}`);
|
|
35033
|
+
let clientId = config.clientId;
|
|
35034
|
+
if (!clientId) {
|
|
35035
|
+
if (!meta.registration_endpoint) throw new Error(`${label} does not support dynamic client registration and no clientId was configured. Set a pre-registered client id for this server.`);
|
|
35036
|
+
callbacks.onProgress?.("Registering OAuth client\u2026");
|
|
35037
|
+
clientId = await registerClient(meta.registration_endpoint, `Prime Agent (${label})`);
|
|
35038
|
+
}
|
|
35039
|
+
const { verifier, challenge } = await generatePKCE();
|
|
35040
|
+
const state = randomState();
|
|
35041
|
+
const scope = config.scopes ?? meta.scopes_supported?.join(" ");
|
|
35042
|
+
const cb = await startCallbackServer(label);
|
|
35043
|
+
try {
|
|
35044
|
+
const authParams = new URLSearchParams({
|
|
35045
|
+
client_id: clientId,
|
|
35046
|
+
response_type: "code",
|
|
35047
|
+
redirect_uri: cb.redirectUri,
|
|
35048
|
+
code_challenge: challenge,
|
|
35049
|
+
code_challenge_method: "S256",
|
|
35050
|
+
state
|
|
35051
|
+
});
|
|
35052
|
+
if (scope) authParams.set("scope", scope);
|
|
35053
|
+
if (discovery.resource) authParams.set("resource", discovery.resource);
|
|
35054
|
+
const authorizationUrl = new URL(meta.authorization_endpoint);
|
|
35055
|
+
for (const [name, value] of authParams) authorizationUrl.searchParams.set(name, value);
|
|
35056
|
+
callbacks.onAuth({
|
|
35057
|
+
url: authorizationUrl.toString(),
|
|
35058
|
+
instructions: "Complete login in your browser. If the browser is on another machine, paste the final redirect URL here."
|
|
35059
|
+
});
|
|
35060
|
+
let result;
|
|
35061
|
+
let manualCancelled = false;
|
|
35062
|
+
let manualError;
|
|
35063
|
+
if (callbacks.onManualCodeInput) {
|
|
35064
|
+
const manual = callbacks.onManualCodeInput().then((input) => {
|
|
35065
|
+
const parsed = parseRedirectInput(input, state);
|
|
35066
|
+
cb.cancel();
|
|
35067
|
+
return parsed;
|
|
35068
|
+
}).catch(async (err) => {
|
|
35069
|
+
if (err instanceof Error && /state mismatch|authorization code/i.test(err.message)) manualError = err;
|
|
35070
|
+
else manualCancelled = true;
|
|
35071
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
35072
|
+
cb.cancel();
|
|
35073
|
+
return null;
|
|
35074
|
+
});
|
|
35075
|
+
result = await cb.waitForCode() ?? await manual;
|
|
35076
|
+
if (!result && manualError) throw manualError;
|
|
35077
|
+
} else {
|
|
35078
|
+
result = await cb.waitForCode();
|
|
35079
|
+
if (!result) result = parseRedirectInput(await callbacks.onPrompt({
|
|
35080
|
+
message: "Paste the authorization code or full redirect URL:",
|
|
35081
|
+
placeholder: cb.redirectUri
|
|
35082
|
+
}), state);
|
|
35083
|
+
}
|
|
35084
|
+
if (!result) throw new Error(manualCancelled ? "Login cancelled" : "Missing authorization code");
|
|
35085
|
+
if (result.state !== state) throw new Error("OAuth state mismatch");
|
|
35086
|
+
callbacks.onProgress?.("Exchanging authorization code for tokens\u2026");
|
|
35087
|
+
return toCredentials(await exchangeToken(meta.token_endpoint, {
|
|
35088
|
+
grant_type: "authorization_code",
|
|
35089
|
+
code: result.code,
|
|
35090
|
+
redirect_uri: cb.redirectUri,
|
|
35091
|
+
client_id: clientId,
|
|
35092
|
+
code_verifier: verifier,
|
|
35093
|
+
...discovery.resource ? { resource: discovery.resource } : {}
|
|
35094
|
+
}), meta.token_endpoint, clientId, config.url, discovery.resource, discovery.issuer);
|
|
35095
|
+
} finally {
|
|
35096
|
+
cb.server.close();
|
|
35097
|
+
}
|
|
35098
|
+
}
|
|
35099
|
+
async function refreshToken(credentials) {
|
|
35100
|
+
const creds = credentials;
|
|
35101
|
+
if (creds.endpoint !== config.url) throw new Error(`Stored OAuth credentials are not bound to ${config.url}; re-run /mcp login ${config.server}`);
|
|
35102
|
+
const configuredResource = canonicalResource(validatedHttpsUrl(config.url, "MCP endpoint"));
|
|
35103
|
+
if (creds.resource !== void 0 && creds.resource !== configuredResource) throw new Error(`Stored OAuth credentials are not bound to ${configuredResource}; re-run /mcp login ${config.server}`);
|
|
35104
|
+
if (creds.resource === void 0 !== (creds.issuer === void 0)) throw new Error(`Stored OAuth credentials for ${label} have incomplete resource binding; re-run /mcp login ${config.server}`);
|
|
35105
|
+
if (creds.issuer !== void 0) validatedHttpsUrl(creds.issuer, "Stored authorization server issuer");
|
|
35106
|
+
if (!creds.refresh) throw new Error(`No refresh token stored for ${label}; re-run /mcp login ${config.server}`);
|
|
35107
|
+
const discovery = await discover(config.url);
|
|
35108
|
+
if (creds.resource === void 0 !== (discovery.resource === void 0)) throw new Error(`OAuth discovery mode changed for ${config.url}; re-run /mcp login ${config.server}`);
|
|
35109
|
+
if (creds.resource) {
|
|
35110
|
+
if (discovery.resource !== creds.resource || discovery.issuer !== creds.issuer) throw new Error(`Stored OAuth credentials do not match current protected-resource metadata for ${config.url}`);
|
|
35111
|
+
}
|
|
35112
|
+
const tokenEndpoint = creds.tokenEndpoint ?? discovery.metadata.token_endpoint;
|
|
35113
|
+
if (creds.tokenEndpoint && discovery.metadata.token_endpoint !== creds.tokenEndpoint) throw new Error(`Stored OAuth token endpoint does not match current authorization-server metadata for ${config.url}`);
|
|
35114
|
+
const clientId = creds.clientId ?? config.clientId;
|
|
35115
|
+
if (!tokenEndpoint) throw new Error(`No token endpoint stored for ${label}; re-run /mcp login ${config.server}`);
|
|
35116
|
+
return toCredentials(await exchangeToken(tokenEndpoint, {
|
|
35117
|
+
grant_type: "refresh_token",
|
|
35118
|
+
refresh_token: creds.refresh,
|
|
35119
|
+
...clientId ? { client_id: clientId } : {},
|
|
35120
|
+
...creds.resource ? { resource: creds.resource } : {}
|
|
35121
|
+
}), tokenEndpoint, clientId ?? "", creds.endpoint, creds.resource, creds.issuer, creds.refresh);
|
|
35122
|
+
}
|
|
35123
|
+
return {
|
|
35124
|
+
id: `mcp:${config.server}`,
|
|
35125
|
+
name: label,
|
|
35126
|
+
usesCallbackServer: true,
|
|
35127
|
+
login,
|
|
35128
|
+
refreshToken,
|
|
35129
|
+
getApiKey: (credentials) => credentials.access
|
|
35130
|
+
};
|
|
35131
|
+
}
|
|
35132
|
+
var BUILTIN_MCP_CATALOG = [{
|
|
35133
|
+
server: "linear",
|
|
35134
|
+
label: "Linear",
|
|
35135
|
+
url: "https://mcp.linear.app/mcp",
|
|
35136
|
+
oauth: {
|
|
35137
|
+
kind: "oauth",
|
|
35138
|
+
label: "Linear"
|
|
35139
|
+
}
|
|
35140
|
+
}, {
|
|
35141
|
+
server: "notion",
|
|
35142
|
+
label: "Notion",
|
|
35143
|
+
url: "https://mcp.notion.com/mcp",
|
|
35144
|
+
oauth: {
|
|
35145
|
+
kind: "oauth",
|
|
35146
|
+
label: "Notion"
|
|
35147
|
+
}
|
|
35148
|
+
}];
|
|
35149
|
+
function getCatalogEntry(server) {
|
|
35150
|
+
return BUILTIN_MCP_CATALOG.find((entry) => entry.server === server);
|
|
35151
|
+
}
|
|
35152
|
+
function registerBuiltinMcpOAuthProviders() {
|
|
35153
|
+
for (const entry of BUILTIN_MCP_CATALOG) {
|
|
35154
|
+
if (entry.oauth?.kind !== "oauth") continue;
|
|
35155
|
+
if (getOAuthProvider(`mcp:${entry.server}`)) continue;
|
|
35156
|
+
registerOAuthProvider(createMcpOAuthProvider({
|
|
35157
|
+
server: entry.server,
|
|
35158
|
+
label: entry.label,
|
|
35159
|
+
url: entry.url,
|
|
35160
|
+
scopes: entry.oauth.scopes,
|
|
35161
|
+
clientId: entry.oauth.clientId
|
|
35162
|
+
}));
|
|
35163
|
+
}
|
|
35164
|
+
}
|
|
35165
|
+
var MCP_AUTH_PREFIX = "mcp:";
|
|
35166
|
+
function mcpProviderId(name) {
|
|
35167
|
+
return `${MCP_AUTH_PREFIX}${name}`;
|
|
35168
|
+
}
|
|
35169
|
+
var McpRequestError = class extends Error {
|
|
35170
|
+
status = 400;
|
|
35171
|
+
constructor(message) {
|
|
35172
|
+
super(message);
|
|
35173
|
+
this.name = "McpRequestError";
|
|
35174
|
+
}
|
|
35175
|
+
};
|
|
35176
|
+
function validateHttpMcpUrl(value) {
|
|
35177
|
+
let url;
|
|
35178
|
+
try {
|
|
35179
|
+
url = new URL(value);
|
|
35180
|
+
} catch {
|
|
35181
|
+
throw new McpRequestError("Invalid MCP URL.");
|
|
35182
|
+
}
|
|
35183
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || !url.hostname || url.username || url.password) throw new McpRequestError("MCP URL must be an http(s) URL without embedded credentials.");
|
|
35184
|
+
return url.toString();
|
|
35185
|
+
}
|
|
35186
|
+
function stdioCommandPreview(config) {
|
|
35187
|
+
return [config.command, ...config.args ?? []].join(" ");
|
|
35188
|
+
}
|
|
35189
|
+
function mcpEnvBindings(config) {
|
|
35190
|
+
if (config.type !== "stdio" || !config.env) return void 0;
|
|
35191
|
+
const bindings = Object.entries(config.env).map(([child, mapping]) => ({
|
|
35192
|
+
child,
|
|
35193
|
+
source: mapping.env
|
|
35194
|
+
}));
|
|
35195
|
+
return bindings.length > 0 ? bindings : void 0;
|
|
35196
|
+
}
|
|
35197
|
+
function isMcpAuthed(server, auth, env) {
|
|
35198
|
+
if (server.config.enabled === false) return false;
|
|
35199
|
+
if (server.userDeclared && getCatalogEntry(server.name)) return false;
|
|
35200
|
+
if (server.config.type === "stdio") return true;
|
|
35201
|
+
const usesOAuth = server.config.type === "http" && server.config.oauth === true;
|
|
35202
|
+
const bearerTokenEnvVar = server.config.type === "http" ? server.config.bearerTokenEnvVar : void 0;
|
|
35203
|
+
if (!usesOAuth && !bearerTokenEnvVar) return true;
|
|
35204
|
+
if (bearerTokenEnvVar && env[bearerTokenEnvVar]?.trim()) return true;
|
|
35205
|
+
const cred = auth.get(mcpProviderId(server.name));
|
|
35206
|
+
if (cred === void 0) return false;
|
|
35207
|
+
if (!server.userDeclared) return true;
|
|
35208
|
+
const endpoint = cred.endpoint;
|
|
35209
|
+
return typeof endpoint === "string" && server.config.type === "http" && endpoint === server.config.url;
|
|
35210
|
+
}
|
|
35211
|
+
function mcpConnectionStatus(server, authed) {
|
|
35212
|
+
if (server.config.enabled === false) return "disabled";
|
|
35213
|
+
if (authed) return server.config.type === "http" && server.config.oauth !== true && !server.config.bearerTokenEnvVar ? "anonymous" : "connected";
|
|
35214
|
+
return "needs_auth";
|
|
35215
|
+
}
|
|
35216
|
+
function toMcpConnectionInfo(server, auth, env) {
|
|
35217
|
+
const usesOAuth = server.config.type === "http" && server.config.oauth === true;
|
|
35218
|
+
const catalogShadow = server.userDeclared && Boolean(getCatalogEntry(server.name));
|
|
35219
|
+
const authed = isMcpAuthed(server, auth, env);
|
|
35220
|
+
const envBindings = mcpEnvBindings(server.config);
|
|
35221
|
+
return {
|
|
35222
|
+
name: server.name,
|
|
35223
|
+
label: server.label,
|
|
35224
|
+
source: server.source,
|
|
35225
|
+
transport: server.config.type,
|
|
35226
|
+
usesOAuth,
|
|
35227
|
+
enabled: authed,
|
|
35228
|
+
status: mcpConnectionStatus(server, authed),
|
|
35229
|
+
...server.config.type === "http" ? { url: server.config.url } : {},
|
|
35230
|
+
...server.config.type === "stdio" ? { commandPreview: stdioCommandPreview(server.config) } : {},
|
|
35231
|
+
...server.config.type === "stdio" && server.config.cwd ? { cwdPreview: safePathLabel(server.config.cwd) } : {},
|
|
35232
|
+
...server.config.type === "http" && server.config.bearerTokenEnvVar ? { bearerTokenEnvVar: server.config.bearerTokenEnvVar } : {},
|
|
35233
|
+
...envBindings ? { envBindings } : {},
|
|
35234
|
+
...catalogShadow ? { error: "This name is reserved for a built-in integration." } : {}
|
|
35235
|
+
};
|
|
35236
|
+
}
|
|
35237
|
+
function listMcpServers(userServers) {
|
|
35238
|
+
const listed = [];
|
|
35239
|
+
for (const entry of BUILTIN_MCP_CATALOG) listed.push({
|
|
35240
|
+
name: entry.server,
|
|
35241
|
+
label: entry.label,
|
|
35242
|
+
source: "builtin",
|
|
35243
|
+
userDeclared: false,
|
|
35244
|
+
config: {
|
|
35245
|
+
type: "http",
|
|
35246
|
+
url: entry.url,
|
|
35247
|
+
oauth: true
|
|
35248
|
+
}
|
|
35249
|
+
});
|
|
35250
|
+
for (const [name, config] of Object.entries(userServers ?? {}).sort(([left], [right]) => left.localeCompare(right))) listed.push({
|
|
35251
|
+
name,
|
|
35252
|
+
label: name,
|
|
35253
|
+
source: "user",
|
|
35254
|
+
userDeclared: true,
|
|
35255
|
+
config
|
|
35256
|
+
});
|
|
35257
|
+
return listed;
|
|
35258
|
+
}
|
|
35259
|
+
function listMcpConnections(userServers, auth, env = process.env) {
|
|
35260
|
+
return listMcpServers(userServers).map((server) => toMcpConnectionInfo(server, auth, env));
|
|
35261
|
+
}
|
|
35262
|
+
function dropMcpServerCredentials(name, auth) {
|
|
35263
|
+
if (getCatalogEntry(name)) return;
|
|
35264
|
+
try {
|
|
35265
|
+
auth.removeVerified(mcpProviderId(name));
|
|
35266
|
+
} catch (error) {
|
|
35267
|
+
throw new McpRequestError(`Could not remove stored credentials for this MCP server: ${error instanceof Error ? error.message : String(error)}`);
|
|
35268
|
+
}
|
|
35269
|
+
}
|
|
35270
|
+
async function confineMcpStdioCwd(cwd, workspaceRoot) {
|
|
35271
|
+
if (cwd === void 0 || cwd.trim() === "") return void 0;
|
|
35272
|
+
const root2 = resolve(workspaceRoot);
|
|
35273
|
+
const canonicalRoot = await realpath(root2).catch(() => root2);
|
|
35274
|
+
const candidate = resolve(root2, cwd);
|
|
35275
|
+
const existingCandidate = await realpath(candidate).catch(() => void 0);
|
|
35276
|
+
if (existingCandidate && existingCandidate !== canonicalRoot && !existingCandidate.startsWith(`${canonicalRoot}${sep}`)) throw new McpRequestError("MCP stdio working directory must stay inside the workspace.");
|
|
35277
|
+
let ancestor = dirname(candidate);
|
|
35278
|
+
while (true) {
|
|
35279
|
+
const resolvedAncestor = await realpath(ancestor).catch(() => void 0);
|
|
35280
|
+
if (resolvedAncestor) {
|
|
35281
|
+
if (resolvedAncestor !== canonicalRoot && !resolvedAncestor.startsWith(`${canonicalRoot}${sep}`)) throw new McpRequestError("MCP stdio working directory must stay inside the workspace.");
|
|
35282
|
+
break;
|
|
35283
|
+
}
|
|
35284
|
+
const parent = dirname(ancestor);
|
|
35285
|
+
if (parent === ancestor) throw new McpRequestError("MCP stdio working directory must stay inside the workspace.");
|
|
35286
|
+
ancestor = parent;
|
|
35287
|
+
}
|
|
35288
|
+
return candidate;
|
|
35289
|
+
}
|
|
35290
|
+
function storedApiForCustomProvider(api) {
|
|
35291
|
+
return api === "google-genai" ? "google-generative-ai" : api;
|
|
35292
|
+
}
|
|
35293
|
+
function uiApiForCustomProvider(value) {
|
|
35294
|
+
if (value === "google-generative-ai") return "google-genai";
|
|
35295
|
+
return isPiCustomProviderApi(value) ? value : void 0;
|
|
35296
|
+
}
|
|
35297
|
+
function envVarNameForManagedProvider(providerId) {
|
|
35298
|
+
if (providerId === "openai-chat-completions") return "OPENAI_CHAT_COMPLETIONS_API_KEY";
|
|
35299
|
+
const slug = providerId.slice(providerId.indexOf("+") + 1).toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
35300
|
+
return isOccProviderId(providerId) ? `OPENAI_CHAT_COMPLETIONS_${slug}_API_KEY` : `CUSTOM_${slug}_API_KEY`;
|
|
35301
|
+
}
|
|
35302
|
+
function readModelsJson(filePath) {
|
|
35303
|
+
try {
|
|
35304
|
+
if (!existsSync(filePath)) return {};
|
|
35305
|
+
return parseModelsJson(readFileSync(filePath, "utf-8"));
|
|
35306
|
+
} catch {
|
|
35307
|
+
return {};
|
|
35308
|
+
}
|
|
35309
|
+
}
|
|
35310
|
+
function stripJsonComments(input) {
|
|
35311
|
+
return input.replace(/"(?:\\.|[^"\\])*"|\/\/[^\n]*/g, (match) => match[0] === '"' ? match : "").replace(/"(?:\\.|[^"\\])*"|,(\s*[}\]])/g, (match, tail) => tail ?? (match[0] === '"' ? match : ""));
|
|
35312
|
+
}
|
|
35313
|
+
function parseModelsJson(raw) {
|
|
35314
|
+
const parsed = JSON.parse(stripJsonComments(raw));
|
|
35315
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("models.json must contain an object");
|
|
35316
|
+
return parsed;
|
|
35317
|
+
}
|
|
35318
|
+
function readModelsJsonForWrite(filePath) {
|
|
35319
|
+
if (!existsSync(filePath)) return {};
|
|
35320
|
+
try {
|
|
35321
|
+
return parseModelsJson(readFileSync(filePath, "utf-8"));
|
|
35322
|
+
} catch (error) {
|
|
35323
|
+
throw new Error(`Refusing to update models.json because it could not be parsed: ${error instanceof Error ? error.message : error}`);
|
|
35324
|
+
}
|
|
35325
|
+
}
|
|
35326
|
+
function mergeModelDefinitions(existing, incoming) {
|
|
35327
|
+
const existingById = new Map((existing ?? []).map((model) => [model.id, model]));
|
|
35328
|
+
const seen = /* @__PURE__ */ new Set();
|
|
35329
|
+
return incoming.flatMap((model) => {
|
|
35330
|
+
if (seen.has(model.id)) return [];
|
|
35331
|
+
seen.add(model.id);
|
|
35332
|
+
return [{
|
|
35333
|
+
...existingById.get(model.id),
|
|
35334
|
+
...model
|
|
35335
|
+
}];
|
|
35336
|
+
});
|
|
35337
|
+
}
|
|
35338
|
+
function listCustomProviders(filePath) {
|
|
35339
|
+
return readModelsJson(filePath).providers ?? {};
|
|
35340
|
+
}
|
|
35341
|
+
function writeModelsJson(filePath, data) {
|
|
35342
|
+
mkdirSync(dirname(filePath), {
|
|
35343
|
+
recursive: true,
|
|
35344
|
+
mode: 448
|
|
35345
|
+
});
|
|
35346
|
+
const serialized = `${JSON.stringify(data, null, " ")}
|
|
35347
|
+
`;
|
|
35348
|
+
const tmpPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
35349
|
+
writeFileSync(tmpPath, serialized, "utf-8");
|
|
35350
|
+
renameSync(tmpPath, filePath);
|
|
35351
|
+
}
|
|
35352
|
+
function upsertCustomProvider(filePath, providerId, input) {
|
|
35353
|
+
const data = readModelsJsonForWrite(filePath);
|
|
35354
|
+
const providers = { ...data.providers ?? {} };
|
|
35355
|
+
const existing = providers[providerId] ?? {};
|
|
35356
|
+
providers[providerId] = {
|
|
35357
|
+
...existing,
|
|
35358
|
+
name: input.name ?? existing.name,
|
|
35359
|
+
baseUrl: input.baseUrl,
|
|
35360
|
+
api: storedApiForCustomProvider(input.api),
|
|
35361
|
+
apiKey: input.apiKey,
|
|
35362
|
+
models: mergeModelDefinitions(existing.models, input.models)
|
|
35363
|
+
};
|
|
35364
|
+
writeModelsJson(filePath, {
|
|
35365
|
+
...data,
|
|
35366
|
+
providers
|
|
35367
|
+
});
|
|
35368
|
+
}
|
|
35369
|
+
function addCustomProviderModelIds(filePath, providerId, modelIds) {
|
|
35370
|
+
const data = readModelsJsonForWrite(filePath);
|
|
35371
|
+
const providers = { ...data.providers ?? {} };
|
|
35372
|
+
const existing = providers[providerId];
|
|
35373
|
+
if (!existing) return;
|
|
35374
|
+
providers[providerId] = {
|
|
35375
|
+
...existing,
|
|
35376
|
+
models: mergeModelDefinitions(existing.models, [...existing.models ?? [], ...modelIds.map((id) => ({ id }))])
|
|
35377
|
+
};
|
|
35378
|
+
writeModelsJson(filePath, {
|
|
35379
|
+
...data,
|
|
35380
|
+
providers
|
|
35381
|
+
});
|
|
35382
|
+
}
|
|
35383
|
+
function removeCustomProvider(filePath, providerId) {
|
|
35384
|
+
const data = readModelsJsonForWrite(filePath);
|
|
35385
|
+
const providers = data.providers;
|
|
35386
|
+
if (!providers || !(providerId in providers)) return;
|
|
35387
|
+
const next = { ...providers };
|
|
35388
|
+
delete next[providerId];
|
|
35389
|
+
writeModelsJson(filePath, {
|
|
35390
|
+
...data,
|
|
35391
|
+
providers: next
|
|
35392
|
+
});
|
|
35393
|
+
}
|
|
35394
|
+
function isDiscoverableEntry(entry) {
|
|
35395
|
+
const baseUrl = entry?.baseUrl;
|
|
35396
|
+
if (!baseUrl) return false;
|
|
35397
|
+
const api = uiApiForCustomProvider(entry?.api);
|
|
35398
|
+
if (api && !isOccFamilyApi(api)) return false;
|
|
35399
|
+
if (entry?.api && !api) return false;
|
|
35400
|
+
try {
|
|
35401
|
+
const parsed = new URL(baseUrl);
|
|
35402
|
+
return parsed.protocol === "https:" || parsed.protocol === "http:";
|
|
35403
|
+
} catch {
|
|
35404
|
+
return false;
|
|
35405
|
+
}
|
|
35406
|
+
}
|
|
34952
35407
|
var PRIME_PROVIDER_ENV_MAP = {
|
|
34953
35408
|
openai: "OPENAI_API_KEY",
|
|
34954
35409
|
"azure-openai-responses": "AZURE_OPENAI_API_KEY",
|
|
@@ -35072,7 +35527,7 @@ function listChatProviders() {
|
|
|
35072
35527
|
function handleChatProvidersGet(_request) {
|
|
35073
35528
|
return wrapApiHandler(async () => {
|
|
35074
35529
|
return Response.json({ providers: buildProviders() });
|
|
35075
|
-
});
|
|
35530
|
+
}, _request);
|
|
35076
35531
|
}
|
|
35077
35532
|
function requireBaseUrl(baseUrl, providerId) {
|
|
35078
35533
|
const trimmed = baseUrl?.trim() ?? "";
|
|
@@ -35141,7 +35596,7 @@ function handleChatProvidersPost(request) {
|
|
|
35141
35596
|
success: true,
|
|
35142
35597
|
providers: buildProviders()
|
|
35143
35598
|
});
|
|
35144
|
-
});
|
|
35599
|
+
}, request);
|
|
35145
35600
|
}
|
|
35146
35601
|
function handleChatProvidersDelete(request) {
|
|
35147
35602
|
return wrapApiHandler(async () => {
|
|
@@ -35155,7 +35610,7 @@ function handleChatProvidersDelete(request) {
|
|
|
35155
35610
|
success: true,
|
|
35156
35611
|
providers: buildProviders()
|
|
35157
35612
|
});
|
|
35158
|
-
});
|
|
35613
|
+
}, request);
|
|
35159
35614
|
}
|
|
35160
35615
|
var LOGIN_TTL_MS = 96e4;
|
|
35161
35616
|
var sessions = /* @__PURE__ */ new Map();
|
|
@@ -35285,7 +35740,7 @@ function cancelOAuthLogin(loginId) {
|
|
|
35285
35740
|
error: "Login cancelled"
|
|
35286
35741
|
};
|
|
35287
35742
|
}
|
|
35288
|
-
function oauthDeps() {
|
|
35743
|
+
function oauthDeps$1() {
|
|
35289
35744
|
const config = getPrimeConfig();
|
|
35290
35745
|
return {
|
|
35291
35746
|
login: (providerId, callbacks) => config.authStorage.login(providerId, callbacks),
|
|
@@ -35312,8 +35767,423 @@ function handleChatProvidersOAuthPost(request) {
|
|
|
35312
35767
|
status: "error",
|
|
35313
35768
|
error: `Unknown OAuth provider: ${body.providerId}`
|
|
35314
35769
|
}, { status: 400 });
|
|
35315
|
-
return Response.json(startOAuthLogin(body.providerId, oauthDeps()));
|
|
35316
|
-
});
|
|
35770
|
+
return Response.json(startOAuthLogin(body.providerId, oauthDeps$1()));
|
|
35771
|
+
}, request);
|
|
35772
|
+
}
|
|
35773
|
+
function defaultMcpDeps() {
|
|
35774
|
+
const config = getPrimeConfig();
|
|
35775
|
+
const settings = config.defaultSettings;
|
|
35776
|
+
return {
|
|
35777
|
+
getUserServers: () => settings.getGlobalMcpServers(),
|
|
35778
|
+
setUserServer: (name, serverConfig, force) => {
|
|
35779
|
+
settings.setGlobalMcpServer(name, serverConfig, force);
|
|
35780
|
+
},
|
|
35781
|
+
removeUserServer: (name) => settings.removeGlobalMcpServer(name),
|
|
35782
|
+
flushSettings: async () => {
|
|
35783
|
+
await settings.flush();
|
|
35784
|
+
const error = settings.drainErrors("global")[0];
|
|
35785
|
+
if (error) throw error.error;
|
|
35786
|
+
},
|
|
35787
|
+
auth: config.authStorage,
|
|
35788
|
+
workspaceRoot: config.defaultCwd,
|
|
35789
|
+
env: process.env,
|
|
35790
|
+
reloadAuth: () => {
|
|
35791
|
+
config.reloadAuth();
|
|
35792
|
+
},
|
|
35793
|
+
reloadResources: async () => {
|
|
35794
|
+
await getBridge().reloadResources();
|
|
35795
|
+
}
|
|
35796
|
+
};
|
|
35797
|
+
}
|
|
35798
|
+
function listedConnections(deps) {
|
|
35799
|
+
return listMcpConnections(deps.getUserServers(), deps.auth, deps.env);
|
|
35800
|
+
}
|
|
35801
|
+
function listResponse(deps) {
|
|
35802
|
+
return { connections: listedConnections(deps) };
|
|
35803
|
+
}
|
|
35804
|
+
function toMcpOAuthResponse(snapshot2, connections) {
|
|
35805
|
+
return {
|
|
35806
|
+
status: snapshot2.status,
|
|
35807
|
+
...snapshot2.loginId ? { loginId: snapshot2.loginId } : {},
|
|
35808
|
+
...snapshot2.authUrl ? { authUrl: snapshot2.authUrl } : {},
|
|
35809
|
+
...snapshot2.userCode ? { userCode: snapshot2.userCode } : {},
|
|
35810
|
+
...snapshot2.instructions ? { instructions: snapshot2.instructions } : {},
|
|
35811
|
+
...snapshot2.prompt ? { prompt: snapshot2.prompt } : {},
|
|
35812
|
+
...snapshot2.error ? { error: snapshot2.error } : {},
|
|
35813
|
+
...connections ? { connections } : {}
|
|
35814
|
+
};
|
|
35815
|
+
}
|
|
35816
|
+
function ensureMcpOAuthProvider(name, deps) {
|
|
35817
|
+
registerBuiltinMcpOAuthProviders();
|
|
35818
|
+
if (getCatalogEntry(name)) return;
|
|
35819
|
+
const config = deps.getUserServers()?.[name];
|
|
35820
|
+
if (!config || config.type !== "http" || config.oauth !== true) throw new McpRequestError("This MCP server does not use OAuth.");
|
|
35821
|
+
registerOAuthProvider(createMcpOAuthProvider({
|
|
35822
|
+
server: name,
|
|
35823
|
+
label: name,
|
|
35824
|
+
url: config.url
|
|
35825
|
+
}));
|
|
35826
|
+
}
|
|
35827
|
+
function oauthDeps(deps) {
|
|
35828
|
+
return {
|
|
35829
|
+
login: (providerId, callbacks) => deps.auth.login(providerId, callbacks),
|
|
35830
|
+
reloadAuth: () => {
|
|
35831
|
+
deps.reloadAuth();
|
|
35832
|
+
deps.reloadResources();
|
|
35833
|
+
},
|
|
35834
|
+
listProviders: () => []
|
|
35835
|
+
};
|
|
35836
|
+
}
|
|
35837
|
+
async function logoutMcp(name, deps) {
|
|
35838
|
+
try {
|
|
35839
|
+
deps.auth.removeVerified(mcpProviderId(name));
|
|
35840
|
+
} catch (error) {
|
|
35841
|
+
throw new McpRequestError(`Could not remove stored credentials: ${error instanceof Error ? error.message : String(error)}`);
|
|
35842
|
+
}
|
|
35843
|
+
deps.reloadAuth();
|
|
35844
|
+
await deps.reloadResources();
|
|
35845
|
+
return {
|
|
35846
|
+
status: "success",
|
|
35847
|
+
connections: listedConnections(deps)
|
|
35848
|
+
};
|
|
35849
|
+
}
|
|
35850
|
+
function handleChatMcpGet(_request, deps = defaultMcpDeps()) {
|
|
35851
|
+
return wrapApiHandler(async () => Response.json(listResponse(deps)), _request);
|
|
35852
|
+
}
|
|
35853
|
+
function handleChatMcpPost(request, deps = defaultMcpDeps()) {
|
|
35854
|
+
return wrapApiHandler(async () => {
|
|
35855
|
+
const body = ChatMcpUpsertRequestSchema.parse(await request.json().catch(() => ({})));
|
|
35856
|
+
if (getCatalogEntry(body.name)) throw new McpRequestError(`MCP server name "${body.name}" is reserved for a built-in integration.`);
|
|
35857
|
+
if (deps.getUserServers()?.[body.name] && body.force !== true) throw new McpRequestError(`MCP server "${body.name}" already exists. Replace it to continue.`);
|
|
35858
|
+
let config;
|
|
35859
|
+
switch (body.transport) {
|
|
35860
|
+
case "http":
|
|
35861
|
+
if (body.bearerTokenEnvVar && body.oauth) throw new McpRequestError("OAuth and a bearer-token environment variable cannot be combined.");
|
|
35862
|
+
config = {
|
|
35863
|
+
type: "http",
|
|
35864
|
+
url: validateHttpMcpUrl(body.url),
|
|
35865
|
+
...body.bearerTokenEnvVar ? { bearerTokenEnvVar: body.bearerTokenEnvVar } : {},
|
|
35866
|
+
...body.oauth ? { oauth: true } : {}
|
|
35867
|
+
};
|
|
35868
|
+
break;
|
|
35869
|
+
case "stdio": {
|
|
35870
|
+
if (body.command.includes("\0") || body.args?.some((part) => part.includes("\0"))) throw new McpRequestError("MCP command arguments cannot contain NUL.");
|
|
35871
|
+
const env = Object.fromEntries((body.env ?? []).map((binding) => [binding.child, { env: binding.source }]));
|
|
35872
|
+
const cwd = await confineMcpStdioCwd(body.cwd, deps.workspaceRoot);
|
|
35873
|
+
config = {
|
|
35874
|
+
type: "stdio",
|
|
35875
|
+
command: body.command,
|
|
35876
|
+
...body.args && body.args.length > 0 ? { args: body.args } : {},
|
|
35877
|
+
...cwd ? { cwd } : {},
|
|
35878
|
+
...Object.keys(env).length > 0 ? { env } : {}
|
|
35879
|
+
};
|
|
35880
|
+
break;
|
|
35881
|
+
}
|
|
35882
|
+
default:
|
|
35883
|
+
throw new McpRequestError(`Unsupported MCP transport: ${String(body)}`);
|
|
35884
|
+
}
|
|
35885
|
+
dropMcpServerCredentials(body.name, deps.auth);
|
|
35886
|
+
deps.setUserServer(body.name, config, true);
|
|
35887
|
+
await deps.flushSettings();
|
|
35888
|
+
deps.reloadAuth();
|
|
35889
|
+
await deps.reloadResources();
|
|
35890
|
+
return Response.json(listResponse(deps));
|
|
35891
|
+
}, request);
|
|
35892
|
+
}
|
|
35893
|
+
function handleChatMcpDelete(request, deps = defaultMcpDeps()) {
|
|
35894
|
+
return wrapApiHandler(async () => {
|
|
35895
|
+
const body = ChatMcpDeleteRequestSchema.parse(await request.json().catch(() => ({})));
|
|
35896
|
+
if (!deps.removeUserServer(body.name)) throw new McpRequestError(`MCP server "${body.name}" was not found.`);
|
|
35897
|
+
await deps.flushSettings();
|
|
35898
|
+
dropMcpServerCredentials(body.name, deps.auth);
|
|
35899
|
+
deps.reloadAuth();
|
|
35900
|
+
await deps.reloadResources();
|
|
35901
|
+
return Response.json(listResponse(deps));
|
|
35902
|
+
}, request);
|
|
35903
|
+
}
|
|
35904
|
+
function handleChatMcpOAuthPost(request, deps = defaultMcpDeps()) {
|
|
35905
|
+
return wrapApiHandler(async () => {
|
|
35906
|
+
const body = ChatMcpOAuthLoginRequestSchema.parse(await request.json().catch(() => ({})));
|
|
35907
|
+
if (![...BUILTIN_MCP_CATALOG.map((entry) => entry.server), ...Object.keys(deps.getUserServers() ?? {})].includes(body.name) && !body.loginId) throw new McpRequestError(`Unknown MCP server: ${body.name}`);
|
|
35908
|
+
if (body.cancel) {
|
|
35909
|
+
if (!body.loginId) return Response.json({
|
|
35910
|
+
status: "error",
|
|
35911
|
+
error: "loginId is required to cancel"
|
|
35912
|
+
}, { status: 400 });
|
|
35913
|
+
return Response.json(toMcpOAuthResponse(cancelOAuthLogin(body.loginId)));
|
|
35914
|
+
}
|
|
35915
|
+
if (body.loginId && body.promptAnswer !== void 0) return Response.json(toMcpOAuthResponse(continueOAuthLogin(body.loginId, body.promptAnswer)));
|
|
35916
|
+
if (body.loginId) {
|
|
35917
|
+
const snapshot2 = pollOAuthLogin(body.loginId);
|
|
35918
|
+
return Response.json(toMcpOAuthResponse(snapshot2, snapshot2.status === "success" ? listedConnections(deps) : void 0));
|
|
35919
|
+
}
|
|
35920
|
+
const action = body.action ?? "login";
|
|
35921
|
+
switch (action) {
|
|
35922
|
+
case "logout":
|
|
35923
|
+
return Response.json(await logoutMcp(body.name, deps));
|
|
35924
|
+
case "reconnect":
|
|
35925
|
+
await logoutMcp(body.name, deps);
|
|
35926
|
+
break;
|
|
35927
|
+
case "login":
|
|
35928
|
+
break;
|
|
35929
|
+
default:
|
|
35930
|
+
throw new McpRequestError(`Unsupported MCP OAuth action: ${String(action)}`);
|
|
35931
|
+
}
|
|
35932
|
+
ensureMcpOAuthProvider(body.name, deps);
|
|
35933
|
+
const providerId = mcpProviderId(body.name);
|
|
35934
|
+
if (!getOAuthProvider(providerId)) return Response.json({
|
|
35935
|
+
status: "error",
|
|
35936
|
+
error: `Unknown OAuth provider: ${providerId}`
|
|
35937
|
+
}, { status: 400 });
|
|
35938
|
+
return Response.json(toMcpOAuthResponse(startOAuthLogin(providerId, oauthDeps(deps))));
|
|
35939
|
+
}, request);
|
|
35940
|
+
}
|
|
35941
|
+
var BodySchema$1 = external_exports.object({
|
|
35942
|
+
sessionId: SessionIdSchema,
|
|
35943
|
+
model: external_exports.object({
|
|
35944
|
+
provider: external_exports.string(),
|
|
35945
|
+
id: external_exports.string()
|
|
35946
|
+
})
|
|
35947
|
+
});
|
|
35948
|
+
function handleChatModelPost(request) {
|
|
35949
|
+
return wrapApiHandler(async () => {
|
|
35950
|
+
const raw = await request.json().catch(() => ({}));
|
|
35951
|
+
const body = BodySchema$1.parse(raw);
|
|
35952
|
+
const bridge = getBridge();
|
|
35953
|
+
const session = bridge.getSession(body.sessionId) ?? await bridge.resumeSessionById(body.sessionId);
|
|
35954
|
+
if (!session || !await requireProjectSession(session)) return Response.json({ message: `Unknown session: ${body.sessionId}` }, { status: 404 });
|
|
35955
|
+
await bridge.setModel(body.sessionId, {
|
|
35956
|
+
provider: body.model.provider,
|
|
35957
|
+
id: body.model.id
|
|
35958
|
+
});
|
|
35959
|
+
return Response.json({ ok: true });
|
|
35960
|
+
}, request);
|
|
35961
|
+
}
|
|
35962
|
+
function toPatternCandidate(model) {
|
|
35963
|
+
return {
|
|
35964
|
+
id: model.id,
|
|
35965
|
+
name: model.name,
|
|
35966
|
+
provider: model.provider,
|
|
35967
|
+
modelId: model.id,
|
|
35968
|
+
key: `${model.provider}/${model.id}`
|
|
35969
|
+
};
|
|
35970
|
+
}
|
|
35971
|
+
function handleChatModelsGet(request) {
|
|
35972
|
+
return wrapApiHandler(async () => {
|
|
35973
|
+
const config = getPrimeConfig();
|
|
35974
|
+
const cwd = await cwdForRequest(request);
|
|
35975
|
+
const settings = config.settingsFor(cwd);
|
|
35976
|
+
const registry = config.modelRegistry;
|
|
35977
|
+
const scope = new URL(request.url).searchParams.get("scope") === "all" ? "all" : "enabled";
|
|
35978
|
+
let models = registry.getAll();
|
|
35979
|
+
if (scope === "enabled") {
|
|
35980
|
+
models = models.filter((model) => registry.hasConfiguredAuth(model));
|
|
35981
|
+
const patterns = settings.getEnabledModels();
|
|
35982
|
+
if (patterns !== void 0) models = models.filter((model) => isModelPatternEnabled(toPatternCandidate(model), patterns));
|
|
35983
|
+
}
|
|
35984
|
+
const diagnostics = [];
|
|
35985
|
+
const defaultProvider = settings.getDefaultProvider();
|
|
35986
|
+
const defaultModel = settings.getDefaultModel();
|
|
35987
|
+
const defaultThinkingLevel = settings.getDefaultThinkingLevel();
|
|
35988
|
+
const selectedModelKey = defaultProvider && defaultModel ? `${defaultProvider}/${defaultModel}` : void 0;
|
|
35989
|
+
return Response.json({
|
|
35990
|
+
models: models.map((m) => {
|
|
35991
|
+
const thinkingLevels = getSupportedThinkingLevels(m);
|
|
35992
|
+
const fallback = m.reasoning ? "medium" : "off";
|
|
35993
|
+
return {
|
|
35994
|
+
key: `${m.provider}/${m.id}`,
|
|
35995
|
+
provider: m.provider,
|
|
35996
|
+
id: m.id,
|
|
35997
|
+
name: m.name,
|
|
35998
|
+
reasoning: m.reasoning,
|
|
35999
|
+
input: m.input,
|
|
36000
|
+
contextWindow: m.contextWindow,
|
|
36001
|
+
maxTokens: m.maxTokens,
|
|
36002
|
+
available: registry.hasConfiguredAuth(m),
|
|
36003
|
+
thinkingLevels,
|
|
36004
|
+
defaultThinkingLevel: thinkingLevels.includes(fallback) ? fallback : thinkingLevels[0] ?? "off"
|
|
36005
|
+
};
|
|
36006
|
+
}),
|
|
36007
|
+
...selectedModelKey ? { selectedModelKey } : {},
|
|
36008
|
+
...defaultProvider ? { defaultProvider } : {},
|
|
36009
|
+
...defaultModel ? { defaultModel } : {},
|
|
36010
|
+
...defaultThinkingLevel ? { defaultThinkingLevel } : {},
|
|
36011
|
+
diagnostics
|
|
36012
|
+
});
|
|
36013
|
+
}, request);
|
|
36014
|
+
}
|
|
36015
|
+
function openAiModelsUrl(baseUrl) {
|
|
36016
|
+
const parsed = new URL(baseUrl);
|
|
36017
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") throw new Error("model discovery requires an http(s) URL");
|
|
36018
|
+
if (parsed.protocol === "http:" && !isLoopbackHostname(parsed.hostname)) throw new Error("model discovery requires https for non-loopback hosts");
|
|
36019
|
+
const path = parsed.pathname.replace(/\/+$/, "");
|
|
36020
|
+
parsed.pathname = path.endsWith("/v1") ? `${path}/models` : `${path}/v1/models`;
|
|
36021
|
+
parsed.search = "";
|
|
36022
|
+
parsed.hash = "";
|
|
36023
|
+
return parsed;
|
|
36024
|
+
}
|
|
36025
|
+
function handleChatModelsDiscoverPost(request) {
|
|
36026
|
+
return wrapApiHandler(async () => {
|
|
36027
|
+
const raw = await request.json().catch(() => ({}));
|
|
36028
|
+
const body = ChatModelsDiscoverRequestSchema.parse(raw);
|
|
36029
|
+
const config = getPrimeConfig();
|
|
36030
|
+
const apiKey = await config.modelRegistry.getApiKeyForProvider(body.providerId);
|
|
36031
|
+
if (!apiKey) return Response.json({
|
|
36032
|
+
providerId: body.providerId,
|
|
36033
|
+
models: []
|
|
36034
|
+
});
|
|
36035
|
+
const provider = body.providerId;
|
|
36036
|
+
const entry = listCustomProviders(`${config.agentDir}/models.json`)[provider];
|
|
36037
|
+
const api = uiApiForCustomProvider(entry?.api);
|
|
36038
|
+
if (entry?.api && !api || api && !isOccFamilyApi(api)) return Response.json({
|
|
36039
|
+
providerId: provider,
|
|
36040
|
+
models: []
|
|
36041
|
+
});
|
|
36042
|
+
const baseUrl = entry?.baseUrl;
|
|
36043
|
+
if (!baseUrl) return Response.json({
|
|
36044
|
+
providerId: provider,
|
|
36045
|
+
models: []
|
|
36046
|
+
});
|
|
36047
|
+
try {
|
|
36048
|
+
const modelsUrl = openAiModelsUrl(baseUrl);
|
|
36049
|
+
const response = await fetch(modelsUrl, {
|
|
36050
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
36051
|
+
redirect: "error",
|
|
36052
|
+
signal: AbortSignal.timeout(1e4)
|
|
36053
|
+
});
|
|
36054
|
+
if (!response.ok) return Response.json({
|
|
36055
|
+
providerId: provider,
|
|
36056
|
+
models: []
|
|
36057
|
+
});
|
|
36058
|
+
const models = ((await response.json()).data ?? []).map((m) => ({
|
|
36059
|
+
key: `${provider}/${m.id}`,
|
|
36060
|
+
provider,
|
|
36061
|
+
id: m.id,
|
|
36062
|
+
name: m.id,
|
|
36063
|
+
reasoning: false,
|
|
36064
|
+
input: ["text"],
|
|
36065
|
+
available: true,
|
|
36066
|
+
defaultThinkingLevel: "off",
|
|
36067
|
+
thinkingLevels: ["off"]
|
|
36068
|
+
}));
|
|
36069
|
+
if (models.length > 0) {
|
|
36070
|
+
addCustomProviderModelIds(`${config.agentDir}/models.json`, provider, models.map((model) => model.id));
|
|
36071
|
+
config.reloadAuth();
|
|
36072
|
+
}
|
|
36073
|
+
return Response.json({
|
|
36074
|
+
providerId: provider,
|
|
36075
|
+
models
|
|
36076
|
+
});
|
|
36077
|
+
} catch {
|
|
36078
|
+
return Response.json({
|
|
36079
|
+
providerId: provider,
|
|
36080
|
+
models: []
|
|
36081
|
+
});
|
|
36082
|
+
}
|
|
36083
|
+
}, request);
|
|
36084
|
+
}
|
|
36085
|
+
function toThinkingLevel(level) {
|
|
36086
|
+
return level;
|
|
36087
|
+
}
|
|
36088
|
+
function handleChatNewPost(request) {
|
|
36089
|
+
return wrapApiHandler(async () => {
|
|
36090
|
+
const bridge = getBridge();
|
|
36091
|
+
const registry = getPrimeConfig().projectRegistry;
|
|
36092
|
+
const raw = await request.json().catch(() => ({}));
|
|
36093
|
+
const body = ChatNewRequestSchema.parse(raw);
|
|
36094
|
+
const projectId = body.projectId ?? await registry.projectIdForCwd(getPrimeConfig().defaultCwd) ?? (await registry.register(getPrimeConfig().defaultCwd)).projectId;
|
|
36095
|
+
const project = await registry.get(projectId);
|
|
36096
|
+
bridge.ensureKernelReady(project.canonicalPath).catch(() => {
|
|
36097
|
+
});
|
|
36098
|
+
const session = await bridge.createSession({
|
|
36099
|
+
cwd: project.canonicalPath,
|
|
36100
|
+
projectId,
|
|
36101
|
+
thinkingLevel: toThinkingLevel(body.thinkingLevel),
|
|
36102
|
+
mode: body.mode,
|
|
36103
|
+
openUI: body.openUI
|
|
36104
|
+
});
|
|
36105
|
+
if (body.model) {
|
|
36106
|
+
await bridge.setModel(session.sessionId, body.model);
|
|
36107
|
+
const thinking = body.model.thinkingLevel ?? body.thinkingLevel;
|
|
36108
|
+
if (thinking) await session.connection.setThinkingLevel(toThinkingLevel(thinking));
|
|
36109
|
+
}
|
|
36110
|
+
return Response.json({
|
|
36111
|
+
session: {
|
|
36112
|
+
sessionId: session.sessionId,
|
|
36113
|
+
projectId
|
|
36114
|
+
},
|
|
36115
|
+
messages: [],
|
|
36116
|
+
planPresentations: [],
|
|
36117
|
+
presentation: bridge.getPresentation(session.sessionId)
|
|
36118
|
+
});
|
|
36119
|
+
}, request);
|
|
36120
|
+
}
|
|
36121
|
+
function record(value) {
|
|
36122
|
+
return typeof value === "object" && value !== null ? value : void 0;
|
|
36123
|
+
}
|
|
36124
|
+
function artifactIndexFor(artifact) {
|
|
36125
|
+
const input = record(artifact.input);
|
|
36126
|
+
return typeof input?.artifactIndex === "number" ? input.artifactIndex : void 0;
|
|
36127
|
+
}
|
|
36128
|
+
function handleChatOpenUIArtifactPut(request) {
|
|
36129
|
+
return wrapApiHandler(async () => {
|
|
36130
|
+
const raw = await request.json().catch(() => ({}));
|
|
36131
|
+
const parsed = ChatOpenUIArtifactUpsertRequestSchema.safeParse(raw);
|
|
36132
|
+
if (!parsed.success) return Response.json({ message: "Invalid OpenUI artifact request." }, { status: 400 });
|
|
36133
|
+
const body = parsed.data;
|
|
36134
|
+
const validation = validateAndNormalizeOpenUIHtmlArtifact(body.artifact);
|
|
36135
|
+
if (!validation.ok) return Response.json({ message: validation.reason }, { status: validation.status ?? 400 });
|
|
36136
|
+
const bridge = getBridge();
|
|
36137
|
+
const session = bridge.getSession(body.sessionId) ?? await bridge.resumeSessionById(body.sessionId);
|
|
36138
|
+
if (!session || !await requireProjectSession(session)) return Response.json({ message: `Unknown session: ${body.sessionId}` }, { status: 404 });
|
|
36139
|
+
const messages = await bridge.getMessages(session.sessionId);
|
|
36140
|
+
const incomingId = body.assistantMessageId;
|
|
36141
|
+
const exact = messages.find((message) => message.role === "assistant" && message.id === incomingId);
|
|
36142
|
+
const existing = bridge.getPresentation(session.sessionId).artifactRuns.flatMap((run) => run.artifacts).filter((artifact2) => artifact2.kind === "openui-html").find((artifact2) => artifactIndexFor(artifact2) === body.artifactIndex && (record(artifact2.input)?.clientMessageId === incomingId || artifact2.sourceMessageId === incomingId));
|
|
36143
|
+
const fallback = existing ? void 0 : [...messages].reverse().find((message) => message.role === "assistant");
|
|
36144
|
+
const assistantMessageId = exact?.id ?? existing?.sourceMessageId ?? fallback?.id;
|
|
36145
|
+
if (!assistantMessageId) return Response.json({ message: "Unable to associate OpenUI artifact with an assistant message." }, { status: 409 });
|
|
36146
|
+
const artifact = {
|
|
36147
|
+
id: stablePresentationId(`${assistantMessageId}:openui-html:${body.artifactIndex}`),
|
|
36148
|
+
runId: stablePresentationId(`${assistantMessageId}:openui`),
|
|
36149
|
+
sourceMessageId: assistantMessageId,
|
|
36150
|
+
kind: "openui-html",
|
|
36151
|
+
title: validation.value.title,
|
|
36152
|
+
status: "success",
|
|
36153
|
+
input: {
|
|
36154
|
+
clientMessageId: incomingId,
|
|
36155
|
+
artifactIndex: body.artifactIndex
|
|
36156
|
+
},
|
|
36157
|
+
output: validation.value,
|
|
36158
|
+
timestamp: Date.now()
|
|
36159
|
+
};
|
|
36160
|
+
const presentation = await bridge.upsertPresentationArtifact(session.sessionId, artifact);
|
|
36161
|
+
return Response.json({
|
|
36162
|
+
artifact,
|
|
36163
|
+
presentation
|
|
36164
|
+
});
|
|
36165
|
+
}, request);
|
|
36166
|
+
}
|
|
36167
|
+
function handleChatPlanPresentationPut(request) {
|
|
36168
|
+
return wrapApiHandler(async () => {
|
|
36169
|
+
const body = ChatPlanPresentationUpsertRequestSchema.parse(await request.json().catch(() => ({})));
|
|
36170
|
+
const bridge = getBridge();
|
|
36171
|
+
const session = bridge.getSession(body.sessionId) ?? await bridge.resumeSessionById(body.sessionId);
|
|
36172
|
+
if (!session || !await requireProjectSession(session)) return Response.json({ message: `Unknown session: ${body.sessionId}` }, { status: 404 });
|
|
36173
|
+
const messages = await bridge.getMessages(body.sessionId);
|
|
36174
|
+
const incomingId = body.presentation.assistantMessageId;
|
|
36175
|
+
const known = messages.find((message) => message.id === incomingId && message.role === "assistant");
|
|
36176
|
+
const existing = (await loadManagedPlanPresentations(session)).find((item) => item.assistantMessageId === incomingId || item.clientMessageId === incomingId);
|
|
36177
|
+
const fallback = existing ? void 0 : [...messages].reverse().find((message) => message.role === "assistant");
|
|
36178
|
+
const assistantMessageId = known?.id ?? existing?.assistantMessageId ?? fallback?.id;
|
|
36179
|
+
if (!assistantMessageId) return Response.json({ message: "Unable to associate Plan presentation with an assistant message" }, { status: 409 });
|
|
36180
|
+
const clientMessageId = incomingId !== assistantMessageId ? existing?.clientMessageId ?? incomingId : existing?.clientMessageId;
|
|
36181
|
+
return Response.json({ presentation: await upsertManagedPlanPresentation(session, {
|
|
36182
|
+
...body.presentation,
|
|
36183
|
+
assistantMessageId,
|
|
36184
|
+
...clientMessageId ? { clientMessageId } : {}
|
|
36185
|
+
}) });
|
|
36186
|
+
}, request);
|
|
35317
36187
|
}
|
|
35318
36188
|
function handleChatQuestionPost(request) {
|
|
35319
36189
|
return wrapApiHandler(async () => {
|
|
@@ -35325,19 +36195,27 @@ function handleChatQuestionPost(request) {
|
|
|
35325
36195
|
ok: false,
|
|
35326
36196
|
message: "answer requires sessionId and toolCallId"
|
|
35327
36197
|
}, { status: 400 });
|
|
35328
|
-
|
|
36198
|
+
const bridge = getBridge();
|
|
36199
|
+
if (!await requireProjectSession(bridge.getSession(sessionId) ?? await bridge.resumeSessionById(sessionId))) return Response.json({
|
|
36200
|
+
ok: false,
|
|
36201
|
+
message: `Unknown session: ${sessionId}`
|
|
36202
|
+
}, { status: 404 });
|
|
36203
|
+
if (!bridge.answerDialog(sessionId, toolCallId, body.answer)) return Response.json({
|
|
35329
36204
|
ok: false,
|
|
35330
36205
|
message: "Question is no longer active"
|
|
35331
36206
|
}, { status: 404 });
|
|
35332
36207
|
return Response.json({ ok: true });
|
|
35333
|
-
});
|
|
36208
|
+
}, request);
|
|
35334
36209
|
}
|
|
35335
36210
|
function handleChatQueueMutationPost(request) {
|
|
35336
36211
|
return wrapApiHandler(async () => {
|
|
35337
36212
|
const body = ChatQueueMutationRequestSchema.parse(await request.json().catch(() => ({})));
|
|
35338
|
-
const
|
|
36213
|
+
const bridge = getBridge();
|
|
36214
|
+
if (!await requireProjectSession(bridge.getSession(body.sessionId) ?? await bridge.resumeSessionById(body.sessionId))) return Response.json({ message: `Unknown session: ${body.sessionId}` }, { status: 404 });
|
|
36215
|
+
const mutation = body.mutation ?? { type: "delete" };
|
|
36216
|
+
const result = await bridge.mutateQueuedMessage(body.sessionId, body.lane, body.index, body.expectedText, mutation);
|
|
35339
36217
|
return Response.json(ChatQueueMutationResponseSchema.parse(result));
|
|
35340
|
-
});
|
|
36218
|
+
}, request);
|
|
35341
36219
|
}
|
|
35342
36220
|
function packageSourceToString(source) {
|
|
35343
36221
|
if (typeof source === "string") return { name: source };
|
|
@@ -35394,7 +36272,7 @@ function handleChatResourcesGet(request) {
|
|
|
35394
36272
|
})),
|
|
35395
36273
|
diagnostics
|
|
35396
36274
|
});
|
|
35397
|
-
});
|
|
36275
|
+
}, request);
|
|
35398
36276
|
}
|
|
35399
36277
|
var BodySchema = ChatSessionMetadataSchema.extend({ sessionId: SessionIdSchema });
|
|
35400
36278
|
function handleChatResumePost(request) {
|
|
@@ -35416,7 +36294,7 @@ function handleChatResumePost(request) {
|
|
|
35416
36294
|
});
|
|
35417
36295
|
}
|
|
35418
36296
|
return Response.json({ message: "resume requires sessionId" }, { status: 400 });
|
|
35419
|
-
});
|
|
36297
|
+
}, request);
|
|
35420
36298
|
}
|
|
35421
36299
|
function handleChatSessionGet(request) {
|
|
35422
36300
|
return wrapApiHandler(async () => {
|
|
@@ -35428,7 +36306,10 @@ function handleChatSessionGet(request) {
|
|
|
35428
36306
|
const parsedParentSessionId = SessionIdSchema.safeParse(parentSessionId);
|
|
35429
36307
|
const parsedChildId = SessionIdSchema.safeParse(childId);
|
|
35430
36308
|
if (!parsedParentSessionId.success || !parsedChildId.success) return Response.json({ message: "Invalid subagent session identifiers" }, { status: 400 });
|
|
35431
|
-
const
|
|
36309
|
+
const bridge2 = getBridge();
|
|
36310
|
+
const liveParent = bridge2.getSession(parsedParentSessionId.data);
|
|
36311
|
+
if (liveParent && !await requireProjectSession(liveParent)) return Response.json({ message: `Unknown session: ${parsedParentSessionId.data}` }, { status: 404 });
|
|
36312
|
+
const child = await bridge2.loadRlmChildTranscript(parsedParentSessionId.data, parsedChildId.data);
|
|
35432
36313
|
if (!child) return Response.json({ message: "Unknown subagent transcript" }, { status: 404 });
|
|
35433
36314
|
return Response.json({
|
|
35434
36315
|
session: {
|
|
@@ -35447,7 +36328,7 @@ function handleChatSessionGet(request) {
|
|
|
35447
36328
|
const bridge = getBridge();
|
|
35448
36329
|
const projectId = requestedProjectId ? ProjectIdSchema.parse(requestedProjectId) : void 0;
|
|
35449
36330
|
const existing = projectId ? await bridge.resumeSessionById(sessionId, projectId, { openUI }) : bridge.getSession(sessionId) ?? await bridge.resumeSessionById(sessionId, void 0, { openUI });
|
|
35450
|
-
if (!existing) return Response.json({ message: `Unknown session: ${sessionId}` }, { status: 404 });
|
|
36331
|
+
if (!existing || !await requireProjectSession(existing)) return Response.json({ message: `Unknown session: ${sessionId}` }, { status: 404 });
|
|
35451
36332
|
return Response.json({
|
|
35452
36333
|
session: {
|
|
35453
36334
|
sessionId: existing.sessionId,
|
|
@@ -35457,7 +36338,7 @@ function handleChatSessionGet(request) {
|
|
|
35457
36338
|
planPresentations: await loadManagedPlanPresentations(existing),
|
|
35458
36339
|
presentation: bridge.getPresentation(existing.sessionId)
|
|
35459
36340
|
});
|
|
35460
|
-
});
|
|
36341
|
+
}, request);
|
|
35461
36342
|
}
|
|
35462
36343
|
var RenameSessionSchema = external_exports.object({
|
|
35463
36344
|
sessionId: SessionIdSchema,
|
|
@@ -35468,24 +36349,28 @@ function handleChatSessionRenamePatch(request) {
|
|
|
35468
36349
|
return wrapApiHandler(async () => {
|
|
35469
36350
|
const body = RenameSessionSchema.parse(await request.json().catch(() => ({})));
|
|
35470
36351
|
const bridge = getBridge();
|
|
35471
|
-
|
|
36352
|
+
const session = bridge.getSession(body.sessionId) ?? await bridge.resumeSessionById(body.sessionId);
|
|
36353
|
+
if (!session || !await requireProjectSession(session)) return Response.json({ message: `Unknown session: ${body.sessionId}` }, { status: 404 });
|
|
35472
36354
|
bridge.setSessionName(body.sessionId, body.title);
|
|
35473
36355
|
return Response.json({
|
|
35474
36356
|
ok: true,
|
|
35475
36357
|
sessionId: body.sessionId,
|
|
35476
36358
|
title: body.title
|
|
35477
36359
|
});
|
|
35478
|
-
});
|
|
36360
|
+
}, request);
|
|
35479
36361
|
}
|
|
35480
36362
|
function handleChatSessionDelete(request) {
|
|
35481
36363
|
return wrapApiHandler(async () => {
|
|
35482
36364
|
const body = DeleteSessionSchema.parse(await request.json().catch(() => ({})));
|
|
35483
|
-
|
|
36365
|
+
const bridge = getBridge();
|
|
36366
|
+
const session = bridge.getSession(body.sessionId) ?? await bridge.resumeSessionById(body.sessionId);
|
|
36367
|
+
if (!session || !await requireProjectSession(session)) return Response.json({ message: `Unknown session: ${body.sessionId}` }, { status: 404 });
|
|
36368
|
+
if (!await bridge.deleteSession(body.sessionId)) return Response.json({ message: `Unknown session: ${body.sessionId}` }, { status: 404 });
|
|
35484
36369
|
return Response.json({
|
|
35485
36370
|
ok: true,
|
|
35486
36371
|
sessionId: body.sessionId
|
|
35487
36372
|
});
|
|
35488
|
-
});
|
|
36373
|
+
}, request);
|
|
35489
36374
|
}
|
|
35490
36375
|
function stringValue(value) {
|
|
35491
36376
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
@@ -35509,14 +36394,53 @@ function normalizeSessionListRow(source) {
|
|
|
35509
36394
|
source,
|
|
35510
36395
|
sessionId,
|
|
35511
36396
|
cwd,
|
|
35512
|
-
title: stringValue(raw.sessionName) ?? stringValue(raw.name),
|
|
36397
|
+
title: meaningfulSessionLabel(stringValue(raw.sessionName) ?? stringValue(raw.name)),
|
|
35513
36398
|
createdAt,
|
|
35514
36399
|
updatedAt,
|
|
35515
36400
|
messageCount: messageCountValue(raw.messageCount),
|
|
35516
|
-
firstMessage: typeof raw.firstMessage === "string" ? raw.firstMessage : "",
|
|
36401
|
+
firstMessage: meaningfulSessionLabel(typeof raw.firstMessage === "string" ? raw.firstMessage : void 0) ?? "",
|
|
35517
36402
|
isSubagent
|
|
35518
36403
|
};
|
|
35519
36404
|
}
|
|
36405
|
+
function sessionSourcePath(source) {
|
|
36406
|
+
const raw = source;
|
|
36407
|
+
return stringValue(raw.sessionFile) ?? stringValue(raw.path);
|
|
36408
|
+
}
|
|
36409
|
+
function latestBy(entries, time) {
|
|
36410
|
+
if (entries.length === 0) return void 0;
|
|
36411
|
+
return entries.reduce((latest, entry) => time(entry) >= time(latest) ? entry : latest);
|
|
36412
|
+
}
|
|
36413
|
+
function presentationListActivity(presentation) {
|
|
36414
|
+
if (!presentation) return { activityCount: 0 };
|
|
36415
|
+
const artifacts = presentation.artifactRuns.flatMap((run) => run.artifacts);
|
|
36416
|
+
const latestRefinement = latestBy(presentation.refinements, (entry) => entry.timestamp);
|
|
36417
|
+
const latestArtifact = latestBy(artifacts, (entry) => entry.timestamp);
|
|
36418
|
+
const latestBash = latestBy(presentation.userBash, (entry) => entry.startedAt);
|
|
36419
|
+
return {
|
|
36420
|
+
title: meaningfulSessionLabel(presentation.sessionName) ?? meaningfulSessionLabel(latestRefinement?.summary) ?? meaningfulSessionLabel(latestArtifact?.title) ?? meaningfulSessionLabel(latestBash?.command),
|
|
36421
|
+
activityCount: presentation.refinements.length + artifacts.length + presentation.userBash.length
|
|
36422
|
+
};
|
|
36423
|
+
}
|
|
36424
|
+
function applyPresentationToSessionRow(row, presentation) {
|
|
36425
|
+
const { title: presentationTitle, activityCount } = presentationListActivity(presentation);
|
|
36426
|
+
const firstMessage = row.firstMessage || presentationTitle || "";
|
|
36427
|
+
return {
|
|
36428
|
+
title: row.title ?? meaningfulSessionLabel(firstMessage) ?? presentationTitle ?? fallbackSessionLabel(row.sessionId),
|
|
36429
|
+
firstMessage,
|
|
36430
|
+
messageCount: row.messageCount > 0 ? row.messageCount : activityCount > 0 ? 1 : 0
|
|
36431
|
+
};
|
|
36432
|
+
}
|
|
36433
|
+
function sessionNeedsPresentationJoin(row) {
|
|
36434
|
+
return row.messageCount === 0 || !row.title || !row.firstMessage;
|
|
36435
|
+
}
|
|
36436
|
+
async function loadSessionListPresentation(row, source, livePresentation) {
|
|
36437
|
+
const liveActivity = presentationListActivity(livePresentation);
|
|
36438
|
+
if (liveActivity.activityCount > 0 || liveActivity.title) return livePresentation;
|
|
36439
|
+
if (!sessionNeedsPresentationJoin(row)) return livePresentation;
|
|
36440
|
+
const path = sessionSourcePath(source);
|
|
36441
|
+
if (!path) return livePresentation;
|
|
36442
|
+
return await loadManagedPrimePresentation({ sessionPath: path }) ?? livePresentation;
|
|
36443
|
+
}
|
|
35520
36444
|
function sessionStatus(info, live) {
|
|
35521
36445
|
if (live?.isStreaming || live?.session?.isStreaming || info.isStreaming) return "running";
|
|
35522
36446
|
if (info.activity === "working" && (info.isSessionActive || info.hasRunningRlmChildren === true)) return "running";
|
|
@@ -35544,22 +36468,24 @@ function handleProjectsGet(_request) {
|
|
|
35544
36468
|
for (const projectId of assignments.values()) if (projectId) counts.set(projectId, (counts.get(projectId) ?? 0) + 1);
|
|
35545
36469
|
return Response.json({
|
|
35546
36470
|
projects: await getPrimeConfig().projectRegistry.list(counts),
|
|
35547
|
-
sessions: sessions2.map((source) => {
|
|
36471
|
+
sessions: await Promise.all(sessions2.map(async (source) => {
|
|
35548
36472
|
const session = normalizeSessionListRow(source);
|
|
36473
|
+
const liveSession = getBridge().getSession(session.sessionId);
|
|
36474
|
+
const fields = applyPresentationToSessionRow(session, await loadSessionListPresentation(session, source, liveSession?.mapperState?.presentation));
|
|
35549
36475
|
return {
|
|
35550
36476
|
sessionId: session.sessionId,
|
|
35551
36477
|
projectId: assignments.get(session.sessionId) ?? null,
|
|
35552
|
-
title: redactSessionLabelSecrets(
|
|
36478
|
+
title: redactSessionLabelSecrets(fields.title),
|
|
35553
36479
|
createdAt: session.createdAt,
|
|
35554
36480
|
updatedAt: session.updatedAt,
|
|
35555
|
-
status: sessionStatus(session.source,
|
|
35556
|
-
messageCount:
|
|
35557
|
-
firstMessage:
|
|
36481
|
+
status: sessionStatus(session.source, liveSession),
|
|
36482
|
+
messageCount: fields.messageCount,
|
|
36483
|
+
firstMessage: fields.firstMessage ? redactSessionLabelSecrets(fields.firstMessage) : "",
|
|
35558
36484
|
...session.isSubagent ? { isSubagent: true } : {}
|
|
35559
36485
|
};
|
|
35560
|
-
})
|
|
36486
|
+
}))
|
|
35561
36487
|
});
|
|
35562
|
-
});
|
|
36488
|
+
}, _request);
|
|
35563
36489
|
}
|
|
35564
36490
|
function handleProjectsPost(request) {
|
|
35565
36491
|
return wrapApiHandler(async () => {
|
|
@@ -35567,20 +36493,20 @@ function handleProjectsPost(request) {
|
|
|
35567
36493
|
const registry = getPrimeConfig().projectRegistry;
|
|
35568
36494
|
const path = await registry.resolveDirectoryInput(body);
|
|
35569
36495
|
return Response.json({ project: await registry.register(path, body.name) }, { status: 201 });
|
|
35570
|
-
});
|
|
36496
|
+
}, request);
|
|
35571
36497
|
}
|
|
35572
36498
|
function handleProjectPatch(request) {
|
|
35573
36499
|
return wrapApiHandler(async () => {
|
|
35574
36500
|
const projectId = ProjectIdSchema.parse(new URL(request.url).searchParams.get("projectId") ?? "");
|
|
35575
36501
|
const body = ProjectRenameRequestSchema.parse(await request.json().catch(() => ({})));
|
|
35576
36502
|
return Response.json({ project: await getPrimeConfig().projectRegistry.rename(projectId, body.name) });
|
|
35577
|
-
});
|
|
36503
|
+
}, request);
|
|
35578
36504
|
}
|
|
35579
36505
|
function handleProjectDelete(request) {
|
|
35580
36506
|
return wrapApiHandler(async () => {
|
|
35581
36507
|
const projectId = ProjectIdSchema.parse(new URL(request.url).searchParams.get("projectId") ?? "");
|
|
35582
36508
|
return Response.json({ project: await getPrimeConfig().projectRegistry.unregister(projectId) });
|
|
35583
|
-
});
|
|
36509
|
+
}, request);
|
|
35584
36510
|
}
|
|
35585
36511
|
function handleProjectSessionFork(request) {
|
|
35586
36512
|
return wrapApiHandler(async () => {
|
|
@@ -35590,7 +36516,7 @@ function handleProjectSessionFork(request) {
|
|
|
35590
36516
|
sessionId,
|
|
35591
36517
|
projectId: body.targetProjectId
|
|
35592
36518
|
}, { status: 201 });
|
|
35593
|
-
});
|
|
36519
|
+
}, request);
|
|
35594
36520
|
}
|
|
35595
36521
|
function handleProjectBrowseGet(request) {
|
|
35596
36522
|
return wrapApiHandler(async () => {
|
|
@@ -35600,7 +36526,7 @@ function handleProjectBrowseGet(request) {
|
|
|
35600
36526
|
token: url.searchParams.get("token") ?? void 0
|
|
35601
36527
|
});
|
|
35602
36528
|
return Response.json(result);
|
|
35603
|
-
});
|
|
36529
|
+
}, request);
|
|
35604
36530
|
}
|
|
35605
36531
|
function handleChatSessionsGet(_request) {
|
|
35606
36532
|
return wrapApiHandler(async () => {
|
|
@@ -35611,20 +36537,21 @@ function handleChatSessionsGet(_request) {
|
|
|
35611
36537
|
const formatted = await Promise.all(sessions2.map(async (s) => {
|
|
35612
36538
|
const session = normalizeSessionListRow(s);
|
|
35613
36539
|
const liveSession = bridge.getSession(session.sessionId);
|
|
36540
|
+
const fields = applyPresentationToSessionRow(session, await loadSessionListPresentation(session, s, liveSession?.mapperState?.presentation));
|
|
35614
36541
|
return {
|
|
35615
36542
|
sessionId: session.sessionId,
|
|
35616
36543
|
projectId: await getPrimeConfig().projectRegistry.projectIdForSession(session.sessionId, liveSession?.cwd ?? session.cwd),
|
|
35617
|
-
title:
|
|
36544
|
+
title: fields.title,
|
|
35618
36545
|
createdAt: session.createdAt,
|
|
35619
36546
|
updatedAt: session.updatedAt,
|
|
35620
36547
|
status: sessionStatus(session.source, liveSession),
|
|
35621
|
-
messageCount:
|
|
35622
|
-
firstMessage:
|
|
36548
|
+
messageCount: fields.messageCount,
|
|
36549
|
+
firstMessage: fields.firstMessage,
|
|
35623
36550
|
...session.isSubagent ? { isSubagent: true } : {}
|
|
35624
36551
|
};
|
|
35625
36552
|
}));
|
|
35626
36553
|
return Response.json({ sessions: projectId ? formatted.filter((session) => session.projectId === projectId) : formatted });
|
|
35627
|
-
});
|
|
36554
|
+
}, _request);
|
|
35628
36555
|
}
|
|
35629
36556
|
function toProjectShape(project) {
|
|
35630
36557
|
const out = {};
|
|
@@ -35694,7 +36621,7 @@ function handleChatSettingsGet(request) {
|
|
|
35694
36621
|
return wrapApiHandler(async () => {
|
|
35695
36622
|
const cwd = await cwdForRequest(request);
|
|
35696
36623
|
return Response.json(buildResponse(cwd));
|
|
35697
|
-
});
|
|
36624
|
+
}, request);
|
|
35698
36625
|
}
|
|
35699
36626
|
function handleChatSettingsPatch(request) {
|
|
35700
36627
|
return wrapApiHandler(async () => {
|
|
@@ -35719,7 +36646,7 @@ function handleChatSettingsPatch(request) {
|
|
|
35719
36646
|
if (patch.themes !== void 0) manager.setThemePaths(patch.themes);
|
|
35720
36647
|
if (patch.packages !== void 0) manager.setPackages(patch.packages);
|
|
35721
36648
|
return Response.json(buildResponse(cwd));
|
|
35722
|
-
});
|
|
36649
|
+
}, request);
|
|
35723
36650
|
}
|
|
35724
36651
|
function handleHealthGet(request) {
|
|
35725
36652
|
return wrapApiHandler(async () => {
|
|
@@ -35729,12 +36656,12 @@ function handleHealthGet(request) {
|
|
|
35729
36656
|
kernel,
|
|
35730
36657
|
uptimeMs: process.uptime() * 1e3
|
|
35731
36658
|
});
|
|
35732
|
-
});
|
|
36659
|
+
}, request);
|
|
35733
36660
|
}
|
|
35734
36661
|
function handleWorkspaceBrowseGet(request) {
|
|
35735
36662
|
return wrapApiHandler(async () => {
|
|
35736
36663
|
return Response.json({ message: "Workspace root switching is disabled; use /api/projects/browse for opaque directory tokens." }, { status: 410 });
|
|
35737
|
-
});
|
|
36664
|
+
}, request);
|
|
35738
36665
|
}
|
|
35739
36666
|
function canonicalizePath(path) {
|
|
35740
36667
|
try {
|
|
@@ -35855,7 +36782,7 @@ function handleWorkspaceFileGet(request) {
|
|
|
35855
36782
|
const result = await readWorkspaceFile(await cwdForRequest(request), path);
|
|
35856
36783
|
if (result.kind === "error") return Response.json({ message: result.message }, { status: result.status });
|
|
35857
36784
|
return Response.json(result.body);
|
|
35858
|
-
});
|
|
36785
|
+
}, request);
|
|
35859
36786
|
}
|
|
35860
36787
|
var IGNORED = /* @__PURE__ */ new Set([
|
|
35861
36788
|
".git",
|
|
@@ -35935,179 +36862,195 @@ function handleWorkspaceTreeGet(_request) {
|
|
|
35935
36862
|
nodes,
|
|
35936
36863
|
diagnostics
|
|
35937
36864
|
});
|
|
35938
|
-
});
|
|
36865
|
+
}, _request);
|
|
35939
36866
|
}
|
|
35940
|
-
var Route$
|
|
35941
|
-
var Route$
|
|
35942
|
-
var Route$
|
|
36867
|
+
var Route$27 = createFileRoute("/api/chat")({ server: { handlers: { POST: ({ request }) => handleChatPost(request) } } });
|
|
36868
|
+
var Route$26 = createFileRoute("/api/health")({ server: { handlers: { GET: ({ request }) => handleHealthGet(request) } } });
|
|
36869
|
+
var Route$25 = createFileRoute("/api/projects")({ server: { handlers: {
|
|
35943
36870
|
DELETE: ({ request }) => handleProjectDelete(request),
|
|
35944
36871
|
GET: ({ request }) => handleProjectsGet(request),
|
|
35945
36872
|
PATCH: ({ request }) => handleProjectPatch(request),
|
|
35946
36873
|
POST: ({ request }) => handleProjectsPost(request)
|
|
35947
36874
|
} } });
|
|
35948
|
-
var Route$
|
|
35949
|
-
var Route$
|
|
35950
|
-
var Route$
|
|
35951
|
-
var Route$
|
|
35952
|
-
var Route$
|
|
35953
|
-
var Route$
|
|
35954
|
-
|
|
35955
|
-
|
|
35956
|
-
|
|
36875
|
+
var Route$24 = createFileRoute("/api/chat/abort")({ server: { handlers: { POST: ({ request }) => handleChatAbortPost(request) } } });
|
|
36876
|
+
var Route$23 = createFileRoute("/api/chat/artifacts")({ server: { handlers: { PUT: ({ request }) => handleChatOpenUIArtifactPut(request) } } });
|
|
36877
|
+
var Route$22 = createFileRoute("/api/chat/command")({ server: { handlers: { POST: ({ request }) => handleChatCommandPost(request) } } });
|
|
36878
|
+
var Route$21 = createFileRoute("/api/chat/commands")({ server: { handlers: { GET: ({ request }) => handleChatCommandsGet(request) } } });
|
|
36879
|
+
var Route$20 = createFileRoute("/api/chat/events")({ server: { handlers: { GET: ({ request }) => handleChatEventsGet(request) } } });
|
|
36880
|
+
var Route$19 = createFileRoute("/api/chat/mcp")({ server: { handlers: {
|
|
36881
|
+
GET: ({ request }) => handleChatMcpGet(request),
|
|
36882
|
+
POST: ({ request }) => handleChatMcpPost(request),
|
|
36883
|
+
DELETE: ({ request }) => handleChatMcpDelete(request)
|
|
36884
|
+
} } });
|
|
36885
|
+
var Route$18 = createFileRoute("/api/chat/model")({ server: { handlers: { POST: ({ request }) => handleChatModelPost(request) } } });
|
|
36886
|
+
var Route$17 = createFileRoute("/api/chat/models")({ server: { handlers: { GET: ({ request }) => handleChatModelsGet(request) } } });
|
|
36887
|
+
var Route$16 = createFileRoute("/api/chat/new")({ server: { handlers: { POST: ({ request }) => handleChatNewPost(request) } } });
|
|
36888
|
+
var Route$15 = createFileRoute("/api/chat/providers")({ server: { handlers: {
|
|
35957
36889
|
GET: ({ request }) => handleChatProvidersGet(request),
|
|
35958
36890
|
POST: ({ request }) => handleChatProvidersPost(request),
|
|
35959
36891
|
DELETE: ({ request }) => handleChatProvidersDelete(request)
|
|
35960
36892
|
} } });
|
|
35961
|
-
var Route$
|
|
35962
|
-
var Route$
|
|
35963
|
-
var Route$
|
|
35964
|
-
var Route$
|
|
36893
|
+
var Route$14 = createFileRoute("/api/chat/question")({ server: { handlers: { POST: ({ request }) => handleChatQuestionPost(request) } } });
|
|
36894
|
+
var Route$13 = createFileRoute("/api/chat/resources")({ server: { handlers: { GET: ({ request }) => handleChatResourcesGet(request) } } });
|
|
36895
|
+
var Route$12 = createFileRoute("/api/chat/resume")({ server: { handlers: { POST: ({ request }) => handleChatResumePost(request) } } });
|
|
36896
|
+
var Route$11 = createFileRoute("/api/chat/session")({ server: { handlers: {
|
|
35965
36897
|
GET: ({ request }) => new URL(request.url).searchParams.has("attachmentId") ? handleChatAttachmentGet(request) : handleChatSessionGet(request),
|
|
35966
36898
|
POST: ({ request }) => handleChatAttachmentsPost(request),
|
|
35967
36899
|
PUT: ({ request }) => handleChatPlanPresentationPut(request),
|
|
35968
36900
|
PATCH: ({ request }) => handleChatQueueMutationPost(request)
|
|
35969
36901
|
} } });
|
|
35970
|
-
var Route$
|
|
36902
|
+
var Route$10 = createFileRoute("/api/chat/sessions")({ server: { handlers: {
|
|
35971
36903
|
DELETE: ({ request }) => handleChatSessionDelete(request),
|
|
35972
36904
|
GET: ({ request }) => handleChatSessionsGet(request),
|
|
35973
36905
|
PATCH: ({ request }) => handleChatSessionRenamePatch(request)
|
|
35974
36906
|
} } });
|
|
35975
|
-
var Route$
|
|
36907
|
+
var Route$9 = createFileRoute("/api/chat/settings")({ server: { handlers: {
|
|
35976
36908
|
GET: ({ request }) => handleChatSettingsGet(request),
|
|
35977
36909
|
PATCH: ({ request }) => handleChatSettingsPatch(request)
|
|
35978
36910
|
} } });
|
|
35979
|
-
var Route$
|
|
35980
|
-
var Route$
|
|
35981
|
-
var Route$
|
|
35982
|
-
var Route$
|
|
35983
|
-
var Route$
|
|
35984
|
-
var Route$
|
|
36911
|
+
var Route$8 = createFileRoute("/api/projects/browse")({ server: { handlers: { GET: ({ request }) => handleProjectBrowseGet(request) } } });
|
|
36912
|
+
var Route$7 = createFileRoute("/api/projects/fork")({ server: { handlers: { POST: ({ request }) => handleProjectSessionFork(request) } } });
|
|
36913
|
+
var Route$6 = createFileRoute("/api/workspace/browse")({ server: { handlers: { GET: ({ request }) => handleWorkspaceBrowseGet(request) } } });
|
|
36914
|
+
var Route$5 = createFileRoute("/api/workspace/file")({ server: { handlers: { GET: ({ request }) => handleWorkspaceFileGet(request) } } });
|
|
36915
|
+
var Route$4 = createFileRoute("/api/workspace/root")({ server: { handlers: { POST: () => Response.json({ message: "The workspace root is fixed when Fleet starts" }, { status: 405 }) } } });
|
|
36916
|
+
var Route$3 = createFileRoute("/api/workspace/tree")({ server: { handlers: { GET: ({ request }) => handleWorkspaceTreeGet(request) } } });
|
|
36917
|
+
var Route$2 = createFileRoute("/api/chat/mcp/oauth")({ server: { handlers: { POST: ({ request }) => handleChatMcpOAuthPost(request) } } });
|
|
35985
36918
|
var Route$1 = createFileRoute("/api/chat/models/discover")({ server: { handlers: { POST: ({ request }) => handleChatModelsDiscoverPost(request) } } });
|
|
35986
36919
|
var Route = createFileRoute("/api/chat/providers/oauth")({ server: { handlers: { POST: ({ request }) => handleChatProvidersOAuthPost(request) } } });
|
|
35987
|
-
var IndexRoute = Route$
|
|
36920
|
+
var IndexRoute = Route$28.update({
|
|
35988
36921
|
id: "/",
|
|
35989
36922
|
path: "/",
|
|
35990
|
-
getParentRoute: () => Route$
|
|
36923
|
+
getParentRoute: () => Route$29
|
|
35991
36924
|
});
|
|
35992
|
-
var ApiChatRoute = Route$
|
|
36925
|
+
var ApiChatRoute = Route$27.update({
|
|
35993
36926
|
id: "/api/chat",
|
|
35994
36927
|
path: "/api/chat",
|
|
35995
|
-
getParentRoute: () => Route$
|
|
36928
|
+
getParentRoute: () => Route$29
|
|
35996
36929
|
});
|
|
35997
|
-
var ApiHealthRoute = Route$
|
|
36930
|
+
var ApiHealthRoute = Route$26.update({
|
|
35998
36931
|
id: "/api/health",
|
|
35999
36932
|
path: "/api/health",
|
|
36000
|
-
getParentRoute: () => Route$
|
|
36933
|
+
getParentRoute: () => Route$29
|
|
36001
36934
|
});
|
|
36002
|
-
var ApiProjectsRoute = Route$
|
|
36935
|
+
var ApiProjectsRoute = Route$25.update({
|
|
36003
36936
|
id: "/api/projects",
|
|
36004
36937
|
path: "/api/projects",
|
|
36005
|
-
getParentRoute: () => Route$
|
|
36938
|
+
getParentRoute: () => Route$29
|
|
36006
36939
|
});
|
|
36007
|
-
var ApiChatAbortRoute = Route$
|
|
36940
|
+
var ApiChatAbortRoute = Route$24.update({
|
|
36008
36941
|
id: "/abort",
|
|
36009
36942
|
path: "/abort",
|
|
36010
36943
|
getParentRoute: () => ApiChatRoute
|
|
36011
36944
|
});
|
|
36012
|
-
var ApiChatArtifactsRoute = Route$
|
|
36945
|
+
var ApiChatArtifactsRoute = Route$23.update({
|
|
36013
36946
|
id: "/artifacts",
|
|
36014
36947
|
path: "/artifacts",
|
|
36015
36948
|
getParentRoute: () => ApiChatRoute
|
|
36016
36949
|
});
|
|
36017
|
-
var ApiChatCommandRoute = Route$
|
|
36950
|
+
var ApiChatCommandRoute = Route$22.update({
|
|
36018
36951
|
id: "/command",
|
|
36019
36952
|
path: "/command",
|
|
36020
36953
|
getParentRoute: () => ApiChatRoute
|
|
36021
36954
|
});
|
|
36022
|
-
var ApiChatCommandsRoute = Route$
|
|
36955
|
+
var ApiChatCommandsRoute = Route$21.update({
|
|
36023
36956
|
id: "/commands",
|
|
36024
36957
|
path: "/commands",
|
|
36025
36958
|
getParentRoute: () => ApiChatRoute
|
|
36026
36959
|
});
|
|
36027
|
-
var ApiChatEventsRoute = Route$
|
|
36960
|
+
var ApiChatEventsRoute = Route$20.update({
|
|
36028
36961
|
id: "/events",
|
|
36029
36962
|
path: "/events",
|
|
36030
36963
|
getParentRoute: () => ApiChatRoute
|
|
36031
36964
|
});
|
|
36032
|
-
var
|
|
36965
|
+
var ApiChatMcpRoute = Route$19.update({
|
|
36966
|
+
id: "/mcp",
|
|
36967
|
+
path: "/mcp",
|
|
36968
|
+
getParentRoute: () => ApiChatRoute
|
|
36969
|
+
});
|
|
36970
|
+
var ApiChatModelRoute = Route$18.update({
|
|
36033
36971
|
id: "/model",
|
|
36034
36972
|
path: "/model",
|
|
36035
36973
|
getParentRoute: () => ApiChatRoute
|
|
36036
36974
|
});
|
|
36037
|
-
var ApiChatModelsRoute = Route$
|
|
36975
|
+
var ApiChatModelsRoute = Route$17.update({
|
|
36038
36976
|
id: "/models",
|
|
36039
36977
|
path: "/models",
|
|
36040
36978
|
getParentRoute: () => ApiChatRoute
|
|
36041
36979
|
});
|
|
36042
|
-
var ApiChatNewRoute = Route$
|
|
36980
|
+
var ApiChatNewRoute = Route$16.update({
|
|
36043
36981
|
id: "/new",
|
|
36044
36982
|
path: "/new",
|
|
36045
36983
|
getParentRoute: () => ApiChatRoute
|
|
36046
36984
|
});
|
|
36047
|
-
var ApiChatProvidersRoute = Route$
|
|
36985
|
+
var ApiChatProvidersRoute = Route$15.update({
|
|
36048
36986
|
id: "/providers",
|
|
36049
36987
|
path: "/providers",
|
|
36050
36988
|
getParentRoute: () => ApiChatRoute
|
|
36051
36989
|
});
|
|
36052
|
-
var ApiChatQuestionRoute = Route$
|
|
36990
|
+
var ApiChatQuestionRoute = Route$14.update({
|
|
36053
36991
|
id: "/question",
|
|
36054
36992
|
path: "/question",
|
|
36055
36993
|
getParentRoute: () => ApiChatRoute
|
|
36056
36994
|
});
|
|
36057
|
-
var ApiChatResourcesRoute = Route$
|
|
36995
|
+
var ApiChatResourcesRoute = Route$13.update({
|
|
36058
36996
|
id: "/resources",
|
|
36059
36997
|
path: "/resources",
|
|
36060
36998
|
getParentRoute: () => ApiChatRoute
|
|
36061
36999
|
});
|
|
36062
|
-
var ApiChatResumeRoute = Route$
|
|
37000
|
+
var ApiChatResumeRoute = Route$12.update({
|
|
36063
37001
|
id: "/resume",
|
|
36064
37002
|
path: "/resume",
|
|
36065
37003
|
getParentRoute: () => ApiChatRoute
|
|
36066
37004
|
});
|
|
36067
|
-
var ApiChatSessionRoute = Route$
|
|
37005
|
+
var ApiChatSessionRoute = Route$11.update({
|
|
36068
37006
|
id: "/session",
|
|
36069
37007
|
path: "/session",
|
|
36070
37008
|
getParentRoute: () => ApiChatRoute
|
|
36071
37009
|
});
|
|
36072
|
-
var ApiChatSessionsRoute = Route$
|
|
37010
|
+
var ApiChatSessionsRoute = Route$10.update({
|
|
36073
37011
|
id: "/sessions",
|
|
36074
37012
|
path: "/sessions",
|
|
36075
37013
|
getParentRoute: () => ApiChatRoute
|
|
36076
37014
|
});
|
|
36077
|
-
var ApiChatSettingsRoute = Route$
|
|
37015
|
+
var ApiChatSettingsRoute = Route$9.update({
|
|
36078
37016
|
id: "/settings",
|
|
36079
37017
|
path: "/settings",
|
|
36080
37018
|
getParentRoute: () => ApiChatRoute
|
|
36081
37019
|
});
|
|
36082
|
-
var ApiProjectsBrowseRoute = Route$
|
|
37020
|
+
var ApiProjectsBrowseRoute = Route$8.update({
|
|
36083
37021
|
id: "/browse",
|
|
36084
37022
|
path: "/browse",
|
|
36085
37023
|
getParentRoute: () => ApiProjectsRoute
|
|
36086
37024
|
});
|
|
36087
|
-
var ApiProjectsForkRoute = Route$
|
|
37025
|
+
var ApiProjectsForkRoute = Route$7.update({
|
|
36088
37026
|
id: "/fork",
|
|
36089
37027
|
path: "/fork",
|
|
36090
37028
|
getParentRoute: () => ApiProjectsRoute
|
|
36091
37029
|
});
|
|
36092
|
-
var ApiWorkspaceBrowseRoute = Route$
|
|
37030
|
+
var ApiWorkspaceBrowseRoute = Route$6.update({
|
|
36093
37031
|
id: "/api/workspace/browse",
|
|
36094
37032
|
path: "/api/workspace/browse",
|
|
36095
|
-
getParentRoute: () => Route$
|
|
37033
|
+
getParentRoute: () => Route$29
|
|
36096
37034
|
});
|
|
36097
|
-
var ApiWorkspaceFileRoute = Route$
|
|
37035
|
+
var ApiWorkspaceFileRoute = Route$5.update({
|
|
36098
37036
|
id: "/api/workspace/file",
|
|
36099
37037
|
path: "/api/workspace/file",
|
|
36100
|
-
getParentRoute: () => Route$
|
|
37038
|
+
getParentRoute: () => Route$29
|
|
36101
37039
|
});
|
|
36102
|
-
var ApiWorkspaceRootRoute = Route$
|
|
37040
|
+
var ApiWorkspaceRootRoute = Route$4.update({
|
|
36103
37041
|
id: "/api/workspace/root",
|
|
36104
37042
|
path: "/api/workspace/root",
|
|
36105
|
-
getParentRoute: () => Route$
|
|
37043
|
+
getParentRoute: () => Route$29
|
|
36106
37044
|
});
|
|
36107
|
-
var ApiWorkspaceTreeRoute = Route$
|
|
37045
|
+
var ApiWorkspaceTreeRoute = Route$3.update({
|
|
36108
37046
|
id: "/api/workspace/tree",
|
|
36109
37047
|
path: "/api/workspace/tree",
|
|
36110
|
-
getParentRoute: () => Route$
|
|
37048
|
+
getParentRoute: () => Route$29
|
|
37049
|
+
});
|
|
37050
|
+
var ApiChatMcpOauthRoute = Route$2.update({
|
|
37051
|
+
id: "/oauth",
|
|
37052
|
+
path: "/oauth",
|
|
37053
|
+
getParentRoute: () => ApiChatMcpRoute
|
|
36111
37054
|
});
|
|
36112
37055
|
var ApiChatModelsDiscoverRoute = Route$1.update({
|
|
36113
37056
|
id: "/discover",
|
|
@@ -36119,6 +37062,8 @@ var ApiChatProvidersOauthRoute = Route.update({
|
|
|
36119
37062
|
path: "/oauth",
|
|
36120
37063
|
getParentRoute: () => ApiChatProvidersRoute
|
|
36121
37064
|
});
|
|
37065
|
+
var ApiChatMcpRouteChildren = { ApiChatMcpOauthRoute };
|
|
37066
|
+
var ApiChatMcpRouteWithChildren = ApiChatMcpRoute._addFileChildren(ApiChatMcpRouteChildren);
|
|
36122
37067
|
var ApiChatModelsRouteChildren = { ApiChatModelsDiscoverRoute };
|
|
36123
37068
|
var ApiChatModelsRouteWithChildren = ApiChatModelsRoute._addFileChildren(ApiChatModelsRouteChildren);
|
|
36124
37069
|
var ApiChatProvidersRouteChildren = { ApiChatProvidersOauthRoute };
|
|
@@ -36128,6 +37073,7 @@ var ApiChatRouteChildren = {
|
|
|
36128
37073
|
ApiChatCommandRoute,
|
|
36129
37074
|
ApiChatCommandsRoute,
|
|
36130
37075
|
ApiChatEventsRoute,
|
|
37076
|
+
ApiChatMcpRoute: ApiChatMcpRouteWithChildren,
|
|
36131
37077
|
ApiChatModelRoute,
|
|
36132
37078
|
ApiChatModelsRoute: ApiChatModelsRouteWithChildren,
|
|
36133
37079
|
ApiChatNewRoute,
|
|
@@ -36154,7 +37100,7 @@ var rootRouteChildren = {
|
|
|
36154
37100
|
ApiWorkspaceRootRoute,
|
|
36155
37101
|
ApiWorkspaceTreeRoute
|
|
36156
37102
|
};
|
|
36157
|
-
var routeTree = Route$
|
|
37103
|
+
var routeTree = Route$29._addFileChildren(rootRouteChildren)._addFileTypes();
|
|
36158
37104
|
function getRouter() {
|
|
36159
37105
|
return createRouter({
|
|
36160
37106
|
routeTree,
|