bosun 0.36.0 → 0.36.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 (98) hide show
  1. package/.env.example +98 -16
  2. package/README.md +27 -0
  3. package/agent-event-bus.mjs +5 -5
  4. package/agent-pool.mjs +129 -12
  5. package/agent-prompts.mjs +7 -1
  6. package/agent-sdk.mjs +13 -2
  7. package/agent-supervisor.mjs +2 -2
  8. package/agent-work-report.mjs +1 -1
  9. package/anomaly-detector.mjs +6 -6
  10. package/autofix.mjs +15 -15
  11. package/bosun-skills.mjs +4 -4
  12. package/bosun.schema.json +160 -4
  13. package/claude-shell.mjs +11 -11
  14. package/cli.mjs +21 -21
  15. package/codex-config.mjs +19 -19
  16. package/codex-shell.mjs +180 -29
  17. package/config-doctor.mjs +27 -2
  18. package/config.mjs +60 -7
  19. package/copilot-shell.mjs +4 -4
  20. package/error-detector.mjs +1 -1
  21. package/fleet-coordinator.mjs +2 -2
  22. package/gemini-shell.mjs +692 -0
  23. package/github-oauth-portal.mjs +1 -1
  24. package/github-reconciler.mjs +2 -2
  25. package/kanban-adapter.mjs +741 -168
  26. package/merge-strategy.mjs +25 -25
  27. package/monitor.mjs +123 -105
  28. package/opencode-shell.mjs +22 -22
  29. package/package.json +7 -1
  30. package/postinstall.mjs +22 -22
  31. package/pr-cleanup-daemon.mjs +6 -6
  32. package/prepublish-check.mjs +4 -4
  33. package/presence.mjs +2 -2
  34. package/primary-agent.mjs +85 -7
  35. package/publish.mjs +1 -1
  36. package/review-agent.mjs +1 -1
  37. package/session-tracker.mjs +11 -0
  38. package/setup-web-server.mjs +429 -21
  39. package/setup.mjs +367 -12
  40. package/shared-knowledge.mjs +1 -1
  41. package/startup-service.mjs +9 -9
  42. package/stream-resilience.mjs +58 -4
  43. package/sync-engine.mjs +2 -2
  44. package/task-assessment.mjs +9 -9
  45. package/task-cli.mjs +1 -1
  46. package/task-complexity.mjs +71 -2
  47. package/task-context.mjs +1 -2
  48. package/task-executor.mjs +104 -41
  49. package/telegram-bot.mjs +825 -494
  50. package/telegram-sentinel.mjs +28 -28
  51. package/ui/app.js +256 -23
  52. package/ui/app.monolith.js +1 -1
  53. package/ui/components/agent-selector.js +4 -3
  54. package/ui/components/chat-view.js +101 -28
  55. package/ui/components/diff-viewer.js +3 -3
  56. package/ui/components/kanban-board.js +3 -3
  57. package/ui/components/session-list.js +255 -35
  58. package/ui/components/workspace-switcher.js +3 -3
  59. package/ui/demo.html +209 -194
  60. package/ui/index.html +3 -3
  61. package/ui/modules/icon-utils.js +206 -142
  62. package/ui/modules/icons.js +2 -27
  63. package/ui/modules/settings-schema.js +29 -5
  64. package/ui/modules/streaming.js +30 -2
  65. package/ui/modules/vision-stream.js +275 -0
  66. package/ui/modules/voice-client.js +102 -9
  67. package/ui/modules/voice-fallback.js +62 -6
  68. package/ui/modules/voice-overlay.js +594 -59
  69. package/ui/modules/voice.js +31 -38
  70. package/ui/setup.html +284 -34
  71. package/ui/styles/components.css +47 -0
  72. package/ui/styles/sessions.css +75 -0
  73. package/ui/tabs/agents.js +73 -43
  74. package/ui/tabs/chat.js +37 -40
  75. package/ui/tabs/control.js +2 -2
  76. package/ui/tabs/dashboard.js +1 -1
  77. package/ui/tabs/infra.js +10 -10
  78. package/ui/tabs/library.js +8 -8
  79. package/ui/tabs/logs.js +10 -10
  80. package/ui/tabs/settings.js +20 -20
  81. package/ui/tabs/tasks.js +76 -47
  82. package/ui-server.mjs +1761 -124
  83. package/update-check.mjs +13 -13
  84. package/ve-kanban.mjs +1 -1
  85. package/whatsapp-channel.mjs +5 -5
  86. package/workflow-engine.mjs +20 -1
  87. package/workflow-nodes.mjs +904 -4
  88. package/workflow-templates/agents.mjs +321 -7
  89. package/workflow-templates/ci-cd.mjs +6 -6
  90. package/workflow-templates/github.mjs +156 -84
  91. package/workflow-templates/planning.mjs +8 -8
  92. package/workflow-templates/reliability.mjs +8 -8
  93. package/workflow-templates/security.mjs +3 -3
  94. package/workflow-templates.mjs +15 -9
  95. package/workspace-manager.mjs +85 -1
  96. package/workspace-monitor.mjs +2 -2
  97. package/workspace-registry.mjs +2 -2
  98. package/worktree-manager.mjs +1 -1
