zelari-code 2.8.0 → 2.9.1

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,218 @@ 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.wire);
40623
+ Object.freeze(input.sampling);
40624
+ Object.freeze(input.compaction);
40625
+ return Object.freeze(input);
40626
+ }
40627
+ function resolveHarnessProfile(model, providerId) {
40628
+ const provider = providerId?.trim().toLowerCase();
40629
+ if (provider === "deepseek") return "deepseek-v4";
40630
+ if (provider === "grok") return "grok";
40631
+ if (provider === "minimax") return "minimax";
40632
+ if (provider === "glm") return "glm";
40633
+ if (model && DEEPSEEK_RE.test(model)) return "deepseek-v4";
40634
+ if (model && GROK_RE.test(model)) return "grok";
40635
+ if (model && MINIMAX_RE.test(model)) return "minimax";
40636
+ if (model && GLM_RE.test(model)) return "glm";
40480
40637
  return "default";
40481
40638
  }
40482
- function capabilitiesFor(model) {
40483
- return resolveHarnessProfile(model) === "deepseek-v4" ? DEEPSEEK_V4_CAPS : DEFAULT_CAPS;
40639
+ function capabilitiesFor(model, providerId) {
40640
+ switch (resolveHarnessProfile(model, providerId)) {
40641
+ case "deepseek-v4":
40642
+ return DEEPSEEK_V4_CAPS;
40643
+ case "grok":
40644
+ return GROK_CAPS;
40645
+ case "minimax":
40646
+ return model && MINIMAX_M3_RE.test(model) ? MINIMAX_M3_CAPS : MINIMAX_M2_CAPS;
40647
+ case "glm":
40648
+ return GLM_CAPS;
40649
+ default:
40650
+ return DEFAULT_CAPS;
40651
+ }
40484
40652
  }
40485
- var DEFAULT_CAPS, DEEPSEEK_V4_CAPS, DEEPSEEK_V4_RE;
40653
+ 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
40654
  var init_capabilities = __esm({
40487
40655
  "src/cli/provider/capabilities.ts"() {
40488
40656
  "use strict";
40489
- DEFAULT_CAPS = Object.freeze({
40657
+ SHARED_COMPACTION = { warnAt: 0.7, compactAt: 0.85, hardAt: 0.95 };
40658
+ DEFAULT_CAPS = frozenProfile({
40490
40659
  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 }),
40660
+ reasoning: { supported: true, levels: ["low", "medium", "high"], replayReasoning: true },
40661
+ promptCache: { supported: true, pricedCacheRead: false },
40662
+ toolCalling: { parallel: true },
40663
+ buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
40664
+ wire: {
40665
+ grokRequestHeaders: false,
40666
+ omitAutoToolChoice: false,
40667
+ toolCallDeltasResetIdle: false,
40668
+ retriesBeforeOutput: 0,
40669
+ strictSseJson: false
40670
+ },
40671
+ sampling: { temperature: 0.7 },
40672
+ compaction: { ...SHARED_COMPACTION },
40500
40673
  profile: "default"
40501
40674
  });
40502
- DEEPSEEK_V4_CAPS = Object.freeze({
40675
+ DEEPSEEK_V4_CAPS = frozenProfile({
40503
40676
  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 }),
40677
+ reasoning: { supported: true, levels: ["high", "max"], replayReasoning: true },
40678
+ promptCache: { supported: true, pricedCacheRead: true },
40679
+ toolCalling: { parallel: true },
40680
+ buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
40681
+ wire: {
40682
+ grokRequestHeaders: false,
40683
+ omitAutoToolChoice: false,
40684
+ toolCallDeltasResetIdle: false,
40685
+ retriesBeforeOutput: 0,
40686
+ strictSseJson: false
40687
+ },
40688
+ sampling: { temperature: 0.7 },
40689
+ compaction: { ...SHARED_COMPACTION },
40513
40690
  profile: "deepseek-v4"
40514
40691
  });
40515
- DEEPSEEK_V4_RE = /^deepseek-v4(\.|-|$)/i;
40692
+ GROK_CAPS = frozenProfile({
40693
+ contextWindow: 5e5,
40694
+ reasoning: {
40695
+ supported: true,
40696
+ levels: ["low", "medium", "high", "xhigh"],
40697
+ replayReasoning: false
40698
+ },
40699
+ promptCache: {
40700
+ supported: true,
40701
+ pricedCacheRead: true,
40702
+ conversationAffinityHeader: "x-grok-conv-id"
40703
+ },
40704
+ toolCalling: { parallel: true },
40705
+ buildRecovery: { forceToolChoice: true, maxForcedTurns: 1 },
40706
+ wire: {
40707
+ grokRequestHeaders: true,
40708
+ omitAutoToolChoice: true,
40709
+ toolCallDeltasResetIdle: true,
40710
+ retriesBeforeOutput: 1,
40711
+ strictSseJson: true
40712
+ },
40713
+ sampling: { temperature: 0.7 },
40714
+ compaction: { ...SHARED_COMPACTION },
40715
+ profile: "grok"
40716
+ });
40717
+ MINIMAX_M3_CAPS = frozenProfile({
40718
+ contextWindow: 1e6,
40719
+ reasoning: { supported: true, replayReasoning: true },
40720
+ promptCache: { supported: false, pricedCacheRead: false },
40721
+ toolCalling: { parallel: true },
40722
+ buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
40723
+ wire: {
40724
+ grokRequestHeaders: false,
40725
+ omitAutoToolChoice: false,
40726
+ toolCallDeltasResetIdle: false,
40727
+ retriesBeforeOutput: 0,
40728
+ strictSseJson: false
40729
+ },
40730
+ sampling: { temperature: 0.7 },
40731
+ compaction: { ...SHARED_COMPACTION },
40732
+ profile: "minimax"
40733
+ });
40734
+ MINIMAX_M2_CAPS = frozenProfile({
40735
+ contextWindow: 204800,
40736
+ reasoning: { supported: true, replayReasoning: true },
40737
+ promptCache: { supported: false, pricedCacheRead: false },
40738
+ toolCalling: { parallel: true },
40739
+ buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
40740
+ wire: {
40741
+ grokRequestHeaders: false,
40742
+ omitAutoToolChoice: false,
40743
+ toolCallDeltasResetIdle: false,
40744
+ retriesBeforeOutput: 0,
40745
+ strictSseJson: false
40746
+ },
40747
+ sampling: { temperature: 0.7 },
40748
+ compaction: { ...SHARED_COMPACTION },
40749
+ profile: "minimax"
40750
+ });
40751
+ GLM_CAPS = frozenProfile({
40752
+ contextWindow: 2e5,
40753
+ reasoning: { supported: true, replayReasoning: true },
40754
+ promptCache: { supported: true, pricedCacheRead: false },
40755
+ toolCalling: { parallel: true },
40756
+ buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
40757
+ wire: {
40758
+ grokRequestHeaders: false,
40759
+ omitAutoToolChoice: false,
40760
+ toolCallDeltasResetIdle: false,
40761
+ retriesBeforeOutput: 0,
40762
+ strictSseJson: false
40763
+ },
40764
+ sampling: { temperature: 0.7 },
40765
+ compaction: { ...SHARED_COMPACTION },
40766
+ profile: "glm"
40767
+ });
40768
+ DEEPSEEK_RE = /^deepseek-(?:v4(?:\.|-|$)|chat$|reasoner$)/i;
40769
+ GROK_RE = /^grok(?:\.|-|$)/i;
40770
+ MINIMAX_RE = /^minimax(?:\.|-|$)/i;
40771
+ MINIMAX_M3_RE = /^minimax-m3(?:\.|-|$)/i;
40772
+ GLM_RE = /^glm(?:\.|-|$)/i;
40773
+ }
40774
+ });
40775
+
40776
+ // src/cli/provider/sse.ts
40777
+ var SseDataDecoder;
40778
+ var init_sse = __esm({
40779
+ "src/cli/provider/sse.ts"() {
40780
+ "use strict";
40781
+ SseDataDecoder = class {
40782
+ lineBuffer = "";
40783
+ dataLines = [];
40784
+ firstText = true;
40785
+ push(text, final = false) {
40786
+ if (this.firstText) {
40787
+ this.firstText = false;
40788
+ if (text.charCodeAt(0) === 65279) text = text.slice(1);
40789
+ }
40790
+ this.lineBuffer += text;
40791
+ const lines = this.lineBuffer.split("\n");
40792
+ this.lineBuffer = final ? "" : lines.pop() ?? "";
40793
+ const events = [];
40794
+ for (const rawLine of lines) {
40795
+ this.acceptLine(rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine, events);
40796
+ }
40797
+ if (final) {
40798
+ if (this.lineBuffer.length > 0) {
40799
+ this.acceptLine(
40800
+ this.lineBuffer.endsWith("\r") ? this.lineBuffer.slice(0, -1) : this.lineBuffer,
40801
+ events
40802
+ );
40803
+ this.lineBuffer = "";
40804
+ }
40805
+ this.dispatch(events);
40806
+ }
40807
+ return events;
40808
+ }
40809
+ acceptLine(line, events) {
40810
+ if (line.length === 0) {
40811
+ this.dispatch(events);
40812
+ return;
40813
+ }
40814
+ if (line.startsWith(":")) return;
40815
+ const colon = line.indexOf(":");
40816
+ const field = colon < 0 ? line : line.slice(0, colon);
40817
+ if (field !== "data") return;
40818
+ let value = colon < 0 ? "" : line.slice(colon + 1);
40819
+ if (value.startsWith(" ")) value = value.slice(1);
40820
+ this.dataLines.push(value);
40821
+ }
40822
+ dispatch(events) {
40823
+ if (this.dataLines.length === 0) return;
40824
+ events.push(this.dataLines.join("\n"));
40825
+ this.dataLines = [];
40826
+ }
40827
+ };
40516
40828
  }
40517
40829
  });
40518
40830
 
@@ -40524,12 +40836,14 @@ __export(openai_compatible_exports, {
40524
40836
  modelSupportsVision: () => modelSupportsVision,
40525
40837
  openaiCompatibleProvider: () => openaiCompatibleProvider,
40526
40838
  parseCachedPromptTokens: () => parseCachedPromptTokens,
40839
+ parseOpenAiStreamError: () => parseOpenAiStreamError,
40527
40840
  providerConfigFor: () => providerConfigFor,
40528
40841
  providerFromEnv: () => providerFromEnv,
40529
40842
  readChunkWithTimeout: () => readChunkWithTimeout,
40530
40843
  resolveActiveProvider: () => resolveActiveProvider,
40531
40844
  resolveBaseUrl: () => resolveBaseUrl
40532
40845
  });
40846
+ import { randomUUID as randomUUID2 } from "node:crypto";
40533
40847
  function abortableSleep(ms, signal) {
40534
40848
  return new Promise((resolve7) => {
40535
40849
  if (signal?.aborted) return resolve7();
@@ -40573,9 +40887,10 @@ async function readChunkWithTimeout(reader, opts) {
40573
40887
  reader.read(),
40574
40888
  new Promise((_, reject) => {
40575
40889
  idleTimer = setTimeout(() => {
40890
+ const totalIdleMs = Math.max(opts.idleMs, Date.now() - opts.lastUsefulAt());
40576
40891
  reject(
40577
40892
  new Error(
40578
- `Provider stream idle for ${Math.round(waitMs / 1e3)}s (no tokens). The model/gateway stalled \u2014 try again or switch model. Override with ZELARI_PROVIDER_STREAM_IDLE_MS.`
40893
+ `Provider stream idle for ${Math.round(totalIdleMs / 1e3)}s (no useful deltas). The model/gateway stalled \u2014 try again or switch model. Override with ZELARI_PROVIDER_STREAM_IDLE_MS.`
40579
40894
  )
40580
40895
  );
40581
40896
  }, waitMs);
@@ -40623,6 +40938,22 @@ function parseCachedPromptTokens(usage) {
40623
40938
  }
40624
40939
  return 0;
40625
40940
  }
40941
+ function parseOpenAiStreamError(value) {
40942
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
40943
+ const root = value;
40944
+ const nested = root.error;
40945
+ if (nested && typeof nested === "object" && !Array.isArray(nested)) {
40946
+ const error51 = nested;
40947
+ const message = typeof error51.message === "string" && error51.message.trim() ? error51.message.trim() : "unknown error";
40948
+ const type = typeof error51.type === "string" && error51.type.trim() ? error51.type.trim() : "server_error";
40949
+ return `Provider stream error (${type}): ${message}`;
40950
+ }
40951
+ if (typeof nested === "string" && nested.trim()) {
40952
+ const type = typeof root.code === "string" && root.code.trim() ? root.code.trim() : "server_error";
40953
+ return `Provider stream error (${type}): ${nested.trim()}`;
40954
+ }
40955
+ return null;
40956
+ }
40626
40957
  function resolveBaseUrl(providerId) {
40627
40958
  const custom2 = getCustomEndpoint(providerId);
40628
40959
  if (custom2) return custom2;
@@ -40700,7 +41031,8 @@ ${notes}
40700
41031
  return { role: m.role, content: m.content };
40701
41032
  }
40702
41033
  function openaiCompatibleProvider(config2) {
40703
- return async function* (params) {
41034
+ const run = async function* (params, streamRetryAttempt = 0) {
41035
+ const capabilities = capabilitiesFor(params.model, config2.providerId);
40704
41036
  const vision = modelSupportsVision(params.model);
40705
41037
  const messages = params.messages.map((m) => {
40706
41038
  const cacheable = !(m.role === "user" && m.images && m.images.length > 0);
@@ -40720,7 +41052,7 @@ function openaiCompatibleProvider(config2) {
40720
41052
  model: params.model,
40721
41053
  messages,
40722
41054
  stream: true,
40723
- temperature: generation?.temperature ?? capabilitiesFor(params.model).sampling.temperature,
41055
+ temperature: generation?.temperature ?? capabilities.sampling.temperature,
40724
41056
  // Task G.4.2 — request the provider to send real token usage in
40725
41057
  // the final chunk (gated by `stream_options.include_usage` on the
40726
41058
  // OpenAI-compatible API). Providers that don't honor this (some
@@ -40756,7 +41088,31 @@ function openaiCompatibleProvider(config2) {
40756
41088
  parameters: t.parameters
40757
41089
  }
40758
41090
  }));
40759
- body.tool_choice = "auto";
41091
+ const recoveryAttempt = generation?.recoveryAttempt ?? 1;
41092
+ const forceRecoveryTool = generation?.toolChoice === "required" && capabilities.buildRecovery.forceToolChoice && recoveryAttempt <= capabilities.buildRecovery.maxForcedTurns;
41093
+ if (forceRecoveryTool) {
41094
+ body.tool_choice = "required";
41095
+ } else if (!capabilities.wire.omitAutoToolChoice) {
41096
+ body.tool_choice = "auto";
41097
+ }
41098
+ }
41099
+ const headers2 = {
41100
+ "Content-Type": "application/json",
41101
+ Authorization: `Bearer ${config2.apiKey}`,
41102
+ ...config2.extraHeaders ?? {}
41103
+ };
41104
+ const affinityHeader = capabilities.promptCache.conversationAffinityHeader;
41105
+ const conversationId = params.conversationId?.trim();
41106
+ const safeConversationId = conversationId && conversationId.length <= 256 && !/[\u0000-\u001f\u007f]/.test(conversationId) ? conversationId : void 0;
41107
+ if (affinityHeader && safeConversationId) {
41108
+ headers2[affinityHeader] = safeConversationId;
41109
+ }
41110
+ if (capabilities.wire.grokRequestHeaders) {
41111
+ headers2.Accept = "text/event-stream";
41112
+ headers2["x-grok-client-identifier"] = "zelari-code";
41113
+ headers2["x-grok-req-id"] = `zelari-${randomUUID2()}`;
41114
+ headers2["x-grok-model-override"] = params.model;
41115
+ if (safeConversationId) headers2["x-grok-session-id"] = safeConversationId;
40760
41116
  }
40761
41117
  let response;
40762
41118
  let lastErrText = "";
@@ -40781,10 +41137,7 @@ function openaiCompatibleProvider(config2) {
40781
41137
  try {
40782
41138
  response = await fetch(`${config2.baseUrl}/chat/completions`, {
40783
41139
  method: "POST",
40784
- headers: {
40785
- "Content-Type": "application/json",
40786
- Authorization: `Bearer ${config2.apiKey}`
40787
- },
41140
+ headers: headers2,
40788
41141
  body: JSON.stringify(body),
40789
41142
  // Cancel aborts the HTTP request; stream idle is enforced below
40790
41143
  // per-chunk so active multi-minute streams are not killed.
@@ -40827,9 +41180,10 @@ function openaiCompatibleProvider(config2) {
40827
41180
  }
40828
41181
  const reader = response.body.getReader();
40829
41182
  const decoder = new TextDecoder();
40830
- let buffer = "";
41183
+ const sseDecoder = new SseDataDecoder();
40831
41184
  const toolCallAccumulator = /* @__PURE__ */ new Map();
40832
41185
  let emittedToolCall = false;
41186
+ let emittedProviderDelta = false;
40833
41187
  let reasoningDetailsBuf = "";
40834
41188
  const tryParseArgs = (raw) => {
40835
41189
  const t = raw.trim();
@@ -40852,6 +41206,7 @@ function openaiCompatibleProvider(config2) {
40852
41206
  if (args === null) continue;
40853
41207
  toolCallAccumulator.delete(idx);
40854
41208
  emittedToolCall = true;
41209
+ emittedProviderDelta = true;
40855
41210
  markUseful();
40856
41211
  yield {
40857
41212
  kind: "tool_call",
@@ -40887,18 +41242,19 @@ function openaiCompatibleProvider(config2) {
40887
41242
  await reader.cancel(msg);
40888
41243
  } catch {
40889
41244
  }
41245
+ if (!emittedProviderDelta && streamRetryAttempt < capabilities.wire.retriesBeforeOutput) {
41246
+ await abortableSleep(backoffDelay(streamRetryAttempt, null), params.signal);
41247
+ yield* run(params, streamRetryAttempt + 1);
41248
+ return;
41249
+ }
40890
41250
  yield { kind: "error", message: msg };
40891
41251
  return;
40892
41252
  }
40893
41253
  const { value, done } = chunk;
40894
- if (done) break;
40895
- buffer += decoder.decode(value, { stream: true });
40896
- const lines = buffer.split("\n");
40897
- buffer = lines.pop() ?? "";
40898
- for (const line of lines) {
40899
- const trimmed = line.trim();
40900
- if (!trimmed.startsWith("data:")) continue;
40901
- const data = trimmed.slice(5).trim();
41254
+ const decoded = done ? decoder.decode() : decoder.decode(value, { stream: true });
41255
+ const events = sseDecoder.push(decoded, done);
41256
+ for (const data of events) {
41257
+ if (data.length === 0) continue;
40902
41258
  if (data === "[DONE]") {
40903
41259
  yield* flushToolAccumulator();
40904
41260
  yield {
@@ -40908,7 +41264,22 @@ function openaiCompatibleProvider(config2) {
40908
41264
  return;
40909
41265
  }
40910
41266
  try {
40911
- const parsed = JSON.parse(data);
41267
+ const rawParsed = JSON.parse(data);
41268
+ const streamError = parseOpenAiStreamError(rawParsed);
41269
+ if (streamError) {
41270
+ try {
41271
+ await reader.cancel(streamError);
41272
+ } catch {
41273
+ }
41274
+ if (!emittedProviderDelta && streamRetryAttempt < capabilities.wire.retriesBeforeOutput) {
41275
+ await abortableSleep(backoffDelay(streamRetryAttempt, null), params.signal);
41276
+ yield* run(params, streamRetryAttempt + 1);
41277
+ return;
41278
+ }
41279
+ yield { kind: "error", message: streamError };
41280
+ return;
41281
+ }
41282
+ const parsed = rawParsed;
40912
41283
  const choice = parsed.choices?.[0];
40913
41284
  const delta = choice?.delta;
40914
41285
  if (parsed.usage && typeof parsed.usage === "object") {
@@ -40917,6 +41288,7 @@ function openaiCompatibleProvider(config2) {
40917
41288
  const totalTokens = typeof parsed.usage.total_tokens === "number" ? parsed.usage.total_tokens : promptTokens + completionTokens;
40918
41289
  const cachedPromptTokens = parseCachedPromptTokens(parsed.usage);
40919
41290
  markUseful();
41291
+ emittedProviderDelta = true;
40920
41292
  yield {
40921
41293
  kind: "usage",
40922
41294
  usage: {
@@ -40929,11 +41301,13 @@ function openaiCompatibleProvider(config2) {
40929
41301
  }
40930
41302
  if (typeof delta?.content === "string" && delta.content.length > 0) {
40931
41303
  markUseful();
41304
+ emittedProviderDelta = true;
40932
41305
  yield { kind: "text", delta: delta.content };
40933
41306
  }
40934
41307
  const reasoning = delta?.reasoning_content ?? delta?.reasoning;
40935
41308
  if (typeof reasoning === "string" && reasoning.length > 0) {
40936
41309
  markUseful();
41310
+ emittedProviderDelta = true;
40937
41311
  yield { kind: "thinking", delta: reasoning };
40938
41312
  }
40939
41313
  const details = delta?.reasoning_details;
@@ -40947,16 +41321,21 @@ function openaiCompatibleProvider(config2) {
40947
41321
  reasoningDetailsBuf = t;
40948
41322
  if (piece.length > 0) {
40949
41323
  markUseful();
41324
+ emittedProviderDelta = true;
40950
41325
  yield { kind: "thinking", delta: piece };
40951
41326
  }
40952
41327
  } else {
40953
41328
  reasoningDetailsBuf += t;
40954
41329
  markUseful();
41330
+ emittedProviderDelta = true;
40955
41331
  yield { kind: "thinking", delta: t };
40956
41332
  }
40957
41333
  }
40958
41334
  }
40959
41335
  if (Array.isArray(delta?.tool_calls)) {
41336
+ if (capabilities.wire.toolCallDeltasResetIdle && delta.tool_calls.length > 0) {
41337
+ markUseful();
41338
+ }
40960
41339
  for (const tc of delta.tool_calls) {
40961
41340
  const idx = tc.index ?? 0;
40962
41341
  const existing = toolCallAccumulator.get(idx) ?? {
@@ -40973,12 +41352,21 @@ function openaiCompatibleProvider(config2) {
40973
41352
  if (choice?.finish_reason) {
40974
41353
  yield* flushToolAccumulator();
40975
41354
  markUseful();
41355
+ emittedProviderDelta = true;
40976
41356
  const reason = choice.finish_reason === "stop" && emittedToolCall ? "tool_calls" : choice.finish_reason;
40977
41357
  yield { kind: "finish", reason };
40978
41358
  }
40979
41359
  } catch {
41360
+ if (capabilities.wire.strictSseJson) {
41361
+ yield {
41362
+ kind: "error",
41363
+ message: "Malformed Grok SSE data event (expected Chat Completions JSON)."
41364
+ };
41365
+ return;
41366
+ }
40980
41367
  }
40981
41368
  }
41369
+ if (done) break;
40982
41370
  }
40983
41371
  yield* flushToolAccumulator();
40984
41372
  yield {
@@ -40989,6 +41377,7 @@ function openaiCompatibleProvider(config2) {
40989
41377
  reader.releaseLock();
40990
41378
  }
40991
41379
  };
41380
+ return (params) => run(params);
40992
41381
  }
40993
41382
  function extraFromStored(providerId) {
40994
41383
  const stored = getOAuthToken(providerId);
@@ -41031,6 +41420,7 @@ var init_openai_compatible = __esm({
41031
41420
  init_providerConfig();
41032
41421
  init_thinking();
41033
41422
  init_capabilities();
41423
+ init_sse();
41034
41424
  RETRYABLE_STATUSES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
41035
41425
  MAX_RETRIES = (() => {
41036
41426
  const raw = process.env.ZELARI_PROVIDER_MAX_RETRIES;
@@ -44009,11 +44399,11 @@ var init_metrics3 = __esm({
44009
44399
  });
44010
44400
 
44011
44401
  // src/cli/state/fileStateStore.ts
44012
- import { createHash as createHash13, randomUUID as randomUUID2 } from "node:crypto";
44402
+ import { createHash as createHash13, randomUUID as randomUUID3 } from "node:crypto";
44013
44403
  import { promises as fs21 } from "node:fs";
44014
44404
  import * as path43 from "node:path";
44015
44405
  function shortId() {
44016
- return randomUUID2().replace(/-/g, "").slice(0, 12);
44406
+ return randomUUID3().replace(/-/g, "").slice(0, 12);
44017
44407
  }
44018
44408
  async function writeJsonAtomic(filePath, data) {
44019
44409
  await fs21.mkdir(path43.dirname(filePath), { recursive: true });
@@ -44946,7 +45336,7 @@ function expectsDiskImplementation(task, phase2, prior) {
44946
45336
  const trimmed = task.trim();
44947
45337
  if (!trimmed) return false;
44948
45338
  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(
45339
+ 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
45340
  trimmed
44951
45341
  )) {
44952
45342
  return true;
@@ -46380,7 +46770,7 @@ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.node_id = n.id);
46380
46770
  });
46381
46771
 
46382
46772
  // src/cli/memory/sqliteBackend.ts
46383
- import { createHash as createHash15, randomUUID as randomUUID3 } from "node:crypto";
46773
+ import { createHash as createHash15, randomUUID as randomUUID4 } from "node:crypto";
46384
46774
  import { promises as fs23 } from "node:fs";
46385
46775
  import * as path46 from "node:path";
46386
46776
  function boundedLimit(value, fallback = 50) {
@@ -46503,7 +46893,7 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
46503
46893
  const createdAt = input.createdAt ?? now;
46504
46894
  const recordedAt = input.recordedAt ?? createdAt;
46505
46895
  const node = MemoryNodeSchema.parse({
46506
- id: input.id ?? `mem_${randomUUID3()}`,
46896
+ id: input.id ?? `mem_${randomUUID4()}`,
46507
46897
  schemaVersion: 1,
46508
46898
  projectId: input.projectId,
46509
46899
  kind: input.kind,
@@ -46529,7 +46919,7 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
46529
46919
  (version_id, memory_id, revision, snapshot_json, recorded_at, actor, reason)
46530
46920
  VALUES (?, ?, 1, ?, ?, ?, ?)`,
46531
46921
  params: [
46532
- `ver_${randomUUID3()}`,
46922
+ `ver_${randomUUID4()}`,
46533
46923
  node.id,
46534
46924
  JSON.stringify(node),
46535
46925
  recordedAt,
@@ -46590,7 +46980,7 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
46590
46980
  (version_id, memory_id, revision, snapshot_json, recorded_at, actor, reason)
46591
46981
  VALUES (?, ?, (SELECT COALESCE(MAX(revision), 0) + 1 FROM memory_versions WHERE memory_id=?), ?, ?, ?, ?)`,
46592
46982
  params: [
46593
- `ver_${randomUUID3()}`,
46983
+ `ver_${randomUUID4()}`,
46594
46984
  updated.id,
46595
46985
  updated.id,
46596
46986
  JSON.stringify(updated),
@@ -46824,7 +47214,7 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
46824
47214
  if (decoded) return decoded;
46825
47215
  const edge = MemoryEdgeSchema.parse({
46826
47216
  ...input,
46827
- id: input.id ?? `edge_${randomUUID3()}`,
47217
+ id: input.id ?? `edge_${randomUUID4()}`,
46828
47218
  strength: input.strength ?? 1,
46829
47219
  confidence: input.confidence ?? 0.8,
46830
47220
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -50207,7 +50597,7 @@ import { promisify as promisify2 } from "node:util";
50207
50597
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
50208
50598
  import { tmpdir as tmpdir2 } from "node:os";
50209
50599
  import path49 from "node:path";
50210
- import { randomUUID as randomUUID4 } from "node:crypto";
50600
+ import { randomUUID as randomUUID5 } from "node:crypto";
50211
50601
  async function git3(cwd, args, env) {
50212
50602
  const { stdout } = await execFileAsync2("git", ["-C", cwd, ...args], {
50213
50603
  maxBuffer: 64 * 1024 * 1024,
@@ -50250,7 +50640,7 @@ async function createCheckpoint(cwd, label = "checkpoint") {
50250
50640
  }
50251
50641
  try {
50252
50642
  const { tree, head } = await snapshotTree(cwd);
50253
- const id3 = randomUUID4().slice(0, 8);
50643
+ const id3 = randomUUID5().slice(0, 8);
50254
50644
  const createdAt = Date.now();
50255
50645
  const message = `zelari-checkpoint ${id3}: ${label}`;
50256
50646
  const commitArgs = ["commit-tree", tree, "-m", message];
@@ -50417,7 +50807,7 @@ __export(fileBackend_exports, {
50417
50807
  getMemoryBackend: () => getMemoryBackend,
50418
50808
  isMemoryEnabled: () => isMemoryEnabled
50419
50809
  });
50420
- import { randomUUID as randomUUID5 } from "node:crypto";
50810
+ import { randomUUID as randomUUID6 } from "node:crypto";
50421
50811
  import { promises as fs26 } from "node:fs";
50422
50812
  import * as path50 from "node:path";
50423
50813
  function tokenize(text) {
@@ -50476,7 +50866,7 @@ var init_fileBackend = __esm({
50476
50866
  }
50477
50867
  async add(content, metadata2 = {}, graph) {
50478
50868
  const fact = {
50479
- id: randomUUID5(),
50869
+ id: randomUUID6(),
50480
50870
  content,
50481
50871
  metadata: metadata2,
50482
50872
  ...graph ? { graph } : {},
@@ -50584,7 +50974,7 @@ __export(zelariMission_exports, {
50584
50974
  resolveMaxTokens: () => resolveMaxTokens,
50585
50975
  runZelariMission: () => runZelariMission
50586
50976
  });
50587
- import { randomUUID as randomUUID6 } from "node:crypto";
50977
+ import { randomUUID as randomUUID7 } from "node:crypto";
50588
50978
  import { promises as fs28 } from "node:fs";
50589
50979
  import * as path52 from "node:path";
50590
50980
  function resolveMaxIterations(env = process.env) {
@@ -50681,7 +51071,7 @@ async function runZelariMission(userMessage, brief, deps) {
50681
51071
  const maxStall = resolveMaxStall(deps.env);
50682
51072
  const maxCost = resolveMaxCost(deps.env);
50683
51073
  const maxTokens = resolveMaxTokens(deps.env);
50684
- const missionId = deps.missionId ?? `m_${randomUUID6().slice(0, 8)}`;
51074
+ const missionId = deps.missionId ?? `m_${randomUUID7().slice(0, 8)}`;
50685
51075
  const startedAt = now().toISOString();
50686
51076
  const state3 = {
50687
51077
  missionId,
@@ -51129,6 +51519,7 @@ async function runAgentMissionSlice(deps) {
51129
51519
  tools: toolSpecs,
51130
51520
  toolRegistry: deps.toolRegistry,
51131
51521
  providerStream: deps.providerStream,
51522
+ buildLiveness: { mutationRequired: writeRetry, maxRecoveries: 2 },
51132
51523
  cwd: deps.projectRoot,
51133
51524
  maxToolCallsPerTurn: maxToolCalls,
51134
51525
  maxToolLoopIterations: maxToolLoop,
@@ -57212,7 +57603,7 @@ var init_mcpCli = __esm({
57212
57603
 
57213
57604
  // src/cli/mcp/mcpPermissionServer.ts
57214
57605
  import { createInterface as createInterface2 } from "node:readline";
57215
- import { randomUUID as randomUUID8 } from "node:crypto";
57606
+ import { randomUUID as randomUUID9 } from "node:crypto";
57216
57607
  function startPermissionMcpServer(opts) {
57217
57608
  const socketPath = opts.socketPath.trim();
57218
57609
  const requestTimeoutMs = opts.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
@@ -57308,7 +57699,7 @@ function startPermissionMcpServer(opts) {
57308
57699
  socketPath,
57309
57700
  {
57310
57701
  t: "ask",
57311
- id: randomUUID8(),
57702
+ id: randomUUID9(),
57312
57703
  kind: "permission",
57313
57704
  tool: toolName,
57314
57705
  input: input2,
@@ -57347,7 +57738,7 @@ function startPermissionMcpServer(opts) {
57347
57738
  socketPath,
57348
57739
  {
57349
57740
  t: "ask",
57350
- id: randomUUID8(),
57741
+ id: randomUUID9(),
57351
57742
  kind: "question",
57352
57743
  question,
57353
57744
  choices,
@@ -57639,7 +58030,7 @@ var init_config = __esm({
57639
58030
  // src/cli/companion/runManager.ts
57640
58031
  import { spawn as spawn17 } from "node:child_process";
57641
58032
  import { createInterface as createInterface3 } from "node:readline";
57642
- import { randomUUID as randomUUID9 } from "node:crypto";
58033
+ import { randomUUID as randomUUID10 } from "node:crypto";
57643
58034
  import { writeFileSync as writeFileSync26, unlinkSync as unlinkSync3 } from "node:fs";
57644
58035
  import { join as join44 } from "node:path";
57645
58036
  import { tmpdir as tmpdir3 } from "node:os";
@@ -57708,7 +58099,7 @@ var init_runManager = __esm({
57708
58099
  }
57709
58100
  const prompt = args.prompt?.trim();
57710
58101
  if (!prompt) return { ok: false, error: "prompt is required" };
57711
- const id3 = randomUUID9();
58102
+ const id3 = randomUUID10();
57712
58103
  const mode = (args.mode || "kraken").toLowerCase();
57713
58104
  const phase2 = (args.phase || "build").toLowerCase();
57714
58105
  const run = {
@@ -62658,12 +63049,12 @@ function estimateHistoryTokens(messages) {
62658
63049
  }
62659
63050
  return n;
62660
63051
  }
62661
- function defaultContextLimitForModel(model) {
62662
- return capabilitiesFor(model).contextWindow;
63052
+ function defaultContextLimitForModel(model, provider) {
63053
+ return capabilitiesFor(model, provider).contextWindow;
62663
63054
  }
62664
- function resolveContextLimit(model) {
63055
+ function resolveContextLimit(model, provider) {
62665
63056
  return envNumber(process.env.ZELARI_CONTEXT_LIMIT, {
62666
- default: defaultContextLimitForModel(model),
63057
+ default: defaultContextLimitForModel(model, provider),
62667
63058
  min: 4e3,
62668
63059
  max: 2e6
62669
63060
  });
@@ -62679,8 +63070,8 @@ function phaseKnobs(phase2) {
62679
63070
  }
62680
63071
  var RESERVED_OUTPUT_TOKENS = 8192;
62681
63072
  async function applyBudgetPolicyAsync(history2, phase2, opts) {
62682
- const contextLimit = resolveContextLimit(opts?.model);
62683
- const compact3 = capabilitiesFor(opts?.model).compaction;
63073
+ const contextLimit = resolveContextLimit(opts?.model, opts?.provider);
63074
+ const compact3 = capabilitiesFor(opts?.model, opts?.provider).compaction;
62684
63075
  const sessionExtra = opts?.sessionTokens ?? 0;
62685
63076
  const warnings = [];
62686
63077
  let { historyTurns, maxToolLoopIterations } = phaseKnobs(phase2);
@@ -62955,8 +63346,11 @@ function messageWasRecompacted(message, history2) {
62955
63346
  if (message.compactedFromSeq === void 0) return false;
62956
63347
  return !history2.some((candidate) => candidate.seq !== void 0 && candidate.seq === message.seq);
62957
63348
  }
62958
- function resourceStatusMessage(payload) {
62959
- return { role: "system", content: formatResourceSnapshot(payload) };
63349
+ function resourceStatusTail(payload) {
63350
+ return payload ? [{ role: "system", content: formatResourceSnapshot(payload) }] : [];
63351
+ }
63352
+ function isLegacyResourceStatus(message) {
63353
+ return message.role === "system" && message.content.startsWith("RESOURCE STATUS");
62960
63354
  }
62961
63355
  async function sessionHistory(session) {
62962
63356
  if (!session || session.status !== "active") return null;
@@ -62967,7 +63361,10 @@ async function sessionHistory(session) {
62967
63361
  async function buildModelContext(input) {
62968
63362
  const derived = await sessionHistory(input.session);
62969
63363
  const source2 = derived ? "session" : "fallback";
62970
- const sourceHistory = derived ?? [...input.fallbackHistory];
63364
+ const sourceHistory = (derived ?? [...input.fallbackHistory]).filter(
63365
+ (message) => !isLegacyResourceStatus(message)
63366
+ );
63367
+ const requestTail = resourceStatusTail(input.resourceSnapshot);
62971
63368
  const inputTokens = estimateHistoryTokens(sourceHistory);
62972
63369
  const requestSurface = input.systemMessages || input.tools ? {
62973
63370
  provider: input.provider ?? "local",
@@ -62977,7 +63374,8 @@ async function buildModelContext(input) {
62977
63374
  } : null;
62978
63375
  let budget = await applyBudgetPolicyAsync(sourceHistory, input.phase, {
62979
63376
  model: input.model,
62980
- sessionTokens: input.sessionTokens,
63377
+ provider: input.provider,
63378
+ sessionTokens: (input.sessionTokens ?? 0) + estimateHistoryTokens(requestTail),
62981
63379
  sessionId: input.sessionId,
62982
63380
  signal: input.signal,
62983
63381
  requestSnapshot: input.requestSnapshot,
@@ -63024,16 +63422,11 @@ async function buildModelContext(input) {
63024
63422
  };
63025
63423
  input.onCompactionMetric?.(compactionMetrics);
63026
63424
  }
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
63425
  if (requestSurface) {
63033
63426
  const measured = measureRequest({
63034
63427
  systemMessages: requestSurface.systemMessages,
63035
63428
  tools: requestSurface.tools,
63036
- conversation: history2,
63429
+ conversation: [...history2, ...requestTail],
63037
63430
  anchor: input.requestSnapshot,
63038
63431
  contextLimit: budget.contextLimit,
63039
63432
  reservedOutputTokens: 8192
@@ -63046,7 +63439,7 @@ async function buildModelContext(input) {
63046
63439
  contextPressureTokens: measured.contextPressureTokens
63047
63440
  };
63048
63441
  } else {
63049
- const estimated = estimateHistoryTokens(history2);
63442
+ const estimated = estimateHistoryTokens([...history2, ...requestTail]);
63050
63443
  budget = {
63051
63444
  ...budget,
63052
63445
  history: history2,
@@ -63056,6 +63449,7 @@ async function buildModelContext(input) {
63056
63449
  }
63057
63450
  return {
63058
63451
  history: history2,
63452
+ requestTail,
63059
63453
  budget,
63060
63454
  source: source2,
63061
63455
  ...compactionPayload ? { compactionPayload } : {},
@@ -63476,6 +63870,17 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
63476
63870
  })),
63477
63871
  toolRegistry,
63478
63872
  providerStream,
63873
+ buildLiveness: {
63874
+ mutationRequired: expectsDiskImplementation(
63875
+ userText,
63876
+ workPhase,
63877
+ historyForModel
63878
+ ),
63879
+ maxRecoveries: 2
63880
+ },
63881
+ requestTail: () => resourceStatusTail(
63882
+ writerRef.current?.spine?.latestResourceSnapshot() ?? null
63883
+ ),
63479
63884
  // 2.6 Phase 3: host-owned pre-dispatch resource gate via the spine
63480
63885
  // mirror (doc section 11.3). Degrade-and-stop (null gate = allow).
63481
63886
  // 2.6.1 (plan §13): argument-aware — bash is essential only when
@@ -69243,7 +69648,6 @@ init_harness();
69243
69648
  init_dist();
69244
69649
  init_events2();
69245
69650
  init_conversationContext();
69246
- init_council();
69247
69651
  init_toolRegistry();
69248
69652
  init_candidateRegistry();
69249
69653
  init_metrics2();
@@ -69287,7 +69691,7 @@ init_taskTool();
69287
69691
  init_sessionTodos();
69288
69692
  import { promises as fs41 } from "node:fs";
69289
69693
  import path68 from "node:path";
69290
- import { randomUUID as randomUUID7 } from "node:crypto";
69694
+ import { randomUUID as randomUUID8 } from "node:crypto";
69291
69695
 
69292
69696
  // src/cli/kraken/verifierLifecycle.ts
69293
69697
  init_verification2();
@@ -69584,7 +69988,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
69584
69988
  });
69585
69989
  log(formatKrakenGraphAscii2(graph));
69586
69990
  if (opts.planOnly) {
69587
- const planId = randomUUID7();
69991
+ const planId = randomUUID8();
69588
69992
  const planDir = path68.join(cwd, ".zelari", "radio");
69589
69993
  const planPath = path68.join(planDir, `plan-${planId}.json`);
69590
69994
  await fs41.mkdir(planDir, { recursive: true });
@@ -69900,6 +70304,11 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
69900
70304
  }
69901
70305
  const effectiveTask = buildAgentUserWithHistory(opts.task, historySeed);
69902
70306
  if (opts.task) spine.userMessage(effectiveTask);
70307
+ const wantWrites = expectsDiskImplementation(
70308
+ opts.task,
70309
+ opts.phase,
70310
+ historySeed
70311
+ );
69903
70312
  const maxToolLoop = (() => {
69904
70313
  const n = envNumber(process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS, {
69905
70314
  default: 30,
@@ -69916,6 +70325,8 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
69916
70325
  tools,
69917
70326
  toolRegistry,
69918
70327
  providerStream,
70328
+ buildLiveness: { mutationRequired: wantWrites, maxRecoveries: 2 },
70329
+ requestTail: () => resourceStatusTail(spine.spine.latestResourceSnapshot()),
69919
70330
  // 2.6 Phase 3: host-owned pre-dispatch resource gate (doc section 11.3).
69920
70331
  // Advisory by default; ZELARI_RESOURCE_ENFORCEMENT=protected enables the
69921
70332
  // protected verification reserve. Degrade-and-stop (null gate = allow).
@@ -69929,12 +70340,13 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
69929
70340
  memoryContextChars: 2e3
69930
70341
  } : {}
69931
70342
  });
70343
+ const readBuildProgress = () => {
70344
+ const getter = harness.getBuildProgress;
70345
+ return typeof getter === "function" ? getter.call(harness) : { mutationsAttempted: 0, mutationsSucceeded: 0 };
70346
+ };
69932
70347
  let finalReason = "completed";
69933
70348
  let exitCode = 0;
69934
70349
  const textBuffer = [];
69935
- let successfulWrites = 0;
69936
- let emittedWrites = 0;
69937
- const pendingToolNames = /* @__PURE__ */ new Map();
69938
70350
  const scrub = createStreamScrubber2();
69939
70351
  try {
69940
70352
  for await (const event of harness.run()) {
@@ -69943,27 +70355,6 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
69943
70355
  if (event.type === "message_start") {
69944
70356
  scrub.reset();
69945
70357
  }
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
70358
  if (event.type === "message_delta" && typeof event.delta === "string") {
69968
70359
  const cleanDelta = scrub.push(event.delta);
69969
70360
  if (opts.output === "json") {
@@ -70003,17 +70394,18 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
70003
70394
  finalReason: "error",
70004
70395
  exitCode: 2,
70005
70396
  textBuffer,
70006
- successfulWrites,
70007
- emittedWrites,
70397
+ successfulWrites: readBuildProgress().mutationsSucceeded,
70398
+ emittedWrites: readBuildProgress().mutationsAttempted,
70008
70399
  messages: harness.getMessages()
70009
70400
  };
70010
70401
  }
70402
+ const buildProgress = readBuildProgress();
70011
70403
  return {
70012
70404
  finalReason,
70013
70405
  exitCode,
70014
70406
  textBuffer,
70015
- successfulWrites,
70016
- emittedWrites,
70407
+ successfulWrites: buildProgress.mutationsSucceeded,
70408
+ emittedWrites: buildProgress.mutationsAttempted,
70017
70409
  messages: harness.getMessages()
70018
70410
  };
70019
70411
  }
@@ -70037,41 +70429,6 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
70037
70429
  }
70038
70430
  ];
70039
70431
  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
70432
  let strictExit = 0;
70076
70433
  const verifierReviewDeps = {
70077
70434
  session: { provider, model },
@@ -70155,7 +70512,7 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
70155
70512
  }
70156
70513
  process.stdout.write("");
70157
70514
  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" });
70515
+ emitEvent({ type: "log", message: "[headless] BUILD failed: zero successful mutations after liveness recovery" });
70159
70516
  }
70160
70517
  try {
70161
70518
  const closeStatus = pass.finalReason === "error" ? "error" : strictExit !== 0 ? "stopped" : "completed";