@nredd/pi-subagents 0.0.0-stage → 0.22.0-nredd.10

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 (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1444 -2
  3. package/dist/chunks/chunk-MSGGFB5Q.ts +6755 -0
  4. package/dist/chunks/chunk-MSGGFB5Q.ts.map +7 -0
  5. package/dist/chunks/conversation-viewer-A7AMRDVY.ts +15 -0
  6. package/dist/chunks/conversation-viewer-A7AMRDVY.ts.map +7 -0
  7. package/dist/index.ts +9874 -0
  8. package/dist/index.ts.map +7 -0
  9. package/package.json +82 -4
  10. package/src/abortable.ts +43 -0
  11. package/src/agent-color.ts +161 -0
  12. package/src/agent-file-toggle.ts +298 -0
  13. package/src/agent-manager.ts +2431 -0
  14. package/src/agent-runner.ts +1703 -0
  15. package/src/agent-source-badge.ts +75 -0
  16. package/src/agent-types.ts +346 -0
  17. package/src/child-context.ts +33 -0
  18. package/src/clock.ts +25 -0
  19. package/src/completion-outbox.ts +144 -0
  20. package/src/context.ts +58 -0
  21. package/src/cross-extension-rpc.ts +200 -0
  22. package/src/custom-agents.ts +441 -0
  23. package/src/default-agents.ts +126 -0
  24. package/src/detached-results.ts +150 -0
  25. package/src/enabled-models.ts +181 -0
  26. package/src/enterprise-local.ts +67 -0
  27. package/src/env.ts +33 -0
  28. package/src/error-message.ts +11 -0
  29. package/src/git-path.ts +66 -0
  30. package/src/group-join.ts +142 -0
  31. package/src/home-paths.ts +27 -0
  32. package/src/index.ts +5047 -0
  33. package/src/invocation-config.ts +158 -0
  34. package/src/memory.ts +179 -0
  35. package/src/mention-clone.ts +200 -0
  36. package/src/mention.ts +141 -0
  37. package/src/model-call.ts +83 -0
  38. package/src/model-resolver.ts +333 -0
  39. package/src/model-scope.ts +71 -0
  40. package/src/model-selection.ts +170 -0
  41. package/src/model-tiers.ts +176 -0
  42. package/src/nested-tools.ts +512 -0
  43. package/src/notification-result.ts +118 -0
  44. package/src/output-file.ts +186 -0
  45. package/src/package-resources.ts +639 -0
  46. package/src/plan-mode-children.ts +176 -0
  47. package/src/process-budget.ts +346 -0
  48. package/src/prompts.ts +161 -0
  49. package/src/quota-admission.ts +121 -0
  50. package/src/resource-loader.ts +65 -0
  51. package/src/schedule-store.ts +153 -0
  52. package/src/schedule.ts +514 -0
  53. package/src/settings.ts +851 -0
  54. package/src/skill-loader.ts +288 -0
  55. package/src/stale-ctx.ts +16 -0
  56. package/src/startup-error.ts +29 -0
  57. package/src/status-note.ts +113 -0
  58. package/src/structured-output.ts +130 -0
  59. package/src/types.ts +487 -0
  60. package/src/ui/agent-mention.ts +219 -0
  61. package/src/ui/agent-row.ts +245 -0
  62. package/src/ui/agent-widget.ts +722 -0
  63. package/src/ui/conversation-viewer.ts +837 -0
  64. package/src/ui/fallback-flag.ts +114 -0
  65. package/src/ui/fleet-list.ts +1020 -0
  66. package/src/ui/fleet-state.ts +154 -0
  67. package/src/ui/notification-view.ts +139 -0
  68. package/src/ui/schedule-menu.ts +105 -0
  69. package/src/ui/select-item.ts +45 -0
  70. package/src/ui/viewer-keys.ts +39 -0
  71. package/src/ui/workflow-card.ts +459 -0
  72. package/src/ui/workflow-dialog.ts +1138 -0
  73. package/src/ui/workflow-menu.ts +193 -0
  74. package/src/usage.ts +167 -0
  75. package/src/workflow/collisions.ts +123 -0
  76. package/src/workflow/entry.ts +47 -0
  77. package/src/workflow/host.ts +398 -0
  78. package/src/workflow/journal.ts +176 -0
  79. package/src/workflow/json-schema.ts +129 -0
  80. package/src/workflow/meta.ts +329 -0
  81. package/src/workflow/progress.ts +554 -0
  82. package/src/workflow/runtime.ts +1249 -0
  83. package/src/workflow/saved.ts +259 -0
  84. package/src/workflow/task.ts +317 -0
  85. package/src/workflow/tool-description.ts +200 -0
  86. package/src/workflow/worker-source.ts +903 -0
  87. package/src/worktree.ts +520 -0
  88. package/src/xml.ts +13 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/ui/conversation-viewer.ts", "../../src/agent-types.ts", "../../src/default-agents.ts", "../../src/agent-color.ts", "../../src/clock.ts", "../../src/context.ts", "../../src/usage.ts", "../../src/ui/agent-widget.ts", "../../src/agent-manager.ts", "../../src/agent-runner.ts", "../../src/child-context.ts", "../../src/env.ts", "../../src/home-paths.ts", "../../src/memory.ts", "../../src/nested-tools.ts", "../../src/abortable.ts", "../../src/custom-agents.ts", "../../src/error-message.ts", "../../src/package-resources.ts", "../../src/invocation-config.ts", "../../src/model-tiers.ts", "../../src/model-resolver.ts", "../../src/enabled-models.ts", "../../src/model-scope.ts", "../../src/quota-admission.ts", "../../src/model-selection.ts", "../../src/output-file.ts", "../../src/status-note.ts", "../../src/worktree.ts", "../../src/git-path.ts", "../../src/plan-mode-children.ts", "../../src/prompts.ts", "../../src/resource-loader.ts", "../../src/skill-loader.ts", "../../src/stale-ctx.ts", "../../src/structured-output.ts", "../../src/mention.ts", "../../src/process-budget.ts", "../../src/model-call.ts", "../../src/ui/fallback-flag.ts", "../../src/ui/viewer-keys.ts"],
4
+ "sourcesContent": ["/**\n * conversation-viewer.ts \u2014 Live conversation overlay for viewing agent sessions.\n *\n * Displays a scrollable, live-updating view of an agent's conversation.\n * Subscribes to session events for real-time streaming updates.\n */\n\nimport { type AgentSession, getMarkdownTheme } from \"@earendil-works/pi-coding-agent\";\nimport { type Component, type Focusable, Input, Markdown, type MarkdownOptions, type MarkdownTheme, matchesKey, type OverlayOptions, ScrollView, type ScrollViewScrollbar, stripTerminalSequences, type TUI, type TuiMouseEvent, type TuiMouseEventResult, truncateToWidth, visibleWidth, wrapTextWithAnsi } from \"@earendil-works/pi-tui\";\nimport { renderAgentName } from \"../agent-color.js\";\nimport { type Clock, realClock, type TimerHandle } from \"../clock.js\";\nimport { extractText } from \"../context.js\";\nimport type { AgentRecord, ViewerMarkdownMode } from \"../types.js\";\nimport { getLifetimeCost, getLifetimeTotal, getSessionContextPercent } from \"../usage.js\";\nimport type { Theme } from \"./agent-widget.js\";\nimport { type AgentActivity, buildInvocationTags, describeActivity, fgPreservingNestedStyles, formatCost, formatDuration, formatSessionTokens, getPromptModeLabel } from \"./agent-widget.js\";\nimport { fallbackFlag } from \"./fallback-flag.js\";\nimport { createViewerKeys, type ViewerKeybindings, type ViewerKeys } from \"./viewer-keys.js\";\n\n/** Base lines consumed by chrome: top border + header + header sep + footer sep + footer + bottom border. */\nconst CHROME_LINES_BASE = 6;\nconst MIN_VIEWPORT = 3;\n/** Height ceiling shared by the overlay's `maxHeight` and the viewer's internal viewport cap. */\nexport const VIEWPORT_HEIGHT_PCT = 70;\nconst SCROLLBAR_WIDTH = 1;\n\n/** Follow the active renderer, not a setting that may require a restart. */\nexport function getConversationOverlayOptions(tui: Pick<TUI, \"mode\">): OverlayOptions {\n return tui.mode === \"fullscreen\"\n ? { anchor: \"top-left\", width: \"100%\", maxHeight: \"100%\", margin: 0 }\n : { anchor: \"center\", width: \"90%\", maxHeight: `${VIEWPORT_HEIGHT_PCT}%` };\n}\n\n/** Ticks the header and activity line forward while an agent runs, so `thinking \u00B7 2m41s` keeps counting. */\nconst LIVE_TICK_MS = 1000;\n\n/**\n * Cap on a single tool result or bash output before the viewer elides the rest.\n *\n * The cap is not cosmetic \u2014 it bounds render cost. `buildContentLines()` runs on\n * every render *and* on every scroll key (`handleInput` calls it to compute\n * `maxScroll`), so an uncapped 200 KB result costs ~6 ms per keystroke to parse\n * as Markdown, against ~0.5 ms once capped and effectively nothing on a cache\n * hit (best of 5, width 76). 16 KB is roughly a screenful at every terminal size\n * and still ~30x the 500 characters this replaces, which was small enough to cut\n * most real results mid-sentence.\n */\nexport const RESULT_MAX_CHARS = 16_000;\n\n/** The `b` affordance: whether this run can be handed to the background now, and the handoff. */\nexport interface ViewerBackgroundAction {\n available(): boolean;\n send(): void;\n}\n\n/** Cycle order for the viewer's `m` key. */\nconst MARKDOWN_MODES: readonly ViewerMarkdownMode[] = [\"off\", \"assistant\", \"all\"];\n\n/** Footer labels \u2014 short, because the idle footer is already full at 80 columns. */\nconst MARKDOWN_MODE_LABELS: Record<ViewerMarkdownMode, string> = {\n off: \"raw\",\n assistant: \"md\",\n all: \"md+\",\n};\n\n/**\n * Both options keep the renderer from *rewriting* source that only looks like\n * Markdown: without them `3) a / 7) b / 9) c` comes back renumbered `3. 4. 5.`\n * and backslash escapes are normalized away. Neither is a safe edit to make to\n * a tool's output, and both are cheap to switch off.\n */\nconst MARKDOWN_OPTIONS: MarkdownOptions = {\n preserveOrderedListMarkers: true,\n preserveBackslashEscapes: true,\n};\n\n/**\n * Pi's own Markdown theme when this process has one, else a theme built from the\n * viewer's `Theme`.\n *\n * Preferring pi's is what buys syntax-highlighted code fences (it carries a\n * `highlightCode`), and it keeps this surface consistent with the notification\n * renderer, which uses the same source. It has to be *probed* rather than\n * try/caught around the call: `getMarkdownTheme()` returns arrow functions that\n * read pi's global theme lazily, so an uninitialized theme throws inside\n * `render()` \u2014 long after this returns \u2014 and takes the overlay with it. That is\n * the case in tests and any embedded session that never called `initTheme()`.\n */\nfunction resolveMarkdownTheme(th: Theme): MarkdownTheme {\n try {\n const piTheme = getMarkdownTheme();\n piTheme.heading(\"probe\");\n return piTheme;\n } catch {\n return fallbackMarkdownTheme(th);\n }\n}\n\n/**\n * `Theme` carries only `fg` and `bold`, so the three remaining styles are\n * written as raw SGR. Rendering them as plain text instead would silently drop\n * `*emphasis*`'s markers with nothing in their place, turning a formatting\n * change into a content change.\n */\nfunction fallbackMarkdownTheme(th: Theme): MarkdownTheme {\n const sgr = (on: number, off: number) => (text: string) => `\\x1b[${on}m${text}\\x1b[${off}m`;\n return {\n heading: text => th.bold(th.fg(\"accent\", text)),\n link: text => th.fg(\"accent\", text),\n linkUrl: text => th.fg(\"muted\", text),\n code: text => th.fg(\"muted\", text),\n codeBlock: text => th.fg(\"muted\", text),\n codeBlockBorder: text => th.fg(\"dim\", text),\n quote: text => th.fg(\"muted\", text),\n quoteBorder: text => th.fg(\"dim\", text),\n hr: text => th.fg(\"dim\", text),\n listBullet: text => th.fg(\"accent\", text),\n bold: text => th.bold(text),\n italic: sgr(3, 23),\n underline: sgr(4, 24),\n strikethrough: sgr(9, 29),\n };\n}\n\n/**\n * Cap `text` at `RESULT_MAX_CHARS`, reporting the elision separately rather than\n * appending it.\n *\n * Separately because the notice is the viewer's chrome, not the tool's output.\n * Appended into the string it becomes content: a cut landing inside a fenced\n * code block \u2014 likely, on exactly the large `ctx_execute` results this is for \u2014\n * renders the notice as a line of source inside the fence.\n */\nfunction capResult(text: string): { text: string; elided: number } {\n if (text.length <= RESULT_MAX_CHARS) return { text, elided: 0 };\n return {\n text: text.slice(0, RESULT_MAX_CHARS),\n elided: text.length - RESULT_MAX_CHARS,\n };\n}\n\n/**\n * `999` \u00B7 `1.5k` \u00B7 `8.4M` \u2014 a magnitude cue, not an exact count, past 1000.\n *\n * The bracket is chosen against the *rounded* value, so 999,999 reads `1M`\n * rather than the `1000.0k` a naive `< 1e6` test produces.\n */\nfunction humanCount(n: number): string {\n if (n < 1_000) return `${n}`;\n const thousands = n < 999_950;\n const value = thousands ? n / 1_000 : n / 1_000_000;\n return `${value.toFixed(1).replace(/\\.0$/, \"\")}${thousands ? \"k\" : \"M\"}`;\n}\n\nfunction truncationNote(elided: number): string {\n return `... (truncated, ${humanCount(elided)} more character${elided === 1 ? \"\" : \"s\"})`;\n}\n\nexport class ConversationViewer implements Component, Focusable {\n private scrollOffset = 0;\n private autoScroll = true;\n focused = false;\n private readonly fullscreen: boolean;\n private viewport: { width: number; top: number; height: number; maxScroll: number; thumbTop: number; thumbHeight: number } | undefined;\n private scrollbarGrabOffset: number | undefined;\n private footerTargets: { start: number; end: number; key: string }[] = [];\n private latestTarget: { row: number; start: number; end: number } | undefined;\n private newMessages = 0;\n private readonly scrollView: ScrollView;\n private unsubscribe: (() => void) | undefined;\n private lastInnerW = 0;\n private closed = false;\n /** Repaints once a second while the agent runs; see `LIVE_TICK_MS`. */\n private liveTimer: TimerHandle | undefined;\n /** Two-press confirm guard for the stop key, so a stray key can't kill the agent. */\n private stopArmed = false;\n private keys: ViewerKeys;\n /** Steering composer \u2014 present while the user is typing a message to the agent. */\n private composer: Input | undefined;\n /** Resolved once: pi's Markdown theme is fixed for the life of the process. */\n private readonly markdownTheme: MarkdownTheme;\n /** Set by the `m` key. Wins over the setting so `m` works without a persist hook. */\n private markdownModeOverride: ViewerMarkdownMode | undefined;\n /**\n * One `Markdown` per message, so its own text/width cache does the work. A\n * fresh instance per render would re-parse the whole transcript on every\n * keystroke \u2014 the component caches, but only across calls to the same object.\n * Weak so a compacted-away message doesn't pin its render.\n */\n private readonly markdownCache = new WeakMap<object, { md: Markdown; text: string; failed?: boolean }>();\n\n constructor(\n private tui: TUI,\n private session: AgentSession,\n private record: AgentRecord,\n private activity: AgentActivity | undefined,\n private theme: Theme,\n private done: (result: undefined) => void,\n /** Abort the agent shown here. Omitted \u2192 no stop affordance (e.g. read-only history). */\n private onStop?: () => void,\n /** User keybindings from `ctx.ui.custom()`. Omitted \u2192 hardcoded defaults. */\n keybindings?: ViewerKeybindings,\n /** Send a steering message to the agent. Omitted \u2192 no compose affordance. */\n private onSteer?: (message: string) => void,\n /**\n * Whether the header shows an estimated cost after the token count. Read\n * once, at construction: the overlay is opened from a menu, so the setting\n * cannot change while it is on screen.\n */\n private showCost = false,\n /**\n * The current `viewerMarkdown` setting. Read live rather than captured,\n * unlike `showCost`: `m` changes it while the overlay is on screen.\n * Omitted \u2192 `assistant`.\n */\n private viewerMarkdown?: () => ViewerMarkdownMode,\n /**\n * Persist a mode chosen with `m`, so the key and `/agents \u2192 Settings` mean\n * the same thing. Omitted \u2192 `m` still cycles, viewer-locally.\n */\n private onMarkdownMode?: (mode: ViewerMarkdownMode) => void,\n /** Pi's fullscreen scrollbar preference, captured when the observer opens. */\n scrollbarMode: ScrollViewScrollbar = \"auto\",\n /**\n * Hand this run to the background. `available` is read live \u2014 it turns\n * false the instant the handoff lands or the run ends. Omitted \u2192 no `b`\n * affordance (history views).\n */\n private onBackground?: ViewerBackgroundAction,\n private readonly clock: Clock = realClock,\n ) {\n this.fullscreen = tui.mode === \"fullscreen\";\n this.markdownTheme = resolveMarkdownTheme(theme);\n this.keys = createViewerKeys(keybindings);\n this.scrollView = new ScrollView({\n render: width => this.buildContentLines(width),\n invalidate: () => {},\n }, { follow: \"end\", scrollbar: this.fullscreen ? scrollbarMode : \"hidden\" });\n this.unsubscribe = session.subscribe(event => {\n if (this.closed) return;\n if (this.fullscreen && !this.scrollView.isFollowingEnd && event.type === \"message_start\" && [\"user\", \"assistant\", \"toolResult\", \"bashExecution\"].includes(event.message.role)) {\n this.newMessages++;\n }\n this.tui.requestRender();\n });\n if (record.status === \"running\" || record.status === \"queued\") {\n this.liveTimer = this.clock.setInterval(() => {\n if (this.closed) return;\n this.tui.requestRender();\n if (this.record.status !== \"running\" && this.record.status !== \"queued\") this.stopLiveTimer();\n }, LIVE_TICK_MS);\n this.liveTimer.unref?.();\n }\n }\n\n private stopLiveTimer(): void {\n this.liveTimer?.cancel();\n this.liveTimer = undefined;\n }\n\n private close(): void {\n this.closed = true;\n this.done(undefined);\n }\n\n handleInput(data: string): void {\n if (this.closed) return;\n if (this.fullscreen && (matchesKey(data, \"ctrl+end\") || (!this.composer && matchesKey(data, \"end\")))) {\n this.jumpToLatest();\n return;\n }\n // While composing a steer message, the input owns all keys (Enter sends,\n // Esc cancels \u2014 both wired in openComposer()). Editing keys flow through.\n if (this.composer) {\n this.composer.handleInput(data);\n this.tui.requestRender();\n return;\n }\n\n if (matchesKey(data, \"escape\") || matchesKey(data, \"ctrl+c\") || matchesKey(data, \"q\")) {\n this.close();\n return;\n }\n\n // Enter opens the steering composer (only while the agent can still be\n // steered) \u2014 then type + Enter sends, Esc or an empty submit returns. When\n // not steerable, fall through so the key still disarms a pending stop.\n if (matchesKey(data, \"enter\") && this.canSteer()) {\n this.stopArmed = false;\n this.openComposer();\n return;\n }\n\n // Hand a live foreground run to the background. Single press, unlike stop:\n // the transition is one-way but keeps the agent working, so a stray key\n // costs a notification rather than the run.\n if (matchesKey(data, \"b\") && this.canSendToBackground()) {\n this.stopArmed = false;\n this.onBackground?.send();\n this.tui.requestRender();\n return;\n }\n\n // Stop/abort the agent (only while it can still be stopped). Two-press:\n // first \"x\" arms, second confirms \u2014 any other key disarms.\n if (matchesKey(data, \"x\")) {\n if (this.isStoppable()) {\n if (this.stopArmed) {\n this.stopArmed = false;\n this.onStop?.();\n } else {\n this.stopArmed = true;\n }\n this.tui.requestRender();\n }\n return;\n }\n\n // Cycle raw \u2192 assistant-only \u2192 everything. The escape hatch that makes\n // Markdown rendering safe to default on: a result the renderer reshapes\n // (a diff, an indented log, a `#`-commented script) is one key from verbatim.\n if (matchesKey(data, \"m\")) {\n this.stopArmed = false;\n const next = MARKDOWN_MODES[(MARKDOWN_MODES.indexOf(this.markdownMode()) + 1) % MARKDOWN_MODES.length];\n this.markdownModeOverride = next;\n this.onMarkdownMode?.(next);\n this.tui.requestRender();\n return;\n }\n if (this.stopArmed) this.stopArmed = false;\n\n const totalLines = this.buildContentLines(this.lastInnerW).length;\n const viewportHeight = this.viewportHeight();\n if (this.fullscreen) {\n this.scrollView.updateLayout(totalLines, viewportHeight, () => {\n if (!this.closed) this.tui.requestRender();\n });\n if (this.keys.scrollUp(data)) this.scrollView.scrollBy(-1);\n else if (this.keys.scrollDown(data)) this.scrollView.scrollBy(1);\n else if (this.keys.pageUp(data)) this.scrollView.scrollBy(-viewportHeight);\n else if (this.keys.pageDown(data)) this.scrollView.scrollBy(viewportHeight);\n else if (matchesKey(data, \"home\")) this.scrollView.scrollToStart();\n return;\n }\n const maxScroll = Math.max(0, totalLines - viewportHeight);\n\n if (this.keys.scrollUp(data)) {\n this.scrollOffset = Math.max(0, this.scrollOffset - 1);\n this.autoScroll = this.scrollOffset >= maxScroll;\n } else if (this.keys.scrollDown(data)) {\n this.scrollOffset = Math.min(maxScroll, this.scrollOffset + 1);\n this.autoScroll = this.scrollOffset >= maxScroll;\n } else if (this.keys.pageUp(data)) {\n this.scrollOffset = Math.max(0, this.scrollOffset - viewportHeight);\n this.autoScroll = false;\n } else if (this.keys.pageDown(data)) {\n this.scrollOffset = Math.min(maxScroll, this.scrollOffset + viewportHeight);\n this.autoScroll = this.scrollOffset >= maxScroll;\n } else if (matchesKey(data, \"home\")) {\n this.scrollOffset = 0;\n this.autoScroll = false;\n } else if (matchesKey(data, \"end\")) {\n this.scrollOffset = maxScroll;\n this.autoScroll = true;\n }\n }\n\n private jumpToLatest(): void {\n this.scrollView.scrollToEnd();\n this.newMessages = 0;\n this.stopArmed = false;\n this.tui.requestRender();\n }\n\n handleMouse(event: TuiMouseEvent): TuiMouseEventResult {\n if (!this.fullscreen) return { handled: false };\n // Every cell belongs to this observer. Even unused clicks/drags must not\n // fall through to Pi's transcript selection, scrolling, or editor.\n if (this.closed || !this.viewport) return { handled: true, render: false };\n const view = this.viewport;\n const onScrollbar = this.scrollView.scrollbar !== \"hidden\" && event.x >= view.width - SCROLLBAR_WIDTH && event.x < view.width && event.y >= view.top && event.y < view.top + view.height;\n if (event.type === \"move\") {\n this.scrollView.setScrollbarActive(onScrollbar);\n return { handled: true, render: false };\n }\n if (event.type === \"wheel\") {\n this.stopArmed = false;\n this.scrollView.scrollBy(event.wheelDelta ?? 0);\n return { handled: true, render: true };\n }\n if (event.type === \"release\") {\n const wasDragging = this.scrollbarGrabOffset !== undefined;\n this.scrollbarGrabOffset = undefined;\n this.scrollView.setScrollbarActive(onScrollbar);\n return { handled: true, render: wasDragging };\n }\n if (event.type === \"drag\" && this.scrollbarGrabOffset !== undefined) {\n const travel = view.height - view.thumbHeight;\n const position = Math.max(0, Math.min(travel, event.y - view.top - this.scrollbarGrabOffset));\n this.scrollView.scrollTo(travel > 0 ? Math.round(position / travel * view.maxScroll) : 0);\n return { handled: true, render: true };\n }\n if (event.type === \"press\" && event.button === \"left\") {\n this.scrollbarGrabOffset = undefined;\n this.scrollView.setScrollbarActive(onScrollbar);\n if (this.latestTarget && event.y === this.latestTarget.row && event.x >= this.latestTarget.start && event.x < this.latestTarget.end) {\n this.jumpToLatest();\n return { handled: true, render: true };\n }\n if (event.y === this.tui.terminal.rows - 1) {\n const target = this.footerTargets.find(t => event.x >= t.start && event.x < t.end);\n if (target) {\n this.handleInput(target.key);\n return { handled: true, render: true };\n }\n }\n this.stopArmed = false;\n if (this.composer && event.y === this.tui.terminal.rows - 2) {\n this.composer.handleMouse({ ...event, x: event.x - 1, y: 0, width: this.lastInnerW, height: 1 });\n return { handled: true, render: true };\n }\n if (onScrollbar && view.maxScroll > 0) {\n const y = event.y - view.top;\n if (y >= view.thumbTop && y < view.thumbTop + view.thumbHeight) {\n this.scrollbarGrabOffset = y - view.thumbTop;\n return { handled: true, capture: true, render: true };\n }\n this.scrollView.scrollBy(y < view.thumbTop ? -view.height : view.height);\n // A track click still pages, but holding it can grab the thumb too.\n this.scrollbarGrabOffset = Math.floor(view.thumbHeight / 2);\n return { handled: true, capture: true, render: true };\n }\n return { handled: true, render: true };\n }\n return { handled: true, render: false };\n }\n\n render(width: number): string[] {\n this.footerTargets = [];\n this.latestTarget = undefined;\n this.viewport = undefined;\n const rows = Math.max(0, this.tui.terminal.rows);\n if (!this.fullscreen && width < 6) return []; // too narrow for any meaningful rendering\n if (width <= SCROLLBAR_WIDTH + 1) return Array.from({ length: rows }, () => \" \".repeat(Math.max(0, width)));\n const th = this.theme;\n const innerW = this.fullscreen ? this.scrollView.getContentWidth(width - 1) : width - 4;\n this.lastInnerW = innerW;\n const lines: string[] = [];\n const footerActions: { label: string; key: string }[] = [];\n const pad = (s: string, len: number) => {\n const vis = visibleWidth(s);\n return s + \" \".repeat(Math.max(0, len - vis));\n };\n const row = (content: string, scrollbar?: string): string => {\n if (this.fullscreen) {\n const contentWidth = width - 1 - (scrollbar ? SCROLLBAR_WIDTH : 0);\n return \" \" + truncateToWidth(content, contentWidth, scrollbar ? \"\" : \"...\", true) + (scrollbar ?? \"\");\n }\n return th.fg(\"border\", \"\u2502\") + \" \" + truncateToWidth(pad(content, innerW), innerW, \"...\", true) + \" \" + th.fg(\"border\", \"\u2502\");\n };\n const hrTop = th.fg(\"border\", `\u256D${\"\u2500\".repeat(width - 2)}\u256E`);\n const hrBot = th.fg(\"border\", `\u2570${\"\u2500\".repeat(width - 2)}\u256F`);\n const hrMid = row(th.fg(\"dim\", \"\u2500\".repeat(innerW)));\n\n // Header\n if (!this.fullscreen) lines.push(hrTop);\n const modeLabel = getPromptModeLabel(this.record.type);\n const modeTag = modeLabel ? ` ${th.fg(\"dim\", `(${modeLabel})`)}` : \"\";\n const statusIcon = this.record.status === \"running\"\n ? th.fg(\"accent\", \"\u25CF\")\n : this.record.status === \"completed\"\n ? th.fg(\"success\", \"\u2713\")\n : this.record.status === \"error\"\n ? th.fg(\"error\", \"\u2717\")\n : th.fg(\"dim\", \"\u25CB\");\n const duration = formatDuration(this.record.startedAt, this.record.completedAt, this.clock.now());\n\n const headerParts: string[] = [duration];\n const toolUses = this.activity?.toolUses ?? this.record.toolUses;\n if (toolUses > 0) headerParts.unshift(`${toolUses} tool${toolUses === 1 ? \"\" : \"s\"}`);\n // Spend from the record, context from the live session: the record is the\n // only total that survives the agent finishing and the only one carrying a\n // nested child's spend.\n const tokens = getLifetimeTotal(this.record.lifetimeUsage);\n if (tokens > 0) {\n const percent = getSessionContextPercent(this.activity?.session);\n headerParts.push(formatSessionTokens(tokens, percent, th, this.record.compactionCount));\n }\n const cost = this.showCost ? formatCost(getLifetimeCost(this.record.lifetimeUsage)) : \"\";\n if (cost) headerParts.push(cost);\n\n lines.push(row(\n `${statusIcon} ${renderAgentName(this.record.type, th, { bold: true })}${modeTag} ${th.fg(\"muted\", this.record.description)} ${th.fg(\"dim\", \"\u00B7\")} ${fgPreservingNestedStyles(th, \"dim\", headerParts.join(\" \u00B7 \"))}`,\n ));\n const invocationLine = this.invocationLine();\n if (invocationLine) lines.push(row(invocationLine));\n lines.push(hrMid);\n\n // Content area \u2014 rebuild every render (live data, no cache needed)\n const contentLines = this.fullscreen ? this.scrollView.render(width - 1) : this.buildContentLines(innerW);\n const viewportHeight = this.viewportHeight();\n const maxScroll = Math.max(0, contentLines.length - viewportHeight);\n if (this.fullscreen) {\n this.scrollView.updateLayout(contentLines.length, viewportHeight, () => {\n if (!this.closed) this.tui.requestRender();\n });\n if (this.scrollView.isFollowingEnd) this.newMessages = 0;\n } else if (this.autoScroll) {\n this.scrollOffset = maxScroll;\n }\n\n const visibleStart = this.fullscreen ? this.scrollView.scrollTop : Math.min(this.scrollOffset, maxScroll);\n const visible = contentLines.slice(visibleStart, visibleStart + viewportHeight);\n // Match Pi's scrollbar geometry: rounded size, at least two rows when available.\n const thumbHeight = Math.min(viewportHeight, Math.max(2, Math.round(viewportHeight * viewportHeight / Math.max(1, contentLines.length))));\n const thumbTop = maxScroll > 0 ? Math.round(visibleStart / maxScroll * (viewportHeight - thumbHeight)) : 0;\n this.viewport = { width, top: lines.length, height: viewportHeight, maxScroll, thumbTop, thumbHeight };\n\n for (let i = 0; i < viewportHeight; i++) {\n let scrollbar: string | undefined;\n if (this.scrollView.isScrollbarVisible) {\n const onThumb = i >= thumbTop && i < thumbTop + thumbHeight;\n if (onThumb) {\n scrollbar = th.fg(\"scrollbarThumb\", this.scrollView.isScrollbarActive ? \"\u2588\" : \"\u2503\");\n } else {\n scrollbar = th.fg(\"scrollbarTrack\", \"\u2502\");\n }\n }\n lines.push(row(visible[i] ?? \"\", scrollbar));\n }\n\n // Keep the divider pinned above the footer, with the jump control centered\n // inside it. Neither scrolling nor new messages change its position.\n if (this.fullscreen && !this.scrollView.isFollowingEnd && maxScroll > 0 && rows >= this.chromeLines()) {\n const text = this.newMessages > 0\n ? `${this.newMessages} new message${this.newMessages === 1 ? \"\" : \"s\"}`\n : \"Jump to latest message\";\n const label = truncateToWidth(`[ \u2193 ${text} \u00B7 Ctrl+End ]`, innerW, \"\u2026\");\n const labelWidth = visibleWidth(label);\n const padding = Math.floor((innerW - labelWidth) / 2);\n this.latestTarget = { row: lines.length, start: padding + 1, end: padding + 1 + labelWidth };\n lines.push(row(th.fg(\"dim\", \"\u2500\".repeat(padding)) + th.fg(\"accent\", label) + th.fg(\"dim\", \"\u2500\".repeat(innerW - padding - labelWidth))));\n } else {\n lines.push(hrMid);\n }\n if (this.composer) {\n // Composer row: the Input renders its own `> ` prompt and cursor.\n this.composer.focused = this.focused;\n // Input always renders exactly one row.\n lines.push(row(this.composer.render(innerW)[0]));\n footerActions.push({ label: \"Enter send\", key: \"\\r\" }, { label: \"Esc cancel\", key: \"\\x1b\" });\n const composeHint = th.fg(\"dim\", \"Enter send \u00B7 Esc cancel\");\n const composeLeft = th.fg(\"accent\", \"\u270E steer\");\n const composeGap = Math.max(1, innerW - visibleWidth(composeLeft) - visibleWidth(composeHint));\n lines.push(row(composeLeft + \" \".repeat(composeGap) + composeHint));\n } else {\n // Actions on the left, navigation on the right. The scroll hint keeps its\n // full key list so the less-obvious bindings stay discoverable; it leads\n // the right group so \"Esc close\" is the only part that truncates first.\n const sep = th.fg(\"dim\", \" \u00B7 \");\n if (this.canSteer()) footerActions.push({ label: \"Enter steer\", key: \"\\r\" });\n // Abbreviated for the same reason as the Markdown group below.\n if (this.canSendToBackground()) footerActions.push({ label: \"b bg\", key: \"b\" });\n if (this.isStoppable()) {\n footerActions.push({ label: this.stopArmed ? \"x again to STOP\" : \"x stop\", key: \"x\" });\n }\n // Abbreviated (`raw`/`md`/`md+`) because the idle footer is already full\n // at 80 columns with steer + stop present, and this group has no\n // degradation step below \"drop the line-count readout\".\n footerActions.push({ label: `m ${MARKDOWN_MODE_LABELS[this.markdownMode()]}`, key: \"m\" });\n const actions = footerActions.map(a => th.fg(a.key === \"x\" && this.stopArmed ? \"error\" : \"dim\", a.label));\n footerActions.push({ label: \"Esc close\", key: \"\\x1b\" });\n const footerRight = th.fg(\"dim\", \"\u2191\u2193 scroll \u00B7 PgUp/PgDn or Shift+\u2191\u2193 \u00B7 Esc close\");\n\n // Prepend the line-count/scroll-% readout only when there's spare width \u2014\n // it's the first thing dropped so it never crowds out the hints.\n const scrollPct = contentLines.length <= viewportHeight\n ? \"100%\"\n : `${Math.round(((visibleStart + viewportHeight) / contentLines.length) * 100)}%`;\n const count = th.fg(\"dim\", `${contentLines.length} lines \u00B7 ${scrollPct}`);\n const withCount = [count, ...actions].join(sep);\n const footerLeft = visibleWidth(withCount) + visibleWidth(footerRight) + 1 <= innerW\n ? withCount\n : actions.join(sep);\n\n const footerGap = Math.max(1, innerW - visibleWidth(footerLeft) - visibleWidth(footerRight));\n lines.push(row(footerLeft + \" \".repeat(footerGap) + footerRight));\n }\n if (!this.fullscreen) {\n lines.push(hrBot);\n return lines;\n }\n // Keep the footer on screen even in a terminal shorter than the chrome.\n // Never empty: the header and footer rows were pushed above.\n const footer = lines.pop()!;\n const output = rows > 0 ? [...lines.slice(0, rows - 1), footer] : [];\n const footerText = stripTerminalSequences(footer);\n for (const action of footerActions) {\n const index = footerText.indexOf(action.label);\n if (index < 0) continue; // a clipped label is not a clickable control\n const start = visibleWidth(footerText.slice(0, index));\n this.footerTargets.push({ start, end: start + visibleWidth(action.label), key: action.key });\n }\n return output;\n }\n\n /** Stoppable only when a stop handler exists and the agent is still active. */\n private isStoppable(): boolean {\n return !!this.onStop && (this.record.status === \"running\" || this.record.status === \"queued\");\n }\n\n /** The mode in force: an `m` press, else the setting, else the default. */\n private markdownMode(): ViewerMarkdownMode {\n return this.markdownModeOverride ?? this.viewerMarkdown?.() ?? \"assistant\";\n }\n\n /** Wrap `text` literally \u2014 the pre-Markdown path, and the fallback from it. */\n private rawLines(text: string, width: number, dim: boolean): string[] {\n const lines = wrapTextWithAnsi(text, width);\n return dim ? lines.map(l => this.theme.fg(\"dim\", l)) : lines;\n }\n\n /** Render `text` as Markdown, reusing this message's component instance. */\n private markdownLines(msg: AgentSession[\"messages\"][number], text: string, width: number, dim: boolean): string[] {\n let entry = this.markdownCache.get(msg);\n if (!entry) {\n entry = {\n md: new Markdown(\n text,\n 0,\n 0,\n this.markdownTheme,\n // Keeps result prose visually receded, the way the raw path's\n // per-line `fg(\"dim\", \u2026)` did. Fenced code is the exception and is\n // left alone deliberately: pi's theme highlights it with its own\n // colors, which this would otherwise flatten.\n dim ? { color: (t: string) => this.theme.fg(\"dim\", t) } : undefined,\n MARKDOWN_OPTIONS,\n ),\n text,\n };\n this.markdownCache.set(msg, entry);\n } else if (entry.text !== text) {\n // Streaming: the message object is stable, its text grows. A failed\n // prefix remains unsafe after append-only deltas, so retry only when the\n // content was replaced or truncated.\n const shouldRetry = !text.startsWith(entry.text);\n entry.md.setText(text);\n entry.text = text;\n if (shouldRetry) entry.failed = false;\n }\n if (entry.failed) return this.rawLines(text, width, dim);\n\n try {\n return entry.md.render(width);\n } catch {\n // The parser is recursive and this is arbitrary tool output: ~54 nested\n // blockquotes overflow the stack, and no amount of fuzzing proves that is\n // the only such input. `render()` is on the TUI's critical path, so a\n // throw here takes the overlay down for content the literal path shows\n // fine \u2014 degrade to that instead, and remember, since the throw would\n // otherwise repeat on every render and every scroll key.\n entry.failed = true;\n return this.rawLines(text, width, dim);\n }\n }\n\n /** Steerable only when a steer handler exists and the agent is still active. */\n private canSteer(): boolean {\n return !!this.onSteer && (this.record.status === \"running\" || this.record.status === \"queued\");\n }\n\n /**\n * Asked of the owner rather than derived from the record: only the caller\n * blocked on this run knows it can let go of it, and `blocking` alone also\n * matches spawns nobody can hand off (the agent generator).\n */\n private canSendToBackground(): boolean {\n return this.onBackground?.available() === true;\n }\n\n /** Open the inline steering composer and route subsequent input to it. */\n private openComposer(): void {\n const input = new Input();\n input.focused = true;\n input.onSubmit = (value: string) => {\n const message = value.trim();\n this.composer = undefined;\n if (message) this.onSteer?.(message);\n this.tui.requestRender();\n };\n input.onEscape = () => {\n this.composer = undefined;\n this.tui.requestRender();\n };\n this.composer = input;\n this.tui.requestRender();\n }\n\n invalidate(): void { /* no cached state to clear */ }\n\n dispose(): void {\n this.closed = true;\n this.scrollView.setScrollbar(\"hidden\"); // clears Pi's auto-hide timer\n this.stopLiveTimer();\n if (this.unsubscribe) {\n this.unsubscribe();\n this.unsubscribe = undefined;\n }\n }\n\n // ---- Private ----\n\n private viewportHeight(): number {\n if (this.fullscreen) return Math.max(0, this.tui.terminal.rows - this.chromeLines());\n // Cap mirrors the overlay's maxHeight \u2014 otherwise the viewer would render\n // more lines than the overlay shows and clip the footer.\n const maxRows = Math.floor((this.tui.terminal.rows * VIEWPORT_HEIGHT_PCT) / 100);\n return Math.max(MIN_VIEWPORT, maxRows - this.chromeLines());\n }\n\n private chromeLines(): number {\n // The composer adds one row above the footer hint while it's open.\n return CHROME_LINES_BASE - (this.fullscreen ? 2 : 0) + (this.invocationLine() ? 1 : 0) + (this.composer ? 1 : 0);\n }\n\n private invocationLine(): string | undefined {\n // Canonical id here, short label everywhere else: this overlay is opened to\n // inspect one agent and has the width for it, and two providers can serve\n // models whose short names read alike.\n const { modelName, modelId, tags } = buildInvocationTags(this.record.invocation);\n const model = modelId ?? modelName;\n const flag = fallbackFlag(this.theme, this.record);\n const parts = [...(model ? [model] : []), ...tags];\n if (parts.length === 0 && !flag) return undefined;\n // The flag leads the (possibly very long) canonical model id.\n return `${this.theme.fg(\"dim\", \" \u21B3\")} ${flag ? `${flag} ` : \"\"}${this.theme.fg(\"dim\", parts.join(\" \u00B7 \"))}`;\n }\n\n private buildContentLines(width: number): string[] {\n if (width <= 0) return [];\n\n const th = this.theme;\n const messages = this.session.messages;\n const lines: string[] = [];\n\n if (messages.length === 0) {\n lines.push(th.fg(\"dim\", \"(waiting for first message...)\"));\n return lines;\n }\n\n const mode = this.markdownMode();\n let needsSeparator = false;\n for (const msg of messages) {\n if (msg.role === \"user\") {\n const text = typeof msg.content === \"string\"\n ? msg.content\n : extractText(msg.content);\n if (!text.trim()) continue;\n if (needsSeparator) lines.push(th.fg(\"dim\", \"\u2500\u2500\u2500\"));\n lines.push(th.fg(\"accent\", \"[User]\"));\n for (const line of wrapTextWithAnsi(text.trim(), width)) {\n lines.push(line);\n }\n } else if (msg.role === \"assistant\") {\n const textParts: string[] = [];\n const toolCalls: string[] = [];\n for (const c of msg.content) {\n if (c.type === \"text\" && c.text) textParts.push(c.text);\n else if (c.type === \"toolCall\") {\n toolCalls.push((c as any).name ?? (c as any).toolName ?? \"unknown\");\n }\n }\n if (needsSeparator) lines.push(th.fg(\"dim\", \"\u2500\u2500\u2500\"));\n lines.push(th.bold(\"[Assistant]\"));\n if (textParts.length > 0) {\n const text = textParts.join(\"\\n\").trim();\n lines.push(...(mode === \"off\"\n ? this.rawLines(text, width, false)\n : this.markdownLines(msg, text, width, false)));\n }\n for (const name of toolCalls) {\n lines.push(truncateToWidth(th.fg(\"muted\", ` [Tool: ${name}]`), width));\n }\n } else if (msg.role === \"toolResult\") {\n const { text, elided } = capResult(extractText(msg.content).trim());\n if (!text) continue;\n if (needsSeparator) lines.push(th.fg(\"dim\", \"\u2500\u2500\u2500\"));\n lines.push(th.fg(\"dim\", \"[Result]\"));\n lines.push(...(mode === \"all\"\n ? this.markdownLines(msg, text, width, true)\n : this.rawLines(text, width, true)));\n if (elided) lines.push(truncateToWidth(th.fg(\"dim\", truncationNote(elided)), width));\n } else if ((msg as any).role === \"bashExecution\") {\n const bash = msg as any;\n if (needsSeparator) lines.push(th.fg(\"dim\", \"\u2500\u2500\u2500\"));\n lines.push(truncateToWidth(th.fg(\"muted\", ` $ ${bash.command}`), width));\n if (bash.output?.trim()) {\n // Same cap as a tool result, never Markdown: command output is the one\n // thing here that is definitionally not authored as Markdown.\n const { text, elided } = capResult(bash.output.trim());\n lines.push(...this.rawLines(text, width, true));\n if (elided) lines.push(truncateToWidth(th.fg(\"dim\", truncationNote(elided)), width));\n }\n } else {\n continue;\n }\n needsSeparator = true;\n }\n\n // The message being streamed is not in `messages` until it ends. Showing its\n // text as it arrives is what makes the viewer live rather than a log that\n // jumps a whole reply at a time. Literal, not Markdown: it is rebuilt on\n // every delta, and a half-written fence would reflow the whole message.\n const streaming = this.session.state?.streamingMessage;\n if (streaming?.role === \"assistant\" && !messages.includes(streaming)) {\n const text = streaming.content\n .flatMap(c => (c.type === \"text\" && c.text ? [c.text] : []))\n .join(\"\\n\")\n .trim();\n if (text) {\n if (needsSeparator) lines.push(th.fg(\"dim\", \"\u2500\u2500\u2500\"));\n lines.push(th.bold(\"[Assistant]\"));\n lines.push(...this.rawLines(text, width, false));\n }\n }\n\n // Streaming indicator for running agents\n if (this.record.status === \"running\" && this.activity) {\n const act = describeActivity(this.activity.activeTools, this.activity.responseText, this.activity.modelCall, this.clock.now());\n lines.push(\"\");\n lines.push(truncateToWidth(th.fg(\"accent\", \"\u258D \") + th.fg(\"dim\", act), width));\n }\n\n return lines.map(l => truncateToWidth(l, width));\n }\n}\n", "/**\n * agent-types.ts \u2014 Unified agent type registry.\n *\n * Merges embedded default agents with user-defined agents from .pi/agents/*.md, .agents/agents/*.md, and global agents.\n * User agents override defaults with the same name. Disabled agents are kept but excluded from spawning.\n */\n\nimport { createCodingTools, createReadOnlyTools } from \"@earendil-works/pi-coding-agent\";\nimport { DEFAULT_AGENTS } from \"./default-agents.js\";\nimport type { AgentConfig } from \"./types.js\";\n\n/**\n * All known built-in tool names, derived from pi's own tool factories rather\n * than hardcoded so the set tracks pi-mono if it adds/renames a built-in.\n * `createCodingTools` \u2192 read/bash/edit/write; `createReadOnlyTools` \u2192\n * read/grep/find/ls; their de-duplicated union is the 7 built-ins\n * (read, bash, edit, write, grep, find, ls). The `cwd` only binds tool\n * operations we never invoke here \u2014 we read each tool's `.name` and discard it.\n */\nexport const BUILTIN_TOOL_NAMES: string[] = [\n ...new Set([...createCodingTools(\".\"), ...createReadOnlyTools(\".\")].map((t) => t.name)),\n];\n\n/** Unified runtime registry of all agents (defaults + user-defined). */\nconst agents = new Map<string, AgentConfig>();\n\n/** When true, DEFAULT_AGENTS are skipped during registration. */\nlet disableDefaults = false;\n\n/** Check whether default agents are disabled. */\nexport function isDefaultsDisabled(): boolean { return disableDefaults; }\n\n/** Set whether default agents are disabled. */\nexport function setDefaultsDisabled(b: boolean): void { disableDefaults = b; }\n\n/** `fallbackSubagent` value that disables the fallback entirely (strict dispatch). */\nexport const NO_FALLBACK = \"none\";\n\n/**\n * Agent type substituted when a caller-supplied `subagent_type` doesn't resolve\n * to exactly one enabled agent. `undefined` keeps the historical behavior\n * (general-purpose); `NO_FALLBACK` makes dispatch fail closed. Set from\n * `subagents.json` (`fallbackSubagent`).\n *\n * Module state rather than an index.ts closure because every caller-supplied\n * spawn path needs it \u2014 the Agent tool, the scheduler, and cross-extension RPC.\n */\nlet fallbackSubagent: string | undefined;\n\n/** Get the configured fallback agent type. undefined = general-purpose. */\nexport function getFallbackSubagent(): string | undefined { return fallbackSubagent; }\n\n/** Set the configured fallback agent type. undefined = general-purpose. */\nexport function setFallbackSubagent(v: string | undefined): void { fallbackSubagent = v; }\n\n/**\n * Build a registry map: DEFAULT_AGENTS first (unless disabled via settings),\n * then user agents overlaid on top (same name overrides the default).\n * Pure \u2014 callers that must not disturb the process-wide registry (nested\n * delegation resolving agents from its own config root) build their own map.\n */\nexport function buildAgentRegistry(userAgents: Map<string, AgentConfig>): Map<string, AgentConfig> {\n const registry = new Map<string, AgentConfig>();\n if (!disableDefaults) {\n for (const [name, config] of DEFAULT_AGENTS) registry.set(name, config);\n }\n for (const [name, config] of userAgents) registry.set(name, config);\n return registry;\n}\n\n/**\n * Register agents into the unified registry.\n * Starts with DEFAULT_AGENTS, then overlays user agents (overrides defaults with same name).\n * Disabled agents (enabled === false) are kept in the registry but excluded from spawning.\n */\nexport function registerAgents(userAgents: Map<string, AgentConfig>): void {\n agents.clear();\n for (const [name, config] of buildAgentRegistry(userAgents)) {\n agents.set(name, config);\n }\n}\n\n/** Case-insensitive key resolution within a registry. */\nfunction resolveKeyIn(registry: Map<string, AgentConfig>, name: string): string | undefined {\n if (registry.has(name)) return name;\n const lower = name.toLowerCase();\n for (const key of registry.keys()) {\n if (key.toLowerCase() === lower) return key;\n }\n return undefined;\n}\n\n/** Case-insensitive key resolution. */\nfunction resolveKey(name: string): string | undefined {\n return resolveKeyIn(agents, name);\n}\n\n/** Resolve a type name case-insensitively in a registry. Returns the canonical key or undefined. */\nexport function resolveTypeIn(registry: Map<string, AgentConfig>, name: string): string | undefined {\n return resolveKeyIn(registry, name);\n}\n\n/** Get the agent config for a type (case-insensitive) from a registry. */\nexport function getAgentConfigIn(registry: Map<string, AgentConfig>, name: string): AgentConfig | undefined {\n const key = resolveKeyIn(registry, name);\n return key ? registry.get(key) : undefined;\n}\n\n/** Check if a type is valid and enabled (case-insensitive) in a registry. */\nexport function isValidTypeIn(registry: Map<string, AgentConfig>, type: string): boolean {\n const key = resolveKeyIn(registry, type);\n if (!key) return false;\n return registry.get(key)?.enabled !== false;\n}\n\n/** Get all enabled type names in a registry (for spawning and tool descriptions). */\nexport function getAvailableTypesIn(registry: Map<string, AgentConfig>): string[] {\n return [...registry.entries()]\n .filter(([_, config]) => config.enabled !== false)\n .map(([name]) => name);\n}\n\n/**\n * Case-insensitive resolution that refuses to guess. An exact match always wins;\n * otherwise the name must match exactly one key. Two agents differing only in\n * case are reachable (`loadCustomAgents` keys by filename across three\n * directories), and picking whichever came first would silently dispatch a\n * different agent, model and tool policy than the caller meant.\n */\nfunction resolveUnambiguousKeyIn(registry: Map<string, AgentConfig>, name: string): string | undefined {\n if (registry.has(name)) return name;\n const lower = name.toLowerCase();\n const matches = [...registry.keys()].filter(key => key.toLowerCase() === lower);\n return matches.length === 1 ? matches[0] : undefined;\n}\n\n/**\n * The canonical key for a caller-supplied name that identifies exactly one\n * ENABLED agent, or undefined. Strict by construction: no fallback, no guessing\n * between case-variants. Nested delegation resolves with this directly, since\n * \"unknown types are rejected rather than falling back\" is its own contract.\n */\nexport function resolveEnabledTypeIn(\n registry: Map<string, AgentConfig>,\n requested: unknown,\n): string | undefined {\n const raw = typeof requested === \"string\" ? requested.trim() : \"\";\n if (!raw) return undefined;\n const key = resolveUnambiguousKeyIn(registry, raw);\n return key !== undefined && registry.get(key)?.enabled !== false ? key : undefined;\n}\n\n/** Outcome of resolving a caller-supplied `subagent_type` into a spawnable type. */\nexport type SpawnTypeResolution =\n /** Spawn this type. `fellBackFrom` is set when it isn't what the caller asked for. */\n | { ok: true; type: string; fellBackFrom?: string }\n /** Refuse the spawn and return this message to the caller. */\n | { ok: false; message: string };\n\n/**\n * Resolve a caller-supplied agent type against a registry, applying the\n * `fallbackSubagent` policy. The single decision point for every caller-supplied\n * spawn \u2014 the Agent tool, the scheduler, cross-extension RPC, and the nested\n * tools \u2014 so a type that fails here never reaches `runAgent`, where `getConfig`\n * would silently substitute general-purpose.\n *\n * Unknown, disabled, and case-ambiguous names are all treated the same way:\n * the caller named something that doesn't identify exactly one enabled agent.\n *\n * Pure over `registry` \u2014 callers that need fresh agent files reload before\n * calling (the Agent tool already does, per spawn). Reloading here would mean\n * importing custom-agents.ts, which imports this module.\n */\nexport function resolveSpawnTypeIn(\n registry: Map<string, AgentConfig>,\n requested: unknown,\n): SpawnTypeResolution {\n const raw = typeof requested === \"string\" ? requested.trim() : \"\";\n const available = () => getAvailableTypesIn(registry).join(\", \") || \"(none)\";\n\n const key = resolveEnabledTypeIn(registry, raw);\n if (key !== undefined) return { ok: true, type: key };\n\n // A missing type follows the same policy as a wrong one rather than always\n // erroring: before this setting existed an empty type fell back like any\n // other unresolvable name, and only opting in should change that.\n const reason = raw ? `Unknown or disabled agent type: \"${raw}\".` : \"No agent type given.\";\n\n // Trimmed like `requested`: a padded value set programmatically would\n // otherwise be reported as a missing agent.\n const configured = typeof fallbackSubagent === \"string\" ? fallbackSubagent.trim() : undefined;\n\n if (configured !== undefined && configured.toLowerCase() === NO_FALLBACK) {\n return { ok: false, message: `${reason} Available: ${available()}.` };\n }\n\n if (configured !== undefined) {\n // An explicitly configured fallback that is itself unusable is a\n // misconfiguration, not a second chance to guess \u2014 say so rather than\n // quietly dropping to general-purpose.\n const fallbackKey = resolveUnambiguousKeyIn(registry, configured);\n if (fallbackKey === undefined || registry.get(fallbackKey)?.enabled === false) {\n return {\n ok: false,\n message:\n `${reason} The configured fallbackSubagent \"${configured}\" is itself ` +\n `unknown or disabled. Available: ${available()}.`,\n };\n }\n return { ok: true, type: fallbackKey, fellBackFrom: raw };\n }\n\n // Unset: historical behavior, deliberately unchanged. #183 asks for the\n // fallback to remain the default, so the pre-existing hole it leaves \u2014 an\n // unregistered general-purpose resolving to `getConfig`'s all-tools hardcoded\n // tier \u2014 is what `fallbackSubagent: none` is for, not something to close\n // under everyone silently.\n return { ok: true, type: \"general-purpose\", fellBackFrom: raw };\n}\n\n/** Resolve a caller-supplied agent type against the process-wide registry. */\nexport function resolveSpawnType(requested: unknown): SpawnTypeResolution {\n return resolveSpawnTypeIn(agents, requested);\n}\n\n/** Resolve a type name case-insensitively. Returns the canonical key or undefined. */\nexport function resolveType(name: string): string | undefined {\n return resolveKey(name);\n}\n\n/** Get the agent config for a type (case-insensitive). */\nexport function getAgentConfig(name: string): AgentConfig | undefined {\n return getAgentConfigIn(agents, name);\n}\n\n/** Get all enabled type names (for spawning and tool descriptions). */\nexport function getAvailableTypes(): string[] {\n return getAvailableTypesIn(agents);\n}\n\n/** Get all type names including disabled (for UI listing). */\nexport function getAllTypes(): string[] {\n return [...agents.keys()];\n}\n\n/** Get names of default agents currently in the registry. */\nexport function getDefaultAgentNames(): string[] {\n return [...agents.entries()]\n .filter(([_, config]) => config.isDefault === true)\n .map(([name]) => name);\n}\n\n/** Get names of user-defined agents (non-defaults) currently in the registry. */\nexport function getUserAgentNames(): string[] {\n return [...agents.entries()]\n .filter(([_, config]) => config.isDefault !== true)\n .map(([name]) => name);\n}\n\n/** Check if a type is valid and enabled (case-insensitive). */\nexport function isValidType(type: string): boolean {\n return isValidTypeIn(agents, type);\n}\n\n/** Tool names required for memory management. */\nconst MEMORY_TOOL_NAMES = [\"read\", \"write\", \"edit\"];\n\n/**\n * Get memory tool names (read/write/edit) not already in the provided set.\n */\nexport function getMemoryToolNames(existingToolNames: Set<string>): string[] {\n return MEMORY_TOOL_NAMES.filter(n => !existingToolNames.has(n));\n}\n\n/** Tool names needed for read-only memory access. */\nconst READONLY_MEMORY_TOOL_NAMES = [\"read\"];\n\n/**\n * Get read-only memory tool names not already in the provided set.\n */\nexport function getReadOnlyMemoryToolNames(existingToolNames: Set<string>): string[] {\n return READONLY_MEMORY_TOOL_NAMES.filter(n => !existingToolNames.has(n));\n}\n\n/** Get built-in tool names for a type (case-insensitive). */\nexport function getToolNamesForType(type: string): string[] {\n const key = resolveKey(type);\n const raw = key ? agents.get(key) : undefined;\n const config = raw?.enabled !== false ? raw : undefined;\n // `undefined` (definition omitted the field) \u2192 all built-ins; an explicit `[]`\n // (`tools: none` or a `tools:` with only `ext:` entries) \u2192 zero built-ins.\n return config?.builtinToolNames ?? [...BUILTIN_TOOL_NAMES];\n}\n\n/** Get config for a type (case-insensitive, returns a SubagentTypeConfig-compatible object). Falls back to general-purpose. */\nexport function getConfig(type: string): {\n displayName: string;\n color?: string;\n description: string;\n builtinToolNames: string[];\n extensions: true | string[] | false;\n excludeExtensions?: string[];\n skills: true | string[] | false;\n promptMode: \"replace\" | \"append\";\n} {\n const key = resolveKey(type);\n const config = key ? agents.get(key) : undefined;\n if (config && config.enabled !== false) {\n return {\n displayName: config.displayName ?? config.name,\n color: config.color,\n description: config.description,\n builtinToolNames: config.builtinToolNames ?? BUILTIN_TOOL_NAMES,\n extensions: config.extensions,\n excludeExtensions: config.excludeExtensions,\n skills: config.skills,\n promptMode: config.promptMode,\n };\n }\n\n // Fallback for unknown/disabled types \u2014 general-purpose config\n const gp = agents.get(\"general-purpose\");\n if (gp && gp.enabled !== false) {\n return {\n displayName: gp.displayName ?? gp.name,\n color: gp.color,\n description: gp.description,\n builtinToolNames: gp.builtinToolNames ?? BUILTIN_TOOL_NAMES,\n extensions: gp.extensions,\n excludeExtensions: gp.excludeExtensions,\n skills: gp.skills,\n promptMode: gp.promptMode,\n };\n }\n\n // Absolute fallback (should never happen)\n return {\n displayName: \"Agent\",\n description: \"General-purpose agent for complex, multi-step tasks\",\n builtinToolNames: BUILTIN_TOOL_NAMES,\n extensions: true,\n skills: true,\n promptMode: \"append\",\n };\n}\n\n", "/**\n * default-agents.ts \u2014 Embedded default agent configurations.\n *\n * These are always available but can be overridden by user .md files with the same name.\n */\n\nimport type { AgentConfig } from \"./types.js\";\n\n/**\n * Tool surface shared by Explore and Plan. `bash` is left out because a prompt cannot\n * make an unrestricted shell read-only, and extensions are off because extension tools\n * can run commands or write. A `.pi/agents/<Name>.md` override can opt back in with an\n * explicit `extensions:` list.\n */\nconst READ_ONLY_SURFACE: Pick<AgentConfig, \"builtinToolNames\" | \"extensions\" | \"skills\"> = {\n builtinToolNames: [\"read\", \"grep\", \"find\", \"ls\"],\n extensions: false,\n skills: true,\n};\n\nexport const DEFAULT_AGENTS: Map<string, AgentConfig> = new Map([\n [\n \"general-purpose\",\n {\n name: \"general-purpose\",\n displayName: \"Agent\",\n description: \"General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you.\",\n // builtinToolNames omitted \u2014 means \"all available tools\" (resolved at lookup time)\n // inheritContext / runInBackground / isolated omitted \u2014 strategy fields, callers decide per-call.\n // Setting them to false would lock callsite intent (see resolveAgentInvocationConfig in invocation-config.ts).\n extensions: true,\n skills: true,\n systemPrompt: \"\",\n promptMode: \"append\",\n isDefault: true,\n },\n ],\n [\n \"Explore\",\n {\n name: \"Explore\",\n displayName: \"Explore\",\n description: \"Fast read-only search agent for locating code. Use it to find files by pattern (eg. \\\"src/components/**/*.tsx\\\"), grep for symbols or keywords (eg. \\\"API endpoints\\\"), or answer \\\"where is X defined / which files reference Y.\\\" Do NOT use it for code review, design-doc auditing, cross-file consistency checks, or open-ended analysis \u2014 it reads excerpts rather than whole files and will miss content past its read window. When calling, specify search breadth: \\\"quick\\\" for a single targeted lookup, \\\"medium\\\" for moderate exploration, or \\\"very thorough\\\" to search across multiple locations and naming conventions.\",\n ...READ_ONLY_SURFACE,\n // Bind the role per machine, not to a provider or model generation.\n model: \"@cheap\",\n systemPrompt: `# CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS\nYou are a file search specialist. You excel at thoroughly navigating and exploring codebases.\nYour role is EXCLUSIVELY to search and analyze existing code. You do NOT have access to file editing tools.\n\nYou are STRICTLY PROHIBITED from:\n- Creating new files\n- Modifying existing files\n- Deleting files\n- Moving or copying files\n- Creating temporary files anywhere, including /tmp\n- Using redirect operators (>, >>, |) or heredocs to write to files\n- Running ANY commands that change system state\n\n# Tool Usage\n- Use the find tool for file pattern matching\n- Use the grep tool for content search\n- Use the read tool for reading files\n- Make independent tool calls in parallel for efficiency\n- Adapt search approach based on thoroughness level specified\n\n# Output\n- Use absolute file paths in all references\n- Report findings as regular messages\n- Do not use emojis\n- Be thorough and precise`,\n promptMode: \"replace\",\n isDefault: true,\n },\n ],\n [\n \"Plan\",\n {\n name: \"Plan\",\n displayName: \"Plan\",\n description: \"Software architect agent for designing implementation plans. Use this when you need to plan the implementation strategy for a task. Returns step-by-step plans, identifies critical files, and considers architectural trade-offs.\",\n ...READ_ONLY_SURFACE,\n systemPrompt: `# CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS\nYou are a software architect and planning specialist.\nYour role is EXCLUSIVELY to explore the codebase and design implementation plans.\nYou do NOT have access to file editing tools \u2014 attempting to edit files will fail.\n\nYou are STRICTLY PROHIBITED from:\n- Creating new files\n- Modifying existing files\n- Deleting files\n- Moving or copying files\n- Creating temporary files anywhere, including /tmp\n- Using redirect operators (>, >>, |) or heredocs to write to files\n- Running ANY commands that change system state\n\n# Planning Process\n1. Understand requirements\n2. Explore thoroughly (read files, find patterns, understand architecture)\n3. Design solution based on your assigned perspective\n4. Detail the plan with step-by-step implementation strategy\n\n# Requirements\n- Consider trade-offs and architectural decisions\n- Identify dependencies and sequencing\n- Anticipate potential challenges\n- Follow existing patterns where appropriate\n\n# Tool Usage\n- Use the find tool for file pattern matching\n- Use the grep tool for content search\n- Use the read tool for reading files\n\n# Output Format\n- Use absolute file paths\n- Do not use emojis\n- End your response with:\n\n### Critical Files for Implementation\nList 3-5 files most critical for implementing this plan:\n- /absolute/path/to/file.ts - [Brief reason]`,\n promptMode: \"replace\",\n isDefault: true,\n },\n ],\n]);\n", "/**\n * agent-color.ts \u2014 Claude Code-compatible agent name badges.\n *\n * Claude Code renders a subagent's name as a badge: the configured color is the\n * background, the text an inverse foreground. Its eight named colors are\n * reproduced here, along with six-digit hex and the extra palette names Agency\n * Agents uses, so those definitions render as written.\n */\n\nimport { getConfig } from \"./agent-types.js\";\n\nconst NAMED_AGENT_COLORS: Readonly<Record<string, string>> = {\n // Claude Code's eight subagent colors, as its default theme renders them.\n red: \"#DC2626\",\n blue: \"#6A9BCC\",\n green: \"#16A34A\",\n yellow: \"#CA8A04\",\n purple: \"#827DBD\",\n orange: \"#D97757\",\n pink: \"#C46686\",\n cyan: \"#0891B2\",\n // Agency Agents palette aliases.\n amber: \"#F59E0B\",\n teal: \"#008080\",\n indigo: \"#6366F1\",\n gold: \"#EAB308\",\n \"neon-green\": \"#10B981\",\n \"neon-cyan\": \"#06B6D4\",\n \"metallic-blue\": \"#3B82F6\",\n violet: \"#8B5CF6\",\n rose: \"#F43F5E\",\n lime: \"#84CC16\",\n gray: \"#6B7280\",\n grey: \"#6B7280\",\n fuchsia: \"#D946EF\",\n slate: \"#64748B\",\n navy: \"#1E3A8A\",\n};\n\nconst CUBE_VALUES = [0, 95, 135, 175, 215, 255];\nconst GRAY_VALUES = Array.from({ length: 24 }, (_, i) => 8 + i * 10);\nconst BLACK = { r: 0, g: 0, b: 0 };\nconst WHITE = { r: 255, g: 255, b: 255 };\n\ntype Rgb = { r: number; g: number; b: number };\ntype ColorMode = \"truecolor\" | \"256color\";\n\nexport interface AgentNameTheme {\n fg(color: string, text: string): string;\n bold(text: string): string;\n getColorMode?(): ColorMode;\n}\n\nexport interface AgentNameStyle {\n /** Existing theme foreground used when no valid agent color is configured. */\n fallbackColor?: string;\n /** Reapply an enclosing background after the badge instead of resetting it. */\n restoreBackground?: string;\n bold?: boolean;\n}\n\n/** Resolve Claude Code/Agency Agents color syntax to normalized #RRGGBB. */\nexport function resolveAgentColor(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const normalized = value.trim().toLowerCase();\n const resolved = NAMED_AGENT_COLORS[normalized] ?? normalized;\n return /^#[0-9a-f]{6}$/i.test(resolved) ? resolved.toUpperCase() : undefined;\n}\n\nfunction parseHex(hex: string): Rgb {\n return {\n r: Number.parseInt(hex.slice(1, 3), 16),\n g: Number.parseInt(hex.slice(3, 5), 16),\n b: Number.parseInt(hex.slice(5, 7), 16),\n };\n}\n\n/** Index of the entry in `values` closest to `value`. */\nfunction nearest(values: readonly number[], value: number): number {\n return values.reduce((best, v, i) => (Math.abs(value - v) < Math.abs(value - values[best]) ? i : best), 0);\n}\n\n/**\n * Quantize to the xterm-256 palette the way pi's own theme does, returning both\n * the index to emit and the color the terminal will actually show \u2014 badge\n * contrast is judged against the latter.\n */\nfunction rgbTo256({ r, g, b }: Rgb): { index: number; rgb: Rgb } {\n const [rIndex, gIndex, bIndex] = [r, g, b].map((channel) => nearest(CUBE_VALUES, channel));\n const distance = ({ r: cr, g: cg, b: cb }: Rgb) => 0.299 * (r - cr) ** 2 + 0.587 * (g - cg) ** 2 + 0.114 * (b - cb) ** 2;\n const grayIndex = nearest(GRAY_VALUES, Math.round(0.299 * r + 0.587 * g + 0.114 * b));\n const gray = { r: GRAY_VALUES[grayIndex], g: GRAY_VALUES[grayIndex], b: GRAY_VALUES[grayIndex] };\n const cube = { r: CUBE_VALUES[rIndex], g: CUBE_VALUES[gIndex], b: CUBE_VALUES[bIndex] };\n // Only near-neutral colors may take the gray ramp; anything else keeps its tint.\n if (Math.max(r, g, b) - Math.min(r, g, b) < 10 && distance(gray) < distance(cube)) {\n return { index: 232 + grayIndex, rgb: gray };\n }\n return { index: 16 + 36 * rIndex + 6 * gIndex + bIndex, rgb: cube };\n}\n\nfunction ansiColor(layer: \"foreground\" | \"background\", color: Rgb | number): string {\n const code = layer === \"foreground\" ? 38 : 48;\n return typeof color === \"number\"\n ? `\\u001b[${code};5;${color}m`\n : `\\u001b[${code};2;${color.r};${color.g};${color.b}m`;\n}\n\nfunction relativeLuminance({ r, g, b }: Rgb): number {\n const linear = (value: number) => {\n const channel = value / 255;\n return channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);\n}\n\n/**\n * Render one name as a padded background badge when `color` is valid. Claude\n * Code uses one inverse color for every badge's text; black or white is picked\n * by WCAG contrast here instead, so each palette entry stays readable. Invalid\n * or omitted colors preserve the caller's existing theme styling.\n */\nexport function renderAgentNameLabel(\n name: string,\n color: string | undefined,\n theme: AgentNameTheme,\n style: AgentNameStyle = {},\n): string {\n const resolved = resolveAgentColor(color);\n if (!resolved) {\n const text = style.bold ? theme.bold(name) : name;\n return style.fallbackColor ? theme.fg(style.fallbackColor, text) : text;\n }\n\n const rgb = parseHex(resolved);\n const quantized = (theme.getColorMode?.() ?? \"truecolor\") === \"256color\" ? rgbTo256(rgb) : undefined;\n const shown = quantized?.rgb ?? rgb;\n const contrasting = relativeLuminance(shown) > 0.179 ? BLACK : WHITE;\n const label = style.bold ? theme.bold(` ${name} `) : ` ${name} `;\n\n return ansiColor(\"background\", quantized?.index ?? rgb)\n + ansiColor(\"foreground\", quantized ? rgbTo256(contrasting).index : contrasting)\n + label\n + \"\\u001b[39m\"\n + (style.restoreBackground ?? \"\\u001b[49m\");\n}\n\n/** Whether an agent renders as a badge \u2014 i.e. it has a valid configured color. */\nexport function hasAgentBadge(type: string | undefined): boolean {\n return type !== undefined && resolveAgentColor(getConfig(type).color) !== undefined;\n}\n\n/** Render a registered agent's display name with its configured color. */\nexport function renderAgentName(\n type: string | undefined,\n theme: AgentNameTheme,\n style: AgentNameStyle = {},\n): string {\n if (!type) return renderAgentNameLabel(\"Agent\", undefined, theme, style);\n const config = getConfig(type);\n return renderAgentNameLabel(config.displayName, config.color, theme, style);\n}\n", "/** A timer owns cancellation, without requiring a Node-specific handle. */\nexport interface TimerHandle {\n cancel(): void;\n unref?(): void;\n}\n\n/** Scheduling boundary, structurally compatible with pi-session-kit's clock. */\nexport interface Clock {\n now(): number;\n setTimeout(callback: () => void, ms: number): TimerHandle;\n setInterval(callback: () => void, ms: number): TimerHandle;\n}\n\n/** Native timers keep their original reference/unref behavior; cancellation uses the native clear functions. */\nexport const realClock: Clock = {\n now: () => Date.now(),\n setTimeout(callback, ms) {\n const timer = setTimeout(callback, ms);\n return { cancel: () => clearTimeout(timer) };\n },\n setInterval(callback, ms) {\n const timer = setInterval(callback, ms);\n return { cancel: () => clearInterval(timer), unref: () => { timer.unref(); } };\n },\n};\n", "/**\n * context.ts \u2014 Extract parent conversation context for subagent inheritance.\n */\n\nimport type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\n\n/** Extract text from a message content block array. */\nexport function extractText(content: unknown[]): string {\n return content\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text ?? \"\")\n .join(\"\\n\");\n}\n\n/**\n * Build a text representation of the parent conversation context.\n * Used when inherit_context is true to give the subagent visibility\n * into what has been discussed/done so far.\n */\nexport function buildParentContext(ctx: ExtensionContext): string {\n const entries = ctx.sessionManager.getBranch();\n if (!entries || entries.length === 0) return \"\";\n\n const parts: string[] = [];\n\n for (const entry of entries) {\n if (entry.type === \"message\") {\n const msg = entry.message;\n if (msg.role === \"user\") {\n const text = typeof msg.content === \"string\"\n ? msg.content\n : extractText(msg.content);\n if (text.trim()) parts.push(`[User]: ${text.trim()}`);\n } else if (msg.role === \"assistant\") {\n const text = extractText(msg.content);\n if (text.trim()) parts.push(`[Assistant]: ${text.trim()}`);\n }\n // Skip toolResult messages \u2014 too verbose for context\n } else if (entry.type === \"compaction\") {\n // Include compaction summaries \u2014 they're already condensed\n if (entry.summary) {\n parts.push(`[Summary]: ${entry.summary}`);\n }\n }\n }\n\n if (parts.length === 0) return \"\";\n\n return `# Parent Conversation Context\nThe following is the conversation history from the parent session that spawned you.\nUse this context to understand what has been discussed and decided so far.\n\n${parts.join(\"\\n\\n\")}\n\n---\n# Your Task (below)\n`;\n}\n", "/** usage.ts \u2014 Token usage: shapes, accumulator operators, session-stats readers. */\n\n/**\n * Lifetime usage components, accumulated via `message_end` events. Survives\n * compaction (which replaces session.state.messages and would reset any\n * stats-derived sum). cacheRead is excluded because each turn's cacheRead is\n * the cumulative cached prefix re-read on that one call \u2014 summing across\n * turns counts the prefix N times. See issue #38.\n *\n * That exclusion is about this *display* total, not about what was billed: the\n * prefix really is re-read and re-charged on every call. So `cacheRead` is\n * accumulated here anyway, kept out of `getLifetimeTotal` and used only where\n * billing is the question \u2014 reporting to the parent session, whose own messages\n * pi counts the same way (`addUsageToTotals`). Reporting 0 there would make a\n * subagent's rows count differently from every other row in one total.\n *\n * `cost` is a plain sum for the same reason: it is what pi charged for that one\n * message (`usage.cost.total`, priced from the model's rates), not a cumulative\n * figure. Both are optional because a model with no pricing data reports no\n * cost, and because every accumulator predates them; absent reads as 0.\n */\nexport type LifetimeUsage = { input: number; output: number; cacheWrite: number; cacheRead?: number; cost?: number };\n\n/**\n * Sum of lifetime *token* components for DISPLAY, or 0 if undefined.\n * Deliberately excludes `cacheRead` (see above) and `cost` \u2014 that is money, not\n * tokens, and lives on the same object only because it accumulates on the same\n * events.\n */\nexport function getLifetimeTotal(u?: LifetimeUsage): number {\n return u ? u.input + u.output + u.cacheWrite : 0;\n}\n\n/** Accumulated cost in USD, or 0 when unpriced/undefined. */\nexport function getLifetimeCost(u?: LifetimeUsage): number {\n return u?.cost ?? 0;\n}\n\n/** Add a usage delta into a target accumulator (mutates target). */\nexport function addUsage(into: LifetimeUsage, delta: LifetimeUsage): void {\n into.input += delta.input;\n into.output += delta.output;\n into.cacheWrite += delta.cacheWrite;\n if (delta.cacheRead) into.cacheRead = (into.cacheRead ?? 0) + delta.cacheRead;\n if (delta.cost) into.cost = (into.cost ?? 0) + delta.cost;\n}\n\n/**\n * A pi `Usage`. Rebuilt here rather than imported so this module stays\n * dependency-free for tests; the fields are pi's, and every one of them must be\n * present: pi's `addUsageToTotals` dereferences `usage.cost.total` with no\n * guard, so a partial object throws inside pi rather than at the call site.\n *\n * This is pi's convention for spend in anything handed to a consumer \u2014 every\n * extension-facing payload that carries it takes the whole object\n * (`ToolResultEvent`, `ToolResultEventResult`, `AssistantMessage`, \u2026), never a\n * flattened cost. Pi flattens only in computed read APIs it expects you to\n * render, like `SessionStats`. So both places we hand usage to someone else \u2014\n * `AgentToolResult.usage` and the `subagents:completed` / `subagents:failed`\n * events \u2014 carry this, and gain whatever pi adds to `Usage` for free.\n */\nexport type ReportedUsage = {\n input: number;\n output: number;\n cacheRead: number;\n cacheWrite: number;\n totalTokens: number;\n cost: { input: number; output: number; cacheRead: number; cacheWrite: number; total: number };\n};\n\n/**\n * Render an accumulator as a pi `Usage`, or undefined when nothing was spent \u2014\n * callers attach nothing rather than a zero, so a consumer can tell \"spent\n * nothing\" from \"never ran\".\n *\n * `cacheRead` IS included, unlike in `getLifetimeTotal`: pi sums it across a\n * session's own assistant messages, and the prefix genuinely is re-read and\n * re-billed on every call. Only `total` is populated on the cost breakdown; pi\n * reads nothing else from it, and the per-kind split is not tracked.\n */\nexport function toReportedUsage(u: LifetimeUsage): ReportedUsage | undefined {\n const { input, output, cacheWrite, cacheRead = 0, cost = 0 } = u;\n if (input === 0 && output === 0 && cacheWrite === 0 && cacheRead === 0 && cost === 0) return undefined;\n return {\n input,\n output,\n cacheRead,\n cacheWrite,\n totalTokens: input + output + cacheRead + cacheWrite,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: cost },\n };\n}\n\n/**\n * Subagent spend that the parent session has not been told about yet.\n *\n * Subagents run in their own pi sessions, so none of what they spend appears in\n * the parent's `getSessionStats()`. Pi does aggregate `toolResult.usage` into\n * those stats, though \u2014 so the way back into the parent's footer and `/cost` is\n * to hang the spend on a tool result. Background and scheduled agents finish\n * between tool calls with nothing to hang it on, hence a pool: every assistant\n * message lands here as it happens, and the next tool result we return carries\n * whatever has accumulated.\n *\n * Drain empties it, so each message is reported exactly once no matter how many\n * results are returned or how many agents were running.\n */\nexport class PendingUsagePool {\n private pending: LifetimeUsage = { input: 0, output: 0, cacheWrite: 0, cacheRead: 0, cost: 0 };\n private dirty = false;\n\n add(delta: LifetimeUsage): void {\n addUsage(this.pending, delta);\n this.dirty = true;\n }\n\n /**\n * Take everything accumulated so far as a pi `Usage`, resetting the pool.\n * Returns undefined when nothing is pending, so callers can leave the tool\n * result untouched rather than attaching a zero.\n */\n drain(): ReportedUsage | undefined {\n if (!this.dirty) return undefined;\n const drained = toReportedUsage(this.pending);\n this.pending = { input: 0, output: 0, cacheWrite: 0, cacheRead: 0, cost: 0 };\n this.dirty = false;\n return drained;\n }\n}\n\n/** Minimal shape we read from upstream `getSessionStats()`. */\nexport type SessionStatsLike = {\n tokens: { input: number; output: number; cacheWrite: number };\n contextUsage?: { percent: number | null };\n};\nexport type SessionLike = { getSessionStats(): SessionStatsLike };\n\n/**\n * Session-scoped token count: input + output + cacheWrite as reported by\n * upstream `getSessionStats().tokens` for the *current* session window.\n *\n * RESETS at compaction \u2014 upstream replaces `session.state.messages` and the\n * stats are derived from that array. For a lifetime total that survives\n * compaction, use `getLifetimeTotal(lifetimeUsage)` instead, which reads\n * from an independent accumulator fed by `message_end` events.\n *\n * Avoids upstream's `tokens.total` field, which sums per-turn `cacheRead`\n * and so counts the cumulative cached prefix N times across N turns\n * (issue #38).\n */\nexport function getSessionTokens(session: SessionLike | undefined): number {\n if (!session) return 0;\n try {\n const t = session.getSessionStats().tokens;\n return t.input + t.output + t.cacheWrite;\n } catch { return 0; }\n}\n\n/**\n * Context-window utilization (0\u2013100), or null when unavailable\n * (no model contextWindow, or post-compaction before the next response).\n */\nexport function getSessionContextPercent(session: SessionLike | undefined): number | null {\n if (!session) return null;\n try { return session.getSessionStats().contextUsage?.percent ?? null; }\n catch { return null; }\n}\n", "/**\n * agent-widget.ts \u2014 Persistent widget showing running/completed agents above the editor.\n *\n * Displays a tree of agents with animated spinners, live stats, and activity descriptions.\n * Uses the callback form of setWidget for themed rendering.\n */\n\nimport { truncateToWidth } from \"@earendil-works/pi-tui\";\nimport { renderAgentName } from \"../agent-color.js\";\nimport { type AgentManager, isTopLevelAgent } from \"../agent-manager.js\";\nimport { getConfig } from \"../agent-types.js\";\nimport { type Clock, realClock, type TimerHandle } from \"../clock.js\";\nimport { describeModelCall, type ModelCallState } from \"../model-call.js\";\nimport type { ModelFallback } from \"../model-resolver.js\";\nimport type { TierDisclosure } from \"../model-tiers.js\";\nimport type { AgentInvocation, SubagentType, WidgetMode } from \"../types.js\";\nimport { getLifetimeCost, getLifetimeTotal, getSessionContextPercent, type LifetimeUsage, type SessionLike } from \"../usage.js\";\nimport { fallbackFlag } from \"./fallback-flag.js\";\n\n// ---- Constants ----\n\n/** Maximum number of rendered lines before overflow collapse kicks in. */\nconst MAX_WIDGET_LINES = 12;\n\n/** Braille spinner frames for animated running indicator. */\nexport const SPINNER = [\"\u280B\", \"\u2819\", \"\u2839\", \"\u2838\", \"\u283C\", \"\u2834\", \"\u2826\", \"\u2827\", \"\u2807\", \"\u280F\"];\n\n/** Statuses that indicate an error/non-success outcome (used for linger behavior and icon rendering). */\nexport const ERROR_STATUSES = new Set([\"error\", \"aborted\", \"steered\", \"stopped\"]);\n\n/** Tool name \u2192 human-readable action for activity descriptions. */\nconst TOOL_DISPLAY: Record<string, string> = {\n read: \"reading\",\n bash: \"running command\",\n edit: \"editing\",\n write: \"writing\",\n grep: \"searching\",\n find: \"finding files\",\n ls: \"listing\",\n};\n\n// ---- Types ----\n\nexport type Theme = {\n fg(color: string, text: string): string;\n bold(text: string): string;\n};\n\nexport type UICtx = {\n setStatus(key: string, text: string | undefined): void;\n setWidget(\n key: string,\n content: undefined | ((tui: any, theme: Theme) => { render(): string[]; invalidate(): void; dispose?(): void }),\n options?: { placement?: \"aboveEditor\" | \"belowEditor\" },\n ): void;\n};\n\n/** Per-agent live activity state. */\nexport interface AgentActivity {\n activeTools: Map<string, string>;\n toolUses: number;\n responseText: string;\n session?: SessionLike;\n /** Current turn count. */\n turnCount: number;\n /** Effective max turns for this agent (undefined = unlimited). */\n maxTurns?: number;\n /** The model call in flight, if any; see `describeModelCall`. */\n modelCall?: ModelCallState;\n}\n\n/** Metadata attached to Agent tool results for custom rendering. */\nexport interface AgentDetails {\n displayName: string;\n description: string;\n subagentType: string;\n toolUses: number;\n tokens: string;\n durationMs: number;\n status: \"queued\" | \"running\" | \"completed\" | \"steered\" | \"aborted\" | \"stopped\" | \"error\" | \"background\";\n /** Human-readable description of what the agent is currently doing. */\n activity?: string;\n /** Current spinner frame index (for animated running indicator). */\n spinnerFrame?: number;\n /** Show the ctrl+b hint on this running foreground call's row \u2014 one row per batch. */\n backgroundHint?: boolean;\n /** Short label for the model the run used, e.g. \"haiku 4.5\". */\n modelName?: string;\n /** Set when a configured model did not resolve and the run fell back to the parent model. */\n modelNote?: string;\n /** The structured form of {@link modelNote}, for the one-line label. */\n modelFallback?: ModelFallback;\n modelTier?: TierDisclosure;\n /** Notable config tags (e.g. [\"thinking: high\", \"isolated\"]). */\n tags?: string[];\n /** Current turn count. */\n turnCount?: number;\n /** Effective max turns (undefined = unlimited). */\n maxTurns?: number;\n /** Estimated cost in USD; 0 when the model has no pricing data. */\n cost?: number;\n agentId?: string;\n error?: string;\n /** The `.output` transcript, when one was written. */\n outputFile?: string;\n}\n\n// ---- Formatting helpers ----\n\n/** Apply foreground styling while restoring it after nested foreground/full ANSI resets. */\nexport function fgPreservingNestedStyles(theme: Theme, color: string, text: string): string {\n const styledEmpty = theme.fg(color, \"\");\n const styleStart = styledEmpty.replace(/\\u001b\\[(?:0|39)m/g, \"\");\n return theme.fg(color, text.replace(/\\u001b\\[(?:0|39)m/g, reset => `${reset}${styleStart}`));\n}\n\n/**\n * Format a token count as a bare magnitude: \"950\", \"18.4k\", \"1.2M\". The unit is\n * picked against the ROUNDED thousands, so 999,999 reads \"1.0M\", never \"1000.0k\".\n * Every token formatter wraps this one so the boundary is fixed in one place.\n */\nexport function formatCompactTokens(count: number): string {\n const thousands = Number((count / 1_000).toFixed(1));\n if (thousands >= 1_000) return `${(count / 1_000_000).toFixed(1)}M`;\n if (count >= 1_000) return `${thousands.toFixed(1)}k`;\n return `${count}`;\n}\n\n/** Format a token count compactly: \"33.8k token\", \"1.2M token\". */\nexport function formatTokens(count: number): string {\n return `${formatCompactTokens(count)} token`;\n}\n\n/**\n * Format a cost as `~$0.0042`, or \"\" when there is nothing to show.\n *\n * The tilde is load-bearing: this is pi's own estimate from the model's listed\n * rates, not a billed figure, and the surfaces that print it sit next to token\n * counts that ARE exact.\n *\n * Nothing is printed for zero, which is also what a model with no pricing data\n * reports: `$0.00` beside a local model's tokens would claim its cost was\n * measured and found to be nothing, rather than never measured at all. For the\n * same reason a real cost too small for four decimals reads `<$0.0001` \u2014 it was\n * measured, and rounding it to `~$0.0000` would say the opposite.\n */\nexport function formatCost(cost: number): string {\n if (!(cost > 0)) return \"\"; // also catches NaN\n if (cost < 0.0001) return \"<$0.0001\";\n if (cost >= 1) return `~$${cost.toFixed(2)}`;\n // Under a dollar: cents at minimum, four decimals at most, nothing trailing.\n // Most single runs land between a tenth of a cent and a dime, where rounding\n // to cents would collapse a 4x difference in spend into the same figure.\n const rounded = Number(cost.toFixed(4));\n const decimals = (String(rounded).split(\".\")[1] ?? \"\").length;\n return `~$${rounded.toFixed(Math.max(2, decimals))}`;\n}\n\n/**\n * Token count with optional context-fill % and compaction-count annotations.\n * Thresholds for percent: <70% dim, 70\u201385% warning, \u226585% error.\n * Compaction count rendered as `\u21CAN` in dim.\n *\n * \"12.3k token\" \u2014 no annotations\n * \"12.3k token (45%)\" \u2014 percent only\n * \"12.3k token (\u21CA2)\" \u2014 compactions only (e.g. right after compact)\n * \"12.3k token (45% \u00B7 \u21CA2)\" \u2014 both\n */\nexport function formatSessionTokens(\n tokens: number,\n percent: number | null,\n theme: Theme,\n compactions = 0,\n): string {\n const tokenStr = formatTokens(tokens);\n const annot: string[] = [];\n if (percent !== null) {\n const color = percent >= 85 ? \"error\" : percent >= 70 ? \"warning\" : \"dim\";\n annot.push(theme.fg(color, `${Math.round(percent)}%`));\n }\n if (compactions > 0) {\n annot.push(theme.fg(\"dim\", `\u21CA${compactions}`));\n }\n if (annot.length === 0) return tokenStr;\n return `${tokenStr} (${annot.join(\" \u00B7 \")})`;\n}\n\n/** Format turn count with optional max limit: \"\u21BB5\u226430\" or \"\u21BB5\". */\nexport function formatTurns(turnCount: number, maxTurns?: number | null): string {\n return maxTurns != null ? `\u21BB${turnCount}\u2264${maxTurns}` : `\u21BB${turnCount}`;\n}\n\n/** Format milliseconds as human-readable duration. */\nexport function formatMs(ms: number): string {\n return `${(ms / 1000).toFixed(1)}s`;\n}\n\n/** Format duration from start/completed timestamps. */\nexport function formatDuration(startedAt: number, completedAt?: number, now = Date.now()): string {\n if (completedAt) return formatMs(completedAt - startedAt);\n return `${formatMs(now - startedAt)} (running)`;\n}\n\n/** Get display name for any agent type (built-in or custom). */\nexport function getDisplayName(type: SubagentType): string {\n return getConfig(type).displayName;\n}\n\n/** Short label for prompt mode: \"twin\" for append, nothing for replace (the default). */\nexport function getPromptModeLabel(type: SubagentType): string | undefined {\n const config = getConfig(type);\n return config.promptMode === \"append\" ? \"twin\" : undefined;\n}\n\n/**\n * Mode label is not included \u2014 callers add it where they want it.\n *\n * Both model forms come back so each surface can pick by width; the\n * \"(asked X)\" annotation is applied here rather than by callers, so a value the\n * spawn did not honor cannot be rendered as though it had been (#182).\n */\nexport function buildInvocationTags(\n invocation: AgentInvocation | undefined,\n): { modelName?: string; modelId?: string; tags: string[] } {\n const tags: string[] = [];\n if (!invocation) return { tags };\n const asked = (value: string | undefined, requested: string | undefined): string | undefined =>\n value && requested && requested !== value ? `${value} (asked ${requested})` : value;\n const thinking = asked(invocation.thinking, invocation.requestedThinking);\n if (thinking) tags.push(`thinking: ${thinking}`);\n if (invocation.isolated) tags.push(\"isolated\");\n if (invocation.isolation === \"worktree\") tags.push(\"worktree\");\n if (invocation.planMode) tags.push(\"plan\");\n if (invocation.inheritContext) tags.push(\"inherit context\");\n if (invocation.runInBackground) tags.push(\"background\");\n if (invocation.maxTurns != null) tags.push(`max turns: ${invocation.maxTurns}`);\n return { modelName: invocation.modelName, modelId: invocation.modelId, tags };\n}\n\n/**\n * The thinking tag from {@link buildInvocationTags} as `think:high`, or \"\" when\n * there is none. Both agent lists use it so the configured level cannot read as\n * a duplicate of the live `thinking \u00B7 4s` activity on the same row (#144).\n */\nexport function compactThinkingTag(tags: readonly string[]): string {\n return (tags.find(tag => tag.startsWith(\"thinking: \")) ?? \"\").replace(/^thinking: /, \"think:\");\n}\n\n/** Truncate text to its first non-blank line, max `len` chars. */\nfunction truncateLine(text: string, len = 60): string {\n // Trimming the whole text first drops any leading blank lines, so its first\n // line is the first non-blank one (or \"\" for blank text).\n const line = text.trim().split(\"\\n\")[0].trimEnd();\n if (line.length <= len) return line;\n return line.slice(0, len) + \"\u2026\";\n}\n\n/**\n * Build a human-readable activity string: running tools first, then the model\n * call in flight (`thinking \u00B7 2m41s`, `writing \u00B7 3.2k tok`, `stalled? \u00B7 2m41s`),\n * then the latest response text.\n */\nexport function describeActivity(\n activeTools: Map<string, string>,\n responseText?: string,\n modelCall?: ModelCallState,\n now: number = Date.now(),\n): string {\n if (activeTools.size > 0) {\n const groups = new Map<string, number>();\n for (const toolName of activeTools.values()) {\n const action = TOOL_DISPLAY[toolName] ?? toolName;\n groups.set(action, (groups.get(action) ?? 0) + 1);\n }\n\n const parts: string[] = [];\n for (const [action, count] of groups) {\n if (count > 1) {\n parts.push(`${action} ${count} ${action === \"searching\" ? \"patterns\" : \"files\"}`);\n } else {\n parts.push(action);\n }\n }\n return parts.join(\", \") + \"\u2026\";\n }\n\n const call = describeModelCall(modelCall, now);\n if (call) return call;\n\n // No tools active \u2014 show truncated response text if available\n if (responseText && responseText.trim().length > 0) {\n return truncateLine(responseText);\n }\n\n return \"thinking\u2026\";\n}\n\n// ---- Widget manager ----\n\nexport class AgentWidget {\n private uiCtx: UICtx | undefined;\n private widgetFrame = 0;\n private widgetInterval: TimerHandle | undefined;\n /** Tracks how many turns each finished agent has survived. Key: agent ID, Value: turns since finished. */\n private finishedTurnAge = new Map<string, number>();\n /** How many extra turns errors/aborted agents linger (completed agents clear after 1 turn). */\n private static readonly ERROR_LINGER_TURNS = 2;\n\n /** Whether the widget callback is currently registered with the TUI. */\n private widgetRegistered = false;\n /** Cached TUI reference from widget factory callback, used for requestRender(). */\n private tui: any | undefined;\n /** The registered widget component, so a late `dispose()` of a replaced one is ignored. */\n private component: object | undefined;\n /** Last status bar text, used to avoid redundant setStatus calls. */\n private lastStatusText: string | undefined;\n\n constructor(\n private manager: AgentManager,\n private agentActivity: Map<string, AgentActivity>,\n /**\n * Read live at render time. Selects which agents the widget shows \u2014 see\n * `WidgetMode`. Defaults to `\"all\"` when a caller supplies no policy; the\n * extension supplies one defaulting to `\"background\"`.\n */\n private mode: () => WidgetMode = () => \"all\",\n /**\n * Read live at render time, like `mode`. Whether running agents show an\n * estimated cost beside their token count. Defaults to off \u2014 the extension\n * supplies the user's `showCost` setting.\n */\n private showCost: () => boolean = () => false,\n /**\n * Read live at render time, like `mode`. Whether running agents name the\n * model driving them and the thinking level it is running at. Defaults to\n * off \u2014 the extension supplies the user's `showModel` setting \u2014 because the\n * row is already dense and the same pair is on the tool result and in the\n * conversation viewer unconditionally.\n */\n private showModel: () => boolean = () => false,\n private readonly clock: Clock = realClock,\n ) {}\n\n /**\n * Agents eligible for the widget, per the current `WidgetMode`:\n * - `off`: none (the widget's existing empty-state path hides it entirely).\n * - `background`: drop only agents *known* to be foreground\n * (`isBackground === false`); keep everything else \u2014 background, queued,\n * scheduled, or RPC-spawned (`undefined`). Keying off the `isBackground`\n * record flag rather than the UI-only `invocation` snapshot (which only the\n * Agent-tool path sets), and excluding rather than allow-listing, means\n * only proven-foreground runs drop out \u2014 nothing else silently vanishes.\n * - `all`: every agent.\n */\n private widgetAgents() {\n const all = this.manager.listAgents().filter(isTopLevelAgent);\n switch (this.mode()) {\n case \"off\": return [];\n case \"background\": return all.filter(a => a.isBackground !== false);\n default: return all;\n }\n }\n\n /** Set the UI context (grabbed from first tool execution). */\n setUICtx(ctx: UICtx) {\n if (ctx !== this.uiCtx) {\n // UICtx changed \u2014 the widget registered on the old context is gone.\n // Force re-registration on next update().\n this.uiCtx = ctx;\n this.widgetRegistered = false;\n this.tui = undefined;\n this.lastStatusText = undefined;\n }\n }\n\n /**\n * Called on each new turn (tool_execution_start).\n * Ages finished agents and clears those that have lingered long enough.\n */\n onTurnStart() {\n // Age all finished agents\n for (const [id, age] of this.finishedTurnAge) {\n this.finishedTurnAge.set(id, age + 1);\n }\n // Trigger a widget refresh (will filter out expired agents)\n this.update();\n }\n\n /** Ensure the widget update timer is running. */\n ensureTimer() {\n if (!this.widgetInterval) {\n this.widgetInterval = this.clock.setInterval(() => this.update(), 80);\n }\n }\n\n /** Check if a finished agent should still be shown in the widget. */\n private shouldShowFinished(agentId: string, status: string): boolean {\n const age = this.finishedTurnAge.get(agentId) ?? 0;\n const maxAge = ERROR_STATUSES.has(status) ? AgentWidget.ERROR_LINGER_TURNS : 1;\n return age < maxAge;\n }\n\n /** Record an agent as finished (call when agent completes). */\n markFinished(agentId: string) {\n if (!this.finishedTurnAge.has(agentId)) {\n this.finishedTurnAge.set(agentId, 0);\n }\n }\n\n /**\n * Drop an agent's finished-age (call when a settled agent starts running\n * again, i.e. a background resume). markFinished only seeds an age it has not\n * seen before, so a resumed agent would otherwise keep the age from its\n * previous run \u2014 already past the linger limit, hiding the new run's\n * completion line entirely.\n */\n markRunning(agentId: string) {\n this.finishedTurnAge.delete(agentId);\n }\n\n /** Render a finished agent line. */\n private renderFinishedLine(a: { id: string; type: SubagentType; status: string; description: string; toolUses: number; startedAt: number; completedAt: number; error?: string; lifetimeUsage?: LifetimeUsage; modelFallback?: ModelFallback; modelTier?: TierDisclosure }, theme: Theme): string {\n const modeLabel = getPromptModeLabel(a.type);\n const duration = formatMs(a.completedAt - a.startedAt);\n\n let icon: string;\n let statusText: string;\n if (a.status === \"completed\") {\n icon = theme.fg(\"success\", \"\u2713\");\n statusText = \"\";\n } else if (a.status === \"steered\") {\n icon = theme.fg(\"warning\", \"\u2713\");\n statusText = theme.fg(\"warning\", \" (turn limit)\");\n } else if (a.status === \"stopped\") {\n icon = theme.fg(\"dim\", \"\u25A0\");\n statusText = theme.fg(\"dim\", \" stopped\");\n } else if (a.status === \"error\") {\n icon = theme.fg(\"error\", \"\u2717\");\n const errMsg = a.error ? `: ${a.error.slice(0, 60)}` : \"\";\n statusText = theme.fg(\"error\", ` error${errMsg}`);\n } else {\n // aborted\n icon = theme.fg(\"error\", \"\u2717\");\n statusText = theme.fg(\"warning\", \" aborted\");\n }\n\n const parts: string[] = [];\n const activity = this.agentActivity.get(a.id);\n if (activity) parts.push(formatTurns(activity.turnCount, activity.maxTurns));\n if (a.toolUses > 0) parts.push(`${a.toolUses} tool use${a.toolUses === 1 ? \"\" : \"s\"}`);\n // Not gated by `showModel`: a substituted model is never a cosmetic detail.\n // From the record, not the activity tracker: that entry is deleted the\n // moment an agent finishes, and \"what did it cost\" is a question asked\n // about finished agents.\n const costText = this.showCost() ? formatCost(getLifetimeCost(a.lifetimeUsage)) : \"\";\n if (costText) parts.push(costText);\n parts.push(duration);\n\n const modeTag = modeLabel ? ` ${theme.fg(\"dim\", `(${modeLabel})`)}` : \"\";\n const flag = fallbackFlag(theme, a) ? `${fallbackFlag(theme, a)} ` : \"\";\n return `${icon} ${flag}${renderAgentName(a.type, theme, { fallbackColor: \"dim\" })}${modeTag} ${theme.fg(\"dim\", a.description)} ${theme.fg(\"dim\", \"\u00B7\")} ${theme.fg(\"dim\", parts.join(\" \u00B7 \"))}${statusText}`;\n }\n\n /**\n * Render the widget content. Called from the registered widget's render() callback,\n * reading live state each time instead of capturing it in a closure.\n */\n private renderWidget(tui: any, theme: Theme): string[] {\n const allAgents = this.widgetAgents();\n const running = allAgents.filter(a => a.status === \"running\");\n const queued = allAgents.filter(a => a.status === \"queued\");\n const finished = allAgents.filter((a): a is typeof a & { completedAt: number } =>\n a.status !== \"running\" && a.status !== \"queued\" && !!a.completedAt\n && this.shouldShowFinished(a.id, a.status),\n );\n\n const hasActive = running.length > 0 || queued.length > 0;\n const hasFinished = finished.length > 0;\n\n // Nothing to show \u2014 return empty (widget will be unregistered by update())\n if (!hasActive && !hasFinished) return [];\n\n const w = tui.terminal.columns;\n const truncate = (line: string) => truncateToWidth(line, w);\n const headingColor = hasActive ? \"accent\" : \"dim\";\n const headingIcon = hasActive ? \"\u25CF\" : \"\u25CB\";\n const frame = SPINNER[this.widgetFrame % SPINNER.length];\n\n // Build sections separately for overflow-aware assembly.\n // Each running agent = 2 lines (header + activity), finished = 1 line, queued = 1 line.\n\n const finishedLines: string[] = [];\n for (const a of finished) {\n finishedLines.push(truncate(theme.fg(\"dim\", \"\u251C\u2500\") + \" \" + this.renderFinishedLine(a, theme)));\n }\n\n const runningLines: string[][] = []; // each entry is [header, activity]\n for (const a of running) {\n const modeLabel = getPromptModeLabel(a.type);\n const modeTag = modeLabel ? ` ${theme.fg(\"dim\", `(${modeLabel})`)}` : \"\";\n const flag = fallbackFlag(theme, a) ? `${fallbackFlag(theme, a)} ` : \"\";\n const elapsed = formatMs(this.clock.now() - a.startedAt);\n\n const bg = this.agentActivity.get(a.id);\n const toolUses = bg?.toolUses ?? a.toolUses;\n // Spend comes from the record, never from the activity tracker: the record\n // is the one that survives the agent finishing, and the one nested-tools\n // folds a hidden child's spend into. Reading the tracker while an agent\n // runs and the record once it stops made the figure jump at completion.\n const tokens = getLifetimeTotal(a.lifetimeUsage);\n const contextPercent = getSessionContextPercent(bg?.session);\n const tokenText = tokens > 0 ? formatSessionTokens(tokens, contextPercent, theme, a.compactionCount) : \"\";\n const costText = this.showCost() ? formatCost(getLifetimeCost(a.lifetimeUsage)) : \"\";\n\n const parts: string[] = [];\n if (this.showModel()) {\n // Leading, and paired: a thinking level means nothing without the model\n // it applies to. The tag is taken from buildInvocationTags rather than\n // rebuilt so the \"(asked X)\" annotation survives.\n const { modelName, tags } = buildInvocationTags(a.invocation);\n if (modelName) parts.push(modelName);\n const thinkingTag = compactThinkingTag(tags);\n if (thinkingTag) parts.push(thinkingTag);\n }\n if (bg) parts.push(formatTurns(bg.turnCount, bg.maxTurns));\n if (toolUses > 0) parts.push(`${toolUses} tool use${toolUses === 1 ? \"\" : \"s\"}`);\n if (tokenText) parts.push(tokenText);\n if (costText) parts.push(costText);\n parts.push(elapsed);\n const statsText = parts.join(\" \u00B7 \");\n\n const activity = bg ? describeActivity(bg.activeTools, bg.responseText, bg.modelCall, this.clock.now()) : \"thinking\u2026\";\n\n runningLines.push([\n truncate(theme.fg(\"dim\", \"\u251C\u2500\") + ` ${theme.fg(\"accent\", frame)} ${flag}${renderAgentName(a.type, theme, { bold: true })}${modeTag} ${theme.fg(\"muted\", a.description)} ${theme.fg(\"dim\", \"\u00B7\")} ${fgPreservingNestedStyles(theme, \"dim\", statsText)}`),\n truncate(theme.fg(\"dim\", \"\u2502 \") + theme.fg(\"dim\", ` \u23BF ${activity}`)),\n ]);\n }\n\n const queuedLine = queued.length > 0\n ? truncate(theme.fg(\"dim\", \"\u251C\u2500\") + ` ${theme.fg(\"muted\", \"\u25E6\")} ${theme.fg(\"dim\", `${queued.length} queued`)}`)\n : undefined;\n\n // Assemble with overflow cap (heading + overflow indicator = 2 reserved lines).\n const maxBody = MAX_WIDGET_LINES - 1; // heading takes 1 line\n const totalBody = finishedLines.length + runningLines.length * 2 + (queuedLine ? 1 : 0);\n\n const lines: string[] = [truncate(theme.fg(headingColor, headingIcon) + \" \" + theme.fg(headingColor, \"Agents\"))];\n\n if (totalBody <= maxBody) {\n // Everything fits \u2014 add all lines and fix up connectors for the last item.\n lines.push(...finishedLines);\n for (const pair of runningLines) lines.push(...pair);\n if (queuedLine) lines.push(queuedLine);\n\n // Fix last connector: swap \u251C\u2500 \u2192 \u2514\u2500 and \u2502 \u2192 space for activity lines.\n // Something is active or finished (checked above), so the body is never\n // empty and `last` is past the heading.\n const last = lines.length - 1;\n lines[last] = lines[last].replace(\"\u251C\u2500\", \"\u2514\u2500\");\n // If the last item is a running agent, its header and activity are the\n // last two lines: fix the header's connector and the activity's indent.\n if (runningLines.length > 0 && !queuedLine) {\n lines[last - 1] = lines[last - 1].replace(\"\u251C\u2500\", \"\u2514\u2500\");\n lines[last] = lines[last].replace(\"\u2502 \", \" \");\n }\n } else {\n // Overflow \u2014 prioritize: running > queued > finished.\n // Reserve 1 line for overflow indicator.\n let budget = maxBody - 1;\n let hiddenRunning = 0;\n let hiddenFinished = 0;\n\n // Reserve the queued line's row up front. It is a single summary of N\n // waiting agents, so it cannot be folded into the \"+N more\" count (which\n // is denominated in agents) without either under-reporting it as 1 or\n // inflating the total with agents that were never getting their own rows.\n // Reserving costs at most one running agent \u2014 which IS counted below \u2014\n // and makes the drop unreachable. It matters most exactly when it used to\n // vanish: the pool is saturated and the queue is what the user needs to see.\n const queuedReserve = queuedLine ? 1 : 0;\n budget -= queuedReserve;\n\n // 1. Running agents (2 lines each)\n for (const pair of runningLines) {\n if (budget >= 2) {\n lines.push(...pair);\n budget -= 2;\n } else {\n hiddenRunning++;\n }\n }\n\n // 2. Queued line (always fits \u2014 its row was reserved above)\n if (queuedLine) {\n budget += queuedReserve;\n lines.push(queuedLine);\n budget--;\n }\n\n // 3. Finished agents\n for (const fl of finishedLines) {\n if (budget >= 1) {\n lines.push(fl);\n budget--;\n } else {\n hiddenFinished++;\n }\n }\n\n // Overflow summary\n const overflowParts: string[] = [];\n if (hiddenRunning > 0) overflowParts.push(`${hiddenRunning} running`);\n if (hiddenFinished > 0) overflowParts.push(`${hiddenFinished} finished`);\n const overflowText = overflowParts.join(\", \");\n lines.push(truncate(theme.fg(\"dim\", \"\u2514\u2500\") + ` ${theme.fg(\"dim\", `+${hiddenRunning + hiddenFinished} more (${overflowText})`)}`)\n );\n }\n\n return lines;\n }\n\n /** Force an immediate widget update. */\n update() {\n if (!this.uiCtx) return;\n const allAgents = this.widgetAgents();\n\n // Lightweight existence checks \u2014 full categorization happens in renderWidget()\n let runningCount = 0;\n let queuedCount = 0;\n let hasFinished = false;\n for (const a of allAgents) {\n if (a.status === \"running\") { runningCount++; }\n else if (a.status === \"queued\") { queuedCount++; }\n else if (a.completedAt && this.shouldShowFinished(a.id, a.status)) { hasFinished = true; }\n }\n const hasActive = runningCount > 0 || queuedCount > 0;\n\n // Nothing to show \u2014 clear widget\n if (!hasActive && !hasFinished) {\n if (this.widgetRegistered) {\n this.uiCtx.setWidget(\"agents\", undefined);\n this.widgetRegistered = false;\n this.tui = undefined;\n }\n if (this.lastStatusText !== undefined) {\n this.uiCtx.setStatus(\"subagents\", undefined);\n this.lastStatusText = undefined;\n }\n if (this.widgetInterval) { this.widgetInterval.cancel(); this.widgetInterval = undefined; }\n // Clean up stale entries\n for (const [id] of this.finishedTurnAge) {\n if (!allAgents.some(a => a.id === id)) this.finishedTurnAge.delete(id);\n }\n return;\n }\n\n // Status bar \u2014 only call setStatus when the text actually changes\n let newStatusText: string | undefined;\n if (hasActive) {\n const statusParts: string[] = [];\n if (runningCount > 0) statusParts.push(`${runningCount} running`);\n if (queuedCount > 0) statusParts.push(`${queuedCount} queued`);\n const total = runningCount + queuedCount;\n newStatusText = `${statusParts.join(\", \")} agent${total === 1 ? \"\" : \"s\"}`;\n }\n if (newStatusText !== this.lastStatusText) {\n this.uiCtx.setStatus(\"subagents\", newStatusText);\n this.lastStatusText = newStatusText;\n }\n\n this.widgetFrame++;\n\n // Register widget callback once; subsequent updates use requestRender()\n // which re-invokes render() without replacing the component (avoids layout thrashing).\n if (!this.widgetRegistered) {\n this.uiCtx.setWidget(\"agents\", (tui, theme) => {\n this.tui = tui;\n const component = {\n render: () => this.renderWidget(tui, theme),\n invalidate: () => {\n // Theme changed \u2014 force re-registration so factory captures fresh theme.\n this.widgetRegistered = false;\n this.tui = undefined;\n },\n // Core disposes every extension widget on /reload and when plan mode\n // is entered or left. Without this the flag stayed true, update() only\n // ever asked a dead component to re-render, and the widget vanished.\n // Only the live component may reset it: a replaced one is disposed\n // after its successor registered.\n dispose: () => {\n if (this.component !== component) return;\n this.component = undefined;\n this.widgetRegistered = false;\n this.tui = undefined;\n },\n };\n this.component = component;\n return component;\n }, { placement: \"aboveEditor\" });\n this.widgetRegistered = true;\n } else {\n // Widget already registered \u2014 just request a re-render of existing components.\n this.tui?.requestRender();\n }\n }\n\n dispose() {\n if (this.widgetInterval) {\n this.widgetInterval.cancel();\n this.widgetInterval = undefined;\n }\n if (this.uiCtx) {\n this.uiCtx.setWidget(\"agents\", undefined);\n this.uiCtx.setStatus(\"subagents\", undefined);\n }\n this.widgetRegistered = false;\n this.component = undefined;\n this.tui = undefined;\n this.lastStatusText = undefined;\n }\n}\n", "/**\n * agent-manager.ts \u2014 Tracks agents, background execution, resume support.\n *\n * There are two independent concurrency pools, never one:\n *\n * - Background (`maxConcurrent`, default 10) bounds detached agents.\n * - Foreground (`maxConcurrentForeground`, default 0 = unlimited) bounds\n * agents a caller is blocking on inline \u2014 `spawnAndWait`.\n *\n * Independent by design: a foreground agent blocks the parent anyway, so\n * charging it to the background pool would let a saturated pool starve the main\n * session of work it could have done itself. Excess agents in either pool are\n * queued and auto-started as slots free up. Nested children take no slot in\n * either \u2014 see `occupiesPoolSlot` / `occupiesForegroundSlot`.\n *\n * Both pools are per manager. Above them sits the process-wide budget\n * (`process-budget.ts`, `maxActiveSubagents`), which EVERY run takes a lease\n * from \u2014 nested, workflow, scheduled, RPC, and resumes included \u2014 across every\n * manager in the process. A start needs room in its pool (if it has one) and a\n * lease; whichever is missing, it waits in `queue`.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { accessSync, constants, opendirSync, statSync } from \"node:fs\";\nimport { isAbsolute } from \"node:path\";\nimport type { Model } from \"@earendil-works/pi-ai\";\nimport type { AgentSession, ExtensionAPI, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { type AssistantMessageInfo, resumeAgent, runAgent, type ToolActivity } from \"./agent-runner.js\";\nimport { getAgentConfig } from \"./agent-types.js\";\nimport { type Clock, realClock, type TimerHandle } from \"./clock.js\";\nimport { errorMessage } from \"./error-message.js\";\nimport { assignHandle, handleBase } from \"./mention.js\";\nimport type { ModelCallEvent } from \"./model-call.js\";\nimport { describeModel, describePhysicalModel, describeVirtualModel, isVirtualModel, type ModelFallback } from \"./model-resolver.js\";\nimport { admitModelSelection, describeSelection, type ModelSelection, modelSelectionNote, selectModel } from \"./model-selection.js\";\nimport { type TierDisclosure, tierDisclosure } from \"./model-tiers.js\";\nimport { appendModelFallbackEntry, appendModelTierEntry } from \"./output-file.js\";\nimport { type PlanToolPolicy, queryPlanPolicy } from \"./plan-mode-children.js\";\nimport {\n assertWithinBudgetDepth,\n BUDGET_QUEUE_FULL_ERROR,\n type BudgetLease,\n budgetHasPendingRoom,\n enqueueBudget,\n pumpBudget,\n releaseBudget,\n tryAcquireBudget,\n} from \"./process-budget.js\";\nimport { describeBlock } from \"./quota-admission.js\";\nimport { isStaleCtxError } from \"./stale-ctx.js\";\nimport type { AgentInvocation, AgentRecord, AgentTombstone, IsolationMode, MentionResolution, Pool, SubagentType, ThinkingLevel } from \"./types.js\";\nimport { addUsage, type LifetimeUsage } from \"./usage.js\";\nimport type { CompiledSchema } from \"./workflow/json-schema.js\";\nimport { cleanupWorktree, createWorktree, isWorktreeIsolationEnabled, pruneWorktrees, type WorktreeCleanupResult, type WorktreeInfo } from \"./worktree.js\";\n\n/**\n * Relabel a record's model from the response that just finished. A virtual\n * selection (`router/default`) is only a name until a request is routed; the\n * assistant message is the one place that records the physical model, so the\n * label follows it (and follows a router fallback to the next model).\n */\nfunction relabelFromResponse(record: AgentRecord, message: AssistantMessageInfo | undefined): void {\n const registry = (record.session as { modelRegistry?: Parameters<typeof describePhysicalModel>[1] } | undefined)\n ?.modelRegistry;\n const physical = describePhysicalModel(message, registry);\n if (!physical) return;\n record.invocation ??= {};\n Object.assign(record.invocation, physical);\n if ((record.modelTier?.kind === \"routed\" || record.modelTier?.kind === \"static\") && record.modelTier.answered !== physical.modelId) {\n record.modelTier = { ...record.modelTier, answered: physical.modelId };\n if (record.outputFile) appendModelTierEntry(record.outputFile, record.id, record.modelTier);\n }\n}\n\n/** Keep a cleanup failure visible on every result, including errors and stopped workflows. */\nfunction recordWorktreeCleanup(record: AgentRecord, result: WorktreeCleanupResult): void {\n record.worktreeResult = result;\n if (!result.error) return;\n const note = `Worktree cleanup failed: ${result.error}. Worktree retained at \\`${result.path}\\`${result.branch ? `; branch \\`${result.branch}\\` was created` : \"\"}. Inspect and recover it before removing it.`;\n record.error = record.error ? `${record.error}\\n${note}` : note;\n record.result = record.result ? `${record.result}\\n\\n${note}` : note;\n if (record.status !== \"stopped\") record.status = \"error\";\n}\n\nexport type OnAgentComplete = (record: AgentRecord) => void;\nexport type OnAgentStart = (record: AgentRecord) => void;\n/**\n * Fired when `abort`, `detach` or `abortAll` stops a record that was still queued. Such a record\n * never reaches `onComplete` (it never ran, so there is no result to announce), but a listener\n * that heard it spawn needs to learn it ended.\n */\nexport type OnAgentQueuedStop = (record: AgentRecord) => void;\n/** Fired when the retention sweep evicts a top-level agent whose result was never read (#330). */\nexport type OnAgentReaped = (note: EvictedNote) => void;\n/**\n * Fired by `steer()` once a message is delivered or queued. Every steer path\n * goes through it except the steer tools (`steer_subagent` in index.ts, and its\n * nested twin in nested-tools.ts), which await the session directly.\n */\nexport type OnAgentSteered = (record: AgentRecord, message: string) => void;\nexport type OnAgentCompact = (record: AgentRecord, info: CompactionInfo) => void;\n/**\n * Fired once per assistant `message_end`, for EVERY agent this manager owns \u2014\n * top-level and nested alike, spawns and resumes. The one place where each\n * message is seen exactly once: `AgentRecord.lifetimeUsage` is deliberately\n * double-booked into ancestors (see `nested-tools.ts`) so a hidden child's spend\n * shows up on the record a human can see, which makes those records useless as\n * a basis for anything that must not count a message twice \u2014 parent-session\n * accounting above all.\n */\nexport type OnAgentUsage = (record: AgentRecord, usage: LifetimeUsage) => void;\nexport type CompactionInfo = { reason: \"manual\" | \"threshold\" | \"overflow\"; tokensBefore: number };\n\n/**\n * Default max concurrent background agents.\n *\n * Raised from 4 when top-level spawns started defaulting to background\n * (`backgroundByDefault`): foreground agents bypass this pool entirely, so\n * while foreground was the default a fan-out of six ran six. With background\n * as the default every top-level agent takes a slot, and a limit of 4 would\n * have silently queued the tail of exactly the parallel fan-outs the `Agent`\n * tool description tells the model to send.\n */\nconst DEFAULT_MAX_CONCURRENT = 10;\n\n/**\n * Default max concurrent foreground (blocking) agents \u2014 `0` = unlimited, the\n * extension's existing convention for \"no ceiling\" (`defaultMaxTurns`).\n *\n * Off by default because nothing here ever bounded foreground work, and pi\n * dispatches a message's tool calls through `Promise.all`, so an unqualified\n * fan-out of blocking `Agent` calls has always run all at once. Users who want\n * it bounded \u2014 chiefly local models, where parallel agents thrash the prompt\n * cache (#253) \u2014 opt in; everyone else keeps today's behaviour exactly.\n */\nconst DEFAULT_MAX_CONCURRENT_FOREGROUND = 0;\n\n/**\n * How long a finished record stays in memory once its result was consumed\n * (fetched, or delivered inline to a blocking caller). Nothing is waiting on it\n * any more; the window only covers a follow-up `get_subagent_result` or steer.\n */\nconst CONSUMED_RECORD_TTL_MS = 10 * 60_000;\n\n/**\n * How long a finished record nobody has read stays in memory, measured from\n * completion. Far longer than the consumed window: an orchestrator that was busy\n * when the notice arrived still gets to fetch the full result an hour later.\n */\nconst UNCONSUMED_RECORD_TTL_MS = 60 * 60_000;\n\n/**\n * Read a retention override in minutes (fractions and 0 allowed) from `name`,\n * else `fallbackMs`. An env var rather than a setting: the windows are not a\n * user knob, but eviction is otherwise unobservable in an end-to-end test,\n * which cannot wait an hour. Invalid values warn and keep the default.\n */\nfunction retentionMs(name: string, fallbackMs: number): number {\n const raw = process.env[name]?.trim();\n if (!raw) return fallbackMs;\n const minutes = Number(raw);\n if (!Number.isFinite(minutes) || minutes < 0) {\n console.warn(`[pi-subagents] ignoring ${name}=\"${raw}\": expected minutes >= 0`);\n return fallbackMs;\n }\n return minutes * 60_000;\n}\n\n/** Sweep cadence: every minute, or as often as the shortest window needs, never under a second. */\nconst MAX_SWEEP_INTERVAL_MS = 60_000;\nconst MIN_SWEEP_INTERVAL_MS = 1_000;\n\n/** How many evicted ids keep an answer to \"what happened to that agent\". */\nconst MAX_EVICTED_NOTES = 500;\n\n/** Mark a record's result as read, which shortens its retention and suppresses its notice. */\nexport function markConsumed(record: Pick<AgentRecord, \"resultConsumed\" | \"consumedAt\">, now = Date.now()): void {\n record.resultConsumed = true;\n record.consumedAt = now;\n}\n\n/**\n * What survives a record's eviction, so a later `get_subagent_result` or steer\n * can say what became of the agent instead of \"not found\".\n */\nexport interface EvictedNote {\n id: string;\n type: SubagentType;\n description: string;\n status: AgentRecord[\"status\"];\n /** Whole minutes between completion and eviction. */\n evictedAfterMin: number;\n /** The `.output` transcript when one was written, else the session file. */\n transcript?: string;\n /** The run's model fallback, so even an evicted agent's id still discloses it. */\n modelFallback?: ModelFallback;\n modelTier?: TierDisclosure;\n /** Set when a saved session exists but its name now belongs to another agent, so it was not kept reopenable. */\n nameTaken?: string;\n}\n\n/** The text a tool returns for an id whose record was evicted. */\nexport function describeEvicted(note: EvictedNote): string {\n const where = note.transcript ? `; transcript: ${note.transcript}` : \"\";\n const disclosure = modelSelectionNote(note);\n const fallback = disclosure ? `\\n${disclosure}` : \"\";\n return `Agent \"${note.id}\" (${note.description}) ${note.status}, evicted after ${note.evictedAfterMin} min${where}${fallback}`;\n}\n\n/**\n * How many evicted agents stay addressable by name. Only a bound on memory \u2014\n * a session that spawns hundreds of agents shouldn't retain every one \u2014 and\n * far above the handful anyone keeps in their head.\n */\nconst MAX_TOMBSTONES = 100;\n\n/**\n * Validate a caller-supplied SpawnOptions.cwd. `undefined`/`null` mean \"unset\"\n * (parent cwd). Anything else must be an absolute path to an existing\n * directory \u2014 curated errors instead of TypeErrors from path/fs internals\n * (RPC callers send arbitrary JSON: null, numbers, file paths).\n */\nfunction assertValidSpawnCwd(cwd: unknown): asserts cwd is string | undefined | null {\n if (cwd == null) return;\n if (typeof cwd !== \"string\" || !isAbsolute(cwd)) {\n throw new Error(`SpawnOptions.cwd must be an absolute path: \"${String(cwd)}\"`);\n }\n let isDirectory = false;\n try {\n isDirectory = statSync(cwd).isDirectory();\n } catch {\n throw new Error(`SpawnOptions.cwd does not exist: \"${cwd}\"`);\n }\n if (!isDirectory) {\n throw new Error(`SpawnOptions.cwd is not a directory: \"${cwd}\"`);\n }\n}\n\n/**\n * Fail fast when a working directory exists but cannot be opened (#436).\n * `stat` succeeds on such a directory (POSIX `chmod 000`, or a macOS privacy\n * denial of an external volume), so without this the child starts and every\n * read fails with a bare EPERM/EACCES. Only those two codes are rejected: a\n * missing directory stays the caller's concern (`assertValidSpawnCwd`).\n */\nfunction assertReadableCwd(cwd: string, label: string): void {\n try {\n opendirSync(cwd).closeSync();\n // opendir needs only the read bit; children also need search (x) to reach anything inside.\n accessSync(cwd, constants.R_OK | constants.X_OK);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"EACCES\" && code !== \"EPERM\") return;\n throw new Error(\n `${label} is not readable (${code}): \"${cwd}\". Check its permissions; on macOS also check Privacy & Security -> Files & Folders / Full Disk Access for the terminal app (external volumes need it).`,\n );\n }\n}\n\n/** Validate the cwd a child will run in: caller-supplied `SpawnOptions.cwd`, else the session cwd. */\nfunction assertSpawnCwd(cwd: unknown, sessionCwd: string): void {\n assertValidSpawnCwd(cwd);\n if (cwd == null) assertReadableCwd(sessionCwd, \"The session cwd\");\n else assertReadableCwd(cwd, \"SpawnOptions.cwd\");\n}\n\n/** The session's own pending agents, split by whether their completion wakes the parent. */\nexport interface OwnedPending {\n /** Background agents (Agent tool, `@handle`, scheduler, background resume) whose completion notice starts a parent turn. */\n notifying: number;\n /** Foreground agents and RPC spawns without `isBackground`, whose settle notifies nobody. */\n silent: number;\n}\n\n/** A record whose run is over. Every settle and stop stamps `completedAt`; only a (re)start clears it. */\ntype SettledRecord = AgentRecord & { completedAt: number };\n\n/** Whether `record` is past its run (neither running nor queued), and so carries `completedAt`. */\nfunction isSettled(record: AgentRecord): record is SettledRecord {\n return record.status !== \"running\" && record.status !== \"queued\";\n}\n\n/**\n * Whether a record occupies one of the `maxConcurrent` background slots.\n * Nested children don't: their parent already holds a slot, so counting (and\n * therefore queueing) them would deadlock a parent that waits on its own child.\n *\n * Note this bounds nothing horizontally \u2014 the depth cap limits how DEEP nesting\n * goes, not how WIDE. A parent's only limit on concurrent children is that each\n * spawn costs it a turn, which is unbounded when max turns is unlimited.\n */\nfunction occupiesPoolSlot(\n record: Pick<AgentRecord, \"isBackground\" | \"parentAgentId\" | \"workflowId\">,\n): boolean {\n return !!record.isBackground && isTopLevelAgent(record);\n}\n\n/**\n * Whether a record is one of the session's own agents, rather than something\n * another agent or a workflow owns.\n *\n * The single definition behind every user-facing surface \u2014 the fleet list, the\n * widget, the `/agents` menus, `@handle` resolution, and the completion events\n * and session entries. An owned child reports through its owner, so surfacing\n * it separately would double-count the same work in the places a person reads.\n */\nexport function isTopLevelAgent(\n record: Pick<AgentRecord, \"parentAgentId\" | \"workflowId\">,\n): boolean {\n return record.parentAgentId === undefined && record.workflowId === undefined;\n}\n\n/**\n * Whether a record occupies one of the `maxConcurrentForeground` slots.\n *\n * Keyed on `blocking` \u2014 a caller awaiting this record inline \u2014 rather than on\n * `isBackground === false`, because `spawn()` is also the funnel for DETACHED\n * starts (cross-extension RPC, `@handle` mentions, the registry) that may pass\n * `isBackground: false` and are documented to run immediately regardless. Those\n * block nobody, so bounding them buys nothing and would park a record with no\n * one waiting to release it.\n *\n * Nested children are excluded for the same reason as `occupiesPoolSlot`, and\n * more sharply: their parent is blocked *awaiting them*, so queueing a child\n * behind its own parent is a guaranteed deadlock rather than a possible one.\n * Enforced here rather than at the call site so no caller can reintroduce it.\n *\n * A workflow's children go out through `spawnAndWait` and so are `blocking`\n * too, and are excluded on the same `isTopLevelAgent` test as the background\n * pool: the run already caps how many of its agents run at once, and charging\n * them here as well would let one fan-out queue behind a limit meant for the\n * session's own work.\n *\n * Like the background pool this bounds width at the top level only \u2014 a parent's\n * own fan-out is limited by nothing but its turn budget.\n */\nfunction occupiesForegroundSlot(\n record: Pick<AgentRecord, \"blocking\" | \"parentAgentId\" | \"workflowId\">,\n): boolean {\n return !!record.blocking && isTopLevelAgent(record);\n}\n\n/** A start waiting in `AgentManager.queue`; see there. */\ninterface QueueEntry {\n id: string;\n /** The queued record; it stays in `agents` while queued, since only settled records are evicted. */\n record: AgentRecord;\n /** The pool it needs room in, or undefined when it waits on the budget alone. */\n pool?: Pool;\n start: () => Promise<void>;\n release: () => void;\n /** Withdraw the budget waiter. A no-op once granted. */\n cancel: () => void;\n /** Resolves once the entry has left the queue, started (and settled its startup) or not. */\n left: Promise<void>;\n}\n\ninterface SpawnArgs {\n pi: ExtensionAPI;\n ctx: ExtensionContext;\n type: SubagentType;\n prompt: string;\n options: SpawnOptions;\n}\n\ninterface SpawnOptions {\n /** Home inherited by nested callers; the manager's home is the default. */\n homeDir?: string;\n description: string;\n /**\n * Optional memorable name for this instance, becoming a second handle\n * (`@auth-audit`) alongside the type-derived one. Slugged, not validated \u2014\n * anything unusable degrades via `handleBase` rather than failing the spawn.\n */\n name?: string;\n /**\n * Reopen this pi session file instead of starting a fresh conversation, so a\n * mention of an evicted agent continues where it left off. The agent's\n * definition is still resolved from its type, so the continuation runs under\n * the type's CURRENT config.\n */\n resumeSessionFile?: string;\n /**\n * Take an evicted agent's names back verbatim instead of allocating fresh\n * ones, so a resumed conversation keeps the handle the user just typed \u2014\n * `handleBase(type)` cannot reproduce a numbered `explore-2`. Safe without an\n * `assignHandle` pass because tombstoned names are excluded from allocation\n * (`takenHandles`), so nothing live can be holding them.\n *\n * Internal capability, like `resumeSessionFile`: a forged handle would\n * duplicate a live agent's name and make `resolveMention` ambiguous, so\n * `spawnTopLevel` strips it from anything a caller sends.\n */\n reclaim?: { handle: string; alias?: string };\n model?: Model<any> | string;\n /** Internal preflight outcome, stored on the record without resolving again. */\n modelSelection?: ModelSelection;\n /** Historical outcome only, never used to label the continuation. */\n previousModelTier?: TierDisclosure;\n /** Historical fallback only, never used to label the continuation. */\n previousModelFallback?: ModelFallback;\n /** Internal, like `reclaim`: the evicted id a reopen continues. */\n previousId?: string;\n\n maxTurns?: number;\n isolated?: boolean;\n inheritContext?: boolean;\n thinkingLevel?: ThinkingLevel;\n isBackground?: boolean;\n /**\n * Skip whichever pool's queue check applies to this spawn \u2014 start immediately\n * even if the configured concurrency limit would otherwise queue it. The slot\n * is still COUNTED once the run starts, so a bypassing spawn transiently\n * exceeds the limit rather than being invisible to it.\n *\n * Used by the scheduler, so a fired job can't be deferred past its trigger\n * window, and by the `/agents` agent-file generator, which has no way to\n * cancel a wait (see its call site).\n */\n bypassQueue?: boolean;\n /**\n * A caller is awaiting this record inline (`spawnAndWait`) \u2014 what\n * `maxConcurrentForeground` bounds. Set only by `spawnAndWait`; stripped from\n * caller-supplied options by `spawnTopLevel`, since a forged `blocking` would\n * defer a detached start behind a queue its caller cannot see or release.\n */\n blocking?: boolean;\n /**\n * The workflow run this child belongs to, when a workflow spawned it.\n *\n * Ownership, not decoration. A workflow's children are the workflow's \u2014 they\n * report through its card, its notification and its dialog, so they are\n * filtered out of every top-level surface exactly as nested children are, and\n * they take no `maxConcurrent` slot: the run has its own concurrency cap, and\n * counting them twice would let one workflow starve the whole session.\n */\n workflowId?: string;\n /**\n * Make the child report through a `StructuredOutput` tool built from this\n * compiled schema. Set only by the workflow host, for `agent({ schema })`.\n */\n structuredOutput?: CompiledSchema;\n /** Isolation mode \u2014 \"worktree\" creates a temp git worktree for the agent. */\n isolation?: IsolationMode;\n /**\n * Working directory for the agent (absolute path). Default: parent session\n * cwd. The agent's tools operate here, but .pi config (extensions, skills,\n * settings, memory) still loads from the parent session's project \u2014 the\n * target directory's `.pi` extensions never execute. With isolation:\n * \"worktree\", the worktree is created FROM this directory and the result\n * branch lands in that repo.\n */\n cwd?: string;\n /**\n * Last chance to look at an isolated agent's worktree, awaited immediately\n * before it is committed to a branch and removed.\n *\n * Exists because that removal happens inside the settle path, before\n * `spawnAndWait` resolves: by the time a caller has the finished record, the\n * directory the child actually wrote in is gone. Anything that must inspect\n * or verify that tree \u2014 a workflow `gate` is the motivating case \u2014 has to run\n * here or it silently inspects the main tree instead.\n *\n * Fires only on the normal settle path, and only when a worktree was created.\n * Not on the error path and not on the stop-during-copy guard: those are\n * already failing, and delaying cleanup there would leak a copy for no gain.\n * A rejection is swallowed \u2014 the hook can never keep the worktree alive.\n */\n onBeforeWorktreeCleanup?: (worktreePath: string) => Promise<void>;\n /** Resolved invocation snapshot captured for UI display. */\n invocation?: AgentInvocation;\n /** Parent abort signal \u2014 when aborted, the subagent is also stopped. */\n signal?: AbortSignal;\n /** Prepare the record before it can be queued or started. A throw rejects the spawn. */\n onPrepare?: (id: string) => void;\n /**\n * Called synchronously once the record is in the map and its promise is set,\n * before `onSessionCreated` fires.\n *\n * Carried on the options rather than parked on the manager for the duration\n * of a spawn: with a foreground queue, `startAgent` can run at drain time,\n * long after any such field would have been restored, and the callback would\n * silently never fire (or fire into an unrelated caller's closure).\n */\n onSpawned?: (id: string) => void;\n /**\n * Called synchronously when the spawn is queued instead of started, with how\n * many entries in its own pool are ahead of it. The foreground UI uses it to\n * say so while it waits; nothing else needs it.\n */\n onQueued?: (id: string, ahead: number) => void;\n /** Called on tool start/end with activity info (for streaming progress to UI). */\n onToolActivity?: (activity: ToolActivity) => void;\n /** Called on streaming text deltas from the assistant response. */\n onTextDelta?: (delta: string, fullText: string) => void;\n /** Called for every streaming event of each model call (for the in-flight activity line). */\n onModelCall?: (event: ModelCallEvent) => void;\n /** Called when the agent session is created (for accessing session stats). */\n onSessionCreated?: (session: AgentSession) => void;\n /** Called at the end of each agentic turn with the cumulative count. */\n onTurnEnd?: (turnCount: number) => void;\n /** Called once per assistant message_end with that message's usage delta. */\n onAssistantUsage?: (usage: { input: number; output: number; cacheWrite: number }) => void;\n /** Called when the session successfully compacts. */\n onCompaction?: (info: CompactionInfo) => void;\n /** Nesting depth: top-level subagent = 1. */\n depth?: number;\n /** Parent agent ID for ownership-scoped nested controls. */\n parentAgentId?: string;\n /** Effective inherited nesting cap for this branch. */\n maxSubagentDepth?: number;\n /** Config-discovery root inherited by nested launches when it differs from the working directory. */\n configCwd?: string;\n /** Project-trust decision for `configCwd`; only meaningful paired with it, set by nested launches. */\n configProjectTrusted?: boolean;\n /** Root session id, inherited by nested launches so transcripts stay grouped. */\n rootSessionId?: string;\n}\n\ninterface ResumeOptions {\n /**\n * Run the resumed turn detached in the background: return immediately with\n * the record still \"running\" (or \"queued\" at the concurrency limit) and\n * notify on completion via onComplete, exactly like a background spawn.\n * Default (false/undefined) runs the resume inline and returns the settled\n * record \u2014 the historical behavior.\n */\n isBackground?: boolean;\n /**\n * Explicit turn limit for the resumed run: this, else the limit the agent\n * was spawned with, else its type's own `max_turns`, else the default \u2014\n * counted afresh from the resume prompt (#368).\n */\n maxTurns?: number;\n /** Called on streaming text and model-call changes during this resume. */\n onTextDelta?: (delta: string, fullText: string) => void;\n onModelCall?: (event: ModelCallEvent) => void;\n /** Called at the end of each resumed turn with the count since the resume. */\n onTurnEnd?: (turnCount: number) => void;\n /** Called on tool start/end with activity info (for streaming progress to UI). */\n onToolActivity?: (activity: ToolActivity) => void;\n /** Called once per assistant message_end with that message's usage delta. */\n onAssistantUsage?: (usage: { input: number; output: number; cacheWrite: number }) => void;\n /** Called when the session successfully compacts. */\n onCompaction?: (info: CompactionInfo) => void;\n /**\n * Background resume only: called synchronously when the run actually starts \u2014\n * immediately, or later from drainQueue. Callers wire per-run side effects\n * (output-file streaming) here rather than at the call site, so a resume that\n * is stopped while still queued never leaves a subscription behind: `abort()`\n * drops a queued record without reaching `settle()`, which is what would have\n * torn that subscription down.\n */\n onStarted?: () => void;\n}\n\n/** Best-effort ceiling on one child's shutdown handlers, so teardown can't strand a quit. */\nconst CHILD_SHUTDOWN_TIMEOUT_MS = 3_000;\n\n/**\n * Close the extension lifecycle `runAgent` opened with `bindExtensions`, then dispose.\n *\n * `AgentSession.dispose()` only calls `ExtensionRunner.invalidate()` \u2014 pi emits the event\n * itself in `AgentSessionRuntime.dispose()` beforehand, and this is the one place that binds\n * extensions onto a session without going through that path. Without the emit, everything an\n * extension armed in `session_start` leaks once per spawn, and its next tick throws\n * `assertActive()` from a bare timer callback \u2014 an uncaughtException that kills pi (#242).\n */\nasync function shutdownChildSession(session: AgentSession | undefined): Promise<void> {\n let deadline: ReturnType<typeof setTimeout> | undefined;\n try {\n const runner = session?.extensionRunner;\n // Optional all the way down: on a pi without the getter, or a stubbed session from a\n // partial `onSessionCreated`, skip the emit \u2014 the same degrade as before this fix.\n if (runner?.hasHandlers?.(\"session_shutdown\")) {\n // Raced, not awaited outright. `emit` runs every handler serially with no timeout of\n // its own, and dispose() is reached from pi's own `session_shutdown` with the TUI\n // already torn down \u2014 one hung handler would leave a dead terminal.\n await Promise.race([\n runner.emit({ type: \"session_shutdown\", reason: \"quit\" }),\n new Promise<void>(resolve => {\n deadline = setTimeout(resolve, CHILD_SHUTDOWN_TIMEOUT_MS);\n deadline.unref();\n }),\n ]);\n }\n } catch { /* a partial session must degrade, not take the teardown down with it */ }\n finally {\n // Promise.race does not cancel its loser, even when a handler rejects.\n if (deadline !== undefined) clearTimeout(deadline);\n }\n // Always, even on timeout: disposal is what this function ultimately exists to do.\n try { session?.dispose?.(); } catch { /* ignore */ }\n}\n\n/**\n * Wrap an observer the child's own agent loop calls (usage, compaction) so a\n * throw cannot reach that loop. pi records a throw from a session listener as\n * the turn's failure, so an observer closed over a replaced session's `pi`\n * (\"This extension ctx is stale ...\") used to end a detached child with an\n * empty error turn and \"No output\" (#145). That failure is expected after a\n * reload and dropped silently. Any other throw is a real observer defect: it\n * is logged once per observer and also kept from killing the run.\n */\nfunction guardObserver<A extends unknown[]>(name: string, observer: ((...args: A) => void) | undefined): ((...args: A) => void) | undefined {\n if (!observer) return undefined;\n let logged = false;\n return (...args: A) => {\n try {\n observer(...args);\n } catch (error) {\n if (isStaleCtxError(error) || logged) return;\n logged = true;\n console.error(`pi-subagents: ${name} observer failed; further failures are not logged`, error);\n }\n };\n}\n\nexport class AgentManager {\n private agents = new Map<string, AgentRecord>();\n private cleanupInterval: TimerHandle;\n /** `CONSUMED_RECORD_TTL_MS` unless `PI_SUBAGENTS_CONSUMED_TTL_MIN` overrides it. */\n private readonly consumedTtlMs = retentionMs(\"PI_SUBAGENTS_CONSUMED_TTL_MIN\", CONSUMED_RECORD_TTL_MS);\n /** `UNCONSUMED_RECORD_TTL_MS` unless `PI_SUBAGENTS_UNREAD_TTL_MIN` overrides it. */\n private readonly unreadTtlMs = retentionMs(\"PI_SUBAGENTS_UNREAD_TTL_MIN\", UNCONSUMED_RECORD_TTL_MS);\n private onComplete?: OnAgentComplete;\n private onStart?: OnAgentStart;\n private onQueuedStop?: OnAgentQueuedStop;\n private onReaped?: OnAgentReaped;\n private onCompact?: OnAgentCompact;\n private onUsage?: OnAgentUsage;\n private onSteered?: OnAgentSteered;\n private maxConcurrent: number;\n private maxConcurrentForeground = DEFAULT_MAX_CONCURRENT_FOREGROUND;\n /** Base repos worktrees were created from \u2014 so dispose() can prune them all,\n * not just the parent repo (caller-supplied cwd can target other repos). */\n private worktreeRepos = new Set<string>();\n\n /**\n * Startup phases, keyed by agent id. `spawn()` still returns synchronously,\n * but an agent using worktree isolation is not running yet when it does \u2014\n * copying the repo is an awaited git call. This is what `awaitStartup` hands\n * callers that must fail their tool call on a startup failure, and what\n * `waitForAll` waits on while a record is \"running\" with no `promise` yet.\n * Entries are dropped once the run is underway, and kept (rejected) after a\n * startup failure so a late `awaitStartup` still sees it.\n */\n private startups = new Map<string, Promise<void>>();\n\n /**\n * Evicted agents that can still be reached by name, keyed by handle. Outlives\n * the 10-minute record cleanup \u2014 that timer exists to bound memory, not to\n * expire a conversation the user might still want \u2014 and is cleared alongside\n * completed records on session start/switch.\n */\n private tombstones = new Map<string, AgentTombstone>();\n\n /** Evicted records by id, oldest first (insertion order). */\n private evictedNotes = new Map<string, EvictedNote>();\n /** Evicted id -> the id its reopened conversation runs under, so the old id keeps resolving (#330). */\n private successors = new Map<string, string>();\n\n /**\n * Agents waiting to start, tagged with the pool they wait on (none for a\n * start that only waits on the process budget). Each entry is also a waiter\n * in the process-wide budget queue, which is what actually starts it: the\n * budget picks the earliest entry, across every manager, whose depth fits\n * and whose own pool has room, so neither pool can head-of-line-block the\n * other, and every removal path (`abort`, `abortAll`, `dispose`) stays a\n * single filter.\n *\n * `release` wakes a caller blocked in `spawnAndWait`, and is fired once the\n * entry's `start` has SETTLED rather than at drain time: startup is async\n * now, so releasing earlier would wake the caller before `record.promise`\n * exists and it would read a still-starting agent as one that never ran.\n * Removing an entry from this array MUST release it \u2014 a queued record has no\n * promise to await, and pi has no tool-execution timeout to bail the caller\n * out.\n */\n private queue: QueueEntry[] = [];\n /** Number of currently running background agents. */\n private runningBackground = 0;\n /** Number of currently running foreground (blocking) agents. */\n private runningForeground = 0;\n\n constructor(\n onComplete?: OnAgentComplete,\n maxConcurrent = DEFAULT_MAX_CONCURRENT,\n onStart?: OnAgentStart,\n onCompact?: OnAgentCompact,\n onUsage?: OnAgentUsage,\n onSteered?: OnAgentSteered,\n private readonly clock: Clock = realClock,\n private readonly homeDir?: string,\n onQueuedStop?: OnAgentQueuedStop,\n onReaped?: OnAgentReaped,\n ) {\n this.onComplete = onComplete;\n this.onStart = onStart;\n this.onQueuedStop = guardObserver(\"queued stop\", onQueuedStop);\n this.onReaped = guardObserver(\"reaped\", onReaped);\n this.onCompact = guardObserver(\"compaction\", onCompact);\n this.onUsage = guardObserver(\"usage\", onUsage);\n this.onSteered = onSteered;\n this.maxConcurrent = maxConcurrent;\n // Sweep finished records past their retention window (see cleanup()).\n const sweepMs = Math.min(\n MAX_SWEEP_INTERVAL_MS,\n Math.max(MIN_SWEEP_INTERVAL_MS, Math.min(this.consumedTtlMs, this.unreadTtlMs)),\n );\n this.cleanupInterval = this.clock.setInterval(() => this.cleanup(), sweepMs);\n this.cleanupInterval.unref?.();\n }\n\n /**\n * Put a run under Plan mode's policy when its owning agent's run is (a nested\n * child) or the parent session is planning right now (everything else, a\n * workflow stage included). The gate object is kept, since the child's hooks\n * hold it.\n */\n private decidePlanGate(record: AgentRecord, query: () => PlanToolPolicy | undefined): void {\n const owner = record.parentAgentId === undefined ? undefined : this.agents.get(record.parentAgentId);\n const policy = owner?.planGate?.policy ?? query();\n record.planGate ??= {};\n record.planGate.policy = policy;\n if (policy || record.invocation?.planMode) {\n record.invocation ??= {};\n record.invocation.planMode = policy ? true : undefined;\n }\n }\n\n /** Spawns and settles, in order: `spawnSeq` / `settleSeq` on lifecycle events. */\n private lifecycleSequence = 0;\n\n /** The next lifecycle sequence number; the host stamps `settleSeq` with it at settle. */\n nextSequence(): number {\n return ++this.lifecycleSequence;\n }\n\n /** Update the max concurrent background agents limit. */\n setMaxConcurrent(n: number) {\n this.maxConcurrent = Math.max(1, n);\n // Start queued agents if the new limit allows\n this.drainQueue();\n }\n\n getMaxConcurrent(): number {\n return this.maxConcurrent;\n }\n\n /** Update the max concurrent foreground (blocking) agents limit. 0 = unlimited. */\n setMaxConcurrentForeground(n: number) {\n // Floor 0, not 1: unlimited is a meaningful value here and the default.\n this.maxConcurrentForeground = Math.max(0, n);\n // Start queued agents if the new limit allows \u2014 including everything, when\n // the limit is cleared back to unlimited mid-run.\n this.drainQueue();\n }\n\n getMaxConcurrentForeground(): number {\n return this.maxConcurrentForeground;\n }\n\n /**\n * Which pool a spawn is charged to, or undefined for one that is charged to\n * neither (nested children, detached non-background spawns).\n *\n * Nothing here queues when the limit is unset \u2014 `poolHasRoom` reports an\n * unlimited pool as always having room, so that alone is what keeps the\n * default path identical. The `> 0` guard is belt and braces on top: it also\n * keeps the counter from churning and the settle path from calling a drain\n * that would find nothing to do. Both are unobservable, which is why no test\n * pins them; the observable half \u2014 that the default start stays synchronous \u2014\n * is pinned in `test/foreground-concurrency.test.ts`.\n */\n private poolFor(record: AgentRecord): Pool | undefined {\n if (occupiesPoolSlot(record)) return \"background\";\n if (this.maxConcurrentForeground > 0 && occupiesForegroundSlot(record)) return \"foreground\";\n return undefined;\n }\n\n private poolHasRoom(pool: Pool): boolean {\n return pool === \"background\"\n ? this.runningBackground < this.maxConcurrent\n : this.maxConcurrentForeground === 0 || this.runningForeground < this.maxConcurrentForeground;\n }\n\n /**\n * Spawn an agent and return its ID immediately (for background use).\n * If the concurrency limit is reached, the agent is queued.\n *\n * The id comes back synchronously, but with `isolation: \"worktree\"` the agent\n * is not running yet when it does \u2014 the repo copy is an awaited git call.\n * Callers that must fail a tool call on a startup failure await\n * `awaitStartup(id)`; everyone else sees it on the record (status \"error\").\n */\n spawn(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n type: SubagentType,\n prompt: string,\n options: SpawnOptions,\n ): string {\n // Validate before the queue branch \u2014 a queued spawn should fail at the\n // call, not minutes later at drain. Throw (not warn): programmatic callers\n // can fix and retry; the RPC layer converts throws into error envelopes.\n assertSpawnCwd(options.cwd, ctx.cwd);\n const selection = options.modelSelection ?? selectModel({\n homeDir: options.homeDir ?? this.homeDir,\n agentType: type,\n definitionModel: getAgentConfig(type)?.model,\n paramModel: options.model,\n parentModel: ctx.model,\n registry: ctx.modelRegistry,\n cwd: options.configCwd ?? ctx.cwd,\n agentLabel: getAgentConfig(type)?.displayName,\n });\n if (typeof selection === \"string\") throw new Error(selection);\n if (selection.scopeWarning && !options.modelSelection) ctx.ui.notify(selection.scopeWarning, \"warning\");\n options = { ...options, model: selection.model, modelSelection: selection };\n\n const id = randomUUID().slice(0, 17);\n const abortController = new AbortController();\n const record: AgentRecord = {\n id,\n type,\n // Owned children \u2014 nested, or a workflow's \u2014 are filtered out of every\n // top-level surface, so no handle: nothing can address them and they must\n // not consume a name a top-level sibling could otherwise take.\n handle: !isTopLevelAgent(options)\n ? undefined\n // A reclaimed handle is used as-is: it belongs to the conversation this\n // spawn is reopening, and re-deriving it would lose the numbering.\n : options.reclaim?.handle ?? assignHandle(handleBase(type), this.takenHandles()),\n description: options.description,\n // Reclaimed here, or filled in below from `name` \u2014 in which case it must\n // see the handle this record just took, since both come out of the same\n // namespace.\n alias: isTopLevelAgent(options) ? options.reclaim?.alias : undefined,\n // Overwritten below when the spawn is actually queued; a foreground spawn\n // that queues flips to \"queued\" there rather than being guessed at here,\n // since the pool decision needs the finished record.\n status: options.isBackground ? \"queued\" : \"running\",\n toolUses: 0,\n startedAt: this.clock.now(),\n abortController,\n lifetimeUsage: { input: 0, output: 0, cacheWrite: 0, cost: 0 },\n spawnSeq: this.nextSequence(),\n compactionCount: 0,\n // Raw tri-state (not coerced to a boolean): true = background, false =\n // foreground (has an inline tool-result surface), undefined = caller never\n // declared it (e.g. a cross-extension RPC spawn). The widget's background-\n // only filter excludes only explicit `false`, so undefined agents \u2014 which\n // have no inline surface \u2014 stay visible instead of vanishing.\n isBackground: options.isBackground,\n // Whether anyone is awaiting this agent is a property of the agent, not\n // of the call that made it \u2014 and both settle paths need it long after\n // `options` has stopped being the interesting object.\n blocking: options.blocking,\n invocation: options.invocation,\n modelFallback: selection.fallback,\n modelSelection: selection,\n modelTier: selection.tier ? tierDisclosure(selection.tier) : undefined,\n previousModelTier: options.previousModelTier,\n previousModelFallback: options.previousModelFallback,\n previousId: options.previousId,\n depth: options.depth ?? 1,\n parentAgentId: options.parentAgentId,\n workflowId: options.workflowId,\n maxSubagentDepth: options.maxSubagentDepth,\n rootSessionId: options.rootSessionId,\n };\n this.decidePlanGate(record, () => queryPlanPolicy(pi.events));\n record.planQuery = () => queryPlanPolicy(pi.events, \"restrict\");\n this.agents.set(id, record);\n // After the insert, so `takenHandles()` already counts this record's own\n // handle \u2014 a spawn named after its own type gets `explore-2`, not a\n // duplicate `explore` that would make resolution ambiguous.\n if (record.handle !== undefined && record.alias === undefined && options.name !== undefined) {\n record.nameBase = handleBase(options.name);\n record.alias = assignHandle(record.nameBase, this.takenHandles());\n }\n\n const args: SpawnArgs = { pi, ctx, type, prompt, options };\n\n const pool = this.poolFor(record);\n // `bypassQueue` skips the pool, never the process budget: that ceiling is\n // the one guarantee every path shares.\n const waitPool = options.bypassQueue ? undefined : pool;\n let lease: BudgetLease | undefined;\n try {\n lease = this.admit(record, waitPool);\n } catch (err) {\n this.agents.delete(id);\n throw err;\n }\n try {\n options.onPrepare?.(id);\n } catch (err) {\n this.agents.delete(id);\n releaseBudget(lease);\n this.drainQueue();\n throw err;\n }\n if (lease === undefined) {\n // Queue it \u2014 started once its pool has room and the process budget a\n // lease, whichever was missing.\n // Idempotent for background (already \"queued\"); the flip that matters is\n // a blocking foreground spawn, optimistically marked \"running\" above.\n record.status = \"queued\";\n // A queued record never reaches startAgent's signal wiring, so arm the\n // parent abort here or Esc could not release the position.\n if (!this.armQueuedAbort(record, options.signal)) return id;\n let release!: () => void;\n record.startGate = new Promise<void>(resolve => { release = resolve; });\n // Failure bookkeeping keys on whether an inline caller gets the throw,\n // which is `blocking`, not on which pool (if any) it waited for.\n const failAs: Pool = record.blocking ? \"foreground\" : \"background\";\n this.enqueueStart(id, record, waitPool, () => this.launch(id, record, args, failAs), () => release());\n options.onQueued?.(id, this.queue.filter(e => e.pool === waitPool).length - 1);\n return id;\n }\n\n record.budgetLease = lease;\n this.launch(id, record, args, undefined);\n return id;\n }\n\n /**\n * Wire a parent abort signal for a record that is about to be QUEUED.\n * `startAgent` does this for running agents, and a queued record never gets\n * there, so without this Esc could not release a queue position.\n *\n * Returns false when the signal is ALREADY aborted, in which case the record\n * is stopped here and must not be enqueued: `addEventListener` never fires on\n * an aborted signal, so a `spawnAndWait` on it would wait forever \u2014 pi has no\n * tool-execution timeout to bail it out.\n *\n * The listener is removable (`record.detachParentAbort`): `startAgent`\n * replaces it with its own, and `sendToBackground` must be able to take it\n * off, or the caller that armed it could stop a run it no longer owns.\n */\n private armQueuedAbort(record: AgentRecord, signal?: AbortSignal): boolean {\n if (signal === undefined) return true;\n if (signal.aborted) {\n record.status = \"stopped\";\n record.completedAt = this.clock.now();\n return false;\n }\n this.armParentAbort(record, signal);\n return true;\n }\n\n /**\n * Stop `record` when its caller's `signal` aborts, replacing any listener an\n * earlier stage armed \u2014 at most one is live per record, so one call to\n * `detachParentAbort` cuts the run loose from its caller.\n */\n private armParentAbort(record: AgentRecord, signal: AbortSignal | undefined): void {\n this.detachParentAbort(record);\n if (signal === undefined) return;\n const onParentAbort = () => this.abort(record.id);\n signal.addEventListener(\"abort\", onParentAbort, { once: true });\n record.detachParentAbort = () => signal.removeEventListener(\"abort\", onParentAbort);\n }\n\n private detachParentAbort(record: AgentRecord): void {\n record.detachParentAbort?.();\n record.detachParentAbort = undefined;\n }\n\n /**\n * The one admission check every start makes: a lease now when `pool` (if\n * any) has room and the process budget admits `record`'s depth, else\n * undefined and the caller queues. Throws, having changed nothing, when the\n * start could never be admitted (deeper than the budget reserves for) or the\n * budget's wait queue is full.\n */\n private admit(record: AgentRecord, pool: Pool | undefined): BudgetLease | undefined {\n assertWithinBudgetDepth(record.depth);\n const lease = pool === undefined || this.poolHasRoom(pool) ? tryAcquireBudget(record.depth) : undefined;\n if (lease === undefined && !budgetHasPendingRoom()) throw new Error(BUDGET_QUEUE_FULL_ERROR);\n return lease;\n }\n\n /** Give back `record`'s budget lease, if it holds one. Callers drain afterwards. */\n private releaseLease(record: AgentRecord): void {\n releaseBudget(record.budgetLease);\n record.budgetLease = undefined;\n }\n\n /**\n * Park a start in `queue` and in the process budget. The budget calls\n * `grant` once the record's depth fits and `pool` (if any) has room; `start`\n * then runs and `release` fires when it settles. A record that stopped being\n * \"queued\" without being dequeued hands the lease straight back.\n */\n private enqueueStart(\n id: string,\n record: AgentRecord,\n pool: Pool | undefined,\n start: () => Promise<void>,\n release: () => void,\n ): void {\n let markLeft!: () => void;\n const left = new Promise<void>(resolve => { markLeft = resolve; });\n const entry: QueueEntry = {\n id,\n record,\n pool,\n start,\n release: () => {\n release();\n markLeft();\n },\n // enqueueBudget only registers; grant cannot run until the next pump,\n // after this entry has been initialized and published in the queue.\n cancel: enqueueBudget({\n depth: record.depth,\n ready: () => pool === undefined || this.poolHasRoom(pool),\n grant: (lease) => {\n this.queue = this.queue.filter(e => e !== entry);\n if (this.agents.get(id) !== record || record.status !== \"queued\") {\n releaseBudget(lease);\n entry.release();\n return;\n }\n record.budgetLease = lease;\n // Detached, and never rejects: a late failure (e.g. strict worktree\n // isolation) lands on the record inside `launch`. The release waits\n // for that startup to SETTLE: a release at grant time would wake a\n // blocked `spawnAndWait` while `record.promise` was still undefined,\n // and it would read a healthy agent as one that never ran.\n void entry.start().then(() => entry.release(), () => entry.release());\n },\n }),\n left,\n };\n this.queue.push(entry);\n }\n\n /** Add `delta` to the running count of `pool`; no pool, no count. */\n private chargePool(pool: Pool | undefined, delta: 1 | -1): void {\n if (pool === \"background\") this.runningBackground += delta;\n else if (pool === \"foreground\") this.runningForeground += delta;\n }\n\n /**\n * Kick off an agent's startup and register it under `startups`. The returned\n * promise never rejects \u2014 the failure is delivered through `awaitStartup`,\n * and to the record.\n *\n * @param failAs - For a start that QUEUED (on a pool or on the budget\n * alone), how a startup failure is reported: \"foreground\" when an inline\n * `spawnAndWait` caller gets it as a throw, else \"background\". Undefined\n * for an immediate start. A queued start can begin minutes after `spawn()`\n * returned, and nobody is awaiting `awaitStartup` by then, so its failure\n * lives on the record as status \"error\". An immediate start instead drops\n * the record, exactly as the throw out of `spawn()` did: no orphan in\n * `listAgents()`, and the handle goes back.\n */\n private launch(id: string, record: AgentRecord, args: SpawnArgs, failAs: Pool | undefined): Promise<void> {\n const startup = this.startAgent(id, record, args).then(\n () => { this.startups.delete(id); },\n (err) => {\n this.startups.delete(id);\n try {\n if (failAs !== undefined) {\n // Mirrors settleRun: an inline caller gets this failure as a throw\n // out of spawnAndWait, so an unconsumed record would ALSO nudge the\n // session about it \u2014 the same failure reported twice.\n if (failAs === \"foreground\") markConsumed(record, this.clock.now());\n record.status = \"error\";\n record.error = errorMessage(err);\n record.completedAt = this.clock.now();\n try { this.onComplete?.(record); } catch { /* the startup failure is the error worth reporting */ }\n } else {\n this.agents.delete(id);\n }\n } finally {\n // The agent never kept its slot (startAgent gives it back on failure)\n // or its lease, so anything queued behind it can go now.\n this.releaseLease(record);\n this.drainQueue();\n }\n throw err;\n },\n );\n this.startups.set(id, startup);\n // Nothing is obliged to await `startups` \u2014 swallow the rejection once here\n // so an unawaited startup can't take the process down, and hand callers\n // (drainQueue) that swallowed promise.\n return startup.catch(() => {});\n }\n\n /**\n * Resolves once the agent is actually running, and rejects with the startup\n * failure (strict worktree isolation) that `spawn()` used to throw before the\n * repo copy became async. Resolves immediately for an agent that is already\n * running, still queued, or unknown \u2014 so callers can await it unconditionally.\n *\n * Call it in the same tick as the `spawn()` it belongs to: a failed startup\n * takes its record (and this entry) with it, exactly as the throw did.\n */\n awaitStartup(id: string): Promise<void> {\n return this.startups.get(id) ?? Promise.resolve();\n }\n\n /** Actually start an agent (called immediately or from queue drain). */\n private async startAgent(\n id: string,\n record: AgentRecord,\n { pi, ctx, type, prompt, options }: SpawnArgs,\n ) {\n // Re-validate the cwd (caller-supplied, else the session's): queued spawns can start minutes after\n // spawn()'s check, and the directory may be gone by then (TOCTOU). Same\n // curated errors; drainQueue parks a throw on the record as an error.\n assertSpawnCwd(options.cwd, ctx.cwd);\n // Single resolution point for the caller-supplied cwd \u2014 the worktree base\n // repo and both cleanup calls below MUST agree on this value forever.\n const customCwd = options.cwd ?? undefined; // null (RPC \"unset\") \u2192 undefined\n const baseCwd = customCwd ?? ctx.cwd;\n\n // Take the running state \u2014 and with it the concurrency slot \u2014 BEFORE the\n // first await. Creating a worktree is an awaited git call, and drainQueue\n // reads the pool counters synchronously in a loop: incrementing after the\n // await would let it start every queued agent at once while the first is\n // still copying its repo. Claiming \"running\" here also keeps abort() and\n // abortAll() able to reach an agent whose worktree is still being created.\n //\n // The pool is resolved ONCE, here, and recorded for `settleRun`:\n // `poolFor` reads `maxConcurrentForeground`, which the user can change from\n // `/agents \u2192 Settings` mid-run, so recomputing it at settle time would\n // decrement a pool this run never charged (counter underflow, limit\n // silently lifted) or skip the decrement for one it did (leaked slot \u2014\n // every later blocking spawn queues forever). Only `sendToBackground`\n // changes it afterwards, moving the counters with it. The two startup exits\n // below never reach `settleRun`, so they hand the slot back themselves.\n record.chargedPool = this.poolFor(record);\n record.status = \"running\";\n record.startedAt = this.clock.now();\n record.startGate = undefined;\n this.chargePool(record.chargedPool, 1);\n\n // Hold the pool slot BEFORE awaiting admission, just as for worktree creation.\n try {\n if (options.modelSelection?.tierBinding && !options.modelSelection.tierAdmitted) {\n const block = await admitModelSelection(options.modelSelection, ctx.modelRegistry, pi.events);\n // Admitting an unadmitted binding always resolves its `tier`.\n record.modelTier = tierDisclosure(options.modelSelection.tier!);\n record.modelFallback = options.modelSelection.fallback;\n if (block) throw new Error(`${modelSelectionNote(record)} ${describeBlock(block)} The agent was not started.`);\n if (record.abortController?.signal.aborted || options.signal?.aborted) throw new Error(\"Agent aborted during model admission.\");\n }\n if (record.modelTier) {\n record.invocation ??= {};\n Object.assign(record.invocation, describeSelection(options.modelSelection, ctx.modelRegistry));\n }\n } catch (error) {\n this.chargePool(record.chargedPool, -1);\n throw error;\n }\n\n // Worktree isolation: try to create a temporary git worktree. Strict \u2014\n // fail loud if not possible (no silent fallback to main tree). Done BEFORE\n // the run is kicked off so a failure doesn't leave a half-running agent.\n // The project switch is enforced here as well as at the tool boundary\n // because cross-extension RPC forwards its options unvalidated \u2014 a schema\n // that omits the field can't stop a caller that never saw the schema.\n // The agent file's `isolation:` is resolved here too, not by each caller:\n // mentions pass none, and RPC forwards only its caller's value. Workflow\n // children are the exception, as in Claude Code, whose workflow agent()\n // reads only the script's option and ignores the definition's.\n const isolation = options.workflowId !== undefined\n ? options.isolation\n : getAgentConfig(type)?.isolation ?? options.isolation;\n // A worktree exists to make edits, which a child started while planning may not.\n if (isolation === \"worktree\" && record.planGate?.policy) {\n this.chargePool(record.chargedPool, -1);\n throw new Error('Cannot run with isolation: \"worktree\" while Plan mode is active: a worktree exists to make edits. Omit `isolation`, or leave Plan mode first.');\n }\n let worktreeCwd: string | undefined;\n if (isolation === \"worktree\" && isWorktreeIsolationEnabled()) {\n let wt: WorktreeInfo;\n try {\n wt = await createWorktree(pi, baseCwd, id);\n } catch (err) {\n this.chargePool(record.chargedPool, -1);\n const cause = errorMessage(err);\n // Only a parent-cwd spawn can be fixed by pointing `cwd` elsewhere.\n const hint = customCwd === undefined\n ? \" To isolate another repo, pass its path as the `Agent` tool's `cwd`; or omit `isolation`.\"\n : \" Pass a `cwd` inside a git repo with at least one commit, or omit `isolation`.\";\n throw new Error(`Cannot run with isolation: \"worktree\": ${cause}.${hint}`);\n }\n record.worktree = wt;\n // workPath preserves subdirectory scoping for caller-supplied cwds: a\n // cwd deep in a monorepo maps to the same subdir inside the copy, not\n // the copied repo's root. Plain worktree spawns keep the historical\n // behavior (agent at the copy's root) \u2014 moving them to workPath would\n // also move .pi config discovery when the parent session sits in a repo\n // subdirectory, silently dropping extensions/skills.\n worktreeCwd = customCwd !== undefined ? wt.workPath : wt.path;\n this.worktreeRepos.add(baseCwd);\n // The widget's \"worktree\" tag reads this; only callers that resolve the\n // agent file themselves seed it.\n record.invocation ??= {};\n record.invocation.isolation = \"worktree\";\n\n // No longer \"running\" means a stop landed while the copy was being made\n // (abort(), abortAll()) \u2014 a window that did not exist when creation was\n // synchronous. The record is already terminal, so launching the run would\n // burn tokens on work nobody is waiting for: discard the fresh (and by\n // definition unchanged) worktree instead.\n if (record.status !== \"running\") {\n this.chargePool(record.chargedPool, -1);\n recordWorktreeCleanup(record, await cleanupWorktree(pi, baseCwd, wt, options.description));\n if (record.worktreeResult?.error) {\n if (!record.isBackground) markConsumed(record, this.clock.now());\n try { this.onComplete?.(record); } catch { /* do not strand the lease */ }\n }\n // After the cleanup, not before: the copy is still being removed until here.\n this.releaseLease(record);\n this.drainQueue();\n return;\n }\n }\n\n // A throwing `onStart` fails the startup like a worktree failure: hand the\n // slot back and remove the copy, since nothing will ever settle this run.\n // The lease goes back in `launch`, after the cleanup.\n try {\n this.onStart?.(record);\n } catch (err) {\n this.chargePool(record.chargedPool, -1);\n if (record.worktree) {\n try {\n recordWorktreeCleanup(record, await cleanupWorktree(pi, baseCwd, record.worktree, options.description));\n } catch { /* ignore unexpected cleanup errors */ }\n }\n if (record.worktreeResult?.error) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`${message}\\n${record.error}`);\n }\n throw err;\n }\n\n // Wire parent abort signal to stop the subagent when the parent is interrupted.\n // A queued spawn can start minutes after the caller handed us its signal,\n // by which time it may already be aborted \u2014 and `addEventListener` would\n // never fire, leaving a child the parent can no longer reach.\n if (options.signal?.aborted) this.abort(id);\n else this.armParentAbort(record, options.signal);\n const detach = () => this.detachParentAbort(record);\n\n record.ranThisRun = record.status === \"running\";\n const promise = runAgent(ctx, type, prompt, {\n pi,\n clock: this.clock,\n homeDir: options.homeDir ?? this.homeDir,\n agentId: id,\n model: options.modelSelection?.model,\n modelSelection: record.modelSelection!,\n maxTurns: options.maxTurns,\n isolated: options.isolated,\n inheritContext: options.inheritContext,\n thinkingLevel: options.thinkingLevel,\n structuredOutput: options.structuredOutput,\n planGate: record.planGate,\n resumeSessionFile: options.resumeSessionFile,\n nested: options.parentAgentId !== undefined,\n workflow: options.workflowId !== undefined,\n // Worktree wins for the working dir (the agent must run in the copy \u2014\n // which, with a custom cwd, was created from that target). Config stays\n // with the parent project when a caller-supplied cwd is in play; it must\n // stay undefined otherwise so plain worktree runs keep resolving config\n // (incl. relative extension paths and memory) inside the worktree copy.\n cwd: worktreeCwd ?? customCwd,\n // Set iff a worktree was created (see above) \u2014 names the directory the\n // copy came from, so the prompt can tell the agent not to work there.\n worktreeBase: worktreeCwd ? baseCwd : undefined,\n configCwd: options.configCwd ?? (customCwd !== undefined ? ctx.cwd : undefined),\n configProjectTrusted: options.configCwd !== undefined ? options.configProjectTrusted : undefined,\n signal: record.abortController!.signal,\n onToolActivity: (activity) => {\n if (activity.type === \"end\") record.toolUses++;\n options.onToolActivity?.(activity);\n },\n onTurnEnd: options.onTurnEnd,\n onTextDelta: options.onTextDelta,\n onModelCall: options.onModelCall,\n onAssistantUsage: (usage, message) => {\n relabelFromResponse(record, message);\n addUsage(record.lifetimeUsage, usage);\n this.onUsage?.(record, usage);\n options.onAssistantUsage?.(usage);\n },\n onCompaction: (info) => {\n record.compactionCount++;\n this.onCompact?.(record, info);\n options.onCompaction?.(info);\n },\n nestedRuntime: {\n manager: this,\n parentAgentId: id,\n depth: record.depth,\n maxSubagentDepth: record.maxSubagentDepth,\n },\n onSessionCreated: (session) => {\n record.session = session;\n // Capture now, while the session object exists: after eviction this\n // path is the only thing that can reopen the conversation, and an\n // in-memory session reports undefined, which correctly means\n // \"nothing to come back to\".\n // Optional chaining, not defensiveness for its own sake: this is the\n // only field read off the session at creation, so an older pi or a\n // stubbed session must degrade to \"not resumable\" rather than throw\n // and take the whole spawn down with it.\n record.sessionFile = session.sessionManager?.getSessionFile?.();\n // Same reason, different field: the model and thinking level are only\n // knowable once pi has resolved its defaults and clamped the level to\n // what the model supports. Writing them back here makes the record\n // authoritative, so every surface reads one place instead of each\n // re-deriving \"session, else the request\" for itself.\n if (session.model) {\n record.invocation ??= {};\n // Read the kept request first: a caller's level survives being clamped\n // AND, one line later, being replaced by the effective one.\n const requested = record.invocation.requestedThinking ?? record.invocation.thinking;\n Object.assign(\n record.invocation,\n record.modelTier?.kind === \"routed\" && record.modelTier.admitted\n ? describeSelection(options.modelSelection, ctx.modelRegistry)\n : isVirtualModel(session.model) ? describeVirtualModel(session.model) : describeModel(session.model),\n );\n // Guarded for the reason above: a session that reports no level keeps\n // the request rather than losing it. Overwriting unconditionally would\n // turn an older or stubbed session into a blank `thinking:` tag, which\n // is worse than the stale-but-true value it replaced.\n if (session.thinkingLevel) {\n record.invocation.thinking = session.thinkingLevel;\n if (requested && requested !== session.thinkingLevel) {\n record.invocation.requestedThinking = requested;\n }\n }\n }\n // The transcript says it too: it is what someone opens to find out what ran.\n if (record.modelFallback && record.outputFile) appendModelFallbackEntry(record.outputFile, record.id, record.modelFallback);\n if (record.modelTier && record.outputFile) appendModelTierEntry(record.outputFile, record.id, record.modelTier);\n // Flush any steers that arrived before the session was ready\n if (record.pendingSteers?.length) {\n for (const msg of record.pendingSteers) {\n session.steer(msg).catch(() => {});\n }\n record.pendingSteers = undefined;\n }\n options.onSessionCreated?.(session);\n },\n })\n .then(async ({ responseText, session, aborted, steered, failure, structuredJson, structuredRetried }) => {\n this.settleOutcome(record, { text: responseText, failure, aborted, steered });\n // Kept beside `result`, never inside it: `result` is prose meant for a\n // reader \u2014 it is previewed, transcribed, and appended to below \u2014 while\n // this is a machine-readable payload one caller asked for by schema.\n record.structuredJson = structuredJson;\n record.structuredRetried = structuredRetried;\n record.session = session;\n\n detach();\n\n // Final flush of streaming output file\n if (record.outputCleanup) {\n try { record.outputCleanup(); } catch { /* ignore */ }\n record.outputCleanup = undefined;\n }\n\n // Clean up worktree if used\n if (record.worktree) {\n // The one moment the child's tree still exists and the child is done\n // writing to it. try/catch, not decoration: a hook that throws must\n // not leave the worktree behind.\n if (options.onBeforeWorktreeCleanup) {\n try {\n await options.onBeforeWorktreeCleanup(record.worktree.path);\n } catch { /* ignore \u2014 never block cleanup */ }\n }\n const wtResult = await cleanupWorktree(pi, baseCwd, record.worktree, options.description);\n recordWorktreeCleanup(record, wtResult);\n if (!wtResult.error && wtResult.hasChanges && wtResult.branch) {\n // With a caller-supplied cwd the branch lives in THAT repo, not the\n // parent session's \u2014 say so, or the orchestrator merges in the wrong repo.\n // Named by its toplevel: the cwd may be a subdirectory of it.\n const repo = record.worktree.repoRoot;\n const repoNote = customCwd !== undefined ? ` in \\`${repo}\\`` : \"\";\n // Appended to the prose only. A structured child's caller parses\n // `structuredJson`, which stays untouched \u2014 but `result` is also\n // what a human reads, so the note still belongs on it.\n record.result = responseText +\n `\\n\\n---\\nChanges saved to branch \\`${wtResult.branch}\\`${repoNote}. Merge with: \\`git merge ${wtResult.branch}\\`${customCwd !== undefined ? ` (run in \\`${repo}\\`)` : \"\"}`;\n }\n }\n\n this.abortOwnedChildren(id);\n\n this.settleRun(record, true);\n return responseText;\n })\n .catch(async (err) => {\n // Don't overwrite status if externally stopped via abort()\n if (record.status !== \"stopped\") {\n record.status = \"error\";\n }\n record.error = errorMessage(err);\n record.completedAt ??= this.clock.now();\n\n detach();\n\n // Final flush of streaming output file on error\n if (record.outputCleanup) {\n try { record.outputCleanup(); } catch { /* ignore */ }\n record.outputCleanup = undefined;\n }\n\n // Best-effort worktree cleanup on error\n if (record.worktree) {\n try {\n const wtResult = await cleanupWorktree(pi, baseCwd, record.worktree, options.description);\n recordWorktreeCleanup(record, wtResult);\n } catch { /* ignore cleanup errors */ }\n }\n\n this.abortOwnedChildren(id);\n\n this.settleRun(record, false);\n return \"\";\n });\n\n record.promise = promise;\n\n // Notify caller that spawn is complete (record is in the map, promise is set).\n // Called synchronously \u2014 onSessionCreated fires asynchronously inside runAgent.\n // Used by spawnAndWait to let the caller set up output files before streaming\n // starts. Read off the options, so a spawn that started from a queue drain\n // still reaches the caller that queued it.\n options.onSpawned?.(id);\n }\n\n /**\n * The shared tail of both settle paths: release whatever pool slot the run\n * held, notify, and let the queue drain into the freed slot.\n *\n * The decrement lives HERE and nowhere else. `abort()` on a running record\n * only fires its controller and leaves the run to settle normally, so\n * decrementing there too would double-free \u2014 permanently lifting the limit.\n *\n * Foreground agents fire `onComplete` for lifecycle symmetry, with\n * `resultConsumed` set so the callback skips notifications the inline result\n * already delivered.\n *\n * @param guardCallback swallow a throwing `onComplete` (the success path does;\n * the error path historically did not, and keeps not doing so).\n *\n * Releases `record.chargedPool` \u2014 the pool the run was charged to at start\n * (or moved to by `sendToBackground`), never a recomputed one, so a mid-run\n * change to `maxConcurrentForeground` can't make the release disagree with\n * the acquire.\n */\n private settleRun(record: AgentRecord, guardCallback: boolean): void {\n if (!record.isBackground) markConsumed(record, this.clock.now());\n // Nobody waits on a settled run; a later foreground resume must not look\n // like a spawn `sendToBackground` could hand off.\n record.blocking = false;\n this.chargePool(record.chargedPool, -1);\n // Every run that reaches here holds a budget lease (each start takes one),\n // so every settle frees a slot some queued start, in any manager, may need.\n this.releaseLease(record);\n\n try {\n if (guardCallback) {\n try { this.onComplete?.(record); } catch { /* ignore completion side-effect errors */ }\n } else {\n this.onComplete?.(record);\n }\n } finally {\n // Drained even when an unguarded `onComplete` throws: the slot and lease\n // are already free, and a waiter that misses this drain may be the child\n // a running parent is blocked on, with nothing else left to pump.\n this.drainQueue();\n }\n }\n\n /**\n * Stop the nested children a settled parent owns. Nested records are hidden\n * from the UI and only their owner can consume them, so a child outliving its\n * parent would burn tokens unseen with no way to reach it. Grandchildren are\n * covered transitively \u2014 each abort lands in that child's own settle path.\n */\n private abortOwnedChildren(parentId: string): void {\n for (const [id, record] of this.agents) {\n if (record.parentAgentId === parentId) this.abort(id);\n }\n }\n\n /**\n * Start queued agents up to each pool's concurrency limit and the process\n * budget. The budget owns the order (`pumpBudget`): the earliest waiter, in\n * any manager, whose depth fits and whose own pool has room. Eligibility per\n * entry rather than `shift`: with one queue serving several limits, a\n * saturated pool at the head would otherwise stall everything behind it.\n * Taking the earliest eligible entry keeps FIFO within each pool.\n */\n private drainQueue() {\n pumpBudget();\n }\n\n /**\n * Remove queued entries and wake anyone blocked on them. The single point\n * that enforces \"leaving the queue releases the waiter\" \u2014 a missed release is\n * an unbounded hang, not a failed call.\n */\n private dequeue(pred: (entry: QueueEntry) => boolean): void {\n const kept: typeof this.queue = [];\n const removed: QueueEntry[] = [];\n for (const entry of this.queue) (pred(entry) ? removed : kept).push(entry);\n this.queue = kept;\n for (const entry of removed) {\n entry.cancel();\n entry.release();\n }\n }\n\n /**\n * Spawn an agent and wait for completion (foreground use).\n * Charged to the foreground pool (`maxConcurrentForeground`), which is\n * unlimited by default; never to the background one.\n * Returns { id, record } so callers can access the agent ID.\n *\n * @param onSpawned - Called synchronously once the run is kicked off, before\n * onSessionCreated fires.\n */\n async spawnAndWait(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n type: SubagentType,\n prompt: string,\n options: Omit<SpawnOptions, \"isBackground\">,\n onSpawned?: (id: string) => void,\n ): Promise<{ id: string; record: AgentRecord }> {\n // `blocking` is what maxConcurrentForeground bounds, and this is its only\n // source. onSpawned rides on the options rather than on a field of this\n // manager: a queued spawn starts at drain time, long after any install/\n // restore pair around this call would have put the field back \u2014 and it now\n // fires after an await (worktree creation) even on the immediate path.\n const id = this.spawn(pi, ctx, type, prompt, {\n ...options,\n isBackground: false,\n blocking: true,\n onSpawned,\n });\n const record = this.agents.get(id)!;\n\n // Queued: nothing to await yet \u2014 the promise appears when the drain starts\n // it. The gate resolves (never rejects) on every path out of the queue,\n // start and abort alike, so a rejection can never escape into the caller's\n // tool `execute` and take down pi's whole Promise.all tool batch.\n if (record.status === \"queued\") await record.startGate;\n\n // The run promise only exists once startup is past its awaited repo copy \u2014\n // without this the call would return before the agent had started at all.\n // A startup failure (strict worktree isolation) rejects here, which is what\n // the immediate path owes its caller: the Agent tool reports failure by\n // letting this throw out of `execute`. A queued spawn's failure landed on\n // the record instead (nobody was awaiting `startups` at drain time) and is\n // rethrown below, so the contract is the same either way.\n await this.awaitStartup(id);\n\n // undefined when it was aborted while queued, or stopped mid-copy, and so\n // never ran \u2014 the record is already terminal with a completedAt, which is\n // what the caller renders.\n if (record.promise) await record.promise;\n\n // A record that ended \"error\" without ever getting a promise never ran: the\n // same startup failure spawn() rethrows on the immediate path (#179). Keep\n // one contract rather than letting queue pressure decide whether a strict\n // worktree failure throws or returns as a result.\n if (record.promise === undefined && record.status === \"error\") {\n throw new Error(record.error);\n }\n return { id, record };\n }\n\n /**\n * Hand a live run to the background without restarting it. The session,\n * promise, in-flight turn, transcript and worktree all continue under the\n * same id; what changes is who answers for it. The caller's parent-abort\n * listener comes off (its Esc no longer reaches the run \u2014 `abort()` and\n * `/agents` still do), the slot moves to the background pool, and the run\n * then settles through the ordinary background path, since `settleRun`\n * reads the live `isBackground` and `chargedPool`.\n *\n * Releasing the caller is the caller's job \u2014 the `Agent` tool races its own\n * wake-up against `spawnAndWait`. This only refuses what it can see: a run\n * nobody is blocking on (a background or detached spawn, one already handed\n * off, or a foreground RESUME \u2014 `blocking` is cleared when the spawned run\n * settles, and a resume never charged the slot this would move), and one\n * that reports through something other than the session (a nested child, a\n * workflow's agent).\n *\n * The background slot is taken even when the pool is full: suspending a\n * live run is not an option, so it runs over the limit and queued\n * background work waits for the count to drop, as with `bypassQueue`.\n */\n sendToBackground(id: string): boolean {\n const record = this.agents.get(id);\n if (!record?.blocking || !isTopLevelAgent(record) || record.status !== \"running\" || !record.promise) return false;\n\n this.detachParentAbort(record);\n this.chargePool(record.chargedPool, -1);\n record.chargedPool = \"background\";\n this.chargePool(record.chargedPool, 1);\n record.blocking = false;\n record.isBackground = true;\n record.resultConsumed = false;\n // A freed foreground slot may have unblocked a queued blocking spawn.\n this.drainQueue();\n return true;\n }\n\n /**\n * Resume an existing agent session with a new prompt.\n */\n async resume(\n id: string,\n prompt: string,\n signal?: AbortSignal,\n options?: ResumeOptions,\n ): Promise<AgentRecord | undefined> {\n const record = this.agents.get(id);\n if (!record?.session) return undefined;\n\n // Never re-enter a run that is still in flight, on either path. Starting a\n // second run would overwrite record.abortController \u2014 orphaning the live\n // run beyond the reach of `/agents` stop and abortAll() \u2014 take a second\n // pool slot and budget lease, and then reject from session.prompt() with\n // \"Agent is already processing\", whose settle path would abort the LIVE\n // run's children and report a failure for a run that is still going. A\n // detached resume makes this easy to hit (the caller gets control back\n // while the record stays \"running\"), and parallel tool calls make it\n // possible inline. Checked before anything below mutates the record, and\n // both paths flip the status synchronously, so a second call made in the\n // same tick is refused too. The caller decides whether to wait or steer.\n if (record.status === \"running\" || record.status === \"queued\") return undefined;\n // Decided per run: a resume after the parent left Plan gets its full surface back.\n // `spawn` sets `planQuery` on every record this manager holds.\n this.decidePlanGate(record, record.planQuery!);\n\n // Background resume: settle asynchronously and notify on completion exactly\n // like a background spawn, returning immediately with the record still\n // \"running\" \u2014 or \"queued\" when at the concurrency limit. Previously\n // run_in_background was ignored on resume (the Agent tool's resume branch\n // returned before its background branch, and resume() only ever awaited\n // inline), so a resumed agent always blocked the caller until it finished.\n if (options?.isBackground) {\n // The pool it will be charged to once `isBackground` is set below; asked\n // before anything mutates the record, so a refusal leaves it untouched.\n const pool: Pool | undefined = occupiesPoolSlot({ ...record, isBackground: true }) ? \"background\" : undefined;\n const lease = this.admit(record, pool);\n\n record.isBackground = true;\n record.resultConsumed = false;\n record.noticeDelivered = undefined;\n record.ranThisRun = false;\n record.consumedAt = undefined;\n record.result = undefined;\n record.error = undefined;\n record.completedAt = undefined;\n record.status = \"queued\";\n\n // `startResume` throws only from the `onStart` callback, after it has\n // charged the pool and with the lease held: hand both back and leave the\n // record an error rather than \"running\" forever.\n const start = () => {\n try {\n this.startResume(id, record, prompt, signal, options);\n } catch (err) {\n if (occupiesPoolSlot(record)) this.runningBackground--;\n this.releaseLease(record);\n record.status = \"error\";\n record.error = errorMessage(err);\n record.completedAt = this.clock.now();\n this.drainQueue();\n throw err;\n }\n };\n if (lease === undefined) {\n // At a limit \u2014 queue it, started when a slot and a lease free up. A\n // detached resume has no inline caller, hence nothing to release. The\n // queue is shared with spawns, whose startup is async, so entries are\n // promise-shaped even though a resume starts synchronously; a failure\n // is reported here, since the budget pump swallows throws.\n this.enqueueStart(id, record, pool, async () => {\n try {\n start();\n } catch {\n this.onComplete?.(record);\n }\n }, () => {});\n } else {\n record.budgetLease = lease;\n start();\n }\n return record;\n }\n\n // Foreground resume: run inline and return the settled record. Takes a\n // budget lease like everything else, waiting for one if the process is at\n // its limit; the caller's signal (or `/agents` stop) releases the wait.\n // No pool: the foreground pool does not cover resumes (see the README).\n const lease = this.admit(record, undefined);\n record.ranThisRun = false;\n record.noticeDelivered = undefined;\n record.status = lease === undefined ? \"queued\" : \"running\";\n record.budgetLease = lease;\n record.startedAt = this.clock.now();\n record.completedAt = undefined;\n record.result = undefined;\n record.error = undefined;\n // Fresh controller, as on the detached path: `abort()` fires whatever\n // `record.abortController` holds, and the spawn's has long settled \u2014 so a\n // stop from `/agents` or the caller's Esc would mark the record stopped\n // while the resumed prompt ran on to completion.\n const abortController = new AbortController();\n record.abortController = abortController;\n this.armParentAbort(record, signal);\n // `addEventListener` never fires on a signal that is already aborted, and\n // the runner skips the prompt only when ITS signal is \u2014 stop now, so that\n // holds for a resume issued on a call that was cancelled first. On a\n // record still waiting for a lease this stops it outright.\n if (signal?.aborted) this.abort(id);\n\n if (lease === undefined) {\n // The queue entry's `start` only marks the record running: the run itself\n // stays inline below, so the caller awaits the same `resumeAgent` call\n // as an unqueued resume, and the lease the grant handed over is released\n // by the same tail. `granted` tells a grant from a removal (abort,\n // dispose), which resolves the same promise.\n let granted = false;\n if (record.status === \"queued\") {\n await new Promise<void>(resolve => {\n this.enqueueStart(id, record, undefined, async () => {\n granted = true;\n record.status = \"running\";\n record.startedAt = this.clock.now();\n }, resolve);\n });\n }\n // Removed while it waited: it never ran, so there is nothing to settle.\n // `abort` already marked it stopped; `dispose` and `detach` did not.\n if (!granted) {\n if (record.status === \"queued\") {\n record.status = \"stopped\";\n record.completedAt = this.clock.now();\n }\n markConsumed(record, this.clock.now());\n this.detachParentAbort(record);\n return record;\n }\n }\n\n try {\n // Positive evidence for the reap notice: only a live signal means the prompt runs.\n record.ranThisRun = record.status === \"running\";\n this.settleOutcome(record, await resumeAgent(record.session, prompt, {\n clock: this.clock,\n type: record.type,\n maxTurns: options?.maxTurns ?? record.invocation?.maxTurns,\n onTurnEnd: options?.onTurnEnd,\n onTextDelta: options?.onTextDelta,\n onModelCall: options?.onModelCall,\n onToolActivity: (activity) => {\n if (activity.type === \"end\") record.toolUses++;\n options?.onToolActivity?.(activity);\n },\n onAssistantUsage: (usage, message) => {\n relabelFromResponse(record, message);\n addUsage(record.lifetimeUsage, usage);\n this.onUsage?.(record, usage);\n options?.onAssistantUsage?.(usage);\n },\n onCompaction: (info) => {\n record.compactionCount++;\n this.onCompact?.(record, info);\n options?.onCompaction?.(info);\n },\n signal: abortController.signal,\n }));\n } catch (err) {\n this.failResume(record, err);\n }\n this.detachParentAbort(record);\n // The caller gets the settled record inline, whatever the outcome.\n markConsumed(record, this.clock.now());\n\n // Same contract as the spawn settle paths: children spawned during the\n // resumed turn must not outlive it \u2014 nothing else can see or reach them.\n this.abortOwnedChildren(id);\n\n this.releaseLease(record);\n this.drainQueue();\n return record;\n }\n\n /**\n * Write a run's outcome onto its record \u2014 a spawn's or a resume's, with one\n * precedence: an external stop keeps \"stopped\"; a hard abort (turn limit +\n * grace) is \"aborted\"; a failed final turn (a provider error pi resolved\n * instead of rejecting, #144) is an \"error\", not a completion with an empty\n * or stale result; otherwise \"steered\" or \"completed\". The run's text stays\n * available in every case.\n */\n private settleOutcome(\n record: AgentRecord,\n { text, failure, aborted, steered }: Awaited<ReturnType<typeof resumeAgent>>,\n ): void {\n if (record.status !== \"stopped\") {\n if (aborted) {\n record.status = \"aborted\";\n } else if (failure) {\n record.status = \"error\";\n record.error = failure;\n } else {\n record.status = steered ? \"steered\" : \"completed\";\n }\n }\n record.result = text;\n record.completedAt ??= this.clock.now();\n }\n\n /** A resume whose runner rejected: an error, unless an external stop got there first. */\n private failResume(record: AgentRecord, err: unknown): void {\n if (record.status !== \"stopped\") {\n record.status = \"error\";\n record.error = errorMessage(err);\n }\n record.completedAt ??= this.clock.now();\n }\n\n /**\n * Start a background resume run: detached, settling and notifying like\n * startAgent's background path. Invoked immediately, or from drainQueue when\n * a concurrency slot frees. The session already exists (resume reuses it), so\n * there is no onSessionCreated to hang per-run wiring off \u2014 callers use\n * `options.onStarted`, which fires on both the immediate and the drained path.\n */\n private startResume(\n id: string,\n record: AgentRecord,\n prompt: string,\n parentSignal: AbortSignal | undefined,\n options: ResumeOptions,\n ) {\n if (!record.session) {\n this.releaseLease(record);\n this.drainQueue();\n return;\n }\n\n record.status = \"running\";\n record.startedAt = this.clock.now();\n if (occupiesPoolSlot(record)) this.runningBackground++;\n this.onStart?.(record);\n\n // Fresh abort controller so /agents stop and steering target THIS run rather\n // than the previous one's settled controller.\n const abortController = new AbortController();\n record.abortController = abortController;\n // Optional, and NOT what the Agent tool passes for a detached resume: a\n // parent signal aborts on the parent's own interrupt (user Esc), which is\n // right for a foreground run whose result the caller is awaiting, and wrong\n // for a detached one \u2014 background spawns omit it for exactly this reason.\n let detachParentSignal: (() => void) | undefined;\n if (parentSignal) {\n const onParentAbort = () => this.abort(id);\n parentSignal.addEventListener(\"abort\", onParentAbort, { once: true });\n detachParentSignal = () => parentSignal.removeEventListener(\"abort\", onParentAbort);\n }\n\n // Per-run side effects (output streaming) \u2014 see ResumeOptions.onStarted.\n // After the record is in its running shape, before the run is kicked off.\n try { options.onStarted?.(); } catch { /* ignore caller wiring errors */ }\n\n const settle = () => {\n detachParentSignal?.();\n detachParentSignal = undefined;\n // Final flush of streaming output file\n if (record.outputCleanup) {\n try { record.outputCleanup(); } catch { /* ignore */ }\n record.outputCleanup = undefined;\n }\n // Children spawned during the resumed turn must not outlive it.\n this.abortOwnedChildren(id);\n if (occupiesPoolSlot(record)) this.runningBackground--;\n this.releaseLease(record);\n try { this.onComplete?.(record); } catch { /* ignore completion side-effect errors */ }\n this.drainQueue();\n };\n\n record.ranThisRun = true;\n const promise = resumeAgent(record.session, prompt, {\n clock: this.clock,\n type: record.type,\n maxTurns: options.maxTurns ?? record.invocation?.maxTurns,\n onTurnEnd: options.onTurnEnd,\n onTextDelta: options.onTextDelta,\n onModelCall: options.onModelCall,\n onToolActivity: (activity) => {\n if (activity.type === \"end\") record.toolUses++;\n options.onToolActivity?.(activity);\n },\n onAssistantUsage: (usage, message) => {\n relabelFromResponse(record, message);\n addUsage(record.lifetimeUsage, usage);\n this.onUsage?.(record, usage);\n options.onAssistantUsage?.(usage);\n },\n onCompaction: (info) => {\n record.compactionCount++;\n this.onCompact?.(record, info);\n options.onCompaction?.(info);\n },\n signal: abortController.signal,\n })\n .then((outcome) => {\n this.settleOutcome(record, outcome);\n settle();\n return outcome.text;\n })\n .catch((err) => {\n this.failResume(record, err);\n settle();\n return \"\";\n });\n\n record.promise = promise;\n }\n\n /**\n * Send a steering message to an agent from the UI (mirrors the steer_subagent\n * tool). A live session delivers it now \u2014 it interrupts the agent after its\n * current tool execution and appears as a user message. If the session isn't\n * ready yet, the message is queued on `pendingSteers` and flushed when the\n * session is created. Returns false if the agent can't accept steering\n * (unknown id, or no longer running/queued). Fires `onSteered` on either\n * accepted path, so the UI viewers, an `@handle` and the RPC all report\n * the steer the same way without each emitting by hand. The steer tools\n * bypass this method because they await delivery.\n */\n steer(id: string, message: string): boolean {\n const record = this.agents.get(id);\n if (!record) return false;\n if (record.status !== \"running\" && record.status !== \"queued\") return false;\n if (record.session) {\n record.session.steer(message).catch(() => {});\n } else {\n if (!record.pendingSteers) record.pendingSteers = [];\n record.pendingSteers.push(message);\n }\n this.onSteered?.(record, message);\n return true;\n }\n\n getRecord(id: string): AgentRecord | undefined {\n return this.agents.get(id);\n }\n\n /**\n * Handles held outside this manager, e.g. by live survivors of an orphaned one, which a fresh\n * spawn must not reuse: a listener keys lifecycle events by handle, so a twin would mix the two up.\n */\n reservedHandles: () => Iterable<string> = () => [];\n\n /** Handles already in use, so a fresh spawn can pick an unclaimed one. */\n private takenHandles(): Set<string> {\n const taken = new Set<string>(this.reservedHandles());\n for (const record of this.agents.values()) {\n if (record.handle) taken.add(record.handle);\n if (record.alias) taken.add(record.alias);\n }\n // Tombstones hold their names too: an evicted `@explore` is still\n // resurrectable, so a later Explore must become `explore-2` rather than\n // shadowing a conversation the user can still reach.\n for (const entry of this.tombstones.values()) {\n taken.add(entry.handle);\n if (entry.alias) taken.add(entry.alias);\n }\n return taken;\n }\n\n /**\n * Resolve an `@name` from the prompt. Matches a top-level agent's handle or\n * alias case-insensitively, then falls back to an exact agent id so\n * `@<agentId>` works too.\n */\n resolveMention(name: string): MentionResolution | undefined {\n const wanted = name.toLowerCase();\n for (const record of this.agents.values()) {\n if (record.parentAgentId !== undefined) continue;\n // Handle and alias share one lowercase namespace (`takenHandles`, and a\n // reopen reclaims the evicted record's own names), so at most one agent\n // answers a name and it makes no difference which of the two matched.\n if (record.handle === wanted || record.alias === wanted) return { kind: \"live\", record };\n }\n const byId = this.agents.get(name);\n if (byId?.parentAgentId === undefined && byId !== undefined) return { kind: \"live\", record: byId };\n // Only once nothing live answers: a tombstone is a conversation to reopen,\n // and reopening one while its record still exists would fork the session.\n for (const entry of this.tombstones.values()) {\n if (entry.handle.toLowerCase() === wanted || entry.alias?.toLowerCase() === wanted || entry.id === name) {\n return { kind: \"tombstone\", entry };\n }\n }\n return undefined;\n }\n\n /**\n * Forget an evicted agent, by handle. For the case where its session file has\n * gone: the entry can then only ever fail, while still holding the name\n * against the type that would otherwise start a fresh agent under it.\n *\n * A *successful* resume does not drop its tombstone \u2014 the live record it\n * creates already wins in `resolveMention`, and overwrites the entry in place\n * when it is itself evicted.\n */\n dropTombstone(handle: string): void {\n this.tombstones.delete(handle);\n }\n\n /** Evicted agents whose conversation can still be reopened, newest first. */\n listTombstones(): AgentTombstone[] {\n return [...this.tombstones.values()].sort((a, b) => b.completedAt - a.completedAt);\n }\n\n listAgents(): AgentRecord[] {\n return [...this.agents.values()].sort(\n (a, b) => b.startedAt - a.startedAt,\n );\n }\n\n /**\n * Stop a running or queued agent; false when it was neither.\n *\n * @param by `\"parent\"` when the agent that spawned it asked (`stop_subagent`);\n * omitted for a human stop. Written on every stop, so a resumed record never\n * carries an earlier run's answer.\n */\n abort(id: string, by?: AgentRecord[\"stoppedBy\"]): boolean {\n const record = this.agents.get(id);\n if (!record) return false;\n\n // Remove from queue if queued. No decrement \u2014 the slot was never taken \u2014\n // and no onComplete, matching what a queued background abort has always\n // done; a blocking caller learns of the stop from its own tool result.\n if (record.status === \"queued\") {\n this.dequeue(q => q.id === id);\n record.stoppedBy = by;\n this.stopQueued(record);\n return true;\n }\n\n if (record.status !== \"running\") return false;\n // Before the abort: the run settles asynchronously and its notice reads this.\n record.stoppedBy = by;\n record.abortController?.abort();\n record.status = \"stopped\";\n record.completedAt = this.clock.now();\n return true;\n }\n\n /** Mark a dequeued record stopped and tell `onQueuedStop`; the queue entry is already gone. */\n private stopQueued(record: AgentRecord): void {\n record.status = \"stopped\";\n record.completedAt = this.clock.now();\n this.onQueuedStop?.(record);\n }\n\n /** Dispose a record's session and remove it from the map. */\n private removeRecord(id: string, record: SettledRecord): void {\n this.tombstone(record);\n this.noteEviction(record);\n const session = record.session;\n // Detached before the shutdown starts, so the record leaves the map at once and\n // nothing can observe a session that is half torn down.\n record.session = undefined;\n this.agents.delete(id);\n // A failed startup keeps its (rejected) entry so a late awaitStartup still\n // sees it; drop it with the record so the map can't grow unbounded.\n this.startups.delete(id);\n // Fire-and-forget is right here and only here: this runs from the 60s cleanup timer\n // and from `clearCompleted()` on session boundaries, with the process staying alive,\n // so handlers get their full window. The quit path awaits instead \u2014 see dispose().\n void shutdownChildSession(session);\n }\n\n /**\n * Preserve enough of a departing record for `@handle` to reopen its\n * conversation later. Nothing to keep unless it has both a handle to be\n * addressed by and a session file to reopen \u2014 an in-memory session leaves no\n * transcript, so the mention would have nothing to continue from.\n */\n private tombstone(record: SettledRecord): void {\n const entry = this.tombstoneOf(record);\n if (entry) this.storeTombstone(entry);\n }\n\n /** What `@handle` needs to reopen `record`'s conversation; undefined without a handle and a session file. */\n private tombstoneOf(record: SettledRecord): AgentTombstone | undefined {\n if (!record.handle || !record.sessionFile) return undefined;\n return {\n handle: record.handle,\n alias: record.alias,\n id: record.id,\n type: record.type,\n description: record.description,\n sessionFile: record.sessionFile,\n completedAt: record.completedAt,\n ...(record.modelTier ? { modelTier: record.modelTier } : {}),\n ...(record.modelFallback ? { modelFallback: record.modelFallback } : {}),\n };\n }\n\n /** Tombstones for whichever of `ids` are settled here and reopenable, to hand to a session that will never see these records. */\n evictionTombstones(ids: readonly string[]): AgentTombstone[] {\n return [...this.agents.values()]\n .filter(isSettled)\n .filter(record => isTopLevelAgent(record) && ids.includes(record.id))\n .flatMap(record => this.tombstoneOf(record) ?? []);\n }\n\n /**\n * Keep `entry` reopenable by handle, alias and id. Also how an agent that settled in an\n * orphaned manager (`/new`, `/reload`) stays reopenable here (#330). A name already held\n * by another live agent, an evicted conversation or a handle reserved for another manager's\n * survivor stays with its holder (as `takenHandles` has it): two conversations must not\n * answer to one `@name`. The entry is then not kept and its note says why.\n */\n rememberTombstone(entry: AgentTombstone): void {\n const names = [entry.handle, ...(entry.alias ? [entry.alias] : [])];\n const reserved = new Set<string>(this.reservedHandles());\n const owns = (own: { id: string; handle?: string; alias?: string }, name: string) =>\n own.id !== entry.id && (name === own.handle || name === own.alias);\n const taken = names.find(\n name =>\n reserved.has(name) ||\n [...this.agents.values()].some(own => owns(own, name)) ||\n [...this.tombstones.values()].some(own => owns(own, name)),\n );\n if (taken !== undefined) {\n const note = this.evictedNotes.get(entry.id);\n if (note) note.nameTaken = taken;\n return;\n }\n this.storeTombstone(entry);\n }\n\n private storeTombstone(entry: AgentTombstone): void {\n this.tombstones.set(entry.handle, entry);\n // Bound the memory a long session can accumulate. Oldest first, since the\n // agent someone still wants to reach is the one they used most recently.\n while (this.tombstones.size > MAX_TOMBSTONES) {\n const oldest = [...this.tombstones.values()].reduce((a, b) => (a.completedAt <= b.completedAt ? a : b));\n this.tombstones.delete(oldest.handle);\n }\n }\n\n /** Remember that `record` existed, so its id still answers with something better than \"not found\". */\n private noteEviction(record: SettledRecord): void {\n // Only the top-level tools read notes, and an owned child (nested or a\n // workflow's) must stay unreachable from them after eviction as before it.\n if (!isTopLevelAgent(record)) return;\n this.rememberEvicted(this.evictionNote(record));\n }\n\n /** Notes for whichever of `ids` are settled here, to hand to a session that will never see these records. */\n evictionNotes(ids: readonly string[]): EvictedNote[] {\n return [...this.agents.values()].filter(isSettled).filter(record => isTopLevelAgent(record) && ids.includes(record.id)).map(record => this.evictionNote(record));\n }\n\n /** What a settled record leaves behind once it is gone from this manager. */\n private evictionNote(record: SettledRecord): EvictedNote {\n return {\n id: record.id,\n type: record.type,\n description: record.description,\n status: record.status,\n evictedAfterMin: Math.max(0, Math.round((this.clock.now() - record.completedAt) / 60_000)),\n transcript: record.outputFile ?? record.sessionFile,\n ...(record.modelTier ? { modelTier: record.modelTier } : {}),\n ...(record.modelFallback ? { modelFallback: record.modelFallback } : {}),\n };\n }\n\n /**\n * Keep `note` addressable by its id, bounded by age. Also how a result handed\n * over by an orphaned manager (`/new`, `/reload`) stays answerable here: the\n * record settled in a manager this one never saw (#330).\n */\n rememberEvicted(note: EvictedNote): void {\n this.evictedNotes.delete(note.id);\n this.evictedNotes.set(note.id, note);\n // Insertion order is age order (the note was just re-inserted above).\n for (const oldest of this.evictedNotes.keys()) {\n if (this.evictedNotes.size <= MAX_EVICTED_NOTES) break;\n this.evictedNotes.delete(oldest);\n }\n }\n\n /** Record that evicted `id` was reopened as `next`; bounded like the eviction notes. */\n linkSuccessor(id: string, next: string): void {\n this.successors.delete(id);\n this.successors.set(id, next);\n // One link per call, so at most one over the bound: drop the oldest.\n if (this.successors.size > MAX_EVICTED_NOTES) this.successors.delete(this.successors.keys().next().value as string);\n }\n\n /** Forget a reopen that never started, so `id` resolves to its tombstone again. */\n unlinkSuccessor(id: string): void {\n this.successors.delete(id);\n }\n\n /** The newest id `id` continues under, following every reopen; `id` itself when never reopened. */\n latestId(id: string): string {\n // Acyclic: every successor is a freshly generated id.\n let current = id;\n for (let next = this.successors.get(current); next !== undefined; next = this.successors.get(current)) current = next;\n return current;\n }\n\n /** What became of an evicted agent, by id; undefined for an id this session never evicted. */\n getEvictedNote(id: string): EvictedNote | undefined {\n return this.evictedNotes.get(id);\n }\n\n /**\n * Evict finished records past their window: 10 minutes from the moment the\n * result was consumed, 60 from completion while nobody has read it. A consumed\n * record with no stamp (set directly, not through `markConsumed`) is aged from\n * completion.\n */\n private cleanup() {\n const now = this.clock.now();\n for (const [id, record] of this.agents) {\n if (!isSettled(record)) continue;\n const { completedAt } = record;\n const expired = record.resultConsumed\n ? now - (record.consumedAt ?? completedAt) >= this.consumedTtlMs\n : now - completedAt >= this.unreadTtlMs;\n if (!expired) continue;\n const ran = record.ranThisRun === true && (record.result !== undefined || record.error !== undefined);\n this.removeRecord(id, record);\n // Evicting a result nobody read is a loss the parent must hear about. Owned\n // children never leave a note, and only their owner could have read them.\n // Nothing was lost when the parent saw the completion notice (a failure's\n // stays unread in FleetView), or when no run produced a result (stopped in\n // the queue, refused, or failed before the runner started).\n const note = record.resultConsumed || record.noticeDelivered || !ran ? undefined : this.evictedNotes.get(id);\n if (note) this.onReaped?.(note);\n }\n }\n\n /**\n * Remove all completed/stopped/errored records immediately.\n * Called on session start/switch so tasks from a prior session don't persist.\n * Pass skipUnconsumed=true to preserve records the LLM hasn't read yet\n * (resultConsumed=false) \u2014 they will be evicted by the cleanup timer instead (60 minutes).\n */\n clearCompleted(skipUnconsumed = false): void {\n for (const [id, record] of this.agents) {\n if (!isSettled(record)) continue;\n if (skipUnconsumed && !record.resultConsumed) continue;\n this.removeRecord(id, record);\n }\n // Unconditional: both callers are session boundaries (`session_start` and\n // `session_before_switch`), and `skipUnconsumed` only spares records whose\n // results the LLM has yet to read \u2014 it does not make the sweep partial in\n // the sense that matters here. A new session means new handles, or\n // `@explore` would silently reach an agent the user never started. Claude\n // Code resets its registry on `/clear` for the same reason.\n this.tombstones.clear();\n // Ids are only meaningful within the session that issued them.\n this.evictedNotes.clear();\n this.successors.clear();\n }\n\n /** Whether any agents are still running or queued. */\n hasRunning(): boolean {\n return [...this.agents.values()].some(\n r => r.status === \"running\" || r.status === \"queued\",\n );\n }\n\n /**\n * The session's own agents (see `isTopLevelAgent`) still running or queued,\n * split by whether their completion wakes the parent. A background agent's\n * settle sends a completion notice that starts a turn, in every join mode;\n * a foreground one, or an RPC spawn that omits `isBackground`, is marked\n * consumed at settle and notifies nobody. Owned children report through their owner, so counting\n * them would double-count the same work.\n */\n ownedPending(): OwnedPending {\n const pending = [...this.agents.values()].filter(\n r => isTopLevelAgent(r) && (r.status === \"running\" || r.status === \"queued\"),\n );\n const notifying = pending.filter(r => r.isBackground).length;\n return { notifying, silent: pending.length - notifying };\n }\n\n /**\n * Abort everything that cannot outlive its session and let the rest finish.\n * Survivors are running top-level background agents and their nested children:\n * they own their own session and report through a notification. Queued agents\n * would start later against a stale context, foreground agents belong to a\n * tool call that is being torn down, and workflow children die with their\n * workflow, so all of those are aborted. A QUEUED nested child is kept: its\n * parent is a survivor waiting on it (the process budget can queue one), and\n * if the parent is stopped instead, its settle aborts the child.\n *\n * @returns how many agents keep running.\n */\n detach(): number {\n const keepQueued = ({ record }: QueueEntry): boolean =>\n record.parentAgentId !== undefined && record.workflowId === undefined;\n const dropped = this.queue.filter(entry => !keepQueued(entry)).map(({ record }) => record);\n this.dequeue(entry => !keepQueued(entry));\n for (const record of dropped) this.stopQueued(record);\n let survivors = 0;\n for (const record of this.agents.values()) {\n if (record.status !== \"running\") continue;\n const outlives = record.workflowId === undefined && (!!record.isBackground || record.parentAgentId !== undefined);\n if (outlives) {\n survivors++;\n continue;\n }\n record.abortController?.abort();\n record.status = \"stopped\";\n record.completedAt = this.clock.now();\n }\n return survivors;\n }\n\n /** Abort all running and queued agents immediately. */\n abortAll(): number {\n let count = 0;\n // Clear queued agents first\n const dropped = this.queue.map(({ record }) => record);\n this.dequeue(() => true);\n for (const record of dropped) {\n this.stopQueued(record);\n count++;\n }\n // Abort running agents\n for (const record of this.agents.values()) {\n if (record.status === \"running\") {\n record.abortController?.abort();\n record.status = \"stopped\";\n record.completedAt = this.clock.now();\n count++;\n }\n }\n return count;\n }\n\n /** Wait for all running and queued agents to complete (including queued ones). */\n async waitForAll(): Promise<void> {\n // Loop because drainQueue respects the concurrency limit \u2014 as running\n // agents finish they start queued ones, which need awaiting too.\n while (true) {\n this.drainQueue();\n const pending: Promise<unknown>[] = [];\n for (const record of this.agents.values()) {\n if (record.status !== \"running\" && record.status !== \"queued\") continue;\n // An agent whose worktree is still being created is \"running\" with no\n // `promise` yet \u2014 without its startup the wait would return too early.\n const startup = this.startups.get(record.id);\n if (startup) pending.push(startup);\n if (record.promise) pending.push(record.promise);\n }\n // A queued start may be waiting on another manager's leases, with\n // nothing in this one to wait on: wait for it to leave the queue.\n for (const entry of this.queue) pending.push(entry.left);\n if (pending.length === 0) break;\n await Promise.allSettled(pending);\n }\n }\n\n /**\n * @param pi - Needed to run `git worktree prune`, which is async now and so\n * cannot be reached through a stored spawn argument at shutdown. Omitting\n * it (tests, teardown of a manager that never spawned) skips the prune.\n */\n async dispose(pi?: ExtensionAPI): Promise<void> {\n this.cleanupInterval.cancel();\n // Clear queue \u2014 via dequeue, so anyone blocked in spawnAndWait is woken\n // rather than left awaiting a gate nothing will ever resolve.\n this.dequeue(() => true);\n const sessions = [...this.agents.values()].map(record => record.session);\n this.agents.clear();\n this.startups.clear();\n if (pi) {\n // Prune any orphaned git worktrees (crash recovery). Detached: dispose runs\n // on the shutdown path, which cannot wait for git. Started before the awaited\n // shutdown below rather than after it, so the git calls have that window to\n // finish in instead of racing the process exit that follows.\n const prune = (repo: string) => { pruneWorktrees(pi, repo).catch(() => {}); };\n prune(process.cwd());\n // Also prune repos that caller-supplied cwds created worktrees in \u2014 a clean\n // exit with in-flight agents would otherwise leave stale registrations there.\n for (const repo of this.worktreeRepos) prune(repo);\n }\n // Awaited, unlike the eviction path: pi awaits this extension's `session_shutdown`\n // handler and the process exits right after it returns, so anything left unawaited\n // here never runs at all. Bounded \u2014 each call carries its own ceiling, concurrently.\n await Promise.all(sessions.map(session => shutdownChildSession(session)));\n // Leases are NOT released here. `shutdownChildSession` is bounded and does\n // not wait for a run's promise, a worktree copy or its cleanup, so work can\n // still be going on; each run hands its lease back from its own settle\n // path (`settleRun`, the resume tails, the startup-failure and mid-copy\n // exits), which no longer needs this manager's maps. A run that never\n // settles keeps its slot, which is the honest count.\n this.drainQueue();\n }\n}\n", "/**\n * agent-runner.ts \u2014 Core execution engine: creates sessions, runs agents, collects results.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, isAbsolute, join, resolve } from \"node:path\";\nimport type { Model } from \"@earendil-works/pi-ai\";\nimport type { ExtensionContext, LoadExtensionsResult } from \"@earendil-works/pi-coding-agent\";\nimport {\n type AgentSession,\n type AgentSessionEvent,\n createAgentSession,\n createCodemodeExtension,\n createMcpExtension,\n createToolSearchExtension,\n type DefaultResourceLoader,\n defineTool,\n type ExtensionAPI,\n type InlineExtension,\n SessionManager,\n SettingsManager,\n} from \"@earendil-works/pi-coding-agent\";\nimport { Type } from \"typebox\";\nimport { BUILTIN_TOOL_NAMES, getAgentConfig, getConfig, getMemoryToolNames, getReadOnlyMemoryToolNames, getToolNamesForType } from \"./agent-types.js\";\nimport { bindChildResourceLoader, runInChildSessionContext } from \"./child-context.js\";\nimport { type Clock, realClock } from \"./clock.js\";\nimport { buildParentContext, extractText } from \"./context.js\";\nimport { DEFAULT_AGENTS } from \"./default-agents.js\";\nimport { detectEnv } from \"./env.js\";\nimport { normalizeHomePath, resolveAgentDir } from \"./home-paths.js\";\nimport { buildMemoryBlock, buildReadOnlyMemoryBlock } from \"./memory.js\";\nimport type { ModelCallEvent } from \"./model-call.js\";\nimport type { ModelFallback } from \"./model-resolver.js\";\nimport type { ModelSelection } from \"./model-selection.js\";\nimport {\n createNestedSubagentTools,\n getMaxSubagentDepth,\n hasNestableTypes,\n NESTED_WORKFLOW_ERROR,\n NESTED_WORKFLOW_NO_AGENT_ERROR,\n type NestedAgentManager,\n} from \"./nested-tools.js\";\nimport { type PlanGate, planGateReason } from \"./plan-mode-children.js\";\nimport { buildAgentPrompt, type PromptExtras } from \"./prompts.js\";\nimport { createHomeResourceLoader } from \"./resource-loader.js\";\nimport { preloadSkills } from \"./skill-loader.js\";\nimport { isStaleCtxError } from \"./stale-ctx.js\";\nimport { createStructuredCapture, createStructuredOutputTool, structuredRetryPrompt } from \"./structured-output.js\";\nimport type { SubagentType, ThinkingLevel } from \"./types.js\";\nimport type { LifetimeUsage } from \"./usage.js\";\nimport type { CompiledSchema } from \"./workflow/json-schema.js\";\n\n/**\n * Tool names registered by THIS extension. Single source of truth so the\n * registration sites (index.ts) and the subagent exclusion list below can't\n * drift apart. These are our own tools, not pi built-ins, so they can't be\n * derived from pi \u2014 but they only need defining once.\n */\nexport const SUBAGENT_TOOL_NAMES = {\n AGENT: \"Agent\",\n WORKFLOW: \"SubagentWorkflow\",\n GET_RESULT: \"get_subagent_result\",\n STEER: \"steer_subagent\",\n STOP: \"stop_subagent\",\n} as const;\n\n/**\n * Workflow tools, ours and other extensions', that must fail inside a subagent\n * with an explanation. The same names as `FOREIGN_WORKFLOW_TOOL_NAMES`, repeated\n * because that module imports this one.\n */\nconst BLOCKED_IN_SUBAGENT: ReadonlySet<string> = new Set([SUBAGENT_TOOL_NAMES.WORKFLOW, \"Workflow\", \"workflow\"]);\n\n/**\n * Stand-in for our own `SubagentWorkflow` in a child session, where the real\n * tool is excluded. Without it a call never reaches `beforeToolCall` (core\n * answers \"Tool SubagentWorkflow not found\" first), so the model gets no reason\n * and retries; a foreign `workflow` tool is loaded in the child and does get\n * one. The scope hook blocks the call with `NESTED_WORKFLOW_ERROR`; the throw\n * covers a session without that hook.\n */\nfunction createWorkflowRefusalTool(reason: string) {\n return defineTool({\n name: SUBAGENT_TOOL_NAMES.WORKFLOW,\n label: \"SubagentWorkflow\",\n description: \"Not available inside a subagent; calling it explains why.\",\n // Open object: whatever arguments the model sends, the refusal is the answer.\n parameters: Type.Object({}),\n execute: async () => {\n throw new Error(reason);\n },\n });\n}\n\n/** Names of tools registered by this extension that subagents must NOT inherit. */\nconst EXCLUDED_TOOL_NAMES: string[] = Object.values(SUBAGENT_TOOL_NAMES);\n\n/**\n * Canonical name of an extension for `extensions: [...]` allowlist matching.\n * Lowercased \u2014 extension names match case-insensitively so `extensions: [Mcp]`\n * resolves the same as `[mcp]`. Tool names within `ext:foo/bar` are not affected.\n * Directory extensions (`foo/index.ts`) resolve to the parent directory name;\n * single-file extensions to the basename minus `.ts`/`.js`.\n */\nexport function extensionCanonicalName(extPath: string): string {\n const base = basename(extPath);\n const name = base === \"index.ts\" || base === \"index.js\"\n ? basename(dirname(extPath))\n : base.replace(/\\.(ts|js)$/, \"\");\n return name.toLowerCase();\n}\n\n/**\n * The unscoped, lowercased npm short name of the pi package that DECLARES\n * `extPath` as an extension entry \u2014 or undefined if the entry doesn't belong to\n * such a package.\n *\n * Climbs from the entry's directory looking for the package that owns it, and\n * stays strictly within that package's tree by stopping at two structural\n * boundaries \u2014 no hardcoded depth:\n * - the FIRST `package.json` found (the package root); the entry's own\n * manifest always sits at the root, above the entry, below any node_modules.\n * - a `node_modules` directory: a package never spans one (it's where OTHER\n * packages live), so reaching it means we've climbed out of the package \u2014\n * stop before reading a consumer's or parent package's manifest.\n * The name is then taken only when that root's `pi.extensions` manifest actually\n * lists this entry, either as the file itself or as a directory pi resolves to\n * this `index.ts`/`index.js` (pi-web-access declares `./dist`). That \"declares this entry\" check is deliberate: our own test\n * fixtures live under this repo, whose root manifest declares `./src/index.ts`\n * as `@tintinweb/pi-subagents`, so a looser rule would misattribute every\n * co-located file to `pi-subagents`.\n */\nfunction extensionPackageName(extPath: string): string | undefined {\n // `builtin:<name>` names no file; climbing from it would read the process cwd's manifest.\n if (extPath.startsWith(\"builtin:\")) return undefined;\n const entry = resolve(extPath);\n const indexDir = /^index\\.(ts|js)$/.test(basename(entry)) ? dirname(entry) : undefined;\n let dir = dirname(extPath);\n for (;;) {\n // Climbing into node_modules means we've left the owning package's tree.\n if (basename(dir) === \"node_modules\") return undefined;\n let pkg: { name?: unknown; pi?: { extensions?: unknown } };\n try {\n pkg = JSON.parse(readFileSync(join(dir, \"package.json\"), \"utf-8\"));\n } catch {\n const parent = dirname(dir);\n if (parent === dir) return undefined; // walked to the filesystem root\n dir = parent;\n continue;\n }\n // First package.json wins \u2014 it's the package root; decide here.\n const entries = pkg.pi?.extensions;\n if (\n typeof pkg.name === \"string\" &&\n Array.isArray(entries) &&\n entries.some((e) => {\n if (typeof e !== \"string\") return false;\n const declared = resolve(dir, e);\n return declared === entry || declared === indexDir;\n })\n ) {\n const short = pkg.name.startsWith(\"@\") ? pkg.name.slice(pkg.name.indexOf(\"/\") + 1) : pkg.name;\n return short.toLowerCase();\n }\n return undefined;\n }\n}\n\n/**\n * All names an extension answers to for allowlist matching (lowercased): its\n * path-derived {@link extensionCanonicalName} plus, when a pi package manifest\n * declares this entry, that package's unscoped short name (`@scope/foo` \u2192 `foo`).\n * #143: an extension installed via `pi.extensions: [\"./src/index.ts\"]` would\n * otherwise only ever match as `src` (the source directory), never by its\n * package name. The path-derived name is preserved, so it keeps matching too.\n */\nexport function extensionCanonicalNames(extPath: string): string[] {\n const canonical = extensionCanonicalName(extPath);\n const pkg = extensionPackageName(extPath);\n return pkg && pkg !== canonical ? [canonical, pkg] : [canonical];\n}\n\n/**\n * Classify `extensions: string[]` frontmatter entries for the loader-level filter.\n *\n * An entry is a PATH iff it contains a path separator or starts with `~`; otherwise\n * it is a NAME. `\"*\"` sets the wildcard flag (keep all default-discovered extensions).\n *\n * Path entries are resolved (`~` expanded, made absolute against `cwd`) into `paths`\n * \u2014 and their canonical name is also added to `names`. The loader override matches\n * everything by canonical name, so path-loaded extensions are matched via their name\n * rather than their post-staging `Extension.path`.\n */\nexport function parseExtensionsSpec(\n entries: string[],\n cwd: string,\n homeDir = homedir(),\n): { names: Set<string>; paths: string[]; wildcard: boolean } {\n const names = new Set<string>();\n const paths: string[] = [];\n let wildcard = false;\n for (const entry of entries) {\n if (!entry) continue;\n if (entry === \"*\") {\n wildcard = true;\n continue;\n }\n const isPathEntry = entry.includes(\"/\") || entry.includes(\"\\\\\") || entry.startsWith(\"~\");\n if (!isPathEntry) {\n names.add(entry.toLowerCase());\n continue;\n }\n // This frontmatter caller historically expands both slash forms on every\n // platform, without interpreting file URLs or Windows shell drive forms.\n let p = entry;\n if (p === \"~\" || p.startsWith(\"~/\") || p.startsWith(\"~\\\\\")) p = homeDir + p.slice(1);\n const abs = isAbsolute(p) ? p : resolve(cwd, p);\n paths.push(abs);\n names.add(extensionCanonicalName(abs));\n }\n return { names, paths, wildcard };\n}\n\n/**\n * Parse raw `ext:` selector strings (from the `tools:` CSV) into the set of\n * extension names to keep loaded and a per-extension tool-narrowing map.\n *\n * `ext:foo` \u2192 `extNames` has `foo`, no narrowing entry (all of foo's tools).\n * `ext:foo/bar` \u2192 `extNames` has `foo`, `narrowing.foo` has `bar` (only `bar`).\n * A name lands in `narrowing` only when a `/tool` form is seen, so a bare\n * `ext:foo` alongside `ext:foo/bar` leaves narrowing in effect (narrowing wins).\n * The split is on the first `/`; extension canonical names never contain `/`.\n */\nexport function parseExtSelectors(entries: string[]): {\n extNames: Set<string>;\n narrowing: Map<string, Set<string>>;\n} {\n const extNames = new Set<string>();\n const narrowing = new Map<string, Set<string>>();\n for (const raw of entries) {\n if (!raw) continue;\n const body = raw.slice(\"ext:\".length);\n const slash = body.indexOf(\"/\");\n // Extension name matches case-insensitively (matches the loader-side canonical\n // name). Tool names are case-preserved \u2014 they're matched against pi-mono's\n // registered identifiers, which are case-sensitive.\n const name = (slash === -1 ? body : body.slice(0, slash)).trim().toLowerCase();\n if (!name) continue;\n extNames.add(name);\n if (slash === -1) continue;\n const tool = body.slice(slash + 1).trim();\n if (!tool) continue;\n let set = narrowing.get(name);\n if (!set) {\n set = new Set();\n narrowing.set(name, set);\n }\n set.add(tool);\n }\n return { extNames, narrowing };\n}\n\n/**\n * Keep a subagent's tool scope correct as extensions register tools over time.\n *\n * Extensions may call `registerTool` long after load \u2014 pi-mcp from `session_start`,\n * context-mode from `before_agent_start` \u2014 so scope has to be re-derived rather than\n * snapshotted. `registerTool` writes into the very `extension.tools` maps this reads,\n * so `inScope()` sees late arrivals on the next call.\n *\n * Two enforcement points, because neither covers the whole picture:\n *\n * - `turn_end` re-narrows the ACTIVE set. pi emits `turn_end` immediately before\n * `prepareNextTurn` re-snapshots `agent.state.tools`, and session listeners run\n * synchronously, so the narrow lands in time for turns 2..N.\n * - `beforeToolCall` blocks out-of-scope calls. Turn 1 cannot be narrowed at all:\n * `before_agent_start` fires INSIDE `prompt()` and may widen the tool set, but\n * `createContextSnapshot()` freezes that turn's tools immediately after \u2014 there\n * is no hook in between. A call-time check is the only correct guard there.\n *\n * Both are installed on the session and deliberately NOT unsubscribed: they must\n * outlive the `runAgent` call so resumed/steered turns stay scoped. pi's `dispose()`\n * clears `_eventListeners`, so they die with the session rather than leaking.\n *\n * Only meaningful when extensions are loaded \u2014 under `noExtensions`/`isolated` the\n * static `allowedToolNames` allowlist already gates the registry itself.\n */\nexport function installExtensionToolScope(\n session: AgentSession,\n ctx: {\n loader: DefaultResourceLoader;\n toolNames: string[];\n disallowedSet: Set<string> | undefined;\n extNames: Set<string>;\n narrowing: Map<string, Set<string>>;\n /**\n * Injected `customTools` to keep active regardless of the built-in list.\n *\n * Two kinds arrive here and they are blocked for different reasons: opt-in\n * nested-delegation tools share EXCLUDED_TOOL_NAMES' names, and\n * StructuredOutput is simply not a built-in, so neither survives a `keep`\n * seeded from `toolNames`.\n */\n readmitToolNames: Set<string>;\n /** Receives the scope check the child's nested-call gate extension applies. */\n nestedCallGate: NestedCallGate;\n /** Why workflow tools are refused. */\n workflowError: string;\n },\n): void {\n const { loader, toolNames, disallowedSet, extNames, narrowing, readmitToolNames, nestedCallGate, workflowError } = ctx;\n\n // The names allowed right now. Mirrors the `ext:` opt-in flip: when any `ext:`\n // selector is present, extension tools become an explicit allowlist \u2014 a loaded\n // extension not named by a selector contributes nothing (its handlers still ran),\n // and `ext:foo/bar` narrows `foo` to just `bar`.\n const inScope = (): Set<string> => {\n const keep = new Set(toolNames.filter((t) => !disallowedSet?.has(t)));\n const optInActive = extNames.size > 0;\n for (const extension of loader.getExtensions().extensions) {\n const canons = extensionCanonicalNames(extension.path);\n if (optInActive && !canons.some((c) => extNames.has(c))) continue;\n // First alias that carries a narrowing set \u2014 a user won't narrow one\n // extension under two different names, so first-match is correct.\n const narrowed = canons.map((c) => narrowing.get(c)).find(Boolean);\n for (const name of extension.tools.keys()) {\n if (narrowed && !narrowed.has(name)) continue;\n if (disallowedSet?.has(name)) continue;\n keep.add(name);\n }\n }\n for (const name of EXCLUDED_TOOL_NAMES) keep.delete(name);\n // Injected tools are legitimately active for this agent \u2014 re-admit them so\n // the renarrow keeps them in the active set and beforeToolCall doesn't\n // block them. Already vetted against `disallowed_tools` by the caller,\n // which is the only place that knows which kind may be taken back.\n for (const name of readmitToolNames) keep.add(name);\n return keep;\n };\n\n // Names this agent selects explicitly: its built-ins, injected tools, and\n // `ext:foo/bar` narrowings. pi activates a named tool even when it is\n // `defaultActive: false`, as `--tools` does.\n const named = new Set([...toolNames, ...readmitToolNames, ...[...narrowing.values()].flatMap((s) => [...s])]);\n\n // Activate what pi itself would: only tools declared to the model (`direct`/\n // `model-only` exposure), and of those only named ones or ones not opted out\n // with `defaultActive: false`. `codemode`/`deferred` tools (pi's MCP tools by\n // default) stay undeclared until their extension or `tool_search` activates\n // them \u2014 so an already-active tool is kept, or turn_end would undo that.\n const renarrow = () => {\n const allowed = inScope();\n const current = session.getActiveToolNames();\n const active = new Set(current);\n const next = session\n .getAllTools()\n .filter(({ name, exposure = \"direct\" }) => {\n if (!allowed.has(name)) return false;\n if (active.has(name)) return true;\n if (exposure !== \"direct\" && exposure !== \"model-only\") return false;\n return named.has(name) || session.getToolDefinition(name)?.defaultActive !== false;\n })\n .map((t) => t.name);\n // setActiveToolsByName unconditionally rebuilds the system prompt, so skip\n // the no-op that steady-state turns would otherwise pay for every turn.\n if (next.length !== current.length || next.some((n, i) => n !== current[i])) {\n session.setActiveToolsByName(next);\n }\n };\n\n // Activate what registered during session_start (eager MCP servers); pi would\n // otherwise leave only its four default built-ins active at turn 1.\n renarrow();\n\n session.subscribe((event: AgentSessionEvent) => {\n if (event.type === \"turn_end\") renarrow();\n });\n\n nestedCallGate.allows = (name) => inScope().has(name);\n\n const priorBeforeToolCall = session.agent.beforeToolCall;\n session.agent.beforeToolCall = async (context, signal) => {\n // Ahead of the scope check so a workflow tool registered by another\n // extension gets the reason, not \"not available\": it is loaded here like\n // any extension tool, and would otherwise run and report to a dead session.\n if (BLOCKED_IN_SUBAGENT.has(context.toolCall.name)) {\n return { block: true, reason: workflowError };\n }\n if (!inScope().has(context.toolCall.name)) {\n return {\n block: true,\n reason: `Tool \"${context.toolCall.name}\" is not available to this subagent.`,\n };\n }\n return priorBeforeToolCall?.(context, signal);\n };\n}\n\n/**\n * Set once the child's tool scope (and, while planning, its Plan check) is\n * installed; until then the gate admits everything.\n */\ntype NestedCallGate = {\n allows?: (name: string) => boolean;\n planReason?: (toolName: string, input: unknown, cwd: string) => string | undefined;\n};\n\n/**\n * Inline extension that applies the subagent's tool scope to calls a tool makes\n * through `ctx.executeTool()` \u2014 codemode scripts calling MCP tools. pi runs those\n * past extensions' `tool_call` handlers only, never `agent.beforeToolCall`, and\n * every registered `codemode`/`deferred` tool is callable there whether or not\n * it is in scope.\n */\nconst SCOPE_GATE_NAME = \"pi-subagents-scope\";\n\nfunction scopeGateExtension(gate: NestedCallGate): InlineExtension {\n return {\n name: SCOPE_GATE_NAME,\n hidden: true,\n factory: (ext) => {\n ext.on(\"tool_call\", (event, ctx) => {\n if (gate.allows?.(event.toolName) === false) {\n return { block: true, reason: `Tool \"${event.toolName}\" is not available to this subagent.` };\n }\n const reason = gate.planReason?.(event.toolName, event.input, ctx.cwd);\n return reason === undefined ? undefined : { block: true, reason };\n });\n },\n };\n}\n\n/** Default max turns. undefined = unlimited (no turn limit). */\nlet defaultMaxTurns: number | undefined;\n\n/** Normalize max turns. undefined or 0 = unlimited, otherwise minimum 1. */\nexport function normalizeMaxTurns(n: number | undefined): number | undefined {\n if (n == null || n === 0) return undefined;\n return Math.max(1, n);\n}\n\n/** Get the default max turns value. undefined = unlimited. */\nexport function getDefaultMaxTurns(): number | undefined { return defaultMaxTurns; }\n/** Set the default max turns value. undefined or 0 = unlimited, otherwise minimum 1. */\nexport function setDefaultMaxTurns(n: number | undefined): void { defaultMaxTurns = normalizeMaxTurns(n); }\n\n/**\n * The turn limit a run of `type` will actually enforce: an explicit value if the\n * caller supplied one, else the agent's own `max_turns`, else the project\n * default. `undefined` = unlimited.\n *\n * Exported because the widget's turn counter (`\u21BB3\u226420`) has to predict this\n * before the run starts, and a second copy of the expression would drift from\n * the one below that enforces it.\n */\nexport function resolveEffectiveMaxTurns(type: string, explicit?: number): number | undefined {\n return normalizeMaxTurns(explicit ?? getAgentConfig(type)?.maxTurns ?? defaultMaxTurns);\n}\n\n/**\n * Project default for `persist_session`, from the `rememberAgents` setting.\n * On by default: a persisted session is what lets `@handle` reopen an agent's\n * conversation after its record has been evicted, which is the whole point of\n * addressing an agent by a name that outlives one run. Per-agent frontmatter\n * still overrides it in both directions.\n */\nlet rememberAgents = true;\n\n/** Whether subagent sessions are persisted by default. */\nexport function getRememberAgents(): boolean { return rememberAgents; }\n/** Set whether subagent sessions are persisted by default. */\nexport function setRememberAgents(b: boolean): void { rememberAgents = b; }\n\n/** Additional turns allowed after the soft limit steer message. */\nlet graceTurns = 5;\n\n/** Get the grace turns value. */\nexport function getGraceTurns(): number { return graceTurns; }\n/** Set the grace turns value (minimum 1). */\nexport function setGraceTurns(n: number): void { graceTurns = Math.max(1, n); }\n\n/**\n * Sent as a tool-less turn when a turn cap or its grace wrap-up fired, so the\n * result is a report rather than whatever the agent last narrated before it\n * was cut off (\"Now let me check the tests...\").\n */\nconst FINAL_REPORT_PROMPT =\n \"You are out of turns and have no tools left. Do NOT call any tool or say what you would do next. \"\n + \"Write your complete final report now: everything you found, concrete file paths and line numbers, \"\n + \"what you changed or concluded, and anything unfinished or unverified.\";\n\n/** Info about a tool event in the subagent. */\nexport interface ToolActivity {\n type: \"start\" | \"end\";\n toolName: string;\n}\n\n/** Physical model identity carried by an assistant message. */\nexport interface AssistantMessageInfo {\n api?: string;\n provider?: string;\n model?: string;\n}\n\nexport interface RunOptions {\n /** Backoff before each stale-ctx re-prompt (#145); defaults to 1s, 3s, 9s. `[]` disables recovery. */\n staleRetryDelaysMs?: readonly number[];\n /** Clock that times the stale-ctx backoff; the manager passes its own. Defaults to native timers. */\n clock?: Clock;\n /** ExtensionAPI instance \u2014 used for pi.exec() instead of execSync. */\n pi: ExtensionAPI;\n /** Manager-assigned id; suffixes session name to disambiguate parallel spawns (e.g. `Explore#a1b2c3d4`). */\n agentId?: string;\n model?: Model<any>;\n /** Required admitted spawn outcome. The runner never resolves or admits models. */\n modelSelection: ModelSelection;\n maxTurns?: number;\n signal?: AbortSignal;\n /** Applies only when the agent file leaves `isolated:` unset \u2014 frontmatter is authoritative. */\n isolated?: boolean;\n inheritContext?: boolean;\n thinkingLevel?: ThinkingLevel;\n /**\n * Reopen this pi session file rather than starting an empty conversation.\n * `createAgentSession` seeds itself from whatever its SessionManager holds,\n * so pointing it at an existing file rehydrates that agent's history and the\n * prompt continues it. Everything else \u2014 tools, model, system prompt, turn\n * caps \u2014 is still resolved from the agent type, so the continuation runs\n * under the type's *current* definition, not the one the original run used.\n */\n resumeSessionFile?: string;\n /**\n * True when another agent spawned this one. Only top-level agents get a\n * handle, so only they can be reopened by name \u2014 which is the whole reason\n * `rememberAgents` persists a session at all. A nested run's transcript would\n * be unreachable by anything, so it stays in memory unless its own\n * frontmatter asks otherwise.\n */\n nested?: boolean;\n /**\n * True when a workflow run spawned this agent. Its final text is the value\n * `agent()` resolves to rather than a report a person reads, and the prompt\n * says so \u2014 but only when `structuredOutput` is unset, since that child\n * already has a `StructuredOutput` tool to answer through and two competing\n * \"this is how you return your answer\" instructions is worse than one.\n */\n workflow?: boolean;\n /** Override working directory (e.g. for worktree isolation). */\n cwd?: string;\n /** Home directory for tilde expansion and user-scoped storage. Defaults at run time. */\n homeDir?: string;\n /**\n * Directory the worktree copy was created from. Set only when `cwd` points\n * into a worktree \u2014 the prompt then tells the agent to stay in the copy\n * instead of following the inherited parent prompt back to the main tree.\n */\n worktreeBase?: string;\n /**\n * Where .pi config is discovered (project extensions, skills, pi settings,\n * agent memory). Default: same as the working directory. The manager sets\n * this to the parent session's cwd when `SpawnOptions.cwd` points the\n * working directory elsewhere \u2014 the agent works *there* but carries the\n * parent project's config (the target's `.pi` extensions never execute).\n *\n * WARNING for future callers: if you pass `cwd` pointing at a directory the\n * user didn't open, you almost certainly must pass `configCwd` too \u2014\n * omitting it makes the target's `.pi` extensions execute in this process.\n * (Worktree isolation is the one intentional exception: its copy IS the\n * parent's repo, so config resolving inside it is correct.)\n */\n configCwd?: string;\n /**\n * Project-trust decision for `configCwd`, inherited from the spawning session.\n * Honored only alongside an explicit `configCwd`: a nested spawn after a\n * custom-cwd spawn runs under a child ctx that deliberately reports its own\n * (execution) cwd as untrusted, so re-deriving from `ctx` would drop the\n * config root's trust. Never marks the execution cwd trusted.\n */\n configProjectTrusted?: boolean;\n /** Called on tool start/end with activity info. */\n onToolActivity?: (activity: ToolActivity) => void;\n /** Called on streaming text deltas from the assistant response. */\n onTextDelta?: (delta: string, fullText: string) => void;\n /** Called for every streaming event of each model call, so a UI can say what an in-flight call is doing. */\n onModelCall?: (event: ModelCallEvent) => void;\n onSessionCreated?: (session: AgentSession) => void;\n /** Direct runner callers can observe the same configured fallback as the shared spawn. */\n onModelFallback?: (fallback: ModelFallback) => void;\n /** Called at the end of each agentic turn with the cumulative count. */\n onTurnEnd?: (turnCount: number) => void;\n /**\n * Called once per assistant message_end with that message's usage delta.\n * Lets callers maintain a lifetime accumulator that survives compaction\n * (which replaces session.state.messages and resets stats-derived sums).\n *\n * `cost` is pi's own `usage.cost.total` for that message \u2014 priced from the\n * model's rates, so it is 0 (not missing) for a model pi has no pricing for.\n * We never price anything ourselves; every dollar figure this extension shows\n * or reports traces back to this field.\n */\n onAssistantUsage?: (usage: LifetimeUsage, message: AssistantMessageInfo) => void;\n /**\n * Called when the session successfully compacts. `tokensBefore` is upstream's\n * pre-compaction context size estimate. Aborted compactions don't fire.\n */\n onCompaction?: (info: { reason: \"manual\" | \"threshold\" | \"overflow\"; tokensBefore: number }) => void;\n /**\n * Make this child report through a `StructuredOutput` tool built from this\n * schema, and put the validated payload on {@link RunResult.structuredJson}.\n *\n * Already compiled by the caller, so a schema this runtime cannot validate\n * fails at the call that wrote it rather than inside the child.\n */\n structuredOutput?: CompiledSchema;\n /**\n * The Plan restriction for this child's runs (#437). Installed once on the\n * session and read per call; the manager sets `policy` per run.\n */\n planGate?: PlanGate;\n /** Runtime bridge for opt-in child-safe nested delegation. */\n nestedRuntime?: {\n manager: NestedAgentManager;\n parentAgentId: string;\n depth: number;\n maxSubagentDepth?: number;\n };\n}\n\nexport interface RunResult {\n responseText: string;\n session: AgentSession;\n /** True if the agent was hard-aborted (max_turns + grace exceeded). */\n aborted: boolean;\n /** True if the agent was steered to wrap up (hit soft turn limit) but finished in time. */\n steered: boolean;\n /**\n * A failure message for the run's FINAL assistant turn, when that turn failed:\n * a provider error (stopReason \"error\"), or a \"length\" stop that produced no\n * text (a silent max-token death). pi resolves an exhausted-retries failure\n * normally instead of rejecting, so without this the manager would report such\n * a run as completed \u2014 with an empty result, or worse, an earlier turn's text\n * presented as the answer (#144). Undefined for a clean stop, or a \"length\"\n * stop that produced text (a legitimate truncated answer).\n */\n failure?: string;\n /**\n * The validated `StructuredOutput` payload as canonical JSON, when the caller\n * asked for a schema and the child produced one.\n *\n * Deliberately not folded into {@link responseText}: `record.result` picks up\n * a worktree branch note on the way out, which would leave the caller with\n * unparseable JSON, and merging the two would make \"produced structured\n * output\" indistinguishable from \"happened to answer in JSON\".\n */\n structuredJson?: string;\n /** Whether the extra structured-output prompt had to be sent. */\n structuredRetried?: boolean;\n}\n\n/**\n * Subscribe to a session and collect the last assistant message text.\n * Returns an object with a `getText()` getter and an `unsubscribe` function.\n */\nfunction collectResponseText(session: AgentSession) {\n let text = \"\";\n let laterTool = false;\n let previousText = \"\";\n let previousLaterTool = false;\n const unsubscribe = session.subscribe((event: AgentSessionEvent) => {\n // message_start also fires for user and toolResult messages \u2014 resetting on\n // those would wipe assistant text already collected. Reset only when a new\n // ASSISTANT message begins, so getText() is the last assistant message's text.\n if (event.type === \"message_start\" && event.message.role === \"assistant\") {\n if (text.trim()) {\n previousText = text;\n previousLaterTool = laterTool;\n }\n text = \"\";\n laterTool = false;\n }\n if (event.type === \"message_update\" && event.assistantMessageEvent.type === \"text_delta\") {\n text += event.assistantMessageEvent.delta;\n }\n if (event.type === \"tool_execution_end\") {\n if (text.trim()) laterTool = true;\n else if (previousText.trim()) previousLaterTool = true;\n }\n });\n return { getText: () => text, getPreviousText: () => previousText, hasLaterTool: () => text.trim() ? laterTool : previousLaterTool, unsubscribe };\n}\n\n/**\n * Get the last non-empty assistant text produced during THIS invocation.\n * `startIndex` is the message count captured before the prompt, so the walk-back\n * never crosses into a previous turn: on a resume whose new turn failed empty,\n * this returns \"\" instead of the prior turn's answer (#144). A fresh spawn passes\n * 0, since the whole history belongs to that run.\n */\nfunction getLastAssistantText(session: AgentSession, startIndex: number): string {\n for (let i = session.messages.length - 1; i >= startIndex; i--) {\n const msg = session.messages[i];\n if (msg.role !== \"assistant\") continue;\n const text = extractText(msg.content).trim();\n if (text) return text;\n }\n return \"\";\n}\n\n/**\n * Translate a session event into the in-flight model call it belongs to. Only\n * assistant messages count; user and tool-result messages are not model calls.\n * Tool-call argument streaming counts as writing: the model is producing output.\n */\nexport function forwardModelCall(event: AgentSessionEvent, emit: (event: ModelCallEvent) => void): void {\n if (event.type === \"message_start\") {\n if (event.message.role === \"assistant\") emit({ type: \"start\" });\n } else if (event.type === \"message_end\") {\n if (event.message.role === \"assistant\") emit({ type: \"end\" });\n } else if (event.type === \"message_update\") {\n const e = event.assistantMessageEvent;\n if (e.type === \"thinking_delta\") emit({ type: \"delta\", kind: \"thinking\", chars: e.delta.length });\n else if (e.type === \"text_delta\" || e.type === \"toolcall_delta\") emit({ type: \"delta\", kind: \"writing\", chars: e.delta.length });\n else emit({ type: \"beat\" });\n } else if (event.type === \"tool_execution_start\") {\n // Tools run between calls: the call that requested them has ended.\n emit({ type: \"end\" });\n }\n}\n\n/**\n * Whether THIS invocation's last assistant message is a finished answer: text,\n * no tool call pending, and a stop that was not an abort, a tool-use handoff or\n * a token-limit cut. Anything else is a teaser or a cut-off report.\n */\nfunction endedWithReport(session: AgentSession, startIndex: number): boolean {\n for (let i = session.messages.length - 1; i >= startIndex; i--) {\n const msg = session.messages[i];\n if (msg.role !== \"assistant\") continue;\n const hasToolCall = msg.content.some((c) => c.type === \"toolCall\");\n const cutOff = msg.stopReason === \"aborted\" || msg.stopReason === \"toolUse\" || msg.stopReason === \"length\";\n return !hasToolCall && !cutOff && extractText(msg.content).trim() !== \"\";\n }\n return false;\n}\n\n/** The reason a tool call gets during the forced report turn. */\nconst FINAL_REPORT_TOOL_BLOCKED = \"No tools are available for the final report. Write the report as text now.\";\n\n/**\n * Prompt the session once more with its tools switched off and ask for the full\n * report. Returns whether that produced assistant text. Never throws: the run\n * keeps whatever it had if the extra turn fails.\n *\n * Clearing the active set alone is not enough: `prompt()` fires\n * `before_agent_start`, and an extension may re-activate its tools there\n * (pi-deferred-context-engine re-pins its always-active spine), after which the\n * turn's tools are snapshotted. So for this turn the loadout is pinned empty by\n * shadowing `setActiveToolsByName` (the path `pi.setActiveTools` takes), and any\n * call that still gets through (a tool activated by a registry refresh) is\n * blocked with `terminate`, which ends the loop after that batch. The caller's\n * turn hook is the hard stop behind both.\n */\nasync function forceFinalReport(session: AgentSession, startIndex: number, signal?: AbortSignal): Promise<boolean> {\n const previousTools = session.getActiveToolNames();\n const setActiveTools = session.setActiveToolsByName;\n const priorBeforeToolCall = session.agent.beforeToolCall;\n try {\n await session.waitForIdle?.();\n // A stop can arrive while an aborted tool batch drains. Never start a new\n // prompt after that stop just because the report was already scheduled.\n if (signal?.aborted) return false;\n setActiveTools.call(session, []);\n session.setActiveToolsByName = () => setActiveTools.call(session, []);\n session.agent.beforeToolCall = async () => ({ block: true, terminate: true, reason: FINAL_REPORT_TOOL_BLOCKED });\n await session.prompt(FINAL_REPORT_PROMPT);\n } catch {\n return false;\n } finally {\n session.setActiveToolsByName = setActiveTools;\n session.agent.beforeToolCall = priorBeforeToolCall;\n session.setActiveToolsByName(previousTools);\n }\n return endedWithReport(session, startIndex);\n}\n\n/**\n * Error message of THIS invocation's final assistant message, when that turn\n * failed. Two failure shapes, both keyed off how the final turn STOPPED:\n * - stopReason \"error\": a provider failure pi resolved instead of rejecting\n * (any text; partial output is surfaced separately).\n * - stopReason \"length\" with NO text: a silent max-token death \u2014 the run hit\n * the output-token ceiling before writing anything, which would otherwise\n * land as a \"completed\" run with an empty result (the #144 symptom).\n * Everything else completes: a clean \"stop\"/\"toolUse\" final, and \u2014 crucially \u2014 a\n * \"length\" stop that DID produce text (a legitimate truncated-but-useful answer).\n * \"aborted\" is handled by the manager's abort flag / \"stopped\" guard, not here.\n * Bounded by `startIndex` (like the text fallback) so a resume that produced no\n * assistant message of its own never inherits a PRIOR turn's stop reason.\n */\nfunction finalTurnError(session: AgentSession, startIndex: number): string | undefined {\n for (let i = session.messages.length - 1; i >= startIndex; i--) {\n const msg = session.messages[i];\n if (msg.role !== \"assistant\") continue;\n if (msg.stopReason === \"error\") {\n return (msg as { errorMessage?: string }).errorMessage?.trim() || \"provider error with no output\";\n }\n if (msg.stopReason === \"length\" && !extractText(msg.content).trim()) {\n return \"run hit the output token limit before producing any text\";\n }\n return undefined;\n }\n return undefined;\n}\n\n/** Waits before each re-prompt of a step lost to a stale ctx: a reload re-registers within seconds. */\nconst STALE_CTX_RETRY_DELAYS_MS: readonly number[] = [1_000, 3_000, 9_000];\n\n/** Sent when the session's last step died on a stale ctx; the transcript already holds the work so far. */\nconst STALE_CTX_RETRY_PROMPT = \"Your previous step was interrupted by a session reload before it produced output. Continue the task from where you left off.\";\n\n/**\n * Resolve after `ms`, or as soon as `signal` aborts. Never rejects.\n */\nfunction sleep(ms: number, signal: AbortSignal | undefined, clock: Clock): Promise<void> {\n return new Promise((resolve) => {\n if (signal?.aborted) return resolve();\n const done = () => {\n timer.cancel();\n signal?.removeEventListener(\"abort\", done);\n resolve();\n };\n const timer = clock.setTimeout(done, ms);\n signal?.addEventListener(\"abort\", done, { once: true });\n });\n}\n\n/**\n * Re-prompt a session whose final step died on a stale extension ctx, backing\n * off between attempts so a reload in progress can re-register its routes.\n * Returns once the final step no longer fails that way, retries are spent, or\n * `signal` aborts. A permanently dead runtime (the parent session was replaced)\n * exhausts the retries and is reported by `staleCtxOutcome`.\n *\n * Why appending a continue prompt is safe, and re-sending the task is not: the\n * failed step died in model routing or an observer, before the model produced\n * anything, so the transcript already holds every tool call and result the run\n * made. Re-sending the task would show the model the same work twice and invite\n * it to repeat side effects (a push, a PR). The continue prompt adds one user\n * turn and nothing else, so the tool batch is never replayed; a tool that did\n * run is in context as a result.\n *\n * Kept for stale-ctx failures that routing no longer causes itself: core now hands\n * `route` the requesting session's context (#581), so another session's reload or\n * disposal cannot invalidate this request, but an extension callback that captured\n * a dead ctx can still throw, and only this turns that into a bounded retry and a report.\n */\nexport async function retryStaleCtx(\n session: AgentSession,\n startIndex: number,\n signal: AbortSignal | undefined,\n delays: readonly number[] = STALE_CTX_RETRY_DELAYS_MS,\n clock: Clock = realClock,\n): Promise<void> {\n for (const delay of delays) {\n if (!isStaleCtxError(finalTurnError(session, startIndex))) return;\n await sleep(delay, signal, clock);\n if (signal?.aborted) return;\n await session.prompt(STALE_CTX_RETRY_PROMPT);\n }\n}\n\n/**\n * Whether a follow-up prompt (the structured-output retry, the forced final\n * report) may still be sent. Not once the run was stopped, and not while the\n * final step is still a stale ctx: the runtime is dead, so the prompt would\n * fail the same way and mask the real outcome behind a doomed turn.\n */\nfunction mayFollowUp(session: AgentSession, startIndex: number, signal: AbortSignal | undefined): boolean {\n return !signal?.aborted && staleCtxOutcome(session, startIndex) === undefined;\n}\n\n/** Bounded activity only: tool arguments, results and unknown names are never copied. */\nfunction partialProgress(session: AgentSession, startIndex: number): string {\n const calls: string[] = [];\n for (let i = session.messages.length - 1; i >= startIndex && calls.length < 5; i--) {\n const msg = session.messages[i];\n if (msg.role !== \"toolResult\") continue;\n const name = BUILTIN_TOOL_NAMES.includes(msg.toolName) ? msg.toolName : \"other tool\";\n calls.unshift(`${name} (${msg.isError ? \"failed\" : \"completed\"})`);\n }\n return calls.length ? `Latest activity: ${calls.join(\", \")}.` : \"\";\n}\n\n/** Mark prose as earlier progress when subsequent tool results exist. */\nfunction failureText(session: AgentSession, startIndex: number, text: string, partial: string, laterTool: boolean, streamed: boolean): string {\n if (!text) return partial;\n if (streamed) return laterTool ? `Earlier progress:\\n${text}\\n\\n${partial}` : text;\n let hasLaterResult = false;\n for (let i = session.messages.length - 1; i >= startIndex; i--) {\n const msg = session.messages[i];\n if (msg.role === \"assistant\" && extractText(msg.content).trim() === text) break;\n if (msg.role === \"toolResult\") hasLaterResult = true;\n }\n return hasLaterResult ? `Earlier progress:\\n${text}\\n\\n${partial}` : text;\n}\n\n/**\n * The failure and partial result for a run whose final step is still a stale\n * ctx after retries; undefined for any other outcome.\n */\nexport function staleCtxOutcome(session: AgentSession, startIndex: number): { failure: string; partial: string } | undefined {\n const error = finalTurnError(session, startIndex);\n if (!isStaleCtxError(error)) return undefined;\n return {\n failure: `interrupted by a session reload or replacement; the agent's model runtime went stale and retries did not recover it: ${error}`,\n partial: partialProgress(session, startIndex),\n };\n}\n\n/** The per-run callbacks a spawn and a resume share, plus the resolved turn limit. */\ntype RunObserverOptions = Pick<RunOptions, \"onTurnEnd\" | \"onTextDelta\" | \"onModelCall\" | \"onToolActivity\" | \"onAssistantUsage\" | \"onCompaction\"> & {\n /** Already resolved: undefined = unlimited. */\n maxTurns?: number;\n};\n\n/**\n * Observe one prompt of a session \u2014 a spawn's or a resume's \u2014 and enforce its\n * turn limit: steer once at `maxTurns`, hard-abort after the grace turns.\n * `steered` / `aborted` are live fields, read while the prompt is still in\n * flight (the structured-output retry) and after it settles (the result).\n * Shared by `runAgent` and `resumeAgent` so a resumed run is bounded exactly\n * like the first one (#368).\n */\nfunction observeRun(session: AgentSession, options: RunObserverOptions) {\n let turnCount = 0;\n let currentMessageText = \"\";\n let finalizingTurns = 0;\n const run = {\n steered: false,\n aborted: false,\n finalizing: false,\n };\n const unsubscribe = session.subscribe((event: AgentSessionEvent) => {\n if (event.type === \"turn_end\") {\n turnCount++;\n options.onTurnEnd?.(turnCount);\n if (run.finalizing) {\n // The report gets one tool-free turn, even if an extension promotes tools.\n finalizingTurns++;\n if (finalizingTurns > 1 || (event.toolResults?.length ?? 0) > 0) {\n run.aborted = true;\n session.abort();\n }\n } else if (options.maxTurns != null) {\n if (!run.steered && turnCount >= options.maxTurns) {\n run.steered = true;\n session.steer(\"You have reached your turn limit. Wrap up immediately \u2014 provide your final answer now.\");\n } else if (run.steered && turnCount >= options.maxTurns + graceTurns) {\n run.aborted = true;\n session.abort();\n }\n }\n }\n if (options.onModelCall) forwardModelCall(event, options.onModelCall);\n if (event.type === \"message_start\") {\n currentMessageText = \"\";\n }\n if (event.type === \"message_update\" && event.assistantMessageEvent.type === \"text_delta\") {\n currentMessageText += event.assistantMessageEvent.delta;\n options.onTextDelta?.(event.assistantMessageEvent.delta, currentMessageText);\n }\n if (event.type === \"tool_execution_start\") {\n options.onToolActivity?.({ type: \"start\", toolName: event.toolName });\n }\n if (event.type === \"tool_execution_end\") {\n options.onToolActivity?.({ type: \"end\", toolName: event.toolName });\n }\n if (event.type === \"message_end\" && event.message.role === \"assistant\") {\n const u = (event.message as any).usage;\n if (u) options.onAssistantUsage?.({\n input: u.input ?? 0,\n output: u.output ?? 0,\n cacheWrite: u.cacheWrite ?? 0,\n cacheRead: u.cacheRead ?? 0,\n cost: u.cost?.total ?? 0,\n }, event.message as AssistantMessageInfo);\n }\n if (event.type === \"compaction_end\" && !event.aborted && event.result) {\n options.onCompaction?.({ reason: event.reason, tokensBefore: event.result.tokensBefore });\n }\n });\n // Keep the live state object captured by the listener, adding only the real cleanup.\n return Object.assign(run, { unsubscribe });\n}\n\n/**\n * Wire an AbortSignal to abort a session.\n * Returns a cleanup function to remove the listener.\n */\nfunction forwardAbortSignal(session: AgentSession, signal?: AbortSignal): () => void {\n if (!signal) return () => {};\n const onAbort = () => session.abort();\n signal.addEventListener(\"abort\", onAbort, { once: true });\n return () => signal.removeEventListener(\"abort\", onAbort);\n}\n\nfunction resolveConfiguredSessionDir(sessionDir: string | undefined, cwd: string, homeDir = homedir()): string | undefined {\n if (!sessionDir) return undefined;\n if (sessionDir === \"~\" || sessionDir.startsWith(\"~/\")) return resolve(homeDir, sessionDir.slice(2));\n if (isAbsolute(sessionDir)) return sessionDir;\n return resolve(cwd, sessionDir);\n}\n\nexport async function runAgent(\n ctx: ExtensionContext,\n type: SubagentType,\n prompt: string,\n options: RunOptions,\n): Promise<RunResult> {\n const config = getConfig(type);\n const agentConfig = getAgentConfig(type);\n\n // Resolve working directory: worktree override > parent cwd\n const effectiveCwd = options.cwd ?? ctx.cwd;\n // Filesystem work happens in effectiveCwd; config discovery in configCwd.\n // They differ only for SpawnOptions.cwd spawns (config stays with the parent).\n const configCwd = options.configCwd ?? effectiveCwd;\n\n const env = await detectEnv(options.pi, effectiveCwd);\n\n // Get parent system prompt for append-mode agents\n const parentSystemPrompt = ctx.getSystemPrompt();\n const agentDir = resolveAgentDir(options.homeDir);\n // The child inherits the parent's project-trust decision. Pi otherwise defaults\n // SettingsManager to trusted, which could load project MCP configuration; resolve\n // it before resource loading so untrusted skills cannot shadow trusted resources.\n const projectTrusted = options.configCwd !== undefined && options.configProjectTrusted !== undefined\n ? options.configProjectTrusted\n : ctx.isProjectTrusted();\n const settingsManager = SettingsManager.create(configCwd, agentDir, { projectTrusted });\n\n // Build prompt extras (memory, skill preloading)\n const extras: PromptExtras = {};\n if (options.worktreeBase) extras.worktreeBase = options.worktreeBase;\n if (options.workflow && !options.structuredOutput) extras.workflowChild = true;\n if (options.planGate?.policy) extras.planMode = true;\n\n // Resolved here, not by each caller: mention and RPC spawns pass no `isolated`,\n // and the agent file's value must hold on every path.\n const isolated = agentConfig?.isolated ?? options.isolated;\n // Resolve extensions/skills: isolated overrides to false\n const extensions = isolated ? false : config.extensions;\n // Nulling excludes under isolated also suppresses the orphaned-exclude warning \u2014\n // isolation is an intentional override, not a misconfiguration.\n const excludeExtensions = isolated ? undefined : config.excludeExtensions;\n const skills = isolated ? false : config.skills;\n\n // Skill preloading: when skills is string[], preload their content into prompt\n if (Array.isArray(skills)) {\n const loaded = await preloadSkills(skills, configCwd, { agentDir, settingsManager, homeDir: options.homeDir });\n if (loaded.length > 0) {\n extras.skillBlocks = loaded;\n }\n }\n\n let toolNames = getToolNamesForType(type);\n\n // Persistent memory: detect write capability and branch accordingly.\n // Account for disallowedTools \u2014 a tool in the base set but on the denylist is not truly available.\n if (agentConfig?.memory) {\n const existingNames = new Set(toolNames);\n const denied = agentConfig.disallowedTools ? new Set(agentConfig.disallowedTools) : undefined;\n const effectivelyHas = (name: string) => existingNames.has(name) && !denied?.has(name);\n const hasWriteTools = effectivelyHas(\"write\") || effectivelyHas(\"edit\");\n\n if (hasWriteTools) {\n // Read-write memory: add any missing memory tool names (read/write/edit)\n const extraNames = getMemoryToolNames(existingNames);\n if (extraNames.length > 0) toolNames = [...toolNames, ...extraNames];\n extras.memoryBlock = buildMemoryBlock(agentConfig.name, agentConfig.memory, configCwd, options.homeDir);\n } else {\n // Read-only memory: only add read tool name, use read-only prompt\n const extraNames = getReadOnlyMemoryToolNames(existingNames);\n if (extraNames.length > 0) toolNames = [...toolNames, ...extraNames];\n extras.memoryBlock = buildReadOnlyMemoryBlock(agentConfig.name, agentConfig.memory, configCwd, options.homeDir);\n }\n }\n\n // At (or past) the cap this agent can never spawn, so it can never own a child\n // to fetch from or steer either \u2014 inject nothing rather than three tools whose\n // every call is an error. This is also what makes `maxSubagentDepth` 0/1 mean\n // \"nesting off\" instead of \"nesting always fails\". Resolved before the system\n // prompt because an agent that asked for subagents and was refused is told so.\n const effectiveMaxDepth = options.nestedRuntime?.maxSubagentDepth ?? getMaxSubagentDepth();\n const nestedRuntime = options.nestedRuntime && options.nestedRuntime.depth < effectiveMaxDepth\n ? options.nestedRuntime\n : undefined;\n // One answer for the prompt and the workflow refusal: does this child end up with `Agent`?\n // An allowlist that resolves to no enabled agent leaves Agent nothing to\n // accept; omit the tools rather than advertise \"none\" as a type (#331, #333).\n const nestingPossible = Boolean(\n agentConfig?.allowedSubagents && nestedRuntime && !isolated\n && hasNestableTypes(agentConfig.allowedSubagents, { homeDir: options.homeDir, configCwd, projectTrusted }),\n );\n const agentAvailable = nestingPossible && !agentConfig?.disallowedTools?.includes(\"Agent\");\n if (agentConfig?.allowedSubagents && !agentAvailable) extras.nestingDisabled = true;\n\n // Build system prompt from agent config\n let systemPrompt: string;\n if (agentConfig) {\n systemPrompt = buildAgentPrompt(agentConfig, effectiveCwd, env, parentSystemPrompt, extras);\n } else {\n // Unknown type fallback: spread the canonical general-purpose config (defensive \u2014\n // unreachable in practice since index.ts resolves unknown types before calling runAgent).\n const fallback = DEFAULT_AGENTS.get(\"general-purpose\");\n if (!fallback) throw new Error(`No fallback config available for unknown type \"${type}\"`);\n systemPrompt = buildAgentPrompt({ ...fallback, name: type }, effectiveCwd, env, parentSystemPrompt, extras);\n }\n\n // When skills is string[], we've already preloaded them into the prompt.\n // Still pass noSkills: true since we don't need the skill loader to load them again.\n const noSkills = skills === false || Array.isArray(skills);\n\n // Extension loading:\n // - true \u2192 all default-discovered extensions\n // - false \u2192 none (noExtensions)\n // - string[] \u2192 loader-level allowlist. Bare names keep the matching\n // default-discovered extension; path entries load that extension fresh;\n // \"*\" keeps all default-discovered extensions. Excluded extensions never\n // bind handlers or register tools (their factory still runs once).\n //\n // Suppress AGENTS.md/CLAUDE.md and APPEND_SYSTEM.md \u2014 upstream's\n // buildSystemPrompt() re-appends both AFTER systemPromptOverride, which\n // would defeat prompt_mode: replace and isolated: true. Parent context, if\n // wanted, reaches the subagent via prompt_mode: append (parentSystemPrompt\n // is embedded in systemPromptOverride) or inherit_context (conversation).\n // `ext:` selectors from the `tools:` CSV narrow which extension tools surface to\n // the LLM. They do NOT control loading \u2014 `extensions:` is the sole authority for\n // which extensions load. `ext:foo` against an extension that `extensions:` excluded\n // is an orphan and warns after reload. `isolated` means no extension tools at all.\n const { extNames, narrowing } = parseExtSelectors(\n isolated ? [] : (agentConfig?.extSelectors ?? []),\n );\n const noExtensions = extensions === false;\n\n const extensionsSpec = Array.isArray(extensions)\n ? parseExtensionsSpec(extensions, configCwd, options.homeDir)\n : undefined;\n const keepNames = extensionsSpec?.names ?? new Set<string>();\n // `exclude_extensions:` is a denylist applied AFTER the include set \u2014 exclude wins.\n // Plain canonical names only (case-insensitive). Note: excluded extensions'\n // factories still run once during reload() (see comment above) \u2014 exclusion\n // suppresses handler binding and tool registration; it is not a sandbox.\n const excludeNames = new Set((excludeExtensions ?? []).map((n) => n.toLowerCase()));\n const hasExcludes = excludeNames.size > 0;\n // The override filters loaded extensions down to `keepNames` minus `excludeNames`.\n // It's only needed when we're neither loading everything without excludes\n // (`extensions: true` or a `\"*\"` wildcard) nor nothing (`noExtensions`).\n const loadAll = extensions === true || extensionsSpec?.wildcard === true;\n const additionalExtensionPaths = extensionsSpec?.paths.length ? extensionsSpec.paths : undefined;\n // Pre-filter discovered set, captured by the override \u2014 the exclude-typo warning\n // must compare against this, not the surviving set (absence from survivors is\n // an exclude *succeeding*).\n let discoveredNames: Set<string> | undefined;\n const extensionsOverride: ((base: LoadExtensionsResult) => LoadExtensionsResult) | undefined =\n noExtensions || (loadAll && !hasExcludes)\n ? undefined\n : (base) => {\n discoveredNames = new Set(base.extensions.flatMap((e) => extensionCanonicalNames(e.path)));\n return {\n ...base,\n extensions: base.extensions.filter((e) => {\n if (e.path === `<inline:${SCOPE_GATE_NAME}>`) return true; // ours, not the agent's\n const canons = extensionCanonicalNames(e.path);\n if (canons.some((n) => excludeNames.has(n))) return false; // exclude wins\n return loadAll || canons.some((n) => keepNames.has(n));\n }),\n };\n };\n\n // That trust covers the parent's project (`configCwd`), not a directory a spawn\n // was sent into. The session answers `ctx.isProjectTrusted()` for its own cwd,\n // which pi's MCP uses to read `<cwd>/.pi/mcp.json` \u2014 so a cross-directory session\n // keeps the parent project's settings but reports its cwd as untrusted. The\n // loader keeps the trusted manager: it loads the parent project's extensions.\n const sessionSettingsManager =\n resolve(effectiveCwd) === resolve(configCwd)\n ? settingsManager\n : Object.assign(SettingsManager.create(configCwd, agentDir, { projectTrusted }), {\n isProjectTrusted: () => false,\n });\n const nestedCallGate: NestedCallGate = {};\n\n const loader = createHomeResourceLoader({\n settingsManager,\n // pi's CLI hands its built-in extensions to the loader it builds; this one starts\n // with none. Forwarded as `builtin:` resources they load as in the main session \u2014\n // default-on, disabled by `-builtin:<name>` in settings \u2014 and the per-agent\n // allowlist filters them like any other extension. pi's `llama.cpp` built-in is\n // CLI-only (not exported). Fresh factories per spawn: MCP state lives in the closure.\n extensionFactories: [\n { name: \"codemode\", factory: createCodemodeExtension(), builtin: true, replaceable: true },\n { name: \"tool-search\", factory: createToolSearchExtension(), builtin: true, replaceable: true },\n { name: \"mcp\", factory: createMcpExtension(), builtin: true, replaceable: true },\n // Under `noExtensions` the static allowlist gates the registry itself.\n ...(noExtensions ? [] : [scopeGateExtension(nestedCallGate)]),\n ],\n // Mirrors pi's CLI: `--no-mcp` keeps MCP out of subagents too, and `--no-extensions`\n // keeps all the built-ins out. Discovered extensions still follow `extensions:`.\n disabledBuiltinExtensions: process.argv.some((a) => a === \"--no-extensions\" || a === \"-ne\")\n ? [\"codemode\", \"tool-search\", \"mcp\"]\n : process.argv.includes(\"--no-mcp\")\n ? [\"mcp\"]\n : undefined,\n cwd: configCwd,\n agentDir,\n noExtensions,\n additionalExtensionPaths,\n extensionsOverride,\n noSkills,\n noPromptTemplates: true,\n noThemes: true,\n noContextFiles: true,\n systemPromptOverride: () => systemPrompt,\n appendSystemPromptOverride: () => [],\n }, options.homeDir);\n await bindChildResourceLoader(loader).reload();\n\n // Plain entries in `tools:` are expected to be built-in names (extension tools\n // go through `ext:`), so an unknown name there is unambiguously a typo. Previously\n // this produced a silently broken agent (#75) \u2014 pi-mono accepted the bogus name\n // into the allowlist, then dropped it at registration with no signal back.\n if (agentConfig?.builtinToolNames?.length) {\n const knownBuiltins = new Set(BUILTIN_TOOL_NAMES);\n for (const name of agentConfig.builtinToolNames) {\n if (!knownBuiltins.has(name)) {\n options.onToolActivity?.({\n type: \"end\",\n toolName: `tools-error:tool \"${name}\" requested by agent \"${type}\" is not a known built-in`,\n });\n }\n }\n }\n\n // A subagent spawns mid-task, so a bad `extensions:`/`ext:` entry warns rather\n // than aborts. Two distinct misconfigurations to catch:\n // - `extensions: [foo]` but no extension named foo was discovered (typo or\n // path that failed to load \u2014 path entries fold their canonical name into\n // `keepNames`, so this covers them too).\n // - `tools: ext:foo` but foo isn't in the loaded set (because `extensions:`\n // didn't include it). Since v0.9, `ext:` no longer pulls extensions in;\n // loading is `extensions:`-authoritative.\n // An exclude_extensions: alongside extensions: false is contradictory \u2014 nothing\n // loads, so there is nothing to exclude.\n if (hasExcludes && noExtensions) {\n options.onToolActivity?.({\n type: \"end\",\n toolName: `extension-error:exclude_extensions has no effect for agent \"${type}\" \u2014 extensions: false loads nothing`,\n });\n }\n // Exclude typo check: compares against the PRE-filter discovered set (an excluded\n // name absent from the surviving set is the exclude working as intended). Also\n // flags path-like and \"*\" entries \u2014 excludes are plain names only.\n if (hasExcludes && discoveredNames) {\n for (const name of excludeNames) {\n if (!discoveredNames.has(name)) {\n options.onToolActivity?.({\n type: \"end\",\n toolName: `extension-error:exclude_extensions: \"${name}\" for agent \"${type}\" did not match any discovered extension`,\n });\n }\n }\n }\n if (keepNames.size > 0 || extNames.size > 0) {\n const survivingNames = new Set(\n loader.getExtensions().extensions.flatMap((e) => extensionCanonicalNames(e.path)),\n );\n for (const name of keepNames) {\n if (!survivingNames.has(name)) {\n options.onToolActivity?.({\n type: \"end\",\n toolName: excludeNames.has(name)\n ? `extension-error:extension \"${name}\" is in both extensions: and exclude_extensions: for agent \"${type}\" \u2014 exclude wins`\n : `extension-error:extension \"${name}\" requested by agent \"${type}\" was not loaded`,\n });\n }\n }\n for (const name of extNames) {\n if (!survivingNames.has(name)) {\n options.onToolActivity?.({\n type: \"end\",\n toolName: `extension-error:ext:${name} referenced by agent \"${type}\" but extension \"${name}\" is not loaded (check extensions:/exclude_extensions:)`,\n });\n }\n }\n }\n\n const model = options.modelSelection.model;\n if (options.modelSelection.fallback) options.onModelFallback?.(options.modelSelection.fallback);\n\n // Resolve thinking level: explicit option > agent config > undefined (inherit)\n const thinkingLevel = options.thinkingLevel ?? agentConfig?.thinking;\n\n const disallowedSet = agentConfig?.disallowedTools\n ? new Set(agentConfig.disallowedTools)\n : undefined;\n\n // Nested delegation tools (opt-in, ownership-scoped). Empty unless the agent\n // set `allowed_subagents` and a nestedRuntime was provided \u2014 and never when\n // isolated. Their names collide with EXCLUDED_TOOL_NAMES by design, so the\n // scoping below re-admits them explicitly (registry deny + active-set narrow).\n const nestedTools = agentConfig?.allowedSubagents && nestedRuntime && nestingPossible\n ? createNestedSubagentTools({\n manager: nestedRuntime.manager,\n pi: options.pi,\n parentAgentId: nestedRuntime.parentAgentId,\n depth: nestedRuntime.depth,\n maxSubagentDepth: effectiveMaxDepth,\n allowedSubagents: agentConfig.allowedSubagents,\n homeDir: options.homeDir,\n configCwd,\n projectTrusted,\n })\n : [];\n const nestedToolNames = new Set(nestedTools.map(tool => tool.name));\n\n // The `agent({ schema })` contract: this child reports its answer by calling\n // StructuredOutput, and `structuredJson` below is what the caller reads. The\n // schema was already compiled by whoever asked for it, so a bad one failed\n // before any of this ran.\n const structuredCapture = options.structuredOutput ? createStructuredCapture() : undefined;\n const structuredTools = options.structuredOutput && structuredCapture\n ? [createStructuredOutputTool(options.structuredOutput, structuredCapture)]\n : [];\n const structuredToolNames = new Set(structuredTools.map(tool => tool.name));\n // Re-admitted together at every gate below. Kept as one set so a new injected\n // tool cannot be added to some of the three gates and forgotten at the rest.\n //\n // `disallowed_tools` is applied HERE rather than at the gates, because the two\n // kinds answer to it differently: a nested delegation tool is an opt-in the\n // agent's own frontmatter can take back, while StructuredOutput exists only\n // because this call asked for a schema \u2014 removing it would make the request\n // unsatisfiable by construction rather than merely restricted.\n // Only where extensions load, which is also where a foreign `workflow` tool\n // would be visible and refused; an isolated child gets no workflow tool at all.\n const workflowError = agentAvailable ? NESTED_WORKFLOW_ERROR : NESTED_WORKFLOW_NO_AGENT_ERROR;\n const refusalTools = !noExtensions && !disallowedSet?.has(SUBAGENT_TOOL_NAMES.WORKFLOW)\n ? [createWorkflowRefusalTool(workflowError)]\n : [];\n const readmitToolNames = new Set([\n ...[...nestedToolNames].filter(name => !disallowedSet?.has(name)),\n ...structuredToolNames,\n ...refusalTools.map(tool => tool.name),\n ]);\n\n // \u2500\u2500\u2500 Tool scoping \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // Some extensions register their tools ASYNCHRONOUSLY, long after the\n // `loader.reload()` above: pi-mcp calls registerTool from `session_start`\n // (once its MCP servers connect), context-mode from `before_agent_start`.\n // That is deliberate on their part \u2014 eagerly spawning an MCP bridge during\n // extension discovery orphans child processes on pi's non-agent code paths\n // (--help, config, trust probing).\n //\n // So the tool set cannot be snapshotted here. pi's `allowedToolNames` gates\n // tool *registration* (`_refreshToolRegistry`'s `isAllowedTool`), not merely\n // the active set, and is frozen at construction \u2014 a name absent from the\n // snapshot is dropped forever, even once the tool actually registers (#125).\n //\n // Whenever extensions are in play we therefore:\n // - leave `allowedToolNames` unset, so pi's live gate admits tools whenever\n // they register;\n // - express the name-stable, permanent part of the scope (our own\n // orchestration tools, built-ins the agent didn't ask for, and\n // `disallowedTools`) as `excludeTools`, which pi re-applies on every\n // registry refresh;\n // - enforce `ext:` narrowing on the ACTIVE set via the live `inScope()`\n // predicate installed after bind \u2014 the active set is what the LLM sees,\n // so a registry tool that is never activated is invisible and uncallable.\n //\n // `noExtensions`/`isolated` keeps the historical static allowlist: nothing\n // async can appear there, and a hard registry gate is the correct boundary.\n const builtinToolNameSet = new Set(toolNames);\n\n let sessionTools: string[] | undefined;\n let sessionExcludeTools: string[] | undefined;\n if (noExtensions) {\n // Strict allowlist: built-ins the agent asked for, plus any opt-in nested\n // tools (whose names would otherwise be dropped as EXCLUDED_TOOL_NAMES).\n sessionTools = [\n ...toolNames.filter(\n (t) => !EXCLUDED_TOOL_NAMES.includes(t) && !disallowedSet?.has(t),\n ),\n ...[...nestedToolNames].filter((t) => !disallowedSet?.has(t)),\n // Not filtered through `disallowedSet`, unlike the nested tools above:\n // the caller asked for a schema, and removing the only tool that can\n // satisfy it would make the request unsatisfiable by construction rather\n // than merely restricted.\n ...structuredToolNames,\n ];\n } else {\n // Deny the orchestration tools EXCEPT the nested ones this agent opted into \u2014\n // those are injected as customTools and must survive the registry gate.\n const denyTools = new Set<string>(\n EXCLUDED_TOOL_NAMES.filter((t) => !nestedToolNames.has(t) && !readmitToolNames.has(t)),\n );\n // Keep only the built-ins the agent asked for \u2014 deny the rest.\n for (const name of BUILTIN_TOOL_NAMES) {\n if (!builtinToolNameSet.has(name)) denyTools.add(name);\n }\n if (disallowedSet) {\n // disallowed_tools wins even over an opt-in nested tool of the same name.\n // Not over StructuredOutput, though \u2014 see the allowlist branch above.\n for (const name of disallowedSet) {\n if (!structuredToolNames.has(name)) denyTools.add(name);\n }\n }\n sessionExcludeTools = [...denyTools];\n }\n\n const configuredSessionDir = resolveConfiguredSessionDir(agentConfig?.sessionDir, effectiveCwd, options.homeDir);\n const sessionDirSetting = process.env.PI_CODING_AGENT_SESSION_DIR ?? settingsManager.getSessionDir?.();\n // SessionManager's implicit default consults the host home again. Pin the\n // same cwd encoding under our injected agentDir instead when isolating a run.\n // SDK settings go straight through SessionManager's native normalization;\n // unlike frontmatter, file URLs expand and relative settings stay relative.\n const defaultSessionDir = options.homeDir === undefined\n ? sessionDirSetting\n : sessionDirSetting\n ? normalizeHomePath(sessionDirSetting, options.homeDir)\n : join(resolve(agentDir), \"sessions\", `--${resolve(effectiveCwd).replace(/^[/\\\\\\\\]/, \"\").replace(/[/\\\\\\\\:]/g, \"-\")}--`);\n // Frontmatter wins when it says anything; otherwise the project default,\n // which `rememberAgents` supplies for top-level agents only. Same precedence\n // as `outputTranscript`.\n const persistSession = agentConfig?.persistSession ?? (options.nested ? false : rememberAgents);\n const sessionManager = options.resumeSessionFile\n // Reopening an existing conversation: the file already carries its own\n // header (cwd, parent) and history, so none of the create-time options\n // apply. `sessionDir` still matters for a later /new or /branch off it.\n ? SessionManager.open(options.resumeSessionFile, configuredSessionDir ?? defaultSessionDir)\n : persistSession\n ? SessionManager.create(effectiveCwd, configuredSessionDir ?? defaultSessionDir, {\n // Optional metadata \u2014 it only nests the subagent under its spawner in\n // `/resume`. Until `rememberAgents` this ran solely for the rare\n // `persist_session: true` agent; now it runs for every spawn, so a\n // context without a session manager (a bare programmatic ctx) must\n // still persist rather than take the whole spawn down.\n parentSession: ctx.sessionManager?.getSessionFile?.(),\n })\n : SessionManager.inMemory(effectiveCwd);\n\n // Pi 0.80.8 replaced createAgentSession's modelRegistry option with\n // modelRuntime, but ExtensionContext still exposes only the registry facade.\n // Pass both so the full supported Pi range retains the parent's providers.\n const parentModelRuntime = (ctx.modelRegistry as unknown as { runtime?: unknown }).runtime;\n const sessionOpts: Parameters<typeof createAgentSession>[0] & {\n modelRegistry: ExtensionContext[\"modelRegistry\"];\n modelRuntime?: unknown;\n } = {\n cwd: effectiveCwd,\n agentDir,\n sessionManager,\n settingsManager: sessionSettingsManager,\n modelRegistry: ctx.modelRegistry,\n // `as never` is what keeps this assignable across the supported Pi range:\n // pre-0.80.8 the field exists only via the `modelRuntime?: unknown` shim\n // above, while newer Pi types it as `ModelRuntime` \u2014 a shape an opaque\n // `unknown` read off the private facade field can never satisfy.\n ...(parentModelRuntime !== undefined && { modelRuntime: parentModelRuntime as never }),\n model,\n tools: sessionTools,\n customTools: [...nestedTools, ...structuredTools, ...refusalTools],\n resourceLoader: loader,\n };\n if (sessionExcludeTools) {\n sessionOpts.excludeTools = sessionExcludeTools;\n }\n if (thinkingLevel) {\n sessionOpts.thinkingLevel = thinkingLevel;\n }\n\n const { session } = await runInChildSessionContext(() => createAgentSession(sessionOpts));\n\n const baseSessionName = agentConfig?.name ?? type;\n session.setSessionName(\n options.agentId ? `${baseSessionName}#${options.agentId.slice(0, 8)}` : baseSessionName,\n );\n\n // Bind extensions so that session_start fires and extensions can initialize\n // (e.g. loading credentials, setting up state). Tool gating already happened\n // at session construction via the `tools:` allowlist above \u2014 no separate\n // post-bind filter is needed. All ExtensionBindings fields are optional.\n await session.bindExtensions({\n onError: (err) => {\n options.onToolActivity?.({\n type: \"end\",\n toolName: `extension-error:${err.extensionPath}`,\n });\n },\n });\n\n // With `allowedToolNames` unset, the registry is scoped by `excludeTools` but\n // the ACTIVE set still needs managing: pi activates only its four default\n // built-ins at turn 1, and `ext:` narrowing has no registry-level expression\n // (we can't deny the name of a tool that hasn't registered yet). Both are\n // handled below by re-deriving scope from the loader's live extension maps \u2014\n // `registerTool` writes into those same maps, so late arrivals are judged too.\n if (!noExtensions) {\n installExtensionToolScope(session, {\n loader,\n toolNames,\n disallowedSet,\n extNames,\n narrowing,\n readmitToolNames,\n nestedCallGate,\n workflowError,\n });\n }\n\n // Plan mode (#437): outermost, so a call Plan refuses reaches no other hook.\n // Read per call, because the manager decides the gate per run (spawn, resume).\n const planGate = options.planGate;\n if (planGate) {\n const planReason = (toolName: string, input: unknown, cwd: string) =>\n planGateReason(planGate, { toolName, input, cwd }, () => session.getAllTools(), readmitToolNames);\n nestedCallGate.planReason = planReason;\n const priorBeforeToolCall = session.agent.beforeToolCall;\n session.agent.beforeToolCall = async (context, signal) => {\n const reason = planReason(context.toolCall.name, context.args, effectiveCwd);\n if (reason !== undefined) return { block: true, reason };\n return priorBeforeToolCall?.(context, signal);\n };\n }\n\n options.onSessionCreated?.(session);\n\n const run = observeRun(session, { ...options, maxTurns: resolveEffectiveMaxTurns(type, options.maxTurns) });\n\n const collector = collectResponseText(session);\n const cleanupAbort = forwardAbortSignal(session, options.signal);\n\n // Build the effective prompt: optionally prepend parent context\n let effectivePrompt = prompt;\n if (options.inheritContext) {\n const parentContext = buildParentContext(ctx);\n if (parentContext) {\n effectivePrompt = parentContext + prompt;\n }\n }\n\n // Boundary for the history fallback: only assistant text produced from here\n // on counts as this run's output (a fresh session, so usually 0).\n const startLen = session.messages.length;\n let structuredRetried = false;\n try {\n // A signal that fired before this point never calls the listener above, and\n // pi's `session.abort()` is a no-op until a run is active \u2014 so a child whose\n // parent is already gone is not prompted at all.\n if (options.signal?.aborted !== true) await session.prompt(effectivePrompt);\n await retryStaleCtx(session, startLen, options.signal, options.staleRetryDelaysMs, options.clock);\n\n // A cap fired. The wrap-up steer is only a request: a model deep in a tool\n // loop keeps calling tools through the grace turns and is then aborted\n // mid-turn, leaving its last narration as the \"result\". Demand the report\n // in a turn that cannot call tools.\n if (run.steered && mayFollowUp(session, startLen, options.signal) && !endedWithReport(session, startLen)) {\n run.finalizing = true;\n const reported = await forceFinalReport(session, startLen, options.signal);\n // A delivered report is a wrap-up, not a failure: the agent did hand back\n // its findings, just later than it would have chosen.\n if (reported) run.aborted = false;\n }\n\n // One more prompt when a schema was asked for and nothing usable came back\n // \u2014 the model answered in prose, or only ever called the tool invalidly.\n // Inside this `try`, so the turn tracking, the text collector and above all\n // the abort forwarding are still live: torn down first, a retry would be\n // unkillable.\n if (structuredCapture !== undefined && structuredCapture.json === undefined\n && !run.aborted && mayFollowUp(session, startLen, options.signal)) {\n structuredRetried = true;\n await session.prompt(structuredRetryPrompt(structuredCapture));\n }\n } finally {\n run.unsubscribe();\n collector.unsubscribe();\n cleanupAbort();\n }\n\n const stale = staleCtxOutcome(session, startLen);\n const text = collector.getText().trim() || getLastAssistantText(session, startLen);\n // A child asked for structured output that never gave any has failed, however\n // articulate its prose was. Reported through `failure` so it travels the same\n // path as a provider error rather than arriving as a successful empty answer.\n const structuredFailure = structuredCapture !== undefined && structuredCapture.json === undefined\n ? structuredCapture.lastError !== undefined\n ? `The agent's StructuredOutput call did not match the required schema: ${structuredCapture.lastError}`\n : \"The agent did not report its answer through StructuredOutput.\"\n : undefined;\n const failure = stale?.failure ?? finalTurnError(session, startLen) ?? structuredFailure;\n const streamed = collector.getText().trim() || collector.getPreviousText().trim();\n return {\n responseText: failure ? failureText(session, startLen, streamed || text, stale?.partial ?? partialProgress(session, startLen), collector.hasLaterTool(), Boolean(streamed)) : text,\n session,\n aborted: run.aborted,\n steered: run.steered,\n failure,\n ...(structuredCapture?.json !== undefined ? { structuredJson: structuredCapture.json } : {}),\n ...(structuredRetried ? { structuredRetried } : {}),\n };\n}\n\n/**\n * Send a new prompt to an existing session (resume). A fresh run of the same\n * agent: the turn limit is resolved as `runAgent` resolves it \u2014 an explicit\n * `maxTurns`, else the agent type's own `max_turns`, else the project default\n * \u2014 and counted from this prompt (#368).\n */\nexport async function resumeAgent(\n session: AgentSession,\n prompt: string,\n options: Pick<RunOptions, \"staleRetryDelaysMs\" | \"clock\" | \"maxTurns\" | \"onTurnEnd\" | \"onTextDelta\" | \"onModelCall\" | \"onToolActivity\" | \"onAssistantUsage\" | \"onCompaction\" | \"signal\"> & {\n /** The agent's type, for its own `max_turns`. */\n type: SubagentType;\n },\n): Promise<{ text: string; failure?: string } & Pick<RunResult, \"aborted\" | \"steered\">> {\n // Boundary for the history fallback: the session already holds prior turns,\n // so only assistant text produced by THIS resume prompt counts as its output\n // \u2014 a failed resume must not surface the previous turn's answer (#144).\n const startLen = session.messages.length;\n const collector = collectResponseText(session);\n const cleanupAbort = forwardAbortSignal(session, options.signal);\n const run = observeRun(session, { ...options, maxTurns: resolveEffectiveMaxTurns(options.type, options.maxTurns) });\n\n try {\n // Already aborted: not prompted, as in `runAgent`.\n if (options.signal?.aborted !== true) await session.prompt(prompt);\n await retryStaleCtx(session, startLen, options.signal, options.staleRetryDelaysMs, options.clock);\n if (run.steered && mayFollowUp(session, startLen, options.signal) && !endedWithReport(session, startLen)) {\n run.finalizing = true;\n if (await forceFinalReport(session, startLen, options.signal)) run.aborted = false;\n }\n } finally {\n collector.unsubscribe();\n run.unsubscribe();\n cleanupAbort();\n }\n\n const stale = staleCtxOutcome(session, startLen);\n const failure = stale?.failure ?? finalTurnError(session, startLen);\n const text = collector.getText().trim() || getLastAssistantText(session, startLen);\n const streamed = collector.getText().trim() || collector.getPreviousText().trim();\n return {\n text: failure ? failureText(session, startLen, streamed || text, stale?.partial ?? partialProgress(session, startLen), collector.hasLaterTool(), Boolean(streamed)) : text,\n failure,\n aborted: run.aborted,\n steered: run.steered,\n };\n}\n\n/**\n * Send a steering message to a running subagent.\n * The message will interrupt the agent after its current tool execution.\n */\nexport async function steerAgent(\n session: AgentSession,\n message: string,\n): Promise<void> {\n await session.steer(message);\n}\n\n/**\n * Get the subagent's conversation messages as formatted text.\n */\nexport function getAgentConversation(session: AgentSession): string {\n const parts: string[] = [];\n\n for (const msg of session.messages) {\n if (msg.role === \"user\") {\n const text = typeof msg.content === \"string\"\n ? msg.content\n : extractText(msg.content);\n if (text.trim()) parts.push(`[User]: ${text.trim()}`);\n } else if (msg.role === \"assistant\") {\n const textParts: string[] = [];\n const toolCalls: string[] = [];\n for (const c of msg.content) {\n if (c.type === \"text\" && c.text) textParts.push(c.text);\n else if (c.type === \"toolCall\") toolCalls.push(` Tool: ${(c as any).name ?? (c as any).toolName ?? \"unknown\"}`);\n }\n if (textParts.length > 0) parts.push(`[Assistant]: ${textParts.join(\"\\n\")}`);\n if (toolCalls.length > 0) parts.push(`[Tool Calls]:\\n${toolCalls.join(\"\\n\")}`);\n } else if (msg.role === \"toolResult\") {\n const text = extractText(msg.content);\n const truncated = text.length > 200 ? text.slice(0, 200) + \"...\" : text;\n parts.push(`[Tool Result (${msg.toolName})]: ${truncated}`);\n }\n }\n\n return parts.join(\"\\n\\n\");\n}\n", "import { AsyncLocalStorage } from \"node:async_hooks\";\n\n/**\n * Marks resource loading/session construction performed for a subagent. This is\n * async-context-local so concurrent top-level extension work is unaffected.\n */\n// Pi reloads extension modules with jiti's module cache disabled. The parent\n// runner and the discovered child extension can therefore hold different module\n// instances, but must consult the same async-local session marker.\nconst contextKey = Symbol.for(\"pi-subagents:child-session-context\");\nconst globals = globalThis as typeof globalThis & { [contextKey]?: AsyncLocalStorage<boolean> };\nconst childSessionContext = globals[contextKey] ?? new AsyncLocalStorage<boolean>();\nglobals[contextKey] = childSessionContext;\n\nexport function inChildSessionContext(): boolean {\n return childSessionContext.getStore() === true;\n}\n\nexport function runInChildSessionContext<T>(fn: () => Promise<T>): Promise<T> {\n return childSessionContext.run(true, fn);\n}\n\n/**\n * Make every future `reload()` of a child session's loader run in the child\n * context. A session reload (e.g. an extension calling `ctx.reload()`) calls\n * `loader.reload()` again and re-runs each extension factory, long after the\n * construction-time {@link runInChildSessionContext} has exited.\n */\nexport function bindChildResourceLoader<T extends { reload(): Promise<void> }>(loader: T): T {\n const reload = loader.reload.bind(loader);\n loader.reload = () => runInChildSessionContext(reload);\n return loader;\n}\n", "/**\n * env.ts \u2014 Detect environment info (git, platform) for subagent system prompts.\n */\n\nimport type { ExtensionAPI } from \"@earendil-works/pi-coding-agent\";\nimport type { EnvInfo } from \"./types.js\";\n\nexport async function detectEnv(pi: ExtensionAPI, cwd: string): Promise<EnvInfo> {\n let isGitRepo = false;\n let branch = \"\";\n\n try {\n const result = await pi.exec(\"git\", [\"rev-parse\", \"--is-inside-work-tree\"], { cwd, timeout: 5000 });\n isGitRepo = result.code === 0 && result.stdout.trim() === \"true\";\n } catch {\n // Not a git repo or git not installed\n }\n\n if (isGitRepo) {\n try {\n const result = await pi.exec(\"git\", [\"branch\", \"--show-current\"], { cwd, timeout: 5000 });\n branch = result.code === 0 ? result.stdout.trim() : \"unknown\";\n } catch {\n branch = \"unknown\";\n }\n }\n\n return {\n isGitRepo,\n branch,\n platform: process.platform,\n };\n}\n", "/** User-scoped paths. Omitted homes keep Pi's call-time runtime defaults. */\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { getAgentDir } from \"@earendil-works/pi-coding-agent\";\n\n/** Mirror Pi's agent-dir override semantics without changing the process environment. */\nexport function resolveAgentDir(homeDir?: string): string {\n if (homeDir === undefined) return getAgentDir();\n const configured = process.env.PI_CODING_AGENT_DIR;\n if (!configured) return join(homeDir, \".pi\", \"agent\");\n return normalizeHomePath(configured, homeDir);\n}\n\n/** Pi's normalizePath is not exported by its public package entry point. */\nexport function normalizeHomePath(path: string, homeDir = homedir()): string {\n // Match Pi's native normalization of Git Bash, WSL and Cygwin drive paths.\n if (process.platform === \"win32\" && path.startsWith(\"/\") && !path.startsWith(\"//\") && !path.includes(\"\\\\\")) {\n const [, letter, remainder] = path.match(/^\\/(?:mnt\\/|cygdrive\\/)?([a-z])(?:\\/(.*))?$/i) ?? [];\n if (letter) path = `${letter.toUpperCase()}:\\\\${remainder?.replaceAll(\"/\", \"\\\\\") ?? \"\"}`;\n }\n if (path === \"~\") return homeDir;\n if (path.startsWith(\"~/\") || (process.platform === \"win32\" && path.startsWith(\"~\\\\\"))) {\n return join(homeDir, path.slice(2));\n }\n return path.startsWith(\"file://\") ? fileURLToPath(path) : path;\n}\n", "/**\n * memory.ts \u2014 Persistent agent memory: per-agent memory directories that persist across sessions.\n *\n * Memory scopes:\n * - \"user\" \u2192 getAgentDir()/agent-memory/{agent-name}/ (default ~/.pi/agent/agent-memory/, honors $PI_CODING_AGENT_DIR)\n * - \"project\" \u2192 .pi/agent-memory/{agent-name}/\n * - \"local\" \u2192 .pi/agent-memory-local/{agent-name}/\n *\n * The user scope previously hardcoded ~/.pi/agent-memory/. That legacy location\n * is still honored (read + write) when it exists and the new location doesn't,\n * so existing memories aren't orphaned.\n */\n\nimport { existsSync, lstatSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { resolveAgentDir } from \"./home-paths.js\";\nimport type { MemoryScope } from \"./types.js\";\n\n/** Maximum lines to read from MEMORY.md */\nconst MAX_MEMORY_LINES = 200;\n\n/**\n * Returns true if a name contains characters not allowed in agent/skill names.\n * Uses a whitelist: only alphanumeric, hyphens, underscores, and dots (no leading dot).\n */\nexport function isUnsafeName(name: string): boolean {\n if (!name || name.length > 128) return true;\n return !/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name);\n}\n\n/**\n * Returns true if the given path is a symlink (defense against symlink attacks).\n */\nexport function isSymlink(filePath: string): boolean {\n try {\n return lstatSync(filePath).isSymbolicLink();\n } catch {\n return false;\n }\n}\n\n/**\n * Safely read a file, rejecting symlinks.\n * Returns undefined if the file doesn't exist, is a symlink, or can't be read.\n */\nexport function safeReadFile(filePath: string): string | undefined {\n if (!existsSync(filePath)) return undefined;\n if (isSymlink(filePath)) return undefined;\n try {\n return readFileSync(filePath, \"utf-8\");\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolve the memory directory path for a given agent + scope + cwd.\n * Throws if agentName contains path traversal characters.\n */\nexport function resolveMemoryDir(agentName: string, scope: MemoryScope, cwd: string, homeDir = homedir()): string {\n if (isUnsafeName(agentName)) {\n throw new Error(`Unsafe agent name for memory directory: \"${agentName}\"`);\n }\n switch (scope) {\n case \"user\": {\n const current = join(resolveAgentDir(homeDir), \"agent-memory\", agentName);\n // Legacy location from when this path was hardcoded. Keep using it if it\n // already holds this agent's memory and the new location hasn't been\n // created yet \u2014 otherwise existing memories would be silently orphaned.\n const legacy = join(homeDir, \".pi\", \"agent-memory\", agentName);\n if (!existsSync(current) && existsSync(legacy) && !isSymlink(legacy)) {\n return legacy;\n }\n return current;\n }\n case \"project\":\n return join(cwd, \".pi\", \"agent-memory\", agentName);\n case \"local\":\n return join(cwd, \".pi\", \"agent-memory-local\", agentName);\n }\n}\n\n/**\n * Ensure the memory directory exists, creating it if needed.\n * Refuses to create directories if any component in the path is a symlink\n * to prevent symlink-based directory traversal attacks.\n */\nexport function ensureMemoryDir(memoryDir: string): void {\n // If the directory already exists, verify it's not a symlink\n if (existsSync(memoryDir)) {\n if (isSymlink(memoryDir)) {\n throw new Error(`Refusing to use symlinked memory directory: ${memoryDir}`);\n }\n return;\n }\n mkdirSync(memoryDir, { recursive: true });\n}\n\n/**\n * Read the first N lines of MEMORY.md from the memory directory, if it exists.\n * Returns undefined if no MEMORY.md exists or if the path is a symlink.\n */\nexport function readMemoryIndex(memoryDir: string): string | undefined {\n // Reject symlinked memory directories\n if (isSymlink(memoryDir)) return undefined;\n\n const memoryFile = join(memoryDir, \"MEMORY.md\");\n const content = safeReadFile(memoryFile);\n if (content === undefined) return undefined;\n\n const lines = content.split(\"\\n\");\n if (lines.length > MAX_MEMORY_LINES) {\n return lines.slice(0, MAX_MEMORY_LINES).join(\"\\n\") + \"\\n... (truncated at 200 lines)\";\n }\n return content;\n}\n\n/**\n * Build the memory block to inject into the agent's system prompt.\n * Also ensures the memory directory exists (creates it if needed).\n */\nexport function buildMemoryBlock(agentName: string, scope: MemoryScope, cwd: string, homeDir = homedir()): string {\n const memoryDir = resolveMemoryDir(agentName, scope, cwd, homeDir);\n // Create the memory directory so the agent can immediately write to it\n ensureMemoryDir(memoryDir);\n\n const existingMemory = readMemoryIndex(memoryDir);\n\n const header = `# Agent Memory\n\nYou have a persistent memory directory at: ${memoryDir}/\nMemory scope: ${scope}\n\nThis memory persists across sessions. Use it to build up knowledge over time.`;\n\n const memoryContent = existingMemory\n ? `\\n\\n## Current MEMORY.md\\n${existingMemory}`\n : `\\n\\nNo MEMORY.md exists yet. Create one at ${join(memoryDir, \"MEMORY.md\")} to start building persistent memory.`;\n\n const instructions = `\n\n## Memory Instructions\n- MEMORY.md is an index file \u2014 keep it concise (under 200 lines). Lines after 200 are truncated.\n- Store detailed memories in separate files within ${memoryDir}/ and link to them from MEMORY.md.\n- Each memory file should use this frontmatter format:\n \\`\\`\\`markdown\n ---\n name: <memory name>\n description: <one-line description>\n type: <user|feedback|project|reference>\n ---\n <memory content>\n \\`\\`\\`\n- Update or remove memories that become outdated. Check for existing memories before creating duplicates.\n- You have Read, Write, and Edit tools available for managing memory files.`;\n\n return header + memoryContent + instructions;\n}\n\n/**\n * Build a read-only memory block for agents that lack write/edit tools.\n * Does NOT create the memory directory \u2014 agents can only consume existing memory.\n */\nexport function buildReadOnlyMemoryBlock(agentName: string, scope: MemoryScope, cwd: string, homeDir = homedir()): string {\n const memoryDir = resolveMemoryDir(agentName, scope, cwd, homeDir);\n const existingMemory = readMemoryIndex(memoryDir);\n\n const header = `# Agent Memory (read-only)\n\nMemory scope: ${scope}\nYou have read-only access to memory. You can reference existing memories but cannot create or modify them.`;\n\n const memoryContent = existingMemory\n ? `\\n\\n## Current MEMORY.md\\n${existingMemory}`\n : `\\n\\nNo memory is available yet. Other agents or sessions with write access can create memories for you to consume.`;\n\n return header + memoryContent;\n}\n", "import type { Model } from \"@earendil-works/pi-ai\";\nimport {\n type AgentSession,\n defineTool,\n type ExtensionAPI,\n type ExtensionContext,\n type ToolDefinition,\n} from \"@earendil-works/pi-coding-agent\";\nimport { Type } from \"typebox\";\nimport { abortable } from \"./abortable.js\";\nimport {\n buildAgentRegistry,\n getAgentConfigIn,\n getAvailableTypesIn,\n resolveEnabledTypeIn,\n resolveTypeIn,\n} from \"./agent-types.js\";\nimport { loadCustomAgents } from \"./custom-agents.js\";\nimport { errorMessage } from \"./error-message.js\";\nimport { isolationParam, resolveAgentInvocationConfig } from \"./invocation-config.js\";\nimport { type ModelSelection, modelIdentityNote, modelSelectionNote, selectModel } from \"./model-selection.js\";\nimport {\n createOutputFilePath,\n getOutputTranscriptDefault,\n streamToOutputFile,\n writeInitialEntry,\n} from \"./output-file.js\";\nimport { getForegroundOutcomeNote, getStatusNote, partialOutputSuffix } from \"./status-note.js\";\nimport type {\n AgentConfig,\n AgentInvocation,\n AgentRecord,\n IsolationMode,\n ThinkingLevel,\n} from \"./types.js\";\nimport { addUsage } from \"./usage.js\";\nimport { isWorktreeIsolationEnabled } from \"./worktree.js\";\n\n/**\n * Hard ceiling on nesting for every branch: main session = 0, its subagents = 1,\n * their children = 2. `0`/`1` disables nesting entirely. Set from\n * `subagents.json` (`maxSubagentDepth`). Read when a subagent session is built,\n * so a change applies to sessions started after it.\n */\nlet maxSubagentDepth = 2;\n\nexport function getMaxSubagentDepth(): number { return maxSubagentDepth; }\nexport function setMaxSubagentDepth(n: number): void { maxSubagentDepth = Math.max(0, Math.floor(n)); }\n\nconst NESTED_TOOL_NAMES = [\"Agent\", \"get_subagent_result\", \"steer_subagent\", \"stop_subagent\"] as const;\n\n/**\n * Why a subagent may not start background work. A detached child's completion\n * is delivered as a follow-up to the session that spawned it, and a subagent\n * session ends the moment it returns its answer, so the notice would go to a\n * session that no longer exists and the work would be aborted with its owner.\n */\nexport const NESTED_BACKGROUND_ERROR =\n \"Background agents are not available inside a subagent: when you finish, this session ends and nothing is left to receive the result. \"\n + \"Omit run_in_background; the call blocks and returns the child's result inline.\";\n\n/** Same reasoning for workflow tools, which run in the background and notify on completion. */\nexport const NESTED_WORKFLOW_ERROR =\n \"Workflows are not available inside a subagent: a workflow runs in the background and reports to the session that started it, \"\n + \"and this session ends when you return your answer. Do the work directly, or call Agent in the foreground.\";\n\n/**\n * `NESTED_WORKFLOW_ERROR` for a child that was never given `Agent` (depth cap,\n * isolation, `disallowed_tools`, or no `allowed_subagents`). Cause-neutral on purpose. Pointing it at a tool it does not have\n * sends it hunting, and then shelling out to a CLI that escapes every limit.\n */\nexport const NESTED_WORKFLOW_NO_AGENT_ERROR =\n \"Workflows are not available inside a subagent: a workflow runs in the background and reports to the session that started it, \"\n + \"and this session ends when you return your answer. Nested subagents are disabled for this session, so there is no Agent tool either. \"\n + \"Do the work directly.\";\n\ninterface NestedSpawnOptions {\n homeDir?: string;\n description: string;\n model?: Model<any>;\n modelSelection?: ModelSelection;\n maxTurns?: number;\n isolated?: boolean;\n inheritContext?: boolean;\n thinkingLevel?: ThinkingLevel;\n isBackground?: boolean;\n isolation?: IsolationMode;\n invocation?: AgentInvocation;\n signal?: AbortSignal;\n onAssistantUsage?: (usage: { input: number; output: number; cacheWrite: number }) => void;\n onSessionCreated?: (session: AgentSession) => void;\n onPrepare?: (id: string) => void;\n depth: number;\n parentAgentId: string;\n maxSubagentDepth: number;\n configCwd?: string;\n /** Trust decision for `configCwd`; always set together with it. */\n configProjectTrusted?: boolean;\n rootSessionId?: string;\n}\n\nexport interface NestedAgentManager {\n spawn(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n type: string,\n prompt: string,\n options: NestedSpawnOptions,\n ): string;\n /** Resolves once the spawned agent is running; rejects on a startup failure. */\n awaitStartup(id: string): Promise<void>;\n spawnAndWait(\n pi: ExtensionAPI,\n ctx: ExtensionContext,\n type: string,\n prompt: string,\n options: Omit<NestedSpawnOptions, \"isBackground\">,\n ): Promise<{ id: string; record: AgentRecord }>;\n getRecord(id: string): AgentRecord | undefined;\n resume(id: string, prompt: string, signal?: AbortSignal, options?: { maxTurns?: number }): Promise<AgentRecord | undefined>;\n /** Stop a running or queued agent; false when it was neither. */\n abort(id: string, by?: AgentRecord[\"stoppedBy\"]): boolean;\n}\n\nexport interface NestedToolContext {\n /** Home shared by this branch's user-resource discovery. */\n homeDir?: string;\n manager: NestedAgentManager;\n pi: ExtensionAPI;\n parentAgentId: string;\n depth: number;\n maxSubagentDepth: number;\n /** \"all\" = any enabled agent; string[] = only those types. Never empty. */\n allowedSubagents: \"all\" | string[];\n /** Root used for agent/config discovery; may differ from the agent's working directory. */\n configCwd: string;\n /**\n * The spawning session's project-trust decision for `configCwd`, as the runner\n * resolved it for the child's own settings. Gates project agent files in the\n * registry built here; read from the session's state it would answer for the\n * child's cwd, which is untrusted for a cross-directory spawn.\n */\n projectTrusted: boolean;\n}\n\nfunction textResult(text: string, isError = false) {\n return { content: [{ type: \"text\" as const, text }], isError, details: {} };\n}\n\nfunction ownsRecord(record: AgentRecord | undefined, parentAgentId: string): record is AgentRecord {\n return record?.parentAgentId === parentAgentId;\n}\n\n/**\n * How the caller received this record, which decides the outcome wording.\n *\n * - \"inline\": a foreground spawn or a resume. The full output is in this very\n * result and no agent id was handed back, so the note must say there is\n * nothing left to fetch \u2014 otherwise the parent invents an id, calls\n * `get_subagent_result`, and hits \"not owned by this parent\" (#174, the same\n * trap the top-level foreground path fell into).\n * - \"fetched\": `get_subagent_result` on a background child. The parent holds a\n * valid id and can poll again, so the background wording applies.\n */\ntype ResultPosition = \"inline\" | \"fetched\";\n\nfunction formatRecord(record: AgentRecord, position: ResultPosition): string {\n // Read off the record, so a fetched or resumed child reports what ran, not\n // what the current call would have configured.\n const note = [modelSelectionNote(record), modelIdentityNote(record)].filter(Boolean).join(\"\\n\");\n return note ? `${note}\\n\\n${formatOutcome(record, position)}` : formatOutcome(record, position);\n}\n\nfunction formatOutcome(record: AgentRecord, position: ResultPosition): string {\n if (record.status === \"error\") {\n return `Agent failed: ${record.error ?? \"unknown error\"}${partialOutputSuffix(record)}`;\n }\n if (record.status === \"queued\" || record.status === \"running\") {\n return `Agent ${record.id} is ${record.status}.`;\n }\n // A truncated run must not read as a finished one. The top-level path carries\n // this in its result headline; a nested result has no headline, so the note\n // leads \u2014 appended, it would look like part of the child's own output.\n const text = record.result?.trim() || record.error?.trim() || \"No output.\";\n const note = position === \"inline\"\n ? getForegroundOutcomeNote(record.status, record.stoppedBy)\n : getStatusNote(record.status, record.stoppedBy);\n return note ? `Nested agent${note}.\\n\\n${text}` : text;\n}\n\ntype NestedRegistryScope = Pick<NestedToolContext, \"homeDir\" | \"configCwd\" | \"projectTrusted\">;\n\nfunction loadNestedRegistry(scope: NestedRegistryScope): Map<string, AgentConfig> {\n return buildAgentRegistry(loadCustomAgents(scope.configCwd, false, { projectTrusted: scope.projectTrusted, homeDir: scope.homeDir }));\n}\n\nfunction allowedTypeSet(\n registry: Map<string, AgentConfig>,\n allowedSubagents: NestedToolContext[\"allowedSubagents\"],\n): Set<string> | undefined {\n return allowedSubagents === \"all\"\n ? undefined\n : new Set(allowedSubagents.map(name => resolveTypeIn(registry, name) ?? name));\n}\n\nfunction availableNestedTypes(\n registry: Map<string, AgentConfig>,\n allowedSubagents: NestedToolContext[\"allowedSubagents\"],\n): string[] {\n const allowed = allowedTypeSet(registry, allowedSubagents);\n return getAvailableTypesIn(registry).filter(name => allowed === undefined || allowed.has(name));\n}\n\n/**\n * Whether a parent with this allowlist could spawn anything at all. An\n * allowlist naming only missing or disabled agents (or `all` over an empty\n * registry) leaves `Agent` with nothing to accept; the runner must then not\n * inject the tools, the same as `allowed_subagents` being unset (#331, #333).\n */\nexport function hasNestableTypes(\n allowedSubagents: NestedToolContext[\"allowedSubagents\"],\n scope: NestedRegistryScope,\n): boolean {\n return availableNestedTypes(loadNestedRegistry(scope), allowedSubagents).length > 0;\n}\n\n/** Build child-safe orchestration tools scoped to one parent agent instance. */\nexport function createNestedSubagentTools(context: NestedToolContext): ToolDefinition[] {\n // Agents resolve from a registry built for THIS branch's config root (under\n // worktree isolation, the copy). Never via registerAgents \u2014 that is\n // process-global state shared with the main session and every other agent.\n const loadRegistry = () => loadNestedRegistry(context);\n const allowedTypesIn = (registry: Map<string, AgentConfig>) => allowedTypeSet(registry, context.allowedSubagents);\n const availableIn = (registry: Map<string, AgentConfig>) => availableNestedTypes(registry, context.allowedSubagents);\n // Never the literal \"none\": a model reads it as a type name and calls it (#331, #333).\n const listAvailable = (registry: Map<string, AgentConfig>): string => {\n const names = availableIn(registry);\n return names.length > 0 ? names.join(\", \") : \"no agent types are currently available\";\n };\n\n const agentTool = defineTool({\n name: NESTED_TOOL_NAMES[0],\n label: \"Agent\",\n description:\n \"Launch a child-safe nested subagent for bounded delegated work. \" +\n \"Only use agent types allowed by this parent agent; nesting is depth-limited.\",\n parameters: Type.Object({\n prompt: Type.String({ description: \"Self-contained task for the nested agent.\" }),\n description: Type.String({ description: \"Short 3-5 word task description.\" }),\n subagent_type: Type.String({ description: `Allowed nested agent type. Available: ${listAvailable(loadRegistry())}.` }),\n model: Type.Optional(Type.String({ description: \"Optional configured @tier or provider/model override; explicit values win over agentModels and the definition.\" })),\n thinking: Type.Optional(Type.String({ description: \"Optional thinking level.\" })),\n max_turns: Type.Optional(Type.Number({ minimum: 1 })),\n run_in_background: Type.Optional(\n Type.Boolean({\n description: \"Not supported inside a subagent: nested spawns always block and return the child's result inline. Passing true returns an error.\",\n }),\n ),\n resume: Type.Optional(Type.String({ description: \"Resume a nested agent owned by this parent.\" })),\n isolated: Type.Optional(Type.Boolean()),\n inherit_context: Type.Optional(Type.Boolean()),\n ...isolationParam(isWorktreeIsolationEnabled()),\n }),\n execute: async (_toolCallId, params, signal, _onUpdate, ctx) => {\n if (params.run_in_background === true) return textResult(NESTED_BACKGROUND_ERROR, true);\n if (params.resume) {\n const existing = context.manager.getRecord(params.resume);\n if (!ownsRecord(existing, context.parentAgentId)) {\n return textResult(`Nested agent not found or not owned by this parent: \"${params.resume}\".`, true);\n }\n // Two resumes of one child in the same turn (parallel tool calls) would\n // run two prompts on one session; the manager refuses the second, and\n // this says why instead of a generic failure.\n if (existing.status === \"running\" || existing.status === \"queued\") {\n return textResult(\n `Nested agent \"${params.resume}\" is still ${existing.status}; it can only be resumed once its current run finishes.`,\n true,\n );\n }\n // Frontmatter authoritative, as on the spawn path; the manager falls\n // back to the limit the child was spawned with, then the default.\n const resumed = await context.manager.resume(params.resume, params.prompt, signal, {\n maxTurns: getAgentConfigIn(loadRegistry(), existing.type)?.maxTurns ?? params.max_turns,\n });\n return resumed\n ? textResult(formatRecord(resumed, \"inline\"), resumed.status === \"error\")\n : textResult(`Failed to resume nested agent \"${params.resume}\".`, true);\n }\n\n if (context.depth >= context.maxSubagentDepth) {\n return textResult(\n `Nested subagent call blocked (depth=${context.depth}, max=${context.maxSubagentDepth}). Complete the task directly.`,\n true,\n );\n }\n\n // Reloaded per call so new agent files are picked up without a restart.\n const registry = loadRegistry();\n const rawType = params.subagent_type;\n // Strict resolve, never the fallback policy: a project-level\n // `fallbackSubagent` must not hand a nested caller an agent its allowlist\n // never named. The list stays allowlist-filtered so a typo can't enumerate\n // agents this parent may not reach.\n const resolvedType = resolveEnabledTypeIn(registry, rawType);\n if (resolvedType === undefined) {\n if (availableIn(registry).length === 0) {\n return textResult(\n `No nested agent types are available to this parent, so Agent cannot spawn anything. Do the work yourself, inline.`,\n true,\n );\n }\n return textResult(\n `Unknown or disabled nested agent type: \"${rawType}\". Allowed: ${availableIn(registry).join(\", \")}.`,\n true,\n );\n }\n const allowed = allowedTypesIn(registry);\n if (allowed !== undefined && !allowed.has(resolvedType)) {\n return textResult(\n `Nested agent type \"${resolvedType}\" is not allowed for this parent. Allowed: ${[...allowed].join(\", \")}.`,\n true,\n );\n }\n\n const config = getAgentConfigIn(registry, resolvedType);\n // Foreground regardless of `backgroundByDefault` \u2014 see the reasoning on\n // ResolveOptions. An explicit `true` here still opts in.\n const invocation = resolveAgentInvocationConfig(config, params, {\n worktreeAllowed: isWorktreeIsolationEnabled(),\n defaultRunInBackground: false,\n });\n const selection = selectModel({\n homeDir: context.homeDir,\n agentType: resolvedType, definitionModel: config?.model, paramModel: params.model,\n parentModel: ctx.model, registry: ctx.modelRegistry, cwd: context.configCwd, agentLabel: config?.displayName,\n });\n if (typeof selection === \"string\") return textResult(selection, true);\n const model = selection.model;\n\n // The whole branch shares the root session's transcript directory; read it\n // off the owning parent rather than this child session's own id.\n const rootSessionId = context.manager.getRecord(context.parentAgentId)?.rootSessionId;\n const childDepth = context.depth + 1;\n const options: NestedSpawnOptions = {\n homeDir: context.homeDir,\n description: params.description,\n model,\n modelSelection: selection,\n maxTurns: invocation.maxTurns,\n isolated: invocation.isolated,\n inheritContext: invocation.inheritContext,\n thinkingLevel: invocation.thinking,\n isolation: invocation.isolation,\n invocation: {\n thinking: invocation.thinking,\n maxTurns: invocation.maxTurns,\n isolated: invocation.isolated,\n inheritContext: invocation.inheritContext,\n isolation: invocation.isolation,\n },\n // Nested children are hidden from every reporting surface, so their spend\n // would otherwise be unattributable. Fold it into every ancestor's record:\n // the top-level one appears in lifecycle events, completion notifications,\n // and `/agents`, and those all read `lifetimeUsage`. The whole chain is\n // walked, not just the immediate parent \u2014 a spawn callback only fires for\n // that child's OWN turns, so stopping at one level would hide a\n // great-grandchild from the only record anyone can see. (The live\n // widget/fleet counters read their own per-agent activity tracker, which\n // still sees only the top-level agent's own turns.)\n onAssistantUsage: (usage) => {\n for (let id: string | undefined = context.parentAgentId; id !== undefined; ) {\n const ancestor = context.manager.getRecord(id);\n if (!ancestor) break;\n addUsage(ancestor.lifetimeUsage, usage);\n id = ancestor.parentAgentId;\n }\n },\n depth: childDepth,\n parentAgentId: context.parentAgentId,\n maxSubagentDepth: context.maxSubagentDepth,\n configCwd: context.configCwd,\n configProjectTrusted: context.projectTrusted,\n rootSessionId,\n };\n\n // Transcript wiring, same gate as the top-level path: the child's\n // `output_transcript` frontmatter wins, else the project default. Without\n // it a nested run leaves no artifact but the string it returned \u2014 the\n // parent's own transcript records the call and the answer, never the tool\n // calls in between, which is exactly what a misbehaving child needs to\n // explain itself. Filed under the ROOT session and this branch's config\n // root, so a nested transcript lands in the same `tasks/` directory as its\n // ancestors' rather than in a directory of its own.\n const transcriptSessionId =\n rootSessionId !== undefined && (config?.outputTranscript ?? getOutputTranscriptDefault())\n ? rootSessionId\n : undefined;\n let childId: string | undefined;\n const attachTranscript = (id: string): void => {\n childId = id;\n if (transcriptSessionId === undefined) return;\n const rec = context.manager.getRecord(id);\n if (!rec) return;\n rec.outputFile = createOutputFilePath(context.configCwd, id, transcriptSessionId);\n writeInitialEntry(rec.outputFile, id, params.prompt, ctx.cwd);\n };\n options.onSessionCreated = (session) => {\n const rec = childId === undefined ? undefined : context.manager.getRecord(childId);\n if (rec?.outputFile && childId !== undefined) {\n rec.outputCleanup = streamToOutputFile(session, rec.outputFile, childId, ctx.cwd);\n }\n };\n\n // `ctx` is forwarded to the manager unmodified, never captured at tool-build\n // time: each AgentSession builds its own ExtensionRunner from that session's\n // cwd/sessionManager/modelRegistry, so this is the CHILD's context. Capturing\n // one earlier would silently give a grandchild the wrong worktree base, the\n // wrong conversation under inherit_context, and the wrong inherited model.\n //\n // spawn() throws on strict worktree-isolation failure and cwd validation \u2014\n // report it as a tool error, like the top-level Agent tool does, instead of\n // letting it escape into the child's turn.\n try {\n const { record } = await context.manager.spawnAndWait(\n context.pi,\n ctx,\n resolvedType,\n params.prompt,\n { ...options, signal, onPrepare: attachTranscript },\n );\n return textResult(formatRecord(record, \"inline\"), record.status === \"error\");\n } catch (err) {\n return textResult(errorMessage(err), true);\n }\n },\n });\n\n const resultTool = defineTool({\n name: NESTED_TOOL_NAMES[1],\n label: \"Get Nested Agent Result\",\n description: \"Check or wait for a background nested agent owned by this parent.\",\n parameters: Type.Object({\n agent_id: Type.String(),\n wait: Type.Optional(Type.Boolean()),\n }),\n execute: async (_toolCallId, params, signal) => {\n const record = context.manager.getRecord(params.agent_id);\n if (!ownsRecord(record, context.parentAgentId)) {\n return textResult(`Nested agent not found or not owned by this parent: \"${params.agent_id}\".`, true);\n }\n // Wait for completion if requested. Cancellation (e.g. the parent's tool\n // call is aborted) stops only this wait; the nested child keeps running and\n // stays unconsumed. Queued records have no promise until the manager starts\n // them, so poll \u2014 abortably \u2014 until they leave the queue, then await.\n if (params.wait && (record.status === \"queued\" || record.status === \"running\")) {\n while (record.status === \"queued\") {\n await abortable(new Promise<void>(resolve => setTimeout(resolve, 250)), signal);\n }\n if (record.promise) await abortable(record.promise, signal);\n }\n return textResult(formatRecord(record, \"fetched\"), record.status === \"error\");\n },\n });\n\n const steerTool = defineTool({\n name: NESTED_TOOL_NAMES[2],\n label: \"Steer Nested Agent\",\n description: \"Send guidance to a running nested agent owned by this parent.\",\n parameters: Type.Object({\n agent_id: Type.String(),\n message: Type.String(),\n }),\n execute: async (_toolCallId, params) => {\n const record = context.manager.getRecord(params.agent_id);\n if (!ownsRecord(record, context.parentAgentId) || record.status !== \"running\") {\n return textResult(`Running nested agent not found or not owned by this parent: \"${params.agent_id}\".`, true);\n }\n // Session not ready yet \u2014 queue the steer. The manager flushes pending\n // steers when the session is created (same contract as the top-level tool).\n if (!record.session) {\n if (!record.pendingSteers) record.pendingSteers = [];\n record.pendingSteers.push(params.message);\n return textResult(`Steering message queued for nested agent ${params.agent_id}.`);\n }\n try {\n await record.session.steer(params.message);\n } catch (err) {\n return textResult(`Failed to steer nested agent: ${err instanceof Error ? err.message : String(err)}`, true);\n }\n return textResult(`Steering message sent to nested agent ${params.agent_id}.`);\n },\n });\n\n const stopTool = defineTool({\n name: NESTED_TOOL_NAMES[3],\n label: \"Stop Nested Agent\",\n description: \"Stop a running or queued nested agent owned by this parent. It ends with status `stopped` before its next tool call.\",\n parameters: Type.Object({\n agent_id: Type.String(),\n }),\n execute: async (_toolCallId, params) => {\n const record = context.manager.getRecord(params.agent_id);\n if (!ownsRecord(record, context.parentAgentId) || (record.status !== \"running\" && record.status !== \"queued\")) {\n return textResult(`Running nested agent not found or not owned by this parent: \"${params.agent_id}\".`, true);\n }\n context.manager.abort(record.id, \"parent\");\n return textResult(`Nested agent ${params.agent_id} stopped.`);\n },\n });\n\n return [agentTool, resultTool, steerTool, stopTool];\n}\n", "/**\n * abortable.ts \u2014 race a promise against an AbortSignal without cancelling the\n * underlying work.\n *\n * Used by the `get_subagent_result` wait paths (top-level and nested): pressing\n * Esc cancels only the caller's wait; the background child keeps running and its\n * result stays unconsumed. The listener is removed on every settle path so the\n * signal accumulates no handlers, and a late settlement of the wrapped promise\n * after an abort is absorbed as a no-op (no unhandled rejection).\n */\n\n/** Await a promise until it settles or the caller cancels, without aborting the underlying work. */\nexport function abortable<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return promise;\n if (signal.aborted) return Promise.reject(signal.reason);\n\n return new Promise<T>((resolve, reject) => {\n let settled = false;\n const cleanup = () => signal.removeEventListener(\"abort\", onAbort);\n // The listener is removed on every settle path, so abort can only fire while pending.\n const onAbort = () => {\n settled = true;\n cleanup();\n reject(signal.reason);\n };\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n promise.then(\n (value) => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(value);\n },\n (error: unknown) => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(error);\n },\n );\n });\n}\n", "/**\n * custom-agents.ts \u2014 Load user-defined agents from project (.pi/agents/, plus the shared .agents/agents/ workspace) and global ($PI_CODING_AGENT_DIR/agents/, default ~/.pi/agent/agents/) locations, plus any installed pi package that declares them (see package-resources.ts).\n */\n\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport { parseFrontmatter } from \"@earendil-works/pi-coding-agent\";\nimport { BUILTIN_TOOL_NAMES } from \"./agent-types.js\";\nimport { errorMessage } from \"./error-message.js\";\nimport { resolveAgentDir } from \"./home-paths.js\";\nimport {\n isPackageResourceExcluded,\n isProjectTrusted,\n MAX_PACKAGE_RESOURCE_BYTES,\n packageAgentDirs,\n packageAgentFiles,\n} from \"./package-resources.js\";\nimport type { AgentConfig, IsolationMode, MemoryScope, ThinkingLevel } from \"./types.js\";\n\n/**\n * The one thing a declared `name:` may not contain, matching Claude Code\n * exactly: it reserves `:` for plugin-scoped identifiers (`my-plugin:reviewer`)\n * and refuses to load a file whose name uses one.\n *\n * Nothing else is rejected. Claude Code's docs describe names as \"lowercase\n * letters and hyphens\", but that is guidance \u2014 the only stated load failure is\n * the colon, so `name: Code Reviewer` must work here too. (The stricter\n * letters/digits/underscore/hyphen regex in Claude Code applies to the Agent\n * tool's spawn-time `name` parameter, which is a different field.) Mixed case\n * has to be allowed regardless: the built-in types `Explore` and `Plan` use it,\n * and a file must be able to override one.\n */\nconst RESERVED_IN_TYPE = \":\";\n\n/** Where an agent file was found. Widens `AgentConfig.source` for the loader. */\ntype AgentSource = \"project\" | \"global\" | \"package\";\n\n/** Answers whether a `!` entry in some package manifest excludes this path. */\ntype Excluder = (path: string) => boolean;\n\n/**\n * Overrides for the package tier. The gate and project-trust state normally come\n * from the session values in package-resources.ts, so these exist for tests and\n * for a caller that has to pin a scan it already performed.\n */\nexport interface LoadCustomAgentsOptions {\n /** Explicit package directories, bypassing discovery. */\n packageDirs?: string[];\n /** Explicit package files, bypassing discovery. */\n packageFiles?: string[];\n /** Explicit `!` exclusion predicate, bypassing discovery. */\n packageExcluded?: Excluder;\n /**\n * Whether pi trusts the project at `cwd`. Gates the project roots and, for\n * discovered packages, the project's `.pi/settings.json`. Omitted falls back to\n * the session state in package-resources.ts, which is untrusted until pi's\n * answer is recorded.\n */\n projectTrusted?: boolean;\n /** Home directory for the default global agent directory. Defaults at call time. */\n homeDir?: string;\n}\n\n/**\n * Scan for custom agent .md files from multiple locations.\n * Discovery hierarchy (higher priority wins):\n * 1. Project: <cwd>/.pi/agents/*.md (authoritative \u2014 also where /agents writes)\n * 2. Workspace: <cwd>/.agents/agents/*.md (shared cross-tool .agents workspace, read-only)\n * 3. Global: $PI_CODING_AGENT_DIR/agents/*.md (default: ~/.pi/agent/agents/*.md)\n * 4. Package: paths declared by an installed pi package (read-only)\n *\n * The two project roots are project-supplied content and load only when pi\n * trusts the project (`opts.projectTrusted`, else the session state). Untrusted,\n * they are not even read: they cannot override a global or package agent, and a\n * malformed file in them neither warns nor, under `strict`, throws. Global agents\n * and globally configured packages are unaffected; packages configured only by\n * the project's `.pi/settings.json` are gated by the same decision.\n *\n * Project-level agents override global ones with the same name. On a name clash\n * between the two project locations, .pi/agents wins \u2014 .pi stays the project\n * authority; .agents/agents is an additional read location.\n * Any name is allowed \u2014 names matching defaults (e.g. \"Explore\") override them.\n *\n * Package agents load *first*, so everything the user or project wrote outranks\n * them. That is what makes them safe to adopt: a package can offer a `reviewer`,\n * and a `.pi/agents/reviewer.md` silently takes it back. It mirrors pi's own\n * resource precedence, where package-provided skills rank below every user and\n * project one, and Claude Code's, where a plugin agent is the lowest tier.\n *\n * An agent's type comes from its frontmatter `name:`, falling back to the\n * filename \u2014 Claude Code's rule, where \"the filename doesn't have to match\".\n * Because the type is now declared rather than derived from a unique path, two\n * files can claim the same one; the later load wins, as it always has for a\n * filename clash, and `warnSkippedOverride` reports the substitution.\n */\nexport function loadCustomAgents(\n cwd: string,\n strict = false,\n opts: LoadCustomAgentsOptions = {},\n): Map<string, AgentConfig> {\n const globalDir = join(resolveAgentDir(opts.homeDir), \"agents\");\n const workspaceProjectDir = join(cwd, \".agents\", \"agents\");\n const projectDir = join(cwd, \".pi\", \"agents\");\n\n const projectTrusted = opts.projectTrusted ?? isProjectTrusted();\n const discovery = { projectTrusted, homeDir: opts.homeDir };\n const pkgDirs = opts.packageDirs ?? packageAgentDirs(cwd, discovery);\n const pkgFiles = opts.packageFiles ?? packageAgentFiles(cwd, discovery);\n // `!./agents/wip.md` alongside `./agents` excludes one file out of a directory\n // that is only enumerated here, so the check has to run per file.\n const excluded: Excluder = opts.packageExcluded ?? (path => isPackageResourceExcluded(path, cwd, \"agents\", discovery));\n\n const agents = new Map<string, AgentConfig>();\n for (const dir of pkgDirs) loadFromDir(dir, agents, \"package\", strict, excluded); // lowest priority\n for (const file of pkgFiles) loadOneFile(file, agents, \"package\", strict);\n loadFromDir(globalDir, agents, \"global\", strict);\n if (projectTrusted) {\n loadFromDir(workspaceProjectDir, agents, \"project\", strict); // shared workspace\n loadFromDir(projectDir, agents, \"project\", strict); // highest priority (overwrites)\n }\n\n warnedLastLoad = warnedThisLoad;\n warnedThisLoad = new Set();\n return agents;\n}\n\n/** Load agent configs from a directory into the map, skipping any `excluded` path. */\nfunction loadFromDir(\n dir: string,\n agents: Map<string, AgentConfig>,\n source: AgentSource,\n strict: boolean,\n excluded?: Excluder,\n): void {\n if (!existsSync(dir)) return;\n\n let files: string[];\n try {\n files = readdirSync(dir).filter(f => f.endsWith(\".md\"));\n } catch {\n return;\n }\n\n for (const file of files) {\n const path = join(dir, file);\n if (excluded?.(path)) continue;\n loadOneFile(path, agents, source, strict);\n }\n}\n\n/**\n * Load one agent file into the map.\n *\n * Split out of `loadFromDir` because a package manifest may name an individual\n * `.md` rather than a directory, and because the size guard below has to apply\n * to both paths.\n */\nfunction loadOneFile(path: string, agents: Map<string, AgentConfig>, source: AgentSource, strict: boolean): void {\n const filenameType = basename(path, \".md\");\n\n // Package files are third-party content read on every `Agent` call, so a\n // pathological one is skipped rather than pulled into the session. Claude\n // Code applies the same 1 MB ceiling to plugin-provided agents. Local files\n // are the user's own and stay unbounded, as they always have been.\n if (source === \"package\" && !withinSizeLimit(path)) {\n warnIfNew(`Skipping package agent ${path}: not a regular file, or larger than ${MAX_PACKAGE_RESOURCE_BYTES} bytes.`);\n return;\n }\n\n // `strict` is deliberately not passed for a package file. Failing activation\n // over a broken agent file is right for a checked-in `.pi/agents/` \u2014 the point\n // is that a repo's own file cannot silently fall through to a same-named one\n // elsewhere. A file inside a third-party package is not the user's to fix, and\n // one bad `.md` in any installed package would otherwise stop pi from\n // starting at all. Warn and skip, as for a non-strict local file.\n const parsed = readAgentFile(path, strict && source !== \"package\");\n if (!parsed) {\n warnSkippedOverride(filenameType, agents);\n return;\n }\n const { frontmatter: fm, body } = parsed;\n\n // Claude Code's rule: `name:` IS the agent type, and the filename need not\n // match. Absent, the filename stands in \u2014 Claude Code requires the field,\n // but most files here predate it and must keep loading.\n const declared = str(fm.name)?.trim();\n if (declared?.includes(RESERVED_IN_TYPE)) {\n // Refusing beats silently substituting: the file would otherwise load\n // under its filename, so `Agent({subagent_type})` would succeed against\n // an agent whose declared identity nothing honoured.\n warnIfNew(\n `Agent file ${path} declares name \"${declared}\", which contains \"${RESERVED_IN_TYPE}\" \u2014 reserved for `\n + \"plugin-scoped identifiers. Rename it, or move the label to `display_name:`. Skipping.\",\n );\n // No `warnSkippedOverride`: this file would have registered under its\n // *declared* name, which nothing else can hold (a colon keeps it out of\n // the registry), so it shadowed nothing. Passing the filename instead\n // would report a substitution of an unrelated agent that never happened.\n return;\n }\n // `||`, not `??`: a quoted empty or all-whitespace `name:` would otherwise\n // register the agent under the empty type \u2014 unspawnable, and it takes the\n // filename-derived one down with it.\n const name = declared || filenameType;\n\n const { builtinToolNames, extSelectors } = parseToolsField(fm.tools);\n\n agents.set(name, {\n name,\n // Only `display_name` now: `name` is the type, and `getConfig` already\n // falls back to the type when no label is set \u2014 so a Claude Code file\n // with `name: code-reviewer` still badges as \"code-reviewer\".\n displayName: str(fm.display_name),\n color: str(fm.color),\n description: str(fm.description) ?? name,\n builtinToolNames,\n extSelectors,\n disallowedTools: csvListOptional(fm.disallowed_tools),\n extensions: inheritField(fm.extensions ?? fm.inherit_extensions),\n excludeExtensions: csvListOptional(fm.exclude_extensions),\n skills: inheritField(fm.skills ?? fm.inherit_skills),\n model: str(fm.model),\n thinking: str(fm.thinking) as ThinkingLevel | undefined,\n maxTurns: nonNegativeInt(fm.max_turns),\n persistSession: fm.persist_session != null ? fm.persist_session === true : undefined,\n outputTranscript: fm.output_transcript != null ? fm.output_transcript !== false : undefined,\n sessionDir: str(fm.session_dir),\n allowedSubagents: parseAllowedSubagents(fm.allowed_subagents),\n systemPrompt: body.trim(),\n promptMode: fm.prompt_mode === \"append\" ? \"append\" : \"replace\",\n inheritContext: fm.inherit_context != null ? fm.inherit_context === true : undefined,\n runInBackground: fm.run_in_background != null ? fm.run_in_background === true : undefined,\n isolated: fm.isolated != null ? fm.isolated === true : undefined,\n memory: parseMemory(fm.memory),\n isolation: parseIsolation(fm.isolation),\n enabled: fm.enabled !== false, // default true; explicitly false disables\n source,\n sourcePath: path,\n });\n}\n\n/**\n * True when `path` is a regular file within the package-resource size ceiling.\n *\n * Only applied to package-provided files: they arrive from a third party and are\n * re-read on every `Agent` call, so a 500 MB `.md` \u2014 or a fifo that never ends \u2014\n * must not be reachable from a spawn. A stat failure counts as \"not within\",\n * because the alternative is reading something we could not describe.\n */\nfunction withinSizeLimit(path: string): boolean {\n try {\n const stat = statSync(path);\n return stat.isFile() && stat.size <= MAX_PACKAGE_RESOURCE_BYTES;\n } catch {\n return false;\n }\n}\n\n/**\n * Read and parse one agent file, or warn and return undefined for the caller to\n * skip. One bad file must not take the whole extension down with it \u2014 an\n * unparseable `.md` used to abort activation, so pi exited before the TUI.\n *\n * The path is as much of the fix as the recovery: a bare YAML error (\"line 2,\n * column 14\") is unactionable when agents come from three directories at once,\n * and the only other symptom is `Unknown agent type`, which reads like a typo.\n *\n * Under `strict` the same failure rethrows, still naming the path, so callers\n * that opted into failing closed stop rather than run a substituted agent.\n */\n/**\n * Parse an agent file's frontmatter, tolerating a leading UTF-8 BOM.\n *\n * Editors across the Windows/CJK world write UTF-8 with a BOM by default, and\n * pi's parser did not look past one before 0.84.3: the fence never matched, so\n * the frontmatter came back empty and the *whole file* \u2014 YAML and all \u2014 became\n * the body. An agent authored that way silently lost every field. `tools: none`\n * going missing is the sharp edge: the agent registers with the default\n * toolset rather than none, which is a wider grant than its author wrote.\n *\n * Stripped here rather than detected per pi version, because this is the only\n * place agent files are read and the BOM is a file-encoding artifact, not\n * content \u2014 normalising it at the boundary keeps one behaviour across the whole\n * supported peer range instead of forking on what happens to be installed.\n */\nexport function parseAgentFrontmatter<T extends Record<string, unknown>>(content: string): { frontmatter: T; body: string } {\n return parseFrontmatter<T>(content.startsWith(\"\\uFEFF\") ? content.slice(1) : content);\n}\n\nfunction readAgentFile(path: string, strict: boolean): { frontmatter: Record<string, unknown>; body: string } | undefined {\n try {\n return parseAgentFrontmatter<Record<string, unknown>>(readFileSync(path, \"utf-8\"));\n } catch (err) {\n const reason = errorMessage(err);\n if (strict) throw new Error(`${path}: ${reason}`);\n warnIfNew(`Skipping agent file ${path}: ${reason}`);\n return undefined;\n }\n}\n\n/**\n * A skipped file that was overriding an already-loaded agent leaves the name\n * pointing at a *different* file \u2014 its own prompt, model and tools. Nothing\n * downstream can flag that: unlike an unknown type, the `Agent` call succeeds.\n */\nfunction warnSkippedOverride(name: string, agents: Map<string, AgentConfig>): void {\n const surviving = agents.get(name);\n // Nothing shadowed, or what it shadowed is disabled: dispatch refuses the type\n // either way (see resolveEnabledTypeIn), so there is no substitution to report.\n if (!surviving?.sourcePath || surviving.enabled === false) return;\n warnIfNew(`Agent \"${name}\" now loads from ${surviving.sourcePath} instead`);\n}\n\nlet warnedLastLoad = new Set<string>();\nlet warnedThisLoad = new Set<string>();\n\n/**\n * Agents reload on activation and again on every `Agent` call, so an unchanged\n * problem would re-warn all session \u2014 over a painted TUI, since pi does not\n * redirect console output. Compare against the previous load rather than every\n * load ever, so a file that is fixed and then broken again still reports.\n */\nfunction warnIfNew(message: string): void {\n warnedThisLoad.add(message);\n if (warnedLastLoad.has(message)) return;\n console.warn(`[pi-subagents] ${message}`);\n}\n\n// ---- Field parsers ----\n// All follow the same convention: omitted \u2192 default, \"none\"/empty \u2192 nothing, value \u2192 exact.\n\n/** Extract a string or undefined. */\nfunction str(val: unknown): string | undefined {\n return typeof val === \"string\" ? val : undefined;\n}\n\n/** Extract a non-negative integer or undefined. 0 means unlimited for max_turns. */\nfunction nonNegativeInt(val: unknown): number | undefined {\n return typeof val === \"number\" && val >= 0 ? val : undefined;\n}\n\n/**\n * Parse a raw CSV field value into items, or undefined if absent/empty/\"none\".\n */\nfunction parseCsvField(val: unknown): string[] | undefined {\n if (val === undefined || val === null) return undefined;\n const s = String(val).trim();\n if (!s || s === \"none\") return undefined;\n const items = s.split(\",\").map(t => t.trim()).filter(Boolean);\n return items.length > 0 ? items : undefined;\n}\n\n/**\n * Parse the nested-delegation allowlist. Single field, default-off:\n * omitted/empty/\"none\"/`false` \u2192 undefined (no nested tools); \"all\"/\"*\"/`true`\n * \u2192 \"all\" (any enabled agent); csv \u2192 only the listed types.\n *\n * Booleans are accepted because `extensions:`/`skills:` take them and users\n * generalize: without this, YAML's `true` stringifies into an agent type\n * literally named \"true\", so the tools appear and every spawn is refused.\n */\nfunction parseAllowedSubagents(val: unknown): \"all\" | string[] | undefined {\n if (typeof val === \"boolean\") return val ? \"all\" : undefined;\n const items = parseCsvField(val);\n if (!items) return undefined;\n return items.some(i => i === \"*\" || i.toLowerCase() === \"all\") ? \"all\" : items;\n}\n\n/**\n * Parse a comma-separated list field with defaults.\n * omitted \u2192 defaults; \"none\"/empty \u2192 []; csv \u2192 listed items.\n */\nfunction csvList(val: unknown, defaults: string[]): string[] {\n if (val === undefined || val === null) return defaults;\n return parseCsvField(val) ?? [];\n}\n\n/**\n * Partition the `tools:` CSV into the built-in tool allowlist and raw `ext:` selectors.\n * `*` (and the case-insensitive alias `all`, for `tools: all`) expands to all\n * built-ins; plain entries are built-in names; `ext:` entries are extension-tool\n * selectors parsed later by the runner. omitted \u2192 all built-ins, no selectors.\n * `tools:` present with only `ext:` entries \u2192 zero built-ins (use `*`).\n */\nfunction parseToolsField(val: unknown): { builtinToolNames: string[]; extSelectors: string[] | undefined } {\n const entries = csvList(val, BUILTIN_TOOL_NAMES);\n const isWildcard = (e: string) => e === \"*\" || e.toLowerCase() === \"all\";\n const hasWildcard = entries.some(isWildcard);\n const plain = entries.filter(e => !isWildcard(e) && !e.startsWith(\"ext:\"));\n const extEntries = entries.filter(e => e.startsWith(\"ext:\"));\n return {\n builtinToolNames: hasWildcard ? [...new Set([...BUILTIN_TOOL_NAMES, ...plain])] : plain,\n extSelectors: extEntries.length > 0 ? extEntries : undefined,\n };\n}\n\n/**\n * Parse an optional comma-separated list field.\n * omitted \u2192 undefined; \"none\"/empty \u2192 undefined; csv \u2192 listed items.\n */\nfunction csvListOptional(val: unknown): string[] | undefined {\n return parseCsvField(val);\n}\n\n/**\n * Parse a memory scope field.\n * omitted \u2192 undefined; \"user\"/\"project\"/\"local\" \u2192 MemoryScope.\n */\nfunction parseMemory(val: unknown): MemoryScope | undefined {\n if (val === \"user\" || val === \"project\" || val === \"local\") return val;\n return undefined;\n}\n\n/**\n * Parse the `isolation` frontmatter field.\n *\n * `off` is kept as a value rather than folded into `undefined` because the two\n * do not mean the same thing here: agent config outranks tool-call params, so\n * `off` vetoes a caller's `worktree` while an absent field lets it through.\n *\n * pi's frontmatter parser is not YAML 1.1 \u2014 bare `off` and `no` arrive as\n * strings and only `false` becomes a boolean \u2014 so all three spellings are\n * accepted rather than leaving an author's intent silently dropped. Anything\n * else stays `undefined`, as before.\n */\nfunction parseIsolation(val: unknown): IsolationMode | undefined {\n if (val === \"worktree\") return \"worktree\";\n if (val === \"off\" || val === \"none\" || val === \"no\" || val === false) return \"off\";\n return undefined;\n}\n\n/**\n * Parse an inherit field (extensions, skills).\n * omitted/true \u2192 true (inherit all); false/\"none\"/empty \u2192 false; csv \u2192 listed names.\n */\nfunction inheritField(val: unknown): true | string[] | false {\n if (val === undefined || val === null || val === true) return true;\n if (val === false || val === \"none\") return false;\n const items = csvList(val, []);\n return items.length > 0 ? items : false;\n}\n", "/**\n * error-message.ts \u2014 the text a caught value reports.\n *\n * `catch` binds `unknown`: an `Error` gives its message, and anything else a\n * caller threw (a string, a rejected non-Error) is stringified as-is.\n */\n\n/** The message of `error` when it is an `Error`, else `String(error)`. */\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n", "/**\n * package-resources.ts \u2014 Discover agent and workflow files that installed pi\n * packages declare in their `package.json`.\n *\n * ## Why this exists\n *\n * Pi already ships four resource types inside packages \u2014 `extensions`, `skills`,\n * `prompts`, `themes` \u2014 resolved from a `pi` manifest key or, when there is no\n * `pi` key at all, from convention directories. Subagents are *our* concept, so\n * pi knows nothing about them and a package author's only option was to copy\n * `.md` files into `.pi/agents/` on every container start (#109).\n *\n * ## The contract\n *\n * Two-sided, deliberately:\n *\n * 1. The package author opts in by naming the paths in `package.json`.\n * 2. The user opts in by running `pi install`, which is already the trust\n * decision for that package \u2014 pi executes its `extensions/` and injects its\n * `skills/` into the system prompt with no further prompt. A declared `.md`\n * agent is strictly less privileged than either, so it rides the boundary\n * the user already crossed rather than inventing a second one.\n *\n * There is deliberately **no convention-directory fallback**. Pi scans `skills/`\n * only when a package has no `pi` key whatsoever; we never scan an undeclared\n * `agents/`. A package that happens to carry an `agents/` folder for some other\n * tool must not start contributing subagents to pi because it was installed for\n * an unrelated reason.\n *\n * ## Which packages are visible\n *\n * Only what pi itself has configured \u2014 `settings.json -> packages[]`, global and\n * project \u2014 read through pi's own `DefaultPackageManager.listConfiguredPackages()`.\n * That call is synchronous, pure, and never installs anything; it also resolves\n * npm / git / local install roots, pnpm global roots and legacy fallbacks, which\n * is why it is worth borrowing rather than reimplementing.\n *\n * `node_modules` is never scanned. Being a transitive dependency of the user's\n * project means nothing here \u2014 the same rule pi applies to itself.\n *\n * ## Accepted manifest spellings\n *\n * All four mean the same thing. The `pi-subagents` top-level key exists for\n * cross-compatibility with `nicobailon/pi-subagents`, which reads the same two\n * shapes, so a package author writes one manifest that works on either extension.\n *\n * \"pi\": { \"subagents\": { \"agents\": [\"./agents\"], \"workflows\": [\"./flows\"] } }\n * \"pi\": { \"subagents\": [\"./agents\"] } // shorthand for { agents }\n * \"pi-subagents\": { \"agents\": [\"./agents\"] }\n * \"pi-subagents\": [\"./agents\"] // shorthand for { agents }\n *\n * Adding `pi.subagents` is safe for pi itself: its `readPiManifest` reads only\n * `extensions`/`skills`/`prompts`/`themes` and ignores every other key.\n */\n\nimport { existsSync, readFileSync, realpathSync, statSync } from \"node:fs\";\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport { DefaultPackageManager, SettingsManager } from \"@earendil-works/pi-coding-agent\";\nimport { normalizeHomePath, resolveAgentDir } from \"./home-paths.js\";\n\n/** Resource kinds a package may declare. Agents are `.md`, workflows are `.js`. */\nexport type PackageResourceKind = \"agents\" | \"workflows\";\n\n/** File extension scanned for each kind, mirroring the local roots for each. */\nconst KIND_EXTENSION: Record<PackageResourceKind, string> = {\n agents: \".md\",\n workflows: \".js\",\n};\n\n/**\n * Per-file size ceiling for package-provided resources, matching Claude Code's\n * plugin-agent limit. These files come from third-party packages and are read\n * eagerly on every agent load; a pathological one should be skipped, not\n * `readFileSync`'d into the session.\n */\nexport const MAX_PACKAGE_RESOURCE_BYTES = 1_048_576;\n\n/** One installed pi package that declared something we understand. */\nexport interface PiPackage {\n /** The settings source string, e.g. `npm:@foo/bar@1.0.0` or an absolute path. */\n source: string;\n /** `package.json` `name`, when the manifest could be read. */\n name?: string;\n /** Unscoped, lowercased short name (`@scope/foo` becomes `foo`) for allowlist matching. */\n shortName?: string;\n /** Which settings scope configured it. */\n scope: \"user\" | \"project\";\n /** Absolute path of the installed package root. */\n root: string;\n /**\n * What its manifest declared. Carried here rather than re-read downstream:\n * `listPiPackages` has to parse the manifest anyway to know whether the\n * package declares anything at all, and reading it twice would leave two\n * places that could disagree about what a package said.\n */\n declared: DeclaredEntries;\n}\n\n/**\n * The gate for one resource kind, as persisted in our settings:\n * `true` (default) = every declaring package, `false` = none, `string[]` =\n * only packages whose short name, full name, or source matches an entry.\n */\nexport type PackageGate = boolean | string[] | undefined;\n\nexport interface PackageDiscoveryOptions {\n /** Home directory for user settings and installed resources, resolved at call time. */\n homeDir?: string;\n /**\n * Pi's project-trust state for `cwd`, from `ctx.isProjectTrusted()`. When\n * false, `.pi/settings.json` is not read \u2014 so a package configured only by an\n * untrusted project is invisible to us, exactly as it is to pi. Omitted falls\n * back to the session state set by {@link setProjectTrusted}.\n */\n projectTrusted?: boolean;\n /** Gate override. Omitted falls back to the session state for the kind. */\n gate?: PackageGate;\n}\n\n// ---- Session state ----\n//\n// Held here rather than threaded through every caller, matching how the rest of\n// this extension carries session-wide settings (`setMaxSubagentDepth`,\n// `setWorktreeIsolationEnabled`, ...). The alternative was an options bag\n// travelling from `index.ts` through `resolveWorkflowScript`,\n// `resolveWorkflowSource`, `readSavedWorkflow` and `listSavedWorkflows` purely\n// so a gate could be consulted at the bottom.\n//\n// Both gates start `undefined`, which reads as `true`: absent settings mean\n// every declaring package contributes, matching pi's own default for the\n// resources it owns.\n\nlet agentsGate: PackageGate;\nlet workflowsGate: PackageGate;\n/**\n * Defaults to `false` \u2014 an extension activates before any session context\n * exists, and pi's persisted trust file is not a substitute for its canonical\n * answer (project trust events and `--approve`/`--noapprove` override it). Only\n * `ctx.isProjectTrusted()` on `session_start` raises it, via `setProjectTrusted`.\n */\nlet projectTrustedState = false;\n\n/** Apply the `packageAgents` setting. Drops the cache, since roots may change. */\nexport function setPackageAgentsGate(gate: PackageGate): void {\n agentsGate = gate;\n invalidatePackageCache();\n}\n\n/** Apply the `packageWorkflows` setting. Drops the cache, since roots may change. */\nexport function setPackageWorkflowsGate(gate: PackageGate): void {\n workflowsGate = gate;\n invalidatePackageCache();\n}\n\nexport function getPackageAgentsGate(): PackageGate {\n return agentsGate;\n}\n\nexport function getPackageWorkflowsGate(): PackageGate {\n return workflowsGate;\n}\n\n/**\n * Record pi's project-trust answer. Drops the cache when the answer changes,\n * since a project's `packages[]` becomes visible or invisible with it. A repeat\n * of the same answer is a no-op \u2014 `session_start` fires on every new, resumed\n * and forked session, and it has its own reason to invalidate.\n */\nexport function setProjectTrusted(trusted: boolean): void {\n if (projectTrustedState === trusted) return;\n projectTrustedState = trusted;\n invalidatePackageCache();\n}\n\n/**\n * Pi's project-trust answer as last recorded, `false` until one is. The loader\n * for project-supplied agent files reads this, so a missing answer fails closed.\n */\nexport function isProjectTrusted(): boolean {\n return projectTrustedState;\n}\n\n/** Reset every session-scoped value. Tests only \u2014 the extension never un-loads. */\nexport function resetPackageState(): void {\n agentsGate = undefined;\n workflowsGate = undefined;\n projectTrustedState = false;\n invalidatePackageCache();\n}\n\n/** What a package declared, after normalising the accepted spellings. */\nexport interface DeclaredEntries {\n agents?: string[];\n workflows?: string[];\n}\n\n/** Absolute paths a declaration resolved to, split by what the loader needs. */\nexport interface ResolvedResourcePaths {\n dirs: string[];\n files: string[];\n /**\n * Canonical paths of `!` entries. Kept separate from `dirs`/`files` rather\n * than subtracted from them because an exclusion usually names a file *inside*\n * an included directory, which is not enumerated until load time.\n */\n excluded: ReadonlySet<string>;\n}\n\n// ---- Manifest reading ----\n\n/** A string array, or undefined for anything else. Mirrors pi's `readPiManifest` strictness. */\nfunction stringArray(val: unknown): string[] | undefined {\n return Array.isArray(val) && val.every(e => typeof e === \"string\") ? (val as string[]) : undefined;\n}\n\n/**\n * Normalize one accepted spelling into `{ agents, workflows }`.\n * A bare array is the `agents` shorthand \u2014 the only kind that existed when the\n * shorthand was worth having, and the shape the other fork's docs show.\n */\nfunction normalizeDeclaration(val: unknown): DeclaredEntries | undefined {\n const asArray = stringArray(val);\n if (asArray) return { agents: asArray };\n if (!val || typeof val !== \"object\" || Array.isArray(val)) return undefined;\n const obj = val as Record<string, unknown>;\n const agents = stringArray(obj.agents);\n const workflows = stringArray(obj.workflows);\n if (!agents && !workflows) return undefined;\n return { agents, workflows };\n}\n\n/**\n * Read the subagent declaration out of a parsed `package.json`.\n *\n * `pi.subagents` wins over the top-level `pi-subagents` when a package carries\n * both \u2014 the pi-namespaced key is the primary spelling here, and a package that\n * writes both almost certainly means them to be identical anyway.\n */\nexport function readSubagentManifest(pkg: unknown): DeclaredEntries | undefined {\n if (!pkg || typeof pkg !== \"object\") return undefined;\n const obj = pkg as Record<string, unknown>;\n const piKey = obj.pi;\n if (piKey && typeof piKey === \"object\" && !Array.isArray(piKey)) {\n const nested = normalizeDeclaration((piKey as Record<string, unknown>).subagents);\n if (nested) return nested;\n }\n return normalizeDeclaration(obj[\"pi-subagents\"]);\n}\n\n/** Parse `<root>/package.json`, or undefined when it is missing or malformed. */\nfunction readPackageJson(root: string): Record<string, unknown> | undefined {\n try {\n const parsed: unknown = JSON.parse(readFileSync(join(root, \"package.json\"), \"utf-8\"));\n return parsed && typeof parsed === \"object\" ? (parsed as Record<string, unknown>) : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** `@scope/foo` becomes `foo`, lowercased. The name a user types in an allowlist. */\nexport function unscopedShortName(name: string): string {\n const short = name.startsWith(\"@\") ? name.slice(name.indexOf(\"/\") + 1) : name;\n return short.toLowerCase();\n}\n\n// ---- Path resolution ----\n\n/**\n * Canonical absolute path, resolving symlinks as far as the path exists.\n *\n * A plain `realpathSync` is not enough: an exclusion may name a file the package\n * does not ship yet, and a bare `resolve()` fallback would leave it uncanonical\n * \u2014 which on macOS means `/var/...` compared against a canonical `/private/var/...`\n * root, so the containment check below rejects it. Canonicalizing the nearest\n * existing ancestor and re-appending the rest keeps both sides comparable.\n */\nfunction realOrSelf(path: string): string {\n const abs = resolve(path);\n try {\n return realpathSync(abs);\n } catch {\n const parent = dirname(abs);\n return parent === abs ? abs : join(realOrSelf(parent), basename(abs));\n }\n}\n\n/**\n * True when `candidate` is inside `root`. Package manifests are third-party\n * input, so `\"../../.ssh\"` must not become a scanned directory \u2014 pi refuses the\n * same shape with \"Refusing to use path outside package install root\".\n *\n * Compared on canonical paths, because `..` is not the only way out: a symlinked\n * `agents/` pointing at `/etc` is textually inside the root, and `readdirSync`\n * follows it. Both sides are canonicalized so a package installed *under* a\n * symlink (`/var` \u2192 `/private/var` on macOS) still matches itself.\n */\nfunction isInside(root: string, candidate: string): boolean {\n const rel = relative(realOrSelf(root), realOrSelf(candidate));\n return rel !== \"\" && !rel.startsWith(\"..\") && !isAbsolute(rel);\n}\n\n/**\n * Resolve one manifest entry against the package root, returning the path only\n * when it stays inside the package and exists.\n *\n * Globs are deliberately not supported. Pi's own manifest expands them because\n * it resolves four resource types across arbitrary layouts; here the entries are\n * one or two directories, and a glob would mean walking a third-party tree to\n * answer. A directory or a file path covers the declared use cases.\n */\nfunction expandEntry(root: string, entry: string): string | undefined {\n const target = resolve(root, entry);\n if (!isInside(root, target) || !existsSync(target)) return undefined;\n return target;\n}\n\n/**\n * Resolve one kind's declared entries into concrete absolute paths inside the\n * package: directories to scan, and individual files.\n *\n * Split into `{ dirs, files }` rather than a flat list because the agent loader\n * takes directories (it does its own `readdirSync` and frontmatter handling),\n * while a manifest entry naming a single file has to be surfaced on its own.\n *\n * `!entry` marks an exclusion. Exact paths only \u2014 pi's own `!` is gitignore-style\n * glob negation, and globs are not supported here for the reason above.\n */\nexport function resolveDeclaredPaths(\n root: string,\n entries: string[] | undefined,\n kind: PackageResourceKind,\n): ResolvedResourcePaths {\n const dirs: string[] = [];\n const files: string[] = [];\n const excluded = new Set<string>();\n if (!entries) return { dirs, files, excluded };\n\n // Exclusions are collected first and stored canonically, so `!./agents/wip.md`\n // matches the same file however the loader spelled its way to it. They do not\n // have to exist: a package may exclude a path it ships conditionally.\n for (const entry of entries) {\n if (!entry.startsWith(\"!\")) continue;\n const target = resolve(root, entry.slice(1));\n if (isInside(root, target)) excluded.add(realOrSelf(target));\n }\n\n const ext = KIND_EXTENSION[kind];\n for (const entry of entries) {\n if (entry.startsWith(\"!\")) continue;\n const path = expandEntry(root, entry);\n if (!path || excluded.has(realOrSelf(path))) continue;\n let stat: ReturnType<typeof statSync>;\n try {\n stat = statSync(path);\n } catch {\n continue;\n }\n if (stat.isDirectory()) {\n if (!dirs.includes(path)) dirs.push(path);\n } else if (stat.isFile() && path.endsWith(ext) && !files.includes(path)) {\n files.push(path);\n }\n }\n return { dirs, files, excluded };\n}\n\n// ---- Package enumeration ----\n\ninterface ConfiguredPackageRow {\n source: string;\n scope: \"user\" | \"project\";\n installedPath?: string;\n}\n\n/**\n * Build a read-only view of pi's configured packages.\n *\n * Feature-detected rather than assumed: the peer range `>=1.1.0` is open-ended,\n * so a later pi that drops or renames this API contributes no packages instead\n * of failing activation.\n */\nfunction configuredPackages(cwd: string, projectTrusted: boolean, homeDir?: string): ConfiguredPackageRow[] {\n try {\n if (typeof DefaultPackageManager !== \"function\") return [];\n const agentDir = resolveAgentDir(homeDir);\n const settingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted });\n const manager = new DefaultPackageManager({ cwd, agentDir, settingsManager });\n if (typeof manager.listConfiguredPackages !== \"function\") return [];\n if (homeDir === undefined) return manager.listConfiguredPackages();\n // Pi's enumerator expands local package sources through its own ambient\n // home. Reuse its public installed-path resolver with normalized inputs,\n // preserving the original source for package-gate matching and diagnostics.\n const rows: ConfiguredPackageRow[] = [];\n for (const scope of [\"user\", \"project\"] as const) {\n const settings = scope === \"user\" ? settingsManager.getGlobalSettings() : settingsManager.getProjectSettings();\n for (const pkg of settings.packages ?? []) {\n const source = typeof pkg === \"string\" ? pkg : pkg.source;\n rows.push({ source, scope, installedPath: manager.getInstalledPath(normalizeHomePath(source, homeDir), scope) });\n }\n }\n return rows;\n } catch {\n return [];\n }\n}\n\n/**\n * Every installed pi package that declares subagent resources, in pi's own\n * order (global entries first, then project). Duplicates by root are collapsed \u2014\n * a package listed in both scopes is one package on disk.\n */\nexport function listPiPackages(cwd: string, projectTrusted = false, homeDir?: string): PiPackage[] {\n const seen = new Set<string>();\n const out: PiPackage[] = [];\n for (const entry of configuredPackages(cwd, projectTrusted, homeDir)) {\n const root = entry.installedPath;\n if (!root || seen.has(root)) continue;\n const manifest = readPackageJson(root);\n const declared = manifest ? readSubagentManifest(manifest) : undefined;\n if (!manifest || !declared) continue;\n seen.add(root);\n const name = typeof manifest.name === \"string\" ? manifest.name : undefined;\n out.push({\n source: entry.source,\n name,\n shortName: name ? unscopedShortName(name) : undefined,\n scope: entry.scope,\n root,\n declared,\n });\n }\n return out;\n}\n\n/**\n * Whether `pkg` passes the gate. `true`/omitted admits everything; an array\n * matches case-insensitively against the unscoped short name, the full package\n * name, or the settings source string \u2014 users reach for whichever of the three\n * they happen to have in front of them.\n */\nexport function packageAllowed(pkg: PiPackage, gate: PackageGate): boolean {\n if (gate === false) return false;\n if (gate === undefined || gate === true) return true;\n const candidates = new Set(\n [pkg.shortName, pkg.name?.toLowerCase(), pkg.source.toLowerCase()].filter(\n (v): v is string => typeof v === \"string\",\n ),\n );\n return gate.some(allowed => candidates.has(allowed.trim().toLowerCase()));\n}\n\n// ---- Caching ----\n\n/** An admitted package's install root and the name to show for it. */\ninterface PackageOwner {\n /** Normalized, so it compares against a normalized candidate path. */\n root: string;\n name: string;\n}\n\n/**\n * `loadCustomAgents` runs on activation and again on every `Agent` call, so an\n * uncached scan would re-read pi's settings and every package manifest per\n * spawn. What is cached is only the *root list* \u2014 which packages declare what \u2014\n * because that changes when settings change, not when a file is edited. The\n * agent files themselves are still re-read on every load, so editing a linked\n * package's agent still takes effect immediately.\n *\n * Keyed by cwd because nested subagents load from `context.configCwd`, which is\n * not necessarily the main session's directory, and by the gate because a\n * settings change must not be served a stale allowlist.\n */\ninterface CacheEntry {\n agents: ResolvedResourcePaths;\n workflows: ResolvedResourcePaths;\n /**\n * Every package the gate admitted, longest root first, so a path can be\n * traced back to the package that contributed it. Recorded during the scan\n * that already enumerated them rather than re-derived later: a second pass\n * would re-read pi's settings and every manifest, and could disagree with\n * this entry about which packages the gate let through.\n */\n owners: PackageOwner[];\n}\n\n/** A resolved-paths value with nothing in it. Fresh each call \u2014 callers get copies. */\nfunction emptyPaths(): ResolvedResourcePaths {\n return { dirs: [], files: [], excluded: new Set() };\n}\n\n/** A whole cache entry with nothing in it, for a gate that admits no package. */\nfunction emptyEntry(): CacheEntry {\n return { agents: emptyPaths(), workflows: emptyPaths(), owners: [] };\n}\nconst cache = new Map<string, CacheEntry>();\n\n/** Drop the memoized package scan. Called on `/reload` and after settings changes. */\nexport function invalidatePackageCache(): void {\n cache.clear();\n}\n\nfunction scan(cwd: string, projectTrusted: boolean, gate: PackageGate, homeDir?: string): CacheEntry {\n const entry = emptyEntry();\n for (const pkg of listPiPackages(cwd, projectTrusted, homeDir)) {\n if (!packageAllowed(pkg, gate)) continue;\n // The root is normalized here, not at lookup time: the declared paths below\n // go through `resolve(root, entry)`, so a root that arrived with a trailing\n // separator would never prefix-match the very paths it produced.\n //\n // `name` is absent only when the manifest had no usable `name` string; the\n // settings source (`npm:@foo/bar@1.0.0`) is the last resort, which is what\n // pi itself falls back to when it labels a package-provided resource.\n entry.owners.push({ root: resolve(pkg.root), name: pkg.name ?? pkg.shortName ?? pkg.source });\n for (const kind of [\"agents\", \"workflows\"] as const) {\n const resolvedPaths = resolveDeclaredPaths(pkg.root, pkg.declared[kind], kind);\n entry[kind].dirs.push(...resolvedPaths.dirs);\n entry[kind].files.push(...resolvedPaths.files);\n // One flat set across packages: an exclusion is an absolute path, so it\n // can only ever match inside the package that wrote it.\n for (const path of resolvedPaths.excluded) (entry[kind].excluded as Set<string>).add(path);\n }\n }\n // Longest root first, so a package installed inside another's `node_modules`\n // claims its own files rather than losing them to its host.\n entry.owners.sort((a, b) => b.root.length - a.root.length);\n return entry;\n}\n\nfunction cacheEntryFor(cwd: string, kind: PackageResourceKind, opts: PackageDiscoveryOptions): CacheEntry {\n const gate = opts.gate ?? (kind === \"agents\" ? agentsGate : workflowsGate);\n // An empty allowlist matches nothing, like `false` \u2014 see `sanitizePackageGate`\n // in settings.ts for why an empty array is kept rather than dropped.\n if (gate === false || (Array.isArray(gate) && gate.length === 0)) return emptyEntry();\n const projectTrusted = opts.projectTrusted ?? projectTrustedState;\n // `\\u0000` written as an escape, not a raw byte: a literal NUL makes this\n // whole file read as binary to grep, ripgrep and git, which silently drops\n // it from search results.\n const key = `${cwd}\\u0000${opts.homeDir ?? \"\"}\\u0000${resolveAgentDir(opts.homeDir)}\\u0000${projectTrusted ? 1 : 0}\\u0000${JSON.stringify(gate ?? true)}`;\n let hit = cache.get(key);\n if (!hit) {\n hit = scan(cwd, projectTrusted, gate, opts.homeDir);\n cache.set(key, hit);\n }\n return hit;\n}\n\nfunction resolved(cwd: string, kind: PackageResourceKind, opts: PackageDiscoveryOptions): ResolvedResourcePaths {\n return cacheEntryFor(cwd, kind, opts)[kind];\n}\n\n/**\n * Name of the installed package that provided `path`, or undefined when no\n * admitted package owns it. What `/agents` shows so a package agent can name its\n * origin, and what a user needs in order to write a `packageAgents` allowlist.\n *\n * `kind` selects which gate to consult, because the two are configured\n * separately: a package may be admitted for agents but not for workflows.\n *\n * A plain prefix test is enough. `resolveDeclaredPaths` builds every declared\n * path as `resolve(root, entry)` without canonicalizing it \u2014 only the\n * containment check and the exclusion set go through `realOrSelf` \u2014 so a\n * `sourcePath` the loader derived from one is textually inside the root it came\n * from. The `sep` anchor keeps `\u2026/node_modules/foo` from claiming\n * `\u2026/node_modules/foo-bar`.\n */\nexport function packageNameForPath(\n path: string,\n cwd: string,\n kind: PackageResourceKind = \"agents\",\n opts: PackageDiscoveryOptions = {},\n): string | undefined {\n const abs = resolve(path);\n return cacheEntryFor(cwd, kind, opts).owners.find(\n o => abs === o.root || abs.startsWith(o.root + sep),\n )?.name;\n}\n\n/**\n * Directories of package-declared agent files, lowest-precedence first.\n * Fed to `loadCustomAgents` ahead of the global and project roots.\n */\nexport function packageAgentDirs(cwd: string, opts: PackageDiscoveryOptions = {}): string[] {\n // A copy: the cache holds this array for the rest of the session, so a caller\n // that sorted or spliced it would corrupt every later load.\n return [...resolved(cwd, \"agents\", opts).dirs];\n}\n\n/** Individually declared agent `.md` files (a manifest entry naming a file, not a directory). */\nexport function packageAgentFiles(cwd: string, opts: PackageDiscoveryOptions = {}): string[] {\n return [...resolved(cwd, \"agents\", opts).files];\n}\n\n/**\n * Whether a `!` entry in some package manifest excludes this path.\n *\n * Checked at load time rather than subtracted during resolution, because the\n * common exclusion \u2014 `[\"./agents\", \"!./agents/wip.md\"]` \u2014 names a file inside a\n * directory that is not enumerated until the loader reads it.\n */\nexport function isPackageResourceExcluded(\n path: string,\n cwd: string,\n kind: PackageResourceKind,\n opts: PackageDiscoveryOptions = {},\n): boolean {\n const excluded = resolved(cwd, kind, opts).excluded;\n return excluded.size > 0 && excluded.has(realOrSelf(path));\n}\n\n/**\n * Directories of package-declared workflow scripts, appended to\n * `savedWorkflowRoots` so a name resolves there last.\n */\nexport function packageWorkflowDirs(cwd: string, opts: PackageDiscoveryOptions = {}): string[] {\n return [...resolved(cwd, \"workflows\", opts).dirs];\n}\n\n/**\n * Individually declared workflow scripts, as `name -> absolute path`.\n *\n * A name lookup wants a directory, and a declared *file* has none \u2014 but standing\n * its parent directory in as a root would make every sibling `.js` resolvable,\n * so `workflows: [\"./one.js\"]` would quietly offer the package's other scripts\n * too, and `[\"./index.js\"]` would offer everything at the package root. That is\n * the opposite of the rule the whole feature rests on, that a package only\n * contributes what it names. An exact map keeps the declaration honest, and\n * matches how a declared agent file is already handled.\n *\n * Later entries lose a name clash, so a package's own directory-sourced script\n * is not displaced by a file entry from a package resolved after it.\n */\nexport function packageWorkflowFiles(cwd: string, opts: PackageDiscoveryOptions = {}): Map<string, string> {\n const out = new Map<string, string>();\n for (const path of resolved(cwd, \"workflows\", opts).files) {\n const name = basename(path, KIND_EXTENSION.workflows);\n if (!out.has(name)) out.set(name, path);\n }\n return out;\n}\n", "import { homedir } from \"node:os\";\nimport { resolve } from \"node:path\";\nimport { Type } from \"typebox\";\nimport type { AgentConfig, IsolationMode, ThinkingLevel } from \"./types.js\";\n\n/**\n * The model-facing `isolation` parameter, shared by the `Agent` tool and the\n * nested delegation tool so the two cannot drift.\n *\n * Shape matters more than wording here. As a single-value optional literal,\n * models that fill every optional parameter \u2014 the transcript on #231 shows one\n * emitting `resume: \"\"`, `schedule: \"\"` and `model: \"default\"` alongside it \u2014\n * had only `\"worktree\"` available to fill it with, and kept spawning worktrees\n * across three turns while their own reasoning said to omit the field. Every\n * other optional parameter has an inert filler; this one did not. `\"off\"` is\n * listed first and described as the default so the harmless value is the\n * obvious one to reach for.\n *\n * The wording tracks Claude Code's own `isolation` parameter, whose phrasing\n * models have the most exposure to: one description on the union rather than\n * per-value ones, opening \"Isolation mode.\", then a sentence per value in\n * schema order, each with its caveats in a trailing parenthetical. Two clauses\n * are ours, because our shape is not theirs \u2014 `\"off\"` has no counterpart there\n * (their enum is `worktree | remote`, so both of their values do something),\n * and neither does the uncommitted-work warning, which is the specific trap\n * #231 fell into. Deliberately absent is any \"only use a worktree when\u2026\"\n * restriction: Claude Code's `Agent` tool states the capability and stops, and\n * a second legal value is what lets a model decline one, not being told to.\n */\nconst isolationParamShape = {\n isolation: Type.Optional(\n Type.Union([Type.Literal(\"off\"), Type.Literal(\"worktree\")], {\n description:\n 'Isolation mode. Default \"off\". \"off\" runs the agent in the current checkout, the same as omitting the field. \"worktree\" creates a temporary git worktree so the agent works on an isolated copy of the repo (a copy cannot see uncommitted or staged changes in the main checkout).',\n }),\n ),\n};\n\n/**\n * Build the `isolation` parameter for a tool schema, or nothing when the\n * project disabled worktrees (`worktreeIsolation: false`).\n *\n * Dropping the field beats accepting it and quietly downgrading. The setting is\n * for a project whose model passes `\"worktree\"` on *every* call, so a\n * per-result \"isolation was disabled\" note would be noise on every result and\n * would keep raising the salience of a capability that isn't there. With no\n * field there is nothing to pass, nothing to drop, and nothing to explain \u2014 the\n * same trade `scheduleParam` makes for disabled scheduling, at zero LLM-context\n * cost. The resolver gate and the `agent-manager` check still cover the paths a\n * schema can't reach: agent files, the scheduler, and cross-extension RPC.\n *\n * Like `scheduleParam`, this is read once at tool registration \u2014 flipping the\n * setting needs a new pi session for the schema to change.\n */\nexport function isolationParam(enabled: boolean): Partial<typeof isolationParamShape> {\n return enabled ? isolationParamShape : {};\n}\n\n/**\n * The model-facing `cwd` parameter of the `Agent` tool.\n *\n * Exists because the worktree is made from the repo containing the agent's\n * working directory, which used to always be the session cwd: a session started\n * in `~` had no way to isolate an agent in `~/code/some-repo`.\n */\nexport const cwdParam = {\n cwd: Type.Optional(\n Type.String({\n description:\n 'Working directory for the agent: absolute, \"~/\"-prefixed, or relative to the session cwd. Default: the session cwd. With isolation: \"worktree\", the worktree is created from the git repo containing this directory, the agent runs at the same subdirectory inside the copy, and the result branch lands in that repo. Pass it whenever the target repo is not the session cwd. Project config (.pi extensions, skills, settings) still loads from the session cwd.',\n }),\n ),\n};\n\n/**\n * Resolve the `Agent` tool's `cwd` against the session cwd: `~` and `~/`\n * expand to the home directory, a relative path resolves against `sessionCwd`.\n * Blank means unset: models that fill every optional parameter send `\"\"`.\n * Existence is checked later by the manager, which re-checks at start time.\n */\nexport function resolveCwdParam(cwd: string | undefined, sessionCwd: string, homeDir = homedir()): string | undefined {\n const trimmed = cwd?.trim();\n if (!trimmed) return undefined;\n if (trimmed === \"~\") return homeDir;\n if (trimmed.startsWith(\"~/\")) return resolve(homeDir, trimmed.slice(2));\n return resolve(sessionCwd, trimmed);\n}\n\ninterface AgentInvocationParams {\n model?: string;\n thinking?: string;\n max_turns?: number;\n run_in_background?: boolean;\n inherit_context?: boolean;\n isolated?: boolean;\n /**\n * Untyped on purpose. Both tool schemas now build this field conditionally\n * and spread it, which erases TypeBox's literal inference to `unknown` (the\n * `schedule` param has the same shape). The resolver below narrows by\n * comparison rather than trusting the declaration, which also makes it safe\n * for the cross-extension RPC path, where options arrive unvalidated.\n */\n isolation?: unknown;\n}\n\ninterface ResolveOptions {\n /**\n * Whether worktree isolation is permitted at all. False when the project set\n * `worktreeIsolation: false`, which drops a requested worktree rather than\n * failing the call: the fail-loud precedent covers spawns that *cannot* work,\n * while this one is the user opting out, and throwing would break exactly the\n * calls the `\"off\"` value exists to tolerate. Defaults to allowed.\n */\n worktreeAllowed?: boolean;\n /**\n * What an unqualified spawn means \u2014 neither the call nor the agent file said.\n *\n * Top-level callers pass the `backgroundByDefault` setting (default `true`,\n * following Claude Code). Nested callers pass `false` unconditionally: a\n * detached child is killed by `abortOwnedChildren` when its parent settles\n * and has no notification path of its own, so backgrounding one loses its\n * work. Both call sites pass it explicitly; the `false` fallback only covers\n * a caller that supplies no options at all, which in-tree means tests.\n */\n defaultRunInBackground?: boolean;\n}\n\nexport function resolveAgentInvocationConfig(\n agentConfig: AgentConfig | undefined,\n params: AgentInvocationParams,\n opts?: ResolveOptions,\n): {\n thinking?: ThinkingLevel;\n maxTurns?: number;\n inheritContext: boolean;\n runInBackground: boolean;\n isolated: boolean;\n isolation?: IsolationMode;\n} {\n // Precedence first, collapse second \u2014 reversing these loses the veto, since\n // an agent file's \"off\" only outranks a caller's \"worktree\" while it is still\n // a value. Everything downstream then sees \"worktree\" or nothing at all.\n const requested = agentConfig?.isolation ?? params.isolation;\n const isolation = requested === \"worktree\" && opts?.worktreeAllowed !== false ? \"worktree\" : undefined;\n\n return {\n // A specialist's frontmatter is a reusable default, not a policy boundary:\n // an explicit dispatch chooses the effort for this run. Pi still clamps the\n // selected level to the resolved model, and agent-manager records that\n // requested-versus-effective difference after the session starts.\n thinking: (params.thinking ?? agentConfig?.thinking) as ThinkingLevel | undefined,\n maxTurns: agentConfig?.maxTurns ?? params.max_turns,\n inheritContext: agentConfig?.inheritContext ?? params.inherit_context ?? false,\n runInBackground: agentConfig?.runInBackground ?? params.run_in_background ?? opts?.defaultRunInBackground ?? false,\n isolated: agentConfig?.isolated ?? params.isolated ?? false,\n isolation,\n };\n}\n", "/** Exact, provider-neutral model tiers. Router profiles retain ownership of failover. */\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport type { ModelRegistry } from \"./model-resolver.js\";\nimport type { QuotaBlock } from \"./quota-admission.js\";\n\n/** One registered router profile OR an ordered exact physical chain, never both. */\nexport type TierBinding =\n | { kind: \"routed\"; tier: string; profile: string }\n | { kind: \"static\"; tier: string; members: string[] };\n\n/** Why an earlier static member could not be selected. */\ninterface TierSkip {\n ref: string;\n why: \"no-credentials\" | \"quota\";\n}\n\n/** Resolution is explicit even when no model can run; callers never guess a neighbouring tier. */\nexport type TierOutcome =\n | { kind: \"routed\"; tier: string; model: Model<Api>; profile: string; admitted?: string; answered?: string }\n | { kind: \"static\"; tier: string; model: Model<Api>; member: string; skipped: TierSkip[]; quotaSignal: boolean; answered?: string }\n | { kind: \"unmapped\"; tier: string }\n | { kind: \"unavailable\"; tier: string; tried: string[] }\n | { kind: \"exhausted\"; tier: string; block: QuotaBlock; skipped: TierSkip[] };\n\n/** Persist identity and decisions, never provider URLs, headers or credential-bearing model overlays. */\nexport type TierDisclosure = TierOutcome extends infer Outcome\n ? Outcome extends { model: Model<Api> } ? Omit<Outcome, \"model\"> & { model: Pick<Model<Api>, \"provider\" | \"id\" | \"name\" | \"api\"> } : Outcome\n : never;\n\n/** Project a runtime outcome onto its credential-free persisted shape. */\nexport function tierDisclosure(outcome: TierDisclosure): TierDisclosure {\n if (outcome.kind !== \"routed\" && outcome.kind !== \"static\") return outcome;\n const { provider, id, name, api } = outcome.model;\n return { ...outcome, model: { provider, id, name, api } };\n}\n\n/** Trusted policy for configuration failures; quota exhaustion is handled separately. */\nexport interface ModelResolution {\n onUnmapped?: \"error\" | \"inherit\";\n onUnavailable?: \"error\" | \"inherit\";\n}\n\n/** Admission metadata includes the physical label and distinguishes fail-open from measured admission. */\nexport interface TierAdmission {\n block?: QuotaBlock;\n resolvedModel?: string;\n quotaSignal: boolean;\n}\n\nconst TIER_NAME = /^[a-z0-9][a-z0-9._-]*$/;\nconst MODEL_REF = /^[^\\s/]+\\/\\S+$/;\nlet bindings: Record<string, string[]> = {};\nlet policy: ModelResolution = {};\n\n/** Reject the entire binding, never silently shorten a malformed chain. */\nexport function parseTierBinding(tier: string, members: unknown): TierBinding | undefined {\n if (tier.trim() !== tier || !TIER_NAME.test(tier) || !Array.isArray(members) || members.length === 0\n || members.some(ref => typeof ref !== \"string\" || ref.trim() !== ref || !MODEL_REF.test(ref))) return undefined;\n const refs = members as string[];\n if (refs.some(ref => ref.startsWith(\"router/\"))) {\n return refs.length === 1 ? { kind: \"routed\", tier, profile: refs[0]! } : undefined;\n }\n return { kind: \"static\", tier, members: [...refs] };\n}\n\n/** Settings have already been validated at the trusted global boundary. */\nexport function setModelTiers(tiers: Record<string, string[]> | undefined, resolution: ModelResolution | undefined): void {\n bindings = Object.fromEntries(Object.entries(tiers ?? {}).map(([key, refs]) => [key, [...refs]]));\n policy = { ...resolution };\n}\n\n/** Configured tier keys, sorted, for prompt guidance. Never the members: those are profile config. */\nexport function configuredTierNames(): string[] {\n return Object.keys(bindings).sort();\n}\n\n/** Return a snapshot; missing policies mean inherit with disclosure. */\nexport function getModelResolution(): ModelResolution {\n return { ...policy };\n}\n\n/** A missing or malformed name is unmapped, including bare @ and mixed case. */\nexport function tierBinding(tier: string): TierBinding | undefined {\n return parseTierBinding(tier, bindings[tier]);\n}\n\n/** Exact lookup independent of enabledModels, version ranking and provider retry. */\nexport function exactTierModel(ref: string, registry: ModelRegistry): Model<Api> | undefined {\n if (ref.trim() !== ref || !MODEL_REF.test(ref)) return undefined;\n const slash = ref.indexOf(\"/\");\n const found = registry.find(ref.slice(0, slash), ref.slice(slash + 1)) as Model<Api> | undefined;\n if (!found) return undefined;\n if (ref.startsWith(\"router/\")) return found.api === \"pi-virtual\" ? found : undefined;\n const available = registry.getAvailable?.() ?? registry.getAll();\n return available.some(model => model.provider === found.provider && model.id === found.id) ? found : undefined;\n}\n\n/** Resolve once per dispatch; a refused routed tier never tries another profile. */\nexport async function resolveTier(tier: string, deps: {\n registry: ModelRegistry;\n admit: (ref: string) => Promise<TierAdmission>;\n binding?: TierBinding;\n}): Promise<TierOutcome> {\n const binding = deps.binding ?? tierBinding(tier);\n if (!binding) return { kind: \"unmapped\", tier };\n if (binding.kind === \"routed\") {\n const model = exactTierModel(binding.profile, deps.registry);\n if (!model) return { kind: \"unavailable\", tier, tried: [binding.profile] };\n const admission = await deps.admit(binding.profile);\n if (admission.block) return { kind: \"exhausted\", tier, block: admission.block, skipped: [] };\n return { kind: \"routed\", tier, model, profile: binding.profile, admitted: admission.resolvedModel };\n }\n const skipped: TierSkip[] = [];\n const blocks: QuotaBlock[] = [];\n for (const member of binding.members) {\n const model = exactTierModel(member, deps.registry);\n if (!model) {\n skipped.push({ ref: member, why: \"no-credentials\" });\n continue;\n }\n const admission = await deps.admit(member);\n if (admission.block) {\n skipped.push({ ref: member, why: \"quota\" });\n blocks.push(admission.block);\n continue;\n }\n return { kind: \"static\", tier, model, member, skipped, quotaSignal: admission.quotaSignal };\n }\n if (blocks.length) {\n // Wait only if every refusal permits it. Unknown resets must not invent a wake time.\n const resets = blocks.flatMap(block => block.resetAt === undefined ? [] : [block.resetAt]);\n return { kind: \"exhausted\", tier, skipped, block: {\n model: `@${tier}`, wait: blocks.every(block => block.wait !== false),\n resetAt: resets.length ? Math.min(...resets) : undefined,\n } };\n }\n return { kind: \"unavailable\", tier, tried: [...binding.members] };\n}\n\n/** Validate stored provenance without re-resolving a historical request against today's registry. */\nexport function isTierDisclosure(raw: unknown): raw is TierDisclosure {\n if (!raw || typeof raw !== \"object\") return false;\n const value = raw as Record<string, unknown>;\n if (typeof value.tier !== \"string\") return false;\n if (value.kind === \"unmapped\") return true;\n if (value.kind === \"unavailable\") return Array.isArray(value.tried) && value.tried.every(ref => typeof ref === \"string\");\n const skipsValid = Array.isArray(value.skipped) && value.skipped.every(skip => skip && typeof skip === \"object\"\n && typeof skip.ref === \"string\" && (skip.why === \"quota\" || skip.why === \"no-credentials\"));\n if (value.kind === \"exhausted\") {\n const block = value.block as QuotaBlock | undefined;\n return skipsValid && !!block && typeof block.model === \"string\"\n && (block.wait === undefined || typeof block.wait === \"boolean\")\n && (block.resetAt === undefined || (typeof block.resetAt === \"number\" && Number.isFinite(block.resetAt)));\n }\n const model = value.model as Partial<Model<Api>> | undefined;\n if (!model || typeof model.provider !== \"string\" || typeof model.id !== \"string\"\n || typeof model.name !== \"string\" || typeof model.api !== \"string\") return false;\n if (value.answered !== undefined && typeof value.answered !== \"string\") return false;\n if (value.kind === \"routed\") return typeof value.profile === \"string\" && value.profile.startsWith(\"router/\")\n && (value.admitted === undefined || typeof value.admitted === \"string\");\n return value.kind === \"static\" && typeof value.member === \"string\" && skipsValid && typeof value.quotaSignal === \"boolean\";\n}\n\n/** Durable one-line disclosure, also useful before the first assistant response. */\nexport function tierNote(outcome: TierDisclosure | undefined, answering?: string): string {\n if (!outcome) return \"\";\n const tier = `@${outcome.tier}`;\n const answered = answering ?? ((outcome.kind === \"routed\" || outcome.kind === \"static\") ? outcome.answered : undefined);\n switch (outcome.kind) {\n case \"routed\": return `Model: ${tier} -> ${answered ?? outcome.admitted ?? outcome.profile} via ${outcome.profile}${answered && outcome.admitted && answered !== outcome.admitted ? ` (switched from ${outcome.admitted} within tier)` : \"\"}`;\n case \"static\": return `Model: ${tier} -> ${answered ?? outcome.member} (static${outcome.quotaSignal ? \"\" : \"; no quota signal\"})${outcome.skipped.length ? `; skipped ${outcome.skipped.map(skip => `${skip.ref}: ${skip.why}`).join(\", \")}` : \"\"}`;\n case \"unmapped\": return `Note: model tier ${tier} is unmapped; inheriting the parent model.`;\n case \"unavailable\": return `Note: model tier ${tier} is unavailable; inheriting the parent model.`;\n case \"exhausted\": return `Model: ${tier} is exhausted.`;\n }\n}\n", "/**\n * Model resolution: exact match (\"provider/modelId\") with fuzzy fallback for tool inputs.\n */\nimport { exactTierModel } from \"./model-tiers.js\";\n\nexport interface ModelEntry {\n id: string;\n name: string;\n provider: string;\n}\n\nexport interface ModelRegistry {\n find(provider: string, modelId: string): any;\n getAll(): any[];\n getAvailable?(): any[];\n}\n\n/** Logical model aliases supplied only by trusted global machine configuration. */\nlet modelAliases = new Map<string, string[]>();\n\n/**\n * Replace the configured logical aliases. Alias keys are case-insensitive;\n * candidates are canonical provider/model IDs and are resolved against the\n * available registry at dispatch time.\n */\nexport function setModelAliases(aliases: Record<string, string[]> | undefined): void {\n modelAliases = new Map(\n Object.entries(aliases ?? {}).map(([alias, candidates]) => [alias.toLowerCase(), [...candidates]]),\n );\n}\n\n/**\n * Per-agent model overrides from trusted global configuration: agent `type`\n * (or `\"*\"`) -> model input. Resolved through `resolveModel`, so a value may be\n * an alias, an exact `provider/id`, or a fuzzy name.\n */\nlet agentModels = new Map<string, string>();\n\n/** Replace the configured per-agent model map. Keys are matched case-insensitively. */\nexport function setAgentModels(models: Record<string, string> | undefined): void {\n agentModels = new Map(Object.entries(models ?? {}).map(([type, model]) => [type.toLowerCase(), model]));\n}\n\n/** A snapshot for the shared selection policy; callers cannot mutate configuration. */\nexport function getAgentModels(): ReadonlyMap<string, string> {\n return new Map(agentModels);\n}\n\n/**\n * Narrows fuzzy candidates to the models the user enabled (pi's `enabledModels`),\n * as lowercase `provider/id` keys. Injected rather than imported so this module\n * stays free of settings I/O; `undefined` means no scope is configured. An\n * unresolved dispatch passes its config root only for its diagnostic.\n */\nexport type ModelScopeProvider = (\n registry: ModelRegistry,\n context?: { cwd: string; homeDir?: string },\n) => ReadonlySet<string> | undefined;\n\nlet modelScopeProvider: ModelScopeProvider | undefined;\n\n/** Install (or clear) the enabled-model scope used to rank fuzzy matches. */\nexport function setModelScopeProvider(provider: ModelScopeProvider | undefined): void {\n modelScopeProvider = provider;\n}\n\n/** A copy for diagnostics and tests; callers cannot mutate resolver state. */\nexport function getModelAliases(): ReadonlyMap<string, readonly string[]> {\n return new Map([...modelAliases].map(([alias, candidates]) => [alias, [...candidates]]));\n}\n\n/**\n * Both display forms of a model. The short one goes on tight rows (the widget,\n * the Agent tool result), the canonical one where there is room to disambiguate\n * two providers serving a similarly-named model (the conversation viewer).\n *\n * One function, because `index.ts` labels the model it resolved before the run\n * and `agent-manager.ts` relabels it from the live session afterwards \u2014 the two\n * must agree or the label would visibly change the moment the session starts.\n */\nexport function describeModel(\n model: { provider: string; id: string; name?: string },\n): { modelName: string; modelId: string } {\n return {\n modelName: (model.name ?? model.id).replace(/^Claude\\s+/i, \"\").toLowerCase(),\n modelId: `${model.provider}/${model.id}`,\n };\n}\n\n/**\n * A CONFIG model (`agentModels`, an agent's `model:`, a stored job's model) that\n * did not resolve, so the spawn ran on the parent model instead. Recorded once on\n * the `AgentRecord` by the shared spawn path; every surface reads it from there.\n */\nexport interface ModelFallback {\n /** The configured input that failed to resolve. */\n input: string;\n /** Further configured inputs that also failed (e.g. a stored job model AND an `agentModels` override). */\n also?: string[];\n /** `provider/id` of the model actually used; absent when the session default (a parent with no model) ran. */\n used?: string;\n /** Whose model `used` is: the parent's (default) or the agent's own configured model (`agentModels` / definition `model:`), which took over from an unresolved stored model. */\n via?: \"parent\" | \"agent\";\n}\n\n/** The fallback outcome for `input` when the spawn ran on `parent`. */\nexport function modelFallbackTo(input: string, parent: { provider: string; id: string } | undefined): ModelFallback {\n return parent ? { input, used: `${parent.provider}/${parent.id}` } : { input };\n}\n\n/**\n * The disclosure line for a fallback: same `Note:` prefix as the unknown-agent-type\n * note. Empty string when there was none, so callers can concatenate it blindly.\n */\nexport function modelFallbackNote(fallback: ModelFallback | undefined): string {\n if (!fallback) return \"\";\n const whose = fallback.via === \"agent\" ? \"the agent's own model\" : \"parent model\";\n const used = fallback.used ? `${whose} ${fallback.used}` : \"the session default model\";\n const inputs = [fallback.input, ...(fallback.also ?? [])];\n const named = inputs.length === 1 ? `model \"${inputs[0]}\" did` : `models ${inputs.map(i => `\"${i}\"`).join(\", \")} did`;\n return `Note: configured ${named} not resolve; running on ${used}.`;\n}\n\n/** API id pi gives virtual catalog entries such as `router/default`; they never reach a provider. */\nconst VIRTUAL_MODEL_API = \"pi-virtual\";\n\n/** Whether `model` is a virtual (router) selection rather than a physical model. */\nexport function isVirtualModel(model: { api?: string } | undefined): boolean {\n return model?.api === VIRTUAL_MODEL_API;\n}\n\n/** The pre-response label of a virtual selection: no physical model has answered yet. */\nexport function describeVirtualModel(model: { provider: string; id: string; name?: string }): {\n modelName: string;\n modelId: string;\n} {\n const described = describeModel(model);\n return { ...described, modelName: `${described.modelName} (routing)` };\n}\n\n/**\n * The physical model behind an assistant message, or `undefined` when the\n * message names none (an error from failed routing carries the virtual model).\n *\n * With a virtual selection (`agentModels[\"*\"] = \"router/default\"`) the session\n * model is the router; only responses record where a request actually went, so\n * rows must be relabelled from them. `registry` supplies the display name, and\n * is optional: without it the id stands in.\n */\nexport function describePhysicalModel(\n message: { api?: string; provider?: string; model?: string } | undefined,\n registry?: { find?(provider: string, modelId: string): { name?: string } | undefined },\n): { modelName: string; modelId: string } | undefined {\n if (!message?.provider || !message.model || isVirtualModel(message)) return undefined;\n const found = registry?.find?.(message.provider, message.model);\n return describeModel({ provider: message.provider, id: message.model, name: found?.name });\n}\n\n/** Parsed `[major, minor]` of a model id, or undefined when the family has no known scheme. */\nexport type ModelVersion = readonly [major: number, minor: number];\n\n/**\n * Pull a version out of a model id (provider prefix ignored):\n * - `claude-<family>-<n>[-<n>]`, e.g. `claude-opus-4-6`, `claude-opus-5`\n * - `claude-<n>[-<n>]-<family>`, e.g. `claude-3-5-sonnet-20241022`\n * - `gpt-<n>[.<n>]-<variant>`, e.g. `gpt-6.1-sol`\n * A minor is one or two digits, so a trailing `-20250514` date stamp is never\n * read as one. Dots and dashes are interchangeable between the parts.\n */\nexport function parseModelVersion(id: string): ModelVersion | undefined {\n const bare = id.slice(id.lastIndexOf(\"/\") + 1).toLowerCase();\n const claude = /^claude-[a-z]+-(\\d{1,2})(?:[-.](\\d{1,2})(?!\\d))?(?:-|$)/.exec(bare)\n ?? /^claude-(\\d{1,2})(?:[-.](\\d{1,2})(?!\\d))?-[a-z]/.exec(bare);\n const match = claude ?? /^gpt-(\\d+)(?:[.-](\\d{1,2})(?!\\d))?(?:-|$)/.exec(bare);\n if (!match) return undefined;\n return [Number(match[1]), Number(match[2] ?? 0)];\n}\n\n/** Descending version order; an unversioned model sorts after every versioned one. */\nfunction compareVersionsDesc(a: ModelVersion | undefined, b: ModelVersion | undefined): number {\n if (a && b) return b[0] - a[0] || b[1] - a[1];\n return a ? -1 : b ? 1 : 0;\n}\n\n/**\n * Resolve a model string to a Model instance.\n * Tries exact match first (\"provider/modelId\"), then fuzzy match against all available models.\n * Returns the Model on success, or an error message string on failure.\n */\nexport function resolveModel(\n input: string,\n registry: ModelRegistry,\n context?: { cwd: string; homeDir?: string },\n): any | string {\n const aliasCandidates = modelAliases.get(input.trim().toLowerCase());\n if (aliasCandidates) {\n for (const candidate of aliasCandidates) {\n const resolved = exactTierModel(candidate, registry);\n if (resolved) return resolved;\n }\n return `Model alias \"${input}\" has no available candidate.\\n\\nCandidates:\\n${aliasCandidates.map(candidate => ` ${candidate}`).join(\"\\n\")}`;\n }\n return resolveCanonicalModel(input, registry, context);\n}\n\n/**\n * Pick among fuzzy candidates. Restricted to the enabled model scope when one is\n * configured and any candidate is in it, then newest parsed version first, then\n * match score. A bare family name like \"opus\" therefore means the newest opus\n * the user has enabled, not whichever id happens to be shortest.\n */\nfunction scopedCandidates<T extends { entry: ModelEntry }>(\n candidates: T[],\n registry: ModelRegistry,\n context?: { cwd: string; homeDir?: string },\n): T[] {\n const scope = modelScopeProvider?.(registry, context);\n const scoped = scope ? candidates.filter(candidate => scope.has(`${candidate.entry.provider}/${candidate.entry.id}`.toLowerCase())) : [];\n return scoped.length > 0 ? scoped : candidates;\n}\n\n/** Stable tie-breaker independent of registry insertion order and locale. */\nfunction compareModelIdentity(a: ModelEntry, b: ModelEntry): number {\n const left = `${a.provider}/${a.id}`;\n const right = `${b.provider}/${b.id}`;\n return Number(left > right) - Number(left < right);\n}\n\nfunction rankFuzzy(\n matches: { entry: ModelEntry; score: number }[],\n registry: ModelRegistry,\n context?: { cwd: string; homeDir?: string },\n): ModelEntry | undefined {\n const ranked = scopedCandidates(matches, registry, context)\n .map(c => ({ ...c, version: parseModelVersion(c.entry.id) }))\n .sort((a, b) => compareVersionsDesc(a.version, b.version) || b.score - a.score || compareModelIdentity(a.entry, b.entry));\n return ranked[0]?.entry;\n}\n\n/** Numeric runs stay ordered and contiguous: `5-5` cannot reuse the `5` in `4-5`. */\nfunction versionRuns(value: string): string[] {\n return [...value.replace(/-\\d{8}$/, \"\").matchAll(/(?:^|[\\s-])(\\d+(?:[\\s-]+\\d+)*)(?=$|[\\s-])/g)].map(match => match[1]!.replace(/\\s+/g, \"-\"));\n}\n\n/** Resolve an exact or fuzzy provider/model request without consulting aliases. */\nfunction resolveCanonicalModel(\n input: string,\n registry: ModelRegistry,\n context?: { cwd: string; homeDir?: string },\n): any | string {\n // Available models (those with auth configured)\n const all = (registry.getAvailable?.() ?? registry.getAll()) as ModelEntry[];\n const availableSet = new Set(all.map(m => `${m.provider}/${m.id}`.toLowerCase()));\n\n // 1. Exact match: \"provider/modelId\" \u2014 only if available (has auth)\n const slashIdx = input.indexOf(\"/\");\n if (slashIdx !== -1) {\n const provider = input.slice(0, slashIdx);\n const modelId = input.slice(slashIdx + 1);\n if (availableSet.has(input.toLowerCase())) {\n const found = registry.find(provider, modelId);\n if (found) return found;\n }\n }\n\n // 2. Fuzzy match against available models. Normalize separators so cosmetic\n // punctuation differences still match \u2014 e.g. \"claude-haiku-4.5\" and\n // \"claude-haiku-4-5\" (dot vs dash in the version) resolve to the same model.\n const normalize = (s: string) => s.toLowerCase().replace(/\\./g, \"-\");\n const query = normalize(input);\n const requestedVersions = versionRuns(query.slice(slashIdx + 1));\n\n // Score each model: prefer exact id match > id contains > name contains > provider+id contains\n const matches: { entry: ModelEntry; score: number }[] = [];\n\n for (const m of all) {\n const id = normalize(m.id);\n const name = normalize(m.name);\n const full = normalize(`${m.provider}/${m.id}`);\n const idVersions = versionRuns(id);\n const versions = idVersions.length > 0 ? idVersions : versionRuns(name);\n // Filter before scope/ranking, including substring and name matches. A\n // major-only input can select a newer minor, but never another major or\n // a minor token masquerading as the requested major.\n if (!requestedVersions.every(requested => versions.some(version => version === requested || version.startsWith(`${requested}-`)))) continue;\n\n let score = 0;\n if (id === query || full === query) {\n score = 100; // exact\n } else if (id.includes(query) || full.includes(query)) {\n score = 60 + (query.length / id.length) * 30; // substring, prefer tighter matches\n } else if (name.includes(query)) {\n score = 40 + (query.length / name.length) * 20;\n } else if (\n // A trailing date-stamp token (e.g. \"20251001\") is optional, so a\n // date-pinned config like \"claude-haiku-4-5-20251001\" still matches an\n // undated registry id like \"claude-haiku-4-5\".\n query\n .split(/[\\s\\-/]+/)\n .every(part => /^\\d{8}$/.test(part) || id.includes(part) || name.includes(part) || m.provider.toLowerCase().includes(part))\n ) {\n score = 20; // all parts present somewhere\n }\n\n if (score >= 20) matches.push({ entry: m, score });\n }\n\n // An exact id (or provider/id) is the caller naming a model, not describing\n // one: it wins outright, whatever the scope or any newer sibling.\n const exact = matches.filter(c => c.score === 100);\n const exactBest = exact.sort((a, b) => compareModelIdentity(a.entry, b.entry))[0];\n const bestMatch = exactBest ? exactBest.entry : rankFuzzy(matches, registry, context);\n if (bestMatch) {\n const found = registry.find(bestMatch.provider, bestMatch.id);\n if (found) return found;\n }\n\n // 3. Provider fallback: a \"provider/modelId\" query that didn't match under the\n // named provider (exact or fuzzy above) retries against all providers. The\n // named provider is preferred when present; this only kicks in when it isn't,\n // so the same model from another provider beats falling back to \"inherit\".\n if (slashIdx !== -1) {\n const bare = resolveCanonicalModel(input.slice(slashIdx + 1), registry, context);\n if (typeof bare !== \"string\") return bare;\n }\n\n // 4. No match \u2014 list available models\n const modelList = scopedCandidates(all.map(entry => ({ entry })), registry, context)\n .map(({ entry }) => ` ${entry.provider}/${entry.id}`)\n .sort()\n .join(\"\\n\");\n return `Model not found: \"${input}\".\\n\\nAvailable models:\\n${modelList}`;\n}\n", "/**\n * Reads `enabledModels` from pi's settings (global `<agentDir>/settings.json`\n * + project-local `<cwd>/.pi/settings.json`, project wins) and resolves\n * entries to concrete `provider/modelId` keys for scope validation.\n *\n * **Project overrides global**, mirroring pi's own `SettingsManager`\n * deep-merge behavior and matching the precedence we use for our own\n * `subagents.json` settings (see `src/settings.ts:loadSettings`). If\n * project file has `enabledModels` set, it wholly replaces global's\n * (array fields are replaced, not concatenated).\n *\n * **Limited subset of upstream's resolveModelScope.** We support exact\n * `provider/modelId` matching only. Upstream (pi-coding-agent's\n * `core/model-resolver.ts`) additionally supports glob patterns\n * (`*sonnet*`, `anthropic/*`), bare model IDs without provider, and\n * thinking-level suffixes (`provider/*:high`). Those forms are silently\n * ignored here.\n *\n * In practice, pi's `/scoped-models` picker writes exact `provider/modelId`\n * entries, so the limitation is invisible for users who configure scope\n * through pi's UI. Hand-edited settings using globs or bare IDs will\n * produce an empty allowed set (scope check becomes a no-op).\n *\n * Example:\n * enabledModels = [\"anthropic/claude-sonnet-4-6\", \"anthropic/claude-opus-4-6\"]\n * \u2192 resolves to { \"anthropic/claude-sonnet-4-6\", \"anthropic/claude-opus-4-6\" }\n */\n\nimport { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { resolveAgentDir } from \"./home-paths.js\";\nimport type { ModelEntry } from \"./model-resolver.js\";\n\n/** Minimal registry shape \u2014 only the methods resolveEnabledModels actually calls. */\nexport interface ModelRegistryRef {\n getAll(): unknown[];\n getAvailable?(): unknown[];\n}\n\n/** Paths to pi's settings.json files: [project, global] (project takes precedence). */\nfunction settingsPaths(cwd: string, homeDir?: string): [project: string, global: string] {\n return [\n join(cwd, \".pi\", \"settings.json\"),\n join(resolveAgentDir(homeDir), \"settings.json\"),\n ];\n}\n\n/** Read `enabledModels` from a single settings.json file. Undefined when missing or absent. */\nfunction readField(path: string): string[] | undefined {\n if (!existsSync(path)) return undefined;\n try {\n const raw = JSON.parse(readFileSync(path, \"utf-8\"));\n if (Array.isArray(raw?.enabledModels)) return raw.enabledModels as string[];\n } catch {\n /* corrupt file \u2014 silent */\n }\n return undefined;\n}\n\n/**\n * Read enabledModels from pi's settings \u2014 project-local overrides global.\n * Mirrors pi's SettingsManager deep-merge for the `enabledModels` field\n * (and matches our own loadSettings precedence in src/settings.ts).\n * Returns undefined when neither file has the field.\n */\nexport function readEnabledModels(cwd: string, homeDir?: string): string[] | undefined {\n const [project, global] = settingsPaths(cwd, homeDir);\n return readField(project) ?? readField(global);\n}\n\n/**\n * Resolve enabledModels patterns \u2192 Set<\"provider/modelId\"> (lowercase keys).\n *\n * Only exact `provider/modelId` patterns are matched (case-insensitive).\n * Patterns without a slash, with glob characters, or with a `:thinking`\n * suffix are silently dropped. See module-level docstring for rationale.\n *\n * Cache: keyed on JSON.stringify(patterns) + mtime/size of *both*\n * project and global settings.json files. Re-resolves when either file\n * changes or the patterns argument differs.\n *\n * Returns undefined when no patterns are provided or no patterns match\n * (scope check becomes a no-op at the call site).\n */\n\n// Module-level cache \u2014 invalidated when either settings.json changes or patterns differ.\nlet cachedAllowed: Set<string> | undefined;\nlet cachedHash = \"\";\nlet cachedPatternsKey = \"\";\n\n/** mtime+size hash of one file, or \"missing\" if absent. */\nfunction hashOf(path: string): string {\n try {\n const s = statSync(path);\n return `${s.mtimeMs}-${s.size}`;\n } catch {\n return \"missing\";\n }\n}\n\nexport function resolveEnabledModels(\n patterns: string[] | undefined,\n registry: ModelRegistryRef,\n cwd: string = process.cwd(),\n homeDir?: string,\n): Set<string> | undefined {\n // Fast path: check cache (stat both project and global settings.json files)\n const patternsKey = JSON.stringify(patterns);\n const [project, global] = settingsPaths(cwd, homeDir);\n const fileHash = `${project}:${hashOf(project)};${global}:${hashOf(global)}`;\n\n if (fileHash === cachedHash && patternsKey === cachedPatternsKey) {\n return cachedAllowed;\n }\n\n // Cache miss \u2014 resolve\n if (!patterns || patterns.length === 0) {\n cachedHash = fileHash;\n cachedPatternsKey = patternsKey;\n cachedAllowed = undefined;\n return undefined;\n }\n\n const available = (registry.getAvailable?.() ?? registry.getAll()) as ModelEntry[];\n const allowed = new Set<string>();\n\n for (const pattern of patterns) {\n const trimmed = pattern.trim();\n if (!trimmed) continue; // skip empty/whitespace\n resolveExact(trimmed, available, allowed);\n }\n\n const result = allowed.size > 0 ? allowed : undefined;\n cachedHash = fileHash;\n cachedPatternsKey = patternsKey;\n cachedAllowed = result;\n return result;\n}\n\n\n\n/**\n * True when `model` is in the allowed set. Centralizes the key format\n * (`provider/id` lowercase) so callers don't have to reproduce it \u2014\n * both set-building (resolveExact) and lookup go through `modelKey`.\n */\nexport function isModelInScope(\n model: { provider: string; id: string },\n allowed: Set<string>,\n): boolean {\n return allowed.has(modelKey(model));\n}\n\n/** Canonical lowercase `provider/id` key for the allowed set. */\nfunction modelKey(model: { provider: string; id: string }): string {\n return `${model.provider}/${model.id}`.toLowerCase();\n}\n\n/**\n * Resolve exact model pattern. Example: \"google/gemma-4-31b-it\".\n */\nfunction resolveExact(\n pattern: string,\n available: ModelEntry[],\n allowed: Set<string>,\n): void {\n // \"provider/modelId\" \u2014 exact (colon is part of id, not split)\n const slashIdx = pattern.indexOf(\"/\");\n if (slashIdx === -1) return; // bare modelId not supported\n\n const provider = pattern.slice(0, slashIdx).toLowerCase();\n const modelId = pattern.slice(slashIdx + 1).toLowerCase();\n const exact = available.find(\n m => m.provider.toLowerCase() === provider && m.id.toLowerCase() === modelId,\n );\n if (exact) {\n allowed.add(modelKey(exact));\n }\n}\n\n\n", "/**\n * model-scope.ts \u2014 `scopeModels` policy, shared by the top-level Agent tool and\n * the nested delegation tools so a nested spawn can't escape the allowlist the\n * top-level path enforces.\n *\n * State lives here (rather than in an index.ts closure) for the same reason\n * `disableDefaults` lives in agent-types.ts: both entry points need it.\n */\n\nimport { isModelInScope, type ModelRegistryRef, readEnabledModels, resolveEnabledModels } from \"./enabled-models.js\";\n\n/**\n * When enabled, subagent model choices are validated against `enabledModels`\n * from pi's settings \u2014 both global `<agentDir>/settings.json` and project-local\n * `<cwd>/.pi/settings.json` (project overrides global). Off by default; opt-in\n * via `/agents \u2192 Settings`. See the SubagentsSettings.scopeModels docstring for\n * the hard-error vs warn-and-proceed policy and its rationale.\n */\nlet scopeModelsEnabled = false;\n\nexport function isScopeModelsEnabled(): boolean { return scopeModelsEnabled; }\nexport function setScopeModelsEnabled(enabled: boolean): void { scopeModelsEnabled = enabled; }\n\nexport type ModelScopeVerdict =\n /** In scope, or nothing to validate against (feature off / no allowlist). */\n | { kind: \"ok\" }\n /** Caller-supplied out-of-scope choice \u2014 refuse the spawn with this message. */\n | { kind: \"error\"; message: string }\n /** Frontmatter-pinned or parent-inherited \u2014 proceed, but tell the user. */\n | { kind: \"warn\"; message: string };\n\n/**\n * Check the effective resolved model against the user's enabledModels list.\n *\n * scopeModels guards against *runtime* LLM choices, not user-level config:\n * - Caller-supplied out-of-scope \u2192 hard error (the orchestrator made an explicit\n * out-of-scope choice; surface it so it picks differently).\n * - Frontmatter-pinned or parent-inherited out-of-scope \u2192 warn but proceed (the\n * user authored/installed this agent or chose the parent's model; trust it).\n */\nexport function checkModelScope(args: {\n homeDir?: string;\n model: { provider: string; id: string } | undefined;\n cwd: string;\n modelRegistry: ModelRegistryRef;\n /** True when the model came from the tool call rather than frontmatter. */\n callerSupplied: boolean;\n /** Display name used in the warning toast. */\n agentLabel: string;\n /** The raw `model:` input, when there was one. */\n modelInput?: string;\n}): ModelScopeVerdict {\n const { model, cwd, modelRegistry, callerSupplied, agentLabel, modelInput } = args;\n if (!scopeModelsEnabled || !model) return { kind: \"ok\" };\n\n const allowed = resolveEnabledModels(readEnabledModels(cwd, args.homeDir), modelRegistry, cwd, args.homeDir);\n if (!allowed || isModelInScope(model, allowed)) return { kind: \"ok\" };\n\n if (callerSupplied) {\n const list = [...allowed].sort().map(m => ` ${m}`).join(\"\\n\");\n return {\n kind: \"error\",\n message: `Model not in scope: \"${modelInput}\".\\n\\nAllowed models (from enabledModels):\\n${list}`,\n };\n }\n const modelLabel = modelInput ?? `${model.provider}/${model.id}`;\n return {\n kind: \"warn\",\n message: `Agent \"${agentLabel}\" using out-of-scope model \"${modelLabel}\"`,\n };\n}\n", "/**\n * quota-admission.ts \u2014 ask a subscription router whether a dispatch may start.\n *\n * Quota tracking lives in a separate extension (nredd/pi-subscription-router),\n * reached over `pi.events` with the same envelope as `cross-extension-rpc.ts`:\n * emit `router:rpc:admit` `{ requestId, model }`, reply on\n * `router:rpc:admit:reply:<requestId>` as `{ success, data?: { ok, resolvedModel?, resetAt?, wait? } }` (`resolvedModel` labels the admitted physical model).\n *\n * Admission fails open. No router installed, a slow router, a malformed reply\n * or a router error all admit the dispatch: quota is advisory here, and the\n * router still routes (or fails) each request inside the child.\n */\n\nimport { nanoid } from \"nanoid\";\nimport { type Clock, realClock } from \"./clock.js\";\nimport type { TierAdmission } from \"./model-tiers.js\";\n\nexport const ADMIT_CHANNEL = \"router:rpc:admit\";\n\n/**\n * How long to wait for a reply. The router answers from cached state within\n * the same macrotask, so this only bounds the cost when no router is installed.\n */\nconst ADMIT_TIMEOUT_MS = 100;\n\n/** Minimal `pi.events` surface. */\nexport interface AdmissionEvents {\n emit(channel: string, data: unknown): void;\n on(channel: string, handler: (data: unknown) => void): () => void;\n}\n\n/** A dispatch the router refused, with the earliest known reset (epoch ms). */\nexport interface QuotaBlock {\n model: string;\n resetAt?: number;\n /**\n * False when the router's exhaustion policy says fail now instead of parking.\n * Absent (an older router) means the dispatch may park until `resetAt`.\n */\n wait?: boolean;\n}\n\n/** Whether a refused background dispatch may be parked until the block's reset. */\nexport function mayPark(block: QuotaBlock): block is QuotaBlock & { resetAt: number } {\n return block.resetAt !== undefined && block.wait !== false;\n}\n\n/** `provider/id` for a model, the key the router expects. */\nexport function modelRef(model: { provider: string; id: string }): string {\n return `${model.provider}/${model.id}`;\n}\n\n/** Resolve to the block when the router refuses `model`, else undefined. */\nexport async function checkAdmission(\n events: AdmissionEvents,\n model: string,\n timeoutMs = ADMIT_TIMEOUT_MS,\n clock: Clock = realClock,\n signal?: AbortSignal,\n): Promise<QuotaBlock | undefined> {\n return (await admissionOutcome(events, model, timeoutMs, clock, signal)).block;\n}\n\n/** Retain the physical admission label and whether the router supplied a signal. */\nexport function admissionOutcome(\n events: AdmissionEvents,\n model: string,\n timeoutMs = ADMIT_TIMEOUT_MS,\n clock: Clock = realClock,\n signal?: AbortSignal,\n): Promise<TierAdmission> {\n if (signal?.aborted) return Promise.reject(new DOMException(\"Admission cancelled\", \"AbortError\"));\n const requestId = nanoid();\n return new Promise((resolve, reject) => {\n // Every step is idempotent and a promise settles once, so no `done` latch is needed.\n const cleanup = () => {\n timer.cancel();\n unsubscribe();\n signal?.removeEventListener(\"abort\", abort);\n };\n const abort = () => {\n cleanup();\n reject(new DOMException(\"Admission cancelled\", \"AbortError\"));\n };\n const finish = (outcome: TierAdmission) => {\n cleanup();\n resolve(outcome);\n };\n const unsubscribe = events.on(`${ADMIT_CHANNEL}:reply:${requestId}`, raw => {\n const reply = raw as { success?: unknown; data?: { ok?: unknown; resolvedModel?: unknown; resetAt?: unknown; wait?: unknown } } | undefined;\n if (reply?.success !== true || typeof reply.data?.ok !== \"boolean\") return finish({ quotaSignal: false });\n if (reply.data.ok) return finish({ quotaSignal: true, resolvedModel: typeof reply.data.resolvedModel === \"string\" ? reply.data.resolvedModel : undefined });\n const resetAt = reply.data.resetAt;\n const wait = reply.data.wait;\n finish({ quotaSignal: true, block: {\n model,\n resetAt: typeof resetAt === \"number\" && Number.isFinite(resetAt) ? resetAt : undefined,\n ...(typeof wait === \"boolean\" ? { wait } : {}),\n } });\n });\n const timer = clock.setTimeout(() => finish({ quotaSignal: false }), timeoutMs);\n signal?.addEventListener(\"abort\", abort, { once: true });\n events.emit(ADMIT_CHANNEL, { requestId, model });\n });\n}\n\n/** One-line reason for a refused dispatch. */\nexport function describeBlock(block: QuotaBlock): string {\n const when = block.resetAt === undefined ? \"an unknown time\" : new Date(block.resetAt).toISOString();\n return `Subscription quota for ${block.model} is exhausted; it resets at ${when}.`;\n}\n\n/** Delay past a reported reset before a parked dispatch starts, so usage has refilled. */\nexport const QUOTA_RESTART_GRACE_MS = 60_000;\n\n/**\n * Delay before re-admitting a parked dispatch whose reset passed while pi was\n * closed. The router warms its usage cache on session_start; asking before that\n * finishes would always fail open.\n */\nexport const PARKED_RESUME_DELAY_MS = 10_000;\n", "/** One selection policy for every dispatch, independent of its transport. */\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { type Clock, realClock } from \"./clock.js\";\nimport { describeModel, describeVirtualModel, getAgentModels, getModelAliases, isVirtualModel, type ModelFallback, type ModelRegistry, modelFallbackNote, modelFallbackTo, resolveModel } from \"./model-resolver.js\";\nimport { checkModelScope } from \"./model-scope.js\";\nimport { exactTierModel, getModelResolution, parseTierBinding, resolveTier, type TierBinding, type TierDisclosure, type TierOutcome, tierBinding, tierNote } from \"./model-tiers.js\";\nimport { type AdmissionEvents, admissionOutcome, type QuotaBlock } from \"./quota-admission.js\";\n\n/** Exact compatibility pins for user-defined legacy Explore definitions. User aliases win. */\nconst LEGACY_MODEL_PINS = new Map([\n [\"claude-haiku-4-5\", \"anthropic/claude-haiku-4-5\"],\n]);\n\n/** The winning precedence level, before resolution or fallback. */\nexport type ModelSource = \"param\" | \"agentModels:type\" | \"agentModels:*\" | \"definition\" | \"parent\";\n\n/** Keep the original request even when it could not be resolved. */\nexport interface ModelSelection {\n requested?: string;\n source: ModelSource;\n model: Model<Api> | undefined;\n outcome: \"resolved\" | \"inherited\" | \"fallback\";\n fallback?: ModelFallback;\n scopeWarning?: string;\n /** Serializable tier provenance, retained when the answering model changes. */\n tier?: TierOutcome;\n /** A prepared binding is resolved with admission before starting the child. */\n tierBinding?: TierBinding;\n tierAdmitted?: boolean;\n /** Startup-only parent floor if credentials/profile disappear between preflight and admission. */\n tierParent?: Model<Api>;\n}\n\n/** Choose the input once: explicit parameter > type > wildcard > definition; blank strings are unset. */\nexport function modelRequest(type: string, definitionModel?: string, paramModel?: string | Model<Api> | null): {\n requested?: string;\n source: ModelSource;\n} {\n if (paramModel != null && (typeof paramModel !== \"string\" || paramModel.trim() !== \"\")) {\n return { requested: typeof paramModel === \"string\" ? paramModel : `${paramModel.provider}/${paramModel.id}`, source: \"param\" };\n }\n const overrides = getAgentModels();\n const typed = overrides.get(type.toLowerCase());\n if (typed?.trim()) return { requested: typed, source: \"agentModels:type\" };\n const wildcard = overrides.get(\"*\");\n if (wildcard?.trim()) return { requested: wildcard, source: \"agentModels:*\" };\n if (definitionModel?.trim()) return { requested: definitionModel, source: \"definition\" };\n return { source: \"parent\" };\n}\n\n/**\n * Choose an exact configured input or tier binding before record creation.\n * Only explicit non-tier tool inputs retain fuzzy matching. Tier admission is\n * asynchronous and completes through admitModelSelection before startup; this\n * synchronous preflight preserves spawn's immediate-id and validation contract.\n * An already-open resume keeps the record and does not select again.\n */\nexport function selectModel(request: {\n homeDir?: string;\n agentType: string;\n definitionModel?: string;\n paramModel?: string | Model<Api> | null;\n parentModel: Model<Api> | undefined;\n registry: ModelRegistry;\n cwd: string;\n agentLabel?: string;\n}): ModelSelection | string {\n const input = modelRequest(request.agentType, request.definitionModel, request.paramModel);\n let selection: ModelSelection = { ...input, model: request.parentModel, outcome: \"inherited\" };\n if (input.requested) {\n const requested = input.requested.trim();\n const legacy = getModelAliases().get(requested.toLowerCase());\n const legacyBinding = legacy ? parseTierBinding(\"legacy\", legacy) : undefined;\n // Preserve existing enterprise manifests during the built-in Explore migration.\n // An explicit cheap binding always wins, even when it is unavailable.\n const cheapCompatibility = requested === \"@cheap\" && request.agentType === \"Explore\"\n && input.source === \"definition\"\n ? parseTierBinding(\"cheap\", getModelAliases().get(\"claude-haiku-4-5\")) : undefined;\n const binding = requested.startsWith(\"@\") ? tierBinding(requested.slice(1)) ?? cheapCompatibility\n : legacyBinding ? { ...legacyBinding, tier: requested } : undefined;\n if (requested.startsWith(\"@\") || legacy) {\n const tier = requested.startsWith(\"@\") ? requested.slice(1) : requested;\n const refs = binding?.kind === \"routed\" ? [binding.profile] : binding?.members ?? [];\n const model = refs.map(ref => exactTierModel(ref, request.registry)).find(Boolean);\n if (!binding || !model) {\n const outcome: TierOutcome = binding ? { kind: \"unavailable\", tier, tried: refs } : { kind: \"unmapped\", tier };\n const mode = outcome.kind === \"unmapped\" ? getModelResolution().onUnmapped : getModelResolution().onUnavailable;\n if (mode === \"error\") return `Model tier @${tier} is ${outcome.kind}.`;\n selection = { ...selection, tier: outcome, outcome: \"fallback\", fallback: modelFallbackTo(input.requested, request.parentModel) };\n } else {\n selection = { ...input, model, outcome: \"resolved\", tierBinding: binding, tierParent: request.parentModel };\n }\n } else {\n const compatibilityPin = input.source === \"definition\" && request.agentType === \"Explore\"\n ? LEGACY_MODEL_PINS.get(requested) : undefined;\n const resolved = request.paramModel != null && typeof request.paramModel === \"object\"\n ? request.paramModel : input.source === \"param\" ? resolveModel(requested, request.registry, { cwd: request.cwd, homeDir: request.homeDir })\n : exactTierModel(compatibilityPin ?? requested, request.registry) ?? `Model not found: \"${requested}\".`;\n if (typeof resolved !== \"string\") selection = { ...input, model: resolved, outcome: \"resolved\" };\n else if (compatibilityPin) {\n const tier: TierOutcome = { kind: \"unavailable\", tier: requested, tried: [compatibilityPin] };\n if (getModelResolution().onUnavailable === \"error\") return `Model tier @${requested} is unavailable.`;\n selection = { ...selection, tier, outcome: \"fallback\", fallback: modelFallbackTo(input.requested, request.parentModel) };\n } else {\n if (input.source === \"param\" || getModelResolution().onUnavailable === \"error\") return resolved;\n selection = { ...selection, outcome: \"fallback\", fallback: modelFallbackTo(input.requested, request.parentModel) };\n }\n }\n }\n const scope = checkModelScope({\n model: selection.model, cwd: request.cwd, modelRegistry: request.registry,\n callerSupplied: input.source === \"param\" && !selection.tierBinding && !selection.tier, agentLabel: request.agentLabel ?? request.agentType,\n modelInput: input.requested, homeDir: request.homeDir,\n });\n if (scope.kind === \"error\") return scope.message;\n if (scope.kind === \"warn\") selection.scopeWarning = scope.message;\n return selection;\n}\n\n/** Label an admitted physical model before any response, without replacing the virtual selection. */\nexport function describeSelection(selection: ModelSelection | undefined, registry: ModelRegistry): { modelName?: string; modelId?: string } {\n const admitted = selection?.tier?.kind === \"routed\" ? selection.tier.admitted : undefined;\n if (admitted) {\n const slash = admitted.indexOf(\"/\");\n const provider = admitted.slice(0, slash);\n const id = admitted.slice(slash + 1);\n return describeModel(registry.find(provider, id) ?? { provider, id });\n }\n const model = selection?.model;\n return model ? isVirtualModel(model) ? describeVirtualModel(model) : describeModel(model) : {};\n}\n\n/** Resolved selection identity for model-facing text, not an actionable fallback warning. */\nexport function modelIdentityNote(carrier: { modelSelection?: ModelSelection; modelTier?: TierDisclosure } | undefined): string {\n const selected = carrier?.modelSelection?.model;\n // Tier notes already carry admission/answer provenance. Literal virtual\n // selections have no such evidence, so never claim their alias is a leaf.\n return selected && !carrier?.modelTier\n ? `Resolved model: ${selected.provider}/${selected.id}${isVirtualModel(selected) ? \" (routing alias; physical response model: unknown)\" : \"\"}.`\n : \"\";\n}\n\n/** One disclosure for records, persisted details, workflows and notices. */\nexport function modelSelectionNote(carrier: { modelTier?: TierDisclosure; modelFallback?: ModelFallback; invocation?: { modelId?: string } } | undefined): string {\n const tier = carrier?.modelTier;\n const fallback = carrier?.modelFallback;\n const sameRequest = tier && (fallback?.input === tier.tier || fallback?.input === `@${tier.tier}`);\n return [tierNote(tier, carrier?.invocation?.modelId), sameRequest ? \"\" : modelFallbackNote(fallback)].filter(Boolean).join(\"\\n\");\n}\n\n/** Admission for tiers is made once and is shared by every transport. */\nexport async function admitModelSelection(selection: ModelSelection, registry: ModelRegistry, events: AdmissionEvents, clock: Clock = realClock, signal?: AbortSignal): Promise<QuotaBlock | undefined> {\n if (!selection.tierBinding || selection.tierAdmitted) return selection.tier?.kind === \"exhausted\" ? selection.tier.block : undefined;\n selection.tier = await resolveTier(selection.tierBinding.tier, {\n registry, binding: selection.tierBinding, admit: ref => admissionOutcome(events, ref, undefined, clock, signal),\n });\n selection.tierAdmitted = true;\n if (selection.tier.kind === \"routed\" || selection.tier.kind === \"static\") selection.model = selection.tier.model;\n if (selection.tier.kind === \"exhausted\") return selection.tier.block;\n // The binding is handed to `resolveTier`, so it is never `unmapped` here.\n if (selection.tier.kind === \"unavailable\") {\n if (getModelResolution().onUnavailable === \"error\") throw new Error(`Model tier @${selection.tier.tier} is unavailable.`);\n selection.model = selection.tierParent;\n selection.outcome = \"fallback\";\n selection.fallback = modelFallbackTo(selection.requested ?? `@${selection.tier.tier}`, selection.tierParent);\n delete selection.tierBinding;\n }\n delete selection.tierParent;\n return undefined;\n}\n", "/**\n * output-file.ts \u2014 Streaming JSONL output file for agent transcripts.\n *\n * Creates a per-agent output file that streams conversation turns as JSONL,\n * matching Claude Code's task output file format.\n */\n\nimport { appendFileSync, chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { AgentSession, AgentSessionEvent } from \"@earendil-works/pi-coding-agent\";\nimport { type ModelFallback, modelFallbackNote } from \"./model-resolver.js\";\nimport { type TierDisclosure, tierDisclosure, tierNote } from \"./model-tiers.js\";\n\n/**\n * Project/global default for writing a subagent's `.output` transcript; a custom\n * agent's `output_transcript` overrides it per agent.\n *\n * State lives here rather than in an index.ts closure because both spawn paths\n * need it \u2014 the top-level Agent tool and the nested delegation tools. Same\n * reason `scopeModels` lives in model-scope.ts: a setting only one path can read\n * is a setting the other path silently ignores.\n */\nlet outputTranscriptDefault = true;\n\nexport function getOutputTranscriptDefault(): boolean { return outputTranscriptDefault; }\nexport function setOutputTranscriptDefault(b: boolean): void { outputTranscriptDefault = b; }\n\n/**\n * Encode a cwd path as a filesystem-safe directory name. Handles:\n * - POSIX: \"/home/user/project\" \u2192 \"home-user-project\"\n * - Windows: \"C:\\Users\\foo\\project\" \u2192 \"Users-foo-project\"\n * - UNC: \"\\\\\\\\server\\\\share\\\\project\" \u2192 \"server-share-project\"\n */\nexport function encodeCwd(cwd: string): string {\n return cwd\n .replace(/[/\\\\]/g, \"-\") // both separators \u2192 dash\n .replace(/^[A-Za-z]:-/, \"\") // strip Windows drive prefix (\"C:-\")\n .replace(/^-+/, \"\"); // strip leading dashes (POSIX root, UNC)\n}\n\n/**\n * The per-session scratch directory, created if missing.\n * Mirrors Claude Code's layout: /tmp/{prefix}-{uid}/{encoded-cwd}/{sessionId}/tasks\n *\n * Shared with the workflow tool, which persists each invocation's script here so\n * iterating on one is edit-file-then-rerun \u2014 the same convention, one directory.\n */\nexport function sessionTaskDir(cwd: string, sessionId: string): string {\n const encoded = encodeCwd(cwd);\n const root = join(tmpdir(), `pi-subagents-${process.getuid?.() ?? 0}`);\n mkdirSync(root, { recursive: true, mode: 0o700 });\n // chmod is a no-op on Windows and throws on some Windows filesystems.\n // On Unix we still want to enforce 0o700 past umask, so only swallow on Windows.\n try {\n chmodSync(root, 0o700);\n } catch (err) {\n if (process.platform !== \"win32\") throw err;\n }\n const dir = join(root, encoded, sessionId, \"tasks\");\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\n/** Create the output file path, ensuring the directory exists. */\nexport function createOutputFilePath(cwd: string, agentId: string, sessionId: string): string {\n return join(sessionTaskDir(cwd, sessionId), `${agentId}.output`);\n}\n\n/**\n * Ensure a transcript file exists without disturbing what is already in it.\n *\n * A resume reuses the agent's existing transcript (same deterministic path), so\n * it must never call `writeInitialEntry` \u2014 that truncates, discarding turns the\n * completion notification still points the user at, and any history the session\n * has since compacted away is gone for good. Appending nothing creates the file\n * when this is the agent's first transcript and is a no-op when it is not.\n */\nexport function ensureOutputFile(path: string): void {\n try {\n appendFileSync(path, \"\", \"utf-8\");\n } catch { /* ignore \u2014 streaming writes are best-effort too */ }\n}\n\n/** Append the model-fallback disclosure as a transcript line (best effort, like streaming writes). */\nexport function appendModelFallbackEntry(path: string, agentId: string, fallback: ModelFallback): void {\n try {\n // A resumed agent reuses its transcript, which may already say it.\n if (existsSync(path) && readFileSync(path, \"utf-8\").includes('\"type\":\"model-fallback\"')) return;\n appendFileSync(\n path,\n `${JSON.stringify({ isSidechain: true, agentId, type: \"model-fallback\", modelFallback: fallback, note: modelFallbackNote(fallback), timestamp: new Date().toISOString() })}\\n`,\n \"utf-8\",\n );\n } catch { /* ignore */ }\n}\n\n/** Append tier provenance separately from assistant messages for durable replay. */\nexport function appendModelTierEntry(path: string, agentId: string, modelTier: TierDisclosure): void {\n try {\n appendFileSync(path, `${JSON.stringify({ isSidechain: true, agentId, type: \"model-tier\", modelTier: tierDisclosure(modelTier), note: tierNote(modelTier), timestamp: new Date().toISOString() })}\\n`, \"utf-8\");\n } catch { /* transcript writes are best effort */ }\n}\n\n/** Write the initial user prompt entry. */\nexport function writeInitialEntry(path: string, agentId: string, prompt: string, cwd: string): void {\n const entry = {\n isSidechain: true,\n agentId,\n type: \"user\",\n message: { role: \"user\", content: prompt },\n timestamp: new Date().toISOString(),\n cwd,\n };\n writeFileSync(path, JSON.stringify(entry) + \"\\n\", \"utf-8\");\n}\n\n/**\n * Subscribe to session events and flush new messages to the output file on each turn_end.\n * Returns a cleanup function that does a final flush and unsubscribes.\n */\nexport function streamToOutputFile(\n session: AgentSession,\n path: string,\n agentId: string,\n cwd: string,\n startIndex?: number,\n): () => void {\n // Index of the first message this stream is responsible for. A resume hands\n // in the session's length as of just before the run: the session already\n // holds every prior turn, and re-emitting those would duplicate history that\n // is already in the file. A spawn has already written its prompt as the\n // initial entry, so it starts after the first user message \u2014 found on the\n // first flush, because pi puts a system message ahead of it and adds both\n // only once the prompt runs.\n let writtenCount = startIndex;\n\n const flush = () => {\n const messages = session.messages;\n if (writtenCount === undefined) {\n const prompt = messages.findIndex((m) => m.role === \"user\");\n if (prompt === -1) return;\n writtenCount = prompt + 1;\n }\n while (writtenCount < messages.length) {\n const msg = messages[writtenCount++];\n // Pi's prompt and tool-loadout records; a Claude Code transcript has no\n // such entry.\n if (msg.role === \"system\") continue;\n const entry = {\n isSidechain: true,\n agentId,\n type: msg.role === \"assistant\" ? \"assistant\" : msg.role === \"user\" ? \"user\" : \"toolResult\",\n message: msg,\n timestamp: new Date().toISOString(),\n cwd,\n };\n try {\n appendFileSync(path, JSON.stringify(entry) + \"\\n\", \"utf-8\");\n } catch { /* ignore write errors */ }\n }\n };\n\n const unsubscribe = session.subscribe((event: AgentSessionEvent) => {\n if (event.type === \"turn_end\") flush();\n // Compaction replaces session.messages with a shorter, summarized array,\n // leaving writtenCount past the new end \u2014 without re-anchoring, the flush\n // loop would never match again and streaming would halt for good (#145).\n // Flush before it runs so any not-yet-flushed tail still reaches the file,\n // then re-anchor to the rebuilt array once it lands. The re-anchor is\n // deferred a microtask because on the overflow-retry path pi trims the\n // trailing error assistant message AFTER emitting compaction_end \u2014\n // anchoring synchronously would sit one past the trimmed array and skip\n // the first post-compaction message. Aborted/failed compactions leave\n // session.messages untouched, so only successful ones re-anchor.\n if (event.type === \"compaction_start\") flush();\n if (event.type === \"compaction_end\" && !event.aborted && event.result) {\n queueMicrotask(() => { writtenCount = session.messages.length; });\n }\n });\n\n return () => {\n flush();\n unsubscribe();\n };\n}\n", "/**\n * status-note.ts \u2014 Honest framing for an agent result: the parenthetical status\n * note for a non-normal outcome, and the salvaged partial output of a failure.\n *\n * Lives here rather than in an index.ts closure because both entry points need\n * it \u2014 the top-level tools and the nested delegation tools, which can't import\n * from index.ts (that is the extension entry, and it already reaches these tools\n * through agent-runner).\n */\n\nimport type { AgentRecord } from \"./types.js\";\n\n/** Who stopped a `stopped` record: the spawning agent, or (unset) a human. */\ntype StoppedBy = AgentRecord[\"stoppedBy\"];\n\n/**\n * Explicit parenthetical note for a non-normal terminal outcome, so the parent\n * agent can't mistake partial output for a completed result. Empty string for a\n * clean completion (and any unknown/non-terminal status).\n *\n * `stopped` (a human aborted it) is deliberately distinct from `aborted` (the\n * turn limit was hit) \u2014 the parent should treat human intervention differently\n * from a budget cutoff. A stop the parent itself made with `stop_subagent`\n * (`stoppedBy: \"parent\"`) is stated plainly instead: shouting a human\n * intervention that never happened would misreport its own decision back to it.\n */\nexport function getStatusNote(status: string, stoppedBy?: StoppedBy): string {\n switch (status) {\n case \"stopped\":\n return stoppedBy === \"parent\"\n ? \" (stopped by the parent with stop_subagent before completion \u2014 output is partial; the task was NOT finished)\"\n : \" (STOPPED BY THE USER before completion \u2014 output is partial; the task was NOT finished)\";\n case \"aborted\":\n return \" (aborted \u2014 hit the turn limit before completion; output may be incomplete)\";\n case \"steered\":\n return \" (wrapped up at the turn limit \u2014 output may be partial)\";\n default:\n return \"\";\n }\n}\n\n/**\n * Foreground variant of `getStatusNote`. A foreground caller is in a different\n * position from a background one, so it needs different text:\n *\n * - It already holds the agent's ENTIRE output inline, whereas the background\n * notification carries a 500-char preview. So only here can we truthfully\n * say there is nothing more to fetch \u2014 which is the whole point, because\n * - it has no agent id. The id travels in the tool result's renderer\n * `details`, which is never serialized to the model. A parent that reads\n * \"output may be partial\" as \"truncated, go retrieve the rest\" therefore\n * has nothing valid to call `get_subagent_result` with, and will invent an\n * id (#174).\n *\n * Only the lead clause varies between the three, and each variation carries\n * information: `wrapped up` vs `aborted` tells the parent whether the output is\n * a considered final answer or a fragment, and `stopped` shouts because a human\n * intervening outranks everything else in the string. Only `steered` hedges on\n * completion \u2014 it was told to wrap up and did, so it may well have finished at\n * the limit; an aborted run blew through its grace turns while still working,\n * and `stopped` can only fire on a running agent, so neither ever delivered a\n * final answer. Identical confidence gets identical wording: phrasing one fact\n * two ways invites a hunt for a distinction that isn't there.\n *\n * Every clause is a statement about state, never an instruction to act, and\n * `get_subagent_result` is never named \u2014 naming the tool we steer away from only\n * raises its salience. Two instructions were tried here and cut: \"re-spawn with\n * a higher max_turns\" (pushes a fresh multi-minute run to save one wasted tool\n * call) and, on `stopped`, \"ask before restarting it\" (restates the lead, and\n * presumes someone is present to ask \u2014 false under `pi -p`, in scheduled jobs,\n * and in any background-driven run). Nothing here can measure whether wording\n * improves parent behavior, so removing a false cue (which cannot induce new\n * behavior) and adding an instruction (which can) are not equally safe bets.\n * Don't add either back without a way to measure it.\n */\nexport function getForegroundOutcomeNote(status: string, stoppedBy?: StoppedBy): string {\n switch (status) {\n case \"stopped\":\n return stoppedBy === \"parent\"\n ? \" (stopped by the parent with stop_subagent \u2014 everything the agent produced is above; the task is unfinished)\"\n : \" (STOPPED BY THE USER \u2014 everything the agent produced is above; the task is unfinished)\";\n case \"aborted\":\n return \" (aborted at the turn limit \u2014 everything the agent produced is above; the task is unfinished)\";\n case \"steered\":\n return \" (wrapped up at the turn limit \u2014 everything the agent produced is above; the task may be unfinished)\";\n default:\n return \"\";\n }\n}\n\n/**\n * For an `error` run whose session survived, the hint that resuming it\n * continues the work, naming the agent; \"\" otherwise. A provider or auth\n * failure (e.g. a credential helper that failed transiently, #456) ends the\n * turn but keeps the whole transcript, so the parent should resume the agent\n * rather than re-spawn it and repay its context. A run that never got a\n * session has nothing to resume.\n */\nexport function resumeHint(record: Pick<AgentRecord, \"id\" | \"status\" | \"session\">): string {\n return record.status === \"error\" && record.session\n ? `transcript intact; resume agent ${record.id} to continue`\n : \"\";\n}\n\n/**\n * Salvaged partial output of a failed run, as a labeled suffix for the error\n * surfaces (or \"\" if the run produced nothing). `record.result` is bounded to\n * the run's own turns, so this is never a stale earlier answer (#144).\n */\nexport function partialOutputSuffix(record: AgentRecord): string {\n const partial = record.result?.trim();\n return partial ? `\\n\\nPartial output before the failure:\\n${partial}` : \"\";\n}\n", "/**\n * worktree.ts \u2014 Git worktree isolation for agents.\n *\n * Creates a temporary git worktree so the agent works on an isolated copy of the repo.\n * On completion, if no changes were made and nothing in it would be lost, the worktree is cleaned up.\n * If changes exist, a branch is created and returned in the result.\n * If git cannot inspect, commit or remove, the worktree is kept and the result carries `error` and `path`.\n *\n * Every git call goes through `pi.exec` (async) rather than `execFileSync`: a\n * worktree copy can take seconds, and a session that spawns several isolated\n * agents at once would otherwise serialize them all on the TUI's event loop.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { type BigIntStats, existsSync, lstatSync, readdirSync, readFileSync, realpathSync, statSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join, relative, resolve } from \"node:path\";\nimport type { ExtensionAPI } from \"@earendil-works/pi-coding-agent\";\nimport { errorMessage } from \"./error-message.js\";\nimport { QUOTE_PATH_ARGS, unquoteGitPath } from \"./git-path.js\";\n\nexport interface WorktreeInfo {\n /** Absolute path to the worktree directory (the copied repo's root). */\n path: string;\n /** Branch name created for this worktree (if changes exist). */\n branch: string;\n /** Commit SHA that the worktree was created from. */\n baseSha: string;\n /** Resolved toplevel of the repo the worktree was created from; the result branch lands here. */\n repoRoot: string;\n /**\n * Where the agent should work inside the worktree: the equivalent of the\n * cwd the worktree was created from. Equals `path` when that cwd was the\n * repo root; points at the copied subdirectory when it was deeper (e.g. a\n * monorepo package), so the requested scoping survives isolation.\n */\n workPath: string;\n}\n\n/**\n * Project-wide switch for worktree isolation (`worktreeIsolation` in\n * subagents.json). Default `true` \u2014 unchanged behaviour.\n *\n * The `\"off\"` isolation value gives a model a legal way to decline a worktree,\n * but it still depends on the model choosing it. This is the deterministic half\n * of the same fix: on a large repo where every worktree costs real time and\n * disk (#184), turning it off means no caller can create one, whatever it\n * passes.\n */\nlet worktreeIsolationEnabled = true;\n\nexport function setWorktreeIsolationEnabled(enabled: boolean): void {\n worktreeIsolationEnabled = enabled;\n}\n\nexport function isWorktreeIsolationEnabled(): boolean {\n return worktreeIsolationEnabled;\n}\n\nexport interface WorktreeCleanupResult {\n /** Whether changes were found in the worktree. */\n hasChanges: boolean;\n /** Branch name if changes were committed. */\n branch?: string;\n /** Worktree path if it was kept. */\n path?: string;\n /** Cleanup failure; the worktree may contain uncommitted or unreachable work. */\n error?: string;\n}\n\n/**\n * Run git and return its trimmed stdout, throwing on failure so callers keep\n * the try/catch control flow `execFileSync` gave them.\n *\n * `pi.exec` never rejects \u2014 it reports failure in the result \u2014 and a command\n * killed by its timeout comes back as `killed` with an exit code of 0, so both\n * have to be checked to reproduce `execFileSync`'s \"throws on anything but a\n * clean exit\".\n */\nasync function git(pi: ExtensionAPI, cwd: string, args: string[], timeout: number): Promise<string> {\n return (await gitRaw(pi, cwd, args, timeout)).trim();\n}\n\n/** `git`, with stdout untrimmed: a path may start or end with whitespace. */\nasync function gitRaw(pi: ExtensionAPI, cwd: string, args: string[], timeout: number): Promise<string> {\n const result = await pi.exec(\"git\", args, { cwd, timeout });\n if (result.killed) throw new GitTimeoutError(`\\`git ${args.join(\" \")}\\` timed out after ${timeout}ms in ${cwd}`);\n if (result.code !== 0) {\n throw new Error(result.stderr.trim() || `git ${args.join(\" \")} failed (exit ${result.code})`);\n }\n return result.stdout;\n}\n\n/** A git call killed by its timeout \u2014 reported as-is, never as a repo-state cause. */\nclass GitTimeoutError extends Error {}\n\n/**\n * Why `createWorktree` could not isolate an agent. The message names the\n * directory it tried and the specific cause, so a caller can tell \"wrong\n * directory\" from \"repo with no commits\" from a git failure.\n */\nexport class WorktreeError extends Error {}\n\n/** Run one git step, rethrowing a failure as a `WorktreeError` whose message is `cause(detail)`. */\nasync function step(run: Promise<string>, cause: (detail: string) => string): Promise<string> {\n try {\n return await run;\n } catch (err) {\n const detail = errorMessage(err);\n throw new WorktreeError(err instanceof GitTimeoutError ? detail : cause(detail));\n }\n}\n\n/**\n * Create a temporary git worktree for an agent, from the repo containing `cwd`\n * (which may be any directory inside it, not just the toplevel).\n *\n * @throws WorktreeError \u2014 `cwd` is not inside a git work tree, the repo has no\n * commits yet, `git worktree add` failed, or a git call timed out.\n */\nexport async function createWorktree(pi: ExtensionAPI, cwd: string, agentId: string): Promise<WorktreeInfo> {\n const inside = await step(\n git(pi, cwd, [\"rev-parse\", \"--is-inside-work-tree\"], 5000),\n detail => `${cwd} is not inside a git repository (${detail})`,\n );\n // \"false\" with a clean exit: inside a `.git` dir or a bare repo.\n if (inside !== \"true\") throw new WorktreeError(`${cwd} is inside a git directory but not a work tree`);\n // realpath both sides \u2014 git emits resolved paths while cwd may arrive\n // through a symlink (macOS /tmp).\n const repoRoot = realpathSync(await step(\n git(pi, cwd, [\"rev-parse\", \"--show-toplevel\"], 5000),\n detail => `${cwd} has no git work tree toplevel (${detail})`,\n ));\n const baseSha = await step(\n git(pi, cwd, [\"rev-parse\", \"--verify\", \"HEAD\"], 5000),\n () => `${repoRoot} has no commits yet; commit at least once`,\n );\n // Where cwd sits inside the repo (\"\" at the root): the agent must work at\n // the same subdirectory inside the copy, or a monorepo-package cwd would\n // silently widen to the whole repo.\n const subdir = relative(repoRoot, realpathSync(cwd));\n\n const branch = `pi-agent-${agentId}`;\n const suffix = randomUUID().slice(0, 8);\n const worktreePath = join(tmpdir(), `pi-agent-${agentId}-${suffix}`);\n\n // Create detached worktree at HEAD\n await step(\n git(pi, cwd, [\"worktree\", \"add\", \"--detach\", worktreePath, \"HEAD\"], 30000),\n detail => `\\`git worktree add\\` failed in ${repoRoot}: ${detail}`,\n );\n return { path: worktreePath, branch, baseSha, repoRoot, workPath: subdir ? join(worktreePath, subdir) : worktreePath };\n}\n\n/**\n * Clean up a worktree after agent completion.\n * - If no changes: remove worktree entirely.\n * - If changes exist: create a branch, commit changes, return branch info.\n */\nexport async function cleanupWorktree(\n pi: ExtensionAPI,\n cwd: string,\n worktree: WorktreeInfo,\n agentDescription: string,\n): Promise<WorktreeCleanupResult> {\n if (!existsSync(worktree.path)) {\n return { hasChanges: false };\n }\n\n let branch: string | undefined;\n try {\n // Submodule state lives in the worktree's private git dir and is deleted with it.\n await assertSubmodulesDisposable(pi, worktree.path, worktree.baseSha);\n // Check for uncommitted changes in the worktree\n const status = await dirtyState(pi, worktree.path);\n\n if (status) {\n // Changes exist \u2014 stage, commit, and create a branch\n const modes = await indexOnlyModes(pi, worktree.path);\n if (modes.length > 0) {\n throw new Error(`mode staged only in the index; worktree kept: ${modes.join(\", \")}`);\n }\n await git(pi, worktree.path, [\"add\", \"-A\"], 10000);\n // `add -A` skips a moved gitlink hidden by `submodule.<name>.ignore = all`; an empty\n // commit would fail opaquely, so say why and keep the worktree.\n if (!(await git(pi, worktree.path, [\"diff\", \"--cached\", \"--name-only\"], 10000))) {\n throw new Error(`uncommitted changes could not be staged (a submodule \\`ignore\\` setting can hide a moved gitlink); worktree kept:\\n${status}`);\n }\n // Truncate description for commit message (no shell sanitization needed \u2014 pi.exec uses argv)\n const safeDesc = agentDescription.slice(0, 200);\n const commitMsg = `pi-agent: ${safeDesc}`;\n await git(pi, worktree.path, [\"commit\", \"--no-verify\", \"-m\", commitMsg], 10000);\n } else {\n const currentSha = await git(pi, worktree.path, [\"rev-parse\", \"HEAD\"], 5000);\n\n if (currentSha === worktree.baseSha) {\n // No changes \u2014 remove worktree\n await removeWorktree(pi, cwd, worktree.path, worktree.baseSha);\n return { hasChanges: false };\n }\n }\n\n // Create a branch pointing to the worktree's HEAD.\n // If the branch already exists, append a suffix to avoid overwriting previous work.\n let branchName = worktree.branch;\n try {\n await git(pi, worktree.path, [\"branch\", branchName], 5000);\n } catch {\n // Branch already exists \u2014 use a unique suffix\n branchName = `${worktree.branch}-${Date.now()}`;\n await git(pi, worktree.path, [\"branch\", branchName], 5000);\n }\n // Update branch name in worktree info for the caller\n worktree.branch = branchName;\n branch = branchName;\n\n // Remove the worktree (branch persists in main repo)\n await removeWorktree(pi, cwd, worktree.path, worktree.baseSha);\n\n return {\n hasChanges: true,\n branch: worktree.branch,\n };\n } catch (error) {\n // A failed status means the contents are unknown, not clean. Never remove\n // the tree after a failed preservation step: even committed HEAD may have\n // no reachable branch yet.\n return {\n hasChanges: true,\n ...(branch ? { branch } : {}),\n path: worktree.path,\n error: (error instanceof Error ? error.message : String(error)) || \"Unknown git failure\",\n };\n }\n}\n\n/**\n * Lines of a path listing, read without `-z` and with `core.quotePath=true`: every\n * non-ASCII path byte is escaped, so `pi.exec` decoding stdout chunk by chunk cannot\n * corrupt a path (see `unquoteGitPath`). Each line's paths are decoded by the caller.\n */\nasync function gitLines(pi: ExtensionAPI, repo: string, args: string[], timeout: number): Promise<string[]> {\n return (await gitRaw(pi, repo, [...QUOTE_PATH_ARGS, ...args], timeout)).split(\"\\n\").filter(Boolean);\n}\n\nconst INDEX_BATCH = 200;\n\n/** `git update-index <flag> -- <paths>` in argv-sized batches. */\nasync function updateIndex(pi: ExtensionAPI, repo: string, flag: string, paths: string[]): Promise<void> {\n for (let i = 0; i < paths.length; i += INDEX_BATCH) {\n await git(pi, repo, [\"update-index\", flag, \"--\", ...paths.slice(i, i + INDEX_BATCH)], 30000);\n }\n}\n\n/**\n * Clear the assume-unchanged and skip-worktree index bits of `repo`: with either\n * set, `status` and git's own removal check ignore edits to the file, so an edited\n * file would be deleted with the worktree. A skip-worktree file absent from disk\n * (sparse checkout) is left alone: clearing it would report a deletion nobody made.\n * The tree is disposable, so mutating its index is fine.\n */\nasync function clearHiddenIndexBits(pi: ExtensionAPI, repo: string): Promise<void> {\n const assumed: string[] = [];\n const skipped: string[] = [];\n // `-v` tags: lowercase = assume-unchanged, `S` (or `s` with both) = skip-worktree.\n for (const entry of await gitLines(pi, repo, [\"ls-files\", \"-v\"], 30000)) {\n const tag = entry.charAt(0);\n const hidden = tag !== tag.toUpperCase() || tag === \"S\";\n if (!hidden) continue;\n const path = unquoteGitPath(entry.slice(2));\n if (tag !== tag.toUpperCase()) assumed.push(path);\n if (tag.toLowerCase() === \"s\" && lstatOrUndefined(join(repo, path))) skipped.push(path);\n }\n await updateIndex(pi, repo, \"--no-assume-unchanged\", assumed);\n await updateIndex(pi, repo, \"--no-skip-worktree\", skipped);\n}\n\n/** `lstat` of `path`, or undefined when it is missing or unreachable (ENOENT, ENOTDIR). */\nfunction lstatOrUndefined(path: string): BigIntStats | undefined {\n try {\n return lstatSync(path, { bigint: true });\n } catch (error) {\n // Anything else (EACCES, ...) is unknown, not absent: let cleanup fail and keep the tree.\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\" || code === \"ENOTDIR\") return undefined;\n throw error;\n }\n}\n\n/**\n * Regular files whose staged executable bit (index vs `HEAD`, a new file counting as a change)\n * differs from the file on disk, decoded. `add -A` restages from disk and would silently drop\n * such a mode, and an index-only mode cannot be told from a later on-disk change, so cleanup\n * keeps the worktree instead of guessing. A plain unstaged `chmod` is not listed: the index\n * still matches `HEAD`, so `add -A` commits the disk mode. Skipped when `core.fileMode=false`:\n * git ignores the bit then, so a mismatch is not a change.\n */\nasync function indexOnlyModes(pi: ExtensionAPI, repo: string): Promise<string[]> {\n if ((await git(pi, repo, [\"config\", \"--type=bool\", \"--default\", \"true\", \"core.fileMode\"], 5000)) === \"false\") return [];\n const paths: string[] = [];\n // `:<old mode> <new mode> <old sha> <new sha> <status>` TAB `<path>`\n for (const line of await gitLines(pi, repo, [\"diff\", \"--cached\", \"--raw\", \"--no-renames\"], 30000)) {\n const tab = line.indexOf(\"\\t\");\n const [oldMode, newMode] = line.slice(1, tab).split(\" \");\n if (oldMode === newMode || (newMode !== \"100644\" && newMode !== \"100755\")) continue;\n const path = unquoteGitPath(line.slice(tab + 1));\n const disk = lstatOrUndefined(join(repo, path));\n if (disk?.isFile() && ((disk.mode & 0o100n) !== 0n) !== (newMode === \"100755\")) paths.push(path);\n }\n return paths;\n}\n\n/**\n * Uncommitted state of `repo`, untracked files and submodule changes included.\n * `status.showUntrackedFiles=no` in user or repo config would otherwise hide new\n * files from `status`, and `submodule.<name>.ignore` / `diff.ignoreSubmodules`\n * would hide a moved gitlink; a clean-looking tree gets removed with them.\n * Index bits that hide edits are cleared first, see `clearHiddenIndexBits`.\n */\nasync function dirtyState(pi: ExtensionAPI, repo: string): Promise<string> {\n await clearHiddenIndexBits(pi, repo);\n return await git(pi, repo, [\"status\", \"--porcelain\", \"--untracked-files=all\", \"--ignore-submodules=none\"], 10000);\n}\n\nconst GITLINK_MODE = \"160000\";\n\n/**\n * Gitlinks (mode 160000) of `repo` as path -> sha: the index when `rev` is\n * omitted, else the tree of `rev`. Independent of `.gitmodules`: git refuses to\n * remove a worktree on the gitlink, not on the config file.\n */\nasync function gitlinks(pi: ExtensionAPI, repo: string, rev?: string): Promise<Map<string, string>> {\n const links = new Map<string, string>();\n for (const entry of await gitLines(pi, repo, rev ? [\"ls-tree\", \"-r\", rev] : [\"ls-files\", \"-s\"], 30000)) {\n // `gitLines` drops blanks, so every entry is `<fields>` TAB `<path>`.\n const tab = entry.indexOf(\"\\t\");\n // ls-files: `<mode> <sha> <stage>`; ls-tree: `<mode> <type> <sha>`.\n const [mode, second, third] = entry.slice(0, tab).split(\" \");\n if (mode === GITLINK_MODE) links.set(unquoteGitPath(entry.slice(tab + 1)), rev ? (third as string) : (second as string));\n }\n return links;\n}\n\n/** What removing a repository would destroy: stashes and commits (branch, tag or HEAD) no remote-tracking ref (or `published`) contains. */\nasync function unpublished(pi: ExtensionAPI, gitArgs: string[], cwd: string, published: Iterable<string>): Promise<string> {\n const stash = await git(pi, cwd, [...gitArgs, \"stash\", \"list\"], 10000);\n // `--not` with an object this repository lacks would fail the whole listing.\n const known: string[] = [];\n for (const sha of published) {\n const probe = await pi.exec(\"git\", [...gitArgs, \"cat-file\", \"-e\", `${sha}^{commit}`], { cwd, timeout: 5000 });\n if (!probe.killed && probe.code === 0) known.push(sha);\n }\n // Tags count: a local tag can be the only ref holding a commit. Offline there is\n // no telling a fetched tag from a local one, so an unpublished tagged commit fails safe.\n const commits = await git(pi, cwd, [...gitArgs, \"rev-list\", \"--branches\", \"--tags\", \"HEAD\", \"--not\", \"--remotes\", ...known], 30000);\n return [stash, commits].filter(Boolean).join(\"\\n\");\n}\n\n/**\n * The git dir of the repository whose work tree is `dir`, read from `.git` (a directory, or\n * a `gitdir: <path>` file for a submodule) rather than from `git rev-parse` output, which\n * `pi.exec` can mis-decode when the path is non-ASCII.\n */\nfunction gitDirOf(dir: string): string {\n const dotGit = join(dir, \".git\");\n if (statSync(dotGit).isDirectory()) return dotGit;\n const target = /^gitdir: (.+)$/m.exec(readFileSync(dotGit, \"utf8\"))?.[1];\n if (!target) throw new Error(`${dotGit} is neither a directory nor a gitdir file`);\n return resolve(dir, target.trim());\n}\n\n/**\n * Inspect the nested repository at `dir`, then the ones behind its own gitlinks.\n * `recorded` is the sha a trusted baseline pins it at (when any).\n */\nasync function inspectRepo(\n pi: ExtensionAPI,\n dir: string,\n label: string,\n recorded: string | undefined,\n trusted: Set<string>,\n seen: Set<string>,\n problems: string[],\n): Promise<void> {\n seen.add(realpathSync(gitDirOf(dir)));\n const dirty = await dirtyState(pi, dir);\n const lost = await unpublished(pi, [], dir, recorded ? [recorded] : []);\n const detail = [dirty, lost].filter(Boolean).join(\"\\n\");\n if (detail) problems.push(`${label}:\\n${detail}`);\n const head = await git(pi, dir, [\"rev-parse\", \"HEAD\"], 5000);\n await inspectGitlinks(pi, dir, head === recorded ? \"HEAD\" : undefined, trusted, seen, problems);\n await inspectIgnoredRepos(pi, dir, dir, trusted, seen, problems);\n}\n\n/**\n * Inspect nested repositories under gitignored paths of `repo` not already\n * `seen`. Labels are relative to `root`, the worktree.\n */\nasync function inspectIgnoredRepos(\n pi: ExtensionAPI,\n repo: string,\n root: string,\n trusted: Set<string>,\n seen: Set<string>,\n problems: string[],\n): Promise<void> {\n for (const dir of await ignoredRepoDirs(pi, repo)) {\n if (!seen.has(realpathSync(gitDirOf(dir)))) {\n await inspectRepo(pi, dir, relative(root, dir), undefined, trusted, seen, problems);\n }\n }\n}\n\n/**\n * Inspect the nested repository behind every gitlink of `repo`, recursively.\n * `baseRev` is a revision whose gitlinks are already trusted as published (the\n * commit the worktree was created from): a nested HEAD at exactly that recorded\n * sha, e.g. fetched by sha during `submodule update`, is not at risk. A gitlink\n * the agent introduced has no baseline, so only remote-tracking refs vouch for it.\n * Every baseline sha seen is added to `trusted`, for repositories no gitlink reaches.\n */\nasync function inspectGitlinks(\n pi: ExtensionAPI,\n repo: string,\n baseRev: string | undefined,\n trusted: Set<string>,\n seen: Set<string>,\n problems: string[],\n): Promise<void> {\n const base = baseRev ? await gitlinks(pi, repo, baseRev) : new Map<string, string>();\n for (const sha of base.values()) trusted.add(sha);\n for (const path of (await gitlinks(pi, repo)).keys()) {\n const dir = join(repo, path);\n if (existsSync(join(dir, \".git\"))) await inspectRepo(pi, dir, path, base.get(path), trusted, seen, problems);\n }\n}\n\n/**\n * Nested repositories under gitignored paths: `add -A` skips them, so no gitlink\n * records them, yet plain removal deletes their ignored content.\n */\nasync function ignoredRepoDirs(pi: ExtensionAPI, worktreePath: string): Promise<string[]> {\n const entries = await gitLines(pi, worktreePath, [\"status\", \"--porcelain\", \"--ignored\", \"--untracked-files=all\", \"--ignore-submodules=none\"], 30000);\n // With `--untracked-files=all` git lists an ignored nested repository as its own `!! dir/` entry.\n // Only directory entries (`dir/`, or `\"dir/\"` when quoted) can be a clone: decode just those.\n const dirs = entries.filter(entry => entry.startsWith(\"!! \") && /\\/\"?$/.test(entry)).map(entry => unquoteGitPath(entry.slice(3)));\n return dirs.map(dir => join(worktreePath, dir)).filter(dir => existsSync(join(dir, \".git\")));\n}\n\n/** Git dirs under a `modules` directory, including those nested in other submodule git dirs. */\nfunction moduleGitDirs(dir: string): string[] {\n if (existsSync(join(dir, \"HEAD\")) && existsSync(join(dir, \"objects\"))) {\n const nested = join(dir, \"modules\");\n return [dir, ...(existsSync(nested) ? moduleGitDirs(nested) : [])];\n }\n return readdirSync(dir, { withFileTypes: true }).flatMap(entry => (entry.isDirectory() ? moduleGitDirs(join(dir, entry.name)) : []));\n}\n\n/** Absolute `modules` directory of the worktree's private git dir, when present. */\nfunction modulesDir(worktreePath: string): string | undefined {\n const dir = join(gitDirOf(worktreePath), \"modules\");\n return existsSync(dir) ? dir : undefined;\n}\n\n/**\n * Throw unless every nested repository the removal would delete holds nothing\n * but already-published state. Git deletes submodule git dirs with the worktree,\n * so unpushed commits or uncommitted files there would be lost even after the\n * outer repo is branched. Covers every gitlink in the index, registered in\n * `.gitmodules` or not, plus any leftover repository in the worktree's `modules`\n * dir (e.g. after the agent deleted `.gitmodules`).\n */\nasync function assertSubmodulesDisposable(pi: ExtensionAPI, worktreePath: string, baseSha: string): Promise<void> {\n const seen = new Set<string>();\n const trusted = new Set<string>();\n const problems: string[] = [];\n await inspectGitlinks(pi, worktreePath, baseSha, trusted, seen, problems);\n await inspectIgnoredRepos(pi, worktreePath, worktreePath, trusted, seen, problems);\n const modules = modulesDir(worktreePath);\n for (const gitDir of modules ? moduleGitDirs(modules) : []) {\n if (seen.has(realpathSync(gitDir))) continue;\n const lost = await unpublished(pi, [\"--git-dir\", gitDir], worktreePath, trusted);\n if (lost) problems.push(`${gitDir}:\\n${lost}`);\n }\n if (problems.length) throw new Error(`submodule work would be lost on removal; worktree kept:\\n${problems.join(\"\\n\")}`);\n}\n\n/** Whether git would refuse plain removal for submodule state: any gitlink in the index or a `modules` dir. */\nasync function hasSubmoduleState(pi: ExtensionAPI, worktreePath: string): Promise<boolean> {\n return (await gitlinks(pi, worktreePath)).size > 0 || modulesDir(worktreePath) !== undefined;\n}\n\n/**\n * Remove only a clean worktree; git refuses newly appeared uncommitted work.\n *\n * Git also refuses any worktree with submodule state, clean or not. Whether that\n * is why removal failed is decided structurally (gitlinks, `modules` dir), never\n * from git's locale-dependent message. Only then is `--force` used, and only after\n * the outer tree and every nested repository re-verify as holding nothing unpublished.\n */\nasync function removeWorktree(pi: ExtensionAPI, cwd: string, worktreePath: string, baseSha: string): Promise<void> {\n try {\n // Git's own clean check honors `status.showUntrackedFiles`; pin it so config cannot hide new files.\n await git(pi, cwd, [\"-c\", \"status.showUntrackedFiles=all\", \"worktree\", \"remove\", worktreePath], 10000);\n } catch (error) {\n if (!(await hasSubmoduleState(pi, worktreePath))) throw error;\n if (await dirtyState(pi, worktreePath)) throw error;\n await assertSubmodulesDisposable(pi, worktreePath, baseSha);\n await git(pi, cwd, [\"worktree\", \"remove\", \"--force\", worktreePath], 10000);\n }\n}\n\n/**\n * Prune any orphaned worktrees (crash recovery).\n */\nexport async function pruneWorktrees(pi: ExtensionAPI, cwd: string): Promise<void> {\n try {\n await git(pi, cwd, [\"worktree\", \"prune\"], 5000);\n } catch { /* ignore */ }\n}\n", "/**\n * git-path.ts -- decode the C-style quoted paths git prints without `-z`.\n *\n * `pi.exec` decodes each stdout chunk as UTF-8 on its own, so a multibyte\n * character split across two chunks becomes U+FFFD. With `core.quotePath=true`\n * git escapes every non-ASCII byte (and control characters, `\"` and `\\`) as\n * `\"...\"` with octal escapes, so a listing read without `-z` is pure ASCII and\n * survives any chunking; this module turns it back into the real path.\n */\n\nconst SIMPLE_ESCAPES: Record<string, number> = {\n a: 0x07,\n b: 0x08,\n f: 0x0c,\n n: 0x0a,\n r: 0x0d,\n t: 0x09,\n v: 0x0b,\n '\"': 0x22,\n \"\\\\\": 0x5c,\n};\n\nconst UTF8 = new TextDecoder(\"utf-8\", { fatal: true, ignoreBOM: true });\n\n/** Args that make `git` quote every non-ASCII path byte; put them before the subcommand. */\nexport const QUOTE_PATH_ARGS = [\"-c\", \"core.quotePath=true\"];\n\n/**\n * Decode one path as git prints it: a plain name is returned as is, a `\"...\"` name is\n * unescaped to bytes and decoded as UTF-8. Throws on anything that cannot name a file\n * as a JS string: raw non-ASCII (the listing was not quoted, so it may be mis-decoded),\n * a malformed escape, or bytes that are not valid UTF-8.\n */\nexport function unquoteGitPath(text: string): string {\n const quoted = text.length >= 2 && text.startsWith('\"') && text.endsWith('\"');\n const body = quoted ? text.slice(1, -1) : text;\n for (let i = 0; i < body.length; i++) {\n if (body.charCodeAt(i) > 0x7f) throw new Error(`git printed a non-ASCII path unquoted (${JSON.stringify(text)}); it may be mis-decoded`);\n }\n if (!quoted) return text;\n const bytes: number[] = [];\n for (let i = 0; i < body.length; i++) {\n const char = body.charAt(i);\n if (char === '\"') throw new Error(`malformed quoted git path ${JSON.stringify(text)}`);\n if (char !== \"\\\\\") {\n bytes.push(body.charCodeAt(i));\n continue;\n }\n const next = body.charAt(i + 1);\n const octal = /^[0-3][0-7]{2}$/.test(body.slice(i + 1, i + 4)) ? body.slice(i + 1, i + 4) : undefined;\n if (octal) {\n bytes.push(Number.parseInt(octal, 8));\n i += 3;\n } else if (next in SIMPLE_ESCAPES) {\n bytes.push(SIMPLE_ESCAPES[next] as number);\n i += 1;\n } else {\n throw new Error(`malformed escape in quoted git path ${JSON.stringify(text)}`);\n }\n }\n try {\n return UTF8.decode(Uint8Array.from(bytes));\n } catch {\n throw new Error(`git path ${JSON.stringify(text)} is not valid UTF-8 and cannot be inspected`);\n }\n}\n", "/**\n * plan-mode-children.ts -- keeps a child started while the parent plans in Plan\n * mode (#437), as Claude Code keeps a subagent spawned in plan mode in plan mode.\n *\n * pi-plan-mode gates only its own session's tool calls, and a child is a separate\n * session on a separate event bus. So right before a child runs, the manager asks\n * the parent's pi-plan-mode, synchronously on the parent's `pi.events`, whether it\n * is planning; when it is, the answer carries the Plan tool policy, and this\n * module applies it to every call the child makes. No answer means pi-plan-mode is\n * not installed, and nothing changes.\n *\n * The contract mirrors `packages/plan-mode/src/child-policy.ts`, repeated rather\n * than imported because either package installs without the other.\n */\nimport type { ToolInfo } from \"@earendil-works/pi-coding-agent\";\nimport type { AgentRecord } from \"./types.js\";\n\nexport const PLAN_MODE_STATE_QUERY = \"pi-plan-mode:state-query\";\n/** pi-plan-mode asks here whether a compatible gate is installed; answering is the handshake. */\nexport const PLAN_MODE_GATE_QUERY = \"pi-plan-mode:gate-query\";\nconst PLAN_MODE_STATE_VERSION = 1;\n\n/** Buses on which pi-plan-mode has shown itself by asking {@link PLAN_MODE_GATE_QUERY}. */\nconst planModeSeen = new WeakSet<object>();\n\n/**\n * Answer pi-plan-mode's gate query, so Plan admits `Agent` and friends, and remember that Plan\n * mode is installed on this bus: from then on a state query nobody answers fails closed.\n */\nexport function answerPlanGateQueries(events: { on(channel: string, handler: (data: unknown) => void): unknown }): void {\n events.on(PLAN_MODE_GATE_QUERY, (data) => {\n planModeSeen.add(events);\n const reply = (data as { reply?: unknown } | undefined)?.reply;\n if (typeof reply === \"function\") reply({ version: PLAN_MODE_STATE_VERSION, gate: \"@nredd/pi-subagents\" });\n });\n}\n\n/** Thrown when pi-plan-mode is installed but did not answer whether it is planning. */\nexport const PLAN_MODE_SILENT_ERROR =\n \"Plan mode is installed but did not answer whether it is planning, so this subagent was not started. Reload Pi, or update @nredd/pi-plan-mode and @nredd/pi-subagents together.\";\n\n/** One tool call inside a child session. */\ninterface PlanModeChildToolCall {\n toolName: string;\n input: unknown;\n cwd: string;\n tool: ToolInfo | undefined;\n}\n\n/** Why Plan mode refuses a child's tool call, or `undefined` when it may run. */\nexport type PlanToolPolicy = (call: PlanModeChildToolCall) => string | undefined;\n\n/**\n * The Plan restriction one child run is under. Mutable on purpose: it is decided\n * per run (a spawn, then each resume) while the hooks reading it are installed\n * once, on the child's session.\n */\nexport interface PlanGate {\n policy?: PlanToolPolicy;\n}\n\n/** Tools a child keeps without asking: safe built-ins only. */\nconst FAIL_CLOSED_TOOLS: ReadonlySet<string> = new Set([\"read\", \"grep\", \"find\", \"ls\"]);\n\n/**\n * For a planner that says it is active but sent no policy this host understands:\n * nothing beyond the safe built-ins, so a contract mismatch can never run a child\n * unrestricted.\n */\nconst failClosedPolicy: PlanToolPolicy = ({ toolName }) =>\n FAIL_CLOSED_TOOLS.has(toolName)\n ? undefined\n : `Plan mode is active and sent no tool policy this subagent understands, so '${toolName}' is blocked.`;\n\n/**\n * Ask the parent's pi-plan-mode whether a child started now must plan. Returns\n * the policy to run it under, or `undefined` when nobody is planning. Several\n * answers (two Plan extensions) combine fail-closed: any active one restricts.\n * A malformed answer (not version 1 with a boolean `active`) restricts like an unusable one.\n * When Plan mode is installed but nothing answers, a new child is refused\n * (`silent: \"refuse\"`, which throws) and a resumed one runs fail-closed.\n */\nexport function queryPlanPolicy(\n events: { emit(channel: string, data: unknown): void } | undefined,\n silent: \"refuse\" | \"restrict\" = \"refuse\",\n): PlanToolPolicy | undefined {\n // Hosts without an event bus (bare programmatic callers) cannot run pi-plan-mode either.\n if (!events) return undefined;\n const policies: PlanToolPolicy[] = [];\n let answered = false;\n events.emit(PLAN_MODE_STATE_QUERY, {\n version: PLAN_MODE_STATE_VERSION,\n reply: (state: unknown) => {\n const answer = state as { version?: unknown; active?: unknown; evaluate?: unknown } | undefined;\n // Only a well-formed answer says whether Plan is on; anything else restricts, never frees.\n if (answer?.version !== PLAN_MODE_STATE_VERSION || typeof answer.active !== \"boolean\") {\n policies.push(failClosedPolicy);\n return;\n }\n answered = true;\n if (!answer.active) return;\n policies.push(typeof answer.evaluate === \"function\" ? (answer.evaluate as PlanToolPolicy) : failClosedPolicy);\n },\n });\n if (!answered && policies.length === 0 && planModeSeen.has(events)) {\n if (silent === \"refuse\") throw new Error(PLAN_MODE_SILENT_ERROR);\n return failClosedPolicy;\n }\n if (policies.length === 0) return undefined;\n return (call) => {\n for (const policy of policies) {\n const reason = policy(call);\n if (reason !== undefined) return reason;\n }\n return undefined;\n };\n}\n\n/**\n * Whether a Plan policy is active on `events` now, failing closed: an installed Plan mode that\n * answers badly or not at all counts as planning. For work that would otherwise outlive Plan\n * unrestricted (a schedule, a quota-parked dispatch, steering an unrestricted child).\n */\nexport function planningNow(events: { emit(channel: string, data: unknown): void } | undefined): boolean {\n return queryPlanPolicy(events, \"restrict\") !== undefined;\n}\n\n/**\n * Whether a steer must be refused: the agent is running or queued under no Plan policy (it started\n * before Plan) while Plan is active, so the steer would drive it with its full surface. The one\n * predicate for `steer_subagent` and `subagents:rpc:steer`.\n */\nexport function planSteerBlocked(\n record: Pick<AgentRecord, \"status\" | \"planGate\">,\n events: { emit(channel: string, data: unknown): void } | undefined,\n): boolean {\n return (record.status === \"running\" || record.status === \"queued\") && !record.planGate?.policy && planningNow(events);\n}\n\n/** Plan's model must not steer a child that runs without Plan's restrictions. */\nexport function planSteerRefusal(id: string): string {\n return (\n `Cannot steer agent \"${id}\" while Plan mode is active: it started before Plan and runs without Plan's restrictions, so a steer could make it edit. ` +\n \"Wait for it to finish and steer it then (that resumes it read-only), stop it with stop_subagent, or leave Plan mode (/plan exit) first.\"\n );\n}\n\n/** A scheduled agent fires as a fresh spawn, after Plan, with nothing restricting it. */\nexport const PLAN_SCHEDULE_REFUSAL =\n \"Cannot schedule an agent while Plan mode is active: it would start later, after Plan, without Plan's restrictions. Start it now, or leave Plan mode first.\";\n\n/** A quota-parked dispatch is a scheduled job too. */\nexport const PLAN_PARK_REFUSAL =\n \"The agent was not started or parked: Plan mode is active, and a parked agent would start after Plan without Plan's restrictions. Retry after the reset, or leave Plan mode first.\";\n\n/**\n * The refusal for one child tool call, or `undefined`. Tools this extension\n * injects (nested delegation, whose children inherit the gate; StructuredOutput;\n * the workflow refusal) are exempt: Plan's policy has no entry for them.\n */\nexport function planGateReason(\n gate: PlanGate | undefined,\n call: { toolName: string; input: unknown; cwd: string },\n tools: () => ToolInfo[],\n exempt: ReadonlySet<string>,\n): string | undefined {\n const policy = gate?.policy;\n if (!policy || exempt.has(call.toolName)) return undefined;\n return policy({ ...call, tool: tools().find((tool) => tool.name === call.toolName) });\n}\n\n/** Told to a child started while planning, so a refused write is not a surprise. */\nexport const PLAN_MODE_CHILD_PROMPT = `<plan_mode>\nYour parent is in Plan mode, so you are too: investigate and report, do not change anything.\nedit and write are blocked, bash runs only reviewed read-only commands, and other tools run only when Plan mode admits them.\n</plan_mode>`;\n", "/**\n * prompts.ts \u2014 System prompt builder for agents.\n */\n\nimport { PLAN_MODE_CHILD_PROMPT } from \"./plan-mode-children.js\";\nimport type { AgentConfig, EnvInfo } from \"./types.js\";\n\n/** Extra sections to inject into the system prompt (memory, skills, etc.). */\nexport interface PromptExtras {\n /** Persistent memory content to inject (first 200 lines of MEMORY.md + instructions). */\n memoryBlock?: string;\n /** Preloaded skill contents to inject. */\n skillBlocks?: { name: string; content: string }[];\n /**\n * Parent directory the worktree copy was created from. Set only for\n * `isolation: \"worktree\"` spawns \u2014 triggers the block that tells the agent\n * to stay in the copy.\n */\n worktreeBase?: string;\n /** Set when the parent was planning at spawn: the child is told it plans too (#437). */\n planMode?: boolean;\n /**\n * Set only for a workflow's own children, and only when they have no\n * `StructuredOutput` tool to answer through.\n *\n * A workflow child's final text is not read by a human \u2014 it is the value\n * `agent()` resolves to, and the script interpolates it straight into the\n * next stage's prompt. Without this, children answer the way every other\n * subagent does (a report addressed to a reader), and the padding becomes\n * input tokens for the stage downstream. Claude Code's `Workflow` tool\n * documents this contract to the script-writing model; this is the end of it\n * that makes the documentation true.\n *\n * Deliberately NOT applied to every subagent. In pi an ordinary agent's\n * output IS read by a human \u2014 through FleetView, the conversation viewer and\n * `get_subagent_result` \u2014 so terse raw data would be the wrong answer there.\n */\n workflowChild?: boolean;\n /**\n * Set when the agent lists `allowed_subagents` but got no `Agent` tool (depth\n * cap, isolation, `disallowed_tools`). Without the line it reads the missing tool as a fault and\n * emulates one, e.g. by shelling out to `claude -p`, which escapes the depth\n * cap, quota admission and usage reporting.\n */\n nestingDisabled?: boolean;\n}\n\n/**\n * Build the system prompt for an agent from its config.\n *\n * - \"replace\" mode: env header + config.systemPrompt (full control, no parent identity)\n * - \"append\" mode: parent system prompt + sub-agent context + env header + config.systemPrompt\n * - \"append\" with empty systemPrompt: pure parent clone\n *\n * Both modes include an `<active_agent name=\"${config.name}\"/>` tag so downstream\n * extensions (e.g. permission/policy systems) can resolve per-agent policy\n * inside the child session by parsing the system prompt. In replace mode the tag\n * is prepended; in append mode it follows the shared inherited content so the\n * parent prompt forms an identical, cacheable byte prefix with the parent\n * session (the LLM's KV cache can then reuse those tokens across every spawn).\n *\n * @param parentSystemPrompt The parent agent's effective system prompt (for append mode).\n * @param extras Optional extra sections to inject (memory, preloaded skills).\n */\nexport function buildAgentPrompt(\n config: AgentConfig,\n cwd: string,\n env: EnvInfo,\n parentSystemPrompt?: string,\n extras?: PromptExtras,\n): string {\n const activeAgentTag = `<active_agent name=\"${config.name}\"/>\\n\\n`;\n\n const envBlock = `# Environment\nWorking directory: ${cwd}\n${env.isGitRepo ? `Git repository: yes\\nBranch: ${env.branch}` : \"Not a git repository\"}\nPlatform: ${env.platform}`;\n\n // A worktree agent is told its cwd twice: by the env block above (the copy)\n // and by whatever names the main checkout \u2014 the inherited parent prompt in\n // append mode, or the task prompt in either mode. It follows the latter and\n // works in the shared tree (#187), so resolve the contradiction explicitly.\n const worktreeBlock = extras?.worktreeBase\n ? `\\n\\n<worktree_isolation>\nYour working directory is an isolated git worktree copy of ${extras.worktreeBase}.\nWork only inside it \u2014 never in ${extras.worktreeBase}, even if other instructions name that path as your working directory.\n</worktree_isolation>`\n : \"\";\n\n // The script, not a person, reads what this child returns \u2014 see\n // `PromptExtras.workflowChild` for why only workflow children get this.\n const workflowBlock = extras?.workflowChild\n ? `\\n\\n<workflow_child>\nYour final message IS the return value of this task. A workflow script captures it and passes it to the next stage; no person reads it.\nReturn only the answer, in exactly the shape the prompt asks for \u2014 no preamble, no summary of what you did, no offer to continue.\n</workflow_child>`\n : \"\";\n\n const planModeBlock = extras?.planMode ? `\\n\\n${PLAN_MODE_CHILD_PROMPT}` : \"\";\n\n const nestingBlock = extras?.nestingDisabled\n ? `\\n\\n<nesting_disabled>\nNested subagents are disabled for this session, so you have no Agent tool. Do the work yourself, inline.\nDo not emulate subagents by running another agent CLI (e.g. \\`claude -p\\`) from bash.\n</nesting_disabled>`\n : \"\";\n\n // Build optional extras suffix\n const extraSections: string[] = [];\n if (extras?.memoryBlock) {\n extraSections.push(extras.memoryBlock);\n }\n if (extras?.skillBlocks?.length) {\n for (const skill of extras.skillBlocks) {\n extraSections.push(`\\n# Preloaded Skill: ${skill.name}\\n${skill.content}`);\n }\n }\n const extrasSuffix = extraSections.length > 0 ? \"\\n\\n\" + extraSections.join(\"\\n\") : \"\";\n\n if (config.promptMode === \"append\") {\n const identity = parentSystemPrompt || genericBase;\n\n const bridge = `<sub_agent_context>\nYou are operating as a sub-agent invoked to handle a specific task.\n- Use the read tool instead of cat/head/tail\n- Use the edit tool instead of sed/awk\n- Use the write tool instead of echo/heredoc\n- Use the find tool instead of bash find/ls for file search\n- Use the grep tool instead of bash grep/rg for content search\n- Make independent tool calls in parallel\n- Use absolute file paths\n- Do not use emojis\n- Be concise but complete\n</sub_agent_context>`;\n\n const customSection = config.systemPrompt?.trim()\n ? `\\n\\n<agent_instructions>\\n${config.systemPrompt}\\n</agent_instructions>`\n : \"\";\n\n // Place shared/stable content first so the LLM's KV cache can reuse the\n // inherited prefix across all subagent invocations. The parent prompt is\n // placed verbatim (no wrapper tag) so it forms an identical byte prefix\n // with the parent session, maximising KV cache hits. The <active_agent>\n // tag and env block vary per call and are placed after the cached prefix.\n return identity + \"\\n\\n\" + bridge + \"\\n\\n\" + activeAgentTag + envBlock + worktreeBlock + planModeBlock + workflowBlock + nestingBlock + customSection + extrasSuffix;\n }\n\n // \"replace\" mode \u2014 env header + the config's full system prompt\n const replaceHeader = `You are a pi coding agent sub-agent.\nYou have been invoked to handle a specific task autonomously.\n\n${envBlock}`;\n\n return activeAgentTag + replaceHeader + worktreeBlock + planModeBlock + workflowBlock + nestingBlock + \"\\n\\n\" + config.systemPrompt + extrasSuffix;\n}\n\n/** Fallback base prompt when parent system prompt is unavailable in append mode. */\nconst genericBase = `# Role\nYou are a general-purpose coding agent for complex, multi-step tasks.\nYou have full access to read, write, edit files, and execute commands.\nDo what has been asked; nothing more, nothing less.`;\n", "/** Normalize explicit settings paths before Pi's real package manager resolves them. */\nimport { DefaultPackageManager, DefaultResourceLoader, SettingsManager } from \"@earendil-works/pi-coding-agent\";\nimport { normalizeHomePath } from \"./home-paths.js\";\n\ntype ResourceLoaderOptions = ConstructorParameters<typeof DefaultResourceLoader>[0];\ntype ResourceSettings = ReturnType<SettingsManager[\"getGlobalSettings\"]>;\n\nconst RESOURCE_FIELDS = [\"extensions\", \"skills\", \"prompts\", \"themes\"] as const;\n\n/** Keep filter modifiers and non-home paths intact; only replace leading home references. */\nfunction expandSetting(entry: string, homeDir: string, modifiers = true): string {\n const prefix = modifiers && /^[!+-]/.test(entry) ? entry[0] : \"\";\n const path = entry.slice(prefix.length);\n const trimmed = path.trim();\n if (trimmed !== \"~\" && !trimmed.startsWith(\"~/\") && !(process.platform === \"win32\" && trimmed.startsWith(\"~\\\\\"))) return entry;\n return prefix + normalizeHomePath(trimmed, homeDir);\n}\n\n/** Return copies so loading resources never changes persisted settings or their source objects. */\nexport function normalizeResourceSettings(settings: ResourceSettings, homeDir: string): ResourceSettings {\n const normalized = { ...settings };\n for (const field of RESOURCE_FIELDS) {\n if (settings[field]) normalized[field] = settings[field].map(entry => expandSetting(entry, homeDir));\n }\n if (settings.packages) {\n normalized.packages = settings.packages.map(pkg => {\n if (typeof pkg === \"string\") return expandSetting(pkg, homeDir, false);\n const copy = { ...pkg, source: expandSetting(pkg.source, homeDir, false) };\n for (const field of RESOURCE_FIELDS) {\n if (pkg[field]) copy[field] = pkg[field].map(entry => expandSetting(entry, homeDir));\n }\n return copy;\n });\n }\n return normalized;\n}\n\ntype PackageManagerOptions = ConstructorParameters<typeof DefaultPackageManager>[0];\n\n/** Wrap settings readers once so Pi receives injected-home resource paths. */\nfunction normalizeHomeResourceSettings(settingsManager: SettingsManager, homeDir: string): SettingsManager {\n const globalSettings = settingsManager.getGlobalSettings.bind(settingsManager);\n const projectSettings = settingsManager.getProjectSettings.bind(settingsManager);\n // Wrap the public readers, not a cached snapshot: reload and project-trust\n // decisions continue to be owned by Pi, and every read receives fresh copies.\n Object.assign(settingsManager, {\n getGlobalSettings: () => normalizeResourceSettings(globalSettings(), homeDir),\n getProjectSettings: () => normalizeResourceSettings(projectSettings(), homeDir),\n });\n return settingsManager;\n}\n\n/** Build Pi's package manager with injected-home settings normalization. */\nexport function createHomePackageManager(options: PackageManagerOptions, homeDir?: string): DefaultPackageManager {\n if (homeDir === undefined) return new DefaultPackageManager(options);\n // `homeDir` also redirects Pi's automatic `<home>/.agents/skills` root (nredd/pi#13).\n return new DefaultPackageManager({ ...options, homeDir, settingsManager: normalizeHomeResourceSettings(options.settingsManager, homeDir) });\n}\n\n/** Use the real loader/manager while preventing ambient-home expansion of explicit settings. */\nexport function createHomeResourceLoader(options: ResourceLoaderOptions, homeDir?: string): DefaultResourceLoader {\n if (homeDir === undefined) return new DefaultResourceLoader(options);\n const settingsManager = options.settingsManager ?? SettingsManager.create(options.cwd, options.agentDir);\n return new DefaultResourceLoader({ ...options, homeDir, settingsManager: normalizeHomeResourceSettings(settingsManager, homeDir) });\n}\n", "/** Resolve named preloaded skills through Pi's configured resource discovery. */\n\nimport { type Dirent, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, realpathSync, rmSync, statSync, symlinkSync } from \"node:fs\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport { loadSkills, type ResolvedResource, SettingsManager, type SettingsManager as SettingsManagerType } from \"@earendil-works/pi-coding-agent\";\nimport { isSymlink, isUnsafeName, safeReadFile } from \"./memory.js\";\nimport { createHomePackageManager } from \"./resource-loader.js\";\n\n/** Discovery is inspect-only: missing sources are never installed or activated. */\nconst skipMissingSource = async (): Promise<\"skip\"> => \"skip\";\n\nexport interface PreloadedSkill {\n name: string;\n content: string;\n}\n\nexport interface SkillPreloadOptions {\n agentDir: string;\n settingsManager: SettingsManagerType;\n homeDir?: string;\n}\n\n/**\n * Load named skills through Pi, retaining the preloader's legacy user roots.\n *\n * Pi owns configured package discovery, parsing, trust, and missing-package\n * handling. A second untrusted manager exposes the user/package candidates\n * which Pi's realpath collapse can hide behind a rejected project symlink.\n */\nexport async function preloadSkills(\n skillNames: string[],\n cwd: string,\n options: SkillPreloadOptions,\n): Promise<PreloadedSkill[]> {\n if (skillNames.length === 0) return [];\n const primary = createHomePackageManager({ cwd, agentDir: options.agentDir, settingsManager: options.settingsManager }, options.homeDir);\n const primaryResources = await primary.resolve(skipMissingSource);\n const fallbackSettings = SettingsManager.create(cwd, options.agentDir, { projectTrusted: false });\n const fallback = createHomePackageManager({ cwd, agentDir: options.agentDir, settingsManager: fallbackSettings }, options.homeDir);\n const fallbackResources = await fallback.resolve(skipMissingSource);\n\n const rejectedProjectPaths = new Set(primaryResources.skills\n .filter(resource => isTier(resource, \"project\") && isSymlinkedProjectSkill(resource, cwd))\n .map(resource => canonicalPath(resource.path)));\n // A path that cannot be canonicalized never matches, so it is never restored.\n const isBehindRejectedAlias = (resource: ResolvedResource): boolean => {\n const canonical = canonicalPath(resource.path);\n return canonical !== undefined && rejectedProjectPaths.has(canonical);\n };\n // Package candidates collapsed behind a rejected project alias, resolved with\n // Pi's own project package filters applied.\n const aliasFreeSkills = rejectedProjectPaths.size === 0 ? [] : await resolveAliasFreePackageSkills(cwd, options);\n const recoveredPackages = aliasFreeSkills.filter(isBehindRejectedAlias);\n\n // Resolve native disabled paths through Pi's parser, preserving every filter form it supports.\n const disabledNames = new Set(loadTier(\n [...primaryResources.skills, ...fallbackResources.skills, ...recoveredPackages].filter(resource => !resource.enabled),\n cwd,\n options.agentDir,\n ).map(skill => skill.name));\n const project = discoveredSkills(\n primaryResources.skills.filter(resource => resource.enabled && isTier(resource, \"project\") && !isSymlinkedProjectSkill(resource, cwd)),\n cwd,\n options.agentDir,\n );\n const user = discoveredSkills(\n [\n ...primaryResources.skills,\n // Only restore a user candidate Pi collapsed behind a rejected project alias.\n // Other fallback user resources could bypass Pi's project filters.\n ...fallbackResources.skills.filter(isBehindRejectedAlias),\n ].filter(resource => resource.enabled && isTier(resource, \"user\") && !isAmbientUserAgentsSkill(resource, options.homeDir)),\n cwd,\n options.agentDir,\n );\n const packages = discoveredSkills(\n [\n ...primaryResources.skills,\n // Only restore a package candidate Pi collapsed behind a rejected project alias.\n ...recoveredPackages,\n ].filter(resource => resource.enabled && isTier(resource, \"package\") && !isAmbientUserAgentsSkill(resource, options.homeDir)),\n cwd,\n options.agentDir,\n );\n\n // Historical user roots, including their raw top-level `<name>.md` lookup.\n const home = resolve(options.homeDir ?? homedir());\n const legacyUserRoots = [join(options.agentDir, \"skills\"), join(home, \".agents\", \"skills\"), join(home, \".pi\", \"skills\")];\n return skillNames.map(name => {\n const native = project.get(name) ?? user.get(name) ?? packages.get(name);\n const content = native\n ?? (disabledNames.has(name)\n ? undefined\n : (options.settingsManager.isProjectTrusted() ? findInRoots(projectSkillRoots(cwd).map(root => join(root, \"skills\")), name, false) : undefined)\n ?? findInRoots(legacyUserRoots, name, true));\n return { name, content: content ?? `(Skill \"${name}\" not found in Pi's configured skill resources)` };\n });\n}\n\n/** Precedence tier of a resolved skill: top-level project or user resources, or package resources. */\nfunction isTier(resource: ResolvedResource, tier: \"project\" | \"user\" | \"package\"): boolean {\n return tier === \"package\" ? resource.metadata.origin === \"package\" : resource.metadata.origin === \"top-level\" && resource.metadata.scope === tier;\n}\n\n/** Absolutize an existing local project package source, which Pi resolves against `<cwd>/.pi`. */\nfunction absolutizeProjectSource(source: string, cwd: string): string {\n const local = resolve(cwd, \".pi\", source);\n return !source.startsWith(\"npm:\") && existsSync(local) ? local : source;\n}\n\n/**\n * Resolve package skills as Pi would, minus the project's top-level skill dirs.\n *\n * Pi collapses resources by realpath, so a rejected project symlink can hide a\n * package skill together with the project package filter that applies to it.\n * Resolving from an empty scratch cwd, with the real project settings and\n * npm/git install roots carried over, keeps Pi as the owner of those filters.\n */\nasync function resolveAliasFreePackageSkills(cwd: string, options: SkillPreloadOptions): Promise<ResolvedResource[]> {\n const scratch = mkdtempSync(join(tmpdir(), \"skill-preload-\"));\n try {\n for (const dir of [\"npm\", \"git\"]) {\n const real = join(cwd, \".pi\", dir);\n if (!existsSync(real)) continue;\n mkdirSync(join(scratch, \".pi\"), { recursive: true });\n symlinkSync(real, join(scratch, \".pi\", dir), \"dir\");\n }\n const project = options.settingsManager.getProjectSettings();\n const settings = {\n global: options.settingsManager.getGlobalSettings(),\n project: { ...project, packages: project.packages?.map(pkg => typeof pkg === \"string\"\n ? absolutizeProjectSource(pkg, cwd)\n : { ...pkg, source: absolutizeProjectSource(pkg.source, cwd) }) },\n };\n // Pi's public storage seam replaces the scratch cwd's settings with the real\n // ones. `normalizeHomeResourceSettings` cannot: it only rewrites a manager's\n // own settings, and `createHomePackageManager` still applies it on top.\n const settingsManager = SettingsManager.fromStorage(\n { withLock: (scope, read) => void read(JSON.stringify(settings[scope])) },\n { projectTrusted: options.settingsManager.isProjectTrusted() },\n );\n const manager = createHomePackageManager({ cwd: scratch, agentDir: options.agentDir, settingsManager }, options.homeDir);\n return (await manager.resolve(skipMissingSource)).skills.filter(resource => resource.metadata.origin === \"package\");\n } finally {\n rmSync(scratch, { recursive: true, force: true });\n }\n}\n\n/** Parse resolved skill paths with Pi's own loader and validation. */\nfunction loadTier(resources: ResolvedResource[], cwd: string, agentDir: string): ReturnType<typeof loadSkills>[\"skills\"] {\n return loadSkills({ cwd, agentDir, skillPaths: resources.map(resource => resource.path), includeDefaults: false }).skills;\n}\n\n/** Load Pi-valid skills from a precedence tier, retaining the first declared name. */\nfunction discoveredSkills(resources: ResolvedResource[], cwd: string, agentDir: string): Map<string, string> {\n return new Map(loadTier(resources, cwd, agentDir).map(skill => [skill.name, readFileSync(skill.filePath, \"utf-8\").trim()]));\n}\n\n/** Find a named legacy skill under roots in order without broadening Pi discovery. */\nfunction findInRoots(roots: string[], name: string, trusted: boolean): string | undefined {\n if (isUnsafeName(name)) return undefined;\n for (const root of roots) {\n const content = findInRoot(root, name, trusted);\n if (content !== undefined) return content;\n }\n return undefined;\n}\n\n/** Match the former preloader's flat-file and recursive Agent Skills lookup. */\nfunction findInRoot(root: string, name: string, trusted: boolean): string | undefined {\n if (!trusted && isPathThroughSymlink(dirname(root), root)) return undefined;\n const flat = readSkillFile(join(root, `${name}.md`), trusted)?.trim();\n if (flat !== undefined) return flat;\n if (!existsSync(root)) return undefined;\n\n const queue = [root];\n const seen = new Set<string>();\n // `root` passed the symlink check above and every queued directory passed it before it was\n // pushed, so `current` needs no second check. Iteration visits entries pushed meanwhile, in order.\n for (const current of queue) {\n if (trusted) {\n const canonical = canonicalPath(current);\n // A directory raced away since it was queued has nothing left to read.\n if (canonical === undefined || seen.has(canonical)) continue;\n seen.add(canonical);\n }\n let entries: Dirent<string>[];\n try {\n entries = readdirSync(current, { withFileTypes: true }).sort((left, right) => Number(left.name > right.name) - Number(left.name < right.name));\n } catch {\n continue;\n }\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue;\n const path = join(current, entry.name);\n if (!trusted && isPathThroughSymlink(dirname(root), path)) continue;\n const isDirectory = entry.isDirectory() || (trusted && entry.isSymbolicLink() && isDirectoryTarget(path));\n if (!isDirectory) continue;\n const skillFile = join(path, \"SKILL.md\");\n if (existsSync(skillFile)) {\n const content = entry.name === name ? readSkillFile(skillFile, trusted)?.trim() : undefined;\n if (content !== undefined) return content;\n continue;\n }\n queue.push(path);\n }\n }\n return undefined;\n}\n\nfunction readSkillFile(path: string, trusted: boolean): string | undefined {\n if (!trusted) return safeReadFile(path);\n try {\n return statSync(path).isFile() ? readFileSync(path, \"utf-8\") : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isDirectoryTarget(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Match Pi's realpath identity without importing its private path utility.\n *\n * Unlike Pi, an uncanonicalizable path (raced away, EACCES) yields undefined\n * rather than the raw path, so it can never match a rejected alias. That is\n * also why `realOrSelf` in `package-resources.ts` is not reused: it falls back\n * to the realpath of the nearest existing parent.\n */\nfunction canonicalPath(path: string): string | undefined {\n try {\n return realpathSync(path);\n } catch {\n return undefined;\n }\n}\n\n/** Exclude Pi's ambient user root when a caller supplies a distinct injected home. */\nexport function isAmbientUserAgentsSkill(resource: ResolvedResource, homeDir?: string, runtimeHome = homedir()): boolean {\n if (homeDir === undefined || resource.metadata.scope !== \"user\" || resource.metadata.source !== \"auto\") return false;\n const injectedRoot = join(resolve(homeDir), \".agents\", \"skills\");\n return !isPathWithin(injectedRoot, resource.path) && isPathWithin(join(runtimeHome, \".agents\", \"skills\"), resource.path);\n}\n\n/** Reject project symlinks before accepting their resources or resolving collisions. Callers pass project-tier resources only. */\nfunction isSymlinkedProjectSkill(resource: ResolvedResource, cwd: string): boolean {\n return projectSkillRoots(cwd).some(root => isPathThroughSymlink(root, resource.path));\n}\n\n/** Match Pi's project skill roots while checking their parent directories too. */\nfunction projectSkillRoots(cwd: string): string[] {\n const roots = [join(cwd, \".pi\")];\n let directory = resolve(cwd);\n while (true) {\n roots.push(join(directory, \".agents\"));\n if (existsSync(join(directory, \".git\"))) break;\n const parent = dirname(directory);\n if (parent === directory) break;\n directory = parent;\n }\n return roots;\n}\n\n/** Textual containment. Unlike `isInside` in `package-resources.ts`, it must not canonicalize: that would erase the symlinks callers look for. */\nfunction isPathWithin(root: string, path: string): boolean {\n const relativePath = relative(resolve(root), resolve(path));\n return relativePath === \"\" || (!relativePath.startsWith(`..${sep}`) && relativePath !== \"..\" && !isAbsolute(relativePath));\n}\n\nfunction isPathThroughSymlink(root: string, path: string): boolean {\n const absoluteRoot = resolve(root);\n if (!isPathWithin(absoluteRoot, path)) return false;\n const relativePath = relative(absoluteRoot, resolve(path));\n let current = absoluteRoot;\n if (isSymlink(current)) return true;\n for (const segment of relativePath.split(sep)) {\n current = join(current, segment);\n if (isSymlink(current)) return true;\n }\n return false;\n}\n", "/**\n * stale-ctx.ts -- recognising pi's \"extension ctx is stale\" failure.\n *\n * pi invalidates an extension runner on reload and on session replacement\n * (/new, /fork, /resume). Anything that still reaches the old runner or its\n * `pi` throws this message (#145).\n */\n\n/** Matched on the stable prefix of core's message. */\nexport const STALE_CTX_RE = /extension ctx is stale after session replacement or reload/i;\n\n/** Whether `error` (an `Error` or a message string) is the stale-ctx failure. */\nexport function isStaleCtxError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : typeof error === \"string\" ? error : \"\";\n return STALE_CTX_RE.test(message);\n}\n", "/**\n * structured-output.ts \u2014 the synthetic tool behind `agent(prompt, { schema })`.\n *\n * A workflow script that passes a `schema` wants an *object* back, not prose it\n * has to parse. Claude Code does this by giving the child a `StructuredOutput`\n * tool whose input schema is the caller's schema, so the provider fills the\n * fields, and returning the validated payload as the agent's result.\n *\n * We do the same, with one gap named up front: Claude Code *forces* the call,\n * and we cannot. `toolChoice` exists in pi-ai's provider layer but is not\n * plumbed through `AgentSession`, so an extension has no way to require a\n * particular tool. What we have instead is three softer pressures \u2014\n *\n * 1. `constrainedSampling`, so providers that support it hold the payload to\n * the schema at sampling time;\n * 2. the tool's description, snippet and guideline, which say the answer must\n * come through this call;\n * 3. validation here, answering a bad payload with `isError` so the model\n * sees what was wrong and calls again inside the same run.\n *\n * \u2014 and, when all three fail, one more prompt from `runAgent`. See\n * {@link structuredRetryPrompt}.\n *\n * The name matches Claude Code's exactly, so a ported prompt that mentions\n * `StructuredOutput` is still telling the truth.\n */\n\nimport { defineTool, type ToolDefinition } from \"@earendil-works/pi-coding-agent\";\nimport type { CompiledSchema } from \"./workflow/json-schema.js\";\n\n/**\n * Deliberately NOT added to `SUBAGENT_TOOL_NAMES`: that list becomes\n * `EXCLUDED_TOOL_NAMES`, which is exactly the denial this tool has to avoid.\n * Nor to `BUILTIN_TOOL_NAMES` \u2014 it is ours to inject, never a name a user may\n * ask for in an agent's `tools:` frontmatter.\n */\nexport const STRUCTURED_OUTPUT_TOOL_NAME = \"StructuredOutput\";\n\n/** What the child produced, filled in as the tool is called. */\nexport interface StructuredCapture {\n /** The last payload that validated, canonicalised. Absent until one does. */\n json?: string;\n /** Why the most recent attempt was rejected, for the retry prompt. */\n lastError?: string;\n /** Whether the tool was called at all \u2014 \"never tried\" reads differently. */\n called: boolean;\n}\n\nexport function createStructuredCapture(): StructuredCapture {\n return { called: false };\n}\n\n/**\n * Build the tool for one child.\n *\n * `capture` is the box the caller reads afterwards. It is passed in rather than\n * returned so `runAgent` owns its lifetime and can consult it on every exit\n * path, including the ones where the tool was never reached.\n */\nexport function createStructuredOutputTool(\n compiled: CompiledSchema,\n capture: StructuredCapture,\n): ToolDefinition {\n return defineTool({\n name: STRUCTURED_OUTPUT_TOOL_NAME,\n label: \"Structured Output\",\n description:\n \"Report your final answer. Call this exactly once, with the complete result, and put everything the \"\n + \"caller needs inside the arguments \u2014 text written outside this call is discarded. If a call is \"\n + \"rejected for not matching the schema, fix the reported fields and call it again.\",\n promptSnippet: \"Report your final answer as structured data\",\n promptGuidelines: [\n \"Your final answer MUST be reported by calling StructuredOutput. Prose outside that call is discarded.\",\n ],\n // The caller's schema *is* the tool's input schema, verbatim \u2014 that is what\n // makes the provider fill the fields. pi types this as TypeBox's `TSchema`,\n // which v1 defines as an open interface, so a plain JSON Schema satisfies\n // it without a cast at runtime or a conversion at author time.\n parameters: compiled.schema as never,\n // \"prefer\", not \"require\": a provider that cannot constrain sampling should\n // fall through to validation-and-retry rather than fail the call outright.\n constrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n // Models occasionally send the whole payload as one JSON string instead of\n // an object. Recovering that costs nothing and saves a whole retry.\n prepareArguments: (args: unknown) => {\n if (typeof args !== \"string\") return args as never;\n try {\n return JSON.parse(args) as never;\n } catch {\n return args as never;\n }\n },\n execute: async (_toolCallId, params) => {\n capture.called = true;\n const verdict = compiled.check(params);\n if (verdict !== true) {\n capture.lastError = verdict;\n // `isError` puts the reason in front of the model as a tool result, so\n // it can correct itself inside this same run. This is where most\n // mismatches are resolved; the prompt-level retry is the backstop.\n return {\n content: [{\n type: \"text\",\n text: `StructuredOutput did not match the required schema:\\n${verdict}\\nCall it again with a corrected value.`,\n }],\n isError: true,\n details: {},\n };\n }\n // Last valid call wins: a model that calls twice meant the second one.\n capture.json = JSON.stringify(params);\n capture.lastError = undefined;\n return { content: [{ type: \"text\", text: \"Recorded.\" }], details: {} };\n },\n }) as ToolDefinition;\n}\n\n/**\n * The one extra prompt sent when a run ended with nothing captured.\n *\n * Distinguishes \"never called it\" from \"called it wrongly\" \u2014 the two need\n * different corrections, and telling a model it got the shape wrong when it\n * never answered at all sends it looking for a mistake it did not make.\n */\nexport function structuredRetryPrompt(capture: StructuredCapture): string {\n const reason = capture.called && capture.lastError !== undefined\n ? `Your last ${STRUCTURED_OUTPUT_TOOL_NAME} call did not match the required schema: ${capture.lastError}`\n : `You did not call ${STRUCTURED_OUTPUT_TOOL_NAME}, so your answer was not recorded.`;\n return `${reason}\\n\\nCall ${STRUCTURED_OUTPUT_TOOL_NAME} now with your complete final answer. Do not reply with prose.`;\n}\n", "/**\n * mention.ts \u2014 the `@handle` grammar for messaging a subagent from the prompt.\n *\n * Claude Code lets you type `@code-review take another look` at the prompt and\n * routes the message to that agent instead of the main model. Its grammar is\n * reproduced here so the two behave identically:\n *\n * - suggestions fire on `@` at the start of the input or after whitespace,\n * followed by `[\\w-]*` (so `@src/foo.ts` is a file, never an agent);\n * - a send is recognized only at the START of the input, and only with a\n * non-empty message after the handle. That is why a bare `@code-review`\n * goes to the main model rather than anywhere near the agent.\n *\n * A record's own identity is a UUID plus a deliberately non-unique description,\n * neither of which is typeable, so the handle is derived from the agent type.\n * Colliding handles are numbered (`explore`, `explore-2`), which is also what\n * Claude Code's `allocateName` does \u2014 it recycles a name only once the task\n * behind it is gone. Its SendMessage prompt describes the *registry* as\n * latest-wins, which is a different thing and not how names are allocated.\n */\n\n/**\n * Suggestion trigger: `@` at a token boundary plus the partial handle typed so\n * far. Ported from Claude Code, including the CJK sentence-ending punctuation\n * it accepts as a boundary.\n */\nexport const MENTION_TRIGGER = /(^|[\\s\u3002\u3001\uFF1F\uFF01])@([\\w-]*)$/;\n\n/** Send grammar: leading `@handle`, then a non-empty message. */\nconst MENTION_SEND = /^@([\\w-]+)\\s+([\\s\\S]+)$/;\n\n/**\n * Upper bound on a handle, matching Claude Code's `dSS`. Nothing here generates\n * a name this long, but an agent type or a model-supplied name can be arbitrary\n * text, and an unbounded handle would wrap the suggestion popup.\n */\nconst MAX_HANDLE_LENGTH = 64;\n\n/**\n * Handles that address something other than a subagent, and so can never be\n * allocated to one. Claude Code reserves exactly this name (`Vq = \"main\"`),\n * refusing it at spawn and routing it to the main conversation instead.\n */\nconst RESERVED_HANDLES: ReadonlySet<string> = new Set([\"main\"]);\n\n/** Whether `@handle` names the main conversation rather than any subagent. */\nexport function isReservedHandle(handle: string): boolean {\n return RESERVED_HANDLES.has(handle.toLowerCase());\n}\n\n/** Slug of an agent type or name, restricted to the `[\\w-]` the grammar allows. */\nexport function handleBase(type: string): string {\n const slug = type.toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, MAX_HANDLE_LENGTH)\n // The slice can land mid-run and leave the trailing hyphen back.\n .replace(/-+$/, \"\");\n return slug || \"agent\";\n}\n\n/**\n * `base`, else `base-2`, `base-3`, \u2026 \u2014 the first form that is neither `taken`\n * nor reserved. Callers pass one shared `taken` set covering type-derived\n * handles and model-supplied aliases alike, so the two can never collide.\n */\nexport function assignHandle(base: string, taken: ReadonlySet<string>): string {\n let candidate = base;\n let n = 1;\n while (taken.has(candidate) || RESERVED_HANDLES.has(candidate)) {\n n++;\n candidate = `${base}-${n}`;\n }\n return candidate;\n}\n\n/**\n * Map a typed handle back to a registered agent type, so `@explore fix it`\n * reaches the Explore agent even when no instance has ever run. `handleBase` is\n * the single source of truth in both directions, so a type is addressable by\n * exactly the handle its instances would be given.\n */\nexport function resolveHandleToType(handle: string, types: readonly string[]): string | undefined {\n const wanted = handle.toLowerCase();\n // A type slugging to a reserved name is unaddressable rather than shadowing\n // it \u2014 `assignHandle` refuses that name too, so its instances never hold one.\n if (RESERVED_HANDLES.has(wanted)) return undefined;\n return types.find(type => handleBase(type) === wanted);\n}\n\n/**\n * Claude Code documents `@agent-<name>` as the form you type by hand when the\n * picker isn't involved. Accepted here as an exact synonym: the caller tries the\n * handle as written first, so an agent genuinely called `agent-foo` still wins\n * over `@agent-` + `foo`, and only falls back to this when that finds nothing.\n * Returns undefined when the prefix is absent or is the whole handle.\n */\nexport function stripAgentPrefix(handle: string): string | undefined {\n const rest = /^agent-(.+)$/i.exec(handle)?.[1];\n return rest || undefined;\n}\n\n/**\n * A spawn needs the short description every agent surface renders. A mention\n * carries no separate label, so the message itself becomes one: first line,\n * whitespace collapsed, clipped to roughly the 3-5 words the Agent tool asks of\n * the model.\n */\nexport function describeMention(message: string): string {\n const oneLine = message.split(\"\\n\", 1)[0].replace(/\\s+/g, \" \").trim();\n return oneLine.length > 40 ? `${oneLine.slice(0, 39).trimEnd()}\u2026` : oneLine;\n}\n\n/**\n * What Claude Code sends the main model when a mention names an agent it could\n * start. Its `@agent-<type>` mention is not a spawn at all: it becomes an\n * `agent_mention` attachment, which renders to a synthetic `isMeta` user\n * message placed after the user's own untouched text \u2014 no tool forcing, no\n * allowed-tools narrowing, and the Task tool is not even named. The model reads\n * this and calls the tool itself.\n *\n * Ported verbatim from the 2.1.233 bundle's attachment renderer, trailing space\n * before the closing newline included, so the wording the model was trained\n * against is the wording it gets. The one substitution is ours: pi's equivalent\n * of Task is the `Agent` tool, and the agent listing that teaches valid\n * `subagent_type` values is the tool spec rather than a separate attachment.\n */\nexport function agentMentionReminder(type: string): string {\n return `<system-reminder>\\nThe user has expressed a desire to invoke the agent \"${type}\". Please invoke the agent appropriately, passing in the required context to it. \\n</system-reminder>`;\n}\n\n/**\n * Split `@handle message` into its parts, or null when the text isn't a send \u2014\n * a bare handle, a leading file path, or a mention that isn't at the start.\n */\nexport function parseMention(text: string): { handle: string; message: string } | null {\n const match = MENTION_SEND.exec(text);\n if (!match) return null;\n const message = match[2].trim();\n return message ? { handle: match[1], message } : null;\n}\n", "/**\n * process-budget.ts -- one ceiling on running subagents for the whole pi process.\n *\n * `maxConcurrent` and `maxConcurrentForeground` are per `AgentManager`, and\n * there can be more than one manager per process: `/new`, `/resume`, `/fork`\n * and `/reload` activate a fresh one and leave the previous manager alive until\n * its background agents finish. (Subagent sessions do not activate this\n * extension; nested children run in the parent's manager.) Those pools also\n * exempt nested children, workflow children, scheduled jobs and resumes. The budget is the one count all of them share, kept on `globalThis`\n * under `Symbol.for` so every manager and every module instance (a `/reload`\n * loads a fresh copy of this file) sees the same state.\n *\n * Scope is the PROCESS, not the machine: two pi processes each get their own\n * budget. It bounds running agents, not CPU, memory or commands.\n *\n * Every run holds one lease from the moment it is admitted until it actually\n * settles. A parent keeps its lease while it waits on a child: releasing it\n * around a nested call would be wrong, because pi runs a turn's tool calls in\n * parallel and the parent's other tools are still executing.\n *\n * Holding parent leases is what makes a plain cap deadlock: twelve parents\n * each waiting on a child that can never start. The reserve prevents it. With\n * `L` the policy's `maxDepth` (one value for the whole process, NOT a branch's\n * own cap) and `limit(j) = maxActive - nestedReserve * (L - j)`, a run at depth\n * `d` is admitted only while, for EVERY level `j` from `d` to `L`,\n *\n * active at depth <= j < limit(j)\n *\n * (`j = L` is the plain `active < maxActive`). So with `maxActive: 12,\n * nestedReserve: 2, L: 2`, at most ten top-level runs hold slots at once, and\n * the last two only ever go to depth-2 children. Every admission keeps\n * `count(<= j) <= limit(j)` for all `j`, releases only lower counts, and\n * policy changes that could break it wait for an idle process (see\n * `setBudgetPolicy`). Suppose every holder is a parent blocked on a child and\n * `k < L` is the deepest level holding any: then `active = count(<= k) <=\n * limit(k) < limit(k + 1) <= maxActive`, so a depth-`k+1` child fits at every\n * level. Leaves (depth `L`) never wait on anyone, so they finish. That needs\n * `limit` strictly increasing and `limit(1) >= 1` -- `isCoherent` -- and a run\n * deeper than `L` refused outright (`assertWithinBudgetDepth`), since nothing\n * reserves a slot for it. Top-level, workflow and scheduled runs all count as\n * depth 1.\n *\n * Waiters are served first-come-first-served among the ELIGIBLE: a deeper\n * waiter may pass a shallower one whose threshold is not met, which is what the\n * reserve is for. Without that, a root at the head of the line would block the\n * child that its own siblings are waiting on.\n */\n\nconst BUDGET_KEY = Symbol.for(\"pi-subagents:process-budget\");\n\n/** Bumped on any incompatible change to `BudgetState`'s shape. */\nconst BUDGET_VERSION = 2;\n\n/**\n * Queued starts the budget will hold while it is enabled. Only a bound on\n * memory and on runaway fan-out -- a full queue fails the spawn with\n * `BUDGET_QUEUE_FULL_ERROR` instead of parking work nobody will see start.\n */\nexport const MAX_PENDING_SUBAGENTS = 128;\n\nexport const DEFAULT_BUDGET_POLICY: Readonly<BudgetPolicy> = {\n maxActive: 0,\n nestedReserve: 2,\n maxDepth: 2,\n};\n\nexport interface BudgetPolicy {\n /** Process-wide ceiling on running subagents. `0` = off (counted, never enforced). */\n maxActive: number;\n /** Slots held back per nesting level below a run, so children can always start. */\n nestedReserve: number;\n /**\n * The deepest level the reserve covers: the GLOBAL `maxSubagentDepth`, so a\n * project file cannot reshape a process-wide policy. A deeper run is refused.\n */\n maxDepth: number;\n}\n\n/** One admitted run. Released exactly once; later releases are no-ops. */\nexport interface BudgetLease {\n readonly depth: number;\n released: boolean;\n}\n\n/** A start waiting for admission. */\nexport interface BudgetWaiter {\n /** Nesting depth of the run: top-level = 1. */\n depth: number;\n /** Local conditions the owner also needs (its own pool limits). */\n ready: () => boolean;\n /** Takes ownership of the lease. Must not throw; a throw is swallowed and the lease released. */\n grant: (lease: BudgetLease) => void;\n}\n\ninterface BudgetState {\n version: number;\n policy: BudgetPolicy;\n /** A tightening change, applied once no lease is active (`setBudgetPolicy`). */\n pendingPolicy: BudgetPolicy | undefined;\n active: Set<BudgetLease>;\n waiters: BudgetWaiter[];\n pumping: boolean;\n repump: boolean;\n}\n\nexport const BUDGET_QUEUE_FULL_ERROR =\n `Subagent queue is full (${MAX_PENDING_SUBAGENTS} waiting for the process-wide maxActiveSubagents limit). `\n + \"Wait for running agents to finish, or do the work directly.\";\n\nfunction freshState(): BudgetState {\n return {\n version: BUDGET_VERSION,\n policy: { ...DEFAULT_BUDGET_POLICY },\n pendingPolicy: undefined,\n active: new Set(),\n waiters: [],\n pumping: false,\n repump: false,\n };\n}\n\n/**\n * The process's budget state. An incompatible version (a `/reload` onto a\n * build that changed the shape) refuses budget operations until pi restarts.\n * Never fork the state: two private counts could each admit the whole cap.\n */\nfunction state(): BudgetState {\n const g = globalThis as Record<symbol, unknown>;\n const existing = g[BUDGET_KEY] as BudgetState | undefined;\n if (existing === undefined) {\n const created = freshState();\n g[BUDGET_KEY] = created;\n return created;\n }\n if (existing.version === BUDGET_VERSION) return existing;\n throw new Error(\n `[pi-subagents] Incompatible process budget v${String(existing.version)} already loaded (this build uses v${String(BUDGET_VERSION)}). `\n + \"Restart pi before starting more subagents; no private budget will be created.\",\n );\n}\n\n/** The deepest level `policy` reserves for; nesting off still means one level. */\nconst topLevel = (policy: BudgetPolicy): number => Math.max(1, policy.maxDepth);\n\n/**\n * How many runs at depth <= `level` may hold leases before a run at `level` or\n * shallower has to wait. No floor: `isCoherent` keeps it at least one.\n */\nexport function admissionLimit(policy: BudgetPolicy, level: number): number {\n if (policy.maxActive <= 0) return Number.POSITIVE_INFINITY;\n return policy.maxActive - policy.nestedReserve * (topLevel(policy) - level);\n}\n\n/**\n * Whether `policy` is deadlock-free: off, or `limit` strictly increasing from\n * at least one at depth 1 -- a reserve of one or more, and room for one\n * top-level run after reserving for every level below it.\n */\nexport function isCoherent(policy: BudgetPolicy): boolean {\n if (policy.maxActive <= 0 || topLevel(policy) === 1) return true;\n return policy.nestedReserve >= 1 && admissionLimit(policy, 1) >= 1;\n}\n\n/** Every level's limit is at least what it was, so no held lease can block a child that fit before. */\nfunction relaxes(from: BudgetPolicy, to: BudgetPolicy): boolean {\n if (to.maxActive <= 0) return true;\n if (from.maxActive <= 0 || topLevel(from) !== topLevel(to)) return false;\n for (let level = 1; level <= topLevel(to); level++) {\n if (admissionLimit(to, level) < admissionLimit(from, level)) return false;\n }\n return true;\n}\n\nexport function getBudgetPolicy(): BudgetPolicy {\n return { ...state().policy };\n}\n\n/**\n * Replace the policy. Last writer wins: every activation in the process\n * shares it. An incoherent policy is refused with a warning. A change that\n * could strand a waiting child -- turning the budget on, lowering a limit,\n * changing `maxDepth` -- is held until no lease is active, since running\n * parents were admitted under the old limits; turning it off or raising\n * limits applies at once.\n */\nexport function setBudgetPolicy(next: BudgetPolicy): void {\n const policy: BudgetPolicy = {\n maxActive: Math.max(0, Math.floor(next.maxActive)),\n nestedReserve: Math.max(0, Math.floor(next.nestedReserve)),\n maxDepth: Math.max(0, Math.floor(next.maxDepth)),\n };\n if (!isCoherent(policy)) {\n console.warn(\n `[pi-subagents] Ignoring maxActiveSubagents ${String(policy.maxActive)} with nestedSubagentReserve ${String(policy.nestedReserve)} `\n + `at maxSubagentDepth ${String(policy.maxDepth)}: it could deadlock. Nesting needs a reserve of at least 1 and `\n + \"maxActiveSubagents >= nestedSubagentReserve * (maxSubagentDepth - 1) + 1.\",\n );\n return;\n }\n const s = state();\n if (s.active.size === 0 || relaxes(s.policy, policy)) {\n s.policy = policy;\n s.pendingPolicy = undefined;\n pumpBudget();\n } else {\n s.pendingPolicy = policy;\n console.warn(\n `[pi-subagents] Process budget change deferred until all running subagents settle: `\n + `maxActiveSubagents=${String(policy.maxActive)}, nestedSubagentReserve=${String(policy.nestedReserve)}, `\n + `maxSubagentDepth=${String(policy.maxDepth)}. The previous policy remains in force; continuous work can delay this indefinitely.`,\n );\n }\n}\n\n/** The policy waiting for the process to go idle, if any. For diagnostics and tests. */\nexport function getPendingBudgetPolicy(): BudgetPolicy | undefined {\n const pending = state().pendingPolicy;\n return pending === undefined ? undefined : { ...pending };\n}\n\n/**\n * Throw when the budget is on and a run at `depth` is deeper than its policy\n * reserves for: it could wait forever behind its own ancestors. Pass/fail is\n * fixed for the run's life, since `maxDepth` changes only while idle.\n */\nexport function assertWithinBudgetDepth(depth: number): void {\n const { policy } = state();\n if (policy.maxActive > 0 && depth > topLevel(policy)) {\n throw new Error(\n `Nested subagent at depth ${String(depth)} exceeds the process budget's depth ${String(topLevel(policy))} `\n + \"(global maxSubagentDepth). Complete the task directly.\",\n );\n }\n}\n\n/** Running leases and waiting starts, for diagnostics and tests. */\nexport function budgetUsage(): { active: number; pending: number; maxActive: number } {\n const s = state();\n return { active: s.active.size, pending: s.waiters.length, maxActive: s.policy.maxActive };\n}\n\nfunction admits(s: BudgetState, depth: number): boolean {\n const { policy } = s;\n if (policy.maxActive <= 0) return true;\n const top = topLevel(policy);\n const level = Math.max(1, depth);\n if (level > top) return false;\n // Leases deeper than `top` cannot exist while it is on; clamp so they still count in the total.\n const atDepth = new Array<number>(top + 1).fill(0);\n for (const lease of s.active) {\n const index = Math.min(top, Math.max(1, lease.depth));\n atDepth[index] = atDepth[index]! + 1;\n }\n let atOrAbove = 0;\n for (let j = 1; j <= top; j++) {\n atOrAbove += atDepth[j]!;\n if (j >= level && atOrAbove >= admissionLimit(policy, j)) return false;\n }\n return true;\n}\n\nfunction newLease(s: BudgetState, depth: number): BudgetLease {\n const lease: BudgetLease = { depth, released: false };\n s.active.add(lease);\n return lease;\n}\n\n/**\n * Take a lease now, or undefined when this depth is at its limit or an earlier\n * eligible waiter has first claim. Completion listeners can spawn synchronously\n * between release and drain; re-entrant grant callbacks can do the same.\n */\nexport function tryAcquireBudget(depth: number): BudgetLease | undefined {\n const s = state();\n if (!admits(s, depth) || s.waiters.some(waiter => admits(s, waiter.depth) && waiter.ready())) return undefined;\n return newLease(s, depth);\n}\n\n/** Whether another waiter fits. Always true while the budget is off. */\nexport function budgetHasPendingRoom(): boolean {\n const s = state();\n return s.policy.maxActive <= 0 || s.waiters.length < MAX_PENDING_SUBAGENTS;\n}\n\n/** Join the queue. Returns a cancel function; cancelling a granted waiter is a no-op. */\nexport function enqueueBudget(waiter: BudgetWaiter): () => void {\n state().waiters.push(waiter);\n return () => {\n const s = state();\n const i = s.waiters.indexOf(waiter);\n if (i !== -1) s.waiters.splice(i, 1);\n };\n}\n\n/**\n * Give a lease back. Idempotent; does not pump, so callers keep their own\n * ordering. The last release applies a held policy change.\n */\nexport function releaseBudget(lease: BudgetLease | undefined): void {\n if (lease === undefined || lease.released) return;\n lease.released = true;\n const s = state();\n s.active.delete(lease);\n if (s.active.size === 0 && s.pendingPolicy !== undefined) {\n s.policy = s.pendingPolicy;\n s.pendingPolicy = undefined;\n }\n}\n\n/**\n * Admit every waiter that fits, earliest first, re-scanning after each grant\n * because a grant changes the counts (`ready()` reads the owner's pools).\n * Re-entrant calls from inside a grant are folded into the running loop.\n */\nexport function pumpBudget(): void {\n const s = state();\n if (s.pumping) {\n s.repump = true;\n return;\n }\n s.pumping = true;\n try {\n do {\n s.repump = false;\n for (;;) {\n const i = s.waiters.findIndex(w => admits(s, w.depth) && w.ready());\n if (i === -1) break;\n const waiter = s.waiters.splice(i, 1)[0]!;\n const lease = newLease(s, waiter.depth);\n try {\n waiter.grant(lease);\n } catch {\n releaseBudget(lease);\n }\n }\n } while (s.repump);\n } finally {\n s.pumping = false;\n }\n}\n\n/** Test-only: forget all leases and waiters and restore the default policy. */\nexport function resetBudgetForTests(): void {\n const g = globalThis as Record<symbol, unknown>;\n g[BUDGET_KEY] = freshState();\n}\n", "/**\n * model-call.ts -- what an agent's in-flight model call is doing right now.\n *\n * A single model call can sit silent for minutes (long thinking, a slow\n * provider), and the widget used to say `thinking\u2026` for all of it with nothing\n * to tell a busy agent from a dead stream. This tracks the call from the\n * session's streaming events so every surface can say how long it has been\n * thinking, how much it has written, or that it has gone quiet.\n */\n\n/** One streaming event from an assistant message, as the runner reports it. */\nexport type ModelCallEvent =\n | { type: \"start\" }\n | { type: \"delta\"; kind: \"thinking\" | \"writing\"; chars: number }\n /** A stream event that carries no text (block boundaries): proof of life only. */\n | { type: \"beat\" }\n | { type: \"end\" };\n\nexport interface ModelCallState {\n startedAt: number;\n /** The last stream event of any kind, which is what `stalled?` is measured from. */\n lastEventAt: number;\n kind: \"thinking\" | \"writing\";\n /** Characters streamed as text or tool-call arguments this call. */\n writtenChars: number;\n}\n\n/** Silence this long mid-call reads as stalled. */\nexport const STALL_MS = 2 * 60_000;\n\n/** Rough characters per token, for a figure shown before the provider reports usage. */\nconst CHARS_PER_TOKEN = 4;\n\n/** Fold one event into `current`; `undefined` means no call is in flight. */\nexport function applyModelCallEvent(\n current: ModelCallState | undefined,\n event: ModelCallEvent,\n now: number,\n): ModelCallState | undefined {\n switch (event.type) {\n case \"start\":\n return { startedAt: now, lastEventAt: now, kind: \"thinking\", writtenChars: 0 };\n case \"end\":\n return undefined;\n case \"beat\":\n return current ? { ...current, lastEventAt: now } : current;\n case \"delta\": {\n const base = current ?? { startedAt: now, lastEventAt: now, kind: \"thinking\" as const, writtenChars: 0 };\n return {\n ...base,\n lastEventAt: now,\n // Once it has started writing, a late thinking block does not flip it back.\n kind: event.kind === \"writing\" ? \"writing\" : base.kind,\n writtenChars: base.writtenChars + (event.kind === \"writing\" ? event.chars : 0),\n };\n }\n }\n}\n\n/** `41s`, `2m41s`, `1h05m`. */\nexport function formatClock(ms: number): string {\n const total = Math.max(0, Math.floor(ms / 1000));\n if (total < 60) return `${total}s`;\n const minutes = Math.floor(total / 60);\n if (minutes < 60) return `${minutes}m${String(total % 60).padStart(2, \"0\")}s`;\n return `${Math.floor(minutes / 60)}h${String(minutes % 60).padStart(2, \"0\")}m`;\n}\n\n/**\n * `thinking \u00B7 2m41s`, `writing \u00B7 3.2k tok`, or `stalled? \u00B7 2m41s`; undefined\n * when no call is in flight.\n */\nexport function describeModelCall(state: ModelCallState | undefined, now: number): string | undefined {\n if (!state) return undefined;\n const silent = now - state.lastEventAt;\n if (silent >= STALL_MS) return `stalled? \u00B7 ${formatClock(silent)}`;\n if (state.kind === \"writing\") {\n // `950`, `3.2k`.\n const tokens = Math.round(state.writtenChars / CHARS_PER_TOKEN);\n return `writing \u00B7 ${tokens < 1_000 ? `${tokens}` : `${(tokens / 1_000).toFixed(1).replace(/\\.0$/, \"\")}k`} tok`;\n }\n return `thinking \u00B7 ${formatClock(now - state.startedAt)}`;\n}\n", "/**\n * fallback-flag.ts -- the ONE compact indicator for \"this agent ran on another\n * model than configured\", shared by every renderer that shows model info.\n *\n * Rows are `label + stats` clamped from the right, so anything appended after\n * unbounded text (a description, an error, a canonical model id) is the first\n * thing a narrow terminal cuts. The flag is therefore always rendered FIRST and\n * the rest is truncated around it. Renderers must use these helpers rather than\n * building their own marker; `test/fallback-flag-renderers.test.ts` walks every\n * renderer and fails the ones that do not.\n */\nimport { stripTerminalSequences, truncateToWidth, visibleWidth, wrapTextWithAnsi } from \"@earendil-works/pi-tui\";\nimport type { TierDisclosure } from \"../model-tiers.js\";\n\n/** Minimal theme surface, so this module has no dependency on the widgets that use it. */\ninterface FlagTheme {\n fg(color: string, text: string): string;\n}\n\n/** Anything that can carry the fallback: a record, details or notice details. */\nexport interface FallbackCarrier {\n modelFallback?: unknown;\n modelNote?: string;\n modelTier?: TierDisclosure;\n}\n\n/** Whether this tier's answer differs from the member/profile admitted for it. */\nfunction switchedWithinTier(tier: TierDisclosure): boolean {\n if (tier.kind !== \"routed\" && tier.kind !== \"static\") return false;\n const baseline = tier.kind === \"routed\" ? tier.admitted : tier.member;\n return baseline !== undefined && tier.answered !== undefined && tier.answered !== baseline;\n}\n\n/** Whether `carrier` needs an actionable fallback warning, not merely tier identity. */\nexport const hasFallback = (carrier: FallbackCarrier | undefined): boolean => {\n if (carrier?.modelFallback !== undefined) return true;\n const tier = carrier?.modelTier;\n if (!tier) return carrier?.modelNote !== undefined;\n return tier.kind === \"unmapped\" || tier.kind === \"unavailable\" || switchedWithinTier(tier);\n};\n\n/** Plain tier identity/outcome flag, or `[fallback]`; group counts retain the same identity. */\nexport function fallbackFlagText(count = 1, carrier?: FallbackCarrier): string {\n const tier = carrier?.modelTier;\n const suffix = count > 1 ? ` x${count}` : \"\";\n return tier ? `[@${tier.tier}${tier.kind !== \"routed\" && tier.kind !== \"static\" ? ` ${tier.kind}` : \"\"}${suffix}]`\n : `[fallback${suffix}]`;\n}\n\n/** The themed tier identity or actionable fallback flag for `carrier`. */\nexport function fallbackFlag(theme: FlagTheme, carrier: FallbackCarrier | undefined, count = 1): string {\n if (carrier?.modelTier) return theme.fg(hasFallback(carrier) ? \"warning\" : \"dim\", fallbackFlagText(count, carrier));\n return hasFallback(carrier) ? theme.fg(\"warning\", fallbackFlagText(count, carrier)) : \"\";\n}\n\n/** What a flag degrades to when even it does not fit; plain so it cannot depend on a theme. */\nconst MINIMAL_FLAGS = [\"[fb]\", \"!\"] as const;\n\n/**\n * Wrap control text into a fixed row budget while preserving both its opening\n * and final diagnosis around an explicit omitted-rows marker. The budget is at\n * least three rows: one each for the opening, the marker and the diagnosis.\n * A non-finite `maxRows` gets that floor rather than poisoning the slices.\n */\nexport function boundedWrappedRows(text: string, width: number, maxRows: number, marker: string): string[] {\n const rows = wrapTextWithAnsi(text, width);\n const budget = Number.isFinite(maxRows) ? Math.max(3, Math.trunc(maxRows)) : 3;\n if (rows.length <= budget) return rows;\n\n // Reserve a row for the omission marker and favor the final rows: fallback\n // diagnoses live at the end, while the first row still names the control text.\n // At least two rows are omitted, so the marker never replaces a single row.\n const firstCount = Math.max(1, Math.floor((budget - 1) / 2));\n const lastCount = budget - firstCount - 1;\n const omitted = rows.length - firstCount - lastCount;\n const omission = stripTerminalSequences(\n truncateToWidth(`${marker} ${omitted} more lines`, width, \"\"),\n );\n return [...rows.slice(0, firstCount), omission, ...rows.slice(-lastCount)];\n}\n\n/**\n * `prefix + flag + rest`, never wider than `width`, and the flag is never cut.\n *\n * Normal case: the prefix and the flag are reserved first and `rest` (a string,\n * or a function of the width left for it) is truncated to what remains.\n *\n * Narrow case, when `prefix + flag + \" \"` exceeds `width`: the prefix and then\n * the rest are dropped before the flag is. If the flag alone still does not\n * fit, it degrades to a plain `[fb]`, then `!`. Only a zero width renders\n * nothing. An empty string `rest` renders no separator after the flag, so a\n * caller sizing the flag alone gets just the flag.\n */\nexport function withLeadingFlag(\n prefix: string,\n flag: string,\n rest: string | ((inner: number) => string),\n width: number,\n): string {\n const lead = flag ? `${prefix}${flag}${rest === \"\" ? \"\" : \" \"}` : prefix;\n if (!flag || visibleWidth(lead) <= width) {\n const inner = Math.max(0, width - visibleWidth(lead));\n const body = typeof rest === \"function\" ? rest(inner) : truncateToWidth(rest, inner);\n return truncateToWidth(lead + body, width);\n }\n const flagWidth = visibleWidth(flag);\n if (flagWidth <= width) {\n const inner = width - flagWidth - 1;\n if (inner < 1 || rest === \"\") return flag;\n const body = typeof rest === \"function\" ? rest(inner) : truncateToWidth(rest, inner);\n return truncateToWidth(`${flag} ${body}`, width);\n }\n return MINIMAL_FLAGS.find(m => visibleWidth(m) <= width) ?? \"\";\n}\n", "/**\n * viewer-keys.ts \u2014 Scroll key matchers for the conversation viewer.\n *\n * Resolves `tui.select.*` through the user's keybindings when pi provides a\n * manager, falling back to the previous hardcoded keys otherwise. The viewer's\n * k/j and shift+arrow aliases always work alongside whatever is bound.\n */\n\nimport { type KeyId, matchesKey } from \"@earendil-works/pi-tui\";\n\n/** The `tui.select.*` keybinding ids the viewer resolves. */\nexport type ViewerScrollKeybinding =\n | \"tui.select.up\"\n | \"tui.select.down\"\n | \"tui.select.pageUp\"\n | \"tui.select.pageDown\";\n\n/** Structural subset of pi-tui's `KeybindingsManager` (which satisfies it). */\nexport interface ViewerKeybindings {\n matches(data: string, keybinding: ViewerScrollKeybinding): boolean;\n}\n\nexport interface ViewerKeys {\n scrollUp(data: string): boolean;\n scrollDown(data: string): boolean;\n pageUp(data: string): boolean;\n pageDown(data: string): boolean;\n}\n\nexport function createViewerKeys(keybindings?: ViewerKeybindings): ViewerKeys {\n const matches = (data: string, id: ViewerScrollKeybinding, fallback: KeyId): boolean =>\n keybindings ? keybindings.matches(data, id) : matchesKey(data, fallback);\n return {\n scrollUp: (data) => matches(data, \"tui.select.up\", \"up\") || matchesKey(data, \"k\"),\n scrollDown: (data) => matches(data, \"tui.select.down\", \"down\") || matchesKey(data, \"j\"),\n pageUp: (data) => matches(data, \"tui.select.pageUp\", \"pageUp\") || matchesKey(data, \"shift+up\"),\n pageDown: (data) => matches(data, \"tui.select.pageDown\", \"pageDown\") || matchesKey(data, \"shift+down\"),\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["matchesKey", "stripTerminalSequences", "truncateToWidth", "visibleWidth", "wrapTextWithAnsi", "resolved", "truncateToWidth", "randomUUID", "statSync", "isAbsolute", "readFileSync", "homedir", "basename", "dirname", "isAbsolute", "join", "resolve", "defineTool", "SettingsManager", "Type", "homedir", "join", "homedir", "join", "Type", "resolve", "existsSync", "readFileSync", "statSync", "basename", "join", "existsSync", "readFileSync", "join", "agents", "readFileSync", "join", "existsSync", "join", "agents", "existsSync", "basename", "statSync", "readFileSync", "homedir", "resolve", "resolved", "existsSync", "readFileSync", "statSync", "join", "join", "existsSync", "readFileSync", "statSync", "resolve", "resolved", "existsSync", "mkdirSync", "readFileSync", "join", "join", "mkdirSync", "existsSync", "readFileSync", "existsSync", "lstatSync", "readdirSync", "readFileSync", "realpathSync", "statSync", "tmpdir", "join", "relative", "resolve", "realpathSync", "relative", "join", "tmpdir", "existsSync", "lstatSync", "statSync", "readFileSync", "resolve", "readdirSync", "Type", "resolve", "state", "policy", "DefaultPackageManager", "SettingsManager", "DefaultPackageManager", "SettingsManager", "existsSync", "mkdirSync", "readdirSync", "readFileSync", "realpathSync", "statSync", "homedir", "tmpdir", "dirname", "isAbsolute", "join", "relative", "resolve", "sep", "SettingsManager", "SettingsManager", "resolve", "homedir", "join", "existsSync", "tmpdir", "mkdirSync", "readFileSync", "dirname", "readdirSync", "statSync", "realpathSync", "relative", "sep", "isAbsolute", "defineTool", "defineTool", "Type", "basename", "dirname", "resolve", "readFileSync", "join", "homedir", "isAbsolute", "SettingsManager", "policy", "policy", "policy", "isAbsolute", "statSync", "resolve", "policy", "randomUUID", "lease", "state", "truncateToWidth", "matchesKey", "visibleWidth", "truncateToWidth", "sep", "stripTerminalSequences", "wrapTextWithAnsi"]
7
+ }