@synergenius/flow-weaver-pack-weaver 0.9.59 → 0.9.77

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 (217) hide show
  1. package/dist/ai-chat-provider.d.ts +12 -0
  2. package/dist/ai-chat-provider.d.ts.map +1 -1
  3. package/dist/ai-chat-provider.js +351 -335
  4. package/dist/ai-chat-provider.js.map +1 -1
  5. package/dist/bot/agent-loop.d.ts +20 -0
  6. package/dist/bot/agent-loop.d.ts.map +1 -0
  7. package/dist/bot/agent-loop.js +331 -0
  8. package/dist/bot/agent-loop.js.map +1 -0
  9. package/dist/bot/ai-router.d.ts +19 -0
  10. package/dist/bot/ai-router.d.ts.map +1 -0
  11. package/dist/bot/ai-router.js +104 -0
  12. package/dist/bot/ai-router.js.map +1 -0
  13. package/dist/bot/assistant-tools.d.ts.map +1 -1
  14. package/dist/bot/assistant-tools.js +49 -33
  15. package/dist/bot/assistant-tools.js.map +1 -1
  16. package/dist/bot/async-mutex.d.ts +13 -0
  17. package/dist/bot/async-mutex.d.ts.map +1 -0
  18. package/dist/bot/async-mutex.js +37 -0
  19. package/dist/bot/async-mutex.js.map +1 -0
  20. package/dist/bot/bot-manager.d.ts +2 -2
  21. package/dist/bot/bot-manager.d.ts.map +1 -1
  22. package/dist/bot/bot-manager.js +3 -3
  23. package/dist/bot/bot-manager.js.map +1 -1
  24. package/dist/bot/bot-registry.js +2 -2
  25. package/dist/bot/bot-registry.js.map +1 -1
  26. package/dist/bot/conversation-store.d.ts +1 -0
  27. package/dist/bot/conversation-store.d.ts.map +1 -1
  28. package/dist/bot/conversation-store.js.map +1 -1
  29. package/dist/bot/dashboard.d.ts.map +1 -1
  30. package/dist/bot/dashboard.js +17 -8
  31. package/dist/bot/dashboard.js.map +1 -1
  32. package/dist/bot/improve-loop.js.map +1 -1
  33. package/dist/bot/index.d.ts +2 -4
  34. package/dist/bot/index.d.ts.map +1 -1
  35. package/dist/bot/index.js +1 -2
  36. package/dist/bot/index.js.map +1 -1
  37. package/dist/bot/instance-manager.d.ts +31 -0
  38. package/dist/bot/instance-manager.d.ts.map +1 -0
  39. package/dist/bot/instance-manager.js +115 -0
  40. package/dist/bot/instance-manager.js.map +1 -0
  41. package/dist/bot/orchestrator.d.ts +36 -0
  42. package/dist/bot/orchestrator.d.ts.map +1 -0
  43. package/dist/bot/orchestrator.js +176 -0
  44. package/dist/bot/orchestrator.js.map +1 -0
  45. package/dist/bot/profile-store.d.ts +36 -0
  46. package/dist/bot/profile-store.d.ts.map +1 -0
  47. package/dist/bot/profile-store.js +208 -0
  48. package/dist/bot/profile-store.js.map +1 -0
  49. package/dist/bot/profile-types.d.ts +126 -0
  50. package/dist/bot/profile-types.d.ts.map +1 -0
  51. package/dist/bot/profile-types.js +7 -0
  52. package/dist/bot/profile-types.js.map +1 -0
  53. package/dist/bot/run-store.d.ts.map +1 -1
  54. package/dist/bot/run-store.js +8 -0
  55. package/dist/bot/run-store.js.map +1 -1
  56. package/dist/bot/runner.d.ts +4 -0
  57. package/dist/bot/runner.d.ts.map +1 -1
  58. package/dist/bot/runner.js +5 -1
  59. package/dist/bot/runner.js.map +1 -1
  60. package/dist/bot/swarm-controller.d.ts +109 -0
  61. package/dist/bot/swarm-controller.d.ts.map +1 -0
  62. package/dist/bot/swarm-controller.js +640 -0
  63. package/dist/bot/swarm-controller.js.map +1 -0
  64. package/dist/bot/swarm-event-log.d.ts +28 -0
  65. package/dist/bot/swarm-event-log.d.ts.map +1 -0
  66. package/dist/bot/swarm-event-log.js +54 -0
  67. package/dist/bot/swarm-event-log.js.map +1 -0
  68. package/dist/bot/task-prompt-builder.d.ts +22 -0
  69. package/dist/bot/task-prompt-builder.d.ts.map +1 -0
  70. package/dist/bot/task-prompt-builder.js +240 -0
  71. package/dist/bot/task-prompt-builder.js.map +1 -0
  72. package/dist/bot/task-store.d.ts +21 -0
  73. package/dist/bot/task-store.d.ts.map +1 -0
  74. package/dist/bot/task-store.js +364 -0
  75. package/dist/bot/task-store.js.map +1 -0
  76. package/dist/bot/task-types.d.ts +79 -0
  77. package/dist/bot/task-types.d.ts.map +1 -0
  78. package/dist/bot/task-types.js +6 -0
  79. package/dist/bot/task-types.js.map +1 -0
  80. package/dist/bot/types.d.ts +8 -0
  81. package/dist/bot/types.d.ts.map +1 -1
  82. package/dist/cli-handlers.d.ts.map +1 -1
  83. package/dist/cli-handlers.js +79 -54
  84. package/dist/cli-handlers.js.map +1 -1
  85. package/dist/cli.d.ts +3 -0
  86. package/dist/cli.d.ts.map +1 -0
  87. package/dist/cli.js +749 -0
  88. package/dist/cli.js.map +1 -0
  89. package/dist/docs/docs/weaver-bot-usage.md +35 -18
  90. package/dist/docs/docs/weaver-config.md +20 -0
  91. package/dist/docs/docs/weaver-task-queue.md +31 -19
  92. package/dist/docs/weaver-config.md +15 -9
  93. package/dist/index.d.ts +2 -2
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +1 -1
  96. package/dist/index.js.map +1 -1
  97. package/dist/mcp-tools.d.ts +17 -0
  98. package/dist/mcp-tools.d.ts.map +1 -1
  99. package/dist/mcp-tools.js +98 -279
  100. package/dist/mcp-tools.js.map +1 -1
  101. package/dist/node-types/bot-report.d.ts.map +1 -1
  102. package/dist/node-types/bot-report.js +6 -24
  103. package/dist/node-types/bot-report.js.map +1 -1
  104. package/dist/node-types/orchestrator-dispatch.d.ts +17 -0
  105. package/dist/node-types/orchestrator-dispatch.d.ts.map +1 -0
  106. package/dist/node-types/orchestrator-dispatch.js +63 -0
  107. package/dist/node-types/orchestrator-dispatch.js.map +1 -0
  108. package/dist/node-types/orchestrator-load-state.d.ts +16 -0
  109. package/dist/node-types/orchestrator-load-state.d.ts.map +1 -0
  110. package/dist/node-types/orchestrator-load-state.js +60 -0
  111. package/dist/node-types/orchestrator-load-state.js.map +1 -0
  112. package/dist/node-types/orchestrator-route.d.ts +16 -0
  113. package/dist/node-types/orchestrator-route.d.ts.map +1 -0
  114. package/dist/node-types/orchestrator-route.js +28 -0
  115. package/dist/node-types/orchestrator-route.js.map +1 -0
  116. package/dist/node-types/receive-task.d.ts +2 -3
  117. package/dist/node-types/receive-task.d.ts.map +1 -1
  118. package/dist/node-types/receive-task.js +3 -48
  119. package/dist/node-types/receive-task.js.map +1 -1
  120. package/dist/templates/weaver-template.d.ts +11 -0
  121. package/dist/templates/weaver-template.d.ts.map +1 -0
  122. package/dist/templates/weaver-template.js +53 -0
  123. package/dist/templates/weaver-template.js.map +1 -0
  124. package/dist/ui/bot-activity.js +2 -2
  125. package/dist/ui/bot-constants.d.ts +14 -0
  126. package/dist/ui/bot-constants.d.ts.map +1 -0
  127. package/dist/ui/bot-constants.js +189 -0
  128. package/dist/ui/bot-constants.js.map +1 -0
  129. package/dist/ui/bot-panel.js +207 -245
  130. package/dist/ui/bot-slot-card.js +141 -0
  131. package/dist/ui/budget-bar.js +59 -0
  132. package/dist/ui/chat-task-result.js +178 -0
  133. package/dist/ui/decision-log.js +136 -0
  134. package/dist/ui/profile-card.js +158 -0
  135. package/dist/ui/profile-editor.js +597 -0
  136. package/dist/ui/swarm-controls.js +245 -0
  137. package/dist/ui/swarm-dashboard.js +3012 -0
  138. package/dist/ui/task-create-form.js +98 -0
  139. package/dist/ui/task-detail-view.js +1044 -0
  140. package/dist/ui/task-pool-list.js +156 -0
  141. package/dist/workflows/orchestrator.d.ts +21 -0
  142. package/dist/workflows/orchestrator.d.ts.map +1 -0
  143. package/dist/workflows/orchestrator.js +281 -0
  144. package/dist/workflows/orchestrator.js.map +1 -0
  145. package/dist/workflows/weaver-bot-session.d.ts +65 -0
  146. package/dist/workflows/weaver-bot-session.d.ts.map +1 -0
  147. package/dist/workflows/weaver-bot-session.js +68 -0
  148. package/dist/workflows/weaver-bot-session.js.map +1 -0
  149. package/dist/workflows/weaver.d.ts +24 -0
  150. package/dist/workflows/weaver.d.ts.map +1 -0
  151. package/dist/workflows/weaver.js +28 -0
  152. package/dist/workflows/weaver.js.map +1 -0
  153. package/flowweaver.manifest.json +547 -133
  154. package/package.json +1 -1
  155. package/src/ai-chat-provider.ts +378 -371
  156. package/src/bot/ai-router.ts +132 -0
  157. package/src/bot/assistant-tools.ts +47 -29
  158. package/src/bot/async-mutex.ts +37 -0
  159. package/src/bot/bot-manager.ts +3 -3
  160. package/src/bot/bot-registry.ts +2 -2
  161. package/src/bot/conversation-store.ts +2 -1
  162. package/src/bot/dashboard.ts +17 -8
  163. package/src/bot/improve-loop.ts +6 -6
  164. package/src/bot/index.ts +2 -4
  165. package/src/bot/instance-manager.ts +128 -0
  166. package/src/bot/orchestrator.ts +244 -0
  167. package/src/bot/profile-store.ts +225 -0
  168. package/src/bot/profile-types.ts +141 -0
  169. package/src/bot/run-store.ts +8 -0
  170. package/src/bot/runner.ts +9 -1
  171. package/src/bot/swarm-controller.ts +780 -0
  172. package/src/bot/swarm-event-log.ts +57 -0
  173. package/src/bot/task-prompt-builder.ts +309 -0
  174. package/src/bot/task-store.ts +407 -0
  175. package/src/bot/task-types.ts +100 -0
  176. package/src/bot/types.ts +8 -0
  177. package/src/cli-handlers.ts +78 -53
  178. package/src/docs/weaver-bot-usage.md +35 -18
  179. package/src/docs/weaver-config.md +20 -0
  180. package/src/docs/weaver-task-queue.md +31 -19
  181. package/src/index.ts +5 -4
  182. package/src/mcp-tools.ts +129 -372
  183. package/src/node-types/bot-report.ts +6 -24
  184. package/src/node-types/orchestrator-dispatch.ts +71 -0
  185. package/src/node-types/orchestrator-load-state.ts +66 -0
  186. package/src/node-types/orchestrator-route.ts +33 -0
  187. package/src/node-types/receive-task.ts +3 -57
  188. package/src/ui/bot-activity.tsx +2 -2
  189. package/src/ui/bot-constants.ts +192 -0
  190. package/src/ui/bot-panel.tsx +213 -247
  191. package/src/ui/bot-slot-card.tsx +139 -0
  192. package/src/ui/budget-bar.tsx +30 -0
  193. package/src/ui/chat-task-result.tsx +236 -0
  194. package/src/ui/decision-log.tsx +148 -0
  195. package/src/ui/profile-card.tsx +157 -0
  196. package/src/ui/profile-editor.tsx +384 -0
  197. package/src/ui/swarm-controls.tsx +260 -0
  198. package/src/ui/swarm-dashboard.tsx +647 -0
  199. package/src/ui/task-create-form.tsx +87 -0
  200. package/src/ui/task-detail-view.tsx +841 -0
  201. package/src/ui/task-pool-list.tsx +187 -0
  202. package/src/workflows/orchestrator.ts +302 -0
  203. package/dist/docs/weaver-bot-usage.md +0 -34
  204. package/dist/docs/weaver-genesis.md +0 -32
  205. package/dist/docs/weaver-task-queue.md +0 -34
  206. package/dist/ui/bot-workspace.js +0 -1015
  207. package/dist/ui/chat-bot-result.js +0 -71
  208. package/dist/ui/queue-input.js +0 -82
  209. package/dist/ui/session-bar.js +0 -174
  210. package/src/bot/error-guide.ts +0 -4
  211. package/src/bot/retry-utils.ts +0 -4
  212. package/src/bot/session-state.ts +0 -116
  213. package/src/bot/task-queue.ts +0 -262
  214. package/src/ui/bot-workspace.tsx +0 -442
  215. package/src/ui/chat-bot-result.tsx +0 -81
  216. package/src/ui/queue-input.tsx +0 -56
  217. package/src/ui/session-bar.tsx +0 -157
