@nklisch/pi-enhanced 0.2.6 → 0.3.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/node_modules/@nklisch/pi-clearance/native/clearance-core.linux-x64-gnu.node +0 -0
  3. package/node_modules/@nklisch/pi-clearance/native/clearance-core.win32-x64-msvc.node +0 -0
  4. package/node_modules/@nklisch/pi-plugins/README.md +4 -2
  5. package/node_modules/@nklisch/pi-plugins/dist/hooks.js +81 -8
  6. package/node_modules/@nklisch/pi-plugins/dist/hooks.js.map +1 -1
  7. package/node_modules/@nklisch/pi-plugins/dist/mcp.js +32 -1
  8. package/node_modules/@nklisch/pi-plugins/dist/mcp.js.map +1 -1
  9. package/node_modules/@nklisch/pi-plugins/dist/pi/plugin-manager.d.ts +10 -4
  10. package/node_modules/@nklisch/pi-plugins/dist/pi/plugin-manager.js +144 -10
  11. package/node_modules/@nklisch/pi-plugins/dist/pi/plugin-manager.js.map +1 -1
  12. package/node_modules/@nklisch/pi-plugins/dist/runtime-discovery.js +40 -14
  13. package/node_modules/@nklisch/pi-plugins/dist/runtime-discovery.js.map +1 -1
  14. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/CHANGELOG.md +25 -0
  15. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/README.md +75 -47
  16. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/dist/public.d.ts +171 -140
  17. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/dist/settings.d.ts +2 -2
  18. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/FORK-MAINTENANCE.md +8 -7
  19. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/VISION.md +12 -10
  20. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/architecture/architecture.md +112 -105
  21. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/comparison-with-upstream.md +3 -3
  22. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/decisions/0004-reconsider-ui-direction.md +5 -0
  23. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/package.json +1 -1
  24. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/custom-agents.ts +31 -4
  25. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/default-agents.ts +1 -1
  26. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/invocation-config.ts +7 -4
  27. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/index.ts +18 -9
  28. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/layered-settings.ts +2 -2
  29. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/child-lifecycle.ts +10 -63
  30. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/concurrency-limiter.ts +122 -76
  31. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/create-subagent-session.ts +3 -5
  32. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/lifecycle-interceptor.ts +4 -3
  33. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/run-listeners.ts +2 -23
  34. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-manager.ts +177 -252
  35. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-session.ts +90 -280
  36. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-state.ts +153 -223
  37. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent.ts +569 -683
  38. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/workspace.ts +1 -1
  39. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/notification.ts +78 -119
  40. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/renderer.ts +15 -42
  41. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/subagent-events-observer.ts +44 -95
  42. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/service/service-adapter.ts +157 -90
  43. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/service/service.ts +60 -68
  44. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/conversation.ts +3 -3
  45. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/query-source.ts +28 -0
  46. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/query.ts +327 -0
  47. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/settings.ts +1 -1
  48. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/agent-tool.ts +171 -249
  49. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/get-result-tool.ts +51 -92
  50. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/helpers.ts +9 -6
  51. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/list-tool.ts +46 -0
  52. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/parent-tool-registry.ts +17 -0
  53. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/query-session-tool.ts +330 -0
  54. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/result-renderer.ts +27 -111
  55. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/resume-tool.ts +105 -0
  56. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/spawn-config.ts +26 -8
  57. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/steer-tool.ts +27 -111
  58. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/stop-tool.ts +53 -0
  59. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/types.ts +11 -5
  60. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/agent-widget.ts +33 -27
  61. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/display.ts +6 -3
  62. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigation.ts +121 -10
  63. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigator.ts +430 -112
  64. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/subagents-settings.ts +1 -1
  65. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/widget-renderer.ts +8 -9
  66. package/node_modules/@nklisch/pi-plugins/package.json +2 -2
  67. package/package.json +1 -1
  68. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/background-spawner.ts +0 -81
  69. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/foreground-runner.ts +0 -149
  70. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/get-result-report.ts +0 -77
