@wolfx/opencode-magic-context 0.21.8-patch.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/dist/agents/dreamer.d.ts +2 -0
- package/dist/agents/dreamer.d.ts.map +1 -0
- package/dist/agents/historian.d.ts +3 -0
- package/dist/agents/historian.d.ts.map +1 -0
- package/dist/agents/magic-context-prompt.d.ts +3 -0
- package/dist/agents/magic-context-prompt.d.ts.map +1 -0
- package/dist/agents/permissions.d.ts +142 -0
- package/dist/agents/permissions.d.ts.map +1 -0
- package/dist/agents/sidekick.d.ts +2 -0
- package/dist/agents/sidekick.d.ts.map +1 -0
- package/dist/config/agent-disable.d.ts +26 -0
- package/dist/config/agent-disable.d.ts.map +1 -0
- package/dist/config/index.d.ts +33 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/schema/agent-overrides.d.ts +55 -0
- package/dist/config/schema/agent-overrides.d.ts.map +1 -0
- package/dist/config/schema/magic-context.d.ts +841 -0
- package/dist/config/schema/magic-context.d.ts.map +1 -0
- package/dist/config/schema.d.ts +3 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/variable.d.ts +48 -0
- package/dist/config/variable.d.ts.map +1 -0
- package/dist/features/builtin-commands/commands.d.ts +3 -0
- package/dist/features/builtin-commands/commands.d.ts.map +1 -0
- package/dist/features/builtin-commands/types.d.ts +5 -0
- package/dist/features/builtin-commands/types.d.ts.map +1 -0
- package/dist/features/magic-context/compaction-marker.d.ts +91 -0
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -0
- package/dist/features/magic-context/compaction.d.ts +7 -0
- package/dist/features/magic-context/compaction.d.ts.map +1 -0
- package/dist/features/magic-context/compartment-lease.d.ts +14 -0
- package/dist/features/magic-context/compartment-lease.d.ts.map +1 -0
- package/dist/features/magic-context/compartment-storage.d.ts +130 -0
- package/dist/features/magic-context/compartment-storage.d.ts.map +1 -0
- package/dist/features/magic-context/compression-depth-storage.d.ts +14 -0
- package/dist/features/magic-context/compression-depth-storage.d.ts.map +1 -0
- package/dist/features/magic-context/defaults.d.ts +2 -0
- package/dist/features/magic-context/defaults.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/index.d.ts +8 -0
- package/dist/features/magic-context/dreamer/index.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/lease.d.ts +8 -0
- package/dist/features/magic-context/dreamer/lease.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/queue.d.ts +44 -0
- package/dist/features/magic-context/dreamer/queue.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/runner.d.ts +81 -0
- package/dist/features/magic-context/dreamer/runner.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/scheduler.d.ts +33 -0
- package/dist/features/magic-context/dreamer/scheduler.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +41 -0
- package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/storage-dream-state.d.ts +5 -0
- package/dist/features/magic-context/dreamer/storage-dream-state.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/task-prompts.d.ts +26 -0
- package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -0
- package/dist/features/magic-context/git-commits/git-log-reader.d.ts +57 -0
- package/dist/features/magic-context/git-commits/git-log-reader.d.ts.map +1 -0
- package/dist/features/magic-context/git-commits/index.d.ts +7 -0
- package/dist/features/magic-context/git-commits/index.d.ts.map +1 -0
- package/dist/features/magic-context/git-commits/indexer.d.ts +43 -0
- package/dist/features/magic-context/git-commits/indexer.d.ts.map +1 -0
- package/dist/features/magic-context/git-commits/search-git-commits.d.ts +32 -0
- package/dist/features/magic-context/git-commits/search-git-commits.d.ts.map +1 -0
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts +19 -0
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -0
- package/dist/features/magic-context/git-commits/storage-git-commits.d.ts +47 -0
- package/dist/features/magic-context/git-commits/storage-git-commits.d.ts.map +1 -0
- package/dist/features/magic-context/index.d.ts +12 -0
- package/dist/features/magic-context/index.d.ts.map +1 -0
- package/dist/features/magic-context/key-files/aft-availability.d.ts +11 -0
- package/dist/features/magic-context/key-files/aft-availability.d.ts.map +1 -0
- package/dist/features/magic-context/key-files/identify-key-files.d.ts +84 -0
- package/dist/features/magic-context/key-files/identify-key-files.d.ts.map +1 -0
- package/dist/features/magic-context/key-files/project-key-files.d.ts +42 -0
- package/dist/features/magic-context/key-files/project-key-files.d.ts.map +1 -0
- package/dist/features/magic-context/key-files/read-history.d.ts +26 -0
- package/dist/features/magic-context/key-files/read-history.d.ts.map +1 -0
- package/dist/features/magic-context/key-files/read-stats.d.ts +20 -0
- package/dist/features/magic-context/key-files/read-stats.d.ts.map +1 -0
- package/dist/features/magic-context/key-files/storage-key-files.d.ts +25 -0
- package/dist/features/magic-context/key-files/storage-key-files.d.ts.map +1 -0
- package/dist/features/magic-context/memory/constants.d.ts +5 -0
- package/dist/features/magic-context/memory/constants.d.ts.map +1 -0
- package/dist/features/magic-context/memory/cosine-similarity.d.ts +2 -0
- package/dist/features/magic-context/memory/cosine-similarity.d.ts.map +1 -0
- package/dist/features/magic-context/memory/embedding-backfill.d.ts +9 -0
- package/dist/features/magic-context/memory/embedding-backfill.d.ts.map +1 -0
- package/dist/features/magic-context/memory/embedding-cache.d.ts +8 -0
- package/dist/features/magic-context/memory/embedding-cache.d.ts.map +1 -0
- package/dist/features/magic-context/memory/embedding-identity.d.ts +11 -0
- package/dist/features/magic-context/memory/embedding-identity.d.ts.map +1 -0
- package/dist/features/magic-context/memory/embedding-local.d.ts +20 -0
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -0
- package/dist/features/magic-context/memory/embedding-openai.d.ts +44 -0
- package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -0
- package/dist/features/magic-context/memory/embedding-probe.d.ts +69 -0
- package/dist/features/magic-context/memory/embedding-probe.d.ts.map +1 -0
- package/dist/features/magic-context/memory/embedding-provider.d.ts +15 -0
- package/dist/features/magic-context/memory/embedding-provider.d.ts.map +1 -0
- package/dist/features/magic-context/memory/embedding.d.ts +39 -0
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -0
- package/dist/features/magic-context/memory/index.d.ts +12 -0
- package/dist/features/magic-context/memory/index.d.ts.map +1 -0
- package/dist/features/magic-context/memory/normalize-hash.d.ts +3 -0
- package/dist/features/magic-context/memory/normalize-hash.d.ts.map +1 -0
- package/dist/features/magic-context/memory/project-identity.d.ts +23 -0
- package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -0
- package/dist/features/magic-context/memory/promotion.d.ts +13 -0
- package/dist/features/magic-context/memory/promotion.d.ts.map +1 -0
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +8 -0
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -0
- package/dist/features/magic-context/memory/storage-memory-fts.d.ts +12 -0
- package/dist/features/magic-context/memory/storage-memory-fts.d.ts.map +1 -0
- package/dist/features/magic-context/memory/storage-memory.d.ts +31 -0
- package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -0
- package/dist/features/magic-context/memory/types.d.ts +37 -0
- package/dist/features/magic-context/memory/types.d.ts.map +1 -0
- package/dist/features/magic-context/message-index-async.d.ts +12 -0
- package/dist/features/magic-context/message-index-async.d.ts.map +1 -0
- package/dist/features/magic-context/message-index.d.ts +10 -0
- package/dist/features/magic-context/message-index.d.ts.map +1 -0
- package/dist/features/magic-context/migrations.d.ts +33 -0
- package/dist/features/magic-context/migrations.d.ts.map +1 -0
- package/dist/features/magic-context/mock-database.d.ts +3 -0
- package/dist/features/magic-context/mock-database.d.ts.map +1 -0
- package/dist/features/magic-context/overflow-detection.d.ts +51 -0
- package/dist/features/magic-context/overflow-detection.d.ts.map +1 -0
- package/dist/features/magic-context/plugin-messages.d.ts +75 -0
- package/dist/features/magic-context/plugin-messages.d.ts.map +1 -0
- package/dist/features/magic-context/project-embedding-registry.d.ts +44 -0
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -0
- package/dist/features/magic-context/range-parser.d.ts +13 -0
- package/dist/features/magic-context/range-parser.d.ts.map +1 -0
- package/dist/features/magic-context/resolve-subagent-fallback.d.ts +40 -0
- package/dist/features/magic-context/resolve-subagent-fallback.d.ts.map +1 -0
- package/dist/features/magic-context/scheduler.d.ts +18 -0
- package/dist/features/magic-context/scheduler.d.ts.map +1 -0
- package/dist/features/magic-context/search.d.ts +69 -0
- package/dist/features/magic-context/search.d.ts.map +1 -0
- package/dist/features/magic-context/sidekick/agent.d.ts +13 -0
- package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -0
- package/dist/features/magic-context/sidekick/core.d.ts +38 -0
- package/dist/features/magic-context/sidekick/core.d.ts.map +1 -0
- package/dist/features/magic-context/sidekick/index.d.ts +3 -0
- package/dist/features/magic-context/sidekick/index.d.ts.map +1 -0
- package/dist/features/magic-context/storage-db.d.ts +48 -0
- package/dist/features/magic-context/storage-db.d.ts.map +1 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts +246 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -0
- package/dist/features/magic-context/storage-meta-session.d.ts +6 -0
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -0
- package/dist/features/magic-context/storage-meta-shared.d.ts +31 -0
- package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -0
- package/dist/features/magic-context/storage-meta.d.ts +3 -0
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -0
- package/dist/features/magic-context/storage-notes.d.ts +62 -0
- package/dist/features/magic-context/storage-notes.d.ts.map +1 -0
- package/dist/features/magic-context/storage-ops.d.ts +7 -0
- package/dist/features/magic-context/storage-ops.d.ts.map +1 -0
- package/dist/features/magic-context/storage-source.d.ts +5 -0
- package/dist/features/magic-context/storage-source.d.ts.map +1 -0
- package/dist/features/magic-context/storage-subagent-invocations.d.ts +52 -0
- package/dist/features/magic-context/storage-subagent-invocations.d.ts.map +1 -0
- package/dist/features/magic-context/storage-tags.d.ts +206 -0
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -0
- package/dist/features/magic-context/storage.d.ts +11 -0
- package/dist/features/magic-context/storage.d.ts.map +1 -0
- package/dist/features/magic-context/subagent-token-capture.d.ts +33 -0
- package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -0
- package/dist/features/magic-context/tagger.d.ts +64 -0
- package/dist/features/magic-context/tagger.d.ts.map +1 -0
- package/dist/features/magic-context/tool-definition-tokens.d.ts +79 -0
- package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -0
- package/dist/features/magic-context/tool-owner-backfill.d.ts +90 -0
- package/dist/features/magic-context/tool-owner-backfill.d.ts.map +1 -0
- package/dist/features/magic-context/types.d.ts +72 -0
- package/dist/features/magic-context/types.d.ts.map +1 -0
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts +22 -0
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -0
- package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +33 -0
- package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -0
- package/dist/features/magic-context/work-metrics.d.ts +13 -0
- package/dist/features/magic-context/work-metrics.d.ts.map +1 -0
- package/dist/hooks/auto-update-checker/cache.d.ts +23 -0
- package/dist/hooks/auto-update-checker/cache.d.ts.map +1 -0
- package/dist/hooks/auto-update-checker/checker.d.ts +13 -0
- package/dist/hooks/auto-update-checker/checker.d.ts.map +1 -0
- package/dist/hooks/auto-update-checker/constants.d.ts +10 -0
- package/dist/hooks/auto-update-checker/constants.d.ts.map +1 -0
- package/dist/hooks/auto-update-checker/index.d.ts +40 -0
- package/dist/hooks/auto-update-checker/index.d.ts.map +1 -0
- package/dist/hooks/auto-update-checker/types.d.ts +50 -0
- package/dist/hooks/auto-update-checker/types.d.ts.map +1 -0
- package/dist/hooks/is-anthropic-provider.d.ts +2 -0
- package/dist/hooks/is-anthropic-provider.d.ts.map +1 -0
- package/dist/hooks/magic-context/apply-context-nudge.d.ts +5 -0
- package/dist/hooks/magic-context/apply-context-nudge.d.ts.map +1 -0
- package/dist/hooks/magic-context/apply-operations.d.ts +7 -0
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-hint.d.ts +34 -0
- package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-runner.d.ts +53 -0
- package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -0
- package/dist/hooks/magic-context/boundary-execution.d.ts +24 -0
- package/dist/hooks/magic-context/boundary-execution.d.ts.map +1 -0
- package/dist/hooks/magic-context/cache-busting-signals.d.ts +10 -0
- package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -0
- package/dist/hooks/magic-context/caveman-cleanup.d.ts +86 -0
- package/dist/hooks/magic-context/caveman-cleanup.d.ts.map +1 -0
- package/dist/hooks/magic-context/caveman.d.ts +35 -0
- package/dist/hooks/magic-context/caveman.d.ts.map +1 -0
- package/dist/hooks/magic-context/command-handler.d.ts +89 -0
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -0
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts +106 -0
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-parser.d.ts +18 -0
- package/dist/hooks/magic-context/compartment-parser.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-prompt.d.ts +19 -0
- package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-runner-compressor.d.ts +87 -0
- package/dist/hooks/magic-context/compartment-runner-compressor.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts +26 -0
- package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts +42 -0
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +6 -0
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-runner-mapping.d.ts +33 -0
- package/dist/hooks/magic-context/compartment-runner-mapping.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts +29 -0
- package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts +3 -0
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-runner-state-xml.d.ts +21 -0
- package/dist/hooks/magic-context/compartment-runner-state-xml.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +102 -0
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-runner-validation.d.ts +28 -0
- package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-runner.d.ts +54 -0
- package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-trigger.d.ts +17 -0
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -0
- package/dist/hooks/magic-context/derive-budgets.d.ts +57 -0
- package/dist/hooks/magic-context/derive-budgets.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 -0
- package/dist/hooks/magic-context/event-handler.d.ts +49 -0
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -0
- package/dist/hooks/magic-context/event-payloads.d.ts +62 -0
- package/dist/hooks/magic-context/event-payloads.d.ts.map +1 -0
- package/dist/hooks/magic-context/event-resolvers.d.ts +72 -0
- package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -0
- package/dist/hooks/magic-context/execute-flush.d.ts +3 -0
- package/dist/hooks/magic-context/execute-flush.d.ts.map +1 -0
- package/dist/hooks/magic-context/execute-status.d.ts +12 -0
- package/dist/hooks/magic-context/execute-status.d.ts.map +1 -0
- package/dist/hooks/magic-context/format-bytes.d.ts +2 -0
- package/dist/hooks/magic-context/format-bytes.d.ts.map +1 -0
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts +22 -0
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -0
- package/dist/hooks/magic-context/historian-state-file.d.ts +43 -0
- package/dist/hooks/magic-context/historian-state-file.d.ts.map +1 -0
- package/dist/hooks/magic-context/hook-handlers.d.ts +165 -0
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -0
- package/dist/hooks/magic-context/hook.d.ts +118 -0
- package/dist/hooks/magic-context/hook.d.ts.map +1 -0
- package/dist/hooks/magic-context/image-token-estimate.d.ts +6 -0
- package/dist/hooks/magic-context/image-token-estimate.d.ts.map +1 -0
- package/dist/hooks/magic-context/index.d.ts +3 -0
- package/dist/hooks/magic-context/index.d.ts.map +1 -0
- package/dist/hooks/magic-context/inject-compartments.d.ts +52 -0
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -0
- package/dist/hooks/magic-context/key-files-block.d.ts +27 -0
- package/dist/hooks/magic-context/key-files-block.d.ts.map +1 -0
- package/dist/hooks/magic-context/live-session-state.d.ts +42 -0
- package/dist/hooks/magic-context/live-session-state.d.ts.map +1 -0
- package/dist/hooks/magic-context/note-nudger.d.ts +71 -0
- package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -0
- package/dist/hooks/magic-context/note-visibility.d.ts +43 -0
- package/dist/hooks/magic-context/note-visibility.d.ts.map +1 -0
- package/dist/hooks/magic-context/nudge-bands.d.ts +6 -0
- package/dist/hooks/magic-context/nudge-bands.d.ts.map +1 -0
- package/dist/hooks/magic-context/nudge-injection.d.ts +7 -0
- package/dist/hooks/magic-context/nudge-injection.d.ts.map +1 -0
- package/dist/hooks/magic-context/nudge-placement-store.d.ts +15 -0
- package/dist/hooks/magic-context/nudge-placement-store.d.ts.map +1 -0
- package/dist/hooks/magic-context/nudger.d.ts +21 -0
- package/dist/hooks/magic-context/nudger.d.ts.map +1 -0
- package/dist/hooks/magic-context/read-session-chunk.d.ts +99 -0
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -0
- package/dist/hooks/magic-context/read-session-db.d.ts +21 -0
- package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -0
- package/dist/hooks/magic-context/read-session-formatting.d.ts +35 -0
- package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -0
- package/dist/hooks/magic-context/read-session-raw.d.ts +10 -0
- package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -0
- package/dist/hooks/magic-context/send-session-notification.d.ts +13 -0
- package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -0
- package/dist/hooks/magic-context/sentinel.d.ts +102 -0
- package/dist/hooks/magic-context/sentinel.d.ts.map +1 -0
- package/dist/hooks/magic-context/strip-content.d.ts +140 -0
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -0
- package/dist/hooks/magic-context/strip-structural-noise.d.ts +17 -0
- package/dist/hooks/magic-context/strip-structural-noise.d.ts.map +1 -0
- package/dist/hooks/magic-context/system-injection-stripper.d.ts +2 -0
- package/dist/hooks/magic-context/system-injection-stripper.d.ts.map +1 -0
- package/dist/hooks/magic-context/system-prompt-hash.d.ts +85 -0
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -0
- package/dist/hooks/magic-context/tag-content-primitives.d.ts +6 -0
- package/dist/hooks/magic-context/tag-content-primitives.d.ts.map +1 -0
- package/dist/hooks/magic-context/tag-id-fallback.d.ts +9 -0
- package/dist/hooks/magic-context/tag-id-fallback.d.ts.map +1 -0
- package/dist/hooks/magic-context/tag-messages.d.ts +48 -0
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -0
- package/dist/hooks/magic-context/tag-part-guards.d.ts +23 -0
- package/dist/hooks/magic-context/tag-part-guards.d.ts.map +1 -0
- package/dist/hooks/magic-context/temporal-awareness.d.ts +73 -0
- package/dist/hooks/magic-context/temporal-awareness.d.ts.map +1 -0
- package/dist/hooks/magic-context/text-complete.d.ts +8 -0
- package/dist/hooks/magic-context/text-complete.d.ts.map +1 -0
- package/dist/hooks/magic-context/todo-view.d.ts +102 -0
- package/dist/hooks/magic-context/todo-view.d.ts.map +1 -0
- package/dist/hooks/magic-context/tokenizer-calibration.d.ts +85 -0
- package/dist/hooks/magic-context/tokenizer-calibration.d.ts.map +1 -0
- package/dist/hooks/magic-context/tool-drop-target.d.ts +48 -0
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +66 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform-context-state.d.ts +12 -0
- package/dist/hooks/magic-context/transform-context-state.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform-message-helpers.d.ts +29 -0
- package/dist/hooks/magic-context/transform-message-helpers.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform-operations.d.ts +5 -0
- package/dist/hooks/magic-context/transform-operations.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +100 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform-stage-logger.d.ts +2 -0
- package/dist/hooks/magic-context/transform-stage-logger.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform.d.ts +145 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +179800 -0
- package/dist/plugin/conflict-warning-hook.d.ts +34 -0
- package/dist/plugin/conflict-warning-hook.d.ts.map +1 -0
- package/dist/plugin/dream-timer.d.ts +44 -0
- package/dist/plugin/dream-timer.d.ts.map +1 -0
- package/dist/plugin/embedding-bootstrap-helpers.d.ts +35 -0
- package/dist/plugin/embedding-bootstrap-helpers.d.ts.map +1 -0
- package/dist/plugin/embedding-bootstrap.d.ts +3 -0
- package/dist/plugin/embedding-bootstrap.d.ts.map +1 -0
- package/dist/plugin/event.d.ts +13 -0
- package/dist/plugin/event.d.ts.map +1 -0
- package/dist/plugin/hooks/create-session-hooks.d.ts +44 -0
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -0
- package/dist/plugin/messages-transform.d.ts +46 -0
- package/dist/plugin/messages-transform.d.ts.map +1 -0
- package/dist/plugin/normalize-tool-arg-schemas.d.ts +7 -0
- package/dist/plugin/normalize-tool-arg-schemas.d.ts.map +1 -0
- package/dist/plugin/rpc-handlers.d.ts +21 -0
- package/dist/plugin/rpc-handlers.d.ts.map +1 -0
- package/dist/plugin/sidebar-snapshot-cache.d.ts +19 -0
- package/dist/plugin/sidebar-snapshot-cache.d.ts.map +1 -0
- package/dist/plugin/tool-registry.d.ts +8 -0
- package/dist/plugin/tool-registry.d.ts.map +1 -0
- package/dist/plugin/types.d.ts +3 -0
- package/dist/plugin/types.d.ts.map +1 -0
- package/dist/shared/announcement.d.ts +55 -0
- package/dist/shared/announcement.d.ts.map +1 -0
- package/dist/shared/assistant-message-extractor.d.ts +2 -0
- package/dist/shared/assistant-message-extractor.d.ts.map +1 -0
- package/dist/shared/bounded-session-map.d.ts +45 -0
- package/dist/shared/bounded-session-map.d.ts.map +1 -0
- package/dist/shared/conflict-detector.d.ts +74 -0
- package/dist/shared/conflict-detector.d.ts.map +1 -0
- package/dist/shared/conflict-fixer.d.ts +3 -0
- package/dist/shared/conflict-fixer.d.ts.map +1 -0
- package/dist/shared/data-path.d.ts +121 -0
- package/dist/shared/data-path.d.ts.map +1 -0
- package/dist/shared/error-message.d.ts +32 -0
- package/dist/shared/error-message.d.ts.map +1 -0
- package/dist/shared/format-bytes.d.ts +2 -0
- package/dist/shared/format-bytes.d.ts.map +1 -0
- package/dist/shared/format-threshold.d.ts +24 -0
- package/dist/shared/format-threshold.d.ts.map +1 -0
- package/dist/shared/harness.d.ts +43 -0
- package/dist/shared/harness.d.ts.map +1 -0
- package/dist/shared/index.d.ts +6 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/internal-initiator-marker.d.ts +2 -0
- package/dist/shared/internal-initiator-marker.d.ts.map +1 -0
- package/dist/shared/jsonc-parser.d.ts +8 -0
- package/dist/shared/jsonc-parser.d.ts.map +1 -0
- package/dist/shared/logger.d.ts +10 -0
- package/dist/shared/logger.d.ts.map +1 -0
- package/dist/shared/model-requirements.d.ts +26 -0
- package/dist/shared/model-requirements.d.ts.map +1 -0
- package/dist/shared/model-suggestion-retry.d.ts +68 -0
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -0
- package/dist/shared/models-dev-cache.d.ts +65 -0
- package/dist/shared/models-dev-cache.d.ts.map +1 -0
- package/dist/shared/native-binding.d.ts +87 -0
- package/dist/shared/native-binding.d.ts.map +1 -0
- package/dist/shared/normalize-sdk-response.d.ts +5 -0
- package/dist/shared/normalize-sdk-response.d.ts.map +1 -0
- package/dist/shared/opencode-compaction-detector.d.ts +2 -0
- package/dist/shared/opencode-compaction-detector.d.ts.map +1 -0
- package/dist/shared/opencode-config-dir-types.d.ts +14 -0
- package/dist/shared/opencode-config-dir-types.d.ts.map +1 -0
- package/dist/shared/opencode-config-dir.d.ts +5 -0
- package/dist/shared/opencode-config-dir.d.ts.map +1 -0
- package/dist/shared/record-type-guard.d.ts +2 -0
- package/dist/shared/record-type-guard.d.ts.map +1 -0
- package/dist/shared/resolve-fallbacks.d.ts +32 -0
- package/dist/shared/resolve-fallbacks.d.ts.map +1 -0
- package/dist/shared/rpc-client.d.ts +17 -0
- package/dist/shared/rpc-client.d.ts.map +1 -0
- package/dist/shared/rpc-notifications.d.ts +24 -0
- package/dist/shared/rpc-notifications.d.ts.map +1 -0
- package/dist/shared/rpc-server.d.ts +20 -0
- package/dist/shared/rpc-server.d.ts.map +1 -0
- package/dist/shared/rpc-types.d.ts +105 -0
- package/dist/shared/rpc-types.d.ts.map +1 -0
- package/dist/shared/rpc-utils.d.ts +19 -0
- package/dist/shared/rpc-utils.d.ts.map +1 -0
- package/dist/shared/sqlite-helpers.d.ts +16 -0
- package/dist/shared/sqlite-helpers.d.ts.map +1 -0
- package/dist/shared/sqlite.d.ts +43 -0
- package/dist/shared/sqlite.d.ts.map +1 -0
- package/dist/shared/stable-json.d.ts +21 -0
- package/dist/shared/stable-json.d.ts.map +1 -0
- package/dist/shared/subagent-runner.d.ts +208 -0
- package/dist/shared/subagent-runner.d.ts.map +1 -0
- package/dist/shared/system-directive.d.ts +3 -0
- package/dist/shared/system-directive.d.ts.map +1 -0
- package/dist/shared/tag-transcript.d.ts +66 -0
- package/dist/shared/tag-transcript.d.ts.map +1 -0
- package/dist/shared/transcript-opencode.d.ts +71 -0
- package/dist/shared/transcript-opencode.d.ts.map +1 -0
- package/dist/shared/transcript.d.ts +212 -0
- package/dist/shared/transcript.d.ts.map +1 -0
- package/dist/shared/tui-config.d.ts +10 -0
- package/dist/shared/tui-config.d.ts.map +1 -0
- package/dist/tools/ctx-expand/constants.d.ts +3 -0
- package/dist/tools/ctx-expand/constants.d.ts.map +1 -0
- package/dist/tools/ctx-expand/index.d.ts +2 -0
- package/dist/tools/ctx-expand/index.d.ts.map +1 -0
- package/dist/tools/ctx-expand/tools.d.ts +3 -0
- package/dist/tools/ctx-expand/tools.d.ts.map +1 -0
- package/dist/tools/ctx-expand/types.d.ts +5 -0
- package/dist/tools/ctx-expand/types.d.ts.map +1 -0
- package/dist/tools/ctx-memory/constants.d.ts +4 -0
- package/dist/tools/ctx-memory/constants.d.ts.map +1 -0
- package/dist/tools/ctx-memory/index.d.ts +4 -0
- package/dist/tools/ctx-memory/index.d.ts.map +1 -0
- package/dist/tools/ctx-memory/tools.d.ts +4 -0
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -0
- package/dist/tools/ctx-memory/types.d.ts +35 -0
- package/dist/tools/ctx-memory/types.d.ts.map +1 -0
- package/dist/tools/ctx-note/constants.d.ts +2 -0
- package/dist/tools/ctx-note/constants.d.ts.map +1 -0
- package/dist/tools/ctx-note/index.d.ts +4 -0
- package/dist/tools/ctx-note/index.d.ts.map +1 -0
- package/dist/tools/ctx-note/tools.d.ts +15 -0
- package/dist/tools/ctx-note/tools.d.ts.map +1 -0
- package/dist/tools/ctx-note/types.d.ts +9 -0
- package/dist/tools/ctx-note/types.d.ts.map +1 -0
- package/dist/tools/ctx-reduce/constants.d.ts +2 -0
- package/dist/tools/ctx-reduce/constants.d.ts.map +1 -0
- package/dist/tools/ctx-reduce/index.d.ts +4 -0
- package/dist/tools/ctx-reduce/index.d.ts.map +1 -0
- package/dist/tools/ctx-reduce/tools.d.ts +9 -0
- package/dist/tools/ctx-reduce/tools.d.ts.map +1 -0
- package/dist/tools/ctx-reduce/types.d.ts +4 -0
- package/dist/tools/ctx-reduce/types.d.ts.map +1 -0
- package/dist/tools/ctx-search/constants.d.ts +4 -0
- package/dist/tools/ctx-search/constants.d.ts.map +1 -0
- package/dist/tools/ctx-search/index.d.ts +4 -0
- package/dist/tools/ctx-search/index.d.ts.map +1 -0
- package/dist/tools/ctx-search/tools.d.ts +4 -0
- package/dist/tools/ctx-search/tools.d.ts.map +1 -0
- package/dist/tools/ctx-search/types.d.ts +34 -0
- package/dist/tools/ctx-search/types.d.ts.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tui/data/context-db.d.ts +36 -0
- package/dist/tui/data/context-db.d.ts.map +1 -0
- package/package.json +80 -0
- package/src/shared/announcement.test.ts +143 -0
- package/src/shared/announcement.ts +97 -0
- package/src/shared/assistant-message-extractor.ts +74 -0
- package/src/shared/bounded-session-map.test.ts +97 -0
- package/src/shared/bounded-session-map.ts +84 -0
- package/src/shared/conflict-detector.test.ts +232 -0
- package/src/shared/conflict-detector.ts +371 -0
- package/src/shared/conflict-fixer.test.ts +124 -0
- package/src/shared/conflict-fixer.ts +222 -0
- package/src/shared/data-path.test.ts +159 -0
- package/src/shared/data-path.ts +155 -0
- package/src/shared/error-message.test.ts +94 -0
- package/src/shared/error-message.ts +115 -0
- package/src/shared/format-bytes.ts +5 -0
- package/src/shared/format-threshold.ts +28 -0
- package/src/shared/harness.ts +61 -0
- package/src/shared/index.ts +5 -0
- package/src/shared/internal-initiator-marker.ts +1 -0
- package/src/shared/jsonc-parser.ts +138 -0
- package/src/shared/logger.ts +94 -0
- package/src/shared/model-requirements.ts +86 -0
- package/src/shared/model-suggestion-retry.test.ts +251 -0
- package/src/shared/model-suggestion-retry.ts +348 -0
- package/src/shared/models-dev-cache.test.ts +394 -0
- package/src/shared/models-dev-cache.ts +337 -0
- package/src/shared/native-binding.ts +311 -0
- package/src/shared/normalize-sdk-response.ts +40 -0
- package/src/shared/opencode-compaction-detector.test.ts +222 -0
- package/src/shared/opencode-compaction-detector.ts +81 -0
- package/src/shared/opencode-config-dir-types.ts +15 -0
- package/src/shared/opencode-config-dir.ts +38 -0
- package/src/shared/record-type-guard.ts +3 -0
- package/src/shared/resolve-fallbacks.test.ts +136 -0
- package/src/shared/resolve-fallbacks.ts +76 -0
- package/src/shared/rpc-client.test.ts +161 -0
- package/src/shared/rpc-client.ts +183 -0
- package/src/shared/rpc-notifications.test.ts +20 -0
- package/src/shared/rpc-notifications.ts +53 -0
- package/src/shared/rpc-server.ts +174 -0
- package/src/shared/rpc-types.ts +104 -0
- package/src/shared/rpc-utils.ts +72 -0
- package/src/shared/session-messages-bounded.test.ts +112 -0
- package/src/shared/sqlite-helpers.ts +27 -0
- package/src/shared/sqlite.ts +134 -0
- package/src/shared/stable-json.test.ts +87 -0
- package/src/shared/stable-json.ts +37 -0
- package/src/shared/subagent-runner.ts +222 -0
- package/src/shared/system-directive.ts +9 -0
- package/src/shared/tag-transcript.ts +553 -0
- package/src/shared/transcript-opencode.ts +259 -0
- package/src/shared/transcript.ts +226 -0
- package/src/shared/tui-config.ts +99 -0
- package/src/tui/data/context-db.ts +303 -0
- package/src/tui/index.tsx +692 -0
- package/src/tui/slots/sidebar-content.tsx +482 -0
- package/src/tui/types/opencode-plugin-tui.d.ts +232 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { SidebarSnapshot, StatusDetail } from "../../shared/rpc-types";
|
|
2
|
+
export type { SidebarSnapshot, StatusDetail };
|
|
3
|
+
/** Initialize the RPC client. Call once on TUI startup. */
|
|
4
|
+
export declare function initRpcClient(directory: string): void;
|
|
5
|
+
/** Clean up the RPC client. */
|
|
6
|
+
export declare function closeRpc(): void;
|
|
7
|
+
/** Fetch sidebar snapshot from the server via RPC. */
|
|
8
|
+
export declare function loadSidebarSnapshot(sessionId: string, directory: string): Promise<SidebarSnapshot>;
|
|
9
|
+
/** Fetch full status detail from the server via RPC. */
|
|
10
|
+
export declare function loadStatusDetail(sessionId: string, directory: string, modelKey?: string): Promise<StatusDetail>;
|
|
11
|
+
/** Get compartment count via RPC. */
|
|
12
|
+
export declare function getCompartmentCount(sessionId: string): Promise<number>;
|
|
13
|
+
/** Send recomp request to server via RPC. */
|
|
14
|
+
export declare function requestRecomp(sessionId: string): Promise<boolean>;
|
|
15
|
+
export interface TuiMessage {
|
|
16
|
+
type: string;
|
|
17
|
+
payload: Record<string, unknown>;
|
|
18
|
+
sessionId?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Fetch the current startup announcement from the server, if any.
|
|
22
|
+
* Returns `{show: false}` when there's nothing to announce or when the
|
|
23
|
+
* configured ANNOUNCEMENT_VERSION has already been dismissed.
|
|
24
|
+
*/
|
|
25
|
+
export interface AnnouncementResponse {
|
|
26
|
+
show: boolean;
|
|
27
|
+
version?: string;
|
|
28
|
+
features?: string[];
|
|
29
|
+
footer?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function getAnnouncement(): Promise<AnnouncementResponse>;
|
|
32
|
+
/** Mark the current ANNOUNCEMENT_VERSION as dismissed on the server. */
|
|
33
|
+
export declare function markAnnounced(): Promise<boolean>;
|
|
34
|
+
/** Poll for pending server→TUI notifications via RPC. */
|
|
35
|
+
export declare function consumeTuiMessages(): Promise<TuiMessage[]>;
|
|
36
|
+
//# sourceMappingURL=context-db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-db.d.ts","sourceRoot":"","sources":["../../../src/tui/data/context-db.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA0B,eAAe,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEpG,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;AAc9C,2DAA2D;AAC3D,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAGrD;AAED,+BAA+B;AAC/B,wBAAgB,QAAQ,IAAI,IAAI,CAI/B;AA0FD,sDAAsD;AACtD,wBAAsB,mBAAmB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CA4B1B;AAED,wDAAwD;AACxD,wBAAsB,gBAAgB,CAClC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC,CA4CvB;AAED,qCAAqC;AACrC,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ5E;AAED,6CAA6C;AAC7C,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQvE;AAED,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAkBrE;AAED,wEAAwE;AACxE,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAQtD;AAED,yDAAyD;AACzD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAqBhE"}
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wolfx/opencode-magic-context",
|
|
3
|
+
"version": "0.21.8-patch.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "OpenCode plugin for Magic Context — cross-session memory and context management",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"author": "ualtinok",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"opencode",
|
|
12
|
+
"plugin",
|
|
13
|
+
"context",
|
|
14
|
+
"memory",
|
|
15
|
+
"ai",
|
|
16
|
+
"llm",
|
|
17
|
+
"prompt-caching",
|
|
18
|
+
"session-history"
|
|
19
|
+
],
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/cortexkit/magic-context",
|
|
23
|
+
"directory": "packages/plugin"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src/tui",
|
|
28
|
+
"src/shared",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public",
|
|
33
|
+
"registry": "https://registry.npmjs.org/"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "bun build src/index.ts --outdir dist --target node --format esm --external @opencode-ai/plugin --external @huggingface/transformers --external onnxruntime-web --external better-sqlite3 --external bun:sqlite && tsc --emitDeclarationOnly",
|
|
37
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.scripts.json",
|
|
38
|
+
"test": "bun test",
|
|
39
|
+
"lint": "biome check .",
|
|
40
|
+
"lint:fix": "biome check --write .",
|
|
41
|
+
"format": "biome format --write .",
|
|
42
|
+
"format:check": "biome format .",
|
|
43
|
+
"clean": "rm -rf dist",
|
|
44
|
+
"prepublishOnly": "bun run build"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@huggingface/transformers": "^4.1.0",
|
|
48
|
+
"@opencode-ai/plugin": "^1.14.39",
|
|
49
|
+
"@opencode-ai/sdk": "^1.14.39",
|
|
50
|
+
"ai-tokenizer": "^1.0.6",
|
|
51
|
+
"better-sqlite3": "^12.9.0",
|
|
52
|
+
"comment-json": "^4.2.5",
|
|
53
|
+
"nanotar": "^0.3.0",
|
|
54
|
+
"zod": "^4.1.8"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@biomejs/biome": "^2.4.7",
|
|
58
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
59
|
+
"@types/node": "^22.0.0",
|
|
60
|
+
"bun-types": "^1.3.10",
|
|
61
|
+
"typescript": "^5.8.0"
|
|
62
|
+
},
|
|
63
|
+
"exports": {
|
|
64
|
+
".": {
|
|
65
|
+
"types": "./dist/index.d.ts",
|
|
66
|
+
"import": "./dist/index.js"
|
|
67
|
+
},
|
|
68
|
+
"./tui": {
|
|
69
|
+
"types": "./src/tui/index.tsx",
|
|
70
|
+
"import": "./src/tui/index.tsx"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"oc-plugin": [
|
|
74
|
+
"server",
|
|
75
|
+
"tui"
|
|
76
|
+
],
|
|
77
|
+
"peerDependencies": {
|
|
78
|
+
"@opencode-ai/plugin": ">=1.14.0"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as os from "node:os";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `announcement.ts` reads/writes a single `last_announced_version` file under
|
|
8
|
+
* `getMagicContextStorageDir()`. The behavior we test:
|
|
9
|
+
* 1. `markAnnouncementSeen` then `readLastAnnouncedVersion` round-trips
|
|
10
|
+
* 2. `shouldShowAnnouncement` returns false after a matching mark
|
|
11
|
+
* 3. `shouldShowAnnouncement` returns true after a non-matching mark
|
|
12
|
+
* 4. Empty-version inputs are no-ops (don't crash, don't write garbage)
|
|
13
|
+
*
|
|
14
|
+
* We isolate writes by pointing `XDG_DATA_HOME` at a temp dir before requiring
|
|
15
|
+
* the module fresh per test, since the module captures the storage path at
|
|
16
|
+
* import time via `getMagicContextStorageDir()`.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
let tmpRoot = "";
|
|
20
|
+
let originalXdg: string | undefined;
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "mc-announcement-test-"));
|
|
24
|
+
originalXdg = process.env.XDG_DATA_HOME;
|
|
25
|
+
process.env.XDG_DATA_HOME = tmpRoot;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
if (originalXdg === undefined) {
|
|
30
|
+
delete process.env.XDG_DATA_HOME;
|
|
31
|
+
} else {
|
|
32
|
+
process.env.XDG_DATA_HOME = originalXdg;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
fs.rmSync(tmpRoot, { recursive: true, force: true });
|
|
36
|
+
} catch {
|
|
37
|
+
// best-effort
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("announcement state persistence", () => {
|
|
42
|
+
test("round-trips a dismissed version through the file", async () => {
|
|
43
|
+
// Fresh import after XDG override so the module captures the temp path
|
|
44
|
+
const mod = await import(`./announcement?t=${Date.now()}-rt`);
|
|
45
|
+
const { readLastAnnouncedVersion, markAnnouncementSeen } = mod;
|
|
46
|
+
|
|
47
|
+
expect(readLastAnnouncedVersion()).toBe("");
|
|
48
|
+
|
|
49
|
+
markAnnouncementSeen("9.9.9");
|
|
50
|
+
expect(readLastAnnouncedVersion()).toBe("9.9.9");
|
|
51
|
+
|
|
52
|
+
markAnnouncementSeen("9.9.10");
|
|
53
|
+
expect(readLastAnnouncedVersion()).toBe("9.9.10");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("ignores empty / zero-length version marks", async () => {
|
|
57
|
+
const mod = await import(`./announcement?t=${Date.now()}-empty`);
|
|
58
|
+
const { readLastAnnouncedVersion, markAnnouncementSeen } = mod;
|
|
59
|
+
|
|
60
|
+
markAnnouncementSeen("");
|
|
61
|
+
expect(readLastAnnouncedVersion()).toBe("");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("creates the storage directory if it does not exist", async () => {
|
|
65
|
+
const mod = await import(`./announcement?t=${Date.now()}-mkdir`);
|
|
66
|
+
const { markAnnouncementSeen } = mod;
|
|
67
|
+
|
|
68
|
+
// Storage dir lives under tmpRoot + cortexkit/magic-context — does not
|
|
69
|
+
// exist yet at the start of the test
|
|
70
|
+
const expectedDir = path.join(tmpRoot, "cortexkit", "magic-context");
|
|
71
|
+
expect(fs.existsSync(expectedDir)).toBe(false);
|
|
72
|
+
|
|
73
|
+
markAnnouncementSeen("0.21.7");
|
|
74
|
+
|
|
75
|
+
expect(fs.existsSync(expectedDir)).toBe(true);
|
|
76
|
+
expect(fs.readFileSync(path.join(expectedDir, "last_announced_version"), "utf-8")).toBe(
|
|
77
|
+
"0.21.7",
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("trims whitespace from stored version on read", async () => {
|
|
82
|
+
const mod = await import(`./announcement?t=${Date.now()}-trim`);
|
|
83
|
+
const { readLastAnnouncedVersion } = mod;
|
|
84
|
+
|
|
85
|
+
const dir = path.join(tmpRoot, "cortexkit", "magic-context");
|
|
86
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
87
|
+
fs.writeFileSync(path.join(dir, "last_announced_version"), " 1.2.3 \n");
|
|
88
|
+
|
|
89
|
+
expect(readLastAnnouncedVersion()).toBe("1.2.3");
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("shouldShowAnnouncement gating", () => {
|
|
94
|
+
test("returns false when the live version is already marked", async () => {
|
|
95
|
+
const mod = await import(`./announcement?t=${Date.now()}-match`);
|
|
96
|
+
const {
|
|
97
|
+
ANNOUNCEMENT_VERSION,
|
|
98
|
+
ANNOUNCEMENT_FEATURES,
|
|
99
|
+
markAnnouncementSeen,
|
|
100
|
+
shouldShowAnnouncement,
|
|
101
|
+
} = mod;
|
|
102
|
+
|
|
103
|
+
// Skip the test if announcements are currently disabled (empty constants)
|
|
104
|
+
// — the gate's empty-input behavior is covered separately below.
|
|
105
|
+
if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
markAnnouncementSeen(ANNOUNCEMENT_VERSION);
|
|
110
|
+
expect(shouldShowAnnouncement()).toBe(false);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("returns true when the live version was never marked", async () => {
|
|
114
|
+
const mod = await import(`./announcement?t=${Date.now()}-none`);
|
|
115
|
+
const { ANNOUNCEMENT_VERSION, ANNOUNCEMENT_FEATURES, shouldShowAnnouncement } = mod;
|
|
116
|
+
|
|
117
|
+
if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0) {
|
|
118
|
+
// When empty, the gate is always false regardless of state
|
|
119
|
+
expect(shouldShowAnnouncement()).toBe(false);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// No mark has been written in this fresh tmpRoot, so the gate is open
|
|
124
|
+
expect(shouldShowAnnouncement()).toBe(true);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("returns true when a different (older) version is marked", async () => {
|
|
128
|
+
const mod = await import(`./announcement?t=${Date.now()}-older`);
|
|
129
|
+
const {
|
|
130
|
+
ANNOUNCEMENT_VERSION,
|
|
131
|
+
ANNOUNCEMENT_FEATURES,
|
|
132
|
+
markAnnouncementSeen,
|
|
133
|
+
shouldShowAnnouncement,
|
|
134
|
+
} = mod;
|
|
135
|
+
|
|
136
|
+
if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
markAnnouncementSeen("0.0.0-pre-historic");
|
|
141
|
+
expect(shouldShowAnnouncement()).toBe(true);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Release-notes startup announcement shared by OpenCode plugin and Pi plugin.
|
|
3
|
+
*
|
|
4
|
+
* Bump `ANNOUNCEMENT_VERSION` and populate `ANNOUNCEMENT_FEATURES` *only* when a
|
|
5
|
+
* release ships user-facing news worth surfacing once at startup. Patch releases
|
|
6
|
+
* with no user-visible changes should leave both untouched — that way a user who
|
|
7
|
+
* already dismissed the dialog for the current `ANNOUNCEMENT_VERSION` won't see
|
|
8
|
+
* it again on the next bugfix bump.
|
|
9
|
+
*
|
|
10
|
+
* The persisted state is a single line of text (`last_announced_version`) under
|
|
11
|
+
* `getMagicContextStorageDir()`. OpenCode and Pi share the same file because
|
|
12
|
+
* they share the same storage root — so dismissing in one harness suppresses
|
|
13
|
+
* the dialog in the other for the same announcement.
|
|
14
|
+
*
|
|
15
|
+
* Leave both empty (`""` and `[]`) to skip the dialog entirely.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import * as fs from "node:fs";
|
|
19
|
+
import * as path from "node:path";
|
|
20
|
+
import { getMagicContextStorageDir } from "./data-path";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Bump only when there are user-visible changes worth a startup dialog.
|
|
24
|
+
* Does NOT need to match the published package version.
|
|
25
|
+
*/
|
|
26
|
+
export const ANNOUNCEMENT_VERSION = "0.21.7";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Short, user-facing bullet strings. Keep each line ~80 chars or shorter so the
|
|
30
|
+
* TUI dialog renders cleanly without horizontal scroll on a typical terminal.
|
|
31
|
+
*/
|
|
32
|
+
export const ANNOUNCEMENT_FEATURES: ReadonlyArray<string> = [
|
|
33
|
+
"Pi parity sweep: 44 audit findings fixed, including a critical SHIP-BLOCKER where /ctx-flush did not drain the pending Pi compaction queue.",
|
|
34
|
+
"Pi historian recovery fix: empty/no-op historian returns now clear emergency recovery so sessions cannot loop forever at 95%.",
|
|
35
|
+
"trimPiMessagesToBoundary now sweeps non-contiguous tool-result orphans, fixing provider 400s after compaction in long Pi sessions.",
|
|
36
|
+
"Hidden subagent tool isolation: historian, dreamer, and sidekick can no longer spawn subagents or run unsafe tools.",
|
|
37
|
+
"TUI sidebar and /ctx-status header now show execute threshold inline: '47.5% / 65%' on the left, '475K / 1.0M' on the right.",
|
|
38
|
+
"doctor --issue now caps GitHub issue bodies at ~60KB with a dedicated 'Recent errors' section so reports stay submittable.",
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Persistent footer rendered below the version-specific bullets in every
|
|
43
|
+
* announcement. Stays in place across releases so users always see the Discord
|
|
44
|
+
* invite without us needing to repeat it in `ANNOUNCEMENT_FEATURES` each time.
|
|
45
|
+
*
|
|
46
|
+
* Leave empty (`""`) to suppress the footer.
|
|
47
|
+
*/
|
|
48
|
+
export const ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU";
|
|
49
|
+
|
|
50
|
+
const STATE_FILENAME = "last_announced_version";
|
|
51
|
+
|
|
52
|
+
function getStateFilePath(): string {
|
|
53
|
+
return path.join(getMagicContextStorageDir(), STATE_FILENAME);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Read the most recently dismissed announcement version, or `""` if none.
|
|
58
|
+
*
|
|
59
|
+
* Best-effort: any read failure returns `""` (which forces the announcement to
|
|
60
|
+
* re-show). The cost of a spurious second dialog is much smaller than the cost
|
|
61
|
+
* of suppressing a real announcement due to a transient FS error.
|
|
62
|
+
*/
|
|
63
|
+
export function readLastAnnouncedVersion(): string {
|
|
64
|
+
try {
|
|
65
|
+
const file = getStateFilePath();
|
|
66
|
+
if (!fs.existsSync(file)) return "";
|
|
67
|
+
return fs.readFileSync(file, "utf-8").trim();
|
|
68
|
+
} catch {
|
|
69
|
+
return "";
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Persist `version` as the most recently dismissed announcement. Best-effort:
|
|
75
|
+
* write failures are swallowed so dialog-confirm flows never throw on storage
|
|
76
|
+
* errors. Worst case the user sees the same dialog once more on next startup.
|
|
77
|
+
*/
|
|
78
|
+
export function markAnnouncementSeen(version: string): void {
|
|
79
|
+
if (!version) return;
|
|
80
|
+
try {
|
|
81
|
+
const dir = getMagicContextStorageDir();
|
|
82
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
83
|
+
fs.writeFileSync(getStateFilePath(), version);
|
|
84
|
+
} catch {
|
|
85
|
+
// best-effort
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* True when the configured `ANNOUNCEMENT_VERSION` has not yet been dismissed
|
|
91
|
+
* AND there is at least one feature to show. Used by both the TUI dialog path
|
|
92
|
+
* and the Desktop ignored-message fallback.
|
|
93
|
+
*/
|
|
94
|
+
export function shouldShowAnnouncement(): boolean {
|
|
95
|
+
if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0) return false;
|
|
96
|
+
return readLastAnnouncedVersion() !== ANNOUNCEMENT_VERSION;
|
|
97
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
type MessageTime = { created?: number };
|
|
2
|
+
|
|
3
|
+
type MessageInfo = {
|
|
4
|
+
role?: string;
|
|
5
|
+
time?: MessageTime;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type MessagePart = {
|
|
9
|
+
type?: string;
|
|
10
|
+
text?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type SessionMessage = {
|
|
14
|
+
info?: MessageInfo;
|
|
15
|
+
parts?: unknown;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
import { isRecord } from "./record-type-guard";
|
|
19
|
+
|
|
20
|
+
function asSessionMessage(value: unknown): SessionMessage | null {
|
|
21
|
+
if (!isRecord(value)) return null;
|
|
22
|
+
const info = value.info;
|
|
23
|
+
const parts = value.parts;
|
|
24
|
+
return {
|
|
25
|
+
info: isRecord(info)
|
|
26
|
+
? {
|
|
27
|
+
role: typeof info.role === "string" ? info.role : undefined,
|
|
28
|
+
time: isRecord(info.time)
|
|
29
|
+
? {
|
|
30
|
+
created:
|
|
31
|
+
typeof info.time.created === "number"
|
|
32
|
+
? info.time.created
|
|
33
|
+
: undefined,
|
|
34
|
+
}
|
|
35
|
+
: undefined,
|
|
36
|
+
}
|
|
37
|
+
: undefined,
|
|
38
|
+
parts,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getCreatedTime(message: SessionMessage): number {
|
|
43
|
+
return message.info?.time?.created ?? 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getTextParts(message: SessionMessage): MessagePart[] {
|
|
47
|
+
if (!Array.isArray(message.parts)) return [];
|
|
48
|
+
return message.parts
|
|
49
|
+
.filter((part): part is Record<string, unknown> => isRecord(part))
|
|
50
|
+
.map((part) => ({
|
|
51
|
+
type: typeof part.type === "string" ? part.type : undefined,
|
|
52
|
+
text: typeof part.text === "string" ? part.text : undefined,
|
|
53
|
+
}))
|
|
54
|
+
.filter((part) => part.type === "text" && Boolean(part.text));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function extractLatestAssistantText(messages: unknown): string | null {
|
|
58
|
+
if (!Array.isArray(messages) || messages.length === 0) return null;
|
|
59
|
+
|
|
60
|
+
const assistantMessages = messages
|
|
61
|
+
.map(asSessionMessage)
|
|
62
|
+
.filter((message): message is SessionMessage => message !== null)
|
|
63
|
+
.filter((message) => message.info?.role === "assistant")
|
|
64
|
+
.sort((a, b) => getCreatedTime(b) - getCreatedTime(a));
|
|
65
|
+
|
|
66
|
+
const latest = assistantMessages[0];
|
|
67
|
+
if (!latest) return null;
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
getTextParts(latest)
|
|
71
|
+
.map((part) => part.text)
|
|
72
|
+
.join("\n") || null
|
|
73
|
+
);
|
|
74
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { BoundedSessionMap } from "./bounded-session-map";
|
|
3
|
+
|
|
4
|
+
describe("BoundedSessionMap", () => {
|
|
5
|
+
it("rejects non-positive caps", () => {
|
|
6
|
+
expect(() => new BoundedSessionMap(0)).toThrow();
|
|
7
|
+
expect(() => new BoundedSessionMap(-5)).toThrow();
|
|
8
|
+
expect(() => new BoundedSessionMap(Number.NaN)).toThrow();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("stores and retrieves values", () => {
|
|
12
|
+
const map = new BoundedSessionMap<number>(3);
|
|
13
|
+
map.set("a", 1);
|
|
14
|
+
map.set("b", 2);
|
|
15
|
+
expect(map.get("a")).toBe(1);
|
|
16
|
+
expect(map.get("b")).toBe(2);
|
|
17
|
+
expect(map.get("missing")).toBeUndefined();
|
|
18
|
+
expect(map.size).toBe(2);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("evicts the oldest entry when cap is exceeded", () => {
|
|
22
|
+
const map = new BoundedSessionMap<string>(3);
|
|
23
|
+
map.set("a", "alpha");
|
|
24
|
+
map.set("b", "bravo");
|
|
25
|
+
map.set("c", "charlie");
|
|
26
|
+
map.set("d", "delta"); // evicts "a"
|
|
27
|
+
expect(map.has("a")).toBe(false);
|
|
28
|
+
expect(map.has("b")).toBe(true);
|
|
29
|
+
expect(map.has("c")).toBe(true);
|
|
30
|
+
expect(map.has("d")).toBe(true);
|
|
31
|
+
expect(map.size).toBe(3);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("treats get() as a touch for LRU ordering", () => {
|
|
35
|
+
const map = new BoundedSessionMap<string>(3);
|
|
36
|
+
map.set("a", "alpha");
|
|
37
|
+
map.set("b", "bravo");
|
|
38
|
+
map.set("c", "charlie");
|
|
39
|
+
// Touch "a" — now "b" is the oldest.
|
|
40
|
+
expect(map.get("a")).toBe("alpha");
|
|
41
|
+
map.set("d", "delta");
|
|
42
|
+
expect(map.has("b")).toBe(false);
|
|
43
|
+
expect(map.has("a")).toBe(true);
|
|
44
|
+
expect(map.has("c")).toBe(true);
|
|
45
|
+
expect(map.has("d")).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("peek() does NOT touch recency", () => {
|
|
49
|
+
const map = new BoundedSessionMap<number>(3);
|
|
50
|
+
map.set("a", 1);
|
|
51
|
+
map.set("b", 2);
|
|
52
|
+
map.set("c", 3);
|
|
53
|
+
expect(map.peek("a")).toBe(1);
|
|
54
|
+
// Adding a fourth entry should still evict "a" since peek didn't touch it.
|
|
55
|
+
map.set("d", 4);
|
|
56
|
+
expect(map.has("a")).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("set() on existing key refreshes recency without growing size", () => {
|
|
60
|
+
const map = new BoundedSessionMap<number>(3);
|
|
61
|
+
map.set("a", 1);
|
|
62
|
+
map.set("b", 2);
|
|
63
|
+
map.set("c", 3);
|
|
64
|
+
map.set("a", 100); // refresh "a" to most-recent with new value
|
|
65
|
+
expect(map.size).toBe(3);
|
|
66
|
+
expect(map.get("a")).toBe(100);
|
|
67
|
+
map.set("d", 4); // evicts "b" (now oldest)
|
|
68
|
+
expect(map.has("b")).toBe(false);
|
|
69
|
+
expect(map.has("a")).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("delete() removes entries and returns true when present", () => {
|
|
73
|
+
const map = new BoundedSessionMap<number>(3);
|
|
74
|
+
map.set("a", 1);
|
|
75
|
+
expect(map.delete("a")).toBe(true);
|
|
76
|
+
expect(map.delete("a")).toBe(false);
|
|
77
|
+
expect(map.size).toBe(0);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("clear() drops all entries", () => {
|
|
81
|
+
const map = new BoundedSessionMap<number>(3);
|
|
82
|
+
map.set("a", 1);
|
|
83
|
+
map.set("b", 2);
|
|
84
|
+
map.clear();
|
|
85
|
+
expect(map.size).toBe(0);
|
|
86
|
+
expect(map.get("a")).toBeUndefined();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("tolerates cap=1 edge case (every set evicts previous)", () => {
|
|
90
|
+
const map = new BoundedSessionMap<number>(1);
|
|
91
|
+
map.set("a", 1);
|
|
92
|
+
map.set("b", 2);
|
|
93
|
+
expect(map.has("a")).toBe(false);
|
|
94
|
+
expect(map.get("b")).toBe(2);
|
|
95
|
+
expect(map.size).toBe(1);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded LRU map keyed by session id.
|
|
3
|
+
*
|
|
4
|
+
* Rationale: magic-context maintains several module-scope Maps that track
|
|
5
|
+
* per-session state (prepared injection cache, per-message token cache, etc.).
|
|
6
|
+
* These are cleared on the `session.deleted` event, but sessions that are
|
|
7
|
+
* never explicitly deleted — because OpenCode crashed, the user force-quit,
|
|
8
|
+
* the session was archived rather than deleted, or the session simply outlived
|
|
9
|
+
* the plugin process's interest in it — leak entries for the lifetime of the
|
|
10
|
+
* plugin process.
|
|
11
|
+
*
|
|
12
|
+
* In long-running OpenCode instances with thousands of sessions over time,
|
|
13
|
+
* an unbounded `Map<sessionId, LargeObject>` can retain tens of megabytes
|
|
14
|
+
* indefinitely. A session-scoped LRU with a generous cap (e.g. 100) covers
|
|
15
|
+
* any realistic working-set of active sessions a user actually cares about,
|
|
16
|
+
* while evicting cold session ids that will either never return or be
|
|
17
|
+
* rebuilt from durable SQLite state on their next transform pass.
|
|
18
|
+
*
|
|
19
|
+
* Implementation notes:
|
|
20
|
+
* - Built on `Map` which preserves insertion order. On every `set`/`get`
|
|
21
|
+
* touch we delete+reinsert to move the key to the tail (most-recent).
|
|
22
|
+
* - Eviction drops the oldest entry (first in iteration order).
|
|
23
|
+
* - The cached value type is generic — callers decide what per-session state
|
|
24
|
+
* to store. For injection/token state, all three properties of the cached
|
|
25
|
+
* object are safe to throw away: they are either recomputable from the
|
|
26
|
+
* messages array on the next pass, or reloadable from SQLite.
|
|
27
|
+
*/
|
|
28
|
+
export class BoundedSessionMap<V> {
|
|
29
|
+
private readonly maxEntries: number;
|
|
30
|
+
private readonly store = new Map<string, V>();
|
|
31
|
+
|
|
32
|
+
constructor(maxEntries: number) {
|
|
33
|
+
if (!Number.isFinite(maxEntries) || maxEntries < 1) {
|
|
34
|
+
throw new Error(`BoundedSessionMap: maxEntries must be >= 1, got ${maxEntries}`);
|
|
35
|
+
}
|
|
36
|
+
this.maxEntries = maxEntries;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get(sessionId: string): V | undefined {
|
|
40
|
+
const value = this.store.get(sessionId);
|
|
41
|
+
if (value === undefined) return undefined;
|
|
42
|
+
// Touch: move to most-recent position.
|
|
43
|
+
this.store.delete(sessionId);
|
|
44
|
+
this.store.set(sessionId, value);
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Peek without touching recency — useful for `has`-style checks that
|
|
50
|
+
* should not rearrange LRU order. Use sparingly; `get` is the normal
|
|
51
|
+
* access path.
|
|
52
|
+
*/
|
|
53
|
+
peek(sessionId: string): V | undefined {
|
|
54
|
+
return this.store.get(sessionId);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
has(sessionId: string): boolean {
|
|
58
|
+
return this.store.has(sessionId);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
set(sessionId: string, value: V): void {
|
|
62
|
+
if (this.store.has(sessionId)) {
|
|
63
|
+
// Refresh recency.
|
|
64
|
+
this.store.delete(sessionId);
|
|
65
|
+
} else if (this.store.size >= this.maxEntries) {
|
|
66
|
+
// Evict oldest entry. Map iteration is insertion-ordered.
|
|
67
|
+
const oldest = this.store.keys().next().value;
|
|
68
|
+
if (oldest !== undefined) this.store.delete(oldest);
|
|
69
|
+
}
|
|
70
|
+
this.store.set(sessionId, value);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
delete(sessionId: string): boolean {
|
|
74
|
+
return this.store.delete(sessionId);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
clear(): void {
|
|
78
|
+
this.store.clear();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get size(): number {
|
|
82
|
+
return this.store.size;
|
|
83
|
+
}
|
|
84
|
+
}
|