@@ -7,6 +7,8 @@
7
7
  * - Custom Agent Profile
8
8
  * - Agent Session Monitor (recommended)
9
9
  * - Backend Agent (recommended)
10
+ * - Voice + Video Rollout (Parallel Lanes)
11
+ * - Meeting Orchestrator + Subworkflow Chain
10
12
  */
11
13
 
12
14
  import { node, edge, resetLayout } from "./_helpers.mjs";
@@ -145,11 +147,11 @@ After completing your implementation:
145
147
  }, { x: 200, y: 1080 }),
146
148
 
147
149
  node("notify-success", "notify.telegram", "Notify Success", {
148
- message: " Frontend task **{{taskTitle}}** passed visual verification and is complete.",
150
+ message: ":check: Frontend task **{{taskTitle}}** passed visual verification and is complete.",
149
151
  }, { x: 200, y: 1200 }),
150
152
 
151
153
  node("notify-failure", "notify.telegram", "Notify Review Failed", {
152
- message: " Frontend task **{{taskTitle}}** failed visual verification. Review evidence in .bosun/evidence/",
154
+ message: ":close: Frontend task **{{taskTitle}}** failed visual verification. Review evidence in .bosun/evidence/",
153
155
  }, { x: 600, y: 1080 }),
154
156
 
155
157
  node("log-failure", "notify.log", "Log Failure", {
@@ -240,7 +242,7 @@ Provide a structured review with specific file:line references.`,
240
242
  }, { x: 400, y: 500 }),
241
243
 
242
244
  node("notify", "notify.telegram", "Post Review", {
243
- message: "📝 PR review complete for {{branch}}",
245
+ message: ":edit: PR review complete for {{branch}}",
244
246
  }, { x: 400, y: 640 }),
245
247
  ],
246
248
  edges: [
@@ -386,7 +388,7 @@ export const AGENT_SESSION_MONITOR_TEMPLATE = {
386
388
  }, { x: 100, y: 800 }),
387
389
 
388
390
  node("alert-hung", "notify.telegram", "Alert Hung Sessions", {
389
- message: "🔴 Agent session appears hung — auto-continue attempted. Check status.",
391
+ message: ":dot: Agent session appears hung — auto-continue attempted. Check status.",
390
392
  }, { x: 100, y: 950 }),
391
393
 
392
394
  node("all-healthy", "notify.log", "Sessions Healthy", {
@@ -530,7 +532,7 @@ Commit with message "feat: implement [feature]"`,
530
532
  }, { x: 180, y: 1320 }),
531
533
 
532
534
  node("notify-pr-failed", "notify.telegram", "Escalate Lifecycle Handoff Failure", {
533
- message: "⚠️ Backend agent passed validation for {{taskTitle}} but failed to record Bosun PR lifecycle handoff after retries. Manual follow-up required.",
535
+ message: ":alert: Backend agent passed validation for {{taskTitle}} but failed to record Bosun PR lifecycle handoff after retries. Manual follow-up required.",
534
536
  }, { x: 420, y: 1320 }),
535
537
 
