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
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
parseLimit,
|
|
13
13
|
parseOffset,
|
|
14
14
|
readBody,
|
|
15
|
+
BODY_LIMIT_LARGE,
|
|
15
16
|
} = require('./http/api-utils');
|
|
16
17
|
const authFlows = require('./auth/flow-manager');
|
|
17
18
|
const {
|
|
@@ -20,7 +21,6 @@ const {
|
|
|
20
21
|
} = require('./auth/provider-flows');
|
|
21
22
|
|
|
22
23
|
const DATA_DIR = process.env.WALL_E_DATA_DIR || path.join(process.env.HOME, '.walle', 'data');
|
|
23
|
-
const BRAIN_DB_PATH = path.join(DATA_DIR, 'wall-e-brain.db');
|
|
24
24
|
const TELEMETRY_DB_PATH = path.join(DATA_DIR, 'telemetry.db');
|
|
25
25
|
const FEEDBACK_RATE_LIMIT_PER_MINUTE = 2;
|
|
26
26
|
const FEEDBACK_RATE_LIMIT_WINDOW_MS = 60 * 1000;
|
|
@@ -49,6 +49,8 @@ const TELEMETRY_DIAGNOSTIC_EVENTS = new Set([
|
|
|
49
49
|
'upgrade',
|
|
50
50
|
'upgrade_prompt',
|
|
51
51
|
'funnel',
|
|
52
|
+
'session_integrity_issue',
|
|
53
|
+
'session_integrity_issue_summary',
|
|
52
54
|
]);
|
|
53
55
|
const TELEMETRY_DIAGNOSTIC_PREFIXES = ['ctm_update_'];
|
|
54
56
|
const TELEMETRY_REDACTED_TEXT = '[redacted after retention]';
|
|
@@ -556,6 +558,11 @@ function telemetryCleanupCandidateStats(tdb, policy = telemetryCleanupPolicy(),
|
|
|
556
558
|
};
|
|
557
559
|
}
|
|
558
560
|
|
|
561
|
+
function telemetryCleanupCheckpointMode() {
|
|
562
|
+
const raw = String(process.env.WALLE_TELEMETRY_CLEANUP_CHECKPOINT_MODE || 'PASSIVE').toUpperCase();
|
|
563
|
+
return new Set(['PASSIVE', 'FULL', 'RESTART', 'TRUNCATE']).has(raw) ? raw : 'PASSIVE';
|
|
564
|
+
}
|
|
565
|
+
|
|
559
566
|
function telemetryAggregateArchivedEvents(tdb, since) {
|
|
560
567
|
return telemetrySafeCount(
|
|
561
568
|
tdb,
|
|
@@ -584,6 +591,103 @@ function telemetryEventsByTypeSince(tdb, since) {
|
|
|
584
591
|
`).all(since, String(since || '').slice(0, 10));
|
|
585
592
|
}
|
|
586
593
|
|
|
594
|
+
function telemetrySetIntersectionSize(left, right) {
|
|
595
|
+
let count = 0;
|
|
596
|
+
for (const value of left || []) {
|
|
597
|
+
if (right && right.has(value)) count += 1;
|
|
598
|
+
}
|
|
599
|
+
return count;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
function telemetrySetDifferenceSize(left, right) {
|
|
603
|
+
let count = 0;
|
|
604
|
+
for (const value of left || []) {
|
|
605
|
+
if (!right || !right.has(value)) count += 1;
|
|
606
|
+
}
|
|
607
|
+
return count;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function telemetryStableIdentityFromRow(row) {
|
|
611
|
+
return row && row.machine_bucket ? `m:${row.machine_bucket}` : `i:${row?.install_id || ''}`;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
function telemetryMapCountsToRows(map, countKey = 'install_count') {
|
|
615
|
+
return Array.from(map.entries())
|
|
616
|
+
.map(([key, value]) => ({ key, [countKey]: value.size || value }))
|
|
617
|
+
.sort((a, b) => b[countKey] - a[countKey] || String(a.key).localeCompare(String(b.key)));
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
function telemetryEmbeddingFeatureAdoption(tdb, since, activeInstalls) {
|
|
621
|
+
const rows = tdb.prepare(`
|
|
622
|
+
SELECT te.event, te.install_id, ti.machine_bucket, te.meta, te.received_at
|
|
623
|
+
FROM telemetry_events te
|
|
624
|
+
LEFT JOIN telemetry_installs ti ON ti.install_id = te.install_id
|
|
625
|
+
WHERE te.event IN ('embedding_status', 'embedding_provider_switch', 'embedding_usage')
|
|
626
|
+
AND te.received_at >= ?
|
|
627
|
+
ORDER BY te.received_at ASC, te.id ASC
|
|
628
|
+
`).all(since);
|
|
629
|
+
const latestStatusByIdentity = new Map();
|
|
630
|
+
const setupView = new Set();
|
|
631
|
+
const switchSuccess = new Set();
|
|
632
|
+
const switchFailed = new Set();
|
|
633
|
+
const usage = new Set();
|
|
634
|
+
const usageByOperation = new Map();
|
|
635
|
+
|
|
636
|
+
for (const row of rows) {
|
|
637
|
+
const identity = telemetryStableIdentityFromRow(row);
|
|
638
|
+
if (!identity || identity === 'i:') continue;
|
|
639
|
+
let meta = {};
|
|
640
|
+
try { meta = row.meta ? JSON.parse(row.meta) : {}; } catch {}
|
|
641
|
+
|
|
642
|
+
if (row.event === 'embedding_status') {
|
|
643
|
+
latestStatusByIdentity.set(identity, meta);
|
|
644
|
+
if (meta.reason === 'setup_view') setupView.add(identity);
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
if (row.event === 'embedding_provider_switch') {
|
|
648
|
+
if (meta.ok) switchSuccess.add(identity);
|
|
649
|
+
else switchFailed.add(identity);
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
if (row.event === 'embedding_usage') {
|
|
653
|
+
usage.add(identity);
|
|
654
|
+
const operation = String(meta.operation || 'unknown').slice(0, 80) || 'unknown';
|
|
655
|
+
if (!usageByOperation.has(operation)) usageByOperation.set(operation, new Set());
|
|
656
|
+
usageByOperation.get(operation).add(identity);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
const enabled = new Set();
|
|
661
|
+
const enabledByProvider = new Map();
|
|
662
|
+
const latestStateCounts = new Map();
|
|
663
|
+
for (const [identity, meta] of latestStatusByIdentity.entries()) {
|
|
664
|
+
const state = String(meta.state || 'unknown').slice(0, 80) || 'unknown';
|
|
665
|
+
latestStateCounts.set(state, (latestStateCounts.get(state) || 0) + 1);
|
|
666
|
+
if (meta.enabled || meta.state === 'ready') {
|
|
667
|
+
enabled.add(identity);
|
|
668
|
+
const provider = String(meta.provider || 'unknown').slice(0, 80) || 'unknown';
|
|
669
|
+
if (!enabledByProvider.has(provider)) enabledByProvider.set(provider, new Set());
|
|
670
|
+
enabledByProvider.get(provider).add(identity);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
const denominator = activeInstalls || 0;
|
|
675
|
+
const pct = (num) => denominator > 0 ? Math.round(num / denominator * 100) / 100 : null;
|
|
676
|
+
return {
|
|
677
|
+
reporting_installs: latestStatusByIdentity.size,
|
|
678
|
+
enabled_installs: enabled.size,
|
|
679
|
+
usage_installs: usage.size,
|
|
680
|
+
setup_view_installs: setupView.size,
|
|
681
|
+
switch_success_installs: switchSuccess.size,
|
|
682
|
+
switch_failed_installs: switchFailed.size,
|
|
683
|
+
enabled_pct_active: pct(enabled.size),
|
|
684
|
+
usage_pct_active: pct(usage.size),
|
|
685
|
+
latest_state: telemetryMapCountsToRows(latestStateCounts, 'install_count'),
|
|
686
|
+
enabled_by_provider: telemetryMapCountsToRows(enabledByProvider),
|
|
687
|
+
usage_by_operation: telemetryMapCountsToRows(usageByOperation),
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
|
|
587
691
|
function archiveAndDeleteTelemetryEvents(tdb, bucket, batchSize) {
|
|
588
692
|
const selectRows = tdb.prepare(`
|
|
589
693
|
SELECT id, date(received_at) as day, event, COALESCE(version, '') as version,
|
|
@@ -803,8 +907,9 @@ function runTelemetryCleanup(options = {}) {
|
|
|
803
907
|
|
|
804
908
|
let checkpoint = null;
|
|
805
909
|
try {
|
|
806
|
-
const
|
|
807
|
-
|
|
910
|
+
const mode = telemetryCleanupCheckpointMode();
|
|
911
|
+
const rows = tdb.pragma(`wal_checkpoint(${mode})`);
|
|
912
|
+
checkpoint = { ok: true, mode, rows };
|
|
808
913
|
} catch (e) {
|
|
809
914
|
checkpoint = { ok: false, error: e.message };
|
|
810
915
|
}
|
|
@@ -1064,18 +1169,16 @@ function buildSkillMd(body) {
|
|
|
1064
1169
|
return lines.join('\n');
|
|
1065
1170
|
}
|
|
1066
1171
|
|
|
1067
|
-
let
|
|
1172
|
+
let readDbOverride = null;
|
|
1068
1173
|
|
|
1069
1174
|
function getReadDb() {
|
|
1070
|
-
if (
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
}
|
|
1175
|
+
if (readDbOverride) return readDbOverride;
|
|
1176
|
+
if (!brain || !ensureBrainInit()) return null;
|
|
1177
|
+
try {
|
|
1178
|
+
return brain.getDb();
|
|
1179
|
+
} catch {
|
|
1180
|
+
return null;
|
|
1077
1181
|
}
|
|
1078
|
-
return readDb;
|
|
1079
1182
|
}
|
|
1080
1183
|
|
|
1081
1184
|
let brain = null;
|
|
@@ -1380,7 +1483,14 @@ function getQuestionsList(params) {
|
|
|
1380
1483
|
if (!db) return [];
|
|
1381
1484
|
|
|
1382
1485
|
const status = params.get('status') || 'pending';
|
|
1383
|
-
|
|
1486
|
+
// Paginate: this endpoint had no LIMIT, so it returned every pending question (15k+ on
|
|
1487
|
+
// a busy brain) as one unbounded blob. Default to a page of 100; callers can override
|
|
1488
|
+
// with ?limit= and page with ?offset=.
|
|
1489
|
+
const limit = parseLimit(params, 100);
|
|
1490
|
+
const offset = Math.max(0, parseInt(params.get('offset') || '0', 10) || 0);
|
|
1491
|
+
return db.prepare(
|
|
1492
|
+
'SELECT * FROM pending_questions WHERE status = ? ORDER BY created_at DESC LIMIT ? OFFSET ?'
|
|
1493
|
+
).all(status, limit, offset);
|
|
1384
1494
|
}
|
|
1385
1495
|
|
|
1386
1496
|
function getStats() {
|
|
@@ -1421,22 +1531,73 @@ function handleWalleApi(req, res, url) {
|
|
|
1421
1531
|
const schedulerHandled = handleSchedulerApi(req, res, url);
|
|
1422
1532
|
if (schedulerHandled !== false) return schedulerHandled;
|
|
1423
1533
|
|
|
1424
|
-
// GET /api/wall-e/health —
|
|
1534
|
+
// GET /api/wall-e/health — liveness check. Includes event-loop delay stats: if this
|
|
1535
|
+
// endpoint responds at all the loop is not currently wedged, and `event_loop.peak_ms` /
|
|
1536
|
+
// `last_warning` show whether it has stalled recently (a synchronous DB query starving
|
|
1537
|
+
// the loop). A blocked loop can't answer this, so a tight-timeout probe of it is a
|
|
1538
|
+
// truer readiness signal than "the process is running".
|
|
1425
1539
|
if (p === '/api/wall-e/health' && m === 'GET') {
|
|
1426
|
-
|
|
1540
|
+
let eventLoop = { enabled: false };
|
|
1541
|
+
try { eventLoop = require('./lib/event-loop-monitor').stats(); } catch {}
|
|
1542
|
+
return jsonResponse(res, { status: 'ok', uptime: process.uptime(), version: '0.1.0', event_loop: eventLoop }), true;
|
|
1427
1543
|
}
|
|
1428
1544
|
|
|
1429
1545
|
// GET /api/wall-e/alerts — service alerts (auth failures, skill disabled, update available)
|
|
1430
1546
|
if (p === '/api/wall-e/alerts' && m === 'GET') {
|
|
1431
1547
|
try {
|
|
1548
|
+
res.setHeader('Cache-Control', 'no-store, max-age=0');
|
|
1432
1549
|
const { getServiceAlerts } = require('./skills/skill-planner');
|
|
1550
|
+
const { buildServiceHealth } = require('./lib/service-health');
|
|
1433
1551
|
const alerts = getServiceAlerts({ includeVersionUpdate: true });
|
|
1434
|
-
|
|
1552
|
+
let activeProvider = process.env.WALLE_PROVIDER || '';
|
|
1553
|
+
let activeModel = process.env.WALLE_MODEL || '';
|
|
1554
|
+
try {
|
|
1555
|
+
activeProvider = brain?.getKv?.('walle_provider') || activeProvider;
|
|
1556
|
+
activeModel = brain?.getKv?.('walle_model') || activeModel;
|
|
1557
|
+
} catch {}
|
|
1558
|
+
const summary = buildServiceHealth(alerts, {
|
|
1559
|
+
activeProvider,
|
|
1560
|
+
activeModel,
|
|
1561
|
+
});
|
|
1562
|
+
return jsonResponse(res, { alerts, summary }), true;
|
|
1435
1563
|
} catch (e) {
|
|
1436
1564
|
return jsonResponse(res, { alerts: [], error: e.message }), true;
|
|
1437
1565
|
}
|
|
1438
1566
|
}
|
|
1439
1567
|
|
|
1568
|
+
// GET /api/wall-e/coding/boundaries?session_id=… — persisted snapshot
|
|
1569
|
+
// boundaries (newest first) for the rewind UI.
|
|
1570
|
+
if (p === '/api/wall-e/coding/boundaries' && m === 'GET') {
|
|
1571
|
+
try {
|
|
1572
|
+
const sessionId = String(url.searchParams.get('session_id') || '').slice(0, 200);
|
|
1573
|
+
if (!sessionId) return jsonResponse(res, { ok: false, error: 'session_id required' }, 400), true;
|
|
1574
|
+
const { listSessionBoundaries } = require('./coding/snapshot-service');
|
|
1575
|
+
return jsonResponse(res, { ok: true, boundaries: listSessionBoundaries(sessionId, { brain }) }), true;
|
|
1576
|
+
} catch (e) {
|
|
1577
|
+
return jsonResponse(res, { ok: false, error: e.message }, 500), true;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
// POST /api/wall-e/coding/rewind — restore the worktree to a snapshot
|
|
1582
|
+
// boundary. Restores tracked snapshot content; never deletes files the
|
|
1583
|
+
// snapshot system has not seen.
|
|
1584
|
+
if (p === '/api/wall-e/coding/rewind' && m === 'POST') {
|
|
1585
|
+
return readBody(req, { maxBytes: 16 * 1024 }).then(body => {
|
|
1586
|
+
try {
|
|
1587
|
+
const sessionId = String(body.session_id || body.sessionId || '').slice(0, 200);
|
|
1588
|
+
const boundaryId = String(body.boundary_id || body.boundaryId || '').slice(0, 200);
|
|
1589
|
+
if (!sessionId || !boundaryId) {
|
|
1590
|
+
return jsonResponse(res, { ok: false, error: 'session_id and boundary_id required' }, 400);
|
|
1591
|
+
}
|
|
1592
|
+
const { revertSessionBoundary } = require('./coding/snapshot-service');
|
|
1593
|
+
const result = revertSessionBoundary({ sessionId, boundaryId, brain });
|
|
1594
|
+
return jsonResponse(res, { ok: true, ...result });
|
|
1595
|
+
} catch (e) {
|
|
1596
|
+
return jsonResponse(res, { ok: false, error: e.message }, 400);
|
|
1597
|
+
}
|
|
1598
|
+
}), true;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1440
1601
|
// POST /api/wall-e/feedback/ingest — explicit CTM feedback handoff.
|
|
1441
1602
|
// This route stores curated feedback as memory/knowledge. It does not ingest
|
|
1442
1603
|
// screenshots or full transcripts unless CTM included consented previews.
|
|
@@ -1624,6 +1785,13 @@ function handleWalleApi(req, res, url) {
|
|
|
1624
1785
|
}
|
|
1625
1786
|
}
|
|
1626
1787
|
|
|
1788
|
+
// GET /api/wall-e/boot-profile — per-phase startup timing (instrumentation)
|
|
1789
|
+
if (p === '/api/wall-e/boot-profile' && m === 'GET') {
|
|
1790
|
+
let profile = null;
|
|
1791
|
+
try { profile = require('./lib/boot-profile').getProfile(); } catch (_) {}
|
|
1792
|
+
return jsonResponse(res, { profile }), true;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1627
1795
|
// GET /api/wall-e/scheduler — scheduler observability
|
|
1628
1796
|
if (p === '/api/wall-e/scheduler' && m === 'GET') {
|
|
1629
1797
|
const { Scheduler } = require('./lib/scheduler');
|
|
@@ -1782,7 +1950,10 @@ function handleWalleApi(req, res, url) {
|
|
|
1782
1950
|
if (p === '/api/wall-e/gws/accounts' && m === 'GET') {
|
|
1783
1951
|
(async () => {
|
|
1784
1952
|
try {
|
|
1953
|
+
res.setHeader('Cache-Control', 'no-store, max-age=0');
|
|
1785
1954
|
const gwsSetup = require('./skills/_bundled/gws-workspace/setup');
|
|
1955
|
+
let skillPlanner = null;
|
|
1956
|
+
try { skillPlanner = require('./skills/skill-planner'); } catch {}
|
|
1786
1957
|
const accounts = gwsSetup.listAccounts();
|
|
1787
1958
|
const gwsProfiles = typeof gwsSetup.getGwsProfiles === 'function' ? gwsSetup.getGwsProfiles() : [];
|
|
1788
1959
|
const hasClientSecret = gwsProfiles.length
|
|
@@ -1849,6 +2020,15 @@ function handleWalleApi(req, res, url) {
|
|
|
1849
2020
|
detail.reauthRequired = false;
|
|
1850
2021
|
detail.authIssue = null;
|
|
1851
2022
|
detail.syncMode = 'auto';
|
|
2023
|
+
if (skillPlanner && typeof skillPlanner.clearResolvedGoogleWorkspaceHealthAlerts === 'function') {
|
|
2024
|
+
try {
|
|
2025
|
+
skillPlanner.clearResolvedGoogleWorkspaceHealthAlerts({
|
|
2026
|
+
email: acct.email,
|
|
2027
|
+
profileId: acct.profileId || null,
|
|
2028
|
+
authenticated: true,
|
|
2029
|
+
});
|
|
2030
|
+
} catch {}
|
|
2031
|
+
}
|
|
1852
2032
|
const apiResults = await gwsSetup.testApis(creds.access_token);
|
|
1853
2033
|
for (const r of apiResults) {
|
|
1854
2034
|
detail.apis[r.name.toLowerCase()] = r.enabled;
|
|
@@ -2323,9 +2503,15 @@ function handleWalleApi(req, res, url) {
|
|
|
2323
2503
|
if (!hasApiKey && (walleProvider === 'ollama' || walleProvider === 'mlx')) hasApiKey = true;
|
|
2324
2504
|
|
|
2325
2505
|
let serviceAlerts = [];
|
|
2506
|
+
let serviceAlertSummary = null;
|
|
2326
2507
|
try {
|
|
2327
2508
|
const { getServiceAlerts } = require('./skills/skill-planner');
|
|
2509
|
+
const { buildServiceHealth } = require('./lib/service-health');
|
|
2328
2510
|
serviceAlerts = getServiceAlerts({ includeVersionUpdate: true });
|
|
2511
|
+
serviceAlertSummary = buildServiceHealth(serviceAlerts, {
|
|
2512
|
+
activeProvider: walleProvider,
|
|
2513
|
+
activeModel: walleModel,
|
|
2514
|
+
});
|
|
2329
2515
|
} catch {}
|
|
2330
2516
|
|
|
2331
2517
|
let slackSocketMode = null;
|
|
@@ -2350,6 +2536,7 @@ function handleWalleApi(req, res, url) {
|
|
|
2350
2536
|
walle_model: walleModel,
|
|
2351
2537
|
has_api_key: hasApiKey,
|
|
2352
2538
|
service_alerts: serviceAlerts,
|
|
2539
|
+
service_alert_summary: serviceAlertSummary,
|
|
2353
2540
|
slack_socket_mode: slackSocketMode,
|
|
2354
2541
|
}
|
|
2355
2542
|
}), true;
|
|
@@ -2360,6 +2547,7 @@ function handleWalleApi(req, res, url) {
|
|
|
2360
2547
|
try {
|
|
2361
2548
|
const embeddingsModule = require('./embeddings');
|
|
2362
2549
|
if (!brain || !ensureBrainInit()) return jsonResponse(res, { providers: [], stats: {}, totalMemories: 0, error: 'Brain module not available' }, 503), true;
|
|
2550
|
+
const auto = embeddingsModule.autoSelectProvider?.('setup_view') || null;
|
|
2363
2551
|
const providers = embeddingsModule.getProviderStatus();
|
|
2364
2552
|
const stats = embeddingsModule.getAllEmbeddingStats();
|
|
2365
2553
|
const totalMemories = brain.getDb().prepare("SELECT count(*) as c FROM memories WHERE content IS NOT NULL AND length(content) > 10").get().c;
|
|
@@ -2394,13 +2582,28 @@ function handleWalleApi(req, res, url) {
|
|
|
2394
2582
|
etaMinutes: recentRate > 0 ? Math.ceil(remaining / recentRate) : null,
|
|
2395
2583
|
};
|
|
2396
2584
|
}
|
|
2397
|
-
|
|
2585
|
+
const setup = embeddingsModule.getEmbeddingSetupState?.() || {};
|
|
2586
|
+
jsonResponse(res, { providers, stats, totalMemories, backfillProgress, setup, auto });
|
|
2587
|
+
try { embeddingsModule.trackEmbeddingSetupView?.(); } catch {}
|
|
2398
2588
|
} catch (e) {
|
|
2399
2589
|
jsonResponse(res, { providers: [], stats: {}, totalMemories: 0, error: e.message });
|
|
2400
2590
|
}
|
|
2401
2591
|
return true;
|
|
2402
2592
|
}
|
|
2403
2593
|
|
|
2594
|
+
if (p === '/api/wall-e/setup/embeddings/policy' && m === 'POST') {
|
|
2595
|
+
readBody(req).then((body) => {
|
|
2596
|
+
try {
|
|
2597
|
+
const embeddingsModule = require('./embeddings');
|
|
2598
|
+
const result = embeddingsModule.setEmbeddingPolicy(body.policy);
|
|
2599
|
+
jsonResponse(res, result, result.ok ? 200 : 400);
|
|
2600
|
+
} catch (e) {
|
|
2601
|
+
jsonResponse(res, { ok: false, message: e.message }, 400);
|
|
2602
|
+
}
|
|
2603
|
+
}).catch((e) => jsonResponse(res, { ok: false, message: e.message }, 400));
|
|
2604
|
+
return true;
|
|
2605
|
+
}
|
|
2606
|
+
|
|
2404
2607
|
if (p === '/api/wall-e/setup/embeddings/switch' && m === 'POST') {
|
|
2405
2608
|
readBody(req).then((body) => {
|
|
2406
2609
|
try {
|
|
@@ -2496,13 +2699,17 @@ function handleWalleApi(req, res, url) {
|
|
|
2496
2699
|
const type = sanitizeSetupProviderType(body.type);
|
|
2497
2700
|
if (!type) return jsonResponse(res, { ok: false, error: 'Invalid provider type' }, 400);
|
|
2498
2701
|
const model = sanitizeSetupModel(body.model);
|
|
2702
|
+
const hasBaseUrl = Object.prototype.hasOwnProperty.call(body, 'base_url')
|
|
2703
|
+
|| Object.prototype.hasOwnProperty.call(body, 'baseUrl');
|
|
2704
|
+
const hasCustomHeaders = Object.prototype.hasOwnProperty.call(body, 'custom_headers')
|
|
2705
|
+
|| Object.prototype.hasOwnProperty.call(body, 'customHeaders');
|
|
2499
2706
|
const result = brain.saveSetupProvider({
|
|
2500
2707
|
id: body.id || `${type}-default`,
|
|
2501
2708
|
name: body.name || SETUP_PROVIDER_NAMES[type] || type,
|
|
2502
2709
|
type,
|
|
2503
|
-
baseUrl: body.base_url || body.baseUrl || null,
|
|
2710
|
+
baseUrl: hasBaseUrl ? (body.base_url || body.baseUrl || null) : undefined,
|
|
2504
2711
|
apiKeyEncrypted: typeof body.api_key === 'string' ? body.api_key.replace(/[\r\n\s]/g, '').slice(0, 200) : (body.apiKeyEncrypted || null),
|
|
2505
|
-
customHeaders: body.custom_headers || body.customHeaders || null,
|
|
2712
|
+
customHeaders: hasCustomHeaders ? (body.custom_headers || body.customHeaders || null) : undefined,
|
|
2506
2713
|
enabled: body.enabled !== false,
|
|
2507
2714
|
model,
|
|
2508
2715
|
setDefault: Boolean(body.set_default),
|
|
@@ -2880,19 +3087,73 @@ function handleWalleApi(req, res, url) {
|
|
|
2880
3087
|
try {
|
|
2881
3088
|
const backups = brain.listBackups();
|
|
2882
3089
|
const dbPath = brain.getDbPath();
|
|
2883
|
-
|
|
2884
|
-
|
|
3090
|
+
let dbSize = 0;
|
|
3091
|
+
try { dbSize = require('fs').statSync(dbPath).size; } catch {}
|
|
3092
|
+
const info = typeof brain.getBackupDirInfo === 'function'
|
|
3093
|
+
? brain.getBackupDirInfo()
|
|
3094
|
+
: { backup_dir: brain.BACKUP_DIR };
|
|
3095
|
+
jsonResponse(res, {
|
|
3096
|
+
data: {
|
|
3097
|
+
backups,
|
|
3098
|
+
db_path: dbPath,
|
|
3099
|
+
data_dir: path.dirname(dbPath),
|
|
3100
|
+
backup_dir: info.backup_dir || brain.BACKUP_DIR,
|
|
3101
|
+
default_backup_dir: info.default_backup_dir || '',
|
|
3102
|
+
configured_backup_dir: info.configured_backup_dir || '',
|
|
3103
|
+
backup_dir_source: info.source || 'default',
|
|
3104
|
+
db_size: dbSize,
|
|
3105
|
+
},
|
|
3106
|
+
});
|
|
3107
|
+
} catch (e) { jsonResponse(res, { error: e.message }, 500); }
|
|
3108
|
+
return true;
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
// GET /api/wall-e/storage — current Wall-E data and backup locations
|
|
3112
|
+
if (p === '/api/wall-e/storage' && m === 'GET') {
|
|
3113
|
+
if (!brain) return jsonResponse(res, { error: 'Brain not available' }, 503), true;
|
|
3114
|
+
try {
|
|
3115
|
+
if (ensureBrainInit) ensureBrainInit();
|
|
3116
|
+
const dbPath = brain.getDbPath();
|
|
3117
|
+
const info = typeof brain.getBackupDirInfo === 'function'
|
|
3118
|
+
? brain.getBackupDirInfo()
|
|
3119
|
+
: { backup_dir: brain.BACKUP_DIR };
|
|
3120
|
+
jsonResponse(res, {
|
|
3121
|
+
data: {
|
|
3122
|
+
db_path: dbPath,
|
|
3123
|
+
data_dir: path.dirname(dbPath),
|
|
3124
|
+
backup_dir: info.backup_dir || brain.BACKUP_DIR,
|
|
3125
|
+
default_backup_dir: info.default_backup_dir || '',
|
|
3126
|
+
configured_backup_dir: info.configured_backup_dir || '',
|
|
3127
|
+
backup_dir_source: info.source || 'default',
|
|
3128
|
+
},
|
|
3129
|
+
});
|
|
2885
3130
|
} catch (e) { jsonResponse(res, { error: e.message }, 500); }
|
|
2886
3131
|
return true;
|
|
2887
3132
|
}
|
|
2888
3133
|
|
|
3134
|
+
// PUT /api/wall-e/storage/backup-dir — update Wall-E-owned backup directory
|
|
3135
|
+
if (p === '/api/wall-e/storage/backup-dir' && m === 'PUT') {
|
|
3136
|
+
if (!brain || !ensureBrainInit()) return jsonResponse(res, { error: 'Brain not available' }, 503), true;
|
|
3137
|
+
readBody(req, 32 * 1024)
|
|
3138
|
+
.then((body) => {
|
|
3139
|
+
const result = brain.setBackupDir(body.backup_dir || '', {
|
|
3140
|
+
persist: true,
|
|
3141
|
+
moveExisting: !!body.move_existing,
|
|
3142
|
+
});
|
|
3143
|
+
jsonResponse(res, { data: result });
|
|
3144
|
+
})
|
|
3145
|
+
.catch((e) => jsonResponse(res, { error: e.message }, 400));
|
|
3146
|
+
return true;
|
|
3147
|
+
}
|
|
3148
|
+
|
|
2889
3149
|
// POST /api/wall-e/backups — create brain backup
|
|
2890
3150
|
if (p === '/api/wall-e/backups' && m === 'POST') {
|
|
2891
3151
|
if (!brain || !ensureBrainInit()) return jsonResponse(res, { error: 'Brain not available' }, 503), true;
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
3152
|
+
// createBackup is async (non-blocking incremental backup) — resolve before responding.
|
|
3153
|
+
Promise.resolve()
|
|
3154
|
+
.then(() => brain.createBackup('manual'))
|
|
3155
|
+
.then((result) => jsonResponse(res, { data: result }))
|
|
3156
|
+
.catch((e) => jsonResponse(res, { error: e.message }, 500));
|
|
2896
3157
|
return true;
|
|
2897
3158
|
}
|
|
2898
3159
|
|
|
@@ -3349,6 +3610,67 @@ function handleWalleApi(req, res, url) {
|
|
|
3349
3610
|
return true;
|
|
3350
3611
|
}
|
|
3351
3612
|
|
|
3613
|
+
// GET /api/wall-e/diagnostics/write-lock — brain.db write-lock probes (mirrors CTM's
|
|
3614
|
+
// /api/diagnostics/write-lock). Reports THIS process's (the daemon's) acquire/busy/hold/
|
|
3615
|
+
// wait stats by label. Cross-process contention from skill subprocesses shows up in the
|
|
3616
|
+
// `[sqlite-write-lock] busy fail-fast … pid=… holder=… caller=…` log lines. ?reset=1
|
|
3617
|
+
// snapshots and clears (for windowed deltas).
|
|
3618
|
+
if (p === '/api/wall-e/diagnostics/write-lock' && m === 'GET') {
|
|
3619
|
+
try {
|
|
3620
|
+
const b = brain || require('./brain');
|
|
3621
|
+
const reset = params.get('reset') === '1' || params.get('reset') === 'true';
|
|
3622
|
+
const stats = reset ? b.resetWriteLockStats() : b.getWriteLockStats();
|
|
3623
|
+
jsonResponse(res, { ok: true, generatedAt: Date.now(), reset, stats });
|
|
3624
|
+
} catch (e) {
|
|
3625
|
+
jsonResponse(res, { ok: false, error: e.message }, 500);
|
|
3626
|
+
}
|
|
3627
|
+
return true;
|
|
3628
|
+
}
|
|
3629
|
+
|
|
3630
|
+
// GET/POST /api/wall-e/questions/digest/settings — opt-in digest push channels. The CTM
|
|
3631
|
+
// Wall-E tab is always on (no toggle); Slack DM + email are off by default and enabled
|
|
3632
|
+
// here. Stored as kv flags read by the daily digest job.
|
|
3633
|
+
if (p === '/api/wall-e/questions/digest/settings' && m === 'GET') {
|
|
3634
|
+
try {
|
|
3635
|
+
const b = brain || require('./brain');
|
|
3636
|
+
const { KV } = require('./loops/question-digest');
|
|
3637
|
+
jsonResponse(res, { ok: true, settings: {
|
|
3638
|
+
slack_enabled: String(b.getKv(KV.slackEnabled) || '').toLowerCase() === 'true',
|
|
3639
|
+
slack_channel: b.getKv(KV.slackChannel) || '',
|
|
3640
|
+
email_enabled: String(b.getKv(KV.emailEnabled) || '').toLowerCase() === 'true',
|
|
3641
|
+
email_to: b.getKv(KV.emailTo) || '',
|
|
3642
|
+
} });
|
|
3643
|
+
} catch (e) { jsonResponse(res, { ok: false, error: e.message }, 500); }
|
|
3644
|
+
return true;
|
|
3645
|
+
}
|
|
3646
|
+
if (p === '/api/wall-e/questions/digest/settings' && m === 'POST') {
|
|
3647
|
+
if (!brain) return jsonResponse(res, { ok: false, error: 'Brain not available' }, 503), true;
|
|
3648
|
+
readBody(req).then((body) => {
|
|
3649
|
+
body = body || {};
|
|
3650
|
+
const { KV } = require('./loops/question-digest');
|
|
3651
|
+
if ('slack_enabled' in body) brain.setKv(KV.slackEnabled, String(!!body.slack_enabled));
|
|
3652
|
+
if ('slack_channel' in body) brain.setKv(KV.slackChannel, String(body.slack_channel || ''));
|
|
3653
|
+
if ('email_enabled' in body) brain.setKv(KV.emailEnabled, String(!!body.email_enabled));
|
|
3654
|
+
if ('email_to' in body) brain.setKv(KV.emailTo, String(body.email_to || ''));
|
|
3655
|
+
jsonResponse(res, { ok: true });
|
|
3656
|
+
}).catch((e) => jsonResponse(res, { ok: false, error: e.message }, 400));
|
|
3657
|
+
return true;
|
|
3658
|
+
}
|
|
3659
|
+
|
|
3660
|
+
// GET /api/wall-e/questions/digest — current undelivered digest questions (inspection +
|
|
3661
|
+
// the daily digest job). The CTM Wall-E tab itself answers via the existing
|
|
3662
|
+
// GET /api/wall-e/questions + POST /api/wall-e/questions/:id/answer routes above.
|
|
3663
|
+
if (p === '/api/wall-e/questions/digest' && m === 'GET') {
|
|
3664
|
+
try {
|
|
3665
|
+
const { buildDigest } = require('./loops/question-digest');
|
|
3666
|
+
const digest = buildDigest({ max: parseInt(params.get('max') || '10', 10) || 10 });
|
|
3667
|
+
jsonResponse(res, { ok: true, ...digest });
|
|
3668
|
+
} catch (e) {
|
|
3669
|
+
jsonResponse(res, { ok: false, error: e.message }, 500);
|
|
3670
|
+
}
|
|
3671
|
+
return true;
|
|
3672
|
+
}
|
|
3673
|
+
|
|
3352
3674
|
// GET /api/wall-e/workspace/status — Item H of prompt-catalog deep-dive.
|
|
3353
3675
|
// Returns which workspace prompt files exist + which templates are
|
|
3354
3676
|
// available to install. Used by the setup page to render the
|
|
@@ -4120,7 +4442,105 @@ function handleWalleApi(req, res, url) {
|
|
|
4120
4442
|
return true;
|
|
4121
4443
|
}
|
|
4122
4444
|
|
|
4123
|
-
// POST /api/wall-e/coding —
|
|
4445
|
+
// POST /api/wall-e/coding/turn — execute one Wall-E coding turn.
|
|
4446
|
+
//
|
|
4447
|
+
// This is the native coding-run boundary for CTM/phone sessions. It differs
|
|
4448
|
+
// from /api/wall-e/chat?stream=1 by running the coding orchestrator directly
|
|
4449
|
+
// and returning a typed completion outcome: changed, read-only, blocked, or
|
|
4450
|
+
// failed. Chat can still discuss code, but coding sessions need this stronger
|
|
4451
|
+
// contract so prose alone cannot masquerade as completed implementation work.
|
|
4452
|
+
if (p === '/api/wall-e/coding/turn' && m === 'POST') {
|
|
4453
|
+
const wantsStream = params.get('stream') === '1' || (req.headers.accept || '').includes('text/event-stream');
|
|
4454
|
+
// Coding messages can carry pasted image attachments (base64) — accept the
|
|
4455
|
+
// same 16MB cap as /api/wall-e/chat, not the 1MB text default (a >1MB image
|
|
4456
|
+
// otherwise fails with "Body too large (>1MB)").
|
|
4457
|
+
readBody(req, { maxBytes: BODY_LIMIT_LARGE }).then(async body => {
|
|
4458
|
+
let requestFinished = false;
|
|
4459
|
+
const abortController = new AbortController();
|
|
4460
|
+
if (typeof res.on === 'function') {
|
|
4461
|
+
res.on('close', () => {
|
|
4462
|
+
if (!requestFinished) abortController.abort();
|
|
4463
|
+
});
|
|
4464
|
+
}
|
|
4465
|
+
const sendJsonError = (err, status = 500) => {
|
|
4466
|
+
jsonResponse(res, { error: err.message || String(err), code: err.code || 'WALLE_CODING_TURN_ERROR' }, status);
|
|
4467
|
+
};
|
|
4468
|
+
const sendStreamEvent = wantsStream
|
|
4469
|
+
? (event) => {
|
|
4470
|
+
try { res.write('data: ' + JSON.stringify(event) + '\n\n'); } catch {}
|
|
4471
|
+
}
|
|
4472
|
+
: () => {};
|
|
4473
|
+
try {
|
|
4474
|
+
if (!body.message && !body.request && !body.prompt) {
|
|
4475
|
+
if (wantsStream) {
|
|
4476
|
+
res.writeHead(400, {
|
|
4477
|
+
'Content-Type': 'text/event-stream',
|
|
4478
|
+
'Cache-Control': 'no-cache',
|
|
4479
|
+
'Connection': 'keep-alive',
|
|
4480
|
+
});
|
|
4481
|
+
sendStreamEvent({ type: 'error', error: 'message is required', code: 'BAD_REQUEST' });
|
|
4482
|
+
requestFinished = true;
|
|
4483
|
+
res.end();
|
|
4484
|
+
} else {
|
|
4485
|
+
sendJsonError(new Error('message is required'), 400);
|
|
4486
|
+
}
|
|
4487
|
+
return;
|
|
4488
|
+
}
|
|
4489
|
+
if (wantsStream) {
|
|
4490
|
+
res.writeHead(200, {
|
|
4491
|
+
'Content-Type': 'text/event-stream',
|
|
4492
|
+
'Cache-Control': 'no-cache',
|
|
4493
|
+
'Connection': 'keep-alive',
|
|
4494
|
+
});
|
|
4495
|
+
}
|
|
4496
|
+
const { CodingRunController } = require('./coding/coding-run-controller');
|
|
4497
|
+
const controller = new CodingRunController();
|
|
4498
|
+
const result = await controller.runTurn(body, {
|
|
4499
|
+
signal: abortController.signal,
|
|
4500
|
+
onEvent: sendStreamEvent,
|
|
4501
|
+
});
|
|
4502
|
+
requestFinished = true;
|
|
4503
|
+
if (wantsStream) {
|
|
4504
|
+
sendStreamEvent({ type: 'done', reply: result.reply, data: result });
|
|
4505
|
+
res.end();
|
|
4506
|
+
} else {
|
|
4507
|
+
jsonResponse(res, { data: result });
|
|
4508
|
+
}
|
|
4509
|
+
} catch (err) {
|
|
4510
|
+
requestFinished = true;
|
|
4511
|
+
const isUserCancelled = err?.code === 'WALLE_CANCELLED'
|
|
4512
|
+
|| err?.message === 'Cancelled'
|
|
4513
|
+
|| (err?.name === 'AbortError' && abortController.signal.aborted);
|
|
4514
|
+
if (wantsStream) {
|
|
4515
|
+
if (!res.headersSent) {
|
|
4516
|
+
res.writeHead(isUserCancelled ? 499 : 500, {
|
|
4517
|
+
'Content-Type': 'text/event-stream',
|
|
4518
|
+
'Cache-Control': 'no-cache',
|
|
4519
|
+
'Connection': 'keep-alive',
|
|
4520
|
+
});
|
|
4521
|
+
}
|
|
4522
|
+
sendStreamEvent({
|
|
4523
|
+
type: isUserCancelled ? 'cancelled' : 'error',
|
|
4524
|
+
error: isUserCancelled ? 'Cancelled' : (err.message || String(err)),
|
|
4525
|
+
code: isUserCancelled ? 'WALLE_CANCELLED' : (err.code || 'WALLE_CODING_TURN_ERROR'),
|
|
4526
|
+
});
|
|
4527
|
+
try { res.end(); } catch {}
|
|
4528
|
+
} else {
|
|
4529
|
+
sendJsonError(err, isUserCancelled ? 499 : 500);
|
|
4530
|
+
}
|
|
4531
|
+
}
|
|
4532
|
+
}).catch(e => {
|
|
4533
|
+
if (wantsStream && res.headersSent) {
|
|
4534
|
+
try { res.write('data: ' + JSON.stringify({ type: 'error', error: e.message }) + '\n\n'); } catch {}
|
|
4535
|
+
try { res.end(); } catch {}
|
|
4536
|
+
} else {
|
|
4537
|
+
jsonResponse(res, { error: e.message }, 400);
|
|
4538
|
+
}
|
|
4539
|
+
});
|
|
4540
|
+
return true;
|
|
4541
|
+
}
|
|
4542
|
+
|
|
4543
|
+
// POST /api/wall-e/coding — start a queued coding task
|
|
4124
4544
|
if (p === '/api/wall-e/coding' && m === 'POST') {
|
|
4125
4545
|
if (!brain || !ensureBrainInit()) return jsonResponse(res, { error: 'Brain module not available' }, 503), true;
|
|
4126
4546
|
readBody(req).then(body => {
|
|
@@ -4148,7 +4568,7 @@ function handleWalleApi(req, res, url) {
|
|
|
4148
4568
|
} catch (e) {
|
|
4149
4569
|
jsonResponse(res, { error: e.message }, 500);
|
|
4150
4570
|
}
|
|
4151
|
-
}).catch(e => jsonResponse(res, { error: e.message }, 500));
|
|
4571
|
+
}).catch(e => jsonResponse(res, { error: e.message, code: e.code || '' }, e.code === 'BODY_TOO_LARGE' ? 413 : 500));
|
|
4152
4572
|
return true;
|
|
4153
4573
|
}
|
|
4154
4574
|
|
|
@@ -4424,6 +4844,7 @@ function handleWalleApi(req, res, url) {
|
|
|
4424
4844
|
|
|
4425
4845
|
// GET /api/wall-e/shadow/stats — shadow training pipeline stats
|
|
4426
4846
|
if (p === '/api/wall-e/shadow/stats' && m === 'GET') {
|
|
4847
|
+
(async () => {
|
|
4427
4848
|
try {
|
|
4428
4849
|
const db = brain.getDb();
|
|
4429
4850
|
const totalResults = db.prepare('SELECT COUNT(*) AS count FROM shadow_results').get().count;
|
|
@@ -4458,41 +4879,22 @@ function handleWalleApi(req, res, url) {
|
|
|
4458
4879
|
// Harvest progress — total CTM sessions vs processed
|
|
4459
4880
|
let harvestProgress = null;
|
|
4460
4881
|
try {
|
|
4461
|
-
const
|
|
4462
|
-
const
|
|
4463
|
-
const
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
SELECT COUNT(*) AS count FROM (
|
|
4476
|
-
SELECT session_id FROM prompt_executions WHERE role = 'user'
|
|
4477
|
-
GROUP BY session_id HAVING COUNT(*) >= 2
|
|
4478
|
-
)
|
|
4479
|
-
`).get().count;
|
|
4480
|
-
ctmDb.close();
|
|
4481
|
-
|
|
4482
|
-
const singleReplayed = (replayStats['ctm-replay']?.totalProcessed) || 0;
|
|
4483
|
-
const multiReplayed = (replayStats['ctm-replay-mt']?.totalProcessed) || 0;
|
|
4484
|
-
|
|
4485
|
-
harvestProgress = {
|
|
4486
|
-
totalSessions,
|
|
4487
|
-
totalPairs,
|
|
4488
|
-
multiTurnSessions,
|
|
4489
|
-
singleTurnReplayed: singleReplayed,
|
|
4490
|
-
multiTurnReplayed: multiReplayed,
|
|
4491
|
-
totalReplayed: singleReplayed + multiReplayed,
|
|
4492
|
-
};
|
|
4493
|
-
}
|
|
4882
|
+
const { getPromptExecutionStats } = require('./memory/ctm-prompt-executions-client');
|
|
4883
|
+
const stats = await getPromptExecutionStats({ timeoutMs: 1000 });
|
|
4884
|
+
const singleReplayed = (replayStats['ctm-replay']?.totalProcessed) || 0;
|
|
4885
|
+
const multiReplayed = (replayStats['ctm-replay-mt']?.totalProcessed) || 0;
|
|
4886
|
+
|
|
4887
|
+
harvestProgress = {
|
|
4888
|
+
totalSessions: stats.totalSessions || 0,
|
|
4889
|
+
totalPairs: stats.totalPairs || 0,
|
|
4890
|
+
multiTurnSessions: stats.multiTurnSessions || 0,
|
|
4891
|
+
singleTurnReplayed: singleReplayed,
|
|
4892
|
+
multiTurnReplayed: multiReplayed,
|
|
4893
|
+
totalReplayed: singleReplayed + multiReplayed,
|
|
4894
|
+
source: 'ctm-api',
|
|
4895
|
+
};
|
|
4494
4896
|
} catch (e) {
|
|
4495
|
-
|
|
4897
|
+
harvestProgress = { source: 'ctm-api', unavailable: true, error: e.message };
|
|
4496
4898
|
}
|
|
4497
4899
|
|
|
4498
4900
|
// Recent results — last 5 shadow results for sample browser
|
|
@@ -4509,19 +4911,21 @@ function handleWalleApi(req, res, url) {
|
|
|
4509
4911
|
LIMIT 5
|
|
4510
4912
|
`).all();
|
|
4511
4913
|
|
|
4512
|
-
|
|
4914
|
+
jsonResponse(res, { data: {
|
|
4513
4915
|
totalResults, evaluatedResults,
|
|
4514
4916
|
avgScore: avgScore != null ? Math.round(avgScore * 1000) / 1000 : null,
|
|
4515
4917
|
byModel, byTaskType, promotionCandidates, modelScores,
|
|
4516
4918
|
replayStats, harvestProgress, recentResults,
|
|
4517
|
-
} })
|
|
4919
|
+
} });
|
|
4518
4920
|
} catch (e) {
|
|
4519
|
-
|
|
4921
|
+
jsonResponse(res, { data: {
|
|
4520
4922
|
totalResults: 0, evaluatedResults: 0, avgScore: null,
|
|
4521
4923
|
byModel: [], byTaskType: [], promotionCandidates: [], modelScores: [],
|
|
4522
4924
|
replayStats: {}, harvestProgress: null, recentResults: [],
|
|
4523
|
-
} })
|
|
4925
|
+
} });
|
|
4524
4926
|
}
|
|
4927
|
+
})();
|
|
4928
|
+
return true;
|
|
4525
4929
|
}
|
|
4526
4930
|
|
|
4527
4931
|
// GET /api/wall-e/shadow/comparisons — paginated side-by-side comparison viewer
|
|
@@ -5578,6 +5982,28 @@ function handleWalleApi(req, res, url) {
|
|
|
5578
5982
|
summary.recent_feedback = [];
|
|
5579
5983
|
}
|
|
5580
5984
|
|
|
5985
|
+
try {
|
|
5986
|
+
summary.feature_adoption = {
|
|
5987
|
+
memory_search: telemetryEmbeddingFeatureAdoption(tdb, since, summary.active_installs || 0),
|
|
5988
|
+
};
|
|
5989
|
+
} catch {
|
|
5990
|
+
summary.feature_adoption = {
|
|
5991
|
+
memory_search: {
|
|
5992
|
+
reporting_installs: 0,
|
|
5993
|
+
enabled_installs: 0,
|
|
5994
|
+
usage_installs: 0,
|
|
5995
|
+
setup_view_installs: 0,
|
|
5996
|
+
switch_success_installs: 0,
|
|
5997
|
+
switch_failed_installs: 0,
|
|
5998
|
+
enabled_pct_active: null,
|
|
5999
|
+
usage_pct_active: null,
|
|
6000
|
+
latest_state: [],
|
|
6001
|
+
enabled_by_provider: [],
|
|
6002
|
+
usage_by_operation: [],
|
|
6003
|
+
},
|
|
6004
|
+
};
|
|
6005
|
+
}
|
|
6006
|
+
|
|
5581
6007
|
// Compat lifecycle data (Phase 4)
|
|
5582
6008
|
try {
|
|
5583
6009
|
// Version distribution with last_seen
|
|
@@ -5612,8 +6038,28 @@ function handleWalleApi(req, res, url) {
|
|
|
5612
6038
|
// Safe to remove: deprecated features with 0 usage
|
|
5613
6039
|
try {
|
|
5614
6040
|
const compat = require('./compat');
|
|
5615
|
-
|
|
5616
|
-
|
|
6041
|
+
const registry = typeof compat.getRegistry === 'function' ? compat.getRegistry() : {};
|
|
6042
|
+
summary.compat_removal_status = Object.entries(registry).map(([key, info]) => {
|
|
6043
|
+
const telemetryKey = info.telemetryKey || key;
|
|
6044
|
+
const activeInstalls = featureCounts[telemetryKey] || 0;
|
|
6045
|
+
const deprecated = Boolean(info.deprecatedIn);
|
|
6046
|
+
const safeToRemove = deprecated && activeInstalls === 0;
|
|
6047
|
+
const blockedReason = safeToRemove
|
|
6048
|
+
? ''
|
|
6049
|
+
: (!deprecated ? 'not_deprecated' : (activeInstalls > 0 ? 'active_usage' : 'not_scheduled'));
|
|
6050
|
+
return {
|
|
6051
|
+
key,
|
|
6052
|
+
telemetry_key: telemetryKey,
|
|
6053
|
+
deprecated,
|
|
6054
|
+
deprecated_in: info.deprecatedIn || null,
|
|
6055
|
+
remove_after: info.removeAfter || null,
|
|
6056
|
+
active_installs: activeInstalls,
|
|
6057
|
+
safe_to_remove: safeToRemove,
|
|
6058
|
+
blocked_reason: blockedReason,
|
|
6059
|
+
};
|
|
6060
|
+
});
|
|
6061
|
+
summary.safe_to_remove = summary.compat_removal_status
|
|
6062
|
+
.filter(c => c.safe_to_remove)
|
|
5617
6063
|
.map(c => c.key);
|
|
5618
6064
|
} catch {}
|
|
5619
6065
|
|
|
@@ -5650,6 +6096,7 @@ function handleWalleApi(req, res, url) {
|
|
|
5650
6096
|
apply_clicked: new Set(),
|
|
5651
6097
|
apply_started: new Set(),
|
|
5652
6098
|
completed: new Set(),
|
|
6099
|
+
first_tracked_completed: new Set(),
|
|
5653
6100
|
};
|
|
5654
6101
|
for (const row of upgradeRows) {
|
|
5655
6102
|
const identity = row.machine_bucket ? `m:${row.machine_bucket}` : `i:${row.install_id}`;
|
|
@@ -5657,6 +6104,7 @@ function handleWalleApi(req, res, url) {
|
|
|
5657
6104
|
try { meta = row.meta ? JSON.parse(row.meta) : {}; } catch {}
|
|
5658
6105
|
if (row.event === 'upgrade') {
|
|
5659
6106
|
upgradeSets.completed.add(identity);
|
|
6107
|
+
if (meta.first_tracked) upgradeSets.first_tracked_completed.add(identity);
|
|
5660
6108
|
continue;
|
|
5661
6109
|
}
|
|
5662
6110
|
if (row.event === 'funnel') {
|
|
@@ -5683,17 +6131,23 @@ function handleWalleApi(req, res, url) {
|
|
|
5683
6131
|
}
|
|
5684
6132
|
if (row.event === 'ctm_update_apply_started') upgradeSets.apply_started.add(identity);
|
|
5685
6133
|
}
|
|
6134
|
+
const completedAfterApply = telemetrySetIntersectionSize(upgradeSets.completed, upgradeSets.apply_started);
|
|
6135
|
+
const externalCompleted = telemetrySetDifferenceSize(upgradeSets.completed, upgradeSets.apply_started);
|
|
5686
6136
|
summary.upgrade_funnel = {
|
|
5687
6137
|
available: upgradeSets.available.size,
|
|
5688
6138
|
prompted: upgradeSets.prompted.size,
|
|
5689
6139
|
dismissed: upgradeSets.dismissed.size,
|
|
5690
6140
|
apply_clicked: upgradeSets.apply_clicked.size,
|
|
5691
6141
|
apply_started: upgradeSets.apply_started.size,
|
|
5692
|
-
completed:
|
|
6142
|
+
completed: completedAfterApply,
|
|
6143
|
+
completed_after_apply: completedAfterApply,
|
|
6144
|
+
completed_observed: upgradeSets.completed.size,
|
|
6145
|
+
external_completed: externalCompleted,
|
|
6146
|
+
first_tracked_completed: upgradeSets.first_tracked_completed.size,
|
|
5693
6147
|
prompt_rate: pct(upgradeSets.prompted.size, upgradeSets.available.size),
|
|
5694
6148
|
apply_rate: pct(upgradeSets.apply_clicked.size, upgradeSets.prompted.size),
|
|
5695
6149
|
start_rate: pct(upgradeSets.apply_started.size, upgradeSets.apply_clicked.size),
|
|
5696
|
-
completion_rate: pct(
|
|
6150
|
+
completion_rate: pct(completedAfterApply, upgradeSets.apply_started.size),
|
|
5697
6151
|
};
|
|
5698
6152
|
} catch {}
|
|
5699
6153
|
|
|
@@ -6230,7 +6684,7 @@ function handleWalleApi(req, res, url) {
|
|
|
6230
6684
|
|
|
6231
6685
|
// Allow overriding the read DB (for testing)
|
|
6232
6686
|
function _setReadDb(db) {
|
|
6233
|
-
|
|
6687
|
+
readDbOverride = db;
|
|
6234
6688
|
}
|
|
6235
6689
|
|
|
6236
6690
|
function _setBrain(b) {
|