@cortexkit/opencode-magic-context 0.42.5 → 0.42.6

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 (128) hide show
  1. package/README.md +2 -2
  2. package/dist/config/index.d.ts +9 -0
  3. package/dist/config/index.d.ts.map +1 -1
  4. package/dist/config/schema/magic-context.d.ts +1 -0
  5. package/dist/config/schema/magic-context.d.ts.map +1 -1
  6. package/dist/{conflict-warning-hook-jyj54gbe.js → conflict-warning-hook-aktepwpz.js} +3 -3
  7. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  8. package/dist/features/magic-context/context-authority.d.ts +28 -1
  9. package/dist/features/magic-context/context-authority.d.ts.map +1 -1
  10. package/dist/features/magic-context/dreamer/open-opencode-db.d.ts.map +1 -1
  11. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  12. package/dist/features/magic-context/memory/embedding-local.d.ts +1 -0
  13. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  14. package/dist/features/magic-context/memory/embedding.d.ts +1 -1
  15. package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
  16. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  17. package/dist/features/magic-context/migrations.d.ts +12 -0
  18. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  19. package/dist/features/magic-context/project-embedding-registry.d.ts +1 -0
  20. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  21. package/dist/features/magic-context/session-project-backfill.d.ts.map +1 -1
  22. package/dist/features/magic-context/storage-db.d.ts +1 -1
  23. package/dist/features/magic-context/tool-owner-backfill.d.ts.map +1 -1
  24. package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
  25. package/dist/hooks/magic-context/cache-busting-signals.d.ts +0 -1
  26. package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
  27. package/dist/hooks/magic-context/channel2-delivery.d.ts +8 -0
  28. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  29. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +12 -0
  30. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  31. package/dist/hooks/magic-context/hook.d.ts +4 -4
  32. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  33. package/dist/hooks/magic-context/module-state-sync.d.ts +3 -0
  34. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  35. package/dist/hooks/magic-context/module-transport.d.ts +24 -2
  36. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/module-wire.d.ts +1 -1
  38. package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
  39. package/dist/hooks/magic-context/producer-window-guard.d.ts +31 -1
  40. package/dist/hooks/magic-context/producer-window-guard.d.ts.map +1 -1
  41. package/dist/hooks/magic-context/read-session-chunk.d.ts +6 -0
  42. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/read-session-db.d.ts +8 -0
  44. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/read-session-formatting.d.ts +6 -0
  46. package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
  47. package/dist/hooks/magic-context/rust-mode-transform.d.ts +30 -0
  48. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  49. package/dist/hooks/magic-context/rust-refusal-recovery.d.ts +28 -0
  50. package/dist/hooks/magic-context/rust-refusal-recovery.d.ts.map +1 -0
  51. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  52. package/dist/hooks/magic-context/transform.d.ts +7 -0
  53. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  54. package/dist/{index-jkrqhc7y.js → index-a9ssj59b.js} +94 -15
  55. package/dist/{index-3wbd8sdq.js → index-djp6rwz6.js} +455 -46
  56. package/dist/{index-p474rw9p.js → index-ngjmj6xx.js} +1 -1
  57. package/dist/{index-d8mgqezq.js → index-s61hh7gv.js} +50 -17
  58. package/dist/{index-1ar7b3e9.js → index-znraa0kv.js} +1 -1
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +1485 -360
  61. package/dist/plugin/embedding-bootstrap.d.ts.map +1 -1
  62. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  63. package/dist/plugin/memory-id-translation.d.ts +23 -0
  64. package/dist/plugin/memory-id-translation.d.ts.map +1 -0
  65. package/dist/plugin/rust-tool-backends.d.ts +1 -1
  66. package/dist/plugin/rust-tool-backends.d.ts.map +1 -1
  67. package/dist/{recomp-orchestrator-k20sfpm2.js → recomp-orchestrator-0xx1364v.js} +4 -4
  68. package/dist/{send-session-notification-xnypkxpx.js → send-session-notification-jbxknvar.js} +2 -2
  69. package/dist/shared/auto-update-provenance.d.ts +9 -0
  70. package/dist/shared/auto-update-provenance.d.ts.map +1 -0
  71. package/dist/shared/conflict-detector.d.ts +5 -1
  72. package/dist/shared/conflict-detector.d.ts.map +1 -1
  73. package/dist/shared/opencode-db-path.d.ts +31 -2
  74. package/dist/shared/opencode-db-path.d.ts.map +1 -1
  75. package/dist/shared/prompt-surface-runtime.d.ts +3 -3
  76. package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
  77. package/dist/{storage-meta-session-x3j0q9qy.js → storage-meta-session-z818pn1e.js} +2 -2
  78. package/dist/tools/ctx-expand/mode.d.ts +31 -0
  79. package/dist/tools/ctx-expand/mode.d.ts.map +1 -0
  80. package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
  81. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  82. package/dist/tools/ctx-note/constants.d.ts +1 -1
  83. package/dist/tools/ctx-note/constants.d.ts.map +1 -1
  84. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  85. package/dist/tools/ctx-note/types.d.ts +1 -1
  86. package/dist/tools/ctx-note/types.d.ts.map +1 -1
  87. package/dist/tools/ctx-reduce/constants.d.ts +1 -1
  88. package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
  89. package/dist/tools/ctx-search/types.d.ts +1 -1
  90. package/dist/tools/ctx-search/types.d.ts.map +1 -1
  91. package/dist/tools/light-descriptions.d.ts +2 -2
  92. package/dist/tools/light-descriptions.d.ts.map +1 -1
  93. package/dist/v2/hidden-completion.d.ts +69 -13
  94. package/dist/v2/hidden-completion.d.ts.map +1 -1
  95. package/dist/v2/hooks/context.d.ts +13 -1
  96. package/dist/v2/hooks/context.d.ts.map +1 -1
  97. package/dist/v2/hooks/hidden-child.d.ts +31 -0
  98. package/dist/v2/hooks/hidden-child.d.ts.map +1 -0
  99. package/dist/v2/hooks/store.d.ts.map +1 -1
  100. package/dist/v2/hooks/types.d.ts +99 -19
  101. package/dist/v2/hooks/types.d.ts.map +1 -1
  102. package/dist/v2/server.d.ts +19 -0
  103. package/dist/v2/server.d.ts.map +1 -1
  104. package/dist/v2/server.js +1781 -253
  105. package/dist/v2/store-reader.d.ts +11 -5
  106. package/dist/v2/store-reader.d.ts.map +1 -1
  107. package/dist/v2/tui/index.d.ts +10 -0
  108. package/dist/v2/tui/index.d.ts.map +1 -0
  109. package/dist/v2/tui/types.d.ts +80 -0
  110. package/dist/v2/tui/types.d.ts.map +1 -0
  111. package/package.json +5 -4
  112. package/src/agents/magic-context-prompt.ts +1 -1
  113. package/src/config/index.ts +31 -1
  114. package/src/config/protected-tokens.test.ts +40 -0
  115. package/src/config/schema/magic-context.ts +8 -3
  116. package/src/shared/auto-update-provenance.ts +42 -0
  117. package/src/shared/conflict-detector.test.ts +53 -0
  118. package/src/shared/conflict-detector.ts +88 -19
  119. package/src/shared/models-dev-cache.test.ts +25 -0
  120. package/src/shared/opencode-db-path.test.ts +96 -0
  121. package/src/shared/opencode-db-path.ts +146 -15
  122. package/src/shared/prompt-surface-a1-golden.md +12 -16
  123. package/src/shared/prompt-surface-runtime.test.ts +20 -0
  124. package/src/shared/prompt-surface-runtime.ts +7 -5
  125. package/src/tui/entry.mjs +11 -1
  126. package/src/v2/tui/host-contract.test.ts +202 -0
  127. package/src/v2/tui/index.ts +270 -0
  128. package/src/v2/tui/types.ts +67 -0
package/dist/v2/server.js CHANGED
@@ -53526,6 +53526,13 @@ function parseJsonc(content, options = {}) {
53526
53526
  const normalized = stripTrailingCommas(stripJsonComments(content));
53527
53527
  return sanitizeParsedJson(JSON.parse(normalized), options);
53528
53528
  }
