@aeondave/pi-persona 1.16.0 → 1.16.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.
package/AGENTS.md CHANGED
@@ -198,6 +198,8 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
198
198
 
199
199
  ## Testing
200
200
 
201
+ - Offline SDK harnesses must await `session_shutdown` before SDK `dispose()` and temporary-profile
202
+ deletion. `dispose()` disconnects SDK listeners; it does not join extension-owned writers.
201
203
  - TDD: write the failing test first for `core/*` and any behavior change; watch it fail, then fix.
202
204
  - Done = `npm run typecheck` clean **and** full suite green. The suite has **two** intentional skips,
203
205
  both Windows-only — the runner reports `skipped 2` on Windows and `skipped 0` elsewhere (see
package/CHANGELOG.md CHANGED
@@ -6,6 +6,21 @@ used in its [GitHub releases](https://github.com/AeonDave/pi-persona/releases).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.16.1](https://github.com/AeonDave/pi-persona/releases/tag/v1.16.1) - 2026-10-06
10
+
11
+ ### Fixed
12
+
13
+ - Publish the real pending-supervisor-ask state as `agent.updated` telemetry for Flow. Refresh it on
14
+ ask delivery and reply/timeout/cancellation settlement, without duplicate events or text-based
15
+ guesses; queued and terminal state remain authoritative.
16
+ - Make the native offline codemode harness await extension shutdown before deleting its temporary
17
+ profile; SDK `dispose()` alone does not flush the extension's telemetry writer.
18
+
19
+ ### Packaging
20
+
21
+ - Add the npm author and focused Pi gallery keywords; align the banner preview and pinned install
22
+ examples with this release.
23
+
9
24
  ## [1.16.0](https://github.com/AeonDave/pi-persona/releases/tag/v1.16.0) - 2026-10-03
10
25
 
11
26
  ### Compatibility
package/README.md CHANGED
@@ -39,9 +39,9 @@ your customizations.
39
39
  | Install option | Command |
40
40
  |---|---|
41
41
  | This project only | `pi install -l npm:@aeondave/pi-persona` |
42
- | Pin this release | `pi install npm:@aeondave/pi-persona@1.16.0` |
42
+ | Pin this release | `pi install npm:@aeondave/pi-persona@1.16.1` |
43
43
  | Update an unpinned install | `pi update npm:@aeondave/pi-persona` |
44
- | Git alternative | `pi install git:github.com/AeonDave/pi-persona@v1.16.0` |
44
+ | Git alternative | `pi install git:github.com/AeonDave/pi-persona@v1.16.1` |
45
45
 
46
46
  Restart Pi after updating. For a pinned install, install the new version or tag explicitly.
47
47
  If switching from a Git install, remove that source first with
package/docs/TELEMETRY.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Telemetry wire contract
2
2
 
3
+ Agent `waiting` is an explicit projection of a pending supervisor ask, read through the live
4
+ engine steer handle. Ask delivery and settlement (reply, timeout or cancellation) refresh the
5
+ projection; overlapping asks keep it waiting until the last one settles. Queued and terminal
6
+ statuses retain precedence. The producer deduplicates unchanged projections and never infers
7
+ waiting from tool arguments, output text or a quiet clock.
8
+
3
9
  Telemetry is a vendor-neutral v2 envelope. `producerId` and `producerVersion` identify the emitting plugin; `version` identifies the wire schema. `seq` is monotonic only within `(producerId, sessionId)`, and `id` is deduplicated within that same scope.
4
10
 
5
11
  The pi-persona producer writes semantic projections under `telemetry/v2/<workspace>/<producerId>/`. `<workspace>` always identifies the Pi process's actual cwd; joining another Exocom scope does not rewrite telemetry identity. It never persists task/prompt text, tool arguments/activity, model output, paths, secrets, or message bodies. Known pi-persona event payloads are allowlisted; an unreviewed producer event retains only its envelope/type (payload `{}`) at the producer and consumer boundary. Future producers must add a reviewed allowlist/schema before publishing data intended for a consumer.
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@aeondave/pi-persona",
3
- "version": "1.16.0",
3
+ "version": "1.16.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Supervised multi-agent orchestration for Pi — async workers, live steering, cross-session collaboration, and switchable personas.",
7
+ "author": "AeonDave",
7
8
  "repository": {
8
9
  "type": "git",
9
10
  "url": "git+https://github.com/AeonDave/pi-persona.git"
@@ -18,12 +19,16 @@
18
19
  "keywords": [
19
20
  "pi-package",
20
21
  "pi-extension",
22
+ "pi-coding-agent",
21
23
  "pi",
22
- "persona",
23
24
  "subagents",
24
25
  "orchestration",
25
26
  "multi-agent",
26
- "supervisor"
27
+ "supervisor",
28
+ "async-agents",
29
+ "live-steering",
30
+ "cross-session",
31
+ "persona"
27
32
  ],
28
33
  "license": "MIT",
29
34
  "files": [
@@ -99,7 +104,7 @@
99
104
  "typescript": "^7.0.2"
100
105
  },
101
106
  "pi": {
102
- "image": "https://raw.githubusercontent.com/AeonDave/pi-persona/v1.16.0/assets/banner.png",
107
+ "image": "https://raw.githubusercontent.com/AeonDave/pi-persona/v1.16.1/assets/banner.png",
103
108
  "video": "https://cdn.jsdelivr.net/gh/AeonDave/pi-persona@6655d281ce7965a75303dd704bd29db73db04070/assets/demo1.mp4",
104
109
  "extensions": [
105
110
  "./src/extension.ts"
package/src/extension.ts CHANGED
@@ -535,6 +535,8 @@ export default function piPersona(pi: ExtensionAPI, options: PiPersonaOptions =
535
535
  // left hanging when Pi resolves a call as "immediate" and never reaches a result.
536
536
  type PendingIntercomTelemetry = { kind: string; to: string; size: number; replyTo?: string };
537
537
  const telemetryIntercomPending = new Map<string, PendingIntercomTelemetry>();
538
+ // node id → steer that one agent (in-process engine only): inject a live user message.
539
+ const steerRegistry = new Map<string, SteerFn>();
538
540
  function telemetryKind(node: AgentNode): TelemetryAgentKind {
539
541
  if (node.kind) return node.kind;
540
542
  if (node.id.startsWith("flow:")) return "flow";
@@ -547,9 +549,10 @@ export default function piPersona(pi: ExtensionAPI, options: PiPersonaOptions =
547
549
  // "queued" is a marker WE set (the seeded roster / a launched async run), so it is a real
548
550
  // state. Nothing ever sets `detail` to a waiting state — it is a usage string, an error, or
549
551
  // `toolActivity(name, args)`, which splices the tool's own argument text — so a substring
550
- // test for "waiting" could only ever fire on a leg that is running normally.
552
+ // test for "waiting" could only ever fire on a leg that is running normally. A live in-process
553
+ // steer handle has the authoritative bus predicate for a supervisor ask.
551
554
  if (isQueuedMarker(node.detail)) return "queued";
552
- return "running";
555
+ return steerRegistry.get(node.id)?.isWaitingForSupervisor?.() === true ? "waiting" : "running";
553
556
  }
554
557
  function telemetryAgent(node: AgentNode): TelemetryAgentInput {
555
558
  return {
@@ -585,6 +588,22 @@ export default function piPersona(pi: ExtensionAPI, options: PiPersonaOptions =
585
588
  // unfiltered publish appends one byte-identical duplicate per chunk: a 5k-chunk leg writes
586
589
  // ~1.5MB of them and evicts genuine history from the producer's file budget.
587
590
  const lastAgentProjection = new Map<string, string>();
591
+ function publishAgentProjection(node: AgentNode): void {
592
+ const producer = telemetry;
593
+ if (!producer) return;
594
+ const agent = telemetryAgent(node);
595
+ const projection = JSON.stringify(agent);
596
+ if (lastAgentProjection.get(node.id) === projection) return;
597
+ lastAgentProjection.set(node.id, projection);
598
+ producer.publishAgentUpdated(node.id, agent);
599
+ }
600
+ function refreshSteeredAgentTelemetry(): void {
601
+ if (!telemetry || steerRegistry.size === 0) return;
602
+ const steeredIds = new Set(steerRegistry.keys());
603
+ for (const node of agentTree.snapshot()) {
604
+ if (steeredIds.has(node.id)) publishAgentProjection(node);
605
+ }
606
+ }
588
607
  function publishAgentTreeChange(change: AgentTreeChange): void {
589
608
  const producer = telemetry;
590
609
  if (!producer) return;
@@ -594,10 +613,7 @@ export default function piPersona(pi: ExtensionAPI, options: PiPersonaOptions =
594
613
  return;
595
614
  }
596
615
  if (change.type === "updated") {
597
- const projection = JSON.stringify(telemetryAgent(change.node));
598
- if (lastAgentProjection.get(change.node.id) === projection) return;
599
- lastAgentProjection.set(change.node.id, projection);
600
- producer.publishAgentUpdated(change.node.id, telemetryAgent(change.node));
616
+ publishAgentProjection(change.node);
601
617
  return;
602
618
  }
603
619
  if (change.type === "removed") {
@@ -644,8 +660,6 @@ export default function piPersona(pi: ExtensionAPI, options: PiPersonaOptions =
644
660
  return true;
645
661
  }
646
662
 
647
- // node id → steer that one agent (in-process engine only): inject a live user message.
648
- const steerRegistry = new Map<string, SteerFn>();
649
663
  function waitingTreeIds(nodes: readonly AgentNode[] = agentTree.snapshot()): Set<string> {
650
664
  return deriveWaitingNodeIds(nodes, (id) => steerRegistry.get(id)?.isWaitingForSupervisor?.() === true);
651
665
  }
@@ -1063,6 +1077,7 @@ export default function piPersona(pi: ExtensionAPI, options: PiPersonaOptions =
1063
1077
  bus.onAskSettled(({ id }) => {
1064
1078
  intercomNotifier.discard((ask) => ask.askId === id);
1065
1079
  telemetryAskSenders.delete(id);
1080
+ if (!disposed) refreshSteeredAgentTelemetry();
1066
1081
  });
1067
1082
  // Supervisor-armable alarms: when a timer expires it WAKES the session by routing the fire
1068
1083
  // through the same idle-delivery path (an idle delivery starts a fresh turn, so the supervisor
@@ -1144,6 +1159,7 @@ export default function piPersona(pi: ExtensionAPI, options: PiPersonaOptions =
1144
1159
  expectsReply: env.expectsReply,
1145
1160
  size: Buffer.byteLength(env.text, "utf8"),
1146
1161
  });
1162
+ if (!disposed && env.expectsReply) refreshSteeredAgentTelemetry();
1147
1163
  if (disposed || env.to !== SUPERVISOR || !env.expectsReply) return;
1148
1164
  // Only an ask can be replied to, so only an ask needs its sender remembered. Oldest first
1149
1165
  // out: a long session must not grow this without bound.
@@ -4,7 +4,7 @@ export const TELEMETRY_EVENT_NAME = "pi:telemetry" as const;
4
4
  export const LEGACY_TELEMETRY_EVENT_NAME = "pi-persona:telemetry" as const;
5
5
  export const LEGACY_TELEMETRY_VERSION = 1 as const;
6
6
  export const TELEMETRY_PRODUCER_ID = "pi-persona" as const;
7
- export const TELEMETRY_PRODUCER_VERSION = "1.16.0" as const;
7
+ export const TELEMETRY_PRODUCER_VERSION = "1.16.1" as const;
8
8
 
9
9
  export type InstanceStatus = "active" | "idle" | "stopped" | "stale" | (string & {});
10
10
  export type AgentKind = "subagent" | "delegate" | "council" | "flow" | "phase" | (string & {});