pi2dsh 0.9.0 → 0.11.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.
Files changed (33) hide show
  1. package/README.md +262 -148
  2. package/README.zh.md +223 -129
  3. package/dist/{analyzer-C86ba-27.mjs → analyzer-CsrBeS8r.mjs} +2 -2
  4. package/dist/{analyzer-C86ba-27.mjs.map → analyzer-CsrBeS8r.mjs.map} +1 -1
  5. package/dist/cli.mjs +3 -3
  6. package/dist/compat/pi-ai.d.mts +2 -1
  7. package/dist/compat/pi-ai.d.mts.map +1 -1
  8. package/dist/compat/pi-ai.mjs +2 -3
  9. package/dist/compat/pi-coding-agent.d.mts +259 -29
  10. package/dist/compat/pi-coding-agent.d.mts.map +1 -1
  11. package/dist/compat/pi-coding-agent.mjs +2 -2
  12. package/dist/credentials-oauth.mjs +2 -2
  13. package/dist/{generator-C0jNM-yu.mjs → generator-CSOv6wYT.mjs} +2 -2
  14. package/dist/{generator-C0jNM-yu.mjs.map → generator-CSOv6wYT.mjs.map} +1 -1
  15. package/dist/host.mjs +1 -1
  16. package/dist/index.mjs +4 -4
  17. package/dist/{mcp-config-Dlou-ZA-.mjs → mcp-config-Cn5gWemZ.mjs} +29 -29
  18. package/dist/mcp-config-Cn5gWemZ.mjs.map +1 -0
  19. package/dist/{pi-ai-BA3h0Dwv.mjs → pi-ai-Dyg4zyLZ.mjs} +196 -75
  20. package/dist/pi-ai-Dyg4zyLZ.mjs.map +1 -0
  21. package/dist/{pi-coding-agent-CznNsOnV.mjs → pi-coding-agent-Ctw-BhoY.mjs} +0 -0
  22. package/dist/pi-coding-agent-Ctw-BhoY.mjs.map +1 -0
  23. package/dist/{runtime-DMEJknhK.mjs → runtime-DFD6u4NO.mjs} +548 -141
  24. package/dist/runtime-DFD6u4NO.mjs.map +1 -0
  25. package/dist/runtime.d.mts.map +1 -1
  26. package/dist/runtime.mjs +1 -1
  27. package/package.json +8 -4
  28. package/dist/mcp-config-Dlou-ZA-.mjs.map +0 -1
  29. package/dist/pi-ai-BA3h0Dwv.mjs.map +0 -1
  30. package/dist/pi-coding-agent-CznNsOnV.mjs.map +0 -1
  31. package/dist/pi-uuid-Db8ShZsK.mjs +0 -47
  32. package/dist/pi-uuid-Db8ShZsK.mjs.map +0 -1
  33. package/dist/runtime-DMEJknhK.mjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
 
