@ymy88/pi-subagents 0.0.0-stage → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/CHANGELOG.md +904 -0
  2. package/CONTRIBUTING.md +72 -0
  3. package/LICENSE +21 -0
  4. package/README.md +1170 -2
  5. package/SECURITY.md +95 -0
  6. package/dist/abortable.d.ts +12 -0
  7. package/dist/abortable.js +42 -0
  8. package/dist/agent-color.d.ts +35 -0
  9. package/dist/agent-color.js +123 -0
  10. package/dist/agent-file-toggle.d.ts +133 -0
  11. package/dist/agent-file-toggle.js +287 -0
  12. package/dist/agent-manager.d.ts +552 -0
  13. package/dist/agent-manager.js +1466 -0
  14. package/dist/agent-record-entry.d.ts +96 -0
  15. package/dist/agent-record-entry.js +121 -0
  16. package/dist/agent-runner.d.ts +310 -0
  17. package/dist/agent-runner.js +1195 -0
  18. package/dist/agent-source-badge.d.ts +50 -0
  19. package/dist/agent-source-badge.js +74 -0
  20. package/dist/agent-types.d.ts +119 -0
  21. package/dist/agent-types.js +286 -0
  22. package/dist/child-context.d.ts +2 -0
  23. package/dist/child-context.js +12 -0
  24. package/dist/completion-outbox.d.ts +63 -0
  25. package/dist/completion-outbox.js +104 -0
  26. package/dist/context.d.ts +12 -0
  27. package/dist/context.js +56 -0
  28. package/dist/cross-extension-rpc.d.ts +72 -0
  29. package/dist/cross-extension-rpc.js +153 -0
  30. package/dist/custom-agents.d.ts +77 -0
  31. package/dist/custom-agents.js +396 -0
  32. package/dist/default-agents.d.ts +7 -0
  33. package/dist/default-agents.js +121 -0
  34. package/dist/enabled-models.d.ts +49 -0
  35. package/dist/enabled-models.js +145 -0
  36. package/dist/env.d.ts +6 -0
  37. package/dist/env.js +28 -0
  38. package/dist/group-join.d.ts +32 -0
  39. package/dist/group-join.js +116 -0
  40. package/dist/index.d.ts +50 -0
  41. package/dist/index.js +4111 -0
  42. package/dist/invocation-config.d.ts +108 -0
  43. package/dist/invocation-config.js +83 -0
  44. package/dist/memory.d.ts +53 -0
  45. package/dist/memory.js +165 -0
  46. package/dist/mention-clone.d.ts +79 -0
  47. package/dist/mention-clone.js +155 -0
  48. package/dist/mention.d.ts +81 -0
  49. package/dist/mention.js +131 -0
  50. package/dist/model-resolver.d.ts +36 -0
  51. package/dist/model-resolver.js +95 -0
  52. package/dist/model-scope.d.ts +49 -0
  53. package/dist/model-scope.js +48 -0
  54. package/dist/nested-tools.d.ts +57 -0
  55. package/dist/nested-tools.js +303 -0
  56. package/dist/output-file.d.ts +43 -0
  57. package/dist/output-file.js +153 -0
  58. package/dist/package-resources.d.ts +240 -0
  59. package/dist/package-resources.js +519 -0
  60. package/dist/prompts.d.ts +76 -0
  61. package/dist/prompts.js +121 -0
  62. package/dist/schedule-store.d.ts +38 -0
  63. package/dist/schedule-store.js +155 -0
  64. package/dist/schedule.d.ts +109 -0
  65. package/dist/schedule.js +359 -0
  66. package/dist/settings.d.ts +398 -0
  67. package/dist/settings.js +282 -0
  68. package/dist/skill-loader.d.ts +24 -0
  69. package/dist/skill-loader.js +93 -0
  70. package/dist/status-note.d.ts +61 -0
  71. package/dist/status-note.js +85 -0
  72. package/dist/structured-output.d.ts +61 -0
  73. package/dist/structured-output.js +112 -0
  74. package/dist/types.d.ts +391 -0
  75. package/dist/types.js +5 -0
  76. package/dist/ui/agent-mention.d.ts +82 -0
  77. package/dist/ui/agent-mention.js +187 -0
  78. package/dist/ui/agent-widget.d.ts +219 -0
  79. package/dist/ui/agent-widget.js +585 -0
  80. package/dist/ui/conversation-viewer.d.ts +177 -0
  81. package/dist/ui/conversation-viewer.js +905 -0
  82. package/dist/ui/fleet-list.d.ts +211 -0
  83. package/dist/ui/fleet-list.js +489 -0
  84. package/dist/ui/schedule-menu.d.ts +16 -0
  85. package/dist/ui/schedule-menu.js +94 -0
  86. package/dist/ui/select-item.d.ts +27 -0
  87. package/dist/ui/select-item.js +34 -0
  88. package/dist/ui/viewer-keys.d.ts +22 -0
  89. package/dist/ui/viewer-keys.js +18 -0
  90. package/dist/ui/workflow-card.d.ts +175 -0
  91. package/dist/ui/workflow-card.js +332 -0
  92. package/dist/ui/workflow-dialog.d.ts +305 -0
  93. package/dist/ui/workflow-dialog.js +843 -0
  94. package/dist/ui/workflow-menu.d.ts +60 -0
  95. package/dist/ui/workflow-menu.js +147 -0
  96. package/dist/usage.d.ts +135 -0
  97. package/dist/usage.js +120 -0
  98. package/dist/workflow/collisions.d.ts +95 -0
  99. package/dist/workflow/collisions.js +88 -0
  100. package/dist/workflow/entry.d.ts +32 -0
  101. package/dist/workflow/entry.js +29 -0
  102. package/dist/workflow/host.d.ts +62 -0
  103. package/dist/workflow/host.js +419 -0
  104. package/dist/workflow/journal.d.ts +97 -0
  105. package/dist/workflow/journal.js +120 -0
  106. package/dist/workflow/json-schema.d.ts +52 -0
  107. package/dist/workflow/json-schema.js +112 -0
  108. package/dist/workflow/meta.d.ts +67 -0
  109. package/dist/workflow/meta.js +317 -0
  110. package/dist/workflow/progress.d.ts +224 -0
  111. package/dist/workflow/progress.js +361 -0
  112. package/dist/workflow/runtime.d.ts +334 -0
  113. package/dist/workflow/runtime.js +830 -0
  114. package/dist/workflow/saved.d.ts +102 -0
  115. package/dist/workflow/saved.js +247 -0
  116. package/dist/workflow/task.d.ts +136 -0
  117. package/dist/workflow/task.js +207 -0
  118. package/dist/workflow/tool-description.d.ts +38 -0
  119. package/dist/workflow/tool-description.js +199 -0
  120. package/dist/workflow/worker-source.d.ts +47 -0
  121. package/dist/workflow/worker-source.js +778 -0
  122. package/dist/worktree.d.ts +52 -0
  123. package/dist/worktree.js +164 -0
  124. package/dist/xml.d.ts +10 -0
  125. package/dist/xml.js +12 -0
  126. package/docs/packages.md +211 -0
  127. package/docs/rpc.md +192 -0
  128. package/docs/workflows.md +447 -0
  129. package/examples/agent-tool-description.md +42 -0
  130. package/examples/workflows/compose.js +51 -0
  131. package/examples/workflows/fan-out-audit.js +47 -0
  132. package/examples/workflows/gated-fix.js +60 -0
  133. package/examples/workflows/lib/count-child.js +27 -0
  134. package/examples/workflows/review-panel.js +63 -0
  135. package/examples/workflows/structured-findings.js +78 -0
  136. package/package.json +74 -4
  137. package/src/abortable.ts +43 -0
  138. package/src/agent-color.ts +161 -0
  139. package/src/agent-file-toggle.ts +297 -0
  140. package/src/agent-manager.ts +1735 -0
  141. package/src/agent-record-entry.ts +153 -0
  142. package/src/agent-runner.ts +1468 -0
  143. package/src/agent-source-badge.ts +75 -0
  144. package/src/agent-types.ts +346 -0
  145. package/src/child-context.ts +15 -0
  146. package/src/completion-outbox.ts +116 -0
  147. package/src/context.ts +58 -0
  148. package/src/cross-extension-rpc.ts +221 -0
  149. package/src/custom-agents.ts +452 -0
  150. package/src/default-agents.ts +125 -0
  151. package/src/enabled-models.ts +180 -0
  152. package/src/env.ts +33 -0
  153. package/src/group-join.ts +141 -0
  154. package/src/index.ts +4433 -0
  155. package/src/invocation-config.ts +155 -0
  156. package/src/memory.ts +179 -0
  157. package/src/mention-clone.ts +195 -0
  158. package/src/mention.ts +141 -0
  159. package/src/model-resolver.ts +118 -0
  160. package/src/model-scope.ts +70 -0
  161. package/src/nested-tools.ts +426 -0
  162. package/src/output-file.ts +164 -0
  163. package/src/package-resources.ts +652 -0
  164. package/src/prompts.ts +171 -0
  165. package/src/schedule-store.ts +153 -0
  166. package/src/schedule.ts +386 -0
  167. package/src/settings.ts +650 -0
  168. package/src/skill-loader.ts +102 -0
  169. package/src/status-note.ts +90 -0
  170. package/src/structured-output.ts +130 -0
  171. package/src/types.ts +404 -0
  172. package/src/ui/agent-mention.ts +216 -0
  173. package/src/ui/agent-widget.ts +661 -0
  174. package/src/ui/conversation-viewer.ts +928 -0
  175. package/src/ui/fleet-list.ts +559 -0
  176. package/src/ui/schedule-menu.ts +105 -0
  177. package/src/ui/select-item.ts +45 -0
  178. package/src/ui/viewer-keys.ts +43 -0
  179. package/src/ui/workflow-card.ts +470 -0
  180. package/src/ui/workflow-dialog.ts +1115 -0
  181. package/src/ui/workflow-menu.ts +193 -0
  182. package/src/usage.ts +167 -0
  183. package/src/workflow/collisions.ts +123 -0
  184. package/src/workflow/entry.ts +47 -0
  185. package/src/workflow/host.ts +467 -0
  186. package/src/workflow/journal.ts +164 -0
  187. package/src/workflow/json-schema.ts +129 -0
  188. package/src/workflow/meta.ts +325 -0
  189. package/src/workflow/progress.ts +551 -0
  190. package/src/workflow/runtime.ts +1219 -0
  191. package/src/workflow/saved.ts +259 -0
  192. package/src/workflow/task.ts +302 -0
  193. package/src/workflow/tool-description.ts +200 -0
  194. package/src/workflow/worker-source.ts +781 -0
  195. package/src/worktree.ts +205 -0
  196. package/src/xml.ts +13 -0
