@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,197 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { randomBytes } from 'node:crypto';
|
|
4
|
+
import { deriveKey, seal, toBase64Url, utf8Encode, } from '@minionry/e2ee';
|
|
5
|
+
import { agreeWithPeerPublicKey, E2EE_PUBLIC_KEY_PATTERN, ensureE2eeIdentity, } from './e2ee-identity.js';
|
|
6
|
+
const GROUP_KEY_BYTES = 32;
|
|
7
|
+
export const INITIAL_GROUP_KEY_EPOCH = 1;
|
|
8
|
+
export const RETAINED_PRIOR_EPOCHS = 2;
|
|
9
|
+
const MAX_WRAP_CONTEXTS = 256;
|
|
10
|
+
export const KEK_SALT = new Uint8Array(32);
|
|
11
|
+
export function kekInfo(cliIdentityPublicKey, webEphemeralPublicKey) {
|
|
12
|
+
return `minionry/e2ee/kek/v1|${cliIdentityPublicKey}|${webEphemeralPublicKey}`;
|
|
13
|
+
}
|
|
14
|
+
export const KEY_DELIVERY_AAD_LABEL = 'minionry/e2ee/key-delivery/v1';
|
|
15
|
+
export function keyDeliveryAad(cliIdentityPublicKey, webEphemeralPublicKey) {
|
|
16
|
+
return utf8Encode(`${KEY_DELIVERY_AAD_LABEL}|${cliIdentityPublicKey}|${webEphemeralPublicKey}`);
|
|
17
|
+
}
|
|
18
|
+
const sessions = new Map();
|
|
19
|
+
function retireCurrentKey(session) {
|
|
20
|
+
if (!session.material)
|
|
21
|
+
return;
|
|
22
|
+
session.retired.unshift({ epoch: session.epoch, material: session.material });
|
|
23
|
+
session.material = null;
|
|
24
|
+
while (session.retired.length > RETAINED_PRIOR_EPOCHS) {
|
|
25
|
+
const expired = session.retired.pop();
|
|
26
|
+
expired?.material.fill(0);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function ensureGroupKeySession(orchestraKey) {
|
|
30
|
+
let session = sessions.get(orchestraKey);
|
|
31
|
+
if (!session) {
|
|
32
|
+
session = {
|
|
33
|
+
material: new Uint8Array(randomBytes(GROUP_KEY_BYTES)),
|
|
34
|
+
epoch: INITIAL_GROUP_KEY_EPOCH,
|
|
35
|
+
retired: [],
|
|
36
|
+
wrapContexts: new Map(),
|
|
37
|
+
};
|
|
38
|
+
sessions.set(orchestraKey, session);
|
|
39
|
+
return session;
|
|
40
|
+
}
|
|
41
|
+
if (!session.material) {
|
|
42
|
+
session.epoch++;
|
|
43
|
+
session.material = new Uint8Array(randomBytes(GROUP_KEY_BYTES));
|
|
44
|
+
}
|
|
45
|
+
return session;
|
|
46
|
+
}
|
|
47
|
+
function rotateGroupKeySession(orchestraKey) {
|
|
48
|
+
const session = sessions.get(orchestraKey);
|
|
49
|
+
if (!session)
|
|
50
|
+
return null;
|
|
51
|
+
retireCurrentKey(session);
|
|
52
|
+
session.epoch++;
|
|
53
|
+
session.material = new Uint8Array(randomBytes(GROUP_KEY_BYTES));
|
|
54
|
+
return session;
|
|
55
|
+
}
|
|
56
|
+
function enterCleartextEpoch(orchestraKey) {
|
|
57
|
+
const session = sessions.get(orchestraKey);
|
|
58
|
+
if (!session?.material)
|
|
59
|
+
return;
|
|
60
|
+
retireCurrentKey(session);
|
|
61
|
+
session.epoch++;
|
|
62
|
+
}
|
|
63
|
+
export async function deriveFromGroupKey(orchestraKey, salt, info) {
|
|
64
|
+
const session = sessions.get(orchestraKey);
|
|
65
|
+
if (!session?.material)
|
|
66
|
+
return null;
|
|
67
|
+
return { key: await deriveKey(session.material, salt, info), epoch: session.epoch };
|
|
68
|
+
}
|
|
69
|
+
export async function deriveFromGroupKeyForEpoch(orchestraKey, epoch, salt, info) {
|
|
70
|
+
const session = sessions.get(orchestraKey);
|
|
71
|
+
if (!session)
|
|
72
|
+
return null;
|
|
73
|
+
let material = null;
|
|
74
|
+
if (session.material && session.epoch === epoch) {
|
|
75
|
+
material = session.material;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
material = session.retired.find((r) => r.epoch === epoch)?.material ?? null;
|
|
79
|
+
}
|
|
80
|
+
if (!material)
|
|
81
|
+
return null;
|
|
82
|
+
return { key: await deriveKey(material, salt, info), epoch };
|
|
83
|
+
}
|
|
84
|
+
export function getGroupKeyEpochState(orchestraKey) {
|
|
85
|
+
const session = sessions.get(orchestraKey);
|
|
86
|
+
if (!session)
|
|
87
|
+
return null;
|
|
88
|
+
return { epoch: session.epoch, cleartext: session.material === null };
|
|
89
|
+
}
|
|
90
|
+
export function dropGroupKeyWrapContext(orchestraKey, viewerId) {
|
|
91
|
+
sessions.get(orchestraKey)?.wrapContexts.delete(viewerId);
|
|
92
|
+
}
|
|
93
|
+
export function resetE2eeGroupKeysForTests() {
|
|
94
|
+
sessions.clear();
|
|
95
|
+
}
|
|
96
|
+
function warn(message) {
|
|
97
|
+
console.warn(`[e2ee] ${message}`);
|
|
98
|
+
}
|
|
99
|
+
async function sealGroupKeyEnvelope(viewerId, webEphemeralPublicKey, session) {
|
|
100
|
+
if (!session.material)
|
|
101
|
+
throw new Error('no key material in the current epoch');
|
|
102
|
+
const identity = await ensureE2eeIdentity();
|
|
103
|
+
if (!identity.available || !identity.publicKey) {
|
|
104
|
+
throw new Error('this device has no usable E2EE identity');
|
|
105
|
+
}
|
|
106
|
+
const sharedSecret = await agreeWithPeerPublicKey(webEphemeralPublicKey);
|
|
107
|
+
const kek = await deriveKey(sharedSecret, KEK_SALT, kekInfo(identity.publicKey, webEphemeralPublicKey));
|
|
108
|
+
const plaintext = utf8Encode(JSON.stringify({ key: toBase64Url(session.material), epoch: session.epoch }));
|
|
109
|
+
const aad = keyDeliveryAad(identity.publicKey, webEphemeralPublicKey);
|
|
110
|
+
const box = await seal(kek, plaintext, aad);
|
|
111
|
+
return {
|
|
112
|
+
v: 1,
|
|
113
|
+
type: 'e2ee_key',
|
|
114
|
+
enc: false,
|
|
115
|
+
to: viewerId,
|
|
116
|
+
payload: {
|
|
117
|
+
data: {
|
|
118
|
+
publicKey: webEphemeralPublicKey,
|
|
119
|
+
sealed: { n: toBase64Url(box.nonce), c: toBase64Url(box.ct) },
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function recordWrapContext(session, viewerId, webEphemeralPublicKey) {
|
|
125
|
+
if (!session.wrapContexts.has(viewerId) && session.wrapContexts.size >= MAX_WRAP_CONTEXTS) {
|
|
126
|
+
const oldest = session.wrapContexts.keys().next().value;
|
|
127
|
+
if (oldest !== undefined)
|
|
128
|
+
session.wrapContexts.delete(oldest);
|
|
129
|
+
}
|
|
130
|
+
session.wrapContexts.set(viewerId, webEphemeralPublicKey);
|
|
131
|
+
}
|
|
132
|
+
export async function handleE2eeKeyRequest(message, ctx) {
|
|
133
|
+
try {
|
|
134
|
+
if (ctx.visibility === 'public') {
|
|
135
|
+
warn('Ignoring a group-key request: this Space is public (cleartext by design)');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const viewerId = message._viewer;
|
|
139
|
+
if (typeof viewerId !== 'string' || viewerId.length === 0) {
|
|
140
|
+
warn('Ignoring a group-key request without a relay-assigned viewer id (older relay?)');
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const data = message.data;
|
|
144
|
+
const rawKey = message.publicKey ?? data?.publicKey;
|
|
145
|
+
const webEphemeralPublicKey = typeof rawKey === 'string' && E2EE_PUBLIC_KEY_PATTERN.test(rawKey) ? rawKey : null;
|
|
146
|
+
if (!webEphemeralPublicKey) {
|
|
147
|
+
warn('Ignoring a group-key request with a missing or malformed ephemeral public key');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const session = ensureGroupKeySession(ctx.orchestraKey);
|
|
151
|
+
const envelope = await sealGroupKeyEnvelope(viewerId, webEphemeralPublicKey, session);
|
|
152
|
+
ctx.sendEnvelope(envelope);
|
|
153
|
+
recordWrapContext(session, viewerId, webEphemeralPublicKey);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
warn(`Group-key delivery failed (${err instanceof Error ? err.message : String(err)}) — the requester will retry or fall back to cleartext`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export async function handleE2eeMembershipChange(message, ctx) {
|
|
160
|
+
try {
|
|
161
|
+
const KNOWN_CHANGES = new Set([
|
|
162
|
+
'share_added',
|
|
163
|
+
'role_changed',
|
|
164
|
+
'share_revoked',
|
|
165
|
+
'share_blocked',
|
|
166
|
+
'share_unblocked',
|
|
167
|
+
'visibility_changed',
|
|
168
|
+
]);
|
|
169
|
+
const change = typeof message.change === 'string' && KNOWN_CHANGES.has(message.change)
|
|
170
|
+
? message.change
|
|
171
|
+
: 'membership_changed';
|
|
172
|
+
if (ctx.visibility === 'public') {
|
|
173
|
+
enterCleartextEpoch(ctx.orchestraKey);
|
|
174
|
+
warn(`Space is public after '${change}' — entered the cleartext epoch, encryption off`);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const session = rotateGroupKeySession(ctx.orchestraKey);
|
|
178
|
+
if (!session)
|
|
179
|
+
return;
|
|
180
|
+
let pushed = 0;
|
|
181
|
+
for (const [viewerId, webEphemeralPublicKey] of [...session.wrapContexts]) {
|
|
182
|
+
try {
|
|
183
|
+
const envelope = await sealGroupKeyEnvelope(viewerId, webEphemeralPublicKey, session);
|
|
184
|
+
ctx.sendEnvelope(envelope);
|
|
185
|
+
pushed++;
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
session.wrapContexts.delete(viewerId);
|
|
189
|
+
warn('Dropped a wrap context that failed to re-seal during rotation');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
warn(`Rotated the group key on '${change}' (epoch ${session.epoch}); re-sealed to ${pushed} connected session(s)`);
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
warn(`Group-key rotation failed (${err instanceof Error ? err.message : String(err)}) — keys unchanged`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { chmodSync, existsSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
4
|
+
import { agree, deriveSafetyNumber, fromBase64Url, generateIdentityKeyPair, toBase64Url, } from '@minionry/e2ee';
|
|
5
|
+
import { ensureMachineDir, machineFile } from '../../bin/machine-layout.js';
|
|
6
|
+
import { getCredentials } from './platform-credentials.js';
|
|
7
|
+
import { resolvePlatformUrl } from './platform-url.js';
|
|
8
|
+
const IDENTITY_FILE_VERSION = 1;
|
|
9
|
+
export const E2EE_PUBLIC_KEY_PATTERN = /^[A-Za-z0-9_-]{43}$/;
|
|
10
|
+
export function getE2eeIdentityPath() {
|
|
11
|
+
return machineFile('e2eeIdentity');
|
|
12
|
+
}
|
|
13
|
+
function warn(message) {
|
|
14
|
+
console.warn(`[e2ee] ${message}`);
|
|
15
|
+
}
|
|
16
|
+
function unavailable(reason) {
|
|
17
|
+
return { available: false, publicKey: null, reason };
|
|
18
|
+
}
|
|
19
|
+
let cachedStatus = null;
|
|
20
|
+
let cachedPrivateKey = null;
|
|
21
|
+
let ensureInFlight = null;
|
|
22
|
+
export function ensureE2eeIdentity() {
|
|
23
|
+
if (cachedStatus)
|
|
24
|
+
return Promise.resolve({ ...cachedStatus });
|
|
25
|
+
ensureInFlight ??= loadOrGenerate()
|
|
26
|
+
.then((result) => {
|
|
27
|
+
cachedStatus = result.status;
|
|
28
|
+
cachedPrivateKey = result.privateKey;
|
|
29
|
+
return { ...result.status };
|
|
30
|
+
})
|
|
31
|
+
.finally(() => {
|
|
32
|
+
ensureInFlight = null;
|
|
33
|
+
});
|
|
34
|
+
return ensureInFlight;
|
|
35
|
+
}
|
|
36
|
+
export async function agreeWithPeerPublicKey(theirPublicKeyBase64Url) {
|
|
37
|
+
const status = await ensureE2eeIdentity();
|
|
38
|
+
if (!status.available || !cachedPrivateKey) {
|
|
39
|
+
throw new Error(`e2ee identity unavailable${status.reason ? `: ${status.reason}` : ''}`);
|
|
40
|
+
}
|
|
41
|
+
return agree(fromBase64Url(theirPublicKeyBase64Url), cachedPrivateKey);
|
|
42
|
+
}
|
|
43
|
+
export function safetyNumberFor(publicKeyA, publicKeyB) {
|
|
44
|
+
return deriveSafetyNumber(fromBase64Url(publicKeyA), fromBase64Url(publicKeyB));
|
|
45
|
+
}
|
|
46
|
+
export async function deriveSessionSafetyNumber(peerPublicKeyBase64Url) {
|
|
47
|
+
const status = await ensureE2eeIdentity();
|
|
48
|
+
if (!status.available || !status.publicKey) {
|
|
49
|
+
throw new Error(`e2ee identity unavailable${status.reason ? `: ${status.reason}` : ''}`);
|
|
50
|
+
}
|
|
51
|
+
return safetyNumberFor(status.publicKey, peerPublicKeyBase64Url);
|
|
52
|
+
}
|
|
53
|
+
export const REGISTRATION_RETRY_DELAYS_MS = [
|
|
54
|
+
60_000,
|
|
55
|
+
120_000,
|
|
56
|
+
600_000,
|
|
57
|
+
1_800_000,
|
|
58
|
+
];
|
|
59
|
+
let registrationRetryTimer = null;
|
|
60
|
+
export async function registerE2eeIdentityWithPlatform(platformUrl, options) {
|
|
61
|
+
const base = platformUrl ?? resolvePlatformUrl();
|
|
62
|
+
const outcome = await attemptRegistration(base);
|
|
63
|
+
if (outcome === 'retryable') {
|
|
64
|
+
scheduleRegistrationRetry(base, options?.retryDelaysMs ?? REGISTRATION_RETRY_DELAYS_MS, 0);
|
|
65
|
+
}
|
|
66
|
+
return outcome === 'registered';
|
|
67
|
+
}
|
|
68
|
+
async function attemptRegistration(base) {
|
|
69
|
+
const status = await ensureE2eeIdentity();
|
|
70
|
+
if (!status.available || !status.publicKey)
|
|
71
|
+
return 'permanent';
|
|
72
|
+
const creds = getCredentials();
|
|
73
|
+
if (!creds?.token)
|
|
74
|
+
return 'permanent';
|
|
75
|
+
try {
|
|
76
|
+
const response = await fetch(`${base}/api/auth/device/e2ee-key`, {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
headers: {
|
|
79
|
+
'Authorization': `Bearer ${creds.token}`,
|
|
80
|
+
'Content-Type': 'application/json',
|
|
81
|
+
},
|
|
82
|
+
body: JSON.stringify({ e2eePublicKey: status.publicKey }),
|
|
83
|
+
});
|
|
84
|
+
if (response.ok)
|
|
85
|
+
return 'registered';
|
|
86
|
+
const retryable = response.status === 429 || response.status >= 500;
|
|
87
|
+
warn(`Public-key registration returned ${response.status} — ${retryable ? 'will retry' : 'continuing without E2EE registration (older relay?)'}`);
|
|
88
|
+
return retryable ? 'retryable' : 'permanent';
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
warn(`Public-key registration failed (${err instanceof Error ? err.message : String(err)}) — will retry`);
|
|
92
|
+
return 'retryable';
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function scheduleRegistrationRetry(base, delays, attempt) {
|
|
96
|
+
if (delays.length === 0)
|
|
97
|
+
return;
|
|
98
|
+
const delay = delays[Math.min(attempt, delays.length - 1)];
|
|
99
|
+
const jittered = Math.round(delay * (0.75 + Math.random() * 0.5));
|
|
100
|
+
if (registrationRetryTimer)
|
|
101
|
+
clearTimeout(registrationRetryTimer);
|
|
102
|
+
registrationRetryTimer = setTimeout(() => {
|
|
103
|
+
registrationRetryTimer = null;
|
|
104
|
+
void attemptRegistration(base).then((outcome) => {
|
|
105
|
+
if (outcome === 'retryable')
|
|
106
|
+
scheduleRegistrationRetry(base, delays, attempt + 1);
|
|
107
|
+
});
|
|
108
|
+
}, jittered);
|
|
109
|
+
registrationRetryTimer.unref();
|
|
110
|
+
}
|
|
111
|
+
export function resetE2eeIdentityForTests() {
|
|
112
|
+
cachedStatus = null;
|
|
113
|
+
cachedPrivateKey = null;
|
|
114
|
+
ensureInFlight = null;
|
|
115
|
+
if (registrationRetryTimer) {
|
|
116
|
+
clearTimeout(registrationRetryTimer);
|
|
117
|
+
registrationRetryTimer = null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async function loadOrGenerate() {
|
|
121
|
+
try {
|
|
122
|
+
if (existsSync(getE2eeIdentityPath())) {
|
|
123
|
+
return loadExisting();
|
|
124
|
+
}
|
|
125
|
+
return await generateAndPersist();
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
warn(`Unexpected identity failure (${err instanceof Error ? err.message : String(err)}) — continuing WITHOUT end-to-end encryption`);
|
|
129
|
+
return { status: unavailable('unexpected identity failure'), privateKey: null };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function loadExisting() {
|
|
133
|
+
const path = getE2eeIdentityPath();
|
|
134
|
+
if (process.platform !== 'win32') {
|
|
135
|
+
const mode = statSync(path).mode & 0o777;
|
|
136
|
+
if ((mode & 0o077) !== 0) {
|
|
137
|
+
warn(`Identity key file ${path} has unsafe permissions (0${mode.toString(8)}, expected 0600) — continuing WITHOUT end-to-end encryption. Fix with: chmod 600 ${path}`);
|
|
138
|
+
return { status: unavailable('identity file has unsafe permissions (expected 0600)'), privateKey: null };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
const record = JSON.parse(readFileSync(path, 'utf-8'));
|
|
143
|
+
if (record.v !== IDENTITY_FILE_VERSION) {
|
|
144
|
+
warn(`Identity key file ${path} has an unsupported format version — continuing WITHOUT end-to-end encryption. Upgrade the CLI, or delete the file to generate a fresh identity on next login.`);
|
|
145
|
+
return { status: unavailable('identity file version is not supported by this CLI'), privateKey: null };
|
|
146
|
+
}
|
|
147
|
+
const publicKey = record.publicKey;
|
|
148
|
+
const privateKeyB64u = record.privateKey;
|
|
149
|
+
if (typeof publicKey !== 'string' ||
|
|
150
|
+
!E2EE_PUBLIC_KEY_PATTERN.test(publicKey) ||
|
|
151
|
+
typeof privateKeyB64u !== 'string') {
|
|
152
|
+
throw new Error('malformed identity record');
|
|
153
|
+
}
|
|
154
|
+
const privateKey = fromBase64Url(privateKeyB64u);
|
|
155
|
+
if (privateKey.length < 32) {
|
|
156
|
+
throw new Error('malformed identity record');
|
|
157
|
+
}
|
|
158
|
+
return { status: { available: true, publicKey }, privateKey };
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
warn(`Identity key file ${path} is unreadable or corrupt — continuing WITHOUT end-to-end encryption. Delete the file to generate a fresh identity on next login (peers will re-pin the new key).`);
|
|
162
|
+
return { status: unavailable('identity file is unreadable or corrupt'), privateKey: null };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function generateAndPersist() {
|
|
166
|
+
const generated = await generateIdentityKeyPair().catch((err) => {
|
|
167
|
+
warn(`This runtime cannot generate an X25519 identity key (${err instanceof Error ? err.message : String(err)}) — continuing WITHOUT end-to-end encryption`);
|
|
168
|
+
return null;
|
|
169
|
+
});
|
|
170
|
+
if (!generated) {
|
|
171
|
+
return { status: unavailable('key generation unsupported on this runtime'), privateKey: null };
|
|
172
|
+
}
|
|
173
|
+
const publicKey = toBase64Url(generated.publicKey);
|
|
174
|
+
const record = `${JSON.stringify({
|
|
175
|
+
v: IDENTITY_FILE_VERSION,
|
|
176
|
+
publicKey,
|
|
177
|
+
privateKey: toBase64Url(generated.privateKey),
|
|
178
|
+
createdAt: new Date().toISOString(),
|
|
179
|
+
}, null, 2)}\n`;
|
|
180
|
+
const path = getE2eeIdentityPath();
|
|
181
|
+
const tmpPath = `${path}.${process.pid}.tmp`;
|
|
182
|
+
try {
|
|
183
|
+
ensureMachineDir('credentials');
|
|
184
|
+
writeFileSync(tmpPath, record, { mode: 0o600 });
|
|
185
|
+
try {
|
|
186
|
+
chmodSync(tmpPath, 0o600);
|
|
187
|
+
renameSync(tmpPath, path);
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
try {
|
|
191
|
+
unlinkSync(tmpPath);
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
}
|
|
195
|
+
throw err;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
warn(`Could not persist the identity key (${err instanceof Error ? err.message : String(err)}) — continuing WITHOUT end-to-end encryption`);
|
|
200
|
+
return { status: unavailable('could not persist identity key'), privateKey: null };
|
|
201
|
+
}
|
|
202
|
+
return { status: { available: true, publicKey }, privateKey: generated.privateKey };
|
|
203
|
+
}
|