@cortexkit/opencode-magic-context 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +26 -1
  2. package/dist/agents/magic-context-prompt.d.ts +1 -1
  3. package/dist/agents/magic-context-prompt.d.ts.map +1 -1
  4. package/dist/config/schema/magic-context.d.ts +11 -0
  5. package/dist/config/schema/magic-context.d.ts.map +1 -1
  6. package/dist/features/magic-context/dreamer/task-prompts.d.ts +1 -1
  7. package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -1
  8. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -1
  9. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  10. package/dist/features/magic-context/types.d.ts +12 -1
  11. package/dist/features/magic-context/types.d.ts.map +1 -1
  12. package/dist/hooks/magic-context/apply-operations.d.ts +8 -1
  13. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  14. package/dist/hooks/magic-context/edit-marker.d.ts +11 -0
  15. package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -0
  16. package/dist/hooks/magic-context/hook.d.ts +1 -0
  17. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  18. package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
  19. package/dist/hooks/magic-context/supersession-reclaim.d.ts +34 -0
  20. package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -0
  21. package/dist/hooks/magic-context/system-prompt-hash.d.ts +5 -0
  22. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  23. package/dist/hooks/magic-context/tag-messages.d.ts +8 -0
  24. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  25. package/dist/hooks/magic-context/tool-drop-target.d.ts +2 -0
  26. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  27. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +8 -0
  28. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  29. package/dist/hooks/magic-context/transform.d.ts +4 -0
  30. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  31. package/dist/index.js +306 -43
  32. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  33. package/dist/plugin/tool-registry.d.ts.map +1 -1
  34. package/dist/shared/announcement.d.ts +1 -1
  35. package/dist/shared/commit-detection.d.ts +29 -0
  36. package/dist/shared/commit-detection.d.ts.map +1 -0
  37. package/dist/shared/tag-transcript.d.ts.map +1 -1
  38. package/dist/shared/transcript.d.ts +15 -0
  39. package/dist/shared/transcript.d.ts.map +1 -1
  40. package/package.json +1 -1
  41. package/src/shared/announcement.ts +3 -3
  42. package/src/shared/commit-detection.test.ts +63 -0
  43. package/src/shared/commit-detection.ts +53 -0
  44. package/src/shared/tag-transcript.ts +32 -0
  45. package/src/shared/transcript-opencode.ts +33 -0
  46. package/src/shared/transcript.ts +17 -0
package/dist/index.js CHANGED
@@ -15407,6 +15407,7 @@ var init_magic_context = __esm(() => {
15407
15407
  }).describe("Embedding provider configuration"),
15408
15408
  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).'),
15409
15409
  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."),
