@astralyn/pi 1.4.8 → 1.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/bundle/chunks/{chunk-I2COK45I.js → chunk-6GTUUUCJ.js} +128 -128
  3. package/dist/bundle/chunks/{chunk-PU2IWWXV.js → chunk-DLVLAQEG.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-MG5XDTXV.js → chunk-LPF7HQ3S.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-FODCTZXW.js → chunk-MF3T3ETJ.js} +4 -4
  6. package/dist/bundle/chunks/{chunk-RO2VH6UZ.js → chunk-R267VV5T.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-RLNMABLM.js → chunk-RVKT7OUB.js} +1 -1
  8. package/dist/bundle/chunks/{chunk-5VIOGR76.js → chunk-UCH27AVQ.js} +1 -1
  9. package/dist/bundle/chunks/{cli-MEL7SGJD.js → cli-MBFCFGI2.js} +1 -1
  10. package/dist/bundle/chunks/{execute-4CWRNHPO.js → execute-FQKRO4XJ.js} +1 -1
  11. package/dist/bundle/chunks/{runtime-R3X67XMR.js → runtime-3RPOJS5T.js} +1 -1
  12. package/dist/bundle/chunks/{virtual-modules-BBLD7YLS.js → virtual-modules-6IJ6V2CG.js} +1 -1
  13. package/dist/bundle/cli.js +1 -1
  14. package/dist/bundle/index.js +1 -1
  15. package/dist/bundle/rpc-entry.js +1 -1
  16. package/dist/core/agent-session.d.ts +34 -0
  17. package/dist/core/agent-session.d.ts.map +1 -1
  18. package/dist/core/agent-session.js +99 -2
  19. package/dist/core/agent-session.js.map +1 -1
  20. package/dist/core/isolated-session.d.ts +7 -2
  21. package/dist/core/isolated-session.d.ts.map +1 -1
  22. package/dist/core/isolated-session.js +7 -3
  23. package/dist/core/isolated-session.js.map +1 -1
  24. package/dist/core/session-manager.d.ts +17 -1
  25. package/dist/core/session-manager.d.ts.map +1 -1
  26. package/dist/core/session-manager.js +29 -0
  27. package/dist/core/session-manager.js.map +1 -1
  28. package/dist/core/tasks/delivery.d.ts +42 -7
  29. package/dist/core/tasks/delivery.d.ts.map +1 -1
  30. package/dist/core/tasks/delivery.js +129 -15
  31. package/dist/core/tasks/delivery.js.map +1 -1
  32. package/dist/core/tasks/execution.d.ts +27 -14
  33. package/dist/core/tasks/execution.d.ts.map +1 -1
  34. package/dist/core/tasks/execution.js +90 -86
  35. package/dist/core/tasks/execution.js.map +1 -1
  36. package/dist/core/tasks/limits.d.ts +13 -1
  37. package/dist/core/tasks/limits.d.ts.map +1 -1
  38. package/dist/core/tasks/limits.js +14 -1
  39. package/dist/core/tasks/limits.js.map +1 -1
  40. package/dist/core/tasks/output.d.ts +9 -1
  41. package/dist/core/tasks/output.d.ts.map +1 -1
  42. package/dist/core/tasks/output.js +23 -10
  43. package/dist/core/tasks/output.js.map +1 -1
  44. package/dist/core/tasks/presentation.d.ts +1 -1
  45. package/dist/core/tasks/presentation.d.ts.map +1 -1
  46. package/dist/core/tasks/presentation.js +6 -4
  47. package/dist/core/tasks/presentation.js.map +1 -1
  48. package/dist/core/tasks/record.d.ts +41 -29
  49. package/dist/core/tasks/record.d.ts.map +1 -1
  50. package/dist/core/tasks/record.js +82 -37
  51. package/dist/core/tasks/record.js.map +1 -1
  52. package/dist/core/tasks/reminder.js +2 -2
  53. package/dist/core/tasks/reminder.js.map +1 -1
  54. package/dist/core/tasks/runtime.d.ts +17 -14
  55. package/dist/core/tasks/runtime.d.ts.map +1 -1
  56. package/dist/core/tasks/runtime.js +68 -116
  57. package/dist/core/tasks/runtime.js.map +1 -1
  58. package/dist/core/tasks/scheduler.d.ts +3 -1
  59. package/dist/core/tasks/scheduler.d.ts.map +1 -1
  60. package/dist/core/tasks/scheduler.js +16 -12
  61. package/dist/core/tasks/scheduler.js.map +1 -1
  62. package/dist/core/tasks/session.d.ts +24 -3
  63. package/dist/core/tasks/session.d.ts.map +1 -1
  64. package/dist/core/tasks/session.js +73 -9
  65. package/dist/core/tasks/session.js.map +1 -1
  66. package/dist/core/tasks/store.d.ts +17 -4
  67. package/dist/core/tasks/store.d.ts.map +1 -1
  68. package/dist/core/tasks/store.js +45 -48
  69. package/dist/core/tasks/store.js.map +1 -1
  70. package/dist/core/tasks/types.d.ts +72 -29
  71. package/dist/core/tasks/types.d.ts.map +1 -1
  72. package/dist/core/tasks/types.js +7 -0
  73. package/dist/core/tasks/types.js.map +1 -1
  74. package/dist/core/tasks/wait.d.ts +19 -0
  75. package/dist/core/tasks/wait.d.ts.map +1 -0
  76. package/dist/core/tasks/wait.js +45 -0
  77. package/dist/core/tasks/wait.js.map +1 -0
  78. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  79. package/dist/core/tools/shell-execution.js +2 -1
  80. package/dist/core/tools/shell-execution.js.map +1 -1
  81. package/dist/core/tools/shell-tool.d.ts.map +1 -1
  82. package/dist/core/tools/shell-tool.js +20 -13
  83. package/dist/core/tools/shell-tool.js.map +1 -1
  84. package/dist/extensions/agent/activity-lines.d.ts +10 -0
  85. package/dist/extensions/agent/activity-lines.d.ts.map +1 -0
  86. package/dist/extensions/agent/activity-lines.js +76 -0
  87. package/dist/extensions/agent/activity-lines.js.map +1 -0
  88. package/dist/extensions/agent/activity.d.ts +25 -4
  89. package/dist/extensions/agent/activity.d.ts.map +1 -1
  90. package/dist/extensions/agent/activity.js +76 -21
  91. package/dist/extensions/agent/activity.js.map +1 -1
  92. package/dist/extensions/agent/artifacts.d.ts +15 -0
  93. package/dist/extensions/agent/artifacts.d.ts.map +1 -0
  94. package/dist/extensions/agent/artifacts.js +44 -0
  95. package/dist/extensions/agent/artifacts.js.map +1 -0
  96. package/dist/extensions/agent/progress.d.ts +30 -4
  97. package/dist/extensions/agent/progress.d.ts.map +1 -1
  98. package/dist/extensions/agent/progress.js +84 -11
  99. package/dist/extensions/agent/progress.js.map +1 -1
  100. package/dist/extensions/agent/render.d.ts.map +1 -1
  101. package/dist/extensions/agent/render.js +8 -24
  102. package/dist/extensions/agent/render.js.map +1 -1
  103. package/dist/extensions/agent/report.d.ts +11 -3
  104. package/dist/extensions/agent/report.d.ts.map +1 -1
  105. package/dist/extensions/agent/report.js +32 -7
  106. package/dist/extensions/agent/report.js.map +1 -1
  107. package/dist/extensions/agent/tool.d.ts.map +1 -1
  108. package/dist/extensions/agent/tool.js +20 -5
  109. package/dist/extensions/agent/tool.js.map +1 -1
  110. package/dist/extensions/agent/types.d.ts +2 -0
  111. package/dist/extensions/agent/types.d.ts.map +1 -1
  112. package/dist/extensions/agent/types.js.map +1 -1
  113. package/dist/extensions/agent/worker.d.ts +7 -0
  114. package/dist/extensions/agent/worker.d.ts.map +1 -1
  115. package/dist/extensions/agent/worker.js +9 -3
  116. package/dist/extensions/agent/worker.js.map +1 -1
  117. package/dist/extensions/index.d.ts.map +1 -1
  118. package/dist/extensions/index.js +2 -0
  119. package/dist/extensions/index.js.map +1 -1
  120. package/dist/extensions/search/index.d.ts.map +1 -1
  121. package/dist/extensions/search/index.js +6 -7
  122. package/dist/extensions/search/index.js.map +1 -1
  123. package/dist/extensions/shell-paths/index.d.ts +8 -0
  124. package/dist/extensions/shell-paths/index.d.ts.map +1 -0
  125. package/dist/extensions/shell-paths/index.js +74 -0
  126. package/dist/extensions/shell-paths/index.js.map +1 -0
  127. package/dist/extensions/tasks/tool/actions.d.ts.map +1 -1
  128. package/dist/extensions/tasks/tool/actions.js +15 -11
  129. package/dist/extensions/tasks/tool/actions.js.map +1 -1
  130. package/dist/extensions/tasks/tool/schema.d.ts +1 -1
  131. package/dist/extensions/tasks/tool/schema.d.ts.map +1 -1
  132. package/dist/extensions/tasks/tool/schema.js +5 -5
  133. package/dist/extensions/tasks/tool/schema.js.map +1 -1
  134. package/dist/extensions/tasks/tool/types.d.ts +2 -0
  135. package/dist/extensions/tasks/tool/types.d.ts.map +1 -1
  136. package/dist/extensions/tasks/tool/types.js.map +1 -1
  137. package/dist/extensions/tasks/tool.d.ts.map +1 -1
  138. package/dist/extensions/tasks/tool.js +3 -2
  139. package/dist/extensions/tasks/tool.js.map +1 -1
  140. package/dist/extensions/tasks/ui/completion-render.d.ts.map +1 -1
  141. package/dist/extensions/tasks/ui/completion-render.js +2 -2
  142. package/dist/extensions/tasks/ui/completion-render.js.map +1 -1
  143. package/dist/extensions/tasks/ui/footer.d.ts +37 -0
  144. package/dist/extensions/tasks/ui/footer.d.ts.map +1 -0
  145. package/dist/extensions/tasks/ui/footer.js +129 -0
  146. package/dist/extensions/tasks/ui/footer.js.map +1 -0
  147. package/dist/extensions/tasks/ui/frame.d.ts +36 -0
  148. package/dist/extensions/tasks/ui/frame.d.ts.map +1 -0
  149. package/dist/extensions/tasks/ui/frame.js +33 -0
  150. package/dist/extensions/tasks/ui/frame.js.map +1 -0
  151. package/dist/extensions/tasks/ui/help.d.ts +6 -0
  152. package/dist/extensions/tasks/ui/help.d.ts.map +1 -0
  153. package/dist/extensions/tasks/ui/help.js +53 -0
  154. package/dist/extensions/tasks/ui/help.js.map +1 -0
  155. package/dist/extensions/tasks/ui/inspector.d.ts +4 -3
  156. package/dist/extensions/tasks/ui/inspector.d.ts.map +1 -1
  157. package/dist/extensions/tasks/ui/inspector.js +25 -6
  158. package/dist/extensions/tasks/ui/inspector.js.map +1 -1
  159. package/dist/extensions/tasks/ui/layout.d.ts +15 -18
  160. package/dist/extensions/tasks/ui/layout.d.ts.map +1 -1
  161. package/dist/extensions/tasks/ui/layout.js +162 -255
  162. package/dist/extensions/tasks/ui/layout.js.map +1 -1
  163. package/dist/extensions/tasks/ui/list.d.ts +3 -1
  164. package/dist/extensions/tasks/ui/list.d.ts.map +1 -1
  165. package/dist/extensions/tasks/ui/list.js +19 -14
  166. package/dist/extensions/tasks/ui/list.js.map +1 -1
  167. package/dist/extensions/tasks/ui/manager.d.ts +17 -5
  168. package/dist/extensions/tasks/ui/manager.d.ts.map +1 -1
  169. package/dist/extensions/tasks/ui/manager.js +147 -90
  170. package/dist/extensions/tasks/ui/manager.js.map +1 -1
  171. package/dist/extensions/tasks/ui/model.d.ts +32 -5
  172. package/dist/extensions/tasks/ui/model.d.ts.map +1 -1
  173. package/dist/extensions/tasks/ui/model.js +7 -7
  174. package/dist/extensions/tasks/ui/model.js.map +1 -1
  175. package/dist/extensions/tasks/ui/panes.d.ts +40 -0
  176. package/dist/extensions/tasks/ui/panes.d.ts.map +1 -0
  177. package/dist/extensions/tasks/ui/panes.js +144 -0
  178. package/dist/extensions/tasks/ui/panes.js.map +1 -0
  179. package/dist/extensions/tasks/ui/render.d.ts.map +1 -1
  180. package/dist/extensions/tasks/ui/render.js +11 -7
  181. package/dist/extensions/tasks/ui/render.js.map +1 -1
  182. package/dist/extensions/tasks/ui/viewport.d.ts +12 -4
  183. package/dist/extensions/tasks/ui/viewport.d.ts.map +1 -1
  184. package/dist/extensions/tasks/ui/viewport.js +23 -7
  185. package/dist/extensions/tasks/ui/viewport.js.map +1 -1
  186. package/dist/extensions/tasks/ui/views.d.ts +12 -6
  187. package/dist/extensions/tasks/ui/views.d.ts.map +1 -1
  188. package/dist/extensions/tasks/ui/views.js +39 -32
  189. package/dist/extensions/tasks/ui/views.js.map +1 -1
  190. package/dist/modes/interactive/chat-viewport.d.ts +5 -2
  191. package/dist/modes/interactive/chat-viewport.d.ts.map +1 -1
  192. package/dist/modes/interactive/chat-viewport.js +72 -12
  193. package/dist/modes/interactive/chat-viewport.js.map +1 -1
  194. package/dist/modes/interactive/components/session-selector.d.ts +11 -1
  195. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  196. package/dist/modes/interactive/components/session-selector.js +43 -17
  197. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  198. package/dist/modes/interactive/components/sticky-user-message.d.ts +23 -0
  199. package/dist/modes/interactive/components/sticky-user-message.d.ts.map +1 -0
  200. package/dist/modes/interactive/components/sticky-user-message.js +58 -0
  201. package/dist/modes/interactive/components/sticky-user-message.js.map +1 -0
  202. package/dist/modes/interactive/components/user-message.d.ts +9 -0
  203. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  204. package/dist/modes/interactive/components/user-message.js +51 -10
  205. package/dist/modes/interactive/components/user-message.js.map +1 -1
  206. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  207. package/dist/modes/interactive/interactive-mode.js +4 -1
  208. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  209. package/dist/modes/interactive/tool-view/chat.d.ts +3 -2
  210. package/dist/modes/interactive/tool-view/chat.d.ts.map +1 -1
  211. package/dist/modes/interactive/tool-view/chat.js +3 -3
  212. package/dist/modes/interactive/tool-view/chat.js.map +1 -1
  213. package/dist/modes/interactive/transcript-layout.d.ts +23 -0
  214. package/dist/modes/interactive/transcript-layout.d.ts.map +1 -0
  215. package/dist/modes/interactive/transcript-layout.js +29 -0
  216. package/dist/modes/interactive/transcript-layout.js.map +1 -0
  217. package/dist/modes/print-mode.d.ts.map +1 -1
  218. package/dist/modes/print-mode.js +37 -2
  219. package/dist/modes/print-mode.js.map +1 -1
  220. package/dist/modes/rpc/rpc-client.d.ts +11 -0
  221. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  222. package/dist/modes/rpc/rpc-client.js +48 -0
  223. package/dist/modes/rpc/rpc-client.js.map +1 -1
  224. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  225. package/dist/modes/rpc/rpc-mode.js +1 -0
  226. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  227. package/dist/modes/rpc/rpc-types.d.ts +2 -0
  228. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  229. package/dist/modes/rpc/rpc-types.js.map +1 -1
  230. package/docs/bundled/README.md +1 -0
  231. package/docs/bundled/extensions/agent.md +39 -7
  232. package/docs/bundled/extensions/shell-paths.md +17 -0
  233. package/docs/bundled/tasks.md +25 -21
  234. package/docs/docs.json +4 -0
  235. package/docs/extensions.md +14 -10
  236. package/docs/json.md +3 -0
  237. package/docs/rpc.md +14 -0
  238. package/docs/sdk.md +11 -1
  239. package/docs/session-format.md +10 -4
  240. package/docs/sessions.md +1 -1
  241. package/docs/usage.md +3 -1
  242. package/npm-shrinkwrap.json +2 -2
  243. package/package.json +1 -1
