pi-forge 0.0.0 → 1.1.4

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.
Files changed (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -4
  3. package/bin/pi-forge.mjs +37 -0
  4. package/dist/client/assets/CodeMirrorEditor-BqaaP1EE.js +34 -0
  5. package/dist/client/assets/CodeMirrorEditor-BqaaP1EE.js.map +1 -0
  6. package/dist/client/assets/index-B-529kgJ.css +32 -0
  7. package/dist/client/assets/index-BzKzxXFs.js +392 -0
  8. package/dist/client/assets/index-BzKzxXFs.js.map +1 -0
  9. package/dist/client/assets/workbox-window.prod.es5-BBnX5xw4.js +3 -0
  10. package/dist/client/assets/workbox-window.prod.es5-BBnX5xw4.js.map +1 -0
  11. package/dist/client/icons/icon-192.png +0 -0
  12. package/dist/client/icons/icon-512.png +0 -0
  13. package/dist/client/icons/icon-maskable-512.png +0 -0
  14. package/dist/client/icons/icon.svg +9 -0
  15. package/dist/client/index.html +24 -0
  16. package/dist/client/manifest.webmanifest +1 -0
  17. package/dist/client/offline.html +142 -0
  18. package/dist/client/sw.js +3 -0
  19. package/dist/client/sw.js.map +1 -0
  20. package/dist/client/workbox-6d7155ed.js +3 -0
  21. package/dist/client/workbox-6d7155ed.js.map +1 -0
  22. package/dist/server/agent-resource-loader.js +126 -0
  23. package/dist/server/agent-resource-loader.js.map +1 -0
  24. package/dist/server/attachment-converters.js +96 -0
  25. package/dist/server/attachment-converters.js.map +1 -0
  26. package/dist/server/auth.js +209 -0
  27. package/dist/server/auth.js.map +1 -0
  28. package/dist/server/compaction-history.js +106 -0
  29. package/dist/server/compaction-history.js.map +1 -0
  30. package/dist/server/concurrency.js +49 -0
  31. package/dist/server/concurrency.js.map +1 -0
  32. package/dist/server/config-export.js +220 -0
  33. package/dist/server/config-export.js.map +1 -0
  34. package/dist/server/config-manager.js +528 -0
  35. package/dist/server/config-manager.js.map +1 -0
  36. package/dist/server/config.js +326 -0
  37. package/dist/server/config.js.map +1 -0
  38. package/dist/server/conversion-worker.mjs +90 -0
  39. package/dist/server/diagnostics.js +137 -0
  40. package/dist/server/diagnostics.js.map +1 -0
  41. package/dist/server/extensions-discovery.js +147 -0
  42. package/dist/server/extensions-discovery.js.map +1 -0
  43. package/dist/server/file-manager.js +734 -0
  44. package/dist/server/file-manager.js.map +1 -0
  45. package/dist/server/file-references.js +215 -0
  46. package/dist/server/file-references.js.map +1 -0
  47. package/dist/server/file-searcher.js +385 -0
  48. package/dist/server/file-searcher.js.map +1 -0
  49. package/dist/server/git-runner.js +684 -0
  50. package/dist/server/git-runner.js.map +1 -0
  51. package/dist/server/index.js +468 -0
  52. package/dist/server/index.js.map +1 -0
  53. package/dist/server/mcp/config.js +133 -0
  54. package/dist/server/mcp/config.js.map +1 -0
  55. package/dist/server/mcp/manager.js +351 -0
  56. package/dist/server/mcp/manager.js.map +1 -0
  57. package/dist/server/mcp/tool-bridge.js +173 -0
  58. package/dist/server/mcp/tool-bridge.js.map +1 -0
  59. package/dist/server/project-manager.js +301 -0
  60. package/dist/server/project-manager.js.map +1 -0
  61. package/dist/server/pty-manager.js +354 -0
  62. package/dist/server/pty-manager.js.map +1 -0
  63. package/dist/server/routes/_schemas.js +73 -0
  64. package/dist/server/routes/_schemas.js.map +1 -0
  65. package/dist/server/routes/auth.js +164 -0
  66. package/dist/server/routes/auth.js.map +1 -0
  67. package/dist/server/routes/config.js +1163 -0
  68. package/dist/server/routes/config.js.map +1 -0
  69. package/dist/server/routes/control.js +464 -0
  70. package/dist/server/routes/control.js.map +1 -0
  71. package/dist/server/routes/exec.js +217 -0
  72. package/dist/server/routes/exec.js.map +1 -0
  73. package/dist/server/routes/files.js +847 -0
  74. package/dist/server/routes/files.js.map +1 -0
  75. package/dist/server/routes/git.js +837 -0
  76. package/dist/server/routes/git.js.map +1 -0
  77. package/dist/server/routes/health.js +97 -0
  78. package/dist/server/routes/health.js.map +1 -0
  79. package/dist/server/routes/mcp.js +300 -0
  80. package/dist/server/routes/mcp.js.map +1 -0
  81. package/dist/server/routes/projects.js +259 -0
  82. package/dist/server/routes/projects.js.map +1 -0
  83. package/dist/server/routes/prompt.js +496 -0
  84. package/dist/server/routes/prompt.js.map +1 -0
  85. package/dist/server/routes/sessions.js +783 -0
  86. package/dist/server/routes/sessions.js.map +1 -0
  87. package/dist/server/routes/stream.js +69 -0
  88. package/dist/server/routes/stream.js.map +1 -0
  89. package/dist/server/routes/terminal.js +335 -0
  90. package/dist/server/routes/terminal.js.map +1 -0
  91. package/dist/server/session-registry.js +1197 -0
  92. package/dist/server/session-registry.js.map +1 -0
  93. package/dist/server/skill-overrides.js +151 -0
  94. package/dist/server/skill-overrides.js.map +1 -0
  95. package/dist/server/skills-export.js +257 -0
  96. package/dist/server/skills-export.js.map +1 -0
  97. package/dist/server/sse-bridge.js +220 -0
  98. package/dist/server/sse-bridge.js.map +1 -0
  99. package/dist/server/tool-overrides.js +277 -0
  100. package/dist/server/tool-overrides.js.map +1 -0
  101. package/dist/server/turn-diff-builder.js +280 -0
  102. package/dist/server/turn-diff-builder.js.map +1 -0
  103. package/package.json +53 -12
@@ -0,0 +1,133 @@
1
+ import { chmodSync } from "node:fs";
2
+ import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
3
+ import { dirname } from "node:path";
4
+ import { randomUUID } from "node:crypto";
5
+ import { config } from "../config.js";
6
+ const SECRET_PLACEHOLDER = "***REDACTED***";
7
+ async function ensureDir() {
8
+ await mkdir(dirname(config.mcpConfigFile), { recursive: true });
9
+ }
10
+ async function atomicWriteJson(data) {
11
+ await ensureDir();
12
+ const path = config.mcpConfigFile;
13
+ const tmp = `${path}.${randomUUID()}.tmp`;
14
+ await writeFile(tmp, JSON.stringify(data, null, 2), { mode: 0o600 });
15
+ // Some kernels honour the umask on the initial create; reapply 0600
16
+ // explicitly so the persisted file always matches what we promised
17
+ // in the docstring.
18
+ try {
19
+ chmodSync(tmp, 0o600);
20
+ }
21
+ catch {
22
+ // Best-effort — if chmod fails (e.g. read-only fs in tests), the
23
+ // umask-applied perms are still likely fine.
24
+ }
25
+ try {
26
+ await rename(tmp, path);
27
+ }
28
+ catch (err) {
29
+ await unlink(tmp).catch(() => undefined);
30
+ throw err;
31
+ }
32
+ }
33
+ export async function readMcpJson() {
34
+ try {
35
+ const raw = await readFile(config.mcpConfigFile, "utf8");
36
+ if (raw.trim().length === 0)
37
+ return { servers: {} };
38
+ const parsed = JSON.parse(raw);
39
+ if (typeof parsed !== "object" || parsed === null || !("servers" in parsed)) {
40
+ return { servers: {} };
41
+ }
42
+ const servers = parsed.servers;
43
+ const disabled = parsed.disabled === true;
44
+ if (typeof servers !== "object" || servers === null) {
45
+ return { disabled, servers: {} };
46
+ }
47
+ return { disabled, servers: servers };
48
+ }
49
+ catch (err) {
50
+ if (err.code === "ENOENT")
51
+ return { servers: {} };
52
+ throw err;
53
+ }
54
+ }
55
+ /**
56
+ * Same as readMcpJson but with every header VALUE replaced with the
57
+ * redaction sentinel. Used by the read-path API route so an inline
58
+ * bearer token is never echoed back to the browser.
59
+ */
60
+ export async function readMcpJsonRedacted() {
61
+ const raw = await readMcpJson();
62
+ const out = {};
63
+ for (const [name, server] of Object.entries(raw.servers)) {
64
+ const cleaned = { url: server.url };
65
+ if (server.transport !== undefined)
66
+ cleaned.transport = server.transport;
67
+ if (server.enabled !== undefined)
68
+ cleaned.enabled = server.enabled;
69
+ if (server.headers !== undefined) {
70
+ cleaned.headers = {};
71
+ for (const k of Object.keys(server.headers)) {
72
+ cleaned.headers[k] = SECRET_PLACEHOLDER;
73
+ }
74
+ }
75
+ out[name] = cleaned;
76
+ }
77
+ return { disabled: raw.disabled === true, servers: out };
78
+ }
79
+ /**
80
+ * Write `mcp.json`, merging the secret-placeholder for header values
81
+ * back to the prior persisted value. Mirrors the round-trip safety
82
+ * config-manager.writeModelsJson uses for `apiKey` — without this, an
83
+ * "edit and save" round-trip from the UI would write the literal
84
+ * sentinel back to disk and lock the user out of their MCP server.
85
+ */
86
+ export async function writeMcpJson(next) {
87
+ const existing = await readMcpJson().catch(() => ({ servers: {} }));
88
+ const safe = { servers: {} };
89
+ if (next.disabled === true)
90
+ safe.disabled = true;
91
+ for (const [name, server] of Object.entries(next.servers ?? {})) {
92
+ const merged = { url: server.url };
93
+ if (server.transport !== undefined)
94
+ merged.transport = server.transport;
95
+ if (server.enabled !== undefined)
96
+ merged.enabled = server.enabled;
97
+ if (server.headers !== undefined) {
98
+ merged.headers = {};
99
+ const prior = existing.servers[name]?.headers ?? {};
100
+ for (const [hk, hv] of Object.entries(server.headers)) {
101
+ // Sentinel ↦ keep prior value (or drop the key if no prior).
102
+ if (hv === SECRET_PLACEHOLDER) {
103
+ if (prior[hk] !== undefined)
104
+ merged.headers[hk] = prior[hk];
105
+ }
106
+ else {
107
+ merged.headers[hk] = hv;
108
+ }
109
+ }
110
+ }
111
+ safe.servers[name] = merged;
112
+ }
113
+ await atomicWriteJson(safe);
114
+ }
115
+ export async function upsertMcpServer(name, server) {
116
+ const cur = await readMcpJson();
117
+ cur.servers[name] = server;
118
+ await writeMcpJson(cur);
119
+ }
120
+ export async function setMcpDisabled(disabled) {
121
+ const cur = await readMcpJson();
122
+ cur.disabled = disabled;
123
+ await writeMcpJson(cur);
124
+ }
125
+ export async function deleteMcpServer(name) {
126
+ const cur = await readMcpJson();
127
+ if (cur.servers[name] === undefined)
128
+ return false;
129
+ delete cur.servers[name];
130
+ await writeMcpJson(cur);
131
+ return true;
132
+ }
133
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/mcp/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,351 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
4
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
5
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
6
+ import { readMcpJson } from "./config.js";
7
+ import { bridgeMcpTool } from "./tool-bridge.js";
8
+ const PROJECT_MCP_FILE = ".mcp.json";
9
+ function entryKey(scope, name) {
10
+ return scope === "global" ? `global::${name}` : `project:${scope.project}::${name}`;
11
+ }
12
+ const pool = new Map();
13
+ /** Tracks projects we've loaded once already so repeat session
14
+ * creates in the same project don't redundantly re-read the file. */
15
+ const loadedProjects = new Set();
16
+ /**
17
+ * Mirrored from `mcp.json#disabled` on every load so the hot path
18
+ * (`customToolsForProject`, called every `createAgentSession`) doesn't
19
+ * have to do file I/O.
20
+ */
21
+ let globallyEnabled = true;
22
+ export function isGloballyEnabled() {
23
+ return globallyEnabled;
24
+ }
25
+ /* ----------------------------- public API ----------------------------- */
26
+ export async function loadGlobal() {
27
+ const cfg = await readMcpJson();
28
+ globallyEnabled = cfg.disabled !== true;
29
+ await syncScope("global", cfg.servers);
30
+ }
31
+ export async function loadProject(projectId, projectPath) {
32
+ const cfg = await readProjectMcpJson(projectPath);
33
+ await syncScope({ project: projectId }, cfg);
34
+ loadedProjects.add(projectId);
35
+ }
36
+ export async function ensureProjectLoaded(projectId, projectPath) {
37
+ if (loadedProjects.has(projectId))
38
+ return;
39
+ await loadProject(projectId, projectPath);
40
+ }
41
+ /**
42
+ * Re-read the global config file and sync the pool. Called on every
43
+ * write through `routes/mcp.ts` so the UI's "save" reflects in
44
+ * connection state immediately.
45
+ */
46
+ export async function reloadGlobal() {
47
+ loadedProjects.clear(); // project files may reference globals too
48
+ await loadGlobal();
49
+ }
50
+ /**
51
+ * Build the `customTools` list for a session in `projectId`. Returns
52
+ * the union of every connected, enabled server's bridged tools across
53
+ * the global scope and the project scope. On name collision the
54
+ * project entry wins (the session sees the project's bridged tool,
55
+ * not the global one).
56
+ */
57
+ export function customToolsForProject(projectId) {
58
+ // Server-name override: when the project has a server with the
59
+ // same NAME as a global server, the project entry replaces the
60
+ // global one entirely (not just on tool-name collision). Reason:
61
+ // operators expect a project's `.mcp.json` to fully shadow a same-
62
+ // named global entry — different auth tokens, different `enabled`
63
+ // flags, and (if URLs match) one TCP connection rather than two.
64
+ const projectServerNames = new Set();
65
+ for (const e of pool.values()) {
66
+ if (e.scope === "global")
67
+ continue;
68
+ if (e.scope.project !== projectId)
69
+ continue;
70
+ projectServerNames.add(e.name);
71
+ }
72
+ const seenToolNames = new Set();
73
+ const out = [];
74
+ // Project entries first so their tools land in `seen` and any
75
+ // remaining tool-name collisions across other servers go to the
76
+ // project's version.
77
+ for (const e of pool.values()) {
78
+ if (e.scope === "global")
79
+ continue;
80
+ if (e.scope.project !== projectId)
81
+ continue;
82
+ if (e.state !== "connected")
83
+ continue;
84
+ for (const t of e.bridged) {
85
+ if (seenToolNames.has(t.name))
86
+ continue;
87
+ seenToolNames.add(t.name);
88
+ out.push(t);
89
+ }
90
+ }
91
+ for (const e of pool.values()) {
92
+ if (e.scope !== "global")
93
+ continue;
94
+ // Server-name shadowed by a project entry — skip the global
95
+ // entry entirely.
96
+ if (projectServerNames.has(e.name))
97
+ continue;
98
+ if (e.state !== "connected")
99
+ continue;
100
+ for (const t of e.bridged) {
101
+ if (seenToolNames.has(t.name))
102
+ continue;
103
+ seenToolNames.add(t.name);
104
+ out.push(t);
105
+ }
106
+ }
107
+ return out;
108
+ }
109
+ export function getStatus(opts) {
110
+ const out = [];
111
+ for (const e of pool.values()) {
112
+ if (e.scope !== "global") {
113
+ if (opts?.projectId !== undefined && e.scope.project !== opts.projectId)
114
+ continue;
115
+ if (opts?.projectId === undefined)
116
+ continue; // omit project entries from global view
117
+ }
118
+ // Pair each raw `entry.tools[i]` with the bridged tool sitting
119
+ // at the same index — `connectEntry` builds them in lockstep, so
120
+ // index alignment is the load-bearing invariant. Surfacing both
121
+ // names lets the UI key toggles by the bridged name (which pi
122
+ // sees) while still showing the operator the human-friendlier
123
+ // unprefixed form.
124
+ const tools = e.tools.map((t, i) => ({
125
+ name: e.bridged[i]?.name ?? `${e.name}__${t.name}`,
126
+ shortName: t.name,
127
+ description: t.description,
128
+ }));
129
+ const status = {
130
+ scope: e.scope === "global" ? "global" : "project",
131
+ name: e.name,
132
+ url: e.config.url,
133
+ enabled: e.config.enabled !== false,
134
+ state: e.state,
135
+ toolCount: e.tools.length,
136
+ tools,
137
+ };
138
+ if (e.scope !== "global")
139
+ status.projectId = e.scope.project;
140
+ if (e.lastError !== undefined)
141
+ status.lastError = e.lastError;
142
+ if (e.config.transport !== undefined)
143
+ status.transport = e.config.transport;
144
+ out.push(status);
145
+ }
146
+ return out;
147
+ }
148
+ /**
149
+ * Force a connection attempt (or reconnection) for the named server.
150
+ * Returns the resulting status entry. Useful for the "Probe" button
151
+ * in Settings.
152
+ */
153
+ export async function probe(scope, name) {
154
+ const entry = pool.get(entryKey(scope, name));
155
+ if (entry === undefined)
156
+ return undefined;
157
+ await disconnectEntry(entry);
158
+ await connectEntry(entry);
159
+ const opts = scope === "global" ? undefined : { projectId: scope.project };
160
+ return getStatus(opts).find((s) => s.name === name && s.scope === (scope === "global" ? "global" : "project"));
161
+ }
162
+ export async function disposeAll() {
163
+ await Promise.allSettled(Array.from(pool.values()).map((entry) => disconnectEntry(entry)));
164
+ pool.clear();
165
+ loadedProjects.clear();
166
+ }
167
+ /* ----------------------------- internals ----------------------------- */
168
+ async function syncScope(scope, configs) {
169
+ // Disconnect + drop entries that no longer exist in the config (or
170
+ // moved scope). Mutating during iteration is fine because we take a
171
+ // snapshot of keys first.
172
+ const wantNames = new Set(Object.keys(configs));
173
+ for (const [key, entry] of Array.from(pool.entries())) {
174
+ if (entryScopeMatches(entry.scope, scope) && !wantNames.has(entry.name)) {
175
+ await disconnectEntry(entry);
176
+ pool.delete(key);
177
+ }
178
+ }
179
+ // Add / update each declared server.
180
+ for (const [name, cfg] of Object.entries(configs)) {
181
+ const key = entryKey(scope, name);
182
+ const existing = pool.get(key);
183
+ if (existing !== undefined) {
184
+ const sameUrl = existing.config.url === cfg.url;
185
+ const sameTransport = existing.config.transport === cfg.transport;
186
+ const sameEnabled = (existing.config.enabled !== false) === (cfg.enabled !== false);
187
+ const sameHeaders = JSON.stringify(existing.config.headers ?? {}) === JSON.stringify(cfg.headers ?? {});
188
+ existing.config = cfg;
189
+ if (sameUrl && sameTransport && sameEnabled && sameHeaders) {
190
+ // Nothing meaningful changed; skip the disconnect/reconnect dance.
191
+ continue;
192
+ }
193
+ await disconnectEntry(existing);
194
+ if (cfg.enabled === false) {
195
+ existing.state = "disabled";
196
+ continue;
197
+ }
198
+ void connectEntry(existing);
199
+ continue;
200
+ }
201
+ const entry = {
202
+ scope,
203
+ name,
204
+ config: cfg,
205
+ state: cfg.enabled === false ? "disabled" : "idle",
206
+ tools: [],
207
+ bridged: [],
208
+ };
209
+ pool.set(key, entry);
210
+ if (cfg.enabled !== false) {
211
+ void connectEntry(entry);
212
+ }
213
+ }
214
+ }
215
+ function entryScopeMatches(a, b) {
216
+ if (a === "global" && b === "global")
217
+ return true;
218
+ if (a !== "global" && b !== "global")
219
+ return a.project === b.project;
220
+ return false;
221
+ }
222
+ async function connectEntry(entry) {
223
+ entry.state = "connecting";
224
+ delete entry.lastError;
225
+ try {
226
+ const { client, transport, resolvedTransport } = await openConnection(entry.config);
227
+ entry.client = client;
228
+ entry.transport = transport;
229
+ entry.config.transport = resolvedTransport;
230
+ const list = await client.listTools();
231
+ entry.tools = (list.tools ?? []).map((t) => ({
232
+ name: t.name,
233
+ description: typeof t.description === "string" ? t.description : "",
234
+ inputSchema: t.inputSchema ?? {
235
+ type: "object",
236
+ properties: {},
237
+ },
238
+ }));
239
+ entry.bridged = entry.tools.map((t) => bridgeMcpTool({
240
+ serverName: entry.name,
241
+ toolName: t.name,
242
+ description: t.description,
243
+ inputSchema: t.inputSchema,
244
+ getClient: () => pool.get(entryKey(entry.scope, entry.name))?.client,
245
+ }));
246
+ entry.state = "connected";
247
+ }
248
+ catch (err) {
249
+ delete entry.client;
250
+ delete entry.transport;
251
+ entry.tools = [];
252
+ entry.bridged = [];
253
+ entry.state = "error";
254
+ entry.lastError = err instanceof Error ? err.message : String(err);
255
+ }
256
+ }
257
+ async function disconnectEntry(entry) {
258
+ const client = entry.client;
259
+ const transport = entry.transport;
260
+ delete entry.client;
261
+ delete entry.transport;
262
+ entry.tools = [];
263
+ entry.bridged = [];
264
+ if (entry.state !== "disabled")
265
+ entry.state = "idle";
266
+ // Best-effort close. The MCP SDK's Client.close() also closes the
267
+ // transport, but we belt-and-suspender the transport too in case
268
+ // the client never finished handshaking.
269
+ // close() can be sync (void) or async (Promise<void>) depending on
270
+ // the transport — Promise.resolve normalizes either to a thenable.
271
+ await Promise.resolve(client?.close()).catch(() => undefined);
272
+ await Promise.resolve(transport?.close()).catch(() => undefined);
273
+ }
274
+ /**
275
+ * Open a connection using the requested transport. `auto` (default)
276
+ * attempts StreamableHTTP first, then falls back to SSE on failure —
277
+ * covers fastmcp servers regardless of which transport they expose.
278
+ */
279
+ async function openConnection(cfg) {
280
+ const url = new URL(cfg.url);
281
+ const requested = cfg.transport ?? "auto";
282
+ if (requested === "streamable-http") {
283
+ return await openStreamableHttp(url, cfg.headers);
284
+ }
285
+ if (requested === "sse") {
286
+ return await openSse(url, cfg.headers);
287
+ }
288
+ // auto: try streamable-http, fall back to sse
289
+ try {
290
+ return await openStreamableHttp(url, cfg.headers);
291
+ }
292
+ catch {
293
+ return await openSse(url, cfg.headers);
294
+ }
295
+ }
296
+ async function openStreamableHttp(url, headers) {
297
+ const transport = new StreamableHTTPClientTransport(url, headers !== undefined ? { requestInit: { headers } } : undefined);
298
+ const client = new Client({ name: "pi-forge", version: "1.0.0" }, { capabilities: {} });
299
+ await client.connect(transport);
300
+ return { client, transport, resolvedTransport: "streamable-http" };
301
+ }
302
+ async function openSse(url, headers) {
303
+ // Build options inline — exactOptionalPropertyTypes refuses to
304
+ // accept explicit `undefined` for optional properties, so the
305
+ // header-bearing variant builds the full options literal in one
306
+ // shot rather than composing it field-by-field.
307
+ const transport = headers !== undefined
308
+ ? new SSEClientTransport(url, {
309
+ requestInit: { headers },
310
+ // Custom EventSource fetch factory so the SSE GET also
311
+ // carries the Authorization header. Browsers' native
312
+ // EventSource doesn't accept headers, but the MCP SDK's
313
+ // bundled eventsource shim does, via this factory hook.
314
+ eventSourceInit: {
315
+ fetch: (input, init) => fetch(input, {
316
+ ...init,
317
+ headers: { ...(init?.headers ?? {}), ...headers },
318
+ }),
319
+ },
320
+ })
321
+ : new SSEClientTransport(url);
322
+ const client = new Client({ name: "pi-forge", version: "1.0.0" }, { capabilities: {} });
323
+ await client.connect(transport);
324
+ return { client, transport, resolvedTransport: "sse" };
325
+ }
326
+ /* -------------------------- project-scope read -------------------------- */
327
+ async function readProjectMcpJson(projectPath) {
328
+ const path = join(projectPath, PROJECT_MCP_FILE);
329
+ try {
330
+ const raw = await readFile(path, "utf8");
331
+ if (raw.trim().length === 0)
332
+ return {};
333
+ const parsed = JSON.parse(raw);
334
+ if (typeof parsed !== "object" || parsed === null)
335
+ return {};
336
+ // Accept both `{ servers: {...} }` (pi-forge shape) and
337
+ // `{ mcpServers: {...} }` (Claude Desktop / pi-mcp-adapter shape)
338
+ // so a project that already speaks the standard MCP file format
339
+ // works without rewriting.
340
+ const servers = parsed.servers ?? parsed.mcpServers;
341
+ if (typeof servers !== "object" || servers === null)
342
+ return {};
343
+ return servers;
344
+ }
345
+ catch (err) {
346
+ if (err.code === "ENOENT")
347
+ return {};
348
+ throw err;
349
+ }
350
+ }
351
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/mcp/manager.ts"],"names":[],"mappings":"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"}