bosun 0.40.21 → 0.41.1
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 +8 -0
- package/README.md +20 -0
- package/agent/agent-custom-tools.mjs +23 -5
- package/agent/agent-event-bus.mjs +248 -6
- package/agent/agent-pool.mjs +131 -30
- package/agent/agent-work-analyzer.mjs +8 -16
- package/agent/primary-agent.mjs +81 -7
- package/agent/retry-queue.mjs +164 -0
- package/bench/swebench/bosun-swebench.mjs +5 -0
- package/bosun.config.example.json +25 -0
- package/bosun.schema.json +825 -183
- package/cli.mjs +267 -8
- package/config/config-doctor.mjs +51 -2
- package/config/config.mjs +232 -5
- package/github/github-auth-manager.mjs +70 -19
- package/infra/library-manager.mjs +894 -60
- package/infra/monitor.mjs +701 -69
- package/infra/runtime-accumulator.mjs +376 -84
- package/infra/session-tracker.mjs +95 -28
- package/infra/test-runtime.mjs +267 -0
- package/lib/codebase-audit.mjs +133 -18
- package/package.json +30 -8
- package/server/setup-web-server.mjs +29 -1
- package/server/ui-server.mjs +1571 -49
- package/setup.mjs +27 -24
- package/shell/codex-shell.mjs +34 -3
- package/shell/copilot-shell.mjs +50 -8
- package/task/msg-hub.mjs +193 -0
- package/task/pipeline.mjs +544 -0
- package/task/task-claims.mjs +6 -10
- package/task/task-cli.mjs +38 -2
- package/task/task-executor-pipeline.mjs +143 -0
- package/task/task-executor.mjs +36 -27
- package/telegram/get-telegram-chat-id.mjs +57 -47
- package/ui/components/chat-view.js +18 -1
- package/ui/components/workspace-switcher.js +321 -9
- package/ui/demo-defaults.js +17830 -10433
- package/ui/demo.html +9 -1
- package/ui/modules/router.js +1 -1
- package/ui/modules/settings-schema.js +2 -0
- package/ui/modules/state.js +54 -57
- package/ui/modules/voice-client-sdk.js +376 -37
- package/ui/modules/voice-client.js +173 -33
- package/ui/setup.html +68 -2
- package/ui/styles/components.css +571 -1
- package/ui/styles.css +201 -1
- package/ui/tabs/dashboard.js +74 -0
- package/ui/tabs/library.js +410 -55
- package/ui/tabs/logs.js +10 -0
- package/ui/tabs/settings.js +178 -99
- package/ui/tabs/tasks.js +1083 -507
- package/ui/tabs/telemetry.js +34 -0
- package/ui/tabs/workflow-canvas-utils.mjs +38 -1
- package/ui/tabs/workflows.js +1275 -402
- package/voice/voice-agents-sdk.mjs +2 -2
- package/voice/voice-relay.mjs +28 -20
- package/workflow/declarative-workflows.mjs +145 -0
- package/workflow/msg-hub.mjs +237 -0
- package/workflow/pipeline-workflows.mjs +287 -0
- package/workflow/pipeline.mjs +828 -315
- package/workflow/project-detection.mjs +559 -0
- package/workflow/workflow-cli.mjs +128 -0
- package/workflow/workflow-contract.mjs +433 -232
- package/workflow/workflow-engine.mjs +510 -47
- package/workflow/workflow-nodes/custom-loader.mjs +251 -0
- package/workflow/workflow-nodes.mjs +2024 -184
- package/workflow/workflow-templates.mjs +118 -24
- package/workflow-templates/agents.mjs +20 -20
- package/workflow-templates/bosun-native.mjs +212 -2
- package/workflow-templates/code-quality.mjs +20 -14
- package/workflow-templates/continuation-loop.mjs +339 -0
- package/workflow-templates/github.mjs +516 -40
- package/workflow-templates/planning.mjs +446 -17
- package/workflow-templates/reliability.mjs +65 -12
- package/workflow-templates/task-batch.mjs +27 -10
- package/workflow-templates/task-execution.mjs +752 -0
- package/workflow-templates/task-lifecycle.mjs +117 -14
- package/workspace/context-cache.mjs +66 -18
- package/workspace/workspace-manager.mjs +153 -1
- package/workflow-templates/issue-continuation.mjs +0 -243
package/lib/codebase-audit.mjs
CHANGED
|
@@ -23,8 +23,6 @@ const SOURCE_TYPES = new Map([
|
|
|
23
23
|
|
|
24
24
|
const SUMMARY_MARKERS = ["CLAUDE:SUMMARY", "BOSUN:SUMMARY"];
|
|
25
25
|
const WARN_MARKERS = ["CLAUDE:WARN", "BOSUN:WARN"];
|
|
26
|
-
const SUMMARY_LINE_RE = /^\s*(?:\/\/|#)\s*(?:CLAUDE|BOSUN):SUMMARY\b/i;
|
|
27
|
-
const WARN_LINE_RE = /^\s*(?:\/\/|#)\s*(?:CLAUDE|BOSUN):WARN\b/i;
|
|
28
26
|
const GENERATED_PATTERNS = [
|
|
29
27
|
/^\.git(?:\/|$)/,
|
|
30
28
|
/^node_modules(?:\/|$)/,
|
|
@@ -151,6 +149,101 @@ function getSourceType(pathValue) {
|
|
|
151
149
|
return SOURCE_TYPES.get(extname(pathValue).toLowerCase()) || null;
|
|
152
150
|
}
|
|
153
151
|
|
|
152
|
+
function parseImportSpecifiers(content, language) {
|
|
153
|
+
if (language !== "javascript" && language !== "typescript") return [];
|
|
154
|
+
const specs = new Set();
|
|
155
|
+
const importRegex = /import\s+(?:[^"'`]+?\s+from\s+)?["'`]([^"'`]+)["'`]/g;
|
|
156
|
+
const dynamicImportRegex = /import\(\s*["'`]([^"'`]+)["'`]\s*\)/g;
|
|
157
|
+
const requireRegex = /require\(\s*["'`]([^"'`]+)["'`]\s*\)/g;
|
|
158
|
+
for (const pattern of [importRegex, dynamicImportRegex, requireRegex]) {
|
|
159
|
+
let match;
|
|
160
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
161
|
+
if (match[1]) specs.add(match[1]);
|
|
162
|
+
}
|
|
163
|
+
pattern.lastIndex = 0;
|
|
164
|
+
}
|
|
165
|
+
return [...specs];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function resolveLocalImportPath(repoRoot, fromFile, specifier) {
|
|
169
|
+
if (!specifier || !specifier.startsWith(".")) return "";
|
|
170
|
+
const fromDir = dirname(fromFile);
|
|
171
|
+
const absoluteBase = resolve(fromDir, specifier);
|
|
172
|
+
const candidates = [
|
|
173
|
+
absoluteBase,
|
|
174
|
+
`${absoluteBase}.js`,
|
|
175
|
+
`${absoluteBase}.mjs`,
|
|
176
|
+
`${absoluteBase}.cjs`,
|
|
177
|
+
`${absoluteBase}.ts`,
|
|
178
|
+
`${absoluteBase}.tsx`,
|
|
179
|
+
`${absoluteBase}.jsx`,
|
|
180
|
+
resolve(absoluteBase, "index.js"),
|
|
181
|
+
resolve(absoluteBase, "index.mjs"),
|
|
182
|
+
resolve(absoluteBase, "index.cjs"),
|
|
183
|
+
resolve(absoluteBase, "index.ts"),
|
|
184
|
+
resolve(absoluteBase, "index.tsx"),
|
|
185
|
+
resolve(absoluteBase, "index.jsx"),
|
|
186
|
+
];
|
|
187
|
+
for (const candidate of candidates) {
|
|
188
|
+
const info = safeStat(candidate);
|
|
189
|
+
if (info?.isFile()) return toPosix(relative(repoRoot, candidate));
|
|
190
|
+
}
|
|
191
|
+
return "";
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function findCycleMembers(edgesByFile) {
|
|
195
|
+
const states = new Map();
|
|
196
|
+
const stack = [];
|
|
197
|
+
const inCycles = new Set();
|
|
198
|
+
|
|
199
|
+
function visit(node) {
|
|
200
|
+
const state = states.get(node) || 0;
|
|
201
|
+
if (state === 2) return;
|
|
202
|
+
if (state === 1) {
|
|
203
|
+
const cycleStart = stack.lastIndexOf(node);
|
|
204
|
+
if (cycleStart >= 0) {
|
|
205
|
+
for (let index = cycleStart; index < stack.length; index += 1) inCycles.add(stack[index]);
|
|
206
|
+
inCycles.add(node);
|
|
207
|
+
}
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
states.set(node, 1);
|
|
211
|
+
stack.push(node);
|
|
212
|
+
for (const dep of edgesByFile.get(node) || []) visit(dep);
|
|
213
|
+
stack.pop();
|
|
214
|
+
states.set(node, 2);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
for (const node of edgesByFile.keys()) visit(node);
|
|
218
|
+
return inCycles;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function appendCircularDependencyWarnings(files, repoRoot, warningKinds) {
|
|
222
|
+
const sourceSet = new Set(files.map((file) => file.path));
|
|
223
|
+
const edgesByFile = new Map();
|
|
224
|
+
for (const file of files) {
|
|
225
|
+
if (file.language !== "javascript" && file.language !== "typescript") continue;
|
|
226
|
+
const deps = [];
|
|
227
|
+
for (const specifier of file.importSpecifiers || []) {
|
|
228
|
+
const resolved = resolveLocalImportPath(repoRoot, file.absolutePath, specifier);
|
|
229
|
+
if (resolved && sourceSet.has(resolved)) deps.push(resolved);
|
|
230
|
+
}
|
|
231
|
+
edgesByFile.set(file.path, deps);
|
|
232
|
+
}
|
|
233
|
+
const cycleMembers = findCycleMembers(edgesByFile);
|
|
234
|
+
for (const file of files) {
|
|
235
|
+
if (!cycleMembers.has(file.path)) continue;
|
|
236
|
+
if (file.warnings.some((warning) => warning.kind === "circular-deps")) continue;
|
|
237
|
+
file.warnings.push({
|
|
238
|
+
kind: "circular-deps",
|
|
239
|
+
text: "Module participates in circular dependency chains; avoid reordering imports or eager top-level side effects.",
|
|
240
|
+
functionName: "__module__",
|
|
241
|
+
lineIndex: file.firstFunctionLine,
|
|
242
|
+
});
|
|
243
|
+
warningKinds["circular-deps"] = (warningKinds["circular-deps"] || 0) + 1;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
154
247
|
function detectCategory(relPath) {
|
|
155
248
|
if (/(^|\/)(tests?|__tests__|fixtures?|sandbox)(\/|$)|\.(test|spec)\./i.test(relPath)) return "test";
|
|
156
249
|
if (/(^|\/)(config|configs)(\/|$)|(^|\/)(AGENTS|CLAUDE)\.md$/i.test(relPath)) return "config";
|
|
@@ -159,15 +252,20 @@ function detectCategory(relPath) {
|
|
|
159
252
|
return "core";
|
|
160
253
|
}
|
|
161
254
|
|
|
162
|
-
function
|
|
163
|
-
const
|
|
164
|
-
|
|
255
|
+
function isAnnotationLine(line, markers) {
|
|
256
|
+
const trimmed = String(line || "").trim();
|
|
257
|
+
if (!trimmed.startsWith("//") && !trimmed.startsWith("#")) return false;
|
|
258
|
+
return markers.some((marker) => new RegExp(`\\b${marker}\\b`).test(trimmed));
|
|
165
259
|
}
|
|
166
260
|
|
|
167
|
-
function extractAnnotationLines(content) {
|
|
261
|
+
function extractAnnotationLines(content, markers = SUMMARY_MARKERS) {
|
|
168
262
|
const lines = content.split(/\r?\n/);
|
|
169
|
-
|
|
170
|
-
|
|
263
|
+
return lines.filter((line) => isAnnotationLine(line, markers));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function collectAnnotations(content) {
|
|
267
|
+
const summaryLine = extractAnnotationLines(content, SUMMARY_MARKERS)[0] || "";
|
|
268
|
+
const warnLines = extractAnnotationLines(content, WARN_MARKERS);
|
|
171
269
|
return { summaryLine, warnLines };
|
|
172
270
|
}
|
|
173
271
|
|
|
@@ -210,7 +308,8 @@ export function scanRepository(rootDir, options = {}) {
|
|
|
210
308
|
if (isGeneratedPath(relPath)) return;
|
|
211
309
|
|
|
212
310
|
const content = readText(absolutePath);
|
|
213
|
-
const
|
|
311
|
+
const contentLines = content.split(/\r?\n/);
|
|
312
|
+
const annotations = collectAnnotations(content);
|
|
214
313
|
const functionMatches = findFunctionMatches(content, sourceType.language);
|
|
215
314
|
const warnings = analyzeFileWarnings(content, sourceType.language, functionMatches);
|
|
216
315
|
for (const warning of warnings) {
|
|
@@ -223,12 +322,14 @@ export function scanRepository(rootDir, options = {}) {
|
|
|
223
322
|
language: sourceType.language,
|
|
224
323
|
extension: extname(absolutePath).toLowerCase(),
|
|
225
324
|
comment: sourceType.comment,
|
|
226
|
-
lines: content === "" ? 0 :
|
|
325
|
+
lines: content === "" ? 0 : contentLines.length,
|
|
227
326
|
category: detectCategory(relPath),
|
|
228
|
-
hasSummary:
|
|
229
|
-
hasWarn:
|
|
327
|
+
hasSummary: annotations.summaryLine !== "",
|
|
328
|
+
hasWarn: annotations.warnLines.length > 0,
|
|
230
329
|
summaryLine: annotations.summaryLine,
|
|
231
330
|
warnLines: annotations.warnLines,
|
|
331
|
+
importSpecifiers: parseImportSpecifiers(content, sourceType.language),
|
|
332
|
+
firstFunctionLine: functionMatches[0]?.lineIndex ?? findInsertionIndex(contentLines),
|
|
232
333
|
warnings,
|
|
233
334
|
});
|
|
234
335
|
}
|
|
@@ -261,6 +362,7 @@ export function scanRepository(rootDir, options = {}) {
|
|
|
261
362
|
const relPath = toPosix(relative(repoRoot, targetDir));
|
|
262
363
|
if (getSourceType(targetDir) && !isGeneratedPath(relPath)) addFile(targetDir);
|
|
263
364
|
}
|
|
365
|
+
appendCircularDependencyWarnings(files, repoRoot, warningKinds);
|
|
264
366
|
|
|
265
367
|
const result = {
|
|
266
368
|
rootDir: repoRoot,
|
|
@@ -432,7 +534,7 @@ function hasNearbyWarn(lines, lineIndex) {
|
|
|
432
534
|
const start = Math.max(0, lineIndex - 2);
|
|
433
535
|
const end = Math.min(lines.length - 1, lineIndex + 1);
|
|
434
536
|
for (let index = start; index <= end; index += 1) {
|
|
435
|
-
if (
|
|
537
|
+
if (isAnnotationLine(lines[index], WARN_MARKERS)) return true;
|
|
436
538
|
}
|
|
437
539
|
return false;
|
|
438
540
|
}
|
|
@@ -447,8 +549,9 @@ export function generateWarnings(rootDir, options = {}) {
|
|
|
447
549
|
const inserts = [];
|
|
448
550
|
for (const warning of file.warnings) {
|
|
449
551
|
if (hasNearbyWarn(lines, warning.lineIndex)) continue;
|
|
552
|
+
const preferredIndex = Number.isInteger(warning.lineIndex) ? warning.lineIndex : findInsertionIndex(lines);
|
|
450
553
|
inserts.push({
|
|
451
|
-
index: warning.functionName ?
|
|
554
|
+
index: warning.functionName ? preferredIndex : findInsertionIndex(lines),
|
|
452
555
|
text: buildCommentLine(file.comment, "CLAUDE:WARN", warning.text),
|
|
453
556
|
});
|
|
454
557
|
}
|
|
@@ -618,7 +721,8 @@ function findStaleWarnings(content, language) {
|
|
|
618
721
|
const matcher = patterns[language];
|
|
619
722
|
if (!matcher) return stale;
|
|
620
723
|
for (let index = 0; index < lines.length; index += 1) {
|
|
621
|
-
if (!
|
|
724
|
+
if (!isAnnotationLine(lines[index], WARN_MARKERS)) continue;
|
|
725
|
+
if (/circular dependency/i.test(lines[index])) continue;
|
|
622
726
|
const window = lines.slice(index + 1, index + 5).join("\n");
|
|
623
727
|
if (!matcher.test(window)) stale.push(index + 1);
|
|
624
728
|
}
|
|
@@ -666,9 +770,21 @@ export function runConformity(rootDir, options = {}) {
|
|
|
666
770
|
|
|
667
771
|
export function migrateAnnotations(rootDir, options = {}) {
|
|
668
772
|
const scan = scanRepository(rootDir, options);
|
|
773
|
+
const migrateLegacyAnnotationMarkers = (content) =>
|
|
774
|
+
content
|
|
775
|
+
.replace(/BOSUN:SUMMARY/g, "CLAUDE:SUMMARY")
|
|
776
|
+
.replace(/BOSUN:WARN/g, "CLAUDE:WARN")
|
|
777
|
+
.replace(
|
|
778
|
+
/^(\s*(?:\/\/|#)\s*)(?:LEGACY:)?SUMMARY\s*[:\-]\s*/gim,
|
|
779
|
+
"$1CLAUDE:SUMMARY ",
|
|
780
|
+
)
|
|
781
|
+
.replace(
|
|
782
|
+
/^(\s*(?:\/\/|#)\s*)(?:LEGACY:)?WARN(?:ING)?\s*[:\-]\s*/gim,
|
|
783
|
+
"$1CLAUDE:WARN ",
|
|
784
|
+
);
|
|
669
785
|
const changed = updateFiles(
|
|
670
|
-
scan.files
|
|
671
|
-
(file, content) => content
|
|
786
|
+
scan.files,
|
|
787
|
+
(file, content) => migrateLegacyAnnotationMarkers(content),
|
|
672
788
|
options,
|
|
673
789
|
);
|
|
674
790
|
return {
|
|
@@ -804,4 +920,3 @@ export async function runAuditCli(argv, io = {}) {
|
|
|
804
920
|
const shouldFail = command === "conformity" || Boolean(flags.ci);
|
|
805
921
|
return { exitCode: shouldFail && result.ok === false ? 1 : 0, result };
|
|
806
922
|
}
|
|
807
|
-
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bosun",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.1",
|
|
4
4
|
"description": "Bosun Autonomous Engineering — manages AI agent executors with failover, extremely powerful workflow builder, and a massive amount of included default workflow templates for autonomous engineering, creates PRs via Vibe-Kanban API, and sends Telegram notifications. Supports N executors with weighted distribution, multi-repo projects, and auto-setup.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -71,10 +71,17 @@
|
|
|
71
71
|
"./container-runner": "./infra/container-runner.mjs",
|
|
72
72
|
"./compat": "./compat.mjs",
|
|
73
73
|
"./task-cli": "./task/task-cli.mjs",
|
|
74
|
+
"./task-pipeline": "./task/pipeline.mjs",
|
|
75
|
+
"./task-msg-hub": "./task/msg-hub.mjs",
|
|
76
|
+
"./workflow-cli": "./workflow/workflow-cli.mjs",
|
|
77
|
+
"./pipeline-workflows": "./workflow/pipeline-workflows.mjs",
|
|
74
78
|
"./github-auth-manager": "./github/github-auth-manager.mjs",
|
|
75
79
|
"./git-commit-helpers": "./git/git-commit-helpers.mjs",
|
|
76
80
|
"./opencode-shell": "./shell/opencode-shell.mjs",
|
|
77
|
-
"./context-indexer": "./workspace/context-indexer.mjs"
|
|
81
|
+
"./context-indexer": "./workspace/context-indexer.mjs",
|
|
82
|
+
"./msg-hub": "./workflow/msg-hub.mjs",
|
|
83
|
+
"./declarative-workflows": "./workflow/declarative-workflows.mjs",
|
|
84
|
+
"./pipeline": "./workflow/pipeline.mjs"
|
|
78
85
|
},
|
|
79
86
|
"bin": {
|
|
80
87
|
"bosun": "cli.mjs",
|
|
@@ -106,8 +113,10 @@
|
|
|
106
113
|
"pretest": "npm run syntax:check",
|
|
107
114
|
"test": "node --max-old-space-size=4096 node_modules/vitest/vitest.mjs run --config vitest.config.mjs",
|
|
108
115
|
"test:vitest": "node --max-old-space-size=4096 node_modules/vitest/vitest.mjs run --config vitest.config.mjs",
|
|
109
|
-
"test:node": "node --test tests/*.node.test.mjs",
|
|
116
|
+
"test:node": "node --import ./tests/node-test-bootstrap.mjs --test tests/*.node.test.mjs",
|
|
110
117
|
"test:all": "npm run test:vitest && npm run test:node",
|
|
118
|
+
"test:e2e": "npx playwright test server/playwright-ui-e2e.mjs",
|
|
119
|
+
"test:e2e:all": "npx playwright test server/playwright-ui-e2e.mjs server/playwright-ui-smoke.mjs",
|
|
111
120
|
"test:voice-provider-smoke": "vitest run --config vitest.config.mjs tests/voice-provider-smoke.test.mjs",
|
|
112
121
|
"check:native-call-parity": "vitest run --config vitest.config.mjs tests/voice-provider-smoke.test.mjs tests/native-call-parity-checklist.test.mjs",
|
|
113
122
|
"test:watch": "vitest",
|
|
@@ -147,6 +156,7 @@
|
|
|
147
156
|
"agent/agent-custom-tools.mjs",
|
|
148
157
|
"agent/agent-endpoint.mjs",
|
|
149
158
|
"agent/agent-event-bus.mjs",
|
|
159
|
+
"agent/retry-queue.mjs",
|
|
150
160
|
"agent/agent-pool.mjs",
|
|
151
161
|
"agent/agent-prompts.mjs",
|
|
152
162
|
"agent/agent-sdk.mjs",
|
|
@@ -200,7 +210,8 @@
|
|
|
200
210
|
"infra/library-manager.mjs",
|
|
201
211
|
"infra/maintenance.mjs",
|
|
202
212
|
"workflow/manual-flows.mjs",
|
|
203
|
-
"workflow
|
|
213
|
+
"workflow/pipeline-workflows.mjs",
|
|
214
|
+
"workflow/workflow-cli.mjs",
|
|
204
215
|
"workflow/mcp-discovery-proxy.mjs",
|
|
205
216
|
"workflow/mcp-workflow-adapter.mjs",
|
|
206
217
|
"workflow/mcp-registry.mjs",
|
|
@@ -222,6 +233,7 @@
|
|
|
222
233
|
"agent/review-agent.mjs",
|
|
223
234
|
"git/sdk-conflict-resolver.mjs",
|
|
224
235
|
"infra/session-tracker.mjs",
|
|
236
|
+
"infra/test-runtime.mjs",
|
|
225
237
|
"setup.mjs",
|
|
226
238
|
"server/setup-web-server.mjs",
|
|
227
239
|
"shell/pwsh-runtime.mjs",
|
|
@@ -241,7 +253,10 @@
|
|
|
241
253
|
"task/task-claims.mjs",
|
|
242
254
|
"task/task-context.mjs",
|
|
243
255
|
"task/task-attachments.mjs",
|
|
256
|
+
"task/pipeline.mjs",
|
|
257
|
+
"task/msg-hub.mjs",
|
|
244
258
|
"task/task-executor.mjs",
|
|
259
|
+
"task/task-executor-pipeline.mjs",
|
|
245
260
|
"task/task-store.mjs",
|
|
246
261
|
"telegram/telegram-bot.mjs",
|
|
247
262
|
"server/ui-server.mjs",
|
|
@@ -289,6 +304,8 @@
|
|
|
289
304
|
"workflow/workflow-engine.mjs",
|
|
290
305
|
"workflow/workflow-migration.mjs",
|
|
291
306
|
"workflow/workflow-nodes.mjs",
|
|
307
|
+
"workflow/workflow-nodes/custom-loader.mjs",
|
|
308
|
+
"workflow/project-detection.mjs",
|
|
292
309
|
"workflow/workflow-templates.mjs",
|
|
293
310
|
"workflow/workflow-contract.mjs",
|
|
294
311
|
"workflow/pipeline.mjs",
|
|
@@ -303,13 +320,18 @@
|
|
|
303
320
|
"workflow-templates/research.mjs",
|
|
304
321
|
"workflow-templates/security.mjs",
|
|
305
322
|
"workflow-templates/task-batch.mjs",
|
|
323
|
+
"workflow-templates/task-execution.mjs",
|
|
306
324
|
"workflow-templates/task-lifecycle.mjs",
|
|
307
325
|
"workflow-templates/issue-continuation.mjs",
|
|
326
|
+
"workflow-templates/continuation-loop.mjs",
|
|
327
|
+
"workflow-templates/code-quality.mjs",
|
|
308
328
|
"workflow-templates/bosun-native.mjs",
|
|
309
329
|
"bosun-tui.mjs",
|
|
310
330
|
"tui/",
|
|
311
331
|
"tools/",
|
|
312
|
-
"ui/vendor/"
|
|
332
|
+
"ui/vendor/",
|
|
333
|
+
"workflow/msg-hub.mjs",
|
|
334
|
+
"workflow/declarative-workflows.mjs"
|
|
313
335
|
],
|
|
314
336
|
"dependencies": {
|
|
315
337
|
"@anthropic-ai/claude-agent-sdk": "latest",
|
|
@@ -327,12 +349,12 @@
|
|
|
327
349
|
"express-rate-limit": "^8.0.0",
|
|
328
350
|
"hono": "^4.12.7",
|
|
329
351
|
"htm": "3.1.1",
|
|
352
|
+
"ink": "^5.0.0",
|
|
353
|
+
"ink-text-input": "^6.0.0",
|
|
330
354
|
"preact": "10.25.4",
|
|
331
355
|
"qrcode-terminal": "^0.12.0",
|
|
332
356
|
"vibe-kanban": "latest",
|
|
333
|
-
"ws": "^8.19.0"
|
|
334
|
-
"ink": "^5.0.0",
|
|
335
|
-
"ink-text-input": "^6.0.0"
|
|
357
|
+
"ws": "^8.19.0"
|
|
336
358
|
},
|
|
337
359
|
"devDependencies": {
|
|
338
360
|
"@emotion/react": "^11.14.0",
|
|
@@ -19,6 +19,7 @@ import { fileURLToPath } from "node:url";
|
|
|
19
19
|
import { createRequire } from "node:module";
|
|
20
20
|
import { execSync } from "node:child_process";
|
|
21
21
|
import { homedir } from "node:os";
|
|
22
|
+
import { ensureTestRuntimeSandbox } from "../infra/test-runtime.mjs";
|
|
22
23
|
import { scaffoldSkills } from "../agent/bosun-skills.mjs";
|
|
23
24
|
import { ensureCodexConfig, ensureTrustedProjects } from "../shell/codex-config.mjs";
|
|
24
25
|
import {
|
|
@@ -28,6 +29,7 @@ import {
|
|
|
28
29
|
resolveWorkflowTemplateIds,
|
|
29
30
|
normalizeTemplateOverridesById,
|
|
30
31
|
} from "../workflow/workflow-templates.mjs";
|
|
32
|
+
import { discoverTelegramChats } from "../telegram/get-telegram-chat-id.mjs";
|
|
31
33
|
|
|
32
34
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
33
35
|
|
|
@@ -1420,6 +1422,9 @@ function resolveConfigDir() {
|
|
|
1420
1422
|
if (isExpectedHome) return cwd;
|
|
1421
1423
|
}
|
|
1422
1424
|
|
|
1425
|
+
const sandbox = ensureTestRuntimeSandbox();
|
|
1426
|
+
if (sandbox?.configDir) return sandbox.configDir;
|
|
1427
|
+
|
|
1423
1428
|
const preferWindowsDirs =
|
|
1424
1429
|
process.platform === "win32" && !isWslInteropRuntime();
|
|
1425
1430
|
const baseDir = preferWindowsDirs
|
|
@@ -1977,6 +1982,20 @@ function handleValidate(body) {
|
|
|
1977
1982
|
return { ok: true, valid: Object.keys(errors).length === 0, errors };
|
|
1978
1983
|
}
|
|
1979
1984
|
|
|
1985
|
+
async function handleTelegramChatIdLookup(body) {
|
|
1986
|
+
const token = String(body?.token || "").trim();
|
|
1987
|
+
if (!token) {
|
|
1988
|
+
return { ok: false, status: 400, error: "TELEGRAM_BOT_TOKEN is required" };
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
try {
|
|
1992
|
+
const { chats, message } = await discoverTelegramChats(token);
|
|
1993
|
+
return { ok: true, status: 200, chats, message };
|
|
1994
|
+
} catch (err) {
|
|
1995
|
+
return { ok: false, status: 500, error: err.message || String(err) };
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1980
1999
|
function handleApply(body) {
|
|
1981
2000
|
try {
|
|
1982
2001
|
const { env = {}, configJson = {} } = body || {};
|
|
@@ -2575,6 +2594,15 @@ async function handleRequest(req, res) {
|
|
|
2575
2594
|
}
|
|
2576
2595
|
jsonResponse(res, 200, handleValidate(await readBody(req)));
|
|
2577
2596
|
return;
|
|
2597
|
+
case "telegram-chat-id": {
|
|
2598
|
+
if (req.method !== "POST") {
|
|
2599
|
+
jsonResponse(res, 405, { ok: false, error: "POST required" });
|
|
2600
|
+
return;
|
|
2601
|
+
}
|
|
2602
|
+
const result = await handleTelegramChatIdLookup(await readBody(req));
|
|
2603
|
+
jsonResponse(res, result.status, result);
|
|
2604
|
+
return;
|
|
2605
|
+
}
|
|
2578
2606
|
case "apply":
|
|
2579
2607
|
if (req.method !== "POST") {
|
|
2580
2608
|
jsonResponse(res, 405, { ok: false, error: "POST required" });
|
|
@@ -2980,6 +3008,7 @@ export async function startSetupServer(options = {}) {
|
|
|
2980
3008
|
export {
|
|
2981
3009
|
applyTelegramMiniAppSetupEnv,
|
|
2982
3010
|
applyNonBlockingSetupEnvDefaults,
|
|
3011
|
+
handleTelegramChatIdLookup,
|
|
2983
3012
|
normalizeWorkflowTemplateOverrides,
|
|
2984
3013
|
normalizeTelegramUiPort,
|
|
2985
3014
|
normalizeRepoConfigEntry,
|
|
@@ -2995,4 +3024,3 @@ if (process.argv[1] && resolve(process.argv[1]) === resolve(__filename_setup_web
|
|
|
2995
3024
|
process.exit(1);
|
|
2996
3025
|
});
|
|
2997
3026
|
}
|
|
2998
|
-
|