bosun 0.41.8 → 0.41.10
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/README.md +23 -1
- package/agent/agent-event-bus.mjs +31 -2
- package/agent/agent-pool.mjs +275 -40
- package/agent/agent-prompts.mjs +9 -1
- package/agent/agent-supervisor.mjs +22 -0
- package/agent/autofix.mjs +1 -1
- package/agent/primary-agent.mjs +115 -5
- package/cli.mjs +3 -2
- package/config/config.mjs +47 -33
- package/config/context-shredding-config.mjs +1 -1
- package/config/repo-root.mjs +41 -33
- package/desktop/main.mjs +350 -25
- package/desktop/preload.cjs +8 -0
- package/desktop/preload.mjs +19 -0
- package/entrypoint.mjs +332 -0
- package/git/sdk-conflict-resolver.mjs +1 -1
- package/infra/health-status.mjs +72 -0
- package/infra/library-manager.mjs +58 -1
- package/infra/maintenance.mjs +1 -2
- package/infra/monitor.mjs +26 -8
- package/infra/session-tracker.mjs +30 -3
- package/package.json +12 -4
- package/server/bosun-mcp-server.mjs +1004 -0
- package/server/setup-web-server.mjs +288 -259
- package/server/ui-server.mjs +1323 -26
- package/shell/claude-shell.mjs +14 -1
- package/shell/codex-config.mjs +1 -1
- package/shell/codex-model-profiles.mjs +170 -30
- package/shell/codex-shell.mjs +63 -18
- package/shell/opencode-providers.mjs +20 -8
- package/task/task-executor.mjs +28 -0
- package/task/task-store.mjs +13 -4
- package/telegram/telegram-sentinel.mjs +54 -3
- package/tools/list-todos.mjs +7 -1
- package/ui/app.js +3 -2
- package/ui/components/agent-selector.js +127 -0
- package/ui/components/session-list.js +15 -10
- package/ui/demo-defaults.js +334 -336
- package/ui/modules/router.js +2 -0
- package/ui/modules/state.js +13 -5
- package/ui/tabs/chat.js +3 -0
- package/ui/tabs/library.js +284 -52
- package/ui/tabs/tasks.js +5 -13
- package/ui/tabs/workflows.js +766 -3
- package/workflow/workflow-engine.mjs +246 -5
- package/workflow/workflow-nodes/definitions.mjs +37 -0
- package/workflow/workflow-nodes.mjs +1014 -184
- package/workflow/workflow-templates.mjs +0 -5
- package/workflow-templates/_helpers.mjs +253 -0
- package/workflow-templates/agents.mjs +199 -226
- package/workflow-templates/github.mjs +106 -16
- package/workflow-templates/sub-workflows.mjs +233 -0
- package/workflow-templates/task-execution.mjs +125 -471
- package/workflow-templates/task-lifecycle.mjs +11 -48
- package/workspace/command-diagnostics.mjs +460 -0
- package/workspace/context-cache.mjs +396 -28
- package/workspace/worktree-manager.mjs +1 -1
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* - Meeting Orchestrator + Subworkflow Chain
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { node, edge, resetLayout } from "./_helpers.mjs";
|
|
14
|
+
import { node, edge, resetLayout, embedSubWorkflow, wire } from "./_helpers.mjs";
|
|
15
|
+
import { VALIDATION_GATE_SUB, PR_CHECK_HANDOFF_SUB } from "./sub-workflows.mjs";
|
|
15
16
|
|
|
16
17
|
const AGENT_SESSION_MONITOR_COMMAND = [
|
|
17
18
|
'node -e "',
|
|
@@ -495,39 +496,48 @@ export const AGENT_SESSION_MONITOR_TEMPLATE = {
|
|
|
495
496
|
|
|
496
497
|
resetLayout();
|
|
497
498
|
|
|
498
|
-
export const BACKEND_AGENT_TEMPLATE = {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
499
|
+
export const BACKEND_AGENT_TEMPLATE = (() => {
|
|
500
|
+
resetLayout();
|
|
501
|
+
|
|
502
|
+
// ── Embed sub-workflows ────────────────────────────────────────────────
|
|
503
|
+
const mainValidation = embedSubWorkflow(VALIDATION_GATE_SUB, "main-");
|
|
504
|
+
const retryValidation = embedSubWorkflow(VALIDATION_GATE_SUB, "retry-");
|
|
505
|
+
const mainPrHandoff = embedSubWorkflow(PR_CHECK_HANDOFF_SUB, "main-");
|
|
506
|
+
const retryPrHandoff = embedSubWorkflow(PR_CHECK_HANDOFF_SUB, "retry-");
|
|
507
|
+
|
|
508
|
+
return {
|
|
509
|
+
id: "template-backend-agent",
|
|
510
|
+
name: "Task Completion Agent",
|
|
511
|
+
description:
|
|
512
|
+
"General-purpose task completion agent with a test-first methodology. " +
|
|
513
|
+
"Writes tests first, implements the feature, validates with build + lint, " +
|
|
514
|
+
"then creates a PR. Works with any language/framework — commands are " +
|
|
515
|
+
"auto-detected from your project or fully customizable.",
|
|
516
|
+
category: "agents",
|
|
517
|
+
enabled: true,
|
|
518
|
+
recommended: true,
|
|
519
|
+
trigger: "trigger.task_assigned",
|
|
520
|
+
variables: {
|
|
521
|
+
testCommand: "npm test",
|
|
522
|
+
buildCommand: "npm run build",
|
|
523
|
+
lintCommand: "",
|
|
524
|
+
baseBranch: "main",
|
|
525
|
+
protectedBranches: ["main", "master", "develop", "production"],
|
|
526
|
+
agentSdk: "auto",
|
|
527
|
+
timeoutMs: 3600000,
|
|
528
|
+
autoFixTimeoutMs: 1200000,
|
|
529
|
+
},
|
|
530
|
+
nodes: [
|
|
531
|
+
node("trigger", "trigger.task_assigned", "Task Assigned", {
|
|
532
|
+
}, { x: 400, y: 50 }),
|
|
523
533
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
534
|
+
node("plan-work", "agent.run_planner", "Plan Implementation", {
|
|
535
|
+
prompt: "Analyze the task requirements and create a step-by-step implementation plan. Identify which files need to be modified, what tests need to be written, and any API contracts to maintain.",
|
|
536
|
+
outputVariable: "plan",
|
|
537
|
+
}, { x: 400, y: 180 }),
|
|
528
538
|
|
|
529
|
-
|
|
530
|
-
|
|
539
|
+
node("write-tests", "action.run_agent", "Write Tests First", {
|
|
540
|
+
prompt: `# Test-First Development
|
|
531
541
|
|
|
532
542
|
Based on the plan:
|
|
533
543
|
{{plan}}
|
|
@@ -539,12 +549,12 @@ Write comprehensive tests FIRST before any implementation:
|
|
|
539
549
|
|
|
540
550
|
Use the project's test command: {{testCommand}}
|
|
541
551
|
Commit with message "test: add tests for [feature]"`,
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
552
|
+
sdk: "{{agentSdk}}",
|
|
553
|
+
timeoutMs: "{{timeoutMs}}",
|
|
554
|
+
}, { x: 400, y: 330 }),
|
|
545
555
|
|
|
546
|
-
|
|
547
|
-
|
|
556
|
+
node("implement", "action.run_agent", "Implement Feature", {
|
|
557
|
+
prompt: `# Implement Feature
|
|
548
558
|
|
|
549
559
|
The tests have been written. Now implement the feature to make them pass:
|
|
550
560
|
1. Follow existing code conventions
|
|
@@ -554,79 +564,60 @@ The tests have been written. Now implement the feature to make them pass:
|
|
|
554
564
|
|
|
555
565
|
Run \`{{testCommand}}\` after implementation.
|
|
556
566
|
Commit with message "feat: implement [feature]"`,
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
node("notify-done", "notify.log", "Task Complete", {
|
|
613
|
-
message: "Task completion agent finished task — PR lifecycle handoff recorded",
|
|
614
|
-
level: "info",
|
|
615
|
-
}, { x: 180, y: 1320 }),
|
|
616
|
-
|
|
617
|
-
node("notify-pr-failed", "notify.telegram", "Escalate Lifecycle Handoff Failure", {
|
|
618
|
-
message: ":alert: Task completion agent passed validation for {{taskTitle}} but failed to record Bosun PR lifecycle handoff after retries. Manual follow-up required.",
|
|
619
|
-
}, { x: 420, y: 1320 }),
|
|
620
|
-
|
|
621
|
-
node("set-validation-summary", "action.set_variable", "Summarize Validation Output", {
|
|
622
|
-
key: "validationSummary",
|
|
623
|
-
value:
|
|
624
|
-
"(() => { const implement = $ctx.getNodeOutput('implement') || {}; const build = $ctx.getNodeOutput('build') || {}; const test = $ctx.getNodeOutput('test-final') || {}; const lint = $ctx.getNodeOutput('lint') || {}; return ['- implement.success: ' + (implement.success === true), '- build.passed: ' + (build.passed === true), '- test-final.passed: ' + (test.passed === true), '- lint.passed: ' + (lint.passed === true), '', 'Build output:', String(build.output || '').slice(0, 6000), '', 'Test output:', String(test.output || '').slice(0, 6000), '', 'Lint output:', String(lint.output || '').slice(0, 6000)].join('\\n'); })()",
|
|
625
|
-
isExpression: true,
|
|
626
|
-
}, { x: 620, y: 1090 }),
|
|
627
|
-
|
|
628
|
-
node("auto-fix", "action.run_agent", "Auto-Fix Validation Failures", {
|
|
629
|
-
prompt: `# Fix Validation Failures
|
|
567
|
+
sdk: "{{agentSdk}}",
|
|
568
|
+
timeoutMs: "{{timeoutMs}}",
|
|
569
|
+
}, { x: 400, y: 490 }),
|
|
570
|
+
|
|
571
|
+
// ── Main Validation Gate (build → test → lint) via sub-workflow ────
|
|
572
|
+
...mainValidation.nodes,
|
|
573
|
+
|
|
574
|
+
node("all-passed", "condition.expression", "All Checks Passed?", {
|
|
575
|
+
expression: `$ctx.getNodeOutput('main-build')?.passed === true && $ctx.getNodeOutput('main-test')?.passed === true && $ctx.getNodeOutput('main-lint')?.passed === true`,
|
|
576
|
+
}, { x: 400, y: 1040, outputs: ["yes", "no"] }),
|
|
577
|
+
|
|
578
|
+
// ── Main Push + PR path ────────────────────────────────────────────
|
|
579
|
+
node("push-branch", "action.push_branch", "Push Branch", {
|
|
580
|
+
worktreePath: "{{worktreePath}}",
|
|
581
|
+
branch: "{{branch}}",
|
|
582
|
+
baseBranch: "{{baseBranch}}",
|
|
583
|
+
rebaseBeforePush: true,
|
|
584
|
+
emptyDiffGuard: true,
|
|
585
|
+
protectedBranches: "{{protectedBranches}}",
|
|
586
|
+
}, { x: 250, y: 1110 }),
|
|
587
|
+
|
|
588
|
+
node("create-pr", "action.create_pr", "Handoff PR Lifecycle", {
|
|
589
|
+
title: "feat: {{taskTitle}}",
|
|
590
|
+
body: "Implements backend task with test-first methodology.\n\n**Plan:**\n{{plan}}\n\nAll tests passing. Bosun lifecycle handoff ready.",
|
|
591
|
+
branch: "{{branch}}",
|
|
592
|
+
baseBranch: "{{baseBranch}}",
|
|
593
|
+
failOnError: true,
|
|
594
|
+
maxRetries: 3,
|
|
595
|
+
retryDelayMs: 15000,
|
|
596
|
+
continueOnError: true,
|
|
597
|
+
}, { x: 250, y: 1170 }),
|
|
598
|
+
|
|
599
|
+
// ── Main PR handoff (pr-ok? → set-inreview → dispatch) via sub-wf ─
|
|
600
|
+
...mainPrHandoff.nodes,
|
|
601
|
+
|
|
602
|
+
node("notify-done", "notify.log", "Task Complete", {
|
|
603
|
+
message: "Task completion agent finished task — PR lifecycle handoff recorded",
|
|
604
|
+
level: "info",
|
|
605
|
+
}, { x: 180, y: 1320 }),
|
|
606
|
+
|
|
607
|
+
node("notify-pr-failed", "notify.telegram", "Escalate Lifecycle Handoff Failure", {
|
|
608
|
+
message: ":alert: Task completion agent passed validation for {{taskTitle}} but failed to record Bosun PR lifecycle handoff after retries. Manual follow-up required.",
|
|
609
|
+
}, { x: 420, y: 1320 }),
|
|
610
|
+
|
|
611
|
+
// ── Retry path (validation failed → auto-fix → re-validate) ───────
|
|
612
|
+
node("set-validation-summary", "action.set_variable", "Summarize Validation Output", {
|
|
613
|
+
key: "validationSummary",
|
|
614
|
+
value:
|
|
615
|
+
"(() => { const implement = $ctx.getNodeOutput('implement') || {}; const build = $ctx.getNodeOutput('main-build') || {}; const test = $ctx.getNodeOutput('main-test') || {}; const lint = $ctx.getNodeOutput('main-lint') || {}; return ['- implement.success: ' + (implement.success === true), '- build.passed: ' + (build.passed === true), '- test-final.passed: ' + (test.passed === true), '- lint.passed: ' + (lint.passed === true), '', 'Build output:', String(build.output || '').slice(0, 6000), '', 'Test output:', String(test.output || '').slice(0, 6000), '', 'Lint output:', String(lint.output || '').slice(0, 6000)].join('\\n'); })()",
|
|
616
|
+
isExpression: true,
|
|
617
|
+
}, { x: 620, y: 1090 }),
|
|
618
|
+
|
|
619
|
+
node("auto-fix", "action.run_agent", "Auto-Fix Validation Failures", {
|
|
620
|
+
prompt: `# Fix Validation Failures
|
|
630
621
|
|
|
631
622
|
The first validation pass failed for task **{{taskTitle}}**.
|
|
632
623
|
|
|
@@ -642,123 +633,105 @@ Keep the original task scope.
|
|
|
642
633
|
|
|
643
634
|
Run build + tests + lint locally before finishing.
|
|
644
635
|
Commit with message "fix: address validation failures"`,
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
edge("pr-created-retry", "set-inreview-retry", { condition: "$output?.result === true", port: "yes" }),
|
|
742
|
-
edge("set-inreview-retry", "notify-done-retry"),
|
|
743
|
-
edge("pr-created-retry", "notify-pr-failed-retry", { condition: "$output?.result !== true", port: "no" }),
|
|
744
|
-
],
|
|
745
|
-
metadata: {
|
|
746
|
-
author: "bosun",
|
|
747
|
-
version: 2,
|
|
748
|
-
createdAt: "2025-02-25T00:00:00Z",
|
|
749
|
-
templateVersion: "2.0.0",
|
|
750
|
-
tags: ["agent", "task-completion", "test-first", "tdd", "multi-language"],
|
|
751
|
-
replaces: {
|
|
752
|
-
module: "primary-agent.mjs",
|
|
753
|
-
functions: ["runAgentWithTask"],
|
|
754
|
-
calledFrom: ["task-executor.mjs:executeTask"],
|
|
755
|
-
description:
|
|
756
|
-
"Replaces generic agent task execution with a structured " +
|
|
757
|
-
"workflow. Test-first methodology, build/lint gates, and Bosun-managed PR lifecycle handoff " +
|
|
758
|
-
"are enforced as distinct workflow stages. Works with any language/framework.",
|
|
636
|
+
sdk: "{{agentSdk}}",
|
|
637
|
+
timeoutMs: "{{autoFixTimeoutMs}}",
|
|
638
|
+
}, { x: 620, y: 1170 }),
|
|
639
|
+
|
|
640
|
+
// ── Retry Validation Gate (build → test → lint) via sub-workflow ───
|
|
641
|
+
...retryValidation.nodes,
|
|
642
|
+
|
|
643
|
+
node("retry-passed", "condition.expression", "Retry Checks Passed?", {
|
|
644
|
+
expression: `$ctx.getNodeOutput('retry-build')?.passed === true && $ctx.getNodeOutput('retry-test')?.passed === true && $ctx.getNodeOutput('retry-lint')?.passed === true`,
|
|
645
|
+
}, { x: 620, y: 1690, outputs: ["yes", "no"] }),
|
|
646
|
+
|
|
647
|
+
// ── Retry Push + PR path ───────────────────────────────────────────
|
|
648
|
+
node("push-branch-retry", "action.push_branch", "Push Branch (Retry)", {
|
|
649
|
+
worktreePath: "{{worktreePath}}",
|
|
650
|
+
branch: "{{branch}}",
|
|
651
|
+
baseBranch: "{{baseBranch}}",
|
|
652
|
+
rebaseBeforePush: true,
|
|
653
|
+
emptyDiffGuard: true,
|
|
654
|
+
protectedBranches: "{{protectedBranches}}",
|
|
655
|
+
}, { x: 450, y: 1760 }),
|
|
656
|
+
|
|
657
|
+
node("create-pr-retry", "action.create_pr", "Handoff PR Lifecycle (After Retry)", {
|
|
658
|
+
title: "feat: {{taskTitle}}",
|
|
659
|
+
body: "Implements backend task after auto-fix retry.\n\n**Plan:**\n{{plan}}\n\nValidation passed after remediation. Bosun lifecycle handoff ready.",
|
|
660
|
+
branch: "{{branch}}",
|
|
661
|
+
baseBranch: "{{baseBranch}}",
|
|
662
|
+
failOnError: true,
|
|
663
|
+
maxRetries: 3,
|
|
664
|
+
retryDelayMs: 15000,
|
|
665
|
+
continueOnError: true,
|
|
666
|
+
}, { x: 450, y: 1820 }),
|
|
667
|
+
|
|
668
|
+
// ── Retry PR handoff via sub-workflow ──────────────────────────────
|
|
669
|
+
...retryPrHandoff.nodes,
|
|
670
|
+
|
|
671
|
+
node("notify-done-retry", "notify.log", "Task Complete (After Retry)", {
|
|
672
|
+
message: "Task completion agent finished task after retry — PR lifecycle handoff recorded",
|
|
673
|
+
level: "info",
|
|
674
|
+
}, { x: 360, y: 1980 }),
|
|
675
|
+
|
|
676
|
+
node("notify-fail", "notify.telegram", "Checks Failed", {
|
|
677
|
+
message: ":alert: Task completion agent: validation failed for task {{taskTitle}} even after remediation pass. Manual review needed.",
|
|
678
|
+
}, { x: 820, y: 1820 }),
|
|
679
|
+
|
|
680
|
+
node("notify-pr-failed-retry", "notify.telegram", "Escalate Lifecycle Failure (Retry Path)", {
|
|
681
|
+
message: ":alert: Task completion agent remediation passed for {{taskTitle}} but Bosun PR lifecycle handoff failed after retries. Manual follow-up required.",
|
|
682
|
+
}, { x: 620, y: 1980 }),
|
|
683
|
+
],
|
|
684
|
+
edges: [
|
|
685
|
+
edge("trigger", "plan-work"),
|
|
686
|
+
edge("plan-work", "write-tests"),
|
|
687
|
+
edge("write-tests", "implement"),
|
|
688
|
+
|
|
689
|
+
// implement → main validation gate
|
|
690
|
+
wire("implement", mainValidation.entryNodeId),
|
|
691
|
+
...mainValidation.edges,
|
|
692
|
+
wire(mainValidation.exitNodeId, "all-passed"),
|
|
693
|
+
|
|
694
|
+
// Main pass → push → PR → handoff
|
|
695
|
+
edge("all-passed", "push-branch", { condition: "$output?.result === true", port: "yes" }),
|
|
696
|
+
edge("all-passed", "set-validation-summary", { condition: "$output?.result !== true", port: "no" }),
|
|
697
|
+
edge("push-branch", "create-pr"),
|
|
698
|
+
wire("create-pr", mainPrHandoff.entryNodeId),
|
|
699
|
+
...mainPrHandoff.edges,
|
|
700
|
+
wire(mainPrHandoff.exitNodeId, "notify-done"),
|
|
701
|
+
edge(mainPrHandoff.entryNodeId, "notify-pr-failed", { condition: "$output?.result !== true", port: "no" }),
|
|
702
|
+
|
|
703
|
+
// Retry path: auto-fix → retry validation → push → PR → handoff
|
|
704
|
+
edge("set-validation-summary", "auto-fix"),
|
|
705
|
+
wire("auto-fix", retryValidation.entryNodeId),
|
|
706
|
+
...retryValidation.edges,
|
|
707
|
+
wire(retryValidation.exitNodeId, "retry-passed"),
|
|
708
|
+
|
|
709
|
+
edge("retry-passed", "push-branch-retry", { condition: "$output?.result === true", port: "yes" }),
|
|
710
|
+
edge("retry-passed", "notify-fail", { condition: "$output?.result !== true", port: "no" }),
|
|
711
|
+
edge("push-branch-retry", "create-pr-retry"),
|
|
712
|
+
wire("create-pr-retry", retryPrHandoff.entryNodeId),
|
|
713
|
+
...retryPrHandoff.edges,
|
|
714
|
+
wire(retryPrHandoff.exitNodeId, "notify-done-retry"),
|
|
715
|
+
edge(retryPrHandoff.entryNodeId, "notify-pr-failed-retry", { condition: "$output?.result !== true", port: "no" }),
|
|
716
|
+
],
|
|
717
|
+
metadata: {
|
|
718
|
+
author: "bosun",
|
|
719
|
+
version: 2,
|
|
720
|
+
createdAt: "2025-02-25T00:00:00Z",
|
|
721
|
+
templateVersion: "2.0.0",
|
|
722
|
+
tags: ["agent", "task-completion", "test-first", "tdd", "multi-language"],
|
|
723
|
+
replaces: {
|
|
724
|
+
module: "primary-agent.mjs",
|
|
725
|
+
functions: ["runAgentWithTask"],
|
|
726
|
+
calledFrom: ["task-executor.mjs:executeTask"],
|
|
727
|
+
description:
|
|
728
|
+
"Replaces generic agent task execution with a structured " +
|
|
729
|
+
"workflow. Test-first methodology, build/lint gates, and Bosun-managed PR lifecycle handoff " +
|
|
730
|
+
"are enforced as distinct workflow stages. Works with any language/framework.",
|
|
731
|
+
},
|
|
759
732
|
},
|
|
760
|
-
}
|
|
761
|
-
};
|
|
733
|
+
};
|
|
734
|
+
})();
|
|
762
735
|
|
|
763
736
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
764
737
|
// Voice + Video Rollout (Parallel Lanes)
|