@@ -1,233 +1,163 @@
1
- /**
2
- * subagent-state.ts — SubagentState value object: lifecycle status, metrics, and live activity.
3
- *
4
- * Owns the passive, readable state of a subagent — status, result, error,
5
- * timestamps, stats (toolUses, lifetimeUsage, compactionCount), and live-activity
6
- * fields (turnCount, activeTools, responseText) — together with the transition
7
- * methods (markRunning, markCompleted, …), accumulation methods
8
- * (incrementToolUses, addUsage, incrementCompactions), and live-activity
9
- * transition methods (incrementTurnCount, addActiveTool, removeActiveTool,
10
- * resetResponseText, appendResponseText) that mutate them.
11
- *
12
- * State is encapsulated behind getters; external code reads through them but
13
- * mutates only via the transition/accumulation methods. The value object owns
14
- * all of its own mutations — no field is written from outside.
15
- *
16
- * Subagent holds one of these privately and delegates its getters and mutation
17
- * methods to it. Extracting it lets the lifecycle state machine and the
18
- * session-event observer be unit-tested without constructing an executor.
19
- */
1
+ /** Authoritative coarse lifecycle state and metrics for one subagent record. */
20
2
 
21
3
  import type { LifetimeUsage } from "#src/lifecycle/usage";
22
4
  import { addUsage } from "#src/lifecycle/usage";
23
5
 
24
- export type SubagentStatus =
25
- | "queued"
26
- | "running"
27
- | "completed"
28
- | "steered"
29
- | "aborted"
30
- | "stopped"
31
- | "error";
6
+ export type SubagentStatus = "queued" | "running" | "completed" | "stopped" | "error";
7
+
8
+ export type SubagentTerminalReason =
9
+ | "completed"
10
+ | "explicit_stop"
11
+ | "parent_cancelled"
12
+ | "runtime_timeout"
13
+ | "turn_limit_graceful"
14
+ | "turn_limit_hard"
15
+ | "lifecycle_abort"
16
+ | "provider_failure"
17
+ | "execution_failure"
18
+ | "workspace_teardown_failure";
19
+
20
+ export type SubagentStopReason = "explicit_stop" | "parent_cancelled" | "runtime_timeout";
32
21
 
33
22
  export interface SubagentStateInit {
34
- status?: SubagentStatus;
35
- result?: string;
36
- error?: string;
37
- /** Whether the limiter never admitted this agent. */
38
- stoppedWhileQueued?: boolean;
39
- startedAt?: number;
40
- completedAt?: number;
41
- /** Time the parent first collected the terminal outcome. */
42
- consumedAt?: number;
23
+ status?: SubagentStatus;
24
+ result?: string;
25
+ error?: string;
26
+ startedAt?: number;
27
+ completedAt?: number;
28
+ consumedAt?: number;
29
+ terminalReason?: SubagentTerminalReason;
30
+ toolUses?: number;
31
+ lifetimeUsage?: LifetimeUsage;
32
+ compactionCount?: number;
33
+ turnCount?: number;
34
+ activeTools?: ReadonlyMap<string, string>;
35
+ responseText?: string;
43
36
  }
44
37
 