@@ -0,0 +1,1044 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/ui/task-detail-view.tsx
21
+ var task_detail_view_exports = {};
22
+ __export(task_detail_view_exports, {
23
+ TaskDetailView: () => TaskDetailView,
24
+ default: () => task_detail_view_default
25
+ });
26
+ module.exports = __toCommonJS(task_detail_view_exports);
27
+
28
+ // src/ui/use-stream-timeline.ts
29
+ var React = require("react");
30
+ var { useMemo, useState, useEffect, useRef } = React;
31
+ function useStreamTimeline(events, isDone) {
32
+ const [elapsed, setElapsed] = useState(0);
33
+ const startTimeRef = useRef(null);
34
+ useEffect(() => {
35
+ if (events.length === 0) {
36
+ startTimeRef.current = null;
37
+ setElapsed(0);
38
+ } else if (startTimeRef.current === null) {
39
+ startTimeRef.current = events[0].timestamp;
40
+ }
41
+ }, [events.length]);
42
+ useEffect(() => {
43
+ if (isDone || !startTimeRef.current) return;
44
+ const tick = () => setElapsed(Date.now() - (startTimeRef.current ?? Date.now()));
45
+ tick();
46
+ const interval = setInterval(tick, 1e3);
47
+ return () => clearInterval(interval);
48
+ }, [isDone, events.length]);
49
+ const timeline = useMemo(() => {
50
+ const entries = [];
51
+ const nodeEntryIndex = /* @__PURE__ */ new Map();
52
+ const nodeStarts = /* @__PURE__ */ new Map();
53
+ let idCounter = 0;
54
+ for (const event of events) {
55
+ const d = event.data ?? {};
56
+ switch (event.type) {
57
+ case "bot-started":
58
+ entries.push({
59
+ id: `s-${idCounter++}`,
60
+ timestamp: new Date(event.timestamp),
61
+ type: "task-started",
62
+ label: "Task started",
63
+ detail: d.instruction
64
+ });
65
+ break;
66
+ case "node-start": {
67
+ const nodeId = d.nodeId;
68
+ if (nodeId) nodeStarts.set(nodeId, event.timestamp);
69
+ const idx = entries.length;
70
+ nodeEntryIndex.set(nodeId, idx);
71
+ entries.push({
72
+ id: `s-${idCounter++}`,
73
+ timestamp: new Date(event.timestamp),
74
+ type: "node-started",
75
+ nodeId,
76
+ label: d.label ?? d.nodeType ?? nodeId ?? "Node"
77
+ });
78
+ break;
79
+ }
80
+ case "node-complete": {
81
+ const nodeId = d.nodeId;
82
+ const startTs = nodeStarts.get(nodeId);
83
+ const duration = d.durationMs ?? (startTs ? event.timestamp - startTs : void 0);
84
+ if (nodeId) nodeStarts.delete(nodeId);
85
+ const rawOutputs = d.outputs;
86
+ const completed = {
87
+ id: `s-${idCounter++}`,
88
+ timestamp: new Date(startTs ?? event.timestamp),
89
+ type: "node-completed",
90
+ nodeId,
91
+ label: d.label ?? d.nodeType ?? nodeId ?? "Node",
92
+ duration,
93
+ outputs: rawOutputs && rawOutputs.length > 0 ? rawOutputs : void 0
94
+ };
95
+ const existingIdx = nodeEntryIndex.get(nodeId);
96
+ if (existingIdx != null && entries[existingIdx]) {
97
+ entries[existingIdx] = completed;
98
+ nodeEntryIndex.delete(nodeId);
99
+ } else {
100
+ entries.push(completed);
101
+ }
102
+ break;
103
+ }
104
+ case "node-error": {
105
+ const nodeId = d.nodeId;
106
+ const startTs = nodeStarts.get(nodeId);
107
+ const duration = d.durationMs ?? (startTs ? event.timestamp - startTs : void 0);
108
+ if (nodeId) nodeStarts.delete(nodeId);
109
+ const rawOutputs = d.outputs;
110
+ const failed = {
111
+ id: `s-${idCounter++}`,
112
+ timestamp: new Date(startTs ?? event.timestamp),
113
+ type: "node-failed",
114
+ nodeId,
115
+ label: d.label ?? d.nodeType ?? nodeId ?? "Node",
116
+ detail: d.error,
117
+ duration,
118
+ outputs: rawOutputs && rawOutputs.length > 0 ? rawOutputs : void 0
119
+ };
120
+ const existingIdx = nodeEntryIndex.get(nodeId);
121
+ if (existingIdx != null && entries[existingIdx]) {
122
+ entries[existingIdx] = failed;
123
+ nodeEntryIndex.delete(nodeId);
124
+ } else {
125
+ entries.push(failed);
126
+ }
127
+ break;
128
+ }
129
+ case "bot-completed":
130
+ entries.push({
131
+ id: `s-${idCounter++}`,
132
+ timestamp: new Date(event.timestamp),
133
+ type: "task-completed",
134
+ label: d.success ? "Task completed" : "Task finished",
135
+ detail: d.summary
136
+ });
137
+ break;
138
+ case "bot-failed":
139
+ entries.push({
140
+ id: `s-${idCounter++}`,
141
+ timestamp: new Date(event.timestamp),
142
+ type: "task-failed",
143
+ label: "Task failed",
144
+ detail: d.error
145
+ });
146
+ break;
147
+ // Skip audit, cost-update, done — they're used for metadata, not timeline
148
+ default:
149
+ break;
150
+ }
151
+ }
152
+ return entries;
153
+ }, [events]);
154
+ const { phase, instruction, cost, plan, awaitingApproval } = useMemo(() => {
155
+ let phase2 = "idle";
156
+ let instruction2 = null;
157
+ let cost2 = null;
158
+ let plan2 = null;
159
+ let awaitingApproval2 = false;
160
+ for (const event of events) {
161
+ const d = event.data ?? {};
162
+ if (event.type === "bot-started") {
163
+ phase2 = "planning";
164
+ instruction2 = d.instruction ?? null;
165
+ } else if (event.type === "node-start" && phase2 !== "completed" && phase2 !== "failed") {
166
+ phase2 = "executing";
167
+ } else if (event.type === "bot-completed") {
168
+ phase2 = d.success ? "completed" : "failed";
169
+ } else if (event.type === "bot-failed") {
170
+ phase2 = "failed";
171
+ } else if (event.type === "cost-update") {
172
+ cost2 = d.totalCost ?? cost2;
173
+ } else if (event.type === "audit:plan-created" || event.type === "plan-created") {
174
+ const planData = d.plan ?? d;
175
+ const summary = planData.summary ?? "";
176
+ const steps = planData.steps ?? [];
177
+ if (summary || steps.length > 0) {
178
+ plan2 = { summary, steps };
179
+ }
180
+ } else if (event.type === "approval-needed") {
181
+ awaitingApproval2 = true;
182
+ } else if (event.type === "audit:approval-decision") {
183
+ awaitingApproval2 = false;
184
+ }
185
+ }
186
+ if (isDone && phase2 !== "completed" && phase2 !== "failed") {
187
+ phase2 = "completed";
188
+ }
189
+ return { phase: phase2, instruction: instruction2, cost: cost2, plan: plan2, awaitingApproval: awaitingApproval2 };
190
+ }, [events, isDone]);
191
+ return { timeline, phase, instruction, elapsed, cost, plan, awaitingApproval };
192
+ }
193
+
194
+ // src/ui/trace-to-timeline.ts
195
+ function traceToTimeline(run) {
196
+ const entries = [];
197
+ let idCounter = 0;
198
+ const meta = run.nodeMeta ?? {};
199
+ if (run.trace && run.trace.length > 0) {
200
+ const nodeStarts = /* @__PURE__ */ new Map();
201
+ for (const event of run.trace) {
202
+ if (event.type === "node-start") {
203
+ nodeStarts.set(event.nodeId, event);
204
+ } else if (event.type === "node-complete" || event.type === "node-error") {
205
+ const start = nodeStarts.get(event.nodeId);
206
+ const duration = event.durationMs ?? (start ? event.timestamp - start.timestamp : void 0);
207
+ const nm = meta[event.nodeId] ?? (event.nodeType ? meta[event.nodeType] : void 0);
208
+ entries.push({
209
+ id: `trace-${idCounter++}`,
210
+ timestamp: new Date(event.timestamp),
211
+ type: event.type === "node-complete" ? "node-completed" : "node-failed",
212
+ nodeId: event.nodeId,
213
+ label: nm?.label ?? event.nodeType ?? event.nodeId,
214
+ detail: event.error,
215
+ duration,
216
+ color: nm?.color,
217
+ icon: nm?.icon,
218
+ outputs: event.outputs && event.outputs.length > 0 ? event.outputs : void 0
219
+ });
220
+ nodeStarts.delete(event.nodeId);
221
+ }
222
+ }
223
+ for (const [nodeId, event] of nodeStarts) {
224
+ const nm = meta[nodeId] ?? (event.nodeType ? meta[event.nodeType] : void 0);
225
+ entries.push({
226
+ id: `trace-${idCounter++}`,
227
+ timestamp: new Date(event.timestamp),
228
+ type: "node-started",
229
+ nodeId,
230
+ label: nm?.label ?? event.nodeType ?? nodeId,
231
+ color: nm?.color,
232
+ icon: nm?.icon
233
+ });
234
+ }
235
+ } else if (run.stepLog && run.stepLog.length > 0) {
236
+ for (const step of run.stepLog) {
237
+ const type = step.status === "ok" ? "node-completed" : step.status === "error" ? "node-failed" : "node-completed";
238
+ entries.push({
239
+ id: `step-${idCounter++}`,
240
+ timestamp: new Date(run.startedAt ?? Date.now()),
241
+ type,
242
+ label: step.step,
243
+ detail: step.detail,
244
+ icon: step.status === "ok" ? "success" : step.status === "error" ? "error" : "warning"
245
+ });
246
+ }
247
+ }
248
+ if (run.outcome === "failed" || run.outcome === "error") {
249
+ let errorDetail = "";
250
+ if (run.auditTrail) {
251
+ for (const a of run.auditTrail) {
252
+ if (a.type === "step-complete" && a.data) {
253
+ const errors = a.data.errors;
254
+ if (errors && errors.length > 0) {
255
+ errorDetail = errors.map((e) => e.length > 120 ? e.slice(0, 117) + "..." : e).join("\n");
256
+ break;
257
+ }
258
+ }
259
+ }
260
+ }
261
+ if (!errorDetail && run.summary) {
262
+ const parts = run.summary.split("|").map((p) => p.trim());
263
+ const outcomePart = parts.find((p) => p.startsWith("Outcome:"));
264
+ const summaryPart = parts.find((p) => p.startsWith("Summary:"));
265
+ errorDetail = summaryPart?.replace("Summary:", "").trim() ?? outcomePart ?? run.summary;
266
+ }
267
+ entries.push({
268
+ id: `result-${idCounter++}`,
269
+ timestamp: new Date(run.finishedAt ?? run.startedAt ?? Date.now()),
270
+ type: "task-failed",
271
+ label: "Task failed",
272
+ detail: errorDetail || "Unknown failure",
273
+ icon: "error"
274
+ });
275
+ } else if (run.outcome === "completed" && run.success) {
276
+ entries.push({
277
+ id: `result-${idCounter++}`,
278
+ timestamp: new Date(run.finishedAt ?? run.startedAt ?? Date.now()),
279
+ type: "task-completed",
280
+ label: "Task completed",
281
+ detail: run.summary?.includes("|") ? run.summary.split("|").find((p) => p.trim().startsWith("Summary:"))?.replace("Summary:", "").trim() : void 0
282
+ });
283
+ }
284
+ entries.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
285
+ return entries;
286
+ }
287
+
288
+ // src/ui/task-detail-view.tsx
289
+ var React2 = require("react");
290
+ var { useState: useState2, useEffect: useEffect2, useCallback, useRef: useRef2, useMemo: useMemo2 } = React2;
291
+ var {
292
+ Flex,
293
+ Typography,
294
+ ScrollArea,
295
+ StatusIcon,
296
+ Tag,
297
+ Badge,
298
+ Icon,
299
+ IconButton,
300
+ TaskBlock,
301
+ Button,
302
+ Card,
303
+ Chip,
304
+ Checkbox,
305
+ Table,
306
+ Tabs,
307
+ EmptyState,
308
+ toast,
309
+ usePackWorkspace,
310
+ useEventStream
311
+ } = require("@fw/plugin-ui-kit");
312
+ var statusToIcon = {
313
+ "pending": "pending",
314
+ "in-progress": "running",
315
+ "done": "completed",
316
+ "failed": "failed",
317
+ "blocked": "pending",
318
+ "cancelled": "failed"
319
+ };
320
+ var statusToLabel = {
321
+ "pending": "Pending",
322
+ "in-progress": "In Progress",
323
+ "done": "Done",
324
+ "failed": "Failed",
325
+ "blocked": "Blocked",
326
+ "cancelled": "Cancelled"
327
+ };
328
+ var headerStyle = {
329
+ padding: "12px 16px",
330
+ borderBottom: "1px solid var(--color-border-default)",
331
+ flexShrink: 0
332
+ };
333
+ var fileItemStyle = {
334
+ fontFamily: "monospace",
335
+ fontSize: "12px",
336
+ color: "var(--color-text-mid)",
337
+ padding: "2px 4px",
338
+ borderRadius: "4px"
339
+ };
340
+ var fileItemHoverStyle = {
341
+ ...fileItemStyle,
342
+ backgroundColor: "var(--color-surface-elevated)"
343
+ };
344
+ var subtaskRowStyle = {
345
+ padding: "6px 8px",
346
+ cursor: "pointer",
347
+ borderRadius: "6px"
348
+ };
349
+ var subtaskRowHoverStyle = {
350
+ ...subtaskRowStyle,
351
+ backgroundColor: "var(--color-surface-elevated)"
352
+ };
353
+ function SubtaskRowItem({ sub, onBack }) {
354
+ const [hovered, setHovered] = useState2(false);
355
+ return React2.createElement(
356
+ Flex,
357
+ {
358
+ variant: "row-center-start-nowrap-8",
359
+ style: hovered ? subtaskRowHoverStyle : subtaskRowStyle,
360
+ onClick: () => onBack(),
361
+ onMouseEnter: () => setHovered(true),
362
+ onMouseLeave: () => setHovered(false)
363
+ },
364
+ React2.createElement(StatusIcon, {
365
+ status: statusToIcon[sub.status] || "pending",
366
+ size: "sm"
367
+ }),
368
+ React2.createElement(
369
+ Flex,
370
+ {
371
+ variant: "row-center-start-nowrap-0",
372
+ style: { flex: 1, minWidth: 0 }
373
+ },
374
+ React2.createElement(Typography, { variant: "caption-regular", truncate: true }, sub.title)
375
+ ),
376
+ sub.assignedProfile && React2.createElement(Tag, {
377
+ size: "small",
378
+ color: "info"
379
+ }, sub.assignedProfile),
380
+ React2.createElement(Typography, {
381
+ variant: "caption-regular",
382
+ color: "color-text-subtle"
383
+ }, `#${sub.attempt}`)
384
+ );
385
+ }
386
+ function TaskDetailView({ taskId, onBack }) {
387
+ const ctx = usePackWorkspace();
388
+ const { callTool } = ctx;
389
+ const packId = ctx.packId;
390
+ const [task, setTask] = useState2(null);
391
+ const [subtasks, setSubtasks] = useState2([]);
392
+ const [history, setHistory] = useState2([]);
393
+ const [loading, setLoading] = useState2(true);
394
+ const fetchTask = useCallback(async () => {
395
+ try {
396
+ const raw = await callTool("fw_weaver_task_get", { id: taskId });
397
+ const data = typeof raw === "string" ? JSON.parse(raw) : raw;
398
+ if (!data) return;
399
+ const t = data.task ?? data;
400
+ setTask(t);
401
+ if (data.subtasks && Array.isArray(data.subtasks)) {
402
+ setSubtasks(data.subtasks);
403
+ } else if (t.isParent) {
404
+ const listRaw = await callTool("fw_weaver_task_list", { parentId: taskId });
405
+ const listData = typeof listRaw === "string" ? JSON.parse(listRaw) : listRaw;
406
+ if (Array.isArray(listData)) {
407
+ setSubtasks(listData);
408
+ }
409
+ }
410
+ } catch (err) {
411
+ }
412
+ }, [callTool, taskId]);
413
+ const fetchHistory = useCallback(async () => {
414
+ try {
415
+ const raw = await callTool("fw_weaver_history", { taskId });
416
+ const data = typeof raw === "string" ? JSON.parse(raw) : raw;
417
+ if (Array.isArray(data)) {
418
+ setHistory(
419
+ data.map((r) => {
420
+ const costObj = r.cost && typeof r.cost === "object" ? r.cost : void 0;
421
+ return { ...r, costDetail: costObj, cost: costObj?.totalCost };
422
+ })
423
+ );
424
+ }
425
+ } catch {
426
+ }
427
+ }, [callTool, taskId]);
428
+ useEffect2(() => {
429
+ setLoading(true);
430
+ Promise.all([fetchTask(), fetchHistory()]).finally(() => setLoading(false));
431
+ }, [fetchTask, fetchHistory]);
432
+ useEffect2(() => {
433
+ if (!task || task.status !== "in-progress") return;
434
+ const interval = setInterval(() => {
435
+ fetchTask();
436
+ fetchHistory();
437
+ }, 5e3);
438
+ return () => clearInterval(interval);
439
+ }, [task?.status, fetchTask, fetchHistory]);
440
+ const stream = useEventStream();
441
+ const {
442
+ timeline: liveTimeline,
443
+ phase: livePhase,
444
+ instruction: liveInstruction,
445
+ elapsed,
446
+ cost: liveCost,
447
+ plan,
448
+ awaitingApproval
449
+ } = useStreamTimeline(stream.events, stream.isDone);
450
+ const currentRunId = task?.currentRunId;
451
+ const isLive = task?.status === "in-progress" && !!currentRunId;
452
+ useEffect2(() => {
453
+ if (!isLive || !currentRunId) return;
454
+ stream.start(packId, "fw_weaver_events", currentRunId);
455
+ return () => stream.stop();
456
+ }, [isLive, currentRunId, packId]);
457
+ const [detailTab, setDetailTab] = useState2("runs");
458
+ const [actionLoading, setActionLoading] = useState2(null);
459
+ const [availableProfiles, setAvailableProfiles] = useState2([]);
460
+ useEffect2(() => {
461
+ callTool("fw_weaver_profile_list", {}).then((raw) => {
462
+ const data = typeof raw === "string" ? JSON.parse(raw) : raw;
463
+ if (Array.isArray(data)) setAvailableProfiles(data);
464
+ }).catch(() => {
465
+ });
466
+ }, [callTool]);
467
+ const handleRetry = useCallback(async () => {
468
+ setActionLoading("retry");
469
+ try {
470
+ await callTool("fw_weaver_task_retry", { id: taskId });
471
+ toast("Task retried, back in pool", { type: "success" });
472
+ fetchTask();
473
+ } catch (err) {
474
+ toast(err instanceof Error ? err.message : "Failed to retry", { type: "error" });
475
+ }
476
+ setActionLoading(null);
477
+ }, [callTool, taskId, fetchTask]);
478
+ const handleCancel = useCallback(async () => {
479
+ const ok = await ctx.confirm("Cancel this task? It cannot be undone.", {
480
+ title: "Cancel Task",
481
+ confirmLabel: "Cancel Task",
482
+ state: "warning"
483
+ });
484
+ if (!ok) return;
485
+ setActionLoading("cancel");
486
+ try {
487
+ await callTool("fw_weaver_task_cancel", { id: taskId });
488
+ toast("Task cancelled", { type: "info" });
489
+ fetchTask();
490
+ } catch (err) {
491
+ toast(err instanceof Error ? err.message : "Failed to cancel", { type: "error" });
492
+ }
493
+ setActionLoading(null);
494
+ }, [callTool, taskId, fetchTask, ctx]);
495
+ const handleAssignProfile = useCallback(async (profileId) => {
496
+ setActionLoading("assign-profile");
497
+ try {
498
+ const newProfile = task?.assignedProfile === profileId ? void 0 : profileId;
499
+ await callTool("fw_weaver_task_update", { id: taskId, assignedProfile: newProfile ?? null });
500
+ toast(newProfile ? `Assigned profile ${profileId}` : `Unassigned profile`, { type: "success" });
501
+ fetchTask();
502
+ } catch (err) {
503
+ toast(err instanceof Error ? err.message : "Failed to assign profile", { type: "error" });
504
+ }
505
+ setActionLoading(null);
506
+ }, [callTool, taskId, task, fetchTask]);
507
+ const handlePriorityChange = useCallback(async (delta) => {
508
+ const newPriority = Math.max(0, (task?.priority ?? 0) + delta);
509
+ try {
510
+ await callTool("fw_weaver_task_update", { id: taskId, priority: newPriority });
511
+ fetchTask();
512
+ } catch {
513
+ }
514
+ }, [callTool, taskId, task, fetchTask]);
515
+ const [expandedRunId, setExpandedRunId] = useState2(null);
516
+ const [liveExpanded, setLiveExpanded] = useState2(true);
517
+ const toggleExpand = useCallback((id) => {
518
+ setExpandedRunId((prev) => prev === id ? null : id);
519
+ }, []);
520
+ const scrollRef = useRef2(null);
521
+ useEffect2(() => {
522
+ const el = scrollRef.current;
523
+ if (el) el.scrollTop = el.scrollHeight;
524
+ }, [liveTimeline.length, stream.events.length]);
525
+ const [approvalStatus, setApprovalStatus] = useState2(null);
526
+ const [approvalLoading, setApprovalLoading] = useState2(false);
527
+ useEffect2(() => {
528
+ if (awaitingApproval) setApprovalStatus("pending");
529
+ }, [awaitingApproval]);
530
+ useEffect2(() => {
531
+ if (stream.events.length === 0) setApprovalStatus(null);
532
+ }, [stream.events.length]);
533
+ const handleApprove = useCallback(async () => {
534
+ setApprovalLoading(true);
535
+ try {
536
+ await callTool("fw_weaver_approve", { approved: true });
537
+ setApprovalStatus("approved");
538
+ toast("Plan approved", { type: "success" });
539
+ } catch (err) {
540
+ toast(err instanceof Error ? err.message : "Failed to approve", { type: "error" });
541
+ }
542
+ setApprovalLoading(false);
543
+ }, [callTool]);
544
+ const handleReject = useCallback(async () => {
545
+ setApprovalLoading(true);
546
+ try {
547
+ await callTool("fw_weaver_approve", { approved: false });
548
+ setApprovalStatus("rejected");
549
+ toast("Plan rejected", { type: "info" });
550
+ } catch (err) {
551
+ toast(err instanceof Error ? err.message : "Failed to reject", { type: "error" });
552
+ }
553
+ setApprovalLoading(false);
554
+ }, [callTool]);
555
+ const runItems = useMemo2(() => {
556
+ return history.map((run) => ({
557
+ run,
558
+ runTimeline: traceToTimeline(run)
559
+ }));
560
+ }, [history]);
561
+ function extractInstruction(run) {
562
+ if (run.instruction) {
563
+ const text = run.instruction;
564
+ return text.length > 120 ? text.slice(0, 117) + "..." : text;
565
+ }
566
+ if (run.summary) {
567
+ const summary = run.summary;
568
+ if (summary.includes("|")) {
569
+ const parts = summary.split("|").map((p) => p.trim());
570
+ const taskPart = parts.find((p) => p.startsWith("Task:"));
571
+ const summaryPart = parts.find((p) => p.startsWith("Summary:"));
572
+ const text = taskPart?.replace("Task:", "").trim() ?? summaryPart?.replace("Summary:", "").trim() ?? parts[0] ?? "";
573
+ return text.length > 120 ? text.slice(0, 117) + "..." : text;
574
+ }
575
+ return summary.length > 120 ? summary.slice(0, 117) + "..." : summary;
576
+ }
577
+ return "Bot run";
578
+ }
579
+ if (loading && !task) {
580
+ return React2.createElement(
581
+ Flex,
582
+ {
583
+ variant: "column-stretch-start-nowrap-0",
584
+ style: { width: "100%", height: "100%", overflow: "hidden" }
585
+ },
586
+ React2.createElement(
587
+ Flex,
588
+ {
589
+ variant: "column-stretch-start-nowrap-8",
590
+ style: headerStyle
591
+ },
592
+ React2.createElement(
593
+ Button,
594
+ { variant: "ghost", size: "sm", onClick: onBack },
595
+ React2.createElement(Icon, { name: "arrowBack", size: 16 }),
596
+ " Back"
597
+ )
598
+ ),
599
+ React2.createElement(
600
+ Flex,
601
+ {
602
+ variant: "column-center-center-nowrap-0",
603
+ style: { flex: 1 }
604
+ },
605
+ React2.createElement(
606
+ Typography,
607
+ { variant: "caption-regular", color: "color-text-subtle" },
608
+ "Loading task..."
609
+ )
610
+ )
611
+ );
612
+ }
613
+ if (!task) {
614
+ return React2.createElement(
615
+ Flex,
616
+ {
617
+ variant: "column-stretch-start-nowrap-0",
618
+ style: { width: "100%", height: "100%", overflow: "hidden" }
619
+ },
620
+ React2.createElement(
621
+ Flex,
622
+ {
623
+ variant: "column-stretch-start-nowrap-8",
624
+ style: headerStyle
625
+ },
626
+ React2.createElement(
627
+ Button,
628
+ { variant: "ghost", size: "sm", onClick: onBack },
629
+ React2.createElement(Icon, { name: "arrowBack", size: 16 }),
630
+ " Back"
631
+ )
632
+ ),
633
+ React2.createElement(
634
+ Flex,
635
+ {
636
+ variant: "column-center-center-nowrap-0",
637
+ style: { flex: 1 }
638
+ },
639
+ React2.createElement(
640
+ Typography,
641
+ { variant: "caption-regular", color: "color-text-subtle" },
642
+ "Task not found."
643
+ )
644
+ )
645
+ );
646
+ }
647
+ const hasContext = task.context?.files?.length > 0 || task.context?.notes;
648
+ const hasSubtasks = task.isParent && subtasks.length > 0;
649
+ const hasRuns = runItems.length > 0 || isLive;
650
+ return React2.createElement(
651
+ Flex,
652
+ {
653
+ variant: "column-stretch-start-nowrap-0",
654
+ style: { width: "100%", height: "100%", overflow: "hidden" }
655
+ },
656
+ // ── Header ──
657
+ React2.createElement(
658
+ Flex,
659
+ {
660
+ variant: "column-stretch-start-nowrap-6",
661
+ style: { ...headerStyle, padding: "12px 16px", borderBottom: "1px solid var(--color-border-default)" }
662
+ },
663
+ // Top row: back + title + status
664
+ React2.createElement(
665
+ Flex,
666
+ { variant: "row-center-start-nowrap-8" },
667
+ React2.createElement(IconButton, {
668
+ icon: "back",
669
+ size: "xs",
670
+ variant: "clear",
671
+ onClick: onBack
672
+ }),
673
+ React2.createElement(StatusIcon, {
674
+ status: statusToIcon[task.status] || "pending",
675
+ size: "sm"
676
+ }),
677
+ React2.createElement(Typography, {
678
+ variant: "caption-thick",
679
+ color: "color-text-high",
680
+ style: { flex: 1, minWidth: 0, wordBreak: "break-word" }
681
+ }, task.title || "Untitled Task")
682
+ ),
683
+ // Meta row: status tag, assigned profile, priority, attempts
684
+ React2.createElement(
685
+ Flex,
686
+ { variant: "row-center-start-wrap-6" },
687
+ React2.createElement(Tag, {
688
+ size: "small",
689
+ color: task.status === "done" ? "positive" : task.status === "failed" ? "negative" : task.status === "in-progress" ? "info" : task.status === "blocked" ? "caution" : "secondary"
690
+ }, statusToLabel[task.status] || task.status || "pending"),
691
+ task.assignedProfile && React2.createElement(Tag, { key: `profile-${task.assignedProfile}`, size: "small", color: "info" }, task.assignedProfile),
692
+ task.priority > 0 && React2.createElement(Tag, {
693
+ size: "small",
694
+ color: task.priority >= 3 ? "caution" : "info"
695
+ }, `P${task.priority}`),
696
+ task.attempt != null && task.maxAttempts != null && React2.createElement(Typography, {
697
+ variant: "smallCaption-regular",
698
+ color: "color-text-subtle"
699
+ }, `Attempt ${task.attempt}/${task.maxAttempts}`)
700
+ ),
701
+ // Description
702
+ task.description && React2.createElement(Typography, {
703
+ variant: "smallCaption-regular",
704
+ color: "color-text-medium"
705
+ }, task.description),
706
+ // Profile routing info
707
+ task.assignedProfile && React2.createElement(
708
+ Flex,
709
+ { variant: "column-stretch-start-nowrap-2" },
710
+ React2.createElement(Typography, {
711
+ variant: "smallCaption-regular",
712
+ color: "color-text-medium"
713
+ }, `Profile: ${task.assignedProfile}`),
714
+ task.routingReason && React2.createElement(Typography, {
715
+ variant: "smallCaption-regular",
716
+ color: "color-text-subtle"
717
+ }, task.routingReason)
718
+ )
719
+ // (Actions moved to tab)
720
+ ),
721
+ // ── Tabs ──
722
+ React2.createElement(Tabs, {
723
+ tabs: [
724
+ { id: "runs", title: `Runs (${runItems.length}${isLive ? "+1" : ""})` },
725
+ ...hasSubtasks ? [{ id: "subtasks", title: `Subtasks (${subtasks.filter((s) => s.status === "done").length}/${subtasks.length})` }] : [],
726
+ ...task.status !== "done" && task.status !== "cancelled" ? [{ id: "actions", title: "Actions" }] : [],
727
+ ...hasContext ? [{ id: "context", title: "Context" }] : []
728
+ ],
729
+ activeTabId: detailTab,
730
+ onSelectTab: (id) => setDetailTab(id),
731
+ size: "sm"
732
+ }),
733
+ // ── Tab content ──
734
+ React2.createElement(
735
+ ScrollArea,
736
+ { ref: scrollRef, style: { flex: 1 } },
737
+ React2.createElement(
738
+ Flex,
739
+ { variant: "column-stretch-start-nowrap-8", style: { padding: "12px 16px" } },
740
+ // ── Runs tab ──
741
+ detailTab === "runs" && (hasRuns || (task.runs?.length ?? 0) > 0) ? React2.createElement(
742
+ Flex,
743
+ { variant: "column-stretch-start-nowrap-8" },
744
+ ...runItems.map(({ run, runTimeline }) => {
745
+ const runId = run.id;
746
+ const isExpanded = expandedRunId === runId;
747
+ const isSuccess = run.outcome === "completed" || run.success === true;
748
+ return React2.createElement(TaskBlock, {
749
+ key: `run-${runId}`,
750
+ state: isSuccess ? "completed" : "failed",
751
+ instruction: extractInstruction(run),
752
+ timeline: runTimeline,
753
+ cost: typeof run.cost === "number" ? run.cost : run.costDetail?.totalCost ?? null,
754
+ plan: run.plan,
755
+ startedAt: run.startedAt,
756
+ durationMs: run.durationMs ?? run.duration,
757
+ expanded: isExpanded,
758
+ onToggleExpand: () => toggleExpand(runId)
759
+ });
760
+ }),
761
+ // Live run
762
+ isLive && React2.createElement(TaskBlock, {
763
+ key: "live-run",
764
+ state: "running",
765
+ instruction: liveInstruction ?? task.title,
766
+ timeline: liveTimeline,
767
+ phase: livePhase,
768
+ elapsed,
769
+ cost: liveCost,
770
+ plan,
771
+ error: stream.error,
772
+ approval: approvalStatus ?? void 0,
773
+ approvalLoading,
774
+ onApprove: handleApprove,
775
+ onReject: handleReject,
776
+ expanded: liveExpanded,
777
+ onToggleExpand: () => setLiveExpanded((v) => !v)
778
+ })
779
+ ) : detailTab === "runs" && React2.createElement(EmptyState, {
780
+ icon: "smartToy",
781
+ message: "No runs yet",
782
+ description: "This task has not been executed yet."
783
+ }),
784
+ // ── Subtasks tab ──
785
+ detailTab === "subtasks" && hasSubtasks && React2.createElement(
786
+ Flex,
787
+ {
788
+ variant: "column-stretch-start-nowrap-0"
789
+ },
790
+ ...(subtasks ?? []).map(
791
+ (sub) => React2.createElement(SubtaskRowItem, {
792
+ key: sub.id,
793
+ sub,
794
+ onBack
795
+ })
796
+ )
797
+ ),
798
+ // ── Actions tab ──
799
+ detailTab === "actions" && React2.createElement(
800
+ Flex,
801
+ {
802
+ variant: "column-stretch-start-nowrap-16"
803
+ },
804
+ // Status actions
805
+ React2.createElement(
806
+ Flex,
807
+ { variant: "column-stretch-start-nowrap-8" },
808
+ React2.createElement(Typography, { variant: "caption-thick", color: "color-text-medium" }, "Status"),
809
+ React2.createElement(
810
+ Flex,
811
+ { variant: "row-center-start-nowrap-6" },
812
+ task.status === "failed" && React2.createElement(Button, {
813
+ size: "xs",
814
+ variant: "fill",
815
+ color: "primary",
816
+ onClick: handleRetry,
817
+ loading: actionLoading === "retry",
818
+ disabled: !!actionLoading
819
+ }, "Retry Task"),
820
+ (task.status === "pending" || task.status === "in-progress" || task.status === "blocked") && React2.createElement(Button, {
821
+ size: "xs",
822
+ variant: "outlined",
823
+ color: "danger",
824
+ onClick: handleCancel,
825
+ loading: actionLoading === "cancel",
826
+ disabled: !!actionLoading
827
+ }, "Cancel Task")
828
+ )
829
+ ),
830
+ // Priority
831
+ React2.createElement(
832
+ Flex,
833
+ { variant: "column-stretch-start-nowrap-8" },
834
+ React2.createElement(Typography, { variant: "caption-thick", color: "color-text-medium" }, "Priority"),
835
+ React2.createElement(
836
+ Flex,
837
+ { variant: "row-center-start-nowrap-8" },
838
+ React2.createElement(IconButton, {
839
+ icon: "expandLess",
840
+ size: "xs",
841
+ variant: "outlined",
842
+ onClick: () => handlePriorityChange(1),
843
+ title: "Increase priority"
844
+ }),
845
+ React2.createElement(
846
+ Typography,
847
+ { variant: "smallCaption-regular", color: "color-text-high" },
848
+ `P${task.priority ?? 0}`
849
+ ),
850
+ React2.createElement(IconButton, {
851
+ icon: "expandMore",
852
+ size: "xs",
853
+ variant: "outlined",
854
+ onClick: () => handlePriorityChange(-1),
855
+ title: "Decrease priority"
856
+ })
857
+ )
858
+ ),
859
+ // Assign Profile
860
+ availableProfiles.length > 0 && React2.createElement(
861
+ Flex,
862
+ { variant: "column-stretch-start-nowrap-8" },
863
+ React2.createElement(Typography, { variant: "caption-thick", color: "color-text-medium" }, "Assign Profile"),
864
+ React2.createElement(Table, {
865
+ size: "compact",
866
+ getRowKey: (row) => row.id,
867
+ columns: [
868
+ {
869
+ key: "icon",
870
+ header: "",
871
+ width: "30px",
872
+ render: (_, row) => React2.createElement(Icon, {
873
+ name: row.icon || "smartToy",
874
+ size: 14,
875
+ color: row.color || "color-text-medium"
876
+ })
877
+ },
878
+ {
879
+ key: "name",
880
+ header: "Profile"
881
+ },
882
+ {
883
+ key: "capabilities",
884
+ header: "Capabilities",
885
+ render: (_, row) => {
886
+ const caps = row.capabilities || [];
887
+ if (caps.length === 0) return null;
888
+ return React2.createElement(
889
+ Flex,
890
+ { variant: "row-center-start-wrap-4" },
891
+ ...caps.slice(0, 4).map(
892
+ (cap) => React2.createElement(
893
+ "span",
894
+ { key: cap.name, title: cap.description },
895
+ React2.createElement(Chip, { label: cap.name, size: "small", color: "color-brand-main" })
896
+ )
897
+ ),
898
+ caps.length > 4 && React2.createElement(Typography, {
899
+ variant: "smallCaption-regular",
900
+ color: "color-text-subtle"
901
+ }, `+${caps.length - 4}`)
902
+ );
903
+ }
904
+ },
905
+ {
906
+ key: "assigned",
907
+ header: "Assign",
908
+ width: "50px",
909
+ align: "right",
910
+ render: (_, row) => {
911
+ const isAssigned = task.assignedProfile === row.id;
912
+ return React2.createElement(Checkbox, {
913
+ checked: isAssigned,
914
+ onChange: () => handleAssignProfile(row.id),
915
+ size: "sm"
916
+ });
917
+ }
918
+ }
919
+ ],
920
+ data: availableProfiles
921
+ })
922
+ )
923
+ ),
924
+ // ── Context tab ──
925
+ detailTab === "context" && hasContext && React2.createElement(
926
+ Flex,
927
+ {
928
+ variant: "column-stretch-start-nowrap-12"
929
+ },
930
+ // Files
931
+ (task.context?.files?.length ?? 0) > 0 && React2.createElement(
932
+ Flex,
933
+ {
934
+ variant: "column-stretch-start-nowrap-4"
935
+ },
936
+ React2.createElement(Typography, { variant: "caption-thick", color: "color-text-medium" }, "Files"),
937
+ ...(task.context?.files ?? []).map(
938
+ (file) => React2.createElement(Typography, {
939
+ key: file,
940
+ variant: "smallCaption-regular",
941
+ color: "color-text-high",
942
+ style: { fontFamily: "var(--font-mono, monospace)" }
943
+ }, file)
944
+ )
945
+ ),
946
+ // Notes
947
+ task.context?.notes && React2.createElement(
948
+ Flex,
949
+ {
950
+ variant: "column-stretch-start-nowrap-4"
951
+ },
952
+ React2.createElement(Typography, { variant: "caption-thick", color: "color-text-medium" }, "Notes"),
953
+ React2.createElement(Typography, {
954
+ variant: "smallCaption-regular",
955
+ color: "color-text-high",
956
+ style: { whiteSpace: "pre-wrap" }
957
+ }, task.context.notes)
958
+ ),
959
+ // Last error
960
+ task.context?.lastError && React2.createElement(
961
+ Flex,
962
+ {
963
+ variant: "column-stretch-start-nowrap-4"
964
+ },
965
+ React2.createElement(Typography, { variant: "caption-thick", color: "color-status-negative" }, "Last Error"),
966
+ React2.createElement(Typography, {
967
+ variant: "smallCaption-regular",
968
+ color: "color-text-high",
969
+ style: { fontFamily: "var(--font-mono, monospace)", whiteSpace: "pre-wrap" }
970
+ }, task.context.lastError)
971
+ ),
972
+ // Run summaries (accumulated context)
973
+ (task.context?.runSummaries?.length ?? 0) > 0 && React2.createElement(
974
+ Flex,
975
+ {
976
+ variant: "column-stretch-start-nowrap-6"
977
+ },
978
+ React2.createElement(Typography, { variant: "caption-thick", color: "color-text-medium" }, "Run Summaries"),
979
+ ...(task.context?.runSummaries ?? []).map(
980
+ (rs, i) => React2.createElement(
981
+ Card,
982
+ {
983
+ key: `rs-${i}`,
984
+ variant: "bordered",
985
+ padding: "compact",
986
+ style: { gap: "4px" }
987
+ },
988
+ React2.createElement(
989
+ Flex,
990
+ { variant: "row-center-space-between-nowrap-8" },
991
+ React2.createElement(Typography, {
992
+ variant: "smallCaption-thick",
993
+ color: rs.outcome === "success" ? "color-status-positive" : "color-status-negative"
994
+ }, `${rs.outcome === "success" ? "Success" : "Failed"} (${rs.botId ?? "unknown bot"})`),
995
+ React2.createElement(Typography, {
996
+ variant: "smallCaption-regular",
997
+ color: "color-text-subtle"
998
+ }, `${Math.round((rs.durationMs ?? 0) / 1e3)}s \xB7 ${rs.tokensUsed ?? 0} tok \xB7 $${(rs.cost ?? 0).toFixed(3)}`)
999
+ ),
1000
+ React2.createElement(Typography, {
1001
+ variant: "smallCaption-regular",
1002
+ color: "color-text-medium"
1003
+ }, rs.summary ?? ""),
1004
+ (rs.filesModified ?? []).length > 0 && React2.createElement(Typography, {
1005
+ variant: "smallCaption-regular",
1006
+ color: "color-text-subtle",
1007
+ style: { fontFamily: "var(--font-mono, monospace)" }
1008
+ }, `Files: ${rs.filesModified.join(", ")}`),
1009
+ rs.error && React2.createElement(Typography, {
1010
+ variant: "smallCaption-regular",
1011
+ color: "color-status-negative"
1012
+ }, `Error: ${rs.error}`)
1013
+ )
1014
+ )
1015
+ ),
1016
+ // Budget
1017
+ (task.tokensUsed > 0 || task.costUsed > 0) && React2.createElement(
1018
+ Flex,
1019
+ {
1020
+ variant: "column-stretch-start-nowrap-4"
1021
+ },
1022
+ React2.createElement(Typography, { variant: "caption-thick", color: "color-text-medium" }, "Budget"),
1023
+ React2.createElement(
1024
+ Flex,
1025
+ { variant: "row-center-start-nowrap-16" },
1026
+ React2.createElement(
1027
+ Typography,
1028
+ { variant: "smallCaption-regular", color: "color-text-high" },
1029
+ `Tokens: ${task.tokensUsed?.toLocaleString() ?? 0}${task.budgetTokens ? ` / ${task.budgetTokens.toLocaleString()}` : ""}`
1030
+ ),
1031
+ React2.createElement(
1032
+ Typography,
1033
+ { variant: "smallCaption-regular", color: "color-text-high" },
1034
+ `Cost: $${(task.costUsed ?? 0).toFixed(3)}${task.budgetCost ? ` / $${task.budgetCost.toFixed(2)}` : ""}`
1035
+ )
1036
+ )
1037
+ )
1038
+ )
1039
+ )
1040
+ )
1041
+ );
1042
+ }
1043
+ var task_detail_view_default = TaskDetailView;
1044
+ module.exports = TaskDetailView;