15410
+ smart_drops: exports_external.boolean().default(false).describe("Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 5), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart."),
15410
15411
  caveman_text_compression: exports_external.object({
15411
15412
  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%)."),
15412
15413
  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.")
@@ -16922,6 +16923,19 @@ var init_read_session_db = __esm(async () => {
16922
16923
  await init_sqlite();
16923
16924
  });
16924
16925
 
16926
+ // src/shared/commit-detection.ts
16927
+ function textMentionsRecentCommit(text) {
16928
+ return COMMIT_HASH_TEST_PATTERN.test(text) && COMMIT_VERB_PATTERN.test(text);
16929
+ }
16930
+ function createCommitHashExtractPattern() {
16931
+ return new RegExp(`\`?\\b(${HASH_HEX})\\b\`?`, "gi");
16932
+ }
16933
+ var HASH_HEX = "[0-9a-f]{7,12}", COMMIT_HASH_TEST_PATTERN, COMMIT_VERB_PATTERN;
16934
+ var init_commit_detection = __esm(() => {
16935
+ COMMIT_HASH_TEST_PATTERN = new RegExp(`\\b${HASH_HEX}\\b`, "i");
16936
+ COMMIT_VERB_PATTERN = /\b(?:commit(?:ted|ting|s)?|cherry-?pick(?:ed|ing|s)?|merge[ds]?|merging|rebas(?:e|ed|es|ing))\b/i;
16937
+ });
16938
+
16925
16939
  // ../../node_modules/.bun/ai-tokenizer@1.0.6/node_modules/ai-tokenizer/dist/index.js
16926
16940
  function _typeof(o) {
16927
16941
  "@babel/helpers - typeof";
@@ -149471,7 +149485,7 @@ function formatBlock(block) {
149471
149485
  function extractCommitHashes(text) {
149472
149486
  const hashes = [];
149473
149487
  const seen = new Set;
149474
- for (const match of text.matchAll(COMMIT_HASH_PATTERN)) {
149488
+ for (const match of text.matchAll(createCommitHashExtractPattern())) {
149475
149489
  const hash2 = match[1]?.toLowerCase();
149476
149490
  if (!hash2 || seen.has(hash2))
149477
149491
  continue;
@@ -149484,10 +149498,10 @@ function extractCommitHashes(text) {
149484
149498
  }
149485
149499
  function compactTextForSummary(text, role) {
149486
149500
  const commitHashes = role === "assistant" ? extractCommitHashes(text) : [];
149487
- if (commitHashes.length === 0 || !COMMIT_HINT_PATTERN.test(text)) {
149501
+ if (commitHashes.length === 0 || !COMMIT_VERB_PATTERN.test(text)) {
149488
149502
  return { text, commitHashes };
149489
149503
  }
149490
- const withoutHashes = text.replace(COMMIT_HASH_PATTERN, "").replace(/\(\s*\)/g, "").replace(/\s+,/g, ",").replace(/,\s*,+/g, ", ").replace(/\s{2,}/g, " ").replace(/\s+([,.;:])/g, "$1").trim();
149504
+ const withoutHashes = text.replace(createCommitHashExtractPattern(), "").replace(/\(\s*\)/g, "").replace(/\s+,/g, ",").replace(/,\s*,+/g, ", ").replace(/\s{2,}/g, " ").replace(/\s+([,.;:])/g, "$1").trim();
149491
149505
  return {
149492
149506
  text: withoutHashes.length > 0 ? withoutHashes : text,
149493
149507
  commitHashes
@@ -149506,12 +149520,11 @@ function mergeCommitHashes(existing, next) {
149506
149520
  }
149507
149521
  return merged;
149508
149522
  }
149509
- var COMMIT_HASH_PATTERN, COMMIT_HINT_PATTERN, MAX_COMMITS_PER_BLOCK = 5, tokenizer;
149523
+ var MAX_COMMITS_PER_BLOCK = 5, tokenizer;
149510
149524
  var init_read_session_formatting = __esm(() => {
149525
+ init_commit_detection();
149511
149526
  init_dist();
149512
149527
  init_claude();
149513
- COMMIT_HASH_PATTERN = /`?\b([0-9a-f]{6,12})\b`?/gi;
149514
- COMMIT_HINT_PATTERN = /\b(commit(?:ted)?|cherry-?pick(?:ed)?|hash(?:es)?|sha)\b/i;
149515
149528
  tokenizer = new src_default(exports_claude);
149516
149529
  });
149517
149530
 
@@ -149818,6 +149831,37 @@ var init_tag_part_guards = __esm(() => {
149818
149831
  init_tag_content_primitives();
149819
149832
  });
149820
149833
 
149834
+ // src/hooks/magic-context/edit-marker.ts
149835
+ function safeSlice(str, maxLen) {
149836
+ if (str.length <= maxLen)
149837
+ return str;
149838
+ const lastCharCode = str.charCodeAt(maxLen - 1);
149839
+ if (lastCharCode >= 55296 && lastCharCode <= 56319) {
149840
+ return str.slice(0, maxLen - 1);
149841
+ }
149842
+ return str.slice(0, maxLen);
149843
+ }
149844
+ function isEditTool(name2) {
149845
+ return name2 === "edit" || name2 === "write";
149846
+ }
149847
+ function applyEditMarkerToInput(input) {
149848
+ for (const key of Object.keys(input)) {
149849
+ if (PATH_KEYS.has(key))
149850
+ continue;
149851
+ const value = input[key];
149852
+ if (typeof value !== "string" || !DIFF_KEYS.has(key))
149853
+ continue;
149854
+ if (value.endsWith(TRUNCATION_SENTINEL))
149855
+ continue;
149856
+ input[key] = value.length > EDIT_REGION_HINT_LEN ? `${safeSlice(value, EDIT_REGION_HINT_LEN)}${TRUNCATION_SENTINEL}` : value;
149857
+ }
149858
+ }
149859
+ var TRUNCATION_SENTINEL = "...[truncated]", EDIT_REGION_HINT_LEN = 40, PATH_KEYS, DIFF_KEYS;
149860
+ var init_edit_marker = __esm(() => {
149861
+ PATH_KEYS = new Set(["filePath", "file_path", "path"]);
149862
+ DIFF_KEYS = new Set(["oldString", "newString", "content", "old_string", "new_string"]);
149863
+ });
149864
+
149821
149865
  // src/hooks/magic-context/tool-drop-target.ts
149822
149866
  function isToolCallId(value) {
149823
149867
  return typeof value === "string" && value.length > 0;
@@ -149884,7 +149928,41 @@ function estimateInputSize(input) {
149884
149928
  return 0;
149885
149929
  }
149886
149930
  }
149887
- function safeSlice(str, maxLen) {
149931
+ function editMarkerToolPart(part, tagId) {
149932
+ if (!isRecord(part))
149933
+ return;
149934
+ const sentinel = `[dropped §${tagId}§]`;
149935
+ if (part.type === "tool" && isRecord(part.state)) {
149936
+ part.state.output = sentinel;
149937
+ if (isRecord(part.state.input))
149938
+ applyEditMarkerToInput(part.state.input);
149939
+ return;
149940
+ }
149941
+ if (part.type === "tool_result") {
149942
+ part.content = sentinel;
149943
+ return;
149944
+ }
149945
+ if (part.type === "tool-invocation" && isRecord(part.args)) {
149946
+ applyEditMarkerToInput(part.args);
149947
+ return;
149948
+ }
149949
+ if (part.type === "tool_use" && isRecord(part.input)) {
149950
+ applyEditMarkerToInput(part.input);
149951
+ }
149952
+ }
149953
+ function readToolPartInput(part) {
149954
+ if (!isRecord(part))
149955
+ return null;
149956
+ if (part.type === "tool" && isRecord(part.state) && isRecord(part.state.input)) {
149957
+ return part.state.input;
149958
+ }
149959
+ if (part.type === "tool-invocation" && isRecord(part.args))
149960
+ return part.args;
149961
+ if (part.type === "tool_use" && isRecord(part.input))
149962
+ return part.input;
149963
+ return null;
149964
+ }
149965
+ function safeSlice2(str, maxLen) {
149888
149966
  if (str.length <= maxLen)
149889
149967
  return str;
149890
149968
  const lastCharCode = str.charCodeAt(maxLen - 1);
@@ -149897,9 +149975,9 @@ function truncateInputValues(input) {
149897
149975
  for (const key of Object.keys(input)) {
149898
149976
  const value = input[key];
149899
149977
  if (typeof value === "string") {
149900
- if (value.endsWith(TRUNCATION_SENTINEL) || value === "[object]" || /^\[\d+ items\]$/.test(value))
149978
+ if (value.endsWith(TRUNCATION_SENTINEL2) || value === "[object]" || /^\[\d+ items\]$/.test(value))
149901
149979
  continue;
149902
- input[key] = value.length > 5 ? `${safeSlice(value, 5)}${TRUNCATION_SENTINEL}` : value;
149980
+ input[key] = value.length > 5 ? `${safeSlice2(value, 5)}${TRUNCATION_SENTINEL2}` : value;
149903
149981
  } else if (Array.isArray(value)) {
149904
149982
  input[key] = `[${value.length} items]`;
149905
149983
  } else if (value !== null && typeof value === "object") {
@@ -150003,6 +150081,18 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
150003
150081
  clearThinkingParts(thinkingParts);
150004
150082
  return "truncated";
150005
150083
  };
150084
+ const editMarker = () => {
150085
+ const entry = index.get(compositeKey);
150086
+ if (!entry || entry.occurrences.length === 0)
150087
+ return "absent";
150088
+ if (!entry.hasResult)
150089
+ return "incomplete";
150090
+ for (const occurrence of entry.occurrences) {
150091
+ editMarkerToolPart(occurrence.part, tagId);
150092
+ }
150093
+ clearThinkingParts(thinkingParts);
150094
+ return "truncated";
150095
+ };
150006
150096
  return {
150007
150097
  setContent: (content) => {
150008
150098
  if (isDropContent(content)) {
@@ -150026,14 +150116,34 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
150026
150116
  },
150027
150117
  drop,
150028
150118
  truncate,
150119
+ editMarker,
150029
150120
  canDrop: () => {
150030
150121
  const entry = index.get(compositeKey);
150031
150122
  return !!entry && entry.occurrences.length > 0 && entry.hasResult;
150123
+ },
150124
+ readInput: () => {
150125
+ const entry = index.get(compositeKey);
150126
+ if (!entry)
150127
+ return null;
150128
+ for (const occurrence of entry.occurrences) {
150129
+ if (occurrence.kind !== "invocation")
150130
+ continue;
150131
+ const input = readToolPartInput(occurrence.part);
150132
+ if (input)
150133
+ return input;
150134
+ }
150135
+ for (const occurrence of entry.occurrences) {
150136
+ const input = readToolPartInput(occurrence.part);
150137
+ if (input)
150138
+ return input;
150139
+ }
150140
+ return null;
150032
150141
  }
150033
150142
  };
150034
150143
  }
150035
- var DROP_PREFIX = "[dropped", IGNORE_PART_TYPES, TRUNCATION_SENTINEL = "...[truncated]";
150144
+ var DROP_PREFIX = "[dropped", IGNORE_PART_TYPES, TRUNCATION_SENTINEL2 = "...[truncated]";
150036
150145
  var init_tool_drop_target = __esm(() => {
150146
+ init_edit_marker();
150037
150147
  init_tag_content_primitives();
150038
150148
  IGNORE_PART_TYPES = new Set([
150039
150149
  "thinking",
@@ -155975,7 +156085,7 @@ function toTagEntry(row) {
155975
156085
  messageId: row.message_id,
155976
156086
  type,
155977
156087
  status,
155978
- dropMode: row.drop_mode === "truncated" ? "truncated" : "full",
156088
+ dropMode: row.drop_mode === "truncated" ? "truncated" : row.drop_mode === "edit_marker" ? "edit_marker" : "full",
155979
156089
  toolName: row.tool_name ?? null,
155980
156090
  inputByteSize: row.input_byte_size ?? 0,
155981
156091
  byteSize: row.byte_size,
@@ -186528,12 +186638,12 @@ function shouldShowAnnouncement() {
186528
186638
  }
186529
186639
  return ordering > 0;
186530
186640
  }
186531
- var ANNOUNCEMENT_VERSION = "0.28.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
186641
+ var ANNOUNCEMENT_VERSION = "0.29.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
186532
186642
  var init_announcement = __esm(() => {
186533
186643
  init_data_path();
186534
186644
  ANNOUNCEMENT_FEATURES = [
186535
- `New 'language' option: set a top-level 2-letter language code (e.g. "tr" or "es") and Magic Context writes its summaries, memories, and guidance in that language, while keeping all structure (tags, categories, code, paths) in English. User-level only, off by default.`,
186536
- "The ctx_reduce reminder now reflects how much tool output is actually reclaimable, instead of escalating to 'urgent' just because you're near compaction. It also no longer suggests dropping the agent's task list or tiny status outputs."
186645
+ `New 'smart_drops' option (opt-in, off by default): on long, edit-heavy sessions it reclaims more context by dropping tool output a later call made obsolete (superseded edits, old todowrite/ctx_reduce, spent status calls) instead of only the oldest. When off, the prompt is byte-identical to before. Enable with "smart_drops": true.`,
186646
+ "When memory is disabled, the ctx_memory tool and its guidance are no longer shown (they had nothing to write to). ctx_search stays, searching conversation history and git commits."
186537
186647
  ];
186538
186648
  });
186539
186649
 
@@ -188141,6 +188251,7 @@ var MAINTAIN_DOCS_SYSTEM_PROMPT = `You are a documentation maintainer for the ma
188141
188251
 
188142
188252
  ## Rules
188143
188253
  - **NEVER touch protected regions.** Any content between \`<!-- mc:protected START ... -->\` and \`<!-- mc:protected END -->\` is hand-authored and cache-critical. Reproduce it BYTE-FOR-BYTE — do not edit, reword, reorder, summarize, trim, or drop a single line, and keep the marker comments. Only a human edits that region.
188254
+ - **Preserve an existing doc's structure, voice, and density.** When a doc already exists, it is the source of truth for shape: keep its headings, ordering, level of detail, and writing style. Make the SMALLEST edits that bring it back in sync with the code. NEVER reshape hand-written prose into a generic template, collapse a dense section into bullet stubs, or drop hard-won detail (specific invariants, edge cases, mechanism descriptions) because it does not fit a standard layout. A doc denser and more specific than a template is BETTER, not worse: leave it that way.
188144
188255
  - **Be prescriptive** ("Use X pattern", not "X pattern is used"). **Current state only** — no temporal language, no history.
188145
188256
  - **Verify before writing** — read the actual files, never guess. All file paths in the docs must point to files that exist.`;
188146
188257
  var REVIEW_USER_MEMORIES_SYSTEM_PROMPT = `You are a user-profile reviewer for the magic-context system. You run during a scheduled dream window to decide which recurring behavioral observations about the human user are real, persistent patterns worth keeping in their global user profile.
@@ -188256,7 +188367,7 @@ Return only XML in this exact shape:
188256
188367
  function buildMaintainDocsPrompt(projectPath, lastDreamAt, existingDocs) {
188257
188368
  const hasAny = existingDocs.architecture || existingDocs.structure;
188258
188369
  const gitSinceClause = lastDreamAt ? `Run \`git log --oneline --since="${new Date(Number(lastDreamAt)).toISOString()}"\` to see what changed since the last dream.` : "No previous dream timestamp — treat this as a full analysis.";
188259
- const modeIntro = hasAny ? `Some docs already exist. Update only the sections affected by recent changes. Do NOT rewrite unchanged sections.` : `No docs exist yet. Create both ARCHITECTURE.md and STRUCTURE.md from scratch using the templates below.`;
188370
+ const modeIntro = hasAny ? `Some docs already exist and are the source of truth for shape. Make SURGICAL \`edit\` changes to only the sections affected by recent code changes; preserve every other section, the existing structure, and the existing density verbatim. Do NOT regenerate a whole file, do NOT reshape prose into a template, and do NOT use the templates below (they are for creation only). If nothing material changed, change nothing.` : `No docs exist yet. Create both ARCHITECTURE.md and STRUCTURE.md from scratch using the templates below as a STARTING shape, then go deeper than the template wherever the code warrants it.`;
188260
188371
  return `## Task: Maintain Codebase Documentation
188261
188372
 
188262
188373
  **Project:** ${projectPath}
@@ -188271,15 +188382,16 @@ ${modeIntro}
188271
188382
  ### Process
188272
188383
 
188273
188384
  1. **Check what changed.** ${gitSinceClause}
188274
- 2. **Read existing docs** (if they exist) to understand current state.
188385
+ 2. **Read existing docs** (if they exist) IN FULL to understand their current structure, depth, and voice; you will preserve all of it except what code changes force you to touch.
188275
188386
  3. **Explore the codebase** to verify and update:
188276
188387
  - Directory structure: \`find . -type d -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' | head -60\`
188277
188388
  - Entry points: \`ls src/index.* src/main.* 2>/dev/null\`
188278
188389
  - Key imports: \`grep -r "^import\\|^export" src/ --include="*.ts" | head -80\`
188279
- 4. **Write or update** using the Write tool. Always write to project root, NOT to .planning/.
188390
+ 4. **Apply the change.** If the doc EXISTS: use \`edit\` for the specific sections that drifted, never rewrite the whole file with \`write\`. If the doc is MISSING: create it with \`write\`. Always at project root, NOT \`.planning/\`.
188280
188391
 
188281
188392
  ### Rules
188282
188393
  - **NEVER touch protected regions**: any content between \`<!-- mc:protected START ... -->\` and \`<!-- mc:protected END -->\` is hand-authored and cache-critical. Reproduce it BYTE-FOR-BYTE in your rewrite — do not edit, reword, reorder, summarize, trim, or drop a single line of it, and keep the marker comments themselves. Only a human edits that region.
188394
+ - **Preserve existing structure and density**: when a doc exists, keep its headings, ordering, level of detail, and voice. Make the smallest edits that re-sync it with the code. NEVER flatten dense hand-written prose into the generic template, collapse a detailed section into bullet stubs, or drop specific invariants/edge-cases/mechanism detail because it does not match a standard layout. Denser and more specific than the template is BETTER.
188283
188395
  - **Be prescriptive**: "Use X pattern" not "X pattern is used"
188284
188396
  - **Always include file paths** in backticks
188285
188397
  - **Write current state only**: no temporal language, no history
@@ -191259,10 +191371,23 @@ function getAsyncModule() {
191259
191371
  asyncModulePromise ??= newQuickJSAsyncWASMModuleFromVariant(import_quickjs_singlefile_cjs_release_asyncify.default);
191260
191372
  return asyncModulePromise;
191261
191373
  }
191374
+ var sandboxRunChain = Promise.resolve();
191375
+ function withSandboxLock(fn) {
191376
+ const run = sandboxRunChain.then(fn, fn);
191377
+ sandboxRunChain = run.then(() => {
191378
+ return;
191379
+ }, () => {
191380
+ return;
191381
+ });
191382
+ return run;
191383
+ }
191262
191384
  var DEFAULT_TIMEOUT_MS = 2000;
191263
191385
  var DEFAULT_HEAP_LIMIT_BYTES = 8 * 1024 * 1024;
191264
191386
  var DEFAULT_STACK_LIMIT_BYTES = 512 * 1024;
191265
191387
  async function runCompiledSmartNoteCheck(options) {
191388
+ return withSandboxLock(() => runCompiledSmartNoteCheckLocked(options));
191389
+ }
191390
+ async function runCompiledSmartNoteCheckLocked(options) {
191266
191391
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
191267
191392
  const controller = new AbortController;
191268
191393
  const externalAbort = () => controller.abort(options.signal?.reason);
@@ -198717,7 +198842,7 @@ var RECENT_TOOL_SKELETON_WINDOW = 20;
198717
198842
  function buildReplacementContent(tagId) {
198718
198843
  return `[dropped §${tagId}§]`;
198719
198844
  }
198720
- function applyPendingOperations(sessionId, db, targets, protectedTags = 0, preloadedTags, preloadedPendingOps, syntheticPendingOps = []) {
198845
+ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set) {
198721
198846
  let didMutateMessage = false;
198722
198847
  db.transaction(() => {
198723
198848
  const tags = preloadedTags ?? getTagsBySession(db, sessionId);
@@ -198748,7 +198873,15 @@ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, prelo
198748
198873
  }
198749
198874
  let shouldPersistDrop = false;
198750
198875
  if (isToolTag) {
198751
- if (skeletonWindow.has(pendingOp.tagId)) {
198876
+ if (editMarkerTagIds.has(pendingOp.tagId)) {
198877
+ const markResult = target?.editMarker?.() ?? "absent";
198878
+ if (markResult === "incomplete" || markResult === "absent") {
198879
+ continue;
198880
+ }
198881
+ didMutateMessage = true;
198882
+ updateTagDropMode(db, sessionId, pendingOp.tagId, "edit_marker");
198883
+ shouldPersistDrop = true;
198884
+ } else if (skeletonWindow.has(pendingOp.tagId)) {
198752
198885
  const truncResult = target?.truncate?.() ?? "absent";
198753
198886
  if (truncResult === "incomplete" || synthetic && truncResult !== "truncated") {
198754
198887
  continue;
@@ -198793,7 +198926,12 @@ function applyFlushedStatuses(sessionId, db, targets, preloadedTags) {
198793
198926
  if (tag.status === "dropped") {
198794
198927
  const target = targets.get(tag.tagNumber);
198795
198928
  if (tag.type === "tool") {
198796
- if (tag.dropMode === "truncated") {
198929
+ if (tag.dropMode === "edit_marker") {
198930
+ const markResult = target?.editMarker?.() ?? "absent";
198931
+ if (markResult === "truncated") {
198932
+ didMutateMessage = true;
198933
+ }
198934
+ } else if (tag.dropMode === "truncated") {
198797
198935
  const truncResult = target?.truncate?.() ?? "absent";
198798
198936
  if (truncResult === "truncated") {
198799
198937
  didMutateMessage = true;
@@ -198848,6 +198986,7 @@ function stripStructuralNoise(messages) {
198848
198986
  // src/hooks/magic-context/tag-messages.ts
198849
198987
  init_storage_tags();
198850
198988
  await init_storage();
198989
+ init_commit_detection();
198851
198990
  // src/hooks/magic-context/drop-stale-reduce-calls.ts
198852
198991
  var STALE_TOOL_NAMES = new Set(["ctx_reduce"]);
198853
198992
  function isReduceToolPart(part) {
@@ -199168,7 +199307,6 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
199168
199307
  let lastReduceMessageIndex = -1;
199169
199308
  const RECENT_REDUCE_LOOKBACK = 10;
199170
199309
  const COMMIT_LOOKBACK = 5;
199171
- const COMMIT_HASH_PATTERN2 = /\b[0-9a-f]{7,12}\b/;
199172
199310
  let commitDetected = false;
199173
199311
  let accDerive = 0;
199174
199312
  let accGetToolTag = 0;
@@ -199359,7 +199497,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
199359
199497
  for (const part of message.parts) {
199360
199498
  if (isTextPart(part)) {
199361
199499
  const text = part.text;
199362
- if (COMMIT_HASH_PATTERN2.test(text) && /\b(commit|committed|cherry-pick|merge|rebas)/i.test(text)) {
199500
+ if (textMentionsRecentCommit(text)) {
199363
199501
  commitDetected = true;
199364
199502
  break;
199365
199503
  }
@@ -200854,6 +200992,99 @@ function isVisibleNoteReadPart(part) {
200854
200992
  return false;
200855
200993
  }
200856
200994
 
200995
+ // src/hooks/magic-context/supersession-reclaim.ts
200996
+ init_edit_marker();
200997
+ await init_storage();
200998
+ var TODOWRITE_KEEP = 1;
200999
+ var CTX_REDUCE_KEEP = 5;
201000
+ var ZERO_VALUE_META_TOOLS = new Set(["bash_status", "bash_kill"]);
201001
+ var CTX_NOTE_ZERO_VALUE_ACTIONS = new Set(["read", "dismiss"]);
201002
+ function buildSupersessionReclaimOps(input) {
201003
+ const realPendingTagIds = new Set((input.pendingOps ?? []).map((op) => op.tagId));
201004
+ const tags = getActiveTagsBySession(input.db, input.sessionId);
201005
+ const toolTags = tags.filter((tag) => tag.type === "tool" && tag.status === "active").sort((left, right) => right.tagNumber - left.tagNumber);
201006
+ const dropTagIds = [];
201007
+ let todowriteSeen = 0;
201008
+ let ctxReduceSeen = 0;
201009
+ for (const tag of toolTags) {
201010
+ const name2 = tag.toolName;
201011
+ if (!name2)
201012
+ continue;
201013
+ let isTarget = false;
201014
+ if (name2 === "todowrite") {
201015
+ todowriteSeen += 1;
201016
+ isTarget = todowriteSeen > TODOWRITE_KEEP;
201017
+ } else if (name2 === "ctx_reduce") {
201018
+ ctxReduceSeen += 1;
201019
+ isTarget = ctxReduceSeen > CTX_REDUCE_KEEP;
201020
+ } else if (ZERO_VALUE_META_TOOLS.has(name2)) {
201021
+ isTarget = true;
201022
+ } else if (name2 === "ctx_note") {
201023
+ const action = input.targets.get(tag.tagNumber)?.readInput?.()?.action;
201024
+ isTarget = typeof action === "string" && CTX_NOTE_ZERO_VALUE_ACTIONS.has(action);
201025
+ }
201026
+ if (isTarget)
201027
+ dropTagIds.push(tag.tagNumber);
201028
+ }
201029
+ const synthetic = [];
201030
+ for (const tagId of dropTagIds) {
201031
+ if (realPendingTagIds.has(tagId))
201032
+ continue;
201033
+ if (input.targets.get(tagId)?.canDrop?.() !== true)
201034
+ continue;
201035
+ synthetic.push({
201036
+ id: 0,
201037
+ sessionId: input.sessionId,
201038
+ tagId,
201039
+ operation: "drop",
201040
+ queuedAt: 0
201041
+ });
201042
+ }
201043
+ return synthetic;
201044
+ }
201045
+ function buildEditSupersessionReclaim(input) {
201046
+ const realPendingTagIds = new Set((input.pendingOps ?? []).map((op) => op.tagId));
201047
+ const tags = getActiveTagsBySession(input.db, input.sessionId);
201048
+ const editTags = tags.filter((tag) => tag.type === "tool" && tag.status === "active" && isEditTool(tag.toolName)).sort((left, right) => right.tagNumber - left.tagNumber);
201049
+ const seenFile = new Set;
201050
+ const ops = [];
201051
+ const editMarkerTagIds = new Set;
201052
+ for (const tag of editTags) {
201053
+ const filePath = readFilePath(input.targets.get(tag.tagNumber));
201054
+ if (!filePath)
201055
+ continue;
201056
+ if (!seenFile.has(filePath)) {
201057
+ seenFile.add(filePath);
201058
+ continue;
201059
+ }
201060
+ if (realPendingTagIds.has(tag.tagNumber))
201061
+ continue;
201062
+ if (input.targets.get(tag.tagNumber)?.canDrop?.() !== true)
201063
+ continue;
201064
+ editMarkerTagIds.add(tag.tagNumber);
201065
+ ops.push({
201066
+ id: 0,
201067
+ sessionId: input.sessionId,
201068
+ tagId: tag.tagNumber,
201069
+ operation: "drop",
201070
+ queuedAt: 0
201071
+ });
201072
+ }
201073
+ return { ops, editMarkerTagIds };
201074
+ }
201075
+ var FILE_PATH_KEYS = ["filePath", "file_path", "path"];
201076
+ function readFilePath(target) {
201077
+ const input = target?.readInput?.();
201078
+ if (!input)
201079
+ return null;
201080
+ for (const key of FILE_PATH_KEYS) {
201081
+ const value = input[key];
201082
+ if (typeof value === "string" && value.length > 0)
201083
+ return value;
201084
+ }
201085
+ return null;
201086
+ }
201087
+
200857
201088
  // src/hooks/magic-context/todo-view.ts
200858
201089
  import { createHash as createHash12 } from "node:crypto";
200859
201090
  var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
@@ -201124,9 +201355,38 @@ async function runPostTransformPhase(args) {
201124
201355
  watermark: args.sessionMeta.toolReclaimWatermark ?? 0,
201125
201356
  pendingOps
201126
201357
  });
201358
+ const editMarkerTagIds = new Set;
201359
+ if (args.smartDrops) {
201360
+ const selectedIds = new Set(syntheticPendingOps.map((op) => op.tagId));
201361
+ const supersessionOps = buildSupersessionReclaimOps({
201362
+ db: args.db,
201363
+ sessionId: args.sessionId,
201364
+ targets: args.targets,
201365
+ pendingOps
201366
+ });
201367
+ for (const op of supersessionOps) {
201368
+ if (!selectedIds.has(op.tagId)) {
201369
+ syntheticPendingOps.push(op);
201370
+ selectedIds.add(op.tagId);
201371
+ }
201372
+ }
201373
+ const editReclaim = buildEditSupersessionReclaim({
201374
+ db: args.db,
201375
+ sessionId: args.sessionId,
201376
+ targets: args.targets,
201377
+ pendingOps
201378
+ });
201379
+ for (const op of editReclaim.ops) {
201380
+ if (!selectedIds.has(op.tagId)) {
201381
+ syntheticPendingOps.push(op);
201382
+ selectedIds.add(op.tagId);
201383
+ editMarkerTagIds.add(op.tagId);
201384
+ }
201385
+ }
201386
+ }
201127
201387
  autoReclaimTargetCount = syntheticPendingOps.length;
201128
201388
  if (syntheticPendingOps.length > 0) {
201129
- autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTags, undefined, [], syntheticPendingOps);
201389
+ autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTags, undefined, [], syntheticPendingOps, editMarkerTagIds);
201130
201390
  if (autoReclaimDidMutate) {
201131
201391
  droppedCount += syntheticPendingOps.length;
201132
201392
  autoReclaimDidMutateThisPass = true;
@@ -202068,6 +202328,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
202068
202328
  sessionDirectory,
202069
202329
  autoSearch: deps.autoSearch,
202070
202330
  cavemanTextCompression: deps.ctxReduceEnabled === false && !reducedMode ? deps.cavemanTextCompression : undefined,
202331
+ smartDrops: deps.smartDrops === true,
202071
202332
  resolvedProviderID,
202072
202333
  historyRefreshSessions: deps.historyRefreshSessions,
202073
202334
  m0M1: {
@@ -202983,16 +203244,20 @@ var PARTNER_FRAME_CLOSER_NO_REDUCE = `
202983
203244
  Context is managed for you entirely automatically — there's nothing to prune and no warnings to act on. Stay reasonably concise per operation, and never let context size change *what* work you take on or *how thoroughly* you do it.`;
202984
203245
  var CTX_NOTE_GUIDANCE = `Use \`ctx_note\` ONLY for genuinely future concerns — something to revisit much later, not work coming up in the next few turns (that's already in your active context) and not active multi-step work (use todos for that). Magic Context preserves your full context across both compaction and restarts, so an upcoming restart or "let's come back to this later" is never a reason to take a note — nothing is lost either way. Notes you do take survive compression and resurface at natural work boundaries (after commits, historian runs, todo completion).`;
202985
203246
  var TOOL_HISTORY_GUIDANCE = `Compressed history intentionally omits tool calls and their outputs — summaries like "I edited file X" are historian records, not patterns to replicate. In the live conversation, older tool calls and their results are cleaned up to save context — you may see your own past messages referencing actions without the corresponding tool call or result visible. This is normal context management. ALWAYS use real tool calls; never simulate, fabricate, or inline tool outputs in your text. If there is no tool result message, the action did not happen. NEVER simulate, hallucinate or claim tool calls, command output, search results, file edits, or diffs in plain text as if they actually occurred.`;
202986
- var BASE_INTRO = (protectedTags) => `Messages and tool outputs are tagged with §N§ identifiers (e.g., §1§, §42§).
202987
- Use \`ctx_reduce\` to mark spent tagged content as discardable and reclaim space. Marking is NOT an immediate delete — it queues the content, which stays fully visible until space is actually needed (as soon as the next turn if you're already under pressure, much later if not), so mark a tool output as soon as you're done with it rather than hoarding the call for the end of the turn. The last ${protectedTags} tags are protected (marking one just queues it until it ages out). Syntax: "3-5", "1,2,9", or "1-5,8,12-15".
202988
- Do not announce or narrate \`ctx_reduce\` drops — just call the tool silently. Saying "I'll drop these outputs" wastes tokens the user does not care about.
202989
- ${CTX_NOTE_GUIDANCE}
202990
- Use \`ctx_memory\` for durable project knowledge: write what future sessions must know, update/archive/merge the memories you see in \`<project-memory>\` when they drift. Memories persist across sessions and every new session starts with them.
203247
+ var MEMORY_GUIDANCE = `Use \`ctx_memory\` for durable project knowledge: write what future sessions must know, update/archive/merge the memories you see in \`<project-memory>\` when they drift. Memories persist across sessions and every new session starts with them.
202991
203248
  **Save to memory proactively**: If you spent multiple turns finding something (a file path, a DB location, a config pattern, a workaround), save it with \`ctx_memory\` so future sessions don't repeat the search. Examples:
202992
203249
  - Found a project's source code path after searching → \`ctx_memory(action="write", category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/opencode")\`
202993
203250
  - Discovered a non-obvious build/test command → \`ctx_memory(action="write", category="PROJECT_RULES", content="Always use scripts/release.sh for releases")\`
202994
- - Learned a constraint the hard way → \`ctx_memory(action="write", category="CONSTRAINTS", content="Dashboard Tauri build needs RGBA PNGs, not grayscale")\`
202995
- Use \`ctx_search\` to search across project memories, indexed git commits, and this session's full conversation history (including compacted parts) from one query.
203251
+ - Learned a constraint the hard way → \`ctx_memory(action="write", category="CONSTRAINTS", content="Dashboard Tauri build needs RGBA PNGs, not grayscale")\``;
203252
+ function memoryGuidanceBlock(memoryEnabled) {
203253
+ return memoryEnabled ? `${MEMORY_GUIDANCE}
203254
+ ` : "";
203255
+ }
203256
+ var BASE_INTRO = (protectedTags, memoryEnabled) => `Messages and tool outputs are tagged with §N§ identifiers (e.g., §1§, §42§).
203257
+ Use \`ctx_reduce\` to mark spent tagged content as discardable and reclaim space. Marking is NOT an immediate delete — it queues the content, which stays fully visible until space is actually needed (as soon as the next turn if you're already under pressure, much later if not), so mark a tool output as soon as you're done with it rather than hoarding the call for the end of the turn. The last ${protectedTags} tags are protected (marking one just queues it until it ages out). Syntax: "3-5", "1,2,9", or "1-5,8,12-15".
203258
+ Do not announce or narrate \`ctx_reduce\` drops — just call the tool silently. Saying "I'll drop these outputs" wastes tokens the user does not care about.
203259
+ ${CTX_NOTE_GUIDANCE}
203260
+ ${memoryGuidanceBlock(memoryEnabled)}Use \`ctx_search\` to search across project memories, indexed git commits, and this session's full conversation history (including compacted parts) from one query.
202996
203261
  Use \`ctx_expand\` to recover the raw conversation behind a \`<compartment>\` summary in \`<session-history>\` — pass its \`start\`/\`end\` attributes when the summary is not enough (exact wording, values, error text).
202997
203262
  **Search before asking the user**: If you can't remember or don't know something that might have been discussed before or stored in project memory, use \`ctx_search\` before asking the user. Examples:
202998
203263
  - Can't remember where a related codebase or dependency lives → \`ctx_search(query="opencode source code path")\`
@@ -203006,13 +203271,8 @@ NEVER drop large ranges blindly (e.g., "1-50"). Review each tag before deciding.
203006
203271
  Keep your user's instructions and intent — never drop a user message for its directive, even an old one. But a large block of pasted content inside a user message (logs, data dumps, long code, attachments) is fair to mark discardable once you've extracted what you need — it stays searchable via \`ctx_search\`.
203007
203272
  NEVER drop assistant text messages unless they are exceptionally large. Your conversation messages are lightweight; only large tool outputs are worth dropping.
203008
203273
  Before your turn finishes, consider using \`ctx_reduce\` to drop large tool outputs you no longer need.`;
203009
- var BASE_INTRO_NO_REDUCE = () => `${CTX_NOTE_GUIDANCE}
203010
- Use \`ctx_memory\` for durable project knowledge: write what future sessions must know, update/archive/merge the memories you see in \`<project-memory>\` when they drift. Memories persist across sessions and every new session starts with them.
203011
- **Save to memory proactively**: If you spent multiple turns finding something (a file path, a DB location, a config pattern, a workaround), save it with \`ctx_memory\` so future sessions don't repeat the search. Examples:
203012
- - Found a project's source code path after searching → \`ctx_memory(action="write", category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/opencode")\`
203013
- - Discovered a non-obvious build/test command → \`ctx_memory(action="write", category="PROJECT_RULES", content="Always use scripts/release.sh for releases")\`
203014
- - Learned a constraint the hard way → \`ctx_memory(action="write", category="CONSTRAINTS", content="Dashboard Tauri build needs RGBA PNGs, not grayscale")\`
203015
- Use \`ctx_search\` to search across project memories, indexed git commits, and this session's full conversation history (including compacted parts) from one query.
203274
+ var BASE_INTRO_NO_REDUCE = (memoryEnabled) => `${CTX_NOTE_GUIDANCE}
203275
+ ${memoryGuidanceBlock(memoryEnabled)}Use \`ctx_search\` to search across project memories, indexed git commits, and this session's full conversation history (including compacted parts) from one query.
203016
203276
  Use \`ctx_expand\` to recover the raw conversation behind a \`<compartment>\` summary in \`<session-history>\` — pass its \`start\`/\`end\` attributes when the summary is not enough (exact wording, values, error text).
203017
203277
  **Search before asking the user**: If you can't remember or don't know something that might have been discussed before or stored in project memory, use \`ctx_search\` before asking the user. Examples:
203018
203278
  - Can't remember where a related codebase or dependency lives → \`ctx_search(query="opencode source code path")\`
@@ -203046,7 +203306,7 @@ Drop silently — do not narrate it. NEVER drop large ranges blindly (e.g., "1-5
203046
203306
  Older tool calls may show \`[dropped §N§]\` sentinels; that is normal context management, not a pattern to copy. ALWAYS make fresh real tool calls when you need data again; never fabricate or inline tool output.`;
203047
203307
  var CAVEMAN_COMPRESSION_WARNING = `
203048
203308
  **BEWARE**: History compression is on; older user AND assistant text — including your own earlier responses — has been deterministically rewritten in a terse caveman style (dropped articles, missing auxiliaries, \`//\` instead of connectives like \`because\`). This is automatic context compression that runs after the fact, not your actual prior wording or the user's. **DO NOT mimic this style in new turns.** Write fresh responses in normal prose. If you notice your output drifting into caveman cadence, that drift is in-context-learning bleeding from the compressed history — consciously revert to full sentences.`;
203049
- function buildMagicContextSection(_agent, protectedTags, ctxReduceEnabled = true, dreamerEnabled = false, temporalAwarenessEnabled = false, cavemanTextCompressionEnabled = false, subagentMode = false, language) {
203309
+ function buildMagicContextSection(_agent, protectedTags, ctxReduceEnabled = true, dreamerEnabled = false, temporalAwarenessEnabled = false, cavemanTextCompressionEnabled = false, subagentMode = false, language, memoryEnabled = true) {
203050
203310
  if (subagentMode) {
203051
203311
  return `## Magic Context
203052
203312
 
@@ -203068,14 +203328,14 @@ ${languageDirective}` : "";
203068
203328
  ${LONG_TERM_PARTNER_FRAME}
203069
203329
  ${PARTNER_FRAME_CLOSER_NO_REDUCE}
203070
203330
 
203071
- ${BASE_INTRO_NO_REDUCE()}${smartNoteGuidance}${temporalGuidance}${cavemanWarning}${languageGuidance}`;
203331
+ ${BASE_INTRO_NO_REDUCE(memoryEnabled)}${smartNoteGuidance}${temporalGuidance}${cavemanWarning}${languageGuidance}`;
203072
203332
  }
203073
203333
  return `## Magic Context
203074
203334
 
203075
203335
  ${LONG_TERM_PARTNER_FRAME}
203076
203336
  ${PARTNER_FRAME_CLOSER_REDUCE}
203077
203337
 
203078
- ${BASE_INTRO(protectedTags)}${smartNoteGuidance}${temporalGuidance}
203338
+ ${BASE_INTRO(protectedTags, memoryEnabled)}${smartNoteGuidance}${temporalGuidance}
203079
203339
  ${GENERIC_SECTION}
203080
203340
 
203081
203341
  Prefer many small targeted operations over one large blanket operation, and keep the working set tidy as routine maintenance.${languageGuidance}`;
@@ -203136,7 +203396,7 @@ function createSystemPromptHashHandler(deps) {
203136
203396
  const fullPrompt = output.system.join(`
203137
203397
  `);
203138
203398
  if (fullPrompt.length > 0 && !fullPrompt.includes(MAGIC_CONTEXT_MARKER) && !skipGuidanceForDisabledSubagent) {
203139
- const guidance = buildMagicContextSection(null, deps.protectedTags, effectiveCtxReduceEnabled, deps.dreamerEnabled, deps.experimentalTemporalAwareness, deps.experimentalCavemanTextCompression, subagentReduceMode, deps.language);
203399
+ const guidance = buildMagicContextSection(null, deps.protectedTags, effectiveCtxReduceEnabled, deps.dreamerEnabled, deps.experimentalTemporalAwareness, deps.experimentalCavemanTextCompression, subagentReduceMode, deps.language, deps.memoryEnabled !== false);
203140
203400
  output.system.push(guidance);
203141
203401
  sessionLog(sessionId, `injected generic guidance into system prompt (ctxReduce=${effectiveCtxReduceEnabled}, subagent=${isSubagentSession}, subagentReduceMode=${subagentReduceMode})`);
203142
203402
  }
@@ -203574,6 +203834,7 @@ function createMagicContextHook(deps) {
203574
203834
  channel1StateBySession,
203575
203835
  protectedTags: deps.config.protected_tags,
203576
203836
  ctxReduceEnabled,
203837
+ smartDrops: deps.config.smart_drops === true,
203577
203838
  clearReasoningAge: deps.config.clear_reasoning_age ?? 50,
203578
203839
  commitClusterTrigger: deps.config.commit_cluster_trigger,
203579
203840
  historyRefreshSessions,
@@ -203755,6 +204016,7 @@ function createMagicContextHook(deps) {
203755
204016
  protectedTags: deps.config.protected_tags,
203756
204017
  ctxReduceEnabled,
203757
204018
  dreamerEnabled: dreamerRunnable,
204019
+ memoryEnabled: deps.config.memory?.enabled !== false,
203758
204020
  language: deps.config.language,
203759
204021
  injectDocs: deps.config.dreamer?.inject_docs !== false,
203760
204022
  directory: deps.directory,
@@ -206141,6 +206403,7 @@ function createToolRegistry(args) {
206141
206403
  ensureProjectRegisteredFromOpenCodeDirectory(ctx.directory, db);
206142
206404
  const resolveProjectPath = (directory) => resolveProjectIdentity(directory);
206143
206405
  const ctxReduceEnabled = pluginConfig.ctx_reduce_enabled !== false;
206406
+ const memoryEnabled = pluginConfig.memory?.enabled !== false;
206144
206407
  const allTools = {
206145
206408
  ...ctxReduceEnabled ? createCtxReduceTools({
206146
206409
  db,
@@ -206157,12 +206420,12 @@ function createToolRegistry(args) {
206157
206420
  resolveProjectPath,
206158
206421
  ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory
206159
206422
  }),
206160
- ...createCtxMemoryTools({
206423
+ ...memoryEnabled ? createCtxMemoryTools({
206161
206424
  db,
206162
206425
  resolveProjectPath,
206163
206426
  ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
206164
206427
  allowedActions: [...CTX_MEMORY_ACTIONS]
206165
- })
206428
+ }) : {}
206166
206429
  };
206167
206430
  for (const toolDefinition of Object.values(allTools)) {
206168
206431
  normalizeToolArgSchemas(toolDefinition);
@@ -1 +1 @@
1
- {"version":3,"file":"create-session-hooks.d.ts","sourceRoot":"","sources":["../../../src/plugin/hooks/create-session-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAO7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BjF;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;IACvC,gBAAgB,EAAE,gBAAgB,CAAC;CACtC;;;;;;qBA+By6J,CAAC;;;;;;;;;;;;qBAAvsD,CAAC;mBAAyB,CAAC;iBAAuB,CAAC;iBAAuB,CAAC;0BAAc,CAAC;uBAAiB,CAAC;;;;;;0BAAmtmC,CAAC;;;;;;EADnitC"}
1
+ {"version":3,"file":"create-session-hooks.d.ts","sourceRoot":"","sources":["../../../src/plugin/hooks/create-session-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAO7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BjF;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;IACvC,gBAAgB,EAAE,gBAAgB,CAAC;CACtC;;;;;;qBA+BmvK,CAAC;;;;;;;;;;;;qBAAjhE,CAAC;mBAAyB,CAAC;iBAAuB,CAAC;iBAAuB,CAAC;0BAAc,CAAC;uBAAiB,CAAC;;;;;;0BAAggnC,CAAC;;;;;;EADh1tC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../../src/plugin/tool-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAiB1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;CAC1C,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAiFjC"}
1
+ {"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../../src/plugin/tool-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAiB1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;CAC1C,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAyFjC"}