@astralyn/pi 0.81.1-2 → 0.82.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 (176) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +14 -1
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +1 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/cli/config-selector.d.ts.map +1 -1
  7. package/dist/cli/config-selector.js +1 -1
  8. package/dist/cli/config-selector.js.map +1 -1
  9. package/dist/cli/startup-ui.d.ts.map +1 -1
  10. package/dist/cli/startup-ui.js +1 -1
  11. package/dist/cli/startup-ui.js.map +1 -1
  12. package/dist/core/agent-session.d.ts +11 -0
  13. package/dist/core/agent-session.d.ts.map +1 -1
  14. package/dist/core/agent-session.js +7 -8
  15. package/dist/core/agent-session.js.map +1 -1
  16. package/dist/core/compaction/compaction.d.ts.map +1 -1
  17. package/dist/core/compaction/compaction.js +11 -3
  18. package/dist/core/compaction/compaction.js.map +1 -1
  19. package/dist/core/extensions/runner.d.ts.map +1 -1
  20. package/dist/core/extensions/runner.js +4 -0
  21. package/dist/core/extensions/runner.js.map +1 -1
  22. package/dist/core/extensions/types.d.ts +9 -1
  23. package/dist/core/extensions/types.d.ts.map +1 -1
  24. package/dist/core/extensions/types.js.map +1 -1
  25. package/dist/core/model-config.d.ts +30 -0
  26. package/dist/core/model-config.d.ts.map +1 -1
  27. package/dist/core/model-config.js +6 -0
  28. package/dist/core/model-config.js.map +1 -1
  29. package/dist/core/model-registry.d.ts.map +1 -1
  30. package/dist/core/model-registry.js +2 -2
  31. package/dist/core/model-registry.js.map +1 -1
  32. package/dist/core/model-resolver.d.ts.map +1 -1
  33. package/dist/core/model-resolver.js +7 -0
  34. package/dist/core/model-resolver.js.map +1 -1
  35. package/dist/core/model-runtime.d.ts +0 -1
  36. package/dist/core/model-runtime.d.ts.map +1 -1
  37. package/dist/core/model-runtime.js +3 -5
  38. package/dist/core/model-runtime.js.map +1 -1
  39. package/dist/core/remote-catalog-provider.d.ts +1 -1
  40. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  41. package/dist/core/remote-catalog-provider.js +5 -10
  42. package/dist/core/remote-catalog-provider.js.map +1 -1
  43. package/dist/core/settings-manager.d.ts +1 -1
  44. package/dist/core/settings-manager.d.ts.map +1 -1
  45. package/dist/core/settings-manager.js.map +1 -1
  46. package/dist/core/system-prompt.d.ts.map +1 -1
  47. package/dist/core/system-prompt.js +1 -1
  48. package/dist/core/system-prompt.js.map +1 -1
  49. package/dist/core/tools/bash.d.ts +2 -1
  50. package/dist/core/tools/bash.d.ts.map +1 -1
  51. package/dist/core/tools/bash.js +45 -45
  52. package/dist/core/tools/bash.js.map +1 -1
  53. package/dist/core/tools/find.d.ts.map +1 -1
  54. package/dist/core/tools/find.js +1 -0
  55. package/dist/core/tools/find.js.map +1 -1
  56. package/dist/core/tools/read.d.ts.map +1 -1
  57. package/dist/core/tools/read.js +4 -3
  58. package/dist/core/tools/read.js.map +1 -1
  59. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  60. package/dist/core/tools/tool-definition-wrapper.js +5 -1
  61. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  62. package/dist/extensions/index.d.ts.map +1 -1
  63. package/dist/extensions/index.js +2 -0
  64. package/dist/extensions/index.js.map +1 -1
  65. package/dist/extensions/llama/provider.d.ts.map +1 -1
  66. package/dist/extensions/llama/provider.js +1 -2
  67. package/dist/extensions/llama/provider.js.map +1 -1
  68. package/dist/extensions/subagent/activity.d.ts +16 -0
  69. package/dist/extensions/subagent/activity.d.ts.map +1 -0
  70. package/dist/extensions/subagent/activity.js +150 -0
  71. package/dist/extensions/subagent/activity.js.map +1 -0
  72. package/dist/extensions/subagent/agents.d.ts +7 -0
  73. package/dist/extensions/subagent/agents.d.ts.map +1 -0
  74. package/dist/extensions/subagent/agents.js +218 -0
  75. package/dist/extensions/subagent/agents.js.map +1 -0
  76. package/dist/extensions/subagent/constants.d.ts +22 -0
  77. package/dist/extensions/subagent/constants.d.ts.map +1 -0
  78. package/dist/extensions/subagent/constants.js +32 -0
  79. package/dist/extensions/subagent/constants.js.map +1 -0
  80. package/dist/extensions/subagent/index.d.ts +3 -0
  81. package/dist/extensions/subagent/index.d.ts.map +1 -0
  82. package/dist/extensions/subagent/index.js +249 -0
  83. package/dist/extensions/subagent/index.js.map +1 -0
  84. package/dist/extensions/subagent/picker.d.ts +31 -0
  85. package/dist/extensions/subagent/picker.d.ts.map +1 -0
  86. package/dist/extensions/subagent/picker.js +116 -0
  87. package/dist/extensions/subagent/picker.js.map +1 -0
  88. package/dist/extensions/subagent/render.d.ts +8 -0
  89. package/dist/extensions/subagent/render.d.ts.map +1 -0
  90. package/dist/extensions/subagent/render.js +322 -0
  91. package/dist/extensions/subagent/render.js.map +1 -0
  92. package/dist/extensions/subagent/resolve.d.ts +16 -0
  93. package/dist/extensions/subagent/resolve.d.ts.map +1 -0
  94. package/dist/extensions/subagent/resolve.js +103 -0
  95. package/dist/extensions/subagent/resolve.js.map +1 -0
  96. package/dist/extensions/subagent/runner.d.ts +30 -0
  97. package/dist/extensions/subagent/runner.d.ts.map +1 -0
  98. package/dist/extensions/subagent/runner.js +355 -0
  99. package/dist/extensions/subagent/runner.js.map +1 -0
  100. package/dist/extensions/subagent/schema.d.ts +28 -0
  101. package/dist/extensions/subagent/schema.d.ts.map +1 -0
  102. package/dist/extensions/subagent/schema.js +33 -0
  103. package/dist/extensions/subagent/schema.js.map +1 -0
  104. package/dist/extensions/subagent/sdk-runner.d.ts +14 -0
  105. package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -0
  106. package/dist/extensions/subagent/sdk-runner.js +210 -0
  107. package/dist/extensions/subagent/sdk-runner.js.map +1 -0
  108. package/dist/extensions/subagent/settings.d.ts +9 -0
  109. package/dist/extensions/subagent/settings.d.ts.map +1 -0
  110. package/dist/extensions/subagent/settings.js +131 -0
  111. package/dist/extensions/subagent/settings.js.map +1 -0
  112. package/dist/extensions/subagent/types.d.ts +99 -0
  113. package/dist/extensions/subagent/types.d.ts.map +1 -0
  114. package/dist/extensions/subagent/types.js +2 -0
  115. package/dist/extensions/subagent/types.js.map +1 -0
  116. package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
  117. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  118. package/dist/modes/interactive/components/extension-editor.js +16 -46
  119. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  120. package/dist/modes/interactive/components/index.d.ts +1 -0
  121. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  122. package/dist/modes/interactive/components/index.js +1 -0
  123. package/dist/modes/interactive/components/index.js.map +1 -1
  124. package/dist/modes/interactive/components/tool-execution.d.ts +2 -0
  125. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  126. package/dist/modes/interactive/components/tool-execution.js +25 -4
  127. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  128. package/dist/modes/interactive/components/tool-group.d.ts +16 -0
  129. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -0
  130. package/dist/modes/interactive/components/tool-group.js +64 -0
  131. package/dist/modes/interactive/components/tool-group.js.map +1 -0
  132. package/dist/modes/interactive/external-editor.d.ts +12 -0
  133. package/dist/modes/interactive/external-editor.d.ts.map +1 -0
  134. package/dist/modes/interactive/external-editor.js +37 -0
  135. package/dist/modes/interactive/external-editor.js.map +1 -0
  136. package/dist/modes/interactive/interactive-mode.d.ts +3 -1
  137. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  138. package/dist/modes/interactive/interactive-mode.js +61 -62
  139. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  140. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  141. package/dist/modes/rpc/rpc-mode.js +1 -0
  142. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  143. package/dist/utils/clipboard.d.ts.map +1 -1
  144. package/dist/utils/clipboard.js +19 -8
  145. package/dist/utils/clipboard.js.map +1 -1
  146. package/dist/utils/version-check.d.ts.map +1 -1
  147. package/dist/utils/version-check.js +3 -1
  148. package/dist/utils/version-check.js.map +1 -1
  149. package/docs/compaction.md +1 -1
  150. package/docs/custom-provider.md +5 -2
  151. package/docs/environment-variables.md +88 -0
  152. package/docs/extensions.md +11 -3
  153. package/docs/index.md +4 -1
  154. package/docs/models.md +6 -2
  155. package/docs/providers.md +8 -1
  156. package/docs/rpc.md +23 -6
  157. package/docs/settings.md +1 -1
  158. package/docs/usage.md +0 -13
  159. package/examples/extensions/custom-compaction.ts +3 -0
  160. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  161. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  162. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  163. package/examples/extensions/gondolin/package-lock.json +2 -2
  164. package/examples/extensions/gondolin/package.json +1 -1
  165. package/examples/extensions/handoff.ts +9 -1
  166. package/examples/extensions/sandbox/package-lock.json +2 -2
  167. package/examples/extensions/sandbox/package.json +1 -1
  168. package/examples/extensions/summarize.ts +3 -0
  169. package/examples/extensions/with-deps/package-lock.json +2 -2
  170. package/examples/extensions/with-deps/package.json +1 -1
  171. package/npm-shrinkwrap.json +16 -15
  172. package/package.json +5 -4
  173. package/dist/core/tools/bash-command-summary.d.ts +0 -7
  174. package/dist/core/tools/bash-command-summary.d.ts.map +0 -1
  175. package/dist/core/tools/bash-command-summary.js +0 -261
  176. package/dist/core/tools/bash-command-summary.js.map +0 -1
