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,258 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
const FRONTEND_FILE_RE = /\.(html?|css|scss|sass|less|jsx|tsx|vue|svelte|astro)\b/i;
|
|
7
|
+
const HTML_FILE_RE = /\.html?\b/i;
|
|
8
|
+
const JS_FILE_RE = /\.(?:mjs|cjs|js|jsx|ts|tsx)\b/i;
|
|
9
|
+
const ASSET_ATTR_RE = /\b(?:src|href|poster)\s*=\s*["']([^"']+)["']/gi;
|
|
10
|
+
const SRCSET_RE = /\bsrcset\s*=\s*["']([^"']+)["']/gi;
|
|
11
|
+
const CSS_URL_RE = /url\(\s*(['"]?)([^'")]+)\1\s*\)/gi;
|
|
12
|
+
const EVENT_HANDLER_ATTR_RE = /\bon([a-z][a-z0-9_-]*)\s*=\s*(["'])([\s\S]*?)\2/gi;
|
|
13
|
+
const SCRIPT_SRC_RE = /<script\b[^>]*\bsrc\s*=\s*(["'])([^"']+)\1[^>]*>/gi;
|
|
14
|
+
const INLINE_SCRIPT_RE = /<script\b(?![^>]*\bsrc\b)[^>]*>([\s\S]*?)<\/script>/gi;
|
|
15
|
+
const JS_CALL_RE = /(?:^|[^\w$.\]])(?:window\.|globalThis\.)?([A-Za-z_$][\w$]*)\s*\(/g;
|
|
16
|
+
const JS_KEYWORDS = new Set([
|
|
17
|
+
'if',
|
|
18
|
+
'for',
|
|
19
|
+
'while',
|
|
20
|
+
'switch',
|
|
21
|
+
'catch',
|
|
22
|
+
'function',
|
|
23
|
+
'return',
|
|
24
|
+
'typeof',
|
|
25
|
+
'void',
|
|
26
|
+
'new',
|
|
27
|
+
'do',
|
|
28
|
+
'else',
|
|
29
|
+
'class',
|
|
30
|
+
'super',
|
|
31
|
+
'import',
|
|
32
|
+
'export',
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
function isFrontendFile(filePath = '') {
|
|
36
|
+
return FRONTEND_FILE_RE.test(String(filePath || ''));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isHtmlFile(filePath = '') {
|
|
40
|
+
return HTML_FILE_RE.test(String(filePath || ''));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isScriptFile(filePath = '') {
|
|
44
|
+
return JS_FILE_RE.test(String(filePath || ''));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function shouldSkipReference(ref = '') {
|
|
48
|
+
const value = String(ref || '').trim();
|
|
49
|
+
if (!value) return true;
|
|
50
|
+
return value.startsWith('#')
|
|
51
|
+
|| /^(?:https?:|data:|mailto:|tel:|javascript:|blob:|about:)/i.test(value);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function cleanReference(ref = '') {
|
|
55
|
+
const value = String(ref || '').trim();
|
|
56
|
+
const hashIdx = value.indexOf('#');
|
|
57
|
+
const queryIdx = value.indexOf('?');
|
|
58
|
+
const cut = [hashIdx, queryIdx].filter((n) => n >= 0).sort((a, b) => a - b)[0];
|
|
59
|
+
return cut >= 0 ? value.slice(0, cut) : value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function srcsetReferences(value = '') {
|
|
63
|
+
return String(value || '')
|
|
64
|
+
.split(',')
|
|
65
|
+
.map((entry) => entry.trim().split(/\s+/)[0])
|
|
66
|
+
.filter(Boolean);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function extractLocalAssetReferences(content = '') {
|
|
70
|
+
const refs = [];
|
|
71
|
+
let match;
|
|
72
|
+
while ((match = ASSET_ATTR_RE.exec(content))) refs.push(match[1]);
|
|
73
|
+
while ((match = CSS_URL_RE.exec(content))) refs.push(match[2]);
|
|
74
|
+
while ((match = SRCSET_RE.exec(content))) refs.push(...srcsetReferences(match[1]));
|
|
75
|
+
return refs
|
|
76
|
+
.map(cleanReference)
|
|
77
|
+
.filter((ref) => !shouldSkipReference(ref));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function resolveReference(cwd, sourceFile, ref) {
|
|
81
|
+
if (/^file:\/\//i.test(ref)) {
|
|
82
|
+
try {
|
|
83
|
+
return new URL(ref).pathname;
|
|
84
|
+
} catch {
|
|
85
|
+
return ref;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (ref.startsWith('/')) return path.resolve(cwd, `.${ref}`);
|
|
89
|
+
return path.resolve(path.dirname(sourceFile), ref);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function extractInlineHandlerCalls(content = '') {
|
|
93
|
+
const calls = [];
|
|
94
|
+
let match;
|
|
95
|
+
while ((match = EVENT_HANDLER_ATTR_RE.exec(content))) {
|
|
96
|
+
const event = match[1];
|
|
97
|
+
const expression = match[3] || '';
|
|
98
|
+
let callMatch;
|
|
99
|
+
while ((callMatch = JS_CALL_RE.exec(expression))) {
|
|
100
|
+
const name = callMatch[1];
|
|
101
|
+
if (!name || JS_KEYWORDS.has(name)) continue;
|
|
102
|
+
calls.push({ event, expression, name });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return calls;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function extractScriptSources(content = '') {
|
|
109
|
+
const refs = [];
|
|
110
|
+
let match;
|
|
111
|
+
while ((match = SCRIPT_SRC_RE.exec(content))) refs.push(match[2]);
|
|
112
|
+
return refs
|
|
113
|
+
.map(cleanReference)
|
|
114
|
+
.filter((ref) => !shouldSkipReference(ref));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function extractInlineScripts(content = '') {
|
|
118
|
+
const scripts = [];
|
|
119
|
+
let match;
|
|
120
|
+
while ((match = INLINE_SCRIPT_RE.exec(content))) scripts.push(match[1] || '');
|
|
121
|
+
return scripts;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function extractDeclaredGlobalNames(content = '') {
|
|
125
|
+
const names = new Set();
|
|
126
|
+
const patterns = [
|
|
127
|
+
/\bfunction\s+([A-Za-z_$][\w$]*)\s*\(/g,
|
|
128
|
+
/\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?(?:function\b|\([^)]*\)\s*=>|[A-Za-z_$][\w$]*\s*=>)/g,
|
|
129
|
+
/\b(?:window|globalThis)\.([A-Za-z_$][\w$]*)\s*=/g,
|
|
130
|
+
];
|
|
131
|
+
for (const pattern of patterns) {
|
|
132
|
+
let match;
|
|
133
|
+
while ((match = pattern.exec(content))) names.add(match[1]);
|
|
134
|
+
}
|
|
135
|
+
return names;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function checkInlineEventHandlers(cwd, files = []) {
|
|
139
|
+
const missing = [];
|
|
140
|
+
const checked = [];
|
|
141
|
+
const htmlFiles = [...new Set(files || [])]
|
|
142
|
+
.filter(isHtmlFile)
|
|
143
|
+
.map((file) => path.isAbsolute(file) ? file : path.join(cwd, file));
|
|
144
|
+
|
|
145
|
+
for (const sourceFile of htmlFiles) {
|
|
146
|
+
if (!fs.existsSync(sourceFile) || !fs.statSync(sourceFile).isFile()) continue;
|
|
147
|
+
const html = fs.readFileSync(sourceFile, 'utf8');
|
|
148
|
+
const handlers = extractInlineHandlerCalls(html);
|
|
149
|
+
if (!handlers.length) continue;
|
|
150
|
+
|
|
151
|
+
const declared = new Set();
|
|
152
|
+
for (const script of extractInlineScripts(html)) {
|
|
153
|
+
for (const name of extractDeclaredGlobalNames(script)) declared.add(name);
|
|
154
|
+
}
|
|
155
|
+
for (const ref of extractScriptSources(html)) {
|
|
156
|
+
const resolved = resolveReference(cwd, sourceFile, ref);
|
|
157
|
+
if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile()) continue;
|
|
158
|
+
const js = fs.readFileSync(resolved, 'utf8');
|
|
159
|
+
for (const name of extractDeclaredGlobalNames(js)) declared.add(name);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
for (const handler of handlers) {
|
|
163
|
+
const item = {
|
|
164
|
+
source: path.relative(cwd, sourceFile),
|
|
165
|
+
event: handler.event,
|
|
166
|
+
name: handler.name,
|
|
167
|
+
expression: handler.expression,
|
|
168
|
+
};
|
|
169
|
+
checked.push(item);
|
|
170
|
+
if (!declared.has(handler.name)) missing.push(item);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
ok: missing.length === 0,
|
|
176
|
+
checked,
|
|
177
|
+
missing,
|
|
178
|
+
htmlFiles: htmlFiles.map((file) => path.relative(cwd, file)),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function checkLocalAssetReferences(cwd, files = []) {
|
|
183
|
+
const missing = [];
|
|
184
|
+
const checked = [];
|
|
185
|
+
const frontendFiles = [...new Set(files || [])]
|
|
186
|
+
.filter(isFrontendFile)
|
|
187
|
+
.map((file) => path.isAbsolute(file) ? file : path.join(cwd, file));
|
|
188
|
+
|
|
189
|
+
for (const sourceFile of frontendFiles) {
|
|
190
|
+
if (!fs.existsSync(sourceFile) || !fs.statSync(sourceFile).isFile()) continue;
|
|
191
|
+
const content = fs.readFileSync(sourceFile, 'utf8');
|
|
192
|
+
for (const ref of extractLocalAssetReferences(content)) {
|
|
193
|
+
const resolved = resolveReference(cwd, sourceFile, ref);
|
|
194
|
+
checked.push({ source: path.relative(cwd, sourceFile), reference: ref, resolved });
|
|
195
|
+
if (!fs.existsSync(resolved)) {
|
|
196
|
+
missing.push({ source: path.relative(cwd, sourceFile), reference: ref, resolved });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
ok: missing.length === 0,
|
|
203
|
+
checked,
|
|
204
|
+
missing,
|
|
205
|
+
frontendFiles: frontendFiles.map((file) => path.relative(cwd, file)),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function resolveFrontendEntrypoints(cwd, files = [], { limit = 4 } = {}) {
|
|
210
|
+
const entrypoints = [];
|
|
211
|
+
const seen = new Set();
|
|
212
|
+
const add = (file) => {
|
|
213
|
+
if (!file) return;
|
|
214
|
+
const abs = path.isAbsolute(file) ? file : path.join(cwd, file);
|
|
215
|
+
if (!isHtmlFile(abs)) return;
|
|
216
|
+
if (!fs.existsSync(abs) || !fs.statSync(abs).isFile()) return;
|
|
217
|
+
const real = path.resolve(abs);
|
|
218
|
+
if (seen.has(real)) return;
|
|
219
|
+
seen.add(real);
|
|
220
|
+
entrypoints.push(real);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
for (const file of files || []) add(file);
|
|
224
|
+
for (const file of files || []) {
|
|
225
|
+
const abs = path.isAbsolute(file) ? file : path.join(cwd, file);
|
|
226
|
+
if (!isFrontendFile(abs) && !isScriptFile(abs)) continue;
|
|
227
|
+
add(path.join(path.dirname(abs), 'index.html'));
|
|
228
|
+
}
|
|
229
|
+
add(path.join(cwd, 'index.html'));
|
|
230
|
+
return entrypoints.slice(0, limit);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function checkFrontendStaticContracts(cwd, files = []) {
|
|
234
|
+
const assets = checkLocalAssetReferences(cwd, files);
|
|
235
|
+
const handlers = checkInlineEventHandlers(cwd, files);
|
|
236
|
+
return {
|
|
237
|
+
ok: assets.ok && handlers.ok,
|
|
238
|
+
assets,
|
|
239
|
+
handlers,
|
|
240
|
+
concerns: [
|
|
241
|
+
...assets.missing.map((item) => `[frontend-assets] ${item.source} references missing local asset ${item.reference}`),
|
|
242
|
+
...handlers.missing.map((item) => `[frontend-js] ${item.source} ${item.event}= handler calls missing ${item.name}()`),
|
|
243
|
+
],
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
module.exports = {
|
|
248
|
+
isFrontendFile,
|
|
249
|
+
isHtmlFile,
|
|
250
|
+
isScriptFile,
|
|
251
|
+
extractLocalAssetReferences,
|
|
252
|
+
extractInlineHandlerCalls,
|
|
253
|
+
extractDeclaredGlobalNames,
|
|
254
|
+
checkInlineEventHandlers,
|
|
255
|
+
checkLocalAssetReferences,
|
|
256
|
+
checkFrontendStaticContracts,
|
|
257
|
+
resolveFrontendEntrypoints,
|
|
258
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { RuntimeEventWriter, createRuntimeEvent } = require('./runtime-events');
|
|
4
|
+
|
|
5
|
+
class LifecycleHookBus {
|
|
6
|
+
constructor({ events = null, middleware = null, runtimeEvents = null, now = () => new Date().toISOString(), defaults = {} } = {}) {
|
|
7
|
+
this.events = events;
|
|
8
|
+
this.middleware = middleware;
|
|
9
|
+
this.runtimeEvents = runtimeEvents || new RuntimeEventWriter({ events, now, defaults });
|
|
10
|
+
this.now = now;
|
|
11
|
+
this.defaults = defaults;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async emit(type, payload = {}, defaults = {}) {
|
|
15
|
+
const event = this.runtimeEvents.emit({ type, payload }, defaults);
|
|
16
|
+
if (this.events?.emit) {
|
|
17
|
+
this.events.emit(`lifecycle.${type}`, event);
|
|
18
|
+
}
|
|
19
|
+
if (this.middleware?.run) {
|
|
20
|
+
await this.middleware.run('onEvent', {
|
|
21
|
+
...(this.defaults || {}),
|
|
22
|
+
...(defaults || {}),
|
|
23
|
+
lifecycleEvent: type,
|
|
24
|
+
}, {
|
|
25
|
+
...event,
|
|
26
|
+
type: `lifecycle.${type}`,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return event;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async wrap(type, payload, fn, defaults = {}) {
|
|
33
|
+
await this.emit(`${type}_started`, payload, defaults);
|
|
34
|
+
try {
|
|
35
|
+
const result = await fn();
|
|
36
|
+
await this.emit(`${type}_finished`, { ...payload, result: summarizeResult(result) }, defaults);
|
|
37
|
+
return result;
|
|
38
|
+
} catch (err) {
|
|
39
|
+
await this.emit(`${type}_failed`, { ...payload, error: err.message }, defaults);
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
child(defaults = {}) {
|
|
45
|
+
return new LifecycleHookBus({
|
|
46
|
+
events: this.events,
|
|
47
|
+
middleware: this.middleware,
|
|
48
|
+
runtimeEvents: this.runtimeEvents.child(defaults),
|
|
49
|
+
now: this.now,
|
|
50
|
+
defaults: { ...this.defaults, ...defaults },
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function summarizeResult(result) {
|
|
56
|
+
if (result == null) return null;
|
|
57
|
+
if (typeof result === 'string') return { type: 'string', chars: result.length };
|
|
58
|
+
if (typeof result !== 'object') return { type: typeof result };
|
|
59
|
+
return {
|
|
60
|
+
type: 'object',
|
|
61
|
+
keys: Object.keys(result).sort().slice(0, 20),
|
|
62
|
+
ok: result.ok === true,
|
|
63
|
+
error: result.error ? String(result.error) : '',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function normalizeLifecycleEvent(input = {}, defaults = {}) {
|
|
68
|
+
return createRuntimeEvent(input, defaults);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
LifecycleHookBus,
|
|
73
|
+
normalizeLifecycleEvent,
|
|
74
|
+
summarizeResult,
|
|
75
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1', '[::1]']);
|
|
4
|
+
|
|
5
|
+
function extractLoopbackUrls(text) {
|
|
6
|
+
const source = String(text || '');
|
|
7
|
+
const matches = source.match(/https?:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(?::\d+)?(?:\/[^\s<>)\]]*)?/gi) || [];
|
|
8
|
+
const seen = new Set();
|
|
9
|
+
const urls = [];
|
|
10
|
+
for (const match of matches) {
|
|
11
|
+
const raw = match.replace(/[.,;:!?]+$/g, '');
|
|
12
|
+
const normalized = normalizeLoopbackUrl(raw);
|
|
13
|
+
if (!normalized || seen.has(normalized.href)) continue;
|
|
14
|
+
seen.add(normalized.href);
|
|
15
|
+
urls.push({ raw, ...normalized });
|
|
16
|
+
}
|
|
17
|
+
return urls;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function normalizeLoopbackUrl(raw) {
|
|
21
|
+
try {
|
|
22
|
+
const parsed = new URL(String(raw || '').trim());
|
|
23
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
24
|
+
if (!LOOPBACK_HOSTS.has(hostname) && !LOOPBACK_HOSTS.has(parsed.host.toLowerCase())) return null;
|
|
25
|
+
const port = parsed.port || (parsed.protocol === 'https:' ? '443' : '80');
|
|
26
|
+
const pathname = parsed.pathname || '/';
|
|
27
|
+
const normalizedPath = pathname === '/index.html' ? '/' : pathname.replace(/\/+$/, '') || '/';
|
|
28
|
+
return {
|
|
29
|
+
href: parsed.href,
|
|
30
|
+
origin: `${parsed.protocol}//${hostname}:${port}`,
|
|
31
|
+
protocol: parsed.protocol,
|
|
32
|
+
hostname,
|
|
33
|
+
port,
|
|
34
|
+
pathname,
|
|
35
|
+
routeKey: `${parsed.protocol}//${hostname}:${port}${normalizedPath}`,
|
|
36
|
+
};
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function analyzeLocalPreviewClaims(text, toolCalls = []) {
|
|
43
|
+
const urls = extractLoopbackUrls(text);
|
|
44
|
+
if (urls.length === 0) {
|
|
45
|
+
return { ok: true, hasPositiveClaim: false, urls: [], unsupportedUrls: [], verifiedUrls: [] };
|
|
46
|
+
}
|
|
47
|
+
const positiveUrls = urls.filter((url) => _looksLikePositivePreviewClaim(text, url.raw));
|
|
48
|
+
if (positiveUrls.length === 0) {
|
|
49
|
+
return { ok: true, hasPositiveClaim: false, urls, unsupportedUrls: [], verifiedUrls: [] };
|
|
50
|
+
}
|
|
51
|
+
const evidence = _collectPreviewEvidence(toolCalls);
|
|
52
|
+
const unsupportedUrls = [];
|
|
53
|
+
const verifiedUrls = [];
|
|
54
|
+
for (const url of positiveUrls) {
|
|
55
|
+
const match = evidence.find((item) => _evidenceSupportsUrl(item, url));
|
|
56
|
+
if (match) verifiedUrls.push({ ...url, evidence: match });
|
|
57
|
+
else unsupportedUrls.push(url);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
ok: unsupportedUrls.length === 0,
|
|
61
|
+
hasPositiveClaim: true,
|
|
62
|
+
urls: positiveUrls,
|
|
63
|
+
unsupportedUrls,
|
|
64
|
+
verifiedUrls,
|
|
65
|
+
evidence,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function buildLocalPreviewVerificationNudge(analysis) {
|
|
70
|
+
const urls = (analysis?.unsupportedUrls || []).map((url) => url.raw).join(', ');
|
|
71
|
+
return [
|
|
72
|
+
`[System: Your previous response claimed local preview URL(s) were live or reachable without current successful preview-tool evidence: ${urls || '(local URL)'}.`,
|
|
73
|
+
'Do not claim HTTP 200, "server is back", "restarted", "serving", "live", or "reachable" from memory, terminal text, or a background/nohup shell command.',
|
|
74
|
+
'Call check_url for the exact URL now, or call start_static_server for the target directory if you need a managed server, then answer from that tool result.',
|
|
75
|
+
'If the check fails, say the URL is not reachable and include the actual error. If the URL is localhost/127.0.0.1, say it is only verified from Wall-E host loopback; phone or remote browser access needs CTM remote/tunnel context.]',
|
|
76
|
+
].join(' ');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function buildUnsupportedLocalPreviewReply(analysis) {
|
|
80
|
+
const urls = (analysis?.unsupportedUrls || []).map((url) => url.raw).join(', ') || 'the local preview URL';
|
|
81
|
+
return [
|
|
82
|
+
`I cannot honestly confirm ${urls} is live yet.`,
|
|
83
|
+
'',
|
|
84
|
+
'The previous answer attempted to claim a local preview was reachable, but this turn has no successful `check_url`, `start_static_server`, or `browser_screenshot` evidence for that URL. A `localhost` or `127.0.0.1` link also only proves Wall-E host loopback access; phone or remote browser access needs the CTM remote/tunnel path.',
|
|
85
|
+
].join('\n');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function _looksLikePositivePreviewClaim(text, rawUrl) {
|
|
89
|
+
const source = String(text || '');
|
|
90
|
+
const idx = source.indexOf(rawUrl);
|
|
91
|
+
const window = idx >= 0
|
|
92
|
+
? source.slice(Math.max(0, idx - 180), Math.min(source.length, idx + rawUrl.length + 220))
|
|
93
|
+
: source;
|
|
94
|
+
const lower = window.toLowerCase();
|
|
95
|
+
const positive = /\b(?:http\s*200|status\s*200|server(?:\s+is)?\s+(?:back|up|running)|back\s+up|reachable|accessible|available|live|serving|started|restarted|ready|works|open\s+(?:it|this|the)|visit|you\s+can\s+(?:open|use|view|access))\b/.test(lower)
|
|
96
|
+
|| /(?:→|->)\s*http\s*200/i.test(window);
|
|
97
|
+
if (!positive) return false;
|
|
98
|
+
const negative = /\b(?:not|isn['’]?t|cannot|can['’]?t|couldn['’]?t|failed|failure|refused|timed\s*out|unreachable|inaccessible|not\s+reachable|not\s+accessible|not\s+available|down|no\s+listener|connection\s+refused|does\s+not)\b/.test(lower);
|
|
99
|
+
if (!negative) return true;
|
|
100
|
+
return /\b(?:now|after|restarted|server(?:\s+is)?\s+back|http\s*200|status\s*200)\b/.test(lower)
|
|
101
|
+
&& !/\b(?:still|remains)\s+(?:not\s+)?(?:down|unreachable|inaccessible|broken)\b/.test(lower);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function _collectPreviewEvidence(toolCalls = []) {
|
|
105
|
+
const evidence = [];
|
|
106
|
+
for (const call of Array.isArray(toolCalls) ? toolCalls : []) {
|
|
107
|
+
const name = call?.tool || call?.name;
|
|
108
|
+
if (!['check_url', 'start_static_server', 'browser_screenshot'].includes(name)) continue;
|
|
109
|
+
if (call?.ok !== true) continue;
|
|
110
|
+
const result = call.result || {};
|
|
111
|
+
const ok = result.ok === true
|
|
112
|
+
|| result.health?.ok === true
|
|
113
|
+
|| (name === 'browser_screenshot' && result.path && !result.error);
|
|
114
|
+
if (!ok) continue;
|
|
115
|
+
const candidateUrls = [
|
|
116
|
+
result.url,
|
|
117
|
+
result.health?.url,
|
|
118
|
+
call.args?.url,
|
|
119
|
+
call.input?.url,
|
|
120
|
+
].filter(Boolean);
|
|
121
|
+
for (const candidate of candidateUrls) {
|
|
122
|
+
const normalized = normalizeLoopbackUrl(candidate);
|
|
123
|
+
if (!normalized) continue;
|
|
124
|
+
evidence.push({
|
|
125
|
+
tool: name,
|
|
126
|
+
url: candidate,
|
|
127
|
+
...normalized,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return evidence;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function _evidenceSupportsUrl(evidence, claim) {
|
|
135
|
+
if (!evidence || !claim) return false;
|
|
136
|
+
if (evidence.routeKey === claim.routeKey) return true;
|
|
137
|
+
if (evidence.origin !== claim.origin && !_sameLoopbackEndpoint(evidence, claim)) return false;
|
|
138
|
+
const evidencePath = evidence.pathname || '/';
|
|
139
|
+
const claimPath = claim.pathname || '/';
|
|
140
|
+
return (evidencePath === '/index.html' && claimPath === '/')
|
|
141
|
+
|| (evidencePath === '/' && claimPath === '/index.html');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function _sameLoopbackEndpoint(a, b) {
|
|
145
|
+
return a.protocol === b.protocol
|
|
146
|
+
&& String(a.port || '') === String(b.port || '')
|
|
147
|
+
&& LOOPBACK_HOSTS.has(String(a.hostname || '').toLowerCase())
|
|
148
|
+
&& LOOPBACK_HOSTS.has(String(b.hostname || '').toLowerCase());
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = {
|
|
152
|
+
analyzeLocalPreviewClaims,
|
|
153
|
+
buildLocalPreviewVerificationNudge,
|
|
154
|
+
buildUnsupportedLocalPreviewReply,
|
|
155
|
+
extractLoopbackUrls,
|
|
156
|
+
normalizeLoopbackUrl,
|
|
157
|
+
};
|
|
@@ -3,11 +3,37 @@
|
|
|
3
3
|
const crypto = require('node:crypto');
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
const { checkPermission } = require('../tools/permission-checker');
|
|
6
|
-
const { analyzeShellCommand, initParser: initShellParser } = require('../tools/shell-analyzer');
|
|
6
|
+
const { analyzeShellCommand, initParser: initShellParser, bashArityPrefix } = require('../tools/shell-analyzer');
|
|
7
|
+
|
|
8
|
+
// Shell builtins that only navigate; skipped when choosing the approval card's
|
|
9
|
+
// display pattern so a leading `cd` doesn't label the request as "cd *".
|
|
10
|
+
const _DISPLAY_NAV = new Set(['cd', 'pushd', 'popd', 'dirs']);
|
|
11
|
+
|
|
12
|
+
// Pick the pattern shown on the approval card (and stored for "always" rules)
|
|
13
|
+
// for a compound run_shell command: the first meaningful (non-navigation)
|
|
14
|
+
// clause, so `cd /x && git push` is labelled `git push *`, not `cd *`.
|
|
15
|
+
function pickShellDisplayPattern(clauses, command) {
|
|
16
|
+
const meaningful = clauses.find((t) => Array.isArray(t) && t.length > 0 && !_DISPLAY_NAV.has(t[0]))
|
|
17
|
+
|| (clauses.length > 0 ? clauses[0] : null);
|
|
18
|
+
if (meaningful && meaningful.length > 0) {
|
|
19
|
+
return `${bashArityPrefix(meaningful).join(' ')} *`;
|
|
20
|
+
}
|
|
21
|
+
return `${String(command).split(/\s+/)[0] || '*'} *`;
|
|
22
|
+
}
|
|
7
23
|
const { PermissionRulesStore } = require('./permission-rules-store');
|
|
8
24
|
const { inferPatchPaths } = require('./snapshot-service');
|
|
9
25
|
|
|
10
26
|
const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;
|
|
27
|
+
// Timeout semantics for a permission request:
|
|
28
|
+
// > 0 -> auto-deny after N ms (used for headless/automated runs)
|
|
29
|
+
// === 0 -> headless: resolve immediately via headlessPolicy (no prompt)
|
|
30
|
+
// WAIT_FOR_REPLY (< 0) -> interactive: never auto-deny; stay pending until the user
|
|
31
|
+
// replies or the session is cleared (matches Claude Code /
|
|
32
|
+
// opencode, which wait for the user instead of timing out).
|
|
33
|
+
// The < 0 case needs no special branch: ask() only arms a timer when the effective
|
|
34
|
+
// timeout is > 0, and authorize()'s headless shortcut matches exactly === 0, so a
|
|
35
|
+
// negative value naturally falls through to a no-timer wait.
|
|
36
|
+
const WAIT_FOR_REPLY = -1;
|
|
11
37
|
const _sharedPending = new Map();
|
|
12
38
|
|
|
13
39
|
class PermissionService {
|
|
@@ -27,20 +53,21 @@ class PermissionService {
|
|
|
27
53
|
}
|
|
28
54
|
|
|
29
55
|
async authorize({ sessionId = '', tool, input = {}, cwd = '', projectRoot = '', mode = '', metadata = {}, timeoutMs, headless = false } = {}) {
|
|
56
|
+
const permissionContextId = metadata.permissionContextId || metadata.permission_context_id || createPermissionContextId();
|
|
30
57
|
const requests = await buildToolPermissionRequests(tool, input, {
|
|
31
58
|
cwd,
|
|
32
59
|
projectRoot: projectRoot || cwd,
|
|
33
60
|
sessionId,
|
|
34
61
|
mode,
|
|
35
|
-
metadata,
|
|
62
|
+
metadata: { ...metadata, permissionContextId },
|
|
36
63
|
});
|
|
37
|
-
if (requests.length === 0) return { decision: 'allow', source: 'default', reason: 'No permission required' };
|
|
64
|
+
if (requests.length === 0) return { decision: 'allow', source: 'default', reason: 'No permission required', permissionContextId };
|
|
38
65
|
|
|
39
66
|
for (const request of requests) {
|
|
40
67
|
const evaluated = await this.evaluatePermission(request.check);
|
|
41
68
|
if (evaluated.decision === 'allow') continue;
|
|
42
69
|
if (evaluated.decision === 'deny') {
|
|
43
|
-
return { ...evaluated, request };
|
|
70
|
+
return { ...evaluated, request, permissionContextId };
|
|
44
71
|
}
|
|
45
72
|
|
|
46
73
|
const always = this.rulesStore.findAlways({
|
|
@@ -60,6 +87,7 @@ class PermissionService {
|
|
|
60
87
|
source: 'headless',
|
|
61
88
|
reason: `Permission required for ${request.permission}/${request.pattern}`,
|
|
62
89
|
request,
|
|
90
|
+
permissionContextId,
|
|
63
91
|
};
|
|
64
92
|
}
|
|
65
93
|
|
|
@@ -67,17 +95,19 @@ class PermissionService {
|
|
|
67
95
|
...request,
|
|
68
96
|
sessionId,
|
|
69
97
|
metadata: { ...metadata, ...request.metadata, evaluated },
|
|
98
|
+
permissionContextId,
|
|
70
99
|
timeoutMs,
|
|
71
100
|
});
|
|
72
|
-
if (reply.decision !== 'allow') return { ...reply, request };
|
|
101
|
+
if (reply.decision !== 'allow') return { ...reply, request, permissionContextId };
|
|
73
102
|
}
|
|
74
103
|
|
|
75
|
-
return { decision: 'allow', source: 'permissions', reason: 'Permission checks passed' };
|
|
104
|
+
return { decision: 'allow', source: 'permissions', reason: 'Permission checks passed', permissionContextId };
|
|
76
105
|
}
|
|
77
106
|
|
|
78
|
-
ask({ sessionId = '', permission, pattern = '*', patterns = null, tool = '', fingerprint = '', metadata = {}, timeoutMs } = {}) {
|
|
107
|
+
ask({ sessionId = '', permission, pattern = '*', patterns = null, tool = '', fingerprint = '', metadata = {}, permissionContextId = '', timeoutMs } = {}) {
|
|
79
108
|
if (!permission) throw new Error('permission is required');
|
|
80
109
|
const id = `perm_${crypto.randomUUID().slice(0, 8)}`;
|
|
110
|
+
const contextId = permissionContextId || metadata.permissionContextId || metadata.permission_context_id || createPermissionContextId();
|
|
81
111
|
const effectiveTimeout = timeoutMs ?? this.timeoutMs;
|
|
82
112
|
|
|
83
113
|
return new Promise((resolve) => {
|
|
@@ -92,7 +122,8 @@ class PermissionService {
|
|
|
92
122
|
patterns: patterns || [pattern],
|
|
93
123
|
tool,
|
|
94
124
|
fingerprint: fingerprint || metadata.fingerprint || '',
|
|
95
|
-
|
|
125
|
+
permissionContextId: contextId,
|
|
126
|
+
metadata: { ...metadata, permissionContextId: contextId },
|
|
96
127
|
createdAt: Date.now(),
|
|
97
128
|
timer,
|
|
98
129
|
resolve,
|
|
@@ -152,8 +183,9 @@ class PermissionService {
|
|
|
152
183
|
_resolveEntry(entry, result) {
|
|
153
184
|
if (entry.timer) clearTimeout(entry.timer);
|
|
154
185
|
this.pending.delete(entry.id);
|
|
155
|
-
|
|
156
|
-
|
|
186
|
+
const resolved = { ...result, permissionContextId: entry.permissionContextId || entry.metadata?.permissionContextId || '' };
|
|
187
|
+
this._emit('permission.replied', { ...publicEntry(entry), result: resolved });
|
|
188
|
+
entry.resolve(resolved);
|
|
157
189
|
}
|
|
158
190
|
|
|
159
191
|
_expire(id) {
|
|
@@ -181,14 +213,19 @@ async function buildToolPermissionRequests(tool, input = {}, { cwd = '', project
|
|
|
181
213
|
const command = input.command || '';
|
|
182
214
|
await initShellParser();
|
|
183
215
|
const analysis = await analyzeShellCommand(command, input.cwd || cwd || root);
|
|
184
|
-
|
|
185
|
-
|
|
216
|
+
// commandTokens is an array of per-clause token arrays (split on && ; | etc).
|
|
217
|
+
// The whole compound command must be permission-checked clause-by-clause, so
|
|
218
|
+
// pass the full list through to checkPermission; keep the first clause in
|
|
219
|
+
// metadata.commandTokens so the approval fingerprint stays stable.
|
|
220
|
+
const commandClauses = Array.isArray(analysis.commandTokens) ? analysis.commandTokens : [];
|
|
221
|
+
const commandTokens = commandClauses.length > 0 ? commandClauses[0] : undefined;
|
|
222
|
+
const pattern = pickShellDisplayPattern(commandClauses, command);
|
|
186
223
|
return withApprovalFingerprints([{
|
|
187
224
|
...base,
|
|
188
225
|
permission: 'bash',
|
|
189
226
|
pattern,
|
|
190
227
|
metadata: { ...base.metadata, command, commandTokens },
|
|
191
|
-
check: { tool: 'run_shell', command, commandTokens, projectPath: root, sessionId, mode },
|
|
228
|
+
check: { tool: 'run_shell', command, commandTokens, commandClauses, projectPath: root, sessionId, mode },
|
|
192
229
|
}], input);
|
|
193
230
|
}
|
|
194
231
|
|
|
@@ -339,6 +376,7 @@ function publicEntry(entry) {
|
|
|
339
376
|
return {
|
|
340
377
|
id: entry.id,
|
|
341
378
|
sessionId: entry.sessionId,
|
|
379
|
+
permissionContextId: entry.permissionContextId || entry.metadata?.permissionContextId || '',
|
|
342
380
|
permission: entry.permission,
|
|
343
381
|
pattern: entry.pattern,
|
|
344
382
|
patterns: entry.patterns,
|
|
@@ -349,6 +387,10 @@ function publicEntry(entry) {
|
|
|
349
387
|
};
|
|
350
388
|
}
|
|
351
389
|
|
|
390
|
+
function createPermissionContextId() {
|
|
391
|
+
return `permctx_${crypto.randomUUID().slice(0, 8)}`;
|
|
392
|
+
}
|
|
393
|
+
|
|
352
394
|
function getDefaultPermissionService() {
|
|
353
395
|
return new PermissionService();
|
|
354
396
|
}
|
|
@@ -365,7 +407,9 @@ module.exports = {
|
|
|
365
407
|
buildToolPermissionRequests,
|
|
366
408
|
approvalFingerprint,
|
|
367
409
|
approvalFingerprintInput,
|
|
410
|
+
createPermissionContextId,
|
|
368
411
|
getDefaultPermissionService,
|
|
369
412
|
clearPendingPermissions,
|
|
370
413
|
DEFAULT_TIMEOUT_MS,
|
|
414
|
+
WAIT_FOR_REPLY,
|
|
371
415
|
};
|