@cortexkit/opencode-magic-context 0.45.0 → 0.46.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/README.md +26 -0
- package/dist/{announcement-f75t58v9.js → announcement-y35wzg2r.js} +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/live-run-config.d.ts.map +1 -1
- package/dist/config/migrate-config-location.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +10 -4
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/{conflict-warning-hook-5yrz2r24.js → conflict-warning-hook-7fj2b9jw.js} +6 -5
- package/dist/context-8dkpszy5.js +4483 -0
- package/dist/{derive-budgets-a63zsm5c.js → derive-budgets-7nj7r1rv.js} +2 -2
- package/dist/embedding-worker.js +4 -4
- package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts +45 -0
- package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts.map +1 -0
- package/dist/features/magic-context/checkout-claim.d.ts +155 -0
- package/dist/features/magic-context/checkout-claim.d.ts.map +1 -0
- package/dist/features/magic-context/compaction-marker.d.ts +20 -3
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-storage.d.ts +23 -2
- package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/provider-output-failure.d.ts +6 -2
- package/dist/features/magic-context/dreamer/provider-output-failure.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/provider-output-failure.test-support.d.ts +30 -0
- package/dist/features/magic-context/dreamer/provider-output-failure.test-support.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-executor.d.ts +9 -0
- package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify-diff.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify-gate.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.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/project-identity-cache.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-verifications.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory.d.ts +3 -0
- package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
- package/dist/features/magic-context/memory/verification-paths.d.ts +2 -2
- package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -1
- package/dist/features/magic-context/merged-reasoning-decisions.d.ts.map +1 -1
- package/dist/features/magic-context/message-index-async.d.ts +3 -3
- package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
- package/dist/features/magic-context/message-index.d.ts +2 -0
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/migration-v95-perf-indexes.d.ts +12 -0
- package/dist/features/magic-context/migration-v95-perf-indexes.d.ts.map +1 -0
- package/dist/features/magic-context/migration-worker-client.d.ts +4 -4
- package/dist/features/magic-context/migration-worker-client.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts +1 -0
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/mural/render-trigger.d.ts.map +1 -1
- package/dist/features/magic-context/mural/resolve-mural.d.ts +15 -4
- package/dist/features/magic-context/mural/resolve-mural.d.ts.map +1 -1
- package/dist/features/magic-context/mural/source-revision.d.ts +7 -0
- package/dist/features/magic-context/mural/source-revision.d.ts.map +1 -0
- package/dist/features/magic-context/mural/storage-mural-cues.d.ts.map +1 -1
- package/dist/features/magic-context/reclaim-protection.d.ts +15 -10
- package/dist/features/magic-context/reclaim-protection.d.ts.map +1 -1
- package/dist/features/magic-context/session-cache-ttl.d.ts +4 -2
- package/dist/features/magic-context/session-cache-ttl.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/capabilities.d.ts +3 -0
- package/dist/features/magic-context/smart-notes/capabilities.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/github-token.d.ts +5 -0
- package/dist/features/magic-context/smart-notes/github-token.d.ts.map +1 -0
- 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/smart-notes/sandbox-runner.d.ts +12 -0
- package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts +6 -0
- package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/storage.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/types.d.ts +2 -0
- package/dist/features/magic-context/smart-notes/types.d.ts.map +1 -1
- package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts +6 -9
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
- package/dist/features/magic-context/storage-ops.d.ts +8 -1
- package/dist/features/magic-context/storage-ops.d.ts.map +1 -1
- package/dist/features/magic-context/storage-replay-document.d.ts +7 -0
- package/dist/features/magic-context/storage-replay-document.d.ts.map +1 -1
- package/dist/features/magic-context/storage-schema-helpers.d.ts +2 -0
- package/dist/features/magic-context/storage-schema-helpers.d.ts.map +1 -1
- package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
- package/dist/features/magic-context/storage-source.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts +11 -3
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +2 -2
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/temporal-decisions.d.ts +10 -0
- package/dist/features/magic-context/temporal-decisions.d.ts.map +1 -0
- package/dist/features/magic-context/tool-definition-tokens.d.ts +2 -0
- package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
- package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
- package/dist/features/magic-context/types.d.ts +7 -6
- package/dist/features/magic-context/types.d.ts.map +1 -1
- package/dist/features/magic-context/window-report-ledger.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
- package/dist/hooks/magic-context/apply-operations.d.ts +8 -0
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts +6 -3
- package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
- package/dist/hooks/magic-context/channel2-cycle.d.ts +2 -0
- package/dist/hooks/magic-context/channel2-cycle.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts +7 -0
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-prompt.d.ts +2 -2
- package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-render-epoch.d.ts +8 -0
- package/dist/hooks/magic-context/compartment-render-epoch.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts +18 -4
- package/dist/hooks/magic-context/compartment-runner-drop-queue.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-partial-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +12 -0
- package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
- package/dist/hooks/magic-context/decision-calibration.d.ts +3 -0
- package/dist/hooks/magic-context/decision-calibration.d.ts.map +1 -1
- package/dist/hooks/magic-context/default-protection-pressure.test-support.d.ts +37 -0
- package/dist/hooks/magic-context/default-protection-pressure.test-support.d.ts.map +1 -0
- package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts +4 -0
- package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts.map +1 -1
- package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -1
- package/dist/hooks/magic-context/emergency-drop.d.ts +2 -0
- package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
- package/dist/hooks/magic-context/emergency-fail-closed.d.ts +21 -1
- package/dist/hooks/magic-context/emergency-fail-closed.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts +5 -0
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +30 -1
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts +2 -0
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/historian-prompt-fit.d.ts +4 -2
- package/dist/hooks/magic-context/historian-prompt-fit.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +2 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +9 -10
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-measured-request.d.ts +69 -0
- package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -0
- package/dist/hooks/magic-context/lkg-persist.d.ts +2 -0
- package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-replay-fit.d.ts +14 -0
- package/dist/hooks/magic-context/lkg-replay-fit.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-replay.d.ts +10 -1
- package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-slot.d.ts +4 -0
- package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-state-sync.d.ts +2 -0
- package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
- package/dist/hooks/magic-context/note-nudger.d.ts +17 -5
- package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-chunk.d.ts +1 -1
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-db.d.ts +1 -0
- package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-formatting.d.ts +7 -0
- package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-raw.d.ts +4 -0
- 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/recomp-orchestrator.d.ts +2 -0
- package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
- package/dist/hooks/magic-context/reference-retrieval.d.ts +27 -17
- package/dist/hooks/magic-context/reference-retrieval.d.ts.map +1 -1
- package/dist/hooks/magic-context/request-hook-order.d.ts +56 -0
- package/dist/hooks/magic-context/request-hook-order.d.ts.map +1 -0
- package/dist/hooks/magic-context/rust-mode-transform.d.ts +22 -3
- package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts +4 -2
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/supersession-reclaim.d.ts +4 -0
- package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts +7 -0
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +12 -3
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
- package/dist/hooks/magic-context/temporal-awareness.d.ts +6 -3
- package/dist/hooks/magic-context/temporal-awareness.d.ts.map +1 -1
- package/dist/hooks/magic-context/temporal-served-projection.d.ts +4 -0
- package/dist/hooks/magic-context/temporal-served-projection.d.ts.map +1 -0
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-reclaim.d.ts +2 -0
- package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-message-helpers.d.ts +5 -0
- package/dist/hooks/magic-context/transform-message-helpers.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +41 -17
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +12 -0
- 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-vvtfyw1z.js → index-0d3g3461.js} +5 -13
- package/dist/index-1bc61ans.js +154 -0
- package/dist/{index-n96ag4rk.js → index-1zx87sdm.js} +5 -1
- package/dist/{index-4krbw8z9.js → index-3h0ybwah.js} +608 -102
- package/dist/{index-gd5qx1j9.js → index-5eqk6z3s.js} +62 -1
- package/dist/index-5gq3b2ya.js +494 -0
- package/dist/{index-75zjgwga.js → index-7qw742ev.js} +1 -1
- package/dist/{index-f85teqck.js → index-8da2zjhz.js} +3 -256
- package/dist/{index-w9jwmntv.js → index-b35pxds2.js} +9 -1
- package/dist/{index-8fgkmxmy.js → index-e2dtv0ra.js} +4 -3
- package/dist/{v2/server-a4m2b1yv.js → index-fg34g6a5.js} +55 -1
- package/dist/{index-xgt9k6c6.js → index-j7fvnjye.js} +2 -1
- package/dist/{index-2aq21j41.js → index-k4404na5.js} +418 -127
- package/dist/{index-2ntg5sd4.js → index-k5bdx1bx.js} +9 -5
- package/dist/{index-bmzf7zxv.js → index-majxda46.js} +23 -5
- package/dist/{index-16ny736w.js → index-p821bjdb.js} +14406 -13726
- package/dist/{index-remp7e2g.js → index-q4yp4b52.js} +16 -1
- package/dist/index-qr6r7akd.js +28505 -0
- package/dist/{index-fr2z4qy8.js → index-r5hmbx3t.js} +132 -169
- package/dist/index-sfnj6h8h.js +259 -0
- package/dist/index-sj29b3z2.js +30 -0
- package/dist/{index-q7yesyk9.js → index-yasgb8ej.js} +23 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1983 -33118
- package/dist/{message-time-backfill-an311pmk.js → message-time-backfill-68gj6t3e.js} +2 -2
- package/dist/migration-worker.js +12 -7
- package/dist/plugin/dream-timer.d.ts +25 -1
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +2 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/messages-transform.d.ts +13 -0
- package/dist/plugin/messages-transform.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts +4 -0
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/plugin/subagent-tool-policy.d.ts +14 -0
- package/dist/plugin/subagent-tool-policy.d.ts.map +1 -0
- package/dist/plugin/tool-registry.d.ts +1 -0
- package/dist/plugin/tool-registry.d.ts.map +1 -1
- package/dist/{read-session-chunk-8rxs0tc9.js → read-session-chunk-egz7r68d.js} +8 -8
- package/dist/{recomp-orchestrator-nzamtw29.js → recomp-orchestrator-ejq7ex5d.js} +15 -15
- package/dist/{send-session-notification-nqpv7cne.js → send-session-notification-dyw42dtr.js} +4 -4
- package/dist/shared/announcement.d.ts.map +1 -1
- package/dist/shared/cache-ttl-display.d.ts +6 -4
- package/dist/shared/cache-ttl-display.d.ts.map +1 -1
- package/dist/shared/model-cache-ttl.d.ts +1 -1
- package/dist/shared/model-cache-ttl.d.ts.map +1 -1
- package/dist/shared/model-suggestion-retry.d.ts +2 -0
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/models-dev-cache.d.ts.map +1 -1
- package/dist/shared/protected-tools-policy.d.ts +6 -0
- package/dist/shared/protected-tools-policy.d.ts.map +1 -0
- package/dist/shared/quota-diagnostic.d.ts +4 -0
- package/dist/shared/quota-diagnostic.d.ts.map +1 -0
- package/dist/shared/rpc-server.d.ts.map +1 -1
- package/dist/shared/sqlite-context-pragmas.d.ts +12 -0
- package/dist/shared/sqlite-context-pragmas.d.ts.map +1 -0
- package/dist/shared/sqlite-helpers.d.ts +9 -0
- package/dist/shared/sqlite-helpers.d.ts.map +1 -1
- package/dist/shared/sqlite.d.ts +10 -0
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/shared/status-summary.d.ts +1 -0
- package/dist/shared/status-summary.d.ts.map +1 -1
- package/dist/shared/status-view-check.d.ts.map +1 -1
- package/dist/shared/status-view.d.ts +4 -0
- package/dist/shared/status-view.d.ts.map +1 -1
- package/dist/shared/storage-permissions.d.ts +24 -0
- package/dist/shared/storage-permissions.d.ts.map +1 -1
- package/dist/shared/temporal-upgrade-fixture.d.ts +19 -0
- package/dist/shared/temporal-upgrade-fixture.d.ts.map +1 -0
- package/dist/shared/user-facing-codes.d.ts +5 -0
- package/dist/shared/user-facing-codes.d.ts.map +1 -1
- package/dist/shared/write-transaction-timing.d.ts +8 -1
- package/dist/shared/write-transaction-timing.d.ts.map +1 -1
- package/dist/tools/ctx-expand/render.d.ts.map +1 -1
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- package/dist/tools/ctx-reduce/constants.d.ts +2 -0
- package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
- package/dist/tools/ctx-reduce/tools.d.ts +4 -4
- package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
- package/dist/{transform-postprocess-phase-414phndq.js → transform-postprocess-phase-tz3pat2p.js} +15 -15
- package/dist/v2/context-8vgtb6sz.js +52166 -0
- package/dist/v2/{derive-budgets-v0krf3t7.js → derive-budgets-kdgp4s3r.js} +4 -3
- package/dist/v2/embedding-worker.js +6 -5
- package/dist/v2/fold/boundary.d.ts +2 -0
- package/dist/v2/fold/boundary.d.ts.map +1 -1
- package/dist/v2/fold/owner.d.ts.map +1 -1
- package/dist/v2/hooks/channel2.d.ts +2 -0
- package/dist/v2/hooks/channel2.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-timer.d.ts +39 -0
- package/dist/v2/hooks/dream-timer.d.ts.map +1 -0
- package/dist/v2/hooks/payload.d.ts.map +1 -1
- package/dist/v2/hooks/store.d.ts.map +1 -1
- package/dist/v2/hooks/tools.d.ts +1 -1
- package/dist/v2/hooks/tools.d.ts.map +1 -1
- package/dist/v2/hooks/update-check.d.ts.map +1 -1
- package/dist/v2/{message-time-backfill-0n93vrd7.js → message-time-backfill-r6qkem1x.js} +3 -3
- package/dist/v2/migration-worker.js +13 -8
- package/dist/v2/{read-session-chunk-hjza38hr.js → read-session-chunk-8vjp6581.js} +9 -9
- package/dist/v2/recomp-orchestrator-5xj0yzyk.js +39 -0
- package/dist/v2/{safe-notification-target-wtj0bbc2.js → safe-notification-target-eb1n1vfb.js} +2 -2
- package/dist/v2/{send-session-notification-mq9frrtm.js → send-session-notification-qs0j78v6.js} +6 -6
- package/dist/v2/server-14vq4kpm.js +30 -0
- package/dist/v2/server-1bc61ans.js +154 -0
- package/dist/v2/{server-n96ag4rk.js → server-1zx87sdm.js} +5 -1
- package/dist/v2/server-3n4q9xme.js +79 -0
- package/dist/v2/server-4663ejam.js +3351 -0
- package/dist/v2/{server-rhdgxp1t.js → server-51dv1pr5.js} +63 -2
- package/dist/v2/{server-5317ykaf.js → server-6r257mf5.js} +1 -1
- package/dist/v2/server-84w6rvvf.js +14 -0
- package/dist/v2/{server-qpg6wf72.js → server-ajzeteqw.js} +9 -1
- package/dist/{index-a4m2b1yv.js → v2/server-fg34g6a5.js} +55 -1
- package/dist/v2/{server-e36nf2p1.js → server-frbm99q5.js} +1595 -1599
- package/dist/v2/{server-remp7e2g.js → server-g0fjrkta.js} +16 -1
- package/dist/v2/{server-z19x7eqz.js → server-mcfawjgc.js} +4 -4
- package/dist/v2/server-p2en78c8.js +3892 -0
- package/dist/v2/{server-hfjfbg59.js → server-qp5hx1ad.js} +608 -105
- package/dist/v2/{server-c4g2y1z8.js → server-vnh7r35f.js} +2778 -5383
- package/dist/v2/server-vs5gpnd4.js +493 -0
- package/dist/v2/{server-w99cyt6a.js → server-wvjvfhck.js} +14 -6
- package/dist/v2/{server-v5xgft5v.js → server-xtp687da.js} +186 -3533
- package/dist/v2/{server-0jqw05sa.js → server-y8maxeft.js} +6 -84
- package/dist/v2/server.d.ts.map +1 -1
- package/dist/v2/server.js +104 -49288
- package/dist/v2/store-reader.d.ts +39 -1
- package/dist/v2/store-reader.d.ts.map +1 -1
- package/dist/v2/tool-result.d.ts +8 -0
- package/dist/v2/tool-result.d.ts.map +1 -0
- package/dist/v2/tui/index.d.ts.map +1 -1
- package/dist/v2/{wrapup-orchestrator-tbyx78dz.js → wrapup-orchestrator-r5t1pyj8.js} +20 -16
- package/dist/wrapup-orchestrator-kw3x3myw.js +26 -0
- package/package.json +22 -7
- package/src/config/index.ts +21 -4
- package/src/config/latch-permanence-guard.test.ts +6 -1
- package/src/config/live-run-config.ts +1 -0
- package/src/config/migrate-config-location.test.ts +31 -1
- package/src/config/migrate-config-location.ts +8 -41
- package/src/config/protected-tools.test.ts +70 -0
- package/src/config/raw-loader.test.ts +15 -0
- package/src/config/raw-loader.ts +1 -1
- package/src/config/removed-agent-source-fence.test.ts +10 -1
- package/src/config/schema/magic-context.test.ts +20 -1
- package/src/config/schema/magic-context.ts +21 -7
- package/src/shared/announcement.ts +6 -5
- package/src/shared/cache-ttl-display.test.ts +1 -1
- package/src/shared/cache-ttl-display.ts +17 -16
- package/src/shared/fold-render-lock-fence.test.ts +84 -0
- package/src/shared/fold-render-lock-fixtures.test.ts +276 -0
- package/src/shared/model-cache-ttl.test.ts +2 -2
- package/src/shared/model-cache-ttl.ts +8 -4
- package/src/shared/model-suggestion-retry.test.ts +104 -1
- package/src/shared/model-suggestion-retry.ts +63 -6
- package/src/shared/models-dev-cache.ts +3 -11
- package/src/shared/protected-tools-policy.ts +23 -0
- package/src/shared/quota-diagnostic.ts +9 -0
- package/src/shared/rpc-server.ts +6 -54
- package/src/shared/sqlite-context-pragmas.test.ts +105 -0
- package/src/shared/sqlite-context-pragmas.ts +24 -0
- package/src/shared/sqlite-helpers.ts +17 -0
- package/src/shared/sqlite.ts +75 -0
- package/src/shared/status-detail-text.test.ts +18 -1
- package/src/shared/status-summary.ts +11 -0
- package/src/shared/status-view-check.ts +5 -0
- package/src/shared/status-view.test.ts +11 -2
- package/src/shared/status-view.ts +12 -1
- package/src/shared/storage-permissions.test.ts +204 -0
- package/src/shared/storage-permissions.ts +192 -0
- package/src/shared/temporal-upgrade-fixture.ts +50 -0
- package/src/shared/user-facing-codes.ts +6 -0
- package/src/shared/write-transaction-timing.test.ts +39 -0
- package/src/shared/write-transaction-timing.ts +25 -1
- package/src/tui/dialogs/status-dialog-render.test.ts +1 -1
- package/src/tui/index.tsx +3 -1
- package/src/tui/startup-order.test.ts +16 -0
- package/src/tui-compiled/index.tsx +3 -1
- package/src/v2/tui/index.ts +9 -2
- package/dist/index-anq4nn6f.js +0 -131
- package/dist/index-e44zzy84.js +0 -10
- package/dist/index-x23gah8c.js +0 -16
- package/dist/v2/recomp-orchestrator-1aq7h44c.js +0 -36
- package/dist/v2/server-e44zzy84.js +0 -10
- package/dist/v2/server-fgmxwrgy.js +0 -16
- package/dist/v2/server-r7cmye3k.js +0 -131
- package/dist/wrapup-orchestrator-h28bqsy6.js +0 -26
- package/dist/v2/{server-ckpc8pxy.js → server-1qbnzc80.js} +8 -8
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
} from "../../features/magic-context/dreamer/task-registry";
|
|
9
9
|
import { toolTemplateError } from "../../shared/historian-tool-template";
|
|
10
10
|
import { isValidPromptSurfaceModelKey } from "../../shared/prompt-surface";
|
|
11
|
+
import { DEFAULT_PROTECTED_TOOLS, mergeProtectedTools } from "../../shared/protected-tools-policy";
|
|
11
12
|
import { AgentOverrideConfigSchema } from "./agent-overrides";
|
|
12
13
|
|
|
13
14
|
export const DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65;
|
|
@@ -918,6 +919,8 @@ export interface MuralConfig {
|
|
|
918
919
|
}
|
|
919
920
|
|
|
920
921
|
export interface MagicContextConfig {
|
|
922
|
+
/** The loader sets this to distinguish an explicit `5m` from the built-in default; users do not configure it. */
|
|
923
|
+
cacheTtlConfigured?: boolean;
|
|
921
924
|
enabled: boolean;
|
|
922
925
|
/** User-level setting that lets a session in the canonical home directory use project memory. */
|
|
923
926
|
allow_home_project: boolean;
|
|
@@ -955,6 +958,7 @@ export interface MagicContextConfig {
|
|
|
955
958
|
execute_threshold_tokens?: { default?: number; [modelKey: string]: number | undefined };
|
|
956
959
|
protected_tokens?: number;
|
|
957
960
|
protected_tags?: number;
|
|
961
|
+
protected_tools: Record<string, number>;
|
|
958
962
|
clear_reasoning_age: number;
|
|
959
963
|
history_budget_percentage: number;
|
|
960
964
|
historian_timeout_ms: number;
|
|
@@ -1038,7 +1042,8 @@ export interface MagicContextConfig {
|
|
|
1038
1042
|
* on its own; when off, the messages sent to the model are byte-identical to
|
|
1039
1043
|
* the age-based-only behavior. Experimental, opt-in, default off until cache
|
|
1040
1044
|
* stability is proven. */
|
|
1041
|
-
|
|
1045
|
+
/** Deprecated and ignored: supersession reclaim is always on. */
|
|
1046
|
+
smart_drops?: unknown;
|
|
1042
1047
|
/**
|
|
1043
1048
|
* Age-tier caveman compression for long user/assistant text parts.
|
|
1044
1049
|
* Graduated from `experimental.caveman_text_compression`; opt-in, default off.
|
|
@@ -1187,7 +1192,7 @@ export const MagicContextConfigSchema = z
|
|
|
1187
1192
|
.union([z.string(), z.object({ default: z.string() }).catchall(z.string())])
|
|
1188
1193
|
.default("5m")
|
|
1189
1194
|
.describe(
|
|
1190
|
-
'How long Magic Context assumes the provider\'s cached prefix stays valid. This is MC\'s own deferral gate — it does not change the provider\'s actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "provider/model": "1h", "provider/*": "never" }); keys resolve most-specific first (exact provider/model, bare model ID, shorter dash-prefixes, then the provider/* wildcard).
|
|
1195
|
+
'How long Magic Context assumes the provider\'s cached prefix stays valid. This is MC\'s own deferral gate — it does not change the provider\'s actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "provider/model": "1h", "provider/*": "never" }); keys resolve most-specific first (exact provider/model, bare model ID, shorter dash-prefixes, then the provider/* wildcard, then default). User and project settings, including an explicit "5m" or object default, apply on the next pass. Only built-in defaults are frozen per session, including across restarts: when unset, GPT-5.6 and later (including gpt-6*, through any provider prefix) use 30m, other models use 5m. /ctx-status shows the effective TTL and whether it comes from your config or a frozen built-in default. Editing the TTL does not itself rewrite prompt bytes; a lowered TTL rebuilds only after normal idle expiry. OpenAI documents at least 30 minutes since the latest write or reuse: https://developers.openai.com/api/docs/guides/prompt-caching (Cache lifetime and Summary of model differences). Set to "never" to mean MC never assumes expiry (for lanes kept warm externally by a cache-keep tool) — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time. Provider-side extended TTL is a separate request-level concern (cache_control: { ttl } in the request body).',
|
|
1191
1196
|
),
|
|
1192
1197
|
prompt_surface: PromptSurfaceConfigSchema.default({ default: "full" }).describe(
|
|
1193
1198
|
"Prompt-surface presets: default is full; models use bare model IDs, provider/model, or provider/* routing keys. Guidance and tool-description overrides are user-level only. OpenCode 1.x, Pi, and OMP register tool descriptions once per process (they follow the default preset). OpenCode 2 rewrites the five ctx_* descriptions per request from the draft model.",
|
|
@@ -1346,12 +1351,12 @@ export const MagicContextConfigSchema = z
|
|
|
1346
1351
|
.boolean()
|
|
1347
1352
|
.default(true)
|
|
1348
1353
|
.describe(
|
|
1349
|
-
"When true (default), Magic Context creates and re-tightens its storage directories to owner-only 0700 and storage files to owner-only 0600. Set false only for a deliberate trusted-group deployment whose operator manages
|
|
1354
|
+
"When true (default), Magic Context creates and re-tightens its TypeScript-mode storage directories to owner-only 0700 and storage files to owner-only 0600. Set false only for a deliberate trusted-group deployment whose operator manages those files externally; in TypeScript mode Magic Context then skips its own creation modes and recursive tightening. In Rust transform mode, ck-mc's store library always keeps the shared data directory owner-only 0700, regardless of this setting. USER-LEVEL ONLY — ignored in project config for security. On Windows, POSIX chmod modes are already meaningless, so this setting is a no-op.",
|
|
1350
1355
|
),
|
|
1351
1356
|
})
|
|
1352
1357
|
.default({ enforce_private_permissions: true })
|
|
1353
1358
|
.describe(
|
|
1354
|
-
"Storage permission policy. The default keeps session content and memories owner-private. Disabling enforcement is for trusted shared-group storage managed externally;
|
|
1359
|
+
"Storage permission policy. The default keeps session content and memories owner-private. Disabling enforcement is for trusted shared-group storage managed externally; TypeScript mode follows that policy, but Rust transform mode always keeps its shared data directory owner-only because ck-mc's store library enforces it.",
|
|
1355
1360
|
),
|
|
1356
1361
|
embedding: EmbeddingConfigSchema.default({
|
|
1357
1362
|
provider: "local",
|
|
@@ -1438,10 +1443,18 @@ export const MagicContextConfigSchema = z
|
|
|
1438
1443
|
"Pi-only child-process extension controls. This setting is user-level only; project configuration cannot choose which extensions a user's subagent children load.",
|
|
1439
1444
|
),
|
|
1440
1445
|
smart_drops: z
|
|
1441
|
-
.
|
|
1442
|
-
.
|
|
1446
|
+
.unknown()
|
|
1447
|
+
.optional()
|
|
1448
|
+
.describe(
|
|
1449
|
+
"Deprecated: ignored. Content-aware supersession reclaim is always on, only on passes already rebuilding the cache. Remove this key; it no longer does anything.",
|
|
1450
|
+
)
|
|
1451
|
+
.meta({ deprecated: true }),
|
|
1452
|
+
protected_tools: z
|
|
1453
|
+
.record(z.string(), z.number().int().nonnegative())
|
|
1454
|
+
.default({ ...DEFAULT_PROTECTED_TOOLS })
|
|
1455
|
+
.transform((map) => mergeProtectedTools(map))
|
|
1443
1456
|
.describe(
|
|
1444
|
-
"
|
|
1457
|
+
"Keep each tool's newest N still-active results in every automatic drop lane (issue 621). User and project maps merge over defaults {todowrite: 1, ctx_reduce: 3}; 0 turns protection off. Names are case-insensitive and ignore leading mcp_. Holds even at 95% pressure, with no byte cap: large protected outputs can reach refusal sooner. Queued drops, from the agent or historian publication, are held until newer calls displace the result and a later cache-rebuilding pass applies them. The historian's summary is unaffected; the raw result leaves at the next fold. Frozen strips are unaffected. Changes and rotation never originate a bust; dropped results are never restored.",
|
|
1445
1458
|
),
|
|
1446
1459
|
caveman_text_compression: z
|
|
1447
1460
|
.object({
|
|
@@ -1571,6 +1584,7 @@ export const MagicContextConfigSchema = z
|
|
|
1571
1584
|
|
|
1572
1585
|
/** Settings whose fresh values can be used by later agent runs without changing rendered prompt bytes. */
|
|
1573
1586
|
export const LIVE_RELOAD_CONFIG_PATHS = [
|
|
1587
|
+
"cache_ttl",
|
|
1574
1588
|
"mural.model",
|
|
1575
1589
|
"toast_duration_ms",
|
|
1576
1590
|
"historian.opencode.model",
|
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
* Leave both empty (`""` and `[]`) to skip the dialog entirely.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import
|
|
18
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
19
19
|
import * as path from "node:path";
|
|
20
20
|
import { compareSemverCore } from "../hooks/auto-update-checker/semver";
|
|
21
21
|
import { getMagicContextStorageDir } from "./data-path";
|
|
22
|
+
import { ensureStorageDirectorySync, writeStorageFileAtomicSync } from "./storage-permissions";
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Bump only when there are user-visible changes worth a startup dialog.
|
|
@@ -60,8 +61,8 @@ type AnnouncementStateRead =
|
|
|
60
61
|
function readAnnouncementState(): AnnouncementStateRead {
|
|
61
62
|
try {
|
|
62
63
|
const file = getStateFilePath();
|
|
63
|
-
if (!
|
|
64
|
-
const version =
|
|
64
|
+
if (!existsSync(file)) return { status: "missing" };
|
|
65
|
+
const version = readFileSync(file, "utf-8").trim();
|
|
65
66
|
if (!version) return { status: "error" };
|
|
66
67
|
return { status: "valid", version };
|
|
67
68
|
} catch {
|
|
@@ -88,8 +89,8 @@ export function markAnnouncementSeen(version: string): void {
|
|
|
88
89
|
if (!version) return;
|
|
89
90
|
try {
|
|
90
91
|
const dir = getMagicContextStorageDir();
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
ensureStorageDirectorySync(dir);
|
|
93
|
+
writeStorageFileAtomicSync(getStateFilePath(), version);
|
|
93
94
|
} catch {
|
|
94
95
|
// best-effort
|
|
95
96
|
}
|
|
@@ -45,7 +45,7 @@ describe("resolveCacheTtlDisplay", () => {
|
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
expect(configured.source).toBe("config");
|
|
48
|
-
expect(session).toEqual({ value: "
|
|
48
|
+
expect(session).toEqual({ value: "1h", source: "config", modelKey });
|
|
49
49
|
expect(fallback).toEqual({ value: "5m", source: "default", modelKey });
|
|
50
50
|
});
|
|
51
51
|
|
|
@@ -10,7 +10,7 @@ export interface CacheTtlDisplay {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export interface ResolveCacheTtlDisplayArgs {
|
|
13
|
-
frozen?: ResolvedCacheTtl;
|
|
13
|
+
frozen?: ResolvedCacheTtl & { builtInDefault?: ResolvedCacheTtl };
|
|
14
14
|
configured: MagicContextConfig["cache_ttl"];
|
|
15
15
|
configuredExplicitly: boolean;
|
|
16
16
|
modelKey: string | undefined;
|
|
@@ -20,12 +20,22 @@ export interface ResolveCacheTtlDisplayArgs {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* Resolve
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* Resolve the lifetime shown in status without changing the value saved for the scheduler.
|
|
24
|
+
* The next pass uses current settings; a saved built-in lifetime applies only to the same
|
|
25
|
+
* model, even after an override is removed.
|
|
26
26
|
*/
|
|
27
27
|
export function resolveCacheTtlDisplay(args: ResolveCacheTtlDisplayArgs): CacheTtlDisplay {
|
|
28
|
-
|
|
28
|
+
const resolved = resolveModelCacheTtl(
|
|
29
|
+
args.configured,
|
|
30
|
+
args.modelKey,
|
|
31
|
+
args.configuredExplicitly,
|
|
32
|
+
);
|
|
33
|
+
if (resolved.source === "config") return resolved;
|
|
34
|
+
if (args.frozen && (!args.modelKey || args.frozen.modelKey === args.modelKey)) {
|
|
35
|
+
return args.frozen.source === "config"
|
|
36
|
+
? (args.frozen.builtInDefault ?? resolved)
|
|
37
|
+
: args.frozen;
|
|
38
|
+
}
|
|
29
39
|
if (
|
|
30
40
|
(args.sessionModelKey && (!args.modelKey || args.sessionModelKey === args.modelKey)) ||
|
|
31
41
|
(!args.modelKey && !args.sessionModelKey && args.sessionValue !== "5m")
|
|
@@ -37,22 +47,13 @@ export function resolveCacheTtlDisplay(args: ResolveCacheTtlDisplayArgs): CacheT
|
|
|
37
47
|
};
|
|
38
48
|
}
|
|
39
49
|
|
|
40
|
-
const resolved = resolveModelCacheTtl(args.configured, args.modelKey);
|
|
41
|
-
if (
|
|
42
|
-
resolved.source === "default" &&
|
|
43
|
-
typeof args.configured === "string" &&
|
|
44
|
-
args.configuredExplicitly
|
|
45
|
-
)
|
|
46
|
-
return { ...resolved, source: "config" };
|
|
47
50
|
return resolved;
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
export function formatCacheTtlDisplay(display: CacheTtlDisplay): string {
|
|
51
|
-
if (display.source === "OpenAI GPT-5.6+ default")
|
|
52
|
-
return `Cache TTL: ${display.value} (${display.source})`;
|
|
53
54
|
if (display.source === "session") return `Cache TTL: ${display.value} (session)`;
|
|
54
55
|
if (display.source === "config") {
|
|
55
|
-
return `Cache TTL: ${display.value} (config
|
|
56
|
+
return `Cache TTL: ${display.value} (your config)`;
|
|
56
57
|
}
|
|
57
|
-
return `Cache TTL: ${display.value} (default
|
|
58
|
+
return `Cache TTL: ${display.value} (built-in default, frozen for this session)`;
|
|
58
59
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import ts from "typescript";
|
|
5
|
+
|
|
6
|
+
const root = resolve(import.meta.dir, "../../../../");
|
|
7
|
+
|
|
8
|
+
for (const [host, path, functions] of [
|
|
9
|
+
[
|
|
10
|
+
"OpenCode",
|
|
11
|
+
"packages/plugin/src/hooks/magic-context/inject-compartments.ts",
|
|
12
|
+
["materializeM0", "softRefreshCachedM1"],
|
|
13
|
+
],
|
|
14
|
+
[
|
|
15
|
+
"Pi",
|
|
16
|
+
"packages/pi-plugin/src/inject-compartments-pi.ts",
|
|
17
|
+
["materializeM0Pi", "softRefreshCachedM1Pi"],
|
|
18
|
+
],
|
|
19
|
+
] as const) {
|
|
20
|
+
test(`${host} fold and refresh render m[1] inside their writer section`, () => {
|
|
21
|
+
const source = ts.createSourceFile(
|
|
22
|
+
path,
|
|
23
|
+
readFileSync(resolve(root, path), "utf8"),
|
|
24
|
+
ts.ScriptTarget.Latest,
|
|
25
|
+
true,
|
|
26
|
+
);
|
|
27
|
+
const inspected: string[] = [];
|
|
28
|
+
const violations: string[] = [];
|
|
29
|
+
function visit(node: ts.Node): void {
|
|
30
|
+
if (
|
|
31
|
+
ts.isFunctionDeclaration(node) &&
|
|
32
|
+
node.name &&
|
|
33
|
+
functions.some((name) => name === node.name?.text)
|
|
34
|
+
) {
|
|
35
|
+
inspected.push(node.name.text);
|
|
36
|
+
const calls: ts.CallExpression[] = [];
|
|
37
|
+
function collect(child: ts.Node): void {
|
|
38
|
+
if (ts.isCallExpression(child)) calls.push(child);
|
|
39
|
+
ts.forEachChild(child, collect);
|
|
40
|
+
}
|
|
41
|
+
collect(node);
|
|
42
|
+
const admission = calls.find(
|
|
43
|
+
(call) =>
|
|
44
|
+
call.expression.getText(source).endsWith(".exec") &&
|
|
45
|
+
call.arguments[0]?.getText(source) === '"BEGIN IMMEDIATE"',
|
|
46
|
+
);
|
|
47
|
+
expect(admission).toBeDefined();
|
|
48
|
+
const commit = calls.find(
|
|
49
|
+
(call) =>
|
|
50
|
+
admission &&
|
|
51
|
+
call.pos > admission.pos &&
|
|
52
|
+
call.expression.getText(source).endsWith(".exec") &&
|
|
53
|
+
call.arguments[0]?.getText(source) === '"COMMIT"',
|
|
54
|
+
);
|
|
55
|
+
expect(commit).toBeDefined();
|
|
56
|
+
const renders = calls.filter((call) =>
|
|
57
|
+
/^renderM1(?:Pi)?WithMetadata$/.test(call.expression.getText(source)),
|
|
58
|
+
);
|
|
59
|
+
expect(renders).toHaveLength(1);
|
|
60
|
+
for (const render of renders) {
|
|
61
|
+
if (
|
|
62
|
+
!admission ||
|
|
63
|
+
!commit ||
|
|
64
|
+
render.pos < admission.pos ||
|
|
65
|
+
render.pos > commit.pos
|
|
66
|
+
)
|
|
67
|
+
violations.push(`${node.name.text}: m[1] render outside writer`);
|
|
68
|
+
}
|
|
69
|
+
for (const call of calls) {
|
|
70
|
+
if (
|
|
71
|
+
call.expression.getText(source).endsWith("onFoldPrepare") &&
|
|
72
|
+
admission &&
|
|
73
|
+
call.pos > admission.pos
|
|
74
|
+
)
|
|
75
|
+
violations.push(`${node.name.text}: wire preparation inside writer`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
ts.forEachChild(node, visit);
|
|
79
|
+
}
|
|
80
|
+
visit(source);
|
|
81
|
+
expect(inspected.sort()).toEqual([...functions].sort());
|
|
82
|
+
expect(violations).toEqual([]);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import { rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { appendCompartments } from "../features/magic-context/compartment-storage";
|
|
6
|
+
import {
|
|
7
|
+
insertMemory,
|
|
8
|
+
setMemoryClassification,
|
|
9
|
+
updateMemorySeenCount,
|
|
10
|
+
updateMemoryVerification,
|
|
11
|
+
} from "../features/magic-context/memory/storage-memory";
|
|
12
|
+
import {
|
|
13
|
+
recordIndexedMessageTime,
|
|
14
|
+
recordMessageFtsRowid,
|
|
15
|
+
} from "../features/magic-context/message-fts-rowid-map";
|
|
16
|
+
import { runMigrations } from "../features/magic-context/migrations";
|
|
17
|
+
import { getOrCreateSessionMeta } from "../features/magic-context/storage";
|
|
18
|
+
import { initializeDatabase } from "../features/magic-context/storage-db";
|
|
19
|
+
import { recoverUnresolvedCompartments } from "../features/magic-context/store-generation-rebase";
|
|
20
|
+
import { renderMemoryBlockV2 } from "../hooks/magic-context/inject-compartments";
|
|
21
|
+
import { estimateTokens } from "../hooks/magic-context/read-session-formatting";
|
|
22
|
+
import { Database } from "./sqlite";
|
|
23
|
+
import { createTestTempDirFromPath } from "./test-temp-dir";
|
|
24
|
+
|
|
25
|
+
export interface LockedDeltaFixture {
|
|
26
|
+
db: Database;
|
|
27
|
+
sibling: Database;
|
|
28
|
+
directory: string;
|
|
29
|
+
sessionId: string;
|
|
30
|
+
projectPath: string;
|
|
31
|
+
close: () => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function createLockedDeltaFixture(
|
|
35
|
+
label: string,
|
|
36
|
+
open?: (path: string) => Database,
|
|
37
|
+
): LockedDeltaFixture {
|
|
38
|
+
const directory = createTestTempDirFromPath(join(tmpdir(), `mc-locked-delta-${label}-`));
|
|
39
|
+
const path = join(directory, "context.db");
|
|
40
|
+
const db = open ? open(path) : new Database(path);
|
|
41
|
+
if (!open) {
|
|
42
|
+
initializeDatabase(db);
|
|
43
|
+
runMigrations(db);
|
|
44
|
+
}
|
|
45
|
+
db.exec("PRAGMA journal_mode=WAL");
|
|
46
|
+
const sibling = new Database(path);
|
|
47
|
+
const sessionId = label;
|
|
48
|
+
const projectPath = "git:locked-delta";
|
|
49
|
+
getOrCreateSessionMeta(db, sessionId);
|
|
50
|
+
return {
|
|
51
|
+
db,
|
|
52
|
+
sibling,
|
|
53
|
+
directory,
|
|
54
|
+
sessionId,
|
|
55
|
+
projectPath,
|
|
56
|
+
close: () => {
|
|
57
|
+
sibling.close();
|
|
58
|
+
db.close();
|
|
59
|
+
rmSync(directory, { recursive: true, force: true });
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export interface LockedDeltaOptions {
|
|
64
|
+
memoryBudget?: number;
|
|
65
|
+
temporalAwareness?: boolean;
|
|
66
|
+
}
|
|
67
|
+
interface LockedDeltaDriver<Markers> {
|
|
68
|
+
host: string;
|
|
69
|
+
create: (label: string) => LockedDeltaFixture;
|
|
70
|
+
materialize: (fixture: LockedDeltaFixture, options: LockedDeltaOptions) => Markers;
|
|
71
|
+
refresh: (
|
|
72
|
+
fixture: LockedDeltaFixture,
|
|
73
|
+
options: LockedDeltaOptions,
|
|
74
|
+
beforeAdmission: () => void,
|
|
75
|
+
) => void;
|
|
76
|
+
render: (fixture: LockedDeltaFixture, options: LockedDeltaOptions, markers: Markers) => string;
|
|
77
|
+
temporalHeadings?: boolean;
|
|
78
|
+
}
|
|
79
|
+
function compartment() {
|
|
80
|
+
return {
|
|
81
|
+
sequence: 0,
|
|
82
|
+
startMessage: 1,
|
|
83
|
+
endMessage: 2,
|
|
84
|
+
startMessageId: "a",
|
|
85
|
+
endMessageId: "b",
|
|
86
|
+
title: "locked history",
|
|
87
|
+
content: "locked history",
|
|
88
|
+
p1: "locked history",
|
|
89
|
+
p2: "summary",
|
|
90
|
+
p3: "outcome",
|
|
91
|
+
p4: "anchor",
|
|
92
|
+
legacy: 0,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function persistedDelta(f: LockedDeltaFixture): string {
|
|
96
|
+
return getOrCreateSessionMeta(f.db, f.sessionId).cachedM1Bytes?.toString("utf8") ?? "";
|
|
97
|
+
}
|
|
98
|
+
function refreshAtAdmission<Markers>(
|
|
99
|
+
driver: LockedDeltaDriver<Markers>,
|
|
100
|
+
f: LockedDeltaFixture,
|
|
101
|
+
options: LockedDeltaOptions,
|
|
102
|
+
write: () => void,
|
|
103
|
+
) {
|
|
104
|
+
let admissions = 0;
|
|
105
|
+
let hooks = 0;
|
|
106
|
+
const exec = f.db.exec.bind(f.db);
|
|
107
|
+
f.db.exec = (sql) => {
|
|
108
|
+
if (sql === "BEGIN IMMEDIATE") admissions++;
|
|
109
|
+
return exec(sql);
|
|
110
|
+
};
|
|
111
|
+
try {
|
|
112
|
+
driver.refresh(f, options, () => {
|
|
113
|
+
expect(admissions).toBe(0);
|
|
114
|
+
hooks++;
|
|
115
|
+
write();
|
|
116
|
+
});
|
|
117
|
+
expect(hooks).toBe(1);
|
|
118
|
+
expect(admissions).toBe(1);
|
|
119
|
+
} finally {
|
|
120
|
+
f.db.exec = exec;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** These fixtures use real sibling writes, then compare persisted bytes to an independent live render. */
|
|
125
|
+
export function registerLockedDeltaRegressions<Markers>(driver: LockedDeltaDriver<Markers>): void {
|
|
126
|
+
for (const change of ["importance", "reinforcement", "verification"] as const) {
|
|
127
|
+
test(`${driver.host} m[1] reads memory ${change} under its writer`, () => {
|
|
128
|
+
const f = driver.create(`${driver.host}-${change}`);
|
|
129
|
+
try {
|
|
130
|
+
const sample = insertMemory(f.db, {
|
|
131
|
+
projectPath: "git:budget-only",
|
|
132
|
+
category: "ARCHITECTURE",
|
|
133
|
+
content: "candidate A ".repeat(40),
|
|
134
|
+
});
|
|
135
|
+
const options = {
|
|
136
|
+
memoryBudget:
|
|
137
|
+
4 * (estimateTokens(renderMemoryBlockV2([sample], "new-memories")) + 2),
|
|
138
|
+
};
|
|
139
|
+
const markers = driver.materialize(f, options);
|
|
140
|
+
const a = insertMemory(f.db, {
|
|
141
|
+
projectPath: f.projectPath,
|
|
142
|
+
category: "ARCHITECTURE",
|
|
143
|
+
content: "candidate A ".repeat(40),
|
|
144
|
+
});
|
|
145
|
+
const b = insertMemory(f.db, {
|
|
146
|
+
projectPath: f.projectPath,
|
|
147
|
+
category: "ARCHITECTURE",
|
|
148
|
+
content: "candidate B ".repeat(40),
|
|
149
|
+
});
|
|
150
|
+
setMemoryClassification(f.db, a.id, { importance: 50 });
|
|
151
|
+
setMemoryClassification(f.db, b.id, { importance: 50 });
|
|
152
|
+
f.db
|
|
153
|
+
.prepare(
|
|
154
|
+
"UPDATE memories SET last_seen_at = CASE WHEN id = ? THEN 1000 ELSE 0 END, verified_at = NULL WHERE id IN (?, ?)",
|
|
155
|
+
)
|
|
156
|
+
.run(a.id, a.id, b.id);
|
|
157
|
+
const before = driver.render(f, options, markers);
|
|
158
|
+
expect(before).toContain("candidate A");
|
|
159
|
+
expect(before).not.toContain("candidate B");
|
|
160
|
+
refreshAtAdmission(driver, f, options, () => {
|
|
161
|
+
if (change === "importance")
|
|
162
|
+
setMemoryClassification(f.sibling, b.id, { importance: 100 });
|
|
163
|
+
else if (change === "reinforcement") updateMemorySeenCount(f.sibling, b.id);
|
|
164
|
+
else updateMemoryVerification(f.sibling, b.id, "verified");
|
|
165
|
+
});
|
|
166
|
+
const fresh = driver.render(f, options, markers);
|
|
167
|
+
expect(fresh).toContain("candidate B");
|
|
168
|
+
expect(fresh).not.toContain("candidate A");
|
|
169
|
+
expect(persistedDelta(f)).toBe(fresh);
|
|
170
|
+
expect(persistedDelta(f)).not.toBe(before);
|
|
171
|
+
} finally {
|
|
172
|
+
f.close();
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
test(`${driver.host} m[1] reads in-place recovered compartment ranges under its writer`, () => {
|
|
178
|
+
const f = driver.create(`${driver.host}-ranges`);
|
|
179
|
+
try {
|
|
180
|
+
const options = {};
|
|
181
|
+
const markers = driver.materialize(f, options);
|
|
182
|
+
appendCompartments(f.db, f.sessionId, [compartment()]);
|
|
183
|
+
f.db
|
|
184
|
+
.prepare(
|
|
185
|
+
"UPDATE compartments SET rebase_status = 'unresolved' WHERE session_id = ?",
|
|
186
|
+
)
|
|
187
|
+
.run(f.sessionId);
|
|
188
|
+
const before = driver.render(f, options, markers);
|
|
189
|
+
expect(before).toContain("## 1-2");
|
|
190
|
+
const revision = f.db
|
|
191
|
+
.prepare("SELECT version FROM compartment_history_versions WHERE session_id = ?")
|
|
192
|
+
.get(f.sessionId) as { version: number };
|
|
193
|
+
refreshAtAdmission(driver, f, options, () => {
|
|
194
|
+
const recovered = recoverUnresolvedCompartments({
|
|
195
|
+
db: f.sibling,
|
|
196
|
+
sessionId: f.sessionId,
|
|
197
|
+
resolveOrdinal: (id) => (id === "a" ? 3 : id === "b" ? 4 : undefined),
|
|
198
|
+
reason: "Recovered fixture anchors",
|
|
199
|
+
});
|
|
200
|
+
expect(recovered.rowsRewritten).toBe(1);
|
|
201
|
+
});
|
|
202
|
+
const updated = f.db
|
|
203
|
+
.prepare("SELECT version FROM compartment_history_versions WHERE session_id = ?")
|
|
204
|
+
.get(f.sessionId) as { version: number };
|
|
205
|
+
expect(updated.version).toBeGreaterThan(revision.version);
|
|
206
|
+
const fresh = driver.render(f, options, markers);
|
|
207
|
+
expect(fresh).toContain("## 3-4");
|
|
208
|
+
expect(fresh).not.toContain("## 1-2");
|
|
209
|
+
expect(persistedDelta(f)).toBe(fresh);
|
|
210
|
+
} finally {
|
|
211
|
+
f.close();
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test(`${driver.host} m[1] uses the baseline cutoff for a newly expired additive memory`, () => {
|
|
216
|
+
const f = driver.create(`${driver.host}-expiry`);
|
|
217
|
+
const realNow = Date.now;
|
|
218
|
+
let now = 1000;
|
|
219
|
+
Date.now = () => now;
|
|
220
|
+
try {
|
|
221
|
+
const options = {};
|
|
222
|
+
const markers = driver.materialize(f, options);
|
|
223
|
+
now = 2000;
|
|
224
|
+
const before = driver.render(f, options, markers);
|
|
225
|
+
expect(before).not.toContain("eligible at the baseline cutoff");
|
|
226
|
+
refreshAtAdmission(driver, f, options, () => {
|
|
227
|
+
insertMemory(f.sibling, {
|
|
228
|
+
projectPath: f.projectPath,
|
|
229
|
+
category: "ARCHITECTURE",
|
|
230
|
+
content: "Memory eligible at the baseline cutoff",
|
|
231
|
+
expiresAt: 2500,
|
|
232
|
+
});
|
|
233
|
+
now = 3000;
|
|
234
|
+
});
|
|
235
|
+
const fresh = driver.render(f, options, markers);
|
|
236
|
+
expect(fresh).toContain("eligible at the baseline cutoff");
|
|
237
|
+
expect(persistedDelta(f)).toBe(fresh);
|
|
238
|
+
} finally {
|
|
239
|
+
Date.now = realNow;
|
|
240
|
+
f.close();
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
if (driver.temporalHeadings) {
|
|
245
|
+
test(`${driver.host} m[1] reads indexed temporal headings under its writer`, () => {
|
|
246
|
+
const f = driver.create(`${driver.host}-dates`);
|
|
247
|
+
const originalXdgDataHome = process.env.XDG_DATA_HOME;
|
|
248
|
+
process.env.XDG_DATA_HOME = f.directory;
|
|
249
|
+
try {
|
|
250
|
+
const options = { temporalAwareness: true };
|
|
251
|
+
const markers = driver.materialize(f, options);
|
|
252
|
+
appendCompartments(f.db, f.sessionId, [compartment()]);
|
|
253
|
+
for (const ordinal of [1, 2])
|
|
254
|
+
recordMessageFtsRowid(f.db, f.sessionId, ordinal, ordinal);
|
|
255
|
+
const before = driver.render(f, options, markers);
|
|
256
|
+
expect(before).not.toContain("2025-01-01");
|
|
257
|
+
refreshAtAdmission(driver, f, options, () => {
|
|
258
|
+
for (const ordinal of [1, 2])
|
|
259
|
+
recordIndexedMessageTime(
|
|
260
|
+
f.sibling,
|
|
261
|
+
f.sessionId,
|
|
262
|
+
ordinal,
|
|
263
|
+
Date.UTC(2025, 0, 1),
|
|
264
|
+
);
|
|
265
|
+
});
|
|
266
|
+
const fresh = driver.render(f, options, markers);
|
|
267
|
+
expect(fresh).toContain("2025-01-01");
|
|
268
|
+
expect(persistedDelta(f)).toBe(fresh);
|
|
269
|
+
} finally {
|
|
270
|
+
if (originalXdgDataHome === undefined) delete process.env.XDG_DATA_HOME;
|
|
271
|
+
else process.env.XDG_DATA_HOME = originalXdgDataHome;
|
|
272
|
+
f.close();
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -29,8 +29,8 @@ describe("known model cache TTL", () => {
|
|
|
29
29
|
expect(resolveCacheTtl("5m", "openai/gpt-6")).toBe("30m");
|
|
30
30
|
expect(resolveCacheTtl("10m", "openai/gpt-6")).toBe("10m");
|
|
31
31
|
});
|
|
32
|
-
it("honors per-model entries
|
|
33
|
-
expect(resolveCacheTtl({ default: "10m" }, "openai/gpt-6")).toBe("
|
|
32
|
+
it("honors per-model entries and configured defaults before built-ins", () => {
|
|
33
|
+
expect(resolveCacheTtl({ default: "10m" }, "openai/gpt-6")).toBe("10m");
|
|
34
34
|
expect(resolveCacheTtl({ default: "10m", "gpt-6": "5m" }, "openai/gpt-6")).toBe("5m");
|
|
35
35
|
expect(resolveCacheTtl({ default: "10m", "openai/*": "never" }, "openai/gpt-6")).toBe(
|
|
36
36
|
"never",
|
|
@@ -28,6 +28,8 @@ const MODEL_CACHE_LIFETIMES = [
|
|
|
28
28
|
export function resolveModelCacheTtl(
|
|
29
29
|
config: CacheTtlConfig | undefined,
|
|
30
30
|
modelKey: string | undefined,
|
|
31
|
+
configuredExplicitly = typeof config === "object" ||
|
|
32
|
+
(typeof config === "string" && config !== "5m"),
|
|
31
33
|
): ResolvedCacheTtl {
|
|
32
34
|
if (config && typeof config !== "string") {
|
|
33
35
|
const match =
|
|
@@ -37,11 +39,13 @@ export function resolveModelCacheTtl(
|
|
|
37
39
|
modelKey !== "default"
|
|
38
40
|
? config[modelKey]
|
|
39
41
|
: resolveModelConfigValue(config, modelKey)?.value;
|
|
40
|
-
|
|
42
|
+
const value = match ?? config.default;
|
|
43
|
+
if (value !== undefined && configuredExplicitly)
|
|
44
|
+
return { value, source: "config", modelKey };
|
|
41
45
|
}
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
if (typeof config === "string" &&
|
|
46
|
+
// The loader supplies provenance: an explicit 5m is policy too. Older callers
|
|
47
|
+
// without that bit still distinguish non-default strings from the schema's 5m.
|
|
48
|
+
if (typeof config === "string" && configuredExplicitly)
|
|
45
49
|
return { value: config, source: "config", modelKey };
|
|
46
50
|
const model =
|
|
47
51
|
canonicalModelIdentity(modelKey ?? "")
|