@minionry/minion 0.7.36
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/LICENSE +14 -0
- package/PRIVACY.md +357 -0
- package/README.md +57 -0
- package/THIRD_PARTY_NOTICES.md +245 -0
- package/bin/branding.js +4 -0
- package/bin/commands/browser-install.js +483 -0
- package/bin/commands/create-sandbox.js +542 -0
- package/bin/commands/fingerprint.js +101 -0
- package/bin/commands/login.js +400 -0
- package/bin/commands/logout.js +93 -0
- package/bin/commands/minions.js +211 -0
- package/bin/commands/sandboxes.js +309 -0
- package/bin/commands/status.js +298 -0
- package/bin/commands/whoami.js +153 -0
- package/bin/launch-env.js +35 -0
- package/bin/machine-identity.js +221 -0
- package/bin/machine-layout.js +200 -0
- package/bin/minion.js +839 -0
- package/bin/platform-endpoints.js +8 -0
- package/bin/postinstall.js +52 -0
- package/bin/pty-doctor.js +326 -0
- package/bin/pty-locator.js +110 -0
- package/bin/pty-provision.js +186 -0
- package/bin/sandbox/Dockerfile +78 -0
- package/bin/sandbox/entrypoint.sh +14 -0
- package/bin/sandbox/install-repo.sh +53 -0
- package/bin/sandbox/seccomp-userns.json +883 -0
- package/bin/sandbox-config.js +306 -0
- package/dist/bin/machine-identity.js +221 -0
- package/dist/bin/machine-layout.js +200 -0
- package/dist/electron-host/agent-lease.js +141 -0
- package/dist/electron-host/dom-driver.js +642 -0
- package/dist/electron-host/ipc-protocol.js +89 -0
- package/dist/electron-host/js-driver.js +216 -0
- package/dist/electron-host/view-manager.js +254 -0
- package/dist/server/cli/engine-resume.js +49 -0
- package/dist/server/cli/eta-estimator.js +278 -0
- package/dist/server/cli/headless/background-activity.js +109 -0
- package/dist/server/cli/headless/claude-invoker-process.js +614 -0
- package/dist/server/cli/headless/claude-invoker-stall.js +150 -0
- package/dist/server/cli/headless/claude-invoker-stream.js +555 -0
- package/dist/server/cli/headless/claude-invoker-tools.js +148 -0
- package/dist/server/cli/headless/claude-invoker.js +151 -0
- package/dist/server/cli/headless/engine-availability.js +92 -0
- package/dist/server/cli/headless/engine-notice.js +185 -0
- package/dist/server/cli/headless/haiku-assessments.js +293 -0
- package/dist/server/cli/headless/headless-logger.js +75 -0
- package/dist/server/cli/headless/index.js +9 -0
- package/dist/server/cli/headless/mcp-config.js +314 -0
- package/dist/server/cli/headless/native-timeout-detector.js +72 -0
- package/dist/server/cli/headless/output-utils.js +71 -0
- package/dist/server/cli/headless/prompt-utils.js +82 -0
- package/dist/server/cli/headless/resilient-runner.js +326 -0
- package/dist/server/cli/headless/retry-strategies.js +292 -0
- package/dist/server/cli/headless/runner.js +245 -0
- package/dist/server/cli/headless/stall-assessor.js +295 -0
- package/dist/server/cli/headless/tool-watchdog.js +447 -0
- package/dist/server/cli/headless/types.js +18 -0
- package/dist/server/cli/history-portability.js +85 -0
- package/dist/server/cli/improvisation-attachments.js +99 -0
- package/dist/server/cli/improvisation-history-store.js +121 -0
- package/dist/server/cli/improvisation-movements.js +137 -0
- package/dist/server/cli/improvisation-output-queue.js +34 -0
- package/dist/server/cli/improvisation-retry.js +8 -0
- package/dist/server/cli/improvisation-session-manager.js +1016 -0
- package/dist/server/cli/improvisation-types.js +31 -0
- package/dist/server/cli/plan-lifecycle.js +72 -0
- package/dist/server/cli/prompt-builders.js +371 -0
- package/dist/server/cli/retry/retry-best-result.js +28 -0
- package/dist/server/cli/retry/retry-context-loss.js +75 -0
- package/dist/server/cli/retry/retry-recovery-strategies.js +213 -0
- package/dist/server/cli/retry/retry-resume-strategy.js +20 -0
- package/dist/server/cli/retry/retry-runner-factory.js +92 -0
- package/dist/server/cli/retry/retry-tool-results.js +22 -0
- package/dist/server/cli/retry/retry-types.js +3 -0
- package/dist/server/engines/EngineEvent.js +57 -0
- package/dist/server/engines/claude/ClaudeCodeEngine.js +316 -0
- package/dist/server/engines/claude/claude-command.js +32 -0
- package/dist/server/engines/codex/CodexEngine.js +469 -0
- package/dist/server/engines/codex/codex-auth.js +203 -0
- package/dist/server/engines/codex/codex-invoker.js +205 -0
- package/dist/server/engines/codex/codex-provision.js +215 -0
- package/dist/server/engines/credentials/credential-probe.js +88 -0
- package/dist/server/engines/credentials/model-profiles.js +249 -0
- package/dist/server/engines/credentials/provider-credentials.js +146 -0
- package/dist/server/engines/engine-event-stream.js +52 -0
- package/dist/server/engines/execution/engine-session.js +380 -0
- package/dist/server/engines/factory.js +42 -0
- package/dist/server/engines/hermes/HermesEngine.js +628 -0
- package/dist/server/engines/hermes/hermes-auth.js +159 -0
- package/dist/server/engines/hermes/hermes-gateway-home.js +271 -0
- package/dist/server/engines/hermes/hermes-invoker.js +350 -0
- package/dist/server/engines/hermes/hermes-provision.js +318 -0
- package/dist/server/engines/read-only.js +20 -0
- package/dist/server/engines/types.js +27 -0
- package/dist/server/handlers/company-execution-registry.js +67 -0
- package/dist/server/handlers/company-handlers.js +514 -0
- package/dist/server/handlers/company-triggers.js +189 -0
- package/dist/server/handlers/company-types.js +3 -0
- package/dist/server/index.js +244 -0
- package/dist/server/mcp/app-tools-bridge.js +110 -0
- package/dist/server/mcp/app-tools-mcp-server.js +99 -0
- package/dist/server/mcp/bouncer-integration.js +744 -0
- package/dist/server/mcp/browser-mcp-server.js +915 -0
- package/dist/server/mcp/browser-redaction.js +103 -0
- package/dist/server/mcp/classifier/BouncerClassifier.js +3 -0
- package/dist/server/mcp/classifier/ClaudeBouncerClassifier.js +212 -0
- package/dist/server/mcp/classifier/factory.js +124 -0
- package/dist/server/mcp/classifier/health.js +54 -0
- package/dist/server/mcp/classifier/telemetry.js +0 -0
- package/dist/server/mcp/company-patterns.js +104 -0
- package/dist/server/mcp/department-profiles.js +133 -0
- package/dist/server/mcp/quality-bridge.js +153 -0
- package/dist/server/mcp/quality-mcp-server.js +105 -0
- package/dist/server/mcp/security-analysis.js +384 -0
- package/dist/server/mcp/security-audit.js +152 -0
- package/dist/server/mcp/security-patterns.js +314 -0
- package/dist/server/mcp/server.js +194 -0
- package/dist/server/mcp/test-utils/agent-simulator.js +301 -0
- package/dist/server/mcp/test-utils/e2e-agent.js +103 -0
- package/dist/server/mcp/test-utils/e2e-capture.js +92 -0
- package/dist/server/mcp/test-utils/e2e-client.js +116 -0
- package/dist/server/mcp/test-utils/e2e-fixtures.js +87 -0
- package/dist/server/mcp/test-utils/e2e-gating.js +8 -0
- package/dist/server/mcp/test-utils/e2e-harness.js +8 -0
- package/dist/server/mcp/test-utils/e2e-scenarios.js +105 -0
- package/dist/server/routes/files.js +18 -0
- package/dist/server/routes/improvise.js +64 -0
- package/dist/server/routes/index.js +7 -0
- package/dist/server/routes/instances.js +41 -0
- package/dist/server/routes/internal.js +900 -0
- package/dist/server/routes/notifications.js +110 -0
- package/dist/server/server-setup.js +282 -0
- package/dist/server/services/agent-push.js +148 -0
- package/dist/server/services/analytics.js +197 -0
- package/dist/server/services/apps/build.js +249 -0
- package/dist/server/services/apps/greenlight.js +199 -0
- package/dist/server/services/apps/install.js +101 -0
- package/dist/server/services/apps/layout.js +35 -0
- package/dist/server/services/apps/serve.js +665 -0
- package/dist/server/services/apps/space-apps.js +248 -0
- package/dist/server/services/auth.js +48 -0
- package/dist/server/services/browser/chrome-sandbox.js +245 -0
- package/dist/server/services/browser/chromium-launch-spec.js +51 -0
- package/dist/server/services/browser/claude-reasoner.js +669 -0
- package/dist/server/services/browser/debug-log.js +3 -0
- package/dist/server/services/browser/driver-state.js +546 -0
- package/dist/server/services/browser/electron-provision.js +256 -0
- package/dist/server/services/browser/host-internal.js +245 -0
- package/dist/server/services/browser/host-mock.js +334 -0
- package/dist/server/services/browser/host-types.js +3 -0
- package/dist/server/services/browser/host.js +1067 -0
- package/dist/server/services/browser/index.js +4 -0
- package/dist/server/services/browser/ipc-client.js +354 -0
- package/dist/server/services/browser/pipewire-sink.js +199 -0
- package/dist/server/services/browser/preflight.js +590 -0
- package/dist/server/services/browser/reasoning-agent.js +659 -0
- package/dist/server/services/browser/sandbox-policy.js +169 -0
- package/dist/server/services/browser/stderr-noise-filter.js +26 -0
- package/dist/server/services/browser/telemetry.js +107 -0
- package/dist/server/services/browser/xvfb-supervisor.js +139 -0
- package/dist/server/services/browser-frame-policy.js +56 -0
- package/dist/server/services/client-id.js +32 -0
- package/dist/server/services/collab/registry.js +408 -0
- package/dist/server/services/collab/session.js +489 -0
- package/dist/server/services/collab/text-diff.js +28 -0
- package/dist/server/services/collab/types.js +19 -0
- package/dist/server/services/e2ee-group-key.js +197 -0
- package/dist/server/services/e2ee-identity.js +203 -0
- package/dist/server/services/file-explorer-ops.js +328 -0
- package/dist/server/services/file-transfer-zip.js +188 -0
- package/dist/server/services/files.js +111 -0
- package/dist/server/services/git/branch-ops.js +62 -0
- package/dist/server/services/git/command.js +68 -0
- package/dist/server/services/git/commit-message.js +74 -0
- package/dist/server/services/git/diff-ops.js +56 -0
- package/dist/server/services/git/haiku.js +76 -0
- package/dist/server/services/git/head-watcher.js +226 -0
- package/dist/server/services/git/index.js +17 -0
- package/dist/server/services/git/log-ops.js +98 -0
- package/dist/server/services/git/merge-ops.js +314 -0
- package/dist/server/services/git/parsers.js +401 -0
- package/dist/server/services/git/remote-ops.js +192 -0
- package/dist/server/services/git/status-ops.js +105 -0
- package/dist/server/services/git/suggestion-ops.js +80 -0
- package/dist/server/services/git/tag-ops.js +36 -0
- package/dist/server/services/git/types.js +4 -0
- package/dist/server/services/git/worktree-ops.js +114 -0
- package/dist/server/services/instances.js +337 -0
- package/dist/server/services/model-catalog.js +247 -0
- package/dist/server/services/observability/posthog.js +153 -0
- package/dist/server/services/pathUtils.js +114 -0
- package/dist/server/services/plan/agent-loader.js +97 -0
- package/dist/server/services/plan/agent-manager.js +363 -0
- package/dist/server/services/plan/agent-resolver.js +74 -0
- package/dist/server/services/plan/agents/assess-stall.md +33 -0
- package/dist/server/services/plan/agents/browser-planner.md +53 -0
- package/dist/server/services/plan/agents/browser-reasoner.md +114 -0
- package/dist/server/services/plan/agents/check-injection.md +95 -0
- package/dist/server/services/plan/agents/classify-error.md +30 -0
- package/dist/server/services/plan/agents/code-review.md +142 -0
- package/dist/server/services/plan/agents/commit-message.md +28 -0
- package/dist/server/services/plan/agents/detect-context-loss.md +30 -0
- package/dist/server/services/plan/agents/execute-issue.md +58 -0
- package/dist/server/services/plan/agents/fix-quality.md +25 -0
- package/dist/server/services/plan/agents/plan-coordinator.md +72 -0
- package/dist/server/services/plan/agents/pr-description.md +29 -0
- package/dist/server/services/plan/agents/retry-task.md +27 -0
- package/dist/server/services/plan/agents/review-code.md +38 -0
- package/dist/server/services/plan/agents/review-quality.md +45 -0
- package/dist/server/services/plan/agents/triage-findings.md +78 -0
- package/dist/server/services/plan/agents/verify-review.md +57 -0
- package/dist/server/services/plan/approval-evaluator.js +143 -0
- package/dist/server/services/plan/board-archive.js +102 -0
- package/dist/server/services/plan/board-config.js +108 -0
- package/dist/server/services/plan/board-export.js +214 -0
- package/dist/server/services/plan/composer-prompt.js +115 -0
- package/dist/server/services/plan/composer.js +664 -0
- package/dist/server/services/plan/config-installer.js +103 -0
- package/dist/server/services/plan/dependency-resolver.js +137 -0
- package/dist/server/services/plan/executor.js +696 -0
- package/dist/server/services/plan/front-matter.js +43 -0
- package/dist/server/services/plan/issue-classification.js +10 -0
- package/dist/server/services/plan/issue-effort.js +182 -0
- package/dist/server/services/plan/issue-loader.js +35 -0
- package/dist/server/services/plan/issue-prompt-builder.js +152 -0
- package/dist/server/services/plan/issue-retry.js +42 -0
- package/dist/server/services/plan/issue-writer.js +102 -0
- package/dist/server/services/plan/metrics-collector.js +272 -0
- package/dist/server/services/plan/output-manager.js +77 -0
- package/dist/server/services/plan/parser-core.js +435 -0
- package/dist/server/services/plan/parser-migration.js +108 -0
- package/dist/server/services/plan/parser.js +258 -0
- package/dist/server/services/plan/plan-runner-factory.js +68 -0
- package/dist/server/services/plan/pm-timeline.js +320 -0
- package/dist/server/services/plan/progress-log.js +101 -0
- package/dist/server/services/plan/prompt-builder.js +142 -0
- package/dist/server/services/plan/quality-delta.js +274 -0
- package/dist/server/services/plan/readiness-planner.js +34 -0
- package/dist/server/services/plan/review-gate.js +409 -0
- package/dist/server/services/plan/review-report.js +134 -0
- package/dist/server/services/plan/review-verdict-stream.js +161 -0
- package/dist/server/services/plan/state-reconciler.js +238 -0
- package/dist/server/services/plan/template-diff.js +175 -0
- package/dist/server/services/plan/template-instantiator.js +516 -0
- package/dist/server/services/plan/template-manifest.js +56 -0
- package/dist/server/services/plan/template-types.js +3 -0
- package/dist/server/services/plan/trigger-evaluator.js +211 -0
- package/dist/server/services/plan/types.js +3 -0
- package/dist/server/services/plan/watcher.js +73 -0
- package/dist/server/services/platform-credentials.js +56 -0
- package/dist/server/services/platform-e2ee.js +421 -0
- package/dist/server/services/platform-envelope.js +102 -0
- package/dist/server/services/platform-heartbeat.js +88 -0
- package/dist/server/services/platform-reconnect.js +60 -0
- package/dist/server/services/platform-token-lifecycle.js +95 -0
- package/dist/server/services/platform-url.js +17 -0
- package/dist/server/services/platform.js +656 -0
- package/dist/server/services/runtime-info.js +9 -0
- package/dist/server/services/schedule/agent-schedule-store.js +232 -0
- package/dist/server/services/schedule/agent-scheduler.js +323 -0
- package/dist/server/services/schedule/daily-timing.js +105 -0
- package/dist/server/services/schedule/quality-schedule-launch.js +11 -0
- package/dist/server/services/schedule/quality-schedule-store.js +211 -0
- package/dist/server/services/schedule/quality-scheduler.js +215 -0
- package/dist/server/services/schedule/run-bootstrap.js +329 -0
- package/dist/server/services/schedule/schedule-store.js +238 -0
- package/dist/server/services/schedule/schedule-wire.js +77 -0
- package/dist/server/services/schedule/scheduler.js +310 -0
- package/dist/server/services/schedule/template-source.js +97 -0
- package/dist/server/services/sdk/agent-sessions.js +264 -0
- package/dist/server/services/sdk/agents.js +557 -0
- package/dist/server/services/sdk/app-endpoints.js +48 -0
- package/dist/server/services/sdk/app-tools.js +303 -0
- package/dist/server/services/sdk/audit.js +48 -0
- package/dist/server/services/sdk/browser-transport.js +188 -0
- package/dist/server/services/sdk/browser.js +605 -0
- package/dist/server/services/sdk/composer.js +129 -0
- package/dist/server/services/sdk/connect.js +273 -0
- package/dist/server/services/sdk/consent-cooldown.js +31 -0
- package/dist/server/services/sdk/endpoint-url.js +141 -0
- package/dist/server/services/sdk/endpoints.js +314 -0
- package/dist/server/services/sdk/file-change-notify.js +36 -0
- package/dist/server/services/sdk/files-app.js +163 -0
- package/dist/server/services/sdk/files-search.js +131 -0
- package/dist/server/services/sdk/files-transfer.js +279 -0
- package/dist/server/services/sdk/files-workspace.js +233 -0
- package/dist/server/services/sdk/git.js +520 -0
- package/dist/server/services/sdk/grant-store.js +318 -0
- package/dist/server/services/sdk/host-ops.js +84 -0
- package/dist/server/services/sdk/inference-claude.js +214 -0
- package/dist/server/services/sdk/inference.js +247 -0
- package/dist/server/services/sdk/live-registry.js +42 -0
- package/dist/server/services/sdk/local-app-bindings.js +71 -0
- package/dist/server/services/sdk/pipeline.js +190 -0
- package/dist/server/services/sdk/pm-execute.js +228 -0
- package/dist/server/services/sdk/pm-planning-tap.js +29 -0
- package/dist/server/services/sdk/pm-schedule.js +165 -0
- package/dist/server/services/sdk/pm.js +634 -0
- package/dist/server/services/sdk/quality-change-notify.js +20 -0
- package/dist/server/services/sdk/quality-schedule.js +165 -0
- package/dist/server/services/sdk/quality.js +602 -0
- package/dist/server/services/sdk/rate-limits.js +198 -0
- package/dist/server/services/sdk/registry.js +597 -0
- package/dist/server/services/sdk/revoke.js +86 -0
- package/dist/server/services/sdk/run-profile.js +41 -0
- package/dist/server/services/sdk/sandbox.js +89 -0
- package/dist/server/services/sdk/storage.js +110 -0
- package/dist/server/services/sdk/streams.js +147 -0
- package/dist/server/services/sdk/terminal.js +201 -0
- package/dist/server/services/sdk/test-utils/workshop-browser-app.js +466 -0
- package/dist/server/services/sentry.js +99 -0
- package/dist/server/services/settings.js +374 -0
- package/dist/server/services/snippets/expander.js +87 -0
- package/dist/server/services/snippets/index.js +6 -0
- package/dist/server/services/snippets/loader.js +119 -0
- package/dist/server/services/snippets/parser.js +52 -0
- package/dist/server/services/snippets/types.js +3 -0
- package/dist/server/services/snippets/watcher.js +60 -0
- package/dist/server/services/space-layout.js +80 -0
- package/dist/server/services/system-prompts.js +219 -0
- package/dist/server/services/terminal/pty-manager.js +206 -0
- package/dist/server/services/terminal/pty-utils.js +150 -0
- package/dist/server/services/timeline/assembler.js +890 -0
- package/dist/server/services/timeline/contract.js +196 -0
- package/dist/server/services/timeline/index.js +4 -0
- package/dist/server/services/websocket/agent-schedule-handlers.js +217 -0
- package/dist/server/services/websocket/apps-handlers.js +399 -0
- package/dist/server/services/websocket/ask-user-question-bridge.js +112 -0
- package/dist/server/services/websocket/autocomplete-index.js +415 -0
- package/dist/server/services/websocket/autocomplete-match.js +243 -0
- package/dist/server/services/websocket/autocomplete.js +407 -0
- package/dist/server/services/websocket/browser-agent-runtime.js +208 -0
- package/dist/server/services/websocket/browser-device-profile.js +46 -0
- package/dist/server/services/websocket/browser-handlers.js +377 -0
- package/dist/server/services/websocket/browser-host-broadcast.js +179 -0
- package/dist/server/services/websocket/browser-ice-config.js +121 -0
- package/dist/server/services/websocket/browser-payloads.js +222 -0
- package/dist/server/services/websocket/browser-viewer-lifecycle.js +84 -0
- package/dist/server/services/websocket/browser-viewer-registry.js +118 -0
- package/dist/server/services/websocket/collab-broadcast.js +11 -0
- package/dist/server/services/websocket/collab-handlers.js +116 -0
- package/dist/server/services/websocket/commit-suggestion-service.js +132 -0
- package/dist/server/services/websocket/debug-log.js +38 -0
- package/dist/server/services/websocket/dispatch-util.js +10 -0
- package/dist/server/services/websocket/engine-auth-handlers.js +323 -0
- package/dist/server/services/websocket/engine-credential-watcher.js +83 -0
- package/dist/server/services/websocket/engine-profile-handlers.js +92 -0
- package/dist/server/services/websocket/file-definition-handlers.js +180 -0
- package/dist/server/services/websocket/file-download-handler.js +291 -0
- package/dist/server/services/websocket/file-explorer-handlers.js +291 -0
- package/dist/server/services/websocket/file-search-handlers.js +267 -0
- package/dist/server/services/websocket/file-share-handlers.js +328 -0
- package/dist/server/services/websocket/file-transfer-http.js +361 -0
- package/dist/server/services/websocket/file-upload-handler.js +267 -0
- package/dist/server/services/websocket/file-utils.js +346 -0
- package/dist/server/services/websocket/git-branch-handlers.js +90 -0
- package/dist/server/services/websocket/git-diff-handlers.js +59 -0
- package/dist/server/services/websocket/git-handlers.js +212 -0
- package/dist/server/services/websocket/git-head-watcher.js +85 -0
- package/dist/server/services/websocket/git-log-handlers.js +104 -0
- package/dist/server/services/websocket/git-pr-handlers.js +56 -0
- package/dist/server/services/websocket/git-tag-handlers.js +53 -0
- package/dist/server/services/websocket/git-utils.js +11 -0
- package/dist/server/services/websocket/git-worktree-handlers.js +521 -0
- package/dist/server/services/websocket/handler-context.js +113 -0
- package/dist/server/services/websocket/handler.js +1197 -0
- package/dist/server/services/websocket/index.js +5 -0
- package/dist/server/services/websocket/movement-written-files.js +26 -0
- package/dist/server/services/websocket/msg-id-tracker.js +48 -0
- package/dist/server/services/websocket/plan-board-handlers.js +410 -0
- package/dist/server/services/websocket/plan-execution-handlers.js +244 -0
- package/dist/server/services/websocket/plan-handlers.js +67 -0
- package/dist/server/services/websocket/plan-helpers.js +161 -0
- package/dist/server/services/websocket/plan-issue-handlers.js +168 -0
- package/dist/server/services/websocket/plan-sprint-handlers.js +190 -0
- package/dist/server/services/websocket/plan-transfer-handlers.js +310 -0
- package/dist/server/services/websocket/pm-timeline-broadcast.js +28 -0
- package/dist/server/services/websocket/post-session-scan.js +132 -0
- package/dist/server/services/websocket/prompt-queue-handlers.js +96 -0
- package/dist/server/services/websocket/quality-agent-cost.js +229 -0
- package/dist/server/services/websocket/quality-agent-notes.js +113 -0
- package/dist/server/services/websocket/quality-change-activity.js +187 -0
- package/dist/server/services/websocket/quality-complexity.js +345 -0
- package/dist/server/services/websocket/quality-dependencies.js +445 -0
- package/dist/server/services/websocket/quality-duplication.js +162 -0
- package/dist/server/services/websocket/quality-eta.js +65 -0
- package/dist/server/services/websocket/quality-fingerprint.js +104 -0
- package/dist/server/services/websocket/quality-grading.js +575 -0
- package/dist/server/services/websocket/quality-handlers.js +48 -0
- package/dist/server/services/websocket/quality-linting.js +270 -0
- package/dist/server/services/websocket/quality-operations.js +54 -0
- package/dist/server/services/websocket/quality-persistence.js +410 -0
- package/dist/server/services/websocket/quality-review-agent.js +526 -0
- package/dist/server/services/websocket/quality-run.js +220 -0
- package/dist/server/services/websocket/quality-secrets.js +0 -0
- package/dist/server/services/websocket/quality-service.js +775 -0
- package/dist/server/services/websocket/quality-tools.js +383 -0
- package/dist/server/services/websocket/quality-triage-agent.js +101 -0
- package/dist/server/services/websocket/quality-types.js +149 -0
- package/dist/server/services/websocket/recommended-answers.js +28 -0
- package/dist/server/services/websocket/schedule-handlers.js +197 -0
- package/dist/server/services/websocket/sdk-agent-host.js +569 -0
- package/dist/server/services/websocket/sdk-browser-host.js +459 -0
- package/dist/server/services/websocket/sdk-composer-host.js +10 -0
- package/dist/server/services/websocket/sdk-git-host.js +115 -0
- package/dist/server/services/websocket/sdk-handlers.js +242 -0
- package/dist/server/services/websocket/sdk-pm-execution-host.js +63 -0
- package/dist/server/services/websocket/sdk-pm-schedule-host.js +21 -0
- package/dist/server/services/websocket/sdk-quality-schedule-host.js +34 -0
- package/dist/server/services/websocket/sdk-terminal-host.js +140 -0
- package/dist/server/services/websocket/session-handlers.js +565 -0
- package/dist/server/services/websocket/session-history.js +335 -0
- package/dist/server/services/websocket/session-initialization.js +315 -0
- package/dist/server/services/websocket/session-registry.js +340 -0
- package/dist/server/services/websocket/session-role-directory.js +39 -0
- package/dist/server/services/websocket/settings-handlers.js +276 -0
- package/dist/server/services/websocket/skill-handlers.js +324 -0
- package/dist/server/services/websocket/skill-watcher.js +83 -0
- package/dist/server/services/websocket/snippet-handlers.js +261 -0
- package/dist/server/services/websocket/tab-broadcast.js +35 -0
- package/dist/server/services/websocket/tab-event-buffer.js +110 -0
- package/dist/server/services/websocket/tab-event-replay.js +47 -0
- package/dist/server/services/websocket/tab-handlers.js +211 -0
- package/dist/server/services/websocket/terminal-handlers.js +268 -0
- package/dist/server/services/websocket/types.js +96 -0
- package/dist/server/types/company-messages.js +102 -0
- package/dist/server/utils/agent-manager.js +202 -0
- package/dist/server/utils/console-timestamps.js +24 -0
- package/dist/server/utils/file-store.js +112 -0
- package/dist/server/utils/paths.js +28 -0
- package/dist/server/utils/port-manager.js +43 -0
- package/dist/server/utils/port.js +204 -0
- package/electron-host/dist/agent-lease.js +141 -0
- package/electron-host/dist/capture-recovery.js +77 -0
- package/electron-host/dist/codec-policy.js +37 -0
- package/electron-host/dist/controller-channel.js +60 -0
- package/electron-host/dist/controller-handlers.js +153 -0
- package/electron-host/dist/device-emulator.js +106 -0
- package/electron-host/dist/dom-driver.js +642 -0
- package/electron-host/dist/domain-registry.js +159 -0
- package/electron-host/dist/domain-validators.js +308 -0
- package/electron-host/dist/editable-focus-reporter.js +143 -0
- package/electron-host/dist/fake-peer.test-util.js +105 -0
- package/electron-host/dist/host-log.js +31 -0
- package/electron-host/dist/host-wire.js +11 -0
- package/electron-host/dist/input-router.js +421 -0
- package/electron-host/dist/ipc-protocol.js +89 -0
- package/electron-host/dist/ipc-server.js +193 -0
- package/electron-host/dist/js-driver.js +216 -0
- package/electron-host/dist/main-guards.js +70 -0
- package/electron-host/dist/main.js +716 -0
- package/electron-host/dist/roster-sync.js +87 -0
- package/electron-host/dist/rpc-context.js +1 -0
- package/electron-host/dist/rpc-tab-methods.js +138 -0
- package/electron-host/dist/rpc-webrtc-methods.js +121 -0
- package/electron-host/dist/screen-capture-cache.js +147 -0
- package/electron-host/dist/sdk-injector.js +166 -0
- package/electron-host/dist/sdp.js +102 -0
- package/electron-host/dist/session-surface.js +78 -0
- package/electron-host/dist/surface-sizing.js +59 -0
- package/electron-host/dist/view-manager.js +254 -0
- package/electron-host/dist/viewer-registry.js +46 -0
- package/electron-host/dist/viewer-session.js +288 -0
- package/electron-host/dist/webrtc-channels.js +14 -0
- package/electron-host/dist/webrtc-controller.js +57 -0
- package/electron-host/dist/webrtc-ice-filter.js +13 -0
- package/electron-host/dist/webrtc-peer.js +45 -0
- package/electron-host/package.json +12 -0
- package/electron-host/tsconfig.json +23 -0
- package/electron-host/webrtc-controller-preload.cjs +3 -0
- package/electron-host/webrtc-controller.html +14 -0
- package/package.json +85 -0
- package/vendor/e2ee/LICENSE +14 -0
- package/vendor/e2ee/package.json +14 -0
- package/vendor/e2ee/src/index.js +310 -0
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { ResilientRunner } from '../../cli/headless/resilient-runner.js';
|
|
5
|
+
import { resolveClaudeCommand } from '../../engines/claude/claude-command.js';
|
|
6
|
+
import { EMPTY_OUTPUT_NOTICE } from '../../engines/execution/engine-session.js';
|
|
7
|
+
import { loadSkillPrompt } from '../plan/agent-loader.js';
|
|
8
|
+
import { getBrowserAllowlist, getModel } from '../settings.js';
|
|
9
|
+
import { browserDebugEnabled, browserLog } from './debug-log.js';
|
|
10
|
+
import { defaultAgentReasoner } from './reasoning-agent.js';
|
|
11
|
+
const reasonerLog = browserLog('claude-reasoner');
|
|
12
|
+
const agentLog = browserLog('agent');
|
|
13
|
+
export const REASONER_TIMEOUT_MS = 60_000;
|
|
14
|
+
const AVAILABILITY_PROBE_TIMEOUT_MS = 5_000;
|
|
15
|
+
const DEFAULT_MODEL = 'sonnet';
|
|
16
|
+
function probeClaudeAvailability(claudeCommand) {
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
const child = spawn(claudeCommand, ['--version'], {
|
|
19
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
20
|
+
});
|
|
21
|
+
let settled = false;
|
|
22
|
+
const timer = setTimeout(() => {
|
|
23
|
+
if (settled)
|
|
24
|
+
return;
|
|
25
|
+
settled = true;
|
|
26
|
+
try {
|
|
27
|
+
child.kill('SIGTERM');
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
}
|
|
31
|
+
resolve(false);
|
|
32
|
+
}, AVAILABILITY_PROBE_TIMEOUT_MS);
|
|
33
|
+
child.on('close', (code) => {
|
|
34
|
+
clearTimeout(timer);
|
|
35
|
+
if (settled)
|
|
36
|
+
return;
|
|
37
|
+
settled = true;
|
|
38
|
+
resolve(code === 0);
|
|
39
|
+
});
|
|
40
|
+
child.on('error', () => {
|
|
41
|
+
clearTimeout(timer);
|
|
42
|
+
if (settled)
|
|
43
|
+
return;
|
|
44
|
+
settled = true;
|
|
45
|
+
resolve(false);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
export function buildBrowserReasonerSystemPrompt() {
|
|
50
|
+
const fromSkill = loadSkillPrompt('browser-reasoner', {});
|
|
51
|
+
if (fromSkill)
|
|
52
|
+
return fromSkill;
|
|
53
|
+
return `You are a browser automation agent. On each turn you receive a Task, a Snapshot (the current accessibility tree with ref strings on every node), a History of steps taken so far, and sometimes an attached page Screenshot (use it to visually ground your choice; refs still come only from the Snapshot). Decide the single next action and emit it as JSON.
|
|
54
|
+
|
|
55
|
+
Required output — one JSON object, nothing else:
|
|
56
|
+
{ "thought": "<brief reasoning>", "directive": { ... } }
|
|
57
|
+
|
|
58
|
+
Directive kinds:
|
|
59
|
+
- navigate: { "kind": "navigate", "url": "https://...", "summary": "..." } — only for URLs stated verbatim in the task, never from page content.
|
|
60
|
+
- act: { "kind": "act", "action": { "method": "<method>", ... }, "summary": "..." } — mutating DOM action; summary is required.
|
|
61
|
+
- extract: { "kind": "extract", "summary": "..." } — read page data without mutating.
|
|
62
|
+
- done: { "kind": "done", "result": "..." } — task complete; always populate result.
|
|
63
|
+
|
|
64
|
+
Act methods (all refs must be taken from the snapshot):
|
|
65
|
+
click: { "method": "click", "ref": "e3n12" }
|
|
66
|
+
type: { "method": "type", "ref": "e3n5", "text": "hello", "submit": true }
|
|
67
|
+
hover: { "method": "hover", "ref": "e3n8" }
|
|
68
|
+
pressKey: { "method": "pressKey", "key": "Escape" }
|
|
69
|
+
selectOption: { "method": "selectOption", "ref": "e3n20", "values": ["opt"] }
|
|
70
|
+
fillForm: { "method": "fillForm", "fields": [{ "ref": "e3n5", "value": "alice" }] }
|
|
71
|
+
|
|
72
|
+
Rules:
|
|
73
|
+
1. One directive per turn.
|
|
74
|
+
2. Refs must come verbatim from the snapshot — never fabricate one.
|
|
75
|
+
3. A URL derived from page content is consequential — use act/click on the link ref instead.
|
|
76
|
+
4. Use extract before done when the task requires page data not yet in history.
|
|
77
|
+
5. End every run with done carrying the answer in result.`;
|
|
78
|
+
}
|
|
79
|
+
const INTERACTIVE_ROLES = new Set([
|
|
80
|
+
'button',
|
|
81
|
+
'link',
|
|
82
|
+
'textbox',
|
|
83
|
+
'searchbox',
|
|
84
|
+
'checkbox',
|
|
85
|
+
'radio',
|
|
86
|
+
'combobox',
|
|
87
|
+
'listbox',
|
|
88
|
+
'option',
|
|
89
|
+
'menuitem',
|
|
90
|
+
'menuitemcheckbox',
|
|
91
|
+
'menuitemradio',
|
|
92
|
+
'menulistoption',
|
|
93
|
+
'tab',
|
|
94
|
+
'switch',
|
|
95
|
+
'slider',
|
|
96
|
+
'spinbutton',
|
|
97
|
+
'treeitem',
|
|
98
|
+
'gridcell',
|
|
99
|
+
'columnheader',
|
|
100
|
+
'rowheader',
|
|
101
|
+
]);
|
|
102
|
+
export const DEFAULT_SNAPSHOT_CHAR_BUDGET = 8_000;
|
|
103
|
+
function formatNode(node, depth) {
|
|
104
|
+
const indent = ' '.repeat(depth);
|
|
105
|
+
let line = `${indent}${node.ref} ${node.role}`;
|
|
106
|
+
if (node.name)
|
|
107
|
+
line += ` "${node.name}"`;
|
|
108
|
+
if (node.value !== undefined)
|
|
109
|
+
line += ` value="${node.value}"`;
|
|
110
|
+
if (node.checked !== undefined)
|
|
111
|
+
line += ` checked=${node.checked}`;
|
|
112
|
+
if (node.selected)
|
|
113
|
+
line += ' selected';
|
|
114
|
+
if (node.disabled)
|
|
115
|
+
line += ' disabled';
|
|
116
|
+
if (node.expanded !== undefined)
|
|
117
|
+
line += ` expanded=${node.expanded}`;
|
|
118
|
+
return line;
|
|
119
|
+
}
|
|
120
|
+
export function serializeSnapshot(snapshot, opts = {}) {
|
|
121
|
+
const charBudget = opts.charBudget ?? DEFAULT_SNAPSHOT_CHAR_BUDGET;
|
|
122
|
+
const refs = new Set();
|
|
123
|
+
const lines = [
|
|
124
|
+
`URL: ${snapshot.url}`,
|
|
125
|
+
`Title: ${snapshot.title}`,
|
|
126
|
+
'',
|
|
127
|
+
];
|
|
128
|
+
let chars = lines.join('\n').length + 1;
|
|
129
|
+
let truncated = false;
|
|
130
|
+
function walk(node, depth) {
|
|
131
|
+
if (truncated)
|
|
132
|
+
return;
|
|
133
|
+
const roleLc = node.role.toLowerCase();
|
|
134
|
+
if (INTERACTIVE_ROLES.has(roleLc)) {
|
|
135
|
+
const line = formatNode(node, depth);
|
|
136
|
+
if (chars + line.length + 1 > charBudget) {
|
|
137
|
+
truncated = true;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
lines.push(line);
|
|
141
|
+
chars += line.length + 1;
|
|
142
|
+
refs.add(node.ref);
|
|
143
|
+
}
|
|
144
|
+
for (const child of node.children) {
|
|
145
|
+
if (truncated)
|
|
146
|
+
break;
|
|
147
|
+
walk(child, depth + 1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
walk(snapshot.root, 0);
|
|
151
|
+
if (truncated) {
|
|
152
|
+
lines.push('... [snapshot truncated: char budget exceeded]');
|
|
153
|
+
}
|
|
154
|
+
return { text: lines.join('\n'), refs };
|
|
155
|
+
}
|
|
156
|
+
export function buildUserMessage(input) {
|
|
157
|
+
const { task, snapshot, history, currentGoal, screenshot } = input;
|
|
158
|
+
const { text: snapshotText } = serializeSnapshot(snapshot);
|
|
159
|
+
const historyText = history.length === 0
|
|
160
|
+
? '(none)'
|
|
161
|
+
: history
|
|
162
|
+
.map((h, i) => `${i + 1}. [${h.phase}] ${h.detail}`)
|
|
163
|
+
.join('\n');
|
|
164
|
+
return [
|
|
165
|
+
'## Task',
|
|
166
|
+
task,
|
|
167
|
+
...(currentGoal !== undefined
|
|
168
|
+
? [
|
|
169
|
+
'',
|
|
170
|
+
'## Current sub-goal',
|
|
171
|
+
currentGoal,
|
|
172
|
+
'Work only on this sub-goal. Emit a plain `done` (with a one-line result) the moment it is complete — even if the overall Task has later sub-goals.',
|
|
173
|
+
]
|
|
174
|
+
: []),
|
|
175
|
+
'',
|
|
176
|
+
'## Current page',
|
|
177
|
+
snapshotText,
|
|
178
|
+
...(screenshot
|
|
179
|
+
? [
|
|
180
|
+
'',
|
|
181
|
+
'## Screenshot',
|
|
182
|
+
'A screenshot of the current page is attached. Use it to visually locate the right element or understand content the accessibility snapshot misses (canvas, images, layout). Every ref you emit must still come verbatim from the snapshot above.',
|
|
183
|
+
]
|
|
184
|
+
: []),
|
|
185
|
+
'',
|
|
186
|
+
'## History',
|
|
187
|
+
historyText,
|
|
188
|
+
'',
|
|
189
|
+
'Emit the next directive as JSON now.',
|
|
190
|
+
].join('\n');
|
|
191
|
+
}
|
|
192
|
+
function extractJsonObject(raw) {
|
|
193
|
+
const jsonFenced = raw.match(/```json\s*([\s\S]*?)```/);
|
|
194
|
+
if (jsonFenced)
|
|
195
|
+
return jsonFenced[1].trim();
|
|
196
|
+
const anyFenced = raw.match(/```[^\n]*\n([\s\S]*?)```/);
|
|
197
|
+
if (anyFenced)
|
|
198
|
+
return anyFenced[1].trim();
|
|
199
|
+
const braceMatch = raw.match(/\{[\s\S]*\}/);
|
|
200
|
+
if (braceMatch)
|
|
201
|
+
return braceMatch[0].trim();
|
|
202
|
+
return raw.trim();
|
|
203
|
+
}
|
|
204
|
+
const ACTION_VALIDATORS = {
|
|
205
|
+
click: (a) => {
|
|
206
|
+
if (typeof a.ref !== 'string' || !a.ref)
|
|
207
|
+
throw new Error('click requires ref');
|
|
208
|
+
return { method: 'click', ref: a.ref };
|
|
209
|
+
},
|
|
210
|
+
type: (a) => {
|
|
211
|
+
if (typeof a.ref !== 'string' || !a.ref)
|
|
212
|
+
throw new Error('type requires ref');
|
|
213
|
+
if (typeof a.text !== 'string')
|
|
214
|
+
throw new Error('type requires text');
|
|
215
|
+
return { method: 'type', ref: a.ref, text: a.text, ...(a.submit !== undefined ? { submit: Boolean(a.submit) } : {}) };
|
|
216
|
+
},
|
|
217
|
+
hover: (a) => {
|
|
218
|
+
if (typeof a.ref !== 'string' || !a.ref)
|
|
219
|
+
throw new Error('hover requires ref');
|
|
220
|
+
return { method: 'hover', ref: a.ref };
|
|
221
|
+
},
|
|
222
|
+
pressKey: (a) => {
|
|
223
|
+
if (typeof a.key !== 'string' || !a.key)
|
|
224
|
+
throw new Error('pressKey requires key');
|
|
225
|
+
return { method: 'pressKey', key: a.key };
|
|
226
|
+
},
|
|
227
|
+
selectOption: (a) => {
|
|
228
|
+
if (typeof a.ref !== 'string' || !a.ref)
|
|
229
|
+
throw new Error('selectOption requires ref');
|
|
230
|
+
if (!Array.isArray(a.values) || !a.values.every((v) => typeof v === 'string'))
|
|
231
|
+
throw new Error('selectOption requires values: string[]');
|
|
232
|
+
return { method: 'selectOption', ref: a.ref, values: a.values };
|
|
233
|
+
},
|
|
234
|
+
fillForm: (a) => {
|
|
235
|
+
if (!Array.isArray(a.fields))
|
|
236
|
+
throw new Error('fillForm requires fields array');
|
|
237
|
+
const fields = a.fields.map((f) => {
|
|
238
|
+
if (!f || typeof f !== 'object')
|
|
239
|
+
throw new Error('fillForm field must be an object');
|
|
240
|
+
const ff = f;
|
|
241
|
+
if (typeof ff.ref !== 'string' || !ff.ref)
|
|
242
|
+
throw new Error('fillForm field requires ref');
|
|
243
|
+
if (typeof ff.value !== 'string')
|
|
244
|
+
throw new Error('fillForm field requires value');
|
|
245
|
+
return { ref: ff.ref, value: ff.value };
|
|
246
|
+
});
|
|
247
|
+
return { method: 'fillForm', fields };
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
function validateAction(raw) {
|
|
251
|
+
if (!raw || typeof raw !== 'object')
|
|
252
|
+
throw new Error('action must be an object');
|
|
253
|
+
const a = raw;
|
|
254
|
+
const method = a.method;
|
|
255
|
+
const validator = ACTION_VALIDATORS[method];
|
|
256
|
+
if (!validator)
|
|
257
|
+
throw new Error(`unknown act method "${method}"`);
|
|
258
|
+
return validator(a);
|
|
259
|
+
}
|
|
260
|
+
function validateDirectiveObject(raw) {
|
|
261
|
+
const kind = raw.kind;
|
|
262
|
+
switch (kind) {
|
|
263
|
+
case 'navigate': {
|
|
264
|
+
if (typeof raw.url !== 'string' || !raw.url)
|
|
265
|
+
throw new Error('navigate requires url');
|
|
266
|
+
return { kind: 'navigate', url: raw.url, ...(typeof raw.summary === 'string' ? { summary: raw.summary } : {}) };
|
|
267
|
+
}
|
|
268
|
+
case 'act': {
|
|
269
|
+
const action = validateAction(raw.action);
|
|
270
|
+
const summary = typeof raw.summary === 'string' ? raw.summary : '';
|
|
271
|
+
return { kind: 'act', action, summary };
|
|
272
|
+
}
|
|
273
|
+
case 'extract':
|
|
274
|
+
return { kind: 'extract', ...(typeof raw.summary === 'string' ? { summary: raw.summary } : {}) };
|
|
275
|
+
case 'done':
|
|
276
|
+
return { kind: 'done', ...(raw.result !== undefined ? { result: String(raw.result) } : {}) };
|
|
277
|
+
default:
|
|
278
|
+
throw new Error(`unknown directive kind "${kind}"`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function getDirectiveRefs(directive) {
|
|
282
|
+
if (directive.kind !== 'act')
|
|
283
|
+
return [];
|
|
284
|
+
const action = directive.action;
|
|
285
|
+
switch (action.method) {
|
|
286
|
+
case 'click': return [action.ref];
|
|
287
|
+
case 'type': return [action.ref];
|
|
288
|
+
case 'hover': return [action.ref];
|
|
289
|
+
case 'pressKey': return [];
|
|
290
|
+
case 'selectOption': return [action.ref];
|
|
291
|
+
case 'fillForm': return action.fields.map((f) => f.ref);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function firstInvalidRef(directive, validRefs) {
|
|
295
|
+
if (validRefs.size === 0)
|
|
296
|
+
return null;
|
|
297
|
+
for (const ref of getDirectiveRefs(directive)) {
|
|
298
|
+
if (!validRefs.has(ref))
|
|
299
|
+
return ref;
|
|
300
|
+
}
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
function isEmptyModelOutput(rawText) {
|
|
304
|
+
const trimmed = rawText?.trim();
|
|
305
|
+
return !trimmed || trimmed === EMPTY_OUTPUT_NOTICE;
|
|
306
|
+
}
|
|
307
|
+
export function parseDirective(rawText, validRefs) {
|
|
308
|
+
try {
|
|
309
|
+
if (isEmptyModelOutput(rawText)) {
|
|
310
|
+
return { kind: 'done', result: 'browser-reasoner: empty response from model' };
|
|
311
|
+
}
|
|
312
|
+
const jsonStr = extractJsonObject(rawText);
|
|
313
|
+
let parsed;
|
|
314
|
+
try {
|
|
315
|
+
parsed = JSON.parse(jsonStr);
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
return { kind: 'done', result: `browser-reasoner: failed to parse JSON from model response` };
|
|
319
|
+
}
|
|
320
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
321
|
+
return { kind: 'done', result: 'browser-reasoner: parsed value is not an object' };
|
|
322
|
+
}
|
|
323
|
+
const rawDirective = parsed.directive;
|
|
324
|
+
if (!rawDirective || typeof rawDirective !== 'object' || Array.isArray(rawDirective)) {
|
|
325
|
+
return { kind: 'done', result: 'browser-reasoner: response missing "directive" field' };
|
|
326
|
+
}
|
|
327
|
+
const directive = validateDirectiveObject(rawDirective);
|
|
328
|
+
const invalidRef = firstInvalidRef(directive, validRefs);
|
|
329
|
+
if (invalidRef !== null) {
|
|
330
|
+
return { kind: 'done', result: `browser-reasoner: ref "${invalidRef}" is not present in the current snapshot` };
|
|
331
|
+
}
|
|
332
|
+
return directive;
|
|
333
|
+
}
|
|
334
|
+
catch (err) {
|
|
335
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
336
|
+
return { kind: 'done', result: `browser-reasoner: ${msg}` };
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
export function parseReasonerResponse(raw) {
|
|
340
|
+
return parseDirective(raw, new Set());
|
|
341
|
+
}
|
|
342
|
+
async function _runResilient(prompt, opts) {
|
|
343
|
+
const { model, engineId, effortLevel, timeoutMs, workingDir, imageAttachments } = opts;
|
|
344
|
+
const runner = new ResilientRunner({
|
|
345
|
+
workingDir,
|
|
346
|
+
prompt,
|
|
347
|
+
policy: 'NONE',
|
|
348
|
+
inferenceOnly: true,
|
|
349
|
+
effortLevel: effortLevel ?? 'auto',
|
|
350
|
+
...(imageAttachments && imageAttachments.length > 0 ? { imageAttachments } : {}),
|
|
351
|
+
...(model ? { model } : {}),
|
|
352
|
+
...(engineId ? { engineId } : {}),
|
|
353
|
+
stallWarningMs: Math.max(1_000, Math.floor(timeoutMs / 2)),
|
|
354
|
+
stallKillMs: timeoutMs,
|
|
355
|
+
stallHardCapMs: timeoutMs,
|
|
356
|
+
verbose: false,
|
|
357
|
+
logLabel: 'browser-reasoner',
|
|
358
|
+
outputCallback: () => { },
|
|
359
|
+
});
|
|
360
|
+
const result = await runner.run();
|
|
361
|
+
return result.assistantResponse ?? '';
|
|
362
|
+
}
|
|
363
|
+
function navIsUserDerived(url, task) {
|
|
364
|
+
const taskLc = task.toLowerCase();
|
|
365
|
+
if (taskLc.includes(url.toLowerCase()))
|
|
366
|
+
return true;
|
|
367
|
+
try {
|
|
368
|
+
const host = new URL(url).hostname.toLowerCase();
|
|
369
|
+
return host.length > 0 && taskLc.includes(host);
|
|
370
|
+
}
|
|
371
|
+
catch {
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const SECOND_LEVEL_REGISTRY_LABELS = new Set(['co', 'com', 'net', 'org', 'ac', 'gov', 'edu']);
|
|
376
|
+
function navIsSiteNamed(url, task) {
|
|
377
|
+
try {
|
|
378
|
+
const host = new URL(url).hostname.toLowerCase();
|
|
379
|
+
const taskLc = task.toLowerCase();
|
|
380
|
+
return registrableLabels(host).some((label) => taskNamesLabel(taskLc, label));
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
function registrableLabels(host) {
|
|
387
|
+
const labels = host.split('.').filter((l) => l.length > 0);
|
|
388
|
+
if (labels[0] === 'www')
|
|
389
|
+
labels.shift();
|
|
390
|
+
if (labels.length < 2)
|
|
391
|
+
return [];
|
|
392
|
+
const secondLevel = labels[labels.length - 2];
|
|
393
|
+
const site = SECOND_LEVEL_REGISTRY_LABELS.has(secondLevel) && labels.length >= 3
|
|
394
|
+
? labels[labels.length - 3]
|
|
395
|
+
: secondLevel;
|
|
396
|
+
return site.length >= 3 ? [site] : [];
|
|
397
|
+
}
|
|
398
|
+
function taskNamesLabel(taskLc, label) {
|
|
399
|
+
const escaped = label.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
400
|
+
return new RegExp(`(^|[^a-z0-9])${escaped}([^a-z0-9]|$)`).test(taskLc);
|
|
401
|
+
}
|
|
402
|
+
function hostOf(value) {
|
|
403
|
+
try {
|
|
404
|
+
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(value) ? value : `https://${value}`;
|
|
405
|
+
return new URL(withScheme).hostname.toLowerCase();
|
|
406
|
+
}
|
|
407
|
+
catch {
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function originIsAllowlisted(url, allowlist) {
|
|
412
|
+
const host = hostOf(url);
|
|
413
|
+
if (!host)
|
|
414
|
+
return false;
|
|
415
|
+
if (host === 'localhost' || host === '127.0.0.1' || host.endsWith('.localhost'))
|
|
416
|
+
return true;
|
|
417
|
+
for (const entry of allowlist) {
|
|
418
|
+
const entryHost = hostOf(entry);
|
|
419
|
+
if (!entryHost)
|
|
420
|
+
continue;
|
|
421
|
+
if (host === entryHost || host.endsWith(`.${entryHost}`))
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
function classifyNavigate(url, task, allowlist) {
|
|
427
|
+
if (navIsUserDerived(url, task))
|
|
428
|
+
return 'trusted';
|
|
429
|
+
if (navIsSiteNamed(url, task))
|
|
430
|
+
return 'allowlisted';
|
|
431
|
+
if (originIsAllowlisted(url, allowlist))
|
|
432
|
+
return 'allowlisted';
|
|
433
|
+
return 'blocked';
|
|
434
|
+
}
|
|
435
|
+
function directiveRejection(directive, validRefs, task, allowlist) {
|
|
436
|
+
if (directive.kind === 'act' && validRefs.size > 0) {
|
|
437
|
+
for (const ref of getDirectiveRefs(directive)) {
|
|
438
|
+
if (!validRefs.has(ref)) {
|
|
439
|
+
return `ref "${ref}" is not present in the current snapshot — choose a ref from the page above or use extract`;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
if (directive.kind === 'navigate' && classifyNavigate(directive.url, task, allowlist) === 'blocked') {
|
|
445
|
+
return `navigation to "${directive.url}" is derived from page content and is outside the origin allowlist — click the link's ref instead of navigating`;
|
|
446
|
+
}
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
function annotateNavigate(directive, task, allowlist) {
|
|
450
|
+
if (directive.kind !== 'navigate')
|
|
451
|
+
return directive;
|
|
452
|
+
if (classifyNavigate(directive.url, task, allowlist) !== 'allowlisted')
|
|
453
|
+
return directive;
|
|
454
|
+
const tag = '[content-derived: allowlisted, treat as consequential]';
|
|
455
|
+
const summary = directive.summary ? `${directive.summary} ${tag}` : tag;
|
|
456
|
+
return { ...directive, summary };
|
|
457
|
+
}
|
|
458
|
+
function logPrompt(fullPrompt) {
|
|
459
|
+
if (!browserDebugEnabled)
|
|
460
|
+
return;
|
|
461
|
+
const promptChars = fullPrompt.length;
|
|
462
|
+
const promptTokens = Math.ceil(promptChars / 4);
|
|
463
|
+
agentLog('prompt', `chars=${promptChars} tokens~${promptTokens}`);
|
|
464
|
+
}
|
|
465
|
+
function logResponse(raw) {
|
|
466
|
+
if (!browserDebugEnabled)
|
|
467
|
+
return;
|
|
468
|
+
const responseChars = raw.length;
|
|
469
|
+
const truncated = responseChars > 500 ? `${raw.slice(0, 500)}... [truncated ${responseChars - 500} chars]` : raw;
|
|
470
|
+
agentLog('response', truncated);
|
|
471
|
+
}
|
|
472
|
+
function screenshotAttachments(screenshot) {
|
|
473
|
+
if (!screenshot)
|
|
474
|
+
return undefined;
|
|
475
|
+
return [
|
|
476
|
+
{
|
|
477
|
+
fileName: `page-screenshot.${screenshot.format}`,
|
|
478
|
+
filePath: '',
|
|
479
|
+
content: screenshot.data,
|
|
480
|
+
isImage: true,
|
|
481
|
+
mimeType: screenshot.format === 'jpeg' ? 'image/jpeg' : 'image/png',
|
|
482
|
+
},
|
|
483
|
+
];
|
|
484
|
+
}
|
|
485
|
+
async function inferWithEmptyRetry(inferOnce, baseSuffix) {
|
|
486
|
+
const first = await inferOnce(baseSuffix);
|
|
487
|
+
if (!isEmptyModelOutput(first.raw))
|
|
488
|
+
return first;
|
|
489
|
+
reasonerLog('empty-turn', 'model produced no visible output — re-prompting once');
|
|
490
|
+
return inferOnce(`${baseSuffix}\n\n## Correction\nYour previous turn produced no visible output. Respond now with ONLY the required JSON object ({ "thought": ..., "directive": ... }) — no other text, no hidden reasoning.`);
|
|
491
|
+
}
|
|
492
|
+
async function inferTurn(config, suffix, imageAttachments) {
|
|
493
|
+
const { staticPrefix, infer, model, engineId, effortLevel, claudeCommand, timeoutMs, workingDir } = config;
|
|
494
|
+
const fullPrompt = `${staticPrefix}\n${suffix}`;
|
|
495
|
+
logPrompt(fullPrompt);
|
|
496
|
+
const raw = await infer(fullPrompt, {
|
|
497
|
+
...(model !== undefined ? { model } : {}),
|
|
498
|
+
...(engineId ? { engineId } : {}),
|
|
499
|
+
...(effortLevel ? { effortLevel } : {}),
|
|
500
|
+
claudeCommand,
|
|
501
|
+
timeoutMs,
|
|
502
|
+
workingDir,
|
|
503
|
+
...(imageAttachments && imageAttachments.length > 0 ? { imageAttachments } : {}),
|
|
504
|
+
});
|
|
505
|
+
logResponse(raw);
|
|
506
|
+
const directive = parseDirective(raw, new Set());
|
|
507
|
+
if (browserDebugEnabled) {
|
|
508
|
+
agentLog('directive', JSON.stringify(directive));
|
|
509
|
+
}
|
|
510
|
+
return { raw, directive };
|
|
511
|
+
}
|
|
512
|
+
export function createClaudeReasoner(opts = {}) {
|
|
513
|
+
const claudeCommand = opts.claudeCommand ?? resolveClaudeCommand();
|
|
514
|
+
const timeoutMs = opts.timeoutMs ?? REASONER_TIMEOUT_MS;
|
|
515
|
+
const workingDir = opts.workingDir ?? process.cwd();
|
|
516
|
+
const engineId = opts.engine;
|
|
517
|
+
const effortLevel = opts.effortLevel;
|
|
518
|
+
const isClaudeEngine = (engineId ?? 'claude-code') === 'claude-code';
|
|
519
|
+
const model = opts.model ?? (isClaudeEngine ? (opts.useSettingsModel ? getModel() : DEFAULT_MODEL) : undefined);
|
|
520
|
+
const infer = opts.infer ?? _runResilient;
|
|
521
|
+
const fallback = opts.fallback ?? defaultAgentReasoner;
|
|
522
|
+
const probe = opts.probe ??
|
|
523
|
+
(isClaudeEngine ? () => probeClaudeAvailability(claudeCommand) : () => Promise.resolve(true));
|
|
524
|
+
const getAllowlist = opts.getAllowlist ?? getBrowserAllowlist;
|
|
525
|
+
const staticPrefix = `${buildBrowserReasonerSystemPrompt()}\n\n---\n`;
|
|
526
|
+
let probePromise = null;
|
|
527
|
+
return async (input) => {
|
|
528
|
+
try {
|
|
529
|
+
if (probePromise === null) {
|
|
530
|
+
probePromise = probe();
|
|
531
|
+
}
|
|
532
|
+
const available = await probePromise;
|
|
533
|
+
if (!available) {
|
|
534
|
+
reasonerLog('fallback', `claude binary unavailable (cmd=${claudeCommand}) — using fallback reasoner`);
|
|
535
|
+
return fallback(input);
|
|
536
|
+
}
|
|
537
|
+
const { refs } = serializeSnapshot(input.snapshot);
|
|
538
|
+
const allowlist = getAllowlist();
|
|
539
|
+
const baseSuffix = buildUserMessage(input);
|
|
540
|
+
const turnAttachments = screenshotAttachments(input.screenshot);
|
|
541
|
+
const inferOnce = (suffix) => inferTurn({
|
|
542
|
+
staticPrefix,
|
|
543
|
+
infer,
|
|
544
|
+
model,
|
|
545
|
+
...(engineId ? { engineId } : {}),
|
|
546
|
+
...(effortLevel ? { effortLevel } : {}),
|
|
547
|
+
claudeCommand,
|
|
548
|
+
timeoutMs,
|
|
549
|
+
workingDir,
|
|
550
|
+
}, suffix, turnAttachments);
|
|
551
|
+
let directive = (await inferWithEmptyRetry(inferOnce, baseSuffix)).directive;
|
|
552
|
+
let rejection = directiveRejection(directive, refs, input.task, allowlist);
|
|
553
|
+
if (rejection) {
|
|
554
|
+
reasonerLog('reprompt', rejection);
|
|
555
|
+
const corrected = `${baseSuffix}\n\n## Correction\nYour previous directive was rejected: ${rejection}\nEmit a corrected directive as JSON now. Use only refs present in the snapshot above; for any destination not named in the Task, click the link's ref instead of navigating.`;
|
|
556
|
+
directive = (await inferOnce(corrected)).directive;
|
|
557
|
+
rejection = directiveRejection(directive, refs, input.task, allowlist);
|
|
558
|
+
if (rejection) {
|
|
559
|
+
return { kind: 'done', result: `browser-reasoner: ${rejection}` };
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return annotateNavigate(directive, input.task, allowlist);
|
|
563
|
+
}
|
|
564
|
+
catch (err) {
|
|
565
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
566
|
+
reasonerLog('error', msg);
|
|
567
|
+
return { kind: 'done', result: `browser-reasoner: ${msg}` };
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
export const PLANNER_MAX_GOALS = 8;
|
|
572
|
+
export function buildBrowserPlannerSystemPrompt() {
|
|
573
|
+
const fromSkill = loadSkillPrompt('browser-planner', {});
|
|
574
|
+
if (fromSkill)
|
|
575
|
+
return fromSkill;
|
|
576
|
+
return `You are the PLANNER for a browser automation agent. Decompose the user's Task into an ordered list of high-level sub-goals that an executor will carry out one at a time.
|
|
577
|
+
|
|
578
|
+
Required output — one JSON object, nothing else:
|
|
579
|
+
{ "thought": "<brief reasoning>", "plan": ["<sub-goal 1>", "<sub-goal 2>", ...] }
|
|
580
|
+
|
|
581
|
+
Rules:
|
|
582
|
+
1. Each sub-goal is ONE short, page-independent instruction (e.g. "navigate to google.com", "type 'cat' in the search box and submit", "report the top results"). 2 to ${PLANNER_MAX_GOALS} sub-goals.
|
|
583
|
+
2. Do NOT reference element ids/refs or invent selectors — the executor sees the live page and picks those.
|
|
584
|
+
3. Do NOT invent URLs or hostnames that are not stated in the Task. Only include a "navigate to <url>" sub-goal when that URL/host appears in the Task itself.
|
|
585
|
+
4. The final sub-goal should report or confirm the outcome the Task asked for.
|
|
586
|
+
5. Keep it minimal — no steps unrelated to the Task.`;
|
|
587
|
+
}
|
|
588
|
+
function buildPlannerUserMessage(input) {
|
|
589
|
+
const lines = ['## Task', input.task];
|
|
590
|
+
if (input.snapshot) {
|
|
591
|
+
const { text } = serializeSnapshot(input.snapshot);
|
|
592
|
+
lines.push('', '## Current page', text);
|
|
593
|
+
}
|
|
594
|
+
lines.push('', 'Emit the plan as JSON now.');
|
|
595
|
+
return lines.join('\n');
|
|
596
|
+
}
|
|
597
|
+
export function parsePlan(raw, max = PLANNER_MAX_GOALS) {
|
|
598
|
+
try {
|
|
599
|
+
if (!raw?.trim())
|
|
600
|
+
return [];
|
|
601
|
+
const parsed = JSON.parse(extractJsonObject(raw));
|
|
602
|
+
const arr = parsed?.plan;
|
|
603
|
+
if (!Array.isArray(arr))
|
|
604
|
+
return [];
|
|
605
|
+
const goals = [];
|
|
606
|
+
for (const item of arr) {
|
|
607
|
+
if (typeof item !== 'string')
|
|
608
|
+
continue;
|
|
609
|
+
const g = item.trim();
|
|
610
|
+
if (g && !goals.includes(g))
|
|
611
|
+
goals.push(g);
|
|
612
|
+
if (goals.length >= max)
|
|
613
|
+
break;
|
|
614
|
+
}
|
|
615
|
+
return goals;
|
|
616
|
+
}
|
|
617
|
+
catch {
|
|
618
|
+
return [];
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
export function createClaudePlanner(opts = {}) {
|
|
622
|
+
const claudeCommand = opts.claudeCommand ?? resolveClaudeCommand();
|
|
623
|
+
const timeoutMs = opts.timeoutMs ?? REASONER_TIMEOUT_MS;
|
|
624
|
+
const workingDir = opts.workingDir ?? process.cwd();
|
|
625
|
+
const engineId = opts.engine;
|
|
626
|
+
const isClaudeEngine = (engineId ?? 'claude-code') === 'claude-code';
|
|
627
|
+
const model = opts.model ?? (isClaudeEngine ? (opts.useSettingsModel ? getModel() : DEFAULT_MODEL) : undefined);
|
|
628
|
+
const infer = opts.infer ?? _runResilient;
|
|
629
|
+
const probe = opts.probe ??
|
|
630
|
+
(isClaudeEngine ? () => probeClaudeAvailability(claudeCommand) : () => Promise.resolve(true));
|
|
631
|
+
const maxGoals = opts.maxGoals ?? PLANNER_MAX_GOALS;
|
|
632
|
+
const fallback = opts.fallback ?? ((input) => [input.task]);
|
|
633
|
+
const staticPrefix = `${buildBrowserPlannerSystemPrompt()}\n\n---\n`;
|
|
634
|
+
const inferOpts = inferenceOptions({ model, engineId, effortLevel: opts.effortLevel }, { claudeCommand, timeoutMs, workingDir });
|
|
635
|
+
let probePromise = null;
|
|
636
|
+
return async (input) => {
|
|
637
|
+
try {
|
|
638
|
+
if (probePromise === null)
|
|
639
|
+
probePromise = probe();
|
|
640
|
+
if (!(await probePromise)) {
|
|
641
|
+
reasonerLog('planner.fallback', `claude unavailable (cmd=${claudeCommand}) — single-goal plan`);
|
|
642
|
+
return fallback(input);
|
|
643
|
+
}
|
|
644
|
+
const fullPrompt = `${staticPrefix}\n${buildPlannerUserMessage(input)}`;
|
|
645
|
+
const raw = await infer(fullPrompt, inferOpts);
|
|
646
|
+
const goals = parsePlan(raw, maxGoals);
|
|
647
|
+
logPlannerDebug(raw, goals);
|
|
648
|
+
return goals.length > 0 ? goals : fallback(input);
|
|
649
|
+
}
|
|
650
|
+
catch (err) {
|
|
651
|
+
reasonerLog('planner.error', err instanceof Error ? err.message : String(err));
|
|
652
|
+
return fallback(input);
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
function inferenceOptions(target, base) {
|
|
657
|
+
return {
|
|
658
|
+
...(target.model !== undefined ? { model: target.model } : {}),
|
|
659
|
+
...(target.engineId ? { engineId: target.engineId } : {}),
|
|
660
|
+
...(target.effortLevel ? { effortLevel: target.effortLevel } : {}),
|
|
661
|
+
...base,
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
function logPlannerDebug(raw, goals) {
|
|
665
|
+
if (!browserDebugEnabled)
|
|
666
|
+
return;
|
|
667
|
+
agentLog('planner.response', raw.length > 500 ? `${raw.slice(0, 500)}...` : raw);
|
|
668
|
+
agentLog('planner.plan', JSON.stringify(goals));
|
|
669
|
+
}
|