2
- import { P as AssistantMessageEventStream, i as builtinProviders, r as __setPiAiLlmBridge } from "./pi-ai-BA3h0Dwv.mjs";
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: {
@@ -282,9 +303,22 @@ var PiSessionBridge = class {
282
303
  //#endregion
283
304
  //#region src/subagent-bridge.ts
284
305
  let subagentSerial = 0;
306
+ /** Flatten a Pi message's content to text for transcript seeding. */
307
+ function piMessageText(message) {
308
+ const content = message.content;
309
+ if (typeof content === "string") return content;
310
+ if (!Array.isArray(content)) return "";
311
+ return content.map((block) => {
312
+ const record = block;
313
+ if (record?.type === "text" && typeof record.text === "string") return record.text;
314
+ if (record?.type === "toolCall" && typeof record.name === "string") return `(tool ${record.name})`;
315
+ return "";
316
+ }).filter((text) => text.length > 0).join("\n");
317
+ }
285
318
  var PiBridgedAgentSession = class {
286
319
  agent = {};
287
320
  messages = [];
321
+ #seed = [];
288
322
  #host;
289
323
  #handle;
290
324
  #session;
@@ -292,6 +326,10 @@ var PiBridgedAgentSession = class {
292
326
  #subscribers = /* @__PURE__ */ new Set();
293
327
  #disposers = [];
294
328
  #activeToolNames;
329
+ #state;
330
+ #model;
331
+ #streaming = false;
332
+ #pendingToolCalls = /* @__PURE__ */ new Set();
295
333
  #sessionName = "";
296
334
  #turns = 0;
297
335
  #aborted = false;
@@ -320,6 +358,51 @@ var PiBridgedAgentSession = class {
320
358
  return next();
321
359
  });
322
360
  this.#disposers.push(offEvents, offPre);
361
+ const session = this;
362
+ this.#state = {
363
+ get systemPrompt() {
364
+ return "";
365
+ },
366
+ get model() {
367
+ return session.#model;
368
+ },
369
+ get thinkingLevel() {
370
+ return "off";
371
+ },
372
+ get tools() {
373
+ return [...session.#tools];
374
+ },
375
+ set tools(_next) {},
376
+ get messages() {
377
+ return [...session.messages];
378
+ },
379
+ set messages(next) {
380
+ session.#assignTranscript(next);
381
+ },
382
+ get isStreaming() {
383
+ return session.#streaming;
384
+ },
385
+ get pendingToolCalls() {
386
+ return new Set(session.#pendingToolCalls);
387
+ }
388
+ };
389
+ this.agent.state = this.#state;
390
+ }
391
+ /** Pi's AgentState projection, shared by `session.state` and `session.agent.state`. */
392
+ get state() {
393
+ return this.#state;
394
+ }
395
+ /**
396
+ * Pi's `state.messages = …` assignment. Messages already present in this
397
+ * child's projection stay as they are (they are durable); anything new is
398
+ * queued and delivered with the next prompt so the child model really sees
399
+ * the transcript the package seeded.
400
+ */
401
+ #assignTranscript(next) {
402
+ const identity = (message) => JSON.stringify([message.role, message.content]);
403
+ const known = new Set(this.messages.map(identity));
404
+ this.#seed = next.filter((message) => !known.has(identity(message)));
405
+ for (const message of this.#seed) this.messages.push(message);
323
406
  }
324
407
  #project(event) {
325
408
  const type = event.type;
@@ -328,12 +411,27 @@ var PiBridgedAgentSession = class {
328
411
  handler(piEvent);
329
412
  } catch {}
330
413
  };
331
- if (type === "turn/start") emit({
332
- type: "turn_start",
333
- turnIndex: Number(event.data.turn ?? 1) - 1
334
- });
414
+ if (type === "turn/start") {
415
+ this.#streaming = true;
416
+ emit({
417
+ type: "turn_start",
418
+ turnIndex: Number(event.data.turn ?? 1) - 1
419
+ });
420
+ }
421
+ if (type === "request/header") {
422
+ const config = event.data.config ?? {};
423
+ if (typeof config.model === "string") this.#model = {
424
+ id: config.model,
425
+ provider: String(config.provider ?? "")
426
+ };
427
+ }
428
+ if (type === "tools/result" || type === "tool/result") {
429
+ const data = event.data;
430
+ this.#pendingToolCalls.delete(String(data.callId ?? ""));
431
+ }
335
432
  if (type === "tool/call") {
336
433
  const data = event.data;
434
+ this.#pendingToolCalls.add(String(data.callId ?? ""));
337
435
  let args = {};
338
436
  try {
339
437
  args = JSON.parse(String(data.arguments ?? "{}"));
@@ -380,6 +478,8 @@ var PiBridgedAgentSession = class {
380
478
  }
381
479
  if (type === "turn/end") {
382
480
  this.#turns += 1;
481
+ this.#streaming = false;
482
+ this.#pendingToolCalls.clear();
383
483
  emit({
384
484
  type: "turn_end",
385
485
  turnIndex: Number(event.data.turn ?? 1) - 1,
@@ -396,6 +496,28 @@ var PiBridgedAgentSession = class {
396
496
  return () => this.#subscribers.delete(handler);
397
497
  }
398
498
  async prompt(text) {
499
+ if (this.#seed.length > 0) {
500
+ const seeded = this.#seed;
501
+ this.#seed = [];
502
+ const rendered = seeded.map((message) => {
503
+ const role = String(message.role ?? "user");
504
+ const content = piMessageText(message);
505
+ return content.length === 0 ? void 0 : `[${role}]: ${content}`;
506
+ }).filter((line) => line !== void 0);
507
+ if (rendered.length > 0) {
508
+ const seedBlocks = await this.#host.piContentToDsh([{
509
+ type: "text",
510
+ text: `<prior-conversation>\n${rendered.join("\n\n")}\n</prior-conversation>`
511
+ }]);
512
+ this.#host.deliver(this.#handle.agent, createUserMessage({
513
+ content: seedBlocks,
514
+ source: {
515
+ kind: "plugin",
516
+ plugin: this.#host.messageSource
517
+ }
518
+ }), "inject");
519
+ }
520
+ }
399
521
  const blocks = await this.#host.piContentToDsh([{
400
522
  type: "text",
401
523
  text: String(text)
@@ -475,6 +597,18 @@ var PiBridgedAgentSession = class {
475
597
  await this.#handle.dispose();
476
598
  }
477
599
  };
600
+ /**
601
+ * The name DSH's own child catalog shows for a side thread. Pi packages rarely
602
+ * label a child, so the package that started it is the honest fallback: with
603
+ * several Pi packages installed, their threads stay apart in one list.
604
+ * @param requested - a label the calling package supplied, if any.
605
+ * @param packageName - the Pi package the call came from.
606
+ */
607
+ function childLabel(requested, packageName) {
608
+ if (typeof requested === "string" && requested.trim().length > 0) return requested.trim().slice(0, 80);
609
+ const owner = packageName?.trim();
610
+ return owner === void 0 || owner.length === 0 ? "Pi side conversation" : `${owner} side conversation`;
611
+ }
478
612
  async function createBridgedAgentSession(host, options) {
479
613
  const agents = host.cordis.get("agents");
480
614
  if (agents?.create === void 0) throw new Error("pi2dsh: createAgentSession() needs the DSH agent registry in the host composition");
@@ -515,6 +649,17 @@ async function createBridgedAgentSession(host, options) {
515
649
  throw new Error(`pi2dsh: subagent creation needs the DSH host loop (model runtime) to provide the agent factory; this composition cannot run one (${error instanceof Error ? error.message : String(error)})`);
516
650
  }
517
651
  const tools = [...Array.isArray(options.tools) ? options.tools : [], ...Array.isArray(options.customTools) ? options.customTools : []];
652
+ const childSession = handle.agent.session;
653
+ if (typeof childSession?.append === "function") try {
654
+ childSession.append("subagent/descriptor", {
655
+ version: 2,
656
+ mode: "continuable",
657
+ provider: "pi2dsh",
658
+ label: childLabel(options.label, host.packageName)
659
+ });
660
+ } catch (error) {
661
+ host.cordis.logger?.warn?.(`[pi2dsh] child session could not record its subagent identity: ${error instanceof Error ? error.message : String(error)}`);
662
+ }
518
663
  return { session: new PiBridgedAgentSession(host, handle, tools) };
519
664
  }
