pi2dsh 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -2
- package/README.zh.md +26 -0
- package/dist/{analyzer-DLwDZoYB.mjs → analyzer-LpQ59yjZ.mjs} +2 -2
- package/dist/{analyzer-DLwDZoYB.mjs.map → analyzer-LpQ59yjZ.mjs.map} +1 -1
- package/dist/cli.mjs +3 -2
- package/dist/cli.mjs.map +1 -1
- package/dist/client.js +17 -12
- package/dist/compat/pi-coding-agent.d.mts +2 -2
- package/dist/compat/pi-coding-agent.mjs +2 -2
- package/dist/{mcp-config-CyCPWeUs.mjs → compatibility-CsJEjhu8.mjs} +10 -187
- package/dist/compatibility-CsJEjhu8.mjs.map +1 -0
- package/dist/credentials-oauth.mjs +1 -1
- package/dist/host.d.mts +9 -2
- package/dist/host.d.mts.map +1 -1
- package/dist/host.mjs +7 -2
- package/dist/host.mjs.map +1 -1
- package/dist/index.d.mts +8 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +154 -8
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-config-C1K-IzzB.mjs +180 -0
- package/dist/mcp-config-C1K-IzzB.mjs.map +1 -0
- package/dist/{pi-coding-agent-DXJ_Jzo0.mjs → pi-coding-agent-CPXFo0UO.mjs} +0 -0
- package/dist/pi-coding-agent-CPXFo0UO.mjs.map +1 -0
- package/dist/{pi-coding-agent-69yY0ke-.d.mts → pi-coding-agent-Pvy0m9tS.d.mts} +6 -2
- package/dist/{pi-coding-agent-69yY0ke-.d.mts.map → pi-coding-agent-Pvy0m9tS.d.mts.map} +1 -1
- package/dist/{runtime-CW52OWvW.mjs → runtime-CGDq6LKi.mjs} +557 -27
- package/dist/runtime-CGDq6LKi.mjs.map +1 -0
- package/dist/runtime.d.mts +83 -41
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +2 -2
- package/package.json +7 -2
- package/dist/mcp-config-CyCPWeUs.mjs.map +0 -1
- package/dist/pi-coding-agent-DXJ_Jzo0.mjs.map +0 -1
- package/dist/runtime-CW52OWvW.mjs.map +0 -1
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
2
|
+
import { Dn as PiCapabilityError, En as CapabilityLedger, F as generateBranchSummary, b as Theme, d as ExtensionRunner, w as __runWithSubagentSessionFactory } from "./pi-coding-agent-CPXFo0UO.mjs";
|
|
3
3
|
import { t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
|
|
4
4
|
import { $ as AssistantMessageEventStream, S as getSupportedThinkingLevels, c as builtinProviders, et as isContextOverflow, o as __runWithPiAiRuntime, r as __createPiAiRuntimeRegistry } from "./pi-ai-DQPHUR9S.mjs";
|
|
5
5
|
import { W as getKeybindings, _t as stripTerminalSequences } from "./pi-tui-DruSeKmd.mjs";
|
|
6
|
+
import { r as piMcpConfigPaths, t as collectPiMcpServers } from "./mcp-config-C1K-IzzB.mjs";
|
|
6
7
|
import { c as resolvePiProviderAuth, i as oauthCredentialRef, l as storedOAuthCredential, n as joinSignals, o as providerSupportsOAuth, r as loginPiProvider, t as FileCredentialStore } from "./oauth-bridge-C_MAPMGA.mjs";
|
|
7
8
|
import { createRequire } from "node:module";
|
|
8
9
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
9
10
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, unlinkSync } from "node:fs";
|
|
10
11
|
import { basename, dirname, join, resolve } from "node:path";
|
|
11
12
|
import { fileURLToPath } from "node:url";
|
|
12
|
-
import { tmpdir } from "node:os";
|
|
13
|
+
import { homedir, tmpdir } from "node:os";
|
|
13
14
|
import { EventEmitter } from "node:events";
|
|
14
15
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
15
16
|
import { createJiti } from "jiti";
|
|
@@ -912,7 +913,21 @@ var PiBridgedAgentSession = class {
|
|
|
912
913
|
this.#restrictionDispose = toolsService.restrict({ allow: this.#activeToolNames.map(nativeToolNameOf).filter((name) => known.has(name)) });
|
|
913
914
|
} catch {}
|
|
914
915
|
}
|
|
915
|
-
|
|
916
|
+
/** Per-extension mount failures recorded at creation, for bindExtensions' onError. */
|
|
917
|
+
#extensionFailures = [];
|
|
918
|
+
adoptExtensionFailures(failures) {
|
|
919
|
+
this.#extensionFailures = failures;
|
|
920
|
+
}
|
|
921
|
+
async bindExtensions(bindings = {}) {
|
|
922
|
+
const onError = bindings.onError;
|
|
923
|
+
if (typeof onError !== "function") return;
|
|
924
|
+
for (const failure of this.#extensionFailures) try {
|
|
925
|
+
onError({
|
|
926
|
+
extensionPath: failure.name,
|
|
927
|
+
error: failure.error
|
|
928
|
+
});
|
|
929
|
+
} catch {}
|
|
930
|
+
}
|
|
916
931
|
async dispose() {
|
|
917
932
|
for (const dispose of this.#disposers.splice(0)) try {
|
|
918
933
|
dispose();
|
|
@@ -948,6 +963,7 @@ async function createBridgedAgentSession(host, options) {
|
|
|
948
963
|
const providedManager = options.sessionManager;
|
|
949
964
|
const archiveFile = typeof providedManager?.getSessionFile === "function" ? providedManager.getSessionFile() : void 0;
|
|
950
965
|
const resumeSessionId = host.resumeSessionIdFor?.(archiveFile);
|
|
966
|
+
const sideline = providedManager !== void 0 && archiveFile === void 0;
|
|
951
967
|
subagentSerial += 1;
|
|
952
968
|
const sessionId = `pi2dsh-sub-${Date.now().toString(36)}-${subagentSerial}`;
|
|
953
969
|
let handle;
|
|
@@ -1061,15 +1077,30 @@ async function createBridgedAgentSession(host, options) {
|
|
|
1061
1077
|
version: 2,
|
|
1062
1078
|
mode: "continuable",
|
|
1063
1079
|
provider: "pi2dsh",
|
|
1064
|
-
label: childLabel(options.label, host.packageName)
|
|
1080
|
+
label: `${sideline ? "Side: " : ""}${childLabel(options.label, host.packageName)}`
|
|
1065
1081
|
});
|
|
1066
1082
|
} catch (error) {
|
|
1067
1083
|
host.cordis.logger?.warn?.(`[pi2dsh] child session could not record its subagent identity: ${error instanceof Error ? error.message : String(error)}`);
|
|
1068
1084
|
}
|
|
1069
1085
|
const thinkingLevel = typeof options.thinkingLevel === "string" ? options.thinkingLevel : void 0;
|
|
1070
1086
|
host.adoptChildAgent?.(handle.agent, thinkingLevel);
|
|
1087
|
+
let extensionFailures = [];
|
|
1088
|
+
try {
|
|
1089
|
+
extensionFailures = await host.mountChildExtensions?.(handle.agent, options.resourceLoader) ?? [];
|
|
1090
|
+
} catch (error) {
|
|
1091
|
+
extensionFailures = [{
|
|
1092
|
+
name: "pi2dsh:child-extensions",
|
|
1093
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1094
|
+
}];
|
|
1095
|
+
}
|
|
1096
|
+
for (const failure of extensionFailures) {
|
|
1097
|
+
const message = `[pi2dsh] child extension ${JSON.stringify(failure.name)} did not mount: ${failure.error}`;
|
|
1098
|
+
host.cordis.logger?.warn?.(message);
|
|
1099
|
+
console.warn(message);
|
|
1100
|
+
}
|
|
1071
1101
|
const session = new PiBridgedAgentSession(host, handle, tools, thinkingLevel);
|
|
1072
1102
|
session.adoptRestriction(initialRestrictionDispose);
|
|
1103
|
+
session.adoptExtensionFailures(extensionFailures);
|
|
1073
1104
|
return { session };
|
|
1074
1105
|
}
|
|
1075
1106
|
//#endregion
|
|
@@ -1109,6 +1140,7 @@ function messageText(message) {
|
|
|
1109
1140
|
*/
|
|
1110
1141
|
var BrowserSurfaces = class {
|
|
1111
1142
|
#byParent = /* @__PURE__ */ new Map();
|
|
1143
|
+
#commandRunners = /* @__PURE__ */ new Map();
|
|
1112
1144
|
#surfaces = /* @__PURE__ */ new Map();
|
|
1113
1145
|
#entrySources = /* @__PURE__ */ new Map();
|
|
1114
1146
|
#draftRequests = /* @__PURE__ */ new Map();
|
|
@@ -1150,6 +1182,7 @@ var BrowserSurfaces = class {
|
|
|
1150
1182
|
if (typeof component?.render !== "function") {
|
|
1151
1183
|
this.#scene = void 0;
|
|
1152
1184
|
this.#invalidateScene();
|
|
1185
|
+
console.warn(`[pi2dsh] web scene for ${packageName}: component lacks render(width)`);
|
|
1153
1186
|
reject(/* @__PURE__ */ new TypeError("Pi custom component must implement render(width)"));
|
|
1154
1187
|
return;
|
|
1155
1188
|
}
|
|
@@ -1159,6 +1192,7 @@ var BrowserSurfaces = class {
|
|
|
1159
1192
|
if (this.#scene !== run) return;
|
|
1160
1193
|
this.#scene = void 0;
|
|
1161
1194
|
this.#invalidateScene();
|
|
1195
|
+
console.warn(`[pi2dsh] web scene for ${packageName}: component factory failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}`);
|
|
1162
1196
|
reject(error);
|
|
1163
1197
|
});
|
|
1164
1198
|
});
|
|
@@ -1179,6 +1213,7 @@ var BrowserSurfaces = class {
|
|
|
1179
1213
|
const failed = this.#scene;
|
|
1180
1214
|
this.#scene = void 0;
|
|
1181
1215
|
this.#invalidateScene();
|
|
1216
|
+
console.warn(`[pi2dsh] web scene for ${scene.package}: render(width) failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}`);
|
|
1182
1217
|
failed?.reject(error);
|
|
1183
1218
|
return {
|
|
1184
1219
|
open: false,
|
|
@@ -1234,6 +1269,32 @@ var BrowserSurfaces = class {
|
|
|
1234
1269
|
};
|
|
1235
1270
|
}
|
|
1236
1271
|
/**
|
|
1272
|
+
* Register the executor for one package's Pi commands on one session, so
|
|
1273
|
+
* product UI (a side-chat window's input, its action buttons) can run the
|
|
1274
|
+
* package's OWN command handlers — the same code path the composer takes.
|
|
1275
|
+
* Generic by construction: the runner closure carries the package runtime;
|
|
1276
|
+
* this registry only routes (session, package) to it.
|
|
1277
|
+
* @param sessionId - the root session the package is mounted for.
|
|
1278
|
+
* @param packageName - the Pi package owning the commands.
|
|
1279
|
+
* @param runner - executes one registered Pi command by its Pi name.
|
|
1280
|
+
* @returns a disposer that unregisters the runner.
|
|
1281
|
+
*/
|
|
1282
|
+
registerCommandRunner(sessionId, packageName, runner) {
|
|
1283
|
+
const runners = this.#commandRunners.get(sessionId) ?? /* @__PURE__ */ new Map();
|
|
1284
|
+
runners.set(packageName, runner);
|
|
1285
|
+
this.#commandRunners.set(sessionId, runners);
|
|
1286
|
+
return () => {
|
|
1287
|
+
const live = this.#commandRunners.get(sessionId);
|
|
1288
|
+
if (live === void 0) return;
|
|
1289
|
+
if (live.get(packageName) === runner) live.delete(packageName);
|
|
1290
|
+
if (live.size === 0) this.#commandRunners.delete(sessionId);
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
/** The registered runner for (session, package), when one is mounted. */
|
|
1294
|
+
commandRunner(sessionId, packageName) {
|
|
1295
|
+
return this.#commandRunners.get(sessionId)?.get(packageName);
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1237
1298
|
* The panel's view of one parent session.
|
|
1238
1299
|
* @param parentSessionId - session the browser is currently showing.
|
|
1239
1300
|
* @returns every side thread opened under it, oldest first.
|
|
@@ -1535,7 +1596,7 @@ function publishAuthorization(url) {
|
|
|
1535
1596
|
function revokeAuthorization(path) {
|
|
1536
1597
|
pendingAuthorizations.delete(path.slice(18));
|
|
1537
1598
|
}
|
|
1538
|
-
function registerBrowserSurfaceRoute(ctx, registry) {
|
|
1599
|
+
function registerBrowserSurfaceRoute(ctx, registry, hooks) {
|
|
1539
1600
|
const web = ctx.get("webServer");
|
|
1540
1601
|
if (web === void 0 || typeof web.register !== "function") return false;
|
|
1541
1602
|
ctx.effect(() => web.register({
|
|
@@ -1560,6 +1621,75 @@ function registerBrowserSurfaceRoute(ctx, registry) {
|
|
|
1560
1621
|
response.end();
|
|
1561
1622
|
return;
|
|
1562
1623
|
}
|
|
1624
|
+
if (url.pathname === "/pi2dsh/mcp-state" && (method === "GET" || method === "HEAD")) {
|
|
1625
|
+
if (hooks?.mcpState === void 0) {
|
|
1626
|
+
response.writeHead(404);
|
|
1627
|
+
response.end();
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
const body = JSON.stringify(await hooks.mcpState(url.searchParams.get("session") ?? ""));
|
|
1631
|
+
response.writeHead(200, {
|
|
1632
|
+
"content-type": "application/json; charset=utf-8",
|
|
1633
|
+
"cache-control": "no-store"
|
|
1634
|
+
});
|
|
1635
|
+
response.end(method === "HEAD" ? void 0 : body);
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1638
|
+
if (url.pathname === "/pi2dsh/mcp-action" && method === "POST") {
|
|
1639
|
+
if (hooks?.mcpAction === void 0) {
|
|
1640
|
+
response.writeHead(404);
|
|
1641
|
+
response.end();
|
|
1642
|
+
return;
|
|
1643
|
+
}
|
|
1644
|
+
const chunks = [];
|
|
1645
|
+
const raw = await new Promise((settle) => {
|
|
1646
|
+
const stream = req;
|
|
1647
|
+
stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
1648
|
+
stream.on("end", () => settle(Buffer.concat(chunks).toString("utf8")));
|
|
1649
|
+
});
|
|
1650
|
+
let outcome;
|
|
1651
|
+
try {
|
|
1652
|
+
const payload = JSON.parse(raw || "{}");
|
|
1653
|
+
if (typeof payload.session !== "string" || typeof payload.server !== "string" || typeof payload.disabled !== "boolean") throw new TypeError("mcp-action needs { session, server, disabled }");
|
|
1654
|
+
const scope = payload.scope === "global" ? "global" : "project";
|
|
1655
|
+
outcome = await hooks.mcpAction(payload.session, payload.server, payload.disabled, scope);
|
|
1656
|
+
} catch (error) {
|
|
1657
|
+
response.writeHead(400, { "content-type": "application/json; charset=utf-8" });
|
|
1658
|
+
response.end(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }));
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
response.writeHead(200, { "content-type": "application/json; charset=utf-8" });
|
|
1662
|
+
response.end(JSON.stringify(outcome ?? { ok: true }));
|
|
1663
|
+
return;
|
|
1664
|
+
}
|
|
1665
|
+
if (url.pathname === "/pi2dsh/pi-command" && method === "POST") {
|
|
1666
|
+
const chunks = [];
|
|
1667
|
+
const raw = await new Promise((settle) => {
|
|
1668
|
+
const stream = req;
|
|
1669
|
+
stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
1670
|
+
stream.on("end", () => settle(Buffer.concat(chunks).toString("utf8")));
|
|
1671
|
+
});
|
|
1672
|
+
try {
|
|
1673
|
+
const payload = JSON.parse(raw || "{}");
|
|
1674
|
+
if (typeof payload.session !== "string" || typeof payload.package !== "string" || typeof payload.command !== "string") throw new TypeError("pi-command needs { session, package, command }");
|
|
1675
|
+
const runner = registry.commandRunner(payload.session, payload.package);
|
|
1676
|
+
if (runner === void 0) {
|
|
1677
|
+
response.writeHead(404, { "content-type": "application/json; charset=utf-8" });
|
|
1678
|
+
response.end(JSON.stringify({ error: `no ${payload.package} command runner mounted for this session` }));
|
|
1679
|
+
return;
|
|
1680
|
+
}
|
|
1681
|
+
const notice = await runner(payload.command, typeof payload.args === "string" ? payload.args : "");
|
|
1682
|
+
response.writeHead(200, { "content-type": "application/json; charset=utf-8" });
|
|
1683
|
+
response.end(JSON.stringify({
|
|
1684
|
+
ok: true,
|
|
1685
|
+
...notice === void 0 ? {} : { notice }
|
|
1686
|
+
}));
|
|
1687
|
+
} catch (error) {
|
|
1688
|
+
response.writeHead(400, { "content-type": "application/json; charset=utf-8" });
|
|
1689
|
+
response.end(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }));
|
|
1690
|
+
}
|
|
1691
|
+
return;
|
|
1692
|
+
}
|
|
1563
1693
|
if (method === "POST" && (url.pathname === "/pi2dsh/scene-input" || url.pathname === "/pi2dsh/scene-close")) {
|
|
1564
1694
|
const chunks = [];
|
|
1565
1695
|
const body = await new Promise((settle) => {
|
|
@@ -3112,7 +3242,7 @@ function registerPiProviderRoute(options) {
|
|
|
3112
3242
|
}
|
|
3113
3243
|
//#endregion
|
|
3114
3244
|
//#region src/tui-surfaces.ts
|
|
3115
|
-
function service(ctx, name) {
|
|
3245
|
+
function service$1(ctx, name) {
|
|
3116
3246
|
try {
|
|
3117
3247
|
return ctx.get(name, false);
|
|
3118
3248
|
} catch {
|
|
@@ -3159,6 +3289,8 @@ function preferredWidth(options) {
|
|
|
3159
3289
|
var TuiSurfaceAdapter = class {
|
|
3160
3290
|
packageName;
|
|
3161
3291
|
instanceKey;
|
|
3292
|
+
kind = "tuiScenes";
|
|
3293
|
+
nativeCommands = dshTuiLocalCommands();
|
|
3162
3294
|
sceneId;
|
|
3163
3295
|
scenes;
|
|
3164
3296
|
status;
|
|
@@ -3171,10 +3303,10 @@ var TuiSurfaceAdapter = class {
|
|
|
3171
3303
|
constructor(ctx, packageName, instanceKey) {
|
|
3172
3304
|
this.packageName = packageName;
|
|
3173
3305
|
this.instanceKey = instanceKey;
|
|
3174
|
-
const scenes = service(ctx, "tuiScenes");
|
|
3306
|
+
const scenes = service$1(ctx, "tuiScenes");
|
|
3175
3307
|
if (scenes === void 0) throw new Error("pi2dsh: dsh-TUI scene service is unavailable");
|
|
3176
3308
|
this.scenes = scenes;
|
|
3177
|
-
this.status = service(ctx, "tuiStatus");
|
|
3309
|
+
this.status = service$1(ctx, "tuiStatus");
|
|
3178
3310
|
this.sceneId = sceneIdFor(instanceKey === void 0 ? packageName : `${packageName}-${instanceKey}`);
|
|
3179
3311
|
this.unregisterScene = scenes.register({
|
|
3180
3312
|
id: this.sceneId,
|
|
@@ -3307,7 +3439,7 @@ function mountTuiSurfaceAdapter(ctx, packageName, publish, instanceKey) {
|
|
|
3307
3439
|
publish(void 0);
|
|
3308
3440
|
});
|
|
3309
3441
|
};
|
|
3310
|
-
if (service(ctx, "tuiScenes") !== void 0) {
|
|
3442
|
+
if (service$1(ctx, "tuiScenes") !== void 0) {
|
|
3311
3443
|
attach(ctx);
|
|
3312
3444
|
return;
|
|
3313
3445
|
}
|
|
@@ -3400,8 +3532,252 @@ function dshTuiLocalCommands() {
|
|
|
3400
3532
|
cachedTuiLocalCommands = tuiLocalCommandsForVersion(version);
|
|
3401
3533
|
return cachedTuiLocalCommands;
|
|
3402
3534
|
}
|
|
3403
|
-
|
|
3404
|
-
|
|
3535
|
+
/** Host-native command ownership, independent of the concrete TUI package. */
|
|
3536
|
+
function commandNameForTerminal(name, nativeCommands) {
|
|
3537
|
+
return nativeCommands?.has(name) === true ? `pi-${name}` : name;
|
|
3538
|
+
}
|
|
3539
|
+
/** Bridge fallback commands disappear when the active Host already owns one. */
|
|
3540
|
+
function shouldRegisterCompatibilityCommand(name, nativeCommands) {
|
|
3541
|
+
return nativeCommands?.has(name) !== true;
|
|
3542
|
+
}
|
|
3543
|
+
//#endregion
|
|
3544
|
+
//#region src/pi-component-relay.ts
|
|
3545
|
+
let relaySerial = 0;
|
|
3546
|
+
function relayId() {
|
|
3547
|
+
relaySerial += 1;
|
|
3548
|
+
return `pi2dsh-custom-${relaySerial}`;
|
|
3549
|
+
}
|
|
3550
|
+
/**
|
|
3551
|
+
* One Host-owned Pi component session expressed as data messages.
|
|
3552
|
+
*
|
|
3553
|
+
* The result value never crosses the presentation boundary: Pi's own `done`
|
|
3554
|
+
* callback completes it on the Host. Frames and input are deliberately plain
|
|
3555
|
+
* data so the presentation transport can change independently.
|
|
3556
|
+
*/
|
|
3557
|
+
var PiComponentRelay = class {
|
|
3558
|
+
sessionId = relayId();
|
|
3559
|
+
options;
|
|
3560
|
+
ready;
|
|
3561
|
+
result;
|
|
3562
|
+
component;
|
|
3563
|
+
invalidations = /* @__PURE__ */ new Set();
|
|
3564
|
+
resolveResult;
|
|
3565
|
+
rejectResult;
|
|
3566
|
+
revision = 0;
|
|
3567
|
+
closed = false;
|
|
3568
|
+
constructor(factory, theme, keybindings, options) {
|
|
3569
|
+
this.options = options;
|
|
3570
|
+
this.result = new Promise((resolve, reject) => {
|
|
3571
|
+
this.resolveResult = resolve;
|
|
3572
|
+
this.rejectResult = reject;
|
|
3573
|
+
});
|
|
3574
|
+
const driver = { requestRender: () => this.invalidate() };
|
|
3575
|
+
const done = (value) => this.close(value);
|
|
3576
|
+
this.ready = Promise.resolve().then(() => factory(driver, theme, keybindings, done)).then((component) => {
|
|
3577
|
+
if (this.closed) {
|
|
3578
|
+
component.dispose?.();
|
|
3579
|
+
return false;
|
|
3580
|
+
}
|
|
3581
|
+
if (typeof component?.render !== "function") throw new TypeError("Pi custom component must implement render(width)");
|
|
3582
|
+
this.component = component;
|
|
3583
|
+
this.invalidate();
|
|
3584
|
+
return true;
|
|
3585
|
+
}).catch((error) => {
|
|
3586
|
+
this.fail(error);
|
|
3587
|
+
return false;
|
|
3588
|
+
});
|
|
3589
|
+
}
|
|
3590
|
+
get active() {
|
|
3591
|
+
return !this.closed;
|
|
3592
|
+
}
|
|
3593
|
+
onInvalidate(listener) {
|
|
3594
|
+
this.invalidations.add(listener);
|
|
3595
|
+
return () => this.invalidations.delete(listener);
|
|
3596
|
+
}
|
|
3597
|
+
frame(request) {
|
|
3598
|
+
if (request.sessionId !== this.sessionId) throw new Error("stale Pi component render session");
|
|
3599
|
+
const width = Math.max(1, Math.floor(request.width));
|
|
3600
|
+
return {
|
|
3601
|
+
sessionId: this.sessionId,
|
|
3602
|
+
revision: this.revision,
|
|
3603
|
+
width,
|
|
3604
|
+
lines: this.component?.render(width) ?? []
|
|
3605
|
+
};
|
|
3606
|
+
}
|
|
3607
|
+
input(message) {
|
|
3608
|
+
if (message.sessionId !== this.sessionId || this.closed) return;
|
|
3609
|
+
this.component?.handleInput?.(message.data);
|
|
3610
|
+
}
|
|
3611
|
+
invalidate() {
|
|
3612
|
+
if (this.closed) return;
|
|
3613
|
+
this.revision += 1;
|
|
3614
|
+
for (const listener of this.invalidations) listener(this.revision);
|
|
3615
|
+
}
|
|
3616
|
+
close(value) {
|
|
3617
|
+
if (this.closed) return;
|
|
3618
|
+
this.closed = true;
|
|
3619
|
+
const component = this.component;
|
|
3620
|
+
this.component = void 0;
|
|
3621
|
+
component?.dispose?.();
|
|
3622
|
+
this.invalidations.clear();
|
|
3623
|
+
this.resolveResult(value);
|
|
3624
|
+
}
|
|
3625
|
+
fail(error) {
|
|
3626
|
+
if (this.closed) return;
|
|
3627
|
+
this.closed = true;
|
|
3628
|
+
const component = this.component;
|
|
3629
|
+
this.component = void 0;
|
|
3630
|
+
component?.dispose?.();
|
|
3631
|
+
this.invalidations.clear();
|
|
3632
|
+
this.rejectResult(error);
|
|
3633
|
+
}
|
|
3634
|
+
};
|
|
3635
|
+
//#endregion
|
|
3636
|
+
//#region src/pi-tui-extension-surface.ts
|
|
3637
|
+
function service(ctx) {
|
|
3638
|
+
try {
|
|
3639
|
+
return ctx.get("piTuiExtensions", false);
|
|
3640
|
+
} catch {
|
|
3641
|
+
return;
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3644
|
+
function statusId(packageName, instanceKey, key) {
|
|
3645
|
+
return `pi2dsh-status-${`${packageName}${instanceKey === void 0 ? "" : `-${instanceKey}`}-${key}`.toLowerCase().replace(/[^a-z0-9_-]+/gu, "-").replace(/^-+|-+$/gu, "") || "entry"}`;
|
|
3646
|
+
}
|
|
3647
|
+
function overlayOptions(options) {
|
|
3648
|
+
const raw = typeof options?.overlayOptions === "function" ? options.overlayOptions() : options?.overlayOptions;
|
|
3649
|
+
return raw === void 0 ? void 0 : { ...raw };
|
|
3650
|
+
}
|
|
3651
|
+
/** dsh-pi-tui backend over the public `piTuiExtensions` service. */
|
|
3652
|
+
var PiTuiExtensionSurfaceAdapter = class {
|
|
3653
|
+
extensionService;
|
|
3654
|
+
unstableFacade;
|
|
3655
|
+
packageName;
|
|
3656
|
+
instanceKey;
|
|
3657
|
+
kind = "piTuiExtensions";
|
|
3658
|
+
nativeCommands;
|
|
3659
|
+
statusHandles = /* @__PURE__ */ new Map();
|
|
3660
|
+
mounts = /* @__PURE__ */ new Set();
|
|
3661
|
+
disposed = false;
|
|
3662
|
+
constructor(extensionService, unstableFacade, nativeCommands, packageName, instanceKey) {
|
|
3663
|
+
this.extensionService = extensionService;
|
|
3664
|
+
this.unstableFacade = unstableFacade;
|
|
3665
|
+
this.packageName = packageName;
|
|
3666
|
+
this.instanceKey = instanceKey;
|
|
3667
|
+
this.nativeCommands = new Set(nativeCommands);
|
|
3668
|
+
}
|
|
3669
|
+
get available() {
|
|
3670
|
+
if (this.disposed) return false;
|
|
3671
|
+
try {
|
|
3672
|
+
return this.extensionService.api().capabilities.has("unstable.surface.handle");
|
|
3673
|
+
} catch {
|
|
3674
|
+
return false;
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
setStatus(key, text) {
|
|
3678
|
+
if (this.disposed) return;
|
|
3679
|
+
const id = statusId(this.packageName, this.instanceKey, key);
|
|
3680
|
+
const previous = this.statusHandles.get(id);
|
|
3681
|
+
if (text === void 0) {
|
|
3682
|
+
previous?.dispose();
|
|
3683
|
+
this.statusHandles.delete(id);
|
|
3684
|
+
return;
|
|
3685
|
+
}
|
|
3686
|
+
const value = {
|
|
3687
|
+
spans: [{
|
|
3688
|
+
text: String(text),
|
|
3689
|
+
tone: "textDim"
|
|
3690
|
+
}],
|
|
3691
|
+
minWidth: 4,
|
|
3692
|
+
importance: 50
|
|
3693
|
+
};
|
|
3694
|
+
if (previous !== void 0) {
|
|
3695
|
+
previous.replace(value);
|
|
3696
|
+
return;
|
|
3697
|
+
}
|
|
3698
|
+
if (!this.extensionService.api().capabilities.has("slot.chrome.footer.status")) return;
|
|
3699
|
+
this.statusHandles.set(id, this.extensionService.register("chrome.footer.status", {
|
|
3700
|
+
id,
|
|
3701
|
+
order: 500,
|
|
3702
|
+
description: `Pi status ${key} from ${this.packageName}`
|
|
3703
|
+
}, value));
|
|
3704
|
+
}
|
|
3705
|
+
async custom(factory, theme, keybindings, options) {
|
|
3706
|
+
if (!this.available) return void 0;
|
|
3707
|
+
for (const active of [...this.mounts]) active.relay.close(void 0);
|
|
3708
|
+
const relay = new PiComponentRelay(factory, theme, keybindings, options);
|
|
3709
|
+
const record = { relay };
|
|
3710
|
+
this.mounts.add(record);
|
|
3711
|
+
try {
|
|
3712
|
+
if (!await relay.ready || !relay.active) return await relay.result;
|
|
3713
|
+
if (this.disposed) {
|
|
3714
|
+
relay.close(void 0);
|
|
3715
|
+
return await relay.result;
|
|
3716
|
+
}
|
|
3717
|
+
const lease = this.unstableFacade.surface.handle.mountComponent({
|
|
3718
|
+
render: (width) => relay.frame({
|
|
3719
|
+
sessionId: relay.sessionId,
|
|
3720
|
+
width
|
|
3721
|
+
}).lines,
|
|
3722
|
+
handleInput: (data) => relay.input({
|
|
3723
|
+
sessionId: relay.sessionId,
|
|
3724
|
+
data
|
|
3725
|
+
}),
|
|
3726
|
+
dispose: () => relay.close(void 0)
|
|
3727
|
+
}, overlayOptions(options));
|
|
3728
|
+
record.lease = lease;
|
|
3729
|
+
const offInvalidate = relay.onInvalidate(() => lease.invalidate());
|
|
3730
|
+
const release = () => {
|
|
3731
|
+
offInvalidate();
|
|
3732
|
+
lease.close();
|
|
3733
|
+
};
|
|
3734
|
+
relay.result.then(release, release);
|
|
3735
|
+
if (!lease.active) relay.close(void 0);
|
|
3736
|
+
lease.focus();
|
|
3737
|
+
return await relay.result;
|
|
3738
|
+
} catch (error) {
|
|
3739
|
+
relay.fail(error);
|
|
3740
|
+
throw error;
|
|
3741
|
+
} finally {
|
|
3742
|
+
this.mounts.delete(record);
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
dispose() {
|
|
3746
|
+
if (this.disposed) return;
|
|
3747
|
+
this.disposed = true;
|
|
3748
|
+
for (const handle of this.statusHandles.values()) handle.dispose();
|
|
3749
|
+
this.statusHandles.clear();
|
|
3750
|
+
for (const active of this.mounts) {
|
|
3751
|
+
active.relay.close(void 0);
|
|
3752
|
+
active.lease?.close();
|
|
3753
|
+
}
|
|
3754
|
+
this.mounts.clear();
|
|
3755
|
+
}
|
|
3756
|
+
};
|
|
3757
|
+
/**
|
|
3758
|
+
* Build the optional backend from published public entry points.
|
|
3759
|
+
* Returns undefined when the service is absent or cannot provide the exact
|
|
3760
|
+
* raw-component capability; callers then keep the existing dsh-TUI/Web path.
|
|
3761
|
+
*/
|
|
3762
|
+
async function createPiTuiExtensionSurfaceAdapter(ctx, packageName, instanceKey) {
|
|
3763
|
+
const extensionService = service(ctx);
|
|
3764
|
+
if (extensionService === void 0) return void 0;
|
|
3765
|
+
const api = extensionService.api();
|
|
3766
|
+
if (api.apiVersion !== 1 || !api.capabilities.has("unstable.surface.handle")) {
|
|
3767
|
+
ctx.logger?.warn(`pi2dsh: piTuiExtensions cannot host Pi components (api=${api.apiVersion}, raw surface=${api.capabilities.has("unstable.surface.handle")})`);
|
|
3768
|
+
return;
|
|
3769
|
+
}
|
|
3770
|
+
try {
|
|
3771
|
+
const [hostModule, unstableModule] = await Promise.all([import("@xmoon76/dsh-pi-tui"), import("@xmoon76/dsh-pi-tui/extensions/unstable")]);
|
|
3772
|
+
if (unstableModule.UNSTABLE_API_LEVEL !== 1) {
|
|
3773
|
+
ctx.logger?.warn(`pi2dsh: unsupported dsh-pi-tui unstable API level ${unstableModule.UNSTABLE_API_LEVEL}`);
|
|
3774
|
+
return;
|
|
3775
|
+
}
|
|
3776
|
+
return new PiTuiExtensionSurfaceAdapter(extensionService, unstableModule.unstable(extensionService), hostModule.LOCAL_COMMANDS, packageName, instanceKey);
|
|
3777
|
+
} catch (error) {
|
|
3778
|
+
ctx.logger?.warn(`pi2dsh: could not attach the public piTuiExtensions backend: ${error instanceof Error ? error.message : String(error)}`);
|
|
3779
|
+
return;
|
|
3780
|
+
}
|
|
3405
3781
|
}
|
|
3406
3782
|
//#endregion
|
|
3407
3783
|
//#region src/runtime.ts
|
|
@@ -3854,7 +4230,7 @@ function projectDialogPrompt(title, supplementalDetail, linkMode) {
|
|
|
3854
4230
|
...detail.length === 0 ? {} : { detail }
|
|
3855
4231
|
};
|
|
3856
4232
|
}
|
|
3857
|
-
function contextFor(ctx, state, agent, signal, command = false, sessionOverride) {
|
|
4233
|
+
function contextFor(ctx, state, agent, signal, command = false, sessionOverride, headlessUi = false) {
|
|
3858
4234
|
const notices = [];
|
|
3859
4235
|
const userQuestions = optionalService(ctx, "userQuestions");
|
|
3860
4236
|
const dialogLinkMode = optionalService(ctx, "tuiScenes") === void 0 ? "markdown" : "terminal";
|
|
@@ -3920,6 +4296,7 @@ function contextFor(ctx, state, agent, signal, command = false, sessionOverride)
|
|
|
3920
4296
|
setTitle: (title) => putSurface(ctx, state, agent, "title", title),
|
|
3921
4297
|
custom: async (factory, options) => {
|
|
3922
4298
|
if (typeof factory !== "function") return void 0;
|
|
4299
|
+
if (headlessUi) return void 0;
|
|
3923
4300
|
const surfaces = state.tuiSurfaces;
|
|
3924
4301
|
if (surfaces !== void 0) return surfaces.custom(factory, state.theme, getKeybindings(), options);
|
|
3925
4302
|
const browser = state.shared.browserSurfaces;
|
|
@@ -4120,7 +4497,8 @@ function contextFor(ctx, state, agent, signal, command = false, sessionOverride)
|
|
|
4120
4497
|
},
|
|
4121
4498
|
ui,
|
|
4122
4499
|
get mode() {
|
|
4123
|
-
|
|
4500
|
+
if (state.tuiSurfaces?.available === true) return "tui";
|
|
4501
|
+
return state.shared.browserSurfaces !== void 0 && state.shared.browserSurfacesRouted === true ? "tui" : "rpc";
|
|
4124
4502
|
},
|
|
4125
4503
|
get hasUI() {
|
|
4126
4504
|
return state.tuiSurfaces?.available === true || humanAnswererAvailable(userQuestions, agent);
|
|
@@ -5234,6 +5612,59 @@ function oauthStoreOf(state) {
|
|
|
5234
5612
|
}
|
|
5235
5613
|
const COMPANION_ROUTE_PREFIX = "pi2dsh-companion/";
|
|
5236
5614
|
const SHARED_HOST_STATE = /* @__PURE__ */ new WeakMap();
|
|
5615
|
+
function registerChildExtensionCatalog(ctx, catalog) {
|
|
5616
|
+
sharedHostStateOf(ctx).childExtensions = catalog;
|
|
5617
|
+
}
|
|
5618
|
+
/** Read the installed-package catalog registered on shared host state, or undefined. */
|
|
5619
|
+
function getSharedChildExtensionCatalog(ctx) {
|
|
5620
|
+
return sharedHostStateOf(ctx).childExtensions;
|
|
5621
|
+
}
|
|
5622
|
+
/**
|
|
5623
|
+
* Which installed packages a creator's resource loader selects for its child
|
|
5624
|
+
* — the creator's OWN filter code decides (the loader's getExtensions applies
|
|
5625
|
+
* noExtensions and extensionsOverride), this only maps the surviving entry
|
|
5626
|
+
* paths back to package names. No loader at all means Pi's default: the full
|
|
5627
|
+
* discovered set (sdk.ts builds a default loader and loads everything).
|
|
5628
|
+
*/
|
|
5629
|
+
function resolveChildExtensionPackages(loader, catalog) {
|
|
5630
|
+
if (loader === void 0 || loader === null) return {
|
|
5631
|
+
names: [...new Set(catalog.packageByEntryPath.values())],
|
|
5632
|
+
failures: []
|
|
5633
|
+
};
|
|
5634
|
+
const getExtensions = loader.getExtensions;
|
|
5635
|
+
if (typeof getExtensions !== "function") return {
|
|
5636
|
+
names: [],
|
|
5637
|
+
failures: []
|
|
5638
|
+
};
|
|
5639
|
+
const names = /* @__PURE__ */ new Set();
|
|
5640
|
+
const failures = [];
|
|
5641
|
+
let entries;
|
|
5642
|
+
try {
|
|
5643
|
+
entries = getExtensions.call(loader)?.extensions ?? [];
|
|
5644
|
+
} catch (error) {
|
|
5645
|
+
return {
|
|
5646
|
+
names: [],
|
|
5647
|
+
failures: [{
|
|
5648
|
+
name: "resourceLoader.getExtensions",
|
|
5649
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5650
|
+
}]
|
|
5651
|
+
};
|
|
5652
|
+
}
|
|
5653
|
+
for (const entry of entries) {
|
|
5654
|
+
const path = entry?.path;
|
|
5655
|
+
if (typeof path !== "string" || path.length === 0) continue;
|
|
5656
|
+
const name = catalog.packageByEntryPath.get(resolve(path));
|
|
5657
|
+
if (name !== void 0) names.add(name);
|
|
5658
|
+
else failures.push({
|
|
5659
|
+
name: path,
|
|
5660
|
+
error: "not an installed DSH plugin — path-loaded extensions are not supported on this host; install it with `dsh plugin add <pkg>`"
|
|
5661
|
+
});
|
|
5662
|
+
}
|
|
5663
|
+
return {
|
|
5664
|
+
names: [...names],
|
|
5665
|
+
failures
|
|
5666
|
+
};
|
|
5667
|
+
}
|
|
5237
5668
|
/**
|
|
5238
5669
|
* Pi's provider ledger is layered, not flat (model-runtime.ts:742-786 at the
|
|
5239
5670
|
* pinned upstream): a builtin base map, an extension overlay where defined
|
|
@@ -5494,16 +5925,20 @@ async function materializeAttachmentImage(ctx, attachment) {
|
|
|
5494
5925
|
}
|
|
5495
5926
|
}
|
|
5496
5927
|
function ensureLoginCommand(ctx, state) {
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5928
|
+
if (!shouldRegisterCompatibilityCommand("login", state.tuiSurfaces?.nativeCommands) && optionalService(ctx, "authorization") !== void 0) {
|
|
5929
|
+
logger(ctx).debug("[pi2dsh] native terminal owns /login and the authorization service is composed; Pi OAuth flows are available through it");
|
|
5930
|
+
return;
|
|
5931
|
+
}
|
|
5932
|
+
if (state.shared.loginCommandRegistered === true) return;
|
|
5933
|
+
state.shared.loginCommandRegistered = true;
|
|
5502
5934
|
try {
|
|
5503
5935
|
registerLoginCommand(ctx, state);
|
|
5936
|
+
ctx.effect(() => () => {
|
|
5937
|
+
state.shared.loginCommandRegistered = false;
|
|
5938
|
+
});
|
|
5504
5939
|
} catch (error) {
|
|
5505
|
-
|
|
5506
|
-
logger(ctx).warn(`[pi2dsh] /login
|
|
5940
|
+
state.shared.loginCommandRegistered = false;
|
|
5941
|
+
logger(ctx).warn(`[pi2dsh] /login could not be registered; provider logins remain available on the host's own sign-in surface (${error instanceof Error ? error.message : String(error)})`);
|
|
5507
5942
|
}
|
|
5508
5943
|
}
|
|
5509
5944
|
/**
|
|
@@ -6279,9 +6714,9 @@ function normalizedPiCommandName(piName) {
|
|
|
6279
6714
|
}
|
|
6280
6715
|
function dshCommandName(ctx, state, piName) {
|
|
6281
6716
|
const validName = normalizedPiCommandName(piName);
|
|
6282
|
-
const name =
|
|
6717
|
+
const name = commandNameForTerminal(validName, state.tuiSurfaces?.nativeCommands);
|
|
6283
6718
|
if (name !== piName) {
|
|
6284
|
-
const reason = name === `pi-${validName}` ? `because
|
|
6719
|
+
const reason = name === `pi-${validName}` ? `because the active terminal reserves /${validName} for its native command (host commands win on collisions)` : "to satisfy DSH command naming";
|
|
6285
6720
|
logger(ctx).warn(`[pi2dsh] Pi command /${piName} registered as /${name} ${reason}`);
|
|
6286
6721
|
}
|
|
6287
6722
|
return name;
|
|
@@ -6767,6 +7202,12 @@ async function applyPiPackage(ctx, options) {
|
|
|
6767
7202
|
const shared = sharedHostStateOf(ctx);
|
|
6768
7203
|
const scopedOwner = options.ownerAgent ?? scopeOf(ctx);
|
|
6769
7204
|
const ownerAgent = typeof scopedOwner === "object" && scopedOwner !== null ? scopedOwner : void 0;
|
|
7205
|
+
if (ownerAgent !== void 0 && options.hostAnchor !== true) {
|
|
7206
|
+
shared.childPackageTools ??= /* @__PURE__ */ new WeakMap();
|
|
7207
|
+
const byPackage = shared.childPackageTools.get(ownerAgent) ?? /* @__PURE__ */ new Map();
|
|
7208
|
+
byPackage.set(options.manifest.package.name, runtimeTools);
|
|
7209
|
+
shared.childPackageTools.set(ownerAgent, byPackage);
|
|
7210
|
+
}
|
|
6770
7211
|
const state = {
|
|
6771
7212
|
shared,
|
|
6772
7213
|
packageName: options.manifest.package.name,
|
|
@@ -6829,9 +7270,17 @@ async function applyPiPackage(ctx, options) {
|
|
|
6829
7270
|
publishedOAuthKeys: shared.publishedOAuthKeys,
|
|
6830
7271
|
tuiSurfaces: void 0
|
|
6831
7272
|
};
|
|
6832
|
-
|
|
7273
|
+
const surfaceInstanceKey = typeof ownerAgent?.id === "string" ? ownerAgent.id : void 0;
|
|
7274
|
+
const piTuiSurface = await createPiTuiExtensionSurfaceAdapter(ctx, state.packageName, surfaceInstanceKey);
|
|
7275
|
+
if (piTuiSurface !== void 0) {
|
|
7276
|
+
state.tuiSurfaces = piTuiSurface;
|
|
7277
|
+
ctx.effect(() => () => {
|
|
7278
|
+
piTuiSurface.dispose();
|
|
7279
|
+
if (state.tuiSurfaces === piTuiSurface) state.tuiSurfaces = void 0;
|
|
7280
|
+
});
|
|
7281
|
+
} else mountTuiSurfaceAdapter(ctx, state.packageName, (adapter) => {
|
|
6833
7282
|
state.tuiSurfaces = adapter;
|
|
6834
|
-
},
|
|
7283
|
+
}, surfaceInstanceKey);
|
|
6835
7284
|
subscribeLifecycle(ctx, state);
|
|
6836
7285
|
subscribeInterceptors(ctx, state);
|
|
6837
7286
|
shared.providerBuiltins ??= /* @__PURE__ */ new Map();
|
|
@@ -6885,7 +7334,57 @@ async function applyPiPackage(ctx, options) {
|
|
|
6885
7334
|
});
|
|
6886
7335
|
}
|
|
6887
7336
|
const browserSurfaces = state.shared.browserSurfaces ??= new BrowserSurfaces();
|
|
6888
|
-
if (state.shared.browserSurfacesRouted !== true)
|
|
7337
|
+
if (state.shared.browserSurfacesRouted !== true) {
|
|
7338
|
+
const sessionCwd = (session) => {
|
|
7339
|
+
const cwd = ctx.get("sessions")?.get?.(session)?.header?.cwd;
|
|
7340
|
+
if (typeof cwd === "string" && cwd.length > 0) return cwd;
|
|
7341
|
+
return session === "" ? homedir() : process.cwd();
|
|
7342
|
+
};
|
|
7343
|
+
const globalLayerPaths = (cwd) => new Set(piMcpConfigPaths(cwd).slice(0, 4));
|
|
7344
|
+
state.shared.browserSurfacesRouted = registerBrowserSurfaceRoute(ctx, browserSurfaces, {
|
|
7345
|
+
async mcpState(session) {
|
|
7346
|
+
const cwd = sessionCwd(session);
|
|
7347
|
+
const globals = globalLayerPaths(cwd);
|
|
7348
|
+
const { servers, sources } = collectPiMcpServers(cwd);
|
|
7349
|
+
return {
|
|
7350
|
+
cwd,
|
|
7351
|
+
sources,
|
|
7352
|
+
servers: [...servers.values()].map((server) => ({
|
|
7353
|
+
name: server.name,
|
|
7354
|
+
transport: server.transport,
|
|
7355
|
+
target: server.transport === "stdio" ? [server.command, ...server.args ?? []].filter(Boolean).join(" ") : server.url ?? "",
|
|
7356
|
+
disabled: server.disabled,
|
|
7357
|
+
sourcePath: server.sourcePath,
|
|
7358
|
+
layer: globals.has(server.sourcePath) ? "global" : "project",
|
|
7359
|
+
envKeys: Object.keys(server.env ?? {}),
|
|
7360
|
+
headerKeys: Object.keys(server.headers ?? {})
|
|
7361
|
+
}))
|
|
7362
|
+
};
|
|
7363
|
+
},
|
|
7364
|
+
async mcpAction(session, server, disabled, scope) {
|
|
7365
|
+
const cwd = sessionCwd(session);
|
|
7366
|
+
const { servers } = collectPiMcpServers(cwd);
|
|
7367
|
+
if (!servers.has(server)) throw new TypeError(`unknown MCP server ${JSON.stringify(server)}`);
|
|
7368
|
+
const overridePath = scope === "global" ? [...globalLayerPaths(cwd)][3] : join(cwd, ".pi", "mcp.json");
|
|
7369
|
+
let current = {};
|
|
7370
|
+
try {
|
|
7371
|
+
current = JSON.parse(await readFile(overridePath, "utf8"));
|
|
7372
|
+
} catch {}
|
|
7373
|
+
const mcpServers = typeof current.mcpServers === "object" && current.mcpServers !== null ? current.mcpServers : {};
|
|
7374
|
+
mcpServers[server] = {
|
|
7375
|
+
...typeof mcpServers[server] === "object" && mcpServers[server] !== null ? mcpServers[server] : {},
|
|
7376
|
+
disabled
|
|
7377
|
+
};
|
|
7378
|
+
current.mcpServers = mcpServers;
|
|
7379
|
+
await mkdir(dirname(overridePath), { recursive: true });
|
|
7380
|
+
await writeFile(overridePath, `${JSON.stringify(current, null, 2)}\n`);
|
|
7381
|
+
return {
|
|
7382
|
+
ok: true,
|
|
7383
|
+
note: "run /reload (or restart the session) to apply"
|
|
7384
|
+
};
|
|
7385
|
+
}
|
|
7386
|
+
});
|
|
7387
|
+
}
|
|
6889
7388
|
ctx.effect(() => browserSurfaces.trackCompletions(state.packageName ?? "pi", async (trigger, query) => {
|
|
6890
7389
|
if (state.autocompleteProviders.length === 0) return [];
|
|
6891
7390
|
let provider = { getSuggestions: async () => null };
|
|
@@ -6941,6 +7440,21 @@ async function applyPiPackage(ctx, options) {
|
|
|
6941
7440
|
}
|
|
6942
7441
|
return rendered;
|
|
6943
7442
|
}));
|
|
7443
|
+
const runnerSessionId = ownerAgent === void 0 ? "" : String(agentSession(ownerAgent)?.id ?? "");
|
|
7444
|
+
if (runnerSessionId.length > 0) {
|
|
7445
|
+
const disposeRunner = browserSurfaces.registerCommandRunner(runnerSessionId, state.packageName, async (name, args) => {
|
|
7446
|
+
const live = state.commands.get(name);
|
|
7447
|
+
if (live === void 0) throw new Error(`${state.packageName} has no command ${JSON.stringify(name)}`);
|
|
7448
|
+
const commandContext = contextFor(ctx, state, ownerAgent, void 0, true, void 0, true);
|
|
7449
|
+
await runInPiRuntime(state, ownerAgent, async () => {
|
|
7450
|
+
await ensurePiSessionStarted(ctx, state, ownerAgent, void 0);
|
|
7451
|
+
await live.handler(args, commandContext);
|
|
7452
|
+
});
|
|
7453
|
+
const notices = commandContext.__notices;
|
|
7454
|
+
return notices.length > 0 ? notices.join("\n") : void 0;
|
|
7455
|
+
});
|
|
7456
|
+
ctx.effect(() => disposeRunner);
|
|
7457
|
+
}
|
|
6944
7458
|
state.subagentSessionFactory = async (subagentOptions) => {
|
|
6945
7459
|
const created = await createBridgedAgentSession(subagentHost(), subagentOptions);
|
|
6946
7460
|
const parent = agentSession(currentAgent(state));
|
|
@@ -6995,6 +7509,21 @@ async function applyPiPackage(ctx, options) {
|
|
|
6995
7509
|
return state.bridge.readonlySessionManager(session, cwd);
|
|
6996
7510
|
},
|
|
6997
7511
|
resumeSessionIdFor: (file) => state.bridge.sessionIdOfArchiveFile(file),
|
|
7512
|
+
mountChildExtensions: async (childAgent, loader) => {
|
|
7513
|
+
const shared = sharedHostStateOf(ctx);
|
|
7514
|
+
const catalog = shared.childExtensions;
|
|
7515
|
+
if (catalog === void 0) return [];
|
|
7516
|
+
const { names, failures } = resolveChildExtensionPackages(loader, catalog);
|
|
7517
|
+
if (names.length === 0) return failures;
|
|
7518
|
+
const mountFailures = await catalog.mount(childAgent, names);
|
|
7519
|
+
const attachable = loader;
|
|
7520
|
+
if (typeof attachable?.attachChildToolResolver === "function") attachable.attachChildToolResolver((path) => {
|
|
7521
|
+
const packageName = catalog.packageByEntryPath.get(resolve(path));
|
|
7522
|
+
if (packageName === void 0) return void 0;
|
|
7523
|
+
return shared.childPackageTools?.get(childAgent)?.get(packageName);
|
|
7524
|
+
});
|
|
7525
|
+
return [...failures, ...mountFailures];
|
|
7526
|
+
},
|
|
6998
7527
|
sessionGoneFromPersistence: async (sessionId) => {
|
|
6999
7528
|
const persistence = optionalService(ctx, "sessionPersistence");
|
|
7000
7529
|
if (typeof persistence?.list !== "function") return void 0;
|
|
@@ -7063,6 +7592,7 @@ const runtimeInternals = {
|
|
|
7063
7592
|
currentPiModel,
|
|
7064
7593
|
lastRequestRouteOf,
|
|
7065
7594
|
resolveCallerRoute,
|
|
7595
|
+
resolveChildExtensionPackages,
|
|
7066
7596
|
dshToPiContent,
|
|
7067
7597
|
expandPrompt,
|
|
7068
7598
|
isKnownImageTool,
|
|
@@ -7073,6 +7603,6 @@ const runtimeInternals = {
|
|
|
7073
7603
|
textBlocks
|
|
7074
7604
|
};
|
|
7075
7605
|
//#endregion
|
|
7076
|
-
export {
|
|
7606
|
+
export { overlayProviderConfig as a, runtimeInternals as c, normalizeToolSchema as i, getSharedChildExtensionCatalog as n, registerChildExtensionCatalog as o, mergeProviderRegistration as r, registerVisionCompanions as s, applyPiPackage as t };
|
|
7077
7607
|
|
|
7078
|
-
//# sourceMappingURL=runtime-
|
|
7608
|
+
//# sourceMappingURL=runtime-CGDq6LKi.mjs.map
|