@cortexkit/opencode-magic-context 0.47.0 → 0.49.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-kzx4dmk1.js} +12 -10
- package/dist/{context-wq4ffwyb.js → context-nj5f293n.js} +2765 -1925
- package/dist/{derive-budgets-ke12jnnh.js → derive-budgets-qz5rrr08.js} +4 -3
- package/dist/embedding-activity-g1dhes6g.js +10 -0
- package/dist/embedding-backfill-aetxv1vt.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/git-commits/search-git-commits.d.ts +2 -0
- package/dist/features/magic-context/git-commits/search-git-commits.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-rerank.d.ts +35 -0
- package/dist/features/magic-context/search-rerank.d.ts.map +1 -0
- package/dist/features/magic-context/search.d.ts +40 -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-persisted.d.ts +13 -2
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-session.d.ts +7 -1
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta.d.ts +1 -1
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
- package/dist/features/magic-context/storage-session-tables.d.ts +2 -0
- package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tag-identity-revision.d.ts +50 -0
- package/dist/features/magic-context/storage-tag-identity-revision.d.ts.map +1 -0
- package/dist/features/magic-context/storage-tags.d.ts +153 -4
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +1 -1
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -1
- package/dist/features/magic-context/tagger.d.ts +2 -0
- package/dist/features/magic-context/tagger.d.ts.map +1 -1
- package/dist/features/magic-context/transform-decision-log.d.ts +4 -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-deadline.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-replay.fixture.d.ts +24 -0
- package/dist/hooks/magic-context/auto-search-replay.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-runner.d.ts +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 +34 -3
- package/dist/hooks/magic-context/auto-search-worker-client.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +3 -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/emergency-fail-closed.d.ts +28 -0
- package/dist/hooks/magic-context/emergency-fail-closed.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/historian-host-runner.d.ts +8 -0
- package/dist/hooks/magic-context/historian-host-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +3 -2
- 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/latest-thinking-recovery.d.ts +7 -0
- package/dist/hooks/magic-context/latest-thinking-recovery.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/pass-outcome.d.ts +1 -0
- package/dist/hooks/magic-context/pass-outcome.d.ts.map +1 -1
- 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 +19 -1
- 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 +118 -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/rust-mode-transform.d.ts +36 -0
- package/dist/hooks/magic-context/rust-mode-transform.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/shared-compartment-boundaries.d.ts +8 -1
- package/dist/hooks/magic-context/shared-compartment-boundaries.d.ts.map +1 -1
- package/dist/hooks/magic-context/strict-thinking-prefix.d.ts +8 -0
- package/dist/hooks/magic-context/strict-thinking-prefix.d.ts.map +1 -0
- 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 +13 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +9 -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-q6hef7fh.js → index-0sahzkwr.js} +6 -19
- package/dist/{index-k5bdx1bx.js → index-0w56v4fm.js} +3 -5
- package/dist/{index-5gq3b2ya.js → index-1bt88epp.js} +227 -205
- package/dist/{index-cwf6s3ay.js → index-1g30axtz.js} +3279 -2907
- package/dist/{index-5a2r0p9f.js → index-1r0k9js3.js} +20 -13
- package/dist/index-2bvekkfy.js +11 -0
- package/dist/{index-6d9e1m08.js → index-2jcbj7r1.js} +13301 -13225
- package/dist/index-2jgwttpt.js +3269 -0
- package/dist/index-4dhv7mqz.js +131 -0
- package/dist/{index-sj29b3z2.js → index-4mjhqadz.js} +3 -3
- package/dist/{index-0c82743p.js → index-57mrqed8.js} +17 -15
- package/dist/{index-b35pxds2.js → index-58e3y90n.js} +1 -18
- package/dist/index-7jzrrxap.js +931 -0
- package/dist/index-8ajstryz.js +18 -0
- package/dist/{index-sfpzqvdz.js → index-8cd2j99z.js} +2 -3
- package/dist/{index-6wkcswft.js → index-9qjqq45k.js} +29 -19
- package/dist/{index-adwfkpex.js → index-9rt53q79.js} +23 -23
- package/dist/index-b7mv1jx3.js +1060 -0
- package/dist/index-d9vfe7xq.js +16 -0
- package/dist/{index-gg8j07zz.js → index-ezmszwbd.js} +8 -6
- package/dist/index-fb3zxn06.js +13 -0
- package/dist/index-fr0wbhdn.js +43 -0
- package/dist/{index-mc22ayvf.js → index-ghc9f0n7.js} +11 -9
- package/dist/index-gzcmtmar.js +171 -0
- package/dist/{index-w2t4ah5j.js → index-h2py7207.js} +6762 -7400
- package/dist/index-h2wc01qk.js +120 -0
- package/dist/index-h5zfkjyk.js +1277 -0
- package/dist/{index-92bp57hg.js → index-ha87j7a8.js} +1343 -149
- package/dist/index-hj2q50k0.js +856 -0
- package/dist/{index-wx8a6bw3.js → index-kb9nn0a0.js} +270 -53
- package/dist/index-kmpvemph.js +1314 -0
- package/dist/index-kp5qe690.js +3030 -0
- package/dist/{index-m5fe6jch.js → index-kq57tdf0.js} +152 -2453
- package/dist/{v2/server-fq7kq32k.js → index-mfkzp7qj.js} +1 -16
- package/dist/{v2/server-njt3np1k.js → index-nm6a8xpd.js} +220 -961
- package/dist/{index-hybnrwq0.js → index-nsjyysj0.js} +137 -130
- package/dist/index-nydv6g8r.js +3569 -0
- package/dist/index-pavzsdc6.js +17 -0
- package/dist/index-peshmj6h.js +152 -0
- package/dist/index-pxwp2hjk.js +571 -0
- package/dist/{v2/server-yr3zj7e7.js → index-qt1qqasc.js} +6 -7
- package/dist/{v2/server-51dv1pr5.js → index-qx53vezw.js} +301 -27
- package/dist/{index-rrrsepyw.js → index-s4j7t92z.js} +90 -85
- package/dist/{index-9pk9exrb.js → index-stbr4ce6.js} +18 -18
- package/dist/{index-fzbvakh0.js → index-tqf7yg27.js} +3 -3
- package/dist/index-vkbqdnkj.js +2307 -0
- package/dist/{index-8da2zjhz.js → index-z1tjp257.js} +9 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +608 -349
- package/dist/logger-ewak5q1s.js +20 -0
- package/dist/message-index-bounded-h0mrd4pr.js +124 -0
- package/dist/{v2/message-time-backfill-1f9tzvcs.js → message-time-backfill-8x06r9kx.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 +3 -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-rtt0djyb.js +88 -0
- package/dist/raw-ordinal-warmup-worker.js +60 -0
- package/dist/{read-session-chunk-4jey7hpt.js → read-session-chunk-ty89v75e.js} +17 -9
- package/dist/read-session-raw-8sjbc9h0.js +60 -0
- package/dist/recomp-orchestrator-4f1yyd1q.js +57 -0
- package/dist/{v2/safe-notification-target-eb1n1vfb.js → safe-notification-target-q0cyrx3x.js} +4 -2
- package/dist/search-pz4f4wge.js +45 -0
- package/dist/{v2/send-session-notification-c0wtscea.js → send-session-notification-38cd5dqt.js} +10 -7
- package/dist/shared/auto-search-lifecycle.d.ts +14 -0
- package/dist/shared/auto-search-lifecycle.d.ts.map +1 -1
- 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/logger.d.ts.map +1 -1
- package/dist/shared/model-resolution.d.ts +2 -3
- package/dist/shared/model-resolution.d.ts.map +1 -1
- package/dist/shared/models-dev-temperature.d.ts +18 -0
- package/dist/shared/models-dev-temperature.d.ts.map +1 -0
- package/dist/shared/project-directory-key.d.ts +16 -0
- package/dist/shared/project-directory-key.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/subagent-temperature.d.ts +46 -0
- package/dist/shared/subagent-temperature.d.ts.map +1 -0
- 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-k0pda32s.js +133 -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-reduce/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/types.d.ts +1 -0
- package/dist/tools/ctx-search/types.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-tck4g20s.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-crbt6p1y.js} +4708 -4218
- package/dist/v2/{derive-budgets-nc9avxz8.js → derive-budgets-fgej9j46.js} +4 -3
- package/dist/v2/embedding-activity-g1dhes6g.js +10 -0
- package/dist/v2/embedding-backfill-ph1qfyn3.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/hidden-child-native.d.ts.map +1 -1
- package/dist/v2/hidden-completion.d.ts +7 -0
- package/dist/v2/hidden-completion.d.ts.map +1 -1
- 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 +5 -3
- package/dist/v2/hooks/dream-trigger.d.ts.map +1 -1
- package/dist/v2/hooks/generate.d.ts +9 -2
- package/dist/v2/hooks/generate.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-pj02s7sr.js +19 -0
- package/dist/v2/message-index-bounded-xwqdywxg.js +123 -0
- package/dist/{message-time-backfill-r5epkzj3.js → v2/message-time-backfill-cje68egj.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-d6m7tyxr.js +86 -0
- package/dist/v2/raw-ordinal-warmup-worker.js +60 -0
- package/dist/v2/{read-session-chunk-gyyv7w2r.js → read-session-chunk-8p5mdryx.js} +16 -8
- package/dist/v2/read-session-raw-j8dvp7f4.js +59 -0
- package/dist/v2/recomp-orchestrator-ckfgt6wq.js +57 -0
- package/dist/{safe-notification-target-43r8jsxw.js → v2/safe-notification-target-y3p1hce9.js} +3 -3
- package/dist/v2/search-ym8rehhz.js +45 -0
- package/dist/{send-session-notification-0m68ms3n.js → v2/send-session-notification-5m0yapqx.js} +9 -8
- package/dist/v2/{server-rz514f14.js → server-19zjmn02.js} +2044 -2060
- package/dist/v2/server-1tk82krw.js +796 -0
- package/dist/v2/server-2bvekkfy.js +11 -0
- package/dist/v2/{server-ajzeteqw.js → server-2ra6pwf3.js} +1 -18
- package/dist/v2/server-2s6ayq3t.js +1048 -0
- package/dist/v2/{server-fcdehk1s.js → server-2s9qz6n7.js} +4 -4
- package/dist/v2/server-3j4d00kf.js +171 -0
- package/dist/v2/{server-14vq4kpm.js → server-3t0q2cqx.js} +3 -3
- package/dist/v2/server-4dhv7mqz.js +131 -0
- package/dist/v2/server-4ez8mntn.js +3213 -0
- package/dist/v2/{server-6r257mf5.js → server-676xw7at.js} +3 -3
- package/dist/v2/{server-vs5gpnd4.js → server-6byqfbqf.js} +165 -145
- package/dist/v2/server-7ekna9zs.js +120 -0
- package/dist/v2/server-7h861yms.js +1272 -0
- package/dist/v2/server-7jzrrxap.js +931 -0
- package/dist/v2/server-8ajstryz.js +18 -0
- package/dist/v2/{server-sfpzqvdz.js → server-8cd2j99z.js} +2 -3
- package/dist/v2/{server-cpepxy2q.js → server-8k2agx29.js} +14 -12
- package/dist/v2/server-c5rrgrcd.js +3545 -0
- package/dist/v2/server-d9vfe7xq.js +16 -0
- package/dist/v2/server-fb3zxn06.js +13 -0
- package/dist/v2/server-fr0wbhdn.js +43 -0
- package/dist/v2/{server-y10vbq6y.js → server-hb6xhh9q.js} +11 -1053
- package/dist/v2/server-jvxzm1jy.js +3023 -0
- package/dist/v2/{server-wx8a6bw3.js → server-kb9nn0a0.js} +270 -53
- package/dist/{index-5eqk6z3s.js → v2/server-kzns2hbz.js} +301 -27
- package/dist/{index-rrbbspwh.js → v2/server-mfkzp7qj.js} +1 -16
- package/dist/v2/server-pavzsdc6.js +17 -0
- package/dist/v2/{server-vd4e7174.js → server-pj4pjv02.js} +21 -17
- package/dist/v2/{server-e0c1b7a7.js → server-q4ph9bwn.js} +1340 -148
- package/dist/{index-yr3zj7e7.js → v2/server-qt1qqasc.js} +6 -7
- package/dist/v2/{server-qdjnb2z1.js → server-r5p3b1wy.js} +11 -9
- package/dist/v2/{server-d0sraw7m.js → server-sa8jvrfc.js} +291 -286
- package/dist/v2/server-ss95ky04.js +1048 -0
- package/dist/v2/{server-1qbnzc80.js → server-t4k4qexw.js} +142 -150
- package/dist/{index-x3kwrmqk.js → v2/server-v4mewb78.js} +35 -792
- package/dist/v2/server-w32kmdez.js +154 -0
- package/dist/v2/{server-nf82q6pt.js → server-x4hscabv.js} +5547 -5449
- package/dist/v2/server-xwz4dqh9.js +569 -0
- package/dist/v2/{server-efhwzx05.js → server-ycw9qqcy.js} +23 -23
- package/dist/v2/{server-50hvkg3v.js → server-zm570tr2.js} +160 -158
- package/dist/v2/server-zp53y8js.js +1311 -0
- 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-8vw924zn.js +132 -0
- package/dist/v2/store-reader.d.ts +24 -2
- 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-a7efxaax.js} +51 -30
- package/dist/wrapup-orchestrator-barbc6h9.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/auto-search-lifecycle.ts +43 -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/logger.test.ts +38 -0
- package/src/shared/logger.ts +10 -2
- package/src/shared/model-resolution.test.ts +54 -17
- package/src/shared/model-resolution.ts +6 -17
- package/src/shared/models-dev-temperature.ts +107 -0
- package/src/shared/project-directory-key.test.ts +59 -0
- package/src/shared/project-directory-key.ts +20 -0
- 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/subagent-temperature.test.ts +270 -0
- package/src/shared/subagent-temperature.ts +110 -0
- 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
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
__setCanonicalDirectoryRealpathForTests,
|
|
14
14
|
canonicalProjectDirectory,
|
|
15
15
|
projectDirectoryKey,
|
|
16
|
+
sameProjectDirectory,
|
|
16
17
|
} from "./project-directory-key";
|
|
17
18
|
import { projectHash, rpcPortDirsForLookup } from "./rpc-utils";
|
|
18
19
|
import { createTestTempDirFromPath } from "./test-temp-dir";
|
|
@@ -109,3 +110,61 @@ describe("one discovery directory per project directory", () => {
|
|
|
109
110
|
expect(dirs[0]).toBe(join("/storage", "rpc", projectHash("C:\\Users\\A\\Proj\\")));
|
|
110
111
|
});
|
|
111
112
|
});
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Background-session code compares a session's recorded directory with the
|
|
116
|
+
* plugin's own. OpenCode 2 on Windows records `D:/coding/app` while the plugin
|
|
117
|
+
* knows `D:\coding\app`; both must count as one directory, and a different
|
|
118
|
+
* directory must never be taken for this one.
|
|
119
|
+
*/
|
|
120
|
+
describe("sameProjectDirectory", () => {
|
|
121
|
+
for (const [name, left, right] of WINDOWS_PAIRS) {
|
|
122
|
+
test(`Windows ${name} is the same directory`, () => {
|
|
123
|
+
expect(sameProjectDirectory(left, right)).toBe(true);
|
|
124
|
+
expect(sameProjectDirectory(right, left)).toBe(true);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
test("Windows forward slashes against backslashes, as OpenCode 2 stores them", () => {
|
|
129
|
+
expect(
|
|
130
|
+
sameProjectDirectory(
|
|
131
|
+
"D:/coding/siac/wt/migracion-asincrona",
|
|
132
|
+
"D:\\coding\\siac\\wt\\migracion-asincrona",
|
|
133
|
+
),
|
|
134
|
+
).toBe(true);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("Windows `.` and `..` segments and a trailing forward slash", () => {
|
|
138
|
+
expect(
|
|
139
|
+
sameProjectDirectory("C:\\Users\\dev\\.\\work\\tmp\\..\\app", "C:/Users/dev/work/app/"),
|
|
140
|
+
).toBe(true);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("POSIX trailing slash and `..` segments", () => {
|
|
144
|
+
expect(sameProjectDirectory("/work/app/", "/work/app")).toBe(true);
|
|
145
|
+
expect(sameProjectDirectory("/work/tmp/../app", "/work/app")).toBe(true);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("different directories are refused", () => {
|
|
149
|
+
expect(
|
|
150
|
+
sameProjectDirectory(
|
|
151
|
+
"D:/coding/siac/wt/notificaciones-pui",
|
|
152
|
+
"D:\\coding\\siac\\wt\\migracion-asincrona",
|
|
153
|
+
),
|
|
154
|
+
).toBe(false);
|
|
155
|
+
// A sibling whose name extends this one, a parent, and another drive.
|
|
156
|
+
expect(sameProjectDirectory("C:/Users/dev/app-worktree", "C:\\Users\\dev\\app")).toBe(
|
|
157
|
+
false,
|
|
158
|
+
);
|
|
159
|
+
expect(sameProjectDirectory("C:/Users/dev", "C:\\Users\\dev\\app")).toBe(false);
|
|
160
|
+
expect(sameProjectDirectory("D:/Users/dev/app", "C:\\Users\\dev\\app")).toBe(false);
|
|
161
|
+
// POSIX paths are case-sensitive.
|
|
162
|
+
expect(sameProjectDirectory("/work/App", "/work/app")).toBe(false);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("an empty directory matches nothing, not even the process's working directory", () => {
|
|
166
|
+
expect(sameProjectDirectory("", process.cwd())).toBe(false);
|
|
167
|
+
expect(sameProjectDirectory(process.cwd(), "")).toBe(false);
|
|
168
|
+
expect(sameProjectDirectory("", "")).toBe(false);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
@@ -20,6 +20,26 @@ export function projectDirectoryKey(directory: string): string {
|
|
|
20
20
|
return path.resolve(directory);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Whether two spellings name the same directory, judged by spelling alone.
|
|
25
|
+
*
|
|
26
|
+
* Hosts and the plugin do not agree on how to write a directory: OpenCode 2 on
|
|
27
|
+
* Windows stores a session's directory as `D:/work/app` while the plugin's own
|
|
28
|
+
* location is `D:\work\app`, and a drive letter can arrive in either case.
|
|
29
|
+
* Both sides go through `projectDirectoryKey`, so separators, Windows case,
|
|
30
|
+
* `\\?\` prefixes, trailing separators and `.`/`..` segments cannot make one
|
|
31
|
+
* directory look like two. POSIX paths keep their case. Symlinks are not
|
|
32
|
+
* resolved here; callers that must follow them use `canonicalProjectDirectory`.
|
|
33
|
+
*
|
|
34
|
+
* An empty spelling never matches anything: `path.resolve("")` is the process's
|
|
35
|
+
* working directory, and a session with no recorded directory must not be
|
|
36
|
+
* taken for one in the directory the process happens to run in.
|
|
37
|
+
*/
|
|
38
|
+
export function sameProjectDirectory(a: string, b: string): boolean {
|
|
39
|
+
if (a.length === 0 || b.length === 0) return false;
|
|
40
|
+
return projectDirectoryKey(a) === projectDirectoryKey(b);
|
|
41
|
+
}
|
|
42
|
+
|
|
23
43
|
let realpathForCanonicalDirectory: (directory: string) => string = (directory) =>
|
|
24
44
|
realpathSync.native(directory);
|
|
25
45
|
|
|
@@ -1,12 +1,64 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
2
3
|
import {
|
|
3
4
|
Database,
|
|
5
|
+
detectSqliteRuntime,
|
|
4
6
|
getSqliteMemoryStats,
|
|
5
7
|
loadSqliteModule,
|
|
6
8
|
SqliteRuntimeUnavailableError,
|
|
7
9
|
} from "./sqlite";
|
|
8
10
|
|
|
9
11
|
describe("SQLite runtime selector", () => {
|
|
12
|
+
it("suppresses only the node:sqlite experimental warning in a real Node process", () => {
|
|
13
|
+
// Node 24.21 no longer emits this warning, so inject it during loading
|
|
14
|
+
// to keep the suppression assertion load-bearing on newer runtimes.
|
|
15
|
+
const selectorUrl = new URL("./sqlite.ts", import.meta.url).href;
|
|
16
|
+
const script = `
|
|
17
|
+
import { loadSqliteModule } from ${JSON.stringify(selectorUrl)};
|
|
18
|
+
const originalEmitWarning = process.emitWarning;
|
|
19
|
+
let listenerSawX = false;
|
|
20
|
+
process.on("warning", (warning) => {
|
|
21
|
+
if (warning.message === "x") listenerSawX = true;
|
|
22
|
+
});
|
|
23
|
+
await loadSqliteModule("Node.js", async (specifier) => {
|
|
24
|
+
if (specifier !== "node:sqlite") throw new Error("unexpected backend: " + specifier);
|
|
25
|
+
process.emitWarning("SQLite is an experimental feature and might change at any time", "ExperimentalWarning");
|
|
26
|
+
process.emitWarning("x", "ExperimentalWarning");
|
|
27
|
+
return {};
|
|
28
|
+
});
|
|
29
|
+
if (process.emitWarning !== originalEmitWarning) throw new Error("emitWarning was not restored");
|
|
30
|
+
process.emitWarning("after", "ExperimentalWarning");
|
|
31
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
32
|
+
if (!listenerSawX) throw new Error("the original warning listener was not called");
|
|
33
|
+
`;
|
|
34
|
+
const child = spawnSync("node", ["--trace-warnings", "--input-type=module", "-e", script], {
|
|
35
|
+
encoding: "utf8",
|
|
36
|
+
windowsHide: true,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(child.error).toBeUndefined();
|
|
40
|
+
expect(child.status).toBe(0);
|
|
41
|
+
expect(child.stderr).not.toContain("SQLite is an experimental feature");
|
|
42
|
+
expect(child.stderr).toContain("ExperimentalWarning: x");
|
|
43
|
+
expect(child.stderr).toContain("ExperimentalWarning: after");
|
|
44
|
+
expect(child.stderr).toMatch(/ExperimentalWarning: x[\s\S]*?\n\s+at /);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("leaves Bun and OpenCode warning emission untouched", async () => {
|
|
48
|
+
expect(detectSqliteRuntime()).toBe("Bun");
|
|
49
|
+
const originalEmitWarning = process.emitWarning;
|
|
50
|
+
let requestedSpecifier = "";
|
|
51
|
+
|
|
52
|
+
await loadSqliteModule("Bun", async (specifier) => {
|
|
53
|
+
requestedSpecifier = specifier;
|
|
54
|
+
expect(process.emitWarning).toBe(originalEmitWarning);
|
|
55
|
+
return {};
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
expect(requestedSpecifier).toBe("bun:sqlite");
|
|
59
|
+
expect(process.emitWarning).toBe(originalEmitWarning);
|
|
60
|
+
});
|
|
61
|
+
|
|
10
62
|
it("reports live connection PRAGMAs and removes closed handles", () => {
|
|
11
63
|
const before = getSqliteMemoryStats().connectionCount;
|
|
12
64
|
const db = new Database(":memory:");
|
package/src/shared/sqlite.ts
CHANGED
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
43
43
|
import { statSync } from "node:fs";
|
|
44
|
+
|
|
44
45
|
// Type import only — runtime is loaded dynamically below. @types/better-sqlite3
|
|
45
46
|
// has the richest definitions and is a structural superset of the API surface
|
|
46
47
|
// we use, so calls typed against BetterSqlite3 work under bun:sqlite and
|
|
@@ -169,13 +170,51 @@ export class SqliteRuntimeUnavailableError extends Error {
|
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
172
|
|
|
173
|
+
// Node requests this warning during node:sqlite's module evaluation, although
|
|
174
|
+
// warning delivery happens later. Intercept only the request while importing;
|
|
175
|
+
// replacing warning listeners would not suppress the default stderr output.
|
|
176
|
+
function isNodeSqliteExperimentalWarning(args: unknown[]): boolean {
|
|
177
|
+
const [warning, options] = args;
|
|
178
|
+
const message = warning instanceof Error ? warning.message : warning;
|
|
179
|
+
const type =
|
|
180
|
+
typeof options === "string"
|
|
181
|
+
? options
|
|
182
|
+
: options && typeof options === "object"
|
|
183
|
+
? (options as { type?: unknown }).type
|
|
184
|
+
: undefined;
|
|
185
|
+
return (
|
|
186
|
+
type === "ExperimentalWarning" &&
|
|
187
|
+
typeof message === "string" &&
|
|
188
|
+
message.startsWith("SQLite is an experimental feature")
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async function importSqliteModuleForRuntime(
|
|
193
|
+
runtime: SqliteRuntime,
|
|
194
|
+
specifier: string,
|
|
195
|
+
importer: (specifier: string) => Promise<SqliteModule>,
|
|
196
|
+
): Promise<SqliteModule> {
|
|
197
|
+
if (runtime !== "Node.js") return importer(specifier);
|
|
198
|
+
|
|
199
|
+
const originalEmitWarning = process.emitWarning;
|
|
200
|
+
process.emitWarning = function (this: unknown, ...args: unknown[]): void {
|
|
201
|
+
if (isNodeSqliteExperimentalWarning(args)) return;
|
|
202
|
+
Reflect.apply(originalEmitWarning, this, args);
|
|
203
|
+
} as typeof process.emitWarning;
|
|
204
|
+
try {
|
|
205
|
+
return await importer(specifier);
|
|
206
|
+
} finally {
|
|
207
|
+
process.emitWarning = originalEmitWarning;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
172
211
|
export async function loadSqliteModule(
|
|
173
212
|
runtime: SqliteRuntime = detectSqliteRuntime(),
|
|
174
213
|
importer: (specifier: string) => Promise<SqliteModule> = importSqliteModule,
|
|
175
214
|
): Promise<SqliteModule> {
|
|
176
215
|
const specifier = runtime === "Bun" ? bunSpec : nodeSpec;
|
|
177
216
|
try {
|
|
178
|
-
return await
|
|
217
|
+
return await importSqliteModuleForRuntime(runtime, specifier, importer);
|
|
179
218
|
} catch (error) {
|
|
180
219
|
if (isModuleNotFoundError(error, specifier)) {
|
|
181
220
|
throw new SqliteRuntimeUnavailableError(runtime, specifier, error);
|
|
@@ -234,6 +273,110 @@ export interface SqliteMemoryStats {
|
|
|
234
273
|
const trackedSqliteConnections = new Map<number, TrackedSqliteConnection>();
|
|
235
274
|
let nextSqliteConnectionSequence = 1;
|
|
236
275
|
|
|
276
|
+
/**
|
|
277
|
+
* Columns of Magic Context's `tags` table (context.db) that never decide which
|
|
278
|
+
* message a tag belongs to, its number, its type, or its reasoning token estimate.
|
|
279
|
+
*/
|
|
280
|
+
const TAG_COLUMNS_OUTSIDE_IDENTITY = new Set([
|
|
281
|
+
"status",
|
|
282
|
+
"drop_mode",
|
|
283
|
+
"byte_size",
|
|
284
|
+
"input_byte_size",
|
|
285
|
+
"reasoning_byte_size",
|
|
286
|
+
"token_count",
|
|
287
|
+
"input_token_count",
|
|
288
|
+
"caveman_depth",
|
|
289
|
+
"entry_fingerprint",
|
|
290
|
+
"tool_name",
|
|
291
|
+
"harness",
|
|
292
|
+
]);
|
|
293
|
+
|
|
294
|
+
let tagIdentityWriteGeneration = 0;
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Whether a write statement may change an existing `tags` row's identity
|
|
298
|
+
* (session, number, type, owner message, reasoning token count) or remove a
|
|
299
|
+
* row. Plain appends without an explicit `id`, and updates that assign only
|
|
300
|
+
* columns in {@link TAG_COLUMNS_OUTSIDE_IDENTITY}, cannot; everything else that
|
|
301
|
+
* names the table is treated as if it could, including DDL and multi-statement
|
|
302
|
+
* scripts. Erring towards true only costs a cache rebuild.
|
|
303
|
+
*/
|
|
304
|
+
export function mayChangeTagIdentity(sql: string): boolean {
|
|
305
|
+
if (!/\btags\b/i.test(sql) || /^\s*(?:SELECT|EXPLAIN|PRAGMA)\b/i.test(sql)) return false;
|
|
306
|
+
if (/^\s*WITH\b/i.test(sql) && !/\b(?:INSERT|UPDATE|DELETE|REPLACE)\b/i.test(sql)) return false;
|
|
307
|
+
// One statement only: a script can hide a DELETE behind a harmless first statement.
|
|
308
|
+
if (/;\s*\S/.test(sql) || /\bREPLACE\b/i.test(sql) || /\bON\s+CONFLICT\b/i.test(sql))
|
|
309
|
+
return true;
|
|
310
|
+
const insert = /^\s*INSERT\s+INTO\s+(?:main\.)?["`]?tags["`]?\s*\(([^)]*)\)/i.exec(sql);
|
|
311
|
+
if (insert) {
|
|
312
|
+
const columns = (insert[1] ?? "").split(",").map((column) =>
|
|
313
|
+
column
|
|
314
|
+
.trim()
|
|
315
|
+
.replace(/["`[\]]/g, "")
|
|
316
|
+
.toLowerCase(),
|
|
317
|
+
);
|
|
318
|
+
return columns.includes("id") || columns.includes("rowid");
|
|
319
|
+
}
|
|
320
|
+
const update = /^\s*UPDATE\s+(?:main\.)?["`]?tags["`]?\s+SET\s+([\s\S]*?)\bWHERE\b/i.exec(sql);
|
|
321
|
+
if (update && !/\bSELECT\b/i.test(sql)) {
|
|
322
|
+
// Provably identity-free only when every top-level assignment is a plain
|
|
323
|
+
// `column = ...` naming an allowed column. A tuple assignment such as
|
|
324
|
+
// `(tag_number, reasoning_token_count) = (...)`, or anything this cannot
|
|
325
|
+
// read, counts as an identity write.
|
|
326
|
+
const assignments = topLevelCommaSegments(update[1] ?? "");
|
|
327
|
+
if (!assignments) return true;
|
|
328
|
+
return !assignments.every((assignment) => {
|
|
329
|
+
const column = /^\s*["`]?(\w+)["`]?\s*=(?!=)/.exec(assignment)?.[1];
|
|
330
|
+
return column !== undefined && TAG_COLUMNS_OUTSIDE_IDENTITY.has(column.toLowerCase());
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Split SQL text at commas outside parentheses and quotes. Returns null when
|
|
338
|
+
* the parentheses or quotes do not balance.
|
|
339
|
+
*/
|
|
340
|
+
function topLevelCommaSegments(text: string): string[] | null {
|
|
341
|
+
const segments: string[] = [];
|
|
342
|
+
let depth = 0;
|
|
343
|
+
let quote: string | null = null;
|
|
344
|
+
let start = 0;
|
|
345
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
346
|
+
const char = text[index];
|
|
347
|
+
if (quote) {
|
|
348
|
+
// A doubled quote inside a quoted run is an escaped quote.
|
|
349
|
+
if (char === quote) {
|
|
350
|
+
if (text[index + 1] === quote) index += 1;
|
|
351
|
+
else quote = null;
|
|
352
|
+
}
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (char === "'" || char === '"' || char === "`") quote = char;
|
|
356
|
+
else if (char === "(") depth += 1;
|
|
357
|
+
else if (char === ")") {
|
|
358
|
+
depth -= 1;
|
|
359
|
+
if (depth < 0) return null;
|
|
360
|
+
} else if (char === "," && depth === 0) {
|
|
361
|
+
segments.push(text.slice(start, index));
|
|
362
|
+
start = index + 1;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (quote || depth !== 0) return null;
|
|
366
|
+
segments.push(text.slice(start));
|
|
367
|
+
return segments;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Counts executions, on any connection this process opened, of statements for
|
|
372
|
+
* which {@link mayChangeTagIdentity} is true. A cache built from `tags` stays
|
|
373
|
+
* valid for this process's own writes while the count is unchanged; commits by
|
|
374
|
+
* other connections show up in `PRAGMA data_version` instead.
|
|
375
|
+
*/
|
|
376
|
+
export function getTagIdentityWriteGeneration(): number {
|
|
377
|
+
return tagIdentityWriteGeneration;
|
|
378
|
+
}
|
|
379
|
+
|
|
237
380
|
/** Route native Bun and Node transaction entry through the same acquisition retry.
|
|
238
381
|
* Native Bun transaction wrappers execute BEGIN internally, bypassing an exec override,
|
|
239
382
|
* so both runtimes use this small synchronous wrapper instead. Writable handles
|
|
@@ -257,8 +400,15 @@ function installTransactionRouting(db: BetterSqlite3.Database, readonly: boolean
|
|
|
257
400
|
}
|
|
258
401
|
if (WRITER_TRANSACTION_END.test(sql) && openWriterTransactions.has(db))
|
|
259
402
|
return endWriterTransaction(db, () => nativeExec(sql), sql);
|
|
260
|
-
if (
|
|
261
|
-
|
|
403
|
+
if (
|
|
404
|
+
!/^\s*(?:SELECT|EXPLAIN|PRAGMA|COMMIT|END|ROLLBACK|SAVEPOINT|RELEASE)\b/i.test(sql)
|
|
405
|
+
) {
|
|
406
|
+
try {
|
|
407
|
+
return withAutocommitTimeout(db, () => nativeExec(sql));
|
|
408
|
+
} finally {
|
|
409
|
+
if (mayChangeTagIdentity(sql)) tagIdentityWriteGeneration += 1;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
262
412
|
return nativeExec(sql);
|
|
263
413
|
},
|
|
264
414
|
});
|
|
@@ -271,15 +421,22 @@ function installTransactionRouting(db: BetterSqlite3.Database, readonly: boolean
|
|
|
271
421
|
// SELECT/EXPLAIN cannot acquire a writer. Treat CTEs conservatively:
|
|
272
422
|
// WITH can introduce INSERT/UPDATE/DELETE as well as a read query.
|
|
273
423
|
if (!readonly && !/^\s*(?:SELECT|EXPLAIN|PRAGMA)\b/i.test(sql)) {
|
|
424
|
+
const changesTagIdentity = mayChangeTagIdentity(sql);
|
|
274
425
|
for (const method of ["run", "get", "all"] as const) {
|
|
275
426
|
const execute = statement[method].bind(statement);
|
|
276
427
|
Object.defineProperty(statement, method, {
|
|
277
428
|
configurable: true,
|
|
278
429
|
// biome-ignore lint/suspicious/noExplicitAny: retain SQLite's native binding overloads.
|
|
279
|
-
value: (...args: any[]) =>
|
|
280
|
-
|
|
430
|
+
value: (...args: any[]) => {
|
|
431
|
+
try {
|
|
432
|
+
return withAutocommitTimeout(db, () => execute(...args));
|
|
433
|
+
} finally {
|
|
434
|
+
if (changesTagIdentity) tagIdentityWriteGeneration += 1;
|
|
435
|
+
}
|
|
436
|
+
},
|
|
281
437
|
});
|
|
282
438
|
}
|
|
439
|
+
if (changesTagIdentity) wrapRemainingTagWriteForms(statement);
|
|
283
440
|
}
|
|
284
441
|
return statement;
|
|
285
442
|
},
|
|
@@ -330,6 +487,43 @@ function installTransactionRouting(db: BetterSqlite3.Database, readonly: boolean
|
|
|
330
487
|
});
|
|
331
488
|
}
|
|
332
489
|
|
|
490
|
+
/**
|
|
491
|
+
* Count tag identity writes made through the statement forms the transaction
|
|
492
|
+
* routing does not wrap. `iterate()` runs the statement while its result is
|
|
493
|
+
* consumed, so the generation moves both when iteration starts and when it
|
|
494
|
+
* ends: a summary read in between is then rebuilt on its next read.
|
|
495
|
+
*/
|
|
496
|
+
// biome-ignore lint/suspicious/noExplicitAny: statements from both backends share these method names.
|
|
497
|
+
function wrapRemainingTagWriteForms(statement: any): void {
|
|
498
|
+
if (typeof statement.iterate === "function") {
|
|
499
|
+
const iterate = statement.iterate.bind(statement);
|
|
500
|
+
Object.defineProperty(statement, "iterate", {
|
|
501
|
+
configurable: true,
|
|
502
|
+
value: function* (...args: unknown[]) {
|
|
503
|
+
tagIdentityWriteGeneration += 1;
|
|
504
|
+
try {
|
|
505
|
+
yield* iterate(...args);
|
|
506
|
+
} finally {
|
|
507
|
+
tagIdentityWriteGeneration += 1;
|
|
508
|
+
}
|
|
509
|
+
},
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
if (typeof statement.values === "function") {
|
|
513
|
+
const values = statement.values.bind(statement);
|
|
514
|
+
Object.defineProperty(statement, "values", {
|
|
515
|
+
configurable: true,
|
|
516
|
+
value: (...args: unknown[]) => {
|
|
517
|
+
try {
|
|
518
|
+
return values(...args);
|
|
519
|
+
} finally {
|
|
520
|
+
tagIdentityWriteGeneration += 1;
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
333
527
|
function trackSqliteConnection(
|
|
334
528
|
db: BetterSqlite3.Database,
|
|
335
529
|
filename: unknown,
|
|
@@ -440,6 +634,11 @@ export function getSqliteDatabasePath(db: Database): string | null {
|
|
|
440
634
|
: connection.filename;
|
|
441
635
|
}
|
|
442
636
|
}
|
|
637
|
+
// Native Bun/better-sqlite3 handles can reach readers without our constructor
|
|
638
|
+
// wrapper. Their filename is still available without a SQLite query.
|
|
639
|
+
const native = db as unknown as { filename?: unknown; name?: unknown };
|
|
640
|
+
const path = native.filename ?? native.name;
|
|
641
|
+
if (typeof path === "string" && path !== ":memory:" && path !== "") return path;
|
|
443
642
|
return null;
|
|
444
643
|
}
|
|
445
644
|
|
|
@@ -569,6 +768,33 @@ interface StatementOwner {
|
|
|
569
768
|
const statementOwners = new WeakMap<Database, StatementOwner>();
|
|
570
769
|
const FIRST_PRUNE_AT = 256;
|
|
571
770
|
|
|
771
|
+
/**
|
|
772
|
+
* Bun's default close (`sqlite3_close_v2`) only releases the native connection
|
|
773
|
+
* once every statement created by prepare() is finalized. The close override
|
|
774
|
+
* in ownPreparedStatement can finalize only statements that are still
|
|
775
|
+
* reachable. Once the garbage collector
|
|
776
|
+
* has marked a one-shot statement dead, its weak reference is already cleared,
|
|
777
|
+
* but the statement is finalized only when its memory is later swept. Until
|
|
778
|
+
* then the closed connection keeps the database, WAL and shared-memory files
|
|
779
|
+
* open, for an unbounded time.
|
|
780
|
+
*
|
|
781
|
+
* `close(true)` finalizes every outstanding statement, reachable or not, and
|
|
782
|
+
* releases the connection immediately. When the caller did not ask for errors
|
|
783
|
+
* and that close fails, fall back to the caller's own close so a teardown path
|
|
784
|
+
* never starts throwing; the fallback can defer the release as before.
|
|
785
|
+
*/
|
|
786
|
+
function closeReleasingStatements(
|
|
787
|
+
close: (...args: unknown[]) => unknown,
|
|
788
|
+
args: unknown[],
|
|
789
|
+
): unknown {
|
|
790
|
+
if (args[0] === true) return close(true);
|
|
791
|
+
try {
|
|
792
|
+
return close(true);
|
|
793
|
+
} catch {
|
|
794
|
+
return close(...args);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
572
798
|
function ownPreparedStatement(db: Database, statement: Statement): Statement {
|
|
573
799
|
const finalizable = statement as FinalizableStatement;
|
|
574
800
|
// Node finalizes its statements on close and exposes no finalize() method.
|
|
@@ -592,7 +818,7 @@ function ownPreparedStatement(db: Database, statement: Statement): Statement {
|
|
|
592
818
|
}
|
|
593
819
|
}
|
|
594
820
|
references.clear();
|
|
595
|
-
const result = close
|
|
821
|
+
const result = closeReleasingStatements(close, args);
|
|
596
822
|
if (failure) throw failure;
|
|
597
823
|
return result;
|
|
598
824
|
},
|
|
@@ -650,22 +876,31 @@ export function withSqliteBackgroundWriter<T>(operation: () => T): T {
|
|
|
650
876
|
export function withSqliteTransformPass<T>(operation: () => T): T {
|
|
651
877
|
const existing = transformPassScope.getStore();
|
|
652
878
|
if (existing?.active) return operation();
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
879
|
+
const reservation = reserveForegroundSqliteTurn();
|
|
880
|
+
const run = (release: () => void): T => {
|
|
881
|
+
const lease = { active: true, remainingWaitMs: FOREGROUND_IN_PASS_BUSY_TIMEOUT_MS };
|
|
882
|
+
return transformPassScope.run(lease, () => {
|
|
883
|
+
try {
|
|
884
|
+
const result = operation();
|
|
885
|
+
if (result && typeof (result as { then?: unknown }).then === "function") {
|
|
886
|
+
return Promise.resolve(result).finally(() => {
|
|
887
|
+
lease.active = false;
|
|
888
|
+
release();
|
|
889
|
+
}) as T;
|
|
890
|
+
}
|
|
891
|
+
lease.active = false;
|
|
892
|
+
release();
|
|
893
|
+
return result;
|
|
894
|
+
} catch (error) {
|
|
895
|
+
lease.active = false;
|
|
896
|
+
release();
|
|
897
|
+
throw error;
|
|
661
898
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
}
|
|
668
|
-
});
|
|
899
|
+
});
|
|
900
|
+
};
|
|
901
|
+
// Foreground callers racing maintenance are awaited transforms. Idle
|
|
902
|
+
// synchronous callers keep the existing immediate return/throw behavior.
|
|
903
|
+
return typeof reservation === "function" ? run(reservation) : (reservation.then(run) as T);
|
|
669
904
|
}
|
|
670
905
|
|
|
671
906
|
/** Start detached maintenance work without borrowing a foreground pass's budget. */
|
|
@@ -836,16 +1071,20 @@ function acquireShort(db: Database, acquire: () => unknown, site: string): void
|
|
|
836
1071
|
* `acquireShort`, then report how long the writer waited for the lock
|
|
837
1072
|
* (`acquire_ms`) and how long it then held it (`hold_ms`) when either crosses
|
|
838
1073
|
* the threshold. A long hold blocks every other process's writer, so it is
|
|
839
|
-
* worth seeing even when the lock itself came quickly.
|
|
1074
|
+
* worth seeing even when the lock itself came quickly. The native end statement's
|
|
1075
|
+
* `end_ms` is reported separately, so a slow FTS merge or checkpoint at COMMIT
|
|
1076
|
+
* is not mistaken for acquisition time.
|
|
840
1077
|
*/
|
|
841
1078
|
function endWriterTransaction(db: Database, end: () => unknown, sql: string): unknown {
|
|
842
1079
|
let ended = false;
|
|
1080
|
+
const endStarted = performance.now();
|
|
843
1081
|
try {
|
|
844
1082
|
const result = end();
|
|
845
1083
|
ended = true;
|
|
846
1084
|
return result;
|
|
847
1085
|
} finally {
|
|
848
1086
|
const open = openWriterTransactions.get(db);
|
|
1087
|
+
const endMs = performance.now() - endStarted;
|
|
849
1088
|
// A COMMIT that failed with the transaction still open has not ended it.
|
|
850
1089
|
if (open && !isInTransaction(db)) {
|
|
851
1090
|
openWriterTransactions.delete(db);
|
|
@@ -857,7 +1096,7 @@ function endWriterTransaction(db: Database, end: () => unknown, sql: string): un
|
|
|
857
1096
|
? "committed"
|
|
858
1097
|
: "failed";
|
|
859
1098
|
reportSqliteDiagnostic(
|
|
860
|
-
`sqlite writer site=${open.site} lane=${open.lane} acquire_ms=${Math.round(open.acquireMs)} hold_ms=${Math.round(holdMs)} attempts=${open.attempts} outcome=${outcome}`,
|
|
1099
|
+
`sqlite writer site=${open.site} lane=${open.lane} acquire_ms=${Math.round(open.acquireMs)} hold_ms=${Math.round(holdMs)} end_ms=${Math.round(endMs)} attempts=${open.attempts} outcome=${outcome}`,
|
|
861
1100
|
);
|
|
862
1101
|
}
|
|
863
1102
|
}
|
|
@@ -1056,3 +1295,80 @@ export function withPrivilegedWriter<T>(db: Database, operation: () => T): T {
|
|
|
1056
1295
|
throw error;
|
|
1057
1296
|
}
|
|
1058
1297
|
}
|
|
1298
|
+
|
|
1299
|
+
// Process-local admission only; SQLite remains the cross-process writer arbiter.
|
|
1300
|
+
const indexCoordinationKey = Symbol.for("magic-context.index-foreground-coordination.v1");
|
|
1301
|
+
const indexCoordinationHeap = globalThis as unknown as Record<
|
|
1302
|
+
symbol,
|
|
1303
|
+
SharedArrayBuffer | undefined
|
|
1304
|
+
>;
|
|
1305
|
+
const indexCoordinationBuffer =
|
|
1306
|
+
indexCoordinationHeap[indexCoordinationKey] ??
|
|
1307
|
+
new SharedArrayBuffer(3 * Int32Array.BYTES_PER_ELEMENT);
|
|
1308
|
+
indexCoordinationHeap[indexCoordinationKey] = indexCoordinationBuffer;
|
|
1309
|
+
const indexCoordinationState = new Int32Array(indexCoordinationBuffer);
|
|
1310
|
+
// Slots: foreground interest, current maintenance owner, next owner token.
|
|
1311
|
+
|
|
1312
|
+
export function indexCoordinationInput(): {
|
|
1313
|
+
indexCoordination: SharedArrayBuffer;
|
|
1314
|
+
indexOwner: number;
|
|
1315
|
+
} {
|
|
1316
|
+
return {
|
|
1317
|
+
indexCoordination: indexCoordinationBuffer,
|
|
1318
|
+
indexOwner: Atomics.add(indexCoordinationState, 2, 1) + 1,
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
const yieldIndexTurn = () => new Promise<void>((resolve) => setTimeout(resolve, 1));
|
|
1323
|
+
|
|
1324
|
+
/** Announce interest before waiting, so no maintenance chunk overtakes a foreground turn. */
|
|
1325
|
+
function reserveForegroundSqliteTurn(): (() => void) | Promise<() => void> {
|
|
1326
|
+
Atomics.add(indexCoordinationState, 0, 1);
|
|
1327
|
+
const release = () => {
|
|
1328
|
+
Atomics.sub(indexCoordinationState, 0, 1);
|
|
1329
|
+
Atomics.notify(indexCoordinationState, 0);
|
|
1330
|
+
};
|
|
1331
|
+
if (Atomics.load(indexCoordinationState, 1) === 0) return release;
|
|
1332
|
+
return (async () => {
|
|
1333
|
+
while (Atomics.load(indexCoordinationState, 1) !== 0) await yieldIndexTurn();
|
|
1334
|
+
return release;
|
|
1335
|
+
})();
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
export function releaseIndexOwner(input: {
|
|
1339
|
+
indexCoordination?: SharedArrayBuffer;
|
|
1340
|
+
indexOwner?: number;
|
|
1341
|
+
}): void {
|
|
1342
|
+
if (!input.indexCoordination || !input.indexOwner) return;
|
|
1343
|
+
const shared = new Int32Array(input.indexCoordination);
|
|
1344
|
+
Atomics.compareExchange(shared, 1, input.indexOwner, 0);
|
|
1345
|
+
Atomics.notify(shared, 1);
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
/** One synchronous transaction per permit; release the permit before yielding. */
|
|
1349
|
+
export async function withIndexChunk<T>(
|
|
1350
|
+
input: { indexCoordination?: SharedArrayBuffer; indexOwner?: number },
|
|
1351
|
+
operation: () => T,
|
|
1352
|
+
): Promise<T> {
|
|
1353
|
+
if (!input.indexCoordination || !input.indexOwner) return operation();
|
|
1354
|
+
const shared = new Int32Array(input.indexCoordination);
|
|
1355
|
+
for (;;) {
|
|
1356
|
+
if (
|
|
1357
|
+
Atomics.load(shared, 0) === 0 &&
|
|
1358
|
+
Atomics.compareExchange(shared, 1, 0, input.indexOwner) === 0
|
|
1359
|
+
) {
|
|
1360
|
+
if (Atomics.load(shared, 0) === 0) break;
|
|
1361
|
+
releaseIndexOwner(input);
|
|
1362
|
+
}
|
|
1363
|
+
await yieldIndexTurn();
|
|
1364
|
+
}
|
|
1365
|
+
try {
|
|
1366
|
+
return await operation();
|
|
1367
|
+
} finally {
|
|
1368
|
+
releaseIndexOwner(input);
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
export async function yieldIndexChunk(): Promise<void> {
|
|
1373
|
+
await yieldIndexTurn();
|
|
1374
|
+
}
|