536
538
  node("set-validation-summary", "action.set_variable", "Summarize Validation Output", {
@@ -599,11 +601,11 @@ Commit with message "fix: address backend workflow validation failures"`,
599
601
  }, { x: 360, y: 1980 }),
600
602
 
601
603
  node("notify-fail", "notify.telegram", "Checks Failed", {
602
- message: "⚠️ Backend agent: validation failed for task {{taskTitle}} even after remediation pass. Manual review needed.",
604
+ message: ":alert: Backend agent: validation failed for task {{taskTitle}} even after remediation pass. Manual review needed.",
603
605
  }, { x: 820, y: 1820 }),
604
606
 
605
607
  node("notify-pr-failed-retry", "notify.telegram", "Escalate Lifecycle Failure (Retry Path)", {
606
- message: "⚠️ Backend agent remediation passed for {{taskTitle}} but Bosun PR lifecycle handoff failed after retries. Manual follow-up required.",
608
+ message: ":alert: Backend agent remediation passed for {{taskTitle}} but Bosun PR lifecycle handoff failed after retries. Manual follow-up required.",
607
609
  }, { x: 620, y: 1980 }),
608
610
  ],
609
611
  edges: [
@@ -647,3 +649,315 @@ Commit with message "fix: address backend workflow validation failures"`,
647
649
  },
648
650
  },
649
651
  };
