pi2dsh 0.13.3 → 0.14.1

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 (35) hide show
  1. package/README.md +2 -0
  2. package/README.zh.md +2 -0
  3. package/dist/{analyzer-DBtUYKI1.mjs → analyzer-DPZ8LzSt.mjs} +2 -2
  4. package/dist/{analyzer-DBtUYKI1.mjs.map → analyzer-DPZ8LzSt.mjs.map} +1 -1
  5. package/dist/cli.mjs +2 -2
  6. package/dist/compat/pi-ai.d.mts +1 -1
  7. package/dist/compat/pi-ai.mjs +1 -1
  8. package/dist/compat/pi-coding-agent.mjs +1 -1
  9. package/dist/{compatibility-Bz6ZXA7F.mjs → compatibility-CP2tpyhg.mjs} +13 -1
  10. package/dist/compatibility-CP2tpyhg.mjs.map +1 -0
  11. package/dist/{credentials-oauth-CAohSLcB.mjs → credentials-oauth-Didpkkjx.mjs} +3 -3
  12. package/dist/{credentials-oauth-CAohSLcB.mjs.map → credentials-oauth-Didpkkjx.mjs.map} +1 -1
  13. package/dist/credentials-oauth.mjs +1 -1
  14. package/dist/host.d.mts +3 -1
  15. package/dist/host.d.mts.map +1 -1
  16. package/dist/host.mjs +4 -3
  17. package/dist/host.mjs.map +1 -1
  18. package/dist/index.d.mts +34 -4
  19. package/dist/index.d.mts.map +1 -1
  20. package/dist/index.mjs +117 -35
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/{pi-ai-Dh7HUxbt.mjs → pi-ai-DpqiLdPA.mjs} +7 -2
  23. package/dist/{pi-ai-Dh7HUxbt.mjs.map → pi-ai-DpqiLdPA.mjs.map} +1 -1
  24. package/dist/{pi-ai-CfokFhIL.d.mts → pi-ai-ZU5MelXy.d.mts} +7 -2
  25. package/dist/{pi-ai-CfokFhIL.d.mts.map → pi-ai-ZU5MelXy.d.mts.map} +1 -1
  26. package/dist/{pi-coding-agent-Cvez0jkF.mjs → pi-coding-agent-DK8hbJP5.mjs} +0 -0
  27. package/dist/{pi-coding-agent-Cvez0jkF.mjs.map → pi-coding-agent-DK8hbJP5.mjs.map} +1 -1
  28. package/dist/{runtime-Dd2KhoX-.mjs → runtime-BiD3SeGf.mjs} +86 -13
  29. package/dist/runtime-BiD3SeGf.mjs.map +1 -0
  30. package/dist/runtime.d.mts +19 -1
  31. package/dist/runtime.d.mts.map +1 -1
  32. package/dist/runtime.mjs +1 -1
  33. package/package.json +8 -6
  34. package/dist/compatibility-Bz6ZXA7F.mjs.map +0 -1
  35. package/dist/runtime-Dd2KhoX-.mjs.map +0 -1
@@ -1,9 +1,9 @@
1
1
 
