@synergenius/flow-weaver-pack-weaver 0.9.201 → 0.9.203

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 (38) hide show
  1. package/dist/bot/preflight.d.ts.map +1 -1
  2. package/dist/bot/preflight.js +26 -0
  3. package/dist/bot/preflight.js.map +1 -1
  4. package/dist/bot/task-create-handler.d.ts +9 -0
  5. package/dist/bot/task-create-handler.d.ts.map +1 -1
  6. package/dist/bot/task-create-handler.js +26 -0
  7. package/dist/bot/task-create-handler.js.map +1 -1
  8. package/dist/node-types/agent-execute.d.ts.map +1 -1
  9. package/dist/node-types/agent-execute.js +26 -9
  10. package/dist/node-types/agent-execute.js.map +1 -1
  11. package/dist/node-types/plan-task.d.ts.map +1 -1
  12. package/dist/node-types/plan-task.js +28 -2
  13. package/dist/node-types/plan-task.js.map +1 -1
  14. package/dist/ui/bot-slot-card.js +10 -0
  15. package/dist/ui/budget-bar.js +5 -3
  16. package/dist/ui/budget-strip.js +156 -0
  17. package/dist/ui/chat-task-result.js +22 -27
  18. package/dist/ui/instance-stream-view.js +36 -0
  19. package/dist/ui/swarm-dashboard.js +1596 -1654
  20. package/dist/ui/task-detail-view.js +973 -485
  21. package/dist/ui/task-editor.js +32 -34
  22. package/dist/ui/task-pool-list.js +11 -3
  23. package/flowweaver.manifest.json +1 -1
  24. package/package.json +3 -2
  25. package/src/bot/preflight.ts +26 -0
  26. package/src/bot/task-create-handler.ts +39 -0
  27. package/src/node-types/agent-execute.ts +27 -10
  28. package/src/node-types/plan-task.ts +25 -2
  29. package/src/ui/bot-slot-card.tsx +23 -0
  30. package/src/ui/budget-bar.tsx +13 -5
  31. package/src/ui/budget-strip.tsx +199 -0
  32. package/src/ui/chat-task-result.tsx +5 -25
  33. package/src/ui/instance-stream-view.tsx +50 -1
  34. package/src/ui/swarm-dashboard.tsx +89 -84
  35. package/src/ui/task-detail-view.tsx +376 -442
  36. package/src/ui/task-editor.tsx +65 -96
  37. package/src/ui/task-pool-list.tsx +3 -12
  38. package/src/ui/task-status.ts +60 -0
@@ -24,8 +24,8 @@ __export(task_detail_view_exports, {
24
24
  default: () => task_detail_view_default
25
25
  });
26
26
  module.exports = __toCommonJS(task_detail_view_exports);
27
- var import_react = require("react");
28
- var import_plugin_ui_kit = require("@fw/plugin-ui-kit");
27
+ var import_react2 = require("react");
28
+ var import_plugin_ui_kit2 = require("@fw/plugin-ui-kit");
29
29
 
30
30
  // src/ui/use-stream-timeline.ts
31
31
  var React = require("react");
@@ -326,85 +326,629 @@ function traceToTimeline(run) {
326
326
  return entries;
327
327
  }
328
328
 