@@ -1,7 +1,13 @@
1
1
  import type { AgentToolResult } from "@earendil-works/pi-agent-core";
2
2
  import type { Usage } from "@earendil-works/pi-ai/compat";
3
+ import type { Theme } from "../../modes/interactive/theme/theme.ts";
3
4
  /** An executor-owned machine source: the task ID prefix, never a dispatch key for the runtime. */
4
5
  export type TaskKind = string;
6
+ /**
7
+ * Where the task actually runs. `background` exactly when its caller was released with a
8
+ * background outcome; a caller that is waiting, or was asked to leave but is still held while
9
+ * the executor prepares, is `foreground`.
10
+ */
5
11
  export type TaskMode = "foreground" | "background";
6
12
  export declare const TASK_TERMINAL_STATUSES: readonly ["completed", "partial", "failed", "cancelled", "timeout"];
7
13
  export type TaskTerminalStatus = (typeof TASK_TERMINAL_STATUSES)[number];
@@ -45,14 +51,18 @@ export interface TaskSnapshot {
45
51
  outputPath?: string;
46
52
  /** Bounded model-readable result text. */
47
53
  result?: TaskText;
48
- /** Additional human-only Output text; model-facing reads use the result instead. */
54
+ /**
55
+ * The executor's human-only view. In /tasks it replaces the result as what a person reads;
56
+ * model-facing reads always use `result`. A terminal snapshot has one only if the completion
57
+ * supplied it: the last progress display does not survive settlement.
58
+ */
49
59
  display?: TaskText;
50
60
  error?: string;
51
61
  }
