@cortexkit/opencode-magic-context 0.46.1 → 0.48.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/dist/agents/magic-context-prompt.d.ts +1 -1
- package/dist/agents/magic-context-prompt.d.ts.map +1 -1
- package/dist/{announcement-y35wzg2r.js → announcement-fp14dw0n.js} +3 -2
- package/dist/auto-search-worker.js +112 -0
- 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/mural-model-deprecation.d.ts +15 -0
- package/dist/config/mural-model-deprecation.d.ts.map +1 -0
- package/dist/config/project-security.d.ts +0 -3
- package/dist/config/project-security.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +21 -9
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/{conflict-warning-hook-7fj2b9jw.js → conflict-warning-hook-w8cykrnf.js} +12 -9
- package/dist/{context-sh2m2vde.js → context-m0cy262m.js} +1785 -913
- package/dist/{derive-budgets-7nj7r1rv.js → derive-budgets-sg0xsq7s.js} +4 -3
- package/dist/embedding-activity-g1dhes6g.js +10 -0
- package/dist/embedding-backfill-9rcm1mfy.js +21 -0
- package/dist/embedding-cache-mgyr73ef.js +16 -0
- package/dist/embedding-worker.js +11 -9
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts +1 -0
- package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-config.d.ts +3 -3
- package/dist/features/magic-context/dreamer/task-config.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-executor.d.ts +1 -1
- 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-registry.d.ts +1 -0
- package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
- package/dist/features/magic-context/message-index-async.d.ts +16 -3
- package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
- package/dist/features/magic-context/message-index-bounded.d.ts +17 -0
- package/dist/features/magic-context/message-index-bounded.d.ts.map +1 -0
- package/dist/features/magic-context/message-index.d.ts +7 -1
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/mural/render-trigger.d.ts +7 -4
- package/dist/features/magic-context/mural/render-trigger.d.ts.map +1 -1
- package/dist/features/magic-context/overflow-detection.d.ts +2 -0
- package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
- package/dist/features/magic-context/pi-content-decisions.d.ts +7 -1
- package/dist/features/magic-context/pi-content-decisions.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts +7 -0
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/search.d.ts +31 -0
- package/dist/features/magic-context/search.d.ts.map +1 -1
- package/dist/features/magic-context/session-activity.d.ts.map +1 -1
- package/dist/features/magic-context/session-project-storage.d.ts +8 -2
- package/dist/features/magic-context/session-project-storage.d.ts.map +1 -1
- 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/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-historian-runs.d.ts +2 -5
- package/dist/features/magic-context/storage-historian-runs.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +12 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-session.d.ts +6 -0
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tag-identity-revision.d.ts +30 -0
- package/dist/features/magic-context/storage-tag-identity-revision.d.ts.map +1 -0
- package/dist/features/magic-context/storage-tags.d.ts +148 -3
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +1 -0
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -1
- package/dist/features/magic-context/transform-decision-log.d.ts +4 -2
- package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
- package/dist/harness-e4avh192.js +10 -0
- package/dist/hooks/magic-context/active-anthropic-turn.d.ts +10 -0
- package/dist/hooks/magic-context/active-anthropic-turn.d.ts.map +1 -0
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-blocking.fixture.d.ts +2 -0
- package/dist/hooks/magic-context/auto-search-blocking.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-deadline.d.ts +7 -0
- package/dist/hooks/magic-context/auto-search-deadline.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-host-review.fixture.d.ts +3 -0
- package/dist/hooks/magic-context/auto-search-host-review.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-lock-review.fixture.d.ts +2 -0
- package/dist/hooks/magic-context/auto-search-lock-review.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-long-lock-review.fixture.d.ts +2 -0
- package/dist/hooks/magic-context/auto-search-long-lock-review.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-omp-host-review.fixture.d.ts +4 -0
- package/dist/hooks/magic-context/auto-search-omp-host-review.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-omp-loader.fixture.d.ts +3 -0
- package/dist/hooks/magic-context/auto-search-omp-loader.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-runner.d.ts +1 -1
- package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-snapshot.fixture.d.ts +4 -0
- package/dist/hooks/magic-context/auto-search-snapshot.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-worker-client.d.ts +98 -0
- package/dist/hooks/magic-context/auto-search-worker-client.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-worker.d.ts +2 -0
- package/dist/hooks/magic-context/auto-search-worker.d.ts.map +1 -0
- package/dist/hooks/magic-context/caveman-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +1 -0
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +3 -5
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts +2 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts +3 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
- package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/historian-drain-gate.d.ts +11 -0
- package/dist/hooks/magic-context/historian-drain-gate.d.ts.map +1 -0
- package/dist/hooks/magic-context/hook.d.ts +3 -2
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/latest-assistant-turn.d.ts +25 -0
- package/dist/hooks/magic-context/latest-assistant-turn.d.ts.map +1 -0
- package/dist/hooks/magic-context/latest-thinking-recovery.d.ts +61 -0
- package/dist/hooks/magic-context/latest-thinking-recovery.d.ts.map +1 -0
- package/dist/hooks/magic-context/lkg-persist.d.ts +4 -3
- package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-replay.d.ts +13 -8
- package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-slot.d.ts +139 -2
- package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
- package/dist/hooks/magic-context/message-search-accepting-silent-worker.fixture.d.ts +2 -0
- package/dist/hooks/magic-context/message-search-accepting-silent-worker.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
- package/dist/hooks/magic-context/oc-stall-r2-warmup-worker.fixture.d.ts +2 -0
- package/dist/hooks/magic-context/oc-stall-r2-warmup-worker.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/oc-stall-search-review.fixture.d.ts +2 -0
- package/dist/hooks/magic-context/oc-stall-search-review.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/opencode-proven-floor.d.ts +6 -0
- package/dist/hooks/magic-context/opencode-proven-floor.d.ts.map +1 -0
- package/dist/hooks/magic-context/opencode1-to-model-messages.fixture.d.ts +63 -0
- package/dist/hooks/magic-context/opencode1-to-model-messages.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/pass-outcome.d.ts.map +1 -1
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
- package/dist/hooks/magic-context/provider-visible-parts.d.ts +45 -0
- package/dist/hooks/magic-context/provider-visible-parts.d.ts.map +1 -0
- package/dist/hooks/magic-context/raw-ordinal-warmup-silent-worker.fixture.d.ts +2 -0
- package/dist/hooks/magic-context/raw-ordinal-warmup-silent-worker.fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/raw-ordinal-warmup-worker.d.ts +2 -0
- package/dist/hooks/magic-context/raw-ordinal-warmup-worker.d.ts.map +1 -0
- package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts +87 -0
- package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts.map +1 -0
- package/dist/hooks/magic-context/read-session-chunk.d.ts +12 -0
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-formatting.d.ts +5 -0
- package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-raw.d.ts +83 -1
- package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
- package/dist/hooks/magic-context/reasoning-budget-status.d.ts +15 -0
- package/dist/hooks/magic-context/reasoning-budget-status.d.ts.map +1 -0
- package/dist/hooks/magic-context/reasoning-budget.d.ts +40 -0
- package/dist/hooks/magic-context/reasoning-budget.d.ts.map +1 -0
- package/dist/hooks/magic-context/reasoning-removal.d.ts +6 -6
- package/dist/hooks/magic-context/reasoning-removal.d.ts.map +1 -1
- package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/sentinel.d.ts +45 -1
- package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts +21 -5
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts +1 -0
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts +21 -0
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-owner-warmup.d.ts +6 -0
- package/dist/hooks/magic-context/tag-owner-warmup.d.ts.map +1 -0
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
- package/dist/hooks/magic-context/token-count-exact.d.ts +35 -0
- package/dist/hooks/magic-context/token-count-exact.d.ts.map +1 -0
- package/dist/hooks/magic-context/tool-drop-target.d.ts +5 -0
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +3 -28
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +28 -6
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +11 -3
- 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-hpecdzec.js → index-0an7742d.js} +6820 -6587
- package/dist/index-0qhce371.js +120 -0
- package/dist/{index-q6hef7fh.js → index-0sahzkwr.js} +6 -19
- package/dist/{index-k5bdx1bx.js → index-0w56v4fm.js} +3 -5
- package/dist/index-14cjxt20.js +819 -0
- package/dist/{v2/server-51dv1pr5.js → index-1qb0z7wa.js} +301 -27
- package/dist/index-2bvekkfy.js +11 -0
- package/dist/{index-sj29b3z2.js → index-2y0s2hep.js} +3 -3
- package/dist/index-4dhv7mqz.js +131 -0
- package/dist/{index-b35pxds2.js → index-58e3y90n.js} +1 -18
- package/dist/index-5zygecde.js +152 -0
- package/dist/{index-sjthx78w.js → index-692jzy0p.js} +16879 -22907
- package/dist/index-72nhv486.js +2307 -0
- package/dist/index-7jzrrxap.js +931 -0
- package/dist/index-7mx8v0pw.js +3591 -0
- package/dist/index-8ajstryz.js +18 -0
- package/dist/{index-sfpzqvdz.js → index-8cd2j99z.js} +2 -3
- package/dist/{index-hybnrwq0.js → index-8j7gqj40.js} +131 -128
- package/dist/index-bdckkfw6.js +3261 -0
- package/dist/{index-8x2v7gg9.js → index-bhvjj0ys.js} +158 -2455
- package/dist/index-c43kr12f.js +3030 -0
- package/dist/index-cb7emxgj.js +984 -0
- package/dist/index-d9vfe7xq.js +16 -0
- package/dist/{index-5gq3b2ya.js → index-db7zwa3v.js} +147 -209
- package/dist/index-dhwzyd54.js +1142 -0
- package/dist/{index-8da2zjhz.js → index-eeezr5zz.js} +9 -7
- package/dist/{index-pkbcrdqs.js → index-f0h6xwqm.js} +3412 -4552
- package/dist/index-fb3zxn06.js +13 -0
- package/dist/index-fbv1dn35.js +171 -0
- package/dist/index-fr0wbhdn.js +43 -0
- package/dist/{index-mc22ayvf.js → index-ghc9f0n7.js} +11 -9
- package/dist/{index-fzbvakh0.js → index-jcbd3znx.js} +3 -3
- package/dist/{index-5p8jdswx.js → index-k1xb52kd.js} +20 -13
- package/dist/index-k9nnwad5.js +3532 -0
- package/dist/{v2/server-fg34g6a5.js → index-kb9nn0a0.js} +309 -52
- package/dist/index-knh4y330.js +566 -0
- package/dist/{index-q4yp4b52.js → index-mfkzp7qj.js} +28 -28
- package/dist/{index-sgthv3f7.js → index-mmyh6d8f.js} +4 -4
- package/dist/index-pavzsdc6.js +17 -0
- package/dist/{index-0d3g3461.js → index-pdecwzrd.js} +19 -16
- package/dist/index-pg50n748.js +1060 -0
- package/dist/index-q2tqeqde.js +2106 -0
- package/dist/index-q7h7csab.js +3469 -0
- package/dist/index-qt1qqasc.js +22 -0
- package/dist/{index-majxda46.js → index-ty64eqcn.js} +28 -18
- package/dist/{index-7qw742ev.js → index-yq8n9qcb.js} +25 -44
- package/dist/{index-sfnj6h8h.js → index-z8e0psj8.js} +20 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1061 -260
- package/dist/logger-d3wex3dz.js +20 -0
- package/dist/message-index-bounded-7ezbgddp.js +124 -0
- package/dist/{v2/message-time-backfill-r6qkem1x.js → message-time-backfill-brbd63hv.js} +8 -6
- package/dist/migration-worker.js +25 -16
- package/dist/{model-resolution-xhfmyyvy.js → model-resolution-nx97z3x7.js} +1 -1
- package/dist/plugin/dream-timer.d.ts +1 -1
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +3 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/host-stall-profiler-report.d.ts +2 -0
- package/dist/plugin/host-stall-profiler-report.d.ts.map +1 -0
- package/dist/plugin/host-stall-profiler.d.ts +3 -0
- package/dist/plugin/host-stall-profiler.d.ts.map +1 -0
- package/dist/plugin/messages-transform.d.ts +21 -19
- package/dist/plugin/messages-transform.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/plugin/tool-registry.d.ts.map +1 -1
- package/dist/project-embedding-registry-7qzptcw7.js +88 -0
- package/dist/raw-ordinal-warmup-worker.js +60 -0
- package/dist/{read-session-chunk-egz7r68d.js → read-session-chunk-6k83m4fj.js} +15 -9
- package/dist/read-session-raw-3g9qy1xa.js +58 -0
- package/dist/recomp-orchestrator-d3fp1cy0.js +57 -0
- package/dist/{v2/safe-notification-target-eb1n1vfb.js → safe-notification-target-5ffqq32m.js} +4 -2
- package/dist/search-epax1ecv.js +45 -0
- package/dist/{v2/send-session-notification-qs0j78v6.js → send-session-notification-erecz4y4.js} +10 -6
- package/dist/shared/auto-search-lifecycle.d.ts +7 -0
- package/dist/shared/auto-search-lifecycle.d.ts.map +1 -0
- package/dist/shared/conflict-detector.d.ts.map +1 -1
- package/dist/shared/historian-tool-expansions.d.ts +1 -1
- package/dist/shared/historian-tool-expansions.d.ts.map +1 -1
- package/dist/shared/historian-tool-template.d.ts +2 -2
- package/dist/shared/historian-tool-template.d.ts.map +1 -1
- package/dist/shared/host-stall-profiler-bun.d.ts +46 -0
- package/dist/shared/host-stall-profiler-bun.d.ts.map +1 -0
- package/dist/shared/host-stall-profiler-common.d.ts +58 -0
- package/dist/shared/host-stall-profiler-common.d.ts.map +1 -0
- package/dist/shared/host-stall-profiler-node.d.ts +36 -0
- package/dist/shared/host-stall-profiler-node.d.ts.map +1 -0
- package/dist/shared/host-stall-profiler-report.d.ts +68 -0
- package/dist/shared/host-stall-profiler-report.d.ts.map +1 -0
- package/dist/shared/host-stall-profiler.d.ts +5 -0
- package/dist/shared/host-stall-profiler.d.ts.map +1 -0
- package/dist/shared/model-resolution.d.ts +2 -3
- package/dist/shared/model-resolution.d.ts.map +1 -1
- package/dist/shared/sqlite.d.ts +46 -1
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/shared/stable-json.d.ts.map +1 -1
- package/dist/shared/status-view.d.ts.map +1 -1
- package/dist/shared/user-facing-codes.d.ts +0 -5
- package/dist/shared/user-facing-codes.d.ts.map +1 -1
- package/dist/shared/window-geometry.d.ts +4 -0
- package/dist/shared/window-geometry.d.ts.map +1 -1
- package/dist/sqlite-context-pragmas-mv9jqwjh.js +6 -0
- package/dist/sqlite-mhjkerzq.js +46 -0
- package/dist/storage-memory-07fx57k6.js +71 -0
- package/dist/storage-tags-d3b0v2ss.js +131 -0
- package/dist/{task-config-v81k8jvk.js → task-config-cgpg0nvh.js} +2 -2
- package/dist/tools/ctx-expand/render.d.ts.map +1 -1
- package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
- package/dist/tools/ctx-note/constants.d.ts +4 -0
- package/dist/tools/ctx-note/constants.d.ts.map +1 -1
- package/dist/tools/ctx-note/tools.d.ts +1 -0
- package/dist/tools/ctx-note/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/tools.d.ts.map +1 -1
- package/dist/tools/parameter-descriptions.d.ts +2 -2
- package/dist/tools/parameter-descriptions.d.ts.map +1 -1
- package/dist/{transform-postprocess-phase-bqhz6vdr.js → transform-postprocess-phase-spcy2qre.js} +35 -17
- package/dist/transformers-node-wasm.js +18415 -18415
- package/dist/v2/auto-search-worker.js +112 -0
- package/dist/v2/{context-zecmzk5s.js → context-sf98kstd.js} +8378 -8530
- package/dist/v2/{derive-budgets-kdgp4s3r.js → derive-budgets-3vc0y84t.js} +4 -3
- package/dist/v2/embedding-activity-g1dhes6g.js +10 -0
- package/dist/v2/embedding-backfill-vn8g1nh1.js +21 -0
- package/dist/v2/embedding-cache-mgyr73ef.js +16 -0
- package/dist/v2/embedding-worker.js +12 -9
- package/dist/v2/fold/host-media.d.ts +4 -0
- package/dist/v2/fold/host-media.d.ts.map +1 -1
- package/dist/v2/fold/memory-cache.d.ts +70 -0
- package/dist/v2/fold/memory-cache.d.ts.map +1 -0
- package/dist/v2/fold/native-codec.d.ts +10 -0
- package/dist/v2/fold/native-codec.d.ts.map +1 -0
- package/dist/v2/fold/native-replay.d.ts +58 -0
- package/dist/v2/fold/native-replay.d.ts.map +1 -0
- package/dist/v2/fold/policy.d.ts +24 -0
- package/dist/v2/fold/policy.d.ts.map +1 -0
- package/dist/v2/harness-e4avh192.js +10 -0
- package/dist/v2/hidden-completion.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-manual.d.ts +1 -1
- package/dist/v2/hooks/dream-manual.d.ts.map +1 -1
- package/dist/v2/hooks/dream-timer.d.ts.map +1 -1
- package/dist/v2/hooks/dream-trigger.d.ts +1 -2
- package/dist/v2/hooks/dream-trigger.d.ts.map +1 -1
- package/dist/v2/hooks/payload.d.ts.map +1 -1
- package/dist/v2/hooks/tools.d.ts.map +1 -1
- package/dist/v2/hooks/types.d.ts +6 -0
- package/dist/v2/hooks/types.d.ts.map +1 -1
- package/dist/v2/logger-mxd0ym09.js +19 -0
- package/dist/v2/message-index-bounded-dy3s2k1e.js +123 -0
- package/dist/{message-time-backfill-68gj6t3e.js → v2/message-time-backfill-gtx1pwk1.js} +7 -7
- package/dist/v2/migration-worker.js +24 -15
- package/dist/v2/{model-resolution-xhfmyyvy.js → model-resolution-nx97z3x7.js} +1 -1
- package/dist/v2/project-embedding-registry-1tgba5dv.js +86 -0
- package/dist/v2/raw-ordinal-warmup-worker.js +60 -0
- package/dist/v2/{read-session-chunk-8vjp6581.js → read-session-chunk-rh4khdkv.js} +14 -8
- package/dist/v2/read-session-raw-bsbmf0vj.js +57 -0
- package/dist/v2/recomp-orchestrator-az61rfcg.js +57 -0
- package/dist/{safe-notification-target-43r8jsxw.js → v2/safe-notification-target-73ax1p5v.js} +3 -3
- package/dist/v2/search-nzkwrc6n.js +45 -0
- package/dist/{send-session-notification-dyw42dtr.js → v2/send-session-notification-6km439kn.js} +9 -7
- package/dist/{index-5eqk6z3s.js → v2/server-1r6pmz4f.js} +301 -27
- package/dist/v2/server-2bvekkfy.js +11 -0
- package/dist/v2/server-2fbhp79z.js +3205 -0
- package/dist/v2/{server-ajzeteqw.js → server-2ra6pwf3.js} +1 -18
- package/dist/v2/server-4dhv7mqz.js +131 -0
- package/dist/v2/{server-xa4xe3rv.js → server-4k748ke6.js} +11 -1053
- package/dist/v2/{server-vs5gpnd4.js → server-52awr2mw.js} +81 -145
- package/dist/v2/{server-1qbnzc80.js → server-5m3dt5r1.js} +136 -148
- package/dist/v2/server-686jg6eb.js +3508 -0
- package/dist/v2/server-7jzrrxap.js +931 -0
- package/dist/v2/server-7wwc2nga.js +3023 -0
- package/dist/v2/server-8ajstryz.js +18 -0
- package/dist/v2/{server-sfpzqvdz.js → server-8cd2j99z.js} +2 -3
- package/dist/v2/server-8pyt7hev.js +3408 -0
- package/dist/v2/server-8tqanswc.js +984 -0
- package/dist/v2/{server-14vq4kpm.js → server-aan4q8mx.js} +3 -3
- package/dist/v2/server-d9vfe7xq.js +16 -0
- package/dist/v2/server-e0vdaae2.js +3591 -0
- package/dist/v2/server-ezhze64f.js +1048 -0
- package/dist/v2/server-fb3zxn06.js +13 -0
- package/dist/v2/server-fr0wbhdn.js +43 -0
- package/dist/v2/server-g5r0n3b6.js +1137 -0
- package/dist/v2/server-gjcr4w98.js +154 -0
- package/dist/v2/server-k228xhjg.js +171 -0
- package/dist/v2/{server-jc7y02q0.js → server-k8x2rbxc.js} +5119 -10948
- package/dist/{index-fg34g6a5.js → v2/server-kb9nn0a0.js} +309 -52
- package/dist/v2/{server-g0fjrkta.js → server-mfkzp7qj.js} +28 -28
- package/dist/v2/server-pavzsdc6.js +17 -0
- package/dist/v2/server-psqc7e9n.js +2106 -0
- package/dist/v2/server-qt1qqasc.js +22 -0
- package/dist/v2/server-qye6ykf7.js +120 -0
- package/dist/v2/{server-qdjnb2z1.js → server-r5p3b1wy.js} +11 -9
- package/dist/v2/server-sggvvzhb.js +759 -0
- package/dist/v2/{server-y8maxeft.js → server-v06jcv0w.js} +16 -13
- package/dist/v2/server-vqpf3167.js +1048 -0
- package/dist/v2/{server-c5gz8wph.js → server-x2g40a71.js} +2048 -2059
- package/dist/v2/{server-wvjvfhck.js → server-xdfwt6kh.js} +20 -16
- package/dist/v2/{server-mcfawjgc.js → server-xxm59eww.js} +25 -44
- package/dist/v2/server-yczc713m.js +564 -0
- package/dist/v2/{server-3n4q9xme.js → server-z2037m6z.js} +4 -4
- package/dist/v2/{server-e29d7p7c.js → server-zm570tr2.js} +166 -160
- package/dist/v2/{server-6r257mf5.js → server-zxhgvsf9.js} +3 -3
- package/dist/v2/server.js +16 -14
- package/dist/v2/sqlite-context-pragmas-mv9jqwjh.js +6 -0
- package/dist/v2/sqlite-mhjkerzq.js +46 -0
- package/dist/v2/storage-memory-07fx57k6.js +71 -0
- package/dist/v2/storage-tags-w4tv77sn.js +130 -0
- package/dist/v2/store-reader.d.ts +16 -0
- package/dist/v2/store-reader.d.ts.map +1 -1
- package/dist/v2/{task-config-tbndqyny.js → task-config-x0hq3qfd.js} +2 -2
- package/dist/v2/transformers-node-wasm.js +18415 -18415
- package/dist/v2/tui/index.d.ts.map +1 -1
- package/dist/v2/tui/types.d.ts +1 -10
- package/dist/v2/tui/types.d.ts.map +1 -1
- package/dist/v2/{wrapup-orchestrator-0snhvwcv.js → wrapup-orchestrator-mz7efs7w.js} +51 -27
- package/dist/wrapup-orchestrator-amzta1t4.js +44 -0
- package/package.json +4 -3
- package/src/agents/magic-context-prompt.ts +27 -2
- package/src/agents/smart-notes-enabled.test.ts +294 -0
- package/src/agents/smart-notes-on.golden.json +70 -0
- package/src/config/index.test.ts +67 -1
- package/src/config/index.ts +8 -0
- package/src/config/latch-permanence-guard.test.ts +4 -0
- package/src/config/live-run-config.test.ts +37 -1
- package/src/config/live-run-config.ts +28 -0
- package/src/config/migrate-config-location.ts +10 -3
- package/src/config/mural-model-deprecation.ts +24 -0
- package/src/config/project-security.hostile-matrix.test.ts +4 -44
- package/src/config/project-security.test.ts +9 -14
- package/src/config/project-security.ts +13 -55
- package/src/config/schema/magic-context.test.ts +6 -5
- package/src/config/schema/magic-context.ts +34 -16
- package/src/features/magic-context/dreamer/task-registry.ts +6 -0
- package/src/shared/auto-search-lifecycle.ts +27 -0
- package/src/shared/conflict-detector.test.ts +56 -0
- package/src/shared/conflict-detector.ts +16 -5
- package/src/shared/historian-tool-defaults.json +6 -6
- package/src/shared/historian-tool-expansions.ts +65 -8
- package/src/shared/historian-tool-preview-defaults.json +13 -0
- package/src/shared/historian-tool-template.ts +48 -14
- package/src/shared/host-stall-profiler-bun.ts +358 -0
- package/src/shared/host-stall-profiler-common.ts +159 -0
- package/src/shared/host-stall-profiler-node.test.ts +234 -0
- package/src/shared/host-stall-profiler-node.ts +274 -0
- package/src/shared/host-stall-profiler-report.ts +248 -0
- package/src/shared/host-stall-profiler.ts +57 -0
- package/src/shared/model-resolution.test.ts +54 -17
- package/src/shared/model-resolution.ts +6 -17
- package/src/shared/sqlite-640-review-r2.test.ts +136 -0
- package/src/shared/sqlite-640-review.test.ts +183 -0
- package/src/shared/sqlite-acquisition-routing.test.ts +18 -0
- package/src/shared/sqlite.test.ts +52 -0
- package/src/shared/sqlite.ts +423 -37
- package/src/shared/stable-json-linear.test.ts +109 -0
- package/src/shared/stable-json.ts +37 -7
- package/src/shared/status-view.test.ts +6 -1
- package/src/shared/status-view.ts +15 -1
- package/src/shared/tag-transcript.ts +6 -0
- package/src/shared/user-facing-codes.ts +2 -6
- package/src/shared/window-geometry.ts +10 -0
- package/src/shared/write-transaction-attribution.test.ts +2 -2
- package/src/v2/tui/host-contract.test.ts +41 -67
- package/src/v2/tui/index.ts +6 -214
- package/src/v2/tui/types.ts +5 -17
- package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts +0 -45
- package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts.map +0 -1
- package/dist/features/magic-context/checkout-claim.d.ts +0 -155
- package/dist/features/magic-context/checkout-claim.d.ts.map +0 -1
- package/dist/index-3h0ybwah.js +0 -6540
- package/dist/index-r5hmbx3t.js +0 -7773
- package/dist/recomp-orchestrator-y15j0rb9.js +0 -39
- package/dist/v2/recomp-orchestrator-8ejxvrzz.js +0 -39
- package/dist/v2/server-frbm99q5.js +0 -7698
- package/dist/v2/server-qp5hx1ad.js +0 -6366
- package/dist/wrapup-orchestrator-39amhv9s.js +0 -26
- /package/dist/{index-en1k8h8m.js → index-2pp04pmg.js} +0 -0
- /package/dist/v2/{index-en1k8h8m.js → index-2pp04pmg.js} +0 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host stall profiler: an off-by-default diagnostic that names the JavaScript
|
|
3
|
+
* blocking OpenCode's main thread during multi-second host stalls.
|
|
4
|
+
*
|
|
5
|
+
* Why it exists: OpenCode runs every plugin in one Bun runtime. When that
|
|
6
|
+
* runtime stops processing for seconds, native stack samples show only the
|
|
7
|
+
* native side (for example a synchronous SQLite step) and never which plugin's
|
|
8
|
+
* JavaScript made the call. JavaScriptCore's sampling profiler samples the
|
|
9
|
+
* main thread from its own thread, so it records stacks *during* the block,
|
|
10
|
+
* while a main-thread timer can only measure the lag afterwards. This module
|
|
11
|
+
* pairs the two: a 250 ms watchdog measures the lag, and when a gap exceeds
|
|
12
|
+
* the threshold it drains the sampler, keeps the samples inside the stall
|
|
13
|
+
* window, attributes each one to the plugin whose code owns it, and writes one
|
|
14
|
+
* JSON report per stall.
|
|
15
|
+
*
|
|
16
|
+
* Control is a file switch, not a config key: the profiler runs only while
|
|
17
|
+
* `<magic-context storage>/host-profiler/enable` exists. The switch is checked
|
|
18
|
+
* every 5 s, so creating or deleting the file turns the profiler on or off
|
|
19
|
+
* without restarting the host. With the file absent the only work is one
|
|
20
|
+
* `existsSync` per 5 s: `bun:jsc` is never imported and no watchdog runs.
|
|
21
|
+
*
|
|
22
|
+
* Every path fails open: a failure is logged once and never reaches a turn.
|
|
23
|
+
* If `bun:jsc` cannot be loaded (not running under Bun), the profiler
|
|
24
|
+
* disables itself for the rest of the process.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
28
|
+
import * as path from "node:path";
|
|
29
|
+
import {
|
|
30
|
+
DEFAULT_SAMPLE_INTERVAL_MS,
|
|
31
|
+
DEFAULT_STALL_THRESHOLD_MS,
|
|
32
|
+
emitStallReport,
|
|
33
|
+
HOST_PROFILER_ENABLE_FILENAME,
|
|
34
|
+
type HostStallProfilerHandle,
|
|
35
|
+
type HostStallProfilerOptions,
|
|
36
|
+
type MemorySnapshot,
|
|
37
|
+
type ProfilerRuntimeDeps,
|
|
38
|
+
parseEnableFile,
|
|
39
|
+
SWITCH_POLL_MS,
|
|
40
|
+
WATCHDOG_INTERVAL_MS,
|
|
41
|
+
} from "./host-stall-profiler-common";
|
|
42
|
+
import type { JscSampleTrace } from "./host-stall-profiler-report";
|
|
43
|
+
|
|
44
|
+
const MEMORY_SNAPSHOT_EVERY_TICKS = 4;
|
|
45
|
+
const CALIBRATION_CHUNK_MS = 3;
|
|
46
|
+
const CALIBRATION_MAX_CHUNKS = 30;
|
|
47
|
+
|
|
48
|
+
/** The subset of `bun:jsc` the profiler uses. */
|
|
49
|
+
export interface JscProfilerApi {
|
|
50
|
+
startSamplingProfiler(directory?: string): void;
|
|
51
|
+
samplingProfilerStackTraces(): unknown;
|
|
52
|
+
/**
|
|
53
|
+
* Runs a callback under the sampler at the given interval (microseconds)
|
|
54
|
+
* and leaves the sampler PAUSED afterwards. `bun:jsc` exposes no stop or
|
|
55
|
+
* interval setter, so this is how the profiler sets its sampling interval
|
|
56
|
+
* and how it stops sampling when the switch is turned off.
|
|
57
|
+
*/
|
|
58
|
+
profile(callback: () => unknown, sampleIntervalMicros?: number): unknown;
|
|
59
|
+
heapSize?(): number;
|
|
60
|
+
memoryUsage?(): unknown;
|
|
61
|
+
percentAvailableMemoryInUse?(): number | null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface HostStallProfilerDeps extends ProfilerRuntimeDeps {
|
|
65
|
+
loadJsc(): Promise<unknown>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function asJscApi(module: unknown): JscProfilerApi | null {
|
|
69
|
+
const candidate = (module as { default?: unknown } | null) ?? null;
|
|
70
|
+
for (const value of [candidate, candidate?.default]) {
|
|
71
|
+
const api = value as Partial<JscProfilerApi> | null | undefined;
|
|
72
|
+
if (
|
|
73
|
+
api &&
|
|
74
|
+
typeof api.startSamplingProfiler === "function" &&
|
|
75
|
+
typeof api.samplingProfilerStackTraces === "function" &&
|
|
76
|
+
typeof api.profile === "function"
|
|
77
|
+
) {
|
|
78
|
+
return api as JscProfilerApi;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function createHostStallProfiler(deps: HostStallProfilerDeps): HostStallProfilerHandle {
|
|
85
|
+
let jsc: JscProfilerApi | null = null;
|
|
86
|
+
let unavailable = false;
|
|
87
|
+
let pollTimer: unknown = null;
|
|
88
|
+
let watchdog: unknown = null;
|
|
89
|
+
let options: HostStallProfilerOptions = {
|
|
90
|
+
thresholdMs: DEFAULT_STALL_THRESHOLD_MS,
|
|
91
|
+
sampleIntervalMs: DEFAULT_SAMPLE_INTERVAL_MS,
|
|
92
|
+
};
|
|
93
|
+
let lastTickAt = 0;
|
|
94
|
+
let tickCount = 0;
|
|
95
|
+
let memoryBefore: MemorySnapshot | null = null;
|
|
96
|
+
/** JSC sample timestamp (ms) minus `deps.now()` for the same instant; null when unknown. */
|
|
97
|
+
let clockOffsetMs: number | null = null;
|
|
98
|
+
let checking: Promise<void> | null = null;
|
|
99
|
+
const loggedOnce = new Set<string>();
|
|
100
|
+
|
|
101
|
+
const safeLog = (message: string): void => {
|
|
102
|
+
try {
|
|
103
|
+
deps.log(message);
|
|
104
|
+
} catch {
|
|
105
|
+
// Logging must never take the profiler, or a turn, down with it.
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const logOnce = (key: string, message: string, error?: unknown): void => {
|
|
109
|
+
if (loggedOnce.has(key)) return;
|
|
110
|
+
loggedOnce.add(key);
|
|
111
|
+
const detail =
|
|
112
|
+
error === undefined
|
|
113
|
+
? ""
|
|
114
|
+
: `: ${error instanceof Error ? error.message : String(error)}`;
|
|
115
|
+
safeLog(`[magic-context] host stall profiler: ${message}${detail}`);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const drain = (api: JscProfilerApi): JscSampleTrace[] => {
|
|
119
|
+
const raw = api.samplingProfilerStackTraces() as { traces?: unknown } | null;
|
|
120
|
+
return Array.isArray(raw?.traces) ? (raw.traces as JscSampleTrace[]) : [];
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/** Pause the sampler (see `JscProfilerApi.profile`), discarding what it held. */
|
|
124
|
+
const pauseSampler = (api: JscProfilerApi, intervalMs: number): void => {
|
|
125
|
+
// Drain first so `profile` has little to process. Before the sampler
|
|
126
|
+
// has ever run, `samplingProfilerStackTraces` throws ("never
|
|
127
|
+
// started"); `profile` itself creates the sampler, so that is benign.
|
|
128
|
+
try {
|
|
129
|
+
drain(api);
|
|
130
|
+
} catch {
|
|
131
|
+
// Nothing buffered yet.
|
|
132
|
+
}
|
|
133
|
+
api.profile(() => undefined, Math.round(intervalMs * 1000));
|
|
134
|
+
drain(api);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Relate JSC's sample clock to `deps.now()`. Sample timestamps come from
|
|
139
|
+
* JavaScriptCore's monotonic clock, whose origin differs from
|
|
140
|
+
* `performance.now()`. Short busy-waits at a 1 ms interval bracket a
|
|
141
|
+
* handful of samples between two known `now()` readings; the midpoint of
|
|
142
|
+
* the feasible offsets is accurate to a few milliseconds, far below any
|
|
143
|
+
* stall threshold. A restarted sampler thread can take one old interval
|
|
144
|
+
* to wake, so the busy-wait repeats in short chunks until a chunk yields
|
|
145
|
+
* samples, bounded by `CALIBRATION_MAX_CHUNKS`.
|
|
146
|
+
*/
|
|
147
|
+
const calibrate = (api: JscProfilerApi): number | null => {
|
|
148
|
+
pauseSampler(api, 1);
|
|
149
|
+
api.startSamplingProfiler();
|
|
150
|
+
let offset: number | null = null;
|
|
151
|
+
for (let chunk = 0; chunk < CALIBRATION_MAX_CHUNKS && offset === null; chunk++) {
|
|
152
|
+
const start = deps.now();
|
|
153
|
+
let end = start;
|
|
154
|
+
for (let i = 0; i < 50_000_000 && end - start < CALIBRATION_CHUNK_MS; i++) {
|
|
155
|
+
end = deps.now();
|
|
156
|
+
}
|
|
157
|
+
const stamps = drain(api)
|
|
158
|
+
.map((trace) => trace.timestamp)
|
|
159
|
+
.filter(
|
|
160
|
+
(value): value is number => typeof value === "number" && Number.isFinite(value),
|
|
161
|
+
)
|
|
162
|
+
.map((seconds) => seconds * 1000);
|
|
163
|
+
if (stamps.length >= 2) {
|
|
164
|
+
offset = (Math.max(...stamps) - end + (Math.min(...stamps) - start)) / 2;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
pauseSampler(api, 1);
|
|
168
|
+
return offset;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const snapshot = (api: JscProfilerApi): MemorySnapshot => {
|
|
172
|
+
const read = <T>(fn: () => T): T | null => {
|
|
173
|
+
try {
|
|
174
|
+
return fn();
|
|
175
|
+
} catch {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
return {
|
|
180
|
+
at: new Date(deps.wallNow()).toISOString(),
|
|
181
|
+
heap_size_bytes: read(() => api.heapSize?.() ?? null),
|
|
182
|
+
jsc_memory: read(() => api.memoryUsage?.() ?? null),
|
|
183
|
+
rss_bytes: read(() => deps.rss()),
|
|
184
|
+
percent_available_memory_in_use: read(
|
|
185
|
+
() => api.percentAvailableMemoryInUse?.() ?? null,
|
|
186
|
+
),
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const recordStall = (
|
|
191
|
+
api: JscProfilerApi,
|
|
192
|
+
startMs: number,
|
|
193
|
+
endMs: number,
|
|
194
|
+
traces: JscSampleTrace[],
|
|
195
|
+
): void => {
|
|
196
|
+
const after = snapshot(api);
|
|
197
|
+
let windowed = traces;
|
|
198
|
+
let windowFilter = "since-last-collection";
|
|
199
|
+
if (clockOffsetMs !== null) {
|
|
200
|
+
const slackMs = 2 * options.sampleIntervalMs + 20;
|
|
201
|
+
const lo = startMs + clockOffsetMs - slackMs;
|
|
202
|
+
const hi = endMs + clockOffsetMs + slackMs;
|
|
203
|
+
const inWindow = traces.filter((trace) => {
|
|
204
|
+
const at =
|
|
205
|
+
typeof trace.timestamp === "number" ? trace.timestamp * 1000 : Number.NaN;
|
|
206
|
+
return at >= lo && at <= hi;
|
|
207
|
+
});
|
|
208
|
+
if (inWindow.length > 0 || traces.length === 0) {
|
|
209
|
+
windowed = inWindow;
|
|
210
|
+
windowFilter = "timestamp";
|
|
211
|
+
} else {
|
|
212
|
+
// A calibration that no longer matches (for example after the
|
|
213
|
+
// machine slept) must not silently empty the report.
|
|
214
|
+
windowFilter = "since-last-collection (timestamp filter matched no sample)";
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
emitStallReport(deps, {
|
|
218
|
+
startMs,
|
|
219
|
+
endMs,
|
|
220
|
+
traces,
|
|
221
|
+
windowed,
|
|
222
|
+
windowFilter,
|
|
223
|
+
options,
|
|
224
|
+
before: memoryBefore,
|
|
225
|
+
after,
|
|
226
|
+
backend: "jsc",
|
|
227
|
+
});
|
|
228
|
+
memoryBefore = after;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const tick = (): void => {
|
|
232
|
+
const api = jsc;
|
|
233
|
+
if (!api || watchdog === null) return;
|
|
234
|
+
try {
|
|
235
|
+
const now = deps.now();
|
|
236
|
+
const startMs = lastTickAt;
|
|
237
|
+
lastTickAt = now;
|
|
238
|
+
const traces = drain(api);
|
|
239
|
+
if (now - startMs - WATCHDOG_INTERVAL_MS >= options.thresholdMs) {
|
|
240
|
+
try {
|
|
241
|
+
recordStall(api, startMs, now, traces);
|
|
242
|
+
} catch (error) {
|
|
243
|
+
logOnce("report", "could not write a stall report", error);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
tickCount += 1;
|
|
247
|
+
if (tickCount % MEMORY_SNAPSHOT_EVERY_TICKS === 0) memoryBefore = snapshot(api);
|
|
248
|
+
} catch (error) {
|
|
249
|
+
logOnce("tick", "watchdog tick failed", error);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const enable = (api: JscProfilerApi, next: HostStallProfilerOptions): void => {
|
|
254
|
+
const startedAt = deps.now();
|
|
255
|
+
try {
|
|
256
|
+
options = next;
|
|
257
|
+
clockOffsetMs = calibrate(api);
|
|
258
|
+
pauseSampler(api, options.sampleIntervalMs);
|
|
259
|
+
api.startSamplingProfiler();
|
|
260
|
+
lastTickAt = deps.now();
|
|
261
|
+
tickCount = 0;
|
|
262
|
+
memoryBefore = snapshot(api);
|
|
263
|
+
watchdog = deps.setInterval(tick, WATCHDOG_INTERVAL_MS);
|
|
264
|
+
safeLog(
|
|
265
|
+
`[magic-context] host stall profiler enabled: threshold ${options.thresholdMs}ms, sample interval ${options.sampleIntervalMs}ms, clock calibration ${clockOffsetMs === null ? "unavailable" : "ok"}, setup ${Math.round(deps.now() - startedAt)}ms, reports in ${deps.profilerDir()}`,
|
|
266
|
+
);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
watchdog = null;
|
|
269
|
+
try {
|
|
270
|
+
pauseSampler(api, options.sampleIntervalMs);
|
|
271
|
+
} catch {
|
|
272
|
+
// Already failing open; the enable error below is the one worth logging.
|
|
273
|
+
}
|
|
274
|
+
logOnce("enable", "could not start", error);
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const disable = (reason: string): void => {
|
|
279
|
+
if (watchdog !== null) deps.clearInterval(watchdog);
|
|
280
|
+
watchdog = null;
|
|
281
|
+
memoryBefore = null;
|
|
282
|
+
if (jsc) {
|
|
283
|
+
try {
|
|
284
|
+
pauseSampler(jsc, options.sampleIntervalMs);
|
|
285
|
+
} catch (error) {
|
|
286
|
+
logOnce("disable", "could not pause the sampler", error);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
safeLog(`[magic-context] host stall profiler disabled: ${reason}`);
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const ensureJsc = async (): Promise<JscProfilerApi | null> => {
|
|
293
|
+
if (jsc) return jsc;
|
|
294
|
+
try {
|
|
295
|
+
const api = asJscApi(await deps.loadJsc());
|
|
296
|
+
if (!api) throw new Error("bun:jsc lacks the sampling profiler API");
|
|
297
|
+
jsc = api;
|
|
298
|
+
return api;
|
|
299
|
+
} catch (error) {
|
|
300
|
+
unavailable = true;
|
|
301
|
+
if (pollTimer !== null) deps.clearInterval(pollTimer);
|
|
302
|
+
pollTimer = null;
|
|
303
|
+
logOnce("jsc", "bun:jsc is unavailable, profiler disabled for this process", error);
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const runCheck = async (): Promise<void> => {
|
|
309
|
+
if (unavailable) return;
|
|
310
|
+
try {
|
|
311
|
+
const enablePath = path.join(deps.profilerDir(), HOST_PROFILER_ENABLE_FILENAME);
|
|
312
|
+
if (!existsSync(enablePath)) {
|
|
313
|
+
if (watchdog !== null) disable("enable file removed");
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const parsed = parseEnableFile(readFileSync(enablePath, "utf8"));
|
|
317
|
+
if (parsed.error) logOnce(`options:${parsed.error}`, parsed.error);
|
|
318
|
+
if (watchdog !== null) {
|
|
319
|
+
if (jsc && parsed.options.sampleIntervalMs !== options.sampleIntervalMs) {
|
|
320
|
+
pauseSampler(jsc, parsed.options.sampleIntervalMs);
|
|
321
|
+
jsc.startSamplingProfiler();
|
|
322
|
+
}
|
|
323
|
+
options = parsed.options;
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const api = await ensureJsc();
|
|
327
|
+
if (!api || watchdog !== null || !existsSync(enablePath)) return;
|
|
328
|
+
enable(api, parsed.options);
|
|
329
|
+
} catch (error) {
|
|
330
|
+
logOnce("check", "enable-file check failed", error);
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const checkNow = (): Promise<void> => {
|
|
335
|
+
if (!checking) {
|
|
336
|
+
checking = runCheck().finally(() => {
|
|
337
|
+
checking = null;
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
return checking;
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
start() {
|
|
345
|
+
if (pollTimer !== null || unavailable) return;
|
|
346
|
+
pollTimer = deps.setInterval(() => void checkNow(), SWITCH_POLL_MS);
|
|
347
|
+
void checkNow();
|
|
348
|
+
},
|
|
349
|
+
checkNow,
|
|
350
|
+
stop() {
|
|
351
|
+
if (pollTimer !== null) deps.clearInterval(pollTimer);
|
|
352
|
+
pollTimer = null;
|
|
353
|
+
if (watchdog !== null) disable("stopped");
|
|
354
|
+
},
|
|
355
|
+
isActive: () => watchdog !== null,
|
|
356
|
+
isUnavailable: () => unavailable,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { chmodSync, existsSync, readdirSync, unlinkSync } from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { aggregateTraces, type JscSampleTrace } from "./host-stall-profiler-report";
|
|
4
|
+
import { ensureStorageDirectorySync, writeStorageFileAtomicSync } from "./storage-permissions";
|
|
5
|
+
|
|
6
|
+
export const HOST_PROFILER_DIRNAME = "host-profiler";
|
|
7
|
+
export const HOST_PROFILER_ENABLE_FILENAME = "enable";
|
|
8
|
+
export const SWITCH_POLL_MS = 5_000;
|
|
9
|
+
export const WATCHDOG_INTERVAL_MS = 250;
|
|
10
|
+
export const DEFAULT_STALL_THRESHOLD_MS = 3_000;
|
|
11
|
+
export const DEFAULT_SAMPLE_INTERVAL_MS = 10;
|
|
12
|
+
export const MAX_REPORT_FILES = 50;
|
|
13
|
+
export const MAX_SAMPLES_PER_WINDOW = 20_000;
|
|
14
|
+
export const PROFILE_WINDOW_MS = 10_000;
|
|
15
|
+
|
|
16
|
+
export interface HostStallProfilerOptions {
|
|
17
|
+
thresholdMs: number;
|
|
18
|
+
sampleIntervalMs: number;
|
|
19
|
+
}
|
|
20
|
+
export interface HostStallProfilerHandle {
|
|
21
|
+
start(): void;
|
|
22
|
+
checkNow(): Promise<void>;
|
|
23
|
+
stop(): void;
|
|
24
|
+
isActive(): boolean;
|
|
25
|
+
isUnavailable(): boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface MemorySnapshot {
|
|
28
|
+
at: string;
|
|
29
|
+
heap_size_bytes: number | null;
|
|
30
|
+
jsc_memory: unknown;
|
|
31
|
+
rss_bytes: number | null;
|
|
32
|
+
percent_available_memory_in_use: number | null;
|
|
33
|
+
}
|
|
34
|
+
export interface ProfilerRuntimeDeps {
|
|
35
|
+
profilerDir(): string;
|
|
36
|
+
now(): number;
|
|
37
|
+
wallNow(): number;
|
|
38
|
+
setInterval(callback: () => void, ms: number): unknown;
|
|
39
|
+
clearInterval(handle: unknown): void;
|
|
40
|
+
rss(): number;
|
|
41
|
+
log(message: string): void;
|
|
42
|
+
pid: number;
|
|
43
|
+
bunVersion: string | null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** An empty enable file uses defaults; JSON allows bounded diagnostic tuning. */
|
|
47
|
+
export function parseEnableFile(content: string): {
|
|
48
|
+
options: HostStallProfilerOptions;
|
|
49
|
+
error: string | null;
|
|
50
|
+
} {
|
|
51
|
+
const options = {
|
|
52
|
+
thresholdMs: DEFAULT_STALL_THRESHOLD_MS,
|
|
53
|
+
sampleIntervalMs: DEFAULT_SAMPLE_INTERVAL_MS,
|
|
54
|
+
};
|
|
55
|
+
if (!content.trim()) return { options, error: null };
|
|
56
|
+
try {
|
|
57
|
+
const parsed = JSON.parse(content) as Record<string, unknown>;
|
|
58
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
59
|
+
return { options, error: "enable file is not a JSON object" };
|
|
60
|
+
}
|
|
61
|
+
if (typeof parsed.threshold_ms === "number" && Number.isFinite(parsed.threshold_ms)) {
|
|
62
|
+
options.thresholdMs = Math.min(600_000, Math.max(500, parsed.threshold_ms));
|
|
63
|
+
}
|
|
64
|
+
if (
|
|
65
|
+
typeof parsed.sample_interval_ms === "number" &&
|
|
66
|
+
Number.isFinite(parsed.sample_interval_ms)
|
|
67
|
+
) {
|
|
68
|
+
options.sampleIntervalMs = Math.min(100, Math.max(1, parsed.sample_interval_ms));
|
|
69
|
+
}
|
|
70
|
+
return { options, error: null };
|
|
71
|
+
} catch (error) {
|
|
72
|
+
return {
|
|
73
|
+
options,
|
|
74
|
+
error: `enable file is not valid JSON (${error instanceof Error ? error.message : String(error)})`,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface StallReportInput {
|
|
80
|
+
startMs: number;
|
|
81
|
+
endMs: number;
|
|
82
|
+
traces: JscSampleTrace[];
|
|
83
|
+
windowed: JscSampleTrace[];
|
|
84
|
+
windowFilter: string;
|
|
85
|
+
options: HostStallProfilerOptions;
|
|
86
|
+
before: MemorySnapshot | null;
|
|
87
|
+
after: MemorySnapshot;
|
|
88
|
+
backend: "jsc" | "v8";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Write the same report schema and rank code owners by sampled stacks on every runtime. */
|
|
92
|
+
export function emitStallReport(deps: ProfilerRuntimeDeps, input: StallReportInput): void {
|
|
93
|
+
const { traces, windowed, options, startMs, endMs } = input;
|
|
94
|
+
const stride = windowed.length / MAX_SAMPLES_PER_WINDOW;
|
|
95
|
+
const kept =
|
|
96
|
+
windowed.length <= MAX_SAMPLES_PER_WINDOW
|
|
97
|
+
? windowed
|
|
98
|
+
: Array.from(
|
|
99
|
+
{ length: MAX_SAMPLES_PER_WINDOW },
|
|
100
|
+
(_, i) => windowed[Math.floor(i * stride)],
|
|
101
|
+
);
|
|
102
|
+
const aggregate = aggregateTraces(kept);
|
|
103
|
+
const gapMs = endMs - startMs;
|
|
104
|
+
const endWallMs = deps.wallNow();
|
|
105
|
+
const report = {
|
|
106
|
+
kind: "magic-context-host-stall",
|
|
107
|
+
schema_version: 1,
|
|
108
|
+
pid: deps.pid,
|
|
109
|
+
bun_version: deps.bunVersion,
|
|
110
|
+
node_version: input.backend === "v8" ? process.versions.node : undefined,
|
|
111
|
+
backend: input.backend,
|
|
112
|
+
platform: process.platform,
|
|
113
|
+
window: {
|
|
114
|
+
start: new Date(endWallMs - gapMs).toISOString(),
|
|
115
|
+
end: new Date(endWallMs).toISOString(),
|
|
116
|
+
duration_ms: Math.round(gapMs),
|
|
117
|
+
lag_ms: Math.round(gapMs - WATCHDOG_INTERVAL_MS),
|
|
118
|
+
threshold_ms: options.thresholdMs,
|
|
119
|
+
},
|
|
120
|
+
sampling: {
|
|
121
|
+
interval_ms: options.sampleIntervalMs,
|
|
122
|
+
samples_collected: traces.length,
|
|
123
|
+
samples_in_window: windowed.length,
|
|
124
|
+
samples_aggregated: kept.length,
|
|
125
|
+
window_filter: input.windowFilter,
|
|
126
|
+
note:
|
|
127
|
+
aggregate.samples === 0
|
|
128
|
+
? "No JavaScript samples in the window: the main thread was not executing inside the JavaScript VM (idle wait, process suspension, or native work outside any JS call)."
|
|
129
|
+
: undefined,
|
|
130
|
+
},
|
|
131
|
+
memory: { before: input.before, after: input.after },
|
|
132
|
+
owners: aggregate.owners,
|
|
133
|
+
top_frames: aggregate.top_frames,
|
|
134
|
+
top_js_frames: aggregate.top_js_frames,
|
|
135
|
+
top_stacks: aggregate.top_stacks,
|
|
136
|
+
};
|
|
137
|
+
const dir = deps.profilerDir();
|
|
138
|
+
ensureStorageDirectorySync(dir, true);
|
|
139
|
+
chmodSync(dir, 0o700);
|
|
140
|
+
const stamp = new Date(endWallMs).toISOString().replaceAll(":", "-");
|
|
141
|
+
let name = `stall-${stamp}.json`;
|
|
142
|
+
for (let n = 1; existsSync(path.join(dir, name)); n++) name = `stall-${stamp}-${n}.json`;
|
|
143
|
+
const file = path.join(dir, name);
|
|
144
|
+
writeStorageFileAtomicSync(file, `${JSON.stringify(report, null, 2)}\n`, true);
|
|
145
|
+
const reports = readdirSync(dir)
|
|
146
|
+
.filter((entry) => /^stall-.*\.json$/.test(entry))
|
|
147
|
+
.sort();
|
|
148
|
+
for (const stale of reports.slice(0, Math.max(0, reports.length - MAX_REPORT_FILES))) {
|
|
149
|
+
try {
|
|
150
|
+
unlinkSync(path.join(dir, stale));
|
|
151
|
+
} catch {
|
|
152
|
+
/* Pruning must not suppress a captured report. */
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const top = aggregate.owners[0];
|
|
156
|
+
deps.log(
|
|
157
|
+
`[magic-context] host stall profiler: ${Math.round(gapMs)}ms main-thread stall, ${aggregate.samples} samples, top owner ${top ? `${top.owner} (${top.percent}%)` : "none"} → ${file}`,
|
|
158
|
+
);
|
|
159
|
+
}
|