652
+
653
+ // ═══════════════════════════════════════════════════════════════════════════
654
+ // Voice + Video Rollout (Parallel Lanes)
655
+ // ═══════════════════════════════════════════════════════════════════════════
656
+
657
+ resetLayout();
658
+
659
+ export const VOICE_VIDEO_PARALLEL_ROLLOUT_TEMPLATE = {
660
+ id: "template-voice-video-parallel-rollout",
661
+ name: "Voice + Video Rollout (Parallel Lanes)",
662
+ description:
663
+ "Launches three agent lanes in parallel (capture pipeline, provider adapters, " +
664
+ "and QA/rollout hardening) to accelerate Voice + Video delivery while keeping " +
665
+ "workstreams isolated by worktree.",
666
+ category: "agents",
667
+ enabled: false,
668
+ trigger: "trigger.manual",
669
+ variables: {
670
+ lane1Worktree: "{{worktreePath}}",
671
+ lane2Worktree: "{{worktreePath}}",
672
+ lane3Worktree: "{{worktreePath}}",
673
+ integrationBranch: "feat/voice-video-integration",
674
+ definitionOfDone:
675
+ "Voice + vision works end-to-end, provider fallback is explicit, and tests cover config + transport + failure paths.",
676
+ },
677
+ nodes: [
678
+ node("trigger", "trigger.manual", "Launch Parallel Rollout", {}, { x: 500, y: 50 }),
679
+
680
+ node("check-worktrees", "condition.expression", "Worktrees Distinct?", {
681
+ expression:
682
+ "(() => { " +
683
+ "const a = String($data?.lane1Worktree || '').trim(); " +
684
+ "const b = String($data?.lane2Worktree || '').trim(); " +
685
+ "const c = String($data?.lane3Worktree || '').trim(); " +
686
+ "if (!a || !b || !c) return false; " +
687
+ "return new Set([a, b, c]).size === 3; " +
688
+ "})()",
689
+ }, { x: 500, y: 170 }),
690
+
691
+ node("notify-worktree-error", "notify.telegram", "Invalid Worktree Setup", {
692
+ message:
693
+ "Parallel rollout aborted. Configure three distinct worktrees in " +
694
+ "`lane1Worktree`, `lane2Worktree`, and `lane3Worktree` before launching.",
695
+ }, { x: 860, y: 170 }),
696
+
697
+ node("kickoff-log", "notify.log", "Kickoff Parallel Lanes", {
698
+ message:
699
+ "Starting parallel rollout on branch {{integrationBranch}} with 3 lanes.",
700
+ level: "info",
701
+ }, { x: 500, y: 290 }),
702
+
703
+ node("lane-capture-core", "action.run_agent", "Lane 1: Capture Core", {
704
+ prompt:
705
+ "# Lane 1 - Capture Core\n\n" +
706
+ "Work only in this lane's worktree. Focus on:\n" +
707
+ "1. Voice video config/schema/env/settings keys\n" +
708
+ "2. Browser capture loop (screen/camera), adaptive FPS, compression, change detection\n" +
709
+ "3. Overlay controls + capture state indicators\n\n" +
710
+ "Guardrails:\n" +
711
+ "- Do not touch provider dispatch code owned by Lane 2\n" +
712
+ "- Keep changes bounded to UI/config paths\n" +
713
+ "- Add/extend tests for capture throttling and config behavior\n\n" +
714
+ "Target branch: {{integrationBranch}}\n" +
715
+ "Definition of done: {{definitionOfDone}}",
716
+ sdk: "auto",
717
+ cwd: "{{lane1Worktree}}",
718
+ timeoutMs: 5400000,
719
+ includeTaskContext: false,
720
+ failOnError: true,
721
+ }, { x: 120, y: 450 }),
722
+
723
+ node("lane-provider-bridge", "action.run_agent", "Lane 2: Provider Bridge", {
724
+ prompt:
725
+ "# Lane 2 - Provider Bridge\n\n" +
726
+ "Work only in this lane's worktree. Focus on:\n" +
727
+ "1. Server-side vision frame ingress route and validation\n" +
728
+ "2. Provider dispatch in voice relay (OpenAI image path, Gemini live path, Claude vision path)\n" +
729
+ "3. Rate-limits, payload caps, and fallback semantics\n\n" +
730
+ "Guardrails:\n" +
731
+ "- Do not edit overlay/capture UI owned by Lane 1\n" +
732
+ "- Keep provider logic behind explicit feature flags\n" +
733
+ "- Add/extend tests for endpoint validation and provider routing\n\n" +
734
+ "Target branch: {{integrationBranch}}\n" +
735
+ "Definition of done: {{definitionOfDone}}",
736
+ sdk: "auto",
737
+ cwd: "{{lane2Worktree}}",
738
+ timeoutMs: 5400000,
739
+ includeTaskContext: false,
740
+ failOnError: true,
741
+ }, { x: 500, y: 450 }),
742
+
743
+ node("lane-hardening", "action.run_agent", "Lane 3: QA + Rollout", {
744
+ prompt:
745
+ "# Lane 3 - QA + Rollout Hardening\n\n" +
746
+ "Work only in this lane's worktree. Focus on:\n" +
747
+ "1. Integration tests, resilience tests, and docs updates\n" +
748
+ "2. Migration/rollout notes and operator controls\n" +
749
+ "3. Conflict-free merge guidance across Lane 1 and Lane 2 outputs\n\n" +
750
+ "Guardrails:\n" +
751
+ "- Avoid touching core capture loop and provider dispatch internals unless a test proves breakage\n" +
752
+ "- Keep this lane focused on verification, docs, and release safety\n" +
753
+ "- Produce a concise verification summary\n\n" +
754
+ "Target branch: {{integrationBranch}}\n" +
755
+ "Definition of done: {{definitionOfDone}}",
756
+ sdk: "auto",
757
+ cwd: "{{lane3Worktree}}",
758
+ timeoutMs: 3600000,
759
+ includeTaskContext: false,
760
+ failOnError: true,
761
+ }, { x: 880, y: 450 }),
762
+
763
+ node("aggregate", "transform.aggregate", "Aggregate Lane Results", {
764
+ sources: ["lane-capture-core", "lane-provider-bridge", "lane-hardening"],
765
+ }, { x: 500, y: 640 }),
766
+
767
+ node("all-passed", "condition.expression", "All Lanes Passed?", {
768
+ expression:
769
+ "$ctx.getNodeOutput('lane-capture-core')?.success === true && " +
770
+ "$ctx.getNodeOutput('lane-provider-bridge')?.success === true && " +
771
+ "$ctx.getNodeOutput('lane-hardening')?.success === true",
772
+ }, { x: 500, y: 770 }),
773
+
774
+ node("notify-success", "notify.telegram", "Notify Success", {
775
+ message:
776
+ "Parallel Voice + Video rollout lanes completed successfully on {{integrationBranch}}. " +
777
+ "Proceed to integration and final verification.",
778
+ }, { x: 300, y: 910 }),
779
+
780
+ node("notify-failure", "notify.telegram", "Notify Failure", {
781
+ message:
782
+ "Parallel Voice + Video rollout has lane failures on {{integrationBranch}}. " +
783
+ "Inspect lane outputs before integration.",
784
+ }, { x: 700, y: 910 }),
785
+ ],
786
+ edges: [
787
+ edge("trigger", "check-worktrees"),
788
+ edge("check-worktrees", "kickoff-log", { condition: "$output?.result === true" }),
789
+ edge("check-worktrees", "notify-worktree-error", { condition: "$output?.result !== true" }),
790
+ edge("kickoff-log", "lane-capture-core"),
791
+ edge("kickoff-log", "lane-provider-bridge"),
792
+ edge("kickoff-log", "lane-hardening"),
793
+ edge("lane-capture-core", "aggregate"),
794
+ edge("lane-provider-bridge", "aggregate"),
795
+ edge("lane-hardening", "aggregate"),
796
+ edge("aggregate", "all-passed"),
797
+ edge("all-passed", "notify-success", { condition: "$output?.result === true" }),
798
+ edge("all-passed", "notify-failure", { condition: "$output?.result !== true" }),
799
+ ],
800
+ metadata: {
801
+ author: "bosun",
802
+ version: 1,
803
+ createdAt: "2026-02-28T00:00:00Z",
804
+ templateVersion: "1.0.0",
805
+ tags: ["voice", "video", "parallel", "subagents", "rollout"],
806
+ },
807
+ };
808
+
809
+ // ═══════════════════════════════════════════════════════════════════════════
810
+ // Meeting Orchestrator + Subworkflow Chain
811
+ // ═══════════════════════════════════════════════════════════════════════════
812
+
813
+ resetLayout();
814
+
815
+ export const MEETING_SUBWORKFLOW_CHAIN_TEMPLATE = {
816
+ id: "template-meeting-subworkflow-chain",
817
+ name: "Meeting Orchestrator + Subworkflow Chain",
818
+ description:
819
+ "Runs a meeting session start/send/vision/transcript/finalize flow, applies " +
820
+ "a wake-phrase trigger + transcript quality guard, then invokes a child " +
821
+ "workflow via action.execute_workflow for post-meeting automation.",
822
+ category: "agents",
823
+ enabled: false,
824
+ trigger: "trigger.manual",
825
+ variables: {
826
+ sessionTitle: "Sprint Planning Sync",
827
+ meetingExecutor: "codex",
828
+ wakePhrase: "bosun wake",
829
+ openingMessage:
830
+ "Kick off planning review. Capture decisions, blockers, and next actions.",
831
+ frameDataUrl: "",
832
+ visionSource: "screen",
833
+ visionPrompt:
834
+ "Summarize visible meeting context, shared docs, and any blockers shown.",
835
+ visionModel: "",
836
+ visionMinIntervalMs: 1500,
837
+ forceVisionAnalyze: false,
838
+ minTranscriptChars: 140,
839
+ childWorkflowId: "template-task-planner",
840
+ finalizeDisposition: "completed",
841
+ notifyPrefix: ":memo:",
842
+ },
843
+ nodes: [
844
+ node("trigger", "trigger.manual", "Start Meeting Orchestration", {}, { x: 450, y: 50 }),
845
+
846
+ node("meeting-start", "meeting.start", "Meeting Start", {
847
+ title: "{{sessionTitle}}",
848
+ executor: "{{meetingExecutor}}",
849
+ wakePhrase: "{{wakePhrase}}",
850
+ includeTaskContext: true,
851
+ }, { x: 450, y: 190 }),
852
+
853
+ node("meeting-send", "meeting.send", "Send Opening Prompt", {
854
+ message: "{{openingMessage}}",
855
+ role: "system",
856
+ }, { x: 450, y: 320 }),
857
+
858
+ node("meeting-vision", "meeting.vision", "Analyze Meeting Frame", {
859
+ frameDataUrl: "{{frameDataUrl}}",
860
+ source: "{{visionSource}}",
861
+ prompt: "{{visionPrompt}}",
862
+ visionModel: "{{visionModel}}",
863
+ minIntervalMs: "{{visionMinIntervalMs}}",
864
+ forceAnalyze: "{{forceVisionAnalyze}}",
865
+ failOnError: false,
866
+ }, { x: 450, y: 450 }),
867
+
868
+ node("meeting-transcript", "meeting.transcript", "Capture Transcript", {
869
+ includeMessages: true,
870
+ }, { x: 450, y: 580 }),
871
+
872
+ node("wake-phrase-trigger", "trigger.meeting.wake_phrase", "Wake Phrase Trigger", {
873
+ wakePhrase: "{{wakePhrase}}",
874
+ text: "{{meeting-transcript.transcript}}",
875
+ mode: "contains",
876
+ }, { x: 450, y: 710 }),
877
+
878
+ node("guard-transcript", "condition.expression", "Wake Phrase + Transcript Guard", {
879
+ expression:
880
+ "(() => { const transcript = String($ctx.getNodeOutput('meeting-transcript')?.transcript || ''); const minChars = Number($data?.minTranscriptChars || 0); const hasWake = $ctx.getNodeOutput('wake-phrase-trigger')?.triggered === true; return transcript.length >= minChars && hasWake; })()",
881
+ }, { x: 450, y: 840 }),
882
+
883
+ node("notify-guard-failed", "notify.telegram", "Notify Guard Failed", {
884
+ message:
885
+ "{{notifyPrefix}} Meeting transcript guard failed for **{{sessionTitle}}**. " +
886
+ "Wake phrase missing or transcript shorter than {{minTranscriptChars}} chars.",
887
+ }, { x: 840, y: 840 }),
888
+
889
+ node("execute-child-workflow", "action.execute_workflow", "Run Child Workflow", {
890
+ workflowId: "{{childWorkflowId}}",
891
+ mode: "sync",
892
+ inheritContext: true,
893
+ includeKeys: [
894
+ "meetingSessionId",
895
+ "sessionTitle",
896
+ "wakePhrase",
897
+ "meetingVisionSummary",
898
+ ],
899
+ input: {
900
+ parentWorkflowId: "{{_workflowId}}",
901
+ parentRunId: "{{_workflowRunId}}",
902
+ sessionTitle: "{{sessionTitle}}",
903
+ wakePhrase: "{{wakePhrase}}",
904
+ transcript: "{{meeting-transcript.transcript}}",
905
+ visionSummary: "{{meeting-vision.summary}}",
906
+ },
907
+ outputVariable: "childWorkflowResult",
908
+ failOnChildError: false,
909
+ }, { x: 450, y: 980 }),
910
+
911
+ node("child-workflow-ok", "condition.expression", "Child Workflow Succeeded?", {
912
+ expression:
913
+ "$ctx.getNodeOutput('execute-child-workflow')?.success === true",
914
+ }, { x: 450, y: 1110 }),
915
+
916
+ node("notify-chain-success", "notify.telegram", "Notify Chain Success", {
917
+ message:
918
+ "{{notifyPrefix}} Meeting workflow chained into **{{childWorkflowId}}** " +
919
+ "successfully for **{{sessionTitle}}**.",
920
+ }, { x: 250, y: 1230 }),
921
+
922
+ node("notify-chain-failed", "notify.telegram", "Notify Chain Failure", {
923
+ message:
924
+ ":alert: Meeting flow completed but child workflow **{{childWorkflowId}}** failed " +
925
+ "or timed out for **{{sessionTitle}}**.",
926
+ }, { x: 650, y: 1230 }),
927
+
928
+ node("meeting-finalize", "meeting.finalize", "Finalize Meeting Session", {
929
+ status: "{{finalizeDisposition}}",
930
+ note: "Meeting subworkflow chain finalized.",
931
+ }, { x: 450, y: 1360 }),
932
+
933
+ node("final-log", "notify.log", "Record Final Outcome", {
934
+ message:
935
+ "Meeting orchestration finalized for {{sessionTitle}} with child workflow {{childWorkflowId}}",
936
+ level: "info",
937
+ }, { x: 450, y: 1490 }),
938
+ ],
939
+ edges: [
940
+ edge("trigger", "meeting-start"),
941
+ edge("meeting-start", "meeting-send"),
942
+ edge("meeting-send", "meeting-vision"),
943
+ edge("meeting-vision", "meeting-transcript"),
944
+ edge("meeting-transcript", "wake-phrase-trigger"),
945
+ edge("wake-phrase-trigger", "guard-transcript"),
946
+ edge("guard-transcript", "execute-child-workflow", { condition: "$output?.result === true", port: "yes" }),
947
+ edge("guard-transcript", "notify-guard-failed", { condition: "$output?.result !== true", port: "no" }),
948
+ edge("execute-child-workflow", "child-workflow-ok"),
949
+ edge("child-workflow-ok", "notify-chain-success", { condition: "$output?.result === true", port: "yes" }),
950
+ edge("child-workflow-ok", "notify-chain-failed", { condition: "$output?.result !== true", port: "no" }),
951
+ edge("notify-chain-success", "meeting-finalize"),
952
+ edge("notify-chain-failed", "meeting-finalize"),
953
+ edge("notify-guard-failed", "meeting-finalize"),
954
+ edge("meeting-finalize", "final-log"),
955
+ ],
956
+ metadata: {
957
+ author: "bosun",
958
+ version: 1,
959
+ createdAt: "2026-02-28T00:00:00Z",
960
+ templateVersion: "1.0.0",
961
+ tags: ["meeting", "subworkflow", "chaining", "agents"],
962
+ },
963
+ };
@@ -52,7 +52,7 @@ export const BUILD_DEPLOY_TEMPLATE = {
52
52
  }, { x: 400, y: 570 }),