@@ -0,0 +1,210 @@
1
+ import { DefaultResourceLoader } from "../../core/resource-loader.js";
2
+ import { createAgentSession } from "../../core/sdk.js";
3
+ import { SessionManager } from "../../core/session-manager.js";
4
+ import { SettingsManager } from "../../core/settings-manager.js";
5
+ import { activitySummary, addUsage, appendActivity, assistantText, boundText, finalAssistantText, resultSummary, setLiveText, } from "./activity.js";
6
+ import { ERROR_TEXT_LIMIT, LIVE_TEXT_LIMIT, SINGLE_OUTPUT_LIMIT } from "./constants.js";
7
+ function workerSystemPrompt(base, task) {
8
+ return [
9
+ base,
10
+ `You are Pi subagent "${task.agent.name}", working independently on one delegated task.`,
11
+ "You cannot see the parent conversation; rely entirely on the task briefing and repository context available in your working directory.",
12
+ "Complete the task fully—do not gold-plate it, but do not leave it half-done.",
13
+ "Stay inside the assigned working directory and delegated scope.",
14
+ "Do not ask the end user questions. If blocked, report the exact blocker and what would resolve it.",
15
+ "Do not spawn subagents or invoke tools outside the configured tool list.",
16
+ "When referencing files in the final report, use absolute paths so the caller can locate them unambiguously.",
17
+ "End with a concise report covering findings or changes, verification performed, blockers, and unresolved risks. The caller will relay it to the user, so include only the essentials.",
18
+ task.agent.systemPrompt,
19
+ ]
20
+ .filter((part) => Boolean(part?.trim()))
21
+ .join("\n\n");
22
+ }
23
+ function lastAssistantMessage(session) {
24
+ for (let index = session.messages.length - 1; index >= 0; index--) {
25
+ const message = session.messages[index];
26
+ if (message?.role === "assistant")
27
+ return message;
28
+ }
29
+ return undefined;
30
+ }
31
+ function assistantError(message) {
32
+ if (!message || message.role !== "assistant")
33
+ return undefined;
34
+ return message.errorMessage;
35
+ }
36
+ function emitThrottled(onProgress) {
37
+ let pending = false;
38
+ return () => {
39
+ if (!onProgress || pending)
40
+ return;
41
+ pending = true;
42
+ setTimeout(() => {
43
+ pending = false;
44
+ onProgress();
45
+ }, 80);
46
+ };
47
+ }
48
+ function cancelThrottled(onProgress) {
49
+ onProgress();
50
+ }
51
+ export async function runSdkTask(options) {
52
+ const { task, run, modelRuntime, agentDir, projectTrusted, signal, onProgress } = options;
53
+ const emitTextProgress = emitThrottled(onProgress);
54
+ let unsubscribe;
55
+ let unregisterAbort;
56
+ let session;
57
+ const activeActivities = new Map();
58
+ const seenAssistantMessages = new Set();
59
+ const markAbort = async () => {
60
+ run.status = "aborted";
61
+ if (session)
62
+ await session.abort();
63
+ };
64
+ try {
65
+ if (signal?.aborted) {
66
+ run.status = "aborted";
67
+ run.error = "Subagent was aborted before it started.";
68
+ return run;
69
+ }
70
+ run.status = "running";
71
+ run.startedAt = Date.now();
72
+ onProgress?.();
73
+ const settingsManager = SettingsManager.create(task.cwd, agentDir, { projectTrusted });
74
+ const resourceLoader = new DefaultResourceLoader({
75
+ cwd: task.cwd,
76
+ agentDir,
77
+ settingsManager,
78
+ noExtensions: true,
79
+ noSkills: true,
80
+ noPromptTemplates: true,
81
+ noThemes: true,
82
+ systemPromptOverride: (base) => workerSystemPrompt(base, task),
83
+ });
84
+ await resourceLoader.reload();
85
+ const created = await createAgentSession({
86
+ cwd: task.cwd,
87
+ agentDir,
88
+ modelRuntime,
89
+ model: task.model,
90
+ thinkingLevel: task.thinking,
91
+ tools: task.agent.tools,
92
+ resourceLoader,
93
+ sessionManager: SessionManager.inMemory(task.cwd),
94
+ settingsManager,
95
+ });
96
+ session = created.session;
97
+ const emitImmediate = () => onProgress?.();
98
+ const emitText = emitTextProgress;
99
+ unsubscribe = session.subscribe((event) => {
100
+ if (event.type === "turn_end") {
101
+ run.usage.turns++;
102
+ run.currentActivity = undefined;
103
+ emitImmediate();
104
+ return;
105
+ }
106
+ if (event.type === "message_end" && event.message.role === "assistant") {
107
+ if (!seenAssistantMessages.has(event.message)) {
108
+ seenAssistantMessages.add(event.message);
109
+ addUsage(run.usage, event.message.usage);
110
+ }
111
+ run.liveText = setLiveText(assistantText(event.message));
112
+ emitText();
113
+ return;
114
+ }
115
+ if (event.type === "message_update") {
116
+ if (event.message.role === "assistant")
117
+ run.liveText = setLiveText(assistantText(event.message));
118
+ if (event.assistantMessageEvent.type === "thinking_delta")
119
+ run.currentActivity = "Thinking…";
120
+ if (event.assistantMessageEvent.type === "text_delta")
121
+ run.currentActivity = "Writing response…";
122
+ emitText();
123
+ return;
124
+ }
125
+ if (event.type === "tool_execution_start") {
126
+ run.usage.toolUses++;
127
+ const activity = {
128
+ id: event.toolCallId,
129
+ toolName: event.toolName,
130
+ summary: activitySummary(event.toolName, event.args),
131
+ status: "running",
132
+ startedAt: Date.now(),
133
+ };
134
+ activeActivities.set(event.toolCallId, activity);
135
+ appendActivity(run.activities, activity);
136
+ run.currentActivity = activity.summary;
137
+ emitImmediate();
138
+ return;
139
+ }
140
+ if (event.type === "tool_execution_update") {
141
+ run.currentActivity = activitySummary(event.toolName, event.args);
142
+ emitText();
143
+ return;
144
+ }
145
+ if (event.type === "tool_execution_end") {
146
+ const activity = activeActivities.get(event.toolCallId);
147
+ if (activity) {
148
+ activity.status = event.isError ? "failed" : "succeeded";
149
+ activity.endedAt = Date.now();
150
+ activity.resultSummary = resultSummary(event.result);
151
+ }
152
+ run.currentActivity = undefined;
153
+ emitImmediate();
154
+ }
155
+ });
156
+ const abortListener = () => {
157
+ void markAbort().catch(() => undefined);
158
+ };
159
+ unregisterAbort = options.registerAbort?.(markAbort);
160
+ if (signal)
161
+ signal.addEventListener("abort", abortListener, { once: true });
162
+ try {
163
+ await session.prompt(task.prompt);
164
+ }
165
+ finally {
166
+ if (signal)
167
+ signal.removeEventListener("abort", abortListener);
168
+ }
169
+ const finalMessage = lastAssistantMessage(session);
170
+ run.finalOutput = finalAssistantText(session.messages);
171
+ const error = assistantError(finalMessage);
172
+ if (signal?.aborted || finalMessage?.stopReason === "aborted") {
173
+ run.status = "aborted";
174
+ run.error = boundText(error ?? "Subagent was aborted.", ERROR_TEXT_LIMIT);
175
+ }
176
+ else if (finalMessage?.stopReason === "error" || error) {
177
+ run.status = "failed";
178
+ run.error = boundText(error ?? "Subagent failed.", ERROR_TEXT_LIMIT);
179
+ }
180
+ else {
181
+ run.status = "completed";
182
+ }
183
+ }
184
+ catch (error) {
185
+ if (signal?.aborted || run.status === "aborted") {
186
+ run.status = "aborted";
187
+ run.error = run.error ?? "Subagent was aborted.";
188
+ }
189
+ else {
190
+ run.status = "failed";
191
+ run.error = boundText(error instanceof Error ? error.message : String(error), ERROR_TEXT_LIMIT);
192
+ }
193
+ if (session)
194
+ run.finalOutput = finalAssistantText(session.messages);
195
+ }
196
+ finally {
197
+ cancelThrottled(emitTextProgress);
198
+ unregisterAbort?.();
199
+ unsubscribe?.();
200
+ session?.dispose();
201
+ run.liveText = boundText(run.liveText, LIVE_TEXT_LIMIT);
202
+ run.finalOutput = boundText(run.finalOutput, SINGLE_OUTPUT_LIMIT);
203
+ if (run.error)
204
+ run.error = boundText(run.error, ERROR_TEXT_LIMIT);
205
+ run.endedAt = Date.now();
206
+ onProgress?.();
207
+ }
208
+ return run;
209
+ }
210
+ //# sourceMappingURL=sdk-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk-runner.js","sourceRoot":"","sources":["../../../src/extensions/subagent/sdk-runner.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { AgentSessionEvent } from \"../../core/agent-session.ts\";\nimport type { ModelRuntime } from \"../../core/model-runtime.ts\";\nimport { DefaultResourceLoader } from \"../../core/resource-loader.ts\";\nimport { createAgentSession } from \"../../core/sdk.ts\";\nimport { SessionManager } from \"../../core/session-manager.ts\";\nimport { SettingsManager } from \"../../core/settings-manager.ts\";\nimport {\n\tactivitySummary,\n\taddUsage,\n\tappendActivity,\n\tassistantText,\n\tboundText,\n\tfinalAssistantText,\n\tresultSummary,\n\tsetLiveText,\n} from \"./activity.ts\";\nimport { ERROR_TEXT_LIMIT, LIVE_TEXT_LIMIT, SINGLE_OUTPUT_LIMIT } from \"./constants.ts\";\nimport type { ResolvedSubagentTask, SubagentRunDetails, ToolActivity } from \"./types.ts\";\n\nexport interface SdkRunnerOptions {\n\ttask: ResolvedSubagentTask;\n\trun: SubagentRunDetails;\n\tmodelRuntime: ModelRuntime;\n\tagentDir: string;\n\tprojectTrusted: boolean;\n\tsignal?: AbortSignal;\n\tonProgress?: () => void;\n\tregisterAbort?: (abort: () => Promise<void>) => () => void;\n}\n\nfunction workerSystemPrompt(base: string | undefined, task: ResolvedSubagentTask): string {\n\treturn [\n\t\tbase,\n\t\t`You are Pi subagent \"${task.agent.name}\", working independently on one delegated task.`,\n\t\t\"You cannot see the parent conversation; rely entirely on the task briefing and repository context available in your working directory.\",\n\t\t\"Complete the task fully—do not gold-plate it, but do not leave it half-done.\",\n\t\t\"Stay inside the assigned working directory and delegated scope.\",\n\t\t\"Do not ask the end user questions. If blocked, report the exact blocker and what would resolve it.\",\n\t\t\"Do not spawn subagents or invoke tools outside the configured tool list.\",\n\t\t\"When referencing files in the final report, use absolute paths so the caller can locate them unambiguously.\",\n\t\t\"End with a concise report covering findings or changes, verification performed, blockers, and unresolved risks. The caller will relay it to the user, so include only the essentials.\",\n\t\ttask.agent.systemPrompt,\n\t]\n\t\t.filter((part): part is string => Boolean(part?.trim()))\n\t\t.join(\"\\n\\n\");\n}\n\nfunction lastAssistantMessage(session: { messages: readonly AgentMessage[] }) {\n\tfor (let index = session.messages.length - 1; index >= 0; index--) {\n\t\tconst message = session.messages[index];\n\t\tif (message?.role === \"assistant\") return message;\n\t}\n\treturn undefined;\n}\n\nfunction assistantError(message: ReturnType<typeof lastAssistantMessage>): string | undefined {\n\tif (!message || message.role !== \"assistant\") return undefined;\n\treturn message.errorMessage;\n}\n\nfunction emitThrottled(onProgress: (() => void) | undefined): () => void {\n\tlet pending = false;\n\treturn () => {\n\t\tif (!onProgress || pending) return;\n\t\tpending = true;\n\t\tsetTimeout(() => {\n\t\t\tpending = false;\n\t\t\tonProgress();\n\t\t}, 80);\n\t};\n}\n\nfunction cancelThrottled(onProgress: () => void): void {\n\tonProgress();\n}\n\nexport async function runSdkTask(options: SdkRunnerOptions): Promise<SubagentRunDetails> {\n\tconst { task, run, modelRuntime, agentDir, projectTrusted, signal, onProgress } = options;\n\tconst emitTextProgress = emitThrottled(onProgress);\n\tlet unsubscribe: (() => void) | undefined;\n\tlet unregisterAbort: (() => void) | undefined;\n\tlet session: Awaited<ReturnType<typeof createAgentSession>>[\"session\"] | undefined;\n\tconst activeActivities = new Map<string, ToolActivity>();\n\tconst seenAssistantMessages = new Set<unknown>();\n\tconst markAbort = async (): Promise<void> => {\n\t\trun.status = \"aborted\";\n\t\tif (session) await session.abort();\n\t};\n\n\ttry {\n\t\tif (signal?.aborted) {\n\t\t\trun.status = \"aborted\";\n\t\t\trun.error = \"Subagent was aborted before it started.\";\n\t\t\treturn run;\n\t\t}\n\n\t\trun.status = \"running\";\n\t\trun.startedAt = Date.now();\n\t\tonProgress?.();\n\t\tconst settingsManager = SettingsManager.create(task.cwd, agentDir, { projectTrusted });\n\t\tconst resourceLoader = new DefaultResourceLoader({\n\t\t\tcwd: task.cwd,\n\t\t\tagentDir,\n\t\t\tsettingsManager,\n\t\t\tnoExtensions: true,\n\t\t\tnoSkills: true,\n\t\t\tnoPromptTemplates: true,\n\t\t\tnoThemes: true,\n\t\t\tsystemPromptOverride: (base) => workerSystemPrompt(base, task),\n\t\t});\n\t\tawait resourceLoader.reload();\n\t\tconst created = await createAgentSession({\n\t\t\tcwd: task.cwd,\n\t\t\tagentDir,\n\t\t\tmodelRuntime,\n\t\t\tmodel: task.model,\n\t\t\tthinkingLevel: task.thinking,\n\t\t\ttools: task.agent.tools,\n\t\t\tresourceLoader,\n\t\t\tsessionManager: SessionManager.inMemory(task.cwd),\n\t\t\tsettingsManager,\n\t\t});\n\t\tsession = created.session;\n\t\tconst emitImmediate = () => onProgress?.();\n\t\tconst emitText = emitTextProgress;\n\t\tunsubscribe = session.subscribe((event: AgentSessionEvent) => {\n\t\t\tif (event.type === \"turn_end\") {\n\t\t\t\trun.usage.turns++;\n\t\t\t\trun.currentActivity = undefined;\n\t\t\t\temitImmediate();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (event.type === \"message_end\" && event.message.role === \"assistant\") {\n\t\t\t\tif (!seenAssistantMessages.has(event.message)) {\n\t\t\t\t\tseenAssistantMessages.add(event.message);\n\t\t\t\t\taddUsage(run.usage, event.message.usage);\n\t\t\t\t}\n\t\t\t\trun.liveText = setLiveText(assistantText(event.message));\n\t\t\t\temitText();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (event.type === \"message_update\") {\n\t\t\t\tif (event.message.role === \"assistant\") run.liveText = setLiveText(assistantText(event.message));\n\t\t\t\tif (event.assistantMessageEvent.type === \"thinking_delta\") run.currentActivity = \"Thinking…\";\n\t\t\t\tif (event.assistantMessageEvent.type === \"text_delta\") run.currentActivity = \"Writing response…\";\n\t\t\t\temitText();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (event.type === \"tool_execution_start\") {\n\t\t\t\trun.usage.toolUses++;\n\t\t\t\tconst activity: ToolActivity = {\n\t\t\t\t\tid: event.toolCallId,\n\t\t\t\t\ttoolName: event.toolName,\n\t\t\t\t\tsummary: activitySummary(event.toolName, event.args),\n\t\t\t\t\tstatus: \"running\",\n\t\t\t\t\tstartedAt: Date.now(),\n\t\t\t\t};\n\t\t\t\tactiveActivities.set(event.toolCallId, activity);\n\t\t\t\tappendActivity(run.activities, activity);\n\t\t\t\trun.currentActivity = activity.summary;\n\t\t\t\temitImmediate();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (event.type === \"tool_execution_update\") {\n\t\t\t\trun.currentActivity = activitySummary(event.toolName, event.args);\n\t\t\t\temitText();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (event.type === \"tool_execution_end\") {\n\t\t\t\tconst activity = activeActivities.get(event.toolCallId);\n\t\t\t\tif (activity) {\n\t\t\t\t\tactivity.status = event.isError ? \"failed\" : \"succeeded\";\n\t\t\t\t\tactivity.endedAt = Date.now();\n\t\t\t\t\tactivity.resultSummary = resultSummary(event.result);\n\t\t\t\t}\n\t\t\t\trun.currentActivity = undefined;\n\t\t\t\temitImmediate();\n\t\t\t}\n\t\t});\n\t\tconst abortListener = () => {\n\t\t\tvoid markAbort().catch(() => undefined);\n\t\t};\n\t\tunregisterAbort = options.registerAbort?.(markAbort);\n\t\tif (signal) signal.addEventListener(\"abort\", abortListener, { once: true });\n\t\ttry {\n\t\t\tawait session.prompt(task.prompt);\n\t\t} finally {\n\t\t\tif (signal) signal.removeEventListener(\"abort\", abortListener);\n\t\t}\n\t\tconst finalMessage = lastAssistantMessage(session);\n\t\trun.finalOutput = finalAssistantText(session.messages);\n\t\tconst error = assistantError(finalMessage);\n\t\tif (signal?.aborted || finalMessage?.stopReason === \"aborted\") {\n\t\t\trun.status = \"aborted\";\n\t\t\trun.error = boundText(error ?? \"Subagent was aborted.\", ERROR_TEXT_LIMIT);\n\t\t} else if (finalMessage?.stopReason === \"error\" || error) {\n\t\t\trun.status = \"failed\";\n\t\t\trun.error = boundText(error ?? \"Subagent failed.\", ERROR_TEXT_LIMIT);\n\t\t} else {\n\t\t\trun.status = \"completed\";\n\t\t}\n\t} catch (error) {\n\t\tif (signal?.aborted || run.status === \"aborted\") {\n\t\t\trun.status = \"aborted\";\n\t\t\trun.error = run.error ?? \"Subagent was aborted.\";\n\t\t} else {\n\t\t\trun.status = \"failed\";\n\t\t\trun.error = boundText(error instanceof Error ? error.message : String(error), ERROR_TEXT_LIMIT);\n\t\t}\n\t\tif (session) run.finalOutput = finalAssistantText(session.messages);\n\t} finally {\n\t\tcancelThrottled(emitTextProgress);\n\t\tunregisterAbort?.();\n\t\tunsubscribe?.();\n\t\tsession?.dispose();\n\t\trun.liveText = boundText(run.liveText, LIVE_TEXT_LIMIT);\n\t\trun.finalOutput = boundText(run.finalOutput, SINGLE_OUTPUT_LIMIT);\n\t\tif (run.error) run.error = boundText(run.error, ERROR_TEXT_LIMIT);\n\t\trun.endedAt = Date.now();\n\t\tonProgress?.();\n\t}\n\treturn run;\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { SubagentConfigFile, SubagentProfileOverride } from "./types.ts";
2
+ export declare function getSubagentConfigPath(agentDir?: string): string;
3
+ export declare function emptySubagentConfig(): SubagentConfigFile;
4
+ export declare function parseSubagentConfig(raw: string): SubagentConfigFile;
5
+ export declare function loadSubagentConfig(agentDir?: string): Promise<SubagentConfigFile>;
6
+ export declare function saveSubagentConfig(config: SubagentConfigFile, agentDir?: string): Promise<void>;
7
+ export declare function updateProfileOverride(profile: string, patch: Partial<SubagentProfileOverride>, agentDir?: string): Promise<SubagentConfigFile>;
8
+ export declare function resetProfileOverrides(agentDir?: string): Promise<void>;
9
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/extensions/subagent/settings.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAiC9E,wBAAgB,qBAAqB,CAAC,QAAQ,SAAgB,GAAG,MAAM,CAEtE;AAED,wBAAgB,mBAAmB,IAAI,kBAAkB,CAExD;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,CA6BnE;AAED,wBAAsB,kBAAkB,CAAC,QAAQ,SAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAQ9F;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,EAAE,QAAQ,SAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB5G;AAID,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,CAAC,uBAAuB,CAAC,EACvC,QAAQ,SAAgB,GACtB,OAAO,CAAC,kBAAkB,CAAC,CAgB7B;AAED,wBAAsB,qBAAqB,CAAC,QAAQ,SAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnF","sourcesContent":["import { mkdir, readFile, rename, unlink, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { withFileMutationQueue } from \"../../core/tools/file-mutation-queue.ts\";\nimport { SUBAGENT_CONFIG_FILE, SUBAGENT_CONFIG_VERSION, THINKING_LEVELS } from \"./constants.ts\";\nimport type { SubagentConfigFile, SubagentProfileOverride } from \"./types.ts\";\n\nfunction isThinkingLevel(value: unknown): boolean {\n\treturn typeof value === \"string\" && (THINKING_LEVELS as readonly string[]).includes(value);\n}\n\n// Overrides hold concrete values only; absence means \"inherit the parent\n// session\". Legacy \"inherit\" entries from earlier versions are dropped.\nfunction normalizeOverride(value: unknown, profile: string): SubagentProfileOverride {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(`Profile override for \"${profile}\" must be an object.`);\n\t}\n\tconst input = value as Record<string, unknown>;\n\tconst output: SubagentProfileOverride = {};\n\tif (input.model !== undefined && input.model !== \"inherit\") {\n\t\tif (typeof input.model !== \"string\" || input.model.trim().length === 0) {\n\t\t\tthrow new Error(`Profile \"${profile}\" model override must be a model id.`);\n\t\t}\n\t\toutput.model = input.model.trim();\n\t}\n\tif (input.thinking !== undefined && input.thinking !== \"inherit\") {\n\t\tif (!isThinkingLevel(input.thinking)) {\n\t\t\tthrow new Error(`Profile \"${profile}\" thinking override is invalid.`);\n\t\t}\n\t\toutput.thinking = input.thinking as SubagentProfileOverride[\"thinking\"];\n\t}\n\tconst unknownKeys = Object.keys(input).filter((key) => key !== \"model\" && key !== \"thinking\");\n\tif (unknownKeys.length > 0) {\n\t\tthrow new Error(`Profile \"${profile}\" has unsupported setting(s): ${unknownKeys.join(\", \")}.`);\n\t}\n\treturn output;\n}\n\nexport function getSubagentConfigPath(agentDir = getAgentDir()): string {\n\treturn join(agentDir, SUBAGENT_CONFIG_FILE);\n}\n\nexport function emptySubagentConfig(): SubagentConfigFile {\n\treturn { version: SUBAGENT_CONFIG_VERSION, profiles: {} };\n}\n\nexport function parseSubagentConfig(raw: string): SubagentConfigFile {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tthrow new Error(`${SUBAGENT_CONFIG_FILE} is not valid JSON.`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`${SUBAGENT_CONFIG_FILE} must be a JSON object.`);\n\t}\n\tconst root = parsed as Record<string, unknown>;\n\tif (root.version !== undefined && root.version !== SUBAGENT_CONFIG_VERSION) {\n\t\tthrow new Error(`${SUBAGENT_CONFIG_FILE} has unsupported version ${String(root.version)}.`);\n\t}\n\tif (\n\t\troot.profiles !== undefined &&\n\t\t(!root.profiles || typeof root.profiles !== \"object\" || Array.isArray(root.profiles))\n\t) {\n\t\tthrow new Error(`${SUBAGENT_CONFIG_FILE} profiles must be an object.`);\n\t}\n\tconst profiles: Record<string, SubagentProfileOverride> = {};\n\tfor (const [name, value] of Object.entries((root.profiles as Record<string, unknown> | undefined) ?? {})) {\n\t\tif (!name.trim()) throw new Error(`${SUBAGENT_CONFIG_FILE} contains an empty profile name.`);\n\t\tprofiles[name] = normalizeOverride(value, name);\n\t}\n\tconst unknownKeys = Object.keys(root).filter((key) => key !== \"version\" && key !== \"profiles\");\n\tif (unknownKeys.length > 0)\n\t\tthrow new Error(`${SUBAGENT_CONFIG_FILE} has unsupported field(s): ${unknownKeys.join(\", \")}.`);\n\treturn { version: SUBAGENT_CONFIG_VERSION, profiles };\n}\n\nexport async function loadSubagentConfig(agentDir = getAgentDir()): Promise<SubagentConfigFile> {\n\tconst filePath = getSubagentConfigPath(agentDir);\n\ttry {\n\t\treturn parseSubagentConfig(await readFile(filePath, \"utf8\"));\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return emptySubagentConfig();\n\t\tthrow error;\n\t}\n}\n\nexport async function saveSubagentConfig(config: SubagentConfigFile, agentDir = getAgentDir()): Promise<void> {\n\tconst filePath = getSubagentConfigPath(agentDir);\n\tconst payload = `${JSON.stringify({ version: SUBAGENT_CONFIG_VERSION, profiles: config.profiles }, null, 2)}\\n`;\n\tawait mkdir(dirname(filePath), { recursive: true });\n\tawait withFileMutationQueue(filePath, async () => {\n\t\tconst tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;\n\t\ttry {\n\t\t\tawait writeFile(tempPath, payload, { encoding: \"utf8\", mode: 0o600 });\n\t\t\tawait rename(tempPath, filePath);\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait unlink(tempPath);\n\t\t\t} catch {\n\t\t\t\t// Ignore cleanup errors and preserve the original failure.\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t});\n}\n\n// Only keys present in the patch change; a key set to undefined clears\n// that override (back to inheriting the parent session).\nexport async function updateProfileOverride(\n\tprofile: string,\n\tpatch: Partial<SubagentProfileOverride>,\n\tagentDir = getAgentDir(),\n): Promise<SubagentConfigFile> {\n\tconst config = await loadSubagentConfig(agentDir);\n\tconst current = config.profiles[profile] ?? {};\n\tconst next: SubagentProfileOverride = { ...current };\n\tif (\"model\" in patch) {\n\t\tif (patch.model === undefined) delete next.model;\n\t\telse next.model = patch.model;\n\t}\n\tif (\"thinking\" in patch) {\n\t\tif (patch.thinking === undefined) delete next.thinking;\n\t\telse next.thinking = patch.thinking;\n\t}\n\tif (Object.keys(next).length === 0) delete config.profiles[profile];\n\telse config.profiles[profile] = next;\n\tawait saveSubagentConfig(config, agentDir);\n\treturn config;\n}\n\nexport async function resetProfileOverrides(agentDir = getAgentDir()): Promise<void> {\n\tawait saveSubagentConfig(emptySubagentConfig(), agentDir);\n}\n"]}
@@ -0,0 +1,131 @@
1
+ import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import { getAgentDir } from "../../config.js";
4
+ import { withFileMutationQueue } from "../../core/tools/file-mutation-queue.js";
5
+ import { SUBAGENT_CONFIG_FILE, SUBAGENT_CONFIG_VERSION, THINKING_LEVELS } from "./constants.js";
6
+ function isThinkingLevel(value) {
7
+ return typeof value === "string" && THINKING_LEVELS.includes(value);
8
+ }
9
+ // Overrides hold concrete values only; absence means "inherit the parent
10
+ // session". Legacy "inherit" entries from earlier versions are dropped.
11
+ function normalizeOverride(value, profile) {
12
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
13
+ throw new Error(`Profile override for "${profile}" must be an object.`);
14
+ }
15
+ const input = value;
16
+ const output = {};
17
+ if (input.model !== undefined && input.model !== "inherit") {
18
+ if (typeof input.model !== "string" || input.model.trim().length === 0) {
19
+ throw new Error(`Profile "${profile}" model override must be a model id.`);
20
+ }
21
+ output.model = input.model.trim();
22
+ }
23
+ if (input.thinking !== undefined && input.thinking !== "inherit") {
24
+ if (!isThinkingLevel(input.thinking)) {
25
+ throw new Error(`Profile "${profile}" thinking override is invalid.`);
26
+ }
27
+ output.thinking = input.thinking;
28
+ }
29
+ const unknownKeys = Object.keys(input).filter((key) => key !== "model" && key !== "thinking");
30
+ if (unknownKeys.length > 0) {
31
+ throw new Error(`Profile "${profile}" has unsupported setting(s): ${unknownKeys.join(", ")}.`);
32
+ }
33
+ return output;
34
+ }
35
+ export function getSubagentConfigPath(agentDir = getAgentDir()) {
36
+ return join(agentDir, SUBAGENT_CONFIG_FILE);
37
+ }
38
+ export function emptySubagentConfig() {
39
+ return { version: SUBAGENT_CONFIG_VERSION, profiles: {} };
40
+ }
41
+ export function parseSubagentConfig(raw) {
42
+ let parsed;
43
+ try {
44
+ parsed = JSON.parse(raw);
45
+ }
46
+ catch {
47
+ throw new Error(`${SUBAGENT_CONFIG_FILE} is not valid JSON.`);
48
+ }
49
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
50
+ throw new Error(`${SUBAGENT_CONFIG_FILE} must be a JSON object.`);
51
+ }
52
+ const root = parsed;
53
+ if (root.version !== undefined && root.version !== SUBAGENT_CONFIG_VERSION) {
54
+ throw new Error(`${SUBAGENT_CONFIG_FILE} has unsupported version ${String(root.version)}.`);
55
+ }
56
+ if (root.profiles !== undefined &&
57
+ (!root.profiles || typeof root.profiles !== "object" || Array.isArray(root.profiles))) {
58
+ throw new Error(`${SUBAGENT_CONFIG_FILE} profiles must be an object.`);
59
+ }
60
+ const profiles = {};
61
+ for (const [name, value] of Object.entries(root.profiles ?? {})) {
62
+ if (!name.trim())
63
+ throw new Error(`${SUBAGENT_CONFIG_FILE} contains an empty profile name.`);
64
+ profiles[name] = normalizeOverride(value, name);
65
+ }
66
+ const unknownKeys = Object.keys(root).filter((key) => key !== "version" && key !== "profiles");
67
+ if (unknownKeys.length > 0)
68
+ throw new Error(`${SUBAGENT_CONFIG_FILE} has unsupported field(s): ${unknownKeys.join(", ")}.`);
69
+ return { version: SUBAGENT_CONFIG_VERSION, profiles };
70
+ }
71
+ export async function loadSubagentConfig(agentDir = getAgentDir()) {
72
+ const filePath = getSubagentConfigPath(agentDir);
73
+ try {
74
+ return parseSubagentConfig(await readFile(filePath, "utf8"));
75
+ }
76
+ catch (error) {
77
+ if (error.code === "ENOENT")
78
+ return emptySubagentConfig();
79
+ throw error;
80
+ }
81
+ }
82
+ export async function saveSubagentConfig(config, agentDir = getAgentDir()) {
83
+ const filePath = getSubagentConfigPath(agentDir);
84
+ const payload = `${JSON.stringify({ version: SUBAGENT_CONFIG_VERSION, profiles: config.profiles }, null, 2)}\n`;
85
+ await mkdir(dirname(filePath), { recursive: true });
86
+ await withFileMutationQueue(filePath, async () => {
87
+ const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
88
+ try {
89
+ await writeFile(tempPath, payload, { encoding: "utf8", mode: 0o600 });
90
+ await rename(tempPath, filePath);
91
+ }
92
+ catch (error) {
93
+ try {
94
+ await unlink(tempPath);
95
+ }
96
+ catch {
97
+ // Ignore cleanup errors and preserve the original failure.
98
+ }
99
+ throw error;
100
+ }
101
+ });
102
+ }
103
+ // Only keys present in the patch change; a key set to undefined clears
104
+ // that override (back to inheriting the parent session).
105
+ export async function updateProfileOverride(profile, patch, agentDir = getAgentDir()) {
106
+ const config = await loadSubagentConfig(agentDir);
107
+ const current = config.profiles[profile] ?? {};
108
+ const next = { ...current };
109
+ if ("model" in patch) {
110
+ if (patch.model === undefined)
111
+ delete next.model;
112
+ else
113
+ next.model = patch.model;
114
+ }
115
+ if ("thinking" in patch) {
116
+ if (patch.thinking === undefined)
117
+ delete next.thinking;
118
+ else
119
+ next.thinking = patch.thinking;
120
+ }
121
+ if (Object.keys(next).length === 0)
122
+ delete config.profiles[profile];
123
+ else
124
+ config.profiles[profile] = next;
125
+ await saveSubagentConfig(config, agentDir);
126
+ return config;
127
+ }
128
+ export async function resetProfileOverrides(agentDir = getAgentDir()) {
129
+ await saveSubagentConfig(emptySubagentConfig(), agentDir);
130
+ }
131
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/extensions/subagent/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGhG,SAAS,eAAe,CAAC,KAAc,EAAW;IACjD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,eAAqC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAAA,CAC3F;AAED,yEAAyE;AACzE,wEAAwE;AACxE,SAAS,iBAAiB,CAAC,KAAc,EAAE,OAAe,EAA2B;IACpF,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,yBAAyB,OAAO,sBAAsB,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,KAAK,GAAG,KAAgC,CAAC;IAC/C,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC5D,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxE,MAAM,IAAI,KAAK,CAAC,YAAY,OAAO,sCAAsC,CAAC,CAAC;QAC5E,CAAC;QACD,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACnC,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAClE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,YAAY,OAAO,iCAAiC,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,QAA+C,CAAC;IACzE,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,UAAU,CAAC,CAAC;IAC9F,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,YAAY,OAAO,iCAAiC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACd;AAED,MAAM,UAAU,qBAAqB,CAAC,QAAQ,GAAG,WAAW,EAAE,EAAU;IACvE,OAAO,IAAI,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;AAAA,CAC5C;AAED,MAAM,UAAU,mBAAmB,GAAuB;IACzD,OAAO,EAAE,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAAA,CAC1D;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAsB;IACpE,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,GAAG,oBAAoB,qBAAqB,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACpE,MAAM,IAAI,KAAK,CAAC,GAAG,oBAAoB,yBAAyB,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,IAAI,GAAG,MAAiC,CAAC;IAC/C,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,uBAAuB,EAAE,CAAC;QAC5E,MAAM,IAAI,KAAK,CAAC,GAAG,oBAAoB,4BAA4B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7F,CAAC;IACD,IACC,IAAI,CAAC,QAAQ,KAAK,SAAS;QAC3B,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EACpF,CAAC;QACF,MAAM,IAAI,KAAK,CAAC,GAAG,oBAAoB,8BAA8B,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,QAAQ,GAA4C,EAAE,CAAC;IAC7D,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAE,IAAI,CAAC,QAAgD,IAAI,EAAE,CAAC,EAAE,CAAC;QAC1G,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,oBAAoB,kCAAkC,CAAC,CAAC;QAC7F,QAAQ,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,UAAU,CAAC,CAAC;IAC/F,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,GAAG,oBAAoB,8BAA8B,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjG,OAAO,EAAE,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,CAAC;AAAA,CACtD;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAQ,GAAG,WAAW,EAAE,EAA+B;IAC/F,MAAM,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,CAAC;QACJ,OAAO,mBAAmB,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,mBAAmB,EAAE,CAAC;QACrF,MAAM,KAAK,CAAC;IACb,CAAC;AAAA,CACD;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAA0B,EAAE,QAAQ,GAAG,WAAW,EAAE,EAAiB;IAC7G,MAAM,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IAChH,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,qBAAqB,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC;QACjD,MAAM,QAAQ,GAAG,GAAG,QAAQ,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;QAChE,IAAI,CAAC;YACJ,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACtE,MAAM,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC;gBACJ,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACR,2DAA2D;YAC5D,CAAC;YACD,MAAM,KAAK,CAAC;QACb,CAAC;IAAA,CACD,CAAC,CAAC;AAAA,CACH;AAED,uEAAuE;AACvE,yDAAyD;AACzD,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAC1C,OAAe,EACf,KAAuC,EACvC,QAAQ,GAAG,WAAW,EAAE,EACM;IAC9B,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IAC/C,MAAM,IAAI,GAA4B,EAAE,GAAG,OAAO,EAAE,CAAC;IACrD,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;;YAC5C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC/B,CAAC;IACD,IAAI,UAAU,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC;;YAClD,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IACrC,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;;QAC/D,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IACrC,MAAM,kBAAkB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC3C,OAAO,MAAM,CAAC;AAAA,CACd;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,QAAQ,GAAG,WAAW,EAAE,EAAiB;IACpF,MAAM,kBAAkB,CAAC,mBAAmB,EAAE,EAAE,QAAQ,CAAC,CAAC;AAAA,CAC1D","sourcesContent":["import { mkdir, readFile, rename, unlink, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { withFileMutationQueue } from \"../../core/tools/file-mutation-queue.ts\";\nimport { SUBAGENT_CONFIG_FILE, SUBAGENT_CONFIG_VERSION, THINKING_LEVELS } from \"./constants.ts\";\nimport type { SubagentConfigFile, SubagentProfileOverride } from \"./types.ts\";\n\nfunction isThinkingLevel(value: unknown): boolean {\n\treturn typeof value === \"string\" && (THINKING_LEVELS as readonly string[]).includes(value);\n}\n\n// Overrides hold concrete values only; absence means \"inherit the parent\n// session\". Legacy \"inherit\" entries from earlier versions are dropped.\nfunction normalizeOverride(value: unknown, profile: string): SubagentProfileOverride {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(`Profile override for \"${profile}\" must be an object.`);\n\t}\n\tconst input = value as Record<string, unknown>;\n\tconst output: SubagentProfileOverride = {};\n\tif (input.model !== undefined && input.model !== \"inherit\") {\n\t\tif (typeof input.model !== \"string\" || input.model.trim().length === 0) {\n\t\t\tthrow new Error(`Profile \"${profile}\" model override must be a model id.`);\n\t\t}\n\t\toutput.model = input.model.trim();\n\t}\n\tif (input.thinking !== undefined && input.thinking !== \"inherit\") {\n\t\tif (!isThinkingLevel(input.thinking)) {\n\t\t\tthrow new Error(`Profile \"${profile}\" thinking override is invalid.`);\n\t\t}\n\t\toutput.thinking = input.thinking as SubagentProfileOverride[\"thinking\"];\n\t}\n\tconst unknownKeys = Object.keys(input).filter((key) => key !== \"model\" && key !== \"thinking\");\n\tif (unknownKeys.length > 0) {\n\t\tthrow new Error(`Profile \"${profile}\" has unsupported setting(s): ${unknownKeys.join(\", \")}.`);\n\t}\n\treturn output;\n}\n\nexport function getSubagentConfigPath(agentDir = getAgentDir()): string {\n\treturn join(agentDir, SUBAGENT_CONFIG_FILE);\n}\n\nexport function emptySubagentConfig(): SubagentConfigFile {\n\treturn { version: SUBAGENT_CONFIG_VERSION, profiles: {} };\n}\n\nexport function parseSubagentConfig(raw: string): SubagentConfigFile {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tthrow new Error(`${SUBAGENT_CONFIG_FILE} is not valid JSON.`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`${SUBAGENT_CONFIG_FILE} must be a JSON object.`);\n\t}\n\tconst root = parsed as Record<string, unknown>;\n\tif (root.version !== undefined && root.version !== SUBAGENT_CONFIG_VERSION) {\n\t\tthrow new Error(`${SUBAGENT_CONFIG_FILE} has unsupported version ${String(root.version)}.`);\n\t}\n\tif (\n\t\troot.profiles !== undefined &&\n\t\t(!root.profiles || typeof root.profiles !== \"object\" || Array.isArray(root.profiles))\n\t) {\n\t\tthrow new Error(`${SUBAGENT_CONFIG_FILE} profiles must be an object.`);\n\t}\n\tconst profiles: Record<string, SubagentProfileOverride> = {};\n\tfor (const [name, value] of Object.entries((root.profiles as Record<string, unknown> | undefined) ?? {})) {\n\t\tif (!name.trim()) throw new Error(`${SUBAGENT_CONFIG_FILE} contains an empty profile name.`);\n\t\tprofiles[name] = normalizeOverride(value, name);\n\t}\n\tconst unknownKeys = Object.keys(root).filter((key) => key !== \"version\" && key !== \"profiles\");\n\tif (unknownKeys.length > 0)\n\t\tthrow new Error(`${SUBAGENT_CONFIG_FILE} has unsupported field(s): ${unknownKeys.join(\", \")}.`);\n\treturn { version: SUBAGENT_CONFIG_VERSION, profiles };\n}\n\nexport async function loadSubagentConfig(agentDir = getAgentDir()): Promise<SubagentConfigFile> {\n\tconst filePath = getSubagentConfigPath(agentDir);\n\ttry {\n\t\treturn parseSubagentConfig(await readFile(filePath, \"utf8\"));\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return emptySubagentConfig();\n\t\tthrow error;\n\t}\n}\n\nexport async function saveSubagentConfig(config: SubagentConfigFile, agentDir = getAgentDir()): Promise<void> {\n\tconst filePath = getSubagentConfigPath(agentDir);\n\tconst payload = `${JSON.stringify({ version: SUBAGENT_CONFIG_VERSION, profiles: config.profiles }, null, 2)}\\n`;\n\tawait mkdir(dirname(filePath), { recursive: true });\n\tawait withFileMutationQueue(filePath, async () => {\n\t\tconst tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;\n\t\ttry {\n\t\t\tawait writeFile(tempPath, payload, { encoding: \"utf8\", mode: 0o600 });\n\t\t\tawait rename(tempPath, filePath);\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait unlink(tempPath);\n\t\t\t} catch {\n\t\t\t\t// Ignore cleanup errors and preserve the original failure.\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t});\n}\n\n// Only keys present in the patch change; a key set to undefined clears\n// that override (back to inheriting the parent session).\nexport async function updateProfileOverride(\n\tprofile: string,\n\tpatch: Partial<SubagentProfileOverride>,\n\tagentDir = getAgentDir(),\n): Promise<SubagentConfigFile> {\n\tconst config = await loadSubagentConfig(agentDir);\n\tconst current = config.profiles[profile] ?? {};\n\tconst next: SubagentProfileOverride = { ...current };\n\tif (\"model\" in patch) {\n\t\tif (patch.model === undefined) delete next.model;\n\t\telse next.model = patch.model;\n\t}\n\tif (\"thinking\" in patch) {\n\t\tif (patch.thinking === undefined) delete next.thinking;\n\t\telse next.thinking = patch.thinking;\n\t}\n\tif (Object.keys(next).length === 0) delete config.profiles[profile];\n\telse config.profiles[profile] = next;\n\tawait saveSubagentConfig(config, agentDir);\n\treturn config;\n}\n\nexport async function resetProfileOverrides(agentDir = getAgentDir()): Promise<void> {\n\tawait saveSubagentConfig(emptySubagentConfig(), agentDir);\n}\n"]}
@@ -0,0 +1,99 @@
1
+ import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
2
+ import type { Api, Model, Usage } from "@earendil-works/pi-ai";
3
+ export type AgentSource = "builtin" | "user" | "project";
4
+ export type SubagentMode = "single" | "parallel" | "chain";
5
+ export type SubagentRunStatus = "queued" | "running" | "completed" | "failed" | "aborted";
6
+ export type ToolActivityStatus = "running" | "succeeded" | "failed";
7
+ export interface AgentDefinition {
8
+ name: string;
9
+ description: string;
10
+ tools: string[];
11
+ systemPrompt: string;
12
+ source: AgentSource;
13
+ filePath: string;
14
+ backend: "sdk";
15
+ }
16
+ export interface AgentDiagnostic {
17
+ path: string;
18
+ message: string;
19
+ source: Exclude<AgentSource, "builtin">;
20
+ }
21
+ export interface AgentDiscoveryResult {
22
+ agents: AgentDefinition[];
23
+ diagnostics: AgentDiagnostic[];
24
+ projectAgentsDir?: string;
25
+ projectAgentsTrusted: boolean;
26
+ }
27
+ export interface SubagentProfileOverride {
28
+ model?: string;
29
+ thinking?: ThinkingLevel;
30
+ }
31
+ export interface SubagentConfigFile {
32
+ version: 1;
33
+ profiles: Record<string, SubagentProfileOverride>;
34
+ }
35
+ export interface ResolvedSubagentTask {
36
+ agent: AgentDefinition;
37
+ description: string;
38
+ prompt: string;
39
+ cwd: string;
40
+ model: Model<Api>;
41
+ thinking: ThinkingLevel;
42
+ modelSource: "profile" | "parent";
43
+ thinkingSource: "profile" | "parent";
44
+ }
45
+ export interface ToolActivity {
46
+ id: string;
47
+ toolName: string;
48
+ summary: string;
49
+ status: ToolActivityStatus;
50
+ startedAt: number;
51
+ endedAt?: number;
52
+ resultSummary?: string;
53
+ }
54
+ export interface SubagentUsage {
55
+ turns: number;
56
+ toolUses: number;
57
+ input: number;
58
+ output: number;
59
+ cacheRead: number;
60
+ cacheWrite: number;
61
+ totalTokens: number;
62
+ cost: number;
63
+ }
64
+ export interface SubagentRunDetails {
65
+ id: string;
66
+ agent: string;
67
+ agentSource: AgentSource;
68
+ description: string;
69
+ prompt: string;
70
+ cwd: string;
71
+ model: string;
72
+ thinking: ThinkingLevel;
73
+ status: SubagentRunStatus;
74
+ startedAt?: number;
75
+ endedAt?: number;
76
+ currentActivity?: string;
77
+ activities: ToolActivity[];
78
+ liveText: string;
79
+ finalOutput: string;
80
+ error?: string;
81
+ usage: SubagentUsage;
82
+ step?: number;
83
+ }
84
+ export interface SubagentDetails {
85
+ mode: SubagentMode;
86
+ status: SubagentRunStatus;
87
+ runs: SubagentRunDetails[];
88
+ startedAt: number;
89
+ endedAt?: number;
90
+ usage: SubagentUsage;
91
+ error?: string;
92
+ }
93
+ export interface SubagentExecutionResult {
94
+ content: string;
95
+ details: SubagentDetails;
96
+ usage?: Usage;
97
+ isError: boolean;
98
+ }
99
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/extensions/subagent/types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model, Usage } from \"@earendil-works/pi-ai\";\n\nexport type AgentSource = \"builtin\" | \"user\" | \"project\";\nexport type SubagentMode = \"single\" | \"parallel\" | \"chain\";\nexport type SubagentRunStatus = \"queued\" | \"running\" | \"completed\" | \"failed\" | \"aborted\";\nexport type ToolActivityStatus = \"running\" | \"succeeded\" | \"failed\";\n\nexport interface AgentDefinition {\n\tname: string;\n\tdescription: string;\n\ttools: string[];\n\tsystemPrompt: string;\n\tsource: AgentSource;\n\tfilePath: string;\n\tbackend: \"sdk\";\n}\n\nexport interface AgentDiagnostic {\n\tpath: string;\n\tmessage: string;\n\tsource: Exclude<AgentSource, \"builtin\">;\n}\n\nexport interface AgentDiscoveryResult {\n\tagents: AgentDefinition[];\n\tdiagnostics: AgentDiagnostic[];\n\tprojectAgentsDir?: string;\n\tprojectAgentsTrusted: boolean;\n}\n\nexport interface SubagentProfileOverride {\n\tmodel?: string;\n\tthinking?: ThinkingLevel;\n}\n\nexport interface SubagentConfigFile {\n\tversion: 1;\n\tprofiles: Record<string, SubagentProfileOverride>;\n}\n\nexport interface ResolvedSubagentTask {\n\tagent: AgentDefinition;\n\tdescription: string;\n\tprompt: string;\n\tcwd: string;\n\tmodel: Model<Api>;\n\tthinking: ThinkingLevel;\n\tmodelSource: \"profile\" | \"parent\";\n\tthinkingSource: \"profile\" | \"parent\";\n}\n\nexport interface ToolActivity {\n\tid: string;\n\ttoolName: string;\n\tsummary: string;\n\tstatus: ToolActivityStatus;\n\tstartedAt: number;\n\tendedAt?: number;\n\tresultSummary?: string;\n}\n\nexport interface SubagentUsage {\n\tturns: number;\n\ttoolUses: number;\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\ttotalTokens: number;\n\tcost: number;\n}\n\nexport interface SubagentRunDetails {\n\tid: string;\n\tagent: string;\n\tagentSource: AgentSource;\n\tdescription: string;\n\tprompt: string;\n\tcwd: string;\n\tmodel: string;\n\tthinking: ThinkingLevel;\n\tstatus: SubagentRunStatus;\n\tstartedAt?: number;\n\tendedAt?: number;\n\tcurrentActivity?: string;\n\tactivities: ToolActivity[];\n\tliveText: string;\n\tfinalOutput: string;\n\terror?: string;\n\tusage: SubagentUsage;\n\tstep?: number;\n}\n\nexport interface SubagentDetails {\n\tmode: SubagentMode;\n\tstatus: SubagentRunStatus;\n\truns: SubagentRunDetails[];\n\tstartedAt: number;\n\tendedAt?: number;\n\tusage: SubagentUsage;\n\terror?: string;\n}\n\nexport interface SubagentExecutionResult {\n\tcontent: string;\n\tdetails: SubagentDetails;\n\tusage?: Usage;\n\tisError: boolean;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/extensions/subagent/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model, Usage } from \"@earendil-works/pi-ai\";\n\nexport type AgentSource = \"builtin\" | \"user\" | \"project\";\nexport type SubagentMode = \"single\" | \"parallel\" | \"chain\";\nexport type SubagentRunStatus = \"queued\" | \"running\" | \"completed\" | \"failed\" | \"aborted\";\nexport type ToolActivityStatus = \"running\" | \"succeeded\" | \"failed\";\n\nexport interface AgentDefinition {\n\tname: string;\n\tdescription: string;\n\ttools: string[];\n\tsystemPrompt: string;\n\tsource: AgentSource;\n\tfilePath: string;\n\tbackend: \"sdk\";\n}\n\nexport interface AgentDiagnostic {\n\tpath: string;\n\tmessage: string;\n\tsource: Exclude<AgentSource, \"builtin\">;\n}\n\nexport interface AgentDiscoveryResult {\n\tagents: AgentDefinition[];\n\tdiagnostics: AgentDiagnostic[];\n\tprojectAgentsDir?: string;\n\tprojectAgentsTrusted: boolean;\n}\n\nexport interface SubagentProfileOverride {\n\tmodel?: string;\n\tthinking?: ThinkingLevel;\n}\n\nexport interface SubagentConfigFile {\n\tversion: 1;\n\tprofiles: Record<string, SubagentProfileOverride>;\n}\n\nexport interface ResolvedSubagentTask {\n\tagent: AgentDefinition;\n\tdescription: string;\n\tprompt: string;\n\tcwd: string;\n\tmodel: Model<Api>;\n\tthinking: ThinkingLevel;\n\tmodelSource: \"profile\" | \"parent\";\n\tthinkingSource: \"profile\" | \"parent\";\n}\n\nexport interface ToolActivity {\n\tid: string;\n\ttoolName: string;\n\tsummary: string;\n\tstatus: ToolActivityStatus;\n\tstartedAt: number;\n\tendedAt?: number;\n\tresultSummary?: string;\n}\n\nexport interface SubagentUsage {\n\tturns: number;\n\ttoolUses: number;\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\ttotalTokens: number;\n\tcost: number;\n}\n\nexport interface SubagentRunDetails {\n\tid: string;\n\tagent: string;\n\tagentSource: AgentSource;\n\tdescription: string;\n\tprompt: string;\n\tcwd: string;\n\tmodel: string;\n\tthinking: ThinkingLevel;\n\tstatus: SubagentRunStatus;\n\tstartedAt?: number;\n\tendedAt?: number;\n\tcurrentActivity?: string;\n\tactivities: ToolActivity[];\n\tliveText: string;\n\tfinalOutput: string;\n\terror?: string;\n\tusage: SubagentUsage;\n\tstep?: number;\n}\n\nexport interface SubagentDetails {\n\tmode: SubagentMode;\n\tstatus: SubagentRunStatus;\n\truns: SubagentRunDetails[];\n\tstartedAt: number;\n\tendedAt?: number;\n\tusage: SubagentUsage;\n\terror?: string;\n}\n\nexport interface SubagentExecutionResult {\n\tcontent: string;\n\tdetails: SubagentDetails;\n\tusage?: Usage;\n\tisError: boolean;\n}\n"]}
@@ -16,7 +16,6 @@ export declare class ExtensionEditorComponent extends Container implements Focus
16
16
  set focused(value: boolean);