53529
+ function readJsoncFile(filePath) {
53530
+ try {
53531
+ return parseJsonc(readFileSync(filePath, "utf-8"));
53532
+ } catch (_error) {
53533
+ return null;
53534
+ }
53535
+ }
53529
53536
  function detectConfigFile(basePath) {
53530
53537
  const jsoncPath = `${basePath}.jsonc`;
53531
53538
  const jsonPath = `${basePath}.json`;
@@ -59744,6 +59751,7 @@ var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65;
59744
59751
  var EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 90% for cache safety: output capacity is reserved from the usable context window, and the remaining 10% absorbs mid-turn growth before the absolute 95% emergency wall. Use a value between 20 and 90.";
59745
59752
  var DEFAULT_HISTORIAN_TIMEOUT_MS = 600000;
59746
59753
  var DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15;
59754
+ var PROTECTED_TOKENS_MIN = 4000;
59747
59755
  var DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2";
59748
59756
  var PiThinkingLevelSchema = _enum(["off", "minimal", "low", "medium", "high", "xhigh", "max"]).optional();
59749
59757
  var OmpThinkingLevelSchema = _enum(["off", "minimal", "low", "medium", "high", "xhigh", "max", "inherit", "auto"]).optional();
@@ -60113,8 +60121,8 @@ var MagicContextConfigSchema = object({
60113
60121
  smart_notes: object({
60114
60122
  retina_handoff: boolean2().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.")
60115
60123
  }).default({ retina_handoff: false }).describe("Smart-note ownership transition controls."),
60116
- cache_ttl: union([string2(), object({ default: string2() }).catchall(string2())]).default("5m").describe(`How long Magic Context assumes the provider's cached prefix stays valid. This is MC's own deferral gate — it does not change the provider's actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "model-id": "10m" }). Set to "never" to mean MC never assumes expiry (for lanes kept warm externally by a cache-keep tool) — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time. Provider-side extended TTL is a separate request-level concern (cache_control: { ttl } in the request body).`),
60117
- prompt_surface: PromptSurfaceConfigSchema.default({ default: "full" }).describe("Prompt-surface presets: default is full; models use bare model IDs, provider/model, or provider/* routing keys. Guidance and tool-description overrides are user-level only. On OpenCode and Pi, per-model routing applies to the guidance block only: tool descriptions are registered once per process, so they follow the default preset (a v1 plugin-surface limitation; per-model tool descriptions are planned for the OpenCode v2 plugin API once the SDK stabilizes)."),
60124
+ cache_ttl: union([string2(), object({ default: string2() }).catchall(string2())]).default("5m").describe(`How long Magic Context assumes the provider's cached prefix stays valid. This is MC's own deferral gate — it does not change the provider's actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "provider/model": "1h", "provider/*": "never" }); keys resolve most-specific first (exact provider/model, bare model ID, shorter dash-prefixes, then the provider/* wildcard, then default). Set to "never" to mean MC never assumes expiry (for lanes kept warm externally by a cache-keep tool) — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time. Provider-side extended TTL is a separate request-level concern (cache_control: { ttl } in the request body).`),
60125
+ prompt_surface: PromptSurfaceConfigSchema.default({ default: "full" }).describe("Prompt-surface presets: default is full; models use bare model IDs, provider/model, or provider/* routing keys. Guidance and tool-description overrides are user-level only. OpenCode 1.x, Pi, and OMP register tool descriptions once per process (they follow the default preset). OpenCode 2 rewrites the five ctx_* descriptions per request from the draft model."),
60118
60126
  output_reserve: union([
60119
60127
  number2().min(0),
60120
60128
  object({ default: number2().min(0) }).catchall(number2().min(0))
@@ -60130,7 +60138,7 @@ var MagicContextConfigSchema = object({
60130
60138
  execute_threshold_tokens: object({
60131
60139
  default: number2().min(5000).max(2000000).optional()
60132
60140
  }).catchall(number2().min(5000).max(2000000)).optional().describe("Absolute token thresholds per model. When matched, overrides execute_threshold_percentage for that model. Accepts `default` for all models or per-model keys. Values above 90% × context_limit are clamped with a warning log. Min 5_000, max 2_000_000."),
60133
- protected_tokens: number2().int().min(4000).max(1e6).optional().describe("Positive integer token floor to protect from automatic reclaim (min: 4_000, max: 1_000_000). When omitted, the derived default is clamp(round(0.05 × usableSoft), min(16_000, round(0.08 × usableSoft)), 64_000)."),
60141
+ protected_tokens: number2().int().min(PROTECTED_TOKENS_MIN).max(1e6).optional().describe("Positive integer token floor to protect from automatic reclaim (min: 4_000, max: 1_000_000). When omitted, the derived default is clamp(round(0.05 × usableSoft), min(16_000, round(0.08 × usableSoft)), 64_000)."),
60134
60142
  protected_tags: unknown().optional().describe("Deprecated: number of recent tags to protect. Ignored for behaviour; use protected_tokens instead.").meta({ deprecated: true }),
60135
60143
  clear_reasoning_age: number2().min(10).default(50).describe("Clear reasoning/thinking blocks older than N tags (default: 50)"),
60136
60144
  history_budget_percentage: number2().min(0.05).max(0.5).default(DEFAULT_HISTORY_BUDGET_PERCENTAGE).describe("Fraction of usable context (context_limit × execute_threshold) reserved for the session history block (default: 0.15)"),
@@ -61449,6 +61457,9 @@ function redactConfigValue(value) {
61449
61457
  return typeof value;
61450
61458
  }
61451
61459
  var warnedProtectedTagsDeprecation = false;
61460
+ function formatProtectedTokensBelowMinWarning(value) {
61461
+ return `protected_tokens is a token floor (minimum ${PROTECTED_TOKENS_MIN}, default derived from the context window); ${value} looks like the old protected_tags count. Remove the key to use the default, or set a token count such as 16000.`;
61462
+ }
61452
61463
  function warnProtectedTagsDeprecationOnce() {
61453
61464
  if (!warnedProtectedTagsDeprecation) {
61454
61465
  warnedProtectedTagsDeprecation = true;
@@ -61539,6 +61550,11 @@ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
61539
61550
  delete patched[key];
61540
61551
  const defaultVal = defaults[key];
61541
61552
  const reason = customMessagesByKey.get(key);
61553
+ const invalidRawValue = rawConfig[key];
61554
+ if (key === "protected_tokens" && typeof invalidRawValue === "number" && invalidRawValue < PROTECTED_TOKENS_MIN) {
61555
+ warnings.push(formatProtectedTokensBelowMinWarning(invalidRawValue));
61556
+ continue;
61557
+ }
61542
61558
  warnings.push(`"${key}": invalid value (${redactConfigValue(rawConfig[key])}), using default ${JSON.stringify(defaultVal)}.${reason ? ` ${reason}` : ""}`);
61543
61559
  }
61544
61560
  const retryMigrated = migrateLegacyAgentEnabledInMemory(migrateDreamerV2(migrateLegacyExperimental(patched, preMigrationWarnings), preMigrationWarnings), preMigrationWarnings);
@@ -61732,6 +61748,10 @@ function loadPluginConfigDetailed(directory) {
61732
61748
  cacheTtlConfigured
61733
61749
  };
61734
61750
  }
61751
+
61752
+ // src/v2/server.ts
61753
+ init_logger();
61754
+
61735
61755
  // src/features/magic-context/memory/project-identity.ts
61736
61756
  init_logger();
61737
61757
  import { execFileSync } from "node:child_process";
@@ -64109,6 +64129,28 @@ async function pullAndApplyMirrorPageWithStatus(args) {
64109
64129
  limit
64110
64130
  });
64111
64131
  const nextCursor = applyMirrorPage({ db: args.db, page: response.page });
64132
+ if (args.domain === "memories" && args.module.memoryIdentityAck) {
64133
+ const rowsByProject = new Map;
64134
+ for (const feed of response.page.rows) {
64135
+ if (feed.domain !== "memories" || feed.op === "tombstone")
64136
+ continue;
64137
+ const project = rowString(feed.full_row_snapshot, "project_path");
64138
+ if (!project)
64139
+ continue;
64140
+ const identity = mirrorIdentity(args.db, "memories", project, feed.module_row_id);
64141
+ if (!identity)
64142
+ continue;
64143
+ const rows = rowsByProject.get(project) ?? [];
64144
+ rows.push({
64145
+ module_row_id: feed.module_row_id,
64146
+ context_row_id: identity.context_row_id
64147
+ });
64148
+ rowsByProject.set(project, rows);
64149
+ }
64150
+ for (const [project, rows] of rowsByProject) {
64151
+ await args.module.memoryIdentityAck({ project, rows });
64152
+ }
64153
+ }
64112
64154
  return {
64113
64155
  cursor: nextCursor,
64114
64156
  hasMore: response.page.has_more,
@@ -64222,6 +64264,25 @@ function extractTexts(parts) {
64222
64264
  }
64223
64265
  return texts;
64224
64266
  }
64267
+ function extractToolResultBodyTokens(parts) {
64268
+ let tokens = 0;
64269
+ for (const part of parts) {
64270
+ if (part === null || typeof part !== "object")
64271
+ continue;
64272
+ const p = part;
64273
+ if (p.type !== "tool")
64274
+ continue;
64275
+ const state = p.state;
64276
+ if (!state || typeof state !== "object")
64277
+ continue;
64278
+ const body = state.output ?? state.error;
64279
+ if (body === undefined)
64280
+ continue;
64281
+ const text = typeof body === "string" ? body : JSON.stringify(body);
64282
+ tokens += Math.ceil(text.length / 4);
64283
+ }
64284
+ return tokens;
64285
+ }
64225
64286
  function extractToolCallSummaries(parts) {
64226
64287
  const summaries = [];
64227
64288
  for (const part of parts) {
@@ -65409,7 +65470,7 @@ function refreshTailHygieneBaseline(input) {
65409
65470
  for (let index = input.previous.baselineParts.length;index < measured.parts.length; index += 1) {
65410
65471
  const part = measured.parts[index];
65411
65472
  turnDeltaT += part.tokens;
65412
- if (part.kind !== "toolOutput")
65473
+ if (part.kind !== "toolOutput" || !part.protected)
65413
65474
  turnDeltaU += part.uTokens;
65414
65475
  }
65415
65476
  return {
@@ -66477,15 +66538,16 @@ import { isAbsolute as isAbsolute4, join as join7 } from "node:path";
66477
66538
  var cachedResolution = null;
66478
66539
  var lastReadFailure = null;
66479
66540
  var claimedDiagnostics = new Set;
66480
- function openCodeDataDir() {
66481
- return join7(process.env.XDG_DATA_HOME ?? join7(homedir8(), ".local", "share"), "opencode");
66541
+ function openCodeDataDir(env = process.env, dataHome) {
66542
+ return join7(dataHome ?? env.XDG_DATA_HOME ?? join7(homedir8(), ".local", "share"), "opencode");
66482
66543
  }
66483
- function environmentKey(dataDir) {
66544
+ function environmentKey(dataDir, hostGeneration, channel, env) {
66484
66545
  return [
66546
+ hostGeneration,
66485
66547
  dataDir,
66486
- process.env.OPENCODE_DB ?? "",
66487
- process.env.OPENCODE_DISABLE_CHANNEL_DB ?? "",
66488
- process.env.OPENCODE_CHANNEL ?? ""
66548
+ env.OPENCODE_DB ?? "",
66549
+ env.OPENCODE_DISABLE_CHANNEL_DB ?? "",
66550
+ channel ?? env.OPENCODE_CHANNEL ?? ""
66489
66551
  ].join("\x00");
66490
66552
  }
66491
66553
  function channelPath(dataDir, channel) {
@@ -66517,8 +66579,8 @@ function discoverOpenCodeDb(dataDir) {
66517
66579
  const channel = name === "opencode.db" ? null : name.slice("opencode-".length, -".db".length) || null;
66518
66580
  return { path: existing.path, source: "discovered", channel };
66519
66581
  }
66520
- function resolveFresh(dataDir) {
66521
- const explicit = process.env.OPENCODE_DB;
66582
+ function resolveV1Fresh(dataDir, env = process.env) {
66583
+ const explicit = env.OPENCODE_DB;
66522
66584
  if (explicit !== undefined && explicit.length > 0) {
66523
66585
  if (explicit === ":memory:") {
66524
66586
  return { path: explicit, source: "OPENCODE_DB", channel: null };
@@ -66529,24 +66591,47 @@ function resolveFresh(dataDir) {
66529
66591
  channel: null
66530
66592
  };
66531
66593
  }
66532
- const disableChannelDb = process.env.OPENCODE_DISABLE_CHANNEL_DB;
66594
+ const disableChannelDb = env.OPENCODE_DISABLE_CHANNEL_DB;
66533
66595
  if (disableChannelDb === "1" || disableChannelDb === "true") {
66534
66596
  return { path: join7(dataDir, "opencode.db"), source: "default", channel: null };
66535
66597
  }
66536
- const channel = process.env.OPENCODE_CHANNEL;
66598
+ const channel = env.OPENCODE_CHANNEL;
66537
66599
  if (channel !== undefined && channel.length > 0) {
66538
66600
  return { path: channelPath(dataDir, channel), source: "channel", channel };
66539
66601
  }
66540
66602
  return discoverOpenCodeDb(dataDir);
66541
66603
  }
66542
- function resolveOpenCodeDbPath() {
66543
- const dataDir = openCodeDataDir();
66544
- const key = environmentKey(dataDir);
66604
+ function sourceOpenCodeDatabaseFilename(hostGeneration, channel, env = process.env) {
66605
+ if (hostGeneration === "v1") {
66606
+ const explicit = env.OPENCODE_DB;
66607
+ if (explicit !== undefined && explicit.length > 0)
66608
+ return explicit;
66609
+ if (env.OPENCODE_DISABLE_CHANNEL_DB === "1" || env.OPENCODE_DISABLE_CHANNEL_DB === "true") {
66610
+ return "opencode.db";
66611
+ }
66612
+ return ["latest", "beta", "prod"].includes(channel) ? "opencode.db" : `opencode-${channel}.db`;
66613
+ }
66614
+ return env.OPENCODE_DB ?? (["latest", "dev", "beta", "next", "prod"].includes(channel) || env.OPENCODE_DISABLE_CHANNEL_DB === "1" || env.OPENCODE_DISABLE_CHANNEL_DB === "true" ? "opencode.db" : `opencode-${channel.replace(/[^a-zA-Z0-9._-]/g, "")}.db`);
66615
+ }
66616
+ function resolveV2Fresh(dataDir, channel, env) {
66617
+ const filename = sourceOpenCodeDatabaseFilename("v2", channel, env);
66618
+ const explicit = env.OPENCODE_DB !== undefined;
66619
+ return {
66620
+ path: filename === ":memory:" ? filename : join7(dataDir, filename),
66621
+ source: explicit ? "OPENCODE_DB" : env.OPENCODE_CHANNEL ? "channel" : "default",
66622
+ channel: explicit ? null : channel
66623
+ };
66624
+ }
66625
+ function resolveOpenCodeDbPath(hostGeneration = "v1", options = {}) {
66626
+ const env = options.env ?? process.env;
66627
+ const dataDir = openCodeDataDir(env, options.dataHome);
66628
+ const channel = options.channel ?? env.OPENCODE_CHANNEL;
66629
+ const key = environmentKey(dataDir, hostGeneration, channel, env);
66545
66630
  if (cachedResolution?.key === key && (!cachedResolution.existed || existsSync8(cachedResolution.resolution.path))) {
66546
66631
  if (cachedResolution.existed)
66547
66632
  return cachedResolution.resolution;
66548
66633
  }
66549
- const resolution = resolveFresh(dataDir);
66634
+ const resolution = hostGeneration === "v2" ? resolveV2Fresh(dataDir, channel ?? "latest", env) : resolveV1Fresh(dataDir, env);
66550
66635
  cachedResolution = {
66551
66636
  key,
66552
66637
  resolution,
@@ -66554,6 +66639,29 @@ function resolveOpenCodeDbPath() {
66554
66639
  };
66555
66640
  return resolution;
66556
66641
  }
66642
+ function schemaTableNames(db, schema = "main") {
66643
+ const rows = db.prepare(`SELECT name FROM ${schema}.sqlite_master WHERE type = 'table' AND name IN ('message', 'part', 'session', 'project', 'session_message')`).all();
66644
+ return new Set(rows.flatMap((row) => typeof row.name === "string" ? [row.name] : []));
66645
+ }
66646
+ function detectOpenCodeStoreGeneration(db, schema = "main") {
66647
+ const tables = schemaTableNames(db, schema);
66648
+ const hasV1Messages = tables.has("message") && tables.has("part");
66649
+ if (hasV1Messages)
66650
+ return "v1";
66651
+ if (tables.has("session_message"))
66652
+ return "v2";
66653
+ if (tables.has("session") || tables.has("project"))
66654
+ return "v1";
66655
+ return "unknown";
66656
+ }
66657
+ function assertOpenCodeStoreGeneration(db, expected, path, schema = "main") {
66658
+ const actual = detectOpenCodeStoreGeneration(db, schema);
66659
+ if (actual === expected)
66660
+ return;
66661
+ if (actual === "unknown")
66662
+ return;
66663
+ throw new Error(`OpenCode store generation mismatch at ${path}: expected ${expected}, found ${actual}; refusing generation-specific database access`);
66664
+ }
66557
66665
  function openCodeDbPathExists(resolution = resolveOpenCodeDbPath()) {
66558
66666
  return resolution.path !== ":memory:" && existsSync8(resolution.path);
66559
66667
  }
@@ -66611,6 +66719,12 @@ function getReadOnlySessionDb() {
66611
66719
  }
66612
66720
  closeCachedReadOnlyDb();
66613
66721
  const db = new Database(dbPath, { readonly: true });
66722
+ try {
66723
+ assertOpenCodeStoreGeneration(db, "v1", dbPath);
66724
+ } catch (error) {
66725
+ closeQuietly(db);
66726
+ throw error;
66727
+ }
66614
66728
  cachedReadOnlyDb = { path: dbPath, db };
66615
66729
  clearOpenCodeDbReadFailure();
66616
66730
  return db;
@@ -67002,6 +67116,20 @@ function countRawSessionMessageOrdinalsFromDb(db, sessionId) {
67002
67116
  )`).get(sessionId);
67003
67117
  return typeof row?.count === "number" ? row.count : 0;
67004
67118
  }
67119
+ function readRawSessionMessageIdOrdinalsFromDb(db, sessionId) {
67120
+ const messageRows = db.prepare("SELECT id, data FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(sessionId).filter(isRawMessageRow);
67121
+ const ordinalById = new Map;
67122
+ let ordinal = 0;
67123
+ for (const row of messageRows) {
67124
+ const info = parseJsonRecord(row.data);
67125
+ if (isRawCompactionSummaryInfo(info))
67126
+ continue;
67127
+ ordinal += 1;
67128
+ if (info)
67129
+ ordinalById.set(row.id, ordinal);
67130
+ }
67131
+ return ordinalById;
67132
+ }
67005
67133
  function readRawSessionMessageOrdinalPageFromDb(db, sessionId, after, limit) {
67006
67134
  const pageSize = Math.max(1, Math.floor(limit));
67007
67135
  const rows = (after ? db.prepare(`SELECT id, data, time_created
@@ -68260,6 +68388,17 @@ function getRawSessionStoredMessageCount(sessionId) {
68260
68388
  return 0;
68261
68389
  return withReadOnlySessionDb((db) => countStoredRawSessionMessagesFromDb(db, sessionId));
68262
68390
  }
68391
+ function readRawSessionMessageIdOrdinals(sessionId) {
68392
+ const provider = sessionProviders.get(sessionId);
68393
+ if (provider?.readMessageIdOrdinals)
68394
+ return provider.readMessageIdOrdinals();
68395
+ if (provider) {
68396
+ return new Map(provider.readMessages().map((message) => [message.id, message.ordinal]));
68397
+ }
68398
+ if (!openCodeDbExists())
68399
+ return new Map;
68400
+ return withReadOnlySessionDb((db) => readRawSessionMessageIdOrdinalsFromDb(db, sessionId));
68401
+ }
68263
68402
  function readRawSessionMessagePartsById(sessionId, messageId, onQuery) {
68264
68403
  const provider = sessionProviders.get(sessionId);
68265
68404
  if (provider?.readMessagePartsById)
@@ -68427,6 +68566,14 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
68427
68566
  const totalMessageCount = getCachedAbsoluteMessageCount(sessionId) ?? messages.length;
68428
68567
  const startOrdinal = Math.max(1, offset);
68429
68568
  const completedToolArcs = buildToolArcs(messages).flatMap((arc) => arc.resOrdinal === null ? [] : [{ start: arc.invOrdinal, end: arc.resOrdinal }]);
68569
+ const completedToolComponents = [];
68570
+ for (const arc of completedToolArcs) {
68571
+ const component = completedToolComponents[completedToolComponents.length - 1];
68572
+ if (component && arc.start <= component.end)
68573
+ component.end = Math.max(component.end, arc.end);
68574
+ else
68575
+ completedToolComponents.push({ ...arc });
68576
+ }
68430
68577
  const lines = [];
68431
68578
  const lineMeta = [];
68432
68579
  const flushedToolOnlyBlocks = [];
@@ -68440,6 +68587,25 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
68440
68587
  let pendingNoiseMeta = [];
68441
68588
  let commitClusters = 0;
68442
68589
  let lastFlushedRole = "";
68590
+ let admittedOversizeComponentEnd = null;
68591
+ let currentBlockApproxTokens = 0;
68592
+ let formattedBudgetCrossed = false;
68593
+ let sourceCharacters = 0;
68594
+ const toolResultBoundaries = [];
68595
+ function pinComponentWhenFormattedBudgetCrosses(ordinal, appendedText) {
68596
+ if (admittedOversizeComponentEnd !== null || formattedBudgetCrossed || !currentBlock)
68597
+ return;
68598
+ currentBlockApproxTokens += estimateTokens(appendedText) + (currentBlock.parts.length > 1 ? 1 : 0);
68599
+ if (totalTokens + currentBlockApproxTokens + 64 <= tokenBudget)
68600
+ return;
68601
+ const previewTokens = totalTokens + estimateTokens(formatBlock(currentBlock));
68602
+ if (previewTokens <= tokenBudget)
68603
+ return;
68604
+ formattedBudgetCrossed = true;
68605
+ const component = completedToolComponents.find((candidate) => candidate.start <= ordinal && candidate.end >= ordinal);
68606
+ if (component)
68607
+ admittedOversizeComponentEnd = component.end;
68608
+ }
68443
68609
  function recordFilteredNoise(meta) {
68444
68610
  pendingNoiseMeta.push(meta);
68445
68611
  if (!currentBlock) {
@@ -68466,7 +68632,23 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
68466
68632
  highestScannedOrdinal = Math.max(highestScannedOrdinal, lastOrdinal);
68467
68633
  lastMessageId = currentBlock.meta[currentBlock.meta.length - 1]?.messageId ?? "";
68468
68634
  messagesProcessed += currentBlock.meta.length;
68635
+ const lineStart = sourceCharacters + (lines.length > 0 ? 1 : 0);
68636
+ const renderedParts = currentBlock.parts.join(" / ");
68637
+ let partOffset = lineStart + (blockText.length - renderedParts.length);
68638
+ for (let index = 0;index < currentBlock.parts.length; index++) {
68639
+ const part = currentBlock.parts[index] ?? "";
68640
+ const partMeta = currentBlock.partMeta[index];
68641
+ if (partMeta && partMeta.toolResultBodyTokens > 0) {
68642
+ toolResultBoundaries.push({
68643
+ ordinal: partMeta.ordinal,
68644
+ sourceOffset: partOffset,
68645
+ bodyTokens: partMeta.toolResultBodyTokens
68646
+ });
68647
+ }
68648
+ partOffset += part.length + (index + 1 < currentBlock.parts.length ? 3 : 0);
68649
+ }
68469
68650
  lines.push(blockText);
68651
+ sourceCharacters = lineStart + blockText.length;
68470
68652
  lineMeta.push(...currentBlock.meta);
68471
68653
  totalTokens += blockTokens;
68472
68654
  if (currentBlock.isToolOnly) {
@@ -68476,11 +68658,15 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
68476
68658
  });
68477
68659
  }
68478
68660
  currentBlock = null;
68661
+ currentBlockApproxTokens = 0;
68479
68662
  return true;
68480
68663
  }
68481
68664
  for (const msg of messages) {
68482
68665
  if (eligibleEndOrdinal !== undefined && msg.ordinal >= eligibleEndOrdinal)
68483
68666
  break;
68667
+ if (admittedOversizeComponentEnd !== null && msg.ordinal > admittedOversizeComponentEnd) {
68668
+ break;
68669
+ }
68484
68670
  if (msg.ordinal < startOrdinal)
68485
68671
  continue;
68486
68672
  const meta = { ordinal: msg.ordinal, messageId: msg.id };
@@ -68494,6 +68680,10 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
68494
68680
  if (currentBlock && currentBlock.role === "A") {
68495
68681
  currentBlock.endOrdinal = msg.ordinal;
68496
68682
  currentBlock.parts.push(tcText);
68683
+ currentBlock.partMeta.push({
68684
+ ordinal: msg.ordinal,
68685
+ toolResultBodyTokens: extractToolResultBodyTokens(msg.parts)
68686
+ });
68497
68687
  currentBlock.meta.push(...pendingNoiseMeta, meta);
68498
68688
  pendingNoiseMeta = [];
68499
68689
  } else {
@@ -68504,12 +68694,19 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
68504
68694
  startOrdinal: pendingNoiseMeta[0]?.ordinal ?? msg.ordinal,
68505
68695
  endOrdinal: msg.ordinal,
68506
68696
  parts: [tcText],
68697
+ partMeta: [
68698
+ {
68699
+ ordinal: msg.ordinal,
68700
+ toolResultBodyTokens: extractToolResultBodyTokens(msg.parts)
68701
+ }
68702
+ ],
68507
68703
  meta: [...pendingNoiseMeta, meta],
68508
68704
  commitHashes: [],
68509
68705
  isToolOnly: true
68510
68706
  };
68511
68707
  pendingNoiseMeta = [];
68512
68708
  }
68709
+ pinComponentWhenFormattedBudgetCrosses(msg.ordinal, tcText);
68513
68710
  continue;
68514
68711
  }
68515
68712
  const role = compactRole(msg.role);
@@ -68526,11 +68723,16 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
68526
68723
  if (currentBlock && currentBlock.role === role) {
68527
68724
  currentBlock.endOrdinal = msg.ordinal;
68528
68725
  currentBlock.parts.push(text);
68726
+ currentBlock.partMeta.push({
68727
+ ordinal: msg.ordinal,
68728
+ toolResultBodyTokens: extractToolResultBodyTokens(msg.parts)
68729
+ });
68529
68730
  currentBlock.meta.push(...pendingNoiseMeta, meta);
68530
68731
  currentBlock.commitHashes = mergeCommitHashes(currentBlock.commitHashes, compacted.commitHashes);
68531
68732
  if (msgHasNarrative)
68532
68733
  currentBlock.isToolOnly = false;
68533
68734
  pendingNoiseMeta = [];
68735
+ pinComponentWhenFormattedBudgetCrosses(msg.ordinal, text);
68534
68736
  continue;
68535
68737
  }
68536
68738
  if (!flushCurrentBlock())
@@ -68540,11 +68742,18 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
68540
68742
  startOrdinal: pendingNoiseMeta[0]?.ordinal ?? msg.ordinal,
68541
68743
  endOrdinal: msg.ordinal,
68542
68744
  parts: [text],
68745
+ partMeta: [
68746
+ {
68747
+ ordinal: msg.ordinal,
68748
+ toolResultBodyTokens: extractToolResultBodyTokens(msg.parts)
68749
+ }
68750
+ ],
68543
68751
  meta: [...pendingNoiseMeta, meta],
68544
68752
  commitHashes: [...compacted.commitHashes],
68545
68753
  isToolOnly: !msgHasNarrative
68546
68754
  };
68547
68755
  pendingNoiseMeta = [];
68756
+ pinComponentWhenFormattedBudgetCrosses(msg.ordinal, text);
68548
68757
  }
68549
68758
  if (flushCurrentBlock() && pendingNoiseMeta.length > 0) {
68550
68759
  highestScannedOrdinal = Math.max(highestScannedOrdinal, pendingNoiseMeta[pendingNoiseMeta.length - 1]?.ordinal ?? highestScannedOrdinal);
@@ -68575,7 +68784,8 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
68575
68784
  ...messagesProcessed === 0 && text.length === 0 ? { filteredNoiseLines: pendingNoiseMeta } : {},
68576
68785
  commitClusterCount: commitClusters,
68577
68786
  toolOnlyRanges,
68578
- completedToolArcs
68787
+ completedToolArcs,
68788
+ toolResultBoundaries
68579
68789
  };
68580
68790
  }
68581
68791
  function readRawSessionSeedTail(sessionId, boundaryId, onQuery) {
@@ -69537,6 +69747,114 @@ function isSqliteLockError(error) {
69537
69747
  function tableExists2(db, name) {
69538
69748
  return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name));
69539
69749
  }
69750
+ function tableHasHarnessColumn(db, name) {
69751
+ if (!tableExists2(db, name))
69752
+ return false;
69753
+ return db.prepare(`PRAGMA table_info(${name})`).all().some((column) => column.name === "harness");
69754
+ }
69755
+ var V85_OPENCODE2_RELABEL_TABLES = [
69756
+ "tags",
69757
+ "pending_ops",
69758
+ "source_contents",
69759
+ "compartments",
69760
+ "compartment_chunk_embeddings",
69761
+ "session_projects",
69762
+ "compartment_events",
69763
+ "compression_depth",
69764
+ "session_facts",
69765
+ "primer_candidates",
69766
+ "notes",
69767
+ "message_history_index",
69768
+ "message_history_source",
69769
+ "pending_session_cleanup",
69770
+ "message_history_orphan_sweep",
69771
+ "session_meta",
69772
+ "subagent_invocations",
69773
+ "historian_runs",
69774
+ "transform_decisions",
69775
+ "recomp_compartments",
69776
+ "recomp_facts"
69777
+ ];
69778
+ var V85_OPTIONAL_OPENCODE2_RELABEL_TABLES = ["session_project_backfill_state"];
69779
+ function deleteLosingOpenCode2Twin(db, table, joinColumns, newerPredicate) {
69780
+ if (!tableHasHarnessColumn(db, table))
69781
+ return;
69782
+ const naturalJoin = joinColumns.map((column) => `oc.${column} = o2.${column}`).join(" AND ");
69783
+ const o2On = naturalJoin ? `${naturalJoin} AND oc.harness = 'opencode'` : `oc.harness = 'opencode'`;
69784
+ const ocOn = naturalJoin ? `${naturalJoin} AND o2.harness = 'opencode2'` : `o2.harness = 'opencode2'`;
69785
+ db.exec(`
69786
+ DELETE FROM ${table}
69787
+ WHERE rowid IN (
69788
+ SELECT o2.rowid
69789
+ FROM ${table} AS o2
69790
+ JOIN ${table} AS oc
69791
+ ON ${o2On}
69792
+ WHERE o2.harness = 'opencode2'
69793
+ AND NOT (${newerPredicate})
69794
+ );
69795
+ DELETE FROM ${table}
69796
+ WHERE rowid IN (
69797
+ SELECT oc.rowid
69798
+ FROM ${table} AS oc
69799
+ JOIN ${table} AS o2
69800
+ ON ${ocOn}
69801
+ WHERE oc.harness = 'opencode'
69802
+ AND (${newerPredicate})
69803
+ );
69804
+ `);
69805
+ }
69806
+ function relabelOpenCode2HarnessRows(db) {
69807
+ deleteLosingOpenCode2Twin(db, "session_projects", ["session_id"], "o2.updated_at > oc.updated_at");
69808
+ deleteLosingOpenCode2Twin(db, "primer_candidates", ["project_path", "session_id", "source_start_message_id", "source_end_message_id"], "o2.created_at > oc.created_at");
69809
+ deleteLosingOpenCode2Twin(db, "transform_decisions", ["session_id", "message_id"], "o2.ts_ms > oc.ts_ms");
69810
+ deleteLosingOpenCode2Twin(db, "message_history_orphan_sweep", [], "COALESCE(o2.last_swept_at, -1) > COALESCE(oc.last_swept_at, -1)");
69811
+ if (tableHasHarnessColumn(db, "session_project_backfill_state")) {
69812
+ db.exec(`
69813
+ DELETE FROM session_project_backfill_state
69814
+ WHERE harness = 'opencode2'
69815
+ AND EXISTS (
69816
+ SELECT 1 FROM session_project_backfill_state WHERE harness = 'opencode'
69817
+ )
69818
+ AND NOT (
69819
+ (status = 'completed'
69820
+ AND (SELECT status FROM session_project_backfill_state WHERE harness = 'opencode')
69821
+ != 'completed')
69822
+ OR (
69823
+ status = (SELECT status FROM session_project_backfill_state WHERE harness = 'opencode')
69824
+ AND COALESCE(started_at, -1) > COALESCE(
69825
+ (SELECT started_at FROM session_project_backfill_state WHERE harness = 'opencode'),
69826
+ -1
69827
+ )
69828
+ )
69829
+ );
69830
+ DELETE FROM session_project_backfill_state
69831
+ WHERE harness = 'opencode'
69832
+ AND EXISTS (
69833
+ SELECT 1 FROM session_project_backfill_state WHERE harness = 'opencode2'
69834
+ )
69835
+ AND (
69836
+ ((SELECT status FROM session_project_backfill_state WHERE harness = 'opencode2') = 'completed'
69837
+ AND status != 'completed')
69838
+ OR (
69839
+ status = (SELECT status FROM session_project_backfill_state WHERE harness = 'opencode2')
69840
+ AND COALESCE(
69841
+ (SELECT started_at FROM session_project_backfill_state WHERE harness = 'opencode2'),
69842
+ -1
69843
+ ) > COALESCE(started_at, -1)
69844
+ )
69845
+ );
69846
+ `);
69847
+ }
69848
+ const tables = new Set([
69849
+ ...V85_OPENCODE2_RELABEL_TABLES,
69850
+ ...V85_OPTIONAL_OPENCODE2_RELABEL_TABLES
69851
+ ]);
69852
+ for (const table of tables) {
69853
+ if (!tableHasHarnessColumn(db, table))
69854
+ continue;
69855
+ db.exec(`UPDATE ${table} SET harness = 'opencode' WHERE harness = 'opencode2'`);
69856
+ }
69857
+ }
69540
69858
  function healMismatchedTierClose(db, table, hasLegacy) {
69541
69859
  if (!tableExists2(db, table))
69542
69860
  return;
@@ -71699,6 +72017,13 @@ var MIGRATIONS = [
71699
72017
  ensureColumn(db, "session_meta", "protected_tokens_effective", "INTEGER");
71700
72018
  ensureColumn(db, "session_meta", "protected_tokens_pre_snapshot", "TEXT");
71701
72019
  }
72020
+ },
72021
+ {
72022
+ version: 85,
72023
+ description: "relabel OpenCode 1.x mis-tagged opencode2 session rows",
72024
+ up(db) {
72025
+ relabelOpenCode2HarnessRows(db);
72026
+ }
71702
72027
  }
71703
72028
  ];
71704
72029
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -72855,6 +73180,7 @@ function runToolOwnerBackfill(db) {
72855
73180
  const escapedDbPath = opencodeDbPath.replaceAll("'", "''");
72856
73181
  db.exec(`ATTACH '${escapedDbPath}' AS oc_backfill`);
72857
73182
  try {
73183
+ assertOpenCodeStoreGeneration(db, "v1", opencodeDbPath, "oc_backfill");
72858
73184
  backfillToolOwnersInChunks(db, result);
72859
73185
  } finally {
72860
73186
  try {
@@ -73070,7 +73396,7 @@ var lastMigrationOnOpenRefusal = null;
73070
73396
  function getSchemaFenceRejection() {
73071
73397
  return lastSchemaFenceRejection;
73072
73398
  }
73073
- var LATEST_SUPPORTED_VERSION = 84;
73399
+ var LATEST_SUPPORTED_VERSION = 85;
73074
73400
  var BOOT_SQLITE_BUSY_TIMEOUT_MS = 5000;
73075
73401
  var PERMISSIONS_ENFORCEABLE = process.platform !== "win32";
73076
73402
  var defaultStoragePermissionFs = { chmodSync: chmodSync2, mkdirSync: mkdirSync4 };
@@ -73524,7 +73850,7 @@ function initializeDatabase(db, busyTimeoutMs = BOOT_SQLITE_BUSY_TIMEOUT_MS) {
73524
73850
  tag_id INTEGER,
73525
73851
  session_id TEXT,
73526
73852
  content TEXT,
73527
- created_at INTEGER,
73853
+ created_at INTEGER, -- epoch ms; Date.now() on source writes, preserved on session clones
73528
73854
  harness TEXT NOT NULL DEFAULT 'opencode',
73529
73855
  PRIMARY KEY(session_id, tag_id)
73530
73856
  );
@@ -73548,7 +73874,7 @@ function initializeDatabase(db, busyTimeoutMs = BOOT_SQLITE_BUSY_TIMEOUT_MS) {
73548
73874
  p1_embedding BLOB,
73549
73875
  p1_embedding_model_id TEXT,
73550
73876
  legacy INTEGER NOT NULL DEFAULT 0,
73551
- created_at INTEGER NOT NULL,
73877
+ created_at INTEGER NOT NULL, -- epoch ms (Date.now())
73552
73878
  harness TEXT NOT NULL DEFAULT 'opencode',
73553
73879
  UNIQUE(session_id, sequence)
73554
73880
  );
@@ -73567,7 +73893,7 @@ function initializeDatabase(db, busyTimeoutMs = BOOT_SQLITE_BUSY_TIMEOUT_MS) {
73567
73893
  model_id TEXT NOT NULL,
73568
73894
  dims INTEGER NOT NULL,
73569
73895
  vector BLOB NOT NULL,
73570
- created_at INTEGER NOT NULL,
73896
+ created_at INTEGER NOT NULL, -- epoch ms (Date.now())
73571
73897
  UNIQUE(compartment_id, model_id, window_index)
73572
73898
  );
73573
73899
  CREATE INDEX IF NOT EXISTS idx_cce_session ON compartment_chunk_embeddings(session_id);
@@ -73590,7 +73916,7 @@ function initializeDatabase(db, busyTimeoutMs = BOOT_SQLITE_BUSY_TIMEOUT_MS) {
73590
73916
  kind TEXT NOT NULL,
73591
73917
  at_compartment INTEGER,
73592
73918
  fields_json TEXT NOT NULL DEFAULT '{}',
73593
- created_at INTEGER NOT NULL,
73919
+ created_at INTEGER NOT NULL, -- epoch ms (Date.now())
73594
73920
  harness TEXT NOT NULL DEFAULT 'opencode'
73595
73921
  );
73596
73922
  CREATE INDEX IF NOT EXISTS idx_compartment_events_session
@@ -73619,7 +73945,7 @@ function initializeDatabase(db, busyTimeoutMs = BOOT_SQLITE_BUSY_TIMEOUT_MS) {
73619
73945
  session_id TEXT NOT NULL,
73620
73946
  category TEXT NOT NULL,
73621
73947
  content TEXT NOT NULL,
73622
- created_at INTEGER NOT NULL,
73948
+ created_at INTEGER NOT NULL, -- epoch ms (Date.now())
73623
73949
  updated_at INTEGER NOT NULL,
73624
73950
  harness TEXT NOT NULL DEFAULT 'opencode'
73625
73951
  );
@@ -73638,7 +73964,7 @@ function initializeDatabase(db, busyTimeoutMs = BOOT_SQLITE_BUSY_TIMEOUT_MS) {
73638
73964
  source_message_time INTEGER NOT NULL,
73639
73965
  question_embedding BLOB,
73640
73966
  question_embedding_model_id TEXT,
73641
- created_at INTEGER NOT NULL,
73967
+ created_at INTEGER NOT NULL, -- epoch ms (Date.now())
73642
73968
  UNIQUE(project_path, harness, session_id, source_start_message_id, source_end_message_id)
73643
73969
  );
73644
73970
  CREATE INDEX IF NOT EXISTS idx_primer_candidates_project_time
@@ -73661,7 +73987,7 @@ function initializeDatabase(db, busyTimeoutMs = BOOT_SQLITE_BUSY_TIMEOUT_MS) {
73661
73987
  answer_refreshed_at INTEGER,
73662
73988
  source_candidate_ids TEXT NOT NULL DEFAULT '[]',
73663
73989
  source_candidate_provenance TEXT,
73664
- created_at INTEGER NOT NULL,
73990
+ created_at INTEGER NOT NULL, -- epoch ms (Date.now())
73665
73991
  updated_at INTEGER NOT NULL
73666
73992
  );
73667
73993
  CREATE INDEX IF NOT EXISTS idx_primers_project_status_observed
@@ -73774,7 +74100,7 @@ function initializeDatabase(db, busyTimeoutMs = BOOT_SQLITE_BUSY_TIMEOUT_MS) {
73774
74100
  job_id TEXT,
73775
74101
  cursor TEXT,
73776
74102
  status TEXT NOT NULL DEFAULT 'pending',
73777
- created_at INTEGER NOT NULL DEFAULT 0,
74103
+ created_at INTEGER NOT NULL DEFAULT 0, -- epoch ms (Date.now())
73778
74104
  updated_at INTEGER NOT NULL DEFAULT 0,
73779
74105
  UNIQUE(session_id, request_key)
73780
74106
  );
@@ -73815,7 +74141,7 @@ function initializeDatabase(db, busyTimeoutMs = BOOT_SQLITE_BUSY_TIMEOUT_MS) {
73815
74141
  shadow_epoch INTEGER NOT NULL DEFAULT 0,
73816
74142
  corpus_hash TEXT NOT NULL DEFAULT '',
73817
74143
  coverage_json TEXT NOT NULL DEFAULT '{}',
73818
- created_at INTEGER NOT NULL DEFAULT 0,
74144
+ created_at INTEGER NOT NULL DEFAULT 0, -- epoch ms (Date.now())
73819
74145
  UNIQUE(dedup_key, cohort_key)
73820
74146
  );
73821
74147
  CREATE INDEX IF NOT EXISTS idx_embedding_measurement_session
@@ -74238,7 +74564,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
74238
74564
  importance_avg REAL,
74239
74565
  discarded_last INTEGER NOT NULL DEFAULT 0,
74240
74566
  legacy INTEGER NOT NULL DEFAULT 0,
74241
- created_at INTEGER NOT NULL
74567
+ created_at INTEGER NOT NULL -- epoch ms (Date.now())
74242
74568
  );
74243
74569
  CREATE INDEX IF NOT EXISTS idx_historian_runs_session
74244
74570
  ON historian_runs(session_id, created_at DESC);
@@ -74291,7 +74617,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
74291
74617
  importance INTEGER NOT NULL DEFAULT 50,
74292
74618
  episode_type TEXT,
74293
74619
  pass_number INTEGER NOT NULL,
74294
- created_at INTEGER NOT NULL,
74620
+ created_at INTEGER NOT NULL, -- epoch ms (Date.now())
74295
74621
  harness TEXT NOT NULL DEFAULT 'opencode',
74296
74622
  UNIQUE(session_id, sequence)
74297
74623
  );
@@ -74302,7 +74628,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
74302
74628
  category TEXT NOT NULL,
74303
74629
  content TEXT NOT NULL,
74304
74630
  pass_number INTEGER NOT NULL,
74305
- created_at INTEGER NOT NULL,
74631
+ created_at INTEGER NOT NULL, -- epoch ms (Date.now())
74306
74632
  harness TEXT NOT NULL DEFAULT 'opencode'
74307
74633
  );
74308
74634
 
@@ -81305,6 +81631,7 @@ async function injectWasmOrt() {
81305
81631
  try {
81306
81632
  const { module: ortWeb, entryPath } = await importWasmOrtForRuntime();
81307
81633
  if (ortWeb.env?.wasm) {
81634
+ ortWeb.env.wasm.numThreads = 1;
81308
81635
  ortWeb.env.wasm.wasmPaths = `${pathToFileURL2(dirname7(entryPath)).href}/`;
81309
81636
  }
81310
81637
  globalThis[Symbol.for("onnxruntime")] = ortWeb;
@@ -88642,6 +88969,19 @@ function normalizeSDKResponse(response, fallback, options) {
88642
88969
  return fallback;
88643
88970
  }
88644
88971
  // src/shared/prompt-surface-runtime.ts
88972
+ import { existsSync as existsSync12, readFileSync as readFileSync11, statSync as statSync10 } from "node:fs";
88973
+ import { dirname as dirname8, isAbsolute as isAbsolute5, resolve as resolve5 } from "node:path";
88974
+
88975
+ // src/tools/light-descriptions.ts
88976
+ var CTX_REDUCE_LIGHT_DESCRIPTION = `Marking QUEUES content for release. It stays fully visible to you until it is actually released, which may be the next turn or many turns later. Newest tags stay protected until they age out. Release leaves a placeholder; recover only by rerunning the source or recovery tool. Mark only finished material. Mark analyzed, redundant, saved, or confirmatory outputs; keep user messages, unresolved errors, unextracted evidence, and exact wording. NEVER blanket-mark a large range: review every tag first.`;
88977
+ var CTX_EXPAND_LIGHT_DESCRIPTION = `For ctx_expand users, recover compacted conversation by passing a session-history heading's inclusive start/end ordinals. Results are raw [N] U:/A: transcript capped near 15K tokens; oversized ranges return the head and a continuation. Use verbose=true to list each message ordinal, part previews, and tool-output sizes; use message=N for one complete stored message and its tool exchanges. NEVER expand ranges after the last compartment because that live tail is already visible.`;
88978
+ var CTX_NOTE_LIGHT_DESCRIPTION = `For ctx_note: write saves, read lists, update changes one note (note_ids=[N]), dismiss retires 1–50 (note_ids); surface_condition makes a smart note. Smart-note conditions must be externally verifiable via GitHub, disk, git, or web—not this conversation or future actions.`;
88979
+ var CTX_MEMORY_LIGHT_DESCRIPTION = `For ctx_memory users, write one standalone durable fact with category and content; update one ID, archive one or more IDs, merge two or more IDs, or get one to twenty numeric IDs. get reads memories in every status; list remains dreamer-only, so primary agents must NEVER assume bulk-list access.`;
88980
+ var CTX_SEARCH_LIGHT_DESCRIPTION = `For ctx_search users, retrieve only hidden recall: memories not in <project-memory>, compacted messages outside the live tail, commits, and notes; phrase query as a question carrying exact terms. Omit sources for broad search; select memory, message, git_commit, or note, or pass memory IDs directly. Hits expand through ctx_expand.`;
88981
+
88982
+ // src/shared/prompt-surface-runtime.ts
88983
+ var GUIDANCE_MARKER = "## Magic Context";
88984
+ var GUIDANCE_MARKER_LINE = /^## Magic Context[\t ]*\r?$/gm;
88645
88985
  var ACTIVE_TOOL_IDS = [
88646
88986
  "ctx_reduce",
88647
88987
  "ctx_expand",
@@ -88649,7 +88989,99 @@ var ACTIVE_TOOL_IDS = [
88649
88989
  "ctx_memory",
88650
88990
  "ctx_search"
88651
88991
  ];
88992
+ var LIGHT_TOOL_DESCRIPTIONS = {
88993
+ ctx_reduce: CTX_REDUCE_LIGHT_DESCRIPTION,
88994
+ ctx_expand: CTX_EXPAND_LIGHT_DESCRIPTION,
88995
+ ctx_note: CTX_NOTE_LIGHT_DESCRIPTION,
88996
+ ctx_memory: CTX_MEMORY_LIGHT_DESCRIPTION,
88997
+ ctx_search: CTX_SEARCH_LIGHT_DESCRIPTION
88998
+ };
88652
88999
  var PROMPT_SURFACE_TOOL_ID_SET = new Set(ACTIVE_TOOL_IDS);
89000
+ function resolveUserConfigDirectory(options) {
89001
+ if (options.userConfigDirectory)
89002
+ return resolve5(options.userConfigDirectory);
89003
+ const sharedBase = cortexKitUserConfigBasePath();
89004
+ const shared = detectConfigFile(sharedBase);
89005
+ if (shared.format !== "none")
89006
+ return dirname8(shared.path);
89007
+ if (options.harness) {
89008
+ const legacy = resolveLegacyConfigSourcesForHarness(options.directory ?? process.cwd(), options.harness === "omp" ? "pi" : options.harness === "opencode2" ? "opencode" : options.harness).user.find((source) => existsSync12(source.path));
89009
+ if (legacy)
89010
+ return dirname8(legacy.path);
89011
+ }
89012
+ return dirname8(sharedBase);
89013
+ }
89014
+ function markerCount(content) {
89015
+ return content.match(GUIDANCE_MARKER_LINE)?.length ?? 0;
89016
+ }
89017
+ function createPromptSurfaceRuntime(options) {
89018
+ const userConfigDirectory = resolveUserConfigDirectory(options);
89019
+ const warned = new Set;
89020
+ const warnOnce = (key, message) => {
89021
+ if (warned.has(key))
89022
+ return;
89023
+ warned.add(key);
89024
+ options.warn(message);
89025
+ };
89026
+ const readGuidanceOverride = (configuredPath) => {
89027
+ if (!configuredPath)
89028
+ return;
89029
+ const path = isAbsolute5(configuredPath) ? configuredPath : resolve5(userConfigDirectory, configuredPath);
89030
+ let content;
89031
+ try {
89032
+ if (!statSync10(path).isFile()) {
89033
+ warnOnce(`guidance-not-file:${path}`, `prompt_surface.guidance_override_path (${path}) is not a file; using built-in guidance.`);
89034
+ return;
89035
+ }
89036
+ content = readFileSync11(path, "utf8");
89037
+ } catch (error) {
89038
+ const reason = error instanceof Error ? error.message : String(error);
89039
+ warnOnce(`guidance-unreadable:${path}:${reason}`, `prompt_surface.guidance_override_path (${path}) could not be read (${reason}); using built-in guidance.`);
89040
+ return;
89041
+ }
89042
+ if (content.trim().length === 0) {
89043
+ warnOnce(`guidance-empty:${path}`, `prompt_surface.guidance_override_path (${path}) is empty; using built-in guidance.`);
89044
+ return;
89045
+ }
89046
+ const markers = markerCount(content);
89047
+ if (markers !== 1) {
89048
+ warnOnce(`guidance-marker-count:${path}:${markers}`, `prompt_surface.guidance_override_path (${path}) must contain exactly one ${JSON.stringify(GUIDANCE_MARKER)} section marker; found ${markers}. Using built-in guidance.`);
89049
+ return;
89050
+ }
89051
+ return content;
89052
+ };
89053
+ return {
89054
+ resolveRegistration(config, modelKey) {
89055
+ const { preset } = resolvePromptSurface(config, modelKey);
89056
+ const overrides = config?.tool_descriptions ?? {};
89057
+ for (const [toolId, description] of Object.entries(overrides)) {
89058
+ if (!PROMPT_SURFACE_TOOL_ID_SET.has(toolId)) {
89059
+ warnOnce(`unknown-tool:${toolId}`, `prompt_surface.tool_descriptions.${toolId} is not a known ctx_* tool ID; the override was ignored.`);
89060
+ } else if (description.trim().length === 0) {
89061
+ warnOnce(`empty-tool:${toolId}`, `prompt_surface.tool_descriptions.${toolId} is empty; the override was ignored.`);
89062
+ }
89063
+ }
89064
+ return {
89065
+ preset,
89066
+ descriptionFor(toolId, fullDescription) {
89067
+ if (!PROMPT_SURFACE_TOOL_ID_SET.has(toolId))
89068
+ return fullDescription;
89069
+ const override = overrides[toolId];
89070
+ if (override !== undefined && override.trim().length > 0)
89071
+ return override;
89072
+ return preset === "light" ? LIGHT_TOOL_DESCRIPTIONS[toolId] : fullDescription;
89073
+ }
89074
+ };
89075
+ },
89076
+ resolveGuidance(config, modelKey) {
89077
+ const { preset } = resolvePromptSurface(config, modelKey);
89078
+ return {
89079
+ preset,
89080
+ primaryOverride: readGuidanceOverride(config?.guidance_override_path)
89081
+ };
89082
+ }
89083
+ };
89084
+ }
88653
89085
  var guidanceEpochCacheByRuntime = new WeakMap;
88654
89086
  function createPromptSurfaceGuidanceEpochCache(runtime) {
88655
89087
  const shared = guidanceEpochCacheByRuntime.get(runtime);
@@ -88972,7 +89404,7 @@ init_logger();
88972
89404
  // src/features/magic-context/compaction-marker.ts
88973
89405
  init_logger();
88974
89406
  import { createHash as createHash16 } from "node:crypto";
88975
- import { existsSync as existsSync12 } from "node:fs";
89407
+ import { existsSync as existsSync13 } from "node:fs";
88976
89408
  var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
88977
89409
  var ID_PREFIX_HEX_LENGTH = 12;
88978
89410
  var ID_SUFFIX_LENGTH = 14;
@@ -89044,10 +89476,16 @@ function getWritableOpenCodeDb() {
89044
89476
  closeQuietly(cachedWriteDb.db);
89045
89477
  } catch {}
89046
89478
  }
89047
- if (!existsSync12(dbPath)) {
89479
+ if (!existsSync13(dbPath)) {
89048
89480
  throw new Error(`OpenCode database not found at ${dbPath} (source=${resolution.source}; is OpenCode installed?)`);
89049
89481
  }
89050
89482
  const db = new Database(dbPath);
89483
+ try {
89484
+ assertOpenCodeStoreGeneration(db, "v1", dbPath);
89485
+ } catch (error) {
89486
+ closeQuietly(db);
89487
+ throw error;
89488
+ }
89051
89489
  db.exec("PRAGMA busy_timeout=5000");
89052
89490
  db.exec("PRAGMA journal_mode=WAL");
89053
89491
  cachedWriteDb = { path: dbPath, db };
@@ -94704,17 +95142,65 @@ function persistFilteredNoise(db, sessionId, chunk, eligibleEnd) {
94704
95142
  }
94705
95143
 
94706
95144
  // src/hooks/magic-context/producer-window-guard.ts
94707
- var PRODUCER_WINDOW_REFUSAL_MARGIN = 0.15;
95145
+ var PRODUCER_WINDOW_REFUSAL_MARGIN = 0.03;
95146
+ var HISTORIAN_TRUNCATION_MARKER = "[… tokens truncated by Magic Context to fit the historian window …]";
95147
+ function producerInputTokenLimit(contextLimitTokens, maxOutputTokens) {
95148
+ if (typeof contextLimitTokens !== "number" || !Number.isFinite(contextLimitTokens) || contextLimitTokens <= 0 || !Number.isFinite(maxOutputTokens) || maxOutputTokens < 0) {
95149
+ return;
95150
+ }
95151
+ const usableInputTokens = Math.max(0, Math.floor(contextLimitTokens - maxOutputTokens));
95152
+ return Math.max(0, Math.floor(usableInputTokens * (1 - PRODUCER_WINDOW_REFUSAL_MARGIN)));
95153
+ }
94708
95154
  function producerWindowFailureReason(input) {
94709
95155
  const { producerSourceTokens, contextLimitTokens, maxOutputTokens } = input;
94710
- if (typeof contextLimitTokens !== "number" || !Number.isFinite(contextLimitTokens) || contextLimitTokens <= 0 || !Number.isFinite(producerSourceTokens) || producerSourceTokens <= 0 || !Number.isFinite(maxOutputTokens) || maxOutputTokens < 0) {
95156
+ const producerInputLimitTokens = producerInputTokenLimit(contextLimitTokens, maxOutputTokens);
95157
+ if (producerInputLimitTokens === undefined || typeof contextLimitTokens !== "number" || !Number.isFinite(producerSourceTokens) || producerSourceTokens <= 0) {
94711
95158
  return null;
94712
95159
  }
94713
95160
  const usableInputTokens = Math.max(0, Math.floor(contextLimitTokens - maxOutputTokens));
94714
- const refusalThreshold = usableInputTokens * (1 + PRODUCER_WINDOW_REFUSAL_MARGIN);
94715
- if (producerSourceTokens < refusalThreshold)
95161
+ if (producerSourceTokens <= producerInputLimitTokens)
94716
95162
  return null;
94717
- return `producer_source_exceeds_window producer_source_tokens=${Math.round(producerSourceTokens)} usable_input_tokens=${usableInputTokens} context_limit_tokens=${Math.round(contextLimitTokens)} max_output_tokens=${Math.round(maxOutputTokens)} refusal_margin=${PRODUCER_WINDOW_REFUSAL_MARGIN}`;
95163
+ return `producer_source_exceeds_window producer_source_tokens=${Math.round(producerSourceTokens)} usable_input_tokens=${usableInputTokens} producer_input_limit_tokens=${producerInputLimitTokens} context_limit_tokens=${Math.round(contextLimitTokens)} max_output_tokens=${Math.round(maxOutputTokens)} estimator_margin=${PRODUCER_WINDOW_REFUSAL_MARGIN}`;
95164
+ }
95165
+ function splitMarkerPair() {
95166
+ return `
95167
+ ${HISTORIAN_TRUNCATION_MARKER}
95168
+ ${HISTORIAN_TRUNCATION_MARKER}
95169
+ `;
95170
+ }
95171
+ function fitAtomicHistorianSourceToProducerWindow(args) {
95172
+ const producerInputLimitTokens = producerInputTokenLimit(args.contextLimitTokens, args.maxOutputTokens);
95173
+ const originalTokens = estimateTokens(args.text);
95174
+ if (producerInputLimitTokens === undefined || originalTokens < producerInputLimitTokens || producerInputLimitTokens <= 0) {
95175
+ return { text: args.text, producerInputLimitTokens, removedTokens: 0 };
95176
+ }
95177
+ const boundary = [...args.resultBoundaries ?? []].filter((candidate) => Number.isFinite(candidate.sourceOffset) && candidate.sourceOffset > 0 && candidate.sourceOffset < args.text.length).sort((a, b) => b.bodyTokens - a.bodyTokens || a.ordinal - b.ordinal)[0];
95178
+ const splitOffset = boundary?.sourceOffset ?? Math.floor(args.text.length / 2);
95179
+ const left = args.text.slice(0, splitOffset);
95180
+ const right = args.text.slice(splitOffset);
95181
+ const markers = splitMarkerPair();
95182
+ const target = producerInputLimitTokens;
95183
+ let lo = 0;
95184
+ let hi = 1;
95185
+ let best = markers;
95186
+ for (let iteration = 0;iteration < 48; iteration++) {
95187
+ const scale = (lo + hi) / 2;
95188
+ const leftLength = Math.floor(left.length * scale);
95189
+ const rightLength = Math.floor(right.length * scale);
95190
+ const candidate = left.slice(0, leftLength) + markers + right.slice(right.length - rightLength);
95191
+ if (estimateTokens(candidate) <= target) {
95192
+ best = candidate;
95193
+ lo = scale;
95194
+ } else {
95195
+ hi = scale;
95196
+ }
95197
+ }
95198
+ return {
95199
+ text: best,
95200
+ producerInputLimitTokens,
95201
+ ...boundary ? { splitBoundaryOrdinal: boundary.ordinal } : {},
95202
+ removedTokens: Math.max(0, originalTokens - estimateTokens(best))
95203
+ };
94718
95204
  }
94719
95205
 
94720
95206
  // src/hooks/magic-context/protected-tail-boundary.ts
@@ -97075,6 +97561,25 @@ function shouldSuppressHistorianAlert(sessionId) {
97075
97561
  lastHistorianAlertBySession.set(sessionId, Date.now());
97076
97562
  return false;
97077
97563
  }
97564
+ function findDanglingPublicationBoundary(sessionId, compartments, resolveOrdinal = readRawSessionMessageOrdinalById) {
97565
+ for (const compartment of compartments) {
97566
+ if (resolveOrdinal(sessionId, compartment.startMessageId) === null) {
97567
+ return {
97568
+ sequence: compartment.sequence,
97569
+ side: "start",
97570
+ messageId: compartment.startMessageId
97571
+ };
97572
+ }
97573
+ if (resolveOrdinal(sessionId, compartment.endMessageId) === null) {
97574
+ return {
97575
+ sequence: compartment.sequence,
97576
+ side: "end",
97577
+ messageId: compartment.endMessageId
97578
+ };
97579
+ }
97580
+ }
97581
+ return null;
97582
+ }
97078
97583
  async function runCompartmentAgent(deps) {
97079
97584
  const {
97080
97585
  client,
@@ -97278,11 +97783,20 @@ async function runCompartmentAgent(deps) {
97278
97783
  rollbackDrainReservation();
97279
97784
  return;
97280
97785
  }
97281
- const chunkText = chunk.oversizeAtomicUnit ? chunk.text : truncateHistorianInputIfNeeded(chunk.text, historianChunkTokens);
97786
+ const fittedAtomicSource = chunk.oversizeAtomicUnit ? fitAtomicHistorianSourceToProducerWindow({
97787
+ text: chunk.text,
97788
+ resultBoundaries: chunk.toolResultBoundaries,
97789
+ contextLimitTokens: deps.historianContextLimit,
97790
+ maxOutputTokens: deps.historianMaxOutputTokens ?? 32000
97791
+ }) : null;
97792
+ const chunkText = chunk.oversizeAtomicUnit ? fittedAtomicSource?.text ?? chunk.text : truncateHistorianInputIfNeeded(chunk.text, historianChunkTokens);
97282
97793
  const producerSourceTokens = estimateTokens(chunkText);
97283
97794
  if (boundarySnapshot.oversizeAtomicUnit || chunk.oversizeAtomicUnit) {
97284
97795
  sessionLog(sessionId, `historian oversize admission: range=${chunk.startIndex}-${chunk.endIndex} rawComponentTokens=${boundarySnapshot.diagnostics?.head.completedFence.tokenMass ?? "unknown"} perRunCap=${perRunCap} producerSourceTokens=${producerSourceTokens} historianChunkTokens=${historianChunkTokens}; ${describeBoundaryDiagnostics(boundarySnapshot)}`);
97285
97796
  }
97797
+ if (fittedAtomicSource && fittedAtomicSource.removedTokens > 0) {
97798
+ sessionLog(sessionId, `historian pathological component split: range=${chunk.startIndex}-${chunk.endIndex} resultBoundary=${fittedAtomicSource.splitBoundaryOrdinal ?? "midpoint"} removedTokens=${fittedAtomicSource.removedTokens} producerSourceTokens=${producerSourceTokens} producerInputLimitTokens=${fittedAtomicSource.producerInputLimitTokens ?? "unknown"}`);
97799
+ }
97286
97800
  const producerWindowFailure = producerWindowFailureReason({
97287
97801
  producerSourceTokens,
97288
97802
  contextLimitTokens: deps.historianContextLimit,
@@ -97413,6 +97927,16 @@ ${chunkText}`,
97413
97927
  return;
97414
97928
  }
97415
97929
  const compartmentTagKeys = await getRawSessionTagKeysThrough(sessionId, lastCompartmentEnd, { db });
97930
+ const danglingBoundary = findDanglingPublicationBoundary(sessionId, newCompartments);
97931
+ if (danglingBoundary) {
97932
+ const reason = `compartment boundary disappeared before publication (sequence=${danglingBoundary.sequence} side=${danglingBoundary.side} missing_id=${danglingBoundary.messageId})`;
97933
+ telemetry.failureReason = `publish-boundary: ${reason}`;
97934
+ sessionLog(sessionId, `historian publish refused: sequence=${danglingBoundary.sequence} side=${danglingBoundary.side} missing_id=${danglingBoundary.messageId}; raw snapshot changed during the historian run`);
97935
+ const failCount = incrementHistorianFailure(db, sessionId, reason);
97936
+ await notifyHistorianIssue(buildHistorianFailureNotice(failCount, reason));
97937
+ rollbackDrainReservation();
97938
+ return;
97939
+ }
97416
97940
  let published = false;
97417
97941
  const transactionStartedAt = performance.now();
97418
97942
  db.exec("BEGIN IMMEDIATE");
@@ -98319,7 +98843,7 @@ function canConsumeDeferredOnThisPass(args) {
98319
98843
  return args.schedulerDecision === "execute" || args.contextPercentage >= (args.forceMaterializationPercentage ?? escalationBands(65).forceMaterializationPercentage);
98320
98844
  }
98321
98845
  function hasReclaimRide(signals) {
98322
- return signals.hardFold || signals.force || signals.explicitFlush || signals.publishedHistory || signals.agentDrop;
98846
+ return signals.hardFold || signals.force || signals.explicitFlush || signals.publishedHistory;
98323
98847
  }
98324
98848
 
98325
98849
  // src/hooks/magic-context/caveman-cleanup.ts
@@ -98441,7 +98965,7 @@ function replayCavemanCompression(sessionId, db, targets, tags) {
98441
98965
  }
98442
98966
 
98443
98967
  // src/hooks/magic-context/compaction-off-transition.ts
98444
- import { existsSync as existsSync13 } from "node:fs";
98968
+ import { existsSync as existsSync14 } from "node:fs";
98445
98969
  init_logger();
98446
98970
  var loggedUnverifiedMarkerCleanupRetry = false;
98447
98971
  var COMPACTION_OFF_FLIP_NOTICE = [
@@ -98477,7 +99001,7 @@ function clearCachedM0Baseline(db, sessionId) {
98477
99001
  return (result.changes ?? 0) > 0;
98478
99002
  }
98479
99003
  function cleanupOffMarkers(sessionId) {
98480
- if (!existsSync13(getOpenCodeDbPath())) {
99004
+ if (!existsSync14(getOpenCodeDbPath())) {
98481
99005
  return { verified: true, removedLineages: 0, removedRows: 0, retainedLineages: 0 };
98482
99006
  }
98483
99007
  return removeMcOwnedCompactionMarkers(sessionId, MARKER_SUMMARY_TEXT);
@@ -99440,7 +99964,7 @@ function createPassOutcome() {
99440
99964
  }
99441
99965
 
99442
99966
  // src/hooks/magic-context/rust-mode-transform.ts
99443
- import { createHash as createHash19 } from "node:crypto";
99967
+ import { createHash as createHash19, randomUUID as randomUUID4 } from "node:crypto";
99444
99968
  init_logger();
99445
99969
 
99446
99970
  // src/hooks/magic-context/module-state-sync.ts
@@ -99681,11 +100205,35 @@ function toFlatModuleWireBody(payload) {
99681
100205
  function moduleWireBodyBytes(payload) {
99682
100206
  return Buffer.byteLength(JSON.stringify(toFlatModuleWireBody(payload)));
99683
100207
  }
99684
- function buildPagedModuleTransformPayloads(body, pageMaxBytes = MODULE_PAGE_MAX_BYTES) {
100208
+ function buildPagedModuleTransformPayloads(body, pageMaxBytes = MODULE_PAGE_MAX_BYTES, forcePageEnvelope = false) {
99685
100209
  const serializedBody = JSON.stringify(body);
99686
100210
  const unpagedBytes = Buffer.byteLength(serializedBody);
99687
- if (unpagedBytes <= pageMaxBytes)
99688
- return [{ page: body, bytes: unpagedBytes }];
100211
+ if (unpagedBytes <= pageMaxBytes) {
100212
+ if (!forcePageEnvelope)
100213
+ return [{ page: body, bytes: unpagedBytes }];
100214
+ const pageContent = Object.fromEntries([
100215
+ "input",
100216
+ "messages",
100217
+ "native_messages",
100218
+ "ts_output",
100219
+ "ts_ck_messages",
100220
+ "normalizations",
100221
+ "tool_input_key_orders"
100222
+ ].filter((field) => {
100223
+ const value = body[field];
100224
+ return Array.isArray(value) || value !== null && typeof value === "object" && field === "tool_input_key_orders";
100225
+ }).map((field) => [field, body[field]]));
100226
+ const page = {
100227
+ transform_page_id: crypto2.createHash("sha256").update(serializedBody).digest("hex"),
100228
+ transform_generation: body.shadow_generation ?? 0,
100229
+ transform_page_index: 0,
100230
+ transform_page_total: 1,
100231
+ transform_page_complete: true,
100232
+ transform_page_digest: transformPageDigest(pageContent),
100233
+ ...body
100234
+ };
100235
+ return [{ page, bytes: Buffer.byteLength(JSON.stringify(page)) }];
100236
+ }
99689
100237
  const arrayFields = [
99690
100238
  "input",
99691
100239
  "messages",
@@ -100329,36 +100877,43 @@ function canonicalOrdinalForMessageId(args) {
100329
100877
  args.state.idOrdinalMemo.set(args.messageId, canonical);
100330
100878
  return canonical;
100331
100879
  }
100332
- function serializeCompartment(args) {
100880
+ var boundaryDiagnosticObserverForTest = null;
100881
+ function logBoundaryDiagnostic(sessionId, message) {
100882
+ sessionLog(sessionId, message);
100883
+ boundaryDiagnosticObserverForTest?.(message);
100884
+ }
100885
+ function readCompartmentBoundaryResolution(args) {
100333
100886
  const startRaw = args.readRawById(args.compartment.startMessageId);
100334
100887
  const endRaw = args.readRawById(args.compartment.endMessageId);
100335
- const startOrdinal = canonicalOrdinalForMessageId({
100336
- sessionId: args.sessionId,
100337
- raw: startRaw,
100338
- messageId: args.compartment.startMessageId,
100339
- generation: args.state.moduleGeneration,
100340
- state: args.state
100341
- });
100342
- const endOrdinal = canonicalOrdinalForMessageId({
100343
- sessionId: args.sessionId,
100344
- raw: endRaw,
100345
- messageId: args.compartment.endMessageId,
100346
- generation: args.state.moduleGeneration,
100347
- state: args.state
100348
- });
100349
- if (startOrdinal === "mismatch" || endOrdinal === "mismatch")
100350
- return "mismatch";
100351
- if (startOrdinal === null || endOrdinal === null)
100352
- return null;
100353
- const startCreatedAt = startRaw?.createdAt;
100354
- const endCreatedAt = endRaw?.createdAt;
100888
+ return {
100889
+ startRaw,
100890
+ endRaw,
100891
+ startOrdinal: canonicalOrdinalForMessageId({
100892
+ sessionId: args.sessionId,
100893
+ raw: startRaw,
100894
+ messageId: args.compartment.startMessageId,
100895
+ generation: args.state.moduleGeneration,
100896
+ state: args.state
100897
+ }),
100898
+ endOrdinal: canonicalOrdinalForMessageId({
100899
+ sessionId: args.sessionId,
100900
+ raw: endRaw,
100901
+ messageId: args.compartment.endMessageId,
100902
+ generation: args.state.moduleGeneration,
100903
+ state: args.state
100904
+ })
100905
+ };
100906
+ }
100907
+ function serializeCompartment(args) {
100908
+ const startCreatedAt = args.startRaw?.createdAt;
100909
+ const endCreatedAt = args.endRaw?.createdAt;
100355
100910
  const dateRange = typeof startCreatedAt === "number" && typeof endCreatedAt === "number" ? { start_date: formatDate(startCreatedAt), end_date: formatDate(endCreatedAt) } : {};
100356
100911
  return {
100357
100912
  sequence: args.compartment.sequence,
100358
- start_message: startOrdinal,
100359
- end_message: endOrdinal,
100360
- start_message_id: flatBlockIdForRawMessage(args.compartment.startMessageId, startRaw, "start"),
100361
- end_message_id: flatBlockIdForRawMessage(args.compartment.endMessageId, endRaw, "end"),
100913
+ start_message: args.startOrdinal,
100914
+ end_message: args.endOrdinal,
100915
+ start_message_id: flatBlockIdForRawMessage(args.compartment.startMessageId, args.startRaw, "start"),
100916
+ end_message_id: flatBlockIdForRawMessage(args.compartment.endMessageId, args.endRaw, "end"),
100362
100917
  ...dateRange,
100363
100918
  title: args.compartment.title,
100364
100919
  content: args.compartment.content,
@@ -100372,6 +100927,15 @@ function serializeCompartment(args) {
100372
100927
  created_at: args.compartment.createdAt
100373
100928
  };
100374
100929
  }
100930
+ function adjacentCompartmentBoundaryId(args) {
100931
+ const previous = args.direction === "previous";
100932
+ const row = args.db.prepare(`SELECT ${previous ? "end_message_id" : "start_message_id"} AS message_id
100933
+ FROM compartments
100934
+ WHERE session_id = ? AND sequence ${previous ? "<" : ">"} ?
100935
+ ORDER BY sequence ${previous ? "DESC" : "ASC"}
100936
+ LIMIT 1`).get(args.sessionId, args.sequence);
100937
+ return typeof row?.message_id === "string" && row.message_id.length > 0 ? row.message_id : null;
100938
+ }
100375
100939
  function seedBoundaryFromSerializedCompartments(compartments) {
100376
100940
  const serialized = compartments.filter(isRecord3).filter((compartment) => typeof compartment.sequence === "number" && typeof compartment.end_message_id === "string");
100377
100941
  serialized.sort((left, right) => left.sequence - right.sequence);
@@ -100844,21 +101408,102 @@ async function buildModuleStateSyncPayload(args) {
100844
101408
  const compartments = [];
100845
101409
  let serializedCount = 0;
100846
101410
  const compartmentsToSerialize = compartmentsChanged ? args.force ? inventory ? readCompartmentsAfterSequence(args.pass.db, args.pass.sessionId, inventory.maxCompartmentSequence) : getCompartments(args.pass.db, args.pass.sessionId) : readCompartmentsAfterSequence(args.pass.db, args.pass.sessionId, acked.compartment_sequence) : [];
100847
- for (const compartment of compartmentsToSerialize) {
100848
- args.options?.beforeSerializeCompartment?.();
100849
- if (args.options?.shouldAbortSeed?.())
100850
- return "seed_budget";
100851
- const serialized = serializeCompartment({
101411
+ const boundaryResolutions = new Map;
101412
+ const resolveBoundary = (compartment) => {
101413
+ const cached = boundaryResolutions.get(compartment.sequence);
101414
+ if (cached)
101415
+ return cached;
101416
+ const resolved = readCompartmentBoundaryResolution({
100852
101417
  compartment,
100853
101418
  sessionId: args.pass.sessionId,
100854
101419
  readRawById,
100855
101420
  state: args.state
100856
101421
  });
100857
- if (serialized === "mismatch")
101422
+ boundaryResolutions.set(compartment.sequence, resolved);
101423
+ return resolved;
101424
+ };
101425
+ const canonicalOrdinalForAdjacentId = (messageId) => {
101426
+ if (!messageId)
101427
+ return null;
101428
+ const raw = readRawById(messageId);
101429
+ return canonicalOrdinalForMessageId({
101430
+ sessionId: args.pass.sessionId,
101431
+ raw,
101432
+ messageId,
101433
+ generation: args.state.moduleGeneration,
101434
+ state: args.state
101435
+ });
101436
+ };
101437
+ let firstRawOrdinal;
101438
+ for (const [index, compartment] of compartmentsToSerialize.entries()) {
101439
+ args.options?.beforeSerializeCompartment?.();
101440
+ if (args.options?.shouldAbortSeed?.())
101441
+ return "seed_budget";
101442
+ const boundary = resolveBoundary(compartment);
101443
+ if (boundary.startOrdinal === "mismatch" || boundary.endOrdinal === "mismatch") {
100858
101444
  return "mismatch";
100859
- if (serialized === null)
100860
- return "unresolved";
100861
- compartments.push(serialized);
101445
+ }
101446
+ const startMissing = boundary.startOrdinal === null;
101447
+ const endMissing = boundary.endOrdinal === null;
101448
+ if (startMissing && endMissing) {
101449
+ logBoundaryDiagnostic(args.pass.sessionId, `state-sync compartment skipped session=${args.pass.sessionId} sequence=${compartment.sequence} missing_start_id=${compartment.startMessageId} missing_end_id=${compartment.endMessageId} method=both_boundaries_dangling`);
101450
+ continue;
101451
+ }
101452
+ let startOrdinal = boundary.startOrdinal;
101453
+ if (startOrdinal === null) {
101454
+ const previous = compartmentsToSerialize[index - 1];
101455
+ const previousBoundaryId = previous ? previous.endMessageId : adjacentCompartmentBoundaryId({
101456
+ db: args.pass.db,
101457
+ sessionId: args.pass.sessionId,
101458
+ sequence: compartment.sequence,
101459
+ direction: "previous"
101460
+ });
101461
+ const previousEnd = previous ? resolveBoundary(previous).endOrdinal : canonicalOrdinalForAdjacentId(previousBoundaryId);
101462
+ if (previousEnd === "mismatch")
101463
+ return "mismatch";
101464
+ if (typeof previousEnd === "number") {
101465
+ startOrdinal = previousEnd + 1;
101466
+ logBoundaryDiagnostic(args.pass.sessionId, `state-sync boundary repaired session=${args.pass.sessionId} sequence=${compartment.sequence} side=start missing_id=${compartment.startMessageId} resolved_ordinal=${startOrdinal} method=previous_compartment_end_plus_one`);
101467
+ } else if (previousBoundaryId === null) {
101468
+ if (firstRawOrdinal === undefined) {
101469
+ const ordinals = [
101470
+ ...readRawSessionMessageIdOrdinals(args.pass.sessionId).values()
101471
+ ].filter((ordinal) => ordinal >= 1).sort((left, right) => left - right);
101472
+ firstRawOrdinal = ordinals[0] ?? null;
101473
+ }
101474
+ startOrdinal = firstRawOrdinal;
101475
+ if (startOrdinal !== null) {
101476
+ logBoundaryDiagnostic(args.pass.sessionId, `state-sync boundary repaired session=${args.pass.sessionId} sequence=${compartment.sequence} side=start missing_id=${compartment.startMessageId} resolved_ordinal=${startOrdinal} method=raw_store_first_ordinal`);
101477
+ }
101478
+ }
101479
+ }
101480
+ let endOrdinal = boundary.endOrdinal;
101481
+ if (endOrdinal === null) {
101482
+ const next = compartmentsToSerialize[index + 1];
101483
+ const nextStart = next ? resolveBoundary(next).startOrdinal : canonicalOrdinalForAdjacentId(adjacentCompartmentBoundaryId({
101484
+ db: args.pass.db,
101485
+ sessionId: args.pass.sessionId,
101486
+ sequence: compartment.sequence,
101487
+ direction: "next"
101488
+ }));
101489
+ if (nextStart === "mismatch")
101490
+ return "mismatch";
101491
+ if (typeof nextStart === "number") {
101492
+ endOrdinal = nextStart - 1;
101493
+ logBoundaryDiagnostic(args.pass.sessionId, `state-sync boundary repaired session=${args.pass.sessionId} sequence=${compartment.sequence} side=end missing_id=${compartment.endMessageId} resolved_ordinal=${endOrdinal} method=next_compartment_start_minus_one`);
101494
+ }
101495
+ }
101496
+ if (startOrdinal === null || endOrdinal === null || startOrdinal > endOrdinal) {
101497
+ logBoundaryDiagnostic(args.pass.sessionId, `state-sync compartment skipped session=${args.pass.sessionId} sequence=${compartment.sequence} missing_start_id=${startMissing ? compartment.startMessageId : "none"} missing_end_id=${endMissing ? compartment.endMessageId : "none"} method=${startOrdinal !== null && endOrdinal !== null ? "invalid_repaired_range" : "no_adjacent_canonical_boundary"}`);
101498
+ continue;
101499
+ }
101500
+ compartments.push(serializeCompartment({
101501
+ compartment,
101502
+ startRaw: boundary.startRaw,
101503
+ endRaw: boundary.endRaw,
101504
+ startOrdinal,
101505
+ endOrdinal
101506
+ }));
100862
101507
  serializedCount += 1;
100863
101508
  const yieldEvery = Math.max(1, args.options?.yieldEveryCompartments ?? 10);
100864
101509
  if (serializedCount % yieldEvery === 0) {
@@ -103763,7 +104408,8 @@ async function runPostTransformPhase(args) {
103763
104408
  const firstRenderBust = m0M1EnabledForFold && !completeCachedPrefixAvailable;
103764
104409
  let foldExecutedThisPass = false;
103765
104410
  let publishedM1RefreshedThisPass = false;
103766
- const softRefreshOpportunity = args.schedulerDecision === "execute";
104411
+ let prefixPreflightFailed = false;
104412
+ const softRefreshOpportunity = args.schedulerDecision === "execute" || deferredMaterialize;
103767
104413
  let m0RematerializedThisPass = false;
103768
104414
  const m0CoverageBeforeFold = args.sessionMeta.cachedM0Bytes === null ? -1 : args.sessionMeta.cachedM0MaxCompartmentSeq;
103769
104415
  let m0MaterializeReason = null;
@@ -103790,6 +104436,7 @@ async function runPostTransformPhase(args) {
103790
104436
  compactionOff
103791
104437
  });
103792
104438
  preparedPrefix = foldResult;
104439
+ prefixPreflightFailed = foldResult.materializationContentionRetryExhausted === true;
103793
104440
  foldExecutedThisPass = foldExecutesThisPass(foldDueDecision.value || softRefreshOpportunity, foldResult.m0RematerializedThisPass);
103794
104441
  publishedM1RefreshedThisPass = !foldResult.materializationContentionRetryExhausted && previousM1 !== args.sessionMeta.cachedM1Bytes?.toString("utf8");
103795
104442
  m0RematerializedThisPass = foldResult.m0RematerializedThisPass;
@@ -103811,29 +104458,29 @@ async function runPostTransformPhase(args) {
103811
104458
  }
103812
104459
  } catch (error) {
103813
104460
  preparedPrefix = cachedPrefixBeforePreflight;
104461
+ prefixPreflightFailed = true;
103814
104462
  args.passOutcome?.record("m0-m1-fold-preexecution-degradation");
103815
104463
  sessionLog(args.sessionId, "transform: m[0] HARD fold pre-execution failed:", getErrorMessage(error));
103816
104464
  }
103817
104465
  sessionLog(args.sessionId, `m[0] HARD fold decision: reason=${foldDueDecision.reason ?? "unknown"} executed=${foldExecutedThisPass}`);
103818
104466
  }
103819
- const publishedWorkDrainAllowed = args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || emergencyDropEligible || foldExecutedThisPass || firstRenderBust;
103820
- const shouldReadPendingOps = !compactionOff && (materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || foldExecutedThisPass || firstRenderBust || compartmentRunning);
104467
+ const shouldReadPendingOps = !compactionOff && (materializationRequested || publishedM1RefreshedThisPass || args.schedulerDecision === "execute" || forceMaterialization || foldExecutedThisPass || firstRenderBust || compartmentRunning);
103821
104468
  const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
103822
104469
  const hasPendingUserOps = pendingOps.length > 0;
103823
104470
  const formatPendingOpsDepth = () => {
103824
104471
  const depth = getPendingOpsCount(args.db, args.sessionId);
103825
104472
  return depth === null ? "not loaded (deferred pass)" : String(depth);
103826
104473
  };
103827
- const shouldApplyPendingOps = !compactionOff && (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || foldExecutedThisPass || firstRenderBust) && publishedWorkDrainAllowed;
103828
104474
  const rideSignals = {
103829
104475
  hardFold: foldExecutedThisPass || firstRenderBust,
103830
- force: forceMaterialization || emergencyDropEligible,
103831
- explicitFlush: isExplicitFlush,
103832
- publishedHistory: publishedM1RefreshedThisPass || !m0M1EnabledForFold && (args.pendingCompartmentInjection?.compartmentCount ?? 0) > 0 && (args.historyRebuiltThisPass || args.rebuiltHistoryFromInitialPrepare || args.canConsumeDeferredLate && args.deferredHistoryWasPendingAtPassStart),
103833
- agentDrop: false
103834
- };
103835
- let shouldRunHeuristics = !compactionOff && hasReclaimRide(rideSignals) && (rideSignals.publishedHistory || materializationRequested || forceMaterialization || foldExecutedThisPass || firstRenderBust || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
103836
- let isCacheBustingPass = !compactionOff && hasReclaimRide(rideSignals);
104476
+ force: emergencyDropEligible && (args.contextUsage.percentage >= 95 || getEmergencyInputSample(args.db, args.sessionId) === 0),
104477
+ explicitFlush: isExplicitFlush || deferredMaterialize && !prefixPreflightFailed,
104478
+ publishedHistory: publishedM1RefreshedThisPass || !m0M1EnabledForFold && (args.pendingCompartmentInjection?.compartmentCount ?? 0) > 0 && (args.historyRebuiltThisPass || args.rebuiltHistoryFromInitialPrepare || args.canConsumeDeferredLate && args.deferredHistoryWasPendingAtPassStart)
104479
+ };
104480
+ const publishedWorkDrainAllowed = !compactionOff && hasReclaimRide(rideSignals);
104481
+ const shouldApplyPendingOps = publishedWorkDrainAllowed;
104482
+ const shouldRunHeuristics = !compactionOff && hasReclaimRide(rideSignals) && (rideSignals.publishedHistory || materializationRequested || forceMaterialization || foldExecutedThisPass || firstRenderBust || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
104483
+ const isCacheBustingPass = publishedWorkDrainAllowed;
103837
104484
  if (isCacheBustingPass && args.client && args.ctxReduceAvailability.callable && !hasLoggedCtxReducePermissionDeny(args.sessionId)) {
103838
104485
  try {
103839
104486
  const denied = await resolveToolPermissionDenied(args.client, args.sessionId, "ctx_reduce", args.activeAgent);
@@ -103859,13 +104506,8 @@ async function runPostTransformPhase(args) {
103859
104506
  if (!shouldApplyPendingOps && args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
103860
104507
  sessionLog(args.sessionId, `pending ops WILL NOT APPLY — reason=${args.schedulerDeferReason} pendingOps=${formatPendingOpsDepth()} context=${args.contextUsage.percentage.toFixed(1)}%`);
103861
104508
  }
103862
- if (compartmentRunning && hasPendingUserOps) {
103863
- if (publishedWorkDrainAllowed) {
103864
- const bypassReason = forceMaterialization ? `emergency >=${args.forceMaterializationPercentage}%` : "m0 hard fold";
103865
- sessionLog(args.sessionId, `transform: compartment-gate bypass (${bypassReason}) — applying ${pendingOps.length} pending ops while compartment agent runs (${args.contextUsage.percentage.toFixed(1)}%)`);
103866
- } else {
103867
- sessionLog(args.sessionId, "transform: deferring pending ops — compartment agent in progress");
103868
- }
104509
+ if (hasPendingUserOps && !shouldApplyPendingOps) {
104510
+ sessionLog(args.sessionId, `pending ops held — reason=no originating cache-bust opportunity; scheduler=${args.schedulerDecision}, historianRunning=${compartmentRunning}`);
103869
104511
  }
103870
104512
  let explicitMaterializedSuccessfully = false;
103871
104513
  let deferredMaterializedSuccessfully = false;
@@ -103897,9 +104539,6 @@ async function runPostTransformPhase(args) {
103897
104539
  const tApply = performance.now();
103898
104540
  pendingOpsDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.contextUsage.percentage >= 95 ? newestCtxReduceTagNumbers(getTagsBySession(args.db, args.sessionId)) : args.protectedTagIds, undefined, pendingOps, [], new Set, (reduction) => droppedTokenReductions.push(reduction));
103899
104541
  if (pendingOpsDidMutate) {
103900
- rideSignals.agentDrop = true;
103901
- isCacheBustingPass = hasReclaimRide(rideSignals);
103902
- shouldRunHeuristics = isCacheBustingPass;
103903
104542
  droppedCount += pendingOps.length;
103904
104543
  for (const pendingOp of pendingOps) {
103905
104544
  const message = args.targets.get(pendingOp.tagId)?.message;
@@ -104661,6 +105300,8 @@ var RUST_PARK_RETRY_INTERVAL = 5;
104661
105300
  var RUST_EMERGENCY_WALL_PCT = 95;
104662
105301
  var RUST_PARK_PROBE_PRESSURE_BYPASS_PCT = 90;
104663
105302
  var RUST_SEND_TIMEOUT_MS = 15000;
105303
+ var RUST_SILENT_RESEND_AFTER_MS = 1e4;
105304
+ var RUST_HEALTH_PROBE_TIMEOUT_MS = 2000;
104664
105305
  var RUST_LKG_FROZEN_HEALTHY_PASS_LIMIT = 8;
104665
105306
  var RUST_LKG_FROZEN_RAW_TAIL_GROWTH_LIMIT = 16;
104666
105307
  function activeAgentFromMessages(messages) {
@@ -105570,6 +106211,64 @@ function createRustModeTransform(deps, options) {
105570
106211
  clearTimeout(timer);
105571
106212
  }
105572
106213
  };
106214
+ const callTransformWithSilentResend = async (args, attemptTimeoutMs) => {
106215
+ const startedAtMs = Date.now();
106216
+ const deadlineMs = startedAtMs + attemptTimeoutMs;
106217
+ const silentAfterMs = options.silentResendAfterMsForTests ?? RUST_SILENT_RESEND_AFTER_MS;
106218
+ const probeTimeoutMs = options.healthProbeTimeoutMsForTests ?? RUST_HEALTH_PROBE_TIMEOUT_MS;
106219
+ const originalAttemptId = randomUUID4();
106220
+ const originalBody = isRecord6(args.body) ? { ...args.body, attempt_id: originalAttemptId } : args.body;
106221
+ const original = callModule({ ...args, body: originalBody }, attemptTimeoutMs);
106222
+ if (attemptTimeoutMs <= silentAfterMs)
106223
+ return original;
106224
+ let silentTimer;
106225
+ const first = await Promise.race([
106226
+ original.then((response) => ({ kind: "response", response }), (error) => ({ kind: "error", error })),
106227
+ new Promise((resolve) => {
106228
+ silentTimer = setTimeout(() => resolve({ kind: "silent" }), silentAfterMs);
106229
+ })
106230
+ ]);
106231
+ if (first.kind !== "silent")
106232
+ clearTimeout(silentTimer);
106233
+ if (first.kind === "response")
106234
+ return first.response;
106235
+ if (first.kind === "error")
106236
+ throw first.error;
106237
+ const probeBudgetMs = Math.min(probeTimeoutMs, Math.max(0, deadlineMs - Date.now()));
106238
+ if (probeBudgetMs <= 0)
106239
+ return original;
106240
+ try {
106241
+ await callModule({
106242
+ sessionId: args.sessionId,
106243
+ projectRoot: args.projectRoot,
106244
+ method: "session.status",
106245
+ body: {
106246
+ method: "session.status",
106247
+ v: 1,
106248
+ session_id: args.sessionId
106249
+ },
106250
+ bypassSessionLane: true
106251
+ }, probeBudgetMs);
106252
+ } catch {
106253
+ return original;
106254
+ }
106255
+ const remainingMs = Math.max(0, deadlineMs - Date.now());
106256
+ if (remainingMs <= 0)
106257
+ return original;
106258
+ const resendAttemptId = randomUUID4();
106259
+ sessionLog(args.sessionId, `rust silent resend original_attempt=${originalAttemptId} resend_attempt=${resendAttemptId} silent_gap_ms=${Date.now() - startedAtMs}`);
106260
+ const resendBody = isRecord6(args.body) ? {
106261
+ ...args.body,
106262
+ attempt_id: resendAttemptId,
106263
+ original_attempt_id: originalAttemptId,
106264
+ resend: true
106265
+ } : args.body;
106266
+ return callModule({
106267
+ ...args,
106268
+ body: resendBody,
106269
+ bypassSessionLane: true
106270
+ }, remainingMs);
106271
+ };
105573
106272
  const markFailure = (sessionId, state, error) => {
105574
106273
  state.consecutiveFailures = isNonRetryableStateSyncFailure(error) ? Math.max(RUST_FAILURE_PARK_THRESHOLD, state.consecutiveFailures + 1) : state.consecutiveFailures + 1;
105575
106274
  state.failureCount += 1;
@@ -105786,6 +106485,8 @@ function createRustModeTransform(deps, options) {
105786
106485
  } catch {}
105787
106486
  let appliedAt;
105788
106487
  let emergencyFailClosed = false;
106488
+ let providerProvenEmergency = false;
106489
+ let recoveryProjectRoot = options.projectRoot ?? deps.directory ?? "";
105789
106490
  const passUsageSnapshot = loadContextUsage(deps.contextUsageMap, deps.db, sessionId);
105790
106491
  requestInputTokens = Math.max(0, Math.floor(passUsageSnapshot.inputTokens));
105791
106492
  let preflightError;
@@ -105819,11 +106520,15 @@ function createRustModeTransform(deps, options) {
105819
106520
  }
105820
106521
  const transformGeometry = transformGeometryForWire(resolvedWindowGeometry);
105821
106522
  const hasTrustedEmergencyWall = transformGeometry ? transformGeometry.usable_hard > 0 : resolvedContextLimit !== undefined && resolvedContextLimit > 0;
105822
- emergencyFailClosed = isProviderOverflowFailClosedProven(sessionId) || hardWallUsagePercentage(passUsageSnapshot, transformGeometry) >= RUST_EMERGENCY_WALL_PCT && hasTrustedEmergencyWall;
106523
+ const hardWallPercentage = hardWallUsagePercentage(passUsageSnapshot, transformGeometry);
106524
+ const providerOverflowProven = isProviderOverflowFailClosedProven(sessionId);
106525
+ emergencyFailClosed = providerOverflowProven || hardWallPercentage >= RUST_EMERGENCY_WALL_PCT && hasTrustedEmergencyWall;
105823
106526
  if (overflowState) {
105824
106527
  const detectedLimitMatchesModel = overflowState.detectedContextLimitModelKey === null || canonicalModelIdentity(overflowState.detectedContextLimitModelKey) === canonicalModelIdentity(modelKey ?? "");
105825
106528
  const hasProviderProof = overflowState.detectedContextLimit > 0 && detectedLimitMatchesModel || isProviderOverflowReconfirmed(sessionId);
105826
- emergencyFailClosed ||= overflowState.needsEmergencyRecovery && overflowState.emergencyRecoveryOrigin === "provider_overflow" && hasProviderProof;
106529
+ const persistedProviderEmergency = overflowState.needsEmergencyRecovery && overflowState.emergencyRecoveryOrigin === "provider_overflow" && hasProviderProof;
106530
+ emergencyFailClosed ||= persistedProviderEmergency;
106531
+ providerProvenEmergency = hardWallPercentage >= RUST_EMERGENCY_WALL_PCT && (providerOverflowProven || persistedProviderEmergency);
105827
106532
  }
105828
106533
  const serveRawFallback = (cause) => {
105829
106534
  const contextLimit = transformGeometry?.usable_hard ?? resolvedContextLimit ?? (overflowState && overflowState.detectedContextLimit > 0 ? overflowState.detectedContextLimit : undefined);
@@ -106126,6 +106831,7 @@ function createRustModeTransform(deps, options) {
106126
106831
  nowMs: Date.now()
106127
106832
  };
106128
106833
  const projectRoot = options.projectRoot ?? directory;
106834
+ recoveryProjectRoot = projectRoot;
106129
106835
  const authoritySeqAdoption = { used: false };
106130
106836
  const memorySyncRequested = options.memorySyncRequestedSessions?.delete(sessionId) === true;
106131
106837
  const currentStateSyncInputSignature = stateSyncInputSignature({
@@ -106320,7 +107026,7 @@ function createRustModeTransform(deps, options) {
106320
107026
  logStage(sessionId, "wireBuild", wireBuildStartedAt, timings, wireDelta ? `mode=tail_delta input=${encodedInput.length}` : "mode=full");
106321
107027
  const sendTransformSeries = async (payload, detail = "") => {
106322
107028
  const pagingStartedAt = performance.now();
106323
- const pages = buildPagedModuleTransformPayloads(payload, options.modulePageMaxBytes);
107029
+ const pages = buildPagedModuleTransformPayloads(payload, options.modulePageMaxBytes, true);
106324
107030
  timings.paging += performance.now() - pagingStartedAt;
106325
107031
  const seedMessageCount = Array.isArray(payload.input) ? payload.input.length : Array.isArray(payload.messages) ? payload.messages.length : 0;
106326
107032
  const paged = pages.some((entry) => typeof entry.page.transform_page_id === "string");
@@ -106331,7 +107037,7 @@ function createRustModeTransform(deps, options) {
106331
107037
  try {
106332
107038
  const attemptClass = paged ? index === pages.length - 1 ? "transform_series_execute" : "transform_page_upload" : undefined;
106333
107039
  const attemptTimeoutMs = options.moduleTimeoutMs ?? (attemptClass === "transform_series_execute" ? transformColdStartExecuteTimeoutMs(seedMessageCount) : attemptClass === "transform_page_upload" ? TRANSFORM_PAGE_UPLOAD_TIMEOUT_MS : timeoutMs);
106334
- moduleResponse = await callModule({
107040
+ const callArgs = {
106335
107041
  sessionId,
106336
107042
  projectRoot,
106337
107043
  method: "transform",
@@ -106342,7 +107048,8 @@ function createRustModeTransform(deps, options) {
106342
107048
  },
106343
107049
  generationSensitive: paged && index > 0,
106344
107050
  attemptClass
106345
- }, attemptTimeoutMs);
107051
+ };
107052
+ moduleResponse = page.transform_page_complete ? await callTransformWithSilentResend(callArgs, attemptTimeoutMs) : await callModule(callArgs, attemptTimeoutMs);
106346
107053
  } catch (error) {
106347
107054
  if (paged && isTransformPageAttemptMismatch(error)) {
106348
107055
  return {
@@ -106868,6 +107575,21 @@ function createRustModeTransform(deps, options) {
106868
107575
  sessionLog(sessionId, "mc_rust_emergency_refusal before_lkg");
106869
107576
  markFailure(sessionId, state, error);
106870
107577
  finishPass(false, false);
107578
+ const refusedUser = newestUserMessage(messages);
107579
+ const refusedUserMessageId = refusedUser ? messageIdOf(refusedUser) : null;
107580
+ if (refusedUserMessageId) {
107581
+ try {
107582
+ options.onEngineReconnectRefusal?.({
107583
+ sessionId,
107584
+ projectRoot: recoveryProjectRoot,
107585
+ refusedUserMessageId,
107586
+ providerProvenEmergency,
107587
+ compactionOff: deps.compactionOff === true
107588
+ });
107589
+ } catch (recoveryError) {
107590
+ sessionLog(sessionId, "rust refusal recovery failed to arm:", recoveryError);
107591
+ }
107592
+ }
106871
107593
  throw new EmergencyFailClosedError(ENGINE_RECONNECTING_USER_MESSAGE, {
106872
107594
  cause: error
106873
107595
  });
@@ -107356,6 +108078,7 @@ function createTransform(deps) {
107356
108078
  projectRoot: deps.rustModeProjectRoot,
107357
108079
  notifyParked: deps.onRustModeParked,
107358
108080
  onProjectPrepared: deps.onRustModeProjectPrepared,
108081
+ onEngineReconnectRefusal: deps.onRustEngineReconnectRefusal,
107359
108082
  memorySyncRequestedSessions: deps.rustMemorySyncRequestedSessions,
107360
108083
  allowAuthorityProtocolBypassForTests: deps.rustModeAllowAuthorityProtocolBypassForTests
107361
108084
  }) : undefined;
@@ -108437,6 +109160,264 @@ async function maybeSendUpgradeReminder(deps, sessionId) {
108437
109160
  }
108438
109161
  }
108439
109162
 
109163
+ // src/shared/conflict-detector.ts
109164
+ import { homedir as homedir10 } from "node:os";
109165
+ import { join as join12 } from "node:path";
109166
+ init_logger();
109167
+
109168
+ // src/shared/opencode-config-dir.ts
109169
+ import { homedir as homedir9 } from "node:os";
109170
+ import { join as join11, resolve as resolve6 } from "node:path";
109171
+ function getCliConfigDir() {
109172
+ const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
109173
+ if (envConfigDir) {
109174
+ return resolve6(envConfigDir);
109175
+ }
109176
+ if (process.platform === "win32") {
109177
+ return join11(homedir9(), ".config", "opencode");
109178
+ }
109179
+ return join11(process.env.XDG_CONFIG_HOME || join11(homedir9(), ".config"), "opencode");
109180
+ }
109181
+ function getOpenCodeConfigDir(_options) {
109182
+ return getCliConfigDir();
109183
+ }
109184
+ function getOpenCodeConfigPaths(options) {
109185
+ const configDir = getOpenCodeConfigDir(options);
109186
+ return {
109187
+ configDir,
109188
+ configJson: join11(configDir, "opencode.json"),
109189
+ configJsonc: join11(configDir, "opencode.jsonc"),
109190
+ packageJson: join11(configDir, "package.json"),
109191
+ omoConfig: join11(configDir, "magic-context.jsonc")
109192
+ };
109193
+ }
109194
+
109195
+ // src/shared/conflict-detector.ts
109196
+ function detectConflicts(directory, options) {
109197
+ const compactionEnabled = options?.compactionEnabled ?? true;
109198
+ const hostGeneration = options?.hostGeneration ?? "v1";
109199
+ const conflicts = {
109200
+ compactionAuto: false,
109201
+ compactionPrune: false,
109202
+ dcpPlugin: false,
109203
+ omoPreemptiveCompaction: false,
109204
+ omoContextWindowMonitor: false,
109205
+ omoAnthropicRecovery: false
109206
+ };
109207
+ const reasons = [];
109208
+ let compactionResult = options?.resolvedCompaction ?? checkCompaction(directory, hostGeneration);
109209
+ if (process.env.OPENCODE_DISABLE_AUTOCOMPACT) {
109210
+ compactionResult = { auto: false, prune: false };
109211
+ }
109212
+ if (hostGeneration === "v1" && compactionEnabled && compactionResult.auto) {
109213
+ conflicts.compactionAuto = true;
109214
+ reasons.push(options?.resolvedCompaction ? "OpenCode auto-compaction is enabled (compaction.auto=true) (resolved config)" : "OpenCode auto-compaction is enabled (compaction.auto=true)");
109215
+ }
109216
+ if (hostGeneration === "v1" && compactionEnabled && compactionResult.prune) {
109217
+ conflicts.compactionPrune = true;
109218
+ reasons.push(options?.resolvedCompaction ? "OpenCode prune is enabled (compaction.prune=true) (resolved config)" : "OpenCode prune is enabled (compaction.prune=true)");
109219
+ }
109220
+ const dcpFound = checkDcpPlugin(directory);
109221
+ if (dcpFound) {
109222
+ conflicts.dcpPlugin = true;
109223
+ reasons.push("opencode-dcp plugin is installed — it conflicts with Magic Context's context management");
109224
+ }
109225
+ const omoResult = checkOmoHooks(directory);
109226
+ if (omoResult.preemptiveCompaction) {
109227
+ conflicts.omoPreemptiveCompaction = true;
109228
+ reasons.push("oh-my-opencode preemptive-compaction hook is active — it triggers compaction that conflicts with historian");
109229
+ }
109230
+ if (omoResult.contextWindowMonitor) {
109231
+ conflicts.omoContextWindowMonitor = true;
109232
+ reasons.push("oh-my-opencode context-window-monitor hook is active — it injects usage warnings that overlap with Magic Context nudges");
109233
+ }
109234
+ if (omoResult.anthropicRecovery) {
109235
+ conflicts.omoAnthropicRecovery = true;
109236
+ reasons.push("oh-my-opencode anthropic-context-window-limit-recovery hook is active — it triggers emergency compaction that bypasses historian");
109237
+ }
109238
+ return {
109239
+ hasConflict: reasons.length > 0,
109240
+ reasons,
109241
+ conflicts,
109242
+ nativeCompaction: {
109243
+ auto: compactionResult.auto,
109244
+ prune: hostGeneration === "v1" ? compactionResult.prune : false
109245
+ }
109246
+ };
109247
+ }
109248
+ function checkCompaction(directory, hostGeneration) {
109249
+ if (process.env.OPENCODE_DISABLE_AUTOCOMPACT) {
109250
+ return { auto: false, prune: false };
109251
+ }
109252
+ const projectResult = readProjectCompaction(directory, hostGeneration);
109253
+ if (projectResult.resolved)
109254
+ return projectResult;
109255
+ const userResult = readUserCompaction(hostGeneration);
109256
+ if (userResult.resolved)
109257
+ return userResult;
109258
+ return { auto: true, prune: false };
109259
+ }
109260
+ function readProjectCompaction(directory, hostGeneration) {
109261
+ const dotOcJsonc = join12(directory, ".opencode", "opencode.jsonc");
109262
+ const dotOcJson = join12(directory, ".opencode", "opencode.json");
109263
+ const dotOcConfig = readJsoncFile(dotOcJsonc) ?? readJsoncFile(dotOcJson);
109264
+ if (dotOcConfig?.compaction) {
109265
+ const c = dotOcConfig.compaction;
109266
+ if (c.auto !== undefined || hostGeneration === "v1" && c.prune !== undefined || hostGeneration === "v2" && (c.keep?.tokens !== undefined || c.buffer !== undefined)) {
109267
+ return resolvedCompactionBlock(c, hostGeneration);
109268
+ }
109269
+ }
109270
+ const rootJsonc = join12(directory, "opencode.jsonc");
109271
+ const rootJson = join12(directory, "opencode.json");
109272
+ const rootConfig = readJsoncFile(rootJsonc) ?? readJsoncFile(rootJson);
109273
+ if (rootConfig?.compaction) {
109274
+ const c = rootConfig.compaction;
109275
+ if (c.auto !== undefined || hostGeneration === "v1" && c.prune !== undefined || hostGeneration === "v2" && (c.keep?.tokens !== undefined || c.buffer !== undefined)) {
109276
+ return resolvedCompactionBlock(c, hostGeneration);
109277
+ }
109278
+ }
109279
+ return { auto: false, prune: false, resolved: false };
109280
+ }
109281
+ function readUserCompaction(hostGeneration) {
109282
+ try {
109283
+ const paths = getOpenCodeConfigPaths({ binary: "opencode" });
109284
+ const config = readJsoncFile(paths.configJsonc) ?? readJsoncFile(paths.configJson);
109285
+ if (config?.compaction) {
109286
+ const c = config.compaction;
109287
+ if (c.auto !== undefined || hostGeneration === "v1" && c.prune !== undefined || hostGeneration === "v2" && (c.keep?.tokens !== undefined || c.buffer !== undefined)) {
109288
+ return resolvedCompactionBlock(c, hostGeneration);
109289
+ }
109290
+ }
109291
+ } catch {}
109292
+ return { auto: false, prune: false, resolved: false };
109293
+ }
109294
+ function resolvedCompactionBlock(block, hostGeneration) {
109295
+ if (hostGeneration === "v2") {
109296
+ return {
109297
+ auto: block.auto !== false,
109298
+ prune: false,
109299
+ resolved: true,
109300
+ ...typeof block.keep?.tokens === "number" ? { keepTokens: block.keep.tokens } : {},
109301
+ ...typeof block.buffer === "number" ? { buffer: block.buffer } : {}
109302
+ };
109303
+ }
109304
+ return { auto: block.auto === true, prune: block.prune === true, resolved: true };
109305
+ }
109306
+ var DCP_PACKAGE_NAMES = new Set(["@tarquinen/opencode-dcp"]);
109307
+ function checkDcpPlugin(directory) {
109308
+ const plugins = collectPluginEntries(directory);
109309
+ return plugins.some((p) => matchesPackageName(p, DCP_PACKAGE_NAMES));
109310
+ }
109311
+ function matchesPackageName(entry, canonicalNames) {
109312
+ if (entry.startsWith("file:") || entry.startsWith("http:") || entry.startsWith("https:") || entry.startsWith("/") || entry.startsWith("./") || entry.startsWith("../")) {
109313
+ return false;
109314
+ }
109315
+ const lastAt = entry.lastIndexOf("@");
109316
+ const nameOnly = lastAt > 0 ? entry.slice(0, lastAt) : entry;
109317
+ return canonicalNames.has(nameOnly);
109318
+ }
109319
+ function extractPluginName(entry) {
109320
+ if (typeof entry === "string")
109321
+ return entry;
109322
+ if (Array.isArray(entry) && typeof entry[0] === "string")
109323
+ return entry[0];
109324
+ return null;
109325
+ }
109326
+ function collectPluginEntries(directory) {
109327
+ const plugins = [];
109328
+ const pushFrom = (entries) => {
109329
+ if (!entries)
109330
+ return;
109331
+ for (const entry of entries) {
109332
+ const name = extractPluginName(entry);
109333
+ if (name)
109334
+ plugins.push(name);
109335
+ }
109336
+ };
109337
+ for (const configPath of [
109338
+ join12(directory, ".opencode", "opencode.jsonc"),
109339
+ join12(directory, ".opencode", "opencode.json"),
109340
+ join12(directory, "opencode.jsonc"),
109341
+ join12(directory, "opencode.json")
109342
+ ]) {
109343
+ const config = readJsoncFile(configPath);
109344
+ pushFrom(config?.plugin);
109345
+ }
109346
+ try {
109347
+ const paths = getOpenCodeConfigPaths({ binary: "opencode" });
109348
+ for (const configPath of [paths.configJsonc, paths.configJson]) {
109349
+ const config = readJsoncFile(configPath);
109350
+ pushFrom(config?.plugin);
109351
+ }
109352
+ } catch {}
109353
+ return plugins;
109354
+ }
109355
+ var OMO_PACKAGE_NAMES = new Set(["oh-my-opencode", "oh-my-openagent"]);
109356
+ function checkOmoHooks(directory) {
109357
+ const result = {
109358
+ preemptiveCompaction: false,
109359
+ contextWindowMonitor: false,
109360
+ anthropicRecovery: false
109361
+ };
109362
+ const plugins = collectPluginEntries(directory);
109363
+ const hasOmo = plugins.some((p) => matchesPackageName(p, OMO_PACKAGE_NAMES));
109364
+ if (!hasOmo)
109365
+ return result;
109366
+ const disabledHooks = readOmoDisabledHooks(directory);
109367
+ result.preemptiveCompaction = !disabledHooks.has("preemptive-compaction");
109368
+ result.contextWindowMonitor = !disabledHooks.has("context-window-monitor");
109369
+ result.anthropicRecovery = !disabledHooks.has("anthropic-context-window-limit-recovery");
109370
+ return result;
109371
+ }
109372
+ function readOmoDisabledHooks(directory) {
109373
+ const disabled = new Set;
109374
+ const configNames = [
109375
+ "oh-my-opencode.jsonc",
109376
+ "oh-my-opencode.json",
109377
+ "oh-my-openagent.jsonc",
109378
+ "oh-my-openagent.json"
109379
+ ];
109380
+ try {
109381
+ const paths = getOpenCodeConfigPaths({ binary: "opencode" });
109382
+ for (const name of configNames) {
109383
+ const configPath = join12(paths.configDir, name);
109384
+ const config = readJsoncFile(configPath);
109385
+ if (config?.disabled_hooks) {
109386
+ for (const hook of config.disabled_hooks) {
109387
+ disabled.add(hook);
109388
+ }
109389
+ }
109390
+ }
109391
+ } catch {}
109392
+ for (const name of configNames) {
109393
+ const config = readJsoncFile(join12(directory, name));
109394
+ if (config?.disabled_hooks) {
109395
+ for (const hook of config.disabled_hooks) {
109396
+ disabled.add(hook);
109397
+ }
109398
+ }
109399
+ }
109400
+ const homeDir = process.env.HOME || homedir10();
109401
+ const omoHomeDir = join12(homeDir, ".omo");
109402
+ for (const name of ["omo.jsonc", "omo.json"]) {
109403
+ const config = readJsoncFile(join12(omoHomeDir, name));
109404
+ if (config?.["[opencode]"]?.disabled_hooks) {
109405
+ for (const hook of config["[opencode]"].disabled_hooks) {
109406
+ disabled.add(hook);
109407
+ }
109408
+ }
109409
+ }
109410
+ for (const name of ["omo.jsonc", "omo.json"]) {
109411
+ const config = readJsoncFile(join12(directory, ".omo", name));
109412
+ if (config?.["[opencode]"]?.disabled_hooks) {
109413
+ for (const hook of config["[opencode]"].disabled_hooks) {
109414
+ disabled.add(hook);
109415
+ }
109416
+ }
109417
+ }
109418
+ return disabled;
109419
+ }
109420
+
108440
109421
  // src/v2/hooks/context.ts
108441
109422
  init_data_path();
108442
109423
 
@@ -108808,7 +109789,240 @@ ${data.output?.output ?? ""}`
108808
109789
  return [...content.length ? [make("assistant", content)] : [], ...results];
108809
109790
  }
108810
109791
 
109792
+ // src/v2/hooks/hidden-child.ts
109793
+ var HIDDEN_HISTORIAN_AGENT = "historian";
109794
+ var HIDDEN_DREAMER_AGENT = "dreamer-classifier";
109795
+ async function registerHiddenChildAgents(agent) {
109796
+ await agent.transform((editor) => {
109797
+ for (const id of [HIDDEN_HISTORIAN_AGENT, HIDDEN_DREAMER_AGENT]) {
109798
+ editor.update(id, (config) => {
109799
+ config.system = "Magic Context hidden completion carrier.";
109800
+ config.description = "Internal Magic Context hidden completion carrier.";
109801
+ config.mode = "primary";
109802
+ config.hidden = true;
109803
+ config.request.settings = {};
109804
+ config.request.headers = {};
109805
+ config.request.body = {};
109806
+ config.permissions = [{ action: "*", resource: "*", effect: "deny" }];
109807
+ });
109808
+ }
109809
+ });
109810
+ }
109811
+ function newestUserText(draft) {
109812
+ const message = draft.messages.at(-1);
109813
+ if (!message || message.role !== undefined && message.role !== "user")
109814
+ return;
109815
+ const content = message.content;
109816
+ if (typeof content === "string" && content.length > 0)
109817
+ return content;
109818
+ const parts = Array.isArray(content) ? content : Array.isArray(message.parts) ? message.parts : [];
109819
+ for (const part of parts) {
109820
+ if (!part || typeof part !== "object")
109821
+ continue;
109822
+ const record = part;
109823
+ if (typeof record.text !== "string" || record.text.length === 0)
109824
+ continue;
109825
+ if (record.type === undefined || record.type === "text" || record.type === "input_text") {
109826
+ return record.text;
109827
+ }
109828
+ }
109829
+ return;
109830
+ }
109831
+ function calibratedParts(attempt) {
109832
+ const parts = attempt.request.body.parts;
109833
+ if (!Array.isArray(parts) || parts.length === 0 || parts.some((part) => !part || typeof part !== "object" || part.type !== "text" || typeof part.text !== "string")) {
109834
+ throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Hidden completion accepts text-only calibrated prompts", true);
109835
+ }
109836
+ return parts.map((part) => ({ type: "text", text: part.text }));
109837
+ }
109838
+
109839
+ class HiddenChildHook {
109840
+ childIDs = new Set;
109841
+ attempts = new Map;
109842
+ registerChild(sessionID) {
109843
+ this.childIDs.add(sessionID);
109844
+ }
109845
+ registerAttempt(marker, attempt) {
109846
+ this.registerChild(attempt.childSessionId);
109847
+ this.attempts.set(marker, attempt);
109848
+ }
109849
+ releaseAttempt(marker) {
109850
+ this.attempts.delete(marker);
109851
+ }
109852
+ owns(sessionID) {
109853
+ return this.childIDs.has(sessionID);
109854
+ }
109855
+ apply(draft) {
109856
+ if (!this.owns(draft.sessionID))
109857
+ return false;
109858
+ const raw = newestUserText(draft);
109859
+ const stripped = raw === undefined ? undefined : stripWellFormedLeadingTagPrefix(raw);
109860
+ const attempt = (raw !== undefined ? this.attempts.get(raw) : undefined) ?? (stripped && stripped !== raw ? this.attempts.get(stripped) : undefined);
109861
+ if (!attempt || attempt.childSessionId !== draft.sessionID) {
109862
+ throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Refusing an unregistered prompt on a Magic Context hidden-run session", true);
109863
+ }
109864
+ if (attempt.request.signal?.aborted) {
109865
+ throw new Error("Hidden completion prompt aborted");
109866
+ }
109867
+ const system = typeof attempt.request.body.system === "string" ? attempt.request.body.system : attempt.identity.system;
109868
+ const temperature = attempt.request.body.temperature;
109869
+ draft.system = [{ type: "text", text: system }];
109870
+ draft.messages = [{ role: "user", content: calibratedParts(attempt) }];
109871
+ draft.options = {
109872
+ maxOutputTokens: 32768,
109873
+ maxTokens: 32768,
109874
+ ...typeof temperature === "number" && Number.isFinite(temperature) ? { temperature } : {}
109875
+ };
109876
+ draft.tools = {};
109877
+ attempt.shaped = true;
109878
+ return true;
109879
+ }
109880
+ }
109881
+
108811
109882
  // src/v2/hidden-completion.ts
109883
+ var META_PREFIX = "opencode2_hidden_children:";
109884
+ var POLL_INTERVAL_MS = 200;
109885
+ function hiddenChildrenMetaKey(projectIdentity) {
109886
+ return `${META_PREFIX}${projectIdentity}`;
109887
+ }
109888
+ function emptyMeta() {
109889
+ return { version: 1, active: {}, retired_children: [] };
109890
+ }
109891
+ function isModel(value) {
109892
+ if (!value || typeof value !== "object")
109893
+ return false;
109894
+ const model = value;
109895
+ return typeof model.providerID === "string" && typeof model.modelID === "string";
109896
+ }
109897
+ function isRole(value) {
109898
+ return value === "historian" || value === "dreamer";
109899
+ }
109900
+ function isPersistedChild(value) {
109901
+ if (!value || typeof value !== "object")
109902
+ return false;
109903
+ const child = value;
109904
+ return typeof child.id === "string" && isRole(child.role) && typeof child.generation === "string" && typeof child.title === "string" && isModel(child.model) && typeof child.created_at === "number" && typeof child.title_reasserted === "boolean";
109905
+ }
109906
+ function parseMeta(value) {
109907
+ if (value === null)
109908
+ return emptyMeta();
109909
+ let parsed;
109910
+ try {
109911
+ parsed = JSON.parse(value);
109912
+ } catch (error) {
109913
+ throw new Error("Invalid OpenCode 2 hidden-child metadata JSON", { cause: error });
109914
+ }
109915
+ if (!parsed || typeof parsed !== "object") {
109916
+ throw new Error("Invalid OpenCode 2 hidden-child metadata");
109917
+ }
109918
+ const candidate = parsed;
109919
+ if (candidate.version !== 1 || !candidate.active || !candidate.retired_children) {
109920
+ throw new Error("Unsupported OpenCode 2 hidden-child metadata version");
109921
+ }
109922
+ const active = {};
109923
+ for (const role of ["historian", "dreamer"]) {
109924
+ const child = candidate.active[role];
109925
+ if (child !== undefined) {
109926
+ if (!isPersistedChild(child) || child.role !== role) {
109927
+ throw new Error(`Invalid OpenCode 2 ${role} child metadata`);
109928
+ }
109929
+ active[role] = child;
109930
+ }
109931
+ }
109932
+ const retired = candidate.retired_children;
109933
+ if (!Array.isArray(retired) || retired.some((child) => !isPersistedChild(child) || typeof child.retired_at !== "number" || typeof child.reason !== "string")) {
109934
+ throw new Error("Invalid OpenCode 2 retired-child metadata");
109935
+ }
109936
+ return { version: 1, active, retired_children: retired };
109937
+ }
109938
+
109939
+ class HiddenChildStateStore {
109940
+ db;
109941
+ key;
109942
+ constructor(db, projectIdentity) {
109943
+ this.db = db;
109944
+ this.key = hiddenChildrenMetaKey(projectIdentity);
109945
+ }
109946
+ read() {
109947
+ const row = this.db.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?").get(this.key);
109948
+ return parseMeta(row?.value ?? null);
109949
+ }
109950
+ mutate(change) {
109951
+ return this.db.transaction(() => {
109952
+ const state = this.read();
109953
+ const result = change(state);
109954
+ this.db.prepare(`INSERT INTO schema_migrations_meta (key, value) VALUES (?, ?)
109955
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(this.key, JSON.stringify(state));
109956
+ return result;
109957
+ })();
109958
+ }
109959
+ put(child) {
109960
+ this.mutate((state) => {
109961
+ state.active[child.role] = child;
109962
+ });
109963
+ }
109964
+ updateModel(child, model) {
109965
+ return this.mutate((state) => {
109966
+ const active = state.active[child.role];
109967
+ if (!active || active.id !== child.id)
109968
+ return { ...child, model };
109969
+ active.model = model;
109970
+ return { ...active };
109971
+ });
109972
+ }
109973
+ markTitleReasserted(child) {
109974
+ return this.mutate((state) => {
109975
+ const active = state.active[child.role];
109976
+ if (!active || active.id !== child.id)
109977
+ return { ...child, title_reasserted: true };
109978
+ active.title_reasserted = true;
109979
+ return { ...active };
109980
+ });
109981
+ }
109982
+ retire(child, reason) {
109983
+ this.mutate((state) => {
109984
+ const active = state.active[child.role];
109985
+ if (!active || active.id !== child.id)
109986
+ return;
109987
+ state.retired_children.push({
109988
+ ...active,
109989
+ retired_at: Date.now(),
109990
+ reason
109991
+ });
109992
+ delete state.active[child.role];
109993
+ });
109994
+ }
109995
+ }
109996
+ function modelKey(model) {
109997
+ return `${model.providerID}/${model.modelID}`;
109998
+ }
109999
+ function sameModel(left, right) {
110000
+ return modelKey(left) === modelKey(right) && left.variant === right.variant;
110001
+ }
110002
+ function configuredHead(identity) {
110003
+ const candidates = [identity.model, ...identity.configuredModels ?? []];
110004
+ for (const candidate of candidates) {
110005
+ const entry = toModelEntry(candidate);
110006
+ const parsed = entry ? parseProviderModel(entry.model) : null;
110007
+ if (parsed)
110008
+ return { ...parsed, ...entry?.qualifier ? { variant: entry.qualifier } : {} };
110009
+ }
110010
+ return;
110011
+ }
110012
+ function roleFor(identity) {
110013
+ return identity.kind === "dreamer-task" ? "dreamer" : "historian";
110014
+ }
110015
+ function roleTitle(role) {
110016
+ return role === "historian" ? "Magic Context historian" : "Magic Context dreamer";
110017
+ }
110018
+ function roleAgent(role) {
110019
+ return role === "historian" ? HIDDEN_HISTORIAN_AGENT : HIDDEN_DREAMER_AGENT;
110020
+ }
110021
+ function promptText(request) {
110022
+ const parts = request.body.parts;
110023
+ return Array.isArray(parts) ? parts.flatMap((part) => part && typeof part === "object" && typeof part.text === "string" ? [part.text] : []).join(`
110024
+ `) : "";
110025
+ }
108812
110026
  function meter(system, prompt, text) {
108813
110027
  return {
108814
110028
  input: estimateTokens(system) + estimateTokens(prompt),
@@ -108817,115 +110031,294 @@ function meter(system, prompt, text) {
108817
110031
  cacheWrite: 0
108818
110032
  };
108819
110033
  }
108820
- async function createV2HiddenCompletionExecutor(host, currentModel) {
110034
+ function successfulReusableAssistant(row) {
110035
+ return row !== undefined && typeof row.data.finish === "string" && row.data.error === undefined && row.data.tokens !== undefined;
110036
+ }
110037
+ function assistantText(row) {
110038
+ const text = (row.data.content ?? []).flatMap((part) => part.type === "text" && typeof part.text === "string" ? [part.text] : []).join("");
110039
+ return text.length > 0 ? text : null;
110040
+ }
110041
+ function errorText(value) {
110042
+ if (value instanceof Error)
110043
+ return value.message;
110044
+ if (typeof value === "string")
110045
+ return value;
110046
+ try {
110047
+ return JSON.stringify(value);
110048
+ } catch {
110049
+ return String(value);
110050
+ }
110051
+ }
110052
+ function requestModel(request, current) {
110053
+ const requested = request.body.model;
110054
+ if (requested && typeof requested.providerID === "string" && typeof requested.modelID === "string") {
110055
+ return {
110056
+ providerID: requested.providerID,
110057
+ modelID: requested.modelID,
110058
+ ...typeof request.body.variant === "string" ? { variant: request.body.variant } : {}
110059
+ };
110060
+ }
110061
+ return current;
110062
+ }
110063
+ function withReader(openReader, read) {
110064
+ const reader = openReader();
110065
+ try {
110066
+ return read(reader);
110067
+ } finally {
110068
+ reader.close?.();
110069
+ }
110070
+ }
110071
+ async function sleepUntilPoll(signal, deadline) {
110072
+ if (signal?.aborted)
110073
+ throw new Error("Hidden completion prompt aborted");
110074
+ const delay = Math.min(POLL_INTERVAL_MS, Math.max(0, deadline - Date.now()));
110075
+ if (delay <= 0)
110076
+ return;
110077
+ await new Promise((resolve, reject) => {
110078
+ const timer = setTimeout(resolve, delay);
110079
+ const abort = () => {
110080
+ clearTimeout(timer);
110081
+ reject(new Error("Hidden completion prompt aborted"));
110082
+ };
110083
+ signal?.addEventListener("abort", abort, { once: true });
110084
+ if (signal?.aborted)
110085
+ abort();
110086
+ else
110087
+ setTimeout(() => {
110088
+ signal?.removeEventListener("abort", abort);
110089
+ }, delay);
110090
+ });
110091
+ }
110092
+ async function awaitAssistantRow(openReader, childID, afterSeq, deadline, signal) {
110093
+ for (;; ) {
110094
+ const row = withReader(openReader, (reader) => reader.latestAssistant(childID));
110095
+ if (row && row.seq > afterSeq) {
110096
+ if (row.data.error !== undefined) {
110097
+ throw new Error(`Hidden completion provider error: ${errorText(row.data.error)}`);
110098
+ }
110099
+ if (typeof row.data.finish === "string")
110100
+ return row;
110101
+ }
110102
+ if (Date.now() >= deadline) {
110103
+ throw new Error("Hidden completion timed out waiting for a persisted assistant row");
110104
+ }
110105
+ await sleepUntilPoll(signal, deadline);
110106
+ }
110107
+ }
110108
+ async function createV2HiddenCompletionExecutor(host, options) {
108821
110109
  const runs = new WeakMap;
108822
- const pending = new Map;
108823
- const modelKey = (model) => `${model.providerID}/${model.modelID}`;
108824
- const requireModel = async (sessionID) => {
108825
- const model = sessionID ? await currentModel(sessionID) : null;
108826
- if (!model)
108827
- throw new HiddenCompletionRefusal("hidden_model_unsupported", "Hidden completion requires an existing session with a resolved current model", true);
108828
- return model;
108829
- };
108830
- const refuseModel = (requested, actual, terminal = false) => {
108831
- throw new HiddenCompletionRefusal("hidden_model_unsupported", `Hidden completion model ${requested} is unavailable on opencode2; use the session model ${actual} in historian.model or dreaming task model configuration, or unset the configured model`, terminal);
108832
- };
108833
- await host.hook("generate", async (draft) => {
108834
- const last = draft.messages.at(-1);
108835
- if (last?.role !== "user" || last.content.length !== 1)
108836
- return;
108837
- const part = last.content[0];
108838
- if (part?.type !== "text" || typeof part.text !== "string")
108839
- return;
108840
- const attempt = pending.get(part.text);
108841
- if (!attempt || draft.sessionID !== attempt.run.identity.parentSessionId)
108842
- return;
108843
- const actual = `${draft.model.providerID}/${draft.model.id}`;
108844
- if (modelKey(attempt.model) !== actual)
108845
- refuseModel(modelKey(attempt.model), actual);
108846
- if (attempt.request.signal?.aborted)
108847
- throw new Error("Hidden completion prompt aborted");
108848
- const body = attempt.request.body;
108849
- if (typeof body.variant === "string" && body.variant !== draft.model.variant) {
108850
- refuseModel(`${actual} (${body.variant})`, `${actual} (${draft.model.variant ?? "default variant"})`);
110110
+ const store = new HiddenChildStateStore(options.db, options.projectIdentity);
110111
+ const generation = options.generation ?? "opencode2";
110112
+ const roleTails = new Map;
110113
+ const persisted = store.read();
110114
+ for (const child of [...Object.values(persisted.active), ...persisted.retired_children]) {
110115
+ if (child)
110116
+ options.hook.registerChild(child.id);
110117
+ }
110118
+ const acquireRole = async (role) => {
110119
+ const previous = roleTails.get(role) ?? Promise.resolve();
110120
+ let release;
110121
+ const gate = new Promise((resolve) => {
110122
+ release = resolve;
110123
+ });
110124
+ const tail = previous.then(() => gate);
110125
+ roleTails.set(role, tail);
110126
+ await previous;
110127
+ return () => {
110128
+ release();
110129
+ if (roleTails.get(role) === tail)
110130
+ roleTails.delete(role);
110131
+ };
110132
+ };
110133
+ const resolveHead = async (identity) => {
110134
+ const configured = configuredHead(identity);
110135
+ if (configured)
110136
+ return configured;
110137
+ if (!identity.parentSessionId) {
110138
+ throw new HiddenCompletionRefusal("hidden_model_unsupported", "Hidden completion requires a configured model or an existing parent session model", true);
108851
110139
  }
108852
- const parts = body.parts;
108853
- if (!Array.isArray(parts) || parts.some((item) => item.type !== "text" || typeof item.text !== "string")) {
108854
- throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Hidden completion accepts text-only calibrated prompts", true);
110140
+ const parent = await host.get({ sessionID: identity.parentSessionId });
110141
+ if (!parent.model) {
110142
+ throw new HiddenCompletionRefusal("hidden_model_unsupported", "Hidden completion could not resolve the parent session model", true);
108855
110143
  }
108856
- draft.system = [
108857
- {
108858
- type: "text",
108859
- text: typeof body.system === "string" ? body.system : attempt.run.identity.system
110144
+ return {
110145
+ providerID: parent.model.providerID,
110146
+ modelID: parent.model.id,
110147
+ ...parent.model.variant ? { variant: parent.model.variant } : {}
110148
+ };
110149
+ };
110150
+ const switchChildModel = async (run, requested) => {
110151
+ if (sameModel(run.child.model, requested))
110152
+ return;
110153
+ await host.switchModel({
110154
+ sessionID: run.child.id,
110155
+ model: {
110156
+ providerID: requested.providerID,
110157
+ id: requested.modelID,
110158
+ ...requested.variant ? { variant: requested.variant } : {}
108860
110159
  }
108861
- ];
108862
- draft.messages = [
108863
- { role: "user", content: parts.map((item) => ({ type: "text", text: item.text })) }
108864
- ];
108865
- draft.tools = {};
108866
- if (attempt.run.identity.maxOutputTokens !== undefined)
108867
- draft.options.maxOutputTokens = attempt.run.identity.maxOutputTokens;
108868
- attempt.shaped = true;
108869
- });
110160
+ });
110161
+ run.child = store.updateModel(run.child, requested);
110162
+ };
110163
+ const retire = (run, reason) => {
110164
+ if (run.retired)
110165
+ return;
110166
+ store.retire(run.child, reason);
110167
+ run.retired = true;
110168
+ };
110169
+ const interruptAndRetire = async (run, reason) => {
110170
+ try {
110171
+ await host.interrupt({ sessionID: run.child.id });
110172
+ } finally {
110173
+ retire(run, reason);
110174
+ }
110175
+ };
108870
110176
  return {
108871
110177
  capabilities: { tools: false, harness: "opencode2" },
108872
110178
  async open(identity) {
108873
- const model = await requireModel(identity.parentSessionId);
108874
- const configured = (identity.configuredModels ?? (identity.model ? [identity.model] : [])).map(toModelEntry).filter((entry) => entry !== undefined);
108875
- if (configured.length && !configured.some((entry) => entry.model === modelKey(model))) {
108876
- refuseModel(configured.map((entry) => entry.model).join(", "), modelKey(model), true);
108877
- }
108878
- const handle = { id: `mc:hidden:${crypto.randomUUID()}` };
108879
- runs.set(handle, { identity });
108880
- return handle;
110179
+ const role = roleFor(identity);
110180
+ const releaseRole = await acquireRole(role);
110181
+ let openedChild;
110182
+ try {
110183
+ await options.ensureAgent?.();
110184
+ const head = await resolveHead(identity);
110185
+ let active = store.read().active[role];
110186
+ if (active && active.generation !== generation) {
110187
+ store.retire(active, "host-generation-changed");
110188
+ active = undefined;
110189
+ }
110190
+ if (active) {
110191
+ const activeID = active.id;
110192
+ const latest = withReader(options.openReader, (reader) => reader.latestAssistant(activeID));
110193
+ if (!successfulReusableAssistant(latest)) {
110194
+ store.retire(active, "newest-assistant-not-reusable");
110195
+ active = undefined;
110196
+ }
110197
+ }
110198
+ if (!active) {
110199
+ const title = roleTitle(role);
110200
+ const created = await host.create({
110201
+ title,
110202
+ agent: roleAgent(role),
110203
+ model: {
110204
+ providerID: head.providerID,
110205
+ id: head.modelID,
110206
+ ...head.variant ? { variant: head.variant } : {}
110207
+ },
110208
+ location: { directory: identity.directory },
110209
+ metadata: { magic_context: "hidden-run", role }
110210
+ });
110211
+ if (!created.id)
110212
+ throw new Error("OpenCode 2 did not return a child session id");
110213
+ active = {
110214
+ id: created.id,
110215
+ role,
110216
+ generation,
110217
+ title,
110218
+ model: head,
110219
+ created_at: Date.now(),
110220
+ title_reasserted: false
110221
+ };
110222
+ store.put(active);
110223
+ options.hook.registerChild(active.id);
110224
+ }
110225
+ openedChild = active;
110226
+ const handle = { id: active.id, childSessionId: active.id };
110227
+ const run = {
110228
+ identity,
110229
+ role,
110230
+ child: active,
110231
+ releaseRole,
110232
+ failed: false,
110233
+ retired: false
110234
+ };
110235
+ runs.set(handle, run);
110236
+ await switchChildModel(run, head);
110237
+ return handle;
110238
+ } catch (error) {
110239
+ if (openedChild)
110240
+ store.retire(openedChild, "hidden-run-open-failed");
110241
+ releaseRole();
110242
+ throw error;
110243
+ }
108881
110244
  },
108882
110245
  async attempt(handle, request) {
108883
110246
  const run = runs.get(handle);
108884
110247
  if (!run)
108885
110248
  throw new Error("Unknown hidden completion run");
108886
- const sessionID = run.identity.parentSessionId;
108887
- const actual = await requireModel(sessionID);
108888
- if (sessionID === undefined)
108889
- throw new Error("Hidden completion session id missing");
108890
- const requested = request.body.model ?? actual;
108891
- if (modelKey(requested) !== modelKey(actual))
108892
- refuseModel(modelKey(requested), modelKey(actual));
108893
- if (request.signal?.aborted)
110249
+ if (request.signal?.aborted) {
110250
+ await interruptAndRetire(run, "aborted-before-prompt");
108894
110251
  throw new Error("Hidden completion prompt aborted");
108895
- const marker = `${handle.id}:${crypto.randomUUID()}`;
108896
- const state = { run, request, model: actual, shaped: false };
108897
- pending.set(marker, state);
110252
+ }
110253
+ const requested = requestModel(request, run.child.model);
110254
+ await switchChildModel(run, requested);
110255
+ const baseline = withReader(options.openReader, (reader) => reader.latestSequence(run.child.id));
110256
+ const marker = `mc:hidden:${crypto.randomUUID()}:${crypto.randomUUID()}`;
110257
+ const attempt = {
110258
+ childSessionId: run.child.id,
110259
+ identity: run.identity,
110260
+ request,
110261
+ shaped: false
110262
+ };
110263
+ options.hook.registerAttempt(marker, attempt);
110264
+ const deadline = Date.now() + run.identity.timeoutMs;
110265
+ let abortReject;
110266
+ const aborted = new Promise((_resolve, reject) => {
110267
+ abortReject = reject;
110268
+ });
110269
+ const onAbort = () => {
110270
+ interruptAndRetire(run, "prompt-aborted").finally(() => abortReject(new Error("Hidden completion prompt aborted")));
110271
+ };
110272
+ const deadlineTimer = setTimeout(() => {
110273
+ interruptAndRetire(run, "prompt-timeout").finally(() => abortReject(new Error("Hidden completion prompt timed out")));
110274
+ }, Math.max(0, deadline - Date.now()));
110275
+ request.signal?.addEventListener("abort", onAbort, { once: true });
108898
110276
  try {
108899
- const generation = host.generate({ sessionID, prompt: marker }, { signal: request.signal });
108900
- const result = await new Promise((resolve, reject) => {
108901
- const abort = () => reject(new Error("Hidden completion prompt aborted"));
108902
- request.signal?.addEventListener("abort", abort, { once: true });
108903
- generation.then(resolve, reject).finally(() => {
108904
- request.signal?.removeEventListener("abort", abort);
108905
- pending.delete(marker);
108906
- });
108907
- if (request.signal?.aborted)
108908
- abort();
108909
- });
108910
- if (!state.shaped)
108911
- throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Host did not dispatch the hidden generate hook", true);
108912
- const prompt = request.body.parts.map((part) => part.text).join(`
108913
- `);
110277
+ await Promise.race([
110278
+ host.prompt({ sessionID: run.child.id, text: marker }),
110279
+ aborted
110280
+ ]);
110281
+ await Promise.race([host.wait({ sessionID: run.child.id }), aborted]);
110282
+ clearTimeout(deadlineTimer);
110283
+ const row = await Promise.race([
110284
+ awaitAssistantRow(options.openReader, run.child.id, baseline, deadline, request.signal),
110285
+ aborted
110286
+ ]);
110287
+ if (!attempt.shaped) {
110288
+ throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Host did not dispatch the hidden child context hook", true);
110289
+ }
110290
+ if (!run.child.title_reasserted) {
110291
+ await host.update({ sessionID: run.child.id, title: run.child.title });
110292
+ run.child = store.markTitleReasserted(run.child);
110293
+ }
110294
+ const text = assistantText(row);
108914
110295
  const system = typeof request.body.system === "string" ? request.body.system : run.identity.system;
108915
- const usage = meter(system, prompt, result.text);
108916
- usage.input += run.usage?.input ?? 0;
108917
- usage.output += run.usage?.output ?? 0;
108918
- run.usage = usage;
110296
+ const tokens = row.data.tokens;
108919
110297
  run.completion = {
108920
- text: result.text,
108921
- usage,
108922
- lengthCapped: false,
108923
- providerId: actual.providerID,
108924
- modelId: actual.modelID
110298
+ text,
110299
+ reasoning: null,
110300
+ usage: tokens ? {
110301
+ input: tokens.input,
110302
+ output: tokens.output,
110303
+ cacheRead: tokens.cache.read,
110304
+ cacheWrite: tokens.cache.write
110305
+ } : meter(system, promptText(request), text ?? ""),
110306
+ lengthCapped: ["length", "max_tokens"].includes(row.data.finish ?? ""),
110307
+ providerId: row.data.model?.providerID ?? requested.providerID,
110308
+ modelId: row.data.model?.id ?? requested.modelID
108925
110309
  };
110310
+ } catch (error) {
110311
+ run.failed = true;
110312
+ if (request.signal?.aborted && !run.retired) {
110313
+ await interruptAndRetire(run, "prompt-aborted");
110314
+ } else if (error instanceof Error && error.message.includes("timed out") && !run.retired) {
110315
+ await interruptAndRetire(run, "prompt-timeout");
110316
+ }
110317
+ throw error;
108926
110318
  } finally {
108927
- if (!request.signal?.aborted)
108928
- pending.delete(marker);
110319
+ clearTimeout(deadlineTimer);
110320
+ request.signal?.removeEventListener("abort", onAbort);
110321
+ options.hook.releaseAttempt(marker);
108929
110322
  }
108930
110323
  },
108931
110324
  async collect(handle) {
@@ -108934,18 +110327,27 @@ async function createV2HiddenCompletionExecutor(host, currentModel) {
108934
110327
  throw new Error("Hidden completion has no settled output");
108935
110328
  return completion;
108936
110329
  },
108937
- async close() {}
110330
+ async close(handle, settlement) {
110331
+ if (!handle)
110332
+ return;
110333
+ const run = runs.get(handle);
110334
+ if (!run)
110335
+ return;
110336
+ try {
110337
+ if (!run.completion && (run.failed || !settlement.promptSettled)) {
110338
+ retire(run, "hidden-run-failed");
110339
+ }
110340
+ } finally {
110341
+ runs.delete(handle);
110342
+ run.releaseRole();
110343
+ }
110344
+ }
108938
110345
  };
108939
110346
  }
108940
110347
 
108941
110348
  // src/v2/store-reader.ts
108942
- import { join as join11 } from "node:path";
108943
- function sourceDatabaseFilename(channel, env = process.env) {
108944
- return env.OPENCODE_DB ?? (["latest", "dev", "beta", "next", "prod"].includes(channel) || env.OPENCODE_DISABLE_CHANNEL_DB === "1" || env.OPENCODE_DISABLE_CHANNEL_DB === "true" ? "opencode.db" : `opencode-${channel.replace(/[^a-zA-Z0-9._-]/g, "")}.db`);
108945
- }
108946
110349
  function gaDatabasePath(dataHome, channel = "latest", env = process.env) {
108947
- const filename = sourceDatabaseFilename(channel, env);
108948
- return filename === ":memory:" ? filename : join11(dataHome, "opencode", filename);
110350
+ return resolveOpenCodeDbPath("v2", { dataHome, channel, env }).path;
108949
110351
  }
108950
110352
  function decode2(row) {
108951
110353
  const data = JSON.parse(row.data);
@@ -108962,6 +110364,12 @@ class V2StoreReader {
108962
110364
  db;
108963
110365
  constructor(path) {
108964
110366
  this.db = new Database(path, { readonly: true, fileMustExist: true });
110367
+ try {
110368
+ assertOpenCodeStoreGeneration(this.db, "v2", path);
110369
+ } catch (error) {
110370
+ this.db.close();
110371
+ throw error;
110372
+ }
108965
110373
  }
108966
110374
  close() {
108967
110375
  this.db.close();
@@ -108987,6 +110395,16 @@ class V2StoreReader {
108987
110395
  idleRows(sessionID, after = -1) {
108988
110396
  return this.all(sessionID, after, "idle");
108989
110397
  }
110398
+ latestSequence(sessionID) {
110399
+ const row = this.db.prepare("SELECT MAX(seq) AS seq FROM session_message WHERE session_id = ?").get(sessionID);
110400
+ return typeof row?.seq === "number" ? row.seq : -1;
110401
+ }
110402
+ latestAssistant(sessionID) {
110403
+ const row = this.db.prepare(`SELECT id, session_id, type, seq, data FROM session_message
110404
+ WHERE session_id = ? AND type = 'assistant'
110405
+ ORDER BY seq DESC LIMIT 1`).get(sessionID);
110406
+ return row ? decode2(row) : undefined;
110407
+ }
108990
110408
  window(sessionID) {
108991
110409
  return this.db.transaction(() => {
108992
110410
  const cut = this.latestCompaction(sessionID);
@@ -109062,7 +110480,7 @@ function buildDreamTaskRuntimeConfigs(dreamer, harness, language, muralModel) {
109062
110480
 
109063
110481
  // src/features/magic-context/dreamer/task-executor.ts
109064
110482
  import { createHash as createHash27 } from "node:crypto";
109065
- import { existsSync as existsSync16 } from "node:fs";
110483
+ import { existsSync as existsSync17 } from "node:fs";
109066
110484
 
109067
110485
  // src/agents/dreamer.ts
109068
110486
  var DREAMER_AGENT = "dreamer";
@@ -112099,7 +113517,7 @@ function deterministicJitterMs(intervalMs, noteId, hash) {
112099
113517
  }
112100
113518
 
112101
113519
  // src/features/magic-context/smart-notes/wake-plane.ts
112102
- import { join as join12 } from "node:path";
113520
+ import { join as join13 } from "node:path";
112103
113521
  init_data_path();
112104
113522
  var WAKE_PLANE_CAPABILITY = "wake.create";
112105
113523
  var WAKE_PLANE_STATUS_TTL_MS = 5 * 60 * 1000;
@@ -112109,7 +113527,7 @@ var inFlightProbe = null;
112109
113527
  var catalogProbe = probeWakePlaneCatalog;
112110
113528
  var now = () => Date.now();
112111
113529
  function connectionFile() {
112112
- return join12(getDataDir(), "cortexkit", "run", "subc-connection.json");
113530
+ return join13(getDataDir(), "cortexkit", "run", "subc-connection.json");
112113
113531
  }
112114
113532
  async function probeWakePlaneCatalog() {
112115
113533
  const file = connectionFile();
@@ -112759,8 +114177,8 @@ async function archiveExpiredMemories(args) {
112759
114177
 
112760
114178
  // src/features/magic-context/dreamer/maintain-docs-protected-enforcement.ts
112761
114179
  init_logger();
112762
- import { existsSync as existsSync14, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "node:fs";
112763
- import { join as join13 } from "node:path";
114180
+ import { existsSync as existsSync15, readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "node:fs";
114181
+ import { join as join14 } from "node:path";
112764
114182
 
112765
114183
  // src/features/magic-context/dreamer/protected-regions.ts
112766
114184
  var PROTECTED_START_TOKEN = "mc:protected START";
@@ -112861,10 +114279,10 @@ var MAINTAIN_DOCS_SNAPSHOT_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
112861
114279
  function snapshotMaintainDocsFiles(docsDir) {
112862
114280
  const snapshot = new Map;
112863
114281
  for (const name of MAINTAIN_DOCS_SNAPSHOT_FILES) {
112864
- const path = join13(docsDir, name);
114282
+ const path = join14(docsDir, name);
112865
114283
  try {
112866
- if (existsSync14(path)) {
112867
- snapshot.set(name, readFileSync11(path, "utf8"));
114284
+ if (existsSync15(path)) {
114285
+ snapshot.set(name, readFileSync12(path, "utf8"));
112868
114286
  }
112869
114287
  } catch {}
112870
114288
  }
@@ -112872,9 +114290,9 @@ function snapshotMaintainDocsFiles(docsDir) {
112872
114290
  }
112873
114291
  function enforceMaintainDocsProtectedRegions(args) {
112874
114292
  for (const [fileName, original] of args.snapshot) {
112875
- const path = join13(args.docsDir, fileName);
114293
+ const path = join14(args.docsDir, fileName);
112876
114294
  try {
112877
- const current = readFileSync11(path, "utf8");
114295
+ const current = readFileSync12(path, "utf8");
112878
114296
  const { text, violated } = enforceProtectedRegions(original, current);
112879
114297
  if (!violated) {
112880
114298
  continue;
@@ -112892,7 +114310,7 @@ import { createHash as createHash25 } from "node:crypto";
112892
114310
  init_logger();
112893
114311
 
112894
114312
  // src/features/magic-context/dreamer/map-memories-prompt.ts
112895
- import { existsSync as existsSync15, statSync as statSync10 } from "node:fs";
114313
+ import { existsSync as existsSync16, statSync as statSync11 } from "node:fs";
112896
114314
  import path8 from "node:path";
112897
114315
  var MAP_MEMORIES_SYSTEM_PROMPT = `You are a memory mapper for the magic-context system. You map project memories to the repository files that back them.
112898
114316
 
@@ -112930,7 +114348,7 @@ function extractMemoryCandidatePaths(content, repoDir) {
112930
114348
  if (!abs.startsWith(`${root}/`))
112931
114349
  continue;
112932
114350
  try {
112933
- if (existsSync15(abs) && statSync10(abs).isFile())
114351
+ if (existsSync16(abs) && statSync11(abs).isFile())
112934
114352
  found.add(rel);
112935
114353
  } catch {}
112936
114354
  if (found.size >= MAX_SEED_PATHS_PER_MEMORY)
@@ -115562,8 +116980,8 @@ async function runAgenticTask(config, ctx, helpers) {
115562
116980
  const lastRunAt = getTaskScheduleState(db, projectIdentity, config.task)?.lastRunAt ?? null;
115563
116981
  const maintainDocsSnapshot = task === "maintain-docs" ? snapshotMaintainDocsFiles(docsDir) : undefined;
115564
116982
  const existingDocs = task === "maintain-docs" ? {
115565
- architecture: existsSync16(`${docsDir}/ARCHITECTURE.md`),
115566
- structure: existsSync16(`${docsDir}/STRUCTURE.md`)
116983
+ architecture: existsSync17(`${docsDir}/ARCHITECTURE.md`),
116984
+ structure: existsSync17(`${docsDir}/STRUCTURE.md`)
115567
116985
  } : undefined;
115568
116986
  const abortController = new AbortController;
115569
116987
  let leaseLost = false;
@@ -115790,11 +117208,11 @@ function planDueTasks(db, projectIdentity, tasks, now) {
115790
117208
  }
115791
117209
  return due;
115792
117210
  }
115793
- function advanceAfterRun(db, projectIdentity, due, finishedAt, status, error, schedulePatch) {
117211
+ function advanceAfterRun(db, projectIdentity, due, finishedAt, status, error, schedulePatch, startedAt) {
115794
117212
  writeTaskScheduleState(db, {
115795
117213
  projectPath: projectIdentity,
115796
117214
  task: due.config.task,
115797
- lastRunAt: status === "completed" ? finishedAt : readLastRunAt(db, projectIdentity, due.config.task),
117215
+ lastRunAt: status === "completed" ? startedAt ?? finishedAt : readLastRunAt(db, projectIdentity, due.config.task),
115798
117216
  nextDueAt: nextDueAtMs(due.config.schedule, finishedAt, due.scheduledAt),
115799
117217
  schedule: due.config.schedule,
115800
117218
  lastStatus: status,
@@ -115878,6 +117296,7 @@ async function runDomainGroup(deps, group, cb) {
115878
117296
  }
115879
117297
  }
115880
117298
  let outcome;
117299
+ const startedAt = Date.now();
115881
117300
  try {
115882
117301
  outcome = await executor(due.config, {
115883
117302
  db,
@@ -115891,7 +117310,7 @@ async function runDomainGroup(deps, group, cb) {
115891
117310
  }
115892
117311
  const finishedAt = Date.now();
115893
117312
  if (outcome.status === "completed") {
115894
- advanceAfterRun(db, projectIdentity, due, finishedAt, "completed", null, outcome.schedulePatch);
117313
+ advanceAfterRun(db, projectIdentity, due, finishedAt, "completed", null, outcome.schedulePatch, startedAt);
115895
117314
  cb?.onRan?.(due.config.task, outcome.detail, outcome.backlog);
115896
117315
  } else if (outcome.transient) {
115897
117316
  recordTransientFailure(db, projectIdentity, due, finishedAt, outcome.error ?? null);
@@ -116136,7 +117555,7 @@ function rawMessages(rows, history = rows) {
116136
117555
  const ordinals = new Map(history.filter(isRawRow).map((row, index) => [row.id, index + 1]));
116137
117556
  return rows.filter(isRawRow).map((row) => ({
116138
117557
  id: row.id,
116139
- ordinal: ordinals.get(row.id),
117558
+ ordinal: ordinals.get(row.id) ?? 0,
116140
117559
  role: row.type === "assistant" ? "assistant" : "user",
116141
117560
  createdAt: row.data.time?.created,
116142
117561
  parts: row.type === "assistant" ? (row.data.content ?? []).map((part) => {
@@ -116170,20 +117589,96 @@ function createHostSeams(context, read, liveModels) {
116170
117589
  hostRefuse: (_client, sessionID) => interruptBeforeProvider(context.session, sessionID)
116171
117590
  };
116172
117591
  }
117592
+ function toolResultText(result) {
117593
+ const content = result?.content ?? result?.output;
117594
+ if (typeof content === "string")
117595
+ return content;
117596
+ if (content && typeof content === "object" && !Array.isArray(content)) {
117597
+ const record = content;
117598
+ if (typeof record.text === "string")
117599
+ return record.text;
117600
+ if (typeof record.value === "string")
117601
+ return record.value;
117602
+ return "";
117603
+ }
117604
+ if (!Array.isArray(content))
117605
+ return "";
117606
+ return content.map((part) => {
117607
+ if (typeof part === "string")
117608
+ return part;
117609
+ if (!part || typeof part !== "object")
117610
+ return "";
117611
+ const record = part;
117612
+ if (typeof record.text === "string")
117613
+ return record.text;
117614
+ if (typeof record.value === "string")
117615
+ return record.value;
117616
+ return "";
117617
+ }).filter(Boolean).join(`
117618
+ `);
117619
+ }
117620
+ function catalogModels(listed) {
117621
+ const rows = Array.isArray(listed) ? listed : listed && typeof listed === "object" && Array.isArray(listed.data) ? listed.data : [];
117622
+ return rows.flatMap((row) => {
117623
+ if (!row || typeof row !== "object")
117624
+ return [];
117625
+ const model = row;
117626
+ if (typeof model.id !== "string" || typeof model.providerID !== "string")
117627
+ return [];
117628
+ const contextLimit = model.limit?.context;
117629
+ if (typeof contextLimit !== "number" || !Number.isFinite(contextLimit))
117630
+ return [];
117631
+ return [{ id: model.id, providerID: model.providerID, limit: { context: contextLimit } }];
117632
+ });
117633
+ }
117634
+ function applyV2PromptSurfaceTools(draft, runtime, config) {
117635
+ if (!draft.tools)
117636
+ return;
117637
+ const modelKey = `${draft.model.providerID}/${draft.model.id}`;
117638
+ const registration = runtime.resolveRegistration(config, modelKey);
117639
+ for (const id of ACTIVE_TOOL_IDS) {
117640
+ const tool = draft.tools[id];
117641
+ if (!tool)
117642
+ continue;
117643
+ tool.description = registration.descriptionFor(id, tool.description);
117644
+ }
117645
+ }
116173
117646
  async function registerContext(context) {
116174
117647
  const directory = context.location.directory;
116175
117648
  const config = loadPluginConfigDetailed(directory).config;
116176
117649
  if (!config.enabled || !isCompactionEnabled(config))
116177
117650
  return;
117651
+ const conflicts = detectConflicts(directory, {
117652
+ compactionEnabled: true,
117653
+ hostGeneration: "v2"
117654
+ });
117655
+ if (conflicts.hasConflict) {
117656
+ console.warn(`[magic-context] v2 setup disabled by conflicting context hooks: ${conflicts.reasons.join("; ")}`);
117657
+ return;
117658
+ }
116178
117659
  const folds = new FoldOwner(context.storage);
116179
117660
  const limits = new Map;
116180
117661
  const queriedModels = new Set;
116181
117662
  const liveModels = new Map;
116182
- const hostGenerate = context.session.generate?.bind(context.session);
116183
- const hiddenCompletionExecutor = hostGenerate ? await createV2HiddenCompletionExecutor({
116184
- hook: (name, callback) => context.session.hook(name, callback),
116185
- generate: (input, options) => hostGenerate(input, options)
116186
- }, (sessionID) => liveModels.get(sessionID) ?? null) : undefined;
117663
+ const promptSurfaceRuntime = createPromptSurfaceRuntime({
117664
+ harness: "opencode2",
117665
+ directory,
117666
+ warn: (message) => console.warn(`[magic-context] config warning: ${message}`)
117667
+ });
117668
+ let db;
117669
+ try {
117670
+ db = openDatabase() ?? undefined;
117671
+ } catch {}
117672
+ const hiddenChildHook = new HiddenChildHook;
117673
+ await registerHiddenChildAgents(context.agent);
117674
+ let hiddenAgentsReady;
117675
+ const hiddenCompletionExecutor = db && isDatabasePersisted(db) ? await createV2HiddenCompletionExecutor(context.session, {
117676
+ db,
117677
+ projectIdentity: resolveProjectIdentity(directory) ?? directory,
117678
+ hook: hiddenChildHook,
117679
+ ensureAgent: () => hiddenAgentsReady ??= context.agent.reload(),
117680
+ openReader: () => new V2StoreReader(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"))
117681
+ }) : undefined;
116187
117682
  const dreamTrigger = hiddenCompletionExecutor && config.dreamer && !config.dreamer.disable ? startDreamTrigger(context, {
116188
117683
  config: config.dreamer,
116189
117684
  executor: hiddenCompletionExecutor,
@@ -116204,16 +117699,17 @@ async function registerContext(context) {
116204
117699
  let toolDuties;
116205
117700
  await context.tool.hook("execute.before", (draft) => assertExecutableToolInput(draft.input));
116206
117701
  await context.tool.hook("execute.after", async (draft) => {
116207
- if (!db || draft.status !== "completed")
117702
+ if (!db)
117703
+ return;
117704
+ if (draft.status && draft.status !== "completed")
116208
117705
  return;
116209
117706
  try {
116210
117707
  toolDuties ??= createToolExecuteAfterHook({ db, channel1StateBySession: channel1 });
116211
- const content = draft.result?.content;
116212
- const text = typeof content === "string" ? content : Array.isArray(content) ? content.filter((part) => part.type === "text").map((part) => part.text).join(`
116213
- `) : "";
117708
+ const text = toolResultText(draft.result);
116214
117709
  const output = { output: text };
116215
117710
  await toolDuties({ ...draft, args: draft.input }, output);
116216
117711
  if (draft.result && output.output !== text) {
117712
+ const content = draft.result.content;
116217
117713
  if (typeof content === "string")
116218
117714
  draft.result.content = output.output;
116219
117715
  else if (Array.isArray(content) && output.output.startsWith(text))
@@ -116238,7 +117734,6 @@ async function registerContext(context) {
116238
117734
  getCount: (sessionID) => read(sessionID).length
116239
117735
  });
116240
117736
  let transform;
116241
- let db;
116242
117737
  const refuseIfUnsafe = async (draft) => {
116243
117738
  let unsafe = false;
116244
117739
  try {
@@ -116252,10 +117747,8 @@ async function registerContext(context) {
116252
117747
  const tokens = latest?.data.tokens;
116253
117748
  const modelKey = `${draft.model.providerID}/${draft.model.id}`;
116254
117749
  if (!queriedModels.has(modelKey)) {
116255
- const catalog = await context.catalog.model.list({
116256
- location: context.location
116257
- });
116258
- for (const model of catalog.data)
117750
+ const catalog = await Promise.resolve(context.model.list());
117751
+ for (const model of catalogModels(catalog))
116259
117752
  limits.set(`${model.providerID}/${model.id}`, model.limit.context);
116260
117753
  queriedModels.add(modelKey);
116261
117754
  }
@@ -116275,7 +117768,8 @@ async function registerContext(context) {
116275
117768
  } finally {
116276
117769
  reader.close();
116277
117770
  }
116278
- } catch {
117771
+ } catch (error) {
117772
+ console.warn("[magic-context] v2 refuseIfUnsafe", error);
116279
117773
  unsafe = true;
116280
117774
  }
116281
117775
  if (unsafe)
@@ -116328,6 +117822,26 @@ async function registerContext(context) {
116328
117822
  }
116329
117823
  });
116330
117824
  await context.session.hook("context", async (draft) => {
117825
+ if (hiddenChildHook.apply(draft))
117826
+ return;
117827
+ liveModels.set(draft.sessionID, {
117828
+ providerID: draft.model.providerID,
117829
+ modelID: draft.model.id
117830
+ });
117831
+ variants.set(draft.sessionID, draft.model.variant);
117832
+ agents.set(draft.sessionID, draft.agent);
117833
+ applyV2PromptSurfaceTools(draft, promptSurfaceRuntime, config.prompt_surface);
117834
+ if (context.tool.transform) {
117835
+ const modelKey = `${draft.model.providerID}/${draft.model.id}`;
117836
+ const registration = promptSurfaceRuntime.resolveRegistration(config.prompt_surface, modelKey);
117837
+ await context.tool.transform((editor) => {
117838
+ for (const id of ACTIVE_TOOL_IDS) {
117839
+ editor.update(id, (tool) => {
117840
+ tool.description = registration.descriptionFor(id, tool.description);
117841
+ });
117842
+ }
117843
+ });
117844
+ }
116331
117845
  let postFold = false;
116332
117846
  try {
116333
117847
  if (await refuseIfUnsafe(draft))
@@ -116444,6 +117958,9 @@ async function registerContext(context) {
116444
117958
  const mapped = adaptPayload(draft, admitted);
116445
117959
  await transform({}, mapped);
116446
117960
  mapped.commit();
117961
+ if (db) {
117962
+ await deliverPendingChannel2(context, db, draft.sessionID, channel1.get(draft.sessionID));
117963
+ }
116447
117964
  if (checkpoint && submitted !== undefined) {
116448
117965
  const head = draft.messages.find((message) => message.id === HEAD_IDS[0]);
116449
117966
  const baseline = head?.content.find((part) => part.type === "text")?.text;
@@ -116483,8 +118000,8 @@ ${baseline}
116483
118000
  }
116484
118001
 
116485
118002
  // src/v2/hooks/update-check.ts
116486
- import { existsSync as existsSync17, readFileSync as readFileSync12 } from "node:fs";
116487
- import { dirname as dirname8, join as join15 } from "node:path";
118003
+ import { existsSync as existsSync18, readFileSync as readFileSync13 } from "node:fs";
118004
+ import { dirname as dirname9, join as join16 } from "node:path";
116488
118005
  import { fileURLToPath as fileURLToPath2 } from "node:url";
116489
118006
 
116490
118007
  // src/hooks/auto-update-checker/checker.ts
@@ -116492,26 +118009,26 @@ init_logger();
116492
118009
  var import_comment_json = __toESM(require_src2(), 1);
116493
118010
 
116494
118011
  // src/hooks/auto-update-checker/constants.ts
116495
- import { homedir as homedir9, platform } from "node:os";
116496
- import { join as join14 } from "node:path";
118012
+ import { homedir as homedir11, platform } from "node:os";
118013
+ import { join as join15 } from "node:path";
116497
118014
  var PACKAGE_NAME = "@cortexkit/opencode-magic-context";
116498
118015
  var NPM_REGISTRY_URL = "https://registry.npmjs.org";
116499
118016
  var NPM_FETCH_TIMEOUT = 1e4;
116500
118017
  function getOpenCodeCacheRoot() {
116501
118018
  if (platform() === "win32") {
116502
- return join14(process.env.LOCALAPPDATA ?? homedir9(), "opencode");
118019
+ return join15(process.env.LOCALAPPDATA ?? homedir11(), "opencode");
116503
118020
  }
116504
- return join14(homedir9(), ".cache", "opencode");
118021
+ return join15(homedir11(), ".cache", "opencode");
116505
118022
  }
116506
118023
  function getOpenCodeConfigRoot() {
116507
118024
  if (platform() === "win32") {
116508
- return join14(process.env.APPDATA ?? join14(homedir9(), "AppData", "Roaming"), "opencode");
118025
+ return join15(process.env.APPDATA ?? join15(homedir11(), "AppData", "Roaming"), "opencode");
116509
118026
  }
116510
- return join14(process.env.XDG_CONFIG_HOME ?? join14(homedir9(), ".config"), "opencode");
118027
+ return join15(process.env.XDG_CONFIG_HOME ?? join15(homedir11(), ".config"), "opencode");
116511
118028
  }
116512
- var CACHE_DIR = join14(getOpenCodeCacheRoot(), "packages");
116513
- var USER_OPENCODE_CONFIG = join14(getOpenCodeConfigRoot(), "opencode.json");
116514
- var USER_OPENCODE_CONFIG_JSONC = join14(getOpenCodeConfigRoot(), "opencode.jsonc");
118029
+ var CACHE_DIR = join15(getOpenCodeCacheRoot(), "packages");
118030
+ var USER_OPENCODE_CONFIG = join15(getOpenCodeConfigRoot(), "opencode.json");
118031
+ var USER_OPENCODE_CONFIG_JSONC = join15(getOpenCodeConfigRoot(), "opencode.jsonc");
116515
118032
 
116516
118033
  // src/hooks/auto-update-checker/semver.ts
116517
118034
  function isValidSemver(version) {
@@ -116573,18 +118090,18 @@ async function getLatestVersion(channel = "latest", options = {}) {
116573
118090
  // src/v2/hooks/update-check.ts
116574
118091
  init_rpc_notifications();
116575
118092
  function packageInfo() {
116576
- let directory = dirname8(fileURLToPath2(import.meta.url));
118093
+ let directory = dirname9(fileURLToPath2(import.meta.url));
116577
118094
  for (;; ) {
116578
118095
  try {
116579
- const pkg = JSON.parse(readFileSync12(join15(directory, "package.json"), "utf8"));
118096
+ const pkg = JSON.parse(readFileSync13(join16(directory, "package.json"), "utf8"));
116580
118097
  if (pkg.name === "@cortexkit/opencode-magic-context" && typeof pkg.version === "string") {
116581
118098
  return {
116582
118099
  version: pkg.version,
116583
- development: existsSync17(join15(directory, "src/v2/server.ts"))
118100
+ development: existsSync18(join16(directory, "src/v2/server.ts"))
116584
118101
  };
116585
118102
  }
116586
118103
  } catch {}
116587
- const parent = dirname8(directory);
118104
+ const parent = dirname9(directory);
116588
118105
  if (parent === directory)
116589
118106
  throw new Error("Magic Context package manifest is unavailable");
116590
118107
  directory = parent;
@@ -116627,7 +118144,17 @@ function startUpdateChecks(context, check = (signal) => {
116627
118144
  }
116628
118145
 
116629
118146
  // src/v2/server.ts
118147
+ function isOpenCode2HostContext(context) {
118148
+ if (typeof context !== "object" || context === null)
118149
+ return false;
118150
+ const session = context.session;
118151
+ return typeof session === "object" && session !== null && typeof session.hook === "function";
118152
+ }
116630
118153
  async function setup(context) {
118154
+ if (!isOpenCode2HostContext(context)) {
118155
+ log("v2 setup() called on a host without session.hook; v1 server lane owns this host, v2 lane inert");
118156
+ return async () => {};
118157
+ }
116631
118158
  setHarness("opencode2");
116632
118159
  const duties = await registerContext(context);
116633
118160
  const checks = loadPluginConfigDetailed(context.location.directory).config.auto_update === false ? undefined : startUpdateChecks(context);
@@ -116643,5 +118170,6 @@ var server_default = {
116643
118170
  };
116644
118171
  export {
116645
118172
  server_default as default,
118173
+ isOpenCode2HostContext,
116646
118174
  setup
116647
118175
  };