@@ -0,0 +1,153 @@
1
+ /**
2
+ * agent-record-entry.ts — what a finished top-level agent leaves behind in the session.
3
+ *
4
+ * The live record is evicted about ten minutes after the agent finishes, read or
5
+ * not, and is gone after a reload or a restart. Its completion notification
6
+ * carries only a preview of the result and points at `get_subagent_result` for
7
+ * the rest, so that pointer has to outlive the record: the final record is
8
+ * appended to the session as this entry, and `get_subagent_result` falls back
9
+ * to it.
10
+ *
11
+ * It is also what lets `Agent({ resume })` reopen an evicted agent: the entry
12
+ * names the session file the conversation lives in, so the id the model holds
13
+ * still leads somewhere after eviction, a reload or a restart.
14
+ */
15
+
16
+ import { existsSync } from "node:fs";
17
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
18
+ import { resolveSpawnType } from "./agent-types.js";
19
+ import type { AgentRecord, SubagentType } from "./types.js";
20
+
21
+ /** `customType` of the session entry a finished top-level agent appends. */
22
+ export const AGENT_RECORD_ENTRY_TYPE = "subagents:record";
23
+
24
+ /** The persisted snapshot of a finished agent. */
25
+ export interface AgentRecordEntryData {
26
+ id: string;
27
+ type: AgentRecord["type"];
28
+ description: string;
29
+ status: AgentRecord["status"];
30
+ result?: string;
31
+ error?: string;
32
+ startedAt: number;
33
+ completedAt?: number;
34
+ /**
35
+ * The agent's persisted pi session, when it has one — what a resume reopens.
36
+ * Absent for an in-memory session (`rememberAgents` off, or
37
+ * `persist_session: false`), which leaves nothing to come back to.
38
+ */
39
+ sessionFile?: string;
40
+ /** Names to give back to the reopened agent, as the `@handle` path does. */
41
+ handle?: string;
42
+ alias?: string;
43
+ /** Set when the agent's work lived in a worktree that is now gone — see {@link worktreeLost}. */
44
+ worktreeLost?: boolean;
45
+ }
46
+
47
+ /**
48
+ * Whether the agent ran in a worktree that held its work and has since been
49
+ * removed. Settling always removes the worktree, committing any changes to a
50
+ * branch first, so only a clean one (`hasChanges: false`) leaves nothing
51
+ * behind; a run that failed before cleanup reported nothing and counts as lost.
52
+ * Claude Code draws the same line: it resumes an isolated agent outside its
53
+ * worktree only when the worktree was removed clean, and never builds a fresh
54
+ * one on resume.
55
+ */
56
+ export function worktreeLost(record: Pick<AgentRecord, "worktree" | "worktreeResult">): boolean {
57
+ return record.worktree !== undefined && record.worktreeResult?.hasChanges !== false;
58
+ }
59
+
60
+ /** Snapshot a finished record for {@link AGENT_RECORD_ENTRY_TYPE}. */
61
+ export function agentRecordEntryData(record: AgentRecord): AgentRecordEntryData {
62
+ return {
63
+ id: record.id,
64
+ type: record.type,
65
+ description: record.description,
66
+ status: record.status,
67
+ result: record.result,
68
+ error: record.error,
69
+ startedAt: record.startedAt,
70
+ completedAt: record.completedAt,
71
+ sessionFile: record.sessionFile,
72
+ handle: record.handle,
73
+ alias: record.alias,
74
+ worktreeLost: worktreeLost(record) || undefined,
75
+ };
76
+ }
77
+
78
+ function isAgentRecordEntryData(data: unknown): data is AgentRecordEntryData {
79
+ if (typeof data !== "object" || data === null) return false;
80
+ const { id, type, status, startedAt } = data as Record<string, unknown>;
81
+ return typeof id === "string" && typeof type === "string" && typeof status === "string" && typeof startedAt === "number";
82
+ }
83
+
84
+ /**
85
+ * The latest persisted record of `id` on the current branch. A resumed agent
86
+ * appends a new entry on each finish, so the last one wins; an entry on an
87
+ * abandoned branch is not this conversation's.
88
+ *
89
+ * When `matchHandle` is set, the handle and alias match too, case-insensitively
90
+ * like `@handle`, and only if no entry's id is `id`. Resume leaves it off: it
91
+ * reopens whatever this returns, and a handle would reopen a saved session
92
+ * while that agent's live record still exists.
93
+ */
94
+ export function findAgentRecordEntry(ctx: ExtensionContext, id: string, matchHandle = false): AgentRecordEntryData | undefined {
95
+ const entries = ctx.sessionManager.getBranch();
96
+ const wanted = id.toLowerCase();
97
+ let named: AgentRecordEntryData | undefined;
98
+ for (let i = entries.length - 1; i >= 0; i--) {
99
+ const entry = entries[i];
100
+ if (entry.type !== "custom" || entry.customType !== AGENT_RECORD_ENTRY_TYPE) continue;
101
+ if (!isAgentRecordEntryData(entry.data)) continue;
102
+ if (entry.data.id === id) return entry.data;
103
+ if (
104
+ matchHandle &&
105
+ named === undefined &&
106
+ (entry.data.handle?.toLowerCase() === wanted || entry.data.alias?.toLowerCase() === wanted)
107
+ ) {
108
+ named = entry.data;
109
+ }
110
+ }
111
+ return named;
112
+ }
113
+
114
+ /**
115
+ * Whether an evicted agent's saved conversation can be reopened, and the
116
+ * agent type to reopen it under. Shared by `@handle`, `Agent({ resume })` and
117
+ * a workflow's `resume`, so all three refuse the same cases in the same words;
118
+ * `reason` completes "Could not resume X —" and "cannot be resumed —".
119
+ *
120
+ * The file is checked here rather than left to SessionManager.open: that runs
121
+ * inside runAgent, whose rejection lands on the record as an agent error, not
122
+ * as a refusal. A `/new` in another pi window or a manual delete makes the
123
+ * conversation unrecoverable (Claude Code's `not_reachable`); `gone` marks
124
+ * that, and the no-file case, as refusals that can never clear.
125
+ *
126
+ * The Agent tool deliberately falls back to general-purpose for a type it
127
+ * cannot resolve (#183), which covers a deleted file AND a merely disabled
128
+ * one. A resume must not inherit that: reopening this conversation under a
129
+ * different agent's prompt and tools is not continuing it, and the new record
130
+ * would re-tombstone under the substitute, so the handle would never find its
131
+ * way back. `@handle` and the Agent tool reload the agent files first.
132
+ *
133
+ * `worktreeLost` refuses for good, as Claude Code does ("its worktree no
134
+ * longer exists"): the conversation's edits were made in a directory that is
135
+ * gone, and reopening it in the parent's checkout or a fresh worktree would
136
+ * continue that work somewhere it never happened.
137
+ */
138
+ export function reopenTarget(
139
+ type: string,
140
+ sessionFile: string | undefined,
141
+ worktreeLost?: boolean,
142
+ ): { ok: true; type: SubagentType; sessionFile: string } | { ok: false; reason: string; gone: boolean } {
143
+ if (sessionFile === undefined) {
144
+ return { ok: false, reason: "its conversation was not saved (`rememberAgents` or `persist_session` was off)", gone: true };
145
+ }
146
+ if (!existsSync(sessionFile)) return { ok: false, reason: "its session is gone", gone: true };
147
+ if (worktreeLost) return { ok: false, reason: "its worktree no longer exists", gone: true };
148
+ const dispatch = resolveSpawnType(type);
149
+ if (!dispatch.ok || dispatch.fellBackFrom !== undefined) {
150
+ return { ok: false, reason: `the ${type} agent is no longer available`, gone: false };
151
+ }
152
+ return { ok: true, type: dispatch.type, sessionFile };
153
+ }