@cortexkit/opencode-magic-context 0.41.3 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -3
- package/dist/agents/hidden-agent-registrations.d.ts +1 -3
- package/dist/agents/hidden-agent-registrations.d.ts.map +1 -1
- package/dist/agents/magic-context-prompt.d.ts +1 -1
- package/dist/agents/magic-context-prompt.d.ts.map +1 -1
- package/dist/agents/permissions.d.ts +1 -22
- package/dist/agents/permissions.d.ts.map +1 -1
- package/dist/config/agent-disable.d.ts +0 -5
- package/dist/config/agent-disable.d.ts.map +1 -1
- package/dist/config/index.d.ts +14 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/migrate-config-location.d.ts.map +1 -1
- package/dist/config/project-security.d.ts +17 -0
- package/dist/config/project-security.d.ts.map +1 -1
- package/dist/config/removed-agent-config.d.ts +8 -0
- package/dist/config/removed-agent-config.d.ts.map +1 -0
- package/dist/config/schema/magic-context.d.ts +23 -201
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/{conflict-warning-hook-z5sd697e.js → conflict-warning-hook-6p3xqeac.js} +4 -4
- package/dist/{derive-budgets-901a0pk0.js → derive-budgets-s2pgnnm4.js} +4 -2
- package/dist/features/builtin-commands/commands.d.ts +0 -4
- package/dist/features/builtin-commands/commands.d.ts.map +1 -1
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts +7 -0
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
- package/dist/features/magic-context/context-authority.d.ts +31 -4
- package/dist/features/magic-context/context-authority.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/map-memories.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/open-opencode-db.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/retrospective-orphan-sweep.d.ts +19 -9
- package/dist/features/magic-context/dreamer/retrospective-orphan-sweep.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +13 -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.map +1 -1
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts +7 -0
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
- package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/sweep-coordinator.d.ts.map +1 -1
- package/dist/features/magic-context/index.d.ts +0 -1
- package/dist/features/magic-context/index.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts +13 -0
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-synapse.d.ts +43 -10
- package/dist/features/magic-context/memory/embedding-synapse.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
- package/dist/features/magic-context/memory/project-identity.d.ts +1 -0
- package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
- package/dist/features/magic-context/memory/promotion.d.ts +7 -1
- package/dist/features/magic-context/memory/promotion.d.ts.map +1 -1
- package/dist/features/magic-context/merged-reasoning-decisions.d.ts +6 -0
- package/dist/features/magic-context/merged-reasoning-decisions.d.ts.map +1 -0
- package/dist/features/magic-context/message-fts-rowid-map.d.ts.map +1 -1
- package/dist/features/magic-context/message-index-async.d.ts +12 -0
- package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
- package/dist/features/magic-context/mural/render-trigger.d.ts +6 -0
- package/dist/features/magic-context/mural/render-trigger.d.ts.map +1 -1
- package/dist/features/magic-context/no-content-compartment.d.ts +12 -0
- package/dist/features/magic-context/no-content-compartment.d.ts.map +1 -0
- package/dist/features/magic-context/pi-content-decisions.d.ts +9 -0
- package/dist/features/magic-context/pi-content-decisions.d.ts.map +1 -0
- package/dist/features/magic-context/project-docs-hash.d.ts +4 -0
- package/dist/features/magic-context/project-docs-hash.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts +13 -4
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/protection-window.d.ts +79 -0
- package/dist/features/magic-context/protection-window.d.ts.map +1 -0
- package/dist/features/magic-context/search.d.ts.map +1 -1
- package/dist/features/magic-context/session-project-backfill.d.ts.map +1 -1
- package/dist/features/magic-context/shadow-backfill-state.d.ts +26 -0
- package/dist/features/magic-context/shadow-backfill-state.d.ts.map +1 -0
- package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts +4 -0
- package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/storage.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 +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-embedding-measurements.d.ts +2 -2
- package/dist/features/magic-context/storage-embedding-measurements.d.ts.map +1 -1
- package/dist/features/magic-context/storage-historian-runs.d.ts +4 -0
- package/dist/features/magic-context/storage-historian-runs.d.ts.map +1 -1
- package/dist/features/magic-context/storage-memory-mutation-log.d.ts +1 -0
- package/dist/features/magic-context/storage-memory-mutation-log.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +81 -15
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta.d.ts +1 -1
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
- package/dist/features/magic-context/storage-native-replay.d.ts +29 -0
- package/dist/features/magic-context/storage-native-replay.d.ts.map +1 -0
- package/dist/features/magic-context/storage-notes.d.ts +6 -0
- package/dist/features/magic-context/storage-notes.d.ts.map +1 -1
- package/dist/features/magic-context/storage-replay-document.d.ts +33 -0
- package/dist/features/magic-context/storage-replay-document.d.ts.map +1 -0
- package/dist/features/magic-context/storage-subagent-invocations.d.ts +1 -1
- package/dist/features/magic-context/storage-subagent-invocations.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts +19 -11
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +3 -3
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -1
- package/dist/features/magic-context/tagger.d.ts +13 -0
- package/dist/features/magic-context/tagger.d.ts.map +1 -1
- package/dist/features/magic-context/tool-owner-backfill.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
- package/dist/features/magic-context/workspaces.d.ts.map +1 -1
- package/dist/hooks/magic-context/apply-operations.d.ts +11 -5
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts +9 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
- package/dist/hooks/magic-context/caveman-cleanup.d.ts +1 -1
- package/dist/hooks/magic-context/caveman-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
- package/dist/hooks/magic-context/child-session-spawn.d.ts +3 -3
- package/dist/hooks/magic-context/child-session-spawn.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +5 -10
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts +10 -21
- 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-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +4 -0
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +26 -2
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
- package/dist/hooks/magic-context/decay-render.d.ts.map +1 -1
- package/dist/hooks/magic-context/derive-budgets.d.ts +1 -0
- package/dist/hooks/magic-context/derive-budgets.d.ts.map +1 -1
- package/dist/hooks/magic-context/dropped-input-guard.d.ts +9 -0
- package/dist/hooks/magic-context/dropped-input-guard.d.ts.map +1 -0
- package/dist/hooks/magic-context/emergency-drop.d.ts +9 -2
- package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts +0 -1
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-payloads.d.ts +7 -6
- package/dist/hooks/magic-context/event-payloads.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-resolvers.d.ts +1 -1
- package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
- package/dist/hooks/magic-context/execute-status.d.ts +8 -2
- package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
- package/dist/hooks/magic-context/format-embed-status.d.ts.map +1 -1
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts +11 -4
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts +5 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +17 -5
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +14 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/issue-423-fixture.d.ts +37 -0
- package/dist/hooks/magic-context/issue-423-fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/issue-424-fixture.d.ts +11 -0
- package/dist/hooks/magic-context/issue-424-fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/live-session-state.d.ts +1 -1
- package/dist/hooks/magic-context/lkg-slot.d.ts +34 -0
- package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-state-sync-timing.d.ts +21 -0
- package/dist/hooks/magic-context/module-state-sync-timing.d.ts.map +1 -0
- package/dist/hooks/magic-context/module-state-sync.d.ts +21 -7
- package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-transport.d.ts +12 -0
- package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-wire.d.ts +8 -0
- package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
- package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
- package/dist/hooks/magic-context/persist-filtered-noise.d.ts +5 -0
- package/dist/hooks/magic-context/persist-filtered-noise.d.ts.map +1 -0
- package/dist/hooks/magic-context/producer-window-guard.d.ts +8 -0
- package/dist/hooks/magic-context/producer-window-guard.d.ts.map +1 -0
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts +65 -0
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-chunk.d.ts +20 -18
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-db.d.ts +22 -12
- package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-formatting.d.ts +8 -0
- package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-raw.d.ts +10 -1
- package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts +4 -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.map +1 -1
- package/dist/hooks/magic-context/rust-mode-transform.d.ts +79 -11
- package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/send-session-notification.d.ts +11 -10
- package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
- package/dist/hooks/magic-context/sentinel.d.ts +3 -3
- package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts +7 -0
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/supersession-reclaim.d.ts +13 -0
- package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts +2 -3
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts +2 -0
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +16 -6
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-drop-target.d.ts +1 -0
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +2 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-context-state.d.ts +7 -1
- package/dist/hooks/magic-context/transform-context-state.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +11 -4
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +11 -2
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/upgrade-reminder.d.ts +7 -9
- package/dist/hooks/magic-context/upgrade-reminder.d.ts.map +1 -1
- package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
- package/dist/index-1974jvn3.js +783 -0
- package/dist/{index-npx8vhmy.js → index-36wd1d6k.js} +7 -30
- package/dist/{index-kby1sng5.js → index-avwt563y.js} +8 -1
- package/dist/{index-vmmjdpc0.js → index-c9hamh36.js} +18357 -16010
- package/dist/{index-0bycg0np.js → index-jmtjh2d3.js} +4 -4
- package/dist/{index-q264erdp.js → index-nqgjwfzn.js} +70 -38
- package/dist/index-sd3egckz.js +1583 -0
- package/dist/{index-dn1rwpd8.js → index-xdtge3y2.js} +58 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6826 -6660
- package/dist/plugin/conflict-warning-hook.d.ts +5 -6
- package/dist/plugin/conflict-warning-hook.d.ts.map +1 -1
- package/dist/plugin/dream-timer.d.ts +1 -0
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/embedding-routing.d.ts +4 -1
- package/dist/plugin/embedding-routing.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +19 -2
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts +31 -1
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/plugin/rust-tool-backends.d.ts +1 -0
- package/dist/plugin/rust-tool-backends.d.ts.map +1 -1
- package/dist/plugin/tool-registry.d.ts.map +1 -1
- package/dist/{recomp-orchestrator-f5m2wk74.js → recomp-orchestrator-3atsasjy.js} +6 -6
- package/dist/{send-session-notification-hdh02wy9.js → send-session-notification-1qeqkswb.js} +6 -4
- package/dist/shared/cache-ttl-display.d.ts +23 -0
- package/dist/shared/cache-ttl-display.d.ts.map +1 -0
- package/dist/shared/cache-ttl-seed.d.ts +10 -0
- package/dist/shared/cache-ttl-seed.d.ts.map +1 -0
- package/dist/shared/child-session-teardown.d.ts +34 -0
- package/dist/shared/child-session-teardown.d.ts.map +1 -0
- package/dist/shared/config-diagnostics.d.ts +30 -0
- package/dist/shared/config-diagnostics.d.ts.map +1 -0
- package/dist/shared/config-warning-surface.d.ts +3 -0
- package/dist/shared/config-warning-surface.d.ts.map +1 -0
- package/dist/shared/data-path.d.ts +10 -9
- package/dist/shared/data-path.d.ts.map +1 -1
- package/dist/shared/harness-provider-map.d.ts +7 -0
- package/dist/shared/harness-provider-map.d.ts.map +1 -1
- package/dist/shared/jsonc-parser.d.ts +12 -0
- package/dist/shared/jsonc-parser.d.ts.map +1 -1
- package/dist/shared/keep-subagents.d.ts +1 -1
- package/dist/shared/keep-subagents.d.ts.map +1 -1
- package/dist/shared/model-suggestion-retry.d.ts +15 -11
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/opencode-db-path.d.ts +24 -0
- package/dist/shared/opencode-db-path.d.ts.map +1 -0
- package/dist/shared/pi-executable.d.ts +6 -0
- package/dist/shared/pi-executable.d.ts.map +1 -0
- package/dist/shared/prompt-surface-runtime.d.ts +10 -5
- package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
- package/dist/shared/resolve-fallbacks.d.ts +1 -1
- package/dist/shared/rpc-types.d.ts +117 -0
- package/dist/shared/rpc-types.d.ts.map +1 -1
- package/dist/shared/rpc-utils.d.ts.map +1 -1
- package/dist/shared/sqlite.d.ts +42 -0
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/shared/status-detail-text.d.ts.map +1 -1
- package/dist/shared/subagent-runner.d.ts +17 -10
- package/dist/shared/subagent-runner.d.ts.map +1 -1
- package/dist/shared/tag-transcript.d.ts.map +1 -1
- package/dist/shared/transcript.d.ts +6 -0
- package/dist/shared/transcript.d.ts.map +1 -1
- package/dist/shared/window-geometry.d.ts +23 -0
- package/dist/shared/window-geometry.d.ts.map +1 -1
- package/dist/shared/write-transaction-timing.d.ts +1 -1
- package/dist/shared/write-transaction-timing.d.ts.map +1 -1
- package/dist/{storage-meta-session-3rxx9ekm.js → storage-meta-session-e6g0mmec.js} +2 -2
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- package/dist/tools/ctx-memory/verification-recording.d.ts.map +1 -1
- package/dist/tools/ctx-note/constants.d.ts +1 -1
- package/dist/tools/ctx-note/constants.d.ts.map +1 -1
- package/dist/tools/ctx-note/tools.d.ts.map +1 -1
- package/dist/tools/ctx-note/types.d.ts +1 -0
- package/dist/tools/ctx-note/types.d.ts.map +1 -1
- package/dist/tools/ctx-reduce/tools.d.ts +10 -1
- package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/constants.d.ts +1 -1
- package/dist/tools/ctx-search/constants.d.ts.map +1 -1
- package/dist/tools/light-descriptions.d.ts +2 -2
- package/dist/tools/light-descriptions.d.ts.map +1 -1
- package/package.json +2 -3
- package/src/agents/hidden-agent-registrations.ts +3 -15
- package/src/agents/magic-context-prompt.test.ts +7 -5
- package/src/agents/magic-context-prompt.ts +22 -30
- package/src/agents/permissions.test.ts +1 -42
- package/src/agents/permissions.ts +1 -24
- package/src/config/agent-disable.ts +5 -22
- package/src/config/index.test.ts +169 -14
- package/src/config/index.ts +137 -21
- package/src/config/latch-permanence-guard.test.ts +4 -0
- package/src/config/migrate-config-location.test.ts +39 -6
- package/src/config/migrate-config-location.ts +18 -31
- package/src/config/profiles.ts +1 -1
- package/src/config/project-security.hostile-matrix.test.ts +0 -8
- package/src/config/project-security.test.ts +11 -22
- package/src/config/project-security.ts +103 -9
- package/src/config/protected-tokens.test.ts +235 -0
- package/src/config/removed-agent-config.ts +45 -0
- package/src/config/removed-agent-source-fence.test.ts +56 -0
- package/src/config/schema/magic-context.test.ts +21 -42
- package/src/config/schema/magic-context.ts +46 -37
- package/src/shared/cache-ttl-display.test.ts +84 -0
- package/src/shared/cache-ttl-display.ts +64 -0
- package/src/shared/cache-ttl-seed.ts +23 -0
- package/src/shared/child-session-teardown.test.ts +218 -0
- package/src/shared/child-session-teardown.ts +66 -0
- package/src/shared/config-diagnostics.test.ts +29 -0
- package/src/shared/config-diagnostics.ts +64 -0
- package/src/shared/config-warning-surface.ts +28 -0
- package/src/shared/data-path.ts +10 -9
- package/src/shared/harness-provider-map.test.ts +16 -0
- package/src/shared/harness-provider-map.ts +15 -0
- package/src/shared/jsonc-parser.test.ts +14 -1
- package/src/shared/jsonc-parser.ts +93 -0
- package/src/shared/keep-subagents.ts +9 -14
- package/src/shared/model-suggestion-retry.ts +144 -29
- package/src/shared/opencode-db-path.test.ts +196 -0
- package/src/shared/opencode-db-path.ts +215 -0
- package/src/shared/pi-executable.ts +20 -0
- package/src/shared/prompt-surface-a1-golden.md +50 -35
- package/src/shared/prompt-surface-runtime.test.ts +28 -0
- package/src/shared/prompt-surface-runtime.ts +22 -5
- package/src/shared/resolve-fallbacks.ts +1 -1
- package/src/shared/rpc-types.ts +124 -0
- package/src/shared/rpc-utils.ts +2 -3
- package/src/shared/session-messages-bounded.test.ts +1 -1
- package/src/shared/sqlite-import-fence.test.ts +19 -0
- package/src/shared/sqlite.test.ts +27 -1
- package/src/shared/sqlite.ts +204 -1
- package/src/shared/status-detail-text.test.ts +8 -4
- package/src/shared/status-detail-text.ts +20 -1
- package/src/shared/subagent-runner.ts +17 -10
- package/src/shared/tag-transcript.ts +53 -22
- package/src/shared/transcript.ts +7 -0
- package/src/shared/window-geometry.test.ts +44 -0
- package/src/shared/window-geometry.ts +89 -11
- package/src/shared/write-transaction-attribution.test.ts +241 -0
- package/src/shared/write-transaction-timing.ts +2 -1
- package/src/tui/index.tsx +18 -4
- package/src/tui/slots/sidebar-content.tsx +12 -7
- package/src/tui-compiled/index.tsx +237 -225
- package/src/tui-compiled/slots/sidebar-content.tsx +301 -305
- package/dist/agents/sidekick.d.ts +0 -2
- package/dist/agents/sidekick.d.ts.map +0 -1
- package/dist/features/magic-context/defaults.d.ts +0 -2
- package/dist/features/magic-context/defaults.d.ts.map +0 -1
- package/dist/features/magic-context/sidekick/agent.d.ts +0 -14
- package/dist/features/magic-context/sidekick/agent.d.ts.map +0 -1
- package/dist/features/magic-context/sidekick/core.d.ts +0 -38
- package/dist/features/magic-context/sidekick/core.d.ts.map +0 -1
- package/dist/features/magic-context/sidekick/index.d.ts +0 -3
- package/dist/features/magic-context/sidekick/index.d.ts.map +0 -1
- package/dist/hooks/magic-context/boundary-execution.d.ts +0 -27
- package/dist/hooks/magic-context/boundary-execution.d.ts.map +0 -1
- package/dist/index-jfpk81yt.js +0 -146
- package/dist/index-raatkvw5.js +0 -360
- package/src/agents/sidekick.ts +0 -1
- package/src/features/magic-context/defaults.ts +0 -1
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/// <reference types="bun-types" />
|
|
2
|
+
|
|
3
|
+
import { afterEach, describe, expect, mock, test } from "bun:test";
|
|
4
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
5
|
+
import { join, relative } from "node:path";
|
|
6
|
+
import ts from "typescript";
|
|
7
|
+
|
|
8
|
+
import { sweepOrphanedRetrospectiveChildren } from "../features/magic-context/dreamer/retrospective-orphan-sweep";
|
|
9
|
+
import { teardownChildSession } from "./child-session-teardown";
|
|
10
|
+
import { _resetKeepSubagentsForTesting, setKeepSubagents } from "./keep-subagents";
|
|
11
|
+
import { Database } from "./sqlite";
|
|
12
|
+
import { closeQuietly } from "./sqlite-helpers";
|
|
13
|
+
|
|
14
|
+
interface TeardownFixture {
|
|
15
|
+
client: {
|
|
16
|
+
session: {
|
|
17
|
+
delete: ReturnType<typeof mock>;
|
|
18
|
+
update: ReturnType<typeof mock>;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
calls: string[];
|
|
22
|
+
deleted: string[];
|
|
23
|
+
archived: string[];
|
|
24
|
+
messages: string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function teardownFixture(): TeardownFixture {
|
|
28
|
+
const calls: string[] = [];
|
|
29
|
+
const deleted: string[] = [];
|
|
30
|
+
const archived: string[] = [];
|
|
31
|
+
const messages: string[] = [];
|
|
32
|
+
return {
|
|
33
|
+
calls,
|
|
34
|
+
deleted,
|
|
35
|
+
archived,
|
|
36
|
+
messages,
|
|
37
|
+
client: {
|
|
38
|
+
session: {
|
|
39
|
+
update: mock(async ({ path }: { path: { id: string } }) => {
|
|
40
|
+
calls.push("archive");
|
|
41
|
+
archived.push(path.id);
|
|
42
|
+
return {};
|
|
43
|
+
}),
|
|
44
|
+
delete: mock(async ({ path }: { path: { id: string } }) => {
|
|
45
|
+
calls.push("delete");
|
|
46
|
+
deleted.push(path.id);
|
|
47
|
+
return {};
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
afterEach(() => {
|
|
55
|
+
_resetKeepSubagentsForTesting();
|
|
56
|
+
mock.restore();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("teardownChildSession", () => {
|
|
60
|
+
test("deletes an ordinary child only after its prompt settles", async () => {
|
|
61
|
+
const fixture = teardownFixture();
|
|
62
|
+
await teardownChildSession({
|
|
63
|
+
client: fixture.client,
|
|
64
|
+
sessionId: "settled-ordinary",
|
|
65
|
+
sessionDirectory: "/repo",
|
|
66
|
+
promptSettled: true,
|
|
67
|
+
privacySensitive: false,
|
|
68
|
+
context: "ordinary",
|
|
69
|
+
log: (message) => fixture.messages.push(message),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(fixture.deleted).toEqual(["settled-ordinary"]);
|
|
73
|
+
expect(fixture.archived).toEqual([]);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("keeps a settled ordinary child but deletes a settled privacy child under keep_subagents", async () => {
|
|
77
|
+
setKeepSubagents(true);
|
|
78
|
+
const ordinary = teardownFixture();
|
|
79
|
+
await teardownChildSession({
|
|
80
|
+
client: ordinary.client,
|
|
81
|
+
sessionId: "kept-ordinary",
|
|
82
|
+
promptSettled: true,
|
|
83
|
+
privacySensitive: false,
|
|
84
|
+
context: "ordinary",
|
|
85
|
+
log: (message) => ordinary.messages.push(message),
|
|
86
|
+
});
|
|
87
|
+
expect(ordinary.deleted).toEqual([]);
|
|
88
|
+
|
|
89
|
+
const privacy = teardownFixture();
|
|
90
|
+
await teardownChildSession({
|
|
91
|
+
client: privacy.client,
|
|
92
|
+
sessionId: "deleted-private",
|
|
93
|
+
promptSettled: true,
|
|
94
|
+
privacySensitive: true,
|
|
95
|
+
context: "private",
|
|
96
|
+
log: (message) => privacy.messages.push(message),
|
|
97
|
+
});
|
|
98
|
+
expect(privacy.deleted).toEqual(["deleted-private"]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("archives an unsettled child before logging, leaves it intact, then the age gate reaps it", async () => {
|
|
102
|
+
const fixture = teardownFixture();
|
|
103
|
+
const db = new Database(":memory:");
|
|
104
|
+
db.exec(`
|
|
105
|
+
CREATE TABLE session (
|
|
106
|
+
id TEXT PRIMARY KEY,
|
|
107
|
+
title TEXT,
|
|
108
|
+
directory TEXT,
|
|
109
|
+
time_created INTEGER
|
|
110
|
+
);
|
|
111
|
+
INSERT INTO session VALUES (
|
|
112
|
+
'unsettled-private',
|
|
113
|
+
'magic-context-dream-map-memories',
|
|
114
|
+
'/repo',
|
|
115
|
+
1
|
|
116
|
+
);
|
|
117
|
+
`);
|
|
118
|
+
try {
|
|
119
|
+
await teardownChildSession({
|
|
120
|
+
client: fixture.client,
|
|
121
|
+
sessionId: "unsettled-private",
|
|
122
|
+
sessionDirectory: "/repo",
|
|
123
|
+
promptSettled: false,
|
|
124
|
+
privacySensitive: true,
|
|
125
|
+
context: "[dreamer] map-memories",
|
|
126
|
+
log: (message) => {
|
|
127
|
+
fixture.calls.push("log");
|
|
128
|
+
fixture.messages.push(message);
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
expect(fixture.calls).toEqual(["archive", "log"]);
|
|
133
|
+
expect(fixture.deleted).toEqual([]);
|
|
134
|
+
expect(fixture.messages).toEqual([
|
|
135
|
+
"[dreamer] map-memories: prompt unsettled — session unsettled-private left to the age-gated sweep",
|
|
136
|
+
]);
|
|
137
|
+
expect(
|
|
138
|
+
db.prepare("SELECT id FROM session WHERE id = ?").get("unsettled-private"),
|
|
139
|
+
).toEqual({
|
|
140
|
+
id: "unsettled-private",
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const swept = await sweepOrphanedRetrospectiveChildren({
|
|
144
|
+
opencodeDb: db,
|
|
145
|
+
client: fixture.client as never,
|
|
146
|
+
sessionDirectory: "/repo",
|
|
147
|
+
staleMs: 1_000,
|
|
148
|
+
now: 1_002,
|
|
149
|
+
});
|
|
150
|
+
expect(swept).toBe(1);
|
|
151
|
+
expect(fixture.deleted).toEqual(["unsettled-private"]);
|
|
152
|
+
} finally {
|
|
153
|
+
closeQuietly(db);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
function productionTypeScriptFiles(directory: string): string[] {
|
|
159
|
+
const files: string[] = [];
|
|
160
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
161
|
+
const path = join(directory, entry.name);
|
|
162
|
+
if (entry.isDirectory()) files.push(...productionTypeScriptFiles(path));
|
|
163
|
+
else if (entry.name.endsWith(".ts") && !entry.name.endsWith(".test.ts")) files.push(path);
|
|
164
|
+
}
|
|
165
|
+
return files;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function clientSessionDeleteOffsets(path: string, source: string): number[] {
|
|
169
|
+
const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true);
|
|
170
|
+
const offsets: number[] = [];
|
|
171
|
+
const visit = (node: ts.Node): void => {
|
|
172
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
|
|
173
|
+
const deleteAccess = node.expression;
|
|
174
|
+
const sessionAccess = deleteAccess.expression;
|
|
175
|
+
if (
|
|
176
|
+
deleteAccess.name.text === "delete" &&
|
|
177
|
+
ts.isPropertyAccessExpression(sessionAccess) &&
|
|
178
|
+
sessionAccess.name.text === "session" &&
|
|
179
|
+
(ts.isIdentifier(sessionAccess.expression)
|
|
180
|
+
? sessionAccess.expression.text === "client"
|
|
181
|
+
: ts.isPropertyAccessExpression(sessionAccess.expression) &&
|
|
182
|
+
sessionAccess.expression.name.text === "client")
|
|
183
|
+
) {
|
|
184
|
+
offsets.push(node.getStart(sourceFile));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
ts.forEachChild(node, visit);
|
|
188
|
+
};
|
|
189
|
+
visit(sourceFile);
|
|
190
|
+
return offsets;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
describe("child-session delete source fence", () => {
|
|
194
|
+
test("every client.session.delete call is the age-gated sweep or promptSettled-gated teardown", () => {
|
|
195
|
+
const sourceRoot = join(import.meta.dir, "..");
|
|
196
|
+
const sites: string[] = [];
|
|
197
|
+
for (const path of productionTypeScriptFiles(sourceRoot)) {
|
|
198
|
+
const source = readFileSync(path, "utf8");
|
|
199
|
+
for (const offset of clientSessionDeleteOffsets(path, source)) {
|
|
200
|
+
const line = source.slice(0, offset).split("\n").length;
|
|
201
|
+
sites.push(`${relative(sourceRoot, path)}:${line}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Directory walk order differs between macOS and Linux; the fence is a set.
|
|
206
|
+
expect(sites.map((site) => site.replace(/:\d+$/, "")).sort()).toEqual([
|
|
207
|
+
"features/magic-context/dreamer/retrospective-orphan-sweep.ts",
|
|
208
|
+
"shared/child-session-teardown.ts",
|
|
209
|
+
]);
|
|
210
|
+
const teardownSource = readFileSync(
|
|
211
|
+
join(sourceRoot, "shared/child-session-teardown.ts"),
|
|
212
|
+
"utf8",
|
|
213
|
+
);
|
|
214
|
+
expect(teardownSource).toMatch(
|
|
215
|
+
/if\s*\(\s*promptSettled[\s\S]{0,200}client\.session\.delete\s*\(/,
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { shouldKeepSubagents } from "./keep-subagents";
|
|
2
|
+
|
|
3
|
+
interface ChildSessionRequest {
|
|
4
|
+
path: { id: string };
|
|
5
|
+
query?: { directory: string };
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface ArchiveChildSessionRequest extends ChildSessionRequest {
|
|
9
|
+
body: { time: { archived: number } };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ChildSessionTeardownClient {
|
|
13
|
+
session: {
|
|
14
|
+
delete(request: ChildSessionRequest): Promise<unknown>;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface TeardownChildSessionArgs {
|
|
19
|
+
client: ChildSessionTeardownClient;
|
|
20
|
+
sessionId: string | null;
|
|
21
|
+
sessionDirectory?: string;
|
|
22
|
+
promptSettled: boolean;
|
|
23
|
+
privacySensitive: boolean;
|
|
24
|
+
context: string;
|
|
25
|
+
log: (message: string) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Retire a child only after its prompt helper resolves. An unresolved client call
|
|
30
|
+
* can leave OpenCode's server loop writing, so that row is archived for immediate
|
|
31
|
+
* UI hiding and retained until the age-gated sweep can delete it safely.
|
|
32
|
+
*
|
|
33
|
+
* OpenCode's generated v2 SDK models archival as `session.update` with
|
|
34
|
+
* `time.archived`; the plugin's legacy path/body client reaches the same PATCH
|
|
35
|
+
* endpoint, although its generated TypeScript body type does not yet expose time.
|
|
36
|
+
*/
|
|
37
|
+
export async function teardownChildSession(args: TeardownChildSessionArgs): Promise<void> {
|
|
38
|
+
const { client, sessionId, sessionDirectory, promptSettled, privacySensitive, context, log } =
|
|
39
|
+
args;
|
|
40
|
+
if (!sessionId) return;
|
|
41
|
+
|
|
42
|
+
const request: ChildSessionRequest = {
|
|
43
|
+
path: { id: sessionId },
|
|
44
|
+
...(sessionDirectory ? { query: { directory: sessionDirectory } } : {}),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
if (promptSettled && (privacySensitive || !shouldKeepSubagents())) {
|
|
48
|
+
await client.session.delete(request).catch((error: unknown) => {
|
|
49
|
+
log(`${context}: session cleanup failed: ${String(error)}`);
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!promptSettled) {
|
|
55
|
+
const archiveSession = client.session as unknown as {
|
|
56
|
+
update?: (request: ArchiveChildSessionRequest) => Promise<unknown>;
|
|
57
|
+
};
|
|
58
|
+
await archiveSession
|
|
59
|
+
.update?.({
|
|
60
|
+
...request,
|
|
61
|
+
body: { time: { archived: Date.now() } },
|
|
62
|
+
})
|
|
63
|
+
.catch(() => {});
|
|
64
|
+
log(`${context}: prompt unsettled — session ${sessionId} left to the age-gated sweep`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type ConfigParseFailure,
|
|
5
|
+
claimConfigParseFailuresOnce,
|
|
6
|
+
resetClaimedConfigParseFailuresForTesting,
|
|
7
|
+
} from "./config-diagnostics";
|
|
8
|
+
|
|
9
|
+
const failure: ConfigParseFailure = {
|
|
10
|
+
warningClass: "file-parse",
|
|
11
|
+
source: "user",
|
|
12
|
+
path: "/tmp/magic-context.jsonc",
|
|
13
|
+
line: 1,
|
|
14
|
+
column: 1,
|
|
15
|
+
message: "invalid symbol",
|
|
16
|
+
recovered: true,
|
|
17
|
+
warning: "/tmp/magic-context.jsonc:1:1: invalid symbol",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
describe("config parse warning notice claims", () => {
|
|
21
|
+
beforeEach(resetClaimedConfigParseFailuresForTesting);
|
|
22
|
+
|
|
23
|
+
it("emits each parse failure once per harness surface", () => {
|
|
24
|
+
expect(claimConfigParseFailuresOnce("opencode", [failure])).toEqual([failure]);
|
|
25
|
+
expect(claimConfigParseFailuresOnce("opencode", [failure])).toEqual([]);
|
|
26
|
+
expect(claimConfigParseFailuresOnce("pi", [failure])).toEqual([failure]);
|
|
27
|
+
expect(claimConfigParseFailuresOnce("pi", [failure])).toEqual([]);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export const CONFIG_WARNING_CLASS = {
|
|
2
|
+
FILE_PARSE: "file-parse",
|
|
3
|
+
FILE_IO: "file-io",
|
|
4
|
+
INVALID_LEAF: "invalid-leaf",
|
|
5
|
+
} as const;
|
|
6
|
+
|
|
7
|
+
export type ConfigWarningClass = (typeof CONFIG_WARNING_CLASS)[keyof typeof CONFIG_WARNING_CLASS];
|
|
8
|
+
|
|
9
|
+
export interface ConfigParseFailure {
|
|
10
|
+
warningClass: typeof CONFIG_WARNING_CLASS.FILE_PARSE;
|
|
11
|
+
source: "user" | "project";
|
|
12
|
+
path: string;
|
|
13
|
+
line: number;
|
|
14
|
+
column: number;
|
|
15
|
+
message: string;
|
|
16
|
+
recovered: boolean;
|
|
17
|
+
warning: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ConfigWarningDetail {
|
|
21
|
+
warningClass: ConfigWarningClass;
|
|
22
|
+
source?: "user" | "project";
|
|
23
|
+
path?: string;
|
|
24
|
+
line?: number;
|
|
25
|
+
column?: number;
|
|
26
|
+
message: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function formatConfigParseStatusLine(failure: ConfigParseFailure): string {
|
|
30
|
+
const disposition = failure.recovered
|
|
31
|
+
? "recovered values applied; fix the file"
|
|
32
|
+
: "running on defaults";
|
|
33
|
+
return `Config: PARSE FAILED (${failure.path}:${failure.line}:${failure.column}) — ${disposition}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function formatConfigParseNotice(failures: readonly ConfigParseFailure[]): string {
|
|
37
|
+
const lines = failures.map(
|
|
38
|
+
(failure) => `${formatConfigParseStatusLine(failure)}\n${failure.message}`,
|
|
39
|
+
);
|
|
40
|
+
return ["⚠️ Magic Context config parse failure", ...lines].join("\n\n");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const claimedFailures = new Set<string>();
|
|
44
|
+
|
|
45
|
+
function failureKey(surface: string, failure: ConfigParseFailure): string {
|
|
46
|
+
return `${surface}\0${failure.path}\0${failure.line}\0${failure.column}\0${failure.message}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Claim parse-failure notices once for each runtime surface in this process. */
|
|
50
|
+
export function claimConfigParseFailuresOnce(
|
|
51
|
+
surface: "opencode" | "pi",
|
|
52
|
+
failures: readonly ConfigParseFailure[],
|
|
53
|
+
): ConfigParseFailure[] {
|
|
54
|
+
return failures.filter((failure) => {
|
|
55
|
+
const key = failureKey(surface, failure);
|
|
56
|
+
if (claimedFailures.has(key)) return false;
|
|
57
|
+
claimedFailures.add(key);
|
|
58
|
+
return true;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function resetClaimedConfigParseFailuresForTesting(): void {
|
|
63
|
+
claimedFailures.clear();
|
|
64
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ConfigParseFailure } from "./config-diagnostics";
|
|
2
|
+
import { formatConfigParseStatusLine } from "./config-diagnostics";
|
|
3
|
+
|
|
4
|
+
export function buildOpenCodeConfigWarningBanner(
|
|
5
|
+
warnings: readonly string[],
|
|
6
|
+
parseFailures: readonly ConfigParseFailure[],
|
|
7
|
+
allParseFailures: readonly ConfigParseFailure[] = parseFailures,
|
|
8
|
+
): string {
|
|
9
|
+
const parseWarningStrings = new Set(allParseFailures.map((failure) => failure.warning));
|
|
10
|
+
const ordinaryWarnings = warnings.filter(
|
|
11
|
+
(warning) =>
|
|
12
|
+
![...parseWarningStrings].some((parseWarning) => warning.includes(parseWarning)),
|
|
13
|
+
);
|
|
14
|
+
const entries = [
|
|
15
|
+
...parseFailures.map(
|
|
16
|
+
(failure) =>
|
|
17
|
+
`- **TOP SEVERITY:** ${formatConfigParseStatusLine(failure)} — ${failure.message}`,
|
|
18
|
+
),
|
|
19
|
+
...ordinaryWarnings.map((warning) => `- ${warning}`),
|
|
20
|
+
];
|
|
21
|
+
return [
|
|
22
|
+
"## ⚠️ Magic Context Config Warning",
|
|
23
|
+
"",
|
|
24
|
+
...entries,
|
|
25
|
+
"",
|
|
26
|
+
"Fix the reported `magic-context.jsonc` file; Magic Context remains enabled.",
|
|
27
|
+
].join("\n");
|
|
28
|
+
}
|
package/src/shared/data-path.ts
CHANGED
|
@@ -13,16 +13,17 @@ export function getDataDir(): string {
|
|
|
13
13
|
* Layout:
|
|
14
14
|
* - OpenCode: `${os.tmpdir()}/opencode/magic-context/`
|
|
15
15
|
* - Pi: `${os.tmpdir()}/pi/magic-context/`
|
|
16
|
+
* - OMP: `${os.tmpdir()}/omp/magic-context/`
|
|
16
17
|
*
|
|
17
18
|
* Why a per-harness subtree of `os.tmpdir()`:
|
|
18
19
|
* 1. OpenCode Desktop runs as an Electron app with a permission sandbox.
|
|
19
20
|
* Writing to arbitrary tmp paths can trigger user-visible permission
|
|
20
21
|
* prompts; the `${tmpdir}/opencode/` subtree is allow-listed by
|
|
21
22
|
* OpenCode, so anything we put under it never asks for permission.
|
|
22
|
-
* 2. Splitting
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* 2. Splitting harnesses keeps their logs and historian dump directories
|
|
24
|
+
* cleanly separated. `doctor --issue` for each harness reports diagnostics
|
|
25
|
+
* from the matching subtree, so issue reports do not include another
|
|
26
|
+
* harness's log noise.
|
|
26
27
|
* 3. Pi has no permission sandbox, so the path choice is purely
|
|
27
28
|
* cosmetic for Pi — it just keeps the layout symmetric.
|
|
28
29
|
*
|
|
@@ -37,13 +38,13 @@ export function getMagicContextTempDir(harness: HarnessId = getHarness()): strin
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
|
-
* Standard log file path the plugin writes to.
|
|
41
|
-
*
|
|
42
|
-
*
|
|
41
|
+
* Standard log file path the plugin writes to. Each harness writes to a
|
|
42
|
+
* separate log under its own subtree so a machine running multiple harnesses
|
|
43
|
+
* does not interleave session traces.
|
|
43
44
|
*
|
|
44
45
|
* The plugin's buffered logger calls this on every flush rather than
|
|
45
|
-
* caching, so `setHarness(
|
|
46
|
-
*
|
|
46
|
+
* caching, so the boot-time `setHarness()` call is reflected in the next
|
|
47
|
+
* flush.
|
|
47
48
|
*/
|
|
48
49
|
export function getMagicContextLogPath(harness: HarnessId = getHarness()): string {
|
|
49
50
|
// An explicit override wins over the harness temp-dir default, so users on
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
2
|
import {
|
|
3
|
+
canonicalModelIdentity,
|
|
3
4
|
modelRefLookupOrder,
|
|
4
5
|
ompModelRefToCanonical,
|
|
5
6
|
piModelRefToCanonical,
|
|
@@ -8,6 +9,21 @@ import {
|
|
|
8
9
|
} from "./harness-provider-map";
|
|
9
10
|
|
|
10
11
|
describe("harness-provider-map", () => {
|
|
12
|
+
describe("canonicalModelIdentity", () => {
|
|
13
|
+
it("collapses Astra route aliases without changing unrelated Copilot models", () => {
|
|
14
|
+
for (const ref of [
|
|
15
|
+
"openai/gpt-6-astra",
|
|
16
|
+
"openai-codex/gpt-6-astra",
|
|
17
|
+
"github-copilot/gpt-6-astra",
|
|
18
|
+
]) {
|
|
19
|
+
expect(canonicalModelIdentity(ref)).toBe("openai/gpt-6-astra");
|
|
20
|
+
}
|
|
21
|
+
expect(canonicalModelIdentity("github-copilot/claude-opus-5")).toBe(
|
|
22
|
+
"github-copilot/claude-opus-5",
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
11
27
|
describe("resolveModelRefForPi (canonical -> Pi, used when spawning)", () => {
|
|
12
28
|
it("maps the diverging auth-plugin providers, preserving the model id", () => {
|
|
13
29
|
expect(resolveModelRefForPi("openai/gpt-5.5")).toBe("openai-codex/gpt-5.5");
|
|
@@ -58,6 +58,10 @@ const OMP_TO_CANONICAL_PROVIDER: Readonly<Record<string, string>> = {
|
|
|
58
58
|
"opencode-zen": "opencode",
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
+
const CANONICAL_MODEL_IDENTITY_ALIASES: Readonly<Record<string, string>> = {
|
|
62
|
+
"github-copilot/gpt-6-astra": "openai/gpt-6-astra",
|
|
63
|
+
};
|
|
64
|
+
|
|
61
65
|
/** Remap only the provider prefix (text before the first "/"), preserving the
|
|
62
66
|
* model id verbatim. No "/", empty provider, or unmapped provider -> unchanged.
|
|
63
67
|
* Lookups are own-property only, so provider ids that collide with
|
|
@@ -72,6 +76,17 @@ function remapProviderPrefix(ref: string, map: Readonly<Record<string, string>>)
|
|
|
72
76
|
return `${map[provider]}${ref.slice(slash)}`;
|
|
73
77
|
}
|
|
74
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Canonicalize only for identity comparisons and cache policy; callers must not
|
|
81
|
+
* use the result as a provider spawn route. Provider-wide Pi/OMP aliases are
|
|
82
|
+
* normalized first; model-specific aliases stay explicit because GitHub Copilot
|
|
83
|
+
* also serves non-OpenAI model families.
|
|
84
|
+
*/
|
|
85
|
+
export function canonicalModelIdentity(ref: string): string {
|
|
86
|
+
const harnessCanonical = piModelRefToCanonical(ompModelRefToCanonical(ref));
|
|
87
|
+
return CANONICAL_MODEL_IDENTITY_ALIASES[harnessCanonical.toLowerCase()] ?? harnessCanonical;
|
|
88
|
+
}
|
|
89
|
+
|
|
75
90
|
/** Pi-native `provider/model` -> canonical (OpenCode). Identity when unmapped.
|
|
76
91
|
* Used by the Pi setup wizard so configs it writes stay OpenCode-readable. */
|
|
77
92
|
export function piModelRefToCanonical(ref: string): string {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import { parseJsonc } from "./jsonc-parser";
|
|
3
|
+
import { parseJsonc, parseJsoncRecovering } from "./jsonc-parser";
|
|
4
4
|
|
|
5
5
|
describe("parseJsonc prototype-pollution hardening", () => {
|
|
6
6
|
it("rejects dangerous keys recursively, including inside arrays", () => {
|
|
@@ -30,4 +30,17 @@ describe("parseJsonc prototype-pollution hardening", () => {
|
|
|
30
30
|
expect(Object.getPrototypeOf(items[0])).toBe(Object.prototype);
|
|
31
31
|
expect("polluted" in items[0]).toBe(false);
|
|
32
32
|
});
|
|
33
|
+
|
|
34
|
+
it("preserves hardening when tolerant recovery encounters __proto__", () => {
|
|
35
|
+
const rejected: string[] = [];
|
|
36
|
+
const parsed = parseJsoncRecovering<Record<string, unknown>>(
|
|
37
|
+
'\\{\n"__proto__":{"polluted":true},"cache_ttl":"1h"}',
|
|
38
|
+
{ onRejectedKey: (path) => rejected.push(path.join(".")) },
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
expect(parsed.value).toEqual({ cache_ttl: "1h" });
|
|
42
|
+
expect(parsed.issues[0]).toMatchObject({ line: 1, column: 1 });
|
|
43
|
+
expect(rejected).toContain("__proto__");
|
|
44
|
+
expect(({} as { polluted?: boolean }).polluted).toBeUndefined();
|
|
45
|
+
});
|
|
33
46
|
});
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
type ParseError,
|
|
5
|
+
parse as parseJsoncDocument,
|
|
6
|
+
printParseErrorCode,
|
|
7
|
+
} from "jsonc-parser/lib/esm/main.js";
|
|
8
|
+
// ^ Deep ESM import on purpose, same as jsonc-edit.ts: the package's "main" is a
|
|
9
|
+
// UMD bundle whose runtime-relative requires (`./impl/format`) survive bundling
|
|
10
|
+
// verbatim and crash the plugin at boot. The build:dists load-probe gate exists
|
|
11
|
+
// to catch exactly this; do not import the bare package name.
|
|
12
|
+
|
|
3
13
|
export function stripJsonComments(content: string): string {
|
|
4
14
|
let result = "";
|
|
5
15
|
let inString = false;
|
|
@@ -155,6 +165,89 @@ export function sanitizeParsedJson<T>(
|
|
|
155
165
|
return sanitized as T;
|
|
156
166
|
}
|
|
157
167
|
|
|
168
|
+
export interface JsoncParseIssue {
|
|
169
|
+
line: number;
|
|
170
|
+
column: number;
|
|
171
|
+
offset: number;
|
|
172
|
+
length: number;
|
|
173
|
+
message: string;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface RecoveringJsoncParseResult<T> {
|
|
177
|
+
value: T;
|
|
178
|
+
issues: JsoncParseIssue[];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function lineAndColumnAt(content: string, offset: number): { line: number; column: number } {
|
|
182
|
+
const before = content.slice(0, Math.max(0, offset));
|
|
183
|
+
const lines = before.split(/\r?\n/);
|
|
184
|
+
return { line: lines.length, column: (lines.at(-1)?.length ?? 0) + 1 };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function parseIssue(content: string, error: ParseError): JsoncParseIssue {
|
|
188
|
+
const location = lineAndColumnAt(content, error.offset);
|
|
189
|
+
const code = printParseErrorCode(error.error);
|
|
190
|
+
const message = code.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
|
|
191
|
+
return {
|
|
192
|
+
...location,
|
|
193
|
+
offset: error.offset,
|
|
194
|
+
length: error.length,
|
|
195
|
+
message,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Parse JSONC with the same recovery grammar used by the runtime config loaders.
|
|
201
|
+
* Syntax diagnostics are never discarded: callers must surface every non-empty
|
|
202
|
+
* `issues` result even when the parser recovered a usable object.
|
|
203
|
+
*/
|
|
204
|
+
function normalizeJsoncParserObjects(
|
|
205
|
+
value: unknown,
|
|
206
|
+
options: ParsedJsonSanitizerOptions,
|
|
207
|
+
path: string[] = [],
|
|
208
|
+
): unknown {
|
|
209
|
+
if (Array.isArray(value)) {
|
|
210
|
+
return value.map((entry, index) =>
|
|
211
|
+
normalizeJsoncParserObjects(entry, options, [...path, String(index)]),
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
if (value === null || typeof value !== "object") return value;
|
|
215
|
+
|
|
216
|
+
const prototype = Object.getPrototypeOf(value);
|
|
217
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
218
|
+
// jsonc-parser assigns an own "__proto__" property through normal JS
|
|
219
|
+
// assignment, which changes only this parsed object's prototype. Treat
|
|
220
|
+
// that prototype as the rejected key and copy only its own safe fields.
|
|
221
|
+
options.onRejectedKey?.([...path, "__proto__"]);
|
|
222
|
+
}
|
|
223
|
+
const normalized: Record<string, unknown> = {};
|
|
224
|
+
for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {
|
|
225
|
+
Object.defineProperty(normalized, key, {
|
|
226
|
+
configurable: true,
|
|
227
|
+
enumerable: true,
|
|
228
|
+
writable: true,
|
|
229
|
+
value: normalizeJsoncParserObjects(entry, options, [...path, key]),
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
return normalized;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function parseJsoncRecovering<T = unknown>(
|
|
236
|
+
content: string,
|
|
237
|
+
options: ParsedJsonSanitizerOptions = {},
|
|
238
|
+
): RecoveringJsoncParseResult<T> {
|
|
239
|
+
const errors: ParseError[] = [];
|
|
240
|
+
const parsed = parseJsoncDocument(content, errors, {
|
|
241
|
+
allowTrailingComma: true,
|
|
242
|
+
disallowComments: false,
|
|
243
|
+
allowEmptyContent: false,
|
|
244
|
+
}) as T;
|
|
245
|
+
return {
|
|
246
|
+
value: sanitizeParsedJson(normalizeJsoncParserObjects(parsed, options) as T, options),
|
|
247
|
+
issues: errors.map((error) => parseIssue(content, error)),
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
158
251
|
export function parseJsonc<T = unknown>(
|
|
159
252
|
content: string,
|
|
160
253
|
options: ParsedJsonSanitizerOptions = {},
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Debug / data-collection switch
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Debug / data-collection switch for settled ordinary child sessions
|
|
3
|
+
* (historian and memory migration). Privacy-sensitive Dreamer and
|
|
4
|
+
* smart-note children are still deleted after their prompts settle.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* inspectable in OpenCode's session store / the dashboard. Intended for
|
|
10
|
-
* short-term data collection (e.g. profiling what the dreamer actually does)
|
|
11
|
-
* before the dreamer v2 overhaul, NOT for steady-state use — kept sessions
|
|
12
|
-
* accumulate in the host's session DB until manually cleared.
|
|
6
|
+
* Unsettled children are never deleted inline because OpenCode's server loop may
|
|
7
|
+
* still be writing after a client timeout or abort. They remain for the
|
|
8
|
+
* age-gated sweep; privacy-sensitive rows are swept even when this switch is on.
|
|
13
9
|
*
|
|
14
|
-
* Process-global, set once at boot from config (mirrors `harness.ts`). A
|
|
15
|
-
*
|
|
16
|
-
* per-call args — it's a coarse, boot-time debug toggle.
|
|
10
|
+
* Process-global, set once at boot from config (mirrors `harness.ts`). A config
|
|
11
|
+
* change requires a restart to take effect.
|
|
17
12
|
*/
|
|
18
13
|
let keepSubagents = false;
|
|
19
14
|
|
|
@@ -22,7 +17,7 @@ export function setKeepSubagents(value: boolean): void {
|
|
|
22
17
|
keepSubagents = value === true;
|
|
23
18
|
}
|
|
24
19
|
|
|
25
|
-
/** True when
|
|
20
|
+
/** True when settled ordinary child sessions should be retained. */
|
|
26
21
|
export function shouldKeepSubagents(): boolean {
|
|
27
22
|
return keepSubagents;
|
|
28
23
|
}
|