329
- // src/ui/task-detail-view.tsx
330
- var import_jsx_runtime = require("react/jsx-runtime");
331
- var statusToIcon = {
329
+ // src/ui/task-editor.tsx
330
+ var import_react = require("react");
331
+ var import_plugin_ui_kit = require("@fw/plugin-ui-kit");
332
+
333
+ // src/ui/task-status.ts
334
+ var TASK_STATUS_ICON = {
332
335
  "open": "pending",
333
336
  "in-progress": "running",
334
337
  "done": "completed",
335
338
  "cancelled": "failed"
336
339
  };
337
- var statusToLabel = {
340
+ var TASK_STATUS_ICON_OVERRIDE = {
341
+ "in-progress": "pendingActions"
342
+ };
343
+ var TASK_STATUS_LABEL = {
338
344
  "open": "Open",
339
- "in-progress": "Running",
345
+ "in-progress": "In Progress",
340
346
  "done": "Done",
341
347
  "cancelled": "Cancelled"
342
348
  };
343
- var headerStyle = {
344
- padding: "12px 16px",
345
- borderBottom: "1px solid var(--color-border-default)",
346
- flexShrink: 0
347
- };
348
- var fileItemStyle = {
349
- fontFamily: "monospace",
350
- fontSize: "12px",
351
- color: "var(--color-text-mid)",
352
- padding: "2px 4px",
353
- borderRadius: "4px"
349
+ var TASK_STATUS_CHIP = {
350
+ "open": "info",
351
+ "in-progress": "warning",
352
+ "done": "success",
353
+ "cancelled": "error"
354
354
  };
355
- var fileItemHoverStyle = {
356
- ...fileItemStyle,
357
- backgroundColor: "var(--color-surface-elevated)"
355
+ var TASK_STATUS_COLOR = {
356
+ "open": "color-brand-alt",
357
+ "in-progress": "color-status-info",
358
+ "done": "color-status-positive",
359
+ "cancelled": "color-status-negative"
358
360
  };
359
- var subtaskRowStyle = {
360
- padding: "6px 8px",
361
- cursor: "pointer",
362
- borderRadius: "6px"
363
- };
364
- var subtaskRowHoverStyle = {
365
- ...subtaskRowStyle,
366
- backgroundColor: "var(--color-surface-elevated)"
367
- };
368
- function SubtaskRowItem({ sub, onBack }) {
369
- const [hovered, setHovered] = (0, import_react.useState)(false);
361
+
362
+ // src/ui/task-editor.tsx
363
+ var import_jsx_runtime = require("react/jsx-runtime");
364
+ var PRIORITY_OPTIONS = [
365
+ { id: "0", label: "0 - None" },
366
+ { id: "1", label: "1 - Low" },
367
+ { id: "2", label: "2 - Medium" },
368
+ { id: "3", label: "3 - High" },
369
+ { id: "4", label: "4 - Critical" }
370
+ ];
371
+ var COMPLEXITY_OPTIONS = [
372
+ { id: "", label: "Not set" },
373
+ { id: "trivial", label: "Trivial" },
374
+ { id: "simple", label: "Simple" },
375
+ { id: "moderate", label: "Moderate" },
376
+ { id: "complex", label: "Complex" }
377
+ ];
378
+ function TaskEditor({ mode, taskId, onSave, onCancel, onDelete, embedded }) {
379
+ const ctx = (0, import_plugin_ui_kit.usePackWorkspace)();
380
+ const { callTool } = ctx;
381
+ const [title, setTitle] = (0, import_react.useState)("");
382
+ const [description, setDescription] = (0, import_react.useState)("");
383
+ const [priority, setPriority] = (0, import_react.useState)("0");
384
+ const [complexity, setComplexity] = (0, import_react.useState)("");
385
+ const [assignedProfile, setAssignedProfile] = (0, import_react.useState)("");
386
+ const [budgetCost, setBudgetCost] = (0, import_react.useState)("");
387
+ const [notes, setNotes] = (0, import_react.useState)("");
388
+ const [files, setFiles] = (0, import_react.useState)([]);
389
+ const [newFile, setNewFile] = (0, import_react.useState)("");
390
+ const [dependsOn, setDependsOn] = (0, import_react.useState)([]);
391
+ const [newDep, setNewDep] = (0, import_react.useState)("");
392
+ const [taskData, setTaskData] = (0, import_react.useState)(null);
393
+ const [profiles, setProfiles] = (0, import_react.useState)([]);
394
+ const [availableTasks, setAvailableTasks] = (0, import_react.useState)([]);
395
+ const [loading, setLoading] = (0, import_react.useState)(mode === "edit");
396
+ (0, import_react.useEffect)(() => {
397
+ (async () => {
398
+ try {
399
+ const raw = await callTool("fw_weaver_profile_list", {});
400
+ const data = typeof raw === "string" ? JSON.parse(raw) : raw;
401
+ if (Array.isArray(data)) {
402
+ setProfiles(data.map((p) => ({
403
+ id: p.id,
404
+ name: p.name || p.id
405
+ })));
406
+ }
407
+ } catch {
408
+ }
409
+ try {
410
+ const taskRaw = await callTool("fw_weaver_task_list", {});
411
+ const taskData2 = typeof taskRaw === "string" ? JSON.parse(taskRaw) : taskRaw;
412
+ if (Array.isArray(taskData2)) {
413
+ setAvailableTasks(taskData2.map((t) => ({
414
+ id: t.id,
415
+ title: t.title || t.id
416
+ })));
417
+ }
418
+ } catch {
419
+ }
420
+ })();
421
+ }, [callTool]);
422
+ (0, import_react.useEffect)(() => {
423
+ if (mode !== "edit" || !taskId) return;
424
+ let cancelled = false;
425
+ (async () => {
426
+ try {
427
+ const raw = await callTool("fw_weaver_task_get", { id: taskId });
428
+ if (cancelled) return;
429
+ const data = typeof raw === "string" ? JSON.parse(raw) : raw;
430
+ const t = data?.task ?? data;
431
+ if (!t || !t.id) {
432
+ (0, import_plugin_ui_kit.toast)("Task not found", { type: "error" });
433
+ onCancel();
434
+ return;
435
+ }
436
+ setTaskData(t);
437
+ setTitle(t.title || "");
438
+ setDescription(t.description || "");
439
+ setPriority(String(t.priority ?? 0));
440
+ setComplexity(t.complexity || "");
441
+ setAssignedProfile(t.assignedProfile || "");
442
+ setBudgetCost(t.budgetCost != null ? String(t.budgetCost) : "");
443
+ setNotes(t.context?.notes || "");
444
+ setFiles(t.context?.files || []);
445
+ setDependsOn(t.dependsOn || []);
446
+ } catch {
447
+ (0, import_plugin_ui_kit.toast)("Failed to load task", { type: "error" });
448
+ onCancel();
449
+ } finally {
450
+ if (!cancelled) setLoading(false);
451
+ }
452
+ })();
453
+ return () => {
454
+ cancelled = true;
455
+ };
456
+ }, [mode, taskId, callTool]);
457
+ const isDirty = (0, import_react.useCallback)(() => {
458
+ if (mode === "create") {
459
+ return !!(title.trim() || description.trim() || notes.trim() || files.length > 0 || dependsOn.length > 0 || priority !== "0" || complexity || assignedProfile || budgetCost);
460
+ }
461
+ if (!taskData) return false;
462
+ return title.trim() !== (taskData.title || "") || description.trim() !== (taskData.description || "") || notes.trim() !== (taskData.context?.notes || "") || JSON.stringify(files) !== JSON.stringify(taskData.context?.files || []) || priority !== String(taskData.priority ?? 0) || complexity !== (taskData.complexity || "") || assignedProfile !== (taskData.assignedProfile || "") || budgetCost !== (taskData.budgetCost != null ? String(taskData.budgetCost) : "");
463
+ }, [mode, title, description, notes, files, dependsOn, priority, complexity, assignedProfile, budgetCost, taskData]);
464
+ const handleBack = (0, import_react.useCallback)(async () => {
465
+ if (isDirty()) {
466
+ const ok = await ctx.confirm("Discard unsaved changes?", {
467
+ title: "Unsaved Changes",
468
+ state: "warning"
469
+ });
470
+ if (!ok) return;
471
+ }
472
+ onCancel();
473
+ }, [isDirty, ctx, onCancel]);
474
+ const handleAddFile = (0, import_react.useCallback)(() => {
475
+ const trimmed = newFile.trim();
476
+ if (!trimmed) return;
477
+ setFiles((prev) => [...prev, trimmed]);
478
+ setNewFile("");
479
+ }, [newFile]);
480
+ const handleRemoveFile = (0, import_react.useCallback)((index) => {
481
+ setFiles((prev) => prev.filter((_, i) => i !== index));
482
+ }, []);
483
+ const handleAddDep = (0, import_react.useCallback)(() => {
484
+ const trimmed = newDep.trim();
485
+ if (!trimmed) return;
486
+ setDependsOn((prev) => [...prev, trimmed]);
487
+ setNewDep("");
488
+ }, [newDep]);
489
+ const handleRemoveDep = (0, import_react.useCallback)((index) => {
490
+ setDependsOn((prev) => prev.filter((_, i) => i !== index));
491
+ }, []);
492
+ const handleSave = (0, import_react.useCallback)(async () => {
493
+ if (!title.trim()) {
494
+ (0, import_plugin_ui_kit.toast)("Title is required", { type: "error" });
495
+ return;
496
+ }
497
+ try {
498
+ if (mode === "create") {
499
+ const args = {
500
+ title: title.trim(),
501
+ description: description.trim(),
502
+ priority: parseInt(priority, 10) || 0
503
+ };
504
+ if (complexity) args.complexity = complexity;
505
+ if (assignedProfile) args.assignedProfile = assignedProfile;
506
+ if (budgetCost) args.budgetCost = parseFloat(budgetCost);
507
+ if (dependsOn.length > 0) args.dependsOn = dependsOn;
508
+ const result = await callTool("fw_weaver_task_create", args);
509
+ const createData = typeof result === "string" ? JSON.parse(result) : result;
510
+ const createdId = createData?.task?.id;
511
+ if (createdId && (notes.trim() || files.length > 0)) {
512
+ await callTool("fw_weaver_task_update", {
513
+ id: createdId,
514
+ context: {
515
+ notes: notes.trim(),
516
+ files,
517
+ runHistory: [],
518
+ stagnationCount: 0
519
+ }
520
+ });
521
+ }
522
+ (0, import_plugin_ui_kit.toast)("Task created", { type: "success" });
523
+ } else {
524
+ const patch = {
525
+ id: taskId,
526
+ title: title.trim(),
527
+ description: description.trim(),
528
+ priority: parseInt(priority, 10) || 0,
529
+ complexity: complexity || void 0,
530
+ assignedProfile: assignedProfile || null
531
+ };
532
+ if (budgetCost) {
533
+ patch.budgetCost = parseFloat(budgetCost);
534
+ } else {
535
+ patch.budgetCost = void 0;
536
+ }
537
+ patch.context = {
538
+ files,
539
+ notes: notes.trim(),
540
+ runHistory: taskData?.context?.runHistory || [],
541
+ stagnationCount: taskData?.context?.stagnationCount ?? 0
542
+ };
543
+ await callTool("fw_weaver_task_update", patch);
544
+ (0, import_plugin_ui_kit.toast)("Task updated", { type: "success" });
545
+ }
546
+ onSave();
547
+ } catch (err) {
548
+ (0, import_plugin_ui_kit.toast)(err instanceof Error ? err.message : `Failed to ${mode} task`, { type: "error" });
549
+ }
550
+ }, [mode, taskId, title, description, priority, complexity, assignedProfile, budgetCost, notes, files, dependsOn, taskData, callTool, onSave]);
551
+ const handleDelete = (0, import_react.useCallback)(async () => {
552
+ if (!taskId) return;
553
+ const ok = await ctx.confirm("Are you sure you want to cancel this task?", {
554
+ title: "Cancel Task",
555
+ confirmLabel: "Cancel Task",
556
+ state: "danger"
557
+ });
558
+ if (!ok) return;
559
+ try {
560
+ await callTool("fw_weaver_task_cancel", { id: taskId });
561
+ (0, import_plugin_ui_kit.toast)("Task cancelled", { type: "success" });
562
+ if (onDelete) onDelete();
563
+ } catch (err) {
564
+ (0, import_plugin_ui_kit.toast)(err instanceof Error ? err.message : "Failed to cancel task", { type: "error" });
565
+ }
566
+ }, [taskId, callTool, onDelete, ctx]);
567
+ if (loading) {
568
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
569
+ import_plugin_ui_kit.Flex,
570
+ {
571
+ variant: "column-center-center-nowrap-12",
572
+ style: { padding: "24px 16px" },
573
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "caption-regular", color: "color-text-subtle", children: "Loading task..." })
574
+ }
575
+ );
576
+ }
577
+ const profileOptions = [
578
+ { id: "", label: "Not assigned" },
579
+ ...profiles.map((p) => ({ id: p.id, label: p.name }))
580
+ ];
370
581
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
371
582
  import_plugin_ui_kit.Flex,
372
583
  {
373
- variant: "row-center-start-nowrap-8",
374
- style: hovered ? subtaskRowHoverStyle : subtaskRowStyle,
375
- onClick: () => onBack(),
376
- onMouseEnter: () => setHovered(true),
377
- onMouseLeave: () => setHovered(false),
584
+ variant: "column-stretch-start-nowrap-0",
585
+ style: { width: "100%", height: "100%", overflow: "hidden" },
378
586
  children: [
379
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
380
- import_plugin_ui_kit.StatusIcon,
587
+ !embedded && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
588
+ import_plugin_ui_kit.Flex,
381
589
  {
382
- status: statusToIcon[sub.status] || "pending",
383
- size: "sm"
590
+ variant: "row-center-space-between-nowrap-8",
591
+ style: { padding: "8px 16px", flexShrink: 0, borderBottom: "1px solid var(--color-border-default)" },
592
+ children: [
593
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "row-center-start-nowrap-8", children: [
594
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
595
+ import_plugin_ui_kit.IconButton,
596
+ {
597
+ icon: "back",
598
+ size: "xs",
599
+ variant: "clear",
600
+ onClick: handleBack,
601
+ title: "Back"
602
+ }
603
+ ),
604
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "caption-thick", color: "color-text-high", children: mode === "create" ? "Create Task" : "Edit Task" })
605
+ ] }),
606
+ mode === "edit" && onDelete && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
607
+ import_plugin_ui_kit.IconButton,
608
+ {
609
+ icon: "outlinedDelete",
610
+ size: "sm",
611
+ variant: "clear",
612
+ color: "danger",
613
+ onClick: handleDelete,
614
+ title: "Cancel task"
615
+ }
616
+ )
617
+ ]
384
618
  }
385
619
  ),
386
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
620
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
387
621
  import_plugin_ui_kit.Flex,
