@wolfx/opencode-magic-context 0.22.3 → 0.22.4

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 (34) hide show
  1. package/dist/config/schema/magic-context.d.ts +7 -0
  2. package/dist/config/schema/magic-context.d.ts.map +1 -1
  3. package/dist/features/magic-context/dreamer/runner.d.ts.map +1 -1
  4. package/dist/features/magic-context/key-files/aft-availability.d.ts.map +1 -1
  5. package/dist/features/magic-context/key-files/identify-key-files.d.ts.map +1 -1
  6. package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
  7. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  8. package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
  9. package/dist/features/magic-context/storage-db.d.ts +1 -1
  10. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  11. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  12. package/dist/features/magic-context/storage-meta-shared.d.ts +7 -1
  13. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  14. package/dist/features/magic-context/tool-definition-tokens.d.ts +21 -0
  15. package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
  16. package/dist/features/magic-context/types.d.ts +4 -0
  17. package/dist/features/magic-context/types.d.ts.map +1 -1
  18. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
  19. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
  20. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  21. package/dist/hooks/magic-context/inject-compartments.d.ts +41 -0
  22. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  23. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +2 -1
  24. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  25. package/dist/hooks/magic-context/transform.d.ts +8 -0
  26. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +268 -72
  29. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  30. package/dist/shared/keep-subagents.d.ts +7 -0
  31. package/dist/shared/keep-subagents.d.ts.map +1 -0
  32. package/package.json +1 -1
  33. package/src/shared/keep-subagents.test.ts +39 -0
  34. package/src/shared/keep-subagents.ts +33 -0
package/dist/index.js CHANGED
@@ -14967,6 +14967,7 @@ var init_magic_context = __esm(() => {
14967
14967
  model: DEFAULT_LOCAL_EMBEDDING_MODEL
14968
14968
  }).describe("Embedding provider configuration"),
14969
14969
  temporal_awareness: exports_external.boolean().default(true).describe('Inject wall-clock gap markers (<!-- +Xm -->) between user messages where > 5 min elapsed since the previous message, and add start/end date attributes on compartments. Gives the agent a sense of session pacing and "how long ago" across multi-day sessions. Graduated from experimental.temporal_awareness; default: true (set false to opt out).'),
