pi2dsh 0.9.0 → 0.10.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 +4 -1
- package/README.zh.md +4 -1
- package/dist/{analyzer-C86ba-27.mjs → analyzer-CsrBeS8r.mjs} +2 -2
- package/dist/{analyzer-C86ba-27.mjs.map → analyzer-CsrBeS8r.mjs.map} +1 -1
- package/dist/cli.mjs +3 -3
- package/dist/compat/pi-ai.d.mts +2 -1
- package/dist/compat/pi-ai.d.mts.map +1 -1
- package/dist/compat/pi-ai.mjs +2 -3
- package/dist/compat/pi-coding-agent.d.mts +259 -29
- package/dist/compat/pi-coding-agent.d.mts.map +1 -1
- package/dist/compat/pi-coding-agent.mjs +2 -2
- package/dist/credentials-oauth.mjs +2 -2
- package/dist/{generator-C0jNM-yu.mjs → generator-CSOv6wYT.mjs} +2 -2
- package/dist/{generator-C0jNM-yu.mjs.map → generator-CSOv6wYT.mjs.map} +1 -1
- package/dist/host.mjs +1 -1
- package/dist/index.mjs +4 -4
- package/dist/{mcp-config-Dlou-ZA-.mjs → mcp-config-Cn5gWemZ.mjs} +29 -29
- package/dist/mcp-config-Cn5gWemZ.mjs.map +1 -0
- package/dist/{pi-ai-BA3h0Dwv.mjs → pi-ai-Dyg4zyLZ.mjs} +196 -75
- package/dist/pi-ai-Dyg4zyLZ.mjs.map +1 -0
- package/dist/{pi-coding-agent-CznNsOnV.mjs → pi-coding-agent-Ctw-BhoY.mjs} +0 -0
- package/dist/pi-coding-agent-Ctw-BhoY.mjs.map +1 -0
- package/dist/{runtime-DMEJknhK.mjs → runtime-Ce3PTbWU.mjs} +417 -135
- package/dist/runtime-Ce3PTbWU.mjs.map +1 -0
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +1 -1
- package/package.json +5 -3
- package/dist/mcp-config-Dlou-ZA-.mjs.map +0 -1
- package/dist/pi-ai-BA3h0Dwv.mjs.map +0 -1
- package/dist/pi-coding-agent-CznNsOnV.mjs.map +0 -1
- package/dist/pi-uuid-Db8ShZsK.mjs +0 -47
- package/dist/pi-uuid-Db8ShZsK.mjs.map +0 -1
- package/dist/runtime-DMEJknhK.mjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
2
|
+
import { F as AssistantMessageEventStream, a as builtinProviders, i as __setPiAiLlmBridge } from "./pi-ai-Dyg4zyLZ.mjs";
|
|
3
|
+
import { P as generateBranchSummary, Tn as PiCapabilityError, b as Theme, d as ExtensionRunner, w as __setSubagentSessionFactory, wn as CapabilityLedger } from "./pi-coding-agent-Ctw-BhoY.mjs";
|
|
3
4
|
import { t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
|
|
4
|
-
import { E as __setSubagentSessionFactory, S as Theme, f as ExtensionRunner } from "./pi-coding-agent-CznNsOnV.mjs";
|
|
5
5
|
import { a as resolvePiProviderAuth, n as loginPiProvider, r as providerSupportsOAuth, t as FileCredentialStore } from "./oauth-bridge-CfyImWx4.mjs";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
@@ -94,6 +94,17 @@ var PiSessionBridge = class {
|
|
|
94
94
|
});
|
|
95
95
|
return id;
|
|
96
96
|
}
|
|
97
|
+
appendBranchSummary(sessionId, summary, fromId) {
|
|
98
|
+
const id = randomUUID();
|
|
99
|
+
this.persist(sessionId, {
|
|
100
|
+
kind: "branch_summary",
|
|
101
|
+
id,
|
|
102
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
103
|
+
summary,
|
|
104
|
+
fromId
|
|
105
|
+
});
|
|
106
|
+
return id;
|
|
107
|
+
}
|
|
97
108
|
appendLabel(sessionId, targetId, label) {
|
|
98
109
|
this.persist(sessionId, {
|
|
99
110
|
kind: "label",
|
|
@@ -197,6 +208,16 @@ var PiSessionBridge = class {
|
|
|
197
208
|
...record.data === void 0 ? {} : { data: record.data }
|
|
198
209
|
}
|
|
199
210
|
});
|
|
211
|
+
else if (record.kind === "branch_summary") merged.push({
|
|
212
|
+
time,
|
|
213
|
+
entry: {
|
|
214
|
+
type: "branch_summary",
|
|
215
|
+
id: record.id,
|
|
216
|
+
timestamp: record.timestamp,
|
|
217
|
+
summary: record.summary,
|
|
218
|
+
fromId: record.fromId
|
|
219
|
+
}
|
|
220
|
+
});
|
|
200
221
|
else if (record.kind === "label") merged.push({
|
|
201
222
|
time,
|
|
202
223
|
entry: {
|
|
@@ -1493,6 +1514,11 @@ function cwdOf(agent) {
|
|
|
1493
1514
|
function unsupported(name) {
|
|
1494
1515
|
throw new Error(`pi2dsh: Pi API ${name} requires a native DSH port; inspect the compatibility report`);
|
|
1495
1516
|
}
|
|
1517
|
+
function capabilityLedgerOf(ctx, state) {
|
|
1518
|
+
const shared = state.shared;
|
|
1519
|
+
if (shared.capabilityLedger === void 0) shared.capabilityLedger = new CapabilityLedger((message) => logger(ctx).warn(message));
|
|
1520
|
+
return shared.capabilityLedger;
|
|
1521
|
+
}
|
|
1496
1522
|
function optionalService(ctx, name) {
|
|
1497
1523
|
return ctx.get(name);
|
|
1498
1524
|
}
|
|
@@ -1551,7 +1577,45 @@ function thinkingLevelOf(state, agent) {
|
|
|
1551
1577
|
}
|
|
1552
1578
|
return state.globalThinkingLevel;
|
|
1553
1579
|
}
|
|
1554
|
-
function
|
|
1580
|
+
function durableSeqOf(entryId) {
|
|
1581
|
+
const match = /^dsh-(\d+)$/.exec(entryId);
|
|
1582
|
+
return match === null ? void 0 : Number(match[1]);
|
|
1583
|
+
}
|
|
1584
|
+
function shrinkToTurnBoundary(events, boundary) {
|
|
1585
|
+
const slice = events.slice(0, boundary + 1);
|
|
1586
|
+
for (let i = slice.length - 1; i >= 0; i--) {
|
|
1587
|
+
const type = slice[i]?.type;
|
|
1588
|
+
if (type === "turn/end") return boundary;
|
|
1589
|
+
if (type === "turn/start") return Number(slice[i].seq) - 1;
|
|
1590
|
+
}
|
|
1591
|
+
return boundary;
|
|
1592
|
+
}
|
|
1593
|
+
async function summarizeAbandonedBranch(ctx, state, agent, events, boundary, options) {
|
|
1594
|
+
const abandoned = events.slice(boundary + 1);
|
|
1595
|
+
if (abandoned.length === 0) return void 0;
|
|
1596
|
+
const model = agent === void 0 ? void 0 : currentPiModel(state, agent);
|
|
1597
|
+
if (model === void 0) {
|
|
1598
|
+
logger(ctx).warn("[pi2dsh] ctx.navigateTree: no current model route, navigating without a branch summary");
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
const entries = state.bridge.readonlySessionManager({
|
|
1602
|
+
id: "pi2dsh-abandoned-branch",
|
|
1603
|
+
events: abandoned
|
|
1604
|
+
}, cwdOf(agent)).getEntries?.() ?? [];
|
|
1605
|
+
if (entries.length === 0) return void 0;
|
|
1606
|
+
const result = await generateBranchSummary(entries, {
|
|
1607
|
+
model,
|
|
1608
|
+
signal: new AbortController().signal,
|
|
1609
|
+
...typeof options.customInstructions === "string" ? { customInstructions: options.customInstructions } : {},
|
|
1610
|
+
...options.replaceInstructions === true ? { replaceInstructions: true } : {}
|
|
1611
|
+
});
|
|
1612
|
+
if (result.error !== void 0) {
|
|
1613
|
+
logger(ctx).warn(`[pi2dsh] ctx.navigateTree: branch summarization failed (${result.error}), navigating without a summary`);
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1616
|
+
return result.summary;
|
|
1617
|
+
}
|
|
1618
|
+
function contextFor(ctx, state, agent, signal, command = false, sessionOverride) {
|
|
1555
1619
|
const notices = [];
|
|
1556
1620
|
const userQuestions = optionalService(ctx, "userQuestions");
|
|
1557
1621
|
const ui = {
|
|
@@ -1626,7 +1690,7 @@ function contextFor(ctx, state, agent, signal, command = false) {
|
|
|
1626
1690
|
state.toolsExpanded = expanded === true;
|
|
1627
1691
|
}
|
|
1628
1692
|
};
|
|
1629
|
-
const session = agentSession(agent);
|
|
1693
|
+
const session = sessionOverride ?? agentSession(agent);
|
|
1630
1694
|
const providerConfig = (name) => state.providers.get(name);
|
|
1631
1695
|
const catalog = state.modelCatalog;
|
|
1632
1696
|
const piNativeEntry = (provider, id) => {
|
|
@@ -1666,119 +1730,121 @@ function contextFor(ctx, state, agent, signal, command = false) {
|
|
|
1666
1730
|
stream: dshRoutedStream,
|
|
1667
1731
|
streamSimple: dshRoutedStream
|
|
1668
1732
|
});
|
|
1669
|
-
const
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
const provider = String(model?.provider ?? "");
|
|
1688
|
-
if (provider.length === 0) return false;
|
|
1689
|
-
return state.providers.has(provider) || (catalog?.all() ?? []).some((entry) => entry.provider === provider);
|
|
1690
|
-
},
|
|
1691
|
-
getApiKeyAndHeaders: async (model) => {
|
|
1692
|
-
const provider = String(model?.provider ?? "");
|
|
1693
|
-
const config = providerConfig(provider);
|
|
1694
|
-
if (config !== void 0) {
|
|
1695
|
-
const auth = (await resolvePiProviderAuth({
|
|
1696
|
-
providerId: provider,
|
|
1697
|
-
providerConfig: config,
|
|
1698
|
-
store: oauthStoreOf(state)
|
|
1699
|
-
}))?.auth;
|
|
1700
|
-
if (auth?.apiKey === void 0) return { ok: false };
|
|
1701
|
-
return {
|
|
1702
|
-
ok: true,
|
|
1703
|
-
apiKey: auth.apiKey,
|
|
1704
|
-
...auth.headers === void 0 ? {} : { headers: auth.headers },
|
|
1705
|
-
...auth.baseUrl === void 0 && config.baseUrl === void 0 ? {} : { baseUrl: auth.baseUrl ?? config.baseUrl }
|
|
1706
|
-
};
|
|
1707
|
-
}
|
|
1708
|
-
try {
|
|
1709
|
-
const entry = llmOf(ctx)?.listConfigurableProviders?.()?.find((candidate) => candidate.provider === provider);
|
|
1710
|
-
if (entry === void 0) return { ok: false };
|
|
1711
|
-
const section = ctx.get("settings")?.get(entry.settingsNs);
|
|
1712
|
-
const ref = entry.settingsPath.reduce((node, key) => typeof node === "object" && node !== null ? node[key] : void 0, section)?.apiKeyEnv;
|
|
1713
|
-
if (typeof ref !== "string" || ref.length === 0) return { ok: false };
|
|
1714
|
-
const resolved = await ctx.get("credentials")?.resolve(ref);
|
|
1715
|
-
if (typeof resolved?.value !== "string" || resolved.value.length === 0) return { ok: false };
|
|
1716
|
-
return {
|
|
1717
|
-
ok: true,
|
|
1718
|
-
apiKey: resolved.value
|
|
1719
|
-
};
|
|
1720
|
-
} catch {
|
|
1721
|
-
return { ok: false };
|
|
1722
|
-
}
|
|
1723
|
-
},
|
|
1724
|
-
getProviderAuthStatus: (provider) => providerSupportsOAuth(providerConfig(provider)) ? "oauth" : "none",
|
|
1725
|
-
getProvider: (provider) => {
|
|
1726
|
-
const base = providerConfig(provider);
|
|
1727
|
-
if (base !== void 0) return state.providerRouteDisposers.has(provider) ? dshRoutedPiProvider(base, provider) : base;
|
|
1728
|
-
if ((catalog?.all() ?? []).some((entry) => entry.provider === provider)) return dshRoutedPiProvider({
|
|
1729
|
-
id: provider,
|
|
1730
|
-
name: provider
|
|
1731
|
-
}, provider);
|
|
1732
|
-
},
|
|
1733
|
-
complete: async (model, context, options) => {
|
|
1734
|
-
const result = await dshRoutedStream(model, context ?? {}, options).result();
|
|
1735
|
-
if (result instanceof Error) throw result;
|
|
1736
|
-
return result;
|
|
1737
|
-
},
|
|
1738
|
-
getRegisteredProviderConfig: (provider) => providerConfig(provider),
|
|
1739
|
-
getRegisteredProviderIds: () => [...state.providers.keys()],
|
|
1740
|
-
getProviderDisplayName: (provider) => {
|
|
1741
|
-
const config = providerConfig(provider);
|
|
1742
|
-
return typeof config?.name === "string" ? config.name : provider;
|
|
1743
|
-
},
|
|
1744
|
-
getProviderAuth: async (provider) => {
|
|
1745
|
-
const config = providerConfig(provider);
|
|
1746
|
-
if (config === void 0) return void 0;
|
|
1747
|
-
const resolved = await resolvePiProviderAuth({
|
|
1748
|
-
providerId: provider,
|
|
1749
|
-
providerConfig: config,
|
|
1750
|
-
store: oauthStoreOf(state)
|
|
1751
|
-
});
|
|
1752
|
-
if (resolved?.auth === void 0) return resolved;
|
|
1753
|
-
return resolved.auth.baseUrl === void 0 && config.baseUrl !== void 0 ? {
|
|
1754
|
-
...resolved,
|
|
1755
|
-
auth: {
|
|
1756
|
-
...resolved.auth,
|
|
1757
|
-
baseUrl: config.baseUrl
|
|
1758
|
-
}
|
|
1759
|
-
} : resolved;
|
|
1760
|
-
},
|
|
1761
|
-
getApiKeyForProvider: async (provider) => {
|
|
1762
|
-
const config = providerConfig(provider);
|
|
1763
|
-
if (config === void 0) return void 0;
|
|
1764
|
-
return ((await resolvePiProviderAuth({
|
|
1733
|
+
const modelRegistry = {
|
|
1734
|
+
getAll: () => allModels(),
|
|
1735
|
+
getAvailable: () => allModels(),
|
|
1736
|
+
find: (provider, modelId) => {
|
|
1737
|
+
const entry = catalog?.find(provider, modelId);
|
|
1738
|
+
return entry === void 0 ? void 0 : restorePiShape(entry);
|
|
1739
|
+
},
|
|
1740
|
+
getError: () => void 0,
|
|
1741
|
+
hasConfiguredAuth: (model) => {
|
|
1742
|
+
const provider = String(model?.provider ?? "");
|
|
1743
|
+
if (provider.length === 0) return false;
|
|
1744
|
+
return state.providers.has(provider) || (catalog?.all() ?? []).some((entry) => entry.provider === provider);
|
|
1745
|
+
},
|
|
1746
|
+
getApiKeyAndHeaders: async (model) => {
|
|
1747
|
+
const provider = String(model?.provider ?? "");
|
|
1748
|
+
const config = providerConfig(provider);
|
|
1749
|
+
if (config !== void 0) {
|
|
1750
|
+
const auth = (await resolvePiProviderAuth({
|
|
1765
1751
|
providerId: provider,
|
|
1766
1752
|
providerConfig: config,
|
|
1767
1753
|
store: oauthStoreOf(state)
|
|
1768
|
-
}))?.auth
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1754
|
+
}))?.auth;
|
|
1755
|
+
if (auth?.apiKey === void 0) return { ok: false };
|
|
1756
|
+
return {
|
|
1757
|
+
ok: true,
|
|
1758
|
+
apiKey: auth.apiKey,
|
|
1759
|
+
...auth.headers === void 0 ? {} : { headers: auth.headers },
|
|
1760
|
+
...auth.baseUrl === void 0 && config.baseUrl === void 0 ? {} : { baseUrl: auth.baseUrl ?? config.baseUrl }
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
try {
|
|
1764
|
+
const entry = llmOf(ctx)?.listConfigurableProviders?.()?.find((candidate) => candidate.provider === provider);
|
|
1765
|
+
if (entry === void 0) return { ok: false };
|
|
1766
|
+
const section = ctx.get("settings")?.get(entry.settingsNs);
|
|
1767
|
+
const ref = entry.settingsPath.reduce((node, key) => typeof node === "object" && node !== null ? node[key] : void 0, section)?.apiKeyEnv;
|
|
1768
|
+
if (typeof ref !== "string" || ref.length === 0) return { ok: false };
|
|
1769
|
+
const resolved = await ctx.get("credentials")?.resolve(ref);
|
|
1770
|
+
if (typeof resolved?.value !== "string" || resolved.value.length === 0) return { ok: false };
|
|
1776
1771
|
return {
|
|
1777
|
-
|
|
1778
|
-
|
|
1772
|
+
ok: true,
|
|
1773
|
+
apiKey: resolved.value
|
|
1779
1774
|
};
|
|
1775
|
+
} catch {
|
|
1776
|
+
return { ok: false };
|
|
1780
1777
|
}
|
|
1781
1778
|
},
|
|
1779
|
+
getProviderAuthStatus: (provider) => providerSupportsOAuth(providerConfig(provider)) ? "oauth" : "none",
|
|
1780
|
+
getProvider: (provider) => {
|
|
1781
|
+
const base = providerConfig(provider);
|
|
1782
|
+
if (base !== void 0) return state.providerRouteDisposers.has(provider) ? dshRoutedPiProvider(base, provider) : base;
|
|
1783
|
+
if ((catalog?.all() ?? []).some((entry) => entry.provider === provider)) return dshRoutedPiProvider({
|
|
1784
|
+
id: provider,
|
|
1785
|
+
name: provider
|
|
1786
|
+
}, provider);
|
|
1787
|
+
},
|
|
1788
|
+
complete: async (model, context, options) => {
|
|
1789
|
+
const result = await dshRoutedStream(model, context ?? {}, options).result();
|
|
1790
|
+
if (result instanceof Error) throw result;
|
|
1791
|
+
return result;
|
|
1792
|
+
},
|
|
1793
|
+
getRegisteredProviderConfig: (provider) => providerConfig(provider),
|
|
1794
|
+
getRegisteredProviderIds: () => [...state.providers.keys()],
|
|
1795
|
+
getProviderDisplayName: (provider) => {
|
|
1796
|
+
const config = providerConfig(provider);
|
|
1797
|
+
return typeof config?.name === "string" ? config.name : provider;
|
|
1798
|
+
},
|
|
1799
|
+
getProviderAuth: async (provider) => {
|
|
1800
|
+
const config = providerConfig(provider);
|
|
1801
|
+
if (config === void 0) return void 0;
|
|
1802
|
+
const resolved = await resolvePiProviderAuth({
|
|
1803
|
+
providerId: provider,
|
|
1804
|
+
providerConfig: config,
|
|
1805
|
+
store: oauthStoreOf(state)
|
|
1806
|
+
});
|
|
1807
|
+
if (resolved?.auth === void 0) return resolved;
|
|
1808
|
+
return resolved.auth.baseUrl === void 0 && config.baseUrl !== void 0 ? {
|
|
1809
|
+
...resolved,
|
|
1810
|
+
auth: {
|
|
1811
|
+
...resolved.auth,
|
|
1812
|
+
baseUrl: config.baseUrl
|
|
1813
|
+
}
|
|
1814
|
+
} : resolved;
|
|
1815
|
+
},
|
|
1816
|
+
getApiKeyForProvider: async (provider) => {
|
|
1817
|
+
const config = providerConfig(provider);
|
|
1818
|
+
if (config === void 0) return void 0;
|
|
1819
|
+
return ((await resolvePiProviderAuth({
|
|
1820
|
+
providerId: provider,
|
|
1821
|
+
providerConfig: config,
|
|
1822
|
+
store: oauthStoreOf(state)
|
|
1823
|
+
}))?.auth)?.apiKey;
|
|
1824
|
+
},
|
|
1825
|
+
isUsingOAuth: (model) => {
|
|
1826
|
+
const provider = String(model?.provider ?? "");
|
|
1827
|
+
return provider.length > 0 && providerSupportsOAuth(providerConfig(provider));
|
|
1828
|
+
},
|
|
1829
|
+
refresh: async () => {
|
|
1830
|
+
await catalog?.refresh();
|
|
1831
|
+
return {
|
|
1832
|
+
models: allModels(),
|
|
1833
|
+
errors: []
|
|
1834
|
+
};
|
|
1835
|
+
}
|
|
1836
|
+
};
|
|
1837
|
+
const contextCwd = typeof (sessionOverride?.header)?.cwd === "string" ? sessionOverride.header.cwd : cwdOf(agent);
|
|
1838
|
+
const base = {
|
|
1839
|
+
ui,
|
|
1840
|
+
mode: "rpc",
|
|
1841
|
+
hasUI: userQuestions !== void 0,
|
|
1842
|
+
cwd: contextCwd,
|
|
1843
|
+
sessionManager: session === void 0 ? state.bridge.readonlySessionManager({
|
|
1844
|
+
id: "pi2dsh-detached",
|
|
1845
|
+
events: []
|
|
1846
|
+
}, contextCwd) : state.bridge.readonlySessionManager(session, contextCwd),
|
|
1847
|
+
modelRegistry,
|
|
1782
1848
|
model: agent === void 0 ? void 0 : currentPiModel(state, agent),
|
|
1783
1849
|
scopedModels: catalog?.all() ?? [],
|
|
1784
1850
|
thinkingLevel: thinkingLevelOf(state, agent),
|
|
@@ -1794,9 +1860,55 @@ function contextFor(ctx, state, agent, signal, command = false) {
|
|
|
1794
1860
|
});
|
|
1795
1861
|
},
|
|
1796
1862
|
hasPendingMessages: () => false,
|
|
1797
|
-
shutdown: () =>
|
|
1863
|
+
shutdown: () => {
|
|
1864
|
+
capabilityLedgerOf(ctx, state).reportHostDecision({
|
|
1865
|
+
capability: "ctx.shutdown",
|
|
1866
|
+
reason: "Pi delegates shutdown behavior to the host, and on DSH the user owns process exit.",
|
|
1867
|
+
guidance: "The shutdown request was recorded and ignored.",
|
|
1868
|
+
packageName: state.packageName
|
|
1869
|
+
});
|
|
1870
|
+
},
|
|
1798
1871
|
getContextUsage: () => void 0,
|
|
1799
|
-
compact: () =>
|
|
1872
|
+
compact: (options) => {
|
|
1873
|
+
const ledger = capabilityLedgerOf(ctx, state);
|
|
1874
|
+
const compaction = optionalService(ctx, "compaction");
|
|
1875
|
+
const target = agent;
|
|
1876
|
+
const onError = options?.onError;
|
|
1877
|
+
if (compaction === void 0 || typeof target?.runMaintenance !== "function") {
|
|
1878
|
+
const gap = new PiCapabilityError({
|
|
1879
|
+
capability: "ctx.compact",
|
|
1880
|
+
reason: compaction === void 0 ? "this DSH composition mounts no compaction service." : "compaction needs a live DSH agent for this turn.",
|
|
1881
|
+
guidance: "Compaction runs through the host compaction plugin when one is composed.",
|
|
1882
|
+
packageName: state.packageName
|
|
1883
|
+
});
|
|
1884
|
+
ledger.reportDegraded({
|
|
1885
|
+
capability: "ctx.compact",
|
|
1886
|
+
reason: gap.message,
|
|
1887
|
+
guidance: "",
|
|
1888
|
+
packageName: state.packageName
|
|
1889
|
+
});
|
|
1890
|
+
onError?.(gap);
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
compaction.compactNow(target, new AbortController().signal).then((result) => {
|
|
1894
|
+
if (result === null || result === void 0) return;
|
|
1895
|
+
const dsh = result;
|
|
1896
|
+
const summaryText = (Array.isArray(dsh.summary) ? dsh.summary : []).filter((block) => typeof block === "object" && block !== null && block.type === "text" && typeof block.text === "string").map((block) => block.text).join("\n");
|
|
1897
|
+
const onComplete = options?.onComplete;
|
|
1898
|
+
onComplete?.({
|
|
1899
|
+
summary: summaryText,
|
|
1900
|
+
firstKeptEntryId: "",
|
|
1901
|
+
tokensBefore: dsh.shadowedTokenCount ?? 0
|
|
1902
|
+
});
|
|
1903
|
+
}).catch((error) => {
|
|
1904
|
+
const failure = error instanceof Error ? error : new Error(String(error));
|
|
1905
|
+
if (onError !== void 0) {
|
|
1906
|
+
onError(failure);
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
logger(ctx).warn(`[pi2dsh] plugin "${state.packageName}": ctx.compact failed: ${failure.message}`);
|
|
1910
|
+
});
|
|
1911
|
+
},
|
|
1800
1912
|
getSystemPrompt: () => state.currentSystemPrompt,
|
|
1801
1913
|
__agent: agent,
|
|
1802
1914
|
__notices: notices
|
|
@@ -1807,11 +1919,139 @@ function contextFor(ctx, state, agent, signal, command = false) {
|
|
|
1807
1919
|
const wait = agent?.whenIdle;
|
|
1808
1920
|
if (typeof wait === "function") await wait.call(agent);
|
|
1809
1921
|
},
|
|
1810
|
-
newSession: () =>
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1922
|
+
newSession: async (options) => {
|
|
1923
|
+
const sessions = optionalService(ctx, "sessions");
|
|
1924
|
+
if (sessions === void 0) {
|
|
1925
|
+
capabilityLedgerOf(ctx, state).reportDegraded({
|
|
1926
|
+
capability: "ctx.newSession",
|
|
1927
|
+
reason: "this DSH composition mounts no session service.",
|
|
1928
|
+
guidance: "",
|
|
1929
|
+
packageName: state.packageName
|
|
1930
|
+
});
|
|
1931
|
+
return { cancelled: true };
|
|
1932
|
+
}
|
|
1933
|
+
const parent = agentSession(agent);
|
|
1934
|
+
const created = sessions.create(void 0, { meta: {
|
|
1935
|
+
cwd: cwdOf(agent),
|
|
1936
|
+
...parent?.id === void 0 ? {} : { parentSession: parent.id }
|
|
1937
|
+
} });
|
|
1938
|
+
const withSession = options?.withSession;
|
|
1939
|
+
await withSession?.(contextFor(ctx, state, agent, signal, true, created));
|
|
1940
|
+
capabilityLedgerOf(ctx, state).reportHostDecision({
|
|
1941
|
+
capability: "ctx.newSession",
|
|
1942
|
+
reason: `a new DSH session was created (${String(created.id)}).`,
|
|
1943
|
+
guidance: "Which session the surface shows stays a host choice — open it from the DSH session list.",
|
|
1944
|
+
packageName: state.packageName
|
|
1945
|
+
});
|
|
1946
|
+
return { cancelled: false };
|
|
1947
|
+
},
|
|
1948
|
+
fork: async (entryId, options) => {
|
|
1949
|
+
const sessions = optionalService(ctx, "sessions");
|
|
1950
|
+
const source = agentSession(agent);
|
|
1951
|
+
if (sessions === void 0 || source === void 0) {
|
|
1952
|
+
capabilityLedgerOf(ctx, state).reportDegraded({
|
|
1953
|
+
capability: "ctx.fork",
|
|
1954
|
+
reason: sessions === void 0 ? "this DSH composition mounts no session service." : "forking needs the live session of an active agent.",
|
|
1955
|
+
guidance: "",
|
|
1956
|
+
packageName: state.packageName
|
|
1957
|
+
});
|
|
1958
|
+
return { cancelled: true };
|
|
1959
|
+
}
|
|
1960
|
+
const seq = durableSeqOf(String(entryId));
|
|
1961
|
+
if (seq === void 0) throw new Error(`pi2dsh: ctx.fork(${JSON.stringify(String(entryId))}) — only durable-log entries (projected ids "dsh-<seq>") can anchor a fork; package-appended sidecar entries are not part of the DSH durable log`);
|
|
1962
|
+
const position = options?.position ?? "before";
|
|
1963
|
+
const events = source.events ?? [];
|
|
1964
|
+
const requested = Math.min(position === "at" ? seq : seq - 1, events.length - 1);
|
|
1965
|
+
const boundary = requested < 0 ? -1 : shrinkToTurnBoundary(events, requested);
|
|
1966
|
+
const child = boundary < 0 ? sessions.create(void 0, { meta: {
|
|
1967
|
+
cwd: cwdOf(agent),
|
|
1968
|
+
parentSession: source.id
|
|
1969
|
+
} }) : sessions.fork(source, boundary);
|
|
1970
|
+
const withSession = options?.withSession;
|
|
1971
|
+
await withSession?.(contextFor(ctx, state, agent, signal, true, child));
|
|
1972
|
+
capabilityLedgerOf(ctx, state).reportHostDecision({
|
|
1973
|
+
capability: "ctx.fork",
|
|
1974
|
+
reason: `the session was forked on DSH's official prefix-fork surface (child ${String(child.id)}; DSH forks land on completed-turn boundaries).`,
|
|
1975
|
+
guidance: "Open the forked session from the DSH session list.",
|
|
1976
|
+
packageName: state.packageName
|
|
1977
|
+
});
|
|
1978
|
+
return { cancelled: false };
|
|
1979
|
+
},
|
|
1980
|
+
navigateTree: async (targetId, options) => {
|
|
1981
|
+
const sessions = optionalService(ctx, "sessions");
|
|
1982
|
+
const source = agentSession(agent);
|
|
1983
|
+
if (sessions === void 0 || source === void 0) {
|
|
1984
|
+
capabilityLedgerOf(ctx, state).reportDegraded({
|
|
1985
|
+
capability: "ctx.navigateTree",
|
|
1986
|
+
reason: sessions === void 0 ? "this DSH composition mounts no session service." : "tree navigation needs the live session of an active agent.",
|
|
1987
|
+
guidance: "",
|
|
1988
|
+
packageName: state.packageName
|
|
1989
|
+
});
|
|
1990
|
+
return { cancelled: true };
|
|
1991
|
+
}
|
|
1992
|
+
const seq = durableSeqOf(String(targetId));
|
|
1993
|
+
if (seq === void 0) throw new Error(`pi2dsh: ctx.navigateTree(${JSON.stringify(String(targetId))}) — only durable-log entries (projected ids "dsh-<seq>") can be navigation targets; package-appended sidecar entries are not part of the DSH durable log`);
|
|
1994
|
+
const events = source.events ?? [];
|
|
1995
|
+
const capped = Math.min(seq, events.length - 1);
|
|
1996
|
+
const boundary = capped < 0 ? -1 : shrinkToTurnBoundary(events, capped);
|
|
1997
|
+
const child = boundary < 0 ? sessions.create(void 0, { meta: {
|
|
1998
|
+
cwd: cwdOf(agent),
|
|
1999
|
+
parentSession: source.id
|
|
2000
|
+
} }) : sessions.fork(source, boundary);
|
|
2001
|
+
if (options?.summarize === true) {
|
|
2002
|
+
const summary = await summarizeAbandonedBranch(ctx, state, agent, events, boundary, options);
|
|
2003
|
+
if (summary !== void 0) state.bridge.appendBranchSummary(String(child.id), summary, String(targetId));
|
|
2004
|
+
}
|
|
2005
|
+
if (typeof options?.label === "string") state.bridge.appendLabel(String(child.id), String(targetId), options.label);
|
|
2006
|
+
capabilityLedgerOf(ctx, state).reportHostDecision({
|
|
2007
|
+
capability: "ctx.navigateTree",
|
|
2008
|
+
reason: `navigation forked the session at the target on DSH's official surface (child ${String(child.id)}; the DSH tree lives BETWEEN sessions via fork lineage, not inside one log).`,
|
|
2009
|
+
guidance: "Open the navigated session from the DSH session list.",
|
|
2010
|
+
packageName: state.packageName
|
|
2011
|
+
});
|
|
2012
|
+
return { cancelled: false };
|
|
2013
|
+
},
|
|
2014
|
+
switchSession: async (sessionPath, options) => {
|
|
2015
|
+
const sessions = optionalService(ctx, "sessions");
|
|
2016
|
+
if (sessions === void 0) {
|
|
2017
|
+
capabilityLedgerOf(ctx, state).reportDegraded({
|
|
2018
|
+
capability: "ctx.switchSession",
|
|
2019
|
+
reason: "this DSH composition mounts no session service.",
|
|
2020
|
+
guidance: "",
|
|
2021
|
+
packageName: state.packageName
|
|
2022
|
+
});
|
|
2023
|
+
return { cancelled: true };
|
|
2024
|
+
}
|
|
2025
|
+
const raw = String(sessionPath);
|
|
2026
|
+
const base = raw.replace(/\\/g, "/").split("/").pop() ?? raw;
|
|
2027
|
+
const candidate = base.endsWith(".jsonl") ? base.slice(0, -6) : base;
|
|
2028
|
+
const target = sessions.get(candidate) ?? sessions.list().find((entry) => String(entry.id) === candidate);
|
|
2029
|
+
if (target === void 0) throw new Error(`pi2dsh: ctx.switchSession(${JSON.stringify(raw)}) — no live DSH session ${JSON.stringify(candidate)}; switching to persisted sessions is host-owned (resume them from the DSH surface first)`);
|
|
2030
|
+
const withSession = options?.withSession;
|
|
2031
|
+
await withSession?.(contextFor(ctx, state, agent, signal, true, target));
|
|
2032
|
+
capabilityLedgerOf(ctx, state).reportHostDecision({
|
|
2033
|
+
capability: "ctx.switchSession",
|
|
2034
|
+
reason: `the live DSH session ${JSON.stringify(candidate)} was targeted.`,
|
|
2035
|
+
guidance: "Which session the surface shows stays a host choice — open it from the DSH session list.",
|
|
2036
|
+
packageName: state.packageName
|
|
2037
|
+
});
|
|
2038
|
+
return { cancelled: false };
|
|
2039
|
+
},
|
|
2040
|
+
reload: async () => {
|
|
2041
|
+
const remounts = state.shared.packageRemounts;
|
|
2042
|
+
if (remounts === void 0 || remounts.size === 0) return;
|
|
2043
|
+
for (const [name, remount] of remounts) try {
|
|
2044
|
+
await remount();
|
|
2045
|
+
} catch (error) {
|
|
2046
|
+
logger(ctx).warn(`[pi2dsh] ctx.reload: remounting "${name}" failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2047
|
+
}
|
|
2048
|
+
capabilityLedgerOf(ctx, state).reportHostDecision({
|
|
2049
|
+
capability: "ctx.reload",
|
|
2050
|
+
reason: "extension entries were disposed and remounted through a fresh loader.",
|
|
2051
|
+
guidance: "Skills, prompts, and themes are host-managed and reload when dsh restarts.",
|
|
2052
|
+
packageName: state.packageName
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
1815
2055
|
});
|
|
1816
2056
|
return base;
|
|
1817
2057
|
}
|
|
@@ -2488,7 +2728,12 @@ function registerLoginCommand(ctx, state) {
|
|
|
2488
2728
|
});
|
|
2489
2729
|
}
|
|
2490
2730
|
function registerTool(ctx, state, tool) {
|
|
2491
|
-
if (state.tools.has(tool.name))
|
|
2731
|
+
if (state.tools.has(tool.name)) {
|
|
2732
|
+
const previous = state.tools.get(tool.name);
|
|
2733
|
+
state.tools.set(tool.name, tool);
|
|
2734
|
+
if (JSON.stringify(previous.parameters ?? null) !== JSON.stringify(tool.parameters ?? null)) logger(ctx).warn(`[pi2dsh] tool ${tool.name} was re-registered with a different parameter schema; the new schema takes effect when dsh restarts (behavior is already live)`);
|
|
2735
|
+
return;
|
|
2736
|
+
}
|
|
2492
2737
|
const normalized = normalizeToolSchema(tool.parameters);
|
|
2493
2738
|
for (const warning of normalized.warnings) logger(ctx).warn(`[pi2dsh] tool ${tool.name}: ${warning}`);
|
|
2494
2739
|
state.tools.set(tool.name, tool);
|
|
@@ -2503,12 +2748,13 @@ function registerTool(ctx, state, tool) {
|
|
|
2503
2748
|
},
|
|
2504
2749
|
isConcurrencySafe: () => tool.executionMode === "parallel",
|
|
2505
2750
|
async execute(args, exec) {
|
|
2751
|
+
const live = state.tools.get(tool.name) ?? tool;
|
|
2506
2752
|
const mutated = state.argMutations.get(exec);
|
|
2507
2753
|
if (mutated !== void 0) state.argMutations.delete(exec);
|
|
2508
2754
|
const effective = mutated ?? args;
|
|
2509
|
-
const prepared =
|
|
2755
|
+
const prepared = live.prepareArguments?.(cloneJson(effective)) ?? effective;
|
|
2510
2756
|
const agent = exec.agent;
|
|
2511
|
-
const result = await normalizeToolResultForDsh(ctx, await state.agentScope.run(agent, () =>
|
|
2757
|
+
const result = await normalizeToolResultForDsh(ctx, await state.agentScope.run(agent, () => live.execute(String(exec.callId), prepared, exec.signal, (update) => {
|
|
2512
2758
|
dispatch(state, "tool_execution_update", {
|
|
2513
2759
|
type: "tool_execution_update",
|
|
2514
2760
|
toolCallId: String(exec.callId),
|
|
@@ -2649,8 +2895,8 @@ function dshCommandName(ctx, piName) {
|
|
|
2649
2895
|
}
|
|
2650
2896
|
function registerCommand(ctx, state, command) {
|
|
2651
2897
|
if (state.commands.has(command.name)) {
|
|
2652
|
-
state.
|
|
2653
|
-
|
|
2898
|
+
state.commands.set(command.name, command);
|
|
2899
|
+
return;
|
|
2654
2900
|
}
|
|
2655
2901
|
state.commands.set(command.name, command);
|
|
2656
2902
|
const commands = ctx.get("commands");
|
|
@@ -2666,7 +2912,8 @@ function registerCommand(ctx, state, command) {
|
|
|
2666
2912
|
async handler(invocation) {
|
|
2667
2913
|
const agent = invocation.agent;
|
|
2668
2914
|
const commandContext = contextFor(ctx, state, agent, invocation.signal, true);
|
|
2669
|
-
|
|
2915
|
+
const live = state.commands.get(command.name) ?? command;
|
|
2916
|
+
await state.agentScope.run(agent, () => live.handler(String(invocation.rawInput ?? "").trimStart(), commandContext));
|
|
2670
2917
|
const notices = commandContext.__notices;
|
|
2671
2918
|
return {
|
|
2672
2919
|
kind: "success",
|
|
@@ -2955,7 +3202,7 @@ async function registerPromptCommands(ctx, state, rootDir, manifest) {
|
|
|
2955
3202
|
});
|
|
2956
3203
|
}
|
|
2957
3204
|
}
|
|
2958
|
-
async function loadExtensions(rootDir, manifest, api, onExtensionError) {
|
|
3205
|
+
async function loadExtensions(rootDir, manifest, api, onExtensionError, onCapabilityGap, onHostInfraReference) {
|
|
2959
3206
|
const resolveShim = async (name) => {
|
|
2960
3207
|
const compiled = fileURLToPath(new URL(`./compat/${name}.mjs`, import.meta.url));
|
|
2961
3208
|
try {
|
|
@@ -2995,14 +3242,22 @@ async function loadExtensions(rootDir, manifest, api, onExtensionError) {
|
|
|
2995
3242
|
});
|
|
2996
3243
|
const failures = [];
|
|
2997
3244
|
let mounted = 0;
|
|
2998
|
-
for (const extension of manifest.extensions)
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3245
|
+
for (const extension of manifest.extensions) {
|
|
3246
|
+
try {
|
|
3247
|
+
const source = await readFile(join(rootDir, extension), "utf8");
|
|
3248
|
+
const infraImport = /import[^;]*?\b(ModelRuntime|DefaultPackageManager)\b[^;]*?from\s*['"]@(?:earendil-works|mariozechner)\/pi-coding-agent['"]/su.exec(source);
|
|
3249
|
+
if (infraImport !== null) onHostInfraReference?.(infraImport[1], extension);
|
|
3250
|
+
} catch {}
|
|
3251
|
+
try {
|
|
3252
|
+
const loaded = await jiti.import(join(rootDir, extension));
|
|
3253
|
+
const candidate = typeof loaded === "object" && loaded !== null && "default" in loaded ? loaded.default : loaded;
|
|
3254
|
+
if (typeof candidate !== "function") throw new TypeError(`Pi extension ${extension} has no default factory function`);
|
|
3255
|
+
await candidate(api);
|
|
3256
|
+
mounted += 1;
|
|
3257
|
+
} catch (error) {
|
|
3258
|
+
if (error instanceof PiCapabilityError || error instanceof Error && error.name === "PiCapabilityError") onCapabilityGap?.(error, extension);
|
|
3259
|
+
failures.push(`${extension}: ${error instanceof Error ? error.message : String(error)}`);
|
|
3260
|
+
}
|
|
3006
3261
|
}
|
|
3007
3262
|
if (failures.length > 0 && mounted === 0 && manifest.extensions.length > 0) throw new Error(`every Pi extension entry failed to load:\n${failures.map((item) => `- ${item}`).join("\n")}`);
|
|
3008
3263
|
for (const failure of failures) onExtensionError?.(failure);
|
|
@@ -3023,6 +3278,7 @@ async function applyPiPackage(ctx, options) {
|
|
|
3023
3278
|
const shared = sharedHostStateOf(ctx);
|
|
3024
3279
|
const state = {
|
|
3025
3280
|
shared,
|
|
3281
|
+
packageName: options.manifest.package.name,
|
|
3026
3282
|
handlers: /* @__PURE__ */ new Map(),
|
|
3027
3283
|
tools: runtimeTools,
|
|
3028
3284
|
runner: new ExtensionRunner(piToolRecords),
|
|
@@ -3116,8 +3372,34 @@ async function applyPiPackage(ctx, options) {
|
|
|
3116
3372
|
}, subagentOptions));
|
|
3117
3373
|
ctx.effect(() => () => __setSubagentSessionFactory(void 0));
|
|
3118
3374
|
await registerPromptCommands(ctx, state, rootDir, options.manifest);
|
|
3119
|
-
|
|
3120
|
-
|
|
3375
|
+
const onExtensionError = (failure) => logger(ctx).warn(`[pi2dsh] extension entry failed and was skipped (matching Pi's per-extension error isolation): ${failure}`);
|
|
3376
|
+
const onCapabilityGap = (gap) => capabilityLedgerOf(ctx, state).reportUnusable({
|
|
3377
|
+
capability: gap.capability,
|
|
3378
|
+
reason: "this package needs it during startup.",
|
|
3379
|
+
guidance: gap.message,
|
|
3380
|
+
packageName: state.packageName
|
|
3381
|
+
});
|
|
3382
|
+
const onHostInfraReference = (symbol) => capabilityLedgerOf(ctx, state).reportStartupReference({
|
|
3383
|
+
capability: symbol,
|
|
3384
|
+
reason: symbol === "DefaultPackageManager" ? "installing packages is owned by the DSH host and its security gates (dsh plugin add/remove)." : "standalone model stacks are owned by the DSH host llm configuration (packages read ctx.modelRegistry).",
|
|
3385
|
+
guidance: "",
|
|
3386
|
+
packageName: state.packageName
|
|
3387
|
+
});
|
|
3388
|
+
const mountExtensions = () => loadExtensions(rootDir, options.manifest, createPiApi(ctx, state), onExtensionError, onCapabilityGap, onHostInfraReference);
|
|
3389
|
+
await mountExtensions();
|
|
3390
|
+
const remounts = shared.packageRemounts ??= /* @__PURE__ */ new Map();
|
|
3391
|
+
remounts.set(state.packageName, async () => {
|
|
3392
|
+
state.handlers.clear();
|
|
3393
|
+
state.eventBus.removeAllListeners();
|
|
3394
|
+
await registerPromptCommands(ctx, state, rootDir, options.manifest);
|
|
3395
|
+
await mountExtensions();
|
|
3396
|
+
});
|
|
3397
|
+
ctx.effect(() => () => {
|
|
3398
|
+
remounts.delete(state.packageName);
|
|
3399
|
+
});
|
|
3400
|
+
const health = state.shared.capabilityLedger?.healthOf(state.packageName);
|
|
3401
|
+
const healthSuffix = health === void 0 || health.status === "ok" ? "" : ` — ${health.status.toUpperCase()}: missing Pi capabilities ${health.gaps.join(", ")}`;
|
|
3402
|
+
logger(ctx).info(`[pi2dsh] loaded ${options.manifest.package.name}: ${state.tools.size} tools, ${state.commands.size} commands, ${options.manifest.skillDirs.length} skill roots${healthSuffix}`);
|
|
3121
3403
|
}
|
|
3122
3404
|
const runtimeInternals = {
|
|
3123
3405
|
expandPrompt,
|
|
@@ -3128,4 +3410,4 @@ const runtimeInternals = {
|
|
|
3128
3410
|
//#endregion
|
|
3129
3411
|
export { runtimeInternals as i, normalizeToolSchema as n, registerVisionCompanions as r, applyPiPackage as t };
|
|
3130
3412
|
|
|
3131
|
-
//# sourceMappingURL=runtime-
|
|
3413
|
+
//# sourceMappingURL=runtime-Ce3PTbWU.mjs.map
|