388
622
  {
389
- variant: "row-center-start-nowrap-0",
390
- style: { flex: 1, minWidth: 0 },
391
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "caption-regular", truncate: true, children: sub.title })
623
+ variant: "column-stretch-start-nowrap-10",
624
+ style: { flex: 1, minHeight: 0, overflow: "auto", padding: "12px 16px" },
625
+ children: [
626
+ mode === "edit" && taskData && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Field, { label: "Status", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
627
+ import_plugin_ui_kit.Chip,
628
+ {
629
+ label: taskData.status,
630
+ size: "small",
631
+ color: TASK_STATUS_COLOR[taskData.status] || "color-brand-alt"
632
+ }
633
+ ) }),
634
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Field, { label: "Title", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
635
+ import_plugin_ui_kit.Input,
636
+ {
637
+ type: "text",
638
+ size: "small",
639
+ placeholder: "Task title (required)",
640
+ value: title,
641
+ onChange: (v) => setTitle(v),
642
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
643
+ inputBoxStyle: { maxWidth: "none" }
644
+ }
645
+ ) }),
646
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Field, { label: "Description", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
647
+ import_plugin_ui_kit.Input,
648
+ {
649
+ type: "text",
650
+ size: "small",
651
+ placeholder: "Detailed task description",
652
+ value: description,
653
+ onChange: (v) => setDescription(v),
654
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
655
+ inputBoxStyle: { maxWidth: "none" }
656
+ }
657
+ ) }),
658
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Field, { label: "Priority", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
659
+ import_plugin_ui_kit.Input,
660
+ {
661
+ type: "select",
662
+ size: "small",
663
+ options: PRIORITY_OPTIONS,
664
+ optionId: priority,
665
+ onChange: (id) => setPriority(id),
666
+ defaultBoxStyle: { flex: 1, minWidth: 0 }
667
+ }
668
+ ) }),
669
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Field, { label: "Complexity", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
670
+ import_plugin_ui_kit.Input,
671
+ {
672
+ type: "select",
673
+ size: "small",
674
+ options: COMPLEXITY_OPTIONS,
675
+ optionId: complexity,
676
+ onChange: (id) => setComplexity(id),
677
+ defaultBoxStyle: { flex: 1, minWidth: 0 }
678
+ }
679
+ ) }),
680
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Field, { label: "Profile", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
681
+ import_plugin_ui_kit.Input,
682
+ {
683
+ type: "select",
684
+ size: "small",
685
+ options: profileOptions,
686
+ optionId: assignedProfile,
687
+ onChange: (id) => setAssignedProfile(id),
688
+ placeholder: "Select profile",
689
+ defaultBoxStyle: { flex: 1, minWidth: 0 }
690
+ }
691
+ ) }),
692
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Field, { label: "Budget Cost", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
693
+ import_plugin_ui_kit.Input,
694
+ {
695
+ type: "number",
696
+ size: "small",
697
+ placeholder: "Optional cost limit (USD)",
698
+ value: budgetCost,
699
+ onChange: (v) => setBudgetCost(v)
700
+ }
701
+ ) }),
702
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Field, { label: "Notes", align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
703
+ import_plugin_ui_kit.Input,
704
+ {
705
+ type: "text",
706
+ size: "small",
707
+ multiline: true,
708
+ placeholder: "Optional notes for context",
709
+ value: notes,
710
+ onChange: (v) => setNotes(v),
711
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
712
+ inputBoxStyle: { maxWidth: "none" }
713
+ }
714
+ ) }),
715
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Field, { label: "Files", align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-6", children: [
716
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
717
+ import_plugin_ui_kit.Input,
718
+ {
719
+ type: "path",
720
+ size: "small",
721
+ placeholder: "Click to browse files",
722
+ value: "",
723
+ onClick: async () => {
724
+ const selected = await ctx.browseFiles({ title: "Select Files", multiple: true });
725
+ if (selected.length > 0) {
726
+ setFiles((prev) => {
727
+ const unique = selected.filter((f) => !prev.includes(f));
728
+ return [...prev, ...unique];
729
+ });
730
+ }
731
+ },
732
+ defaultBoxStyle: { flex: 1, minWidth: 0 }
733
+ }
734
+ ),
735
+ files.map((file, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
736
+ import_plugin_ui_kit.Flex,
737
+ {
738
+ variant: "row-center-start-nowrap-6",
739
+ style: { paddingLeft: "4px" },
740
+ children: [
741
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
742
+ import_plugin_ui_kit.Typography,
743
+ {
744
+ variant: "smallCaption-regular",
745
+ color: "color-text-high",
746
+ style: { flex: 1, minWidth: 0, fontFamily: "var(--font-mono, monospace)" },
747
+ children: file
748
+ }
749
+ ),
750
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
751
+ import_plugin_ui_kit.IconButton,
752
+ {
753
+ icon: "close",
754
+ size: "xs",
755
+ variant: "clear",
756
+ color: "danger",
757
+ onClick: () => handleRemoveFile(idx)
758
+ }
759
+ )
760
+ ]
761
+ },
762
+ `file-${idx}`
763
+ ))
764
+ ] }) }),
765
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Field, { label: "Dependencies", align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-6", children: [
766
+ mode === "create" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "row-center-start-nowrap-4", children: [
767
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
768
+ import_plugin_ui_kit.Input,
769
+ {
770
+ type: "select",
771
+ size: "small",
772
+ placeholder: "Select a task",
773
+ options: availableTasks.filter((t) => !dependsOn.includes(t.id) && t.id !== taskId).map((t) => ({ id: t.id, label: t.title })),
774
+ optionId: newDep,
775
+ onChange: (v) => setNewDep(v),
776
+ defaultBoxStyle: { flex: 1, minWidth: 0 }
777
+ }
778
+ ),
779
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
780
+ import_plugin_ui_kit.IconButton,
781
+ {
782
+ icon: "add",
783
+ size: "sm",
784
+ variant: "outlined",
785
+ color: "primary",
786
+ onClick: handleAddDep,
787
+ disabled: !newDep.trim()
788
+ }
789
+ )
790
+ ] }),
791
+ dependsOn.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-4", children: dependsOn.map((dep, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
792
+ import_plugin_ui_kit.Flex,
793
+ {
794
+ variant: "row-center-start-nowrap-6",
795
+ style: { paddingLeft: "4px" },
796
+ children: [
797
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
798
+ import_plugin_ui_kit.Typography,
799
+ {
800
+ variant: "smallCaption-regular",
801
+ color: "color-text-high",
802
+ style: { flex: 1, minWidth: 0 },
803
+ children: (() => {
804
+ const t = availableTasks.find((t2) => t2.id === dep);
805
+ return t ? t.title : dep;
806
+ })()
807
+ }
808
+ ),
809
+ mode === "create" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
810
+ import_plugin_ui_kit.IconButton,
811
+ {
812
+ icon: "close",
813
+ size: "xs",
814
+ variant: "clear",
815
+ color: "danger",
816
+ onClick: () => handleRemoveDep(idx)
817
+ }
818
+ )
819
+ ]
820
+ },
821
+ `dep-${idx}`
822
+ )) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
823
+ import_plugin_ui_kit.Typography,
824
+ {
825
+ variant: "smallCaption-regular",
826
+ color: "color-text-subtle",
827
+ style: { paddingLeft: "4px" },
828
+ children: "None"
829
+ }
830
+ ),
831
+ mode === "edit" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
832
+ import_plugin_ui_kit.Typography,
833
+ {
834
+ variant: "smallCaption-regular",
835
+ color: "color-text-subtle",
836
+ style: { paddingLeft: "4px", fontStyle: "italic" },
837
+ children: "Dependencies cannot be changed after creation"
838
+ }
839
+ )
840
+ ] }) })
841
+ ]
392
842
  }
393
843
  ),
394
- sub.assignedProfile && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Chip, { label: sub.assignedProfile, size: "small", color: "color-status-info" })
844
+ !embedded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
845
+ import_plugin_ui_kit.Flex,
846
+ {
847
+ variant: "row-center-end-nowrap-8",
848
+ style: { padding: "8px 16px", flexShrink: 0, borderTop: "1px solid var(--color-border-default)" },
849
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
850
+ import_plugin_ui_kit.Button,
851
+ {
852
+ size: "xs",
853
+ variant: "fill",
854
+ color: "primary",
855
+ onClick: handleSave,
856
+ disabled: !title.trim(),
857
+ children: mode === "create" ? "Create" : "Save"
858
+ }
859
+ )
860
+ }
861
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
862
+ import_plugin_ui_kit.Flex,
863
+ {
864
+ variant: "row-center-end-nowrap-8",
865
+ style: { padding: "8px 16px", flexShrink: 0 },
866
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
867
+ import_plugin_ui_kit.Button,
868
+ {
869
+ size: "xs",
870
+ variant: "fill",
871
+ color: "primary",
872
+ onClick: handleSave,
873
+ disabled: !title.trim(),
874
+ children: "Save"
875
+ }
876
+ )
877
+ }
878
+ )
879
+ ]
880
+ }
881
+ );
882
+ }
883
+ var task_editor_default = TaskEditor;
884
+
885
+ // src/ui/task-detail-view.tsx
886
+ var import_jsx_runtime2 = require("react/jsx-runtime");
887
+ var headerStyle = {
888
+ padding: "12px 16px",
889
+ borderBottom: "1px solid var(--color-border-faint)",
890
+ flexShrink: 0
891
+ };
892
+ function SubtaskRowItem(props) {
893
+ const { sub, onClick } = props;
894
+ const [hovered, setHovered] = (0, import_react2.useState)(false);
895
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
896
+ import_plugin_ui_kit2.Flex,
897
+ {
898
+ variant: "row-center-start-nowrap-8",
899
+ style: {
900
+ padding: "6px 8px",
901
+ cursor: "pointer",
902
+ borderRadius: "6px",
903
+ backgroundColor: hovered ? "var(--color-surface-hover)" : "transparent"
904
+ },
905
+ onClick,
906
+ onMouseEnter: () => setHovered(true),
907
+ onMouseLeave: () => setHovered(false),
908
+ children: [
909
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.StatusIcon, { status: TASK_STATUS_ICON[sub.status] || "pending", icon: TASK_STATUS_ICON_OVERRIDE[sub.status], size: "sm" }),
910
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "caption-regular", truncate: true, style: { flex: 1, minWidth: 0 }, children: sub.title }),
911
+ sub.assignedProfile && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Chip, { label: sub.assignedProfile, size: "small", color: "color-status-info" })
395
912
  ]
