jeo-code 0.11.1 → 0.11.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.
@@ -220,16 +220,18 @@ export async function runTeamEngine(opts: TeamEngineOptions = {}): Promise<{ ok:
220
220
  return { ok: false, reason: err.message };
221
221
  }
222
222
 
223
- // Round-13: verify the plan's hash matches the consensus hash to prevent silent edits after approval
224
- if (planState.consensus_hash) {
225
- const currentHash = createHash("sha256").update(planContent).digest("hex");
226
- if (currentHash !== planState.consensus_hash) {
227
- log(
228
- `[ERROR] Plan file has been modified since it was reviewed by the consensus critic.\n` +
229
- ` Re-run 'jeo ralplan' to let the critic review the updated plan, then approve and execute again.`
230
- );
231
- return { ok: false, reason: "Plan file modified since consensus review" };
232
- }
223
+ // Execution requires the exact reviewed bytes, including for legacy state.
224
+ if (!planState.consensus_hash) {
225
+ log(`[ERROR] Plan lacks a consensus review hash. Re-run 'jeo ralplan', then approve and execute again.`);
226
+ return { ok: false, reason: "Plan lacks a consensus review hash" };
227
+ }
228
+ const currentHash = createHash("sha256").update(planContent).digest("hex");
229
+ if (currentHash !== planState.consensus_hash) {
230
+ log(
231
+ `[ERROR] Plan file has been modified since it was reviewed by the consensus critic.\n` +
232
+ ` Re-run 'jeo ralplan' to let the critic review the updated plan, then approve and execute again.`
233
+ );
234
+ return { ok: false, reason: "Plan file modified since consensus review" };
233
235
  }
234
236
 
235
237
  let rawPlan: any;
@@ -288,6 +290,7 @@ export async function runTeamEngine(opts: TeamEngineOptions = {}): Promise<{ ok:
288
290
  skill: "team" as const,
289
291
  slug: planState.slug,
290
292
  plan_path: planPath,
293
+ consensus_hash: planState.consensus_hash,
291
294
  completed_tasks: [],
292
295
  pending_tasks: [...tasks],
293
296
  };
@@ -302,8 +305,9 @@ export async function runTeamEngine(opts: TeamEngineOptions = {}): Promise<{ ok:
302
305
  // Round-7 #1 (architect ref 7-Round7Workflow): a team-state left over from a
303
306
  // PREVIOUS plan must never be reused — pending=[] from plan A would make plan B
304
307
  // no-op into a false "all executed" success, and a mid-flight leftover would run
305
- // plan-A task text under plan-B roles. A different plan reinitializes execution.
306
- if (teamState.plan_path !== planPath || teamState.slug !== planState.slug) {
308
+ // plan-A task text under plan-B roles. Changed bytes or legacy unbound state
309
+ // also reinitialize execution, even when the plan path and slug are unchanged.
310
+ if (teamState.plan_path !== planPath || teamState.slug !== planState.slug || teamState.consensus_hash !== planState.consensus_hash) {
307
311
  log(`${categoryBadge("progress")} New plan detected (${planPath}) — restarting execution from its task list.`);
308
312
  teamState = {
309
313
  active: true,
@@ -311,6 +315,7 @@ export async function runTeamEngine(opts: TeamEngineOptions = {}): Promise<{ ok:
311
315
  skill: "team" as const,
312
316
  slug: planState.slug,
313
317
  plan_path: planPath,
318
+ consensus_hash: planState.consensus_hash,
314
319
  completed_tasks: [],
315
320
  pending_tasks: [...tasks],
316
321
  };
@@ -209,5 +209,6 @@ export async function runUltragoalEngine(opts: UltragoalEngineOptions = {}): Pro
209
209
  }
210
210
 
211
211
  export async function runUltragoalCommand(): Promise<void> {
212
- await runUltragoalEngine();
212
+ const result = await runUltragoalEngine();
213
+ if (!result.ok) process.exitCode = 1;
213
214
  }