@narumitw/pi-subagents 2.0.1 → 2.0.3

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 (148) hide show
  1. package/README.md +20 -7
  2. package/dist/chunks/auto-transport-SY2VHUFH.ts +109 -0
  3. package/dist/chunks/auto-transport-SY2VHUFH.ts.map +7 -0
  4. package/dist/chunks/capability-grant-CGEWOEKE.ts +19 -0
  5. package/dist/chunks/capability-grant-CGEWOEKE.ts.map +7 -0
  6. package/dist/chunks/chunk-434NII74.ts +282 -0
  7. package/dist/chunks/chunk-434NII74.ts.map +7 -0
  8. package/dist/chunks/chunk-47SK2QYC.ts +56 -0
  9. package/dist/chunks/chunk-47SK2QYC.ts.map +7 -0
  10. package/dist/chunks/chunk-6KJ34M6S.ts +159 -0
  11. package/dist/chunks/chunk-6KJ34M6S.ts.map +7 -0
  12. package/dist/chunks/chunk-7OBINKFM.ts +80 -0
  13. package/dist/chunks/chunk-7OBINKFM.ts.map +7 -0
  14. package/dist/chunks/chunk-7QPPBBXZ.ts +335 -0
  15. package/dist/chunks/chunk-7QPPBBXZ.ts.map +7 -0
  16. package/dist/chunks/chunk-AEUYS7JC.ts +73 -0
  17. package/dist/chunks/chunk-AEUYS7JC.ts.map +7 -0
  18. package/dist/chunks/chunk-BFK2Z4ZF.ts +189 -0
  19. package/dist/chunks/chunk-BFK2Z4ZF.ts.map +7 -0
  20. package/dist/chunks/chunk-BOAXY55Y.ts +153 -0
  21. package/dist/chunks/chunk-BOAXY55Y.ts.map +7 -0
  22. package/dist/chunks/chunk-C4L6P266.ts +22 -0
  23. package/dist/chunks/chunk-C4L6P266.ts.map +7 -0
  24. package/dist/chunks/chunk-DPPVEQAM.ts +29 -0
  25. package/dist/chunks/chunk-DPPVEQAM.ts.map +7 -0
  26. package/dist/chunks/chunk-DQMN4OYM.ts +913 -0
  27. package/dist/chunks/chunk-DQMN4OYM.ts.map +7 -0
  28. package/dist/chunks/chunk-DSOOH73Y.ts +238 -0
  29. package/dist/chunks/chunk-DSOOH73Y.ts.map +7 -0
  30. package/dist/chunks/chunk-EFBPISNT.ts +421 -0
  31. package/dist/chunks/chunk-EFBPISNT.ts.map +7 -0
  32. package/dist/chunks/chunk-EWWXFU7N.ts +150 -0
  33. package/dist/chunks/chunk-EWWXFU7N.ts.map +7 -0
  34. package/dist/chunks/chunk-F4L2UVSK.ts +380 -0
  35. package/dist/chunks/chunk-F4L2UVSK.ts.map +7 -0
  36. package/dist/chunks/chunk-F5YWVHQX.ts +1543 -0
  37. package/dist/chunks/chunk-F5YWVHQX.ts.map +7 -0
  38. package/dist/chunks/chunk-G3RSMSXJ.ts +63 -0
  39. package/dist/chunks/chunk-G3RSMSXJ.ts.map +7 -0
  40. package/dist/chunks/chunk-G6VZTCFH.ts +70 -0
  41. package/dist/chunks/chunk-G6VZTCFH.ts.map +7 -0
  42. package/dist/chunks/chunk-H3FP6DLR.ts +160 -0
  43. package/dist/chunks/chunk-H3FP6DLR.ts.map +7 -0
  44. package/dist/chunks/chunk-HA36LPCO.ts +130 -0
  45. package/dist/chunks/chunk-HA36LPCO.ts.map +7 -0
  46. package/dist/chunks/chunk-HKC4ES4B.ts +65 -0
  47. package/dist/chunks/chunk-HKC4ES4B.ts.map +7 -0
  48. package/dist/chunks/chunk-HOP5FXDT.ts +27 -0
  49. package/dist/chunks/chunk-HOP5FXDT.ts.map +7 -0
  50. package/dist/chunks/chunk-I2FAK44T.ts +324 -0
  51. package/dist/chunks/chunk-I2FAK44T.ts.map +7 -0
  52. package/dist/chunks/chunk-IGAMVWFN.ts +139 -0
  53. package/dist/chunks/chunk-IGAMVWFN.ts.map +7 -0
  54. package/dist/chunks/chunk-KMGKCEO4.ts +38 -0
  55. package/dist/chunks/chunk-KMGKCEO4.ts.map +7 -0
  56. package/dist/chunks/chunk-N7BLVXKK.ts +73 -0
  57. package/dist/chunks/chunk-N7BLVXKK.ts.map +7 -0
  58. package/dist/chunks/chunk-NIF42QMF.ts +297 -0
  59. package/dist/chunks/chunk-NIF42QMF.ts.map +7 -0
  60. package/dist/chunks/chunk-O4VO6JUJ.ts +52 -0
  61. package/dist/chunks/chunk-O4VO6JUJ.ts.map +7 -0
  62. package/dist/chunks/chunk-ONDTY4EL.ts +91 -0
  63. package/dist/chunks/chunk-ONDTY4EL.ts.map +7 -0
  64. package/dist/chunks/chunk-OVPHFGKO.ts +1769 -0
  65. package/dist/chunks/chunk-OVPHFGKO.ts.map +7 -0
  66. package/dist/chunks/chunk-P7OH4XMF.ts +60 -0
  67. package/dist/chunks/chunk-P7OH4XMF.ts.map +7 -0
  68. package/dist/chunks/chunk-PSK43Y6A.ts +339 -0
  69. package/dist/chunks/chunk-PSK43Y6A.ts.map +7 -0
  70. package/dist/chunks/chunk-QBORTI4W.ts +468 -0
  71. package/dist/chunks/chunk-QBORTI4W.ts.map +7 -0
  72. package/dist/chunks/chunk-QDVGH2X7.ts +171 -0
  73. package/dist/chunks/chunk-QDVGH2X7.ts.map +7 -0
  74. package/dist/chunks/chunk-RHRQMT7Q.ts +490 -0
  75. package/dist/chunks/chunk-RHRQMT7Q.ts.map +7 -0
  76. package/dist/chunks/chunk-RRR66UWR.ts +28 -0
  77. package/dist/chunks/chunk-RRR66UWR.ts.map +7 -0
  78. package/dist/chunks/chunk-RSUXZD6S.ts +275 -0
  79. package/dist/chunks/chunk-RSUXZD6S.ts.map +7 -0
  80. package/dist/chunks/chunk-RTCVYIZA.ts +221 -0
  81. package/dist/chunks/chunk-RTCVYIZA.ts.map +7 -0
  82. package/dist/chunks/chunk-S2IWVK3J.ts +44 -0
  83. package/dist/chunks/chunk-S2IWVK3J.ts.map +7 -0
  84. package/dist/chunks/chunk-SCZ33MYW.ts +52 -0
  85. package/dist/chunks/chunk-SCZ33MYW.ts.map +7 -0
  86. package/dist/chunks/chunk-SWGQLFSD.ts +60 -0
  87. package/dist/chunks/chunk-SWGQLFSD.ts.map +7 -0
  88. package/dist/chunks/chunk-UMBPMVJW.ts +22 -0
  89. package/dist/chunks/chunk-UMBPMVJW.ts.map +7 -0
  90. package/dist/chunks/chunk-UVFVHIOP.ts +735 -0
  91. package/dist/chunks/chunk-UVFVHIOP.ts.map +7 -0
  92. package/dist/chunks/completion-delivery-YPOWSSV3.ts +16 -0
  93. package/dist/chunks/completion-delivery-YPOWSSV3.ts.map +7 -0
  94. package/dist/chunks/config-status-J4GPWP46.ts +34 -0
  95. package/dist/chunks/config-status-J4GPWP46.ts.map +7 -0
  96. package/dist/chunks/config-ui-3IBMHTQB.ts +1146 -0
  97. package/dist/chunks/config-ui-3IBMHTQB.ts.map +7 -0
  98. package/dist/chunks/consult-NYXVDN5G.ts +518 -0
  99. package/dist/chunks/consult-NYXVDN5G.ts.map +7 -0
  100. package/dist/chunks/context-QDKLVQXE.ts +11 -0
  101. package/dist/chunks/context-QDKLVQXE.ts.map +7 -0
  102. package/dist/chunks/create-stateful-transport-4WKZHRSI.ts +130 -0
  103. package/dist/chunks/create-stateful-transport-4WKZHRSI.ts.map +7 -0
  104. package/dist/chunks/cwd-policy-NB6XZ5GF.ts +17 -0
  105. package/dist/chunks/cwd-policy-NB6XZ5GF.ts.map +7 -0
  106. package/dist/chunks/delegation-contract-WJPT4FVS.ts +24 -0
  107. package/dist/chunks/delegation-contract-WJPT4FVS.ts.map +7 -0
  108. package/dist/chunks/discovery-K25T3SH4.ts +12 -0
  109. package/dist/chunks/discovery-K25T3SH4.ts.map +7 -0
  110. package/dist/chunks/execution-DS2DEIQZ.ts +4034 -0
  111. package/dist/chunks/execution-DS2DEIQZ.ts.map +7 -0
  112. package/dist/chunks/in-process-transport-TEYAWSEC.ts +38 -0
  113. package/dist/chunks/in-process-transport-TEYAWSEC.ts.map +7 -0
  114. package/dist/chunks/inspect-UOQQ3KNL.ts +619 -0
  115. package/dist/chunks/inspect-UOQQ3KNL.ts.map +7 -0
  116. package/dist/chunks/peer-communication-KL36Z6CO.ts +294 -0
  117. package/dist/chunks/peer-communication-KL36Z6CO.ts.map +7 -0
  118. package/dist/chunks/persistence-VSGXAW4P.ts +344 -0
  119. package/dist/chunks/persistence-VSGXAW4P.ts.map +7 -0
  120. package/dist/chunks/registry-E6XPJB7L.ts +1324 -0
  121. package/dist/chunks/registry-E6XPJB7L.ts.map +7 -0
  122. package/dist/chunks/retained-semantic-state-7WXSGRJU.ts +81 -0
  123. package/dist/chunks/retained-semantic-state-7WXSGRJU.ts.map +7 -0
  124. package/dist/chunks/rpc-transport-Y6LA5BOP.ts +1154 -0
  125. package/dist/chunks/rpc-transport-Y6LA5BOP.ts.map +7 -0
  126. package/dist/chunks/runtime-policy-5YELCOVC.ts +15 -0
  127. package/dist/chunks/runtime-policy-5YELCOVC.ts.map +7 -0
  128. package/dist/chunks/semantic-snapshot-WPJ3UAFW.ts +19 -0
  129. package/dist/chunks/semantic-snapshot-WPJ3UAFW.ts.map +7 -0
  130. package/dist/chunks/spawn-idempotency-QGHO2WKC.ts +13 -0
  131. package/dist/chunks/spawn-idempotency-QGHO2WKC.ts.map +7 -0
  132. package/dist/chunks/stateful-lifecycle-JAR6K55H.ts +15 -0
  133. package/dist/chunks/stateful-lifecycle-JAR6K55H.ts.map +7 -0
  134. package/dist/chunks/subprocess-transport-C2XVR25R.ts +158 -0
  135. package/dist/chunks/subprocess-transport-C2XVR25R.ts.map +7 -0
  136. package/dist/chunks/workspace-WDKLN72J.ts +11 -0
  137. package/dist/chunks/workspace-WDKLN72J.ts.map +7 -0
  138. package/dist/index.ts +1057 -0
  139. package/dist/index.ts.map +7 -0
  140. package/package.json +9 -5
  141. package/src/index.ts +1 -1
  142. package/src/settings-reader.ts +208 -0
  143. package/src/settings.ts +22 -187
  144. package/src/stateful-registration.ts +1230 -0
  145. package/src/stateful-safety.ts +1 -1
  146. package/src/stateful.ts +2 -1234
  147. package/src/subagents-extension.ts +307 -0
  148. package/src/subagents.ts +1 -308
