@gotgenes/pi-subagents 6.17.1 → 6.18.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 (52) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/docs/architecture/architecture.md +8 -9
  3. package/docs/plans/0164-reorganize-into-domain-directories.md +409 -0
  4. package/docs/retro/0164-reorganize-into-domain-directories.md +82 -0
  5. package/package.json +7 -2
  6. package/src/{agent-types.ts → config/agent-types.ts} +2 -2
  7. package/src/{custom-agents.ts → config/custom-agents.ts} +5 -4
  8. package/src/{default-agents.ts → config/default-agents.ts} +1 -1
  9. package/src/{invocation-config.ts → config/invocation-config.ts} +1 -1
  10. package/src/handlers/index.ts +2 -2
  11. package/src/handlers/lifecycle.ts +2 -1
  12. package/src/index.ts +27 -26
  13. package/src/{agent-manager.ts → lifecycle/agent-manager.ts} +17 -14
  14. package/src/{agent-record.ts → lifecycle/agent-record.ts} +6 -6
  15. package/src/{agent-runner.ts → lifecycle/agent-runner.ts} +9 -9
  16. package/src/{parent-snapshot.ts → lifecycle/parent-snapshot.ts} +2 -1
  17. package/src/{worktree-state.ts → lifecycle/worktree-state.ts} +1 -1
  18. package/src/{worktree.ts → lifecycle/worktree.ts} +1 -1
  19. package/src/{notification.ts → observation/notification.ts} +4 -4
  20. package/src/{record-observer.ts → observation/record-observer.ts} +3 -2
  21. package/src/{renderer.ts → observation/renderer.ts} +2 -2
  22. package/src/runtime.ts +2 -2
  23. package/src/{service-adapter.ts → service/service-adapter.ts} +7 -7
  24. package/src/{service.ts → service/service.ts} +2 -1
  25. package/src/{context.ts → session/context.ts} +2 -0
  26. package/src/{env.ts → session/env.ts} +2 -2
  27. package/src/{memory.ts → session/memory.ts} +2 -2
  28. package/src/{model-resolver.ts → session/model-resolver.ts} +2 -1
  29. package/src/{prompts.ts → session/prompts.ts} +4 -4
  30. package/src/{session-config.ts → session/session-config.ts} +5 -5
  31. package/src/{skill-loader.ts → session/skill-loader.ts} +3 -3
  32. package/src/tools/agent-tool.ts +14 -14
  33. package/src/tools/background-spawner.ts +8 -8
  34. package/src/tools/foreground-runner.ts +16 -15
  35. package/src/tools/get-result-tool.ts +6 -6
  36. package/src/tools/helpers.ts +4 -4
  37. package/src/tools/spawn-config.ts +7 -6
  38. package/src/tools/steer-tool.ts +3 -3
  39. package/src/types.ts +1 -1
  40. package/src/ui/agent-activity-tracker.ts +1 -1
  41. package/src/ui/agent-config-editor.ts +6 -5
  42. package/src/ui/agent-creation-wizard.ts +5 -5
  43. package/src/ui/agent-menu.ts +10 -9
  44. package/src/ui/agent-widget.ts +7 -8
  45. package/src/ui/conversation-viewer.ts +7 -7
  46. package/src/ui/display.ts +2 -2
  47. package/src/ui/ui-observer.ts +2 -1
  48. package/src/ui/widget-renderer.ts +5 -5
  49. /package/src/{execution-state.ts → lifecycle/execution-state.ts} +0 -0
  50. /package/src/{usage.ts → lifecycle/usage.ts} +0 -0
  51. /package/src/{notification-state.ts → observation/notification-state.ts} +0 -0
  52. /package/src/{session-dir.ts → session/session-dir.ts} +0 -0
@@ -1,23 +1,23 @@
1
1
  import type { AgentToolResult } from "@earendil-works/pi-coding-agent";
