zelari-code 2.8.0 → 2.9.0

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.
@@ -22068,7 +22068,7 @@ function extractToolObjects(text) {
22068
22068
  }
22069
22069
  return out;
22070
22070
  }
22071
- var AgentHarness, DOOM_LOOP_THRESHOLD;
22071
+ var BUILD_LIVENESS_RECOVERY_PROMPT, AgentHarness, DOOM_LOOP_THRESHOLD;
22072
22072
  var init_AgentHarness = __esm({
22073
22073
  "packages/core/dist/core/AgentHarness.js"() {
22074
22074
  "use strict";
@@ -22079,6 +22079,7 @@ var init_AgentHarness = __esm({
22079
22079
  init_requestSnapshot();
22080
22080
  init_textLoopDetect();
22081
22081
  init_textLoopDetect();
22082
+ BUILD_LIVENESS_RECOVERY_PROMPT = "[build-liveness] The requested task requires an on-disk implementation, but no successful project mutation has occurred yet. Continue working. Inspect only as needed, then make the required change with an available mutating tool. Do not merely describe a patch or claim completion.";
22082
22083
  AgentHarness = class {
22083
22084
  config;
22084
22085
  eventBus;
@@ -22115,6 +22116,13 @@ var init_AgentHarness = __esm({
22115
22116
  growth = emptyContextGrowthStats();
22116
22117
  /** Ephemeral per-run context; never appended to `config.messages`. */
22117
22118
  activeMemoryContext = "";
22119
+ buildProgress = {
22120
+ toolCalls: 0,
22121
+ mutationsAttempted: 0,
22122
+ mutationsSucceeded: 0,
22123
+ verificationCalls: 0,
22124
+ recoveries: 0
22125
+ };
22118
22126
  constructor(config2) {
22119
22127
  this.config = config2;
22120
22128
  this.eventBus = config2.eventBus;
@@ -22145,6 +22153,33 @@ var init_AgentHarness = __esm({
22145
22153
  getMessages() {
22146
22154
  return this.config.messages;
22147
22155
  }
22156
+ /** Immutable snapshot of host-observed build progress for this run. */
22157
+ getBuildProgress() {
22158
+ return { ...this.buildProgress };
22159
+ }
22160
+ toolPermissions(toolName) {
22161
+ return this.config.toolRegistry?.get(toolName)?.permissions ?? [];
22162
+ }
22163
+ isMutationTool(toolName, args) {
22164
+ const permissions = this.toolPermissions(toolName);
22165
+ if (!permissions.includes("write"))
22166
+ return false;
22167
+ if (args.dryRun === true)
22168
+ return false;
22169
+ return classifyToolConcurrency({
22170
+ toolName,
22171
+ args,
22172
+ permissions,
22173
+ registered: Boolean(this.config.toolRegistry?.get(toolName))
22174
+ }) === "exclusive";
22175
+ }
22176
+ recordSuccessfulTool(toolName, args) {
22177
+ const permissions = this.toolPermissions(toolName);
22178
+ if (this.isMutationTool(toolName, args))
22179
+ this.buildProgress.mutationsSucceeded += 1;
22180
+ if (permissions.includes("execute"))
22181
+ this.buildProgress.verificationCalls += 1;
22182
+ }
22148
22183
  /**
22149
22184
  * Member identity fields (memberId + memberName) to merge into every
22150
22185
  * event payload. Returns an empty object when the run is a direct
@@ -22386,6 +22421,13 @@ ${shared2.content}`,
22386
22421
  this.toolCallCounts = /* @__PURE__ */ new Map();
22387
22422
  this.textToolReentries = 0;
22388
22423
  this.growth = emptyContextGrowthStats();
22424
+ this.buildProgress = {
22425
+ toolCalls: 0,
22426
+ mutationsAttempted: 0,
22427
+ mutationsSucceeded: 0,
22428
+ verificationCalls: 0,
22429
+ recoveries: 0
22430
+ };
22389
22431
  const memoryWarning = await this.prepareMemoryContext();
22390
22432
  const startEvent = createBrainEvent("agent_start", this.sessionId, {
22391
22433
  model: this.config.model,
@@ -22410,7 +22452,11 @@ ${shared2.content}`,
22410
22452
  this.emit(initialMsgStart);
22411
22453
  yield initialMsgStart;
22412
22454
  let initialTurnLength = 0;
22413
- const initialFinishRef = { value: "stop" };
22455
+ const initialFinishRef = {
22456
+ value: "stop",
22457
+ clarificationRequested: false,
22458
+ providerError: false
22459
+ };
22414
22460
  const initialUsageRef = { value: null };
22415
22461
  for await (const ev of this.runSingleTurn(initialMessageId, initialFinishRef, initialUsageRef)) {
22416
22462
  if (ev.type === "message_delta") {
@@ -22437,16 +22483,51 @@ ${shared2.content}`,
22437
22483
  const hardCap = this.maxToolLoopHardCap;
22438
22484
  let extensions = 0;
22439
22485
  const maxExtensions = 8;
22440
- while (!this.cancelled && !hadError && toolLoopTurns < softCap && initialFinishRef.value === "tool_calls") {
22486
+ const maxBuildRecoveries = Math.max(0, Math.min(10, this.config.buildLiveness?.maxRecoveries ?? 2));
22487
+ const planBuildRecovery = (turn) => {
22488
+ if (!this.config.buildLiveness?.mutationRequired)
22489
+ return null;
22490
+ if (this.buildProgress.mutationsSucceeded > 0)
22491
+ return null;
22492
+ if (turn.value !== "stop" || turn.clarificationRequested || turn.providerError)
22493
+ return null;
22494
+ if (this.buildProgress.recoveries >= maxBuildRecoveries)
22495
+ return null;
22496
+ this.buildProgress.recoveries += 1;
22497
+ this.config.messages.push({ role: "user", content: BUILD_LIVENESS_RECOVERY_PROMPT });
22498
+ return {
22499
+ purpose: "build-recovery",
22500
+ toolChoice: "required",
22501
+ recoveryAttempt: this.buildProgress.recoveries
22502
+ };
22503
+ };
22504
+ let lastTurnState = initialFinishRef;
22505
+ let recoveryGeneration = planBuildRecovery(initialFinishRef);
22506
+ while (!this.cancelled && !hadError && toolLoopTurns < hardCap && (toolLoopTurns < softCap || recoveryGeneration !== null) && (initialFinishRef.value === "tool_calls" || recoveryGeneration !== null)) {
22441
22507
  toolLoopTurns++;
22508
+ if (recoveryGeneration) {
22509
+ const recoveryEvent = createBrainEvent("error", this.sessionId, {
22510
+ severity: "recoverable",
22511
+ message: `BUILD liveness recovery ${recoveryGeneration.recoveryAttempt}/${maxBuildRecoveries}: no successful mutation observed; continuing instead of completing.`,
22512
+ code: "build_liveness_recovery"
22513
+ });
22514
+ this.emit(recoveryEvent);
22515
+ yield recoveryEvent;
22516
+ }
22442
22517
  const turnMessageId = crypto.randomUUID();
22443
22518
  const msgStart = createBrainEvent("message_start", this.sessionId, { messageId: turnMessageId, role: "assistant", ...this.memberFields() });
22444
22519
  this.emit(msgStart);
22445
22520
  yield msgStart;
22446
22521
  let turnLength = 0;
22447
- const turnFinishRef = { value: "stop" };
22522
+ const turnFinishRef = {
22523
+ value: "stop",
22524
+ clarificationRequested: false,
22525
+ providerError: false
22526
+ };
22448
22527
  const turnUsageRef = { value: null };
22449
- for await (const ev of this.runSingleTurn(turnMessageId, turnFinishRef, turnUsageRef)) {
22528
+ const generation = recoveryGeneration ?? void 0;
22529
+ recoveryGeneration = null;
22530
+ for await (const ev of this.runSingleTurn(turnMessageId, turnFinishRef, turnUsageRef, generation)) {
22450
22531
  if (ev.type === "message_delta") {
22451
22532
  turnLength += ev.delta.length;
22452
22533
  } else if (ev.type === "error") {
@@ -22466,6 +22547,10 @@ ${shared2.content}`,
22466
22547
  this.emit(msgEnd);
22467
22548
  yield msgEnd;
22468
22549
  initialFinishRef.value = turnFinishRef.value;
22550
+ initialFinishRef.clarificationRequested = turnFinishRef.clarificationRequested;
22551
+ initialFinishRef.providerError = turnFinishRef.providerError;
22552
+ lastTurnState = turnFinishRef;
22553
+ recoveryGeneration = planBuildRecovery(turnFinishRef);
22469
22554
  if (hadError || this.cancelled)
22470
22555
  break;
22471
22556
  if (initialFinishRef.value === "tool_calls" && toolLoopTurns >= softCap && toolLoopTurns < hardCap && extensions < maxExtensions) {
@@ -22489,10 +22574,23 @@ ${shared2.content}`,
22489
22574
  if (!this.cancelled && !hadError && initialFinishRef.value === "tool_calls" && hitHardCap) {
22490
22575
  yield* this.runFinalAnswerTurn();
22491
22576
  }
22577
+ if (!this.cancelled && !hadError && this.config.buildLiveness?.mutationRequired && this.buildProgress.mutationsSucceeded === 0 && !lastTurnState.clarificationRequested) {
22578
+ hadError = true;
22579
+ const providerFailed = lastTurnState.providerError;
22580
+ const stalled = createBrainEvent("error", this.sessionId, {
22581
+ severity: "fatal",
22582
+ message: providerFailed ? "BUILD provider call failed before any successful on-disk mutation was observed." : `BUILD stalled after ${this.buildProgress.recoveries} recovery turn(s): the task required an on-disk mutation, but no successful mutation was observed.`,
22583
+ code: providerFailed ? "build_liveness_provider_error" : "build_liveness_stalled"
22584
+ });
22585
+ this.emit(stalled);
22586
+ yield stalled;
22587
+ }
22492
22588
  let turns = 0;
22493
22589
  while (turns < this.maxQueuedIterations) {
22494
22590
  if (this.cancelled)
22495
22591
  break;
22592
+ if (hadError)
22593
+ break;
22496
22594
  if (this.queue.length === 0)
22497
22595
  break;
22498
22596
  const queuedPrompt = this.dequeueNext();
@@ -22508,7 +22606,11 @@ ${shared2.content}`,
22508
22606
  this.emit(msgStart);
22509
22607
  yield msgStart;
22510
22608
  let turnLength = 0;
22511
- const turnFinishRef = { value: "stop" };
22609
+ const turnFinishRef = {
22610
+ value: "stop",
22611
+ clarificationRequested: false,
22612
+ providerError: false
22613
+ };
22512
22614
  const turnUsageRef = { value: null };
22513
22615
  for await (const ev of this.runSingleTurn(turnMessageId, turnFinishRef, turnUsageRef)) {
22514
22616
  if (ev.type === "message_delta") {
@@ -22570,17 +22672,26 @@ ${shared2.content}`,
22570
22672
  }
22571
22673
  /** Build a provider-only view with memory after the stable system prefix. */
22572
22674
  messagesForProvider() {
22573
- if (!this.activeMemoryContext)
22574
- return this.config.messages;
22675
+ let messages = this.config.messages;
22575
22676
  let prefixEnd = 0;
22576
- while (prefixEnd < this.config.messages.length && this.config.messages[prefixEnd]?.role === "system") {
22577
- prefixEnd += 1;
22677
+ if (this.activeMemoryContext) {
22678
+ while (prefixEnd < messages.length && messages[prefixEnd]?.role === "system") {
22679
+ prefixEnd += 1;
22680
+ }
22681
+ messages = [
22682
+ ...messages.slice(0, prefixEnd),
22683
+ { role: "system", content: this.activeMemoryContext },
22684
+ ...messages.slice(prefixEnd)
22685
+ ];
22686
+ }
22687
+ if (!this.config.requestTail)
22688
+ return messages;
22689
+ try {
22690
+ const tail2 = this.config.requestTail();
22691
+ return tail2.length > 0 ? [...messages, ...tail2] : messages;
22692
+ } catch {
22693
+ return messages;
22578
22694
  }
22579
- return [
22580
- ...this.config.messages.slice(0, prefixEnd),
22581
- { role: "system", content: this.activeMemoryContext },
22582
- ...this.config.messages.slice(prefixEnd)
22583
- ];
22584
22695
  }
22585
22696
  /**
22586
22697
  * v1.36.0: capture a deterministic snapshot of the routed request just
@@ -22614,17 +22725,19 @@ ${shared2.content}`,
22614
22725
  * Extracted from the original monolithic `run()` body to enable
22615
22726
  * the queue-draining loop in Task 18.1.
22616
22727
  */
22617
- async *runSingleTurn(messageId, finishRef, usageRef) {
22728
+ async *runSingleTurn(messageId, finishRef, usageRef, generation) {
22618
22729
  try {
22619
22730
  const requestMessages = this.messagesForProvider();
22620
- this.emitSnapshot(this.config.tools, void 0, requestMessages);
22731
+ this.emitSnapshot(this.config.tools, generation, requestMessages);
22621
22732
  recordRequest(this.growth, requestMessages);
22622
22733
  const stream = this.config.providerStream({
22623
22734
  messages: requestMessages,
22624
22735
  model: this.config.model,
22625
22736
  provider: this.config.provider,
22626
22737
  tools: this.config.tools,
22627
- signal: this.activeController?.signal
22738
+ signal: this.activeController?.signal,
22739
+ conversationId: this.sessionId,
22740
+ generation
22628
22741
  });
22629
22742
  let toolCallsThisTurn = 0;
22630
22743
  const maxToolCalls = this.config.maxToolCallsPerTurn;
@@ -22690,6 +22803,10 @@ ${shared2.content}`,
22690
22803
  yield thinkEvent;
22691
22804
  } else if (delta.kind === "tool_call") {
22692
22805
  toolCallsThisTurn++;
22806
+ this.buildProgress.toolCalls += 1;
22807
+ if (this.isMutationTool(delta.toolName, delta.args)) {
22808
+ this.buildProgress.mutationsAttempted += 1;
22809
+ }
22693
22810
  turnToolCalls.push({ id: delta.toolCallId, name: delta.toolName, args: delta.args });
22694
22811
  const toolStartEvent = createBrainEvent("tool_execution_start", this.sessionId, {
22695
22812
  toolCallId: delta.toolCallId,
@@ -22743,11 +22860,18 @@ ${cached2}`
22743
22860
  this.toolCallCache.set(item.cacheKey, item.content);
22744
22861
  }
22745
22862
  }
22863
+ for (let i = 0; i < executed.length; i++) {
22864
+ const item = executed[i];
22865
+ const pending = pendingNativeTools[i];
22866
+ if (!item.isError)
22867
+ this.recordSuccessfulTool(pending.toolName, pending.args);
22868
+ }
22746
22869
  pendingNativeTools.length = 0;
22747
22870
  }
22748
22871
  const clarificationPause = /---QUESTION---/.test(turnText) && /"choices"\s*:\s*\[/.test(turnText);
22749
22872
  if (clarificationPause) {
22750
22873
  finishRef.value = "stop";
22874
+ finishRef.clarificationRequested = true;
22751
22875
  }
22752
22876
  const textTools = clarificationPause ? [] : parseTextToolCalls(turnText);
22753
22877
  const toolsToRun = textTools.filter((tt) => {
@@ -22770,6 +22894,10 @@ ${cached2}`
22770
22894
  if (typeof maxToolCalls === "number" && toolCallsThisTurn + 1 > maxToolCalls)
22771
22895
  break;
22772
22896
  toolCallsThisTurn++;
22897
+ this.buildProgress.toolCalls += 1;
22898
+ if (this.isMutationTool(tt.name, tt.args)) {
22899
+ this.buildProgress.mutationsAttempted += 1;
22900
+ }
22773
22901
  const toolCallId = `text-${crypto.randomUUID().slice(0, 8)}`;
22774
22902
  turnToolCalls.push({ id: toolCallId, name: tt.name, args: tt.args });
22775
22903
  const startEv = createBrainEvent("tool_execution_start", this.sessionId, {
@@ -22831,6 +22959,8 @@ ${cached2}`
22831
22959
  this.emit(endEv);
22832
22960
  yield endEv;
22833
22961
  turnToolResults.push({ toolCallId, content: resultStr });
22962
+ if (!isError)
22963
+ this.recordSuccessfulTool(tt.name, tt.args);
22834
22964
  executedAny = true;
22835
22965
  }
22836
22966
  if (executedAny) {
@@ -22868,6 +22998,7 @@ ${cached2}`
22868
22998
  }
22869
22999
  break;
22870
23000
  } else if (delta.kind === "error") {
23001
+ finishRef.providerError = true;
22871
23002
  const errEvent = createBrainEvent("error", this.sessionId, {
22872
23003
  severity: "recoverable",
22873
23004
  message: delta.message
@@ -22880,6 +23011,7 @@ ${cached2}`
22880
23011
  }
22881
23012
  }
22882
23013
  } catch (err) {
23014
+ finishRef.providerError = true;
22883
23015
  const errorMessage = err instanceof Error ? err.message : String(err);
22884
23016
  const errEvent = createBrainEvent("error", this.sessionId, {
22885
23017
  severity: "recoverable",
@@ -22924,7 +23056,11 @@ ${cached2}`
22924
23056
  content: "[system] Hard tool-iteration ceiling reached. Stop calling tools and give a clear status: what is DONE, what remains, and the exact next steps. Use what you already gathered. Do not apologize for the tools."
22925
23057
  });
22926
23058
  let totalLength = 0;
22927
- const finishRef = { value: "stop" };
23059
+ const finishRef = {
23060
+ value: "stop",
23061
+ clarificationRequested: false,
23062
+ providerError: false
23063
+ };
22928
23064
  const usageRef = { value: null };
22929
23065
  const requestMessages = this.messagesForProvider();
22930
23066
  recordRequest(this.growth, requestMessages);
@@ -22935,7 +23071,8 @@ ${cached2}`
22935
23071
  model: this.config.model,
22936
23072
  provider: this.config.provider,
22937
23073
  tools: [],
22938
- signal: this.activeController?.signal
23074
+ signal: this.activeController?.signal,
23075
+ conversationId: this.sessionId
22939
23076
  });
22940
23077
  for await (const delta of stream) {
22941
23078
  if (this.cancelled)
@@ -23506,6 +23643,7 @@ var init_hooks = __esm({
23506
23643
  var harness_exports = {};
23507
23644
  __export(harness_exports, {
23508
23645
  AgentHarness: () => AgentHarness,
23646
+ BUILD_LIVENESS_RECOVERY_PROMPT: () => BUILD_LIVENESS_RECOVERY_PROMPT,
23509
23647
  DOOM_LOOP_THRESHOLD: () => DOOM_LOOP_THRESHOLD,
23510
23648
  LifecycleHookRunner: () => LifecycleHookRunner,
23511
23649
  SessionJsonlWriter: () => SessionJsonlWriter,
@@ -29771,8 +29909,8 @@ var init_types8 = __esm({
29771
29909
  // observation, digest). Not model-surface. Schema review per ADR-0021.
29772
29910
  "verification.evidence",
29773
29911
  // 2.6 Track B (resource-aware execution, doc §9-§12): host-owned resource
29774
- // state. `resource.snapshot` is model-surface with LATEST-ONLY projection
29775
- // (doc §10.2 see modelSurface.ts); limit/reserve events are state-only.
29912
+ // state. `resource.snapshot` is rendered only as a volatile request tail;
29913
+ // it never enters the persistent model-history projection.
29776
29914
  "resource.epoch_started",
29777
29915
  "resource.snapshot",
29778
29916
  "resource.limit_reached",
@@ -30206,13 +30344,6 @@ function deriveMessages(events, options = {}) {
30206
30344
  seq: e.seq
30207
30345
  });
30208
30346
  break;
30209
- case "resource.snapshot":
30210
- messages.push({
30211
- role: "system",
30212
- content: formatResourceSnapshot(d),
30213
- seq: e.seq
30214
- });
30215
- break;
30216
30347
  }
30217
30348
  }
30218
30349
  pushDueCheckpoints(Number.POSITIVE_INFINITY);
@@ -30239,7 +30370,7 @@ function pairToolCalls(events) {
30239
30370
  }
30240
30371
  return ordered;
30241
30372
  }
30242
- var MODEL_SURFACE_KINDS, LATEST_ONLY_SURFACE_KINDS;
30373
+ var MODEL_SURFACE_KINDS, EPHEMERAL_TAIL_EVENT_KINDS, LATEST_ONLY_SURFACE_KINDS;
30243
30374
  var init_modelSurface = __esm({
30244
30375
  "packages/core/dist/session/modelSurface.js"() {
30245
30376
  "use strict";
@@ -30249,11 +30380,12 @@ var init_modelSurface = __esm({
30249
30380
  "assistant.message",
30250
30381
  "tool.call",
30251
30382
  "tool.result",
30252
- "session.compacted",
30253
- // 2.6: budget awareness for the model (latest-only projection below).
30383
+ "session.compacted"
30384
+ ]);
30385
+ EPHEMERAL_TAIL_EVENT_KINDS = /* @__PURE__ */ new Set([
30254
30386
  "resource.snapshot"
30255
30387
  ]);
30256
- LATEST_ONLY_SURFACE_KINDS = /* @__PURE__ */ new Set(["resource.snapshot"]);
30388
+ LATEST_ONLY_SURFACE_KINDS = /* @__PURE__ */ new Set();
30257
30389
  }
30258
30390
  });
30259
30391
 
@@ -33263,6 +33395,7 @@ __export(dist_exports, {
33263
33395
  AgentHarness: () => AgentHarness,
33264
33396
  BENNETTS_RAZOR: () => BENNETTS_RAZOR,
33265
33397
  BENNETTS_RAZOR_SHORT: () => BENNETTS_RAZOR_SHORT,
33398
+ BUILD_LIVENESS_RECOVERY_PROMPT: () => BUILD_LIVENESS_RECOVERY_PROMPT,
33266
33399
  BUILT_IN_PROFILES: () => BUILT_IN_PROFILES,
33267
33400
  BonConfigSchema: () => BonConfigSchema,
33268
33401
  BudgetPressureSchema: () => BudgetPressureSchema,
@@ -33293,6 +33426,7 @@ __export(dist_exports, {
33293
33426
  DefaultMemorySanitizer: () => DefaultMemorySanitizer,
33294
33427
  DefaultMemoryService: () => DefaultMemoryService,
33295
33428
  DeterministicCheckSchema: () => DeterministicCheckSchema,
33429
+ EPHEMERAL_TAIL_EVENT_KINDS: () => EPHEMERAL_TAIL_EVENT_KINDS,
33296
33430
  EVENT_BACKED_EVIDENCE_TIERS: () => EVENT_BACKED_EVIDENCE_TIERS,
33297
33431
  EXPERIMENTAL_FLAGS: () => EXPERIMENTAL_FLAGS,
33298
33432
  EventBus: () => EventBus,
@@ -34875,7 +35009,7 @@ var init_sessionSpine = __esm({
34875
35009
  data: { ...snapshot }
34876
35010
  }).then(() => void 0);
34877
35011
  }
34878
- /** Latest emitted resource snapshot (the model-visible one), or null. */
35012
+ /** Latest emitted resource snapshot (available for request-tail injection). */
34879
35013
  latestResourceSnapshot() {
34880
35014
  return this.budgetRuntime?.latestEmitted() ?? null;
34881
35015
  }
@@ -36968,6 +37102,10 @@ async function runTentacle(opts) {
36968
37102
  tools: sub.tools,
36969
37103
  toolRegistry: sub.registry,
36970
37104
  providerStream: sub.providerStream,
37105
+ buildLiveness: {
37106
+ mutationRequired: agent === "general",
37107
+ maxRecoveries: 2
37108
+ },
36971
37109
  cwd: runCwd,
36972
37110
  maxToolCallsPerTurn: maxToolCalls,
36973
37111
  maxToolLoopIterations: Math.max(12, maxToolCalls + 4),
@@ -40475,44 +40613,120 @@ var init_semantic2 = __esm({
40475
40613
  });
40476
40614
 
40477
40615
  // src/cli/provider/capabilities.ts
40478
- function resolveHarnessProfile(model) {
40479
- if (model && DEEPSEEK_V4_RE.test(model)) return "deepseek-v4";
40616
+ function frozenProfile(input) {
40617
+ if (input.reasoning.levels) Object.freeze(input.reasoning.levels);
40618
+ Object.freeze(input.reasoning);
40619
+ Object.freeze(input.promptCache);
40620
+ Object.freeze(input.toolCalling);
40621
+ Object.freeze(input.buildRecovery);
40622
+ Object.freeze(input.sampling);
40623
+ Object.freeze(input.compaction);
40624
+ return Object.freeze(input);
40625
+ }
40626
+ function resolveHarnessProfile(model, providerId) {
40627
+ const provider = providerId?.trim().toLowerCase();
40628
+ if (provider === "deepseek") return "deepseek-v4";
40629
+ if (provider === "grok") return "grok";
40630
+ if (provider === "minimax") return "minimax";
40631
+ if (provider === "glm") return "glm";
40632
+ if (model && DEEPSEEK_RE.test(model)) return "deepseek-v4";
40633
+ if (model && GROK_RE.test(model)) return "grok";
40634
+ if (model && MINIMAX_RE.test(model)) return "minimax";
40635
+ if (model && GLM_RE.test(model)) return "glm";
40480
40636
  return "default";
40481
40637
  }
40482
- function capabilitiesFor(model) {
40483
- return resolveHarnessProfile(model) === "deepseek-v4" ? DEEPSEEK_V4_CAPS : DEFAULT_CAPS;
40638
+ function capabilitiesFor(model, providerId) {
40639
+ switch (resolveHarnessProfile(model, providerId)) {
40640
+ case "deepseek-v4":
40641
+ return DEEPSEEK_V4_CAPS;
40642
+ case "grok":
40643
+ return GROK_CAPS;
40644
+ case "minimax":
40645
+ return model && MINIMAX_M3_RE.test(model) ? MINIMAX_M3_CAPS : MINIMAX_M2_CAPS;
40646
+ case "glm":
40647
+ return GLM_CAPS;
40648
+ default:
40649
+ return DEFAULT_CAPS;
40650
+ }
40484
40651
  }
40485
- var DEFAULT_CAPS, DEEPSEEK_V4_CAPS, DEEPSEEK_V4_RE;
40652
+ var SHARED_COMPACTION, DEFAULT_CAPS, DEEPSEEK_V4_CAPS, GROK_CAPS, MINIMAX_M3_CAPS, MINIMAX_M2_CAPS, GLM_CAPS, DEEPSEEK_RE, GROK_RE, MINIMAX_RE, MINIMAX_M3_RE, GLM_RE;
40486
40653
  var init_capabilities = __esm({
40487
40654
  "src/cli/provider/capabilities.ts"() {
40488
40655
  "use strict";
40489
- DEFAULT_CAPS = Object.freeze({
40656
+ SHARED_COMPACTION = { warnAt: 0.7, compactAt: 0.85, hardAt: 0.95 };
40657
+ DEFAULT_CAPS = frozenProfile({
40490
40658
  contextWindow: 4e5,
40491
- reasoning: Object.freeze({
40492
- supported: true,
40493
- levels: Object.freeze(["low", "medium", "high"]),
40494
- replayReasoning: true
40495
- }),
40496
- promptCache: Object.freeze({ supported: true, pricedCacheRead: false }),
40497
- toolCalling: Object.freeze({ parallel: true }),
40498
- sampling: Object.freeze({ temperature: 0.7 }),
40499
- compaction: Object.freeze({ warnAt: 0.7, compactAt: 0.85, hardAt: 0.95 }),
40659
+ reasoning: { supported: true, levels: ["low", "medium", "high"], replayReasoning: true },
40660
+ promptCache: { supported: true, pricedCacheRead: false },
40661
+ toolCalling: { parallel: true },
40662
+ buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
40663
+ sampling: { temperature: 0.7 },
40664
+ compaction: { ...SHARED_COMPACTION },
40500
40665
  profile: "default"
40501
40666
  });
40502
- DEEPSEEK_V4_CAPS = Object.freeze({
40667
+ DEEPSEEK_V4_CAPS = frozenProfile({
40503
40668
  contextWindow: 1e6,
40504
- reasoning: Object.freeze({
40505
- supported: true,
40506
- levels: Object.freeze(["high", "max"]),
40507
- replayReasoning: true
40508
- }),
40509
- promptCache: Object.freeze({ supported: true, pricedCacheRead: true }),
40510
- toolCalling: Object.freeze({ parallel: true }),
40511
- sampling: Object.freeze({ temperature: 0.7 }),
40512
- compaction: Object.freeze({ warnAt: 0.7, compactAt: 0.85, hardAt: 0.95 }),
40669
+ reasoning: { supported: true, levels: ["high", "max"], replayReasoning: true },
40670
+ promptCache: { supported: true, pricedCacheRead: true },
40671
+ toolCalling: { parallel: true },
40672
+ buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
40673
+ sampling: { temperature: 0.7 },
40674
+ compaction: { ...SHARED_COMPACTION },
40513
40675
  profile: "deepseek-v4"
40514
40676
  });
40515
- DEEPSEEK_V4_RE = /^deepseek-v4(\.|-|$)/i;
40677
+ GROK_CAPS = frozenProfile({
40678
+ contextWindow: 5e5,
40679
+ reasoning: {
40680
+ supported: true,
40681
+ levels: ["low", "medium", "high", "xhigh"],
40682
+ replayReasoning: false
40683
+ },
40684
+ promptCache: {
40685
+ supported: true,
40686
+ pricedCacheRead: true,
40687
+ conversationAffinityHeader: "x-grok-conv-id"
40688
+ },
40689
+ toolCalling: { parallel: true },
40690
+ buildRecovery: { forceToolChoice: true, maxForcedTurns: 1 },
40691
+ sampling: { temperature: 0.7 },
40692
+ compaction: { ...SHARED_COMPACTION },
40693
+ profile: "grok"
40694
+ });
40695
+ MINIMAX_M3_CAPS = frozenProfile({
40696
+ contextWindow: 1e6,
40697
+ reasoning: { supported: true, replayReasoning: true },
40698
+ promptCache: { supported: false, pricedCacheRead: false },
40699
+ toolCalling: { parallel: true },
40700
+ buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
40701
+ sampling: { temperature: 0.7 },
40702
+ compaction: { ...SHARED_COMPACTION },
40703
+ profile: "minimax"
40704
+ });
40705
+ MINIMAX_M2_CAPS = frozenProfile({
40706
+ contextWindow: 204800,
40707
+ reasoning: { supported: true, replayReasoning: true },
40708
+ promptCache: { supported: false, pricedCacheRead: false },
40709
+ toolCalling: { parallel: true },
40710
+ buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
40711
+ sampling: { temperature: 0.7 },
40712
+ compaction: { ...SHARED_COMPACTION },
40713
+ profile: "minimax"
40714
+ });
40715
+ GLM_CAPS = frozenProfile({
40716
+ contextWindow: 2e5,
40717
+ reasoning: { supported: true, replayReasoning: true },
40718
+ promptCache: { supported: true, pricedCacheRead: false },
40719
+ toolCalling: { parallel: true },
40720
+ buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
40721
+ sampling: { temperature: 0.7 },
40722
+ compaction: { ...SHARED_COMPACTION },
40723
+ profile: "glm"
40724
+ });
40725
+ DEEPSEEK_RE = /^deepseek-(?:v4(?:\.|-|$)|chat$|reasoner$)/i;
40726
+ GROK_RE = /^grok(?:\.|-|$)/i;
40727
+ MINIMAX_RE = /^minimax(?:\.|-|$)/i;
40728
+ MINIMAX_M3_RE = /^minimax-m3(?:\.|-|$)/i;
40729
+ GLM_RE = /^glm(?:\.|-|$)/i;
40516
40730
  }
40517
40731
  });
40518
40732
 
@@ -40701,6 +40915,7 @@ ${notes}
40701
40915
  }
40702
40916
  function openaiCompatibleProvider(config2) {
40703
40917
  return async function* (params) {
40918
+ const capabilities = capabilitiesFor(params.model, config2.providerId);
40704
40919
  const vision = modelSupportsVision(params.model);
40705
40920
  const messages = params.messages.map((m) => {
40706
40921
  const cacheable = !(m.role === "user" && m.images && m.images.length > 0);
@@ -40720,7 +40935,7 @@ function openaiCompatibleProvider(config2) {
40720
40935
  model: params.model,
40721
40936
  messages,
40722
40937
  stream: true,
40723
- temperature: generation?.temperature ?? capabilitiesFor(params.model).sampling.temperature,
40938
+ temperature: generation?.temperature ?? capabilities.sampling.temperature,
40724
40939
  // Task G.4.2 — request the provider to send real token usage in
40725
40940
  // the final chunk (gated by `stream_options.include_usage` on the
40726
40941
  // OpenAI-compatible API). Providers that don't honor this (some
@@ -40756,7 +40971,19 @@ function openaiCompatibleProvider(config2) {
40756
40971
  parameters: t.parameters
40757
40972
  }
40758
40973
  }));
40759
- body.tool_choice = "auto";
40974
+ const recoveryAttempt = generation?.recoveryAttempt ?? 1;
40975
+ const forceRecoveryTool = generation?.toolChoice === "required" && capabilities.buildRecovery.forceToolChoice && recoveryAttempt <= capabilities.buildRecovery.maxForcedTurns;
40976
+ body.tool_choice = forceRecoveryTool ? "required" : "auto";
40977
+ }
40978
+ const headers2 = {
40979
+ "Content-Type": "application/json",
40980
+ Authorization: `Bearer ${config2.apiKey}`,
40981
+ ...config2.extraHeaders ?? {}
40982
+ };
40983
+ const affinityHeader = capabilities.promptCache.conversationAffinityHeader;
40984
+ const conversationId = params.conversationId?.trim();
40985
+ if (affinityHeader && conversationId && conversationId.length <= 256 && !/[\u0000-\u001f\u007f]/.test(conversationId)) {
40986
+ headers2[affinityHeader] = conversationId;
40760
40987
  }
40761
40988
  let response;
40762
40989
  let lastErrText = "";
@@ -40781,10 +41008,7 @@ function openaiCompatibleProvider(config2) {
40781
41008
  try {
40782
41009
  response = await fetch(`${config2.baseUrl}/chat/completions`, {
40783
41010
  method: "POST",
40784
- headers: {
40785
- "Content-Type": "application/json",
40786
- Authorization: `Bearer ${config2.apiKey}`
40787
- },
41011
+ headers: headers2,
40788
41012
  body: JSON.stringify(body),
40789
41013
  // Cancel aborts the HTTP request; stream idle is enforced below
40790
41014
  // per-chunk so active multi-minute streams are not killed.
@@ -44946,7 +45170,7 @@ function expectsDiskImplementation(task, phase2, prior) {
44946
45170
  const trimmed = task.trim();
44947
45171
  if (!trimmed) return false;
44948
45172
  if (isShortContinueReply(trimmed)) return true;
44949
- if (/\b(implement|implementa|scrivi|scriviamo|applica|modifica|fix|write|edit|crea|aggiungi|aggiorna|apply|patch)\b/i.test(
45173
+ if (/\b(implement(?:a|are)?|scriv(?:i|iamo|ere)|applica(?:re)?|modifica(?:re)?|fix|write|edit|crea(?:re)?|aggiung(?:i|ere)|aggiorn(?:a|are)|apply|patch|refactor|corregg(?:i|ere)|risolv(?:i|ere)|remove|rimuov(?:i|ere)|rename|rinomina(?:re)?|replace|sostituisc(?:i|e)|delete|elimina(?:re)?|build|costruisc(?:i|e)|convert(?:i|ire)?|migra(?:re)?|upgrade)\b/i.test(
44950
45174
  trimmed
44951
45175
  )) {
44952
45176
  return true;
@@ -51129,6 +51353,7 @@ async function runAgentMissionSlice(deps) {
51129
51353
  tools: toolSpecs,
51130
51354
  toolRegistry: deps.toolRegistry,
51131
51355
  providerStream: deps.providerStream,
51356
+ buildLiveness: { mutationRequired: writeRetry, maxRecoveries: 2 },
51132
51357
  cwd: deps.projectRoot,
51133
51358
  maxToolCallsPerTurn: maxToolCalls,
51134
51359
  maxToolLoopIterations: maxToolLoop,
@@ -62658,12 +62883,12 @@ function estimateHistoryTokens(messages) {
62658
62883
  }
62659
62884
  return n;
62660
62885
  }
62661
- function defaultContextLimitForModel(model) {
62662
- return capabilitiesFor(model).contextWindow;
62886
+ function defaultContextLimitForModel(model, provider) {
62887
+ return capabilitiesFor(model, provider).contextWindow;
62663
62888
  }
62664
- function resolveContextLimit(model) {
62889
+ function resolveContextLimit(model, provider) {
62665
62890
  return envNumber(process.env.ZELARI_CONTEXT_LIMIT, {
62666
- default: defaultContextLimitForModel(model),
62891
+ default: defaultContextLimitForModel(model, provider),
62667
62892
  min: 4e3,
62668
62893
  max: 2e6
62669
62894
  });
@@ -62679,8 +62904,8 @@ function phaseKnobs(phase2) {
62679
62904
  }
62680
62905
  var RESERVED_OUTPUT_TOKENS = 8192;
62681
62906
  async function applyBudgetPolicyAsync(history2, phase2, opts) {
62682
- const contextLimit = resolveContextLimit(opts?.model);
62683
- const compact3 = capabilitiesFor(opts?.model).compaction;
62907
+ const contextLimit = resolveContextLimit(opts?.model, opts?.provider);
62908
+ const compact3 = capabilitiesFor(opts?.model, opts?.provider).compaction;
62684
62909
  const sessionExtra = opts?.sessionTokens ?? 0;
62685
62910
  const warnings = [];
62686
62911
  let { historyTurns, maxToolLoopIterations } = phaseKnobs(phase2);
@@ -62955,8 +63180,11 @@ function messageWasRecompacted(message, history2) {
62955
63180
  if (message.compactedFromSeq === void 0) return false;
62956
63181
  return !history2.some((candidate) => candidate.seq !== void 0 && candidate.seq === message.seq);
62957
63182
  }
62958
- function resourceStatusMessage(payload) {
62959
- return { role: "system", content: formatResourceSnapshot(payload) };
63183
+ function resourceStatusTail(payload) {
63184
+ return payload ? [{ role: "system", content: formatResourceSnapshot(payload) }] : [];
63185
+ }
63186
+ function isLegacyResourceStatus(message) {
63187
+ return message.role === "system" && message.content.startsWith("RESOURCE STATUS");
62960
63188
  }
62961
63189
  async function sessionHistory(session) {
62962
63190
  if (!session || session.status !== "active") return null;
@@ -62967,7 +63195,10 @@ async function sessionHistory(session) {
62967
63195
  async function buildModelContext(input) {
62968
63196
  const derived = await sessionHistory(input.session);
62969
63197
  const source2 = derived ? "session" : "fallback";
62970
- const sourceHistory = derived ?? [...input.fallbackHistory];
63198
+ const sourceHistory = (derived ?? [...input.fallbackHistory]).filter(
63199
+ (message) => !isLegacyResourceStatus(message)
63200
+ );
63201
+ const requestTail = resourceStatusTail(input.resourceSnapshot);
62971
63202
  const inputTokens = estimateHistoryTokens(sourceHistory);
62972
63203
  const requestSurface = input.systemMessages || input.tools ? {
62973
63204
  provider: input.provider ?? "local",
@@ -62977,7 +63208,8 @@ async function buildModelContext(input) {
62977
63208
  } : null;
62978
63209
  let budget = await applyBudgetPolicyAsync(sourceHistory, input.phase, {
62979
63210
  model: input.model,
62980
- sessionTokens: input.sessionTokens,
63211
+ provider: input.provider,
63212
+ sessionTokens: (input.sessionTokens ?? 0) + estimateHistoryTokens(requestTail),
62981
63213
  sessionId: input.sessionId,
62982
63214
  signal: input.signal,
62983
63215
  requestSnapshot: input.requestSnapshot,
@@ -63024,16 +63256,11 @@ async function buildModelContext(input) {
63024
63256
  };
63025
63257
  input.onCompactionMetric?.(compactionMetrics);
63026
63258
  }
63027
- if (input.resourceSnapshot && !history2.some(
63028
- (m) => m.role === "system" && typeof m.content === "string" && m.content.startsWith("RESOURCE STATUS")
63029
- )) {
63030
- history2 = [...history2, resourceStatusMessage(input.resourceSnapshot)];
63031
- }
63032
63259
  if (requestSurface) {
63033
63260
  const measured = measureRequest({
63034
63261
  systemMessages: requestSurface.systemMessages,
63035
63262
  tools: requestSurface.tools,
63036
- conversation: history2,
63263
+ conversation: [...history2, ...requestTail],
63037
63264
  anchor: input.requestSnapshot,
63038
63265
  contextLimit: budget.contextLimit,
63039
63266
  reservedOutputTokens: 8192
@@ -63046,7 +63273,7 @@ async function buildModelContext(input) {
63046
63273
  contextPressureTokens: measured.contextPressureTokens
63047
63274
  };
63048
63275
  } else {
63049
- const estimated = estimateHistoryTokens(history2);
63276
+ const estimated = estimateHistoryTokens([...history2, ...requestTail]);
63050
63277
  budget = {
63051
63278
  ...budget,
63052
63279
  history: history2,
@@ -63056,6 +63283,7 @@ async function buildModelContext(input) {
63056
63283
  }
63057
63284
  return {
63058
63285
  history: history2,
63286
+ requestTail,
63059
63287
  budget,
63060
63288
  source: source2,
63061
63289
  ...compactionPayload ? { compactionPayload } : {},
@@ -63476,6 +63704,17 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
63476
63704
  })),
63477
63705
  toolRegistry,
63478
63706
  providerStream,
63707
+ buildLiveness: {
63708
+ mutationRequired: expectsDiskImplementation(
63709
+ userText,
63710
+ workPhase,
63711
+ historyForModel
63712
+ ),
63713
+ maxRecoveries: 2
63714
+ },
63715
+ requestTail: () => resourceStatusTail(
63716
+ writerRef.current?.spine?.latestResourceSnapshot() ?? null
63717
+ ),
63479
63718
  // 2.6 Phase 3: host-owned pre-dispatch resource gate via the spine
63480
63719
  // mirror (doc section 11.3). Degrade-and-stop (null gate = allow).
63481
63720
  // 2.6.1 (plan §13): argument-aware — bash is essential only when
@@ -69243,7 +69482,6 @@ init_harness();
69243
69482
  init_dist();
69244
69483
  init_events2();
69245
69484
  init_conversationContext();
69246
- init_council();
69247
69485
  init_toolRegistry();
69248
69486
  init_candidateRegistry();
69249
69487
  init_metrics2();
@@ -69900,6 +70138,11 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
69900
70138
  }
69901
70139
  const effectiveTask = buildAgentUserWithHistory(opts.task, historySeed);
69902
70140
  if (opts.task) spine.userMessage(effectiveTask);
70141
+ const wantWrites = expectsDiskImplementation(
70142
+ opts.task,
70143
+ opts.phase,
70144
+ historySeed
70145
+ );
69903
70146
  const maxToolLoop = (() => {
69904
70147
  const n = envNumber(process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS, {
69905
70148
  default: 30,
@@ -69916,6 +70159,8 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
69916
70159
  tools,
69917
70160
  toolRegistry,
69918
70161
  providerStream,
70162
+ buildLiveness: { mutationRequired: wantWrites, maxRecoveries: 2 },
70163
+ requestTail: () => resourceStatusTail(spine.spine.latestResourceSnapshot()),
69919
70164
  // 2.6 Phase 3: host-owned pre-dispatch resource gate (doc section 11.3).
69920
70165
  // Advisory by default; ZELARI_RESOURCE_ENFORCEMENT=protected enables the
69921
70166
  // protected verification reserve. Degrade-and-stop (null gate = allow).
@@ -69929,12 +70174,13 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
69929
70174
  memoryContextChars: 2e3
69930
70175
  } : {}
69931
70176
  });
70177
+ const readBuildProgress = () => {
70178
+ const getter = harness.getBuildProgress;
70179
+ return typeof getter === "function" ? getter.call(harness) : { mutationsAttempted: 0, mutationsSucceeded: 0 };
70180
+ };
69932
70181
  let finalReason = "completed";
69933
70182
  let exitCode = 0;
69934
70183
  const textBuffer = [];
69935
- let successfulWrites = 0;
69936
- let emittedWrites = 0;
69937
- const pendingToolNames = /* @__PURE__ */ new Map();
69938
70184
  const scrub = createStreamScrubber2();
69939
70185
  try {
69940
70186
  for await (const event of harness.run()) {
@@ -69943,27 +70189,6 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
69943
70189
  if (event.type === "message_start") {
69944
70190
  scrub.reset();
69945
70191
  }
69946
- if (event.type === "tool_execution_start") {
69947
- const name = event.toolName ?? "";
69948
- const id3 = event.toolCallId ?? "";
69949
- if (id3 && name) pendingToolNames.set(id3, name);
69950
- if (name === "write_file" || name === "edit_file" || name === "apply_diff") {
69951
- emittedWrites += 1;
69952
- }
69953
- }
69954
- if (event.type === "tool_execution_end") {
69955
- const id3 = event.toolCallId ?? "";
69956
- const name = pendingToolNames.get(id3) ?? "";
69957
- pendingToolNames.delete(id3);
69958
- const isError = !!event.isError;
69959
- const result = String(event.result ?? "");
69960
- if ((name === "write_file" || name === "edit_file" || name === "apply_diff") && !isError) {
69961
- const zeroEdit = name === "edit_file" && /occurrencesReplaced["']?\s*[:=]\s*0\b|0 occurrence|no changes/i.test(
69962
- result
69963
- );
69964
- if (!zeroEdit) successfulWrites += 1;
69965
- }
69966
- }
69967
70192
  if (event.type === "message_delta" && typeof event.delta === "string") {
69968
70193
  const cleanDelta = scrub.push(event.delta);
69969
70194
  if (opts.output === "json") {
@@ -70003,17 +70228,18 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
70003
70228
  finalReason: "error",
70004
70229
  exitCode: 2,
70005
70230
  textBuffer,
70006
- successfulWrites,
70007
- emittedWrites,
70231
+ successfulWrites: readBuildProgress().mutationsSucceeded,
70232
+ emittedWrites: readBuildProgress().mutationsAttempted,
70008
70233
  messages: harness.getMessages()
70009
70234
  };
70010
70235
  }
70236
+ const buildProgress = readBuildProgress();
70011
70237
  return {
70012
70238
  finalReason,
70013
70239
  exitCode,
70014
70240
  textBuffer,
70015
- successfulWrites,
70016
- emittedWrites,
70241
+ successfulWrites: buildProgress.mutationsSucceeded,
70242
+ emittedWrites: buildProgress.mutationsAttempted,
70017
70243
  messages: harness.getMessages()
70018
70244
  };
70019
70245
  }
@@ -70037,41 +70263,6 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
70037
70263
  }
70038
70264
  ];
70039
70265
  let pass = await runSinglePass(initialMessages, sessionId2);
70040
- const wantWrites = expectsDiskImplementation(
70041
- opts.task,
70042
- opts.phase,
70043
- historySeed
70044
- );
70045
- if (wantWrites && pass.successfulWrites === 0 && pass.finalReason === "completed" && pass.exitCode === 0) {
70046
- const retryPrompt = buildImplementationWriteRetryPrompt(opts.task);
70047
- if (opts.output === "json") {
70048
- emitEvent({
70049
- type: "log",
70050
- message: "[headless] BUILD: no successful write_file/edit_file \u2014 forcing implementation retry"
70051
- });
70052
- } else {
70053
- process.stderr.write(
70054
- `[zelari-code --headless] BUILD: no successful writes \u2014 forcing implementation retry
70055
- `
70056
- );
70057
- }
70058
- const retryMessages = [
70059
- ...pass.messages.filter((m) => m.role !== "system")
70060
- ];
70061
- const withSystem = [
70062
- ...systemMessages,
70063
- ...retryMessages,
70064
- { role: "user", content: retryPrompt }
70065
- ];
70066
- progressRuntime.beginPass();
70067
- const retry = await runSinglePass(withSystem, `${sessionId2}-write-retry`);
70068
- pass = {
70069
- ...retry,
70070
- textBuffer: [...pass.textBuffer, ...retry.textBuffer],
70071
- successfulWrites: pass.successfulWrites + retry.successfulWrites,
70072
- emittedWrites: pass.emittedWrites + retry.emittedWrites
70073
- };
70074
- }
70075
70266
  let strictExit = 0;
70076
70267
  const verifierReviewDeps = {
70077
70268
  session: { provider, model },
@@ -70155,7 +70346,7 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
70155
70346
  }
70156
70347
  process.stdout.write("");
70157
70348
  if (pass.finalReason !== "error" && opts.output === "json" && wantWrites && pass.successfulWrites === 0) {
70158
- emitEvent({ type: "log", message: "[headless] BUILD warning: still zero successful writes after retry" });
70349
+ emitEvent({ type: "log", message: "[headless] BUILD failed: zero successful mutations after liveness recovery" });
70159
70350
  }
70160
70351
  try {
70161
70352
  const closeStatus = pass.finalReason === "error" ? "error" : strictExit !== 0 ? "stopped" : "completed";