@cortexkit/opencode-magic-context 0.49.16 → 0.49.18
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/auto-search-worker.js +76 -63
- package/dist/chunk-embedding-write-worker.js +11 -11
- package/dist/{compaction-marker-candidates-v5c6997n.js → compaction-marker-candidates-n4krhat4.js} +2 -2
- package/dist/compaction-marker-candidates-worker.js +2 -2
- package/dist/config/schema/magic-context.d.ts +394 -394
- package/dist/{conflict-warning-hook-znry4j76.js → conflict-warning-hook-4pmz879v.js} +5 -5
- package/dist/{context-3znk23va.js → context-m897gfp9.js} +304 -145
- package/dist/{embedding-backfill-q4n8dend.js → embedding-backfill-fmz50tsy.js} +11 -11
- package/dist/embedding-worker-process.js +1 -1
- package/dist/embedding-worker.js +4 -4
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts +1 -1
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/indexer.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
- package/dist/features/magic-context/memory/project-identity-cache.d.ts +2 -0
- package/dist/features/magic-context/memory/project-identity-cache.d.ts.map +1 -1
- package/dist/features/magic-context/message-index-async.d.ts +1 -1
- package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
- package/dist/features/magic-context/message-index.d.ts +5 -0
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/search.d.ts +6 -1
- package/dist/features/magic-context/search.d.ts.map +1 -1
- package/dist/features/magic-context/storage-host-instruction-retention.d.ts +11 -0
- package/dist/features/magic-context/storage-host-instruction-retention.d.ts.map +1 -0
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +2 -2
- package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
- package/dist/features/magic-context/storage-session-tables.d.ts +9 -1
- package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-deadline.d.ts +2 -1
- package/dist/hooks/magic-context/auto-search-deadline.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-hint.d.ts +3 -0
- package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-worker-client.d.ts +10 -2
- package/dist/hooks/magic-context/auto-search-worker-client.d.ts.map +1 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts +22 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts +2 -0
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts +4 -2
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
- package/dist/hooks/magic-context/file-token-coverage.d.ts +11 -0
- package/dist/hooks/magic-context/file-token-coverage.d.ts.map +1 -0
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +9 -0
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
- package/dist/hooks/magic-context/historian-host-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/host-served-rows.d.ts +25 -0
- package/dist/hooks/magic-context/host-served-rows.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +7 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-recovery-fence.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-slot.d.ts +1 -1
- package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
- package/dist/hooks/magic-context/pass-outcome.d.ts +2 -0
- package/dist/hooks/magic-context/pass-outcome.d.ts.map +1 -1
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts +2 -1
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/signed-thinking-hold.d.ts +59 -0
- package/dist/hooks/magic-context/signed-thinking-hold.d.ts.map +1 -0
- package/dist/hooks/magic-context/system-prompt-diagnostics.d.ts +8 -0
- package/dist/hooks/magic-context/system-prompt-diagnostics.d.ts.map +1 -0
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-content-primitives.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts +6 -1
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/todo-view.d.ts +2 -2
- package/dist/hooks/magic-context/tool-drop-target.d.ts +3 -2
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +6 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-context-state.d.ts +19 -0
- package/dist/hooks/magic-context/transform-context-state.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +19 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-stage-logger.d.ts +3 -0
- package/dist/hooks/magic-context/transform-stage-logger.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +1 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/{index-9nkg2dzk.js → index-24fezq97.js} +3 -3
- package/dist/{index-v9asb16b.js → index-24jbw52d.js} +5 -5
- package/dist/{index-a8bvhwqs.js → index-2vxtcb95.js} +32 -3
- package/dist/{index-f71thw8j.js → index-4s3t0nd0.js} +1 -1
- package/dist/{index-6a6dq53h.js → index-6s5941tm.js} +5 -5
- package/dist/{index-fkx2qnvw.js → index-6x57ar45.js} +2 -2
- package/dist/{index-ek1yxvvz.js → index-936py2wm.js} +361 -70
- package/dist/{index-dqe8pq4x.js → index-a6mc0v4d.js} +6 -3
- package/dist/{index-hehkf6zm.js → index-b5vqckbw.js} +12 -6
- package/dist/{v2/server-wafzvyhg.js → index-beht37jy.js} +8 -0
- package/dist/{index-7b2cfmaz.js → index-bjcnntmz.js} +2 -2
- package/dist/{index-hqkczed7.js → index-c5pytzne.js} +22 -2
- package/dist/{index-nd7m2a5a.js → index-cf74k5ak.js} +27 -5
- package/dist/{index-kn4t1haw.js → index-e4xv8890.js} +531 -253
- package/dist/{index-cj9g0j7a.js → index-fgncb0ng.js} +7 -7
- package/dist/{index-5mwk1nek.js → index-jn12fvvh.js} +1 -1
- package/dist/{index-n6m03s3n.js → index-ke416mdc.js} +1 -1
- package/dist/{index-mtw9e71a.js → index-kq82mtg0.js} +2 -2
- package/dist/{index-n78avt2p.js → index-n37sebck.js} +1 -1
- package/dist/{index-wk0n1cgt.js → index-qn7xstt2.js} +2 -2
- package/dist/{index-v63beg1z.js → index-r4nkrs05.js} +3 -3
- package/dist/{index-j6zw70pf.js → index-rmwykbbb.js} +60 -21
- package/dist/{index-saews2s3.js → index-rr2bb45z.js} +1 -1
- package/dist/{index-ayym1x7f.js → index-s1ex9y6p.js} +195 -748
- package/dist/{index-7pa32z07.js → index-s734jcsr.js} +1 -1
- package/dist/{index-b17m64g9.js → index-s74zqahq.js} +1 -1
- package/dist/{index-4qfy7v57.js → index-s7j8tvhv.js} +31 -20
- package/dist/{index-wv9n2zcq.js → index-v8awdgvd.js} +4 -4
- package/dist/{index-p4vde22c.js → index-x4njr8df.js} +965 -77
- package/dist/{index-qrahzcqv.js → index-ze7mvk54.js} +10 -7
- package/dist/index.js +39 -39
- package/dist/{message-fts-rowid-map-yvx5a9jw.js → message-fts-rowid-map-17s0dfn4.js} +5 -3
- package/dist/{message-index-t4pz7akd.js → message-index-66jv6fh4.js} +13 -13
- package/dist/{message-index-bounded-6th8djy9.js → message-index-bounded-n1frdn85.js} +17 -17
- package/dist/{message-time-backfill-8egzkd3z.js → message-time-backfill-73mmm76q.js} +1 -1
- package/dist/migration-worker.js +8 -8
- package/dist/plugin/dream-timer.d.ts +11 -0
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/{project-embedding-registry-2dea0a77.js → project-embedding-registry-z74mhqkf.js} +10 -10
- package/dist/raw-ordinal-warmup-worker.js +10 -10
- package/dist/{read-session-chunk-4pwqxm5a.js → read-session-chunk-v06g3vka.js} +7 -7
- package/dist/{read-session-raw-5ar8se5v.js → read-session-raw-rsc8c7qy.js} +2 -2
- package/dist/{recomp-orchestrator-tjcaj5x7.js → recomp-orchestrator-ghpk2dtq.js} +24 -24
- package/dist/{search-archive-02jws7hw.js → search-archive-4d53y23e.js} +8 -8
- package/dist/{search-rb01n29x.js → search-nkf271d4.js} +20 -20
- package/dist/{send-session-notification-2x9edkrp.js → send-session-notification-6ve0e8p4.js} +4 -4
- package/dist/shared/historian-cache.d.ts +8 -0
- package/dist/shared/historian-cache.d.ts.map +1 -0
- package/dist/shared/model-suggestion-retry.d.ts +2 -0
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/rpc-discovery-cleanup.d.ts +3 -0
- package/dist/shared/rpc-discovery-cleanup.d.ts.map +1 -0
- package/dist/shared/rpc-server.d.ts +2 -0
- package/dist/shared/rpc-server.d.ts.map +1 -1
- package/dist/shared/search-text.d.ts +8 -0
- package/dist/shared/search-text.d.ts.map +1 -0
- package/dist/shared/sqlite.d.ts +4 -2
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/shared/storage-file-mutex.d.ts.map +1 -1
- package/dist/shared/subagent-runner.d.ts +2 -0
- package/dist/shared/subagent-runner.d.ts.map +1 -1
- package/dist/shared/system-directive.d.ts +2 -0
- package/dist/shared/system-directive.d.ts.map +1 -1
- package/dist/{sqlite-4pqyynrs.js → sqlite-zf72c52d.js} +1 -1
- package/dist/{storage-memory-j3v3hc83.js → storage-memory-y3qmy00r.js} +2 -2
- package/dist/{storage-tags-4z1w27xa.js → storage-tags-r7k9tjcv.js} +8 -4
- package/dist/{transform-postprocess-phase-xaw5c3xp.js → transform-postprocess-phase-zpgav0h7.js} +24 -24
- package/dist/v2/auto-search-worker.js +76 -63
- package/dist/v2/chunk-embedding-write-worker.js +11 -11
- package/dist/v2/{compaction-marker-candidates-1vqwr3s5.js → compaction-marker-candidates-ebx3388k.js} +2 -2
- package/dist/v2/compaction-marker-candidates-worker.js +2 -2
- package/dist/v2/{context-acw1nhv8.js → context-f2xh7ba4.js} +1171 -448
- package/dist/v2/embedding-backfill-7c7yr69y.js +23 -0
- package/dist/v2/embedding-worker-process.js +1 -1
- package/dist/v2/embedding-worker.js +4 -4
- package/dist/v2/fold/native-replay.d.ts +11 -2
- package/dist/v2/fold/native-replay.d.ts.map +1 -1
- package/dist/v2/fold/policy.d.ts.map +1 -1
- package/dist/v2/fold/restore.d.ts.map +1 -1
- package/dist/v2/hooks/context.d.ts.map +1 -1
- package/dist/v2/hooks/hidden-child.d.ts +8 -0
- package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
- package/dist/v2/hooks/payload.d.ts.map +1 -1
- package/dist/v2/hooks/types.d.ts +17 -0
- package/dist/v2/hooks/types.d.ts.map +1 -1
- package/dist/v2/{message-fts-rowid-map-8vf0v7cr.js → message-fts-rowid-map-wfx67gfd.js} +5 -3
- package/dist/v2/{message-index-e6qzw477.js → message-index-48f7hw7a.js} +13 -13
- package/dist/v2/{message-index-bounded-dsrf49y7.js → message-index-bounded-w3hfm29z.js} +17 -17
- package/dist/v2/{message-time-backfill-q5pgxf0d.js → message-time-backfill-04t0km1z.js} +1 -1
- package/dist/v2/migration-worker.js +8 -8
- package/dist/v2/{project-embedding-registry-rek75aqw.js → project-embedding-registry-gnkj56xp.js} +10 -10
- package/dist/v2/raw-ordinal-warmup-worker.js +10 -10
- package/dist/v2/{read-session-chunk-7bpygfv2.js → read-session-chunk-zpgmxwte.js} +7 -7
- package/dist/v2/{read-session-raw-pw2n1qgc.js → read-session-raw-yaegtjzh.js} +2 -2
- package/dist/v2/{recomp-orchestrator-hzpgg06e.js → recomp-orchestrator-4vfxej9t.js} +24 -24
- package/dist/v2/{search-archive-fn4wy8sx.js → search-archive-vv48s2aa.js} +8 -8
- package/dist/v2/{search-sf2vg5pk.js → search-kza414f0.js} +20 -20
- package/dist/v2/{send-session-notification-hmr7q0nt.js → send-session-notification-3pxn658x.js} +4 -4
- package/dist/v2/{server-n5q841qn.js → server-1nyybqan.js} +31 -20
- package/dist/v2/{server-785mb90s.js → server-1wy7b9de.js} +6 -3
- package/dist/v2/{server-0mzjjw3s.js → server-27gq4mfz.js} +27 -5
- package/dist/v2/{server-g59aatsz.js → server-2ehj0bw7.js} +965 -77
- package/dist/v2/{server-kqpawe1a.js → server-46neh5fa.js} +12 -6
- package/dist/v2/{server-rrqpvwqd.js → server-6tmj0s7j.js} +2 -2
- package/dist/v2/{server-kr2kc9dz.js → server-8by8qfec.js} +10 -7
- package/dist/v2/{server-r9gjxcte.js → server-a2eqhkxr.js} +7 -7
- package/dist/v2/{server-vbe4se57.js → server-a9xqj88f.js} +1 -1
- package/dist/{index-wafzvyhg.js → v2/server-beht37jy.js} +8 -0
- package/dist/v2/{server-6fyp0v67.js → server-bfpda1tb.js} +195 -749
- package/dist/v2/{server-05xjtq6c.js → server-d04vrx0j.js} +1 -1
- package/dist/v2/{server-zs8d0s3b.js → server-g3qma5c0.js} +1 -1
- package/dist/v2/{server-00hx04yn.js → server-gpvay0xz.js} +2 -2
- package/dist/v2/{server-gha9x4qq.js → server-h1v0pyxb.js} +2 -2
- package/dist/v2/{server-hgg55hde.js → server-hy3d3vsx.js} +1 -1
- package/dist/v2/{server-vgpab6rd.js → server-my7k4eds.js} +4 -4
- package/dist/v2/{server-d8tj10db.js → server-n1prf1g6.js} +1 -1
- package/dist/v2/{server-n78avt2p.js → server-n37sebck.js} +1 -1
- package/dist/v2/{server-y5pznjt9.js → server-nj659894.js} +5 -5
- package/dist/v2/{server-zyw55ygv.js → server-qv7f0hhe.js} +5 -5
- package/dist/v2/{server-e3ftpk7v.js → server-rmygf5pn.js} +32 -3
- package/dist/v2/{server-0ppsweh6.js → server-tgnbmwah.js} +22 -2
- package/dist/v2/{server-1hcbw661.js → server-xhab8jx8.js} +60 -21
- package/dist/v2/{server-6714jebr.js → server-xj136kt8.js} +1 -1
- package/dist/v2/{server-aavz8pm6.js → server-zzkj2fch.js} +3 -3
- package/dist/v2/server.js +4 -4
- package/dist/v2/{sqlite-4pqyynrs.js → sqlite-zf72c52d.js} +1 -1
- package/dist/v2/{storage-memory-j3v3hc83.js → storage-memory-y3qmy00r.js} +2 -2
- package/dist/v2/{storage-tags-hkwtbp3g.js → storage-tags-3wdb8zph.js} +8 -4
- package/dist/v2/store-reader.d.ts +8 -0
- package/dist/v2/store-reader.d.ts.map +1 -1
- package/dist/v2/{wrapup-orchestrator-x4xj1782.js → wrapup-orchestrator-psqz7yh0.js} +24 -24
- package/dist/wrapup-orchestrator-s9zc5b00.js +48 -0
- package/package.json +1 -1
- package/src/config/latch-permanence-guard.test.ts +4 -0
- package/src/shared/historian-cache.test.ts +69 -0
- package/src/shared/historian-cache.ts +55 -0
- package/src/shared/model-suggestion-retry.ts +2 -0
- package/src/shared/rpc-discovery-cleanup.test.ts +57 -0
- package/src/shared/rpc-discovery-cleanup.ts +57 -0
- package/src/shared/rpc-server.ts +36 -13
- package/src/shared/search-text.test.ts +47 -0
- package/src/shared/search-text.ts +63 -0
- package/src/shared/sqlite.test.ts +56 -0
- package/src/shared/sqlite.ts +51 -2
- package/src/shared/storage-file-mutex-review.test.ts +22 -2
- package/src/shared/storage-file-mutex.ts +11 -1
- package/src/shared/subagent-runner.ts +2 -0
- package/src/shared/system-directive.ts +19 -1
- package/src/shared/tag-transcript.ts +12 -4
- package/dist/v2/embedding-backfill-jyd6492b.js +0 -23
- package/dist/wrapup-orchestrator-vj2tbp22.js +0 -48
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { removeNestedBlocks } from "./system-directive";
|
|
2
|
+
|
|
3
|
+
export function removeTaskNotifications(text: string): string {
|
|
4
|
+
return removeNestedBlocks(text, ["task", "task_cohort"]);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/** Remove injected notifications before scoring or rendering; previously saved hints replay unchanged. */
|
|
8
|
+
export function cleanSearchText(text: string): string {
|
|
9
|
+
return removeNestedBlocks(text, ["system-reminder", "task", "task_cohort"])
|
|
10
|
+
.replace(/\s+/g, " ")
|
|
11
|
+
.trim();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const QUERY_STOP_WORDS = new Set(
|
|
15
|
+
"a an and are as at be been by can could did do does for from how i in is it me my of on or our please should that the their them there these they this to us was we were what when where which who why will with would you your".split(
|
|
16
|
+
" ",
|
|
17
|
+
),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
function terms(text: string): string[] {
|
|
21
|
+
return [
|
|
22
|
+
...new Set(
|
|
23
|
+
(text.toLowerCase().match(/[\p{L}\p{N}_]+/gu) ?? []).filter(
|
|
24
|
+
(term) => !QUERY_STOP_WORDS.has(term),
|
|
25
|
+
),
|
|
26
|
+
),
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Score the share of distinct query terms present, independently of other results. */
|
|
31
|
+
export function keywordRelevance(query: string, content: string): number {
|
|
32
|
+
const needles = terms(query);
|
|
33
|
+
if (needles.length === 0) return 0;
|
|
34
|
+
const words = new Set(terms(cleanSearchText(content)));
|
|
35
|
+
return (0.8 * needles.filter((term) => words.has(term)).length) / needles.length;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Pick the densest matching passage before compression can discard the matched words. */
|
|
39
|
+
export function matchedSearchSnippet(content: string, query: string, cap = 220): string {
|
|
40
|
+
const text = cleanSearchText(content);
|
|
41
|
+
const needles = new Set(terms(query));
|
|
42
|
+
const matches = [...text.matchAll(/[\p{L}\p{N}_]+/gu)].filter((match) =>
|
|
43
|
+
needles.has(match[0].toLowerCase()),
|
|
44
|
+
);
|
|
45
|
+
if (matches.length === 0) return "";
|
|
46
|
+
let bestStart = matches[0].index;
|
|
47
|
+
let bestCoverage = -1;
|
|
48
|
+
for (const match of matches) {
|
|
49
|
+
const start = Math.max(0, match.index - Math.floor(cap / 5));
|
|
50
|
+
const coverage = keywordRelevance(query, text.slice(start, start + cap));
|
|
51
|
+
if (coverage > bestCoverage) {
|
|
52
|
+
bestStart = start;
|
|
53
|
+
bestCoverage = coverage;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Avoid emitting half a word at the left edge of a passage.
|
|
57
|
+
if (bestStart > 0) {
|
|
58
|
+
const boundary = text.indexOf(" ", bestStart);
|
|
59
|
+
if (boundary >= 0 && boundary < matches[matches.length - 1].index) bestStart = boundary + 1;
|
|
60
|
+
}
|
|
61
|
+
const passage = text.slice(bestStart, bestStart + cap).trim();
|
|
62
|
+
return `${bestStart > 0 ? "…" : ""}${passage}${bestStart + cap < text.length ? "…" : ""}`;
|
|
63
|
+
}
|
|
@@ -1,14 +1,40 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
3
6
|
import {
|
|
4
7
|
Database,
|
|
5
8
|
detectSqliteRuntime,
|
|
6
9
|
getSqliteMemoryStats,
|
|
7
10
|
loadSqliteModule,
|
|
11
|
+
openImmutableDatabase,
|
|
8
12
|
SqliteRuntimeUnavailableError,
|
|
9
13
|
} from "./sqlite";
|
|
14
|
+
import { createTestTempDir } from "./test-temp-dir";
|
|
10
15
|
|
|
11
16
|
describe("SQLite runtime selector", () => {
|
|
17
|
+
it("imports the shared SQLite module in Bun without node:sqlite available", () => {
|
|
18
|
+
const sqliteUrl = new URL("./sqlite.ts", import.meta.url).href;
|
|
19
|
+
const script = `
|
|
20
|
+
const getBuiltinModule = process.getBuiltinModule;
|
|
21
|
+
process.getBuiltinModule = function (specifier) {
|
|
22
|
+
if (specifier === "node:sqlite") throw new Error("node:sqlite deliberately unavailable");
|
|
23
|
+
return getBuiltinModule.call(process, specifier);
|
|
24
|
+
};
|
|
25
|
+
await import(${JSON.stringify(sqliteUrl)});
|
|
26
|
+
console.log("shared SQLite import succeeded");
|
|
27
|
+
`;
|
|
28
|
+
const child = spawnSync(process.execPath, ["-e", script], {
|
|
29
|
+
encoding: "utf8",
|
|
30
|
+
windowsHide: true,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(child.error).toBeUndefined();
|
|
34
|
+
expect(child.status).toBe(0);
|
|
35
|
+
expect(child.stdout).toContain("shared SQLite import succeeded");
|
|
36
|
+
});
|
|
37
|
+
|
|
12
38
|
it("suppresses only the node:sqlite experimental warning in a real Node process", () => {
|
|
13
39
|
// Node 24.21 no longer emits this warning, so inject it during loading
|
|
14
40
|
// to keep the suppression assertion load-bearing on newer runtimes.
|
|
@@ -80,6 +106,36 @@ describe("SQLite runtime selector", () => {
|
|
|
80
106
|
expect(getSqliteMemoryStats().connectionCount).toBe(before);
|
|
81
107
|
});
|
|
82
108
|
|
|
109
|
+
it("reads a checkpointed WAL database without creating sidecars or changing bytes", () => {
|
|
110
|
+
const { dir: directory, cleanup } = createTestTempDir(
|
|
111
|
+
"mc-plugin-test-xdg-pid-",
|
|
112
|
+
"immutable-sqlite-",
|
|
113
|
+
);
|
|
114
|
+
const path = join(directory, "context.db");
|
|
115
|
+
try {
|
|
116
|
+
const writer = new Database(path);
|
|
117
|
+
writer.exec(
|
|
118
|
+
"PRAGMA journal_mode=WAL; CREATE TABLE sample (value INTEGER); INSERT INTO sample VALUES (42); PRAGMA wal_checkpoint(TRUNCATE)",
|
|
119
|
+
);
|
|
120
|
+
writer.close();
|
|
121
|
+
expect(existsSync(`${path}-wal`)).toBe(false);
|
|
122
|
+
expect(existsSync(`${path}-shm`)).toBe(false);
|
|
123
|
+
|
|
124
|
+
const before = createHash("sha256").update(readFileSync(path)).digest("hex");
|
|
125
|
+
const reader = openImmutableDatabase(path);
|
|
126
|
+
try {
|
|
127
|
+
expect(reader.prepare("SELECT value FROM sample").get()).toEqual({ value: 42 });
|
|
128
|
+
} finally {
|
|
129
|
+
reader.close();
|
|
130
|
+
}
|
|
131
|
+
expect(createHash("sha256").update(readFileSync(path)).digest("hex")).toBe(before);
|
|
132
|
+
expect(existsSync(`${path}-wal`)).toBe(false);
|
|
133
|
+
expect(existsSync(`${path}-shm`)).toBe(false);
|
|
134
|
+
} finally {
|
|
135
|
+
cleanup();
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
83
139
|
it("wraps a missing node:sqlite module with the detected runtime and cause", async () => {
|
|
84
140
|
const cause = Object.assign(new Error("No such built-in module: node:sqlite"), {
|
|
85
141
|
code: "ERR_UNKNOWN_BUILTIN_MODULE",
|
package/src/shared/sqlite.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* flag-free since Node 22.13/23.4).
|
|
9
9
|
*
|
|
10
10
|
* Bun has no `node:sqlite`, and Node/Electron have no `bun:sqlite`. Static
|
|
11
|
-
* imports of either would crash at parse time in the wrong runtime, so
|
|
12
|
-
*
|
|
11
|
+
* imports of either would crash at parse time in the wrong runtime, so the
|
|
12
|
+
* selected backend is loaded only after runtime detection.
|
|
13
13
|
*
|
|
14
14
|
* Why `node:sqlite` instead of `better-sqlite3`: better-sqlite3 is a native
|
|
15
15
|
* module requiring per-ABI prebuilds, and Electron's ABI never matches the npm
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
import { AsyncLocalStorage, AsyncResource } from "node:async_hooks";
|
|
43
43
|
import { statSync } from "node:fs";
|
|
44
|
+
import { pathToFileURL } from "node:url";
|
|
44
45
|
|
|
45
46
|
// Type import only — runtime is loaded dynamically below. @types/better-sqlite3
|
|
46
47
|
// has the richest definitions and is a structural superset of the API surface
|
|
@@ -140,6 +141,13 @@ const bunSpec = "bun:" + "sqlite";
|
|
|
140
141
|
const nodeSpec = "node:" + "sqlite";
|
|
141
142
|
|
|
142
143
|
async function importSqliteModule(specifier: string): Promise<SqliteModule> {
|
|
144
|
+
if (specifier === nodeSpec && typeof process.getBuiltinModule === "function") {
|
|
145
|
+
const loaded = process.getBuiltinModule(specifier) as SqliteModule | undefined;
|
|
146
|
+
if (loaded) return loaded;
|
|
147
|
+
throw Object.assign(new Error(`No such built-in module: ${specifier}`), {
|
|
148
|
+
code: "ERR_UNKNOWN_BUILTIN_MODULE",
|
|
149
|
+
});
|
|
150
|
+
}
|
|
143
151
|
// The runtime chooses this specifier; Vite must not resolve it as a
|
|
144
152
|
// build-time dependency because the other runtime's backend is absent.
|
|
145
153
|
return (await import(
|
|
@@ -252,6 +260,7 @@ const sqliteModule = await loadSqliteModule(detectedRuntime);
|
|
|
252
260
|
const DatabaseImpl: typeof BetterSqlite3 = isBun
|
|
253
261
|
? (sqliteModule.Database as typeof BetterSqlite3)
|
|
254
262
|
: buildNodeSqliteDatabaseClass(sqliteModule.DatabaseSync);
|
|
263
|
+
let immutableDatabaseImpl: typeof BetterSqlite3 | undefined;
|
|
255
264
|
|
|
256
265
|
interface TrackedSqliteConnection {
|
|
257
266
|
sequence: number;
|
|
@@ -655,6 +664,46 @@ function buildNodeSqliteDatabaseClass(DatabaseSync: any): typeof BetterSqlite3 {
|
|
|
655
664
|
|
|
656
665
|
export const Database: typeof BetterSqlite3 = TrackedDatabase;
|
|
657
666
|
|
|
667
|
+
function immutableDatabaseImplementation(): typeof BetterSqlite3 {
|
|
668
|
+
if (!isBun) return DatabaseImpl;
|
|
669
|
+
if (immutableDatabaseImpl) return immutableDatabaseImpl;
|
|
670
|
+
|
|
671
|
+
const getBuiltinModule = process.getBuiltinModule;
|
|
672
|
+
if (typeof getBuiltinModule !== "function")
|
|
673
|
+
throw new SqliteRuntimeUnavailableError(
|
|
674
|
+
"Bun",
|
|
675
|
+
nodeSpec,
|
|
676
|
+
new Error("This Bun runtime does not expose process.getBuiltinModule"),
|
|
677
|
+
);
|
|
678
|
+
const nodeSqlite = getBuiltinModule.call(process, nodeSpec) as SqliteModule | undefined;
|
|
679
|
+
if (!nodeSqlite?.DatabaseSync)
|
|
680
|
+
throw new SqliteRuntimeUnavailableError(
|
|
681
|
+
"Bun",
|
|
682
|
+
nodeSpec,
|
|
683
|
+
new Error(`No such built-in module: ${nodeSpec}`),
|
|
684
|
+
);
|
|
685
|
+
|
|
686
|
+
immutableDatabaseImpl = buildNodeSqliteDatabaseClass(nodeSqlite.DatabaseSync);
|
|
687
|
+
return immutableDatabaseImpl;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/** Open a closed SQLite file without asking SQLite to create missing WAL sidecars. */
|
|
691
|
+
export function openImmutableDatabase(path: string): BetterSqlite3.Database {
|
|
692
|
+
// Immutable mode avoids creating missing WAL sidecars; callers must first rule out writers.
|
|
693
|
+
const uri = pathToFileURL(path);
|
|
694
|
+
uri.searchParams.set("immutable", "1");
|
|
695
|
+
const target = immutableDatabaseImplementation();
|
|
696
|
+
const db = inRootAsyncContext(
|
|
697
|
+
() =>
|
|
698
|
+
Reflect.construct(
|
|
699
|
+
target,
|
|
700
|
+
[uri.href, { readonly: true }],
|
|
701
|
+
target,
|
|
702
|
+
) as BetterSqlite3.Database,
|
|
703
|
+
);
|
|
704
|
+
return trackSqliteConnection(db, uri.href, { readonly: true });
|
|
705
|
+
}
|
|
706
|
+
|
|
658
707
|
/** The constructor path, without querying SQLite on the prompt thread. */
|
|
659
708
|
export function getSqliteDatabasePath(db: Database): string | null {
|
|
660
709
|
for (const connection of trackedSqliteConnections.values()) {
|
|
@@ -1,13 +1,33 @@
|
|
|
1
|
-
import { expect, test } from "bun:test";
|
|
1
|
+
import { expect, spyOn, test } from "bun:test";
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { readdirSync, readFileSync, rmdirSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { __resetRpcIdentityTestHooks, __setRpcIdentityTestHooks } from "./rpc-utils";
|
|
6
6
|
import { withStorageFileMutex } from "./storage-file-mutex";
|
|
7
|
+
import * as permissions from "./storage-permissions";
|
|
7
8
|
import { createTestTempDir } from "./test-temp-dir";
|
|
8
9
|
|
|
9
10
|
const mutex = join(import.meta.dir, "storage-file-mutex.ts");
|
|
10
11
|
|
|
12
|
+
test("mutex retries ticket creation when empty-directory cleanup wins the mkdir race", () => {
|
|
13
|
+
const { dir: root, cleanup } = createTestTempDir("mc-mutex-rmdir-");
|
|
14
|
+
const directory = join(root, "locks");
|
|
15
|
+
const write = permissions.writeStorageFileSync;
|
|
16
|
+
let attempts = 0;
|
|
17
|
+
const writer = spyOn(permissions, "writeStorageFileSync").mockImplementation((...args) => {
|
|
18
|
+
if (attempts++ === 0) rmdirSync(directory);
|
|
19
|
+
return write(...args);
|
|
20
|
+
});
|
|
21
|
+
try {
|
|
22
|
+
expect(withStorageFileMutex(directory, () => "acquired")).toBe("acquired");
|
|
23
|
+
// The successful contender also rewrites its ticket atomically once.
|
|
24
|
+
expect(attempts).toBe(3);
|
|
25
|
+
} finally {
|
|
26
|
+
writer.mockRestore();
|
|
27
|
+
cleanup();
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
11
31
|
async function holder(root: string) {
|
|
12
32
|
const script = `
|
|
13
33
|
import { existsSync } from 'node:fs';
|
|
@@ -68,7 +68,17 @@ export function withStorageFileMutex<T>(directory: string, work: () => T, timeou
|
|
|
68
68
|
const ticket: Ticket = { choosing: true, number: 0, birth, checksum: "" };
|
|
69
69
|
const encodedTicket = () =>
|
|
70
70
|
JSON.stringify({ ...ticket, checksum: ticketChecksum(name, ticket) });
|
|
71
|
-
|
|
71
|
+
for (let attempt = 0; ; attempt++) {
|
|
72
|
+
try {
|
|
73
|
+
writeStorageFileSync(ownPath, encodedTicket(), { flag: "wx", forcePrivate: true });
|
|
74
|
+
break;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
// A session cleanup can remove an empty directory between mkdir and
|
|
77
|
+
// ticket creation. No ticket exists yet, so retry before contending.
|
|
78
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT" || attempt >= 2) throw error;
|
|
79
|
+
ensurePrivateStorageDirectorySync(directory);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
72
82
|
const deadline = performance.now() + timeoutMs;
|
|
73
83
|
const peers = (): [string, Ticket | null][] => {
|
|
74
84
|
const found: [string, Ticket | null][] = [];
|
|
@@ -64,6 +64,8 @@ export interface SubagentRunOptions {
|
|
|
64
64
|
agent: string;
|
|
65
65
|
systemPrompt: string;
|
|
66
66
|
userMessage: string;
|
|
67
|
+
/** Hidden historian only: use `write` to retain cache markers for retries or later turns. */
|
|
68
|
+
cacheTail?: import("./historian-cache").HistorianCacheTail;
|
|
67
69
|
model?: string | undefined;
|
|
68
70
|
fallbackModels?: readonly ModelInput[];
|
|
69
71
|
timeoutMs?: number | undefined;
|
|
@@ -5,5 +5,23 @@ export function isSystemDirective(text: string): boolean {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export function removeSystemReminders(text: string): string {
|
|
8
|
-
return text
|
|
8
|
+
return removeNestedBlocks(text, ["system-reminder"]).trim();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Remove matching tagged regions, including nested regions and regions with no closing tag. */
|
|
12
|
+
export function removeNestedBlocks(text: string, names: readonly string[]): string {
|
|
13
|
+
const tags = new RegExp(`<(/?)(${names.join("|")})(?:\\s[^<>]*?)?\\s*(/?)>`, "gi");
|
|
14
|
+
const stack: string[] = [];
|
|
15
|
+
let end = 0;
|
|
16
|
+
let result = "";
|
|
17
|
+
for (const match of text.matchAll(tags)) {
|
|
18
|
+
if (stack.length === 0) result += text.slice(end, match.index);
|
|
19
|
+
const name = match[2].toLowerCase();
|
|
20
|
+
if (match[1]) {
|
|
21
|
+
if (stack[stack.length - 1] === name) stack.pop();
|
|
22
|
+
} else if (!match[3]) stack.push(name);
|
|
23
|
+
end = match.index + match[0].length;
|
|
24
|
+
}
|
|
25
|
+
if (stack.length === 0) result += text.slice(end);
|
|
26
|
+
return result;
|
|
9
27
|
}
|
|
@@ -835,12 +835,17 @@ class ConversationEndGuard {
|
|
|
835
835
|
}
|
|
836
836
|
}
|
|
837
837
|
|
|
838
|
-
wouldStrand(
|
|
838
|
+
wouldStrand(
|
|
839
|
+
occurrences: readonly ToolOccurrence[],
|
|
840
|
+
plannedRemovals?: ReadonlySet<unknown>,
|
|
841
|
+
): boolean {
|
|
839
842
|
const end = this.end;
|
|
840
843
|
if (!end || !occurrences.some((occ) => occ.message === end)) return false;
|
|
841
844
|
const leaving = new Set(occurrences.map((occ) => partKey(occ.part)));
|
|
842
845
|
const survives = (part: TranscriptPart) =>
|
|
843
|
-
!leaving.has(partKey(part)) &&
|
|
846
|
+
!leaving.has(partKey(part)) &&
|
|
847
|
+
!this.removed.has(partKey(part)) &&
|
|
848
|
+
!plannedRemovals?.has(partKey(part));
|
|
844
849
|
return end.info.role === "assistant"
|
|
845
850
|
? !end.parts.some((part) => part.kind === "tool_result" && survives(part))
|
|
846
851
|
: !end.parts.some((part) => partHasContent(part) && survives(part));
|
|
@@ -1380,8 +1385,11 @@ function buildAggregateTarget(
|
|
|
1380
1385
|
}
|
|
1381
1386
|
return null;
|
|
1382
1387
|
},
|
|
1383
|
-
wouldStrandConversationEnd(): boolean {
|
|
1384
|
-
return conversationEnd?.wouldStrand(occurrences) ?? false;
|
|
1388
|
+
wouldStrandConversationEnd(plannedRemovals): boolean {
|
|
1389
|
+
return conversationEnd?.wouldStrand(occurrences, plannedRemovals) ?? false;
|
|
1390
|
+
},
|
|
1391
|
+
notePlannedRemoval(plannedRemovals): void {
|
|
1392
|
+
for (const occ of occurrences) plannedRemovals.add(partKey(occ.part));
|
|
1385
1393
|
},
|
|
1386
1394
|
editMarker(): "truncated" | "absent" {
|
|
1387
1395
|
// Edit-marker: preserve the tool_use input's filePath + a region
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ensureMemoryEmbeddings2
|
|
3
|
-
} from "./server-aavz8pm6.js";
|
|
4
|
-
import"./server-kr2kc9dz.js";
|
|
5
|
-
import"./server-4dhv7mqz.js";
|
|
6
|
-
import"./server-qt1qqasc.js";
|
|
7
|
-
import"./server-gha9x4qq.js";
|
|
8
|
-
import"./server-271qxsf5.js";
|
|
9
|
-
import"./server-hgg55hde.js";
|
|
10
|
-
import"./server-kqpawe1a.js";
|
|
11
|
-
import"./server-rrqpvwqd.js";
|
|
12
|
-
import"./server-e3ftpk7v.js";
|
|
13
|
-
import"./server-785mb90s.js";
|
|
14
|
-
import"./server-6714jebr.js";
|
|
15
|
-
import"./server-51779zs2.js";
|
|
16
|
-
import"./server-6pmqg9m4.js";
|
|
17
|
-
import"./server-0ppsweh6.js";
|
|
18
|
-
import"./server-wafzvyhg.js";
|
|
19
|
-
import"./server-f2xf5gcb.js";
|
|
20
|
-
import"./server-pavzsdc6.js";
|
|
21
|
-
export {
|
|
22
|
-
ensureMemoryEmbeddings2 as ensureMemoryEmbeddings
|
|
23
|
-
};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
runManagedWrapup2
|
|
3
|
-
} from "./index-v9asb16b.js";
|
|
4
|
-
import"./index-v63beg1z.js";
|
|
5
|
-
import"./index-ayym1x7f.js";
|
|
6
|
-
import"./index-f71thw8j.js";
|
|
7
|
-
import"./index-wv9n2zcq.js";
|
|
8
|
-
import"./index-p4vde22c.js";
|
|
9
|
-
import"./index-sd3egckz.js";
|
|
10
|
-
import"./index-9nkg2dzk.js";
|
|
11
|
-
import"./index-qrahzcqv.js";
|
|
12
|
-
import"./index-n78avt2p.js";
|
|
13
|
-
import"./index-4dhv7mqz.js";
|
|
14
|
-
import"./index-v10f1rjv.js";
|
|
15
|
-
import"./index-b17m64g9.js";
|
|
16
|
-
import"./index-qt1qqasc.js";
|
|
17
|
-
import"./index-j6zw70pf.js";
|
|
18
|
-
import"./index-nd7m2a5a.js";
|
|
19
|
-
import"./index-1zx87sdm.js";
|
|
20
|
-
import"./index-mtw9e71a.js";
|
|
21
|
-
import"./index-x8a7jmkh.js";
|
|
22
|
-
import"./index-y9f76s3f.js";
|
|
23
|
-
import"./index-7b2cfmaz.js";
|
|
24
|
-
import"./index-wgypt3cs.js";
|
|
25
|
-
import"./index-saews2s3.js";
|
|
26
|
-
import"./index-hehkf6zm.js";
|
|
27
|
-
import"./index-fkx2qnvw.js";
|
|
28
|
-
import"./index-cj9g0j7a.js";
|
|
29
|
-
import"./index-fb3zxn06.js";
|
|
30
|
-
import"./index-wk0n1cgt.js";
|
|
31
|
-
import"./index-a8bvhwqs.js";
|
|
32
|
-
import"./index-dqe8pq4x.js";
|
|
33
|
-
import"./index-fr0wbhdn.js";
|
|
34
|
-
import"./index-nj7yykkx.js";
|
|
35
|
-
import"./index-n6m03s3n.js";
|
|
36
|
-
import"./index-bp5083x2.js";
|
|
37
|
-
import"./index-58e3y90n.js";
|
|
38
|
-
import"./index-7pa32z07.js";
|
|
39
|
-
import"./index-v0p37hm2.js";
|
|
40
|
-
import"./index-k29z4aqh.js";
|
|
41
|
-
import"./index-hqkczed7.js";
|
|
42
|
-
import"./index-wafzvyhg.js";
|
|
43
|
-
import"./index-j75v2476.js";
|
|
44
|
-
import"./index-g2q4htwp.js";
|
|
45
|
-
import"./index-pavzsdc6.js";
|
|
46
|
-
export {
|
|
47
|
-
runManagedWrapup2 as runManagedWrapup
|
|
48
|
-
};
|