bosun 0.41.2 → 0.41.3

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 (71) hide show
  1. package/.env.example +1 -1
  2. package/agent/agent-prompt-catalog.mjs +971 -0
  3. package/agent/agent-prompts.mjs +2 -970
  4. package/agent/agent-supervisor.mjs +6 -3
  5. package/agent/autofix-git.mjs +33 -0
  6. package/agent/autofix-prompts.mjs +151 -0
  7. package/agent/autofix.mjs +11 -175
  8. package/agent/bosun-skills.mjs +3 -2
  9. package/bosun.config.example.json +17 -0
  10. package/bosun.schema.json +87 -188
  11. package/cli.mjs +34 -1
  12. package/config/config-doctor.mjs +5 -250
  13. package/config/config-file-names.mjs +5 -0
  14. package/config/config.mjs +89 -493
  15. package/config/executor-config.mjs +493 -0
  16. package/config/repo-root.mjs +1 -2
  17. package/config/workspace-health.mjs +242 -0
  18. package/git/git-safety.mjs +15 -0
  19. package/github/github-oauth-portal.mjs +46 -0
  20. package/infra/library-manager-utils.mjs +22 -0
  21. package/infra/library-manager-well-known-sources.mjs +578 -0
  22. package/infra/library-manager.mjs +512 -1030
  23. package/infra/monitor.mjs +28 -9
  24. package/infra/session-tracker.mjs +10 -7
  25. package/kanban/kanban-adapter.mjs +17 -1
  26. package/lib/codebase-audit-manifests.mjs +117 -0
  27. package/lib/codebase-audit.mjs +18 -115
  28. package/package.json +18 -3
  29. package/server/ui-server.mjs +1194 -79
  30. package/shell/codex-config-file.mjs +178 -0
  31. package/shell/codex-config.mjs +538 -575
  32. package/task/task-cli.mjs +54 -3
  33. package/task/task-executor.mjs +143 -13
  34. package/task/task-store.mjs +409 -1
  35. package/telegram/telegram-bot.mjs +127 -0
  36. package/tools/apply-pr-suggestions.mjs +401 -0
  37. package/tools/syntax-check.mjs +21 -9
  38. package/ui/app.js +3 -14
  39. package/ui/components/kanban-board.js +227 -4
  40. package/ui/components/session-list.js +85 -5
  41. package/ui/demo-defaults.js +334 -80
  42. package/ui/demo.html +155 -0
  43. package/ui/modules/session-api.js +96 -0
  44. package/ui/modules/settings-schema.js +1 -2
  45. package/ui/modules/state.js +21 -3
  46. package/ui/setup.html +4 -5
  47. package/ui/styles/components.css +58 -4
  48. package/ui/tabs/agents.js +12 -15
  49. package/ui/tabs/control.js +1 -0
  50. package/ui/tabs/library.js +484 -22
  51. package/ui/tabs/manual-flows.js +105 -29
  52. package/ui/tabs/tasks.js +785 -140
  53. package/ui/tabs/telemetry.js +129 -11
  54. package/ui/tabs/workflow-canvas-utils.mjs +130 -0
  55. package/ui/tabs/workflows.js +293 -23
  56. package/voice/voice-tool-definitions.mjs +757 -0
  57. package/voice/voice-tools.mjs +34 -778
  58. package/workflow/manual-flow-audit.mjs +165 -0
  59. package/workflow/manual-flows.mjs +164 -259
  60. package/workflow/workflow-engine.mjs +147 -58
  61. package/workflow/workflow-nodes/definitions.mjs +1207 -0
  62. package/workflow/workflow-nodes/transforms.mjs +612 -0
  63. package/workflow/workflow-nodes.mjs +304 -52
  64. package/workflow/workflow-templates.mjs +313 -191
  65. package/workflow-templates/_helpers.mjs +154 -0
  66. package/workflow-templates/agents.mjs +61 -4
  67. package/workflow-templates/code-quality.mjs +7 -7
  68. package/workflow-templates/github.mjs +20 -10
  69. package/workflow-templates/task-batch.mjs +20 -9
  70. package/workflow-templates/task-lifecycle.mjs +31 -6
  71. package/workspace/worktree-manager.mjs +277 -3
@@ -111,13 +111,13 @@ async function loadRuns() {
111
111
  }
112
112
  }
113
113
 
