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,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
function _isCodexPath(fp) {
|
|
7
|
+
return String(fp || '').includes(`${path.sep}.codex${path.sep}sessions${path.sep}`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Lossless hydration for the row-store read path.
|
|
11
|
+
//
|
|
12
|
+
// transcript_events rows store a LIGHTWEIGHT, truncated, text-only projection of each
|
|
13
|
+
// message (good for search + fast pagination) plus a byte offset (jsonl_path, byte_start,
|
|
14
|
+
// byte_end) into the source JSONL. To render a session WITHOUT losing content (tool calls,
|
|
15
|
+
// tool results, images, >50KB messages), we use the rows only to LOCATE the page's bytes,
|
|
16
|
+
// then read that bounded span from the JSONL and parse it with the SAME parser the legacy
|
|
17
|
+
// blob/JSONL read path uses (_parseJsonlIntoMessages) — so the hydrated messages are
|
|
18
|
+
// byte-identical to what the blob path renders. The rows are an index; the JSONL stays the
|
|
19
|
+
// source of truth. The read is bounded to the page's span (not the whole multi-GB file), so
|
|
20
|
+
// there is no freeze.
|
|
21
|
+
|
|
22
|
+
function readByteRange(filePath, start, length) {
|
|
23
|
+
const len = Math.max(0, Number(length) || 0);
|
|
24
|
+
if (!filePath || len === 0) return '';
|
|
25
|
+
const fd = fs.openSync(filePath, 'r');
|
|
26
|
+
try {
|
|
27
|
+
const buf = Buffer.alloc(len);
|
|
28
|
+
const n = fs.readSync(fd, buf, 0, len, Math.max(0, Number(start) || 0));
|
|
29
|
+
return buf.subarray(0, n).toString('utf8');
|
|
30
|
+
} finally {
|
|
31
|
+
try { fs.closeSync(fd); } catch { /* ignore */ }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// rows: page rows with { jsonl_path, byte_start, byte_end }.
|
|
36
|
+
// lightweightFallback: the row-text messages to serve if NOTHING can be hydrated
|
|
37
|
+
// (every source file moved/truncated) — so a missing file degrades to text, never throws.
|
|
38
|
+
// Returns FULL-fidelity messages for the page, chronologically sorted.
|
|
39
|
+
function hydratePageMessages(rows, lightweightFallback = []) {
|
|
40
|
+
let parser;
|
|
41
|
+
try { parser = require('./jsonl-conversation-parser'); } catch { return lightweightFallback; }
|
|
42
|
+
const claudeParse = parser._parseJsonlIntoMessages;
|
|
43
|
+
if (typeof claudeParse !== 'function') return lightweightFallback;
|
|
44
|
+
// The Codex content parser lives in session-history (jsonl-conversation-parser imports but
|
|
45
|
+
// does NOT re-export it). Without it, Codex content parses as 0/garbage.
|
|
46
|
+
let codexParse = null;
|
|
47
|
+
try {
|
|
48
|
+
const sh = require('./session-history');
|
|
49
|
+
if (typeof sh.parseCodexJsonlIntoMessages === 'function') codexParse = sh.parseCodexJsonlIntoMessages;
|
|
50
|
+
} catch { /* optional */ }
|
|
51
|
+
|
|
52
|
+
const list = Array.isArray(rows) ? rows : [];
|
|
53
|
+
if (list.length === 0) return lightweightFallback;
|
|
54
|
+
const liteOf = (r) => ({ role: r && r.role, text: (r && (r.text != null ? r.text : r.content)) || '', timestamp: (r && r.timestamp) || '' });
|
|
55
|
+
|
|
56
|
+
// Group the page's rows per source file and decide PER FILE how to hydrate:
|
|
57
|
+
// - Contiguous span (Claude: timestamps monotonic with byte → the page's rows sit in a
|
|
58
|
+
// small byte range). Reading that whole span and parsing it captures the tool-use /
|
|
59
|
+
// tool-result lines BETWEEN the message rows — which the transcript rows omit but the
|
|
60
|
+
// blob/JSONL render shows. This is what makes Claude render-identical to the blob path.
|
|
61
|
+
// - Row-by-row (Codex: timestamps are NOT monotonic with byte, so the page's rows scatter
|
|
62
|
+
// across the whole multi-GB file; a span read would cover ~the entire file = wrong content
|
|
63
|
+
// + a near-freeze). Reading each row's own line stays bounded and exact.
|
|
64
|
+
// The span-size threshold distinguishes the two automatically from the actual byte layout.
|
|
65
|
+
const MAX_SPAN_BYTES = 16 * 1024 * 1024;
|
|
66
|
+
const byFile = new Map();
|
|
67
|
+
for (const r of list) {
|
|
68
|
+
const fp = r && r.jsonl_path;
|
|
69
|
+
if (!fp || !(Number(r.byte_end) > Number(r.byte_start))) { byFile.set('__lite__:' + (byFile.size), { lite: liteOf(r) }); continue; }
|
|
70
|
+
const g = byFile.get(fp) || { fp, rows: [], min: Infinity, max: 0 };
|
|
71
|
+
g.rows.push(r); g.min = Math.min(g.min, Number(r.byte_start)); g.max = Math.max(g.max, Number(r.byte_end));
|
|
72
|
+
byFile.set(fp, g);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const out = [];
|
|
76
|
+
let hydratedAny = false;
|
|
77
|
+
const parseInto = (content, fp, sink) => {
|
|
78
|
+
if (_isCodexPath(fp) && typeof codexParse === 'function') codexParse(content, sink, {});
|
|
79
|
+
else claudeParse(content, sink, { sourceFile: fp });
|
|
80
|
+
};
|
|
81
|
+
for (const [, g] of byFile) {
|
|
82
|
+
if (g.lite) { out.push(g.lite); continue; }
|
|
83
|
+
const spanBytes = g.max - g.min;
|
|
84
|
+
// Span-read only for Claude/generic (rows contiguous in byte; captures interleaved tool
|
|
85
|
+
// lines). Codex ALWAYS goes row-by-row: its rows already exclude tool/event payloads, and
|
|
86
|
+
// its timestamps aren't byte-monotonic so even a small span can mis-span. Provider, not
|
|
87
|
+
// span size, is the right discriminator (small-span Codex regressed under a size-only rule).
|
|
88
|
+
if (!_isCodexPath(g.fp) && spanBytes > 0 && spanBytes <= MAX_SPAN_BYTES) {
|
|
89
|
+
let content = '';
|
|
90
|
+
try { content = readByteRange(g.fp, g.min, spanBytes); } catch { content = ''; }
|
|
91
|
+
const parsed = [];
|
|
92
|
+
if (content) { try { parseInto(content, g.fp, parsed); } catch { /* */ } }
|
|
93
|
+
if (parsed.length) { for (const m of parsed) out.push(m); hydratedAny = true; continue; }
|
|
94
|
+
// fall through to row-by-row if the span produced nothing
|
|
95
|
+
}
|
|
96
|
+
for (const r of g.rows) {
|
|
97
|
+
let content = '';
|
|
98
|
+
try { content = readByteRange(g.fp, Number(r.byte_start), Number(r.byte_end) - Number(r.byte_start)); } catch { content = ''; }
|
|
99
|
+
const parsed = [];
|
|
100
|
+
if (content) { try { parseInto(content, g.fp, parsed); } catch { /* */ } }
|
|
101
|
+
if (parsed.length) { for (const m of parsed) out.push(m); hydratedAny = true; }
|
|
102
|
+
else out.push(liteOf(r));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (!hydratedAny) return lightweightFallback;
|
|
106
|
+
out.forEach(m => { if (m) { delete m._sourceFile; delete m._sourceLine; delete m._entrySessionId; } });
|
|
107
|
+
// Order chronologically to match the blob path's sortTimelineMessagesInPlace.
|
|
108
|
+
out.sort((a, b) => String(a.timestamp || '').localeCompare(String(b.timestamp || '')));
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = { hydratePageMessages, readByteRange };
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Main-thread DB census + budget guard.
|
|
4
|
+
//
|
|
5
|
+
// THE PROBLEM IT SOLVES: CTM's freeze is never really "addApprovalObservation" or
|
|
6
|
+
// "backfillRewrite" — those are just WHICH of the dozens of synchronous main-thread DB
|
|
7
|
+
// callers happened to hit cold Dropbox pages first this boot. The existing
|
|
8
|
+
// [perf-lag]/[freeze-probe] diagnostics surface the single worst block, so we fix one
|
|
9
|
+
// driver, the next surfaces, forever (whack-a-mole). This module turns the hunt into a
|
|
10
|
+
// CENSUS: instrument the main-thread DB handle so a single cold boot yields the COMPLETE
|
|
11
|
+
// ranked list of every main-thread DB op (by cumulative + max cost, with a stack for the
|
|
12
|
+
// slow ones) — and a definition of done: zero UNBOUNDED main-thread ops on the cold path.
|
|
13
|
+
//
|
|
14
|
+
// THE INVARIANT IT ENFORCES: "no unbounded synchronous DB op on the main thread." A
|
|
15
|
+
// single-row indexed .get() is fine even cold (one page); a full scan, a SELECT * on a
|
|
16
|
+
// blob column, or a multi-row write freezes the loop. When an op exceeds the budget we
|
|
17
|
+
// log `[db-budget]` with the SQL + stack so a NEW violation shows up the moment it's
|
|
18
|
+
// written, not three restarts later.
|
|
19
|
+
//
|
|
20
|
+
// SAFETY: this is debug instrumentation, OFF by default. When disabled, maybeInstrument()
|
|
21
|
+
// returns the raw better-sqlite3 handle untouched — zero overhead, zero behavior change.
|
|
22
|
+
// HARD RULE: it adds per-DB-call overhead, so it must NEVER run on the primary (doing so
|
|
23
|
+
// caused a real production slowdown). It only arms on a dev/staging instance (which sets
|
|
24
|
+
// DEV_CTM_PORT) with CTM_DB_CENSUS=1. There is no primary-arming path.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
// Capture a stack for an op only when it is at least this slow (ms) — keeps per-call
|
|
28
|
+
// overhead negligible for the thousands of fast ops while still attributing every freeze.
|
|
29
|
+
const STACK_MS = clampInt(process.env.CTM_DB_CENSUS_STACK_MS, 25, 1, 60000);
|
|
30
|
+
// Emit a `[db-budget]` warning when a single main-thread op exceeds this (ms). This is the
|
|
31
|
+
// invariant tripwire — an unbounded op (scan / blob / big write) on the loop.
|
|
32
|
+
const BUDGET_MS = clampInt(process.env.CTM_DB_CENSUS_BUDGET_MS, 100, 1, 600000);
|
|
33
|
+
// Cap distinct SQL keys retained, so a pathological dynamic-SQL generator can't grow the
|
|
34
|
+
// census map without bound. The hottest keys (by sumMs) are always kept.
|
|
35
|
+
const MAX_KEYS = clampInt(process.env.CTM_DB_CENSUS_MAX_KEYS, 2000, 16, 100000);
|
|
36
|
+
|
|
37
|
+
function clampInt(raw, dflt, lo, hi) {
|
|
38
|
+
const n = Number(raw);
|
|
39
|
+
if (!Number.isFinite(n)) return dflt;
|
|
40
|
+
return Math.max(lo, Math.min(hi, Math.trunc(n)));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let _enabled = false;
|
|
44
|
+
let _armedReason = '';
|
|
45
|
+
const _census = new Map(); // sqlKey → stats
|
|
46
|
+
let _startedAt = 0;
|
|
47
|
+
let _budgetWarnings = 0;
|
|
48
|
+
|
|
49
|
+
// Decide whether to arm. HARD RULE: this census wraps the live DB handle and adds per-call
|
|
50
|
+
// overhead — it must NEVER run on the primary (it caused a real production slowdown there).
|
|
51
|
+
// It only arms on a dev/staging instance, which sets DEV_CTM_PORT. There is deliberately no
|
|
52
|
+
// primary-arming path (no sentinel) — staging only.
|
|
53
|
+
function _shouldArm() {
|
|
54
|
+
if (!process.env.DEV_CTM_PORT) return ''; // primary: never arm, full stop
|
|
55
|
+
if (process.env.CTM_DB_CENSUS === '1') return 'env';
|
|
56
|
+
return '';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isEnabled() { return _enabled; }
|
|
60
|
+
function armedReason() { return _armedReason; }
|
|
61
|
+
|
|
62
|
+
function _shortSql(sql) {
|
|
63
|
+
const s = String(sql || '').replace(/\s+/g, ' ').trim();
|
|
64
|
+
return s.length > 200 ? s.slice(0, 200) + '…' : s;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// A trimmed stack: drop this module's frames + the node internals, keep the CTM call site.
|
|
68
|
+
function _captureStack() {
|
|
69
|
+
const raw = new Error().stack || '';
|
|
70
|
+
return raw
|
|
71
|
+
.split('\n')
|
|
72
|
+
.slice(1)
|
|
73
|
+
.filter((l) => !l.includes('main-db-census.js') && !l.includes('node:internal'))
|
|
74
|
+
.slice(0, 6)
|
|
75
|
+
.map((l) => l.trim())
|
|
76
|
+
.join(' <- ');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function _record(sqlKey, op, ms, rows) {
|
|
80
|
+
let st = _census.get(sqlKey);
|
|
81
|
+
if (!st) {
|
|
82
|
+
if (_census.size >= MAX_KEYS) return; // bounded; hottest keys already retained
|
|
83
|
+
st = { sql: _shortSql(sqlKey), op, count: 0, sumMs: 0, maxMs: 0, maxRows: 0, slowStack: '', slowMs: 0 };
|
|
84
|
+
_census.set(sqlKey, st);
|
|
85
|
+
}
|
|
86
|
+
st.count += 1;
|
|
87
|
+
st.sumMs += ms;
|
|
88
|
+
if (ms > st.maxMs) st.maxMs = ms;
|
|
89
|
+
if (rows > st.maxRows) st.maxRows = rows;
|
|
90
|
+
if (ms >= STACK_MS && ms > st.slowMs) {
|
|
91
|
+
st.slowMs = ms;
|
|
92
|
+
st.slowStack = _captureStack();
|
|
93
|
+
}
|
|
94
|
+
if (ms >= BUDGET_MS) {
|
|
95
|
+
_budgetWarnings += 1;
|
|
96
|
+
// The invariant tripwire. Logged (not thrown) in prod so it can never break a request;
|
|
97
|
+
// a dev harness can choose to throw on these.
|
|
98
|
+
console.warn(`[db-budget] main-thread ${op} took ${Math.round(ms)}ms rows=${rows} sql="${st.sql}"`
|
|
99
|
+
+ (st.slowStack ? `\n ${st.slowStack}` : ''));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Wrap a better-sqlite3 Statement with timed get/all/run/iterate. Toggle/chaining methods
|
|
104
|
+
// (pluck/expand/raw/bind/safeIntegers) return `this` in better-sqlite3, so our versions
|
|
105
|
+
// return the WRAPPER to keep the proxy across chains (e.g. `.pluck().get()` stays timed).
|
|
106
|
+
function _wrapStatement(stmt) {
|
|
107
|
+
const sqlKey = stmt.source || '(unknown sql)';
|
|
108
|
+
const timed = (op) => function (...args) {
|
|
109
|
+
const t0 = process.hrtime.bigint();
|
|
110
|
+
const out = stmt[op](...args);
|
|
111
|
+
const ms = Number(process.hrtime.bigint() - t0) / 1e6;
|
|
112
|
+
let rows = 0;
|
|
113
|
+
if (op === 'all' && Array.isArray(out)) rows = out.length;
|
|
114
|
+
else if (op === 'get') rows = out ? 1 : 0;
|
|
115
|
+
else if (op === 'run' && out && typeof out.changes === 'number') rows = out.changes;
|
|
116
|
+
_record(sqlKey, op, ms, rows);
|
|
117
|
+
return out;
|
|
118
|
+
};
|
|
119
|
+
const wrapper = {
|
|
120
|
+
get: timed('get'),
|
|
121
|
+
all: timed('all'),
|
|
122
|
+
run: timed('run'),
|
|
123
|
+
iterate: timed('iterate'),
|
|
124
|
+
};
|
|
125
|
+
// Chaining toggles → delegate, but return the wrapper so timing survives the chain.
|
|
126
|
+
for (const m of ['pluck', 'expand', 'raw', 'bind', 'safeIntegers']) {
|
|
127
|
+
if (typeof stmt[m] === 'function') {
|
|
128
|
+
wrapper[m] = function (...args) { stmt[m](...args); return wrapper; };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Pass-through for metadata methods/props that callers read.
|
|
132
|
+
wrapper.columns = function (...args) { return stmt.columns(...args); };
|
|
133
|
+
Object.defineProperties(wrapper, {
|
|
134
|
+
source: { get: () => stmt.source },
|
|
135
|
+
reader: { get: () => stmt.reader },
|
|
136
|
+
readonly: { get: () => stmt.readonly },
|
|
137
|
+
busy: { get: () => stmt.busy },
|
|
138
|
+
database: { get: () => stmt.database },
|
|
139
|
+
_rawStatement: { value: stmt },
|
|
140
|
+
});
|
|
141
|
+
return wrapper;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Wrap the connection so .prepare() returns wrapped statements and .exec/.pragma are timed.
|
|
145
|
+
// Everything else delegates to the raw handle unchanged (transaction, backup, pragma config,
|
|
146
|
+
// close, etc.), so behavior is identical — only the timed paths are observed.
|
|
147
|
+
function _wrapConnection(rawDb) {
|
|
148
|
+
return new Proxy(rawDb, {
|
|
149
|
+
get(target, prop, receiver) {
|
|
150
|
+
if (prop === 'prepare') {
|
|
151
|
+
return function (sql) {
|
|
152
|
+
const stmt = target.prepare(sql);
|
|
153
|
+
try { return _wrapStatement(stmt); } catch { return stmt; }
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (prop === 'exec') {
|
|
157
|
+
return function (sql) {
|
|
158
|
+
const t0 = process.hrtime.bigint();
|
|
159
|
+
const out = target.exec(sql);
|
|
160
|
+
const ms = Number(process.hrtime.bigint() - t0) / 1e6;
|
|
161
|
+
_record(`exec: ${_shortSql(sql)}`, 'exec', ms, 0);
|
|
162
|
+
return out;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
if (prop === 'pragma') {
|
|
166
|
+
return function (source, options) {
|
|
167
|
+
const t0 = process.hrtime.bigint();
|
|
168
|
+
const out = target.pragma(source, options);
|
|
169
|
+
const ms = Number(process.hrtime.bigint() - t0) / 1e6;
|
|
170
|
+
_record(`pragma: ${_shortSql(source)}`, 'pragma', ms, 0);
|
|
171
|
+
return out;
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const val = Reflect.get(target, prop, receiver);
|
|
175
|
+
return typeof val === 'function' ? val.bind(target) : val;
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Wrap the handle IF armed; otherwise return it untouched. Called once per initDb/connectDb
|
|
181
|
+
// right after the connection is opened, BEFORE the restore storm runs.
|
|
182
|
+
function maybeInstrument(rawDb) {
|
|
183
|
+
if (!rawDb) return rawDb;
|
|
184
|
+
if (!_enabled) {
|
|
185
|
+
const reason = _shouldArm();
|
|
186
|
+
if (!reason) return rawDb; // default path: raw handle, zero overhead
|
|
187
|
+
_enabled = true;
|
|
188
|
+
_armedReason = reason;
|
|
189
|
+
_startedAt = Date.now();
|
|
190
|
+
console.warn(`[db-census] ARMED (${reason}) — instrumenting main-thread DB handle; `
|
|
191
|
+
+ `budget=${BUDGET_MS}ms stackThreshold=${STACK_MS}ms. GET /api/diagnostics/db-census to read.`);
|
|
192
|
+
}
|
|
193
|
+
try { return _wrapConnection(rawDb); } catch { return rawDb; }
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Ranked snapshot (by cumulative main-thread ms — the cold-boot cost of each query).
|
|
197
|
+
function getCensus({ limit = 100 } = {}) {
|
|
198
|
+
const rows = [..._census.values()]
|
|
199
|
+
.map((s) => ({ ...s, avgMs: s.count ? +(s.sumMs / s.count).toFixed(2) : 0,
|
|
200
|
+
sumMs: +s.sumMs.toFixed(1), maxMs: +s.maxMs.toFixed(1) }))
|
|
201
|
+
.sort((a, b) => b.sumMs - a.sumMs);
|
|
202
|
+
return {
|
|
203
|
+
enabled: _enabled,
|
|
204
|
+
armedReason: _armedReason,
|
|
205
|
+
sinceMs: _startedAt ? Date.now() - _startedAt : 0,
|
|
206
|
+
budgetMs: BUDGET_MS,
|
|
207
|
+
stackThresholdMs: STACK_MS,
|
|
208
|
+
budgetWarnings: _budgetWarnings,
|
|
209
|
+
distinctSql: _census.size,
|
|
210
|
+
top: rows.slice(0, Math.max(1, limit)),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function reset() { _census.clear(); _budgetWarnings = 0; _startedAt = Date.now(); }
|
|
215
|
+
|
|
216
|
+
module.exports = { maybeInstrument, getCensus, reset, isEnabled, armedReason };
|
|
@@ -17,6 +17,15 @@
|
|
|
17
17
|
const MIN_PAGE_SIZE = 1;
|
|
18
18
|
const MAX_PAGE_SIZE = 1000;
|
|
19
19
|
|
|
20
|
+
function _pageSize(limit) {
|
|
21
|
+
const rawLimit = Number.isFinite(limit) ? Math.floor(limit) : 0;
|
|
22
|
+
return Math.max(MIN_PAGE_SIZE, Math.min(MAX_PAGE_SIZE, rawLimit || MIN_PAGE_SIZE));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function _loadedOffset(offset) {
|
|
26
|
+
return Math.max(0, Number.isFinite(offset) ? Math.floor(offset) : 0);
|
|
27
|
+
}
|
|
28
|
+
|
|
20
29
|
/**
|
|
21
30
|
* @param {Array} all — chronologically sorted messages
|
|
22
31
|
* @param {number} offset — how many most-recent messages are already loaded
|
|
@@ -29,9 +38,8 @@ function paginateMessages(all, offset, limit) {
|
|
|
29
38
|
if (total === 0) {
|
|
30
39
|
return { messages: [], total: 0, has_more: false, next_offset: 0 };
|
|
31
40
|
}
|
|
32
|
-
const alreadyLoaded =
|
|
33
|
-
const
|
|
34
|
-
const pageSize = Math.max(MIN_PAGE_SIZE, Math.min(MAX_PAGE_SIZE, rawLimit || MIN_PAGE_SIZE));
|
|
41
|
+
const alreadyLoaded = _loadedOffset(offset);
|
|
42
|
+
const pageSize = _pageSize(limit);
|
|
35
43
|
const remaining = Math.max(0, total - alreadyLoaded);
|
|
36
44
|
const take = Math.min(pageSize, remaining);
|
|
37
45
|
const endIdx = total - alreadyLoaded; // exclusive
|
|
@@ -44,4 +52,98 @@ function paginateMessages(all, offset, limit) {
|
|
|
44
52
|
};
|
|
45
53
|
}
|
|
46
54
|
|
|
47
|
-
|
|
55
|
+
function defaultIsTurnStart(message) {
|
|
56
|
+
return !!message
|
|
57
|
+
&& String(message.role || '').trim() === 'user'
|
|
58
|
+
&& String(message.text || message.content || message.message || '').trim().length > 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function splitMessagesIntoTurns(all, options = {}) {
|
|
62
|
+
const arr = Array.isArray(all) ? all : [];
|
|
63
|
+
const isTurnStart = typeof options.isTurnStart === 'function'
|
|
64
|
+
? options.isTurnStart
|
|
65
|
+
: defaultIsTurnStart;
|
|
66
|
+
const setup = [];
|
|
67
|
+
const turns = [];
|
|
68
|
+
let current = null;
|
|
69
|
+
|
|
70
|
+
arr.forEach((message, index) => {
|
|
71
|
+
if (isTurnStart(message, index, arr)) {
|
|
72
|
+
current = {
|
|
73
|
+
type: 'turn',
|
|
74
|
+
start_index: index,
|
|
75
|
+
end_index: index,
|
|
76
|
+
messages: [message],
|
|
77
|
+
};
|
|
78
|
+
turns.push(current);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (current) {
|
|
82
|
+
current.messages.push(message);
|
|
83
|
+
current.end_index = index;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
setup.push(message);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
if (setup.length > 0) {
|
|
90
|
+
turns.unshift({
|
|
91
|
+
type: 'setup',
|
|
92
|
+
start_index: 0,
|
|
93
|
+
end_index: setup.length - 1,
|
|
94
|
+
messages: setup,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return turns;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Paginates by complete semantic turns instead of raw rows.
|
|
102
|
+
*
|
|
103
|
+
* Review/conversation UIs group raw provider rows after fetching. Raw-message
|
|
104
|
+
* pagination can begin in the middle of a long tool-heavy turn, which leaves
|
|
105
|
+
* the renderer without the owning user prompt and makes it collapse everything
|
|
106
|
+
* into a fake "setup" block. This helper keeps the same newest-first pagination
|
|
107
|
+
* shape as paginateMessages, but `offset` and `limit` count complete turns.
|
|
108
|
+
*/
|
|
109
|
+
function paginateMessageTurns(all, offset, limit, options = {}) {
|
|
110
|
+
const turns = splitMessagesIntoTurns(all, options);
|
|
111
|
+
const total = turns.length;
|
|
112
|
+
if (total === 0) {
|
|
113
|
+
return {
|
|
114
|
+
messages: [],
|
|
115
|
+
total: 0,
|
|
116
|
+
has_more: false,
|
|
117
|
+
next_offset: 0,
|
|
118
|
+
page_kind: 'turns',
|
|
119
|
+
turn_count: 0,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const alreadyLoaded = _loadedOffset(offset);
|
|
124
|
+
const pageSize = _pageSize(limit);
|
|
125
|
+
const remaining = Math.max(0, total - alreadyLoaded);
|
|
126
|
+
const take = Math.min(pageSize, remaining);
|
|
127
|
+
const endIdx = total - alreadyLoaded;
|
|
128
|
+
const startIdx = Math.max(0, endIdx - take);
|
|
129
|
+
const pageTurns = turns.slice(startIdx, endIdx);
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
messages: pageTurns.flatMap(turn => turn.messages),
|
|
133
|
+
total,
|
|
134
|
+
has_more: startIdx > 0,
|
|
135
|
+
next_offset: alreadyLoaded + take,
|
|
136
|
+
page_kind: 'turns',
|
|
137
|
+
turn_count: pageTurns.length,
|
|
138
|
+
first_turn_index: pageTurns.length ? startIdx : -1,
|
|
139
|
+
last_turn_index: pageTurns.length ? endIdx - 1 : -1,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module.exports = {
|
|
144
|
+
paginateMessages,
|
|
145
|
+
paginateMessageTurns,
|
|
146
|
+
splitMessagesIntoTurns,
|
|
147
|
+
MIN_PAGE_SIZE,
|
|
148
|
+
MAX_PAGE_SIZE,
|
|
149
|
+
};
|