53
53
 
54
54
  node("notify", "notify.telegram", "Notify Deploy", {
55
- message: "🚀 Deployment to production completed for {{branch}}",
55
+ message: ":rocket: Deployment to production completed for {{branch}}",
56
56
  }, { x: 400, y: 700 }),
57
57
  ],
58
58
  edges: [
@@ -173,11 +173,11 @@ Commit the result with message "docs: update changelog for vX.Y.Z".`,
173
173
  }, { x: 250, y: 1220 }),
174
174
 
175
175
  node("notify-success", "notify.telegram", "Notify: Released", {
176
- message: "📦 **Release published!**\n\nVersion: v{{version}}\nnpm + GitHub release created.",
176
+ message: ":box: **Release published!**\n\nVersion: v{{version}}\nnpm + GitHub release created.",
177
177
  }, { x: 250, y: 1350 }),
178
178
 
179
179
  node("notify-failure", "notify.telegram", "Notify: Release Failed", {
180
- message: " **Release pipeline failed** at test stage.\n\nVersion bump was {{bumpType}} but tests did not pass. Manual intervention required.",
180
+ message: ":close: **Release pipeline failed** at test stage.\n\nVersion bump was {{bumpType}} but tests did not pass. Manual intervention required.",
181
181
  }, { x: 600, y: 960 }),
182
182
  ],
183
183
  edges: [
@@ -275,7 +275,7 @@ export const CANARY_DEPLOY_TEMPLATE = {
275
275
  }, { x: 100, y: 960 }),
276
276
 
277
277
  node("notify-success", "notify.telegram", "Deploy Succeeded", {
278
- message: " **Canary deploy promoted to production** successfully.",
278
+ message: ":check: **Canary deploy promoted to production** successfully.",
279
279
  }, { x: 100, y: 1090 }),
280
280
 
281
281
  node("rollback", "action.run_command", "Rollback", {
@@ -284,11 +284,11 @@ export const CANARY_DEPLOY_TEMPLATE = {
284
284
  }, { x: 550, y: 700 }),
285
285
 
286
286
  node("notify-rollback", "notify.telegram", "Deploy Rolled Back", {
287
- message: "🔄 **Canary deploy rolled back.**\n\nSmoke tests or staging deploy failed. Production unchanged.",
287
+ message: ":refresh: **Canary deploy rolled back.**\n\nSmoke tests or staging deploy failed. Production unchanged.",
288
288
  }, { x: 550, y: 830 }),
289
289
 
290
290
  node("notify-staging-fail", "notify.telegram", "Staging Failed", {
291
- message: " **Staging deploy failed.** Not proceeding to canary phase.",
291
+ message: ":close: **Staging deploy failed.** Not proceeding to canary phase.",
292
292
  }, { x: 600, y: 440 }),
293
293
  ],
294
294
  edges: [