@cortexkit/opencode-magic-context 0.47.0 → 0.48.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/agents/magic-context-prompt.d.ts +1 -1
- package/dist/agents/magic-context-prompt.d.ts.map +1 -1
- package/dist/{announcement-y35wzg2r.js → announcement-fp14dw0n.js} +3 -2
- package/dist/auto-search-worker.js +27 -30
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/mural-model-deprecation.d.ts +15 -0
- package/dist/config/mural-model-deprecation.d.ts.map +1 -0
- package/dist/config/project-security.d.ts +0 -3
- package/dist/config/project-security.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +10 -6
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/{conflict-warning-hook-z44ynfz7.js → conflict-warning-hook-w8cykrnf.js} +12 -10
- package/dist/{context-wq4ffwyb.js → context-m0cy262m.js} +2690 -1903
- package/dist/{derive-budgets-ke12jnnh.js → derive-budgets-sg0xsq7s.js} +4 -3
- package/dist/embedding-activity-g1dhes6g.js +10 -0
- package/dist/embedding-backfill-9rcm1mfy.js +21 -0
- package/dist/embedding-cache-mgyr73ef.js +16 -0
- package/dist/embedding-worker.js +11 -9
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts +1 -0
- package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-config.d.ts +3 -3
- package/dist/features/magic-context/dreamer/task-config.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-executor.d.ts +1 -1
- package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-registry.d.ts +1 -0
- package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
- package/dist/features/magic-context/message-index-async.d.ts +16 -3
- package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
- package/dist/features/magic-context/message-index-bounded.d.ts +17 -0
- package/dist/features/magic-context/message-index-bounded.d.ts.map +1 -0
- package/dist/features/magic-context/message-index.d.ts +7 -1
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/mural/render-trigger.d.ts +7 -4
- package/dist/features/magic-context/mural/render-trigger.d.ts.map +1 -1
- package/dist/features/magic-context/pi-content-decisions.d.ts +7 -1
- package/dist/features/magic-context/pi-content-decisions.d.ts.map +1 -1
- package/dist/features/magic-context/search.d.ts +29 -0
- package/dist/features/magic-context/search.d.ts.map +1 -1
- package/dist/features/magic-context/session-activity.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/runner.d.ts +1 -0
- package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-session.d.ts +6 -0
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tag-identity-revision.d.ts +30 -0
- package/dist/features/magic-context/storage-tag-identity-revision.d.ts.map +1 -0
- package/dist/features/magic-context/storage-tags.d.ts +144 -4
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -1
- package/dist/features/magic-context/transform-decision-log.d.ts +1 -1
- package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
- package/dist/harness-e4avh192.js +10 -0
- package/dist/hooks/magic-context/active-anthropic-turn.d.ts +2 -0
- package/dist/hooks/magic-context/active-anthropic-turn.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-worker-client.d.ts +32 -3
- package/dist/hooks/magic-context/auto-search-worker-client.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +1 -0
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +1 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-persist.d.ts +4 -3
- package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-replay.d.ts +13 -8
- package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-slot.d.ts +139 -2
- package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
- package/dist/hooks/magic-context/message-search-accepting-silent-worker.fixture.d.ts +2 -0
- package/dist/hooks/magic-context/message-search-accepting-silent-worker.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/oc-stall-r2-warmup-worker.fixture.d.ts +2 -0
- package/dist/hooks/magic-context/oc-stall-r2-warmup-worker.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/oc-stall-search-review.fixture.d.ts +2 -0
- package/dist/hooks/magic-context/oc-stall-search-review.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/opencode1-to-model-messages.fixture.d.ts +63 -0
- package/dist/hooks/magic-context/opencode1-to-model-messages.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/provider-visible-parts.d.ts +45 -0
- package/dist/hooks/magic-context/provider-visible-parts.d.ts.map +1 -0
- package/dist/hooks/magic-context/raw-ordinal-warmup-silent-worker.fixture.d.ts +2 -0
- package/dist/hooks/magic-context/raw-ordinal-warmup-silent-worker.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/raw-ordinal-warmup-worker.d.ts +2 -0
- package/dist/hooks/magic-context/raw-ordinal-warmup-worker.d.ts.map +1 -0
- package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts +87 -0
- package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts.map +1 -0
- package/dist/hooks/magic-context/read-session-chunk.d.ts +12 -0
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-formatting.d.ts +5 -0
- package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-raw.d.ts +83 -1
- package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
- package/dist/hooks/magic-context/reasoning-budget.d.ts.map +1 -1
- package/dist/hooks/magic-context/sentinel.d.ts +41 -1
- package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts +14 -2
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts +1 -0
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts +8 -0
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-owner-warmup.d.ts +6 -0
- package/dist/hooks/magic-context/tag-owner-warmup.d.ts.map +1 -0
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
- package/dist/hooks/magic-context/token-count-exact.d.ts +35 -0
- package/dist/hooks/magic-context/token-count-exact.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +8 -2
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
- package/dist/{index-w2t4ah5j.js → index-0an7742d.js} +14072 -14286
- package/dist/index-0qhce371.js +120 -0
- package/dist/{index-q6hef7fh.js → index-0sahzkwr.js} +6 -19
- package/dist/{index-k5bdx1bx.js → index-0w56v4fm.js} +3 -5
- package/dist/index-14cjxt20.js +819 -0
- package/dist/{v2/server-51dv1pr5.js → index-1qb0z7wa.js} +301 -27
- package/dist/index-2bvekkfy.js +11 -0
- package/dist/{index-sj29b3z2.js → index-2y0s2hep.js} +3 -3
- package/dist/index-4dhv7mqz.js +131 -0
- package/dist/{index-b35pxds2.js → index-58e3y90n.js} +1 -18
- package/dist/index-5zygecde.js +152 -0
- package/dist/{index-6d9e1m08.js → index-692jzy0p.js} +17775 -17450
- package/dist/index-72nhv486.js +2307 -0
- package/dist/index-7jzrrxap.js +931 -0
- package/dist/{v2/server-njt3np1k.js → index-7mx8v0pw.js} +220 -961
- package/dist/index-8ajstryz.js +18 -0
- package/dist/{index-sfpzqvdz.js → index-8cd2j99z.js} +2 -3
- package/dist/{index-hybnrwq0.js → index-8j7gqj40.js} +131 -128
- package/dist/index-bdckkfw6.js +3261 -0
- package/dist/{index-m5fe6jch.js → index-bhvjj0ys.js} +152 -2453
- package/dist/index-c43kr12f.js +3030 -0
- package/dist/index-cb7emxgj.js +984 -0
- package/dist/index-d9vfe7xq.js +16 -0
- package/dist/{index-5gq3b2ya.js → index-db7zwa3v.js} +147 -209
- package/dist/index-dhwzyd54.js +1142 -0
- package/dist/{index-8da2zjhz.js → index-eeezr5zz.js} +9 -7
- package/dist/{index-cwf6s3ay.js → index-f0h6xwqm.js} +2828 -2618
- package/dist/index-fb3zxn06.js +13 -0
- package/dist/index-fbv1dn35.js +171 -0
- package/dist/index-fr0wbhdn.js +43 -0
- package/dist/{index-mc22ayvf.js → index-ghc9f0n7.js} +11 -9
- package/dist/{index-fzbvakh0.js → index-jcbd3znx.js} +3 -3
- package/dist/{index-5a2r0p9f.js → index-k1xb52kd.js} +20 -13
- package/dist/index-k9nnwad5.js +3532 -0
- package/dist/{index-wx8a6bw3.js → index-kb9nn0a0.js} +270 -53
- package/dist/index-knh4y330.js +566 -0
- package/dist/{v2/server-fq7kq32k.js → index-mfkzp7qj.js} +1 -16
- package/dist/{index-gg8j07zz.js → index-mmyh6d8f.js} +4 -4
- package/dist/index-pavzsdc6.js +17 -0
- package/dist/{index-0c82743p.js → index-pdecwzrd.js} +17 -15
- package/dist/index-pg50n748.js +1060 -0
- package/dist/{index-92bp57hg.js → index-q2tqeqde.js} +123 -80
- package/dist/{index-rrrsepyw.js → index-q7h7csab.js} +90 -85
- package/dist/{v2/server-yr3zj7e7.js → index-qt1qqasc.js} +6 -7
- package/dist/{index-6wkcswft.js → index-ty64eqcn.js} +28 -18
- package/dist/{index-adwfkpex.js → index-yq8n9qcb.js} +23 -23
- package/dist/{index-9pk9exrb.js → index-z8e0psj8.js} +18 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +586 -344
- package/dist/logger-d3wex3dz.js +20 -0
- package/dist/message-index-bounded-7ezbgddp.js +124 -0
- package/dist/{v2/message-time-backfill-1f9tzvcs.js → message-time-backfill-brbd63hv.js} +8 -6
- package/dist/migration-worker.js +25 -18
- package/dist/{model-resolution-xhfmyyvy.js → model-resolution-nx97z3x7.js} +1 -1
- package/dist/plugin/dream-timer.d.ts +1 -1
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +1 -0
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/host-stall-profiler-report.d.ts +1 -66
- package/dist/plugin/host-stall-profiler-report.d.ts.map +1 -1
- package/dist/plugin/host-stall-profiler.d.ts +2 -95
- package/dist/plugin/host-stall-profiler.d.ts.map +1 -1
- package/dist/plugin/messages-transform.d.ts +0 -13
- package/dist/plugin/messages-transform.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/plugin/tool-registry.d.ts.map +1 -1
- package/dist/project-embedding-registry-7qzptcw7.js +88 -0
- package/dist/raw-ordinal-warmup-worker.js +60 -0
- package/dist/{read-session-chunk-4jey7hpt.js → read-session-chunk-6k83m4fj.js} +15 -9
- package/dist/read-session-raw-3g9qy1xa.js +58 -0
- package/dist/recomp-orchestrator-d3fp1cy0.js +57 -0
- package/dist/{v2/safe-notification-target-eb1n1vfb.js → safe-notification-target-5ffqq32m.js} +4 -2
- package/dist/search-epax1ecv.js +45 -0
- package/dist/{v2/send-session-notification-c0wtscea.js → send-session-notification-erecz4y4.js} +10 -7
- package/dist/shared/conflict-detector.d.ts.map +1 -1
- package/dist/shared/host-stall-profiler-bun.d.ts +46 -0
- package/dist/shared/host-stall-profiler-bun.d.ts.map +1 -0
- package/dist/shared/host-stall-profiler-common.d.ts +58 -0
- package/dist/shared/host-stall-profiler-common.d.ts.map +1 -0
- package/dist/shared/host-stall-profiler-node.d.ts +36 -0
- package/dist/shared/host-stall-profiler-node.d.ts.map +1 -0
- package/dist/shared/host-stall-profiler-report.d.ts +68 -0
- package/dist/shared/host-stall-profiler-report.d.ts.map +1 -0
- package/dist/shared/host-stall-profiler.d.ts +5 -0
- package/dist/shared/host-stall-profiler.d.ts.map +1 -0
- package/dist/shared/model-resolution.d.ts +2 -3
- package/dist/shared/model-resolution.d.ts.map +1 -1
- package/dist/shared/sqlite.d.ts +30 -0
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/shared/stable-json.d.ts.map +1 -1
- package/dist/shared/user-facing-codes.d.ts +0 -5
- package/dist/shared/user-facing-codes.d.ts.map +1 -1
- package/dist/sqlite-context-pragmas-mv9jqwjh.js +6 -0
- package/dist/sqlite-mhjkerzq.js +46 -0
- package/dist/storage-memory-07fx57k6.js +71 -0
- package/dist/storage-tags-d3b0v2ss.js +131 -0
- package/dist/{task-config-v81k8jvk.js → task-config-cgpg0nvh.js} +2 -2
- package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
- package/dist/tools/ctx-note/constants.d.ts +4 -0
- package/dist/tools/ctx-note/constants.d.ts.map +1 -1
- package/dist/tools/ctx-note/tools.d.ts +1 -0
- package/dist/tools/ctx-note/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/tools.d.ts.map +1 -1
- package/dist/tools/parameter-descriptions.d.ts +2 -2
- package/dist/tools/parameter-descriptions.d.ts.map +1 -1
- package/dist/{transform-postprocess-phase-z5hzpsxv.js → transform-postprocess-phase-spcy2qre.js} +35 -20
- package/dist/transformers-node-wasm.js +18415 -18415
- package/dist/v2/auto-search-worker.js +27 -30
- package/dist/v2/{context-14v1hr8b.js → context-sf98kstd.js} +3737 -3004
- package/dist/v2/{derive-budgets-nc9avxz8.js → derive-budgets-3vc0y84t.js} +4 -3
- package/dist/v2/embedding-activity-g1dhes6g.js +10 -0
- package/dist/v2/embedding-backfill-vn8g1nh1.js +21 -0
- package/dist/v2/embedding-cache-mgyr73ef.js +16 -0
- package/dist/v2/embedding-worker.js +12 -9
- package/dist/v2/fold/host-media.d.ts +4 -0
- package/dist/v2/fold/host-media.d.ts.map +1 -1
- package/dist/v2/fold/memory-cache.d.ts +70 -0
- package/dist/v2/fold/memory-cache.d.ts.map +1 -0
- package/dist/v2/fold/native-codec.d.ts +10 -0
- package/dist/v2/fold/native-codec.d.ts.map +1 -0
- package/dist/v2/fold/native-replay.d.ts +58 -0
- package/dist/v2/fold/native-replay.d.ts.map +1 -0
- package/dist/v2/fold/policy.d.ts +24 -0
- package/dist/v2/fold/policy.d.ts.map +1 -0
- package/dist/v2/harness-e4avh192.js +10 -0
- package/dist/v2/hooks/context.d.ts +2 -2
- package/dist/v2/hooks/context.d.ts.map +1 -1
- package/dist/v2/hooks/dream-manual.d.ts +1 -1
- package/dist/v2/hooks/dream-manual.d.ts.map +1 -1
- package/dist/v2/hooks/dream-timer.d.ts.map +1 -1
- package/dist/v2/hooks/dream-trigger.d.ts +1 -2
- package/dist/v2/hooks/dream-trigger.d.ts.map +1 -1
- package/dist/v2/hooks/payload.d.ts.map +1 -1
- package/dist/v2/hooks/tools.d.ts.map +1 -1
- package/dist/v2/hooks/types.d.ts +6 -0
- package/dist/v2/hooks/types.d.ts.map +1 -1
- package/dist/v2/logger-mxd0ym09.js +19 -0
- package/dist/v2/message-index-bounded-dy3s2k1e.js +123 -0
- package/dist/{message-time-backfill-r5epkzj3.js → v2/message-time-backfill-gtx1pwk1.js} +7 -7
- package/dist/v2/migration-worker.js +24 -17
- package/dist/v2/{model-resolution-xhfmyyvy.js → model-resolution-nx97z3x7.js} +1 -1
- package/dist/v2/project-embedding-registry-1tgba5dv.js +86 -0
- package/dist/v2/raw-ordinal-warmup-worker.js +60 -0
- package/dist/v2/{read-session-chunk-gyyv7w2r.js → read-session-chunk-rh4khdkv.js} +14 -8
- package/dist/v2/read-session-raw-bsbmf0vj.js +57 -0
- package/dist/v2/recomp-orchestrator-az61rfcg.js +57 -0
- package/dist/{safe-notification-target-43r8jsxw.js → v2/safe-notification-target-73ax1p5v.js} +3 -3
- package/dist/v2/search-nzkwrc6n.js +45 -0
- package/dist/{send-session-notification-0m68ms3n.js → v2/send-session-notification-6km439kn.js} +9 -8
- package/dist/{index-5eqk6z3s.js → v2/server-1r6pmz4f.js} +301 -27
- package/dist/v2/server-2bvekkfy.js +11 -0
- package/dist/v2/server-2fbhp79z.js +3205 -0
- package/dist/v2/{server-ajzeteqw.js → server-2ra6pwf3.js} +1 -18
- package/dist/v2/server-4dhv7mqz.js +131 -0
- package/dist/v2/{server-y10vbq6y.js → server-4k748ke6.js} +11 -1053
- package/dist/v2/{server-vs5gpnd4.js → server-52awr2mw.js} +81 -145
- package/dist/v2/{server-1qbnzc80.js → server-5m3dt5r1.js} +136 -148
- package/dist/v2/server-686jg6eb.js +3508 -0
- package/dist/v2/server-7jzrrxap.js +931 -0
- package/dist/v2/server-7wwc2nga.js +3023 -0
- package/dist/v2/server-8ajstryz.js +18 -0
- package/dist/v2/{server-sfpzqvdz.js → server-8cd2j99z.js} +2 -3
- package/dist/v2/{server-d0sraw7m.js → server-8pyt7hev.js} +291 -286
- package/dist/v2/server-8tqanswc.js +984 -0
- package/dist/v2/{server-14vq4kpm.js → server-aan4q8mx.js} +3 -3
- package/dist/v2/server-d9vfe7xq.js +16 -0
- package/dist/{index-x3kwrmqk.js → v2/server-e0vdaae2.js} +35 -792
- package/dist/v2/server-ezhze64f.js +1048 -0
- package/dist/v2/server-fb3zxn06.js +13 -0
- package/dist/v2/server-fr0wbhdn.js +43 -0
- package/dist/v2/server-g5r0n3b6.js +1137 -0
- package/dist/v2/server-gjcr4w98.js +154 -0
- package/dist/v2/server-k228xhjg.js +171 -0
- package/dist/v2/{server-nf82q6pt.js → server-k8x2rbxc.js} +5946 -5602
- package/dist/v2/{server-wx8a6bw3.js → server-kb9nn0a0.js} +270 -53
- package/dist/{index-rrbbspwh.js → v2/server-mfkzp7qj.js} +1 -16
- package/dist/v2/server-pavzsdc6.js +17 -0
- package/dist/v2/{server-e0c1b7a7.js → server-psqc7e9n.js} +122 -79
- package/dist/{index-yr3zj7e7.js → v2/server-qt1qqasc.js} +6 -7
- package/dist/v2/server-qye6ykf7.js +120 -0
- package/dist/v2/{server-qdjnb2z1.js → server-r5p3b1wy.js} +11 -9
- package/dist/v2/server-sggvvzhb.js +759 -0
- package/dist/v2/{server-cpepxy2q.js → server-v06jcv0w.js} +14 -12
- package/dist/v2/server-vqpf3167.js +1048 -0
- package/dist/v2/{server-rz514f14.js → server-x2g40a71.js} +2044 -2060
- package/dist/v2/{server-vd4e7174.js → server-xdfwt6kh.js} +20 -16
- package/dist/v2/{server-efhwzx05.js → server-xxm59eww.js} +23 -23
- package/dist/v2/server-yczc713m.js +564 -0
- package/dist/v2/{server-fcdehk1s.js → server-z2037m6z.js} +4 -4
- package/dist/v2/{server-50hvkg3v.js → server-zm570tr2.js} +160 -158
- package/dist/v2/{server-6r257mf5.js → server-zxhgvsf9.js} +3 -3
- package/dist/v2/server.js +16 -14
- package/dist/v2/sqlite-context-pragmas-mv9jqwjh.js +6 -0
- package/dist/v2/sqlite-mhjkerzq.js +46 -0
- package/dist/v2/storage-memory-07fx57k6.js +71 -0
- package/dist/v2/storage-tags-w4tv77sn.js +130 -0
- package/dist/v2/store-reader.d.ts +16 -0
- package/dist/v2/store-reader.d.ts.map +1 -1
- package/dist/v2/{task-config-tbndqyny.js → task-config-x0hq3qfd.js} +2 -2
- package/dist/v2/transformers-node-wasm.js +18415 -18415
- package/dist/v2/tui/index.d.ts.map +1 -1
- package/dist/v2/tui/types.d.ts +1 -10
- package/dist/v2/tui/types.d.ts.map +1 -1
- package/dist/v2/{wrapup-orchestrator-nbz854vc.js → wrapup-orchestrator-mz7efs7w.js} +51 -30
- package/dist/wrapup-orchestrator-amzta1t4.js +44 -0
- package/package.json +4 -3
- package/src/agents/magic-context-prompt.ts +27 -2
- package/src/agents/smart-notes-enabled.test.ts +294 -0
- package/src/agents/smart-notes-on.golden.json +70 -0
- package/src/config/index.test.ts +67 -1
- package/src/config/index.ts +2 -0
- package/src/config/latch-permanence-guard.test.ts +4 -0
- package/src/config/mural-model-deprecation.ts +24 -0
- package/src/config/project-security.hostile-matrix.test.ts +4 -44
- package/src/config/project-security.test.ts +9 -14
- package/src/config/project-security.ts +13 -55
- package/src/config/schema/magic-context.test.ts +2 -2
- package/src/config/schema/magic-context.ts +16 -10
- package/src/features/magic-context/dreamer/task-registry.ts +6 -0
- package/src/shared/conflict-detector.test.ts +56 -0
- package/src/shared/conflict-detector.ts +16 -5
- package/src/shared/host-stall-profiler-bun.ts +358 -0
- package/src/shared/host-stall-profiler-common.ts +159 -0
- package/src/shared/host-stall-profiler-node.test.ts +234 -0
- package/src/shared/host-stall-profiler-node.ts +274 -0
- package/src/shared/host-stall-profiler-report.ts +248 -0
- package/src/shared/host-stall-profiler.ts +57 -0
- package/src/shared/model-resolution.test.ts +54 -17
- package/src/shared/model-resolution.ts +6 -17
- package/src/shared/sqlite.test.ts +52 -0
- package/src/shared/sqlite.ts +339 -23
- package/src/shared/stable-json-linear.test.ts +109 -0
- package/src/shared/stable-json.ts +37 -7
- package/src/shared/user-facing-codes.ts +2 -6
- package/src/shared/write-transaction-attribution.test.ts +2 -2
- package/src/v2/tui/host-contract.test.ts +41 -67
- package/src/v2/tui/index.ts +6 -214
- package/src/v2/tui/types.ts +5 -17
- package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts +0 -45
- package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts.map +0 -1
- package/dist/features/magic-context/checkout-claim.d.ts +0 -155
- package/dist/features/magic-context/checkout-claim.d.ts.map +0 -1
- package/dist/index-bb36vgr3.js +0 -6608
- package/dist/index-fnn5pjtt.js +0 -6554
- package/dist/recomp-orchestrator-rervg6q4.js +0 -42
- package/dist/v2/recomp-orchestrator-42vjba7p.js +0 -42
- package/dist/v2/server-3trjk1hx.js +0 -6360
- package/dist/v2/server-nm9n3aqq.js +0 -6461
- package/dist/wrapup-orchestrator-b2dztrar.js +0 -29
- /package/dist/{index-5prbx026.js → index-2pp04pmg.js} +0 -0
- /package/dist/v2/{index-5prbx026.js → index-2pp04pmg.js} +0 -0
|
@@ -1,610 +1,244 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
V2_MEMORY_CATEGORIES
|
|
3
|
+
} from "./index-fr0wbhdn.js";
|
|
4
|
+
import {
|
|
5
|
+
log2
|
|
6
|
+
} from "./index-8j7gqj40.js";
|
|
5
7
|
import {
|
|
6
8
|
ensureColumn,
|
|
7
9
|
healAllNullColumns,
|
|
8
10
|
installV95PerfSchema
|
|
9
|
-
} from "./
|
|
11
|
+
} from "./index-db7zwa3v.js";
|
|
10
12
|
import {
|
|
11
13
|
resolveOpenCodeDbPath,
|
|
12
14
|
openCodeDbPathExists,
|
|
13
15
|
getOpenCodeDbProbeDescriptions
|
|
14
|
-
} from "./
|
|
16
|
+
} from "./index-58e3y90n.js";
|
|
15
17
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
withoutSqliteTransformPass
|
|
19
|
-
} from "./server-wx8a6bw3.js";
|
|
18
|
+
Database2
|
|
19
|
+
} from "./index-kb9nn0a0.js";
|
|
20
20
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
normalizeStoredProjectPath,
|
|
22
|
+
storedPathBelongsToIdentity
|
|
23
|
+
} from "./index-knh4y330.js";
|
|
23
24
|
import {
|
|
24
25
|
logSlowWriteTransaction
|
|
25
|
-
} from "./
|
|
26
|
-
|
|
27
|
-
// src/features/magic-context/memory/project-identity.ts
|
|
28
|
-
import { execFileSync } from "node:child_process";
|
|
29
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
30
|
-
import { existsSync, realpathSync as realpathSync2, statSync } from "node:fs";
|
|
31
|
-
import { homedir } from "node:os";
|
|
32
|
-
import path3 from "node:path";
|
|
26
|
+
} from "./index-2y0s2hep.js";
|
|
33
27
|
|
|
34
|
-
// src/features/magic-context/
|
|
28
|
+
// src/features/magic-context/lkg-prefix-chunks.ts
|
|
35
29
|
import { createHash } from "node:crypto";
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
return path.resolve(directory);
|
|
48
|
-
}
|
|
49
|
-
var realpathForCanonicalDirectory = (directory) => realpathSync.native(directory);
|
|
50
|
-
function canonicalProjectDirectory(directory) {
|
|
51
|
-
let resolved = directory;
|
|
52
|
-
try {
|
|
53
|
-
resolved = realpathForCanonicalDirectory(directory);
|
|
54
|
-
} catch {}
|
|
55
|
-
return projectDirectoryKey(resolved);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// src/features/magic-context/memory/project-identity-cache.ts
|
|
59
|
-
function cachePath(directory, storageDir = getMagicContextStorageDir()) {
|
|
60
|
-
const hash = createHash("sha256").update(projectDirectoryKey(directory)).digest("hex");
|
|
61
|
-
return path2.join(storageDir, "project-identities", `${hash}.json`);
|
|
62
|
-
}
|
|
63
|
-
function rememberGitIdentity(directory, identity) {
|
|
64
|
-
try {
|
|
65
|
-
const destination = cachePath(directory);
|
|
66
|
-
writeStorageFileAtomicSync(destination, JSON.stringify({ directory: projectDirectoryKey(directory), identity }));
|
|
67
|
-
} catch {}
|
|
68
|
-
}
|
|
69
|
-
function readRememberedGitIdentity(directory, storageDir) {
|
|
70
|
-
try {
|
|
71
|
-
const record = JSON.parse(readFileSync(cachePath(directory, storageDir), "utf8"));
|
|
72
|
-
if (record.directory === projectDirectoryKey(directory) && /^git:[0-9a-f]{7,64}$/.test(record.identity))
|
|
73
|
-
return record.identity;
|
|
74
|
-
} catch {}
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// src/features/magic-context/memory/project-identity.ts
|
|
79
|
-
var GIT_TIMEOUT_MS = 5000;
|
|
80
|
-
var TRANSIENT_FAILURE_COOLDOWN_MS = 5 * 60 * 1000;
|
|
81
|
-
var identityCache = new Map;
|
|
82
|
-
var linkedGitWorktreeCache = new Map;
|
|
83
|
-
var lastKnownGitIdentityCache = new Map;
|
|
84
|
-
var directoryFallbackCache = new Map;
|
|
85
|
-
var transientFailureCooldown = new Map;
|
|
86
|
-
var dubiousOwnershipFallbackDirectories = new Set;
|
|
87
|
-
var dubiousOwnershipLoggedDirectories = new Set;
|
|
88
|
-
var dubiousOwnershipWarnedDirectories = new Set;
|
|
89
|
-
var transientGitIdentityReuseLoggedDirectories = new Set;
|
|
90
|
-
var sessionIdentityCache = new Map;
|
|
91
|
-
var homeProjectPermission = false;
|
|
92
|
-
var homeProjectSkipLogged = false;
|
|
93
|
-
var pausedIdentityReasons = new Map;
|
|
94
|
-
var pausedIdentityLogged = new Set;
|
|
95
|
-
function setHomeProjectPermission(allowed) {
|
|
96
|
-
homeProjectPermission = allowed;
|
|
97
|
-
}
|
|
98
|
-
function shouldSkipHomeProjectMemory(directory) {
|
|
99
|
-
try {
|
|
100
|
-
assertProjectAllowed(directory, homeProjectPermission);
|
|
101
|
-
return false;
|
|
102
|
-
} catch (error) {
|
|
103
|
-
if (!(error instanceof ProjectIdentityError) || error.errorClass !== "home_project_disabled")
|
|
104
|
-
throw error;
|
|
105
|
-
if (!homeProjectSkipLogged) {
|
|
106
|
-
homeProjectSkipLogged = true;
|
|
107
|
-
log("[magic-context] home project memory disabled; skipping memory features");
|
|
30
|
+
var LKG_PREFIX_CHUNK_CHARS = 64 * 1024;
|
|
31
|
+
function splitLkgPrefix(jsonPrefix) {
|
|
32
|
+
const chunks = [];
|
|
33
|
+
let start = 0;
|
|
34
|
+
while (start < jsonPrefix.length) {
|
|
35
|
+
let end = Math.min(start + LKG_PREFIX_CHUNK_CHARS, jsonPrefix.length);
|
|
36
|
+
if (end < jsonPrefix.length) {
|
|
37
|
+
const last = jsonPrefix.charCodeAt(end - 1);
|
|
38
|
+
if (last >= 55296 && last <= 56319)
|
|
39
|
+
end -= 1;
|
|
108
40
|
}
|
|
109
|
-
|
|
41
|
+
chunks.push(jsonPrefix.slice(start, end));
|
|
42
|
+
start = end;
|
|
110
43
|
}
|
|
44
|
+
return chunks;
|
|
111
45
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
var nowMs = () => Date.now();
|
|
115
|
-
var filesystemProbeObserverForTests;
|
|
116
|
-
|
|
117
|
-
class ProjectIdentityError extends Error {
|
|
118
|
-
errorClass;
|
|
119
|
-
rawDirectory;
|
|
120
|
-
constructor(errorClass, rawDirectory, message, cause) {
|
|
121
|
-
super(message);
|
|
122
|
-
this.name = "ProjectIdentityError";
|
|
123
|
-
this.errorClass = errorClass;
|
|
124
|
-
this.rawDirectory = rawDirectory;
|
|
125
|
-
if (cause) {
|
|
126
|
-
this.cause = cause;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
46
|
+
function hashLkgChunk(body) {
|
|
47
|
+
return createHash("sha256").update(body).digest("hex");
|
|
129
48
|
}
|
|
130
|
-
function
|
|
131
|
-
return
|
|
49
|
+
function hashLkgChunkList(chunkHashes) {
|
|
50
|
+
return createHash("sha256").update(chunkHashes.join(`
|
|
51
|
+
`)).digest("hex");
|
|
132
52
|
}
|
|
133
|
-
function
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
const code = error.code;
|
|
138
|
-
return typeof code === "string" ? code : undefined;
|
|
53
|
+
function layoutLkgPrefix(jsonPrefix) {
|
|
54
|
+
const chunks = splitLkgPrefix(jsonPrefix);
|
|
55
|
+
const chunkHashes = chunks.map(hashLkgChunk);
|
|
56
|
+
return { chunks, chunkHashes, chars: jsonPrefix.length, hash: hashLkgChunkList(chunkHashes) };
|
|
139
57
|
}
|
|
140
|
-
function
|
|
141
|
-
|
|
58
|
+
function assembleLkgPrefix(expected, rows) {
|
|
59
|
+
const { chars, chunks, hash } = expected;
|
|
60
|
+
if (typeof chars !== "number" || !Number.isSafeInteger(chars) || typeof chunks !== "number" || !Number.isSafeInteger(chunks) || typeof hash !== "string" || rows.length !== chunks) {
|
|
142
61
|
return;
|
|
143
62
|
}
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
function getErrorStderr(error) {
|
|
154
|
-
if (error === null || typeof error !== "object" || !("stderr" in error)) {
|
|
155
|
-
return "";
|
|
156
|
-
}
|
|
157
|
-
const stderr = error.stderr;
|
|
158
|
-
if (typeof stderr === "string") {
|
|
159
|
-
return stderr;
|
|
160
|
-
}
|
|
161
|
-
if (Buffer.isBuffer(stderr)) {
|
|
162
|
-
return stderr.toString("utf8");
|
|
163
|
-
}
|
|
164
|
-
return "";
|
|
165
|
-
}
|
|
166
|
-
function directoryFallback(directory) {
|
|
167
|
-
const canonical = path3.resolve(directory);
|
|
168
|
-
const hash = createHash2("md5").update(canonical, "utf8").digest("hex").slice(0, 12);
|
|
169
|
-
return `dir:${hash}`;
|
|
170
|
-
}
|
|
171
|
-
function rememberedIdentityOrDirectoryFallback(canonical) {
|
|
172
|
-
return readRememberedGitIdentity(canonical) ?? directoryFallback(canonical);
|
|
173
|
-
}
|
|
174
|
-
function assertDirectoryUsable(canonicalDirectory, rawDirectory) {
|
|
175
|
-
try {
|
|
176
|
-
const stat = statSync(canonicalDirectory);
|
|
177
|
-
if (!stat.isDirectory()) {
|
|
178
|
-
throw new ProjectIdentityError("unknown", rawDirectory, `Project path is not a directory: ${canonicalDirectory}`);
|
|
179
|
-
}
|
|
180
|
-
} catch (error) {
|
|
181
|
-
if (error instanceof ProjectIdentityError) {
|
|
182
|
-
throw error;
|
|
183
|
-
}
|
|
184
|
-
const code = getErrorCode(error);
|
|
185
|
-
if (code === "EACCES" || code === "EPERM") {
|
|
186
|
-
throw new ProjectIdentityError("permission_denied", rawDirectory, `Permission denied while accessing project directory: ${canonicalDirectory}`, asError(error));
|
|
187
|
-
}
|
|
188
|
-
throw new ProjectIdentityError("unknown", rawDirectory, `Unable to access project directory: ${canonicalDirectory}`, asError(error));
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
function isGitTimeoutError(error) {
|
|
192
|
-
const code = getErrorCode(error);
|
|
193
|
-
const signal = getErrorSignal(error);
|
|
194
|
-
return code === "ETIMEDOUT" || signal === "SIGTERM" || signal === "SIGKILL" || getErrorKilled(error);
|
|
195
|
-
}
|
|
196
|
-
function hasUnbornHead(directory) {
|
|
197
|
-
const options = {
|
|
198
|
-
cwd: directory,
|
|
199
|
-
encoding: "utf8",
|
|
200
|
-
env: { ...process.env, LC_ALL: "C", LANG: "C" },
|
|
201
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
202
|
-
timeout: GIT_TIMEOUT_MS,
|
|
203
|
-
windowsHide: true
|
|
204
|
-
};
|
|
205
|
-
try {
|
|
206
|
-
execFileSyncForIdentity("git", ["rev-parse", "--git-dir"], options);
|
|
207
|
-
try {
|
|
208
|
-
execFileSyncForIdentity("git", ["rev-parse", "--verify", "--quiet", "HEAD"], options);
|
|
209
|
-
return false;
|
|
210
|
-
} catch (error) {
|
|
211
|
-
return !isGitTimeoutError(error) && typeof error === "object" && error !== null && "status" in error && error.status === 1 && getErrorStderr(error) === "";
|
|
212
|
-
}
|
|
213
|
-
} catch {
|
|
214
|
-
return false;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
function classifyGitError(error, rawDirectory) {
|
|
218
|
-
if (isGitTimeoutError(error)) {
|
|
219
|
-
return new ProjectIdentityError("git_timeout", rawDirectory, `git rev-list timed out after ${GIT_TIMEOUT_MS}ms`, asError(error));
|
|
220
|
-
}
|
|
221
|
-
const code = getErrorCode(error);
|
|
222
|
-
if (code === "ENOENT") {
|
|
223
|
-
return new ProjectIdentityError("git_missing", rawDirectory, "git binary is not available in PATH", asError(error));
|
|
224
|
-
}
|
|
225
|
-
if (code === "EACCES" || code === "EPERM") {
|
|
226
|
-
return new ProjectIdentityError("permission_denied", rawDirectory, "Permission denied while spawning git", asError(error));
|
|
227
|
-
}
|
|
228
|
-
const stderr = getErrorStderr(error).toLowerCase();
|
|
229
|
-
if (stderr.includes("detected dubious ownership")) {
|
|
230
|
-
return new ProjectIdentityError("dubious_ownership", rawDirectory, "git refused to read the repository because it detected dubious ownership", asError(error));
|
|
231
|
-
}
|
|
232
|
-
if (stderr.includes("not a git repository") || stderr.includes("does not have any commits yet") || stderr.includes("ambiguous argument 'head'") || stderr.includes("unknown revision or path")) {
|
|
233
|
-
return new ProjectIdentityError("not_git_repo", rawDirectory, "Directory has no git root commit; caller may use directory fallback", asError(error));
|
|
234
|
-
}
|
|
235
|
-
return new ProjectIdentityError("unknown", rawDirectory, "git rev-list failed while resolving project identity", asError(error));
|
|
236
|
-
}
|
|
237
|
-
function resolveProjectIdentityStrict(directory, allowHomeProject = homeProjectPermission) {
|
|
238
|
-
assertProjectAllowed(directory, allowHomeProject);
|
|
239
|
-
const canonical = path3.resolve(directory);
|
|
240
|
-
const cached = identityCache.get(canonical);
|
|
241
|
-
if (cached !== undefined) {
|
|
242
|
-
return cached;
|
|
243
|
-
}
|
|
244
|
-
assertDirectoryUsable(canonical, directory);
|
|
245
|
-
if (!hasGitDir(canonical)) {
|
|
246
|
-
throw new ProjectIdentityError("not_git_repo", directory, "Directory has no git metadata; caller may use directory fallback");
|
|
247
|
-
}
|
|
248
|
-
let output;
|
|
249
|
-
try {
|
|
250
|
-
output = execFileSyncForIdentity("git", ["rev-list", "--max-parents=0", "HEAD"], {
|
|
251
|
-
cwd: canonical,
|
|
252
|
-
encoding: "utf8",
|
|
253
|
-
env: { ...process.env, LC_ALL: "C", LANG: "C" },
|
|
254
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
255
|
-
timeout: GIT_TIMEOUT_MS,
|
|
256
|
-
windowsHide: true
|
|
257
|
-
});
|
|
258
|
-
} catch (error) {
|
|
259
|
-
const classified = classifyGitError(error, directory);
|
|
260
|
-
if (classified.errorClass === "not_git_repo" && hasUnbornHead(canonical)) {
|
|
261
|
-
throw new ProjectIdentityError("no_commits", directory, "Git repository has no commits yet");
|
|
262
|
-
}
|
|
263
|
-
throw classified;
|
|
264
|
-
}
|
|
265
|
-
const rootCommit = output.split(`
|
|
266
|
-
`).map((line) => line.trim().slice(0, 64)).filter((line) => /^[0-9a-f]{7,64}$/.test(line)).sort()[0];
|
|
267
|
-
if (!rootCommit) {
|
|
268
|
-
throw new ProjectIdentityError("unknown", directory, "git rev-list returned no valid root commit hash");
|
|
63
|
+
const bodies = [];
|
|
64
|
+
let length = 0;
|
|
65
|
+
for (let index = 0;index < rows.length; index += 1) {
|
|
66
|
+
const row = rows[index];
|
|
67
|
+
if (row?.chunk !== index || typeof row.body !== "string")
|
|
68
|
+
return;
|
|
69
|
+
bodies.push(row.body);
|
|
70
|
+
length += row.body.length;
|
|
269
71
|
}
|
|
270
|
-
|
|
271
|
-
identityCache.set(canonical, identity);
|
|
272
|
-
lastKnownGitIdentityCache.set(canonical, identity);
|
|
273
|
-
rememberGitIdentity(canonical, identity);
|
|
274
|
-
const root = gitRootDirectory(canonical);
|
|
275
|
-
if (root && root !== canonical)
|
|
276
|
-
rememberGitIdentity(root, identity);
|
|
277
|
-
transientFailureCooldown.delete(canonical);
|
|
278
|
-
dubiousOwnershipFallbackDirectories.delete(canonical);
|
|
279
|
-
transientGitIdentityReuseLoggedDirectories.delete(canonical);
|
|
280
|
-
return identity;
|
|
281
|
-
}
|
|
282
|
-
function shouldUseDirectoryFallback(error) {
|
|
283
|
-
return error.errorClass !== "home_project_disabled";
|
|
284
|
-
}
|
|
285
|
-
function getActiveCooldown(canonical) {
|
|
286
|
-
const until = transientFailureCooldown.get(canonical);
|
|
287
|
-
if (until === undefined)
|
|
288
|
-
return;
|
|
289
|
-
if (nowMs() < until)
|
|
290
|
-
return until;
|
|
291
|
-
transientFailureCooldown.delete(canonical);
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
function lastKnownGitIdentity(canonical) {
|
|
295
|
-
return lastKnownGitIdentityCache.get(canonical) ?? identityCache.get(canonical) ?? readRememberedGitIdentity(canonical);
|
|
296
|
-
}
|
|
297
|
-
function nearestLastKnownGitIdentity(canonical) {
|
|
298
|
-
const visited = new Set;
|
|
299
|
-
const walk = (start) => {
|
|
300
|
-
let current = start;
|
|
301
|
-
while (!visited.has(current)) {
|
|
302
|
-
visited.add(current);
|
|
303
|
-
const cached = lastKnownGitIdentity(current);
|
|
304
|
-
if (cached !== undefined)
|
|
305
|
-
return { identity: cached, source: current };
|
|
306
|
-
if (existsSync(path3.join(current, ".git")))
|
|
307
|
-
break;
|
|
308
|
-
const parent = path3.dirname(current);
|
|
309
|
-
if (parent === current)
|
|
310
|
-
break;
|
|
311
|
-
current = parent;
|
|
312
|
-
}
|
|
72
|
+
if (length !== chars)
|
|
313
73
|
return;
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
if (exactOrAncestor)
|
|
317
|
-
return exactOrAncestor;
|
|
318
|
-
try {
|
|
319
|
-
const realCanonical = realpathSync2.native(canonical);
|
|
320
|
-
if (realCanonical !== canonical)
|
|
321
|
-
return walk(realCanonical);
|
|
322
|
-
} catch {}
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
function reuseLastKnownGitIdentity(canonical) {
|
|
326
|
-
const cached = nearestLastKnownGitIdentity(canonical);
|
|
327
|
-
if (cached === undefined)
|
|
74
|
+
const chunkHashes = bodies.map(hashLkgChunk);
|
|
75
|
+
if (chunkHashes.some((chunkHash, index) => rows[index]?.hash !== chunkHash))
|
|
328
76
|
return;
|
|
329
|
-
if (
|
|
330
|
-
transientGitIdentityReuseLoggedDirectories.add(canonical);
|
|
331
|
-
const sourceNote = cached.source === canonical ? "" : ` from ancestor ${cached.source}`;
|
|
332
|
-
log(`[magic-context] git identity resolution is temporarily unavailable for ${canonical}; reusing the last successful project identity${sourceNote} to avoid splitting project-scoped memory`);
|
|
333
|
-
}
|
|
334
|
-
return cached.identity;
|
|
335
|
-
}
|
|
336
|
-
function formatDubiousOwnershipWarning(canonical) {
|
|
337
|
-
return `Magic Context: git refused to read ${canonical} (dubious ownership — the repo is owned by a different user). Memory features are paused unless a previous git identity is available. Fix: git config --global --add safe.directory ${canonical}`;
|
|
338
|
-
}
|
|
339
|
-
function recordDubiousOwnershipFallback(canonical) {
|
|
340
|
-
dubiousOwnershipFallbackDirectories.add(canonical);
|
|
341
|
-
if (dubiousOwnershipLoggedDirectories.has(canonical))
|
|
77
|
+
if (hashLkgChunkList(chunkHashes) !== hash)
|
|
342
78
|
return;
|
|
343
|
-
|
|
344
|
-
log(`[magic-context] ${formatDubiousOwnershipWarning(canonical)}`);
|
|
345
|
-
}
|
|
346
|
-
function takeDubiousOwnershipProjectIdentityWarning(directory) {
|
|
347
|
-
const canonical = path3.resolve(directory);
|
|
348
|
-
if (!dubiousOwnershipFallbackDirectories.has(canonical))
|
|
349
|
-
return null;
|
|
350
|
-
if (dubiousOwnershipWarnedDirectories.has(canonical))
|
|
351
|
-
return null;
|
|
352
|
-
dubiousOwnershipWarnedDirectories.add(canonical);
|
|
353
|
-
return formatDubiousOwnershipWarning(canonical);
|
|
354
|
-
}
|
|
355
|
-
function canonicalUserHomeDirectory() {
|
|
356
|
-
const homeDirectory = userHomeDirectoryForIdentity();
|
|
357
|
-
try {
|
|
358
|
-
return realpathSync2.native(homeDirectory);
|
|
359
|
-
} catch {
|
|
360
|
-
return homeDirectory;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
function isUserHomeDirectory(directory) {
|
|
364
|
-
if (projectDirectoryKey(directory) === projectDirectoryKey(userHomeDirectoryForIdentity()))
|
|
365
|
-
return true;
|
|
366
|
-
try {
|
|
367
|
-
return projectDirectoryKey(realpathSync2.native(path3.resolve(directory))) === projectDirectoryKey(canonicalUserHomeDirectory());
|
|
368
|
-
} catch {
|
|
369
|
-
return false;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
function assertProjectAllowed(directory, allowHomeProject) {
|
|
373
|
-
const canonical = path3.resolve(directory);
|
|
374
|
-
if (!allowHomeProject && (isUserHomeDirectory(directory) || isUserHomeDirectory(gitRootDirectory(canonical) ?? canonical))) {
|
|
375
|
-
throw new ProjectIdentityError("home_project_disabled", directory, "Home project memory is disabled; set allow_home_project to opt in");
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
function resolveProjectIdentity(directory, allowHomeProject = homeProjectPermission) {
|
|
379
|
-
assertProjectAllowed(directory, allowHomeProject);
|
|
380
|
-
const canonical = path3.resolve(directory);
|
|
381
|
-
const cachedFallback = directoryFallbackCache.get(canonical);
|
|
382
|
-
if (cachedFallback !== undefined) {
|
|
383
|
-
if (!hasGitDir(canonical)) {
|
|
384
|
-
return cachedFallback;
|
|
385
|
-
}
|
|
386
|
-
directoryFallbackCache.delete(canonical);
|
|
387
|
-
}
|
|
388
|
-
if (getActiveCooldown(canonical) !== undefined) {
|
|
389
|
-
if (hasGitDir(canonical)) {
|
|
390
|
-
const cachedGitIdentity = reuseLastKnownGitIdentity(canonical);
|
|
391
|
-
if (cachedGitIdentity !== undefined) {
|
|
392
|
-
return cachedGitIdentity;
|
|
393
|
-
}
|
|
394
|
-
throw new ProjectIdentityError("git_identity_unavailable", directory, "Git identity unavailable; memory features paused until the retry cooldown expires");
|
|
395
|
-
}
|
|
396
|
-
return rememberedIdentityOrDirectoryFallback(canonical);
|
|
397
|
-
}
|
|
398
|
-
try {
|
|
399
|
-
return resolveProjectIdentityStrict(directory, allowHomeProject);
|
|
400
|
-
} catch (error) {
|
|
401
|
-
if (error instanceof ProjectIdentityError && shouldUseDirectoryFallback(error)) {
|
|
402
|
-
if (error.errorClass === "no_commits")
|
|
403
|
-
return directoryFallback(canonical);
|
|
404
|
-
if (!hasGitDir(canonical)) {
|
|
405
|
-
if (error.errorClass === "permission_denied")
|
|
406
|
-
throw error;
|
|
407
|
-
const resolved = rememberedIdentityOrDirectoryFallback(canonical);
|
|
408
|
-
directoryFallbackCache.set(canonical, resolved);
|
|
409
|
-
transientFailureCooldown.delete(canonical);
|
|
410
|
-
return resolved;
|
|
411
|
-
}
|
|
412
|
-
transientFailureCooldown.set(canonical, nowMs() + TRANSIENT_FAILURE_COOLDOWN_MS);
|
|
413
|
-
const cachedGitIdentity = reuseLastKnownGitIdentity(canonical);
|
|
414
|
-
if (error.errorClass === "dubious_ownership")
|
|
415
|
-
recordDubiousOwnershipFallback(canonical);
|
|
416
|
-
if (cachedGitIdentity !== undefined) {
|
|
417
|
-
return cachedGitIdentity;
|
|
418
|
-
}
|
|
419
|
-
throw error;
|
|
420
|
-
}
|
|
421
|
-
throw error;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
function resolveProjectIdentityOrFallback(directory, allowHomeProject = homeProjectPermission) {
|
|
425
|
-
try {
|
|
426
|
-
return resolveProjectIdentity(directory, allowHomeProject);
|
|
427
|
-
} catch (error) {
|
|
428
|
-
const canonical = path3.resolve(directory);
|
|
429
|
-
if (hasGitDir(canonical) || error instanceof ProjectIdentityError && error.errorClass === "home_project_disabled")
|
|
430
|
-
throw error;
|
|
431
|
-
const fallback = rememberedIdentityOrDirectoryFallback(canonical);
|
|
432
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
433
|
-
log(`[magic-context] project identity resolution failed for ${canonical}; using directory fallback ${fallback}: ${message}`);
|
|
434
|
-
return fallback;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
function hasGitDir(canonical) {
|
|
438
|
-
if (hasGitDirInAncestorChain(canonical)) {
|
|
439
|
-
return true;
|
|
440
|
-
}
|
|
441
|
-
try {
|
|
442
|
-
const realCanonical = realpathSync2.native(canonical);
|
|
443
|
-
return realCanonical !== canonical && hasGitDirInAncestorChain(realCanonical);
|
|
444
|
-
} catch {
|
|
445
|
-
return false;
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
function gitRootInAncestorChain(startDirectory) {
|
|
449
|
-
let current = startDirectory;
|
|
450
|
-
while (true) {
|
|
451
|
-
if (existsSync(path3.join(current, ".git"))) {
|
|
452
|
-
try {
|
|
453
|
-
return realpathSync2.native(current);
|
|
454
|
-
} catch {
|
|
455
|
-
return path3.resolve(current);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
const parent = path3.dirname(current);
|
|
459
|
-
if (parent === current) {
|
|
460
|
-
return null;
|
|
461
|
-
}
|
|
462
|
-
current = parent;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
function hasGitDirInAncestorChain(startDirectory) {
|
|
466
|
-
return gitRootInAncestorChain(startDirectory) !== null;
|
|
467
|
-
}
|
|
468
|
-
function gitRootDirectory(canonical) {
|
|
469
|
-
const direct = gitRootInAncestorChain(canonical);
|
|
470
|
-
if (direct)
|
|
471
|
-
return direct;
|
|
472
|
-
try {
|
|
473
|
-
const realCanonical = realpathSync2.native(canonical);
|
|
474
|
-
return realCanonical === canonical ? null : gitRootInAncestorChain(realCanonical);
|
|
475
|
-
} catch {
|
|
476
|
-
return null;
|
|
477
|
-
}
|
|
79
|
+
return { jsonPrefix: bodies.join(""), chunkHashes, hash };
|
|
478
80
|
}
|
|
479
|
-
|
|
480
|
-
|
|
81
|
+
|
|
82
|
+
// src/features/magic-context/migration-v94-write-split.ts
|
|
83
|
+
var LKG_SLOT_CHUNKS_DDL = `
|
|
84
|
+
CREATE TABLE IF NOT EXISTS lkg_slot_chunks (
|
|
85
|
+
session_id TEXT NOT NULL,
|
|
86
|
+
chunk INTEGER NOT NULL,
|
|
87
|
+
hash TEXT NOT NULL,
|
|
88
|
+
body TEXT NOT NULL,
|
|
89
|
+
PRIMARY KEY (session_id, chunk)
|
|
90
|
+
);
|
|
91
|
+
`;
|
|
92
|
+
var SESSION_REPLAY_DECISIONS_DDL = `
|
|
93
|
+
CREATE TABLE IF NOT EXISTS session_replay_decisions (
|
|
94
|
+
session_id TEXT NOT NULL,
|
|
95
|
+
message_id TEXT NOT NULL,
|
|
96
|
+
decision TEXT NOT NULL,
|
|
97
|
+
PRIMARY KEY (session_id, message_id)
|
|
98
|
+
) WITHOUT ROWID;
|
|
99
|
+
`;
|
|
100
|
+
function lkgSlotsDdl(table) {
|
|
101
|
+
return `
|
|
102
|
+
CREATE TABLE IF NOT EXISTS ${table} (
|
|
103
|
+
session_id TEXT PRIMARY KEY,
|
|
104
|
+
json_prefix_chars INTEGER NOT NULL,
|
|
105
|
+
json_prefix_chunks INTEGER NOT NULL,
|
|
106
|
+
json_prefix_hash TEXT NOT NULL,
|
|
107
|
+
input_id_seq TEXT NOT NULL,
|
|
108
|
+
input_content_digests TEXT NOT NULL,
|
|
109
|
+
input_content_signatures TEXT,
|
|
110
|
+
last_input_message_id TEXT NOT NULL,
|
|
111
|
+
model_key TEXT,
|
|
112
|
+
provider_key TEXT,
|
|
113
|
+
captured_at INTEGER NOT NULL,
|
|
114
|
+
row_version INTEGER,
|
|
115
|
+
capture_sequence INTEGER
|
|
116
|
+
);
|
|
117
|
+
`;
|
|
481
118
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
try {
|
|
487
|
-
return realpathSync2.native(resolvedDirectory);
|
|
488
|
-
} catch {
|
|
489
|
-
return resolvedDirectory;
|
|
490
|
-
}
|
|
491
|
-
})();
|
|
492
|
-
if (isUserHomeDirectory(directory) || gitRootDirectory(canonicalDirectory) === canonicalHome) {
|
|
493
|
-
return `this session runs in your home directory (${canonicalHome}), which Magic Context does not treat as a project. ` + "Start OpenCode inside a project folder, or set `allow_home_project: true` in the user-level " + "magic-context.jsonc (~/.config/cortexkit/) to give home sessions their own memory.";
|
|
494
|
-
}
|
|
495
|
-
if (hasGitDir(resolvedDirectory))
|
|
496
|
-
return `git identity resolution for ${resolvedDirectory} is temporarily unavailable. Memory features are paused; retry after git access recovers.`;
|
|
497
|
-
return `the session directory ${resolvedDirectory} could not be read as a project.`;
|
|
119
|
+
var LKG_SLOTS_DDL = lkgSlotsDdl("lkg_slots");
|
|
120
|
+
var LKG_MOVE_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
121
|
+
function tableExists(db, name) {
|
|
122
|
+
return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name));
|
|
498
123
|
}
|
|
499
|
-
function
|
|
500
|
-
|
|
124
|
+
function columnExists(db, table, column) {
|
|
125
|
+
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
126
|
+
return rows.some((row) => row.name === column);
|
|
501
127
|
}
|
|
502
|
-
function
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
return cached.identity;
|
|
128
|
+
function splitLkgSlotPrefixes(db, now = Date.now()) {
|
|
129
|
+
db.exec(LKG_SLOT_CHUNKS_DDL);
|
|
130
|
+
if (!tableExists(db, "lkg_slots")) {
|
|
131
|
+
db.exec(LKG_SLOTS_DDL);
|
|
132
|
+
return;
|
|
508
133
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
134
|
+
if (!columnExists(db, "lkg_slots", "json_prefix"))
|
|
135
|
+
return;
|
|
136
|
+
db.prepare("DELETE FROM lkg_slots WHERE NOT (captured_at >= ?)").run(now - LKG_MOVE_WINDOW_MS);
|
|
137
|
+
db.exec("DROP TABLE IF EXISTS lkg_slots_v94");
|
|
138
|
+
db.exec(lkgSlotsDdl("lkg_slots_v94"));
|
|
139
|
+
const sessionIds = db.prepare("SELECT session_id FROM lkg_slots").all().map((row) => row.session_id);
|
|
140
|
+
const readPrefix = db.prepare("SELECT json_prefix FROM lkg_slots WHERE session_id IS ?");
|
|
141
|
+
const insertSlot = db.prepare(`INSERT OR IGNORE INTO lkg_slots_v94 (
|
|
142
|
+
session_id, json_prefix_chars, json_prefix_chunks, json_prefix_hash,
|
|
143
|
+
input_id_seq, input_content_digests, input_content_signatures,
|
|
144
|
+
last_input_message_id, model_key, provider_key,
|
|
145
|
+
captured_at, row_version, capture_sequence
|
|
146
|
+
)
|
|
147
|
+
SELECT session_id, ?, ?, ?,
|
|
148
|
+
input_id_seq, input_content_digests, input_content_signatures,
|
|
149
|
+
last_input_message_id, model_key, provider_key,
|
|
150
|
+
captured_at, row_version, capture_sequence
|
|
151
|
+
FROM lkg_slots WHERE session_id IS ?`);
|
|
152
|
+
const insertChunk = db.prepare("INSERT INTO lkg_slot_chunks (session_id, chunk, hash, body) VALUES (?, ?, ?, ?)");
|
|
153
|
+
db.prepare("DELETE FROM lkg_slot_chunks").run();
|
|
154
|
+
for (const sessionId of sessionIds) {
|
|
155
|
+
if (typeof sessionId !== "string")
|
|
156
|
+
continue;
|
|
157
|
+
const row = readPrefix.get(sessionId);
|
|
158
|
+
if (typeof row?.json_prefix !== "string")
|
|
159
|
+
continue;
|
|
160
|
+
const layout = layoutLkgPrefix(row.json_prefix);
|
|
161
|
+
const inserted = insertSlot.run(layout.chars, layout.chunks.length, layout.hash, sessionId);
|
|
162
|
+
if (Number(inserted.changes) !== 1)
|
|
163
|
+
continue;
|
|
164
|
+
for (let index = 0;index < layout.chunks.length; index += 1) {
|
|
165
|
+
insertChunk.run(sessionId, index, layout.chunkHashes[index], layout.chunks[index]);
|
|
539
166
|
}
|
|
540
167
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
sessionIdentityCache.set(cacheKey, {
|
|
544
|
-
identity,
|
|
545
|
-
revalidateAt: identity?.startsWith("git:") === true ? null : nowMs() + TRANSIENT_FAILURE_COOLDOWN_MS
|
|
546
|
-
});
|
|
547
|
-
return identity;
|
|
168
|
+
db.exec("DROP TABLE lkg_slots");
|
|
169
|
+
db.exec("ALTER TABLE lkg_slots_v94 RENAME TO lkg_slots");
|
|
548
170
|
}
|
|
549
|
-
function
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
171
|
+
function validDecisionSql(type, value) {
|
|
172
|
+
return `(${type} = 'text' AND (
|
|
173
|
+
${value} IN ('keep', 'strip') OR (
|
|
174
|
+
${value} GLOB 'keep:[1-9]*'
|
|
175
|
+
AND substr(${value}, 6) NOT GLOB '*[^0-9]*'
|
|
176
|
+
AND length(${value}) <= 10
|
|
177
|
+
AND CAST(substr(${value}, 6) AS INTEGER) BETWEEN 2 AND 10000
|
|
178
|
+
)
|
|
179
|
+
))`;
|
|
558
180
|
}
|
|
559
|
-
function
|
|
560
|
-
|
|
181
|
+
function splitReplayDecisions(db) {
|
|
182
|
+
db.exec(SESSION_REPLAY_DECISIONS_DDL);
|
|
183
|
+
if (!tableExists(db, "session_meta"))
|
|
184
|
+
return;
|
|
185
|
+
if (!columnExists(db, "session_meta", "trailing_blank_decisions"))
|
|
186
|
+
return;
|
|
187
|
+
const doc = "sm.trailing_blank_decisions";
|
|
188
|
+
const hasVersionKey = `json_type(${doc}, '$.version') IS NOT NULL`;
|
|
189
|
+
const versionIsDecision = validDecisionSql(`json_type(${doc}, '$.version')`, `json_extract(${doc}, '$.version')`);
|
|
190
|
+
const isV2 = `(${hasVersionKey} AND NOT ${versionIsDecision})`;
|
|
191
|
+
const v2Valid = `(
|
|
192
|
+
json_type(${doc}, '$.version') IN ('integer', 'real')
|
|
193
|
+
AND json_extract(${doc}, '$.version') = 2
|
|
194
|
+
AND json_type(${doc}, '$.trailingBlank') = 'object'
|
|
195
|
+
AND NOT EXISTS (
|
|
196
|
+
SELECT 1 FROM json_each(${doc}, '$.trailingBlank') AS entry
|
|
197
|
+
WHERE entry.key = '' OR NOT ${validDecisionSql("entry.type", "entry.value")}
|
|
198
|
+
)
|
|
199
|
+
)`;
|
|
200
|
+
const v1Valid = `NOT EXISTS (
|
|
201
|
+
SELECT 1 FROM json_each(${doc}) AS entry
|
|
202
|
+
WHERE entry.key = '' OR NOT ${validDecisionSql("entry.type", "entry.value")}
|
|
203
|
+
)`;
|
|
204
|
+
db.exec("DROP TABLE IF EXISTS temp.v94_replay_documents");
|
|
205
|
+
db.exec(`
|
|
206
|
+
CREATE TEMP TABLE v94_replay_documents AS
|
|
207
|
+
SELECT session_id, version FROM (
|
|
208
|
+
SELECT sm.session_id AS session_id, CASE WHEN ${isV2} THEN 2 ELSE 1 END AS version,
|
|
209
|
+
CASE WHEN ${isV2} THEN ${v2Valid} ELSE ${v1Valid} END AS strictly_valid
|
|
210
|
+
FROM session_meta AS sm
|
|
211
|
+
WHERE typeof(${doc}) = 'text' AND ${doc} <> ''
|
|
212
|
+
AND json_valid(${doc}) AND json_type(${doc}) = 'object'
|
|
213
|
+
) WHERE strictly_valid;
|
|
214
|
+
`);
|
|
215
|
+
db.exec(`
|
|
216
|
+
INSERT INTO session_replay_decisions (session_id, message_id, decision)
|
|
217
|
+
SELECT sm.session_id, entry.key, entry.value
|
|
218
|
+
FROM v94_replay_documents AS moved
|
|
219
|
+
JOIN session_meta AS sm ON sm.session_id = moved.session_id
|
|
220
|
+
JOIN json_each(
|
|
221
|
+
${doc}, CASE moved.version WHEN 2 THEN '$.trailingBlank' ELSE '$' END
|
|
222
|
+
) AS entry
|
|
223
|
+
WHERE true
|
|
224
|
+
ON CONFLICT(session_id, message_id) DO UPDATE SET decision = excluded.decision;
|
|
225
|
+
`);
|
|
226
|
+
db.exec(`
|
|
227
|
+
UPDATE session_meta SET trailing_blank_decisions = (
|
|
228
|
+
SELECT CASE moved.version
|
|
229
|
+
WHEN 2 THEN json_set(session_meta.trailing_blank_decisions, '$.trailingBlank', json('{}'))
|
|
230
|
+
ELSE ''
|
|
231
|
+
END
|
|
232
|
+
FROM v94_replay_documents AS moved WHERE moved.session_id = session_meta.session_id
|
|
233
|
+
)
|
|
234
|
+
WHERE session_id IN (SELECT session_id FROM v94_replay_documents);
|
|
235
|
+
`);
|
|
236
|
+
db.exec("DROP TABLE temp.v94_replay_documents");
|
|
561
237
|
}
|
|
562
238
|
|
|
563
239
|
// src/features/magic-context/migrations.ts
|
|
564
240
|
import { isMainThread } from "node:worker_threads";
|
|
565
241
|
|
|
566
|
-
// src/features/magic-context/memory/constants.ts
|
|
567
|
-
var V2_MEMORY_CATEGORIES = [
|
|
568
|
-
"PROJECT_RULES",
|
|
569
|
-
"ARCHITECTURE",
|
|
570
|
-
"CONSTRAINTS",
|
|
571
|
-
"CONFIG_VALUES",
|
|
572
|
-
"NAMING"
|
|
573
|
-
];
|
|
574
|
-
var PROMOTABLE_CATEGORIES = [
|
|
575
|
-
...V2_MEMORY_CATEGORIES,
|
|
576
|
-
"ARCHITECTURE_DECISIONS",
|
|
577
|
-
"CONFIG_DEFAULTS",
|
|
578
|
-
"USER_PREFERENCES",
|
|
579
|
-
"USER_DIRECTIVES",
|
|
580
|
-
"ENVIRONMENT",
|
|
581
|
-
"WORKFLOW_RULES",
|
|
582
|
-
"KNOWN_ISSUES"
|
|
583
|
-
];
|
|
584
|
-
var CATEGORY_PRIORITY = [
|
|
585
|
-
...V2_MEMORY_CATEGORIES,
|
|
586
|
-
"USER_DIRECTIVES",
|
|
587
|
-
"USER_PREFERENCES",
|
|
588
|
-
"CONFIG_DEFAULTS",
|
|
589
|
-
"ARCHITECTURE_DECISIONS",
|
|
590
|
-
"ENVIRONMENT",
|
|
591
|
-
"WORKFLOW_RULES",
|
|
592
|
-
"KNOWN_ISSUES"
|
|
593
|
-
];
|
|
594
|
-
var MEMORY_CATEGORY_ORDER_UNKNOWN = 99;
|
|
595
|
-
var MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
596
|
-
acc[category] = index;
|
|
597
|
-
return acc;
|
|
598
|
-
}, {});
|
|
599
|
-
var MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
600
|
-
function getMemoryCategoryOrder(category) {
|
|
601
|
-
return MEMORY_CATEGORY_ORDER_PRIORITY[category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
602
|
-
}
|
|
603
|
-
var CATEGORY_DEFAULT_TTL = {
|
|
604
|
-
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
605
|
-
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
606
|
-
};
|
|
607
|
-
|
|
608
242
|
// src/shared/xml-unescape.ts
|
|
609
243
|
var XML_ENTITY_REGEX = /&(amp|apos|quot|lt|gt);/g;
|
|
610
244
|
var XML_ENTITIES = {
|
|
@@ -814,7 +448,7 @@ function parseCompartmentOutput(text) {
|
|
|
814
448
|
continue;
|
|
815
449
|
droppedFactBlocks++;
|
|
816
450
|
droppedFacts += items.length;
|
|
817
|
-
|
|
451
|
+
log2(`[historian] Dropped <facts> category ${category} (${items.length} facts)`);
|
|
818
452
|
continue;
|
|
819
453
|
}
|
|
820
454
|
for (const content of items)
|
|
@@ -897,217 +531,6 @@ function parseEvents(text) {
|
|
|
897
531
|
return events;
|
|
898
532
|
}
|
|
899
533
|
|
|
900
|
-
// src/features/magic-context/lkg-prefix-chunks.ts
|
|
901
|
-
import { createHash as createHash3 } from "node:crypto";
|
|
902
|
-
var LKG_PREFIX_CHUNK_CHARS = 64 * 1024;
|
|
903
|
-
function splitLkgPrefix(jsonPrefix) {
|
|
904
|
-
const chunks = [];
|
|
905
|
-
let start = 0;
|
|
906
|
-
while (start < jsonPrefix.length) {
|
|
907
|
-
let end = Math.min(start + LKG_PREFIX_CHUNK_CHARS, jsonPrefix.length);
|
|
908
|
-
if (end < jsonPrefix.length) {
|
|
909
|
-
const last = jsonPrefix.charCodeAt(end - 1);
|
|
910
|
-
if (last >= 55296 && last <= 56319)
|
|
911
|
-
end -= 1;
|
|
912
|
-
}
|
|
913
|
-
chunks.push(jsonPrefix.slice(start, end));
|
|
914
|
-
start = end;
|
|
915
|
-
}
|
|
916
|
-
return chunks;
|
|
917
|
-
}
|
|
918
|
-
function hashLkgChunk(body) {
|
|
919
|
-
return createHash3("sha256").update(body).digest("hex");
|
|
920
|
-
}
|
|
921
|
-
function hashLkgChunkList(chunkHashes) {
|
|
922
|
-
return createHash3("sha256").update(chunkHashes.join(`
|
|
923
|
-
`)).digest("hex");
|
|
924
|
-
}
|
|
925
|
-
function layoutLkgPrefix(jsonPrefix) {
|
|
926
|
-
const chunks = splitLkgPrefix(jsonPrefix);
|
|
927
|
-
const chunkHashes = chunks.map(hashLkgChunk);
|
|
928
|
-
return { chunks, chunkHashes, chars: jsonPrefix.length, hash: hashLkgChunkList(chunkHashes) };
|
|
929
|
-
}
|
|
930
|
-
function assembleLkgPrefix(expected, rows) {
|
|
931
|
-
const { chars, chunks, hash } = expected;
|
|
932
|
-
if (typeof chars !== "number" || !Number.isSafeInteger(chars) || typeof chunks !== "number" || !Number.isSafeInteger(chunks) || typeof hash !== "string" || rows.length !== chunks) {
|
|
933
|
-
return;
|
|
934
|
-
}
|
|
935
|
-
const bodies = [];
|
|
936
|
-
let length = 0;
|
|
937
|
-
for (let index = 0;index < rows.length; index += 1) {
|
|
938
|
-
const row = rows[index];
|
|
939
|
-
if (row?.chunk !== index || typeof row.body !== "string")
|
|
940
|
-
return;
|
|
941
|
-
bodies.push(row.body);
|
|
942
|
-
length += row.body.length;
|
|
943
|
-
}
|
|
944
|
-
if (length !== chars)
|
|
945
|
-
return;
|
|
946
|
-
const chunkHashes = bodies.map(hashLkgChunk);
|
|
947
|
-
if (chunkHashes.some((chunkHash, index) => rows[index]?.hash !== chunkHash))
|
|
948
|
-
return;
|
|
949
|
-
if (hashLkgChunkList(chunkHashes) !== hash)
|
|
950
|
-
return;
|
|
951
|
-
return { jsonPrefix: bodies.join(""), chunkHashes, hash };
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
// src/features/magic-context/migration-v94-write-split.ts
|
|
955
|
-
var LKG_SLOT_CHUNKS_DDL = `
|
|
956
|
-
CREATE TABLE IF NOT EXISTS lkg_slot_chunks (
|
|
957
|
-
session_id TEXT NOT NULL,
|
|
958
|
-
chunk INTEGER NOT NULL,
|
|
959
|
-
hash TEXT NOT NULL,
|
|
960
|
-
body TEXT NOT NULL,
|
|
961
|
-
PRIMARY KEY (session_id, chunk)
|
|
962
|
-
);
|
|
963
|
-
`;
|
|
964
|
-
var SESSION_REPLAY_DECISIONS_DDL = `
|
|
965
|
-
CREATE TABLE IF NOT EXISTS session_replay_decisions (
|
|
966
|
-
session_id TEXT NOT NULL,
|
|
967
|
-
message_id TEXT NOT NULL,
|
|
968
|
-
decision TEXT NOT NULL,
|
|
969
|
-
PRIMARY KEY (session_id, message_id)
|
|
970
|
-
) WITHOUT ROWID;
|
|
971
|
-
`;
|
|
972
|
-
function lkgSlotsDdl(table) {
|
|
973
|
-
return `
|
|
974
|
-
CREATE TABLE IF NOT EXISTS ${table} (
|
|
975
|
-
session_id TEXT PRIMARY KEY,
|
|
976
|
-
json_prefix_chars INTEGER NOT NULL,
|
|
977
|
-
json_prefix_chunks INTEGER NOT NULL,
|
|
978
|
-
json_prefix_hash TEXT NOT NULL,
|
|
979
|
-
input_id_seq TEXT NOT NULL,
|
|
980
|
-
input_content_digests TEXT NOT NULL,
|
|
981
|
-
input_content_signatures TEXT,
|
|
982
|
-
last_input_message_id TEXT NOT NULL,
|
|
983
|
-
model_key TEXT,
|
|
984
|
-
provider_key TEXT,
|
|
985
|
-
captured_at INTEGER NOT NULL,
|
|
986
|
-
row_version INTEGER,
|
|
987
|
-
capture_sequence INTEGER
|
|
988
|
-
);
|
|
989
|
-
`;
|
|
990
|
-
}
|
|
991
|
-
var LKG_SLOTS_DDL = lkgSlotsDdl("lkg_slots");
|
|
992
|
-
var LKG_MOVE_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
993
|
-
function tableExists(db, name) {
|
|
994
|
-
return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name));
|
|
995
|
-
}
|
|
996
|
-
function columnExists(db, table, column) {
|
|
997
|
-
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
998
|
-
return rows.some((row) => row.name === column);
|
|
999
|
-
}
|
|
1000
|
-
function splitLkgSlotPrefixes(db, now = Date.now()) {
|
|
1001
|
-
db.exec(LKG_SLOT_CHUNKS_DDL);
|
|
1002
|
-
if (!tableExists(db, "lkg_slots")) {
|
|
1003
|
-
db.exec(LKG_SLOTS_DDL);
|
|
1004
|
-
return;
|
|
1005
|
-
}
|
|
1006
|
-
if (!columnExists(db, "lkg_slots", "json_prefix"))
|
|
1007
|
-
return;
|
|
1008
|
-
db.prepare("DELETE FROM lkg_slots WHERE NOT (captured_at >= ?)").run(now - LKG_MOVE_WINDOW_MS);
|
|
1009
|
-
db.exec("DROP TABLE IF EXISTS lkg_slots_v94");
|
|
1010
|
-
db.exec(lkgSlotsDdl("lkg_slots_v94"));
|
|
1011
|
-
const sessionIds = db.prepare("SELECT session_id FROM lkg_slots").all().map((row) => row.session_id);
|
|
1012
|
-
const readPrefix = db.prepare("SELECT json_prefix FROM lkg_slots WHERE session_id IS ?");
|
|
1013
|
-
const insertSlot = db.prepare(`INSERT OR IGNORE INTO lkg_slots_v94 (
|
|
1014
|
-
session_id, json_prefix_chars, json_prefix_chunks, json_prefix_hash,
|
|
1015
|
-
input_id_seq, input_content_digests, input_content_signatures,
|
|
1016
|
-
last_input_message_id, model_key, provider_key,
|
|
1017
|
-
captured_at, row_version, capture_sequence
|
|
1018
|
-
)
|
|
1019
|
-
SELECT session_id, ?, ?, ?,
|
|
1020
|
-
input_id_seq, input_content_digests, input_content_signatures,
|
|
1021
|
-
last_input_message_id, model_key, provider_key,
|
|
1022
|
-
captured_at, row_version, capture_sequence
|
|
1023
|
-
FROM lkg_slots WHERE session_id IS ?`);
|
|
1024
|
-
const insertChunk = db.prepare("INSERT INTO lkg_slot_chunks (session_id, chunk, hash, body) VALUES (?, ?, ?, ?)");
|
|
1025
|
-
db.prepare("DELETE FROM lkg_slot_chunks").run();
|
|
1026
|
-
for (const sessionId of sessionIds) {
|
|
1027
|
-
if (typeof sessionId !== "string")
|
|
1028
|
-
continue;
|
|
1029
|
-
const row = readPrefix.get(sessionId);
|
|
1030
|
-
if (typeof row?.json_prefix !== "string")
|
|
1031
|
-
continue;
|
|
1032
|
-
const layout = layoutLkgPrefix(row.json_prefix);
|
|
1033
|
-
const inserted = insertSlot.run(layout.chars, layout.chunks.length, layout.hash, sessionId);
|
|
1034
|
-
if (Number(inserted.changes) !== 1)
|
|
1035
|
-
continue;
|
|
1036
|
-
for (let index = 0;index < layout.chunks.length; index += 1) {
|
|
1037
|
-
insertChunk.run(sessionId, index, layout.chunkHashes[index], layout.chunks[index]);
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
db.exec("DROP TABLE lkg_slots");
|
|
1041
|
-
db.exec("ALTER TABLE lkg_slots_v94 RENAME TO lkg_slots");
|
|
1042
|
-
}
|
|
1043
|
-
function validDecisionSql(type, value) {
|
|
1044
|
-
return `(${type} = 'text' AND (
|
|
1045
|
-
${value} IN ('keep', 'strip') OR (
|
|
1046
|
-
${value} GLOB 'keep:[1-9]*'
|
|
1047
|
-
AND substr(${value}, 6) NOT GLOB '*[^0-9]*'
|
|
1048
|
-
AND length(${value}) <= 10
|
|
1049
|
-
AND CAST(substr(${value}, 6) AS INTEGER) BETWEEN 2 AND 10000
|
|
1050
|
-
)
|
|
1051
|
-
))`;
|
|
1052
|
-
}
|
|
1053
|
-
function splitReplayDecisions(db) {
|
|
1054
|
-
db.exec(SESSION_REPLAY_DECISIONS_DDL);
|
|
1055
|
-
if (!tableExists(db, "session_meta"))
|
|
1056
|
-
return;
|
|
1057
|
-
if (!columnExists(db, "session_meta", "trailing_blank_decisions"))
|
|
1058
|
-
return;
|
|
1059
|
-
const doc = "sm.trailing_blank_decisions";
|
|
1060
|
-
const hasVersionKey = `json_type(${doc}, '$.version') IS NOT NULL`;
|
|
1061
|
-
const versionIsDecision = validDecisionSql(`json_type(${doc}, '$.version')`, `json_extract(${doc}, '$.version')`);
|
|
1062
|
-
const isV2 = `(${hasVersionKey} AND NOT ${versionIsDecision})`;
|
|
1063
|
-
const v2Valid = `(
|
|
1064
|
-
json_type(${doc}, '$.version') IN ('integer', 'real')
|
|
1065
|
-
AND json_extract(${doc}, '$.version') = 2
|
|
1066
|
-
AND json_type(${doc}, '$.trailingBlank') = 'object'
|
|
1067
|
-
AND NOT EXISTS (
|
|
1068
|
-
SELECT 1 FROM json_each(${doc}, '$.trailingBlank') AS entry
|
|
1069
|
-
WHERE entry.key = '' OR NOT ${validDecisionSql("entry.type", "entry.value")}
|
|
1070
|
-
)
|
|
1071
|
-
)`;
|
|
1072
|
-
const v1Valid = `NOT EXISTS (
|
|
1073
|
-
SELECT 1 FROM json_each(${doc}) AS entry
|
|
1074
|
-
WHERE entry.key = '' OR NOT ${validDecisionSql("entry.type", "entry.value")}
|
|
1075
|
-
)`;
|
|
1076
|
-
db.exec("DROP TABLE IF EXISTS temp.v94_replay_documents");
|
|
1077
|
-
db.exec(`
|
|
1078
|
-
CREATE TEMP TABLE v94_replay_documents AS
|
|
1079
|
-
SELECT session_id, version FROM (
|
|
1080
|
-
SELECT sm.session_id AS session_id, CASE WHEN ${isV2} THEN 2 ELSE 1 END AS version,
|
|
1081
|
-
CASE WHEN ${isV2} THEN ${v2Valid} ELSE ${v1Valid} END AS strictly_valid
|
|
1082
|
-
FROM session_meta AS sm
|
|
1083
|
-
WHERE typeof(${doc}) = 'text' AND ${doc} <> ''
|
|
1084
|
-
AND json_valid(${doc}) AND json_type(${doc}) = 'object'
|
|
1085
|
-
) WHERE strictly_valid;
|
|
1086
|
-
`);
|
|
1087
|
-
db.exec(`
|
|
1088
|
-
INSERT INTO session_replay_decisions (session_id, message_id, decision)
|
|
1089
|
-
SELECT sm.session_id, entry.key, entry.value
|
|
1090
|
-
FROM v94_replay_documents AS moved
|
|
1091
|
-
JOIN session_meta AS sm ON sm.session_id = moved.session_id
|
|
1092
|
-
JOIN json_each(
|
|
1093
|
-
${doc}, CASE moved.version WHEN 2 THEN '$.trailingBlank' ELSE '$' END
|
|
1094
|
-
) AS entry
|
|
1095
|
-
WHERE true
|
|
1096
|
-
ON CONFLICT(session_id, message_id) DO UPDATE SET decision = excluded.decision;
|
|
1097
|
-
`);
|
|
1098
|
-
db.exec(`
|
|
1099
|
-
UPDATE session_meta SET trailing_blank_decisions = (
|
|
1100
|
-
SELECT CASE moved.version
|
|
1101
|
-
WHEN 2 THEN json_set(session_meta.trailing_blank_decisions, '$.trailingBlank', json('{}'))
|
|
1102
|
-
ELSE ''
|
|
1103
|
-
END
|
|
1104
|
-
FROM v94_replay_documents AS moved WHERE moved.session_id = session_meta.session_id
|
|
1105
|
-
)
|
|
1106
|
-
WHERE session_id IN (SELECT session_id FROM v94_replay_documents);
|
|
1107
|
-
`);
|
|
1108
|
-
db.exec("DROP TABLE temp.v94_replay_documents");
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
534
|
// src/features/magic-context/opencode2-relabel.ts
|
|
1112
535
|
var OPENCODE2_RELABEL_STATE_KEY = "v87_opencode2_relabel";
|
|
1113
536
|
var V87_HARNESS_TWIN_RULES = [
|
|
@@ -1163,7 +586,7 @@ function collectCandidateSessions(db, shapes) {
|
|
|
1163
586
|
return [...sessions].sort();
|
|
1164
587
|
}
|
|
1165
588
|
function openEvidenceStore(path) {
|
|
1166
|
-
const store = new
|
|
589
|
+
const store = new Database2(path, { readonly: true, fileMustExist: true });
|
|
1167
590
|
try {
|
|
1168
591
|
const hasV1Messages = tableExists2(store, "message");
|
|
1169
592
|
const hasV1Session = tableExists2(store, "session");
|
|
@@ -1274,13 +697,13 @@ function repairOpenCode2HarnessLabels(db, options) {
|
|
|
1274
697
|
reason = "store_schema_unknown";
|
|
1275
698
|
} catch (error) {
|
|
1276
699
|
reason = "store_unreadable";
|
|
1277
|
-
|
|
700
|
+
log2(`[migration] OpenCode session database at ${resolution.path} could not be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
1278
701
|
}
|
|
1279
702
|
}
|
|
1280
703
|
if (!evidence || reason !== null) {
|
|
1281
704
|
evidence?.close();
|
|
1282
705
|
writeUnresolvedState(db, reason ?? "store_not_found", resolution, candidateSessionIds);
|
|
1283
|
-
|
|
706
|
+
log2(`[migration] OpenCode harness labels left unverified for ${candidateSessionIds.length} session(s): ` + `no readable OpenCode session database (${reason ?? "store_not_found"}) at ${resolution.path}. ` + "Nothing was relabelled; `magic-context doctor` reports the affected sessions.");
|
|
1284
707
|
return {
|
|
1285
708
|
status: "unresolved",
|
|
1286
709
|
reason: reason ?? "store_not_found",
|
|
@@ -1314,7 +737,7 @@ function repairOpenCode2HarnessLabels(db, options) {
|
|
|
1314
737
|
clearUnresolvedState(db);
|
|
1315
738
|
if (relabelledSessions.length > 0) {
|
|
1316
739
|
const toOpenCode2 = relabelledSessions.filter((entry) => entry.harness === "opencode2").length;
|
|
1317
|
-
|
|
740
|
+
log2(`[migration] OpenCode harness labels repaired from ${resolution.path}: ` + `${toOpenCode2} session(s) restored to opencode2, ` + `${relabelledSessions.length - toOpenCode2} session(s) set to opencode.`);
|
|
1318
741
|
}
|
|
1319
742
|
return {
|
|
1320
743
|
status: "resolved",
|
|
@@ -1406,7 +829,7 @@ function installCompartmentHistoryVersions(db) {
|
|
|
1406
829
|
}
|
|
1407
830
|
|
|
1408
831
|
// src/features/magic-context/workspaces.ts
|
|
1409
|
-
import { createHash as
|
|
832
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
1410
833
|
var VALID_SHARE_CATEGORIES = new Set(V2_MEMORY_CATEGORIES);
|
|
1411
834
|
var DEFAULT_WORKSPACE_SHARE_CATEGORIES = ["CONSTRAINTS"];
|
|
1412
835
|
function tableExists3(db, tableName) {
|
|
@@ -1427,7 +850,7 @@ function defaultWorkspaceShareCategories() {
|
|
|
1427
850
|
return [...DEFAULT_WORKSPACE_SHARE_CATEGORIES];
|
|
1428
851
|
}
|
|
1429
852
|
function warnInvalidShareCategories(reason, raw) {
|
|
1430
|
-
|
|
853
|
+
log2("[magic-context] WARN: invalid workspace share_categories; sharing no foreign memory categories", {
|
|
1431
854
|
reason,
|
|
1432
855
|
raw
|
|
1433
856
|
});
|
|
@@ -1474,7 +897,7 @@ function selectWorkspaceShareCategories(db, identities) {
|
|
|
1474
897
|
if (!hasMembership)
|
|
1475
898
|
return null;
|
|
1476
899
|
if (!tableExists3(db, "workspaces")) {
|
|
1477
|
-
|
|
900
|
+
log2("[magic-context] WARN: workspace member has no workspaces table; sharing no foreign memory categories");
|
|
1478
901
|
return [];
|
|
1479
902
|
}
|
|
1480
903
|
if (!columnExists2(db, "workspaces", "share_categories")) {
|
|
@@ -1487,7 +910,7 @@ function selectWorkspaceShareCategories(db, identities) {
|
|
|
1487
910
|
ORDER BY workspace.id ASC
|
|
1488
911
|
LIMIT 1`).get(...candidates);
|
|
1489
912
|
if (!row) {
|
|
1490
|
-
|
|
913
|
+
log2("[magic-context] WARN: workspace member has no workspace share_categories row; sharing no foreign memory categories");
|
|
1491
914
|
return [];
|
|
1492
915
|
}
|
|
1493
916
|
return normalizeShareCategories(row.shareCategories);
|
|
@@ -1592,7 +1015,7 @@ function computeWorkspaceEpochFingerprint(db, identities) {
|
|
|
1592
1015
|
const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
1593
1016
|
const epochs = getEpochMap(db, canonical);
|
|
1594
1017
|
const shareCategories = selectWorkspaceShareCategories(db, canonical);
|
|
1595
|
-
const hash =
|
|
1018
|
+
const hash = createHash2("sha256");
|
|
1596
1019
|
hash.update("share_categories", "utf8");
|
|
1597
1020
|
hash.update("\x00");
|
|
1598
1021
|
hash.update(shareCategories === null ? "NO_WORKSPACE" : JSON.stringify(shareCategories), "utf8");
|
|
@@ -2075,10 +1498,10 @@ var MIGRATIONS = [
|
|
|
2075
1498
|
const hasTable = (name) => Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name));
|
|
2076
1499
|
const memoryEmbeddings = hasTable("memory_embeddings") ? db.prepare(`DELETE FROM memory_embeddings
|
|
2077
1500
|
WHERE memory_id NOT IN (SELECT id FROM memories)`).run().changes : 0;
|
|
2078
|
-
|
|
1501
|
+
log2(`[migrations] v12 cleaned ${memoryEmbeddings} orphan memory_embeddings row(s)`);
|
|
2079
1502
|
const gitCommitEmbeddings = hasTable("git_commit_embeddings") ? db.prepare(`DELETE FROM git_commit_embeddings
|
|
2080
1503
|
WHERE sha NOT IN (SELECT sha FROM git_commits)`).run().changes : 0;
|
|
2081
|
-
|
|
1504
|
+
log2(`[migrations] v12 cleaned ${gitCommitEmbeddings} orphan git_commit_embeddings row(s)`);
|
|
2082
1505
|
}
|
|
2083
1506
|
},
|
|
2084
1507
|
{
|
|
@@ -4095,7 +3518,7 @@ function runMigrations(db) {
|
|
|
4095
3518
|
return false;
|
|
4096
3519
|
if (!loggedPlan) {
|
|
4097
3520
|
const pendingCount = MIGRATIONS.filter((candidate) => candidate.version > currentVersion && !isMigrationApplied(db, candidate.version)).length;
|
|
4098
|
-
|
|
3521
|
+
log2(`[migrations] current upstream migration lane: ${currentVersion}, applying ${pendingCount} migration(s)`);
|
|
4099
3522
|
loggedPlan = true;
|
|
4100
3523
|
}
|
|
4101
3524
|
if (isMainThread)
|
|
@@ -4110,13 +3533,13 @@ function runMigrations(db) {
|
|
|
4110
3533
|
break;
|
|
4111
3534
|
if (migration.version <= 61)
|
|
4112
3535
|
touchedLegacyAuthorityBatch = true;
|
|
4113
|
-
|
|
3536
|
+
log2(`[migrations] applied v${migration.version}: ${migration.description}`);
|
|
4114
3537
|
} catch (error) {
|
|
4115
3538
|
if (!migration && isSqliteLockError(error)) {
|
|
4116
3539
|
throw new MigrationLockBusyError(`failed to acquire migration write lock: ${error instanceof Error ? error.message : String(error)}`);
|
|
4117
3540
|
}
|
|
4118
3541
|
if (migration && isSiblingMigrationConflict(db, error, migration.version)) {
|
|
4119
|
-
|
|
3542
|
+
log2(`[migrations] v${migration.version} already applied by sibling instance — resuming with re-read version`);
|
|
4120
3543
|
const reReadVersion = getCurrentVersion(db);
|
|
4121
3544
|
if (reReadVersion > currentVersion)
|
|
4122
3545
|
continue;
|
|
@@ -4124,7 +3547,7 @@ function runMigrations(db) {
|
|
|
4124
3547
|
}
|
|
4125
3548
|
const version = migration?.version ?? currentVersion + 1;
|
|
4126
3549
|
const description = migration?.description ?? "acquire migration write lock";
|
|
4127
|
-
|
|
3550
|
+
log2(`[migrations] FAILED v${version}: ${description} — ${error instanceof Error ? error.message : String(error)}`);
|
|
4128
3551
|
throw new Error(`Migration v${version} failed: ${error instanceof Error ? error.message : String(error)}. Database may need manual repair.`);
|
|
4129
3552
|
}
|
|
4130
3553
|
}
|
|
@@ -4141,7 +3564,7 @@ function runMigrations(db) {
|
|
|
4141
3564
|
}
|
|
4142
3565
|
}
|
|
4143
3566
|
if (loggedPlan) {
|
|
4144
|
-
|
|
3567
|
+
log2(`[migrations] upstream migration lane now: ${MIGRATIONS[MIGRATIONS.length - 1].version}`);
|
|
4145
3568
|
}
|
|
4146
3569
|
}
|
|
4147
3570
|
async function runMigrationsWithRetry(db, options = {}) {
|
|
@@ -4149,7 +3572,7 @@ async function runMigrationsWithRetry(db, options = {}) {
|
|
|
4149
3572
|
const sleep = options.sleep ?? ((delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs)));
|
|
4150
3573
|
const totalAttempts = retryDelaysMs.length + 1;
|
|
4151
3574
|
for (let attempt = 1;attempt <= totalAttempts; attempt += 1) {
|
|
4152
|
-
|
|
3575
|
+
log2(`[migrations] migration lock check attempt ${attempt}/${totalAttempts}`);
|
|
4153
3576
|
try {
|
|
4154
3577
|
runMigrations(db);
|
|
4155
3578
|
return;
|
|
@@ -4159,174 +3582,10 @@ async function runMigrationsWithRetry(db, options = {}) {
|
|
|
4159
3582
|
const delayMs = retryDelaysMs[attempt - 1];
|
|
4160
3583
|
if (delayMs === undefined)
|
|
4161
3584
|
throw error;
|
|
4162
|
-
|
|
3585
|
+
log2(`[migrations] migration write lock is busy; retrying attempt ${attempt + 1}/${totalAttempts} in ${delayMs}ms`);
|
|
4163
3586
|
await sleep(delayMs);
|
|
4164
3587
|
}
|
|
4165
3588
|
}
|
|
4166
3589
|
}
|
|
4167
3590
|
|
|
4168
|
-
|
|
4169
|
-
var BOOT_QUIET_MS = 120000;
|
|
4170
|
-
var bootQuietUntilMs = 0;
|
|
4171
|
-
function beginBootQuietPeriod(now = Date.now()) {
|
|
4172
|
-
if (bootQuietUntilMs === 0)
|
|
4173
|
-
bootQuietUntilMs = now + BOOT_QUIET_MS;
|
|
4174
|
-
}
|
|
4175
|
-
function bootQuietRemainingMs(now = Date.now()) {
|
|
4176
|
-
return Math.max(0, bootQuietUntilMs - now);
|
|
4177
|
-
}
|
|
4178
|
-
function scheduleAfterBootQuiet(task, additionalDelayMs = 0) {
|
|
4179
|
-
const timer = setTimeout(task, bootQuietRemainingMs() + Math.max(0, additionalDelayMs));
|
|
4180
|
-
timer.unref?.();
|
|
4181
|
-
return timer;
|
|
4182
|
-
}
|
|
4183
|
-
|
|
4184
|
-
// src/features/magic-context/message-fts-rowid-map.ts
|
|
4185
|
-
import { createHash as createHash5 } from "node:crypto";
|
|
4186
|
-
var MESSAGE_FTS_ROWID_MAP_BACKFILL_BATCH_SIZE = 100;
|
|
4187
|
-
var BACKFILL_STATE_ID = 1;
|
|
4188
|
-
var EMPTY_INDEX_CONTENT_HASH = createHash5("sha256").update("").digest("hex");
|
|
4189
|
-
var upsertMapStatements = new WeakMap;
|
|
4190
|
-
var rangeReadyStatements = new WeakMap;
|
|
4191
|
-
var updateTimeStatements = new WeakMap;
|
|
4192
|
-
var activeBackfills = new WeakMap;
|
|
4193
|
-
function getUpsertMapStatement(db) {
|
|
4194
|
-
let statement = upsertMapStatements.get(db);
|
|
4195
|
-
if (!statement) {
|
|
4196
|
-
statement = db.prepare(`INSERT INTO message_fts_rowid_map
|
|
4197
|
-
(session_id, message_ordinal, fts_rowid, message_time_ms)
|
|
4198
|
-
VALUES (?, ?, ?, ?)
|
|
4199
|
-
ON CONFLICT(session_id, message_ordinal) DO UPDATE SET
|
|
4200
|
-
fts_rowid = excluded.fts_rowid,
|
|
4201
|
-
message_time_ms = COALESCE(
|
|
4202
|
-
excluded.message_time_ms,
|
|
4203
|
-
message_fts_rowid_map.message_time_ms
|
|
4204
|
-
)`);
|
|
4205
|
-
upsertMapStatements.set(db, statement);
|
|
4206
|
-
}
|
|
4207
|
-
return statement;
|
|
4208
|
-
}
|
|
4209
|
-
function getBackfillState(db) {
|
|
4210
|
-
const row = db.prepare(`SELECT watermark_rowid AS watermarkRowid, completed
|
|
4211
|
-
FROM message_fts_rowid_map_backfill_state
|
|
4212
|
-
WHERE id = ?`).get(BACKFILL_STATE_ID);
|
|
4213
|
-
return {
|
|
4214
|
-
processed: 0,
|
|
4215
|
-
watermarkRowid: typeof row?.watermarkRowid === "number" && Number.isSafeInteger(row.watermarkRowid) ? row.watermarkRowid : 0,
|
|
4216
|
-
completed: row?.completed === 1
|
|
4217
|
-
};
|
|
4218
|
-
}
|
|
4219
|
-
function recordMessageFtsRowid(db, sessionId, messageOrdinal, ftsRowid, messageTimeMs = null) {
|
|
4220
|
-
const numericRowid = Number(ftsRowid);
|
|
4221
|
-
if (!Number.isSafeInteger(numericRowid) || numericRowid <= 0) {
|
|
4222
|
-
throw new Error(`invalid message FTS rowid: ${String(ftsRowid)}`);
|
|
4223
|
-
}
|
|
4224
|
-
const normalizedTime = typeof messageTimeMs === "number" && Number.isSafeInteger(messageTimeMs) && messageTimeMs >= 0 ? messageTimeMs : null;
|
|
4225
|
-
getUpsertMapStatement(db).run(sessionId, messageOrdinal, numericRowid, normalizedTime);
|
|
4226
|
-
}
|
|
4227
|
-
function backfillMessageFtsRowidMapBatch(db, batchSize = MESSAGE_FTS_ROWID_MAP_BACKFILL_BATCH_SIZE) {
|
|
4228
|
-
const boundedBatchSize = Number.isFinite(batchSize) ? Math.min(MESSAGE_FTS_ROWID_MAP_BACKFILL_BATCH_SIZE, Math.max(1, Math.floor(batchSize))) : MESSAGE_FTS_ROWID_MAP_BACKFILL_BATCH_SIZE;
|
|
4229
|
-
let progress = {
|
|
4230
|
-
processed: 0,
|
|
4231
|
-
watermarkRowid: 0,
|
|
4232
|
-
completed: false
|
|
4233
|
-
};
|
|
4234
|
-
let transactionStartedAt = 0;
|
|
4235
|
-
db.transaction(() => {
|
|
4236
|
-
transactionStartedAt = performance.now();
|
|
4237
|
-
db.prepare(`INSERT OR IGNORE INTO message_fts_rowid_map_backfill_state
|
|
4238
|
-
(id, watermark_rowid, completed) VALUES (?, 0, 0)`).run(BACKFILL_STATE_ID);
|
|
4239
|
-
const state = getBackfillState(db);
|
|
4240
|
-
if (state.completed) {
|
|
4241
|
-
progress = state;
|
|
4242
|
-
return;
|
|
4243
|
-
}
|
|
4244
|
-
const rows = db.prepare(`SELECT rowid AS ftsRowid,
|
|
4245
|
-
session_id AS sessionId, message_ordinal AS messageOrdinal
|
|
4246
|
-
FROM message_history_fts WHERE rowid > ? ORDER BY rowid ASC LIMIT ?`).all(state.watermarkRowid, boundedBatchSize);
|
|
4247
|
-
let watermarkRowid = state.watermarkRowid;
|
|
4248
|
-
for (const row of rows) {
|
|
4249
|
-
const ftsRowid = Number(row.ftsRowid);
|
|
4250
|
-
const messageOrdinal = Number(row.messageOrdinal);
|
|
4251
|
-
if (Number.isSafeInteger(ftsRowid) && ftsRowid > watermarkRowid) {
|
|
4252
|
-
watermarkRowid = ftsRowid;
|
|
4253
|
-
}
|
|
4254
|
-
if (typeof row.sessionId === "string" && Number.isSafeInteger(messageOrdinal) && messageOrdinal >= 0 && Number.isSafeInteger(ftsRowid) && ftsRowid > 0) {
|
|
4255
|
-
recordMessageFtsRowid(db, row.sessionId, messageOrdinal, ftsRowid);
|
|
4256
|
-
}
|
|
4257
|
-
}
|
|
4258
|
-
const completed = rows.length < boundedBatchSize;
|
|
4259
|
-
db.prepare(`UPDATE message_fts_rowid_map_backfill_state
|
|
4260
|
-
SET watermark_rowid = ?, completed = ?, updated_at = ?
|
|
4261
|
-
WHERE id = ?`).run(watermarkRowid, completed ? 1 : 0, Date.now(), BACKFILL_STATE_ID);
|
|
4262
|
-
progress = {
|
|
4263
|
-
processed: rows.length,
|
|
4264
|
-
watermarkRowid,
|
|
4265
|
-
completed
|
|
4266
|
-
};
|
|
4267
|
-
}).immediate();
|
|
4268
|
-
logSlowWriteTransaction("message_fts_rowid_backfill", transactionStartedAt);
|
|
4269
|
-
return progress;
|
|
4270
|
-
}
|
|
4271
|
-
async function runMessageFtsRowidMapBackfill(db) {
|
|
4272
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
4273
|
-
for (;; ) {
|
|
4274
|
-
const progress = backfillMessageFtsRowidMapBatch(db);
|
|
4275
|
-
if (progress.completed)
|
|
4276
|
-
return;
|
|
4277
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
4278
|
-
}
|
|
4279
|
-
}
|
|
4280
|
-
function startMessageFtsRowidMapBackfill(db) {
|
|
4281
|
-
const active = activeBackfills.get(db);
|
|
4282
|
-
if (active)
|
|
4283
|
-
return active;
|
|
4284
|
-
const run = withoutSqliteTransformPass(() => withSqliteBackgroundWriter(() => runMessageFtsRowidMapBackfill(db))).finally(() => {
|
|
4285
|
-
activeBackfills.delete(db);
|
|
4286
|
-
});
|
|
4287
|
-
activeBackfills.set(db, run);
|
|
4288
|
-
return run;
|
|
4289
|
-
}
|
|
4290
|
-
function messageFtsOrdinalRangeIsMapped(db, sessionId, startOrdinal, endOrdinal) {
|
|
4291
|
-
if (endOrdinal < startOrdinal)
|
|
4292
|
-
return true;
|
|
4293
|
-
if (getBackfillState(db).completed)
|
|
4294
|
-
return true;
|
|
4295
|
-
let statement = rangeReadyStatements.get(db);
|
|
4296
|
-
if (!statement) {
|
|
4297
|
-
statement = db.prepare(`SELECT COUNT(DISTINCT source.message_ordinal) AS sourceOrdinalCount,
|
|
4298
|
-
COUNT(DISTINCT CASE
|
|
4299
|
-
WHEN source.role IN ('user', 'assistant')
|
|
4300
|
-
AND source.normalized_content_hash != ?
|
|
4301
|
-
THEN source.message_ordinal
|
|
4302
|
-
END) AS expectedMapCount,
|
|
4303
|
-
COUNT(DISTINCT CASE
|
|
4304
|
-
WHEN source.role IN ('user', 'assistant')
|
|
4305
|
-
AND source.normalized_content_hash != ?
|
|
4306
|
-
AND map.fts_rowid IS NOT NULL
|
|
4307
|
-
THEN source.message_ordinal
|
|
4308
|
-
END) AS mappedCount
|
|
4309
|
-
FROM message_history_source AS source
|
|
4310
|
-
LEFT JOIN message_fts_rowid_map AS map
|
|
4311
|
-
ON map.session_id = source.session_id
|
|
4312
|
-
AND map.message_ordinal = source.message_ordinal
|
|
4313
|
-
WHERE source.session_id = ?
|
|
4314
|
-
AND source.message_ordinal BETWEEN ? AND ?`);
|
|
4315
|
-
rangeReadyStatements.set(db, statement);
|
|
4316
|
-
}
|
|
4317
|
-
const row = statement.get(EMPTY_INDEX_CONTENT_HASH, EMPTY_INDEX_CONTENT_HASH, sessionId, startOrdinal, endOrdinal);
|
|
4318
|
-
const ordinalCount = endOrdinal - startOrdinal + 1;
|
|
4319
|
-
return row?.sourceOrdinalCount === ordinalCount && row.expectedMapCount === row.mappedCount;
|
|
4320
|
-
}
|
|
4321
|
-
function deleteUnmappedMessageFtsRows(db, sessionIds) {
|
|
4322
|
-
if (sessionIds.length === 0)
|
|
4323
|
-
return;
|
|
4324
|
-
const state = getBackfillState(db);
|
|
4325
|
-
if (state.completed)
|
|
4326
|
-
return;
|
|
4327
|
-
const placeholders = sessionIds.map(() => "?").join(", ");
|
|
4328
|
-
db.prepare(`DELETE FROM message_history_fts
|
|
4329
|
-
WHERE rowid > ? AND session_id IN (${placeholders})`).run(state.watermarkRowid, ...sessionIds);
|
|
4330
|
-
}
|
|
4331
|
-
|
|
4332
|
-
export { canonicalProjectDirectory, setHomeProjectPermission, shouldSkipHomeProjectMemory, ProjectIdentityError, takeDubiousOwnershipProjectIdentityWarning, isUserHomeDirectory, resolveProjectIdentity, directoryHasGitMetadata, describeUnresolvedProjectIdentity, isUsableProjectIdentity, resolveProjectIdentityForSession, normalizeStoredProjectPath, storedPathBelongsToIdentity, recordMessageFtsRowid, startMessageFtsRowidMapBackfill, messageFtsOrdinalRangeIsMapped, deleteUnmappedMessageFtsRows, V2_MEMORY_CATEGORIES, PROMOTABLE_CATEGORIES, CATEGORY_PRIORITY, getMemoryCategoryOrder, CATEGORY_DEFAULT_TTL, unescapeXml, parseCompartmentOutput, layoutLkgPrefix, assembleLkgPrefix, LKG_SLOT_CHUNKS_DDL, SESSION_REPLAY_DECISIONS_DDL, LKG_SLOTS_DDL, installCompartmentHistoryVersions, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, resolveStoredPathWorkspaceIdentity, storedPathBelongsToWorkspace, sourceNameForMemory, computeWorkspaceEpochFingerprint, FORK_MIGRATION_VERSION_FLOOR, managedAuthorityNoteRow, hasPendingMigrations, getMainThreadMigrationBodyCount, runMigrations, runMigrationsWithRetry, beginBootQuietPeriod, bootQuietRemainingMs, scheduleAfterBootQuiet };
|
|
3591
|
+
export { layoutLkgPrefix, assembleLkgPrefix, LKG_SLOT_CHUNKS_DDL, SESSION_REPLAY_DECISIONS_DDL, LKG_SLOTS_DDL, unescapeXml, parseCompartmentOutput, installCompartmentHistoryVersions, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, resolveStoredPathWorkspaceIdentity, storedPathBelongsToWorkspace, sourceNameForMemory, computeWorkspaceEpochFingerprint, FORK_MIGRATION_VERSION_FLOOR, managedAuthorityNoteRow, hasPendingMigrations, getMainThreadMigrationBodyCount, runMigrations, runMigrationsWithRetry };
|