2
- import type { AgentSpawnConfig } from "../agent-manager";
3
- import type { ParentSnapshot } from "../parent-snapshot";
4
- import type { AgentRecord } from "../types";
5
- import { AgentActivityTracker } from "../ui/agent-activity-tracker";
6
- import {
7
- type AgentDetails,
8
- describeActivity,
9
- formatMs,
10
- SPINNER,
11
- } from "../ui/display";
12
- import { subscribeUIObserver } from "../ui/ui-observer";
13
- import type { AgentActivityAccess } from "./agent-tool";
2
+ import type { AgentSpawnConfig } from "#src/lifecycle/agent-manager";
3
+ import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
4
+ import type { AgentActivityAccess } from "#src/tools/agent-tool";
14
5
  import {
15
6
  buildDetails,
16
7
  formatLifetimeTokens,
17
8
  getStatusNote,
18
9
  textResult,
19
- } from "./helpers";
20
- import type { ResolvedSpawnConfig } from "./spawn-config";
10
+ } from "#src/tools/helpers";
11
+ import type { ResolvedSpawnConfig } from "#src/tools/spawn-config";
12
+ import type { AgentRecord } from "#src/types";
13
+ import { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
14
+ import {
15
+ type AgentDetails,
16
+ describeActivity,
17
+ formatMs,
18
+ SPINNER,
19
+ } from "#src/ui/display";
20
+ import { subscribeUIObserver } from "#src/ui/ui-observer";
21
21
 
22
22
  /** Narrow manager interface for the foreground runner. */
23
23
  export interface ForegroundManagerDeps {
@@ -80,6 +80,7 @@ export async function runForeground(
80
80
  };
81
81
  onUpdate?.({
82
82
  content: [{ type: "text", text: `${toolUses} tool uses...` }],
83
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Pi SDK ToolCallUpdate details type is not exported
83
84
  details: details as any,
84
85
  });
85
86
  };
@@ -151,7 +152,7 @@ export async function runForeground(
151
152
  if (tokenText) statsParts.push(tokenText);
152
153
  return textResult(
153
154
  `${fallbackNote}Agent completed in ${formatMs(durationMs)} (${statsParts.join(", ")})${getStatusNote(record.status)}.\n\n` +
154
- (record.result?.trim() || "No output."),
155
+ (record.result?.trim() ?? "No output."),
155
156
  details,
156
157
  );
157
158
  }
@@ -1,10 +1,10 @@
1
1
  import type { AgentSession } from "@earendil-works/pi-coding-agent";
2
2
  import { Type } from "@sinclair/typebox";
3
- import type { AgentConfigLookup } from "../agent-types";
4
- import type { AgentRecord } from "../types";
5
- import { formatDuration, getDisplayName } from "../ui/display";
6
- import { getSessionContextPercent } from "../usage";
7
- import { formatLifetimeTokens, textResult } from "./helpers";
3
+ import type { AgentConfigLookup } from "#src/config/agent-types";
4
+ import { getSessionContextPercent } from "#src/lifecycle/usage";
5
+ import { formatLifetimeTokens, textResult } from "#src/tools/helpers";
6
+ import type { AgentRecord } from "#src/types";
7
+ import { formatDuration, getDisplayName } from "#src/ui/display";
8
8
 
9
9
  /** Create the get_subagent_result tool definition (without Pi SDK wrapper). */
10
10
  export function createGetResultTool(
@@ -79,7 +79,7 @@ export function createGetResultTool(
79
79
  } else if (record.status === "error") {
80
80
  output += `Error: ${record.error}`;
81
81
  } else {
82
- output += record.result?.trim() || "No output.";
82
+ output += record.result?.trim() ?? "No output.";
83
83
  }
84
84
 
85
85
  // Mark result as consumed — suppresses the completion notification
@@ -1,7 +1,7 @@
1
- import type { AgentConfigLookup } from "../agent-types";
2
- import { AgentActivityTracker } from "../ui/agent-activity-tracker";
3
- import { type AgentDetails, formatTokens } from "../ui/display";
4
- import { getLifetimeTotal, type LifetimeUsage } from "../usage";
1
+ import type { AgentConfigLookup } from "#src/config/agent-types";
2
+ import { getLifetimeTotal, type LifetimeUsage } from "#src/lifecycle/usage";
3
+ import { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
4
+ import { type AgentDetails, formatTokens } from "#src/ui/display";
5
5
 
6
6
  /** Parenthetical status note for completed agent result text. */
7
7
  export function getStatusNote(status: string): string {
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-argument -- Pi SDK types are not fully exported; see upstream Pi SDK for type improvements */
1
2
  /**
2
3
  * spawn-config.ts — Pure config resolution for the Agent tool.
3
4
  *
@@ -7,17 +8,17 @@
7
8
  */
8
9
 
9
10
  import type { Model } from "@earendil-works/pi-ai";
10
- import { normalizeMaxTurns } from "../agent-runner";
11
- import type { AgentTypeRegistry } from "../agent-types";
12
- import { resolveAgentInvocationConfig } from "../invocation-config";
13
- import { resolveInvocationModel } from "../model-resolver";
14
- import type { AgentInvocation, IsolationMode, SubagentType, ThinkingLevel } from "../types";
11
+ import type { AgentTypeRegistry } from "#src/config/agent-types";
12
+ import { resolveAgentInvocationConfig } from "#src/config/invocation-config";
13
+ import { normalizeMaxTurns } from "#src/lifecycle/agent-runner";
14
+ import { resolveInvocationModel } from "#src/session/model-resolver";
15
+ import type { AgentInvocation, IsolationMode, SubagentType, ThinkingLevel } from "#src/types";
15
16
  import {
16
17
  type AgentDetails,
17
18
  buildInvocationTags,
18
19
  getDisplayName,
19
20
  getPromptModeLabel,
20
- } from "../ui/display";
21
+ } from "#src/ui/display";
21
22
 
22
23
  /** Model info extracted from the parent session context. */
23
24
  export interface ModelInfo {
@@ -1,8 +1,8 @@
1
1
  import type { AgentSession } from "@earendil-works/pi-coding-agent";
2
2
  import { Type } from "@sinclair/typebox";
3
- import type { AgentRecord } from "../types";
4
- import { getSessionContextPercent } from "../usage";
5
- import { formatLifetimeTokens, textResult } from "./helpers";
3
+ import { getSessionContextPercent } from "#src/lifecycle/usage";
4
+ import { formatLifetimeTokens, textResult } from "#src/tools/helpers";
5
+ import type { AgentRecord } from "#src/types";
6
6
 
7
7
  /** Create the steer_subagent tool definition (without Pi SDK wrapper). */
8
8
  export function createSteerTool(
package/src/types.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  import type { ThinkingLevel } from "@earendil-works/pi-ai";
6
6
 
7
7
 
8
- export { AgentRecord } from "./agent-record";
8
+ export { AgentRecord } from "#src/lifecycle/agent-record";
9
9
  export type { ThinkingLevel };
10
10
 
11
11
  /** Agent type: any string name (built-in defaults or user-defined). */
@@ -5,7 +5,7 @@
5
5
  * in `ui-observer.ts`. Callers use named transition methods; readers use read-only accessors.
6
6
  */
7
7
 
8
- import type { SessionLike } from "../usage";
8
+ import type { SessionLike } from "#src/lifecycle/usage";
9
9
 
10
10
  /** Per-agent live activity state with explicit transition methods and read-only accessors. */
11
11
  export class AgentActivityTracker {
@@ -7,10 +7,10 @@
7
7
 
8
8
  import { join } from "node:path";
9
9
 
10
- import type { AgentTypeRegistry } from "../agent-types";
11
- import type { AgentConfig } from "../types";
12
- import type { AgentFileOps } from "./agent-file-ops";
13
- import type { MenuUI } from "./agent-menu";
10
+ import type { AgentTypeRegistry } from "#src/config/agent-types";
11
+ import type { AgentConfig } from "#src/types";
12
+ import type { AgentFileOps } from "#src/ui/agent-file-ops";
13
+ import type { MenuUI } from "#src/ui/agent-menu";
14
14
 
15
15
  // ---- Factory ----
16
16
 
@@ -115,7 +115,7 @@ export function createAgentConfigEditor(
115
115
  const fmFields: string[] = [];
116
116
  fmFields.push(`description: ${cfg.description}`);
117
117
  if (cfg.displayName) fmFields.push(`display_name: ${cfg.displayName}`);
118
- fmFields.push(`tools: ${cfg.builtinToolNames?.join(", ") || "all"}`);
118
+ fmFields.push(`tools: ${cfg.builtinToolNames?.join(", ") ?? "all"}`);
119
119
  if (cfg.model) fmFields.push(`model: ${cfg.model}`);
120
120
  if (cfg.thinking) fmFields.push(`thinking: ${cfg.thinking}`);
121
121
  if (cfg.maxTurns) fmFields.push(`max_turns: ${cfg.maxTurns}`);
@@ -174,6 +174,7 @@ export function createAgentConfigEditor(
174
174
  ui.notify(`Disabled ${name} (${targetPath})`, "info");
175
175
  }
176
176
 
177
+ // eslint-disable-next-line @typescript-eslint/require-await
177
178
  async function enableAgent(ui: MenuUI, name: string) {
178
179
  const file = fileOps.findAgentFile(name, agentDirs());
179
180
  if (!file) return;
@@ -7,11 +7,11 @@
7
7
 
8
8
  import { join } from "node:path";
9
9
 
10
- import { BUILTIN_TOOL_NAMES } from "../agent-types";
11
- import type { ParentSnapshot } from "../parent-snapshot";
12
- import type { AgentRecord } from "../types";
13
- import type { AgentFileOps } from "./agent-file-ops";
14
- import type { MenuUI } from "./agent-menu";
10
+ import { BUILTIN_TOOL_NAMES } from "#src/config/agent-types";
11
+ import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
12
+ import type { AgentRecord } from "#src/types";
13
+ import type { AgentFileOps } from "#src/ui/agent-file-ops";
14
+ import type { MenuUI } from "#src/ui/agent-menu";
15
15
 
16
16
  // ---- Deps interface ----
17
17
 
@@ -1,13 +1,14 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment -- Pi SDK types are not fully exported; see upstream Pi SDK for type improvements */
1
2
  import { wrapTextWithAnsi } from "@earendil-works/pi-tui";
2
- import { AgentTypeRegistry } from "../agent-types";
3
- import type { ModelRegistry } from "../model-resolver";
4
- import type { ParentSnapshot } from "../parent-snapshot";
5
- import type { AgentConfig, AgentRecord } from "../types";
6
- import type { AgentActivityTracker } from "./agent-activity-tracker";
7
- import { createAgentConfigEditor } from "./agent-config-editor";
8
- import { createAgentCreationWizard } from "./agent-creation-wizard";
9
- import type { AgentFileOps } from "./agent-file-ops";
10
- import { formatDuration, getDisplayName } from "./display";
3
+ import { AgentTypeRegistry } from "#src/config/agent-types";
4
+ import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
5
+ import type { ModelRegistry } from "#src/session/model-resolver";
6
+ import type { AgentConfig, AgentRecord } from "#src/types";
7
+ import type { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
8
+ import { createAgentConfigEditor } from "#src/ui/agent-config-editor";
9
+ import { createAgentCreationWizard } from "#src/ui/agent-creation-wizard";
10
+ import type { AgentFileOps } from "#src/ui/agent-file-ops";
11
+ import { formatDuration, getDisplayName } from "#src/ui/display";
11
12
 
12
13
  // ---- Deps interface ----
13
14
 
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-redundant-type-constituents -- Pi SDK types are not fully exported; see upstream Pi SDK for type improvements */
1
2
  /**
2
3
  * agent-widget.ts — Persistent widget showing running/completed agents above the editor.
3
4
  *
@@ -5,11 +6,11 @@
5
6
  * Uses the callback form of setWidget for themed rendering.
6
7
  */
7
8
 
8
- import type { AgentManager } from "../agent-manager";
9
- import { AgentTypeRegistry } from "../agent-types";
10
- import type { AgentActivityTracker } from "./agent-activity-tracker";
11
- import { ERROR_STATUSES, type Theme } from "./display";
12
- import { renderWidgetLines } from "./widget-renderer";
9
+ import { AgentTypeRegistry } from "#src/config/agent-types";
10
+ import type { AgentManager } from "#src/lifecycle/agent-manager";
11
+ import type { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
12
+ import { ERROR_STATUSES, type Theme } from "#src/ui/display";
13
+ import { renderWidgetLines } from "#src/ui/widget-renderer";
13
14
 
14
15
  // ---- Types ----
15
16
 
@@ -76,9 +77,7 @@ export class AgentWidget {
76
77
  /** Ensure the widget update timer is running. */
77
78
  // fallow-ignore-next-line unused-class-member
78
79
  ensureTimer() {
79
- if (!this.widgetInterval) {
80
- this.widgetInterval = setInterval(() => this.update(), 80);
81
- }
80
+ this.widgetInterval ??= setInterval(() => this.update(), 80);
82
81
  }
83
82
 
84
83
  /** Check if a finished agent should still be shown in the widget. */
@@ -7,12 +7,12 @@
7
7
 
8
8
  import type { AgentSession } from "@earendil-works/pi-coding-agent";
9
9
  import { type Component, matchesKey, type TUI, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
10
- import type { AgentConfigLookup } from "../agent-types";
11
- import { extractText } from "../context";
12
- import type { AgentRecord } from "../types";
13
- import { getLifetimeTotal, getSessionContextPercent } from "../usage";
14
- import type { AgentActivityTracker } from "./agent-activity-tracker";
15
- import { buildInvocationTags, describeActivity, formatDuration, formatSessionTokens, getDisplayName, getPromptModeLabel, type Theme } from "./display";
10
+ import type { AgentConfigLookup } from "#src/config/agent-types";
11
+ import { getLifetimeTotal, getSessionContextPercent } from "#src/lifecycle/usage";
12
+ import { extractText } from "#src/session/context";
13
+ import type { AgentRecord } from "#src/types";
14
+ import type { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
15
+ import { buildInvocationTags, describeActivity, formatDuration, formatSessionTokens, getDisplayName, getPromptModeLabel, type Theme } from "#src/ui/display";
16
16
 
17
17
  // ── Local message-shape types ───────────────────────────────────────────────
18
18
  // The Pi SDK does not export narrow types for all message content variants.
@@ -299,7 +299,7 @@ export class ConversationViewer implements Component {
299
299
  } else if (isBashExecution(msg)) {
300
300
  if (needsSeparator) lines.push(th.fg("dim", "───"));
301
301
  lines.push(truncateToWidth(th.fg("muted", ` $ ${msg.command}`), width));
302
- if (msg.output?.trim()) {
302
+ if (msg.output.trim()) {
303
303
  const out = msg.output.length > 500
304
304
  ? msg.output.slice(0, 500) + "... (truncated)"
305
305
  : msg.output;
package/src/ui/display.ts CHANGED
@@ -5,8 +5,8 @@
5
5
  * Consumed by the widget, the menu, tool modules, and the notification renderer.
6
6
  */
7
7
 
8
- import type { AgentConfigLookup } from "../agent-types";
9
- import type { AgentInvocation, SubagentType } from "../types";
8
+ import type { AgentConfigLookup } from "#src/config/agent-types";
9
+ import type { AgentInvocation, SubagentType } from "#src/types";
10
10
 
11
11
  // ---- Types ----
12
12
 
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument -- Pi SDK types are not fully exported; see upstream Pi SDK for type improvements */
1
2
  /**
2
3
  * ui-observer.ts — Subscribes to session events and updates AgentActivityTracker state.
3
4
  *
@@ -6,7 +7,7 @@
6
7
  * turn count, lifetime usage).
7
8
  */
8
9
 
9
- import type { AgentActivityTracker } from "./agent-activity-tracker";
10
+ import type { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
10
11
 
11
12
  /** Narrow session interface — only the subscribe method needed by the observer. */
12
13
  interface SubscribableSession {
@@ -6,10 +6,10 @@
6
6
  */
7
7
 
8
8
  import { truncateToWidth } from "@earendil-works/pi-tui";
9
- import type { AgentConfigLookup } from "../agent-types";
10
- import type { SubagentType } from "../types";
11
- import type { LifetimeUsage, SessionLike } from "../usage";
12
- import { getLifetimeTotal, getSessionContextPercent } from "../usage";
9
+ import type { AgentConfigLookup } from "#src/config/agent-types";
10
+ import type { LifetimeUsage, SessionLike } from "#src/lifecycle/usage";
11
+ import { getLifetimeTotal, getSessionContextPercent } from "#src/lifecycle/usage";
12
+ import type { SubagentType } from "#src/types";
13
13
  import {
14
14
  describeActivity,
15
15
  formatMs,
@@ -19,7 +19,7 @@ import {
19
19
  getPromptModeLabel,
20
20
  SPINNER,
21
21
  type Theme,
22
- } from "./display";
22
+ } from "#src/ui/display";
23
23
 
24
24
  // ── Data interfaces ──────────────────────────────────────────────────────────
25
25
 
File without changes
File without changes