396
913
  }
397
914
  );
398
915
  }
916
+ function AcceptanceCheckRow(props) {
917
+ const { name, pass, detail } = props;
918
+ const [expanded, setExpanded] = (0, import_react2.useState)(!pass && !!detail);
919
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
920
+ import_plugin_ui_kit2.CollapsibleBlock,
921
+ {
922
+ status: pass ? "completed" : "error",
923
+ label: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "row-center-start-nowrap-6", style: { flex: 1 }, children: [
924
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-thick", color: pass ? "color-status-positive" : "color-status-negative", children: name }),
925
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-text-subtle", children: pass ? "passed" : "failed" })
926
+ ] }),
927
+ expanded,
928
+ onToggle: () => setExpanded((v) => !v),
929
+ canExpand: !!detail,
930
+ children: detail && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
931
+ import_plugin_ui_kit2.Typography,
932
+ {
933
+ variant: "smallCaption-regular",
934
+ color: "color-text-medium",
935
+ mono: true,
936
+ style: { whiteSpace: "pre-wrap", padding: "6px 0" },
937
+ children: detail
938
+ }
939
+ )
940
+ }
941
+ );
942
+ }
399
943
  function TaskDetailView({ taskId, onBack, onEdit }) {
400
- const ctx = (0, import_plugin_ui_kit.usePackWorkspace)();
944
+ const ctx = (0, import_plugin_ui_kit2.usePackWorkspace)();
401
945
  const { callTool } = ctx;
402
946
  const packId = ctx.packId;
403
- const [task, setTask] = (0, import_react.useState)(null);
404
- const [subtasks, setSubtasks] = (0, import_react.useState)([]);
405
- const [history, setHistory] = (0, import_react.useState)([]);
406
- const [loading, setLoading] = (0, import_react.useState)(true);
407
- const fetchTask = (0, import_react.useCallback)(async () => {
947
+ const [task, setTask] = (0, import_react2.useState)(null);
948
+ const [subtasks, setSubtasks] = (0, import_react2.useState)([]);
949
+ const [history, setHistory] = (0, import_react2.useState)([]);
950
+ const [loading, setLoading] = (0, import_react2.useState)(true);
951
+ const fetchTask = (0, import_react2.useCallback)(async () => {
408
952
  try {
409
953
  const raw = await callTool("fw_weaver_task_get", { id: taskId });
410
954
  const data = typeof raw === "string" ? JSON.parse(raw) : raw;
@@ -435,14 +979,12 @@ function TaskDetailView({ taskId, onBack, onEdit }) {
435
979
  } else if (t.isParent) {
436
980
  const listRaw = await callTool("fw_weaver_task_list", { parentId: taskId });
437
981
  const listData = typeof listRaw === "string" ? JSON.parse(listRaw) : listRaw;
438
- if (Array.isArray(listData)) {
439
- setSubtasks(listData);
440
- }
982
+ if (Array.isArray(listData)) setSubtasks(listData);
441
983
  }
442
- } catch (err) {
984
+ } catch {
443
985
  }
444
986
  }, [callTool, taskId]);
445
- const fetchHistory = (0, import_react.useCallback)(async () => {
987
+ const fetchHistory = (0, import_react2.useCallback)(async () => {
446
988
  try {
447
989
  const raw = await callTool("fw_weaver_history", { taskId });
448
990
  const data = typeof raw === "string" ? JSON.parse(raw) : raw;
@@ -453,16 +995,15 @@ function TaskDetailView({ taskId, onBack, onEdit }) {
453
995
  return { ...r, costDetail: costObj, cost: costObj?.totalCost };
454
996
  })
455
997
  );
456
- return;
457
998
  }
458
999
  } catch {
459
1000
  }
460
1001
  }, [callTool, taskId]);
461
- (0, import_react.useEffect)(() => {
1002
+ (0, import_react2.useEffect)(() => {
462
1003
  setLoading(true);
463
1004
  Promise.all([fetchTask(), fetchHistory()]).finally(() => setLoading(false));
464
1005
  }, [fetchTask, fetchHistory]);
465
- (0, import_react.useEffect)(() => {
1006
+ (0, import_react2.useEffect)(() => {
466
1007
  if (!task || task.status !== "in-progress") return;
467
1008
  const interval = setInterval(() => {
468
1009
  fetchTask();
@@ -470,7 +1011,7 @@ function TaskDetailView({ taskId, onBack, onEdit }) {
470
1011
  }, 5e3);
471
1012
  return () => clearInterval(interval);
472
1013
  }, [task?.status, fetchTask, fetchHistory]);
473
- const stream = (0, import_plugin_ui_kit.useEventStream)();
1014
+ const stream = (0, import_plugin_ui_kit2.useEventStream)();
474
1015
  const {
475
1016
  timeline: liveTimeline,
476
1017
  phase: livePhase,
@@ -483,33 +1024,56 @@ function TaskDetailView({ taskId, onBack, onEdit }) {
483
1024
  } = useStreamTimeline(stream.events, stream.isDone);
484
1025
  const activeRunId = task?.activeRunId;
485
1026
  const isLive = task?.status === "in-progress" && !!activeRunId;
486
- (0, import_react.useEffect)(() => {
1027
+ (0, import_react2.useEffect)(() => {
487
1028
  if (!isLive || !activeRunId) return;
488
1029
  stream.start(packId, "fw_weaver_events", activeRunId);
489
1030
  return () => stream.stop();
490
1031
  }, [isLive, activeRunId, packId]);
491
- const [detailTab, setDetailTab] = (0, import_react.useState)("runs");
492
- const [actionLoading, setActionLoading] = (0, import_react.useState)(null);
493
- const [availableProfiles, setAvailableProfiles] = (0, import_react.useState)([]);
494
- (0, import_react.useEffect)(() => {
495
- callTool("fw_weaver_profile_list", {}).then((raw) => {
496
- const data = typeof raw === "string" ? JSON.parse(raw) : raw;
497
- if (Array.isArray(data)) setAvailableProfiles(data);
498
- }).catch(() => {
499
- });
1032
+ const [activeTab, setActiveTab] = (0, import_react2.useState)("runs");
1033
+ const [actionLoading, setActionLoading] = (0, import_react2.useState)(null);
1034
+ const [runningChecks, setRunningChecks] = (0, import_react2.useState)(false);
1035
+ const [approvalStatus, setApprovalStatus] = (0, import_react2.useState)(null);
1036
+ const [approvalLoading, setApprovalLoading] = (0, import_react2.useState)(false);
1037
+ (0, import_react2.useEffect)(() => {
1038
+ if (awaitingApproval) setApprovalStatus("pending");
1039
+ }, [awaitingApproval]);
1040
+ (0, import_react2.useEffect)(() => {
1041
+ if (stream.events.length === 0) setApprovalStatus(null);
1042
+ }, [stream.events.length]);
1043
+ const handleApprove = (0, import_react2.useCallback)(async () => {
1044
+ setApprovalLoading(true);
1045
+ try {
1046
+ await callTool("fw_weaver_approve", { approved: true });
1047
+ setApprovalStatus("approved");
1048
+ (0, import_plugin_ui_kit2.toast)("Plan approved", { type: "success" });
1049
+ } catch (err) {
1050
+ (0, import_plugin_ui_kit2.toast)(err instanceof Error ? err.message : "Failed to approve", { type: "error" });
1051
+ }
1052
+ setApprovalLoading(false);
1053
+ }, [callTool]);
1054
+ const handleReject = (0, import_react2.useCallback)(async () => {
1055
+ setApprovalLoading(true);
1056
+ try {
1057
+ await callTool("fw_weaver_approve", { approved: false });
1058
+ setApprovalStatus("rejected");
1059
+ (0, import_plugin_ui_kit2.toast)("Plan rejected", { type: "info" });
1060
+ } catch (err) {
1061
+ (0, import_plugin_ui_kit2.toast)(err instanceof Error ? err.message : "Failed to reject", { type: "error" });
1062
+ }
1063
+ setApprovalLoading(false);
500
1064
  }, [callTool]);
501
- const handleRetry = (0, import_react.useCallback)(async () => {
1065
+ const handleRetry = (0, import_react2.useCallback)(async () => {
502
1066
  setActionLoading("retry");
503
1067
  try {
504
1068
  await callTool("fw_weaver_task_retry", { id: taskId });
505
- (0, import_plugin_ui_kit.toast)("Task retried, back in pool", { type: "success" });
1069
+ (0, import_plugin_ui_kit2.toast)("Task retried, back in pool", { type: "success" });
506
1070
  fetchTask();
507
1071
  } catch (err) {
508
- (0, import_plugin_ui_kit.toast)(err instanceof Error ? err.message : "Failed to retry", { type: "error" });
1072
+ (0, import_plugin_ui_kit2.toast)(err instanceof Error ? err.message : "Failed to retry", { type: "error" });
509
1073
  }
510
1074
  setActionLoading(null);
511
1075
  }, [callTool, taskId, fetchTask]);
512
- const handleCancel = (0, import_react.useCallback)(async () => {
1076
+ const handleCancel = (0, import_react2.useCallback)(async () => {
513
1077
  const ok = await ctx.confirm("Cancel this task? It cannot be undone.", {
514
1078
  title: "Cancel Task",
515
1079
  confirmLabel: "Cancel Task",
@@ -519,74 +1083,35 @@ function TaskDetailView({ taskId, onBack, onEdit }) {
519
1083
  setActionLoading("cancel");
520
1084
  try {
521
1085
  await callTool("fw_weaver_task_cancel", { id: taskId });
522
- (0, import_plugin_ui_kit.toast)("Task cancelled", { type: "info" });
1086
+ (0, import_plugin_ui_kit2.toast)("Task cancelled", { type: "info" });
523
1087
  fetchTask();
524
1088
  } catch (err) {
525
- (0, import_plugin_ui_kit.toast)(err instanceof Error ? err.message : "Failed to cancel", { type: "error" });
1089
+ (0, import_plugin_ui_kit2.toast)(err instanceof Error ? err.message : "Failed to cancel", { type: "error" });
526
1090
  }
527
1091
  setActionLoading(null);
528
1092
  }, [callTool, taskId, fetchTask, ctx]);
529
- const handleAssignProfile = (0, import_react.useCallback)(async (profileId) => {
530
- setActionLoading("assign-profile");
1093
+ const handleRunChecks = (0, import_react2.useCallback)(async () => {
1094
+ setRunningChecks(true);
531
1095
  try {
532
- const newProfile = task?.assignedProfile === profileId ? void 0 : profileId;
533
- await callTool("fw_weaver_task_update", { id: taskId, assignedProfile: newProfile ?? null });
534
- (0, import_plugin_ui_kit.toast)(newProfile ? `Assigned profile ${profileId}` : `Unassigned profile`, { type: "success" });
535
- fetchTask();
1096
+ await callTool("fw_weaver_task_update", { id: taskId, runAcceptanceChecks: true });
1097
+ (0, import_plugin_ui_kit2.toast)("Acceptance checks triggered", { type: "info" });
1098
+ setTimeout(() => fetchTask(), 2e3);
536
1099
  } catch (err) {
537
- (0, import_plugin_ui_kit.toast)(err instanceof Error ? err.message : "Failed to assign profile", { type: "error" });
1100
+ (0, import_plugin_ui_kit2.toast)(err instanceof Error ? err.message : "Failed to run checks", { type: "error" });
538
1101
  }
539
- setActionLoading(null);
540
- }, [callTool, taskId, task, fetchTask]);
541
- const handlePriorityChange = (0, import_react.useCallback)(async (delta) => {
542
- const newPriority = Math.max(0, (task?.priority ?? 0) + delta);
543
- try {
544
- await callTool("fw_weaver_task_update", { id: taskId, priority: newPriority });
545
- fetchTask();
546
- } catch {
547
- }
548
- }, [callTool, taskId, task, fetchTask]);
549
- const [expandedRunId, setExpandedRunId] = (0, import_react.useState)(null);
550
- const [liveExpanded, setLiveExpanded] = (0, import_react.useState)(true);
551
- const toggleExpand = (0, import_react.useCallback)((id) => {
1102
+ setRunningChecks(false);
1103
+ }, [callTool, taskId, fetchTask]);
1104
+ const [expandedRunId, setExpandedRunId] = (0, import_react2.useState)(null);
1105
+ const [liveExpanded, setLiveExpanded] = (0, import_react2.useState)(true);
1106
+ const toggleExpand = (0, import_react2.useCallback)((id) => {
552
1107
  setExpandedRunId((prev) => prev === id ? null : id);
553
1108
  }, []);
554
- const scrollRef = (0, import_react.useRef)(null);
555
- (0, import_react.useEffect)(() => {
1109
+ const scrollRef = (0, import_react2.useRef)(null);
1110
+ (0, import_react2.useEffect)(() => {
556
1111
  const el = scrollRef.current;
557
1112
  if (el) el.scrollTop = el.scrollHeight;
558
1113
  }, [liveTimeline.length, stream.events.length]);
559
- const [approvalStatus, setApprovalStatus] = (0, import_react.useState)(null);
560
- const [approvalLoading, setApprovalLoading] = (0, import_react.useState)(false);
561
- (0, import_react.useEffect)(() => {
562
- if (awaitingApproval) setApprovalStatus("pending");
563
- }, [awaitingApproval]);
564
- (0, import_react.useEffect)(() => {
565
- if (stream.events.length === 0) setApprovalStatus(null);
566
- }, [stream.events.length]);
567
- const handleApprove = (0, import_react.useCallback)(async () => {
568
- setApprovalLoading(true);
569
- try {
570
- await callTool("fw_weaver_approve", { approved: true });
571
- setApprovalStatus("approved");
572
- (0, import_plugin_ui_kit.toast)("Plan approved", { type: "success" });
573
- } catch (err) {
574
- (0, import_plugin_ui_kit.toast)(err instanceof Error ? err.message : "Failed to approve", { type: "error" });
575
- }
576
- setApprovalLoading(false);
577
- }, [callTool]);
578
- const handleReject = (0, import_react.useCallback)(async () => {
579
- setApprovalLoading(true);
580
- try {
581
- await callTool("fw_weaver_approve", { approved: false });
582
- setApprovalStatus("rejected");
583
- (0, import_plugin_ui_kit.toast)("Plan rejected", { type: "info" });
584
- } catch (err) {
585
- (0, import_plugin_ui_kit.toast)(err instanceof Error ? err.message : "Failed to reject", { type: "error" });
586
- }
587
- setApprovalLoading(false);
588
- }, [callTool]);
589
- const runItems = (0, import_react.useMemo)(() => {
1114
+ const runItems = (0, import_react2.useMemo)(() => {
590
1115
  return history.map((run) => ({
591
1116
  run,
592
1117
  runTimeline: traceToTimeline(run)
@@ -620,383 +1145,346 @@ function TaskDetailView({ taskId, onBack, onEdit }) {
620
1145
  }
621
1146
  return task?.title ?? "Bot run";
622
1147
  }
623
- if (loading && !task) {
624
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
625
- import_plugin_ui_kit.Flex,
626
- {
627
- variant: "column-stretch-start-nowrap-0",
628
- style: { width: "100%", height: "100%", overflow: "hidden" },
629
- children: [
630
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-8", style: headerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Button, { variant: "ghost", size: "sm", onClick: onBack, children: [
631
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Icon, { name: "arrowBack", size: 16 }),
632
- " Back"
633
- ] }) }),
634
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Flex, { variant: "column-center-center-nowrap-0", style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "caption-regular", color: "color-text-subtle", children: "Loading task..." }) })
635
- ]
1148
+ const acceptanceChecks = task?.acceptance?.checks ?? [];
1149
+ const lastAcceptance = task?.lastAcceptanceCheck;
1150
+ const hasAcceptance = acceptanceChecks.length > 0;
1151
+ const hasContext = (task?.context?.files?.length ?? 0) > 0 || task?.context?.notes;
1152
+ const hasSubtasks = task?.isParent && subtasks.length > 0;
1153
+ const hasRuns = runItems.length > 0 || isLive;
1154
+ const attemptCount = task?.context?.runHistory?.length ?? 0;
1155
+ const isTerminal = task?.status === "done" || task?.status === "cancelled";
1156
+ const blockedByIds = task?.dependsOn?.length ? task.dependsOn : [];
1157
+ const filesChangedSincePass = (0, import_react2.useMemo)(() => {
1158
+ if (!lastAcceptance?.met || !lastAcceptance.checkedAt) return [];
1159
+ const passTime = new Date(lastAcceptance.checkedAt).getTime();
1160
+ const changed = [];
1161
+ for (const run of task?.context?.runHistory ?? []) {
1162
+ const runTime = new Date(run.endedAt).getTime();
1163
+ if (runTime > passTime) {
1164
+ changed.push(...run.filesModified ?? [], ...run.filesCreated ?? []);
636
1165
  }
637
- );
1166
+ }
1167
+ return [...new Set(changed)];
1168
+ }, [lastAcceptance, task?.context?.runHistory]);
1169
+ if (loading && !task) {
1170
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-0", style: { width: "100%", height: "100%", overflow: "hidden" }, children: [
1171
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-8", style: headerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Button, { variant: "ghost", size: "sm", onClick: onBack, children: [
1172
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Icon, { name: "arrowBack", size: 16 }),
1173
+ " Back"
1174
+ ] }) }),
1175
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Flex, { variant: "column-center-center-nowrap-0", style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "caption-regular", color: "color-text-subtle", children: "Loading task..." }) })
1176
+ ] });
638
1177
  }
639
1178
  if (!task) {
640
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
641
- import_plugin_ui_kit.Flex,
642
- {
643
- variant: "column-stretch-start-nowrap-0",
644
- style: { width: "100%", height: "100%", overflow: "hidden" },
645
- children: [
646
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-8", style: headerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Button, { variant: "ghost", size: "sm", onClick: onBack, children: [
647
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Icon, { name: "arrowBack", size: 16 }),
648
- " Back"
649
- ] }) }),
650
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Flex, { variant: "column-center-center-nowrap-0", style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "caption-regular", color: "color-text-subtle", children: "Task not found." }) })
651
- ]
652
- }
653
- );
1179
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-0", style: { width: "100%", height: "100%", overflow: "hidden" }, children: [
1180
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-8", style: headerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Button, { variant: "ghost", size: "sm", onClick: onBack, children: [
1181
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Icon, { name: "arrowBack", size: 16 }),
1182
+ " Back"
1183
+ ] }) }),
1184
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Flex, { variant: "column-center-center-nowrap-0", style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "caption-regular", color: "color-text-subtle", children: "Task not found." }) })
1185
+ ] });
654
1186
  }
