@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,33 @@
1
+ import type { Input } from "@earendil-works/pi-tui";
2
+ import type { AppKeybinding } from "../../../core/keybindings.ts";
1
3
  import { type TaskSnapshot } from "../../../core/tasks/types.ts";
2
4
  import type { TaskViewport } from "./viewport.ts";
3
5
  export type TasksTab = "output" | "info";
4
6
  export type PanelFocus = "list" | "inspector";
7
+ /** What activating a rendered cell does; the manager dispatches on `kind` alone. */
8
+ export type TaskAction = {
9
+ kind: "select";
10
+ taskId: string;
11
+ } | {
12
+ kind: "tab";
13
+ tab: TasksTab;
14
+ } | {
15
+ kind: "key";
16
+ key: AppKeybinding;
17
+ } | {
18
+ kind: "open";
19
+ }
20
+ /** Escape: unwind one layer, return from the inspector in a narrow terminal, or close the panel. */
21
+ | {
22
+ kind: "back";
23
+ };
24
+ /** A clickable row of cells on the screen and the action a click on it performs. */
25
+ export interface TaskHit {
26
+ x: number;
27
+ y: number;
28
+ width: number;
29
+ action: TaskAction;
30
+ }
5
31
  /**
6
32
  * The one transient layer over the browsing panel. Each layer owns its data, so a stale
7
33
  * combination (help over a confirmation, a restore point without a search) cannot exist.
@@ -9,13 +35,14 @@ export type PanelFocus = "list" | "inspector";
9
35
  export type PanelMode = {
10
36
  kind: "browse";
11
37
  }
12
- /** Searching moves focus to the list; `restore` is where Esc returns to. */
38
+ /** Searching moves focus to the list; `restore` is where Esc returns to. The input owns the query. */
13
39
  | {
14
40
  kind: "search";
15
41
  restore: {
16
42
  id?: string;
17
43
  focus: PanelFocus;
18
44
  };
45
+ input: Input;
19
46
  } | {
20
47
  kind: "confirmStop";
21
48
  taskId: string;
@@ -37,14 +64,14 @@ export declare class TaskSelection {
37
64
  readonly state: TasksPanelState;
38
65
  all: TaskSnapshot[];
39
66
  rows: TaskSnapshot[];
40
- query: string;
41
67
  constructor(state: TasksPanelState);
42
68
  get selected(): TaskSnapshot | undefined;
43
69
  get activeCount(): number;
44
- sync(all: TaskSnapshot[]): void;
45
- select(id: string | undefined): void;
70
+ sync(all: TaskSnapshot[], query?: string): void;
71
+ select(id: string | undefined, query?: string): void;
46
72
  /** On reopen, prefer the newest work started since the panel closed over the remembered row. */
47
73
  selectStartedSinceClose(): void;
48
- refresh(): void;
74
+ /** Rows are the retained tasks matching `query`; an empty query matches all of them. */
75
+ refresh(query?: string): void;
49
76
  }
50
77
  //# sourceMappingURL=model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../../src/extensions/tasks/ui/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AACzC,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,WAAW,CAAC;AAE9C;;;GAGG;AACH,MAAM,MAAM,SAAS,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE;AACpB,4EAA4E;GAC1E;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,CAAA;CAAE,CAAC;AAE5C,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,GAAG,OAAO,CAEvE;AAED,6FAA6F;AAC7F,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,QAAQ,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,8FAA8F;AAC9F,qBAAa,aAAa;IACzB,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,GAAG,EAAE,YAAY,EAAE,CAAM;IACzB,IAAI,EAAE,YAAY,EAAE,CAAM;IAC1B,KAAK,SAAM;gBACC,KAAK,EAAE,eAAe;IAGlC,IAAI,QAAQ,IAAI,YAAY,GAAG,SAAS,CAEvC;IACD,IAAI,WAAW,IAAI,MAAM,CAExB;IACD,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,IAAI;IAI/B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAIpC,gGAAgG;IAChG,uBAAuB,IAAI,IAAI;IAM/B,OAAO,IAAI,IAAI;CAmBf"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../../src/extensions/tasks/ui/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AACzC,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,WAAW,CAAC;AAE9C,oFAAoF;AACpF,MAAM,MAAM,UAAU,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,aAAa,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;AAClB,oGAAoG;GAClG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpB,oFAAoF;AACpF,MAAM,WAAW,OAAO;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE;AACpB,sGAAsG;GACpG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAC7E;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,CAAA;CAAE,CAAC;AAE5C,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,GAAG,OAAO,CAEvE;AAED,6FAA6F;AAC7F,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,QAAQ,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,8FAA8F;AAC9F,qBAAa,aAAa;IACzB,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,GAAG,EAAE,YAAY,EAAE,CAAM;IACzB,IAAI,EAAE,YAAY,EAAE,CAAM;gBACd,KAAK,EAAE,eAAe;IAGlC,IAAI,QAAQ,IAAI,YAAY,GAAG,SAAS,CAEvC;IACD,IAAI,WAAW,IAAI,MAAM,CAExB;IACD,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,KAAK,SAAK,GAAG,IAAI;IAI3C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,SAAK,GAAG,IAAI;IAIhD,gGAAgG;IAChG,uBAAuB,IAAI,IAAI;IAM/B,wFAAwF;IACxF,OAAO,CAAC,KAAK,SAAK,GAAG,IAAI;CAmBzB"}
@@ -8,7 +8,6 @@ export class TaskSelection {
8
8
  constructor(state) {
9
9
  this.all = [];
10
10
  this.rows = [];
11
- this.query = "";
12
11
  this.state = state;
13
12
  }
14
13
  get selected() {
@@ -17,13 +16,13 @@ export class TaskSelection {
17
16
  get activeCount() {
18
17
  return this.all.filter((task) => !isTaskTerminal(task.status)).length;
19
18
  }
20
- sync(all) {
19
+ sync(all, query = "") {
21
20
  this.all = all;
22
- this.refresh();
21
+ this.refresh(query);
23
22
  }
24
- select(id) {
23
+ select(id, query = "") {
25
24
  this.state.selectedId = id;
26
- this.refresh();
25
+ this.refresh(query);
27
26
  }
28
27
  /** On reopen, prefer the newest work started since the panel closed over the remembered row. */
29
28
  selectStartedSinceClose() {
@@ -34,7 +33,8 @@ export class TaskSelection {
34
33
  if (fresh.length)
35
34
  this.select(fresh.reduce((a, b) => (b.startedAt > a.startedAt ? b : a)).id);
36
35
  }
37
- refresh() {
36
+ /** Rows are the retained tasks matching `query`; an empty query matches all of them. */
37
+ refresh(query = "") {
38
38
  const { selectedId } = this.state;
39
39
  const active = this.all
40
40
  .filter((task) => !isTaskTerminal(task.status))
@@ -43,7 +43,7 @@ export class TaskSelection {
43
43
  .filter((task) => isTaskTerminal(task.status))
44
44
  .sort((a, b) => (b.endedAt ?? 0) - (a.endedAt ?? 0) || a.id.localeCompare(b.id));
45
45
  const rows = [...active, ...history];
46
- const search = this.query.toLocaleLowerCase().trim();
46
+ const search = query.toLocaleLowerCase().trim();
47
47
  this.rows = search
48
48
  ? rows.filter((task) => `${task.title}\n${task.input?.text ?? ""}\n${task.label}\n${task.kind}\n${task.id}`
49
49
  .toLocaleLowerCase()
@@ -1 +1 @@
1
- {"version":3,"file":"model.js","sourceRoot":"","sources":["../../../../src/extensions/tasks/ui/model.ts"],"names":[],"mappings":"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","sourcesContent":["import { isTaskTerminal, type TaskSnapshot } from \"../../../core/tasks/types.ts\";\nimport type { TaskViewport } from \"./viewport.ts\";\n\nexport type TasksTab = \"output\" | \"info\";\nexport type PanelFocus = \"list\" | \"inspector\";\n\n/**\n * The one transient layer over the browsing panel. Each layer owns its data, so a stale\n * combination (help over a confirmation, a restore point without a search) cannot exist.\n */\nexport type PanelMode =\n\t| { kind: \"browse\" }\n\t/** Searching moves focus to the list; `restore` is where Esc returns to. */\n\t| { kind: \"search\"; restore: { id?: string; focus: PanelFocus } }\n\t| { kind: \"confirmStop\"; taskId: string }\n\t| { kind: \"help\"; viewport: TaskViewport };\n\n/** A task can be asked to stop while it is neither settled nor already stopping. */\nexport function isStoppable(task: Pick<TaskSnapshot, \"status\">): boolean {\n\treturn !isTaskTerminal(task.status) && task.status !== \"stopping\";\n}\n\n/** Remember navigation within one runtime, without retaining output or execution handles. */\nexport interface TasksPanelState {\n\ttab: TasksTab;\n\tselectedId?: string;\n\t/** When the panel last closed; reopening selects work started since then. */\n\tclosedAt?: number;\n}\n\n/** Selection follows identity, including when its row moves from active work into history. */\nexport class TaskSelection {\n\treadonly state: TasksPanelState;\n\tall: TaskSnapshot[] = [];\n\trows: TaskSnapshot[] = [];\n\tquery = \"\";\n\tconstructor(state: TasksPanelState) {\n\t\tthis.state = state;\n\t}\n\tget selected(): TaskSnapshot | undefined {\n\t\treturn this.rows.find((task) => task.id === this.state.selectedId);\n\t}\n\tget activeCount(): number {\n\t\treturn this.all.filter((task) => !isTaskTerminal(task.status)).length;\n\t}\n\tsync(all: TaskSnapshot[]): void {\n\t\tthis.all = all;\n\t\tthis.refresh();\n\t}\n\tselect(id: string | undefined): void {\n\t\tthis.state.selectedId = id;\n\t\tthis.refresh();\n\t}\n\t/** On reopen, prefer the newest work started since the panel closed over the remembered row. */\n\tselectStartedSinceClose(): void {\n\t\tconst { closedAt } = this.state;\n\t\tif (closedAt === undefined) return;\n\t\tconst fresh = this.rows.filter((task) => task.startedAt > closedAt);\n\t\tif (fresh.length) this.select(fresh.reduce((a, b) => (b.startedAt > a.startedAt ? b : a)).id);\n\t}\n\trefresh(): void {\n\t\tconst { selectedId } = this.state;\n\t\tconst active = this.all\n\t\t\t.filter((task) => !isTaskTerminal(task.status))\n\t\t\t.sort((a, b) => b.startedAt - a.startedAt || a.id.localeCompare(b.id));\n\t\tconst history = this.all\n\t\t\t.filter((task) => isTaskTerminal(task.status))\n\t\t\t.sort((a, b) => (b.endedAt ?? 0) - (a.endedAt ?? 0) || a.id.localeCompare(b.id));\n\t\tconst rows = [...active, ...history];\n\t\tconst search = this.query.toLocaleLowerCase().trim();\n\t\tthis.rows = search\n\t\t\t? rows.filter((task) =>\n\t\t\t\t\t`${task.title}\\n${task.input?.text ?? \"\"}\\n${task.label}\\n${task.kind}\\n${task.id}`\n\t\t\t\t\t\t.toLocaleLowerCase()\n\t\t\t\t\t\t.includes(search),\n\t\t\t\t)\n\t\t\t: rows;\n\t\tif (!this.rows.some((task) => task.id === selectedId)) this.state.selectedId = this.rows[0]?.id;\n\t}\n}\n"]}
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../../../src/extensions/tasks/ui/model.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Input } from \"@earendil-works/pi-tui\";\nimport type { AppKeybinding } from \"../../../core/keybindings.ts\";\nimport { isTaskTerminal, type TaskSnapshot } from \"../../../core/tasks/types.ts\";\nimport type { TaskViewport } from \"./viewport.ts\";\n\nexport type TasksTab = \"output\" | \"info\";\nexport type PanelFocus = \"list\" | \"inspector\";\n\n/** What activating a rendered cell does; the manager dispatches on `kind` alone. */\nexport type TaskAction =\n\t| { kind: \"select\"; taskId: string }\n\t| { kind: \"tab\"; tab: TasksTab }\n\t| { kind: \"key\"; key: AppKeybinding }\n\t| { kind: \"open\" }\n\t/** Escape: unwind one layer, return from the inspector in a narrow terminal, or close the panel. */\n\t| { kind: \"back\" };\n\n/** A clickable row of cells on the screen and the action a click on it performs. */\nexport interface TaskHit {\n\tx: number;\n\ty: number;\n\twidth: number;\n\taction: TaskAction;\n}\n\n/**\n * The one transient layer over the browsing panel. Each layer owns its data, so a stale\n * combination (help over a confirmation, a restore point without a search) cannot exist.\n */\nexport type PanelMode =\n\t| { kind: \"browse\" }\n\t/** Searching moves focus to the list; `restore` is where Esc returns to. The input owns the query. */\n\t| { kind: \"search\"; restore: { id?: string; focus: PanelFocus }; input: Input }\n\t| { kind: \"confirmStop\"; taskId: string }\n\t| { kind: \"help\"; viewport: TaskViewport };\n\n/** A task can be asked to stop while it is neither settled nor already stopping. */\nexport function isStoppable(task: Pick<TaskSnapshot, \"status\">): boolean {\n\treturn !isTaskTerminal(task.status) && task.status !== \"stopping\";\n}\n\n/** Remember navigation within one runtime, without retaining output or execution handles. */\nexport interface TasksPanelState {\n\ttab: TasksTab;\n\tselectedId?: string;\n\t/** When the panel last closed; reopening selects work started since then. */\n\tclosedAt?: number;\n}\n\n/** Selection follows identity, including when its row moves from active work into history. */\nexport class TaskSelection {\n\treadonly state: TasksPanelState;\n\tall: TaskSnapshot[] = [];\n\trows: TaskSnapshot[] = [];\n\tconstructor(state: TasksPanelState) {\n\t\tthis.state = state;\n\t}\n\tget selected(): TaskSnapshot | undefined {\n\t\treturn this.rows.find((task) => task.id === this.state.selectedId);\n\t}\n\tget activeCount(): number {\n\t\treturn this.all.filter((task) => !isTaskTerminal(task.status)).length;\n\t}\n\tsync(all: TaskSnapshot[], query = \"\"): void {\n\t\tthis.all = all;\n\t\tthis.refresh(query);\n\t}\n\tselect(id: string | undefined, query = \"\"): void {\n\t\tthis.state.selectedId = id;\n\t\tthis.refresh(query);\n\t}\n\t/** On reopen, prefer the newest work started since the panel closed over the remembered row. */\n\tselectStartedSinceClose(): void {\n\t\tconst { closedAt } = this.state;\n\t\tif (closedAt === undefined) return;\n\t\tconst fresh = this.rows.filter((task) => task.startedAt > closedAt);\n\t\tif (fresh.length) this.select(fresh.reduce((a, b) => (b.startedAt > a.startedAt ? b : a)).id);\n\t}\n\t/** Rows are the retained tasks matching `query`; an empty query matches all of them. */\n\trefresh(query = \"\"): void {\n\t\tconst { selectedId } = this.state;\n\t\tconst active = this.all\n\t\t\t.filter((task) => !isTaskTerminal(task.status))\n\t\t\t.sort((a, b) => b.startedAt - a.startedAt || a.id.localeCompare(b.id));\n\t\tconst history = this.all\n\t\t\t.filter((task) => isTaskTerminal(task.status))\n\t\t\t.sort((a, b) => (b.endedAt ?? 0) - (a.endedAt ?? 0) || a.id.localeCompare(b.id));\n\t\tconst rows = [...active, ...history];\n\t\tconst search = query.toLocaleLowerCase().trim();\n\t\tthis.rows = search\n\t\t\t? rows.filter((task) =>\n\t\t\t\t\t`${task.title}\\n${task.input?.text ?? \"\"}\\n${task.label}\\n${task.kind}\\n${task.id}`\n\t\t\t\t\t\t.toLocaleLowerCase()\n\t\t\t\t\t\t.includes(search),\n\t\t\t\t)\n\t\t\t: rows;\n\t\tif (!this.rows.some((task) => task.id === selectedId)) this.state.selectedId = this.rows[0]?.id;\n\t}\n}\n"]}
@@ -0,0 +1,40 @@
1
+ import type { Keybinding } from "../../../core/keybindings.ts";
2
+ import type { Theme } from "../../../modes/interactive/theme/theme.ts";
3
+ import { type Rect } from "./frame.ts";
4
+ import type { TaskInspector } from "./inspector.ts";
5
+ import type { TaskList } from "./list.ts";
6
+ import type { TaskHit, TaskSelection } from "./model.ts";
7
+ export interface PaneRender {
8
+ lines: string[];
9
+ hits: TaskHit[];
10
+ }
11
+ interface PaneEnv {
12
+ theme: Theme;
13
+ selection: TaskSelection;
14
+ }
15
+ export interface ListPaneOptions {
16
+ /** The focused pane has an accented border. */
17
+ active: boolean;
18
+ /** Whether the rows can be clicked. */
19
+ interactive: boolean;
20
+ /** The rendered search input, shown as the first content row while searching. */
21
+ searchRow?: string;
22
+ /** The task a pending stop question is about. */
23
+ stopTargetId?: string;
24
+ }
25
+ /** Task rows between the borders, and how many tasks a page moves. */
26
+ export declare function renderListPane(env: PaneEnv & {
27
+ list: TaskList;
28
+ }, rect: Rect, options: ListPaneOptions): PaneRender & {
29
+ pageSize: number;
30
+ };
31
+ export interface InspectorPaneOptions {
32
+ active: boolean;
33
+ interactive: boolean;
34
+ }
35
+ export declare function renderInspectorPane(env: PaneEnv & {
36
+ inspector: TaskInspector;
37
+ hint: (key: Keybinding) => string;
38
+ }, rect: Rect, options: InspectorPaneOptions): PaneRender;
39
+ export {};
40
+ //# sourceMappingURL=panes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panes.d.ts","sourceRoot":"","sources":["../../../../src/extensions/tasks/ui/panes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAK/D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2CAA2C,CAAC;AACvE,OAAO,EAAa,KAAK,IAAI,EAAgB,MAAM,YAAY,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAY,MAAM,YAAY,CAAC;AAKnE,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,OAAO,EAAE,CAAC;CAChB;AAED,UAAU,OAAO;IAChB,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC/B,+CAA+C;IAC/C,MAAM,EAAE,OAAO,CAAC;IAChB,uCAAuC;IACvC,WAAW,EAAE,OAAO,CAAC;IACrB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAC7B,GAAG,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,EACjC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,eAAe,GACtB,UAAU,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAkCnC;AAED,MAAM,WAAW,oBAAoB;IACpC,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;CACrB;AA8BD,wBAAgB,mBAAmB,CAClC,GAAG,EAAE,OAAO,GAAG;IAAE,SAAS,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,MAAM,CAAA;CAAE,EAC9E,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,oBAAoB,GAC3B,UAAU,CA2EZ"}
@@ -0,0 +1,144 @@
1
+ /** The list and inspector panes. Each returns its own rows and only the hits it was asked to expose. */
2
+ import { visibleWidth } from "@earendil-works/pi-tui";
3
+ import { runtimeLabel } from "../../../core/tasks/format.js";
4
+ import { taskReadBytes } from "../../../core/tasks/output.js";
5
+ import { isTaskTerminal } from "../../../core/tasks/types.js";
6
+ import { formatSize } from "../../../core/tools/truncate.js";
7
+ import { framePane, TITLE_INDENT } from "./frame.js";
8
+ import { modeName, statusName, statusView } from "./status.js";
9
+ import { cleanTaskText, firstCommandLine } from "./text.js";
10
+ import { streamsLog } from "./views.js";
11
+ /** Task rows between the borders, and how many tasks a page moves. */
12
+ export function renderListPane(env, rect, options) {
13
+ const { theme, selection, list } = env;
14
+ const innerWidth = rect.width - 2;
15
+ const rowsHeight = Math.max(1, rect.height - 2 - (options.searchRow === undefined ? 0 : 1));
16
+ const visible = list.render(selection, theme, innerWidth, rowsHeight, options.stopTargetId);
17
+ const first = options.searchRow === undefined ? 0 : 1;
18
+ const hits = [];
19
+ if (options.interactive)
20
+ visible.forEach((row, index) => {
21
+ if (row.taskId)
22
+ hits.push({
23
+ x: rect.x + 1,
24
+ y: rect.y + 1 + first + index,
25
+ width: innerWidth,
26
+ action: { kind: "select", taskId: row.taskId },
27
+ });
28
+ });
29
+ const active = selection.rows.filter((task) => !isTaskTerminal(task.status)).length;
30
+ const finished = selection.rows.length - active;
31
+ const counts = [active ? `${active} active` : "", finished ? `${finished} finished` : ""].filter(Boolean);
32
+ const title = theme.fg("text", "Tasks") + (counts.length ? theme.fg("muted", ` · ${counts.join(" · ")}`) : "");
33
+ const rows = options.searchRow === undefined
34
+ ? visible.map((row) => row.text)
35
+ : [options.searchRow, ...visible.map((row) => row.text)];
36
+ const frame = framePane({
37
+ width: rect.width,
38
+ theme,
39
+ accent: options.active,
40
+ title,
41
+ status: list.range ? theme.fg("muted", list.range) : undefined,
42
+ rows: Array.from({ length: rect.height - 2 }, (_, i) => rows[i] ?? ""),
43
+ });
44
+ return { lines: frame.lines, hits, pageSize: Math.max(1, rowsHeight - 2) };
45
+ }
46
+ /** `Label · Status · Mode · runtime`, with the status in its own color. */
47
+ function metaLine(task, theme) {
48
+ return [
49
+ theme.fg("muted", cleanTaskText(task.label)),
50
+ theme.fg(statusView(task.status).color, statusName(task.status)),
51
+ theme.fg("muted", modeName(task.mode)),
52
+ theme.fg("muted", runtimeLabel(task)),
53
+ ]
54
+ .filter(Boolean)
55
+ .join(theme.fg("dim", " · "));
56
+ }
57
+ /** The log's reading state: following, browsing a held snapshot, or finished. Other output has none. */
58
+ function readingState(task, inspector, hint) {
59
+ const { output } = inspector.position;
60
+ const terminal = isTaskTerminal(task.status);
61
+ if (output.follow)
62
+ return { text: terminal ? "Finished" : "Live", followable: false };
63
+ const follow = hint("app.tasks.follow");
64
+ return {
65
+ text: terminal ? `Finished · ${follow} load final output` : `Browsing · ${follow} follow`,
66
+ followable: true,
67
+ };
68
+ }
69
+ export function renderInspectorPane(env, rect, options) {
70
+ const { theme, selection, inspector, hint } = env;
71
+ const innerWidth = rect.width - 2;
72
+ const innerHeight = rect.height - 2;
73
+ const task = inspector.task;
74
+ const tab = selection.state.tab;
75
+ const hits = [];
76
+ // The tabs live in the top border; hit boxes follow the rendered label widths.
77
+ const tabs = [
78
+ ["output", "Output"],
79
+ ["info", "Details"],
80
+ ];
81
+ let tabX = rect.x + TITLE_INDENT;
82
+ const title = tabs
83
+ .map(([id, label]) => {
84
+ if (options.interactive)
85
+ hits.push({ x: tabX, y: rect.y, width: visibleWidth(label), action: { kind: "tab", tab: id } });
86
+ tabX += visibleWidth(label) + 2;
87
+ return theme.style(label, tab === id ? { fg: "text", underline: true } : { fg: "muted" });
88
+ })
89
+ .join(" ");
90
+ const rows = [];
91
+ let status = "";
92
+ let followWidth = 0;
93
+ let divider;
94
+ if (task) {
95
+ // A bold title and the meta line form a header; a rule joined to the frame separates it from the tab.
96
+ rows.push(theme.style(cleanTaskText(firstCommandLine(task.title)), { fg: "text", bold: true }), metaLine(task, theme), "");
97
+ divider = rows.length - 1;
98
+ const position = inspector.position;
99
+ const read = position.read;
100
+ const diagnostics = [task.error, read?.readError].filter((text) => !!text).map(cleanTaskText);
101
+ if (tab === "output" && diagnostics.length)
102
+ rows.push(theme.fg("warning", diagnostics.join(" · ").replace(/\n/g, " ")));
103
+ const body = Math.max(1, innerHeight - rows.length);
104
+ if (tab === "info") {
105
+ rows.push(...position.info.layout(inspector.details(innerWidth), innerWidth, body));
106
+ if (position.info.overflows)
107
+ status = theme.fg("muted", position.info.range);
108
+ }
109
+ else {
110
+ rows.push(...position.output.layout(inspector.output(innerWidth), innerWidth, body));
111
+ // Only a log has a reading state; a published result is always the current one.
112
+ if (streamsLog(task)) {
113
+ const reading = readingState(task, inspector, hint);
114
+ status = theme.fg("muted", reading.text);
115
+ if (read?.truncated)
116
+ status += theme.fg("muted", ` · Tail preview: ${formatSize(taskReadBytes(read))} of ${formatSize(read.totalBytes)}`);
117
+ followWidth = reading.followable ? visibleWidth(reading.text) : 0;
118
+ }
119
+ else if (position.output.overflows)
120
+ status = theme.fg("muted", position.output.range);
121
+ }
122
+ }
123
+ else
124
+ rows.push(theme.fg("muted", "Select a task to inspect its result."));
125
+ const frame = framePane({
126
+ width: rect.width,
127
+ theme,
128
+ accent: options.active,
129
+ title,
130
+ status: status || undefined,
131
+ rows: Array.from({ length: innerHeight }, (_, i) => rows[i] ?? ""),
132
+ divider,
133
+ });
134
+ // The held-snapshot state is itself the control that resumes following.
135
+ if (options.interactive && followWidth)
136
+ hits.push({
137
+ x: rect.x + frame.status.x,
138
+ y: rect.y + rect.height - 1,
139
+ width: Math.min(followWidth, frame.status.width),
140
+ action: { kind: "key", key: "app.tasks.follow" },
141
+ });
142
+ return { lines: frame.lines, hits };
143
+ }
144
+ //# sourceMappingURL=panes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panes.js","sourceRoot":"","sources":["../../../../src/extensions/tasks/ui/panes.ts"],"names":[],"mappings":"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","sourcesContent":["/** The list and inspector panes. Each returns its own rows and only the hits it was asked to expose. */\nimport { visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { Keybinding } from \"../../../core/keybindings.ts\";\nimport { runtimeLabel } from \"../../../core/tasks/format.ts\";\nimport { taskReadBytes } from \"../../../core/tasks/output.ts\";\nimport { isTaskTerminal, type TaskSnapshot } from \"../../../core/tasks/types.ts\";\nimport { formatSize } from \"../../../core/tools/truncate.ts\";\nimport type { Theme } from \"../../../modes/interactive/theme/theme.ts\";\nimport { framePane, type Rect, TITLE_INDENT } from \"./frame.ts\";\nimport type { TaskInspector } from \"./inspector.ts\";\nimport type { TaskList } from \"./list.ts\";\nimport type { TaskHit, TaskSelection, TasksTab } from \"./model.ts\";\nimport { modeName, statusName, statusView } from \"./status.ts\";\nimport { cleanTaskText, firstCommandLine } from \"./text.ts\";\nimport { streamsLog } from \"./views.ts\";\n\nexport interface PaneRender {\n\tlines: string[];\n\thits: TaskHit[];\n}\n\ninterface PaneEnv {\n\ttheme: Theme;\n\tselection: TaskSelection;\n}\n\nexport interface ListPaneOptions {\n\t/** The focused pane has an accented border. */\n\tactive: boolean;\n\t/** Whether the rows can be clicked. */\n\tinteractive: boolean;\n\t/** The rendered search input, shown as the first content row while searching. */\n\tsearchRow?: string;\n\t/** The task a pending stop question is about. */\n\tstopTargetId?: string;\n}\n\n/** Task rows between the borders, and how many tasks a page moves. */\nexport function renderListPane(\n\tenv: PaneEnv & { list: TaskList },\n\trect: Rect,\n\toptions: ListPaneOptions,\n): PaneRender & { pageSize: number } {\n\tconst { theme, selection, list } = env;\n\tconst innerWidth = rect.width - 2;\n\tconst rowsHeight = Math.max(1, rect.height - 2 - (options.searchRow === undefined ? 0 : 1));\n\tconst visible = list.render(selection, theme, innerWidth, rowsHeight, options.stopTargetId);\n\tconst first = options.searchRow === undefined ? 0 : 1;\n\tconst hits: TaskHit[] = [];\n\tif (options.interactive)\n\t\tvisible.forEach((row, index) => {\n\t\t\tif (row.taskId)\n\t\t\t\thits.push({\n\t\t\t\t\tx: rect.x + 1,\n\t\t\t\t\ty: rect.y + 1 + first + index,\n\t\t\t\t\twidth: innerWidth,\n\t\t\t\t\taction: { kind: \"select\", taskId: row.taskId },\n\t\t\t\t});\n\t\t});\n\tconst active = selection.rows.filter((task) => !isTaskTerminal(task.status)).length;\n\tconst finished = selection.rows.length - active;\n\tconst counts = [active ? `${active} active` : \"\", finished ? `${finished} finished` : \"\"].filter(Boolean);\n\tconst title = theme.fg(\"text\", \"Tasks\") + (counts.length ? theme.fg(\"muted\", ` · ${counts.join(\" · \")}`) : \"\");\n\tconst rows =\n\t\toptions.searchRow === undefined\n\t\t\t? visible.map((row) => row.text)\n\t\t\t: [options.searchRow, ...visible.map((row) => row.text)];\n\tconst frame = framePane({\n\t\twidth: rect.width,\n\t\ttheme,\n\t\taccent: options.active,\n\t\ttitle,\n\t\tstatus: list.range ? theme.fg(\"muted\", list.range) : undefined,\n\t\trows: Array.from({ length: rect.height - 2 }, (_, i) => rows[i] ?? \"\"),\n\t});\n\treturn { lines: frame.lines, hits, pageSize: Math.max(1, rowsHeight - 2) };\n}\n\nexport interface InspectorPaneOptions {\n\tactive: boolean;\n\tinteractive: boolean;\n}\n\n/** `Label · Status · Mode · runtime`, with the status in its own color. */\nfunction metaLine(task: TaskSnapshot, theme: Theme): string {\n\treturn [\n\t\ttheme.fg(\"muted\", cleanTaskText(task.label)),\n\t\ttheme.fg(statusView(task.status).color, statusName(task.status)),\n\t\ttheme.fg(\"muted\", modeName(task.mode)),\n\t\ttheme.fg(\"muted\", runtimeLabel(task)),\n\t]\n\t\t.filter(Boolean)\n\t\t.join(theme.fg(\"dim\", \" · \"));\n}\n\n/** The log's reading state: following, browsing a held snapshot, or finished. Other output has none. */\nfunction readingState(\n\ttask: TaskSnapshot,\n\tinspector: TaskInspector,\n\thint: (key: Keybinding) => string,\n): { text: string; followable: boolean } {\n\tconst { output } = inspector.position;\n\tconst terminal = isTaskTerminal(task.status);\n\tif (output.follow) return { text: terminal ? \"Finished\" : \"Live\", followable: false };\n\tconst follow = hint(\"app.tasks.follow\");\n\treturn {\n\t\ttext: terminal ? `Finished · ${follow} load final output` : `Browsing · ${follow} follow`,\n\t\tfollowable: true,\n\t};\n}\n\nexport function renderInspectorPane(\n\tenv: PaneEnv & { inspector: TaskInspector; hint: (key: Keybinding) => string },\n\trect: Rect,\n\toptions: InspectorPaneOptions,\n): PaneRender {\n\tconst { theme, selection, inspector, hint } = env;\n\tconst innerWidth = rect.width - 2;\n\tconst innerHeight = rect.height - 2;\n\tconst task = inspector.task;\n\tconst tab = selection.state.tab;\n\tconst hits: TaskHit[] = [];\n\t// The tabs live in the top border; hit boxes follow the rendered label widths.\n\tconst tabs: Array<[TasksTab, string]> = [\n\t\t[\"output\", \"Output\"],\n\t\t[\"info\", \"Details\"],\n\t];\n\tlet tabX = rect.x + TITLE_INDENT;\n\tconst title = tabs\n\t\t.map(([id, label]) => {\n\t\t\tif (options.interactive)\n\t\t\t\thits.push({ x: tabX, y: rect.y, width: visibleWidth(label), action: { kind: \"tab\", tab: id } });\n\t\t\ttabX += visibleWidth(label) + 2;\n\t\t\treturn theme.style(label, tab === id ? { fg: \"text\", underline: true } : { fg: \"muted\" });\n\t\t})\n\t\t.join(\" \");\n\tconst rows: string[] = [];\n\tlet status = \"\";\n\tlet followWidth = 0;\n\tlet divider: number | undefined;\n\tif (task) {\n\t\t// A bold title and the meta line form a header; a rule joined to the frame separates it from the tab.\n\t\trows.push(\n\t\t\ttheme.style(cleanTaskText(firstCommandLine(task.title)), { fg: \"text\", bold: true }),\n\t\t\tmetaLine(task, theme),\n\t\t\t\"\",\n\t\t);\n\t\tdivider = rows.length - 1;\n\t\tconst position = inspector.position;\n\t\tconst read = position.read;\n\t\tconst diagnostics = [task.error, read?.readError].filter((text): text is string => !!text).map(cleanTaskText);\n\t\tif (tab === \"output\" && diagnostics.length)\n\t\t\trows.push(theme.fg(\"warning\", diagnostics.join(\" · \").replace(/\\n/g, \" \")));\n\t\tconst body = Math.max(1, innerHeight - rows.length);\n\t\tif (tab === \"info\") {\n\t\t\trows.push(...position.info.layout(inspector.details(innerWidth), innerWidth, body));\n\t\t\tif (position.info.overflows) status = theme.fg(\"muted\", position.info.range);\n\t\t} else {\n\t\t\trows.push(...position.output.layout(inspector.output(innerWidth), innerWidth, body));\n\t\t\t// Only a log has a reading state; a published result is always the current one.\n\t\t\tif (streamsLog(task)) {\n\t\t\t\tconst reading = readingState(task, inspector, hint);\n\t\t\t\tstatus = theme.fg(\"muted\", reading.text);\n\t\t\t\tif (read?.truncated)\n\t\t\t\t\tstatus += theme.fg(\n\t\t\t\t\t\t\"muted\",\n\t\t\t\t\t\t` · Tail preview: ${formatSize(taskReadBytes(read))} of ${formatSize(read.totalBytes)}`,\n\t\t\t\t\t);\n\t\t\t\tfollowWidth = reading.followable ? visibleWidth(reading.text) : 0;\n\t\t\t} else if (position.output.overflows) status = theme.fg(\"muted\", position.output.range);\n\t\t}\n\t} else rows.push(theme.fg(\"muted\", \"Select a task to inspect its result.\"));\n\tconst frame = framePane({\n\t\twidth: rect.width,\n\t\ttheme,\n\t\taccent: options.active,\n\t\ttitle,\n\t\tstatus: status || undefined,\n\t\trows: Array.from({ length: innerHeight }, (_, i) => rows[i] ?? \"\"),\n\t\tdivider,\n\t});\n\t// The held-snapshot state is itself the control that resumes following.\n\tif (options.interactive && followWidth)\n\t\thits.push({\n\t\t\tx: rect.x + frame.status.x,\n\t\t\ty: rect.y + rect.height - 1,\n\t\t\twidth: Math.min(followWidth, frame.status.width),\n\t\t\taction: { kind: \"key\", key: \"app.tasks.follow\" },\n\t\t});\n\treturn { lines: frame.lines, hits };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../../src/extensions/tasks/ui/render.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAElG,OAAO,EAAE,KAAK,SAAS,EAAkC,MAAM,wBAAwB,CAAC;AACxF,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAIrH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2CAA2C,CAAC;AAEvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD,wEAAwE;AACxE,KAAK,gBAAgB,GAAG,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAOzE,uEAAuE;AACvE,MAAM,WAAW,gBAAgB;IAChC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;IAC7C,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAmBxG;AASD,wBAAgB,eAAe,CAC9B,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,GAC1C,SAAS,CA0BX;AAkCD,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,eAAe,CAAC,YAAY,GAAG,SAAS,CAAC,EACjD,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,GAC1C,SAAS,CAoBX"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../../src/extensions/tasks/ui/render.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAElG,OAAO,EAAE,KAAK,SAAS,EAAkC,MAAM,wBAAwB,CAAC;AACxF,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAIrH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2CAA2C,CAAC;AAEvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD,wEAAwE;AACxE,KAAK,gBAAgB,GAAG,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAOzE,uEAAuE;AACvE,MAAM,WAAW,gBAAgB;IAChC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;IAC7C,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAmBxG;AAUD,wBAAgB,eAAe,CAC9B,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,GAC1C,SAAS,CA2BX;AAkCD,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,eAAe,CAAC,YAAY,GAAG,SAAS,CAAC,EACjD,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,GAC1C,SAAS,CAuBX"}
@@ -36,17 +36,20 @@ export function scheduleWaitRefresh(context, pending) {
36
36
  }
37
37
  state.waitStartedAt = undefined;
38
38
  }
39
- /** Keep the END of oversized text — that is where the outcome lives. */
40
- function capForTranscript(text, limit) {
41
- return text.length > limit ? `…${text.slice(-limit)}` : text;
39
+ /** Keep the end that was read: a report's summary or a log's outcome. */
40
+ function capForTranscript(text, limit, mode = "tail") {
41
+ if (text.length <= limit)
42
+ return text;
43
+ return mode === "head" ? `${text.slice(0, limit)}…` : `…${text.slice(-limit)}`;
42
44
  }
43
45
  // ── tool call ─────────────────────────────────────────────────────────────
44
46
  export function renderTasksCall(args, theme, context) {
45
47
  switch (args.action) {
46
48
  case "read": {
47
- const mode = args.mode ?? "tail";
49
+ // The default end depends on the task's output kind, which the call does not carry.
50
+ const mode = args.mode ? ` ${args.mode}` : "";
48
51
  const size = args.bytes !== undefined ? ` ${formatSize(args.bytes)}` : "";
49
- return new Text(`${theme.fg("toolTitle", theme.bold("tasks read "))}${theme.fg("accent", args.taskId ?? "")}${theme.fg("muted", ` ${mode}${size}`)}`, 0, 0);
52
+ return new Text(`${theme.fg("toolTitle", theme.bold("tasks read "))}${theme.fg("accent", args.taskId ?? "")}${theme.fg("muted", `${mode}${size}`)}`, 0, 0);
50
53
  }
51
54
  case "wait":
52
55
  return renderWaitCall(args, theme, context);
@@ -91,7 +94,7 @@ export function renderTasksResult(result, options, theme, context) {
91
94
  const details = result.details;
92
95
  // Results from older tool versions, such as `bg create`, keep their saved text.
93
96
  const summary = details && !context.isError ? resultSummaryLine(details, theme, options.expanded) : undefined;
94
- if (summary === undefined) {
97
+ if (summary === undefined || details === undefined) {
95
98
  const text = result.content.find((part) => part.type === "text")?.text ?? "";
96
99
  return new Text(theme.fg("toolOutput", text.trimEnd()), 0, 0);
97
100
  }
@@ -99,8 +102,9 @@ export function renderTasksResult(result, options, theme, context) {
99
102
  container.addChild(new TruncatedText(summary, 1, 0));
100
103
  if (options.expanded) {
101
104
  const text = result.content.find((part) => part.type === "text")?.text ?? "";
105
+ const mode = details.action === "read" || details.action === "wait" ? details.mode : undefined;
102
106
  container.addChild(new Text("", 0, 0));
103
- container.addChild(new Text(theme.fg("toolOutput", capForTranscript(text, RESULT_EXPAND_LIMIT).trimEnd()), 1, 0));
107
+ container.addChild(new Text(theme.fg("toolOutput", capForTranscript(text, RESULT_EXPAND_LIMIT, mode).trimEnd()), 1, 0));
104
108
  }
105
109
  return container;
106
110
  }
@@ -1 +1 @@
1
- {"version":3,"file":"render.js","sourceRoot":"","sources":["../../../../src/extensions/tasks/ui/render.ts"],"names":[],"mappings":"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","sourcesContent":["/** Transcript rendering for the native tasks tool: its call/result rows, dispatched on action. */\n\nimport { type Component, Container, Text, TruncatedText } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult, ToolRenderContext, ToolRenderResultOptions } from \"../../../core/extensions/types.ts\";\nimport { clampWaitMs } from \"../../../core/tasks/limits.ts\";\nimport type { TaskStatus } from \"../../../core/tasks/types.ts\";\nimport { formatSize } from \"../../../core/tools/truncate.ts\";\nimport type { Theme } from \"../../../modes/interactive/theme/theme.ts\";\nimport { formatDuration } from \"../../../utils/duration.ts\";\nimport type { TasksInput } from \"../tool/schema.ts\";\nimport type { TasksDetails } from \"../tool/types.ts\";\nimport { statusName, statusView } from \"./status.ts\";\nimport { fileNameOf } from \"./text.ts\";\n\n/** Arguments arrive incrementally, so `action` may not be valid yet. */\ntype TasksRenderInput = Omit<TasksInput, \"action\"> & { action?: string };\n\n/** Cap for expanded transcript views of tool-result text (already bounded at the source). */\nconst RESULT_EXPAND_LIMIT = 4000;\n/** Live pending-wait line refresh cadence; the first settled render clears the timer. */\nconst WAIT_REFRESH_MS = 1000;\n\n/** Per-call live-refresh state owned by the shell's render context. */\nexport interface TasksRenderState {\n\tdispose?: () => void;\n\trefreshTimer?: ReturnType<typeof setTimeout>;\n\t/** First pending render of a wait call; anchors the elapsed display. */\n\twaitStartedAt?: number;\n}\n\n/**\n * Arm a one-shot 1s refresh while a wait call is pending, clear it once\n * settled. The timer fires → context.invalidate() → renderCall re-runs →\n * re-arms, so at most one armed timer exists per tool row. Unref'd: it can\n * never hold the process open.\n */\nexport function scheduleWaitRefresh(context: ToolRenderContext<TasksRenderState>, pending: boolean): void {\n\tconst state = context.state;\n\tif (state === undefined) return; // Standalone render without shell state: nothing to schedule.\n\tif (pending) {\n\t\tstate.dispose = () => scheduleWaitRefresh(context, false);\n\t\tif (state.refreshTimer === undefined) {\n\t\t\tstate.refreshTimer = setTimeout(() => {\n\t\t\t\tstate.refreshTimer = undefined;\n\t\t\t\tcontext.invalidate();\n\t\t\t}, WAIT_REFRESH_MS);\n\t\t\tstate.refreshTimer.unref?.();\n\t\t}\n\t\treturn;\n\t}\n\tif (state.refreshTimer !== undefined) {\n\t\tclearTimeout(state.refreshTimer);\n\t\tstate.refreshTimer = undefined;\n\t}\n\tstate.waitStartedAt = undefined;\n}\n\n/** Keep the END of oversized text — that is where the outcome lives. */\nfunction capForTranscript(text: string, limit: number): string {\n\treturn text.length > limit ? `…${text.slice(-limit)}` : text;\n}\n\n// ── tool call ─────────────────────────────────────────────────────────────\n\nexport function renderTasksCall(\n\targs: TasksRenderInput,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<TasksRenderState>,\n): Component {\n\tswitch (args.action) {\n\t\tcase \"read\": {\n\t\t\tconst mode = args.mode ?? \"tail\";\n\t\t\tconst size = args.bytes !== undefined ? ` ${formatSize(args.bytes)}` : \"\";\n\t\t\treturn new Text(\n\t\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"tasks read \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}${theme.fg(\"muted\", ` ${mode}${size}`)}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t);\n\t\t}\n\t\tcase \"wait\":\n\t\t\treturn renderWaitCall(args, theme, context);\n\t\tcase \"kill\":\n\t\t\treturn new Text(\n\t\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"tasks kill \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t);\n\t\tcase \"list\":\n\t\t\treturn new Text(theme.fg(\"toolTitle\", theme.bold(\"tasks list\")), 0, 0);\n\t\tdefault: {\n\t\t\tconst action = typeof args.action === \"string\" ? ` ${theme.fg(\"dim\", args.action)}` : \"\";\n\t\t\treturn new Text(`${theme.fg(\"toolTitle\", theme.bold(\"tasks\"))}${action}`, 0, 0);\n\t\t}\n\t}\n}\n\n/**\n * Pending wait call: elapsed/wait-window, refreshed once per second by\n * scheduleWaitRefresh until the result settles and takes over the row.\n */\nfunction renderWaitCall(args: TasksRenderInput, theme: Theme, context: ToolRenderContext<TasksRenderState>): Component {\n\tconst taskId = typeof args.taskId === \"string\" ? args.taskId.trim() : \"\";\n\t// isPartial alone means \"not settled\", which also covers argument streaming\n\t// and replayed history rows that never settle; executionStarted narrows it to\n\t// a call that is actually running. The live display also needs shell-owned\n\t// state; without it (standalone renders) fall back to the static line.\n\tconst pending = context.executionStarted === true && context.isPartial === true && context.state !== undefined;\n\tscheduleWaitRefresh(context, pending);\n\tif (!pending) {\n\t\tconst ms = args.waitMs !== undefined ? ` ${formatDuration(clampWaitMs(args.waitMs))}` : \"\";\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"tasks wait \"))}${theme.fg(\"accent\", taskId || \"any\")}${theme.fg(\"muted\", ms)}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tconst state = context.state;\n\tif (state.waitStartedAt === undefined) state.waitStartedAt = Date.now();\n\tconst elapsed = `waiting ${formatDuration(Date.now() - state.waitStartedAt)} / ${formatDuration(clampWaitMs(args.waitMs))}`;\n\treturn new Text(\n\t\t`${theme.fg(\"toolTitle\", theme.bold(\"tasks wait \"))}${theme.fg(\"accent\", taskId || \"any\")} ${theme.fg(\"muted\", elapsed)}`,\n\t\t0,\n\t\t0,\n\t);\n}\n\n// ── tool result ───────────────────────────────────────────────────────────\n\nexport function renderTasksResult(\n\tresult: AgentToolResult<TasksDetails | undefined>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<TasksRenderState>,\n): Component {\n\t// Results are always settled today; clear defensively so no live-refresh\n\t// timer can outlive its row if a host ever streams partial results.\n\tif (context.args?.action === \"wait\" && !options.isPartial) scheduleWaitRefresh(context, false);\n\tconst details = result.details;\n\t// Results from older tool versions, such as `bg create`, keep their saved text.\n\tconst summary = details && !context.isError ? resultSummaryLine(details, theme, options.expanded) : undefined;\n\tif (summary === undefined) {\n\t\tconst text = result.content.find((part) => part.type === \"text\")?.text ?? \"\";\n\t\treturn new Text(theme.fg(\"toolOutput\", text.trimEnd()), 0, 0);\n\t}\n\n\tconst container = new Container();\n\tcontainer.addChild(new TruncatedText(summary, 1, 0));\n\tif (options.expanded) {\n\t\tconst text = result.content.find((part) => part.type === \"text\")?.text ?? \"\";\n\t\tcontainer.addChild(new Text(\"\", 0, 0));\n\t\tcontainer.addChild(new Text(theme.fg(\"toolOutput\", capForTranscript(text, RESULT_EXPAND_LIMIT).trimEnd()), 1, 0));\n\t}\n\treturn container;\n}\n\nfunction resultSummaryLine(details: TasksDetails, theme: Theme, expanded: boolean): string | undefined {\n\t// Collapsed rows stay compact with the log's file name; the full path\n\t// (context-relevant, human-rarely) shows when expanded.\n\tconst shownPath = (path: string) => (expanded ? path : fileNameOf(path));\n\tconst mark = (status: TaskStatus) => {\n\t\tconst { color, glyph } = statusView(status);\n\t\treturn theme.fg(color, glyph);\n\t};\n\tswitch (details.action) {\n\t\tcase \"read\": {\n\t\t\tconst size =\n\t\t\t\tdetails.sliceBytes !== details.totalBytes\n\t\t\t\t\t? `${details.mode} ${formatSize(details.sliceBytes)} of ${formatSize(details.totalBytes)}`\n\t\t\t\t\t: formatSize(details.totalBytes);\n\t\t\treturn `${theme.fg(\"muted\", \"→ \")}${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", `${details.status ? ` ${statusName(details.status)} ·` : \"\"} ${size}${details.outputPath ? ` · ${shownPath(details.outputPath)}` : \"\"}`)}`;\n\t\t}\n\t\tcase \"wait\": {\n\t\t\tconst outcome = details.outcome;\n\t\t\tif (outcome === \"no_tasks\") return theme.fg(\"muted\", \"→ No background tasks running\");\n\t\t\tconst taskId = details.taskId ?? \"any\";\n\t\t\tif (outcome === \"interrupted\") {\n\t\t\t\tconst running = details.running ? ` · ${details.running} still running` : \"\";\n\t\t\t\treturn `${mark(\"cancelled\")} ${theme.fg(\"accent\", taskId)}${theme.fg(\"muted\", ` wait interrupted after ${formatDuration(details.waitedMs)}${running}`)}`;\n\t\t\t}\n\t\t\tif (outcome === \"timed_out\") {\n\t\t\t\tconst status = details.status ?? \"running\";\n\t\t\t\tconst running = details.taskId ? formatSize(details.totalBytes) : `${details.running ?? 0} still running`;\n\t\t\t\treturn `${mark(status)} ${theme.fg(\"accent\", taskId)}${theme.fg(\"muted\", ` ${statusName(status)} · wait ended after ${formatDuration(details.waitedMs)} · ${running}`)}`;\n\t\t\t}\n\t\t\tconst status = details.status ?? \"completed\";\n\t\t\treturn `${mark(status)} ${theme.fg(\"accent\", taskId)}${theme.fg(\"muted\", ` ${statusName(status)} · waited ${formatDuration(details.waitedMs)} · +${formatSize(details.deltaBytes)}`)}`;\n\t\t}\n\t\tcase \"kill\": {\n\t\t\tconst status = details.status ?? (details.requested ? \"stopping\" : \"cancelled\");\n\t\t\treturn `${mark(status)} ${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", ` ${statusName(status)}${details.requested ? \" · cancellation requested\" : \"\"}`)}`;\n\t\t}\n\t\tcase \"list\": {\n\t\t\tconst hidden = details.hidden > 0 ? ` · ${details.hidden} more finished` : \"\";\n\t\t\tconst omitted = details.foregroundOmitted ? ` · ${details.foregroundOmitted} foreground omitted` : \"\";\n\t\t\treturn theme.fg(\"muted\", `${details.running} running · ${details.finished} finished${hidden}${omitted}`);\n\t\t}\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../../../src/extensions/tasks/ui/render.ts"],"names":[],"mappings":"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","sourcesContent":["/** Transcript rendering for the native tasks tool: its call/result rows, dispatched on action. */\n\nimport { type Component, Container, Text, TruncatedText } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult, ToolRenderContext, ToolRenderResultOptions } from \"../../../core/extensions/types.ts\";\nimport { clampWaitMs } from \"../../../core/tasks/limits.ts\";\nimport type { TaskStatus } from \"../../../core/tasks/types.ts\";\nimport { formatSize } from \"../../../core/tools/truncate.ts\";\nimport type { Theme } from \"../../../modes/interactive/theme/theme.ts\";\nimport { formatDuration } from \"../../../utils/duration.ts\";\nimport type { TasksInput } from \"../tool/schema.ts\";\nimport type { TasksDetails } from \"../tool/types.ts\";\nimport { statusName, statusView } from \"./status.ts\";\nimport { fileNameOf } from \"./text.ts\";\n\n/** Arguments arrive incrementally, so `action` may not be valid yet. */\ntype TasksRenderInput = Omit<TasksInput, \"action\"> & { action?: string };\n\n/** Cap for expanded transcript views of tool-result text (already bounded at the source). */\nconst RESULT_EXPAND_LIMIT = 4000;\n/** Live pending-wait line refresh cadence; the first settled render clears the timer. */\nconst WAIT_REFRESH_MS = 1000;\n\n/** Per-call live-refresh state owned by the shell's render context. */\nexport interface TasksRenderState {\n\tdispose?: () => void;\n\trefreshTimer?: ReturnType<typeof setTimeout>;\n\t/** First pending render of a wait call; anchors the elapsed display. */\n\twaitStartedAt?: number;\n}\n\n/**\n * Arm a one-shot 1s refresh while a wait call is pending, clear it once\n * settled. The timer fires → context.invalidate() → renderCall re-runs →\n * re-arms, so at most one armed timer exists per tool row. Unref'd: it can\n * never hold the process open.\n */\nexport function scheduleWaitRefresh(context: ToolRenderContext<TasksRenderState>, pending: boolean): void {\n\tconst state = context.state;\n\tif (state === undefined) return; // Standalone render without shell state: nothing to schedule.\n\tif (pending) {\n\t\tstate.dispose = () => scheduleWaitRefresh(context, false);\n\t\tif (state.refreshTimer === undefined) {\n\t\t\tstate.refreshTimer = setTimeout(() => {\n\t\t\t\tstate.refreshTimer = undefined;\n\t\t\t\tcontext.invalidate();\n\t\t\t}, WAIT_REFRESH_MS);\n\t\t\tstate.refreshTimer.unref?.();\n\t\t}\n\t\treturn;\n\t}\n\tif (state.refreshTimer !== undefined) {\n\t\tclearTimeout(state.refreshTimer);\n\t\tstate.refreshTimer = undefined;\n\t}\n\tstate.waitStartedAt = undefined;\n}\n\n/** Keep the end that was read: a report's summary or a log's outcome. */\nfunction capForTranscript(text: string, limit: number, mode: \"head\" | \"tail\" = \"tail\"): string {\n\tif (text.length <= limit) return text;\n\treturn mode === \"head\" ? `${text.slice(0, limit)}…` : `…${text.slice(-limit)}`;\n}\n\n// ── tool call ─────────────────────────────────────────────────────────────\n\nexport function renderTasksCall(\n\targs: TasksRenderInput,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<TasksRenderState>,\n): Component {\n\tswitch (args.action) {\n\t\tcase \"read\": {\n\t\t\t// The default end depends on the task's output kind, which the call does not carry.\n\t\t\tconst mode = args.mode ? ` ${args.mode}` : \"\";\n\t\t\tconst size = args.bytes !== undefined ? ` ${formatSize(args.bytes)}` : \"\";\n\t\t\treturn new Text(\n\t\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"tasks read \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}${theme.fg(\"muted\", `${mode}${size}`)}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t);\n\t\t}\n\t\tcase \"wait\":\n\t\t\treturn renderWaitCall(args, theme, context);\n\t\tcase \"kill\":\n\t\t\treturn new Text(\n\t\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"tasks kill \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t);\n\t\tcase \"list\":\n\t\t\treturn new Text(theme.fg(\"toolTitle\", theme.bold(\"tasks list\")), 0, 0);\n\t\tdefault: {\n\t\t\tconst action = typeof args.action === \"string\" ? ` ${theme.fg(\"dim\", args.action)}` : \"\";\n\t\t\treturn new Text(`${theme.fg(\"toolTitle\", theme.bold(\"tasks\"))}${action}`, 0, 0);\n\t\t}\n\t}\n}\n\n/**\n * Pending wait call: elapsed/wait-window, refreshed once per second by\n * scheduleWaitRefresh until the result settles and takes over the row.\n */\nfunction renderWaitCall(args: TasksRenderInput, theme: Theme, context: ToolRenderContext<TasksRenderState>): Component {\n\tconst taskId = typeof args.taskId === \"string\" ? args.taskId.trim() : \"\";\n\t// isPartial alone means \"not settled\", which also covers argument streaming\n\t// and replayed history rows that never settle; executionStarted narrows it to\n\t// a call that is actually running. The live display also needs shell-owned\n\t// state; without it (standalone renders) fall back to the static line.\n\tconst pending = context.executionStarted === true && context.isPartial === true && context.state !== undefined;\n\tscheduleWaitRefresh(context, pending);\n\tif (!pending) {\n\t\tconst ms = args.waitMs !== undefined ? ` ${formatDuration(clampWaitMs(args.waitMs))}` : \"\";\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"tasks wait \"))}${theme.fg(\"accent\", taskId || \"any\")}${theme.fg(\"muted\", ms)}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tconst state = context.state;\n\tif (state.waitStartedAt === undefined) state.waitStartedAt = Date.now();\n\tconst elapsed = `waiting ${formatDuration(Date.now() - state.waitStartedAt)} / ${formatDuration(clampWaitMs(args.waitMs))}`;\n\treturn new Text(\n\t\t`${theme.fg(\"toolTitle\", theme.bold(\"tasks wait \"))}${theme.fg(\"accent\", taskId || \"any\")} ${theme.fg(\"muted\", elapsed)}`,\n\t\t0,\n\t\t0,\n\t);\n}\n\n// ── tool result ───────────────────────────────────────────────────────────\n\nexport function renderTasksResult(\n\tresult: AgentToolResult<TasksDetails | undefined>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<TasksRenderState>,\n): Component {\n\t// Results are always settled today; clear defensively so no live-refresh\n\t// timer can outlive its row if a host ever streams partial results.\n\tif (context.args?.action === \"wait\" && !options.isPartial) scheduleWaitRefresh(context, false);\n\tconst details = result.details;\n\t// Results from older tool versions, such as `bg create`, keep their saved text.\n\tconst summary = details && !context.isError ? resultSummaryLine(details, theme, options.expanded) : undefined;\n\tif (summary === undefined || details === undefined) {\n\t\tconst text = result.content.find((part) => part.type === \"text\")?.text ?? \"\";\n\t\treturn new Text(theme.fg(\"toolOutput\", text.trimEnd()), 0, 0);\n\t}\n\n\tconst container = new Container();\n\tcontainer.addChild(new TruncatedText(summary, 1, 0));\n\tif (options.expanded) {\n\t\tconst text = result.content.find((part) => part.type === \"text\")?.text ?? \"\";\n\t\tconst mode = details.action === \"read\" || details.action === \"wait\" ? details.mode : undefined;\n\t\tcontainer.addChild(new Text(\"\", 0, 0));\n\t\tcontainer.addChild(\n\t\t\tnew Text(theme.fg(\"toolOutput\", capForTranscript(text, RESULT_EXPAND_LIMIT, mode).trimEnd()), 1, 0),\n\t\t);\n\t}\n\treturn container;\n}\n\nfunction resultSummaryLine(details: TasksDetails, theme: Theme, expanded: boolean): string | undefined {\n\t// Collapsed rows stay compact with the log's file name; the full path\n\t// (context-relevant, human-rarely) shows when expanded.\n\tconst shownPath = (path: string) => (expanded ? path : fileNameOf(path));\n\tconst mark = (status: TaskStatus) => {\n\t\tconst { color, glyph } = statusView(status);\n\t\treturn theme.fg(color, glyph);\n\t};\n\tswitch (details.action) {\n\t\tcase \"read\": {\n\t\t\tconst size =\n\t\t\t\tdetails.sliceBytes !== details.totalBytes\n\t\t\t\t\t? `${details.mode} ${formatSize(details.sliceBytes)} of ${formatSize(details.totalBytes)}`\n\t\t\t\t\t: formatSize(details.totalBytes);\n\t\t\treturn `${theme.fg(\"muted\", \"→ \")}${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", `${details.status ? ` ${statusName(details.status)} ·` : \"\"} ${size}${details.outputPath ? ` · ${shownPath(details.outputPath)}` : \"\"}`)}`;\n\t\t}\n\t\tcase \"wait\": {\n\t\t\tconst outcome = details.outcome;\n\t\t\tif (outcome === \"no_tasks\") return theme.fg(\"muted\", \"→ No background tasks running\");\n\t\t\tconst taskId = details.taskId ?? \"any\";\n\t\t\tif (outcome === \"interrupted\") {\n\t\t\t\tconst running = details.running ? ` · ${details.running} still running` : \"\";\n\t\t\t\treturn `${mark(\"cancelled\")} ${theme.fg(\"accent\", taskId)}${theme.fg(\"muted\", ` wait interrupted after ${formatDuration(details.waitedMs)}${running}`)}`;\n\t\t\t}\n\t\t\tif (outcome === \"timed_out\") {\n\t\t\t\tconst status = details.status ?? \"running\";\n\t\t\t\tconst running = details.taskId ? formatSize(details.totalBytes) : `${details.running ?? 0} still running`;\n\t\t\t\treturn `${mark(status)} ${theme.fg(\"accent\", taskId)}${theme.fg(\"muted\", ` ${statusName(status)} · wait ended after ${formatDuration(details.waitedMs)} · ${running}`)}`;\n\t\t\t}\n\t\t\tconst status = details.status ?? \"completed\";\n\t\t\treturn `${mark(status)} ${theme.fg(\"accent\", taskId)}${theme.fg(\"muted\", ` ${statusName(status)} · waited ${formatDuration(details.waitedMs)} · +${formatSize(details.deltaBytes)}`)}`;\n\t\t}\n\t\tcase \"kill\": {\n\t\t\tconst status = details.status ?? (details.requested ? \"stopping\" : \"cancelled\");\n\t\t\treturn `${mark(status)} ${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", ` ${statusName(status)}${details.requested ? \" · cancellation requested\" : \"\"}`)}`;\n\t\t}\n\t\tcase \"list\": {\n\t\t\tconst hidden = details.hidden > 0 ? ` · ${details.hidden} more finished` : \"\";\n\t\t\tconst omitted = details.foregroundOmitted ? ` · ${details.foregroundOmitted} foreground omitted` : \"\";\n\t\t\treturn theme.fg(\"muted\", `${details.running} running · ${details.finished} finished${hidden}${omitted}`);\n\t\t}\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n"]}
@@ -1,17 +1,25 @@
1
1
  /** Independent scroll state for each region, with a source-line anchor for resize. */
2
2
  export declare class TaskViewport {
3
- follow: boolean;
3
+ /** Whether the content tails: scrolling to its end resumes following, and it starts following. */
4
+ private tailing;
5
+ private following;
4
6
  private scroll;
5
7
  private anchor?;
6
8
  private entries;
7
9
  private wrapped?;
8
10
  private height;
9
11
  private start;
10
- constructor(follow?: boolean);
12
+ constructor(tails?: boolean);
13
+ /** Whether the view is pinned to the end of the content. */
14
+ get follow(): boolean;
15
+ /** Starts over for content of a different kind: the top, or the tail when it tails. */
16
+ retarget(tails: boolean): void;
11
17
  layout(lines: string[], width: number, height: number): string[];
12
18
  private get max();
13
- move(direction: number, page: boolean, tail: boolean): void;
14
- jump(bottom: boolean, tail: boolean): void;
19
+ move(direction: number, page: boolean): void;
20
+ jump(bottom: boolean): void;
21
+ /** Whether the laid-out content is taller than the viewport. */
22
+ get overflows(): boolean;
15
23
  get range(): string;
16
24
  }
17
25
  //# sourceMappingURL=viewport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"viewport.d.ts","sourceRoot":"","sources":["../../../../src/extensions/tasks/ui/viewport.ts"],"names":[],"mappings":"AAQA,sFAAsF;AACtF,qBAAa,YAAY;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,MAAM,CAAC,CAAmC;IAClD,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,OAAO,CAAC,CAAqC;IACrD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,KAAK,CAAK;gBACN,MAAM,UAAQ;IAG1B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IA+BhE,OAAO,KAAK,GAAG,GAEd;IACD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAM3D,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAM1C,IAAI,KAAK,IAAI,MAAM,CAElB;CACD"}
1
+ {"version":3,"file":"viewport.d.ts","sourceRoot":"","sources":["../../../../src/extensions/tasks/ui/viewport.ts"],"names":[],"mappings":"AAQA,sFAAsF;AACtF,qBAAa,YAAY;IACxB,kGAAkG;IAClG,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,MAAM,CAAC,CAAmC;IAClD,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,OAAO,CAAC,CAAqC;IACrD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,KAAK,CAAK;gBACN,KAAK,UAAQ;IAIzB,4DAA4D;IAC5D,IAAI,MAAM,IAAI,OAAO,CAEpB;IACD,uFAAuF;IACvF,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAM9B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IA+BhE,OAAO,KAAK,GAAG,GAEd;IACD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAM5C,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAM3B,gEAAgE;IAChE,IAAI,SAAS,IAAI,OAAO,CAEvB;IACD,IAAI,KAAK,IAAI,MAAM,CAElB;CACD"}