bosun 0.26.3
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 +918 -0
- package/LICENSE +190 -0
- package/README.md +98 -0
- package/agent-endpoint.mjs +918 -0
- package/agent-hook-bridge.mjs +230 -0
- package/agent-hooks.mjs +1188 -0
- package/agent-pool.mjs +2403 -0
- package/agent-prompts.mjs +689 -0
- package/agent-sdk.mjs +141 -0
- package/anomaly-detector.mjs +1195 -0
- package/autofix.mjs +1294 -0
- package/bosun.config.example.json +115 -0
- package/bosun.schema.json +465 -0
- package/claude-shell.mjs +708 -0
- package/cli.mjs +1028 -0
- package/codex-config.mjs +1274 -0
- package/codex-model-profiles.mjs +135 -0
- package/codex-shell.mjs +762 -0
- package/compat.mjs +286 -0
- package/config-doctor.mjs +613 -0
- package/config.mjs +1724 -0
- package/conflict-resolver.mjs +248 -0
- package/container-runner.mjs +450 -0
- package/copilot-shell.mjs +827 -0
- package/daemon-restart-policy.mjs +56 -0
- package/diff-stats.mjs +282 -0
- package/error-detector.mjs +829 -0
- package/fetch-runtime.mjs +34 -0
- package/fleet-coordinator.mjs +838 -0
- package/get-telegram-chat-id.mjs +71 -0
- package/git-safety.mjs +170 -0
- package/github-reconciler.mjs +403 -0
- package/hook-profiles.mjs +651 -0
- package/kanban-adapter.mjs +4491 -0
- package/lib/logger.mjs +645 -0
- package/maintenance.mjs +828 -0
- package/merge-strategy.mjs +1171 -0
- package/monitor.mjs +12237 -0
- package/package.json +209 -0
- package/postinstall.mjs +187 -0
- package/pr-cleanup-daemon.mjs +978 -0
- package/preflight.mjs +408 -0
- package/prepublish-check.mjs +90 -0
- package/presence.mjs +328 -0
- package/primary-agent.mjs +290 -0
- package/publish.mjs +241 -0
- package/repo-root.mjs +29 -0
- package/restart-controller.mjs +100 -0
- package/review-agent.mjs +557 -0
- package/rotate-agent-logs.sh +133 -0
- package/sdk-conflict-resolver.mjs +973 -0
- package/session-tracker.mjs +880 -0
- package/setup.mjs +3946 -0
- package/shared-knowledge.mjs +410 -0
- package/shared-state-manager.mjs +841 -0
- package/shared-workspace-cli.mjs +199 -0
- package/shared-workspace-registry.mjs +537 -0
- package/shared-workspaces.json +18 -0
- package/startup-service.mjs +1070 -0
- package/sync-engine.mjs +1063 -0
- package/task-archiver.mjs +801 -0
- package/task-assessment.mjs +550 -0
- package/task-claims.mjs +924 -0
- package/task-complexity.mjs +581 -0
- package/task-executor.mjs +5111 -0
- package/task-store.mjs +753 -0
- package/telegram-bot.mjs +9683 -0
- package/telegram-sentinel.mjs +2010 -0
- package/ui/app.js +867 -0
- package/ui/app.legacy.js +1464 -0
- package/ui/app.monolith.js +2488 -0
- package/ui/components/charts.js +226 -0
- package/ui/components/chat-view.js +567 -0
- package/ui/components/command-palette.js +587 -0
- package/ui/components/diff-viewer.js +190 -0
- package/ui/components/forms.js +357 -0
- package/ui/components/kanban-board.js +451 -0
- package/ui/components/session-list.js +305 -0
- package/ui/components/shared.js +525 -0
- package/ui/demo.html +640 -0
- package/ui/index.html +70 -0
- package/ui/modules/api.js +297 -0
- package/ui/modules/icons.js +461 -0
- package/ui/modules/router.js +81 -0
- package/ui/modules/settings-schema.js +261 -0
- package/ui/modules/state.js +679 -0
- package/ui/modules/telegram.js +331 -0
- package/ui/modules/utils.js +270 -0
- package/ui/styles/animations.css +140 -0
- package/ui/styles/base.css +98 -0
- package/ui/styles/components.css +2032 -0
- package/ui/styles/kanban.css +286 -0
- package/ui/styles/layout.css +810 -0
- package/ui/styles/sessions.css +841 -0
- package/ui/styles/variables.css +188 -0
- package/ui/styles.css +141 -0
- package/ui/styles.monolith.css +1046 -0
- package/ui/tabs/agents.js +1417 -0
- package/ui/tabs/chat.js +75 -0
- package/ui/tabs/control.js +892 -0
- package/ui/tabs/dashboard.js +515 -0
- package/ui/tabs/infra.js +537 -0
- package/ui/tabs/logs.js +783 -0
- package/ui/tabs/settings.js +1509 -0
- package/ui/tabs/tasks.js +1385 -0
- package/ui-server.mjs +4084 -0
- package/update-check.mjs +471 -0
- package/utils.mjs +172 -0
- package/ve-kanban.mjs +654 -0
- package/ve-kanban.ps1 +1365 -0
- package/ve-kanban.sh +18 -0
- package/ve-orchestrator.mjs +340 -0
- package/ve-orchestrator.ps1 +6546 -0
- package/ve-orchestrator.sh +18 -0
- package/vibe-kanban-wrapper.mjs +41 -0
- package/vk-error-resolver.mjs +470 -0
- package/vk-log-stream.mjs +914 -0
- package/whatsapp-channel.mjs +520 -0
- package/workspace-monitor.mjs +581 -0
- package/workspace-reaper.mjs +405 -0
- package/workspace-registry.mjs +238 -0
- package/worktree-manager.mjs +1266 -0
package/compat.mjs
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* compat.mjs — Backward compatibility for users migrating from codex-monitor
|
|
4
|
+
*
|
|
5
|
+
* Handles:
|
|
6
|
+
* 1. Legacy env var aliasing: CODEX_MONITOR_X → BOSUN_X
|
|
7
|
+
* 2. Legacy config dir detection: ~/codex-monitor or $CODEX_MONITOR_DIR
|
|
8
|
+
* 3. Migration: copy old config dir to new bosun dir
|
|
9
|
+
*
|
|
10
|
+
* This module is intentionally dependency-free (only Node built-ins) and
|
|
11
|
+
* should be imported as early as possible in the startup path.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from "node:fs";
|
|
15
|
+
import { resolve, join } from "node:path";
|
|
16
|
+
|
|
17
|
+
// ── Legacy config file names accepted from old codex-monitor installations ───
|
|
18
|
+
const LEGACY_CONFIG_NAMES = [
|
|
19
|
+
"codex-monitor.config.json",
|
|
20
|
+
"bosun.config.json",
|
|
21
|
+
".bosun.json",
|
|
22
|
+
"bosun.json",
|
|
23
|
+
".env",
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Env vars the old codex-monitor package used that have been renamed.
|
|
28
|
+
* Format: [oldName, newName]
|
|
29
|
+
* Rule: any CODEX_MONITOR_X maps to BOSUN_X by default, but some had
|
|
30
|
+
* different names entirely — those are listed explicitly below.
|
|
31
|
+
*/
|
|
32
|
+
const EXPLICIT_ALIASES = [
|
|
33
|
+
// Dir / location
|
|
34
|
+
["CODEX_MONITOR_DIR", "BOSUN_DIR"],
|
|
35
|
+
["CODEX_MONITOR_HOME", "BOSUN_HOME"],
|
|
36
|
+
// Runtime flags
|
|
37
|
+
["CODEX_MONITOR_SKIP_AUTO_UPDATE", "BOSUN_SKIP_AUTO_UPDATE"],
|
|
38
|
+
["CODEX_MONITOR_SKIP_UPDATE_CHECK", "BOSUN_SKIP_UPDATE_CHECK"],
|
|
39
|
+
["CODEX_MONITOR_UPDATE_INTERVAL_MS", "BOSUN_UPDATE_INTERVAL_MS"],
|
|
40
|
+
["CODEX_MONITOR_SKIP_POSTINSTALL", "BOSUN_SKIP_POSTINSTALL"],
|
|
41
|
+
["CODEX_MONITOR_INTERACTIVE", "BOSUN_INTERACTIVE"],
|
|
42
|
+
["CODEX_MONITOR_PREFLIGHT_DISABLED", "BOSUN_PREFLIGHT_DISABLED"],
|
|
43
|
+
["CODEX_MONITOR_PREFLIGHT_RETRY_MS", "BOSUN_PREFLIGHT_RETRY_MS"],
|
|
44
|
+
["CODEX_MONITOR_MIN_FREE_GB", "BOSUN_MIN_FREE_GB"],
|
|
45
|
+
["CODEX_MONITOR_INSTANCE_ID", "BOSUN_INSTANCE_ID"],
|
|
46
|
+
["CODEX_MONITOR_MODE", "BOSUN_MODE"],
|
|
47
|
+
["CODEX_MONITOR_SHELL", "BOSUN_SHELL"],
|
|
48
|
+
["CODEX_MONITOR_SHELL_MODE", "BOSUN_SHELL_MODE"],
|
|
49
|
+
["CODEX_MONITOR_PROFILE", "BOSUN_PROFILE"],
|
|
50
|
+
["CODEX_MONITOR_ENV_PROFILE", "BOSUN_ENV_PROFILE"],
|
|
51
|
+
// Task
|
|
52
|
+
["CODEX_MONITOR_TASK_LABEL", "BOSUN_TASK_LABEL"],
|
|
53
|
+
["CODEX_MONITOR_TASK_LABELS", "BOSUN_TASK_LABELS"],
|
|
54
|
+
["CODEX_MONITOR_ENFORCE_TASK_LABEL", "BOSUN_ENFORCE_TASK_LABEL"],
|
|
55
|
+
["CODEX_MONITOR_TASK_UPSTREAM", "BOSUN_TASK_UPSTREAM"],
|
|
56
|
+
// Daemon
|
|
57
|
+
["CODEX_MONITOR_DAEMON", "BOSUN_DAEMON"],
|
|
58
|
+
["CODEX_MONITOR_DAEMON_RESTART_DELAY_MS", "BOSUN_DAEMON_RESTART_DELAY_MS"],
|
|
59
|
+
["CODEX_MONITOR_DAEMON_MAX_RESTARTS", "BOSUN_DAEMON_MAX_RESTARTS"],
|
|
60
|
+
["CODEX_MONITOR_DAEMON_INSTANT_CRASH_WINDOW_MS", "BOSUN_DAEMON_INSTANT_CRASH_WINDOW_MS"],
|
|
61
|
+
["CODEX_MONITOR_DAEMON_MAX_INSTANT_RESTARTS", "BOSUN_DAEMON_MAX_INSTANT_RESTARTS"],
|
|
62
|
+
// Hooks
|
|
63
|
+
["CODEX_MONITOR_HOOK_PROFILE", "BOSUN_HOOK_PROFILE"],
|
|
64
|
+
["CODEX_MONITOR_HOOK_TARGETS", "BOSUN_HOOK_TARGETS"],
|
|
65
|
+
["CODEX_MONITOR_HOOKS_ENABLED", "BOSUN_HOOKS_ENABLED"],
|
|
66
|
+
["CODEX_MONITOR_HOOKS_OVERWRITE", "BOSUN_HOOKS_OVERWRITE"],
|
|
67
|
+
["CODEX_MONITOR_HOOK_NODE_BIN", "BOSUN_HOOK_NODE_BIN"],
|
|
68
|
+
["CODEX_MONITOR_HOOK_BRIDGE_PATH", "BOSUN_HOOK_BRIDGE_PATH"],
|
|
69
|
+
["CODEX_MONITOR_HOOK_PREPUSH", "BOSUN_HOOK_PREPUSH"],
|
|
70
|
+
["CODEX_MONITOR_HOOK_PRECOMMIT", "BOSUN_HOOK_PRECOMMIT"],
|
|
71
|
+
["CODEX_MONITOR_HOOK_TASK_COMPLETE", "BOSUN_HOOK_TASK_COMPLETE"],
|
|
72
|
+
["CODEX_MONITOR_HOOKS_BUILTINS_MODE", "BOSUN_HOOKS_BUILTINS_MODE"],
|
|
73
|
+
["CODEX_MONITOR_HOOKS_FORCE", "BOSUN_HOOKS_FORCE"],
|
|
74
|
+
// Sentinel
|
|
75
|
+
["CODEX_MONITOR_SENTINEL_AUTO_START", "BOSUN_SENTINEL_AUTO_START"],
|
|
76
|
+
["CODEX_MONITOR_SENTINEL_STRICT", "BOSUN_SENTINEL_STRICT"],
|
|
77
|
+
// Prompts
|
|
78
|
+
["CODEX_MONITOR_PROMPT_WORKSPACE", "BOSUN_PROMPT_WORKSPACE"],
|
|
79
|
+
// Repo
|
|
80
|
+
["CODEX_MONITOR_REPO", "BOSUN_REPO"],
|
|
81
|
+
["CODEX_MONITOR_REPO_NAME", "BOSUN_REPO_NAME"],
|
|
82
|
+
["CODEX_MONITOR_REPO_ROOT", "BOSUN_REPO_ROOT"],
|
|
83
|
+
// Config path
|
|
84
|
+
["CODEX_MONITOR_CONFIG_PATH", "BOSUN_CONFIG_PATH"],
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Apply all legacy CODEX_MONITOR_* → BOSUN_* env var aliases.
|
|
89
|
+
* Also does a generic pass: any remaining CODEX_MONITOR_X that wasn't in the
|
|
90
|
+
* explicit list is aliased to BOSUN_X.
|
|
91
|
+
*
|
|
92
|
+
* Existing BOSUN_* values are never overwritten (BOSUN_ wins).
|
|
93
|
+
* Safe to call multiple times (idempotent).
|
|
94
|
+
*/
|
|
95
|
+
export function applyLegacyEnvAliases() {
|
|
96
|
+
// Explicit known renames
|
|
97
|
+
for (const [oldKey, newKey] of EXPLICIT_ALIASES) {
|
|
98
|
+
if (process.env[oldKey] !== undefined && process.env[newKey] === undefined) {
|
|
99
|
+
process.env[newKey] = process.env[oldKey];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Generic pass: CODEX_MONITOR_X → BOSUN_X for anything not already mapped
|
|
104
|
+
for (const key of Object.keys(process.env)) {
|
|
105
|
+
if (!key.startsWith("CODEX_MONITOR_")) continue;
|
|
106
|
+
const suffix = key.slice("CODEX_MONITOR_".length);
|
|
107
|
+
const newKey = `BOSUN_${suffix}`;
|
|
108
|
+
if (process.env[newKey] === undefined) {
|
|
109
|
+
process.env[newKey] = process.env[key];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Returns the legacy codex-monitor config directory if it exists and
|
|
116
|
+
* contains config files, null otherwise.
|
|
117
|
+
*
|
|
118
|
+
* Checks in priority order:
|
|
119
|
+
* 1. $CODEX_MONITOR_DIR env var
|
|
120
|
+
* 2. ~/codex-monitor
|
|
121
|
+
* 3. ~/.codex-monitor
|
|
122
|
+
* 4. ~/.config/codex-monitor
|
|
123
|
+
*/
|
|
124
|
+
export function getLegacyConfigDir() {
|
|
125
|
+
const home =
|
|
126
|
+
process.env.HOME ||
|
|
127
|
+
process.env.USERPROFILE ||
|
|
128
|
+
process.env.APPDATA ||
|
|
129
|
+
null;
|
|
130
|
+
|
|
131
|
+
const candidates = [
|
|
132
|
+
process.env.CODEX_MONITOR_DIR || null,
|
|
133
|
+
home ? join(home, "codex-monitor") : null,
|
|
134
|
+
home ? join(home, ".codex-monitor") : null,
|
|
135
|
+
home ? join(home, ".config", "codex-monitor") : null,
|
|
136
|
+
].filter(Boolean);
|
|
137
|
+
|
|
138
|
+
for (const dir of candidates) {
|
|
139
|
+
if (existsSync(dir) && hasLegacyMarkers(dir)) {
|
|
140
|
+
return dir;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function hasLegacyMarkers(dir) {
|
|
147
|
+
return LEGACY_CONFIG_NAMES.some((name) => existsSync(join(dir, name)));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Returns the target bosun config directory (where we'd migrate to).
|
|
152
|
+
* Does NOT create the directory.
|
|
153
|
+
*/
|
|
154
|
+
export function getNewConfigDir() {
|
|
155
|
+
const home =
|
|
156
|
+
process.env.HOME ||
|
|
157
|
+
process.env.USERPROFILE ||
|
|
158
|
+
process.env.APPDATA ||
|
|
159
|
+
process.cwd();
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
process.env.BOSUN_DIR ||
|
|
163
|
+
join(home, "bosun")
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Detect if the user has a legacy codex-monitor setup but no bosun setup.
|
|
169
|
+
* Returns { hasLegacy, legacyDir, newDir, alreadyMigrated }
|
|
170
|
+
*/
|
|
171
|
+
export function detectLegacySetup() {
|
|
172
|
+
const legacyDir = getLegacyConfigDir();
|
|
173
|
+
const newDir = getNewConfigDir();
|
|
174
|
+
const newHasConfig = hasLegacyMarkers(newDir);
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
hasLegacy: legacyDir !== null,
|
|
178
|
+
legacyDir,
|
|
179
|
+
newDir,
|
|
180
|
+
alreadyMigrated: newHasConfig,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Migrate config files from old codex-monitor dir to new bosun dir.
|
|
186
|
+
* Only copies; never deletes the old directory.
|
|
187
|
+
*
|
|
188
|
+
* Files copied:
|
|
189
|
+
* .env → .env (with CODEX_MONITOR_ → BOSUN_ substitution)
|
|
190
|
+
* bosun.config.json → bosun.config.json
|
|
191
|
+
* codex-monitor.config.json → bosun.config.json (rename)
|
|
192
|
+
* .bosun.json / bosun.json → as-is
|
|
193
|
+
*
|
|
194
|
+
* Returns { migrated: string[], skipped: string[], errors: string[] }
|
|
195
|
+
*/
|
|
196
|
+
export function migrateFromLegacy(legacyDir, newDir, { overwrite = false } = {}) {
|
|
197
|
+
const result = { migrated: [], skipped: [], errors: [] };
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
mkdirSync(newDir, { recursive: true });
|
|
201
|
+
} catch (e) {
|
|
202
|
+
result.errors.push(`Could not create ${newDir}: ${e.message}`);
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Files to migrate: [source name, dest name]
|
|
207
|
+
const filePairs = [
|
|
208
|
+
[".env", ".env"],
|
|
209
|
+
["bosun.config.json", "bosun.config.json"],
|
|
210
|
+
["codex-monitor.config.json","bosun.config.json"],
|
|
211
|
+
[".bosun.json", ".bosun.json"],
|
|
212
|
+
["bosun.json", "bosun.json"],
|
|
213
|
+
];
|
|
214
|
+
|
|
215
|
+
for (const [srcName, destName] of filePairs) {
|
|
216
|
+
const src = join(legacyDir, srcName);
|
|
217
|
+
const dest = join(newDir, destName);
|
|
218
|
+
|
|
219
|
+
if (!existsSync(src)) continue;
|
|
220
|
+
if (existsSync(dest) && !overwrite) {
|
|
221
|
+
result.skipped.push(destName);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
if (srcName === ".env") {
|
|
227
|
+
// Rewrite CODEX_MONITOR_ prefixes to BOSUN_ in .env content
|
|
228
|
+
const content = readFileSync(src, "utf8");
|
|
229
|
+
const updated = rewriteEnvContent(content);
|
|
230
|
+
writeFileSync(dest, updated, "utf8");
|
|
231
|
+
} else {
|
|
232
|
+
copyFileSync(src, dest);
|
|
233
|
+
}
|
|
234
|
+
result.migrated.push(destName);
|
|
235
|
+
} catch (e) {
|
|
236
|
+
result.errors.push(`${destName}: ${e.message}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return result;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Rewrite .env file content: replace CODEX_MONITOR_X= with BOSUN_X=
|
|
245
|
+
* while preserving comments and blank lines.
|
|
246
|
+
*/
|
|
247
|
+
function rewriteEnvContent(content) {
|
|
248
|
+
return content
|
|
249
|
+
.split("\n")
|
|
250
|
+
.map((line) => {
|
|
251
|
+
// Match both active vars and commented-out vars
|
|
252
|
+
return line.replace(/^(#?\s*)CODEX_MONITOR_/, "$1BOSUN_");
|
|
253
|
+
})
|
|
254
|
+
.join("\n");
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* If BOSUN_DIR is not set but CODEX_MONITOR_DIR is (or legacy dir exists),
|
|
259
|
+
* transparently set BOSUN_DIR to point at the legacy dir so bosun reads
|
|
260
|
+
* from it without requiring a migration step.
|
|
261
|
+
*
|
|
262
|
+
* This is the "zero-friction" path: existing users just upgrade the package and
|
|
263
|
+
* it works. Migration is optional (improves going forward).
|
|
264
|
+
*/
|
|
265
|
+
export function autoApplyLegacyDir() {
|
|
266
|
+
// Already set — nothing to do
|
|
267
|
+
if (process.env.BOSUN_DIR) return false;
|
|
268
|
+
|
|
269
|
+
const legacyDir = getLegacyConfigDir();
|
|
270
|
+
if (!legacyDir) return false;
|
|
271
|
+
|
|
272
|
+
process.env.BOSUN_DIR = legacyDir;
|
|
273
|
+
console.log(
|
|
274
|
+
`[compat] Legacy codex-monitor config detected at ${legacyDir} — using it as BOSUN_DIR.`,
|
|
275
|
+
);
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Run full compatibility setup: alias env vars + auto-apply legacy dir.
|
|
281
|
+
* Call this before loadConfig().
|
|
282
|
+
*/
|
|
283
|
+
export function applyAllCompatibility() {
|
|
284
|
+
applyLegacyEnvAliases();
|
|
285
|
+
autoApplyLegacyDir();
|
|
286
|
+
}
|