655
- const hasContext = task.context?.files?.length > 0 || task.context?.notes;
656
- const hasSubtasks = task.isParent && subtasks.length > 0;
657
- const hasRuns = runItems.length > 0 || isLive;
658
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
659
- import_plugin_ui_kit.Flex,
660
- {
661
- variant: "column-stretch-start-nowrap-0",
662
- style: { width: "100%", height: "100%", overflow: "hidden" },
663
- children: [
664
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
665
- import_plugin_ui_kit.Flex,
1187
+ const tabs = [
1188
+ { id: "runs", title: `Runs (${runItems.length}${isLive ? "+1" : ""})` },
1189
+ ...hasAcceptance ? [{ id: "checks", title: "Checks" }] : [],
1190
+ { id: "details", title: "Details" },
1191
+ ...hasSubtasks ? [{ id: "subtasks", title: `Subtasks (${subtasks.filter((s) => s.status === "done").length}/${subtasks.length})` }] : [],
1192
+ ...hasContext ? [{ id: "context", title: "Context" }] : []
1193
+ ];
1194
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-0", style: { width: "100%", height: "100%", overflow: "hidden" }, children: [
1195
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-6", style: headerStyle, children: [
1196
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "row-center-space-between-nowrap-8", style: { minWidth: 0 }, children: [
1197
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "row-center-start-nowrap-8", style: { flex: 1, minWidth: 0 }, children: [
1198
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.IconButton, { icon: "back", size: "xs", variant: "clear", onClick: onBack }),
1199
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1200
+ import_plugin_ui_kit2.StatusIcon,
1201
+ {
1202
+ status: TASK_STATUS_ICON[task.status] || "pending",
1203
+ icon: TASK_STATUS_ICON_OVERRIDE[task.status],
1204
+ size: "sm"
1205
+ }
1206
+ ),
1207
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1208
+ import_plugin_ui_kit2.Typography,
1209
+ {
1210
+ variant: "caption-thick",
1211
+ color: "color-text-high",
1212
+ style: { flex: 1, minWidth: 0, wordBreak: "break-word" },
1213
+ children: task.title || "Untitled Task"
1214
+ }
1215
+ )
1216
+ ] }),
1217
+ !isTerminal && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "row-center-end-nowrap-4", style: { flexShrink: 0 }, children: [
1218
+ task.status === "open" && attemptCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1219
+ import_plugin_ui_kit2.IconButton,
1220
+ {
1221
+ icon: "replay",
1222
+ size: "xs",
1223
+ variant: "outlined",
1224
+ onClick: handleRetry,
1225
+ title: "Retry"
1226
+ }
1227
+ ),
1228
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1229
+ import_plugin_ui_kit2.IconButton,
1230
+ {
1231
+ icon: "close",
1232
+ size: "xs",
1233
+ variant: "outlined",
1234
+ color: "danger",
1235
+ onClick: handleCancel,
1236
+ title: "Cancel"
1237
+ }
1238
+ )
1239
+ ] })
1240
+ ] }),
1241
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "row-center-start-wrap-6", children: [
1242
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.StatusChip, { status: TASK_STATUS_CHIP[task.status] ?? "info", icon: TASK_STATUS_ICON[task.status], children: TASK_STATUS_LABEL[task.status] }),
1243
+ task.assignedProfile && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.StatusChip, { status: "info", icon: "person", children: task.assignedProfile }),
1244
+ task.priority > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1245
+ import_plugin_ui_kit2.StatusChip,
666
1246
  {
667
- variant: "column-stretch-start-nowrap-6",
668
- style: { ...headerStyle, padding: "12px 16px", borderBottom: "1px solid var(--color-border-default)" },
1247
+ status: task.priority >= 3 ? "error" : task.priority === 2 ? "warning" : "info",
1248
+ icon: "flag",
669
1249
  children: [
670
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "row-center-space-between-nowrap-8", children: [
671
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "row-center-start-nowrap-8", style: { flex: 1, minWidth: 0 }, children: [
672
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
673
- import_plugin_ui_kit.IconButton,
674
- {
675
- icon: "back",
676
- size: "xs",
677
- variant: "clear",
678
- onClick: onBack
679
- }
680
- ),
681
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
682
- import_plugin_ui_kit.StatusIcon,
683
- {
684
- status: statusToIcon[task.status] || "pending",
685
- size: "sm"
686
- }
687
- ),
688
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
689
- import_plugin_ui_kit.Typography,
690
- {
691
- variant: "caption-thick",
692
- color: "color-text-high",
693
- style: { flex: 1, minWidth: 0, wordBreak: "break-word" },
694
- children: task.title || "Untitled Task"
695
- }
696
- )
697
- ] }),
698
- onEdit && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
699
- import_plugin_ui_kit.IconButton,
700
- {
701
- icon: "edit",
702
- size: "xs",
703
- variant: "clear",
704
- onClick: () => onEdit(taskId),
705
- title: "Edit task"
706
- }
707
- )
708
- ] }),
709
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "row-center-start-wrap-6", children: [
710
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
711
- import_plugin_ui_kit.Chip,
712
- {
713
- label: statusToLabel[task.status] || task.status || "open",
714
- size: "small",
715
- color: task.status === "done" ? "color-status-positive" : task.status === "cancelled" ? "color-status-negative" : task.status === "in-progress" ? "color-status-info" : "color-brand-alt"
716
- }
717
- ),
718
- task.assignedProfile && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Chip, { label: task.assignedProfile, size: "small", color: "color-status-info" }, `profile-${task.assignedProfile}`),
719
- task.priority > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
720
- import_plugin_ui_kit.Chip,
721
- {
722
- label: `P${task.priority}`,
723
- size: "small",
724
- color: task.priority >= 3 ? "color-status-caution" : "color-status-info"
725
- }
726
- ),
727
- (task.context?.runHistory?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "smallCaption-regular", color: "color-text-subtle", children: `${task.context.runHistory.length} run${task.context.runHistory.length !== 1 ? "s" : ""}` })
728
- ] }),
729
- task.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "smallCaption-regular", color: "color-text-medium", children: task.description }),
730
- task.assignedProfile && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-2", children: [
731
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "smallCaption-regular", color: "color-text-medium", children: `Profile: ${task.assignedProfile}` }),
732
- task.routingReason && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "smallCaption-regular", color: "color-text-subtle", children: task.routingReason })
733
- ] })
1250
+ "P",
1251
+ task.priority
734
1252
  ]
