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,678 @@
|
|
|
1
|
+
// --- Headless Terminal Worker Thread ---
|
|
2
|
+
// Maintains a @xterm/headless Terminal instance per session (no renderer cost).
|
|
3
|
+
// Replaces vterm-worker.js: full xterm.js parser is more accurate for ANSI
|
|
4
|
+
// parsing than the custom VTermScreen, and the serialize addon enables instant
|
|
5
|
+
// terminal state snapshots for tab-switch restore.
|
|
6
|
+
//
|
|
7
|
+
// Message protocol:
|
|
8
|
+
// Main → Worker:
|
|
9
|
+
// { type: 'create', sessionId, cols, rows }
|
|
10
|
+
// { type: 'feed', sessionId, data, requestId? }
|
|
11
|
+
// { type: 'resize', sessionId, cols, rows }
|
|
12
|
+
// { type: 'serialize', sessionId, requestId, scrollback? }
|
|
13
|
+
// { type: 'fingerprint', sessionId, requestId, cols, rows }
|
|
14
|
+
// { type: 'destroy', sessionId }
|
|
15
|
+
// { type: 'reset', sessionId }
|
|
16
|
+
// { type: 'recheck', sessionId, requestId }
|
|
17
|
+
// { type: 'getText', sessionId, requestId }
|
|
18
|
+
// { type: 'getViewportText', sessionId, requestId }
|
|
19
|
+
// { type: 'getRows', sessionId, requestId }
|
|
20
|
+
//
|
|
21
|
+
// Worker → Main:
|
|
22
|
+
// { type: 'feed-result', sessionId, requestId, hasApproval, text?, rawDetected?, rawText?, debugLines }
|
|
23
|
+
// { type: 'serialized', sessionId, requestId, data, cols, rows, fp }
|
|
24
|
+
// { type: 'fingerprinted', sessionId, requestId, fp, cols, rows, scrollbackLen }
|
|
25
|
+
// { type: 'text', sessionId, requestId, text }
|
|
26
|
+
// { type: 'rows', sessionId, requestId, rows: [{ text, wrapped }] }
|
|
27
|
+
|
|
28
|
+
const { Terminal } = require('@xterm/headless');
|
|
29
|
+
const { SerializeAddon } = require('@xterm/addon-serialize');
|
|
30
|
+
const { fingerprintRows, EMPTY_FINGERPRINT } = require('./terminal-fingerprint');
|
|
31
|
+
|
|
32
|
+
const { detectApproval, detectApprovalWithProvider } = require('../workers/approval-patterns');
|
|
33
|
+
const { validateWidget } = require('../workers/approval-widget-validator');
|
|
34
|
+
const {
|
|
35
|
+
MAX_SNAPSHOT_SCROLLBACK_ROWS,
|
|
36
|
+
normalizeSnapshotScrollbackRows,
|
|
37
|
+
} = require('./terminal-snapshot-options');
|
|
38
|
+
|
|
39
|
+
let postMessage = () => {};
|
|
40
|
+
|
|
41
|
+
// Phase 1 temporal thresholds. Tuned empirically: Claude Code stops
|
|
42
|
+
// streaming output ~50ms before showing the prompt; cursor settles within
|
|
43
|
+
// a few ms of the final widget draw. We require a margin.
|
|
44
|
+
const CURSOR_STABLE_MS = 200;
|
|
45
|
+
const OUTPUT_QUIESCENT_MS = 100;
|
|
46
|
+
const DIRECT_APPROVAL_SCAN_INTERVAL_MS = 150;
|
|
47
|
+
|
|
48
|
+
// Phase 3 cooldown: if the post-keystroke verification fails, we disable
|
|
49
|
+
// auto-approval for this session for this window. Prevents a chain of
|
|
50
|
+
// false keystrokes from a persistent false positive.
|
|
51
|
+
const VERIFY_FAIL_COOLDOWN_MS = 30 * 1000;
|
|
52
|
+
|
|
53
|
+
// Per-session headless terminal instances + state
|
|
54
|
+
const terminals = new Map(); // sessionId -> { term, serialize, state }
|
|
55
|
+
|
|
56
|
+
function getOrCreate(sessionId, cols = 120, rows = 30) {
|
|
57
|
+
let entry = terminals.get(sessionId);
|
|
58
|
+
if (!entry) {
|
|
59
|
+
const term = new Terminal({
|
|
60
|
+
cols,
|
|
61
|
+
rows,
|
|
62
|
+
scrollback: MAX_SNAPSHOT_SCROLLBACK_ROWS,
|
|
63
|
+
allowProposedApi: true,
|
|
64
|
+
});
|
|
65
|
+
const serialize = new SerializeAddon();
|
|
66
|
+
term.loadAddon(serialize);
|
|
67
|
+
entry = {
|
|
68
|
+
term,
|
|
69
|
+
serialize,
|
|
70
|
+
state: {
|
|
71
|
+
cursorY: -1, cursorX: -1,
|
|
72
|
+
lastCursorMoveAt: 0,
|
|
73
|
+
lastOutputAt: 0,
|
|
74
|
+
nextDirectApprovalScanAt: 0,
|
|
75
|
+
// Phase 3 verification: set by main thread after it fires a keystroke;
|
|
76
|
+
// worker skips emitting approval-alert while this is in the future.
|
|
77
|
+
verifyUntil: 0,
|
|
78
|
+
// Phase 3 cooldown: set when verification fails; skip all detection
|
|
79
|
+
cooldownUntil: 0,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
terminals.set(sessionId, entry);
|
|
83
|
+
}
|
|
84
|
+
return entry;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Snapshot the current cursor position; update stability timestamps.
|
|
89
|
+
* Called after each feed. Returns the state object.
|
|
90
|
+
*/
|
|
91
|
+
function _trackCursor(entry) {
|
|
92
|
+
const now = Date.now();
|
|
93
|
+
const buf = entry.term.buffer.active;
|
|
94
|
+
const y = buf.cursorY;
|
|
95
|
+
const x = buf.cursorX;
|
|
96
|
+
const s = entry.state;
|
|
97
|
+
if (s.cursorY !== y || s.cursorX !== x) {
|
|
98
|
+
s.cursorY = y;
|
|
99
|
+
s.cursorX = x;
|
|
100
|
+
s.lastCursorMoveAt = now;
|
|
101
|
+
}
|
|
102
|
+
s.lastOutputAt = now;
|
|
103
|
+
return s;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Phase 1 temporal gate: cursor stable, output quiescent.
|
|
108
|
+
*/
|
|
109
|
+
function _temporalGateOk(state) {
|
|
110
|
+
const now = Date.now();
|
|
111
|
+
const cursorAge = now - state.lastCursorMoveAt;
|
|
112
|
+
const outputAge = now - state.lastOutputAt;
|
|
113
|
+
return cursorAge >= CURSOR_STABLE_MS && outputAge >= OUTPUT_QUIESCENT_MS;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Full gate check — combines Phase 1 temporal + Phase 2 structural +
|
|
118
|
+
* Phase 3 cooldown. Returns { ok, reason }.
|
|
119
|
+
*
|
|
120
|
+
* The order matters for debugging: cheap checks first.
|
|
121
|
+
*/
|
|
122
|
+
function _gateApproval(entry, _text) {
|
|
123
|
+
const { state, term } = entry;
|
|
124
|
+
const now = Date.now();
|
|
125
|
+
|
|
126
|
+
// Phase 3: cooldown after verification failure
|
|
127
|
+
if (state.cooldownUntil > now) {
|
|
128
|
+
return { ok: false, reason: 'cooldown' };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Phase 3: in the verification window from a previous keystroke — skip
|
|
132
|
+
if (state.verifyUntil > now) {
|
|
133
|
+
return { ok: false, reason: 'verify-window' };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Phase 1: temporal gate (note: temporal is a SOFT signal — we still
|
|
137
|
+
// require structural widget detection below, so temporal failure alone
|
|
138
|
+
// doesn't reject; we log it as a signal)
|
|
139
|
+
// TEMPORAL IS DISABLED IN RECHECK PATH because the recheck fires on a
|
|
140
|
+
// timer with no fresh output — both ages would always pass. Keep the
|
|
141
|
+
// temporal check advisory only; structural is the primary gate.
|
|
142
|
+
// const temporalOk = _temporalGateOk(state);
|
|
143
|
+
|
|
144
|
+
// Phase 1+2: structural widget validation. Requires alt-screen active,
|
|
145
|
+
// "1. Yes" in bottom rows, widget-like formatting (color or ❯).
|
|
146
|
+
const widget = validateWidget(term);
|
|
147
|
+
if (!widget.valid) {
|
|
148
|
+
return { ok: false, reason: `widget:${widget.reason}` };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return { ok: true, reason: 'ok' };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Throttle log spam — one line per (session, reason) per 10s.
|
|
155
|
+
const _gateMissLog = new Map(); // sessionId -> { reason -> lastLoggedAt }
|
|
156
|
+
function _debugLinesFromText(text) {
|
|
157
|
+
return String(text || '')
|
|
158
|
+
.split('\n')
|
|
159
|
+
.filter(l => l.trim())
|
|
160
|
+
.slice(-3)
|
|
161
|
+
.map(l => l.trim().slice(0, 80));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function _logGateMiss(sessionId, reason, details = {}) {
|
|
165
|
+
const now = Date.now();
|
|
166
|
+
let bySession = _gateMissLog.get(sessionId);
|
|
167
|
+
if (!bySession) { bySession = new Map(); _gateMissLog.set(sessionId, bySession); }
|
|
168
|
+
const last = bySession.get(reason) || 0;
|
|
169
|
+
if (now - last < 10000) return;
|
|
170
|
+
bySession.set(reason, now);
|
|
171
|
+
// Emit a diagnostic to the main thread — main thread logs with session tag
|
|
172
|
+
postMessage({
|
|
173
|
+
type: 'gate-miss',
|
|
174
|
+
sessionId,
|
|
175
|
+
reason,
|
|
176
|
+
source: details.source || 'realtime',
|
|
177
|
+
providerId: details.providerId || null,
|
|
178
|
+
rawDetected: !!details.rawDetected,
|
|
179
|
+
rawText: details.rawText || null,
|
|
180
|
+
debugLines: details.debugLines || _debugLinesFromText(details.rawText || ''),
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function _approvalOutputHasHint(text) {
|
|
185
|
+
if (!text) return false;
|
|
186
|
+
return /do you want|proceed|approve|approval|permission|allow|\byes\b|\bno\b|run this command|bash|edit|tool use|❯|1\.\s*yes|2\.\s*no/i.test(String(text));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Extract visible text from the terminal buffer (for approval detection).
|
|
190
|
+
// Reads the viewport plus a window of scrollback above it so that prompts
|
|
191
|
+
// taller than the viewport (e.g. a Codex prompt with a long heredoc command)
|
|
192
|
+
// still expose their question/reason/command lines — those scroll above
|
|
193
|
+
// viewportY but are still in `buffer.active` for as long as scrollback holds
|
|
194
|
+
// them. Without the scrollback window, only the bottom 3-5 lines of the
|
|
195
|
+
// option list survive and parsers like codex.parse() fail.
|
|
196
|
+
//
|
|
197
|
+
// 80 rows = ~2 viewports of headroom on a typical 30-row terminal. Wider
|
|
198
|
+
// than any Codex prompt observed in production while bounding the scan cost.
|
|
199
|
+
const APPROVAL_SCROLLBACK_ROWS = 80;
|
|
200
|
+
function getVisibleText(term) {
|
|
201
|
+
const buf = term.buffer.active;
|
|
202
|
+
const lines = [];
|
|
203
|
+
const start = Math.max(0, buf.viewportY - APPROVAL_SCROLLBACK_ROWS);
|
|
204
|
+
const end = buf.viewportY + term.rows;
|
|
205
|
+
for (let i = start; i < end; i++) {
|
|
206
|
+
const line = buf.getLine(i);
|
|
207
|
+
if (line) lines.push(line.translateToString(true));
|
|
208
|
+
}
|
|
209
|
+
return lines.join('\n');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function getViewportText(term) {
|
|
213
|
+
const buf = term.buffer.active;
|
|
214
|
+
const lines = [];
|
|
215
|
+
const start = buf.viewportY;
|
|
216
|
+
const end = buf.viewportY + term.rows;
|
|
217
|
+
for (let i = start; i < end; i++) {
|
|
218
|
+
const line = buf.getLine(i);
|
|
219
|
+
if (line) lines.push(line.translateToString(true));
|
|
220
|
+
}
|
|
221
|
+
return lines.join('\n');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Fingerprint of the visible grid at the terminal's CURRENT dims. Shared by the
|
|
225
|
+
// `serialize` and `fingerprint` ops so a snapshot can carry its own content fp and
|
|
226
|
+
// the client can skip a destructive re-render when its buffer already matches.
|
|
227
|
+
function viewportFingerprint(term) {
|
|
228
|
+
const buf = term.buffer.active;
|
|
229
|
+
const rows = term.rows;
|
|
230
|
+
const start = buf.viewportY;
|
|
231
|
+
const rowStrings = [];
|
|
232
|
+
for (let i = 0; i < rows; i++) {
|
|
233
|
+
const line = buf.getLine(start + i);
|
|
234
|
+
rowStrings.push(line ? line.translateToString(true) : '');
|
|
235
|
+
}
|
|
236
|
+
const scrollbackLen = Math.max(0, buf.length - rows);
|
|
237
|
+
return fingerprintRows(rowStrings, { cols: term.cols, rows, scrollbackLen });
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function getVisibleRows(term) {
|
|
241
|
+
const buf = term.buffer.active;
|
|
242
|
+
const rows = [];
|
|
243
|
+
const start = Math.max(0, buf.viewportY - APPROVAL_SCROLLBACK_ROWS);
|
|
244
|
+
const end = buf.viewportY + term.rows;
|
|
245
|
+
for (let i = start; i < end; i++) {
|
|
246
|
+
const line = buf.getLine(i);
|
|
247
|
+
if (line) {
|
|
248
|
+
rows.push({
|
|
249
|
+
text: line.translateToString(true),
|
|
250
|
+
wrapped: !!line.isWrapped,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return rows;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Queue for pending writes — headless xterm.js write() is async (uses microtask),
|
|
258
|
+
// so we need to sequence operations that depend on write completion.
|
|
259
|
+
const writeQueues = new Map(); // sessionId -> Promise chain
|
|
260
|
+
|
|
261
|
+
// Bound how long a single xterm.js write can block the queue. In rare cases
|
|
262
|
+
// (memory pressure, specific ANSI sequences that trip an internal bug)
|
|
263
|
+
// `entry.term.write(data, callback)` fails to invoke the callback, which would
|
|
264
|
+
// otherwise permanently stall the session's write chain — and with it, all
|
|
265
|
+
// approval detection (both direct-feed and recheck await the queue). When
|
|
266
|
+
// this fires we force-advance: the terminal state may be slightly stale for
|
|
267
|
+
// this one chunk, but new writes unblock and detection resumes.
|
|
268
|
+
const WRITE_TIMEOUT_MS = 5000;
|
|
269
|
+
// Telemetry: how many times each session tripped the timeout. Surfaced to
|
|
270
|
+
// the main thread via 'write-stall' messages so the UI can show a degraded
|
|
271
|
+
// badge rather than leaving the user guessing why auto-approve is silent.
|
|
272
|
+
const _writeStallCounts = new Map(); // sessionId -> count
|
|
273
|
+
|
|
274
|
+
function enqueueWrite(sessionId, data) {
|
|
275
|
+
const entry = getOrCreate(sessionId);
|
|
276
|
+
const prev = writeQueues.get(sessionId) || Promise.resolve();
|
|
277
|
+
const next = prev.then(() => new Promise(resolve => {
|
|
278
|
+
let settled = false;
|
|
279
|
+
const timer = setTimeout(() => {
|
|
280
|
+
if (settled) return;
|
|
281
|
+
settled = true;
|
|
282
|
+
const count = (_writeStallCounts.get(sessionId) || 0) + 1;
|
|
283
|
+
_writeStallCounts.set(sessionId, count);
|
|
284
|
+
try {
|
|
285
|
+
postMessage({ type: 'write-stall', sessionId, count, timeoutMs: WRITE_TIMEOUT_MS });
|
|
286
|
+
} catch {}
|
|
287
|
+
resolve();
|
|
288
|
+
}, WRITE_TIMEOUT_MS);
|
|
289
|
+
entry.term.write(data, () => {
|
|
290
|
+
if (settled) return;
|
|
291
|
+
settled = true;
|
|
292
|
+
clearTimeout(timer);
|
|
293
|
+
resolve();
|
|
294
|
+
});
|
|
295
|
+
}));
|
|
296
|
+
// Periodically reset the promise chain to prevent unbounded growth.
|
|
297
|
+
// After the write completes, replace the chain with a fresh resolved promise.
|
|
298
|
+
const reset = next.then(() => {
|
|
299
|
+
if (writeQueues.get(sessionId) === reset) writeQueues.set(sessionId, Promise.resolve());
|
|
300
|
+
});
|
|
301
|
+
writeQueues.set(sessionId, reset);
|
|
302
|
+
return next;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Bounded wait for the pending-writes queue before reading terminal state.
|
|
306
|
+
// Routine detection passes intentionally use a short wait so they stay cheap.
|
|
307
|
+
// Authoritative snapshots, especially the final Codex exit snapshot, can opt
|
|
308
|
+
// into a longer bounded wait because they become the persisted terminal truth.
|
|
309
|
+
const QUEUE_WAIT_TIMEOUT_MS = 2000;
|
|
310
|
+
const MAX_QUEUE_WAIT_TIMEOUT_MS = 15000;
|
|
311
|
+
function normalizeQueueWaitTimeoutMs(value) {
|
|
312
|
+
if (!Number.isFinite(Number(value))) return QUEUE_WAIT_TIMEOUT_MS;
|
|
313
|
+
return Math.max(0, Math.min(MAX_QUEUE_WAIT_TIMEOUT_MS, Number(value)));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function _awaitQueueBounded(sessionId, timeoutMs = QUEUE_WAIT_TIMEOUT_MS) {
|
|
317
|
+
const queue = writeQueues.get(sessionId);
|
|
318
|
+
if (!queue) return;
|
|
319
|
+
const boundedTimeoutMs = normalizeQueueWaitTimeoutMs(timeoutMs);
|
|
320
|
+
let timer;
|
|
321
|
+
const timeoutPromise = new Promise(resolve => {
|
|
322
|
+
timer = setTimeout(resolve, boundedTimeoutMs);
|
|
323
|
+
});
|
|
324
|
+
await Promise.race([queue, timeoutPromise]);
|
|
325
|
+
if (timer) clearTimeout(timer);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const opQueues = new Map(); // sessionId -> Promise chain for feed/serialize/destroy ordering
|
|
329
|
+
|
|
330
|
+
function enqueueSessionOp(sessionId, fn) {
|
|
331
|
+
const prev = opQueues.get(sessionId) || Promise.resolve();
|
|
332
|
+
let next;
|
|
333
|
+
next = prev
|
|
334
|
+
.catch(() => {})
|
|
335
|
+
.then(fn)
|
|
336
|
+
.catch((err) => {
|
|
337
|
+
try {
|
|
338
|
+
postMessage({
|
|
339
|
+
type: 'worker-error',
|
|
340
|
+
sessionId,
|
|
341
|
+
message: err && err.message ? err.message : String(err),
|
|
342
|
+
});
|
|
343
|
+
} catch {}
|
|
344
|
+
})
|
|
345
|
+
.finally(() => {
|
|
346
|
+
if (opQueues.get(sessionId) === next) opQueues.delete(sessionId);
|
|
347
|
+
});
|
|
348
|
+
opQueues.set(sessionId, next);
|
|
349
|
+
return next;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async function handleMessage(msg) {
|
|
353
|
+
switch (msg.type) {
|
|
354
|
+
case 'create': {
|
|
355
|
+
getOrCreate(msg.sessionId, msg.cols, msg.rows);
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
case 'feed': {
|
|
360
|
+
// Feed data into the headless terminal buffer. Two modes:
|
|
361
|
+
//
|
|
362
|
+
// 1. Direct feed (no requestId): from PTY onData — keeps headless terminal
|
|
363
|
+
// current for snapshots. Also runs lightweight approval detection and sends
|
|
364
|
+
// an immediate 'approval-alert' if found. This catches prompts the instant
|
|
365
|
+
// they render, regardless of main-thread CPU load or throttle state.
|
|
366
|
+
//
|
|
367
|
+
// 2. Throttled feed (has requestId): from the approval engine's recheck cycle.
|
|
368
|
+
// Sends full feed-result with hasApproval flag. Acts as safety-net fallback
|
|
369
|
+
// for prompts missed by the direct-feed path (e.g. multi-chunk rendering).
|
|
370
|
+
await enqueueWrite(msg.sessionId, msg.data);
|
|
371
|
+
|
|
372
|
+
const entry = terminals.get(msg.sessionId);
|
|
373
|
+
if (!entry) break;
|
|
374
|
+
|
|
375
|
+
// Phase 1: track cursor/output movement for temporal gating below.
|
|
376
|
+
// Called for BOTH direct-feed and throttled-feed so state is always fresh.
|
|
377
|
+
_trackCursor(entry);
|
|
378
|
+
|
|
379
|
+
if (msg.requestId == null) {
|
|
380
|
+
// Direct feed — run real-time approval detection.
|
|
381
|
+
if (!_approvalOutputHasHint(msg.data)) break;
|
|
382
|
+
const now = Date.now();
|
|
383
|
+
if (entry.state.nextDirectApprovalScanAt && now < entry.state.nextDirectApprovalScanAt) break;
|
|
384
|
+
entry.state.nextDirectApprovalScanAt = now + DIRECT_APPROVAL_SCAN_INTERVAL_MS;
|
|
385
|
+
const text = getVisibleText(entry.term);
|
|
386
|
+
const { detected, providerId } = detectApprovalWithProvider(text);
|
|
387
|
+
if (!detected) break;
|
|
388
|
+
// Phase 1/2/3 gates — see _gateApproval for reasoning.
|
|
389
|
+
const gate = _gateApproval(entry, text);
|
|
390
|
+
if (!gate.ok) {
|
|
391
|
+
// Log once per reason per session to avoid spam.
|
|
392
|
+
_logGateMiss(msg.sessionId, gate.reason, {
|
|
393
|
+
source: 'realtime',
|
|
394
|
+
providerId,
|
|
395
|
+
rawDetected: true,
|
|
396
|
+
rawText: text,
|
|
397
|
+
});
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
postMessage({
|
|
401
|
+
type: 'approval-alert',
|
|
402
|
+
sessionId: msg.sessionId,
|
|
403
|
+
providerId,
|
|
404
|
+
text,
|
|
405
|
+
});
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Throttled recheck path (safety net)
|
|
410
|
+
const text = getVisibleText(entry.term);
|
|
411
|
+
const { detected: hasApprovalRaw, providerId } = detectApprovalWithProvider(text);
|
|
412
|
+
const hintDetected = _approvalOutputHasHint(text);
|
|
413
|
+
// Apply same gating to the throttled path — hasApproval reflects gated decision.
|
|
414
|
+
let gatedApproval = hasApprovalRaw;
|
|
415
|
+
let gateReason = null;
|
|
416
|
+
if (hasApprovalRaw) {
|
|
417
|
+
const gate = _gateApproval(entry, text);
|
|
418
|
+
if (!gate.ok) { gatedApproval = false; gateReason = gate.reason; }
|
|
419
|
+
}
|
|
420
|
+
const debugLines = _debugLinesFromText(text);
|
|
421
|
+
|
|
422
|
+
postMessage({
|
|
423
|
+
type: 'feed-result',
|
|
424
|
+
sessionId: msg.sessionId,
|
|
425
|
+
requestId: msg.requestId,
|
|
426
|
+
hasApproval: gatedApproval,
|
|
427
|
+
providerId,
|
|
428
|
+
text: gatedApproval ? text : null,
|
|
429
|
+
rawDetected: hasApprovalRaw,
|
|
430
|
+
hintDetected,
|
|
431
|
+
rawText: hasApprovalRaw || hintDetected ? text : null,
|
|
432
|
+
debugLines,
|
|
433
|
+
gateReason,
|
|
434
|
+
});
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
case 'recheck': {
|
|
439
|
+
// Re-evaluate current screen without feeding new data
|
|
440
|
+
const entry = terminals.get(msg.sessionId);
|
|
441
|
+
if (!entry) {
|
|
442
|
+
// Send empty result so main thread's _workerPending gets cleared
|
|
443
|
+
if (msg.requestId != null) {
|
|
444
|
+
postMessage({
|
|
445
|
+
type: 'feed-result', sessionId: msg.sessionId,
|
|
446
|
+
requestId: msg.requestId, hasApproval: false, providerId: null, text: null,
|
|
447
|
+
rawDetected: false, rawText: null, debugLines: [],
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
// Wait for any pending writes to complete (bounded — do not hang forever
|
|
453
|
+
// on a stuck write queue)
|
|
454
|
+
await _awaitQueueBounded(msg.sessionId);
|
|
455
|
+
|
|
456
|
+
const text = getVisibleText(entry.term);
|
|
457
|
+
const { detected: hasApprovalRaw, providerId } = detectApprovalWithProvider(text);
|
|
458
|
+
const hintDetected = _approvalOutputHasHint(text);
|
|
459
|
+
// Apply full gating on recheck too (structural + cooldown).
|
|
460
|
+
// Temporal gate is skipped here because recheck fires without fresh
|
|
461
|
+
// output — the structural widget validator is the primary signal.
|
|
462
|
+
let hasApproval = hasApprovalRaw;
|
|
463
|
+
let gateReason = null;
|
|
464
|
+
if (hasApprovalRaw) {
|
|
465
|
+
const gate = _gateApproval(entry, text);
|
|
466
|
+
if (!gate.ok) { hasApproval = false; gateReason = gate.reason; }
|
|
467
|
+
}
|
|
468
|
+
const debugLines = _debugLinesFromText(text);
|
|
469
|
+
|
|
470
|
+
postMessage({
|
|
471
|
+
type: 'feed-result',
|
|
472
|
+
sessionId: msg.sessionId,
|
|
473
|
+
requestId: msg.requestId,
|
|
474
|
+
hasApproval,
|
|
475
|
+
providerId,
|
|
476
|
+
text: hasApproval ? text : null,
|
|
477
|
+
rawDetected: hasApprovalRaw,
|
|
478
|
+
hintDetected,
|
|
479
|
+
rawText: hasApprovalRaw || hintDetected ? text : null,
|
|
480
|
+
debugLines,
|
|
481
|
+
gateReason,
|
|
482
|
+
});
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
case 'verify-start': {
|
|
487
|
+
// Phase 3: main thread just wrote a keystroke. Enter verification
|
|
488
|
+
// window — skip all approval detection until verify-end or window expires.
|
|
489
|
+
const entry = terminals.get(msg.sessionId);
|
|
490
|
+
if (!entry) break;
|
|
491
|
+
entry.state.verifyUntil = Date.now() + (msg.windowMs || 500);
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
case 'verify-end': {
|
|
496
|
+
// Phase 3: main thread observed outcome. If verification failed
|
|
497
|
+
// (the keystroke produced no state transition), enter cooldown.
|
|
498
|
+
const entry = terminals.get(msg.sessionId);
|
|
499
|
+
if (!entry) break;
|
|
500
|
+
entry.state.verifyUntil = 0;
|
|
501
|
+
if (msg.failed) {
|
|
502
|
+
entry.state.cooldownUntil = Date.now() + VERIFY_FAIL_COOLDOWN_MS;
|
|
503
|
+
}
|
|
504
|
+
break;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
case 'resize': {
|
|
508
|
+
const entry = terminals.get(msg.sessionId);
|
|
509
|
+
if (entry) entry.term.resize(msg.cols, msg.rows);
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
case 'serialize': {
|
|
514
|
+
const entry = terminals.get(msg.sessionId);
|
|
515
|
+
if (!entry) {
|
|
516
|
+
postMessage({
|
|
517
|
+
type: 'serialized', sessionId: msg.sessionId,
|
|
518
|
+
requestId: msg.requestId, data: '', cols: 120, rows: 30,
|
|
519
|
+
fp: EMPTY_FINGERPRINT,
|
|
520
|
+
});
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
// Wait for any pending writes to complete before serializing (bounded).
|
|
524
|
+
// Final-exit snapshots pass a longer wait so a large final PTY burst
|
|
525
|
+
// cannot be serialized before xterm has applied it.
|
|
526
|
+
await _awaitQueueBounded(msg.sessionId, msg.queueWaitTimeoutMs);
|
|
527
|
+
|
|
528
|
+
const scrollback = normalizeSnapshotScrollbackRows(msg.scrollback);
|
|
529
|
+
const data = entry.serialize.serialize({ scrollback });
|
|
530
|
+
postMessage({
|
|
531
|
+
type: 'serialized',
|
|
532
|
+
sessionId: msg.sessionId,
|
|
533
|
+
requestId: msg.requestId,
|
|
534
|
+
data,
|
|
535
|
+
cols: entry.term.cols,
|
|
536
|
+
rows: entry.term.rows,
|
|
537
|
+
scrollback,
|
|
538
|
+
fp: viewportFingerprint(entry.term),
|
|
539
|
+
});
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
case 'fingerprint': {
|
|
544
|
+
const entry = terminals.get(msg.sessionId);
|
|
545
|
+
if (!entry) {
|
|
546
|
+
postMessage({
|
|
547
|
+
type: 'fingerprinted', sessionId: msg.sessionId,
|
|
548
|
+
requestId: msg.requestId, fp: EMPTY_FINGERPRINT,
|
|
549
|
+
cols: Number(msg.cols) || 0, rows: Number(msg.rows) || 0, scrollbackLen: 0,
|
|
550
|
+
});
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
553
|
+
// Wait for pending writes so we fingerprint settled state, not mid-write.
|
|
554
|
+
await _awaitQueueBounded(msg.sessionId, msg.queueWaitTimeoutMs);
|
|
555
|
+
// Measure at the CLIENT's dims so client and server fingerprint the same
|
|
556
|
+
// grid (foreign-width content is real divergence). We resize, sample, then
|
|
557
|
+
// resize BACK so the fingerprint probe never permanently mutates the
|
|
558
|
+
// authoritative dims that serialize()/other ops depend on. Guard against
|
|
559
|
+
// NaN/zero dims (hidden/zero-size client container).
|
|
560
|
+
// NOTE: once the dimension-authority pillar (P2) keeps the headless term
|
|
561
|
+
// at the client's dims at all times, this resize round-trip is a no-op.
|
|
562
|
+
const origCols = entry.term.cols;
|
|
563
|
+
const origRows = entry.term.rows;
|
|
564
|
+
const wantResize = Number.isFinite(msg.cols) && Number.isFinite(msg.rows)
|
|
565
|
+
&& msg.cols >= 1 && msg.rows >= 1
|
|
566
|
+
&& (origCols !== msg.cols || origRows !== msg.rows);
|
|
567
|
+
if (wantResize) entry.term.resize(msg.cols, msg.rows);
|
|
568
|
+
const sampleCols = entry.term.cols;
|
|
569
|
+
const sampleRows = entry.term.rows;
|
|
570
|
+
const scrollbackLen = Math.max(0, entry.term.buffer.active.length - sampleRows);
|
|
571
|
+
const fp = viewportFingerprint(entry.term);
|
|
572
|
+
if (wantResize) entry.term.resize(origCols, origRows);
|
|
573
|
+
postMessage({
|
|
574
|
+
type: 'fingerprinted', sessionId: msg.sessionId,
|
|
575
|
+
requestId: msg.requestId, fp,
|
|
576
|
+
cols: sampleCols, rows: sampleRows, scrollbackLen,
|
|
577
|
+
});
|
|
578
|
+
break;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
case 'getText': {
|
|
582
|
+
const entry = terminals.get(msg.sessionId);
|
|
583
|
+
if (!entry) {
|
|
584
|
+
postMessage({ type: 'text', sessionId: msg.sessionId, requestId: msg.requestId, text: '' });
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
await _awaitQueueBounded(msg.sessionId);
|
|
588
|
+
const text = getVisibleText(entry.term);
|
|
589
|
+
postMessage({ type: 'text', sessionId: msg.sessionId, requestId: msg.requestId, text });
|
|
590
|
+
break;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
case 'getViewportText': {
|
|
594
|
+
const entry = terminals.get(msg.sessionId);
|
|
595
|
+
if (!entry) {
|
|
596
|
+
postMessage({ type: 'viewport-text', sessionId: msg.sessionId, requestId: msg.requestId, text: '' });
|
|
597
|
+
break;
|
|
598
|
+
}
|
|
599
|
+
await _awaitQueueBounded(msg.sessionId);
|
|
600
|
+
const text = getViewportText(entry.term);
|
|
601
|
+
postMessage({ type: 'viewport-text', sessionId: msg.sessionId, requestId: msg.requestId, text });
|
|
602
|
+
break;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
case 'getRows': {
|
|
606
|
+
const entry = terminals.get(msg.sessionId);
|
|
607
|
+
if (!entry) {
|
|
608
|
+
postMessage({ type: 'rows', sessionId: msg.sessionId, requestId: msg.requestId, rows: [] });
|
|
609
|
+
break;
|
|
610
|
+
}
|
|
611
|
+
await _awaitQueueBounded(msg.sessionId);
|
|
612
|
+
const rows = getVisibleRows(entry.term);
|
|
613
|
+
postMessage({ type: 'rows', sessionId: msg.sessionId, requestId: msg.requestId, rows });
|
|
614
|
+
break;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
case 'reset': {
|
|
618
|
+
const entry = terminals.get(msg.sessionId);
|
|
619
|
+
if (entry) {
|
|
620
|
+
entry.term.reset();
|
|
621
|
+
writeQueues.delete(msg.sessionId);
|
|
622
|
+
}
|
|
623
|
+
break;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
case 'destroy': {
|
|
627
|
+
const entry = terminals.get(msg.sessionId);
|
|
628
|
+
if (entry) {
|
|
629
|
+
await _awaitQueueBounded(msg.sessionId);
|
|
630
|
+
entry.term.dispose();
|
|
631
|
+
terminals.delete(msg.sessionId);
|
|
632
|
+
writeQueues.delete(msg.sessionId);
|
|
633
|
+
}
|
|
634
|
+
break;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
function dispatchHeadlessMessage(msg) {
|
|
640
|
+
const sessionId = msg && msg.sessionId;
|
|
641
|
+
if (!sessionId) {
|
|
642
|
+
handleMessage(msg).catch((err) => {
|
|
643
|
+
try {
|
|
644
|
+
postMessage({
|
|
645
|
+
type: 'worker-error',
|
|
646
|
+
sessionId: '',
|
|
647
|
+
message: err && err.message ? err.message : String(err),
|
|
648
|
+
});
|
|
649
|
+
} catch {}
|
|
650
|
+
});
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
enqueueSessionOp(sessionId, () => handleMessage(msg));
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function bindHeadlessTerminalService(options = {}) {
|
|
657
|
+
if (typeof options.postMessage !== 'function') {
|
|
658
|
+
throw new Error('bindHeadlessTerminalService requires postMessage');
|
|
659
|
+
}
|
|
660
|
+
postMessage = options.postMessage;
|
|
661
|
+
if (typeof options.onMessage === 'function') options.onMessage(dispatchHeadlessMessage);
|
|
662
|
+
return {
|
|
663
|
+
handleMessage: dispatchHeadlessMessage,
|
|
664
|
+
close() {
|
|
665
|
+
for (const [sessionId, entry] of terminals.entries()) {
|
|
666
|
+
try { entry.term.dispose(); } catch {}
|
|
667
|
+
terminals.delete(sessionId);
|
|
668
|
+
}
|
|
669
|
+
writeQueues.clear();
|
|
670
|
+
opQueues.clear();
|
|
671
|
+
},
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
module.exports = {
|
|
676
|
+
bindHeadlessTerminalService,
|
|
677
|
+
handleMessage: dispatchHeadlessMessage,
|
|
678
|
+
};
|