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.
- package/.env.example +98 -16
- package/README.md +27 -0
- package/agent-event-bus.mjs +5 -5
- package/agent-pool.mjs +129 -12
- package/agent-prompts.mjs +7 -1
- package/agent-sdk.mjs +13 -2
- package/agent-supervisor.mjs +2 -2
- package/agent-work-report.mjs +1 -1
- package/anomaly-detector.mjs +6 -6
- package/autofix.mjs +15 -15
- package/bosun-skills.mjs +4 -4
- package/bosun.schema.json +160 -4
- package/claude-shell.mjs +11 -11
- package/cli.mjs +21 -21
- package/codex-config.mjs +19 -19
- package/codex-shell.mjs +180 -29
- package/config-doctor.mjs +27 -2
- package/config.mjs +60 -7
- package/copilot-shell.mjs +4 -4
- package/error-detector.mjs +1 -1
- package/fleet-coordinator.mjs +2 -2
- package/gemini-shell.mjs +692 -0
- package/github-oauth-portal.mjs +1 -1
- package/github-reconciler.mjs +2 -2
- package/kanban-adapter.mjs +741 -168
- package/merge-strategy.mjs +25 -25
- package/monitor.mjs +123 -105
- package/opencode-shell.mjs +22 -22
- package/package.json +7 -1
- package/postinstall.mjs +22 -22
- package/pr-cleanup-daemon.mjs +6 -6
- package/prepublish-check.mjs +4 -4
- package/presence.mjs +2 -2
- package/primary-agent.mjs +85 -7
- package/publish.mjs +1 -1
- package/review-agent.mjs +1 -1
- package/session-tracker.mjs +11 -0
- package/setup-web-server.mjs +429 -21
- package/setup.mjs +367 -12
- package/shared-knowledge.mjs +1 -1
- package/startup-service.mjs +9 -9
- package/stream-resilience.mjs +58 -4
- package/sync-engine.mjs +2 -2
- package/task-assessment.mjs +9 -9
- package/task-cli.mjs +1 -1
- package/task-complexity.mjs +71 -2
- package/task-context.mjs +1 -2
- package/task-executor.mjs +104 -41
- package/telegram-bot.mjs +825 -494
- package/telegram-sentinel.mjs +28 -28
- package/ui/app.js +256 -23
- package/ui/app.monolith.js +1 -1
- package/ui/components/agent-selector.js +4 -3
- package/ui/components/chat-view.js +101 -28
- package/ui/components/diff-viewer.js +3 -3
- package/ui/components/kanban-board.js +3 -3
- package/ui/components/session-list.js +255 -35
- package/ui/components/workspace-switcher.js +3 -3
- package/ui/demo.html +209 -194
- package/ui/index.html +3 -3
- package/ui/modules/icon-utils.js +206 -142
- package/ui/modules/icons.js +2 -27
- package/ui/modules/settings-schema.js +29 -5
- package/ui/modules/streaming.js +30 -2
- package/ui/modules/vision-stream.js +275 -0
- package/ui/modules/voice-client.js +102 -9
- package/ui/modules/voice-fallback.js +62 -6
- package/ui/modules/voice-overlay.js +594 -59
- package/ui/modules/voice.js +31 -38
- package/ui/setup.html +284 -34
- package/ui/styles/components.css +47 -0
- package/ui/styles/sessions.css +75 -0
- package/ui/tabs/agents.js +73 -43
- package/ui/tabs/chat.js +37 -40
- package/ui/tabs/control.js +2 -2
- package/ui/tabs/dashboard.js +1 -1
- package/ui/tabs/infra.js +10 -10
- package/ui/tabs/library.js +8 -8
- package/ui/tabs/logs.js +10 -10
- package/ui/tabs/settings.js +20 -20
- package/ui/tabs/tasks.js +76 -47
- package/ui-server.mjs +1761 -124
- package/update-check.mjs +13 -13
- package/ve-kanban.mjs +1 -1
- package/whatsapp-channel.mjs +5 -5
- package/workflow-engine.mjs +20 -1
- package/workflow-nodes.mjs +904 -4
- package/workflow-templates/agents.mjs +321 -7
- package/workflow-templates/ci-cd.mjs +6 -6
- package/workflow-templates/github.mjs +156 -84
- package/workflow-templates/planning.mjs +8 -8
- package/workflow-templates/reliability.mjs +8 -8
- package/workflow-templates/security.mjs +3 -3
- package/workflow-templates.mjs +15 -9
- package/workspace-manager.mjs +85 -1
- package/workspace-monitor.mjs +2 -2
- package/workspace-registry.mjs +2 -2
- package/worktree-manager.mjs +1 -1
package/monitor.mjs
CHANGED
|
@@ -330,7 +330,7 @@ function formatAgentAlert(alert) {
|
|
|
330
330
|
const severity = String(alert.severity || "medium").toUpperCase();
|
|
331
331
|
const type = alert.type || "alert";
|
|
332
332
|
const lines = [
|
|
333
|
-
|
|
333
|
+
`:search: Agent Analyzer: ${severity} ${type}`,
|
|
334
334
|
`Attempt: ${alert.attempt_id || "unknown"}`,
|
|
335
335
|
];
|
|
336
336
|
if (alert.task_id) lines.push(`Task: ${alert.task_id}`);
|
|
@@ -525,10 +525,19 @@ async function ensureWorkflowAutomationEngine() {
|
|
|
525
525
|
}
|
|
526
526
|
: null;
|
|
527
527
|
|
|
528
|
+
let meetingService = null;
|
|
529
|
+
try {
|
|
530
|
+
const { createMeetingWorkflowService } = await import("./meeting-workflow-service.mjs");
|
|
531
|
+
meetingService = createMeetingWorkflowService();
|
|
532
|
+
} catch (err) {
|
|
533
|
+
console.warn(`[workflows] meeting service unavailable: ${err?.message || err}`);
|
|
534
|
+
}
|
|
535
|
+
|
|
528
536
|
const services = {
|
|
529
537
|
telegram: telegramService,
|
|
530
538
|
kanban: kanbanService,
|
|
531
539
|
agentPool: agentPoolService,
|
|
540
|
+
meeting: meetingService,
|
|
532
541
|
prompts: agentPrompts || null,
|
|
533
542
|
anomalyDetector: anomalyDetector || null,
|
|
534
543
|
};
|
|
@@ -1122,7 +1131,7 @@ if (!isMainThread || chdirUnsupportedInRuntime) {
|
|
|
1122
1131
|
if (r.success) {
|
|
1123
1132
|
console.log(`[monitor] ✓ workspace repo ready: ${r.name}`);
|
|
1124
1133
|
} else {
|
|
1125
|
-
console.warn(`[monitor]
|
|
1134
|
+
console.warn(`[monitor] :alert: workspace repo failed: ${r.name} — ${r.error}`);
|
|
1126
1135
|
}
|
|
1127
1136
|
}
|
|
1128
1137
|
} catch (err) {
|
|
@@ -1436,7 +1445,7 @@ const workspaceMonitor = new WorkspaceMonitor({
|
|
|
1436
1445
|
cacheDir: resolve(repoRoot, ".cache", "workspace-logs"),
|
|
1437
1446
|
repoRoot,
|
|
1438
1447
|
onStuckDetected: ({ attemptId, reason, recommendation }) => {
|
|
1439
|
-
const msg =
|
|
1448
|
+
const msg = `:alert: Agent ${attemptId.substring(0, 8)} stuck: ${reason}\nRecommendation: ${recommendation}`;
|
|
1440
1449
|
console.warn(`[workspace-monitor] ${msg}`);
|
|
1441
1450
|
void notify?.(msg, { dedupKey: `stuck-${attemptId.substring(0, 8)}` });
|
|
1442
1451
|
},
|
|
@@ -1779,7 +1788,7 @@ function resolveMonitorMonitorTimeoutMs() {
|
|
|
1779
1788
|
if (minTimeout !== null && maxTimeout !== null && maxTimeout < minTimeout) {
|
|
1780
1789
|
warnMonitorTimeoutConfig(
|
|
1781
1790
|
`bounds:${minTimeout}:${maxTimeout}`,
|
|
1782
|
-
`[monitor]
|
|
1791
|
+
`[monitor] :alert: Invalid monitor-monitor timeout bounds: DEVMODE_MONITOR_MONITOR_TIMEOUT_MAX_MS=${maxTimeout}ms is lower than DEVMODE_MONITOR_MONITOR_TIMEOUT_MIN_MS=${minTimeout}ms. Ignoring max bound.`,
|
|
1783
1792
|
);
|
|
1784
1793
|
maxTimeout = null;
|
|
1785
1794
|
}
|
|
@@ -1795,7 +1804,7 @@ function resolveMonitorMonitorTimeoutMs() {
|
|
|
1795
1804
|
if (legacyTimeout < MONITOR_MONITOR_RECOMMENDED_MIN_TIMEOUT_MS) {
|
|
1796
1805
|
warnMonitorTimeoutConfig(
|
|
1797
1806
|
`legacy-low:${legacyTimeout}`,
|
|
1798
|
-
`[monitor]
|
|
1807
|
+
`[monitor] :alert: DEVMODE_AUTO_CODE_FIX_TIMEOUT_MS=${legacyTimeout}ms is low for monitor-monitor (recommended >= ${MONITOR_MONITOR_RECOMMENDED_MIN_TIMEOUT_MS}ms). Set DEVMODE_MONITOR_MONITOR_TIMEOUT_MS to override explicitly.`,
|
|
1799
1808
|
);
|
|
1800
1809
|
}
|
|
1801
1810
|
}
|
|
@@ -1810,7 +1819,7 @@ function resolveMonitorMonitorTimeoutMs() {
|
|
|
1810
1819
|
if (timeoutMs < MONITOR_MONITOR_RECOMMENDED_MIN_TIMEOUT_MS) {
|
|
1811
1820
|
warnMonitorTimeoutConfig(
|
|
1812
1821
|
`effective-low:${timeoutMs}`,
|
|
1813
|
-
`[monitor]
|
|
1822
|
+
`[monitor] :alert: monitor-monitor timeout is ${timeoutMs}ms. Values below ${MONITOR_MONITOR_RECOMMENDED_MIN_TIMEOUT_MS}ms can cause premature failover loops.`,
|
|
1814
1823
|
);
|
|
1815
1824
|
}
|
|
1816
1825
|
|
|
@@ -2267,7 +2276,7 @@ function tripCircuitBreaker(failureCount) {
|
|
|
2267
2276
|
circuitBreakerResetAt = Date.now() + CIRCUIT_BREAKER_PAUSE_MS;
|
|
2268
2277
|
const pauseMin = Math.round(CIRCUIT_BREAKER_PAUSE_MS / 60_000);
|
|
2269
2278
|
console.error(
|
|
2270
|
-
`[monitor]
|
|
2279
|
+
`[monitor] :plug: CIRCUIT BREAKER TRIPPED: ${failureCount} failures in ${Math.round(CIRCUIT_BREAKER_WINDOW_MS / 1000)}s. ` +
|
|
2271
2280
|
`Killing orchestrator and pausing all restarts for ${pauseMin} minutes.`,
|
|
2272
2281
|
);
|
|
2273
2282
|
|
|
@@ -2287,7 +2296,7 @@ function tripCircuitBreaker(failureCount) {
|
|
|
2287
2296
|
if (!circuitBreakerNotified && telegramToken && telegramChatId) {
|
|
2288
2297
|
circuitBreakerNotified = true;
|
|
2289
2298
|
const msg =
|
|
2290
|
-
|
|
2299
|
+
`:plug: Circuit breaker tripped: ${failureCount} failures in ${Math.round(CIRCUIT_BREAKER_WINDOW_MS / 1000)}s.\n` +
|
|
2291
2300
|
`Orchestrator killed. All restarts paused for ${pauseMin} minutes.\n` +
|
|
2292
2301
|
`Will auto-resume at ${new Date(circuitBreakerResetAt).toLocaleTimeString()}.`;
|
|
2293
2302
|
// Fire-and-forget with skipDedup to ensure it gets through
|
|
@@ -2664,7 +2673,7 @@ async function handleMonitorFailure(reason, err) {
|
|
|
2664
2673
|
const pauseMs = Math.max(orchestratorPauseMs, 30 * 60 * 1000);
|
|
2665
2674
|
const pauseMin = Math.max(1, Math.round(pauseMs / 60_000));
|
|
2666
2675
|
const msg =
|
|
2667
|
-
|
|
2676
|
+
`:close: bosun hit hard failure cap (${failureCount}). ` +
|
|
2668
2677
|
`Entering safe mode for ${pauseMin} minute(s); monitor process will stay alive.`;
|
|
2669
2678
|
console.error(`[monitor] ${msg}`);
|
|
2670
2679
|
if (telegramToken && telegramChatId) {
|
|
@@ -2713,7 +2722,7 @@ async function handleMonitorFailure(reason, err) {
|
|
|
2713
2722
|
try {
|
|
2714
2723
|
const shortMsg = message.length > 200 ? message.slice(0, 200) + "…" : message;
|
|
2715
2724
|
await sendTelegramMessage(
|
|
2716
|
-
|
|
2725
|
+
`:alert: bosun exception (${reason}): ${shortMsg}\n\nAttempting recovery (count=${failureCount}).`,
|
|
2717
2726
|
);
|
|
2718
2727
|
} catch {
|
|
2719
2728
|
/* suppress Telegram errors during failure handling */
|
|
@@ -2729,7 +2738,7 @@ async function handleMonitorFailure(reason, err) {
|
|
|
2729
2738
|
if (telegramToken && telegramChatId) {
|
|
2730
2739
|
try {
|
|
2731
2740
|
await sendTelegramMessage(
|
|
2732
|
-
|
|
2741
|
+
`:u1f6e0: bosun auto-fix applied. Restarting monitor.\n${fixResult.outcome}`,
|
|
2733
2742
|
);
|
|
2734
2743
|
} catch {
|
|
2735
2744
|
/* best effort */
|
|
@@ -2745,7 +2754,7 @@ async function handleMonitorFailure(reason, err) {
|
|
|
2745
2754
|
if (telegramToken && telegramChatId) {
|
|
2746
2755
|
try {
|
|
2747
2756
|
await sendTelegramMessage(
|
|
2748
|
-
|
|
2757
|
+
`:close: bosun entering safe mode after repeated failures (${failureCount} in 10m). Pausing restarts for ${pauseMin} minutes.`,
|
|
2749
2758
|
);
|
|
2750
2759
|
} catch {
|
|
2751
2760
|
/* best effort */
|
|
@@ -3039,7 +3048,7 @@ function triggerLoopFix(errorLine, repeatCount) {
|
|
|
3039
3048
|
} catch (err) {
|
|
3040
3049
|
console.warn(`[monitor] loop fix error: ${err.message || err}`);
|
|
3041
3050
|
if (telegramFn) {
|
|
3042
|
-
telegramFn(
|
|
3051
|
+
telegramFn(`:repeat: Loop fix crashed: ${err.message || err}`);
|
|
3043
3052
|
}
|
|
3044
3053
|
} finally {
|
|
3045
3054
|
loopFixInProgress = false;
|
|
@@ -3553,10 +3562,10 @@ function ensureAnomalyDetector() {
|
|
|
3553
3562
|
onAnomaly: wrapAnomalyCallback((anomaly) => {
|
|
3554
3563
|
const icon =
|
|
3555
3564
|
anomaly.severity === "CRITICAL"
|
|
3556
|
-
? "
|
|
3565
|
+
? ":dot:"
|
|
3557
3566
|
: anomaly.severity === "HIGH"
|
|
3558
|
-
? "
|
|
3559
|
-
: "
|
|
3567
|
+
? ":u1f7e0:"
|
|
3568
|
+
: ":dot:";
|
|
3560
3569
|
console.warn(
|
|
3561
3570
|
`[anomaly-detector] ${icon} ${anomaly.severity} ${anomaly.type} [${anomaly.shortId}]: ${anomaly.message}`,
|
|
3562
3571
|
);
|
|
@@ -3742,7 +3751,7 @@ function ensureVkLogStream() {
|
|
|
3742
3751
|
);
|
|
3743
3752
|
|
|
3744
3753
|
// Notify via Telegram
|
|
3745
|
-
const emoji = resolution.result.success ? "
|
|
3754
|
+
const emoji = resolution.result.success ? ":bot:" : ":alert:";
|
|
3746
3755
|
const status = resolution.result.success ? "resolved" : "failed";
|
|
3747
3756
|
const branch =
|
|
3748
3757
|
resolution.context.branch || `PR #${resolution.context.prNumber}`;
|
|
@@ -4729,7 +4738,7 @@ async function startFreshSession(workspaceId, prompt, taskId) {
|
|
|
4729
4738
|
}
|
|
4730
4739
|
|
|
4731
4740
|
console.log(
|
|
4732
|
-
`[monitor]
|
|
4741
|
+
`[monitor] :check: Fresh session started: ${session.id} (retry #${freshSessionCount})`,
|
|
4733
4742
|
);
|
|
4734
4743
|
|
|
4735
4744
|
// Connect the VK log stream to this session for real-time log capture
|
|
@@ -4798,7 +4807,7 @@ async function attemptFreshSessionRetry(reason, logTail) {
|
|
|
4798
4807
|
const taskLabel =
|
|
4799
4808
|
attemptInfo.task_title || attemptInfo.branch || "unknown";
|
|
4800
4809
|
void sendTelegramMessage(
|
|
4801
|
-
|
|
4810
|
+
`:refresh: Fresh session started for "${taskLabel}" (${reason}).\nNew session: ${result.sessionId}`,
|
|
4802
4811
|
);
|
|
4803
4812
|
}
|
|
4804
4813
|
return true;
|
|
@@ -4807,7 +4816,7 @@ async function attemptFreshSessionRetry(reason, logTail) {
|
|
|
4807
4816
|
console.warn(`[monitor] fresh session retry failed: ${result.reason}`);
|
|
4808
4817
|
if (telegramToken && telegramChatId) {
|
|
4809
4818
|
void sendTelegramMessage(
|
|
4810
|
-
|
|
4819
|
+
`:alert: Fresh session retry failed (${reason}): ${result.reason}`,
|
|
4811
4820
|
);
|
|
4812
4821
|
}
|
|
4813
4822
|
return false;
|
|
@@ -5279,7 +5288,7 @@ async function safeRecoverTask(taskId, taskTitle, reason) {
|
|
|
5279
5288
|
const success = await updateTaskStatus(taskId, "todo");
|
|
5280
5289
|
if (success) {
|
|
5281
5290
|
console.log(
|
|
5282
|
-
`[monitor]
|
|
5291
|
+
`[monitor] :repeat: Recovered "${taskTitle}" from ${localStatus || "inprogress"} → todo (${reason}) [${activeBackend} backend - VK status re-fetch skipped]`,
|
|
5283
5292
|
);
|
|
5284
5293
|
} else {
|
|
5285
5294
|
console.warn(
|
|
@@ -5348,11 +5357,11 @@ async function safeRecoverTask(taskId, taskTitle, reason) {
|
|
|
5348
5357
|
if (success) {
|
|
5349
5358
|
if (isInternal) {
|
|
5350
5359
|
console.log(
|
|
5351
|
-
`[monitor]
|
|
5360
|
+
`[monitor] :repeat: Recovered "${taskTitle}" from ${liveStatus} → todo (${reason}) [internal mode — VK session skipped]`,
|
|
5352
5361
|
);
|
|
5353
5362
|
} else {
|
|
5354
5363
|
console.log(
|
|
5355
|
-
`[monitor]
|
|
5364
|
+
`[monitor] :repeat: Recovered "${taskTitle}" from ${liveStatus} → todo (${reason})`,
|
|
5356
5365
|
);
|
|
5357
5366
|
}
|
|
5358
5367
|
}
|
|
@@ -6382,11 +6391,11 @@ async function checkMergedPRsAndUpdateTasks() {
|
|
|
6382
6391
|
completedTaskNames.push(task.title);
|
|
6383
6392
|
if (success) {
|
|
6384
6393
|
console.log(
|
|
6385
|
-
`[monitor]
|
|
6394
|
+
`[monitor] :check: Moved task "${task.title}" from ${taskStatus} → done`,
|
|
6386
6395
|
);
|
|
6387
6396
|
} else {
|
|
6388
6397
|
console.warn(
|
|
6389
|
-
`[monitor]
|
|
6398
|
+
`[monitor] :alert: VK update failed for "${task.title}" — cached anyway (PR is merged)`,
|
|
6390
6399
|
);
|
|
6391
6400
|
}
|
|
6392
6401
|
// ── Trigger downstream rebase for tasks on same upstream ──
|
|
@@ -6467,11 +6476,11 @@ async function checkMergedPRsAndUpdateTasks() {
|
|
|
6467
6476
|
completedTaskNames.push(task.title);
|
|
6468
6477
|
if (success) {
|
|
6469
6478
|
console.log(
|
|
6470
|
-
`[monitor]
|
|
6479
|
+
`[monitor] :check: Moved task "${task.title}" from ${taskStatus} → done`,
|
|
6471
6480
|
);
|
|
6472
6481
|
} else {
|
|
6473
6482
|
console.warn(
|
|
6474
|
-
`[monitor]
|
|
6483
|
+
`[monitor] :alert: VK update failed for "${task.title}" — cached anyway (branch is merged)`,
|
|
6475
6484
|
);
|
|
6476
6485
|
}
|
|
6477
6486
|
// ── Trigger downstream rebase for tasks on same upstream ──
|
|
@@ -6559,7 +6568,7 @@ async function checkMergedPRsAndUpdateTasks() {
|
|
|
6559
6568
|
const attempts = conflictResolutionAttempts.get(task.id) || 0;
|
|
6560
6569
|
if (attempts >= CONFLICT_MAX_ATTEMPTS) {
|
|
6561
6570
|
console.warn(
|
|
6562
|
-
`[monitor]
|
|
6571
|
+
`[monitor] :alert: Task "${task.title}" PR #${conflictCandidates[0].prNumber} conflict resolution exhausted (${attempts}/${CONFLICT_MAX_ATTEMPTS} attempts) — skipping`,
|
|
6563
6572
|
);
|
|
6564
6573
|
} else {
|
|
6565
6574
|
conflictResolutionAttempts.set(task.id, attempts + 1);
|
|
@@ -6581,11 +6590,11 @@ async function checkMergedPRsAndUpdateTasks() {
|
|
|
6581
6590
|
|
|
6582
6591
|
if (!sdkOnCooldown && !sdkExhausted) {
|
|
6583
6592
|
console.log(
|
|
6584
|
-
`[monitor]
|
|
6593
|
+
`[monitor] :alert: Task "${task.title}" PR #${cc.prNumber} has merge conflicts — launching SDK resolver (attempt ${shortId})`,
|
|
6585
6594
|
);
|
|
6586
6595
|
if (telegramToken && telegramChatId) {
|
|
6587
6596
|
void sendTelegramMessage(
|
|
6588
|
-
|
|
6597
|
+
`:git: PR #${cc.prNumber} for "${task.title}" has merge conflicts — launching SDK resolver (attempt ${shortId})`,
|
|
6589
6598
|
);
|
|
6590
6599
|
}
|
|
6591
6600
|
|
|
@@ -6635,23 +6644,23 @@ async function checkMergedPRsAndUpdateTasks() {
|
|
|
6635
6644
|
});
|
|
6636
6645
|
if (result.success) {
|
|
6637
6646
|
console.log(
|
|
6638
|
-
`[monitor]
|
|
6647
|
+
`[monitor] :check: SDK resolved conflicts for PR #${cc.prNumber} (${result.resolvedFiles.length} files)`,
|
|
6639
6648
|
);
|
|
6640
6649
|
clearDirtyTask(task.id);
|
|
6641
6650
|
clearSDKResolutionState(cc.branch);
|
|
6642
6651
|
conflictResolutionAttempts.delete(task.id); // Reset on success
|
|
6643
6652
|
if (telegramToken && telegramChatId) {
|
|
6644
6653
|
void sendTelegramMessage(
|
|
6645
|
-
|
|
6654
|
+
`:check: SDK resolved merge conflicts for PR #${cc.prNumber} "${task.title}" (${result.resolvedFiles.length} files)`,
|
|
6646
6655
|
);
|
|
6647
6656
|
}
|
|
6648
6657
|
} else {
|
|
6649
6658
|
console.warn(
|
|
6650
|
-
`[monitor]
|
|
6659
|
+
`[monitor] :close: SDK conflict resolution failed for PR #${cc.prNumber}: ${result.error}`,
|
|
6651
6660
|
);
|
|
6652
6661
|
if (telegramToken && telegramChatId) {
|
|
6653
6662
|
void sendTelegramMessage(
|
|
6654
|
-
|
|
6663
|
+
`:close: SDK conflict resolution failed for PR #${cc.prNumber} "${task.title}": ${result.error}\nFalling back to orchestrator.`,
|
|
6655
6664
|
);
|
|
6656
6665
|
}
|
|
6657
6666
|
conflictsTriggered++;
|
|
@@ -6669,7 +6678,7 @@ async function checkMergedPRsAndUpdateTasks() {
|
|
|
6669
6678
|
);
|
|
6670
6679
|
if (telegramToken && telegramChatId) {
|
|
6671
6680
|
void sendTelegramMessage(
|
|
6672
|
-
|
|
6681
|
+
`:git: PR #${cc.prNumber} for "${task.title}" has merge conflicts — no worktree, orchestrator will handle (attempt ${shortId})`,
|
|
6673
6682
|
);
|
|
6674
6683
|
}
|
|
6675
6684
|
conflictsTriggered++;
|
|
@@ -6680,11 +6689,11 @@ async function checkMergedPRsAndUpdateTasks() {
|
|
|
6680
6689
|
? "SDK attempts exhausted"
|
|
6681
6690
|
: "SDK on cooldown";
|
|
6682
6691
|
console.log(
|
|
6683
|
-
`[monitor]
|
|
6692
|
+
`[monitor] :alert: Task "${task.title}" PR #${cc.prNumber} has merge conflicts — ${reason}, deferring to orchestrator (attempt ${shortId})`,
|
|
6684
6693
|
);
|
|
6685
6694
|
if (telegramToken && telegramChatId) {
|
|
6686
6695
|
void sendTelegramMessage(
|
|
6687
|
-
|
|
6696
|
+
`:git: PR #${cc.prNumber} for "${task.title}" has merge conflicts — ${reason}, orchestrator will handle (attempt ${shortId})`,
|
|
6688
6697
|
);
|
|
6689
6698
|
}
|
|
6690
6699
|
conflictsTriggered++;
|
|
@@ -6713,7 +6722,7 @@ async function checkMergedPRsAndUpdateTasks() {
|
|
|
6713
6722
|
if (success) {
|
|
6714
6723
|
movedReviewCount++;
|
|
6715
6724
|
console.log(
|
|
6716
|
-
`[monitor]
|
|
6725
|
+
`[monitor] :check: Moved task "${task.title}" from ${taskStatus} → inreview`,
|
|
6717
6726
|
);
|
|
6718
6727
|
}
|
|
6719
6728
|
} else if (!hasOpenPR) {
|
|
@@ -6789,7 +6798,7 @@ async function checkMergedPRsAndUpdateTasks() {
|
|
|
6789
6798
|
if (movedCount <= 3) {
|
|
6790
6799
|
// Few tasks — list them individually
|
|
6791
6800
|
for (const name of completedTaskNames) {
|
|
6792
|
-
void sendTelegramMessage(
|
|
6801
|
+
void sendTelegramMessage(`:check: Task completed: "${name}"`);
|
|
6793
6802
|
}
|
|
6794
6803
|
} else {
|
|
6795
6804
|
// Many tasks — send a single summary to avoid spam
|
|
@@ -6799,7 +6808,7 @@ async function checkMergedPRsAndUpdateTasks() {
|
|
|
6799
6808
|
.join("\n");
|
|
6800
6809
|
const extra = movedCount > 5 ? `\n…and ${movedCount - 5} more` : "";
|
|
6801
6810
|
void sendTelegramMessage(
|
|
6802
|
-
|
|
6811
|
+
`:check: ${movedCount} tasks moved to done:\n${listed}${extra}`,
|
|
6803
6812
|
);
|
|
6804
6813
|
}
|
|
6805
6814
|
}
|
|
@@ -6827,7 +6836,7 @@ async function checkMergedPRsAndUpdateTasks() {
|
|
|
6827
6836
|
if (movedTodoCount <= 3) {
|
|
6828
6837
|
for (const name of recoveredTaskNames) {
|
|
6829
6838
|
void sendTelegramMessage(
|
|
6830
|
-
|
|
6839
|
+
`:repeat: Task recovered to todo (abandoned — no branch/PR): "${name}"`,
|
|
6831
6840
|
);
|
|
6832
6841
|
}
|
|
6833
6842
|
} else {
|
|
@@ -6838,7 +6847,7 @@ async function checkMergedPRsAndUpdateTasks() {
|
|
|
6838
6847
|
const extra =
|
|
6839
6848
|
movedTodoCount > 5 ? `\n…and ${movedTodoCount - 5} more` : "";
|
|
6840
6849
|
void sendTelegramMessage(
|
|
6841
|
-
|
|
6850
|
+
`:repeat: ${movedTodoCount} abandoned tasks recovered to todo:\n${listed}${extra}`,
|
|
6842
6851
|
);
|
|
6843
6852
|
}
|
|
6844
6853
|
}
|
|
@@ -7444,7 +7453,7 @@ async function checkEpicBranches(reason = "interval") {
|
|
|
7444
7453
|
null,
|
|
7445
7454
|
);
|
|
7446
7455
|
void sendTelegramMessage(
|
|
7447
|
-
|
|
7456
|
+
`:alert: Epic sync conflict on ${epicBranch} → ${DEFAULT_TARGET_BRANCH} (${reason})`,
|
|
7448
7457
|
);
|
|
7449
7458
|
}
|
|
7450
7459
|
continue;
|
|
@@ -7475,7 +7484,7 @@ async function checkEpicBranches(reason = "interval") {
|
|
|
7475
7484
|
prUrl: created.url,
|
|
7476
7485
|
});
|
|
7477
7486
|
void sendTelegramMessage(
|
|
7478
|
-
|
|
7487
|
+
`:workflow: Epic PR created for ${epicBranch} → ${DEFAULT_TARGET_BRANCH}\n${created.url}`,
|
|
7479
7488
|
);
|
|
7480
7489
|
} else if (created?.skipped) {
|
|
7481
7490
|
updateEpicMergeCache(cacheKey, {
|
|
@@ -7518,7 +7527,7 @@ async function checkEpicBranches(reason = "interval") {
|
|
|
7518
7527
|
prInfo,
|
|
7519
7528
|
);
|
|
7520
7529
|
void sendTelegramMessage(
|
|
7521
|
-
|
|
7530
|
+
`:alert: Epic PR conflicts for ${epicBranch} → ${DEFAULT_TARGET_BRANCH} (${prInfo.url || "no url"})`,
|
|
7522
7531
|
);
|
|
7523
7532
|
continue;
|
|
7524
7533
|
}
|
|
@@ -7541,7 +7550,7 @@ async function checkEpicBranches(reason = "interval") {
|
|
|
7541
7550
|
prInfo,
|
|
7542
7551
|
);
|
|
7543
7552
|
void sendTelegramMessage(
|
|
7544
|
-
|
|
7553
|
+
`:alert: Epic PR checks failing for ${epicBranch} → ${DEFAULT_TARGET_BRANCH} (${prInfo.url || "no url"})`,
|
|
7545
7554
|
);
|
|
7546
7555
|
continue;
|
|
7547
7556
|
}
|
|
@@ -7717,9 +7726,9 @@ async function checkAndMergeDependabotPRs() {
|
|
|
7717
7726
|
encoding: "utf8",
|
|
7718
7727
|
timeout: 30_000,
|
|
7719
7728
|
});
|
|
7720
|
-
console.log(`[dependabot]
|
|
7729
|
+
console.log(`[dependabot] :check: PR #${pr.number} merged: ${pr.title}`);
|
|
7721
7730
|
void sendTelegramMessage(
|
|
7722
|
-
|
|
7731
|
+
`:check: Auto-merged bot PR #${pr.number}: ${pr.title}`,
|
|
7723
7732
|
);
|
|
7724
7733
|
} catch (mergeErr) {
|
|
7725
7734
|
const errMsg = mergeErr.stderr || mergeErr.message || "";
|
|
@@ -7732,7 +7741,7 @@ async function checkAndMergeDependabotPRs() {
|
|
|
7732
7741
|
`[dependabot] PR #${pr.number}: auto-merge enabled, will merge when protection rules are met`,
|
|
7733
7742
|
);
|
|
7734
7743
|
void sendTelegramMessage(
|
|
7735
|
-
|
|
7744
|
+
`:refresh: Auto-merge enabled for bot PR #${pr.number}: ${pr.title}`,
|
|
7736
7745
|
);
|
|
7737
7746
|
}
|
|
7738
7747
|
}
|
|
@@ -8278,7 +8287,7 @@ async function rebaseDownstreamTasks(mergedUpstreamBranch, excludeAttemptId) {
|
|
|
8278
8287
|
const summary = `Downstream rebase after merge to ${mergedUpstreamBranch}: ${rebasedCount} rebased, ${failedCount} failed`;
|
|
8279
8288
|
console.log(`[${tag}] ${summary}`);
|
|
8280
8289
|
void sendTelegramMessage(
|
|
8281
|
-
|
|
8290
|
+
`:refresh: ${summary}\n${rebaseResults.map((r) => ` ${r.status === "success" ? "✓" : "✗"} ${r.taskTitle}`).join("\n")}`,
|
|
8282
8291
|
);
|
|
8283
8292
|
} else {
|
|
8284
8293
|
console.log(
|
|
@@ -8396,7 +8405,7 @@ async function actOnAssessment(ctx, decision) {
|
|
|
8396
8405
|
await updateTaskStatus(ctx.taskId, "todo");
|
|
8397
8406
|
}
|
|
8398
8407
|
void sendTelegramMessage(
|
|
8399
|
-
|
|
8408
|
+
`:star: Assessment: starting new attempt for "${ctx.taskTitle}" — ${decision.reason || ""}`,
|
|
8400
8409
|
);
|
|
8401
8410
|
break;
|
|
8402
8411
|
|
|
@@ -8415,7 +8424,7 @@ async function actOnAssessment(ctx, decision) {
|
|
|
8415
8424
|
case "manual_review":
|
|
8416
8425
|
console.log(`[${tag}] → manual review`);
|
|
8417
8426
|
void sendTelegramMessage(
|
|
8418
|
-
|
|
8427
|
+
`:eye: Assessment: manual review needed for "${ctx.taskTitle}" — ${decision.reason || ""}`,
|
|
8419
8428
|
);
|
|
8420
8429
|
break;
|
|
8421
8430
|
|
|
@@ -8425,7 +8434,7 @@ async function actOnAssessment(ctx, decision) {
|
|
|
8425
8434
|
await updateTaskStatus(ctx.taskId, "todo");
|
|
8426
8435
|
}
|
|
8427
8436
|
void sendTelegramMessage(
|
|
8428
|
-
|
|
8437
|
+
`:ban: Assessment: closing and replanning "${ctx.taskTitle}" — ${decision.reason || ""}`,
|
|
8429
8438
|
);
|
|
8430
8439
|
break;
|
|
8431
8440
|
|
|
@@ -8866,7 +8875,7 @@ async function smartPRFlow(attemptId, shortId, status) {
|
|
|
8866
8875
|
? ` Examples: ${verify.sampleTitles.join(", ")}`
|
|
8867
8876
|
: "";
|
|
8868
8877
|
void sendTelegramMessage(
|
|
8869
|
-
|
|
8878
|
+
`:check: Task planner verified: ${verify.createdCount} new task(s) detected.${suffix}`,
|
|
8870
8879
|
);
|
|
8871
8880
|
}
|
|
8872
8881
|
return;
|
|
@@ -8878,7 +8887,7 @@ async function smartPRFlow(attemptId, shortId, status) {
|
|
|
8878
8887
|
await archiveAttempt(attemptId);
|
|
8879
8888
|
if (telegramToken && telegramChatId) {
|
|
8880
8889
|
void sendTelegramMessage(
|
|
8881
|
-
"
|
|
8890
|
+
":alert: Task planner incomplete: no new backlog tasks detected. Returned to todo.",
|
|
8882
8891
|
);
|
|
8883
8892
|
}
|
|
8884
8893
|
return;
|
|
@@ -8920,7 +8929,7 @@ async function smartPRFlow(attemptId, shortId, status) {
|
|
|
8920
8929
|
await archiveAttempt(attemptId);
|
|
8921
8930
|
if (telegramToken && telegramChatId) {
|
|
8922
8931
|
void sendTelegramMessage(
|
|
8923
|
-
|
|
8932
|
+
`:trash: Archived attempt ${shortId}: no commits, no changes (status=${status}). Task will be reattempted.`,
|
|
8924
8933
|
);
|
|
8925
8934
|
}
|
|
8926
8935
|
return;
|
|
@@ -8985,7 +8994,7 @@ async function smartPRFlow(attemptId, shortId, status) {
|
|
|
8985
8994
|
? "Fresh session started for reattempt."
|
|
8986
8995
|
: "Will reattempt on next cycle.";
|
|
8987
8996
|
void sendTelegramMessage(
|
|
8988
|
-
|
|
8997
|
+
`:trash: Archived stale attempt ${shortId} after failed rebase. ${action}`,
|
|
8989
8998
|
);
|
|
8990
8999
|
}
|
|
8991
9000
|
return;
|
|
@@ -9083,7 +9092,7 @@ Return a short summary of what you did and any files that needed manual resoluti
|
|
|
9083
9092
|
);
|
|
9084
9093
|
if (telegramToken && telegramChatId) {
|
|
9085
9094
|
void sendTelegramMessage(
|
|
9086
|
-
|
|
9095
|
+
`:check: Codex resolved rebase conflicts for ${shortId}. Log: ${logPath}`,
|
|
9087
9096
|
);
|
|
9088
9097
|
}
|
|
9089
9098
|
return;
|
|
@@ -9093,7 +9102,7 @@ Return a short summary of what you did and any files that needed manual resoluti
|
|
|
9093
9102
|
);
|
|
9094
9103
|
if (telegramToken && telegramChatId) {
|
|
9095
9104
|
void sendTelegramMessage(
|
|
9096
|
-
|
|
9105
|
+
`:alert: Codex failed to resolve conflicts for ${shortId}. Log: ${logPath}`,
|
|
9097
9106
|
);
|
|
9098
9107
|
}
|
|
9099
9108
|
}
|
|
@@ -9103,7 +9112,7 @@ Return a short summary of what you did and any files that needed manual resoluti
|
|
|
9103
9112
|
);
|
|
9104
9113
|
if (telegramToken && telegramChatId) {
|
|
9105
9114
|
void sendTelegramMessage(
|
|
9106
|
-
|
|
9115
|
+
`:alert: Attempt ${shortId} has unresolvable rebase conflicts: ${files.join(", ")}`,
|
|
9107
9116
|
);
|
|
9108
9117
|
}
|
|
9109
9118
|
if (primaryAgentReady) {
|
|
@@ -9159,7 +9168,7 @@ Return a short summary of what you did and any files that needed manual resoluti
|
|
|
9159
9168
|
);
|
|
9160
9169
|
if (telegramToken && telegramChatId) {
|
|
9161
9170
|
void sendTelegramMessage(
|
|
9162
|
-
|
|
9171
|
+
`:alert: Auto-PR skipped for ${shortId}: existing PR #${existingPr.number} (${state}) already linked to ${branchName}.`,
|
|
9163
9172
|
);
|
|
9164
9173
|
}
|
|
9165
9174
|
return;
|
|
@@ -9184,7 +9193,7 @@ Return a short summary of what you did and any files that needed manual resoluti
|
|
|
9184
9193
|
);
|
|
9185
9194
|
if (telegramToken && telegramChatId) {
|
|
9186
9195
|
void sendTelegramMessage(
|
|
9187
|
-
|
|
9196
|
+
`:check: Auto-created PR for ${shortId}${prUrl ? ": " + prUrl : ""}`,
|
|
9188
9197
|
);
|
|
9189
9198
|
}
|
|
9190
9199
|
|
|
@@ -9221,7 +9230,7 @@ Return a short summary of what you did and any files that needed manual resoluti
|
|
|
9221
9230
|
);
|
|
9222
9231
|
if (telegramToken && telegramChatId) {
|
|
9223
9232
|
void sendTelegramMessage(
|
|
9224
|
-
|
|
9233
|
+
`:alert: Auto-PR for ${shortId} failed: repo_id missing. Check VK_BASE_URL/VK_REPO_ID.`,
|
|
9225
9234
|
);
|
|
9226
9235
|
}
|
|
9227
9236
|
return;
|
|
@@ -9234,7 +9243,7 @@ Return a short summary of what you did and any files that needed manual resoluti
|
|
|
9234
9243
|
);
|
|
9235
9244
|
if (telegramToken && telegramChatId) {
|
|
9236
9245
|
void sendTelegramMessage(
|
|
9237
|
-
|
|
9246
|
+
`:alert: Auto-PR for ${shortId} fast-failed (${elapsed}ms) — likely worktree issue. Prompting agent.`,
|
|
9238
9247
|
);
|
|
9239
9248
|
}
|
|
9240
9249
|
if (primaryAgentReady) {
|
|
@@ -9257,7 +9266,7 @@ Return a short summary of what you did and any files that needed manual resoluti
|
|
|
9257
9266
|
);
|
|
9258
9267
|
if (telegramToken && telegramChatId) {
|
|
9259
9268
|
void sendTelegramMessage(
|
|
9260
|
-
|
|
9269
|
+
`:alert: Auto-PR for ${shortId} failed after ${Math.round(elapsed / 1000)}s (prepush hooks). Prompting agent to fix.`,
|
|
9261
9270
|
);
|
|
9262
9271
|
}
|
|
9263
9272
|
if (primaryAgentReady) {
|
|
@@ -9876,7 +9885,10 @@ function buildPlannerTaskDescription({
|
|
|
9876
9885
|
" its dedicated branch and integrates upstream changes continuously.",
|
|
9877
9886
|
" Examples: `feat(veid):` → `origin/veid`, `fix(market):` → `origin/market`.",
|
|
9878
9887
|
" Do NOT set base_branch for cross-cutting tasks that modify many modules.",
|
|
9879
|
-
"8. If a task should target a non-default epic/base branch for other reasons, include `base_branch` in the JSON task object.",
|
|
9888
|
+
"8. If a task should target a non-default epic/base branch for other reasons, include `base_branch` in the JSON task object.",
|
|
9889
|
+
"9. Output MUST be exactly one fenced ```json code block with shape { \"tasks\": [...] } and no surrounding prose.",
|
|
9890
|
+
"10. Each task object must include title, description, implementation_steps, acceptance_criteria, verification.",
|
|
9891
|
+
"11. Do not output placeholder tasks. If uncertain, reduce scope but keep tasks executable.",].join("\n");
|
|
9880
9892
|
}
|
|
9881
9893
|
|
|
9882
9894
|
function normalizePlannerTitleForComparison(title) {
|
|
@@ -10100,7 +10112,7 @@ function buildTaskPlannerStatusText(plannerState, reason = "interval") {
|
|
|
10100
10112
|
? formatElapsedMs(now - Date.parse(plannerState.last_success_at))
|
|
10101
10113
|
: "never";
|
|
10102
10114
|
return [
|
|
10103
|
-
"
|
|
10115
|
+
":clipboard: Codex-Task-Planner Update",
|
|
10104
10116
|
`- Reason: ${reason}`,
|
|
10105
10117
|
`- Planner mode: ${plannerMode}`,
|
|
10106
10118
|
`- Trigger in progress: ${plannerTriggered ? "yes" : "no"}`,
|
|
@@ -10224,7 +10236,7 @@ async function sendTelegramMessage(text, options = {}) {
|
|
|
10224
10236
|
let priority = 4; // default: info
|
|
10225
10237
|
let category = "general";
|
|
10226
10238
|
|
|
10227
|
-
// Positive signals override negative keyword matches — a "
|
|
10239
|
+
// Positive signals override negative keyword matches — a ":check: Task completed"
|
|
10228
10240
|
// message should never be classified as an error even when the task title
|
|
10229
10241
|
// happens to contain words like "error" or "failed".
|
|
10230
10242
|
// Orchestrator periodic updates contain counter labels like "Failed: 0" and
|
|
@@ -10232,7 +10244,7 @@ async function sendTelegramMessage(text, options = {}) {
|
|
|
10232
10244
|
// Status updates (planner, monitor-monitor) contain "Last error: none" which
|
|
10233
10245
|
// is informational, not an actual error.
|
|
10234
10246
|
const isPositive =
|
|
10235
|
-
textLower.includes("
|
|
10247
|
+
textLower.includes(":check:") ||
|
|
10236
10248
|
textLower.includes("task completed") ||
|
|
10237
10249
|
textLower.includes("branch merged") ||
|
|
10238
10250
|
textLower.includes("pr merged") ||
|
|
@@ -10245,7 +10257,7 @@ async function sendTelegramMessage(text, options = {}) {
|
|
|
10245
10257
|
!isPositive &&
|
|
10246
10258
|
(textLower.includes("fatal") ||
|
|
10247
10259
|
textLower.includes("critical") ||
|
|
10248
|
-
textLower.includes("
|
|
10260
|
+
textLower.includes(":zap:"))
|
|
10249
10261
|
) {
|
|
10250
10262
|
priority = 1;
|
|
10251
10263
|
category = "critical";
|
|
@@ -10255,7 +10267,7 @@ async function sendTelegramMessage(text, options = {}) {
|
|
|
10255
10267
|
!isPositive &&
|
|
10256
10268
|
(textLower.includes("error") ||
|
|
10257
10269
|
textLower.includes("failed") ||
|
|
10258
|
-
textLower.includes("
|
|
10270
|
+
textLower.includes(":close:") ||
|
|
10259
10271
|
textLower.includes("auto-fix gave up"))
|
|
10260
10272
|
) {
|
|
10261
10273
|
priority = 2;
|
|
@@ -10264,7 +10276,7 @@ async function sendTelegramMessage(text, options = {}) {
|
|
|
10264
10276
|
// Priority 3: Warnings
|
|
10265
10277
|
else if (
|
|
10266
10278
|
!isPositive &&
|
|
10267
|
-
(textLower.includes("warning") || textLower.includes("
|
|
10279
|
+
(textLower.includes("warning") || textLower.includes(":alert:"))
|
|
10268
10280
|
) {
|
|
10269
10281
|
priority = 3;
|
|
10270
10282
|
category = "warning";
|
|
@@ -10346,7 +10358,7 @@ async function maybeSendWeeklyReport(nowInput = new Date()) {
|
|
|
10346
10358
|
} catch (err) {
|
|
10347
10359
|
console.warn(`[monitor] weekly report generation failed: ${err?.message || err}`);
|
|
10348
10360
|
await sendTelegramMessage(
|
|
10349
|
-
|
|
10361
|
+
`:alert: Weekly report failed: ${err?.message || err}`,
|
|
10350
10362
|
{ dedupKey: "weekly-report:failed", exactDedup: true },
|
|
10351
10363
|
);
|
|
10352
10364
|
}
|
|
@@ -10357,12 +10369,12 @@ globalThis.__bosunNotifyAnomaly = (anomaly) => {
|
|
|
10357
10369
|
if (!telegramToken || !telegramChatId) return;
|
|
10358
10370
|
const icon =
|
|
10359
10371
|
anomaly.severity === "CRITICAL"
|
|
10360
|
-
? "
|
|
10372
|
+
? ":dot:"
|
|
10361
10373
|
: anomaly.severity === "HIGH"
|
|
10362
|
-
? "
|
|
10374
|
+
? ":u1f7e0:"
|
|
10363
10375
|
: anomaly.severity === "MEDIUM"
|
|
10364
|
-
? "
|
|
10365
|
-
: "
|
|
10376
|
+
? ":dot:"
|
|
10377
|
+
: ":dot:";
|
|
10366
10378
|
const lines = [
|
|
10367
10379
|
`${icon} Internal Anomaly: ${anomaly.type}`,
|
|
10368
10380
|
`Attempt: ${anomaly.processId || anomaly.shortId || "unknown"}`,
|
|
@@ -10963,7 +10975,7 @@ async function checkStatusMilestones() {
|
|
|
10963
10975
|
if (!allCompleteNotified) {
|
|
10964
10976
|
allCompleteNotified = true;
|
|
10965
10977
|
await sendTelegramMessage(
|
|
10966
|
-
|
|
10978
|
+
`:server: Fleet entering maintenance mode: ${maintenance.reason}`,
|
|
10967
10979
|
);
|
|
10968
10980
|
}
|
|
10969
10981
|
return;
|
|
@@ -11319,7 +11331,7 @@ async function triggerTaskPlanner(
|
|
|
11319
11331
|
);
|
|
11320
11332
|
if (notify) {
|
|
11321
11333
|
await sendTelegramMessage(
|
|
11322
|
-
|
|
11334
|
+
`:alert: Task planner kanban path failed on ${backend}; using codex fallback.\nReason: ${message}`,
|
|
11323
11335
|
);
|
|
11324
11336
|
}
|
|
11325
11337
|
result = await triggerTaskPlannerViaCodex(reason, details, {
|
|
@@ -11355,7 +11367,7 @@ async function triggerTaskPlanner(
|
|
|
11355
11367
|
);
|
|
11356
11368
|
if (notify) {
|
|
11357
11369
|
await sendTelegramMessage(
|
|
11358
|
-
|
|
11370
|
+
`:alert: Task planner codex path failed; trying kanban fallback.\nReason: ${codexMessage}`,
|
|
11359
11371
|
);
|
|
11360
11372
|
}
|
|
11361
11373
|
|
|
@@ -11472,7 +11484,7 @@ async function triggerTaskPlannerViaKanban(
|
|
|
11472
11484
|
if (notify) {
|
|
11473
11485
|
const suffix = taskUrl ? `\n${taskUrl}` : "";
|
|
11474
11486
|
await sendTelegramMessage(
|
|
11475
|
-
|
|
11487
|
+
`:clipboard: Task planner skipped — existing planning task found.${suffix}`,
|
|
11476
11488
|
);
|
|
11477
11489
|
}
|
|
11478
11490
|
await updatePlannerState({
|
|
@@ -11534,7 +11546,7 @@ async function triggerTaskPlannerViaKanban(
|
|
|
11534
11546
|
if (notify) {
|
|
11535
11547
|
const suffix = createdUrl ? `\n${createdUrl}` : "";
|
|
11536
11548
|
await sendTelegramMessage(
|
|
11537
|
-
|
|
11549
|
+
`:clipboard: Task planner: created task for next phase planning (${reason}).${suffix}`,
|
|
11538
11550
|
);
|
|
11539
11551
|
}
|
|
11540
11552
|
return {
|
|
@@ -11662,6 +11674,12 @@ async function triggerTaskPlannerViaCodex(
|
|
|
11662
11674
|
})),
|
|
11663
11675
|
);
|
|
11664
11676
|
|
|
11677
|
+
if (created.length === 0) {
|
|
11678
|
+
throw new Error(
|
|
11679
|
+
`Task planner parsed ${parsedTasks.length} tasks but created 0 tasks after dedup/materialization`,
|
|
11680
|
+
);
|
|
11681
|
+
}
|
|
11682
|
+
|
|
11665
11683
|
console.log(`[monitor] task planner output saved: ${outPath}`);
|
|
11666
11684
|
console.log(
|
|
11667
11685
|
`[monitor] task planner artifact saved: ${artifactPath} (parsed=${parsedTasks.length}, created=${created.length}, skipped=${skipped.length})`,
|
|
@@ -11674,7 +11692,7 @@ async function triggerTaskPlannerViaCodex(
|
|
|
11674
11692
|
});
|
|
11675
11693
|
if (notify) {
|
|
11676
11694
|
await sendTelegramMessage(
|
|
11677
|
-
|
|
11695
|
+
`:clipboard: Task planner run completed (${reason || "manual"}). Created ${created.length}/${parsedTasks.length} tasks.${
|
|
11678
11696
|
skipped.length > 0
|
|
11679
11697
|
? ` Skipped ${skipped.length} duplicates/failed.`
|
|
11680
11698
|
: ""
|
|
@@ -11911,7 +11929,7 @@ ${logTail}
|
|
|
11911
11929
|
if (telegramToken && telegramChatId) {
|
|
11912
11930
|
const summary = analysisText.slice(0, 500).replace(/\n{3,}/g, "\n\n");
|
|
11913
11931
|
void sendTelegramMessage(
|
|
11914
|
-
|
|
11932
|
+
`:search: Codex Analysis Result (${reason}):\n${summary}${analysisText.length > 500 ? "\n...(truncated)" : ""}`,
|
|
11915
11933
|
);
|
|
11916
11934
|
}
|
|
11917
11935
|
} catch (err) {
|
|
@@ -11930,7 +11948,7 @@ ${logTail}
|
|
|
11930
11948
|
if (telegramToken && telegramChatId) {
|
|
11931
11949
|
const summary = analysisText.slice(0, 500).replace(/\n{3,}/g, "\n\n");
|
|
11932
11950
|
void sendTelegramMessage(
|
|
11933
|
-
|
|
11951
|
+
`:search: Codex Analysis Result (${reason}):\n${summary}${analysisText.length > 500 ? "\n...(truncated)" : ""}`,
|
|
11934
11952
|
);
|
|
11935
11953
|
}
|
|
11936
11954
|
} catch (fallbackErr) {
|
|
@@ -11942,7 +11960,7 @@ ${logTail}
|
|
|
11942
11960
|
"utf8",
|
|
11943
11961
|
);
|
|
11944
11962
|
if (telegramToken && telegramChatId) {
|
|
11945
|
-
void sendTelegramMessage(
|
|
11963
|
+
void sendTelegramMessage(`:search: Codex Analysis Failed: ${message}`);
|
|
11946
11964
|
}
|
|
11947
11965
|
}
|
|
11948
11966
|
}
|
|
@@ -12069,7 +12087,7 @@ async function handleExit(code, signal, logPath) {
|
|
|
12069
12087
|
);
|
|
12070
12088
|
if (telegramToken && telegramChatId) {
|
|
12071
12089
|
void sendTelegramMessage(
|
|
12072
|
-
|
|
12090
|
+
`:clock: Mutex held — backing off ${exitState.backoffMs / 1000}s before retry`,
|
|
12073
12091
|
);
|
|
12074
12092
|
}
|
|
12075
12093
|
restartCount += 1;
|
|
@@ -12257,7 +12275,7 @@ async function handleExit(code, signal, logPath) {
|
|
|
12257
12275
|
}
|
|
12258
12276
|
if (telegramToken && telegramChatId) {
|
|
12259
12277
|
void sendTelegramMessage(
|
|
12260
|
-
|
|
12278
|
+
`:close: Crash loop detected (${restartCountNow} exits in 5m). Pausing orchestrator restarts for ${pauseMin} minutes. Background fix running.`,
|
|
12261
12279
|
);
|
|
12262
12280
|
}
|
|
12263
12281
|
// ── Background crash-loop fix: runs while orchestrator is paused ──
|
|
@@ -12277,7 +12295,7 @@ async function handleExit(code, signal, logPath) {
|
|
|
12277
12295
|
);
|
|
12278
12296
|
if (telegramToken && telegramChatId) {
|
|
12279
12297
|
void sendTelegramMessage(
|
|
12280
|
-
|
|
12298
|
+
`:u1f6e0: Crash-loop fix applied. File watcher will restart orchestrator.\n${fixResult.outcome}`,
|
|
12281
12299
|
);
|
|
12282
12300
|
}
|
|
12283
12301
|
} else {
|
|
@@ -12291,11 +12309,11 @@ async function handleExit(code, signal, logPath) {
|
|
|
12291
12309
|
);
|
|
12292
12310
|
if (freshStarted && telegramToken && telegramChatId) {
|
|
12293
12311
|
void sendTelegramMessage(
|
|
12294
|
-
|
|
12312
|
+
`:refresh: Crash-loop fix failed but fresh session started. New agent will retry.`,
|
|
12295
12313
|
);
|
|
12296
12314
|
} else if (!freshStarted && telegramToken && telegramChatId) {
|
|
12297
12315
|
void sendTelegramMessage(
|
|
12298
|
-
|
|
12316
|
+
`:alert: Crash-loop fix failed: ${fixResult.outcome}. Orchestrator will resume after ${pauseMin}m pause.`,
|
|
12299
12317
|
);
|
|
12300
12318
|
}
|
|
12301
12319
|
}
|
|
@@ -12606,7 +12624,7 @@ function buildMonitorMonitorStatusText(
|
|
|
12606
12624
|
);
|
|
12607
12625
|
|
|
12608
12626
|
const lines = [
|
|
12609
|
-
"
|
|
12627
|
+
":server: Bosun-Monitor Update",
|
|
12610
12628
|
`- Reason: ${reason}`,
|
|
12611
12629
|
`- Running: ${monitorMonitor.running ? "yes" : "no"}`,
|
|
12612
12630
|
`- Current SDK: ${currentSdk}`,
|
|
@@ -13420,7 +13438,7 @@ async function runMonitorMonitorCycle({
|
|
|
13420
13438
|
rotateMonitorSdk("prepare next cycle");
|
|
13421
13439
|
}
|
|
13422
13440
|
void notify?.(
|
|
13423
|
-
|
|
13441
|
+
`:alert: Monitor-Monitor failed (${sdk}): ${String(errMsg).slice(0, 240)}`,
|
|
13424
13442
|
3,
|
|
13425
13443
|
{ dedupKey: "monitor-monitor-failed" },
|
|
13426
13444
|
);
|
|
@@ -13439,7 +13457,7 @@ async function runMonitorMonitorCycle({
|
|
|
13439
13457
|
monitorMonitor.lastError = errMsg;
|
|
13440
13458
|
console.error(`[monitor-monitor] uncaught exception via ${sdk}: ${errMsg}`);
|
|
13441
13459
|
void notify?.(
|
|
13442
|
-
|
|
13460
|
+
`:alert: Monitor-Monitor exception (${sdk}): ${errMsg.slice(0, 240)}`,
|
|
13443
13461
|
3,
|
|
13444
13462
|
{ dedupKey: "monitor-monitor-exception" },
|
|
13445
13463
|
);
|
|
@@ -13733,7 +13751,7 @@ async function startProcess() {
|
|
|
13733
13751
|
);
|
|
13734
13752
|
if (telegramToken && telegramChatId) {
|
|
13735
13753
|
void sendTelegramMessage(
|
|
13736
|
-
|
|
13754
|
+
`:close: Orchestrator script not found: ${scriptPath}\nSet ORCHESTRATOR_SCRIPT to a valid path.`,
|
|
13737
13755
|
);
|
|
13738
13756
|
}
|
|
13739
13757
|
return;
|
|
@@ -13766,7 +13784,7 @@ async function startProcess() {
|
|
|
13766
13784
|
);
|
|
13767
13785
|
if (telegramToken && telegramChatId) {
|
|
13768
13786
|
void sendTelegramMessage(
|
|
13769
|
-
|
|
13787
|
+
`:close: .ps1 orchestrator selected, but PowerShell runtime is unavailable (${pwshLabel}).\n` +
|
|
13770
13788
|
`Install PowerShell 7+ or set PWSH_PATH to a valid executable path. ` +
|
|
13771
13789
|
`Pausing restarts for ${pauseMin} minute(s).`,
|
|
13772
13790
|
);
|
|
@@ -13795,7 +13813,7 @@ async function startProcess() {
|
|
|
13795
13813
|
);
|
|
13796
13814
|
if (telegramToken && telegramChatId) {
|
|
13797
13815
|
void sendTelegramMessage(
|
|
13798
|
-
"
|
|
13816
|
+
":close: shell-mode orchestrator selected (.sh), but bash/sh is missing on PATH.",
|
|
13799
13817
|
);
|
|
13800
13818
|
}
|
|
13801
13819
|
return;
|
|
@@ -14710,7 +14728,7 @@ async function reloadConfig(reason) {
|
|
|
14710
14728
|
if (telegramToken && telegramChatId) {
|
|
14711
14729
|
try {
|
|
14712
14730
|
await sendTelegramMessage(
|
|
14713
|
-
|
|
14731
|
+
`:refresh: .env reloaded (${reason}). Runtime config updated.`,
|
|
14714
14732
|
{ dedupKey: "env-reload" },
|
|
14715
14733
|
);
|
|
14716
14734
|
} catch {
|
|
@@ -15486,7 +15504,7 @@ try {
|
|
|
15486
15504
|
|
|
15487
15505
|
if (isExecutorDisabled()) {
|
|
15488
15506
|
console.log(
|
|
15489
|
-
`[monitor]
|
|
15507
|
+
`[monitor] :ban: task execution DISABLED (EXECUTOR_MODE=${executorMode}) — no tasks will be executed`,
|
|
15490
15508
|
);
|
|
15491
15509
|
} else if (executorMode === "internal" || executorMode === "hybrid") {
|
|
15492
15510
|
// Start internal executor
|
|
@@ -15514,7 +15532,7 @@ if (isExecutorDisabled()) {
|
|
|
15514
15532
|
: "n/a";
|
|
15515
15533
|
const taskId = String(task?.id || task?.task_id || "").trim();
|
|
15516
15534
|
console.log(
|
|
15517
|
-
`[task-executor]
|
|
15535
|
+
`[task-executor] :rocket: started: "${task.title}" (${slot.sdk}) agent=${agentId} branch=${slot.branch} worktree=${slot.worktreePath || "(pending)"}`,
|
|
15518
15536
|
);
|
|
15519
15537
|
if (agentEventBus) agentEventBus.onTaskStarted(task, slot);
|
|
15520
15538
|
if (taskId) {
|
|
@@ -15574,8 +15592,8 @@ if (isExecutorDisabled()) {
|
|
|
15574
15592
|
).trim() || null;
|
|
15575
15593
|
console.log(
|
|
15576
15594
|
finalizationFailed
|
|
15577
|
-
? `[task-executor]
|
|
15578
|
-
: `[task-executor]
|
|
15595
|
+
? `[task-executor] :alert: completed without finalization: "${task.title}" (${result.attempts} attempt(s), reason=${result?.finalizationReason || "unknown"})`
|
|
15596
|
+
: `[task-executor] :check: completed: "${task.title}" (${result.attempts} attempt(s))`,
|
|
15579
15597
|
);
|
|
15580
15598
|
if (!finalizationFailed && agentEventBus) {
|
|
15581
15599
|
agentEventBus.onTaskCompleted(task, result);
|
|
@@ -15660,7 +15678,7 @@ if (isExecutorDisabled()) {
|
|
|
15660
15678
|
const attempts =
|
|
15661
15679
|
Number(err?.attempts || 0) > 0 ? Number(err.attempts) : null;
|
|
15662
15680
|
console.warn(
|
|
15663
|
-
`[task-executor]
|
|
15681
|
+
`[task-executor] :close: failed: "${task.title}" — ${formatMonitorError(err)}`,
|
|
15664
15682
|
);
|
|
15665
15683
|
if (agentEventBus) agentEventBus.onTaskFailed(task, err);
|
|
15666
15684
|
if (taskId) {
|
|
@@ -16074,7 +16092,7 @@ if (isExecutorDisabled()) {
|
|
|
16074
16092
|
telegramToken && telegramChatId
|
|
16075
16093
|
? (event) =>
|
|
16076
16094
|
sendTelegramMessage(
|
|
16077
|
-
|
|
16095
|
+
`:alert: Project sync alert: ${event?.message || "unknown"}`,
|
|
16078
16096
|
)
|
|
16079
16097
|
: null,
|
|
16080
16098
|
failureAlertThreshold:
|
|
@@ -16132,7 +16150,7 @@ startMonitorMonitorSupervisor();
|
|
|
16132
16150
|
startTaskPlannerStatusLoop();
|
|
16133
16151
|
restartGitHubReconciler();
|
|
16134
16152
|
|
|
16135
|
-
// ── Two-way Telegram
|
|
16153
|
+
// ── Two-way Telegram :workflow: primary agent ────────────────────────────────────────
|
|
16136
16154
|
injectMonitorFunctions({
|
|
16137
16155
|
sendTelegramMessage,
|
|
16138
16156
|
readStatusData,
|