bosun 0.41.0 → 0.41.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 (64) hide show
  1. package/.env.example +8 -0
  2. package/README.md +20 -0
  3. package/agent/agent-event-bus.mjs +248 -6
  4. package/agent/agent-pool.mjs +125 -28
  5. package/agent/agent-work-analyzer.mjs +8 -16
  6. package/agent/retry-queue.mjs +164 -0
  7. package/bosun.config.example.json +25 -0
  8. package/bosun.schema.json +825 -183
  9. package/cli.mjs +59 -5
  10. package/config/config.mjs +130 -3
  11. package/infra/monitor.mjs +693 -67
  12. package/infra/runtime-accumulator.mjs +376 -84
  13. package/infra/session-tracker.mjs +82 -25
  14. package/lib/codebase-audit.mjs +133 -18
  15. package/package.json +23 -4
  16. package/server/setup-web-server.mjs +25 -0
  17. package/server/ui-server.mjs +248 -29
  18. package/setup.mjs +27 -24
  19. package/shell/codex-shell.mjs +34 -3
  20. package/shell/copilot-shell.mjs +50 -8
  21. package/task/msg-hub.mjs +193 -0
  22. package/task/pipeline.mjs +544 -0
  23. package/task/task-cli.mjs +38 -2
  24. package/task/task-executor-pipeline.mjs +143 -0
  25. package/task/task-executor.mjs +36 -27
  26. package/telegram/get-telegram-chat-id.mjs +57 -47
  27. package/ui/components/workspace-switcher.js +7 -7
  28. package/ui/demo-defaults.js +15694 -10573
  29. package/ui/modules/settings-schema.js +2 -0
  30. package/ui/modules/state.js +54 -57
  31. package/ui/modules/voice-client-sdk.js +375 -36
  32. package/ui/modules/voice-client.js +140 -31
  33. package/ui/setup.html +68 -2
  34. package/ui/styles/components.css +57 -0
  35. package/ui/styles.css +201 -1
  36. package/ui/tabs/dashboard.js +74 -0
  37. package/ui/tabs/logs.js +10 -0
  38. package/ui/tabs/settings.js +178 -99
  39. package/ui/tabs/tasks.js +31 -1
  40. package/ui/tabs/telemetry.js +34 -0
  41. package/ui/tabs/workflow-canvas-utils.mjs +8 -1
  42. package/ui/tabs/workflows.js +532 -275
  43. package/voice/voice-agents-sdk.mjs +1 -1
  44. package/voice/voice-relay.mjs +6 -6
  45. package/workflow/declarative-workflows.mjs +145 -0
  46. package/workflow/msg-hub.mjs +237 -0
  47. package/workflow/pipeline-workflows.mjs +287 -0
  48. package/workflow/pipeline.mjs +828 -315
  49. package/workflow/workflow-cli.mjs +128 -0
  50. package/workflow/workflow-engine.mjs +329 -17
  51. package/workflow/workflow-nodes/custom-loader.mjs +250 -0
  52. package/workflow/workflow-nodes.mjs +1955 -223
  53. package/workflow/workflow-templates.mjs +26 -8
  54. package/workflow-templates/agents.mjs +0 -1
  55. package/workflow-templates/bosun-native.mjs +212 -2
  56. package/workflow-templates/continuation-loop.mjs +339 -0
  57. package/workflow-templates/github.mjs +516 -40
  58. package/workflow-templates/planning.mjs +446 -17
  59. package/workflow-templates/reliability.mjs +65 -12
  60. package/workflow-templates/task-batch.mjs +24 -8
  61. package/workflow-templates/task-lifecycle.mjs +83 -6
  62. package/workspace/context-cache.mjs +66 -18
  63. package/workspace/workspace-manager.mjs +2 -1
  64. package/workflow-templates/issue-continuation.mjs +0 -243