520
665
  //#endregion
@@ -1493,6 +1638,11 @@ function cwdOf(agent) {
1493
1638
  function unsupported(name) {
1494
1639
  throw new Error(`pi2dsh: Pi API ${name} requires a native DSH port; inspect the compatibility report`);
1495
1640
  }
1641
+ function capabilityLedgerOf(ctx, state) {
1642
+ const shared = state.shared;
1643
+ if (shared.capabilityLedger === void 0) shared.capabilityLedger = new CapabilityLedger((message) => logger(ctx).warn(message));
1644
+ return shared.capabilityLedger;
1645
+ }
1496
1646
  function optionalService(ctx, name) {
1497
1647
  return ctx.get(name);
1498
1648
  }
@@ -1551,7 +1701,45 @@ function thinkingLevelOf(state, agent) {
1551
1701
  }
1552
1702
  return state.globalThinkingLevel;
1553
1703
  }
1554
- function contextFor(ctx, state, agent, signal, command = false) {
1704
+ function durableSeqOf(entryId) {
1705
+ const match = /^dsh-(\d+)$/.exec(entryId);
1706
+ return match === null ? void 0 : Number(match[1]);
1707
+ }
1708
+ function shrinkToTurnBoundary(events, boundary) {
1709
+ const slice = events.slice(0, boundary + 1);
1710
+ for (let i = slice.length - 1; i >= 0; i--) {
1711
+ const type = slice[i]?.type;
1712
+ if (type === "turn/end") return boundary;
1713
+ if (type === "turn/start") return Number(slice[i].seq) - 1;
1714
+ }
1715
+ return boundary;
1716
+ }
1717
+ async function summarizeAbandonedBranch(ctx, state, agent, events, boundary, options) {
1718
+ const abandoned = events.slice(boundary + 1);
1719
+ if (abandoned.length === 0) return void 0;
1720
+ const model = agent === void 0 ? void 0 : currentPiModel(state, agent);
1721
+ if (model === void 0) {
1722
+ logger(ctx).warn("[pi2dsh] ctx.navigateTree: no current model route, navigating without a branch summary");
1723
+ return;
1724
+ }
1725
+ const entries = state.bridge.readonlySessionManager({
1726
+ id: "pi2dsh-abandoned-branch",
1727
+ events: abandoned
1728
+ }, cwdOf(agent)).getEntries?.() ?? [];
1729
+ if (entries.length === 0) return void 0;
1730
+ const result = await generateBranchSummary(entries, {
1731
+ model,
1732
+ signal: new AbortController().signal,
1733
+ ...typeof options.customInstructions === "string" ? { customInstructions: options.customInstructions } : {},
1734
+ ...options.replaceInstructions === true ? { replaceInstructions: true } : {}
1735
+ });
1736
+ if (result.error !== void 0) {
1737
+ logger(ctx).warn(`[pi2dsh] ctx.navigateTree: branch summarization failed (${result.error}), navigating without a summary`);
1738
+ return;
1739
+ }
1740
+ return result.summary;
1741
+ }
1742
+ function contextFor(ctx, state, agent, signal, command = false, sessionOverride) {
1555
1743
  const notices = [];
1556
1744
  const userQuestions = optionalService(ctx, "userQuestions");
1557
1745
  const ui = {
@@ -1626,7 +1814,7 @@ function contextFor(ctx, state, agent, signal, command = false) {
1626
1814
  state.toolsExpanded = expanded === true;
1627
1815
  }
1628
1816
  };
1629
- const session = agentSession(agent);
1817
+ const session = sessionOverride ?? agentSession(agent);
1630
1818
  const providerConfig = (name) => state.providers.get(name);
1631
1819
  const catalog = state.modelCatalog;
1632
1820
  const piNativeEntry = (provider, id) => {
@@ -1666,119 +1854,121 @@ function contextFor(ctx, state, agent, signal, command = false) {
1666
1854
  stream: dshRoutedStream,
1667
1855
  streamSimple: dshRoutedStream
1668
1856
  });
1669
- const base = {
1670
- ui,
1671
- mode: "rpc",
1672
- hasUI: userQuestions !== void 0,
1673
- cwd: cwdOf(agent),
1674
- sessionManager: session === void 0 ? state.bridge.readonlySessionManager({
1675
- id: "pi2dsh-detached",
1676
- events: []
1677
- }, cwdOf(agent)) : state.bridge.readonlySessionManager(session, cwdOf(agent)),
1678
- modelRegistry: {
1679
- getAll: () => allModels(),
1680
- getAvailable: () => allModels(),
1681
- find: (provider, modelId) => {
1682
- const entry = catalog?.find(provider, modelId);
1683
- return entry === void 0 ? void 0 : restorePiShape(entry);
1684
- },
1685
- getError: () => void 0,
1686
- hasConfiguredAuth: (model) => {
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({
1857
+ const modelRegistry = {
1858
+ getAll: () => allModels(),
1859
+ getAvailable: () => allModels(),
1860
+ find: (provider, modelId) => {
1861
+ const entry = catalog?.find(provider, modelId);
1862
+ return entry === void 0 ? void 0 : restorePiShape(entry);
1863
+ },
1864
+ getError: () => void 0,
1865
+ hasConfiguredAuth: (model) => {
1866
+ const provider = String(model?.provider ?? "");
1867
+ if (provider.length === 0) return false;
1868
+ return state.providers.has(provider) || (catalog?.all() ?? []).some((entry) => entry.provider === provider);
1869
+ },
1870
+ getApiKeyAndHeaders: async (model) => {
1871
+ const provider = String(model?.provider ?? "");
1872
+ const config = providerConfig(provider);
1873
+ if (config !== void 0) {
1874
+ const auth = (await resolvePiProviderAuth({
1765
1875
  providerId: provider,
1766
1876
  providerConfig: config,
1767
1877
  store: oauthStoreOf(state)
1768
- }))?.auth)?.apiKey;
1769
- },
1770
- isUsingOAuth: (model) => {
1771
- const provider = String(model?.provider ?? "");
1772
- return provider.length > 0 && providerSupportsOAuth(providerConfig(provider));
1773
- },
1774
- refresh: async () => {
1775
- await catalog?.refresh();
1878
+ }))?.auth;
1879
+ if (auth?.apiKey === void 0) return { ok: false };
1880
+ return {
1881
+ ok: true,
1882
+ apiKey: auth.apiKey,
1883
+ ...auth.headers === void 0 ? {} : { headers: auth.headers },
1884
+ ...auth.baseUrl === void 0 && config.baseUrl === void 0 ? {} : { baseUrl: auth.baseUrl ?? config.baseUrl }
1885
+ };
1886
+ }
1887
+ try {
1888
+ const entry = llmOf(ctx)?.listConfigurableProviders?.()?.find((candidate) => candidate.provider === provider);
1889
+ if (entry === void 0) return { ok: false };
1890
+ const section = ctx.get("settings")?.get(entry.settingsNs);
1891
+ const ref = entry.settingsPath.reduce((node, key) => typeof node === "object" && node !== null ? node[key] : void 0, section)?.apiKeyEnv;
1892
+ if (typeof ref !== "string" || ref.length === 0) return { ok: false };
1893
+ const resolved = await ctx.get("credentials")?.resolve(ref);
1894
+ if (typeof resolved?.value !== "string" || resolved.value.length === 0) return { ok: false };
1776
1895
  return {
1777
- models: allModels(),
1778
- errors: []
1896
+ ok: true,
1897
+ apiKey: resolved.value
1779
1898
  };
1899
+ } catch {
1900
+ return { ok: false };
1780
1901
  }
1781
1902
  },
1903
+ getProviderAuthStatus: (provider) => providerSupportsOAuth(providerConfig(provider)) ? "oauth" : "none",
1904
+ getProvider: (provider) => {
1905
+ const base = providerConfig(provider);
1906
+ if (base !== void 0) return state.providerRouteDisposers.has(provider) ? dshRoutedPiProvider(base, provider) : base;
1907
+ if ((catalog?.all() ?? []).some((entry) => entry.provider === provider)) return dshRoutedPiProvider({
1908
+ id: provider,
1909
+ name: provider
1910
+ }, provider);
1911
+ },
1912
+ complete: async (model, context, options) => {
1913
+ const result = await dshRoutedStream(model, context ?? {}, options).result();
1914
+ if (result instanceof Error) throw result;
1915
+ return result;
1916
+ },
1917
+ getRegisteredProviderConfig: (provider) => providerConfig(provider),
1918
+ getRegisteredProviderIds: () => [...state.providers.keys()],
1919
+ getProviderDisplayName: (provider) => {
1920
+ const config = providerConfig(provider);
1921
+ return typeof config?.name === "string" ? config.name : provider;
1922
+ },
1923
+ getProviderAuth: async (provider) => {
1924
+ const config = providerConfig(provider);
1925
+ if (config === void 0) return void 0;
1926
+ const resolved = await resolvePiProviderAuth({
1927
+ providerId: provider,
1928
+ providerConfig: config,
1929
+ store: oauthStoreOf(state)
1930
+ });
1931
+ if (resolved?.auth === void 0) return resolved;
1932
+ return resolved.auth.baseUrl === void 0 && config.baseUrl !== void 0 ? {
1933
+ ...resolved,
1934
+ auth: {
1935
+ ...resolved.auth,
1936
+ baseUrl: config.baseUrl
1937
+ }
1938
+ } : resolved;
1939
+ },
1940
+ getApiKeyForProvider: async (provider) => {
1941
+ const config = providerConfig(provider);
1942
+ if (config === void 0) return void 0;
1943
+ return ((await resolvePiProviderAuth({
1944
+ providerId: provider,
1945
+ providerConfig: config,
1946
+ store: oauthStoreOf(state)
1947
+ }))?.auth)?.apiKey;
1948
+ },
1949
+ isUsingOAuth: (model) => {
1950
+ const provider = String(model?.provider ?? "");
1951
+ return provider.length > 0 && providerSupportsOAuth(providerConfig(provider));
1952
+ },
1953
+ refresh: async () => {
1954
+ await catalog?.refresh();
1955
+ return {
1956
+ models: allModels(),
1957
+ errors: []
1958
+ };
1959
+ }
1960
+ };
1961
+ const contextCwd = typeof (sessionOverride?.header)?.cwd === "string" ? sessionOverride.header.cwd : cwdOf(agent);
1962
+ const base = {
1963
+ ui,
1964
+ mode: "rpc",
1965
+ hasUI: userQuestions !== void 0,
1966
+ cwd: contextCwd,
1967
+ sessionManager: session === void 0 ? state.bridge.readonlySessionManager({
1968
+ id: "pi2dsh-detached",
1969
+ events: []
1970
+ }, contextCwd) : state.bridge.readonlySessionManager(session, contextCwd),
1971
+ modelRegistry,
1782
1972
  model: agent === void 0 ? void 0 : currentPiModel(state, agent),
1783
1973
  scopedModels: catalog?.all() ?? [],
1784
1974
  thinkingLevel: thinkingLevelOf(state, agent),
@@ -1794,9 +1984,55 @@ function contextFor(ctx, state, agent, signal, command = false) {
1794
1984
  });
1795
1985
  },
1796
1986
  hasPendingMessages: () => false,
1797
- shutdown: () => unsupported("ctx.shutdown"),
1987
+ shutdown: () => {
1988
+ capabilityLedgerOf(ctx, state).reportHostDecision({
1989
+ capability: "ctx.shutdown",
1990
+ reason: "Pi delegates shutdown behavior to the host, and on DSH the user owns process exit.",
1991
+ guidance: "The shutdown request was recorded and ignored.",
1992
+ packageName: state.packageName
1993
+ });
1994
+ },
1798
1995
  getContextUsage: () => void 0,
1799
- compact: () => unsupported("ctx.compact"),
1996
+ compact: (options) => {
1997
+ const ledger = capabilityLedgerOf(ctx, state);
1998
+ const compaction = optionalService(ctx, "compaction");
1999
+ const target = agent;
2000
+ const onError = options?.onError;
2001
+ if (compaction === void 0 || typeof target?.runMaintenance !== "function") {
2002
+ const gap = new PiCapabilityError({
2003
+ capability: "ctx.compact",
2004
+ reason: compaction === void 0 ? "this DSH composition mounts no compaction service." : "compaction needs a live DSH agent for this turn.",
2005
+ guidance: "Compaction runs through the host compaction plugin when one is composed.",
2006
+ packageName: state.packageName
2007
+ });
2008
+ ledger.reportDegraded({
2009
+ capability: "ctx.compact",
2010
+ reason: gap.message,
2011
+ guidance: "",
2012
+ packageName: state.packageName
2013
+ });
2014
+ onError?.(gap);
2015
+ return;
2016
+ }
2017
+ compaction.compactNow(target, new AbortController().signal).then((result) => {
2018
+ if (result === null || result === void 0) return;
2019
+ const dsh = result;
2020
+ 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");
2021
+ const onComplete = options?.onComplete;
2022
+ onComplete?.({
2023
+ summary: summaryText,
2024
+ firstKeptEntryId: "",
2025
+ tokensBefore: dsh.shadowedTokenCount ?? 0
2026
+ });
2027
+ }).catch((error) => {
2028
+ const failure = error instanceof Error ? error : new Error(String(error));
2029
+ if (onError !== void 0) {
2030
+ onError(failure);
2031
+ return;
2032
+ }
2033
+ logger(ctx).warn(`[pi2dsh] plugin "${state.packageName}": ctx.compact failed: ${failure.message}`);
2034
+ });
2035
+ },
1800
2036
  getSystemPrompt: () => state.currentSystemPrompt,
1801
2037
  __agent: agent,
1802
2038
  __notices: notices
@@ -1807,11 +2043,139 @@ function contextFor(ctx, state, agent, signal, command = false) {
1807
2043
  const wait = agent?.whenIdle;
1808
2044
  if (typeof wait === "function") await wait.call(agent);
1809
2045
  },
1810
- newSession: () => unsupported("ctx.newSession"),
1811
- fork: () => unsupported("ctx.fork"),
1812
- navigateTree: () => unsupported("ctx.navigateTree"),
1813
- switchSession: () => unsupported("ctx.switchSession"),
1814
- reload: () => unsupported("ctx.reload")
2046
+ newSession: async (options) => {
2047
+ const sessions = optionalService(ctx, "sessions");
2048
+ if (sessions === void 0) {
2049
+ capabilityLedgerOf(ctx, state).reportDegraded({
2050
+ capability: "ctx.newSession",
2051
+ reason: "this DSH composition mounts no session service.",
2052
+ guidance: "",
2053
+ packageName: state.packageName
2054
+ });
2055
+ return { cancelled: true };
2056
+ }
2057
+ const parent = agentSession(agent);
2058
+ const created = sessions.create(void 0, { meta: {
2059
+ cwd: cwdOf(agent),
2060
+ ...parent?.id === void 0 ? {} : { parentSession: parent.id }
2061
+ } });
2062
+ const withSession = options?.withSession;
2063
+ await withSession?.(contextFor(ctx, state, agent, signal, true, created));
2064
+ capabilityLedgerOf(ctx, state).reportHostDecision({
2065
+ capability: "ctx.newSession",
2066
+ reason: `a new DSH session was created (${String(created.id)}).`,
2067
+ guidance: "Which session the surface shows stays a host choice — open it from the DSH session list.",
2068
+ packageName: state.packageName
2069
+ });
2070
+ return { cancelled: false };
2071
+ },
2072
+ fork: async (entryId, options) => {
2073
+ const sessions = optionalService(ctx, "sessions");
2074
+ const source = agentSession(agent);
2075
+ if (sessions === void 0 || source === void 0) {
2076
+ capabilityLedgerOf(ctx, state).reportDegraded({
2077
+ capability: "ctx.fork",
2078
+ reason: sessions === void 0 ? "this DSH composition mounts no session service." : "forking needs the live session of an active agent.",
2079
+ guidance: "",
2080
+ packageName: state.packageName
2081
+ });
2082
+ return { cancelled: true };
2083
+ }
2084
+ const seq = durableSeqOf(String(entryId));
2085
+ 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`);
2086
+ const position = options?.position ?? "before";
2087
+ const events = source.events ?? [];
2088
+ const requested = Math.min(position === "at" ? seq : seq - 1, events.length - 1);
2089
+ const boundary = requested < 0 ? -1 : shrinkToTurnBoundary(events, requested);
2090
+ const child = boundary < 0 ? sessions.create(void 0, { meta: {
2091
+ cwd: cwdOf(agent),
2092
+ parentSession: source.id
2093
+ } }) : sessions.fork(source, boundary);
2094
+ const withSession = options?.withSession;
2095
+ await withSession?.(contextFor(ctx, state, agent, signal, true, child));
2096
+ capabilityLedgerOf(ctx, state).reportHostDecision({
2097
+ capability: "ctx.fork",
2098
+ reason: `the session was forked on DSH's official prefix-fork surface (child ${String(child.id)}; DSH forks land on completed-turn boundaries).`,
2099
+ guidance: "Open the forked session from the DSH session list.",
2100
+ packageName: state.packageName
2101
+ });
2102
+ return { cancelled: false };
2103
+ },
2104
+ navigateTree: async (targetId, options) => {
2105
+ const sessions = optionalService(ctx, "sessions");
2106
+ const source = agentSession(agent);
2107
+ if (sessions === void 0 || source === void 0) {
2108
+ capabilityLedgerOf(ctx, state).reportDegraded({
2109
+ capability: "ctx.navigateTree",
2110
+ reason: sessions === void 0 ? "this DSH composition mounts no session service." : "tree navigation needs the live session of an active agent.",
2111
+ guidance: "",
2112
+ packageName: state.packageName
2113
+ });
2114
+ return { cancelled: true };
2115
+ }
2116
+ const seq = durableSeqOf(String(targetId));
2117
+ 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`);
2118
+ const events = source.events ?? [];
2119
+ const capped = Math.min(seq, events.length - 1);
2120
+ const boundary = capped < 0 ? -1 : shrinkToTurnBoundary(events, capped);
2121
+ const child = boundary < 0 ? sessions.create(void 0, { meta: {
2122
+ cwd: cwdOf(agent),
2123
+ parentSession: source.id
2124
+ } }) : sessions.fork(source, boundary);
2125
+ if (options?.summarize === true) {
2126
+ const summary = await summarizeAbandonedBranch(ctx, state, agent, events, boundary, options);
2127
+ if (summary !== void 0) state.bridge.appendBranchSummary(String(child.id), summary, String(targetId));
2128
+ }
2129
+ if (typeof options?.label === "string") state.bridge.appendLabel(String(child.id), String(targetId), options.label);
2130
+ capabilityLedgerOf(ctx, state).reportHostDecision({
2131
+ capability: "ctx.navigateTree",
2132
+ 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).`,
2133
+ guidance: "Open the navigated session from the DSH session list.",
2134
+ packageName: state.packageName
2135
+ });
2136
+ return { cancelled: false };
2137
+ },
2138
+ switchSession: async (sessionPath, options) => {
2139
+ const sessions = optionalService(ctx, "sessions");
2140
+ if (sessions === void 0) {
2141
+ capabilityLedgerOf(ctx, state).reportDegraded({
2142
+ capability: "ctx.switchSession",
2143
+ reason: "this DSH composition mounts no session service.",
2144
+ guidance: "",
2145
+ packageName: state.packageName
2146
+ });
2147
+ return { cancelled: true };
2148
+ }
2149
+ const raw = String(sessionPath);
2150
+ const base = raw.replace(/\\/g, "/").split("/").pop() ?? raw;
2151
+ const candidate = base.endsWith(".jsonl") ? base.slice(0, -6) : base;
2152
+ const target = sessions.get(candidate) ?? sessions.list().find((entry) => String(entry.id) === candidate);
2153
+ 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)`);
2154
+ const withSession = options?.withSession;
2155
+ await withSession?.(contextFor(ctx, state, agent, signal, true, target));
2156
+ capabilityLedgerOf(ctx, state).reportHostDecision({
2157
+ capability: "ctx.switchSession",
2158
+ reason: `the live DSH session ${JSON.stringify(candidate)} was targeted.`,
2159
+ guidance: "Which session the surface shows stays a host choice — open it from the DSH session list.",
2160
+ packageName: state.packageName
2161
+ });
2162
+ return { cancelled: false };
2163
+ },
2164
+ reload: async () => {
2165
+ const remounts = state.shared.packageRemounts;
2166
+ if (remounts === void 0 || remounts.size === 0) return;
2167
+ for (const [name, remount] of remounts) try {
2168
+ await remount();
2169
+ } catch (error) {
2170
+ logger(ctx).warn(`[pi2dsh] ctx.reload: remounting "${name}" failed: ${error instanceof Error ? error.message : String(error)}`);
2171
+ }
2172
+ capabilityLedgerOf(ctx, state).reportHostDecision({
2173
+ capability: "ctx.reload",
2174
+ reason: "extension entries were disposed and remounted through a fresh loader.",
2175
+ guidance: "Skills, prompts, and themes are host-managed and reload when dsh restarts.",
2176
+ packageName: state.packageName
2177
+ });
2178
+ }
1815
2179
  });
1816
2180
  return base;
1817
2181
  }
@@ -2488,7 +2852,12 @@ function registerLoginCommand(ctx, state) {
2488
2852
  });
2489
2853
  }
2490
2854
  function registerTool(ctx, state, tool) {
2491
- if (state.tools.has(tool.name)) unregisterTool(state, tool.name);
2855
+ if (state.tools.has(tool.name)) {
2856
+ const previous = state.tools.get(tool.name);
2857
+ state.tools.set(tool.name, tool);
2858
+ 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)`);
2859
+ return;
2860
+ }
2492
2861
  const normalized = normalizeToolSchema(tool.parameters);