@@ -0,0 +1,1146 @@
1
+ // @generated by scripts/build-runtime.mjs; do not edit.
2
+ // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
+ import "./chunk-SCZ33MYW.ts";
4
+ import {
5
+ formatStatefulAgentLine
6
+ } from "./chunk-F5YWVHQX.ts";
7
+ import "./chunk-P7OH4XMF.ts";
8
+ import "./chunk-N7BLVXKK.ts";
9
+ import "./chunk-ONDTY4EL.ts";
10
+ import "./chunk-O4VO6JUJ.ts";
11
+ import {
12
+ discoverAgents
13
+ } from "./chunk-PSK43Y6A.ts";
14
+ import "./chunk-RSUXZD6S.ts";
15
+ import {
16
+ applyStatefulLimitSetting,
17
+ completionLabel,
18
+ consultResourceLabel,
19
+ consultationCwdLabel,
20
+ currentWorkflow,
21
+ delegationCwdLabel,
22
+ formatDetachedLimitSummary,
23
+ formatEmptyStatefulRuntime,
24
+ formatManagerSummary,
25
+ helpLines,
26
+ showSubagentHelp,
27
+ showSubagentStatus,
28
+ showWorkflowPreview,
29
+ statefulLimitInputScreen,
30
+ statefulLimitListScreen,
31
+ statusLines,
32
+ workflowLabel
33
+ } from "./chunk-EFBPISNT.ts";
34
+ import "./chunk-KMGKCEO4.ts";
35
+ import {
36
+ sameToolSet,
37
+ uniqueToolNames,
38
+ updateAgentSettingsPatch,
39
+ updateAgentToolsSetting,
40
+ updateBlockingMaxParallelTasksSetting,
41
+ updateCompletionDeliverySetting,
42
+ updateConsultResourceSetting,
43
+ updateCwdPolicySetting,
44
+ updateDelegationWorkflowSetting,
45
+ updateStatefulTransportSetting
46
+ } from "./chunk-7QPPBBXZ.ts";
47
+ import {
48
+ hasOwn,
49
+ inspectBlockingParallelLimitSettings,
50
+ inspectCompletionDeliverySettings,
51
+ inspectConsultResourceSettings,
52
+ inspectCwdPolicySettings,
53
+ inspectDelegationWorkflowSettings,
54
+ inspectStatefulTransportSettings,
55
+ readSubagentSettings
56
+ } from "./chunk-QBORTI4W.ts";
57
+ import {
58
+ isStatefulLimitField
59
+ } from "./chunk-7OBINKFM.ts";
60
+ import "./chunk-DPPVEQAM.ts";
61
+ import "./chunk-434NII74.ts";
62
+ import "./chunk-C4L6P266.ts";
63
+ import "./chunk-QDVGH2X7.ts";
64
+ import "./chunk-BFK2Z4ZF.ts";
65
+ import {
66
+ safeTerminalLine
67
+ } from "./chunk-SWGQLFSD.ts";
68
+ import "./chunk-I2FAK44T.ts";
69
+ import {
70
+ MAX_BLOCKING_PARALLEL_CONCURRENCY,
71
+ MAX_CONFIGURABLE_PARALLEL_TASKS,
72
+ MAX_SUBAGENT_TIMEOUT_MS
73
+ } from "./chunk-H3FP6DLR.ts";
74
+ import "./chunk-RRR66UWR.ts";
75
+ import "./chunk-S2IWVK3J.ts";
76
+
77
+ // src/execution-ui.ts
78
+ function executionAgentPickerScreen(agents) {
79
+ const configured = readSubagentSettings()?.agents ?? {};
80
+ return {
81
+ kind: "actions",
82
+ title: "Agent Execution Defaults",
83
+ lines: ["Choose an agent to edit its inherited model, thinking, or timeout."],
84
+ items: [
85
+ ...agents.map((agent) => {
86
+ const value = configured[agent.name];
87
+ return {
88
+ id: agent.name,
89
+ label: safeTerminalLine(agent.name),
90
+ description: safeTerminalLine(
91
+ `${agent.source} \xB7 model ${value?.model ?? agent.model ?? "inherited"} \xB7 thinking ${value?.thinkingLevel ?? agent.thinkingLevel ?? "inherited"} \xB7 timeout ${value?.timeoutMs ?? agent.timeoutMs ?? "inherited"}`
92
+ ),
93
+ action: "pick-execution-agent"
94
+ };
95
+ }),
96
+ { id: "back", label: "Back", action: "back" }
97
+ ],
98
+ hint: "back"
99
+ };
100
+ }
101
+ function executionAgentScreen(agent) {
102
+ if (!agent) {
103
+ return {
104
+ kind: "actions",
105
+ title: "Agent Execution Defaults",
106
+ lines: ["No agent selected."],
107
+ items: [{ id: "back", label: "Back", action: "back" }],
108
+ hint: "back"
109
+ };
110
+ }
111
+ const configured = readSubagentSettings()?.agents?.[agent.name];
112
+ return {
113
+ kind: "actions",
114
+ title: `${safeTerminalLine(agent.name)} execution`,
115
+ lines: [
116
+ `Model: ${safeTerminalLine(configured?.model ?? agent.model ?? "inherited")}`,
117
+ `Thinking: ${configured?.thinkingLevel ?? agent.thinkingLevel ?? "inherited"}`,
118
+ `Timeout: ${configured?.timeoutMs ?? agent.timeoutMs ?? "inherited"}`,
119
+ "Explicit tool-call values remain authoritative."
120
+ ],
121
+ items: [
122
+ { id: "thinking", label: "Thinking level", to: "execution-thinking" },
123
+ { id: "model", label: "Model", to: "execution-model" },
124
+ { id: "timeout", label: "Timeout", to: "execution-timeout" },
125
+ {
126
+ id: "reset",
127
+ label: "Reset execution defaults",
128
+ description: "Restore frontmatter or Pi inheritance without changing tools",
129
+ action: "reset-agent-execution"
130
+ },
131
+ { id: "back", label: "Back", action: "back" }
132
+ ],
133
+ hint: "back"
134
+ };
135
+ }
136
+ function executionThinkingScreen(agent) {
137
+ const configured = agent ? readSubagentSettings()?.agents?.[agent.name] : void 0;
138
+ return {
139
+ kind: "settings",
140
+ title: agent ? `${safeTerminalLine(agent.name)} thinking` : "Agent thinking",
141
+ items: agent ? [
142
+ {
143
+ id: "thinking",
144
+ label: "Default thinking level",
145
+ description: "Explicit spawn or blocking call values still win.",
146
+ currentValue: configured?.thinkingLevel ?? agent.thinkingLevel ?? "Inherited",
147
+ values: ["Inherited", "off", "minimal", "low", "medium", "high", "xhigh", "max"],
148
+ action: "set-agent-thinking"
149
+ }
150
+ ] : [],
151
+ hint: "back"
152
+ };
153
+ }
154
+ function executionModelScreen(agent, ctx) {
155
+ const configured = agent ? readSubagentSettings()?.agents?.[agent.name] : void 0;
156
+ const models = ctx.modelRegistry.getAvailable().map((model) => `${model.provider}/${model.id}`).sort((left, right) => left.localeCompare(right)).slice(0, 100);
157
+ return {
158
+ kind: "actions",
159
+ title: agent ? `${safeTerminalLine(agent.name)} model` : "Agent model",
160
+ lines: [
161
+ `Current: ${safeTerminalLine(configured?.model ?? agent?.model ?? "inherited")}`,
162
+ "Choose a session-available model or enter a custom Pi model pattern."
163
+ ],
164
+ items: agent ? [
165
+ {
166
+ id: "model:__inherited__",
167
+ label: "Inherited",
168
+ description: "Use frontmatter or active Pi model resolution",
169
+ action: "set-agent-model"
170
+ },
171
+ ...models.map((model) => ({
172
+ id: `model:${model}`,
173
+ label: safeTerminalLine(model),
174
+ action: "set-agent-model"
175
+ })),
176
+ {
177
+ id: "custom",
178
+ label: "Custom model pattern",
179
+ description: "Enter provider/model, a model pattern, or an optional :thinking suffix",
180
+ to: "execution-model-input"
181
+ },
182
+ { id: "back", label: "Back", action: "back" }
183
+ ] : [],
184
+ hint: "back"
185
+ };
186
+ }
187
+ function executionModelInputScreen(agent) {
188
+ const configured = agent ? readSubagentSettings()?.agents?.[agent.name] : void 0;
189
+ return {
190
+ kind: "input",
191
+ title: agent ? `${safeTerminalLine(agent.name)} model` : "Agent model",
192
+ lines: [
193
+ `Current: ${safeTerminalLine(configured?.model ?? agent?.model ?? "inherited")}`,
194
+ "Enter a Pi CLI model pattern, including an optional :thinking suffix.",
195
+ "Use Reset execution defaults to restore inheritance."
196
+ ],
197
+ placeholder: "provider/model or model pattern",
198
+ action: "set-agent-model",
199
+ hint: "back"
200
+ };
201
+ }
202
+ function executionTimeoutInputScreen(agent) {
203
+ const configured = agent ? readSubagentSettings()?.agents?.[agent.name] : void 0;
204
+ return {
205
+ kind: "input",
206
+ title: agent ? `${safeTerminalLine(agent.name)} timeout` : "Agent timeout",
207
+ lines: [
208
+ `Current: ${configured?.timeoutMs ?? agent?.timeoutMs ?? "inherited"}`,
209
+ `Allowed: 1-${MAX_SUBAGENT_TIMEOUT_MS} milliseconds.`,
210
+ "Use Reset execution defaults to restore inheritance."
211
+ ],
212
+ placeholder: "Timeout in milliseconds",
213
+ action: "set-agent-timeout",
214
+ hint: "back"
215
+ };
216
+ }
217
+ function applyAgentThinking(agent, value, ctx) {
218
+ if (!agent) return { kind: "rejected" };
219
+ const thinkingLevel = value === "Inherited" ? void 0 : value;
220
+ if (thinkingLevel !== void 0 && !["off", "minimal", "low", "medium", "high", "xhigh", "max"].includes(thinkingLevel)) {
221
+ return { kind: "rejected" };
222
+ }
223
+ return saveAgentPatch(agent.name, { thinkingLevel }, ctx, "thinking level");
224
+ }
225
+ function applyAgentModel(agent, value, ctx) {
226
+ if (!agent) return { kind: "rejected" };
227
+ if (value === void 0) return saveAgentPatch(agent.name, { model: void 0 }, ctx, "model");
228
+ const model = value.trim();
229
+ if (!model || Buffer.byteLength(model, "utf8") > 1024 || hasTerminalControl(model)) {
230
+ ctx.ui.notify("Model must contain 1-1024 UTF-8 bytes on one line.", "warning");
231
+ return { kind: "rejected" };
232
+ }
233
+ return saveAgentPatch(agent.name, { model }, ctx, "model");
234
+ }
235
+ function applyAgentTimeout(agent, value, ctx) {
236
+ if (!agent) return { kind: "rejected" };
237
+ const normalized = value?.trim() ?? "";
238
+ if (!/^\d+$/u.test(normalized)) {
239
+ ctx.ui.notify("Timeout must be a whole number of milliseconds.", "warning");
240
+ return { kind: "rejected" };
241
+ }
242
+ const timeoutMs = Number(normalized);
243
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > MAX_SUBAGENT_TIMEOUT_MS) {
244
+ ctx.ui.notify(`Timeout must be between 1 and ${MAX_SUBAGENT_TIMEOUT_MS}.`, "warning");
245
+ return { kind: "rejected" };
246
+ }
247
+ return saveAgentPatch(agent.name, { timeoutMs }, ctx, "timeout");
248
+ }
249
+ function resetAgentExecution(agent, ctx) {
250
+ if (!agent) return { kind: "rejected" };
251
+ return saveAgentPatch(
252
+ agent.name,
253
+ { model: void 0, thinkingLevel: void 0, timeoutMs: void 0 },
254
+ ctx,
255
+ "execution defaults"
256
+ );
257
+ }
258
+ function saveAgentPatch(name, patch, ctx, label) {
259
+ try {
260
+ updateAgentSettingsPatch({ [name]: patch });
261
+ ctx.ui.notify(`${safeTerminalLine(name)} ${label} saved.`, "info");
262
+ return { kind: "back" };
263
+ } catch (error) {
264
+ ctx.ui.notify(
265
+ `${safeTerminalLine(name)} ${label} was not saved: ${formatError(error)}`,
266
+ "error"
267
+ );
268
+ return { kind: "rejected" };
269
+ }
270
+ }
271
+ function hasTerminalControl(value) {
272
+ return [...value].some((character) => {
273
+ const code = character.codePointAt(0) ?? 0;
274
+ return code <= 31 || code >= 127 && code <= 159;
275
+ });
276
+ }
277
+ function formatError(error) {
278
+ return safeTerminalLine(error instanceof Error ? error.message : String(error));
279
+ }
280
+
281
+ // src/parallel-limit-ui.ts
282
+ function blockingParallelLimitScreen(runtime) {
283
+ const limit = inspectBlockingParallelLimitSettings();
284
+ return {
285
+ kind: "input",
286
+ title: "Maximum Parallel Workers",
287
+ lines: [
288
+ `Current: ${runtime.getMaxParallelTasks()} worker tasks per blocking call`,
289
+ `Allowed: 1-${MAX_CONFIGURABLE_PARALLEL_TASKS}`,
290
+ `Parallel execution still starts at most ${MAX_BLOCKING_PARALLEL_CONCURRENCY} workers at once.`,
291
+ safeTerminalText(limit.path)
292
+ ],
293
+ placeholder: "Enter a whole number",
294
+ action: "set-parallel-limit",
295
+ hint: "back"
296
+ };
297
+ }
298
+ function applyBlockingParallelLimitSetting(value, ctx, runtime) {
299
+ const normalized = value?.trim() ?? "";
300
+ if (!/^\d+$/u.test(normalized)) {
301
+ notifyValidationError(ctx);
302
+ return { kind: "rejected" };
303
+ }
304
+ const next = Number(normalized);
305
+ if (!Number.isSafeInteger(next) || next < 1 || next > MAX_CONFIGURABLE_PARALLEL_TASKS) {
306
+ notifyValidationError(ctx);
307
+ return { kind: "rejected" };
308
+ }
309
+ const configured = inspectBlockingParallelLimitSettings();
310
+ if (configured.error) {
311
+ ctx.ui.notify(
312
+ `Subagent settings cannot be edited: ${safeTerminalText(configured.error)}`,
313
+ "error"
314
+ );
315
+ return { kind: "rejected" };
316
+ }
317
+ const previousRuntime = runtime.getMaxParallelTasks();
318
+ const runtimeChanged = next !== previousRuntime;
319
+ const settingsChanged = next !== configured.value;
320
+ if (!runtimeChanged && !settingsChanged) return { kind: "back" };
321
+ if (runtimeChanged) {
322
+ try {
323
+ runtime.setMaxParallelTasks(next);
324
+ } catch (error) {
325
+ ctx.ui.notify(
326
+ `Parallel-worker limit was not applied; user settings are unchanged: ${formatError2(error)}`,
327
+ "error"
328
+ );
329
+ return { kind: "rejected" };
330
+ }
331
+ }
332
+ if (settingsChanged) {
333
+ try {
334
+ updateBlockingMaxParallelTasksSetting(next);
335
+ } catch (saveError) {
336
+ if (runtimeChanged) {
337
+ try {
338
+ runtime.setMaxParallelTasks(previousRuntime);
339
+ } catch (rollbackError) {
340
+ ctx.ui.notify(
341
+ `Subagent settings were not saved, and the runtime rollback failed: ${formatError2(new AggregateError([saveError, rollbackError]))}`,
342
+ "error"
343
+ );
344
+ return { kind: "rejected" };
345
+ }
346
+ }
347
+ ctx.ui.notify(
348
+ "Subagent settings were not saved; the previous runtime limit was restored.",
349
+ "error"
350
+ );
351
+ return { kind: "rejected" };
352
+ }
353
+ }
354
+ ctx.ui.notify(
355
+ `${settingsChanged ? "Saved and " : ""}applied: maximum ${next} parallel workers per blocking call.`,
356
+ "info"
357
+ );
358
+ return { kind: "back" };
359
+ }
360
+ function notifyValidationError(ctx) {
361
+ ctx.ui.notify(
362
+ `Maximum parallel workers must be a whole number from 1 to ${MAX_CONFIGURABLE_PARALLEL_TASKS}.`,
363
+ "warning"
364
+ );
365
+ }
366
+ function safeTerminalText(value) {
367
+ return value.replace(/[\u0000-\u001f\u007f-\u009f]/gu, "?");
368
+ }
369
+ function formatError2(error) {
370
+ return safeTerminalText(error instanceof Error ? error.message : String(error));
371
+ }
372
+
373
+ // src/transport-ui.ts
374
+ var TRANSPORT_OPTIONS = [
375
+ {
376
+ value: "subprocess",
377
+ label: "Fresh subprocess",
378
+ description: "Compatibility path with a fresh isolated Pi process for every turn."
379
+ },
380
+ {
381
+ value: "in-process",
382
+ label: "In process",
383
+ description: "Lowest follow-up overhead for built-in tools, with shared memory and crash boundary."
384
+ },
385
+ {
386
+ value: "rpc",
387
+ label: "Persistent RPC process",
388
+ description: "Retain native history in one isolated Pi process per active retained agent."
389
+ },
390
+ {
391
+ value: "auto",
392
+ label: "Automatic",
393
+ description: "Read-only built-ins use in-process, write-capable built-ins use RPC, and custom tools use subprocess."
394
+ }
395
+ ];
396
+ function transportSettingsScreen(runtime) {
397
+ const configured = inspectStatefulTransportSettings();
398
+ const current = runtime.getRuntimeStatus();
399
+ return {
400
+ kind: "actions",
401
+ title: configured.error ? "Detached Transport \xB7 Read only" : "Detached Transport",
402
+ lines: [
403
+ `Current session: ${transportLabel(current.transport)}`,
404
+ `Configured after reload: ${transportLabel(configured.value)} (${configured.source})`,
405
+ "Transport isolation is not a filesystem or network sandbox.",
406
+ "RPC v1 disables child extensions and supports built-in Pi tools only.",
407
+ ...configured.error ? [
408
+ `Settings cannot be edited: ${safeTerminalLine(configured.error)}`,
409
+ `Repair ${safeTerminalLine(configured.path)} and retry.`
410
+ ] : []
411
+ ],
412
+ items: [
413
+ ...configured.error ? [] : TRANSPORT_OPTIONS.map((option) => ({
414
+ id: option.value,
415
+ label: option.label,
416
+ description: option.description,
417
+ action: "set-transport"
418
+ })),
419
+ { id: "back", label: "Back", action: "back" }
420
+ ],
421
+ hint: "back"
422
+ };
423
+ }
424
+ async function applyTransportSetting(value, ctx, runtime, signal, isCurrent) {
425
+ if (!isTransport(value)) return { kind: "rejected" };
426
+ const before = inspectStatefulTransportSettings();
427
+ if (before.error) return { kind: "rejected" };
428
+ if (value === before.value) return { kind: "stay" };
429
+ const status = runtime.getRuntimeStatus();
430
+ if (status.retainedAgents > 0) {
431
+ ctx.ui.notify(
432
+ `Cannot change transport while ${status.retainedAgents} detached agent${status.retainedAgents === 1 ? " is" : "s are"} retained. Clear Current agents first.`,
433
+ "warning"
434
+ );
435
+ return { kind: "rejected" };
436
+ }
437
+ const option = TRANSPORT_OPTIONS.find((candidate) => candidate.value === value);
438
+ const confirmed = await ctx.ui.confirm(
439
+ `Use ${transportLabel(value)} after reload?`,
440
+ `${option?.description ?? ""}
441
+
442
+ This saves the setting but does not reload Pi automatically.`,
443
+ { signal }
444
+ );
445
+ if (signal.aborted || !isCurrent()) return { kind: "close" };
446
+ if (!confirmed) return { kind: "rejected" };
447
+ const after = inspectStatefulTransportSettings();
448
+ if (after.error || after.value !== before.value || after.source !== before.source) {
449
+ ctx.ui.notify("Transport settings changed while confirming; review again.", "warning");
450
+ return { kind: "rejected" };
451
+ }
452
+ if (runtime.getRuntimeStatus().retainedAgents > 0) {
453
+ ctx.ui.notify(
454
+ "Detached agents appeared while confirming; clear them before changing transport.",
455
+ "warning"
456
+ );
457
+ return { kind: "rejected" };
458
+ }
459
+ try {
460
+ updateStatefulTransportSetting(value);
461
+ ctx.ui.notify(`Saved ${transportLabel(value)}. Run /reload when ready.`, "info");
462
+ return { kind: "stay" };
463
+ } catch (error) {
464
+ ctx.ui.notify(
465
+ `Transport was not saved; the previous setting remains: ${safeTerminalLine(error instanceof Error ? error.message : String(error))}`,
466
+ "error"
467
+ );
468
+ return { kind: "rejected" };
469
+ }
470
+ }
471
+ function responsivenessSetupScreen(runtime) {
472
+ const current = runtime.getRuntimeStatus();
473
+ const configured = inspectStatefulTransportSettings();
474
+ return {
475
+ kind: "actions",
476
+ title: "Responsiveness Setup",
477
+ lines: [
478
+ `Current transport: ${transportLabel(current.transport)}`,
479
+ `Configured transport: ${transportLabel(configured.value)}`,
480
+ "Transport, completion delivery, and thinking defaults are separate explicit choices.",
481
+ "Use Automatic to reduce retained follow-up startup while keeping custom-tool compatibility."
482
+ ],
483
+ items: [
484
+ {
485
+ id: "auto",
486
+ label: "Preview Automatic transport",
487
+ description: "Choose a deterministic transport before each retained agent starts",
488
+ action: "set-transport"
489
+ },
490
+ { id: "transport", label: "Compare all transports", to: "transport" },
491
+ {
492
+ id: "completion",
493
+ label: "Completion delivery",
494
+ description: "Choose separately whether an idle root resumes for synthesis",
495
+ to: "settings"
496
+ },
497
+ { id: "back", label: "Back", action: "back" }
498
+ ],
499
+ hint: "back"
500
+ };
501
+ }
502
+ function transportLabel(value) {
503
+ return TRANSPORT_OPTIONS.find((option) => option.value === value)?.label ?? value;
504
+ }
505
+ function isTransport(value) {
506
+ return ["subprocess", "in-process", "rpc", "auto"].includes(value);
507
+ }
508
+
509
+ // src/config-ui.ts
510
+ var SUBCOMMANDS = [
511
+ { value: "settings", label: "settings", description: "Configure subagent user settings" },
512
+ { value: "status", label: "status", description: "Show effective subagent settings" },
513
+ { value: "help", label: "help", description: "Show subagent settings help" }
514
+ ];
515
+ var TOOL_VIEWPORT_SIZE = 10;
516
+ function registerSubagentConfigLifecycle(pi) {
517
+ const owner = { generation: 0, controller: new AbortController() };
518
+ pi.on("session_start", () => {
519
+ owner.generation += 1;
520
+ owner.controller.abort(new DOMException("Subagent session replaced", "AbortError"));
521
+ owner.controller = new AbortController();
522
+ });
523
+ pi.on("session_shutdown", () => {
524
+ owner.generation += 1;
525
+ owner.controller.abort(new DOMException("Subagent session shut down", "AbortError"));
526
+ });
527
+ return owner;
528
+ }
529
+ function registerSubagentConfigCommand(pi, runtime, owner = registerSubagentConfigLifecycle(pi)) {
530
+ registerSubagentPrimaryCommand(pi, runtime, owner);
531
+ }
532
+ function registerSubagentPrimaryCommand(pi, runtime, owner) {
533
+ pi.registerCommand("subagents", {
534
+ description: "Manage current-session subagents and user settings",
535
+ getArgumentCompletions(prefix) {
536
+ const normalized = prefix.trim().toLowerCase();
537
+ const matches = SUBCOMMANDS.filter((item) => item.value.startsWith(normalized));
538
+ return matches.length > 0 ? matches : null;
539
+ },
540
+ async handler(args, ctx) {
541
+ const subcommand = args.trim().toLowerCase();
542
+ if (!subcommand) {
543
+ await showSubagentManager(pi, ctx, runtime, owner);
544
+ return;
545
+ }
546
+ switch (subcommand) {
547
+ case "settings":
548
+ await showSubagentSettings(ctx, runtime, owner);
549
+ return;
550
+ case "status":
551
+ showSubagentStatus(ctx, runtime);
552
+ return;
553
+ case "help":
554
+ showSubagentHelp(ctx, runtime);
555
+ return;
556
+ default:
557
+ if (ctx.mode === "tui" || ctx.hasUI) {
558
+ ctx.ui.notify(`Unknown /subagents subcommand: ${subcommand}`, "warning");
559
+ }
560
+ }
561
+ }
562
+ });
563
+ }
564
+ async function showSubagentManager(pi, ctx, runtime, owner) {
565
+ if (ctx.mode !== "tui") {
566
+ showSubagentStatus(ctx, runtime);
567
+ return;
568
+ }
569
+ const generation = owner.generation;
570
+ const isCurrent = () => generation === owner.generation && !owner.controller.signal.aborted;
571
+ const { defineMenu, runMenu } = await import("@narumitw/pi-tui-kit");
572
+ if (!isCurrent()) return;
573
+ let availableAgents = discoverAgents(ctx.cwd, "user", readSubagentSettings() ?? {}).agents;
574
+ let toolDraft;
575
+ let selectedExecutionAgent;
576
+ let selectedStatefulLimit = "maxAgents";
577
+ const menu = defineMenu({
578
+ start: "main",
579
+ screens: {
580
+ main: () => {
581
+ const status = runtime.getRuntimeStatus();
582
+ const workflow = inspectDelegationWorkflowSettings();
583
+ return {
584
+ kind: "actions",
585
+ title: "Subagents",
586
+ lines: formatManagerSummary(runtime, status, workflow).split("\n"),
587
+ items: [
588
+ {
589
+ id: "workflow",
590
+ label: "Change delegation",
591
+ description: "Choose async only (recommended) or a compatibility workflow",
592
+ to: "workflow"
593
+ },
594
+ {
595
+ id: "agents",
596
+ label: "Current agents",
597
+ description: `${status.activeAgents} active \xB7 ${status.retainedAgents} retained`,
598
+ to: "agents"
599
+ },
600
+ {
601
+ id: "settings",
602
+ label: "Settings",
603
+ description: "Configure targets, trusted resources, and async completion",
604
+ to: "settings"
605
+ },
606
+ {
607
+ id: "advanced",
608
+ label: "Advanced settings",
609
+ description: "Agent permissions, parallel limit, runtime details, and settings path",
610
+ to: "advanced"
611
+ },
612
+ { id: "help", label: "Help", to: "help" }
613
+ ],
614
+ hint: "close"
615
+ };
616
+ },
617
+ workflow: () => {
618
+ const snapshot = inspectDelegationWorkflowSettings();
619
+ const active = currentWorkflow(runtime, runtime.getRuntimeStatus());
620
+ return {
621
+ kind: "actions",
622
+ title: "Change Delegation",
623
+ lines: [
624
+ `Current: ${workflowLabel(active)}`,
625
+ "Recommended: Async only keeps the main agent responsive and omits blocking delegation and consultation.",
626
+ "Final-answer-dependent detached work needs automatic resume.",
627
+ ...snapshot.value !== active ? [`Configured after reload: ${workflowLabel(snapshot.value)}`] : [],
628
+ ...snapshot.error ? [
629
+ `Settings cannot be edited: ${safeTerminalLine(snapshot.error)}`,
630
+ `Repair ${safeTerminalLine(snapshot.path)} and retry.`
631
+ ] : []
632
+ ],
633
+ items: snapshot.error ? [] : [
634
+ {
635
+ id: "async-only",
636
+ label: "Async only \xB7 Recommended",
637
+ description: "Detached lifecycle plus inspection; omit blocking and consultation",
638
+ action: "set-workflow"
639
+ },
640
+ {
641
+ id: "all",
642
+ label: "All delegation methods",
643
+ description: "Compatibility: async, blocking, inspection, and consultation",
644
+ action: "set-workflow"
645
+ },
646
+ {
647
+ id: "blocking-only",
648
+ label: "Blocking only",
649
+ description: "Compatibility: blocking and consultation without async lifecycle",
650
+ action: "set-workflow"
651
+ }
652
+ ],
653
+ hint: "back"
654
+ };
655
+ },
656
+ agents: () => {
657
+ const agents = runtime.listAgents();
658
+ const status = runtime.getRuntimeStatus();
659
+ return {
660
+ kind: "actions",
661
+ title: "Current-session Subagents",
662
+ lines: agents.length ? agents.map(formatStatefulAgentLine) : [formatEmptyStatefulRuntime(status)],
663
+ items: [
664
+ ...agents.length > 0 ? [
665
+ {
666
+ id: "clear",
667
+ label: "Clear current-session agents",
668
+ description: "Close and delete retained agents for this session",
669
+ action: "clear-agents"
670
+ }
671
+ ] : [],
672
+ { id: "back", label: "Back", action: "back" }
673
+ ],
674
+ hint: "back"
675
+ };
676
+ },
677
+ settings: () => subagentSettingsScreen(runtime),
678
+ advanced: () => {
679
+ const limit = inspectBlockingParallelLimitSettings();
680
+ return {
681
+ kind: "actions",
682
+ title: "Advanced Subagent Settings",
683
+ items: [
684
+ {
685
+ id: "agent-tools",
686
+ label: "Agent tool permissions",
687
+ description: "Customize persistent per-agent tool allow-lists",
688
+ action: "load-agent-picker"
689
+ },
690
+ {
691
+ id: "status",
692
+ label: "Runtime details",
693
+ description: "Show transport, configured source, and settings path",
694
+ to: "status"
695
+ },
696
+ {
697
+ id: "parallel-limit",
698
+ label: "Maximum parallel workers",
699
+ description: `Current: ${runtime.getMaxParallelTasks()} per blocking call`,
700
+ to: "parallel-limit",
701
+ disabled: limit.error !== void 0,
702
+ disabledReason: limit.error ? `Repair ${safeTerminalLine(limit.path)} before editing this setting` : void 0
703
+ },
704
+ {
705
+ id: "stateful-limits",
706
+ label: "Detached agent limits",
707
+ description: formatDetachedLimitSummary(runtime.getRuntimeStatus()),
708
+ to: "stateful-limits"
709
+ },
710
+ {
711
+ id: "performance",
712
+ label: "Performance and execution",
713
+ description: "Transport, responsiveness, and agent defaults",
714
+ to: "performance"
715
+ },
716
+ { id: "back", label: "Back", action: "back" }
717
+ ],
718
+ hint: "back"
719
+ };
720
+ },
721
+ performance: () => ({
722
+ kind: "actions",
723
+ title: "Performance and Execution",
724
+ items: [
725
+ {
726
+ id: "responsiveness",
727
+ label: "Responsiveness setup",
728
+ description: "Preview automatic retained transport and completion guidance",
729
+ to: "responsiveness"
730
+ },
731
+ { id: "transport", label: "Detached transport", to: "transport" },
732
+ {
733
+ id: "agents",
734
+ label: "Agent execution defaults",
735
+ description: "Model, thinking level, and timeout",
736
+ to: "execution-agent-picker"
737
+ },
738
+ { id: "back", label: "Back", action: "back" }
739
+ ],
740
+ hint: "back"
741
+ }),
742
+ responsiveness: () => responsivenessSetupScreen(runtime),
743
+ transport: () => transportSettingsScreen(runtime),
744
+ "execution-agent-picker": () => executionAgentPickerScreen(availableAgents),
745
+ "execution-agent": () => executionAgentScreen(selectedExecutionAgent),
746
+ "execution-thinking": () => executionThinkingScreen(selectedExecutionAgent),
747
+ "execution-model": () => executionModelScreen(selectedExecutionAgent, ctx),
748
+ "execution-model-input": () => executionModelInputScreen(selectedExecutionAgent),
749
+ "execution-timeout": () => executionTimeoutInputScreen(selectedExecutionAgent),
750
+ "parallel-limit": () => blockingParallelLimitScreen(runtime),
751
+ "stateful-limits": () => statefulLimitListScreen(runtime),
752
+ "stateful-limit-input": () => statefulLimitInputScreen(selectedStatefulLimit, runtime),
753
+ status: () => ({
754
+ kind: "detail",
755
+ title: "Subagent runtime details",
756
+ lines: statusLines(runtime),
757
+ hint: "back"
758
+ }),
759
+ help: () => ({
760
+ kind: "detail",
761
+ title: "Subagents help",
762
+ lines: helpLines(runtime),
763
+ hint: "back"
764
+ }),
765
+ "agent-picker": () => {
766
+ const settings = readSubagentSettings() ?? {};
767
+ const configured = settings.agents ?? {};
768
+ return {
769
+ kind: "actions",
770
+ title: "Subagent Tool Configuration",
771
+ lines: ["Select an agent to configure its allowed tools."],
772
+ items: availableAgents.map((agent) => {
773
+ const override = configured[agent.name];
774
+ const hasOverride = override ? hasOwn(override, "tools") : false;
775
+ const summary = hasOverride ? override?.tools && override.tools.length > 0 ? override.tools.join(", ") : "none" : "defaults";
776
+ return {
777
+ id: agent.name,
778
+ label: safeTerminalLine(agent.name),
779
+ description: safeTerminalLine(`${agent.source} \xB7 tools: ${summary}`),
780
+ action: "pick-agent"
781
+ };
782
+ }),
783
+ hint: "back"
784
+ };
785
+ },
786
+ "tool-draft": () => ({
787
+ kind: "multiSelect",
788
+ title: toolDraft ? `${safeTerminalLine(toolDraft.agentName)} tools` : "Agent tools",
789
+ enableSearch: true,
790
+ lines: toolDraft ? [
791
+ `Source: ${safeTerminalLine(toolDraft.agentSource)}`,
792
+ "Toggle a draft, then Save changes."
793
+ ] : ["No agent selected."],
794
+ viewportSize: TOOL_VIEWPORT_SIZE,
795
+ items: toolDraft?.orderedTools.map((name) => {
796
+ const available = toolDraft?.allTools.includes(name) ?? false;
797
+ return {
798
+ id: name,
799
+ label: safeTerminalLine(name),
800
+ description: available ? "Available tool" : "Configured tool is not currently loaded",
801
+ searchText: available ? "available tool" : "configured unavailable preserved",
802
+ selected: toolDraft?.selected.has(name) ?? false,
803
+ disabled: !available,
804
+ disabledReason: available ? void 0 : "Unavailable; preserved until explicitly changed in JSON"
805
+ };
806
+ }) ?? [],
807
+ action: "toggle-tool",
808
+ actions: [
809
+ { id: "save", label: "Save changes", action: "save-tools" },
810
+ { id: "discard", label: "Discard draft", action: "discard-tools" }
811
+ ],
812
+ hint: "back",
813
+ doneLabel: "Close without saving"
814
+ })
815
+ },
816
+ actions: {
817
+ "set-workflow": async ({ itemId, signal }) => {
818
+ if (!isWorkflow(itemId)) return { kind: "rejected" };
819
+ const snapshot = inspectDelegationWorkflowSettings();
820
+ if (snapshot.error) return { kind: "rejected" };
821
+ const active = currentWorkflow(runtime, runtime.getRuntimeStatus());
822
+ if (itemId === active && itemId === snapshot.value) {
823
+ ctx.ui.notify(`Delegation already uses ${workflowLabel(itemId)}.`, "info");
824
+ return { kind: "stay" };
825
+ }
826
+ const requiresReload = itemId !== active;
827
+ if (requiresReload && blockReloadWithRetainedAgents(ctx, runtime)) {
828
+ return { kind: "rejected" };
829
+ }
830
+ if (!await showWorkflowPreview(ctx, active, itemId, requiresReload, signal)) {
831
+ return signal.aborted || !isCurrent() ? { kind: "close" } : { kind: "rejected" };
832
+ }
833
+ if (signal.aborted || !isCurrent()) return { kind: "close" };
834
+ if (requiresReload && blockReloadWithRetainedAgents(ctx, runtime)) {
835
+ return { kind: "rejected" };
836
+ }
837
+ try {
838
+ updateDelegationWorkflowSetting(itemId);
839
+ } catch (error) {
840
+ ctx.ui.notify(
841
+ `Delegation settings were not saved: ${formatError3(error)}. The current workflow is unchanged.`,
842
+ "error"
843
+ );
844
+ return { kind: "rejected" };
845
+ }
846
+ if (!requiresReload) {
847
+ ctx.ui.notify(
848
+ `Saved ${workflowLabel(itemId)}. The current tool surface already matches.`,
849
+ "info"
850
+ );
851
+ return { kind: "stay" };
852
+ }
853
+ ctx.ui.notify(
854
+ `Saved ${workflowLabel(itemId)}. Reloading subagent tools\u2026 If the tool surface does not refresh, run /reload.`,
855
+ "info"
856
+ );
857
+ await ctx.reload();
858
+ return { kind: "close" };
859
+ },
860
+ "clear-agents": async ({ signal }) => {
861
+ const agents = runtime.listAgents();
862
+ if (agents.length === 0) return { kind: "stay" };
863
+ const confirmed = await ctx.ui.confirm(
864
+ "Clear current-session subagents?",
865
+ `Close and delete ${agents.length} retained agent${agents.length === 1 ? "" : "s"}?`,
866
+ { signal }
867
+ );
868
+ if (signal.aborted || !isCurrent()) return { kind: "close" };
869
+ if (!confirmed) return { kind: "rejected" };
870
+ if (runtime.listAgents().map((agent) => agent.id).join("\0") !== agents.map((agent) => agent.id).join("\0")) {
871
+ ctx.ui.notify(
872
+ "Detached agents changed while confirming; review the list again.",
873
+ "warning"
874
+ );
875
+ return { kind: "rejected" };
876
+ }
877
+ const cleared = await runtime.clearAgents();
878
+ if (signal.aborted || !isCurrent()) return { kind: "close" };
879
+ ctx.ui.notify(
880
+ `Cleared ${cleared} current-session subagent${cleared === 1 ? "" : "s"}.`,
881
+ "info"
882
+ );
883
+ return { kind: "stay" };
884
+ },
885
+ "set-transport": async ({ itemId, signal }) => applyTransportSetting(itemId, ctx, runtime, signal, isCurrent),
886
+ "pick-execution-agent": async ({ itemId }) => {
887
+ selectedExecutionAgent = availableAgents.find((agent) => agent.name === itemId);
888
+ return selectedExecutionAgent ? { kind: "to", screen: "execution-agent" } : { kind: "rejected" };
889
+ },
890
+ "set-agent-thinking": async ({ value }) => applyAgentThinking(selectedExecutionAgent, value, ctx),
891
+ "set-agent-model": async ({ itemId, value }) => {
892
+ const selected = value ?? (itemId.startsWith("model:") ? itemId.slice(6) : void 0);
893
+ return applyAgentModel(
894
+ selectedExecutionAgent,
895
+ selected === "__inherited__" ? void 0 : selected,
896
+ ctx
897
+ );
898
+ },
899
+ "set-agent-timeout": async ({ value }) => applyAgentTimeout(selectedExecutionAgent, value, ctx),
900
+ "reset-agent-execution": async () => resetAgentExecution(selectedExecutionAgent, ctx),
901
+ "set-parallel-limit": async ({ value }) => applyBlockingParallelLimitSetting(value, ctx, runtime),
902
+ "pick-stateful-limit": async ({ itemId }) => {
903
+ if (!isStatefulLimitField(itemId)) return { kind: "rejected" };
904
+ selectedStatefulLimit = itemId;
905
+ return { kind: "to", screen: "stateful-limit-input" };
906
+ },
907
+ "set-stateful-limit": async ({ value, signal }) => applyStatefulLimitSetting(selectedStatefulLimit, value, ctx, runtime, {
908
+ signal,
909
+ isCurrent
910
+ }),
911
+ "set-completion": async ({ value }) => applyCompletionSetting(value, ctx, runtime),
912
+ "set-consult-resources": async ({ value }) => applyConsultResourceSetting(value, ctx, runtime),
913
+ "set-consultation-cwd": async ({ value }) => applyConsultationCwdSetting(value, ctx, runtime),
914
+ "set-delegation-cwd": async ({ value }) => applyDelegationCwdSetting(value, ctx, runtime),
915
+ "load-agent-picker": async () => {
916
+ availableAgents = discoverAgents(ctx.cwd, "user", readSubagentSettings() ?? {}).agents;
917
+ if (availableAgents.length === 0) {
918
+ ctx.ui.notify("No agents found", "warning");
919
+ return { kind: "rejected" };
920
+ }
921
+ return { kind: "to", screen: "agent-picker" };
922
+ },
923
+ "pick-agent": async ({ itemId }) => {
924
+ const agent = availableAgents.find((candidate) => candidate.name === itemId);
925
+ if (!agent) return { kind: "rejected" };
926
+ const settings = readSubagentSettings() ?? {};
927
+ const configured = settings.agents?.[agent.name];
928
+ const configuredTools = configured && hasOwn(configured, "tools") ? configured.tools ?? [] : void 0;
929
+ const defaults = discoverAgents(ctx.cwd, "user").agents.find(
930
+ (candidate) => candidate.name === agent.name
931
+ )?.tools;
932
+ const allTools = uniqueToolNames(pi.getAllTools().map((tool) => tool.name)).sort(
933
+ (a, b) => a.localeCompare(b)
934
+ );
935
+ const selected = uniqueToolNames(configuredTools ?? defaults ?? allTools);
936
+ const selectedSet = new Set(selected);
937
+ toolDraft = {
938
+ agentName: agent.name,
939
+ agentSource: agent.source,
940
+ allTools,
941
+ defaultTools: defaults,
942
+ orderedTools: [...selected, ...allTools.filter((name) => !selectedSet.has(name))],
943
+ selected: selectedSet
944
+ };
945
+ return { kind: "to", screen: "tool-draft" };
946
+ },
947
+ "toggle-tool": async ({ itemId, selected }) => {
948
+ if (!toolDraft?.allTools.includes(itemId)) return { kind: "rejected" };
949
+ if (selected) toolDraft.selected.add(itemId);
950
+ else toolDraft.selected.delete(itemId);
951
+ return { kind: "stay" };
952
+ },
953
+ "save-tools": async () => {
954
+ if (!toolDraft) return { kind: "rejected" };
955
+ const selected = toolDraft.orderedTools.filter((name) => toolDraft?.selected.has(name));
956
+ const restoredDefaults = toolDraft.defaultTools === void 0 ? sameToolSet(selected, toolDraft.allTools) : sameToolSet(selected, toolDraft.defaultTools);
957
+ try {
958
+ updateAgentToolsSetting(toolDraft.agentName, restoredDefaults ? void 0 : selected);
959
+ } catch (error) {
960
+ ctx.ui.notify(`Agent tool settings were not saved: ${formatError3(error)}`, "error");
961
+ return { kind: "rejected" };
962
+ }
963
+ ctx.ui.notify(
964
+ restoredDefaults ? `${safeTerminalLine(toolDraft.agentName)}: defaults restored` : `${safeTerminalLine(toolDraft.agentName)}: ${selected.length} tool${selected.length === 1 ? "" : "s"} configured`,
965
+ "info"
966
+ );
967
+ toolDraft = void 0;
968
+ return { kind: "back" };
969
+ },
970
+ "discard-tools": async () => {
971
+ toolDraft = void 0;
972
+ return { kind: "back" };
973
+ },
974
+ back: async () => ({ kind: "back" })
975
+ }
976
+ });
977
+ await runMenu(ctx, menu, {
978
+ getState: () => void 0,
979
+ signal: owner.controller.signal,
980
+ isCurrent
981
+ });
982
+ }
983
+ async function showSubagentSettings(ctx, runtime, owner) {
984
+ const snapshot = inspectConsultResourceSettings();
985
+ if (ctx.mode !== "tui") {
986
+ if (ctx.hasUI) {
987
+ ctx.ui.notify(
988
+ `User settings apply to this and future sessions. Edit settings manually: ${safeTerminalLine(snapshot.path)}`,
989
+ "info"
990
+ );
991
+ }
992
+ return;
993
+ }
994
+ const generation = owner.generation;
995
+ const isCurrent = () => generation === owner.generation && !owner.controller.signal.aborted;
996
+ const { defineMenu, runMenu } = await import("@narumitw/pi-tui-kit");
997
+ if (!isCurrent()) return;
998
+ const menu = defineMenu({
999
+ start: "settings",
1000
+ screens: { settings: () => subagentSettingsScreen(runtime) },
1001
+ actions: {
1002
+ "set-completion": async ({ value }) => applyCompletionSetting(value, ctx, runtime),
1003
+ "set-consult-resources": async ({ value }) => applyConsultResourceSetting(value, ctx, runtime),
1004
+ "set-consultation-cwd": async ({ value }) => applyConsultationCwdSetting(value, ctx, runtime),
1005
+ "set-delegation-cwd": async ({ value }) => applyDelegationCwdSetting(value, ctx, runtime)
1006
+ }
1007
+ });
1008
+ await runMenu(ctx, menu, {
1009
+ getState: () => void 0,
1010
+ signal: owner.controller.signal,
1011
+ isCurrent
1012
+ });
1013
+ }
1014
+ function subagentSettingsScreen(runtime) {
1015
+ const completion = inspectCompletionDeliverySettings();
1016
+ const consult = inspectConsultResourceSettings();
1017
+ const cwdPolicy = inspectCwdPolicySettings();
1018
+ const error = completion.error ?? consult.error ?? cwdPolicy.error;
1019
+ return {
1020
+ kind: "settings",
1021
+ title: error ? "Subagent User Settings \xB7 Read only" : "Subagent User Settings",
1022
+ lines: [
1023
+ "Applies now and to future sessions",
1024
+ "Target and trust settings control startup resources, not filesystem access or sandboxing.",
1025
+ "Manage folder trust with Pi /trust; restart Pi after changing it.",
1026
+ safeTerminalLine(consult.path),
1027
+ ...error ? [`Settings cannot be edited: ${safeTerminalLine(error)}`] : []
1028
+ ],
1029
+ items: error ? [] : [
1030
+ {
1031
+ id: "consultationCwd",
1032
+ label: "Read-only consultation target",
1033
+ description: "Untrusted external targets inherit no target/project resources; agent and package read-only prompts remain.",
1034
+ currentValue: consultationCwdLabel(runtime.getConsultationCwdPolicy()),
1035
+ values: ["Anywhere \xB7 untrusted targets inherit nothing", "Current workspace only"],
1036
+ action: "set-consultation-cwd"
1037
+ },
1038
+ {
1039
+ id: "delegationCwd",
1040
+ label: "General delegation target",
1041
+ description: "Controls starting directories, not absolute paths, shell commands, or OS permissions.",
1042
+ currentValue: delegationCwdLabel(runtime.getDelegationCwdPolicy()),
1043
+ values: [
1044
+ "Current or saved-trusted folders",
1045
+ "Current workspace only",
1046
+ "Anywhere \xB7 normal Pi permissions"
1047
+ ],
1048
+ action: "set-delegation-cwd"
1049
+ },
1050
+ {
1051
+ id: "consultResources",
1052
+ label: "Consultation resources for trusted targets",
1053
+ description: "Choose which trusted context, system, skill, and prompt resources a consultation inherits.",
1054
+ currentValue: consultResourceLabel(runtime.getConsultResourcePolicy()),
1055
+ values: ["Project context only", "No inherited resources", "All trusted resources"],
1056
+ action: "set-consult-resources"
1057
+ },
1058
+ {
1059
+ id: "completionDelivery",
1060
+ label: "When async work finishes",
1061
+ description: "Wait for your next turn, or request one synthesis turn after the root settles.",
1062
+ currentValue: completionLabel(runtime.getCompletionDelivery()),
1063
+ values: ["Wait until my next turn", "Resume automatically when finished"],
1064
+ action: "set-completion"
1065
+ }
1066
+ ]
1067
+ };
1068
+ }
1069
+ function applyCompletionSetting(value, ctx, runtime) {
1070
+ const previous = runtime.getCompletionDelivery();
1071
+ const next = value === "Resume automatically when finished" ? "auto-resume" : "next-turn";
1072
+ if (next === previous) return { kind: "stay" };
1073
+ try {
1074
+ updateCompletionDeliverySetting(next);
1075
+ runtime.setCompletionDelivery(next);
1076
+ ctx.ui.notify(`Saved and applied: ${completionLabel(next)}.`, "info");
1077
+ return { kind: "stay" };
1078
+ } catch (error) {
1079
+ ctx.ui.notify(`Subagent settings were not saved: ${formatError3(error)}`, "error");
1080
+ return { kind: "rejected" };
1081
+ }
1082
+ }
1083
+ function applyConsultResourceSetting(value, ctx, runtime) {
1084
+ const previous = runtime.getConsultResourcePolicy();
1085
+ const next = value === "No inherited resources" ? "none" : value === "All trusted resources" ? "all" : "project-context";
1086
+ if (next === previous) return { kind: "stay" };
1087
+ try {
1088
+ updateConsultResourceSetting(next);
1089
+ runtime.setConsultResourcePolicy(next);
1090
+ ctx.ui.notify(`Saved and applied: ${consultResourceLabel(next)}.`, "info");
1091
+ return { kind: "stay" };
1092
+ } catch (error) {
1093
+ ctx.ui.notify(`Subagent settings were not saved: ${formatError3(error)}`, "error");
1094
+ return { kind: "rejected" };
1095
+ }
1096
+ }
1097
+ function applyConsultationCwdSetting(value, ctx, runtime) {
1098
+ const previous = runtime.getConsultationCwdPolicy();
1099
+ const next = value === "Current workspace only" ? "current-workspace" : "anywhere";
1100
+ if (next === previous) return { kind: "stay" };
1101
+ try {
1102
+ updateCwdPolicySetting("consultation", next);
1103
+ runtime.setConsultationCwdPolicy(next);
1104
+ ctx.ui.notify(`Saved and applied: ${consultationCwdLabel(next)}.`, "info");
1105
+ return { kind: "stay" };
1106
+ } catch (error) {
1107
+ ctx.ui.notify(`Subagent settings were not saved: ${formatError3(error)}`, "error");
1108
+ return { kind: "rejected" };
1109
+ }
1110
+ }
1111
+ function applyDelegationCwdSetting(value, ctx, runtime) {
1112
+ const previous = runtime.getDelegationCwdPolicy();
1113
+ const next = value === "Current workspace only" ? "current-workspace" : value === "Anywhere \xB7 normal Pi permissions" ? "anywhere" : "trusted-targets";
1114
+ if (next === previous) return { kind: "stay" };
1115
+ try {
1116
+ updateCwdPolicySetting("delegation", next);
1117
+ runtime.setDelegationCwdPolicy(next);
1118
+ ctx.ui.notify(`Saved and applied: ${delegationCwdLabel(next)}.`, "info");
1119
+ return { kind: "stay" };
1120
+ } catch (error) {
1121
+ ctx.ui.notify(`Subagent settings were not saved: ${formatError3(error)}`, "error");
1122
+ return { kind: "rejected" };
1123
+ }
1124
+ }
1125
+ function blockReloadWithRetainedAgents(ctx, runtime) {
1126
+ const status = runtime.getRuntimeStatus();
1127
+ if (status.retainedAgents === 0) return false;
1128
+ ctx.ui.notify(
1129
+ `Cannot reload while ${status.retainedAgents} detached subagent${status.retainedAgents === 1 ? " is" : "s are"} retained (${status.activeAgents} active). Open Current agents and clear them after their work is safe to discard, then change delegation.`,
1130
+ "warning"
1131
+ );
1132
+ return true;
1133
+ }
1134
+ function isWorkflow(value) {
1135
+ return value === "all" || value === "async-only" || value === "blocking-only";
1136
+ }
1137
+ function formatError3(error) {
1138
+ return safeTerminalLine(error instanceof Error ? error.message : String(error));
1139
+ }
1140
+ export {
1141
+ registerSubagentConfigCommand,
1142
+ registerSubagentConfigLifecycle,
1143
+ showSubagentManager,
1144
+ showSubagentSettings
1145
+ };
1146
+ //# sourceMappingURL=config-ui-3IBMHTQB.ts.map