@synergenius/flow-weaver-pack-weaver 0.9.80 → 0.9.82

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.
@@ -383,7 +383,7 @@ function SubtaskRowItem({ sub, onBack }) {
383
383
  }, `#${sub.attempt}`)
384
384
  );
385
385
  }
386
- function TaskDetailView({ taskId, onBack }) {
386
+ function TaskDetailView({ taskId, onBack, onEdit }) {
387
387
  const ctx = usePackWorkspace();
388
388
  const { callTool } = ctx;
389
389
  const packId = ctx.packId;
@@ -660,25 +660,36 @@ function TaskDetailView({ taskId, onBack }) {
660
660
  variant: "column-stretch-start-nowrap-6",
661
661
  style: { ...headerStyle, padding: "12px 16px", borderBottom: "1px solid var(--color-border-default)" }
662
662
  },
663
- // Top row: back + title + status
663
+ // Top row: back + title + status + edit
664
664
  React2.createElement(
665
665
  Flex,
666
- { variant: "row-center-start-nowrap-8" },
667
- React2.createElement(IconButton, {
668
- icon: "back",
666
+ { variant: "row-center-space-between-nowrap-8" },
667
+ React2.createElement(
668
+ Flex,
669
+ { variant: "row-center-start-nowrap-8", style: { flex: 1, minWidth: 0 } },
670
+ React2.createElement(IconButton, {
671
+ icon: "back",
672
+ size: "xs",
673
+ variant: "clear",
674
+ onClick: onBack
675
+ }),
676
+ React2.createElement(StatusIcon, {
677
+ status: statusToIcon[task.status] || "pending",
678
+ size: "sm"
679
+ }),
680
+ React2.createElement(Typography, {
681
+ variant: "caption-thick",
682
+ color: "color-text-high",
683
+ style: { flex: 1, minWidth: 0, wordBreak: "break-word" }
684
+ }, task.title || "Untitled Task")
685
+ ),
686
+ onEdit && React2.createElement(IconButton, {
687
+ icon: "edit",
669
688
  size: "xs",
670
689
  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")
690
+ onClick: () => onEdit(taskId),
691
+ title: "Edit task"
692
+ })
682
693
  ),
683
694
  // Meta row: status tag, assigned profile, priority, attempts
684
695
  React2.createElement(
@@ -0,0 +1,613 @@
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-editor.tsx
21
+ var task_editor_exports = {};
22
+ __export(task_editor_exports, {
23
+ TaskEditor: () => TaskEditor,
24
+ default: () => task_editor_default
25
+ });
26
+ module.exports = __toCommonJS(task_editor_exports);
27
+ var React = require("react");
28
+ var { useState, useEffect, useCallback } = React;
29
+ var {
30
+ Flex,
31
+ Typography,
32
+ Input,
33
+ Button,
34
+ IconButton,
35
+ Tag,
36
+ Field,
37
+ toast,
38
+ usePackWorkspace
39
+ } = require("@fw/plugin-ui-kit");
40
+ var PRIORITY_OPTIONS = [
41
+ { id: "0", label: "0 \u2014 None" },
42
+ { id: "1", label: "1 \u2014 Low" },
43
+ { id: "2", label: "2 \u2014 Medium" },
44
+ { id: "3", label: "3 \u2014 High" },
45
+ { id: "4", label: "4 \u2014 Critical" }
46
+ ];
47
+ var COMPLEXITY_OPTIONS = [
48
+ { id: "", label: "Not set" },
49
+ { id: "trivial", label: "Trivial" },
50
+ { id: "simple", label: "Simple" },
51
+ { id: "moderate", label: "Moderate" },
52
+ { id: "complex", label: "Complex" }
53
+ ];
54
+ var STATUS_COLOR = {
55
+ "pending": "secondary",
56
+ "in-progress": "info",
57
+ "blocked": "caution",
58
+ "done": "positive",
59
+ "failed": "negative",
60
+ "cancelled": "negative"
61
+ };
62
+ function TaskEditor({ mode, taskId, onSave, onCancel, onDelete }) {
63
+ const ctx = usePackWorkspace();
64
+ const { callTool } = ctx;
65
+ const [title, setTitle] = useState("");
66
+ const [description, setDescription] = useState("");
67
+ const [priority, setPriority] = useState("0");
68
+ const [complexity, setComplexity] = useState("");
69
+ const [assignedProfile, setAssignedProfile] = useState("");
70
+ const [maxAttempts, setMaxAttempts] = useState("3");
71
+ const [budgetTokens, setBudgetTokens] = useState("");
72
+ const [budgetCost, setBudgetCost] = useState("");
73
+ const [notes, setNotes] = useState("");
74
+ const [files, setFiles] = useState([]);
75
+ const [newFile, setNewFile] = useState("");
76
+ const [dependsOn, setDependsOn] = useState([]);
77
+ const [newDep, setNewDep] = useState("");
78
+ const [taskData, setTaskData] = useState(null);
79
+ const [profiles, setProfiles] = useState([]);
80
+ const [loading, setLoading] = useState(mode === "edit");
81
+ useEffect(() => {
82
+ (async () => {
83
+ try {
84
+ const raw = await callTool("fw_weaver_profile_list", {});
85
+ const data = typeof raw === "string" ? JSON.parse(raw) : raw;
86
+ if (Array.isArray(data)) {
87
+ setProfiles(data.map((p) => ({
88
+ id: p.id,
89
+ name: p.name || p.id
90
+ })));
91
+ }
92
+ } catch {
93
+ }
94
+ })();
95
+ }, [callTool]);
96
+ useEffect(() => {
97
+ if (mode !== "edit" || !taskId) return;
98
+ let cancelled = false;
99
+ (async () => {
100
+ try {
101
+ const raw = await callTool("fw_weaver_task_get", { id: taskId });
102
+ if (cancelled) return;
103
+ const data = typeof raw === "string" ? JSON.parse(raw) : raw;
104
+ const t = data?.task ?? data;
105
+ if (!t || !t.id) {
106
+ toast("Task not found", { type: "error" });
107
+ onCancel();
108
+ return;
109
+ }
110
+ setTaskData(t);
111
+ setTitle(t.title || "");
112
+ setDescription(t.description || "");
113
+ setPriority(String(t.priority ?? 0));
114
+ setComplexity(t.complexity || "");
115
+ setAssignedProfile(t.assignedProfile || "");
116
+ setMaxAttempts(String(t.maxAttempts ?? 3));
117
+ setBudgetTokens(t.budgetTokens != null ? String(t.budgetTokens) : "");
118
+ setBudgetCost(t.budgetCost != null ? String(t.budgetCost) : "");
119
+ setNotes(t.context?.notes || "");
120
+ setFiles(t.context?.files || []);
121
+ setDependsOn(t.dependsOn || []);
122
+ } catch {
123
+ toast("Failed to load task", { type: "error" });
124
+ onCancel();
125
+ } finally {
126
+ if (!cancelled) setLoading(false);
127
+ }
128
+ })();
129
+ return () => {
130
+ cancelled = true;
131
+ };
132
+ }, [mode, taskId, callTool, onCancel]);
133
+ const handleAddFile = useCallback(() => {
134
+ const trimmed = newFile.trim();
135
+ if (!trimmed) return;
136
+ setFiles((prev) => [...prev, trimmed]);
137
+ setNewFile("");
138
+ }, [newFile]);
139
+ const handleRemoveFile = useCallback((index) => {
140
+ setFiles((prev) => prev.filter((_, i) => i !== index));
141
+ }, []);
142
+ const handleAddDep = useCallback(() => {
143
+ const trimmed = newDep.trim();
144
+ if (!trimmed) return;
145
+ setDependsOn((prev) => [...prev, trimmed]);
146
+ setNewDep("");
147
+ }, [newDep]);
148
+ const handleRemoveDep = useCallback((index) => {
149
+ setDependsOn((prev) => prev.filter((_, i) => i !== index));
150
+ }, []);
151
+ const handleSave = useCallback(async () => {
152
+ if (!title.trim()) {
153
+ toast("Title is required", { type: "error" });
154
+ return;
155
+ }
156
+ try {
157
+ if (mode === "create") {
158
+ const args = {
159
+ title: title.trim(),
160
+ description: description.trim(),
161
+ priority: parseInt(priority, 10) || 0,
162
+ maxAttempts: parseInt(maxAttempts, 10) || 3
163
+ };
164
+ if (complexity) args.complexity = complexity;
165
+ if (assignedProfile) args.assignedProfile = assignedProfile;
166
+ if (budgetTokens) args.budgetTokens = parseInt(budgetTokens, 10);
167
+ if (budgetCost) args.budgetCost = parseFloat(budgetCost);
168
+ if (dependsOn.length > 0) args.dependsOn = dependsOn;
169
+ await callTool("fw_weaver_task_create", args);
170
+ toast("Task created", { type: "success" });
171
+ if (notes.trim() || files.length > 0) {
172
+ try {
173
+ } catch {
174
+ }
175
+ }
176
+ } else {
177
+ const patch = {
178
+ id: taskId,
179
+ title: title.trim(),
180
+ description: description.trim(),
181
+ priority: parseInt(priority, 10) || 0,
182
+ maxAttempts: parseInt(maxAttempts, 10) || 3,
183
+ complexity: complexity || void 0,
184
+ assignedProfile: assignedProfile || null
185
+ };
186
+ if (budgetTokens) {
187
+ patch.budgetTokens = parseInt(budgetTokens, 10);
188
+ } else {
189
+ patch.budgetTokens = void 0;
190
+ }
191
+ if (budgetCost) {
192
+ patch.budgetCost = parseFloat(budgetCost);
193
+ } else {
194
+ patch.budgetCost = void 0;
195
+ }
196
+ patch.context = {
197
+ files,
198
+ notes: notes.trim(),
199
+ runSummaries: taskData?.context?.runSummaries || [],
200
+ lastError: taskData?.context?.lastError
201
+ };
202
+ await callTool("fw_weaver_task_update", patch);
203
+ toast("Task updated", { type: "success" });
204
+ }
205
+ onSave();
206
+ } catch (err) {
207
+ toast(err instanceof Error ? err.message : `Failed to ${mode} task`, { type: "error" });
208
+ }
209
+ }, [mode, taskId, title, description, priority, complexity, assignedProfile, maxAttempts, budgetTokens, budgetCost, notes, files, dependsOn, taskData, callTool, onSave]);
210
+ const handleDelete = useCallback(async () => {
211
+ if (!taskId) return;
212
+ const ok = await ctx.confirm("Are you sure you want to cancel this task?", {
213
+ title: "Cancel Task",
214
+ confirmLabel: "Cancel Task",
215
+ state: "danger"
216
+ });
217
+ if (!ok) return;
218
+ try {
219
+ await callTool("fw_weaver_task_cancel", { id: taskId });
220
+ toast("Task cancelled", { type: "success" });
221
+ if (onDelete) onDelete();
222
+ } catch (err) {
223
+ toast(err instanceof Error ? err.message : "Failed to cancel task", { type: "error" });
224
+ }
225
+ }, [taskId, callTool, onDelete, ctx]);
226
+ if (loading) {
227
+ return React.createElement(
228
+ Flex,
229
+ {
230
+ variant: "column-center-center-nowrap-12",
231
+ style: { padding: "24px 16px" }
232
+ },
233
+ React.createElement(Typography, { variant: "caption-regular", color: "color-text-subtle" }, "Loading task...")
234
+ );
235
+ }
236
+ const profileOptions = [
237
+ { id: "", label: "Not assigned" },
238
+ ...profiles.map((p) => ({ id: p.id, label: p.name }))
239
+ ];
240
+ return React.createElement(
241
+ Flex,
242
+ {
243
+ variant: "column-stretch-start-nowrap-0",
244
+ style: { width: "100%", height: "100%", overflow: "hidden" }
245
+ },
246
+ // -- Header bar --
247
+ React.createElement(
248
+ Flex,
249
+ {
250
+ variant: "row-center-space-between-nowrap-8",
251
+ style: { padding: "8px 16px", flexShrink: 0, borderBottom: "1px solid var(--color-border-default)" }
252
+ },
253
+ React.createElement(
254
+ Flex,
255
+ { variant: "row-center-start-nowrap-8" },
256
+ React.createElement(IconButton, {
257
+ icon: "back",
258
+ size: "xs",
259
+ variant: "clear",
260
+ onClick: onCancel,
261
+ title: "Back"
262
+ }),
263
+ React.createElement(
264
+ Typography,
265
+ { variant: "caption-thick", color: "color-text-high" },
266
+ mode === "create" ? "Create Task" : "Edit Task"
267
+ )
268
+ ),
269
+ mode === "edit" && onDelete && React.createElement(IconButton, {
270
+ icon: "outlinedDelete",
271
+ size: "sm",
272
+ variant: "clear",
273
+ color: "danger",
274
+ onClick: handleDelete,
275
+ title: "Cancel task"
276
+ })
277
+ ),
278
+ // -- Scrollable form body --
279
+ React.createElement(
280
+ Flex,
281
+ {
282
+ variant: "column-stretch-start-nowrap-10",
283
+ style: { flex: 1, minHeight: 0, overflow: "auto", padding: "12px 16px" }
284
+ },
285
+ // -- Edit-only: Status tag --
286
+ mode === "edit" && taskData && React.createElement(
287
+ Field,
288
+ { label: "Status" },
289
+ React.createElement(Tag, {
290
+ size: "small",
291
+ color: STATUS_COLOR[taskData.status] || "secondary"
292
+ }, taskData.status)
293
+ ),
294
+ // -- Title --
295
+ React.createElement(
296
+ Field,
297
+ { label: "Title" },
298
+ React.createElement(Input, {
299
+ type: "text",
300
+ size: "small",
301
+ placeholder: "Task title (required)",
302
+ value: title,
303
+ onChange: (v) => setTitle(v),
304
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
305
+ inputBoxStyle: { maxWidth: "none" }
306
+ })
307
+ ),
308
+ // -- Description --
309
+ React.createElement(
310
+ Field,
311
+ { label: "Description" },
312
+ React.createElement(Input, {
313
+ type: "text",
314
+ size: "small",
315
+ placeholder: "Detailed task description",
316
+ value: description,
317
+ onChange: (v) => setDescription(v),
318
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
319
+ inputBoxStyle: { maxWidth: "none" }
320
+ })
321
+ ),
322
+ // -- Priority --
323
+ React.createElement(
324
+ Field,
325
+ { label: "Priority" },
326
+ React.createElement(Input, {
327
+ type: "select",
328
+ size: "small",
329
+ options: PRIORITY_OPTIONS,
330
+ optionId: priority,
331
+ onChange: (id) => setPriority(id),
332
+ defaultBoxStyle: { flex: 1, minWidth: 0 }
333
+ })
334
+ ),
335
+ // -- Complexity --
336
+ React.createElement(
337
+ Field,
338
+ { label: "Complexity" },
339
+ React.createElement(Input, {
340
+ type: "select",
341
+ size: "small",
342
+ options: COMPLEXITY_OPTIONS,
343
+ optionId: complexity,
344
+ onChange: (id) => setComplexity(id),
345
+ defaultBoxStyle: { flex: 1, minWidth: 0 }
346
+ })
347
+ ),
348
+ // -- Assigned Profile --
349
+ React.createElement(
350
+ Field,
351
+ { label: "Profile" },
352
+ React.createElement(Input, {
353
+ type: "select",
354
+ size: "small",
355
+ options: profileOptions,
356
+ optionId: assignedProfile,
357
+ onChange: (id) => setAssignedProfile(id),
358
+ placeholder: "Select profile",
359
+ defaultBoxStyle: { flex: 1, minWidth: 0 }
360
+ })
361
+ ),
362
+ // -- Max Attempts --
363
+ React.createElement(
364
+ Field,
365
+ { label: "Max Attempts" },
366
+ React.createElement(Input, {
367
+ type: "number",
368
+ size: "small",
369
+ placeholder: "3",
370
+ value: maxAttempts,
371
+ onChange: (v) => setMaxAttempts(v),
372
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
373
+ inputBoxStyle: { maxWidth: "none" }
374
+ })
375
+ ),
376
+ // -- Budget Tokens --
377
+ React.createElement(
378
+ Field,
379
+ { label: "Budget Tokens" },
380
+ React.createElement(Input, {
381
+ type: "number",
382
+ size: "small",
383
+ placeholder: "Optional token limit",
384
+ value: budgetTokens,
385
+ onChange: (v) => setBudgetTokens(v),
386
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
387
+ inputBoxStyle: { maxWidth: "none" }
388
+ })
389
+ ),
390
+ // -- Budget Cost --
391
+ React.createElement(
392
+ Field,
393
+ { label: "Budget Cost" },
394
+ React.createElement(Input, {
395
+ type: "number",
396
+ size: "small",
397
+ placeholder: "Optional cost limit (USD)",
398
+ value: budgetCost,
399
+ onChange: (v) => setBudgetCost(v),
400
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
401
+ inputBoxStyle: { maxWidth: "none" }
402
+ })
403
+ ),
404
+ // -- Notes --
405
+ React.createElement(
406
+ Field,
407
+ { label: "Notes" },
408
+ React.createElement(Input, {
409
+ type: "text",
410
+ size: "small",
411
+ placeholder: "Optional notes for context",
412
+ value: notes,
413
+ onChange: (v) => setNotes(v),
414
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
415
+ inputBoxStyle: { maxWidth: "none" }
416
+ })
417
+ ),
418
+ // -- Files --
419
+ React.createElement(
420
+ Field,
421
+ { label: "Files", align: "start" },
422
+ React.createElement(
423
+ Flex,
424
+ { variant: "column-stretch-start-nowrap-6" },
425
+ // Add file row
426
+ React.createElement(
427
+ Flex,
428
+ { variant: "row-center-start-nowrap-4", style: { overflow: "hidden" } },
429
+ React.createElement(Input, {
430
+ type: "text",
431
+ size: "small",
432
+ placeholder: "File path",
433
+ value: newFile,
434
+ onChange: (v) => setNewFile(v),
435
+ onEnter: handleAddFile,
436
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
437
+ inputBoxStyle: { maxWidth: "none" }
438
+ }),
439
+ React.createElement(IconButton, {
440
+ icon: "add",
441
+ size: "sm",
442
+ variant: "outlined",
443
+ color: "primary",
444
+ onClick: handleAddFile,
445
+ disabled: !newFile.trim()
446
+ })
447
+ ),
448
+ ...files.map(
449
+ (file, idx) => React.createElement(
450
+ Flex,
451
+ {
452
+ key: `file-${idx}`,
453
+ variant: "row-center-start-nowrap-6",
454
+ style: { paddingLeft: "4px" }
455
+ },
456
+ React.createElement(Typography, {
457
+ variant: "smallCaption-regular",
458
+ color: "color-text-high",
459
+ style: { flex: 1, minWidth: 0, fontFamily: "var(--font-mono, monospace)" }
460
+ }, file),
461
+ React.createElement(IconButton, {
462
+ icon: "close",
463
+ size: "xs",
464
+ variant: "clear",
465
+ color: "danger",
466
+ onClick: () => handleRemoveFile(idx)
467
+ })
468
+ )
469
+ )
470
+ )
471
+ ),
472
+ // -- Dependencies --
473
+ React.createElement(
474
+ Field,
475
+ { label: "Dependencies", align: "start" },
476
+ React.createElement(
477
+ Flex,
478
+ { variant: "column-stretch-start-nowrap-6" },
479
+ // Add dependency row (create mode only)
480
+ mode === "create" && React.createElement(
481
+ Flex,
482
+ { variant: "row-center-start-nowrap-4", style: { overflow: "hidden" } },
483
+ React.createElement(Input, {
484
+ type: "text",
485
+ size: "small",
486
+ placeholder: "Task ID",
487
+ value: newDep,
488
+ onChange: (v) => setNewDep(v),
489
+ onEnter: handleAddDep,
490
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
491
+ inputBoxStyle: { maxWidth: "none" }
492
+ }),
493
+ React.createElement(IconButton, {
494
+ icon: "add",
495
+ size: "sm",
496
+ variant: "outlined",
497
+ color: "primary",
498
+ onClick: handleAddDep,
499
+ disabled: !newDep.trim()
500
+ })
501
+ ),
502
+ // Dependency list
503
+ dependsOn.length > 0 ? React.createElement(
504
+ Flex,
505
+ { variant: "column-stretch-start-nowrap-4" },
506
+ ...dependsOn.map(
507
+ (dep, idx) => React.createElement(
508
+ Flex,
509
+ {
510
+ key: `dep-${idx}`,
511
+ variant: "row-center-start-nowrap-6",
512
+ style: { paddingLeft: "4px" }
513
+ },
514
+ React.createElement(Typography, {
515
+ variant: "smallCaption-regular",
516
+ color: "color-text-high",
517
+ style: { flex: 1, minWidth: 0, fontFamily: "var(--font-mono, monospace)" }
518
+ }, dep),
519
+ mode === "create" && React.createElement(IconButton, {
520
+ icon: "close",
521
+ size: "xs",
522
+ variant: "clear",
523
+ color: "danger",
524
+ onClick: () => handleRemoveDep(idx)
525
+ })
526
+ )
527
+ )
528
+ ) : React.createElement(Typography, {
529
+ variant: "smallCaption-regular",
530
+ color: "color-text-subtle",
531
+ style: { paddingLeft: "4px" }
532
+ }, "None")
533
+ )
534
+ ),
535
+ // -- Edit-only: read-only metadata --
536
+ mode === "edit" && taskData && React.createElement(
537
+ Flex,
538
+ {
539
+ variant: "column-stretch-start-nowrap-10",
540
+ style: { marginTop: 8, paddingTop: 12, borderTop: "1px solid var(--color-border-default)" }
541
+ },
542
+ React.createElement(
543
+ Field,
544
+ { label: "Created by" },
545
+ React.createElement(
546
+ Typography,
547
+ { variant: "smallCaption-regular", color: "color-text-medium" },
548
+ taskData.createdBy || "unknown"
549
+ )
550
+ ),
551
+ React.createElement(
552
+ Field,
553
+ { label: "Created at" },
554
+ React.createElement(
555
+ Typography,
556
+ { variant: "smallCaption-regular", color: "color-text-medium" },
557
+ taskData.createdAt ? new Date(taskData.createdAt).toLocaleString() : "-"
558
+ )
559
+ ),
560
+ React.createElement(
561
+ Field,
562
+ { label: "Updated at" },
563
+ React.createElement(
564
+ Typography,
565
+ { variant: "smallCaption-regular", color: "color-text-medium" },
566
+ taskData.updatedAt ? new Date(taskData.updatedAt).toLocaleString() : "-"
567
+ )
568
+ ),
569
+ React.createElement(
570
+ Field,
571
+ { label: "Tokens used" },
572
+ React.createElement(
573
+ Typography,
574
+ { variant: "smallCaption-regular", color: "color-text-medium" },
575
+ (taskData.tokensUsed ?? 0).toLocaleString()
576
+ )
577
+ ),
578
+ React.createElement(
579
+ Field,
580
+ { label: "Cost used" },
581
+ React.createElement(
582
+ Typography,
583
+ { variant: "smallCaption-regular", color: "color-text-medium" },
584
+ `$${(taskData.costUsed ?? 0).toFixed(3)}`
585
+ )
586
+ ),
587
+ taskData.context?.lastError && React.createElement(
588
+ Field,
589
+ { label: "Last error", align: "start" },
590
+ React.createElement(Typography, {
591
+ variant: "smallCaption-regular",
592
+ color: "color-status-negative",
593
+ style: { fontFamily: "var(--font-mono, monospace)", whiteSpace: "pre-wrap" }
594
+ }, taskData.context.lastError)
595
+ )
596
+ ),
597
+ // -- Save button --
598
+ React.createElement(
599
+ Flex,
600
+ { variant: "row-center-end-nowrap-8", style: { paddingTop: 8 } },
601
+ React.createElement(Button, {
602
+ size: "xs",
603
+ variant: "fill",
604
+ color: "primary",
605
+ onClick: handleSave,
606
+ disabled: !title.trim()
607
+ }, mode === "create" ? "Create" : "Save")
608
+ )
609
+ )
610
+ );
611
+ }
612
+ var task_editor_default = TaskEditor;
613
+ module.exports = TaskEditor;