@brainforge/core 3.1.13 → 3.1.14
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/dist/index.d.ts +4 -6
- package/dist/index.js +45 -20
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -152,10 +152,7 @@ declare class StateManager {
|
|
|
152
152
|
private statePath;
|
|
153
153
|
private state;
|
|
154
154
|
constructor(workingDir: string);
|
|
155
|
-
|
|
156
|
-
ensurePhaseDir(phaseId: string): Promise<void>;
|
|
157
|
-
writePhaseFile(phaseId: string, filename: string, content: string): Promise<void>;
|
|
158
|
-
readPhaseFile(phaseId: string, filename: string): Promise<string>;
|
|
155
|
+
updatePhaseStatus(phaseId: string, newStatus: PhaseStatus, force?: boolean): Promise<void>;
|
|
159
156
|
load(): Promise<BrainforgeState>;
|
|
160
157
|
save(newState?: BrainforgeState): Promise<void>;
|
|
161
158
|
init(project: ProjectConfig): Promise<BrainforgeState>;
|
|
@@ -752,8 +749,8 @@ interface BugEntry {
|
|
|
752
749
|
}
|
|
753
750
|
interface CommandResult {
|
|
754
751
|
command: string;
|
|
755
|
-
status: 'passed' | 'failed';
|
|
756
|
-
exitCode: number;
|
|
752
|
+
status: 'passed' | 'failed' | 'timeout';
|
|
753
|
+
exitCode: number | null;
|
|
757
754
|
stdout: string;
|
|
758
755
|
stderr: string;
|
|
759
756
|
duration: number;
|
|
@@ -769,6 +766,7 @@ interface VerifyResult {
|
|
|
769
766
|
commandResults?: CommandResult[];
|
|
770
767
|
}
|
|
771
768
|
declare class VerificationEngine {
|
|
769
|
+
private timeoutMs;
|
|
772
770
|
detectAvailableCommands(cwd: string): Promise<string[]>;
|
|
773
771
|
runCommands(commands: string[], cwd: string): Promise<CommandResult[]>;
|
|
774
772
|
buildVerifyPrompt(phase: Phase, stack?: StackInfo, detectedCommands?: string[]): string;
|
package/dist/index.js
CHANGED
|
@@ -166,7 +166,25 @@ async function fileExists(p) {
|
|
|
166
166
|
// src/state/manager.ts
|
|
167
167
|
var STATE_DIR = ".brainforge";
|
|
168
168
|
var STATE_FILE = "core.json";
|
|
169
|
-
var
|
|
169
|
+
var VALID_TRANSITIONS = {
|
|
170
|
+
pending: ["active", "draft"],
|
|
171
|
+
draft: ["discussed", "active"],
|
|
172
|
+
discussed: ["planned", "active"],
|
|
173
|
+
active: ["discussed", "planned", "blocked", "executing"],
|
|
174
|
+
planned: ["executing", "checked", "active"],
|
|
175
|
+
checked: ["executing", "active"],
|
|
176
|
+
executing: ["executed", "failed", "blocked"],
|
|
177
|
+
executed: ["verified", "failed", "needs-manual-verification"],
|
|
178
|
+
"needs-manual-verification": ["verified", "failed"],
|
|
179
|
+
verified: ["shipped", "failed"],
|
|
180
|
+
failed: ["fixed", "active", "planned"],
|
|
181
|
+
fixed: ["verified", "executing"],
|
|
182
|
+
shipped: [],
|
|
183
|
+
// Terminal state
|
|
184
|
+
completed: [],
|
|
185
|
+
// Terminal state
|
|
186
|
+
blocked: ["active", "failed"]
|
|
187
|
+
};
|
|
170
188
|
var StateManager = class {
|
|
171
189
|
constructor(workingDir) {
|
|
172
190
|
this.workingDir = workingDir;
|
|
@@ -175,20 +193,23 @@ var StateManager = class {
|
|
|
175
193
|
workingDir;
|
|
176
194
|
statePath;
|
|
177
195
|
state = null;
|
|
178
|
-
getPhaseDir
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
196
|
+
// ... (getPhaseDir, ensurePhaseDir, writePhaseFile, readPhaseFile unchanged)
|
|
197
|
+
async updatePhaseStatus(phaseId, newStatus, force = false) {
|
|
198
|
+
const phase = this.get().phases.find((p) => p.id === phaseId);
|
|
199
|
+
if (!phase) throw new Error(`Phase "${phaseId}" not found.`);
|
|
200
|
+
if (!force) {
|
|
201
|
+
const allowed = VALID_TRANSITIONS[phase.status] || [];
|
|
202
|
+
if (!allowed.includes(newStatus) && phase.status !== newStatus) {
|
|
203
|
+
throw new Error(`Invalid transition: cannot move phase from "${phase.status}" to "${newStatus}".`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
phase.status = newStatus;
|
|
207
|
+
if (newStatus === "shipped" || newStatus === "completed") {
|
|
208
|
+
phase.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
209
|
+
}
|
|
210
|
+
await this.save();
|
|
191
211
|
}
|
|
212
|
+
// ... (rest of the methods)
|
|
192
213
|
async load() {
|
|
193
214
|
const raw = await fs3.readFile(this.statePath, "utf-8");
|
|
194
215
|
this.state = JSON.parse(raw);
|
|
@@ -7370,6 +7391,8 @@ import { exec as exec2 } from "child_process";
|
|
|
7370
7391
|
import { promisify as promisify2 } from "util";
|
|
7371
7392
|
var execAsync2 = promisify2(exec2);
|
|
7372
7393
|
var VerificationEngine = class {
|
|
7394
|
+
timeoutMs = 5 * 60 * 1e3;
|
|
7395
|
+
// 5 minutes default
|
|
7373
7396
|
async detectAvailableCommands(cwd) {
|
|
7374
7397
|
const commands = [];
|
|
7375
7398
|
try {
|
|
@@ -7425,7 +7448,7 @@ var VerificationEngine = class {
|
|
|
7425
7448
|
for (const command of commands) {
|
|
7426
7449
|
const start = Date.now();
|
|
7427
7450
|
try {
|
|
7428
|
-
const { stdout, stderr } = await execAsync2(command, { cwd });
|
|
7451
|
+
const { stdout, stderr } = await execAsync2(command, { cwd, timeout: this.timeoutMs });
|
|
7429
7452
|
results.push({
|
|
7430
7453
|
command,
|
|
7431
7454
|
status: "passed",
|
|
@@ -7435,10 +7458,11 @@ var VerificationEngine = class {
|
|
|
7435
7458
|
duration: Date.now() - start
|
|
7436
7459
|
});
|
|
7437
7460
|
} catch (err) {
|
|
7461
|
+
const isTimeout = err.signal === "SIGTERM" || err.killed;
|
|
7438
7462
|
results.push({
|
|
7439
7463
|
command,
|
|
7440
|
-
status: "failed",
|
|
7441
|
-
exitCode: err.code
|
|
7464
|
+
status: isTimeout ? "timeout" : "failed",
|
|
7465
|
+
exitCode: err.code ?? null,
|
|
7442
7466
|
stdout: err.stdout || "",
|
|
7443
7467
|
stderr: err.stderr || err.message,
|
|
7444
7468
|
duration: Date.now() - start
|
|
@@ -7501,7 +7525,7 @@ ${cmd}
|
|
|
7501
7525
|
let status = "passed";
|
|
7502
7526
|
if (commandResults.length === 0) {
|
|
7503
7527
|
status = "manual-required";
|
|
7504
|
-
} else if (commandResults.some((r) => r.status
|
|
7528
|
+
} else if (commandResults.some((r) => r.status !== "passed") || bugs.some((b) => b.severity === "critical")) {
|
|
7505
7529
|
status = "failed";
|
|
7506
7530
|
}
|
|
7507
7531
|
const passedCount = commandResults.filter((r) => r.status === "passed").length;
|
|
@@ -7522,11 +7546,12 @@ ${cmd}
|
|
|
7522
7546
|
""
|
|
7523
7547
|
];
|
|
7524
7548
|
for (const r of commandResults) {
|
|
7549
|
+
const statusIcon = r.status === "passed" ? "\u{1F7E2} PASSED" : r.status === "timeout" ? "\u23F3 TIMEOUT" : "\u{1F534} FAILED";
|
|
7525
7550
|
lines.push(
|
|
7526
7551
|
`### \`${r.command}\``,
|
|
7527
7552
|
"",
|
|
7528
|
-
`- **Status:** ${
|
|
7529
|
-
`- **Exit code:** ${r.exitCode}`,
|
|
7553
|
+
`- **Status:** ${statusIcon}`,
|
|
7554
|
+
`- **Exit code:** ${r.exitCode ?? "N/A"}`,
|
|
7530
7555
|
`- **Duration:** ${(r.duration / 1e3).toFixed(2)}s`,
|
|
7531
7556
|
"",
|
|
7532
7557
|
"#### stdout",
|