45
38
  export class SubagentState {
46
- // Transition state — encapsulated behind getters, mutated only via transition methods
47
- private _status: SubagentStatus;
48
- get status(): SubagentStatus { return this._status; }
49
-
50
- private _result?: string;
51
- get result(): string | undefined { return this._result; }
52
-
53
- private _error?: string;
54
- get error(): string | undefined { return this._error; }
55
-
56
- private _startedAt: number;
57
- get startedAt(): number { return this._startedAt; }
58
-
59
- private _completedAt?: number;
60
- get completedAt(): number | undefined { return this._completedAt; }
61
-
62
- private _stoppedWhileQueued: boolean;
63
- get stoppedWhileQueued(): boolean { return this._stoppedWhileQueued; }
64
-
65
- private _consumedAt?: number;
66
- get consumedAt(): number | undefined { return this._consumedAt; }
67
- get consumed(): boolean { return this._consumedAt != null; }
68
-
69
- // Stats accumulated via mutation methods, readable via getters
70
- private _toolUses = 0;
71
- get toolUses(): number { return this._toolUses; }
72
-
73
- private _lifetimeUsage: LifetimeUsage = { input: 0, output: 0, cacheWrite: 0 };
74
- get lifetimeUsage(): Readonly<LifetimeUsage> { return this._lifetimeUsage; }
75
-
76
- private _compactionCount = 0;
77
- get compactionCount(): number { return this._compactionCount; }
78
-
79
- // Live activity — accumulated via transition methods, readable via getters
80
- private _turnCount = 1;
81
- get turnCount(): number { return this._turnCount; }
82
-
83
- private _activeTools = new Map<string, string>();
84
- get activeTools(): ReadonlyMap<string, string> { return this._activeTools; }
85
-
86
- private _toolKeySeq = 0;
87
-
88
- private _responseText = "";
89
- get responseText(): string { return this._responseText; }
90
-
91
- constructor(init: SubagentStateInit = {}) {
92
- this._status = init.status ?? "queued";
93
- this._result = init.result;
94
- this._error = init.error;
95
- this._stoppedWhileQueued = init.stoppedWhileQueued ?? false;
96
- this._startedAt = init.startedAt ?? Date.now();
97
- this._completedAt = init.completedAt;
98
- this._consumedAt = init.consumedAt;
99
- }
100
-
101
- /** Increment tool use count. Called by record-observer on tool_execution_end. */
102
- incrementToolUses(): void {
103
- this._toolUses++;
104
- }
105
-
106
- /** Accumulate a usage delta into lifetimeUsage. Called by record-observer on message_end. */
107
- addUsage(delta: { input: number; output: number; cacheWrite: number }): void {
108
- addUsage(this._lifetimeUsage, delta);
109
- }
110
-
111
- /** Increment compaction count. Called by record-observer on compaction_end. */
112
- incrementCompactions(): void {
113
- this._compactionCount++;
114
- }
115
-
116
- /** Record a turn boundary. Called by record-observer on turn_end. */
117
- incrementTurnCount(): void {
118
- this._turnCount++;
119
- }
120
-
121
- /** Record a tool starting. Called by record-observer on tool_execution_start. */
122
- addActiveTool(toolName: string): void {
123
- this._activeTools.set(toolName + "_" + (++this._toolKeySeq), toolName);
124
- }
125
-
126
- /** Remove one active tool by name (first match). Called by record-observer on tool_execution_end. */
127
- removeActiveTool(toolName: string): void {
128
- for (const [key, name] of this._activeTools) {
129
- if (name === toolName) {
130
- this._activeTools.delete(key);
131
- break;
132
- }
133
- }
134
- }
135
-
136
- /** Reset the current response text. Called by record-observer on message_start. */
137
- resetResponseText(): void {
138
- this._responseText = "";
139
- }
140
-
141
- /** Append a text delta to the current response text. Called by record-observer on message_update. */
142
- appendResponseText(delta: string): void {
143
- this._responseText += delta;
144
- }
145
-
146
- /** Transition to running state. Sets status and startedAt. */
147
- markRunning(startedAt: number): void {
148
- this._status = "running";
149
- this._startedAt = startedAt;
150
- }
151
-
152
- /**
153
- * Transition to completed state.
154
- * Always sets result and completedAt (??=). Only changes status if not stopped.
155
- */
156
- markCompleted(result: string, completedAt?: number): void {
157
- this._result = result;
158
- this._completedAt ??= completedAt ?? Date.now();
159
- if (this._status !== "stopped") {
160
- this._status = "completed";
161
- }
162
- }
163
-
164
- /**
165
- * Transition to aborted state.
166
- * Always sets result and completedAt (??=). Only changes status if not stopped.
167
- */
168
- markAborted(result: string, completedAt?: number): void {
169
- this._result = result;
170
- this._completedAt ??= completedAt ?? Date.now();
171
- if (this._status !== "stopped") {
172
- this._status = "aborted";
173
- }
174
- }
175
-
176
- /**
177
- * Transition to steered state.
178
- * Always sets result and completedAt (??=). Only changes status if not stopped.
179
- */
180
- markSteered(result: string, completedAt?: number): void {
181
- this._result = result;
182
- this._completedAt ??= completedAt ?? Date.now();
183
- if (this._status !== "stopped") {
184
- this._status = "steered";
185
- }
186
- }
187
-
188
- /**
189
- * Transition to error state.
190
- * Always sets error (formatted) and completedAt (??=). Only changes status if not stopped.
191
- */
192
- markError(error: unknown, completedAt?: number): void {
193
- this.markFailed(error, undefined, completedAt);
194
- }
195
-
196
- /** Record a failure together with any partial output produced before it. */
197
- markFailed(error: unknown, partialResult?: string, completedAt?: number): void {
198
- this._error = error instanceof Error ? error.message : String(error);
199
- this._result = partialResult?.trim() ? partialResult : undefined;
200
- this._completedAt ??= completedAt ?? Date.now();
201
- if (this._status !== "stopped") {
202
- this._status = "error";
203
- }
204
- }
205
-
206
- /** Record that the parent collected the outcome. Idempotent. */
207
- markConsumed(at?: number): void {
208
- this._consumedAt ??= at ?? Date.now();
209
- }
210
-
211
- /** Transition to stopped state. Always valid — no guard. */
212
- markStopped(completedAt?: number): void {
213
- this._status = "stopped";
214
- this._completedAt = completedAt ?? Date.now();
215
- }
216
-
217
- /** Stop an agent before the limiter admitted it. */
218
- stopQueued(completedAt?: number): void {
219
- if (this._status === "queued") this._stoppedWhileQueued = true;
220
- this.markStopped(completedAt);
221
- }
222
-
223
- /** Reset for resume: running status, new startedAt, clear completedAt/result/error. */
224
- resetForResume(startedAt: number): void {
225
- this._status = "running";
226
- this._startedAt = startedAt;
227
- this._completedAt = undefined;
228
- this._result = undefined;
229
- this._error = undefined;
230
- this._consumedAt = undefined;
231
- this._stoppedWhileQueued = false;
232
- }
39
+ private _status: SubagentStatus;
40
+ get status(): SubagentStatus { return this._status; }
41
+
42
+ private _result?: string;
43
+ get result(): string | undefined { return this._result; }
44
+
45
+ private _error?: string;
46
+ get error(): string | undefined { return this._error; }
47
+
48
+ private _startedAt: number;
49
+ get startedAt(): number { return this._startedAt; }
50
+
51
+ private _completedAt?: number;
52
+ get completedAt(): number | undefined { return this._completedAt; }
53
+
54
+ private _consumedAt?: number;
55
+ get consumedAt(): number | undefined { return this._consumedAt; }
56
+ get consumed(): boolean { return this._consumedAt != null; }
57
+
58
+ private _terminalReason?: SubagentTerminalReason;
59
+ get terminalReason(): SubagentTerminalReason | undefined { return this._terminalReason; }
60
+
61
+ private _toolUses: number;
62
+ get toolUses(): number { return this._toolUses; }
63
+
64
+ private _lifetimeUsage: LifetimeUsage;
65
+ get lifetimeUsage(): Readonly<LifetimeUsage> { return this._lifetimeUsage; }
66
+
67
+ private _compactionCount: number;
68
+ get compactionCount(): number { return this._compactionCount; }
69
+
70
+ private _turnCount: number;
71
+ get turnCount(): number { return this._turnCount; }
72
+
73
+ private _activeTools: Map<string, string>;
74
+ get activeTools(): ReadonlyMap<string, string> { return this._activeTools; }
75
+ private _toolKeySeq = 0;
76
+
77
+ private _responseText: string;
78
+ get responseText(): string { return this._responseText; }
79
+
80
+ constructor(init: SubagentStateInit = {}) {
81
+ this._status = init.status ?? "queued";
82
+ this._result = init.result;
83
+ this._error = init.error;
84
+ this._startedAt = init.startedAt ?? Date.now();
85
+ this._completedAt = init.completedAt;
86
+ this._consumedAt = init.consumedAt;
87
+ this._terminalReason = init.terminalReason;
88
+ this._toolUses = init.toolUses ?? 0;
89
+ this._lifetimeUsage = { ...(init.lifetimeUsage ?? { input: 0, output: 0, cacheWrite: 0 }) };
90
+ this._compactionCount = init.compactionCount ?? 0;
91
+ this._turnCount = init.turnCount ?? 1;
92
+ this._activeTools = new Map(init.activeTools ?? []);
93
+ this._responseText = init.responseText ?? "";
94
+ }
95
+
96
+ incrementToolUses(): void { this._toolUses++; }
97
+ addUsage(delta: { input: number; output: number; cacheWrite: number }): void { addUsage(this._lifetimeUsage, delta); }
98
+ incrementCompactions(): void { this._compactionCount++; }
99
+ incrementTurnCount(): void { this._turnCount++; }
100
+
101
+ addActiveTool(toolName: string): void {
102
+ this._activeTools.set(`${toolName}_${++this._toolKeySeq}`, toolName);
103
+ }
104
+
105
+ removeActiveTool(toolName: string): void {
106
+ for (const [key, name] of this._activeTools) {
107
+ if (name === toolName) {
108
+ this._activeTools.delete(key);
109
+ break;
110
+ }
111
+ }
112
+ }
113
+
114
+ resetResponseText(): void { this._responseText = ""; }
115
+ appendResponseText(delta: string): void { this._responseText += delta; }
116
+
117
+ markRunning(startedAt: number): void {
118
+ this._status = "running";
119
+ this._startedAt = startedAt;
120
+ this._completedAt = undefined;
121
+ this._result = undefined;
122
+ this._error = undefined;
123
+ this._consumedAt = undefined;
124
+ this._terminalReason = undefined;
125
+ }
126
+
127
+ markCompleted(result: string, reason: "completed" | "turn_limit_graceful", completedAt = Date.now()): void {
128
+ this._status = "completed";
129
+ this._result = result;
130
+ this._error = undefined;
131
+ this._completedAt = completedAt;
132
+ this._terminalReason = reason;
133
+ }
134
+
135
+ markStopped(result: string | undefined, reason: SubagentStopReason | "turn_limit_hard" | "lifecycle_abort", completedAt = Date.now()): void {
136
+ this._status = "stopped";
137
+ this._result = result;
138
+ this._completedAt = completedAt;
139
+ this._terminalReason = reason;
140
+ }
141
+
142
+ markError(error: unknown, reason: "provider_failure" | "execution_failure" | "workspace_teardown_failure", result?: string, completedAt = Date.now()): void {
143
+ this._status = "error";
144
+ this._error = error instanceof Error ? error.message : String(error);
145
+ this._result = result?.trim() ? result : undefined;
146
+ this._completedAt = completedAt;
147
+ this._terminalReason = reason;
148
+ }
149
+
150
+ markConsumed(at = Date.now()): void { this._consumedAt ??= at; }
151
+
152
+ resetForResume(): void {
153
+ this._status = "queued";
154
+ this._completedAt = undefined;
155
+ this._result = undefined;
156
+ this._error = undefined;
157
+ this._consumedAt = undefined;
158
+ this._terminalReason = undefined;
159
+ this._responseText = "";
160
+ this._activeTools.clear();
161
+ this._turnCount = 1;
162
+ }
233
163
  }