pi2dsh 0.19.0 → 0.20.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-BL7Nfvko.mjs} +2 -2
- package/dist/{analyzer-DLwDZoYB.mjs.map → analyzer-BL7Nfvko.mjs.map} +1 -1
- package/dist/cli.mjs +3 -2
- package/dist/cli.mjs.map +1 -1
- 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-D_PV1zgF.mjs} +10 -187
- package/dist/compatibility-D_PV1zgF.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-CBZcd1uU.mjs} +476 -18
- package/dist/runtime-CBZcd1uU.mjs.map +1 -0
- package/dist/runtime.d.mts +66 -40
- 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();
|
|
@@ -1068,8 +1083,23 @@ async function createBridgedAgentSession(host, options) {
|
|
|
1068
1083
|
}
|
|
1069
1084
|
const thinkingLevel = typeof options.thinkingLevel === "string" ? options.thinkingLevel : void 0;
|
|
1070
1085
|
host.adoptChildAgent?.(handle.agent, thinkingLevel);
|
|
1086
|
+
let extensionFailures = [];
|
|
1087
|
+
try {
|
|
1088
|
+
extensionFailures = await host.mountChildExtensions?.(handle.agent, options.resourceLoader) ?? [];
|
|
1089
|
+
} catch (error) {
|
|
1090
|
+
extensionFailures = [{
|
|
1091
|
+
name: "pi2dsh:child-extensions",
|
|
1092
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1093
|
+
}];
|
|
1094
|
+
}
|
|
1095
|
+
for (const failure of extensionFailures) {
|
|
1096
|
+
const message = `[pi2dsh] child extension ${JSON.stringify(failure.name)} did not mount: ${failure.error}`;
|
|
1097
|
+
host.cordis.logger?.warn?.(message);
|
|
1098
|
+
console.warn(message);
|
|
1099
|
+
}
|
|
1071
1100
|
const session = new PiBridgedAgentSession(host, handle, tools, thinkingLevel);
|
|
1072
1101
|
session.adoptRestriction(initialRestrictionDispose);
|
|
1102
|
+
session.adoptExtensionFailures(extensionFailures);
|
|
1073
1103
|
return { session };
|
|
1074
1104
|
}
|
|
1075
1105
|
//#endregion
|
|
@@ -1150,6 +1180,7 @@ var BrowserSurfaces = class {
|
|
|
1150
1180
|
if (typeof component?.render !== "function") {
|
|
1151
1181
|
this.#scene = void 0;
|
|
1152
1182
|
this.#invalidateScene();
|
|
1183
|
+
console.warn(`[pi2dsh] web scene for ${packageName}: component lacks render(width)`);
|
|
1153
1184
|
reject(/* @__PURE__ */ new TypeError("Pi custom component must implement render(width)"));
|
|
1154
1185
|
return;
|
|
1155
1186
|
}
|
|
@@ -1159,6 +1190,7 @@ var BrowserSurfaces = class {
|
|
|
1159
1190
|
if (this.#scene !== run) return;
|
|
1160
1191
|
this.#scene = void 0;
|
|
1161
1192
|
this.#invalidateScene();
|
|
1193
|
+
console.warn(`[pi2dsh] web scene for ${packageName}: component factory failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}`);
|
|
1162
1194
|
reject(error);
|
|
1163
1195
|
});
|
|
1164
1196
|
});
|
|
@@ -1179,6 +1211,7 @@ var BrowserSurfaces = class {
|
|
|
1179
1211
|
const failed = this.#scene;
|
|
1180
1212
|
this.#scene = void 0;
|
|
1181
1213
|
this.#invalidateScene();
|
|
1214
|
+
console.warn(`[pi2dsh] web scene for ${scene.package}: render(width) failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}`);
|
|
1182
1215
|
failed?.reject(error);
|
|
1183
1216
|
return {
|
|
1184
1217
|
open: false,
|
|
@@ -1535,7 +1568,7 @@ function publishAuthorization(url) {
|
|
|
1535
1568
|
function revokeAuthorization(path) {
|
|
1536
1569
|
pendingAuthorizations.delete(path.slice(18));
|
|
1537
1570
|
}
|
|
1538
|
-
function registerBrowserSurfaceRoute(ctx, registry) {
|
|
1571
|
+
function registerBrowserSurfaceRoute(ctx, registry, hooks) {
|
|
1539
1572
|
const web = ctx.get("webServer");
|
|
1540
1573
|
if (web === void 0 || typeof web.register !== "function") return false;
|
|
1541
1574
|
ctx.effect(() => web.register({
|
|
@@ -1560,6 +1593,47 @@ function registerBrowserSurfaceRoute(ctx, registry) {
|
|
|
1560
1593
|
response.end();
|
|
1561
1594
|
return;
|
|
1562
1595
|
}
|
|
1596
|
+
if (url.pathname === "/pi2dsh/mcp-state" && (method === "GET" || method === "HEAD")) {
|
|
1597
|
+
if (hooks?.mcpState === void 0) {
|
|
1598
|
+
response.writeHead(404);
|
|
1599
|
+
response.end();
|
|
1600
|
+
return;
|
|
1601
|
+
}
|
|
1602
|
+
const body = JSON.stringify(await hooks.mcpState(url.searchParams.get("session") ?? ""));
|
|
1603
|
+
response.writeHead(200, {
|
|
1604
|
+
"content-type": "application/json; charset=utf-8",
|
|
1605
|
+
"cache-control": "no-store"
|
|
1606
|
+
});
|
|
1607
|
+
response.end(method === "HEAD" ? void 0 : body);
|
|
1608
|
+
return;
|
|
1609
|
+
}
|
|
1610
|
+
if (url.pathname === "/pi2dsh/mcp-action" && method === "POST") {
|
|
1611
|
+
if (hooks?.mcpAction === void 0) {
|
|
1612
|
+
response.writeHead(404);
|
|
1613
|
+
response.end();
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1616
|
+
const chunks = [];
|
|
1617
|
+
const raw = await new Promise((settle) => {
|
|
1618
|
+
const stream = req;
|
|
1619
|
+
stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
1620
|
+
stream.on("end", () => settle(Buffer.concat(chunks).toString("utf8")));
|
|
1621
|
+
});
|
|
1622
|
+
let outcome;
|
|
1623
|
+
try {
|
|
1624
|
+
const payload = JSON.parse(raw || "{}");
|
|
1625
|
+
if (typeof payload.session !== "string" || typeof payload.server !== "string" || typeof payload.disabled !== "boolean") throw new TypeError("mcp-action needs { session, server, disabled }");
|
|
1626
|
+
const scope = payload.scope === "global" ? "global" : "project";
|
|
1627
|
+
outcome = await hooks.mcpAction(payload.session, payload.server, payload.disabled, scope);
|
|
1628
|
+
} catch (error) {
|
|
1629
|
+
response.writeHead(400, { "content-type": "application/json; charset=utf-8" });
|
|
1630
|
+
response.end(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }));
|
|
1631
|
+
return;
|
|
1632
|
+
}
|
|
1633
|
+
response.writeHead(200, { "content-type": "application/json; charset=utf-8" });
|
|
1634
|
+
response.end(JSON.stringify(outcome ?? { ok: true }));
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1563
1637
|
if (method === "POST" && (url.pathname === "/pi2dsh/scene-input" || url.pathname === "/pi2dsh/scene-close")) {
|
|
1564
1638
|
const chunks = [];
|
|
1565
1639
|
const body = await new Promise((settle) => {
|
|
@@ -3112,7 +3186,7 @@ function registerPiProviderRoute(options) {
|
|
|
3112
3186
|
}
|
|
3113
3187
|
//#endregion
|
|
3114
3188
|
//#region src/tui-surfaces.ts
|
|
3115
|
-
function service(ctx, name) {
|
|
3189
|
+
function service$1(ctx, name) {
|
|
3116
3190
|
try {
|
|
3117
3191
|
return ctx.get(name, false);
|
|
3118
3192
|
} catch {
|
|
@@ -3159,6 +3233,8 @@ function preferredWidth(options) {
|
|
|
3159
3233
|
var TuiSurfaceAdapter = class {
|
|
3160
3234
|
packageName;
|
|
3161
3235
|
instanceKey;
|
|
3236
|
+
kind = "tuiScenes";
|
|
3237
|
+
nativeCommands = dshTuiLocalCommands();
|
|
3162
3238
|
sceneId;
|
|
3163
3239
|
scenes;
|
|
3164
3240
|
status;
|
|
@@ -3171,10 +3247,10 @@ var TuiSurfaceAdapter = class {
|
|
|
3171
3247
|
constructor(ctx, packageName, instanceKey) {
|
|
3172
3248
|
this.packageName = packageName;
|
|
3173
3249
|
this.instanceKey = instanceKey;
|
|
3174
|
-
const scenes = service(ctx, "tuiScenes");
|
|
3250
|
+
const scenes = service$1(ctx, "tuiScenes");
|
|
3175
3251
|
if (scenes === void 0) throw new Error("pi2dsh: dsh-TUI scene service is unavailable");
|
|
3176
3252
|
this.scenes = scenes;
|
|
3177
|
-
this.status = service(ctx, "tuiStatus");
|
|
3253
|
+
this.status = service$1(ctx, "tuiStatus");
|
|
3178
3254
|
this.sceneId = sceneIdFor(instanceKey === void 0 ? packageName : `${packageName}-${instanceKey}`);
|
|
3179
3255
|
this.unregisterScene = scenes.register({
|
|
3180
3256
|
id: this.sceneId,
|
|
@@ -3307,7 +3383,7 @@ function mountTuiSurfaceAdapter(ctx, packageName, publish, instanceKey) {
|
|
|
3307
3383
|
publish(void 0);
|
|
3308
3384
|
});
|
|
3309
3385
|
};
|
|
3310
|
-
if (service(ctx, "tuiScenes") !== void 0) {
|
|
3386
|
+
if (service$1(ctx, "tuiScenes") !== void 0) {
|
|
3311
3387
|
attach(ctx);
|
|
3312
3388
|
return;
|
|
3313
3389
|
}
|
|
@@ -3400,8 +3476,252 @@ function dshTuiLocalCommands() {
|
|
|
3400
3476
|
cachedTuiLocalCommands = tuiLocalCommandsForVersion(version);
|
|
3401
3477
|
return cachedTuiLocalCommands;
|
|
3402
3478
|
}
|
|
3403
|
-
|
|
3404
|
-
|
|
3479
|
+
/** Host-native command ownership, independent of the concrete TUI package. */
|
|
3480
|
+
function commandNameForTerminal(name, nativeCommands) {
|
|
3481
|
+
return nativeCommands?.has(name) === true ? `pi-${name}` : name;
|
|
3482
|
+
}
|
|
3483
|
+
/** Bridge fallback commands disappear when the active Host already owns one. */
|
|
3484
|
+
function shouldRegisterCompatibilityCommand(name, nativeCommands) {
|
|
3485
|
+
return nativeCommands?.has(name) !== true;
|
|
3486
|
+
}
|
|
3487
|
+
//#endregion
|
|
3488
|
+
//#region src/pi-component-relay.ts
|
|
3489
|
+
let relaySerial = 0;
|
|
3490
|
+
function relayId() {
|
|
3491
|
+
relaySerial += 1;
|
|
3492
|
+
return `pi2dsh-custom-${relaySerial}`;
|
|
3493
|
+
}
|
|
3494
|
+
/**
|
|
3495
|
+
* One Host-owned Pi component session expressed as data messages.
|
|
3496
|
+
*
|
|
3497
|
+
* The result value never crosses the presentation boundary: Pi's own `done`
|
|
3498
|
+
* callback completes it on the Host. Frames and input are deliberately plain
|
|
3499
|
+
* data so the presentation transport can change independently.
|
|
3500
|
+
*/
|
|
3501
|
+
var PiComponentRelay = class {
|
|
3502
|
+
sessionId = relayId();
|
|
3503
|
+
options;
|
|
3504
|
+
ready;
|
|
3505
|
+
result;
|
|
3506
|
+
component;
|
|
3507
|
+
invalidations = /* @__PURE__ */ new Set();
|
|
3508
|
+
resolveResult;
|
|
3509
|
+
rejectResult;
|
|
3510
|
+
revision = 0;
|
|
3511
|
+
closed = false;
|
|
3512
|
+
constructor(factory, theme, keybindings, options) {
|
|
3513
|
+
this.options = options;
|
|
3514
|
+
this.result = new Promise((resolve, reject) => {
|
|
3515
|
+
this.resolveResult = resolve;
|
|
3516
|
+
this.rejectResult = reject;
|
|
3517
|
+
});
|
|
3518
|
+
const driver = { requestRender: () => this.invalidate() };
|
|
3519
|
+
const done = (value) => this.close(value);
|
|
3520
|
+
this.ready = Promise.resolve().then(() => factory(driver, theme, keybindings, done)).then((component) => {
|
|
3521
|
+
if (this.closed) {
|
|
3522
|
+
component.dispose?.();
|
|
3523
|
+
return false;
|
|
3524
|
+
}
|
|
3525
|
+
if (typeof component?.render !== "function") throw new TypeError("Pi custom component must implement render(width)");
|
|
3526
|
+
this.component = component;
|
|
3527
|
+
this.invalidate();
|
|
3528
|
+
return true;
|
|
3529
|
+
}).catch((error) => {
|
|
3530
|
+
this.fail(error);
|
|
3531
|
+
return false;
|
|
3532
|
+
});
|
|
3533
|
+
}
|
|
3534
|
+
get active() {
|
|
3535
|
+
return !this.closed;
|
|
3536
|
+
}
|
|
3537
|
+
onInvalidate(listener) {
|
|
3538
|
+
this.invalidations.add(listener);
|
|
3539
|
+
return () => this.invalidations.delete(listener);
|
|
3540
|
+
}
|
|
3541
|
+
frame(request) {
|
|
3542
|
+
if (request.sessionId !== this.sessionId) throw new Error("stale Pi component render session");
|
|
3543
|
+
const width = Math.max(1, Math.floor(request.width));
|
|
3544
|
+
return {
|
|
3545
|
+
sessionId: this.sessionId,
|
|
3546
|
+
revision: this.revision,
|
|
3547
|
+
width,
|
|
3548
|
+
lines: this.component?.render(width) ?? []
|
|
3549
|
+
};
|
|
3550
|
+
}
|
|
3551
|
+
input(message) {
|
|
3552
|
+
if (message.sessionId !== this.sessionId || this.closed) return;
|
|
3553
|
+
this.component?.handleInput?.(message.data);
|
|
3554
|
+
}
|
|
3555
|
+
invalidate() {
|
|
3556
|
+
if (this.closed) return;
|
|
3557
|
+
this.revision += 1;
|
|
3558
|
+
for (const listener of this.invalidations) listener(this.revision);
|
|
3559
|
+
}
|
|
3560
|
+
close(value) {
|
|
3561
|
+
if (this.closed) return;
|
|
3562
|
+
this.closed = true;
|
|
3563
|
+
const component = this.component;
|
|
3564
|
+
this.component = void 0;
|
|
3565
|
+
component?.dispose?.();
|
|
3566
|
+
this.invalidations.clear();
|
|
3567
|
+
this.resolveResult(value);
|
|
3568
|
+
}
|
|
3569
|
+
fail(error) {
|
|
3570
|
+
if (this.closed) return;
|
|
3571
|
+
this.closed = true;
|
|
3572
|
+
const component = this.component;
|
|
3573
|
+
this.component = void 0;
|
|
3574
|
+
component?.dispose?.();
|
|
3575
|
+
this.invalidations.clear();
|
|
3576
|
+
this.rejectResult(error);
|
|
3577
|
+
}
|
|
3578
|
+
};
|
|
3579
|
+
//#endregion
|
|
3580
|
+
//#region src/pi-tui-extension-surface.ts
|
|
3581
|
+
function service(ctx) {
|
|
3582
|
+
try {
|
|
3583
|
+
return ctx.get("piTuiExtensions", false);
|
|
3584
|
+
} catch {
|
|
3585
|
+
return;
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
function statusId(packageName, instanceKey, key) {
|
|
3589
|
+
return `pi2dsh-status-${`${packageName}${instanceKey === void 0 ? "" : `-${instanceKey}`}-${key}`.toLowerCase().replace(/[^a-z0-9_-]+/gu, "-").replace(/^-+|-+$/gu, "") || "entry"}`;
|
|
3590
|
+
}
|
|
3591
|
+
function overlayOptions(options) {
|
|
3592
|
+
const raw = typeof options?.overlayOptions === "function" ? options.overlayOptions() : options?.overlayOptions;
|
|
3593
|
+
return raw === void 0 ? void 0 : { ...raw };
|
|
3594
|
+
}
|
|
3595
|
+
/** dsh-pi-tui backend over the public `piTuiExtensions` service. */
|
|
3596
|
+
var PiTuiExtensionSurfaceAdapter = class {
|
|
3597
|
+
extensionService;
|
|
3598
|
+
unstableFacade;
|
|
3599
|
+
packageName;
|
|
3600
|
+
instanceKey;
|
|
3601
|
+
kind = "piTuiExtensions";
|
|
3602
|
+
nativeCommands;
|
|
3603
|
+
statusHandles = /* @__PURE__ */ new Map();
|
|
3604
|
+
mounts = /* @__PURE__ */ new Set();
|
|
3605
|
+
disposed = false;
|
|
3606
|
+
constructor(extensionService, unstableFacade, nativeCommands, packageName, instanceKey) {
|
|
3607
|
+
this.extensionService = extensionService;
|
|
3608
|
+
this.unstableFacade = unstableFacade;
|
|
3609
|
+
this.packageName = packageName;
|
|
3610
|
+
this.instanceKey = instanceKey;
|
|
3611
|
+
this.nativeCommands = new Set(nativeCommands);
|
|
3612
|
+
}
|
|
3613
|
+
get available() {
|
|
3614
|
+
if (this.disposed) return false;
|
|
3615
|
+
try {
|
|
3616
|
+
return this.extensionService.api().capabilities.has("unstable.surface.handle");
|
|
3617
|
+
} catch {
|
|
3618
|
+
return false;
|
|
3619
|
+
}
|
|
3620
|
+
}
|
|
3621
|
+
setStatus(key, text) {
|
|
3622
|
+
if (this.disposed) return;
|
|
3623
|
+
const id = statusId(this.packageName, this.instanceKey, key);
|
|
3624
|
+
const previous = this.statusHandles.get(id);
|
|
3625
|
+
if (text === void 0) {
|
|
3626
|
+
previous?.dispose();
|
|
3627
|
+
this.statusHandles.delete(id);
|
|
3628
|
+
return;
|
|
3629
|
+
}
|
|
3630
|
+
const value = {
|
|
3631
|
+
spans: [{
|
|
3632
|
+
text: String(text),
|
|
3633
|
+
tone: "textDim"
|
|
3634
|
+
}],
|
|
3635
|
+
minWidth: 4,
|
|
3636
|
+
importance: 50
|
|
3637
|
+
};
|
|
3638
|
+
if (previous !== void 0) {
|
|
3639
|
+
previous.replace(value);
|
|
3640
|
+
return;
|
|
3641
|
+
}
|
|
3642
|
+
if (!this.extensionService.api().capabilities.has("slot.chrome.footer.status")) return;
|
|
3643
|
+
this.statusHandles.set(id, this.extensionService.register("chrome.footer.status", {
|
|
3644
|
+
id,
|
|
3645
|
+
order: 500,
|
|
3646
|
+
description: `Pi status ${key} from ${this.packageName}`
|
|
3647
|
+
}, value));
|
|
3648
|
+
}
|
|
3649
|
+
async custom(factory, theme, keybindings, options) {
|
|
3650
|
+
if (!this.available) return void 0;
|
|
3651
|
+
for (const active of [...this.mounts]) active.relay.close(void 0);
|
|
3652
|
+
const relay = new PiComponentRelay(factory, theme, keybindings, options);
|
|
3653
|
+
const record = { relay };
|
|
3654
|
+
this.mounts.add(record);
|
|
3655
|
+
try {
|
|
3656
|
+
if (!await relay.ready || !relay.active) return await relay.result;
|
|
3657
|
+
if (this.disposed) {
|
|
3658
|
+
relay.close(void 0);
|
|
3659
|
+
return await relay.result;
|
|
3660
|
+
}
|
|
3661
|
+
const lease = this.unstableFacade.surface.handle.mountComponent({
|
|
3662
|
+
render: (width) => relay.frame({
|
|
3663
|
+
sessionId: relay.sessionId,
|
|
3664
|
+
width
|
|
3665
|
+
}).lines,
|
|
3666
|
+
handleInput: (data) => relay.input({
|
|
3667
|
+
sessionId: relay.sessionId,
|
|
3668
|
+
data
|
|
3669
|
+
}),
|
|
3670
|
+
dispose: () => relay.close(void 0)
|
|
3671
|
+
}, overlayOptions(options));
|
|
3672
|
+
record.lease = lease;
|
|
3673
|
+
const offInvalidate = relay.onInvalidate(() => lease.invalidate());
|
|
3674
|
+
const release = () => {
|
|
3675
|
+
offInvalidate();
|
|
3676
|
+
lease.close();
|
|
3677
|
+
};
|
|
3678
|
+
relay.result.then(release, release);
|
|
3679
|
+
if (!lease.active) relay.close(void 0);
|
|
3680
|
+
lease.focus();
|
|
3681
|
+
return await relay.result;
|
|
3682
|
+
} catch (error) {
|
|
3683
|
+
relay.fail(error);
|
|
3684
|
+
throw error;
|
|
3685
|
+
} finally {
|
|
3686
|
+
this.mounts.delete(record);
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3689
|
+
dispose() {
|
|
3690
|
+
if (this.disposed) return;
|
|
3691
|
+
this.disposed = true;
|
|
3692
|
+
for (const handle of this.statusHandles.values()) handle.dispose();
|
|
3693
|
+
this.statusHandles.clear();
|
|
3694
|
+
for (const active of this.mounts) {
|
|
3695
|
+
active.relay.close(void 0);
|
|
3696
|
+
active.lease?.close();
|
|
3697
|
+
}
|
|
3698
|
+
this.mounts.clear();
|
|
3699
|
+
}
|
|
3700
|
+
};
|
|
3701
|
+
/**
|
|
3702
|
+
* Build the optional backend from published public entry points.
|
|
3703
|
+
* Returns undefined when the service is absent or cannot provide the exact
|
|
3704
|
+
* raw-component capability; callers then keep the existing dsh-TUI/Web path.
|
|
3705
|
+
*/
|
|
3706
|
+
async function createPiTuiExtensionSurfaceAdapter(ctx, packageName, instanceKey) {
|
|
3707
|
+
const extensionService = service(ctx);
|
|
3708
|
+
if (extensionService === void 0) return void 0;
|
|
3709
|
+
const api = extensionService.api();
|
|
3710
|
+
if (api.apiVersion !== 1 || !api.capabilities.has("unstable.surface.handle")) {
|
|
3711
|
+
ctx.logger?.warn(`pi2dsh: piTuiExtensions cannot host Pi components (api=${api.apiVersion}, raw surface=${api.capabilities.has("unstable.surface.handle")})`);
|
|
3712
|
+
return;
|
|
3713
|
+
}
|
|
3714
|
+
try {
|
|
3715
|
+
const [hostModule, unstableModule] = await Promise.all([import("@xmoon76/dsh-pi-tui"), import("@xmoon76/dsh-pi-tui/extensions/unstable")]);
|
|
3716
|
+
if (unstableModule.UNSTABLE_API_LEVEL !== 1) {
|
|
3717
|
+
ctx.logger?.warn(`pi2dsh: unsupported dsh-pi-tui unstable API level ${unstableModule.UNSTABLE_API_LEVEL}`);
|
|
3718
|
+
return;
|
|
3719
|
+
}
|
|
3720
|
+
return new PiTuiExtensionSurfaceAdapter(extensionService, unstableModule.unstable(extensionService), hostModule.LOCAL_COMMANDS, packageName, instanceKey);
|
|
3721
|
+
} catch (error) {
|
|
3722
|
+
ctx.logger?.warn(`pi2dsh: could not attach the public piTuiExtensions backend: ${error instanceof Error ? error.message : String(error)}`);
|
|
3723
|
+
return;
|
|
3724
|
+
}
|
|
3405
3725
|
}
|
|
3406
3726
|
//#endregion
|
|
3407
3727
|
//#region src/runtime.ts
|
|
@@ -4120,7 +4440,8 @@ function contextFor(ctx, state, agent, signal, command = false, sessionOverride)
|
|
|
4120
4440
|
},
|
|
4121
4441
|
ui,
|
|
4122
4442
|
get mode() {
|
|
4123
|
-
|
|
4443
|
+
if (state.tuiSurfaces?.available === true) return "tui";
|
|
4444
|
+
return state.shared.browserSurfaces !== void 0 && state.shared.browserSurfacesRouted === true ? "tui" : "rpc";
|
|
4124
4445
|
},
|
|
4125
4446
|
get hasUI() {
|
|
4126
4447
|
return state.tuiSurfaces?.available === true || humanAnswererAvailable(userQuestions, agent);
|
|
@@ -5234,6 +5555,59 @@ function oauthStoreOf(state) {
|
|
|
5234
5555
|
}
|
|
5235
5556
|
const COMPANION_ROUTE_PREFIX = "pi2dsh-companion/";
|
|
5236
5557
|
const SHARED_HOST_STATE = /* @__PURE__ */ new WeakMap();
|
|
5558
|
+
function registerChildExtensionCatalog(ctx, catalog) {
|
|
5559
|
+
sharedHostStateOf(ctx).childExtensions = catalog;
|
|
5560
|
+
}
|
|
5561
|
+
/** Read the installed-package catalog registered on shared host state, or undefined. */
|
|
5562
|
+
function getSharedChildExtensionCatalog(ctx) {
|
|
5563
|
+
return sharedHostStateOf(ctx).childExtensions;
|
|
5564
|
+
}
|
|
5565
|
+
/**
|
|
5566
|
+
* Which installed packages a creator's resource loader selects for its child
|
|
5567
|
+
* — the creator's OWN filter code decides (the loader's getExtensions applies
|
|
5568
|
+
* noExtensions and extensionsOverride), this only maps the surviving entry
|
|
5569
|
+
* paths back to package names. No loader at all means Pi's default: the full
|
|
5570
|
+
* discovered set (sdk.ts builds a default loader and loads everything).
|
|
5571
|
+
*/
|
|
5572
|
+
function resolveChildExtensionPackages(loader, catalog) {
|
|
5573
|
+
if (loader === void 0 || loader === null) return {
|
|
5574
|
+
names: [...new Set(catalog.packageByEntryPath.values())],
|
|
5575
|
+
failures: []
|
|
5576
|
+
};
|
|
5577
|
+
const getExtensions = loader.getExtensions;
|
|
5578
|
+
if (typeof getExtensions !== "function") return {
|
|
5579
|
+
names: [],
|
|
5580
|
+
failures: []
|
|
5581
|
+
};
|
|
5582
|
+
const names = /* @__PURE__ */ new Set();
|
|
5583
|
+
const failures = [];
|
|
5584
|
+
let entries;
|
|
5585
|
+
try {
|
|
5586
|
+
entries = getExtensions.call(loader)?.extensions ?? [];
|
|
5587
|
+
} catch (error) {
|
|
5588
|
+
return {
|
|
5589
|
+
names: [],
|
|
5590
|
+
failures: [{
|
|
5591
|
+
name: "resourceLoader.getExtensions",
|
|
5592
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5593
|
+
}]
|
|
5594
|
+
};
|
|
5595
|
+
}
|
|
5596
|
+
for (const entry of entries) {
|
|
5597
|
+
const path = entry?.path;
|
|
5598
|
+
if (typeof path !== "string" || path.length === 0) continue;
|
|
5599
|
+
const name = catalog.packageByEntryPath.get(resolve(path));
|
|
5600
|
+
if (name !== void 0) names.add(name);
|
|
5601
|
+
else failures.push({
|
|
5602
|
+
name: path,
|
|
5603
|
+
error: "not an installed DSH plugin — path-loaded extensions are not supported on this host; install it with `dsh plugin add <pkg>`"
|
|
5604
|
+
});
|
|
5605
|
+
}
|
|
5606
|
+
return {
|
|
5607
|
+
names: [...names],
|
|
5608
|
+
failures
|
|
5609
|
+
};
|
|
5610
|
+
}
|
|
5237
5611
|
/**
|
|
5238
5612
|
* Pi's provider ledger is layered, not flat (model-runtime.ts:742-786 at the
|
|
5239
5613
|
* pinned upstream): a builtin base map, an extension overlay where defined
|
|
@@ -5494,6 +5868,10 @@ async function materializeAttachmentImage(ctx, attachment) {
|
|
|
5494
5868
|
}
|
|
5495
5869
|
}
|
|
5496
5870
|
function ensureLoginCommand(ctx, state) {
|
|
5871
|
+
if (!shouldRegisterCompatibilityCommand("login", state.tuiSurfaces?.nativeCommands) && optionalService(ctx, "authorization") !== void 0) {
|
|
5872
|
+
logger(ctx).debug("[pi2dsh] native terminal owns /login and the authorization service is composed; Pi OAuth flows are available through it");
|
|
5873
|
+
return;
|
|
5874
|
+
}
|
|
5497
5875
|
const scoped = scopeOf(ctx);
|
|
5498
5876
|
const owner = typeof scoped === "object" && scoped !== null ? scoped : ctx;
|
|
5499
5877
|
const registered = state.shared.loginRegistered ??= /* @__PURE__ */ new WeakSet();
|
|
@@ -6279,9 +6657,9 @@ function normalizedPiCommandName(piName) {
|
|
|
6279
6657
|
}
|
|
6280
6658
|
function dshCommandName(ctx, state, piName) {
|
|
6281
6659
|
const validName = normalizedPiCommandName(piName);
|
|
6282
|
-
const name =
|
|
6660
|
+
const name = commandNameForTerminal(validName, state.tuiSurfaces?.nativeCommands);
|
|
6283
6661
|
if (name !== piName) {
|
|
6284
|
-
const reason = name === `pi-${validName}` ? `because
|
|
6662
|
+
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
6663
|
logger(ctx).warn(`[pi2dsh] Pi command /${piName} registered as /${name} ${reason}`);
|
|
6286
6664
|
}
|
|
6287
6665
|
return name;
|
|
@@ -6767,6 +7145,12 @@ async function applyPiPackage(ctx, options) {
|
|
|
6767
7145
|
const shared = sharedHostStateOf(ctx);
|
|
6768
7146
|
const scopedOwner = options.ownerAgent ?? scopeOf(ctx);
|
|
6769
7147
|
const ownerAgent = typeof scopedOwner === "object" && scopedOwner !== null ? scopedOwner : void 0;
|
|
7148
|
+
if (ownerAgent !== void 0 && options.hostAnchor !== true) {
|
|
7149
|
+
shared.childPackageTools ??= /* @__PURE__ */ new WeakMap();
|
|
7150
|
+
const byPackage = shared.childPackageTools.get(ownerAgent) ?? /* @__PURE__ */ new Map();
|
|
7151
|
+
byPackage.set(options.manifest.package.name, runtimeTools);
|
|
7152
|
+
shared.childPackageTools.set(ownerAgent, byPackage);
|
|
7153
|
+
}
|
|
6770
7154
|
const state = {
|
|
6771
7155
|
shared,
|
|
6772
7156
|
packageName: options.manifest.package.name,
|
|
@@ -6829,9 +7213,17 @@ async function applyPiPackage(ctx, options) {
|
|
|
6829
7213
|
publishedOAuthKeys: shared.publishedOAuthKeys,
|
|
6830
7214
|
tuiSurfaces: void 0
|
|
6831
7215
|
};
|
|
6832
|
-
|
|
7216
|
+
const surfaceInstanceKey = typeof ownerAgent?.id === "string" ? ownerAgent.id : void 0;
|
|
7217
|
+
const piTuiSurface = await createPiTuiExtensionSurfaceAdapter(ctx, state.packageName, surfaceInstanceKey);
|
|
7218
|
+
if (piTuiSurface !== void 0) {
|
|
7219
|
+
state.tuiSurfaces = piTuiSurface;
|
|
7220
|
+
ctx.effect(() => () => {
|
|
7221
|
+
piTuiSurface.dispose();
|
|
7222
|
+
if (state.tuiSurfaces === piTuiSurface) state.tuiSurfaces = void 0;
|
|
7223
|
+
});
|
|
7224
|
+
} else mountTuiSurfaceAdapter(ctx, state.packageName, (adapter) => {
|
|
6833
7225
|
state.tuiSurfaces = adapter;
|
|
6834
|
-
},
|
|
7226
|
+
}, surfaceInstanceKey);
|
|
6835
7227
|
subscribeLifecycle(ctx, state);
|
|
6836
7228
|
subscribeInterceptors(ctx, state);
|
|
6837
7229
|
shared.providerBuiltins ??= /* @__PURE__ */ new Map();
|
|
@@ -6885,7 +7277,57 @@ async function applyPiPackage(ctx, options) {
|
|
|
6885
7277
|
});
|
|
6886
7278
|
}
|
|
6887
7279
|
const browserSurfaces = state.shared.browserSurfaces ??= new BrowserSurfaces();
|
|
6888
|
-
if (state.shared.browserSurfacesRouted !== true)
|
|
7280
|
+
if (state.shared.browserSurfacesRouted !== true) {
|
|
7281
|
+
const sessionCwd = (session) => {
|
|
7282
|
+
const cwd = ctx.get("sessions")?.get?.(session)?.header?.cwd;
|
|
7283
|
+
if (typeof cwd === "string" && cwd.length > 0) return cwd;
|
|
7284
|
+
return session === "" ? homedir() : process.cwd();
|
|
7285
|
+
};
|
|
7286
|
+
const globalLayerPaths = (cwd) => new Set(piMcpConfigPaths(cwd).slice(0, 4));
|
|
7287
|
+
state.shared.browserSurfacesRouted = registerBrowserSurfaceRoute(ctx, browserSurfaces, {
|
|
7288
|
+
async mcpState(session) {
|
|
7289
|
+
const cwd = sessionCwd(session);
|
|
7290
|
+
const globals = globalLayerPaths(cwd);
|
|
7291
|
+
const { servers, sources } = collectPiMcpServers(cwd);
|
|
7292
|
+
return {
|
|
7293
|
+
cwd,
|
|
7294
|
+
sources,
|
|
7295
|
+
servers: [...servers.values()].map((server) => ({
|
|
7296
|
+
name: server.name,
|
|
7297
|
+
transport: server.transport,
|
|
7298
|
+
target: server.transport === "stdio" ? [server.command, ...server.args ?? []].filter(Boolean).join(" ") : server.url ?? "",
|
|
7299
|
+
disabled: server.disabled,
|
|
7300
|
+
sourcePath: server.sourcePath,
|
|
7301
|
+
layer: globals.has(server.sourcePath) ? "global" : "project",
|
|
7302
|
+
envKeys: Object.keys(server.env ?? {}),
|
|
7303
|
+
headerKeys: Object.keys(server.headers ?? {})
|
|
7304
|
+
}))
|
|
7305
|
+
};
|
|
7306
|
+
},
|
|
7307
|
+
async mcpAction(session, server, disabled, scope) {
|
|
7308
|
+
const cwd = sessionCwd(session);
|
|
7309
|
+
const { servers } = collectPiMcpServers(cwd);
|
|
7310
|
+
if (!servers.has(server)) throw new TypeError(`unknown MCP server ${JSON.stringify(server)}`);
|
|
7311
|
+
const overridePath = scope === "global" ? [...globalLayerPaths(cwd)][3] : join(cwd, ".pi", "mcp.json");
|
|
7312
|
+
let current = {};
|
|
7313
|
+
try {
|
|
7314
|
+
current = JSON.parse(await readFile(overridePath, "utf8"));
|
|
7315
|
+
} catch {}
|
|
7316
|
+
const mcpServers = typeof current.mcpServers === "object" && current.mcpServers !== null ? current.mcpServers : {};
|
|
7317
|
+
mcpServers[server] = {
|
|
7318
|
+
...typeof mcpServers[server] === "object" && mcpServers[server] !== null ? mcpServers[server] : {},
|
|
7319
|
+
disabled
|
|
7320
|
+
};
|
|
7321
|
+
current.mcpServers = mcpServers;
|
|
7322
|
+
await mkdir(dirname(overridePath), { recursive: true });
|
|
7323
|
+
await writeFile(overridePath, `${JSON.stringify(current, null, 2)}\n`);
|
|
7324
|
+
return {
|
|
7325
|
+
ok: true,
|
|
7326
|
+
note: "run /reload (or restart the session) to apply"
|
|
7327
|
+
};
|
|
7328
|
+
}
|
|
7329
|
+
});
|
|
7330
|
+
}
|
|
6889
7331
|
ctx.effect(() => browserSurfaces.trackCompletions(state.packageName ?? "pi", async (trigger, query) => {
|
|
6890
7332
|
if (state.autocompleteProviders.length === 0) return [];
|
|
6891
7333
|
let provider = { getSuggestions: async () => null };
|
|
@@ -6995,6 +7437,21 @@ async function applyPiPackage(ctx, options) {
|
|
|
6995
7437
|
return state.bridge.readonlySessionManager(session, cwd);
|
|
6996
7438
|
},
|
|
6997
7439
|
resumeSessionIdFor: (file) => state.bridge.sessionIdOfArchiveFile(file),
|
|
7440
|
+
mountChildExtensions: async (childAgent, loader) => {
|
|
7441
|
+
const shared = sharedHostStateOf(ctx);
|
|
7442
|
+
const catalog = shared.childExtensions;
|
|
7443
|
+
if (catalog === void 0) return [];
|
|
7444
|
+
const { names, failures } = resolveChildExtensionPackages(loader, catalog);
|
|
7445
|
+
if (names.length === 0) return failures;
|
|
7446
|
+
const mountFailures = await catalog.mount(childAgent, names);
|
|
7447
|
+
const attachable = loader;
|
|
7448
|
+
if (typeof attachable?.attachChildToolResolver === "function") attachable.attachChildToolResolver((path) => {
|
|
7449
|
+
const packageName = catalog.packageByEntryPath.get(resolve(path));
|
|
7450
|
+
if (packageName === void 0) return void 0;
|
|
7451
|
+
return shared.childPackageTools?.get(childAgent)?.get(packageName);
|
|
7452
|
+
});
|
|
7453
|
+
return [...failures, ...mountFailures];
|
|
7454
|
+
},
|
|
6998
7455
|
sessionGoneFromPersistence: async (sessionId) => {
|
|
6999
7456
|
const persistence = optionalService(ctx, "sessionPersistence");
|
|
7000
7457
|
if (typeof persistence?.list !== "function") return void 0;
|
|
@@ -7063,6 +7520,7 @@ const runtimeInternals = {
|
|
|
7063
7520
|
currentPiModel,
|
|
7064
7521
|
lastRequestRouteOf,
|
|
7065
7522
|
resolveCallerRoute,
|
|
7523
|
+
resolveChildExtensionPackages,
|
|
7066
7524
|
dshToPiContent,
|
|
7067
7525
|
expandPrompt,
|
|
7068
7526
|
isKnownImageTool,
|
|
@@ -7073,6 +7531,6 @@ const runtimeInternals = {
|
|
|
7073
7531
|
textBlocks
|
|
7074
7532
|
};
|
|
7075
7533
|
//#endregion
|
|
7076
|
-
export {
|
|
7534
|
+
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
7535
|
|
|
7078
|
-
//# sourceMappingURL=runtime-
|
|
7536
|
+
//# sourceMappingURL=runtime-CBZcd1uU.mjs.map
|