hivehq 2.0.0
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/CHANGELOG.md +592 -0
- package/LICENSE +208 -0
- package/LICENSE.BSL +101 -0
- package/NOTICE +15 -0
- package/README.en.md +451 -0
- package/README.md +329 -0
- package/SECURITY.md +59 -0
- package/TRADEMARK.md +41 -0
- package/assets/hive-hero.png +0 -0
- package/assets/hive-team-view.png +0 -0
- package/assets/logo.png +0 -0
- package/assets/qq-group.jpg +0 -0
- package/dist/bin/team +7 -0
- package/dist/bin/team.cmd +3 -0
- package/dist/src/cli/hive-remote.d.ts +46 -0
- package/dist/src/cli/hive-remote.js +257 -0
- package/dist/src/cli/hive-update.d.ts +75 -0
- package/dist/src/cli/hive-update.js +215 -0
- package/dist/src/cli/hive.d.ts +78 -0
- package/dist/src/cli/hive.js +336 -0
- package/dist/src/cli/team.d.ts +38 -0
- package/dist/src/cli/team.js +762 -0
- package/dist/src/server/agent-command-resolver.d.ts +17 -0
- package/dist/src/server/agent-command-resolver.js +106 -0
- package/dist/src/server/agent-exit-classification.d.ts +6 -0
- package/dist/src/server/agent-exit-classification.js +6 -0
- package/dist/src/server/agent-launch-cache.d.ts +20 -0
- package/dist/src/server/agent-launch-cache.js +75 -0
- package/dist/src/server/agent-launch-resolver.d.ts +4 -0
- package/dist/src/server/agent-launch-resolver.js +38 -0
- package/dist/src/server/agent-manager-support.d.ts +36 -0
- package/dist/src/server/agent-manager-support.js +318 -0
- package/dist/src/server/agent-manager.d.ts +54 -0
- package/dist/src/server/agent-manager.js +104 -0
- package/dist/src/server/agent-run-bootstrap.d.ts +83 -0
- package/dist/src/server/agent-run-bootstrap.js +101 -0
- package/dist/src/server/agent-run-exit-handler.d.ts +8 -0
- package/dist/src/server/agent-run-exit-handler.js +32 -0
- package/dist/src/server/agent-run-start-context.d.ts +24 -0
- package/dist/src/server/agent-run-start-context.js +1 -0
- package/dist/src/server/agent-run-starter.d.ts +30 -0
- package/dist/src/server/agent-run-starter.js +155 -0
- package/dist/src/server/agent-run-store.d.ts +51 -0
- package/dist/src/server/agent-run-store.js +137 -0
- package/dist/src/server/agent-run-sync.d.ts +10 -0
- package/dist/src/server/agent-run-sync.js +32 -0
- package/dist/src/server/agent-runtime-active-run.d.ts +3 -0
- package/dist/src/server/agent-runtime-active-run.js +10 -0
- package/dist/src/server/agent-runtime-close.d.ts +5 -0
- package/dist/src/server/agent-runtime-close.js +36 -0
- package/dist/src/server/agent-runtime-contract.d.ts +48 -0
- package/dist/src/server/agent-runtime-contract.js +1 -0
- package/dist/src/server/agent-runtime-flow-adapter.d.ts +10 -0
- package/dist/src/server/agent-runtime-flow-adapter.js +14 -0
- package/dist/src/server/agent-runtime-list-runs.d.ts +3 -0
- package/dist/src/server/agent-runtime-list-runs.js +18 -0
- package/dist/src/server/agent-runtime-ports.d.ts +22 -0
- package/dist/src/server/agent-runtime-ports.js +1 -0
- package/dist/src/server/agent-runtime-stop-run.d.ts +4 -0
- package/dist/src/server/agent-runtime-stop-run.js +19 -0
- package/dist/src/server/agent-runtime-types.d.ts +5 -0
- package/dist/src/server/agent-runtime-types.js +1 -0
- package/dist/src/server/agent-runtime.d.ts +10 -0
- package/dist/src/server/agent-runtime.js +143 -0
- package/dist/src/server/agent-session-store.d.ts +7 -0
- package/dist/src/server/agent-session-store.js +45 -0
- package/dist/src/server/agent-startup-instructions.d.ts +20 -0
- package/dist/src/server/agent-startup-instructions.js +36 -0
- package/dist/src/server/agent-stdin-dispatcher.d.ts +52 -0
- package/dist/src/server/agent-stdin-dispatcher.js +224 -0
- package/dist/src/server/agent-tokens.d.ts +15 -0
- package/dist/src/server/agent-tokens.js +25 -0
- package/dist/src/server/app-state-store.d.ts +10 -0
- package/dist/src/server/app-state-store.js +12 -0
- package/dist/src/server/app.d.ts +20 -0
- package/dist/src/server/app.js +211 -0
- package/dist/src/server/claude-command-defaults.d.ts +1 -0
- package/dist/src/server/claude-command-defaults.js +5 -0
- package/dist/src/server/claude-session-coordinator.d.ts +10 -0
- package/dist/src/server/claude-session-coordinator.js +68 -0
- package/dist/src/server/claude-session-support.d.ts +1 -0
- package/dist/src/server/claude-session-support.js +1 -0
- package/dist/src/server/command-preset-defaults.d.ts +11 -0
- package/dist/src/server/command-preset-defaults.js +63 -0
- package/dist/src/server/command-preset-store.d.ts +49 -0
- package/dist/src/server/command-preset-store.js +83 -0
- package/dist/src/server/cron-util.d.ts +7 -0
- package/dist/src/server/cron-util.js +19 -0
- package/dist/src/server/dispatch-ledger-serializer.d.ts +15 -0
- package/dist/src/server/dispatch-ledger-serializer.js +14 -0
- package/dist/src/server/dispatch-ledger-store.d.ts +108 -0
- package/dist/src/server/dispatch-ledger-store.js +241 -0
- package/dist/src/server/env-sync-message.d.ts +9 -0
- package/dist/src/server/env-sync-message.js +29 -0
- package/dist/src/server/feature-flags.d.ts +42 -0
- package/dist/src/server/feature-flags.js +24 -0
- package/dist/src/server/fs-browse.d.ts +40 -0
- package/dist/src/server/fs-browse.js +306 -0
- package/dist/src/server/fs-pick-folder.d.ts +25 -0
- package/dist/src/server/fs-pick-folder.js +115 -0
- package/dist/src/server/fs-sandbox.d.ts +15 -0
- package/dist/src/server/fs-sandbox.js +56 -0
- package/dist/src/server/hive-team-guidance.d.ts +39 -0
- package/dist/src/server/hive-team-guidance.js +295 -0
- package/dist/src/server/http-errors.d.ts +22 -0
- package/dist/src/server/http-errors.js +44 -0
- package/dist/src/server/live-run-registry.d.ts +22 -0
- package/dist/src/server/live-run-registry.js +52 -0
- package/dist/src/server/local-request-guard.d.ts +3 -0
- package/dist/src/server/local-request-guard.js +41 -0
- package/dist/src/server/machine-name.d.ts +2 -0
- package/dist/src/server/machine-name.js +13 -0
- package/dist/src/server/marketplace-store.d.ts +38 -0
- package/dist/src/server/marketplace-store.js +85 -0
- package/dist/src/server/message-log-store.d.ts +51 -0
- package/dist/src/server/message-log-store.js +90 -0
- package/dist/src/server/open-target-commands.d.ts +54 -0
- package/dist/src/server/open-target-commands.js +204 -0
- package/dist/src/server/orchestrator-autostart.d.ts +42 -0
- package/dist/src/server/orchestrator-autostart.js +114 -0
- package/dist/src/server/orchestrator-launch.d.ts +24 -0
- package/dist/src/server/orchestrator-launch.js +71 -0
- package/dist/src/server/package-version.d.ts +17 -0
- package/dist/src/server/package-version.js +32 -0
- package/dist/src/server/path-canonicalization.d.ts +3 -0
- package/dist/src/server/path-canonicalization.js +29 -0
- package/dist/src/server/platform-path.d.ts +4 -0
- package/dist/src/server/platform-path.js +26 -0
- package/dist/src/server/post-start-input-writer.d.ts +6 -0
- package/dist/src/server/post-start-input-writer.js +242 -0
- package/dist/src/server/preset-launch-support.d.ts +6 -0
- package/dist/src/server/preset-launch-support.js +98 -0
- package/dist/src/server/pty-output-bus.d.ts +8 -0
- package/dist/src/server/pty-output-bus.js +32 -0
- package/dist/src/server/recovery-summary.d.ts +15 -0
- package/dist/src/server/recovery-summary.js +92 -0
- package/dist/src/server/remote-audit-store.d.ts +51 -0
- package/dist/src/server/remote-audit-store.js +108 -0
- package/dist/src/server/remote-config-keys.d.ts +17 -0
- package/dist/src/server/remote-config-keys.js +27 -0
- package/dist/src/server/remote-control-constants.d.ts +30 -0
- package/dist/src/server/remote-control-constants.js +29 -0
- package/dist/src/server/remote-device-session.d.ts +40 -0
- package/dist/src/server/remote-device-session.js +22 -0
- package/dist/src/server/remote-device-store.d.ts +36 -0
- package/dist/src/server/remote-device-store.js +67 -0
- package/dist/src/server/remote-frame-bridge.d.ts +102 -0
- package/dist/src/server/remote-frame-bridge.js +791 -0
- package/dist/src/server/remote-gateway-client.d.ts +14 -0
- package/dist/src/server/remote-gateway-client.js +36 -0
- package/dist/src/server/remote-loopback-auth.d.ts +6 -0
- package/dist/src/server/remote-loopback-auth.js +112 -0
- package/dist/src/server/remote-pairing-tunnel.d.ts +59 -0
- package/dist/src/server/remote-pairing-tunnel.js +146 -0
- package/dist/src/server/remote-pairing.d.ts +58 -0
- package/dist/src/server/remote-pairing.js +237 -0
- package/dist/src/server/remote-tunnel.d.ts +113 -0
- package/dist/src/server/remote-tunnel.js +514 -0
- package/dist/src/server/report-outbox-store.d.ts +36 -0
- package/dist/src/server/report-outbox-store.js +33 -0
- package/dist/src/server/restart-policy-support.d.ts +30 -0
- package/dist/src/server/restart-policy-support.js +21 -0
- package/dist/src/server/restart-policy.d.ts +18 -0
- package/dist/src/server/restart-policy.js +77 -0
- package/dist/src/server/role-template-store.d.ts +45 -0
- package/dist/src/server/role-template-store.js +76 -0
- package/dist/src/server/role-templates.d.ts +7 -0
- package/dist/src/server/role-templates.js +54 -0
- package/dist/src/server/route-helpers.d.ts +9 -0
- package/dist/src/server/route-helpers.js +61 -0
- package/dist/src/server/route-types.d.ts +121 -0
- package/dist/src/server/route-types.js +1 -0
- package/dist/src/server/routes-dispatches.d.ts +2 -0
- package/dist/src/server/routes-dispatches.js +54 -0
- package/dist/src/server/routes-fs.d.ts +2 -0
- package/dist/src/server/routes-fs.js +24 -0
- package/dist/src/server/routes-marketplace.d.ts +2 -0
- package/dist/src/server/routes-marketplace.js +54 -0
- package/dist/src/server/routes-open-workspace.d.ts +2 -0
- package/dist/src/server/routes-open-workspace.js +47 -0
- package/dist/src/server/routes-remote.d.ts +2 -0
- package/dist/src/server/routes-remote.js +166 -0
- package/dist/src/server/routes-runtime.d.ts +2 -0
- package/dist/src/server/routes-runtime.js +79 -0
- package/dist/src/server/routes-settings.d.ts +2 -0
- package/dist/src/server/routes-settings.js +213 -0
- package/dist/src/server/routes-tasks.d.ts +2 -0
- package/dist/src/server/routes-tasks.js +47 -0
- package/dist/src/server/routes-team-memory.d.ts +2 -0
- package/dist/src/server/routes-team-memory.js +154 -0
- package/dist/src/server/routes-team-recall.d.ts +2 -0
- package/dist/src/server/routes-team-recall.js +119 -0
- package/dist/src/server/routes-team.d.ts +2 -0
- package/dist/src/server/routes-team.js +351 -0
- package/dist/src/server/routes-ui.d.ts +2 -0
- package/dist/src/server/routes-ui.js +17 -0
- package/dist/src/server/routes-version.d.ts +2 -0
- package/dist/src/server/routes-version.js +6 -0
- package/dist/src/server/routes-workflow-schedules.d.ts +2 -0
- package/dist/src/server/routes-workflow-schedules.js +58 -0
- package/dist/src/server/routes-workflows.d.ts +2 -0
- package/dist/src/server/routes-workflows.js +83 -0
- package/dist/src/server/routes-workspace-memory-dreams.d.ts +2 -0
- package/dist/src/server/routes-workspace-memory-dreams.js +105 -0
- package/dist/src/server/routes-workspace-memory.d.ts +2 -0
- package/dist/src/server/routes-workspace-memory.js +215 -0
- package/dist/src/server/routes-workspaces.d.ts +2 -0
- package/dist/src/server/routes-workspaces.js +177 -0
- package/dist/src/server/routes.d.ts +6 -0
- package/dist/src/server/routes.js +55 -0
- package/dist/src/server/runtime-database.d.ts +3 -0
- package/dist/src/server/runtime-database.js +41 -0
- package/dist/src/server/runtime-message-builders.d.ts +7 -0
- package/dist/src/server/runtime-message-builders.js +60 -0
- package/dist/src/server/runtime-restart-policy.d.ts +18 -0
- package/dist/src/server/runtime-restart-policy.js +12 -0
- package/dist/src/server/runtime-store-contract.d.ts +162 -0
- package/dist/src/server/runtime-store-contract.js +1 -0
- package/dist/src/server/runtime-store-dream.d.ts +23 -0
- package/dist/src/server/runtime-store-dream.js +16 -0
- package/dist/src/server/runtime-store-helpers.d.ts +115 -0
- package/dist/src/server/runtime-store-helpers.js +411 -0
- package/dist/src/server/runtime-store-memory.d.ts +33 -0
- package/dist/src/server/runtime-store-memory.js +37 -0
- package/dist/src/server/runtime-store-remote.d.ts +5 -0
- package/dist/src/server/runtime-store-remote.js +45 -0
- package/dist/src/server/runtime-store-workflows.d.ts +6 -0
- package/dist/src/server/runtime-store-workflows.js +108 -0
- package/dist/src/server/runtime-store.d.ts +4 -0
- package/dist/src/server/runtime-store.js +165 -0
- package/dist/src/server/session-capture-claude.d.ts +34 -0
- package/dist/src/server/session-capture-claude.js +103 -0
- package/dist/src/server/session-capture-codex.d.ts +6 -0
- package/dist/src/server/session-capture-codex.js +108 -0
- package/dist/src/server/session-capture-gemini.d.ts +5 -0
- package/dist/src/server/session-capture-gemini.js +81 -0
- package/dist/src/server/session-capture-opencode.d.ts +22 -0
- package/dist/src/server/session-capture-opencode.js +75 -0
- package/dist/src/server/session-capture.d.ts +77 -0
- package/dist/src/server/session-capture.js +123 -0
- package/dist/src/server/settings-store.d.ts +22 -0
- package/dist/src/server/settings-store.js +22 -0
- package/dist/src/server/sqlite-schema-v10.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v10.js +13 -0
- package/dist/src/server/sqlite-schema-v11.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v11.js +10 -0
- package/dist/src/server/sqlite-schema-v12.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v12.js +21 -0
- package/dist/src/server/sqlite-schema-v13.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v13.js +4 -0
- package/dist/src/server/sqlite-schema-v14.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v14.js +84 -0
- package/dist/src/server/sqlite-schema-v15.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v15.js +73 -0
- package/dist/src/server/sqlite-schema-v16.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v16.js +6 -0
- package/dist/src/server/sqlite-schema-v17.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v17.js +15 -0
- package/dist/src/server/sqlite-schema-v18.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v18.js +6 -0
- package/dist/src/server/sqlite-schema-v19.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v19.js +17 -0
- package/dist/src/server/sqlite-schema-v20.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v20.js +20 -0
- package/dist/src/server/sqlite-schema-v21.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v21.js +20 -0
- package/dist/src/server/sqlite-schema-v22.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v22.js +27 -0
- package/dist/src/server/sqlite-schema-v23.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v23.js +43 -0
- package/dist/src/server/sqlite-schema-v24.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v24.js +34 -0
- package/dist/src/server/sqlite-schema-v25.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v25.js +127 -0
- package/dist/src/server/sqlite-schema-v26.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v26.js +56 -0
- package/dist/src/server/sqlite-schema-v27.d.ts +6 -0
- package/dist/src/server/sqlite-schema-v27.js +92 -0
- package/dist/src/server/sqlite-schema-v28.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v28.js +19 -0
- package/dist/src/server/sqlite-schema-v5.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v5.js +61 -0
- package/dist/src/server/sqlite-schema-v7.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v7.js +70 -0
- package/dist/src/server/sqlite-schema-v8.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v8.js +6 -0
- package/dist/src/server/sqlite-schema-v9.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v9.js +6 -0
- package/dist/src/server/sqlite-schema.d.ts +3 -0
- package/dist/src/server/sqlite-schema.js +353 -0
- package/dist/src/server/startup-command-parser.d.ts +20 -0
- package/dist/src/server/startup-command-parser.js +72 -0
- package/dist/src/server/system-message.d.ts +8 -0
- package/dist/src/server/system-message.js +8 -0
- package/dist/src/server/task-deps.d.ts +32 -0
- package/dist/src/server/task-deps.js +40 -0
- package/dist/src/server/tasks-file-watcher.d.ts +47 -0
- package/dist/src/server/tasks-file-watcher.js +200 -0
- package/dist/src/server/tasks-file.d.ts +23 -0
- package/dist/src/server/tasks-file.js +101 -0
- package/dist/src/server/tasks-websocket-server.d.ts +8 -0
- package/dist/src/server/tasks-websocket-server.js +95 -0
- package/dist/src/server/team-authz.d.ts +13 -0
- package/dist/src/server/team-authz.js +53 -0
- package/dist/src/server/team-autostaff.d.ts +16 -0
- package/dist/src/server/team-autostaff.js +16 -0
- package/dist/src/server/team-list-enrichment.d.ts +22 -0
- package/dist/src/server/team-list-enrichment.js +40 -0
- package/dist/src/server/team-list-serializer.d.ts +2 -0
- package/dist/src/server/team-list-serializer.js +11 -0
- package/dist/src/server/team-memory-digest.d.ts +52 -0
- package/dist/src/server/team-memory-digest.js +200 -0
- package/dist/src/server/team-memory-dream-applier.d.ts +5 -0
- package/dist/src/server/team-memory-dream-applier.js +234 -0
- package/dist/src/server/team-memory-dream-http-serializers.d.ts +13 -0
- package/dist/src/server/team-memory-dream-http-serializers.js +12 -0
- package/dist/src/server/team-memory-dream-ops.d.ts +40 -0
- package/dist/src/server/team-memory-dream-ops.js +153 -0
- package/dist/src/server/team-memory-dream-reverter.d.ts +22 -0
- package/dist/src/server/team-memory-dream-reverter.js +221 -0
- package/dist/src/server/team-memory-dream-run-store.d.ts +23 -0
- package/dist/src/server/team-memory-dream-run-store.js +211 -0
- package/dist/src/server/team-memory-dream-runner.d.ts +37 -0
- package/dist/src/server/team-memory-dream-runner.js +178 -0
- package/dist/src/server/team-memory-dream-scheduler.d.ts +32 -0
- package/dist/src/server/team-memory-dream-scheduler.js +115 -0
- package/dist/src/server/team-memory-dream-store.d.ts +19 -0
- package/dist/src/server/team-memory-dream-store.js +16 -0
- package/dist/src/server/team-memory-dream-types.d.ts +104 -0
- package/dist/src/server/team-memory-dream-types.js +23 -0
- package/dist/src/server/team-memory-export.d.ts +22 -0
- package/dist/src/server/team-memory-export.js +220 -0
- package/dist/src/server/team-memory-feature.d.ts +12 -0
- package/dist/src/server/team-memory-feature.js +12 -0
- package/dist/src/server/team-memory-http-serializers.d.ts +102 -0
- package/dist/src/server/team-memory-http-serializers.js +46 -0
- package/dist/src/server/team-memory-injection.d.ts +31 -0
- package/dist/src/server/team-memory-injection.js +49 -0
- package/dist/src/server/team-memory-store.d.ts +116 -0
- package/dist/src/server/team-memory-store.js +513 -0
- package/dist/src/server/team-operations.d.ts +102 -0
- package/dist/src/server/team-operations.js +387 -0
- package/dist/src/server/team-recall-store.d.ts +38 -0
- package/dist/src/server/team-recall-store.js +205 -0
- package/dist/src/server/terminal-flow-control.d.ts +19 -0
- package/dist/src/server/terminal-flow-control.js +116 -0
- package/dist/src/server/terminal-input-profile.d.ts +10 -0
- package/dist/src/server/terminal-input-profile.js +9 -0
- package/dist/src/server/terminal-protocol.d.ts +29 -0
- package/dist/src/server/terminal-protocol.js +47 -0
- package/dist/src/server/terminal-state-mirror.d.ts +21 -0
- package/dist/src/server/terminal-state-mirror.js +67 -0
- package/dist/src/server/terminal-stream-hub.d.ts +9 -0
- package/dist/src/server/terminal-stream-hub.js +192 -0
- package/dist/src/server/terminal-ws-server.d.ts +6 -0
- package/dist/src/server/terminal-ws-server.js +115 -0
- package/dist/src/server/ui-auth-helpers.d.ts +4 -0
- package/dist/src/server/ui-auth-helpers.js +28 -0
- package/dist/src/server/ui-auth.d.ts +8 -0
- package/dist/src/server/ui-auth.js +32 -0
- package/dist/src/server/version-service.d.ts +16 -0
- package/dist/src/server/version-service.js +72 -0
- package/dist/src/server/webhook-notifier.d.ts +34 -0
- package/dist/src/server/webhook-notifier.js +47 -0
- package/dist/src/server/websocket-upgrade-safety.d.ts +10 -0
- package/dist/src/server/websocket-upgrade-safety.js +35 -0
- package/dist/src/server/windows-command-line.d.ts +3 -0
- package/dist/src/server/windows-command-line.js +9 -0
- package/dist/src/server/windows-filename.d.ts +2 -0
- package/dist/src/server/windows-filename.js +33 -0
- package/dist/src/server/worker-output-tracker.d.ts +14 -0
- package/dist/src/server/worker-output-tracker.js +50 -0
- package/dist/src/server/workflow-cli-policy.d.ts +60 -0
- package/dist/src/server/workflow-cli-policy.js +110 -0
- package/dist/src/server/workflow-dispatch-awaiter.d.ts +12 -0
- package/dist/src/server/workflow-dispatch-awaiter.js +80 -0
- package/dist/src/server/workflow-feature.d.ts +15 -0
- package/dist/src/server/workflow-feature.js +15 -0
- package/dist/src/server/workflow-http-serializers.d.ts +64 -0
- package/dist/src/server/workflow-http-serializers.js +58 -0
- package/dist/src/server/workflow-output-schema.d.ts +18 -0
- package/dist/src/server/workflow-output-schema.js +41 -0
- package/dist/src/server/workflow-run-log-store.d.ts +19 -0
- package/dist/src/server/workflow-run-log-store.js +45 -0
- package/dist/src/server/workflow-run-store.d.ts +50 -0
- package/dist/src/server/workflow-run-store.js +103 -0
- package/dist/src/server/workflow-runner.d.ts +147 -0
- package/dist/src/server/workflow-runner.js +411 -0
- package/dist/src/server/workflow-schedule-create.d.ts +14 -0
- package/dist/src/server/workflow-schedule-create.js +41 -0
- package/dist/src/server/workflow-schedule-store.d.ts +43 -0
- package/dist/src/server/workflow-schedule-store.js +112 -0
- package/dist/src/server/workflow-scheduler.d.ts +36 -0
- package/dist/src/server/workflow-scheduler.js +97 -0
- package/dist/src/server/workflow-script-loader.d.ts +34 -0
- package/dist/src/server/workflow-script-loader.js +106 -0
- package/dist/src/server/workspace-path-validation.d.ts +1 -0
- package/dist/src/server/workspace-path-validation.js +42 -0
- package/dist/src/server/workspace-shell-runtime.d.ts +35 -0
- package/dist/src/server/workspace-shell-runtime.js +228 -0
- package/dist/src/server/workspace-store-contract.d.ts +32 -0
- package/dist/src/server/workspace-store-contract.js +1 -0
- package/dist/src/server/workspace-store-hydration.d.ts +5 -0
- package/dist/src/server/workspace-store-hydration.js +76 -0
- package/dist/src/server/workspace-store-mutations.d.ts +14 -0
- package/dist/src/server/workspace-store-mutations.js +48 -0
- package/dist/src/server/workspace-store-support.d.ts +33 -0
- package/dist/src/server/workspace-store-support.js +36 -0
- package/dist/src/server/workspace-store.d.ts +5 -0
- package/dist/src/server/workspace-store.js +153 -0
- package/dist/src/shared/fs-browse.d.ts +1 -0
- package/dist/src/shared/fs-browse.js +1 -0
- package/dist/src/shared/open-targets.d.ts +20 -0
- package/dist/src/shared/open-targets.js +36 -0
- package/dist/src/shared/path-input.d.ts +12 -0
- package/dist/src/shared/path-input.js +22 -0
- package/dist/src/shared/remote-bridge-routing.d.ts +19 -0
- package/dist/src/shared/remote-bridge-routing.js +141 -0
- package/dist/src/shared/remote-crypto.d.ts +138 -0
- package/dist/src/shared/remote-crypto.js +427 -0
- package/dist/src/shared/remote-pairing-code.d.ts +7 -0
- package/dist/src/shared/remote-pairing-code.js +47 -0
- package/dist/src/shared/remote-protocol.d.ts +160 -0
- package/dist/src/shared/remote-protocol.js +526 -0
- package/dist/src/shared/team-memory.d.ts +11 -0
- package/dist/src/shared/team-memory.js +10 -0
- package/dist/src/shared/team-recall.d.ts +1 -0
- package/dist/src/shared/team-recall.js +1 -0
- package/dist/src/shared/types.d.ts +66 -0
- package/dist/src/shared/types.js +1 -0
- package/dist/vendor/marketplace/en/LICENSE +21 -0
- package/dist/vendor/marketplace/en/SOURCES.md +12 -0
- package/dist/vendor/marketplace/en/academic/academic-anthropologist.md +125 -0
- package/dist/vendor/marketplace/en/academic/academic-geographer.md +127 -0
- package/dist/vendor/marketplace/en/academic/academic-historian.md +123 -0
- package/dist/vendor/marketplace/en/academic/academic-narratologist.md +118 -0
- package/dist/vendor/marketplace/en/academic/academic-psychologist.md +118 -0
- package/dist/vendor/marketplace/en/design/design-brand-guardian.md +322 -0
- package/dist/vendor/marketplace/en/design/design-image-prompt-engineer.md +236 -0
- package/dist/vendor/marketplace/en/design/design-inclusive-visuals-specialist.md +71 -0
- package/dist/vendor/marketplace/en/design/design-ui-designer.md +383 -0
- package/dist/vendor/marketplace/en/design/design-ux-architect.md +469 -0
- package/dist/vendor/marketplace/en/design/design-ux-researcher.md +329 -0
- package/dist/vendor/marketplace/en/design/design-visual-storyteller.md +149 -0
- package/dist/vendor/marketplace/en/design/design-whimsy-injector.md +438 -0
- package/dist/vendor/marketplace/en/engineering/engineering-ai-data-remediation-engineer.md +211 -0
- package/dist/vendor/marketplace/en/engineering/engineering-ai-engineer.md +146 -0
- package/dist/vendor/marketplace/en/engineering/engineering-autonomous-optimization-architect.md +107 -0
- package/dist/vendor/marketplace/en/engineering/engineering-backend-architect.md +235 -0
- package/dist/vendor/marketplace/en/engineering/engineering-cms-developer.md +536 -0
- package/dist/vendor/marketplace/en/engineering/engineering-code-reviewer.md +76 -0
- package/dist/vendor/marketplace/en/engineering/engineering-codebase-onboarding-engineer.md +173 -0
- package/dist/vendor/marketplace/en/engineering/engineering-data-engineer.md +306 -0
- package/dist/vendor/marketplace/en/engineering/engineering-database-optimizer.md +176 -0
- package/dist/vendor/marketplace/en/engineering/engineering-devops-automator.md +376 -0
- package/dist/vendor/marketplace/en/engineering/engineering-email-intelligence-engineer.md +353 -0
- package/dist/vendor/marketplace/en/engineering/engineering-embedded-firmware-engineer.md +173 -0
- package/dist/vendor/marketplace/en/engineering/engineering-feishu-integration-developer.md +598 -0
- package/dist/vendor/marketplace/en/engineering/engineering-filament-optimization-specialist.md +283 -0
- package/dist/vendor/marketplace/en/engineering/engineering-frontend-developer.md +225 -0
- package/dist/vendor/marketplace/en/engineering/engineering-git-workflow-master.md +84 -0
- package/dist/vendor/marketplace/en/engineering/engineering-incident-response-commander.md +444 -0
- package/dist/vendor/marketplace/en/engineering/engineering-minimal-change-engineer.md +207 -0
- package/dist/vendor/marketplace/en/engineering/engineering-mobile-app-builder.md +493 -0
- package/dist/vendor/marketplace/en/engineering/engineering-rapid-prototyper.md +462 -0
- package/dist/vendor/marketplace/en/engineering/engineering-security-engineer.md +304 -0
- package/dist/vendor/marketplace/en/engineering/engineering-senior-developer.md +176 -0
- package/dist/vendor/marketplace/en/engineering/engineering-software-architect.md +81 -0
- package/dist/vendor/marketplace/en/engineering/engineering-solidity-smart-contract-engineer.md +522 -0
- package/dist/vendor/marketplace/en/engineering/engineering-sre.md +90 -0
- package/dist/vendor/marketplace/en/engineering/engineering-technical-writer.md +393 -0
- package/dist/vendor/marketplace/en/engineering/engineering-threat-detection-engineer.md +534 -0
- package/dist/vendor/marketplace/en/engineering/engineering-voice-ai-integration-engineer.md +561 -0
- package/dist/vendor/marketplace/en/engineering/engineering-wechat-mini-program-developer.md +350 -0
- package/dist/vendor/marketplace/en/finance/finance-bookkeeper-controller.md +260 -0
- package/dist/vendor/marketplace/en/finance/finance-financial-analyst.md +234 -0
- package/dist/vendor/marketplace/en/finance/finance-fpa-analyst.md +263 -0
- package/dist/vendor/marketplace/en/finance/finance-investment-researcher.md +272 -0
- package/dist/vendor/marketplace/en/finance/finance-tax-strategist.md +239 -0
- package/dist/vendor/marketplace/en/game-development/blender/blender-addon-engineer.md +234 -0
- package/dist/vendor/marketplace/en/game-development/game-audio-engineer.md +264 -0
- package/dist/vendor/marketplace/en/game-development/game-designer.md +167 -0
- package/dist/vendor/marketplace/en/game-development/godot/godot-gameplay-scripter.md +334 -0
- package/dist/vendor/marketplace/en/game-development/godot/godot-multiplayer-engineer.md +297 -0
- package/dist/vendor/marketplace/en/game-development/godot/godot-shader-developer.md +266 -0
- package/dist/vendor/marketplace/en/game-development/level-designer.md +208 -0
- package/dist/vendor/marketplace/en/game-development/narrative-designer.md +243 -0
- package/dist/vendor/marketplace/en/game-development/roblox-studio/roblox-avatar-creator.md +297 -0
- package/dist/vendor/marketplace/en/game-development/roblox-studio/roblox-experience-designer.md +305 -0
- package/dist/vendor/marketplace/en/game-development/roblox-studio/roblox-systems-scripter.md +325 -0
- package/dist/vendor/marketplace/en/game-development/technical-artist.md +229 -0
- package/dist/vendor/marketplace/en/game-development/unity/unity-architect.md +271 -0
- package/dist/vendor/marketplace/en/game-development/unity/unity-editor-tool-developer.md +310 -0
- package/dist/vendor/marketplace/en/game-development/unity/unity-multiplayer-engineer.md +321 -0
- package/dist/vendor/marketplace/en/game-development/unity/unity-shader-graph-artist.md +269 -0
- package/dist/vendor/marketplace/en/game-development/unreal-engine/unreal-multiplayer-architect.md +313 -0
- package/dist/vendor/marketplace/en/game-development/unreal-engine/unreal-systems-engineer.md +310 -0
- package/dist/vendor/marketplace/en/game-development/unreal-engine/unreal-technical-artist.md +256 -0
- package/dist/vendor/marketplace/en/game-development/unreal-engine/unreal-world-builder.md +273 -0
- package/dist/vendor/marketplace/en/integrations/mcp-memory/backend-architect-with-memory.md +247 -0
- package/dist/vendor/marketplace/en/manifest.json +1869 -0
- package/dist/vendor/marketplace/en/marketing/marketing-agentic-search-optimizer.md +311 -0
- package/dist/vendor/marketplace/en/marketing/marketing-ai-citation-strategist.md +170 -0
- package/dist/vendor/marketplace/en/marketing/marketing-app-store-optimizer.md +321 -0
- package/dist/vendor/marketplace/en/marketing/marketing-baidu-seo-specialist.md +226 -0
- package/dist/vendor/marketplace/en/marketing/marketing-bilibili-content-strategist.md +199 -0
- package/dist/vendor/marketplace/en/marketing/marketing-book-co-author.md +110 -0
- package/dist/vendor/marketplace/en/marketing/marketing-carousel-growth-engine.md +199 -0
- package/dist/vendor/marketplace/en/marketing/marketing-china-ecommerce-operator.md +283 -0
- package/dist/vendor/marketplace/en/marketing/marketing-china-market-localization-strategist.md +283 -0
- package/dist/vendor/marketplace/en/marketing/marketing-content-creator.md +54 -0
- package/dist/vendor/marketplace/en/marketing/marketing-cross-border-ecommerce.md +259 -0
- package/dist/vendor/marketplace/en/marketing/marketing-douyin-strategist.md +149 -0
- package/dist/vendor/marketplace/en/marketing/marketing-growth-hacker.md +54 -0
- package/dist/vendor/marketplace/en/marketing/marketing-instagram-curator.md +113 -0
- package/dist/vendor/marketplace/en/marketing/marketing-kuaishou-strategist.md +223 -0
- package/dist/vendor/marketplace/en/marketing/marketing-linkedin-content-creator.md +214 -0
- package/dist/vendor/marketplace/en/marketing/marketing-livestream-commerce-coach.md +305 -0
- package/dist/vendor/marketplace/en/marketing/marketing-podcast-strategist.md +277 -0
- package/dist/vendor/marketplace/en/marketing/marketing-private-domain-operator.md +308 -0
- package/dist/vendor/marketplace/en/marketing/marketing-reddit-community-builder.md +123 -0
- package/dist/vendor/marketplace/en/marketing/marketing-seo-specialist.md +321 -0
- package/dist/vendor/marketplace/en/marketing/marketing-short-video-editing-coach.md +412 -0
- package/dist/vendor/marketplace/en/marketing/marketing-social-media-strategist.md +125 -0
- package/dist/vendor/marketplace/en/marketing/marketing-tiktok-strategist.md +125 -0
- package/dist/vendor/marketplace/en/marketing/marketing-twitter-engager.md +126 -0
- package/dist/vendor/marketplace/en/marketing/marketing-video-optimization-specialist.md +119 -0
- package/dist/vendor/marketplace/en/marketing/marketing-wechat-official-account.md +145 -0
- package/dist/vendor/marketplace/en/marketing/marketing-weibo-strategist.md +240 -0
- package/dist/vendor/marketplace/en/marketing/marketing-xiaohongshu-specialist.md +138 -0
- package/dist/vendor/marketplace/en/marketing/marketing-zhihu-strategist.md +162 -0
- package/dist/vendor/marketplace/en/paid-media/paid-media-auditor.md +71 -0
- package/dist/vendor/marketplace/en/paid-media/paid-media-creative-strategist.md +71 -0
- package/dist/vendor/marketplace/en/paid-media/paid-media-paid-social-strategist.md +71 -0
- package/dist/vendor/marketplace/en/paid-media/paid-media-ppc-strategist.md +71 -0
- package/dist/vendor/marketplace/en/paid-media/paid-media-programmatic-buyer.md +71 -0
- package/dist/vendor/marketplace/en/paid-media/paid-media-search-query-analyst.md +71 -0
- package/dist/vendor/marketplace/en/paid-media/paid-media-tracking-specialist.md +71 -0
- package/dist/vendor/marketplace/en/product/product-behavioral-nudge-engine.md +80 -0
- package/dist/vendor/marketplace/en/product/product-feedback-synthesizer.md +119 -0
- package/dist/vendor/marketplace/en/product/product-manager.md +469 -0
- package/dist/vendor/marketplace/en/product/product-sprint-prioritizer.md +154 -0
- package/dist/vendor/marketplace/en/product/product-trend-researcher.md +159 -0
- package/dist/vendor/marketplace/en/project-management/project-management-experiment-tracker.md +198 -0
- package/dist/vendor/marketplace/en/project-management/project-management-jira-workflow-steward.md +230 -0
- package/dist/vendor/marketplace/en/project-management/project-management-project-shepherd.md +194 -0
- package/dist/vendor/marketplace/en/project-management/project-management-studio-operations.md +200 -0
- package/dist/vendor/marketplace/en/project-management/project-management-studio-producer.md +203 -0
- package/dist/vendor/marketplace/en/project-management/project-manager-senior.md +135 -0
- package/dist/vendor/marketplace/en/sales/sales-account-strategist.md +227 -0
- package/dist/vendor/marketplace/en/sales/sales-coach.md +271 -0
- package/dist/vendor/marketplace/en/sales/sales-deal-strategist.md +180 -0
- package/dist/vendor/marketplace/en/sales/sales-discovery-coach.md +225 -0
- package/dist/vendor/marketplace/en/sales/sales-engineer.md +182 -0
- package/dist/vendor/marketplace/en/sales/sales-outbound-strategist.md +201 -0
- package/dist/vendor/marketplace/en/sales/sales-pipeline-analyst.md +267 -0
- package/dist/vendor/marketplace/en/sales/sales-proposal-strategist.md +217 -0
- package/dist/vendor/marketplace/en/spatial-computing/macos-spatial-metal-engineer.md +337 -0
- package/dist/vendor/marketplace/en/spatial-computing/terminal-integration-specialist.md +70 -0
- package/dist/vendor/marketplace/en/spatial-computing/visionos-spatial-engineer.md +54 -0
- package/dist/vendor/marketplace/en/spatial-computing/xr-cockpit-interaction-specialist.md +32 -0
- package/dist/vendor/marketplace/en/spatial-computing/xr-immersive-developer.md +32 -0
- package/dist/vendor/marketplace/en/spatial-computing/xr-interface-architect.md +32 -0
- package/dist/vendor/marketplace/en/specialized/accounts-payable-agent.md +185 -0
- package/dist/vendor/marketplace/en/specialized/agentic-identity-trust.md +387 -0
- package/dist/vendor/marketplace/en/specialized/agents-orchestrator.md +367 -0
- package/dist/vendor/marketplace/en/specialized/automation-governance-architect.md +216 -0
- package/dist/vendor/marketplace/en/specialized/blockchain-security-auditor.md +463 -0
- package/dist/vendor/marketplace/en/specialized/compliance-auditor.md +158 -0
- package/dist/vendor/marketplace/en/specialized/corporate-training-designer.md +192 -0
- package/dist/vendor/marketplace/en/specialized/customer-service.md +398 -0
- package/dist/vendor/marketplace/en/specialized/data-consolidation-agent.md +60 -0
- package/dist/vendor/marketplace/en/specialized/government-digital-presales-consultant.md +363 -0
- package/dist/vendor/marketplace/en/specialized/healthcare-customer-service.md +389 -0
- package/dist/vendor/marketplace/en/specialized/healthcare-marketing-compliance.md +395 -0
- package/dist/vendor/marketplace/en/specialized/hospitality-guest-services.md +603 -0
- package/dist/vendor/marketplace/en/specialized/hr-onboarding.md +451 -0
- package/dist/vendor/marketplace/en/specialized/identity-graph-operator.md +260 -0
- package/dist/vendor/marketplace/en/specialized/language-translator.md +264 -0
- package/dist/vendor/marketplace/en/specialized/legal-billing-time-tracking.md +569 -0
- package/dist/vendor/marketplace/en/specialized/legal-client-intake.md +492 -0
- package/dist/vendor/marketplace/en/specialized/legal-document-review.md +454 -0
- package/dist/vendor/marketplace/en/specialized/loan-officer-assistant.md +555 -0
- package/dist/vendor/marketplace/en/specialized/lsp-index-engineer.md +314 -0
- package/dist/vendor/marketplace/en/specialized/real-estate-buyer-seller.md +596 -0
- package/dist/vendor/marketplace/en/specialized/recruitment-specialist.md +509 -0
- package/dist/vendor/marketplace/en/specialized/report-distribution-agent.md +65 -0
- package/dist/vendor/marketplace/en/specialized/retail-customer-returns.md +566 -0
- package/dist/vendor/marketplace/en/specialized/sales-data-extraction-agent.md +67 -0
- package/dist/vendor/marketplace/en/specialized/sales-outreach.md +425 -0
- package/dist/vendor/marketplace/en/specialized/specialized-chief-of-staff.md +279 -0
- package/dist/vendor/marketplace/en/specialized/specialized-civil-engineer.md +356 -0
- package/dist/vendor/marketplace/en/specialized/specialized-cultural-intelligence-strategist.md +88 -0
- package/dist/vendor/marketplace/en/specialized/specialized-developer-advocate.md +317 -0
- package/dist/vendor/marketplace/en/specialized/specialized-document-generator.md +55 -0
- package/dist/vendor/marketplace/en/specialized/specialized-french-consulting-market.md +192 -0
- package/dist/vendor/marketplace/en/specialized/specialized-korean-business-navigator.md +216 -0
- package/dist/vendor/marketplace/en/specialized/specialized-mcp-builder.md +248 -0
- package/dist/vendor/marketplace/en/specialized/specialized-model-qa.md +488 -0
- package/dist/vendor/marketplace/en/specialized/specialized-salesforce-architect.md +180 -0
- package/dist/vendor/marketplace/en/specialized/specialized-workflow-architect.md +597 -0
- package/dist/vendor/marketplace/en/specialized/study-abroad-advisor.md +282 -0
- package/dist/vendor/marketplace/en/specialized/supply-chain-strategist.md +582 -0
- package/dist/vendor/marketplace/en/support/support-analytics-reporter.md +365 -0
- package/dist/vendor/marketplace/en/support/support-executive-summary-generator.md +212 -0
- package/dist/vendor/marketplace/en/support/support-finance-tracker.md +442 -0
- package/dist/vendor/marketplace/en/support/support-infrastructure-maintainer.md +618 -0
- package/dist/vendor/marketplace/en/support/support-legal-compliance-checker.md +588 -0
- package/dist/vendor/marketplace/en/support/support-support-responder.md +585 -0
- package/dist/vendor/marketplace/en/testing/testing-accessibility-auditor.md +316 -0
- package/dist/vendor/marketplace/en/testing/testing-api-tester.md +306 -0
- package/dist/vendor/marketplace/en/testing/testing-evidence-collector.md +210 -0
- package/dist/vendor/marketplace/en/testing/testing-performance-benchmarker.md +268 -0
- package/dist/vendor/marketplace/en/testing/testing-reality-checker.md +236 -0
- package/dist/vendor/marketplace/en/testing/testing-test-results-analyzer.md +305 -0
- package/dist/vendor/marketplace/en/testing/testing-tool-evaluator.md +394 -0
- package/dist/vendor/marketplace/en/testing/testing-workflow-optimizer.md +450 -0
- package/dist/vendor/marketplace/zh/LICENSE +22 -0
- package/dist/vendor/marketplace/zh/SOURCES.md +12 -0
- package/dist/vendor/marketplace/zh/academic/academic-anthropologist.md +124 -0
- package/dist/vendor/marketplace/zh/academic/academic-geographer.md +126 -0
- package/dist/vendor/marketplace/zh/academic/academic-historian.md +122 -0
- package/dist/vendor/marketplace/zh/academic/academic-narratologist.md +117 -0
- package/dist/vendor/marketplace/zh/academic/academic-psychologist.md +117 -0
- package/dist/vendor/marketplace/zh/academic/academic-study-planner.md +214 -0
- package/dist/vendor/marketplace/zh/design/design-brand-guardian.md +321 -0
- package/dist/vendor/marketplace/zh/design/design-image-prompt-engineer.md +255 -0
- package/dist/vendor/marketplace/zh/design/design-inclusive-visuals-specialist.md +177 -0
- package/dist/vendor/marketplace/zh/design/design-ui-designer.md +382 -0
- package/dist/vendor/marketplace/zh/design/design-ux-architect.md +482 -0
- package/dist/vendor/marketplace/zh/design/design-ux-researcher.md +328 -0
- package/dist/vendor/marketplace/zh/design/design-visual-storyteller.md +159 -0
- package/dist/vendor/marketplace/zh/design/design-whimsy-injector.md +453 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-ai-data-remediation-engineer.md +209 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-ai-engineer.md +161 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-autonomous-optimization-architect.md +115 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-backend-architect.md +234 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-cms-developer.md +534 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-code-reviewer.md +172 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-codebase-onboarding-engineer.md +172 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-data-engineer.md +324 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-database-optimizer.md +175 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-devops-automator.md +375 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-dingtalk-integration-developer.md +574 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-email-intelligence-engineer.md +349 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-embedded-firmware-engineer.md +168 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-embedded-linux-driver-engineer.md +255 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-feishu-integration-developer.md +597 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-filament-optimization-specialist.md +283 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-fpga-digital-design-engineer.md +227 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-frontend-developer.md +224 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-git-workflow-master.md +220 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-incident-response-commander.md +465 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-iot-solution-architect.md +220 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-mechanical-design-engineer.md +311 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-minimal-change-engineer.md +206 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-mobile-app-builder.md +434 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-pc-host-engineer.md +231 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-rapid-prototyper.md +461 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-security-engineer.md +303 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-senior-developer.md +177 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-software-architect.md +200 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-solidity-smart-contract-engineer.md +541 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-sre.md +233 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-technical-writer.md +409 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-threat-detection-engineer.md +553 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-voice-ai-integration-engineer.md +560 -0
- package/dist/vendor/marketplace/zh/engineering/engineering-wechat-mini-program-developer.md +288 -0
- package/dist/vendor/marketplace/zh/finance/finance-bookkeeper-controller.md +271 -0
- package/dist/vendor/marketplace/zh/finance/finance-financial-analyst.md +244 -0
- package/dist/vendor/marketplace/zh/finance/finance-financial-forecaster.md +213 -0
- package/dist/vendor/marketplace/zh/finance/finance-fpa-analyst.md +272 -0
- package/dist/vendor/marketplace/zh/finance/finance-fraud-detector.md +241 -0
- package/dist/vendor/marketplace/zh/finance/finance-investment-researcher.md +283 -0
- package/dist/vendor/marketplace/zh/finance/finance-invoice-manager.md +242 -0
- package/dist/vendor/marketplace/zh/finance/finance-tax-strategist.md +250 -0
- package/dist/vendor/marketplace/zh/game-development/blender/blender-addon-engineer.md +233 -0
- package/dist/vendor/marketplace/zh/game-development/game-audio-engineer.md +265 -0
- package/dist/vendor/marketplace/zh/game-development/game-designer.md +168 -0
- package/dist/vendor/marketplace/zh/game-development/godot/godot-gameplay-scripter.md +335 -0
- package/dist/vendor/marketplace/zh/game-development/godot/godot-multiplayer-engineer.md +296 -0
- package/dist/vendor/marketplace/zh/game-development/godot/godot-shader-developer.md +267 -0
- package/dist/vendor/marketplace/zh/game-development/level-designer.md +209 -0
- package/dist/vendor/marketplace/zh/game-development/narrative-designer.md +244 -0
- package/dist/vendor/marketplace/zh/game-development/roblox-studio/roblox-avatar-creator.md +298 -0
- package/dist/vendor/marketplace/zh/game-development/roblox-studio/roblox-experience-designer.md +306 -0
- package/dist/vendor/marketplace/zh/game-development/roblox-studio/roblox-systems-scripter.md +325 -0
- package/dist/vendor/marketplace/zh/game-development/technical-artist.md +230 -0
- package/dist/vendor/marketplace/zh/game-development/unity/unity-architect.md +272 -0
- package/dist/vendor/marketplace/zh/game-development/unity/unity-editor-tool-developer.md +300 -0
- package/dist/vendor/marketplace/zh/game-development/unity/unity-multiplayer-engineer.md +238 -0
- package/dist/vendor/marketplace/zh/game-development/unity/unity-shader-graph-artist.md +270 -0
- package/dist/vendor/marketplace/zh/game-development/unreal-engine/unreal-multiplayer-architect.md +314 -0
- package/dist/vendor/marketplace/zh/game-development/unreal-engine/unreal-systems-engineer.md +311 -0
- package/dist/vendor/marketplace/zh/game-development/unreal-engine/unreal-technical-artist.md +256 -0
- package/dist/vendor/marketplace/zh/game-development/unreal-engine/unreal-world-builder.md +274 -0
- package/dist/vendor/marketplace/zh/hr/hr-performance-reviewer.md +248 -0
- package/dist/vendor/marketplace/zh/hr/hr-recruiter.md +232 -0
- package/dist/vendor/marketplace/zh/legal/legal-contract-reviewer.md +240 -0
- package/dist/vendor/marketplace/zh/legal/legal-policy-writer.md +308 -0
- package/dist/vendor/marketplace/zh/manifest.json +2181 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-agentic-search-optimizer.md +312 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-ai-citation-strategist.md +169 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-app-store-optimizer.md +319 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-baidu-seo-specialist.md +220 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-bilibili-strategist.md +194 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-book-co-author.md +109 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-carousel-growth-engine.md +215 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-china-ecommerce-operator.md +277 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-china-market-localization-strategist.md +282 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-content-creator.md +145 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-cross-border-ecommerce.md +260 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-daily-news-briefing.md +303 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-douyin-strategist.md +150 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-ecommerce-operator.md +216 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-growth-hacker.md +121 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-instagram-curator.md +179 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-knowledge-commerce-strategist.md +384 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-kuaishou-strategist.md +182 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-linkedin-content-creator.md +232 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-livestream-commerce-coach.md +303 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-podcast-strategist.md +278 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-private-domain-operator.md +309 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-reddit-community-builder.md +127 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-seo-specialist.md +298 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-short-video-editing-coach.md +413 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-social-media-strategist.md +118 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-tiktok-strategist.md +124 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-twitter-engager.md +132 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-video-optimization-specialist.md +128 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-wechat-official-account.md +158 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-wechat-operator.md +156 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-weibo-strategist.md +241 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-weixin-channels-strategist.md +297 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-xiaohongshu-operator.md +139 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-xiaohongshu-specialist.md +151 -0
- package/dist/vendor/marketplace/zh/marketing/marketing-zhihu-strategist.md +175 -0
- package/dist/vendor/marketplace/zh/paid-media/paid-media-auditor.md +170 -0
- package/dist/vendor/marketplace/zh/paid-media/paid-media-creative-strategist.md +173 -0
- package/dist/vendor/marketplace/zh/paid-media/paid-media-paid-social-strategist.md +180 -0
- package/dist/vendor/marketplace/zh/paid-media/paid-media-ppc-strategist.md +180 -0
- package/dist/vendor/marketplace/zh/paid-media/paid-media-programmatic-buyer.md +177 -0
- package/dist/vendor/marketplace/zh/paid-media/paid-media-search-query-analyst.md +182 -0
- package/dist/vendor/marketplace/zh/paid-media/paid-media-tracking-specialist.md +199 -0
- package/dist/vendor/marketplace/zh/product/product-behavioral-nudge-engine.md +246 -0
- package/dist/vendor/marketplace/zh/product/product-feedback-synthesizer.md +175 -0
- package/dist/vendor/marketplace/zh/product/product-manager.md +474 -0
- package/dist/vendor/marketplace/zh/product/product-sprint-prioritizer.md +133 -0
- package/dist/vendor/marketplace/zh/product/product-trend-researcher.md +143 -0
- package/dist/vendor/marketplace/zh/project-management/project-management-experiment-tracker.md +206 -0
- package/dist/vendor/marketplace/zh/project-management/project-management-jira-workflow-steward.md +249 -0
- package/dist/vendor/marketplace/zh/project-management/project-management-project-shepherd.md +202 -0
- package/dist/vendor/marketplace/zh/project-management/project-management-studio-operations.md +208 -0
- package/dist/vendor/marketplace/zh/project-management/project-management-studio-producer.md +211 -0
- package/dist/vendor/marketplace/zh/project-management/project-manager-senior.md +135 -0
- package/dist/vendor/marketplace/zh/sales/sales-account-strategist.md +243 -0
- package/dist/vendor/marketplace/zh/sales/sales-coach.md +291 -0
- package/dist/vendor/marketplace/zh/sales/sales-deal-strategist.md +204 -0
- package/dist/vendor/marketplace/zh/sales/sales-discovery-coach.md +230 -0
- package/dist/vendor/marketplace/zh/sales/sales-engineer.md +200 -0
- package/dist/vendor/marketplace/zh/sales/sales-outbound-strategist.md +208 -0
- package/dist/vendor/marketplace/zh/sales/sales-pipeline-analyst.md +284 -0
- package/dist/vendor/marketplace/zh/sales/sales-proposal-strategist.md +233 -0
- package/dist/vendor/marketplace/zh/spatial-computing/macos-spatial-metal-engineer.md +337 -0
- package/dist/vendor/marketplace/zh/spatial-computing/terminal-integration-specialist.md +236 -0
- package/dist/vendor/marketplace/zh/spatial-computing/visionos-spatial-engineer.md +282 -0
- package/dist/vendor/marketplace/zh/spatial-computing/xr-cockpit-interaction-specialist.md +220 -0
- package/dist/vendor/marketplace/zh/spatial-computing/xr-immersive-developer.md +229 -0
- package/dist/vendor/marketplace/zh/spatial-computing/xr-interface-architect.md +253 -0
- package/dist/vendor/marketplace/zh/specialized/accounts-payable-agent.md +212 -0
- package/dist/vendor/marketplace/zh/specialized/agentic-identity-trust.md +388 -0
- package/dist/vendor/marketplace/zh/specialized/agents-orchestrator.md +366 -0
- package/dist/vendor/marketplace/zh/specialized/automation-governance-architect.md +215 -0
- package/dist/vendor/marketplace/zh/specialized/blockchain-security-auditor.md +484 -0
- package/dist/vendor/marketplace/zh/specialized/compliance-auditor.md +172 -0
- package/dist/vendor/marketplace/zh/specialized/corporate-training-designer.md +191 -0
- package/dist/vendor/marketplace/zh/specialized/data-consolidation-agent.md +327 -0
- package/dist/vendor/marketplace/zh/specialized/gaokao-college-advisor.md +333 -0
- package/dist/vendor/marketplace/zh/specialized/government-digital-presales-consultant.md +362 -0
- package/dist/vendor/marketplace/zh/specialized/healthcare-customer-service.md +388 -0
- package/dist/vendor/marketplace/zh/specialized/healthcare-marketing-compliance.md +394 -0
- package/dist/vendor/marketplace/zh/specialized/hospitality-guest-services.md +597 -0
- package/dist/vendor/marketplace/zh/specialized/hr-onboarding.md +450 -0
- package/dist/vendor/marketplace/zh/specialized/identity-graph-operator.md +270 -0
- package/dist/vendor/marketplace/zh/specialized/language-translator.md +275 -0
- package/dist/vendor/marketplace/zh/specialized/legal-billing-time-tracking.md +566 -0
- package/dist/vendor/marketplace/zh/specialized/legal-client-intake.md +487 -0
- package/dist/vendor/marketplace/zh/specialized/legal-document-review.md +452 -0
- package/dist/vendor/marketplace/zh/specialized/livestock-archive-auditor.md +135 -0
- package/dist/vendor/marketplace/zh/specialized/loan-officer-assistant.md +549 -0
- package/dist/vendor/marketplace/zh/specialized/lsp-index-engineer.md +334 -0
- package/dist/vendor/marketplace/zh/specialized/prompt-engineer.md +176 -0
- package/dist/vendor/marketplace/zh/specialized/real-estate-buyer-seller.md +594 -0
- package/dist/vendor/marketplace/zh/specialized/recruitment-specialist.md +508 -0
- package/dist/vendor/marketplace/zh/specialized/report-distribution-agent.md +354 -0
- package/dist/vendor/marketplace/zh/specialized/retail-customer-returns.md +564 -0
- package/dist/vendor/marketplace/zh/specialized/sales-data-extraction-agent.md +159 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-ai-policy-writer.md +217 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-chief-of-staff.md +278 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-civil-engineer.md +355 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-cultural-intelligence-strategist.md +168 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-developer-advocate.md +334 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-document-generator.md +346 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-french-consulting-market.md +191 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-korean-business-navigator.md +215 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-mcp-builder.md +351 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-meeting-assistant.md +236 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-model-qa.md +507 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-pricing-optimizer.md +254 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-risk-assessor.md +240 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-salesforce-architect.md +179 -0
- package/dist/vendor/marketplace/zh/specialized/specialized-workflow-architect.md +596 -0
- package/dist/vendor/marketplace/zh/specialized/study-abroad-advisor.md +281 -0
- package/dist/vendor/marketplace/zh/specialized/technical-translator-agent.md +167 -0
- package/dist/vendor/marketplace/zh/specialized/zk-steward.md +228 -0
- package/dist/vendor/marketplace/zh/supply-chain/supply-chain-inventory-forecaster.md +212 -0
- package/dist/vendor/marketplace/zh/supply-chain/supply-chain-route-optimizer.md +224 -0
- package/dist/vendor/marketplace/zh/supply-chain/supply-chain-strategist.md +581 -0
- package/dist/vendor/marketplace/zh/supply-chain/supply-chain-vendor-evaluator.md +232 -0
- package/dist/vendor/marketplace/zh/support/support-analytics-reporter.md +364 -0
- package/dist/vendor/marketplace/zh/support/support-executive-summary-generator.md +217 -0
- package/dist/vendor/marketplace/zh/support/support-finance-tracker.md +447 -0
- package/dist/vendor/marketplace/zh/support/support-infrastructure-maintainer.md +623 -0
- package/dist/vendor/marketplace/zh/support/support-legal-compliance-checker.md +587 -0
- package/dist/vendor/marketplace/zh/support/support-recruitment-specialist.md +508 -0
- package/dist/vendor/marketplace/zh/support/support-support-responder.md +584 -0
- package/dist/vendor/marketplace/zh/testing/testing-accessibility-auditor.md +329 -0
- package/dist/vendor/marketplace/zh/testing/testing-api-tester.md +305 -0
- package/dist/vendor/marketplace/zh/testing/testing-embedded-qa-engineer.md +258 -0
- package/dist/vendor/marketplace/zh/testing/testing-evidence-collector.md +153 -0
- package/dist/vendor/marketplace/zh/testing/testing-performance-benchmarker.md +196 -0
- package/dist/vendor/marketplace/zh/testing/testing-reality-checker.md +235 -0
- package/dist/vendor/marketplace/zh/testing/testing-test-results-analyzer.md +313 -0
- package/dist/vendor/marketplace/zh/testing/testing-tool-evaluator.md +402 -0
- package/dist/vendor/marketplace/zh/testing/testing-workflow-optimizer.md +458 -0
- package/package.json +131 -0
- package/scripts/postinstall-native-artifacts.mjs +113 -0
- package/web/dist/assets/AddWorkerDialog-BU2Fn-Mx.js +2 -0
- package/web/dist/assets/AddWorkspaceFlow-BV04MkRt.js +1 -0
- package/web/dist/assets/FirstRunWizard-DS4IYOrd.js +1 -0
- package/web/dist/assets/MarketplaceDrawer-CIQ2B6Fx.js +76 -0
- package/web/dist/assets/TaskGraphDrawer-BPMcRocd.js +1 -0
- package/web/dist/assets/WhatsNewDialog-DEgVY_LD.js +1 -0
- package/web/dist/assets/WorkerModal-DiCcTPpc.js +1 -0
- package/web/dist/assets/WorkflowsDrawer-M2CgAJWK.js +1 -0
- package/web/dist/assets/WorkspaceMemoryDrawer-ClJIqWck.js +1 -0
- package/web/dist/assets/WorkspaceTaskDrawer-gjvXuZ2K.js +1 -0
- package/web/dist/assets/addon-clipboard-wHJhZAA4.js +1 -0
- package/web/dist/assets/addon-fit-DX4qG4td.js +1 -0
- package/web/dist/assets/addon-unicode11-Bt8F3D7-.js +7 -0
- package/web/dist/assets/addon-web-links-DIbG5aQx.js +1 -0
- package/web/dist/assets/addon-webgl-DCtw1yLn.js +64 -0
- package/web/dist/assets/finder-C4Jmsb0B.png +0 -0
- package/web/dist/assets/ghostty-D-Js4rdm.png +0 -0
- package/web/dist/assets/index-bOMtwrkA.js +73 -0
- package/web/dist/assets/index-i9YgsMdD.css +1 -0
- package/web/dist/assets/path-join-7MR1s7b1.js +1 -0
- package/web/dist/assets/search-CmzeVhy0.js +1 -0
- package/web/dist/assets/xterm-B-qIQCd3.js +16 -0
- package/web/dist/assets/zed-C5BQT8X3.png +0 -0
- package/web/dist/bilibili.ico +0 -0
- package/web/dist/cli-icons/claude.png +0 -0
- package/web/dist/cli-icons/codex.png +0 -0
- package/web/dist/cli-icons/gemini.png +0 -0
- package/web/dist/cli-icons/hermes.png +0 -0
- package/web/dist/cli-icons/opencode.svg +18 -0
- package/web/dist/icons/apple-touch-icon-180.png +0 -0
- package/web/dist/icons/icon-192.png +0 -0
- package/web/dist/icons/icon-32.png +0 -0
- package/web/dist/icons/icon-512-maskable.png +0 -0
- package/web/dist/icons/icon-512.png +0 -0
- package/web/dist/index.html +39 -0
- package/web/dist/logo.png +0 -0
- package/web/dist/manifest.webmanifest +60 -0
- package/web/dist/screenshots/wide-overview.png +0 -0
- package/web/dist/sounds/LICENSE-KENNEY.txt +22 -0
- package/web/dist/sounds/hive-beacon.ogg +0 -0
- package/web/dist/sounds/hive-cascade.ogg +0 -0
- package/web/dist/sounds/hive-chime.ogg +0 -0
- package/web/dist/sounds/hive-ping.ogg +0 -0
- package/web/dist/sounds/hive-resolve.ogg +0 -0
- package/web/dist/sounds/hive-soft.ogg +0 -0
- package/web/dist/sw.js +99 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface PostPairConfirmDeps {
|
|
2
|
+
gatewayUrl: string;
|
|
3
|
+
daemonToken: string;
|
|
4
|
+
/** Inject a fetch for tests; defaults to the global fetch. */
|
|
5
|
+
fetchImpl?: typeof fetch;
|
|
6
|
+
}
|
|
7
|
+
export interface PairConfirmBody {
|
|
8
|
+
deviceId: string;
|
|
9
|
+
/** The device's X25519 public key, base64url — opaque to the gateway. */
|
|
10
|
+
devicePubkey: string;
|
|
11
|
+
name: string;
|
|
12
|
+
boundJti: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const postPairConfirm: (deps: PostPairConfirmDeps, body: PairConfirmBody) => Promise<void>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Daemon → gateway HTTP client (plan D5). The pairing data-plane rides the wss
|
|
2
|
+
// tunnel, but the device-row creation is a separate, daemon-token-authed HTTPS
|
|
3
|
+
// call: only a real daemon (post-desktop-confirm) may create the gateway's device
|
|
4
|
+
// row, which is what later lets the phone's /pair/session mint a device-bound
|
|
5
|
+
// cookie. A phone has no daemon token, so it can never self-promote.
|
|
6
|
+
//
|
|
7
|
+
// Wire contract mirrors gateway/src/pair.ts POST /pair/confirm and the shape the
|
|
8
|
+
// gateway tests exercise (gateway/test/pairing-relay.test.ts postConfirm):
|
|
9
|
+
// POST ${gatewayUrl}/pair/confirm
|
|
10
|
+
// Authorization: Bearer <daemonToken>
|
|
11
|
+
// { deviceId, devicePubkey, name, boundJti } (devicePubkey is base64url)
|
|
12
|
+
// The gateway 200s on create-or-idempotent; any non-2xx is a hard failure here so
|
|
13
|
+
// the confirm path can refuse to tell the phone "confirmed" (see remote-pairing).
|
|
14
|
+
//
|
|
15
|
+
// trimSlash + the header/body shape deliberately match src/cli/hive-remote.ts so
|
|
16
|
+
// the daemon and CLI speak the gateway identically.
|
|
17
|
+
const trimSlash = (url) => url.replace(/\/+$/, '');
|
|
18
|
+
export const postPairConfirm = async (deps, body) => {
|
|
19
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
20
|
+
const res = await fetchImpl(`${trimSlash(deps.gatewayUrl)}/pair/confirm`, {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: {
|
|
23
|
+
'content-type': 'application/json',
|
|
24
|
+
authorization: `Bearer ${deps.daemonToken}`,
|
|
25
|
+
},
|
|
26
|
+
body: JSON.stringify({
|
|
27
|
+
deviceId: body.deviceId,
|
|
28
|
+
devicePubkey: body.devicePubkey,
|
|
29
|
+
name: body.name,
|
|
30
|
+
boundJti: body.boundJti,
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
throw new Error(`gateway /pair/confirm failed: ${res.status}`);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const HIVE_REMOTE_SECRET_HEADER = "x-hive-remote-secret";
|
|
2
|
+
export declare const HIVE_REMOTE_DEVICE_HEADER = "x-hive-remote-device";
|
|
3
|
+
export declare function isTunnelDroppedRequestHeader(name: string): boolean;
|
|
4
|
+
export declare function stampLoopbackHeaders(headers: Array<[string, string]> | Record<string, string>, secret: string, deviceId: string): Record<string, string>;
|
|
5
|
+
export declare function isTunnelStrippedResponseHeader(name: string): boolean;
|
|
6
|
+
export declare function sanitizeTunnelResponseHeaders(headers: Array<[string, string]>): Array<[string, string]>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Per-boot internal-secret header plumbing for the loopback bridge (invariant 2).
|
|
2
|
+
//
|
|
3
|
+
// The secret VALUE lives in UiAuth (the single token authority) — it is
|
|
4
|
+
// generated at boot, held only in-process, NEVER persisted, NEVER logged. This
|
|
5
|
+
// file holds only the wire-header names and the request/response header
|
|
6
|
+
// helpers the bridge uses. A 127.0.0.1 request carrying the live secret is
|
|
7
|
+
// authorized as tunnel-originated; absent/forged secret => normal UI-token
|
|
8
|
+
// treatment (rejected). This is the ONLY escalation to tunnel authority, and it
|
|
9
|
+
// is unforgeable from outside the runtime process.
|
|
10
|
+
// Tunnel-originated loopback requests carry these. They are also audit-tagging:
|
|
11
|
+
// x-hive-remote-device identifies the paired device for the audit trail. Both
|
|
12
|
+
// are stripped from any client-supplied copy before we stamp our own, so a
|
|
13
|
+
// phone can neither spoof the device tag nor smuggle a guessed secret.
|
|
14
|
+
export const HIVE_REMOTE_SECRET_HEADER = 'x-hive-remote-secret';
|
|
15
|
+
export const HIVE_REMOTE_DEVICE_HEADER = 'x-hive-remote-device';
|
|
16
|
+
// VULN-LOOPBACK-1: the request side needs the same posture as the response side. The phone fully
|
|
17
|
+
// controls the Open meta header list, and Node's http client copies any header we hand it verbatim
|
|
18
|
+
// (it only synthesises Host when none is present). A strip-2 blocklist let a phone smuggle
|
|
19
|
+
// Host/Origin/Cookie/X-Forwarded-*/Content-Length/Transfer-Encoding onto the 127.0.0.1 request,
|
|
20
|
+
// contradicting this file's "a phone can neither spoof nor smuggle" invariant. So we DROP every
|
|
21
|
+
// header that doesn't belong on a tunnel-originated loopback request and only let through the few
|
|
22
|
+
// the local runtime actually reads.
|
|
23
|
+
//
|
|
24
|
+
// Dropped, by reason:
|
|
25
|
+
// - the 2 tunnel headers (always — we re-stamp our own copy last so it wins)
|
|
26
|
+
// - host / origin — would defeat the daemon's fail-closed local-request guard (self-DoS) and have
|
|
27
|
+
// no business being phone-controlled
|
|
28
|
+
// - cookie — the phone never holds hive_ui_token; a guessed cookie is inert but doesn't belong here
|
|
29
|
+
// - content-length / transfer-encoding — the bridge frames the body itself; a phone-declared length
|
|
30
|
+
// is a request-smuggling primitive
|
|
31
|
+
// - all hop-by-hop headers (meaningless across the mux boundary)
|
|
32
|
+
// - any x-forwarded-* (the daemon is the origin; a forged forwarded chain is never trusted)
|
|
33
|
+
const REQUEST_HOP_BY_HOP_HEADERS = new Set([
|
|
34
|
+
'connection',
|
|
35
|
+
'keep-alive',
|
|
36
|
+
'proxy-authenticate',
|
|
37
|
+
'proxy-authorization',
|
|
38
|
+
'te',
|
|
39
|
+
'trailer',
|
|
40
|
+
'transfer-encoding',
|
|
41
|
+
'upgrade',
|
|
42
|
+
]);
|
|
43
|
+
const REQUEST_DROPPED_HEADERS = new Set([
|
|
44
|
+
'host',
|
|
45
|
+
'origin',
|
|
46
|
+
'cookie',
|
|
47
|
+
'content-length',
|
|
48
|
+
HIVE_REMOTE_SECRET_HEADER,
|
|
49
|
+
HIVE_REMOTE_DEVICE_HEADER,
|
|
50
|
+
]);
|
|
51
|
+
export function isTunnelDroppedRequestHeader(name) {
|
|
52
|
+
const lk = name.toLowerCase();
|
|
53
|
+
if (REQUEST_DROPPED_HEADERS.has(lk))
|
|
54
|
+
return true;
|
|
55
|
+
if (REQUEST_HOP_BY_HOP_HEADERS.has(lk))
|
|
56
|
+
return true;
|
|
57
|
+
if (lk.startsWith('x-forwarded-'))
|
|
58
|
+
return true;
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
// Stamp the loopback request/upgrade headers for a tunnel-originated request:
|
|
62
|
+
// drop every smuggling-prone / tunnel-only header (isTunnelDroppedRequestHeader), then set ours.
|
|
63
|
+
// Accepts the M1 header list ([name, value] pairs, which keep order + duplicates) or a plain record
|
|
64
|
+
// — the bridge passes meta.http.headers (a list) directly.
|
|
65
|
+
export function stampLoopbackHeaders(headers, secret, deviceId) {
|
|
66
|
+
const entries = Array.isArray(headers) ? headers : Object.entries(headers);
|
|
67
|
+
const out = {};
|
|
68
|
+
for (const [k, v] of entries) {
|
|
69
|
+
if (isTunnelDroppedRequestHeader(k))
|
|
70
|
+
continue;
|
|
71
|
+
out[k] = v;
|
|
72
|
+
}
|
|
73
|
+
out[HIVE_REMOTE_SECRET_HEADER] = secret;
|
|
74
|
+
out[HIVE_REMOTE_DEVICE_HEADER] = deviceId;
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
// HARDEN (response-header policy, invariant alongside 1/2): the bridge seals the
|
|
78
|
+
// loopback HTTP response head (status + headers) back to the phone. Some /api
|
|
79
|
+
// responses carry headers meant only for the local browser/runtime boundary —
|
|
80
|
+
// most dangerously Set-Cookie (the master hive_ui_token), but also any internal
|
|
81
|
+
// x-hive-* header now or in the future. The bridge MUST strip these before
|
|
82
|
+
// encodeHttpHead for tunnel-originated responses, so no auth/identity header
|
|
83
|
+
// ever crosses the trust boundary onto a remote device.
|
|
84
|
+
//
|
|
85
|
+
// Strips: hop-by-hop headers (meaningless across the mux boundary), Set-Cookie
|
|
86
|
+
// (any casing), and any x-hive-* internal header. Header NAMES are matched
|
|
87
|
+
// case-insensitively against the response head's [name, value] pairs.
|
|
88
|
+
const HOP_BY_HOP_HEADERS = new Set([
|
|
89
|
+
'connection',
|
|
90
|
+
'keep-alive',
|
|
91
|
+
'proxy-authenticate',
|
|
92
|
+
'proxy-authorization',
|
|
93
|
+
'te',
|
|
94
|
+
'trailer',
|
|
95
|
+
'transfer-encoding',
|
|
96
|
+
'upgrade',
|
|
97
|
+
]);
|
|
98
|
+
const AUTH_BEARING_RESPONSE_HEADERS = new Set(['set-cookie', 'set-cookie2']);
|
|
99
|
+
export function isTunnelStrippedResponseHeader(name) {
|
|
100
|
+
const lk = name.toLowerCase();
|
|
101
|
+
if (HOP_BY_HOP_HEADERS.has(lk))
|
|
102
|
+
return true;
|
|
103
|
+
if (AUTH_BEARING_RESPONSE_HEADERS.has(lk))
|
|
104
|
+
return true;
|
|
105
|
+
// Any internal x-hive-* header is daemon<->local-boundary only; never relay it.
|
|
106
|
+
if (lk.startsWith('x-hive-'))
|
|
107
|
+
return true;
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
export function sanitizeTunnelResponseHeaders(headers) {
|
|
111
|
+
return headers.filter(([name]) => !isTunnelStrippedResponseHeader(name));
|
|
112
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { PostPairConfirmDeps } from './remote-gateway-client.js';
|
|
2
|
+
import type { RemotePairing } from './remote-pairing.js';
|
|
3
|
+
export interface PairingHelloFrame {
|
|
4
|
+
t: 'hello';
|
|
5
|
+
devicePublicKey: string;
|
|
6
|
+
sessionSalt: string;
|
|
7
|
+
proposedName?: string;
|
|
8
|
+
}
|
|
9
|
+
export type PairingInboundFrame = PairingHelloFrame;
|
|
10
|
+
export interface PairAckFrame {
|
|
11
|
+
t: 'pair-ack';
|
|
12
|
+
daemonPublicKey: string;
|
|
13
|
+
daemonId: string;
|
|
14
|
+
deviceId: string;
|
|
15
|
+
protocolVersion: number;
|
|
16
|
+
}
|
|
17
|
+
export interface ConfirmedFrame {
|
|
18
|
+
t: 'confirmed';
|
|
19
|
+
deviceId: string;
|
|
20
|
+
}
|
|
21
|
+
export interface RejectedFrame {
|
|
22
|
+
t: 'rejected';
|
|
23
|
+
reason: 'expired';
|
|
24
|
+
}
|
|
25
|
+
export type PairingOutboundFrame = PairAckFrame | ConfirmedFrame | RejectedFrame;
|
|
26
|
+
export interface RemotePairingTunnelDeps {
|
|
27
|
+
pairing: RemotePairing;
|
|
28
|
+
/** Emit a JSON text frame over the live tunnel socket (the relay fans it to the pair socket). */
|
|
29
|
+
send: (frame: PairingOutboundFrame) => void;
|
|
30
|
+
/** D5 seam: POST /pair/confirm to the gateway. Injected so tests don't hit the real fetch path. */
|
|
31
|
+
postPairConfirm: (deps: PostPairConfirmDeps, body: PairConfirmArgs) => Promise<void>;
|
|
32
|
+
getGatewayUrl: () => string | null;
|
|
33
|
+
getDaemonToken: () => string | null;
|
|
34
|
+
}
|
|
35
|
+
export interface PairConfirmArgs {
|
|
36
|
+
deviceId: string;
|
|
37
|
+
devicePubkey: string;
|
|
38
|
+
name: string;
|
|
39
|
+
boundJti: string;
|
|
40
|
+
}
|
|
41
|
+
export interface RemotePairingTunnel {
|
|
42
|
+
/**
|
|
43
|
+
* The gateway told us a pair socket attached for this daemon, carrying the pairing session's jti
|
|
44
|
+
* (D2). A NEW peer-online RESETS the active pairing (D1 replace race — the relay swapped the pair
|
|
45
|
+
* socket, so any half-done handshake is now stale and must not be confirmable) and records the jti
|
|
46
|
+
* so the next hello binds to it.
|
|
47
|
+
*/
|
|
48
|
+
onPeerOnline(jti: string | undefined): void;
|
|
49
|
+
/** A TEXT frame arrived on the tunnel. Parse + route; on `hello`, run the daemon handshake half. */
|
|
50
|
+
onPairingFrame(text: string): void;
|
|
51
|
+
/**
|
|
52
|
+
* Desktop confirm (D3). Insert the local row (trust root), POST /pair/confirm, then send
|
|
53
|
+
* `confirmed`. Returns the local RemoteDeviceRecord (or null if the engine wouldn't confirm).
|
|
54
|
+
* Throws if the gateway POST fails or boundJti is missing — the route surfaces it and the phone is
|
|
55
|
+
* NOT told confirmed.
|
|
56
|
+
*/
|
|
57
|
+
confirm(pairingId: string, name?: string): Promise<ReturnType<RemotePairing['confirmPairing']>>;
|
|
58
|
+
}
|
|
59
|
+
export declare const createRemotePairingTunnel: (deps: RemotePairingTunnelDeps) => RemotePairingTunnel;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// Daemon-side pairing-over-tunnel glue (plan steps 2 + 4, decisions D1/D2/D3).
|
|
2
|
+
//
|
|
3
|
+
// Pairing rides the SAME outbound gateway socket as the data tunnel, but as JSON TEXT frames (the
|
|
4
|
+
// data plane is binary). The relay forwards them opaque between the unpaired phone's `/relay/pair`
|
|
5
|
+
// socket and this daemon's `/relay/daemon` socket. This driver is the daemon half of the wire:
|
|
6
|
+
//
|
|
7
|
+
// phone -> daemon : {"t":"hello", devicePublicKey, sessionSalt, proposedName?} (b64url keys)
|
|
8
|
+
// daemon -> phone : {"t":"pair-ack", daemonPublicKey, daemonId, deviceId, protocolVersion}
|
|
9
|
+
// ... the human compares the 6-digit SAS on phone vs desktop and confirms ON THE DESKTOP ...
|
|
10
|
+
// daemon -> phone : {"t":"confirmed", deviceId}
|
|
11
|
+
//
|
|
12
|
+
// The driver does NOT own the socket — the tunnel injects `send(obj)` (JSON-stringify + socket.send)
|
|
13
|
+
// and routes inbound text frames here. It DOES own the active-pairing association (D1: one at a time
|
|
14
|
+
// per daemon — the relay allows a single pair socket, replacing the older with 4409) plus the boundJti
|
|
15
|
+
// the gateway conveys (D2: the phone can't read its own HttpOnly-cookie jti, so the relay's pair
|
|
16
|
+
// `peer-online` carries it; the daemon captures it and uses it as boundJti for /pair/confirm).
|
|
17
|
+
//
|
|
18
|
+
// confirm() is the desktop-confirm sequence (D3): local row insert (the trust-root write, owned by the
|
|
19
|
+
// engine) -> AWAIT POST /pair/confirm (creates the gateway device row keyed by boundJti) -> only THEN
|
|
20
|
+
// tell the phone `confirmed`. Ordering guarantees the phone's subsequent /pair/session finds the row
|
|
21
|
+
// (no 403 race). If the gateway POST fails OR boundJti never arrived, we do NOT send `confirmed` — the
|
|
22
|
+
// phone is left to re-scan rather than told a half-finished pairing succeeded.
|
|
23
|
+
import { fromBase64Url, SESSION_SALT_LEN, toBase64Url, X25519_KEY_LEN, } from '../shared/remote-crypto.js';
|
|
24
|
+
const isHello = (v) => typeof v === 'object' &&
|
|
25
|
+
v !== null &&
|
|
26
|
+
v.t === 'hello' &&
|
|
27
|
+
typeof v.devicePublicKey === 'string' &&
|
|
28
|
+
typeof v.sessionSalt === 'string';
|
|
29
|
+
export const createRemotePairingTunnel = (deps) => {
|
|
30
|
+
// At most one active pairing per daemon (D1). A null boundJti means the gateway peer-online either
|
|
31
|
+
// hasn't arrived yet or didn't carry a jti — confirm() refuses in that case.
|
|
32
|
+
let active = null;
|
|
33
|
+
// The jti the most recent pair peer-online carried. Captured separately from `active` because the
|
|
34
|
+
// peer-online arrives BEFORE the hello (the relay emits it on pair-socket attach); the hello then
|
|
35
|
+
// adopts it. A new peer-online overwrites this and resets `active`.
|
|
36
|
+
let pendingBoundJti = null;
|
|
37
|
+
const onPeerOnline = (jti) => {
|
|
38
|
+
// D1 replace race: a new pair socket (possibly a different phone) supersedes any in-flight
|
|
39
|
+
// handshake. Drop the stale active pairing so a confirm on it can never go through.
|
|
40
|
+
active = null;
|
|
41
|
+
pendingBoundJti = jti ?? null;
|
|
42
|
+
};
|
|
43
|
+
const onPairingFrame = (text) => {
|
|
44
|
+
let parsed;
|
|
45
|
+
try {
|
|
46
|
+
parsed = JSON.parse(text);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (!isHello(parsed))
|
|
52
|
+
return;
|
|
53
|
+
let devicePublicKey;
|
|
54
|
+
let sessionSalt;
|
|
55
|
+
try {
|
|
56
|
+
devicePublicKey = fromBase64Url(parsed.devicePublicKey);
|
|
57
|
+
sessionSalt = fromBase64Url(parsed.sessionSalt);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (devicePublicKey.length !== X25519_KEY_LEN || sessionSalt.length !== SESSION_SALT_LEN) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// D1: map the hello to the daemon's single awaiting_handshake pending pairing. The relay only
|
|
66
|
+
// lets one pair socket attach, so there is at most one pending the inbound hello can belong to.
|
|
67
|
+
// (The phone's hello carries no pairingId — that handle lives only on the desktop.)
|
|
68
|
+
const pairingId = deps.pairing.findAwaitingHandshake();
|
|
69
|
+
if (!pairingId) {
|
|
70
|
+
deps.send({ t: 'rejected', reason: 'expired' });
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const view = deps.pairing.submitDeviceHello({
|
|
74
|
+
pairingId,
|
|
75
|
+
devicePublicKey,
|
|
76
|
+
sessionSalt,
|
|
77
|
+
...(parsed.proposedName !== undefined ? { proposedName: parsed.proposedName } : {}),
|
|
78
|
+
});
|
|
79
|
+
if (!view) {
|
|
80
|
+
deps.send({ t: 'rejected', reason: 'expired' });
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const reply = deps.pairing.getHandshakeReply(pairingId);
|
|
84
|
+
if (!reply) {
|
|
85
|
+
deps.send({ t: 'rejected', reason: 'expired' });
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
active = {
|
|
89
|
+
pairingId,
|
|
90
|
+
deviceId: reply.deviceId,
|
|
91
|
+
devicePublicKey,
|
|
92
|
+
boundJti: pendingBoundJti,
|
|
93
|
+
name: parsed.proposedName ?? null,
|
|
94
|
+
};
|
|
95
|
+
deps.send({
|
|
96
|
+
t: 'pair-ack',
|
|
97
|
+
daemonPublicKey: toBase64Url(reply.daemonPublicKey),
|
|
98
|
+
daemonId: reply.daemonId,
|
|
99
|
+
deviceId: reply.deviceId,
|
|
100
|
+
protocolVersion: reply.protocolVersion,
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
const confirm = async (pairingId, name) => {
|
|
104
|
+
// Atomicity (issue: confirm wasn't atomic). The OLD order wrote the device row + consumed the
|
|
105
|
+
// pending FIRST, then checked boundJti/token and POSTed the gateway — so a missing boundJti, a
|
|
106
|
+
// logged-out daemon, or a failed gateway POST left a GHOST local device + a dead (consumed) pairing
|
|
107
|
+
// code, while the desktop reported failure. The device list changed under a "failed" confirm.
|
|
108
|
+
//
|
|
109
|
+
// New order: every pre-write check + the gateway row come FIRST; the local trust-root write happens
|
|
110
|
+
// ONLY after the gateway succeeds. Any pre-write failure leaves the pending pairing fully intact —
|
|
111
|
+
// the desktop can retry, the phone can rescan, nothing half-finished is persisted.
|
|
112
|
+
// Non-consuming gone/expired check: keep the null-return contract for a pairing that's no longer
|
|
113
|
+
// confirmable (so the route still answers "not found" instead of throwing).
|
|
114
|
+
if (!deps.pairing.getPending(pairingId))
|
|
115
|
+
return null;
|
|
116
|
+
// The active handshake carries the devicePublicKey + boundJti (D2) the gateway row is keyed by.
|
|
117
|
+
if (active?.pairingId !== pairingId || !active.boundJti || !active.devicePublicKey) {
|
|
118
|
+
throw new Error('pairing confirm: missing boundJti for gateway registration');
|
|
119
|
+
}
|
|
120
|
+
const gatewayUrl = deps.getGatewayUrl();
|
|
121
|
+
const daemonToken = deps.getDaemonToken();
|
|
122
|
+
if (!gatewayUrl || !daemonToken) {
|
|
123
|
+
throw new Error('pairing confirm: remote not logged in');
|
|
124
|
+
}
|
|
125
|
+
// Resolve the name the SAME way the engine's confirmPairing will (operator override → phone's
|
|
126
|
+
// proposedName → default) so the gateway row and the local row agree on it.
|
|
127
|
+
const deviceName = name ?? active.name ?? 'New device';
|
|
128
|
+
// Gateway row FIRST. If this throws, NOTHING local changed — the pending pairing is still alive.
|
|
129
|
+
await deps.postPairConfirm({ gatewayUrl, daemonToken }, {
|
|
130
|
+
deviceId: active.deviceId,
|
|
131
|
+
devicePubkey: toBase64Url(active.devicePublicKey),
|
|
132
|
+
name: deviceName,
|
|
133
|
+
boundJti: active.boundJti,
|
|
134
|
+
});
|
|
135
|
+
// Trust-root local write happens ONLY now (gateway row exists → the phone's later /pair/session
|
|
136
|
+
// finds it, no 403 race). confirmPairing consumes the pending.
|
|
137
|
+
const record = deps.pairing.confirmPairing(pairingId, name === undefined ? undefined : { name });
|
|
138
|
+
if (!record)
|
|
139
|
+
return null; // vanished in the tiny window since the POST (expired) — nothing to relay
|
|
140
|
+
deps.send({ t: 'confirmed', deviceId: record.id });
|
|
141
|
+
active = null;
|
|
142
|
+
pendingBoundJti = null;
|
|
143
|
+
return record;
|
|
144
|
+
};
|
|
145
|
+
return { onPeerOnline, onPairingFrame, confirm };
|
|
146
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type DeviceKeyPair } from '../shared/remote-crypto.js';
|
|
2
|
+
import type { RemoteAuditStore } from './remote-audit-store.js';
|
|
3
|
+
import type { RemoteDeviceRecord, RemoteDeviceStore } from './remote-device-store.js';
|
|
4
|
+
export type PairingState = 'awaiting_handshake' | 'awaiting_confirm' | 'confirmed' | 'rejected' | 'expired';
|
|
5
|
+
export declare const PAIRING_TTL_MS: number;
|
|
6
|
+
export type PairingRejectReason = 'pairing_expired' | 'pairing_replay' | 'pairing_unknown' | 'pairing_bad_input' | 'pairing_confirm_forbidden';
|
|
7
|
+
export interface PairingTicket {
|
|
8
|
+
pairingId: string;
|
|
9
|
+
qr: string;
|
|
10
|
+
code: string;
|
|
11
|
+
expiresAt: number;
|
|
12
|
+
}
|
|
13
|
+
export interface PendingPairingView {
|
|
14
|
+
pairingId: string;
|
|
15
|
+
deviceName: string | null;
|
|
16
|
+
sas: string;
|
|
17
|
+
expiresAt: number;
|
|
18
|
+
}
|
|
19
|
+
export interface HandshakeReply {
|
|
20
|
+
daemonPublicKey: Uint8Array;
|
|
21
|
+
daemonId: string;
|
|
22
|
+
deviceId: string;
|
|
23
|
+
protocolVersion: number;
|
|
24
|
+
}
|
|
25
|
+
export interface DevicePairingHello {
|
|
26
|
+
pairingId: string;
|
|
27
|
+
devicePublicKey: Uint8Array;
|
|
28
|
+
sessionSalt: Uint8Array;
|
|
29
|
+
proposedName?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface RemotePairingDeps {
|
|
32
|
+
deviceStore: RemoteDeviceStore;
|
|
33
|
+
audit: RemoteAuditStore;
|
|
34
|
+
getGatewayUrl: () => string | null;
|
|
35
|
+
getDaemonId: () => string | null;
|
|
36
|
+
now?: () => number;
|
|
37
|
+
ttlMs?: number;
|
|
38
|
+
newDaemonKeyPair?: () => DeviceKeyPair;
|
|
39
|
+
randomPairingSecret?: () => Uint8Array;
|
|
40
|
+
randomPairingCode?: () => string;
|
|
41
|
+
newId?: () => string;
|
|
42
|
+
setTimer?: (fn: () => void, ms: number) => NodeJS.Timeout;
|
|
43
|
+
clearTimer?: (h: NodeJS.Timeout) => void;
|
|
44
|
+
}
|
|
45
|
+
export interface RemotePairing {
|
|
46
|
+
beginPairing(): PairingTicket;
|
|
47
|
+
submitDeviceHello(hello: DevicePairingHello): PendingPairingView | null;
|
|
48
|
+
getHandshakeReply(pairingId: string): HandshakeReply | null;
|
|
49
|
+
confirmPairing(pairingId: string, opts?: {
|
|
50
|
+
name?: string;
|
|
51
|
+
}): RemoteDeviceRecord | null;
|
|
52
|
+
rejectPairing(pairingId: string, reason?: string): void;
|
|
53
|
+
getPending(pairingId: string): PendingPairingView | null;
|
|
54
|
+
listPending(): PendingPairingView[];
|
|
55
|
+
findAwaitingHandshake(): string | null;
|
|
56
|
+
dispose(): void;
|
|
57
|
+
}
|
|
58
|
+
export declare const createRemotePairing: (deps: RemotePairingDeps) => RemotePairing;
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { randomBytes } from '@noble/ciphers/utils.js';
|
|
3
|
+
import { deriveDaemonSession, encodePairingPayload, generateDeviceKeyPair, PAIRING_SECRET_LEN, REMOTE_CRYPTO_VERSION, SESSION_SALT_LEN, toBase64Url, X25519_KEY_LEN, } from '../shared/remote-crypto.js';
|
|
4
|
+
import { formatPairingCode, generatePairingCode, normalizePairingCode, PAIRING_CODE_SECRET_CONTEXT, } from '../shared/remote-pairing-code.js';
|
|
5
|
+
// Short TTL: a leaked pairing code is useless within five minutes (invariant 2), while real
|
|
6
|
+
// phone/OAuth/manual-entry paths have enough time to complete without racing the clock.
|
|
7
|
+
export const PAIRING_TTL_MS = 5 * 60_000;
|
|
8
|
+
const defaultName = () => 'New device';
|
|
9
|
+
const pairingSecretFromCode = (code) => {
|
|
10
|
+
const normalized = normalizePairingCode(code);
|
|
11
|
+
if (!normalized)
|
|
12
|
+
throw new RangeError('invalid pairing code');
|
|
13
|
+
return new Uint8Array(createHash('sha256').update(PAIRING_CODE_SECRET_CONTEXT).update(normalized).digest());
|
|
14
|
+
};
|
|
15
|
+
const toView = (p) => ({
|
|
16
|
+
pairingId: p.pairingId,
|
|
17
|
+
deviceName: p.proposedName,
|
|
18
|
+
sas: p.sas ?? '',
|
|
19
|
+
expiresAt: p.expiresAt,
|
|
20
|
+
});
|
|
21
|
+
export const createRemotePairing = (deps) => {
|
|
22
|
+
const now = deps.now ?? Date.now;
|
|
23
|
+
const ttlMs = deps.ttlMs ?? PAIRING_TTL_MS;
|
|
24
|
+
const newDaemonKeyPair = deps.newDaemonKeyPair ?? generateDeviceKeyPair;
|
|
25
|
+
const randomPairingSecret = deps.randomPairingSecret;
|
|
26
|
+
const randomPairingCode = deps.randomPairingCode ?? (() => generatePairingCode((length) => randomBytes(length)));
|
|
27
|
+
const newId = deps.newId ?? randomUUID;
|
|
28
|
+
const setTimer = deps.setTimer ?? ((fn, ms) => setTimeout(fn, ms));
|
|
29
|
+
const clearTimer = deps.clearTimer ?? ((h) => clearTimeout(h));
|
|
30
|
+
const pending = new Map();
|
|
31
|
+
// Zero the in-memory secrets the moment a pairing leaves a pre-terminal state. The key bytes are
|
|
32
|
+
// owned by us (never aliased into the store except via a copy on insert), so wiping them here is
|
|
33
|
+
// belt-and-suspenders against a heap dump.
|
|
34
|
+
const wipe = (p) => {
|
|
35
|
+
p.pairingSecret.fill(0);
|
|
36
|
+
p.daemonKeyPair.secretKey.fill(0);
|
|
37
|
+
if (p.sessionKeys) {
|
|
38
|
+
p.sessionKeys.d2p.fill(0);
|
|
39
|
+
p.sessionKeys.p2d.fill(0);
|
|
40
|
+
}
|
|
41
|
+
if (p.timer !== null) {
|
|
42
|
+
clearTimer(p.timer);
|
|
43
|
+
p.timer = null;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const auditReject = (reason, deviceId = null) => {
|
|
47
|
+
deps.audit.enqueue({ action: 'reject', result: 'rejected', rejectReason: reason, deviceId });
|
|
48
|
+
};
|
|
49
|
+
// Drop a pending pairing, wipe its secrets, mark terminal. Used by reject + expire + confirm.
|
|
50
|
+
const discard = (pairingId, state) => {
|
|
51
|
+
const p = pending.get(pairingId);
|
|
52
|
+
if (!p)
|
|
53
|
+
return null;
|
|
54
|
+
p.state = state;
|
|
55
|
+
wipe(p);
|
|
56
|
+
pending.delete(pairingId);
|
|
57
|
+
return p;
|
|
58
|
+
};
|
|
59
|
+
const expire = (pairingId) => {
|
|
60
|
+
const p = pending.get(pairingId);
|
|
61
|
+
if (!p)
|
|
62
|
+
return;
|
|
63
|
+
discard(pairingId, 'expired');
|
|
64
|
+
auditReject('pairing_expired', p.deviceId);
|
|
65
|
+
};
|
|
66
|
+
// Lazy expiry on every access: TTL is enforced even if the timer never fired (and unit tests never
|
|
67
|
+
// rely on a real setTimeout). A pairing whose deadline passed is treated as gone.
|
|
68
|
+
const sweep = () => {
|
|
69
|
+
const t = now();
|
|
70
|
+
for (const [id, p] of [...pending]) {
|
|
71
|
+
if (t >= p.expiresAt)
|
|
72
|
+
expire(id);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
beginPairing() {
|
|
77
|
+
const gatewayUrl = deps.getGatewayUrl();
|
|
78
|
+
const daemonId = deps.getDaemonId();
|
|
79
|
+
if (!gatewayUrl || !daemonId) {
|
|
80
|
+
throw new Error('remote not logged in: cannot start pairing');
|
|
81
|
+
}
|
|
82
|
+
const code = randomPairingCode();
|
|
83
|
+
const pairingSecret = randomPairingSecret?.() ?? pairingSecretFromCode(code);
|
|
84
|
+
if (pairingSecret.length !== PAIRING_SECRET_LEN) {
|
|
85
|
+
throw new RangeError(`pairing secret must be ${PAIRING_SECRET_LEN} bytes`);
|
|
86
|
+
}
|
|
87
|
+
const daemonKeyPair = newDaemonKeyPair();
|
|
88
|
+
const pairingId = newId();
|
|
89
|
+
const deviceId = newId();
|
|
90
|
+
const expiresAt = now() + ttlMs;
|
|
91
|
+
const entry = {
|
|
92
|
+
pairingId,
|
|
93
|
+
deviceId,
|
|
94
|
+
state: 'awaiting_handshake',
|
|
95
|
+
expiresAt,
|
|
96
|
+
pairingSecret,
|
|
97
|
+
daemonKeyPair,
|
|
98
|
+
sessionKeys: null,
|
|
99
|
+
devicePublicKey: null,
|
|
100
|
+
sas: null,
|
|
101
|
+
proposedName: null,
|
|
102
|
+
timer: null,
|
|
103
|
+
};
|
|
104
|
+
entry.timer = setTimer(() => expire(pairingId), ttlMs);
|
|
105
|
+
pending.set(pairingId, entry);
|
|
106
|
+
const qr = encodePairingPayload({
|
|
107
|
+
v: REMOTE_CRYPTO_VERSION,
|
|
108
|
+
gatewayUrl,
|
|
109
|
+
daemonId,
|
|
110
|
+
pairingSecret: toBase64Url(pairingSecret),
|
|
111
|
+
});
|
|
112
|
+
return { pairingId, qr, code: formatPairingCode(code), expiresAt };
|
|
113
|
+
},
|
|
114
|
+
submitDeviceHello(hello) {
|
|
115
|
+
sweep();
|
|
116
|
+
const p = pending.get(hello.pairingId);
|
|
117
|
+
if (!p) {
|
|
118
|
+
// Unknown OR already consumed (a replay deletes/advances the entry).
|
|
119
|
+
auditReject('pairing_unknown');
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
if (p.state !== 'awaiting_handshake') {
|
|
123
|
+
// One-time: a second hello on a token that already produced a pending is a replay.
|
|
124
|
+
auditReject('pairing_replay', p.deviceId);
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
if (now() >= p.expiresAt) {
|
|
128
|
+
expire(hello.pairingId);
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
if (hello.devicePublicKey.length !== X25519_KEY_LEN ||
|
|
132
|
+
hello.sessionSalt.length !== SESSION_SALT_LEN) {
|
|
133
|
+
discard(hello.pairingId, 'rejected');
|
|
134
|
+
auditReject('pairing_bad_input', p.deviceId);
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
const daemonId = deps.getDaemonId();
|
|
138
|
+
if (!daemonId) {
|
|
139
|
+
// Logged out between begin and hello — treat as unusable, drop the pairing.
|
|
140
|
+
discard(hello.pairingId, 'rejected');
|
|
141
|
+
auditReject('pairing_unknown', p.deviceId);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const ids = {
|
|
145
|
+
daemonId,
|
|
146
|
+
deviceId: p.deviceId,
|
|
147
|
+
protocolVersion: REMOTE_CRYPTO_VERSION,
|
|
148
|
+
};
|
|
149
|
+
const keys = deriveDaemonSession({
|
|
150
|
+
daemonSecretKey: p.daemonKeyPair.secretKey,
|
|
151
|
+
devicePublicKey: hello.devicePublicKey,
|
|
152
|
+
daemonPublicKey: p.daemonKeyPair.publicKey,
|
|
153
|
+
pairingSecret: p.pairingSecret,
|
|
154
|
+
sessionSalt: hello.sessionSalt,
|
|
155
|
+
ids,
|
|
156
|
+
});
|
|
157
|
+
p.sessionKeys = { d2p: keys.d2p, p2d: keys.p2d };
|
|
158
|
+
p.sas = keys.sas;
|
|
159
|
+
p.devicePublicKey = hello.devicePublicKey;
|
|
160
|
+
p.proposedName = hello.proposedName ?? null;
|
|
161
|
+
p.state = 'awaiting_confirm';
|
|
162
|
+
// Still NOT persisted, NOT in the provider — a relay attempt now gets provider.get === null.
|
|
163
|
+
return toView(p);
|
|
164
|
+
},
|
|
165
|
+
getHandshakeReply(pairingId) {
|
|
166
|
+
sweep();
|
|
167
|
+
const p = pending.get(pairingId);
|
|
168
|
+
if (!p || p.state !== 'awaiting_confirm')
|
|
169
|
+
return null;
|
|
170
|
+
const daemonId = deps.getDaemonId();
|
|
171
|
+
if (!daemonId)
|
|
172
|
+
return null;
|
|
173
|
+
// daemonPublicKey is PUBLIC — fine to emit so the phone can run deriveDeviceSession.
|
|
174
|
+
return {
|
|
175
|
+
daemonPublicKey: p.daemonKeyPair.publicKey,
|
|
176
|
+
daemonId,
|
|
177
|
+
deviceId: p.deviceId,
|
|
178
|
+
protocolVersion: REMOTE_CRYPTO_VERSION,
|
|
179
|
+
};
|
|
180
|
+
},
|
|
181
|
+
// THE trust root. The route layer guarantees this only runs for a local desktop request.
|
|
182
|
+
confirmPairing(pairingId, opts) {
|
|
183
|
+
sweep();
|
|
184
|
+
const p = pending.get(pairingId);
|
|
185
|
+
if (!p || p.state !== 'awaiting_confirm' || !p.sessionKeys || !p.devicePublicKey) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
const rec = deps.deviceStore.insert({
|
|
189
|
+
id: p.deviceId,
|
|
190
|
+
name: opts?.name ?? p.proposedName ?? defaultName(),
|
|
191
|
+
keys: { d2p: p.sessionKeys.d2p, p2d: p.sessionKeys.p2d },
|
|
192
|
+
devicePublicKey: p.devicePublicKey,
|
|
193
|
+
});
|
|
194
|
+
deps.audit.enqueue({ action: 'session_open', deviceId: rec.id, result: 'ok' });
|
|
195
|
+
// The store INSERT copied the key bytes via toBase64Url, so wiping our in-memory copy is safe.
|
|
196
|
+
discard(pairingId, 'confirmed');
|
|
197
|
+
return rec;
|
|
198
|
+
},
|
|
199
|
+
rejectPairing(pairingId, reason) {
|
|
200
|
+
sweep();
|
|
201
|
+
const p = pending.get(pairingId);
|
|
202
|
+
if (!p)
|
|
203
|
+
return;
|
|
204
|
+
discard(pairingId, 'rejected');
|
|
205
|
+
auditReject(reason ?? 'pairing_replay', p.deviceId);
|
|
206
|
+
},
|
|
207
|
+
getPending(pairingId) {
|
|
208
|
+
sweep();
|
|
209
|
+
const p = pending.get(pairingId);
|
|
210
|
+
if (!p || p.state !== 'awaiting_confirm')
|
|
211
|
+
return null;
|
|
212
|
+
return toView(p);
|
|
213
|
+
},
|
|
214
|
+
listPending() {
|
|
215
|
+
sweep();
|
|
216
|
+
return [...pending.values()].filter((p) => p.state === 'awaiting_confirm').map(toView);
|
|
217
|
+
},
|
|
218
|
+
findAwaitingHandshake() {
|
|
219
|
+
sweep();
|
|
220
|
+
// At most one in practice (D1). If two ever coexist, take the freshest (latest deadline) so a
|
|
221
|
+
// re-minted token wins over a stale one the user abandoned.
|
|
222
|
+
let best = null;
|
|
223
|
+
for (const p of pending.values()) {
|
|
224
|
+
if (p.state !== 'awaiting_handshake')
|
|
225
|
+
continue;
|
|
226
|
+
if (!best || p.expiresAt > best.expiresAt)
|
|
227
|
+
best = p;
|
|
228
|
+
}
|
|
229
|
+
return best?.pairingId ?? null;
|
|
230
|
+
},
|
|
231
|
+
dispose() {
|
|
232
|
+
for (const id of [...pending.keys()]) {
|
|
233
|
+
discard(id, 'rejected');
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
};
|