2
- import { En as PiCapabilityError, F as generateBranchSummary, Tn as CapabilityLedger, b as Theme, d as ExtensionRunner, w as __runWithSubagentSessionFactory } from "./pi-coding-agent-Cvez0jkF.mjs";
2
+ import { En as PiCapabilityError, F as generateBranchSummary, Tn as CapabilityLedger, b as Theme, d as ExtensionRunner, w as __runWithSubagentSessionFactory } from "./pi-coding-agent-DK8hbJP5.mjs";
3
3
  import { t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
4
- import { $ as isContextOverflow, Q as AssistantMessageEventStream, S as getSupportedThinkingLevels, c as builtinProviders, o as __runWithPiAiRuntime, r as __createPiAiRuntimeRegistry } from "./pi-ai-Dh7HUxbt.mjs";
4
+ import { $ as isContextOverflow, Q as AssistantMessageEventStream, S as getSupportedThinkingLevels, c as builtinProviders, o as __runWithPiAiRuntime, r as __createPiAiRuntimeRegistry } from "./pi-ai-DpqiLdPA.mjs";
5
5
  import { W as getKeybindings } from "./pi-tui-DruSeKmd.mjs";
6
- import { a as FileCredentialStore, c as providerSupportsOAuth, i as oauthCredentialRef, l as resolvePiProviderAuth, o as joinSignals, s as loginPiProvider, u as storedOAuthCredential } from "./credentials-oauth-CAohSLcB.mjs";
6
+ import { a as FileCredentialStore, c as providerSupportsOAuth, i as oauthCredentialRef, l as resolvePiProviderAuth, o as joinSignals, s as loginPiProvider, u as storedOAuthCredential } from "./credentials-oauth-Didpkkjx.mjs";
7
7
  import { createRequire } from "node:module";
8
8
  import { access, mkdir, readFile, writeFile } from "node:fs/promises";
9
9
  import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
@@ -358,6 +358,18 @@ var PiSessionBridge = class {
358
358
  //#endregion
359
359
  //#region src/subagent-bridge.ts
360
360
  let subagentSerial = 0;
361
+ /**
362
+ * Cross-scope subscription base. Session events dispatch under the OWNING
363
+ * session's scope; a package instance mounted per Agent registers listeners
364
+ * inside its own Agent's scope and would never see a child session's events.
365
+ * The bridge's callbacks filter by exact session/agent identity, so they
366
+ * subscribe unscoped at the root context — the same posture the old
367
+ * host-level mount had.
368
+ */
369
+ function unscopedEventContext(cordis) {
370
+ const host = cordis;
371
+ return host.root ?? host;
372
+ }
361
373
  /** Flatten a Pi message's content to text for transcript seeding. */
362
374
  function piMessageText(message) {
363
375
  const content = message.content;
@@ -397,7 +409,7 @@ var PiBridgedAgentSession = class {
397
409
  this.#session = handle.agent.session ?? {};
398
410
  this.#tools = tools;
399
411
  this.#activeToolNames = tools.map((tool) => tool?.name).filter((name) => typeof name === "string");
400
- const cordis = host.cordis;
412
+ const cordis = unscopedEventContext(host.cordis);
401
413
  const offEvents = cordis.on("session/event", (session, event) => {
402
414
  if (session !== this.#session) return;
403
415
  this.#project(event);
@@ -596,7 +608,7 @@ var PiBridgedAgentSession = class {
596
608
  type: "text",
597
609
  text: String(text)
598
610
  }]);
599
- const cordis = this.#host.cordis;
611
+ const cordis = unscopedEventContext(this.#host.cordis);
600
612
  const completed = new Promise((resolve) => {
601
613
  const off = cordis.on("session/event", (session, event) => {
602
614
  if (session !== this.#session) return;
@@ -4013,9 +4025,7 @@ function subscribeLifecycle(ctx, state) {
4013
4025
  }
4014
4026
  }
4015
4027
  });
4016
- cordis.on("session/event", (session, event) => {
4017
- const ownedSession = agentSession(state.ownerAgent);
4018
- if (ownedSession !== void 0 ? session !== ownedSession : isSubagentOrigin(session)) return;
4028
+ const projectSessionEvent = (session, event) => {
4019
4029
  const agent = [...state.activeAgents].find((candidate) => candidate.session === session);
4020
4030
  const eventContext = contextFor(ctx, state, agent, void 0);
4021
4031
  const type = event.type;
@@ -4162,6 +4172,14 @@ function subscribeLifecycle(ctx, state) {
4162
4172
  }, eventContext);
4163
4173
  await dispatch(state, "agent_settled", { type: "agent_settled" }, eventContext);
4164
4174
  }).catch((error) => warn("turn end lifecycle", error));
4175
+ };
4176
+ state.projectSessionEvent = projectSessionEvent;
4177
+ cordis.on("session/event", (session, event) => {
4178
+ if (state.hostAnchor) return;
4179
+ const ownedSession = agentSession(state.ownerAgent);
4180
+ if (ownedSession !== void 0 ? session !== ownedSession : isSubagentOrigin(session)) return;
4181
+ if (ownedSession !== void 0 && state.sessionEventsLive !== true) return;
4182
+ projectSessionEvent(session, event);
4165
4183
  });
4166
4184
  cordis.on("agent/request", async (payload, next) => {
4167
4185
  const config = await next();
@@ -4201,9 +4219,35 @@ function subscribeLifecycle(ctx, state) {
4201
4219
  }
4202
4220
  async function flushPendingSessionStarts(ctx, state) {
4203
4221
  state.extensionsReady = true;
4222
+ if (state.ownerAgent !== void 0 && !state.pendingSessionStarts.has(state.ownerAgent)) {
4223
+ const owned = state.ownerAgent;
4224
+ if (!state.activeAgents.has(owned)) {
4225
+ state.activeAgents.add(owned);
4226
+ trackRuntimeSession(state, owned);
4227
+ const session = agentSession(owned);
4228
+ if (session !== void 0) state.bridge.load(session.id);
4229
+ }
4230
+ state.pendingSessionStarts.set(owned, "startup");
4231
+ }
4204
4232
  const pending = [...state.pendingSessionStarts];
4205
4233
  state.pendingSessionStarts.clear();
4206
4234
  for (const [agent, reason] of pending) await startPiSession(ctx, state, agent, reason, void 0);
4235
+ if (state.ownerAgent !== void 0 && state.projectSessionEvent !== void 0) {
4236
+ const session = agentSession(state.ownerAgent);
4237
+ if (session !== void 0) {
4238
+ const events = session.events ?? [];
4239
+ let from = -1;
4240
+ for (let index = events.length - 1; index >= 0; index -= 1) {
4241
+ if (events[index].type === "turn/end") break;
4242
+ if (events[index].type === "turn/start") {
4243
+ from = index;
4244
+ break;
4245
+ }
4246
+ }
4247
+ if (from >= 0) for (let index = from; index < events.length; index += 1) state.projectSessionEvent(session, events[index]);
4248
+ }
4249
+ state.sessionEventsLive = true;
4250
+ }
4207
4251
  }
4208
4252
  /**
4209
4253
  * Start freshly reloaded extension handlers in every live Pi host session.
@@ -4354,7 +4398,7 @@ function subscribeInterceptors(ctx, state) {
4354
4398
  };
4355
4399
  });
4356
4400
  const systemPrompt = optionalService(ctx, "systemPrompt");
4357
- if (systemPrompt !== void 0) ctx.effect(() => systemPrompt.section({
4401
+ if (systemPrompt !== void 0 && !state.hostAnchor) ctx.effect(() => systemPrompt.section({
4358
4402
  name: `pi2dsh:tool-guidance:${state.packageName ?? "pi"}`,
4359
4403
  order: 150,
4360
4404
  text: () => piToolPromptContribution(ctx, state)
@@ -4566,6 +4610,16 @@ function oauthStoreOf(state) {
4566
4610
  }
4567
4611
  const COMPANION_ROUTE_PREFIX = "pi2dsh-companion/";
4568
4612
  const SHARED_HOST_STATE = /* @__PURE__ */ new WeakMap();
4613
+ /**
4614
+ * The engine's own built-in OAuth directory entries, by object identity.
4615
+ * They are login placeholders (no models, no transport), preloaded so
4616
+ * `/login <provider>` works before any package is installed — and a package
4617
+ * registering the SAME provider id owns the richer definition (transport,
4618
+ * catalog, its own flow) and must supersede the placeholder in the shared
4619
+ * ledger. Two PACKAGES colliding on one id still keep first-wins, matching
4620
+ * the route-ownership rule.
4621
+ */
4622
+ const BUILTIN_PROVIDER_SEEDS = /* @__PURE__ */ new WeakSet();
4569
4623
  function sharedHostStateOf(ctx) {
4570
4624
  const key = ctx.root ?? ctx;
4571
4625
  let shared = SHARED_HOST_STATE.get(key);
@@ -5011,6 +5065,10 @@ function registerTool(ctx, state, tool) {
5011
5065
  const normalized = normalizeToolSchema(tool.parameters);
5012
5066
  for (const warning of normalized.warnings) logger(ctx).warn(`[pi2dsh] tool ${tool.name}: ${warning}`);
5013
5067
  state.tools.set(tool.name, tool);
5068
+ if (state.hostAnchor) {
5069
+ state.toolDisposers.set(tool.name, () => {});
5070
+ return;
5071
+ }
5014
5072
  const definition = {
5015
5073
  name: tool.name,
5016
5074
  description: tool.description,
@@ -5071,6 +5129,7 @@ function currentAgent(state) {
5071
5129
  }
5072
5130
  /** Exact-Agent ownership for scoped mounts; legacy root mounts retain their old host-session rule. */
5073
5131
  function acceptsAgent(state, agent) {
5132
+ if (state.hostAnchor) return false;
5074
5133
  if (state.ownerAgent !== void 0) return agent === state.ownerAgent;
5075
5134
  return !isSubagentOrigin(agent);
5076
5135
  }
@@ -5316,6 +5375,7 @@ function registerCommand(ctx, state, command) {
5316
5375
  return;
5317
5376
  }
5318
5377
  state.commands.set(command.name, command);
5378
+ if (state.hostAnchor) return;
5319
5379
  const commands = ctx.get("commands");
5320
5380
  if (commands === void 0) {
5321
5381
  logger(ctx).warn(`[pi2dsh] command /${command.name} was not registered because this DSH composition has no ctx.commands`);
@@ -5490,7 +5550,18 @@ function createPiApi(ctx, state) {
5490
5550
  const name = typeof providerOrName === "string" ? providerOrName : String(providerOrName?.id ?? providerOrName?.name ?? "unnamed");
5491
5551
  const value = typeof providerOrName === "string" ? config ?? {} : providerOrName;
5492
5552
  state.providers.set(name, value);
5493
- if (!state.shared.providers.has(name)) state.shared.providers.set(name, value);
5553
+ const sharedExisting = state.shared.providers.get(name);
5554
+ if (sharedExisting === void 0 || BUILTIN_PROVIDER_SEEDS.has(sharedExisting)) {
5555
+ state.shared.providers.set(name, value);
5556
+ if (sharedExisting !== void 0) {
5557
+ const stale = state.shared.providerRouteDisposers.get(name);
5558
+ if (stale !== void 0) {
5559
+ state.shared.providerRouteDisposers.delete(name);
5560
+ state.shared.providerRouteOwners.delete(name);
5561
+ stale();
5562
+ }
5563
+ }
5564
+ }
5494
5565
  if (providerSupportsOAuth(value)) {
5495
5566
  ensureLoginCommand(ctx, state);
5496
5567
  logger(ctx).info(`[pi2dsh] Pi provider ${JSON.stringify(name)} supports OAuth — log in with /login ${name}`);
@@ -5782,6 +5853,7 @@ async function applyPiPackage(ctx, options) {
5782
5853
  shared,
5783
5854
  packageName: options.manifest.package.name,
5784
5855
  ownerAgent,
5856
+ hostAnchor: options.hostAnchor === true,
5785
5857
  handlers: /* @__PURE__ */ new Map(),
5786
5858
  tools: runtimeTools,
5787
5859
  runner: new ExtensionRunner(piToolRecords),
@@ -5848,6 +5920,7 @@ async function applyPiPackage(ctx, options) {
5848
5920
  baseUrl: provider.baseUrl,
5849
5921
  oauth: provider.auth.oauth
5850
5922
  };
5923
+ BUILTIN_PROVIDER_SEEDS.add(config);
5851
5924
  state.providers.set(provider.id, config);
5852
5925
  if (!shared.providers.has(provider.id)) shared.providers.set(provider.id, config);
5853
5926
  }
@@ -5857,7 +5930,7 @@ async function applyPiPackage(ctx, options) {
5857
5930
  } catch (error) {
5858
5931
  logger(ctx).warn(`[pi2dsh] could not restore the route for logged-in provider ${JSON.stringify(name)}: ${error instanceof Error ? error.message : String(error)}`);
5859
5932
  }
5860
- if (options.manifest.skillDirs.length > 0) {
5933
+ if (options.manifest.skillDirs.length > 0 && state.ownerAgent === void 0) {
5861
5934
  if (ctx.get("skills") === void 0) logger(ctx).warn("[pi2dsh] migrated skills were not mounted because this DSH composition has no ctx.skills");
5862
5935
  else {
5863
5936
  const { apply: applyFilesystemSkills } = await import("@deepseek-ai/dsh-skill-filesystem");
@@ -6014,7 +6087,7 @@ async function applyPiPackage(ctx, options) {
6014
6087
  });
6015
6088
  const health = state.shared.capabilityLedger?.healthOf(state.packageName);
6016
6089
  const healthSuffix = health === void 0 || health.status === "ok" ? "" : ` — ${health.status.toUpperCase()}: missing Pi capabilities ${health.gaps.join(", ")}`;
6017
- logger(ctx).info(`[pi2dsh] loaded ${options.manifest.package.name}: ${state.tools.size} tools, ${state.commands.size} commands, ${options.manifest.skillDirs.length} skill roots${healthSuffix}`);
6090
+ logger(ctx).info(`[pi2dsh] loaded ${options.manifest.package.name}: ${state.tools.size} tools, ${state.commands.size} commands, ${options.manifest.skillDirs.length} skill roots${healthSuffix}${state.hostAnchor ? " (host anchor)" : ""}`);
6018
6091
  }
6019
6092
  const runtimeInternals = {
6020
6093
  compactionReason,
@@ -6031,4 +6104,4 @@ const runtimeInternals = {
6031
6104
  //#endregion
6032
6105
  export { runtimeInternals as i, normalizeToolSchema as n, registerVisionCompanions as r, applyPiPackage as t };
6033
6106
 
6034
- //# sourceMappingURL=runtime-Dd2KhoX-.mjs.map
6107
+ //# sourceMappingURL=runtime-BiD3SeGf.mjs.map