@cortexkit/opencode-magic-context 0.37.0 → 0.38.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.
Files changed (94) hide show
  1. package/README.md +2 -0
  2. package/dist/{derive-budgets-0f8xpyw2.js → derive-budgets-da4yg3tz.js} +1 -1
  3. package/dist/features/magic-context/dreamer/classify-prompt.d.ts +5 -1
  4. package/dist/features/magic-context/dreamer/classify-prompt.d.ts.map +1 -1
  5. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  6. package/dist/features/magic-context/dreamer/manifest-parser.d.ts +8 -0
  7. package/dist/features/magic-context/dreamer/manifest-parser.d.ts.map +1 -1
  8. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts +7 -1
  9. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts.map +1 -1
  10. package/dist/features/magic-context/dreamer/map-memories.d.ts +18 -0
  11. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  12. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +5 -0
  13. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  14. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  15. package/dist/features/magic-context/dreamer/verify-prompt.d.ts +5 -1
  16. package/dist/features/magic-context/dreamer/verify-prompt.d.ts.map +1 -1
  17. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  18. package/dist/features/magic-context/fail-closed-block.d.ts +6 -1
  19. package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
  20. package/dist/features/magic-context/reclaim-protection.d.ts +13 -0
  21. package/dist/features/magic-context/reclaim-protection.d.ts.map +1 -0
  22. package/dist/features/magic-context/storage-db.d.ts +6 -1
  23. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  24. package/dist/features/magic-context/storage-meta-persisted.d.ts +7 -6
  25. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  26. package/dist/features/magic-context/storage-tags.d.ts +13 -5
  27. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  28. package/dist/hooks/auto-update-checker/checker.d.ts +8 -1
  29. package/dist/hooks/auto-update-checker/checker.d.ts.map +1 -1
  30. package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
  31. package/dist/hooks/magic-context/channel2-cycle.d.ts +16 -0
  32. package/dist/hooks/magic-context/channel2-cycle.d.ts.map +1 -0
  33. package/dist/hooks/magic-context/channel2-delivery.d.ts +3 -9
  34. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  35. package/dist/hooks/magic-context/command-handler.d.ts +2 -0
  36. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +33 -103
  38. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
  39. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  40. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  41. package/dist/hooks/magic-context/execute-status.d.ts +2 -1
  42. package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/fold-execution-gate.d.ts +2 -0
  44. package/dist/hooks/magic-context/fold-execution-gate.d.ts.map +1 -0
  45. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  46. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  47. package/dist/hooks/magic-context/live-session-state.d.ts +3 -0
  48. package/dist/hooks/magic-context/live-session-state.d.ts.map +1 -1
  49. package/dist/hooks/magic-context/rust-mode-transform.d.ts +4 -2
  50. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  51. package/dist/hooks/magic-context/strip-content.d.ts +10 -8
  52. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  53. package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
  54. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  55. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +78 -0
  56. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -0
  57. package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
  58. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +3 -0
  59. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  60. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  61. package/dist/{index-q0t189ay.js → index-9zhhvr4w.js} +27 -35
  62. package/dist/{index-0ze9p983.js → index-mmvhrqqb.js} +1428 -191
  63. package/dist/index.js +604 -763
  64. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  65. package/dist/plugin/messages-transform.d.ts.map +1 -1
  66. package/dist/plugin/rpc-handlers.d.ts +2 -0
  67. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  68. package/dist/{recomp-orchestrator-c3ff16k7.js → recomp-orchestrator-jsde4ygw.js} +2 -2
  69. package/dist/shared/models-dev-cache.d.ts +2 -0
  70. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  71. package/dist/shared/rpc-server.d.ts.map +1 -1
  72. package/dist/shared/rpc-types.d.ts +15 -0
  73. package/dist/shared/rpc-types.d.ts.map +1 -1
  74. package/dist/shared/rpc-utils.d.ts +9 -0
  75. package/dist/shared/rpc-utils.d.ts.map +1 -1
  76. package/dist/shared/tail-hygiene-status.d.ts +15 -0
  77. package/dist/shared/tail-hygiene-status.d.ts.map +1 -0
  78. package/dist/shared/window-geometry.d.ts +3 -2
  79. package/dist/shared/window-geometry.d.ts.map +1 -1
  80. package/package.json +3 -1
  81. package/src/config/schema/magic-context.ts +2 -2
  82. package/src/shared/models-dev-cache.test.ts +25 -0
  83. package/src/shared/models-dev-cache.ts +5 -4
  84. package/src/shared/rpc-server.ts +1 -0
  85. package/src/shared/rpc-types.ts +16 -0
  86. package/src/shared/rpc-utils.test.ts +25 -0
  87. package/src/shared/rpc-utils.ts +80 -0
  88. package/src/shared/tail-hygiene-status.ts +57 -0
  89. package/src/shared/window-geometry.test.ts +34 -1
  90. package/src/shared/window-geometry.ts +37 -40
  91. package/src/tui/index.tsx +11 -1
  92. package/src/tui/slots/sidebar-content.tsx +17 -5
  93. package/src/tui-compiled/index.tsx +311 -289
  94. package/src/tui-compiled/slots/sidebar-content.tsx +316 -287
