@cortexkit/opencode-magic-context 0.45.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -0
- package/dist/{announcement-f75t58v9.js → announcement-y35wzg2r.js} +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/live-run-config.d.ts.map +1 -1
- package/dist/config/migrate-config-location.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +10 -4
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/{conflict-warning-hook-5yrz2r24.js → conflict-warning-hook-7fj2b9jw.js} +6 -5
- package/dist/context-8dkpszy5.js +4483 -0
- package/dist/{derive-budgets-a63zsm5c.js → derive-budgets-7nj7r1rv.js} +2 -2
- package/dist/embedding-worker.js +4 -4
- package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts +45 -0
- package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts.map +1 -0
- package/dist/features/magic-context/checkout-claim.d.ts +155 -0
- package/dist/features/magic-context/checkout-claim.d.ts.map +1 -0
- package/dist/features/magic-context/compaction-marker.d.ts +20 -3
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-storage.d.ts +23 -2
- package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/provider-output-failure.d.ts +6 -2
- package/dist/features/magic-context/dreamer/provider-output-failure.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/provider-output-failure.test-support.d.ts +30 -0
- package/dist/features/magic-context/dreamer/provider-output-failure.test-support.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-executor.d.ts +9 -0
- package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify-diff.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify-gate.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/search-git-commits.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/project-identity-cache.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-verifications.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory.d.ts +3 -0
- package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
- package/dist/features/magic-context/memory/verification-paths.d.ts +2 -2
- package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -1
- package/dist/features/magic-context/merged-reasoning-decisions.d.ts.map +1 -1
- package/dist/features/magic-context/message-index-async.d.ts +3 -3
- package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
- package/dist/features/magic-context/message-index.d.ts +2 -0
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/migration-v95-perf-indexes.d.ts +12 -0
- package/dist/features/magic-context/migration-v95-perf-indexes.d.ts.map +1 -0
- package/dist/features/magic-context/migration-worker-client.d.ts +4 -4
- package/dist/features/magic-context/migration-worker-client.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts +1 -0
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/mural/render-trigger.d.ts.map +1 -1
- package/dist/features/magic-context/mural/resolve-mural.d.ts +15 -4
- package/dist/features/magic-context/mural/resolve-mural.d.ts.map +1 -1
- package/dist/features/magic-context/mural/source-revision.d.ts +7 -0
- package/dist/features/magic-context/mural/source-revision.d.ts.map +1 -0
- package/dist/features/magic-context/mural/storage-mural-cues.d.ts.map +1 -1
- package/dist/features/magic-context/reclaim-protection.d.ts +15 -10
- package/dist/features/magic-context/reclaim-protection.d.ts.map +1 -1
- package/dist/features/magic-context/session-cache-ttl.d.ts +4 -2
- package/dist/features/magic-context/session-cache-ttl.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/capabilities.d.ts +3 -0
- package/dist/features/magic-context/smart-notes/capabilities.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/github-token.d.ts +5 -0
- package/dist/features/magic-context/smart-notes/github-token.d.ts.map +1 -0
- package/dist/features/magic-context/smart-notes/runner.d.ts +1 -0
- package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts +12 -0
- package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts +6 -0
- package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/storage.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/types.d.ts +2 -0
- package/dist/features/magic-context/smart-notes/types.d.ts.map +1 -1
- package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts +6 -9
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
- package/dist/features/magic-context/storage-ops.d.ts +8 -1
- package/dist/features/magic-context/storage-ops.d.ts.map +1 -1
- package/dist/features/magic-context/storage-replay-document.d.ts +7 -0
- package/dist/features/magic-context/storage-replay-document.d.ts.map +1 -1
- package/dist/features/magic-context/storage-schema-helpers.d.ts +2 -0
- package/dist/features/magic-context/storage-schema-helpers.d.ts.map +1 -1
- package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
- package/dist/features/magic-context/storage-source.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts +11 -3
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +2 -2
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/temporal-decisions.d.ts +10 -0
- package/dist/features/magic-context/temporal-decisions.d.ts.map +1 -0
- package/dist/features/magic-context/tool-definition-tokens.d.ts +2 -0
- package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
- package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
- package/dist/features/magic-context/types.d.ts +7 -6
- package/dist/features/magic-context/types.d.ts.map +1 -1
- package/dist/features/magic-context/window-report-ledger.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
- package/dist/hooks/magic-context/apply-operations.d.ts +8 -0
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts +6 -3
- package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
- package/dist/hooks/magic-context/channel2-cycle.d.ts +2 -0
- package/dist/hooks/magic-context/channel2-cycle.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts +7 -0
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-prompt.d.ts +2 -2
- package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-render-epoch.d.ts +8 -0
- package/dist/hooks/magic-context/compartment-render-epoch.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts +18 -4
- package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +12 -0
- package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
- package/dist/hooks/magic-context/decision-calibration.d.ts +3 -0
- package/dist/hooks/magic-context/decision-calibration.d.ts.map +1 -1
- package/dist/hooks/magic-context/default-protection-pressure.test-support.d.ts +37 -0
- package/dist/hooks/magic-context/default-protection-pressure.test-support.d.ts.map +1 -0
- package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts +4 -0
- package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts.map +1 -1
- package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -1
- package/dist/hooks/magic-context/emergency-drop.d.ts +2 -0
- package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
- package/dist/hooks/magic-context/emergency-fail-closed.d.ts +21 -1
- package/dist/hooks/magic-context/emergency-fail-closed.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts +5 -0
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +30 -1
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts +2 -0
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/historian-prompt-fit.d.ts +4 -2
- package/dist/hooks/magic-context/historian-prompt-fit.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +2 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +9 -10
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-measured-request.d.ts +69 -0
- package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -0
- package/dist/hooks/magic-context/lkg-persist.d.ts +2 -0
- package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-replay-fit.d.ts +14 -0
- package/dist/hooks/magic-context/lkg-replay-fit.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-replay.d.ts +10 -1
- package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-slot.d.ts +4 -0
- package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-state-sync.d.ts +2 -0
- package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
- package/dist/hooks/magic-context/note-nudger.d.ts +17 -5
- package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-chunk.d.ts +1 -1
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-db.d.ts +1 -0
- package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-formatting.d.ts +7 -0
- package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-raw.d.ts +4 -0
- package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
- package/dist/hooks/magic-context/recomp-orchestrator.d.ts +2 -0
- package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
- package/dist/hooks/magic-context/reference-retrieval.d.ts +27 -17
- package/dist/hooks/magic-context/reference-retrieval.d.ts.map +1 -1
- package/dist/hooks/magic-context/request-hook-order.d.ts +56 -0
- package/dist/hooks/magic-context/request-hook-order.d.ts.map +1 -0
- package/dist/hooks/magic-context/rust-mode-transform.d.ts +22 -3
- package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts +4 -2
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/supersession-reclaim.d.ts +4 -0
- package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts +7 -0
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +12 -3
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
- package/dist/hooks/magic-context/temporal-awareness.d.ts +6 -3
- package/dist/hooks/magic-context/temporal-awareness.d.ts.map +1 -1
- package/dist/hooks/magic-context/temporal-served-projection.d.ts +4 -0
- package/dist/hooks/magic-context/temporal-served-projection.d.ts.map +1 -0
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-reclaim.d.ts +2 -0
- package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-message-helpers.d.ts +5 -0
- package/dist/hooks/magic-context/transform-message-helpers.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +41 -17
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +12 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
- package/dist/{index-vvtfyw1z.js → index-0d3g3461.js} +5 -13
- package/dist/index-1bc61ans.js +154 -0
- package/dist/{index-n96ag4rk.js → index-1zx87sdm.js} +5 -1
- package/dist/{index-4krbw8z9.js → index-3h0ybwah.js} +608 -102
- package/dist/{index-gd5qx1j9.js → index-5eqk6z3s.js} +62 -1
- package/dist/index-5gq3b2ya.js +494 -0
- package/dist/{index-75zjgwga.js → index-7qw742ev.js} +1 -1
- package/dist/{index-f85teqck.js → index-8da2zjhz.js} +3 -256
- package/dist/{index-w9jwmntv.js → index-b35pxds2.js} +9 -1
- package/dist/{index-8fgkmxmy.js → index-e2dtv0ra.js} +4 -3
- package/dist/{v2/server-a4m2b1yv.js → index-fg34g6a5.js} +55 -1
- package/dist/{index-xgt9k6c6.js → index-j7fvnjye.js} +2 -1
- package/dist/{index-2aq21j41.js → index-k4404na5.js} +418 -127
- package/dist/{index-2ntg5sd4.js → index-k5bdx1bx.js} +9 -5
- package/dist/{index-bmzf7zxv.js → index-majxda46.js} +23 -5
- package/dist/{index-16ny736w.js → index-p821bjdb.js} +14406 -13726
- package/dist/{index-remp7e2g.js → index-q4yp4b52.js} +16 -1
- package/dist/index-qr6r7akd.js +28505 -0
- package/dist/{index-fr2z4qy8.js → index-r5hmbx3t.js} +132 -169
- package/dist/index-sfnj6h8h.js +259 -0
- package/dist/index-sj29b3z2.js +30 -0
- package/dist/{index-q7yesyk9.js → index-yasgb8ej.js} +23 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1983 -33118
- package/dist/{message-time-backfill-an311pmk.js → message-time-backfill-68gj6t3e.js} +2 -2
- package/dist/migration-worker.js +12 -7
- package/dist/plugin/dream-timer.d.ts +25 -1
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +2 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/messages-transform.d.ts +13 -0
- package/dist/plugin/messages-transform.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts +4 -0
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/plugin/subagent-tool-policy.d.ts +14 -0
- package/dist/plugin/subagent-tool-policy.d.ts.map +1 -0
- package/dist/plugin/tool-registry.d.ts +1 -0
- package/dist/plugin/tool-registry.d.ts.map +1 -1
- package/dist/{read-session-chunk-8rxs0tc9.js → read-session-chunk-egz7r68d.js} +8 -8
- package/dist/{recomp-orchestrator-nzamtw29.js → recomp-orchestrator-ejq7ex5d.js} +15 -15
- package/dist/{send-session-notification-nqpv7cne.js → send-session-notification-dyw42dtr.js} +4 -4
- package/dist/shared/announcement.d.ts.map +1 -1
- package/dist/shared/cache-ttl-display.d.ts +6 -4
- package/dist/shared/cache-ttl-display.d.ts.map +1 -1
- package/dist/shared/model-cache-ttl.d.ts +1 -1
- package/dist/shared/model-cache-ttl.d.ts.map +1 -1
- package/dist/shared/model-suggestion-retry.d.ts +2 -0
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/models-dev-cache.d.ts.map +1 -1
- package/dist/shared/protected-tools-policy.d.ts +6 -0
- package/dist/shared/protected-tools-policy.d.ts.map +1 -0
- package/dist/shared/quota-diagnostic.d.ts +4 -0
- package/dist/shared/quota-diagnostic.d.ts.map +1 -0
- package/dist/shared/rpc-server.d.ts.map +1 -1
- package/dist/shared/sqlite-context-pragmas.d.ts +12 -0
- package/dist/shared/sqlite-context-pragmas.d.ts.map +1 -0
- package/dist/shared/sqlite-helpers.d.ts +9 -0
- package/dist/shared/sqlite-helpers.d.ts.map +1 -1
- package/dist/shared/sqlite.d.ts +10 -0
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/shared/status-summary.d.ts +1 -0
- package/dist/shared/status-summary.d.ts.map +1 -1
- package/dist/shared/status-view-check.d.ts.map +1 -1
- package/dist/shared/status-view.d.ts +4 -0
- package/dist/shared/status-view.d.ts.map +1 -1
- package/dist/shared/storage-permissions.d.ts +24 -0
- package/dist/shared/storage-permissions.d.ts.map +1 -1
- package/dist/shared/temporal-upgrade-fixture.d.ts +19 -0
- package/dist/shared/temporal-upgrade-fixture.d.ts.map +1 -0
- package/dist/shared/user-facing-codes.d.ts +5 -0
- package/dist/shared/user-facing-codes.d.ts.map +1 -1
- package/dist/shared/write-transaction-timing.d.ts +8 -1
- package/dist/shared/write-transaction-timing.d.ts.map +1 -1
- package/dist/tools/ctx-expand/render.d.ts.map +1 -1
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- package/dist/tools/ctx-reduce/constants.d.ts +2 -0
- package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
- package/dist/tools/ctx-reduce/tools.d.ts +4 -4
- package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
- package/dist/{transform-postprocess-phase-414phndq.js → transform-postprocess-phase-tz3pat2p.js} +15 -15
- package/dist/v2/context-8vgtb6sz.js +52166 -0
- package/dist/v2/{derive-budgets-v0krf3t7.js → derive-budgets-kdgp4s3r.js} +4 -3
- package/dist/v2/embedding-worker.js +6 -5
- package/dist/v2/fold/boundary.d.ts +2 -0
- package/dist/v2/fold/boundary.d.ts.map +1 -1
- package/dist/v2/fold/owner.d.ts.map +1 -1
- package/dist/v2/hooks/channel2.d.ts +2 -0
- package/dist/v2/hooks/channel2.d.ts.map +1 -1
- package/dist/v2/hooks/context.d.ts +2 -2
- package/dist/v2/hooks/context.d.ts.map +1 -1
- package/dist/v2/hooks/dream-timer.d.ts +39 -0
- package/dist/v2/hooks/dream-timer.d.ts.map +1 -0
- package/dist/v2/hooks/payload.d.ts.map +1 -1
- package/dist/v2/hooks/store.d.ts.map +1 -1
- package/dist/v2/hooks/tools.d.ts +1 -1
- package/dist/v2/hooks/tools.d.ts.map +1 -1
- package/dist/v2/hooks/update-check.d.ts.map +1 -1
- package/dist/v2/{message-time-backfill-0n93vrd7.js → message-time-backfill-r6qkem1x.js} +3 -3
- package/dist/v2/migration-worker.js +13 -8
- package/dist/v2/{read-session-chunk-hjza38hr.js → read-session-chunk-8vjp6581.js} +9 -9
- package/dist/v2/recomp-orchestrator-5xj0yzyk.js +39 -0
- package/dist/v2/{safe-notification-target-wtj0bbc2.js → safe-notification-target-eb1n1vfb.js} +2 -2
- package/dist/v2/{send-session-notification-mq9frrtm.js → send-session-notification-qs0j78v6.js} +6 -6
- package/dist/v2/server-14vq4kpm.js +30 -0
- package/dist/v2/server-1bc61ans.js +154 -0
- package/dist/v2/{server-n96ag4rk.js → server-1zx87sdm.js} +5 -1
- package/dist/v2/server-3n4q9xme.js +79 -0
- package/dist/v2/server-4663ejam.js +3351 -0
- package/dist/v2/{server-rhdgxp1t.js → server-51dv1pr5.js} +63 -2
- package/dist/v2/{server-5317ykaf.js → server-6r257mf5.js} +1 -1
- package/dist/v2/server-84w6rvvf.js +14 -0
- package/dist/v2/{server-qpg6wf72.js → server-ajzeteqw.js} +9 -1
- package/dist/{index-a4m2b1yv.js → v2/server-fg34g6a5.js} +55 -1
- package/dist/v2/{server-e36nf2p1.js → server-frbm99q5.js} +1595 -1599
- package/dist/v2/{server-remp7e2g.js → server-g0fjrkta.js} +16 -1
- package/dist/v2/{server-z19x7eqz.js → server-mcfawjgc.js} +4 -4
- package/dist/v2/server-p2en78c8.js +3892 -0
- package/dist/v2/{server-hfjfbg59.js → server-qp5hx1ad.js} +608 -105
- package/dist/v2/{server-c4g2y1z8.js → server-vnh7r35f.js} +2778 -5383
- package/dist/v2/server-vs5gpnd4.js +493 -0
- package/dist/v2/{server-w99cyt6a.js → server-wvjvfhck.js} +14 -6
- package/dist/v2/{server-v5xgft5v.js → server-xtp687da.js} +186 -3533
- package/dist/v2/{server-0jqw05sa.js → server-y8maxeft.js} +6 -84
- package/dist/v2/server.d.ts.map +1 -1
- package/dist/v2/server.js +104 -49288
- package/dist/v2/store-reader.d.ts +39 -1
- package/dist/v2/store-reader.d.ts.map +1 -1
- package/dist/v2/tool-result.d.ts +8 -0
- package/dist/v2/tool-result.d.ts.map +1 -0
- package/dist/v2/tui/index.d.ts.map +1 -1
- package/dist/v2/{wrapup-orchestrator-tbyx78dz.js → wrapup-orchestrator-r5t1pyj8.js} +20 -16
- package/dist/wrapup-orchestrator-kw3x3myw.js +26 -0
- package/package.json +22 -7
- package/src/config/index.ts +21 -4
- package/src/config/latch-permanence-guard.test.ts +6 -1
- package/src/config/live-run-config.ts +1 -0
- package/src/config/migrate-config-location.test.ts +31 -1
- package/src/config/migrate-config-location.ts +8 -41
- package/src/config/protected-tools.test.ts +70 -0
- package/src/config/raw-loader.test.ts +15 -0
- package/src/config/raw-loader.ts +1 -1
- package/src/config/removed-agent-source-fence.test.ts +10 -1
- package/src/config/schema/magic-context.test.ts +20 -1
- package/src/config/schema/magic-context.ts +21 -7
- package/src/shared/announcement.ts +6 -5
- package/src/shared/cache-ttl-display.test.ts +1 -1
- package/src/shared/cache-ttl-display.ts +17 -16
- package/src/shared/fold-render-lock-fence.test.ts +84 -0
- package/src/shared/fold-render-lock-fixtures.test.ts +276 -0
- package/src/shared/model-cache-ttl.test.ts +2 -2
- package/src/shared/model-cache-ttl.ts +8 -4
- package/src/shared/model-suggestion-retry.test.ts +104 -1
- package/src/shared/model-suggestion-retry.ts +63 -6
- package/src/shared/models-dev-cache.ts +3 -11
- package/src/shared/protected-tools-policy.ts +23 -0
- package/src/shared/quota-diagnostic.ts +9 -0
- package/src/shared/rpc-server.ts +6 -54
- package/src/shared/sqlite-context-pragmas.test.ts +105 -0
- package/src/shared/sqlite-context-pragmas.ts +24 -0
- package/src/shared/sqlite-helpers.ts +17 -0
- package/src/shared/sqlite.ts +75 -0
- package/src/shared/status-detail-text.test.ts +18 -1
- package/src/shared/status-summary.ts +11 -0
- package/src/shared/status-view-check.ts +5 -0
- package/src/shared/status-view.test.ts +11 -2
- package/src/shared/status-view.ts +12 -1
- package/src/shared/storage-permissions.test.ts +204 -0
- package/src/shared/storage-permissions.ts +192 -0
- package/src/shared/temporal-upgrade-fixture.ts +50 -0
- package/src/shared/user-facing-codes.ts +6 -0
- package/src/shared/write-transaction-timing.test.ts +39 -0
- package/src/shared/write-transaction-timing.ts +25 -1
- package/src/tui/dialogs/status-dialog-render.test.ts +1 -1
- package/src/tui/index.tsx +3 -1
- package/src/tui/startup-order.test.ts +16 -0
- package/src/tui-compiled/index.tsx +3 -1
- package/src/v2/tui/index.ts +9 -2
- package/dist/index-anq4nn6f.js +0 -131
- package/dist/index-e44zzy84.js +0 -10
- package/dist/index-x23gah8c.js +0 -16
- package/dist/v2/recomp-orchestrator-1aq7h44c.js +0 -36
- package/dist/v2/server-e44zzy84.js +0 -10
- package/dist/v2/server-fgmxwrgy.js +0 -16
- package/dist/v2/server-r7cmye3k.js +0 -131
- package/dist/wrapup-orchestrator-h28bqsy6.js +0 -26
- package/dist/v2/{server-ckpc8pxy.js → server-1qbnzc80.js} +8 -8
|
@@ -0,0 +1,3892 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE,
|
|
3
|
+
PROTECTED_TOKENS_MIN,
|
|
4
|
+
PER_HARNESS_MIGRATION_INVENTORY,
|
|
5
|
+
PER_HARNESS_MODEL_KEYS,
|
|
6
|
+
ConfigProfilesSchema,
|
|
7
|
+
MagicContextConfigSchema
|
|
8
|
+
} from "./server-xtp687da.js";
|
|
9
|
+
import {
|
|
10
|
+
log
|
|
11
|
+
} from "./server-1qbnzc80.js";
|
|
12
|
+
import {
|
|
13
|
+
setWindowOverlayPath,
|
|
14
|
+
setOutputReserveConfig
|
|
15
|
+
} from "./server-y8maxeft.js";
|
|
16
|
+
|
|
17
|
+
// src/config/agent-disable.ts
|
|
18
|
+
var COMPACTION_ENABLED_PATH = `compaction${"."}enabled`;
|
|
19
|
+
function isDreamerRunnable(config) {
|
|
20
|
+
return !!config.dreamer && config.dreamer.disable !== true;
|
|
21
|
+
}
|
|
22
|
+
function isCompactionEnabled(config) {
|
|
23
|
+
return config.compaction?.enabled !== false;
|
|
24
|
+
}
|
|
25
|
+
function clonePlainObject(value) {
|
|
26
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
return { ...value };
|
|
30
|
+
}
|
|
31
|
+
function migrateLegacyEnabledForAgent(args) {
|
|
32
|
+
const agent = clonePlainObject(args.patched[args.agentName]);
|
|
33
|
+
if (!agent || !("enabled" in agent))
|
|
34
|
+
return;
|
|
35
|
+
const enabled = agent.enabled;
|
|
36
|
+
const disable = agent.disable;
|
|
37
|
+
delete agent.enabled;
|
|
38
|
+
if (args.agentName === "historian") {
|
|
39
|
+
args.warnings.push('Removed invalid "historian.enabled" in-memory (run doctor to persist).');
|
|
40
|
+
args.patched.historian = agent;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (disable !== true && enabled === false) {
|
|
44
|
+
agent.disable = true;
|
|
45
|
+
args.warnings.push('Migrated "dreamer.enabled=false" → "dreamer.disable=true" in-memory (run doctor to persist). This now also disables manual /ctx-dream; for manual-only remove disable and set schedule="".');
|
|
46
|
+
}
|
|
47
|
+
args.patched.dreamer = agent;
|
|
48
|
+
}
|
|
49
|
+
function migrateLegacyAgentEnabledInMemory(rawConfig, warnings) {
|
|
50
|
+
const shouldPatch = ["dreamer", "historian"].some((key) => {
|
|
51
|
+
const agent = rawConfig[key];
|
|
52
|
+
return typeof agent === "object" && agent !== null && !Array.isArray(agent) && "enabled" in agent;
|
|
53
|
+
});
|
|
54
|
+
if (!shouldPatch)
|
|
55
|
+
return rawConfig;
|
|
56
|
+
const patched = { ...rawConfig };
|
|
57
|
+
migrateLegacyEnabledForAgent({ patched, agentName: "dreamer", warnings });
|
|
58
|
+
migrateLegacyEnabledForAgent({ patched, agentName: "historian", warnings });
|
|
59
|
+
return patched;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/config/project-security.ts
|
|
63
|
+
var HIDDEN_AGENT_KEYS = ["historian", "dreamer"];
|
|
64
|
+
var HARNESS_KEYS = PER_HARNESS_MODEL_KEYS;
|
|
65
|
+
var HISTORIAN_USER_ONLY_FIELDS = [
|
|
66
|
+
...PER_HARNESS_MIGRATION_INVENTORY.historian.migrated_execution,
|
|
67
|
+
"runner",
|
|
68
|
+
"host_runner"
|
|
69
|
+
];
|
|
70
|
+
var PROMPT_SURFACE_USER_ONLY_FIELDS = ["guidance_override_path", "tool_descriptions"];
|
|
71
|
+
var AGENT_ESCALATION_FIELDS = ["prompt", "permission", "tools"];
|
|
72
|
+
var EMBEDDING_USER_ONLY_FIELDS = [
|
|
73
|
+
"endpoint",
|
|
74
|
+
"provider",
|
|
75
|
+
"fallback_provider",
|
|
76
|
+
"query_instruction",
|
|
77
|
+
"document_prefix"
|
|
78
|
+
];
|
|
79
|
+
var PERCENTAGE_THRESHOLD_REASON = "security: a repository may only raise compaction thresholds above the user's effective value; it cannot force earlier historian work or cloned-repo cost escalation.";
|
|
80
|
+
var TOKEN_THRESHOLD_REASON = "security: a repository may only raise execute_threshold_tokens above the user's trusted token threshold; it cannot force earlier historian work or cloned-repo cost escalation.";
|
|
81
|
+
var TOKEN_THRESHOLD_INTRODUCTION_REASON = "security: a repository cannot introduce a new execute_threshold_tokens override when the user has no trusted token threshold for that key; that could force earlier historian work or cloned-repo cost escalation.";
|
|
82
|
+
var PROTECTED_TOKENS_REASON = "security: a repository may only raise protected_tokens above the resolved user-or-derived floor; it cannot lower protection.";
|
|
83
|
+
function isPlainObject(value) {
|
|
84
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
85
|
+
}
|
|
86
|
+
function resolveProtectedTokensScalar(value) {
|
|
87
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 4000 && value <= 1e6) {
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
var PROTECTED_TOKENS_TIER_OVERRIDES = Symbol.for("@cortexkit/magic-context/protected-tokens-tier-overrides");
|
|
93
|
+
function attachProtectedTokensTierOverrides(config, args) {
|
|
94
|
+
const user = resolveProtectedTokensScalar(args.trustedUser);
|
|
95
|
+
const rawProject = resolveProtectedTokensScalar(args.project);
|
|
96
|
+
const project = rawProject !== undefined && (user === undefined || rawProject >= user) ? rawProject : undefined;
|
|
97
|
+
if (user === undefined && project === undefined)
|
|
98
|
+
return config;
|
|
99
|
+
Object.defineProperty(config, PROTECTED_TOKENS_TIER_OVERRIDES, {
|
|
100
|
+
value: {
|
|
101
|
+
...user !== undefined ? { user } : {},
|
|
102
|
+
...project !== undefined ? { project } : {}
|
|
103
|
+
},
|
|
104
|
+
configurable: false,
|
|
105
|
+
enumerable: false,
|
|
106
|
+
writable: false
|
|
107
|
+
});
|
|
108
|
+
return config;
|
|
109
|
+
}
|
|
110
|
+
function getProtectedTokensTierOverrides(config) {
|
|
111
|
+
return config[PROTECTED_TOKENS_TIER_OVERRIDES];
|
|
112
|
+
}
|
|
113
|
+
function stripListedFields(target, fields, path, removed) {
|
|
114
|
+
for (const field of fields) {
|
|
115
|
+
if (field in target) {
|
|
116
|
+
delete target[field];
|
|
117
|
+
removed.push(path.length > 0 ? `${path}.${field}` : field);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function stripEscalationAtExecutableSite(block, path, removed) {
|
|
122
|
+
stripListedFields(block, AGENT_ESCALATION_FIELDS, path, removed);
|
|
123
|
+
if (isPlainObject(block.model)) {
|
|
124
|
+
stripListedFields(block.model, AGENT_ESCALATION_FIELDS, `${path}.model`, removed);
|
|
125
|
+
}
|
|
126
|
+
if (Array.isArray(block.fallback_models)) {
|
|
127
|
+
for (let index = 0;index < block.fallback_models.length; index++) {
|
|
128
|
+
const entry = block.fallback_models[index];
|
|
129
|
+
if (isPlainObject(entry)) {
|
|
130
|
+
stripListedFields(entry, AGENT_ESCALATION_FIELDS, `${path}.fallback_models.${index}`, removed);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function stripNestedMuralModels(node, path, removed) {
|
|
136
|
+
for (const [key, value] of Object.entries(node)) {
|
|
137
|
+
if (key === "mural" && isPlainObject(value) && "model" in value) {
|
|
138
|
+
delete value.model;
|
|
139
|
+
removed.push(`${path}.${key}.model`);
|
|
140
|
+
} else if (isPlainObject(value)) {
|
|
141
|
+
stripNestedMuralModels(value, `${path}.${key}`, removed);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function isValidPercentageThreshold(value) {
|
|
146
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 20 && value <= 90;
|
|
147
|
+
}
|
|
148
|
+
function isValidTokenThreshold(value) {
|
|
149
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 5000 && value <= 2000000;
|
|
150
|
+
}
|
|
151
|
+
function normalizeTrustedPercentageThresholds(value) {
|
|
152
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
153
|
+
return { defaultValue: value, overrides: new Map };
|
|
154
|
+
}
|
|
155
|
+
if (isPlainObject(value) && typeof value.default === "number" && Number.isFinite(value.default)) {
|
|
156
|
+
const overrides = new Map;
|
|
157
|
+
for (const [key, child] of Object.entries(value)) {
|
|
158
|
+
if (key === "default")
|
|
159
|
+
continue;
|
|
160
|
+
if (typeof child === "number" && Number.isFinite(child)) {
|
|
161
|
+
overrides.set(key, child);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return { defaultValue: value.default, overrides };
|
|
165
|
+
}
|
|
166
|
+
return { defaultValue: DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, overrides: new Map };
|
|
167
|
+
}
|
|
168
|
+
function normalizeTrustedTokenThresholds(value) {
|
|
169
|
+
if (!isPlainObject(value)) {
|
|
170
|
+
return { defaultValue: undefined, overrides: new Map };
|
|
171
|
+
}
|
|
172
|
+
const overrides = new Map;
|
|
173
|
+
for (const [key, child] of Object.entries(value)) {
|
|
174
|
+
if (key === "default")
|
|
175
|
+
continue;
|
|
176
|
+
if (typeof child === "number" && Number.isFinite(child)) {
|
|
177
|
+
overrides.set(key, child);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
defaultValue: typeof value.default === "number" && Number.isFinite(value.default) ? value.default : undefined,
|
|
182
|
+
overrides
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function clonePercentageThresholds(value) {
|
|
186
|
+
return {
|
|
187
|
+
defaultValue: value.defaultValue,
|
|
188
|
+
overrides: new Map(value.overrides)
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function cloneTokenThresholds(value) {
|
|
192
|
+
return {
|
|
193
|
+
defaultValue: value.defaultValue,
|
|
194
|
+
overrides: new Map(value.overrides)
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function percentageThresholdsEqual(left, right) {
|
|
198
|
+
if (left.defaultValue !== right.defaultValue)
|
|
199
|
+
return false;
|
|
200
|
+
if (left.overrides.size !== right.overrides.size)
|
|
201
|
+
return false;
|
|
202
|
+
for (const [key, value] of left.overrides) {
|
|
203
|
+
if (right.overrides.get(key) !== value)
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
function setMergedPercentageThreshold(mergedRaw, value) {
|
|
209
|
+
if (value.overrides.size === 0) {
|
|
210
|
+
mergedRaw.execute_threshold_percentage = value.defaultValue;
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const serialized = { default: value.defaultValue };
|
|
214
|
+
for (const [key, threshold] of value.overrides) {
|
|
215
|
+
serialized[key] = threshold;
|
|
216
|
+
}
|
|
217
|
+
mergedRaw.execute_threshold_percentage = serialized;
|
|
218
|
+
}
|
|
219
|
+
function setMergedTokenThreshold(mergedRaw, value) {
|
|
220
|
+
if (value.defaultValue === undefined && value.overrides.size === 0) {
|
|
221
|
+
delete mergedRaw.execute_threshold_tokens;
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const serialized = {};
|
|
225
|
+
if (value.defaultValue !== undefined) {
|
|
226
|
+
serialized.default = value.defaultValue;
|
|
227
|
+
}
|
|
228
|
+
for (const [key, threshold] of value.overrides) {
|
|
229
|
+
serialized[key] = threshold;
|
|
230
|
+
}
|
|
231
|
+
mergedRaw.execute_threshold_tokens = serialized;
|
|
232
|
+
}
|
|
233
|
+
function makeProjectThresholdWarning(field, reason) {
|
|
234
|
+
return `Ignoring ${field} from project config (${reason})`;
|
|
235
|
+
}
|
|
236
|
+
function stripUnsafeProjectConfigFields(projectRaw) {
|
|
237
|
+
const warnings = [];
|
|
238
|
+
if ("profiles" in projectRaw) {
|
|
239
|
+
delete projectRaw.profiles;
|
|
240
|
+
warnings.push("Ignoring profiles from project config (security: profile definitions are user-level only; a repository may select a named user profile with profile).");
|
|
241
|
+
}
|
|
242
|
+
if ("auto_update" in projectRaw) {
|
|
243
|
+
delete projectRaw.auto_update;
|
|
244
|
+
warnings.push("Ignoring auto_update from project config (security: this setting only honors user-level config).");
|
|
245
|
+
}
|
|
246
|
+
if ("fail_closed_blocking" in projectRaw) {
|
|
247
|
+
delete projectRaw.fail_closed_blocking;
|
|
248
|
+
warnings.push("Ignoring fail_closed_blocking from project config (security: only user-level config may disable or force the loud inoperability gate).");
|
|
249
|
+
}
|
|
250
|
+
if ("debug_rpc" in projectRaw) {
|
|
251
|
+
delete projectRaw.debug_rpc;
|
|
252
|
+
warnings.push("Ignoring debug_rpc from project config (security: only user-level config may enable process heap diagnostics).");
|
|
253
|
+
}
|
|
254
|
+
if ("allow_home_project" in projectRaw) {
|
|
255
|
+
delete projectRaw.allow_home_project;
|
|
256
|
+
warnings.push("Ignoring allow_home_project from project config (security: only user-level config may opt the user's home directory into Magic Context).");
|
|
257
|
+
}
|
|
258
|
+
const compaction = projectRaw.compaction;
|
|
259
|
+
if (isPlainObject(compaction) && "enabled" in compaction) {
|
|
260
|
+
delete compaction.enabled;
|
|
261
|
+
warnings.push("Ignoring compaction.enabled from project config (security: only user-level config may disable Magic Context's context-window management; a cloned repo cannot change how the user's window is owned).");
|
|
262
|
+
}
|
|
263
|
+
if ("output_reserve" in projectRaw) {
|
|
264
|
+
delete projectRaw.output_reserve;
|
|
265
|
+
warnings.push("Ignoring output_reserve from project config (security: output-token reservation only honors user-level config).");
|
|
266
|
+
}
|
|
267
|
+
const models = projectRaw.models;
|
|
268
|
+
if (isPlainObject(models) && "window_overlay_path" in models) {
|
|
269
|
+
delete models.window_overlay_path;
|
|
270
|
+
warnings.push("Ignoring models.window_overlay_path from project config (security: only user-level config may select model geometry metadata).");
|
|
271
|
+
}
|
|
272
|
+
if ("language" in projectRaw) {
|
|
273
|
+
delete projectRaw.language;
|
|
274
|
+
warnings.push("Ignoring language from project config (security: output language is a user-level setting).");
|
|
275
|
+
}
|
|
276
|
+
if ("sqlite" in projectRaw) {
|
|
277
|
+
delete projectRaw.sqlite;
|
|
278
|
+
warnings.push("Ignoring sqlite.* from project config (security: SQLite cache/mmap PRAGMAs apply to the " + "process-global shared database handle; only user-level config may set them).");
|
|
279
|
+
}
|
|
280
|
+
const storage = projectRaw.storage;
|
|
281
|
+
if (isPlainObject(storage) && "enforce_private_permissions" in storage) {
|
|
282
|
+
delete storage.enforce_private_permissions;
|
|
283
|
+
warnings.push("Ignoring storage.enforce_private_permissions from project config (security: only user-level config may opt into externally managed shared storage permissions).");
|
|
284
|
+
}
|
|
285
|
+
const promptSurface = projectRaw.prompt_surface;
|
|
286
|
+
if (isPlainObject(promptSurface)) {
|
|
287
|
+
const removed = [];
|
|
288
|
+
for (const field of PROMPT_SURFACE_USER_ONLY_FIELDS) {
|
|
289
|
+
if (field in promptSurface) {
|
|
290
|
+
delete promptSurface[field];
|
|
291
|
+
removed.push(field);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (removed.length > 0) {
|
|
295
|
+
warnings.push(`Ignoring prompt_surface.${removed.join("/")} from project config (security: repositories may select prompt presets but only user config may provide guidance or tool-description text).`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const pi = projectRaw.pi;
|
|
299
|
+
if (isPlainObject(pi) && "subagent_extensions" in pi) {
|
|
300
|
+
delete pi.subagent_extensions;
|
|
301
|
+
warnings.push("Ignoring pi.subagent_extensions from project config (security: only user-level config may choose extensions loaded by Pi subagent children).");
|
|
302
|
+
}
|
|
303
|
+
for (const field of ["subc", "shadow_embedding"]) {
|
|
304
|
+
if (field in projectRaw) {
|
|
305
|
+
delete projectRaw[field];
|
|
306
|
+
warnings.push(`Ignoring ${field} from project config (security: daemon routing and developer-only embedding traffic are user-level settings).`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const embedding = projectRaw.embedding;
|
|
310
|
+
if (isPlainObject(embedding)) {
|
|
311
|
+
const removed = [];
|
|
312
|
+
for (const field of EMBEDDING_USER_ONLY_FIELDS) {
|
|
313
|
+
if (field in embedding) {
|
|
314
|
+
delete embedding[field];
|
|
315
|
+
removed.push(field);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (removed.length > 0) {
|
|
319
|
+
warnings.push(`Ignoring embedding.${removed.join("/")} from project config ` + "(security: a repository cannot choose where or how private text is embedded).");
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
for (const agentKey of HIDDEN_AGENT_KEYS) {
|
|
323
|
+
const block = projectRaw[agentKey];
|
|
324
|
+
if (!isPlainObject(block))
|
|
325
|
+
continue;
|
|
326
|
+
const removed = [];
|
|
327
|
+
stripEscalationAtExecutableSite(block, agentKey, removed);
|
|
328
|
+
for (const harness of HARNESS_KEYS) {
|
|
329
|
+
const harnessBlock = block[harness];
|
|
330
|
+
if (!isPlainObject(harnessBlock))
|
|
331
|
+
continue;
|
|
332
|
+
stripEscalationAtExecutableSite(harnessBlock, `${agentKey}.${harness}`, removed);
|
|
333
|
+
const tasks = harnessBlock.tasks;
|
|
334
|
+
if (isPlainObject(tasks)) {
|
|
335
|
+
for (const [taskName, taskBlock] of Object.entries(tasks)) {
|
|
336
|
+
if (isPlainObject(taskBlock)) {
|
|
337
|
+
stripEscalationAtExecutableSite(taskBlock, `${agentKey}.${harness}.tasks.${taskName}`, removed);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const schedulingTasks = block.tasks;
|
|
343
|
+
if (isPlainObject(schedulingTasks)) {
|
|
344
|
+
for (const [taskName, taskBlock] of Object.entries(schedulingTasks)) {
|
|
345
|
+
if (isPlainObject(taskBlock)) {
|
|
346
|
+
stripListedFields(taskBlock, AGENT_ESCALATION_FIELDS, `${agentKey}.tasks.${taskName}`, removed);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (removed.length > 0) {
|
|
351
|
+
warnings.push(`Ignoring ${removed.join(", ")} from project config ` + "(security: a repository cannot reprogram or re-permission hidden agents).");
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const historian = projectRaw.historian;
|
|
355
|
+
if (isPlainObject(historian)) {
|
|
356
|
+
const removed = [];
|
|
357
|
+
for (const field of HISTORIAN_USER_ONLY_FIELDS) {
|
|
358
|
+
if (field in historian) {
|
|
359
|
+
delete historian[field];
|
|
360
|
+
removed.push(field);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
for (const harness of HARNESS_KEYS) {
|
|
364
|
+
const harnessBlock = historian[harness];
|
|
365
|
+
if (!isPlainObject(harnessBlock))
|
|
366
|
+
continue;
|
|
367
|
+
for (const field of HISTORIAN_USER_ONLY_FIELDS) {
|
|
368
|
+
if (field in harnessBlock) {
|
|
369
|
+
delete harnessBlock[field];
|
|
370
|
+
removed.push(`${harness}.${field}`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (removed.length > 0) {
|
|
375
|
+
warnings.push(`Ignoring ${removed.map((path) => `historian.${path}`).join(", ")} from project config ` + "(security: historian model selection is user-level only; a repository cannot force extra compaction cost).");
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
const dreamer = projectRaw.dreamer;
|
|
379
|
+
if (isPlainObject(dreamer) && "runner" in dreamer) {
|
|
380
|
+
delete dreamer.runner;
|
|
381
|
+
warnings.push("Ignoring dreamer.runner from project config (security: which process and provider account run dreamer completions is a user-level setting).");
|
|
382
|
+
}
|
|
383
|
+
const mural = projectRaw.mural;
|
|
384
|
+
if (isPlainObject(mural) && "model" in mural) {
|
|
385
|
+
delete mural.model;
|
|
386
|
+
warnings.push("Ignoring mural.model from project config (security: the mural cue-compressor model is a user-level setting; a repository cannot choose where project memory is sent).");
|
|
387
|
+
}
|
|
388
|
+
const experimental = projectRaw.experimental;
|
|
389
|
+
const legacyMural = isPlainObject(experimental) ? experimental.mural : undefined;
|
|
390
|
+
if (isPlainObject(legacyMural) && "model" in legacyMural) {
|
|
391
|
+
delete legacyMural.model;
|
|
392
|
+
warnings.push("Ignoring experimental.mural.model from project config (security: the mural cue-compressor model is a user-level setting; use user-level mural.model).");
|
|
393
|
+
}
|
|
394
|
+
const nestedMuralRemoved = [];
|
|
395
|
+
for (const agentKey of HIDDEN_AGENT_KEYS) {
|
|
396
|
+
const block = projectRaw[agentKey];
|
|
397
|
+
if (!isPlainObject(block))
|
|
398
|
+
continue;
|
|
399
|
+
stripNestedMuralModels(block, agentKey, nestedMuralRemoved);
|
|
400
|
+
}
|
|
401
|
+
if (nestedMuralRemoved.length > 0) {
|
|
402
|
+
warnings.push(`Ignoring ${nestedMuralRemoved.join(", ")} from project config (security: the mural cue-compressor model is a user-level setting; a repository cannot choose where project memory is sent).`);
|
|
403
|
+
}
|
|
404
|
+
return warnings;
|
|
405
|
+
}
|
|
406
|
+
function constrainProjectThresholdOverrides(args) {
|
|
407
|
+
const warnings = [];
|
|
408
|
+
const basePercentage = normalizeTrustedPercentageThresholds(args.trustedBaseConfig.execute_threshold_percentage);
|
|
409
|
+
const baseTokens = normalizeTrustedTokenThresholds(args.trustedBaseConfig.execute_threshold_tokens);
|
|
410
|
+
if ("execute_threshold_percentage" in args.projectRaw) {
|
|
411
|
+
const projectValue = args.projectRaw.execute_threshold_percentage;
|
|
412
|
+
if (isValidPercentageThreshold(projectValue)) {
|
|
413
|
+
const constrained = clonePercentageThresholds(basePercentage);
|
|
414
|
+
constrained.defaultValue = Math.max(basePercentage.defaultValue, projectValue);
|
|
415
|
+
for (const [modelKey, threshold] of basePercentage.overrides) {
|
|
416
|
+
const raisedThreshold = Math.max(threshold, projectValue);
|
|
417
|
+
if (raisedThreshold === constrained.defaultValue) {
|
|
418
|
+
constrained.overrides.delete(modelKey);
|
|
419
|
+
} else {
|
|
420
|
+
constrained.overrides.set(modelKey, raisedThreshold);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
setMergedPercentageThreshold(args.mergedRaw, constrained);
|
|
424
|
+
if (percentageThresholdsEqual(constrained, basePercentage)) {
|
|
425
|
+
warnings.push(makeProjectThresholdWarning("execute_threshold_percentage", PERCENTAGE_THRESHOLD_REASON));
|
|
426
|
+
}
|
|
427
|
+
} else if (isPlainObject(projectValue)) {
|
|
428
|
+
const constrained = clonePercentageThresholds(basePercentage);
|
|
429
|
+
let touchedValidEntry = false;
|
|
430
|
+
if (isValidPercentageThreshold(projectValue.default)) {
|
|
431
|
+
touchedValidEntry = true;
|
|
432
|
+
if (projectValue.default > basePercentage.defaultValue) {
|
|
433
|
+
constrained.defaultValue = projectValue.default;
|
|
434
|
+
} else {
|
|
435
|
+
warnings.push(makeProjectThresholdWarning("execute_threshold_percentage.default", PERCENTAGE_THRESHOLD_REASON));
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
for (const [modelKey, rawValue] of Object.entries(projectValue)) {
|
|
439
|
+
if (modelKey === "default")
|
|
440
|
+
continue;
|
|
441
|
+
if (!isValidPercentageThreshold(rawValue))
|
|
442
|
+
continue;
|
|
443
|
+
touchedValidEntry = true;
|
|
444
|
+
const baseValue = basePercentage.overrides.get(modelKey) ?? basePercentage.defaultValue;
|
|
445
|
+
if (rawValue > baseValue) {
|
|
446
|
+
if (rawValue === constrained.defaultValue) {
|
|
447
|
+
constrained.overrides.delete(modelKey);
|
|
448
|
+
} else {
|
|
449
|
+
constrained.overrides.set(modelKey, rawValue);
|
|
450
|
+
}
|
|
451
|
+
} else {
|
|
452
|
+
warnings.push(makeProjectThresholdWarning(`execute_threshold_percentage.${modelKey}`, PERCENTAGE_THRESHOLD_REASON));
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (touchedValidEntry) {
|
|
456
|
+
setMergedPercentageThreshold(args.mergedRaw, constrained);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
if ("execute_threshold_tokens" in args.projectRaw && isPlainObject(args.projectRaw.execute_threshold_tokens)) {
|
|
461
|
+
const projectValue = args.projectRaw.execute_threshold_tokens;
|
|
462
|
+
const constrained = cloneTokenThresholds(baseTokens);
|
|
463
|
+
let touchedValidEntry = false;
|
|
464
|
+
if (isValidTokenThreshold(projectValue.default)) {
|
|
465
|
+
touchedValidEntry = true;
|
|
466
|
+
if (baseTokens.defaultValue === undefined) {
|
|
467
|
+
warnings.push(makeProjectThresholdWarning("execute_threshold_tokens.default", TOKEN_THRESHOLD_INTRODUCTION_REASON));
|
|
468
|
+
} else if (projectValue.default > baseTokens.defaultValue) {
|
|
469
|
+
constrained.defaultValue = projectValue.default;
|
|
470
|
+
} else {
|
|
471
|
+
warnings.push(makeProjectThresholdWarning("execute_threshold_tokens.default", TOKEN_THRESHOLD_REASON));
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
for (const [modelKey, rawValue] of Object.entries(projectValue)) {
|
|
475
|
+
if (modelKey === "default")
|
|
476
|
+
continue;
|
|
477
|
+
if (!isValidTokenThreshold(rawValue))
|
|
478
|
+
continue;
|
|
479
|
+
touchedValidEntry = true;
|
|
480
|
+
const baseValue = baseTokens.overrides.get(modelKey) ?? baseTokens.defaultValue;
|
|
481
|
+
if (baseValue === undefined) {
|
|
482
|
+
warnings.push(makeProjectThresholdWarning(`execute_threshold_tokens.${modelKey}`, TOKEN_THRESHOLD_INTRODUCTION_REASON));
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
if (rawValue > baseValue) {
|
|
486
|
+
if (rawValue === constrained.defaultValue) {
|
|
487
|
+
constrained.overrides.delete(modelKey);
|
|
488
|
+
} else {
|
|
489
|
+
constrained.overrides.set(modelKey, rawValue);
|
|
490
|
+
}
|
|
491
|
+
} else {
|
|
492
|
+
warnings.push(makeProjectThresholdWarning(`execute_threshold_tokens.${modelKey}`, TOKEN_THRESHOLD_REASON));
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
if (touchedValidEntry) {
|
|
496
|
+
setMergedTokenThreshold(args.mergedRaw, constrained);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if ("protected_tokens" in args.projectRaw) {
|
|
500
|
+
const rawProject = args.projectRaw.protected_tokens;
|
|
501
|
+
const projectVal = resolveProtectedTokensScalar(rawProject);
|
|
502
|
+
const trustedUserVal = resolveProtectedTokensScalar(args.trustedBaseConfig.protected_tokens);
|
|
503
|
+
if (projectVal !== undefined) {
|
|
504
|
+
if (trustedUserVal !== undefined) {
|
|
505
|
+
if (projectVal >= trustedUserVal) {
|
|
506
|
+
args.mergedRaw.protected_tokens = projectVal;
|
|
507
|
+
} else {
|
|
508
|
+
args.mergedRaw.protected_tokens = trustedUserVal;
|
|
509
|
+
warnings.push(makeProjectThresholdWarning("protected_tokens", PROTECTED_TOKENS_REASON));
|
|
510
|
+
}
|
|
511
|
+
} else {
|
|
512
|
+
args.mergedRaw.protected_tokens = projectVal;
|
|
513
|
+
}
|
|
514
|
+
} else {
|
|
515
|
+
if (trustedUserVal !== undefined) {
|
|
516
|
+
args.mergedRaw.protected_tokens = trustedUserVal;
|
|
517
|
+
} else {
|
|
518
|
+
delete args.mergedRaw.protected_tokens;
|
|
519
|
+
}
|
|
520
|
+
warnings.push(makeProjectThresholdWarning("protected_tokens", PROTECTED_TOKENS_REASON));
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return warnings;
|
|
524
|
+
}
|
|
525
|
+
function normalizeEndpoint(value) {
|
|
526
|
+
if (typeof value !== "string")
|
|
527
|
+
return;
|
|
528
|
+
const trimmed = value.trim().replace(/\/+$/, "");
|
|
529
|
+
return trimmed.length > 0 ? trimmed.toLowerCase() : undefined;
|
|
530
|
+
}
|
|
531
|
+
function dropInheritedEmbeddingKeyOnRedirect(projectRaw, mergedRaw, userRaw) {
|
|
532
|
+
const projectEmbedding = projectRaw.embedding;
|
|
533
|
+
if (!isPlainObject(projectEmbedding))
|
|
534
|
+
return [];
|
|
535
|
+
const redirectsEndpoint = "endpoint" in projectEmbedding;
|
|
536
|
+
if (!redirectsEndpoint)
|
|
537
|
+
return [];
|
|
538
|
+
const userEmbedding = userRaw?.embedding;
|
|
539
|
+
if (isPlainObject(userEmbedding)) {
|
|
540
|
+
const projectEndpoint = normalizeEndpoint(projectEmbedding.endpoint);
|
|
541
|
+
const userEndpoint = normalizeEndpoint(userEmbedding.endpoint);
|
|
542
|
+
if (projectEndpoint !== undefined && projectEndpoint === userEndpoint) {
|
|
543
|
+
return [];
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
const providesOwnKey = typeof projectEmbedding.api_key === "string" && projectEmbedding.api_key.length > 0;
|
|
547
|
+
if (providesOwnKey)
|
|
548
|
+
return [];
|
|
549
|
+
const mergedEmbedding = mergedRaw.embedding;
|
|
550
|
+
if (!isPlainObject(mergedEmbedding))
|
|
551
|
+
return [];
|
|
552
|
+
if (!("api_key" in mergedEmbedding))
|
|
553
|
+
return [];
|
|
554
|
+
delete mergedEmbedding.api_key;
|
|
555
|
+
return [
|
|
556
|
+
"Dropped inherited user embedding api_key because project config redirected " + "embedding.endpoint without supplying its own key (security: prevents key " + "exfiltration to a repository-chosen endpoint)."
|
|
557
|
+
];
|
|
558
|
+
}
|
|
559
|
+
function projectContributionPath(projectRaw, issuePath) {
|
|
560
|
+
let node = projectRaw;
|
|
561
|
+
for (let index = 0;index < issuePath.length; index++) {
|
|
562
|
+
const segment = String(issuePath[index]);
|
|
563
|
+
if (!isPlainObject(node) || !Object.hasOwn(node, segment))
|
|
564
|
+
return;
|
|
565
|
+
node = node[segment];
|
|
566
|
+
if (index === issuePath.length - 1 || !isPlainObject(node)) {
|
|
567
|
+
return issuePath.slice(0, index + 1);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
function displacedTrustedValue(trustedRaw, contribution) {
|
|
573
|
+
let node = trustedRaw;
|
|
574
|
+
for (let index = 0;index < contribution.length; index++) {
|
|
575
|
+
const segment = String(contribution[index]);
|
|
576
|
+
if (!isPlainObject(node) || !Object.hasOwn(node, segment))
|
|
577
|
+
return;
|
|
578
|
+
node = node[segment];
|
|
579
|
+
if (index === contribution.length - 1 || !isPlainObject(node)) {
|
|
580
|
+
return { path: contribution.slice(0, index + 1), value: node };
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
function defineOwnValue(target, key, value) {
|
|
586
|
+
Object.defineProperty(target, key, {
|
|
587
|
+
value,
|
|
588
|
+
enumerable: true,
|
|
589
|
+
configurable: true,
|
|
590
|
+
writable: true
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
function writeOwnPath(root, path, value) {
|
|
594
|
+
let node = root;
|
|
595
|
+
for (let index = 0;index < path.length - 1; index++) {
|
|
596
|
+
const segment = String(path[index]);
|
|
597
|
+
const child = node[segment];
|
|
598
|
+
if (!isPlainObject(child))
|
|
599
|
+
return;
|
|
600
|
+
const copy = { ...child };
|
|
601
|
+
defineOwnValue(node, segment, copy);
|
|
602
|
+
node = copy;
|
|
603
|
+
}
|
|
604
|
+
defineOwnValue(node, String(path[path.length - 1]), value);
|
|
605
|
+
}
|
|
606
|
+
var MAX_PROJECT_RESTORE_ROUNDS = 16;
|
|
607
|
+
function restoreTrustedValuesOverInvalidProjectValues(args) {
|
|
608
|
+
const warnings = [];
|
|
609
|
+
const restoredTopLevelKeys = new Set;
|
|
610
|
+
const restored = new Set;
|
|
611
|
+
for (let round = 0;round < MAX_PROJECT_RESTORE_ROUNDS; round++) {
|
|
612
|
+
let changed = false;
|
|
613
|
+
for (const issuePath of args.collectIssuePaths(args.mergedRaw)) {
|
|
614
|
+
const contribution = projectContributionPath(args.projectRaw, issuePath);
|
|
615
|
+
if (contribution === undefined || contribution.length === 0)
|
|
616
|
+
continue;
|
|
617
|
+
const trusted = displacedTrustedValue(args.trustedRaw, contribution);
|
|
618
|
+
if (trusted === undefined)
|
|
619
|
+
continue;
|
|
620
|
+
const key = trusted.path.map(String).join(".");
|
|
621
|
+
if (restored.has(key))
|
|
622
|
+
continue;
|
|
623
|
+
writeOwnPath(args.mergedRaw, trusted.path, trusted.value);
|
|
624
|
+
restored.add(key);
|
|
625
|
+
restoredTopLevelKeys.add(String(trusted.path[0]));
|
|
626
|
+
changed = true;
|
|
627
|
+
warnings.push(`Ignoring invalid ${key} from project config and keeping the user-level value (security: a repository cannot reset user settings by supplying an invalid value).`);
|
|
628
|
+
}
|
|
629
|
+
if (!changed)
|
|
630
|
+
break;
|
|
631
|
+
}
|
|
632
|
+
return { warnings, restoredTopLevelKeys: [...restoredTopLevelKeys] };
|
|
633
|
+
}
|
|
634
|
+
var PROJECT_COMMAND_STRING_FIELDS = ["description", "agent", "model"];
|
|
635
|
+
function wellFormedCommand(value) {
|
|
636
|
+
if (!isPlainObject(value))
|
|
637
|
+
return;
|
|
638
|
+
if (typeof value.template !== "string" || value.template.trim().length === 0)
|
|
639
|
+
return;
|
|
640
|
+
const command = { template: value.template };
|
|
641
|
+
for (const field of PROJECT_COMMAND_STRING_FIELDS) {
|
|
642
|
+
if (value[field] === undefined)
|
|
643
|
+
continue;
|
|
644
|
+
if (typeof value[field] !== "string")
|
|
645
|
+
return;
|
|
646
|
+
command[field] = value[field];
|
|
647
|
+
}
|
|
648
|
+
if (value.subtask !== undefined) {
|
|
649
|
+
if (typeof value.subtask !== "boolean")
|
|
650
|
+
return;
|
|
651
|
+
command.subtask = value.subtask;
|
|
652
|
+
}
|
|
653
|
+
return command;
|
|
654
|
+
}
|
|
655
|
+
function constrainProjectCommands(args) {
|
|
656
|
+
if (!("command" in args.projectRaw))
|
|
657
|
+
return [];
|
|
658
|
+
const warnings = [];
|
|
659
|
+
const trustedCommands = isPlainObject(args.trustedRaw.command) ? args.trustedRaw.command : undefined;
|
|
660
|
+
const merged = { ...trustedCommands ?? {} };
|
|
661
|
+
const projectCommands = args.projectRaw.command;
|
|
662
|
+
if (!isPlainObject(projectCommands)) {
|
|
663
|
+
warnings.push("Ignoring command from project config (it must be an object of named commands).");
|
|
664
|
+
} else {
|
|
665
|
+
for (const [name, value] of Object.entries(projectCommands)) {
|
|
666
|
+
if (trustedCommands && Object.hasOwn(trustedCommands, name)) {
|
|
667
|
+
warnings.push(`Ignoring command.${name} from project config (security: a repository cannot replace a command defined in user config).`);
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
if (args.reservedNames.includes(name)) {
|
|
671
|
+
warnings.push(`Ignoring command.${name} from project config (security: a repository cannot replace a built-in Magic Context command).`);
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
const command = wellFormedCommand(value);
|
|
675
|
+
if (!command) {
|
|
676
|
+
warnings.push(`Ignoring command.${name} from project config (it needs a non-empty string template; description, agent and model must be strings and subtask a boolean).`);
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
Object.defineProperty(merged, name, {
|
|
680
|
+
value: command,
|
|
681
|
+
enumerable: true,
|
|
682
|
+
configurable: true,
|
|
683
|
+
writable: true
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
if (Object.keys(merged).length === 0)
|
|
688
|
+
delete args.mergedRaw.command;
|
|
689
|
+
else
|
|
690
|
+
args.mergedRaw.command = merged;
|
|
691
|
+
return warnings;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// src/config/index.ts
|
|
695
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
696
|
+
|
|
697
|
+
// src/shared/builtin-commands.ts
|
|
698
|
+
var COMPACTION_ENABLED_PATH2 = `compaction${".enabled"}`;
|
|
699
|
+
function getMagicContextBuiltinCommands(compactionEnabled = true) {
|
|
700
|
+
const unavailableInCompactionOff = (command) => `Unavailable when ${COMPACTION_ENABLED_PATH2} is false: /${command} manages compacted history.`;
|
|
701
|
+
return {
|
|
702
|
+
"ctx-status": {
|
|
703
|
+
template: "ctx-status",
|
|
704
|
+
description: "Show magic context status, pending queue, cache TTL, and debug info"
|
|
705
|
+
},
|
|
706
|
+
"ctx-recomp": {
|
|
707
|
+
template: "ctx-recomp",
|
|
708
|
+
description: compactionEnabled ? "Rebuild compressed history from raw history (full or <start>-<end> range); memories are not changed" : unavailableInCompactionOff("ctx-recomp")
|
|
709
|
+
},
|
|
710
|
+
"ctx-wrapup": {
|
|
711
|
+
template: "ctx-wrapup",
|
|
712
|
+
description: compactionEnabled ? "Compact older live history while keeping the newest messages raw" : unavailableInCompactionOff("ctx-wrapup")
|
|
713
|
+
},
|
|
714
|
+
"ctx-flush": {
|
|
715
|
+
template: "ctx-flush",
|
|
716
|
+
description: compactionEnabled ? "Force-process all pending magic context operations immediately" : unavailableInCompactionOff("ctx-flush")
|
|
717
|
+
},
|
|
718
|
+
"ctx-dream": {
|
|
719
|
+
template: "ctx-dream",
|
|
720
|
+
description: "Run the hidden dreamer maintenance pass for this project now"
|
|
721
|
+
},
|
|
722
|
+
"ctx-embed": {
|
|
723
|
+
template: "ctx-embed",
|
|
724
|
+
description: "Embedding status, or start/pause history compartment embedding (start | pause)"
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// src/shared/config-diagnostics.ts
|
|
730
|
+
var CONFIG_WARNING_CLASS = {
|
|
731
|
+
FILE_PARSE: "file-parse",
|
|
732
|
+
FILE_IO: "file-io",
|
|
733
|
+
INVALID_LEAF: "invalid-leaf"
|
|
734
|
+
};
|
|
735
|
+
var claimedFailures = new Set;
|
|
736
|
+
|
|
737
|
+
// src/shared/jsonc-parser.ts
|
|
738
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
739
|
+
|
|
740
|
+
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
741
|
+
function createScanner(text, ignoreTrivia = false) {
|
|
742
|
+
const len = text.length;
|
|
743
|
+
let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
|
|
744
|
+
function scanHexDigits(count, exact) {
|
|
745
|
+
let digits = 0;
|
|
746
|
+
let value = 0;
|
|
747
|
+
while (digits < count || !exact) {
|
|
748
|
+
let ch = text.charCodeAt(pos);
|
|
749
|
+
if (ch >= 48 && ch <= 57) {
|
|
750
|
+
value = value * 16 + ch - 48;
|
|
751
|
+
} else if (ch >= 65 && ch <= 70) {
|
|
752
|
+
value = value * 16 + ch - 65 + 10;
|
|
753
|
+
} else if (ch >= 97 && ch <= 102) {
|
|
754
|
+
value = value * 16 + ch - 97 + 10;
|
|
755
|
+
} else {
|
|
756
|
+
break;
|
|
757
|
+
}
|
|
758
|
+
pos++;
|
|
759
|
+
digits++;
|
|
760
|
+
}
|
|
761
|
+
if (digits < count) {
|
|
762
|
+
value = -1;
|
|
763
|
+
}
|
|
764
|
+
return value;
|
|
765
|
+
}
|
|
766
|
+
function setPosition(newPosition) {
|
|
767
|
+
pos = newPosition;
|
|
768
|
+
value = "";
|
|
769
|
+
tokenOffset = 0;
|
|
770
|
+
token = 16;
|
|
771
|
+
scanError = 0;
|
|
772
|
+
}
|
|
773
|
+
function scanNumber() {
|
|
774
|
+
let start = pos;
|
|
775
|
+
if (text.charCodeAt(pos) === 48) {
|
|
776
|
+
pos++;
|
|
777
|
+
} else {
|
|
778
|
+
pos++;
|
|
779
|
+
while (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
|
780
|
+
pos++;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
if (pos < text.length && text.charCodeAt(pos) === 46) {
|
|
784
|
+
pos++;
|
|
785
|
+
if (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
|
786
|
+
pos++;
|
|
787
|
+
while (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
|
788
|
+
pos++;
|
|
789
|
+
}
|
|
790
|
+
} else {
|
|
791
|
+
scanError = 3;
|
|
792
|
+
return text.substring(start, pos);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
let end = pos;
|
|
796
|
+
if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
|
|
797
|
+
pos++;
|
|
798
|
+
if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) {
|
|
799
|
+
pos++;
|
|
800
|
+
}
|
|
801
|
+
if (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
|
802
|
+
pos++;
|
|
803
|
+
while (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
|
804
|
+
pos++;
|
|
805
|
+
}
|
|
806
|
+
end = pos;
|
|
807
|
+
} else {
|
|
808
|
+
scanError = 3;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return text.substring(start, end);
|
|
812
|
+
}
|
|
813
|
+
function scanString() {
|
|
814
|
+
let result = "", start = pos;
|
|
815
|
+
while (true) {
|
|
816
|
+
if (pos >= len) {
|
|
817
|
+
result += text.substring(start, pos);
|
|
818
|
+
scanError = 2;
|
|
819
|
+
break;
|
|
820
|
+
}
|
|
821
|
+
const ch = text.charCodeAt(pos);
|
|
822
|
+
if (ch === 34) {
|
|
823
|
+
result += text.substring(start, pos);
|
|
824
|
+
pos++;
|
|
825
|
+
break;
|
|
826
|
+
}
|
|
827
|
+
if (ch === 92) {
|
|
828
|
+
result += text.substring(start, pos);
|
|
829
|
+
pos++;
|
|
830
|
+
if (pos >= len) {
|
|
831
|
+
scanError = 2;
|
|
832
|
+
break;
|
|
833
|
+
}
|
|
834
|
+
const ch2 = text.charCodeAt(pos++);
|
|
835
|
+
switch (ch2) {
|
|
836
|
+
case 34:
|
|
837
|
+
result += '"';
|
|
838
|
+
break;
|
|
839
|
+
case 92:
|
|
840
|
+
result += "\\";
|
|
841
|
+
break;
|
|
842
|
+
case 47:
|
|
843
|
+
result += "/";
|
|
844
|
+
break;
|
|
845
|
+
case 98:
|
|
846
|
+
result += "\b";
|
|
847
|
+
break;
|
|
848
|
+
case 102:
|
|
849
|
+
result += "\f";
|
|
850
|
+
break;
|
|
851
|
+
case 110:
|
|
852
|
+
result += `
|
|
853
|
+
`;
|
|
854
|
+
break;
|
|
855
|
+
case 114:
|
|
856
|
+
result += "\r";
|
|
857
|
+
break;
|
|
858
|
+
case 116:
|
|
859
|
+
result += "\t";
|
|
860
|
+
break;
|
|
861
|
+
case 117:
|
|
862
|
+
const ch3 = scanHexDigits(4, true);
|
|
863
|
+
if (ch3 >= 0) {
|
|
864
|
+
result += String.fromCharCode(ch3);
|
|
865
|
+
} else {
|
|
866
|
+
scanError = 4;
|
|
867
|
+
}
|
|
868
|
+
break;
|
|
869
|
+
default:
|
|
870
|
+
scanError = 5;
|
|
871
|
+
}
|
|
872
|
+
start = pos;
|
|
873
|
+
continue;
|
|
874
|
+
}
|
|
875
|
+
if (ch >= 0 && ch <= 31) {
|
|
876
|
+
if (isLineBreak(ch)) {
|
|
877
|
+
result += text.substring(start, pos);
|
|
878
|
+
scanError = 2;
|
|
879
|
+
break;
|
|
880
|
+
} else {
|
|
881
|
+
scanError = 6;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
pos++;
|
|
885
|
+
}
|
|
886
|
+
return result;
|
|
887
|
+
}
|
|
888
|
+
function scanNext() {
|
|
889
|
+
value = "";
|
|
890
|
+
scanError = 0;
|
|
891
|
+
tokenOffset = pos;
|
|
892
|
+
lineStartOffset = lineNumber;
|
|
893
|
+
prevTokenLineStartOffset = tokenLineStartOffset;
|
|
894
|
+
if (pos >= len) {
|
|
895
|
+
tokenOffset = len;
|
|
896
|
+
return token = 17;
|
|
897
|
+
}
|
|
898
|
+
let code = text.charCodeAt(pos);
|
|
899
|
+
if (isWhiteSpace(code)) {
|
|
900
|
+
do {
|
|
901
|
+
pos++;
|
|
902
|
+
value += String.fromCharCode(code);
|
|
903
|
+
code = text.charCodeAt(pos);
|
|
904
|
+
} while (isWhiteSpace(code));
|
|
905
|
+
return token = 15;
|
|
906
|
+
}
|
|
907
|
+
if (isLineBreak(code)) {
|
|
908
|
+
pos++;
|
|
909
|
+
value += String.fromCharCode(code);
|
|
910
|
+
if (code === 13 && text.charCodeAt(pos) === 10) {
|
|
911
|
+
pos++;
|
|
912
|
+
value += `
|
|
913
|
+
`;
|
|
914
|
+
}
|
|
915
|
+
lineNumber++;
|
|
916
|
+
tokenLineStartOffset = pos;
|
|
917
|
+
return token = 14;
|
|
918
|
+
}
|
|
919
|
+
switch (code) {
|
|
920
|
+
case 123:
|
|
921
|
+
pos++;
|
|
922
|
+
return token = 1;
|
|
923
|
+
case 125:
|
|
924
|
+
pos++;
|
|
925
|
+
return token = 2;
|
|
926
|
+
case 91:
|
|
927
|
+
pos++;
|
|
928
|
+
return token = 3;
|
|
929
|
+
case 93:
|
|
930
|
+
pos++;
|
|
931
|
+
return token = 4;
|
|
932
|
+
case 58:
|
|
933
|
+
pos++;
|
|
934
|
+
return token = 6;
|
|
935
|
+
case 44:
|
|
936
|
+
pos++;
|
|
937
|
+
return token = 5;
|
|
938
|
+
case 34:
|
|
939
|
+
pos++;
|
|
940
|
+
value = scanString();
|
|
941
|
+
return token = 10;
|
|
942
|
+
case 47:
|
|
943
|
+
const start = pos - 1;
|
|
944
|
+
if (text.charCodeAt(pos + 1) === 47) {
|
|
945
|
+
pos += 2;
|
|
946
|
+
while (pos < len) {
|
|
947
|
+
if (isLineBreak(text.charCodeAt(pos))) {
|
|
948
|
+
break;
|
|
949
|
+
}
|
|
950
|
+
pos++;
|
|
951
|
+
}
|
|
952
|
+
value = text.substring(start, pos);
|
|
953
|
+
return token = 12;
|
|
954
|
+
}
|
|
955
|
+
if (text.charCodeAt(pos + 1) === 42) {
|
|
956
|
+
pos += 2;
|
|
957
|
+
const safeLength = len - 1;
|
|
958
|
+
let commentClosed = false;
|
|
959
|
+
while (pos < safeLength) {
|
|
960
|
+
const ch = text.charCodeAt(pos);
|
|
961
|
+
if (ch === 42 && text.charCodeAt(pos + 1) === 47) {
|
|
962
|
+
pos += 2;
|
|
963
|
+
commentClosed = true;
|
|
964
|
+
break;
|
|
965
|
+
}
|
|
966
|
+
pos++;
|
|
967
|
+
if (isLineBreak(ch)) {
|
|
968
|
+
if (ch === 13 && text.charCodeAt(pos) === 10) {
|
|
969
|
+
pos++;
|
|
970
|
+
}
|
|
971
|
+
lineNumber++;
|
|
972
|
+
tokenLineStartOffset = pos;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
if (!commentClosed) {
|
|
976
|
+
pos++;
|
|
977
|
+
scanError = 1;
|
|
978
|
+
}
|
|
979
|
+
value = text.substring(start, pos);
|
|
980
|
+
return token = 13;
|
|
981
|
+
}
|
|
982
|
+
value += String.fromCharCode(code);
|
|
983
|
+
pos++;
|
|
984
|
+
return token = 16;
|
|
985
|
+
case 45:
|
|
986
|
+
value += String.fromCharCode(code);
|
|
987
|
+
pos++;
|
|
988
|
+
if (pos === len || !isDigit(text.charCodeAt(pos))) {
|
|
989
|
+
return token = 16;
|
|
990
|
+
}
|
|
991
|
+
case 48:
|
|
992
|
+
case 49:
|
|
993
|
+
case 50:
|
|
994
|
+
case 51:
|
|
995
|
+
case 52:
|
|
996
|
+
case 53:
|
|
997
|
+
case 54:
|
|
998
|
+
case 55:
|
|
999
|
+
case 56:
|
|
1000
|
+
case 57:
|
|
1001
|
+
value += scanNumber();
|
|
1002
|
+
return token = 11;
|
|
1003
|
+
default:
|
|
1004
|
+
while (pos < len && isUnknownContentCharacter(code)) {
|
|
1005
|
+
pos++;
|
|
1006
|
+
code = text.charCodeAt(pos);
|
|
1007
|
+
}
|
|
1008
|
+
if (tokenOffset !== pos) {
|
|
1009
|
+
value = text.substring(tokenOffset, pos);
|
|
1010
|
+
switch (value) {
|
|
1011
|
+
case "true":
|
|
1012
|
+
return token = 8;
|
|
1013
|
+
case "false":
|
|
1014
|
+
return token = 9;
|
|
1015
|
+
case "null":
|
|
1016
|
+
return token = 7;
|
|
1017
|
+
}
|
|
1018
|
+
return token = 16;
|
|
1019
|
+
}
|
|
1020
|
+
value += String.fromCharCode(code);
|
|
1021
|
+
pos++;
|
|
1022
|
+
return token = 16;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
function isUnknownContentCharacter(code) {
|
|
1026
|
+
if (isWhiteSpace(code) || isLineBreak(code)) {
|
|
1027
|
+
return false;
|
|
1028
|
+
}
|
|
1029
|
+
switch (code) {
|
|
1030
|
+
case 125:
|
|
1031
|
+
case 93:
|
|
1032
|
+
case 123:
|
|
1033
|
+
case 91:
|
|
1034
|
+
case 34:
|
|
1035
|
+
case 58:
|
|
1036
|
+
case 44:
|
|
1037
|
+
case 47:
|
|
1038
|
+
return false;
|
|
1039
|
+
}
|
|
1040
|
+
return true;
|
|
1041
|
+
}
|
|
1042
|
+
function scanNextNonTrivia() {
|
|
1043
|
+
let result;
|
|
1044
|
+
do {
|
|
1045
|
+
result = scanNext();
|
|
1046
|
+
} while (result >= 12 && result <= 15);
|
|
1047
|
+
return result;
|
|
1048
|
+
}
|
|
1049
|
+
return {
|
|
1050
|
+
setPosition,
|
|
1051
|
+
getPosition: () => pos,
|
|
1052
|
+
scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
|
|
1053
|
+
getToken: () => token,
|
|
1054
|
+
getTokenValue: () => value,
|
|
1055
|
+
getTokenOffset: () => tokenOffset,
|
|
1056
|
+
getTokenLength: () => pos - tokenOffset,
|
|
1057
|
+
getTokenStartLine: () => lineStartOffset,
|
|
1058
|
+
getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,
|
|
1059
|
+
getTokenError: () => scanError
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
function isWhiteSpace(ch) {
|
|
1063
|
+
return ch === 32 || ch === 9;
|
|
1064
|
+
}
|
|
1065
|
+
function isLineBreak(ch) {
|
|
1066
|
+
return ch === 10 || ch === 13;
|
|
1067
|
+
}
|
|
1068
|
+
function isDigit(ch) {
|
|
1069
|
+
return ch >= 48 && ch <= 57;
|
|
1070
|
+
}
|
|
1071
|
+
var CharacterCodes;
|
|
1072
|
+
(function(CharacterCodes) {
|
|
1073
|
+
CharacterCodes[CharacterCodes["lineFeed"] = 10] = "lineFeed";
|
|
1074
|
+
CharacterCodes[CharacterCodes["carriageReturn"] = 13] = "carriageReturn";
|
|
1075
|
+
CharacterCodes[CharacterCodes["space"] = 32] = "space";
|
|
1076
|
+
CharacterCodes[CharacterCodes["_0"] = 48] = "_0";
|
|
1077
|
+
CharacterCodes[CharacterCodes["_1"] = 49] = "_1";
|
|
1078
|
+
CharacterCodes[CharacterCodes["_2"] = 50] = "_2";
|
|
1079
|
+
CharacterCodes[CharacterCodes["_3"] = 51] = "_3";
|
|
1080
|
+
CharacterCodes[CharacterCodes["_4"] = 52] = "_4";
|
|
1081
|
+
CharacterCodes[CharacterCodes["_5"] = 53] = "_5";
|
|
1082
|
+
CharacterCodes[CharacterCodes["_6"] = 54] = "_6";
|
|
1083
|
+
CharacterCodes[CharacterCodes["_7"] = 55] = "_7";
|
|
1084
|
+
CharacterCodes[CharacterCodes["_8"] = 56] = "_8";
|
|
1085
|
+
CharacterCodes[CharacterCodes["_9"] = 57] = "_9";
|
|
1086
|
+
CharacterCodes[CharacterCodes["a"] = 97] = "a";
|
|
1087
|
+
CharacterCodes[CharacterCodes["b"] = 98] = "b";
|
|
1088
|
+
CharacterCodes[CharacterCodes["c"] = 99] = "c";
|
|
1089
|
+
CharacterCodes[CharacterCodes["d"] = 100] = "d";
|
|
1090
|
+
CharacterCodes[CharacterCodes["e"] = 101] = "e";
|
|
1091
|
+
CharacterCodes[CharacterCodes["f"] = 102] = "f";
|
|
1092
|
+
CharacterCodes[CharacterCodes["g"] = 103] = "g";
|
|
1093
|
+
CharacterCodes[CharacterCodes["h"] = 104] = "h";
|
|
1094
|
+
CharacterCodes[CharacterCodes["i"] = 105] = "i";
|
|
1095
|
+
CharacterCodes[CharacterCodes["j"] = 106] = "j";
|
|
1096
|
+
CharacterCodes[CharacterCodes["k"] = 107] = "k";
|
|
1097
|
+
CharacterCodes[CharacterCodes["l"] = 108] = "l";
|
|
1098
|
+
CharacterCodes[CharacterCodes["m"] = 109] = "m";
|
|
1099
|
+
CharacterCodes[CharacterCodes["n"] = 110] = "n";
|
|
1100
|
+
CharacterCodes[CharacterCodes["o"] = 111] = "o";
|
|
1101
|
+
CharacterCodes[CharacterCodes["p"] = 112] = "p";
|
|
1102
|
+
CharacterCodes[CharacterCodes["q"] = 113] = "q";
|
|
1103
|
+
CharacterCodes[CharacterCodes["r"] = 114] = "r";
|
|
1104
|
+
CharacterCodes[CharacterCodes["s"] = 115] = "s";
|
|
1105
|
+
CharacterCodes[CharacterCodes["t"] = 116] = "t";
|
|
1106
|
+
CharacterCodes[CharacterCodes["u"] = 117] = "u";
|
|
1107
|
+
CharacterCodes[CharacterCodes["v"] = 118] = "v";
|
|
1108
|
+
CharacterCodes[CharacterCodes["w"] = 119] = "w";
|
|
1109
|
+
CharacterCodes[CharacterCodes["x"] = 120] = "x";
|
|
1110
|
+
CharacterCodes[CharacterCodes["y"] = 121] = "y";
|
|
1111
|
+
CharacterCodes[CharacterCodes["z"] = 122] = "z";
|
|
1112
|
+
CharacterCodes[CharacterCodes["A"] = 65] = "A";
|
|
1113
|
+
CharacterCodes[CharacterCodes["B"] = 66] = "B";
|
|
1114
|
+
CharacterCodes[CharacterCodes["C"] = 67] = "C";
|
|
1115
|
+
CharacterCodes[CharacterCodes["D"] = 68] = "D";
|
|
1116
|
+
CharacterCodes[CharacterCodes["E"] = 69] = "E";
|
|
1117
|
+
CharacterCodes[CharacterCodes["F"] = 70] = "F";
|
|
1118
|
+
CharacterCodes[CharacterCodes["G"] = 71] = "G";
|
|
1119
|
+
CharacterCodes[CharacterCodes["H"] = 72] = "H";
|
|
1120
|
+
CharacterCodes[CharacterCodes["I"] = 73] = "I";
|
|
1121
|
+
CharacterCodes[CharacterCodes["J"] = 74] = "J";
|
|
1122
|
+
CharacterCodes[CharacterCodes["K"] = 75] = "K";
|
|
1123
|
+
CharacterCodes[CharacterCodes["L"] = 76] = "L";
|
|
1124
|
+
CharacterCodes[CharacterCodes["M"] = 77] = "M";
|
|
1125
|
+
CharacterCodes[CharacterCodes["N"] = 78] = "N";
|
|
1126
|
+
CharacterCodes[CharacterCodes["O"] = 79] = "O";
|
|
1127
|
+
CharacterCodes[CharacterCodes["P"] = 80] = "P";
|
|
1128
|
+
CharacterCodes[CharacterCodes["Q"] = 81] = "Q";
|
|
1129
|
+
CharacterCodes[CharacterCodes["R"] = 82] = "R";
|
|
1130
|
+
CharacterCodes[CharacterCodes["S"] = 83] = "S";
|
|
1131
|
+
CharacterCodes[CharacterCodes["T"] = 84] = "T";
|
|
1132
|
+
CharacterCodes[CharacterCodes["U"] = 85] = "U";
|
|
1133
|
+
CharacterCodes[CharacterCodes["V"] = 86] = "V";
|
|
1134
|
+
CharacterCodes[CharacterCodes["W"] = 87] = "W";
|
|
1135
|
+
CharacterCodes[CharacterCodes["X"] = 88] = "X";
|
|
1136
|
+
CharacterCodes[CharacterCodes["Y"] = 89] = "Y";
|
|
1137
|
+
CharacterCodes[CharacterCodes["Z"] = 90] = "Z";
|
|
1138
|
+
CharacterCodes[CharacterCodes["asterisk"] = 42] = "asterisk";
|
|
1139
|
+
CharacterCodes[CharacterCodes["backslash"] = 92] = "backslash";
|
|
1140
|
+
CharacterCodes[CharacterCodes["closeBrace"] = 125] = "closeBrace";
|
|
1141
|
+
CharacterCodes[CharacterCodes["closeBracket"] = 93] = "closeBracket";
|
|
1142
|
+
CharacterCodes[CharacterCodes["colon"] = 58] = "colon";
|
|
1143
|
+
CharacterCodes[CharacterCodes["comma"] = 44] = "comma";
|
|
1144
|
+
CharacterCodes[CharacterCodes["dot"] = 46] = "dot";
|
|
1145
|
+
CharacterCodes[CharacterCodes["doubleQuote"] = 34] = "doubleQuote";
|
|
1146
|
+
CharacterCodes[CharacterCodes["minus"] = 45] = "minus";
|
|
1147
|
+
CharacterCodes[CharacterCodes["openBrace"] = 123] = "openBrace";
|
|
1148
|
+
CharacterCodes[CharacterCodes["openBracket"] = 91] = "openBracket";
|
|
1149
|
+
CharacterCodes[CharacterCodes["plus"] = 43] = "plus";
|
|
1150
|
+
CharacterCodes[CharacterCodes["slash"] = 47] = "slash";
|
|
1151
|
+
CharacterCodes[CharacterCodes["formFeed"] = 12] = "formFeed";
|
|
1152
|
+
CharacterCodes[CharacterCodes["tab"] = 9] = "tab";
|
|
1153
|
+
})(CharacterCodes || (CharacterCodes = {}));
|
|
1154
|
+
|
|
1155
|
+
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/string-intern.js
|
|
1156
|
+
var cachedSpaces = new Array(20).fill(0).map((_, index) => {
|
|
1157
|
+
return " ".repeat(index);
|
|
1158
|
+
});
|
|
1159
|
+
var maxCachedValues = 200;
|
|
1160
|
+
var cachedBreakLinesWithSpaces = {
|
|
1161
|
+
" ": {
|
|
1162
|
+
"\n": new Array(maxCachedValues).fill(0).map((_, index) => {
|
|
1163
|
+
return `
|
|
1164
|
+
` + " ".repeat(index);
|
|
1165
|
+
}),
|
|
1166
|
+
"\r": new Array(maxCachedValues).fill(0).map((_, index) => {
|
|
1167
|
+
return "\r" + " ".repeat(index);
|
|
1168
|
+
}),
|
|
1169
|
+
"\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
|
|
1170
|
+
return `\r
|
|
1171
|
+
` + " ".repeat(index);
|
|
1172
|
+
})
|
|
1173
|
+
},
|
|
1174
|
+
"\t": {
|
|
1175
|
+
"\n": new Array(maxCachedValues).fill(0).map((_, index) => {
|
|
1176
|
+
return `
|
|
1177
|
+
` + "\t".repeat(index);
|
|
1178
|
+
}),
|
|
1179
|
+
"\r": new Array(maxCachedValues).fill(0).map((_, index) => {
|
|
1180
|
+
return "\r" + "\t".repeat(index);
|
|
1181
|
+
}),
|
|
1182
|
+
"\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
|
|
1183
|
+
return `\r
|
|
1184
|
+
` + "\t".repeat(index);
|
|
1185
|
+
})
|
|
1186
|
+
}
|
|
1187
|
+
};
|
|
1188
|
+
var supportedEols = [`
|
|
1189
|
+
`, "\r", `\r
|
|
1190
|
+
`];
|
|
1191
|
+
|
|
1192
|
+
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/format.js
|
|
1193
|
+
function format(documentText, range, options) {
|
|
1194
|
+
let initialIndentLevel;
|
|
1195
|
+
let formatText;
|
|
1196
|
+
let formatTextStart;
|
|
1197
|
+
let rangeStart;
|
|
1198
|
+
let rangeEnd;
|
|
1199
|
+
if (range) {
|
|
1200
|
+
rangeStart = range.offset;
|
|
1201
|
+
rangeEnd = rangeStart + range.length;
|
|
1202
|
+
formatTextStart = rangeStart;
|
|
1203
|
+
while (formatTextStart > 0 && !isEOL(documentText, formatTextStart - 1)) {
|
|
1204
|
+
formatTextStart--;
|
|
1205
|
+
}
|
|
1206
|
+
let endOffset = rangeEnd;
|
|
1207
|
+
while (endOffset < documentText.length && !isEOL(documentText, endOffset)) {
|
|
1208
|
+
endOffset++;
|
|
1209
|
+
}
|
|
1210
|
+
formatText = documentText.substring(formatTextStart, endOffset);
|
|
1211
|
+
initialIndentLevel = computeIndentLevel(formatText, options);
|
|
1212
|
+
} else {
|
|
1213
|
+
formatText = documentText;
|
|
1214
|
+
initialIndentLevel = 0;
|
|
1215
|
+
formatTextStart = 0;
|
|
1216
|
+
rangeStart = 0;
|
|
1217
|
+
rangeEnd = documentText.length;
|
|
1218
|
+
}
|
|
1219
|
+
const eol = getEOL(options, documentText);
|
|
1220
|
+
const eolFastPathSupported = supportedEols.includes(eol);
|
|
1221
|
+
let numberLineBreaks = 0;
|
|
1222
|
+
let indentLevel = 0;
|
|
1223
|
+
let indentValue;
|
|
1224
|
+
if (options.insertSpaces) {
|
|
1225
|
+
indentValue = cachedSpaces[options.tabSize || 4] ?? repeat(cachedSpaces[1], options.tabSize || 4);
|
|
1226
|
+
} else {
|
|
1227
|
+
indentValue = "\t";
|
|
1228
|
+
}
|
|
1229
|
+
const indentType = indentValue === "\t" ? "\t" : " ";
|
|
1230
|
+
let scanner = createScanner(formatText, false);
|
|
1231
|
+
let hasError = false;
|
|
1232
|
+
function newLinesAndIndent() {
|
|
1233
|
+
if (numberLineBreaks > 1) {
|
|
1234
|
+
return repeat(eol, numberLineBreaks) + repeat(indentValue, initialIndentLevel + indentLevel);
|
|
1235
|
+
}
|
|
1236
|
+
const amountOfSpaces = indentValue.length * (initialIndentLevel + indentLevel);
|
|
1237
|
+
if (!eolFastPathSupported || amountOfSpaces > cachedBreakLinesWithSpaces[indentType][eol].length) {
|
|
1238
|
+
return eol + repeat(indentValue, initialIndentLevel + indentLevel);
|
|
1239
|
+
}
|
|
1240
|
+
if (amountOfSpaces <= 0) {
|
|
1241
|
+
return eol;
|
|
1242
|
+
}
|
|
1243
|
+
return cachedBreakLinesWithSpaces[indentType][eol][amountOfSpaces];
|
|
1244
|
+
}
|
|
1245
|
+
function scanNext() {
|
|
1246
|
+
let token = scanner.scan();
|
|
1247
|
+
numberLineBreaks = 0;
|
|
1248
|
+
while (token === 15 || token === 14) {
|
|
1249
|
+
if (token === 14 && options.keepLines) {
|
|
1250
|
+
numberLineBreaks += 1;
|
|
1251
|
+
} else if (token === 14) {
|
|
1252
|
+
numberLineBreaks = 1;
|
|
1253
|
+
}
|
|
1254
|
+
token = scanner.scan();
|
|
1255
|
+
}
|
|
1256
|
+
hasError = token === 16 || scanner.getTokenError() !== 0;
|
|
1257
|
+
return token;
|
|
1258
|
+
}
|
|
1259
|
+
const editOperations = [];
|
|
1260
|
+
function addEdit(text, startOffset, endOffset) {
|
|
1261
|
+
if (!hasError && (!range || startOffset < rangeEnd && endOffset > rangeStart) && documentText.substring(startOffset, endOffset) !== text) {
|
|
1262
|
+
editOperations.push({ offset: startOffset, length: endOffset - startOffset, content: text });
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
let firstToken = scanNext();
|
|
1266
|
+
if (options.keepLines && numberLineBreaks > 0) {
|
|
1267
|
+
addEdit(repeat(eol, numberLineBreaks), 0, 0);
|
|
1268
|
+
}
|
|
1269
|
+
if (firstToken !== 17) {
|
|
1270
|
+
let firstTokenStart = scanner.getTokenOffset() + formatTextStart;
|
|
1271
|
+
let initialIndent = indentValue.length * initialIndentLevel < 20 && options.insertSpaces ? cachedSpaces[indentValue.length * initialIndentLevel] : repeat(indentValue, initialIndentLevel);
|
|
1272
|
+
addEdit(initialIndent, formatTextStart, firstTokenStart);
|
|
1273
|
+
}
|
|
1274
|
+
while (firstToken !== 17) {
|
|
1275
|
+
let firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;
|
|
1276
|
+
let secondToken = scanNext();
|
|
1277
|
+
let replaceContent = "";
|
|
1278
|
+
let needsLineBreak = false;
|
|
1279
|
+
while (numberLineBreaks === 0 && (secondToken === 12 || secondToken === 13)) {
|
|
1280
|
+
let commentTokenStart = scanner.getTokenOffset() + formatTextStart;
|
|
1281
|
+
addEdit(cachedSpaces[1], firstTokenEnd, commentTokenStart);
|
|
1282
|
+
firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;
|
|
1283
|
+
needsLineBreak = secondToken === 12;
|
|
1284
|
+
replaceContent = needsLineBreak ? newLinesAndIndent() : "";
|
|
1285
|
+
secondToken = scanNext();
|
|
1286
|
+
}
|
|
1287
|
+
if (secondToken === 2) {
|
|
1288
|
+
if (firstToken !== 1) {
|
|
1289
|
+
indentLevel--;
|
|
1290
|
+
}
|
|
1291
|
+
if (options.keepLines && numberLineBreaks > 0 || !options.keepLines && firstToken !== 1) {
|
|
1292
|
+
replaceContent = newLinesAndIndent();
|
|
1293
|
+
} else if (options.keepLines) {
|
|
1294
|
+
replaceContent = cachedSpaces[1];
|
|
1295
|
+
}
|
|
1296
|
+
} else if (secondToken === 4) {
|
|
1297
|
+
if (firstToken !== 3) {
|
|
1298
|
+
indentLevel--;
|
|
1299
|
+
}
|
|
1300
|
+
if (options.keepLines && numberLineBreaks > 0 || !options.keepLines && firstToken !== 3) {
|
|
1301
|
+
replaceContent = newLinesAndIndent();
|
|
1302
|
+
} else if (options.keepLines) {
|
|
1303
|
+
replaceContent = cachedSpaces[1];
|
|
1304
|
+
}
|
|
1305
|
+
} else {
|
|
1306
|
+
switch (firstToken) {
|
|
1307
|
+
case 3:
|
|
1308
|
+
case 1:
|
|
1309
|
+
indentLevel++;
|
|
1310
|
+
if (options.keepLines && numberLineBreaks > 0 || !options.keepLines) {
|
|
1311
|
+
replaceContent = newLinesAndIndent();
|
|
1312
|
+
} else {
|
|
1313
|
+
replaceContent = cachedSpaces[1];
|
|
1314
|
+
}
|
|
1315
|
+
break;
|
|
1316
|
+
case 5:
|
|
1317
|
+
if (options.keepLines && numberLineBreaks > 0 || !options.keepLines) {
|
|
1318
|
+
replaceContent = newLinesAndIndent();
|
|
1319
|
+
} else {
|
|
1320
|
+
replaceContent = cachedSpaces[1];
|
|
1321
|
+
}
|
|
1322
|
+
break;
|
|
1323
|
+
case 12:
|
|
1324
|
+
replaceContent = newLinesAndIndent();
|
|
1325
|
+
break;
|
|
1326
|
+
case 13:
|
|
1327
|
+
if (numberLineBreaks > 0) {
|
|
1328
|
+
replaceContent = newLinesAndIndent();
|
|
1329
|
+
} else if (!needsLineBreak) {
|
|
1330
|
+
replaceContent = cachedSpaces[1];
|
|
1331
|
+
}
|
|
1332
|
+
break;
|
|
1333
|
+
case 6:
|
|
1334
|
+
if (options.keepLines && numberLineBreaks > 0) {
|
|
1335
|
+
replaceContent = newLinesAndIndent();
|
|
1336
|
+
} else if (!needsLineBreak) {
|
|
1337
|
+
replaceContent = cachedSpaces[1];
|
|
1338
|
+
}
|
|
1339
|
+
break;
|
|
1340
|
+
case 10:
|
|
1341
|
+
if (options.keepLines && numberLineBreaks > 0) {
|
|
1342
|
+
replaceContent = newLinesAndIndent();
|
|
1343
|
+
} else if (secondToken === 6 && !needsLineBreak) {
|
|
1344
|
+
replaceContent = "";
|
|
1345
|
+
}
|
|
1346
|
+
break;
|
|
1347
|
+
case 7:
|
|
1348
|
+
case 8:
|
|
1349
|
+
case 9:
|
|
1350
|
+
case 11:
|
|
1351
|
+
case 2:
|
|
1352
|
+
case 4:
|
|
1353
|
+
if (options.keepLines && numberLineBreaks > 0) {
|
|
1354
|
+
replaceContent = newLinesAndIndent();
|
|
1355
|
+
} else {
|
|
1356
|
+
if ((secondToken === 12 || secondToken === 13) && !needsLineBreak) {
|
|
1357
|
+
replaceContent = cachedSpaces[1];
|
|
1358
|
+
} else if (secondToken !== 5 && secondToken !== 17) {
|
|
1359
|
+
hasError = true;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
break;
|
|
1363
|
+
case 16:
|
|
1364
|
+
hasError = true;
|
|
1365
|
+
break;
|
|
1366
|
+
}
|
|
1367
|
+
if (numberLineBreaks > 0 && (secondToken === 12 || secondToken === 13)) {
|
|
1368
|
+
replaceContent = newLinesAndIndent();
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
if (secondToken === 17) {
|
|
1372
|
+
if (options.keepLines && numberLineBreaks > 0) {
|
|
1373
|
+
replaceContent = newLinesAndIndent();
|
|
1374
|
+
} else {
|
|
1375
|
+
replaceContent = options.insertFinalNewline ? eol : "";
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
const secondTokenStart = scanner.getTokenOffset() + formatTextStart;
|
|
1379
|
+
addEdit(replaceContent, firstTokenEnd, secondTokenStart);
|
|
1380
|
+
firstToken = secondToken;
|
|
1381
|
+
}
|
|
1382
|
+
return editOperations;
|
|
1383
|
+
}
|
|
1384
|
+
function repeat(s, count) {
|
|
1385
|
+
let result = "";
|
|
1386
|
+
for (let i = 0;i < count; i++) {
|
|
1387
|
+
result += s;
|
|
1388
|
+
}
|
|
1389
|
+
return result;
|
|
1390
|
+
}
|
|
1391
|
+
function computeIndentLevel(content, options) {
|
|
1392
|
+
let i = 0;
|
|
1393
|
+
let nChars = 0;
|
|
1394
|
+
const tabSize = options.tabSize || 4;
|
|
1395
|
+
while (i < content.length) {
|
|
1396
|
+
let ch = content.charAt(i);
|
|
1397
|
+
if (ch === cachedSpaces[1]) {
|
|
1398
|
+
nChars++;
|
|
1399
|
+
} else if (ch === "\t") {
|
|
1400
|
+
nChars += tabSize;
|
|
1401
|
+
} else {
|
|
1402
|
+
break;
|
|
1403
|
+
}
|
|
1404
|
+
i++;
|
|
1405
|
+
}
|
|
1406
|
+
return Math.floor(nChars / tabSize);
|
|
1407
|
+
}
|
|
1408
|
+
function getEOL(options, text) {
|
|
1409
|
+
for (let i = 0;i < text.length; i++) {
|
|
1410
|
+
const ch = text.charAt(i);
|
|
1411
|
+
if (ch === "\r") {
|
|
1412
|
+
if (i + 1 < text.length && text.charAt(i + 1) === `
|
|
1413
|
+
`) {
|
|
1414
|
+
return `\r
|
|
1415
|
+
`;
|
|
1416
|
+
}
|
|
1417
|
+
return "\r";
|
|
1418
|
+
} else if (ch === `
|
|
1419
|
+
`) {
|
|
1420
|
+
return `
|
|
1421
|
+
`;
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
return options && options.eol || `
|
|
1425
|
+
`;
|
|
1426
|
+
}
|
|
1427
|
+
function isEOL(text, offset) {
|
|
1428
|
+
return `\r
|
|
1429
|
+
`.indexOf(text.charAt(offset)) !== -1;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/parser.js
|
|
1433
|
+
var ParseOptions;
|
|
1434
|
+
(function(ParseOptions) {
|
|
1435
|
+
ParseOptions.DEFAULT = {
|
|
1436
|
+
allowTrailingComma: false
|
|
1437
|
+
};
|
|
1438
|
+
})(ParseOptions || (ParseOptions = {}));
|
|
1439
|
+
function parse(text, errors = [], options = ParseOptions.DEFAULT) {
|
|
1440
|
+
let currentProperty = null;
|
|
1441
|
+
let currentParent = [];
|
|
1442
|
+
const previousParents = [];
|
|
1443
|
+
function onValue(value) {
|
|
1444
|
+
if (Array.isArray(currentParent)) {
|
|
1445
|
+
currentParent.push(value);
|
|
1446
|
+
} else if (currentProperty !== null) {
|
|
1447
|
+
currentParent[currentProperty] = value;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
const visitor = {
|
|
1451
|
+
onObjectBegin: () => {
|
|
1452
|
+
const object = {};
|
|
1453
|
+
onValue(object);
|
|
1454
|
+
previousParents.push(currentParent);
|
|
1455
|
+
currentParent = object;
|
|
1456
|
+
currentProperty = null;
|
|
1457
|
+
},
|
|
1458
|
+
onObjectProperty: (name) => {
|
|
1459
|
+
currentProperty = name;
|
|
1460
|
+
},
|
|
1461
|
+
onObjectEnd: () => {
|
|
1462
|
+
currentParent = previousParents.pop();
|
|
1463
|
+
},
|
|
1464
|
+
onArrayBegin: () => {
|
|
1465
|
+
const array = [];
|
|
1466
|
+
onValue(array);
|
|
1467
|
+
previousParents.push(currentParent);
|
|
1468
|
+
currentParent = array;
|
|
1469
|
+
currentProperty = null;
|
|
1470
|
+
},
|
|
1471
|
+
onArrayEnd: () => {
|
|
1472
|
+
currentParent = previousParents.pop();
|
|
1473
|
+
},
|
|
1474
|
+
onLiteralValue: onValue,
|
|
1475
|
+
onError: (error, offset, length) => {
|
|
1476
|
+
errors.push({ error, offset, length });
|
|
1477
|
+
}
|
|
1478
|
+
};
|
|
1479
|
+
visit(text, visitor, options);
|
|
1480
|
+
return currentParent[0];
|
|
1481
|
+
}
|
|
1482
|
+
function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {
|
|
1483
|
+
let currentParent = { type: "array", offset: -1, length: -1, children: [], parent: undefined };
|
|
1484
|
+
function ensurePropertyComplete(endOffset) {
|
|
1485
|
+
if (currentParent.type === "property") {
|
|
1486
|
+
currentParent.length = endOffset - currentParent.offset;
|
|
1487
|
+
currentParent = currentParent.parent;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
function onValue(valueNode) {
|
|
1491
|
+
currentParent.children.push(valueNode);
|
|
1492
|
+
return valueNode;
|
|
1493
|
+
}
|
|
1494
|
+
const visitor = {
|
|
1495
|
+
onObjectBegin: (offset) => {
|
|
1496
|
+
currentParent = onValue({ type: "object", offset, length: -1, parent: currentParent, children: [] });
|
|
1497
|
+
},
|
|
1498
|
+
onObjectProperty: (name, offset, length) => {
|
|
1499
|
+
currentParent = onValue({ type: "property", offset, length: -1, parent: currentParent, children: [] });
|
|
1500
|
+
currentParent.children.push({ type: "string", value: name, offset, length, parent: currentParent });
|
|
1501
|
+
},
|
|
1502
|
+
onObjectEnd: (offset, length) => {
|
|
1503
|
+
ensurePropertyComplete(offset + length);
|
|
1504
|
+
currentParent.length = offset + length - currentParent.offset;
|
|
1505
|
+
currentParent = currentParent.parent;
|
|
1506
|
+
ensurePropertyComplete(offset + length);
|
|
1507
|
+
},
|
|
1508
|
+
onArrayBegin: (offset, length) => {
|
|
1509
|
+
currentParent = onValue({ type: "array", offset, length: -1, parent: currentParent, children: [] });
|
|
1510
|
+
},
|
|
1511
|
+
onArrayEnd: (offset, length) => {
|
|
1512
|
+
currentParent.length = offset + length - currentParent.offset;
|
|
1513
|
+
currentParent = currentParent.parent;
|
|
1514
|
+
ensurePropertyComplete(offset + length);
|
|
1515
|
+
},
|
|
1516
|
+
onLiteralValue: (value, offset, length) => {
|
|
1517
|
+
onValue({ type: getNodeType(value), offset, length, parent: currentParent, value });
|
|
1518
|
+
ensurePropertyComplete(offset + length);
|
|
1519
|
+
},
|
|
1520
|
+
onSeparator: (sep, offset, length) => {
|
|
1521
|
+
if (currentParent.type === "property") {
|
|
1522
|
+
if (sep === ":") {
|
|
1523
|
+
currentParent.colonOffset = offset;
|
|
1524
|
+
} else if (sep === ",") {
|
|
1525
|
+
ensurePropertyComplete(offset);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
},
|
|
1529
|
+
onError: (error, offset, length) => {
|
|
1530
|
+
errors.push({ error, offset, length });
|
|
1531
|
+
}
|
|
1532
|
+
};
|
|
1533
|
+
visit(text, visitor, options);
|
|
1534
|
+
const result = currentParent.children[0];
|
|
1535
|
+
if (result) {
|
|
1536
|
+
delete result.parent;
|
|
1537
|
+
}
|
|
1538
|
+
return result;
|
|
1539
|
+
}
|
|
1540
|
+
function findNodeAtLocation(root, path) {
|
|
1541
|
+
if (!root) {
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
let node = root;
|
|
1545
|
+
for (let segment of path) {
|
|
1546
|
+
if (typeof segment === "string") {
|
|
1547
|
+
if (node.type !== "object" || !Array.isArray(node.children)) {
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
let found = false;
|
|
1551
|
+
for (const propertyNode of node.children) {
|
|
1552
|
+
if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === segment && propertyNode.children.length === 2) {
|
|
1553
|
+
node = propertyNode.children[1];
|
|
1554
|
+
found = true;
|
|
1555
|
+
break;
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
if (!found) {
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
} else {
|
|
1562
|
+
const index = segment;
|
|
1563
|
+
if (node.type !== "array" || index < 0 || !Array.isArray(node.children) || index >= node.children.length) {
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
node = node.children[index];
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
return node;
|
|
1570
|
+
}
|
|
1571
|
+
function getNodeValue(node) {
|
|
1572
|
+
switch (node.type) {
|
|
1573
|
+
case "array":
|
|
1574
|
+
return node.children.map(getNodeValue);
|
|
1575
|
+
case "object":
|
|
1576
|
+
const obj = Object.create(null);
|
|
1577
|
+
for (let prop of node.children) {
|
|
1578
|
+
const valueNode = prop.children[1];
|
|
1579
|
+
if (valueNode) {
|
|
1580
|
+
obj[prop.children[0].value] = getNodeValue(valueNode);
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
return obj;
|
|
1584
|
+
case "null":
|
|
1585
|
+
case "string":
|
|
1586
|
+
case "number":
|
|
1587
|
+
case "boolean":
|
|
1588
|
+
return node.value;
|
|
1589
|
+
default:
|
|
1590
|
+
return;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
1594
|
+
const _scanner = createScanner(text, false);
|
|
1595
|
+
const _jsonPath = [];
|
|
1596
|
+
let suppressedCallbacks = 0;
|
|
1597
|
+
function toNoArgVisit(visitFunction) {
|
|
1598
|
+
return visitFunction ? () => suppressedCallbacks === 0 && visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
|
|
1599
|
+
}
|
|
1600
|
+
function toOneArgVisit(visitFunction) {
|
|
1601
|
+
return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
|
|
1602
|
+
}
|
|
1603
|
+
function toOneArgVisitWithPath(visitFunction) {
|
|
1604
|
+
return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) : () => true;
|
|
1605
|
+
}
|
|
1606
|
+
function toBeginVisit(visitFunction) {
|
|
1607
|
+
return visitFunction ? () => {
|
|
1608
|
+
if (suppressedCallbacks > 0) {
|
|
1609
|
+
suppressedCallbacks++;
|
|
1610
|
+
} else {
|
|
1611
|
+
let cbReturn = visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice());
|
|
1612
|
+
if (cbReturn === false) {
|
|
1613
|
+
suppressedCallbacks = 1;
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
} : () => true;
|
|
1617
|
+
}
|
|
1618
|
+
function toEndVisit(visitFunction) {
|
|
1619
|
+
return visitFunction ? () => {
|
|
1620
|
+
if (suppressedCallbacks > 0) {
|
|
1621
|
+
suppressedCallbacks--;
|
|
1622
|
+
}
|
|
1623
|
+
if (suppressedCallbacks === 0) {
|
|
1624
|
+
visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());
|
|
1625
|
+
}
|
|
1626
|
+
} : () => true;
|
|
1627
|
+
}
|
|
1628
|
+
const onObjectBegin = toBeginVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty), onObjectEnd = toEndVisit(visitor.onObjectEnd), onArrayBegin = toBeginVisit(visitor.onArrayBegin), onArrayEnd = toEndVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);
|
|
1629
|
+
const disallowComments = options && options.disallowComments;
|
|
1630
|
+
const allowTrailingComma = options && options.allowTrailingComma;
|
|
1631
|
+
function scanNext() {
|
|
1632
|
+
while (true) {
|
|
1633
|
+
const token = _scanner.scan();
|
|
1634
|
+
switch (_scanner.getTokenError()) {
|
|
1635
|
+
case 4:
|
|
1636
|
+
handleError(14);
|
|
1637
|
+
break;
|
|
1638
|
+
case 5:
|
|
1639
|
+
handleError(15);
|
|
1640
|
+
break;
|
|
1641
|
+
case 3:
|
|
1642
|
+
handleError(13);
|
|
1643
|
+
break;
|
|
1644
|
+
case 1:
|
|
1645
|
+
if (!disallowComments) {
|
|
1646
|
+
handleError(11);
|
|
1647
|
+
}
|
|
1648
|
+
break;
|
|
1649
|
+
case 2:
|
|
1650
|
+
handleError(12);
|
|
1651
|
+
break;
|
|
1652
|
+
case 6:
|
|
1653
|
+
handleError(16);
|
|
1654
|
+
break;
|
|
1655
|
+
}
|
|
1656
|
+
switch (token) {
|
|
1657
|
+
case 12:
|
|
1658
|
+
case 13:
|
|
1659
|
+
if (disallowComments) {
|
|
1660
|
+
handleError(10);
|
|
1661
|
+
} else {
|
|
1662
|
+
onComment();
|
|
1663
|
+
}
|
|
1664
|
+
break;
|
|
1665
|
+
case 16:
|
|
1666
|
+
handleError(1);
|
|
1667
|
+
break;
|
|
1668
|
+
case 15:
|
|
1669
|
+
case 14:
|
|
1670
|
+
break;
|
|
1671
|
+
default:
|
|
1672
|
+
return token;
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
function handleError(error, skipUntilAfter = [], skipUntil = []) {
|
|
1677
|
+
onError(error);
|
|
1678
|
+
if (skipUntilAfter.length + skipUntil.length > 0) {
|
|
1679
|
+
let token = _scanner.getToken();
|
|
1680
|
+
while (token !== 17) {
|
|
1681
|
+
if (skipUntilAfter.indexOf(token) !== -1) {
|
|
1682
|
+
scanNext();
|
|
1683
|
+
break;
|
|
1684
|
+
} else if (skipUntil.indexOf(token) !== -1) {
|
|
1685
|
+
break;
|
|
1686
|
+
}
|
|
1687
|
+
token = scanNext();
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
function parseString(isValue) {
|
|
1692
|
+
const value = _scanner.getTokenValue();
|
|
1693
|
+
if (isValue) {
|
|
1694
|
+
onLiteralValue(value);
|
|
1695
|
+
} else {
|
|
1696
|
+
onObjectProperty(value);
|
|
1697
|
+
_jsonPath.push(value);
|
|
1698
|
+
}
|
|
1699
|
+
scanNext();
|
|
1700
|
+
return true;
|
|
1701
|
+
}
|
|
1702
|
+
function parseLiteral() {
|
|
1703
|
+
switch (_scanner.getToken()) {
|
|
1704
|
+
case 11:
|
|
1705
|
+
const tokenValue = _scanner.getTokenValue();
|
|
1706
|
+
let value = Number(tokenValue);
|
|
1707
|
+
if (isNaN(value)) {
|
|
1708
|
+
handleError(2);
|
|
1709
|
+
value = 0;
|
|
1710
|
+
}
|
|
1711
|
+
onLiteralValue(value);
|
|
1712
|
+
break;
|
|
1713
|
+
case 7:
|
|
1714
|
+
onLiteralValue(null);
|
|
1715
|
+
break;
|
|
1716
|
+
case 8:
|
|
1717
|
+
onLiteralValue(true);
|
|
1718
|
+
break;
|
|
1719
|
+
case 9:
|
|
1720
|
+
onLiteralValue(false);
|
|
1721
|
+
break;
|
|
1722
|
+
default:
|
|
1723
|
+
return false;
|
|
1724
|
+
}
|
|
1725
|
+
scanNext();
|
|
1726
|
+
return true;
|
|
1727
|
+
}
|
|
1728
|
+
function parseProperty() {
|
|
1729
|
+
if (_scanner.getToken() !== 10) {
|
|
1730
|
+
handleError(3, [], [2, 5]);
|
|
1731
|
+
return false;
|
|
1732
|
+
}
|
|
1733
|
+
parseString(false);
|
|
1734
|
+
if (_scanner.getToken() === 6) {
|
|
1735
|
+
onSeparator(":");
|
|
1736
|
+
scanNext();
|
|
1737
|
+
if (!parseValue()) {
|
|
1738
|
+
handleError(4, [], [2, 5]);
|
|
1739
|
+
}
|
|
1740
|
+
} else {
|
|
1741
|
+
handleError(5, [], [2, 5]);
|
|
1742
|
+
}
|
|
1743
|
+
_jsonPath.pop();
|
|
1744
|
+
return true;
|
|
1745
|
+
}
|
|
1746
|
+
function parseObject() {
|
|
1747
|
+
onObjectBegin();
|
|
1748
|
+
scanNext();
|
|
1749
|
+
let needsComma = false;
|
|
1750
|
+
while (_scanner.getToken() !== 2 && _scanner.getToken() !== 17) {
|
|
1751
|
+
if (_scanner.getToken() === 5) {
|
|
1752
|
+
if (!needsComma) {
|
|
1753
|
+
handleError(4, [], []);
|
|
1754
|
+
}
|
|
1755
|
+
onSeparator(",");
|
|
1756
|
+
scanNext();
|
|
1757
|
+
if (_scanner.getToken() === 2 && allowTrailingComma) {
|
|
1758
|
+
break;
|
|
1759
|
+
}
|
|
1760
|
+
} else if (needsComma) {
|
|
1761
|
+
handleError(6, [], []);
|
|
1762
|
+
}
|
|
1763
|
+
if (!parseProperty()) {
|
|
1764
|
+
handleError(4, [], [2, 5]);
|
|
1765
|
+
}
|
|
1766
|
+
needsComma = true;
|
|
1767
|
+
}
|
|
1768
|
+
onObjectEnd();
|
|
1769
|
+
if (_scanner.getToken() !== 2) {
|
|
1770
|
+
handleError(7, [2], []);
|
|
1771
|
+
} else {
|
|
1772
|
+
scanNext();
|
|
1773
|
+
}
|
|
1774
|
+
return true;
|
|
1775
|
+
}
|
|
1776
|
+
function parseArray() {
|
|
1777
|
+
onArrayBegin();
|
|
1778
|
+
scanNext();
|
|
1779
|
+
let isFirstElement = true;
|
|
1780
|
+
let needsComma = false;
|
|
1781
|
+
while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) {
|
|
1782
|
+
if (_scanner.getToken() === 5) {
|
|
1783
|
+
if (!needsComma) {
|
|
1784
|
+
handleError(4, [], []);
|
|
1785
|
+
}
|
|
1786
|
+
onSeparator(",");
|
|
1787
|
+
scanNext();
|
|
1788
|
+
if (_scanner.getToken() === 4 && allowTrailingComma) {
|
|
1789
|
+
break;
|
|
1790
|
+
}
|
|
1791
|
+
} else if (needsComma) {
|
|
1792
|
+
handleError(6, [], []);
|
|
1793
|
+
}
|
|
1794
|
+
if (isFirstElement) {
|
|
1795
|
+
_jsonPath.push(0);
|
|
1796
|
+
isFirstElement = false;
|
|
1797
|
+
} else {
|
|
1798
|
+
_jsonPath[_jsonPath.length - 1]++;
|
|
1799
|
+
}
|
|
1800
|
+
if (!parseValue()) {
|
|
1801
|
+
handleError(4, [], [4, 5]);
|
|
1802
|
+
}
|
|
1803
|
+
needsComma = true;
|
|
1804
|
+
}
|
|
1805
|
+
onArrayEnd();
|
|
1806
|
+
if (!isFirstElement) {
|
|
1807
|
+
_jsonPath.pop();
|
|
1808
|
+
}
|
|
1809
|
+
if (_scanner.getToken() !== 4) {
|
|
1810
|
+
handleError(8, [4], []);
|
|
1811
|
+
} else {
|
|
1812
|
+
scanNext();
|
|
1813
|
+
}
|
|
1814
|
+
return true;
|
|
1815
|
+
}
|
|
1816
|
+
function parseValue() {
|
|
1817
|
+
switch (_scanner.getToken()) {
|
|
1818
|
+
case 3:
|
|
1819
|
+
return parseArray();
|
|
1820
|
+
case 1:
|
|
1821
|
+
return parseObject();
|
|
1822
|
+
case 10:
|
|
1823
|
+
return parseString(true);
|
|
1824
|
+
default:
|
|
1825
|
+
return parseLiteral();
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
scanNext();
|
|
1829
|
+
if (_scanner.getToken() === 17) {
|
|
1830
|
+
if (options.allowEmptyContent) {
|
|
1831
|
+
return true;
|
|
1832
|
+
}
|
|
1833
|
+
handleError(4, [], []);
|
|
1834
|
+
return false;
|
|
1835
|
+
}
|
|
1836
|
+
if (!parseValue()) {
|
|
1837
|
+
handleError(4, [], []);
|
|
1838
|
+
return false;
|
|
1839
|
+
}
|
|
1840
|
+
if (_scanner.getToken() !== 17) {
|
|
1841
|
+
handleError(9, [], []);
|
|
1842
|
+
}
|
|
1843
|
+
return true;
|
|
1844
|
+
}
|
|
1845
|
+
function getNodeType(value) {
|
|
1846
|
+
switch (typeof value) {
|
|
1847
|
+
case "boolean":
|
|
1848
|
+
return "boolean";
|
|
1849
|
+
case "number":
|
|
1850
|
+
return "number";
|
|
1851
|
+
case "string":
|
|
1852
|
+
return "string";
|
|
1853
|
+
case "object": {
|
|
1854
|
+
if (!value) {
|
|
1855
|
+
return "null";
|
|
1856
|
+
} else if (Array.isArray(value)) {
|
|
1857
|
+
return "array";
|
|
1858
|
+
}
|
|
1859
|
+
return "object";
|
|
1860
|
+
}
|
|
1861
|
+
default:
|
|
1862
|
+
return "null";
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/edit.js
|
|
1867
|
+
function setProperty(text, originalPath, value, options) {
|
|
1868
|
+
const path = originalPath.slice();
|
|
1869
|
+
const errors = [];
|
|
1870
|
+
const root = parseTree(text, errors);
|
|
1871
|
+
let parent = undefined;
|
|
1872
|
+
let lastSegment = undefined;
|
|
1873
|
+
while (path.length > 0) {
|
|
1874
|
+
lastSegment = path.pop();
|
|
1875
|
+
parent = findNodeAtLocation(root, path);
|
|
1876
|
+
if (parent === undefined && value !== undefined) {
|
|
1877
|
+
if (typeof lastSegment === "string") {
|
|
1878
|
+
value = { [lastSegment]: value };
|
|
1879
|
+
} else {
|
|
1880
|
+
value = [value];
|
|
1881
|
+
}
|
|
1882
|
+
} else {
|
|
1883
|
+
break;
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
if (!parent) {
|
|
1887
|
+
if (value === undefined) {
|
|
1888
|
+
throw new Error("Can not delete in empty document");
|
|
1889
|
+
}
|
|
1890
|
+
return withFormatting(text, { offset: root ? root.offset : 0, length: root ? root.length : 0, content: JSON.stringify(value) }, options);
|
|
1891
|
+
} else if (parent.type === "object" && typeof lastSegment === "string" && Array.isArray(parent.children)) {
|
|
1892
|
+
const existing = findNodeAtLocation(parent, [lastSegment]);
|
|
1893
|
+
if (existing !== undefined) {
|
|
1894
|
+
if (value === undefined) {
|
|
1895
|
+
if (!existing.parent) {
|
|
1896
|
+
throw new Error("Malformed AST");
|
|
1897
|
+
}
|
|
1898
|
+
const propertyIndex = parent.children.indexOf(existing.parent);
|
|
1899
|
+
let removeBegin;
|
|
1900
|
+
let removeEnd = existing.parent.offset + existing.parent.length;
|
|
1901
|
+
if (propertyIndex > 0) {
|
|
1902
|
+
let previous = parent.children[propertyIndex - 1];
|
|
1903
|
+
removeBegin = previous.offset + previous.length;
|
|
1904
|
+
} else {
|
|
1905
|
+
removeBegin = parent.offset + 1;
|
|
1906
|
+
if (parent.children.length > 1) {
|
|
1907
|
+
let next = parent.children[1];
|
|
1908
|
+
removeEnd = next.offset;
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
return withFormatting(text, { offset: removeBegin, length: removeEnd - removeBegin, content: "" }, options);
|
|
1912
|
+
} else {
|
|
1913
|
+
return withFormatting(text, { offset: existing.offset, length: existing.length, content: JSON.stringify(value) }, options);
|
|
1914
|
+
}
|
|
1915
|
+
} else {
|
|
1916
|
+
if (value === undefined) {
|
|
1917
|
+
return [];
|
|
1918
|
+
}
|
|
1919
|
+
const newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
|
|
1920
|
+
const index = options.getInsertionIndex ? options.getInsertionIndex(parent.children.map((p) => p.children[0].value)) : parent.children.length;
|
|
1921
|
+
let edit;
|
|
1922
|
+
if (index > 0) {
|
|
1923
|
+
let previous = parent.children[index - 1];
|
|
1924
|
+
edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
|
|
1925
|
+
} else if (parent.children.length === 0) {
|
|
1926
|
+
edit = { offset: parent.offset + 1, length: 0, content: newProperty };
|
|
1927
|
+
} else {
|
|
1928
|
+
edit = { offset: parent.offset + 1, length: 0, content: newProperty + "," };
|
|
1929
|
+
}
|
|
1930
|
+
return withFormatting(text, edit, options);
|
|
1931
|
+
}
|
|
1932
|
+
} else if (parent.type === "array" && typeof lastSegment === "number" && Array.isArray(parent.children)) {
|
|
1933
|
+
const insertIndex = lastSegment;
|
|
1934
|
+
if (insertIndex === -1) {
|
|
1935
|
+
const newProperty = `${JSON.stringify(value)}`;
|
|
1936
|
+
let edit;
|
|
1937
|
+
if (parent.children.length === 0) {
|
|
1938
|
+
edit = { offset: parent.offset + 1, length: 0, content: newProperty };
|
|
1939
|
+
} else {
|
|
1940
|
+
const previous = parent.children[parent.children.length - 1];
|
|
1941
|
+
edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
|
|
1942
|
+
}
|
|
1943
|
+
return withFormatting(text, edit, options);
|
|
1944
|
+
} else if (value === undefined && parent.children.length >= 0) {
|
|
1945
|
+
const removalIndex = lastSegment;
|
|
1946
|
+
const toRemove = parent.children[removalIndex];
|
|
1947
|
+
let edit;
|
|
1948
|
+
if (parent.children.length === 1) {
|
|
1949
|
+
edit = { offset: parent.offset + 1, length: parent.length - 2, content: "" };
|
|
1950
|
+
} else if (parent.children.length - 1 === removalIndex) {
|
|
1951
|
+
let previous = parent.children[removalIndex - 1];
|
|
1952
|
+
let offset = previous.offset + previous.length;
|
|
1953
|
+
let parentEndOffset = parent.offset + parent.length;
|
|
1954
|
+
edit = { offset, length: parentEndOffset - 2 - offset, content: "" };
|
|
1955
|
+
} else {
|
|
1956
|
+
edit = { offset: toRemove.offset, length: parent.children[removalIndex + 1].offset - toRemove.offset, content: "" };
|
|
1957
|
+
}
|
|
1958
|
+
return withFormatting(text, edit, options);
|
|
1959
|
+
} else if (value !== undefined) {
|
|
1960
|
+
let edit;
|
|
1961
|
+
const newProperty = `${JSON.stringify(value)}`;
|
|
1962
|
+
if (!options.isArrayInsertion && parent.children.length > lastSegment) {
|
|
1963
|
+
const toModify = parent.children[lastSegment];
|
|
1964
|
+
edit = { offset: toModify.offset, length: toModify.length, content: newProperty };
|
|
1965
|
+
} else if (parent.children.length === 0 || lastSegment === 0) {
|
|
1966
|
+
edit = { offset: parent.offset + 1, length: 0, content: parent.children.length === 0 ? newProperty : newProperty + "," };
|
|
1967
|
+
} else {
|
|
1968
|
+
const index = lastSegment > parent.children.length ? parent.children.length : lastSegment;
|
|
1969
|
+
const previous = parent.children[index - 1];
|
|
1970
|
+
edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
|
|
1971
|
+
}
|
|
1972
|
+
return withFormatting(text, edit, options);
|
|
1973
|
+
} else {
|
|
1974
|
+
throw new Error(`Can not ${value === undefined ? "remove" : options.isArrayInsertion ? "insert" : "modify"} Array index ${insertIndex} as length is not sufficient`);
|
|
1975
|
+
}
|
|
1976
|
+
} else {
|
|
1977
|
+
throw new Error(`Can not add ${typeof lastSegment !== "number" ? "index" : "property"} to parent of type ${parent.type}`);
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
function withFormatting(text, edit, options) {
|
|
1981
|
+
if (!options.formattingOptions) {
|
|
1982
|
+
return [edit];
|
|
1983
|
+
}
|
|
1984
|
+
let newText = applyEdit(text, edit);
|
|
1985
|
+
let begin = edit.offset;
|
|
1986
|
+
let end = edit.offset + edit.content.length;
|
|
1987
|
+
if (edit.length === 0 || edit.content.length === 0) {
|
|
1988
|
+
while (begin > 0 && !isEOL(newText, begin - 1)) {
|
|
1989
|
+
begin--;
|
|
1990
|
+
}
|
|
1991
|
+
while (end < newText.length && !isEOL(newText, end)) {
|
|
1992
|
+
end++;
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
const edits = format(newText, { offset: begin, length: end - begin }, { ...options.formattingOptions, keepLines: false });
|
|
1996
|
+
for (let i = edits.length - 1;i >= 0; i--) {
|
|
1997
|
+
const edit = edits[i];
|
|
1998
|
+
newText = applyEdit(newText, edit);
|
|
1999
|
+
begin = Math.min(begin, edit.offset);
|
|
2000
|
+
end = Math.max(end, edit.offset + edit.length);
|
|
2001
|
+
end += edit.content.length - edit.length;
|
|
2002
|
+
}
|
|
2003
|
+
const editLength = text.length - (newText.length - end) - begin;
|
|
2004
|
+
return [{ offset: begin, length: editLength, content: newText.substring(begin, end) }];
|
|
2005
|
+
}
|
|
2006
|
+
function applyEdit(text, edit) {
|
|
2007
|
+
return text.substring(0, edit.offset) + edit.content + text.substring(edit.offset + edit.length);
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/main.js
|
|
2011
|
+
var createScanner2 = createScanner;
|
|
2012
|
+
var ScanError;
|
|
2013
|
+
(function(ScanError) {
|
|
2014
|
+
ScanError[ScanError["None"] = 0] = "None";
|
|
2015
|
+
ScanError[ScanError["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
|
|
2016
|
+
ScanError[ScanError["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
|
|
2017
|
+
ScanError[ScanError["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
|
|
2018
|
+
ScanError[ScanError["InvalidUnicode"] = 4] = "InvalidUnicode";
|
|
2019
|
+
ScanError[ScanError["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
|
|
2020
|
+
ScanError[ScanError["InvalidCharacter"] = 6] = "InvalidCharacter";
|
|
2021
|
+
})(ScanError || (ScanError = {}));
|
|
2022
|
+
var SyntaxKind;
|
|
2023
|
+
(function(SyntaxKind) {
|
|
2024
|
+
SyntaxKind[SyntaxKind["OpenBraceToken"] = 1] = "OpenBraceToken";
|
|
2025
|
+
SyntaxKind[SyntaxKind["CloseBraceToken"] = 2] = "CloseBraceToken";
|
|
2026
|
+
SyntaxKind[SyntaxKind["OpenBracketToken"] = 3] = "OpenBracketToken";
|
|
2027
|
+
SyntaxKind[SyntaxKind["CloseBracketToken"] = 4] = "CloseBracketToken";
|
|
2028
|
+
SyntaxKind[SyntaxKind["CommaToken"] = 5] = "CommaToken";
|
|
2029
|
+
SyntaxKind[SyntaxKind["ColonToken"] = 6] = "ColonToken";
|
|
2030
|
+
SyntaxKind[SyntaxKind["NullKeyword"] = 7] = "NullKeyword";
|
|
2031
|
+
SyntaxKind[SyntaxKind["TrueKeyword"] = 8] = "TrueKeyword";
|
|
2032
|
+
SyntaxKind[SyntaxKind["FalseKeyword"] = 9] = "FalseKeyword";
|
|
2033
|
+
SyntaxKind[SyntaxKind["StringLiteral"] = 10] = "StringLiteral";
|
|
2034
|
+
SyntaxKind[SyntaxKind["NumericLiteral"] = 11] = "NumericLiteral";
|
|
2035
|
+
SyntaxKind[SyntaxKind["LineCommentTrivia"] = 12] = "LineCommentTrivia";
|
|
2036
|
+
SyntaxKind[SyntaxKind["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
|
|
2037
|
+
SyntaxKind[SyntaxKind["LineBreakTrivia"] = 14] = "LineBreakTrivia";
|
|
2038
|
+
SyntaxKind[SyntaxKind["Trivia"] = 15] = "Trivia";
|
|
2039
|
+
SyntaxKind[SyntaxKind["Unknown"] = 16] = "Unknown";
|
|
2040
|
+
SyntaxKind[SyntaxKind["EOF"] = 17] = "EOF";
|
|
2041
|
+
})(SyntaxKind || (SyntaxKind = {}));
|
|
2042
|
+
var parse2 = parse;
|
|
2043
|
+
var parseTree2 = parseTree;
|
|
2044
|
+
var findNodeAtLocation2 = findNodeAtLocation;
|
|
2045
|
+
var getNodeValue2 = getNodeValue;
|
|
2046
|
+
var ParseErrorCode;
|
|
2047
|
+
(function(ParseErrorCode) {
|
|
2048
|
+
ParseErrorCode[ParseErrorCode["InvalidSymbol"] = 1] = "InvalidSymbol";
|
|
2049
|
+
ParseErrorCode[ParseErrorCode["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
|
|
2050
|
+
ParseErrorCode[ParseErrorCode["PropertyNameExpected"] = 3] = "PropertyNameExpected";
|
|
2051
|
+
ParseErrorCode[ParseErrorCode["ValueExpected"] = 4] = "ValueExpected";
|
|
2052
|
+
ParseErrorCode[ParseErrorCode["ColonExpected"] = 5] = "ColonExpected";
|
|
2053
|
+
ParseErrorCode[ParseErrorCode["CommaExpected"] = 6] = "CommaExpected";
|
|
2054
|
+
ParseErrorCode[ParseErrorCode["CloseBraceExpected"] = 7] = "CloseBraceExpected";
|
|
2055
|
+
ParseErrorCode[ParseErrorCode["CloseBracketExpected"] = 8] = "CloseBracketExpected";
|
|
2056
|
+
ParseErrorCode[ParseErrorCode["EndOfFileExpected"] = 9] = "EndOfFileExpected";
|
|
2057
|
+
ParseErrorCode[ParseErrorCode["InvalidCommentToken"] = 10] = "InvalidCommentToken";
|
|
2058
|
+
ParseErrorCode[ParseErrorCode["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
|
|
2059
|
+
ParseErrorCode[ParseErrorCode["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
|
|
2060
|
+
ParseErrorCode[ParseErrorCode["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
|
|
2061
|
+
ParseErrorCode[ParseErrorCode["InvalidUnicode"] = 14] = "InvalidUnicode";
|
|
2062
|
+
ParseErrorCode[ParseErrorCode["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
|
|
2063
|
+
ParseErrorCode[ParseErrorCode["InvalidCharacter"] = 16] = "InvalidCharacter";
|
|
2064
|
+
})(ParseErrorCode || (ParseErrorCode = {}));
|
|
2065
|
+
function printParseErrorCode(code) {
|
|
2066
|
+
switch (code) {
|
|
2067
|
+
case 1:
|
|
2068
|
+
return "InvalidSymbol";
|
|
2069
|
+
case 2:
|
|
2070
|
+
return "InvalidNumberFormat";
|
|
2071
|
+
case 3:
|
|
2072
|
+
return "PropertyNameExpected";
|
|
2073
|
+
case 4:
|
|
2074
|
+
return "ValueExpected";
|
|
2075
|
+
case 5:
|
|
2076
|
+
return "ColonExpected";
|
|
2077
|
+
case 6:
|
|
2078
|
+
return "CommaExpected";
|
|
2079
|
+
case 7:
|
|
2080
|
+
return "CloseBraceExpected";
|
|
2081
|
+
case 8:
|
|
2082
|
+
return "CloseBracketExpected";
|
|
2083
|
+
case 9:
|
|
2084
|
+
return "EndOfFileExpected";
|
|
2085
|
+
case 10:
|
|
2086
|
+
return "InvalidCommentToken";
|
|
2087
|
+
case 11:
|
|
2088
|
+
return "UnexpectedEndOfComment";
|
|
2089
|
+
case 12:
|
|
2090
|
+
return "UnexpectedEndOfString";
|
|
2091
|
+
case 13:
|
|
2092
|
+
return "UnexpectedEndOfNumber";
|
|
2093
|
+
case 14:
|
|
2094
|
+
return "InvalidUnicode";
|
|
2095
|
+
case 15:
|
|
2096
|
+
return "InvalidEscapeCharacter";
|
|
2097
|
+
case 16:
|
|
2098
|
+
return "InvalidCharacter";
|
|
2099
|
+
}
|
|
2100
|
+
return "<unknown ParseErrorCode>";
|
|
2101
|
+
}
|
|
2102
|
+
function modify(text, path, value, options) {
|
|
2103
|
+
return setProperty(text, path, value, options);
|
|
2104
|
+
}
|
|
2105
|
+
function applyEdits(text, edits) {
|
|
2106
|
+
let sortedEdits = edits.slice(0).sort((a, b) => {
|
|
2107
|
+
const diff = a.offset - b.offset;
|
|
2108
|
+
if (diff === 0) {
|
|
2109
|
+
return a.length - b.length;
|
|
2110
|
+
}
|
|
2111
|
+
return diff;
|
|
2112
|
+
});
|
|
2113
|
+
let lastModifiedOffset = text.length;
|
|
2114
|
+
for (let i = sortedEdits.length - 1;i >= 0; i--) {
|
|
2115
|
+
let e = sortedEdits[i];
|
|
2116
|
+
if (e.offset + e.length <= lastModifiedOffset) {
|
|
2117
|
+
text = applyEdit(text, e);
|
|
2118
|
+
} else {
|
|
2119
|
+
throw new Error("Overlapping edit");
|
|
2120
|
+
}
|
|
2121
|
+
lastModifiedOffset = e.offset;
|
|
2122
|
+
}
|
|
2123
|
+
return text;
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
// src/shared/jsonc-parser.ts
|
|
2127
|
+
function stripJsonComments(content) {
|
|
2128
|
+
let result = "";
|
|
2129
|
+
let inString = false;
|
|
2130
|
+
let escaped = false;
|
|
2131
|
+
let inLineComment = false;
|
|
2132
|
+
let inBlockComment = false;
|
|
2133
|
+
for (let index = 0;index < content.length; index += 1) {
|
|
2134
|
+
const char = content[index];
|
|
2135
|
+
const next = content[index + 1];
|
|
2136
|
+
if (inLineComment) {
|
|
2137
|
+
if (char === `
|
|
2138
|
+
`) {
|
|
2139
|
+
inLineComment = false;
|
|
2140
|
+
result += char;
|
|
2141
|
+
}
|
|
2142
|
+
continue;
|
|
2143
|
+
}
|
|
2144
|
+
if (inBlockComment) {
|
|
2145
|
+
if (char === "*" && next === "/") {
|
|
2146
|
+
inBlockComment = false;
|
|
2147
|
+
index += 1;
|
|
2148
|
+
}
|
|
2149
|
+
continue;
|
|
2150
|
+
}
|
|
2151
|
+
if (inString) {
|
|
2152
|
+
result += char;
|
|
2153
|
+
if (escaped) {
|
|
2154
|
+
escaped = false;
|
|
2155
|
+
} else if (char === "\\") {
|
|
2156
|
+
escaped = true;
|
|
2157
|
+
} else if (char === '"') {
|
|
2158
|
+
inString = false;
|
|
2159
|
+
}
|
|
2160
|
+
continue;
|
|
2161
|
+
}
|
|
2162
|
+
if (char === '"') {
|
|
2163
|
+
inString = true;
|
|
2164
|
+
result += char;
|
|
2165
|
+
continue;
|
|
2166
|
+
}
|
|
2167
|
+
if (char === "/" && next === "/") {
|
|
2168
|
+
inLineComment = true;
|
|
2169
|
+
index += 1;
|
|
2170
|
+
continue;
|
|
2171
|
+
}
|
|
2172
|
+
if (char === "/" && next === "*") {
|
|
2173
|
+
inBlockComment = true;
|
|
2174
|
+
index += 1;
|
|
2175
|
+
continue;
|
|
2176
|
+
}
|
|
2177
|
+
result += char;
|
|
2178
|
+
}
|
|
2179
|
+
return result;
|
|
2180
|
+
}
|
|
2181
|
+
function stripTrailingCommas(content) {
|
|
2182
|
+
let result = "";
|
|
2183
|
+
let inString = false;
|
|
2184
|
+
let escaped = false;
|
|
2185
|
+
for (let index = 0;index < content.length; index += 1) {
|
|
2186
|
+
const char = content[index];
|
|
2187
|
+
if (inString) {
|
|
2188
|
+
result += char;
|
|
2189
|
+
if (escaped) {
|
|
2190
|
+
escaped = false;
|
|
2191
|
+
} else if (char === "\\") {
|
|
2192
|
+
escaped = true;
|
|
2193
|
+
} else if (char === '"') {
|
|
2194
|
+
inString = false;
|
|
2195
|
+
}
|
|
2196
|
+
continue;
|
|
2197
|
+
}
|
|
2198
|
+
if (char === '"') {
|
|
2199
|
+
inString = true;
|
|
2200
|
+
result += char;
|
|
2201
|
+
continue;
|
|
2202
|
+
}
|
|
2203
|
+
if (char === ",") {
|
|
2204
|
+
let lookahead = index + 1;
|
|
2205
|
+
while (lookahead < content.length && /\s/.test(content[lookahead] ?? "")) {
|
|
2206
|
+
lookahead += 1;
|
|
2207
|
+
}
|
|
2208
|
+
const next = content[lookahead];
|
|
2209
|
+
if (next === "}" || next === "]") {
|
|
2210
|
+
continue;
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
result += char;
|
|
2214
|
+
}
|
|
2215
|
+
return result;
|
|
2216
|
+
}
|
|
2217
|
+
var PROTOTYPE_POLLUTION_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
2218
|
+
function isPrototypePollutionKey(key) {
|
|
2219
|
+
return PROTOTYPE_POLLUTION_KEYS.has(key);
|
|
2220
|
+
}
|
|
2221
|
+
function sanitizeParsedJson(value, options = {}, path = []) {
|
|
2222
|
+
if (Array.isArray(value)) {
|
|
2223
|
+
return value.map((entry, index) => sanitizeParsedJson(entry, options, [...path, index]));
|
|
2224
|
+
}
|
|
2225
|
+
if (value === null || typeof value !== "object")
|
|
2226
|
+
return value;
|
|
2227
|
+
const source = value;
|
|
2228
|
+
const sourcePrototype = Object.getPrototypeOf(source);
|
|
2229
|
+
if (sourcePrototype !== null && sourcePrototype !== Object.prototype) {
|
|
2230
|
+
options.onRejectedKey?.([...path, "__proto__"]);
|
|
2231
|
+
}
|
|
2232
|
+
const sanitized = {};
|
|
2233
|
+
for (const key of Object.keys(source)) {
|
|
2234
|
+
if (isPrototypePollutionKey(key)) {
|
|
2235
|
+
options.onRejectedKey?.([...path, key]);
|
|
2236
|
+
continue;
|
|
2237
|
+
}
|
|
2238
|
+
Object.defineProperty(sanitized, key, {
|
|
2239
|
+
value: sanitizeParsedJson(source[key], options, [...path, key]),
|
|
2240
|
+
enumerable: true,
|
|
2241
|
+
configurable: true,
|
|
2242
|
+
writable: true
|
|
2243
|
+
});
|
|
2244
|
+
}
|
|
2245
|
+
return sanitized;
|
|
2246
|
+
}
|
|
2247
|
+
function lineAndColumnAt(content, offset) {
|
|
2248
|
+
const before = content.slice(0, Math.max(0, offset));
|
|
2249
|
+
const lines = before.split(/\r?\n/);
|
|
2250
|
+
return { line: lines.length, column: (lines.at(-1)?.length ?? 0) + 1 };
|
|
2251
|
+
}
|
|
2252
|
+
function parseIssue(content, error) {
|
|
2253
|
+
const location = lineAndColumnAt(content, error.offset);
|
|
2254
|
+
const code = printParseErrorCode(error.error);
|
|
2255
|
+
const message = code.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
|
|
2256
|
+
return {
|
|
2257
|
+
...location,
|
|
2258
|
+
offset: error.offset,
|
|
2259
|
+
length: error.length,
|
|
2260
|
+
message
|
|
2261
|
+
};
|
|
2262
|
+
}
|
|
2263
|
+
function normalizeJsoncParserObjects(value, options, path = []) {
|
|
2264
|
+
if (Array.isArray(value)) {
|
|
2265
|
+
return value.map((entry, index) => normalizeJsoncParserObjects(entry, options, [...path, String(index)]));
|
|
2266
|
+
}
|
|
2267
|
+
if (value === null || typeof value !== "object")
|
|
2268
|
+
return value;
|
|
2269
|
+
const prototype = Object.getPrototypeOf(value);
|
|
2270
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
2271
|
+
options.onRejectedKey?.([...path, "__proto__"]);
|
|
2272
|
+
}
|
|
2273
|
+
const normalized = {};
|
|
2274
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
2275
|
+
Object.defineProperty(normalized, key, {
|
|
2276
|
+
configurable: true,
|
|
2277
|
+
enumerable: true,
|
|
2278
|
+
writable: true,
|
|
2279
|
+
value: normalizeJsoncParserObjects(entry, options, [...path, key])
|
|
2280
|
+
});
|
|
2281
|
+
}
|
|
2282
|
+
return normalized;
|
|
2283
|
+
}
|
|
2284
|
+
function parseJsoncRecovering(content, options = {}) {
|
|
2285
|
+
const errors = [];
|
|
2286
|
+
const parsed = parse2(content, errors, {
|
|
2287
|
+
allowTrailingComma: true,
|
|
2288
|
+
disallowComments: false,
|
|
2289
|
+
allowEmptyContent: false
|
|
2290
|
+
});
|
|
2291
|
+
return {
|
|
2292
|
+
value: sanitizeParsedJson(normalizeJsoncParserObjects(parsed, options), options),
|
|
2293
|
+
issues: errors.map((error) => parseIssue(content, error))
|
|
2294
|
+
};
|
|
2295
|
+
}
|
|
2296
|
+
function parseJsonc(content, options = {}) {
|
|
2297
|
+
const normalized = stripTrailingCommas(stripJsonComments(content));
|
|
2298
|
+
return sanitizeParsedJson(JSON.parse(normalized), options);
|
|
2299
|
+
}
|
|
2300
|
+
function readJsoncFile(filePath) {
|
|
2301
|
+
try {
|
|
2302
|
+
return parseJsonc(readFileSync(filePath, "utf-8"));
|
|
2303
|
+
} catch (_error) {
|
|
2304
|
+
return null;
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
function detectConfigFile(basePath) {
|
|
2308
|
+
const jsoncPath = `${basePath}.jsonc`;
|
|
2309
|
+
const jsonPath = `${basePath}.json`;
|
|
2310
|
+
if (existsSync(jsoncPath)) {
|
|
2311
|
+
return { format: "jsonc", path: jsoncPath };
|
|
2312
|
+
}
|
|
2313
|
+
if (existsSync(jsonPath)) {
|
|
2314
|
+
return { format: "json", path: jsonPath };
|
|
2315
|
+
}
|
|
2316
|
+
return { format: "none", path: jsoncPath };
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2319
|
+
// src/config/migrate-config-location.ts
|
|
2320
|
+
import { homedir } from "node:os";
|
|
2321
|
+
import { basename, dirname, isAbsolute, join } from "node:path";
|
|
2322
|
+
|
|
2323
|
+
// src/shared/jsonc-edit.ts
|
|
2324
|
+
var TOKEN_COMMA = 5;
|
|
2325
|
+
var TOKEN_EOF = 17;
|
|
2326
|
+
function parseDocument(text) {
|
|
2327
|
+
const errors = [];
|
|
2328
|
+
const root = parseTree2(text, errors, { allowTrailingComma: true });
|
|
2329
|
+
if (!root || errors.length > 0) {
|
|
2330
|
+
throw new Error("Cannot edit invalid JSONC");
|
|
2331
|
+
}
|
|
2332
|
+
return root;
|
|
2333
|
+
}
|
|
2334
|
+
function findNode(text, path) {
|
|
2335
|
+
return findNodeAtLocation2(parseDocument(text), path);
|
|
2336
|
+
}
|
|
2337
|
+
function findComma(text, start, end) {
|
|
2338
|
+
const scanner = createScanner2(text, false);
|
|
2339
|
+
scanner.setPosition(start);
|
|
2340
|
+
for (;; ) {
|
|
2341
|
+
const kind = scanner.scan();
|
|
2342
|
+
const offset = scanner.getTokenOffset();
|
|
2343
|
+
if (kind === TOKEN_EOF || offset >= end)
|
|
2344
|
+
return;
|
|
2345
|
+
if (kind === TOKEN_COMMA) {
|
|
2346
|
+
return {
|
|
2347
|
+
offset,
|
|
2348
|
+
length: scanner.getTokenLength(),
|
|
2349
|
+
line: scanner.getTokenStartLine()
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
function setJsoncValue(text, path, value) {
|
|
2355
|
+
const node = findNode(text, path);
|
|
2356
|
+
if (node) {
|
|
2357
|
+
if (Object.is(getNodeValue2(node), value))
|
|
2358
|
+
return text;
|
|
2359
|
+
const serialized = JSON.stringify(value);
|
|
2360
|
+
return text.slice(0, node.offset) + serialized + text.slice(node.offset + node.length);
|
|
2361
|
+
}
|
|
2362
|
+
return applyEdits(text, modify(text, path, value, { formattingOptions: documentFormatting(text) }));
|
|
2363
|
+
}
|
|
2364
|
+
function documentFormatting(text) {
|
|
2365
|
+
const eol = text.includes(`\r
|
|
2366
|
+
`) ? `\r
|
|
2367
|
+
` : `
|
|
2368
|
+
`;
|
|
2369
|
+
const indent = /\n([ \t]+)\S/.exec(text)?.[1];
|
|
2370
|
+
if (indent?.startsWith("\t"))
|
|
2371
|
+
return { eol, insertSpaces: false, tabSize: 1 };
|
|
2372
|
+
return { eol, insertSpaces: true, tabSize: indent ? indent.length : 2 };
|
|
2373
|
+
}
|
|
2374
|
+
function removeObjectProperty(text, object, key) {
|
|
2375
|
+
const properties = object.children ?? [];
|
|
2376
|
+
const index = properties.findIndex((property) => {
|
|
2377
|
+
const propertyKey = property.children?.[0];
|
|
2378
|
+
return propertyKey !== undefined && getNodeValue2(propertyKey) === key;
|
|
2379
|
+
});
|
|
2380
|
+
if (index === -1)
|
|
2381
|
+
return text;
|
|
2382
|
+
const property = properties[index];
|
|
2383
|
+
if (!property)
|
|
2384
|
+
return text;
|
|
2385
|
+
const closingBrace = object.offset + object.length - 1;
|
|
2386
|
+
const next = properties[index + 1];
|
|
2387
|
+
if (next) {
|
|
2388
|
+
const followingComma = findComma(text, property.offset + property.length, next.offset);
|
|
2389
|
+
if (!followingComma)
|
|
2390
|
+
return text;
|
|
2391
|
+
return text.slice(0, property.offset) + text.slice(followingComma.offset + followingComma.length);
|
|
2392
|
+
}
|
|
2393
|
+
const previous = properties[index - 1];
|
|
2394
|
+
const trailingComma = findComma(text, property.offset + property.length, closingBrace);
|
|
2395
|
+
if (!previous) {
|
|
2396
|
+
const afterProperty = property.offset + property.length;
|
|
2397
|
+
if (!trailingComma)
|
|
2398
|
+
return text.slice(0, property.offset) + text.slice(afterProperty);
|
|
2399
|
+
return text.slice(0, property.offset) + text.slice(afterProperty, trailingComma.offset) + text.slice(trailingComma.offset + trailingComma.length);
|
|
2400
|
+
}
|
|
2401
|
+
const precedingComma = findComma(text, previous.offset + previous.length, property.offset);
|
|
2402
|
+
if (!precedingComma)
|
|
2403
|
+
return text;
|
|
2404
|
+
const afterProperty = property.offset + property.length;
|
|
2405
|
+
const withoutProperty = text.slice(0, precedingComma.offset) + text.slice(precedingComma.offset + precedingComma.length, property.offset) + text.slice(afterProperty);
|
|
2406
|
+
if (!trailingComma)
|
|
2407
|
+
return withoutProperty;
|
|
2408
|
+
const shiftedTrailingComma = trailingComma.offset - 1;
|
|
2409
|
+
return withoutProperty.slice(0, shiftedTrailingComma) + withoutProperty.slice(shiftedTrailingComma + trailingComma.length);
|
|
2410
|
+
}
|
|
2411
|
+
function removeJsoncValue(text, path) {
|
|
2412
|
+
const key = path.at(-1);
|
|
2413
|
+
if (typeof key !== "string")
|
|
2414
|
+
return text;
|
|
2415
|
+
const parent = findNode(text, path.slice(0, -1));
|
|
2416
|
+
if (parent?.type !== "object")
|
|
2417
|
+
return text;
|
|
2418
|
+
return removeObjectProperty(text, parent, key);
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
// src/config/migrate-config-location.ts
|
|
2422
|
+
var CONFIG_FILE_BASENAME = "magic-context";
|
|
2423
|
+
function homeDir() {
|
|
2424
|
+
if (process.platform === "win32") {
|
|
2425
|
+
return process.env.USERPROFILE || process.env.HOME || homedir();
|
|
2426
|
+
}
|
|
2427
|
+
return process.env.HOME || homedir();
|
|
2428
|
+
}
|
|
2429
|
+
function configHome() {
|
|
2430
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
2431
|
+
if (xdg && isAbsolute(xdg))
|
|
2432
|
+
return xdg;
|
|
2433
|
+
return join(homeDir(), ".config");
|
|
2434
|
+
}
|
|
2435
|
+
function cortexKitUserConfigBasePath() {
|
|
2436
|
+
return join(configHome(), "cortexkit", CONFIG_FILE_BASENAME);
|
|
2437
|
+
}
|
|
2438
|
+
function cortexKitProjectConfigBasePath(directory) {
|
|
2439
|
+
return join(directory, ".cortexkit", CONFIG_FILE_BASENAME);
|
|
2440
|
+
}
|
|
2441
|
+
function legacySourcesForBase(basePath, label) {
|
|
2442
|
+
return [
|
|
2443
|
+
{ path: `${basePath}.jsonc`, label: `${label} magic-context.jsonc` },
|
|
2444
|
+
{ path: `${basePath}.json`, label: `${label} magic-context.json` }
|
|
2445
|
+
];
|
|
2446
|
+
}
|
|
2447
|
+
function userScopeConfigPaths() {
|
|
2448
|
+
return new Set([
|
|
2449
|
+
`${cortexKitUserConfigBasePath()}.jsonc`,
|
|
2450
|
+
`${cortexKitUserConfigBasePath()}.json`,
|
|
2451
|
+
join(configHome(), "opencode", `${CONFIG_FILE_BASENAME}.jsonc`),
|
|
2452
|
+
join(configHome(), "opencode", `${CONFIG_FILE_BASENAME}.json`),
|
|
2453
|
+
join(homeDir(), ".pi", "agent", `${CONFIG_FILE_BASENAME}.jsonc`),
|
|
2454
|
+
join(homeDir(), ".pi", "agent", `${CONFIG_FILE_BASENAME}.json`)
|
|
2455
|
+
]);
|
|
2456
|
+
}
|
|
2457
|
+
function resolveLegacyConfigSources(directory) {
|
|
2458
|
+
const userPaths = userScopeConfigPaths();
|
|
2459
|
+
return {
|
|
2460
|
+
user: [
|
|
2461
|
+
...legacySourcesForBase(join(configHome(), "opencode", CONFIG_FILE_BASENAME), "OpenCode user"),
|
|
2462
|
+
...legacySourcesForBase(join(homeDir(), ".pi", "agent", CONFIG_FILE_BASENAME), "Pi user")
|
|
2463
|
+
],
|
|
2464
|
+
project: [
|
|
2465
|
+
...legacySourcesForBase(join(directory, CONFIG_FILE_BASENAME), "project root"),
|
|
2466
|
+
...legacySourcesForBase(join(directory, ".opencode", CONFIG_FILE_BASENAME), "OpenCode project"),
|
|
2467
|
+
...legacySourcesForBase(join(directory, ".pi", CONFIG_FILE_BASENAME), "Pi project")
|
|
2468
|
+
].filter((source) => !userPaths.has(source.path))
|
|
2469
|
+
};
|
|
2470
|
+
}
|
|
2471
|
+
function resolveLegacyConfigSourcesForHarness(directory, harness) {
|
|
2472
|
+
if (harness === "pi") {
|
|
2473
|
+
return {
|
|
2474
|
+
user: legacySourcesForBase(join(homeDir(), ".pi", "agent", CONFIG_FILE_BASENAME), "Pi user"),
|
|
2475
|
+
project: legacySourcesForBase(join(directory, ".pi", CONFIG_FILE_BASENAME), "Pi project")
|
|
2476
|
+
};
|
|
2477
|
+
}
|
|
2478
|
+
return {
|
|
2479
|
+
user: legacySourcesForBase(join(configHome(), "opencode", CONFIG_FILE_BASENAME), "OpenCode user"),
|
|
2480
|
+
project: [
|
|
2481
|
+
...legacySourcesForBase(join(directory, CONFIG_FILE_BASENAME), "project root"),
|
|
2482
|
+
...legacySourcesForBase(join(directory, ".opencode", CONFIG_FILE_BASENAME), "OpenCode project")
|
|
2483
|
+
]
|
|
2484
|
+
};
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
// src/config/migrate-dreamer-v2.ts
|
|
2488
|
+
var OLD_VERIFY_TASK = "verify";
|
|
2489
|
+
var OLD_CURATE_TASKS = ["consolidate", "archive-stale", "improve"];
|
|
2490
|
+
var RETIRED_OBJECT_MEMORY_TASKS = ["maintain-memory", ...OLD_CURATE_TASKS];
|
|
2491
|
+
var CANONICAL = [
|
|
2492
|
+
"map-memories",
|
|
2493
|
+
"verify",
|
|
2494
|
+
"verify-broad",
|
|
2495
|
+
"curate",
|
|
2496
|
+
"classify-memories",
|
|
2497
|
+
"retrospective",
|
|
2498
|
+
"maintain-docs",
|
|
2499
|
+
"evaluate-smart-notes",
|
|
2500
|
+
"review-user-memories",
|
|
2501
|
+
"promote-primers",
|
|
2502
|
+
"refresh-primers"
|
|
2503
|
+
];
|
|
2504
|
+
var DEFAULT_BASE_CRON = "0 2 * * *";
|
|
2505
|
+
var DEFAULT_CLASSIFY_CRON = "0 6 * * *";
|
|
2506
|
+
var DEFAULT_RETROSPECTIVE_CRON = "0 5 * * *";
|
|
2507
|
+
var DEFAULT_VERIFY_BROAD_CRON = "0 4 * * 0";
|
|
2508
|
+
function windowToCron(schedule) {
|
|
2509
|
+
if (typeof schedule !== "string")
|
|
2510
|
+
return DEFAULT_BASE_CRON;
|
|
2511
|
+
const m = /^(\d{1,2}):(\d{2})\s*-/.exec(schedule.trim());
|
|
2512
|
+
if (!m)
|
|
2513
|
+
return DEFAULT_BASE_CRON;
|
|
2514
|
+
const hour = Number(m[1]);
|
|
2515
|
+
const minute = Number(m[2]);
|
|
2516
|
+
if (hour >= 24 || minute >= 60)
|
|
2517
|
+
return DEFAULT_BASE_CRON;
|
|
2518
|
+
return `${minute} ${hour} * * *`;
|
|
2519
|
+
}
|
|
2520
|
+
function asObject(value) {
|
|
2521
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
2522
|
+
}
|
|
2523
|
+
function cronIntervalScore(schedule) {
|
|
2524
|
+
const parts = schedule.trim().split(/\s+/);
|
|
2525
|
+
if (parts.length !== 5)
|
|
2526
|
+
return Number.POSITIVE_INFINITY;
|
|
2527
|
+
const [minute, hour, dayOfMonth, month, dayOfWeek] = parts;
|
|
2528
|
+
if (month !== "*")
|
|
2529
|
+
return 366 * 24 * 60;
|
|
2530
|
+
if (dayOfMonth !== "*")
|
|
2531
|
+
return 31 * 24 * 60;
|
|
2532
|
+
if (dayOfWeek !== "*")
|
|
2533
|
+
return 7 * 24 * 60;
|
|
2534
|
+
const everyHour = /^\*\/(\d+)$/.exec(hour ?? "");
|
|
2535
|
+
if (everyHour)
|
|
2536
|
+
return Math.max(1, Number(everyHour[1])) * 60;
|
|
2537
|
+
if (hour === "*") {
|
|
2538
|
+
const everyMinute = /^\*\/(\d+)$/.exec(minute ?? "");
|
|
2539
|
+
return everyMinute ? Math.max(1, Number(everyMinute[1])) : 60;
|
|
2540
|
+
}
|
|
2541
|
+
return 24 * 60;
|
|
2542
|
+
}
|
|
2543
|
+
function mostFrequentSchedule(schedules) {
|
|
2544
|
+
const enabled = schedules.map((s) => s.trim()).filter(Boolean);
|
|
2545
|
+
if (enabled.length === 0)
|
|
2546
|
+
return "";
|
|
2547
|
+
return enabled.sort((a, b) => cronIntervalScore(a) - cronIntervalScore(b))[0] ?? "";
|
|
2548
|
+
}
|
|
2549
|
+
function withoutBroadInterval(entry) {
|
|
2550
|
+
const { broad_interval_days: _broad, ...rest } = entry;
|
|
2551
|
+
return rest;
|
|
2552
|
+
}
|
|
2553
|
+
function reconcileV2TasksObject(rawConfig, dreamer, tasksObject) {
|
|
2554
|
+
const hasVerifyBroad = "verify-broad" in tasksObject;
|
|
2555
|
+
const hasBroadIntervalAnywhere = Object.values(tasksObject).some((v) => asObject(v) && ("broad_interval_days" in v));
|
|
2556
|
+
const hasStaleKeyFiles = "key-files" in tasksObject;
|
|
2557
|
+
if (hasVerifyBroad && !hasBroadIntervalAnywhere && !hasStaleKeyFiles)
|
|
2558
|
+
return rawConfig;
|
|
2559
|
+
const nextTasks = {};
|
|
2560
|
+
for (const [key, value] of Object.entries(tasksObject)) {
|
|
2561
|
+
if (key === "key-files")
|
|
2562
|
+
continue;
|
|
2563
|
+
const obj = asObject(value);
|
|
2564
|
+
nextTasks[key] = obj ? withoutBroadInterval(obj) : value;
|
|
2565
|
+
}
|
|
2566
|
+
if (!hasVerifyBroad) {
|
|
2567
|
+
const verify = asObject(tasksObject.verify);
|
|
2568
|
+
const verifyEnabled = typeof verify?.schedule === "string" && verify.schedule.trim() !== "";
|
|
2569
|
+
nextTasks["verify-broad"] = {
|
|
2570
|
+
schedule: verifyEnabled ? DEFAULT_VERIFY_BROAD_CRON : ""
|
|
2571
|
+
};
|
|
2572
|
+
}
|
|
2573
|
+
return { ...rawConfig, dreamer: { ...dreamer, tasks: nextTasks } };
|
|
2574
|
+
}
|
|
2575
|
+
function migrateDreamerV2(rawConfig, warnings) {
|
|
2576
|
+
const dreamer = asObject(rawConfig.dreamer);
|
|
2577
|
+
if (!dreamer)
|
|
2578
|
+
return rawConfig;
|
|
2579
|
+
const tasksObject = asObject(dreamer.tasks);
|
|
2580
|
+
const hasRetiredObjectTasks = tasksObject ? RETIRED_OBJECT_MEMORY_TASKS.some((task) => (task in tasksObject)) : false;
|
|
2581
|
+
if (tasksObject && !hasRetiredObjectTasks) {
|
|
2582
|
+
const hasLegacyOutsideTasks = "schedule" in dreamer || "user_memories" in dreamer || "pin_key_files" in dreamer || "task_timeout_minutes" in dreamer || "max_runtime_minutes" in dreamer;
|
|
2583
|
+
if (!hasLegacyOutsideTasks) {
|
|
2584
|
+
return reconcileV2TasksObject(rawConfig, dreamer, tasksObject);
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
const hasLegacy = "schedule" in dreamer || Array.isArray(dreamer.tasks) || hasRetiredObjectTasks || "user_memories" in dreamer || "pin_key_files" in dreamer || "task_timeout_minutes" in dreamer || "max_runtime_minutes" in dreamer;
|
|
2588
|
+
if (!hasLegacy)
|
|
2589
|
+
return rawConfig;
|
|
2590
|
+
const baseCron = windowToCron(dreamer.schedule);
|
|
2591
|
+
const timeout = typeof dreamer.task_timeout_minutes === "number" ? dreamer.task_timeout_minutes : undefined;
|
|
2592
|
+
const withTimeout = (entry) => timeout !== undefined ? { ...entry, timeout_minutes: timeout } : entry;
|
|
2593
|
+
const classifySchedule = dreamer.disable === true ? "" : DEFAULT_CLASSIFY_CRON;
|
|
2594
|
+
const retrospectiveSchedule = dreamer.disable === true ? "" : DEFAULT_RETROSPECTIVE_CRON;
|
|
2595
|
+
const tasks = {};
|
|
2596
|
+
if (tasksObject) {
|
|
2597
|
+
for (const [key, value] of Object.entries(tasksObject)) {
|
|
2598
|
+
if (RETIRED_OBJECT_MEMORY_TASKS.includes(key))
|
|
2599
|
+
continue;
|
|
2600
|
+
if (asObject(value))
|
|
2601
|
+
tasks[key] = { ...value };
|
|
2602
|
+
}
|
|
2603
|
+
const maintainMemoryEntry = asObject(tasksObject["maintain-memory"]);
|
|
2604
|
+
if (maintainMemoryEntry) {
|
|
2605
|
+
const schedule = typeof maintainMemoryEntry.schedule === "string" ? maintainMemoryEntry.schedule : baseCron;
|
|
2606
|
+
tasks.verify = withTimeout({
|
|
2607
|
+
...withoutBroadInterval(maintainMemoryEntry),
|
|
2608
|
+
...tasks.verify ?? {},
|
|
2609
|
+
schedule: tasks.verify?.schedule ?? schedule
|
|
2610
|
+
});
|
|
2611
|
+
tasks.curate = withTimeout({
|
|
2612
|
+
...withoutBroadInterval(maintainMemoryEntry),
|
|
2613
|
+
...tasks.curate ?? {},
|
|
2614
|
+
schedule: tasks.curate?.schedule ?? schedule
|
|
2615
|
+
});
|
|
2616
|
+
}
|
|
2617
|
+
const oldVerifyEntry = asObject(tasksObject[OLD_VERIFY_TASK]);
|
|
2618
|
+
if (oldVerifyEntry) {
|
|
2619
|
+
tasks.verify = withTimeout({
|
|
2620
|
+
...withoutBroadInterval(oldVerifyEntry),
|
|
2621
|
+
...tasks.verify ?? {},
|
|
2622
|
+
schedule: tasks.verify?.schedule ?? (typeof oldVerifyEntry.schedule === "string" ? oldVerifyEntry.schedule : baseCron)
|
|
2623
|
+
});
|
|
2624
|
+
}
|
|
2625
|
+
if (!tasks["verify-broad"]) {
|
|
2626
|
+
const verifyEnabled = typeof tasks.verify?.schedule === "string" && tasks.verify.schedule.trim() !== "";
|
|
2627
|
+
tasks["verify-broad"] = withTimeout({
|
|
2628
|
+
schedule: verifyEnabled ? DEFAULT_VERIFY_BROAD_CRON : ""
|
|
2629
|
+
});
|
|
2630
|
+
}
|
|
2631
|
+
const oldCurateEntries = OLD_CURATE_TASKS.map((task) => asObject(tasksObject[task])).filter((entry) => Boolean(entry));
|
|
2632
|
+
if (oldCurateEntries.length > 0) {
|
|
2633
|
+
const oldSchedules = oldCurateEntries.map((entry) => typeof entry.schedule === "string" ? entry.schedule : baseCron);
|
|
2634
|
+
tasks.curate = withTimeout({
|
|
2635
|
+
...tasks.curate ?? {},
|
|
2636
|
+
schedule: mostFrequentSchedule(oldSchedules)
|
|
2637
|
+
});
|
|
2638
|
+
}
|
|
2639
|
+
for (const task of CANONICAL) {
|
|
2640
|
+
if (!tasks[task]) {
|
|
2641
|
+
const schedule = task === "verify" || task === "curate" || task === "verify-broad" ? "" : task === "classify-memories" ? classifySchedule : task === "retrospective" ? retrospectiveSchedule : task === "maintain-docs" ? "" : baseCron;
|
|
2642
|
+
tasks[task] = withTimeout({ schedule });
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
} else {
|
|
2646
|
+
const legacyArray = Array.isArray(dreamer.tasks) ? dreamer.tasks.filter((t) => typeof t === "string") : null;
|
|
2647
|
+
const verifySelected = legacyArray ? legacyArray.includes(OLD_VERIFY_TASK) : true;
|
|
2648
|
+
const curateSelected = legacyArray ? legacyArray.some((task) => OLD_CURATE_TASKS.includes(task)) : true;
|
|
2649
|
+
tasks.verify = withTimeout({
|
|
2650
|
+
schedule: verifySelected ? baseCron : ""
|
|
2651
|
+
});
|
|
2652
|
+
tasks["verify-broad"] = withTimeout({
|
|
2653
|
+
schedule: verifySelected ? DEFAULT_VERIFY_BROAD_CRON : ""
|
|
2654
|
+
});
|
|
2655
|
+
tasks.curate = withTimeout({
|
|
2656
|
+
schedule: curateSelected ? baseCron : ""
|
|
2657
|
+
});
|
|
2658
|
+
tasks["classify-memories"] = withTimeout({
|
|
2659
|
+
schedule: classifySchedule
|
|
2660
|
+
});
|
|
2661
|
+
tasks.retrospective = withTimeout({
|
|
2662
|
+
schedule: retrospectiveSchedule
|
|
2663
|
+
});
|
|
2664
|
+
tasks["maintain-docs"] = withTimeout({
|
|
2665
|
+
schedule: legacyArray?.includes("maintain-docs") ? baseCron : ""
|
|
2666
|
+
});
|
|
2667
|
+
}
|
|
2668
|
+
tasks["map-memories"] ??= withTimeout({ schedule: baseCron });
|
|
2669
|
+
tasks["evaluate-smart-notes"] ??= withTimeout({ schedule: baseCron });
|
|
2670
|
+
const um = asObject(dreamer.user_memories);
|
|
2671
|
+
const umEnabled = um ? um.enabled !== false : true;
|
|
2672
|
+
if (um || !tasks["review-user-memories"]) {
|
|
2673
|
+
tasks["review-user-memories"] = withTimeout({
|
|
2674
|
+
...tasks["review-user-memories"] ?? {},
|
|
2675
|
+
schedule: umEnabled ? baseCron : "",
|
|
2676
|
+
...um && typeof um.promotion_threshold === "number" ? { promotion_threshold: um.promotion_threshold } : {}
|
|
2677
|
+
});
|
|
2678
|
+
}
|
|
2679
|
+
const {
|
|
2680
|
+
schedule: _schedule,
|
|
2681
|
+
tasks: _tasks,
|
|
2682
|
+
task_timeout_minutes: _tto,
|
|
2683
|
+
max_runtime_minutes: _max,
|
|
2684
|
+
user_memories: _um,
|
|
2685
|
+
pin_key_files: _pkf,
|
|
2686
|
+
...rest
|
|
2687
|
+
} = dreamer;
|
|
2688
|
+
warnings.push('Migrated legacy dreamer scheduling (schedule window / tasks array / user_memories / pin_key_files) → per-task "dreamer.tasks" in-memory (run `doctor` to persist).');
|
|
2689
|
+
return { ...rawConfig, dreamer: { ...rest, tasks } };
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
// src/config/migrate-experimental.ts
|
|
2693
|
+
function migrateLegacyExperimental(rawConfig, warnings) {
|
|
2694
|
+
const experimental = rawConfig.experimental;
|
|
2695
|
+
if (typeof experimental !== "object" || experimental === null) {
|
|
2696
|
+
return rawConfig;
|
|
2697
|
+
}
|
|
2698
|
+
const exp = experimental;
|
|
2699
|
+
const hasUM = "user_memories" in exp;
|
|
2700
|
+
const hasPKF = "pin_key_files" in exp;
|
|
2701
|
+
const hasMural = "mural" in exp;
|
|
2702
|
+
const TOP_LEVEL_GRADUATED = ["temporal_awareness", "caveman_text_compression"];
|
|
2703
|
+
const MEMORY_GRADUATED = ["auto_search", "git_commit_indexing"];
|
|
2704
|
+
const hasGraduated = TOP_LEVEL_GRADUATED.some((k) => (k in exp)) || MEMORY_GRADUATED.some((k) => (k in exp)) || hasMural;
|
|
2705
|
+
if (!hasUM && !hasPKF && !hasGraduated) {
|
|
2706
|
+
return rawConfig;
|
|
2707
|
+
}
|
|
2708
|
+
const patched = { ...rawConfig };
|
|
2709
|
+
const dreamer = typeof patched.dreamer === "object" && patched.dreamer !== null ? { ...patched.dreamer } : {};
|
|
2710
|
+
const memory = typeof patched.memory === "object" && patched.memory !== null ? { ...patched.memory } : {};
|
|
2711
|
+
const newExperimental = { ...exp };
|
|
2712
|
+
const coerceToObject = (value) => {
|
|
2713
|
+
if (typeof value === "boolean") {
|
|
2714
|
+
return { enabled: value };
|
|
2715
|
+
}
|
|
2716
|
+
if (typeof value === "object" && value !== null) {
|
|
2717
|
+
return { ...value };
|
|
2718
|
+
}
|
|
2719
|
+
return;
|
|
2720
|
+
};
|
|
2721
|
+
const relocate = (key, dest, destLabel) => {
|
|
2722
|
+
if (!(key in exp))
|
|
2723
|
+
return;
|
|
2724
|
+
const oldValue = exp[key];
|
|
2725
|
+
const existing = dest[key];
|
|
2726
|
+
if (existing === undefined) {
|
|
2727
|
+
dest[key] = oldValue;
|
|
2728
|
+
warnings.push(`Migrated "experimental.${key}" → "${destLabel}${key}" in-memory (run \`doctor\` to persist).`);
|
|
2729
|
+
} else if (typeof oldValue === "object" && oldValue !== null && typeof existing === "object" && existing !== null) {
|
|
2730
|
+
dest[key] = {
|
|
2731
|
+
...oldValue,
|
|
2732
|
+
...existing
|
|
2733
|
+
};
|
|
2734
|
+
}
|
|
2735
|
+
delete newExperimental[key];
|
|
2736
|
+
};
|
|
2737
|
+
for (const key of TOP_LEVEL_GRADUATED)
|
|
2738
|
+
relocate(key, patched, "");
|
|
2739
|
+
for (const key of MEMORY_GRADUATED)
|
|
2740
|
+
relocate(key, memory, "memory.");
|
|
2741
|
+
if (hasMural) {
|
|
2742
|
+
const oldMural = coerceToObject(exp.mural);
|
|
2743
|
+
const existingMural = patched.mural;
|
|
2744
|
+
if (existingMural === undefined) {
|
|
2745
|
+
patched.mural = oldMural ?? exp.mural;
|
|
2746
|
+
warnings.push('Deprecated "experimental.mural"; use top-level "mural" instead (migrated in memory; run `doctor` to persist).');
|
|
2747
|
+
} else if (oldMural !== undefined && typeof existingMural === "object" && existingMural !== null && !Array.isArray(existingMural)) {
|
|
2748
|
+
patched.mural = {
|
|
2749
|
+
...oldMural,
|
|
2750
|
+
...existingMural
|
|
2751
|
+
};
|
|
2752
|
+
}
|
|
2753
|
+
delete newExperimental.mural;
|
|
2754
|
+
}
|
|
2755
|
+
if (hasUM) {
|
|
2756
|
+
const oldUM = coerceToObject(exp.user_memories);
|
|
2757
|
+
if (oldUM !== undefined) {
|
|
2758
|
+
if (dreamer.user_memories === undefined) {
|
|
2759
|
+
dreamer.user_memories = oldUM;
|
|
2760
|
+
warnings.push('Migrated "experimental.user_memories" → "dreamer.user_memories" in-memory (run `doctor` to persist).');
|
|
2761
|
+
} else if (typeof dreamer.user_memories === "object" && dreamer.user_memories !== null) {
|
|
2762
|
+
dreamer.user_memories = {
|
|
2763
|
+
...oldUM,
|
|
2764
|
+
...dreamer.user_memories
|
|
2765
|
+
};
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
delete newExperimental.user_memories;
|
|
2769
|
+
}
|
|
2770
|
+
if (hasPKF) {
|
|
2771
|
+
const oldPKF = coerceToObject(exp.pin_key_files);
|
|
2772
|
+
if (oldPKF !== undefined) {
|
|
2773
|
+
if (dreamer.pin_key_files === undefined) {
|
|
2774
|
+
dreamer.pin_key_files = oldPKF;
|
|
2775
|
+
warnings.push('Migrated "experimental.pin_key_files" → "dreamer.pin_key_files" in-memory (run `doctor` to persist).');
|
|
2776
|
+
} else if (typeof dreamer.pin_key_files === "object" && dreamer.pin_key_files !== null) {
|
|
2777
|
+
dreamer.pin_key_files = {
|
|
2778
|
+
...oldPKF,
|
|
2779
|
+
...dreamer.pin_key_files
|
|
2780
|
+
};
|
|
2781
|
+
} else if (typeof dreamer.pin_key_files === "boolean") {
|
|
2782
|
+
dreamer.pin_key_files = { ...oldPKF, enabled: dreamer.pin_key_files };
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
delete newExperimental.pin_key_files;
|
|
2786
|
+
}
|
|
2787
|
+
patched.experimental = newExperimental;
|
|
2788
|
+
patched.dreamer = dreamer;
|
|
2789
|
+
if (Object.keys(memory).length > 0) {
|
|
2790
|
+
patched.memory = memory;
|
|
2791
|
+
}
|
|
2792
|
+
return patched;
|
|
2793
|
+
}
|
|
2794
|
+
|
|
2795
|
+
// src/config/profiles.ts
|
|
2796
|
+
function withoutProfileFields(raw) {
|
|
2797
|
+
const copy = { ...raw };
|
|
2798
|
+
delete copy.profile;
|
|
2799
|
+
delete copy.profiles;
|
|
2800
|
+
return copy;
|
|
2801
|
+
}
|
|
2802
|
+
function readProfileSelection(raw) {
|
|
2803
|
+
if (!Object.hasOwn(raw, "profile"))
|
|
2804
|
+
return { declared: false };
|
|
2805
|
+
const value = raw.profile;
|
|
2806
|
+
if (typeof value !== "string")
|
|
2807
|
+
return { declared: true };
|
|
2808
|
+
const name = value.trim();
|
|
2809
|
+
return name.length > 0 ? { declared: true, name } : { declared: true };
|
|
2810
|
+
}
|
|
2811
|
+
function resolveConfigProfile(args) {
|
|
2812
|
+
const warnings = [];
|
|
2813
|
+
const userSelection = readProfileSelection(args.userRaw);
|
|
2814
|
+
const projectSelection = readProfileSelection(args.projectRaw);
|
|
2815
|
+
const selection = projectSelection.name ? { name: projectSelection.name, source: "project" } : userSelection.name ? { name: userSelection.name, source: "user" } : undefined;
|
|
2816
|
+
if (projectSelection.declared && !projectSelection.name) {
|
|
2817
|
+
warnings.push("Ignoring invalid profile selection from project config; expected a non-empty string.");
|
|
2818
|
+
}
|
|
2819
|
+
if (!projectSelection.declared && userSelection.declared && !userSelection.name) {
|
|
2820
|
+
warnings.push("Ignoring invalid profile selection from user config; expected a non-empty string.");
|
|
2821
|
+
}
|
|
2822
|
+
let profiles = {};
|
|
2823
|
+
if (Object.hasOwn(args.userRaw, "profiles")) {
|
|
2824
|
+
const parsed = ConfigProfilesSchema.safeParse(args.userRaw.profiles);
|
|
2825
|
+
if (parsed.success) {
|
|
2826
|
+
profiles = parsed.data;
|
|
2827
|
+
} else {
|
|
2828
|
+
warnings.push("Ignoring profiles from user config: invalid profile configuration; profiles may contain only historian/dreamer harness model blocks.");
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
if (!selection) {
|
|
2832
|
+
return {
|
|
2833
|
+
userBase: withoutProfileFields(args.userRaw),
|
|
2834
|
+
projectBase: withoutProfileFields(args.projectRaw),
|
|
2835
|
+
overlay: {},
|
|
2836
|
+
warnings
|
|
2837
|
+
};
|
|
2838
|
+
}
|
|
2839
|
+
if (!Object.hasOwn(profiles, selection.name)) {
|
|
2840
|
+
warnings.push(`Unknown profile "${selection.name}" selected by ${selection.source} config; using base config without a profile.`);
|
|
2841
|
+
return {
|
|
2842
|
+
userBase: withoutProfileFields(args.userRaw),
|
|
2843
|
+
projectBase: withoutProfileFields(args.projectRaw),
|
|
2844
|
+
overlay: {},
|
|
2845
|
+
warnings
|
|
2846
|
+
};
|
|
2847
|
+
}
|
|
2848
|
+
const overlay = profiles[selection.name];
|
|
2849
|
+
return {
|
|
2850
|
+
userBase: withoutProfileFields(args.userRaw),
|
|
2851
|
+
projectBase: withoutProfileFields(args.projectRaw),
|
|
2852
|
+
overlay,
|
|
2853
|
+
activeProfile: selection.name,
|
|
2854
|
+
warnings
|
|
2855
|
+
};
|
|
2856
|
+
}
|
|
2857
|
+
|
|
2858
|
+
// src/config/prune-config-leaf.ts
|
|
2859
|
+
function isPlainObject2(value) {
|
|
2860
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2861
|
+
}
|
|
2862
|
+
function pruneNestedConfigLeaf(block, relativePath) {
|
|
2863
|
+
if (relativePath.length === 0)
|
|
2864
|
+
return null;
|
|
2865
|
+
const result = { ...block };
|
|
2866
|
+
let cursor = result;
|
|
2867
|
+
for (let i = 0;i < relativePath.length - 1; i++) {
|
|
2868
|
+
const seg = String(relativePath[i]);
|
|
2869
|
+
const child = cursor[seg];
|
|
2870
|
+
if (!isPlainObject2(child)) {
|
|
2871
|
+
if (!(seg in cursor))
|
|
2872
|
+
return null;
|
|
2873
|
+
delete cursor[seg];
|
|
2874
|
+
return {
|
|
2875
|
+
block: result,
|
|
2876
|
+
removed: relativePath.slice(0, i + 1).map(String).join(".")
|
|
2877
|
+
};
|
|
2878
|
+
}
|
|
2879
|
+
const clonedChild = { ...child };
|
|
2880
|
+
cursor[seg] = clonedChild;
|
|
2881
|
+
cursor = clonedChild;
|
|
2882
|
+
}
|
|
2883
|
+
const leaf = String(relativePath[relativePath.length - 1]);
|
|
2884
|
+
if (!(leaf in cursor))
|
|
2885
|
+
return null;
|
|
2886
|
+
delete cursor[leaf];
|
|
2887
|
+
return { block: result, removed: relativePath.map(String).join(".") };
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2890
|
+
// src/config/raw-loader.ts
|
|
2891
|
+
import {
|
|
2892
|
+
closeSync,
|
|
2893
|
+
existsSync as existsSync2,
|
|
2894
|
+
linkSync,
|
|
2895
|
+
openSync,
|
|
2896
|
+
readFileSync as readFileSync2,
|
|
2897
|
+
realpathSync,
|
|
2898
|
+
renameSync,
|
|
2899
|
+
statSync,
|
|
2900
|
+
unlinkSync,
|
|
2901
|
+
writeFileSync
|
|
2902
|
+
} from "node:fs";
|
|
2903
|
+
import { basename as basename2, dirname as dirname2, join as join2 } from "node:path";
|
|
2904
|
+
var MODEL_FIELDS = ["model", "fallback_models"];
|
|
2905
|
+
var QUALIFIER_FIELDS = ["variant", "thinking_level"];
|
|
2906
|
+
var TASK_MODEL_FIELDS = [...MODEL_FIELDS, ...QUALIFIER_FIELDS, "timeout_minutes"];
|
|
2907
|
+
var PRE_PER_HARNESS_BACKUP_SUFFIX = ".pre-per-harness.bak";
|
|
2908
|
+
var temporaryFileSequence = 0;
|
|
2909
|
+
function isRecord(value) {
|
|
2910
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2911
|
+
}
|
|
2912
|
+
function asDocument(text) {
|
|
2913
|
+
try {
|
|
2914
|
+
const document = parseJsonc(text.startsWith("\uFEFF") ? text.slice(1) : text);
|
|
2915
|
+
return isRecord(document) ? document : null;
|
|
2916
|
+
} catch {
|
|
2917
|
+
return null;
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
function getAtPath(document, path) {
|
|
2921
|
+
let current = document;
|
|
2922
|
+
for (const part of path) {
|
|
2923
|
+
if (!isRecord(current) || !Object.hasOwn(current, part))
|
|
2924
|
+
return;
|
|
2925
|
+
current = current[part];
|
|
2926
|
+
}
|
|
2927
|
+
return current;
|
|
2928
|
+
}
|
|
2929
|
+
function stableJson(value) {
|
|
2930
|
+
if (Array.isArray(value))
|
|
2931
|
+
return `[${value.map(stableJson).join(",")}]`;
|
|
2932
|
+
if (!isRecord(value))
|
|
2933
|
+
return JSON.stringify(value);
|
|
2934
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
|
|
2935
|
+
}
|
|
2936
|
+
function valuesMatch(left, right) {
|
|
2937
|
+
return stableJson(left) === stableJson(right);
|
|
2938
|
+
}
|
|
2939
|
+
function valueForDiagnostic(value) {
|
|
2940
|
+
return stableJson(value);
|
|
2941
|
+
}
|
|
2942
|
+
function migrateEntryForHarness(value, harness) {
|
|
2943
|
+
if (Array.isArray(value))
|
|
2944
|
+
return value.map((entry) => migrateEntryForHarness(entry, harness));
|
|
2945
|
+
if (!isRecord(value) || !Object.hasOwn(value, "model"))
|
|
2946
|
+
return value;
|
|
2947
|
+
const entry = { model: value.model };
|
|
2948
|
+
if (harness === "opencode" && Object.hasOwn(value, "variant")) {
|
|
2949
|
+
entry.variant = value.variant;
|
|
2950
|
+
}
|
|
2951
|
+
if (harness === "pi" && Object.hasOwn(value, "thinking_level")) {
|
|
2952
|
+
entry.thinking_level = value.thinking_level;
|
|
2953
|
+
}
|
|
2954
|
+
return entry;
|
|
2955
|
+
}
|
|
2956
|
+
function migrateFallbackForHarness(value, harness) {
|
|
2957
|
+
if (typeof value === "string")
|
|
2958
|
+
return [value];
|
|
2959
|
+
return migrateEntryForHarness(value, harness);
|
|
2960
|
+
}
|
|
2961
|
+
function canCreateAtPath(document, path) {
|
|
2962
|
+
let current = document;
|
|
2963
|
+
for (const part of path) {
|
|
2964
|
+
if (current === undefined)
|
|
2965
|
+
return true;
|
|
2966
|
+
if (!isRecord(current))
|
|
2967
|
+
return false;
|
|
2968
|
+
current = current[part];
|
|
2969
|
+
}
|
|
2970
|
+
return current === undefined || isRecord(current);
|
|
2971
|
+
}
|
|
2972
|
+
function flatFieldPath(parts) {
|
|
2973
|
+
return parts.join(".");
|
|
2974
|
+
}
|
|
2975
|
+
function updateDocumentForFlatFields(text) {
|
|
2976
|
+
const hasBom = text.startsWith("\uFEFF");
|
|
2977
|
+
const editableText = hasBom ? text.slice(1) : text;
|
|
2978
|
+
const document = asDocument(text);
|
|
2979
|
+
if (!document) {
|
|
2980
|
+
return { text, hasFlatKeys: false, diagnostics: [], flatPaths: [] };
|
|
2981
|
+
}
|
|
2982
|
+
let nextText = editableText;
|
|
2983
|
+
let hasFlatKeys = false;
|
|
2984
|
+
const diagnostics = [];
|
|
2985
|
+
const flatPaths = [];
|
|
2986
|
+
const sourcePathsToRemove = [];
|
|
2987
|
+
const addDestination = (sourcePath, destinationPath, destinationValue) => {
|
|
2988
|
+
const sourceLabel = flatFieldPath(sourcePath);
|
|
2989
|
+
const destinationLabel = flatFieldPath(destinationPath);
|
|
2990
|
+
if (!canCreateAtPath(document, destinationPath.slice(0, -1))) {
|
|
2991
|
+
diagnostics.push({
|
|
2992
|
+
path: sourceLabel,
|
|
2993
|
+
message: `Flat config field "${sourceLabel}" (${valueForDiagnostic(destinationValue)}) conflicts with non-object destination "${destinationLabel}" (${valueForDiagnostic(getAtPath(document, destinationPath.slice(0, -1)))}); kept the destination and ignored the flat field.`
|
|
2994
|
+
});
|
|
2995
|
+
return;
|
|
2996
|
+
}
|
|
2997
|
+
const existing = getAtPath(document, destinationPath);
|
|
2998
|
+
if (existing !== undefined) {
|
|
2999
|
+
if (!valuesMatch(existing, destinationValue)) {
|
|
3000
|
+
diagnostics.push({
|
|
3001
|
+
path: sourceLabel,
|
|
3002
|
+
message: `Flat config field "${sourceLabel}" (${valueForDiagnostic(destinationValue)}) conflicts with "${destinationLabel}" (${valueForDiagnostic(existing)}); kept "${destinationLabel}" and ignored the flat field.`
|
|
3003
|
+
});
|
|
3004
|
+
}
|
|
3005
|
+
return;
|
|
3006
|
+
}
|
|
3007
|
+
nextText = setJsoncValue(nextText, destinationPath, destinationValue);
|
|
3008
|
+
};
|
|
3009
|
+
const migrateAgentFields = (agentName) => {
|
|
3010
|
+
const agent = document[agentName];
|
|
3011
|
+
if (!isRecord(agent))
|
|
3012
|
+
return;
|
|
3013
|
+
for (const field of MODEL_FIELDS) {
|
|
3014
|
+
if (!Object.hasOwn(agent, field))
|
|
3015
|
+
continue;
|
|
3016
|
+
const sourcePath = [agentName, field];
|
|
3017
|
+
hasFlatKeys = true;
|
|
3018
|
+
flatPaths.push(flatFieldPath(sourcePath));
|
|
3019
|
+
sourcePathsToRemove.push(sourcePath);
|
|
3020
|
+
const migrateValue = field === "fallback_models" ? migrateFallbackForHarness : migrateEntryForHarness;
|
|
3021
|
+
addDestination(sourcePath, [agentName, "opencode", field], migrateValue(agent[field], "opencode"));
|
|
3022
|
+
addDestination(sourcePath, [agentName, "pi", field], migrateValue(agent[field], "pi"));
|
|
3023
|
+
}
|
|
3024
|
+
if (Object.hasOwn(agent, "variant")) {
|
|
3025
|
+
const sourcePath = [agentName, "variant"];
|
|
3026
|
+
hasFlatKeys = true;
|
|
3027
|
+
flatPaths.push(flatFieldPath(sourcePath));
|
|
3028
|
+
sourcePathsToRemove.push(sourcePath);
|
|
3029
|
+
addDestination(sourcePath, [agentName, "opencode", "variant"], agent.variant);
|
|
3030
|
+
}
|
|
3031
|
+
if (Object.hasOwn(agent, "thinking_level")) {
|
|
3032
|
+
const sourcePath = [agentName, "thinking_level"];
|
|
3033
|
+
hasFlatKeys = true;
|
|
3034
|
+
flatPaths.push(flatFieldPath(sourcePath));
|
|
3035
|
+
sourcePathsToRemove.push(sourcePath);
|
|
3036
|
+
addDestination(sourcePath, [agentName, "pi", "thinking_level"], agent.thinking_level);
|
|
3037
|
+
}
|
|
3038
|
+
};
|
|
3039
|
+
migrateAgentFields("historian");
|
|
3040
|
+
migrateAgentFields("dreamer");
|
|
3041
|
+
const dreamer = document.dreamer;
|
|
3042
|
+
const tasks = isRecord(dreamer) ? dreamer.tasks : undefined;
|
|
3043
|
+
if (isRecord(tasks)) {
|
|
3044
|
+
for (const taskName of Object.keys(tasks).sort()) {
|
|
3045
|
+
const task = tasks[taskName];
|
|
3046
|
+
if (!isRecord(task))
|
|
3047
|
+
continue;
|
|
3048
|
+
for (const field of TASK_MODEL_FIELDS) {
|
|
3049
|
+
if (!Object.hasOwn(task, field))
|
|
3050
|
+
continue;
|
|
3051
|
+
const sourcePath = ["dreamer", "tasks", taskName, field];
|
|
3052
|
+
hasFlatKeys = true;
|
|
3053
|
+
flatPaths.push(flatFieldPath(sourcePath));
|
|
3054
|
+
sourcePathsToRemove.push(sourcePath);
|
|
3055
|
+
if (field === "model" || field === "fallback_models") {
|
|
3056
|
+
addDestination(sourcePath, ["dreamer", "opencode", "tasks", taskName, field], field === "fallback_models" ? migrateFallbackForHarness(task[field], "opencode") : migrateEntryForHarness(task[field], "opencode"));
|
|
3057
|
+
addDestination(sourcePath, ["dreamer", "pi", "tasks", taskName, field], field === "fallback_models" ? migrateFallbackForHarness(task[field], "pi") : migrateEntryForHarness(task[field], "pi"));
|
|
3058
|
+
} else if (field === "variant") {
|
|
3059
|
+
addDestination(sourcePath, ["dreamer", "opencode", "tasks", taskName, field], task[field]);
|
|
3060
|
+
} else if (field === "thinking_level") {
|
|
3061
|
+
addDestination(sourcePath, ["dreamer", "pi", "tasks", taskName, field], task[field]);
|
|
3062
|
+
} else {
|
|
3063
|
+
addDestination(sourcePath, ["dreamer", "opencode", "tasks", taskName, field], task[field]);
|
|
3064
|
+
addDestination(sourcePath, ["dreamer", "pi", "tasks", taskName, field], task[field]);
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
for (const sourcePath of sourcePathsToRemove) {
|
|
3070
|
+
nextText = removeJsoncValue(nextText, sourcePath);
|
|
3071
|
+
}
|
|
3072
|
+
return {
|
|
3073
|
+
text: hasBom ? `\uFEFF${nextText}` : nextText,
|
|
3074
|
+
hasFlatKeys,
|
|
3075
|
+
diagnostics,
|
|
3076
|
+
flatPaths
|
|
3077
|
+
};
|
|
3078
|
+
}
|
|
3079
|
+
function hasFlatKeys(input) {
|
|
3080
|
+
const text = typeof input === "string" ? input : input.toString("utf-8");
|
|
3081
|
+
return updateDocumentForFlatFields(text).hasFlatKeys;
|
|
3082
|
+
}
|
|
3083
|
+
function migrateFlatDetailed(input) {
|
|
3084
|
+
const bytes = typeof input === "string" ? Buffer.from(input, "utf-8") : input;
|
|
3085
|
+
const result = updateDocumentForFlatFields(bytes.toString("utf-8"));
|
|
3086
|
+
return {
|
|
3087
|
+
bytes: Buffer.from(result.text, "utf-8"),
|
|
3088
|
+
hasFlatKeys: result.hasFlatKeys,
|
|
3089
|
+
diagnostics: result.diagnostics
|
|
3090
|
+
};
|
|
3091
|
+
}
|
|
3092
|
+
function writeExclusiveBackup(backupPath, bytes, mode) {
|
|
3093
|
+
const temporaryPath = writeTemporaryCandidate(backupPath, bytes, mode);
|
|
3094
|
+
try {
|
|
3095
|
+
try {
|
|
3096
|
+
linkSync(temporaryPath, backupPath);
|
|
3097
|
+
return;
|
|
3098
|
+
} catch (error) {
|
|
3099
|
+
if (error.code !== "EEXIST")
|
|
3100
|
+
throw error;
|
|
3101
|
+
}
|
|
3102
|
+
const existingBytes = readFileSync2(backupPath);
|
|
3103
|
+
if (existingBytes.equals(bytes))
|
|
3104
|
+
return;
|
|
3105
|
+
if (bytes.subarray(0, existingBytes.length).equals(existingBytes)) {
|
|
3106
|
+
renameSync(temporaryPath, backupPath);
|
|
3107
|
+
return;
|
|
3108
|
+
}
|
|
3109
|
+
} finally {
|
|
3110
|
+
try {
|
|
3111
|
+
unlinkSync(temporaryPath);
|
|
3112
|
+
} catch {}
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
function writeTemporaryCandidate(configPath, bytes, mode) {
|
|
3116
|
+
const directory = dirname2(configPath);
|
|
3117
|
+
const stem = basename2(configPath);
|
|
3118
|
+
for (let attempt = 0;attempt < 32; attempt++) {
|
|
3119
|
+
temporaryFileSequence += 1;
|
|
3120
|
+
const path = join2(directory, `.${stem}.per-harness-${process.pid}-${temporaryFileSequence}.tmp`);
|
|
3121
|
+
let descriptor;
|
|
3122
|
+
try {
|
|
3123
|
+
descriptor = openSync(path, "wx", mode);
|
|
3124
|
+
writeFileSync(descriptor, bytes);
|
|
3125
|
+
closeSync(descriptor);
|
|
3126
|
+
return path;
|
|
3127
|
+
} catch (error) {
|
|
3128
|
+
if (descriptor !== undefined) {
|
|
3129
|
+
try {
|
|
3130
|
+
closeSync(descriptor);
|
|
3131
|
+
} catch {}
|
|
3132
|
+
}
|
|
3133
|
+
try {
|
|
3134
|
+
unlinkSync(path);
|
|
3135
|
+
} catch {}
|
|
3136
|
+
if (error.code !== "EEXIST")
|
|
3137
|
+
throw error;
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
throw new Error(`Could not allocate a temporary config file beside ${configPath}`);
|
|
3141
|
+
}
|
|
3142
|
+
function migrationWarning(diagnostic) {
|
|
3143
|
+
return diagnostic.message;
|
|
3144
|
+
}
|
|
3145
|
+
function loadRawConfigFile(options) {
|
|
3146
|
+
if (!existsSync2(options.configPath))
|
|
3147
|
+
return null;
|
|
3148
|
+
let observedBytes;
|
|
3149
|
+
try {
|
|
3150
|
+
observedBytes = readFileSync2(options.configPath);
|
|
3151
|
+
} catch (error) {
|
|
3152
|
+
throw new Error(`failed to read config: ${error instanceof Error ? error.message : String(error)}`);
|
|
3153
|
+
}
|
|
3154
|
+
const initialMigration = migrateFlatDetailed(observedBytes);
|
|
3155
|
+
if (!initialMigration.hasFlatKeys) {
|
|
3156
|
+
return {
|
|
3157
|
+
configPath: options.configPath,
|
|
3158
|
+
bytes: observedBytes,
|
|
3159
|
+
text: observedBytes.toString("utf-8"),
|
|
3160
|
+
warnings: [],
|
|
3161
|
+
migrated: false
|
|
3162
|
+
};
|
|
3163
|
+
}
|
|
3164
|
+
if (options.tier === "project") {
|
|
3165
|
+
return {
|
|
3166
|
+
configPath: options.configPath,
|
|
3167
|
+
bytes: initialMigration.bytes,
|
|
3168
|
+
text: initialMigration.bytes.toString("utf-8"),
|
|
3169
|
+
warnings: [
|
|
3170
|
+
"Adapted flat model config in memory; use historian.opencode/historian.pi and dreamer.opencode/dreamer.pi instead. Project config files are never rewritten.",
|
|
3171
|
+
...initialMigration.diagnostics.map(migrationWarning)
|
|
3172
|
+
],
|
|
3173
|
+
migrated: false
|
|
3174
|
+
};
|
|
3175
|
+
}
|
|
3176
|
+
const backupPath = `${options.configPath}${PRE_PER_HARNESS_BACKUP_SUFFIX}`;
|
|
3177
|
+
for (;; ) {
|
|
3178
|
+
const migration = migrateFlatDetailed(observedBytes);
|
|
3179
|
+
if (!migration.hasFlatKeys) {
|
|
3180
|
+
return {
|
|
3181
|
+
configPath: options.configPath,
|
|
3182
|
+
bytes: observedBytes,
|
|
3183
|
+
text: observedBytes.toString("utf-8"),
|
|
3184
|
+
warnings: [],
|
|
3185
|
+
migrated: false
|
|
3186
|
+
};
|
|
3187
|
+
}
|
|
3188
|
+
let temporaryPath;
|
|
3189
|
+
try {
|
|
3190
|
+
const writePath = realpathSync(options.configPath);
|
|
3191
|
+
const mode = options.tier === "user" ? 384 : statSync(writePath).mode & 511;
|
|
3192
|
+
writeExclusiveBackup(backupPath, observedBytes, mode);
|
|
3193
|
+
temporaryPath = writeTemporaryCandidate(writePath, migration.bytes, mode);
|
|
3194
|
+
options.afterTemporaryWrite?.();
|
|
3195
|
+
const currentBytes = readFileSync2(options.configPath);
|
|
3196
|
+
if (!hasFlatKeys(currentBytes)) {
|
|
3197
|
+
unlinkSync(temporaryPath);
|
|
3198
|
+
return {
|
|
3199
|
+
configPath: options.configPath,
|
|
3200
|
+
bytes: currentBytes,
|
|
3201
|
+
text: currentBytes.toString("utf-8"),
|
|
3202
|
+
warnings: [],
|
|
3203
|
+
migrated: false
|
|
3204
|
+
};
|
|
3205
|
+
}
|
|
3206
|
+
if (!currentBytes.equals(observedBytes)) {
|
|
3207
|
+
unlinkSync(temporaryPath);
|
|
3208
|
+
observedBytes = currentBytes;
|
|
3209
|
+
continue;
|
|
3210
|
+
}
|
|
3211
|
+
renameSync(temporaryPath, writePath);
|
|
3212
|
+
return {
|
|
3213
|
+
configPath: options.configPath,
|
|
3214
|
+
bytes: migration.bytes,
|
|
3215
|
+
text: migration.bytes.toString("utf-8"),
|
|
3216
|
+
warnings: [
|
|
3217
|
+
"Migrated flat historian/dreamer model config to per-harness blocks.",
|
|
3218
|
+
...migration.diagnostics.map(migrationWarning)
|
|
3219
|
+
],
|
|
3220
|
+
migrated: true
|
|
3221
|
+
};
|
|
3222
|
+
} catch (error) {
|
|
3223
|
+
if (temporaryPath) {
|
|
3224
|
+
try {
|
|
3225
|
+
unlinkSync(temporaryPath);
|
|
3226
|
+
} catch {}
|
|
3227
|
+
}
|
|
3228
|
+
return {
|
|
3229
|
+
configPath: options.configPath,
|
|
3230
|
+
bytes: observedBytes,
|
|
3231
|
+
text: observedBytes.toString("utf-8"),
|
|
3232
|
+
warnings: [
|
|
3233
|
+
`Could not migrate flat model config: ${error instanceof Error ? error.message : String(error)}. Flat fields were not applied.`,
|
|
3234
|
+
...migration.diagnostics.map(migrationWarning)
|
|
3235
|
+
],
|
|
3236
|
+
migrated: false
|
|
3237
|
+
};
|
|
3238
|
+
}
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
|
|
3242
|
+
// src/config/removed-agent-config.ts
|
|
3243
|
+
var REMOVED_AGENT_CONFIG_KEY = "sidekick";
|
|
3244
|
+
var REMOVED_AGENT_CONFIG_WARNING = `The "${REMOVED_AGENT_CONFIG_KEY}" configuration was removed and is ignored.`;
|
|
3245
|
+
function isPlainObject3(value) {
|
|
3246
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3247
|
+
}
|
|
3248
|
+
function stripRemovedAgentConfig(rawConfig, warnings) {
|
|
3249
|
+
let removed = false;
|
|
3250
|
+
const patched = { ...rawConfig };
|
|
3251
|
+
if (Object.hasOwn(patched, REMOVED_AGENT_CONFIG_KEY)) {
|
|
3252
|
+
delete patched[REMOVED_AGENT_CONFIG_KEY];
|
|
3253
|
+
removed = true;
|
|
3254
|
+
}
|
|
3255
|
+
if (isPlainObject3(patched.profiles)) {
|
|
3256
|
+
const profiles = { ...patched.profiles };
|
|
3257
|
+
let profilesChanged = false;
|
|
3258
|
+
for (const [name, value] of Object.entries(profiles)) {
|
|
3259
|
+
if (!isPlainObject3(value) || !Object.hasOwn(value, REMOVED_AGENT_CONFIG_KEY))
|
|
3260
|
+
continue;
|
|
3261
|
+
const profile = { ...value };
|
|
3262
|
+
delete profile[REMOVED_AGENT_CONFIG_KEY];
|
|
3263
|
+
profiles[name] = profile;
|
|
3264
|
+
profilesChanged = true;
|
|
3265
|
+
removed = true;
|
|
3266
|
+
}
|
|
3267
|
+
if (profilesChanged)
|
|
3268
|
+
patched.profiles = profiles;
|
|
3269
|
+
}
|
|
3270
|
+
if (removed && !warnings.includes(REMOVED_AGENT_CONFIG_WARNING)) {
|
|
3271
|
+
warnings.push(REMOVED_AGENT_CONFIG_WARNING);
|
|
3272
|
+
}
|
|
3273
|
+
return removed ? patched : rawConfig;
|
|
3274
|
+
}
|
|
3275
|
+
|
|
3276
|
+
// src/config/transform-mode.ts
|
|
3277
|
+
var RUST_COMPACTION_OFF_WARNING = "compaction-off mode does not support rust transform mode; using the TypeScript transform.";
|
|
3278
|
+
var RUST_REQUIRES_USER_SUBC_WARNING = "rust mode requires user-level subc configuration; running ts.";
|
|
3279
|
+
function resolveTransformMode(args) {
|
|
3280
|
+
if (args.configured === "rust" && !args.compactionEnabled) {
|
|
3281
|
+
return {
|
|
3282
|
+
mode: "ts",
|
|
3283
|
+
warnings: [RUST_COMPACTION_OFF_WARNING]
|
|
3284
|
+
};
|
|
3285
|
+
}
|
|
3286
|
+
if (args.configured === "rust" && !args.userTierHasSubc) {
|
|
3287
|
+
return {
|
|
3288
|
+
mode: "ts",
|
|
3289
|
+
warnings: [RUST_REQUIRES_USER_SUBC_WARNING]
|
|
3290
|
+
};
|
|
3291
|
+
}
|
|
3292
|
+
return { mode: args.configured, warnings: [] };
|
|
3293
|
+
}
|
|
3294
|
+
|
|
3295
|
+
// src/config/variable.ts
|
|
3296
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
3297
|
+
import { homedir as homedir2 } from "node:os";
|
|
3298
|
+
import { dirname as dirname3, isAbsolute as isAbsolute2, resolve } from "node:path";
|
|
3299
|
+
var ENV_PATTERN = /\{env:([^}]+)\}/g;
|
|
3300
|
+
var FILE_PATTERN = /\{file:([^}]+)\}/g;
|
|
3301
|
+
function sensitiveFilePathReason(resolvedPath) {
|
|
3302
|
+
const home = homedir2();
|
|
3303
|
+
const sensitiveDirs = [
|
|
3304
|
+
{ dir: resolve(home, ".ssh"), label: "SSH keys" },
|
|
3305
|
+
{ dir: resolve(home, ".aws"), label: "AWS credentials" },
|
|
3306
|
+
{ dir: resolve(home, ".gnupg"), label: "GnuPG keyring" },
|
|
3307
|
+
{ dir: resolve(home, ".config", "gh"), label: "GitHub CLI auth" }
|
|
3308
|
+
];
|
|
3309
|
+
for (const { dir, label } of sensitiveDirs) {
|
|
3310
|
+
if (resolvedPath === dir || resolvedPath.startsWith(`${dir}/`)) {
|
|
3311
|
+
return label;
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
return null;
|
|
3315
|
+
}
|
|
3316
|
+
function substituteConfigVariables(input) {
|
|
3317
|
+
const warnings = [];
|
|
3318
|
+
let text = input.text;
|
|
3319
|
+
if (input.isProjectConfig) {
|
|
3320
|
+
const hasEnvTokens = ENV_PATTERN.test(text);
|
|
3321
|
+
const hasFileTokens = FILE_PATTERN.test(text);
|
|
3322
|
+
ENV_PATTERN.lastIndex = 0;
|
|
3323
|
+
FILE_PATTERN.lastIndex = 0;
|
|
3324
|
+
if (hasEnvTokens || hasFileTokens) {
|
|
3325
|
+
const tokenTypes = [
|
|
3326
|
+
hasEnvTokens ? "{env:}" : undefined,
|
|
3327
|
+
hasFileTokens ? "{file:}" : undefined
|
|
3328
|
+
].filter(Boolean).join(" and ");
|
|
3329
|
+
warnings.push(`Project-level config no longer supports ${tokenTypes} tokens for security reasons; leaving tokens literal. Move secret expansion to user-level config.`);
|
|
3330
|
+
}
|
|
3331
|
+
return { text, warnings };
|
|
3332
|
+
}
|
|
3333
|
+
text = stripJsonComments(text);
|
|
3334
|
+
text = text.replace(ENV_PATTERN, (_, rawName) => {
|
|
3335
|
+
const varName = rawName.trim();
|
|
3336
|
+
const value = varName ? process.env[varName] : undefined;
|
|
3337
|
+
if (value === undefined || value === "") {
|
|
3338
|
+
warnings.push(`Environment variable ${varName} is not set (referenced via {env:${varName}}); using empty string`);
|
|
3339
|
+
return "";
|
|
3340
|
+
}
|
|
3341
|
+
return JSON.stringify(value).slice(1, -1);
|
|
3342
|
+
});
|
|
3343
|
+
const fileMatches = Array.from(text.matchAll(FILE_PATTERN));
|
|
3344
|
+
if (fileMatches.length === 0) {
|
|
3345
|
+
return { text, warnings };
|
|
3346
|
+
}
|
|
3347
|
+
const configDir = input.configPath ? dirname3(input.configPath) : process.cwd();
|
|
3348
|
+
let output = "";
|
|
3349
|
+
let cursor = 0;
|
|
3350
|
+
for (const match of fileMatches) {
|
|
3351
|
+
const token = match[0];
|
|
3352
|
+
const rawPath = match[1] ?? "";
|
|
3353
|
+
const index = match.index ?? 0;
|
|
3354
|
+
output += text.slice(cursor, index);
|
|
3355
|
+
cursor = index + token.length;
|
|
3356
|
+
const lineStart = text.lastIndexOf(`
|
|
3357
|
+
`, index - 1) + 1;
|
|
3358
|
+
const prefix = text.slice(lineStart, index).trimStart();
|
|
3359
|
+
if (prefix.startsWith("//")) {
|
|
3360
|
+
output += token;
|
|
3361
|
+
continue;
|
|
3362
|
+
}
|
|
3363
|
+
let filePath = rawPath.trim();
|
|
3364
|
+
if (filePath.startsWith("~/")) {
|
|
3365
|
+
filePath = resolve(homedir2(), filePath.slice(2));
|
|
3366
|
+
} else if (!isAbsolute2(filePath)) {
|
|
3367
|
+
filePath = resolve(configDir, filePath);
|
|
3368
|
+
}
|
|
3369
|
+
const sensitiveReason = sensitiveFilePathReason(filePath);
|
|
3370
|
+
if (sensitiveReason) {
|
|
3371
|
+
warnings.push(`${token} resolves to a sensitive path (${sensitiveReason}: ${filePath}); ` + "inlining its contents into config — make sure this is intentional.");
|
|
3372
|
+
}
|
|
3373
|
+
if (!existsSync3(filePath)) {
|
|
3374
|
+
warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
|
|
3375
|
+
continue;
|
|
3376
|
+
}
|
|
3377
|
+
let contents;
|
|
3378
|
+
try {
|
|
3379
|
+
contents = readFileSync3(filePath, "utf-8").trim();
|
|
3380
|
+
} catch (error) {
|
|
3381
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3382
|
+
warnings.push(`Failed to read file for ${token} (${filePath}): ${message}; using empty string`);
|
|
3383
|
+
continue;
|
|
3384
|
+
}
|
|
3385
|
+
output += JSON.stringify(contents).slice(1, -1);
|
|
3386
|
+
}
|
|
3387
|
+
output += text.slice(cursor);
|
|
3388
|
+
return { text: output, warnings };
|
|
3389
|
+
}
|
|
3390
|
+
|
|
3391
|
+
// src/config/index.ts
|
|
3392
|
+
function getUserConfigBasePath() {
|
|
3393
|
+
return cortexKitUserConfigBasePath();
|
|
3394
|
+
}
|
|
3395
|
+
function getProjectConfigBasePath(directory) {
|
|
3396
|
+
return cortexKitProjectConfigBasePath(directory);
|
|
3397
|
+
}
|
|
3398
|
+
function resolveLegacyReadFallback(sources) {
|
|
3399
|
+
return { source: sources.find((s) => existsSync4(s.path)) ?? null };
|
|
3400
|
+
}
|
|
3401
|
+
function loadConfigFileDetailed(configPath, source) {
|
|
3402
|
+
if (!existsSync4(configPath)) {
|
|
3403
|
+
return null;
|
|
3404
|
+
}
|
|
3405
|
+
let rawText;
|
|
3406
|
+
let rawWarnings;
|
|
3407
|
+
try {
|
|
3408
|
+
const raw = loadRawConfigFile({ configPath, tier: source });
|
|
3409
|
+
if (!raw)
|
|
3410
|
+
return null;
|
|
3411
|
+
rawText = raw.text;
|
|
3412
|
+
rawWarnings = raw.warnings;
|
|
3413
|
+
} catch (error) {
|
|
3414
|
+
const message = `failed to read config: ${error instanceof Error ? error.message : String(error)}`;
|
|
3415
|
+
return {
|
|
3416
|
+
config: {},
|
|
3417
|
+
warnings: [`${configPath}: ${message}`],
|
|
3418
|
+
parseFailures: [],
|
|
3419
|
+
warningDetails: [
|
|
3420
|
+
{ warningClass: CONFIG_WARNING_CLASS.FILE_IO, source, path: configPath, message }
|
|
3421
|
+
],
|
|
3422
|
+
outcome: "project-file-io-error",
|
|
3423
|
+
source
|
|
3424
|
+
};
|
|
3425
|
+
}
|
|
3426
|
+
try {
|
|
3427
|
+
const substituted = substituteConfigVariables({
|
|
3428
|
+
text: rawText,
|
|
3429
|
+
configPath,
|
|
3430
|
+
isProjectConfig: source === "project"
|
|
3431
|
+
});
|
|
3432
|
+
const rejectedKeyPaths = [];
|
|
3433
|
+
const parsed = parseJsoncRecovering(substituted.text, {
|
|
3434
|
+
onRejectedKey: (path) => rejectedKeyPaths.push(path.join("."))
|
|
3435
|
+
});
|
|
3436
|
+
const config = parsed.value && typeof parsed.value === "object" && !Array.isArray(parsed.value) ? parsed.value : {};
|
|
3437
|
+
const unsafeKeyWarnings = rejectedKeyPaths.map((path) => `Ignored unsafe config key "${path}" (security: prototype-pollution keys are not allowed).`);
|
|
3438
|
+
const firstIssue = parsed.issues[0];
|
|
3439
|
+
const recovered = firstIssue !== undefined && Object.keys(config).length > 0;
|
|
3440
|
+
const parseFailures = firstIssue ? [
|
|
3441
|
+
{
|
|
3442
|
+
warningClass: CONFIG_WARNING_CLASS.FILE_PARSE,
|
|
3443
|
+
source,
|
|
3444
|
+
path: configPath,
|
|
3445
|
+
line: firstIssue.line,
|
|
3446
|
+
column: firstIssue.column,
|
|
3447
|
+
message: firstIssue.message,
|
|
3448
|
+
recovered,
|
|
3449
|
+
warning: `${configPath}:${firstIssue.line}:${firstIssue.column}: ${firstIssue.message}; ${recovered ? "recovered values were applied, but the file must be fixed." : "using defaults for this file."}`
|
|
3450
|
+
}
|
|
3451
|
+
] : [];
|
|
3452
|
+
return {
|
|
3453
|
+
config,
|
|
3454
|
+
warnings: [
|
|
3455
|
+
...parseFailures.map((failure) => failure.warning),
|
|
3456
|
+
...rawWarnings.map((warning) => `${configPath}: ${warning}`),
|
|
3457
|
+
...substituted.warnings.map((warning) => `${configPath}: ${warning}`),
|
|
3458
|
+
...unsafeKeyWarnings.map((warning) => `${configPath}: ${warning}`)
|
|
3459
|
+
],
|
|
3460
|
+
parseFailures,
|
|
3461
|
+
warningDetails: parseFailures,
|
|
3462
|
+
outcome: parseFailures.length > 0 ? "project-file-parse-error" : rejectedKeyPaths.length > 0 ? "schema-recovery" : substituted.warnings.length > 0 ? "substitution-failure" : "ok",
|
|
3463
|
+
source
|
|
3464
|
+
};
|
|
3465
|
+
} catch (error) {
|
|
3466
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3467
|
+
const warning = `${configPath}:1:1: ${message}; using defaults for this file.`;
|
|
3468
|
+
const failure = {
|
|
3469
|
+
warningClass: CONFIG_WARNING_CLASS.FILE_PARSE,
|
|
3470
|
+
source,
|
|
3471
|
+
path: configPath,
|
|
3472
|
+
line: 1,
|
|
3473
|
+
column: 1,
|
|
3474
|
+
message,
|
|
3475
|
+
recovered: false,
|
|
3476
|
+
warning
|
|
3477
|
+
};
|
|
3478
|
+
return {
|
|
3479
|
+
config: {},
|
|
3480
|
+
warnings: [warning],
|
|
3481
|
+
parseFailures: [failure],
|
|
3482
|
+
warningDetails: [failure],
|
|
3483
|
+
outcome: "project-file-parse-error",
|
|
3484
|
+
source
|
|
3485
|
+
};
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
function defineOwnConfigValue(target, key, value) {
|
|
3489
|
+
Object.defineProperty(target, key, {
|
|
3490
|
+
value,
|
|
3491
|
+
enumerable: true,
|
|
3492
|
+
configurable: true,
|
|
3493
|
+
writable: true
|
|
3494
|
+
});
|
|
3495
|
+
}
|
|
3496
|
+
function deepMergeRawConfig(base, override) {
|
|
3497
|
+
const result = {};
|
|
3498
|
+
for (const key of Object.keys(base)) {
|
|
3499
|
+
if (isPrototypePollutionKey(key))
|
|
3500
|
+
continue;
|
|
3501
|
+
defineOwnConfigValue(result, key, base[key]);
|
|
3502
|
+
}
|
|
3503
|
+
for (const key of Object.keys(override)) {
|
|
3504
|
+
if (isPrototypePollutionKey(key))
|
|
3505
|
+
continue;
|
|
3506
|
+
const baseVal = Object.hasOwn(base, key) ? base[key] : undefined;
|
|
3507
|
+
const overrideVal = override[key];
|
|
3508
|
+
let mergedValue;
|
|
3509
|
+
if (baseVal !== null && typeof baseVal === "object" && !Array.isArray(baseVal) && overrideVal !== null && typeof overrideVal === "object" && !Array.isArray(overrideVal)) {
|
|
3510
|
+
mergedValue = key === "protected_tools" ? Object.fromEntries([baseVal, overrideVal].flatMap((value) => Object.entries(value).map(([name, count]) => [
|
|
3511
|
+
name.toLowerCase().replace(/^mcp_/, ""),
|
|
3512
|
+
count
|
|
3513
|
+
]))) : deepMergeRawConfig(baseVal, overrideVal);
|
|
3514
|
+
} else if (key === "disabled_hooks" && Array.isArray(baseVal) && Array.isArray(overrideVal)) {
|
|
3515
|
+
mergedValue = [...new Set([...baseVal, ...overrideVal])];
|
|
3516
|
+
} else {
|
|
3517
|
+
mergedValue = overrideVal;
|
|
3518
|
+
}
|
|
3519
|
+
defineOwnConfigValue(result, key, mergedValue);
|
|
3520
|
+
}
|
|
3521
|
+
return result;
|
|
3522
|
+
}
|
|
3523
|
+
function redactConfigValue(value) {
|
|
3524
|
+
if (value === undefined)
|
|
3525
|
+
return "<missing>";
|
|
3526
|
+
if (value === null)
|
|
3527
|
+
return "null";
|
|
3528
|
+
if (typeof value === "string")
|
|
3529
|
+
return `string, ${value.length} char${value.length === 1 ? "" : "s"}`;
|
|
3530
|
+
if (typeof value === "number")
|
|
3531
|
+
return `number ${value}`;
|
|
3532
|
+
if (typeof value === "boolean")
|
|
3533
|
+
return `boolean ${value}`;
|
|
3534
|
+
if (Array.isArray(value))
|
|
3535
|
+
return `array, ${value.length} item${value.length === 1 ? "" : "s"}`;
|
|
3536
|
+
if (typeof value === "object") {
|
|
3537
|
+
const keys = Object.keys(value);
|
|
3538
|
+
return `object with keys [${keys.join(", ")}]`;
|
|
3539
|
+
}
|
|
3540
|
+
return typeof value;
|
|
3541
|
+
}
|
|
3542
|
+
var warnedProtectedTagsDeprecation = false;
|
|
3543
|
+
function formatProtectedTokensBelowMinWarning(value) {
|
|
3544
|
+
return `protected_tokens is a token floor (minimum ${PROTECTED_TOKENS_MIN}, default derived from the context window); ${value} looks like the old protected_tags count. Remove the key to use the default, or set a token count such as 16000.`;
|
|
3545
|
+
}
|
|
3546
|
+
var MODEL_HARNESS_BLOCKS = ["opencode", "pi", "omp"];
|
|
3547
|
+
function misplacedAgentModelWarnings(rawConfig) {
|
|
3548
|
+
const warnings = [];
|
|
3549
|
+
for (const agent of ["historian", "dreamer"]) {
|
|
3550
|
+
const block = rawConfig[agent];
|
|
3551
|
+
if (!block || typeof block !== "object" || Array.isArray(block))
|
|
3552
|
+
continue;
|
|
3553
|
+
const record = block;
|
|
3554
|
+
if (!Object.hasOwn(record, "model"))
|
|
3555
|
+
continue;
|
|
3556
|
+
const harnessWithModel = MODEL_HARNESS_BLOCKS.find((harness) => {
|
|
3557
|
+
const sub = record[harness];
|
|
3558
|
+
return sub !== null && typeof sub === "object" && !Array.isArray(sub) && Object.hasOwn(sub, "model");
|
|
3559
|
+
});
|
|
3560
|
+
if (harnessWithModel)
|
|
3561
|
+
continue;
|
|
3562
|
+
warnings.push(`${agent}.model is not read: the ${agent} model is resolved per harness, so it has to be ${agent}.opencode.model (OpenCode 1 and 2), ${agent}.pi.model, or ${agent}.omp.model. As written the ${agent} resolves to no models and never runs.`);
|
|
3563
|
+
}
|
|
3564
|
+
return warnings;
|
|
3565
|
+
}
|
|
3566
|
+
function warnProtectedTagsDeprecationOnce() {
|
|
3567
|
+
if (!warnedProtectedTagsDeprecation) {
|
|
3568
|
+
warnedProtectedTagsDeprecation = true;
|
|
3569
|
+
log("[magic-context] protected_tags is deprecated and ignored; use protected_tokens instead.");
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
3573
|
+
const preMigrationWarnings = [];
|
|
3574
|
+
const configWithoutRemovedAgent = stripRemovedAgentConfig(rawConfig, preMigrationWarnings);
|
|
3575
|
+
if (Object.hasOwn(rawConfig, "protected_tags")) {
|
|
3576
|
+
warnProtectedTagsDeprecationOnce();
|
|
3577
|
+
preMigrationWarnings.push("protected_tags is deprecated and ignored; use protected_tokens instead.");
|
|
3578
|
+
}
|
|
3579
|
+
if (Object.hasOwn(rawConfig, "smart_drops")) {
|
|
3580
|
+
preMigrationWarnings.push("smart_drops is deprecated and ignored; supersession reclaim is always on. This key no longer does anything; remove it.");
|
|
3581
|
+
}
|
|
3582
|
+
preMigrationWarnings.push(...misplacedAgentModelWarnings(rawConfig));
|
|
3583
|
+
const migratedExperimental = migrateLegacyExperimental(configWithoutRemovedAgent, preMigrationWarnings);
|
|
3584
|
+
const migratedDreamer = migrateDreamerV2(migratedExperimental, preMigrationWarnings);
|
|
3585
|
+
const migrated = migrateLegacyAgentEnabledInMemory(migratedDreamer, preMigrationWarnings);
|
|
3586
|
+
const parsed = MagicContextConfigSchema.safeParse(migrated);
|
|
3587
|
+
const disabledHooks = Array.isArray(rawConfig.disabled_hooks) ? rawConfig.disabled_hooks.filter((value) => typeof value === "string") : undefined;
|
|
3588
|
+
const command = typeof rawConfig.command === "object" && rawConfig.command !== null ? rawConfig.command : undefined;
|
|
3589
|
+
if (parsed.success) {
|
|
3590
|
+
return {
|
|
3591
|
+
...parsed.data,
|
|
3592
|
+
disabled_hooks: disabledHooks,
|
|
3593
|
+
command,
|
|
3594
|
+
...preMigrationWarnings.length > 0 ? { configWarnings: preMigrationWarnings } : {}
|
|
3595
|
+
};
|
|
3596
|
+
}
|
|
3597
|
+
const defaults = MagicContextConfigSchema.parse({});
|
|
3598
|
+
const warnings = [];
|
|
3599
|
+
const errorPaths = new Set;
|
|
3600
|
+
const customMessagesByKey = new Map;
|
|
3601
|
+
const issuePathsByKey = new Map;
|
|
3602
|
+
const GENERIC_ZOD_PREFIXES = ["Too big", "Too small", "Invalid input", "Invalid", "Expected"];
|
|
3603
|
+
for (const issue of parsed.error.issues) {
|
|
3604
|
+
const topKey = issue.path[0];
|
|
3605
|
+
if (topKey !== undefined) {
|
|
3606
|
+
const key = String(topKey);
|
|
3607
|
+
errorPaths.add(key);
|
|
3608
|
+
const paths = issuePathsByKey.get(key) ?? [];
|
|
3609
|
+
if (issue.code === "unrecognized_keys") {
|
|
3610
|
+
for (const unrecognizedKey of issue.keys) {
|
|
3611
|
+
paths.push([...issue.path, unrecognizedKey]);
|
|
3612
|
+
}
|
|
3613
|
+
} else {
|
|
3614
|
+
paths.push([...issue.path]);
|
|
3615
|
+
}
|
|
3616
|
+
issuePathsByKey.set(key, paths);
|
|
3617
|
+
const msg = issue.message;
|
|
3618
|
+
if (msg && !GENERIC_ZOD_PREFIXES.some((p) => msg.startsWith(p))) {
|
|
3619
|
+
if (!customMessagesByKey.has(key)) {
|
|
3620
|
+
customMessagesByKey.set(key, msg);
|
|
3621
|
+
}
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
const patched = { ...rawConfig };
|
|
3626
|
+
for (const key of errorPaths) {
|
|
3627
|
+
recoveredTopLevelKeys.push(key);
|
|
3628
|
+
const isAgentConfig = key === "historian" || key === "dreamer";
|
|
3629
|
+
const issuePaths = issuePathsByKey.get(key) ?? [];
|
|
3630
|
+
const rawValue = rawConfig[key];
|
|
3631
|
+
const allNested = issuePaths.length > 0 && issuePaths.every((p) => p.length >= 2) && typeof rawValue === "object" && rawValue !== null && !Array.isArray(rawValue);
|
|
3632
|
+
if (allNested) {
|
|
3633
|
+
let prunedBlock = {
|
|
3634
|
+
...rawValue
|
|
3635
|
+
};
|
|
3636
|
+
const prunedLeaves = [];
|
|
3637
|
+
for (const p of issuePaths) {
|
|
3638
|
+
const relative = p.slice(1);
|
|
3639
|
+
const result = pruneNestedConfigLeaf(prunedBlock, relative);
|
|
3640
|
+
if (result) {
|
|
3641
|
+
prunedBlock = result.block;
|
|
3642
|
+
prunedLeaves.push(result.removed);
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
if (prunedLeaves.length === issuePaths.length) {
|
|
3646
|
+
patched[key] = prunedBlock;
|
|
3647
|
+
const reason = customMessagesByKey.get(key);
|
|
3648
|
+
warnings.push(`"${key}": invalid nested field(s) ${prunedLeaves.map((leaf) => `"${key}.${leaf}"`).join(", ")}, using defaults for those.${reason ? ` ${reason}` : ""}`);
|
|
3649
|
+
continue;
|
|
3650
|
+
}
|
|
3651
|
+
}
|
|
3652
|
+
if (isAgentConfig) {
|
|
3653
|
+
delete patched[key];
|
|
3654
|
+
warnings.push(`"${key}": invalid agent configuration, ignoring. Check your magic-context.jsonc.`);
|
|
3655
|
+
continue;
|
|
3656
|
+
}
|
|
3657
|
+
delete patched[key];
|
|
3658
|
+
const defaultVal = defaults[key];
|
|
3659
|
+
const reason = customMessagesByKey.get(key);
|
|
3660
|
+
const invalidRawValue = rawConfig[key];
|
|
3661
|
+
if (key === "protected_tokens" && typeof invalidRawValue === "number" && invalidRawValue < PROTECTED_TOKENS_MIN) {
|
|
3662
|
+
warnings.push(formatProtectedTokensBelowMinWarning(invalidRawValue));
|
|
3663
|
+
continue;
|
|
3664
|
+
}
|
|
3665
|
+
warnings.push(`"${key}": invalid value (${redactConfigValue(rawConfig[key])}), using default ${JSON.stringify(defaultVal)}.${reason ? ` ${reason}` : ""}`);
|
|
3666
|
+
}
|
|
3667
|
+
const retryMigrated = migrateLegacyAgentEnabledInMemory(migrateDreamerV2(migrateLegacyExperimental(patched, preMigrationWarnings), preMigrationWarnings), preMigrationWarnings);
|
|
3668
|
+
const retryParsed = MagicContextConfigSchema.safeParse(retryMigrated);
|
|
3669
|
+
if (retryParsed.success) {
|
|
3670
|
+
return {
|
|
3671
|
+
...retryParsed.data,
|
|
3672
|
+
disabled_hooks: disabledHooks,
|
|
3673
|
+
command,
|
|
3674
|
+
configWarnings: [...preMigrationWarnings, ...warnings]
|
|
3675
|
+
};
|
|
3676
|
+
}
|
|
3677
|
+
warnings.push("Config recovery failed, using all defaults.");
|
|
3678
|
+
return {
|
|
3679
|
+
...defaults,
|
|
3680
|
+
disabled_hooks: disabledHooks,
|
|
3681
|
+
command,
|
|
3682
|
+
configWarnings: [...preMigrationWarnings, ...warnings]
|
|
3683
|
+
};
|
|
3684
|
+
}
|
|
3685
|
+
function collectSchemaIssuePaths(rawConfig) {
|
|
3686
|
+
const scratch = [];
|
|
3687
|
+
const migrated = migrateLegacyAgentEnabledInMemory(migrateDreamerV2(migrateLegacyExperimental(stripRemovedAgentConfig(rawConfig, scratch), scratch), scratch), scratch);
|
|
3688
|
+
const parsed = MagicContextConfigSchema.safeParse(migrated);
|
|
3689
|
+
if (parsed.success)
|
|
3690
|
+
return [];
|
|
3691
|
+
return parsed.error.issues.flatMap((issue) => issue.code === "unrecognized_keys" ? issue.keys.map((key) => [...issue.path, key]) : [[...issue.path]]);
|
|
3692
|
+
}
|
|
3693
|
+
function hasUserTierSubcConfig(config) {
|
|
3694
|
+
const subc = config?.subc;
|
|
3695
|
+
if (typeof subc !== "object" || subc === null || Array.isArray(subc))
|
|
3696
|
+
return false;
|
|
3697
|
+
const connectionFile = subc.connection_file;
|
|
3698
|
+
return typeof connectionFile === "string" && connectionFile.trim().length > 0;
|
|
3699
|
+
}
|
|
3700
|
+
function collectEmptyStringPaths(value, prefix = "") {
|
|
3701
|
+
if (typeof value === "string") {
|
|
3702
|
+
return value === "" && prefix ? [prefix] : [];
|
|
3703
|
+
}
|
|
3704
|
+
if (Array.isArray(value) || value === null || typeof value !== "object") {
|
|
3705
|
+
return [];
|
|
3706
|
+
}
|
|
3707
|
+
const paths = [];
|
|
3708
|
+
for (const [key, child] of Object.entries(value)) {
|
|
3709
|
+
const nextPrefix = prefix ? `${prefix}.${key}` : key;
|
|
3710
|
+
paths.push(...collectEmptyStringPaths(child, nextPrefix));
|
|
3711
|
+
}
|
|
3712
|
+
return paths;
|
|
3713
|
+
}
|
|
3714
|
+
function bindSubstitutionFailures(loaded) {
|
|
3715
|
+
if (!loaded || loaded.warnings.length === 0 || loaded.outcome !== "substitution-failure") {
|
|
3716
|
+
return [];
|
|
3717
|
+
}
|
|
3718
|
+
const emptyPaths = collectEmptyStringPaths(loaded.config);
|
|
3719
|
+
return loaded.warnings.map((message) => {
|
|
3720
|
+
const matchedPath = emptyPaths.find((path) => {
|
|
3721
|
+
const tail = path.split(".").at(-1) ?? path;
|
|
3722
|
+
return message.includes(path) || message.toLowerCase().includes(tail.toLowerCase());
|
|
3723
|
+
});
|
|
3724
|
+
return { keyPath: matchedPath ?? "<unknown>", source: loaded.source, message };
|
|
3725
|
+
});
|
|
3726
|
+
}
|
|
3727
|
+
function combinedOutcome(args) {
|
|
3728
|
+
const sourceOutcomes = Object.values(args.sources);
|
|
3729
|
+
if (sourceOutcomes.includes("project-file-parse-error"))
|
|
3730
|
+
return "project-file-parse-error";
|
|
3731
|
+
if (sourceOutcomes.includes("project-file-io-error"))
|
|
3732
|
+
return "project-file-io-error";
|
|
3733
|
+
if (sourceOutcomes.includes("legacy-config-unmigrated"))
|
|
3734
|
+
return "legacy-config-unmigrated";
|
|
3735
|
+
if (args.recoveredTopLevelKeys.length > 0)
|
|
3736
|
+
return "schema-recovery";
|
|
3737
|
+
if (args.substitutionFailures.length > 0)
|
|
3738
|
+
return "substitution-failure";
|
|
3739
|
+
return "ok";
|
|
3740
|
+
}
|
|
3741
|
+
function loadPluginConfigDetailed(directory, applyRuntimeGlobals = true) {
|
|
3742
|
+
const userDetected = detectConfigFile(getUserConfigBasePath());
|
|
3743
|
+
const projectDetected = detectConfigFile(getProjectConfigBasePath(directory));
|
|
3744
|
+
const legacySources = resolveLegacyConfigSources(directory);
|
|
3745
|
+
const harnessLegacy = resolveLegacyConfigSourcesForHarness(directory, "opencode");
|
|
3746
|
+
const userLegacyFallback = userDetected.format === "none" ? resolveLegacyReadFallback(harnessLegacy.user) : { source: null };
|
|
3747
|
+
const projectLegacyFallback = projectDetected.format === "none" ? resolveLegacyReadFallback(harnessLegacy.project) : { source: null };
|
|
3748
|
+
const legacyUserUnmigrated = userDetected.format === "none" && !userLegacyFallback.source && legacySources.user.some((source) => existsSync4(source.path));
|
|
3749
|
+
const legacyProjectUnmigrated = projectDetected.format === "none" && !projectLegacyFallback.source && legacySources.project.some((source) => existsSync4(source.path));
|
|
3750
|
+
const userLoaded = userDetected.format !== "none" ? loadConfigFileDetailed(userDetected.path, "user") : userLegacyFallback.source ? loadConfigFileDetailed(userLegacyFallback.source.path, "user") : null;
|
|
3751
|
+
const projectLoaded = projectDetected.format !== "none" ? loadConfigFileDetailed(projectDetected.path, "project") : projectLegacyFallback.source ? loadConfigFileDetailed(projectLegacyFallback.source.path, "project") : null;
|
|
3752
|
+
const allWarnings = [];
|
|
3753
|
+
const removedConfigWarnings = [];
|
|
3754
|
+
const userRaw = stripRemovedAgentConfig(userLoaded?.config ?? {}, removedConfigWarnings);
|
|
3755
|
+
if (userLegacyFallback.source) {
|
|
3756
|
+
allWarnings.push(`[user config] reading legacy config from ${userLegacyFallback.source.path} until migration completes; run \`npx @cortexkit/magic-context doctor\` to consolidate into the shared CortexKit location.`);
|
|
3757
|
+
} else if (legacyUserUnmigrated) {
|
|
3758
|
+
allWarnings.push("[user config] legacy Magic Context config exists but the shared CortexKit config is absent; embedding registration is paused until config migration completes.");
|
|
3759
|
+
}
|
|
3760
|
+
if (projectLegacyFallback.source) {
|
|
3761
|
+
allWarnings.push(`[project config] reading legacy config from ${projectLegacyFallback.source.path} until migration completes; run \`npx @cortexkit/magic-context doctor\` to consolidate into the shared CortexKit location.`);
|
|
3762
|
+
} else if (legacyProjectUnmigrated) {
|
|
3763
|
+
allWarnings.push("[project config] legacy Magic Context config exists but the shared CortexKit config is absent; embedding registration is paused until config migration completes.");
|
|
3764
|
+
}
|
|
3765
|
+
if (userLoaded) {
|
|
3766
|
+
allWarnings.push(...userLoaded.warnings.map((w) => `[user config] ${w}`));
|
|
3767
|
+
}
|
|
3768
|
+
let projectRaw = {};
|
|
3769
|
+
if (projectLoaded) {
|
|
3770
|
+
allWarnings.push(...projectLoaded.warnings.map((w) => `[project config] ${w}`));
|
|
3771
|
+
projectRaw = stripRemovedAgentConfig(projectLoaded.config, removedConfigWarnings);
|
|
3772
|
+
for (const warning of stripUnsafeProjectConfigFields(projectRaw)) {
|
|
3773
|
+
allWarnings.push(`[project config] ${warning}`);
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
allWarnings.push(...removedConfigWarnings.map((warning) => `[config] ${warning}`));
|
|
3777
|
+
const profileResolution = resolveConfigProfile({
|
|
3778
|
+
userRaw,
|
|
3779
|
+
projectRaw
|
|
3780
|
+
});
|
|
3781
|
+
allWarnings.push(...profileResolution.warnings.map((warning) => `[config] ${warning}`));
|
|
3782
|
+
const trustedProfiledRaw = deepMergeRawConfig(profileResolution.userBase, profileResolution.overlay);
|
|
3783
|
+
let mergedRaw = trustedProfiledRaw;
|
|
3784
|
+
const trustedBaseConfig = parsePluginConfig(trustedProfiledRaw);
|
|
3785
|
+
let projectRestoredTopLevelKeys = [];
|
|
3786
|
+
if (projectLoaded) {
|
|
3787
|
+
mergedRaw = deepMergeRawConfig(mergedRaw, profileResolution.projectBase);
|
|
3788
|
+
for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, mergedRaw, profileResolution.userBase)) {
|
|
3789
|
+
allWarnings.push(`[project config] ${warning}`);
|
|
3790
|
+
}
|
|
3791
|
+
for (const warning of constrainProjectThresholdOverrides({
|
|
3792
|
+
mergedRaw,
|
|
3793
|
+
projectRaw: profileResolution.projectBase,
|
|
3794
|
+
trustedBaseConfig
|
|
3795
|
+
})) {
|
|
3796
|
+
allWarnings.push(`[project config] ${warning}`);
|
|
3797
|
+
}
|
|
3798
|
+
const restoredOverProject = restoreTrustedValuesOverInvalidProjectValues({
|
|
3799
|
+
mergedRaw,
|
|
3800
|
+
trustedRaw: trustedProfiledRaw,
|
|
3801
|
+
projectRaw: profileResolution.projectBase,
|
|
3802
|
+
collectIssuePaths: collectSchemaIssuePaths
|
|
3803
|
+
});
|
|
3804
|
+
for (const warning of restoredOverProject.warnings) {
|
|
3805
|
+
allWarnings.push(`[project config] ${warning}`);
|
|
3806
|
+
}
|
|
3807
|
+
projectRestoredTopLevelKeys = restoredOverProject.restoredTopLevelKeys;
|
|
3808
|
+
for (const warning of constrainProjectCommands({
|
|
3809
|
+
mergedRaw,
|
|
3810
|
+
trustedRaw: trustedProfiledRaw,
|
|
3811
|
+
projectRaw: profileResolution.projectBase,
|
|
3812
|
+
reservedNames: Object.keys(getMagicContextBuiltinCommands())
|
|
3813
|
+
})) {
|
|
3814
|
+
allWarnings.push(`[project config] ${warning}`);
|
|
3815
|
+
}
|
|
3816
|
+
}
|
|
3817
|
+
const recoveredTopLevelKeys = [];
|
|
3818
|
+
const cacheTtlConfigured = Object.hasOwn(mergedRaw, "cache_ttl");
|
|
3819
|
+
const config = parsePluginConfig(mergedRaw, recoveredTopLevelKeys);
|
|
3820
|
+
for (const key of projectRestoredTopLevelKeys) {
|
|
3821
|
+
if (!recoveredTopLevelKeys.includes(key))
|
|
3822
|
+
recoveredTopLevelKeys.push(key);
|
|
3823
|
+
}
|
|
3824
|
+
attachProtectedTokensTierOverrides(config, {
|
|
3825
|
+
trustedUser: trustedBaseConfig.protected_tokens,
|
|
3826
|
+
project: projectLoaded ? profileResolution.projectBase.protected_tokens : undefined
|
|
3827
|
+
});
|
|
3828
|
+
if (profileResolution.activeProfile)
|
|
3829
|
+
config.profile = profileResolution.activeProfile;
|
|
3830
|
+
if (applyRuntimeGlobals) {
|
|
3831
|
+
setOutputReserveConfig(config.output_reserve);
|
|
3832
|
+
setWindowOverlayPath(config.models?.window_overlay_path);
|
|
3833
|
+
}
|
|
3834
|
+
const leafValidationWarnings = [...config.configWarnings ?? []];
|
|
3835
|
+
if (config.configWarnings?.length) {
|
|
3836
|
+
allWarnings.push(...config.configWarnings.map((w) => {
|
|
3837
|
+
if (userLoaded && projectLoaded)
|
|
3838
|
+
return `[config] ${w}`;
|
|
3839
|
+
if (userLoaded)
|
|
3840
|
+
return `[user config] ${w}`;
|
|
3841
|
+
return `[project config] ${w}`;
|
|
3842
|
+
}));
|
|
3843
|
+
}
|
|
3844
|
+
const resolvedTransformMode = resolveTransformMode({
|
|
3845
|
+
configured: config.transform_mode,
|
|
3846
|
+
userTierHasSubc: hasUserTierSubcConfig(userRaw),
|
|
3847
|
+
compactionEnabled: isCompactionEnabled(config)
|
|
3848
|
+
});
|
|
3849
|
+
config.transform_mode = resolvedTransformMode.mode;
|
|
3850
|
+
allWarnings.push(...resolvedTransformMode.warnings.map((warning) => `[config] ${warning}`));
|
|
3851
|
+
if (allWarnings.length > 0) {
|
|
3852
|
+
config.configWarnings = allWarnings;
|
|
3853
|
+
} else if ("configWarnings" in config) {
|
|
3854
|
+
config.configWarnings = undefined;
|
|
3855
|
+
}
|
|
3856
|
+
const substitutionFailures = [
|
|
3857
|
+
...bindSubstitutionFailures(userLoaded),
|
|
3858
|
+
...bindSubstitutionFailures(projectLoaded)
|
|
3859
|
+
];
|
|
3860
|
+
const configParseFailures = [
|
|
3861
|
+
...userLoaded?.parseFailures ?? [],
|
|
3862
|
+
...projectLoaded?.parseFailures ?? []
|
|
3863
|
+
];
|
|
3864
|
+
const warningDetails = [
|
|
3865
|
+
...userLoaded?.warningDetails ?? [],
|
|
3866
|
+
...projectLoaded?.warningDetails ?? [],
|
|
3867
|
+
...leafValidationWarnings.map((message) => ({
|
|
3868
|
+
warningClass: CONFIG_WARNING_CLASS.INVALID_LEAF,
|
|
3869
|
+
message
|
|
3870
|
+
}))
|
|
3871
|
+
];
|
|
3872
|
+
config.configParseFailures = configParseFailures;
|
|
3873
|
+
config.configWarningDetails = warningDetails;
|
|
3874
|
+
config.cacheTtlConfigured = cacheTtlConfigured;
|
|
3875
|
+
const sources = {
|
|
3876
|
+
userConfig: userLoaded?.outcome ?? (legacyUserUnmigrated ? "legacy-config-unmigrated" : "ok"),
|
|
3877
|
+
projectConfig: projectLoaded?.outcome ?? (legacyProjectUnmigrated ? "legacy-config-unmigrated" : "ok")
|
|
3878
|
+
};
|
|
3879
|
+
return {
|
|
3880
|
+
config,
|
|
3881
|
+
registrationPromptSurface: trustedBaseConfig.prompt_surface,
|
|
3882
|
+
loadOutcome: combinedOutcome({ sources, substitutionFailures, recoveredTopLevelKeys }),
|
|
3883
|
+
sources,
|
|
3884
|
+
substitutionFailures,
|
|
3885
|
+
recoveredTopLevelKeys,
|
|
3886
|
+
configParseFailures,
|
|
3887
|
+
warningDetails,
|
|
3888
|
+
cacheTtlConfigured
|
|
3889
|
+
};
|
|
3890
|
+
}
|
|
3891
|
+
|
|
3892
|
+
export { getMagicContextBuiltinCommands, parseJsoncRecovering, readJsoncFile, detectConfigFile, COMPACTION_ENABLED_PATH, isDreamerRunnable, isCompactionEnabled, cortexKitUserConfigBasePath, cortexKitProjectConfigBasePath, resolveLegacyConfigSources, resolveLegacyConfigSourcesForHarness, getProtectedTokensTierOverrides, loadPluginConfigDetailed };
|