735
1253
  }
736
1254
  ),
737
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
738
- import_plugin_ui_kit.Tabs,
1255
+ attemptCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.StatusChip, { status: "info", icon: "replay", children: [
1256
+ attemptCount,
1257
+ " ",
1258
+ attemptCount === 1 ? "attempt" : "attempts"
1259
+ ] }),
1260
+ task.costUsed > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.StatusChip, { status: "info", icon: "payments", children: [
1261
+ (0, import_plugin_ui_kit2.formatCost)(task.costUsed),
1262
+ task.budgetCost ? ` / ${(0, import_plugin_ui_kit2.formatCost)(task.budgetCost)}` : ""
1263
+ ] }),
1264
+ hasAcceptance && lastAcceptance && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1265
+ import_plugin_ui_kit2.StatusChip,
739
1266
  {
740
- tabs: [
741
- { id: "runs", title: `Runs (${runItems.length}${isLive ? "+1" : ""})` },
742
- ...hasSubtasks ? [{ id: "subtasks", title: `Subtasks (${subtasks.filter((s) => s.status === "done").length}/${subtasks.length})` }] : [],
743
- ...task.status !== "done" && task.status !== "cancelled" ? [{ id: "actions", title: "Actions" }] : [],
744
- ...hasContext ? [{ id: "context", title: "Context" }] : []
745
- ],
746
- activeTabId: detailTab,
747
- onSelectTab: (id) => setDetailTab(id),
748
- size: "sm"
1267
+ status: lastAcceptance.met ? "success" : "error",
1268
+ icon: lastAcceptance.met ? "checkCircle" : "cancel",
1269
+ children: lastAcceptance.met ? "Checks pass" : "Checks fail"
749
1270
  }
