@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,318 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
4
|
+
import { isScope } from '@minionry/app-manifest';
|
|
5
|
+
import { ensureMachineDir, machineFile, machineLockPath } from '../../../bin/machine-layout.js';
|
|
6
|
+
import { withFileLock, writeFileAtomic } from '../../utils/file-store.js';
|
|
7
|
+
import { isLocalhostFamilyOrigin } from './local-app-bindings.js';
|
|
8
|
+
import { isValidAppId } from './sandbox.js';
|
|
9
|
+
const GRANTS_VERSION = 1;
|
|
10
|
+
function grantsFilePath() {
|
|
11
|
+
return machineFile('appGrants');
|
|
12
|
+
}
|
|
13
|
+
function ensureMinionryDir() {
|
|
14
|
+
ensureMachineDir('state');
|
|
15
|
+
}
|
|
16
|
+
function emptyGrantsFile() {
|
|
17
|
+
return { version: GRANTS_VERSION, grants: {} };
|
|
18
|
+
}
|
|
19
|
+
function sanitizeGrant(value) {
|
|
20
|
+
if (typeof value !== 'object' || value === null)
|
|
21
|
+
return null;
|
|
22
|
+
const raw = value;
|
|
23
|
+
if (typeof raw.appId !== 'string' ||
|
|
24
|
+
!isValidAppId(raw.appId) ||
|
|
25
|
+
typeof raw.spaceKey !== 'string' ||
|
|
26
|
+
raw.spaceKey === '' ||
|
|
27
|
+
typeof raw.origin !== 'string' ||
|
|
28
|
+
raw.origin === '' ||
|
|
29
|
+
typeof raw.manifestHash !== 'string' ||
|
|
30
|
+
raw.manifestHash === '' ||
|
|
31
|
+
typeof raw.createdAt !== 'string' ||
|
|
32
|
+
typeof raw.lastUsedAt !== 'string' ||
|
|
33
|
+
!Array.isArray(raw.scopes)) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const grant = {
|
|
37
|
+
appId: raw.appId,
|
|
38
|
+
spaceKey: raw.spaceKey,
|
|
39
|
+
origin: raw.origin,
|
|
40
|
+
scopes: raw.scopes.filter(isScope),
|
|
41
|
+
manifestHash: raw.manifestHash,
|
|
42
|
+
createdAt: raw.createdAt,
|
|
43
|
+
lastUsedAt: raw.lastUsedAt,
|
|
44
|
+
};
|
|
45
|
+
if (typeof raw.config === 'object' && raw.config !== null && !Array.isArray(raw.config)) {
|
|
46
|
+
grant.config = raw.config;
|
|
47
|
+
}
|
|
48
|
+
const usage = sanitizeUsage(raw.usage);
|
|
49
|
+
if (usage)
|
|
50
|
+
grant.usage = usage;
|
|
51
|
+
if (raw.verifiedLocalBinding === true)
|
|
52
|
+
grant.verifiedLocalBinding = true;
|
|
53
|
+
return grant;
|
|
54
|
+
}
|
|
55
|
+
function sanitizeUsage(value) {
|
|
56
|
+
if (typeof value !== 'object' || value === null)
|
|
57
|
+
return null;
|
|
58
|
+
const raw = value;
|
|
59
|
+
if (typeof raw.day !== 'string' ||
|
|
60
|
+
!/^\d{4}-\d{2}-\d{2}$/.test(raw.day) ||
|
|
61
|
+
typeof raw.runs !== 'number' ||
|
|
62
|
+
!Number.isFinite(raw.runs) ||
|
|
63
|
+
raw.runs < 0 ||
|
|
64
|
+
typeof raw.tokens !== 'number' ||
|
|
65
|
+
!Number.isFinite(raw.tokens) ||
|
|
66
|
+
raw.tokens < 0) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return { day: raw.day, runs: raw.runs, tokens: raw.tokens };
|
|
70
|
+
}
|
|
71
|
+
function mergeSpaceEntries(file, spaceKey, apps) {
|
|
72
|
+
if (typeof apps !== 'object' || apps === null)
|
|
73
|
+
return;
|
|
74
|
+
for (const [appId, value] of Object.entries(apps)) {
|
|
75
|
+
const grant = sanitizeGrant(value);
|
|
76
|
+
if (grant && grant.appId === appId && grant.spaceKey === spaceKey) {
|
|
77
|
+
(file.grants[spaceKey] ??= {})[appId] = grant;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function readGrantsFile() {
|
|
82
|
+
const path = grantsFilePath();
|
|
83
|
+
if (!existsSync(path))
|
|
84
|
+
return emptyGrantsFile();
|
|
85
|
+
try {
|
|
86
|
+
const stored = JSON.parse(readFileSync(path, 'utf-8'));
|
|
87
|
+
const file = emptyGrantsFile();
|
|
88
|
+
if (typeof stored !== 'object' || stored === null)
|
|
89
|
+
return file;
|
|
90
|
+
const rawGrants = stored.grants;
|
|
91
|
+
if (typeof rawGrants !== 'object' || rawGrants === null)
|
|
92
|
+
return file;
|
|
93
|
+
for (const [spaceKey, apps] of Object.entries(rawGrants)) {
|
|
94
|
+
mergeSpaceEntries(file, spaceKey, apps);
|
|
95
|
+
}
|
|
96
|
+
return file;
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
console.warn('[GrantStore] Failed to read app-grants.json, treating as empty (apps will need re-consent):', err);
|
|
100
|
+
return emptyGrantsFile();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function grantsLockPath() {
|
|
104
|
+
return machineLockPath('app-grants');
|
|
105
|
+
}
|
|
106
|
+
function withGrantsLock(fn) {
|
|
107
|
+
return withFileLock(grantsLockPath(), fn);
|
|
108
|
+
}
|
|
109
|
+
function writeGrantsFile(file) {
|
|
110
|
+
ensureMinionryDir();
|
|
111
|
+
writeFileAtomic(grantsFilePath(), JSON.stringify(file, null, 2), { mode: 0o600 });
|
|
112
|
+
}
|
|
113
|
+
function assertGrantInput(input, persisted) {
|
|
114
|
+
if (!isValidAppId(input.appId)) {
|
|
115
|
+
throw new Error(`Invalid appId '${input.appId}' — expected the D5 grammar (lowercase [a-z0-9-])`);
|
|
116
|
+
}
|
|
117
|
+
if (typeof input.spaceKey !== 'string' || input.spaceKey === '') {
|
|
118
|
+
throw new Error('spaceKey must be a non-empty string (build it with makeSpaceKey from settings.ts)');
|
|
119
|
+
}
|
|
120
|
+
if (typeof input.origin !== 'string' || input.origin === '') {
|
|
121
|
+
throw new Error('origin must be a non-empty string');
|
|
122
|
+
}
|
|
123
|
+
if (typeof input.manifestHash !== 'string' || input.manifestHash === '') {
|
|
124
|
+
throw new Error('manifestHash must be a non-empty string');
|
|
125
|
+
}
|
|
126
|
+
if (!Array.isArray(input.scopes) || !input.scopes.every((scope) => isScope(scope))) {
|
|
127
|
+
throw new Error('scopes must contain only known v1 scopes (fail closed, invariant 5)');
|
|
128
|
+
}
|
|
129
|
+
if (persisted && isLocalhostFamilyOrigin(input.origin) && input.verifiedLocalBinding !== true) {
|
|
130
|
+
throw new Error(`Refusing to persist a grant keyed on localhost-family origin '${input.origin}' without a ` +
|
|
131
|
+
'CLI-verified port↔appId binding (Epic 8) — dev ports are reassigned across sessions, ' +
|
|
132
|
+
'so a persisted localhost grant could be inherited by a different app. ' +
|
|
133
|
+
'Keep this consent session-scoped instead.');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function buildGrant(input, createdAt) {
|
|
137
|
+
const grant = {
|
|
138
|
+
appId: input.appId,
|
|
139
|
+
spaceKey: input.spaceKey,
|
|
140
|
+
origin: input.origin,
|
|
141
|
+
scopes: [...input.scopes],
|
|
142
|
+
manifestHash: input.manifestHash,
|
|
143
|
+
createdAt,
|
|
144
|
+
lastUsedAt: new Date().toISOString(),
|
|
145
|
+
};
|
|
146
|
+
if (input.config !== undefined)
|
|
147
|
+
grant.config = { ...input.config };
|
|
148
|
+
if (input.verifiedLocalBinding === true)
|
|
149
|
+
grant.verifiedLocalBinding = true;
|
|
150
|
+
return grant;
|
|
151
|
+
}
|
|
152
|
+
export function getGrant(appId, spaceKey) {
|
|
153
|
+
return readGrantsFile().grants[spaceKey]?.[appId];
|
|
154
|
+
}
|
|
155
|
+
export function listGrants(spaceKey) {
|
|
156
|
+
return Object.values(readGrantsFile().grants[spaceKey] ?? {});
|
|
157
|
+
}
|
|
158
|
+
export function sdkGrantStateSnapshot(spaceKey) {
|
|
159
|
+
return {
|
|
160
|
+
grants: listGrants(spaceKey).map((grant) => ({
|
|
161
|
+
appId: grant.appId,
|
|
162
|
+
origin: grant.origin,
|
|
163
|
+
scopes: [...grant.scopes],
|
|
164
|
+
})),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
let persistedGrantsListener = null;
|
|
168
|
+
export function setPersistedGrantsListener(listener) {
|
|
169
|
+
persistedGrantsListener = listener;
|
|
170
|
+
}
|
|
171
|
+
function notifyPersistedGrantsChanged(spaceKey) {
|
|
172
|
+
try {
|
|
173
|
+
persistedGrantsListener?.(spaceKey);
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
console.warn('[GrantStore] persisted-grants listener failed:', err);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
export function setGrant(input) {
|
|
180
|
+
assertGrantInput(input, true);
|
|
181
|
+
const grant = withGrantsLock(() => {
|
|
182
|
+
const file = readGrantsFile();
|
|
183
|
+
const existing = file.grants[input.spaceKey]?.[input.appId];
|
|
184
|
+
const next = buildGrant(input, existing?.createdAt ?? new Date().toISOString());
|
|
185
|
+
if (existing?.usage)
|
|
186
|
+
next.usage = existing.usage;
|
|
187
|
+
(file.grants[input.spaceKey] ??= {})[input.appId] = next;
|
|
188
|
+
writeGrantsFile(file);
|
|
189
|
+
return next;
|
|
190
|
+
});
|
|
191
|
+
notifyPersistedGrantsChanged(input.spaceKey);
|
|
192
|
+
return grant;
|
|
193
|
+
}
|
|
194
|
+
export function updateGrant(appId, spaceKey, update) {
|
|
195
|
+
const merged = withGrantsLock(() => {
|
|
196
|
+
const file = readGrantsFile();
|
|
197
|
+
const existing = file.grants[spaceKey]?.[appId];
|
|
198
|
+
if (!existing) {
|
|
199
|
+
throw new Error(`No persisted grant for app '${appId}' in Space '${spaceKey}'`);
|
|
200
|
+
}
|
|
201
|
+
const next = { ...existing, ...update };
|
|
202
|
+
assertGrantInput(next, true);
|
|
203
|
+
file.grants[spaceKey][appId] = next;
|
|
204
|
+
writeGrantsFile(file);
|
|
205
|
+
return next;
|
|
206
|
+
});
|
|
207
|
+
notifyPersistedGrantsChanged(spaceKey);
|
|
208
|
+
return merged;
|
|
209
|
+
}
|
|
210
|
+
export function removeGrant(appId, spaceKey) {
|
|
211
|
+
const removed = withGrantsLock(() => {
|
|
212
|
+
const file = readGrantsFile();
|
|
213
|
+
const space = file.grants[spaceKey];
|
|
214
|
+
if (!space || !(appId in space))
|
|
215
|
+
return false;
|
|
216
|
+
delete space[appId];
|
|
217
|
+
if (Object.keys(space).length === 0)
|
|
218
|
+
delete file.grants[spaceKey];
|
|
219
|
+
writeGrantsFile(file);
|
|
220
|
+
return true;
|
|
221
|
+
});
|
|
222
|
+
if (removed)
|
|
223
|
+
notifyPersistedGrantsChanged(spaceKey);
|
|
224
|
+
return removed;
|
|
225
|
+
}
|
|
226
|
+
export function touchLastUsed(appId, spaceKey) {
|
|
227
|
+
withGrantsLock(() => {
|
|
228
|
+
const file = readGrantsFile();
|
|
229
|
+
const grant = file.grants[spaceKey]?.[appId];
|
|
230
|
+
if (!grant)
|
|
231
|
+
return;
|
|
232
|
+
grant.lastUsedAt = new Date().toISOString();
|
|
233
|
+
writeGrantsFile(file);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
export function addGrantUsage(appId, spaceKey, day, delta) {
|
|
237
|
+
return withGrantsLock(() => {
|
|
238
|
+
const file = readGrantsFile();
|
|
239
|
+
const grant = file.grants[spaceKey]?.[appId];
|
|
240
|
+
if (!grant)
|
|
241
|
+
return undefined;
|
|
242
|
+
const prior = grant.usage?.day === day ? grant.usage : { day, runs: 0, tokens: 0 };
|
|
243
|
+
grant.usage = {
|
|
244
|
+
day,
|
|
245
|
+
runs: prior.runs + (delta.runs ?? 0),
|
|
246
|
+
tokens: prior.tokens + (delta.tokens ?? 0),
|
|
247
|
+
};
|
|
248
|
+
writeGrantsFile(file);
|
|
249
|
+
return { ...grant.usage };
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
export function computeScopeDelta(requested, granted) {
|
|
253
|
+
const have = new Set(granted);
|
|
254
|
+
const missing = [];
|
|
255
|
+
for (const scope of requested) {
|
|
256
|
+
if (!have.has(scope) && !missing.includes(scope))
|
|
257
|
+
missing.push(scope);
|
|
258
|
+
}
|
|
259
|
+
return missing;
|
|
260
|
+
}
|
|
261
|
+
const sessionGrants = new Map();
|
|
262
|
+
function sessionEntryKey(appId, spaceKey) {
|
|
263
|
+
return `${appId}\u0000${spaceKey}`;
|
|
264
|
+
}
|
|
265
|
+
export function setSessionGrant(viewerId, input) {
|
|
266
|
+
if (typeof viewerId !== 'string' || viewerId === '') {
|
|
267
|
+
throw new Error('viewerId must be a non-empty string for session-scoped grants');
|
|
268
|
+
}
|
|
269
|
+
assertGrantInput(input, false);
|
|
270
|
+
const entryKey = sessionEntryKey(input.appId, input.spaceKey);
|
|
271
|
+
let viewerGrants = sessionGrants.get(viewerId);
|
|
272
|
+
if (!viewerGrants) {
|
|
273
|
+
viewerGrants = new Map();
|
|
274
|
+
sessionGrants.set(viewerId, viewerGrants);
|
|
275
|
+
}
|
|
276
|
+
const existing = viewerGrants.get(entryKey);
|
|
277
|
+
const grant = buildGrant(input, existing?.createdAt ?? new Date().toISOString());
|
|
278
|
+
viewerGrants.set(entryKey, grant);
|
|
279
|
+
return grant;
|
|
280
|
+
}
|
|
281
|
+
export function getSessionGrant(viewerId, appId, spaceKey) {
|
|
282
|
+
return sessionGrants.get(viewerId)?.get(sessionEntryKey(appId, spaceKey));
|
|
283
|
+
}
|
|
284
|
+
export function listSessionGrants(viewerId, spaceKey) {
|
|
285
|
+
const viewerGrants = sessionGrants.get(viewerId);
|
|
286
|
+
if (!viewerGrants)
|
|
287
|
+
return [];
|
|
288
|
+
return [...viewerGrants.values()].filter((grant) => grant.spaceKey === spaceKey);
|
|
289
|
+
}
|
|
290
|
+
export function removeSessionGrant(viewerId, appId, spaceKey) {
|
|
291
|
+
const viewerGrants = sessionGrants.get(viewerId);
|
|
292
|
+
if (!viewerGrants)
|
|
293
|
+
return false;
|
|
294
|
+
const removed = viewerGrants.delete(sessionEntryKey(appId, spaceKey));
|
|
295
|
+
if (viewerGrants.size === 0)
|
|
296
|
+
sessionGrants.delete(viewerId);
|
|
297
|
+
return removed;
|
|
298
|
+
}
|
|
299
|
+
export function removeSessionGrantsForApp(appId, spaceKey) {
|
|
300
|
+
const entryKey = sessionEntryKey(appId, spaceKey);
|
|
301
|
+
let removed = 0;
|
|
302
|
+
for (const [viewerId, viewerGrants] of sessionGrants) {
|
|
303
|
+
if (viewerGrants.delete(entryKey)) {
|
|
304
|
+
removed += 1;
|
|
305
|
+
if (viewerGrants.size === 0)
|
|
306
|
+
sessionGrants.delete(viewerId);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return removed;
|
|
310
|
+
}
|
|
311
|
+
export function clearSessionGrants(viewerId) {
|
|
312
|
+
const viewerGrants = sessionGrants.get(viewerId);
|
|
313
|
+
sessionGrants.delete(viewerId);
|
|
314
|
+
return viewerGrants?.size ?? 0;
|
|
315
|
+
}
|
|
316
|
+
export function clearAllSessionGrants() {
|
|
317
|
+
sessionGrants.clear();
|
|
318
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { can } from '@minionry/roles';
|
|
4
|
+
import { readAppAudit } from './audit.js';
|
|
5
|
+
import { listGrants, listSessionGrants } from './grant-store.js';
|
|
6
|
+
import { SdkMethodError } from './registry.js';
|
|
7
|
+
import { isValidAppId } from './sandbox.js';
|
|
8
|
+
export const SDK_HOST_APP_ID = 'minionry-host';
|
|
9
|
+
export const AUDIT_RECENT_DEFAULT_LIMIT = 50;
|
|
10
|
+
export const AUDIT_RECENT_MAX_LIMIT = 200;
|
|
11
|
+
function assertHostOriginated(args) {
|
|
12
|
+
if (args.appId !== SDK_HOST_APP_ID) {
|
|
13
|
+
throw new SdkMethodError('SCOPE_DENIED', `'${args.method}' is a host-originated management read — apps cannot call it`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function canReadSpaceGrantState(args) {
|
|
17
|
+
return can(args.role, 'execute');
|
|
18
|
+
}
|
|
19
|
+
function toGrantListEntry(grant, kind) {
|
|
20
|
+
return {
|
|
21
|
+
appId: grant.appId,
|
|
22
|
+
origin: grant.origin,
|
|
23
|
+
scopes: [...grant.scopes],
|
|
24
|
+
createdAt: grant.createdAt,
|
|
25
|
+
lastUsedAt: grant.lastUsedAt,
|
|
26
|
+
kind,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function listGrantsHandler(args) {
|
|
30
|
+
assertHostOriginated(args);
|
|
31
|
+
const rows = [];
|
|
32
|
+
if (canReadSpaceGrantState(args)) {
|
|
33
|
+
for (const grant of listGrants(args.spaceKey)) {
|
|
34
|
+
rows.push(toGrantListEntry(grant, 'persisted'));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (args.viewerId) {
|
|
38
|
+
for (const grant of listSessionGrants(args.viewerId, args.spaceKey)) {
|
|
39
|
+
rows.push(toGrantListEntry(grant, 'session'));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
rows.sort((a, b) => (a.lastUsedAt < b.lastUsedAt ? 1 : a.lastUsedAt > b.lastUsedAt ? -1 : 0));
|
|
43
|
+
return { grants: rows };
|
|
44
|
+
}
|
|
45
|
+
function parseAuditParams(params) {
|
|
46
|
+
if (params === undefined || params === null)
|
|
47
|
+
return { limit: AUDIT_RECENT_DEFAULT_LIMIT };
|
|
48
|
+
if (typeof params !== 'object' || Array.isArray(params)) {
|
|
49
|
+
throw new SdkMethodError('BAD_REQUEST', 'audit.recent params must be an object');
|
|
50
|
+
}
|
|
51
|
+
const raw = params;
|
|
52
|
+
let appId;
|
|
53
|
+
if (raw.appId !== undefined) {
|
|
54
|
+
if (typeof raw.appId !== 'string' || !isValidAppId(raw.appId)) {
|
|
55
|
+
throw new SdkMethodError('BAD_REQUEST', 'audit.recent params.appId must be a valid app id');
|
|
56
|
+
}
|
|
57
|
+
appId = raw.appId;
|
|
58
|
+
}
|
|
59
|
+
let limit = AUDIT_RECENT_DEFAULT_LIMIT;
|
|
60
|
+
if (raw.limit !== undefined) {
|
|
61
|
+
if (typeof raw.limit !== 'number' || !Number.isInteger(raw.limit) || raw.limit < 1) {
|
|
62
|
+
throw new SdkMethodError('BAD_REQUEST', 'audit.recent params.limit must be a positive integer');
|
|
63
|
+
}
|
|
64
|
+
limit = Math.min(raw.limit, AUDIT_RECENT_MAX_LIMIT);
|
|
65
|
+
}
|
|
66
|
+
return { appId, limit };
|
|
67
|
+
}
|
|
68
|
+
export function auditRecentHandler(args) {
|
|
69
|
+
assertHostOriginated(args);
|
|
70
|
+
if (!canReadSpaceGrantState(args)) {
|
|
71
|
+
throw new SdkMethodError('SCOPE_DENIED', `role '${args.role}' cannot read the Space activity feed`);
|
|
72
|
+
}
|
|
73
|
+
const { appId, limit } = parseAuditParams(args.params);
|
|
74
|
+
const entries = [];
|
|
75
|
+
for (const entry of readAppAudit()) {
|
|
76
|
+
if (entry.spaceKey !== args.spaceKey)
|
|
77
|
+
continue;
|
|
78
|
+
if (appId !== undefined && entry.appId !== appId)
|
|
79
|
+
continue;
|
|
80
|
+
const { spaceKey: _spaceKey, ...row } = entry;
|
|
81
|
+
entries.push(row);
|
|
82
|
+
}
|
|
83
|
+
return { entries: entries.slice(-limit).reverse() };
|
|
84
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { mkdirSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { buildSpawnEnv, resolveClaudeEffort } from '../../cli/headless/claude-invoker-process.js';
|
|
8
|
+
import { classifyEngineNotice, isSyntheticModel } from '../../cli/headless/engine-notice.js';
|
|
9
|
+
import { resolveClaudeCommand } from '../../engines/claude/claude-command.js';
|
|
10
|
+
import { resolveModelProfile } from '../../engines/credentials/model-profiles.js';
|
|
11
|
+
import { SdkInferenceError, } from './inference.js';
|
|
12
|
+
const DEFAULT_SYSTEM_PROMPT = 'You are a helpful assistant.';
|
|
13
|
+
const KILL_GRACE_MS = 5_000;
|
|
14
|
+
const STDERR_TAIL_BYTES = 4_000;
|
|
15
|
+
function neutralCwd() {
|
|
16
|
+
const dir = join(tmpdir(), 'minionry-sdk-inference');
|
|
17
|
+
try {
|
|
18
|
+
mkdirSync(dir, { recursive: true });
|
|
19
|
+
return dir;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return tmpdir();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function renderInferencePrompt(messages) {
|
|
26
|
+
if (messages.length === 1)
|
|
27
|
+
return messages[0]?.content ?? '';
|
|
28
|
+
const turns = messages.map((message) => `${message.role === 'user' ? 'User' : 'Assistant'}: ${message.content}`);
|
|
29
|
+
return `The conversation so far:\n\n${turns.join('\n\n')}`;
|
|
30
|
+
}
|
|
31
|
+
export function buildClaudeInferenceArgs(exec) {
|
|
32
|
+
const args = ['--print', '--output-format', 'stream-json', '--verbose', '--include-partial-messages'];
|
|
33
|
+
const model = resolveModelProfile(exec.model)?.profile.model ?? exec.model;
|
|
34
|
+
if (model && model !== 'default')
|
|
35
|
+
args.push('--model', model);
|
|
36
|
+
const effort = resolveClaudeEffort(exec.model, exec.effortLevel ?? 'auto', true);
|
|
37
|
+
if (effort)
|
|
38
|
+
args.push('--effort', effort);
|
|
39
|
+
args.push('--tools', '', '--strict-mcp-config', '--no-session-persistence', '--system-prompt', exec.system?.trim() ? exec.system : DEFAULT_SYSTEM_PROMPT);
|
|
40
|
+
return args;
|
|
41
|
+
}
|
|
42
|
+
function parseStreamLine(line) {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(line);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function forwardTextDelta(state, parsed, onDelta) {
|
|
51
|
+
const delta = parsed.event?.type === 'content_block_delta' ? parsed.event.delta : undefined;
|
|
52
|
+
if (delta?.type !== 'text_delta' || !delta.text)
|
|
53
|
+
return;
|
|
54
|
+
state.deltas += delta.text;
|
|
55
|
+
onDelta(delta.text);
|
|
56
|
+
}
|
|
57
|
+
function captureNotice(state, parsed) {
|
|
58
|
+
if (!isSyntheticModel(parsed.message?.model))
|
|
59
|
+
return;
|
|
60
|
+
const text = (parsed.message?.content ?? []).map((block) => block.text ?? '').join('');
|
|
61
|
+
if (text)
|
|
62
|
+
state.noticeText ??= text;
|
|
63
|
+
}
|
|
64
|
+
export function applyClaudeStreamLine(state, line, onDelta) {
|
|
65
|
+
const parsed = parseStreamLine(line);
|
|
66
|
+
if (!parsed || parsed.parent_tool_use_id)
|
|
67
|
+
return;
|
|
68
|
+
switch (parsed.type) {
|
|
69
|
+
case 'system':
|
|
70
|
+
if (parsed.subtype === 'init' && typeof parsed.model === 'string')
|
|
71
|
+
state.resolvedModel = parsed.model;
|
|
72
|
+
return;
|
|
73
|
+
case 'stream_event':
|
|
74
|
+
forwardTextDelta(state, parsed, onDelta);
|
|
75
|
+
return;
|
|
76
|
+
case 'assistant':
|
|
77
|
+
captureNotice(state, parsed);
|
|
78
|
+
return;
|
|
79
|
+
case 'result':
|
|
80
|
+
state.result = parsed;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function classifyFailure(text, source) {
|
|
85
|
+
const notice = classifyEngineNotice(text, source);
|
|
86
|
+
const message = (notice?.text ?? text).trim() || 'Claude Code failed without a message';
|
|
87
|
+
if (notice?.kind === 'limit')
|
|
88
|
+
return new SdkInferenceError('ENGINE_LIMIT', message);
|
|
89
|
+
if (notice?.kind === 'auth')
|
|
90
|
+
return new SdkInferenceError('ENGINE_AUTH', message);
|
|
91
|
+
return new SdkInferenceError('UPSTREAM_ERROR', message);
|
|
92
|
+
}
|
|
93
|
+
function resultErrorText(result) {
|
|
94
|
+
const errors = (result.errors ?? []).filter((entry) => typeof entry === 'string' && entry !== '');
|
|
95
|
+
if (errors.length > 0)
|
|
96
|
+
return errors.join('; ');
|
|
97
|
+
return typeof result.result === 'string' ? result.result : '';
|
|
98
|
+
}
|
|
99
|
+
function usageOf(result) {
|
|
100
|
+
const usage = result.usage;
|
|
101
|
+
if (!usage)
|
|
102
|
+
return undefined;
|
|
103
|
+
return {
|
|
104
|
+
inputTokens: (usage.input_tokens ?? 0) + (usage.cache_creation_input_tokens ?? 0) + (usage.cache_read_input_tokens ?? 0),
|
|
105
|
+
outputTokens: usage.output_tokens ?? 0,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function successOutcome(state, result) {
|
|
109
|
+
const usage = usageOf(result);
|
|
110
|
+
return {
|
|
111
|
+
text: typeof result.result === 'string' && result.result !== '' ? result.result : state.deltas,
|
|
112
|
+
...(state.resolvedModel ? { model: state.resolvedModel } : {}),
|
|
113
|
+
...(usage ? { usage } : {}),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
export function finishClaudeInference(state, exitCode, stderr) {
|
|
117
|
+
const result = state.result;
|
|
118
|
+
if (result && !result.is_error)
|
|
119
|
+
return successOutcome(state, result);
|
|
120
|
+
if (state.noticeText)
|
|
121
|
+
throw classifyFailure(state.noticeText, 'stream');
|
|
122
|
+
if (result)
|
|
123
|
+
throw classifyFailure(resultErrorText(result), 'result');
|
|
124
|
+
throw classifyFailure(stderr || `Claude Code exited with code ${exitCode ?? 'unknown'} before producing a result`, 'stderr');
|
|
125
|
+
}
|
|
126
|
+
function killGroup(child, signal) {
|
|
127
|
+
if (child.pid === undefined || child.exitCode !== null || child.signalCode !== null)
|
|
128
|
+
return;
|
|
129
|
+
try {
|
|
130
|
+
process.kill(-child.pid, signal);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
try {
|
|
134
|
+
child.kill(signal);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export function runClaudeInference(exec, spawnImpl = spawn) {
|
|
141
|
+
return new Promise((resolve, reject) => {
|
|
142
|
+
const command = resolveClaudeCommand();
|
|
143
|
+
let child;
|
|
144
|
+
try {
|
|
145
|
+
child = spawnImpl(command, buildClaudeInferenceArgs(exec), {
|
|
146
|
+
cwd: neutralCwd(),
|
|
147
|
+
env: buildSpawnEnv({ model: exec.model }),
|
|
148
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
149
|
+
detached: true,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
reject(new SdkInferenceError('ENGINE_UNAVAILABLE', `could not start Claude Code: ${error instanceof Error ? error.message : String(error)}`));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const state = { deltas: '' };
|
|
157
|
+
let buffered = '';
|
|
158
|
+
let stderr = '';
|
|
159
|
+
let spawnError = null;
|
|
160
|
+
let killTimer;
|
|
161
|
+
const onAbort = () => {
|
|
162
|
+
killGroup(child, 'SIGTERM');
|
|
163
|
+
killTimer = setTimeout(() => killGroup(child, 'SIGKILL'), KILL_GRACE_MS);
|
|
164
|
+
killTimer.unref();
|
|
165
|
+
};
|
|
166
|
+
if (exec.signal.aborted)
|
|
167
|
+
onAbort();
|
|
168
|
+
else
|
|
169
|
+
exec.signal.addEventListener('abort', onAbort, { once: true });
|
|
170
|
+
child.stdout?.setEncoding('utf8');
|
|
171
|
+
child.stdout?.on('data', (chunk) => {
|
|
172
|
+
buffered += chunk;
|
|
173
|
+
let newline = buffered.indexOf('\n');
|
|
174
|
+
while (newline !== -1) {
|
|
175
|
+
const line = buffered.slice(0, newline).trim();
|
|
176
|
+
buffered = buffered.slice(newline + 1);
|
|
177
|
+
if (line)
|
|
178
|
+
applyClaudeStreamLine(state, line, exec.onDelta);
|
|
179
|
+
newline = buffered.indexOf('\n');
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
child.stderr?.setEncoding('utf8');
|
|
183
|
+
child.stderr?.on('data', (chunk) => {
|
|
184
|
+
stderr = (stderr + chunk).slice(-STDERR_TAIL_BYTES);
|
|
185
|
+
});
|
|
186
|
+
child.on('error', (error) => {
|
|
187
|
+
spawnError = error;
|
|
188
|
+
});
|
|
189
|
+
child.on('close', (code) => {
|
|
190
|
+
exec.signal.removeEventListener('abort', onAbort);
|
|
191
|
+
if (killTimer)
|
|
192
|
+
clearTimeout(killTimer);
|
|
193
|
+
if (buffered.trim())
|
|
194
|
+
applyClaudeStreamLine(state, buffered.trim(), exec.onDelta);
|
|
195
|
+
if (spawnError?.code === 'ENOENT') {
|
|
196
|
+
reject(new SdkInferenceError('ENGINE_UNAVAILABLE', `Claude Code is not installed on this machine ('${command}' was not found)`));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (exec.signal.aborted) {
|
|
200
|
+
reject(new SdkInferenceError('UPSTREAM_ERROR', 'the completion was stopped before it finished'));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
resolve(finishClaudeInference(state, code, spawnError ? `${spawnError.message}\n${stderr}` : stderr));
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
reject(error);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
child.stdin?.on('error', () => {
|
|
211
|
+
});
|
|
212
|
+
child.stdin?.end(renderInferencePrompt(exec.messages).replaceAll('\0', ''));
|
|
213
|
+
});
|
|
214
|
+
}
|