@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 +17 -0
- package/README.md +47 -0
- package/dist/public.d.ts +7 -4
- package/dist/settings.d.ts +82 -0
- package/docs/architecture/architecture.md +193 -207
- package/docs/architecture/history/phase-17-core-consolidation.md +214 -0
- package/docs/plans/0378-consolidate-lifecycle-test-fixtures.md +243 -0
- package/docs/plans/0379-consolidate-ui-tools-test-fixtures.md +335 -0
- package/docs/plans/0380-extract-layered-settings-loader.md +223 -0
- package/docs/plans/0412-unify-session-mock-builders.md +146 -0
- package/docs/plans/0420-fold-run-metrics-live-activity-onto-record.md +228 -0
- package/docs/retro/0378-consolidate-lifecycle-test-fixtures.md +100 -0
- package/docs/retro/0379-consolidate-ui-tools-test-fixtures.md +52 -0
- package/docs/retro/0380-extract-layered-settings-loader.md +97 -0
- package/docs/retro/0412-unify-session-mock-builders.md +80 -0
- package/docs/retro/0420-fold-run-metrics-live-activity-onto-record.md +45 -0
- package/package.json +5 -1
- package/src/layered-settings.ts +105 -0
- package/src/lifecycle/subagent-state.ts +49 -4
- package/src/lifecycle/subagent.ts +4 -0
- package/src/observation/record-observer.ts +25 -1
- package/src/settings.ts +10 -23
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
|
|
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,
|
|
37
|
-
*
|
|
38
|
-
* methods (
|
|
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 };
|