package/dist/index.js CHANGED
@@ -14,9 +14,12 @@ import {
14
14
  AdmissionClass,
15
15
  BoundedSessionMap,
16
16
  CATEGORY_PRIORITY,
17
+ CHANNEL1_FLOOR_TOKENS,
18
+ CHANNEL1_SENTINEL,
17
19
  COMPARTMENT_AGENT_SYSTEM_PROMPT,
18
20
  COMPARTMENT_LEASE_RENEWAL_MS,
19
21
  COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT,
22
+ CTX_REDUCE_KEEP,
20
23
  DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE,
21
24
  DEFAULT_HISTORIAN_TIMEOUT_MS,
22
25
  DEFAULT_LOCAL_EMBEDDING_MODEL,
@@ -65,10 +68,14 @@ import {
65
68
  applyMirroredNoteCompileFields,
66
69
  applyStrippedPlaceholderDelta,
67
70
  archiveMemory,
71
+ assertTailHygieneContentUnchanged,
68
72
  backfillTagTokenCounts,
69
73
  beginBootQuietPeriod,
70
74
  bootQuietRemainingMs,
75
+ buildChannel1Reminder,
76
+ buildChannel2Reminder,
71
77
  buildPrimaryLanguageDirective,
78
+ buildSyntheticTodoPart,
72
79
  buildWorkspaceMemorySqlFilter,
73
80
  bumpProjectMemoryEpoch,
74
81
  bumpProjectUserProfileVersion,
@@ -95,6 +102,7 @@ import {
95
102
  clearRecompStaging,
96
103
  computeCueContentHash,
97
104
  computeNormalizedHash,
105
+ computeSyntheticCallId,
98
106
  computeWorkspaceEpochFingerprint,
99
107
  connectionFileExists,
100
108
  contentSha256,
@@ -108,6 +116,7 @@ import {
108
116
  createPrimer,
109
117
  createPromptSurfaceGuidanceEpochCache,
110
118
  createPromptSurfaceRuntime,
119
+ decideChannel1,
111
120
  deleteTagsByMessageId,
112
121
  deleteUserMemoryCandidates,
113
122
  deriveTagLoadFloor,
@@ -117,6 +126,7 @@ import {
117
126
  drainAuthority,
118
127
  drainCommitBacklogForProject,
119
128
  dropSlot,
129
+ effectiveTailHygiene,
120
130
  embedBatchForProject,
121
131
  embedItemsForProject,
122
132
  embedSessionCompartmentChunks,
@@ -129,6 +139,9 @@ import {
129
139
  ensureContextStoreUuid,
130
140
  ensureMemoryEmbeddings,
131
141
  escalationBands,
142
+ estimateEmergencyDropReclaimTokens,
143
+ estimateImageTokensFromDataUrl,
144
+ evaluateChannel2,
132
145
  expandWorkspaceIdentitySetWithAliases,
133
146
  exports_external,
134
147
  extractLatestAssistantText,
@@ -136,7 +149,6 @@ import {
136
149
  formatDate,
137
150
  getActiveCompartmentRun,
138
151
  getActivePrimers,
139
- getActiveTagTokenAggregate,
140
152
  getActiveTagTokenTotalsByMessage,
141
153
  getActiveTagsBySession,
142
154
  getActiveToolTagsForAgeReclaim,
@@ -218,6 +230,7 @@ import {
218
230
  getTagNumberByMessageId,
219
231
  getTagsByNumbers,
220
232
  getTagsBySession,
233
+ getTailHygieneTags,
221
234
  getToolTagNumberByOwner,
222
235
  getTrailingBlankDecisions,
223
236
  getTriggerTagTokenUpperBound,
@@ -249,6 +262,7 @@ import {
249
262
  isLinkedGitWorktree,
250
263
  isPidAlive,
251
264
  isProviderOverflowReconfirmed,
265
+ isSyntheticTodoPart,
252
266
  lkgContentDigest,
253
267
  loadCompartmentChunkEmbeddingsForSearch,
254
268
  loadPersistedUsage,
@@ -269,6 +283,7 @@ import {
269
283
  nextOccurrence,
270
284
  normalizeSDKResponse,
271
285
  normalizeStoredProjectPath,
286
+ normalizeTodoStateJson,
272
287
  normalizeVerificationFiles,
273
288
  noteEntry,
274
289
  onNoteTrigger,
@@ -281,6 +296,7 @@ import {
281
296
  peekNoteNudgeText,
282
297
  peekProjectEmbeddings,
283
298
  pickNearestPriorOwner,
299
+ planEmergencyDrop,
284
300
  prepareAuthority,
285
301
  prepareCompartmentInjection,
286
302
  primerOccurrenceKey,
@@ -310,6 +326,7 @@ import {
310
326
  recordOverflowDetected,
311
327
  recordSessionProjectIdentity,
312
328
  recordToolDefinition,
329
+ refreshTailHygieneBaseline,
313
330
  registerActiveCompartmentRun,
314
331
  registerModuleNoteEvaluationBridge,
315
332
  registerProjectEmbedding,
@@ -355,6 +372,7 @@ import {
355
372
  runManagedRecomp,
356
373
  runManagedUpgrade,
357
374
  runSqliteOptimize,
375
+ sameTailHygieneStructuralSignature,
358
376
  sanitizeFtsQuery,
359
377
  saveCommitEmbedding,
360
378
  saveEmbeddingIfHashMatches,
@@ -390,7 +408,9 @@ import {
390
408
  supersededMemory,
391
409
  sweepStaleEmbeddingIdentitiesForProject,
392
410
  tagTokenCountIsNull,
411
+ tailHygieneStructuralSignature,
393
412
  takeDubiousOwnershipProjectIdentityWarning,
413
+ toolOutputTokens,
394
414
  trimMemoriesToBudgetV2,
395
415
  updateCavemanDepth,
396
416
  updateMemoryRetrievalCount,
@@ -407,7 +427,7 @@ import {
407
427
  upsertCommits,
408
428
  verificationFileExists,
409
429
  withContentLanguageDirective
410
- } from "./index-0ze9p983.js";
430
+ } from "./index-mmvhrqqb.js";
411
431
  import {
412
432
  deriveHistorianChunkTokens,
413
433
  deriveTriggerBudget,
@@ -422,7 +442,7 @@ import {
422
442
  setStoragePrivatePermissionEnforcement,
423
443
  setWindowOverlayPath,
424
444
  shouldEnforcePrivateStoragePermissions
425
- } from "./index-q0t189ay.js";
445
+ } from "./index-9zhhvr4w.js";
426
446
  import {
427
447
  modelBodyField,
428
448
  resolveFallbackChain
@@ -11051,8 +11071,8 @@ function getCurrentRuntimePackageJsonPath(currentModuleUrl = import.meta.url) {
11051
11071
  return null;
11052
11072
  }
11053
11073
  }
11054
- function findPluginEntry(directory) {
11055
- const winner = getWinningConfig(directory, "server");
11074
+ function findPluginEntry(directory, surface = "server") {
11075
+ const winner = getWinningConfig(directory, surface);
11056
11076
  if (!winner)
11057
11077
  return null;
11058
11078
  const entry = winner.entries.find((value) => value === PACKAGE_NAME || value.startsWith(`${PACKAGE_NAME}@`));
@@ -11066,13 +11086,21 @@ function findPluginEntry(directory) {
11066
11086
  configPath: winner.path
11067
11087
  };
11068
11088
  }
11089
+ function hasExplicitNonExactPluginVersion(spec) {
11090
+ if (!spec.startsWith(`${PACKAGE_NAME}@`))
11091
+ return false;
11092
+ return !isValidSemver(spec.slice(PACKAGE_NAME.length + 1));
11093
+ }
11094
+ function isExactOrBarePluginSpec(spec) {
11095
+ return spec === PACKAGE_NAME || spec.startsWith(`${PACKAGE_NAME}@`) && !hasExplicitNonExactPluginVersion(spec);
11096
+ }
11069
11097
  function configUpdateContent(content, version) {
11070
11098
  const parsed = parseJsonConfig(content);
11071
11099
  if (!parsed)
11072
11100
  return null;
11073
11101
  const entries = getPluginEntries(parsed);
11074
11102
  const current = entries.find((entry) => entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`));
11075
- if (!current)
11103
+ if (!current || !isExactOrBarePluginSpec(current))
11076
11104
  return null;
11077
11105
  const escaped = current.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
11078
11106
  const entryRegex = new RegExp(`(["'])${escaped}\\1`);
@@ -11390,6 +11418,12 @@ async function runBackgroundUpdateCheck(ctx, options) {
11390
11418
  log("[auto-update-checker] Plugin not found in config");
11391
11419
  return;
11392
11420
  }
11421
+ if (hasExplicitNonExactPluginVersion(pluginInfo.entry)) {
11422
+ if (pluginInfo.entry === `${PACKAGE_NAME}@latest`) {
11423
+ log("[auto-update-checker] Explicit @latest leaves the active package unpinned; OpenCode may delete it mid-session.");
11424
+ }
11425
+ return;
11426
+ }
11393
11427
  const cachedVersion = getCachedVersion(pluginInfo.entry);
11394
11428
  const currentVersion = cachedVersion ?? pluginInfo.pinnedVersion;
11395
11429
  if (!currentVersion) {
@@ -11445,6 +11479,7 @@ function createLiveSessionState() {
11445
11479
  liveModelBySession: new Map,
11446
11480
  variantBySession: new Map,
11447
11481
  agentBySession: new Map,
11482
+ channel1StateBySession: new Map,
11448
11483
  historyRefreshSessions: new Set,
11449
11484
  deferredHistoryRefreshSessions: new Set,
11450
11485
  systemPromptRefreshSessions: new Set,
@@ -12723,6 +12758,34 @@ function assertManifestCoversExactly(ids, expectedIds, rootName) {
12723
12758
  throw new Error(`${rootName} manifest missing id ${id}`);
12724
12759
  }
12725
12760
  }
12761
+ var OPEN_TAG_RE = /<([A-Za-z][\w:-]*)\b/;
12762
+ function describeUnrecognizedManifestShape(text, expectedRoot, expectedEntry) {
12763
+ const expected = `expected <${expectedRoot}> with <${expectedEntry}> entries`;
12764
+ const trimmed = text.trim();
12765
+ if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
12766
+ return `JSON ${trimmed.startsWith("[") ? "array" : "object"} unrecognized; ${expected}`;
12767
+ }
12768
+ const firstTag = OPEN_TAG_RE.exec(trimmed)?.[1];
12769
+ if (firstTag && firstTag.toLowerCase() !== expectedRoot.toLowerCase()) {
12770
+ return `root <${firstTag}> unrecognized; ${expected}`;
12771
+ }
12772
+ const escapedRoot = expectedRoot.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12773
+ const bodyMatch = new RegExp(`<${escapedRoot}\\b[^>]*>([\\s\\S]*?)<\\/${escapedRoot}>`, "i").exec(text);
12774
+ const body = (bodyMatch?.[1] ?? "").trim();
12775
+ if (body.startsWith("[") || body.startsWith("{")) {
12776
+ return `JSON ${body.startsWith("[") ? "array" : "object"} unrecognized; ${expected}`;
12777
+ }
12778
+ const innerTag = OPEN_TAG_RE.exec(body)?.[1];
12779
+ if (innerTag && innerTag.toLowerCase() !== expectedEntry.toLowerCase()) {
12780
+ return `root <${innerTag}> unrecognized; ${expected}`;
12781
+ }
12782
+ return `parsed zero entries; ${expected}`;
12783
+ }
12784
+ function assertParsedManifestNonEmpty(parsedCount, expectedCount, text, expectedRoot, expectedEntry) {
12785
+ if (expectedCount > 0 && parsedCount === 0) {
12786
+ throw new Error(describeUnrecognizedManifestShape(text, expectedRoot, expectedEntry));
12787
+ }
12788
+ }
12726
12789
 
12727
12790
  // src/features/magic-context/dreamer/module-apply.ts
12728
12791
  class DreamerModuleBusyError extends Error {
@@ -13754,9 +13817,19 @@ ${renderAnchors(args.anchors ?? [])}### Memory pool to classify
13754
13817
  ${renderPool2(args.memories)}`;
13755
13818
  }
13756
13819
  var SCOPES = new Set(["project", "ecosystem", "universe"]);
13820
+ function classifyBody(text) {
13821
+ try {
13822
+ return extractCompleteManifestBody(text, "classify");
13823
+ } catch (error) {
13824
+ const described = describeUnrecognizedManifestShape(text, "classify", "memory");
13825
+ if (!described.startsWith("parsed zero entries"))
13826
+ throw new Error(described);
13827
+ throw error;
13828
+ }
13829
+ }
13757
13830
  function parseClassifyManifest(text) {
13758
13831
  const out = [];
13759
- const body = extractCompleteManifestBody(text, "classify");
13832
+ const body = classifyBody(text);
13760
13833
  for (const m of body.matchAll(/<memory\b([^>]*)\/?>/g)) {
13761
13834
  const attrs = m[1];
13762
13835
  const idMatch = attrs.match(/\bid\s*=\s*"(\d+)"/);
@@ -13789,9 +13862,18 @@ function parseClassifyManifest(text) {
13789
13862
  }
13790
13863
  out.push(entry);
13791
13864
  }
13865
+ if (out.length === 0 && body.trim().length > 0) {
13866
+ throw new Error(describeUnrecognizedManifestShape(text, "classify", "memory"));
13867
+ }
13792
13868
  assertNoDuplicateManifestIds(out.map((entry) => entry.id), "classify");
13793
13869
  return out;
13794
13870
  }
13871
+ function validateClassifyManifest(text, expectedIds) {
13872
+ const parsed = parseClassifyManifest(text);
13873
+ assertParsedManifestNonEmpty(parsed.length, expectedIds.size, text, "classify", "memory");
13874
+ assertManifestCoversExactly(parsed.map((entry) => entry.id), expectedIds, "classify");
13875
+ return parsed;
13876
+ }
13795
13877
 
13796
13878
  // src/features/magic-context/dreamer/classify.ts
13797
13879
  var MIN_POOL_TO_CLASSIFY = 10;
@@ -13990,7 +14072,7 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
13990
14072
  if (!text)
13991
14073
  throw new Error("classify returned no output");
13992
14074
  try {
13993
- parseClassifyManifest(text);
14075
+ validateClassifyManifest(text, new Set(chunk.map((candidate) => candidate.id)));
13994
14076
  } catch (error) {
13995
14077
  const providerFailure = providerOutputFailureFromInvalidManifest(messages, text);
13996
14078
  if (providerFailure)
@@ -14058,8 +14140,7 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
14058
14140
  if (result.truncated === true) {
14059
14141
  throw new Error("classify returned length-capped output");
14060
14142
  }
14061
- const parsed = parseClassifyManifest(manifestText);
14062
- assertManifestCoversExactly(parsed.map((entry) => entry.id), new Set(chunk.map((candidate) => candidate.id)), "classify");
14143
+ const parsed = validateClassifyManifest(manifestText, new Set(chunk.map((candidate) => candidate.id)));
14063
14144
  const rows = parsed.map((entry) => {
14064
14145
  const candidate = chunk.find((item) => item.id === entry.id);
14065
14146
  if (!candidate)
@@ -16088,11 +16169,33 @@ For each memory below, find the repo file(s) it makes a claim about, or mark it
16088
16169
  ${list}
16089
16170
  </memories>`;
16090
16171
  }
16172
+ var MEMORY_ELEMENT_PATTERN = "<memory\\b([^>]*)(?:\\/>|>([\\s\\S]*?)<\\/memory>)";
16173
+ var NESTED_FILE_PATTERN = "<file\\b([^>]*)\\/?>";
16174
+ function extractNestedFilePaths(inner) {
16175
+ const files = [];
16176
+ for (const match of inner.matchAll(new RegExp(NESTED_FILE_PATTERN, "gi"))) {
16177
+ const pathMatch = match[1].match(/\bpath\s*=\s*"([^"]+)"/);
16178
+ if (pathMatch)
16179
+ files.push(pathMatch[1].trim());
16180
+ }
16181
+ return files.filter(Boolean);
16182
+ }
16183
+ function mappingsBody(text) {
16184
+ try {
16185
+ return extractCompleteManifestBody(text, "mappings");
16186
+ } catch (error) {
16187
+ const described = describeUnrecognizedManifestShape(text, "mappings", "memory");
16188
+ if (!described.startsWith("parsed zero entries"))
16189
+ throw new Error(described);
16190
+ throw error;
16191
+ }
16192
+ }
16091
16193
  function parseMapMemoriesManifest(text) {
16092
16194
  const out = [];
16093
- const body = extractCompleteManifestBody(text, "mappings");
16094
- for (const m of body.matchAll(/<memory\b([^>]*)\/?>/g)) {
16195
+ const body = mappingsBody(text);
16196
+ for (const m of body.matchAll(new RegExp(MEMORY_ELEMENT_PATTERN, "gi"))) {
16095
16197
  const attrs = m[1];
16198
+ const inner = m[2];
16096
16199
  const idMatch = attrs.match(/\bid\s*=\s*"(\d+)"/);
16097
16200
  if (!idMatch)
16098
16201
  throw new Error("mappings manifest entry missing numeric id");
@@ -16101,24 +16204,67 @@ function parseMapMemoriesManifest(text) {
16101
16204
  throw new Error("mappings manifest entry missing numeric id");
16102
16205
  const independent = /\bindependent\s*=\s*"(?:true|1)"/i.test(attrs);
16103
16206
  const filesMatch = attrs.match(/\bfiles\s*=\s*"([^"]*)"/);
16104
- const files = filesMatch ? filesMatch[1].split(",").map((f) => f.trim()).filter(Boolean) : [];
16105
- out.push({ id, files, independent: independent || files.length === 0 });
16207
+ const attrFiles = filesMatch ? filesMatch[1].split(",").map((f) => f.trim()).filter(Boolean) : [];
16208
+ const nestedFiles = inner ? extractNestedFilePaths(inner) : [];
16209
+ const files = attrFiles.length > 0 ? attrFiles : nestedFiles;
16210
+ if (!independent && files.length === 0) {
16211
+ throw new Error(`mappings manifest entry ${id} has neither files nor independent="true"`);
16212
+ }
16213
+ out.push({
16214
+ id,
16215
+ files: independent && files.length === 0 ? [] : files,
16216
+ independent: independent && files.length === 0
16217
+ });
16218
+ }
16219
+ if (out.length === 0 && body.trim().length > 0) {
16220
+ throw new Error(describeUnrecognizedManifestShape(text, "mappings", "memory"));
16106
16221
  }
16107
16222
  assertNoDuplicateManifestIds(out.map((entry) => entry.id), "mappings");
16108
16223
  return out;
16109
16224
  }
16225
+ function validateMapMemoriesManifest(text, expectedIds) {
16226
+ const parsed = parseMapMemoriesManifest(text);
16227
+ assertParsedManifestNonEmpty(parsed.length, expectedIds.size, text, "mappings", "memory");
16228
+ assertManifestCoversExactly(parsed.map((entry) => entry.id), expectedIds, "mappings");
16229
+ return parsed;
16230
+ }
16110
16231
 
16111
16232
  // src/features/magic-context/dreamer/map-memories.ts
16112
16233
  var MAP_BATCH_SIZE = 80;
16113
- function loadUnmappedInputs(db, projectIdentity, repoDir) {
16234
+ var MAX_INDEPENDENT_REQUEUE_PER_RUN = MAP_BATCH_SIZE;
16235
+ function shouldRequeueIndependentMapping(state, content, repoDir) {
16236
+ if (!state.hasSentinel || state.files.length > 0)
16237
+ return false;
16238
+ return extractMemoryCandidatePaths(content, repoDir).length > 0;
16239
+ }
16240
+ function toMapInput(memory, repoDir) {
16241
+ return {
16242
+ id: memory.id,
16243
+ category: memory.category,
16244
+ content: memory.content,
16245
+ candidates: extractMemoryCandidatePaths(memory.content, repoDir)
16246
+ };
16247
+ }
16248
+ function selectMapMemoryInputs(db, projectIdentity, repoDir) {
16114
16249
  const active = getMemoriesByProject(db, projectIdentity);
16115
- const unmapped = new Set(getUnmappedMemoryIds(db, active.map((m) => m.id)));
16116
- return active.filter((m) => unmapped.has(m.id)).map((m) => ({
16117
- id: m.id,
16118
- category: m.category,
16119
- content: m.content,
16120
- candidates: extractMemoryCandidatePaths(m.content, repoDir)
16121
- }));
16250
+ const activeIds = active.map((m) => m.id);
16251
+ const unmapped = new Set(getUnmappedMemoryIds(db, activeIds));
16252
+ const verifications = getMemoryVerifications(db, activeIds);
16253
+ const unmappedInputs = active.filter((m) => unmapped.has(m.id)).map((m) => toMapInput(m, repoDir));
16254
+ const requeue = [];
16255
+ for (const memory of active) {
16256
+ if (unmapped.has(memory.id))
16257
+ continue;
16258
+ const state = verifications.get(memory.id);
16259
+ if (!state)
16260
+ continue;
16261
+ if (!shouldRequeueIndependentMapping(state, memory.content, repoDir))
16262
+ continue;
16263
+ requeue.push(toMapInput(memory, repoDir));
16264
+ if (requeue.length >= MAX_INDEPENDENT_REQUEUE_PER_RUN)
16265
+ break;
16266
+ }
16267
+ return [...unmappedInputs, ...requeue];
16122
16268
  }
16123
16269
  async function mapMemories(args) {
16124
16270
  const result = {
@@ -16128,7 +16274,7 @@ async function mapMemories(args) {
16128
16274
  remaining: 0,
16129
16275
  complete: true
16130
16276
  };
16131
- const inputs = loadUnmappedInputs(args.db, args.projectIdentity, args.sessionDirectory);
16277
+ const inputs = selectMapMemoryInputs(args.db, args.projectIdentity, args.sessionDirectory);
16132
16278
  if (inputs.length === 0)
16133
16279
  return result;
16134
16280
  const batches = [];
@@ -16207,7 +16353,7 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
16207
16353
  const text = extractLatestAssistantText(messages);
16208
16354
  if (!text)
16209
16355
  throw new Error("map-memories returned no output");
16210
- parseMapMemoriesManifest(text);
16356
+ validateMapMemoriesManifest(text, new Set(batch.map((memory) => memory.id)));
16211
16357
  return text;
16212
16358
  }
16213
16359
  });
@@ -16241,10 +16387,13 @@ async function applyBatchMappings(args, batch, manifestText) {
16241
16387
  return { mapped: 0, independent: 0 };
16242
16388
  const planned = [];
16243
16389
  for (const p of parsed) {
16244
- if (p.independent || p.files.length === 0) {
16390
+ if (p.independent) {
16245
16391
  planned.push({ id: p.id, files: [], independent: true });
16246
16392
  continue;
16247
16393
  }
16394
+ if (p.files.length === 0) {
16395
+ throw new Error(`mapping entry ${p.id} has no files and no independent sentinel`);
16396
+ }
16248
16397
  const normalized = await normalizeVerificationFiles({
16249
16398
  cwd: args.sessionDirectory,
16250
16399
  files: p.files
@@ -17389,9 +17538,22 @@ function attrOf(s, name) {
17389
17538
  function filesOf(s) {
17390
17539
  return (attrOf(s, "files") ?? "").split(",").map((f) => f.trim()).filter(Boolean);
17391
17540
  }
17541
+ function verifyIds(parsed) {
17542
+ return [...parsed.verified, ...parsed.updated, ...parsed.archived].map((entry) => entry.id);
17543
+ }
17544
+ function verifyBody(text) {
17545
+ try {
17546
+ return extractCompleteManifestBody(text, "verify");
17547
+ } catch (error) {
17548
+ const described = describeUnrecognizedManifestShape(text, "verify", "verified");
17549
+ if (!described.startsWith("parsed zero entries"))
17550
+ throw new Error(described);
17551
+ throw error;
17552
+ }
17553
+ }
17392
17554
  function parseVerifyManifest(text) {
17393
17555
  const out = { verified: [], updated: [], archived: [] };
17394
- const body = extractCompleteManifestBody(text, "verify");
17556
+ const body = verifyBody(text);
17395
17557
  for (const m of body.matchAll(/<verified\b([^>]*)\/?>/g)) {
17396
17558
  const id = Number.parseInt(attrOf(m[1], "id") ?? "", 10);
17397
17559
  if (!Number.isInteger(id))
@@ -17410,9 +17572,19 @@ function parseVerifyManifest(text) {
17410
17572
  throw new Error("verify manifest entry missing numeric id");
17411
17573
  out.archived.push({ id, reason: attrOf(m[1], "reason") ?? "" });
17412
17574
  }
17413
- assertNoDuplicateManifestIds([...out.verified, ...out.updated, ...out.archived].map((entry) => entry.id), "verify");
17575
+ if (verifyIds(out).length === 0 && body.trim().length > 0) {
17576
+ throw new Error(describeUnrecognizedManifestShape(text, "verify", "verified"));
17577
+ }
17578
+ assertNoDuplicateManifestIds(verifyIds(out), "verify");
17414
17579
  return out;
17415
17580
  }
17581
+ function validateVerifyManifest(text, expectedIds) {
17582
+ const parsed = parseVerifyManifest(text);
17583
+ const ids = verifyIds(parsed);
17584
+ assertParsedManifestNonEmpty(ids.length, expectedIds.size, text, "verify", "verified");
17585
+ assertManifestCoversExactly(ids, expectedIds, "verify");
17586
+ return parsed;
17587
+ }
17416
17588
 
17417
17589
  // src/features/magic-context/dreamer/verify.ts
17418
17590
  var VERIFY_BATCH_SIZE = 50;
@@ -17564,7 +17736,7 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
17564
17736
  if (!text)
17565
17737
  throw new Error("verify returned no output");
17566
17738
  try {
17567
- parseVerifyManifest(text);
17739
+ validateVerifyManifest(text, new Set(batch.map((memory) => memory.id)));
17568
17740
  } catch (error) {
17569
17741
  const providerFailure = providerOutputFailureFromInvalidManifest(messages, text);
17570
17742
  if (providerFailure)
@@ -17784,6 +17956,18 @@ function loadActiveMemoryPromptMemories(db, projectIdentity) {
17784
17956
  const verificationById = getMemoryVerifications(db, memories.map((memory) => memory.id));
17785
17957
  return memories.map((memory) => toCuratePromptMemory(memory, verificationById));
17786
17958
  }
17959
+ var TEXTUAL_CURATE_TOOL_CALL_PATTERNS = [
17960
+ /\[\s*historical tool call\s*\][\s\S]*?(?:^|\n)\s*name\s*:\s*ctx_memory\b[\s\S]*?(?:^|\n)\s*arguments\s*:/im,
17961
+ /(?:^|\n)\s*name\s*:\s*ctx_memory\b[\s\S]*?(?:^|\n)\s*arguments\s*:/im,
17962
+ /(?:^|\n)\s*(?:```[^\n]*\n\s*)?ctx_memory\s*\(\s*action\s*=/im,
17963
+ /["']name["']\s*:\s*["']ctx_memory["'][\s\S]*?["']arguments["']\s*:/i
17964
+ ];
17965
+ function validateCurateAssistantText(text) {
17966
+ if (TEXTUAL_CURATE_TOOL_CALL_PATTERNS.some((pattern) => pattern.test(text))) {
17967
+ throw new Error("Curate returned an unresolved textual ctx_memory tool call.");
17968
+ }
17969
+ return text;
17970
+ }
17787
17971
  function createDreamTaskExecutor(deps) {
17788
17972
  let parentSessionIdPromise;
17789
17973
  const resolveParentSessionId = () => {
@@ -17854,7 +18038,8 @@ function createDreamTaskExecutor(deps) {
17854
18038
  name: config.task,
17855
18039
  durationMs: Date.now() - startedAt,
17856
18040
  resultChars: 0,
17857
- ...error ? { error } : {},
18041
+ ...status === "failed" && error ? { error } : {},
18042
+ ...extra?.progress ? { progress: extra.progress } : {},
17858
18043
  backlog: (() => {
17859
18044
  const end = extra?.backlogAfter ?? getDreamTaskBacklog(db, projectIdentity, config.task);
17860
18045
  const processed = processedDreamTaskItems(backlogAtStart.pending, end.pending);
@@ -17997,11 +18182,12 @@ function createDreamTaskExecutor(deps) {
17997
18182
  const backlogAfter = config.task === "verify-broad" ? { pending: result.remaining, total: backlogAtStart.total } : undefined;
17998
18183
  if (!result.complete) {
17999
18184
  if (broadProgress && processed > 0) {
18000
- recordRun("completed", broadProgress, {
18185
+ recordRun("completed", null, {
18186
+ progress: broadProgress,
18001
18187
  memoryChanges: computeMemoryDelta(memoryBefore),
18002
18188
  backlogAfter
18003
18189
  });
18004
- return { status: "completed", error: broadProgress };
18190
+ return { status: "completed" };
18005
18191
  }
18006
18192
  const error = incompleteMessage(result.remaining);
18007
18193
  recordRun("failed", error, {
@@ -18010,11 +18196,12 @@ function createDreamTaskExecutor(deps) {
18010
18196
  });
18011
18197
  return { status: "failed", transient: true, error };
18012
18198
  }
18013
- recordRun("completed", broadProgress, {
18199
+ recordRun("completed", null, {
18200
+ progress: broadProgress,
18014
18201
  memoryChanges: computeMemoryDelta(memoryBefore),
18015
18202
  backlogAfter
18016
18203
  });
18017
- return broadProgress ? { status: "completed", error: broadProgress } : { status: "completed" };
18204
+ return { status: "completed" };
18018
18205
  }
18019
18206
  if (config.task === "classify-memories") {
18020
18207
  let moduleArgs;
@@ -18481,7 +18668,7 @@ async function runAgenticTask(config, ctx, helpers) {
18481
18668
  const text = extractLatestAssistantText(messages);
18482
18669
  if (!text)
18483
18670
  throw new Error("Dreamer returned no assistant output.");
18484
- return text;
18671
+ return task === "curate" ? validateCurateAssistantText(text) : text;
18485
18672
  }
18486
18673
  });
18487
18674
  if (leaseLost)
@@ -20358,6 +20545,44 @@ function createTagger() {
20358
20545
  // src/hooks/magic-context/command-handler.ts
20359
20546
  import { randomUUID as randomUUID2 } from "node:crypto";
20360
20547
 
20548
+ // src/shared/tail-hygiene-status.ts
20549
+ function finiteNumber(value, fallback = 0) {
20550
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
20551
+ }
20552
+ function resolveTailHygieneStatus(tsBaseline, rustBaseline) {
20553
+ if (rustBaseline !== undefined && rustBaseline !== null) {
20554
+ const t2 = Math.max(0, finiteNumber(rustBaseline.t));
20555
+ const u2 = Math.min(t2, Math.max(0, finiteNumber(rustBaseline.u)));
20556
+ return {
20557
+ u: u2,
20558
+ t: t2,
20559
+ severity: Math.min(1, Math.max(0, finiteNumber(rustBaseline.severity, u2 / Math.max(t2, 1)))),
20560
+ evaluable: rustBaseline.evaluable === true,
20561
+ generationInvalidated: rustBaseline.generation_invalidated === true,
20562
+ baselineGeneration: Math.max(0, finiteNumber(rustBaseline.baseline_generation)),
20563
+ computedAt: Math.max(0, finiteNumber(rustBaseline.computed_at_ms))
20564
+ };
20565
+ }
20566
+ if (tsBaseline === undefined)
20567
+ return;
20568
+ const t = Math.max(0, tsBaseline.baselineT + tsBaseline.turnDeltaT);
20569
+ const u = Math.min(t, Math.max(0, tsBaseline.baselineU + tsBaseline.turnDeltaU));
20570
+ return {
20571
+ u,
20572
+ t,
20573
+ severity: Math.min(1, Math.max(0, u / Math.max(t, 1))),
20574
+ evaluable: tsBaseline.evaluable && !tsBaseline.generationInvalidated,
20575
+ generationInvalidated: tsBaseline.generationInvalidated,
20576
+ baselineGeneration: Math.max(0, tsBaseline.baselineGeneration),
20577
+ computedAt: Math.max(0, tsBaseline.computedAt)
20578
+ };
20579
+ }
20580
+ function formatTailHygiene(status) {
20581
+ const percentage = (status.severity * 100).toFixed(1);
20582
+ const state = status.evaluable ? "" : " · held until baseline refresh";
20583
+ return `${percentage}% · ${status.u.toLocaleString()} / ${status.t.toLocaleString()} tok${state}`;
20584
+ }
20585
+
20361
20586
  // src/hooks/magic-context/execute-flush.ts
20362
20587
  function executeFlush(db, sessionId) {
20363
20588
  try {
@@ -20798,7 +21023,7 @@ function formatExecuteThreshold(detail, contextLimit) {
20798
21023
  }
20799
21024
  return `${percentage}%${clampNote}`;
20800
21025
  }
20801
- function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageConfig = DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, liveModelKey, historyBudgetPercentage, commitClusterTrigger, executeThresholdTokens, contextLimit, dreamer, windowGeometry) {
21026
+ function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageConfig = DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, liveModelKey, historyBudgetPercentage, commitClusterTrigger, executeThresholdTokens, contextLimit, dreamer, windowGeometry, tailHygiene) {
20802
21027
  const thresholdDetail = resolveExecuteThresholdDetail(executeThresholdPercentageConfig, liveModelKey, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, {
20803
21028
  tokensConfig: executeThresholdTokens,
20804
21029
  contextLimit,
@@ -20853,6 +21078,9 @@ function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageC
20853
21078
  `**Protected tags:** ${protectedTags}`,
20854
21079
  `**Subagent session:** ${meta.isSubagent}`
20855
21080
  ];
21081
+ if (tailHygiene !== undefined) {
21082
+ lines.push("", "### Tail Hygiene", `- Reclaimable / eligible: ${formatTailHygiene(tailHygiene)}`, "- Reasoning is excluded from both terms.");
21083
+ }
20856
21084
  if (dreamer?.backlog && Object.keys(dreamer.backlog).length > 0) {
20857
21085
  lines.push("", "### Dreamer", ...dreamer.progress ? [
20858
21086
  `- Running: ${dreamer.progress.task} — ${dreamer.progress.processed}/${dreamer.progress.total} processed`
@@ -21329,10 +21557,12 @@ Embedding status is unavailable.`;
21329
21557
  const liveContextLimit = deps.getContextLimit?.(sessionId);
21330
21558
  const modelSlash = liveModelKey?.indexOf("/") ?? -1;
21331
21559
  const windowGeometry = liveModelKey && modelSlash > 0 ? resolveContextWindowGeometry(liveModelKey.slice(0, modelSlash), liveModelKey.slice(modelSlash + 1), { db: deps.db, sessionID: sessionId }) : undefined;
21560
+ const rustTailHygiene = rustStatus?.tail_hygiene;
21561
+ const tailHygiene = resolveTailHygieneStatus(deps.getTailHygiene?.(sessionId), rustTailHygiene && typeof rustTailHygiene === "object" ? rustTailHygiene : undefined);
21332
21562
  const statusOutput = executeStatus(deps.db, sessionId, deps.protectedTags, deps.executeThresholdPercentage, liveModelKey, deps.historyBudgetPercentage, deps.commitClusterTrigger, deps.executeThresholdTokens, liveContextLimit, deps.dreamer ? {
21333
21563
  backlog: readDreamTaskBacklogsSafely(deps.db, deps.dreamer.projectPath, CANONICAL_DREAM_TASKS),
21334
21564
  progress: deps.getDreamerProgress?.() ?? null
21335
- } : undefined, windowGeometry);
21565
+ } : undefined, windowGeometry, tailHygiene);
21336
21566
  const moduleStatus = rustStatus ? `
21337
21567
 
21338
21568
  ${formatRustStatusText(rustStatus)}` : "";
@@ -22363,185 +22593,6 @@ function captureWindowReport(input) {
22363
22593
 
22364
22594
  // src/hooks/magic-context/channel2-delivery.ts
22365
22595
  import { randomUUID as randomUUID3 } from "node:crypto";
22366
-
22367
- // src/hooks/magic-context/ctx-reduce-nudge.ts
22368
- var CHANNEL1_SENTINEL = "<system-reminder>";
22369
- var TOKENS_PER_BYTE = 0.25;
22370
- var CHANNEL1_FLOOR_TOKENS = 1e4;
22371
- var CHANNEL1_REFIRE_FLOOR_TOKENS = 1e4;
22372
- function channel1RefireTokens(workingWindowTokens) {
22373
- const scaled = Math.round(0.05 * Math.max(0, workingWindowTokens));
22374
- return Math.max(CHANNEL1_REFIRE_FLOOR_TOKENS, scaled);
22375
- }
22376
- var S_GENTLE = 0.2;
22377
- var S_FIRM = 0.4;
22378
- var S_URGENT = 0.65;
22379
- var CHANNEL1_PRESSURE_FLOOR = 0.8;
22380
- var LEVEL_RANK = { gentle: 1, firm: 2, urgent: 3 };
22381
- var DROP_SENTINELS = ["[dropped", "[truncated"];
22382
- function isDroppedToolOutput(output) {
22383
- const head = output.slice(0, 16);
22384
- return DROP_SENTINELS.some((s) => head.startsWith(s));
22385
- }
22386
- function isToolPartWithStringOutput(part) {
22387
- if (part === null || typeof part !== "object")
22388
- return false;
22389
- const p = part;
22390
- if (p.type !== "tool" && p.type !== "tool-invocation")
22391
- return false;
22392
- const state = p.state;
22393
- return typeof state?.output === "string";
22394
- }
22395
- function toolOutputTokens(output) {
22396
- return Math.round(byteSize(output) * TOKENS_PER_BYTE);
22397
- }
22398
- function stringTokens(value) {
22399
- return Math.round(byteSize(value) * TOKENS_PER_BYTE);
22400
- }
22401
- function unknownJsonTokens(value) {
22402
- if (value === undefined || value === null)
22403
- return 0;
22404
- try {
22405
- return stringTokens(JSON.stringify(value));
22406
- } catch {
22407
- return 0;
22408
- }
22409
- }
22410
- function textFromPart(part) {
22411
- if (part === null || typeof part !== "object")
22412
- return "";
22413
- const p = part;
22414
- if (typeof p.text === "string")
22415
- return p.text;
22416
- if (typeof p.content === "string")
22417
- return p.content;
22418
- if (typeof p.thinking === "string")
22419
- return p.thinking;
22420
- return "";
22421
- }
22422
- function computeTailTokenEstimate(messages) {
22423
- let toolOutputTokensTotal = 0;
22424
- let toolCallTokensTotal = 0;
22425
- let conversationTokens = 0;
22426
- for (const message of messages) {
22427
- for (const part of message.parts) {
22428
- if (isToolPartWithStringOutput(part)) {
22429
- const outputTokens = isDroppedToolOutput(part.state.output) ? 0 : toolOutputTokens(part.state.output);
22430
- const inputTokens = unknownJsonTokens(part.state?.input);
22431
- toolOutputTokensTotal += outputTokens;
22432
- toolCallTokensTotal += outputTokens + inputTokens;
22433
- continue;
22434
- }
22435
- conversationTokens += stringTokens(textFromPart(part));
22436
- }
22437
- }
22438
- return {
22439
- tailToolTokens: toolOutputTokensTotal,
22440
- liveTailTokens: conversationTokens + toolCallTokensTotal
22441
- };
22442
- }
22443
- function decideChannel1(input) {
22444
- const { undroppedTokens, workingWindowTokens, hasRecentReduce } = input;
22445
- const pressure = Math.min(1, Math.max(0, input.pressure));
22446
- const resetCycle = hasRecentReduce || undroppedTokens < input.lastNudgeUndropped;
22447
- const lastNudge = resetCycle ? 0 : input.lastNudgeUndropped;
22448
- const lastLevel = resetCycle ? "" : input.lastNudgeLevel;
22449
- const quiet = () => ({
22450
- fire: false,
22451
- level: "gentle",
22452
- undroppedTokens,
22453
- nextLastNudge: lastNudge,
22454
- nextLastNudgeLevel: lastLevel
22455
- });
22456
- if (hasRecentReduce)
22457
- return quiet();
22458
- if (undroppedTokens < CHANNEL1_FLOOR_TOKENS)
22459
- return quiet();
22460
- if (pressure < CHANNEL1_PRESSURE_FLOOR)
22461
- return quiet();
22462
- const denom = Math.max(input.estimatedInputTokens, 1);
22463
- const severity = Math.min(1, undroppedTokens / denom);
22464
- if (severity < S_GENTLE)
22465
- return quiet();
22466
- let level;
22467
- if (severity >= S_URGENT)
22468
- level = "urgent";
22469
- else if (severity >= S_FIRM)
22470
- level = "firm";
22471
- else
22472
- level = "gentle";
22473
- if (lastLevel === "") {
22474
- if (undroppedTokens < lastNudge + channel1RefireTokens(workingWindowTokens)) {
22475
- return quiet();
22476
- }
22477
- } else if (LEVEL_RANK[level] <= LEVEL_RANK[lastLevel]) {
22478
- return quiet();
22479
- }
22480
- return {
22481
- fire: true,
22482
- level,
22483
- undroppedTokens,
22484
- nextLastNudge: undroppedTokens,
22485
- nextLastNudgeLevel: level
22486
- };
22487
- }
22488
- function computePressure(input) {
22489
- const { lastInputTokens, turnToolTokens, contextLimit, executeThresholdPercentage } = input;
22490
- if (contextLimit <= 0 || executeThresholdPercentage <= 0)
22491
- return 0;
22492
- const estimatedInput = lastInputTokens + turnToolTokens;
22493
- const usagePercentage = estimatedInput / contextLimit * 100;
22494
- return usagePercentage / executeThresholdPercentage;
22495
- }
22496
- function approxThousands(tokens) {
22497
- return `${Math.round(tokens / 1000)}k`;
22498
- }
22499
- function formatOldestReclaimableHint(hint) {
22500
- if (!hint || hint.length === 0)
22501
- return "";
22502
- const rendered = hint.slice(0, 4).map((tag) => `§${tag.tagNumber}§ ${tag.toolName ?? "tool"}`).join(" · ");
22503
- return rendered.length > 0 ? `
22504
- oldest reclaimable: ${rendered}.` : "";
22505
- }
22506
- var CHANNEL2_USABLE_FRACTION = 1 / 3;
22507
- var CHANNEL2_MIN_RECLAIMABLE = 1e4;
22508
- function shouldTriggerChannel2(input) {
22509
- if (input.reclaimableTokens < CHANNEL2_MIN_RECLAIMABLE)
22510
- return false;
22511
- if (input.usableTokens <= 0)
22512
- return true;
22513
- return input.reclaimableTokens >= input.usableTokens * CHANNEL2_USABLE_FRACTION;
22514
- }
22515
- function buildChannel2Reminder(undroppedTokens, hint) {
22516
- const amount = approxThousands(undroppedTokens);
22517
- const hintText = formatOldestReclaimableHint(hint);
22518
- return `<system-reminder>
22519
- ` + `Routine context housekeeping is near: a large span of this session will be comparted soon, ` + `and ~${amount} tokens of tool output remain unreduced. Drop spent outputs with ctx_reduce ` + `first so the archived span is the part that matters.${hintText}
22520
- ` + `</system-reminder>`;
22521
- }
22522
- function buildChannel1Reminder(level, undroppedTokens, hint) {
22523
- const amount = approxThousands(undroppedTokens);
22524
- const hintText = formatOldestReclaimableHint(hint);
22525
- let body;
22526
- switch (level) {
22527
- case "gentle":
22528
- body = `You have ~${amount} tokens of tool output you have not reduced. ` + `When you are done with earlier outputs, dropping them with ctx_reduce keeps context lean.`;
22529
- break;
22530
- case "firm":
22531
- body = `~${amount} tokens of unreduced tool output has built up. ` + `At your next natural stopping point, consider dropping what you have already processed with ctx_reduce.`;
22532
- break;
22533
- case "urgent":
22534
- body = `~${amount} tokens of unreduced tool output remain, and a large span of this session will be comparted before long. ` + `Consider dropping spent outputs with ctx_reduce so the archived span is the part that matters.`;
22535
- break;
22536
- }
22537
- return `
22538
-
22539
- <system-reminder>
22540
- ${body}${hintText}
22541
- </system-reminder>`;
22542
- }
22543
-
22544
- // src/hooks/magic-context/channel2-delivery.ts
22545
22596
  function subagentRunIsActive(deps, sessionId) {
22546
22597
  try {
22547
22598
  const meta = getOrCreateSessionMeta(deps.db, sessionId);
@@ -22584,19 +22635,18 @@ async function maybeDeliverChannel2(sessionId, deps) {
22584
22635
  clearPendingChannel2Intent(deps.db, sessionId);
22585
22636
  return false;
22586
22637
  }
22587
- if (deps.directiveText === undefined && (deps.reclaimableTokens === undefined || deps.usableTokens === undefined)) {
22638
+ const evaluation = evaluateChannel2(deps.baseline);
22639
+ if (deps.directiveText === undefined && !evaluation.evaluable) {
22588
22640
  return false;
22589
22641
  }
22590
- if (deps.directiveText === undefined && !shouldTriggerChannel2({
22591
- reclaimableTokens: deps.reclaimableTokens,
22592
- usableTokens: deps.usableTokens
22593
- })) {
22642
+ if (deps.directiveText === undefined && !evaluation.shouldTrigger) {
22594
22643
  try {
22595
22644
  casChannel2NudgeState(deps.db, sessionId, "pending", "");
22596
- sessionLog(sessionId, `channel2 intent cleared pre-delivery (reclaimable ${deps.reclaimableTokens}, usable ${deps.usableTokens} — trigger no longer holds; re-armable)`);
22645
+ sessionLog(sessionId, `channel2 intent cleared pre-delivery (U ${evaluation.reclaimableTokens}, T ${evaluation.tailTokens} — trigger no longer holds; re-armable)`);
22597
22646
  } catch {}
22598
22647
  return false;
22599
22648
  }
22649
+ const effectiveU = evaluation.reclaimableTokens;
22600
22650
  const client = deps.client;
22601
22651
  if (!client)
22602
22652
  return false;
@@ -22610,7 +22660,7 @@ async function maybeDeliverChannel2(sessionId, deps) {
22610
22660
  }
22611
22661
  try {
22612
22662
  const promptContext = await resolvePromptContext(client, sessionId);
22613
- const reminder = deps.directiveText ?? buildChannel2Reminder(deps.reclaimableTokens, deps.oldestReclaimableToolTags);
22663
+ const reminder = deps.directiveText ?? buildChannel2Reminder(effectiveU, deps.oldestReclaimableToolTags);
22614
22664
  const body = {
22615
22665
  noReply: false,
22616
22666
  parts: [{ type: "text", text: reminder, synthetic: true }]
@@ -23296,156 +23346,6 @@ class EmergencyFailClosedError extends Error {
23296
23346
  }
23297
23347
  }
23298
23348
 
23299
- // src/hooks/magic-context/image-token-estimate.ts
23300
- var IMAGE_TOKEN_DIVISOR = 750;
23301
- var IMAGE_FALLBACK_TOKENS = 1200;
23302
- var IMAGE_TOKEN_CAP = 4500;
23303
- function estimateImageTokensFromDataUrl(url) {
23304
- const comma = url.indexOf(",");
23305
- if (comma < 0)
23306
- return IMAGE_FALLBACK_TOKENS;
23307
- const header = url.slice(0, comma);
23308
- const payload = url.slice(comma + 1);
23309
- const sliceLen = Math.min(512, payload.length);
23310
- const preview = payload.slice(0, sliceLen);
23311
- let bytes;
23312
- try {
23313
- bytes = base64Decode(preview);
23314
- } catch {
23315
- return IMAGE_FALLBACK_TOKENS;
23316
- }
23317
- if (header.includes("image/png")) {
23318
- const dims = parsePngDimensions(bytes);
23319
- if (dims)
23320
- return clampImageTokens(Math.ceil(dims.w * dims.h / IMAGE_TOKEN_DIVISOR));
23321
- } else if (header.includes("image/jpeg") || header.includes("image/jpg")) {
23322
- const dims = parseJpegDimensions(bytes);
23323
- if (dims)
23324
- return clampImageTokens(Math.ceil(dims.w * dims.h / IMAGE_TOKEN_DIVISOR));
23325
- } else if (header.includes("image/webp")) {
23326
- const dims = parseWebpDimensions(bytes);
23327
- if (dims)
23328
- return clampImageTokens(Math.ceil(dims.w * dims.h / IMAGE_TOKEN_DIVISOR));
23329
- } else if (header.includes("image/gif")) {
23330
- const dims = parseGifDimensions(bytes);
23331
- if (dims)
23332
- return clampImageTokens(Math.ceil(dims.w * dims.h / IMAGE_TOKEN_DIVISOR));
23333
- }
23334
- return IMAGE_FALLBACK_TOKENS;
23335
- }
23336
- function clampImageTokens(n) {
23337
- if (n < 1)
23338
- return 1;
23339
- if (n > IMAGE_TOKEN_CAP)
23340
- return IMAGE_TOKEN_CAP;
23341
- return n;
23342
- }
23343
- function base64Decode(b64) {
23344
- const pad = b64.length % 4;
23345
- const padded = pad === 0 ? b64 : b64 + "=".repeat(4 - pad);
23346
- const binary = atob(padded);
23347
- const out = new Uint8Array(binary.length);
23348
- for (let i = 0;i < binary.length; i++)
23349
- out[i] = binary.charCodeAt(i);
23350
- return out;
23351
- }
23352
- function parsePngDimensions(b) {
23353
- if (b.length < 24)
23354
- return null;
23355
- if (b[0] !== 137 || b[1] !== 80 || b[2] !== 78 || b[3] !== 71 || b[4] !== 13 || b[5] !== 10 || b[6] !== 26 || b[7] !== 10)
23356
- return null;
23357
- const w = readUint32BE(b, 16);
23358
- const h = readUint32BE(b, 20);
23359
- if (!w || !h)
23360
- return null;
23361
- return { w, h };
23362
- }
23363
- function parseJpegDimensions(b) {
23364
- if (b.length < 4 || b[0] !== 255 || b[1] !== 216)
23365
- return null;
23366
- let i = 2;
23367
- while (i < b.length - 8) {
23368
- if (b[i] !== 255) {
23369
- i++;
23370
- continue;
23371
- }
23372
- const marker = b[i + 1];
23373
- if (marker === undefined)
23374
- break;
23375
- if (isSofMarker(marker)) {
23376
- const h = b[i + 5] << 8 | b[i + 6];
23377
- const w = b[i + 7] << 8 | b[i + 8];
23378
- if (w && h)
23379
- return { w, h };
23380
- return null;
23381
- }
23382
- if (marker === 216 || marker === 217 || marker === 1) {
23383
- i += 2;
23384
- continue;
23385
- }
23386
- const segLen = b[i + 2] << 8 | b[i + 3];
23387
- if (segLen < 2)
23388
- return null;
23389
- i += 2 + segLen;
23390
- }
23391
- return null;
23392
- }
23393
- function isSofMarker(m) {
23394
- if (m >= 192 && m <= 195)
23395
- return true;
23396
- if (m >= 197 && m <= 199)
23397
- return true;
23398
- if (m >= 201 && m <= 203)
23399
- return true;
23400
- if (m >= 205 && m <= 207)
23401
- return true;
23402
- return false;
23403
- }
23404
- function parseWebpDimensions(b) {
23405
- if (b.length < 30)
23406
- return null;
23407
- if (b[0] !== 82 || b[1] !== 73 || b[2] !== 70 || b[3] !== 70)
23408
- return null;
23409
- if (b[8] !== 87 || b[9] !== 69 || b[10] !== 66 || b[11] !== 80)
23410
- return null;
23411
- const variant = String.fromCharCode(b[12], b[13], b[14], b[15]);
23412
- if (variant === "VP8 ") {
23413
- const w = (b[26] | b[27] << 8) & 16383;
23414
- const h = (b[28] | b[29] << 8) & 16383;
23415
- if (w && h)
23416
- return { w, h };
23417
- } else if (variant === "VP8L") {
23418
- const b0 = b[21];
23419
- const b1 = b[22];
23420
- const b2 = b[23];
23421
- const b3 = b[24];
23422
- const w = 1 + ((b0 | b1 << 8) & 16383);
23423
- const h = 1 + ((b1 >> 6 | b2 << 2 | b3 << 10) & 16383);
23424
- if (w && h)
23425
- return { w, h };
23426
- } else if (variant === "VP8X") {
23427
- const w = 1 + (b[24] | b[25] << 8 | b[26] << 16);
23428
- const h = 1 + (b[27] | b[28] << 8 | b[29] << 16);
23429
- if (w && h)
23430
- return { w, h };
23431
- }
23432
- return null;
23433
- }
23434
- function parseGifDimensions(b) {
23435
- if (b.length < 10)
23436
- return null;
23437
- if (b[0] !== 71 || b[1] !== 73 || b[2] !== 70)
23438
- return null;
23439
- const w = b[6] | b[7] << 8;
23440
- const h = b[8] | b[9] << 8;
23441
- if (!w || !h)
23442
- return null;
23443
- return { w, h };
23444
- }
23445
- function readUint32BE(b, offset) {
23446
- return (b[offset] << 24 | b[offset + 1] << 16 | b[offset + 2] << 8 | b[offset + 3]) >>> 0;
23447
- }
23448
-
23449
23349
  // src/hooks/magic-context/tokenizer-calibration.ts
23450
23350
  var CALIBRATION_TABLE = [
23451
23351
  { prefix: "anthropic/claude-opus-4-8", systemRatio: 1.51, toolsRatio: 1.57 },
@@ -24294,7 +24194,7 @@ function createPassOutcome() {
24294
24194
  }
24295
24195
 
24296
24196
  // src/hooks/magic-context/rust-mode-transform.ts
24297
- import { createHash as createHash13 } from "node:crypto";
24197
+ import { createHash as createHash12 } from "node:crypto";
24298
24198
 
24299
24199
  // src/hooks/magic-context/module-state-sync.ts
24300
24200
  import { createHmac, randomUUID as randomUUID5 } from "node:crypto";
@@ -25764,121 +25664,6 @@ class RawFallbackContextLimitError extends Error {
25764
25664
  }
25765
25665
  }
25766
25666
 
25767
- // src/hooks/magic-context/todo-view.ts
25768
- import { createHash as createHash11 } from "node:crypto";
25769
- var TODO_STATUS_PENDING = "pending";
25770
- var TODO_STATUS_IN_PROGRESS = "in_progress";
25771
- var TODO_STATUS_COMPLETED = "completed";
25772
- var TODO_STATUS_CANCELLED = "cancelled";
25773
- var TODO_PRIORITY_HIGH = "high";
25774
- var TODO_PRIORITY_MEDIUM = "medium";
25775
- var TODO_PRIORITY_LOW = "low";
25776
- var TODO_STATUSES = [
25777
- TODO_STATUS_PENDING,
25778
- TODO_STATUS_IN_PROGRESS,
25779
- TODO_STATUS_COMPLETED,
25780
- TODO_STATUS_CANCELLED
25781
- ];
25782
- var TODO_PRIORITIES = [
25783
- TODO_PRIORITY_HIGH,
25784
- TODO_PRIORITY_MEDIUM,
25785
- TODO_PRIORITY_LOW
25786
- ];
25787
- var TODO_STATUS_SET = new Set(TODO_STATUSES);
25788
- var TODO_PRIORITY_SET = new Set(TODO_PRIORITIES);
25789
- var TERMINAL_STATUSES = new Set([
25790
- TODO_STATUS_COMPLETED,
25791
- TODO_STATUS_CANCELLED
25792
- ]);
25793
- var TITLE_DONE_STATUSES = new Set([TODO_STATUS_COMPLETED]);
25794
- var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
25795
- function normalizeTodoStateJson(todos) {
25796
- if (!Array.isArray(todos))
25797
- return null;
25798
- const normalized = [];
25799
- for (const todo of todos) {
25800
- if (!isTodoItem(todo))
25801
- return null;
25802
- normalized.push({
25803
- content: todo.content,
25804
- status: todo.status,
25805
- priority: todo.priority ?? TODO_PRIORITY_MEDIUM
25806
- });
25807
- }
25808
- return JSON.stringify(normalized);
25809
- }
25810
- function buildSyntheticTodoPart(stateJson) {
25811
- const todos = parseTodoState(stateJson);
25812
- if (todos === null || todos.length === 0)
25813
- return null;
25814
- if (todos.every((t) => TERMINAL_STATUSES.has(t.status)))
25815
- return null;
25816
- const callID = computeSyntheticCallId(stateJson);
25817
- const activeCount = todos.filter((t) => !TITLE_DONE_STATUSES.has(t.status)).length;
25818
- const output = JSON.stringify(todos, null, 2);
25819
- const ts = 0;
25820
- return {
25821
- type: "tool",
25822
- callID,
25823
- tool: "todowrite",
25824
- state: {
25825
- status: "completed",
25826
- input: { todos },
25827
- output,
25828
- title: `${activeCount} todos`,
25829
- metadata: { todos, truncated: false },
25830
- time: { start: ts, end: ts }
25831
- },
25832
- syntheticTodoMarker: true
25833
- };
25834
- }
25835
- function computeSyntheticCallId(stateJson) {
25836
- const hash = createHash11("sha256").update(stateJson).digest("hex").slice(0, 16);
25837
- return `${SYNTHETIC_CALL_ID_PREFIX}${hash}`;
25838
- }
25839
- function isSyntheticTodoPart(part) {
25840
- if (part === null || typeof part !== "object")
25841
- return false;
25842
- const p = part;
25843
- if (p.syntheticTodoMarker === true)
25844
- return true;
25845
- return p.type === "tool" && p.tool === "todowrite" && typeof p.callID === "string" && p.callID.startsWith(SYNTHETIC_CALL_ID_PREFIX);
25846
- }
25847
- function parseTodoState(stateJson) {
25848
- if (stateJson.length === 0)
25849
- return null;
25850
- try {
25851
- const parsed = JSON.parse(stateJson);
25852
- if (!Array.isArray(parsed))
25853
- return null;
25854
- const result = [];
25855
- for (const item of parsed) {
25856
- if (!isTodoItem(item))
25857
- return null;
25858
- result.push({
25859
- content: item.content,
25860
- status: item.status,
25861
- priority: item.priority ?? TODO_PRIORITY_MEDIUM
25862
- });
25863
- }
25864
- return result;
25865
- } catch {
25866
- return null;
25867
- }
25868
- }
25869
- function isTodoStatus(value) {
25870
- return typeof value === "string" && TODO_STATUS_SET.has(value);
25871
- }
25872
- function isTodoPriority(value) {
25873
- return typeof value === "string" && TODO_PRIORITY_SET.has(value);
25874
- }
25875
- function isTodoItem(value) {
25876
- if (value === null || typeof value !== "object")
25877
- return false;
25878
- const todo = value;
25879
- return typeof todo.content === "string" && isTodoStatus(todo.status) && (todo.priority === undefined || isTodoPriority(todo.priority));
25880
- }
25881
-
25882
25667
  // src/hooks/magic-context/transform-context-state.ts
25883
25668
  function loadPersistedUsageWatermark(db, sessionId) {
25884
25669
  const result = db.prepare("SELECT last_response_time FROM session_meta WHERE session_id = ?").get(sessionId);
@@ -25982,7 +25767,7 @@ function containsProbeVerbatim(text, probes) {
25982
25767
  }
25983
25768
 
25984
25769
  // src/features/magic-context/search-measurement.ts
25985
- import { createHash as createHash12 } from "node:crypto";
25770
+ import { createHash as createHash11 } from "node:crypto";
25986
25771
  function resultId(result) {
25987
25772
  switch (result.source) {
25988
25773
  case "memory":
@@ -26069,7 +25854,7 @@ async function recordShadowMeasurement(args) {
26069
25854
  }
26070
25855
  }
26071
25856
  function sha256(value) {
26072
- return createHash12("sha256").update(value).digest("hex");
25857
+ return createHash11("sha256").update(value).digest("hex");
26073
25858
  }
26074
25859
 
26075
25860
  // src/features/magic-context/search.ts
@@ -27458,6 +27243,21 @@ ${hintText}`;
27458
27243
  }
27459
27244
  function clearAutoSearchForSession(_sessionId) {}
27460
27245
 
27246
+ // src/hooks/magic-context/channel2-cycle.ts
27247
+ function rearmChannel2AfterCoverageAdvancingHardFold(input) {
27248
+ if (input.compactionOff || !input.foldExecuted || input.previousCoverage === null || input.currentCoverage === null || input.currentCoverage <= input.previousCoverage) {
27249
+ return false;
27250
+ }
27251
+ return casChannel2NudgeState(input.db, input.sessionId, "delivered", "");
27252
+ }
27253
+ function rearmChannel2AfterMeasuredCollapse(input) {
27254
+ if (!input.baseline.evaluable || input.baseline.generationInvalidated)
27255
+ return false;
27256
+ if (effectiveTailHygiene(input.baseline).u >= CHANNEL1_FLOOR_TOKENS)
27257
+ return false;
27258
+ return casChannel2NudgeState(input.db, input.sessionId, "delivered", "");
27259
+ }
27260
+
27461
27261
  // src/hooks/magic-context/drop-stale-reduce-calls.ts
27462
27262
  var STALE_TOOL_NAMES = new Set(["ctx_reduce"]);
27463
27263
  function isReduceToolPart(part) {
@@ -27535,126 +27335,9 @@ function dropStaleReduceCalls(messages, frozenIds, options = {}) {
27535
27335
  return { didDrop, newlyStrippedIds };
27536
27336
  }
27537
27337
 
27538
- // src/hooks/magic-context/emergency-drop.ts
27539
- var TARGET_FRACTION = 0.3;
27540
- var TIER_RECENCY_RESERVE = 0.2;
27541
- var EMERGENCY_REARM_MIN_TOKENS = 2000;
27542
- var T1_TOOLS = new Set(["read", "todowrite", "task", "aft_outline", "aft_zoom"]);
27543
- var T2_TOOLS = new Set(["edit", "write", "apply_patch", "grep", "glob", "aft_search"]);
27544
- function normalizeToolName(toolName) {
27545
- if (!toolName)
27546
- return "";
27547
- let name = toolName.toLowerCase();
27548
- if (name.startsWith("mcp_"))
27549
- name = name.slice(4);
27550
- return name;
27551
- }
27552
- function resolveToolTier(toolName) {
27553
- const name = normalizeToolName(toolName);
27554
- if (T1_TOOLS.has(name))
27555
- return 1;
27556
- if (T2_TOOLS.has(name))
27557
- return 2;
27558
- return 3;
27559
- }
27560
- function tagReclaimBytes(tag) {
27561
- return tag.byteSize + tag.inputByteSize + tag.reasoningByteSize;
27562
- }
27563
- function estimateEmergencyDropReclaimTokens(tag) {
27564
- return Math.round(tagReclaimBytes(tag) * TOKENS_PER_BYTE);
27565
- }
27566
- function planEmergencyDrop(input) {
27567
- const {
27568
- tags,
27569
- floorTags,
27570
- maxTag,
27571
- protectedTags,
27572
- currentTotalInputTokens,
27573
- ceilingTokens,
27574
- priorInputSample,
27575
- hasPriorDrop
27576
- } = input;
27577
- const noop = (reason) => ({
27578
- shouldDrop: false,
27579
- tagNumbers: [],
27580
- reclaimTokens: 0,
27581
- reason
27582
- });
27583
- if (!Number.isFinite(ceilingTokens) || ceilingTokens <= 0) {
27584
- return noop("unknown-ceiling");
27585
- }
27586
- if (!Number.isFinite(currentTotalInputTokens) || currentTotalInputTokens <= 0) {
27587
- return noop("unknown-usage");
27588
- }
27589
- if (hasPriorDrop && currentTotalInputTokens === priorInputSample) {
27590
- return noop("same-input-sample (awaiting fresh usage after prior drop)");
27591
- }
27592
- let tailTokens = 0;
27593
- for (const tag of floorTags) {
27594
- if (tag.status !== "active")
27595
- continue;
27596
- tailTokens += estimateEmergencyDropReclaimTokens(tag);
27597
- }
27598
- const fixedFloor = Math.max(currentTotalInputTokens - tailTokens, 0);
27599
- const workingSpan = Math.max(ceilingTokens - fixedFloor, 0);
27600
- const target = fixedFloor + TARGET_FRACTION * workingSpan;
27601
- const reclaimTokens = Math.round(currentTotalInputTokens - target);
27602
- if (reclaimTokens <= EMERGENCY_REARM_MIN_TOKENS) {
27603
- return noop(`reclaim<=min (${reclaimTokens} <= ${EMERGENCY_REARM_MIN_TOKENS})`);
27604
- }
27605
- const protectedCutoff = maxTag - protectedTags;
27606
- const tierActive = { 1: [], 2: [] };
27607
- for (const tag of tags) {
27608
- if (tag.status !== "active" || tag.type !== "tool")
27609
- continue;
27610
- const tier = resolveToolTier(tag.toolName);
27611
- if (tier === 1 || tier === 2)
27612
- tierActive[tier].push(tag.tagNumber);
27613
- }
27614
- const reserved = new Set;
27615
- for (const tier of [1, 2]) {
27616
- const nums = tierActive[tier];
27617
- if (nums.length === 0)
27618
- continue;
27619
- nums.sort((a, b) => b - a);
27620
- const reserveCount = Math.ceil(TIER_RECENCY_RESERVE * nums.length);
27621
- for (let i = 0;i < reserveCount && i < nums.length; i++) {
27622
- reserved.add(nums[i]);
27623
- }
27624
- }
27625
- const byTier = { 1: [], 2: [], 3: [] };
27626
- for (const tag of tags) {
27627
- if (tag.status !== "active" || tag.type !== "tool")
27628
- continue;
27629
- if (tag.tagNumber > protectedCutoff)
27630
- continue;
27631
- const tier = resolveToolTier(tag.toolName);
27632
- if ((tier === 1 || tier === 2) && reserved.has(tag.tagNumber))
27633
- continue;
27634
- byTier[tier].push(tag);
27635
- }
27636
- const selected = [];
27637
- let reclaimed = 0;
27638
- outer:
27639
- for (const tier of [3, 2, 1]) {
27640
- const group = byTier[tier];
27641
- group.sort((a, b) => a.tagNumber - b.tagNumber);
27642
- for (const tag of group) {
27643
- selected.push(tag.tagNumber);
27644
- reclaimed += estimateEmergencyDropReclaimTokens(tag);
27645
- if (reclaimed >= reclaimTokens)
27646
- break outer;
27647
- }
27648
- }
27649
- if (selected.length === 0) {
27650
- return noop("no-candidates");
27651
- }
27652
- return {
27653
- shouldDrop: true,
27654
- tagNumbers: selected,
27655
- reclaimTokens,
27656
- reason: `tiered drop: ${selected.length} tags, reclaim≈${reclaimed}/${reclaimTokens} tokens (floor≈${fixedFloor}, ceiling=${Math.round(ceilingTokens)})`
27657
- };
27338
+ // src/hooks/magic-context/fold-execution-gate.ts
27339
+ function foldExecutesThisPass(foldDue, materialized) {
27340
+ return foldDue && materialized;
27658
27341
  }
27659
27342
 
27660
27343
  // src/hooks/magic-context/system-injection-stripper.ts
@@ -28305,6 +27988,7 @@ function planMergedAssistantReasoningStrip(messages, mutationExemptMessage) {
28305
27988
  }
28306
27989
  return plan;
28307
27990
  }
27991
+ var MAX_FROZEN_TRAILING_BLANKS = 1e4;
28308
27992
  var CANONICAL_BLANK_PART = { type: "text", text: "" };
28309
27993
  function isSentinelInvisibleTextPart(part) {
28310
27994
  return isRecord(part) && part.type === "text" && typeof part.text === "string" && part.text.trim() === "";
@@ -28312,18 +27996,37 @@ function isSentinelInvisibleTextPart(part) {
28312
27996
  function isCanonicalBlankPart(part) {
28313
27997
  return isRecord(part) && Object.keys(part).length === 2 && part.type === "text" && part.text === "";
28314
27998
  }
28315
- function findTrailingBlankDecisionCandidates(messages, frozenDecisions) {
27999
+ function trailingBlankKeepCount(decision) {
28000
+ if (decision === "keep")
28001
+ return 1;
28002
+ if (!decision.startsWith("keep:"))
28003
+ return;
28004
+ const countText = decision.slice("keep:".length);
28005
+ if (!/^[1-9]\d*$/.test(countText))
28006
+ return;
28007
+ const count = Number(countText);
28008
+ return Number.isSafeInteger(count) && count > 0 && count <= MAX_FROZEN_TRAILING_BLANKS ? count : undefined;
28009
+ }
28010
+ function findTrailingBlankDecisionCandidates(messages, frozenDecisions, options) {
28316
28011
  const decisions = [];
28317
28012
  for (const message of messages) {
28318
28013
  const id = message.info.id;
28319
- if (message.info.role !== "assistant" || typeof id !== "string" || id.length === 0 || frozenDecisions.has(id)) {
28014
+ if (message.info.role !== "assistant" || typeof id !== "string" || id.length === 0) {
28320
28015
  continue;
28321
28016
  }
28322
- const last = message.parts.at(-1);
28323
- decisions.push([
28324
- id,
28325
- message.parts.length === 0 || isSentinelInvisibleTextPart(last) ? "keep" : "strip"
28326
- ]);
28017
+ let trailingCount = 0;
28018
+ while (trailingCount < message.parts.length && isSentinelInvisibleTextPart(message.parts[message.parts.length - trailingCount - 1])) {
28019
+ trailingCount += 1;
28020
+ }
28021
+ if (trailingCount > MAX_FROZEN_TRAILING_BLANKS && trailingCount < message.parts.length) {
28022
+ continue;
28023
+ }
28024
+ const decision = message.parts.length === 0 || trailingCount === message.parts.length ? "keep" : trailingCount === 0 ? "strip" : trailingCount === 1 ? "keep" : `keep:${trailingCount}`;
28025
+ const frozen = frozenDecisions.get(id);
28026
+ if (frozen !== undefined && (id !== options?.refreshMessageId || frozen === decision)) {
28027
+ continue;
28028
+ }
28029
+ decisions.push([id, decision]);
28327
28030
  }
28328
28031
  return decisions;
28329
28032
  }
@@ -28341,24 +28044,26 @@ function applyFrozenTrailingBlankDecisions(messages, newestAssistantId, frozenDe
28341
28044
  while (lastMeaningfulIndex >= 0 && isSentinelInvisibleTextPart(message.parts[lastMeaningfulIndex])) {
28342
28045
  lastMeaningfulIndex -= 1;
28343
28046
  }
28344
- const replaceParts = (start, deleteCount, insertBlank) => {
28047
+ const replaceParts = (start, deleteCount, insertBlankCount) => {
28345
28048
  message = { ...message, parts: [...message.parts] };
28346
28049
  messages[messageIndex] = message;
28347
- message.parts.splice(start, deleteCount, ...insertBlank ? [{ ...CANONICAL_BLANK_PART }] : []);
28050
+ message.parts.splice(start, deleteCount, ...Array.from({ length: insertBlankCount }, () => ({ ...CANONICAL_BLANK_PART })));
28348
28051
  };
28349
28052
  if (lastMeaningfulIndex < 0) {
28350
28053
  if (message.parts.length !== 1 || !isCanonicalBlankPart(message.parts[0])) {
28351
28054
  mutations += Math.max(1, message.parts.length);
28352
- replaceParts(0, message.parts.length, true);
28055
+ replaceParts(0, message.parts.length, 1);
28353
28056
  }
28354
28057
  continue;
28355
28058
  }
28356
28059
  const trailingCount = message.parts.length - lastMeaningfulIndex - 1;
28357
- if (decision === "keep") {
28060
+ const keepCount = trailingBlankKeepCount(decision);
28061
+ if (keepCount !== undefined) {
28358
28062
  const blankIndex = lastMeaningfulIndex + 1;
28359
- if (trailingCount !== 1 || !isCanonicalBlankPart(message.parts[blankIndex])) {
28360
- mutations += Math.max(1, trailingCount);
28361
- replaceParts(blankIndex, trailingCount, true);
28063
+ const suffixIsCanonical = trailingCount === keepCount && message.parts.slice(blankIndex).every(isCanonicalBlankPart);
28064
+ if (!suffixIsCanonical) {
28065
+ mutations += Math.max(1, trailingCount, keepCount);
28066
+ replaceParts(blankIndex, trailingCount, keepCount);
28362
28067
  }
28363
28068
  continue;
28364
28069
  }
@@ -28369,12 +28074,12 @@ function applyFrozenTrailingBlankDecisions(messages, newestAssistantId, frozenDe
28369
28074
  const blankIndex = lastMeaningfulIndex + 1;
28370
28075
  if (trailingCount !== 1 || !isCanonicalBlankPart(message.parts[blankIndex])) {
28371
28076
  mutations += Math.max(1, trailingCount);
28372
- replaceParts(blankIndex, trailingCount, true);
28077
+ replaceParts(blankIndex, trailingCount, 1);
28373
28078
  }
28374
28079
  continue;
28375
28080
  }
28376
28081
  mutations += trailingCount;
28377
- replaceParts(lastMeaningfulIndex + 1, trailingCount, false);
28082
+ replaceParts(lastMeaningfulIndex + 1, trailingCount, 0);
28378
28083
  }
28379
28084
  return mutations;
28380
28085
  }
@@ -28451,7 +28156,6 @@ function stripProcessedImages(messages, frozenIds, options) {
28451
28156
 
28452
28157
  // src/hooks/magic-context/supersession-reclaim.ts
28453
28158
  var TODOWRITE_KEEP = 1;
28454
- var CTX_REDUCE_KEEP = 5;
28455
28159
  var ZERO_VALUE_META_TOOLS = new Set(["bash_status", "bash_kill"]);
28456
28160
  var CTX_NOTE_ZERO_VALUE_ACTIONS = new Set(["read", "dismiss"]);
28457
28161
  function buildSupersessionReclaimOps(input) {
@@ -29509,7 +29213,7 @@ async function runPostTransformPhase(args) {
29509
29213
  const deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
29510
29214
  const materializationRequested = isExplicitFlush || deferredMaterialize;
29511
29215
  const m0M1EnabledForFold = args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory) && (args.fullFeatureMode || compactionOff);
29512
- const m0HardFoldThisPass = m0M1EnabledForFold && args.m0M1 ? mustMaterialize({
29216
+ const foldDueDecision = m0M1EnabledForFold && args.m0M1 ? mustMaterialize({
29513
29217
  db: args.db,
29514
29218
  sessionId: args.sessionId,
29515
29219
  state: args.sessionMeta,
@@ -29520,13 +29224,55 @@ async function runPostTransformPhase(args) {
29520
29224
  memoryInjectionBudgetTokens: args.m0M1.memoryInjectionBudgetTokens,
29521
29225
  historyBudgetTokens: args.m0M1.historyBudgetTokens,
29522
29226
  hardSignals: args.m0M1.hardSignals
29523
- }).value : false;
29524
- const bypassCompartmentGate = forceMaterialization || m0HardFoldThisPass;
29525
- const shouldReadPendingOps = !compactionOff && (materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || m0HardFoldThisPass || compartmentRunning);
29227
+ }) : { value: false, reason: null };
29228
+ let foldExecutedThisPass = false;
29229
+ let m0RematerializedThisPass = false;
29230
+ const m0CoverageBeforeFold = args.sessionMeta.cachedM0Bytes === null ? -1 : args.sessionMeta.cachedM0MaxCompartmentSeq;
29231
+ let m0MaterializeReason = null;
29232
+ if (foldDueDecision.value && args.m0M1) {
29233
+ try {
29234
+ const foldResult = injectM0M1({
29235
+ db: args.db,
29236
+ sessionId: args.sessionId,
29237
+ state: args.sessionMeta,
29238
+ projectPath: args.m0M1.projectPath,
29239
+ projectDirectory: args.m0M1.projectDirectory,
29240
+ injectDocs: args.m0M1.injectDocs,
29241
+ memoryInjectionBudgetTokens: args.m0M1.memoryInjectionBudgetTokens,
29242
+ historyBudgetTokens: args.m0M1.historyBudgetTokens,
29243
+ temporalAwareness: args.m0M1.temporalAwareness,
29244
+ isCacheBustingPass: true,
29245
+ hardSignals: args.m0M1.hardSignals,
29246
+ muralEnabled: args.m0M1.muralEnabled,
29247
+ compactionOff
29248
+ });
29249
+ foldExecutedThisPass = foldExecutesThisPass(foldDueDecision.value, foldResult.m0RematerializedThisPass);
29250
+ m0RematerializedThisPass = foldResult.m0RematerializedThisPass;
29251
+ m0MaterializeReason = foldResult.decision.reason;
29252
+ try {
29253
+ rearmChannel2AfterCoverageAdvancingHardFold({
29254
+ db: args.db,
29255
+ sessionId: args.sessionId,
29256
+ foldExecuted: foldExecutedThisPass,
29257
+ compactionOff,
29258
+ previousCoverage: m0CoverageBeforeFold,
29259
+ currentCoverage: args.sessionMeta.cachedM0MaxCompartmentSeq
29260
+ });
29261
+ } catch (error) {
29262
+ sessionLog(args.sessionId, "channel2 fold-cycle reset failed (ignored):", error);
29263
+ }
29264
+ } catch (error) {
29265
+ args.passOutcome?.record("m0-m1-fold-preexecution-degradation");
29266
+ sessionLog(args.sessionId, "transform: m[0] HARD fold pre-execution failed:", getErrorMessage(error));
29267
+ }
29268
+ sessionLog(args.sessionId, `m[0] HARD fold decision: reason=${foldDueDecision.reason ?? "unknown"} executed=${foldExecutedThisPass}`);
29269
+ }
29270
+ const bypassCompartmentGate = forceMaterialization || foldExecutedThisPass;
29271
+ const shouldReadPendingOps = !compactionOff && (materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || foldExecutedThisPass || compartmentRunning);
29526
29272
  const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
29527
29273
  const hasPendingUserOps = pendingOps.length > 0;
29528
- const shouldApplyPendingOps = !compactionOff && (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || m0HardFoldThisPass) && (!compartmentRunning || bypassCompartmentGate);
29529
- const shouldRunHeuristics = !compactionOff && (!compartmentRunning || bypassCompartmentGate) && (materializationRequested || forceMaterialization || m0HardFoldThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
29274
+ const shouldApplyPendingOps = !compactionOff && (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || foldExecutedThisPass) && (!compartmentRunning || bypassCompartmentGate);
29275
+ const shouldRunHeuristics = !compactionOff && (!compartmentRunning || bypassCompartmentGate) && (materializationRequested || forceMaterialization || foldExecutedThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
29530
29276
  const isCacheBustingPass = shouldApplyPendingOps || shouldRunHeuristics;
29531
29277
  if (isCacheBustingPass && args.client && args.ctxReduceAvailability.callable && !hasLoggedCtxReducePermissionDeny(args.sessionId)) {
29532
29278
  try {
@@ -29542,7 +29288,7 @@ async function runPostTransformPhase(args) {
29542
29288
  const canUseEmptySentinels = modelAcceptsEmptyContent(args.resolvedProviderID);
29543
29289
  if (shouldRunHeuristics) {
29544
29290
  const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
29545
- const reason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : forceMaterialization ? `force_materialization (${args.contextUsage.percentage.toFixed(1)}% >= ${args.forceMaterializationPercentage}%)` : m0HardFoldThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into known m[0] bust, scheduler=${args.schedulerDecision})` : subagentRerun ? `scheduler_execute_subagent_rerun (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})` : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
29291
+ const reason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : forceMaterialization ? `force_materialization (${args.contextUsage.percentage.toFixed(1)}% >= ${args.forceMaterializationPercentage}%)` : foldExecutedThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into executed m[0] bust, scheduler=${args.schedulerDecision})` : subagentRerun ? `scheduler_execute_subagent_rerun (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})` : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
29546
29292
  sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=${args.currentTurnId}`);
29547
29293
  }
29548
29294
  if (alreadyRanThisTurn && args.schedulerDecision === "execute" && !materializationRequested && args.fullFeatureMode) {
@@ -29566,8 +29312,6 @@ async function runPostTransformPhase(args) {
29566
29312
  const droppedTokens = 0;
29567
29313
  let emergencyReclaimedTokens = 0;
29568
29314
  let emergency = false;
29569
- let m0RematerializedThisPass = false;
29570
- let m0MaterializeReason = null;
29571
29315
  let m0M1InjectedThisPass = false;
29572
29316
  let prependedMessageCount = 0;
29573
29317
  const reasoningMutatedMessages = new Set;
@@ -29583,7 +29327,7 @@ async function runPostTransformPhase(args) {
29583
29327
  let autoReclaimDidMutateThisPass = false;
29584
29328
  try {
29585
29329
  if (shouldApplyPendingOps) {
29586
- const applyReason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
29330
+ const applyReason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : foldExecutedThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into executed m[0] bust, scheduler=${args.schedulerDecision})` : `scheduler_execute (scheduler=${args.schedulerDecision})`;
29587
29331
  sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOps.length}, context=${args.contextUsage.percentage.toFixed(1)}%`);
29588
29332
  const tApply = performance.now();
29589
29333
  pendingOpsDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTags, undefined, pendingOps);
@@ -30081,6 +29825,7 @@ async function runPostTransformPhase(args) {
30081
29825
  sessionLog(args.sessionId, "transform failed loading trailing blank decisions:", error);
30082
29826
  }
30083
29827
  }
29828
+ const newestAssistantId = typeof reasoningMutationExemptMessage?.info.id === "string" ? reasoningMutationExemptMessage.info.id : undefined;
30084
29829
  const tFinalRepresentation = performance.now();
30085
29830
  const finalRepresentation = finalizeMessageRepresentation(args.messages, args.resolvedProviderID, {
30086
29831
  prependedMessageCount,
@@ -30091,11 +29836,14 @@ async function runPostTransformPhase(args) {
30091
29836
  skipMergedReasoningStrip: compactionOff,
30092
29837
  skipTrailingWhitespaceStrip: compactionOff
30093
29838
  });
30094
- if (canUseEmptySentinels && !compactionOff && isCacheBustingPass) {
30095
- const candidates = findTrailingBlankDecisionCandidates(args.messages, trailingBlankDecisions);
29839
+ if (canUseEmptySentinels && !compactionOff) {
29840
+ const detectedCandidates = findTrailingBlankDecisionCandidates(args.messages, trailingBlankDecisions, { refreshMessageId: newestAssistantId });
29841
+ const candidates = isCacheBustingPass ? detectedCandidates : detectedCandidates.filter(([id]) => id === newestAssistantId);
30096
29842
  if (candidates.length > 0) {
30097
29843
  try {
30098
- const persisted = addTrailingBlankDecisions(args.db, args.sessionId, candidates);
29844
+ const persisted = addTrailingBlankDecisions(args.db, args.sessionId, candidates, {
29845
+ overwriteMessageId: newestAssistantId
29846
+ });
30099
29847
  if (persisted) {
30100
29848
  const committed = getTrailingBlankDecisions(args.db, args.sessionId);
30101
29849
  const newlyFrozen = new Map;
@@ -30106,8 +29854,9 @@ async function runPostTransformPhase(args) {
30106
29854
  trailingBlankDecisions.set(id, decision);
30107
29855
  newlyFrozen.set(id, decision);
30108
29856
  }
30109
- applyFrozenTrailingBlankDecisions(args.messages, typeof reasoningMutationExemptMessage?.info.id === "string" ? reasoningMutationExemptMessage.info.id : undefined, newlyFrozen);
30110
- bustedThisPass = true;
29857
+ applyFrozenTrailingBlankDecisions(args.messages, newestAssistantId, newlyFrozen);
29858
+ if (isCacheBustingPass)
29859
+ bustedThisPass = true;
30111
29860
  } else {
30112
29861
  args.passOutcome?.record("trailing-blank-decision-persistence-failure");
30113
29862
  sessionLog(args.sessionId, "trailing blank decision: persistence failed; leaving newly observed assistants intact");
@@ -30120,6 +29869,70 @@ async function runPostTransformPhase(args) {
30120
29869
  }
30121
29870
  sessionLog(args.sessionId, `final representation: clearedParts=${finalRepresentation.clearedParts} mergedReasoningParts=${finalRepresentation.mergedReasoningParts}`);
30122
29871
  logTransformTiming(args.sessionId, "finalizeMessageRepresentation", tFinalRepresentation, `clearedParts=${finalRepresentation.clearedParts} mergedReasoningParts=${finalRepresentation.mergedReasoningParts}`);
29872
+ let assertedBaseline;
29873
+ if (args.channel1StateBySession) {
29874
+ if (args.ctxReduceAvailability.callable && !compactionOff) {
29875
+ try {
29876
+ const tags = getTailHygieneTags(args.db, args.sessionId);
29877
+ const previous = args.channel1StateBySession.get(args.sessionId);
29878
+ const baseline = refreshTailHygieneBaseline({
29879
+ messages: args.messages,
29880
+ tags,
29881
+ protectedTags: args.protectedTags,
29882
+ cacheBusting: bustedThisPass,
29883
+ previous
29884
+ });
29885
+ const structuralSignature = tailHygieneStructuralSignature(args.messages);
29886
+ args.channel1StateBySession.set(args.sessionId, {
29887
+ ...baseline,
29888
+ reducedSinceRefresh: baseline.baselineGeneration !== previous?.baselineGeneration ? false : previous?.reducedSinceRefresh ?? false,
29889
+ oldestReclaimableToolTags: getOldestActiveUnprotectedToolTags(args.db, args.sessionId, args.protectedTags)
29890
+ });
29891
+ try {
29892
+ rearmChannel2AfterMeasuredCollapse({
29893
+ db: args.db,
29894
+ sessionId: args.sessionId,
29895
+ baseline
29896
+ });
29897
+ } catch (error) {
29898
+ sessionLog(args.sessionId, "channel2 U-collapse reset failed (ignored):", error);
29899
+ }
29900
+ assertedBaseline = {
29901
+ tags,
29902
+ protectedTags: args.protectedTags,
29903
+ contentSignature: baseline.contentSignature,
29904
+ structuralSignature
29905
+ };
29906
+ } catch (error) {
29907
+ const stale = args.channel1StateBySession.get(args.sessionId);
29908
+ if (stale) {
29909
+ stale.evaluable = false;
29910
+ stale.generationInvalidated = true;
29911
+ }
29912
+ sessionLog(args.sessionId, "tail hygiene baseline refresh failed (held):", error);
29913
+ }
29914
+ } else {
29915
+ args.channel1StateBySession.delete(args.sessionId);
29916
+ }
29917
+ }
29918
+ if (assertedBaseline) {
29919
+ try {
29920
+ const servedSignature = tailHygieneStructuralSignature(args.messages);
29921
+ if (!sameTailHygieneStructuralSignature(assertedBaseline.structuralSignature, servedSignature)) {
29922
+ sessionLog(args.sessionId, `ERROR [tail-hygiene-last-writer-mismatch]: served messages changed after tail-hygiene baseline refresh (expected messages=${assertedBaseline.structuralSignature.messageCount}, parts=[${assertedBaseline.structuralSignature.partCounts.join(",")}], bytes=${assertedBaseline.structuralSignature.totalBytes}; actual messages=${servedSignature.messageCount}, parts=[${servedSignature.partCounts.join(",")}], bytes=${servedSignature.totalBytes})`);
29923
+ }
29924
+ } catch (error) {
29925
+ sessionLog(args.sessionId, "ERROR [tail-hygiene-last-writer-check-failed]: structural production guard failed open:", error);
29926
+ }
29927
+ if (true) {
29928
+ assertTailHygieneContentUnchanged({
29929
+ messages: args.messages,
29930
+ tags: assertedBaseline.tags,
29931
+ protectedTags: assertedBaseline.protectedTags,
29932
+ expectedSignature: assertedBaseline.contentSignature
29933
+ });
29934
+ }
29935
+ }
30123
29936
  return {
30124
29937
  explicitMaterializedSuccessfully,
30125
29938
  deferredMaterializedSuccessfully,
@@ -30341,10 +30154,10 @@ function messageCacheSignature(message) {
30341
30154
  const parts = Array.isArray(message.parts) ? message.parts : [];
30342
30155
  const serializedParts = JSON.stringify(parts) ?? "null";
30343
30156
  const serializedMessage = JSON.stringify(message) ?? "null";
30344
- return `${messageIdOf(message) ?? ""}:${parts.length}:${Buffer.byteLength(serializedParts)}:${createHash13("sha256").update(serializedMessage).digest("hex")}`;
30157
+ return `${messageIdOf(message) ?? ""}:${parts.length}:${Buffer.byteLength(serializedParts)}:${createHash12("sha256").update(serializedMessage).digest("hex")}`;
30345
30158
  }
30346
30159
  function advanceWireFingerprint(previous, encoded) {
30347
- return createHash13("sha256").update(previous).update("\\0").update(JSON.stringify(encoded) ?? "null").digest("hex");
30160
+ return createHash12("sha256").update(previous).update("\\0").update(JSON.stringify(encoded) ?? "null").digest("hex");
30348
30161
  }
30349
30162
  function buildWireFingerprint(encoded) {
30350
30163
  let fingerprint = "rust-wire-v1";
@@ -30603,7 +30416,7 @@ function canonicalizeForChecksum(value) {
30603
30416
  return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalizeForChecksum(value[key])]));
30604
30417
  }
30605
30418
  function checksumSeedRows(rows) {
30606
- return createHash13("sha256").update(JSON.stringify(rows.map(canonicalizeForChecksum))).digest("hex");
30419
+ return createHash12("sha256").update(JSON.stringify(rows.map(canonicalizeForChecksum))).digest("hex");
30607
30420
  }
30608
30421
  function authoritySeedRows(db, projectPath, domain) {
30609
30422
  const snapshots = domain === "memories" ? db.prepare("SELECT * FROM memories WHERE project_path = ? ORDER BY id ASC").all(projectPath) : db.prepare(`SELECT n.*
@@ -30773,7 +30586,14 @@ function mirrorRustSyntheticTodoAnchor(args) {
30773
30586
  clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
30774
30587
  }
30775
30588
  }
30776
- function applyNativeMessagesVerbatim(output, response) {
30589
+ function hasNativeResponseContent(response) {
30590
+ if (typeof response.native_messages === "string" || Array.isArray(response.native_messages)) {
30591
+ return true;
30592
+ }
30593
+ const delta = response.native_messages_delta;
30594
+ return isRecord3(delta) && Array.isArray(delta.messages);
30595
+ }
30596
+ function applyNativeMessagesVerbatim(output, response, previous) {
30777
30597
  const nativeMessages = response.native_messages;
30778
30598
  if (typeof nativeMessages === "string") {
30779
30599
  const parsed = JSON.parse(nativeMessages);
@@ -30781,10 +30601,21 @@ function applyNativeMessagesVerbatim(output, response) {
30781
30601
  throw new Error("rust transform native_messages string was not an array");
30782
30602
  return replaceMessagesInPlace(output, parsed);
30783
30603
  }
30784
- if (!Array.isArray(nativeMessages)) {
30604
+ if (Array.isArray(nativeMessages)) {
30605
+ return replaceMessagesInPlace(output, nativeMessages);
30606
+ }
30607
+ const delta = response.native_messages_delta;
30608
+ if (!isRecord3(delta) || !Array.isArray(delta.messages)) {
30785
30609
  throw new Error("rust transform response omitted native_messages");
30786
30610
  }
30787
- return replaceMessagesInPlace(output, nativeMessages);
30611
+ const replaceFrom = delta.replace_from;
30612
+ if (!previous || delta.after !== previous.fingerprint || typeof replaceFrom !== "number" || !Number.isSafeInteger(replaceFrom) || replaceFrom < 0 || replaceFrom > previous.messages.length) {
30613
+ throw new Error("rust transform native_messages_delta did not match the acknowledged output");
30614
+ }
30615
+ return replaceMessagesInPlace(output, [
30616
+ ...previous.messages.slice(0, replaceFrom),
30617
+ ...delta.messages
30618
+ ]);
30788
30619
  }
30789
30620
  function muralInputForWire(mural) {
30790
30621
  if (!mural?.enabled || !mural.supportsVision || typeof mural.dataUrl !== "string" || mural.dataUrl.length === 0) {
@@ -30988,14 +30819,13 @@ function createRustModeTransform(deps, options) {
30988
30819
  sessionLog(sessionId, "lkg_replay_served");
30989
30820
  return true;
30990
30821
  };
30991
- const prepareRustCapture = (state, sessionId, input, inputSnapshots, response, responseRowVersion) => {
30822
+ const prepareRustCapture = (state, sessionId, input, inputSnapshots, nativeMessages, responseRowVersion) => {
30992
30823
  state.lkgCaptureSequence += 1;
30993
30824
  const inputIds = input.map((message) => message.info.id);
30994
30825
  if (inputIds.some((id) => typeof id !== "string") || new Set(inputIds).size !== inputIds.length || inputIds.length === 0 || inputSnapshots.length !== inputIds.length) {
30995
30826
  return null;
30996
30827
  }
30997
- const native = response.native_messages;
30998
- const jsonPrefix = typeof native === "string" ? native : JSON.stringify(native);
30828
+ const jsonPrefix = JSON.stringify(nativeMessages);
30999
30829
  if (typeof jsonPrefix !== "string")
31000
30830
  return null;
31001
30831
  const keys = resolveLkgModelKeys(input);
@@ -31166,7 +30996,7 @@ function createRustModeTransform(deps, options) {
31166
30996
  const value = timings2[name];
31167
30997
  return typeof value === "number" && Number.isFinite(value) ? value.toFixed(1) : "n/a";
31168
30998
  };
31169
- sessionLog(sessionId, `rust module stages: handler=${stage("handler_total")} apply_once=${stage("total")} ` + `request_to_handler=${stage("request_observed_to_handler")} ` + `projection=${stage("projection")} selection=${stage("selection")} ` + `build_output=${stage("build_output")} store_commit=${stage("store_commit")} ` + `post_attach=${stage("post_attach")} response_encode=${stage("response_encode")} ` + `native_cache_reused=${stage("native_cache_reused_messages")} ` + `native_cache_encoded=${stage("native_cache_encoded_messages")}`);
30999
+ sessionLog(sessionId, `rust module stages: handler=${stage("handler_total")} apply_once=${stage("total")} ` + `request_to_handler=${stage("request_observed_to_handler")} delta_expand=${stage("delta_expand")} ` + `projection_cache_lookup=${stage("projection_cache_lookup")} projection=${stage("projection")} ` + `selection=${stage("selection")} build_output=${stage("build_output")} ` + `store_commit=${stage("store_commit")} trigger=${stage("trigger_ms")} ` + `trigger_boundary=${stage("trigger_boundary_build")} trigger_eval=${stage("trigger_eval")} ` + `projection_cache_store=${stage("projection_cache_store")} native_attach=${stage("native_attach")} ` + `retained_size=${stage("retained_size")} snapshot_store=${stage("snapshot_store")} ` + `post_attach=${stage("post_attach")} response_encode=${stage("response_encode")} ` + `response_meta_encode=${stage("response_meta_encode")} response_splice=${stage("response_splice")} ` + `native_cache_reused=${stage("native_cache_reused_messages")} ` + `native_cache_encoded=${stage("native_cache_encoded_messages")}`);
31170
31000
  }
31171
31001
  if (timings2 && moduleElapsedMs >= 1000) {
31172
31002
  const detail = Object.entries(timings2).filter(([key, value]) => key !== "total" && key !== "handler_total" && typeof value === "number").map(([key, value]) => `${key}:${value.toFixed(1)}`).join(" ");
@@ -31542,8 +31372,14 @@ function createRustModeTransform(deps, options) {
31542
31372
  let response = await sendTransformSeriesWithSingleRestart(body);
31543
31373
  let servedFinalWireEstimate;
31544
31374
  captureResponseTelemetry(response);
31545
- if (isNeedFullSync(response)) {
31546
- options.moduleClient.invalidateStateSyncCapabilities?.();
31375
+ const needFullSync = isNeedFullSync(response);
31376
+ const nativeContentOmitted = !hasNativeResponseContent(response);
31377
+ if (needFullSync || nativeContentOmitted) {
31378
+ if (needFullSync) {
31379
+ options.moduleClient.invalidateStateSyncCapabilities?.();
31380
+ } else {
31381
+ sessionLog(sessionId, "native_delta_fallback_reason=adapter_response_omitted_native_content retry=full");
31382
+ }
31547
31383
  state.forceFullWire = true;
31548
31384
  if (wireDelta) {
31549
31385
  const retryOrdinalStartedAt = performance.now();
@@ -31629,6 +31465,9 @@ function createRustModeTransform(deps, options) {
31629
31465
  if (isNeedFullSync(response)) {
31630
31466
  throw new Error("rust module still requires full sync after a full-array send");
31631
31467
  }
31468
+ if (!hasNativeResponseContent(response)) {
31469
+ throw new Error("rust module omitted native content after a full-array retry");
31470
+ }
31632
31471
  }
31633
31472
  const deliveryPassIds = noteDeliveryPassIds(response);
31634
31473
  const sendNoteDeliveryDisposition = async (method) => {
@@ -31652,7 +31491,11 @@ function createRustModeTransform(deps, options) {
31652
31491
  let appliedMessages;
31653
31492
  const applyStartedAt = performance.now();
31654
31493
  try {
31655
- appliedMessages = applyNativeMessagesVerbatim({ messages: [] }, response);
31494
+ appliedMessages = applyNativeMessagesVerbatim({ messages: [] }, response, previousWireCache?.nativeOutput ? {
31495
+ messages: previousWireCache.nativeOutput,
31496
+ fingerprint: previousWireCache.fingerprint
31497
+ } : undefined);
31498
+ pendingWireCache.nativeOutput = appliedMessages;
31656
31499
  runRustModePostprocess({
31657
31500
  db: deps.db,
31658
31501
  sessionId,
@@ -31689,7 +31532,7 @@ function createRustModeTransform(deps, options) {
31689
31532
  if (cacheBustingPass) {
31690
31533
  dropSlot(sessionId, "lkg_cache_bust_pending_capture");
31691
31534
  }
31692
- const capturePlan = prepareRustCapture(state, sessionId, messages, pendingWireCache.rawContentSnapshots, response, rowVersion);
31535
+ const capturePlan = prepareRustCapture(state, sessionId, messages, pendingWireCache.rawContentSnapshots, appliedMessages, rowVersion);
31693
31536
  let captureMode = "async";
31694
31537
  const captureFailed = (mode, error) => {
31695
31538
  if (states.get(sessionId) !== state || capturePlan && capturePlan.captureSequence !== state.lkgCaptureSequence) {
@@ -31801,35 +31644,39 @@ function createRustModeTransform(deps, options) {
31801
31644
  }
31802
31645
  wireCaches.set(sessionId, pendingWireCache);
31803
31646
  appliedAt = performance.now();
31804
- if (options.moduleClient.mirrorPull) {
31805
- const mirrorPullStartedAt = performance.now();
31806
- try {
31807
- await pullMemoryMirrorOnce({
31808
- db: deps.db,
31809
- module: options.moduleClient
31810
- });
31811
- } catch (error) {
31812
- sessionLog(sessionId, "rust memory mirror-back failed (ignored):", error);
31813
- } finally {
31814
- logStage(sessionId, "mirrorPull", mirrorPullStartedAt, timings);
31815
- }
31816
- }
31817
31647
  const getCompartmentsAfter = options.moduleClient.getCompartmentsAfter;
31818
- if (getCompartmentsAfter) {
31819
- const compartmentMirrorStartedAt = performance.now();
31820
- try {
31821
- await mirrorModuleCompartments({
31822
- db: deps.db,
31823
- sessionId,
31824
- reader: {
31825
- getCompartmentsAfter: (mirroredSessionId, afterSequence) => getCompartmentsAfter.call(options.moduleClient, mirroredSessionId, afterSequence)
31648
+ if (options.moduleClient.mirrorPull || getCompartmentsAfter) {
31649
+ (async () => {
31650
+ if (options.moduleClient.mirrorPull) {
31651
+ const mirrorPullStartedAt = performance.now();
31652
+ try {
31653
+ await pullMemoryMirrorOnce({
31654
+ db: deps.db,
31655
+ module: options.moduleClient
31656
+ });
31657
+ } catch (error) {
31658
+ sessionLog(sessionId, "rust memory mirror-back failed (ignored):", error);
31659
+ } finally {
31660
+ logStage(sessionId, "mirrorPull", mirrorPullStartedAt, timings);
31826
31661
  }
31827
- });
31828
- } catch (error) {
31829
- sessionLog(sessionId, "rust compartment mirror-back failed (ignored):", error);
31830
- } finally {
31831
- logStage(sessionId, "compartmentMirror", compartmentMirrorStartedAt, timings);
31832
- }
31662
+ }
31663
+ if (getCompartmentsAfter) {
31664
+ const compartmentMirrorStartedAt = performance.now();
31665
+ try {
31666
+ await mirrorModuleCompartments({
31667
+ db: deps.db,
31668
+ sessionId,
31669
+ reader: {
31670
+ getCompartmentsAfter: (mirroredSessionId, afterSequence) => getCompartmentsAfter.call(options.moduleClient, mirroredSessionId, afterSequence)
31671
+ }
31672
+ });
31673
+ } catch (error) {
31674
+ sessionLog(sessionId, "rust compartment mirror-back failed (ignored):", error);
31675
+ } finally {
31676
+ logStage(sessionId, "compartmentMirror", compartmentMirrorStartedAt, timings);
31677
+ }
31678
+ }
31679
+ })();
31833
31680
  }
31834
31681
  finishPass(true);
31835
31682
  } catch (error) {
@@ -32888,6 +32735,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
32888
32735
  messageTagNumbers,
32889
32736
  tagger: deps.tagger,
32890
32737
  ctxReduceAvailability,
32738
+ channel1StateBySession: deps.channel1StateBySession,
32891
32739
  todowriteAvailability,
32892
32740
  client: deps.client,
32893
32741
  activeAgent,
@@ -33080,59 +32928,22 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
33080
32928
  sessionLog(sessionId, "conversation_tokens UPDATE failed:", error);
33081
32929
  }
33082
32930
  }
33083
- if (ctxReduceCallable && !compactionOff && deps.channel1StateBySession) {
33084
- try {
33085
- const resolvedExecuteThresholdPct = resolveExecuteThreshold(deps.executeThresholdPercentage ?? 65, deps.getModelKey?.(sessionId), 65, {
33086
- tokensConfig: deps.executeThresholdTokens,
33087
- contextLimit: resolvedContextLimit ?? 0
33088
- });
33089
- let tailToolTokens;
33090
- let liveTailTokens;
32931
+ const channelBaseline = deps.channel1StateBySession?.get(sessionId);
32932
+ if (ctxReduceCallable && !compactionOff && channelBaseline) {
32933
+ const measuredU = Math.min(Math.max(0, channelBaseline.baselineT + channelBaseline.turnDeltaT), Math.max(0, channelBaseline.baselineU + channelBaseline.turnDeltaU));
32934
+ resetLastNudgeCycleIfTailShrank(db, sessionId, measuredU);
32935
+ if (channelBaseline.evaluable && !channelBaseline.generationInvalidated && !channelBaseline.reducedSinceRefresh) {
32936
+ const channel2Evaluation = evaluateChannel2(channelBaseline);
33091
32937
  try {
33092
- const agg = getActiveTagTokenAggregate(db, sessionId, deps.protectedTags);
33093
- tailToolTokens = agg.toolOutput;
33094
- liveTailTokens = agg.conversation + agg.toolCall;
33095
- } catch {
33096
- const estimate = computeTailTokenEstimate(messages);
33097
- tailToolTokens = estimate.tailToolTokens;
33098
- liveTailTokens = estimate.liveTailTokens;
33099
- }
33100
- const executeThresholdTokens = Math.round((resolvedContextLimit ?? 0) * resolvedExecuteThresholdPct / 100);
33101
- const usableTokens = Math.max(0, executeThresholdTokens - contextUsage.inputTokens + liveTailTokens);
33102
- resetLastNudgeCycleIfTailShrank(db, sessionId, tailToolTokens);
33103
- const oldestReclaimableToolTags = getOldestActiveUnprotectedToolTags(db, sessionId, deps.protectedTags);
33104
- deps.channel1StateBySession.set(sessionId, {
33105
- tailToolTokens,
33106
- historyBudgetTokens: historyBudgetTokens ?? 0,
33107
- contextLimit: resolvedContextLimit ?? 0,
33108
- executeThresholdPercentage: resolvedExecuteThresholdPct,
33109
- lastInputTokens: contextUsage.inputTokens,
33110
- turnToolTokens: 0,
33111
- usableTokens,
33112
- reducedSinceRefresh: false,
33113
- oldestReclaimableToolTags
33114
- });
33115
- const channel2MetricsKnown = resolvedContextLimit !== undefined && resolvedContextLimit > 0 && resolvedExecuteThresholdPct > 0;
33116
- if (channel2MetricsKnown) {
33117
- const channel2ShouldTrigger = shouldTriggerChannel2({
33118
- reclaimableTokens: tailToolTokens,
33119
- usableTokens
33120
- });
33121
- try {
33122
- if (channel2ShouldTrigger) {
33123
- casChannel2NudgeState(db, sessionId, "", "pending");
33124
- } else {
33125
- casChannel2NudgeState(db, sessionId, "pending", "");
33126
- }
33127
- } catch (error) {
33128
- sessionLog(sessionId, "channel2 trigger CAS failed (ignored):", error);
32938
+ if (channel2Evaluation.shouldTrigger) {
32939
+ casChannel2NudgeState(db, sessionId, "", "pending");
32940
+ } else {
32941
+ casChannel2NudgeState(db, sessionId, "pending", "");
33129
32942
  }
32943
+ } catch (error) {
32944
+ sessionLog(sessionId, "channel2 trigger CAS failed (ignored):", error);
33130
32945
  }
33131
- } catch (error) {
33132
- sessionLog(sessionId, "channel1 baseline snapshot failed (ignored):", error);
33133
32946
  }
33134
- } else {
33135
- deps.channel1StateBySession?.delete(sessionId);
33136
32947
  }
33137
32948
  const elapsed = (performance.now() - startTime).toFixed(1);
33138
32949
  sessionLog(sessionId, `transform completed in ${elapsed}ms (${messages.length} messages, ${targets.size} targets, watermark: ${watermark})`);
@@ -33190,8 +33001,7 @@ async function deliverChannel2IfPending(deps, sessionId) {
33190
33001
  db: deps.db,
33191
33002
  client: deps.client,
33192
33003
  directiveText: deps.channel2DirectiveTextBySession?.get(sessionId),
33193
- reclaimableTokens: baseline ? baseline.tailToolTokens + baseline.turnToolTokens : undefined,
33194
- usableTokens: baseline?.usableTokens,
33004
+ baseline,
33195
33005
  oldestReclaimableToolTags: baseline?.oldestReclaimableToolTags
33196
33006
  });
33197
33007
  if (delivered || getChannel2NudgeState(deps.db, sessionId) !== "pending") {
@@ -34133,26 +33943,19 @@ function maybeInjectChannel1Nudge(args, sessionId, tool, output) {
34133
33943
  return;
34134
33944
  if (out.output.includes(CHANNEL1_SENTINEL))
34135
33945
  return;
34136
- const thisTurnTokens = toolOutputTokens(out.output);
34137
- state.turnToolTokens += thisTurnTokens;
33946
+ state.turnDeltaT += toolOutputTokens(out.output);
34138
33947
  if (state.reducedSinceRefresh)
34139
33948
  return;
34140
- const undroppedTokens = state.tailToolTokens + state.turnToolTokens;
34141
- const pressure = computePressure({
34142
- lastInputTokens: state.lastInputTokens,
34143
- turnToolTokens: state.turnToolTokens,
34144
- contextLimit: state.contextLimit,
34145
- executeThresholdPercentage: state.executeThresholdPercentage
34146
- });
34147
- const workingWindowTokens = Math.round(state.contextLimit * state.executeThresholdPercentage / 100);
34148
33949
  const decision = decideChannel1({
34149
- undroppedTokens,
34150
- pressure,
34151
- estimatedInputTokens: state.lastInputTokens + state.turnToolTokens,
34152
- workingWindowTokens,
33950
+ baselineU: state.baselineU,
33951
+ baselineT: state.baselineT,
33952
+ turnDeltaU: state.turnDeltaU,
33953
+ turnDeltaT: state.turnDeltaT,
34153
33954
  lastNudgeUndropped: getLastNudgeUndropped(args.db, sessionId),
34154
33955
  lastNudgeLevel: getLastNudgeLevel(args.db, sessionId),
34155
- hasRecentReduce: false
33956
+ hasRecentReduce: false,
33957
+ evaluable: state.evaluable,
33958
+ generationInvalidated: state.generationInvalidated
34156
33959
  });
34157
33960
  setLastNudgeUndropped(args.db, sessionId, decision.nextLastNudge);
34158
33961
  setLastNudgeLevel(args.db, sessionId, decision.nextLastNudgeLevel);
@@ -34170,8 +33973,11 @@ function createToolExecuteAfterHook(args) {
34170
33973
  await flushIgnoredMessages(typedInput.sessionID);
34171
33974
  if (typedInput.tool === "ctx_reduce") {
34172
33975
  const state = args.channel1StateBySession.get(typedInput.sessionID);
34173
- if (state)
33976
+ if (state) {
34174
33977
  state.reducedSinceRefresh = true;
33978
+ state.evaluable = false;
33979
+ state.generationInvalidated = true;
33980
+ }
34175
33981
  try {
34176
33982
  resetLastNudgeCycle(args.db, typedInput.sessionID);
34177
33983
  } catch (error) {
@@ -34237,7 +34043,7 @@ function createToolExecuteAfterHook(args) {
34237
34043
  }
34238
34044
 
34239
34045
  // src/hooks/magic-context/system-prompt-hash.ts
34240
- import { createHash as createHash14 } from "node:crypto";
34046
+ import { createHash as createHash13 } from "node:crypto";
34241
34047
 
34242
34048
  // src/agents/magic-context-prompt.ts
34243
34049
  var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
@@ -34396,6 +34202,9 @@ Prefer many small targeted operations over one large blanket operation, and keep
34396
34202
 
34397
34203
  // src/hooks/magic-context/system-prompt-hash.ts
34398
34204
  var MAGIC_CONTEXT_MARKER = "## Magic Context";
34205
+ var SYSTEM_PROMPT_GUIDANCE_SEPARATOR = `
34206
+
34207
+ `;
34399
34208
  function clearSystemPromptHashSession(sessionId, handleMaps) {
34400
34209
  handleMaps.stickyDateBySession.delete(sessionId);
34401
34210
  handleMaps.cachedDocsBySession.delete(sessionId);
@@ -34457,7 +34266,7 @@ function createSystemPromptHashHandler(deps) {
34457
34266
  `);
34458
34267
  if (fullPrompt.length > 0 && !fullPrompt.includes(MAGIC_CONTEXT_MARKER) && !skipGuidanceForDisabledSubagent) {
34459
34268
  const guidance = buildMagicContextSection(null, deps.protectedTags, effectiveCtxReduceEnabled, deps.dreamerEnabled, deps.experimentalTemporalAwareness, deps.experimentalCavemanTextCompression, subagentReduceMode, deps.language, deps.memoryEnabled !== false, promptSurface.preset, promptSurface.primaryOverride);
34460
- output.system.push(guidance);
34269
+ output.system[0] = `${output.system[0]}${SYSTEM_PROMPT_GUIDANCE_SEPARATOR}${guidance}`;
34461
34270
  sessionLog(sessionId, `injected generic guidance into system prompt (ctxReduce=${effectiveCtxReduceEnabled}, subagent=${isSubagentSession2}, subagentReduceMode=${subagentReduceMode})`);
34462
34271
  }
34463
34272
  const isCacheBusting = deps.systemPromptRefreshSessions.has(sessionId);
@@ -34480,7 +34289,7 @@ function createSystemPromptHashHandler(deps) {
34480
34289
  }
34481
34290
  const stickyDate = stickyDateBySession.get(sessionId);
34482
34291
  const stableCandidate = currentDate && stickyDate && currentDate !== stickyDate ? liveSystemContent.replace(DATE_PATTERN_ALL, stickyDate) : liveSystemContent;
34483
- const stableCandidateHash = createHash14("md5").update(promptSurfaceHashMaterial(stableCandidate, promptSurface.preset)).digest("hex");
34292
+ const stableCandidateHash = createHash13("md5").update(promptSurfaceHashMaterial(stableCandidate, promptSurface.preset)).digest("hex");
34484
34293
  const contentOrPresetChanged = hasPersistedHash && stableCandidateHash !== previousHash;
34485
34294
  const dateMayAdvance = isCacheBusting || contentOrPresetChanged;
34486
34295
  if (currentDate && !stickyDate) {
@@ -34500,7 +34309,7 @@ function createSystemPromptHashHandler(deps) {
34500
34309
  `);
34501
34310
  if (!availability.frozen || !modelKey)
34502
34311
  return;
34503
- const currentHash = createHash14("md5").update(promptSurfaceHashMaterial(systemContent, promptSurface.preset)).digest("hex");
34312
+ const currentHash = createHash13("md5").update(promptSurfaceHashMaterial(systemContent, promptSurface.preset)).digest("hex");
34504
34313
  if (!sessionMetaEarly) {
34505
34314
  return;
34506
34315
  }
@@ -34719,7 +34528,7 @@ function createMagicContextHook(deps) {
34719
34528
  log("[magic-context] disabling feature because persistent storage is unavailable:", reason);
34720
34529
  notifyMagicContextDisabled(deps.client, reason);
34721
34530
  const migration = getMigrationOnOpenRefusal();
34722
- const blockingProcesses = migration?.serverPids.map((pid) => ({ harness: "OpenCode server", pid })) ?? [];
34531
+ const blockingProcesses = migration?.blockingProcesses ?? migration?.serverPids.map((pid) => ({ kind: "process", pid })) ?? [];
34723
34532
  const fence = getSchemaFenceRejection();
34724
34533
  recordHookInitFailure({
34725
34534
  type: "storage",
@@ -34795,7 +34604,7 @@ function createMagicContextHook(deps) {
34795
34604
  const internalChildSessions = deps.liveSessionState?.internalChildSessions ?? new Set;
34796
34605
  const recompProgressBySession = deps.liveSessionState?.recompProgressBySession ?? new Map;
34797
34606
  const dreamerProgressByProject = deps.liveSessionState?.dreamerProgressByProject ?? new Map;
34798
- const channel1StateBySession = new Map;
34607
+ const channel1StateBySession = deps.liveSessionState?.channel1StateBySession ?? new Map;
34799
34608
  const channel2DirectiveTextBySession = new Map;
34800
34609
  const resolveLiveModel = (sessionId) => {
34801
34610
  const cached = liveModelBySession.get(sessionId);
@@ -34826,6 +34635,7 @@ function createMagicContextHook(deps) {
34826
34635
  db,
34827
34636
  liveSessionState: {
34828
34637
  liveModelBySession,
34638
+ channel1StateBySession,
34829
34639
  variantBySession,
34830
34640
  agentBySession,
34831
34641
  historyRefreshSessions,
@@ -35423,6 +35233,7 @@ function createMagicContextHook(deps) {
35423
35233
  return model ? `${model.providerID}/${model.modelID}` : undefined;
35424
35234
  },
35425
35235
  getDreamerProgress: () => dreamerProgressByProject.get(projectPath) ?? null,
35236
+ getTailHygiene: (sessionId) => channel1StateBySession.get(sessionId),
35426
35237
  getContextLimit: (sessionId) => {
35427
35238
  const model = resolveLiveModel(sessionId);
35428
35239
  if (!model)
@@ -35657,8 +35468,27 @@ function replaceMessagesInPlace2(output, next) {
35657
35468
  if (output.messages !== next)
35658
35469
  output.messages.splice(0, output.messages.length, ...next);
35659
35470
  }
35471
+ function preserveUserTerminatedTail(messages, inputTail) {
35472
+ if (inputTail?.info.role !== "user" || messages.at(-1)?.info.role !== "assistant")
35473
+ return;
35474
+ let userIndex = messages.lastIndexOf(inputTail);
35475
+ if (userIndex < 0) {
35476
+ const inputId = inputTail.info.id;
35477
+ for (let index = messages.length - 1;index >= 0; index -= 1) {
35478
+ const message = messages[index];
35479
+ if (message.info.role === "user" && message.info.id === inputId) {
35480
+ userIndex = index;
35481
+ break;
35482
+ }
35483
+ }
35484
+ }
35485
+ const trailingUser = userIndex >= 0 ? messages[userIndex] : inputTail;
35486
+ if (userIndex >= 0)
35487
+ messages.splice(userIndex, 1);
35488
+ messages.push(trailingUser);
35489
+ }
35660
35490
  function createMessagesTransformHandler(args) {
35661
- return async (input, output) => {
35491
+ const run = async (input, output) => {
35662
35492
  const sessionId = resolveSessionId2(output);
35663
35493
  const agent = resolveAgentNameFromMessages(output.messages);
35664
35494
  const isInternalChild = typeof sessionId === "string" && sessionId.length > 0 && args.internalChildSessions?.has(sessionId) === true;
@@ -35779,6 +35609,14 @@ function createMessagesTransformHandler(args) {
35779
35609
  restoreCompactionOffInput();
35780
35610
  return output.messages;
35781
35611
  };
35612
+ return async (input, output) => {
35613
+ const inputTail = output.messages.at(-1);
35614
+ try {
35615
+ return await run(input, output);
35616
+ } finally {
35617
+ preserveUserTerminatedTail(output.messages, inputTail);
35618
+ }
35619
+ };
35782
35620
  }
35783
35621
  function resolveSessionId2(output) {
35784
35622
  for (const message of output.messages) {
@@ -36167,6 +36005,7 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
36167
36005
  }) : contextLimit;
36168
36006
  const nativeContextUsagePercentage = nativeContextLimit > 0 ? effectiveInputTokens / nativeContextLimit * 100 : undefined;
36169
36007
  const calibration = resolveModelCalibration(activeProviderID, activeModelID);
36008
+ const tailHygiene = resolveTailHygieneStatus(liveSessionState?.channel1StateBySession.get(sessionId), moduleStatus?.tail_hygiene);
36170
36009
  const calibrated = calibrateBuckets({
36171
36010
  inputTokens: effectiveInputTokens,
36172
36011
  systemLocal: systemPromptTokens,
@@ -36211,6 +36050,7 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
36211
36050
  conversationTokens: calibrated.conversationTokens,
36212
36051
  toolCallTokens: calibrated.toolCallTokens,
36213
36052
  toolDefinitionTokens: calibrated.toolDefinitionTokens,
36053
+ ...tailHygiene === undefined ? {} : { tailHygiene },
36214
36054
  executeThreshold,
36215
36055
  executeThresholdClamped,
36216
36056
  boundaryPresent: moduleStatus?.boundary_present,
@@ -36447,7 +36287,7 @@ function registerRpcHandlers(rpcServer, args) {
36447
36287
  }
36448
36288
  });
36449
36289
  const buildManagedCtx = async (db) => {
36450
- const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await import("./derive-budgets-0f8xpyw2.js");
36290
+ const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await import("./derive-budgets-da4yg3tz.js");
36451
36291
  const { resolveFallbackChain: resolveFallbackChain2 } = await import("./resolve-fallbacks-5n5tvge1.js");
36452
36292
  const { userMemoryCollectionEnabled: userMemoryCollectionEnabled2 } = await import("./task-config-gbp7r23g.js");
36453
36293
  const DEFAULT_HISTORIAN_TIMEOUT_MS2 = 600000;
@@ -36474,7 +36314,7 @@ function registerRpcHandlers(rpcServer, args) {
36474
36314
  const db = getDb();
36475
36315
  if (!db)
36476
36316
  return { ok: false, error: "db unavailable" };
36477
- const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-c3ff16k7.js");
36317
+ const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-jsde4ygw.js");
36478
36318
  const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-dxske5zm.js");
36479
36319
  log(`[rpc] recomp requested for session ${sessionId}`);
36480
36320
  const ctx = await buildManagedCtx(db);
@@ -36490,7 +36330,7 @@ function registerRpcHandlers(rpcServer, args) {
36490
36330
  const db = getDb();
36491
36331
  if (!db)
36492
36332
  return { ok: false, error: "db unavailable" };
36493
- const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-c3ff16k7.js");
36333
+ const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-jsde4ygw.js");
36494
36334
  const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-dxske5zm.js");
36495
36335
  log(`[rpc] session-upgrade requested for session ${sessionId}`);
36496
36336
  const ctx = await buildManagedCtx(db);
@@ -38340,7 +38180,7 @@ Mark discardable once processed: large outputs you've summarized, repeated or re
38340
38180
  Keep: user messages, unresolved errors, raw evidence you haven't extracted yet, and outputs whose exact wording may matter later.
38341
38181
  Never blanket-mark large ranges (e.g. "1-50") — review what each tag holds first.`;
38342
38182
  // src/tools/ctx-reduce/tools.ts
38343
- import { createHash as createHash15 } from "node:crypto";
38183
+ import { createHash as createHash14 } from "node:crypto";
38344
38184
  import { tool as tool4 } from "@opencode-ai/plugin";
38345
38185
 
38346
38186
  // src/features/magic-context/range-parser.ts
@@ -38410,11 +38250,11 @@ function createCtxReduceTool(deps) {
38410
38250
  const stableId = `oc-${sessionId}-${callId}`;
38411
38251
  if (Buffer.byteLength(stableId) <= 128)
38412
38252
  return stableId;
38413
- return `oc-${createHash15("sha256").update(stableId).digest("hex")}`;
38253
+ return `oc-${createHash14("sha256").update(stableId).digest("hex")}`;
38414
38254
  }
38415
38255
  fallbackCommandSequence += 1;
38416
38256
  const monotonicId = `oc-${sessionId}-${fallbackCommandSequence}`;
38417
- return Buffer.byteLength(monotonicId) <= 128 ? monotonicId : `oc-${createHash15("sha256").update(monotonicId).digest("hex")}`;
38257
+ return Buffer.byteLength(monotonicId) <= 128 ? monotonicId : `oc-${createHash14("sha256").update(monotonicId).digest("hex")}`;
38418
38258
  };
38419
38259
  return tool4({
38420
38260
  description: CTX_REDUCE_DESCRIPTION,
@@ -38954,6 +38794,7 @@ class MagicContextRpcServer {
38954
38794
  port: this.port,
38955
38795
  pid: process.pid,
38956
38796
  started_at: this.startedAt,
38797
+ kind: "OpenCode server",
38957
38798
  token: this.token,
38958
38799
  instance_id: this.instanceId
38959
38800
  }), enforcePrivatePermissions ? { encoding: "utf-8", mode: 384 } : { encoding: "utf-8" });