create-walle 0.9.21 → 0.9.23
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 +27 -5
- package/package.json +2 -2
- package/template/CLAUDE.md +2 -2
- package/template/LICENSE +1 -1
- package/template/bin/ctm-dev-cleanup.js +24 -3
- package/template/bin/ctm-launch.sh +13 -0
- package/template/bin/dev.sh +156 -18
- package/template/bin/node-bin.sh +84 -0
- package/template/bin/pin-node.sh +51 -0
- package/template/claude-task-manager/api-prompts.js +1203 -182
- package/template/claude-task-manager/api-reviews.js +109 -15
- package/template/claude-task-manager/approval-agent.js +1360 -280
- package/template/claude-task-manager/bin/restart-ctm.sh +64 -23
- package/template/claude-task-manager/bin/storage-migration-supervisor.js +338 -0
- package/template/claude-task-manager/db.js +4417 -295
- package/template/claude-task-manager/docs/app-update-refresh-protocol.md +69 -0
- package/template/claude-task-manager/docs/approval-ai-refinement.md +138 -0
- package/template/claude-task-manager/docs/approval-rescue-loop.md +74 -0
- package/template/claude-task-manager/docs/codex-operational-warning-health.md +107 -0
- package/template/claude-task-manager/docs/codex-resume-state-guard-design.md +17 -12
- package/template/claude-task-manager/docs/codex-terminal-render-controller-handoff.md +311 -0
- package/template/claude-task-manager/docs/coding-agent-hooks-architecture.md +418 -0
- package/template/claude-task-manager/docs/conversation-import-freshness.md +20 -0
- package/template/claude-task-manager/docs/google-workspace-auth-health.md +77 -0
- package/template/claude-task-manager/docs/image-paste-ux.md +13 -0
- package/template/claude-task-manager/docs/ipad-web-preview.md +88 -0
- package/template/claude-task-manager/docs/main-loop-offload-architecture.md +66 -0
- package/template/claude-task-manager/docs/microsoft-dev-tunnel-phone-access-design.md +274 -519
- package/template/claude-task-manager/docs/mobile-live-streaming.md +27 -5
- package/template/claude-task-manager/docs/mobile-remote-submission-lifecycle.md +69 -0
- package/template/claude-task-manager/docs/phone-access-design.md +53 -15
- package/template/claude-task-manager/docs/phone-passkey-identity.md +122 -0
- package/template/claude-task-manager/docs/phone-setup.md +3 -0
- package/template/claude-task-manager/docs/prompt-editing-tree-design.md +25 -1
- package/template/claude-task-manager/docs/remote-desktop-access-design.md +268 -0
- package/template/claude-task-manager/docs/restart-lifecycle-architecture.md +95 -0
- package/template/claude-task-manager/docs/runtime-work-control-plane.md +53 -0
- package/template/claude-task-manager/docs/session-interactive-wait-surfaces.md +38 -0
- package/template/claude-task-manager/docs/session-needs-you-dismissal.md +84 -0
- package/template/claude-task-manager/docs/session-render-state-management-design.md +91 -3
- package/template/claude-task-manager/docs/session-standup-command-center-design.md +25 -1
- package/template/claude-task-manager/docs/session-title-authority.md +32 -0
- package/template/claude-task-manager/docs/session-workspace-binding.md +33 -0
- package/template/claude-task-manager/docs/skill-intent-resolution-design.md +72 -0
- package/template/claude-task-manager/docs/walle-mcp-supervisor-health.md +86 -0
- package/template/claude-task-manager/docs/walle-relay-phone-access-design.md +24 -15
- package/template/claude-task-manager/docs/walle-session-history-hydration.md +114 -0
- package/template/claude-task-manager/docs/walle-session-input-queue.md +104 -0
- package/template/claude-task-manager/docs/walle-session-model-catalog.md +90 -0
- package/template/claude-task-manager/docs/walle-session-model-preferences.md +15 -6
- package/template/claude-task-manager/git-utils.js +897 -27
- package/template/claude-task-manager/lib/agent-capabilities.js +33 -0
- package/template/claude-task-manager/lib/agent-cli-cache.js +37 -7
- package/template/claude-task-manager/lib/agent-hooks-installer.js +26 -2
- package/template/claude-task-manager/lib/agent-presets.js +17 -1
- package/template/claude-task-manager/lib/all-sessions-query.js +108 -0
- package/template/claude-task-manager/lib/approval-ai-refinement.js +488 -0
- package/template/claude-task-manager/lib/approval-self-adapt.js +168 -0
- package/template/claude-task-manager/lib/async-semaphore.js +44 -0
- package/template/claude-task-manager/lib/auth-context.js +5 -0
- package/template/claude-task-manager/lib/auth-rate-limit.js +47 -4
- package/template/claude-task-manager/lib/auth-rules.js +29 -2
- package/template/claude-task-manager/lib/auto-approval-verifier.js +129 -16
- package/template/claude-task-manager/lib/background-llm.js +144 -17
- package/template/claude-task-manager/lib/branch-inventory.js +212 -0
- package/template/claude-task-manager/lib/claude-desktop-sessions.js +15 -3
- package/template/claude-task-manager/lib/coalesce-sync-frames.js +151 -0
- package/template/claude-task-manager/lib/codex-launch-health.js +762 -0
- package/template/claude-task-manager/lib/codex-transcript-pager.js +51 -0
- package/template/claude-task-manager/lib/codex-zst.js +124 -0
- package/template/claude-task-manager/lib/coding-agent-models.js +233 -30
- package/template/claude-task-manager/lib/connection-health.js +232 -0
- package/template/claude-task-manager/lib/conversation-blob-parser.js +42 -0
- package/template/claude-task-manager/lib/conversation-tail-merge.js +89 -26
- package/template/claude-task-manager/lib/ctm-session-context-api.js +39 -10
- package/template/claude-task-manager/lib/cursor-conversation-store.js +354 -0
- package/template/claude-task-manager/lib/db-owner-worker-client.js +315 -0
- package/template/claude-task-manager/lib/document-review.js +141 -6
- package/template/claude-task-manager/lib/escalation-review.js +152 -0
- package/template/claude-task-manager/lib/graceful-shutdown.js +159 -0
- package/template/claude-task-manager/lib/headless-term-service.js +678 -0
- package/template/claude-task-manager/lib/heavy-worker-fallback.js +38 -0
- package/template/claude-task-manager/lib/jsonl-conversation-parser.js +542 -0
- package/template/claude-task-manager/lib/jsonl-range-reader.js +112 -0
- package/template/claude-task-manager/lib/main-db-census.js +216 -0
- package/template/claude-task-manager/lib/message-pagination.js +106 -4
- package/template/claude-task-manager/lib/microsoft-dev-tunnel-setup.js +750 -26
- package/template/claude-task-manager/lib/mobile-auth-api.js +274 -7
- package/template/claude-task-manager/lib/mobile-auth-store.js +592 -10
- package/template/claude-task-manager/lib/mobile-notification-dispatcher.js +15 -0
- package/template/claude-task-manager/lib/model-overview-brain-fallback.js +311 -0
- package/template/claude-task-manager/lib/model-overview-cache.js +141 -0
- package/template/claude-task-manager/lib/models-health-routing-notice.js +126 -0
- package/template/claude-task-manager/lib/node-pin-guard.js +93 -0
- package/template/claude-task-manager/lib/perf-tracker.js +242 -6
- package/template/claude-task-manager/lib/permission-match.js +76 -0
- package/template/claude-task-manager/lib/permission-sync.js +133 -20
- package/template/claude-task-manager/lib/process-title.js +35 -0
- package/template/claude-task-manager/lib/prompt-executions-query.js +25 -0
- package/template/claude-task-manager/lib/prompt-index-disk-cache.js +44 -0
- package/template/claude-task-manager/lib/prompt-intent.js +132 -0
- package/template/claude-task-manager/lib/provider-user-context.js +34 -0
- package/template/claude-task-manager/lib/read-pool-client.js +313 -0
- package/template/claude-task-manager/lib/readpool-breaker.js +31 -0
- package/template/claude-task-manager/lib/recent-sessions-breaker.js +12 -0
- package/template/claude-task-manager/lib/remote-feedback-client.js +72 -0
- package/template/claude-task-manager/lib/remote-relay-protocol.js +37 -4
- package/template/claude-task-manager/lib/remote-relay-store.js +159 -0
- package/template/claude-task-manager/lib/remote-submission-observer.js +278 -0
- package/template/claude-task-manager/lib/restart-guard.js +109 -0
- package/template/claude-task-manager/lib/restore-interruption-detector.js +439 -0
- package/template/claude-task-manager/lib/restore-policy.js +13 -0
- package/template/claude-task-manager/lib/restore-resume-batch.js +74 -0
- package/template/claude-task-manager/lib/restore-runtime.js +68 -0
- package/template/claude-task-manager/lib/restore-storm.js +34 -0
- package/template/claude-task-manager/lib/resume-cwd.js +36 -0
- package/template/claude-task-manager/lib/resume-preflight.js +313 -0
- package/template/claude-task-manager/lib/runtime-work-registry.js +444 -0
- package/template/claude-task-manager/lib/sanitize-openai-auth.js +31 -0
- package/template/claude-task-manager/lib/scheduler.js +21 -1
- package/template/claude-task-manager/lib/scrollback-snapshot-store.js +159 -0
- package/template/claude-task-manager/lib/serial-task-queue.js +64 -0
- package/template/claude-task-manager/lib/server-listeners.js +239 -0
- package/template/claude-task-manager/lib/session-capture.js +42 -7
- package/template/claude-task-manager/lib/session-content-backfill.js +131 -0
- package/template/claude-task-manager/lib/session-history.js +388 -43
- package/template/claude-task-manager/lib/session-host-manager.js +287 -0
- package/template/claude-task-manager/lib/session-image-refs.js +209 -0
- package/template/claude-task-manager/lib/session-jobs.js +399 -59
- package/template/claude-task-manager/lib/session-prompt-index.js +137 -0
- package/template/claude-task-manager/lib/session-restore.js +53 -0
- package/template/claude-task-manager/lib/session-standup.js +123 -23
- package/template/claude-task-manager/lib/session-state-bus.js +14 -0
- package/template/claude-task-manager/lib/session-stream.js +64 -16
- package/template/claude-task-manager/lib/session-timeline-summary.js +260 -0
- package/template/claude-task-manager/lib/session-token-usage.js +494 -0
- package/template/claude-task-manager/lib/session-workspace-binding.js +356 -0
- package/template/claude-task-manager/lib/setup-network-config.js +9 -0
- package/template/claude-task-manager/lib/size-cap.js +45 -0
- package/template/claude-task-manager/lib/size-cap.test.js +62 -0
- package/template/claude-task-manager/lib/skill-autocomplete.js +180 -1
- package/template/claude-task-manager/lib/skill-intent-resolver.js +304 -0
- package/template/claude-task-manager/lib/sqlite-driver.js +19 -3
- package/template/claude-task-manager/lib/standup-attention.js +7 -3
- package/template/claude-task-manager/lib/status-authority.js +39 -0
- package/template/claude-task-manager/lib/status-hooks.js +4 -0
- package/template/claude-task-manager/lib/storage-migration.js +235 -0
- package/template/claude-task-manager/lib/structured-capture.js +298 -0
- package/template/claude-task-manager/lib/sync-io-census.js +163 -0
- package/template/claude-task-manager/lib/tailscale-setup.js +6 -0
- package/template/claude-task-manager/lib/terminal-activity-evidence.js +33 -0
- package/template/claude-task-manager/lib/terminal-choice.js +364 -0
- package/template/claude-task-manager/lib/terminal-control-sanitize.js +17 -0
- package/template/claude-task-manager/lib/terminal-fingerprint.js +48 -0
- package/template/claude-task-manager/lib/terminal-output-flush.js +84 -0
- package/template/claude-task-manager/lib/timeline-order.js +122 -0
- package/template/claude-task-manager/lib/transcript-store.js +348 -43
- package/template/claude-task-manager/lib/transport-security.js +84 -1
- package/template/claude-task-manager/lib/wait-state.js +184 -0
- package/template/claude-task-manager/lib/walle-client.js +47 -5
- package/template/claude-task-manager/lib/walle-ctm-history.js +564 -4
- package/template/claude-task-manager/lib/walle-external-actions.js +135 -16
- package/template/claude-task-manager/lib/walle-history-hydration.js +46 -0
- package/template/claude-task-manager/lib/walle-native-health.js +403 -0
- package/template/claude-task-manager/lib/walle-repair.js +701 -0
- package/template/claude-task-manager/lib/walle-session-cache.js +109 -0
- package/template/claude-task-manager/lib/walle-session-context.js +57 -21
- package/template/claude-task-manager/lib/walle-session-model-catalog.js +34 -0
- package/template/claude-task-manager/lib/walle-supervisor.js +539 -63
- package/template/claude-task-manager/lib/walle-transcript.js +52 -0
- package/template/claude-task-manager/lib/worktree-active-sync.js +11 -7
- package/template/claude-task-manager/lib/worktree-cwd.js +32 -1
- package/template/claude-task-manager/package.json +1 -1
- package/template/claude-task-manager/prompt-harvest.js +89 -66
- package/template/claude-task-manager/providers/claude-code.js +51 -3
- package/template/claude-task-manager/providers/cursor.js +140 -45
- package/template/claude-task-manager/public/css/reviews.css +551 -61
- package/template/claude-task-manager/public/css/setup.css +191 -0
- package/template/claude-task-manager/public/css/walle-session.css +865 -10
- package/template/claude-task-manager/public/css/walle.css +154 -0
- package/template/claude-task-manager/public/designs/ai-providers-consolidation-v2.html +830 -0
- package/template/claude-task-manager/public/index.html +18516 -2058
- package/template/claude-task-manager/public/ipad.html +363 -0
- package/template/claude-task-manager/public/js/document-review-links.js +301 -0
- package/template/claude-task-manager/public/js/image-normalize.js +69 -36
- package/template/claude-task-manager/public/js/message-renderer.js +1265 -77
- package/template/claude-task-manager/public/js/prompts.js +66 -29
- package/template/claude-task-manager/public/js/reviews.js +901 -133
- package/template/claude-task-manager/public/js/session-activity-utils.js +11 -1
- package/template/claude-task-manager/public/js/session-search-utils.js +94 -10
- package/template/claude-task-manager/public/js/session-status-precedence.js +23 -5
- package/template/claude-task-manager/public/js/setup.js +1273 -176
- package/template/claude-task-manager/public/js/stream-view.js +691 -73
- package/template/claude-task-manager/public/js/terminal-reconciler.js +210 -0
- package/template/claude-task-manager/public/js/walle-session.js +2455 -158
- package/template/claude-task-manager/public/js/walle.js +455 -28
- package/template/claude-task-manager/public/m/app.css +2909 -262
- package/template/claude-task-manager/public/m/app.js +6601 -398
- package/template/claude-task-manager/public/m/claim.html +224 -17
- package/template/claude-task-manager/public/m/index.html +117 -21
- package/template/claude-task-manager/public/m/sw.js +3 -1
- package/template/claude-task-manager/public/manifest.json +2 -2
- package/template/claude-task-manager/public/prompts.html +30 -14
- package/template/claude-task-manager/queue-engine.js +507 -28
- package/template/claude-task-manager/scripts/repair-claude-session-images.js +27 -8
- package/template/claude-task-manager/server.js +14341 -2197
- package/template/claude-task-manager/session-integrity.js +160 -18
- package/template/claude-task-manager/session-search-ranking.js +1 -0
- package/template/claude-task-manager/session-utils.js +25 -5
- package/template/claude-task-manager/workers/approval-blocklist.js +96 -6
- package/template/claude-task-manager/workers/approval-widget-validator.js +14 -8
- package/template/claude-task-manager/workers/conversation-import-worker.js +11 -50
- package/template/claude-task-manager/workers/db-owner-worker.js +386 -0
- package/template/claude-task-manager/workers/harvest-worker.js +9 -55
- package/template/claude-task-manager/workers/headless-term-worker.js +9 -530
- package/template/claude-task-manager/workers/read-pool-worker.js +387 -0
- package/template/claude-task-manager/workers/scrollback-worker.js +11 -72
- package/template/claude-task-manager/workers/session-host-process.js +146 -0
- package/template/claude-task-manager/workers/session-integrity-worker.js +10 -54
- package/template/claude-task-manager/workers/state-detectors/base.js +18 -1
- package/template/claude-task-manager/workers/state-detectors/claude-code.js +182 -9
- package/template/claude-task-manager/workers/state-detectors/codex.js +150 -2
- package/template/claude-task-manager/workers/state-detectors/cursor.js +127 -0
- package/template/claude-task-manager/workers/state-detectors/gemini.js +21 -0
- package/template/claude-task-manager/workers/state-detectors/index.js +29 -0
- package/template/claude-task-manager/workers/state-detectors/opencode.js +103 -0
- package/template/docs/design/markdown-review-pane.md +206 -0
- package/template/docs/designs/2026-05-17-portkey-gateway-provider-ux.md +129 -38
- package/template/docs/designs/2026-05-20-mobile-worktree-finish-command.md +27 -0
- package/template/docs/designs/2026-05-22-ai-configuration-consolidation.md +248 -0
- package/template/docs/designs/ai-configuration-consolidation-mock.html +812 -0
- package/template/docs/private-memory-and-pii-policy.md +69 -0
- package/template/package.json +2 -1
- package/template/scripts/check-private-data.js +201 -0
- package/template/shared/sqlite-owner-guard.js +30 -0
- package/template/shared/sqlite-owner-write-queue.js +225 -0
- package/template/shared/sqlite-storage-policy.js +111 -0
- package/template/shared/sqlite-write-lock.js +428 -0
- package/template/wall-e/agent-runners/claude-code.js +5 -0
- package/template/wall-e/agent.js +166 -22
- package/template/wall-e/api-walle.js +524 -70
- package/template/wall-e/auth/provider-flows.js +11 -1
- package/template/wall-e/bin/walle-mcp-stdio.js +341 -17
- package/template/wall-e/brain.js +1614 -141
- package/template/wall-e/chat/attachment-blocks.js +96 -0
- package/template/wall-e/chat/attachments.js +2 -1
- package/template/wall-e/chat/capability-resolver.js +7 -7
- package/template/wall-e/chat/context-messages.js +28 -0
- package/template/wall-e/chat/conversation-frame.js +630 -0
- package/template/wall-e/chat/provider-messages.js +125 -0
- package/template/wall-e/chat.js +1002 -233
- package/template/wall-e/coding/acceptance-contract.js +170 -0
- package/template/wall-e/coding/acp-adapter.js +1 -1
- package/template/wall-e/coding/agent-catalog.js +3 -0
- package/template/wall-e/coding/artifact-store.js +93 -0
- package/template/wall-e/coding/capability-router.js +120 -0
- package/template/wall-e/coding/coding-run-controller.js +423 -0
- package/template/wall-e/coding/compaction-service.js +157 -12
- package/template/wall-e/coding/frontend-verification.js +258 -0
- package/template/wall-e/coding/lifecycle-hooks.js +75 -0
- package/template/wall-e/coding/local-preview-contract.js +157 -0
- package/template/wall-e/coding/permission-service.js +57 -13
- package/template/wall-e/coding/prompt-bundle.js +19 -1
- package/template/wall-e/coding/prompt-section-registry.js +227 -0
- package/template/wall-e/coding/provider-compat.js +15 -0
- package/template/wall-e/coding/runtime-events.js +224 -0
- package/template/wall-e/coding/runtime-mode.js +3 -0
- package/template/wall-e/coding/side-git-snapshot.js +160 -4
- package/template/wall-e/coding/snapshot-service.js +143 -1
- package/template/wall-e/coding/stream-processor.js +388 -34
- package/template/wall-e/coding/task-tool.js +141 -4
- package/template/wall-e/coding/tool-execution-controller.js +365 -0
- package/template/wall-e/coding/tool-registry.js +43 -5
- package/template/wall-e/coding/user-hooks.js +217 -0
- package/template/wall-e/coding-orchestrator.js +1330 -221
- package/template/wall-e/coding-prompts.js +20 -4
- package/template/wall-e/context/context-builder.js +15 -2
- package/template/wall-e/decision/confidence.js +1 -1
- package/template/wall-e/docs/coding-acceptance-contract.md +41 -0
- package/template/wall-e/docs/external-action-controller.md +26 -6
- package/template/wall-e/docs/telemetry-lifecycle.md +8 -2
- package/template/wall-e/embeddings.js +591 -53
- package/template/wall-e/external-action-controller.js +12 -0
- package/template/wall-e/http/auth.js +1 -0
- package/template/wall-e/http/chat-api.js +46 -11
- package/template/wall-e/http/model-admin.js +836 -34
- package/template/wall-e/lib/boot-profile.js +88 -0
- package/template/wall-e/lib/event-loop-monitor.js +93 -0
- package/template/wall-e/lib/service-health.js +194 -0
- package/template/wall-e/llm/anthropic.js +130 -5
- package/template/wall-e/llm/client.js +266 -63
- package/template/wall-e/llm/default-fallback.js +382 -0
- package/template/wall-e/llm/health.js +19 -0
- package/template/wall-e/llm/message-guard.js +78 -0
- package/template/wall-e/llm/model-catalog.js +252 -1
- package/template/wall-e/llm/openai.js +26 -4
- package/template/wall-e/llm/portkey-sync.js +654 -0
- package/template/wall-e/llm/provider-error.js +30 -2
- package/template/wall-e/llm/registry.js +5 -1
- package/template/wall-e/llm/request-compat.js +67 -0
- package/template/wall-e/loops/backfill.js +79 -23
- package/template/wall-e/loops/brain-optimize.js +67 -0
- package/template/wall-e/loops/ingest.js +25 -10
- package/template/wall-e/loops/question-digest.js +160 -0
- package/template/wall-e/loops/reflect.js +6 -4
- package/template/wall-e/loops/think.js +39 -12
- package/template/wall-e/mcp-server.js +318 -36
- package/template/wall-e/memory/ctm-context-client.js +52 -14
- package/template/wall-e/memory/ctm-operational-context.js +237 -0
- package/template/wall-e/memory/ctm-prompt-executions-client.js +128 -0
- package/template/wall-e/memory/ctm-session-context.js +111 -63
- package/template/wall-e/prompts/coding/deepseek.txt +3 -0
- package/template/wall-e/prompts/coding/gemini.txt +6 -0
- package/template/wall-e/prompts/coding/gpt.txt +6 -0
- package/template/wall-e/prompts/coding/local.txt +7 -0
- package/template/wall-e/runtime/decision-hooks.js +115 -0
- package/template/wall-e/runtime/devbox-gateway.js +82 -8
- package/template/wall-e/runtime/prompt-manifest.js +86 -0
- package/template/wall-e/runtime/tool-executor.js +269 -0
- package/template/wall-e/runtime/tool-result-envelope.js +138 -0
- package/template/wall-e/runtime/transcript-projection.js +60 -0
- package/template/wall-e/runtime/walle-runtime.js +224 -0
- package/template/wall-e/scripts/db-optimize/migrate.js +162 -0
- package/template/wall-e/scripts/db-optimize/recall-eval.js +117 -0
- package/template/wall-e/server.js +15 -0
- package/template/wall-e/session-files.js +9 -0
- package/template/wall-e/skills/_bundled/google-calendar/run.js +1 -1
- package/template/wall-e/skills/_bundled/gws-workspace/run.js +1 -1
- package/template/wall-e/skills/_bundled/slack-mentions/run.js +76 -6
- package/template/wall-e/skills/claude-code-reader.js +7 -3
- package/template/wall-e/skills/script-skill-runner.js +10 -0
- package/template/wall-e/skills/skill-planner.js +38 -0
- package/template/wall-e/tools/builtin-middleware.js +19 -9
- package/template/wall-e/tools/local-tools.js +1428 -16
- package/template/wall-e/tools/permission-checker.js +73 -5
- package/template/wall-e/tools/question-manager.js +117 -7
- package/template/wall-e/training/harvester.js +12 -28
- package/template/wall-e/training/replay.js +25 -80
- package/template/website/index.html +10 -10
- package/template/wall-e/eval/ab-test.js +0 -203
- package/template/wall-e/eval/agent-runner.js +0 -772
- package/template/wall-e/eval/agent-scorer.js +0 -461
- package/template/wall-e/eval/aggregator.js +0 -414
- package/template/wall-e/eval/allowed-test-commands.js +0 -34
- package/template/wall-e/eval/benchmark-generator.js +0 -113
- package/template/wall-e/eval/benchmarks/chat-eval.json +0 -1662
- package/template/wall-e/eval/benchmarks/chat.json +0 -82
- package/template/wall-e/eval/benchmarks/coding-agent-real.json +0 -1
- package/template/wall-e/eval/benchmarks/coding-agent.json +0 -1581
- package/template/wall-e/eval/benchmarks/coding.json +0 -122
- package/template/wall-e/eval/benchmarks/memory-retrieval.json +0 -234
- package/template/wall-e/eval/benchmarks/reasoning.json +0 -82
- package/template/wall-e/eval/benchmarks/swebench-lite-30.json +0 -212
- package/template/wall-e/eval/benchmarks.js +0 -669
- package/template/wall-e/eval/cc-replay.js +0 -719
- package/template/wall-e/eval/chat-eval.js +0 -525
- package/template/wall-e/eval/check-keys.js +0 -15
- package/template/wall-e/eval/check-providers.js +0 -42
- package/template/wall-e/eval/codex-cli-baseline.js +0 -669
- package/template/wall-e/eval/coding-agent-real.js +0 -570
- package/template/wall-e/eval/context-compactor.js +0 -251
- package/template/wall-e/eval/debug-agent003.js +0 -68
- package/template/wall-e/eval/diagnostics.js +0 -216
- package/template/wall-e/eval/eval-orchestrator.js +0 -642
- package/template/wall-e/eval/evaluate.js +0 -202
- package/template/wall-e/eval/evaluator.js +0 -373
- package/template/wall-e/eval/exporter.js +0 -212
- package/template/wall-e/eval/fixtures/express-basic/package.json +0 -9
- package/template/wall-e/eval/fixtures/express-basic/server.js +0 -115
- package/template/wall-e/eval/fixtures/express-basic/test.js +0 -83
- package/template/wall-e/eval/fixtures/express-buggy/package.json +0 -9
- package/template/wall-e/eval/fixtures/express-buggy/server.js +0 -113
- package/template/wall-e/eval/fixtures/express-buggy/test.js +0 -83
- package/template/wall-e/eval/fixtures/express-buggy-items/package.json +0 -9
- package/template/wall-e/eval/fixtures/express-buggy-items/server.js +0 -112
- package/template/wall-e/eval/fixtures/express-buggy-items/test.js +0 -83
- package/template/wall-e/eval/fixtures/express-buggy-search/package.json +0 -9
- package/template/wall-e/eval/fixtures/express-buggy-search/server.js +0 -121
- package/template/wall-e/eval/fixtures/express-buggy-search/test.js +0 -83
- package/template/wall-e/eval/fixtures/express-rename-data/data.js +0 -34
- package/template/wall-e/eval/fixtures/express-rename-data/package.json +0 -9
- package/template/wall-e/eval/fixtures/express-rename-data/server.js +0 -97
- package/template/wall-e/eval/fixtures/express-rename-data/test.js +0 -88
- package/template/wall-e/eval/fixtures/express-xss/package.json +0 -12
- package/template/wall-e/eval/fixtures/express-xss/server.js +0 -90
- package/template/wall-e/eval/fixtures/express-xss/test.js +0 -67
- package/template/wall-e/eval/fixtures/express-xss/views/profile.ejs +0 -9
- package/template/wall-e/eval/fixtures/fullstack-app/config/default.js +0 -9
- package/template/wall-e/eval/fixtures/fullstack-app/config/test.js +0 -13
- package/template/wall-e/eval/fixtures/fullstack-app/package.json +0 -11
- package/template/wall-e/eval/fixtures/fullstack-app/public/css/style.css +0 -137
- package/template/wall-e/eval/fixtures/fullstack-app/public/index.html +0 -46
- package/template/wall-e/eval/fixtures/fullstack-app/public/js/app.js +0 -121
- package/template/wall-e/eval/fixtures/fullstack-app/public/js/auth.js +0 -71
- package/template/wall-e/eval/fixtures/fullstack-app/public/js/items.js +0 -80
- package/template/wall-e/eval/fixtures/fullstack-app/public/js/users.js +0 -46
- package/template/wall-e/eval/fixtures/fullstack-app/public/login.html +0 -45
- package/template/wall-e/eval/fixtures/fullstack-app/public/register.html +0 -38
- package/template/wall-e/eval/fixtures/fullstack-app/scripts/migrate.js +0 -23
- package/template/wall-e/eval/fixtures/fullstack-app/scripts/seed.js +0 -46
- package/template/wall-e/eval/fixtures/fullstack-app/server/db.js +0 -99
- package/template/wall-e/eval/fixtures/fullstack-app/server/index.js +0 -94
- package/template/wall-e/eval/fixtures/fullstack-app/server/middleware/auth.js +0 -19
- package/template/wall-e/eval/fixtures/fullstack-app/server/middleware/logger.js +0 -19
- package/template/wall-e/eval/fixtures/fullstack-app/server/router.js +0 -50
- package/template/wall-e/eval/fixtures/fullstack-app/server/routes/auth.js +0 -69
- package/template/wall-e/eval/fixtures/fullstack-app/server/routes/health.js +0 -23
- package/template/wall-e/eval/fixtures/fullstack-app/server/routes/items.js +0 -88
- package/template/wall-e/eval/fixtures/fullstack-app/server/routes/users.js +0 -75
- package/template/wall-e/eval/fixtures/fullstack-app/server/test.js +0 -198
- package/template/wall-e/eval/fixtures/fullstack-app/server/utils/response.js +0 -34
- package/template/wall-e/eval/fixtures/fullstack-app/server/utils/validate.js +0 -26
- package/template/wall-e/eval/fixtures/fullstack-app/server.js +0 -8
- package/template/wall-e/eval/fixtures/fullstack-app/test.js +0 -12
- package/template/wall-e/eval/fixtures/monorepo-basic/package.json +0 -8
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/data.js +0 -58
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/middleware.js +0 -46
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/package.json +0 -8
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/routes.js +0 -64
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/server.js +0 -56
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/test.js +0 -116
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/commands.js +0 -61
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/index.js +0 -62
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/output.js +0 -43
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/package.json +0 -11
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/test.js +0 -44
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/formatters.js +0 -43
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/index.js +0 -12
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/package.json +0 -5
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/test.js +0 -55
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/validators.js +0 -29
- package/template/wall-e/eval/fixtures/monorepo-basic/test.js +0 -46
- package/template/wall-e/eval/fixtures/node-cli/index.js +0 -78
- package/template/wall-e/eval/fixtures/node-cli/package.json +0 -10
- package/template/wall-e/eval/fixtures/node-cli/test.js +0 -57
- package/template/wall-e/eval/fixtures/node-typed/package.json +0 -8
- package/template/wall-e/eval/fixtures/node-typed/src/handlers.js +0 -31
- package/template/wall-e/eval/fixtures/node-typed/src/utils.js +0 -33
- package/template/wall-e/eval/fixtures/node-typed/test.js +0 -36
- package/template/wall-e/eval/fixtures/python-flask/app.py +0 -14
- package/template/wall-e/eval/fixtures/python-flask/requirements.txt +0 -2
- package/template/wall-e/eval/fixtures/python-flask/test_app.py +0 -25
- package/template/wall-e/eval/fixtures/wall-e-subset/brain.js +0 -105
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/aggregator.js +0 -101
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/benchmarks/chat.json +0 -20
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/benchmarks/coding.json +0 -32
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/benchmarks.js +0 -64
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/package.json +0 -6
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/server.js +0 -31
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/test.js +0 -18
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/utils.js +0 -34
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/runner.js +0 -104
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/scorer.js +0 -73
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/test.js +0 -134
- package/template/wall-e/eval/fixtures/wall-e-subset/llm/client.js +0 -99
- package/template/wall-e/eval/fixtures/wall-e-subset/llm/providers.js +0 -63
- package/template/wall-e/eval/fixtures/wall-e-subset/llm/test.js +0 -70
- package/template/wall-e/eval/fixtures/wall-e-subset/package.json +0 -10
- package/template/wall-e/eval/fixtures/wall-e-subset/test.js +0 -86
- package/template/wall-e/eval/harvester.js +0 -685
- package/template/wall-e/eval/head-to-head.js +0 -388
- package/template/wall-e/eval/humaneval-adapter.js +0 -321
- package/template/wall-e/eval/list-models.js +0 -31
- package/template/wall-e/eval/livecodebench-adapter.js +0 -291
- package/template/wall-e/eval/mail-integration.js +0 -443
- package/template/wall-e/eval/manifest.js +0 -186
- package/template/wall-e/eval/meta-harness/adapters/coding-agent.js +0 -57
- package/template/wall-e/eval/meta-harness/bootstrap-snapshot.js +0 -149
- package/template/wall-e/eval/meta-harness/candidate-store.js +0 -117
- package/template/wall-e/eval/meta-harness/cli.js +0 -86
- package/template/wall-e/eval/meta-harness/domain-spec.js +0 -154
- package/template/wall-e/eval/meta-harness/domains/coding-agent.domain.json +0 -84
- package/template/wall-e/eval/meta-harness/examples/env-bootstrap-candidate.js +0 -29
- package/template/wall-e/eval/meta-harness/experience-store.js +0 -174
- package/template/wall-e/eval/meta-harness/frontier.js +0 -96
- package/template/wall-e/eval/meta-harness/harness-interface.js +0 -90
- package/template/wall-e/eval/meta-harness/leakage-guard.js +0 -80
- package/template/wall-e/eval/meta-harness/optimizer.js +0 -207
- package/template/wall-e/eval/meta-harness/proposer-runner.js +0 -110
- package/template/wall-e/eval/meta-harness/reporting.js +0 -58
- package/template/wall-e/eval/meta-harness/telemetry.js +0 -27
- package/template/wall-e/eval/meta-harness/validation.js +0 -81
- package/template/wall-e/eval/promoter.js +0 -228
- package/template/wall-e/eval/provider-normalizer.js +0 -33
- package/template/wall-e/eval/replay.js +0 -395
- package/template/wall-e/eval/run-agent-benchmarks.js +0 -386
- package/template/wall-e/eval/run-codex-cli-baseline.js +0 -177
- package/template/wall-e/eval/run-coding-agent-real.js +0 -187
- package/template/wall-e/eval/run-eval.js +0 -435
- package/template/wall-e/eval/run-model-comparison.js +0 -142
- package/template/wall-e/eval/session-evaluator.js +0 -187
- package/template/wall-e/eval/session-miner.js +0 -207
- package/template/wall-e/eval/session-retrieval-benchmark.js +0 -150
- package/template/wall-e/eval/session-transcripts.js +0 -509
- package/template/wall-e/eval/shadow.js +0 -161
- package/template/wall-e/eval/swebench-adapter.js +0 -345
- package/template/wall-e/eval/swebench-docker.js +0 -192
- package/template/wall-e/eval/train.py +0 -320
- package/template/wall-e/eval/trainer.js +0 -232
- package/template/wall-e/eval/weekly-eval-loop.js +0 -241
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const Database = require('better-sqlite3');
|
|
7
|
+
|
|
8
|
+
const CURSOR_HOME = () => path.join(os.homedir(), '.cursor');
|
|
9
|
+
const CACHE = new Map();
|
|
10
|
+
const SHA256_HEX_RE = /^[a-f0-9]{64}$/i;
|
|
11
|
+
|
|
12
|
+
function _decodeMaybeHexJson(value) {
|
|
13
|
+
if (value == null) return null;
|
|
14
|
+
const raw = Buffer.isBuffer(value) ? value.toString('utf8') : String(value);
|
|
15
|
+
const trimmed = raw.trim();
|
|
16
|
+
const candidates = [trimmed];
|
|
17
|
+
if (/^[0-9a-f]+$/i.test(trimmed) && trimmed.length % 2 === 0) {
|
|
18
|
+
try { candidates.unshift(Buffer.from(trimmed, 'hex').toString('utf8')); } catch {}
|
|
19
|
+
}
|
|
20
|
+
for (const value of candidates) {
|
|
21
|
+
const candidate = String(value || '').trim();
|
|
22
|
+
if (!candidate || candidate[0] !== '{') continue;
|
|
23
|
+
try { return JSON.parse(candidate); } catch {}
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function _readMeta(db) {
|
|
29
|
+
const row = db.prepare('SELECT value FROM meta WHERE key = ?').get('0')
|
|
30
|
+
|| db.prepare('SELECT value FROM meta LIMIT 1').get();
|
|
31
|
+
return _decodeMaybeHexJson(row?.value);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function _bufferFromBlob(value) {
|
|
35
|
+
if (Buffer.isBuffer(value)) return value;
|
|
36
|
+
if (value instanceof Uint8Array) return Buffer.from(value);
|
|
37
|
+
return Buffer.from(String(value || ''), 'utf8');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function _orderedBlobRefs(buffer, idSet) {
|
|
41
|
+
if (!Buffer.isBuffer(buffer) || buffer.length < 32 || idSet.size === 0) return [];
|
|
42
|
+
// Find every 32-byte blob-id (graph edge) embedded at any byte offset, in order of first
|
|
43
|
+
// appearance. The naive form allocated a 32-byte subarray AND hex-encoded it at EVERY
|
|
44
|
+
// offset (O(n) Buffer.subarray + hexSlice) — the dominant main-thread freeze in CPU
|
|
45
|
+
// profiles (~26% of non-idle: hexSlice + FastBuffer churn). Hex-encode the WHOLE buffer
|
|
46
|
+
// ONCE (one native call) then slide a 64-char window over the hex string at byte-aligned
|
|
47
|
+
// (even) offsets: no per-offset Buffer allocation, ~3× faster, and O(n) regardless of how
|
|
48
|
+
// many blob ids the session has (the per-id Buffer.indexOf alternative degrades to O(ids×n)
|
|
49
|
+
// as conversations grow). Output is byte-for-byte identical to the naive scan.
|
|
50
|
+
const hexAll = buffer.toString('hex');
|
|
51
|
+
const end = hexAll.length - 64; // byte offset i ↔ hex offset 2i; window is 64 hex chars
|
|
52
|
+
const refs = [];
|
|
53
|
+
const seen = new Set();
|
|
54
|
+
for (let h = 0; h <= end; h += 2) {
|
|
55
|
+
const hex = hexAll.slice(h, h + 64);
|
|
56
|
+
if (!idSet.has(hex) || seen.has(hex)) continue;
|
|
57
|
+
seen.add(hex);
|
|
58
|
+
refs.push(hex);
|
|
59
|
+
}
|
|
60
|
+
return refs;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function _reachableBlobIds(rootBlobId, blobsById) {
|
|
64
|
+
const root = String(rootBlobId || '').trim();
|
|
65
|
+
if (!SHA256_HEX_RE.test(root) || !blobsById.has(root)) return [];
|
|
66
|
+
const idSet = new Set(blobsById.keys());
|
|
67
|
+
const seen = new Set([root]);
|
|
68
|
+
const order = [];
|
|
69
|
+
const queue = [root];
|
|
70
|
+
while (queue.length) {
|
|
71
|
+
const id = queue.shift();
|
|
72
|
+
order.push(id);
|
|
73
|
+
const blob = blobsById.get(id);
|
|
74
|
+
if (!blob || blob[0] === 0x7b) continue; // JSON message blobs do not carry graph edges.
|
|
75
|
+
for (const ref of _orderedBlobRefs(blob, idSet)) {
|
|
76
|
+
if (ref === id || seen.has(ref)) continue;
|
|
77
|
+
seen.add(ref);
|
|
78
|
+
queue.push(ref);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return order;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function _contentText(content, role) {
|
|
85
|
+
if (typeof content === 'string') return content;
|
|
86
|
+
if (!Array.isArray(content)) return '';
|
|
87
|
+
const parts = [];
|
|
88
|
+
for (const item of content) {
|
|
89
|
+
if (!item || typeof item !== 'object') continue;
|
|
90
|
+
if (item.type === 'text' && typeof item.text === 'string') parts.push(item.text);
|
|
91
|
+
else if (role === 'tool' && typeof item.result === 'string') parts.push(item.result);
|
|
92
|
+
}
|
|
93
|
+
return parts.join('\n\n').trim();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function _normalizeCursorUserText(text) {
|
|
97
|
+
const raw = String(text || '').trim();
|
|
98
|
+
if (!raw) return '';
|
|
99
|
+
const query = raw.match(/<user_query>\s*([\s\S]*?)\s*<\/user_query>/i);
|
|
100
|
+
if (query) return query[1].trim();
|
|
101
|
+
if (/^<user_info>/i.test(raw)) return '';
|
|
102
|
+
if (/^\[Previous conversation summary\]/i.test(raw)) return '';
|
|
103
|
+
if (/^Your conversation was summarized due to context constraints\./i.test(raw)) return '';
|
|
104
|
+
return raw;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function _normalizeCursorAssistantText(text) {
|
|
108
|
+
const raw = String(text || '').trim();
|
|
109
|
+
if (!raw) return '';
|
|
110
|
+
if (raw === 'redacted-reasoning' || raw === 'tool-call') return '';
|
|
111
|
+
return raw;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function _messageFromBlobJson(value, index, meta) {
|
|
115
|
+
if (!value || typeof value !== 'object') return null;
|
|
116
|
+
const role = String(value.role || '').trim();
|
|
117
|
+
if (role !== 'user' && role !== 'assistant') return null;
|
|
118
|
+
const rawText = _contentText(value.content, role);
|
|
119
|
+
const text = role === 'user'
|
|
120
|
+
? _normalizeCursorUserText(rawText)
|
|
121
|
+
: _normalizeCursorAssistantText(rawText);
|
|
122
|
+
if (!text) return null;
|
|
123
|
+
const baseMs = Number(meta?.createdAt || 0);
|
|
124
|
+
const timestamp = Number.isFinite(baseMs) && baseMs > 0
|
|
125
|
+
? new Date(baseMs + index).toISOString()
|
|
126
|
+
: '';
|
|
127
|
+
return {
|
|
128
|
+
role,
|
|
129
|
+
text,
|
|
130
|
+
timestamp,
|
|
131
|
+
provider: 'cursor',
|
|
132
|
+
metadata: {
|
|
133
|
+
provider: 'cursor',
|
|
134
|
+
source: 'cursor-local-store',
|
|
135
|
+
cursorAgentId: String(meta?.agentId || ''),
|
|
136
|
+
cursorMessageId: String(value.id || ''),
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function _workspaceUriFromBlob(buffer) {
|
|
142
|
+
const text = _bufferFromBlob(buffer).toString('utf8');
|
|
143
|
+
const match = text.match(/file:\/\/[^\x00-\x1f\x7f]+/);
|
|
144
|
+
return match ? match[0] : '';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function _workspacePathFromUri(uri) {
|
|
148
|
+
const raw = String(uri || '').trim();
|
|
149
|
+
if (!raw.startsWith('file://')) return '';
|
|
150
|
+
let decoded = '';
|
|
151
|
+
try {
|
|
152
|
+
decoded = decodeURIComponent(raw.replace(/^file:\/\//, ''));
|
|
153
|
+
} catch {
|
|
154
|
+
decoded = raw.replace(/^file:\/\//, '');
|
|
155
|
+
}
|
|
156
|
+
if (!decoded || fs.existsSync(decoded)) return decoded;
|
|
157
|
+
// Cursor's root blob is binary/protobuf-like. The workspace URI is embedded
|
|
158
|
+
// as a string, and the following protobuf bytes can occasionally be printable
|
|
159
|
+
// ASCII, so a raw string scan may capture one or two bytes past the path.
|
|
160
|
+
// Trim only when that recovers a real path; deleted workspaces keep the raw
|
|
161
|
+
// decoded value so callers can still inspect the store metadata.
|
|
162
|
+
for (let i = decoded.length - 1; i > 0; i--) {
|
|
163
|
+
const candidate = decoded.slice(0, i);
|
|
164
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
165
|
+
}
|
|
166
|
+
return decoded;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function _statSignature(storeDbPath) {
|
|
170
|
+
const parts = [];
|
|
171
|
+
for (const fp of [storeDbPath, `${storeDbPath}-wal`, `${storeDbPath}-shm`]) {
|
|
172
|
+
try {
|
|
173
|
+
const st = fs.statSync(fp);
|
|
174
|
+
parts.push(`${st.size}:${Math.floor(st.mtimeMs)}`);
|
|
175
|
+
} catch {
|
|
176
|
+
parts.push('0:0');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return parts.join('|');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function loadCursorStore(storeDbPath) {
|
|
183
|
+
const fp = path.resolve(String(storeDbPath || ''));
|
|
184
|
+
const signature = _statSignature(fp);
|
|
185
|
+
const cached = CACHE.get(fp);
|
|
186
|
+
if (cached && cached.signature === signature) return cached.result;
|
|
187
|
+
|
|
188
|
+
const db = new Database(fp, { readonly: true, fileMustExist: true });
|
|
189
|
+
try {
|
|
190
|
+
const meta = _readMeta(db);
|
|
191
|
+
if (!meta?.latestRootBlobId) return null;
|
|
192
|
+
const rows = db.prepare('SELECT id, data FROM blobs').all();
|
|
193
|
+
const blobsById = new Map();
|
|
194
|
+
for (const row of rows) {
|
|
195
|
+
const id = String(row.id || '').trim();
|
|
196
|
+
if (SHA256_HEX_RE.test(id)) blobsById.set(id, _bufferFromBlob(row.data));
|
|
197
|
+
}
|
|
198
|
+
const rootBlob = blobsById.get(String(meta.latestRootBlobId || '').trim()) || null;
|
|
199
|
+
const workspaceUri = rootBlob ? _workspaceUriFromBlob(rootBlob) : '';
|
|
200
|
+
const reachableIds = _reachableBlobIds(meta.latestRootBlobId, blobsById);
|
|
201
|
+
const messages = [];
|
|
202
|
+
reachableIds.forEach((id, index) => {
|
|
203
|
+
const blob = blobsById.get(id);
|
|
204
|
+
if (!blob || blob[0] !== 0x7b) return;
|
|
205
|
+
try {
|
|
206
|
+
const message = _messageFromBlobJson(JSON.parse(blob.toString('utf8')), index, meta);
|
|
207
|
+
if (message) messages.push(message);
|
|
208
|
+
} catch {}
|
|
209
|
+
});
|
|
210
|
+
const result = {
|
|
211
|
+
storeDbPath: fp,
|
|
212
|
+
agentId: String(meta.agentId || ''),
|
|
213
|
+
name: String(meta.name || ''),
|
|
214
|
+
createdAtMs: Number(meta.createdAt || 0) || 0,
|
|
215
|
+
lastUsedModel: String(meta.lastUsedModel || ''),
|
|
216
|
+
workspaceUri,
|
|
217
|
+
workspacePath: _workspacePathFromUri(workspaceUri),
|
|
218
|
+
messages,
|
|
219
|
+
};
|
|
220
|
+
CACHE.set(fp, { signature, result });
|
|
221
|
+
return result;
|
|
222
|
+
} finally {
|
|
223
|
+
db.close();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function _listCursorStoreDbPaths(cursorHome = CURSOR_HOME()) {
|
|
228
|
+
const chatsDir = path.join(cursorHome, 'chats');
|
|
229
|
+
let workspaceDirs = [];
|
|
230
|
+
try { workspaceDirs = fs.readdirSync(chatsDir, { withFileTypes: true }); } catch { return []; }
|
|
231
|
+
const paths = [];
|
|
232
|
+
for (const workspaceEntry of workspaceDirs) {
|
|
233
|
+
if (!workspaceEntry.isDirectory()) continue;
|
|
234
|
+
const workspaceDir = path.join(chatsDir, workspaceEntry.name);
|
|
235
|
+
let agentDirs = [];
|
|
236
|
+
try { agentDirs = fs.readdirSync(workspaceDir, { withFileTypes: true }); } catch { continue; }
|
|
237
|
+
for (const agentEntry of agentDirs) {
|
|
238
|
+
if (!agentEntry.isDirectory()) continue;
|
|
239
|
+
const storePath = path.join(workspaceDir, agentEntry.name, 'store.db');
|
|
240
|
+
if (fs.existsSync(storePath)) paths.push(storePath);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return paths;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function _parseTimeMs(value) {
|
|
247
|
+
if (typeof value === 'number') return Number.isFinite(value) ? value : 0;
|
|
248
|
+
const text = String(value || '').trim();
|
|
249
|
+
if (!text) return 0;
|
|
250
|
+
const parsed = Date.parse(/[zZ]|[+-]\d\d:?\d\d$/.test(text) ? text : text.replace(' ', 'T') + 'Z');
|
|
251
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function _samePath(a, b) {
|
|
255
|
+
if (!a || !b) return false;
|
|
256
|
+
try { return path.resolve(a) === path.resolve(b); } catch { return String(a) === String(b); }
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function findCursorStoresForSession(options = {}) {
|
|
260
|
+
const cwd = String(options.cwd || '').trim();
|
|
261
|
+
const createdAtMs = _parseTimeMs(options.createdAt || options.created_at);
|
|
262
|
+
const updatedAtMs = _parseTimeMs(options.updatedAt || options.updated_at);
|
|
263
|
+
const targetMs = updatedAtMs || createdAtMs || Date.now();
|
|
264
|
+
const agentIds = new Set((options.agentSessionIds || options.agentIds || [])
|
|
265
|
+
.map(id => String(id || '').trim())
|
|
266
|
+
.filter(Boolean));
|
|
267
|
+
const stores = [];
|
|
268
|
+
for (const storeDbPath of _listCursorStoreDbPaths(options.cursorHome)) {
|
|
269
|
+
let store;
|
|
270
|
+
try { store = loadCursorStore(storeDbPath); } catch { continue; }
|
|
271
|
+
if (!store) continue;
|
|
272
|
+
const agentMatch = store.agentId && agentIds.has(store.agentId);
|
|
273
|
+
const cwdMatch = cwd && _samePath(store.workspacePath, cwd);
|
|
274
|
+
if (!agentMatch && !cwdMatch) continue;
|
|
275
|
+
const created = store.createdAtMs || 0;
|
|
276
|
+
const distanceMs = created && targetMs ? Math.abs(created - targetMs) : Number.MAX_SAFE_INTEGER;
|
|
277
|
+
stores.push({
|
|
278
|
+
...store,
|
|
279
|
+
_score: {
|
|
280
|
+
agentMatch: agentMatch ? 1 : 0,
|
|
281
|
+
cwdMatch: cwdMatch ? 1 : 0,
|
|
282
|
+
distanceMs,
|
|
283
|
+
createdAtMs: created,
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
stores.sort((a, b) => (
|
|
288
|
+
b._score.agentMatch - a._score.agentMatch
|
|
289
|
+
|| b._score.cwdMatch - a._score.cwdMatch
|
|
290
|
+
|| a._score.distanceMs - b._score.distanceMs
|
|
291
|
+
|| b._score.createdAtMs - a._score.createdAtMs
|
|
292
|
+
|| a.storeDbPath.localeCompare(b.storeDbPath)
|
|
293
|
+
));
|
|
294
|
+
return stores;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function loadCursorConversationForSession(options = {}) {
|
|
298
|
+
const stores = findCursorStoresForSession(options);
|
|
299
|
+
for (const store of stores) {
|
|
300
|
+
if (store.messages.length > 0) return store;
|
|
301
|
+
}
|
|
302
|
+
return stores[0] || null;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Map a reconstructed cursor store to the fields db.importSessionConversation expects, so a
|
|
306
|
+
// cursor conversation lands in session_conversations exactly like a Claude/Codex import and
|
|
307
|
+
// the normal cache read path serves it. Pure (no I/O) → unit-testable. messages already carry
|
|
308
|
+
// the {role,text,timestamp,provider,metadata} shape the renderer expects.
|
|
309
|
+
function cursorStoreToConversationFields(store) {
|
|
310
|
+
const messages = Array.isArray(store?.messages) ? store.messages : [];
|
|
311
|
+
let user_msg_count = 0;
|
|
312
|
+
let assistant_msg_count = 0;
|
|
313
|
+
let first_message = '';
|
|
314
|
+
let first_assistant_text = '';
|
|
315
|
+
let last_user_content = '';
|
|
316
|
+
for (const m of messages) {
|
|
317
|
+
if (!m || typeof m !== 'object') continue;
|
|
318
|
+
if (m.role === 'user') {
|
|
319
|
+
user_msg_count += 1;
|
|
320
|
+
if (!first_message) first_message = String(m.text || '');
|
|
321
|
+
if (m.text) last_user_content = String(m.text);
|
|
322
|
+
} else if (m.role === 'assistant') {
|
|
323
|
+
assistant_msg_count += 1;
|
|
324
|
+
if (!first_assistant_text) first_assistant_text = String(m.text || '');
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
messages,
|
|
329
|
+
user_msg_count,
|
|
330
|
+
assistant_msg_count,
|
|
331
|
+
first_message,
|
|
332
|
+
last_user_content,
|
|
333
|
+
first_assistant_text,
|
|
334
|
+
project_path: String(store?.workspacePath || ''),
|
|
335
|
+
model_provider: 'cursor',
|
|
336
|
+
model_id: String(store?.lastUsedModel || ''),
|
|
337
|
+
session_created_at: Number(store?.createdAtMs) > 0 ? new Date(Number(store.createdAtMs)).toISOString() : '',
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
module.exports = {
|
|
342
|
+
loadCursorStore,
|
|
343
|
+
findCursorStoresForSession,
|
|
344
|
+
loadCursorConversationForSession,
|
|
345
|
+
cursorStoreToConversationFields,
|
|
346
|
+
statSignature: _statSignature, // cheap size:mtime gate for incremental import
|
|
347
|
+
_test: {
|
|
348
|
+
_decodeMaybeHexJson,
|
|
349
|
+
_orderedBlobRefs,
|
|
350
|
+
_reachableBlobIds,
|
|
351
|
+
_normalizeCursorUserText,
|
|
352
|
+
_parseTimeMs,
|
|
353
|
+
},
|
|
354
|
+
};
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { Worker } = require('node:worker_threads');
|
|
5
|
+
|
|
6
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 30 * 1000;
|
|
7
|
+
const DEFAULT_CLOSE_TIMEOUT_MS = 5 * 1000;
|
|
8
|
+
const DEFAULT_WORKER_WRITE_LOCK_TIMEOUT_MS = 5000;
|
|
9
|
+
// Circuit breaker: after this many consecutive request timeouts the worker is
|
|
10
|
+
// treated as "degraded" (busy/wedged, not merely a one-off slow op), and
|
|
11
|
+
// best-effort ops fail fast WITHOUT being enqueued — so a slow worker stops
|
|
12
|
+
// accumulating a backlog of stale work that re-holds the SQLite write lock.
|
|
13
|
+
const DEFAULT_DEGRADE_AFTER_TIMEOUTS = 3;
|
|
14
|
+
// While degraded, best-effort ops are skipped for this long; after it elapses one
|
|
15
|
+
// is allowed through (half-open probe) — it resets the breaker if it succeeds, or
|
|
16
|
+
// re-arms the cooldown if it times out again.
|
|
17
|
+
const DEFAULT_DEGRADE_COOLDOWN_MS = 5000;
|
|
18
|
+
|
|
19
|
+
function _durationMs(value, fallback) {
|
|
20
|
+
const n = Number(value);
|
|
21
|
+
return Number.isFinite(n) ? Math.max(0, Math.trunc(n)) : fallback;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class CtmDbOwnerWorkerClient {
|
|
25
|
+
constructor(options = {}) {
|
|
26
|
+
if (!options.dbPath) throw new Error('CtmDbOwnerWorkerClient requires dbPath');
|
|
27
|
+
this.dbPath = options.dbPath;
|
|
28
|
+
this.workerPath = options.workerPath || path.resolve(__dirname, '..', 'workers', 'db-owner-worker.js');
|
|
29
|
+
this.initDb = !!options.initDb;
|
|
30
|
+
this.requestTimeoutMs = _durationMs(options.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS);
|
|
31
|
+
this.closeTimeoutMs = _durationMs(options.closeTimeoutMs, DEFAULT_CLOSE_TIMEOUT_MS);
|
|
32
|
+
this.workerWriteLockTimeoutMs = _durationMs(
|
|
33
|
+
options.workerWriteLockTimeoutMs ??
|
|
34
|
+
process.env.CTM_DB_OWNER_WORKER_WRITE_LOCK_TIMEOUT_MS,
|
|
35
|
+
DEFAULT_WORKER_WRITE_LOCK_TIMEOUT_MS
|
|
36
|
+
);
|
|
37
|
+
this.logger = options.logger || console;
|
|
38
|
+
this._degradeAfter = Math.max(1, _durationMs(
|
|
39
|
+
options.degradeAfterTimeouts ?? process.env.CTM_DB_OWNER_WORKER_DEGRADE_AFTER,
|
|
40
|
+
DEFAULT_DEGRADE_AFTER_TIMEOUTS
|
|
41
|
+
));
|
|
42
|
+
this._degradeCooldownMs = _durationMs(
|
|
43
|
+
options.degradeCooldownMs ?? process.env.CTM_DB_OWNER_WORKER_DEGRADE_COOLDOWN_MS,
|
|
44
|
+
DEFAULT_DEGRADE_COOLDOWN_MS
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
this._worker = null;
|
|
48
|
+
this._startPromise = null;
|
|
49
|
+
this._ready = false;
|
|
50
|
+
this._closed = false;
|
|
51
|
+
this._nextRequestId = 1;
|
|
52
|
+
this._pending = new Map();
|
|
53
|
+
// Circuit-breaker state. _consecutiveTimeouts resets on any in-time success.
|
|
54
|
+
// _degradedUntil is the timestamp through which best-effort ops are skipped.
|
|
55
|
+
this._consecutiveTimeouts = 0;
|
|
56
|
+
this._degradedUntil = 0;
|
|
57
|
+
this._status = {
|
|
58
|
+
ready: false,
|
|
59
|
+
pendingClientRequests: 0,
|
|
60
|
+
workerPending: 0,
|
|
61
|
+
workerActive: null,
|
|
62
|
+
completed: 0,
|
|
63
|
+
failed: 0,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
start() {
|
|
68
|
+
if (this._closed) return Promise.reject(new Error('DB owner worker client is closed'));
|
|
69
|
+
if (this._ready) return Promise.resolve(this);
|
|
70
|
+
if (this._startPromise) return this._startPromise;
|
|
71
|
+
|
|
72
|
+
this._startPromise = new Promise((resolve, reject) => {
|
|
73
|
+
const worker = new Worker(this.workerPath, {
|
|
74
|
+
workerData: {
|
|
75
|
+
dbPath: this.dbPath,
|
|
76
|
+
initDb: this.initDb,
|
|
77
|
+
},
|
|
78
|
+
env: {
|
|
79
|
+
...process.env,
|
|
80
|
+
CTM_DB_OWNER_WORKER: '1',
|
|
81
|
+
CTM_SQLITE_WRITE_LOCK_TIMEOUT_MS: String(this.workerWriteLockTimeoutMs),
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
this._worker = worker;
|
|
85
|
+
|
|
86
|
+
const failStart = (err) => {
|
|
87
|
+
if (this._ready) return;
|
|
88
|
+
this._startPromise = null;
|
|
89
|
+
this._worker = null;
|
|
90
|
+
try { worker.terminate(); } catch {}
|
|
91
|
+
reject(err instanceof Error ? err : new Error(String(err || 'DB owner worker failed to start')));
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
worker.on('message', (msg) => {
|
|
95
|
+
if (!msg || typeof msg !== 'object') return;
|
|
96
|
+
if (msg.type === 'ready') {
|
|
97
|
+
this._ready = true;
|
|
98
|
+
this._status.ready = true;
|
|
99
|
+
this._status.workerPending = 0;
|
|
100
|
+
this._status.workerActive = null;
|
|
101
|
+
resolve(this);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (msg.type === 'status') {
|
|
105
|
+
this._status = {
|
|
106
|
+
...this._status,
|
|
107
|
+
...msg.status,
|
|
108
|
+
ready: this._ready,
|
|
109
|
+
pendingClientRequests: this._pending.size,
|
|
110
|
+
};
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (msg.type === 'response') {
|
|
114
|
+
this._finishRequest(msg.requestId, msg.error, msg.result);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (msg.type === 'closed') {
|
|
118
|
+
this._ready = false;
|
|
119
|
+
this._closed = true;
|
|
120
|
+
this._status.ready = false;
|
|
121
|
+
this._rejectAllPending(new Error('DB owner worker closed'));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (msg.type === 'fatal') {
|
|
125
|
+
const err = new Error(msg.error || 'DB owner worker fatal error');
|
|
126
|
+
err.code = msg.code || 'CTM_DB_OWNER_WORKER_FATAL';
|
|
127
|
+
if (!this._ready) failStart(err);
|
|
128
|
+
this._rejectAllPending(err);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (msg.type === 'log' && this.logger && typeof this.logger[msg.level || 'log'] === 'function') {
|
|
132
|
+
this.logger[msg.level || 'log'](`[ctm-db-worker] ${msg.message || ''}`);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
worker.on('error', (err) => {
|
|
137
|
+
if (!this._ready) failStart(err);
|
|
138
|
+
this._rejectAllPending(err);
|
|
139
|
+
});
|
|
140
|
+
worker.on('exit', (code) => {
|
|
141
|
+
const wasReady = this._ready;
|
|
142
|
+
this._ready = false;
|
|
143
|
+
this._worker = null;
|
|
144
|
+
this._startPromise = null;
|
|
145
|
+
this._status.ready = false;
|
|
146
|
+
if (!this._closed && code !== 0) {
|
|
147
|
+
const err = new Error(`DB owner worker exited with code ${code}`);
|
|
148
|
+
err.code = 'CTM_DB_OWNER_WORKER_EXITED';
|
|
149
|
+
if (!wasReady) failStart(err);
|
|
150
|
+
this._rejectAllPending(err);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
return this._startPromise;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
isDegraded() {
|
|
159
|
+
return Date.now() < this._degradedUntil;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
_recordTimeout(op) {
|
|
163
|
+
this._consecutiveTimeouts += 1;
|
|
164
|
+
if (this._consecutiveTimeouts >= this._degradeAfter) {
|
|
165
|
+
const wasDegraded = this.isDegraded();
|
|
166
|
+
this._degradedUntil = Date.now() + this._degradeCooldownMs;
|
|
167
|
+
if (!wasDegraded && this.logger && typeof this.logger.warn === 'function') {
|
|
168
|
+
this.logger.warn(
|
|
169
|
+
`[ctm-db-worker] degraded after ${this._consecutiveTimeouts} consecutive timeouts ` +
|
|
170
|
+
`(last op: ${op}); best-effort ops will be skipped for ${this._degradeCooldownMs}ms`
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
_recordSuccess() {
|
|
177
|
+
if (this._consecutiveTimeouts === 0 && this._degradedUntil === 0) return;
|
|
178
|
+
const wasDegraded = this.isDegraded();
|
|
179
|
+
this._consecutiveTimeouts = 0;
|
|
180
|
+
this._degradedUntil = 0;
|
|
181
|
+
if (wasDegraded && this.logger && typeof this.logger.log === 'function') {
|
|
182
|
+
this.logger.log('[ctm-db-worker] recovered; resuming best-effort ops');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async request(op, payload = {}, options = {}) {
|
|
187
|
+
if (!op) throw new Error('DB owner worker request requires op');
|
|
188
|
+
// Circuit breaker: when the worker is degraded, fail best-effort ops fast
|
|
189
|
+
// WITHOUT enqueuing — a wedged worker must not keep accumulating stale
|
|
190
|
+
// best-effort work (e.g. scrollback) that re-holds the write lock later.
|
|
191
|
+
// After the cooldown one best-effort op is allowed through as a half-open probe.
|
|
192
|
+
if (options.bestEffort && this.isDegraded()) {
|
|
193
|
+
const err = new Error(`DB owner worker degraded; skipped best-effort op: ${op}`);
|
|
194
|
+
err.code = 'CTM_DB_OWNER_WORKER_DEGRADED';
|
|
195
|
+
throw err;
|
|
196
|
+
}
|
|
197
|
+
await this.start();
|
|
198
|
+
if (!this._worker) throw new Error('DB owner worker is not running');
|
|
199
|
+
const requestId = this._nextRequestId++;
|
|
200
|
+
const timeoutMs = _durationMs(options.timeoutMs, this.requestTimeoutMs);
|
|
201
|
+
return await new Promise((resolve, reject) => {
|
|
202
|
+
let timer = null;
|
|
203
|
+
if (timeoutMs > 0) {
|
|
204
|
+
timer = setTimeout(() => {
|
|
205
|
+
this._pending.delete(requestId);
|
|
206
|
+
this._recordTimeout(op);
|
|
207
|
+
reject(new Error(`DB owner worker request timed out: ${op}`));
|
|
208
|
+
}, timeoutMs);
|
|
209
|
+
if (typeof timer.unref === 'function') timer.unref();
|
|
210
|
+
}
|
|
211
|
+
this._pending.set(requestId, { op, resolve, reject, timer });
|
|
212
|
+
this._status.pendingClientRequests = this._pending.size;
|
|
213
|
+
try {
|
|
214
|
+
this._worker.postMessage({ type: 'request', requestId, op, payload });
|
|
215
|
+
} catch (err) {
|
|
216
|
+
this._finishRequest(requestId, err);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async drain(options = {}) {
|
|
222
|
+
return await this.request('drain', {}, options);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
getStatus() {
|
|
226
|
+
return {
|
|
227
|
+
...this._status,
|
|
228
|
+
ready: this._ready,
|
|
229
|
+
closed: this._closed,
|
|
230
|
+
pendingClientRequests: this._pending.size,
|
|
231
|
+
degraded: this.isDegraded(),
|
|
232
|
+
consecutiveTimeouts: this._consecutiveTimeouts,
|
|
233
|
+
dbPath: this.dbPath,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async close(options = {}) {
|
|
238
|
+
if (this._closed) return { ok: true, alreadyClosed: true };
|
|
239
|
+
const worker = this._worker;
|
|
240
|
+
this._closed = true;
|
|
241
|
+
if (!worker) {
|
|
242
|
+
this._rejectAllPending(new Error('DB owner worker closed'));
|
|
243
|
+
return { ok: true, alreadyClosed: true };
|
|
244
|
+
}
|
|
245
|
+
const timeoutMs = _durationMs(options.timeoutMs, this.closeTimeoutMs);
|
|
246
|
+
await new Promise((resolve) => {
|
|
247
|
+
let done = false;
|
|
248
|
+
const finish = () => {
|
|
249
|
+
if (done) return;
|
|
250
|
+
done = true;
|
|
251
|
+
resolve();
|
|
252
|
+
};
|
|
253
|
+
let timer = null;
|
|
254
|
+
if (timeoutMs > 0) {
|
|
255
|
+
timer = setTimeout(() => {
|
|
256
|
+
worker.terminate().finally(finish);
|
|
257
|
+
}, timeoutMs);
|
|
258
|
+
if (typeof timer.unref === 'function') timer.unref();
|
|
259
|
+
}
|
|
260
|
+
const onMessage = (msg) => {
|
|
261
|
+
if (msg?.type !== 'closed') return;
|
|
262
|
+
if (timer) clearTimeout(timer);
|
|
263
|
+
worker.off('message', onMessage);
|
|
264
|
+
finish();
|
|
265
|
+
};
|
|
266
|
+
worker.on('message', onMessage);
|
|
267
|
+
try { worker.postMessage({ type: 'close' }); }
|
|
268
|
+
catch {
|
|
269
|
+
if (timer) clearTimeout(timer);
|
|
270
|
+
worker.off('message', onMessage);
|
|
271
|
+
worker.terminate().finally(finish);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
this._ready = false;
|
|
275
|
+
this._worker = null;
|
|
276
|
+
this._rejectAllPending(new Error('DB owner worker closed'));
|
|
277
|
+
return { ok: true };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
_finishRequest(requestId, error, result) {
|
|
281
|
+
const pending = this._pending.get(requestId);
|
|
282
|
+
if (!pending) return;
|
|
283
|
+
this._pending.delete(requestId);
|
|
284
|
+
this._status.pendingClientRequests = this._pending.size;
|
|
285
|
+
if (pending.timer) clearTimeout(pending.timer);
|
|
286
|
+
if (error) {
|
|
287
|
+
const err = error instanceof Error ? error : new Error(String(error.message || error || 'DB owner worker request failed'));
|
|
288
|
+
if (error.code) err.code = error.code;
|
|
289
|
+
pending.reject(err);
|
|
290
|
+
} else {
|
|
291
|
+
// An in-time reply proves the worker is draining — clear the breaker.
|
|
292
|
+
this._recordSuccess();
|
|
293
|
+
pending.resolve(result);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
_rejectAllPending(err) {
|
|
298
|
+
const pending = Array.from(this._pending.values());
|
|
299
|
+
this._pending.clear();
|
|
300
|
+
this._status.pendingClientRequests = 0;
|
|
301
|
+
for (const req of pending) {
|
|
302
|
+
if (req.timer) clearTimeout(req.timer);
|
|
303
|
+
req.reject(err);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function createDbOwnerWorkerClient(options = {}) {
|
|
309
|
+
return new CtmDbOwnerWorkerClient(options);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
module.exports = {
|
|
313
|
+
CtmDbOwnerWorkerClient,
|
|
314
|
+
createDbOwnerWorkerClient,
|
|
315
|
+
};
|