@cortexkit/opencode-magic-context 0.38.1 → 0.40.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 (172) hide show
  1. package/README.md +57 -4
  2. package/dist/config/index.d.ts.map +1 -1
  3. package/dist/config/profiles.d.ts +22 -0
  4. package/dist/config/profiles.d.ts.map +1 -0
  5. package/dist/config/project-security.d.ts +14 -6
  6. package/dist/config/project-security.d.ts.map +1 -1
  7. package/dist/config/raw-loader.d.ts +42 -0
  8. package/dist/config/raw-loader.d.ts.map +1 -0
  9. package/dist/config/schema/magic-context.d.ts +966 -531
  10. package/dist/config/schema/magic-context.d.ts.map +1 -1
  11. package/dist/features/magic-context/dreamer/classify.d.ts +3 -2
  12. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  13. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts +9 -2
  14. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  15. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts +4 -2
  16. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts.map +1 -1
  17. package/dist/features/magic-context/dreamer/map-memories.d.ts +21 -5
  18. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  19. package/dist/features/magic-context/dreamer/refresh-primers.d.ts +3 -2
  20. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
  21. package/dist/features/magic-context/dreamer/task-config.d.ts +2 -1
  22. package/dist/features/magic-context/dreamer/task-config.d.ts.map +1 -1
  23. package/dist/features/magic-context/dreamer/task-executor.d.ts +0 -1
  24. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  25. package/dist/features/magic-context/dreamer/task-scheduler.d.ts +3 -2
  26. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  27. package/dist/features/magic-context/dreamer/verify-prompt.d.ts +5 -2
  28. package/dist/features/magic-context/dreamer/verify-prompt.d.ts.map +1 -1
  29. package/dist/features/magic-context/dreamer/verify.d.ts +6 -3
  30. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  31. package/dist/features/magic-context/fail-closed-block.d.ts +11 -1
  32. package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
  33. package/dist/features/magic-context/memory/embedding-failure.d.ts +11 -0
  34. package/dist/features/magic-context/memory/embedding-failure.d.ts.map +1 -0
  35. package/dist/features/magic-context/memory/embedding-openai.d.ts +5 -0
  36. package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
  37. package/dist/features/magic-context/memory/embedding-provider.d.ts +3 -0
  38. package/dist/features/magic-context/memory/embedding-provider.d.ts.map +1 -1
  39. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  40. package/dist/features/magic-context/mural/compress-cues.d.ts +3 -2
  41. package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
  42. package/dist/features/magic-context/project-embedding-registry.d.ts +2 -0
  43. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  44. package/dist/features/magic-context/smart-notes/compiler.d.ts +3 -2
  45. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
  46. package/dist/features/magic-context/smart-notes/condition-compiler.d.ts +2 -0
  47. package/dist/features/magic-context/smart-notes/condition-compiler.d.ts.map +1 -1
  48. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -1
  49. package/dist/features/magic-context/storage-db.d.ts +2 -2
  50. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  51. package/dist/features/magic-context/storage-meta-persisted.d.ts +7 -2
  52. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  53. package/dist/features/magic-context/storage-meta-shared.d.ts +1 -0
  54. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  55. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  56. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  57. package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
  58. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  59. package/dist/features/magic-context/storage.d.ts +1 -1
  60. package/dist/features/magic-context/storage.d.ts.map +1 -1
  61. package/dist/features/magic-context/tool-definition-tokens.d.ts +10 -0
  62. package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
  63. package/dist/features/magic-context/transform-decision-log.d.ts +11 -0
  64. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  65. package/dist/features/magic-context/user-memory/review-user-memories.d.ts +3 -2
  66. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
  67. package/dist/hooks/magic-context/channel2-delivery.d.ts +3 -1
  68. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  69. package/dist/hooks/magic-context/command-handler.d.ts +4 -0
  70. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  71. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +4 -1
  72. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
  73. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  74. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  75. package/dist/hooks/magic-context/compartment-runner-types.d.ts +4 -1
  76. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  77. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +14 -2
  78. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
  79. package/dist/hooks/magic-context/emergency-fail-closed.d.ts +7 -0
  80. package/dist/hooks/magic-context/emergency-fail-closed.d.ts.map +1 -1
  81. package/dist/hooks/magic-context/format-embed-failure.d.ts +3 -0
  82. package/dist/hooks/magic-context/format-embed-failure.d.ts.map +1 -0
  83. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  84. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  85. package/dist/hooks/magic-context/inject-compartments.d.ts +13 -1
  86. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  87. package/dist/hooks/magic-context/lkg-persist.d.ts +14 -0
  88. package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -0
  89. package/dist/hooks/magic-context/lkg-slot.d.ts +13 -0
  90. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  91. package/dist/hooks/magic-context/module-state-sync.d.ts +1 -0
  92. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  93. package/dist/hooks/magic-context/module-transport.d.ts +12 -0
  94. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  95. package/dist/hooks/magic-context/raw-fallback-context-limit.d.ts.map +1 -1
  96. package/dist/hooks/magic-context/recomp-orchestrator.d.ts +4 -1
  97. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  98. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  99. package/dist/hooks/magic-context/strip-content.d.ts +6 -0
  100. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  101. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +12 -0
  102. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  103. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +3 -1
  104. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  105. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +5 -0
  106. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  107. package/dist/hooks/magic-context/transform.d.ts +9 -1
  108. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  109. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
  110. package/dist/{index-2y0ybv5x.js → index-3dkzzh0t.js} +15 -17
  111. package/dist/{index-5znjkjws.js → index-axpym70t.js} +879 -170
  112. package/dist/index-ehpzdy0v.js +126 -0
  113. package/dist/{index-22mw8km4.js → index-rw0qrkvq.js} +4 -2
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.js +18466 -16177
  116. package/dist/model-resolution-r9jbcz86.js +15 -0
  117. package/dist/plugin/dream-timer.d.ts +3 -0
  118. package/dist/plugin/dream-timer.d.ts.map +1 -1
  119. package/dist/plugin/hooks/create-session-hooks.d.ts +2 -0
  120. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  121. package/dist/plugin/messages-transform.d.ts +14 -6
  122. package/dist/plugin/messages-transform.d.ts.map +1 -1
  123. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  124. package/dist/{recomp-orchestrator-p030kxtc.js → recomp-orchestrator-dmyvqekw.js} +2 -3
  125. package/dist/shared/jsonc-edit.d.ts +6 -1
  126. package/dist/shared/jsonc-edit.d.ts.map +1 -1
  127. package/dist/shared/model-resolution.d.ts +53 -0
  128. package/dist/shared/model-resolution.d.ts.map +1 -0
  129. package/dist/shared/model-suggestion-retry.d.ts +4 -1
  130. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  131. package/dist/shared/resolve-fallbacks.d.ts +5 -1
  132. package/dist/shared/resolve-fallbacks.d.ts.map +1 -1
  133. package/dist/shared/rpc-types.d.ts +2 -0
  134. package/dist/shared/rpc-types.d.ts.map +1 -1
  135. package/dist/shared/rpc-utils.d.ts +12 -1
  136. package/dist/shared/rpc-utils.d.ts.map +1 -1
  137. package/dist/shared/status-detail-text.d.ts +4 -0
  138. package/dist/shared/status-detail-text.d.ts.map +1 -0
  139. package/dist/shared/subagent-runner.d.ts +2 -1
  140. package/dist/shared/subagent-runner.d.ts.map +1 -1
  141. package/dist/{storage-meta-session-2306t3j7.js → storage-meta-session-yvtbaw7c.js} +1 -1
  142. package/dist/{task-config-at3adc59.js → task-config-a1qmj9bx.js} +2 -2
  143. package/dist/tui/data/context-db.d.ts.map +1 -1
  144. package/dist/tui-compiled/data/context-db.d.ts.map +1 -1
  145. package/package.json +4 -2
  146. package/src/config/index.test.ts +434 -19
  147. package/src/config/index.ts +67 -33
  148. package/src/config/profiles.ts +106 -0
  149. package/src/config/project-security.hostile-matrix.test.ts +480 -0
  150. package/src/config/project-security.test.ts +43 -5
  151. package/src/config/project-security.ts +151 -22
  152. package/src/config/raw-loader.test.ts +424 -0
  153. package/src/config/raw-loader.ts +490 -0
  154. package/src/config/schema/magic-context.test.ts +272 -2
  155. package/src/config/schema/magic-context.ts +342 -49
  156. package/src/shared/jsonc-edit.ts +74 -1
  157. package/src/shared/model-resolution.test.ts +170 -0
  158. package/src/shared/model-resolution.ts +227 -0
  159. package/src/shared/model-suggestion-retry.test.ts +27 -0
  160. package/src/shared/model-suggestion-retry.ts +19 -10
  161. package/src/shared/resolve-fallbacks.test.ts +13 -1
  162. package/src/shared/resolve-fallbacks.ts +19 -4
  163. package/src/shared/rpc-types.ts +2 -0
  164. package/src/shared/rpc-utils.test.ts +32 -0
  165. package/src/shared/rpc-utils.ts +38 -13
  166. package/src/shared/status-detail-text.test.ts +82 -0
  167. package/src/shared/status-detail-text.ts +57 -0
  168. package/src/shared/subagent-runner.ts +3 -1
  169. package/src/tui/data/context-db.ts +1 -0
  170. package/src/tui-compiled/data/context-db.ts +1 -0
  171. package/dist/index-td9depx5.js +0 -46
  172. package/dist/resolve-fallbacks-qf0ekmz9.js +0 -11
@@ -3,9 +3,6 @@ import {
3
3
  modelSupportsVision,
4
4
  shouldEnforcePrivateStoragePermissions
5
5
  } from "./index-mg1yx1ph.js";
