@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,310 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { PlanExecutor } from '../plan/executor.js';
|
|
5
|
+
import { resolvePmDir } from '../plan/parser.js';
|
|
6
|
+
import { wireExecutorEvents } from '../websocket/plan-execution-handlers.js';
|
|
7
|
+
import { schedulerCache } from '../websocket/plan-helpers.js';
|
|
8
|
+
import { bootstrapRun } from './run-bootstrap.js';
|
|
9
|
+
import { ScheduleStore } from './schedule-store.js';
|
|
10
|
+
export const SCHEDULER_TICK_MS = 30_000;
|
|
11
|
+
export const SCHEDULE_ONCE_GRACE_MS = 15 * 60_000;
|
|
12
|
+
export const CONTINUOUS_MIN_SPACING_MS = 60_000;
|
|
13
|
+
export const CONTINUOUS_MAX_BACKOFF_MS = 30 * 60_000;
|
|
14
|
+
export function continuousDelayMs(consecutiveEmptyRuns) {
|
|
15
|
+
const empties = Math.max(0, Math.floor(consecutiveEmptyRuns));
|
|
16
|
+
return Math.min(CONTINUOUS_MIN_SPACING_MS * 2 ** empties, CONTINUOUS_MAX_BACKOFF_MS);
|
|
17
|
+
}
|
|
18
|
+
export class ScheduledRunRegistry {
|
|
19
|
+
runs = new Map();
|
|
20
|
+
get(scheduleId) {
|
|
21
|
+
return this.runs.get(scheduleId);
|
|
22
|
+
}
|
|
23
|
+
has(scheduleId) {
|
|
24
|
+
return this.runs.has(scheduleId);
|
|
25
|
+
}
|
|
26
|
+
set(scheduleId, run) {
|
|
27
|
+
this.runs.set(scheduleId, run);
|
|
28
|
+
}
|
|
29
|
+
delete(scheduleId) {
|
|
30
|
+
this.runs.delete(scheduleId);
|
|
31
|
+
}
|
|
32
|
+
activeIds() {
|
|
33
|
+
return Array.from(this.runs.keys());
|
|
34
|
+
}
|
|
35
|
+
snapshotValues() {
|
|
36
|
+
return Array.from(this.runs.values());
|
|
37
|
+
}
|
|
38
|
+
reset() {
|
|
39
|
+
for (const run of this.runs.values()) {
|
|
40
|
+
try {
|
|
41
|
+
run.settled = true;
|
|
42
|
+
run.executor.removeAllListeners();
|
|
43
|
+
run.executor.stop();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
this.runs.clear();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export class SchedulerEngine {
|
|
52
|
+
workingDir;
|
|
53
|
+
runs = new ScheduledRunRegistry();
|
|
54
|
+
ctx;
|
|
55
|
+
deps;
|
|
56
|
+
tickIntervalMs;
|
|
57
|
+
timer = null;
|
|
58
|
+
store = null;
|
|
59
|
+
constructor(workingDir, ctx, deps = {}) {
|
|
60
|
+
this.workingDir = workingDir;
|
|
61
|
+
this.ctx = ctx;
|
|
62
|
+
this.deps = deps;
|
|
63
|
+
this.tickIntervalMs = deps.tickIntervalMs ?? SCHEDULER_TICK_MS;
|
|
64
|
+
}
|
|
65
|
+
getStore() {
|
|
66
|
+
return this.store;
|
|
67
|
+
}
|
|
68
|
+
isRunning() {
|
|
69
|
+
return this.timer !== null;
|
|
70
|
+
}
|
|
71
|
+
start() {
|
|
72
|
+
if (this.timer)
|
|
73
|
+
return;
|
|
74
|
+
if (!resolvePmDir(this.workingDir))
|
|
75
|
+
return;
|
|
76
|
+
this.store = new ScheduleStore(this.workingDir);
|
|
77
|
+
this.recoverMissedFires();
|
|
78
|
+
this.tick();
|
|
79
|
+
this.timer = setInterval(() => this.tick(), this.tickIntervalMs);
|
|
80
|
+
if (typeof this.timer.unref === 'function')
|
|
81
|
+
this.timer.unref();
|
|
82
|
+
}
|
|
83
|
+
stop() {
|
|
84
|
+
if (this.timer) {
|
|
85
|
+
clearInterval(this.timer);
|
|
86
|
+
this.timer = null;
|
|
87
|
+
}
|
|
88
|
+
this.runs.reset();
|
|
89
|
+
this.store = null;
|
|
90
|
+
}
|
|
91
|
+
tick() {
|
|
92
|
+
const store = this.store;
|
|
93
|
+
if (!store)
|
|
94
|
+
return;
|
|
95
|
+
const now = Date.now();
|
|
96
|
+
for (const record of store.list()) {
|
|
97
|
+
if (!record.enabled)
|
|
98
|
+
continue;
|
|
99
|
+
if (this.runs.has(record.id)) {
|
|
100
|
+
if (record.timing.kind !== 'continuous' && this.isDue(record, now)) {
|
|
101
|
+
this.recordSkippedOverlap(record, now);
|
|
102
|
+
}
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (!this.isDue(record, now))
|
|
106
|
+
continue;
|
|
107
|
+
this.fire(record, now);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
isDue(record, now) {
|
|
111
|
+
if (record.timing.kind === 'continuous') {
|
|
112
|
+
if (record.nextFireAt)
|
|
113
|
+
return parseEpoch(record.nextFireAt) <= now;
|
|
114
|
+
const lastAt = record.lastFire ? parseEpoch(record.lastFire.at) : Number.NaN;
|
|
115
|
+
if (!Number.isFinite(lastAt))
|
|
116
|
+
return true;
|
|
117
|
+
return now - lastAt >= continuousDelayMs(record.consecutiveEmptyRuns);
|
|
118
|
+
}
|
|
119
|
+
if (!record.nextFireAt)
|
|
120
|
+
return false;
|
|
121
|
+
const at = parseEpoch(record.nextFireAt);
|
|
122
|
+
return Number.isFinite(at) && at <= now;
|
|
123
|
+
}
|
|
124
|
+
recoverMissedFires() {
|
|
125
|
+
const store = this.store;
|
|
126
|
+
if (!store)
|
|
127
|
+
return;
|
|
128
|
+
const now = Date.now();
|
|
129
|
+
for (const record of store.list()) {
|
|
130
|
+
if (!record.enabled)
|
|
131
|
+
continue;
|
|
132
|
+
if (record.timing.kind === 'once') {
|
|
133
|
+
this.recoverOnce(record, now);
|
|
134
|
+
}
|
|
135
|
+
else if (record.timing.kind === 'interval') {
|
|
136
|
+
this.recoverInterval(record, now);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
recoverOnce(record, now) {
|
|
141
|
+
if (record.timing.kind !== 'once')
|
|
142
|
+
return;
|
|
143
|
+
const at = parseEpoch(record.timing.at);
|
|
144
|
+
if (!Number.isFinite(at) || at > now)
|
|
145
|
+
return;
|
|
146
|
+
if (now - at <= SCHEDULE_ONCE_GRACE_MS) {
|
|
147
|
+
this.fire(record, now);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const store = this.store;
|
|
151
|
+
if (!store)
|
|
152
|
+
return;
|
|
153
|
+
store.recordFire(record.id, { at: new Date(now).toISOString(), status: 'missed', boardId: null, error: 'missed by more than the 15 minute grace window' }, null);
|
|
154
|
+
store.setEnabled(record.id, false);
|
|
155
|
+
this.broadcastSchedules();
|
|
156
|
+
}
|
|
157
|
+
recoverInterval(record, now) {
|
|
158
|
+
const next = record.nextFireAt ? parseEpoch(record.nextFireAt) : Number.NaN;
|
|
159
|
+
if (Number.isFinite(next) && next > now)
|
|
160
|
+
return;
|
|
161
|
+
this.fire(record, now);
|
|
162
|
+
}
|
|
163
|
+
fire(record, now) {
|
|
164
|
+
const store = this.store;
|
|
165
|
+
if (!store)
|
|
166
|
+
return;
|
|
167
|
+
const pmDir = resolvePmDir(this.workingDir);
|
|
168
|
+
if (!pmDir)
|
|
169
|
+
return;
|
|
170
|
+
const firedAt = new Date(now).toISOString();
|
|
171
|
+
const source = { kind: record.source.kind, durablePath: join(pmDir, record.source.path) };
|
|
172
|
+
let result;
|
|
173
|
+
try {
|
|
174
|
+
result = (this.deps.bootstrap ?? bootstrapRun)(this.workingDir, source, record.input, {
|
|
175
|
+
scheduleId: record.id,
|
|
176
|
+
broadcast: response => this.ctx.broadcastToAll(response),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
this.recordFailedFire(record, firedAt, errorMessage(error));
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
store.recordFire(record.id, { at: firedAt, status: 'started', boardId: result.boardId }, this.nextFireAtAfterStart(record, now));
|
|
184
|
+
this.broadcastSchedules();
|
|
185
|
+
this.ctx.broadcastToAll({
|
|
186
|
+
type: 'planScheduleFired',
|
|
187
|
+
data: { scheduleId: record.id, boardId: result.boardId, firedAt },
|
|
188
|
+
});
|
|
189
|
+
this.startRun(record, result.boardId, now);
|
|
190
|
+
}
|
|
191
|
+
startRun(record, boardId, now) {
|
|
192
|
+
const executor = (this.deps.createExecutor ?? defaultCreateExecutor)(this.workingDir);
|
|
193
|
+
const run = { scheduleId: record.id, boardId, executor, startedAt: now, lastError: null, settled: false };
|
|
194
|
+
this.runs.set(record.id, run);
|
|
195
|
+
(this.deps.wireEvents ?? wireExecutorEvents)(executor, this.ctx, this.workingDir, boardId);
|
|
196
|
+
executor.on('error', (message) => {
|
|
197
|
+
run.lastError = errorMessage(message);
|
|
198
|
+
this.settle(run);
|
|
199
|
+
});
|
|
200
|
+
executor.on('complete', () => { this.settle(run); });
|
|
201
|
+
this.ctx.broadcastToAll({ type: 'planExecutionStarted', data: { status: 'executing', boardId } });
|
|
202
|
+
executor.startBoard(boardId).then(() => this.settle(run), (error) => {
|
|
203
|
+
run.lastError = errorMessage(error);
|
|
204
|
+
this.settle(run);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
settle(run) {
|
|
208
|
+
if (run.settled)
|
|
209
|
+
return;
|
|
210
|
+
run.settled = true;
|
|
211
|
+
this.runs.delete(run.scheduleId);
|
|
212
|
+
const store = this.store;
|
|
213
|
+
const record = store?.get(run.scheduleId);
|
|
214
|
+
if (!store || !record)
|
|
215
|
+
return;
|
|
216
|
+
const issuesCompleted = safeIssuesCompleted(run.executor);
|
|
217
|
+
const productive = !run.lastError && issuesCompleted > 0;
|
|
218
|
+
const consecutiveEmptyRuns = productive ? 0 : record.consecutiveEmptyRuns + 1;
|
|
219
|
+
const status = run.lastError ? 'failed' : 'completed';
|
|
220
|
+
const error = run.lastError ?? (issuesCompleted === 0 ? 'run produced no issues' : undefined);
|
|
221
|
+
const now = Date.now();
|
|
222
|
+
store.recordFire(run.scheduleId, { at: new Date(now).toISOString(), status, boardId: run.boardId, ...(error ? { error } : {}) }, this.nextFireAtAfterSettle(record, now, consecutiveEmptyRuns), consecutiveEmptyRuns);
|
|
223
|
+
if (record.timing.kind === 'once')
|
|
224
|
+
store.setEnabled(run.scheduleId, false);
|
|
225
|
+
this.broadcastSchedules();
|
|
226
|
+
}
|
|
227
|
+
recordFailedFire(record, firedAt, error) {
|
|
228
|
+
const store = this.store;
|
|
229
|
+
if (!store)
|
|
230
|
+
return;
|
|
231
|
+
const consecutiveEmptyRuns = record.consecutiveEmptyRuns + 1;
|
|
232
|
+
const now = parseEpoch(firedAt);
|
|
233
|
+
const entry = { at: firedAt, status: 'failed', boardId: null, error };
|
|
234
|
+
store.recordFire(record.id, entry, this.nextFireAtAfterFailure(record, now, consecutiveEmptyRuns), consecutiveEmptyRuns);
|
|
235
|
+
if (record.timing.kind === 'once')
|
|
236
|
+
store.setEnabled(record.id, false);
|
|
237
|
+
this.broadcastSchedules();
|
|
238
|
+
}
|
|
239
|
+
recordSkippedOverlap(record, now) {
|
|
240
|
+
const store = this.store;
|
|
241
|
+
if (!store)
|
|
242
|
+
return;
|
|
243
|
+
store.recordFire(record.id, { at: new Date(now).toISOString(), status: 'skipped-overlap', boardId: null, error: 'previous run for this schedule is still in flight' }, this.nextFireAtAfterStart(record, now));
|
|
244
|
+
this.broadcastSchedules();
|
|
245
|
+
}
|
|
246
|
+
nextFireAtAfterStart(record, now) {
|
|
247
|
+
if (record.timing.kind === 'interval')
|
|
248
|
+
return new Date(now + record.timing.everyMs).toISOString();
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
nextFireAtAfterFailure(record, now, consecutiveEmptyRuns) {
|
|
252
|
+
if (record.timing.kind === 'once')
|
|
253
|
+
return null;
|
|
254
|
+
if (record.timing.kind === 'continuous') {
|
|
255
|
+
return new Date(now + continuousDelayMs(consecutiveEmptyRuns)).toISOString();
|
|
256
|
+
}
|
|
257
|
+
return new Date(now + record.timing.everyMs).toISOString();
|
|
258
|
+
}
|
|
259
|
+
nextFireAtAfterSettle(record, now, consecutiveEmptyRuns) {
|
|
260
|
+
if (record.timing.kind === 'once')
|
|
261
|
+
return null;
|
|
262
|
+
if (record.timing.kind === 'continuous') {
|
|
263
|
+
return new Date(now + continuousDelayMs(consecutiveEmptyRuns)).toISOString();
|
|
264
|
+
}
|
|
265
|
+
const store = this.store;
|
|
266
|
+
return store?.get(record.id)?.nextFireAt ?? new Date(now + record.timing.everyMs).toISOString();
|
|
267
|
+
}
|
|
268
|
+
broadcastSchedules() {
|
|
269
|
+
if (!this.store)
|
|
270
|
+
return;
|
|
271
|
+
this.ctx.broadcastToAll({ type: 'planSchedulesChanged', data: { schedules: this.store.list() } });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function defaultCreateExecutor(workingDir) {
|
|
275
|
+
return new PlanExecutor(workingDir);
|
|
276
|
+
}
|
|
277
|
+
function parseEpoch(iso) {
|
|
278
|
+
return Date.parse(iso);
|
|
279
|
+
}
|
|
280
|
+
function errorMessage(error) {
|
|
281
|
+
if (typeof error === 'string')
|
|
282
|
+
return error;
|
|
283
|
+
return error instanceof Error ? error.message : String(error);
|
|
284
|
+
}
|
|
285
|
+
function safeIssuesCompleted(executor) {
|
|
286
|
+
try {
|
|
287
|
+
return executor.getMetrics().issuesCompleted;
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
return 0;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
export function getScheduler(workingDir, ctx, deps) {
|
|
294
|
+
let engine = schedulerCache.get(workingDir);
|
|
295
|
+
if (!engine) {
|
|
296
|
+
engine = new SchedulerEngine(workingDir, ctx, deps);
|
|
297
|
+
schedulerCache.set(workingDir, engine);
|
|
298
|
+
}
|
|
299
|
+
return engine;
|
|
300
|
+
}
|
|
301
|
+
export function stopAllSchedulers() {
|
|
302
|
+
for (const engine of schedulerCache.values()) {
|
|
303
|
+
try {
|
|
304
|
+
engine.stop();
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
schedulerCache.clear();
|
|
310
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { validatePathWithinWorkingDir } from '../pathUtils.js';
|
|
6
|
+
import { extractBoardArchive } from '../plan/board-archive.js';
|
|
7
|
+
import { parseFrontMatter } from '../plan/parser-core.js';
|
|
8
|
+
import { loadTemplate, validateTemplate } from '../plan/template-instantiator.js';
|
|
9
|
+
export const MAX_SOURCE_ZIP_BYTES = 50 * 1024 * 1024;
|
|
10
|
+
export class TemplateSourceError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
constructor(code, message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.code = code;
|
|
15
|
+
this.name = 'TemplateSourceError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function durableFileName(kind) {
|
|
19
|
+
return kind === 'template-json' ? 'template.json' : 'template.zip';
|
|
20
|
+
}
|
|
21
|
+
function resolveSourcePath(rawPath, workingDir) {
|
|
22
|
+
const validation = validatePathWithinWorkingDir(rawPath, workingDir);
|
|
23
|
+
if (!validation.valid) {
|
|
24
|
+
throw new TemplateSourceError('invalid_path', validation.error ?? 'Invalid source path');
|
|
25
|
+
}
|
|
26
|
+
if (!existsSync(validation.resolvedPath) || !statSync(validation.resolvedPath).isFile()) {
|
|
27
|
+
throw new TemplateSourceError('not_found', `Source file not found: ${rawPath}`);
|
|
28
|
+
}
|
|
29
|
+
return validation.resolvedPath;
|
|
30
|
+
}
|
|
31
|
+
function resolveTemplateJsonSource(resolvedPath) {
|
|
32
|
+
let template;
|
|
33
|
+
try {
|
|
34
|
+
template = loadTemplate(resolvedPath);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
throw new TemplateSourceError('invalid_template', err instanceof Error ? err.message : String(err));
|
|
38
|
+
}
|
|
39
|
+
const validation = validateTemplate(template);
|
|
40
|
+
if (!validation.valid) {
|
|
41
|
+
const summary = validation.errors.map(e => `${e.pointer ?? '<root>'}: ${e.message}`).join('; ');
|
|
42
|
+
throw new TemplateSourceError('invalid_template', `Template is invalid: ${summary}`);
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
boardTitle: template.board.title,
|
|
46
|
+
issueCount: template.issues.length,
|
|
47
|
+
variables: template.variables ?? [],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function resolveBoardZipSource(resolvedPath) {
|
|
51
|
+
if (statSync(resolvedPath).size > MAX_SOURCE_ZIP_BYTES) {
|
|
52
|
+
throw new TemplateSourceError('too_large', 'Board archive exceeds the 50 MB limit');
|
|
53
|
+
}
|
|
54
|
+
let files;
|
|
55
|
+
try {
|
|
56
|
+
({ files } = extractBoardArchive(readFileSync(resolvedPath)));
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
throw new TemplateSourceError('invalid_archive', err instanceof Error ? err.message : String(err));
|
|
60
|
+
}
|
|
61
|
+
const boardMd = files.get('board.md');
|
|
62
|
+
const { frontMatter } = parseFrontMatter(boardMd ? Buffer.from(boardMd).toString('utf-8') : '');
|
|
63
|
+
const boardTitle = typeof frontMatter.title === 'string' && frontMatter.title ? frontMatter.title : 'Imported board';
|
|
64
|
+
const issueCount = [...files.keys()].filter(p => p.startsWith('backlog/') && p.endsWith('.md')).length;
|
|
65
|
+
return { boardTitle, issueCount };
|
|
66
|
+
}
|
|
67
|
+
export function previewTemplateSource(options) {
|
|
68
|
+
const { workingDir, source } = options;
|
|
69
|
+
const resolvedPath = resolveSourcePath(source.path, workingDir);
|
|
70
|
+
if (source.kind === 'template-json') {
|
|
71
|
+
const { boardTitle, issueCount, variables } = resolveTemplateJsonSource(resolvedPath);
|
|
72
|
+
return { kind: 'template-json', boardTitle, issueCount, variables };
|
|
73
|
+
}
|
|
74
|
+
const { boardTitle, issueCount } = resolveBoardZipSource(resolvedPath);
|
|
75
|
+
return { kind: 'board-zip', boardTitle, issueCount, variables: [] };
|
|
76
|
+
}
|
|
77
|
+
export function resolveTemplateSource(options) {
|
|
78
|
+
const { workingDir, pmDir, scheduleId, source } = options;
|
|
79
|
+
const resolvedPath = resolveSourcePath(source.path, workingDir);
|
|
80
|
+
const durableDir = join(pmDir, 'schedules', scheduleId);
|
|
81
|
+
const durablePath = join(durableDir, durableFileName(source.kind));
|
|
82
|
+
const needsCopy = resolvedPath !== durablePath;
|
|
83
|
+
if (source.kind === 'template-json') {
|
|
84
|
+
const { boardTitle, issueCount, variables } = resolveTemplateJsonSource(resolvedPath);
|
|
85
|
+
if (needsCopy) {
|
|
86
|
+
mkdirSync(durableDir, { recursive: true });
|
|
87
|
+
writeFileSync(durablePath, readFileSync(resolvedPath, 'utf-8'), 'utf-8');
|
|
88
|
+
}
|
|
89
|
+
return { kind: 'template-json', durablePath, boardTitle, issueCount, variables };
|
|
90
|
+
}
|
|
91
|
+
const { boardTitle, issueCount } = resolveBoardZipSource(resolvedPath);
|
|
92
|
+
if (needsCopy) {
|
|
93
|
+
mkdirSync(durableDir, { recursive: true });
|
|
94
|
+
writeFileSync(durablePath, readFileSync(resolvedPath));
|
|
95
|
+
}
|
|
96
|
+
return { kind: 'board-zip', durablePath, boardTitle, issueCount, variables: [] };
|
|
97
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { isImageFile, readFileContent } from '../websocket/file-utils.js';
|
|
4
|
+
import { logAppAudit } from './audit.js';
|
|
5
|
+
import { resolveGuardWithRoot } from './files-transfer.js';
|
|
6
|
+
import { SdkMethodError } from './registry.js';
|
|
7
|
+
export const MAX_PROMPT_ATTACHMENTS = 10;
|
|
8
|
+
function resolveAttachments(args, refs) {
|
|
9
|
+
if (refs.length > MAX_PROMPT_ATTACHMENTS) {
|
|
10
|
+
throw new SdkMethodError('BAD_REQUEST', `agents.sessions.prompt: at most ${MAX_PROMPT_ATTACHMENTS} attachments per prompt`);
|
|
11
|
+
}
|
|
12
|
+
return refs.map((ref) => {
|
|
13
|
+
const { resolvedPath } = resolveGuardWithRoot(args, ref.path);
|
|
14
|
+
const result = readFileContent(resolvedPath, args.workingDir);
|
|
15
|
+
if (result.error) {
|
|
16
|
+
throw new SdkMethodError('BAD_REQUEST', `agents.sessions.prompt: attachment '${ref.path}': ${result.error}`);
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
fileName: result.fileName,
|
|
20
|
+
filePath: resolvedPath,
|
|
21
|
+
content: result.content,
|
|
22
|
+
isImage: Boolean(result.isImage) && isImageFile(resolvedPath),
|
|
23
|
+
mimeType: result.mimeType,
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
let sessionHost = null;
|
|
28
|
+
export function setSdkSessionHost(host) {
|
|
29
|
+
sessionHost = host;
|
|
30
|
+
}
|
|
31
|
+
export function resetSdkSessionHost() {
|
|
32
|
+
sessionHost = null;
|
|
33
|
+
}
|
|
34
|
+
function requireHost() {
|
|
35
|
+
if (!sessionHost) {
|
|
36
|
+
throw new SdkMethodError('INTERNAL', 'agents.sessions host is not wired — the WebSocket handler installs it at startup');
|
|
37
|
+
}
|
|
38
|
+
return sessionHost;
|
|
39
|
+
}
|
|
40
|
+
function paramsObject(params) {
|
|
41
|
+
return typeof params === 'object' && params !== null && !Array.isArray(params) ? params : {};
|
|
42
|
+
}
|
|
43
|
+
function parseSessionIdParams(params, method) {
|
|
44
|
+
const raw = paramsObject(params);
|
|
45
|
+
if (typeof raw.sessionId !== 'string' || raw.sessionId.trim() === '') {
|
|
46
|
+
throw new SdkMethodError('BAD_REQUEST', `${method} requires params { sessionId }`);
|
|
47
|
+
}
|
|
48
|
+
return raw.sessionId;
|
|
49
|
+
}
|
|
50
|
+
function parseCreateParams(params) {
|
|
51
|
+
if (params === undefined || params === null)
|
|
52
|
+
return {};
|
|
53
|
+
const raw = paramsObject(params);
|
|
54
|
+
if (raw.name !== undefined && typeof raw.name !== 'string') {
|
|
55
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.create name must be a string when present');
|
|
56
|
+
}
|
|
57
|
+
return { name: raw.name };
|
|
58
|
+
}
|
|
59
|
+
function parseRenameParams(params) {
|
|
60
|
+
const raw = paramsObject(params);
|
|
61
|
+
if (typeof raw.sessionId !== 'string' || raw.sessionId.trim() === '') {
|
|
62
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.rename requires params { sessionId, name }');
|
|
63
|
+
}
|
|
64
|
+
if (typeof raw.name !== 'string' || raw.name.trim() === '') {
|
|
65
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.rename requires a non-empty string name');
|
|
66
|
+
}
|
|
67
|
+
return { sessionId: raw.sessionId, name: raw.name };
|
|
68
|
+
}
|
|
69
|
+
function parseApproveParams(params) {
|
|
70
|
+
const raw = paramsObject(params);
|
|
71
|
+
if (typeof raw.sessionId !== 'string' || raw.sessionId.trim() === '') {
|
|
72
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.approve requires params { sessionId, approved }');
|
|
73
|
+
}
|
|
74
|
+
if (typeof raw.approved !== 'boolean') {
|
|
75
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.approve requires a boolean approved');
|
|
76
|
+
}
|
|
77
|
+
return { sessionId: raw.sessionId, approved: raw.approved };
|
|
78
|
+
}
|
|
79
|
+
function parseAnswerQuestionParams(params) {
|
|
80
|
+
const raw = paramsObject(params);
|
|
81
|
+
if (typeof raw.sessionId !== 'string' || raw.sessionId.trim() === '') {
|
|
82
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.answerQuestion requires params { sessionId, toolUseId, answers }');
|
|
83
|
+
}
|
|
84
|
+
if (typeof raw.toolUseId !== 'string' || raw.toolUseId.trim() === '') {
|
|
85
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.answerQuestion requires a non-empty toolUseId');
|
|
86
|
+
}
|
|
87
|
+
if (typeof raw.answers !== 'object' || raw.answers === null || Array.isArray(raw.answers)) {
|
|
88
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.answerQuestion requires an answers object');
|
|
89
|
+
}
|
|
90
|
+
const answers = {};
|
|
91
|
+
for (const [key, value] of Object.entries(raw.answers)) {
|
|
92
|
+
if (typeof value !== 'string') {
|
|
93
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.answerQuestion answers values must all be strings');
|
|
94
|
+
}
|
|
95
|
+
answers[key] = value;
|
|
96
|
+
}
|
|
97
|
+
return { sessionId: raw.sessionId, toolUseId: raw.toolUseId, answers };
|
|
98
|
+
}
|
|
99
|
+
function parseAttachmentRefs(raw) {
|
|
100
|
+
if (raw === undefined)
|
|
101
|
+
return undefined;
|
|
102
|
+
if (!Array.isArray(raw)) {
|
|
103
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.prompt attachments must be an array');
|
|
104
|
+
}
|
|
105
|
+
return raw.map((entry, index) => {
|
|
106
|
+
if (typeof entry !== 'object' || entry === null || typeof entry.path !== 'string' || entry.path === '') {
|
|
107
|
+
throw new SdkMethodError('BAD_REQUEST', `agents.sessions.prompt attachments[${index}] requires a non-empty string path`);
|
|
108
|
+
}
|
|
109
|
+
return { path: entry.path };
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function parsePromptParams(params) {
|
|
113
|
+
const raw = paramsObject(params);
|
|
114
|
+
if (typeof raw.sessionId !== 'string' || raw.sessionId.trim() === '') {
|
|
115
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.prompt requires params { sessionId, prompt }');
|
|
116
|
+
}
|
|
117
|
+
if (typeof raw.prompt !== 'string' || raw.prompt.trim() === '') {
|
|
118
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.prompt requires a non-empty prompt');
|
|
119
|
+
}
|
|
120
|
+
return { sessionId: raw.sessionId, prompt: raw.prompt, attachments: parseAttachmentRefs(raw.attachments) };
|
|
121
|
+
}
|
|
122
|
+
function parseReplayParams(params) {
|
|
123
|
+
const raw = paramsObject(params);
|
|
124
|
+
if (typeof raw.sessionId !== 'string' || raw.sessionId.trim() === '') {
|
|
125
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.replay requires params { sessionId, afterSeq }');
|
|
126
|
+
}
|
|
127
|
+
if (typeof raw.afterSeq !== 'number' || !Number.isInteger(raw.afterSeq) || raw.afterSeq < 0) {
|
|
128
|
+
throw new SdkMethodError('BAD_REQUEST', 'agents.sessions.replay afterSeq must be a non-negative integer');
|
|
129
|
+
}
|
|
130
|
+
return { sessionId: raw.sessionId, afterSeq: raw.afterSeq };
|
|
131
|
+
}
|
|
132
|
+
function sessionNotFound(sessionId) {
|
|
133
|
+
return new SdkMethodError('BAD_REQUEST', `unknown sessionId '${sessionId}' — no session in this Space matches it`);
|
|
134
|
+
}
|
|
135
|
+
export function agentsSessionsListHandler(args) {
|
|
136
|
+
return requireHost().list(args.workingDir);
|
|
137
|
+
}
|
|
138
|
+
export function agentsSessionsCreateHandler(args) {
|
|
139
|
+
const { name } = parseCreateParams(args.params);
|
|
140
|
+
const grantScopes = args.grant ? [...args.grant.scopes] : [];
|
|
141
|
+
const summary = requireHost().create({ workingDir: args.workingDir, appId: args.appId, origin: args.origin, name, grantScopes });
|
|
142
|
+
logAppAudit({
|
|
143
|
+
appId: args.appId,
|
|
144
|
+
origin: args.origin,
|
|
145
|
+
method: 'agents.sessions.create',
|
|
146
|
+
decision: 'allow',
|
|
147
|
+
requestId: args.requestId,
|
|
148
|
+
spaceKey: args.spaceKey,
|
|
149
|
+
reason: `session ${summary.id} created${name ? ` (${name})` : ''}`,
|
|
150
|
+
});
|
|
151
|
+
return summary;
|
|
152
|
+
}
|
|
153
|
+
export function agentsSessionsAttachHandler(args) {
|
|
154
|
+
const sessionId = parseSessionIdParams(args.params, 'agents.sessions.attach');
|
|
155
|
+
const summary = requireHost().attach({ workingDir: args.workingDir, sessionId });
|
|
156
|
+
if (!summary)
|
|
157
|
+
throw sessionNotFound(sessionId);
|
|
158
|
+
return summary;
|
|
159
|
+
}
|
|
160
|
+
export function agentsSessionsCloseHandler(args) {
|
|
161
|
+
const sessionId = parseSessionIdParams(args.params, 'agents.sessions.close');
|
|
162
|
+
const closed = requireHost().close({ workingDir: args.workingDir, sessionId });
|
|
163
|
+
if (!closed)
|
|
164
|
+
throw sessionNotFound(sessionId);
|
|
165
|
+
logAppAudit({
|
|
166
|
+
appId: args.appId,
|
|
167
|
+
origin: args.origin,
|
|
168
|
+
method: 'agents.sessions.close',
|
|
169
|
+
decision: 'allow',
|
|
170
|
+
requestId: args.requestId,
|
|
171
|
+
spaceKey: args.spaceKey,
|
|
172
|
+
reason: `session ${sessionId} closed`,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
export function agentsSessionsRenameHandler(args) {
|
|
176
|
+
const { sessionId, name } = parseRenameParams(args.params);
|
|
177
|
+
const summary = requireHost().rename({ workingDir: args.workingDir, sessionId, name });
|
|
178
|
+
if (!summary)
|
|
179
|
+
throw sessionNotFound(sessionId);
|
|
180
|
+
return summary;
|
|
181
|
+
}
|
|
182
|
+
export function agentsSessionsHistoryHandler(args) {
|
|
183
|
+
const sessionId = parseSessionIdParams(args.params, 'agents.sessions.history');
|
|
184
|
+
const result = requireHost().history({ workingDir: args.workingDir, sessionId });
|
|
185
|
+
if (!result)
|
|
186
|
+
throw sessionNotFound(sessionId);
|
|
187
|
+
return result;
|
|
188
|
+
}
|
|
189
|
+
export function agentsSessionsReplayHandler(args) {
|
|
190
|
+
const { sessionId, afterSeq } = parseReplayParams(args.params);
|
|
191
|
+
const outcome = requireHost().replay({ workingDir: args.workingDir, sessionId, afterSeq });
|
|
192
|
+
if (outcome.kind === 'not_found')
|
|
193
|
+
throw sessionNotFound(sessionId);
|
|
194
|
+
if (outcome.kind === 'gap') {
|
|
195
|
+
throw new SdkMethodError('STREAM_GAP', `session '${sessionId}' cannot be replayed from seq ${afterSeq}: events (${afterSeq + 1}..${outcome.evictedThroughSeq}) ` +
|
|
196
|
+
'have been evicted from the buffered window. Reconcile with agents.sessions.history.');
|
|
197
|
+
}
|
|
198
|
+
return outcome.result;
|
|
199
|
+
}
|
|
200
|
+
export function agentsSessionsApproveHandler(args) {
|
|
201
|
+
const { sessionId, approved } = parseApproveParams(args.params);
|
|
202
|
+
const ok = requireHost().approve({ workingDir: args.workingDir, sessionId, approved });
|
|
203
|
+
if (!ok)
|
|
204
|
+
throw sessionNotFound(sessionId);
|
|
205
|
+
logAppAudit({
|
|
206
|
+
appId: args.appId,
|
|
207
|
+
origin: args.origin,
|
|
208
|
+
method: 'agents.sessions.approve',
|
|
209
|
+
decision: 'allow',
|
|
210
|
+
requestId: args.requestId,
|
|
211
|
+
spaceKey: args.spaceKey,
|
|
212
|
+
reason: `session ${sessionId} ${approved ? 'approved' : 'rejected'} a pending tool-approval request`,
|
|
213
|
+
});
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
export function agentsSessionsAnswerQuestionHandler(args) {
|
|
217
|
+
const { sessionId, toolUseId, answers } = parseAnswerQuestionParams(args.params);
|
|
218
|
+
const ok = requireHost().answerQuestion({ workingDir: args.workingDir, sessionId, toolUseId, answers });
|
|
219
|
+
if (!ok)
|
|
220
|
+
throw sessionNotFound(sessionId);
|
|
221
|
+
logAppAudit({
|
|
222
|
+
appId: args.appId,
|
|
223
|
+
origin: args.origin,
|
|
224
|
+
method: 'agents.sessions.answerQuestion',
|
|
225
|
+
decision: 'allow',
|
|
226
|
+
requestId: args.requestId,
|
|
227
|
+
spaceKey: args.spaceKey,
|
|
228
|
+
reason: `session ${sessionId} answered question ${toolUseId}`,
|
|
229
|
+
});
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
export function agentsSessionsPromptHandler(args) {
|
|
233
|
+
const { sessionId, prompt, attachments: attachmentRefs } = parsePromptParams(args.params);
|
|
234
|
+
const attachments = attachmentRefs ? resolveAttachments(args, attachmentRefs) : undefined;
|
|
235
|
+
const result = requireHost().prompt({ workingDir: args.workingDir, sessionId, prompt, attachments });
|
|
236
|
+
if (!result)
|
|
237
|
+
throw sessionNotFound(sessionId);
|
|
238
|
+
logAppAudit({
|
|
239
|
+
appId: args.appId,
|
|
240
|
+
origin: args.origin,
|
|
241
|
+
method: 'agents.sessions.prompt',
|
|
242
|
+
decision: 'allow',
|
|
243
|
+
requestId: args.requestId,
|
|
244
|
+
spaceKey: args.spaceKey,
|
|
245
|
+
reason: `session ${sessionId} ${result.queued ? 'queued' : 'started'} a prompt`,
|
|
246
|
+
});
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
export function agentsSessionsStopHandler(args) {
|
|
250
|
+
const sessionId = parseSessionIdParams(args.params, 'agents.sessions.stop');
|
|
251
|
+
const ok = requireHost().stop({ workingDir: args.workingDir, sessionId });
|
|
252
|
+
if (!ok)
|
|
253
|
+
throw sessionNotFound(sessionId);
|
|
254
|
+
logAppAudit({
|
|
255
|
+
appId: args.appId,
|
|
256
|
+
origin: args.origin,
|
|
257
|
+
method: 'agents.sessions.stop',
|
|
258
|
+
decision: 'allow',
|
|
259
|
+
requestId: args.requestId,
|
|
260
|
+
spaceKey: args.spaceKey,
|
|
261
|
+
reason: `session ${sessionId} execution stopped`,
|
|
262
|
+
});
|
|
263
|
+
return null;
|
|
264
|
+
}
|