@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 CHANGED
@@ -152,10 +152,7 @@ declare class StateManager {
152
152
  private statePath;
153
153
  private state;
154
154
  constructor(workingDir: string);
155
- getPhaseDir(phaseId: string): string;
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 PHASES_DIR = "phases";
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(phaseId) {
179
- return path3.join(this.workingDir, STATE_DIR, PHASES_DIR, phaseId);
180
- }
181
- async ensurePhaseDir(phaseId) {
182
- const dir = this.getPhaseDir(phaseId);
183
- await fs3.mkdir(dir, { recursive: true });
184
- }
185
- async writePhaseFile(phaseId, filename, content) {
186
- await this.ensurePhaseDir(phaseId);
187
- await fs3.writeFile(path3.join(this.getPhaseDir(phaseId), filename), content, "utf-8");
188
- }
189
- async readPhaseFile(phaseId, filename) {
190
- return fs3.readFile(path3.join(this.getPhaseDir(phaseId), filename), "utf-8");
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 || 1,
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 === "failed") || bugs.some((b) => b.severity === "critical")) {
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:** ${r.status === "passed" ? "\u{1F7E2} PASSED" : "\u{1F534} FAILED"}`,
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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainforge/core",
3
- "version": "3.1.13",
3
+ "version": "3.1.14",
4
4
  "description": "Core engine for BrainForge AI — state management, AST mapper, skills, and AI adapters",
5
5
  "type": "module",
6
6
  "license": "MIT",