6
- import {
7
- parseProviderModel
8
- } from "./index-td9depx5.js";
9
6
  import {
10
7
  describeError,
11
8
  getErrorMessage,
@@ -17,7 +14,7 @@ import {
17
14
  ensureSessionMetaRow,
18
15
  persistCachedM0,
19
16
  updateSessionMeta
20
- } from "./index-22mw8km4.js";
17
+ } from "./index-rw0qrkvq.js";
21
18
  import {
22
19
  modelRefLookupOrder,
23
20
  piModelRefToCanonical
@@ -401,9 +398,163 @@ function buildPrimaryLanguageDirective(language) {
401
398
  return `Use ${target} for your natural-language replies to the user unless the user explicitly asks for another language. Keep code, identifiers, file paths, commands, logs, and quoted text verbatim.`;
402
399
  }
403
400
 
401
+ // src/shared/redaction.ts
402
+ import { homedir, userInfo } from "node:os";
403
+ function escapeRegex(value) {
404
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
405
+ }
406
+ var SECRET_WORDS = [
407
+ "key",
408
+ "token",
409
+ "secret",
410
+ "password",
411
+ "auth",
412
+ "authorization",
413
+ "bearer",
414
+ "credential"
415
+ ];
416
+ var SECRET_SEGMENT_PATTERN = new RegExp(`^(?:${SECRET_WORDS.map((w) => `${w}s?`).join("|")})$`, "i");
417
+ var TRAILING_DESCRIPTORS = new Set(["id", "ids", "value", "values", "header", "headers"]);
418
+ function redactionTypeForKey(key) {
419
+ const normalized = key.trim().toLowerCase().replace(/[^a-z0-9_.-]+/g, "_");
420
+ const suffix = normalized.split(".").filter(Boolean).at(-1) ?? normalized;
421
+ return suffix || "secret";
422
+ }
423
+ function isNonSecretScalarValue(value) {
424
+ const v = value.trim();
425
+ if (v === "true" || v === "false" || v === "null" || v === "undefined")
426
+ return true;
427
+ return /^[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(v);
428
+ }
429
+ var SECRET_QUALIFIERS = new Set([
430
+ "api",
431
+ "access",
432
+ "private",
433
+ "client",
434
+ "auth",
435
+ "authorization",
436
+ "secret",
437
+ "bearer",
438
+ "session",
439
+ "refresh",
440
+ "service",
441
+ "x",
442
+ "openai",
443
+ "anthropic",
444
+ "google",
445
+ "github",
446
+ "huggingface",
447
+ "aws",
448
+ "azure"
449
+ ]);
450
+ function sanitizePathString(value) {
451
+ const home = homedir();
452
+ const username = userInfo().username;
453
+ let sanitized = value;
454
+ if (home) {
455
+ sanitized = sanitized.replace(new RegExp(escapeRegex(home), "g"), "~");
456
+ }
457
+ sanitized = sanitized.replace(/\/Users\/[^/]+\//g, "/Users/<USER>/");
458
+ sanitized = sanitized.replace(/\/home\/[^/]+\//g, "/home/<USER>/");
459
+ sanitized = sanitized.replace(/C:\\Users\\[^\\]+\\/g, "C:\\Users\\<USER>\\");
460
+ if (username) {
461
+ sanitized = sanitized.replace(new RegExp(escapeRegex(username), "g"), "<USER>");
462
+ }
463
+ return sanitized;
464
+ }
465
+ var SECRET_TEXT_PATTERNS = [
466
+ {
467
+ pattern: /\bsk-ant-(?:api03-)?[A-Za-z0-9_-]{32,}/g,
468
+ replacement: "<ANTHROPIC_API_KEY_REDACTED>"
469
+ },
470
+ {
471
+ pattern: /\bsk-(?:proj-)?[A-Za-z0-9_-]{32,}/g,
472
+ replacement: "<OPENAI_API_KEY_REDACTED>"
473
+ },
474
+ {
475
+ pattern: /\bgithub_pat_[A-Za-z0-9_]{20,}/g,
476
+ replacement: "<GITHUB_PAT_REDACTED>"
477
+ },
478
+ {
479
+ pattern: /\b(?:gh[opsu]|ghr)_[A-Za-z0-9]{30,}/g,
480
+ replacement: "<GITHUB_TOKEN_REDACTED>"
481
+ },
482
+ {
483
+ pattern: /\bhf_[A-Za-z0-9]{30,}/g,
484
+ replacement: "<HUGGINGFACE_TOKEN_REDACTED>"
485
+ },
486
+ {
487
+ pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g,
488
+ replacement: "<AWS_ACCESS_KEY_ID_REDACTED>"
489
+ },
490
+ {
491
+ pattern: /\bxox[abprsuvc]-[A-Za-z0-9-]{10,}/g,
492
+ replacement: "<SLACK_TOKEN_REDACTED>"
493
+ },
494
+ {
495
+ pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g,
496
+ replacement: "<GOOGLE_API_KEY_REDACTED>"
497
+ },
498
+ {
499
+ pattern: /\b(Authorization\s*:\s*Bearer\s+)([A-Za-z0-9._~+/=-]{8,})/gi,
500
+ replacement: (_full, prefix) => `${prefix}<REDACTED:bearer>`
501
+ },
502
+ {
503
+ pattern: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,
504
+ replacement: "<JWT_REDACTED>"
505
+ },
506
+ {
507
+ pattern: /(["'])([^"']*(?:key|token|secret|password|auth|bearer|credential)[^"']*)\1(\s*:\s*)(["'])([^"']*)\4/gi,
508
+ replacement: (full, quote, key, separator, valueQuote, value) => isNonSecretScalarValue(value) ? full : `${quote}${key}${quote}${separator}${valueQuote}<REDACTED:${redactionTypeForKey(key)}>${valueQuote}`
509
+ },
510
+ {
511
+ pattern: /\b([A-Za-z0-9_.-]*(?:key|token|secret|password|auth|bearer|credential)[A-Za-z0-9_.-]*)\s*=\s*([^\s'"`]+)/gi,
512
+ replacement: (full, key, value) => isNonSecretScalarValue(value) ? full : `${key}=<REDACTED:${redactionTypeForKey(key)}>`
513
+ }
514
+ ];
515
+ function redactSecretText(value) {
516
+ let redacted = value;
517
+ for (const { pattern, replacement } of SECRET_TEXT_PATTERNS) {
518
+ if (typeof replacement === "string") {
519
+ redacted = redacted.replace(pattern, replacement);
520
+ } else {
521
+ redacted = redacted.replace(pattern, replacement);
522
+ }
523
+ }
524
+ return redacted;
525
+ }
526
+ function sanitizeDiagnosticText(value) {
527
+ return redactSecretText(sanitizePathString(value));
528
+ }
529
+ var SHAREABILITY_SENSITIVE_PATTERNS = [
530
+ /\bC:\/Users\/[^/\s]+/i,
531
+ /(?:^|\s)~\/[^\s]+/,
532
+ /\b(?:api[_-]?key|secret|token|password|passwd|pwd|client[_-]?secret|access[_-]?key)\b\s*[:=]\s*\S+/i,
533
+ /\b(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\])(?::\d+)?\b/i,
534
+ /\b(?:10|127)\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,
535
+ /\b192\.168\.\d{1,3}\.\d{1,3}\b/,
536
+ /\b172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}\b/
537
+ ];
538
+ function hasShareabilitySensitiveText(text) {
539
+ try {
540
+ if (sanitizeDiagnosticText(text) !== text)
541
+ return true;
542
+ return SHAREABILITY_SENSITIVE_PATTERNS.some((pattern) => pattern.test(text));
543
+ } catch {
544
+ return true;
545
+ }
546
+ }
547
+
404
548
  // src/features/magic-context/fail-closed-block.ts
405
549
  var FAIL_CLOSED_DOCTOR_COMMAND = "npx @cortexkit/magic-context@latest doctor";
406
550
  var FAIL_CLOSED_REPROBE_EVERY_N = 5;
551
+ function attachFailClosedBlockingProcessEvidence(process2, evidence) {
552
+ Object.defineProperties(process2, {
553
+ startTime: { configurable: true, value: evidence.startTime },
554
+ commandLine: { configurable: true, value: evidence.commandLine }
555
+ });
556
+ return process2;
557
+ }
407
558
 
408
559
  class FailClosedBlockingError extends Error {
409
560
  code = "FAIL_CLOSED_BLOCKING";
@@ -426,6 +577,7 @@ function isMagicContextHiddenAgentName(agent) {
426
577
  return false;
427
578
  }
428
579
  var MAX_FORMATTED_BLOCKING_PROCESSES = 8;
580
+ var MAX_FORMATTED_COMMAND_LINE_LENGTH = 80;
429
581
  function normalizeFailClosedProcessKind(process2) {
430
582
  switch (process2.kind) {
431
583
  case "OpenCode server":
@@ -448,13 +600,61 @@ function normalizeFailClosedProcessKind(process2) {
448
600
  return "process";
449
601
  }
450
602
  }
603
+ function formatFailClosedProcessStartTime(startTime) {
604
+ if (!Number.isFinite(startTime) || startTime <= 0)
605
+ return "unverified";
606
+ try {
607
+ const parts = new Intl.DateTimeFormat("en-US", {
608
+ day: "numeric",
609
+ hour: "2-digit",
610
+ minute: "2-digit",
611
+ month: "short",
612
+ hour12: false
613
+ }).formatToParts(new Date(startTime));
614
+ const values = Object.fromEntries(parts.map(({ type, value }) => [type, value]));
615
+ if (!values.month || !values.day || !values.hour || !values.minute)
616
+ return "unverified";
617
+ return `${values.month} ${values.day} ${values.hour}:${values.minute}`;
618
+ } catch {
619
+ return "unverified";
620
+ }
621
+ }
622
+ function formatFailClosedCommandLine(commandLine) {
623
+ if (typeof commandLine !== "string" || commandLine.trim().length === 0)
624
+ return "unverified";
625
+ try {
626
+ const normalized = commandLine.replaceAll("\x00", " ").replace(/\s+/g, " ").trim();
627
+ if (normalized.length === 0)
628
+ return "unverified";
629
+ const sanitized = sanitizeDiagnosticText(normalized).trim();
630
+ if (sanitized.length === 0)
631
+ return "unverified";
632
+ return sanitized.length > MAX_FORMATTED_COMMAND_LINE_LENGTH ? `${sanitized.slice(0, MAX_FORMATTED_COMMAND_LINE_LENGTH - 3)}...` : sanitized;
633
+ } catch {
634
+ return "unverified";
635
+ }
636
+ }
451
637
  function formatFailClosedBlockingProcesses(processes) {
452
638
  const uniqueProcesses = new Map;
453
639
  for (const process2 of processes) {
454
640
  if (!Number.isInteger(process2.pid) || process2.pid <= 0)
455
641
  continue;
456
- const kind = normalizeFailClosedProcessKind(process2);
457
- uniqueProcesses.set(`${kind}\x00${process2.pid}`, { kind, pid: process2.pid });
642
+ const candidate = {
643
+ kind: normalizeFailClosedProcessKind(process2),
644
+ pid: process2.pid,
645
+ startTime: process2.startTime,
646
+ commandLine: process2.commandLine
647
+ };
648
+ const previous = uniqueProcesses.get(process2.pid);
649
+ if (!previous || previous.kind === "process" && candidate.kind !== "process") {
650
+ uniqueProcesses.set(process2.pid, candidate);
651
+ } else {
652
+ uniqueProcesses.set(process2.pid, {
653
+ ...previous,
654
+ startTime: previous.startTime ?? candidate.startTime,
655
+ commandLine: previous.commandLine ?? candidate.commandLine
656
+ });
657
+ }
458
658
  }
459
659
  const entries = [...uniqueProcesses.values()];
460
660
  const visible = entries.slice(0, MAX_FORMATTED_BLOCKING_PROCESSES);
@@ -464,10 +664,12 @@ function formatFailClosedBlockingProcesses(processes) {
464
664
  rendered.push(`${omitted} more blocking process(es)`);
465
665
  if (rendered.length === 0)
466
666
  return "a live process";
467
- if (rendered.length === 1)
468
- return rendered[0];
469
- const last = rendered.pop();
470
- return `${rendered.join(", ")}, and ${last}`;
667
+ const summary = rendered.length === 1 ? rendered[0] : `${rendered.slice(0, -1).join(", ")}, and ${rendered.at(-1)}`;
668
+ const evidence = entries.map(({ kind, pid, startTime, commandLine }) => `- PID ${pid}: ${kind}, started ${formatFailClosedProcessStartTime(startTime)}, cmd: ${formatFailClosedCommandLine(commandLine)}`).join(`
669
+ `);
670
+ return `${summary}
671
+ Blocking process evidence:
672
+ ${evidence}`;
471
673
  }
472
674
  function formatFailClosedBlockingMessage(reason) {
473
675
  if (reason.kind === "migration_guard") {
@@ -690,6 +892,17 @@ function readPsProcessStartTime(pid) {
690
892
  return null;
691
893
  }
692
894
  }
895
+ function readProcessStartTime(pid) {
896
+ if (!Number.isInteger(pid) || pid <= 0)
897
+ return null;
898
+ return rpcIdentityPlatform === "linux" ? readLinuxProcessStartTime(pid) : rpcIdentityPlatform === "win32" ? null : readPsProcessStartTime(pid);
899
+ }
900
+ function readProcessProbeEvidence(pid) {
901
+ return {
902
+ startTime: readProcessStartTime(pid),
903
+ commandLine: readProcessCommand(pid)
904
+ };
905
+ }
693
906
  function parseCsvLine(line) {
694
907
  const fields = [];
695
908
  let field = "";
@@ -822,16 +1035,16 @@ function commandLooksLikeOpenCode(command) {
822
1035
  const normalized = command.toLowerCase();
823
1036
  return OPEN_CODE_COMMAND_MARKERS.some((marker) => normalized.includes(marker));
824
1037
  }
825
- function isPidIdentityPlausible(record) {
1038
+ function isPidIdentityPlausible(record, evidence) {
826
1039
  if (!Number.isInteger(record.pid) || record.pid <= 0)
827
1040
  return "implausible";
828
1041
  if (Number.isFinite(record.started_at) && record.started_at > 0) {
829
- const processStartTime = rpcIdentityPlatform === "linux" ? readLinuxProcessStartTime(record.pid) : rpcIdentityPlatform === "win32" ? null : readPsProcessStartTime(record.pid);
1042
+ const processStartTime = evidence ? evidence.startTime : readProcessStartTime(record.pid);
830
1043
  if (processStartTime === null)
831
1044
  return "inconclusive";
832
1045
  return processStartTime <= record.started_at + RPC_IDENTITY_SKEW_TOLERANCE_MS ? "plausible" : "implausible";
833
1046
  }
834
- const command = rpcIdentityPlatform === "linux" ? readLinuxProcessCommand(record.pid) : rpcIdentityPlatform === "win32" ? readWindowsProcess(record.pid).command ?? null : readPsProcessCommand(record.pid);
1047
+ const command = evidence ? evidence.commandLine : rpcIdentityPlatform === "linux" ? readLinuxProcessCommand(record.pid) : rpcIdentityPlatform === "win32" ? readWindowsProcess(record.pid).command ?? null : readPsProcessCommand(record.pid);
835
1048
  if (command === null)
836
1049
  return "inconclusive";
837
1050
  return commandLooksLikeOpenCode(command) ? "plausible" : "implausible";
@@ -2410,7 +2623,7 @@ var CATEGORY_DEFAULT_TTL = {
2410
2623
  import { execFileSync as execFileSync2 } from "node:child_process";
2411
2624
  import { createHash as createHash3 } from "node:crypto";
2412
2625
  import { existsSync, realpathSync, statSync } from "node:fs";
2413
- import { homedir } from "node:os";
2626
+ import { homedir as homedir2 } from "node:os";
2414
2627
  import path from "node:path";
2415
2628
  var GIT_TIMEOUT_MS = 5000;
2416
2629
  var TRANSIENT_FAILURE_COOLDOWN_MS = 5 * 60 * 1000;
@@ -2424,7 +2637,7 @@ var dubiousOwnershipLoggedDirectories = new Set;
2424
2637
  var dubiousOwnershipWarnedDirectories = new Set;
2425
2638
  var transientGitIdentityReuseLoggedDirectories = new Set;
2426
2639
  var execFileSyncForIdentity = execFileSync2;
2427
- var userHomeDirectoryForIdentity = () => homedir();
2640
+ var userHomeDirectoryForIdentity = () => homedir2();
2428
2641
  var nowMs = () => Date.now();
2429
2642
 
2430
2643
  class ProjectIdentityError extends Error {
@@ -5161,6 +5374,37 @@ var MIGRATIONS = [
5161
5374
  ensureColumn(db, "transform_decisions", "m0_model_key_prev", "TEXT");
5162
5375
  ensureColumn(db, "transform_decisions", "m0_model_key_new", "TEXT");
5163
5376
  }
5377
+ },
5378
+ {
5379
+ version: 80,
5380
+ description: "record observed m[0] tool-set hash comparisons",
5381
+ up(db) {
5382
+ if (!tableExists2(db, "transform_decisions"))
5383
+ return;
5384
+ ensureColumn(db, "transform_decisions", "m0_tool_set_hash_prev", "TEXT");
5385
+ ensureColumn(db, "transform_decisions", "m0_tool_set_hash_new", "TEXT");
5386
+ }
5387
+ },
5388
+ {
5389
+ version: 81,
5390
+ description: "persist last-known-good transform snapshots across restarts",
5391
+ up(db) {
5392
+ db.exec(`
5393
+ CREATE TABLE IF NOT EXISTS lkg_slots (
5394
+ session_id TEXT PRIMARY KEY,
5395
+ json_prefix TEXT NOT NULL,
5396
+ input_id_seq TEXT NOT NULL,
5397
+ input_content_digests TEXT NOT NULL,
5398
+ input_content_signatures TEXT,
5399
+ last_input_message_id TEXT NOT NULL,
5400
+ model_key TEXT,
5401
+ provider_key TEXT,
5402
+ captured_at INTEGER NOT NULL,
5403
+ row_version INTEGER,
5404
+ capture_sequence INTEGER
5405
+ );
5406
+ `);
5407
+ }
5164
5408
  }
5165
5409
  ];
5166
5410
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -5280,7 +5524,7 @@ import { createHash as createHash5 } from "node:crypto";
5280
5524
  // src/hooks/magic-context/read-session-formatting.ts
5281
5525
  import { existsSync as existsSync2, readFileSync as readFileSync2, realpathSync as realpathSync2 } from "node:fs";
5282
5526
  import { createRequire } from "node:module";
5283
- import { homedir as homedir2 } from "node:os";
5527
+ import { homedir as homedir3 } from "node:os";
5284
5528
  import { dirname, join as join2, resolve } from "node:path";
5285
5529
  import { pathToFileURL } from "node:url";
5286
5530
 
@@ -5397,7 +5641,7 @@ var tokenizerLoadPromise;
5397
5641
  var tokenizerWarningSent = false;
5398
5642
  function tokenizerPackageRoots() {
5399
5643
  const cwd = process.cwd();
5400
- const openCodeCache = join2(process.env.XDG_CACHE_HOME ?? join2(homedir2(), ".cache"), "opencode");
5644
+ const openCodeCache = join2(process.env.XDG_CACHE_HOME ?? join2(homedir3(), ".cache"), "opencode");
5401
5645
  const roots = [cwd, openCodeCache];
5402
5646
  const candidates = [];
5403
5647
  for (const root of roots) {
@@ -5616,6 +5860,14 @@ function keyFor(providerID, modelID, agentName) {
5616
5860
  function fingerprintFor(description, parameters) {
5617
5861
  return createHash5("sha256").update(description).update("\x00").update(stableStringify(parameters)).digest("hex");
5618
5862
  }
5863
+ function getCurrentToolSetHash(providerID, modelID, agentName) {
5864
+ if (!providerID || !modelID)
5865
+ return "";
5866
+ const toolIds = measurements.get(keyFor(providerID, modelID, agentName));
5867
+ if (!toolIds || toolIds.size === 0)
5868
+ return "";
5869
+ return createHash5("sha256").update(Array.from(toolIds.keys()).sort().join("\x00")).digest("hex");
5870
+ }
5619
5871
  function setDatabase(db) {
5620
5872
  persistenceDb = db;
5621
5873
  cachedInsertStmt = null;
@@ -5957,7 +6209,7 @@ function getSchemaFenceRejection() {
5957
6209
  function getMigrationOnOpenRefusal() {
5958
6210
  return lastMigrationOnOpenRefusal;
5959
6211
  }
5960
- var LATEST_SUPPORTED_VERSION = 79;
6212
+ var LATEST_SUPPORTED_VERSION = 81;
5961
6213
  var PERMISSIONS_ENFORCEABLE = process.platform !== "win32";
5962
6214
  var defaultStoragePermissionFs = { chmodSync, mkdirSync };
5963
6215
  var storagePermissionFs = defaultStoragePermissionFs;
@@ -6123,8 +6375,8 @@ function classifyDiscoveryRecordKind(record) {
6123
6375
  }
6124
6376
  return null;
6125
6377
  }
6126
- function classifyRpcProcess(record) {
6127
- return classifyDiscoveryRecordKind(record) ?? classifyProcessKind(readProcessCommand(record.pid));
6378
+ function classifyRpcProcess(record, commandLine) {
6379
+ return classifyDiscoveryRecordKind(record) ?? classifyProcessKind(commandLine === undefined ? readProcessProbeEvidence(record.pid).commandLine : commandLine);
6128
6380
  }
6129
6381
  function classifyJunkDiscovery(portFile, raw, staleFiles) {
6130
6382
  let mtimeMs;
@@ -6201,18 +6453,23 @@ function inspectRpcServerDiscovery(storageDir) {
6201
6453
  continue;
6202
6454
  }
6203
6455
  const liveness = isPidAlive(record.pid);
6204
- const identity = liveness === "dead" ? "implausible" : isPidIdentityPlausible(record);
6205
- if (liveness === "alive" && identity === "plausible") {
6456
+ if (liveness === "dead") {
6457
+ staleFiles.push(portFile);
6458
+ continue;
6459
+ }
6460
+ const evidence = readProcessProbeEvidence(record.pid);
6461
+ const identity = isPidIdentityPlausible(record, evidence);
6462
+ if (identity === "plausible") {
6206
6463
  pids.add(record.pid);
6207
- const detected = {
6208
- kind: classifyRpcProcess(record),
6464
+ const detected = attachFailClosedBlockingProcessEvidence({
6465
+ kind: classifyRpcProcess(record, evidence.commandLine),
6209
6466
  pid: record.pid
6210
- };
6467
+ }, evidence);
6211
6468
  const previous = processByPid.get(record.pid);
6212
6469
  if (!previous || previous.kind === "process" && detected.kind !== "process") {
6213
6470
  processByPid.set(record.pid, detected);
6214
6471
  }
6215
- } else if (liveness === "dead" || identity === "implausible") {
6472
+ } else if (identity === "implausible") {
6216
6473
  staleFiles.push(portFile);
6217
6474
  } else {
6218
6475
  inconclusivePids.add(record.pid);
@@ -6245,6 +6502,9 @@ function inspectRpcServerDiscovery(storageDir) {
6245
6502
  }
6246
6503
  return { state: "stale", serverPids: [], staleFiles };
6247
6504
  }
6505
+ function createPiBlockingProcess(pid) {
6506
+ return attachFailClosedBlockingProcessEvidence({ kind: "Pi", pid }, readProcessProbeEvidence(pid));
6507
+ }
6248
6508
  function formatInconclusiveOpenCodeMigrationWarning(dbPath, pids) {
6249
6509
  return `[magic-context] storage warning: continuing migration for ${dbPath}; OpenCode server PID ${pids.join(", ")} was not confirmed because its liveness or identity check could not run. This commonly means an OS sandbox denied kill(0) or ps. No live OpenCode server was confirmed.`;
6250
6510
  }
@@ -6286,10 +6546,7 @@ function enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion)
6286
6546
  const piDiscovery = inspectLivePiProcesses();
6287
6547
  const piPids = migrationBlockingPiPids(dbPath, discovery, piDiscovery.processIds);
6288
6548
  const serverProcesses = discovery.serverProcesses ?? (discovery.state === "live" ? discovery.serverPids.map((pid) => ({ kind: "process", pid })) : []);
6289
- const blockingProcesses = [
6290
- ...serverProcesses,
6291
- ...piPids.map((pid) => ({ kind: "Pi", pid }))
6292
- ];
6549
+ const blockingProcesses = [...serverProcesses, ...piPids.map(createPiBlockingProcess)];
6293
6550
  if ((discovery.state === "absent" || discovery.state === "stale" || discovery.state === "inconclusive") && piPids.length === 0) {
6294
6551
  lastMigrationOnOpenRefusal = null;
6295
6552
  logInconclusiveMigrationProbes(dbPath, discovery, piDiscovery.state);
@@ -7109,10 +7366,12 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
7109
7366
  decision TEXT NOT NULL,
7110
7367
  materialized INTEGER NOT NULL DEFAULT 0,
7111
7368
  materialize_reason TEXT,
7112
- system_hash_prev TEXT,
7113
- system_hash_new TEXT,
7114
- m0_model_key_prev TEXT,
7115
- m0_model_key_new TEXT,
7369
+ system_hash_prev TEXT,
7370
+ system_hash_new TEXT,
7371
+ m0_tool_set_hash_prev TEXT,
7372
+ m0_tool_set_hash_new TEXT,
7373
+ m0_model_key_prev TEXT,
7374
+ m0_model_key_new TEXT,
7116
7375
  emergency INTEGER NOT NULL DEFAULT 0,
7117
7376
  dropped_tokens INTEGER NOT NULL DEFAULT 0,
7118
7377
  dropped_count INTEGER NOT NULL DEFAULT 0,
@@ -7450,10 +7709,12 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
7450
7709
  decision TEXT NOT NULL,
7451
7710
  materialized INTEGER NOT NULL DEFAULT 0,
7452
7711
  materialize_reason TEXT,
7453
- system_hash_prev TEXT,
7454
- system_hash_new TEXT,
7455
- m0_model_key_prev TEXT,
7456
- m0_model_key_new TEXT,
7712
+ system_hash_prev TEXT,
7713
+ system_hash_new TEXT,
7714
+ m0_tool_set_hash_prev TEXT,
7715
+ m0_tool_set_hash_new TEXT,
7716
+ m0_model_key_prev TEXT,
7717
+ m0_model_key_new TEXT,
7457
7718
  emergency INTEGER NOT NULL DEFAULT 0,
7458
7719
  dropped_tokens INTEGER NOT NULL DEFAULT 0,
7459
7720
  dropped_count INTEGER NOT NULL DEFAULT 0,
@@ -10680,6 +10941,7 @@ function clearEmergencyDropSample(db, sessionId) {
10680
10941
  db.prepare("UPDATE session_meta SET last_emergency_input_sample = 0 WHERE session_id = ?").run(sessionId);
10681
10942
  })();
10682
10943
  }
10944
+ var EMPTY_CHANNEL1_NUDGE_STATE = { level: "", ordinal: 0 };
10683
10945
  function isLastNudgeUndroppedRow(row) {
10684
10946
  return typeof row === "object" && row !== null && typeof row.last_nudge_undropped === "number";
10685
10947
  }
@@ -10689,6 +10951,24 @@ function isLastNudgeLevelRow(row) {
10689
10951
  function normalizeLastNudgeLevel(value) {
10690
10952
  return value === "gentle" || value === "firm" || value === "urgent" ? value : "";
10691
10953
  }
10954
+ function parseChannel1NudgeState(raw) {
10955
+ try {
10956
+ const parsed = JSON.parse(raw);
10957
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
10958
+ return {
10959
+ level: normalizeLastNudgeLevel(parsed.level),
10960
+ ordinal: typeof parsed.ordinal === "number" ? Math.max(0, Math.round(parsed.ordinal)) : 0
10961
+ };
10962
+ }
10963
+ } catch {}
10964
+ return { level: normalizeLastNudgeLevel(raw), ordinal: 0 };
10965
+ }
10966
+ function serializeChannel1NudgeState(value) {
10967
+ return JSON.stringify({
10968
+ level: normalizeLastNudgeLevel(value.level),
10969
+ ordinal: Math.max(0, Math.round(value.ordinal))
10970
+ });
10971
+ }
10692
10972
  function getLastNudgeUndropped(db, sessionId) {
10693
10973
  const result = db.prepare("SELECT last_nudge_undropped FROM session_meta WHERE session_id = ?").get(sessionId);
10694
10974
  return isLastNudgeUndroppedRow(result) ? result.last_nudge_undropped : 0;
@@ -10699,27 +10979,27 @@ function setLastNudgeUndropped(db, sessionId, value) {
10699
10979
  db.prepare("UPDATE session_meta SET last_nudge_undropped = ? WHERE session_id = ?").run(Math.max(0, Math.round(value)), sessionId);
10700
10980
  })();
10701
10981
  }
10702
- function getLastNudgeLevel(db, sessionId) {
10982
+ function getChannel1NudgeState(db, sessionId) {
10703
10983
  const result = db.prepare("SELECT last_nudge_level FROM session_meta WHERE session_id = ?").get(sessionId);
10704
- return isLastNudgeLevelRow(result) ? normalizeLastNudgeLevel(result.last_nudge_level) : "";
10984
+ return isLastNudgeLevelRow(result) ? parseChannel1NudgeState(result.last_nudge_level) : EMPTY_CHANNEL1_NUDGE_STATE;
10705
10985
  }
10706
- function setLastNudgeLevel(db, sessionId, value) {
10986
+ function setChannel1NudgeState(db, sessionId, value) {
10707
10987
  db.transaction(() => {
10708
10988
  ensureSessionMetaRow(db, sessionId);
10709
- db.prepare("UPDATE session_meta SET last_nudge_level = ? WHERE session_id = ?").run(normalizeLastNudgeLevel(value), sessionId);
10989
+ db.prepare("UPDATE session_meta SET last_nudge_level = ? WHERE session_id = ?").run(serializeChannel1NudgeState(value), sessionId);
10710
10990
  })();
10711
10991
  }
10712
10992
  function resetLastNudgeCycle(db, sessionId) {
10713
10993
  db.transaction(() => {
10714
10994
  ensureSessionMetaRow(db, sessionId);
10715
- db.prepare("UPDATE session_meta SET last_nudge_undropped = 0, last_nudge_level = '' WHERE session_id = ?").run(sessionId);
10995
+ db.prepare("UPDATE session_meta SET last_nudge_undropped = 0, last_nudge_level = ? WHERE session_id = ?").run(serializeChannel1NudgeState(EMPTY_CHANNEL1_NUDGE_STATE), sessionId);
10716
10996
  })();
10717
10997
  }
10718
10998
  function resetLastNudgeCycleIfTailShrank(db, sessionId, measuredUndropped) {
10719
10999
  let changed = false;
10720
11000
  db.transaction(() => {
10721
11001
  ensureSessionMetaRow(db, sessionId);
10722
- const result = db.prepare("UPDATE session_meta SET last_nudge_undropped = 0, last_nudge_level = '' WHERE session_id = ? AND last_nudge_undropped > ?").run(sessionId, Math.max(0, Math.round(measuredUndropped)));
11002
+ const result = db.prepare("UPDATE session_meta SET last_nudge_undropped = 0, last_nudge_level = ? WHERE session_id = ? AND last_nudge_undropped > ?").run(serializeChannel1NudgeState(EMPTY_CHANNEL1_NUDGE_STATE), sessionId, Math.max(0, Math.round(measuredUndropped)));
10723
11003
  changed = (result.changes ?? 0) > 0;
10724
11004
  })();
10725
11005
  return changed;
@@ -12417,12 +12697,27 @@ function collectToolPartIdentities(messages) {
12417
12697
  }
12418
12698
  return identities;
12419
12699
  }
12700
+ function isMachineGeneratedUserPart(part) {
12701
+ if (!isRecord(part))
12702
+ return false;
12703
+ const metadata = isRecord(part.metadata) ? part.metadata : null;
12704
+ const marker = metadata && isRecord(metadata.marker) ? metadata.marker : null;
12705
+ return part.synthetic === true || part.ignored === true || marker?.kind != null || isSyntheticTodoPart(part);
12706
+ }
12420
12707
  function isSyntheticMessage(message) {
12421
- const structuralHead = message.info.id === undefined && message.info.role === "user" && message.parts.length > 0 && message.parts.every((part) => isRecord(part) && part.synthetic === true);
12422
- return structuralHead || message.info.summary === true || message.info.id === TODO_HEAD_ANCHOR_ID;
12708
+ const syntheticUserRow = message.info.role === "user" && message.parts.length > 0 && message.parts.every(isMachineGeneratedUserPart);
12709
+ return syntheticUserRow || message.info.summary === true || message.info.id === TODO_HEAD_ANCHOR_ID;
12710
+ }
12711
+ function countRealUserMessages(messages) {
12712
+ let count = 0;
12713
+ for (const message of messages) {
12714
+ if (message.info.role === "user" && !isSyntheticMessage(message))
12715
+ count += 1;
12716
+ }
12717
+ return count;
12423
12718
  }
12424
12719
  function isSyntheticPart(part) {
12425
- return isRecord(part) && part.synthetic === true || isSyntheticTodoPart(part);
12720
+ return isMachineGeneratedUserPart(part);
12426
12721
  }
12427
12722
  function stripChannel1ReminderSpans(output) {
12428
12723
  let stripped = output;
@@ -12583,7 +12878,8 @@ function snapshot(args) {
12583
12878
  const memo = memoizedContent(args.kind, args.content);
12584
12879
  const tag = args.tag;
12585
12880
  const isProtected = tag ? args.protectedNumbers.has(tag.tagNumber) : false;
12586
- const uTokens = tag?.status === "active" && !isProtected && args.kind !== "excluded" ? args.tokens : 0;
12881
+ const queuedForDrop = tag ? args.pendingDropTagNumbers.has(tag.tagNumber) : false;
12882
+ const uTokens = tag?.status === "active" && !isProtected && !queuedForDrop && args.kind !== "excluded" ? args.tokens : 0;
12587
12883
  return {
12588
12884
  key: args.key,
12589
12885
  contentHash: memo.hash,
@@ -12592,7 +12888,8 @@ function snapshot(args) {
12592
12888
  uTokens,
12593
12889
  tagNumber: tag?.tagNumber ?? null,
12594
12890
  tagStatus: tag?.status ?? null,
12595
- protected: isProtected
12891
+ protected: isProtected,
12892
+ queuedForDrop
12596
12893
  };
12597
12894
  }
12598
12895
  function excludedSnapshot(key, part) {
@@ -12603,7 +12900,8 @@ function excludedSnapshot(key, part) {
12603
12900
  content,
12604
12901
  tokens: 0,
12605
12902
  tag: undefined,
12606
- protectedNumbers: new Set
12903
+ protectedNumbers: new Set,
12904
+ pendingDropTagNumbers: new Set
12607
12905
  });
12608
12906
  }
12609
12907
  function fileContentAndTokens(part) {
@@ -12639,6 +12937,7 @@ function sameTailHygieneStructuralSignature(expected, actual) {
12639
12937
  return expected.partCounts.every((count, index) => count === actual.partCounts[index]);
12640
12938
  }
12641
12939
  function measureTailHygiene(input) {
12940
+ const pendingDropTagNumbers = input.pendingDropTagNumbers ?? new Set;
12642
12941
  const toolIdentities = collectToolPartIdentities(input.messages);
12643
12942
  const attribution = buildTagAttribution({
12644
12943
  messages: input.messages,
@@ -12688,7 +12987,8 @@ function measureTailHygiene(input) {
12688
12987
  content,
12689
12988
  tokens: memo.tokens,
12690
12989
  tag,
12691
- protectedNumbers: attribution.protectedNumbers
12990
+ protectedNumbers: attribution.protectedNumbers,
12991
+ pendingDropTagNumbers
12692
12992
  });
12693
12993
  parts.push(measured);
12694
12994
  t += measured.tokens;
@@ -12708,7 +13008,8 @@ function measureTailHygiene(input) {
12708
13008
  content: file.content,
12709
13009
  tokens: file.tokens,
12710
13010
  tag,
12711
- protectedNumbers: attribution.protectedNumbers
13011
+ protectedNumbers: attribution.protectedNumbers,
13012
+ pendingDropTagNumbers
12712
13013
  });
12713
13014
  parts.push(measured);
12714
13015
  t += measured.tokens;
@@ -12732,7 +13033,8 @@ function measureTailHygiene(input) {
12732
13033
  content: inputText,
12733
13034
  tokens: memo.tokens,
12734
13035
  tag,
12735
- protectedNumbers: attribution.protectedNumbers
13036
+ protectedNumbers: attribution.protectedNumbers,
13037
+ pendingDropTagNumbers
12736
13038
  });
12737
13039
  parts.push(measured);
12738
13040
  t += measured.tokens;
@@ -12751,7 +13053,8 @@ function measureTailHygiene(input) {
12751
13053
  content: output,
12752
13054
  tokens: memo.tokens,
12753
13055
  tag,
12754
- protectedNumbers: attribution.protectedNumbers
13056
+ protectedNumbers: attribution.protectedNumbers,
13057
+ pendingDropTagNumbers
12755
13058
  });
12756
13059
  parts.push(measured);
12757
13060
  t += measured.tokens;
@@ -12774,26 +13077,35 @@ function measureTailHygiene(input) {
12774
13077
  };
12775
13078
  }
12776
13079
  function sameMeasuredPrefix(baseline, current) {
12777
- if (current.length < baseline.length)
12778
- return { valid: false, boundaryAdvanceU: 0 };
13080
+ if (current.length < baseline.length) {
13081
+ return { valid: false, boundaryAdvanceU: 0, queuedDropDeltaU: 0 };
13082
+ }
12779
13083
  let boundaryAdvanceU = 0;
13084
+ let queuedDropDeltaU = 0;
12780
13085
  for (let index = 0;index < baseline.length; index += 1) {
12781
13086
  const before = baseline[index];
12782
13087
  const after = current[index];
12783
13088
  if (before.key !== after.key || before.contentHash !== after.contentHash || before.kind !== after.kind || before.tokens !== after.tokens || before.tagNumber !== after.tagNumber || before.tagStatus !== after.tagStatus) {
12784
- return { valid: false, boundaryAdvanceU: 0 };
13089
+ return { valid: false, boundaryAdvanceU: 0, queuedDropDeltaU: 0 };
13090
+ }
13091
+ if (!before.protected && after.protected) {
13092
+ return { valid: false, boundaryAdvanceU: 0, queuedDropDeltaU: 0 };
12785
13093
  }
12786
- if (!before.protected && after.protected)
12787
- return { valid: false, boundaryAdvanceU: 0 };
12788
13094
  if (before.protected && !after.protected) {
12789
- if (after.tagStatus !== "active")
12790
- return { valid: false, boundaryAdvanceU: 0 };
12791
- boundaryAdvanceU += after.tokens;
13095
+ if (after.tagStatus !== "active") {
13096
+ return { valid: false, boundaryAdvanceU: 0, queuedDropDeltaU: 0 };
13097
+ }
13098
+ boundaryAdvanceU += after.uTokens;
13099
+ } else if (before.queuedForDrop !== after.queuedForDrop) {
13100
+ if (before.tagStatus !== "active" || after.tagStatus !== "active") {
13101
+ return { valid: false, boundaryAdvanceU: 0, queuedDropDeltaU: 0 };
13102
+ }
13103
+ queuedDropDeltaU += after.uTokens - before.uTokens;
12792
13104
  } else if (before.uTokens !== after.uTokens) {
12793
- return { valid: false, boundaryAdvanceU: 0 };
13105
+ return { valid: false, boundaryAdvanceU: 0, queuedDropDeltaU: 0 };
12794
13106
  }
12795
13107
  }
12796
- return { valid: true, boundaryAdvanceU };
13108
+ return { valid: true, boundaryAdvanceU, queuedDropDeltaU };
12797
13109
  }
12798
13110
  function refreshTailHygieneBaseline(input) {
12799
13111
  const measured = measureTailHygiene(input);
@@ -12825,7 +13137,7 @@ function refreshTailHygieneBaseline(input) {
12825
13137
  };
12826
13138
  }
12827
13139
  let turnDeltaT = 0;
12828
- let turnDeltaU = prefix.boundaryAdvanceU;
13140
+ let turnDeltaU = prefix.boundaryAdvanceU + prefix.queuedDropDeltaU;
12829
13141
  for (let index = input.previous.baselineParts.length;index < measured.parts.length; index += 1) {
12830
13142
  const part = measured.parts[index];
12831
13143
  turnDeltaT += part.tokens;
@@ -12951,26 +13263,44 @@ function formatOldestReclaimableHint(hint) {
12951
13263
  return rendered.length > 0 ? `
12952
13264
  oldest reclaimable: ${rendered}.` : "";
12953
13265
  }
12954
- function buildChannel2Reminder(undroppedTokens, hint) {
13266
+ function buildChannel2Reminder(undroppedTokens, usableWindowTokens, hint) {
12955
13267
  const amount = approxThousands(undroppedTokens);
13268
+ const usableWindow = approxThousands(usableWindowTokens);
12956
13269
  const hintText = formatOldestReclaimableHint(hint);
12957
13270
  return `<system-reminder>
12958
- ` + `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}
13271
+ ` + `Routine housekeeping: an older span of this session folds into compact history automatically — nothing is lost and nothing pauses. ` + `Drop spent tool outputs with ctx_reduce first so the archive keeps only what matters (~${amount} of ~${usableWindow} reclaimable).${hintText}
12959
13272
  ` + `</system-reminder>`;
12960
13273
  }
12961
- function buildChannel1Reminder(level, undroppedTokens, hint) {
12962
- const amount = approxThousands(undroppedTokens);
13274
+ var CHANNEL1_STICKY_REAL_USER_TURN_GAP = 3;
13275
+ function shouldUseStickyChannel1Reminder(input) {
13276
+ if (input.lastLevel !== input.level)
13277
+ return false;
13278
+ if (input.lastOrdinal > input.currentRealUserTurnCount)
13279
+ return false;
13280
+ const gap = input.currentRealUserTurnCount - input.lastOrdinal;
13281
+ return gap >= 0 && gap < CHANNEL1_STICKY_REAL_USER_TURN_GAP;
13282
+ }
13283
+ function buildChannel1Reminder(level, undroppedTokens, usableWindowTokens, hint, sticky = false) {
12963
13284
  const hintText = formatOldestReclaimableHint(hint);
13285
+ if (sticky) {
13286
+ return `
13287
+
13288
+ <system-reminder>
13289
+ Reminder: ctx_reduce housekeeping still pending —${hintText}
13290
+ </system-reminder>`;
13291
+ }
13292
+ const amount = approxThousands(undroppedTokens);
13293
+ const usableWindow = approxThousands(usableWindowTokens);
12964
13294
  let body;
12965
13295
  switch (level) {
12966
13296
  case "gentle":
12967
- body = `You have ~${amount} tokens of content you have not reduced. ` + `When you are done with earlier outputs, dropping them with ctx_reduce keeps context lean.`;
13297
+ body = `Housekeeping: some earlier tool outputs are spent and can be dropped with ctx_reduce when you are done with them. ` + `Context is managed automatically — this is tidiness, never a reason to rush or narrow scope.`;
12968
13298
  break;
12969
13299
  case "firm":
12970
- body = `~${amount} tokens of unreduced content has built up. ` + `At your next natural stopping point, consider dropping what you have already processed with ctx_reduce.`;
13300
+ body = `Housekeeping: ~${amount} of this session's ~${usableWindow} window is spent tool output. ` + `Drop what you have already processed with ctx_reduce at a natural stopping point. ` + `Not a limit — nothing is lost either way.`;
12971
13301
  break;
12972
13302
  case "urgent":
12973
- body = `~${amount} tokens of unreduced content remain across most of the live tail. ` + `Consider dropping spent outputs with ctx_reduce so the archived span is the part that matters.`;
13303
+ body = `Housekeeping backlog: ~${amount} of this session's ~${usableWindow} window is spent tool output — worth a ctx_reduce pass now. ` + `This is routine and lossless; it is never a reason to change scope.`;
12974
13304
  break;
12975
13305
  }
12976
13306
  return `
@@ -13181,8 +13511,14 @@ function getOldestActiveUnprotectedToolTags(db, sessionId, protectedTags = 0, li
13181
13511
  const params = protectedTags > 0 ? [sessionId, AGE_RECLAIM_MIN_TOKENS, sessionId, protectedTags - 1] : [sessionId, AGE_RECLAIM_MIN_TOKENS];
13182
13512
  const rows = db.prepare(`SELECT tag_number, tool_name
13183
13513
  FROM tags
13184
- WHERE session_id = ? AND status = 'active' AND type = 'tool'
13185
- ${valueFloor}
13514
+ WHERE session_id = ? AND status = 'active' AND type = 'tool'
13515
+ AND NOT EXISTS (
13516
+ SELECT 1 FROM pending_ops
13517
+ WHERE pending_ops.session_id = tags.session_id
13518
+ AND pending_ops.tag_id = tags.tag_number
13519
+ AND pending_ops.operation = 'drop'
13520
+ )
13521
+ ${valueFloor}
13186
13522
  ${whereProtected}
13187
13523
  ORDER BY tag_number ASC, id ASC`).all(...params);
13188
13524
  return rows.filter((row) => typeof row.tag_number === "number").map((row) => ({
@@ -13821,6 +14157,59 @@ function parseReportedLimit(message) {
13821
14157
  return;
13822
14158
  }
13823
14159
 
14160
+ // src/shared/resolve-fallbacks.ts
14161
+ function resolveFallbackChain(userFallbacks) {
14162
+ const userList = normalizeUserFallbacks(userFallbacks);
14163
+ return dedupe(userList.filter(isValidModelSpec));
14164
+ }
14165
+ function normalizeUserFallbacks(userFallbacks) {
14166
+ if (!userFallbacks)
14167
+ return [];
14168
+ if (typeof userFallbacks === "string") {
14169
+ const trimmed = userFallbacks.trim();
14170
+ return trimmed ? [trimmed] : [];
14171
+ }
14172
+ return userFallbacks.map((s) => s.trim()).filter((s) => s.length > 0);
14173
+ }
14174
+ function isValidModelSpec(spec) {
14175
+ const slash = spec.indexOf("/");
14176
+ return slash > 0 && slash < spec.length - 1;
14177
+ }
14178
+ function dedupe(list) {
14179
+ const seen = new Set;
14180
+ const out = [];
14181
+ for (const item of list) {
14182
+ if (seen.has(item))
14183
+ continue;
14184
+ seen.add(item);
14185
+ out.push(item);
14186
+ }
14187
+ return out;
14188
+ }
14189
+ function parseProviderModel(spec) {
14190
+ const slash = spec.indexOf("/");
14191
+ if (slash < 1 || slash >= spec.length - 1)
14192
+ return null;
14193
+ return {
14194
+ providerID: spec.slice(0, slash).trim(),
14195
+ modelID: spec.slice(slash + 1).trim()
14196
+ };
14197
+ }
14198
+ function modelBodyField(spec) {
14199
+ const entry = toModelEntry(spec);
14200
+ if (!entry)
14201
+ return {};
14202
+ const parsed = parseProviderModel(entry.model);
14203
+ return parsed ? { model: parsed, ...entry.qualifier ? { variant: entry.qualifier } : {} } : {};
14204
+ }
14205
+ function toModelEntry(spec) {
14206
+ if (typeof spec === "string") {
14207
+ const model = spec.trim();
14208
+ return model ? { model } : undefined;
14209
+ }
14210
+ return spec;
14211
+ }
14212
+
13824
14213
  // src/shared/model-suggestion-retry.ts
13825
14214
  var ABORT_CALL_TIMEOUT_MS = 3000;
13826
14215
  function copyPromptArgs(args, body) {
@@ -13985,15 +14374,18 @@ async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
13985
14374
  log(`[${callContext}] primary (${explicitPrimaryLabel}) failed: ${shortErr(error)}; trying ${fallbacks.length} fallback(s)`);
13986
14375
  }
13987
14376
  for (let i = 0;i < fallbacks.length; i += 1) {
13988
- const parsed = parseProviderModel(fallbacks[i]);
14377
+ const fallback = toModelEntry(fallbacks[i]);
14378
+ const parsed = fallback ? parseProviderModel(fallback.model) : null;
13989
14379
  if (!parsed) {
13990
- log(`[${callContext}] skipping invalid fallback spec: ${fallbacks[i]}`);
14380
+ log(`[${callContext}] skipping invalid fallback spec: ${String(fallbacks[i])}`);
13991
14381
  continue;
13992
14382
  }
13993
14383
  const label = `${parsed.providerID}/${parsed.modelID}`;
14384
+ const { variant: _primaryVariant, ...bodyWithoutPrimaryVariant } = baseBody;
13994
14385
  const attemptArgs = copyPromptArgs(baseArgs, {
13995
- ...baseBody,
13996
- model: parsed
14386
+ ...bodyWithoutPrimaryVariant,
14387
+ model: parsed,
14388
+ ...fallback?.qualifier ? { variant: fallback.qualifier } : {}
13997
14389
  });
13998
14390
  try {
13999
14391
  await attemptOnce(client, attemptArgs, timeoutMs, options.signal, callContext, label);
@@ -14009,7 +14401,7 @@ async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
14009
14401
  }
14010
14402
  }
14011
14403
  }
14012
- log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks].join(", ")}; last error: ${shortErr(lastError)}`);
14404
+ log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks.map((fallback) => toModelEntry(fallback)?.model ?? String(fallback))].join(", ")}; last error: ${shortErr(lastError)}`);
14013
14405
  throw lastError ?? new Error("All fallback models failed");
14014
14406
  }
14015
14407
  async function attemptAndValidate(client, args, timeoutMs, signal, callContext, attempt, options) {
@@ -14047,15 +14439,18 @@ async function promptSyncWithValidatedOutputRetry(client, args, options) {
14047
14439
  log(`[${callContext}] primary (${explicitPrimaryLabel}) failed validation/prompt: ${shortErr(error)}; trying ${fallbacks.length} fallback(s)`);
14048
14440
  }
14049
14441
  for (let i = 0;i < fallbacks.length; i += 1) {
14050
- const parsed = parseProviderModel(fallbacks[i]);
14442
+ const fallback = toModelEntry(fallbacks[i]);
14443
+ const parsed = fallback ? parseProviderModel(fallback.model) : null;
14051
14444
  if (!parsed) {
14052
- log(`[${callContext}] skipping invalid fallback spec: ${fallbacks[i]}`);
14445
+ log(`[${callContext}] skipping invalid fallback spec: ${String(fallbacks[i])}`);
14053
14446
  continue;
14054
14447
  }
14055
14448
  const label = `${parsed.providerID}/${parsed.modelID}`;
14449
+ const { variant: _primaryVariant, ...bodyWithoutPrimaryVariant } = baseBody;
14056
14450
  const attemptArgs = copyPromptArgs(baseArgs, {
14057
- ...baseBody,
14058
- model: parsed
14451
+ ...bodyWithoutPrimaryVariant,
14452
+ model: parsed,
14453
+ ...fallback?.qualifier ? { variant: fallback.qualifier } : {}
14059
14454
  });
14060
14455
  const attempt = {
14061
14456
  label,
@@ -14080,7 +14475,7 @@ async function promptSyncWithValidatedOutputRetry(client, args, options) {
14080
14475
  }
14081
14476
  }
14082
14477
  }
14083
- log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks].join(", ")}; original error: ${shortErr(firstError)}; last error: ${shortErr(lastError)}`);
14478
+ log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks.map((fallback) => toModelEntry(fallback)?.model ?? String(fallback))].join(", ")}; original error: ${shortErr(firstError)}; last error: ${shortErr(lastError)}`);
14084
14479
  throw firstError ?? lastError ?? new Error("All fallback models failed validation");
14085
14480
  }
14086
14481
  // src/shared/normalize-sdk-response.ts
@@ -14206,15 +14601,15 @@ import {
14206
14601
  unlinkSync as unlinkSync2,
14207
14602
  writeFileSync
14208
14603
  } from "node:fs";
14209
- import { homedir as homedir3 } from "node:os";
14604
+ import { homedir as homedir4 } from "node:os";
14210
14605
  import { basename as basename2, dirname as dirname3, isAbsolute, join as join5 } from "node:path";
14211
14606
  var CONFIG_FILE_BASENAME = "magic-context";
14212
14607
  var MOVED_MARKER_SUFFIX = ".MOVED_READPLEASE";
14213
14608
  function homeDir() {
14214
14609
  if (process.platform === "win32") {
14215
- return process.env.USERPROFILE || process.env.HOME || homedir3();
14610
+ return process.env.USERPROFILE || process.env.HOME || homedir4();
14216
14611
  }
14217
- return process.env.HOME || homedir3();
14612
+ return process.env.HOME || homedir4();
14218
14613
  }
14219
14614
  function configHome() {
14220
14615
  const xdg = process.env.XDG_CONFIG_HOME;
@@ -16753,7 +17148,7 @@ function countSessionCompartmentEmbedCoverage(db, projectPath, sessionId, modelI
16753
17148
  import { createHash as createHash14, randomUUID as randomUUID2 } from "node:crypto";
16754
17149
 
16755
17150
  // src/config/schema/magic-context.ts
16756
- import { homedir as homedir4 } from "node:os";
17151
+ import { homedir as homedir5 } from "node:os";
16757
17152
 
16758
17153
  // ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/external.js
16759
17154
  var exports_external = {};
@@ -17380,7 +17775,7 @@ __export(exports_util, {
17380
17775
  createTransparentProxy: () => createTransparentProxy,
17381
17776
  defineLazy: () => defineLazy,
17382
17777
  esc: () => esc,
17383
- escapeRegex: () => escapeRegex,
17778
+ escapeRegex: () => escapeRegex2,
17384
17779
  explicitlyAborted: () => explicitlyAborted,
17385
17780
  extend: () => extend,
17386
17781
  finalizeIssue: () => finalizeIssue,
@@ -17657,7 +18052,7 @@ var primitiveTypes = /* @__PURE__ */ new Set([
17657
18052
  "symbol",
17658
18053
  "undefined"
17659
18054
  ]);
17660
- function escapeRegex(str) {
18055
+ function escapeRegex2(str) {
17661
18056
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17662
18057
  }
17663
18058
  function clone(inst, def, params) {
@@ -18367,7 +18762,7 @@ function emoji() {
18367
18762
  var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
18368
18763
  var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
18369
18764
  var mac = (delimiter) => {
18370
- const escapedDelim = escapeRegex(delimiter ?? ":");
18765
+ const escapedDelim = escapeRegex2(delimiter ?? ":");
18371
18766
  return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
18372
18767
  };
18373
18768
  var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
@@ -18868,7 +19263,7 @@ var $ZodCheckUpperCase = /* @__PURE__ */ $constructor("$ZodCheckUpperCase", (ins
18868
19263
  });
18869
19264
  var $ZodCheckIncludes = /* @__PURE__ */ $constructor("$ZodCheckIncludes", (inst, def) => {
18870
19265
  $ZodCheck.init(inst, def);
18871
- const escapedRegex = escapeRegex(def.includes);
19266
+ const escapedRegex = escapeRegex2(def.includes);
18872
19267
  const pattern = new RegExp(typeof def.position === "number" ? `^.{${def.position}}${escapedRegex}` : escapedRegex);
18873
19268
  def.pattern = pattern;
18874
19269
  inst._zod.onattach.push((inst2) => {
@@ -18892,7 +19287,7 @@ var $ZodCheckIncludes = /* @__PURE__ */ $constructor("$ZodCheckIncludes", (inst,
18892
19287
  });
18893
19288
  var $ZodCheckStartsWith = /* @__PURE__ */ $constructor("$ZodCheckStartsWith", (inst, def) => {
18894
19289
  $ZodCheck.init(inst, def);
18895
- const pattern = new RegExp(`^${escapeRegex(def.prefix)}.*`);
19290
+ const pattern = new RegExp(`^${escapeRegex2(def.prefix)}.*`);
18896
19291
  def.pattern ?? (def.pattern = pattern);
18897
19292
  inst._zod.onattach.push((inst2) => {
18898
19293
  const bag = inst2._zod.bag;
@@ -18915,7 +19310,7 @@ var $ZodCheckStartsWith = /* @__PURE__ */ $constructor("$ZodCheckStartsWith", (i
18915
19310
  });
18916
19311
  var $ZodCheckEndsWith = /* @__PURE__ */ $constructor("$ZodCheckEndsWith", (inst, def) => {
18917
19312
  $ZodCheck.init(inst, def);
18918
- const pattern = new RegExp(`.*${escapeRegex(def.suffix)}$`);
19313
+ const pattern = new RegExp(`.*${escapeRegex2(def.suffix)}$`);
18919
19314
  def.pattern ?? (def.pattern = pattern);
18920
19315
  inst._zod.onattach.push((inst2) => {
18921
19316
  const bag = inst2._zod.bag;
@@ -20562,7 +20957,7 @@ var $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => {
20562
20957
  const values = getEnumValues(def.entries);
20563
20958
  const valuesSet = new Set(values);
20564
20959
  inst._zod.values = valuesSet;
20565
- inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex(o) : o.toString()).join("|")})$`);
20960
+ inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex2(o) : o.toString()).join("|")})$`);
20566
20961
  inst._zod.parse = (payload, _ctx) => {
20567
20962
  const input = payload.value;
20568
20963
  if (valuesSet.has(input)) {
@@ -20584,7 +20979,7 @@ var $ZodLiteral = /* @__PURE__ */ $constructor("$ZodLiteral", (inst, def) => {
20584
20979
  }
20585
20980
  const values = new Set(def.values);
20586
20981
  inst._zod.values = values;
20587
- inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`);
20982
+ inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex2(o) : o ? escapeRegex2(o.toString()) : String(o)).join("|")})$`);
20588
20983
  inst._zod.parse = (payload, _ctx) => {
20589
20984
  const input = payload.value;
20590
20985
  if (values.has(input)) {
@@ -20949,7 +21344,7 @@ var $ZodTemplateLiteral = /* @__PURE__ */ $constructor("$ZodTemplateLiteral", (i
20949
21344
  const end = source.endsWith("$") ? source.length - 1 : source.length;
20950
21345
  regexParts.push(source.slice(start, end));
20951
21346
  } else if (part === null || primitiveTypes.has(typeof part)) {
20952
- regexParts.push(escapeRegex(`${part}`));
21347
+ regexParts.push(escapeRegex2(`${part}`));
20953
21348
  } else {
20954
21349
  throw new Error(`Invalid template literal part: ${part}`);
20955
21350
  }
@@ -31227,16 +31622,134 @@ var PromptSurfaceConfigSchema = exports_external.object({
31227
31622
  message: "tool description values must not be empty or whitespace-only"
31228
31623
  })).optional().describe("USER-LEVEL ONLY top-level description overrides keyed by ctx_* tool ID; parameter schemas and descriptions are unchanged.")
31229
31624
  }).describe("Prompt-surface preset routing. Project config may select default/models, while guidance_override_path and tool_descriptions are user-level only.");
31625
+ var PER_HARNESS_MIGRATION_INVENTORY = {
31626
+ historian: {
31627
+ retained: [
31628
+ "temperature",
31629
+ "top_p",
31630
+ "prompt",
31631
+ "tools",
31632
+ "disable",
31633
+ "description",
31634
+ "mode",
31635
+ "color",
31636
+ "maxSteps",
31637
+ "permission",
31638
+ "maxTokens",
31639
+ "two_pass",
31640
+ "disallowed_tools"
31641
+ ],
31642
+ migrated_execution: ["model", "fallback_models", "variant", "thinking_level"]
31643
+ },
31644
+ dreamer: {
31645
+ retained: [
31646
+ "temperature",
31647
+ "top_p",
31648
+ "prompt",
31649
+ "tools",
31650
+ "disable",
31651
+ "description",
31652
+ "mode",
31653
+ "color",
31654
+ "maxSteps",
31655
+ "permission",
31656
+ "maxTokens",
31657
+ "inject_docs"
31658
+ ],
31659
+ migrated_execution: ["model", "fallback_models", "variant", "thinking_level"]
31660
+ },
31661
+ task: {
31662
+ retained: ["schedule", "promotion_threshold"],
31663
+ migrated_execution: [
31664
+ "model",
31665
+ "fallback_models",
31666
+ "variant",
31667
+ "thinking_level",
31668
+ "timeout_minutes"
31669
+ ]
31670
+ }
31671
+ };
31672
+ var OcEntryObjectSchema = exports_external.object({
31673
+ model: exports_external.string().describe("OpenCode model ID (for example, provider/model)."),
31674
+ variant: exports_external.string().optional().describe("OpenCode reasoning variant for this entry.")
31675
+ }).strict();
31676
+ var OcEntrySchema = exports_external.union([exports_external.string(), OcEntryObjectSchema]);
31677
+ var PiEntryObjectSchema = exports_external.object({
31678
+ model: exports_external.string().describe("Pi model ID (for example, provider/model)."),
31679
+ thinking_level: PiThinkingLevelSchema.describe("Pi thinking level for this entry.")
31680
+ }).strict();
31681
+ var PiEntrySchema = exports_external.union([exports_external.string(), PiEntryObjectSchema]);
31682
+ var OpenCodeHarnessBlockSchema = exports_external.object({
31683
+ model: OcEntrySchema.optional().describe("Primary OpenCode model entry."),
31684
+ fallback_models: exports_external.array(OcEntrySchema).optional().describe("Ordered fallback OpenCode entries. New-shape configuration requires an array; legacy singleton values migrate to a one-element array."),
31685
+ variant: exports_external.string().optional().describe("OpenCode reasoning variant for the primary entry when it declares none. Fallback entries declare variants per-entry.")
31686
+ }).strict().describe("Strict OpenCode model-resolution block. It accepts no Pi vocabulary.");
31687
+ var PiHarnessBlockSchema = exports_external.object({
31688
+ model: PiEntrySchema.optional().describe("Primary Pi model entry."),
31689
+ fallback_models: exports_external.array(PiEntrySchema).optional().describe("Ordered fallback Pi entries. New-shape configuration requires an array; legacy singleton values migrate to a one-element array."),
31690
+ thinking_level: PiThinkingLevelSchema.describe("Pi thinking level for the primary entry when it declares none. Fallback entries declare thinking levels per-entry.")
31691
+ }).strict().describe("Strict Pi model-resolution block. It accepts no OpenCode vocabulary.");
31692
+ var OpenCodeTaskExecutionSchema = exports_external.object({
31693
+ model: OcEntrySchema.optional().describe("OpenCode model entry for this task."),
31694
+ fallback_models: exports_external.array(OcEntrySchema).optional().describe("Ordered OpenCode fallback entries for this task."),
31695
+ variant: exports_external.string().optional().describe("OpenCode reasoning variant for this task's primary entry when it declares none. Fallback entries declare variants per-entry."),
31696
+ timeout_minutes: exports_external.number().min(5).optional().describe("Minutes allowed for this task before it is aborted.")
31697
+ }).strict();
31698
+ var PiTaskExecutionSchema = exports_external.object({
31699
+ model: PiEntrySchema.optional().describe("Pi model entry for this task."),
31700
+ fallback_models: exports_external.array(PiEntrySchema).optional().describe("Ordered Pi fallback entries for this task."),
31701
+ thinking_level: PiThinkingLevelSchema.describe("Pi thinking level for this task's primary entry when it declares none. Fallback entries declare thinking levels per-entry."),
31702
+ timeout_minutes: exports_external.number().min(5).optional().describe("Minutes allowed for this task before it is aborted.")
31703
+ }).strict();
31704
+ var DreamerOpenCodeHarnessBlockSchema = exports_external.object({
31705
+ model: OcEntrySchema.optional().describe("Primary OpenCode model entry."),
31706
+ fallback_models: exports_external.array(OcEntrySchema).optional().describe("Ordered fallback OpenCode entries. New-shape configuration requires an array; legacy singleton values migrate to a one-element array."),
31707
+ variant: exports_external.string().optional().describe("OpenCode reasoning variant for the primary entry when it declares none. Fallback entries declare variants per-entry."),
31708
+ tasks: exports_external.record(exports_external.string(), OpenCodeTaskExecutionSchema).optional().describe("OpenCode task execution overrides. Each named task accepts only model, fallback_models, variant, and timeout_minutes.")
31709
+ }).strict().describe("Strict OpenCode dreamer model-resolution block. It accepts no Pi vocabulary.");
31710
+ var DreamerPiHarnessBlockSchema = exports_external.object({
31711
+ model: PiEntrySchema.optional().describe("Primary Pi model entry."),
31712
+ fallback_models: exports_external.array(PiEntrySchema).optional().describe("Ordered fallback Pi entries. New-shape configuration requires an array; legacy singleton values migrate to a one-element array."),
31713
+ thinking_level: PiThinkingLevelSchema.describe("Pi thinking level for the primary entry when it declares none. Fallback entries declare thinking levels per-entry."),
31714
+ tasks: exports_external.record(exports_external.string(), PiTaskExecutionSchema).optional().describe("Pi task execution overrides. Each named task accepts only model, fallback_models, thinking_level, and timeout_minutes.")
31715
+ }).strict().describe("Strict Pi dreamer model-resolution block. It accepts no OpenCode vocabulary.");
31716
+ var ProfileOpenCodeModelBlockSchema = exports_external.object({
31717
+ model: OcEntrySchema.optional().describe("Primary OpenCode model entry."),
31718
+ fallback_models: exports_external.array(OcEntrySchema).optional().describe("Ordered fallback OpenCode model entries."),
31719
+ variant: exports_external.string().optional().describe("OpenCode reasoning variant for the primary model entry.")
31720
+ }).strict().describe("Strict profile-only OpenCode model-selection block.");
31721
+ var ProfilePiModelBlockSchema = exports_external.object({
31722
+ model: PiEntrySchema.optional().describe("Primary Pi model entry."),
31723
+ fallback_models: exports_external.array(PiEntrySchema).optional().describe("Ordered fallback Pi model entries."),
31724
+ thinking_level: PiThinkingLevelSchema.describe("Pi thinking level for the primary model entry.")
31725
+ }).strict().describe("Strict profile-only Pi model-selection block.");
31726
+ var ProfileHistorianSchema = exports_external.object({
31727
+ opencode: ProfileOpenCodeModelBlockSchema.optional(),
31728
+ pi: ProfilePiModelBlockSchema.optional()
31729
+ }).strict();
31730
+ var ProfileDreamerSchema = exports_external.object({
31731
+ opencode: ProfileOpenCodeModelBlockSchema.optional(),
31732
+ pi: ProfilePiModelBlockSchema.optional()
31733
+ }).strict();
31734
+ var ProfileSidekickSchema = AgentOverrideConfigSchema.pick({
31735
+ model: true,
31736
+ fallback_models: true,
31737
+ variant: true
31738
+ }).extend({
31739
+ thinking_level: PiThinkingLevelSchema.describe("Pi thinking level for the sidekick model selection.")
31740
+ }).strict();
31741
+ var ConfigProfileSchema = exports_external.object({
31742
+ historian: ProfileHistorianSchema.optional(),
31743
+ dreamer: ProfileDreamerSchema.optional(),
31744
+ sidekick: ProfileSidekickSchema.optional()
31745
+ }).strict().describe("User-owned model-selection overlay. Only historian/dreamer harness model blocks and sidekick model-selection fields are allowed.");
31746
+ var ConfigProfilesSchema = exports_external.record(exports_external.string().trim().min(1, "Profile names must not be empty or whitespace-only."), ConfigProfileSchema);
31230
31747
  var CronScheduleSchema = exports_external.string().refine((s) => s.trim() === "" || isValidCron(s), {
31231
31748
  message: 'Invalid schedule: use a 5-field cron expression (e.g. "0 3 * * *" for 3am daily, "0 3 * * 0" for Sunday 3am, "0 */6 * * *" every 6h) or "" to disable.'
31232
31749
  }).describe('5-field cron schedule (e.g. "0 3 * * *"), or "" to disable this task.');
31233
31750
  var DreamTaskBaseConfigSchema = exports_external.object({
31234
- schedule: CronScheduleSchema.default(""),
31235
- model: exports_external.string().optional().describe("Per-task model override (inherits dreamer.model)"),
31236
- fallback_models: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional().describe("Per-task fallback chain (inherits dreamer.fallback_models)"),
31237
- thinking_level: PiThinkingLevelSchema.describe("Pi only: per-task thinking level"),
31238
- timeout_minutes: exports_external.number().min(5).default(20).describe("Minutes allowed for this task before it is aborted")
31239
- });
31751
+ schedule: CronScheduleSchema.default("")
31752
+ }).strict();
31240
31753
  var PromotionThresholdSchema = exports_external.number().min(2).max(20).optional().describe("review-user-memories: min candidate observations before promotion is considered (default: 3)");
31241
31754
  var PrimerPromotionThresholdSchema = exports_external.number().min(2).max(20).optional().describe("promote-primers: min recurring source days before promotion is considered (default: 2)");
31242
31755
  var DreamTaskConfigSchema = DreamTaskBaseConfigSchema.extend({
@@ -31283,29 +31796,44 @@ var DreamTasksSchema = exports_external.object({
31283
31796
  "review-user-memories": ReviewUserMemoriesTaskConfigSchema.default(() => ReviewUserMemoriesTaskConfigSchema.parse(defaultTaskConfig("review-user-memories"))),
31284
31797
  "promote-primers": PromotePrimersTaskConfigSchema.default(() => PromotePrimersTaskConfigSchema.parse(defaultTaskConfig("promote-primers"))),
31285
31798
  "refresh-primers": DreamTaskBaseConfigSchema.default(() => DreamTaskBaseConfigSchema.parse(defaultTaskConfig("refresh-primers")))
31286
- }).describe("Per-task scheduling + model config. Each task has its own cron schedule and may override the dreamer-level model.");
31287
- var DreamerConfigSchema = AgentOverrideConfigSchema.merge(exports_external.object({
31799
+ }).describe("Harness-independent task metadata. schedule, promotion_threshold, and other task metadata remain here; execution settings live under dreamer.opencode.tasks or dreamer.pi.tasks.");
31800
+ var AgentMetadataSchema = AgentOverrideConfigSchema.pick({
31801
+ temperature: true,
31802
+ top_p: true,
31803
+ prompt: true,
31804
+ tools: true,
31805
+ disable: true,
31806
+ description: true,
31807
+ mode: true,
31808
+ color: true,
31809
+ maxSteps: true,
31810
+ permission: true,
31811
+ maxTokens: true
31812
+ });
31813
+ var DreamerConfigSchema = AgentMetadataSchema.extend({
31814
+ opencode: DreamerOpenCodeHarnessBlockSchema.optional(),
31815
+ pi: DreamerPiHarnessBlockSchema.optional(),
31288
31816
  tasks: DreamTasksSchema.default(() => DreamTasksSchema.parse({})),
31289
- inject_docs: exports_external.boolean().default(true).describe("Inject ARCHITECTURE.md and STRUCTURE.md into the m[0] `<project-docs>` block (default true)"),
31290
- thinking_level: PiThinkingLevelSchema.describe("Pi only: default thinking level for dreamer subagent invocations. See historian.thinking_level.")
31291
- }));
31817
+ inject_docs: exports_external.boolean().default(true).describe("Inject ARCHITECTURE.md and STRUCTURE.md into the m[0] `<project-docs>` block (default true)")
31818
+ });
31292
31819
  var SidekickConfigSchema = AgentOverrideConfigSchema.extend({
31293
31820
  timeout_ms: exports_external.number().default(30000).describe("Timeout for sidekick calls in milliseconds"),
31294
31821
  system_prompt: exports_external.string().optional().describe("Custom system prompt for sidekick"),
31295
- thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level for sidekick subagent invocations. See historian.thinking_level.")
31822
+ thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level for sidekick subagent invocations. See historian.pi.thinking_level.")
31296
31823
  }).optional();
31297
- var HistorianConfigSchema = AgentOverrideConfigSchema.extend({
31824
+ var HistorianConfigSchema = AgentMetadataSchema.extend({
31825
+ opencode: OpenCodeHarnessBlockSchema.optional(),
31826
+ pi: PiHarnessBlockSchema.optional(),
31298
31827
  two_pass: exports_external.boolean().default(false).describe("Run a second editor pass over historian output to clean low-signal U: lines and cross-compartment duplicates. Adds ~1 extra API call and ~1.3x cost per historian run. Useful for models without extended thinking support. (default: false)"),
31299
- thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level passed as --thinking <level> to Pi historian subagent invocations. Required when using reasoning models (e.g. github-copilot/gpt-5.4) because Pi's default thinking-level resolution can pick a value the provider rejects. OpenCode users set variant instead. Valid: off | minimal | low | medium | high | xhigh | max"),
31300
31828
  disallowed_tools: exports_external.array(exports_external.enum(["*", "read", "aft_outline", "aft_zoom", "aft_search"])).default([]).describe(`OpenCode only. Tools to REMOVE from the historian's default allow-list [read, aft_outline, aft_zoom, aft_search]. Applies to both historian and historian-editor agents. Use ["*"] to strip all tool definitions from the model request — this prevents weak instruction-following models (e.g. mistral-small-latest) from entering tool-calling loops. Individual tool names remove just that tool. Note: a user-supplied historian.permission override can re-allow a tool that disallowed_tools removed — disallowed_tools sets the baseline, permission overrides take precedence. (default: [])`)
31301
31829
  }).optional();
31302
31830
  var EmbeddingFallbackProviderSchema = exports_external.enum(["local", "openai-compatible", "off"]);
31303
31831
  function expandConfigPath(value) {
31304
31832
  const trimmed = value.trim();
31305
31833
  if (trimmed === "~")
31306
- return homedir4();
31834
+ return homedir5();
31307
31835
  if (trimmed.startsWith("~/"))
31308
- return `${homedir4()}/${trimmed.slice(2)}`;
31836
+ return `${homedir5()}/${trimmed.slice(2)}`;
31309
31837
  return trimmed;
31310
31838
  }
31311
31839
  var BaseEmbeddingConfigSchema = exports_external.object({
@@ -31406,8 +31934,10 @@ var MagicContextConfigSchema = exports_external.object({
31406
31934
  transform_mode: exports_external.enum(["ts", "rust"]).default("ts").describe('Experimental: routes the entire Magic Context runtime for the project through the ck-mc Rust module over subc (requires user-level `subc` config); "ts" is the current TypeScript pipeline.'),
31407
31935
  auto_update: exports_external.boolean().optional().describe("Enable automatic npm self-update checks for the OpenCode plugin. Security: USER-only in config loader, so hostile project configs cannot suppress updates."),
31408
31936
  language: exports_external.string().trim().toLowerCase().refine((s) => isValidLanguageCode(s), 'language must be a 2-letter ISO 639-1 code (e.g. "tr", "es", "de")').optional().describe("Output language for Magic Context's generated content and guidance, as a " + '2-letter ISO 639-1 code (e.g. "tr", "es", "de", "ja", "pt"). When set, the ' + "historian, dreamer, sidekick, and the agent-guidance block instruct the model to " + "write its PROSE in this language while keeping all structural tokens (XML tags, " + "the five memory category names, code identifiers, file paths) in English. " + "USER-LEVEL ONLY (ignored in project config for security). Unset = today's " + "behavior (model mirrors the conversation; English scaffolding). Changing it " + "triggers one cache re-materialization; existing compartments/memories keep their " + "original language until naturally rewritten."),
31409
- historian: HistorianConfigSchema.describe("Historian agent configuration (model, fallback_models, variant, temperature, maxTokens, permission, two_pass, etc.)"),
31410
- dreamer: DreamerConfigSchema.optional().describe("Dreamer agent + scheduling configuration (model, fallback_models, disable, schedule, tasks, etc.)"),
31937
+ profile: exports_external.string().trim().min(1).optional().describe("Select a named user-owned model profile. A valid project name overrides this user default; an empty string, null, or other non-string project value is ignored with a warning so the user selection still applies. Unknown names warn and use the base configuration."),
31938
+ profiles: ConfigProfilesSchema.optional().describe("User-level named model profiles. A profile may contain only historian/dreamer model, fallback_models, OpenCode variant, and Pi thinking_level fields plus sidekick model-selection fields; task execution policy (including timeout_minutes) is excluded. Project configs may select a name but cannot define profiles."),
31939
+ historian: HistorianConfigSchema.describe("Historian metadata plus independent strict OpenCode and Pi execution blocks. Retained metadata stays at historian; model, fallback_models, variant, and thinking_level belong only in historian.opencode or historian.pi."),
31940
+ dreamer: DreamerConfigSchema.optional().describe("Dreamer metadata and scheduling plus independent strict OpenCode and Pi execution blocks. schedule and promotion_threshold stay at dreamer.tasks; model, fallback_models, variant, thinking_level, and timeout_minutes belong only in the matching harness block."),
31411
31941
  smart_notes: exports_external.object({
31412
31942
  retina_handoff: exports_external.boolean().default(false).describe("When true, dreamer skips smart notes whose surface conditions compiled to retina provider configs at authoring time. Default false keeps both paths active until the retina consumer is deployed.")
31413
31943
  }).default({ retina_handoff: false }).describe("Smart-note ownership transition controls."),
@@ -31822,6 +32352,25 @@ function releaseGitSweepLease(db, projectPath, holderId) {
31822
32352
  });
31823
32353
  }
31824
32354
 
32355
+ // src/features/magic-context/memory/embedding-failure.ts
32356
+ function dominantEmbeddingFailure(failures) {
32357
+ const counts = new Map;
32358
+ for (const failure of failures) {
32359
+ const key = `${failure.class}\x00${failure.reason}`;
32360
+ const current = counts.get(key);
32361
+ if (current)
32362
+ current.count += 1;
32363
+ else
32364
+ counts.set(key, { failure, count: 1 });
32365
+ }
32366
+ let dominant;
32367
+ for (const candidate of counts.values()) {
32368
+ if (!dominant || candidate.count > dominant.count)
32369
+ dominant = candidate;
32370
+ }
32371
+ return dominant?.failure;
32372
+ }
32373
+
31825
32374
  // src/features/magic-context/memory/embedding-synapse.ts
31826
32375
  import { createHash as createHash13 } from "node:crypto";
31827
32376
 
@@ -34201,6 +34750,7 @@ class OpenAICompatibleEmbeddingProvider {
34201
34750
  circuitOpenUntil = 0;
34202
34751
  openLogged = false;
34203
34752
  modelMismatchLogged = false;
34753
+ lastFailureReason = null;
34204
34754
  halfOpenProbeInFlight = false;
34205
34755
  constructor(options) {
34206
34756
  this.endpoint = normalizeEndpoint2(options.endpoint);
@@ -34290,41 +34840,59 @@ class OpenAICompatibleEmbeddingProvider {
34290
34840
  signal: internalController.signal
34291
34841
  });
34292
34842
  if (!response.ok) {
34293
- log(`[magic-context] openai-compatible embedding request failed: ${response.status} ${response.statusText}`);
34294
- this.recordFailure(isProbe);
34843
+ const excerpt = await response.text().catch(() => "");
34844
+ const failure = this.failure("http_error", `HTTP ${response.status} from endpoint${this.bodyExcerpt(excerpt)}`, response.status >= 500 || response.status === 408 || response.status === 429);
34845
+ log(`[magic-context] openai-compatible embedding request failed: ${failure.reason}`);
34846
+ this.recordFailure(isProbe, failure);
34295
34847
  return Array.from({ length: texts.length }, () => null);
34296
34848
  }
34297
34849
  const rawBody = await response.text();
34298
34850
  if (rawBody.trim().length === 0) {
34299
- log(`[magic-context] openai-compatible embedding request returned empty body (status=${response.status}, content-type=${response.headers.get("content-type") ?? "none"})`);
34300
- this.recordFailure(isProbe);
34851
+ const failure = this.failure("invalid_envelope", "response body was empty", false);
34852
+ log(`[magic-context] openai-compatible embedding request failed: ${failure.reason}`);
34853
+ this.recordFailure(isProbe, failure);
34301
34854
  return Array.from({ length: texts.length }, () => null);
34302
34855
  }
34303
34856
  let body;
34304
34857
  try {
34305
34858
  body = JSON.parse(rawBody);
34306
- } catch (parseError) {
34307
- const snippet = rawBody.slice(0, 200).replace(/\s+/g, " ");
34308
- log(`[magic-context] openai-compatible embedding response was not JSON (status=${response.status}, ${rawBody.length}B body, snippet="${snippet}"):`, parseError instanceof Error ? parseError.message : parseError);
34309
- this.recordFailure(isProbe);
34859
+ } catch {
34860
+ const failure = this.failure("invalid_envelope", `response body was not valid JSON${this.bodyExcerpt(rawBody)}`, false);
34861
+ log(`[magic-context] openai-compatible embedding request failed: ${failure.reason}`);
34862
+ this.recordFailure(isProbe, failure);
34310
34863
  return Array.from({ length: texts.length }, () => null);
34311
34864
  }
34312
34865
  const servedModel = typeof body.model === "string" ? body.model : "";
34313
34866
  if (this.model && servedModel && !embeddingModelsMatch(servedModel, this.model)) {
34314
34867
  if (!this.modelMismatchLogged) {
34315
- log(`[magic-context] embedding endpoint served a DIFFERENT model than requested — refusing the substituted vectors (they have the wrong dimensions/space). requested="${this.model}" served="${servedModel}". Check that the endpoint serves the requested model; variant suffixes and vendor prefixes are matched automatically.`);
34868
+ log(`[magic-context] embedding endpoint served a DIFFERENT model than requested — refusing the substituted vectors (they have the wrong dimensions/space). requested="${sanitizeDiagnosticText(this.model)}" served="${sanitizeDiagnosticText(servedModel)}". Check that the endpoint serves the requested model; variant suffixes and vendor prefixes are matched automatically.`);
34316
34869
  this.modelMismatchLogged = true;
34317
34870
  }
34318
- this.recordFailure(isProbe);
34871
+ this.recordFailure(isProbe, this.failure("substitution_rejected", `served model '${sanitizeDiagnosticText(servedModel)}' does not match requested '${sanitizeDiagnosticText(this.model)}' (substitution guard)`, false));
34872
+ return Array.from({ length: texts.length }, () => null);
34873
+ }
34874
+ const responseKeys = Object.keys(body).sort();
34875
+ if (!Array.isArray(body.data)) {
34876
+ const failure = this.failure("invalid_envelope", `response had keys [${responseKeys.join(", ")}] but data[] was absent`, false);
34877
+ log(`[magic-context] openai-compatible embedding request failed: ${failure.reason}`);
34878
+ this.recordFailure(isProbe, failure);
34879
+ return Array.from({ length: texts.length }, () => null);
34880
+ }
34881
+ if (body.data.length === 0) {
34882
+ const failure = this.failure("empty_result", "response data[] was empty", true);
34883
+ log(`[magic-context] openai-compatible embedding request failed: ${failure.reason}`);
34884
+ this.recordFailure(isProbe, failure);
34319
34885
  return Array.from({ length: texts.length }, () => null);
34320
34886
  }
34321
- const items = Array.isArray(body.data) ? body.data : [];
34887
+ const items = body.data;
34322
34888
  const results = Array.from({ length: texts.length }, (_, index) => {
34323
34889
  const embedding = items[index]?.embedding;
34324
34890
  return Array.isArray(embedding) ? Float32Array.from(embedding) : null;
34325
34891
  });
34326
34892
  if (results.every((r) => r === null)) {
34327
- this.recordFailure(isProbe);
34893
+ const failure = this.failure("invalid_envelope", `response had keys [${responseKeys.join(", ")}] but data[].embedding was absent`, false);
34894
+ log(`[magic-context] openai-compatible embedding request failed: ${failure.reason}`);
34895
+ this.recordFailure(isProbe, failure);
34328
34896
  } else {
34329
34897
  this.recordSuccess();
34330
34898
  }
@@ -34334,11 +34902,14 @@ class OpenAICompatibleEmbeddingProvider {
34334
34902
  if (isAbort) {
34335
34903
  if (signal?.aborted) {} else {
34336
34904
  log(`[magic-context] openai-compatible embedding request timed out after ${FETCH_TIMEOUT_MS}ms`);
34337
- this.recordFailure(isProbe);
34905
+ const failure = this.failure("transport_error", `request timed out after ${FETCH_TIMEOUT_MS}ms`, true);
34906
+ this.recordFailure(isProbe, failure);
34338
34907
  }
34339
34908
  } else {
34340
- log("[magic-context] openai-compatible embedding request failed:", error51);
34341
- this.recordFailure(isProbe);
34909
+ const detail = error51 instanceof Error ? error51.message : String(error51);
34910
+ const failure = this.failure("transport_error", `transport error: ${sanitizeDiagnosticText(detail)}`, true);
34911
+ log(`[magic-context] openai-compatible embedding request failed: ${failure.reason}`);
34912
+ this.recordFailure(isProbe, failure);
34342
34913
  }
34343
34914
  return Array.from({ length: texts.length }, () => null);
34344
34915
  } finally {
@@ -34370,14 +34941,23 @@ class OpenAICompatibleEmbeddingProvider {
34370
34941
  return "short_circuit";
34371
34942
  }
34372
34943
  this.halfOpenProbeInFlight = true;
34373
- log("[magic-context] openai-compatible embedding: circuit half-open, probing endpoint");
34944
+ log(`[magic-context] openai-compatible embedding: circuit half-open, probing endpoint after ${this.lastFailureReason?.reason ?? "unknown failure"}`);
34374
34945
  return "probe";
34375
34946
  }
34376
- recordFailure(isProbe) {
34947
+ failure(failureClass, reason, retryable) {
34948
+ return { class: failureClass, reason, retryable };
34949
+ }
34950
+ bodyExcerpt(body) {
34951
+ const excerpt = sanitizeDiagnosticText(body).replace(/\s+/g, " ").trim().slice(0, 200);
34952
+ return excerpt ? `: ${excerpt}` : "";
34953
+ }
34954
+ recordFailure(isProbe, failure) {
34955
+ if (failure)
34956
+ this.lastFailureReason = failure;
34377
34957
  if (isProbe) {
34378
34958
  this.circuitOpenUntil = Date.now() + OPEN_DURATION_MS;
34379
34959
  if (!this.openLogged) {
34380
- log(`[magic-context] openai-compatible embedding: probe failed, re-opening circuit for ${OPEN_DURATION_MS / 60000}min`);
34960
+ log(`[magic-context] openai-compatible embedding: probe failed (${failure?.reason ?? this.lastFailureReason?.reason ?? "unknown failure"}), re-opening circuit for ${OPEN_DURATION_MS / 60000}min`);
34381
34961
  this.openLogged = true;
34382
34962
  }
34383
34963
  this.failureTimes = [];
@@ -34390,7 +34970,7 @@ class OpenAICompatibleEmbeddingProvider {
34390
34970
  if (this.failureTimes.length >= FAILURE_THRESHOLD) {
34391
34971
  this.circuitOpenUntil = now + OPEN_DURATION_MS;
34392
34972
  if (!this.openLogged) {
34393
- log(`[magic-context] openai-compatible embedding: opening circuit for ${OPEN_DURATION_MS / 60000}min after ${this.failureTimes.length} failures in ${FAILURE_WINDOW_MS / 1000}s`);
34973
+ log(`[magic-context] openai-compatible embedding: opening circuit for ${OPEN_DURATION_MS / 60000}min after ${this.failureTimes.length} failures in ${FAILURE_WINDOW_MS / 1000}s (${failure?.reason ?? this.lastFailureReason?.reason ?? "unknown failure"})`);
34394
34974
  this.openLogged = true;
34395
34975
  }
34396
34976
  this.failureTimes = [];
@@ -34403,6 +34983,10 @@ class OpenAICompatibleEmbeddingProvider {
34403
34983
  this.failureTimes = [];
34404
34984
  this.circuitOpenUntil = 0;
34405
34985
  this.openLogged = false;
34986
+ this.lastFailureReason = null;
34987
+ }
34988
+ getLastFailureReason() {
34989
+ return this.lastFailureReason;
34406
34990
  }
34407
34991
  _getCircuitState() {
34408
34992
  if (this.circuitOpenUntil === 0)
@@ -34420,6 +35004,7 @@ class OpenAICompatibleEmbeddingProvider {
34420
35004
  this.circuitOpenUntil = 0;
34421
35005
  this.openLogged = false;
34422
35006
  this.halfOpenProbeInFlight = false;
35007
+ this.lastFailureReason = null;
34423
35008
  }
34424
35009
  }
34425
35010
 
@@ -35669,11 +36254,16 @@ async function drainCommitBacklogForProject(db, projectIdentity, deadline) {
35669
36254
  }
35670
36255
  return total;
35671
36256
  }
36257
+ function getLastEmbeddingFailureForProject(projectIdentity) {
36258
+ const registration = projectRegistrations.get(projectIdentity);
36259
+ return registration?.provider?.getLastFailureReason?.() ?? null;
36260
+ }
35672
36261
  async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates, signal) {
35673
36262
  const noWork = [];
35674
36263
  const failed = [];
36264
+ const failureReasons = [];
35675
36265
  if (candidates.length === 0)
35676
- return { embedded: 0, noWork, failed };
36266
+ return { embedded: 0, noWork, failed, failureReasons };
35677
36267
  const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
35678
36268
  const prepared = [];
35679
36269
  for (const candidate of candidates) {
@@ -35690,7 +36280,7 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
35690
36280
  prepared.push({ candidate, windows });
35691
36281
  }
35692
36282
  if (prepared.length === 0)
35693
- return { embedded: 0, noWork, failed };
36283
+ return { embedded: 0, noWork, failed, failureReasons };
35694
36284
  let embedded = 0;
35695
36285
  let i = 0;
35696
36286
  while (i < prepared.length) {
@@ -35722,6 +36312,11 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
35722
36312
  }
35723
36313
  if (signal?.aborted)
35724
36314
  break;
36315
+ if (!result || result.vectors.size === 0) {
36316
+ const failure = getLastEmbeddingFailureForProject(projectIdentity);
36317
+ if (failure)
36318
+ failureReasons.push(failure);
36319
+ }
35725
36320
  if (result) {
35726
36321
  for (const item of slice) {
35727
36322
  if (persistedIds.has(item.candidate.id))
@@ -35763,7 +36358,7 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
35763
36358
  }
35764
36359
  }
35765
36360
  }
35766
- return { embedded, noWork, failed };
36361
+ return { embedded, noWork, failed, failureReasons };
35767
36362
  }
35768
36363
  async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, options) {
35769
36364
  const snapshot2 = getProjectEmbeddingSnapshot(projectIdentity);
@@ -35801,6 +36396,7 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
35801
36396
  let aborted2 = false;
35802
36397
  let providerDown = false;
35803
36398
  let consecutiveFailedBatches = 0;
36399
+ const failureReasons = [];
35804
36400
  try {
35805
36401
  options?.onProgress?.({ embedded, total });
35806
36402
  for (;; ) {
@@ -35814,7 +36410,8 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
35814
36410
  const {
35815
36411
  embedded: n,
35816
36412
  noWork,
35817
- failed
36413
+ failed,
36414
+ failureReasons: batchFailureReasons
35818
36415
  } = await embedCandidateChunkBatch(db, projectIdentity, snapshot2.chunkModelId, candidates, drainAbort.signal);
35819
36416
  if (leaseLost || !renewGitSweepLease(db, projectIdentity, holderId)) {
35820
36417
  leaseLost = true;
@@ -35822,6 +36419,7 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
35822
36419
  aborted2 = true;
35823
36420
  break;
35824
36421
  }
36422
+ failureReasons.push(...batchFailureReasons);
35825
36423
  for (const id of noWork)
35826
36424
  skipIds.push(id);
35827
36425
  for (const id of failed)
@@ -35853,7 +36451,14 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
35853
36451
  if (providerDown || failedIds.length > 0) {
35854
36452
  const remaining = Math.max(0, countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot2.chunkModelId) - skipIds.length);
35855
36453
  if (remaining > 0) {
35856
- return { status: "stalled", embedded, total, remaining, failed: failedIds.length };
36454
+ return {
36455
+ status: "stalled",
36456
+ embedded,
36457
+ total,
36458
+ remaining,
36459
+ failed: failedIds.length,
36460
+ failure: dominantEmbeddingFailure(failureReasons)
36461
+ };
35857
36462
  }
35858
36463
  }
35859
36464
  return { status: "done", embedded, total, failed: failedIds.length };
@@ -38578,6 +39183,7 @@ async function runValidatedHistorianPass(args) {
38578
39183
  const firstRun = await runHistorianPrompt({
38579
39184
  ...args,
38580
39185
  dumpLabel: `${args.dumpLabelBase}-initial`,
39186
+ modelOverride: args.model,
38581
39187
  agentId: args.agentId
38582
39188
  });
38583
39189
  if (!firstRun.ok || !firstRun.result) {
@@ -38606,6 +39212,7 @@ async function runValidatedHistorianPass(args) {
38606
39212
  ...args,
38607
39213
  prompt: repairPrompt,
38608
39214
  dumpLabel: `${args.dumpLabelBase}-repair`,
39215
+ modelOverride: args.model,
38609
39216
  agentId: args.agentId
38610
39217
  });
38611
39218
  if (!repairRun.ok || !repairRun.result) {
@@ -38646,7 +39253,8 @@ async function runEditorPassOrFallback(args) {
38646
39253
  timeoutMs: args.timeoutMs,
38647
39254
  dumpLabel: `${args.dumpLabelBase}-editor`,
38648
39255
  agentId: HISTORIAN_EDITOR_AGENT,
38649
- parentInvocationId: args.draftInvocationId ?? null
39256
+ parentInvocationId: args.draftInvocationId ?? null,
39257
+ modelOverride: args.model
38650
39258
  });
38651
39259
  if (!editorRun.ok || !editorRun.result) {
38652
39260
  sessionLog(args.parentSessionId, "historian two-pass: editor call failed", {
@@ -38699,7 +39307,7 @@ async function runHistorianPrompt(args) {
38699
39307
  });
38700
39308
  };
38701
39309
  try {
38702
- sessionLog(parentSessionId, `historian: creating child session (agent=${agentId}, model=${modelOverride ? `${modelOverride.providerID}/${modelOverride.modelID}` : `agent:${agentId}`})`);
39310
+ sessionLog(parentSessionId, `historian: creating child session (agent=${toModelEntry(modelOverride)?.model ?? `agent:${agentId}`})`);
38703
39311
  const createResponse = await createChildSessionWithFence({
38704
39312
  client,
38705
39313
  db,
@@ -38723,7 +39331,7 @@ async function runHistorianPrompt(args) {
38723
39331
  query: { directory: sessionDirectory },
38724
39332
  body: {
38725
39333
  agent: agentId,
38726
- ...modelOverride ? { model: modelOverride } : {},
39334
+ ...modelBodyField(modelOverride),
38727
39335
  parts: [{ type: "text", text: prompt, synthetic: true }]
38728
39336
  }
38729
39337
  }, {
@@ -38793,10 +39401,21 @@ async function runHistorianPrompt(args) {
38793
39401
  async function runFallbackHistorianPass(args) {
38794
39402
  const seen = new Set;
38795
39403
  const chain = [];
38796
- for (const candidate of [...args.fallbackModels ?? [], args.fallbackModelId ?? ""]) {
38797
- if (!candidate || seen.has(candidate))
39404
+ const primary = toModelEntry(args.model);
39405
+ for (const candidateInput of [
39406
+ ...args.fallbackModels ?? [],
39407
+ ...args.fallbackModelId ? [{ model: args.fallbackModelId }] : []
39408
+ ]) {
39409
+ const candidate = toModelEntry(candidateInput);
39410
+ if (!candidate)
39411
+ continue;
39412
+ const key = `${candidate.model}\x00${candidate.qualifier ?? ""}`;
39413
+ if (!candidate.model || seen.has(key))
38798
39414
  continue;
38799
- seen.add(candidate);
39415
+ if (primary?.model === candidate.model && primary.qualifier === candidate.qualifier) {
39416
+ continue;
39417
+ }
39418
+ seen.add(key);
38800
39419
  chain.push(candidate);
38801
39420
  }
38802
39421
  if (chain.length === 0) {
@@ -38804,9 +39423,9 @@ async function runFallbackHistorianPass(args) {
38804
39423
  }
38805
39424
  let lastError = args.error;
38806
39425
  for (let i = 0;i < chain.length; i += 1) {
38807
- const modelId = chain[i];
38808
- const modelOverride = parseModelOverride(modelId);
38809
- if (!modelOverride)
39426
+ const modelOverride = chain[i];
39427
+ const modelId = modelOverride.model;
39428
+ if (!parseModelOverride(modelId))
38810
39429
  continue;
38811
39430
  const isSessionModelLastResort = modelId === args.fallbackModelId && i === chain.length - 1;
38812
39431
  sessionLog(args.parentSessionId, `compartment agent: retrying historian with ${modelId} (${isSessionModelLastResort ? "session-model last resort" : "configured fallback"} ${i + 1}/${chain.length})`);
@@ -40351,6 +40970,7 @@ function isDroppedPlaceholder(text) {
40351
40970
  }
40352
40971
  var EMPTY_HARD_SIGNALS = {
40353
40972
  systemHash: "",
40973
+ toolSetHash: "",
40354
40974
  modelKey: "",
40355
40975
  cacheExpired: false,
40356
40976
  lastResponseTime: 0
@@ -40654,6 +41274,7 @@ function readCurrentM0SnapshotMarkersUncached(args) {
40654
41274
  upgradeState: getUpgradeState(args.db, args.sessionId),
40655
41275
  compartmentRenderEpoch: COMPARTMENT_RENDER_EPOCH,
40656
41276
  systemHash: hard.systemHash,
41277
+ toolSetHash: hard.toolSetHash ?? "",
40657
41278
  modelKey: piModelRefToCanonical(hard.modelKey),
40658
41279
  projectIdentity: args.projectPath ?? null,
40659
41280
  muralEnabled: args.muralEnabled === true,
@@ -40669,6 +41290,7 @@ function refreshVolatileMarkerInputs(markers, args) {
40669
41290
  projectDocsHash: projectDirectory && args.injectDocs !== false ? computeProjectDocsHash(projectDirectory) : "",
40670
41291
  materializedAt: Date.now(),
40671
41292
  systemHash: hard.systemHash,
41293
+ toolSetHash: hard.toolSetHash ?? "",
40672
41294
  modelKey: hard.modelKey,
40673
41295
  projectIdentity: args.projectPath ?? null,
40674
41296
  muralEnabled: args.muralEnabled === true,
@@ -40736,6 +41358,7 @@ function snapshotMarkersFromCachedM0(state2) {
40736
41358
  upgradeState: cachedUpgradeIdentity.upgradeState,
40737
41359
  compartmentRenderEpoch: cachedUpgradeIdentity.compartmentRenderEpoch,
40738
41360
  systemHash: state2.cachedM0SystemHash ?? "",
41361
+ toolSetHash: state2.cachedM0ToolSetHash ?? "",
40739
41362
  modelKey: state2.cachedM0ModelKey ?? "",
40740
41363
  projectIdentity: state2.cachedM0ProjectIdentity ?? null,
40741
41364
  muralHash: state2.cachedM0MuralHash ?? null,
@@ -40776,8 +41399,14 @@ function mustMaterialize(args) {
40776
41399
  systemHashNew: hard.systemHash
40777
41400
  };
40778
41401
  }
41402
+ const liveToolSetHash = hard.toolSetHash ?? "";
41403
+ const toolSetHashComparison = liveToolSetHash !== "" ? {
41404
+ m0ToolSetHashPrev: args.state.cachedM0ToolSetHash,
41405
+ m0ToolSetHashNew: liveToolSetHash
41406
+ } : null;
41407
+ const withToolSetHashComparison = (decision) => toolSetHashComparison ? { ...decision, ...toolSetHashComparison } : decision;
40779
41408
  if (hard.cacheExpired && hard.lastResponseTime > 0 && hard.lastResponseTime > (args.state.cachedM0MaterializedAt ?? 0)) {
40780
- return { value: true, reason: "ttl_idle" };
41409
+ return withToolSetHashComparison({ value: true, reason: "ttl_idle" });
40781
41410
  }
40782
41411
  if (current.projectIdentity !== null) {
40783
41412
  const cachedProjectIdentity = args.state.cachedM0ProjectIdentity ?? null;
@@ -40785,23 +41414,23 @@ function mustMaterialize(args) {
40785
41414
  args.state.cachedM0ProjectIdentity = current.projectIdentity;
40786
41415
  args.db.prepare("UPDATE session_meta SET cached_m0_project_identity = ? WHERE session_id = ?").run(current.projectIdentity, args.sessionId);
40787
41416
  } else if (cachedProjectIdentity !== current.projectIdentity) {
40788
- return { value: true, reason: "project_change" };
41417
+ return withToolSetHashComparison({ value: true, reason: "project_change" });
40789
41418
  }
40790
41419
  }
40791
41420
  if (current.workspaceFingerprint !== null || (args.state.cachedM0WorkspaceFingerprint ?? null) !== null) {
40792
41421
  if ((args.state.cachedM0WorkspaceFingerprint ?? null) !== current.workspaceFingerprint) {
40793
- return { value: true, reason: "project_memory_epoch" };
41422
+ return withToolSetHashComparison({ value: true, reason: "project_memory_epoch" });
40794
41423
  }
40795
41424
  } else if (args.state.cachedM0ProjectMemoryEpoch !== current.projectMemoryEpoch) {
40796
41425
  return { value: true, reason: "project_memory_epoch" };
40797
41426
  }
40798
41427
  if (args.state.cachedM0MaxMutationId !== current.maxMutationId) {
40799
- return { value: true, reason: "max_mutation_id" };
41428
+ return withToolSetHashComparison({ value: true, reason: "max_mutation_id" });
40800
41429
  }
40801
41430
  if (cachedUpgradeIdentity.upgradeState !== current.upgradeState) {
40802
- return { value: true, reason: "upgrade_state" };
41431
+ return withToolSetHashComparison({ value: true, reason: "upgrade_state" });
40803
41432
  }
40804
- return { value: false, reason: null };
41433
+ return withToolSetHashComparison({ value: false, reason: null });
40805
41434
  }
40806
41435
  function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions = {}) {
40807
41436
  const selectionOrder = [...memories].sort(memorySelectionOrder);
@@ -41088,6 +41717,7 @@ function applyMarkersToState(state2, m0Bytes, markers, m1Bytes) {
41088
41717
  state2.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
41089
41718
  state2.cachedM0UpgradeState = encodeCachedM0UpgradeIdentity(markers.upgradeState, markers.compartmentRenderEpoch, markers.muralEnabled, markers.renderBudgetIdentity);
41090
41719
  state2.cachedM0SystemHash = markers.systemHash;
41720
+ state2.cachedM0ToolSetHash = markers.toolSetHash;
41091
41721
  state2.cachedM0ModelKey = markers.modelKey;
41092
41722
  state2.cachedM0ProjectIdentity = markers.projectIdentity;
41093
41723
  state2.cachedM0MuralHash = markers.muralHash ?? null;
@@ -41230,6 +41860,7 @@ function materializeM0(options) {
41230
41860
  upgradeState: getUpgradeState(options.db, options.sessionId),
41231
41861
  compartmentRenderEpoch: COMPARTMENT_RENDER_EPOCH,
41232
41862
  systemHash: snapshotMarkers.systemHash,
41863
+ toolSetHash: snapshotMarkers.toolSetHash,
41233
41864
  modelKey: snapshotMarkers.modelKey,
41234
41865
  projectIdentity: projectPath ?? null,
41235
41866
  muralEnabled: snapshotMarkers.muralEnabled,
@@ -41270,6 +41901,7 @@ function materializeM0(options) {
41270
41901
  sessionFactsVersion: snapshotMarkers.sessionFactsVersion,
41271
41902
  upgradeState: encodeCachedM0UpgradeIdentity(snapshotMarkers.upgradeState, snapshotMarkers.compartmentRenderEpoch, snapshotMarkers.muralEnabled, snapshotMarkers.renderBudgetIdentity),
41272
41903
  systemHash: snapshotMarkers.systemHash,
41904
+ toolSetHash: snapshotMarkers.toolSetHash,
41273
41905
  modelKey: snapshotMarkers.modelKey,
41274
41906
  projectIdentity: snapshotMarkers.projectIdentity
41275
41907
  });
@@ -41466,9 +42098,10 @@ function readCachedM0M1Row(db, sessionId) {
41466
42098
  cached_m0_project_docs_hash,
41467
42099
  cached_m0_materialized_at,
41468
42100
  cached_m0_session_facts_version,
41469
- cached_m0_upgrade_state,
41470
- cached_m0_system_hash,
41471
- cached_m0_model_key,
42101
+ cached_m0_upgrade_state,
42102
+ cached_m0_system_hash,
42103
+ cached_m0_tool_set_hash,
42104
+ cached_m0_model_key,
41472
42105
  cached_m0_project_identity,
41473
42106
  memory_block_ids
41474
42107
  FROM session_meta
@@ -41506,6 +42139,7 @@ function markersFromCachedRow(row) {
41506
42139
  upgradeState: cachedUpgradeIdentity.upgradeState,
41507
42140
  compartmentRenderEpoch: cachedUpgradeIdentity.compartmentRenderEpoch,
41508
42141
  systemHash: row.cached_m0_system_hash ?? "",
42142
+ toolSetHash: row.cached_m0_tool_set_hash ?? "",
41509
42143
  modelKey: row.cached_m0_model_key ?? "",
41510
42144
  projectIdentity: row.cached_m0_project_identity ?? null,
41511
42145
  muralHash: row.cached_m0_mural_hash ?? null,
@@ -41514,7 +42148,7 @@ function markersFromCachedRow(row) {
41514
42148
  };
41515
42149
  }
41516
42150
  function cachedRowMatchesState(row, state2) {
41517
- return bufferEqualsNullable(row.cached_m0_bytes, state2.cachedM0Bytes) && (row.cached_m0_mural_data_url ?? null) === (state2.cachedM0MuralDataUrl ?? null) && (row.cached_m0_mural_hash ?? null) === (state2.cachedM0MuralHash ?? null) && row.cached_m0_project_memory_epoch === state2.cachedM0ProjectMemoryEpoch && (row.cached_m0_workspace_fingerprint ?? null) === (state2.cachedM0WorkspaceFingerprint ?? null) && row.cached_m0_project_user_profile_version === state2.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state2.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state2.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state2.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state2.cachedM0MaxMemoryMutationId && row.cached_m0_materialized_at === state2.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state2.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state2.cachedM0UpgradeState ?? null) && (row.cached_m0_system_hash ?? "") === (state2.cachedM0SystemHash ?? "") && piModelRefToCanonical(row.cached_m0_model_key ?? "") === piModelRefToCanonical(state2.cachedM0ModelKey ?? "") && (row.cached_m0_project_identity ?? null) === (state2.cachedM0ProjectIdentity ?? null);
42151
+ return bufferEqualsNullable(row.cached_m0_bytes, state2.cachedM0Bytes) && (row.cached_m0_mural_data_url ?? null) === (state2.cachedM0MuralDataUrl ?? null) && (row.cached_m0_mural_hash ?? null) === (state2.cachedM0MuralHash ?? null) && row.cached_m0_project_memory_epoch === state2.cachedM0ProjectMemoryEpoch && (row.cached_m0_workspace_fingerprint ?? null) === (state2.cachedM0WorkspaceFingerprint ?? null) && row.cached_m0_project_user_profile_version === state2.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state2.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state2.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state2.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state2.cachedM0MaxMemoryMutationId && row.cached_m0_materialized_at === state2.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state2.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state2.cachedM0UpgradeState ?? null) && (row.cached_m0_system_hash ?? "") === (state2.cachedM0SystemHash ?? "") && (row.cached_m0_tool_set_hash ?? "") === (state2.cachedM0ToolSetHash ?? "") && piModelRefToCanonical(row.cached_m0_model_key ?? "") === piModelRefToCanonical(state2.cachedM0ModelKey ?? "") && (row.cached_m0_project_identity ?? null) === (state2.cachedM0ProjectIdentity ?? null);
41518
42152
  }
41519
42153
  function applyCachedRowToState(state2, row) {
41520
42154
  const markers = markersFromCachedRow(row);
@@ -41537,6 +42171,7 @@ function applyCachedRowToState(state2, row) {
41537
42171
  state2.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
41538
42172
  state2.cachedM0UpgradeState = encodeCachedM0UpgradeIdentity(markers.upgradeState, markers.compartmentRenderEpoch, markers.muralEnabled, markers.renderBudgetIdentity);
41539
42173
  state2.cachedM0SystemHash = markers.systemHash;
42174
+ state2.cachedM0ToolSetHash = markers.toolSetHash;
41540
42175
  state2.cachedM0ModelKey = markers.modelKey;
41541
42176
  state2.cachedM0ProjectIdentity = markers.projectIdentity;
41542
42177
  state2.snapshotMarkers = markers;
@@ -45006,6 +45641,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
45006
45641
  sequenceOffset: candidateCompartments.length,
45007
45642
  dumpLabelBase: `recomp-${sessionId}-${chunk.startIndex}-${chunk.endIndex}-pass-${passCount + 1}`,
45008
45643
  timeoutMs: historianTimeoutMs,
45644
+ model: deps.model,
45009
45645
  fallbackModelId: deps.fallbackModelId,
45010
45646
  fallbackModels: deps.fallbackModels,
45011
45647
  twoPass: deps.historianTwoPass,
@@ -45426,6 +46062,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
45426
46062
  sequenceOffset: candidateCompartments.length,
45427
46063
  dumpLabelBase: `partial-recomp-${sessionId}-${chunk.startIndex}-${chunk.endIndex}-pass-${passCount + 1}`,
45428
46064
  timeoutMs: historianTimeoutMs,
46065
+ model: deps.model,
45429
46066
  fallbackModelId: deps.fallbackModelId,
45430
46067
  fallbackModels: deps.fallbackModels,
45431
46068
  twoPass: deps.historianTwoPass,
@@ -45675,6 +46312,10 @@ var LKG_SINGLE_SLOT_BYTES = 24 * 1024 * 1024;
45675
46312
  var LKG_METADATA_BYTES = 256;
45676
46313
  var slots = new Map;
45677
46314
  var totalBytes = 0;
46315
+ var persistenceBackend;
46316
+ function registerLkgPersistence(backend) {
46317
+ persistenceBackend = backend;
46318
+ }
45678
46319
  function slotBytes(slot) {
45679
46320
  const digestBytes = slot.inputContentDigests.reduce((total, digest) => total + 2 * digest.length, 0);
45680
46321
  return 2 * slot.jsonPrefix.length + digestBytes + LKG_METADATA_BYTES;
@@ -45808,24 +46449,91 @@ function captureSlot(sessionId, slot) {
45808
46449
  totalBytes += bytes;
45809
46450
  return true;
45810
46451
  }
46452
+ function installHydratedSlot(sessionId, slot) {
46453
+ const bytes = slotBytes(slot);
46454
+ if (bytes > LKG_SINGLE_SLOT_BYTES)
46455
+ return false;
46456
+ const prior = slots.get(sessionId);
46457
+ if (prior)
46458
+ totalBytes -= prior.bytes;
46459
+ slots.delete(sessionId);
46460
+ while (totalBytes + bytes > LKG_TOTAL_BYTES) {
46461
+ const oldest = slots.keys().next().value;
46462
+ if (oldest === undefined)
46463
+ break;
46464
+ const evicted = slots.get(oldest);
46465
+ slots.delete(oldest);
46466
+ if (evicted)
46467
+ totalBytes -= evicted.bytes;
46468
+ }
46469
+ if (totalBytes + bytes > LKG_TOTAL_BYTES) {
46470
+ if (prior) {
46471
+ slots.set(sessionId, prior);
46472
+ totalBytes += prior.bytes;
46473
+ }
46474
+ return false;
46475
+ }
46476
+ const entry = {
46477
+ slot: {
46478
+ ...slot,
46479
+ inputIdSeq: [...slot.inputIdSeq],
46480
+ inputContentDigests: [...slot.inputContentDigests],
46481
+ inputContentSignatures: slot.inputContentSignatures ? [...slot.inputContentSignatures] : undefined
46482
+ },
46483
+ bytes
46484
+ };
46485
+ slots.set(sessionId, entry);
46486
+ totalBytes += bytes;
46487
+ return true;
46488
+ }
46489
+ function hydrateSlotFromPersistence(sessionId) {
46490
+ const backend = persistenceBackend;
46491
+ if (!backend)
46492
+ return;
46493
+ let loaded;
46494
+ try {
46495
+ loaded = backend.load(sessionId);
46496
+ } catch (error51) {
46497
+ sessionLog(sessionId, "LKG durable hydration failed:", error51);
46498
+ return;
46499
+ }
46500
+ if (!loaded)
46501
+ return;
46502
+ if (!installHydratedSlot(sessionId, loaded))
46503
+ return;
46504
+ sessionLog(sessionId, "lkg_hydrated_from_disk");
46505
+ const entry = slots.get(sessionId);
46506
+ return entry ? copySlotForRead(entry.slot) : undefined;
46507
+ }
46508
+ function copySlotForRead(slot) {
46509
+ return {
46510
+ ...slot,
46511
+ inputIdSeq: [...slot.inputIdSeq],
46512
+ inputContentDigests: [...slot.inputContentDigests],
46513
+ inputContentSignatures: slot.inputContentSignatures ? [...slot.inputContentSignatures] : undefined
46514
+ };
46515
+ }
45811
46516
  function getSlot(sessionId) {
45812
46517
  const entry = slots.get(sessionId);
45813
46518
  if (!entry)
45814
- return;
46519
+ return hydrateSlotFromPersistence(sessionId);
45815
46520
  touch(sessionId, entry);
45816
- return {
45817
- ...entry.slot,
45818
- inputIdSeq: [...entry.slot.inputIdSeq],
45819
- inputContentDigests: [...entry.slot.inputContentDigests],
45820
- inputContentSignatures: entry.slot.inputContentSignatures ? [...entry.slot.inputContentSignatures] : undefined
45821
- };
46521
+ return copySlotForRead(entry.slot);
45822
46522
  }
45823
46523
  function dropSlot(sessionId, _reason) {
45824
46524
  const entry = slots.get(sessionId);
45825
- if (!entry)
46525
+ if (entry) {
46526
+ slots.delete(sessionId);
46527
+ totalBytes -= entry.bytes;
46528
+ }
46529
+ const backend = persistenceBackend;
46530
+ if (!backend)
45826
46531
  return;
45827
- slots.delete(sessionId);
45828
- totalBytes -= entry.bytes;
46532
+ try {
46533
+ backend.clear(sessionId);
46534
+ } catch (error51) {
46535
+ sessionLog(sessionId, "LKG durable clear failed:", error51);
46536
+ }
45829
46537
  }
45830
46538
  function noteEntry(sessionId, messages) {
45831
46539
  const slot = getSlot(sessionId);
@@ -45938,6 +46646,7 @@ function buildRecompDeps(ctx, sessionId) {
45938
46646
  directory: ctx.directory,
45939
46647
  memoryEnabled: ctx.memoryEnabled,
45940
46648
  autoPromote: ctx.autoPromote,
46649
+ model: ctx.historianModel,
45941
46650
  fallbackModels: ctx.fallbackModels,
45942
46651
  language: ctx.language,
45943
46652
  fallbackModelId: ctx.fallbackModelId ?? resolveLiveModelKey(ctx.liveSessionState, sessionId),
@@ -46076,7 +46785,7 @@ async function runUpgradeMemoryMigration(ctx, sessionId, migrationDirectory) {
46076
46785
  directory: migrationDirectory,
46077
46786
  parentSessionId: sessionId,
46078
46787
  primaryModelId: ctx.fallbackModelId ?? resolveLiveModelKey(ctx.liveSessionState, sessionId),
46079
- fallbackModels: ctx.fallbackModels,
46788
+ fallbackModels: ctx.fallbackModels.map((entry) => typeof entry === "string" ? entry : entry.model),
46080
46789
  timeoutMs: ctx.historianTimeoutMs,
46081
46790
  userMemoriesEnabled: ctx.userMemoriesEnabled,
46082
46791
  language: ctx.language
@@ -46087,4 +46796,4 @@ async function runUpgradeMemoryMigration(ctx, sessionId, migrationDirectory) {
46087
46796
  }
46088
46797
  }
46089
46798
 
46090
- export { withContentLanguageDirective, buildPrimaryLanguageDirective, cortexKitUserConfigBasePath, cortexKitProjectConfigBasePath, resolveLegacyConfigSources, resolveLegacyConfigSourcesForHarness, migrateMagicContextConfigLocations, exports_external, DEFAULT_PROTECTED_TAGS, parseCron, nextOccurrence, nextDueAtMs, promptSurfaceConfigIdentity, resolvePromptSurface, resolveModelConfigOrDefault, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, DEFAULT_LOCAL_EMBEDDING_MODEL, MagicContextConfigSchema, getOpenCodeDbPath, removeMcOwnedCompactionMarkers, isFailClosedBlockingError, shouldBypassFailClosedBlock, resolveAgentNameFromMessages, createFailClosedController, recordHookInitFailure, clearHookInitFailure, getLastHookInitFailure, ProjectIdentityError, resolveProjectIdentityStrict, takeDubiousOwnershipProjectIdentityWarning, resolveProjectIdentity, resolveProjectIdentityForSession, normalizeStoredProjectPath, storedPathBelongsToIdentity, isLinkedGitWorktree, recordSessionProjectIdentity, beginBootQuietPeriod, bootQuietRemainingMs, scheduleAfterBootQuiet, rpcPortDir, rpcPortFilePath, isPidAlive, parseRpcPortFile, registerModuleNoteEvaluationBridge, getModuleNoteEvaluationBridge, getContextStoreUuid, ensureContextStoreUuid, getAuthorityManagedMarker, reconcileAuthorityProject, checksumAuthoritySeedRows, prepareAuthority, drainAuthority, getMirrorCursor, applyMirroredNoteCompileFields, applyMirrorPage, pullMemoryMirrorOnce, V2_MEMORY_CATEGORIES, CATEGORY_PRIORITY, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, resolveStoredPathWorkspaceIdentity, storedPathBelongsToWorkspace, sourceNameForMemory, computeWorkspaceEpochFingerprint, textMentionsRecentCommit, hasMeaningfulUserText, extractTexts, extractToolCallSummaries, preloadTokenizer, estimateTokens, normalizeText, recordToolDefinition, getMeasuredToolDefinitionTokens, getSchemaFenceRejection, getMigrationOnOpenRefusal, LATEST_SUPPORTED_VERSION, getDatabasePath, getPersistedSchemaVersion, setSqlitePragmaConfig, runSqliteOptimize, openDatabase, openDatabaseAsync, isDatabasePersisted, getDatabasePersistenceError, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLease, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, clearRecompStaging, isRawCompactionSummaryInfo, extractInMemoryMessageViews, buildInMemoryTailRawMessages, isRecord, estimateTrueRawMessageTokens, invalidateTrueRawTokenCache, stripPersistedAssistantText, byteSize, stripTagPrefix, prependTag, isThinkingPart, isTextPart, isToolPartWithOutput, isFilePart, buildFileSourceContent, isEditTool, partHasCompletedResult, extractToolCallObservation, ToolMutationBatch, createToolDropTarget, setRawMessageProvider, cleanUserText, withRawSessionMessageCache, readRawSessionMessages, primeTailRawMessageCache, primeInMemoryTailRawMessageCache, readRawSessionMessageOrdinalPage, getRawSessionStoredMessageCount, readRawSessionMessagePartsById, readRawSessionMessageOrdinalById, readRawSessionMessageById, readSessionChunk, getMessageIndexSourceIdentity, isMessageIndexSourceCurrent, getLastIndexedOrdinal, getIndexedMessageCorpusSize, getMessageIndexReconciliationStartOrdinal, isMessageIndexReconciledThrough, deleteIndexedMessage, clearIndexedMessages, indexSingleMessage, indexMessagesAfterOrdinal, sweepOrphanedOpenCodeMessageIndexes, recordEmbeddingMeasurement, getMaxM0MutationId, queueMemoryMutation, getMemoryMutationsForRenderByProjects, getMaxMemoryMutationIdForProjects, MAX_EXECUTE_THRESHOLD, escalationBands, isEmergencyRecoveryArmed, isProviderOverflowReconfirmed, getEmergencyRecoveryArmedAt, loadPersistedUsage, loadProtectedTailMeta, resetProtectedTailNoEligibleHead, getWrapupInProgressState, acquireWrapupInProgress, updateWrapupInProgress, releaseWrapupInProgress, resolveCompactionModeRecord, getCompactionModeRecord, setCompactionModeRecord, getPersistedReasoningWatermark, setPersistedReasoningWatermark, clearPersistedReasoningWatermark, getEmergencyInputSample, setEmergencyDropSample, clearEmergencyDropSample, getLastNudgeUndropped, setLastNudgeUndropped, getLastNudgeLevel, setLastNudgeLevel, resetLastNudgeCycle, resetLastNudgeCycleIfTailShrank, getChannel2NudgeState, getChannel2NudgeClaim, setChannel2NudgeState, casChannel2NudgeState, claimChannel2NudgeState, casChannel2NudgeClaim, getPersistedNoteNudge, getNoteNudgeAnchors, getAutoSearchHintDecisions, appendAutoSearchHintDecision, pruneNoteNudgeAnchors, pruneAutoSearchHintDecisions, removeNoteNudgeAnchorByMessageId, removeAutoSearchHintDecisionByMessageId, getPersistedTodoPermissionDenied, setPersistedTodoPermissionDenied, getPersistedTodoSyntheticAnchor, setPersistedTodoSyntheticAnchor, clearPersistedTodoSyntheticAnchor, setNoteLastReadAt, getHistorianFailureState, clearHistorianFailureState, getOverflowState, recordOverflowDetected, recordDetectedContextLimit, clearEmergencyRecovery, clearDetectedContextLimit, getPersistedCompactionMarkerState, setPersistedCompactionMarkerState, getStrippedPlaceholderIds, applyStrippedPlaceholderDelta, removeStrippedPlaceholderId, getMergedReasoningStrippedIds, addMergedReasoningStrippedIds, getTrailingBlankDecisions, addTrailingBlankDecisions, getStaleReduceStrippedIds, addStaleReduceStrippedIds, getProcessedImageStrippedIds, addProcessedImageStrippedIds, getPendingCompactionMarkerState, clearPendingCompactionMarkerStateIf, peekDeferredExecutePending, setDeferredExecutePendingIfAbsent, clearDeferredExecutePendingIfMatches, getSessionsWithPendingMarker, setSessionWorkMetrics, getNotes, addNote, getSessionNotes, getPendingSmartNotes, getReadySmartNotes, updateNote, dismissNote, markNoteReady, markNoteChecked, queuePendingOp, getPendingOps, clearPendingOps, removePendingOp, PRIMER_CANDIDATE_TTL_MS, PRIMER_CANDIDATE_MAX_AGE_MS, primerOccurrenceKey, primerOccurrenceUtcDay, updatePrimerCandidateEmbedding, getPrimerCandidatesByIds, getPrimerCandidatesForPromotion, countPrimerCandidatesForProject, getActivePrimers, createPrimer, updatePrimerSupport, updatePrimerAnswer, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectMemoryEpoch, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, CTX_REDUCE_KEEP, estimateImageTokensFromDataUrl, normalizeTodoStateJson, buildSyntheticTodoPart, computeSyntheticCallId, isSyntheticTodoPart, tailHygieneStructuralSignature, sameTailHygieneStructuralSignature, refreshTailHygieneBaseline, effectiveTailHygiene, assertTailHygieneContentUnchanged, CHANNEL1_SENTINEL, CHANNEL1_FLOOR_TOKENS, toolOutputTokens, decideChannel1, evaluateChannel2, buildChannel2Reminder, buildChannel1Reminder, estimateEmergencyDropReclaimTokens, planEmergencyDrop, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, getActiveTagTokenTotalsByMessage, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, updateTagDropMode, updateCavemanDepth, updateTagMessageId, deleteTagsByMessageId, getMaxTagNumberBySession, getTagNumberByMessageId, deriveTagLoadFloor, getTagsBySession, getActiveTagsBySession, getTailHygieneTags, getDroppedTagsBySession, getTagsByNumbers, getMaxDroppedTagNumber, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, getCandidateToolOwners, pickNearestPriorOwner, createChildSessionWithFence, detectOverflow, promptSyncWithValidatedOutputRetry, normalizeSDKResponse, promptSurfaceHashMaterial, createPromptSurfaceRuntime, createPromptSurfaceGuidanceEpochCache, extractLatestAssistantText, hasLengthCappedOutput, setKeepSubagents, shouldKeepSubagents, recordChildInvocation, COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_EDITOR_SYSTEM_PROMPT, COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT, Priority, AdmissionClass, StaleRouteHandleError, SocketClosedError, SocketTimeoutError, SubcClient, isConsumerReconnectTransient, connectionFileExists, getCompartmentEvents, loadCompartmentChunkEmbeddingsForSearch, cosineSimilarity, SYNAPSE_DEFAULT_MODEL, SynapseEmbeddingProvider, computeNormalizedHash, saveCommitEmbedding, loadProjectCommitEmbeddings, loadUnembeddedCommits, countEmbeddedCommits, upsertCommits, getLatestIndexedCommitTimeMs, enforceProjectCap, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, saveEmbeddingIfHashMatches, getProjectEmbeddings, peekProjectEmbeddings, invalidateProject, invalidateMemory, markProjectLoadUntrusted, contentSha256, sweepStaleEmbeddingIdentitiesForProject, registerProjectEmbedding, registerProjectShadowEmbedding, getShadowEmbeddingMeasurementCohort, getPrimaryEmbeddingMeasurementCohort, embedShadowTextForProject, enqueueShadowEmbeddingItems, registerProjectInObservationMode, getProjectEmbeddingSnapshot, embedTextForProject, embedBatchForProject, embedItemsForProject, embedUnembeddedMemoriesForProject, drainCommitBacklogForProject, embedSessionCompartmentChunks, getEmbeddingCoverageStatus, isEmbeddingEnabled, embedText, ensureMemoryEmbeddings, computeCueContentHash, hasMuralCueColumns, getMuralCueState, memoryNeedsCue, setMuralCue, recordMuralCueRejection, hasMemoryShareableColumn, hasMemoryClassifiedAtColumn, getUnclassifiedMemoryIds, ModuleMemoryAuthorityError, insertMemory, insertMemoryIdempotent, getMemoryByHash, getMemoriesByProject, buildWorkspaceMemorySqlFilter, getMemoriesByProjects, getMaxMemoryIdForProjects, readNewMemoriesForM1Union, getMemoryById, getMemoriesByIds, updateMemorySeenCount, updateMemoryRetrievalCount, setMemoryClassification, supersededMemory, mergeMemoryStats, archiveMemory, getMemoryCountsByStatus, sanitizeFtsQuery, searchMemoriesFTS, searchMemoriesFTSUnion, recordMemoryMapping, recordMemoryVerifications, getUnmappedMemoryIds, clearMemoryVerifications, getMemoryVerifications, resolveGitTopLevel, readGitHead, readGitChangedFilesSince, readGitFileChangeTimesSince, verificationFileExists, normalizeVerificationFiles, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, MARKER_SUMMARY_TEXT, applyDeferredCompactionMarker, removeCompactionMarkerForSession, checkCompactionMarkerConsistency, getMural, resolveMuralWire, BoundedSessionMap, extractM0Block, formatDate, injectTemporalMarkers, clearInjectionCache, getVisibleMemoryIds, prepareCompartmentInjection, renderCompartmentInjection, mustMaterialize, trimMemoriesToBudgetV2, renderMemoryBlockV2, injectM0M1, onNoteTrigger, peekNoteNudgeText, markNoteNudgeDelivered, clearNoteNudgeTriggerAndCooldown, resetNoteNudgeCooldownOnly, clearNoteNudgeTriggerOnly, RECOVERY_NO_HEAD_LIMIT, resolveOpenCodeProtectedTailBoundary, resolveWrapupProtectedTailBoundary, getRawHistoryEligibility, hasRunnableCompartmentWindow, recordHighPressureNoEligibleHead, runCompartmentAgent, snapRangeToCompartments, LKG_SNAPSHOT_ARRAY, LKG_SNAPSHOT_OBJECT, LKG_SNAPSHOT_KEY, LKG_SNAPSHOT_STRING, LKG_SNAPSHOT_NUMBER, LKG_SNAPSHOT_BOOLEAN, LKG_SNAPSHOT_NULL, LKG_SNAPSHOT_UNDEFINED, incrementalLkgContentDigests, lkgContentDigest, captureSlot, getSlot, dropSlot, noteEntry, getActiveCompartmentRun, markActiveCompartmentRunPublished, registerActiveCompartmentRun, startCompartmentAgent, isRecompFailure, isRecompSkip, isRecompComplete, extractRecompReason, contextualizeUpgradeReason, setRecompStarting, setRecompNote, setRecompTerminal, runManagedRecomp, runManagedUpgrade };
46799
+ export { withContentLanguageDirective, buildPrimaryLanguageDirective, cortexKitUserConfigBasePath, cortexKitProjectConfigBasePath, resolveLegacyConfigSources, resolveLegacyConfigSourcesForHarness, migrateMagicContextConfigLocations, exports_external, DEFAULT_PROTECTED_TAGS, parseCron, nextOccurrence, nextDueAtMs, promptSurfaceConfigIdentity, resolvePromptSurface, resolveModelConfigOrDefault, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, DEFAULT_LOCAL_EMBEDDING_MODEL, PER_HARNESS_MIGRATION_INVENTORY, ConfigProfilesSchema, MagicContextConfigSchema, getOpenCodeDbPath, removeMcOwnedCompactionMarkers, hasShareabilitySensitiveText, isFailClosedBlockingError, shouldBypassFailClosedBlock, resolveAgentNameFromMessages, createFailClosedController, recordHookInitFailure, clearHookInitFailure, getLastHookInitFailure, ProjectIdentityError, resolveProjectIdentityStrict, takeDubiousOwnershipProjectIdentityWarning, resolveProjectIdentity, resolveProjectIdentityForSession, normalizeStoredProjectPath, storedPathBelongsToIdentity, isLinkedGitWorktree, recordSessionProjectIdentity, beginBootQuietPeriod, bootQuietRemainingMs, scheduleAfterBootQuiet, rpcPortDir, rpcPortFilePath, isPidAlive, parseRpcPortFile, registerModuleNoteEvaluationBridge, getModuleNoteEvaluationBridge, getContextStoreUuid, ensureContextStoreUuid, getAuthorityManagedMarker, reconcileAuthorityProject, checksumAuthoritySeedRows, prepareAuthority, drainAuthority, getMirrorCursor, applyMirroredNoteCompileFields, applyMirrorPage, pullMemoryMirrorOnce, V2_MEMORY_CATEGORIES, CATEGORY_PRIORITY, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, resolveStoredPathWorkspaceIdentity, storedPathBelongsToWorkspace, sourceNameForMemory, computeWorkspaceEpochFingerprint, textMentionsRecentCommit, hasMeaningfulUserText, extractTexts, extractToolCallSummaries, preloadTokenizer, estimateTokens, normalizeText, getCurrentToolSetHash, recordToolDefinition, getMeasuredToolDefinitionTokens, getSchemaFenceRejection, getMigrationOnOpenRefusal, LATEST_SUPPORTED_VERSION, getDatabasePath, getPersistedSchemaVersion, setSqlitePragmaConfig, runSqliteOptimize, openDatabase, openDatabaseAsync, isDatabasePersisted, getDatabasePersistenceError, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLease, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, clearRecompStaging, isRawCompactionSummaryInfo, extractInMemoryMessageViews, buildInMemoryTailRawMessages, isRecord, estimateTrueRawMessageTokens, invalidateTrueRawTokenCache, stripPersistedAssistantText, byteSize, stripTagPrefix, prependTag, isThinkingPart, isTextPart, isToolPartWithOutput, isFilePart, buildFileSourceContent, isEditTool, partHasCompletedResult, extractToolCallObservation, ToolMutationBatch, createToolDropTarget, setRawMessageProvider, cleanUserText, withRawSessionMessageCache, readRawSessionMessages, primeTailRawMessageCache, primeInMemoryTailRawMessageCache, readRawSessionMessageOrdinalPage, getRawSessionStoredMessageCount, readRawSessionMessagePartsById, readRawSessionMessageOrdinalById, readRawSessionMessageById, readSessionChunk, getMessageIndexSourceIdentity, isMessageIndexSourceCurrent, getLastIndexedOrdinal, getIndexedMessageCorpusSize, getMessageIndexReconciliationStartOrdinal, isMessageIndexReconciledThrough, deleteIndexedMessage, clearIndexedMessages, indexSingleMessage, indexMessagesAfterOrdinal, sweepOrphanedOpenCodeMessageIndexes, recordEmbeddingMeasurement, getMaxM0MutationId, queueMemoryMutation, getMemoryMutationsForRenderByProjects, getMaxMemoryMutationIdForProjects, MAX_EXECUTE_THRESHOLD, escalationBands, isEmergencyRecoveryArmed, isProviderOverflowReconfirmed, getEmergencyRecoveryArmedAt, loadPersistedUsage, loadProtectedTailMeta, resetProtectedTailNoEligibleHead, getWrapupInProgressState, acquireWrapupInProgress, updateWrapupInProgress, releaseWrapupInProgress, resolveCompactionModeRecord, getCompactionModeRecord, setCompactionModeRecord, getPersistedReasoningWatermark, setPersistedReasoningWatermark, clearPersistedReasoningWatermark, getEmergencyInputSample, setEmergencyDropSample, clearEmergencyDropSample, getLastNudgeUndropped, setLastNudgeUndropped, getChannel1NudgeState, setChannel1NudgeState, resetLastNudgeCycle, resetLastNudgeCycleIfTailShrank, getChannel2NudgeState, getChannel2NudgeClaim, setChannel2NudgeState, casChannel2NudgeState, claimChannel2NudgeState, casChannel2NudgeClaim, getPersistedNoteNudge, getNoteNudgeAnchors, getAutoSearchHintDecisions, appendAutoSearchHintDecision, pruneNoteNudgeAnchors, pruneAutoSearchHintDecisions, removeNoteNudgeAnchorByMessageId, removeAutoSearchHintDecisionByMessageId, getPersistedTodoPermissionDenied, setPersistedTodoPermissionDenied, getPersistedTodoSyntheticAnchor, setPersistedTodoSyntheticAnchor, clearPersistedTodoSyntheticAnchor, setNoteLastReadAt, getHistorianFailureState, clearHistorianFailureState, getOverflowState, recordOverflowDetected, recordDetectedContextLimit, clearEmergencyRecovery, clearDetectedContextLimit, getPersistedCompactionMarkerState, setPersistedCompactionMarkerState, getStrippedPlaceholderIds, applyStrippedPlaceholderDelta, removeStrippedPlaceholderId, getMergedReasoningStrippedIds, addMergedReasoningStrippedIds, getTrailingBlankDecisions, addTrailingBlankDecisions, getStaleReduceStrippedIds, addStaleReduceStrippedIds, getProcessedImageStrippedIds, addProcessedImageStrippedIds, getPendingCompactionMarkerState, clearPendingCompactionMarkerStateIf, peekDeferredExecutePending, setDeferredExecutePendingIfAbsent, clearDeferredExecutePendingIfMatches, getSessionsWithPendingMarker, setSessionWorkMetrics, getNotes, addNote, getSessionNotes, getPendingSmartNotes, getReadySmartNotes, updateNote, dismissNote, markNoteReady, markNoteChecked, queuePendingOp, getPendingOps, clearPendingOps, removePendingOp, PRIMER_CANDIDATE_TTL_MS, PRIMER_CANDIDATE_MAX_AGE_MS, primerOccurrenceKey, primerOccurrenceUtcDay, updatePrimerCandidateEmbedding, getPrimerCandidatesByIds, getPrimerCandidatesForPromotion, countPrimerCandidatesForProject, getActivePrimers, createPrimer, updatePrimerSupport, updatePrimerAnswer, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectMemoryEpoch, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, CTX_REDUCE_KEEP, estimateImageTokensFromDataUrl, normalizeTodoStateJson, buildSyntheticTodoPart, computeSyntheticCallId, isSyntheticTodoPart, countRealUserMessages, tailHygieneStructuralSignature, sameTailHygieneStructuralSignature, refreshTailHygieneBaseline, effectiveTailHygiene, assertTailHygieneContentUnchanged, CHANNEL1_SENTINEL, CHANNEL1_FLOOR_TOKENS, toolOutputTokens, decideChannel1, evaluateChannel2, buildChannel2Reminder, shouldUseStickyChannel1Reminder, buildChannel1Reminder, estimateEmergencyDropReclaimTokens, planEmergencyDrop, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, getActiveTagTokenTotalsByMessage, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, updateTagDropMode, updateCavemanDepth, updateTagMessageId, deleteTagsByMessageId, getMaxTagNumberBySession, getTagNumberByMessageId, deriveTagLoadFloor, getTagsBySession, getActiveTagsBySession, getTailHygieneTags, getDroppedTagsBySession, getTagsByNumbers, getMaxDroppedTagNumber, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, getCandidateToolOwners, pickNearestPriorOwner, createChildSessionWithFence, detectOverflow, resolveFallbackChain, modelBodyField, promptSyncWithValidatedOutputRetry, normalizeSDKResponse, promptSurfaceHashMaterial, createPromptSurfaceRuntime, createPromptSurfaceGuidanceEpochCache, extractLatestAssistantText, hasLengthCappedOutput, setKeepSubagents, shouldKeepSubagents, recordChildInvocation, COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_EDITOR_SYSTEM_PROMPT, COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT, Priority, AdmissionClass, StaleRouteHandleError, SocketClosedError, SocketTimeoutError, SubcClient, isConsumerReconnectTransient, connectionFileExists, getCompartmentEvents, loadCompartmentChunkEmbeddingsForSearch, cosineSimilarity, SYNAPSE_DEFAULT_MODEL, SynapseEmbeddingProvider, computeNormalizedHash, saveCommitEmbedding, loadProjectCommitEmbeddings, loadUnembeddedCommits, countEmbeddedCommits, upsertCommits, getLatestIndexedCommitTimeMs, enforceProjectCap, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, saveEmbeddingIfHashMatches, getProjectEmbeddings, peekProjectEmbeddings, invalidateProject, invalidateMemory, markProjectLoadUntrusted, contentSha256, sweepStaleEmbeddingIdentitiesForProject, registerProjectEmbedding, registerProjectShadowEmbedding, getShadowEmbeddingMeasurementCohort, getPrimaryEmbeddingMeasurementCohort, embedShadowTextForProject, enqueueShadowEmbeddingItems, registerProjectInObservationMode, getProjectEmbeddingSnapshot, embedTextForProject, embedBatchForProject, embedItemsForProject, embedUnembeddedMemoriesForProject, drainCommitBacklogForProject, embedSessionCompartmentChunks, getEmbeddingCoverageStatus, isEmbeddingEnabled, embedText, ensureMemoryEmbeddings, computeCueContentHash, hasMuralCueColumns, getMuralCueState, memoryNeedsCue, setMuralCue, recordMuralCueRejection, hasMemoryShareableColumn, hasMemoryClassifiedAtColumn, getUnclassifiedMemoryIds, ModuleMemoryAuthorityError, insertMemory, insertMemoryIdempotent, getMemoryByHash, getMemoriesByProject, buildWorkspaceMemorySqlFilter, getMemoriesByProjects, getMaxMemoryIdForProjects, readNewMemoriesForM1Union, getMemoryById, getMemoriesByIds, updateMemorySeenCount, updateMemoryRetrievalCount, setMemoryClassification, supersededMemory, mergeMemoryStats, archiveMemory, getMemoryCountsByStatus, sanitizeFtsQuery, searchMemoriesFTS, searchMemoriesFTSUnion, recordMemoryMapping, recordMemoryVerifications, getUnmappedMemoryIds, clearMemoryVerifications, getMemoryVerifications, resolveGitTopLevel, readGitHead, readGitChangedFilesSince, readGitFileChangeTimesSince, verificationFileExists, normalizeVerificationFiles, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, getMural, BoundedSessionMap, registerLkgPersistence, LKG_SNAPSHOT_ARRAY, LKG_SNAPSHOT_OBJECT, LKG_SNAPSHOT_KEY, LKG_SNAPSHOT_STRING, LKG_SNAPSHOT_NUMBER, LKG_SNAPSHOT_BOOLEAN, LKG_SNAPSHOT_NULL, LKG_SNAPSHOT_UNDEFINED, incrementalLkgContentDigests, lkgContentDigest, captureSlot, getSlot, dropSlot, noteEntry, onNoteTrigger, peekNoteNudgeText, markNoteNudgeDelivered, clearNoteNudgeTriggerAndCooldown, resetNoteNudgeCooldownOnly, clearNoteNudgeTriggerOnly, extractM0Block, resolveMuralWire, MARKER_SUMMARY_TEXT, applyDeferredCompactionMarker, removeCompactionMarkerForSession, checkCompactionMarkerConsistency, formatDate, injectTemporalMarkers, clearInjectionCache, getVisibleMemoryIds, prepareCompartmentInjection, renderCompartmentInjection, mustMaterialize, trimMemoriesToBudgetV2, renderMemoryBlockV2, injectM0M1, RECOVERY_NO_HEAD_LIMIT, resolveOpenCodeProtectedTailBoundary, resolveWrapupProtectedTailBoundary, getRawHistoryEligibility, hasRunnableCompartmentWindow, recordHighPressureNoEligibleHead, runCompartmentAgent, snapRangeToCompartments, getActiveCompartmentRun, markActiveCompartmentRunPublished, registerActiveCompartmentRun, startCompartmentAgent, isRecompFailure, isRecompSkip, isRecompComplete, extractRecompReason, contextualizeUpgradeReason, setRecompStarting, setRecompNote, setRecompTerminal, runManagedRecomp, runManagedUpgrade };