@cortexkit/opencode-magic-context 0.33.0 → 0.33.1
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/config/schema/magic-context.d.ts +62 -22
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/{conflict-warning-hook-bwa99a04.js → conflict-warning-hook-n48c783v.js} +1 -1
- package/dist/features/magic-context/compaction-marker.d.ts +49 -0
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts +0 -2
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-registry.d.ts +0 -1
- package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/index.d.ts +2 -2
- package/dist/features/magic-context/git-commits/index.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts +0 -2
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/storage-git-commits.d.ts +0 -13
- package/dist/features/magic-context/git-commits/storage-git-commits.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts +1 -2
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/features/magic-context/memory/memory-migration.d.ts +0 -6
- package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +0 -1
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory.d.ts +1 -6
- package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
- package/dist/features/magic-context/memory/verification-paths.d.ts +0 -1
- package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/mural/storage-mural.d.ts +0 -1
- package/dist/features/magic-context/mural/storage-mural.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts +16 -2
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/capabilities.d.ts +0 -2
- package/dist/features/magic-context/smart-notes/capabilities.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/compiler.d.ts +0 -1
- package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/types.d.ts +0 -16
- package/dist/features/magic-context/smart-notes/types.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +0 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +0 -2
- package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/types.d.ts +0 -3
- package/dist/hooks/auto-update-checker/types.d.ts.map +1 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts +0 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
- package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts +49 -0
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-parser.d.ts +12 -0
- package/dist/hooks/magic-context/compartment-parser.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-mapping.d.ts +0 -12
- package/dist/hooks/magic-context/compartment-runner-mapping.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/historian-prompt.generated.d.ts +1 -1
- package/dist/hooks/magic-context/historian-prompt.generated.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +9 -0
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/sentinel.d.ts +39 -0
- package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-drop-target.d.ts +19 -0
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/{index-kxz4tn6m.js → index-56yjaeb2.js} +56 -4
- package/dist/{index-h86twgsp.js → index-c2gahrks.js} +516 -177
- package/dist/{index-bmkea2dq.js → index-ey1bc14z.js} +36 -26
- package/dist/{index-k5y60ymm.js → index-xyaekybw.js} +21 -2
- package/dist/index.js +83 -23
- package/dist/plugin/hooks/create-session-hooks.d.ts +8 -8
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/{recomp-orchestrator-yh7pepvx.js → recomp-orchestrator-2yb2hfh2.js} +2 -3
- package/dist/shared/conflict-detector.d.ts.map +1 -1
- package/dist/shared/sqlite.d.ts +9 -4
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/{storage-meta-session-1phy0b1z.js → storage-meta-session-td6bwtky.js} +1 -1
- package/dist/{task-config-dn9k9szr.js → task-config-5nx3qfz8.js} +1 -2
- package/package.json +2 -2
- package/src/shared/conflict-detector.test.ts +130 -1
- package/src/shared/conflict-detector.ts +34 -2
- package/src/shared/sqlite.ts +13 -33
- package/dist/config/schema.d.ts +0 -3
- package/dist/config/schema.d.ts.map +0 -1
- package/dist/features/magic-context/plugin-messages.d.ts +0 -75
- package/dist/features/magic-context/plugin-messages.d.ts.map +0 -1
- package/dist/hooks/magic-context/compartment-runner-state-xml.d.ts +0 -21
- package/dist/hooks/magic-context/compartment-runner-state-xml.d.ts.map +0 -1
- package/dist/index-anhrfygk.js +0 -57
- package/dist/shared/opencode-compaction-detector.d.ts +0 -2
- package/dist/shared/opencode-compaction-detector.d.ts.map +0 -1
- package/dist/shared/transcript-opencode.d.ts +0 -71
- package/dist/shared/transcript-opencode.d.ts.map +0 -1
- package/dist/tools/index.d.ts +0 -6
- package/dist/tools/index.d.ts.map +0 -1
- package/src/shared/opencode-compaction-detector.test.ts +0 -239
- package/src/shared/opencode-compaction-detector.ts +0 -81
- package/src/shared/transcript-opencode.ts +0 -302
|
@@ -2,9 +2,6 @@ import {
|
|
|
2
2
|
deriveTriggerBudget,
|
|
3
3
|
modelSupportsVision
|
|
4
4
|
} from "./index-63dq2g4d.js";
|
|
5
|
-
import {
|
|
6
|
-
AGENTIC_DREAM_TASKS
|
|
7
|
-
} from "./index-anhrfygk.js";
|
|
8
5
|
import {
|
|
9
6
|
parseProviderModel
|
|
10
7
|
} from "./index-td9depx5.js";
|
|
@@ -32,10 +29,9 @@ import {
|
|
|
32
29
|
persistCachedM0,
|
|
33
30
|
readRawSessionMessages,
|
|
34
31
|
readSessionChunk,
|
|
35
|
-
registerPrivilegedWriter,
|
|
36
32
|
updateSessionMeta,
|
|
37
33
|
withPrivilegedWriter
|
|
38
|
-
} from "./index-
|
|
34
|
+
} from "./index-ey1bc14z.js";
|
|
39
35
|
import {
|
|
40
36
|
log,
|
|
41
37
|
sessionLog
|
|
@@ -1955,6 +1951,184 @@ function pullMemoryMirrorOnce(args) {
|
|
|
1955
1951
|
mirrorFlights.set(args.module, flight);
|
|
1956
1952
|
return flight;
|
|
1957
1953
|
}
|
|
1954
|
+
// src/hooks/magic-context/compartment-parser.ts
|
|
1955
|
+
var COMPARTMENT_REGEX = /<compartment\s+([^>]*?)\s*>(.*?)<\/compartment>/gs;
|
|
1956
|
+
var ATTR_START_REGEX = /\bstart="(\d+)"/;
|
|
1957
|
+
var ATTR_END_REGEX = /\bend="(\d+)"/;
|
|
1958
|
+
var ATTR_TITLE_REGEX = /\btitle="([^"]*)"/;
|
|
1959
|
+
var ATTR_EPISODE_REGEX = /\bepisode_type="([^"]*)"/;
|
|
1960
|
+
var ATTR_IMPORTANCE_REGEX = /\bimportance="(\d+)"/;
|
|
1961
|
+
function makeTierOpenRegex(n) {
|
|
1962
|
+
return new RegExp(`<p${n}\\s*(/?)>`);
|
|
1963
|
+
}
|
|
1964
|
+
var TIER_OPEN_REGEXES = [
|
|
1965
|
+
makeTierOpenRegex(1),
|
|
1966
|
+
makeTierOpenRegex(2),
|
|
1967
|
+
makeTierOpenRegex(3),
|
|
1968
|
+
makeTierOpenRegex(4)
|
|
1969
|
+
];
|
|
1970
|
+
var TIER_CLOSE_ANY_REGEX = /<\/p\d/;
|
|
1971
|
+
var TIER_OPEN_ANY_REGEX = /<p\d/;
|
|
1972
|
+
var CATEGORY_BLOCK_REGEX = /<(PROJECT_RULES|ARCHITECTURE|CONSTRAINTS|CONFIG_VALUES|NAMING)>(.*?)<\/\1>/gs;
|
|
1973
|
+
var FACT_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
|
|
1974
|
+
var UNPROCESSED_REGEX = /<unprocessed_from>(\d+)<\/unprocessed_from>/;
|
|
1975
|
+
var USER_OBSERVATIONS_REGEX = /<user_observations>(.*?)<\/user_observations>/s;
|
|
1976
|
+
var USER_OBS_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
|
|
1977
|
+
var PRIMER_CANDIDATES_REGEX = /<primer_candidates>(.*?)<\/primer_candidates>/s;
|
|
1978
|
+
var PRIMER_ELEMENT_REGEX = /<primer\s+at_compartment="(\d+)"\s*>(.*?)<\/primer>/gs;
|
|
1979
|
+
var PRIMER_ITEM_REGEX = /^\s*(?:\*|-|\d+\.)\s*(.+)$/gm;
|
|
1980
|
+
var FACTS_BLOCK_REGEX = /<facts>(.*?)<\/facts>/s;
|
|
1981
|
+
var EVENTS_BLOCK_REGEX = /<events>(.*?)<\/events>/s;
|
|
1982
|
+
var EVENT_ELEMENT_REGEX = /<([a-z_]+)\s+at_compartment="(\d+)"\s*>(.*?)<\/\1>/gs;
|
|
1983
|
+
var EVENT_FIELD_REGEX = /<([a-z_]+)\s*>(.*?)<\/\1>/gs;
|
|
1984
|
+
function extractTier(inner, index) {
|
|
1985
|
+
const openMatch = TIER_OPEN_REGEXES[index].exec(inner);
|
|
1986
|
+
if (!openMatch)
|
|
1987
|
+
return;
|
|
1988
|
+
if (openMatch[1] === "/")
|
|
1989
|
+
return "";
|
|
1990
|
+
const rest = inner.slice(openMatch.index + openMatch[0].length);
|
|
1991
|
+
const closeAt = rest.search(TIER_CLOSE_ANY_REGEX);
|
|
1992
|
+
let body = closeAt === -1 ? rest : rest.slice(0, closeAt);
|
|
1993
|
+
const openInside = body.search(TIER_OPEN_ANY_REGEX);
|
|
1994
|
+
if (openInside !== -1)
|
|
1995
|
+
body = body.slice(0, openInside);
|
|
1996
|
+
return unescapeXml(body.trim());
|
|
1997
|
+
}
|
|
1998
|
+
function extractTiersFromInner(inner) {
|
|
1999
|
+
return {
|
|
2000
|
+
p1: extractTier(inner, 0),
|
|
2001
|
+
p2: extractTier(inner, 1),
|
|
2002
|
+
p3: extractTier(inner, 2),
|
|
2003
|
+
p4: extractTier(inner, 3)
|
|
2004
|
+
};
|
|
2005
|
+
}
|
|
2006
|
+
function parseCompartmentOutput(text) {
|
|
2007
|
+
const compartments = [];
|
|
2008
|
+
const facts = [];
|
|
2009
|
+
for (const match of text.matchAll(COMPARTMENT_REGEX)) {
|
|
2010
|
+
const attrs = match[1];
|
|
2011
|
+
const inner = match[2];
|
|
2012
|
+
const startMatch = attrs.match(ATTR_START_REGEX);
|
|
2013
|
+
const endMatch = attrs.match(ATTR_END_REGEX);
|
|
2014
|
+
const titleMatch = attrs.match(ATTR_TITLE_REGEX);
|
|
2015
|
+
if (!startMatch || !endMatch || !titleMatch)
|
|
2016
|
+
continue;
|
|
2017
|
+
const startMessage = parseInt(startMatch[1], 10);
|
|
2018
|
+
const endMessage = parseInt(endMatch[1], 10);
|
|
2019
|
+
const title = unescapeXml(titleMatch[1]);
|
|
2020
|
+
if (Number.isNaN(startMessage) || Number.isNaN(endMessage) || !title)
|
|
2021
|
+
continue;
|
|
2022
|
+
const episodeMatch = attrs.match(ATTR_EPISODE_REGEX);
|
|
2023
|
+
const importanceMatch = attrs.match(ATTR_IMPORTANCE_REGEX);
|
|
2024
|
+
const episodeType = episodeMatch ? unescapeXml(episodeMatch[1]) : undefined;
|
|
2025
|
+
const importance = importanceMatch ? parseInt(importanceMatch[1], 10) : undefined;
|
|
2026
|
+
const p1 = extractTier(inner, 0);
|
|
2027
|
+
if (typeof p1 === "string" && p1.length > 0) {
|
|
2028
|
+
const p2 = extractTier(inner, 1);
|
|
2029
|
+
const p3 = extractTier(inner, 2);
|
|
2030
|
+
const p4 = extractTier(inner, 3);
|
|
2031
|
+
compartments.push({
|
|
2032
|
+
startMessage,
|
|
2033
|
+
endMessage,
|
|
2034
|
+
title,
|
|
2035
|
+
content: p1,
|
|
2036
|
+
p1,
|
|
2037
|
+
p2: typeof p2 === "string" ? p2 : p1,
|
|
2038
|
+
p3: typeof p3 === "string" ? p3 : typeof p2 === "string" ? p2 : p1,
|
|
2039
|
+
p4: typeof p4 === "string" ? p4 : "",
|
|
2040
|
+
importance,
|
|
2041
|
+
episodeType
|
|
2042
|
+
});
|
|
2043
|
+
continue;
|
|
2044
|
+
}
|
|
2045
|
+
const content = unescapeXml(inner.trim());
|
|
2046
|
+
if (content) {
|
|
2047
|
+
compartments.push({
|
|
2048
|
+
startMessage,
|
|
2049
|
+
endMessage,
|
|
2050
|
+
title,
|
|
2051
|
+
content,
|
|
2052
|
+
importance,
|
|
2053
|
+
episodeType
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
const factsBlockMatch = text.match(FACTS_BLOCK_REGEX);
|
|
2058
|
+
const factsScope = factsBlockMatch ? factsBlockMatch[1] : text.replace(EVENTS_BLOCK_REGEX, "").replace(/<compartment\s+[^>]*?\s*>.*?<\/compartment>/gs, "");
|
|
2059
|
+
for (const categoryMatch of factsScope.matchAll(CATEGORY_BLOCK_REGEX)) {
|
|
2060
|
+
const category = categoryMatch[1];
|
|
2061
|
+
const blockContent = categoryMatch[2];
|
|
2062
|
+
for (const itemMatch of blockContent.matchAll(FACT_ITEM_REGEX)) {
|
|
2063
|
+
const content = unescapeXml(itemMatch[1].trim());
|
|
2064
|
+
if (content) {
|
|
2065
|
+
facts.push({ category, content });
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
const unprocessedMatch = text.match(UNPROCESSED_REGEX);
|
|
2070
|
+
const unprocessedFrom = unprocessedMatch ? parseInt(unprocessedMatch[1], 10) : null;
|
|
2071
|
+
const userObservations = [];
|
|
2072
|
+
const userObsMatch = text.match(USER_OBSERVATIONS_REGEX);
|
|
2073
|
+
if (userObsMatch) {
|
|
2074
|
+
for (const itemMatch of userObsMatch[1].matchAll(USER_OBS_ITEM_REGEX)) {
|
|
2075
|
+
const obs = unescapeXml(itemMatch[1].trim());
|
|
2076
|
+
if (obs)
|
|
2077
|
+
userObservations.push(obs);
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
const primerCandidates = [];
|
|
2081
|
+
const primerMatch = text.match(PRIMER_CANDIDATES_REGEX);
|
|
2082
|
+
if (primerMatch) {
|
|
2083
|
+
const block = primerMatch[1];
|
|
2084
|
+
let sawElement = false;
|
|
2085
|
+
for (const el of block.matchAll(PRIMER_ELEMENT_REGEX)) {
|
|
2086
|
+
sawElement = true;
|
|
2087
|
+
const question = unescapeXml(el[2].trim());
|
|
2088
|
+
if (question) {
|
|
2089
|
+
primerCandidates.push({
|
|
2090
|
+
question,
|
|
2091
|
+
originCompartmentIndex: Number.parseInt(el[1], 10)
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
if (!sawElement) {
|
|
2096
|
+
for (const itemMatch of block.matchAll(PRIMER_ITEM_REGEX)) {
|
|
2097
|
+
const question = unescapeXml(itemMatch[1].trim());
|
|
2098
|
+
if (question)
|
|
2099
|
+
primerCandidates.push({ question });
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
const events = parseEvents(text);
|
|
2104
|
+
compartments.sort((a, b) => a.startMessage - b.startMessage);
|
|
2105
|
+
return { compartments, facts, events, unprocessedFrom, userObservations, primerCandidates };
|
|
2106
|
+
}
|
|
2107
|
+
function parseEvents(text) {
|
|
2108
|
+
const blockMatch = text.match(EVENTS_BLOCK_REGEX);
|
|
2109
|
+
if (!blockMatch)
|
|
2110
|
+
return [];
|
|
2111
|
+
const block = blockMatch[1];
|
|
2112
|
+
const events = [];
|
|
2113
|
+
for (const elMatch of block.matchAll(EVENT_ELEMENT_REGEX)) {
|
|
2114
|
+
const kind = elMatch[1];
|
|
2115
|
+
const atRaw = parseInt(elMatch[2], 10);
|
|
2116
|
+
const atCompartment = Number.isNaN(atRaw) ? null : atRaw;
|
|
2117
|
+
const fields = {};
|
|
2118
|
+
for (const fieldMatch of elMatch[3].matchAll(EVENT_FIELD_REGEX)) {
|
|
2119
|
+
const name = fieldMatch[1];
|
|
2120
|
+
const value = unescapeXml(fieldMatch[2].trim());
|
|
2121
|
+
if (value)
|
|
2122
|
+
fields[name] = value;
|
|
2123
|
+
}
|
|
2124
|
+
events.push({ kind, atCompartment, fields });
|
|
2125
|
+
}
|
|
2126
|
+
return events;
|
|
2127
|
+
}
|
|
2128
|
+
function unescapeXml(s) {
|
|
2129
|
+
return s.replace(/&/g, "&").replace(/'/g, "'").replace(/"/g, '"').replace(/</g, "<").replace(/>/g, ">");
|
|
2130
|
+
}
|
|
2131
|
+
|
|
1958
2132
|
// src/features/magic-context/storage-schema-helpers.ts
|
|
1959
2133
|
function ensureColumn(db, table, column, definition) {
|
|
1960
2134
|
if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_"'(),[\]\s]+$/i.test(definition)) {
|
|
@@ -2704,15 +2878,38 @@ function isSqliteLockError(error) {
|
|
|
2704
2878
|
function tableExists2(db, name) {
|
|
2705
2879
|
return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name));
|
|
2706
2880
|
}
|
|
2881
|
+
function healMismatchedTierClose(db, table, hasLegacy) {
|
|
2882
|
+
if (!tableExists2(db, table))
|
|
2883
|
+
return;
|
|
2884
|
+
const columns = new Set(db.prepare(`PRAGMA table_info(${table})`).all().map((row) => row.name));
|
|
2885
|
+
for (const required of ["content", "p1", "p2", "p3", "p4"]) {
|
|
2886
|
+
if (!columns.has(required))
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
if (hasLegacy && !columns.has("legacy"))
|
|
2890
|
+
return;
|
|
2891
|
+
const predicate = hasLegacy ? "legacy = 1 AND p1 IS NULL AND content LIKE '%<p1%'" : "p1 IS NULL AND content LIKE '%<p1%'";
|
|
2892
|
+
const rows = db.prepare(`SELECT id, content FROM ${table} WHERE ${predicate}`).all();
|
|
2893
|
+
const update = db.prepare(`UPDATE ${table} SET p1 = ?, p2 = ?, p3 = ?, p4 = ?${hasLegacy ? ", legacy = 0" : ""} WHERE id = ?`);
|
|
2894
|
+
for (const row of rows) {
|
|
2895
|
+
const tiers = extractTiersFromInner(row.content);
|
|
2896
|
+
if (typeof tiers.p1 !== "string" || tiers.p1.length === 0)
|
|
2897
|
+
continue;
|
|
2898
|
+
const p1 = tiers.p1;
|
|
2899
|
+
const p2 = typeof tiers.p2 === "string" ? tiers.p2 : p1;
|
|
2900
|
+
const p3 = typeof tiers.p3 === "string" ? tiers.p3 : p2;
|
|
2901
|
+
const p4 = typeof tiers.p4 === "string" ? tiers.p4 : "";
|
|
2902
|
+
update.run(p1, p2, p3, p4, row.id);
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2707
2905
|
function assertForeignKeyIntegrity(db, table) {
|
|
2708
2906
|
const rows = (table ? db.prepare(`PRAGMA foreign_key_check(${table})`) : db.prepare("PRAGMA foreign_key_check")).all();
|
|
2709
2907
|
if (rows.length > 0) {
|
|
2710
2908
|
throw new Error(`foreign_key_check failed after embedding table rebuild${table ? ` (${table})` : ""} (${rows.length} violation(s))`);
|
|
2711
2909
|
}
|
|
2712
2910
|
}
|
|
2713
|
-
function authorityPrivilegeCheck(
|
|
2714
|
-
|
|
2715
|
-
return typeof native.function === "function" || typeof native.createFunction === "function" ? "mc_privileged_writer() = 0" : "COALESCE((SELECT enabled FROM context_privilege_state WHERE id = 1), 0) = 0";
|
|
2911
|
+
function authorityPrivilegeCheck() {
|
|
2912
|
+
return "COALESCE((SELECT enabled FROM context_privilege_state WHERE id = 1), 0) = 0";
|
|
2716
2913
|
}
|
|
2717
2914
|
function managedAuthorityNoteRow(row) {
|
|
2718
2915
|
return `(
|
|
@@ -2731,7 +2928,7 @@ function managedAuthorityNoteRow(row) {
|
|
|
2731
2928
|
)`;
|
|
2732
2929
|
}
|
|
2733
2930
|
function installLatestAuthorityTriggers(db) {
|
|
2734
|
-
const privilegeCheck = authorityPrivilegeCheck(
|
|
2931
|
+
const privilegeCheck = authorityPrivilegeCheck();
|
|
2735
2932
|
if (tableExists2(db, "memories")) {
|
|
2736
2933
|
db.exec(`
|
|
2737
2934
|
DROP TRIGGER IF EXISTS memories_authority_guard_insert;
|
|
@@ -4657,6 +4854,21 @@ var MIGRATIONS = [
|
|
|
4657
4854
|
ON memory_mutation_log(project_path, target_memory_id, id);
|
|
4658
4855
|
`);
|
|
4659
4856
|
}
|
|
4857
|
+
},
|
|
4858
|
+
{
|
|
4859
|
+
version: 70,
|
|
4860
|
+
description: "heal legacy compartments stranded by mismatched tier closing tags (issue #246)",
|
|
4861
|
+
up(db) {
|
|
4862
|
+
healMismatchedTierClose(db, "compartments", true);
|
|
4863
|
+
healMismatchedTierClose(db, "recomp_compartments", false);
|
|
4864
|
+
}
|
|
4865
|
+
},
|
|
4866
|
+
{
|
|
4867
|
+
version: 71,
|
|
4868
|
+
description: "rebuild authority guard triggers to the durable state-table form (issue #253)",
|
|
4869
|
+
up(db) {
|
|
4870
|
+
installLatestAuthorityTriggers(db);
|
|
4871
|
+
}
|
|
4660
4872
|
}
|
|
4661
4873
|
];
|
|
4662
4874
|
var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
@@ -5286,7 +5498,7 @@ var lastSchemaFenceRejection = null;
|
|
|
5286
5498
|
function getSchemaFenceRejection() {
|
|
5287
5499
|
return lastSchemaFenceRejection;
|
|
5288
5500
|
}
|
|
5289
|
-
var LATEST_SUPPORTED_VERSION =
|
|
5501
|
+
var LATEST_SUPPORTED_VERSION = 71;
|
|
5290
5502
|
var PERMISSIONS_ENFORCEABLE = process.platform !== "win32";
|
|
5291
5503
|
function ensureSecureStorageDir(dir) {
|
|
5292
5504
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
@@ -6551,7 +6763,6 @@ function openDatabase(dbPathOrOptions) {
|
|
|
6551
6763
|
if (!enforceSchemaFence(existing, dbPath, latestSupportedVersion)) {
|
|
6552
6764
|
return null;
|
|
6553
6765
|
}
|
|
6554
|
-
registerPrivilegedWriter(existing);
|
|
6555
6766
|
if (!persistenceByDatabase.has(existing)) {
|
|
6556
6767
|
persistenceByDatabase.set(existing, true);
|
|
6557
6768
|
}
|
|
@@ -6564,7 +6775,6 @@ function openDatabase(dbPathOrOptions) {
|
|
|
6564
6775
|
}
|
|
6565
6776
|
ensureSecureStorageDir(dbDir);
|
|
6566
6777
|
const db = new Database(dbPath);
|
|
6567
|
-
registerPrivilegedWriter(db);
|
|
6568
6778
|
if (!enforceSchemaFence(db, dbPath, latestSupportedVersion)) {
|
|
6569
6779
|
closeQuietly(db);
|
|
6570
6780
|
return null;
|
|
@@ -6603,7 +6813,6 @@ async function openDatabaseAsync(dbPathOrOptions) {
|
|
|
6603
6813
|
migrateLegacyStorageIfNeeded(dbPath, dbDir);
|
|
6604
6814
|
ensureSecureStorageDir(dbDir);
|
|
6605
6815
|
db = new Database(dbPath);
|
|
6606
|
-
registerPrivilegedWriter(db);
|
|
6607
6816
|
if (!enforceSchemaFence(db, dbPath, latestSupportedVersion)) {
|
|
6608
6817
|
closeQuietly(db);
|
|
6609
6818
|
return null;
|
|
@@ -9636,7 +9845,6 @@ class ModuleMemoryAuthorityError extends Error {
|
|
|
9636
9845
|
}
|
|
9637
9846
|
}
|
|
9638
9847
|
function assertTsMemoryWriteAllowed(db, projectPath) {
|
|
9639
|
-
registerPrivilegedWriter(db);
|
|
9640
9848
|
try {
|
|
9641
9849
|
const managed = db.prepare("SELECT 1 FROM authority_managed WHERE project_path = ? UNION SELECT 1 FROM authority_repair_pending WHERE project_path = ? LIMIT 1").get(projectPath, projectPath);
|
|
9642
9850
|
if (managed)
|
|
@@ -25346,8 +25554,7 @@ var EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 80% for cach
|
|
|
25346
25554
|
var DEFAULT_HISTORIAN_TIMEOUT_MS = 300000;
|
|
25347
25555
|
var DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15;
|
|
25348
25556
|
var DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
25349
|
-
var
|
|
25350
|
-
var PiThinkingLevelSchema = exports_external.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional();
|
|
25557
|
+
var PiThinkingLevelSchema = exports_external.enum(["off", "minimal", "low", "medium", "high", "xhigh", "max"]).optional();
|
|
25351
25558
|
var PiConfigSchema = exports_external.object({
|
|
25352
25559
|
subagent_extensions: exports_external.array(exports_external.string().trim().min(1)).optional().describe("User-only allowlist of Pi extensions for Magic Context subagent children. When set, children use --no-extensions and load only these entries (plus Magic Context's scoped child extension where applicable). Relative paths resolve from ~/.pi/agent, matching Pi's settings.json package location. Unset preserves normal Pi extension discovery.")
|
|
25353
25560
|
}).optional();
|
|
@@ -25420,7 +25627,7 @@ var SidekickConfigSchema = AgentOverrideConfigSchema.extend({
|
|
|
25420
25627
|
}).optional();
|
|
25421
25628
|
var HistorianConfigSchema = AgentOverrideConfigSchema.extend({
|
|
25422
25629
|
two_pass: exports_external.boolean().default(false).describe("Run a second editor pass over historian output to clean low-signal U: lines and cross-compartment duplicates. Adds ~1 extra API call and ~1.3x cost per historian run. Useful for models without extended thinking support. (default: false)"),
|
|
25423
|
-
thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level passed as --thinking <level> to Pi historian subagent invocations. Required when using reasoning models (e.g. github-copilot/gpt-5.4) because Pi's default thinking-level resolution can pick a value the provider rejects. OpenCode users set variant instead. Valid: off | minimal | low | medium | high | xhigh"),
|
|
25630
|
+
thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level passed as --thinking <level> to Pi historian subagent invocations. Required when using reasoning models (e.g. github-copilot/gpt-5.4) because Pi's default thinking-level resolution can pick a value the provider rejects. OpenCode users set variant instead. Valid: off | minimal | low | medium | high | xhigh | max"),
|
|
25424
25631
|
disallowed_tools: exports_external.array(exports_external.enum(["*", "read", "aft_outline", "aft_zoom", "aft_search"])).default([]).describe(`OpenCode only. Tools to REMOVE from the historian's default allow-list [read, aft_outline, aft_zoom, aft_search]. Applies to both historian and historian-editor agents. Use ["*"] to strip all tool definitions from the model request — this prevents weak instruction-following models (e.g. mistral-small-latest) from entering tool-calling loops. Individual tool names remove just that tool. Note: a user-supplied historian.permission override can re-allow a tool that disallowed_tools removed — disallowed_tools sets the baseline, permission overrides take precedence. (default: [])`)
|
|
25425
25632
|
}).optional();
|
|
25426
25633
|
var EmbeddingFallbackProviderSchema = exports_external.enum(["local", "openai-compatible", "off"]);
|
|
@@ -29376,6 +29583,9 @@ var shadowWorker = null;
|
|
|
29376
29583
|
var SHADOW_MAX_ITEMS_PER_TICK = 64;
|
|
29377
29584
|
var SHADOW_MAX_BYTES_PER_TICK = 512 * 1024;
|
|
29378
29585
|
var SHADOW_MAX_WALL_CLOCK_MS = 2000;
|
|
29586
|
+
var pendingShadowBackfills = new Map;
|
|
29587
|
+
var shadowBackfillLastIds = new Map;
|
|
29588
|
+
var shadowBackfillStopReasons = new Map;
|
|
29379
29589
|
var loadUnembeddedMemoriesStatements = new WeakMap;
|
|
29380
29590
|
var upsertActiveIdentityStatements = new WeakMap;
|
|
29381
29591
|
var backfillActiveIdentityStatements = new Map;
|
|
@@ -29910,6 +30120,7 @@ function registerProjectShadowEmbedding(db, projectIdentity, config2, sourceDire
|
|
|
29910
30120
|
recordScopeActiveIdentity(db, projectIdentity, "chunk", registration.chunkModelId, now);
|
|
29911
30121
|
persistShadowDescriptor(db, registration);
|
|
29912
30122
|
})();
|
|
30123
|
+
maybeArmShadowBackfill(db, projectIdentity, registration);
|
|
29913
30124
|
return {
|
|
29914
30125
|
projectIdentity,
|
|
29915
30126
|
sourceDirectory,
|
|
@@ -29930,7 +30141,7 @@ function startShadowWorker() {
|
|
|
29930
30141
|
return;
|
|
29931
30142
|
shadowWorker = runShadowWorker().finally(() => {
|
|
29932
30143
|
shadowWorker = null;
|
|
29933
|
-
if (shadowQueue.length > 0)
|
|
30144
|
+
if (shadowQueue.length > 0 || hasPendingShadowBackfill())
|
|
29934
30145
|
startShadowWorker();
|
|
29935
30146
|
});
|
|
29936
30147
|
}
|
|
@@ -29977,6 +30188,117 @@ function enqueueShadowEmbeddingItems(projectIdentity, scope, ids) {
|
|
|
29977
30188
|
shadowQueue.push({ projectIdentity, scope, ids: [...ids] });
|
|
29978
30189
|
startShadowWorker();
|
|
29979
30190
|
}
|
|
30191
|
+
function shadowBackfillMissingBase(scope, primaryModelId, shadowModelId, projectIdentity) {
|
|
30192
|
+
if (scope === "memory") {
|
|
30193
|
+
return {
|
|
30194
|
+
sql: `SELECT m.id AS id
|
|
30195
|
+
FROM memories m
|
|
30196
|
+
JOIN memory_embeddings mp ON mp.memory_id = m.id AND mp.model_id = ?
|
|
30197
|
+
LEFT JOIN memory_embeddings ms ON ms.memory_id = m.id AND ms.model_id = ?
|
|
30198
|
+
WHERE m.project_path = ? AND m.status = 'active' AND ms.memory_id IS NULL`,
|
|
30199
|
+
params: [primaryModelId, shadowModelId, projectIdentity],
|
|
30200
|
+
orderBy: " ORDER BY m.id"
|
|
30201
|
+
};
|
|
30202
|
+
}
|
|
30203
|
+
if (scope === "commit") {
|
|
30204
|
+
return {
|
|
30205
|
+
sql: `SELECT gc.sha AS id
|
|
30206
|
+
FROM git_commits gc
|
|
30207
|
+
JOIN git_commit_embeddings gp ON gp.sha = gc.sha AND gp.model_id = ?
|
|
30208
|
+
LEFT JOIN git_commit_embeddings gs ON gs.sha = gc.sha AND gs.model_id = ?
|
|
30209
|
+
WHERE gc.project_path = ? AND gs.sha IS NULL`,
|
|
30210
|
+
params: [primaryModelId, shadowModelId, projectIdentity],
|
|
30211
|
+
orderBy: " ORDER BY gc.committed_at DESC, gc.sha"
|
|
30212
|
+
};
|
|
30213
|
+
}
|
|
30214
|
+
return {
|
|
30215
|
+
sql: `SELECT DISTINCT cp.compartment_id AS id
|
|
30216
|
+
FROM compartment_chunk_embeddings cp
|
|
30217
|
+
WHERE cp.project_path = ? AND cp.model_id = ?
|
|
30218
|
+
AND NOT EXISTS (
|
|
30219
|
+
SELECT 1 FROM compartment_chunk_embeddings cs
|
|
30220
|
+
WHERE cs.compartment_id = cp.compartment_id AND cs.model_id = ?
|
|
30221
|
+
)`,
|
|
30222
|
+
params: [projectIdentity, primaryModelId, shadowModelId],
|
|
30223
|
+
orderBy: " ORDER BY cp.compartment_id"
|
|
30224
|
+
};
|
|
30225
|
+
}
|
|
30226
|
+
function shadowBackfillMissingIds(db, projectIdentity, scope, primaryModelId, shadowModelId, limit) {
|
|
30227
|
+
const { sql, params, orderBy } = shadowBackfillMissingBase(scope, primaryModelId, shadowModelId, projectIdentity);
|
|
30228
|
+
const rows = db.prepare(`${sql}${orderBy} LIMIT ?`).all(...params, limit);
|
|
30229
|
+
return rows.map((row) => String(row.id));
|
|
30230
|
+
}
|
|
30231
|
+
function shadowModelIdForScope(registration, scope) {
|
|
30232
|
+
return scope === "chunk" ? registration.chunkModelId : registration.modelId;
|
|
30233
|
+
}
|
|
30234
|
+
function hasPendingShadowBackfill(projectIdentity) {
|
|
30235
|
+
if (projectIdentity === undefined)
|
|
30236
|
+
return pendingShadowBackfills.size > 0;
|
|
30237
|
+
const scopes = pendingShadowBackfills.get(projectIdentity);
|
|
30238
|
+
return scopes !== undefined && scopes.size > 0;
|
|
30239
|
+
}
|
|
30240
|
+
function pumpShadowBackfill() {
|
|
30241
|
+
for (const [projectIdentity, scopes] of pendingShadowBackfills) {
|
|
30242
|
+
const db = dbForShadowQueue.get(projectIdentity);
|
|
30243
|
+
const shadow = shadowRegistrations.get(projectIdentity);
|
|
30244
|
+
const primary = projectRegistrations.get(projectIdentity);
|
|
30245
|
+
if (!db || !shadow || !primary) {
|
|
30246
|
+
pendingShadowBackfills.delete(projectIdentity);
|
|
30247
|
+
continue;
|
|
30248
|
+
}
|
|
30249
|
+
for (const scope of [...scopes]) {
|
|
30250
|
+
const primaryModelId = shadowModelIdForScope(primary, scope);
|
|
30251
|
+
const shadowModelId = shadowModelIdForScope(shadow, scope);
|
|
30252
|
+
const stallKey = `${projectIdentity}:${scope}`;
|
|
30253
|
+
if (primaryModelId === "off" || shadowModelId === "off") {
|
|
30254
|
+
scopes.delete(scope);
|
|
30255
|
+
shadowBackfillLastIds.delete(stallKey);
|
|
30256
|
+
continue;
|
|
30257
|
+
}
|
|
30258
|
+
const ids = shadowBackfillMissingIds(db, projectIdentity, scope, primaryModelId, shadowModelId, SHADOW_MAX_ITEMS_PER_TICK);
|
|
30259
|
+
if (ids.length === 0) {
|
|
30260
|
+
shadowBackfillStopReasons.set(stallKey, "drained");
|
|
30261
|
+
scopes.delete(scope);
|
|
30262
|
+
shadowBackfillLastIds.delete(stallKey);
|
|
30263
|
+
continue;
|
|
30264
|
+
}
|
|
30265
|
+
const signature = ids.join(",");
|
|
30266
|
+
if (shadowBackfillLastIds.get(stallKey) === signature) {
|
|
30267
|
+
shadowBackfillStopReasons.set(stallKey, "stalled_no_progress");
|
|
30268
|
+
log(`[shadow] backfill scope ${scope} for ${projectIdentity} retired without progress — ` + `the last batch produced no writes (provider failure or timeout is the usual cause); ` + `${ids.length}+ items remain and retry on the next registration or manual --shadow run`);
|
|
30269
|
+
scopes.delete(scope);
|
|
30270
|
+
shadowBackfillLastIds.delete(stallKey);
|
|
30271
|
+
continue;
|
|
30272
|
+
}
|
|
30273
|
+
shadowBackfillLastIds.set(stallKey, signature);
|
|
30274
|
+
shadowQueue.push({ projectIdentity, scope, ids });
|
|
30275
|
+
}
|
|
30276
|
+
if (scopes.size === 0)
|
|
30277
|
+
pendingShadowBackfills.delete(projectIdentity);
|
|
30278
|
+
}
|
|
30279
|
+
}
|
|
30280
|
+
function maybeArmShadowBackfill(db, projectIdentity, shadow) {
|
|
30281
|
+
if (untrustedLoadProjects.has(projectIdentity))
|
|
30282
|
+
return;
|
|
30283
|
+
const primary = projectRegistrations.get(projectIdentity);
|
|
30284
|
+
if (!primary)
|
|
30285
|
+
return;
|
|
30286
|
+
const pending = new Set;
|
|
30287
|
+
for (const scope of ["memory", "commit", "chunk"]) {
|
|
30288
|
+
const primaryModelId = shadowModelIdForScope(primary, scope);
|
|
30289
|
+
const shadowModelId = shadowModelIdForScope(shadow, scope);
|
|
30290
|
+
if (primaryModelId === "off" || shadowModelId === "off")
|
|
30291
|
+
continue;
|
|
30292
|
+
const probe = shadowBackfillMissingIds(db, projectIdentity, scope, primaryModelId, shadowModelId, 1);
|
|
30293
|
+
if (probe.length > 0)
|
|
30294
|
+
pending.add(scope);
|
|
30295
|
+
}
|
|
30296
|
+
if (pending.size === 0)
|
|
30297
|
+
return;
|
|
30298
|
+
pendingShadowBackfills.set(projectIdentity, pending);
|
|
30299
|
+
pumpShadowBackfill();
|
|
30300
|
+
startShadowWorker();
|
|
30301
|
+
}
|
|
29980
30302
|
async function embedShadowItems(registration, items, db, scope) {
|
|
29981
30303
|
const raw = registration.config;
|
|
29982
30304
|
const fingerprint = typeof raw.synapse_fingerprint === "string" ? raw.synapse_fingerprint : "";
|
|
@@ -30100,7 +30422,15 @@ async function runShadowWorker() {
|
|
|
30100
30422
|
const startedAt = Date.now();
|
|
30101
30423
|
let processed = 0;
|
|
30102
30424
|
let processedBytes = 0;
|
|
30103
|
-
|
|
30425
|
+
for (;; ) {
|
|
30426
|
+
if (shadowQueue.length === 0) {
|
|
30427
|
+
pumpShadowBackfill();
|
|
30428
|
+
if (shadowQueue.length === 0)
|
|
30429
|
+
break;
|
|
30430
|
+
}
|
|
30431
|
+
if (processed >= SHADOW_MAX_ITEMS_PER_TICK || Date.now() - startedAt >= SHADOW_MAX_WALL_CLOCK_MS) {
|
|
30432
|
+
break;
|
|
30433
|
+
}
|
|
30104
30434
|
const item = shadowQueue.shift();
|
|
30105
30435
|
if (!item)
|
|
30106
30436
|
break;
|
|
@@ -31508,6 +31838,53 @@ function injectCompactionMarker(args) {
|
|
|
31508
31838
|
return null;
|
|
31509
31839
|
}
|
|
31510
31840
|
}
|
|
31841
|
+
function listSessionCompactionMarkers(sessionId) {
|
|
31842
|
+
const db = getWritableOpenCodeDb();
|
|
31843
|
+
const partRows = db.prepare(`SELECT id, message_id
|
|
31844
|
+
FROM part
|
|
31845
|
+
WHERE session_id = ?
|
|
31846
|
+
AND COALESCE(json_extract(data, '$.type'), '') = 'compaction'`).all(sessionId);
|
|
31847
|
+
const markers = [];
|
|
31848
|
+
const summaryStmt = db.prepare(`SELECT id
|
|
31849
|
+
FROM message
|
|
31850
|
+
WHERE session_id = ?
|
|
31851
|
+
AND COALESCE(json_extract(data, '$.parentID'), '') = ?
|
|
31852
|
+
AND COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
31853
|
+
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop'
|
|
31854
|
+
AND COALESCE(json_extract(data, '$.providerID'), '') = 'magic-context'`);
|
|
31855
|
+
for (const row of partRows) {
|
|
31856
|
+
if (typeof row.id !== "string" || typeof row.message_id !== "string")
|
|
31857
|
+
continue;
|
|
31858
|
+
const summaryRows = summaryStmt.all(sessionId, row.message_id);
|
|
31859
|
+
const summaryMessageIds = summaryRows.flatMap((summaryRow) => typeof summaryRow.id === "string" ? [summaryRow.id] : []);
|
|
31860
|
+
markers.push({
|
|
31861
|
+
compactionPartId: row.id,
|
|
31862
|
+
boundaryMessageId: row.message_id,
|
|
31863
|
+
summaryMessageIds
|
|
31864
|
+
});
|
|
31865
|
+
}
|
|
31866
|
+
return markers;
|
|
31867
|
+
}
|
|
31868
|
+
function removeForeignCompactionMarker(sessionId, marker, protectedSummaryMessageId) {
|
|
31869
|
+
try {
|
|
31870
|
+
const db = getWritableOpenCodeDb();
|
|
31871
|
+
db.transaction(() => {
|
|
31872
|
+
const deletePartsOfMessage = db.prepare("DELETE FROM part WHERE session_id = ? AND message_id = ?");
|
|
31873
|
+
const deleteMessage = db.prepare("DELETE FROM message WHERE session_id = ? AND id = ?");
|
|
31874
|
+
for (const summaryMessageId of marker.summaryMessageIds) {
|
|
31875
|
+
if (summaryMessageId === protectedSummaryMessageId)
|
|
31876
|
+
continue;
|
|
31877
|
+
deletePartsOfMessage.run(sessionId, summaryMessageId);
|
|
31878
|
+
deleteMessage.run(sessionId, summaryMessageId);
|
|
31879
|
+
}
|
|
31880
|
+
db.prepare("DELETE FROM part WHERE session_id = ? AND id = ?").run(sessionId, marker.compactionPartId);
|
|
31881
|
+
})();
|
|
31882
|
+
return true;
|
|
31883
|
+
} catch (error51) {
|
|
31884
|
+
log(`[magic-context] compaction-marker: foreign-marker removal failed (${sessionId}, part ${marker.compactionPartId}): ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
31885
|
+
return false;
|
|
31886
|
+
}
|
|
31887
|
+
}
|
|
31511
31888
|
function removeCompactionMarker(state) {
|
|
31512
31889
|
try {
|
|
31513
31890
|
const db = getWritableOpenCodeDb();
|
|
@@ -31708,6 +32085,50 @@ function removeCompactionMarkerForSession(db, sessionId) {
|
|
|
31708
32085
|
}
|
|
31709
32086
|
}
|
|
31710
32087
|
}
|
|
32088
|
+
function reconcileForkOrphanedCompactionMarkers(db, sessionId) {
|
|
32089
|
+
if (getHarness() !== "opencode") {
|
|
32090
|
+
return { removed: 0, failed: false };
|
|
32091
|
+
}
|
|
32092
|
+
try {
|
|
32093
|
+
const owned = getPersistedCompactionMarkerState(db, sessionId);
|
|
32094
|
+
if (!owned) {
|
|
32095
|
+
return { removed: 0, failed: false };
|
|
32096
|
+
}
|
|
32097
|
+
const markers = listSessionCompactionMarkers(sessionId);
|
|
32098
|
+
let removed = 0;
|
|
32099
|
+
let failed = false;
|
|
32100
|
+
for (const marker of markers) {
|
|
32101
|
+
if (marker.compactionPartId === owned.compactionPartId) {
|
|
32102
|
+
continue;
|
|
32103
|
+
}
|
|
32104
|
+
if (marker.summaryMessageIds.length === 0) {
|
|
32105
|
+
continue;
|
|
32106
|
+
}
|
|
32107
|
+
const ordering = compareOpenCodeMessagesByCanonicalOrder(sessionId, marker.boundaryMessageId, owned.boundaryMessageId);
|
|
32108
|
+
if (ordering === null || ordering <= 0) {
|
|
32109
|
+
continue;
|
|
32110
|
+
}
|
|
32111
|
+
const currentOwned = getPersistedCompactionMarkerState(db, sessionId);
|
|
32112
|
+
if (!currentOwned || marker.compactionPartId === currentOwned.compactionPartId) {
|
|
32113
|
+
continue;
|
|
32114
|
+
}
|
|
32115
|
+
const ok = removeForeignCompactionMarker(sessionId, marker, currentOwned.summaryMessageId);
|
|
32116
|
+
if (ok) {
|
|
32117
|
+
removed += 1;
|
|
32118
|
+
sessionLog(sessionId, `compaction-marker hygiene: removed fork-orphaned marker part=${marker.compactionPartId} boundary=${marker.boundaryMessageId} (outranked owned boundary ${currentOwned.boundaryMessageId})`);
|
|
32119
|
+
} else {
|
|
32120
|
+
failed = true;
|
|
32121
|
+
}
|
|
32122
|
+
}
|
|
32123
|
+
if (removed > 0) {
|
|
32124
|
+
log(`[magic-context][${sessionId}] compaction-marker hygiene: removed ${removed} fork-orphaned marker(s); filterCompacted will now stop at this session's own marker`);
|
|
32125
|
+
}
|
|
32126
|
+
return { removed, failed };
|
|
32127
|
+
} catch (error51) {
|
|
32128
|
+
sessionLog(sessionId, "compaction-marker hygiene: scan failed (will retry on next degraded pass):", error51);
|
|
32129
|
+
return { removed: 0, failed: true };
|
|
32130
|
+
}
|
|
32131
|
+
}
|
|
31711
32132
|
function checkCompactionMarkerConsistency(db) {
|
|
31712
32133
|
const opencodeDbPath = join5(getDataDir(), "opencode", "opencode.db");
|
|
31713
32134
|
let opencodeDb;
|
|
@@ -32468,6 +32889,8 @@ If no candidates, omit the \`<primer_candidates>\` section entirely.
|
|
|
32468
32889
|
|
|
32469
32890
|
Output valid XML only in this shape:
|
|
32470
32891
|
|
|
32892
|
+
Closing tags must match their opening tier tag (e.g. \`<p1>...</p1>\`, never \`<p1>...</p2>\`).
|
|
32893
|
+
|
|
32471
32894
|
\`\`\`xml
|
|
32472
32895
|
<output>
|
|
32473
32896
|
<compartments>
|
|
@@ -32778,161 +33201,6 @@ function recordChildInvocation(input) {
|
|
|
32778
33201
|
}
|
|
32779
33202
|
}
|
|
32780
33203
|
|
|
32781
|
-
// src/hooks/magic-context/compartment-parser.ts
|
|
32782
|
-
var COMPARTMENT_REGEX = /<compartment\s+([^>]*?)\s*>(.*?)<\/compartment>/gs;
|
|
32783
|
-
var ATTR_START_REGEX = /\bstart="(\d+)"/;
|
|
32784
|
-
var ATTR_END_REGEX = /\bend="(\d+)"/;
|
|
32785
|
-
var ATTR_TITLE_REGEX = /\btitle="([^"]*)"/;
|
|
32786
|
-
var ATTR_EPISODE_REGEX = /\bepisode_type="([^"]*)"/;
|
|
32787
|
-
var ATTR_IMPORTANCE_REGEX = /\bimportance="(\d+)"/;
|
|
32788
|
-
function makeTierRegex(n) {
|
|
32789
|
-
return new RegExp(`<p${n}\\s*/>|<p${n}\\s*>(.*?)</p${n}>`, "s");
|
|
32790
|
-
}
|
|
32791
|
-
var TIER_REGEXES = [makeTierRegex(1), makeTierRegex(2), makeTierRegex(3), makeTierRegex(4)];
|
|
32792
|
-
var CATEGORY_BLOCK_REGEX = /<(PROJECT_RULES|ARCHITECTURE|CONSTRAINTS|CONFIG_VALUES|NAMING)>(.*?)<\/\1>/gs;
|
|
32793
|
-
var FACT_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
|
|
32794
|
-
var UNPROCESSED_REGEX = /<unprocessed_from>(\d+)<\/unprocessed_from>/;
|
|
32795
|
-
var USER_OBSERVATIONS_REGEX = /<user_observations>(.*?)<\/user_observations>/s;
|
|
32796
|
-
var USER_OBS_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
|
|
32797
|
-
var PRIMER_CANDIDATES_REGEX = /<primer_candidates>(.*?)<\/primer_candidates>/s;
|
|
32798
|
-
var PRIMER_ELEMENT_REGEX = /<primer\s+at_compartment="(\d+)"\s*>(.*?)<\/primer>/gs;
|
|
32799
|
-
var PRIMER_ITEM_REGEX = /^\s*(?:\*|-|\d+\.)\s*(.+)$/gm;
|
|
32800
|
-
var FACTS_BLOCK_REGEX = /<facts>(.*?)<\/facts>/s;
|
|
32801
|
-
var EVENTS_BLOCK_REGEX = /<events>(.*?)<\/events>/s;
|
|
32802
|
-
var EVENT_ELEMENT_REGEX = /<([a-z_]+)\s+at_compartment="(\d+)"\s*>(.*?)<\/\1>/gs;
|
|
32803
|
-
var EVENT_FIELD_REGEX = /<([a-z_]+)\s*>(.*?)<\/\1>/gs;
|
|
32804
|
-
function extractTier(inner, index) {
|
|
32805
|
-
const m = inner.match(TIER_REGEXES[index]);
|
|
32806
|
-
if (!m)
|
|
32807
|
-
return;
|
|
32808
|
-
return unescapeXml((m[1] ?? "").trim());
|
|
32809
|
-
}
|
|
32810
|
-
function parseCompartmentOutput(text) {
|
|
32811
|
-
const compartments = [];
|
|
32812
|
-
const facts = [];
|
|
32813
|
-
for (const match of text.matchAll(COMPARTMENT_REGEX)) {
|
|
32814
|
-
const attrs = match[1];
|
|
32815
|
-
const inner = match[2];
|
|
32816
|
-
const startMatch = attrs.match(ATTR_START_REGEX);
|
|
32817
|
-
const endMatch = attrs.match(ATTR_END_REGEX);
|
|
32818
|
-
const titleMatch = attrs.match(ATTR_TITLE_REGEX);
|
|
32819
|
-
if (!startMatch || !endMatch || !titleMatch)
|
|
32820
|
-
continue;
|
|
32821
|
-
const startMessage = parseInt(startMatch[1], 10);
|
|
32822
|
-
const endMessage = parseInt(endMatch[1], 10);
|
|
32823
|
-
const title = unescapeXml(titleMatch[1]);
|
|
32824
|
-
if (Number.isNaN(startMessage) || Number.isNaN(endMessage) || !title)
|
|
32825
|
-
continue;
|
|
32826
|
-
const episodeMatch = attrs.match(ATTR_EPISODE_REGEX);
|
|
32827
|
-
const importanceMatch = attrs.match(ATTR_IMPORTANCE_REGEX);
|
|
32828
|
-
const episodeType = episodeMatch ? unescapeXml(episodeMatch[1]) : undefined;
|
|
32829
|
-
const importance = importanceMatch ? parseInt(importanceMatch[1], 10) : undefined;
|
|
32830
|
-
const p1 = extractTier(inner, 0);
|
|
32831
|
-
if (typeof p1 === "string" && p1.length > 0) {
|
|
32832
|
-
const p2 = extractTier(inner, 1);
|
|
32833
|
-
const p3 = extractTier(inner, 2);
|
|
32834
|
-
const p4 = extractTier(inner, 3);
|
|
32835
|
-
compartments.push({
|
|
32836
|
-
startMessage,
|
|
32837
|
-
endMessage,
|
|
32838
|
-
title,
|
|
32839
|
-
content: p1,
|
|
32840
|
-
p1,
|
|
32841
|
-
p2: typeof p2 === "string" ? p2 : p1,
|
|
32842
|
-
p3: typeof p3 === "string" ? p3 : typeof p2 === "string" ? p2 : p1,
|
|
32843
|
-
p4: typeof p4 === "string" ? p4 : "",
|
|
32844
|
-
importance,
|
|
32845
|
-
episodeType
|
|
32846
|
-
});
|
|
32847
|
-
continue;
|
|
32848
|
-
}
|
|
32849
|
-
const content = unescapeXml(inner.trim());
|
|
32850
|
-
if (content) {
|
|
32851
|
-
compartments.push({
|
|
32852
|
-
startMessage,
|
|
32853
|
-
endMessage,
|
|
32854
|
-
title,
|
|
32855
|
-
content,
|
|
32856
|
-
importance,
|
|
32857
|
-
episodeType
|
|
32858
|
-
});
|
|
32859
|
-
}
|
|
32860
|
-
}
|
|
32861
|
-
const factsBlockMatch = text.match(FACTS_BLOCK_REGEX);
|
|
32862
|
-
const factsScope = factsBlockMatch ? factsBlockMatch[1] : text.replace(EVENTS_BLOCK_REGEX, "").replace(/<compartment\s+[^>]*?\s*>.*?<\/compartment>/gs, "");
|
|
32863
|
-
for (const categoryMatch of factsScope.matchAll(CATEGORY_BLOCK_REGEX)) {
|
|
32864
|
-
const category = categoryMatch[1];
|
|
32865
|
-
const blockContent = categoryMatch[2];
|
|
32866
|
-
for (const itemMatch of blockContent.matchAll(FACT_ITEM_REGEX)) {
|
|
32867
|
-
const content = unescapeXml(itemMatch[1].trim());
|
|
32868
|
-
if (content) {
|
|
32869
|
-
facts.push({ category, content });
|
|
32870
|
-
}
|
|
32871
|
-
}
|
|
32872
|
-
}
|
|
32873
|
-
const unprocessedMatch = text.match(UNPROCESSED_REGEX);
|
|
32874
|
-
const unprocessedFrom = unprocessedMatch ? parseInt(unprocessedMatch[1], 10) : null;
|
|
32875
|
-
const userObservations = [];
|
|
32876
|
-
const userObsMatch = text.match(USER_OBSERVATIONS_REGEX);
|
|
32877
|
-
if (userObsMatch) {
|
|
32878
|
-
for (const itemMatch of userObsMatch[1].matchAll(USER_OBS_ITEM_REGEX)) {
|
|
32879
|
-
const obs = unescapeXml(itemMatch[1].trim());
|
|
32880
|
-
if (obs)
|
|
32881
|
-
userObservations.push(obs);
|
|
32882
|
-
}
|
|
32883
|
-
}
|
|
32884
|
-
const primerCandidates = [];
|
|
32885
|
-
const primerMatch = text.match(PRIMER_CANDIDATES_REGEX);
|
|
32886
|
-
if (primerMatch) {
|
|
32887
|
-
const block = primerMatch[1];
|
|
32888
|
-
let sawElement = false;
|
|
32889
|
-
for (const el of block.matchAll(PRIMER_ELEMENT_REGEX)) {
|
|
32890
|
-
sawElement = true;
|
|
32891
|
-
const question = unescapeXml(el[2].trim());
|
|
32892
|
-
if (question) {
|
|
32893
|
-
primerCandidates.push({
|
|
32894
|
-
question,
|
|
32895
|
-
originCompartmentIndex: Number.parseInt(el[1], 10)
|
|
32896
|
-
});
|
|
32897
|
-
}
|
|
32898
|
-
}
|
|
32899
|
-
if (!sawElement) {
|
|
32900
|
-
for (const itemMatch of block.matchAll(PRIMER_ITEM_REGEX)) {
|
|
32901
|
-
const question = unescapeXml(itemMatch[1].trim());
|
|
32902
|
-
if (question)
|
|
32903
|
-
primerCandidates.push({ question });
|
|
32904
|
-
}
|
|
32905
|
-
}
|
|
32906
|
-
}
|
|
32907
|
-
const events = parseEvents(text);
|
|
32908
|
-
compartments.sort((a, b) => a.startMessage - b.startMessage);
|
|
32909
|
-
return { compartments, facts, events, unprocessedFrom, userObservations, primerCandidates };
|
|
32910
|
-
}
|
|
32911
|
-
function parseEvents(text) {
|
|
32912
|
-
const blockMatch = text.match(EVENTS_BLOCK_REGEX);
|
|
32913
|
-
if (!blockMatch)
|
|
32914
|
-
return [];
|
|
32915
|
-
const block = blockMatch[1];
|
|
32916
|
-
const events = [];
|
|
32917
|
-
for (const elMatch of block.matchAll(EVENT_ELEMENT_REGEX)) {
|
|
32918
|
-
const kind = elMatch[1];
|
|
32919
|
-
const atRaw = parseInt(elMatch[2], 10);
|
|
32920
|
-
const atCompartment = Number.isNaN(atRaw) ? null : atRaw;
|
|
32921
|
-
const fields = {};
|
|
32922
|
-
for (const fieldMatch of elMatch[3].matchAll(EVENT_FIELD_REGEX)) {
|
|
32923
|
-
const name = fieldMatch[1];
|
|
32924
|
-
const value = unescapeXml(fieldMatch[2].trim());
|
|
32925
|
-
if (value)
|
|
32926
|
-
fields[name] = value;
|
|
32927
|
-
}
|
|
32928
|
-
events.push({ kind, atCompartment, fields });
|
|
32929
|
-
}
|
|
32930
|
-
return events;
|
|
32931
|
-
}
|
|
32932
|
-
function unescapeXml(s) {
|
|
32933
|
-
return s.replace(/&/g, "&").replace(/'/g, "'").replace(/"/g, '"').replace(/</g, "<").replace(/>/g, ">");
|
|
32934
|
-
}
|
|
32935
|
-
|
|
32936
33204
|
// src/hooks/magic-context/compartment-runner-mapping.ts
|
|
32937
33205
|
function tierFieldsOf(c) {
|
|
32938
33206
|
return {
|
|
@@ -34540,6 +34808,38 @@ var INJECTION_CACHE_MAX = 100;
|
|
|
34540
34808
|
var injectionCache = new BoundedSessionMap(INJECTION_CACHE_MAX);
|
|
34541
34809
|
function clearInjectionCache(sessionId) {
|
|
34542
34810
|
injectionCache.delete(sessionId);
|
|
34811
|
+
resetDegradedReanchorState(sessionId);
|
|
34812
|
+
}
|
|
34813
|
+
var degradedRebuildCountBySession = new BoundedSessionMap(INJECTION_CACHE_MAX);
|
|
34814
|
+
var reAnchorLoggedBySession = new BoundedSessionMap(INJECTION_CACHE_MAX);
|
|
34815
|
+
var REANCHOR_MIN_DEGRADED_PASSES = 2;
|
|
34816
|
+
function resetDegradedReanchorState(sessionId) {
|
|
34817
|
+
degradedRebuildCountBySession.delete(sessionId);
|
|
34818
|
+
reAnchorLoggedBySession.delete(sessionId);
|
|
34819
|
+
}
|
|
34820
|
+
function noteDegradedRebuild(sessionId) {
|
|
34821
|
+
const next = (degradedRebuildCountBySession.get(sessionId) ?? 0) + 1;
|
|
34822
|
+
degradedRebuildCountBySession.set(sessionId, next);
|
|
34823
|
+
return next;
|
|
34824
|
+
}
|
|
34825
|
+
function clearDegradedRebuild(sessionId) {
|
|
34826
|
+
degradedRebuildCountBySession.delete(sessionId);
|
|
34827
|
+
reAnchorLoggedBySession.delete(sessionId);
|
|
34828
|
+
}
|
|
34829
|
+
function logReanchorOnce(sessionId, message) {
|
|
34830
|
+
if (reAnchorLoggedBySession.get(sessionId))
|
|
34831
|
+
return;
|
|
34832
|
+
reAnchorLoggedBySession.set(sessionId, true);
|
|
34833
|
+
sessionLog(sessionId, message);
|
|
34834
|
+
}
|
|
34835
|
+
function findVisibleReanchorIndex(compartments, visibleMessageIds) {
|
|
34836
|
+
for (let index = compartments.length - 1;index >= 0; index -= 1) {
|
|
34837
|
+
const endMessageId = compartments[index]?.endMessageId;
|
|
34838
|
+
if (typeof endMessageId === "string" && endMessageId.length > 0 && visibleMessageIds.has(endMessageId)) {
|
|
34839
|
+
return index;
|
|
34840
|
+
}
|
|
34841
|
+
}
|
|
34842
|
+
return -1;
|
|
34543
34843
|
}
|
|
34544
34844
|
function getVisibleMemoryIds(db, sessionId) {
|
|
34545
34845
|
try {
|
|
@@ -34729,24 +35029,63 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
34729
35029
|
return result2;
|
|
34730
35030
|
}
|
|
34731
35031
|
let skippedVisibleMessages = 0;
|
|
35032
|
+
let needsFreshMaterialization = false;
|
|
35033
|
+
let resultEndMessage = lastEnd;
|
|
35034
|
+
let resultEndMessageId = null;
|
|
34732
35035
|
const cutoffIndex = messages.findIndex((message) => message.info.id === trimEndMessageId);
|
|
34733
35036
|
if (cutoffIndex >= 0) {
|
|
35037
|
+
clearDegradedRebuild(sessionId);
|
|
34734
35038
|
skippedVisibleMessages = cutoffIndex + 1;
|
|
34735
35039
|
const remaining = messages.slice(cutoffIndex + 1);
|
|
34736
35040
|
messages.splice(0, messages.length, ...remaining);
|
|
35041
|
+
resultEndMessageId = trimEndMessageId;
|
|
34737
35042
|
} else {
|
|
34738
|
-
|
|
35043
|
+
const degradedCount = noteDegradedRebuild(sessionId);
|
|
35044
|
+
if (degradedCount === 1) {
|
|
35045
|
+
reconcileForkOrphanedCompactionMarkers(db, sessionId);
|
|
35046
|
+
}
|
|
35047
|
+
let reAnchored = false;
|
|
35048
|
+
if (degradedCount >= REANCHOR_MIN_DEGRADED_PASSES && isCacheBusting) {
|
|
35049
|
+
const visibleMessageIds = new Set;
|
|
35050
|
+
for (const message of messages) {
|
|
35051
|
+
if (typeof message.info.id === "string")
|
|
35052
|
+
visibleMessageIds.add(message.info.id);
|
|
35053
|
+
}
|
|
35054
|
+
const reAnchorIndex = findVisibleReanchorIndex(compartments, visibleMessageIds);
|
|
35055
|
+
if (reAnchorIndex >= 0) {
|
|
35056
|
+
const reAnchorCompartment = compartments[reAnchorIndex];
|
|
35057
|
+
const reAnchorCutoff = messages.findIndex((message) => message.info.id === reAnchorCompartment.endMessageId);
|
|
35058
|
+
if (reAnchorCutoff >= 0) {
|
|
35059
|
+
skippedVisibleMessages = reAnchorCutoff + 1;
|
|
35060
|
+
const remaining = messages.slice(reAnchorCutoff + 1);
|
|
35061
|
+
messages.splice(0, messages.length, ...remaining);
|
|
35062
|
+
resultEndMessage = reAnchorCompartment.endMessage;
|
|
35063
|
+
resultEndMessageId = reAnchorCompartment.endMessageId;
|
|
35064
|
+
reAnchored = true;
|
|
35065
|
+
logReanchorOnce(sessionId, `compartment injection re-anchored: natural boundary ${trimEndMessageId} not visible for ${degradedCount} passes; splicing at visible compartment boundary ${resultEndMessageId} (ordinal ${resultEndMessage})`);
|
|
35066
|
+
}
|
|
35067
|
+
}
|
|
35068
|
+
if (!reAnchored) {
|
|
35069
|
+
needsFreshMaterialization = true;
|
|
35070
|
+
logReanchorOnce(sessionId, `compartment injection degraded: boundary ${trimEndMessageId} not visible for ${degradedCount} passes and no compartment boundary is visible; requesting fresh materialization to re-cut the baseline`);
|
|
35071
|
+
}
|
|
35072
|
+
} else {
|
|
35073
|
+
sessionLog(sessionId, `compartment injection entering degraded mode: boundary ${trimEndMessageId} not in visible messages (consecutive degraded passes: ${degradedCount})`);
|
|
35074
|
+
}
|
|
34739
35075
|
}
|
|
34740
35076
|
const result = {
|
|
34741
35077
|
block,
|
|
34742
|
-
compartmentEndMessage:
|
|
34743
|
-
compartmentEndMessageId:
|
|
35078
|
+
compartmentEndMessage: resultEndMessage,
|
|
35079
|
+
compartmentEndMessageId: resultEndMessageId,
|
|
34744
35080
|
compartmentCount: compartments.length,
|
|
34745
35081
|
skippedVisibleMessages,
|
|
34746
35082
|
factCount: facts.length,
|
|
34747
35083
|
memoryCount,
|
|
34748
35084
|
rebuiltFromDb: true
|
|
34749
35085
|
};
|
|
35086
|
+
if (needsFreshMaterialization) {
|
|
35087
|
+
result.needsFreshMaterialization = true;
|
|
35088
|
+
}
|
|
34750
35089
|
injectionCache.set(sessionId, { kind: "populated", injection: result });
|
|
34751
35090
|
return result;
|
|
34752
35091
|
}
|