bosun 0.41.2 → 0.41.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 +1 -1
- package/agent/agent-prompt-catalog.mjs +971 -0
- package/agent/agent-prompts.mjs +2 -970
- package/agent/agent-supervisor.mjs +6 -3
- package/agent/autofix-git.mjs +33 -0
- package/agent/autofix-prompts.mjs +151 -0
- package/agent/autofix.mjs +11 -175
- package/agent/bosun-skills.mjs +3 -2
- package/bosun.config.example.json +17 -0
- package/bosun.schema.json +87 -188
- package/cli.mjs +34 -1
- package/config/config-doctor.mjs +5 -250
- package/config/config-file-names.mjs +5 -0
- package/config/config.mjs +89 -493
- package/config/executor-config.mjs +493 -0
- package/config/repo-root.mjs +1 -2
- package/config/workspace-health.mjs +242 -0
- package/git/git-safety.mjs +15 -0
- package/github/github-oauth-portal.mjs +46 -0
- package/infra/library-manager-utils.mjs +22 -0
- package/infra/library-manager-well-known-sources.mjs +578 -0
- package/infra/library-manager.mjs +512 -1030
- package/infra/monitor.mjs +28 -9
- package/infra/session-tracker.mjs +10 -7
- package/kanban/kanban-adapter.mjs +17 -1
- package/lib/codebase-audit-manifests.mjs +117 -0
- package/lib/codebase-audit.mjs +18 -115
- package/package.json +18 -3
- package/server/ui-server.mjs +1194 -79
- package/shell/codex-config-file.mjs +178 -0
- package/shell/codex-config.mjs +538 -575
- package/task/task-cli.mjs +54 -3
- package/task/task-executor.mjs +143 -13
- package/task/task-store.mjs +409 -1
- package/telegram/telegram-bot.mjs +127 -0
- package/tools/apply-pr-suggestions.mjs +401 -0
- package/tools/syntax-check.mjs +21 -9
- package/ui/app.js +3 -14
- package/ui/components/kanban-board.js +227 -4
- package/ui/components/session-list.js +85 -5
- package/ui/demo-defaults.js +334 -80
- package/ui/demo.html +155 -0
- package/ui/modules/session-api.js +96 -0
- package/ui/modules/settings-schema.js +1 -2
- package/ui/modules/state.js +21 -3
- package/ui/setup.html +4 -5
- package/ui/styles/components.css +58 -4
- package/ui/tabs/agents.js +12 -15
- package/ui/tabs/control.js +1 -0
- package/ui/tabs/library.js +484 -22
- package/ui/tabs/manual-flows.js +105 -29
- package/ui/tabs/tasks.js +785 -140
- package/ui/tabs/telemetry.js +129 -11
- package/ui/tabs/workflow-canvas-utils.mjs +130 -0
- package/ui/tabs/workflows.js +293 -23
- package/voice/voice-tool-definitions.mjs +757 -0
- package/voice/voice-tools.mjs +34 -778
- package/workflow/manual-flow-audit.mjs +165 -0
- package/workflow/manual-flows.mjs +164 -259
- package/workflow/workflow-engine.mjs +147 -58
- package/workflow/workflow-nodes/definitions.mjs +1207 -0
- package/workflow/workflow-nodes/transforms.mjs +612 -0
- package/workflow/workflow-nodes.mjs +304 -52
- package/workflow/workflow-templates.mjs +313 -191
- package/workflow-templates/_helpers.mjs +154 -0
- package/workflow-templates/agents.mjs +61 -4
- package/workflow-templates/code-quality.mjs +7 -7
- package/workflow-templates/github.mjs +20 -10
- package/workflow-templates/task-batch.mjs +20 -9
- package/workflow-templates/task-lifecycle.mjs +31 -6
- package/workspace/worktree-manager.mjs +277 -3
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
|
|
5
|
+
export const CODEX_DIR = resolve(homedir(), ".codex");
|
|
6
|
+
export const CONFIG_PATH = resolve(CODEX_DIR, "config.toml");
|
|
7
|
+
|
|
8
|
+
export function readCodexConfig() {
|
|
9
|
+
if (!existsSync(CONFIG_PATH)) return "";
|
|
10
|
+
return readFileSync(CONFIG_PATH, "utf8");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function writeCodexConfig(content) {
|
|
14
|
+
mkdirSync(CODEX_DIR, { recursive: true });
|
|
15
|
+
writeFileSync(CONFIG_PATH, content, "utf8");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getConfigPath() {
|
|
19
|
+
return CONFIG_PATH;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function tomlEscapeStr(value) {
|
|
23
|
+
return String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function formatTomlArrayEscaped(values) {
|
|
27
|
+
return `[${values.map((value) => `"${tomlEscapeStr(value)}"`).join(", ")}]`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function toWindowsNamespacePath(pathValue) {
|
|
31
|
+
const value = String(pathValue || "").trim();
|
|
32
|
+
if (!value) return null;
|
|
33
|
+
if (value.startsWith("\\\\?\\")) return value;
|
|
34
|
+
const drivePath = toWindowsDrivePath(value);
|
|
35
|
+
if (drivePath) return `\\\\?\\${drivePath}`;
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function toWindowsDrivePath(pathValue) {
|
|
40
|
+
const raw = String(pathValue || "").trim();
|
|
41
|
+
if (!raw) return null;
|
|
42
|
+
let value = raw.replace(/\//g, "\\");
|
|
43
|
+
if (value.startsWith("\\\\?\\")) value = value.slice(4);
|
|
44
|
+
if (/^[a-zA-Z]:\\/.test(value)) return value;
|
|
45
|
+
const wslMatch = raw.match(/^\/mnt\/([a-zA-Z])\/(.+)$/);
|
|
46
|
+
if (wslMatch) {
|
|
47
|
+
const drive = wslMatch[1].toUpperCase();
|
|
48
|
+
const rest = wslMatch[2].replace(/\//g, "\\");
|
|
49
|
+
return `${drive}:\\${rest}`;
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function normalizeTrustedPathForCompare(pathValue) {
|
|
55
|
+
const trimTrailingPathSeparators = (value) => {
|
|
56
|
+
let out = String(value || "");
|
|
57
|
+
while (out.endsWith("/") || out.endsWith("\\")) out = out.slice(0, -1);
|
|
58
|
+
return out;
|
|
59
|
+
};
|
|
60
|
+
const raw = String(pathValue || "").trim();
|
|
61
|
+
if (!raw) return "";
|
|
62
|
+
const windowsDrivePath = toWindowsDrivePath(raw);
|
|
63
|
+
if (windowsDrivePath) {
|
|
64
|
+
return trimTrailingPathSeparators(windowsDrivePath).toLowerCase();
|
|
65
|
+
}
|
|
66
|
+
if (process.platform === "win32") {
|
|
67
|
+
let normalized = raw.replace(/\//g, "\\");
|
|
68
|
+
if (normalized.startsWith("\\\\?\\UNC\\")) {
|
|
69
|
+
normalized = "\\\\" + normalized.slice(8);
|
|
70
|
+
} else if (normalized.startsWith("\\\\?\\")) {
|
|
71
|
+
normalized = normalized.slice(4);
|
|
72
|
+
}
|
|
73
|
+
normalized = trimTrailingPathSeparators(normalized);
|
|
74
|
+
return normalized.toLowerCase();
|
|
75
|
+
}
|
|
76
|
+
return trimTrailingPathSeparators(resolve(raw));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function buildTrustedPathVariants(pathValue) {
|
|
80
|
+
const base = resolve(pathValue);
|
|
81
|
+
const variants = [base];
|
|
82
|
+
const namespaced = toWindowsNamespacePath(base);
|
|
83
|
+
if (namespaced && namespaced !== base) variants.push(namespaced);
|
|
84
|
+
return variants;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function parseTomlArrayLiteralEscaped(raw) {
|
|
88
|
+
if (!raw) return [];
|
|
89
|
+
const inner = raw.trim().replace(/^\[/, "").replace(/\]$/, "");
|
|
90
|
+
if (!inner.trim()) return [];
|
|
91
|
+
const items = [];
|
|
92
|
+
let buffer = "";
|
|
93
|
+
let inString = false;
|
|
94
|
+
for (let index = 0; index < inner.length; index++) {
|
|
95
|
+
const char = inner[index];
|
|
96
|
+
if (char === "\\" && inString) {
|
|
97
|
+
buffer += char + (inner[++index] || "");
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (char === '"') {
|
|
101
|
+
inString = !inString;
|
|
102
|
+
buffer += char;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (char === "," && !inString) {
|
|
106
|
+
items.push(buffer.trim());
|
|
107
|
+
buffer = "";
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
buffer += char;
|
|
111
|
+
}
|
|
112
|
+
if (buffer.trim()) items.push(buffer.trim());
|
|
113
|
+
return items
|
|
114
|
+
.map((item) => item.replace(/^"(.*)"$/s, "$1"))
|
|
115
|
+
.map((item) => item.replace(/\\(["\\])/g, "$1"))
|
|
116
|
+
.filter(Boolean);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function collectTrustedProjectVariants(paths) {
|
|
120
|
+
return (paths || [])
|
|
121
|
+
.flatMap((pathValue) => buildTrustedPathVariants(pathValue))
|
|
122
|
+
.filter(Boolean);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function mergeTrustedProjectEntries(existing, desired) {
|
|
126
|
+
const existingNormalized = new Set(
|
|
127
|
+
existing.map((pathValue) => normalizeTrustedPathForCompare(pathValue)).filter(Boolean),
|
|
128
|
+
);
|
|
129
|
+
const added = [];
|
|
130
|
+
const already = [];
|
|
131
|
+
for (const pathValue of desired) {
|
|
132
|
+
const normalized = normalizeTrustedPathForCompare(pathValue);
|
|
133
|
+
if (!normalized) continue;
|
|
134
|
+
if (existingNormalized.has(normalized)) {
|
|
135
|
+
already.push(pathValue);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
existing.push(pathValue);
|
|
139
|
+
existingNormalized.add(normalized);
|
|
140
|
+
added.push(pathValue);
|
|
141
|
+
}
|
|
142
|
+
return { existing, added, already };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function upsertTrustedProjectsLine(toml, newLine, existingMatch) {
|
|
146
|
+
if (existingMatch) {
|
|
147
|
+
return toml.replace(/^trusted_projects\s*=\s*\[[^\]]*\]/m, newLine);
|
|
148
|
+
}
|
|
149
|
+
const firstSection = toml.search(/^\[/m);
|
|
150
|
+
if (firstSection === -1) {
|
|
151
|
+
return `${newLine}\n${toml}`;
|
|
152
|
+
}
|
|
153
|
+
return `${toml.slice(0, firstSection)}${newLine}\n\n${toml.slice(firstSection)}`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function ensureTrustedProjects(paths, { dryRun = false } = {}) {
|
|
157
|
+
const result = { added: [], already: [], path: CONFIG_PATH };
|
|
158
|
+
const desired = collectTrustedProjectVariants(paths);
|
|
159
|
+
if (desired.length === 0) return result;
|
|
160
|
+
|
|
161
|
+
let toml = readCodexConfig() || "";
|
|
162
|
+
const existingMatch = toml.match(/^trusted_projects\s*=\s*(\[[^\]]*\])/m);
|
|
163
|
+
const existing = existingMatch ? parseTomlArrayLiteralEscaped(existingMatch[1]) : [];
|
|
164
|
+
const merged = mergeTrustedProjectEntries(existing, desired);
|
|
165
|
+
result.added = merged.added;
|
|
166
|
+
result.already = merged.already;
|
|
167
|
+
if (result.added.length === 0) return result;
|
|
168
|
+
if (dryRun) return result;
|
|
169
|
+
|
|
170
|
+
toml = upsertTrustedProjectsLine(
|
|
171
|
+
toml,
|
|
172
|
+
`trusted_projects = ${formatTomlArrayEscaped(merged.existing)}`,
|
|
173
|
+
existingMatch,
|
|
174
|
+
);
|
|
175
|
+
mkdirSync(CODEX_DIR, { recursive: true });
|
|
176
|
+
writeFileSync(CONFIG_PATH, toml, "utf8");
|
|
177
|
+
return result;
|
|
178
|
+
}
|