14970
+ keep_subagents: exports_external.boolean().default(false).describe("Debug: keep the child sessions Magic Context spawns for its own subagents (historian, dreamer, sidekick, memory-migration) instead of deleting them on success. Useful for short-term inspection/data collection — their full transcript (prompt, tool calls, token usage, output) stays in the host session store. Kept sessions accumulate until manually cleared; leave false for normal use. Requires a restart to take effect."),
14970
14971
  caveman_text_compression: exports_external.object({
14971
14972
  enabled: exports_external.boolean().default(false).describe("Apply deterministic caveman-style text compression to old conversation text. Only active when ctx_reduce_enabled=false. Compresses user/assistant text in oldest-first tiers: ultra (oldest 20%), full, lite, untouched (newest 40%)."),
14972
14973
  min_chars: exports_external.number().min(100).max(1e4).default(500).describe("Text parts shorter than this (characters) stay untouched. Min 100, max 10000. Default: 500.")
@@ -15749,6 +15750,15 @@ function extractLatestAssistantText(messages) {
15749
15750
  }
15750
15751
  var init_assistant_message_extractor = () => {};
15751
15752
 
15753
+ // src/shared/keep-subagents.ts
15754
+ function setKeepSubagents(value) {
15755
+ keepSubagents = value === true;
15756
+ }
15757
+ function shouldKeepSubagents() {
15758
+ return keepSubagents;
15759
+ }
15760
+ var keepSubagents = false;
15761
+
15752
15762
  // src/features/magic-context/compartment-lease.ts
15753
15763
  function acquireCompartmentLease(db, sessionId, holderId) {
15754
15764
  const acquiredAt = Date.now();
@@ -15835,7 +15845,7 @@ function isSessionMetaRow(row) {
15835
15845
  if (row === null || typeof row !== "object")
15836
15846
  return false;
15837
15847
  const r = row;
15838
- return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
15848
+ return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.cached_m0_system_hash) && isStringOrNull(r.cached_m0_tool_set_hash) && isStringOrNull(r.cached_m0_model_key) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
15839
15849
  }
15840
15850
  function getDefaultSessionMeta(sessionId) {
15841
15851
  return {
@@ -15871,6 +15881,9 @@ function getDefaultSessionMeta(sessionId) {
15871
15881
  cachedM0MaterializedAt: null,
15872
15882
  cachedM0SessionFactsVersion: null,
15873
15883
  cachedM0UpgradeState: null,
15884
+ cachedM0SystemHash: null,
15885
+ cachedM0ToolSetHash: null,
15886
+ cachedM0ModelKey: null,
15874
15887
  lastObservedModelKey: null,
15875
15888
  upgradeRemindedAt: null,
15876
15889
  piStableIdScheme: null
@@ -15922,6 +15935,9 @@ function toSessionMeta(row) {
15922
15935
  cachedM0MaterializedAt: numOrNull(row.cached_m0_materialized_at),
15923
15936
  cachedM0SessionFactsVersion: numOrNull(row.cached_m0_session_facts_version),
15924
15937
  cachedM0UpgradeState: stringOrNull(row.cached_m0_upgrade_state),
15938
+ cachedM0SystemHash: stringOrNull(row.cached_m0_system_hash),
15939
+ cachedM0ToolSetHash: stringOrNull(row.cached_m0_tool_set_hash),
15940
+ cachedM0ModelKey: stringOrNull(row.cached_m0_model_key),
15925
15941
  lastObservedModelKey: stringOrNull(row.last_observed_model_key),
15926
15942
  upgradeRemindedAt: numOrNull(row.upgrade_reminded_at),
15927
15943
  piStableIdScheme: numOrNull(row.pi_stable_id_scheme)
@@ -15941,8 +15957,11 @@ function persistCachedM0(db, sessionId, payload) {
15941
15957
  cached_m0_project_docs_hash = ?,
15942
15958
  cached_m0_materialized_at = ?,
15943
15959
  cached_m0_session_facts_version = ?,
15944
- cached_m0_upgrade_state = ?
15945
- WHERE session_id = ?`).run(Buffer2.from(payload.m0Bytes), payload.projectMemoryEpoch, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer2.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, sessionId);
15960
+ cached_m0_upgrade_state = ?,
15961
+ cached_m0_system_hash = ?,
15962
+ cached_m0_tool_set_hash = ?,
15963
+ cached_m0_model_key = ?
15964
+ WHERE session_id = ?`).run(Buffer2.from(payload.m0Bytes), payload.projectMemoryEpoch, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer2.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, payload.systemHash ?? "", payload.toolSetHash ?? "", payload.modelKey ?? "", sessionId);
15946
15965
  }
15947
15966
  function clearCachedM0M1(db, sessionId) {
15948
15967
  ensureSessionMetaRow(db, sessionId);
@@ -15960,6 +15979,9 @@ function clearCachedM0M1(db, sessionId) {
15960
15979
  ["cached_m0_materialized_at", null],
15961
15980
  ["cached_m0_session_facts_version", null],
15962
15981
  ["cached_m0_upgrade_state", null],
15982
+ ["cached_m0_system_hash", null],
15983
+ ["cached_m0_tool_set_hash", null],
15984
+ ["cached_m0_model_key", null],
15963
15985
  ["cached_m0_last_baseline_end_message_id", null],
15964
15986
  ["memory_block_cache", ""],
15965
15987
  ["memory_block_count", 0],
@@ -16012,6 +16034,9 @@ var init_storage_meta_shared = __esm(() => {
16012
16034
  "cached_m0_materialized_at",
16013
16035
  "cached_m0_session_facts_version",
16014
16036
  "cached_m0_upgrade_state",
16037
+ "cached_m0_system_hash",
16038
+ "cached_m0_tool_set_hash",
16039
+ "cached_m0_model_key",
16015
16040
  "last_observed_model_key",
16016
16041
  "upgrade_reminded_at",
16017
16042
  "pi_stable_id_scheme"
@@ -16048,6 +16073,9 @@ var init_storage_meta_shared = __esm(() => {
16048
16073
  cachedM0MaterializedAt: "cached_m0_materialized_at",
16049
16074
  cachedM0SessionFactsVersion: "cached_m0_session_facts_version",
16050
16075
  cachedM0UpgradeState: "cached_m0_upgrade_state",
16076
+ cachedM0SystemHash: "cached_m0_system_hash",
16077
+ cachedM0ToolSetHash: "cached_m0_tool_set_hash",
16078
+ cachedM0ModelKey: "cached_m0_model_key",
16051
16079
  lastObservedModelKey: "last_observed_model_key",
16052
16080
  upgradeRemindedAt: "upgrade_reminded_at",
16053
16081
  piStableIdScheme: "pi_stable_id_scheme"
@@ -150116,6 +150144,18 @@ function keyFor(providerID, modelID, agentName) {
150116
150144
  function fingerprintFor(description, parameters) {
150117
150145
  return createHash3("sha256").update(description).update("\x00").update(stableStringify(parameters)).digest("hex");
150118
150146
  }
150147
+ function getCurrentToolSetHash(providerID, modelID, agentName) {
150148
+ const key = keyFor(providerID, modelID, agentName);
150149
+ const inner = fingerprints.get(key);
150150
+ if (!inner || inner.size === 0)
150151
+ return "";
150152
+ const parts = [];
150153
+ for (const [toolID, fp] of inner)
150154
+ parts.push(`${toolID}\x00${fp}`);
150155
+ parts.sort();
150156
+ return createHash3("sha256").update(parts.join(`
150157
+ `)).digest("hex");
150158
+ }
150119
150159
  function setDatabase(db) {
150120
150160
  persistenceDb = db;
150121
150161
  cachedInsertStmt = null;
@@ -150909,6 +150949,9 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
150909
150949
  cached_m0_materialized_at INTEGER,
150910
150950
  cached_m0_session_facts_version INTEGER,
150911
150951
  cached_m0_upgrade_state TEXT,
150952
+ cached_m0_system_hash TEXT,
150953
+ cached_m0_tool_set_hash TEXT,
150954
+ cached_m0_model_key TEXT,
150912
150955
  cached_m0_last_baseline_end_message_id TEXT,
150913
150956
  upgrade_reminded_at INTEGER,
150914
150957
  pi_stable_id_scheme INTEGER
@@ -151100,6 +151143,9 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
151100
151143
  ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
151101
151144
  ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
151102
151145
  ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
151146
+ ensureColumn(db, "session_meta", "cached_m0_system_hash", "TEXT");
151147
+ ensureColumn(db, "session_meta", "cached_m0_tool_set_hash", "TEXT");
151148
+ ensureColumn(db, "session_meta", "cached_m0_model_key", "TEXT");
151103
151149
  ensureColumn(db, "session_meta", "cached_m0_last_baseline_end_message_id", "TEXT");
151104
151150
  ensureColumn(db, "session_meta", "upgrade_reminded_at", "INTEGER");
151105
151151
  db.exec(`
@@ -151304,7 +151350,7 @@ function getDatabasePersistenceError(db) {
151304
151350
  return null;
151305
151351
  return persistenceErrorByDatabase.get(db) ?? null;
151306
151352
  }
151307
- var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 29, sqlitePragmaConfig;
151353
+ var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 30, sqlitePragmaConfig;
151308
151354
  var init_storage_db = __esm(async () => {
151309
151355
  init_data_path();
151310
151356
  init_logger();
@@ -152127,6 +152173,28 @@ var init_migrations = __esm(async () => {
152127
152173
  db.exec("ALTER TABLE notes ADD COLUMN anchor_ordinal INTEGER");
152128
152174
  }
152129
152175
  }
152176
+ },
152177
+ {
152178
+ version: 30,
152179
+ description: "HARD-bust m[0] markers: cached system/tool-set/model identity",
152180
+ up: (db) => {
152181
+ const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta' LIMIT 1").get();
152182
+ if (!hasSessionMeta)
152183
+ return;
152184
+ ensureColumn(db, "session_meta", "cached_m0_system_hash", "TEXT");
152185
+ ensureColumn(db, "session_meta", "cached_m0_tool_set_hash", "TEXT");
152186
+ ensureColumn(db, "session_meta", "cached_m0_model_key", "TEXT");
152187
+ const columns = new Set(db.prepare("PRAGMA table_info(session_meta)").all().map((column) => column.name));
152188
+ if (columns.has("cached_m0_bytes")) {
152189
+ db.prepare(`UPDATE session_meta SET
152190
+ cached_m0_bytes = NULL,
152191
+ cached_m1_bytes = NULL,
152192
+ cached_m0_materialized_at = NULL,
152193
+ cached_m0_system_hash = NULL,
152194
+ cached_m0_tool_set_hash = NULL,
152195
+ cached_m0_model_key = NULL`).run();
152196
+ }
152197
+ }
152130
152198
  }
152131
152199
  ];
152132
152200
  LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -153045,6 +153113,9 @@ var init_storage_meta_session = __esm(async () => {
153045
153113
  cached_m0_materialized_at: "NULL AS cached_m0_materialized_at",
153046
153114
  cached_m0_session_facts_version: "NULL AS cached_m0_session_facts_version",
153047
153115
  cached_m0_upgrade_state: "NULL AS cached_m0_upgrade_state",
153116
+ cached_m0_system_hash: "NULL AS cached_m0_system_hash",
153117
+ cached_m0_tool_set_hash: "NULL AS cached_m0_tool_set_hash",
153118
+ cached_m0_model_key: "NULL AS cached_m0_model_key",
153048
153119
  last_observed_model_key: "NULL AS last_observed_model_key",
153049
153120
  upgrade_reminded_at: "NULL AS upgrade_reminded_at"
153050
153121
  };
@@ -163021,25 +163092,56 @@ var require_src2 = __commonJS((exports, module) => {
163021
163092
  // src/features/magic-context/key-files/aft-availability.ts
163022
163093
  import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
163023
163094
  import { homedir as homedir6 } from "node:os";
163024
- import { join as join10 } from "node:path";
163095
+ import { isAbsolute as isAbsolute2, join as join10, resolve as resolve4 } from "node:path";
163096
+ import { fileURLToPath } from "node:url";
163025
163097
  function parseConfig(path6) {
163026
163098
  if (!existsSync9(path6))
163027
163099
  return null;
163028
163100
  return import_comment_json.parse(readFileSync7(path6, "utf-8"));
163029
163101
  }
163030
- function entryMatchesAft(entry) {
163102
+ function stringMentionsAft(value) {
163103
+ return AFT_NAME_NEEDLES.some((needle) => value.includes(needle));
163104
+ }
163105
+ function resolveLocalEntryPackageName(value, configDir) {
163106
+ let dir = null;
163107
+ if (value.startsWith("file://")) {
163108
+ try {
163109
+ dir = fileURLToPath(value);
163110
+ } catch {
163111
+ return null;
163112
+ }
163113
+ } else if (value.startsWith("~/")) {
163114
+ dir = join10(homedir6(), value.slice(2));
163115
+ } else if (value.startsWith("/") || value.startsWith("./") || value.startsWith("../")) {
163116
+ dir = isAbsolute2(value) ? value : resolve4(configDir, value);
163117
+ } else {
163118
+ return null;
163119
+ }
163120
+ try {
163121
+ const pkg = JSON.parse(readFileSync7(join10(dir, "package.json"), "utf-8"));
163122
+ return typeof pkg.name === "string" ? pkg.name : null;
163123
+ } catch {
163124
+ return null;
163125
+ }
163126
+ }
163127
+ function entryMatchesAft(entry, configDir) {
163031
163128
  const value = Array.isArray(entry) ? entry[0] : entry;
163032
- return typeof value === "string" && (value.includes("@cortexkit/aft") || value.includes("aft-opencode") || value.includes("aft-pi"));
163129
+ if (typeof value !== "string")
163130
+ return false;
163131
+ if (stringMentionsAft(value))
163132
+ return true;
163133
+ const name2 = resolveLocalEntryPackageName(value, configDir);
163134
+ return name2 != null && stringMentionsAft(name2);
163033
163135
  }
163034
- function hasAftInArray(value) {
163035
- return Array.isArray(value) && value.some(entryMatchesAft);
163136
+ function hasAftInArray(value, configDir) {
163137
+ return Array.isArray(value) && value.some((entry) => entryMatchesAft(entry, configDir));
163036
163138
  }
163037
- function hasAftAtKeys(value, keys) {
163139
+ function hasAftAtKeys(value, keys, configDir) {
163038
163140
  if (!value || typeof value !== "object")
163039
163141
  return false;
163040
163142
  const record2 = value;
163041
163143
  for (const key of keys) {
163042
- if (hasAftInArray(record2[key]))
163144
+ if (hasAftInArray(record2[key], configDir))
163043
163145
  return true;
163044
163146
  }
163045
163147
  return false;
@@ -163056,7 +163158,8 @@ function getAftAvailability() {
163056
163158
  for (const path6 of opencodePaths) {
163057
163159
  try {
163058
163160
  const config2 = parseConfig(path6);
163059
- if (hasAftAtKeys(config2, ["plugin", "plugins", "mcp", "mcp_servers"])) {
163161
+ const configDir = join10(path6, "..");
163162
+ if (hasAftAtKeys(config2, ["plugin", "plugins", "mcp", "mcp_servers"], configDir)) {
163060
163163
  opencode = true;
163061
163164
  break;
163062
163165
  }
@@ -163066,12 +163169,13 @@ function getAftAvailability() {
163066
163169
  for (const path6 of piPaths) {
163067
163170
  try {
163068
163171
  const config2 = parseConfig(path6);
163069
- if (hasAftAtKeys(config2, ["packages", "extensions"])) {
163172
+ const configDir = join10(path6, "..");
163173
+ if (hasAftAtKeys(config2, ["packages", "extensions"], configDir)) {
163070
163174
  pi = true;
163071
163175
  break;
163072
163176
  }
163073
163177
  const agent = config2?.agent;
163074
- if (hasAftAtKeys(agent, ["packages", "extensions"])) {
163178
+ if (hasAftAtKeys(agent, ["packages", "extensions"], configDir)) {
163075
163179
  pi = true;
163076
163180
  break;
163077
163181
  }
@@ -163088,9 +163192,10 @@ function getAftAvailability() {
163088
163192
  function isAftAvailable() {
163089
163193
  return getAftAvailability().available;
163090
163194
  }
163091
- var import_comment_json, overrideAvailability = null;
163195
+ var import_comment_json, overrideAvailability = null, AFT_NAME_NEEDLES;
163092
163196
  var init_aft_availability = __esm(() => {
163093
163197
  import_comment_json = __toESM(require_src2(), 1);
163198
+ AFT_NAME_NEEDLES = ["@cortexkit/aft", "aft-opencode", "aft-pi"];
163094
163199
  });
163095
163200
 
163096
163201
  // src/features/magic-context/memory/storage-memory-embeddings.ts
@@ -163775,7 +163880,7 @@ async function acquireModelLoadLock(lockPath) {
163775
163880
  if (Date.now() - waitStart > MAX_LOCK_WAIT_MS) {
163776
163881
  throw new Error(`[magic-context] embedding-load lock wait exceeded ${MAX_LOCK_WAIT_MS}ms; another process is still loading the model. Skipping this init attempt to avoid an unsynchronized native load.`);
163777
163882
  }
163778
- await new Promise((resolve5) => setTimeout(resolve5, LOCK_POLL_MS));
163883
+ await new Promise((resolve6) => setTimeout(resolve6, LOCK_POLL_MS));
163779
163884
  }
163780
163885
  }
163781
163886
  }
@@ -163944,7 +164049,7 @@ class LocalEmbeddingProvider {
163944
164049
  }
163945
164050
  const delayMs = 300 * attempt + Math.floor(Math.random() * 200);
163946
164051
  log(`[magic-context] embedding model load attempt ${attempt}/${MAX_ATTEMPTS} failed transiently, retrying in ${delayMs}ms`);
163947
- await new Promise((resolve5) => setTimeout(resolve5, delayMs));
164052
+ await new Promise((resolve6) => setTimeout(resolve6, delayMs));
163948
164053
  }
163949
164054
  }
163950
164055
  if (this.pipeline) {
@@ -163972,8 +164077,8 @@ class LocalEmbeddingProvider {
163972
164077
  if (this.inFlight === 0) {
163973
164078
  return Promise.resolve();
163974
164079
  }
163975
- return new Promise((resolve5) => {
163976
- this.inFlightWaiters.push(resolve5);
164080
+ return new Promise((resolve6) => {
164081
+ this.inFlightWaiters.push(resolve6);
163977
164082
  });
163978
164083
  }
163979
164084
  finishInFlight() {
@@ -164960,7 +165065,7 @@ async function refreshModelLimitsFromApi(client, options) {
164960
165065
  if (ok)
164961
165066
  return;
164962
165067
  if (attempt < attempts) {
164963
- await new Promise((resolve5) => setTimeout(resolve5, delayMs));
165068
+ await new Promise((resolve6) => setTimeout(resolve6, delayMs));
164964
165069
  }
164965
165070
  }
164966
165071
  }
@@ -165946,12 +166051,12 @@ async function runHistorianPrompt(args) {
165946
166051
  error: `Historian failed while processing this session: ${desc.brief}`
165947
166052
  };
165948
166053
  } finally {
165949
- if (agentSessionId && outcomeOk) {
166054
+ if (agentSessionId && outcomeOk && !shouldKeepSubagents()) {
165950
166055
  await client.session.delete({ path: { id: agentSessionId } }).catch((e) => {
165951
166056
  sessionLog(parentSessionId, "compartment agent: session cleanup failed", getErrorMessage(e));
165952
166057
  });
165953
- } else if (agentSessionId && !outcomeOk) {
165954
- sessionLog(parentSessionId, `historian: KEEPING failed child session ${agentSessionId} for debugging (not deleted)`);
166058
+ } else if (agentSessionId && (!outcomeOk || shouldKeepSubagents())) {
166059
+ sessionLog(parentSessionId, `historian: KEEPING child session ${agentSessionId} (${outcomeOk ? "keep_subagents" : "failed"}) — not deleted`);
165955
166060
  }
165956
166061
  }
165957
166062
  }
@@ -166030,8 +166135,8 @@ function isTransientHistorianPromptError(message) {
166030
166135
  ].some((token) => normalized.includes(token));
166031
166136
  }
166032
166137
  function sleep(ms) {
166033
- return new Promise((resolve5) => {
166034
- setTimeout(resolve5, ms);
166138
+ return new Promise((resolve6) => {
166139
+ setTimeout(resolve6, ms);
166035
166140
  });
166036
166141
  }
166037
166142
  function cleanupHistorianDump(sessionId, dumpPath) {
@@ -167040,12 +167145,6 @@ function getMaxCompartmentSeq(db, sessionId) {
167040
167145
  const row = cachedStatement(maxCompartmentSeqStatements, db, "SELECT COALESCE(MAX(sequence), -1) AS s FROM compartments WHERE session_id = ?").get(sessionId);
167041
167146
  return numberFromRow(row, "s");
167042
167147
  }
167043
- function normalizeCachedMaxCompartmentSeq(db, sessionId, stored) {
167044
- if (stored === 0 && getMaxCompartmentSeq(db, sessionId) === EMPTY_MAX_COMPARTMENT_SEQ) {
167045
- return EMPTY_MAX_COMPARTMENT_SEQ;
167046
- }
167047
- return stored;
167048
- }
167049
167148
  function getMaxMemoryId(db, projectPath) {
167050
167149
  if (!projectPath)
167051
167150
  return 0;
@@ -167069,6 +167168,7 @@ function getGlobalUserProfileVersion(db) {
167069
167168
  }
167070
167169
  function readCurrentM0SnapshotMarkers(args) {
167071
167170
  const projectDirectory = args.projectDirectory ?? args.projectPath ?? "";
167171
+ const hard = args.hardSignals ?? EMPTY_HARD_SIGNALS;
167072
167172
  return {
167073
167173
  projectMemoryEpoch: getProjectMemoryEpoch(args.db, args.projectPath),
167074
167174
  projectUserProfileVersion: getGlobalUserProfileVersion(args.db),
@@ -167079,7 +167179,10 @@ function readCurrentM0SnapshotMarkers(args) {
167079
167179
  projectDocsHash: projectDirectory ? computeProjectDocsHash(projectDirectory) : "",
167080
167180
  materializedAt: Date.now(),
167081
167181
  sessionFactsVersion: getSessionFactsVersion(args.db, args.sessionId),
167082
- upgradeState: getUpgradeState(args.db, args.sessionId)
167182
+ upgradeState: getUpgradeState(args.db, args.sessionId),
167183
+ systemHash: hard.systemHash,
167184
+ toolSetHash: hard.toolSetHash,
167185
+ modelKey: hard.modelKey
167083
167186
  };
167084
167187
  }
167085
167188
  function snapshotMarkersFromCachedM0(state) {
@@ -167109,7 +167212,10 @@ function snapshotMarkersFromCachedM0(state) {
167109
167212
  projectDocsHash: state.cachedM0ProjectDocsHash ?? "",
167110
167213
  materializedAt: state.cachedM0MaterializedAt ?? 0,
167111
167214
  sessionFactsVersion: state.cachedM0SessionFactsVersion,
167112
- upgradeState: state.cachedM0UpgradeState
167215
+ upgradeState: state.cachedM0UpgradeState,
167216
+ systemHash: state.cachedM0SystemHash ?? "",
167217
+ toolSetHash: state.cachedM0ToolSetHash ?? "",
167218
+ modelKey: state.cachedM0ModelKey ?? ""
167113
167219
  };
167114
167220
  }
167115
167221
  function mustMaterialize(args) {
@@ -167117,16 +167223,22 @@ function mustMaterialize(args) {
167117
167223
  return { value: true, reason: "first_render" };
167118
167224
  if (!args.state.cachedM1Bytes)
167119
167225
  return { value: true, reason: "cached_m1_missing" };
167226
+ const hard = args.hardSignals ?? EMPTY_HARD_SIGNALS;
167120
167227
  const current = readCurrentM0SnapshotMarkers(args);
167121
- if (args.state.cachedM0ProjectMemoryEpoch !== current.projectMemoryEpoch) {
167122
- return { value: true, reason: "project_memory_epoch" };
167228
+ if (hard.modelKey !== "" && hard.modelKey !== (args.state.cachedM0ModelKey ?? "")) {
167229
+ return { value: true, reason: "model_change" };
167230
+ }
167231
+ if (hard.systemHash !== "" && hard.systemHash !== (args.state.cachedM0SystemHash ?? "")) {
167232
+ return { value: true, reason: "system_hash" };
167123
167233
  }
167124
- if (args.state.cachedM0ProjectUserProfileVersion !== current.projectUserProfileVersion) {
167125
- return { value: true, reason: "project_user_profile_version" };
167234
+ if (hard.toolSetHash !== "" && hard.toolSetHash !== (args.state.cachedM0ToolSetHash ?? "")) {
167235
+ return { value: true, reason: "tool_set_hash" };
167126
167236
  }
167127
- const cachedMaxSeq = args.state.cachedM0MaxCompartmentSeq === null ? null : normalizeCachedMaxCompartmentSeq(args.db, args.sessionId, args.state.cachedM0MaxCompartmentSeq);
167128
- if (cachedMaxSeq !== current.maxCompartmentSeq) {
167129
- return { value: true, reason: "max_compartment_seq" };
167237
+ if (hard.cacheExpired && hard.lastResponseTime > 0 && hard.lastResponseTime > (args.state.cachedM0MaterializedAt ?? 0)) {
167238
+ return { value: true, reason: "ttl_idle" };
167239
+ }
167240
+ if (args.state.cachedM0ProjectMemoryEpoch !== current.projectMemoryEpoch) {
167241
+ return { value: true, reason: "project_memory_epoch" };
167130
167242
  }
167131
167243
  if (args.state.cachedM0MaxMutationId !== current.maxMutationId) {
167132
167244
  return { value: true, reason: "max_mutation_id" };
@@ -167315,6 +167427,9 @@ function applyMarkersToState(state, m0Bytes, markers, m1Bytes) {
167315
167427
  state.cachedM0MaterializedAt = markers.materializedAt;
167316
167428
  state.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
167317
167429
  state.cachedM0UpgradeState = markers.upgradeState;
167430
+ state.cachedM0SystemHash = markers.systemHash;
167431
+ state.cachedM0ToolSetHash = markers.toolSetHash;
167432
+ state.cachedM0ModelKey = markers.modelKey;
167318
167433
  state.snapshotMarkers = markers;
167319
167434
  }
167320
167435
  function historySliceTokens(m0Text) {
@@ -167339,7 +167454,8 @@ function materializeM0(options) {
167339
167454
  db: options.db,
167340
167455
  sessionId: options.sessionId,
167341
167456
  projectPath,
167342
- projectDirectory
167457
+ projectDirectory,
167458
+ hardSignals: options.hardSignals
167343
167459
  });
167344
167460
  docs = projectDirectory ? readProjectDocsCanonical(projectDirectory) : { renderedBlock: "", canonicalHash: "" };
167345
167461
  snapshotMarkers.projectDocsHash = docs.canonicalHash;
@@ -167405,7 +167521,10 @@ function materializeM0(options) {
167405
167521
  projectDocsHash: phase3ProjectDocsHash,
167406
167522
  materializedAt: Date.now(),
167407
167523
  sessionFactsVersion: getSessionFactsVersion(options.db, options.sessionId),
167408
- upgradeState: getUpgradeState(options.db, options.sessionId)
167524
+ upgradeState: getUpgradeState(options.db, options.sessionId),
167525
+ systemHash: snapshotMarkers.systemHash,
167526
+ toolSetHash: snapshotMarkers.toolSetHash,
167527
+ modelKey: snapshotMarkers.modelKey
167409
167528
  };
167410
167529
  const stale = current.projectMemoryEpoch !== snapshotMarkers.projectMemoryEpoch || current.projectUserProfileVersion !== snapshotMarkers.projectUserProfileVersion || current.maxCompartmentSeq !== snapshotMarkers.maxCompartmentSeq || current.maxMutationId !== snapshotMarkers.maxMutationId || current.maxMemoryMutationId !== snapshotMarkers.maxMemoryMutationId || current.projectDocsHash !== snapshotMarkers.projectDocsHash || current.sessionFactsVersion !== snapshotMarkers.sessionFactsVersion || current.upgradeState !== snapshotMarkers.upgradeState;
167411
167530
  if (stale) {
@@ -167427,7 +167546,10 @@ function materializeM0(options) {
167427
167546
  projectDocsHash: snapshotMarkers.projectDocsHash,
167428
167547
  materializedAt: snapshotMarkers.materializedAt,
167429
167548
  sessionFactsVersion: snapshotMarkers.sessionFactsVersion,
167430
- upgradeState: snapshotMarkers.upgradeState
167549
+ upgradeState: snapshotMarkers.upgradeState,
167550
+ systemHash: snapshotMarkers.systemHash,
167551
+ toolSetHash: snapshotMarkers.toolSetHash,
167552
+ modelKey: snapshotMarkers.modelKey
167431
167553
  });
167432
167554
  options.db.prepare("UPDATE session_meta SET memory_block_count = ?, memory_block_ids = ? WHERE session_id = ?").run(renderedMemoryIds.length, JSON.stringify(renderedMemoryIds), options.sessionId);
167433
167555
  options.db.exec("COMMIT");
@@ -167586,6 +167708,9 @@ function readCachedM0M1Row(db, sessionId) {
167586
167708
  cached_m0_materialized_at,
167587
167709
  cached_m0_session_facts_version,
167588
167710
  cached_m0_upgrade_state,
167711
+ cached_m0_system_hash,
167712
+ cached_m0_tool_set_hash,
167713
+ cached_m0_model_key,
167589
167714
  memory_block_ids
167590
167715
  FROM session_meta
167591
167716
  WHERE session_id = ?`).get(sessionId);
@@ -167617,11 +167742,14 @@ function markersFromCachedRow(row) {
167617
167742
  projectDocsHash: row.cached_m0_project_docs_hash ?? "",
167618
167743
  materializedAt: row.cached_m0_materialized_at ?? 0,
167619
167744
  sessionFactsVersion: row.cached_m0_session_facts_version,
167620
- upgradeState: row.cached_m0_upgrade_state
167745
+ upgradeState: row.cached_m0_upgrade_state,
167746
+ systemHash: row.cached_m0_system_hash ?? "",
167747
+ toolSetHash: row.cached_m0_tool_set_hash ?? "",
167748
+ modelKey: row.cached_m0_model_key ?? ""
167621
167749
  };
167622
167750
  }
167623
167751
  function cachedRowMatchesState(row, state) {
167624
- return bufferEqualsNullable(row.cached_m0_bytes, state.cachedM0Bytes) && row.cached_m0_project_memory_epoch === state.cachedM0ProjectMemoryEpoch && row.cached_m0_project_user_profile_version === state.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state.cachedM0MaxMemoryMutationId && (row.cached_m0_project_docs_hash ?? "") === (state.cachedM0ProjectDocsHash ?? "") && row.cached_m0_materialized_at === state.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state.cachedM0UpgradeState ?? null);
167752
+ return bufferEqualsNullable(row.cached_m0_bytes, state.cachedM0Bytes) && row.cached_m0_project_memory_epoch === state.cachedM0ProjectMemoryEpoch && row.cached_m0_project_user_profile_version === state.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state.cachedM0MaxMemoryMutationId && (row.cached_m0_project_docs_hash ?? "") === (state.cachedM0ProjectDocsHash ?? "") && row.cached_m0_materialized_at === state.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state.cachedM0UpgradeState ?? null) && (row.cached_m0_system_hash ?? "") === (state.cachedM0SystemHash ?? "") && (row.cached_m0_tool_set_hash ?? "") === (state.cachedM0ToolSetHash ?? "") && (row.cached_m0_model_key ?? "") === (state.cachedM0ModelKey ?? "");
167625
167753
  }
167626
167754
  function applyCachedRowToState(state, row) {
167627
167755
  const markers = markersFromCachedRow(row);
@@ -167640,6 +167768,9 @@ function applyCachedRowToState(state, row) {
167640
167768
  state.cachedM0MaterializedAt = markers.materializedAt;
167641
167769
  state.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
167642
167770
  state.cachedM0UpgradeState = markers.upgradeState;
167771
+ state.cachedM0SystemHash = markers.systemHash;
167772
+ state.cachedM0ToolSetHash = markers.toolSetHash;
167773
+ state.cachedM0ModelKey = markers.modelKey;
167643
167774
  state.snapshotMarkers = markers;
167644
167775
  }
167645
167776
  function replayCachedM1(state) {
@@ -167756,7 +167887,8 @@ function injectM0M1(options) {
167756
167887
  sessionId: options.sessionId,
167757
167888
  state: options.state,
167758
167889
  projectPath: options.projectPath,
167759
- projectDirectory: options.projectDirectory
167890
+ projectDirectory: options.projectDirectory,
167891
+ hardSignals: options.hardSignals
167760
167892
  });
167761
167893
  let rematerialized = false;
167762
167894
  let contentionExhausted = false;
@@ -167814,7 +167946,10 @@ function injectM0M1(options) {
167814
167946
  m1Text = replayCachedM1(options.state);
167815
167947
  }
167816
167948
  const M0_DRIFT_RATIO_FLOOR = 2000;
167817
- if (!rematerialized && !contentionExhausted && m1Recomputed && options.isCacheBustingPass && (memoryUpdateCount > 40 || m1Text !== M1_EMPTY_PLACEHOLDER && m0Text.length >= M0_DRIFT_RATIO_FLOOR && m1Text.length > m0Text.length * 0.15)) {
167949
+ const M1_ABSOLUTE_CAP_RATIO = 0.2;
167950
+ const m1AbsoluteBudget = (options.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS) * M1_ABSOLUTE_CAP_RATIO;
167951
+ const m1OverAbsoluteCap = m1Text !== M1_EMPTY_PLACEHOLDER && estimateTokens(m1Text) > m1AbsoluteBudget;
167952
+ if (!rematerialized && !contentionExhausted && m1Recomputed && options.isCacheBustingPass && (memoryUpdateCount > 40 || m1OverAbsoluteCap || m1Text !== M1_EMPTY_PLACEHOLDER && m0Text.length >= M0_DRIFT_RATIO_FLOOR && m1Text.length > m0Text.length * 0.15)) {
167818
167953
  try {
167819
167954
  const refolded = materializeWithRetry(options);
167820
167955
  applyMarkersToState(options.state, refolded.m0Bytes, refolded.snapshotMarkers, refolded.m1Bytes);
@@ -167838,7 +167973,7 @@ function injectM0M1(options) {
167838
167973
  m1Text
167839
167974
  };
167840
167975
  }
167841
- var INJECTION_CACHE_MAX = 100, injectionCache, CONSTRAINT_KEYWORDS, MaterializeContentionError, RenderM1InvalidMarkersError, DEFAULT_HISTORY_BUDGET_TOKENS = 60000, DEFAULT_MEMORY_BUDGET_TOKENS = 8000, MEMORY_BLOCK_WRAPPER_TOKENS = 6, DEFAULT_USER_PROFILE_BUDGET_TOKENS = 4000, M0_EMPTY_BODY = "<session-history></session-history>", M1_EMPTY_PLACEHOLDER = "<session-history-since>(no new content since last materialization)</session-history-since>", maxCompartmentSeqStatements, maxMemoryIdStatements, legacyCompartmentCountStatements, m0CompartmentStatements, newCompartmentStatements, EMPTY_MAX_COMPARTMENT_SEQ = -1;
167976
+ var INJECTION_CACHE_MAX = 100, injectionCache, CONSTRAINT_KEYWORDS, EMPTY_HARD_SIGNALS, MaterializeContentionError, RenderM1InvalidMarkersError, DEFAULT_HISTORY_BUDGET_TOKENS = 60000, DEFAULT_MEMORY_BUDGET_TOKENS = 8000, MEMORY_BLOCK_WRAPPER_TOKENS = 6, DEFAULT_USER_PROFILE_BUDGET_TOKENS = 4000, M0_EMPTY_BODY = "<session-history></session-history>", M1_EMPTY_PLACEHOLDER = "<session-history-since>(no new content since last materialization)</session-history-since>", maxCompartmentSeqStatements, maxMemoryIdStatements, legacyCompartmentCountStatements, m0CompartmentStatements, newCompartmentStatements;
167842
167977
  var init_inject_compartments = __esm(async () => {
167843
167978
  init_compartment_storage();
167844
167979
  init_constants();
@@ -167854,6 +167989,13 @@ var init_inject_compartments = __esm(async () => {
167854
167989
  ]);
167855
167990
  injectionCache = new BoundedSessionMap(INJECTION_CACHE_MAX);
167856
167991
  CONSTRAINT_KEYWORDS = /\b(must|never|always|cannot|should not|must not)\b/i;
167992
+ EMPTY_HARD_SIGNALS = {
167993
+ systemHash: "",
167994
+ toolSetHash: "",
167995
+ modelKey: "",
167996
+ cacheExpired: false,
167997
+ lastResponseTime: 0
167998
+ };
167857
167999
  MaterializeContentionError = class MaterializeContentionError extends Error {
167858
168000
  retries;
167859
168001
  reason;
@@ -171259,6 +171401,10 @@ async function runMemoryMigration(deps) {
171259
171401
  const cleanupChildSession = async (sid) => {
171260
171402
  if (!sid)
171261
171403
  return;
171404
+ if (shouldKeepSubagents()) {
171405
+ sessionLog(parentSessionId, `memory-migration: KEEPING child session ${sid} (keep_subagents)`);
171406
+ return;
171407
+ }
171262
171408
  await client.session.delete({ path: { id: sid } }).catch((e) => {
171263
171409
  sessionLog(parentSessionId, `memory-migration: child cleanup failed: ${String(e)}`);
171264
171410
  });
@@ -172739,7 +172885,7 @@ async function runSidekick(deps) {
172739
172885
  }
172740
172886
  return null;
172741
172887
  } finally {
172742
- if (agentSessionId) {
172888
+ if (agentSessionId && !shouldKeepSubagents()) {
172743
172889
  await deps.client.session.delete({
172744
172890
  path: { id: agentSessionId }
172745
172891
  }).catch((error51) => {
@@ -173203,13 +173349,14 @@ init_shared();
173203
173349
  init_assistant_message_extractor();
173204
173350
  init_logger();
173205
173351
  import { readFileSync as readFileSync8 } from "node:fs";
173206
- import { isAbsolute as isAbsolute2, join as join11, relative as relative2 } from "node:path";
173352
+ import { isAbsolute as isAbsolute3, join as join11, relative as relative2 } from "node:path";
173353
+ init_subagent_token_capture();
173207
173354
  init_aft_availability();
173208
173355
  init_project_key_files();
173209
173356
 
173210
173357
  // src/features/magic-context/key-files/read-history.ts
173211
173358
  import { realpathSync as realpathSync3 } from "node:fs";
173212
- import { relative, resolve as resolve4 } from "node:path";
173359
+ import { relative, resolve as resolve5 } from "node:path";
173213
173360
  function toMs(value) {
173214
173361
  if (typeof value === "number" && Number.isFinite(value))
173215
173362
  return value;
@@ -173246,7 +173393,7 @@ function coalesceRanges(ranges) {
173246
173393
  }
173247
173394
  function normalizeProjectRelativePath(projectPath, filePath) {
173248
173395
  const root = realpathSync3(projectPath);
173249
- const abs = filePath.startsWith("/") ? resolve4(filePath) : resolve4(root, filePath);
173396
+ const abs = filePath.startsWith("/") ? resolve5(filePath) : resolve5(root, filePath);
173250
173397
  let real = abs;
173251
173398
  try {
173252
173399
  real = realpathSync3(abs);
@@ -173614,11 +173761,13 @@ async function runKeyFilesLlm(args) {
173614
173761
  const text = extractLatestAssistantText(messages);
173615
173762
  if (!text)
173616
173763
  throw new Error("Dreamer returned no key-files output.");
173617
- return text;
173764
+ return { text, messages };
173618
173765
  } finally {
173619
- await args.client.session.delete({ path: { id: agentSessionId } }).catch(() => {
173620
- return;
173621
- });
173766
+ if (!shouldKeepSubagents()) {
173767
+ await args.client.session.delete({ path: { id: agentSessionId } }).catch(() => {
173768
+ return;
173769
+ });
173770
+ }
173622
173771
  }
173623
173772
  }
173624
173773
  async function runKeyFilesTask(args) {
@@ -173664,9 +173813,27 @@ async function runKeyFilesTask(args) {
173664
173813
  log(`[key-files] lease renewal threw: ${getErrorMessage(error51)}`);
173665
173814
  }
173666
173815
  }, 60000);
173816
+ let invocationRecorded = false;
173817
+ const llmStartedAt = Date.now();
173818
+ const recordKeyFilesInvocation = (params) => {
173819
+ if (!args.parentSessionId || invocationRecorded)
173820
+ return;
173821
+ invocationRecorded = true;
173822
+ recordChildInvocation({
173823
+ db: args.db,
173824
+ parentSessionId: args.parentSessionId,
173825
+ harness: getHarness(),
173826
+ subagent: "dreamer",
173827
+ task: "key files",
173828
+ startedAt: llmStartedAt,
173829
+ status: params.status,
173830
+ messages: params.messages,
173831
+ error: params.error
173832
+ });
173833
+ };
173667
173834
  try {
173668
173835
  try {
173669
- const raw = await runKeyFilesLlm({
173836
+ const { text: raw, messages: llmMessages } = await runKeyFilesLlm({
173670
173837
  client: args.client,
173671
173838
  parentSessionId: args.parentSessionId,
173672
173839
  projectPath,
@@ -173674,8 +173841,10 @@ async function runKeyFilesTask(args) {
173674
173841
  deadline: args.deadline,
173675
173842
  fallbackModels: args.fallbackModels
173676
173843
  });
173844
+ recordKeyFilesInvocation({ status: "completed", messages: llmMessages });
173677
173845
  validated = validateLlmOutput(raw, args.config, projectPath, new Set(candidates.map((candidate) => candidate.path)));
173678
173846
  } catch (error51) {
173847
+ recordKeyFilesInvocation({ status: "failed", error: error51 });
173679
173848
  log(`[key-files] LLM validation failed: ${getErrorMessage(error51)}`);
173680
173849
  throw error51;
173681
173850
  }
@@ -173774,7 +173943,8 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
173774
173943
  db: args.db,
173775
173944
  parentSessionId: args.parentSessionId,
173776
173945
  harness: "opencode",
173777
- subagent: "user_memory_review",
173946
+ subagent: "dreamer",
173947
+ task: "user memories",
173778
173948
  startedAt,
173779
173949
  status: params.status,
173780
173950
  messages: params.messages,
@@ -173898,7 +174068,7 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
173898
174068
  return result;
173899
174069
  } finally {
173900
174070
  clearInterval(leaseInterval);
173901
- if (agentSessionId) {
174071
+ if (agentSessionId && !shouldKeepSubagents()) {
173902
174072
  await args.client.session.delete({
173903
174073
  path: { id: agentSessionId },
173904
174074
  query: { directory: args.sessionDirectory }
@@ -174221,14 +174391,14 @@ async function runDream(args) {
174221
174391
  }
174222
174392
  } finally {
174223
174393
  clearInterval(leaseRenewalInterval);
174224
- if (agentSessionId && !taskFailed) {
174394
+ if (agentSessionId && !taskFailed && !shouldKeepSubagents()) {
174225
174395
  await args.client.session.delete({
174226
174396
  path: { id: agentSessionId }
174227
174397
  }).catch((error51) => {
174228
174398
  log("[dreamer] failed to delete child session:", error51);
174229
174399
  });
174230
- } else if (agentSessionId && taskFailed) {
174231
- log(`[dreamer] KEEPING failed child session ${agentSessionId} for task ${taskName} (debugging)`);
174400
+ } else if (agentSessionId && (taskFailed || shouldKeepSubagents())) {
174401
+ log(`[dreamer] KEEPING child session ${agentSessionId} for task ${taskName} (${taskFailed ? "failed" : "keep_subagents"})`);
174232
174402
  }
174233
174403
  }
174234
174404
  if (lostLease) {
@@ -174513,7 +174683,7 @@ Only include notes whose conditions you could definitively evaluate against exte
174513
174683
  parts: [{ type: "text", text: evaluationPrompt, synthetic: true }]
174514
174684
  }
174515
174685
  }, {
174516
- timeoutMs: Math.min(remainingMs, 300000),
174686
+ timeoutMs: Math.min(remainingMs, 5 * 60 * 1000),
174517
174687
  signal: abortController.signal,
174518
174688
  fallbackModels: args.fallbackModels,
174519
174689
  callContext: "dreamer:smart-notes"
@@ -174589,7 +174759,7 @@ Only include notes whose conditions you could definitively evaluate against exte
174589
174759
  });
174590
174760
  } finally {
174591
174761
  clearInterval(leaseInterval);
174592
- if (agentSessionId) {
174762
+ if (agentSessionId && !shouldKeepSubagents()) {
174593
174763
  await args.client.session.delete({
174594
174764
  path: { id: agentSessionId }
174595
174765
  }).catch(() => {});
@@ -174600,7 +174770,7 @@ var MAX_LEASE_RETRIES = 3;
174600
174770
  async function processDreamQueue(args) {
174601
174771
  const maxRuntimeMs = args.maxRuntimeMinutes * 60 * 1000;
174602
174772
  if (!hasActiveDreamLease(args.db)) {
174603
- clearStaleEntries(args.db, maxRuntimeMs + 1800000, args.projectIdentity);
174773
+ clearStaleEntries(args.db, maxRuntimeMs + 30 * 60 * 1000, args.projectIdentity);
174604
174774
  }
174605
174775
  const entry = dequeueNext(args.db, args.projectIdentity);
174606
174776
  if (!entry) {
@@ -175958,6 +176128,7 @@ function createTagger() {
175958
176128
  // src/hooks/magic-context/hook.ts
175959
176129
  init_magic_context();
175960
176130
  init_project_identity();
176131
+ init_tool_definition_tokens();
175961
176132
  await init_storage();
175962
176133
  init_logger();
175963
176134
  init_resolve_fallbacks();
@@ -177939,7 +178110,7 @@ async function runCompartmentPhase(args) {
177939
178110
  async function awaitCompartmentRun(activeRun, reason) {
177940
178111
  sessionLog(args.sessionId, reason);
177941
178112
  const timeoutMs = args.historianTimeoutMs ?? 120000;
177942
- const timeout = new Promise((resolve5) => setTimeout(() => resolve5("timeout"), timeoutMs));
178113
+ const timeout = new Promise((resolve6) => setTimeout(() => resolve6("timeout"), timeoutMs));
177943
178114
  const result = await Promise.race([activeRun.promise.then(() => "done"), timeout]);
177944
178115
  if (result === "timeout") {
177945
178116
  sessionLog(args.sessionId, `transform: compartment await timed out after ${timeoutMs}ms — proceeding without waiting`);
@@ -179422,10 +179593,10 @@ var AUTO_SEARCH_TIMEOUT_MS = 3000;
179422
179593
  async function unifiedSearchWithTimeout(db, sessionId, projectPath, prompt, options, timeoutMs) {
179423
179594
  const controller = new AbortController;
179424
179595
  let timer;
179425
- const timeoutPromise = new Promise((resolve5) => {
179596
+ const timeoutPromise = new Promise((resolve6) => {
179426
179597
  timer = setTimeout(() => {
179427
179598
  controller.abort();
179428
- resolve5(null);
179599
+ resolve6(null);
179429
179600
  }, timeoutMs);
179430
179601
  });
179431
179602
  try {
@@ -180119,7 +180290,8 @@ async function runPostTransformPhase(args) {
180119
180290
  memoryInjectionBudgetTokens: args.m0M1.memoryInjectionBudgetTokens,
180120
180291
  historyBudgetTokens: args.m0M1.historyBudgetTokens,
180121
180292
  keyFiles: args.m0M1.keyFiles,
180122
- isCacheBustingPass
180293
+ isCacheBustingPass,
180294
+ hardSignals: args.m0M1.hardSignals
180123
180295
  });
180124
180296
  if (result.injected) {
180125
180297
  sessionLog(args.sessionId, `transform: injected m[0]/m[1] (rematerialized=${result.m0RematerializedThisPass}, reason=${result.decision.reason ?? "cache_hit"})`);
@@ -180867,6 +181039,22 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
180867
181039
  const compartmentInProgress = compartmentPhase.compartmentInProgress;
180868
181040
  sessionMeta = { ...sessionMeta, compartmentInProgress };
180869
181041
  logTransformTiming(sessionId, "compartmentPhase", tCompartmentPhase);
181042
+ const hardModel = deps.liveModelBySession?.get(sessionId);
181043
+ const hardModelKey = hardModel ? `${hardModel.providerID}/${hardModel.modelID}` : "";
181044
+ const hardToolSetHash = deps.getToolSetHash?.(sessionId) ?? "";
181045
+ const hardSystemHash = typeof sessionMeta.systemPromptHash === "string" ? sessionMeta.systemPromptHash : "";
181046
+ let hardTtlMs = 5 * 60 * 1000;
181047
+ try {
181048
+ hardTtlMs = parseCacheTtl(sessionMeta.cacheTtl);
181049
+ } catch {}
181050
+ const hardCacheExpired = sessionMeta.lastResponseTime > 0 && Date.now() - sessionMeta.lastResponseTime >= hardTtlMs;
181051
+ const m0HardSignals = {
181052
+ systemHash: hardSystemHash,
181053
+ toolSetHash: hardToolSetHash,
181054
+ modelKey: hardModelKey,
181055
+ cacheExpired: hardCacheExpired,
181056
+ lastResponseTime: sessionMeta.lastResponseTime
181057
+ };
180870
181058
  const lateActiveRunBlocksMaterialization = getActiveCompartmentRun(sessionId) !== undefined && contextUsageEarly.percentage < FORCE_MATERIALIZE_PERCENTAGE;
180871
181059
  const canConsumeDeferredLate = canConsumeDeferredOnThisPass({
180872
181060
  schedulerDecision: midTurnAdjustedSchedulerDecision,
@@ -180930,7 +181118,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
180930
181118
  keyFiles: {
180931
181119
  enabled: deps.experimentalPinKeyFiles === true,
180932
181120
  tokenBudget: deps.experimentalPinKeyFilesTokenBudget ?? 1e4
180933
- }
181121
+ },
181122
+ hardSignals: m0HardSignals
180934
181123
  }
180935
181124
  });
180936
181125
  logTransformTiming(sessionId, "postTransformPhase", tPostProcess);
@@ -182323,6 +182512,12 @@ function createMagicContextHook(deps) {
182323
182512
  const model = liveModelBySession.get(sessionId);
182324
182513
  return resolveModelKey(model?.providerID, model?.modelID);
182325
182514
  },
182515
+ getToolSetHash: (sessionId) => {
182516
+ const model = liveModelBySession.get(sessionId);
182517
+ if (!model)
182518
+ return "";
182519
+ return getCurrentToolSetHash(model.providerID, model.modelID, agentBySession.get(sessionId));
182520
+ },
182326
182521
  getFallbackModelId: (sessionId) => {
182327
182522
  const model = liveModelBySession.get(sessionId);
182328
182523
  return model ? `${model.providerID}/${model.modelID}` : undefined;
@@ -184653,7 +184848,7 @@ class MagicContextRpcServer {
184653
184848
  this.handlers.set(method, handler);
184654
184849
  }
184655
184850
  async start() {
184656
- return new Promise((resolve5, reject) => {
184851
+ return new Promise((resolve6, reject) => {
184657
184852
  const server = createServer((req, res) => this.dispatch(req, res));
184658
184853
  server.on("error", (err) => {
184659
184854
  log(`[rpc] server error: ${err.message}`);
@@ -184683,7 +184878,7 @@ class MagicContextRpcServer {
184683
184878
  } catch (err) {
184684
184879
  log(`[rpc] failed to write port file: ${err}`);
184685
184880
  }
184686
- resolve5(this.port);
184881
+ resolve6(this.port);
184687
184882
  });
184688
184883
  server.unref();
184689
184884
  });
@@ -184776,6 +184971,7 @@ var plugin = async (ctx) => {
184776
184971
  cacheSizeMb: pluginConfig.sqlite.cache_size_mb,
184777
184972
  mmapSizeMb: pluginConfig.sqlite.mmap_size_mb
184778
184973
  });
184974
+ setKeepSubagents(pluginConfig.keep_subagents === true);
184779
184975
  if (pluginConfig.configWarnings?.length) {
184780
184976
  for (const w of pluginConfig.configWarnings) {
184781
184977
  log(`[magic-context] config warning: ${w}`);