@cortexkit/opencode-magic-context 0.45.0 → 0.46.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +13 -7
- 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-sh2m2vde.js +4525 -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-8fgkmxmy.js → index-5p8jdswx.js} +4 -3
- package/dist/{index-75zjgwga.js → index-7qw742ev.js} +1 -1
- package/dist/{index-f85teqck.js → index-8da2zjhz.js} +3 -256
- package/dist/{index-q7yesyk9.js → index-8x2v7gg9.js} +25 -24
- package/dist/{index-w9jwmntv.js → index-b35pxds2.js} +9 -1
- package/dist/{v2/server-a4m2b1yv.js → index-fg34g6a5.js} +55 -1
- package/dist/index-hpecdzec.js +28506 -0
- package/dist/{index-2ntg5sd4.js → index-k5bdx1bx.js} +9 -5
- package/dist/{index-bmzf7zxv.js → index-majxda46.js} +23 -5
- package/dist/{index-2aq21j41.js → index-pkbcrdqs.js} +418 -127
- package/dist/{index-remp7e2g.js → index-q4yp4b52.js} +16 -1
- package/dist/{index-fr2z4qy8.js → index-r5hmbx3t.js} +132 -169
- package/dist/index-sfnj6h8h.js +259 -0
- package/dist/{index-xgt9k6c6.js → index-sgthv3f7.js} +2 -1
- package/dist/index-sj29b3z2.js +30 -0
- package/dist/{index-16ny736w.js → index-sjthx78w.js} +20526 -19817
- 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-y15j0rb9.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-bqhz6vdr.js} +15 -15
- package/dist/v2/context-zecmzk5s.js +52209 -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/hidden-child-native.d.ts +7 -0
- package/dist/v2/hidden-child-native.d.ts.map +1 -1
- package/dist/v2/hidden-child-record.d.ts +8 -0
- package/dist/v2/hidden-child-record.d.ts.map +1 -1
- package/dist/v2/hidden-completion.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/dream-trigger.d.ts +15 -1
- package/dist/v2/hooks/dream-trigger.d.ts.map +1 -1
- package/dist/v2/hooks/hidden-child.d.ts +54 -3
- package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
- package/dist/v2/hooks/payload.d.ts.map +1 -1
- package/dist/v2/hooks/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/types.d.ts +12 -1
- package/dist/v2/hooks/types.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-8ejxvrzz.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-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/v2/server-c5gz8wph.js +3892 -0
- package/dist/v2/{server-v5xgft5v.js → server-e29d7p7c.js} +188 -3533
- 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-c4g2y1z8.js → server-jc7y02q0.js} +2816 -5392
- package/dist/v2/{server-z19x7eqz.js → server-mcfawjgc.js} +4 -4
- package/dist/v2/{server-hfjfbg59.js → server-qp5hx1ad.js} +608 -105
- package/dist/v2/server-vs5gpnd4.js +493 -0
- package/dist/v2/{server-w99cyt6a.js → server-wvjvfhck.js} +14 -6
- package/dist/v2/server-xa4xe3rv.js +3351 -0
- 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-0snhvwcv.js} +20 -16
- package/dist/wrapup-orchestrator-39amhv9s.js +26 -0
- package/package.json +26 -10
- 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 +26 -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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { formatCacheTtlDisplay } from "./cache-ttl-display";
|
|
2
|
+
import { primaryQuotaDiagnostic } from "./quota-diagnostic";
|
|
2
3
|
import type { RunnerStatus, StatusDetail } from "./rpc-types";
|
|
3
4
|
import { renderUserFacingFailure, type UserFacingFailureKey } from "./user-facing-codes";
|
|
4
5
|
|
|
@@ -37,6 +38,7 @@ export interface UserStatusSummary {
|
|
|
37
38
|
warnings: UserFacingFailureKey[];
|
|
38
39
|
hiddenVariantWarnings?: string[];
|
|
39
40
|
dreamerSkipped?: readonly string[];
|
|
41
|
+
dreamerQuotas?: readonly string[];
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
/**
|
|
@@ -129,6 +131,14 @@ export function statusSummaryFromDetail(detail: StatusDetail): UserStatusSummary
|
|
|
129
131
|
warnings: statusWarningsFromDetail(detail),
|
|
130
132
|
hiddenVariantWarnings: detail.hiddenVariantWarnings ?? [],
|
|
131
133
|
dreamerSkipped: detail.dreamerSkipped,
|
|
134
|
+
dreamerQuotas: [
|
|
135
|
+
...new Set(
|
|
136
|
+
(detail.dreamerFailures ?? []).flatMap((failure) => {
|
|
137
|
+
const quota = primaryQuotaDiagnostic(failure.error);
|
|
138
|
+
return quota ? [quota] : [];
|
|
139
|
+
}),
|
|
140
|
+
),
|
|
141
|
+
],
|
|
132
142
|
};
|
|
133
143
|
}
|
|
134
144
|
|
|
@@ -221,6 +231,7 @@ export function renderUserStatusSummary(
|
|
|
221
231
|
values.push(["Dreamer runner", runnerText(summary.dreamerRunner)]);
|
|
222
232
|
}
|
|
223
233
|
for (const skipped of summary.dreamerSkipped ?? []) values.push(["Dreamer skipped", skipped]);
|
|
234
|
+
for (const quota of summary.dreamerQuotas ?? []) values.push(["Dreamer quota", quota]);
|
|
224
235
|
if (summary.historianRefusal) {
|
|
225
236
|
values.push([
|
|
226
237
|
"Historian refusal",
|
|
@@ -312,6 +312,11 @@ export function checkStatusViewSource(candidate: unknown):
|
|
|
312
312
|
lastDreamerRunAt: optional.read("lastDreamerRunAt", isNullableNumber),
|
|
313
313
|
dreamerUnsupportedTasks: optional.readArray("dreamerUnsupportedTasks", isString),
|
|
314
314
|
dreamerSkipped: optional.readArray("dreamerSkipped", isString),
|
|
315
|
+
dreamerFailures: optional.readArray(
|
|
316
|
+
"dreamerFailures",
|
|
317
|
+
(value): value is { task: string; error: string } =>
|
|
318
|
+
isRecord(value) && isString(value.task) && isString(value.error),
|
|
319
|
+
),
|
|
315
320
|
dreamerTickFailure: optional.read(
|
|
316
321
|
"dreamerTickFailure",
|
|
317
322
|
(value): value is NonNullable<StatusViewSource["dreamerTickFailure"]> | null =>
|
|
@@ -264,7 +264,7 @@ describe("status view model", () => {
|
|
|
264
264
|
* gap fit; otherwise the caller draws one column.
|
|
265
265
|
*/
|
|
266
266
|
test("draws two columns only when both columns' values fit", () => {
|
|
267
|
-
const sections = view().sections;
|
|
267
|
+
const sections = view({ cacheTtlSource: "default" }).sections;
|
|
268
268
|
for (const section of sections) {
|
|
269
269
|
const longest = Math.max(...section.rows.map((row) => row.value.length));
|
|
270
270
|
expect(statusSectionWidth(section)).toBe(section.labelWidth + 1 + longest);
|
|
@@ -297,7 +297,7 @@ describe("status view model", () => {
|
|
|
297
297
|
expect(statusColumnsFor(narrowValues, needed).twoColumn).toBe(true);
|
|
298
298
|
expect(statusColumnsFor(narrowValues, needed - 1).twoColumn).toBe(false);
|
|
299
299
|
|
|
300
|
-
// A long value — the
|
|
300
|
+
// A long value — the frozen-default source on the Configured row — pushes the left
|
|
301
301
|
// column past what the dialog has, so the same sections go one column
|
|
302
302
|
// rather than wrapping that value mid-word.
|
|
303
303
|
expect(statusColumnsFor(sections, 84).twoColumn).toBe(false);
|
|
@@ -398,6 +398,15 @@ describe("status view model", () => {
|
|
|
398
398
|
* (issue 496).
|
|
399
399
|
*/
|
|
400
400
|
describe("blocked background maintenance", () => {
|
|
401
|
+
test("shows a scheduled task's primary quota deadline in the status dialog", () => {
|
|
402
|
+
const error =
|
|
403
|
+
"primary quota exhausted until 2026-10-08T03:40:04.275Z; account=private@example.com";
|
|
404
|
+
const row = view({ dreamerFailures: [{ task: "verify", error }] })
|
|
405
|
+
.sections.find((section) => section.title === "History Compression")
|
|
406
|
+
?.rows.find((entry) => entry.label === "Dreamer quota");
|
|
407
|
+
expect(row?.value).toBe("primary quota exhausted until 2026-10-08T03:40:04.275Z");
|
|
408
|
+
expect(row?.tone).toBe("warning");
|
|
409
|
+
});
|
|
401
410
|
const failure = {
|
|
402
411
|
at: NOW - 2 * 3_600_000,
|
|
403
412
|
stage: "message-history maintenance",
|
|
@@ -17,6 +17,7 @@ import type { DreamerTickFailure } from "../features/magic-context/dreamer/tick-
|
|
|
17
17
|
import { formatCacheTtlDisplay } from "./cache-ttl-display";
|
|
18
18
|
import { type ConfigParseFailure, formatConfigParseStatusLine } from "./config-diagnostics";
|
|
19
19
|
import { formatThresholdPercent } from "./format-threshold";
|
|
20
|
+
import { primaryQuotaDiagnostic } from "./quota-diagnostic";
|
|
20
21
|
import type { TailHygieneStatus } from "./rpc-types";
|
|
21
22
|
import {
|
|
22
23
|
type StatusCheck,
|
|
@@ -153,6 +154,7 @@ export interface StatusViewSource {
|
|
|
153
154
|
* its work" are not the same blank space in this view.
|
|
154
155
|
*/
|
|
155
156
|
readonly dreamerTickFailure?: DreamerTickFailure | null;
|
|
157
|
+
readonly dreamerFailures?: readonly { task: string; error: string }[];
|
|
156
158
|
readonly memoryCount: number;
|
|
157
159
|
readonly sessionNoteCount?: number;
|
|
158
160
|
readonly readySmartNoteCount?: number;
|
|
@@ -525,9 +527,18 @@ function dreamerUnsupportedRows(source: StatusViewSource): StatusRow[] {
|
|
|
525
527
|
|
|
526
528
|
/** One row naming the stage that stopped the last maintenance pass, if one did. */
|
|
527
529
|
function dreamerTickFailureRows(source: StatusViewSource, now: number): StatusRow[] {
|
|
530
|
+
const quotas = [
|
|
531
|
+
...new Set(
|
|
532
|
+
(source.dreamerFailures ?? []).flatMap((failure) => {
|
|
533
|
+
const quota = primaryQuotaDiagnostic(failure.error);
|
|
534
|
+
return quota ? [quota] : [];
|
|
535
|
+
}),
|
|
536
|
+
),
|
|
537
|
+
].map((value): StatusRow => ({ label: "Dreamer quota", value, tone: "warning" }));
|
|
528
538
|
const failure = source.dreamerTickFailure;
|
|
529
|
-
if (!failure) return
|
|
539
|
+
if (!failure) return quotas;
|
|
530
540
|
return [
|
|
541
|
+
...quotas,
|
|
531
542
|
{
|
|
532
543
|
label: "Dreamer blocked",
|
|
533
544
|
value: `${failure.stage} failed ${formatRelativeTime(failure.at, now)} (${userFacingFailureCode(
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from "bun:test";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import {
|
|
4
|
+
chmodSync,
|
|
5
|
+
lstatSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
readdirSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
readlinkSync,
|
|
10
|
+
rmSync,
|
|
11
|
+
statSync,
|
|
12
|
+
symlinkSync,
|
|
13
|
+
writeFileSync,
|
|
14
|
+
} from "node:fs";
|
|
15
|
+
import { tmpdir } from "node:os";
|
|
16
|
+
import { dirname, join, resolve } from "node:path";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
import { rememberGitIdentity } from "../features/magic-context/memory/project-identity-cache";
|
|
19
|
+
import { markAnnouncementSeen } from "./announcement";
|
|
20
|
+
import { getMagicContextStorageDir } from "./data-path";
|
|
21
|
+
import {
|
|
22
|
+
__resetStoragePrivatePermissionEnforcementForTests,
|
|
23
|
+
copyStorageFileSync,
|
|
24
|
+
copyStorageTreeSync,
|
|
25
|
+
ensureStorageDirectorySync,
|
|
26
|
+
setStoragePrivatePermissionEnforcement,
|
|
27
|
+
tightenStorageTreeSync,
|
|
28
|
+
writeStorageFileAsync,
|
|
29
|
+
writeStorageFileAtomicSync,
|
|
30
|
+
writeStorageFileSync,
|
|
31
|
+
} from "./storage-permissions";
|
|
32
|
+
|
|
33
|
+
const roots: string[] = [];
|
|
34
|
+
|
|
35
|
+
function entriesBelow(path: string): string[] {
|
|
36
|
+
const found = [path];
|
|
37
|
+
const stat = lstatSync(path);
|
|
38
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) return found;
|
|
39
|
+
for (const entry of readdirSync(path)) found.push(...entriesBelow(join(path, entry)));
|
|
40
|
+
return found;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function assertPrivateTree(root: string): void {
|
|
44
|
+
for (const entry of entriesBelow(root)) {
|
|
45
|
+
const mode = statSync(entry).mode & 0o777;
|
|
46
|
+
expect(mode & 0o077, `${entry} mode ${mode.toString(8)}`).toBe(0);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
afterEach(() => {
|
|
51
|
+
__resetStoragePrivatePermissionEnforcementForTests();
|
|
52
|
+
for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true });
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe("owner-only storage permissions", () => {
|
|
56
|
+
it("creates storage directories, ordinary files, and atomic temporaries privately, then tightens old entries", async () => {
|
|
57
|
+
if (process.platform === "win32") return;
|
|
58
|
+
const root = join(
|
|
59
|
+
tmpdir(),
|
|
60
|
+
"magic-context",
|
|
61
|
+
`permissions-ts-${process.pid}-${randomUUID()}`,
|
|
62
|
+
);
|
|
63
|
+
roots.push(root);
|
|
64
|
+
const storage = join(root, "cortexkit", "magic-context");
|
|
65
|
+
|
|
66
|
+
ensureStorageDirectorySync(storage, true);
|
|
67
|
+
writeStorageFileSync(join(storage, "last_announced_version"), "0.45.0", {
|
|
68
|
+
forcePrivate: true,
|
|
69
|
+
});
|
|
70
|
+
writeStorageFileAtomicSync(join(storage, "last-update-check.json"), "{}\n", true);
|
|
71
|
+
const snapshotPath = join(storage, "snapshot.heapsnapshot");
|
|
72
|
+
await writeStorageFileAsync(snapshotPath, "snapshot", true);
|
|
73
|
+
expect(statSync(snapshotPath).mode & 0o077).toBe(0);
|
|
74
|
+
const legacy = join(storage, "project-identities");
|
|
75
|
+
mkdirSync(legacy, { recursive: true });
|
|
76
|
+
writeFileSync(join(legacy, "legacy.json"), "{}\n");
|
|
77
|
+
chmodSync(legacy, 0o755);
|
|
78
|
+
chmodSync(join(legacy, "legacy.json"), 0o644);
|
|
79
|
+
|
|
80
|
+
const result = tightenStorageTreeSync(storage);
|
|
81
|
+
|
|
82
|
+
expect(result.failures).toBe(0);
|
|
83
|
+
expect(result.tightened).toBe(2);
|
|
84
|
+
assertPrivateTree(storage);
|
|
85
|
+
|
|
86
|
+
const copySource = join(root, "copy-source", "context.db");
|
|
87
|
+
mkdirSync(dirname(copySource), { recursive: true });
|
|
88
|
+
writeFileSync(copySource, "database fixture");
|
|
89
|
+
const copyDestination = join(storage, "backup.db");
|
|
90
|
+
copyStorageFileSync(copySource, copyDestination, true);
|
|
91
|
+
expect(statSync(copyDestination).mode & 0o077).toBe(0);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("copies cache symlinks without widening the copied tree", () => {
|
|
95
|
+
if (process.platform === "win32") return;
|
|
96
|
+
const root = join(tmpdir(), "magic-context", `copy-tree-ts-${process.pid}-${randomUUID()}`);
|
|
97
|
+
roots.push(root);
|
|
98
|
+
const source = join(root, "source");
|
|
99
|
+
const destination = join(root, "data", "cortexkit", "magic-context", "models");
|
|
100
|
+
mkdirSync(source, { recursive: true });
|
|
101
|
+
writeFileSync(join(source, "blob"), "weights");
|
|
102
|
+
symlinkSync("blob", join(source, "snapshot"));
|
|
103
|
+
|
|
104
|
+
copyStorageTreeSync(source, destination, true);
|
|
105
|
+
|
|
106
|
+
expect(lstatSync(join(destination, "snapshot")).isSymbolicLink()).toBe(true);
|
|
107
|
+
expect(readlinkSync(join(destination, "snapshot"))).toBe("blob");
|
|
108
|
+
assertPrivateTree(destination);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("creates state and identity files through their public data-directory writers privately", () => {
|
|
112
|
+
if (process.platform === "win32") return;
|
|
113
|
+
const root = join(tmpdir(), "magic-context", `writers-ts-${process.pid}-${randomUUID()}`);
|
|
114
|
+
roots.push(root);
|
|
115
|
+
const previous = {
|
|
116
|
+
testData: process.env.MAGIC_CONTEXT_TEST_DATA_DIR,
|
|
117
|
+
xdgData: process.env.XDG_DATA_HOME,
|
|
118
|
+
storage: process.env.MAGIC_CONTEXT_STORAGE_DIR,
|
|
119
|
+
};
|
|
120
|
+
process.env.MAGIC_CONTEXT_TEST_DATA_DIR = root;
|
|
121
|
+
process.env.XDG_DATA_HOME = root;
|
|
122
|
+
delete process.env.MAGIC_CONTEXT_STORAGE_DIR;
|
|
123
|
+
setStoragePrivatePermissionEnforcement(true);
|
|
124
|
+
try {
|
|
125
|
+
const storage = getMagicContextStorageDir();
|
|
126
|
+
ensureStorageDirectorySync(storage, true);
|
|
127
|
+
rememberGitIdentity(join(root, "project"), "git:0123456789abcdef");
|
|
128
|
+
markAnnouncementSeen("0.45.0");
|
|
129
|
+
assertPrivateTree(storage);
|
|
130
|
+
} finally {
|
|
131
|
+
if (previous.testData === undefined) delete process.env.MAGIC_CONTEXT_TEST_DATA_DIR;
|
|
132
|
+
else process.env.MAGIC_CONTEXT_TEST_DATA_DIR = previous.testData;
|
|
133
|
+
if (previous.xdgData === undefined) delete process.env.XDG_DATA_HOME;
|
|
134
|
+
else process.env.XDG_DATA_HOME = previous.xdgData;
|
|
135
|
+
if (previous.storage === undefined) delete process.env.MAGIC_CONTEXT_STORAGE_DIR;
|
|
136
|
+
else process.env.MAGIC_CONTEXT_STORAGE_DIR = previous.storage;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("keeps storage filesystem creation behind the shared helper", () => {
|
|
141
|
+
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../../../");
|
|
142
|
+
const scanRoots = [
|
|
143
|
+
"packages/plugin/src",
|
|
144
|
+
"packages/pi-plugin/src",
|
|
145
|
+
"packages/cli/src",
|
|
146
|
+
"packages/dashboard/src",
|
|
147
|
+
];
|
|
148
|
+
const directCreate =
|
|
149
|
+
/(?:\b(?:fs\.)?(?:mkdirSync|mkdir|writeFileSync|writeFile|appendFileSync|appendFile|createWriteStream|copyFileSync|cpSync)\s*\(|\bBun\.write\s*\()/;
|
|
150
|
+
const directOpenWrite = /\b(?:openSync|open)\s*\([^,]+,\s*["'](?:w|wx|a|ax|as|as\+)/;
|
|
151
|
+
const offenders: string[] = [];
|
|
152
|
+
const visit = (absolute: string): void => {
|
|
153
|
+
for (const entry of readdirSync(absolute, { withFileTypes: true })) {
|
|
154
|
+
const path = join(absolute, entry.name);
|
|
155
|
+
if (entry.isDirectory()) {
|
|
156
|
+
if (entry.name !== "node_modules" && entry.name !== "dist") visit(path);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (
|
|
160
|
+
!/\.(?:ts|tsx|js|mjs|cjs)$/.test(entry.name) ||
|
|
161
|
+
/(?:\.test|\.spec)\./.test(entry.name)
|
|
162
|
+
)
|
|
163
|
+
continue;
|
|
164
|
+
const source = readFileSync(path, "utf8");
|
|
165
|
+
if (
|
|
166
|
+
!source.includes("getMagicContextStorageDir") ||
|
|
167
|
+
(!directCreate.test(source) && !directOpenWrite.test(source))
|
|
168
|
+
)
|
|
169
|
+
continue;
|
|
170
|
+
const relative = path.slice(repoRoot.length + 1);
|
|
171
|
+
// Project .gitignore maintenance is outside the private data directory;
|
|
172
|
+
// it writes only the shared per-project ignore file.
|
|
173
|
+
if (relative === "packages/plugin/src/shared/data-path.ts") continue;
|
|
174
|
+
// This migration command reads the MC store but writes only harness session files.
|
|
175
|
+
if (relative === "packages/cli/src/commands/migrate.ts") continue;
|
|
176
|
+
offenders.push(relative);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
for (const root of scanRoots) visit(join(repoRoot, root));
|
|
180
|
+
for (const relative of [
|
|
181
|
+
"packages/plugin/scripts/cache-bust-sentinel.ts",
|
|
182
|
+
"packages/plugin/scripts/transform-latency-sentinel.ts",
|
|
183
|
+
"packages/plugin/scripts/subagent-failure-sentinel.ts",
|
|
184
|
+
]) {
|
|
185
|
+
const source = readFileSync(join(repoRoot, relative), "utf8");
|
|
186
|
+
if (
|
|
187
|
+
source.includes("getMagicContextStorageDir") &&
|
|
188
|
+
(directCreate.test(source) || directOpenWrite.test(source))
|
|
189
|
+
) {
|
|
190
|
+
offenders.push(relative);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
expect(offenders, `direct filesystem creators in storage-aware modules`).toEqual([]);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("keeps shell backups and staging private from their first creation", () => {
|
|
198
|
+
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../../../");
|
|
199
|
+
for (const script of ["scripts/restart-window.sh", "scripts/place-ck-mc.sh"]) {
|
|
200
|
+
const source = readFileSync(join(repoRoot, script), "utf8");
|
|
201
|
+
expect(source, script).toMatch(/^umask 077$/m);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
});
|
|
@@ -4,6 +4,28 @@
|
|
|
4
4
|
* Storage is shared by OpenCode and Pi, so all writers consult one setting before
|
|
5
5
|
* applying POSIX modes. The default preserves the historical owner-only policy.
|
|
6
6
|
*/
|
|
7
|
+
import { randomBytes } from "node:crypto";
|
|
8
|
+
import type { WriteStream } from "node:fs";
|
|
9
|
+
import {
|
|
10
|
+
chmodSync,
|
|
11
|
+
closeSync,
|
|
12
|
+
createWriteStream,
|
|
13
|
+
lstatSync,
|
|
14
|
+
mkdirSync,
|
|
15
|
+
openSync,
|
|
16
|
+
readdirSync,
|
|
17
|
+
readlinkSync,
|
|
18
|
+
readSync,
|
|
19
|
+
renameSync,
|
|
20
|
+
rmSync,
|
|
21
|
+
symlinkSync,
|
|
22
|
+
writeFileSync,
|
|
23
|
+
writeSync,
|
|
24
|
+
} from "node:fs";
|
|
25
|
+
import type { FileHandle } from "node:fs/promises";
|
|
26
|
+
import { open as openAsync, writeFile as writeFileAsync } from "node:fs/promises";
|
|
27
|
+
import { dirname, join } from "node:path";
|
|
28
|
+
|
|
7
29
|
let enforcePrivateStoragePermissions = true;
|
|
8
30
|
|
|
9
31
|
export function setStoragePrivatePermissionEnforcement(enforce: boolean): void {
|
|
@@ -18,3 +40,173 @@ export function shouldEnforcePrivateStoragePermissions(): boolean {
|
|
|
18
40
|
export function __resetStoragePrivatePermissionEnforcementForTests(): void {
|
|
19
41
|
enforcePrivateStoragePermissions = true;
|
|
20
42
|
}
|
|
43
|
+
|
|
44
|
+
/** Create storage directories with owner-only permissions at their creation. */
|
|
45
|
+
export function ensureStorageDirectorySync(
|
|
46
|
+
directory: string,
|
|
47
|
+
forcePrivate = false,
|
|
48
|
+
recursive = true,
|
|
49
|
+
): void {
|
|
50
|
+
const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
|
|
51
|
+
mkdirSync(directory, {
|
|
52
|
+
recursive,
|
|
53
|
+
...(privateMode ? { mode: 0o700 } : {}),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Create or replace a storage file using a private mode from the first byte. */
|
|
58
|
+
export function writeStorageFileSync(
|
|
59
|
+
filePath: string,
|
|
60
|
+
content: string | Uint8Array,
|
|
61
|
+
options: { encoding?: BufferEncoding; flag?: string; forcePrivate?: boolean } = {},
|
|
62
|
+
): void {
|
|
63
|
+
const { forcePrivate = false, ...writeOptions } = options;
|
|
64
|
+
const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
|
|
65
|
+
writeFileSync(filePath, content, {
|
|
66
|
+
...writeOptions,
|
|
67
|
+
...(privateMode ? { mode: 0o600 } : {}),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Write a private sibling then atomically publish it without a permissive temp window. */
|
|
72
|
+
export function writeStorageFileAtomicSync(
|
|
73
|
+
filePath: string,
|
|
74
|
+
content: string | Uint8Array,
|
|
75
|
+
forcePrivate = false,
|
|
76
|
+
): void {
|
|
77
|
+
ensureStorageDirectorySync(dirname(filePath), forcePrivate);
|
|
78
|
+
const tempPath = `${filePath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
|
|
79
|
+
try {
|
|
80
|
+
writeStorageFileSync(tempPath, content, { flag: "wx", forcePrivate });
|
|
81
|
+
renameSync(tempPath, filePath);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
rmSync(tempPath, { force: true });
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function copyStorageFileSync(
|
|
89
|
+
sourcePath: string,
|
|
90
|
+
destinationPath: string,
|
|
91
|
+
forcePrivate = false,
|
|
92
|
+
): void {
|
|
93
|
+
ensureStorageDirectorySync(dirname(destinationPath), forcePrivate);
|
|
94
|
+
const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
|
|
95
|
+
const sourceFd = openSync(sourcePath, "r");
|
|
96
|
+
let destinationFd: number | undefined;
|
|
97
|
+
try {
|
|
98
|
+
destinationFd = openSync(destinationPath, "wx", privateMode ? 0o600 : 0o666);
|
|
99
|
+
const buffer = Buffer.allocUnsafe(1024 * 1024);
|
|
100
|
+
for (;;) {
|
|
101
|
+
const bytesRead = readSync(sourceFd, buffer, 0, buffer.length, null);
|
|
102
|
+
if (bytesRead === 0) break;
|
|
103
|
+
let offset = 0;
|
|
104
|
+
while (offset < bytesRead) {
|
|
105
|
+
offset += writeSync(destinationFd, buffer, offset, bytesRead - offset);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (destinationFd !== undefined) rmSync(destinationPath, { force: true });
|
|
110
|
+
throw error;
|
|
111
|
+
} finally {
|
|
112
|
+
closeSync(sourceFd);
|
|
113
|
+
if (destinationFd !== undefined) closeSync(destinationFd);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function copyStorageTreeSync(
|
|
118
|
+
sourcePath: string,
|
|
119
|
+
destinationPath: string,
|
|
120
|
+
forcePrivate = false,
|
|
121
|
+
): void {
|
|
122
|
+
const stat = lstatSync(sourcePath);
|
|
123
|
+
if (stat.isSymbolicLink()) {
|
|
124
|
+
ensureStorageDirectorySync(dirname(destinationPath), forcePrivate);
|
|
125
|
+
symlinkSync(readlinkSync(sourcePath), destinationPath);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (!stat.isDirectory()) {
|
|
129
|
+
copyStorageFileSync(sourcePath, destinationPath, forcePrivate);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
ensureStorageDirectorySync(destinationPath, forcePrivate);
|
|
133
|
+
for (const entry of readdirSync(sourcePath)) {
|
|
134
|
+
copyStorageTreeSync(join(sourcePath, entry), join(destinationPath, entry), forcePrivate);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function openStorageFileSync(filePath: string, flags: string, forcePrivate = false): number {
|
|
139
|
+
ensureStorageDirectorySync(dirname(filePath), forcePrivate);
|
|
140
|
+
const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
|
|
141
|
+
return openSync(filePath, flags, privateMode ? 0o600 : 0o666);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export async function writeStorageFileAsync(
|
|
145
|
+
filePath: string,
|
|
146
|
+
content: string | Uint8Array,
|
|
147
|
+
forcePrivate = false,
|
|
148
|
+
): Promise<void> {
|
|
149
|
+
const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
|
|
150
|
+
ensureStorageDirectorySync(dirname(filePath), privateMode);
|
|
151
|
+
await writeFileAsync(filePath, content, privateMode ? { mode: 0o600 } : undefined);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export async function writeStorageFileHandleAsync(
|
|
155
|
+
handle: FileHandle,
|
|
156
|
+
content: string,
|
|
157
|
+
): Promise<void> {
|
|
158
|
+
await handle.writeFile(content);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function createStorageWriteStream(filePath: string, forcePrivate = false): WriteStream {
|
|
162
|
+
const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
|
|
163
|
+
return createWriteStream(filePath, privateMode ? { mode: 0o600 } : undefined);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export async function createStorageFileHandleAsync(
|
|
167
|
+
filePath: string,
|
|
168
|
+
flags: string,
|
|
169
|
+
forcePrivate = false,
|
|
170
|
+
) {
|
|
171
|
+
const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
|
|
172
|
+
return openAsync(filePath, flags, privateMode ? 0o600 : undefined);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Tighten existing entries during storage startup; symlinks are never followed. */
|
|
176
|
+
export function tightenStorageTreeSync(root: string): { tightened: number; failures: number } {
|
|
177
|
+
if (!shouldEnforcePrivateStoragePermissions() || process.platform === "win32") {
|
|
178
|
+
return { tightened: 0, failures: 0 };
|
|
179
|
+
}
|
|
180
|
+
let tightened = 0;
|
|
181
|
+
let failures = 0;
|
|
182
|
+
const visit = (entryPath: string): void => {
|
|
183
|
+
let stat: ReturnType<typeof lstatSync>;
|
|
184
|
+
try {
|
|
185
|
+
stat = lstatSync(entryPath);
|
|
186
|
+
} catch {
|
|
187
|
+
failures++;
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (stat.isSymbolicLink()) return;
|
|
191
|
+
const mode = stat.isDirectory() ? 0o700 : 0o600;
|
|
192
|
+
if ((stat.mode & 0o077) !== 0 || (stat.mode & 0o777) !== mode) {
|
|
193
|
+
try {
|
|
194
|
+
chmodSync(entryPath, mode);
|
|
195
|
+
tightened++;
|
|
196
|
+
} catch {
|
|
197
|
+
failures++;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (!stat.isDirectory()) return;
|
|
201
|
+
let entries: string[];
|
|
202
|
+
try {
|
|
203
|
+
entries = readdirSync(entryPath);
|
|
204
|
+
} catch {
|
|
205
|
+
failures++;
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
for (const entry of entries) visit(join(entryPath, entry));
|
|
209
|
+
};
|
|
210
|
+
visit(root);
|
|
211
|
+
return { tightened, failures };
|
|
212
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import fixture from "../../../../testdata/temporal-upgrade-projections.json";
|
|
2
|
+
import type { Database } from "./sqlite";
|
|
3
|
+
|
|
4
|
+
export type TemporalFixtureRuntime = "Pi" | "OpenCode 1" | "OpenCode 2";
|
|
5
|
+
type Value = null | string | number | { base64: string };
|
|
6
|
+
interface CapturedSession {
|
|
7
|
+
sessionId: string;
|
|
8
|
+
cwd?: string;
|
|
9
|
+
input: unknown[];
|
|
10
|
+
entryIds?: string[];
|
|
11
|
+
projection: unknown[];
|
|
12
|
+
projectionJson: string;
|
|
13
|
+
state: Record<string, Array<Record<string, Value>>>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const temporalUpgradeCases: Record<TemporalFixtureRuntime, CapturedSession> = fixture.cases;
|
|
17
|
+
|
|
18
|
+
/** Restore old served state, never by first rendering it with the current code. */
|
|
19
|
+
export function seedTemporalUpgradeFixture(
|
|
20
|
+
db: Database,
|
|
21
|
+
runtime: TemporalFixtureRuntime,
|
|
22
|
+
): CapturedSession {
|
|
23
|
+
const captured = temporalUpgradeCases[runtime];
|
|
24
|
+
db.transaction(() => {
|
|
25
|
+
for (const [table, rows] of Object.entries(captured.state)) {
|
|
26
|
+
for (const row of rows) {
|
|
27
|
+
const columns = Object.keys(row);
|
|
28
|
+
const values = Object.values(row).map((value) =>
|
|
29
|
+
value !== null && typeof value === "object"
|
|
30
|
+
? Buffer.from(value.base64, "base64")
|
|
31
|
+
: value,
|
|
32
|
+
);
|
|
33
|
+
db.prepare(
|
|
34
|
+
`INSERT INTO ${table} (${columns.join(",")}) VALUES (${columns.map(() => "?").join(",")})`,
|
|
35
|
+
).run(...values);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Advance only the cache clock: timestamp-derived marker bytes and
|
|
39
|
+
// the old input/projection are the immutable captured fixture.
|
|
40
|
+
db.prepare("UPDATE session_meta SET last_response_time=? WHERE session_id=?").run(
|
|
41
|
+
Date.now(),
|
|
42
|
+
captured.sessionId,
|
|
43
|
+
);
|
|
44
|
+
db.prepare("UPDATE lkg_slots SET captured_at=? WHERE session_id=?").run(
|
|
45
|
+
Date.now(),
|
|
46
|
+
captured.sessionId,
|
|
47
|
+
);
|
|
48
|
+
}).immediate();
|
|
49
|
+
return captured;
|
|
50
|
+
}
|
|
@@ -245,6 +245,12 @@ export const USER_FACING_FAILURES = {
|
|
|
245
245
|
sentence: "Magic Context has no context.db.",
|
|
246
246
|
action: "Run `npx @cortexkit/magic-context doctor store init`, then restart ck-mc.",
|
|
247
247
|
},
|
|
248
|
+
checkout_claim_held_elsewhere: {
|
|
249
|
+
code: "MC-C16",
|
|
250
|
+
sentence:
|
|
251
|
+
"This request was not sent: this agent is checked out on another machine, so Magic Context will not work on its sessions here.",
|
|
252
|
+
action: "Move the agent back to this machine, then send your message again.",
|
|
253
|
+
},
|
|
248
254
|
single_store_migration_required: {
|
|
249
255
|
code: "MC-C14",
|
|
250
256
|
sentence: "Magic Context's Rust mode needs a one-time migration of its store.",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { expect, spyOn, test } from "bun:test";
|
|
2
|
+
import * as logger from "./logger";
|
|
3
|
+
import { logSlowWriteTransaction } from "./write-transaction-timing";
|
|
4
|
+
|
|
5
|
+
test("slow-write diagnostics distinguish preparation from held rendering and writes", () => {
|
|
6
|
+
const log = spyOn(logger, "log").mockImplementation(() => {});
|
|
7
|
+
try {
|
|
8
|
+
logSlowWriteTransaction("fold", 100, 1000, 1400, {
|
|
9
|
+
pre_metadata: 1,
|
|
10
|
+
pre_onFoldPrepare: 200,
|
|
11
|
+
staleCheck: 5,
|
|
12
|
+
m1Render: 100,
|
|
13
|
+
persistCachedM0: 600,
|
|
14
|
+
sessionMeta: 5,
|
|
15
|
+
onFoldCommit: 10,
|
|
16
|
+
commit: 580,
|
|
17
|
+
});
|
|
18
|
+
expect(log.mock.calls).toEqual([
|
|
19
|
+
[
|
|
20
|
+
"[magic-context] slow write transaction: site=fold held=1300.0ms pre_metadata=1.0ms pre_onFoldPrepare=200.0ms staleCheck=5.0ms m1Render=100.0ms persistCachedM0=600.0ms sessionMeta=5.0ms onFoldCommit=10.0ms commit=580.0ms",
|
|
21
|
+
],
|
|
22
|
+
]);
|
|
23
|
+
logSlowWriteTransaction("fast", 100, 1000, 101);
|
|
24
|
+
expect(log).toHaveBeenCalledTimes(1);
|
|
25
|
+
} finally {
|
|
26
|
+
log.mockRestore();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("step diagnostics cannot make a committed write appear to fail", () => {
|
|
31
|
+
const log = spyOn(logger, "log").mockImplementation(() => {
|
|
32
|
+
throw new Error("logging failed");
|
|
33
|
+
});
|
|
34
|
+
try {
|
|
35
|
+
expect(() => logSlowWriteTransaction("fold", 0, 1000, 2000, { commit: 10 })).not.toThrow();
|
|
36
|
+
} finally {
|
|
37
|
+
log.mockRestore();
|
|
38
|
+
}
|
|
39
|
+
});
|
|
@@ -15,12 +15,36 @@ export function logSlowWriteTransaction(
|
|
|
15
15
|
startedAt: number,
|
|
16
16
|
thresholdMs = SLOW_WRITE_TRANSACTION_THRESHOLD_MS,
|
|
17
17
|
completedAtMs = performance.now(),
|
|
18
|
+
steps?: Readonly<Record<string, number>>,
|
|
18
19
|
): void {
|
|
19
20
|
try {
|
|
20
21
|
const durationMs = completedAtMs - startedAt;
|
|
21
22
|
if (durationMs < thresholdMs) return;
|
|
22
|
-
|
|
23
|
+
const detail = steps
|
|
24
|
+
? Object.entries(steps)
|
|
25
|
+
.map(([name, ms]) => `${name}=${ms.toFixed(1)}ms`)
|
|
26
|
+
.join(" ")
|
|
27
|
+
: "";
|
|
28
|
+
log(
|
|
29
|
+
`[magic-context] slow write transaction: site=${site} held=${durationMs.toFixed(1)}ms${detail ? ` ${detail}` : ""}`,
|
|
30
|
+
);
|
|
23
31
|
} catch {
|
|
24
32
|
// Timing diagnostics must never make a committed write appear to fail.
|
|
25
33
|
}
|
|
26
34
|
}
|
|
35
|
+
|
|
36
|
+
/** Step durations include precomputation when named `pre_*`; held time never does. */
|
|
37
|
+
export class WriteTransactionSteps {
|
|
38
|
+
readonly durations: Record<string, number> = {};
|
|
39
|
+
private last = performance.now();
|
|
40
|
+
|
|
41
|
+
mark(name: string): void {
|
|
42
|
+
const now = performance.now();
|
|
43
|
+
this.durations[name] = now - this.last;
|
|
44
|
+
this.last = now;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
reset(): void {
|
|
48
|
+
this.last = performance.now();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -163,7 +163,7 @@ const LAYOUT_CASES: LayoutCase[] = [
|
|
|
163
163
|
status: LONG_VALUE_STATUS,
|
|
164
164
|
terminalWidth: 80,
|
|
165
165
|
dialogWidth: 60,
|
|
166
|
-
expected: ["Configured", "
|
|
166
|
+
expected: ["Configured", "your config)", "Execute threshold", "Esc to close"],
|
|
167
167
|
rows: COMPLETE_ROWS,
|
|
168
168
|
},
|
|
169
169
|
];
|