@@ -45,6 +45,7 @@ import {
45
45
  PR_CONFLICT_RESOLVER_TEMPLATE,
46
46
  STALE_PR_REAPER_TEMPLATE,
47
47
  RELEASE_DRAFTER_TEMPLATE,
48
+ BOSUN_PR_PROGRESSOR_TEMPLATE,
48
49
  BOSUN_PR_WATCHDOG_TEMPLATE,
49
50
  GITHUB_KANBAN_SYNC_TEMPLATE,
50
51
  SDK_CONFLICT_RESOLVER_TEMPLATE,
@@ -139,6 +140,11 @@ import {
139
140
  FLOW_CONTROL_SUITE_TEMPLATE,
140
141
  } from "../workflow-templates/coverage.mjs";
141
142
 
143
+ // Continuation Loop (issue-state continuation polling)
144
+ import {
145
+ CONTINUATION_LOOP_TEMPLATE,
146
+ } from "../workflow-templates/continuation-loop.mjs";
147
+
142
148
  // MCP Integration (MCP tool → workflow data piping)
143
149
  import {
144
150
  MCP_TOOL_CHAIN_TEMPLATE,
@@ -151,6 +157,7 @@ import {
151
157
  import {
152
158
  BOSUN_TOOL_PIPELINE_TEMPLATE,
153
159
  WORKFLOW_COMPOSITION_TEMPLATE,
160
+ INLINE_WORKFLOW_COMPOSITION_TEMPLATE,
154
161
  MCP_TO_BOSUN_BRIDGE_TEMPLATE,
155
162
  GIT_HEALTH_PIPELINE_TEMPLATE,
156
163
  } from "../workflow-templates/bosun-native.mjs";
@@ -163,6 +170,7 @@ export {
163
170
  PR_CONFLICT_RESOLVER_TEMPLATE,
164
171
  STALE_PR_REAPER_TEMPLATE,
165
172
  RELEASE_DRAFTER_TEMPLATE,
173
+ BOSUN_PR_PROGRESSOR_TEMPLATE,
166
174
  BOSUN_PR_WATCHDOG_TEMPLATE,
167
175
  GITHUB_KANBAN_SYNC_TEMPLATE,
168
176
  SDK_CONFLICT_RESOLVER_TEMPLATE,
@@ -211,12 +219,14 @@ export {
211
219
  MCP_RESEARCH_PROBE_TEMPLATE,
212
220
  AGENT_EXECUTION_PIPELINE_TEMPLATE,
213
221
  FLOW_CONTROL_SUITE_TEMPLATE,
222
+ CONTINUATION_LOOP_TEMPLATE,
214
223
  MCP_TOOL_CHAIN_TEMPLATE,
215
224
  MCP_GITHUB_PR_MONITOR_TEMPLATE,
216
225
  MCP_CROSS_SERVER_PIPELINE_TEMPLATE,
217
226
  MCP_ITERATIVE_RESEARCH_TEMPLATE,
218
227
  BOSUN_TOOL_PIPELINE_TEMPLATE,
219
228
  WORKFLOW_COMPOSITION_TEMPLATE,
229
+ INLINE_WORKFLOW_COMPOSITION_TEMPLATE,
220
230
  MCP_TO_BOSUN_BRIDGE_TEMPLATE,
221
231
  GIT_HEALTH_PIPELINE_TEMPLATE,
222
232
  };
@@ -249,6 +259,7 @@ export const WORKFLOW_TEMPLATES = Object.freeze([
249
259
  PR_CONFLICT_RESOLVER_TEMPLATE,
250
260
  STALE_PR_REAPER_TEMPLATE,
251
261
  RELEASE_DRAFTER_TEMPLATE,
262
+ BOSUN_PR_PROGRESSOR_TEMPLATE,
252
263
  BOSUN_PR_WATCHDOG_TEMPLATE,
253
264
  GITHUB_KANBAN_SYNC_TEMPLATE,
254
265
  SDK_CONFLICT_RESOLVER_TEMPLATE,
@@ -308,6 +319,8 @@ export const WORKFLOW_TEMPLATES = Object.freeze([
308
319
  MCP_RESEARCH_PROBE_TEMPLATE,
309
320
  AGENT_EXECUTION_PIPELINE_TEMPLATE,
310
321
  FLOW_CONTROL_SUITE_TEMPLATE,
322
+ // ── Continuation Loop ──
323
+ CONTINUATION_LOOP_TEMPLATE,
311
324
  // ── MCP Integration (MCP tool → workflow data piping) ──
312
325
  MCP_TOOL_CHAIN_TEMPLATE,
313
326
  MCP_GITHUB_PR_MONITOR_TEMPLATE,
@@ -316,6 +329,7 @@ export const WORKFLOW_TEMPLATES = Object.freeze([
316
329
  // ── Bosun Native (tools, sub-workflows, functions) ──
317
330
  BOSUN_TOOL_PIPELINE_TEMPLATE,
318
331
  WORKFLOW_COMPOSITION_TEMPLATE,
332
+ INLINE_WORKFLOW_COMPOSITION_TEMPLATE,
319
333
  MCP_TO_BOSUN_BRIDGE_TEMPLATE,
320
334
  GIT_HEALTH_PIPELINE_TEMPLATE,
321
335
  ]);
@@ -499,7 +513,8 @@ export function reconcileInstalledTemplates(engine, opts = {}) {
499
513
  result.scanned += 1;
500
514
 
501
515
  try {
502
- const before = stableStringify(def.metadata?.templateState || null);
516
+ const previousState = def.metadata?.templateState || null;
517
+ const before = stableStringify(previousState);
503
518
  applyWorkflowTemplateState(def);
504
519
  const state = def.metadata?.templateState || null;
505
520
  const after = stableStringify(state);
@@ -526,9 +541,8 @@ export function reconcileInstalledTemplates(engine, opts = {}) {
526
541
  });
527
542
  }
528
543
 
529
- const shouldForceUpdate =
530
- state.updateAvailable === true &&
531
- forceUpdateTemplateIds.has(String(state.templateId || "").trim());
544
+ const templateId = String(state.templateId || "").trim();
545
+ const shouldForceUpdate = templateId && forceUpdateTemplateIds.has(templateId);
532
546
  if (shouldForceUpdate) {
533
547
  const saved = updateWorkflowFromTemplate(engine, def.id, { mode: "replace", force: true });
534
548
  result.autoUpdated += 1;
@@ -537,7 +551,8 @@ export function reconcileInstalledTemplates(engine, opts = {}) {
537
551
  continue;
538
552
  }
539
553
 
540
- if (autoUpdateUnmodified && state.updateAvailable === true && state.isCustomized !== true) {
554
+ const wasCustomized = previousState?.isCustomized === true;
555
+ if (autoUpdateUnmodified && state.updateAvailable === true && !wasCustomized) {
541
556
  const saved = updateWorkflowFromTemplate(engine, def.id, { mode: "replace", force: true });
542
557
  result.autoUpdated += 1;
543
558
  result.updatedWorkflowIds.push(saved.id);
@@ -1060,9 +1075,13 @@ export function getWorkflowSetupProfile(profileId = "balanced") {
1060
1075
  * @returns {string[]}
1061
1076
  */
1062
1077
  export function resolveWorkflowTemplateIds(opts = {}) {
1078
+ const fromWorkflowConfig = resolveWorkflowTemplateConfig(opts.workflows || []);
1063
1079
  const explicit = normalizeTemplateIdList(opts.templateIds || []);
1064
- if (explicit.length > 0) return explicit;
1065
- return resolveProfileTemplateIds(opts.profileId || "balanced");
1080
+ if (explicit.length > 0) {
1081
+ return normalizeTemplateIdList([...explicit, ...fromWorkflowConfig.templateIds]);
1082
+ }
1083
+ const fromProfile = resolveProfileTemplateIds(opts.profileId || "balanced");
1084
+ return normalizeTemplateIdList([...fromProfile, ...fromWorkflowConfig.templateIds]);
1066
1085
  }
1067
1086
 
1068
1087
  function coerceTemplateVariableValue(rawValue, defaultValue) {
@@ -1256,4 +1275,3 @@ export function installRecommendedTemplates(engine, overridesById = {}) {
1256
1275
  .map((template) => template.id);
1257
1276
  return installTemplateSet(engine, recommendedIds, overridesById);
1258
1277
  }
1259
-
@@ -1015,4 +1015,3 @@ export const MEETING_SUBWORKFLOW_CHAIN_TEMPLATE = {
1015
1015
  requiredTemplates: ["template-task-planner"],
1016
1016
  },
1017
1017
  };
1018
-
@@ -175,7 +175,217 @@ export const WORKFLOW_COMPOSITION_TEMPLATE = {
175
175
  },
176
176
  };
177
177
 
178
- // ── Template 3: MCP-to-Bosun Bridge ─────────────────────────────────────────
178
+ // ── Template 3: Inline Workflow Composition ────────────────────────────────
179
+ // Demonstrates: Parent workflow containing multiple embedded child workflows
180
+ // Pattern: Inline preflight → inline execution plan → inline summary
181
+
182
+ resetLayout();
183
+ export const INLINE_WORKFLOW_COMPOSITION_TEMPLATE = {
184
+ id: "template-inline-workflow-composition",
185
+ name: "Inline Workflow Composition",
186
+ category: "mcp-integration",
187
+ enabled: true,
188
+ trigger: "trigger.manual",
189
+ description:
190
+ "Compose a parent workflow from embedded child workflows using action.inline_workflow. " +
191
+ "Demonstrates bounded sequential stages that stay inside the parent workflow " +
192
+ "while preserving child run/context boundaries and structured output handoff.",
193
+ variables: {
194
+ inputPayload: "{\"steps\":[\"lint\",\"test\",\"build\"],\"strict\":true}",
195
+ defaultStageOwner: "bosun",
196
+ },
197
+ nodes: [
198
+ node("trigger", "trigger.manual", "Start"),
199
+
200
+ node("inline-prepare", "action.inline_workflow", "Inline Prepare", {
201
+ mode: "sync",
202
+ outputVariable: "inlinePrepareResult",
203
+ input: {
204
+ inputPayload: "{{inputPayload}}",
205
+ defaultStageOwner: "{{defaultStageOwner}}",
206
+ },
207
+ workflow: {
208
+ trigger: "trigger.workflow_call",
209
+ nodes: [
210
+ {
211
+ id: "trigger",
212
+ type: "trigger.workflow_call",
213
+ label: "Inline Trigger",
214
+ config: {
215
+ inputs: {
216
+ inputPayload: { type: "string", required: false },
217
+ defaultStageOwner: { type: "string", required: false },
218
+ },
219
+ },
220
+ },
221
+ {
222
+ id: "normalize-payload",
223
+ type: "action.set_variable",
224
+ label: "Normalize Payload",
225
+ config: {
226
+ key: "normalizedPayload",
227
+ value:
228
+ "(() => {" +
229
+ "const raw = $data?.inputPayload;" +
230
+ "if (raw && typeof raw === 'object') return raw;" +
231
+ "const text = String(raw || '').trim();" +
232
+ "if (!text) return { steps: [] };" +
233
+ "try { return JSON.parse(text); } catch { return { steps: [text] }; }" +
234
+ "})()",
235
+ isExpression: true,
236
+ },
237
+ },
238
+ {
239
+ id: "finish",
240
+ type: "flow.end",
241
+ label: "Finish Prepare",
242
+ config: {
243
+ status: "completed",
244
+ output: {
245
+ stageOwner: "{{defaultStageOwner}}",
246
+ normalizedPayload: "{{$data?.normalizedPayload || { steps: [] }}}",
247
+ stepCount:
248
+ "{{$data?.normalizedPayload && Array.isArray($data.normalizedPayload.steps) ? $data.normalizedPayload.steps.length : 0}}",
249
+ },
250
+ },
251
+ },
252
+ ],
253
+ edges: [
254
+ { id: "e1", source: "trigger", target: "normalize-payload" },
255
+ { id: "e2", source: "normalize-payload", target: "finish" },
256
+ ],
257
+ },
258
+ }),
259
+
260
+ node("inline-plan", "action.inline_workflow", "Inline Stage Plan", {
261
+ mode: "sync",
262
+ outputVariable: "inlinePlanResult",
263
+ input: {
264
+ stageOwner: "{{$ctx.getNodeOutput('inline-prepare')?.stageOwner || $data?.defaultStageOwner || 'bosun'}}",
265
+ normalizedPayload: "{{$ctx.getNodeOutput('inline-prepare')?.normalizedPayload || { steps: [] }}}",
266
+ },
267
+ workflow: {
268
+ trigger: "trigger.workflow_call",
269
+ nodes: [
270
+ {
271
+ id: "trigger",
272
+ type: "trigger.workflow_call",
273
+ label: "Inline Trigger",
274
+ config: {
275
+ inputs: {
276
+ stageOwner: { type: "string", required: false },
277
+ normalizedPayload: { type: "object", required: false },
278
+ },
279
+ },
280
+ },
281
+ {
282
+ id: "build-plan",
283
+ type: "action.set_variable",
284
+ label: "Build Stage Plan",
285
+ config: {
286
+ key: "stagePlan",
287
+ value:
288
+ "(() => {" +
289
+ "const steps = Array.isArray($data?.normalizedPayload?.steps) ? $data.normalizedPayload.steps : [];" +
290
+ "return steps.map((step, index) => ({ index: index + 1, step: String(step || ''), owner: String($data?.stageOwner || 'bosun') }));" +
291
+ "})()",
292
+ isExpression: true,
293
+ },
294
+ },
295
+ {
296
+ id: "finish",
297
+ type: "flow.end",
298
+ label: "Finish Plan",
299
+ config: {
300
+ status: "completed",
301
+ output: {
302
+ stagePlan: "{{$data?.stagePlan || []}}",
303
+ stageCount: "{{$data?.stagePlan?.length || 0}}",
304
+ },
305
+ },
306
+ },
307
+ ],
308
+ edges: [
309
+ { id: "e1", source: "trigger", target: "build-plan" },
310
+ { id: "e2", source: "build-plan", target: "finish" },
311
+ ],
312
+ },
313
+ }),
314
+
315
+ node("inline-summarize", "action.inline_workflow", "Inline Summary", {
316
+ mode: "sync",
317
+ outputVariable: "inlineSummaryResult",
318
+ input: {
319
+ stagePlan: "{{$ctx.getNodeOutput('inline-plan')?.stagePlan || []}}",
320
+ stepCount: "{{$ctx.getNodeOutput('inline-prepare')?.stepCount || 0}}",
321
+ },
322
+ workflow: {
323
+ trigger: "trigger.workflow_call",
324
+ nodes: [
325
+ {
326
+ id: "trigger",
327
+ type: "trigger.workflow_call",
328
+ label: "Inline Trigger",
329
+ config: {
330
+ inputs: {
331
+ stagePlan: { type: "array", required: false },
332
+ stepCount: { type: "number", required: false },
333
+ },
334
+ },
335
+ },
336
+ {
337
+ id: "summarize",
338
+ type: "action.set_variable",
339
+ label: "Summarize Plan",
340
+ config: {
341
+ key: "summary",
342
+ value:
343
+ "(() => {" +
344
+ "const plan = Array.isArray($data?.stagePlan) ? $data.stagePlan : [];" +
345
+ "const labels = plan.map((entry) => String(entry.index) + ':' + String(entry.step || '')).join(', ');" +
346
+ "return {" +
347
+ " summaryMessage: 'Prepared ' + String(Number($data?.stepCount || 0)) + ' inline stage(s)' + (labels ? ' -> ' + labels : '')," +
348
+ " plannedSteps: plan," +
349
+ "};" +
350
+ "})()",
351
+ isExpression: true,
352
+ },
353
+ },
354
+ {
355
+ id: "finish",
356
+ type: "flow.end",
357
+ label: "Finish Summary",
358
+ config: {
359
+ status: "completed",
360
+ output: "{{$data?.summary || { summaryMessage: 'Prepared 0 inline stage(s)', plannedSteps: [] }}}",
361
+ },
362
+ },
363
+ ],
364
+ edges: [
365
+ { id: "e1", source: "trigger", target: "summarize" },
366
+ { id: "e2", source: "summarize", target: "finish" },
367
+ ],
368
+ },
369
+ }),
370
+
371
+ node("log-summary", "notify.log", "Log Inline Summary", {
372
+ message: "{{inline-summarize.summaryMessage}}",
373
+ level: "info",
374
+ }),
375
+ ],
376
+ edges: [
377
+ edge("trigger", "inline-prepare"),
378
+ edge("inline-prepare", "inline-plan"),
379
+ edge("inline-plan", "inline-summarize"),
380
+ edge("inline-summarize", "log-summary"),
381
+ ],
382
+ metadata: {
383
+ author: "virtengine",
384
+ tags: ["workflow", "composition", "inline", "parent-workflow", "embedded"],
385
+ },
386
+ };
387
+
388
+ // ── Template 4: MCP-to-Bosun Bridge ─────────────────────────────────────────
179
389
  // Demonstrates: MCP Tool → Extract → Bosun Function → Sub-Workflow
180
390
  // Pattern: External MCP data → Bosun internal actions → Workflow dispatch
181
391
 
@@ -277,7 +487,7 @@ export const MCP_TO_BOSUN_BRIDGE_TEMPLATE = {
277
487
  },
278
488
  };
279
489
 
280
- // ── Template 4: Git Health → Tool Analysis → Sub-Workflow ───────────────────
490
+ // ── Template 5: Git Health → Tool Analysis → Sub-Workflow ───────────────────
281
491
  // Demonstrates: Bosun functions + tools + sub-workflow in one pipeline
282
492
 
283
493
  resetLayout();