@gotgenes/pi-subagents 16.3.1 → 16.5.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/CHANGELOG.md CHANGED
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [16.5.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v16.4.0...pi-subagents-v16.5.0) (2026-06-17)
9
+
10
+
11
+ ### Features
12
+
13
+ * accumulate live activity in record-observer ([#420](https://github.com/gotgenes/pi-packages/issues/420)) ([c75e7cf](https://github.com/gotgenes/pi-packages/commit/c75e7cf20e44116743fc847238b4364a1edda25a))
14
+ * add live-activity fields to SubagentState ([#420](https://github.com/gotgenes/pi-packages/issues/420)) ([713f19a](https://github.com/gotgenes/pi-packages/commit/713f19aa13306b6c41dc54f3ddfa73fcdfc65427))
15
+ * expose live-activity getters on Subagent ([#420](https://github.com/gotgenes/pi-packages/issues/420)) ([6438d6c](https://github.com/gotgenes/pi-packages/commit/6438d6ca0fdb25b1dfeffa0f76a1eae8630f0cce))
16
+
17
+ ## [16.4.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v16.3.1...pi-subagents-v16.4.0) (2026-06-16)
18
+
19
+
20
+ ### Features
21
+
22
+ * **pi-subagents:** add loadLayeredSettings layered config loader ([2eeba78](https://github.com/gotgenes/pi-packages/commit/2eeba78230bd4537fa568641d4a77a6f1824271c))
23
+ * **pi-subagents:** export loadLayeredSettings via ./settings subpath ([cefe7f6](https://github.com/gotgenes/pi-packages/commit/cefe7f6b7a9133cd0bbcc523ac8b34e48fce0a58))
24
+
8
25
  ## [16.3.1](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v16.3.0...pi-subagents-v16.3.1) (2026-06-16)
9
26
 
10
27
 
package/README.md CHANGED
@@ -360,6 +360,53 @@ When [`@gotgenes/pi-permission-system`](https://github.com/gotgenes/pi-permissio
360
360
  No configuration is required.
361
361
  When `@gotgenes/pi-permission-system` is not installed, the lifecycle events have no subscriber — a harmless no-op.
362
362
 
363
+ ## For Extension Authors
364
+
365
+ This package exposes two public subpath exports for companion extensions to import from the published tarball.
366
+
367
+ ### `@gotgenes/pi-subagents` — cross-extension service contract
368
+
369
+ Access the subagent service from another extension at runtime:
370
+
371
+ ```typescript
372
+ const { getSubagentsService } = await import("@gotgenes/pi-subagents");
373
+ const svc = getSubagentsService();
374
+ svc?.spawn("Explore", "Check for stale TODOs");
375
+ ```
376
+
377
+ Declare this package as an optional peer dependency.
378
+ See `src/service/service.ts` for the full `SubagentsService` interface and the `WorkspaceProvider` seam.
379
+
380
+ ### `@gotgenes/pi-subagents/settings` — layered config loader
381
+
382
+ Extensions that store configuration in JSON files can use the shared layered loader, which reads a global file (`<agentDir>/<filename>`) and a project file (`<cwd>/.pi/<filename>`) and merges them — project wins on conflicts, missing files are silent, malformed files warn and fall back:
383
+
384
+ ```typescript
385
+ import { loadLayeredSettings, type LayeredSettingsSource } from "@gotgenes/pi-subagents/settings";
386
+
387
+ interface MyConfig { enabled?: boolean; limit?: number }
388
+
389
+ function sanitize(raw: unknown): Partial<MyConfig> {
390
+ if (!raw || typeof raw !== "object") return {};
391
+ const r = raw as Record<string, unknown>;
392
+ const out: Partial<MyConfig> = {};
393
+ if (typeof r.enabled === "boolean") out.enabled = r.enabled;
394
+ if (typeof r.limit === "number") out.limit = r.limit;
395
+ return out;
396
+ }
397
+
398
+ const config = loadLayeredSettings<MyConfig>({
399
+ agentDir, // Pi runtime agent home directory
400
+ cwd, // project root — project file lives at <cwd>/.pi/<filename>
401
+ filename: "my-extension.json",
402
+ sanitize,
403
+ warnLabel: "my-extension", // prefix for the malformed-file stderr warning
404
+ });
405
+ ```
406
+
407
+ `loadLayeredSettings` returns `Partial<T>` (all fields optional); apply your defaults after the call.
408
+ It never throws — all error conditions produce a `console.warn` and return `{}`.
409
+
363
410
  ## Architecture
364
411
 
365
412
  This extension is a minimal, composable core: it owns agent spawning, execution, and result retrieval, and exposes a typed `SubagentsService` plus lifecycle events that other extensions build on.
package/dist/public.d.ts CHANGED
@@ -30,12 +30,15 @@ type LifetimeUsage = {
30
30
  };
31
31
 
32
32
  /**
33
- * subagent-state.ts — SubagentState value object: lifecycle status and metrics.
33
+ * subagent-state.ts — SubagentState value object: lifecycle status, metrics, and live activity.
34
34
  *
35
35
  * Owns the passive, readable state of a subagent — status, result, error,
36
- * timestamps, and stats (toolUses, lifetimeUsage, compactionCount) together
37
- * with the transition methods (markRunning, markCompleted, ) and accumulation
38
- * methods (incrementToolUses, addUsage, incrementCompactions) that mutate it.
36
+ * timestamps, stats (toolUses, lifetimeUsage, compactionCount), and live-activity
37
+ * fields (turnCount, activeTools, responseText) together with the transition
38
+ * methods (markRunning, markCompleted, ), accumulation methods
39
+ * (incrementToolUses, addUsage, incrementCompactions), and live-activity
40
+ * transition methods (incrementTurnCount, addActiveTool, removeActiveTool,
41
+ * resetResponseText, appendResponseText) that mutate them.
39
42
  *
40
43
  * State is encapsulated behind getters; external code reads through them but
41
44
  * mutates only via the transition/accumulation methods. The value object owns
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Generic layered settings loader for `@gotgenes/pi-*` extensions.
3
+ *
4
+ * Extensions that store configuration in JSON files under a global agent
5
+ * directory and a per-project `.pi/` folder share the same three-step idiom:
6
+ *
7
+ * 1. Read the global file (`<agentDir>/<filename>`).
8
+ * 2. Read the project file (`<cwd>/.pi/<filename>`).
9
+ * 3. Merge them — project wins on conflicts — and return the result.
10
+ *
11
+ * Both layers are optional: a missing file is silent (`{}`), and a file that
12
+ * cannot be parsed warns to stderr and is treated as absent so startup
13
+ * proceeds normally.
14
+ *
15
+ * ## Usage
16
+ *
17
+ * ```typescript
18
+ * import { loadLayeredSettings, type LayeredSettingsSource } from "@gotgenes/pi-subagents/settings";
19
+ *
20
+ * interface MyConfig { enabled?: boolean; limit?: number }
21
+ *
22
+ * function sanitize(raw: unknown): Partial<MyConfig> {
23
+ * if (!raw || typeof raw !== "object") return {};
24
+ * const r = raw as Record<string, unknown>;
25
+ * const out: Partial<MyConfig> = {};
26
+ * if (typeof r.enabled === "boolean") out.enabled = r.enabled;
27
+ * if (typeof r.limit === "number") out.limit = r.limit;
28
+ * return out;
29
+ * }
30
+ *
31
+ * const config = loadLayeredSettings<MyConfig>({
32
+ * agentDir, // e.g. from the Pi runtime env — the agent home directory
33
+ * cwd, // project root — project file is at <cwd>/.pi/<filename>
34
+ * filename: "my-extension.json",
35
+ * sanitize,
36
+ * warnLabel: "my-extension",
37
+ * });
38
+ * ```
39
+ *
40
+ * @public
41
+ */
42
+ /**
43
+ * Parameters for one layered settings load: describes where the files live,
44
+ * how to validate their contents, and what label to use in warnings.
45
+ *
46
+ * @public
47
+ */
48
+ interface LayeredSettingsSource<T> {
49
+ /** Directory holding the global settings file (typically the Pi agent dir). */
50
+ agentDir: string;
51
+ /** Project root; the project file lives at `<cwd>/.pi/<filename>`. */
52
+ cwd: string;
53
+ /** Base filename for both layers, e.g. `"subagents.json"`. */
54
+ filename: string;
55
+ /**
56
+ * Validate and coerce parsed JSON into a partial settings object.
57
+ * Unknown or invalid fields should be silently dropped — return `{}` for
58
+ * unrecognised shapes. Never throw.
59
+ */
60
+ sanitize: (raw: unknown) => Partial<T>;
61
+ /**
62
+ * Short label used in the malformed-file warning prefix,
63
+ * e.g. `"pi-subagents"` → `"[pi-subagents] Ignoring malformed settings at …"`.
64
+ */
65
+ warnLabel: string;
66
+ }
67
+ /**
68
+ * Load merged layered settings: global provides defaults, project overrides.
69
+ *
70
+ * - A missing file is silent — returns `{}` for that layer.
71
+ * - A file that exists but cannot be parsed warns to stderr and returns `{}` for
72
+ * that layer, so startup proceeds normally.
73
+ * - The two layers are merged with a shallow spread; project keys win.
74
+ *
75
+ * Throws nothing. All error conditions produce a warning and fall back to `{}`.
76
+ *
77
+ * @public
78
+ */
79
+ declare function loadLayeredSettings<T>(source: LayeredSettingsSource<T>): Partial<T>;
80
+
81
+ export { loadLayeredSettings };
82
+ export type { LayeredSettingsSource };