750
- ),
751
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.ScrollArea, { ref: scrollRef, style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-8", style: { padding: "12px 16px" }, children: [
752
- detailTab === "runs" && (hasRuns || (task.context?.runHistory?.length ?? 0) > 0) ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-8", children: [
753
- runItems.map(({ run, runTimeline }) => {
754
- const runId = run.id;
755
- const isExpanded = expandedRunId === runId;
756
- const isSuccess = run.outcome === "completed" || run.success === true;
757
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
758
- import_plugin_ui_kit.TaskBlock,
759
- {
760
- state: isSuccess ? "completed" : "failed",
761
- instruction: extractInstruction(run),
762
- timeline: runTimeline,
763
- report: run.report ?? null,
764
- cost: typeof run.cost === "number" ? run.cost : run.costDetail?.totalCost ?? null,
765
- plan: run.plan,
766
- startedAt: run.startedAt,
767
- durationMs: run.durationMs ?? run.duration,
768
- expanded: isExpanded,
769
- onToggleExpand: () => toggleExpand(runId)
770
- },
771
- `run-${runId}`
772
- );
773
- }),
774
- isLive && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
775
- import_plugin_ui_kit.TaskBlock,
776
- {
777
- state: "running",
778
- instruction: liveInstruction ?? task.title,
779
- timeline: liveTimeline,
780
- report: liveReport,
781
- phase: livePhase,
782
- elapsed,
783
- cost: liveCost,
784
- plan,
785
- error: stream.error,
786
- approval: approvalStatus ?? void 0,
787
- approvalLoading,
788
- onApprove: handleApprove,
789
- onReject: handleReject,
790
- expanded: liveExpanded,
791
- onToggleExpand: () => setLiveExpanded((v) => !v)
792
- },
793
- "live-run"
794
- )
795
- ] }) : detailTab === "runs" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
796
- import_plugin_ui_kit.EmptyState,
1271
+ )
1272
+ ] }),
1273
+ task.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-text-medium", truncate: true, children: task.description })
1274
+ ] }),
1275
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1276
+ import_plugin_ui_kit2.Tabs,
1277
+ {
1278
+ tabs,
1279
+ activeTabId: activeTab,
1280
+ onSelectTab: (id) => setActiveTab(id),
1281
+ size: "sm"
1282
+ }
1283
+ ),
1284
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.ScrollArea, { ref: scrollRef, style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-12", style: { padding: "12px 16px" }, children: [
1285
+ activeTab === "checks" && hasAcceptance && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-8", children: [
1286
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "row-center-space-between-nowrap-8", children: [
1287
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "caption-thick", color: "color-text-medium", children: "Acceptance Checks" }),
1288
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1289
+ import_plugin_ui_kit2.Button,
797
1290
  {
798
- icon: "smartToy",
799
- message: "No runs yet",
800
- description: "This task has not been executed yet."
1291
+ size: "xs",
1292
+ variant: "outlined",
1293
+ onClick: handleRunChecks,
1294
+ loading: runningChecks,
1295
+ disabled: runningChecks || isLive,
1296
+ children: [
1297
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Icon, { name: "playArrow", size: 12 }),
1298
+ " Run"
1299
+ ]
801
1300
  }
802
- ),
803
- detailTab === "subtasks" && hasSubtasks && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-0", children: (subtasks ?? []).map((sub) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
804
- SubtaskRowItem,
1301
+ )
1302
+ ] }),
1303
+ lastAcceptance ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-4", children: [
1304
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "row-center-start-nowrap-8", children: [
1305
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1306
+ import_plugin_ui_kit2.StatusChip,
1307
+ {
1308
+ status: lastAcceptance.met ? "success" : "error",
1309
+ icon: lastAcceptance.met ? "check" : "close",
1310
+ children: [
1311
+ lastAcceptance.results.filter((r) => r.pass).length,
1312
+ "/",
1313
+ lastAcceptance.results.length,
1314
+ " passed"
1315
+ ]
1316
+ }
1317
+ ),
1318
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-text-subtle", children: new Date(lastAcceptance.checkedAt).toLocaleTimeString() })
1319
+ ] }),
1320
+ lastAcceptance.results.map((r) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1321
+ AcceptanceCheckRow,
805
1322
  {
806
- sub,
807
- onBack
1323
+ name: r.name,
1324
+ pass: r.pass,
1325
+ detail: r.detail
808
1326
  },
809
- sub.id
810
- )) }),
811
- detailTab === "actions" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-16", children: [
812
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-8", children: [
813
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "caption-thick", color: "color-text-medium", children: "Status" }),
814
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "row-center-start-nowrap-6", children: [
815
- task.status === "open" && (task.context?.runHistory?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
816
- import_plugin_ui_kit.Button,
817
- {
818
- size: "xs",
819
- variant: "fill",
820
- color: "primary",
821
- onClick: handleRetry,
822
- loading: actionLoading === "retry",
823
- disabled: !!actionLoading,
824
- children: "Retry Task"
825
- }
826
- ),
827
- (task.status === "open" || task.status === "in-progress") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
828
- import_plugin_ui_kit.Button,
829
- {
830
- size: "xs",
831
- variant: "outlined",
832
- color: "danger",
833
- onClick: handleCancel,
834
- loading: actionLoading === "cancel",
835
- disabled: !!actionLoading,
836
- children: "Cancel Task"
837
- }
838
- )
1327
+ r.name
1328
+ )),
1329
+ lastAcceptance.met && filesChangedSincePass.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-4", style: { marginTop: "4px" }, children: [
1330
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "row-center-start-nowrap-6", children: [
1331
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Icon, { name: "warning", size: 12, color: "color-status-caution" }),
1332
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-status-caution", children: [
1333
+ filesChangedSincePass.length,
1334
+ " file",
1335
+ filesChangedSincePass.length !== 1 ? "s" : "",
1336
+ " changed since last pass"
839
1337
  ] })
840
1338
  ] }),
841
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-8", children: [
842
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "caption-thick", color: "color-text-medium", children: "Priority" }),
843
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "row-center-start-nowrap-8", children: [
844
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
845
- import_plugin_ui_kit.IconButton,
846
- {
847
- icon: "expandLess",
848
- size: "xs",
849
- variant: "outlined",
850
- onClick: () => handlePriorityChange(1),
851
- title: "Increase priority"
852
- }
853
- ),
854
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "smallCaption-regular", color: "color-text-high", children: `P${task.priority ?? 0}` }),
855
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
856
- import_plugin_ui_kit.IconButton,
857
- {
858
- icon: "expandMore",
859
- size: "xs",
860
- variant: "outlined",
861
- onClick: () => handlePriorityChange(-1),
862
- title: "Decrease priority"
863
- }
864
- )
865
- ] })
866
- ] }),
867
- availableProfiles.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-8", children: [
868
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "caption-thick", color: "color-text-medium", children: "Assign Profile" }),
869
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
870
- import_plugin_ui_kit.Table,
871
- {
872
- size: "compact",
873
- getRowKey: (row) => row.id,
874
- columns: [
875
- {
876
- key: "icon",
877
- header: "",
878
- width: "30px",
879
- render: (_, row) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
880
- import_plugin_ui_kit.Icon,
881
- {
882
- name: row.icon || "smartToy",
883
- size: 14,
884
- color: row.color || "color-text-medium"
885
- }
886
- )
887
- },
888
- {
889
- key: "name",
890
- header: "Profile"
891
- },
892
- {
893
- key: "capabilities",
894
- header: "Capabilities",
895
- render: (_, row) => {
896
- const caps = row.capabilities || [];
897
- if (caps.length === 0) return null;
898
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "row-center-start-wrap-4", children: [
899
- caps.slice(0, 4).map((cap) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { title: cap.description, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Chip, { label: cap.name, size: "small", color: "color-brand-main" }) }, cap.name)),
900
- caps.length > 4 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "smallCaption-regular", color: "color-text-subtle", children: `+${caps.length - 4}` })
901
- ] });
902
- }
903
- },
904
- {
905
- key: "assigned",
906
- header: "Assign",
907
- width: "50px",
908
- align: "right",
909
- render: (_, row) => {
910
- const isAssigned = task.assignedProfile === row.id;
911
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
912
- import_plugin_ui_kit.Checkbox,
913
- {
914
- checked: isAssigned,
915
- onChange: () => handleAssignProfile(row.id),
916
- size: "sm"
917
- }
918
- );
919
- }
920
- }
921
- ],
922
- data: availableProfiles
923
- }
924
- )
1339
+ filesChangedSincePass.slice(0, 5).map((f) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-text-subtle", mono: true, children: f }, f)),
1340
+ filesChangedSincePass.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-text-subtle", children: [
1341
+ "+",
1342
+ filesChangedSincePass.length - 5,
1343
+ " more"
925
1344
  ] })
