bosun 0.37.0 → 0.37.2

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 (43) hide show
  1. package/.env.example +4 -1
  2. package/agent-tool-config.mjs +338 -0
  3. package/bosun-skills.mjs +59 -4
  4. package/bosun.schema.json +1 -1
  5. package/desktop/launch.mjs +18 -0
  6. package/desktop/main.mjs +52 -13
  7. package/fleet-coordinator.mjs +34 -1
  8. package/kanban-adapter.mjs +30 -3
  9. package/library-manager.mjs +66 -0
  10. package/maintenance.mjs +30 -5
  11. package/monitor.mjs +56 -0
  12. package/package.json +4 -1
  13. package/setup-web-server.mjs +73 -12
  14. package/setup.mjs +3 -3
  15. package/ui/app.js +40 -3
  16. package/ui/components/session-list.js +25 -7
  17. package/ui/components/workspace-switcher.js +48 -1
  18. package/ui/demo.html +176 -0
  19. package/ui/modules/mic-track-registry.js +83 -0
  20. package/ui/modules/settings-schema.js +4 -1
  21. package/ui/modules/state.js +25 -0
  22. package/ui/modules/streaming.js +1 -1
  23. package/ui/modules/voice-barge-in.js +27 -0
  24. package/ui/modules/voice-client-sdk.js +268 -42
  25. package/ui/modules/voice-client.js +665 -61
  26. package/ui/modules/voice-overlay.js +829 -47
  27. package/ui/setup.html +151 -9
  28. package/ui/styles.css +258 -0
  29. package/ui/tabs/chat.js +11 -0
  30. package/ui/tabs/library.js +890 -15
  31. package/ui/tabs/settings.js +51 -11
  32. package/ui/tabs/telemetry.js +327 -105
  33. package/ui/tabs/workflows.js +86 -0
  34. package/ui-server.mjs +1201 -107
  35. package/voice-action-dispatcher.mjs +81 -0
  36. package/voice-agents-sdk.mjs +2 -2
  37. package/voice-relay.mjs +131 -14
  38. package/voice-tools.mjs +475 -9
  39. package/workflow-engine.mjs +54 -0
  40. package/workflow-nodes.mjs +177 -28
  41. package/workflow-templates/github.mjs +205 -94
  42. package/workflow-templates/task-batch.mjs +247 -0
  43. package/workflow-templates.mjs +15 -0
@@ -1102,6 +1102,72 @@ const EXPRESSION_PRESETS = [
1102
1102
  { label: "Branch Match", expr: "/^(feat|fix)\\//.test($data?.branch || '')" },
1103
1103
  ];
1104
1104
 