114
- async function executeFlow(templateId, formValues) {
114
+ async function executeFlow(templateId, formValues, executionContext = {}) {
115
115
  executing.value = true;
116
116
  try {
117
117
  const data = await apiFetch("/api/manual-flows/execute", {
118
118
  method: "POST",
119
119
  headers: { "Content-Type": "application/json" },
120
- body: JSON.stringify({ templateId, formValues }),
120
+ body: JSON.stringify({ templateId, formValues, executionContext }),
121
121
  });
122
122
  if (data?.run) {
123
123
  activeRun.value = data.run;
@@ -499,6 +499,17 @@ function FlowFormView({ template, onBack }) {
499
499
  }
500
500
  return defaults;
501
501
  });
502
+ const [workspaceRepos, setWorkspaceRepos] = useState([]);
503
+ const [targetRepo, setTargetRepo] = useState("");
504
+
505
+ useEffect(() => {
506
+ apiFetch("/api/workspaces/active/repos").then((data) => {
507
+ const repos = Array.isArray(data?.repos) ? data.repos : [];
508
+ setWorkspaceRepos(repos);
509
+ const primary = repos.find((repo) => repo.primary);
510
+ setTargetRepo(primary?.name || repos[0]?.name || "");
511
+ }).catch(() => {});
512
+ }, []);
502
513
 
503
514
  const handleFieldChange = useCallback((fieldId, value) => {
504
515
  setFormValues((prev) => ({ ...prev, [fieldId]: value }));
@@ -506,11 +517,13 @@ function FlowFormView({ template, onBack }) {
506
517
 
507
518
  const handleExecute = useCallback(async () => {
508
519
  haptic();
509
- const run = await executeFlow(template.id, formValues);
520
+ const run = await executeFlow(template.id, formValues, {
521
+ repository: targetRepo || undefined,
522
+ });
510
523
  if (run) {
511
524
  activeRun.value = run;
512
525
  }
513
- }, [template.id, formValues]);
526
+ }, [template.id, formValues, targetRepo]);
514
527
 
515
528
  const catMeta = getCategoryMeta(template.category);
516
529
 
@@ -546,6 +559,42 @@ function FlowFormView({ template, onBack }) {
546
559
  Configuration
547
560
  </${Typography}>
548
561
 
562
+ <${Alert} severity="info" sx=${{ mb: 2 }}>
563
+ Manual flow templates are form-driven task/instruction builders.
564
+ Use the Workflow Launcher tab for the full node graph runtime with branches, loops, and run tracing.
565
+ </${Alert}>
566
+
567
+ ${workspaceRepos.length > 1 && html`
568
+ <${FormControl} fullWidth size="small" sx=${{ mb: 2 }}>
569
+ <${InputLabel}>Target Repository</${InputLabel}>
570
+ <${Select}
571
+ value=${targetRepo || ""}
572
+ label="Target Repository"
573
+ onChange=${(e) => setTargetRepo(e.target.value)}
574
+ >
575
+ ${workspaceRepos.map((repo) => html`
576
+ <${MenuItem} key=${repo.name} value=${repo.name}>
577
+ <${Stack} direction="row" spacing=${1} alignItems="center">
578
+ <span>${repo.name}</span>
579
+ ${repo.primary && html`<${Chip} label="primary" size="small" sx=${{ height: 18, fontSize: "10px" }} />`}
580
+ </${Stack}>
581
+ </${MenuItem}>
582
+ `)}
583
+ </${Select}>
584
+ <${Typography} variant="caption" color="text.secondary" sx=${{ mt: 0.5, ml: 1.5 }}>
585
+ This target is stored with the run and passed through to any task the template creates.
586
+ </${Typography}>
587
+ </${FormControl}>
588
+ `}
589
+ ${workspaceRepos.length === 1 && html`
590
+ <${Chip}
591
+ label=${`Repo: ${workspaceRepos[0]?.name || "default"}`}
592
+ size="small"
593
+ variant="outlined"
594
+ sx=${{ mb: 2, fontSize: "11px" }}
595
+ />
596
+ `}
597
+
549
598
  ${(template.fields || []).map(
550
599
  (field) => html`
551
600
  <${FormField}
@@ -595,23 +644,22 @@ function FlowFormView({ template, onBack }) {
595
644
  function RunResultCard({ run }) {
596
645
  if (!run) return null;
597
646
 
598
- const statusColors = {
599
- pending: "#f59e0b",
600
- running: "#3b82f6",
601
- completed: "#10b981",
602
- failed: "#ef4444",
603
- };
604
- const statusColor = statusColors[run.status] || "#6b7280";
647
+ const statusStyles = getRunStatusBadgeStyles(run.status);
648
+ const repository = String(run?.metadata?.repository || run?.metadata?.targetRepo || "").trim();
649
+ const workspaceId = String(run?.metadata?.workspaceId || "").trim();
650
+ const mode = String(run?.result?.mode || run?.result?.action || "").trim();
651
+ const taskId = String(run?.result?.taskId || "").trim();
652
+ const instructions = String(run?.result?.instructions || "").trim();
605
653
 
606
654
  return html`
607
- <${Paper} variant="outlined" sx=${{ p: 2.5, borderColor: statusColor + "40" }}>
655
+ <${Paper} variant="outlined" sx=${{ p: 2.5, borderColor: statusStyles.color + "40" }}>
608
656
  <${Stack} direction="row" alignItems="center" spacing=${1} sx=${{ mb: 1.5 }}>
609
657
  <${Chip}
610
658
  label=${run.status}
611
659
  size="small"
612
660
  sx=${{
613
- background: statusColor + "20",
614
- color: statusColor,
661
+ background: statusStyles.bg,
662
+ color: statusStyles.color,
615
663
  fontWeight: 600,
616
664
  fontSize: "11px",
617
665
  textTransform: "uppercase",
@@ -634,9 +682,14 @@ function RunResultCard({ run }) {
634
682
 
635
683
  ${run.result && html`
636
684
  <div>
637
- ${run.result.mode && html`
685
+ ${mode && html`
638
686
  <${Typography} variant="body2" sx=${{ mb: 1 }}>
639
- <strong>Mode:</strong> ${run.result.mode}
687
+ <strong>Mode:</strong> ${mode}
688
+ </${Typography}>
689
+ `}
690
+ ${(repository || workspaceId) && html`
691
+ <${Typography} variant="body2" sx=${{ mb: 0.5 }}>
692
+ <strong>Target:</strong> ${repository || "default repo"}${workspaceId ? ` · workspace ${workspaceId}` : ""}
640
693
  </${Typography}>
641
694
  `}
642
695
  ${run.result.filesScanned != null && html`
@@ -654,14 +707,14 @@ function RunResultCard({ run }) {
654
707
  <strong>Files needing warnings:</strong> ${run.result.filesNeedingWarn}
655
708
  </${Typography}>
656
709
  `}
657
- ${run.result.taskId && html`
710
+ ${taskId && html`
658
711
  <${Alert} severity="info" sx=${{ mt: 1 }}>
659
- Task dispatched: ${run.result.taskId}
712
+ Task dispatched: ${taskId}
660
713
  </${Alert}>
661
714
  `}
662
- ${run.result.instructions && html`
715
+ ${instructions && html`
663
716
  <${Alert} severity="info" sx=${{ mt: 1 }}>
664
- ${run.result.instructions}
717
+ ${instructions}
665
718
  </${Alert}>
666
719
  `}
667
720
  ${run.result.inventoryPath && html`
@@ -1035,10 +1088,15 @@ function TemplateListView() {
1035
1088
  return html`
1036
1089
  <div>
1037
1090
  <${Stack} direction="row" justifyContent="space-between" alignItems="center" sx=${{ mb: 2 }}>
1038
- <${Typography} variant="body2" color="text.secondary" sx=${{ maxWidth: "600px" }}>
1039
- One-shot transformations for your codebase. Pick a template, fill the form, and trigger.
1040
- Each flow runs once annotate, generate skills, prepare configs, and more.
1041
- </${Typography}>
1091
+ <div style="max-width: 760px;">
1092
+ <${Typography} variant="body2" color="text.secondary">
1093
+ One-shot form-based helpers for your codebase. These are not graph workflows:
1094
+ each template either dispatches a Kanban task with templated fields or returns operator instructions.
1095
+ </${Typography}>
1096
+ <${Typography} variant="caption" color="text.secondary" sx=${{ display: "block", mt: 0.75 }}>
1097
+ Use this when you want a reusable intake form. Use Workflow Launcher for the full node canvas runtime with branches, joins, retries, and live run history.
1098
+ </${Typography}>
1099
+ </div>
1042
1100
  <${Stack} direction="row" spacing=${1}>
1043
1101
  <${Button}
1044
1102
  variant="contained"
@@ -1113,6 +1171,11 @@ function TemplateListView() {
1113
1171
  </${DialogTitle}>
1114
1172
  <${DialogContent} dividers>
1115
1173
  ${editorError && html`<${Alert} severity="error" sx=${{ mb: 2 }}>${editorError}</${Alert}>`}
1174
+ <${Alert} severity="info" sx=${{ mb: 2 }}>
1175
+ Manual templates define a form plus a single action.
1176
+ "Dispatch Task" creates a Kanban task using the title, description, and labels below.
1177
+ "Instructions-only" stores operator guidance but does not launch a node workflow.
1178
+ </${Alert}>
1116
1179
 
1117
1180
  <${Stack} spacing=${1.5}>
1118
1181
  <${TextField}
@@ -2409,6 +2472,12 @@ function WfLaunchForm({ template, onBack }) {
2409
2472
  <${Typography} variant="body2"><strong>Workflow ID:</strong> <code>${wfLaunchResult.value.workflowId}</code></${Typography}>
2410
2473
  <${Typography} variant="body2"><strong>Run ID:</strong> <code>${wfLaunchResult.value.runId || "resolving..."}</code></${Typography}>
2411
2474
  <${Typography} variant="body2"><strong>Mode:</strong> ${wfLaunchResult.value.mode}</${Typography}>
2475
+ ${(targetRepo || wfLaunchResult.value?.targetRepo || wfLaunchResult.value?.repository) && html`
2476
+ <${Typography} variant="body2"><strong>Target Repo:</strong> ${targetRepo || wfLaunchResult.value?.targetRepo || wfLaunchResult.value?.repository}</${Typography}>
2477
+ `}
2478
+ ${wfLaunchResult.value?.workspaceId && html`
2479
+ <${Typography} variant="body2"><strong>Workspace:</strong> ${wfLaunchResult.value.workspaceId}</${Typography}>
2480
+ `}
2412
2481
  ${wfLaunchResult.value.dispatchedAt && html`
2413
2482
  <${Typography} variant="caption" color="text.secondary">
2414
2483
  Dispatched at ${new Date(wfLaunchResult.value.dispatchedAt).toLocaleString()}
@@ -2432,12 +2501,13 @@ function WfLaunchForm({ template, onBack }) {
2432
2501
  </${Typography}>
2433
2502
  <${Box} sx=${{
2434
2503
  p: 1.5, borderRadius: 1,
2435
- background: "rgba(0,0,0,0.2)",
2504
+ background: "var(--bg-secondary, rgba(0,0,0,0.2))",
2505
+ border: "1px solid var(--border, rgba(255,255,255,0.08))",
2436
2506
  fontFamily: "monospace", fontSize: "0.8em",
2437
2507
  maxHeight: 200, overflow: "auto",
2438
2508
  }}>
2439
2509
  ${Object.entries(wfLaunchResult.value.variables).map(([k, v]) => html`
2440
- <div key=${k}><span style="color: #10b981">${k}</span>: ${JSON.stringify(v)}</div>
2510
+ <div key=${k}><span style="color: var(--accent-success, #10b981)">${k}</span>: ${JSON.stringify(v)}</div>
2441
2511
  `)}
2442
2512
  </${Box}>
2443
2513
  `}
@@ -2839,6 +2909,9 @@ function ManualWorkflowRunHistoryView({ onBack }) {
2839
2909
  <${Stack} spacing=${0.4} sx=${{ fontSize: "0.86rem" }}>
2840
2910
  <${Typography} variant="body2"><strong>Workflow ID:</strong> <code>${selectedRun.workflowId || "—"}</code></${Typography}>
2841
2911
  <${Typography} variant="body2"><strong>Run ID:</strong> <code>${selectedRun.runId || "—"}</code></${Typography}>
2912
+ <${Typography} variant="body2"><strong>Target Repo:</strong> ${selectedRun.targetRepo || "—"}</${Typography}>
2913
+ <${Typography} variant="body2"><strong>Workspace:</strong> ${selectedRun.detail?.data?.workspaceId || selectedRun.detail?.data?.workspace || "—"}</${Typography}>
2914
+ <${Typography} variant="body2"><strong>Trigger:</strong> ${selectedRun.triggerSource || "manual"}${selectedRun.triggerEvent ? ` · ${selectedRun.triggerEvent}` : ""}</${Typography}>
2842
2915
  <${Typography} variant="body2"><strong>Started:</strong> ${formatDate(selectedRun.startedAt)} (${formatRelative(selectedRun.startedAt)})</${Typography}>
2843
2916
  <${Typography} variant="body2"><strong>Finished:</strong> ${finishedAt ? formatDate(finishedAt) : "Running"}</${Typography}>
2844
2917
  <${Typography} variant="body2"><strong>Duration:</strong> ${formatDuration(liveDuration)}</${Typography}>
@@ -2868,17 +2941,17 @@ function ManualWorkflowRunHistoryView({ onBack }) {
2868
2941
 
2869
2942
  <${Paper} variant="outlined" sx=${{ p: 2, mt: 1.5 }}>
2870
2943
  <${Typography} variant="subtitle2" sx=${{ mb: 1 }}>Run Logs (${logs.length})</${Typography}>
2871
- <pre style="white-space:pre-wrap;word-break:break-word;font-size:11px;color:#c9d1d9;background:#111827;border-radius:6px;padding:8px;max-height:320px;overflow:auto;">${safePrettyJson(logs)}</pre>
2944
+ <pre style="white-space:pre-wrap;word-break:break-word;font-size:11px;color:var(--text-primary,#c9d1d9);background:var(--bg-secondary,#111827);border:1px solid var(--border,#2a3040);border-radius:6px;padding:8px;max-height:320px;overflow:auto;">${safePrettyJson(logs)}</pre>
2872
2945
  </${Paper}>
2873
2946
 
2874
2947
  <${Paper} variant="outlined" sx=${{ p: 2, mt: 1.5 }}>
2875
2948
  <${Typography} variant="subtitle2" sx=${{ mb: 1 }}>Errors (${errors.length})</${Typography}>
2876
- <pre style="white-space:pre-wrap;word-break:break-word;font-size:11px;color:#fca5a5;background:#111827;border-radius:6px;padding:8px;max-height:220px;overflow:auto;">${safePrettyJson(errors)}</pre>
2949
+ <pre style="white-space:pre-wrap;word-break:break-word;font-size:11px;color:var(--destructive,#fca5a5);background:var(--bg-secondary,#111827);border:1px solid var(--border,#2a3040);border-radius:6px;padding:8px;max-height:220px;overflow:auto;">${safePrettyJson(errors)}</pre>
2877
2950
  </${Paper}>
2878
2951
 
2879
2952
  <${Paper} variant="outlined" sx=${{ p: 2, mt: 1.5 }}>
2880
2953
  <${Typography} variant="subtitle2" sx=${{ mb: 1 }}>Node Outputs</${Typography}>
2881
- <pre style="white-space:pre-wrap;word-break:break-word;font-size:11px;color:#c9d1d9;background:#111827;border-radius:6px;padding:8px;max-height:280px;overflow:auto;">${safePrettyJson(nodeOutputs)}</pre>
2954
+ <pre style="white-space:pre-wrap;word-break:break-word;font-size:11px;color:var(--text-primary,#c9d1d9);background:var(--bg-secondary,#111827);border:1px solid var(--border,#2a3040);border-radius:6px;padding:8px;max-height:280px;overflow:auto;">${safePrettyJson(nodeOutputs)}</pre>
2882
2955
  </${Paper}>
2883
2956
  </div>
2884
2957
  `;
@@ -2979,6 +3052,9 @@ function ManualWorkflowRunHistoryView({ onBack }) {
2979
3052
  <${Typography} variant="caption" color="text.secondary" sx=${{ display: "block" }}>
2980
3053
  Workflow: ${run.workflowId || "—"}
2981
3054
  </${Typography}>
3055
+ <${Typography} variant="caption" color="text.secondary" sx=${{ display: "block" }}>
3056
+ Target: ${run.targetRepo || "default repo"}${run.detail?.data?.workspaceId ? ` · workspace ${run.detail.data.workspaceId}` : ""}
3057
+ </${Typography}>
2982
3058
  <${Typography} variant="caption" color="text.secondary" sx=${{ display: "block" }}>
2983
3059
  Run: ${run.runId || "—"}
2984
3060
  </${Typography}>