17
17
  constructor(tui: TUI, keybindings: KeybindingsManager, title: string, prefill: string | undefined, onSubmit: (value: string) => void, onCancel: () => void, options?: EditorOptions, externalEditorCommand?: string);
18
18
  handleInput(keyData: string): void;
19
- private getExternalEditorCommand;
20
- private openExternalEditor;
19
+ private handleOpenExternalEditor;
21
20
  }
22
21
  //# sourceMappingURL=extension-editor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension-editor.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/extension-editor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EACN,SAAS,EAET,KAAK,aAAa,EAClB,KAAK,SAAS,EAId,KAAK,GAAG,EACR,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAKvE,qBAAa,wBAAyB,SAAQ,SAAU,YAAW,SAAS;IAC3E,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,qBAAqB,CAAqB;IAElD,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,YACC,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,kBAAkB,EAC/B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EACjC,QAAQ,EAAE,MAAM,IAAI,EACpB,OAAO,CAAC,EAAE,aAAa,EACvB,qBAAqB,CAAC,EAAE,MAAM,EA8C9B;IAED,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAgBjC;IAED,OAAO,CAAC,wBAAwB;YAQlB,kBAAkB;CA2ChC","sourcesContent":["/**\n * Multi-line editor component for extensions.\n * Supports Ctrl+G for external editor.\n */\n\nimport { spawn } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport {\n\tContainer,\n\tEditor,\n\ttype EditorOptions,\n\ttype Focusable,\n\tgetKeybindings,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@earendil-works/pi-tui\";\nimport type { KeybindingsManager } from \"../../../core/keybindings.ts\";\nimport { getEditorTheme, theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint } from \"./keybinding-hints.ts\";\n\nexport class ExtensionEditorComponent extends Container implements Focusable {\n\tprivate editor: Editor;\n\tprivate onSubmitCallback: (value: string) => void;\n\tprivate onCancelCallback: () => void;\n\tprivate tui: TUI;\n\tprivate keybindings: KeybindingsManager;\n\tprivate externalEditorCommand: string | undefined;\n\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.editor.focused = value;\n\t}\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tkeybindings: KeybindingsManager,\n\t\ttitle: string,\n\t\tprefill: string | undefined,\n\t\tonSubmit: (value: string) => void,\n\t\tonCancel: () => void,\n\t\toptions?: EditorOptions,\n\t\texternalEditorCommand?: string,\n\t) {\n\t\tsuper();\n\n\t\tthis.tui = tui;\n\t\tthis.keybindings = keybindings;\n\t\tthis.externalEditorCommand = externalEditorCommand;\n\t\tthis.onSubmitCallback = onSubmit;\n\t\tthis.onCancelCallback = onCancel;\n\n\t\t// Add top border\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Add title\n\t\tthis.addChild(new Text(theme.fg(\"accent\", title), 1, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create editor\n\t\tthis.editor = new Editor(tui, getEditorTheme(), options);\n\t\tif (prefill) {\n\t\t\tthis.editor.setText(prefill);\n\t\t}\n\t\t// Wire up Enter to submit (Shift+Enter for newlines, like the main editor)\n\t\tthis.editor.onSubmit = (text: string) => {\n\t\t\tthis.onSubmitCallback(text);\n\t\t};\n\t\tthis.addChild(this.editor);\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Add hint\n\t\tconst hasExternalEditor = !!this.getExternalEditorCommand();\n\t\tconst hint =\n\t\t\tkeyHint(\"tui.select.confirm\", \"submit\") +\n\t\t\t\" \" +\n\t\t\tkeyHint(\"tui.input.newLine\", \"newline\") +\n\t\t\t\" \" +\n\t\t\tkeyHint(\"tui.select.cancel\", \"cancel\") +\n\t\t\t(hasExternalEditor ? ` ${keyHint(\"app.editor.external\", \"external editor\")}` : \"\");\n\t\tthis.addChild(new Text(hint, 1, 0));\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Add bottom border\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\t// Escape or Ctrl+C to cancel\n\t\tif (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancelCallback();\n\t\t\treturn;\n\t\t}\n\n\t\t// External editor (app keybinding)\n\t\tif (this.keybindings.matches(keyData, \"app.editor.external\")) {\n\t\t\tthis.openExternalEditor();\n\t\t\treturn;\n\t\t}\n\n\t\t// Forward to editor\n\t\tthis.editor.handleInput(keyData);\n\t}\n\n\tprivate getExternalEditorCommand(): string | undefined {\n\t\tconst editorCmd = this.externalEditorCommand || process.env.VISUAL || process.env.EDITOR;\n\t\tif (editorCmd) {\n\t\t\treturn editorCmd;\n\t\t}\n\t\treturn process.platform === \"win32\" ? \"notepad\" : \"nano\";\n\t}\n\n\tprivate async openExternalEditor(): Promise<void> {\n\t\tconst editorCmd = this.getExternalEditorCommand();\n\t\tif (!editorCmd) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst currentText = this.editor.getText();\n\t\tconst tmpFile = path.join(os.tmpdir(), `pi-extension-editor-${Date.now()}.md`);\n\n\t\ttry {\n\t\t\tfs.writeFileSync(tmpFile, currentText, \"utf-8\");\n\t\t\tthis.tui.stop();\n\n\t\t\tconst [editor, ...editorArgs] = editorCmd.split(\" \");\n\t\t\tprocess.stdout.write(`Launching external editor: ${editorCmd}\\nPi will resume when the editor exits.\\n`);\n\n\t\t\t// Do not use spawnSync here. On Windows, synchronous child_process calls can keep\n\t\t\t// Node/libuv's console input read active after tui.stop() pauses stdin, racing\n\t\t\t// vim/nvim for the console input buffer until Ctrl+C cancels the pending read.\n\t\t\tconst status = await new Promise<number | null>((resolve) => {\n\t\t\t\tconst child = spawn(editor, [...editorArgs, tmpFile], {\n\t\t\t\t\tstdio: \"inherit\",\n\t\t\t\t\tshell: process.platform === \"win32\",\n\t\t\t\t});\n\t\t\t\tchild.on(\"error\", () => resolve(null));\n\t\t\t\tchild.on(\"close\", (code) => resolve(code));\n\t\t\t});\n\n\t\t\tif (status === 0) {\n\t\t\t\tconst newContent = fs.readFileSync(tmpFile, \"utf-8\").replace(/\\n$/, \"\");\n\t\t\t\tthis.editor.setText(newContent);\n\t\t\t}\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tfs.unlinkSync(tmpFile);\n\t\t\t} catch {\n\t\t\t\t// Ignore cleanup errors\n\t\t\t}\n\t\t\tthis.tui.start();\n\t\t\t// Force full re-render since external editor uses alternate screen\n\t\t\tthis.tui.requestRender(true);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"extension-editor.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/extension-editor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,SAAS,EAET,KAAK,aAAa,EAClB,KAAK,SAAS,EAId,KAAK,GAAG,EACR,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAMvE,qBAAa,wBAAyB,SAAQ,SAAU,YAAW,SAAS;IAC3E,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,qBAAqB,CAAS;IAEtC,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,YACC,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,kBAAkB,EAC/B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EACjC,QAAQ,EAAE,MAAM,IAAI,EACpB,OAAO,CAAC,EAAE,aAAa,EACvB,qBAAqB,CAAC,EAAE,MAAM,EAiD9B;IAED,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAgBjC;YAEa,wBAAwB;CAgBtC","sourcesContent":["/**\n * Multi-line editor component for extensions.\n * Supports Ctrl+G for external editor.\n */\n\nimport {\n\tContainer,\n\tEditor,\n\ttype EditorOptions,\n\ttype Focusable,\n\tgetKeybindings,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@earendil-works/pi-tui\";\nimport type { KeybindingsManager } from \"../../../core/keybindings.ts\";\nimport { editInExternalEditor } from \"../external-editor.ts\";\nimport { getEditorTheme, theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint } from \"./keybinding-hints.ts\";\n\nexport class ExtensionEditorComponent extends Container implements Focusable {\n\tprivate editor: Editor;\n\tprivate onSubmitCallback: (value: string) => void;\n\tprivate onCancelCallback: () => void;\n\tprivate tui: TUI;\n\tprivate keybindings: KeybindingsManager;\n\tprivate externalEditorCommand: string;\n\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.editor.focused = value;\n\t}\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tkeybindings: KeybindingsManager,\n\t\ttitle: string,\n\t\tprefill: string | undefined,\n\t\tonSubmit: (value: string) => void,\n\t\tonCancel: () => void,\n\t\toptions?: EditorOptions,\n\t\texternalEditorCommand?: string,\n\t) {\n\t\tsuper();\n\n\t\tthis.tui = tui;\n\t\tthis.keybindings = keybindings;\n\t\tthis.externalEditorCommand =\n\t\t\texternalEditorCommand ||\n\t\t\tprocess.env.VISUAL ||\n\t\t\tprocess.env.EDITOR ||\n\t\t\t(process.platform === \"win32\" ? \"notepad\" : \"nano\");\n\t\tthis.onSubmitCallback = onSubmit;\n\t\tthis.onCancelCallback = onCancel;\n\n\t\t// Add top border\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Add title\n\t\tthis.addChild(new Text(theme.fg(\"accent\", title), 1, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create editor\n\t\tthis.editor = new Editor(tui, getEditorTheme(), options);\n\t\tif (prefill) {\n\t\t\tthis.editor.setText(prefill);\n\t\t}\n\t\t// Wire up Enter to submit (Shift+Enter for newlines, like the main editor)\n\t\tthis.editor.onSubmit = (text: string) => {\n\t\t\tthis.onSubmitCallback(text);\n\t\t};\n\t\tthis.addChild(this.editor);\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Add hint\n\t\tconst hint =\n\t\t\tkeyHint(\"tui.select.confirm\", \"submit\") +\n\t\t\t\" \" +\n\t\t\tkeyHint(\"tui.input.newLine\", \"newline\") +\n\t\t\t\" \" +\n\t\t\tkeyHint(\"tui.select.cancel\", \"cancel\") +\n\t\t\t` ${keyHint(\"app.editor.external\", \"external editor\")}`;\n\t\tthis.addChild(new Text(hint, 1, 0));\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Add bottom border\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\t// Escape or Ctrl+C to cancel\n\t\tif (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancelCallback();\n\t\t\treturn;\n\t\t}\n\n\t\t// External editor (app keybinding)\n\t\tif (this.keybindings.matches(keyData, \"app.editor.external\")) {\n\t\t\tvoid this.handleOpenExternalEditor();\n\t\t\treturn;\n\t\t}\n\n\t\t// Forward to editor\n\t\tthis.editor.handleInput(keyData);\n\t}\n\n\tprivate async handleOpenExternalEditor(): Promise<void> {\n\t\tconst content = this.editor.getText();\n\t\tthis.tui.stop();\n\t\ttry {\n\t\t\tconst result = await editInExternalEditor({\n\t\t\t\tcommand: this.externalEditorCommand,\n\t\t\t\tcontent,\n\t\t\t});\n\t\t\tif (result.status === \"complete\") {\n\t\t\t\tthis.editor.setText(result.content);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.tui.start();\n\t\t\tthis.tui.requestRender(true);\n\t\t}\n\t}\n}\n"]}