@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.
- package/README.md +26 -1
- package/dist/agents/magic-context-prompt.d.ts +1 -1
- package/dist/agents/magic-context-prompt.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +11 -0
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-prompts.d.ts +1 -1
- package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/types.d.ts +12 -1
- package/dist/features/magic-context/types.d.ts.map +1 -1
- package/dist/hooks/magic-context/apply-operations.d.ts +8 -1
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/edit-marker.d.ts +11 -0
- package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -0
- package/dist/hooks/magic-context/hook.d.ts +1 -0
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
- package/dist/hooks/magic-context/supersession-reclaim.d.ts +34 -0
- package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -0
- package/dist/hooks/magic-context/system-prompt-hash.d.ts +5 -0
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts +8 -0
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-drop-target.d.ts +2 -0
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +8 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +4 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.js +306 -43
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/tool-registry.d.ts.map +1 -1
- package/dist/shared/announcement.d.ts +1 -1
- package/dist/shared/commit-detection.d.ts +29 -0
- package/dist/shared/commit-detection.d.ts.map +1 -0
- package/dist/shared/tag-transcript.d.ts.map +1 -1
- package/dist/shared/transcript.d.ts +15 -0
- package/dist/shared/transcript.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/shared/announcement.ts +3 -3
- package/src/shared/commit-detection.test.ts +63 -0
- package/src/shared/commit-detection.ts +53 -0
- package/src/shared/tag-transcript.ts +32 -0
- package/src/shared/transcript-opencode.ts +33 -0
- 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(
|
|
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 || !
|
|
149501
|
+
if (commitHashes.length === 0 || !COMMIT_VERB_PATTERN.test(text)) {
|
|
149488
149502
|
return { text, commitHashes };
|
|
149489
149503
|
}
|
|
149490
|
-
const withoutHashes = text.replace(
|
|
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
|
|
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
|
|
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(
|
|
149978
|
+
if (value.endsWith(TRUNCATION_SENTINEL2) || value === "[object]" || /^\[\d+ items\]$/.test(value))
|
|
149901
149979
|
continue;
|
|
149902
|
-
input[key] = value.length > 5 ? `${
|
|
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,
|
|
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.
|
|
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 '
|
|
186536
|
-
"
|
|
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.
|
|
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
|
|
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. **
|
|
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 (
|
|
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 === "
|
|
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 (
|
|
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
|
|
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
|
-
|
|
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 \`
|
|
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+
|
|
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,
|
|
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"}
|