@cortexkit/pi-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/dist/index.js +277 -39
- package/dist/subagent-entry.js +46 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15906,6 +15906,17 @@ function getRawSessionMessageCountFromDb(db, sessionId) {
|
|
|
15906
15906
|
return typeof row?.count === "number" ? row.count : 0;
|
|
15907
15907
|
}
|
|
15908
15908
|
|
|
15909
|
+
// ../plugin/src/shared/commit-detection.ts
|
|
15910
|
+
var HASH_HEX = "[0-9a-f]{7,12}";
|
|
15911
|
+
var COMMIT_HASH_TEST_PATTERN = new RegExp(`\\b${HASH_HEX}\\b`, "i");
|
|
15912
|
+
var COMMIT_VERB_PATTERN = /\b(?:commit(?:ted|ting|s)?|cherry-?pick(?:ed|ing|s)?|merge[ds]?|merging|rebas(?:e|ed|es|ing))\b/i;
|
|
15913
|
+
function textMentionsRecentCommit(text) {
|
|
15914
|
+
return COMMIT_HASH_TEST_PATTERN.test(text) && COMMIT_VERB_PATTERN.test(text);
|
|
15915
|
+
}
|
|
15916
|
+
function createCommitHashExtractPattern() {
|
|
15917
|
+
return new RegExp(`\`?\\b(${HASH_HEX})\\b\`?`, "gi");
|
|
15918
|
+
}
|
|
15919
|
+
|
|
15909
15920
|
// ../../node_modules/.bun/ai-tokenizer@1.0.6/node_modules/ai-tokenizer/dist/index.js
|
|
15910
15921
|
function _typeof(o) {
|
|
15911
15922
|
"@babel/helpers - typeof";
|
|
@@ -148345,8 +148356,6 @@ var decoder = {
|
|
|
148345
148356
|
};
|
|
148346
148357
|
|
|
148347
148358
|
// ../plugin/src/hooks/magic-context/read-session-formatting.ts
|
|
148348
|
-
var COMMIT_HASH_PATTERN = /`?\b([0-9a-f]{6,12})\b`?/gi;
|
|
148349
|
-
var COMMIT_HINT_PATTERN = /\b(commit(?:ted)?|cherry-?pick(?:ed)?|hash(?:es)?|sha)\b/i;
|
|
148350
148359
|
var MAX_COMMITS_PER_BLOCK = 5;
|
|
148351
148360
|
function hasMeaningfulUserText(parts) {
|
|
148352
148361
|
for (const part of parts) {
|
|
@@ -148450,7 +148459,7 @@ function formatBlock(block) {
|
|
|
148450
148459
|
function extractCommitHashes(text) {
|
|
148451
148460
|
const hashes = [];
|
|
148452
148461
|
const seen = new Set;
|
|
148453
|
-
for (const match of text.matchAll(
|
|
148462
|
+
for (const match of text.matchAll(createCommitHashExtractPattern())) {
|
|
148454
148463
|
const hash = match[1]?.toLowerCase();
|
|
148455
148464
|
if (!hash || seen.has(hash))
|
|
148456
148465
|
continue;
|
|
@@ -148463,10 +148472,10 @@ function extractCommitHashes(text) {
|
|
|
148463
148472
|
}
|
|
148464
148473
|
function compactTextForSummary(text, role) {
|
|
148465
148474
|
const commitHashes = role === "assistant" ? extractCommitHashes(text) : [];
|
|
148466
|
-
if (commitHashes.length === 0 || !
|
|
148475
|
+
if (commitHashes.length === 0 || !COMMIT_VERB_PATTERN.test(text)) {
|
|
148467
148476
|
return { text, commitHashes };
|
|
148468
148477
|
}
|
|
148469
|
-
const withoutHashes = text.replace(
|
|
148478
|
+
const withoutHashes = text.replace(createCommitHashExtractPattern(), "").replace(/\(\s*\)/g, "").replace(/\s+,/g, ",").replace(/,\s*,+/g, ", ").replace(/\s{2,}/g, " ").replace(/\s+([,.;:])/g, "$1").trim();
|
|
148470
148479
|
return {
|
|
148471
148480
|
text: withoutHashes.length > 0 ? withoutHashes : text,
|
|
148472
148481
|
commitHashes
|
|
@@ -148688,6 +148697,36 @@ function isRecord(value) {
|
|
|
148688
148697
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
148689
148698
|
}
|
|
148690
148699
|
|
|
148700
|
+
// ../plugin/src/hooks/magic-context/edit-marker.ts
|
|
148701
|
+
var TRUNCATION_SENTINEL = "...[truncated]";
|
|
148702
|
+
var EDIT_REGION_HINT_LEN = 40;
|
|
148703
|
+
var PATH_KEYS = new Set(["filePath", "file_path", "path"]);
|
|
148704
|
+
var DIFF_KEYS = new Set(["oldString", "newString", "content", "old_string", "new_string"]);
|
|
148705
|
+
function safeSlice(str, maxLen) {
|
|
148706
|
+
if (str.length <= maxLen)
|
|
148707
|
+
return str;
|
|
148708
|
+
const lastCharCode = str.charCodeAt(maxLen - 1);
|
|
148709
|
+
if (lastCharCode >= 55296 && lastCharCode <= 56319) {
|
|
148710
|
+
return str.slice(0, maxLen - 1);
|
|
148711
|
+
}
|
|
148712
|
+
return str.slice(0, maxLen);
|
|
148713
|
+
}
|
|
148714
|
+
function isEditTool(name2) {
|
|
148715
|
+
return name2 === "edit" || name2 === "write";
|
|
148716
|
+
}
|
|
148717
|
+
function applyEditMarkerToInput(input) {
|
|
148718
|
+
for (const key of Object.keys(input)) {
|
|
148719
|
+
if (PATH_KEYS.has(key))
|
|
148720
|
+
continue;
|
|
148721
|
+
const value = input[key];
|
|
148722
|
+
if (typeof value !== "string" || !DIFF_KEYS.has(key))
|
|
148723
|
+
continue;
|
|
148724
|
+
if (value.endsWith(TRUNCATION_SENTINEL))
|
|
148725
|
+
continue;
|
|
148726
|
+
input[key] = value.length > EDIT_REGION_HINT_LEN ? `${safeSlice(value, EDIT_REGION_HINT_LEN)}${TRUNCATION_SENTINEL}` : value;
|
|
148727
|
+
}
|
|
148728
|
+
}
|
|
148729
|
+
|
|
148691
148730
|
// ../plugin/src/hooks/magic-context/tool-drop-target.ts
|
|
148692
148731
|
var IGNORE_PART_TYPES = new Set([
|
|
148693
148732
|
"thinking",
|
|
@@ -155191,7 +155230,7 @@ function toTagEntry(row) {
|
|
|
155191
155230
|
messageId: row.message_id,
|
|
155192
155231
|
type,
|
|
155193
155232
|
status,
|
|
155194
|
-
dropMode: row.drop_mode === "truncated" ? "truncated" : "full",
|
|
155233
|
+
dropMode: row.drop_mode === "truncated" ? "truncated" : row.drop_mode === "edit_marker" ? "edit_marker" : "full",
|
|
155195
155234
|
toolName: row.tool_name ?? null,
|
|
155196
155235
|
inputByteSize: row.input_byte_size ?? 0,
|
|
155197
155236
|
byteSize: row.byte_size,
|
|
@@ -156347,10 +156386,10 @@ function compareSemverCore(a, b) {
|
|
|
156347
156386
|
|
|
156348
156387
|
// ../plugin/src/shared/announcement.ts
|
|
156349
156388
|
init_data_path();
|
|
156350
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
156389
|
+
var ANNOUNCEMENT_VERSION = "0.29.0";
|
|
156351
156390
|
var ANNOUNCEMENT_FEATURES = [
|
|
156352
|
-
`New '
|
|
156353
|
-
"
|
|
156391
|
+
`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.`,
|
|
156392
|
+
"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."
|
|
156354
156393
|
];
|
|
156355
156394
|
var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU";
|
|
156356
156395
|
var STATE_FILENAME = "last_announced_version";
|
|
@@ -172455,6 +172494,7 @@ var MagicContextConfigSchema = exports_external.object({
|
|
|
172455
172494
|
}).describe("Embedding provider configuration"),
|
|
172456
172495
|
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).'),
|
|
172457
172496
|
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."),
|
|
172497
|
+
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."),
|
|
172458
172498
|
caveman_text_compression: exports_external.object({
|
|
172459
172499
|
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%)."),
|
|
172460
172500
|
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.")
|
|
@@ -176274,6 +176314,7 @@ var MAINTAIN_DOCS_SYSTEM_PROMPT = `You are a documentation maintainer for the ma
|
|
|
176274
176314
|
|
|
176275
176315
|
## Rules
|
|
176276
176316
|
- **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.
|
|
176317
|
+
- **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.
|
|
176277
176318
|
- **Be prescriptive** ("Use X pattern", not "X pattern is used"). **Current state only** — no temporal language, no history.
|
|
176278
176319
|
- **Verify before writing** — read the actual files, never guess. All file paths in the docs must point to files that exist.`;
|
|
176279
176320
|
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.
|
|
@@ -176389,7 +176430,7 @@ Return only XML in this exact shape:
|
|
|
176389
176430
|
function buildMaintainDocsPrompt(projectPath, lastDreamAt, existingDocs) {
|
|
176390
176431
|
const hasAny = existingDocs.architecture || existingDocs.structure;
|
|
176391
176432
|
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.";
|
|
176392
|
-
const modeIntro = hasAny ? `Some docs already exist.
|
|
176433
|
+
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.`;
|
|
176393
176434
|
return `## Task: Maintain Codebase Documentation
|
|
176394
176435
|
|
|
176395
176436
|
**Project:** ${projectPath}
|
|
@@ -176404,15 +176445,16 @@ ${modeIntro}
|
|
|
176404
176445
|
### Process
|
|
176405
176446
|
|
|
176406
176447
|
1. **Check what changed.** ${gitSinceClause}
|
|
176407
|
-
2. **Read existing docs** (if they exist) to understand current
|
|
176448
|
+
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.
|
|
176408
176449
|
3. **Explore the codebase** to verify and update:
|
|
176409
176450
|
- Directory structure: \`find . -type d -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' | head -60\`
|
|
176410
176451
|
- Entry points: \`ls src/index.* src/main.* 2>/dev/null\`
|
|
176411
176452
|
- Key imports: \`grep -r "^import\\|^export" src/ --include="*.ts" | head -80\`
|
|
176412
|
-
4. **
|
|
176453
|
+
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/\`.
|
|
176413
176454
|
|
|
176414
176455
|
### Rules
|
|
176415
176456
|
- **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.
|
|
176457
|
+
- **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.
|
|
176416
176458
|
- **Be prescriptive**: "Use X pattern" not "X pattern is used"
|
|
176417
176459
|
- **Always include file paths** in backticks
|
|
176418
176460
|
- **Write current state only**: no temporal language, no history
|
|
@@ -177817,10 +177859,23 @@ function getAsyncModule() {
|
|
|
177817
177859
|
asyncModulePromise ??= newQuickJSAsyncWASMModuleFromVariant(import_quickjs_singlefile_cjs_release_asyncify.default);
|
|
177818
177860
|
return asyncModulePromise;
|
|
177819
177861
|
}
|
|
177862
|
+
var sandboxRunChain = Promise.resolve();
|
|
177863
|
+
function withSandboxLock(fn) {
|
|
177864
|
+
const run = sandboxRunChain.then(fn, fn);
|
|
177865
|
+
sandboxRunChain = run.then(() => {
|
|
177866
|
+
return;
|
|
177867
|
+
}, () => {
|
|
177868
|
+
return;
|
|
177869
|
+
});
|
|
177870
|
+
return run;
|
|
177871
|
+
}
|
|
177820
177872
|
var DEFAULT_TIMEOUT_MS = 2000;
|
|
177821
177873
|
var DEFAULT_HEAP_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
177822
177874
|
var DEFAULT_STACK_LIMIT_BYTES = 512 * 1024;
|
|
177823
177875
|
async function runCompiledSmartNoteCheck(options) {
|
|
177876
|
+
return withSandboxLock(() => runCompiledSmartNoteCheckLocked(options));
|
|
177877
|
+
}
|
|
177878
|
+
async function runCompiledSmartNoteCheckLocked(options) {
|
|
177824
177879
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
177825
177880
|
const controller = new AbortController;
|
|
177826
177881
|
const externalAbort = () => controller.abort(options.signal?.reason);
|
|
@@ -184652,7 +184707,7 @@ var RECENT_TOOL_SKELETON_WINDOW = 20;
|
|
|
184652
184707
|
function buildReplacementContent(tagId) {
|
|
184653
184708
|
return `[dropped §${tagId}§]`;
|
|
184654
184709
|
}
|
|
184655
|
-
function applyPendingOperations(sessionId, db, targets, protectedTags = 0, preloadedTags, preloadedPendingOps, syntheticPendingOps = []) {
|
|
184710
|
+
function applyPendingOperations(sessionId, db, targets, protectedTags = 0, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set) {
|
|
184656
184711
|
let didMutateMessage = false;
|
|
184657
184712
|
db.transaction(() => {
|
|
184658
184713
|
const tags = preloadedTags ?? getTagsBySession(db, sessionId);
|
|
@@ -184683,7 +184738,15 @@ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, prelo
|
|
|
184683
184738
|
}
|
|
184684
184739
|
let shouldPersistDrop = false;
|
|
184685
184740
|
if (isToolTag) {
|
|
184686
|
-
if (
|
|
184741
|
+
if (editMarkerTagIds.has(pendingOp.tagId)) {
|
|
184742
|
+
const markResult = target?.editMarker?.() ?? "absent";
|
|
184743
|
+
if (markResult === "incomplete" || markResult === "absent") {
|
|
184744
|
+
continue;
|
|
184745
|
+
}
|
|
184746
|
+
didMutateMessage = true;
|
|
184747
|
+
updateTagDropMode(db, sessionId, pendingOp.tagId, "edit_marker");
|
|
184748
|
+
shouldPersistDrop = true;
|
|
184749
|
+
} else if (skeletonWindow.has(pendingOp.tagId)) {
|
|
184687
184750
|
const truncResult = target?.truncate?.() ?? "absent";
|
|
184688
184751
|
if (truncResult === "incomplete" || synthetic && truncResult !== "truncated") {
|
|
184689
184752
|
continue;
|
|
@@ -184728,7 +184791,12 @@ function applyFlushedStatuses(sessionId, db, targets, preloadedTags) {
|
|
|
184728
184791
|
if (tag.status === "dropped") {
|
|
184729
184792
|
const target = targets.get(tag.tagNumber);
|
|
184730
184793
|
if (tag.type === "tool") {
|
|
184731
|
-
if (tag.dropMode === "
|
|
184794
|
+
if (tag.dropMode === "edit_marker") {
|
|
184795
|
+
const markResult = target?.editMarker?.() ?? "absent";
|
|
184796
|
+
if (markResult === "truncated") {
|
|
184797
|
+
didMutateMessage = true;
|
|
184798
|
+
}
|
|
184799
|
+
} else if (tag.dropMode === "truncated") {
|
|
184732
184800
|
const truncResult = target?.truncate?.() ?? "absent";
|
|
184733
184801
|
if (truncResult === "truncated") {
|
|
184734
184802
|
didMutateMessage = true;
|
|
@@ -186879,6 +186947,97 @@ function renderMemoryBlockV2(memories, wrapper = "project-memory", renderOptions
|
|
|
186879
186947
|
`);
|
|
186880
186948
|
}
|
|
186881
186949
|
|
|
186950
|
+
// ../plugin/src/hooks/magic-context/supersession-reclaim.ts
|
|
186951
|
+
var TODOWRITE_KEEP = 1;
|
|
186952
|
+
var CTX_REDUCE_KEEP = 5;
|
|
186953
|
+
var ZERO_VALUE_META_TOOLS = new Set(["bash_status", "bash_kill"]);
|
|
186954
|
+
var CTX_NOTE_ZERO_VALUE_ACTIONS = new Set(["read", "dismiss"]);
|
|
186955
|
+
function buildSupersessionReclaimOps(input) {
|
|
186956
|
+
const realPendingTagIds = new Set((input.pendingOps ?? []).map((op) => op.tagId));
|
|
186957
|
+
const tags = getActiveTagsBySession(input.db, input.sessionId);
|
|
186958
|
+
const toolTags = tags.filter((tag) => tag.type === "tool" && tag.status === "active").sort((left, right) => right.tagNumber - left.tagNumber);
|
|
186959
|
+
const dropTagIds = [];
|
|
186960
|
+
let todowriteSeen = 0;
|
|
186961
|
+
let ctxReduceSeen = 0;
|
|
186962
|
+
for (const tag of toolTags) {
|
|
186963
|
+
const name2 = tag.toolName;
|
|
186964
|
+
if (!name2)
|
|
186965
|
+
continue;
|
|
186966
|
+
let isTarget = false;
|
|
186967
|
+
if (name2 === "todowrite") {
|
|
186968
|
+
todowriteSeen += 1;
|
|
186969
|
+
isTarget = todowriteSeen > TODOWRITE_KEEP;
|
|
186970
|
+
} else if (name2 === "ctx_reduce") {
|
|
186971
|
+
ctxReduceSeen += 1;
|
|
186972
|
+
isTarget = ctxReduceSeen > CTX_REDUCE_KEEP;
|
|
186973
|
+
} else if (ZERO_VALUE_META_TOOLS.has(name2)) {
|
|
186974
|
+
isTarget = true;
|
|
186975
|
+
} else if (name2 === "ctx_note") {
|
|
186976
|
+
const action = input.targets.get(tag.tagNumber)?.readInput?.()?.action;
|
|
186977
|
+
isTarget = typeof action === "string" && CTX_NOTE_ZERO_VALUE_ACTIONS.has(action);
|
|
186978
|
+
}
|
|
186979
|
+
if (isTarget)
|
|
186980
|
+
dropTagIds.push(tag.tagNumber);
|
|
186981
|
+
}
|
|
186982
|
+
const synthetic = [];
|
|
186983
|
+
for (const tagId of dropTagIds) {
|
|
186984
|
+
if (realPendingTagIds.has(tagId))
|
|
186985
|
+
continue;
|
|
186986
|
+
if (input.targets.get(tagId)?.canDrop?.() !== true)
|
|
186987
|
+
continue;
|
|
186988
|
+
synthetic.push({
|
|
186989
|
+
id: 0,
|
|
186990
|
+
sessionId: input.sessionId,
|
|
186991
|
+
tagId,
|
|
186992
|
+
operation: "drop",
|
|
186993
|
+
queuedAt: 0
|
|
186994
|
+
});
|
|
186995
|
+
}
|
|
186996
|
+
return synthetic;
|
|
186997
|
+
}
|
|
186998
|
+
function buildEditSupersessionReclaim(input) {
|
|
186999
|
+
const realPendingTagIds = new Set((input.pendingOps ?? []).map((op) => op.tagId));
|
|
187000
|
+
const tags = getActiveTagsBySession(input.db, input.sessionId);
|
|
187001
|
+
const editTags = tags.filter((tag) => tag.type === "tool" && tag.status === "active" && isEditTool(tag.toolName)).sort((left, right) => right.tagNumber - left.tagNumber);
|
|
187002
|
+
const seenFile = new Set;
|
|
187003
|
+
const ops = [];
|
|
187004
|
+
const editMarkerTagIds = new Set;
|
|
187005
|
+
for (const tag of editTags) {
|
|
187006
|
+
const filePath = readFilePath(input.targets.get(tag.tagNumber));
|
|
187007
|
+
if (!filePath)
|
|
187008
|
+
continue;
|
|
187009
|
+
if (!seenFile.has(filePath)) {
|
|
187010
|
+
seenFile.add(filePath);
|
|
187011
|
+
continue;
|
|
187012
|
+
}
|
|
187013
|
+
if (realPendingTagIds.has(tag.tagNumber))
|
|
187014
|
+
continue;
|
|
187015
|
+
if (input.targets.get(tag.tagNumber)?.canDrop?.() !== true)
|
|
187016
|
+
continue;
|
|
187017
|
+
editMarkerTagIds.add(tag.tagNumber);
|
|
187018
|
+
ops.push({
|
|
187019
|
+
id: 0,
|
|
187020
|
+
sessionId: input.sessionId,
|
|
187021
|
+
tagId: tag.tagNumber,
|
|
187022
|
+
operation: "drop",
|
|
187023
|
+
queuedAt: 0
|
|
187024
|
+
});
|
|
187025
|
+
}
|
|
187026
|
+
return { ops, editMarkerTagIds };
|
|
187027
|
+
}
|
|
187028
|
+
var FILE_PATH_KEYS = ["filePath", "file_path", "path"];
|
|
187029
|
+
function readFilePath(target) {
|
|
187030
|
+
const input = target?.readInput?.();
|
|
187031
|
+
if (!input)
|
|
187032
|
+
return null;
|
|
187033
|
+
for (const key of FILE_PATH_KEYS) {
|
|
187034
|
+
const value = input[key];
|
|
187035
|
+
if (typeof value === "string" && value.length > 0)
|
|
187036
|
+
return value;
|
|
187037
|
+
}
|
|
187038
|
+
return null;
|
|
187039
|
+
}
|
|
187040
|
+
|
|
186882
187041
|
// ../plugin/src/hooks/magic-context/tool-reclaim.ts
|
|
186883
187042
|
function buildSyntheticToolReclaimOps(input) {
|
|
186884
187043
|
const watermark = Math.max(0, input.watermark);
|
|
@@ -187373,9 +187532,35 @@ function buildAggregateTarget(tagId, occurrences) {
|
|
|
187373
187532
|
}
|
|
187374
187533
|
return any2 ? "truncated" : "absent";
|
|
187375
187534
|
},
|
|
187535
|
+
editMarker() {
|
|
187536
|
+
const sentinel = `[dropped §${tagId}§]`;
|
|
187537
|
+
let any2 = false;
|
|
187538
|
+
for (const occ of occurrences) {
|
|
187539
|
+
if (occ.kind === "tool_use") {
|
|
187540
|
+
const input = occ.part.getToolInput?.();
|
|
187541
|
+
if (input) {
|
|
187542
|
+
const next = { ...input };
|
|
187543
|
+
applyEditMarkerToInput(next);
|
|
187544
|
+
if (occ.part.setToolInput?.(next))
|
|
187545
|
+
any2 = true;
|
|
187546
|
+
}
|
|
187547
|
+
} else if (setToolContentOrText(occ.part, sentinel)) {
|
|
187548
|
+
any2 = true;
|
|
187549
|
+
}
|
|
187550
|
+
}
|
|
187551
|
+
return any2 ? "truncated" : "absent";
|
|
187552
|
+
},
|
|
187376
187553
|
canDrop() {
|
|
187377
187554
|
return occurrences.length > 0;
|
|
187378
187555
|
},
|
|
187556
|
+
readInput() {
|
|
187557
|
+
for (const occ of occurrences) {
|
|
187558
|
+
const input = occ.part.getToolInput?.();
|
|
187559
|
+
if (input)
|
|
187560
|
+
return input;
|
|
187561
|
+
}
|
|
187562
|
+
return null;
|
|
187563
|
+
},
|
|
187379
187564
|
message: {
|
|
187380
187565
|
info: { id: messageId, role },
|
|
187381
187566
|
parts: []
|
|
@@ -188760,8 +188945,6 @@ function maybeDeliverChannel2Pi(pi, db, sessionId, deliverAs = "followUp") {
|
|
|
188760
188945
|
|
|
188761
188946
|
// src/detect-recent-commit.ts
|
|
188762
188947
|
var COMMIT_LOOKBACK = 5;
|
|
188763
|
-
var COMMIT_HASH_PATTERN2 = /\b[0-9a-f]{7,12}\b/;
|
|
188764
|
-
var COMMIT_VERB_PATTERN = /\b(commit|committed|cherry-pick|merge|rebas)/i;
|
|
188765
188948
|
function detectRecentCommit(messages) {
|
|
188766
188949
|
let assistantsScanned = 0;
|
|
188767
188950
|
for (let i = messages.length - 1;i >= 0; i--) {
|
|
@@ -188779,8 +188962,7 @@ function detectRecentCommit(messages) {
|
|
|
188779
188962
|
continue;
|
|
188780
188963
|
for (const part of content) {
|
|
188781
188964
|
if (part && typeof part === "object" && "type" in part && part.type === "text" && "text" in part && typeof part.text === "string") {
|
|
188782
|
-
|
|
188783
|
-
if (COMMIT_HASH_PATTERN2.test(text) && COMMIT_VERB_PATTERN.test(text)) {
|
|
188965
|
+
if (textMentionsRecentCommit(part.text)) {
|
|
188784
188966
|
return true;
|
|
188785
188967
|
}
|
|
188786
188968
|
}
|
|
@@ -194458,16 +194640,20 @@ var PARTNER_FRAME_CLOSER_NO_REDUCE = `
|
|
|
194458
194640
|
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.`;
|
|
194459
194641
|
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).`;
|
|
194460
194642
|
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.`;
|
|
194461
|
-
var
|
|
194462
|
-
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".
|
|
194463
|
-
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.
|
|
194464
|
-
${CTX_NOTE_GUIDANCE}
|
|
194465
|
-
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.
|
|
194643
|
+
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.
|
|
194466
194644
|
**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:
|
|
194467
194645
|
- Found a project's source code path after searching → \`ctx_memory(action="write", category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/opencode")\`
|
|
194468
194646
|
- Discovered a non-obvious build/test command → \`ctx_memory(action="write", category="PROJECT_RULES", content="Always use scripts/release.sh for releases")\`
|
|
194469
|
-
- Learned a constraint the hard way → \`ctx_memory(action="write", category="CONSTRAINTS", content="Dashboard Tauri build needs RGBA PNGs, not grayscale")
|
|
194470
|
-
|
|
194647
|
+
- Learned a constraint the hard way → \`ctx_memory(action="write", category="CONSTRAINTS", content="Dashboard Tauri build needs RGBA PNGs, not grayscale")\``;
|
|
194648
|
+
function memoryGuidanceBlock(memoryEnabled) {
|
|
194649
|
+
return memoryEnabled ? `${MEMORY_GUIDANCE}
|
|
194650
|
+
` : "";
|
|
194651
|
+
}
|
|
194652
|
+
var BASE_INTRO = (protectedTags, memoryEnabled) => `Messages and tool outputs are tagged with §N§ identifiers (e.g., §1§, §42§).
|
|
194653
|
+
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".
|
|
194654
|
+
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.
|
|
194655
|
+
${CTX_NOTE_GUIDANCE}
|
|
194656
|
+
${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.
|
|
194471
194657
|
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).
|
|
194472
194658
|
**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:
|
|
194473
194659
|
- Can't remember where a related codebase or dependency lives → \`ctx_search(query="opencode source code path")\`
|
|
@@ -194481,13 +194667,8 @@ NEVER drop large ranges blindly (e.g., "1-50"). Review each tag before deciding.
|
|
|
194481
194667
|
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\`.
|
|
194482
194668
|
NEVER drop assistant text messages unless they are exceptionally large. Your conversation messages are lightweight; only large tool outputs are worth dropping.
|
|
194483
194669
|
Before your turn finishes, consider using \`ctx_reduce\` to drop large tool outputs you no longer need.`;
|
|
194484
|
-
var BASE_INTRO_NO_REDUCE = () => `${CTX_NOTE_GUIDANCE}
|
|
194485
|
-
Use \`
|
|
194486
|
-
**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:
|
|
194487
|
-
- Found a project's source code path after searching → \`ctx_memory(action="write", category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/opencode")\`
|
|
194488
|
-
- Discovered a non-obvious build/test command → \`ctx_memory(action="write", category="PROJECT_RULES", content="Always use scripts/release.sh for releases")\`
|
|
194489
|
-
- Learned a constraint the hard way → \`ctx_memory(action="write", category="CONSTRAINTS", content="Dashboard Tauri build needs RGBA PNGs, not grayscale")\`
|
|
194490
|
-
Use \`ctx_search\` to search across project memories, indexed git commits, and this session's full conversation history (including compacted parts) from one query.
|
|
194670
|
+
var BASE_INTRO_NO_REDUCE = (memoryEnabled) => `${CTX_NOTE_GUIDANCE}
|
|
194671
|
+
${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.
|
|
194491
194672
|
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).
|
|
194492
194673
|
**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:
|
|
194493
194674
|
- Can't remember where a related codebase or dependency lives → \`ctx_search(query="opencode source code path")\`
|
|
@@ -194521,7 +194702,7 @@ Drop silently — do not narrate it. NEVER drop large ranges blindly (e.g., "1-5
|
|
|
194521
194702
|
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.`;
|
|
194522
194703
|
var CAVEMAN_COMPRESSION_WARNING = `
|
|
194523
194704
|
**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.`;
|
|
194524
|
-
function buildMagicContextSection(_agent, protectedTags, ctxReduceEnabled = true, dreamerEnabled = false, temporalAwarenessEnabled = false, cavemanTextCompressionEnabled = false, subagentMode = false, language) {
|
|
194705
|
+
function buildMagicContextSection(_agent, protectedTags, ctxReduceEnabled = true, dreamerEnabled = false, temporalAwarenessEnabled = false, cavemanTextCompressionEnabled = false, subagentMode = false, language, memoryEnabled = true) {
|
|
194525
194706
|
if (subagentMode) {
|
|
194526
194707
|
return `## Magic Context
|
|
194527
194708
|
|
|
@@ -194543,14 +194724,14 @@ ${languageDirective}` : "";
|
|
|
194543
194724
|
${LONG_TERM_PARTNER_FRAME}
|
|
194544
194725
|
${PARTNER_FRAME_CLOSER_NO_REDUCE}
|
|
194545
194726
|
|
|
194546
|
-
${BASE_INTRO_NO_REDUCE()}${smartNoteGuidance}${temporalGuidance}${cavemanWarning}${languageGuidance}`;
|
|
194727
|
+
${BASE_INTRO_NO_REDUCE(memoryEnabled)}${smartNoteGuidance}${temporalGuidance}${cavemanWarning}${languageGuidance}`;
|
|
194547
194728
|
}
|
|
194548
194729
|
return `## Magic Context
|
|
194549
194730
|
|
|
194550
194731
|
${LONG_TERM_PARTNER_FRAME}
|
|
194551
194732
|
${PARTNER_FRAME_CLOSER_REDUCE}
|
|
194552
194733
|
|
|
194553
|
-
${BASE_INTRO(protectedTags)}${smartNoteGuidance}${temporalGuidance}
|
|
194734
|
+
${BASE_INTRO(protectedTags, memoryEnabled)}${smartNoteGuidance}${temporalGuidance}
|
|
194554
194735
|
${GENERIC_SECTION}
|
|
194555
194736
|
|
|
194556
194737
|
Prefer many small targeted operations over one large blanket operation, and keep the working set tidy as routine maintenance.${languageGuidance}`;
|
|
@@ -194565,7 +194746,7 @@ function buildMagicContextBlock(opts) {
|
|
|
194565
194746
|
const includeGuidance = (opts.includeGuidance ?? true) && !existing.includes(MAGIC_CONTEXT_MARKER);
|
|
194566
194747
|
if (!includeGuidance)
|
|
194567
194748
|
return null;
|
|
194568
|
-
return buildMagicContextSection(null, opts.protectedTags ?? 20, opts.ctxReduceEnabled ?? true, opts.dreamerEnabled ?? false, opts.temporalAwarenessEnabled ?? false, opts.cavemanTextCompressionEnabled ?? false, false, opts.language);
|
|
194749
|
+
return buildMagicContextSection(null, opts.protectedTags ?? 20, opts.ctxReduceEnabled ?? true, opts.dreamerEnabled ?? false, opts.temporalAwarenessEnabled ?? false, opts.cavemanTextCompressionEnabled ?? false, false, opts.language, opts.memoryEnabled !== false);
|
|
194569
194750
|
}
|
|
194570
194751
|
var DATE_PATTERN = /Today's date: .+/;
|
|
194571
194752
|
function processSystemPromptForCache(args) {
|
|
@@ -195100,6 +195281,31 @@ function createPiAssistantPart(working, messageIndex, partIndex, markDirty) {
|
|
|
195100
195281
|
}
|
|
195101
195282
|
return { toolName: p.name, inputByteSize, inputTokenCount };
|
|
195102
195283
|
},
|
|
195284
|
+
getToolInput() {
|
|
195285
|
+
const current = working[messageIndex].content;
|
|
195286
|
+
const p = current[partIndex];
|
|
195287
|
+
if (p?.type !== "toolCall")
|
|
195288
|
+
return null;
|
|
195289
|
+
return p.arguments && typeof p.arguments === "object" ? p.arguments : null;
|
|
195290
|
+
},
|
|
195291
|
+
setToolInput(input) {
|
|
195292
|
+
const current = working[messageIndex].content;
|
|
195293
|
+
const p = current[partIndex];
|
|
195294
|
+
if (p?.type !== "toolCall")
|
|
195295
|
+
return false;
|
|
195296
|
+
try {
|
|
195297
|
+
if (JSON.stringify(p.arguments) === JSON.stringify(input))
|
|
195298
|
+
return false;
|
|
195299
|
+
} catch {}
|
|
195300
|
+
const newContent = current.slice();
|
|
195301
|
+
newContent[partIndex] = { ...p, arguments: input };
|
|
195302
|
+
working[messageIndex] = {
|
|
195303
|
+
...working[messageIndex],
|
|
195304
|
+
content: newContent
|
|
195305
|
+
};
|
|
195306
|
+
markDirty(messageIndex);
|
|
195307
|
+
return true;
|
|
195308
|
+
},
|
|
195103
195309
|
replaceWithSentinel(sentinelText) {
|
|
195104
195310
|
const current = working[messageIndex].content;
|
|
195105
195311
|
const existing = current[partIndex];
|
|
@@ -195933,6 +196139,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
195933
196139
|
projectDirectory,
|
|
195934
196140
|
messages: event.messages,
|
|
195935
196141
|
ctxReduceEnabled: options.ctxReduceEnabled,
|
|
196142
|
+
smartDrops: options.smartDrops === true,
|
|
195936
196143
|
protectedTags: options.protectedTags ?? 20,
|
|
195937
196144
|
heuristics: options.heuristics,
|
|
195938
196145
|
emergencyCeilingTokens,
|
|
@@ -196723,9 +196930,38 @@ async function runPipeline(args) {
|
|
|
196723
196930
|
watermark: reclaimMeta.toolReclaimWatermark ?? 0,
|
|
196724
196931
|
pendingOps
|
|
196725
196932
|
});
|
|
196933
|
+
const editMarkerTagIds = new Set;
|
|
196934
|
+
if (args.smartDrops) {
|
|
196935
|
+
const selectedIds = new Set(syntheticPendingOps.map((op) => op.tagId));
|
|
196936
|
+
const supersessionOps = buildSupersessionReclaimOps({
|
|
196937
|
+
db: args.db,
|
|
196938
|
+
sessionId: args.sessionId,
|
|
196939
|
+
targets,
|
|
196940
|
+
pendingOps
|
|
196941
|
+
});
|
|
196942
|
+
for (const op of supersessionOps) {
|
|
196943
|
+
if (!selectedIds.has(op.tagId)) {
|
|
196944
|
+
syntheticPendingOps.push(op);
|
|
196945
|
+
selectedIds.add(op.tagId);
|
|
196946
|
+
}
|
|
196947
|
+
}
|
|
196948
|
+
const editReclaim = buildEditSupersessionReclaim({
|
|
196949
|
+
db: args.db,
|
|
196950
|
+
sessionId: args.sessionId,
|
|
196951
|
+
targets,
|
|
196952
|
+
pendingOps
|
|
196953
|
+
});
|
|
196954
|
+
for (const op of editReclaim.ops) {
|
|
196955
|
+
if (!selectedIds.has(op.tagId)) {
|
|
196956
|
+
syntheticPendingOps.push(op);
|
|
196957
|
+
selectedIds.add(op.tagId);
|
|
196958
|
+
editMarkerTagIds.add(op.tagId);
|
|
196959
|
+
}
|
|
196960
|
+
}
|
|
196961
|
+
}
|
|
196726
196962
|
autoReclaimTargetCount = syntheticPendingOps.length;
|
|
196727
196963
|
if (syntheticPendingOps.length > 0) {
|
|
196728
|
-
autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, targets, args.protectedTags, undefined, [], syntheticPendingOps);
|
|
196964
|
+
autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, targets, args.protectedTags, undefined, [], syntheticPendingOps, editMarkerTagIds);
|
|
196729
196965
|
if (autoReclaimDidMutate) {
|
|
196730
196966
|
droppedCount += syntheticPendingOps.length;
|
|
196731
196967
|
autoReclaimDidMutateThisPass = true;
|
|
@@ -199451,7 +199687,7 @@ function formatThresholdPercent(value) {
|
|
|
199451
199687
|
// package.json
|
|
199452
199688
|
var package_default = {
|
|
199453
199689
|
name: "@cortexkit/pi-magic-context",
|
|
199454
|
-
version: "0.
|
|
199690
|
+
version: "0.29.0",
|
|
199455
199691
|
type: "module",
|
|
199456
199692
|
description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
|
|
199457
199693
|
main: "dist/index.js",
|
|
@@ -205715,6 +205951,7 @@ async function src_default2(pi) {
|
|
|
205715
205951
|
db,
|
|
205716
205952
|
ensureProjectRegistered: ensureProjectRegisteredFromPiDirectory,
|
|
205717
205953
|
allowDreamerActions: false,
|
|
205954
|
+
memoryToolEnabled: true,
|
|
205718
205955
|
ctxReduceEnabled: config2.ctx_reduce_enabled === true,
|
|
205719
205956
|
protectedTags: config2.protected_tags ?? 20,
|
|
205720
205957
|
dreamerEnabled: isDreamerRunnable(config2)
|
|
@@ -205734,6 +205971,7 @@ async function src_default2(pi) {
|
|
|
205734
205971
|
const buildContextOptions = (cfg, hist, auto) => ({
|
|
205735
205972
|
db: database,
|
|
205736
205973
|
ctxReduceEnabled: cfg.ctx_reduce_enabled,
|
|
205974
|
+
smartDrops: cfg.smart_drops === true,
|
|
205737
205975
|
protectedTags: cfg.protected_tags ?? 20,
|
|
205738
205976
|
heuristics: {
|
|
205739
205977
|
caveman: cfg.ctx_reduce_enabled === false && cfg.caveman_text_compression ? {
|
package/dist/subagent-entry.js
CHANGED
|
@@ -9923,6 +9923,17 @@ function runMigrations(db) {
|
|
|
9923
9923
|
log(`[migrations] schema version now: ${MIGRATIONS[MIGRATIONS.length - 1].version}`);
|
|
9924
9924
|
}
|
|
9925
9925
|
|
|
9926
|
+
// ../plugin/src/shared/commit-detection.ts
|
|
9927
|
+
var HASH_HEX = "[0-9a-f]{7,12}";
|
|
9928
|
+
var COMMIT_HASH_TEST_PATTERN = new RegExp(`\\b${HASH_HEX}\\b`, "i");
|
|
9929
|
+
var COMMIT_VERB_PATTERN = /\b(?:commit(?:ted|ting|s)?|cherry-?pick(?:ed|ing|s)?|merge[ds]?|merging|rebas(?:e|ed|es|ing))\b/i;
|
|
9930
|
+
function textMentionsRecentCommit(text) {
|
|
9931
|
+
return COMMIT_HASH_TEST_PATTERN.test(text) && COMMIT_VERB_PATTERN.test(text);
|
|
9932
|
+
}
|
|
9933
|
+
function createCommitHashExtractPattern() {
|
|
9934
|
+
return new RegExp(`\`?\\b(${HASH_HEX})\\b\`?`, "gi");
|
|
9935
|
+
}
|
|
9936
|
+
|
|
9926
9937
|
// ../plugin/src/shared/internal-initiator-marker.ts
|
|
9927
9938
|
var OMO_INTERNAL_INITIATOR_MARKER = "<!-- OMO_INTERNAL_INITIATOR -->";
|
|
9928
9939
|
|
|
@@ -142374,8 +142385,6 @@ var decoder = {
|
|
|
142374
142385
|
};
|
|
142375
142386
|
|
|
142376
142387
|
// ../plugin/src/hooks/magic-context/read-session-formatting.ts
|
|
142377
|
-
var COMMIT_HASH_PATTERN = /`?\b([0-9a-f]{6,12})\b`?/gi;
|
|
142378
|
-
var COMMIT_HINT_PATTERN = /\b(commit(?:ted)?|cherry-?pick(?:ed)?|hash(?:es)?|sha)\b/i;
|
|
142379
142388
|
var MAX_COMMITS_PER_BLOCK = 5;
|
|
142380
142389
|
function hasMeaningfulUserText(parts) {
|
|
142381
142390
|
for (const part of parts) {
|
|
@@ -142479,7 +142488,7 @@ function formatBlock(block) {
|
|
|
142479
142488
|
function extractCommitHashes(text) {
|
|
142480
142489
|
const hashes = [];
|
|
142481
142490
|
const seen = new Set;
|
|
142482
|
-
for (const match of text.matchAll(
|
|
142491
|
+
for (const match of text.matchAll(createCommitHashExtractPattern())) {
|
|
142483
142492
|
const hash = match[1]?.toLowerCase();
|
|
142484
142493
|
if (!hash || seen.has(hash))
|
|
142485
142494
|
continue;
|
|
@@ -142492,10 +142501,10 @@ function extractCommitHashes(text) {
|
|
|
142492
142501
|
}
|
|
142493
142502
|
function compactTextForSummary(text, role) {
|
|
142494
142503
|
const commitHashes = role === "assistant" ? extractCommitHashes(text) : [];
|
|
142495
|
-
if (commitHashes.length === 0 || !
|
|
142504
|
+
if (commitHashes.length === 0 || !COMMIT_VERB_PATTERN.test(text)) {
|
|
142496
142505
|
return { text, commitHashes };
|
|
142497
142506
|
}
|
|
142498
|
-
const withoutHashes = text.replace(
|
|
142507
|
+
const withoutHashes = text.replace(createCommitHashExtractPattern(), "").replace(/\(\s*\)/g, "").replace(/\s+,/g, ",").replace(/,\s*,+/g, ", ").replace(/\s{2,}/g, " ").replace(/\s+([,.;:])/g, "$1").trim();
|
|
142499
142508
|
return {
|
|
142500
142509
|
text: withoutHashes.length > 0 ? withoutHashes : text,
|
|
142501
142510
|
commitHashes
|
|
@@ -159667,6 +159676,7 @@ var MagicContextConfigSchema = exports_external.object({
|
|
|
159667
159676
|
}).describe("Embedding provider configuration"),
|
|
159668
159677
|
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).'),
|
|
159669
159678
|
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."),
|
|
159679
|
+
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."),
|
|
159670
159680
|
caveman_text_compression: exports_external.object({
|
|
159671
159681
|
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%)."),
|
|
159672
159682
|
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.")
|
|
@@ -163577,6 +163587,36 @@ function isRecord(value) {
|
|
|
163577
163587
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
163578
163588
|
}
|
|
163579
163589
|
|
|
163590
|
+
// ../plugin/src/hooks/magic-context/edit-marker.ts
|
|
163591
|
+
var TRUNCATION_SENTINEL = "...[truncated]";
|
|
163592
|
+
var EDIT_REGION_HINT_LEN = 40;
|
|
163593
|
+
var PATH_KEYS = new Set(["filePath", "file_path", "path"]);
|
|
163594
|
+
var DIFF_KEYS = new Set(["oldString", "newString", "content", "old_string", "new_string"]);
|
|
163595
|
+
function safeSlice(str, maxLen) {
|
|
163596
|
+
if (str.length <= maxLen)
|
|
163597
|
+
return str;
|
|
163598
|
+
const lastCharCode = str.charCodeAt(maxLen - 1);
|
|
163599
|
+
if (lastCharCode >= 55296 && lastCharCode <= 56319) {
|
|
163600
|
+
return str.slice(0, maxLen - 1);
|
|
163601
|
+
}
|
|
163602
|
+
return str.slice(0, maxLen);
|
|
163603
|
+
}
|
|
163604
|
+
function isEditTool(name2) {
|
|
163605
|
+
return name2 === "edit" || name2 === "write";
|
|
163606
|
+
}
|
|
163607
|
+
function applyEditMarkerToInput(input) {
|
|
163608
|
+
for (const key of Object.keys(input)) {
|
|
163609
|
+
if (PATH_KEYS.has(key))
|
|
163610
|
+
continue;
|
|
163611
|
+
const value = input[key];
|
|
163612
|
+
if (typeof value !== "string" || !DIFF_KEYS.has(key))
|
|
163613
|
+
continue;
|
|
163614
|
+
if (value.endsWith(TRUNCATION_SENTINEL))
|
|
163615
|
+
continue;
|
|
163616
|
+
input[key] = value.length > EDIT_REGION_HINT_LEN ? `${safeSlice(value, EDIT_REGION_HINT_LEN)}${TRUNCATION_SENTINEL}` : value;
|
|
163617
|
+
}
|
|
163618
|
+
}
|
|
163619
|
+
|
|
163580
163620
|
// ../plugin/src/hooks/magic-context/tool-drop-target.ts
|
|
163581
163621
|
var IGNORE_PART_TYPES = new Set([
|
|
163582
163622
|
"thinking",
|
|
@@ -171706,7 +171746,7 @@ function toTagEntry(row) {
|
|
|
171706
171746
|
messageId: row.message_id,
|
|
171707
171747
|
type,
|
|
171708
171748
|
status,
|
|
171709
|
-
dropMode: row.drop_mode === "truncated" ? "truncated" : "full",
|
|
171749
|
+
dropMode: row.drop_mode === "truncated" ? "truncated" : row.drop_mode === "edit_marker" ? "edit_marker" : "full",
|
|
171710
171750
|
toolName: row.tool_name ?? null,
|
|
171711
171751
|
inputByteSize: row.input_byte_size ?? 0,
|
|
171712
171752
|
byteSize: row.byte_size,
|
package/package.json
CHANGED