bosun 0.41.2 → 0.41.4
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.
- package/.env.example +1 -1
- package/agent/agent-pool.mjs +9 -2
- package/agent/agent-prompt-catalog.mjs +971 -0
- package/agent/agent-prompts.mjs +2 -970
- package/agent/agent-supervisor.mjs +119 -6
- package/agent/autofix-git.mjs +33 -0
- package/agent/autofix-prompts.mjs +151 -0
- package/agent/autofix.mjs +11 -175
- package/agent/bosun-skills.mjs +3 -2
- package/bosun.config.example.json +17 -0
- package/bosun.schema.json +87 -188
- package/cli.mjs +34 -1
- package/config/config-doctor.mjs +5 -250
- package/config/config-file-names.mjs +5 -0
- package/config/config.mjs +89 -493
- package/config/executor-config.mjs +493 -0
- package/config/repo-root.mjs +1 -2
- package/config/workspace-health.mjs +242 -0
- package/git/git-safety.mjs +15 -0
- package/github/github-oauth-portal.mjs +46 -0
- package/infra/library-manager-utils.mjs +22 -0
- package/infra/library-manager-well-known-sources.mjs +578 -0
- package/infra/library-manager.mjs +512 -1030
- package/infra/monitor.mjs +35 -9
- package/infra/session-tracker.mjs +10 -7
- package/kanban/kanban-adapter.mjs +17 -1
- package/lib/codebase-audit-manifests.mjs +117 -0
- package/lib/codebase-audit.mjs +18 -115
- package/package.json +18 -3
- package/server/setup-web-server.mjs +58 -5
- package/server/ui-server.mjs +1394 -79
- package/shell/codex-config-file.mjs +178 -0
- package/shell/codex-config.mjs +538 -575
- package/task/task-cli.mjs +54 -3
- package/task/task-executor.mjs +143 -13
- package/task/task-store.mjs +409 -1
- package/telegram/telegram-bot.mjs +127 -0
- package/tools/apply-pr-suggestions.mjs +401 -0
- package/tools/syntax-check.mjs +28 -9
- package/ui/app.js +3 -14
- package/ui/components/kanban-board.js +227 -4
- package/ui/components/session-list.js +85 -5
- package/ui/demo-defaults.js +338 -84
- package/ui/demo.html +155 -0
- package/ui/modules/session-api.js +96 -0
- package/ui/modules/settings-schema.js +1 -2
- package/ui/modules/state.js +43 -3
- package/ui/setup.html +4 -5
- package/ui/styles/components.css +58 -4
- package/ui/tabs/agents.js +12 -15
- package/ui/tabs/control.js +1 -0
- package/ui/tabs/library.js +484 -22
- package/ui/tabs/manual-flows.js +105 -29
- package/ui/tabs/tasks.js +848 -141
- package/ui/tabs/telemetry.js +129 -11
- package/ui/tabs/workflow-canvas-utils.mjs +130 -0
- package/ui/tabs/workflows.js +293 -23
- package/voice/voice-tool-definitions.mjs +757 -0
- package/voice/voice-tools.mjs +34 -778
- package/workflow/manual-flow-audit.mjs +165 -0
- package/workflow/manual-flows.mjs +164 -259
- package/workflow/workflow-engine.mjs +147 -58
- package/workflow/workflow-nodes/definitions.mjs +1207 -0
- package/workflow/workflow-nodes/transforms.mjs +612 -0
- package/workflow/workflow-nodes.mjs +358 -63
- package/workflow/workflow-templates.mjs +313 -191
- package/workflow-templates/_helpers.mjs +154 -0
- package/workflow-templates/agents.mjs +61 -4
- package/workflow-templates/code-quality.mjs +7 -7
- package/workflow-templates/github.mjs +20 -10
- package/workflow-templates/task-batch.mjs +44 -11
- package/workflow-templates/task-lifecycle.mjs +31 -6
- package/workspace/worktree-manager.mjs +277 -3
package/ui/tabs/manual-flows.js
CHANGED
|
@@ -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
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
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:
|
|
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:
|
|
614
|
-
color:
|
|
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
|
-
${
|
|
685
|
+
${mode && html`
|
|
638
686
|
<${Typography} variant="body2" sx=${{ mb: 1 }}>
|
|
639
|
-
<strong>Mode:</strong> ${
|
|
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
|
-
${
|
|
710
|
+
${taskId && html`
|
|
658
711
|
<${Alert} severity="info" sx=${{ mt: 1 }}>
|
|
659
|
-
Task dispatched: ${
|
|
712
|
+
Task dispatched: ${taskId}
|
|
660
713
|
</${Alert}>
|
|
661
714
|
`}
|
|
662
|
-
${
|
|
715
|
+
${instructions && html`
|
|
663
716
|
<${Alert} severity="info" sx=${{ mt: 1 }}>
|
|
664
|
-
${
|
|
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
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
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
|
|
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
|
|
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
|
|
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}>
|