926
- ] }),
927
- detailTab === "context" && hasContext && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-12", children: [
928
- (task.context?.files?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-4", children: [
929
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "caption-thick", color: "color-text-medium", children: "Files" }),
930
- (task.context?.files ?? []).map((file) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
931
- import_plugin_ui_kit.Typography,
932
- {
933
- variant: "smallCaption-regular",
934
- color: "color-text-high",
935
- style: { fontFamily: "var(--font-mono, monospace)" },
936
- children: file
937
- },
938
- file
939
- ))
940
- ] }),
941
- task.context?.notes && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-4", children: [
942
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "caption-thick", color: "color-text-medium", children: "Notes" }),
943
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
944
- import_plugin_ui_kit.Typography,
945
- {
946
- variant: "smallCaption-regular",
947
- color: "color-text-high",
948
- style: { whiteSpace: "pre-wrap" },
949
- children: task.context.notes
950
- }
951
- )
952
- ] }),
953
- (task.context?.runHistory?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-6", children: [
954
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "caption-thick", color: "color-text-medium", children: "Run History" }),
955
- (task.context?.runHistory ?? []).map((rs, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
956
- import_plugin_ui_kit.Card,
1345
+ ] })
1346
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-4", children: [
1347
+ acceptanceChecks.map((check) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "row-center-start-nowrap-6", children: [
1348
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Icon, { name: "schedule", size: 12, color: "color-text-subtle" }),
1349
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-text-medium", children: check.name }),
1350
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-text-subtle", mono: true, children: check.command })
1351
+ ] }, check.name)),
1352
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-text-subtle", children: "Not yet run" })
1353
+ ] })
1354
+ ] }),
1355
+ activeTab === "details" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { margin: "-12px -16px", flex: 1, minHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1356
+ task_editor_default,
1357
+ {
1358
+ mode: "edit",
1359
+ taskId,
1360
+ embedded: true,
1361
+ onSave: () => {
1362
+ fetchTask();
1363
+ setActiveTab("actions");
1364
+ },
1365
+ onCancel: () => setActiveTab("actions"),
1366
+ onDelete: () => {
1367
+ fetchTask();
1368
+ setActiveTab("actions");
1369
+ }
1370
+ }
1371
+ ) }),
1372
+ activeTab === "runs" && (hasRuns ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-8", children: [
1373
+ runItems.map(({ run, runTimeline }) => {
1374
+ const runId = run.id;
1375
+ const isExpanded = expandedRunId === runId;
1376
+ const isSuccess = run.outcome === "completed" || run.success === true;
1377
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1378
+ import_plugin_ui_kit2.TaskBlock,
1379
+ {
1380
+ state: isSuccess ? "completed" : "failed",
1381
+ instruction: extractInstruction(run),
1382
+ timeline: runTimeline,
1383
+ report: run.report ?? null,
1384
+ cost: typeof run.cost === "number" ? run.cost : run.costDetail?.totalCost ?? null,
1385
+ plan: run.plan,
1386
+ startedAt: run.startedAt,
1387
+ durationMs: run.durationMs ?? run.duration,
1388
+ expanded: isExpanded,
1389
+ onToggleExpand: () => toggleExpand(runId)
1390
+ },
1391
+ `run-${runId}`
1392
+ );
1393
+ }),
1394
+ isLive && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1395
+ import_plugin_ui_kit2.TaskBlock,
1396
+ {
1397
+ state: "running",
1398
+ instruction: liveInstruction ?? task.title,
1399
+ timeline: liveTimeline,
1400
+ report: liveReport,
1401
+ phase: livePhase,
1402
+ elapsed,
1403
+ cost: liveCost,
1404
+ plan,
1405
+ error: stream.error,
1406
+ approval: approvalStatus ?? void 0,
1407
+ approvalLoading,
1408
+ onApprove: handleApprove,
1409
+ onReject: handleReject,
1410
+ expanded: liveExpanded,
1411
+ onToggleExpand: () => setLiveExpanded((v) => !v)
1412
+ },
1413
+ "live-run"
1414
+ )
1415
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1416
+ import_plugin_ui_kit2.EmptyState,
1417
+ {
1418
+ icon: "smartToy",
1419
+ message: "No runs yet",
1420
+ description: "This task has not been executed yet."
1421
+ }
1422
+ )),
1423
+ activeTab === "subtasks" && hasSubtasks && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-0", children: (subtasks ?? []).map((sub) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SubtaskRowItem, { sub, onClick: onBack }, sub.id)) }),
1424
+ activeTab === "context" && hasContext && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-12", children: [
1425
+ (task.context?.files?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-4", children: [
1426
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "caption-thick", color: "color-text-medium", children: "Files" }),
1427
+ (task.context?.files ?? []).map((file) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1428
+ import_plugin_ui_kit2.Typography,
1429
+ {
1430
+ variant: "smallCaption-regular",
1431
+ color: "color-text-high",
1432
+ mono: true,
1433
+ children: file
1434
+ },
1435
+ file
1436
+ ))
1437
+ ] }),
1438
+ task.context?.notes && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-4", children: [
1439
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "caption-thick", color: "color-text-medium", children: "Notes" }),
1440
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1441
+ import_plugin_ui_kit2.Typography,
1442
+ {
1443
+ variant: "smallCaption-regular",
1444
+ color: "color-text-high",
1445
+ style: { whiteSpace: "pre-wrap" },
1446
+ children: task.context.notes
1447
+ }
1448
+ )
1449
+ ] }),
1450
+ (task.context?.runHistory?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "column-stretch-start-nowrap-6", children: [
1451
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "caption-thick", color: "color-text-medium", children: "Run History" }),
1452
+ (task.context?.runHistory ?? []).map((rs, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Card, { variant: "bordered", padding: "compact", style: { gap: "4px" }, children: [
1453
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Flex, { variant: "row-center-space-between-nowrap-8", children: [
1454
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1455
+ import_plugin_ui_kit2.Typography,
957
1456
  {
958
- variant: "bordered",
959
- padding: "compact",
960
- style: { gap: "4px" },
1457
+ variant: "smallCaption-thick",
1458
+ color: rs.outcome === "success" ? "color-status-positive" : "color-status-negative",
961
1459
  children: [
962
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "row-center-space-between-nowrap-8", children: [
963
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
964
- import_plugin_ui_kit.Typography,
965
- {
966
- variant: "smallCaption-thick",
967
- color: rs.outcome === "success" ? "color-status-positive" : "color-status-negative",
968
- children: `${rs.outcome === "success" ? "Success" : "Failed"} (${rs.botId ?? "unknown bot"})`
969
- }
970
- ),
971
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "smallCaption-regular", color: "color-text-subtle", children: `${Math.round((rs.durationMs ?? 0) / 1e3)}s \xB7 ${rs.tokensUsed ?? 0} tok \xB7 $${(rs.cost ?? 0).toFixed(3)}` })
972
- ] }),
973
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "smallCaption-regular", color: "color-text-medium", children: rs.summary ?? "" }),
974
- (rs.filesModified ?? []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
975
- import_plugin_ui_kit.Typography,
976
- {
977
- variant: "smallCaption-regular",
978
- color: "color-text-subtle",
979
- style: { fontFamily: "var(--font-mono, monospace)" },
980
- children: `Files: ${rs.filesModified.join(", ")}`
981
- }
982
- ),
983
- rs.remainingWork && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "smallCaption-regular", color: "color-status-caution", children: `Remaining: ${rs.remainingWork}` })
1460
+ rs.outcome === "success" ? "Success" : "Failed",
1461
+ " (",
1462
+ rs.botId ?? "unknown bot",
1463
+ ")"
984
1464
  ]
985
- },
986
- `rs-${i}`
987
- ))
988
- ] }),
989
- (task.tokensUsed > 0 || task.costUsed > 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "column-stretch-start-nowrap-4", children: [
990
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "caption-thick", color: "color-text-medium", children: "Budget" }),
991
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_plugin_ui_kit.Flex, { variant: "row-center-start-nowrap-16", children: [
992
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "smallCaption-regular", color: "color-text-high", children: `Tokens: ${task.tokensUsed?.toLocaleString() ?? 0}` }),
993
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_plugin_ui_kit.Typography, { variant: "smallCaption-regular", color: "color-text-high", children: `Cost: $${(task.costUsed ?? 0).toFixed(3)}${task.budgetCost ? ` / $${task.budgetCost.toFixed(2)}` : ""}` })
1465
+ }
1466
+ ),
1467
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-text-subtle", children: [
1468
+ (0, import_plugin_ui_kit2.formatDuration)(rs.durationMs ?? 0),
1469
+ " \xB7 ",
1470
+ rs.tokensUsed ?? 0,
1471
+ " tok \xB7 ",
1472
+ (0, import_plugin_ui_kit2.formatCost)(rs.cost ?? 0)
994
1473
  ] })
1474
+ ] }),
1475
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-text-medium", children: rs.summary ?? "" }),
1476
+ (rs.filesModified ?? []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-text-subtle", mono: true, children: [
1477
+ "Files: ",
1478
+ rs.filesModified.join(", ")
1479
+ ] }),
1480
+ rs.remainingWork && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_plugin_ui_kit2.Typography, { variant: "smallCaption-regular", color: "color-status-caution", children: [
1481
+ "Remaining: ",
1482
+ rs.remainingWork
995
1483
  ] })
996
- ] })
997
- ] }) })
998
- ]
999
- }
1000
- );
1484
+ ] }, `rs-${i}`))
1485
+ ] })
1486
+ ] })
1487
+ ] }) })
1488
+ ] });
1001
1489
  }
1002
1490
  var task_detail_view_default = TaskDetailView;