1105
+ /* ═══════════════════════════════════════════════════════════════
1106
+ * Workflow Agent Library Picker
1107
+ * — Lets users select an agent profile from the Library
1108
+ * ═══════════════════════════════════════════════════════════════ */
1109
+
1110
+ function WorkflowAgentLibraryPicker({ config, onUpdate }) {
1111
+ const [agents, setAgents] = useState([]);
1112
+ const [loading, setLoading] = useState(false);
1113
+ const [expanded, setExpanded] = useState(false);
1114
+
1115
+ const loadAgents = useCallback(async () => {
1116
+ if (agents.length > 0) { setExpanded(e => !e); return; }
1117
+ setLoading(true);
1118
+ try {
1119
+ const res = await apiFetch("/api/library?type=agent&agentType=task");
1120
+ const data = Array.isArray(res?.data) ? res.data : [];
1121
+ setAgents(data);
1122
+ } catch { /* ignore */ }
1123
+ setLoading(false);
1124
+ setExpanded(true);
1125
+ }, [agents.length]);
1126
+
1127
+ const selectAgent = useCallback((agent) => {
1128
+ onUpdate("agentProfileId", agent.id);
1129
+ if (agent.content?.prompt) onUpdate("prompt", agent.content?.prompt);
1130
+ if (agent.content?.model) onUpdate("model", agent.content.model);
1131
+ haptic?.("light");
1132
+ showToast(`Agent "${agent.name || agent.id}" applied`);
1133
+ }, [onUpdate]);
1134
+
1135
+ const selected = config?.agentProfileId;
1136
+
1137
+ return html`
1138
+ <div style="margin-top: 10px; margin-bottom: 6px;">
1139
+ <button
1140
+ onClick=${loadAgents}
1141
+ style="width: 100%; padding: 7px 10px; font-size: 11px; border: 1px solid #2a3040; border-radius: 6px; background: #1a1f2e; color: #c9d1d9; cursor: pointer; display: flex; align-items: center; gap: 8px;"
1142
+ >
1143
+ <span class="btn-icon" style="color: #60a5fa;">${resolveIcon("users")}</span>
1144
+ <span style="flex: 1; text-align: left; font-weight: 500;">Library Agent Profiles</span>
1145
+ ${selected && html`<span style="font-size: 10px; background: #1e3a5f; color: #60a5fa; padding: 1px 6px; border-radius: 4px;">${selected}</span>`}
1146
+ <span style="font-size: 10px; color: #6b7280;">${loading ? "…" : (expanded ? ICONS.chevronDown : ICONS.arrowRight)}</span>
1147
+ </button>
1148
+ ${expanded && html`
1149
+ <div style="margin-top: 6px; display: flex; flex-direction: column; gap: 4px; max-height: 220px; overflow-y: auto; padding-right: 4px;">
1150
+ ${agents.length === 0 && html`<div style="font-size: 11px; color: #6b7280; padding: 6px;">No agent profiles in library.</div>`}
1151
+ ${agents.map(a => html`
1152
+ <button
1153
+ key=${a.id}
1154
+ onClick=${() => selectAgent(a)}
1155
+ style="padding: 6px 10px; font-size: 11px; border: 1px solid ${selected === a.id ? '#2563eb' : '#2a3040'}; border-radius: 6px; background: ${selected === a.id ? '#1e3a5f' : '#161b22'}; color: #c9d1d9; cursor: pointer; text-align: left; transition: all 0.15s;"
1156
+ >
1157
+ <div style="font-weight: 500; display: flex; align-items: center; gap: 6px;">
1158
+ <span class="btn-icon" style="color: ${selected === a.id ? '#60a5fa' : '#6b7280'};">${resolveIcon("user")}</span>
1159
+ <span>${a.name || a.id}</span>
1160
+ ${selected === a.id && html`<span style="margin-left: auto; font-size: 9px; color: #60a5fa;">● active</span>`}
1161
+ </div>
1162
+ ${a.description && html`<div style="font-size: 10px; color: #6b7280; margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">${a.description}</div>`}
1163
+ </button>
1164
+ `)}
1165
+ </div>
1166
+ `}
1167
+ </div>
1168
+ `;
1169
+ }
1170
+
1105
1171
  /* ═══════════════════════════════════════════════════════════════
1106
1172
  * Node Config Editor (right side panel)
1107
1173
  * ═══════════════════════════════════════════════════════════════ */
@@ -1218,6 +1284,7 @@ function NodeConfigEditor({ node, nodeTypes: types, onUpdate, onUpdateLabel, onC
1218
1284
  </div>
1219
1285
  `}
1220
1286
  ${(node.type === "action.run_agent") && html`
1287
+ <${WorkflowAgentLibraryPicker} config=${config} onUpdate=${onFieldChange} />
1221
1288
  <div style="margin-top: 8px; padding: 6px 8px; background: #1a1f2e; border-radius: 6px; border-left: 3px solid #a78bfa;">
1222
1289
  <div style="font-size: 10px; color: #a78bfa; font-weight: 600; margin-bottom: 2px; display: flex; align-items: center; gap: 6px;">
1223
1290
  <span class="btn-icon">${resolveIcon("lightbulb")}</span>
@@ -2252,6 +2319,25 @@ export function WorkflowsTab() {
2252
2319
  loadNodeTypes();
2253
2320
  }, []);
2254
2321
 
2322
+ useEffect(() => {
2323
+ const onWorkspaceSwitched = () => {
2324
+ activeWorkflow.value = null;
2325
+ selectedRunId.value = null;
2326
+ selectedRunDetail.value = null;
2327
+ workflowRuns.value = [];
2328
+ workflowRunsLimit.value = WORKFLOW_RUN_PAGE_SIZE;
2329
+ viewMode.value = "list";
2330
+ setRouteParams({}, { replace: true, skipGuard: true });
2331
+ loadWorkflows();
2332
+ loadTemplates();
2333
+ loadNodeTypes();
2334
+ };
2335
+ window.addEventListener("ve:workspace-switched", onWorkspaceSwitched);
2336
+ return () => {
2337
+ window.removeEventListener("ve:workspace-switched", onWorkspaceSwitched);
2338
+ };
2339
+ }, []);
2340
+
2255
2341
  useEffect(() => {
2256
2342
  const route = routeParams.value || {};
2257
2343
  const workflowId = String(route.workflowId || "").trim();