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,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function stripAnsi(value) {
|
|
4
|
+
return String(value || '')
|
|
5
|
+
.replace(/\x1b\[[0-9;?]*[a-zA-Z]/g, '')
|
|
6
|
+
.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, '')
|
|
7
|
+
.replace(/\x1b[()][A-Z0-9]/g, '')
|
|
8
|
+
.replace(/\x1b>[0-9]*[a-zA-Z]/g, '')
|
|
9
|
+
.replace(/\x1b<[a-zA-Z]/g, '')
|
|
10
|
+
.replace(/\x1b=[0-9]*/g, '')
|
|
11
|
+
.replace(/\x1b\s/g, '')
|
|
12
|
+
.replace(/\r/g, '')
|
|
13
|
+
.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function normalizeText(value) {
|
|
17
|
+
return stripAnsi(value)
|
|
18
|
+
.replace(/\u00a0/g, ' ')
|
|
19
|
+
.split('\n')
|
|
20
|
+
.map((line) => line.replace(/[ \t]+/g, ' ').replace(/\s+$/g, ''))
|
|
21
|
+
.join('\n')
|
|
22
|
+
.trim();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function normalizeAgentType(value) {
|
|
26
|
+
const text = String(value || '').trim().toLowerCase();
|
|
27
|
+
if (!text) return '';
|
|
28
|
+
if (text === 'codex' || text === 'codex-cli' || text === 'codex_cli' || text === 'codex_cli_rs') return 'codex';
|
|
29
|
+
return text;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function looksLikeCodexTranscriptPagerSnapshot(agentType, value) {
|
|
33
|
+
if (normalizeAgentType(agentType) !== 'codex') return false;
|
|
34
|
+
const text = normalizeText(value);
|
|
35
|
+
if (!text) return false;
|
|
36
|
+
|
|
37
|
+
const compact = text.replace(/[ \t]+/g, ' ');
|
|
38
|
+
const hasTranscriptHeading = /(?:^|\n)\s*(?:[\/\\]\s*){1,}\s*T\s*R\s*A\s*N\s*S\s*C\s*R\s*I\s*P\s*T\b/i.test(compact)
|
|
39
|
+
|| /(?:^|\n)\s*T\s*R\s*A\s*N\s*S\s*C\s*R\s*I\s*P\s*T\s*(?:[\/\\]\s*){1,}/i.test(compact);
|
|
40
|
+
const hasQuitInstruction = /\bq\s+to\s+quit\b/i.test(compact);
|
|
41
|
+
const hasScrollInstruction = /\bj\/k\s+to\s+scroll\b/i.test(compact) || /\bpgup\/pgdn\s+to\s+page\b/i.test(compact);
|
|
42
|
+
const hasEditInstruction = /\benter\s+to\s+edit\s+message\b/i.test(compact)
|
|
43
|
+
|| /\besc\/.{0,24}\bto\s+edit\s+(?:prev|previous|next)\b/i.test(compact);
|
|
44
|
+
|
|
45
|
+
return hasTranscriptHeading && hasQuitInstruction && hasScrollInstruction && hasEditInstruction;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
looksLikeCodexTranscriptPagerSnapshot,
|
|
50
|
+
normalizeText,
|
|
51
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Newer Codex CLI versions background-compress cold rollouts to
|
|
4
|
+
// `rollout-*.jsonl.zst` and re-materialize the live `.jsonl` on resume.
|
|
5
|
+
// CTM reads rollouts directly, so a compressed archive must be lazily
|
|
6
|
+
// materialized to a disk cache once and then served like any other rollout.
|
|
7
|
+
// Compressed rollouts are cold + immutable by definition — no tail/HWM
|
|
8
|
+
// semantics needed; the cache key embeds mtime+size so a replaced archive
|
|
9
|
+
// re-materializes.
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const os = require('os');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const zlib = require('zlib');
|
|
15
|
+
const { spawnSync } = require('child_process');
|
|
16
|
+
|
|
17
|
+
const MAX_COMPRESSED_BYTES = 64 * 1024 * 1024; // skip absurd archives
|
|
18
|
+
const MAX_OUTPUT_BYTES = 512 * 1024 * 1024; // decompression bomb guard
|
|
19
|
+
const CACHE_MAX_FILES = 16;
|
|
20
|
+
const CACHE_MAX_BYTES = 1024 * 1024 * 1024;
|
|
21
|
+
|
|
22
|
+
function isZstRolloutFileName(name) {
|
|
23
|
+
return /\.jsonl\.zst$/i.test(String(name || ''));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function cacheDir() {
|
|
27
|
+
if (process.env.CTM_CODEX_ZST_CACHE_DIR) return process.env.CTM_CODEX_ZST_CACHE_DIR;
|
|
28
|
+
return path.join(os.homedir(), '.walle', 'cache', 'codex-zst');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let _capability = null;
|
|
32
|
+
function zstdCapability() {
|
|
33
|
+
if (_capability) return _capability;
|
|
34
|
+
if (typeof zlib.zstdDecompressSync === 'function') { _capability = 'zlib'; return _capability; }
|
|
35
|
+
try {
|
|
36
|
+
const probe = spawnSync('zstd', ['--version'], { stdio: 'ignore', timeout: 5000 });
|
|
37
|
+
if (probe.status === 0) { _capability = 'binary'; return _capability; }
|
|
38
|
+
} catch { /* not on PATH */ }
|
|
39
|
+
_capability = 'none';
|
|
40
|
+
return _capability;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function _decompress(buf) {
|
|
44
|
+
const cap = zstdCapability();
|
|
45
|
+
if (cap === 'zlib') return zlib.zstdDecompressSync(buf, { maxOutputLength: MAX_OUTPUT_BYTES });
|
|
46
|
+
if (cap === 'binary') {
|
|
47
|
+
const run = spawnSync('zstd', ['-dc'], { input: buf, maxBuffer: MAX_OUTPUT_BYTES, timeout: 120000 });
|
|
48
|
+
if (run.status === 0 && run.stdout) return run.stdout;
|
|
49
|
+
throw new Error(`zstd -dc failed: ${String(run.stderr || run.error || 'unknown').slice(0, 200)}`);
|
|
50
|
+
}
|
|
51
|
+
const err = new Error('no zstd decompressor (Node >= 22.15 zlib.zstdDecompressSync or the zstd binary required)');
|
|
52
|
+
err.code = 'NO_ZSTD';
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function _pruneCache(dir) {
|
|
57
|
+
let entries = [];
|
|
58
|
+
try {
|
|
59
|
+
entries = fs.readdirSync(dir)
|
|
60
|
+
.filter(name => name.endsWith('.jsonl'))
|
|
61
|
+
.map(name => {
|
|
62
|
+
const fullPath = path.join(dir, name);
|
|
63
|
+
try { const st = fs.statSync(fullPath); return { fullPath, size: st.size, mtimeMs: st.mtimeMs }; }
|
|
64
|
+
catch { return null; }
|
|
65
|
+
})
|
|
66
|
+
.filter(Boolean)
|
|
67
|
+
.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
68
|
+
} catch { return; }
|
|
69
|
+
let totalBytes = 0;
|
|
70
|
+
entries.forEach((entry, idx) => {
|
|
71
|
+
totalBytes += entry.size;
|
|
72
|
+
if (idx >= CACHE_MAX_FILES || totalBytes > CACHE_MAX_BYTES) {
|
|
73
|
+
try { fs.unlinkSync(entry.fullPath); } catch { /* concurrent prune */ }
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// `.zst` → cached decompressed `.jsonl` path; anything else passes through
|
|
79
|
+
// unchanged so callers can call this unconditionally.
|
|
80
|
+
function materializeCodexRollout(filePath) {
|
|
81
|
+
const p = String(filePath || '');
|
|
82
|
+
if (!isZstRolloutFileName(p)) return { path: p, ok: true, reason: '' };
|
|
83
|
+
let st;
|
|
84
|
+
try { st = fs.statSync(p); } catch { return { path: '', ok: false, reason: 'stat_failed' }; }
|
|
85
|
+
if (st.size > MAX_COMPRESSED_BYTES) return { path: '', ok: false, reason: 'too_large' };
|
|
86
|
+
if (zstdCapability() === 'none') return { path: '', ok: false, reason: 'no_zstd' };
|
|
87
|
+
const dir = cacheDir();
|
|
88
|
+
const key = `${path.basename(p).replace(/\.zst$/i, '').replace(/\.jsonl$/i, '')}-${Math.round(st.mtimeMs)}-${st.size}.jsonl`;
|
|
89
|
+
const out = path.join(dir, key);
|
|
90
|
+
try { if (fs.existsSync(out)) return { path: out, ok: true, reason: 'cache' }; } catch { /* fall through */ }
|
|
91
|
+
try {
|
|
92
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
93
|
+
const decompressed = _decompress(fs.readFileSync(p));
|
|
94
|
+
const tmp = `${out}.tmp-${process.pid}`;
|
|
95
|
+
fs.writeFileSync(tmp, decompressed);
|
|
96
|
+
fs.renameSync(tmp, out);
|
|
97
|
+
_pruneCache(dir);
|
|
98
|
+
return { path: out, ok: true, reason: 'decompressed' };
|
|
99
|
+
} catch (e) {
|
|
100
|
+
return { path: '', ok: false, reason: `decompress_failed:${String(e.code || e.message || '').slice(0, 80)}` };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Drop a `.zst` archive when its live `.jsonl` sibling exists (the
|
|
105
|
+
// resume-rematerialization case — the live file is authoritative).
|
|
106
|
+
function dropZstWithLiveSibling(filePaths) {
|
|
107
|
+
const list = Array.isArray(filePaths) ? filePaths : [];
|
|
108
|
+
const inSet = new Set(list);
|
|
109
|
+
return list.filter(p => {
|
|
110
|
+
if (!isZstRolloutFileName(p)) return true;
|
|
111
|
+
const live = p.replace(/\.zst$/i, '');
|
|
112
|
+
if (inSet.has(live)) return false;
|
|
113
|
+
try { return !fs.existsSync(live); } catch { return true; }
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = {
|
|
118
|
+
isZstRolloutFileName,
|
|
119
|
+
zstdCapability,
|
|
120
|
+
materializeCodexRollout,
|
|
121
|
+
dropZstWithLiveSibling,
|
|
122
|
+
MAX_COMPRESSED_BYTES,
|
|
123
|
+
_pruneCache,
|
|
124
|
+
};
|
|
@@ -22,43 +22,130 @@ const CC_ALIAS_MAP = {
|
|
|
22
22
|
|
|
23
23
|
const AGENT_MODEL_CACHE_TTL = 5000;
|
|
24
24
|
|
|
25
|
+
function _normalizeClaudeModelName(value) {
|
|
26
|
+
if (typeof value !== 'string') return null;
|
|
27
|
+
const alias = value.replace(/\[.*$/, '').trim().toLowerCase();
|
|
28
|
+
return CC_ALIAS_MAP[alias] || (alias.startsWith('claude-') ? alias : null);
|
|
29
|
+
}
|
|
30
|
+
|
|
25
31
|
// Read the actual model used in the most recent assistant turn of a JSONL
|
|
26
32
|
// transcript. This is the source of truth: it reflects what Claude Code
|
|
27
33
|
// actually invoked, immune to alias drift.
|
|
28
|
-
|
|
34
|
+
// Walk a JSONL chunk backwards for the last assistant turn carrying a claude- model id.
|
|
35
|
+
function _scanJsonlForClaudeModelInfo(raw) {
|
|
36
|
+
const lines = raw.split('\n');
|
|
37
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
38
|
+
const line = lines[i];
|
|
39
|
+
if (!line || line[0] !== '{') continue;
|
|
40
|
+
// Cheap pre-filter so we don't JSON.parse every user/system line.
|
|
41
|
+
if (line.indexOf('"model"') === -1) continue;
|
|
42
|
+
try {
|
|
43
|
+
const rec = JSON.parse(line);
|
|
44
|
+
if (!rec || rec.type !== 'assistant') continue;
|
|
45
|
+
const m = rec && rec.message && rec.message.model;
|
|
46
|
+
const model = _normalizeClaudeModelName(m);
|
|
47
|
+
if (model) {
|
|
48
|
+
const timestampMs = typeof rec.timestamp === 'string' ? Date.parse(rec.timestamp) : NaN;
|
|
49
|
+
return {
|
|
50
|
+
model,
|
|
51
|
+
timestampMs: Number.isFinite(timestampMs) ? timestampMs : 0,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
} catch { /* skip malformed line */ }
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function _scanJsonlForClaudeModel(raw) {
|
|
60
|
+
const info = _scanJsonlForClaudeModelInfo(raw);
|
|
61
|
+
return info ? info.model : null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Read just the TAIL of the transcript by default: the model lives in the most
|
|
65
|
+
// recent assistant turn, so reading the whole file (an active session's JSONL is
|
|
66
|
+
// 50–100MB) on the main loop just to find the last line was a model-sync boot
|
|
67
|
+
// freeze — getSessionAgentModel runs this for every session on a cold cache.
|
|
68
|
+
const _CLAUDE_JSONL_MODEL_TAIL_BYTES = Math.max(
|
|
69
|
+
64 * 1024,
|
|
70
|
+
Number(process.env.CTM_CLAUDE_MODEL_JSONL_TAIL_BYTES) || 512 * 1024
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
function getClaudeCodeModelInfoFromJsonl(jsonlPath) {
|
|
29
74
|
if (!jsonlPath) return null;
|
|
30
75
|
try {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
36
|
-
const line = lines[i];
|
|
37
|
-
if (!line || line[0] !== '{') continue;
|
|
38
|
-
// Cheap pre-filter so we don't JSON.parse every user/system line.
|
|
39
|
-
if (line.indexOf('"model"') === -1) continue;
|
|
40
|
-
try {
|
|
41
|
-
const rec = JSON.parse(line);
|
|
42
|
-
if (!rec || rec.type !== 'assistant') continue;
|
|
43
|
-
const m = rec && rec.message && rec.message.model;
|
|
44
|
-
if (typeof m === 'string' && m.startsWith('claude-')) return m;
|
|
45
|
-
} catch { /* skip malformed line */ }
|
|
76
|
+
let size;
|
|
77
|
+
try { size = fs.statSync(jsonlPath).size; } catch { return null; } // missing/unreadable
|
|
78
|
+
if (size <= _CLAUDE_JSONL_MODEL_TAIL_BYTES) {
|
|
79
|
+
return _scanJsonlForClaudeModelInfo(fs.readFileSync(jsonlPath, 'utf8'));
|
|
46
80
|
}
|
|
81
|
+
// Large file: read only the trailing window, dropping the leading partial line
|
|
82
|
+
// (the tail boundary almost certainly splits one).
|
|
83
|
+
const fd = fs.openSync(jsonlPath, 'r');
|
|
84
|
+
let tail;
|
|
85
|
+
try {
|
|
86
|
+
const buf = Buffer.allocUnsafe(_CLAUDE_JSONL_MODEL_TAIL_BYTES);
|
|
87
|
+
const read = fs.readSync(fd, buf, 0, _CLAUDE_JSONL_MODEL_TAIL_BYTES, size - _CLAUDE_JSONL_MODEL_TAIL_BYTES);
|
|
88
|
+
tail = buf.toString('utf8', 0, read);
|
|
89
|
+
} finally { fs.closeSync(fd); }
|
|
90
|
+
const nl = tail.indexOf('\n');
|
|
91
|
+
const found = _scanJsonlForClaudeModelInfo(nl >= 0 ? tail.slice(nl + 1) : tail);
|
|
92
|
+
if (found) return found;
|
|
93
|
+
// Rare: the last assistant-with-model turn is older than the tail window.
|
|
94
|
+
// Fall back to a full read so we are never LESS correct than before — only the
|
|
95
|
+
// (uncommon) miss pays the full cost the old code always paid.
|
|
96
|
+
return _scanJsonlForClaudeModelInfo(fs.readFileSync(jsonlPath, 'utf8'));
|
|
47
97
|
} catch { /* file unreadable */ }
|
|
48
98
|
return null;
|
|
49
99
|
}
|
|
50
100
|
|
|
51
|
-
function
|
|
101
|
+
function getClaudeCodeModelFromJsonl(jsonlPath) {
|
|
102
|
+
const info = getClaudeCodeModelInfoFromJsonl(jsonlPath);
|
|
103
|
+
return info ? info.model : null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function getClaudeCodeModelSelection(homeDir = process.env.HOME) {
|
|
107
|
+
const settingsPath = path.join(homeDir, '.claude', 'settings.json');
|
|
52
108
|
try {
|
|
53
|
-
const raw = JSON.parse(fs.readFileSync(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
109
|
+
const raw = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
110
|
+
const model = _normalizeClaudeModelName(raw.model);
|
|
111
|
+
if (!model) return null;
|
|
112
|
+
let mtimeMs = 0;
|
|
113
|
+
try { mtimeMs = fs.statSync(settingsPath).mtimeMs || 0; } catch {}
|
|
114
|
+
return { model, mtimeMs, rawModel: raw.model, settingsPath };
|
|
57
115
|
} catch {
|
|
58
116
|
return null;
|
|
59
117
|
}
|
|
60
118
|
}
|
|
61
119
|
|
|
120
|
+
function getClaudeCodeModel(homeDir = process.env.HOME) {
|
|
121
|
+
const selection = getClaudeCodeModelSelection(homeDir);
|
|
122
|
+
return selection ? selection.model : null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function shouldPreferClaudeSelectedModel(selection, jsonlInfo) {
|
|
126
|
+
if (!selection || !selection.model) return false;
|
|
127
|
+
if (!jsonlInfo || !jsonlInfo.model) return true;
|
|
128
|
+
if (!selection.mtimeMs || !jsonlInfo.timestampMs) return false;
|
|
129
|
+
return selection.mtimeMs > (jsonlInfo.timestampMs + 1000);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function _coerceTimeMs(value) {
|
|
133
|
+
if (!value) return 0;
|
|
134
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value > 1e12 ? value : value * 1000;
|
|
135
|
+
const parsed = Date.parse(String(value));
|
|
136
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function getClaudeSessionModelName({ jsonlPath, homeDir = process.env.HOME, sessionActivityMs = 0 } = {}) {
|
|
140
|
+
const jsonlInfo = getClaudeCodeModelInfoFromJsonl(jsonlPath);
|
|
141
|
+
const selection = getClaudeCodeModelSelection(homeDir);
|
|
142
|
+
if (shouldPreferClaudeSelectedModel(selection, jsonlInfo)) {
|
|
143
|
+
const activityMs = _coerceTimeMs(sessionActivityMs);
|
|
144
|
+
if (!activityMs || activityMs >= (selection.mtimeMs - 10 * 60 * 1000)) return selection.model;
|
|
145
|
+
}
|
|
146
|
+
return (jsonlInfo && jsonlInfo.model) || (selection && selection.model) || null;
|
|
147
|
+
}
|
|
148
|
+
|
|
62
149
|
function openCodexStateDb(homeDir = process.env.HOME) {
|
|
63
150
|
const Database = require('better-sqlite3');
|
|
64
151
|
const dbPath = path.join(homeDir, '.codex', 'state_5.sqlite');
|
|
@@ -147,7 +234,7 @@ function resolveModelToRegistry(modelName) {
|
|
|
147
234
|
return { model_id: modelName, model_provider: provider };
|
|
148
235
|
}
|
|
149
236
|
|
|
150
|
-
function createCodingAgentModelSync({ sessions, dbModule, broadcastSessionList }) {
|
|
237
|
+
function createCodingAgentModelSync({ sessions, dbModule, broadcastSessionList, resolveClaudeJsonlPath, resolveAgentModelsOffThread }) {
|
|
151
238
|
const agentModelCache = {};
|
|
152
239
|
let agentModelCacheTime = 0;
|
|
153
240
|
|
|
@@ -156,11 +243,23 @@ function createCodingAgentModelSync({ sessions, dbModule, broadcastSessionList }
|
|
|
156
243
|
if (!agentType) return null;
|
|
157
244
|
|
|
158
245
|
const now = Date.now();
|
|
246
|
+
|
|
247
|
+
// For claude, resolve the transcript path up front. session.jsonlPath is
|
|
248
|
+
// only populated by the JSONL file-watcher on a write event, so idle and
|
|
249
|
+
// freshly-restored sessions lack it even though the transcript on disk
|
|
250
|
+
// already records the model — leaving the picker stuck on "(detecting…)".
|
|
251
|
+
// resolveClaudeJsonlPath derives the deterministic path
|
|
252
|
+
// (~/.claude/projects/<encoded-cwd>/<agentSessionId>.jsonl) so detection
|
|
253
|
+
// works without waiting for the next write.
|
|
254
|
+
const claudeJsonlPath = agentType === 'claude'
|
|
255
|
+
? (session.jsonlPath || (resolveClaudeJsonlPath ? resolveClaudeJsonlPath(session) : '') || '')
|
|
256
|
+
: '';
|
|
257
|
+
|
|
159
258
|
// Per-session cache key for claude too because JSONL fallback is
|
|
160
259
|
// per-session. Codex also includes the matched thread id because it can
|
|
161
260
|
// be discovered after spawn.
|
|
162
261
|
const cacheKey = agentType === 'claude'
|
|
163
|
-
? `claude:${session.id}:${
|
|
262
|
+
? `claude:${session.id}:${claudeJsonlPath}`
|
|
164
263
|
: agentType === 'codex'
|
|
165
264
|
? `codex:${session.id}:${session._claudeSessionId || ''}`
|
|
166
265
|
: agentType;
|
|
@@ -172,13 +271,21 @@ function createCodingAgentModelSync({ sessions, dbModule, broadcastSessionList }
|
|
|
172
271
|
let modelName = null;
|
|
173
272
|
switch (agentType) {
|
|
174
273
|
case 'claude':
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
modelName =
|
|
274
|
+
// The JSONL transcript is the historical source of truth because it
|
|
275
|
+
// records what the API actually resolved on the latest assistant turn.
|
|
276
|
+
// Claude Code also rewrites settings.json immediately when the user
|
|
277
|
+
// changes the selected model, before the next assistant turn exists.
|
|
278
|
+
// Prefer that newer live selection only when its mtime is newer than
|
|
279
|
+
// the latest assistant turn timestamp; otherwise keep JSONL precedence.
|
|
280
|
+
modelName = getClaudeSessionModelName({
|
|
281
|
+
jsonlPath: claudeJsonlPath,
|
|
282
|
+
sessionActivityMs: Math.max(
|
|
283
|
+
_coerceTimeMs(session.lastActivity),
|
|
284
|
+
_coerceTimeMs(session.lastPtyActivity),
|
|
285
|
+
_coerceTimeMs(session.updatedAt),
|
|
286
|
+
_coerceTimeMs(session.createdAt)
|
|
287
|
+
),
|
|
288
|
+
});
|
|
182
289
|
break;
|
|
183
290
|
case 'codex':
|
|
184
291
|
modelName = session._claudeSessionId
|
|
@@ -248,10 +355,103 @@ function createCodingAgentModelSync({ sessions, dbModule, broadcastSessionList }
|
|
|
248
355
|
if (changed && typeof broadcastSessionList === 'function') broadcastSessionList();
|
|
249
356
|
}
|
|
250
357
|
|
|
358
|
+
// Off-main-loop variant of syncCodingSessionModels. The fs/DB-heavy resolution (claude JSONL
|
|
359
|
+
// scan + Codex state-DB reads + getCodexThreadTitleById) runs on the read-pool worker via
|
|
360
|
+
// resolveAgentModelsOffThread; only the small DECIDE/APPLY work (model→registry mapping, the
|
|
361
|
+
// CTM-DB title decision, mutating the in-memory session) stays on main. On pool
|
|
362
|
+
// unavailable/timeout (returns null) we SKIP the tick rather than dragging the work back onto
|
|
363
|
+
// the loop — model/title detection is best-effort UI sugar and converges next tick.
|
|
364
|
+
async function syncCodingSessionModelsOffThread() {
|
|
365
|
+
if (typeof resolveAgentModelsOffThread !== 'function') return syncCodingSessionModels();
|
|
366
|
+
let changed = false;
|
|
367
|
+
const items = [];
|
|
368
|
+
const ctx = []; // parallel to items: { session, agentType, wantCodexTitle }
|
|
369
|
+
for (const [, session] of sessions) {
|
|
370
|
+
const agentType = detectAgentType(session.cmd);
|
|
371
|
+
if (!agentType) continue;
|
|
372
|
+
if (agentType === 'gemini') {
|
|
373
|
+
// Pure arg-parse + registry map — no fs/DB; resolve inline on main.
|
|
374
|
+
const model = getSessionAgentModel(session);
|
|
375
|
+
if (model && session.model_id !== model.model_id) {
|
|
376
|
+
session.model_id = model.model_id;
|
|
377
|
+
session.model_provider = model.model_provider;
|
|
378
|
+
changed = true;
|
|
379
|
+
}
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
const claudeJsonlPath = agentType === 'claude'
|
|
383
|
+
? (session.jsonlPath || (resolveClaudeJsonlPath ? resolveClaudeJsonlPath(session) : '') || '')
|
|
384
|
+
: '';
|
|
385
|
+
// Codex title DECISION runs on main (cheap CTM-DB read). Only the actual Codex-DB title
|
|
386
|
+
// FETCH is offloaded (wantCodexTitle). Mirrors the sync version's branches exactly.
|
|
387
|
+
let wantCodexTitle = false;
|
|
388
|
+
if (agentType === 'codex' && !session._codexTitleSynced) {
|
|
389
|
+
const existingTitle = dbModule.getSessionTitleNew(session.id);
|
|
390
|
+
if (existingTitle && existingTitle.userRenamed) {
|
|
391
|
+
session._codexTitleSynced = true;
|
|
392
|
+
} else if (!shouldApplyCodexAutoTitle({ session, existingTitle })) {
|
|
393
|
+
const liveLabel = normalizeTitleText(session.label);
|
|
394
|
+
if (liveLabel
|
|
395
|
+
&& !isGenericCodingSessionLabel(liveLabel, 'codex')
|
|
396
|
+
&& (!existingTitle || normalizeTitleText(existingTitle.title) !== liveLabel)) {
|
|
397
|
+
dbModule.setSessionTitleNew(session.id, liveLabel, false);
|
|
398
|
+
changed = true;
|
|
399
|
+
}
|
|
400
|
+
session._codexTitleSynced = true;
|
|
401
|
+
} else {
|
|
402
|
+
wantCodexTitle = !!session._claudeSessionId;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
items.push({
|
|
406
|
+
id: session.id,
|
|
407
|
+
agentType,
|
|
408
|
+
claudeJsonlPath,
|
|
409
|
+
sessionActivityMs: Math.max(
|
|
410
|
+
_coerceTimeMs(session.lastActivity),
|
|
411
|
+
_coerceTimeMs(session.lastPtyActivity),
|
|
412
|
+
_coerceTimeMs(session.updatedAt),
|
|
413
|
+
_coerceTimeMs(session.createdAt)
|
|
414
|
+
),
|
|
415
|
+
codexThreadId: session._claudeSessionId || null,
|
|
416
|
+
wantCodexTitle,
|
|
417
|
+
});
|
|
418
|
+
ctx.push({ session, agentType, wantCodexTitle });
|
|
419
|
+
}
|
|
420
|
+
if (items.length === 0) {
|
|
421
|
+
if (changed && typeof broadcastSessionList === 'function') broadcastSessionList();
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const results = await resolveAgentModelsOffThread(items);
|
|
425
|
+
if (!results) {
|
|
426
|
+
// Pool unavailable/timeout → skip this tick (do not run the heavy resolve on main).
|
|
427
|
+
if (changed && typeof broadcastSessionList === 'function') broadcastSessionList();
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
const byId = new Map(results.map((r) => [r.id, r]));
|
|
431
|
+
for (const { session, agentType, wantCodexTitle } of ctx) {
|
|
432
|
+
const r = byId.get(session.id);
|
|
433
|
+
if (!r) continue;
|
|
434
|
+
const model = resolveModelToRegistry(r.modelName);
|
|
435
|
+
if (model && session.model_id !== model.model_id) {
|
|
436
|
+
session.model_id = model.model_id;
|
|
437
|
+
session.model_provider = model.model_provider;
|
|
438
|
+
changed = true;
|
|
439
|
+
}
|
|
440
|
+
if (agentType === 'codex' && wantCodexTitle && r.codexTitle) {
|
|
441
|
+
session.label = `Codex: ${r.codexTitle}`;
|
|
442
|
+
session._codexTitleSynced = true;
|
|
443
|
+
dbModule.setSessionTitleNew(session.id, session.label, false);
|
|
444
|
+
changed = true;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (changed && typeof broadcastSessionList === 'function') broadcastSessionList();
|
|
448
|
+
}
|
|
449
|
+
|
|
251
450
|
return {
|
|
252
451
|
detectAgentType,
|
|
253
452
|
getSessionAgentModel,
|
|
254
453
|
syncCodingSessionModels,
|
|
454
|
+
syncCodingSessionModelsOffThread,
|
|
255
455
|
};
|
|
256
456
|
}
|
|
257
457
|
|
|
@@ -260,6 +460,9 @@ module.exports = {
|
|
|
260
460
|
detectAgentType,
|
|
261
461
|
getClaudeCodeModel,
|
|
262
462
|
getClaudeCodeModelFromJsonl,
|
|
463
|
+
getClaudeCodeModelInfoFromJsonl,
|
|
464
|
+
getClaudeCodeModelSelection,
|
|
465
|
+
getClaudeSessionModelName,
|
|
263
466
|
getCodexThreadModel,
|
|
264
467
|
getCodexThreadTitleById,
|
|
265
468
|
getCodexLatestModel,
|