52
62
  export interface TaskUpdate<T> {
53
63
  /** Model-readable progress; also forwarded to a foreground caller's onUpdate. */
54
64
  result: AgentToolResult<T>;
55
- /** Additional human-only Output text. */
65
+ /** The live human-only view while running; replaces the result in /tasks and ends at settlement. */
56
66
  display?: string;
57
67
  /** Cumulative usage so far, settled once if the execution ends without a final usage. */
58
68
  usage?: Usage;
@@ -61,7 +71,10 @@ export interface TaskCompletion<T> {
61
71
  result: AgentToolResult<T>;
62
72
  /** Defaults to completed, or cancelled when the task was already cancelled. */
63
73
  status?: TaskTerminalStatus;
64
- /** Additional human-only Output text, excluded from tasks read and completion context. */
74
+ /**
75
+ * The terminal human-only view. In /tasks it replaces the result as what a person reads; model-facing
76
+ * reads and completion context always use `result`. Without it, the terminal snapshot has no display.
77
+ */
65
78
  display?: string;
66
79
  /** Terminal diagnostic, stored independently of log slices and bounded to 4096 bytes. */
67
80
  error?: string;
@@ -73,7 +86,9 @@ export interface TaskCompletion<T> {
73
86
  export interface TaskControl<T> {
74
87
  readonly id: string;
75
88
  readonly signal: AbortSignal;
89
+ /** Actual placement: `background` only once the caller was released. */
76
90
  readonly mode: TaskMode;
91
+ /** Called once the caller is released and the mode becomes `background`. */
77
92
  onModeChange(listener: (mode: TaskMode) => void): () => void;
78
93
  /** The executor's own preflight passed; from now on the caller may be handed off to the background. */
79
94
  accept(): void;
@@ -83,6 +98,14 @@ export interface TaskControl<T> {
83
98
  /** Cancel this execution, for example when an executor policy limit is exceeded. */
84
99
  cancel(): void;
85
100
  }
101
+ /**
102
+ * Renders a live task's human Output in the Tasks panel: styled, already fitted lines of at most
103
+ * `width` columns, or `undefined` to use the default view (the published `display`, else the
104
+ * result). Called on every repaint while the task runs, so it must be cheap and synchronous.
105
+ * It lives in memory with the running task: never persisted, absent from snapshots, and dropped
106
+ * at settlement. The returned text is trusted extension output, not task text.
107
+ */
108
+ export type TaskPresenter = (width: number, theme: Theme) => string[] | undefined;
86
109
  export interface TaskExecution<T> {
87
110
  kind: TaskKind;
88
111
  /** Human source name; defaults to `kind`. */
@@ -95,8 +118,9 @@ export interface TaskExecution<T> {
95
118
  toolCallId: string;
96
119
  background?: boolean;
97
120
  /**
98
- * At most `limit` executions sharing `key` run at once. Later ones wait as queued tasks
99
- * whose `run` starts when a slot frees; a queued task can be handed off or cancelled.
121
+ * At most `limit` executions sharing `key` run at once; lanes belong to one `kind`, so another
122
+ * executor may reuse the key. Later ones wait as queued tasks whose `run` starts when a slot
123
+ * frees; a queued task can be handed off or cancelled.
100
124
  */
101
125
  concurrency?: {
102
126
  key: string;
@@ -104,8 +128,14 @@ export interface TaskExecution<T> {
104
128
  };
105
129
  signal?: AbortSignal;
106
130
  onUpdate?: (result: AgentToolResult<T>) => void;
131
+ /** Renders the running task's Output in /tasks; see {@link TaskPresenter}. Dropped at settlement. */
132
+ present?: TaskPresenter;
107
133
  run(control: TaskControl<T>): Promise<TaskCompletion<T>>;
108
134
  }
135
+ /**
136
+ * How a tool call ends. A `background` outcome says why the caller was released: `submitted`
137
+ * when it asked for background, `detached` when it was moved while the work ran.
138
+ */
109
139
  export type TaskToolOutcome<T> = {
110
140
  kind: "result";
111
141
  result: AgentToolResult<T>;
@@ -114,14 +144,21 @@ export type TaskToolOutcome<T> = {
114
144
  } | {
115
145
  kind: "background";
116
146
  task: TaskSnapshot;
147
+ reason: "submitted" | "detached";
117
148
  };
118
- /** Which slice of a task's output to read. Defaults to the last 8 KiB. */
149
+ /** Which slice of a task's output to read. Defaults to 8 KiB. */
119
150
  export interface TaskReadOptions {
120
- /** `tail` (default) reads the end of the output, `head` its start. */
151
+ /**
152
+ * `head` reads the start of the output, `tail` its end. Without it a `report` is read from its
153
+ * start and a `log` from its end.
154
+ */
121
155
  mode?: "head" | "tail";
122
156
  /** Maximum bytes to return, bounded by the runtime. */
123
157
  bytes?: number;
124
- /** Only output written after this byte offset; takes precedence over `mode`. */
158
+ /**
159
+ * First unread byte. `head` reads forward from this offset; `tail` returns the newest window
160
+ * at or after it. Without it the output kind selects the default end.
161
+ */
125
162
  sinceBytes?: number;
126
163
  }
127
164
  export interface TaskRead {
@@ -132,6 +169,8 @@ export interface TaskRead {
132
169
  totalBytes: number;
133
170
  truncated: boolean;
134
171
  fromByte?: number;
172
+ /** Raw source-byte end supplied by the runtime; older/custom hosts may omit it. */
173
+ endByte?: number;
135
174
  }
136
175
  /** Optional host integration for products built on the execution runtime. */
137
176
  export interface TasksSessionContext {
@@ -184,32 +223,17 @@ export interface TaskWaitAnyResult {
184
223
  export interface TaskWaitHost {
185
224
  /** Current steering signal. Aborting it ends management waits only, never execution. */
186
225
  readonly interruptSignal: AbortSignal;
226
+ /**
227
+ * Keep `taskIds` out of automatic delivery until the returned release runs. The runtime holds
228
+ * the observed records for the whole observation: before waiting, until after `bind`.
229
+ */
230
+ hold(taskIds: readonly string[]): () => void;
187
231
  /**
188
232
  * A wait observed a settled background task and its `toolCallId` is known. Called while the
189
- * runtime still holds delivery; the host takes over until that tool result persists.
233
+ * observation hold is still in place; the host takes over until that tool result persists.
190
234
  */
191
235
  bind(toolCallId: string, taskId: string): void;
192
236
  }
193
- /**
194
- * What TaskDelivery consumes from the runtime. The runtime keeps only the per-record facts that
195
- * retention and admission need (a settled handoff is undelivered, claimed or delivered, and a
196
- * record under a hold is never a candidate); pausing, failure tracking, the in-flight delivery
197
- * and wait receipts belong to TaskDelivery.
198
- */
199
- export interface TaskDeliveryLedger {
200
- readonly enabled: boolean;
201
- list(): TaskSnapshot[];
202
- /** Settled handoffs eligible for automatic delivery: visible, unclaimed, unobserved and unheld. */
203
- pendingNotifications(): TaskSnapshot[];
204
- /** Take a pending notification; false when it is no longer a candidate. */
205
- claimNotification(id: string): boolean;
206
- /** Return a claimed notification to pending after a failed delivery. */
207
- releaseNotification(id: string): void;
208
- /** Acknowledge a persisted delivery or wait result. */
209
- markDelivered(id: string): void;
210
- /** Keep a record out of automatic delivery, and its output retained, until released. */
211
- holdDelivery(id: string): () => void;
212
- }
213
237
  /** Session-bound public capability. Captured instances close on runtime replacement. */
214
238
  export interface TasksContext {
215
239
  readonly enabled: boolean;
@@ -220,6 +244,11 @@ export interface TasksContext {
220
244
  list(): TaskSnapshot[];
221
245
  get(id: string): TaskSnapshot;
222
246
  read(id: string, options?: TaskReadOptions): Promise<TaskRead>;
247
+ /**
248
+ * The running task's live Output from its executor's `present`, or `undefined` for an unknown,
249
+ * settled or presenter-less task, or when the presenter throws; callers then use the default view.
250
+ */
251
+ presentOutput(id: string, width: number, theme: Theme): string[] | undefined;
223
252
  /**
224
253
  * Observe one task. With `toolCallId` in a session host, the whole observation (wait, read,
225
254
  * receipt) is atomic with respect to automatic delivery; a standalone runtime never
@@ -262,7 +291,21 @@ export interface TaskRuntimeOptions {
262
291
  onCleanupError?: (message: string) => void;
263
292
  /** Synchronous persistence before terminal observers or notifications. */
264
293
  onSettled?: (task: TaskSnapshot, usage: Usage | undefined) => void;
294
+ /**
295
+ * Whether the host can supervise new background work, such as its management tool being
296
+ * active. Gates admission and detaching only; work already admitted is unaffected.
297
+ */
298
+ canManageBackground?: () => boolean;
299
+ /** The runtime closed: a host holding retention pins for it must release them so output cleanup runs. */
300
+ onClosed?: () => void;
265
301
  }
302
+ /**
303
+ * The model-facing management tool, owned by the bundled `builtin:tasks` extension. Background
304
+ * work is admitted only while it is active, so the model can always read, wait for and stop what
305
+ * it starts. Model-facing copy names it through this constant.
306
+ */
307
+ export declare const TASKS_TOOL_NAME = "tasks";
308
+ export declare const TASK_MANAGEMENT_REJECTION = "Background execution needs the tasks tool to read, wait for and stop the work, and it is not active. Activate the tasks tool or run in the foreground. No work was started.";
266
309
  export declare const TASK_BACKGROUND_REJECTION = "Background execution is not permitted in this host. Run with background: false or omit background. No work was started.";
267
310
  export declare function isTaskTerminal(status: TaskStatus): status is TaskTerminalStatus;
268
311
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/types.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,12 @@
1
1
  export const TASK_TERMINAL_STATUSES = ["completed", "partial", "failed", "cancelled", "timeout"];
2
2
  export const TASK_KIND_PATTERN = /^[a-z][a-z0-9-]{0,63}$/;
3
+ /**
4
+ * The model-facing management tool, owned by the bundled `builtin:tasks` extension. Background
5
+ * work is admitted only while it is active, so the model can always read, wait for and stop what
6
+ * it starts. Model-facing copy names it through this constant.
7
+ */
8
+ export const TASKS_TOOL_NAME = "tasks";
9
+ export const TASK_MANAGEMENT_REJECTION = `Background execution needs the ${TASKS_TOOL_NAME} tool to read, wait for and stop the work, and it is not active. Activate the ${TASKS_TOOL_NAME} tool or run in the foreground. No work was started.`;
3
10
  export const TASK_BACKGROUND_REJECTION = "Background execution is not permitted in this host. Run with background: false or omit background. No work was started.";
4
11
  export function isTaskTerminal(status) {
5
12
  return TASK_TERMINAL_STATUSES.includes(status);
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/tasks/types.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,CAAU,CAAC;AAG1G,MAAM,CAAC,MAAM,iBAAiB,GAAG,wBAAwB,CAAC;AAgR1D,MAAM,CAAC,MAAM,yBAAyB,GACrC,yHAAyH,CAAC;AAE3H,MAAM,UAAU,cAAc,CAAC,MAAkB;IAChD,OAAQ,sBAA4C,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACvE,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAGzC,YAAY,IAA6B,EAAE,OAAuB;QACjE,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;CACD","sourcesContent":["import type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport type { Usage } from \"@earendil-works/pi-ai/compat\";\n\n/** An executor-owned machine source: the task ID prefix, never a dispatch key for the runtime. */\nexport type TaskKind = string;\nexport type TaskMode = \"foreground\" | \"background\";\nexport const TASK_TERMINAL_STATUSES = [\"completed\", \"partial\", \"failed\", \"cancelled\", \"timeout\"] as const;\nexport type TaskTerminalStatus = (typeof TASK_TERMINAL_STATUSES)[number];\nexport type TaskStatus = \"queued\" | \"running\" | \"stopping\" | TaskTerminalStatus;\nexport const TASK_KIND_PATTERN = /^[a-z][a-z0-9-]{0,63}$/;\n\n/**\n * How a task's output is shaped, declared by its executor:\n * a `log` streams and carries its outcome at the end; a `report` is one finished document.\n */\nexport type TaskOutputKind = \"log\" | \"report\";\n\n/** A bounded snapshot; truncation is recorded at the source, never inferred from text. */\nexport interface TaskText {\n\ttext: string;\n\ttruncated: boolean;\n}\n\n/** What the task was asked to do, such as a shell command or a delegated briefing. */\nexport interface TaskInput extends TaskText {\n\t/** Human label for the input, such as \"Command\" or \"Prompt\". */\n\tlabel: string;\n\t/** Optional syntax-highlighting language. */\n\tlanguage?: string;\n}\n\n/** One labelled Details row, such as [\"Directory\", \"/repo\"] or [\"Exit\", \"1\"]. */\nexport type TaskFact = readonly [label: string, value: string];\n\n/** A read-only view of one task; the runtime returns frozen snapshots. */\nexport interface TaskSnapshot {\n\tid: string;\n\tkind: TaskKind;\n\t/** Human source name, such as \"Bash\" or \"Agent\". */\n\tlabel: string;\n\ttitle: string;\n\toutput: TaskOutputKind;\n\tinput?: TaskInput;\n\tfacts?: TaskFact[];\n\ttoolCallId: string;\n\tanchorId: string | null;\n\tmode: TaskMode;\n\tstatus: TaskStatus;\n\tstartedAt: number;\n\tendedAt?: number;\n\toutputPath?: string;\n\t/** Bounded model-readable result text. */\n\tresult?: TaskText;\n\t/** Additional human-only Output text; model-facing reads use the result instead. */\n\tdisplay?: TaskText;\n\terror?: string;\n}\n\nexport interface TaskUpdate<T> {\n\t/** Model-readable progress; also forwarded to a foreground caller's onUpdate. */\n\tresult: AgentToolResult<T>;\n\t/** Additional human-only Output text. */\n\tdisplay?: string;\n\t/** Cumulative usage so far, settled once if the execution ends without a final usage. */\n\tusage?: Usage;\n}\n\nexport interface TaskCompletion<T> {\n\tresult: AgentToolResult<T>;\n\t/** Defaults to completed, or cancelled when the task was already cancelled. */\n\tstatus?: TaskTerminalStatus;\n\t/** Additional human-only Output text, excluded from tasks read and completion context. */\n\tdisplay?: string;\n\t/** Terminal diagnostic, stored independently of log slices and bounded to 4096 bytes. */\n\terror?: string;\n\t/** Terminal Details rows; a label replaces the same label given at launch. */\n\tfacts?: TaskFact[];\n\t/** Authoritative cumulative usage; overrides the result's usage and the latest published usage. */\n\tusage?: Usage;\n}\n\nexport interface TaskControl<T> {\n\treadonly id: string;\n\treadonly signal: AbortSignal;\n\treadonly mode: TaskMode;\n\tonModeChange(listener: (mode: TaskMode) => void): () => void;\n\t/** The executor's own preflight passed; from now on the caller may be handed off to the background. */\n\taccept(): void;\n\tpublish(update: TaskUpdate<T>): void;\n\t/** Register once; cleanup must own only this exclusively-created file and close its writer first. */\n\tattachOutput(path: string, cleanup?: () => void | Promise<void>): void;\n\t/** Cancel this execution, for example when an executor policy limit is exceeded. */\n\tcancel(): void;\n}\n\nexport interface TaskExecution<T> {\n\tkind: TaskKind;\n\t/** Human source name; defaults to `kind`. */\n\tlabel?: string;\n\ttitle: string;\n\t/** Defaults to `log`. */\n\toutput?: TaskOutputKind;\n\tinput?: TaskInput;\n\tfacts?: TaskFact[];\n\ttoolCallId: string;\n\tbackground?: boolean;\n\t/**\n\t * At most `limit` executions sharing `key` run at once. Later ones wait as queued tasks\n\t * whose `run` starts when a slot frees; a queued task can be handed off or cancelled.\n\t */\n\tconcurrency?: { key: string; limit: number };\n\tsignal?: AbortSignal;\n\tonUpdate?: (result: AgentToolResult<T>) => void;\n\trun(control: TaskControl<T>): Promise<TaskCompletion<T>>;\n}\n\nexport type TaskToolOutcome<T> =\n\t| { kind: \"result\"; result: AgentToolResult<T>; status: TaskTerminalStatus; error?: string }\n\t| { kind: \"background\"; task: TaskSnapshot };\n\n/** Which slice of a task's output to read. Defaults to the last 8 KiB. */\nexport interface TaskReadOptions {\n\t/** `tail` (default) reads the end of the output, `head` its start. */\n\tmode?: \"head\" | \"tail\";\n\t/** Maximum bytes to return, bounded by the runtime. */\n\tbytes?: number;\n\t/** Only output written after this byte offset; takes precedence over `mode`. */\n\tsinceBytes?: number;\n}\n\nexport interface TaskRead {\n\ttask: TaskSnapshot;\n\ttext: string;\n\t/** Bounded log-read/expiry diagnostic, independent of text slicing and byte offsets. */\n\treadError?: string;\n\ttotalBytes: number;\n\ttruncated: boolean;\n\tfromByte?: number;\n}\n\n/** Optional host integration for products built on the execution runtime. */\nexport interface TasksSessionContext {\n\t/** Running tasks that navigating to `targetId` would cancel on this session branch. */\n\tstoppedByTreeNavigation(targetId: string): TaskSnapshot[];\n}\n\n/** How a wait ended. `closed` means the host shut down, so execution state is unconfirmed. */\nexport type TaskWaitOutcome = \"settled\" | \"interrupted\" | \"timed_out\" | \"closed\";\n\ninterface TaskObservationOptions {\n\t/** Defaults to 20 seconds and is bounded by the runtime. A timeout never cancels execution. */\n\ttimeoutMs?: number;\n\t/** Rejects the wait with the signal's reason; execution continues. */\n\tsignal?: AbortSignal;\n\t/**\n\t * The tool call whose result carries this observation to the model. With a session host, a\n\t * settled background task stays out of automatic notifications until that result is persisted.\n\t * Without it, or in a standalone runtime, the wait is purely observational.\n\t */\n\ttoolCallId?: string;\n}\n\nexport interface TaskWaitOptions extends TaskObservationOptions {\n\t/** Read output while delivery is still held; skipped when steering interrupted the wait. */\n\tread?: Pick<TaskReadOptions, \"bytes\" | \"sinceBytes\">;\n}\n\nexport interface TaskWaitResult {\n\toutcome: TaskWaitOutcome;\n\twaitedMs: number;\n\t/** The task when the wait ended, before `read` was taken. */\n\ttask: TaskSnapshot;\n\tread?: TaskRead;\n}\n\nexport interface TaskWaitAnyOptions extends TaskObservationOptions {\n\t/** Read the settled task's output while delivery is still held. */\n\tread?: Pick<TaskReadOptions, \"bytes\">;\n}\n\nexport interface TaskWaitAnyResult {\n\t/** `no_tasks`: no background task was running at call time, so nothing was observed. */\n\toutcome: TaskWaitOutcome | \"no_tasks\";\n\twaitedMs: number;\n\t/** The first cohort member to settle; present only for `settled`. */\n\ttask?: TaskSnapshot;\n\tread?: TaskRead;\n\t/** Cohort members still running when the wait ended. */\n\trunning: TaskSnapshot[];\n}\n\n/**\n * Host hooks that make waits part of a durable session. TaskSession supplies them; products\n * embedding a bare TaskRuntime omit them and keep waits observational.\n */\nexport interface TaskWaitHost {\n\t/** Current steering signal. Aborting it ends management waits only, never execution. */\n\treadonly interruptSignal: AbortSignal;\n\t/**\n\t * A wait observed a settled background task and its `toolCallId` is known. Called while the\n\t * runtime still holds delivery; the host takes over until that tool result persists.\n\t */\n\tbind(toolCallId: string, taskId: string): void;\n}\n\n/**\n * What TaskDelivery consumes from the runtime. The runtime keeps only the per-record facts that\n * retention and admission need (a settled handoff is undelivered, claimed or delivered, and a\n * record under a hold is never a candidate); pausing, failure tracking, the in-flight delivery\n * and wait receipts belong to TaskDelivery.\n */\nexport interface TaskDeliveryLedger {\n\treadonly enabled: boolean;\n\tlist(): TaskSnapshot[];\n\t/** Settled handoffs eligible for automatic delivery: visible, unclaimed, unobserved and unheld. */\n\tpendingNotifications(): TaskSnapshot[];\n\t/** Take a pending notification; false when it is no longer a candidate. */\n\tclaimNotification(id: string): boolean;\n\t/** Return a claimed notification to pending after a failed delivery. */\n\treleaseNotification(id: string): void;\n\t/** Acknowledge a persisted delivery or wait result. */\n\tmarkDelivered(id: string): void;\n\t/** Keep a record out of automatic delivery, and its output retained, until released. */\n\tholdDelivery(id: string): () => void;\n}\n\n/** Session-bound public capability. Captured instances close on runtime replacement. */\nexport interface TasksContext {\n\treadonly enabled: boolean;\n\treadonly closed?: boolean;\n\t/** Present when the runtime is attached to Pi's durable session lifecycle. */\n\treadonly session?: TasksSessionContext;\n\texecute<T>(execution: TaskExecution<T>): Promise<TaskToolOutcome<T>>;\n\tlist(): TaskSnapshot[];\n\tget(id: string): TaskSnapshot;\n\tread(id: string, options?: TaskReadOptions): Promise<TaskRead>;\n\t/**\n\t * Observe one task. With `toolCallId` in a session host, the whole observation (wait, read,\n\t * receipt) is atomic with respect to automatic delivery; a standalone runtime never\n\t * acknowledges delivery. Rejects with `TaskLookupError` for an unknown or ambiguous id.\n\t */\n\twait(id: string, options?: TaskWaitOptions): Promise<TaskWaitResult>;\n\t/**\n\t * Observe the first task running at call time to settle. Tasks started later are excluded,\n\t * and `no_tasks` is returned for an empty cohort. Delivery holds cover the whole cohort until\n\t * the observation completes; members other than the winner then resume ordinary notification.\n\t */\n\twaitAny(options?: TaskWaitAnyOptions): Promise<TaskWaitAnyResult>;\n\tkill(id: string): boolean;\n\t/**\n\t * Move running foreground executions to the background while background slots remain;\n\t * returns how many moved. Throws when eligible work exists but every slot is taken.\n\t */\n\tdetachForeground(): number;\n\t/** Whether this execution can move now, including host policy and available background slots. */\n\tcanDetach(id: string): boolean;\n\t/** Returns false when the task cannot move; throws when every background slot is taken. */\n\tdetach(id: string): boolean;\n\tsubscribe(listener: () => void): () => void;\n\t/** Keep retained output available without delaying completion delivery. */\n\tretain(id: string): () => void;\n}\n\nexport interface TaskRuntimeOptions {\n\tenabled?: boolean;\n\tbackgroundAllowed?: boolean;\n\t/** Branch-impact queries for a durable host; standalone runtimes omit it. */\n\tsession?: TasksSessionContext;\n\t/** Wait receipts and steering interruption for a durable host; standalone runtimes leave waits observational. */\n\twaits?: TaskWaitHost;\n\tanchor?: () => string | null;\n\t/** Admission limit for unsettled background tasks; foreground work is bounded by its caller. */\n\tmaxBackground?: number;\n\t/** Per-history limit: foreground and background tasks each get this allowance. */\n\tmaxHistory?: number;\n\t/** Best-effort cleanup errors, bounded to 4096 bytes; no retries or execution failure. */\n\tonCleanupError?: (message: string) => void;\n\t/** Synchronous persistence before terminal observers or notifications. */\n\tonSettled?: (task: TaskSnapshot, usage: Usage | undefined) => void;\n}\n\nexport const TASK_BACKGROUND_REJECTION =\n\t\"Background execution is not permitted in this host. Run with background: false or omit background. No work was started.\";\n\nexport function isTaskTerminal(status: TaskStatus): status is TaskTerminalStatus {\n\treturn (TASK_TERMINAL_STATUSES as readonly string[]).includes(status);\n}\n\n/**\n * A failed id lookup, typed so hosts can enrich the message without matching\n * on message text. `matches` snapshots exactly the records the id or prefix\n * resolved against — including records outside the current branch, which\n * list() hides but prefix matching still collides with.\n */\nexport class TaskLookupError extends Error {\n\treadonly kind: \"unknown\" | \"ambiguous\";\n\treadonly matches: TaskSnapshot[];\n\tconstructor(kind: \"unknown\" | \"ambiguous\", matches: TaskSnapshot[]) {\n\t\tsuper(kind === \"ambiguous\" ? \"Ambiguous task ID\" : \"Unknown task ID\");\n\t\tthis.name = \"TaskLookupError\";\n\t\tthis.kind = kind;\n\t\tthis.matches = matches;\n\t}\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/tasks/types.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,CAAU,CAAC;AAG1G,MAAM,CAAC,MAAM,iBAAiB,GAAG,wBAAwB,CAAC;AA6S1D;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AAEvC,MAAM,CAAC,MAAM,yBAAyB,GAAG,kCAAkC,eAAe,iFAAiF,eAAe,sDAAsD,CAAC;AAEjP,MAAM,CAAC,MAAM,yBAAyB,GACrC,yHAAyH,CAAC;AAE3H,MAAM,UAAU,cAAc,CAAC,MAAkB;IAChD,OAAQ,sBAA4C,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACvE,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAGzC,YAAY,IAA6B,EAAE,OAAuB;QACjE,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;CACD","sourcesContent":["import type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport type { Usage } from \"@earendil-works/pi-ai/compat\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\n\n/** An executor-owned machine source: the task ID prefix, never a dispatch key for the runtime. */\nexport type TaskKind = string;\n/**\n * Where the task actually runs. `background` exactly when its caller was released with a\n * background outcome; a caller that is waiting, or was asked to leave but is still held while\n * the executor prepares, is `foreground`.\n */\nexport type TaskMode = \"foreground\" | \"background\";\nexport const TASK_TERMINAL_STATUSES = [\"completed\", \"partial\", \"failed\", \"cancelled\", \"timeout\"] as const;\nexport type TaskTerminalStatus = (typeof TASK_TERMINAL_STATUSES)[number];\nexport type TaskStatus = \"queued\" | \"running\" | \"stopping\" | TaskTerminalStatus;\nexport const TASK_KIND_PATTERN = /^[a-z][a-z0-9-]{0,63}$/;\n\n/**\n * How a task's output is shaped, declared by its executor:\n * a `log` streams and carries its outcome at the end; a `report` is one finished document.\n */\nexport type TaskOutputKind = \"log\" | \"report\";\n\n/** A bounded snapshot; truncation is recorded at the source, never inferred from text. */\nexport interface TaskText {\n\ttext: string;\n\ttruncated: boolean;\n}\n\n/** What the task was asked to do, such as a shell command or a delegated briefing. */\nexport interface TaskInput extends TaskText {\n\t/** Human label for the input, such as \"Command\" or \"Prompt\". */\n\tlabel: string;\n\t/** Optional syntax-highlighting language. */\n\tlanguage?: string;\n}\n\n/** One labelled Details row, such as [\"Directory\", \"/repo\"] or [\"Exit\", \"1\"]. */\nexport type TaskFact = readonly [label: string, value: string];\n\n/** A read-only view of one task; the runtime returns frozen snapshots. */\nexport interface TaskSnapshot {\n\tid: string;\n\tkind: TaskKind;\n\t/** Human source name, such as \"Bash\" or \"Agent\". */\n\tlabel: string;\n\ttitle: string;\n\toutput: TaskOutputKind;\n\tinput?: TaskInput;\n\tfacts?: TaskFact[];\n\ttoolCallId: string;\n\tanchorId: string | null;\n\tmode: TaskMode;\n\tstatus: TaskStatus;\n\tstartedAt: number;\n\tendedAt?: number;\n\toutputPath?: string;\n\t/** Bounded model-readable result text. */\n\tresult?: TaskText;\n\t/**\n\t * The executor's human-only view. In /tasks it replaces the result as what a person reads;\n\t * model-facing reads always use `result`. A terminal snapshot has one only if the completion\n\t * supplied it: the last progress display does not survive settlement.\n\t */\n\tdisplay?: TaskText;\n\terror?: string;\n}\n\nexport interface TaskUpdate<T> {\n\t/** Model-readable progress; also forwarded to a foreground caller's onUpdate. */\n\tresult: AgentToolResult<T>;\n\t/** The live human-only view while running; replaces the result in /tasks and ends at settlement. */\n\tdisplay?: string;\n\t/** Cumulative usage so far, settled once if the execution ends without a final usage. */\n\tusage?: Usage;\n}\n\nexport interface TaskCompletion<T> {\n\tresult: AgentToolResult<T>;\n\t/** Defaults to completed, or cancelled when the task was already cancelled. */\n\tstatus?: TaskTerminalStatus;\n\t/**\n\t * The terminal human-only view. In /tasks it replaces the result as what a person reads; model-facing\n\t * reads and completion context always use `result`. Without it, the terminal snapshot has no display.\n\t */\n\tdisplay?: string;\n\t/** Terminal diagnostic, stored independently of log slices and bounded to 4096 bytes. */\n\terror?: string;\n\t/** Terminal Details rows; a label replaces the same label given at launch. */\n\tfacts?: TaskFact[];\n\t/** Authoritative cumulative usage; overrides the result's usage and the latest published usage. */\n\tusage?: Usage;\n}\n\nexport interface TaskControl<T> {\n\treadonly id: string;\n\treadonly signal: AbortSignal;\n\t/** Actual placement: `background` only once the caller was released. */\n\treadonly mode: TaskMode;\n\t/** Called once the caller is released and the mode becomes `background`. */\n\tonModeChange(listener: (mode: TaskMode) => void): () => void;\n\t/** The executor's own preflight passed; from now on the caller may be handed off to the background. */\n\taccept(): void;\n\tpublish(update: TaskUpdate<T>): void;\n\t/** Register once; cleanup must own only this exclusively-created file and close its writer first. */\n\tattachOutput(path: string, cleanup?: () => void | Promise<void>): void;\n\t/** Cancel this execution, for example when an executor policy limit is exceeded. */\n\tcancel(): void;\n}\n\n/**\n * Renders a live task's human Output in the Tasks panel: styled, already fitted lines of at most\n * `width` columns, or `undefined` to use the default view (the published `display`, else the\n * result). Called on every repaint while the task runs, so it must be cheap and synchronous.\n * It lives in memory with the running task: never persisted, absent from snapshots, and dropped\n * at settlement. The returned text is trusted extension output, not task text.\n */\nexport type TaskPresenter = (width: number, theme: Theme) => string[] | undefined;\n\nexport interface TaskExecution<T> {\n\tkind: TaskKind;\n\t/** Human source name; defaults to `kind`. */\n\tlabel?: string;\n\ttitle: string;\n\t/** Defaults to `log`. */\n\toutput?: TaskOutputKind;\n\tinput?: TaskInput;\n\tfacts?: TaskFact[];\n\ttoolCallId: string;\n\tbackground?: boolean;\n\t/**\n\t * At most `limit` executions sharing `key` run at once; lanes belong to one `kind`, so another\n\t * executor may reuse the key. Later ones wait as queued tasks whose `run` starts when a slot\n\t * frees; a queued task can be handed off or cancelled.\n\t */\n\tconcurrency?: { key: string; limit: number };\n\tsignal?: AbortSignal;\n\tonUpdate?: (result: AgentToolResult<T>) => void;\n\t/** Renders the running task's Output in /tasks; see {@link TaskPresenter}. Dropped at settlement. */\n\tpresent?: TaskPresenter;\n\trun(control: TaskControl<T>): Promise<TaskCompletion<T>>;\n}\n\n/**\n * How a tool call ends. A `background` outcome says why the caller was released: `submitted`\n * when it asked for background, `detached` when it was moved while the work ran.\n */\nexport type TaskToolOutcome<T> =\n\t| { kind: \"result\"; result: AgentToolResult<T>; status: TaskTerminalStatus; error?: string }\n\t| { kind: \"background\"; task: TaskSnapshot; reason: \"submitted\" | \"detached\" };\n\n/** Which slice of a task's output to read. Defaults to 8 KiB. */\nexport interface TaskReadOptions {\n\t/**\n\t * `head` reads the start of the output, `tail` its end. Without it a `report` is read from its\n\t * start and a `log` from its end.\n\t */\n\tmode?: \"head\" | \"tail\";\n\t/** Maximum bytes to return, bounded by the runtime. */\n\tbytes?: number;\n\t/**\n\t * First unread byte. `head` reads forward from this offset; `tail` returns the newest window\n\t * at or after it. Without it the output kind selects the default end.\n\t */\n\tsinceBytes?: number;\n}\n\nexport interface TaskRead {\n\ttask: TaskSnapshot;\n\ttext: string;\n\t/** Bounded log-read/expiry diagnostic, independent of text slicing and byte offsets. */\n\treadError?: string;\n\ttotalBytes: number;\n\ttruncated: boolean;\n\tfromByte?: number;\n\t/** Raw source-byte end supplied by the runtime; older/custom hosts may omit it. */\n\tendByte?: number;\n}\n\n/** Optional host integration for products built on the execution runtime. */\nexport interface TasksSessionContext {\n\t/** Running tasks that navigating to `targetId` would cancel on this session branch. */\n\tstoppedByTreeNavigation(targetId: string): TaskSnapshot[];\n}\n\n/** How a wait ended. `closed` means the host shut down, so execution state is unconfirmed. */\nexport type TaskWaitOutcome = \"settled\" | \"interrupted\" | \"timed_out\" | \"closed\";\n\ninterface TaskObservationOptions {\n\t/** Defaults to 20 seconds and is bounded by the runtime. A timeout never cancels execution. */\n\ttimeoutMs?: number;\n\t/** Rejects the wait with the signal's reason; execution continues. */\n\tsignal?: AbortSignal;\n\t/**\n\t * The tool call whose result carries this observation to the model. With a session host, a\n\t * settled background task stays out of automatic notifications until that result is persisted.\n\t * Without it, or in a standalone runtime, the wait is purely observational.\n\t */\n\ttoolCallId?: string;\n}\n\nexport interface TaskWaitOptions extends TaskObservationOptions {\n\t/** Read output while delivery is still held; skipped when steering interrupted the wait. */\n\tread?: Pick<TaskReadOptions, \"bytes\" | \"sinceBytes\">;\n}\n\nexport interface TaskWaitResult {\n\toutcome: TaskWaitOutcome;\n\twaitedMs: number;\n\t/** The task when the wait ended, before `read` was taken. */\n\ttask: TaskSnapshot;\n\tread?: TaskRead;\n}\n\nexport interface TaskWaitAnyOptions extends TaskObservationOptions {\n\t/** Read the settled task's output while delivery is still held. */\n\tread?: Pick<TaskReadOptions, \"bytes\">;\n}\n\nexport interface TaskWaitAnyResult {\n\t/** `no_tasks`: no background task was running at call time, so nothing was observed. */\n\toutcome: TaskWaitOutcome | \"no_tasks\";\n\twaitedMs: number;\n\t/** The first cohort member to settle; present only for `settled`. */\n\ttask?: TaskSnapshot;\n\tread?: TaskRead;\n\t/** Cohort members still running when the wait ended. */\n\trunning: TaskSnapshot[];\n}\n\n/**\n * Host hooks that make waits part of a durable session. TaskSession supplies them; products\n * embedding a bare TaskRuntime omit them and keep waits observational.\n */\nexport interface TaskWaitHost {\n\t/** Current steering signal. Aborting it ends management waits only, never execution. */\n\treadonly interruptSignal: AbortSignal;\n\t/**\n\t * Keep `taskIds` out of automatic delivery until the returned release runs. The runtime holds\n\t * the observed records for the whole observation: before waiting, until after `bind`.\n\t */\n\thold(taskIds: readonly string[]): () => void;\n\t/**\n\t * A wait observed a settled background task and its `toolCallId` is known. Called while the\n\t * observation hold is still in place; the host takes over until that tool result persists.\n\t */\n\tbind(toolCallId: string, taskId: string): void;\n}\n\n/** Session-bound public capability. Captured instances close on runtime replacement. */\nexport interface TasksContext {\n\treadonly enabled: boolean;\n\treadonly closed?: boolean;\n\t/** Present when the runtime is attached to Pi's durable session lifecycle. */\n\treadonly session?: TasksSessionContext;\n\texecute<T>(execution: TaskExecution<T>): Promise<TaskToolOutcome<T>>;\n\tlist(): TaskSnapshot[];\n\tget(id: string): TaskSnapshot;\n\tread(id: string, options?: TaskReadOptions): Promise<TaskRead>;\n\t/**\n\t * The running task's live Output from its executor's `present`, or `undefined` for an unknown,\n\t * settled or presenter-less task, or when the presenter throws; callers then use the default view.\n\t */\n\tpresentOutput(id: string, width: number, theme: Theme): string[] | undefined;\n\t/**\n\t * Observe one task. With `toolCallId` in a session host, the whole observation (wait, read,\n\t * receipt) is atomic with respect to automatic delivery; a standalone runtime never\n\t * acknowledges delivery. Rejects with `TaskLookupError` for an unknown or ambiguous id.\n\t */\n\twait(id: string, options?: TaskWaitOptions): Promise<TaskWaitResult>;\n\t/**\n\t * Observe the first task running at call time to settle. Tasks started later are excluded,\n\t * and `no_tasks` is returned for an empty cohort. Delivery holds cover the whole cohort until\n\t * the observation completes; members other than the winner then resume ordinary notification.\n\t */\n\twaitAny(options?: TaskWaitAnyOptions): Promise<TaskWaitAnyResult>;\n\tkill(id: string): boolean;\n\t/**\n\t * Move running foreground executions to the background while background slots remain;\n\t * returns how many moved. Throws when eligible work exists but every slot is taken.\n\t */\n\tdetachForeground(): number;\n\t/** Whether this execution can move now, including host policy and available background slots. */\n\tcanDetach(id: string): boolean;\n\t/** Returns false when the task cannot move; throws when every background slot is taken. */\n\tdetach(id: string): boolean;\n\tsubscribe(listener: () => void): () => void;\n\t/** Keep retained output available without delaying completion delivery. */\n\tretain(id: string): () => void;\n}\n\nexport interface TaskRuntimeOptions {\n\tenabled?: boolean;\n\tbackgroundAllowed?: boolean;\n\t/** Branch-impact queries for a durable host; standalone runtimes omit it. */\n\tsession?: TasksSessionContext;\n\t/** Wait receipts and steering interruption for a durable host; standalone runtimes leave waits observational. */\n\twaits?: TaskWaitHost;\n\tanchor?: () => string | null;\n\t/** Admission limit for unsettled background tasks; foreground work is bounded by its caller. */\n\tmaxBackground?: number;\n\t/** Per-history limit: foreground and background tasks each get this allowance. */\n\tmaxHistory?: number;\n\t/** Best-effort cleanup errors, bounded to 4096 bytes; no retries or execution failure. */\n\tonCleanupError?: (message: string) => void;\n\t/** Synchronous persistence before terminal observers or notifications. */\n\tonSettled?: (task: TaskSnapshot, usage: Usage | undefined) => void;\n\t/**\n\t * Whether the host can supervise new background work, such as its management tool being\n\t * active. Gates admission and detaching only; work already admitted is unaffected.\n\t */\n\tcanManageBackground?: () => boolean;\n\t/** The runtime closed: a host holding retention pins for it must release them so output cleanup runs. */\n\tonClosed?: () => void;\n}\n\n/**\n * The model-facing management tool, owned by the bundled `builtin:tasks` extension. Background\n * work is admitted only while it is active, so the model can always read, wait for and stop what\n * it starts. Model-facing copy names it through this constant.\n */\nexport const TASKS_TOOL_NAME = \"tasks\";\n\nexport const TASK_MANAGEMENT_REJECTION = `Background execution needs the ${TASKS_TOOL_NAME} tool to read, wait for and stop the work, and it is not active. Activate the ${TASKS_TOOL_NAME} tool or run in the foreground. No work was started.`;\n\nexport const TASK_BACKGROUND_REJECTION =\n\t\"Background execution is not permitted in this host. Run with background: false or omit background. No work was started.\";\n\nexport function isTaskTerminal(status: TaskStatus): status is TaskTerminalStatus {\n\treturn (TASK_TERMINAL_STATUSES as readonly string[]).includes(status);\n}\n\n/**\n * A failed id lookup, typed so hosts can enrich the message without matching\n * on message text. `matches` snapshots exactly the records the id or prefix\n * resolved against — including records outside the current branch, which\n * list() hides but prefix matching still collides with.\n */\nexport class TaskLookupError extends Error {\n\treadonly kind: \"unknown\" | \"ambiguous\";\n\treadonly matches: TaskSnapshot[];\n\tconstructor(kind: \"unknown\" | \"ambiguous\", matches: TaskSnapshot[]) {\n\t\tsuper(kind === \"ambiguous\" ? \"Ambiguous task ID\" : \"Unknown task ID\");\n\t\tthis.name = \"TaskLookupError\";\n\t\tthis.kind = kind;\n\t\tthis.matches = matches;\n\t}\n}\n"]}
@@ -0,0 +1,19 @@
1
+ export interface WaitSources {
2
+ /** Whether any observed execution has settled. */
3
+ hasSettled(): boolean;
4
+ /** Subscribe to execution state changes; the returned release must remove the listener. */
5
+ subscribe(listener: () => void): () => void;
6
+ timeoutMs: number;
7
+ /** Rejects the wait with the signal's reason. */
8
+ signal?: AbortSignal;
9
+ /** Steering: ends the wait without rejecting. */
10
+ interrupt?: AbortSignal;
11
+ /** The runtime closed: ends the wait without rejecting. */
12
+ closed: AbortSignal;
13
+ }
14
+ /**
15
+ * A race of settlement, timeout, abort, interrupt and close. Whichever ends it first, the timer
16
+ * and every listener are released, so an observation leaves nothing behind. Only an abort rejects.
17
+ */
18
+ export declare function waitForFirst({ hasSettled, subscribe, timeoutMs, signal, interrupt, closed, }: WaitSources): Promise<void>;
19
+ //# sourceMappingURL=wait.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/wait.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC3B,kDAAkD;IAClD,UAAU,IAAI,OAAO,CAAC;IACtB,2FAA2F;IAC3F,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,iDAAiD;IACjD,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,2DAA2D;IAC3D,MAAM,EAAE,WAAW,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAC5B,UAAU,EACV,SAAS,EACT,SAAS,EACT,MAAM,EACN,SAAS,EACT,MAAM,GACN,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B7B"}
@@ -0,0 +1,45 @@
1
+ import { boundWaitMs } from "./limits.js";
2
+ /**
3
+ * A race of settlement, timeout, abort, interrupt and close. Whichever ends it first, the timer
4
+ * and every listener are released, so an observation leaves nothing behind. Only an abort rejects.
5
+ */
6
+ export function waitForFirst({ hasSettled, subscribe, timeoutMs, signal, interrupt, closed, }) {
7
+ if (signal?.aborted)
8
+ return Promise.reject(signal.reason ?? new Error("Wait aborted"));
9
+ if (hasSettled() || interrupt?.aborted || closed.aborted)
10
+ return Promise.resolve();
11
+ return new Promise((resolve, reject) => {
12
+ const releases = [];
13
+ let finished = false;
14
+ const end = (reason) => {
15
+ if (finished)
16
+ return;
17
+ finished = true;
18
+ for (const release of releases)
19
+ release();
20
+ if (reason === undefined)
21
+ resolve();
22
+ else
23
+ reject(reason);
24
+ };
25
+ const on = (source, handler) => {
26
+ if (!source)
27
+ return;
28
+ source.addEventListener("abort", handler, { once: true });
29
+ releases.push(() => source.removeEventListener("abort", handler));
30
+ };
31
+ on(signal, () => end(signal?.reason ?? new Error("Wait aborted")));
32
+ on(interrupt, () => end());
33
+ on(closed, () => end());
34
+ const timer = setTimeout(() => end(), boundWaitMs(timeoutMs));
35
+ releases.push(() => clearTimeout(timer));
36
+ releases.push(subscribe(() => {
37
+ if (hasSettled())
38
+ end();
39
+ }));
40
+ // Close the synchronous gap between the first check and subscription.
41
+ if (hasSettled())
42
+ end();
43
+ });
44
+ }
45
+ //# sourceMappingURL=wait.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait.js","sourceRoot":"","sources":["../../../src/core/tasks/wait.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAgB1C;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EAC5B,UAAU,EACV,SAAS,EACT,SAAS,EACT,MAAM,EACN,SAAS,EACT,MAAM,GACO;IACb,IAAI,MAAM,EAAE,OAAO;QAAE,OAAO,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;IACvF,IAAI,UAAU,EAAE,IAAI,SAAS,EAAE,OAAO,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IACnF,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC5C,MAAM,QAAQ,GAAsB,EAAE,CAAC;QACvC,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,MAAM,GAAG,GAAG,CAAC,MAAgB,EAAE,EAAE;YAChC,IAAI,QAAQ;gBAAE,OAAO;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,KAAK,MAAM,OAAO,IAAI,QAAQ;gBAAE,OAAO,EAAE,CAAC;YAC1C,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,EAAE,CAAC;;gBAC/B,MAAM,CAAC,MAAM,CAAC,CAAC;QACrB,CAAC,CAAC;QACF,MAAM,EAAE,GAAG,CAAC,MAA+B,EAAE,OAAmB,EAAE,EAAE;YACnE,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1D,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QACnE,CAAC,CAAC;QACF,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,IAAI,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;QACnE,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QAC3B,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QACxB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;QAC9D,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;QACzC,QAAQ,CAAC,IAAI,CACZ,SAAS,CAAC,GAAG,EAAE;YACd,IAAI,UAAU,EAAE;gBAAE,GAAG,EAAE,CAAC;QACzB,CAAC,CAAC,CACF,CAAC;QACF,sEAAsE;QACtE,IAAI,UAAU,EAAE;YAAE,GAAG,EAAE,CAAC;IACzB,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { boundWaitMs } from \"./limits.ts\";\n\nexport interface WaitSources {\n\t/** Whether any observed execution has settled. */\n\thasSettled(): boolean;\n\t/** Subscribe to execution state changes; the returned release must remove the listener. */\n\tsubscribe(listener: () => void): () => void;\n\ttimeoutMs: number;\n\t/** Rejects the wait with the signal's reason. */\n\tsignal?: AbortSignal;\n\t/** Steering: ends the wait without rejecting. */\n\tinterrupt?: AbortSignal;\n\t/** The runtime closed: ends the wait without rejecting. */\n\tclosed: AbortSignal;\n}\n\n/**\n * A race of settlement, timeout, abort, interrupt and close. Whichever ends it first, the timer\n * and every listener are released, so an observation leaves nothing behind. Only an abort rejects.\n */\nexport function waitForFirst({\n\thasSettled,\n\tsubscribe,\n\ttimeoutMs,\n\tsignal,\n\tinterrupt,\n\tclosed,\n}: WaitSources): Promise<void> {\n\tif (signal?.aborted) return Promise.reject(signal.reason ?? new Error(\"Wait aborted\"));\n\tif (hasSettled() || interrupt?.aborted || closed.aborted) return Promise.resolve();\n\treturn new Promise<void>((resolve, reject) => {\n\t\tconst releases: Array<() => void> = [];\n\t\tlet finished = false;\n\t\tconst end = (reason?: unknown) => {\n\t\t\tif (finished) return;\n\t\t\tfinished = true;\n\t\t\tfor (const release of releases) release();\n\t\t\tif (reason === undefined) resolve();\n\t\t\telse reject(reason);\n\t\t};\n\t\tconst on = (source: AbortSignal | undefined, handler: () => void) => {\n\t\t\tif (!source) return;\n\t\t\tsource.addEventListener(\"abort\", handler, { once: true });\n\t\t\treleases.push(() => source.removeEventListener(\"abort\", handler));\n\t\t};\n\t\ton(signal, () => end(signal?.reason ?? new Error(\"Wait aborted\")));\n\t\ton(interrupt, () => end());\n\t\ton(closed, () => end());\n\t\tconst timer = setTimeout(() => end(), boundWaitMs(timeoutMs));\n\t\treleases.push(() => clearTimeout(timer));\n\t\treleases.push(\n\t\t\tsubscribe(() => {\n\t\t\t\tif (hasSettled()) end();\n\t\t\t}),\n\t\t);\n\t\t// Close the synchronous gap between the first check and subscription.\n\t\tif (hasSettled()) end();\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"shell-execution.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-execution.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAGlE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGvD,eAAO,MAAM,2BAA2B,QAAmB,CAAC;AAE5D,UAAU,qBAAqB;IAC9B,UAAU,EAAE,cAAc,CAAC;IAC3B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,OAAO,EAAE,WAAW,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;IAClD;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;CACjB;AAwCD,6EAA6E;AAC7E,wBAAsB,eAAe,CACpC,OAAO,EAAE,qBAAqB,GAC5B,OAAO,CAAC,cAAc,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC,CAiKtD"}
1
+ {"version":3,"file":"shell-execution.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-execution.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAGlE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGvD,eAAO,MAAM,2BAA2B,QAAmB,CAAC;AAE5D,UAAU,qBAAqB;IAC9B,UAAU,EAAE,cAAc,CAAC;IAC3B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,OAAO,EAAE,WAAW,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;IAClD;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;CACjB;AAwCD,6EAA6E;AAC7E,wBAAsB,eAAe,CACpC,OAAO,EAAE,qBAAqB,GAC5B,OAAO,CAAC,cAAc,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC,CAkKtD"}
@@ -198,7 +198,8 @@ export async function runShellCommand(options) {
198
198
  ...(failure ? { isError: true } : {}),
199
199
  }
200
200
  : {}),
201
- content: [{ type: "text", text: failure ? `${text ? `${text}\n\n` : ""}${failure.error}` : text }],
201
+ // The command's output only: its failure is the completion's `error`, composed where a result is shown.
202
+ content: [{ type: "text", text }],
202
203
  details,
203
204
  },
204
205
  };
@@ -1 +1 @@
1
- {"version":3,"file":"shell-execution.js","sourceRoot":"","sources":["../../../src/core/tools/shell-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,OAAO,EAAE,iBAAiB,EAAuB,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAsB5D,4FAA4F;AAC5F,SAAS,YAAY,CAAC,KAAc;IACnC,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;IACpH,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;QACjE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,2BAA2B,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;IACvG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;AAC7G,CAAC;AAED,SAAS,YAAY,CACpB,MAAyB,EACzB,QAAwB,EACxB,OAAgB,EAChB,SAAiB;IAEjB,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC;IACvC,IAAI,IAAI,GAAG,QAAQ,CAAC,OAAO,IAAI,SAAS,CAAC;IACzC,IAAI,OAAO,GAAgC,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7G,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;QAC1B,OAAO,GAAG,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,CAAC;QAClE,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,GAAG,UAAU,CAAC,WAAW,GAAG,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,UAAU,CAAC,UAAU,CAAC;QACtC,IAAI,UAAU,CAAC,eAAe,EAAE,CAAC;YAChC,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;YAC3D,IAAI,IAAI,qBAAqB,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,YAAY,OAAO,aAAa,YAAY,mBAAmB,QAAQ,CAAC,cAAc,GAAG,CAAC;QAC1J,CAAC;aAAM,IAAI,UAAU,CAAC,WAAW,KAAK,OAAO,EAAE,CAAC;YAC/C,IAAI,IAAI,sBAAsB,SAAS,IAAI,OAAO,OAAO,UAAU,CAAC,UAAU,kBAAkB,QAAQ,CAAC,cAAc,GAAG,CAAC;QAC5H,CAAC;aAAM,CAAC;YACP,IAAI,IAAI,sBAAsB,SAAS,IAAI,OAAO,OAAO,UAAU,CAAC,UAAU,KAAK,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,yBAAyB,QAAQ,CAAC,cAAc,GAAG,CAAC;QACvK,CAAC;IACF,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC1B,CAAC;AAED,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,eAAe,CACpC,OAA8B;IAE9B,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACnE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5G,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IACpC,IAAI,WAA8B,CAAC;IACnC,IAAI,eAAe,GAAG,IAAI,CAAC;IAC3B,IAAI,WAAqC,CAAC;IAC1C,IAAI,WAAuC,CAAC;IAC5C,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,MAAM,UAAU,GAAG,CAAC,KAAc,EAAE,EAAE;QACrC,IAAI,WAAW;YAAE,OAAO;QACxB,WAAW,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC;YACJ,OAAO,CAAC,MAAM,EAAE,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACR,uDAAuD;QACxD,CAAC;IACF,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC7B,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,aAAa,EAAE,GAAG,2BAA2B,EAAE,CAAC;YAC3F,UAAU,CAAC,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;QAC9E,CAAC;IACF,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,GAAG,EAAE,CACrB,MAAM,CAAC,QAAQ,CAAC;QACf,kBAAkB,EAAE,IAAI;QACxB,QAAQ,EAAE,OAAO,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS;KAC/D,CAAC,CAAC;IACJ,MAAM,OAAO,GAAG,CAAC,QAAyB,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAiD;YAC5D,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;YACnE,OAAO,EAAE,QAAQ;gBAChB,CAAC,CAAC;oBACA,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;oBAC3E,cAAc,EAAE,QAAQ,CAAC,cAAc;iBACvC;gBACF,CAAC,CAAC,SAAS;SACZ,CAAC;QACF,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7B,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC7B,IAAI,CAAC,WAAW;YAAE,OAAO;QACzB,WAAW,GAAG,KAAK,CAAC;QACpB,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC1B,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrB,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC7B,IAAI,WAAW;YAAE,YAAY,CAAC,WAAW,CAAC,CAAC;QAC3C,WAAW,GAAG,SAAS,CAAC;IACzB,CAAC,CAAC;IACF,MAAM,oBAAoB,GAAG,GAAG,EAAE;QACjC,WAAW,GAAG,IAAI,CAAC;QACnB,MAAM,KAAK,GAAG,uBAAuB,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC,CAAC;QACpE,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YAChB,gBAAgB,EAAE,CAAC;YACnB,gBAAgB,EAAE,CAAC;QACpB,CAAC;aAAM,CAAC;YACP,WAAW,KAAK,UAAU,CAAC,GAAG,EAAE;gBAC/B,WAAW,GAAG,SAAS,CAAC;gBACxB,gBAAgB,EAAE,CAAC;YACpB,CAAC,EAAE,KAAK,CAAC,CAAC;QACX,CAAC;IACF,CAAC,CAAC;IACF,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE;QACnC,IAAI,CAAC,eAAe,IAAI,WAAW;YAAE,OAAO;QAC5C,IAAI,CAAC;YACJ,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,2BAA2B,EAAE,CAAC;gBACzG,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,2BAA2B,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;gBACpF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;gBAC3C,UAAU,CAAC,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;YAC9E,CAAC;;gBAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3B,oBAAoB,EAAE,CAAC;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,UAAU,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACF,CAAC,CAAC;IAEF,IAAI,CAAC;QACJ,IAAI,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,cAAe,CAAC;YAC/C,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;gBAC1B,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;gBAC7B,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAA4B,EAAE,EAAE;oBACzD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;wBAAE,MAAM,KAAK,CAAC;gBAC1C,CAAC,CAAC,CAAC;YACJ,CAAC,CAAC;YACF,IAAI,CAAC;gBACJ,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACrC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,MAAM,OAAO,EAAE,CAAC;gBAChB,MAAM,KAAK,CAAC;YACb,CAAC;QACF,CAAC;QACD,mFAAmF;QACnF,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;QACrD,OAAO,EAAE,CAAC;QACV,IAAI,OAAiC,CAAC;QACtC,IAAI,QAAmC,CAAC;QACxC,IAAI,CAAC;YACJ,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;YAChD,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE;gBAC/D,MAAM,EAAE,UAAU;gBAClB,MAAM;gBACN,OAAO;gBACP,GAAG,EAAE,OAAO,CAAC,GAAG;aAChB,CAAC,CAAC;YACH,OAAO,CAAC,MAAM,EAAE,CAAC;YACjB,CAAC,EAAE,QAAQ,EAAE,GAAG,MAAM,SAAS,CAAC,CAAC;YACjC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACvB,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,yCAAyC,EAAE,CAAC;YAClF,CAAC;iBAAM,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;gBAC3B,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,4BAA4B,QAAQ,EAAE,EAAE,CAAC;YAC/E,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,eAAe,GAAG,KAAK,CAAC;QACxB,MAAM,CAAC,MAAM,EAAE,CAAC;QAChB,gBAAgB,EAAE,CAAC;QACnB,IAAI,OAAO;YAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;;YAC5B,gBAAgB,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;QAC7B,4EAA4E;QAC5E,sEAAsE;QACtE,IAAI,WAAW;YAAE,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;QAC7F,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QAC7F,MAAM,UAAU,GACf,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,cAAc,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACrG,OAAO;YACN,MAAM,EAAE,OAAO,EAAE,MAAM;YACvB,KAAK,EAAE,OAAO,EAAE,KAAK;YACrB,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzG,MAAM,EAAE;gBACP,GAAG,CAAC,UAAU,IAAI,OAAO,QAAQ,KAAK,QAAQ;oBAC7C,CAAC,CAAC;wBACA,iBAAiB,EAAE;4BAClB,MAAM,EAAE,UAAU,CAAC,OAAO;4BAC1B,SAAS,EAAE,UAAU,CAAC,SAAS;4BAC/B,GAAG,CAAC,UAAU,CAAC,SAAS,IAAI,KAAK,CAAC,cAAc;gCAC/C,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,CAAC,cAAc,EAAE;gCAC5C,CAAC,CAAC,EAAE,CAAC;4BACN,SAAS,EAAE,QAAQ;4BACnB,iBAAiB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,GAAG,EAAE;yBACzE;wBACD,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBACrC;oBACF,CAAC,CAAC,EAAE,CAAC;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAClG,OAAO;aACP;SACD,CAAC;IACH,CAAC;YAAS,CAAC;QACV,eAAe,GAAG,KAAK,CAAC;QACxB,WAAW,EAAE,EAAE,CAAC;QAChB,gBAAgB,EAAE,CAAC;QACnB,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;IAC9B,CAAC;AACF,CAAC","sourcesContent":["import { unlink } from \"node:fs/promises\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport { boundText } from \"../tasks/output.ts\";\nimport type { TaskCompletion, TaskControl } from \"../tasks/types.ts\";\nimport type { BashOperations, BashSpawnContext } from \"./bash.ts\";\nimport { OutputAccumulator, type OutputSnapshot } from \"./output-accumulator.ts\";\nimport { BASH_UPDATE_THROTTLE_MS } from \"./renderers/bash.ts\";\nimport type { BashToolDetails } from \"./shell-tool.ts\";\nimport { formatSize } from \"./truncate.ts\";\n\nexport const MAX_BACKGROUND_OUTPUT_BYTES = 20 * 1024 * 1024;\n\ninterface ShellExecutionOptions {\n\toperations: BashOperations;\n\tcontext: BashSpawnContext;\n\ttempFilePrefix: string;\n\ttimeout?: number;\n\t/** The task this command runs as; its signal cancels the process. */\n\tcontrol: TaskControl<BashToolDetails | undefined>;\n\t/**\n\t * The command belongs to a session task, which may leave the foreground: its output log is\n\t * created and attached to the task from the first byte, and a final snapshot is always\n\t * published. Otherwise the log is created only if output is truncated.\n\t */\n\ttaskLog: boolean;\n}\n\ninterface ShellFailure {\n\tstatus: \"failed\" | \"cancelled\" | \"timeout\";\n\terror: string;\n}\n\n/** Interpret the documented BashOperations error markers once, before formatting output. */\nfunction shellFailure(error: unknown): ShellFailure {\n\tif (error instanceof Error && error.message === \"aborted\") return { status: \"cancelled\", error: \"Command aborted\" };\n\tif (error instanceof Error && error.message.startsWith(\"timeout:\"))\n\t\treturn { status: \"timeout\", error: `Command timed out after ${error.message.split(\":\")[1]} seconds` };\n\treturn { status: \"failed\", error: boundText(error instanceof Error ? error.message : String(error), 4096) };\n}\n\nfunction formatOutput(\n\toutput: OutputAccumulator,\n\tsnapshot: OutputSnapshot,\n\ttaskLog: boolean,\n\temptyText: string,\n): { text: string; details: BashToolDetails | undefined } {\n\tconst truncation = snapshot.truncation;\n\tlet text = snapshot.content || emptyText;\n\tlet details: BashToolDetails | undefined = taskLog ? { fullOutputPath: snapshot.fullOutputPath } : undefined;\n\tif (truncation.truncated) {\n\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\tconst endLine = truncation.totalLines;\n\t\tif (truncation.lastLinePartial) {\n\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t} else {\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(truncation.maxBytes)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t}\n\t}\n\treturn { text, details };\n}\n\n/** One process and one output owner across foreground/background handoff. */\nexport async function runShellCommand(\n\toptions: ShellExecutionOptions,\n): Promise<TaskCompletion<BashToolDetails | undefined>> {\n\tconst { operations, context, control, taskLog, timeout } = options;\n\tconst signal = control.signal;\n\tconst output = new OutputAccumulator({ tempFilePrefix: options.tempFilePrefix, persistFromStart: taskLog });\n\tconst startedAt = performance.now();\n\tlet outputError: Error | undefined;\n\tlet acceptingOutput = true;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet updateTimer: NodeJS.Timeout | undefined;\n\tlet updateDirty = false;\n\tlet lastUpdateAt = 0;\n\n\tconst failOutput = (error: unknown) => {\n\t\tif (outputError) return;\n\t\toutputError = error instanceof Error ? error : new Error(String(error));\n\t\ttry {\n\t\t\tcontrol.cancel();\n\t\t} catch {\n\t\t\t// Late data must not throw through a process observer.\n\t\t}\n\t};\n\tconst checkOutputLimit = () => {\n\t\tif (control.mode === \"background\" && output.getTotalBytes() > MAX_BACKGROUND_OUTPUT_BYTES) {\n\t\t\tfailOutput(new Error(\"Background command exceeded the 20 MiB output limit\"));\n\t\t}\n\t};\n\tconst snapshot = () =>\n\t\toutput.snapshot({\n\t\t\tpersistIfTruncated: true,\n\t\t\tmaxBytes: control.mode === \"background\" ? 40 * 1024 : undefined,\n\t\t});\n\tconst publish = (snapshot?: OutputSnapshot) => {\n\t\tconst result: AgentToolResult<BashToolDetails | undefined> = {\n\t\t\tcontent: snapshot ? [{ type: \"text\", text: snapshot.content }] : [],\n\t\t\tdetails: snapshot\n\t\t\t\t? {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t};\n\t\tcontrol.publish({ result });\n\t};\n\tconst emitOutputUpdate = () => {\n\t\tif (!updateDirty) return;\n\t\tupdateDirty = false;\n\t\tlastUpdateAt = Date.now();\n\t\tpublish(snapshot());\n\t};\n\tconst clearUpdateTimer = () => {\n\t\tif (updateTimer) clearTimeout(updateTimer);\n\t\tupdateTimer = undefined;\n\t};\n\tconst scheduleOutputUpdate = () => {\n\t\tupdateDirty = true;\n\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\tif (delay <= 0) {\n\t\t\tclearUpdateTimer();\n\t\t\temitOutputUpdate();\n\t\t} else {\n\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\tupdateTimer = undefined;\n\t\t\t\temitOutputUpdate();\n\t\t\t}, delay);\n\t\t}\n\t};\n\tconst handleData = (data: Buffer) => {\n\t\tif (!acceptingOutput || outputError) return;\n\t\ttry {\n\t\t\tif (control.mode === \"background\" && output.getTotalBytes() + data.length > MAX_BACKGROUND_OUTPUT_BYTES) {\n\t\t\t\tconst remaining = Math.max(0, MAX_BACKGROUND_OUTPUT_BYTES - output.getTotalBytes());\n\t\t\t\toutput.append(data.subarray(0, remaining));\n\t\t\t\tfailOutput(new Error(\"Background command exceeded the 20 MiB output limit\"));\n\t\t\t} else output.append(data);\n\t\t\tscheduleOutputUpdate();\n\t\t} catch (error) {\n\t\t\tfailOutput(error);\n\t\t}\n\t};\n\n\ttry {\n\t\tif (taskLog) {\n\t\t\tconst path = output.snapshot().fullOutputPath!;\n\t\t\tconst cleanup = async () => {\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\tawait unlink(path).catch((error: NodeJS.ErrnoException) => {\n\t\t\t\t\tif (error.code !== \"ENOENT\") throw error;\n\t\t\t\t});\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tcontrol.attachOutput(path, cleanup);\n\t\t\t} catch (error) {\n\t\t\t\tawait cleanup();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\t// Detach must check a silent foreground log too, preserving bytes already written.\n\t\tunsubscribe = control.onModeChange(checkOutputLimit);\n\t\tpublish();\n\t\tlet failure: ShellFailure | undefined;\n\t\tlet exitCode: number | null | undefined;\n\t\ttry {\n\t\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\t\t\tconst execution = operations.exec(context.command, context.cwd, {\n\t\t\t\tonData: handleData,\n\t\t\t\tsignal,\n\t\t\t\ttimeout,\n\t\t\t\tenv: context.env,\n\t\t\t});\n\t\t\tcontrol.accept();\n\t\t\t({ exitCode } = await execution);\n\t\t\tif (exitCode === null) {\n\t\t\t\tfailure = { status: \"failed\", error: \"Command terminated without an exit code\" };\n\t\t\t} else if (exitCode !== 0) {\n\t\t\t\tfailure = { status: \"failed\", error: `Command exited with code ${exitCode}` };\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tfailure = shellFailure(error);\n\t\t}\n\t\tacceptingOutput = false;\n\t\toutput.finish();\n\t\tclearUpdateTimer();\n\t\tif (taskLog) publish(snapshot());\n\t\telse emitOutputUpdate();\n\t\tconst final = snapshot();\n\t\tawait output.closeTempFile();\n\t\t// Final progress/cleanup can re-enter handoff. Classify policy cancellation\n\t\t// after those callbacks, independently of the process's abort marker.\n\t\tif (outputError) failure = { status: \"failed\", error: boundText(outputError.message, 4096) };\n\t\tconst { text, details } = formatOutput(output, final, taskLog, failure ? \"\" : \"(no output)\");\n\t\tconst fullOutput =\n\t\t\ttypeof exitCode === \"number\" && !outputError ? await output.readFullOutput(1024 * 1024) : undefined;\n\t\treturn {\n\t\t\tstatus: failure?.status,\n\t\t\terror: failure?.error,\n\t\t\t...(exitCode !== undefined ? { facts: [[\"Exit\", exitCode === null ? \"signal\" : String(exitCode)]] } : {}),\n\t\t\tresult: {\n\t\t\t\t...(fullOutput && typeof exitCode === \"number\"\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tstructuredContent: {\n\t\t\t\t\t\t\t\toutput: fullOutput.content,\n\t\t\t\t\t\t\t\ttruncated: fullOutput.truncated,\n\t\t\t\t\t\t\t\t...(fullOutput.truncated && final.fullOutputPath\n\t\t\t\t\t\t\t\t\t? { full_output_path: final.fullOutputPath }\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\texit_code: exitCode,\n\t\t\t\t\t\t\t\twall_time_seconds: Math.round((performance.now() - startedAt) / 100) / 10,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t...(failure ? { isError: true } : {}),\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t\tcontent: [{ type: \"text\", text: failure ? `${text ? `${text}\\n\\n` : \"\"}${failure.error}` : text }],\n\t\t\t\tdetails,\n\t\t\t},\n\t\t};\n\t} finally {\n\t\tacceptingOutput = false;\n\t\tunsubscribe?.();\n\t\tclearUpdateTimer();\n\t\tawait output.closeTempFile();\n\t}\n}\n"]}
1
+ {"version":3,"file":"shell-execution.js","sourceRoot":"","sources":["../../../src/core/tools/shell-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import { unlink } from \"node:fs/promises\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport { boundText } from \"../tasks/output.ts\";\nimport type { TaskCompletion, TaskControl } from \"../tasks/types.ts\";\nimport type { BashOperations, BashSpawnContext } from \"./bash.ts\";\nimport { OutputAccumulator, type OutputSnapshot } from \"./output-accumulator.ts\";\nimport { BASH_UPDATE_THROTTLE_MS } from \"./renderers/bash.ts\";\nimport type { BashToolDetails } from \"./shell-tool.ts\";\nimport { formatSize } from \"./truncate.ts\";\n\nexport const MAX_BACKGROUND_OUTPUT_BYTES = 20 * 1024 * 1024;\n\ninterface ShellExecutionOptions {\n\toperations: BashOperations;\n\tcontext: BashSpawnContext;\n\ttempFilePrefix: string;\n\ttimeout?: number;\n\t/** The task this command runs as; its signal cancels the process. */\n\tcontrol: TaskControl<BashToolDetails | undefined>;\n\t/**\n\t * The command belongs to a session task, which may leave the foreground: its output log is\n\t * created and attached to the task from the first byte, and a final snapshot is always\n\t * published. Otherwise the log is created only if output is truncated.\n\t */\n\ttaskLog: boolean;\n}\n\ninterface ShellFailure {\n\tstatus: \"failed\" | \"cancelled\" | \"timeout\";\n\terror: string;\n}\n\n/** Interpret the documented BashOperations error markers once, before formatting output. */\nfunction shellFailure(error: unknown): ShellFailure {\n\tif (error instanceof Error && error.message === \"aborted\") return { status: \"cancelled\", error: \"Command aborted\" };\n\tif (error instanceof Error && error.message.startsWith(\"timeout:\"))\n\t\treturn { status: \"timeout\", error: `Command timed out after ${error.message.split(\":\")[1]} seconds` };\n\treturn { status: \"failed\", error: boundText(error instanceof Error ? error.message : String(error), 4096) };\n}\n\nfunction formatOutput(\n\toutput: OutputAccumulator,\n\tsnapshot: OutputSnapshot,\n\ttaskLog: boolean,\n\temptyText: string,\n): { text: string; details: BashToolDetails | undefined } {\n\tconst truncation = snapshot.truncation;\n\tlet text = snapshot.content || emptyText;\n\tlet details: BashToolDetails | undefined = taskLog ? { fullOutputPath: snapshot.fullOutputPath } : undefined;\n\tif (truncation.truncated) {\n\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\tconst endLine = truncation.totalLines;\n\t\tif (truncation.lastLinePartial) {\n\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t} else {\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(truncation.maxBytes)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t}\n\t}\n\treturn { text, details };\n}\n\n/** One process and one output owner across foreground/background handoff. */\nexport async function runShellCommand(\n\toptions: ShellExecutionOptions,\n): Promise<TaskCompletion<BashToolDetails | undefined>> {\n\tconst { operations, context, control, taskLog, timeout } = options;\n\tconst signal = control.signal;\n\tconst output = new OutputAccumulator({ tempFilePrefix: options.tempFilePrefix, persistFromStart: taskLog });\n\tconst startedAt = performance.now();\n\tlet outputError: Error | undefined;\n\tlet acceptingOutput = true;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet updateTimer: NodeJS.Timeout | undefined;\n\tlet updateDirty = false;\n\tlet lastUpdateAt = 0;\n\n\tconst failOutput = (error: unknown) => {\n\t\tif (outputError) return;\n\t\toutputError = error instanceof Error ? error : new Error(String(error));\n\t\ttry {\n\t\t\tcontrol.cancel();\n\t\t} catch {\n\t\t\t// Late data must not throw through a process observer.\n\t\t}\n\t};\n\tconst checkOutputLimit = () => {\n\t\tif (control.mode === \"background\" && output.getTotalBytes() > MAX_BACKGROUND_OUTPUT_BYTES) {\n\t\t\tfailOutput(new Error(\"Background command exceeded the 20 MiB output limit\"));\n\t\t}\n\t};\n\tconst snapshot = () =>\n\t\toutput.snapshot({\n\t\t\tpersistIfTruncated: true,\n\t\t\tmaxBytes: control.mode === \"background\" ? 40 * 1024 : undefined,\n\t\t});\n\tconst publish = (snapshot?: OutputSnapshot) => {\n\t\tconst result: AgentToolResult<BashToolDetails | undefined> = {\n\t\t\tcontent: snapshot ? [{ type: \"text\", text: snapshot.content }] : [],\n\t\t\tdetails: snapshot\n\t\t\t\t? {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t};\n\t\tcontrol.publish({ result });\n\t};\n\tconst emitOutputUpdate = () => {\n\t\tif (!updateDirty) return;\n\t\tupdateDirty = false;\n\t\tlastUpdateAt = Date.now();\n\t\tpublish(snapshot());\n\t};\n\tconst clearUpdateTimer = () => {\n\t\tif (updateTimer) clearTimeout(updateTimer);\n\t\tupdateTimer = undefined;\n\t};\n\tconst scheduleOutputUpdate = () => {\n\t\tupdateDirty = true;\n\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\tif (delay <= 0) {\n\t\t\tclearUpdateTimer();\n\t\t\temitOutputUpdate();\n\t\t} else {\n\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\tupdateTimer = undefined;\n\t\t\t\temitOutputUpdate();\n\t\t\t}, delay);\n\t\t}\n\t};\n\tconst handleData = (data: Buffer) => {\n\t\tif (!acceptingOutput || outputError) return;\n\t\ttry {\n\t\t\tif (control.mode === \"background\" && output.getTotalBytes() + data.length > MAX_BACKGROUND_OUTPUT_BYTES) {\n\t\t\t\tconst remaining = Math.max(0, MAX_BACKGROUND_OUTPUT_BYTES - output.getTotalBytes());\n\t\t\t\toutput.append(data.subarray(0, remaining));\n\t\t\t\tfailOutput(new Error(\"Background command exceeded the 20 MiB output limit\"));\n\t\t\t} else output.append(data);\n\t\t\tscheduleOutputUpdate();\n\t\t} catch (error) {\n\t\t\tfailOutput(error);\n\t\t}\n\t};\n\n\ttry {\n\t\tif (taskLog) {\n\t\t\tconst path = output.snapshot().fullOutputPath!;\n\t\t\tconst cleanup = async () => {\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\tawait unlink(path).catch((error: NodeJS.ErrnoException) => {\n\t\t\t\t\tif (error.code !== \"ENOENT\") throw error;\n\t\t\t\t});\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tcontrol.attachOutput(path, cleanup);\n\t\t\t} catch (error) {\n\t\t\t\tawait cleanup();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\t// Detach must check a silent foreground log too, preserving bytes already written.\n\t\tunsubscribe = control.onModeChange(checkOutputLimit);\n\t\tpublish();\n\t\tlet failure: ShellFailure | undefined;\n\t\tlet exitCode: number | null | undefined;\n\t\ttry {\n\t\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\t\t\tconst execution = operations.exec(context.command, context.cwd, {\n\t\t\t\tonData: handleData,\n\t\t\t\tsignal,\n\t\t\t\ttimeout,\n\t\t\t\tenv: context.env,\n\t\t\t});\n\t\t\tcontrol.accept();\n\t\t\t({ exitCode } = await execution);\n\t\t\tif (exitCode === null) {\n\t\t\t\tfailure = { status: \"failed\", error: \"Command terminated without an exit code\" };\n\t\t\t} else if (exitCode !== 0) {\n\t\t\t\tfailure = { status: \"failed\", error: `Command exited with code ${exitCode}` };\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tfailure = shellFailure(error);\n\t\t}\n\t\tacceptingOutput = false;\n\t\toutput.finish();\n\t\tclearUpdateTimer();\n\t\tif (taskLog) publish(snapshot());\n\t\telse emitOutputUpdate();\n\t\tconst final = snapshot();\n\t\tawait output.closeTempFile();\n\t\t// Final progress/cleanup can re-enter handoff. Classify policy cancellation\n\t\t// after those callbacks, independently of the process's abort marker.\n\t\tif (outputError) failure = { status: \"failed\", error: boundText(outputError.message, 4096) };\n\t\tconst { text, details } = formatOutput(output, final, taskLog, failure ? \"\" : \"(no output)\");\n\t\tconst fullOutput =\n\t\t\ttypeof exitCode === \"number\" && !outputError ? await output.readFullOutput(1024 * 1024) : undefined;\n\t\treturn {\n\t\t\tstatus: failure?.status,\n\t\t\terror: failure?.error,\n\t\t\t...(exitCode !== undefined ? { facts: [[\"Exit\", exitCode === null ? \"signal\" : String(exitCode)]] } : {}),\n\t\t\tresult: {\n\t\t\t\t...(fullOutput && typeof exitCode === \"number\"\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tstructuredContent: {\n\t\t\t\t\t\t\t\toutput: fullOutput.content,\n\t\t\t\t\t\t\t\ttruncated: fullOutput.truncated,\n\t\t\t\t\t\t\t\t...(fullOutput.truncated && final.fullOutputPath\n\t\t\t\t\t\t\t\t\t? { full_output_path: final.fullOutputPath }\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\texit_code: exitCode,\n\t\t\t\t\t\t\t\twall_time_seconds: Math.round((performance.now() - startedAt) / 100) / 10,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t...(failure ? { isError: true } : {}),\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t\t// The command's output only: its failure is the completion's `error`, composed where a result is shown.\n\t\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\t\tdetails,\n\t\t\t},\n\t\t};\n\t} finally {\n\t\tacceptingOutput = false;\n\t\tunsubscribe?.();\n\t\tclearUpdateTimer();\n\t\tawait output.closeTempFile();\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"shell-tool.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG/E,OAAO,EACN,KAAK,cAAc,EACnB,KAAK,eAAe,EAGpB,KAAK,eAAe,EACpB,MAAM,WAAW,CAAC;AAKnB,OAAO,EAAwC,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE5F,QAAA,MAAM,UAAU;;;;EASd,CAAC;AAEH,eAAO,MAAM,gCAAgC;;;CAGnC,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAetD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACpD;AAED,MAAM,MAAM,eAAe,GAAG;IAC7B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAiBF,wBAAgB,yBAAyB,CACxC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,eAAe,GAAG;IAAE,UAAU,EAAE,cAAc,CAAA;CAAE,GACvD,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CA4FjF;AAYD,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAK9C;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe;;;;iCAQpE"}
1
+ {"version":3,"file":"shell-tool.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG/E,OAAO,EACN,KAAK,cAAc,EACnB,KAAK,eAAe,EAGpB,KAAK,eAAe,EACpB,MAAM,WAAW,CAAC;AAKnB,OAAO,EAAwC,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE5F,QAAA,MAAM,UAAU;;;;EASd,CAAC;AAEH,eAAO,MAAM,gCAAgC;;;CAGnC,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAetD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACpD;AAED,MAAM,MAAM,eAAe,GAAG;IAC7B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAyBF,wBAAgB,yBAAyB,CACxC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,eAAe,GAAG;IAAE,UAAU,EAAE,cAAc,CAAA;CAAE,GACvD,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CA4FjF;AAYD,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAK9C;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe;;;;iCAQpE"}
@@ -1,5 +1,6 @@
1
1
  import { Type } from "typebox";
2
2
  import { TaskRuntime } from "../tasks/runtime.js";
3
+ import { TASKS_TOOL_NAME } from "../tasks/types.js";
3
4
  import { resolveSpawnContext, resolveTimeoutMs, } from "./bash.js";
4
5
  import { createShellRenderers } from "./renderers/bash.js";
5
6
  import { runShellCommand } from "./shell-execution.js";
@@ -29,18 +30,24 @@ const bashOutputSchema = Type.Union([
29
30
  }),
30
31
  Type.Object({ task_id: Type.String(), status: Type.String() }),
31
32
  ]);
32
- /** Translate terminal shell failures to the native foreground tool contract once. */
33
+ /**
34
+ * Translate terminal shell failures to the native foreground tool contract once. A task result
35
+ * holds the command's output only; the foreground text is that output followed by the failure.
36
+ */
33
37
  function shellToolResult(completion) {
34
38
  const status = completion.status;
35
- if (completion.result.structuredContent)
36
- return completion.result;
39
+ const output = completion.result.content
40
+ .filter((part) => part.type === "text")
41
+ .map((part) => part.text)
42
+ .join("\n");
43
+ const withError = (error) => (output ? `${output}\n\n${error}` : error);
44
+ if (completion.result.structuredContent) {
45
+ if (!completion.result.isError || !completion.error)
46
+ return completion.result;
47
+ return { ...completion.result, content: [{ type: "text", text: withError(completion.error) }] };
48
+ }
37
49
  if (status === "failed" || status === "timeout" || status === "cancelled") {
38
- const text = completion.result.content
39
- .filter((part) => part.type === "text")
40
- .map((part) => part.text)
41
- .join("\n");
42
- const message = completion.error ? text || completion.error : `${text ? `${text}\n\n` : ""}Command ${status}`;
43
- throw new Error(message);
50
+ throw new Error(completion.error ? withError(completion.error) : `${output ? `${output}\n\n` : ""}Command ${status}`);
44
51
  }
45
52
  return completion.result;
46
53
  }
@@ -52,7 +59,7 @@ export function createShellToolDefinition(cwd, config, options) {
52
59
  return {
53
60
  name: config.name,
54
61
  label: config.label,
55
- description: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr, truncated to the last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first); the full output is saved to a temp file. Optionally provide a timeout in seconds (no default). Choose the mode per call: foreground (default) blocks until the command exits — use it when your next step needs the output; background: true returns immediately with a task ID — use it for long-running work (builds, servers, watchers, big test suites) or when you have independent work to continue. A handoff is not completion: the result arrives later as an automatic completion notification; meanwhile use tasks read to inspect output, tasks wait with an ID for one task or without one for any running task, and tasks kill to stop it. Steering interrupts only a wait, never execution. Background output is limited to 20 MiB; an expired tasks wait window never stops the command.`,
62
+ description: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr, truncated to the last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first); the full output is saved to a temp file. Optionally provide a timeout in seconds (no default). Choose the mode per call: foreground (default) blocks until the command exits — use it when your next step needs the output; background: true returns immediately with a task ID — use it for long-running work (builds, servers, watchers, big test suites) or when you have independent work to continue. A handoff is not completion: the result arrives later as an automatic completion notification; meanwhile use ${TASKS_TOOL_NAME} read to inspect output, ${TASKS_TOOL_NAME} wait with an ID for one task or without one for any running task, and ${TASKS_TOOL_NAME} kill to stop it. Steering interrupts only a wait, never execution. Background output is limited to 20 MiB; an expired ${TASKS_TOOL_NAME} wait window never stops the command.`,
56
63
  promptSnippet: config.promptSnippet,
57
64
  promptGuidelines: exposeSessionEnvironment && config.promptGuidelines ? [...config.promptGuidelines] : undefined,
58
65
  parameters: bashSchema,
@@ -102,13 +109,13 @@ export function createShellToolDefinition(cwd, config, options) {
102
109
  }
103
110
  if (outcome.kind === "result")
104
111
  return shellToolResult(outcome);
105
- const tail = `Task ID: ${outcome.task.id}. Status: ${outcome.task.status}. Completion arrives automatically as a notification — do not poll or immediately wait on it; continue with other work or hand back to the user. Use tasks read to inspect output, tasks wait only when your next step is blocked on a result (one ID or any running task; prefer foreground next time in that case), or tasks kill to stop it.`;
112
+ const tail = `Task ID: ${outcome.task.id}. Status: ${outcome.task.status}. Completion arrives and wakes you automatically — do not poll or wait on it; continue with other work, or end your turn and hand back to the user. If you would only wait for the result, prefer foreground next time. Use ${TASKS_TOOL_NAME} read to inspect output or ${TASKS_TOOL_NAME} kill to stop it.`;
106
113
  // Shell execution can become background work in two ways, and the model has to know which
107
114
  // one it got: a submitted background command starts from an empty log, while a detached
108
115
  // one already holds output and keeps its original timeout.
109
- const handoff = background === true
116
+ const handoff = outcome.reason === "submitted"
110
117
  ? `Command handed to background. ${tail}`
111
- : `Command moved to the background while it was running, by the user. The execution continues unchanged — no restart, and a supplied timeout is still measured from command startup. Output produced so far is already in the log, so tasks read now returns partial output, not a fresh start. ${tail}`;
118
+ : `Command moved to the background while it was running, by the user. The execution continues unchanged — no restart, and a supplied timeout is still measured from command startup. Output produced so far is already in the log, so ${TASKS_TOOL_NAME} read now returns partial output, not a fresh start. ${tail}`;
112
119
  return {
113
120
  structuredContent: { task_id: outcome.task.id, status: outcome.task.status },
114
121
  content: [