@gotgenes/pi-subagents 12.0.0 → 13.0.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 +22 -0
- package/dist/public.d.ts +1 -3
- package/docs/architecture/architecture.md +28 -32
- package/docs/plans/0264-remove-extension-lifecycle-control.md +275 -0
- package/docs/plans/0272-export-workspace-collaborator-types.md +147 -0
- package/docs/retro/0264-remove-extension-lifecycle-control.md +48 -0
- package/docs/retro/0272-export-workspace-collaborator-types.md +38 -0
- package/package.json +1 -1
- package/src/config/agent-types.ts +0 -2
- package/src/config/custom-agents.ts +0 -30
- package/src/config/default-agents.ts +1 -7
- package/src/config/invocation-config.ts +0 -3
- package/src/index.ts +0 -2
- package/src/lifecycle/agent-manager.ts +0 -2
- package/src/lifecycle/agent-runner.ts +6 -14
- package/src/lifecycle/agent.ts +0 -4
- package/src/service/service-adapter.ts +0 -1
- package/src/service/service.ts +20 -9
- package/src/session/prompts.ts +2 -23
- package/src/session/session-config.ts +2 -37
- package/src/tools/agent-tool.ts +0 -5
- package/src/tools/background-spawner.ts +0 -1
- package/src/tools/foreground-runner.ts +0 -1
- package/src/tools/spawn-config.ts +0 -4
- package/src/types.ts +0 -7
- package/src/ui/agent-config-editor.ts +0 -5
- package/src/ui/agent-creation-wizard.ts +0 -4
- package/src/ui/display.ts +1 -2
- package/src/session/safe-fs.ts +0 -45
- package/src/session/skill-loader.ts +0 -104
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,28 @@ 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
|
+
## [13.0.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v12.1.0...pi-subagents-v13.0.0) (2026-05-30)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### ⚠ BREAKING CHANGES
|
|
12
|
+
|
|
13
|
+
* the `skills:` custom-agent frontmatter key and skill preloading are removed; children always load the parent's skills.
|
|
14
|
+
* the `extensions:` custom-agent frontmatter key is removed; children always load the parent's extensions.
|
|
15
|
+
* `SpawnOptions.isolated` and the `isolated:` custom-agent frontmatter key are removed. Children always load the parent's extensions.
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* always inherit extensions; make the recursion guard unconditional ([#264](https://github.com/gotgenes/pi-packages/issues/264)) ([3cc682e](https://github.com/gotgenes/pi-packages/commit/3cc682ec401167f922a1f892f6260a10f9fa99f2))
|
|
20
|
+
* always inherit skills; remove noSkills and the skill-preload path ([#264](https://github.com/gotgenes/pi-packages/issues/264)) ([93266ff](https://github.com/gotgenes/pi-packages/commit/93266ff4a204d154b357efac57912330fad240be))
|
|
21
|
+
* remove isolated from the subagent spawn API and lifecycle ([#264](https://github.com/gotgenes/pi-packages/issues/264)) ([d08f340](https://github.com/gotgenes/pi-packages/commit/d08f34066ea472d850423e67349b7a623ca72f42))
|
|
22
|
+
|
|
23
|
+
## [12.1.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v12.0.0...pi-subagents-v12.1.0) (2026-05-29)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Features
|
|
27
|
+
|
|
28
|
+
* export WorkspaceProvider collaborator types by name ([#272](https://github.com/gotgenes/pi-packages/issues/272)) ([1ff4697](https://github.com/gotgenes/pi-packages/commit/1ff4697a3033be445340d18af005a5d34fb5934d))
|
|
29
|
+
|
|
8
30
|
## [12.0.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v11.6.0...pi-subagents-v12.0.0) (2026-05-29)
|
|
9
31
|
|
|
10
32
|
|
package/dist/public.d.ts
CHANGED
|
@@ -25,7 +25,6 @@ interface AgentInvocation {
|
|
|
25
25
|
modelName?: string;
|
|
26
26
|
thinking?: ThinkingLevel;
|
|
27
27
|
maxTurns?: number;
|
|
28
|
-
isolated?: boolean;
|
|
29
28
|
inheritContext?: boolean;
|
|
30
29
|
runInBackground?: boolean;
|
|
31
30
|
}
|
|
@@ -125,7 +124,6 @@ interface SpawnOptions {
|
|
|
125
124
|
model?: string;
|
|
126
125
|
maxTurns?: number;
|
|
127
126
|
thinkingLevel?: string;
|
|
128
|
-
isolated?: boolean;
|
|
129
127
|
inheritContext?: boolean;
|
|
130
128
|
foreground?: boolean;
|
|
131
129
|
bypassQueue?: boolean;
|
|
@@ -167,4 +165,4 @@ declare function getSubagentsService(): SubagentsService | undefined;
|
|
|
167
165
|
declare function unpublishSubagentsService(): void;
|
|
168
166
|
|
|
169
167
|
export { SUBAGENT_EVENTS, getSubagentsService, publishSubagentsService, unpublishSubagentsService };
|
|
170
|
-
export type { LifetimeUsage, SpawnOptions, SubagentRecord, SubagentStatus, SubagentsService, WorkspaceProvider };
|
|
168
|
+
export type { LifetimeUsage, SpawnOptions, SubagentRecord, SubagentStatus, SubagentsService, Workspace, WorkspaceDisposeOutcome, WorkspaceDisposeResult, WorkspacePrepareContext, WorkspaceProvider };
|
|
@@ -45,8 +45,6 @@ flowchart TB
|
|
|
45
45
|
SessionConfig["assembleSessionConfig<br/>(pure assembler)"]
|
|
46
46
|
Prompts["prompts<br/>(system prompt)"]
|
|
47
47
|
Context["context<br/>(parent history)"]
|
|
48
|
-
SafeFs["safe-fs<br/>(symlink/name guards)"]
|
|
49
|
-
SkillLoader["skill-loader<br/>(preload skills)"]
|
|
50
48
|
Env["env<br/>(git/platform)"]
|
|
51
49
|
ModelResolver["model-resolver<br/>(fuzzy match)"]
|
|
52
50
|
end
|
|
@@ -90,8 +88,7 @@ flowchart TB
|
|
|
90
88
|
AgentManager --> AgentRunner
|
|
91
89
|
AgentRunner --> SessionConfig
|
|
92
90
|
SessionConfig --> AgentTypeRegistry
|
|
93
|
-
SessionConfig --> Prompts &
|
|
94
|
-
SkillLoader --> SafeFs
|
|
91
|
+
SessionConfig --> Prompts & Env
|
|
95
92
|
AgentTypeRegistry --> DefaultAgents & CustomAgents
|
|
96
93
|
RecordObserver -.->|subscribes| AgentRunner
|
|
97
94
|
UIObserver -.->|subscribes| AgentRunner
|
|
@@ -260,8 +257,6 @@ src/
|
|
|
260
257
|
│ ├── prompts.ts system prompt building
|
|
261
258
|
│ ├── content-items.ts shared message content parsing (tool-call names, assistant content)
|
|
262
259
|
│ ├── context.ts parent conversation extraction
|
|
263
|
-
│ ├── safe-fs.ts symlink rejection and safe file reads
|
|
264
|
-
│ ├── skill-loader.ts skill preloading
|
|
265
260
|
│ ├── env.ts git/platform detection
|
|
266
261
|
│ ├── model-resolver.ts fuzzy model name resolution
|
|
267
262
|
│ └── session-dir.ts session directory derivation
|
|
@@ -415,7 +410,7 @@ Key types:
|
|
|
415
410
|
|
|
416
411
|
- `SubagentsService` — `spawn`, `getRecord`, `listAgents`, `abort`, `steer`, `waitForAll`, `hasRunning`.
|
|
417
412
|
- `SubagentRecord` — serializable agent snapshot (no live session objects).
|
|
418
|
-
- `SpawnOptions` — `description`, `model`, `maxTurns`, `thinkingLevel`, `
|
|
413
|
+
- `SpawnOptions` — `description`, `model`, `maxTurns`, `thinkingLevel`, `inheritContext`, `foreground`, `bypassQueue`.
|
|
419
414
|
- `SUBAGENT_EVENTS` — channel constants for `pi.events` subscriptions.
|
|
420
415
|
|
|
421
416
|
### Accessor pattern
|
|
@@ -482,11 +477,11 @@ Latent extensibility is the deliverable; a vacant hook is not.
|
|
|
482
477
|
### Core responsibilities (keep)
|
|
483
478
|
|
|
484
479
|
- **Agent definitions** — name, model, thinking, system prompt, tools list.
|
|
485
|
-
- **Prompt composition** — system prompt assembly
|
|
480
|
+
- **Prompt composition** — system prompt assembly.
|
|
486
481
|
- **Session lifecycle** — create child sessions, bind extensions, run conversation loop, track results.
|
|
487
482
|
- **Concurrency management** — queue, abort, resume, max concurrency.
|
|
488
483
|
- **Recursion guard** — remove pi-subagents' own three tools from child sessions (prevent infinite nesting).
|
|
489
|
-
With `isolated` removed, children always load the parent's resources, so the guard
|
|
484
|
+
With `isolated` removed (#264), children always load the parent's resources, so the guard is unconditional rather than gated on `cfg.extensions`.
|
|
490
485
|
This is the core defending its own invariant, keyed off its own tool names — not policy.
|
|
491
486
|
- **Lifecycle events** — emit awaited, ordered events when child sessions spawn, are created, complete, and are disposed.
|
|
492
487
|
- **Workspace provider seam** — accept a registered `WorkspaceProvider` and consult it for the child's cwd; default to the parent's cwd when none is registered.
|
|
@@ -499,7 +494,8 @@ Latent extensibility is the deliverable; a vacant hook is not.
|
|
|
499
494
|
- **Worktree isolation** (`worktree.ts`, `worktree-isolation.ts`, `GitWorktreeManager`, the `isolation: "worktree"` spawn mode) — environment policy, not core.
|
|
500
495
|
Git worktrees are one *strategy* for choosing the child's working directory; containers, throwaway tmpdirs, and remote sandboxes are others.
|
|
501
496
|
Evicted to `@gotgenes/pi-subagents-worktrees` (#263), the first consumer of the workspace provider seam.
|
|
502
|
-
- **Extension lifecycle control** (`extensions: false`, `isolated`, `noSkills`) —
|
|
497
|
+
- **Extension lifecycle control** (`extensions: false`, `isolated`, `noSkills`) — removed in #264.
|
|
498
|
+
Deny-at-use (the in-child permission layer blocking disallowed tool calls) covers what `isolated` pretended to do for tools.
|
|
503
499
|
Prevent-load (refusing to bind an extension because of load-time side effects, cost, or true sandboxing) is genuinely generative and is left as a *latent* (un-built) provider seam, added only if a real consumer needs it.
|
|
504
500
|
|
|
505
501
|
### Composition model
|
|
@@ -536,20 +532,20 @@ This is achieved across phases: Phase 14 (strip policy), Phase 16 (invert depend
|
|
|
536
532
|
These interfaces carry hidden dependencies that obscure true coupling.
|
|
537
533
|
Bags with 10+ fields are the highest priority for decomposition.
|
|
538
534
|
|
|
539
|
-
| Interface | Fields
|
|
540
|
-
| --------------------------- |
|
|
541
|
-
| `ResolvedSpawnConfig` | 3 nested
|
|
542
|
-
| `AgentSpawnConfig` | 13 → 13 (ParentSessionInfo nested)
|
|
543
|
-
| `RunOptions` | 9 (`RunContext` nested)
|
|
544
|
-
| `SessionConfig` |
|
|
545
|
-
| `NotificationDetails` | 10
|
|
546
|
-
| `ResourceLoaderOptions` | 10
|
|
547
|
-
| `RunnerIO` | split → `EnvironmentIO` (3) + `SessionFactoryIO` (5+1)
|
|
548
|
-
| `CreateSessionOptions` | 9
|
|
549
|
-
| `AgentToolDeps` | 8
|
|
550
|
-
| `AgentMenuDeps` | 8
|
|
551
|
-
| `ConversationViewerOptions` | 8
|
|
552
|
-
| `AgentInit` | 8
|
|
535
|
+
| Interface | Fields | Consumers | Severity |
|
|
536
|
+
| --------------------------- | ----------------------------------------------------------- | ------------------------------------------------- | --------- |
|
|
537
|
+
| `ResolvedSpawnConfig` | 3 nested | foreground-runner, background-spawner, agent-tool | ✓ done |
|
|
538
|
+
| `AgentSpawnConfig` | 13 → 13 (ParentSessionInfo nested) | agent-manager (internal) | ✓ done |
|
|
539
|
+
| `RunOptions` | 9 (`RunContext` nested) | agent-runner | ✓ done |
|
|
540
|
+
| `SessionConfig` | 6 (flat fields; extensions/noSkills/extras removed in #264) | agent-runner (output of assembler) | ✓ done |
|
|
541
|
+
| `NotificationDetails` | 10 | notification | Low (DTO) |
|
|
542
|
+
| `ResourceLoaderOptions` | 10 | agent-runner (SDK bridge) | Low (SDK) |
|
|
543
|
+
| `RunnerIO` | split → `EnvironmentIO` (3) + `SessionFactoryIO` (5+1) | agent-runner | ✓ done |
|
|
544
|
+
| `CreateSessionOptions` | 9 | agent-runner (SDK bridge) | Low (SDK) |
|
|
545
|
+
| `AgentToolDeps` | 8 | agent-tool | ✓ done |
|
|
546
|
+
| `AgentMenuDeps` | 8 | agent-menu | ✓ done |
|
|
547
|
+
| `ConversationViewerOptions` | 8 | conversation-viewer | Low |
|
|
548
|
+
| `AgentInit` | 8 | agent | Low |
|
|
553
549
|
|
|
554
550
|
### Complexity hotspots
|
|
555
551
|
|
|
@@ -604,7 +600,6 @@ interface SpawnExecution {
|
|
|
604
600
|
thinking: ThinkingLevel | undefined;
|
|
605
601
|
inheritContext: boolean;
|
|
606
602
|
runInBackground: boolean;
|
|
607
|
-
isolated: boolean;
|
|
608
603
|
agentInvocation: AgentInvocation;
|
|
609
604
|
}
|
|
610
605
|
|
|
@@ -648,7 +643,7 @@ export interface RunContext {
|
|
|
648
643
|
}
|
|
649
644
|
```
|
|
650
645
|
|
|
651
|
-
The remaining `RunOptions` fields (`model`, `maxTurns`, `signal`, `
|
|
646
|
+
The remaining `RunOptions` fields (`model`, `maxTurns`, `signal`, `thinkingLevel`, `defaultMaxTurns`, `graceTurns`, `onSessionCreated`) are genuine execution parameters.
|
|
652
647
|
`RunOptions` now has 9 fields: 1 nested `context: RunContext` (2 per-call fields) plus 8 flat execution fields.
|
|
653
648
|
|
|
654
649
|
#### SessionConfig (11 fields → extract ToolFilterConfig) — done ([#168][168])
|
|
@@ -761,7 +756,7 @@ Migrate `@gotgenes/pi-permission-system` to subscribe to `session-created`/`disp
|
|
|
761
756
|
#### Step 2: Define the `WorkspaceProvider` seam — [#262] ✅ Delivered
|
|
762
757
|
|
|
763
758
|
Added the `WorkspaceProvider` / `Workspace` interfaces (`src/lifecycle/workspace.ts`) and `SubagentsService.registerWorkspaceProvider` (single provider, throws on duplicate, returns an unregister disposer).
|
|
764
|
-
|
|
759
|
+
All five workspace types are named-re-exported from `service.ts`: `WorkspaceProvider`, `Workspace`, `WorkspacePrepareContext`, `WorkspaceDisposeOutcome`, and `WorkspaceDisposeResult` (added in #272).
|
|
765
760
|
At run-start `Agent.run()` consults the registered provider for the child's cwd and a disposal handle; with no provider the child runs in the parent's cwd (the legacy worktree-collaborator fallback was removed when worktrees left the core in #263).
|
|
766
761
|
On completion the core calls `Workspace.dispose({ status, description })` and appends the returned `resultAddendum` verbatim — the provider owns the wording.
|
|
767
762
|
|
|
@@ -778,16 +773,17 @@ Removed `worktree.ts`, `worktree-isolation.ts`, `GitWorktreeManager`, and the `i
|
|
|
778
773
|
|
|
779
774
|
- Supersedes #256.
|
|
780
775
|
New package registered in `release-please-config.json` and `.pi/settings.json` (after pi-subagents); consumes the published `@gotgenes/pi-subagents` from the registry (`linkWorkspacePackages: false`), since `exports.types` resolves to the shipped declaration bundle.
|
|
781
|
-
|
|
776
|
+
From the release carrying #272, all five workspace types are importable by name: `WorkspaceProvider`, `Workspace`, `WorkspacePrepareContext`, `WorkspaceDisposeOutcome`, and `WorkspaceDisposeResult`.
|
|
782
777
|
- Outcome: git leaves the core; worktree users install one package, everyone else pays nothing.
|
|
783
778
|
|
|
784
|
-
#### Step 4: Remove `isolated` / `extensions: false` / `noSkills` — [#264]
|
|
779
|
+
#### Step 4: Remove `isolated` / `extensions: false` / `noSkills` — [#264] ✅ Delivered
|
|
785
780
|
|
|
786
|
-
Children always load the parent's extensions and skills; the recursion guard
|
|
781
|
+
Children always load the parent's extensions and skills; the recursion guard is now unconditional.
|
|
787
782
|
Deny-at-use (the in-child permission layer) covers tool restriction; prevent-load is left as a latent provider seam (not shipped).
|
|
783
|
+
The `skills` curation axis collapsed symmetrically with `extensions`: `AgentConfig.skills`, the skill-preload path (`skill-loader.ts`, `safe-fs.ts`, `preloadSkills`, `PromptExtras`), `SessionConfig.{extensions,noSkills,extras}`, and the `isolated:` / `extensions:` / `skills:` custom-agent frontmatter keys are all gone.
|
|
788
784
|
|
|
789
|
-
-
|
|
790
|
-
- Outcome: the `isolated`/`extensions`/`noSkills` axis is gone;
|
|
785
|
+
- Depended on: Step 1 (deny-at-use over events).
|
|
786
|
+
- Outcome: the `isolated`/`extensions`/`noSkills`/`skills` axis is gone; the guard is unconditional.
|
|
791
787
|
|
|
792
788
|
#### Step 5: Born-complete child execution; dissolve the runner — [#265]
|
|
793
789
|
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
---
|
|
2
|
+
issue: 264
|
|
3
|
+
issue_title: "Remove isolated / extensions:false / noSkills from core"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Remove the extension-lifecycle-control axis from the core
|
|
7
|
+
|
|
8
|
+
## Problem Statement
|
|
9
|
+
|
|
10
|
+
The core still carries an extension-lifecycle-control axis — `isolated`, `extensions: false`, and `noSkills` — that lets a spawn blanket-disable a child's extensions and skills.
|
|
11
|
+
Per ADR 0002, this is policy that does not belong in a minimal orchestrator.
|
|
12
|
+
Deny-at-use (the in-child permission layer, shipped in Step 1 / #261) already covers what `isolated` pretended to do for tools.
|
|
13
|
+
Prevent-load (refusing to bind an extension for true sandboxing) is genuinely generative and is deliberately left as a *latent, un-built* provider seam — we do not ship a vacant hook.
|
|
14
|
+
|
|
15
|
+
This is Phase 16, Step 4.
|
|
16
|
+
With the axis gone, children always load the parent's extensions and skills, and the recursion guard — which currently gates on `cfg.extensions` — becomes unconditional.
|
|
17
|
+
|
|
18
|
+
## Goals
|
|
19
|
+
|
|
20
|
+
- Remove `isolated` from the spawn API, `SubagentsService`, the lifecycle plumbing, and the config assembler.
|
|
21
|
+
- Remove the `extensions` boolean from `AgentConfig` and the assembler (children always inherit extensions).
|
|
22
|
+
- Remove `noSkills` from the assembler and the resource-loader options.
|
|
23
|
+
- Collapse the skill-curation axis symmetrically: remove `AgentConfig.skills` and the skill-**preload** path (`skill-loader.ts`, `safe-fs.ts`, `preloadSkills`, `PromptExtras`, `extras.skillBlocks`).
|
|
24
|
+
Children always load Pi's full skill system, exactly as `skills: true` does today.
|
|
25
|
+
- Make the recursion guard unconditional — it always strips `subagent` / `get_subagent_result` / `steer_subagent` from children, keyed off the core's own tool names.
|
|
26
|
+
- This is a **breaking** change: the public `SpawnOptions.isolated` field and the `isolated:` / `extensions:` / `skills:` custom-agent frontmatter keys are removed.
|
|
27
|
+
Suggested commits use `feat!:`.
|
|
28
|
+
|
|
29
|
+
## Non-Goals
|
|
30
|
+
|
|
31
|
+
- Born-complete child execution / dissolving the runner — that is Step 5 (#265) and depends on this step.
|
|
32
|
+
`RunOptions`, `runAgent`, `ConcreteAgentRunner`, and `Agent.run()` survive this issue (with `isolated` removed from them).
|
|
33
|
+
- Shipping a prevent-load provider seam — ADR 0002 leaves it latent until a real consumer needs it.
|
|
34
|
+
- Changing `builtinToolNames` (the `tools:` frontmatter allowlist) — that is a separate, surviving concern.
|
|
35
|
+
- Changing deny-at-use behavior in `@gotgenes/pi-permission-system` — already in place from #261.
|
|
36
|
+
|
|
37
|
+
## Background
|
|
38
|
+
|
|
39
|
+
Relevant modules and how they relate:
|
|
40
|
+
|
|
41
|
+
- `src/types.ts` — declares `AgentConfig` (`extensions`, `skills`, `isolated`) and `AgentInvocation` (`isolated`).
|
|
42
|
+
- `src/config/default-agents.ts` — the three embedded agents set `extensions: true`, `skills: true`.
|
|
43
|
+
- `src/config/custom-agents.ts` — parses `extensions` / `skills` / `isolated` from `.md` frontmatter via `resolveBoolExtensions` and `inheritField`.
|
|
44
|
+
- `src/config/invocation-config.ts` — merges `isolated` from agent config + tool params.
|
|
45
|
+
- `src/config/agent-types.ts` — an absolute-fallback `AgentConfig` literal sets `extensions: true`, `skills: true`.
|
|
46
|
+
- `src/session/session-config.ts` — `assembleSessionConfig` derives `extensions`/`skills` from `options.isolated`, calls `io.preloadSkills` when `skills` is `string[]`, and computes `noSkills`.
|
|
47
|
+
Returns `SessionConfig.{ extensions, noSkills, extras }`.
|
|
48
|
+
- `src/session/prompts.ts` — `buildAgentPrompt` injects `extras.skillBlocks` as `# Preloaded Skill:` sections; `PromptExtras` carries only `skillBlocks` (memory was removed in #185).
|
|
49
|
+
- `src/session/skill-loader.ts` — `preloadSkills` reads named skill files from disk; consumes `safe-fs.ts`.
|
|
50
|
+
- `src/session/safe-fs.ts` — symlink/path-traversal guards; **only consumer is `skill-loader.ts`**.
|
|
51
|
+
- `src/lifecycle/agent-runner.ts` — `RunOptions.isolated` flows into the assembler; `createResourceLoader` is called with `noExtensions: !cfg.extensions` and `noSkills: cfg.noSkills`; the recursion guard runs only `if (cfg.extensions)`.
|
|
52
|
+
`ResourceLoaderOptions` (a local narrow interface, not the SDK type) declares `noExtensions?` / `noSkills?`.
|
|
53
|
+
- `src/lifecycle/agent.ts` — `AgentInit.isolated`, the `_isolated` field, and `isolated:` in the `runner.run(...)` call.
|
|
54
|
+
- `src/lifecycle/agent-manager.ts` — `AgentSpawnConfig.isolated` and its pass-through to `new Agent(...)`.
|
|
55
|
+
- `src/tools/{agent-tool,spawn-config,foreground-runner,background-spawner}.ts` — tool schema `isolated`, `SpawnExecution.isolated`, and pass-through.
|
|
56
|
+
- `src/service/{service,service-adapter}.ts` — public `SpawnOptions.isolated` and its pass-through to the manager.
|
|
57
|
+
- `src/ui/{display,agent-config-editor,agent-creation-wizard}.ts` — `isolated` tag, eject-content emission, and generation-prompt template text.
|
|
58
|
+
- `src/index.ts` — wires `preloadSkills` and `buildAgentPrompt` into `assemblerIO`.
|
|
59
|
+
|
|
60
|
+
AGENTS.md constraints that apply:
|
|
61
|
+
|
|
62
|
+
- Conventional Commits; breaking changes use `feat!:`.
|
|
63
|
+
- Do not edit `CHANGELOG.md` (release-please owns it).
|
|
64
|
+
- When removing an export, grep all `src/` and `test/` for the symbol before finalizing (done below).
|
|
65
|
+
- When adding/removing a module, check `docs/architecture/` for layout listings and complexity tables that reference it (done below — Mermaid + tree + field tables).
|
|
66
|
+
- One-sentence-per-line markdown; sequential numbering restarting per heading.
|
|
67
|
+
|
|
68
|
+
## Design Overview
|
|
69
|
+
|
|
70
|
+
This is a **symmetric collapse**, not a refactor.
|
|
71
|
+
Two parallel axes leave the core together:
|
|
72
|
+
|
|
73
|
+
| Axis | Today | After |
|
|
74
|
+
| ---------- | -------------------------------------------------------------- | --------------------------------------------- |
|
|
75
|
+
| Extensions | `extensions: true \| false`; `isolated` forces `false` | always inherit (field gone) |
|
|
76
|
+
| Skills | `skills: true \| string[] \| false`; `isolated` forces `false` | always inherit full skill system (field gone) |
|
|
77
|
+
|
|
78
|
+
The `skills` field collapses for the same reason `extensions` does: `noSkills` is the single mechanism behind **both** restriction modes (`skills: false` → no skills; `skills: string[]` → only those, preloaded into the prompt with the SDK loader suppressed).
|
|
79
|
+
Removing `noSkills` without removing `AgentConfig.skills` would leave a field that silently stops restricting — a `string[]` agent would get its baked-in skills *plus* the full system.
|
|
80
|
+
ADR 0002 says children always load the parent's skills, which is exactly the `skills: true` path; the other two values are skill curation/policy and leave the core.
|
|
81
|
+
|
|
82
|
+
### Assembler after collapse
|
|
83
|
+
|
|
84
|
+
`assembleSessionConfig` loses the `isolated` branch, the `preloadSkills` block, and the `noSkills`/`extensions`/`extras` outputs:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
export interface AssemblerOptions {
|
|
88
|
+
cwd?: string;
|
|
89
|
+
model?: unknown;
|
|
90
|
+
thinkingLevel?: ThinkingLevel;
|
|
91
|
+
// isolated removed
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface SessionConfig {
|
|
95
|
+
effectiveCwd: string;
|
|
96
|
+
systemPrompt: string;
|
|
97
|
+
toolNames: string[];
|
|
98
|
+
model: unknown;
|
|
99
|
+
thinkingLevel: ThinkingLevel | undefined;
|
|
100
|
+
agentMaxTurns: number | undefined;
|
|
101
|
+
// extensions, noSkills, extras removed
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`AssemblerIO` drops `preloadSkills`, keeping only `buildAgentPrompt` (now called without `extras`).
|
|
106
|
+
|
|
107
|
+
### Runner after collapse
|
|
108
|
+
|
|
109
|
+
The resource-loader call drops the two suppression flags, and the guard runs unconditionally:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
const loader = deps.io.createResourceLoader({
|
|
113
|
+
cwd: cfg.effectiveCwd,
|
|
114
|
+
agentDir,
|
|
115
|
+
noPromptTemplates: true,
|
|
116
|
+
noThemes: true,
|
|
117
|
+
noContextFiles: true,
|
|
118
|
+
systemPromptOverride: () => cfg.systemPrompt,
|
|
119
|
+
appendSystemPromptOverride: () => [],
|
|
120
|
+
// noExtensions, noSkills removed
|
|
121
|
+
});
|
|
122
|
+
// ...
|
|
123
|
+
await session.bindExtensions({});
|
|
124
|
+
// Recursion guard — now unconditional (children always load extensions).
|
|
125
|
+
const filtered = filterActiveTools(session.getActiveToolNames());
|
|
126
|
+
session.setActiveToolsByName(filtered);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
`ResourceLoaderOptions` drops `noExtensions?` / `noSkills?` (a local narrow interface — removing the latent fields keeps us honest per ADR 0002's "no vacant hooks").
|
|
130
|
+
|
|
131
|
+
### Call-site sketch — recursion guard (Tell-Don't-Ask check)
|
|
132
|
+
|
|
133
|
+
The guard already asks the session for its active tools and tells it the filtered set — unchanged except for removing the `if`.
|
|
134
|
+
No new collaborator, no reach-through; the only structural change is that `cfg.extensions` is no longer consulted, so `SessionConfig` no longer needs to expose it.
|
|
135
|
+
This is a narrowing of the assembler's output contract, which is the desired direction.
|
|
136
|
+
|
|
137
|
+
### Edge cases
|
|
138
|
+
|
|
139
|
+
- Append-mode agents: `parentSystemPrompt` still embeds parent context via `systemPromptOverride`; nothing about that path depends on skills/extensions flags.
|
|
140
|
+
- Custom agents with legacy `extensions:` / `skills:` / `isolated:` frontmatter: the keys are silently ignored after this change (no parse, no warning).
|
|
141
|
+
`resolveBoolExtensions` already warned on the deprecated allowlist syntax; that warning path is removed with the parser.
|
|
142
|
+
- The absolute-fallback `AgentConfig` in `agent-types.ts` drops `extensions`/`skills` like every other construction site.
|
|
143
|
+
|
|
144
|
+
## Module-Level Changes
|
|
145
|
+
|
|
146
|
+
### Source — `isolated` axis
|
|
147
|
+
|
|
148
|
+
- `src/types.ts` — remove `AgentConfig.isolated`, `AgentInvocation.isolated`.
|
|
149
|
+
- `src/config/invocation-config.ts` — remove `isolated` from `AgentInvocationParams` and the return object.
|
|
150
|
+
- `src/config/custom-agents.ts` — remove the `isolated:` frontmatter parse.
|
|
151
|
+
- `src/session/session-config.ts` — remove `AssemblerOptions.isolated` and the `options.isolated ? false : ...` derivation (read `agentConfig.extensions`/`agentConfig.skills` directly, for now).
|
|
152
|
+
- `src/lifecycle/agent-runner.ts` — remove `RunOptions.isolated` and the `isolated:` argument passed to `assembleSessionConfig`.
|
|
153
|
+
- `src/lifecycle/agent.ts` — remove `AgentInit.isolated`, the `_isolated` field + constructor assignment, and `isolated:` in the `runner.run(...)` call.
|
|
154
|
+
- `src/lifecycle/agent-manager.ts` — remove `AgentSpawnConfig.isolated` and its pass-through to `new Agent(...)`.
|
|
155
|
+
- `src/tools/agent-tool.ts` — remove the `isolated` schema property.
|
|
156
|
+
- `src/tools/spawn-config.ts` — remove `SpawnExecution.isolated`, the `const isolated = resolvedConfig.isolated`, `isolated` in `agentInvocation`, and `isolated` in the `execution` return.
|
|
157
|
+
- `src/tools/foreground-runner.ts` / `src/tools/background-spawner.ts` — remove `isolated: execution.isolated`.
|
|
158
|
+
- `src/service/service.ts` — remove `SpawnOptions.isolated`.
|
|
159
|
+
- `src/service/service-adapter.ts` — remove `isolated: options?.isolated` from the `manager.spawn(...)` call.
|
|
160
|
+
- `src/ui/display.ts` — remove `if (invocation.isolated) tags.push("isolated")` and the `isolated` mention in the JSDoc example.
|
|
161
|
+
- `src/ui/agent-config-editor.ts` — remove the `isolated: true` line from `buildEjectContent`.
|
|
162
|
+
- `src/ui/agent-creation-wizard.ts` — remove the `isolated:` template line and the "Set isolated: true …" guideline.
|
|
163
|
+
|
|
164
|
+
### Source — `extensions` axis + unconditional guard
|
|
165
|
+
|
|
166
|
+
- `src/types.ts` — remove `AgentConfig.extensions`.
|
|
167
|
+
- `src/config/default-agents.ts` — remove `extensions: true` from all three agents.
|
|
168
|
+
- `src/config/agent-types.ts` — remove `extensions: true` from the absolute-fallback literal.
|
|
169
|
+
- `src/config/custom-agents.ts` — remove the `extensions:` frontmatter parse and delete `resolveBoolExtensions`.
|
|
170
|
+
- `src/session/session-config.ts` — remove `SessionConfig.extensions` and stop assigning it.
|
|
171
|
+
- `src/lifecycle/agent-runner.ts` — remove `ResourceLoaderOptions.noExtensions`, drop `noExtensions` from the `createResourceLoader` call, and make the recursion guard unconditional (delete `if (cfg.extensions)`); update the explanatory comment.
|
|
172
|
+
- `src/ui/agent-config-editor.ts` — remove the `extensions: false` line from `buildEjectContent`.
|
|
173
|
+
- `src/ui/agent-creation-wizard.ts` — remove the `extensions:` template line.
|
|
174
|
+
|
|
175
|
+
### Source — `skills` axis + preload path
|
|
176
|
+
|
|
177
|
+
- `src/types.ts` — remove `AgentConfig.skills`.
|
|
178
|
+
- `src/config/default-agents.ts` — remove `skills: true` from all three agents.
|
|
179
|
+
- `src/config/agent-types.ts` — remove `skills: true` from the absolute-fallback literal.
|
|
180
|
+
- `src/config/custom-agents.ts` — remove the `skills:` frontmatter parse and delete `inheritField` (its only remaining callers are `skills`/`extensions`; `csvList`, `parseCsvField`, `str`, `nonNegativeInt` stay — `csvList` still serves `tools:`).
|
|
181
|
+
- `src/session/session-config.ts` — remove `AssemblerIO.preloadSkills`, `SessionConfig.noSkills`, `SessionConfig.extras`, the `extras`/`preloadSkills` block, and the `extras` argument to `buildAgentPrompt`.
|
|
182
|
+
- `src/session/prompts.ts` — remove `PromptExtras`, the `extras` parameter, and the `extrasSuffix` logic.
|
|
183
|
+
- `src/session/skill-loader.ts` — **delete** (export `preloadSkills`, `PreloadedSkill`).
|
|
184
|
+
- `src/session/safe-fs.ts` — **delete** (sole consumer was `skill-loader.ts`).
|
|
185
|
+
- `src/lifecycle/agent-runner.ts` — remove `ResourceLoaderOptions.noSkills` and drop `noSkills` from the `createResourceLoader` call.
|
|
186
|
+
- `src/index.ts` — remove the `preloadSkills` import and its `assemblerIO.preloadSkills` wiring.
|
|
187
|
+
- `src/ui/agent-config-editor.ts` — remove the `skills: false` / `skills: <list>` lines from `buildEjectContent`.
|
|
188
|
+
- `src/ui/agent-creation-wizard.ts` — remove the `skills:` template line.
|
|
189
|
+
|
|
190
|
+
### Tests
|
|
191
|
+
|
|
192
|
+
- `test/session/skill-loader.test.ts` — **delete**.
|
|
193
|
+
- `test/session/safe-fs.test.ts` — **delete**.
|
|
194
|
+
- `test/session/session-config.test.ts` — remove the `isolated`-mode `describe`, the `noSkills` assertions, and the preload tests; keep model-resolution and prompt-assembly assertions.
|
|
195
|
+
- `test/session/prompts.test.ts` — remove `isolated`/`extensions`/`skills` from `AgentConfig` fixtures and any `skillBlocks`/`extras` cases.
|
|
196
|
+
- `test/config/invocation-config.test.ts` — remove `isolated` cases and fixture fields.
|
|
197
|
+
- `test/config/custom-agents.test.ts` — remove `extensions` / `skills` / `isolated` frontmatter-parsing tests.
|
|
198
|
+
- `test/config/agent-types.test.ts` — remove `extensions` / `skills` / `isolated` from fixtures.
|
|
199
|
+
- `test/lifecycle/agent-runner-extension-tools.test.ts` — remove `extensions`/`skills`/`isolated` from the mock config; delete the "extensions: false skips the filter entirely" test; keep/adjust the post-bind guard tests to assert the guard runs unconditionally.
|
|
200
|
+
- `test/tools/spawn-config.test.ts` — remove the "sets isolated from params" test and `isolated` fixture fields.
|
|
201
|
+
- `test/tools/background-spawner.test.ts` / `test/tools/foreground-runner.test.ts` — remove `isolated` from fixtures and `agentInvocation` assertions.
|
|
202
|
+
- `test/tools/result-renderer.test.ts` — remove the `"isolated"` tag case.
|
|
203
|
+
- `test/ui/agent-config-editor.test.ts` — remove the `isolated` / `extensions: false` eject-emission tests.
|
|
204
|
+
- `test/display.test.ts` — remove `extensions`/`skills` from `AgentConfig` fixtures.
|
|
205
|
+
- `test/helpers/runner-io.ts` — remove `extensions`/`skills`/`isolated` from `DEFAULT_AGENT_CONFIG`.
|
|
206
|
+
- `test/helpers/runner-io.test.ts` — remove the `config.extensions`/`config.skills` assertions and the `extensions: true` override case.
|
|
207
|
+
- `test/helpers/ui-stubs.ts` — remove `extensions: true` / `skills: true` from the stub `AgentConfig`.
|
|
208
|
+
|
|
209
|
+
### Docs
|
|
210
|
+
|
|
211
|
+
- `docs/architecture/architecture.md` —
|
|
212
|
+
remove the `SafeFs` and `SkillLoader` nodes from the session-domain Mermaid subgraph;
|
|
213
|
+
remove `safe-fs.ts` and `skill-loader.ts` from the directory-tree listing;
|
|
214
|
+
drop `isolated` from the `SpawnOptions` field list (≈ line 418) and the `RunOptions` field list (≈ line 651);
|
|
215
|
+
mark Phase 16 Step 4 (#264) done in the roadmap and update the "Children always load the parent's extensions and skills" note;
|
|
216
|
+
reflect the smaller session domain (8 → 6 modules).
|
|
217
|
+
- `.pi/skills/package-pi-subagents/SKILL.md` — update the Session domain row (module count 8 → 6, drop `safe-fs.ts` / `skill-loader.ts` from the file list).
|
|
218
|
+
|
|
219
|
+
## Test Impact Analysis
|
|
220
|
+
|
|
221
|
+
1. New coverage enabled — minimal (this is a removal).
|
|
222
|
+
The one behavioral assertion worth strengthening: the post-bind recursion guard now runs **unconditionally**.
|
|
223
|
+
Update `agent-runner-extension-tools.test.ts` so a case that previously relied on `extensions: true` instead asserts the guard always calls `setActiveToolsByName` and always excludes `EXCLUDED_TOOL_NAMES`, with no config dependence.
|
|
224
|
+
2. Tests that become redundant and are removed —
|
|
225
|
+
`skill-loader.test.ts` and `safe-fs.test.ts` (modules deleted);
|
|
226
|
+
the `isolated`-mode `describe` in `session-config.test.ts`;
|
|
227
|
+
the "extensions: false skips the filter entirely" case;
|
|
228
|
+
`isolated` parameter tests in `spawn-config.test.ts` / `invocation-config.test.ts`;
|
|
229
|
+
`extensions` / `skills` frontmatter-parsing tests in `custom-agents.test.ts`.
|
|
230
|
+
3. Tests that must stay (genuinely exercise surviving layers) —
|
|
231
|
+
prompt assembly (`prompts.test.ts`, minus `extras`);
|
|
232
|
+
model resolution in `session-config.test.ts`;
|
|
233
|
+
the post-bind guard ordering tests (adjusted, not removed);
|
|
234
|
+
custom-agent `tools:` parsing (`csvList` survives).
|
|
235
|
+
|
|
236
|
+
## TDD Order
|
|
237
|
+
|
|
238
|
+
Each cycle ends green (`pnpm run check` + `pnpm -r run test`).
|
|
239
|
+
Because removing a field from `AgentConfig` / `AgentInvocation` breaks every reader and every object-literal construction site at once (TS excess-property + property-access), each cycle folds its test updates into the same commit (per the testing skill's removal rule).
|
|
240
|
+
The three axes are split so each commit stays reviewable and leaves the repo compiling.
|
|
241
|
+
|
|
242
|
+
1. Remove the `isolated` axis end-to-end.
|
|
243
|
+
Surface: `types.ts` (`AgentConfig.isolated`, `AgentInvocation.isolated`), `invocation-config.ts`, `custom-agents.ts` (parse only), `session-config.ts` (`AssemblerOptions.isolated` + derivation), `agent-runner.ts` (`RunOptions.isolated`), `agent.ts`, `agent-manager.ts`, `tools/*`, `service*.ts`, `ui/*` (isolated bits), plus all listed tests.
|
|
244
|
+
After: `extensions`/`skills`/`noSkills` still function; the assembler reads `agentConfig.extensions`/`agentConfig.skills` directly.
|
|
245
|
+
Commit: `feat!: remove isolated from the subagent spawn API and lifecycle (#264)`.
|
|
246
|
+
2. Remove the `extensions` axis; make the recursion guard unconditional.
|
|
247
|
+
Surface: `types.ts` (`AgentConfig.extensions`), `default-agents.ts`, `agent-types.ts` (fallback), `custom-agents.ts` (parse + delete `resolveBoolExtensions`), `session-config.ts` (`SessionConfig.extensions`), `agent-runner.ts` (`ResourceLoaderOptions.noExtensions`, drop `noExtensions` arg, unconditional guard), `ui/agent-config-editor.ts` + `ui/agent-creation-wizard.ts` (extensions bits), plus tests (including the guard-always-runs update and deleting the "skips filter" case).
|
|
248
|
+
Commit: `feat!: always inherit extensions; make the recursion guard unconditional (#264)`.
|
|
249
|
+
3. Remove the `skills` axis, `noSkills`, and the skill-preload path.
|
|
250
|
+
Surface: `types.ts` (`AgentConfig.skills`), `default-agents.ts`, `agent-types.ts` (fallback), `custom-agents.ts` (parse + delete `inheritField`), `session-config.ts` (`AssemblerIO.preloadSkills`, `SessionConfig.noSkills`/`extras`, preload block, `buildAgentPrompt` call), `prompts.ts` (`PromptExtras`/`extras`/`extrasSuffix`), delete `skill-loader.ts` + `safe-fs.ts`, `agent-runner.ts` (`ResourceLoaderOptions.noSkills`, drop arg), `index.ts` (wiring), `ui/*` (skills bits), plus tests (delete `skill-loader.test.ts` + `safe-fs.test.ts`).
|
|
251
|
+
Commit: `feat!: always inherit skills; remove noSkills and the skill-preload path (#264)`.
|
|
252
|
+
4. Update the architecture doc and package skill.
|
|
253
|
+
Surface: `docs/architecture/architecture.md` (Mermaid session subgraph, directory tree, `SpawnOptions`/`RunOptions` field lists, roadmap status), `.pi/skills/package-pi-subagents/SKILL.md` (session domain row).
|
|
254
|
+
Commit: `docs: record removal of the extension-lifecycle-control axis (#264)`.
|
|
255
|
+
|
|
256
|
+
## Risks and Mitigations
|
|
257
|
+
|
|
258
|
+
- Risk: `resolveBoolExtensions` / `inheritField` deletion removes a helper still used elsewhere.
|
|
259
|
+
Mitigation: greps confirm `resolveBoolExtensions` is used only by the removed `extensions` parse, and `inheritField` only by `extensions`/`skills`; `csvList`/`parseCsvField` (used by `tools:`) stay.
|
|
260
|
+
- Risk: deleting `safe-fs.ts` orphans an import.
|
|
261
|
+
Mitigation: grep confirms `skill-loader.ts` is its sole consumer; `safe-fs.test.ts` is deleted in the same cycle.
|
|
262
|
+
- Risk: removing `SpawnOptions.isolated` breaks a published consumer of the service.
|
|
263
|
+
Mitigation: this is an intentional breaking change (ADR 0002); `feat!:` triggers a major bump via release-please.
|
|
264
|
+
The public type surface is verified by `pnpm run verify:public-types` after Step 3.
|
|
265
|
+
- Risk: skill behavior silently changes for agents that relied on `skills: string[]` curation.
|
|
266
|
+
Mitigation: documented in Goals as breaking; children now inherit the full skill system, which is strictly more capable, and deny-at-use governs what they may act on.
|
|
267
|
+
- Risk: a test file is touched in multiple cycles (e.g. `runner-io.ts`).
|
|
268
|
+
Mitigation: each cycle removes only the field it owns; ordering is fixed (isolated → extensions → skills) so no cycle leaves a dangling reference.
|
|
269
|
+
|
|
270
|
+
## Open Questions
|
|
271
|
+
|
|
272
|
+
- Should custom-agent `.md` files with now-defunct `extensions:` / `skills:` / `isolated:` frontmatter emit a one-time deprecation warning, or be silently ignored?
|
|
273
|
+
Deferred: silent-ignore matches the Phase 14 precedent for the removed `disallowed_tools` field; revisit only if users report confusion.
|
|
274
|
+
- Does `verify:public-types` need a new negative assertion that `isolated` is absent from `SpawnOptions`?
|
|
275
|
+
Deferred to Step 3 implementation — the existing consumer type-check will fail if a stale field lingers.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
issue: 272
|
|
3
|
+
issue_title: "Export WorkspaceProvider collaborator types by name from the public surface"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Export `WorkspaceProvider` collaborator types by name from the public surface
|
|
7
|
+
|
|
8
|
+
## Problem Statement
|
|
9
|
+
|
|
10
|
+
`@gotgenes/pi-subagents` re-exports the `WorkspaceProvider` seam by name from its public surface, but not the four collaborator types that seam references: `Workspace`, `WorkspacePrepareContext`, `WorkspaceDisposeOutcome`, and `WorkspaceDisposeResult`.
|
|
11
|
+
Those types are inlined into the bundled declaration (rolled in because `WorkspaceProvider` references them) but never exported by name.
|
|
12
|
+
A consumer implementing the seam — `@gotgenes/pi-subagents-worktrees` (#263) — cannot `import type { Workspace, WorkspacePrepareContext } from "@gotgenes/pi-subagents"`.
|
|
13
|
+
Instead it recovers the names through indexed-access gymnastics (`Parameters<WorkspaceProvider["prepare"]>[0]`, `NonNullable<Awaited<ReturnType<...>>>`).
|
|
14
|
+
That compiles and is type-safe, but every seam consumer has to repeat the same incantation rather than importing the names directly.
|
|
15
|
+
|
|
16
|
+
## Goals
|
|
17
|
+
|
|
18
|
+
- Re-export `Workspace`, `WorkspacePrepareContext`, `WorkspaceDisposeOutcome`, and `WorkspaceDisposeResult` by name from `src/service/service.ts`, alongside `WorkspaceProvider`.
|
|
19
|
+
- Confirm the four names land in the bundled `dist/public.d.ts` and are importable by an external consumer.
|
|
20
|
+
- Extend the verification harness (`scripts/verify-public-types.sh`) so its symbol guard and probe consumer assert the four names are present and importable.
|
|
21
|
+
- `feat:` — adds names to the publishable public API surface (purely additive, non-breaking).
|
|
22
|
+
|
|
23
|
+
## Non-Goals
|
|
24
|
+
|
|
25
|
+
- No change to `src/lifecycle/workspace.ts` — the four interfaces already exist there with the right shapes; this issue only re-exports them.
|
|
26
|
+
- No change to the runtime accessor functions, `SubagentsService`, `SpawnOptions`, `SubagentRecord`, or `SUBAGENT_EVENTS`.
|
|
27
|
+
- No edits to `@gotgenes/pi-subagents-worktrees`.
|
|
28
|
+
Replacing its indexed-access aliases with named imports and bumping its `@gotgenes/pi-subagents` dependency is deferred to that package — it can only consume these names after `pi-subagents` cuts a new release carrying them (the registry-consumption model settled in #270).
|
|
29
|
+
- No source restructuring of the entry's type closure (out of scope per #270's design; the rollup bundle already inlines the closure).
|
|
30
|
+
- No new vitest unit test — the re-exports are type-only and erase at runtime, so they are verified by the type-level `verify:public-types` harness, not by the runtime suite.
|
|
31
|
+
|
|
32
|
+
## Background
|
|
33
|
+
|
|
34
|
+
Relevant modules:
|
|
35
|
+
|
|
36
|
+
- `packages/pi-subagents/src/service/service.ts` — the public entry.
|
|
37
|
+
It currently imports `type { WorkspaceProvider } from "#src/lifecycle/workspace"` and `type { LifetimeUsage } from "#src/lifecycle/usage"`, and ends with `export type { LifetimeUsage, ..., WorkspaceProvider }`.
|
|
38
|
+
A standing comment already anticipates this issue: "Named re-exports of those collaborator types are tracked in #272."
|
|
39
|
+
- `packages/pi-subagents/src/lifecycle/workspace.ts` — defines all four collaborator interfaces plus `WorkspaceProvider`.
|
|
40
|
+
`WorkspacePrepareContext` carries `agentId`, `agentType`, `baseCwd`, and optional `invocation`; `WorkspaceDisposeOutcome` carries `status` and `description`; `WorkspaceDisposeResult` carries optional `resultAddendum`; `Workspace` carries `readonly cwd` and `dispose(outcome)`.
|
|
41
|
+
- `packages/pi-subagents/rollup.dts.config.mjs` — rolls `src/service/service.ts` into a self-contained `dist/public.d.ts`, inlining `#src/*` types and keeping `@earendil-works/*` external.
|
|
42
|
+
No config change is needed: once the names are exported from the entry, `rollup-plugin-dts` carries the (already-inlined) declarations through as named exports.
|
|
43
|
+
- `packages/pi-subagents/scripts/verify-public-types.sh` — the CI-backed verification harness.
|
|
44
|
+
It packs the tarball, runs a self-containment guard (`grep '#src'`), loops a symbol-presence guard (`for sym in getSubagentsService WorkspaceProvider SubagentsService LifetimeUsage`), then type-checks a throwaway `probe.ts` consumer against the packaged tarball.
|
|
45
|
+
|
|
46
|
+
Constraints from `AGENTS.md` and the package skill:
|
|
47
|
+
|
|
48
|
+
- Ship-source model with one build step: `build:types` (rollup) regenerates `dist/public.d.ts` at `prepack`; `dist/` is gitignored and must never be committed.
|
|
49
|
+
- Run `pnpm run verify:public-types` after any change to the public surface — it is also a CI step.
|
|
50
|
+
- Open-for-extension/closed-for-modification: pi-subagents is a minimal core; re-exporting collaborator types of an existing seam is consistent with that boundary (no new behavior, no consumer knowledge).
|
|
51
|
+
|
|
52
|
+
## Design Overview
|
|
53
|
+
|
|
54
|
+
The change is additive and type-only.
|
|
55
|
+
`service.ts` already imports the seam's entry type; extend that import to bring in the four collaborator types, then list them in the existing `export type { … }`.
|
|
56
|
+
|
|
57
|
+
Import and re-export shape after the change:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import type { LifetimeUsage } from "#src/lifecycle/usage";
|
|
61
|
+
import type {
|
|
62
|
+
Workspace,
|
|
63
|
+
WorkspaceDisposeOutcome,
|
|
64
|
+
WorkspaceDisposeResult,
|
|
65
|
+
WorkspacePrepareContext,
|
|
66
|
+
WorkspaceProvider,
|
|
67
|
+
} from "#src/lifecycle/workspace";
|
|
68
|
+
|
|
69
|
+
export type {
|
|
70
|
+
LifetimeUsage,
|
|
71
|
+
SpawnOptions,
|
|
72
|
+
SubagentRecord,
|
|
73
|
+
SubagentStatus,
|
|
74
|
+
SubagentsService,
|
|
75
|
+
Workspace,
|
|
76
|
+
WorkspaceDisposeOutcome,
|
|
77
|
+
WorkspaceDisposeResult,
|
|
78
|
+
WorkspacePrepareContext,
|
|
79
|
+
WorkspaceProvider,
|
|
80
|
+
};
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Consumer call site this enables (the pattern that motivates the issue):
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import type {
|
|
87
|
+
Workspace,
|
|
88
|
+
WorkspaceDisposeOutcome,
|
|
89
|
+
WorkspaceDisposeResult,
|
|
90
|
+
WorkspacePrepareContext,
|
|
91
|
+
WorkspaceProvider,
|
|
92
|
+
} from "@gotgenes/pi-subagents";
|
|
93
|
+
|
|
94
|
+
const provider: WorkspaceProvider = {
|
|
95
|
+
async prepare(ctx: WorkspacePrepareContext): Promise<Workspace | undefined> {
|
|
96
|
+
return { cwd: ctx.baseCwd, dispose: (_outcome: WorkspaceDisposeOutcome) => undefined };
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Edge cases:
|
|
102
|
+
|
|
103
|
+
- The standing comment in `service.ts` ("Named re-exports of those collaborator types are tracked in #272") becomes stale once the re-exports land — update it to describe the current state rather than a tracked future.
|
|
104
|
+
- `WorkspaceProvider` already pulls the four collaborator declarations into the rollup bundle by reference, so adding the named exports does not change the bundle's self-containment (the `grep '#src'` guard stays green).
|
|
105
|
+
|
|
106
|
+
## Module-Level Changes
|
|
107
|
+
|
|
108
|
+
- `packages/pi-subagents/src/service/service.ts` — widen the `#src/lifecycle/workspace` type import to include `Workspace`, `WorkspacePrepareContext`, `WorkspaceDisposeOutcome`, and `WorkspaceDisposeResult`; add the same four names to the `export type { … }` block; replace the "tracked in #272" comment with a present-tense description of the seam's named re-exports.
|
|
109
|
+
- `packages/pi-subagents/scripts/verify-public-types.sh` — add the four names to the `for sym in …` symbol-presence guard, and extend the inline `probe.ts` to import and exercise the four types by name (e.g. annotate a `prepare` implementation with `WorkspacePrepareContext`/`Workspace` and reference `WorkspaceDisposeOutcome`/`WorkspaceDisposeResult`).
|
|
110
|
+
|
|
111
|
+
No architecture-doc updates are required: `docs/architecture/architecture.md` lists `workspace.ts` under the Lifecycle domain but does not enumerate the public surface's named exports, and no complexity/health table references this change.
|
|
112
|
+
|
|
113
|
+
## Test Impact Analysis
|
|
114
|
+
|
|
115
|
+
This is a type-only re-export change, not an extraction or refactor.
|
|
116
|
+
|
|
117
|
+
1. New tests enabled: none at the vitest level — type-only re-exports erase at runtime and cannot be observed by the runtime suite.
|
|
118
|
+
The meaningful new assertion is at the type level: the extended `verify:public-types` probe proves the four names are importable from the packaged tarball, and the symbol guard proves they appear in `dist/public.d.ts`.
|
|
119
|
+
2. Redundant existing tests: none.
|
|
120
|
+
`test/service/service.test.ts` exercises the runtime accessors and `SUBAGENT_EVENTS`; it is unaffected and stays as-is.
|
|
121
|
+
3. Tests that must stay as-is: the full vitest suite (the regression canary) and `test/lifecycle/agent.test.ts` (which imports `Workspace`/`WorkspaceProvider` from `#src/lifecycle/workspace` internally — unrelated to the public re-export).
|
|
122
|
+
|
|
123
|
+
## TDD Order
|
|
124
|
+
|
|
125
|
+
The "test surface" here is the type-level verification harness, which is the red→green loop for a type-only public-surface change.
|
|
126
|
+
|
|
127
|
+
1. Extend the verification harness (red → green in one step).
|
|
128
|
+
Add the four names to the `for sym in …` guard in `scripts/verify-public-types.sh` and extend the inline `probe.ts` to import them by name.
|
|
129
|
+
Run `pnpm run verify:public-types` to confirm it fails (red) because the names are absent from `dist/public.d.ts` and the probe import is unresolved.
|
|
130
|
+
Then add the import and `export type` entries in `src/service/service.ts` and update the standing comment, and re-run `pnpm run verify:public-types` to confirm it passes (green).
|
|
131
|
+
Harness change and source change land together because the type checker proves them as a unit — a packaged-tarball probe cannot import names the entry does not yet export.
|
|
132
|
+
Commit: `feat: export WorkspaceProvider collaborator types by name (#272)`.
|
|
133
|
+
|
|
134
|
+
The harness step and the source step are bundled into a single commit deliberately: splitting them would leave the repo in a state where `verify:public-types` (a CI step) fails between commits.
|
|
135
|
+
|
|
136
|
+
## Risks and Mitigations
|
|
137
|
+
|
|
138
|
+
- Risk: the rollup bundle does not surface the new names as named exports.
|
|
139
|
+
Mitigation: `rollup-plugin-dts` carries through whatever the entry exports; the symbol guard + probe in `verify:public-types` prove the names land in `dist/public.d.ts` and are importable.
|
|
140
|
+
- Risk: committing the generated `dist/public.d.ts`.
|
|
141
|
+
Mitigation: `dist/` is gitignored and regenerated at `prepack`; the plan commits only `service.ts` and the harness script.
|
|
142
|
+
- Risk: stale comment misleads future readers.
|
|
143
|
+
Mitigation: the comment update is part of the same step.
|
|
144
|
+
|
|
145
|
+
## Open Questions
|
|
146
|
+
|
|
147
|
+
- The downstream simplification in `@gotgenes/pi-subagents-worktrees` (swap indexed-access aliases for named imports, bump the `@gotgenes/pi-subagents` dependency) is intentionally deferred until a `pi-subagents` release carries these exports — it is tracked with #263's follow-up, not this plan.
|