2493
2862
  for (const warning of normalized.warnings) logger(ctx).warn(`[pi2dsh] tool ${tool.name}: ${warning}`);
2494
2863
  state.tools.set(tool.name, tool);
@@ -2503,12 +2872,13 @@ function registerTool(ctx, state, tool) {
2503
2872
  },
2504
2873
  isConcurrencySafe: () => tool.executionMode === "parallel",
2505
2874
  async execute(args, exec) {
2875
+ const live = state.tools.get(tool.name) ?? tool;
2506
2876
  const mutated = state.argMutations.get(exec);
2507
2877
  if (mutated !== void 0) state.argMutations.delete(exec);
2508
2878
  const effective = mutated ?? args;
2509
- const prepared = tool.prepareArguments?.(cloneJson(effective)) ?? effective;
2879
+ const prepared = live.prepareArguments?.(cloneJson(effective)) ?? effective;
2510
2880
  const agent = exec.agent;
2511
- const result = await normalizeToolResultForDsh(ctx, await state.agentScope.run(agent, () => tool.execute(String(exec.callId), prepared, exec.signal, (update) => {
2881
+ const result = await normalizeToolResultForDsh(ctx, await state.agentScope.run(agent, () => live.execute(String(exec.callId), prepared, exec.signal, (update) => {
2512
2882
  dispatch(state, "tool_execution_update", {
2513
2883
  type: "tool_execution_update",
2514
2884
  toolCallId: String(exec.callId),
@@ -2649,8 +3019,8 @@ function dshCommandName(ctx, piName) {
2649
3019
  }
2650
3020
  function registerCommand(ctx, state, command) {
2651
3021
  if (state.commands.has(command.name)) {
2652
- state.commandDisposers.get(command.name)?.();
2653
- state.commandDisposers.delete(command.name);
3022
+ state.commands.set(command.name, command);
3023
+ return;
2654
3024
  }
2655
3025
  state.commands.set(command.name, command);
2656
3026
  const commands = ctx.get("commands");
@@ -2662,11 +3032,12 @@ function registerCommand(ctx, state, command) {
2662
3032
  const definitionFor = (dshName) => ({
2663
3033
  name: dshName,
2664
3034
  description: command.description || `Migrated Pi command /${command.name}`,
2665
- ...command.argumentHint !== void 0 ? { input: { hint: command.argumentHint } } : {},
3035
+ input: { hint: command.argumentHint ?? "arguments (optional)" },
2666
3036
  async handler(invocation) {
2667
3037
  const agent = invocation.agent;
2668
3038
  const commandContext = contextFor(ctx, state, agent, invocation.signal, true);
2669
- await state.agentScope.run(agent, () => command.handler(String(invocation.rawInput ?? "").trimStart(), commandContext));
3039
+ const live = state.commands.get(command.name) ?? command;
3040
+ await state.agentScope.run(agent, () => live.handler(String(invocation.rawInput ?? "").trimStart(), commandContext));
2670
3041
  const notices = commandContext.__notices;
2671
3042
  return {
2672
3043
  kind: "success",
@@ -2955,7 +3326,7 @@ async function registerPromptCommands(ctx, state, rootDir, manifest) {
2955
3326
  });
2956
3327
  }
2957
3328
  }
2958
- async function loadExtensions(rootDir, manifest, api, onExtensionError) {
3329
+ async function loadExtensions(rootDir, manifest, api, onExtensionError, onCapabilityGap, onHostInfraReference) {
2959
3330
  const resolveShim = async (name) => {
2960
3331
  const compiled = fileURLToPath(new URL(`./compat/${name}.mjs`, import.meta.url));
2961
3332
  try {
@@ -2995,14 +3366,22 @@ async function loadExtensions(rootDir, manifest, api, onExtensionError) {
2995
3366
  });
2996
3367
  const failures = [];
2997
3368
  let mounted = 0;
2998
- for (const extension of manifest.extensions) try {
2999
- const loaded = await jiti.import(join(rootDir, extension));
3000
- const candidate = typeof loaded === "object" && loaded !== null && "default" in loaded ? loaded.default : loaded;
3001
- if (typeof candidate !== "function") throw new TypeError(`Pi extension ${extension} has no default factory function`);
3002
- await candidate(api);
3003
- mounted += 1;
3004
- } catch (error) {
3005
- failures.push(`${extension}: ${error instanceof Error ? error.message : String(error)}`);
3369
+ for (const extension of manifest.extensions) {
3370
+ try {
3371
+ const source = await readFile(join(rootDir, extension), "utf8");
3372
+ const infraImport = /import[^;]*?\b(ModelRuntime|DefaultPackageManager)\b[^;]*?from\s*['"]@(?:earendil-works|mariozechner)\/pi-coding-agent['"]/su.exec(source);
3373
+ if (infraImport !== null) onHostInfraReference?.(infraImport[1], extension);
3374
+ } catch {}
3375
+ try {
3376
+ const loaded = await jiti.import(join(rootDir, extension));
3377
+ const candidate = typeof loaded === "object" && loaded !== null && "default" in loaded ? loaded.default : loaded;
3378
+ if (typeof candidate !== "function") throw new TypeError(`Pi extension ${extension} has no default factory function`);
3379
+ await candidate(api);
3380
+ mounted += 1;
3381
+ } catch (error) {
3382
+ if (error instanceof PiCapabilityError || error instanceof Error && error.name === "PiCapabilityError") onCapabilityGap?.(error, extension);
3383
+ failures.push(`${extension}: ${error instanceof Error ? error.message : String(error)}`);
3384
+ }
3006
3385
  }
3007
3386
  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
3387
  for (const failure of failures) onExtensionError?.(failure);
@@ -3023,6 +3402,7 @@ async function applyPiPackage(ctx, options) {
3023
3402
  const shared = sharedHostStateOf(ctx);
3024
3403
  const state = {
3025
3404
  shared,
3405
+ packageName: options.manifest.package.name,
3026
3406
  handlers: /* @__PURE__ */ new Map(),
3027
3407
  tools: runtimeTools,
3028
3408
  runner: new ExtensionRunner(piToolRecords),
@@ -3112,12 +3492,39 @@ async function applyPiPackage(ctx, options) {
3112
3492
  piContentToDsh: (content) => piToDshContent(ctx, content),
3113
3493
  deliver: (agent, message, mode) => deliverAgentMessage(agent, message, mode),
3114
3494
  messageFromSessionEvent,
3115
- messageSource: state.messageSource
3495
+ messageSource: state.messageSource,
3496
+ packageName: state.packageName
3116
3497
  }, subagentOptions));
3117
3498
  ctx.effect(() => () => __setSubagentSessionFactory(void 0));
3118
3499
  await registerPromptCommands(ctx, state, rootDir, options.manifest);
3119
- await loadExtensions(rootDir, options.manifest, createPiApi(ctx, state), (failure) => logger(ctx).warn(`[pi2dsh] extension entry failed and was skipped (matching Pi's per-extension error isolation): ${failure}`));
3120
- logger(ctx).info(`[pi2dsh] loaded ${options.manifest.package.name}: ${state.tools.size} tools, ${state.commands.size} commands, ${options.manifest.skillDirs.length} skill roots`);
3500
+ const onExtensionError = (failure) => logger(ctx).warn(`[pi2dsh] extension entry failed and was skipped (matching Pi's per-extension error isolation): ${failure}`);
3501
+ const onCapabilityGap = (gap) => capabilityLedgerOf(ctx, state).reportUnusable({
3502
+ capability: gap.capability,
3503
+ reason: "this package needs it during startup.",
3504
+ guidance: gap.message,
3505
+ packageName: state.packageName
3506
+ });
3507
+ const onHostInfraReference = (symbol) => capabilityLedgerOf(ctx, state).reportStartupReference({
3508
+ capability: symbol,
3509
+ 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).",
3510
+ guidance: "",
3511
+ packageName: state.packageName
3512
+ });
3513
+ const mountExtensions = () => loadExtensions(rootDir, options.manifest, createPiApi(ctx, state), onExtensionError, onCapabilityGap, onHostInfraReference);
3514
+ await mountExtensions();
3515
+ const remounts = shared.packageRemounts ??= /* @__PURE__ */ new Map();
3516
+ remounts.set(state.packageName, async () => {
3517
+ state.handlers.clear();
3518
+ state.eventBus.removeAllListeners();
3519
+ await registerPromptCommands(ctx, state, rootDir, options.manifest);
3520
+ await mountExtensions();
3521
+ });
3522
+ ctx.effect(() => () => {
3523
+ remounts.delete(state.packageName);
3524
+ });
3525
+ const health = state.shared.capabilityLedger?.healthOf(state.packageName);
3526
+ const healthSuffix = health === void 0 || health.status === "ok" ? "" : ` — ${health.status.toUpperCase()}: missing Pi capabilities ${health.gaps.join(", ")}`;
3527
+ 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
3528
  }
3122
3529
  const runtimeInternals = {
3123
3530
  expandPrompt,
@@ -3128,4 +3535,4 @@ const runtimeInternals = {
3128
3535
  //#endregion
3129
3536
  export { runtimeInternals as i, normalizeToolSchema as n, registerVisionCompanions as r, applyPiPackage as t };
3130
3537
 
3131
- //# sourceMappingURL=runtime-DMEJknhK.mjs.map
3538
+ //# sourceMappingURL=runtime-DFD6u4NO.mjs.map