@beeos-ai/device-agent 0.4.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/.pi/extensions/android-tools.ts +139 -0
- package/.pi/skills/.gitkeep +0 -0
- package/.pi/skills/ground-mobile-fallback/SKILL.md +50 -0
- package/LICENSE +201 -0
- package/dist/action/handler.d.ts +9 -0
- package/dist/action/handler.js +124 -0
- package/dist/action/handler.js.map +1 -0
- package/dist/adapters/agent-gateway-client.d.ts +256 -0
- package/dist/adapters/agent-gateway-client.js +332 -0
- package/dist/adapters/agent-gateway-client.js.map +1 -0
- package/dist/adapters/agentcore-inner-loop.d.ts +29 -0
- package/dist/adapters/agentcore-inner-loop.js +72 -0
- package/dist/adapters/agentcore-inner-loop.js.map +1 -0
- package/dist/adapters/agentcore-pi.d.ts +215 -0
- package/dist/adapters/agentcore-pi.js +464 -0
- package/dist/adapters/agentcore-pi.js.map +1 -0
- package/dist/adapters/agentcore-runner.d.ts +70 -0
- package/dist/adapters/agentcore-runner.js +255 -0
- package/dist/adapters/agentcore-runner.js.map +1 -0
- package/dist/adapters/device-android-adb.d.ts +41 -0
- package/dist/adapters/device-android-adb.js +279 -0
- package/dist/adapters/device-android-adb.js.map +1 -0
- package/dist/adapters/device-desktop.d.ts +37 -0
- package/dist/adapters/device-desktop.js +101 -0
- package/dist/adapters/device-desktop.js.map +1 -0
- package/dist/adapters/identity-file.d.ts +30 -0
- package/dist/adapters/identity-file.js +50 -0
- package/dist/adapters/identity-file.js.map +1 -0
- package/dist/adapters/transport-bridge-ws.d.ts +39 -0
- package/dist/adapters/transport-bridge-ws.js +49 -0
- package/dist/adapters/transport-bridge-ws.js.map +1 -0
- package/dist/adapters/vlm-inner-loop.d.ts +88 -0
- package/dist/adapters/vlm-inner-loop.js +199 -0
- package/dist/adapters/vlm-inner-loop.js.map +1 -0
- package/dist/agent-runtime/adapters/base.d.ts +145 -0
- package/dist/agent-runtime/adapters/base.js +29 -0
- package/dist/agent-runtime/adapters/base.js.map +1 -0
- package/dist/agent-runtime/adapters/index.d.ts +17 -0
- package/dist/agent-runtime/adapters/index.js +17 -0
- package/dist/agent-runtime/adapters/index.js.map +1 -0
- package/dist/agent-runtime/adapters/mock.d.ts +44 -0
- package/dist/agent-runtime/adapters/mock.js +54 -0
- package/dist/agent-runtime/adapters/mock.js.map +1 -0
- package/dist/agent-runtime/adapters/openai.d.ts +63 -0
- package/dist/agent-runtime/adapters/openai.js +302 -0
- package/dist/agent-runtime/adapters/openai.js.map +1 -0
- package/dist/agent-runtime/adapters/registry.d.ts +49 -0
- package/dist/agent-runtime/adapters/registry.js +129 -0
- package/dist/agent-runtime/adapters/registry.js.map +1 -0
- package/dist/agent-runtime/adapters/ui-tars.d.ts +13 -0
- package/dist/agent-runtime/adapters/ui-tars.js +22 -0
- package/dist/agent-runtime/adapters/ui-tars.js.map +1 -0
- package/dist/agent-runtime/agent-runner.d.ts +149 -0
- package/dist/agent-runtime/agent-runner.js +356 -0
- package/dist/agent-runtime/agent-runner.js.map +1 -0
- package/dist/agent-runtime/core.d.ts +170 -0
- package/dist/agent-runtime/core.js +624 -0
- package/dist/agent-runtime/core.js.map +1 -0
- package/dist/agent-runtime/index.d.ts +16 -0
- package/dist/agent-runtime/index.js +17 -0
- package/dist/agent-runtime/index.js.map +1 -0
- package/dist/agent-runtime/plan-executor.d.ts +118 -0
- package/dist/agent-runtime/plan-executor.js +501 -0
- package/dist/agent-runtime/plan-executor.js.map +1 -0
- package/dist/agent-runtime/planner/base.d.ts +128 -0
- package/dist/agent-runtime/planner/base.js +157 -0
- package/dist/agent-runtime/planner/base.js.map +1 -0
- package/dist/agent-runtime/planner/llm-planner.d.ts +58 -0
- package/dist/agent-runtime/planner/llm-planner.js +112 -0
- package/dist/agent-runtime/planner/llm-planner.js.map +1 -0
- package/dist/agent-runtime/planner/noop-planner.d.ts +13 -0
- package/dist/agent-runtime/planner/noop-planner.js +30 -0
- package/dist/agent-runtime/planner/noop-planner.js.map +1 -0
- package/dist/agent-runtime/planner/prompts.d.ts +33 -0
- package/dist/agent-runtime/planner/prompts.js +165 -0
- package/dist/agent-runtime/planner/prompts.js.map +1 -0
- package/dist/agent-runtime/reflection.d.ts +81 -0
- package/dist/agent-runtime/reflection.js +189 -0
- package/dist/agent-runtime/reflection.js.map +1 -0
- package/dist/agent-runtime/reflectors/action-reflector.d.ts +97 -0
- package/dist/agent-runtime/reflectors/action-reflector.js +233 -0
- package/dist/agent-runtime/reflectors/action-reflector.js.map +1 -0
- package/dist/agent-runtime/reflectors/policy.d.ts +53 -0
- package/dist/agent-runtime/reflectors/policy.js +106 -0
- package/dist/agent-runtime/reflectors/policy.js.map +1 -0
- package/dist/agent-runtime/reflectors/trajectory-reflector.d.ts +94 -0
- package/dist/agent-runtime/reflectors/trajectory-reflector.js +223 -0
- package/dist/agent-runtime/reflectors/trajectory-reflector.js.map +1 -0
- package/dist/agent-runtime/skills/embedding.d.ts +53 -0
- package/dist/agent-runtime/skills/embedding.js +134 -0
- package/dist/agent-runtime/skills/embedding.js.map +1 -0
- package/dist/agent-runtime/skills/fs-store.d.ts +88 -0
- package/dist/agent-runtime/skills/fs-store.js +483 -0
- package/dist/agent-runtime/skills/fs-store.js.map +1 -0
- package/dist/agent-runtime/skills/index.d.ts +10 -0
- package/dist/agent-runtime/skills/index.js +10 -0
- package/dist/agent-runtime/skills/index.js.map +1 -0
- package/dist/agent-runtime/skills/matcher-evolver.d.ts +88 -0
- package/dist/agent-runtime/skills/matcher-evolver.js +110 -0
- package/dist/agent-runtime/skills/matcher-evolver.js.map +1 -0
- package/dist/agent-runtime/skills/memory-store.d.ts +23 -0
- package/dist/agent-runtime/skills/memory-store.js +94 -0
- package/dist/agent-runtime/skills/memory-store.js.map +1 -0
- package/dist/agent-runtime/skills/normalise.d.ts +40 -0
- package/dist/agent-runtime/skills/normalise.js +152 -0
- package/dist/agent-runtime/skills/normalise.js.map +1 -0
- package/dist/agent-runtime/skills/replay.d.ts +46 -0
- package/dist/agent-runtime/skills/replay.js +106 -0
- package/dist/agent-runtime/skills/replay.js.map +1 -0
- package/dist/agent-runtime/skills/sqlite-store.d.ts +60 -0
- package/dist/agent-runtime/skills/sqlite-store.js +234 -0
- package/dist/agent-runtime/skills/sqlite-store.js.map +1 -0
- package/dist/agent-runtime/skills/types.d.ts +99 -0
- package/dist/agent-runtime/skills/types.js +14 -0
- package/dist/agent-runtime/skills/types.js.map +1 -0
- package/dist/agent.d.ts +110 -0
- package/dist/agent.js +162 -0
- package/dist/agent.js.map +1 -0
- package/dist/api.d.ts +27 -0
- package/dist/api.js +48 -0
- package/dist/api.js.map +1 -0
- package/dist/app/agent-host.d.ts +59 -0
- package/dist/app/agent-host.js +263 -0
- package/dist/app/agent-host.js.map +1 -0
- package/dist/app/device-manager.d.ts +28 -0
- package/dist/app/device-manager.js +64 -0
- package/dist/app/device-manager.js.map +1 -0
- package/dist/app/message-store.d.ts +55 -0
- package/dist/app/message-store.js +99 -0
- package/dist/app/message-store.js.map +1 -0
- package/dist/app/session-manager.d.ts +132 -0
- package/dist/app/session-manager.js +350 -0
- package/dist/app/session-manager.js.map +1 -0
- package/dist/bootstrap.d.ts +94 -0
- package/dist/bootstrap.js +459 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/chat.d.ts +16 -0
- package/dist/chat.js +175 -0
- package/dist/chat.js.map +1 -0
- package/dist/config/loader.d.ts +77 -0
- package/dist/config/loader.js +292 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +162 -0
- package/dist/config/schema.js +243 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/actions.d.ts +60 -0
- package/dist/core/actions.js +120 -0
- package/dist/core/actions.js.map +1 -0
- package/dist/core/errors.d.ts +8 -0
- package/dist/core/errors.js +9 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/screen.d.ts +7 -0
- package/dist/core/screen.js +8 -0
- package/dist/core/screen.js.map +1 -0
- package/dist/core/session.d.ts +42 -0
- package/dist/core/session.js +29 -0
- package/dist/core/session.js.map +1 -0
- package/dist/debug/dump-system-prompt.d.ts +1 -0
- package/dist/debug/dump-system-prompt.js +34 -0
- package/dist/debug/dump-system-prompt.js.map +1 -0
- package/dist/device/android.d.ts +25 -0
- package/dist/device/android.js +231 -0
- package/dist/device/android.js.map +1 -0
- package/dist/device/apps.d.ts +3 -0
- package/dist/device/apps.js +77 -0
- package/dist/device/apps.js.map +1 -0
- package/dist/device/base.d.ts +20 -0
- package/dist/device/base.js +2 -0
- package/dist/device/base.js.map +1 -0
- package/dist/device/ui-xml.d.ts +29 -0
- package/dist/device/ui-xml.js +194 -0
- package/dist/device/ui-xml.js.map +1 -0
- package/dist/fleet/adapters/process/node-process-manager.d.ts +157 -0
- package/dist/fleet/adapters/process/node-process-manager.js +664 -0
- package/dist/fleet/adapters/process/node-process-manager.js.map +1 -0
- package/dist/fleet/adapters/sources/local-adb.d.ts +105 -0
- package/dist/fleet/adapters/sources/local-adb.js +353 -0
- package/dist/fleet/adapters/sources/local-adb.js.map +1 -0
- package/dist/fleet/adapters/sources/remote-adb.d.ts +97 -0
- package/dist/fleet/adapters/sources/remote-adb.js +138 -0
- package/dist/fleet/adapters/sources/remote-adb.js.map +1 -0
- package/dist/fleet/adapters/state/beeos-cli-store.d.ts +72 -0
- package/dist/fleet/adapters/state/beeos-cli-store.js +250 -0
- package/dist/fleet/adapters/state/beeos-cli-store.js.map +1 -0
- package/dist/fleet/adapters/state/port-allocator.d.ts +43 -0
- package/dist/fleet/adapters/state/port-allocator.js +173 -0
- package/dist/fleet/adapters/state/port-allocator.js.map +1 -0
- package/dist/fleet/domain/device.d.ts +138 -0
- package/dist/fleet/domain/device.js +49 -0
- package/dist/fleet/domain/device.js.map +1 -0
- package/dist/fleet/domain/events.d.ts +102 -0
- package/dist/fleet/domain/events.js +15 -0
- package/dist/fleet/domain/events.js.map +1 -0
- package/dist/fleet/domain/fsm.d.ts +122 -0
- package/dist/fleet/domain/fsm.js +475 -0
- package/dist/fleet/domain/fsm.js.map +1 -0
- package/dist/fleet/http/status-client.d.ts +31 -0
- package/dist/fleet/http/status-client.js +115 -0
- package/dist/fleet/http/status-client.js.map +1 -0
- package/dist/fleet/http/status-server.d.ts +64 -0
- package/dist/fleet/http/status-server.js +200 -0
- package/dist/fleet/http/status-server.js.map +1 -0
- package/dist/fleet/index.d.ts +27 -0
- package/dist/fleet/index.js +17 -0
- package/dist/fleet/index.js.map +1 -0
- package/dist/fleet/installer/index.d.ts +12 -0
- package/dist/fleet/installer/index.js +13 -0
- package/dist/fleet/installer/index.js.map +1 -0
- package/dist/fleet/installer/launchd-mac.d.ts +73 -0
- package/dist/fleet/installer/launchd-mac.js +291 -0
- package/dist/fleet/installer/launchd-mac.js.map +1 -0
- package/dist/fleet/installer/service-spec.d.ts +70 -0
- package/dist/fleet/installer/service-spec.js +43 -0
- package/dist/fleet/installer/service-spec.js.map +1 -0
- package/dist/fleet/installer/spawn-env.d.ts +45 -0
- package/dist/fleet/installer/spawn-env.js +224 -0
- package/dist/fleet/installer/spawn-env.js.map +1 -0
- package/dist/fleet/ports/clock.d.ts +19 -0
- package/dist/fleet/ports/clock.js +26 -0
- package/dist/fleet/ports/clock.js.map +1 -0
- package/dist/fleet/ports/device-source.d.ts +28 -0
- package/dist/fleet/ports/device-source.js +18 -0
- package/dist/fleet/ports/device-source.js.map +1 -0
- package/dist/fleet/ports/process-manager.d.ts +110 -0
- package/dist/fleet/ports/process-manager.js +27 -0
- package/dist/fleet/ports/process-manager.js.map +1 -0
- package/dist/fleet/ports/state-registry.d.ts +49 -0
- package/dist/fleet/ports/state-registry.js +12 -0
- package/dist/fleet/ports/state-registry.js.map +1 -0
- package/dist/fleet/supervisor.d.ts +107 -0
- package/dist/fleet/supervisor.js +508 -0
- package/dist/fleet/supervisor.js.map +1 -0
- package/dist/grounding/grounder.d.ts +46 -0
- package/dist/grounding/grounder.js +82 -0
- package/dist/grounding/grounder.js.map +1 -0
- package/dist/inbound/acp/handlers/device.d.ts +43 -0
- package/dist/inbound/acp/handlers/device.js +153 -0
- package/dist/inbound/acp/handlers/device.js.map +1 -0
- package/dist/inbound/acp/handlers/initialize.d.ts +71 -0
- package/dist/inbound/acp/handlers/initialize.js +53 -0
- package/dist/inbound/acp/handlers/initialize.js.map +1 -0
- package/dist/inbound/acp/handlers/models.d.ts +16 -0
- package/dist/inbound/acp/handlers/models.js +23 -0
- package/dist/inbound/acp/handlers/models.js.map +1 -0
- package/dist/inbound/acp/handlers/session.d.ts +51 -0
- package/dist/inbound/acp/handlers/session.js +61 -0
- package/dist/inbound/acp/handlers/session.js.map +1 -0
- package/dist/inbound/acp/handlers/skills.d.ts +8 -0
- package/dist/inbound/acp/handlers/skills.js +9 -0
- package/dist/inbound/acp/handlers/skills.js.map +1 -0
- package/dist/inbound/acp/notifier.d.ts +35 -0
- package/dist/inbound/acp/notifier.js +45 -0
- package/dist/inbound/acp/notifier.js.map +1 -0
- package/dist/inbound/acp/router.d.ts +67 -0
- package/dist/inbound/acp/router.js +179 -0
- package/dist/inbound/acp/router.js.map +1 -0
- package/dist/inbound/cli/fleet-command.d.ts +34 -0
- package/dist/inbound/cli/fleet-command.js +792 -0
- package/dist/inbound/cli/fleet-command.js.map +1 -0
- package/dist/inbound/cli/main.d.ts +38 -0
- package/dist/inbound/cli/main.js +364 -0
- package/dist/inbound/cli/main.js.map +1 -0
- package/dist/inbound/cli/run-command.d.ts +101 -0
- package/dist/inbound/cli/run-command.js +405 -0
- package/dist/inbound/cli/run-command.js.map +1 -0
- package/dist/inbound/cli/skills-command.d.ts +39 -0
- package/dist/inbound/cli/skills-command.js +333 -0
- package/dist/inbound/cli/skills-command.js.map +1 -0
- package/dist/inbound/http/server.d.ts +7 -0
- package/dist/inbound/http/server.js +8 -0
- package/dist/inbound/http/server.js.map +1 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/logger/index.d.ts +37 -0
- package/dist/logger/index.js +84 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/mcp-client/autospawn.d.ts +67 -0
- package/dist/mcp-client/autospawn.js +173 -0
- package/dist/mcp-client/autospawn.js.map +1 -0
- package/dist/mcp-client/client.d.ts +78 -0
- package/dist/mcp-client/client.js +168 -0
- package/dist/mcp-client/client.js.map +1 -0
- package/dist/mcp-client/index.d.ts +7 -0
- package/dist/mcp-client/index.js +4 -0
- package/dist/mcp-client/index.js.map +1 -0
- package/dist/mcp-client/inproc.d.ts +47 -0
- package/dist/mcp-client/inproc.js +229 -0
- package/dist/mcp-client/inproc.js.map +1 -0
- package/dist/mcp-client/runtime.d.ts +34 -0
- package/dist/mcp-client/runtime.js +15 -0
- package/dist/mcp-client/runtime.js.map +1 -0
- package/dist/model/adapters/autoglm.d.ts +31 -0
- package/dist/model/adapters/autoglm.js +409 -0
- package/dist/model/adapters/autoglm.js.map +1 -0
- package/dist/model/adapters/base.d.ts +13 -0
- package/dist/model/adapters/base.js +27 -0
- package/dist/model/adapters/base.js.map +1 -0
- package/dist/model/adapters/guiowl.d.ts +1 -0
- package/dist/model/adapters/guiowl.js +253 -0
- package/dist/model/adapters/guiowl.js.map +1 -0
- package/dist/model/adapters/index.d.ts +6 -0
- package/dist/model/adapters/index.js +8 -0
- package/dist/model/adapters/index.js.map +1 -0
- package/dist/model/adapters/maiui.d.ts +1 -0
- package/dist/model/adapters/maiui.js +117 -0
- package/dist/model/adapters/maiui.js.map +1 -0
- package/dist/model/adapters/qwenvl.d.ts +1 -0
- package/dist/model/adapters/qwenvl.js +108 -0
- package/dist/model/adapters/qwenvl.js.map +1 -0
- package/dist/model/adapters/showui.d.ts +1 -0
- package/dist/model/adapters/showui.js +132 -0
- package/dist/model/adapters/showui.js.map +1 -0
- package/dist/model/adapters/tool-call.d.ts +6 -0
- package/dist/model/adapters/tool-call.js +102 -0
- package/dist/model/adapters/tool-call.js.map +1 -0
- package/dist/model/adapters/uitars.d.ts +1 -0
- package/dist/model/adapters/uitars.js +180 -0
- package/dist/model/adapters/uitars.js.map +1 -0
- package/dist/model/base.d.ts +32 -0
- package/dist/model/base.js +2 -0
- package/dist/model/base.js.map +1 -0
- package/dist/model/client.d.ts +26 -0
- package/dist/model/client.js +300 -0
- package/dist/model/client.js.map +1 -0
- package/dist/model/image/compress.d.ts +53 -0
- package/dist/model/image/compress.js +89 -0
- package/dist/model/image/compress.js.map +1 -0
- package/dist/model/image/transport.d.ts +134 -0
- package/dist/model/image/transport.js +154 -0
- package/dist/model/image/transport.js.map +1 -0
- package/dist/orchestrator-system-prompt.d.ts +6 -0
- package/dist/orchestrator-system-prompt.js +81 -0
- package/dist/orchestrator-system-prompt.js.map +1 -0
- package/dist/pi-context.d.ts +82 -0
- package/dist/pi-context.js +62 -0
- package/dist/pi-context.js.map +1 -0
- package/dist/pi-local-skills.d.ts +17 -0
- package/dist/pi-local-skills.js +24 -0
- package/dist/pi-local-skills.js.map +1 -0
- package/dist/plugins/acp/index.d.ts +46 -0
- package/dist/plugins/acp/index.js +111 -0
- package/dist/plugins/acp/index.js.map +1 -0
- package/dist/plugins/agent-sync/index.d.ts +40 -0
- package/dist/plugins/agent-sync/index.js +98 -0
- package/dist/plugins/agent-sync/index.js.map +1 -0
- package/dist/plugins/http-debug/index.d.ts +30 -0
- package/dist/plugins/http-debug/index.js +64 -0
- package/dist/plugins/http-debug/index.js.map +1 -0
- package/dist/plugins/http-debug/server.d.ts +92 -0
- package/dist/plugins/http-debug/server.js +464 -0
- package/dist/plugins/http-debug/server.js.map +1 -0
- package/dist/ports/agent-core.d.ts +158 -0
- package/dist/ports/agent-core.js +2 -0
- package/dist/ports/agent-core.js.map +1 -0
- package/dist/ports/agent-host.d.ts +125 -0
- package/dist/ports/agent-host.js +23 -0
- package/dist/ports/agent-host.js.map +1 -0
- package/dist/ports/device.d.ts +53 -0
- package/dist/ports/device.js +13 -0
- package/dist/ports/device.js.map +1 -0
- package/dist/ports/identity.d.ts +22 -0
- package/dist/ports/identity.js +9 -0
- package/dist/ports/identity.js.map +1 -0
- package/dist/ports/plugin.d.ts +62 -0
- package/dist/ports/plugin.js +35 -0
- package/dist/ports/plugin.js.map +1 -0
- package/dist/ports/transport.d.ts +32 -0
- package/dist/ports/transport.js +12 -0
- package/dist/ports/transport.js.map +1 -0
- package/dist/ports/vlm.d.ts +59 -0
- package/dist/ports/vlm.js +14 -0
- package/dist/ports/vlm.js.map +1 -0
- package/dist/test-lan-autoglm.d.ts +7 -0
- package/dist/test-lan-autoglm.js +46 -0
- package/dist/test-lan-autoglm.js.map +1 -0
- package/dist/test-mem-breakdown.d.ts +1 -0
- package/dist/test-mem-breakdown.js +103 -0
- package/dist/test-mem-breakdown.js.map +1 -0
- package/dist/test-mem.d.ts +1 -0
- package/dist/test-mem.js +60 -0
- package/dist/test-mem.js.map +1 -0
- package/dist/test-mobile-use.d.ts +1 -0
- package/dist/test-mobile-use.js +18 -0
- package/dist/test-mobile-use.js.map +1 -0
- package/dist/test-screenshot-loop.d.ts +1 -0
- package/dist/test-screenshot-loop.js +43 -0
- package/dist/test-screenshot-loop.js.map +1 -0
- package/dist/test-screenshot.d.ts +1 -0
- package/dist/test-screenshot.js +10 -0
- package/dist/test-screenshot.js.map +1 -0
- package/dist/test-ui-xml-dump.d.ts +15 -0
- package/dist/test-ui-xml-dump.js +49 -0
- package/dist/test-ui-xml-dump.js.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.js +23 -0
- package/dist/types.js.map +1 -0
- package/package.json +94 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter — sticky port allocator backed by `~/.beeos/fleet.json`.
|
|
3
|
+
*
|
|
4
|
+
* Sticky semantics: once a serial is mapped to a port, that mapping is kept
|
|
5
|
+
* indefinitely so users can bookmark / paste the URL. The allocator only
|
|
6
|
+
* forgets a mapping if the persisted port collides with another listener at
|
|
7
|
+
* acquire time — then we probe the next free port within the configured
|
|
8
|
+
* range.
|
|
9
|
+
*
|
|
10
|
+
* Range: configurable, defaults to `[7900, 7999]` (matches the historical
|
|
11
|
+
* device-mcp-server default of 7900). 100 slots × per-laptop scale is plenty
|
|
12
|
+
* even for power users running 30 devices.
|
|
13
|
+
*/
|
|
14
|
+
import * as fs from "node:fs";
|
|
15
|
+
import * as net from "node:net";
|
|
16
|
+
import * as os from "node:os";
|
|
17
|
+
import * as path from "node:path";
|
|
18
|
+
const DEFAULT_BASE = 7900;
|
|
19
|
+
const DEFAULT_RANGE = 100;
|
|
20
|
+
const FALLBACK_PORT = 7900;
|
|
21
|
+
export class StickyPortAllocator {
|
|
22
|
+
filePath;
|
|
23
|
+
basePort;
|
|
24
|
+
rangeSize;
|
|
25
|
+
probe;
|
|
26
|
+
map = new Map();
|
|
27
|
+
writeQueue = Promise.resolve();
|
|
28
|
+
started = false;
|
|
29
|
+
constructor(opts = {}) {
|
|
30
|
+
this.filePath = opts.filePath ?? defaultFleetStatePath();
|
|
31
|
+
this.basePort = opts.basePort ?? DEFAULT_BASE;
|
|
32
|
+
this.rangeSize = opts.rangeSize ?? DEFAULT_RANGE;
|
|
33
|
+
this.probe = opts.probe ?? defaultProbe;
|
|
34
|
+
}
|
|
35
|
+
async start() {
|
|
36
|
+
if (this.started)
|
|
37
|
+
return;
|
|
38
|
+
this.started = true;
|
|
39
|
+
await this.load();
|
|
40
|
+
}
|
|
41
|
+
async stop() {
|
|
42
|
+
this.started = false;
|
|
43
|
+
await this.writeQueue;
|
|
44
|
+
}
|
|
45
|
+
async acquire(serial) {
|
|
46
|
+
if (!this.started)
|
|
47
|
+
await this.start();
|
|
48
|
+
const sticky = this.map.get(serial);
|
|
49
|
+
const hint = sticky ?? this.hintFor(serial);
|
|
50
|
+
const port = await this.findAvailable(serial, hint);
|
|
51
|
+
if (this.map.get(serial) !== port) {
|
|
52
|
+
this.map.set(serial, port);
|
|
53
|
+
this.flush();
|
|
54
|
+
}
|
|
55
|
+
return port;
|
|
56
|
+
}
|
|
57
|
+
async release(serial) {
|
|
58
|
+
// Sticky — we keep the mapping. This is a no-op by design but exposed
|
|
59
|
+
// for symmetry. Tests may call `forget` (below) for full reset.
|
|
60
|
+
void serial;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
/** Test/maintenance helper: drop the persisted mapping for a serial. */
|
|
64
|
+
forget(serial) {
|
|
65
|
+
if (this.map.delete(serial))
|
|
66
|
+
this.flush();
|
|
67
|
+
}
|
|
68
|
+
snapshot() {
|
|
69
|
+
return new Map(this.map);
|
|
70
|
+
}
|
|
71
|
+
// ── Internals ────────────────────────────────────────────────────────────
|
|
72
|
+
hintFor(serial) {
|
|
73
|
+
// Stable hash → base + (h % range). Avoids "everyone gets 7900" stampede.
|
|
74
|
+
let h = 2166136261; // FNV-1a
|
|
75
|
+
for (let i = 0; i < serial.length; i++) {
|
|
76
|
+
h ^= serial.charCodeAt(i);
|
|
77
|
+
h = Math.imul(h, 16777619);
|
|
78
|
+
}
|
|
79
|
+
return this.basePort + (Math.abs(h) % this.rangeSize);
|
|
80
|
+
}
|
|
81
|
+
async findAvailable(serial, hint) {
|
|
82
|
+
// Probe `hint` first (so sticky mappings re-acquire the same port), then
|
|
83
|
+
// walk the rest of the range. We don't take ports outside the configured
|
|
84
|
+
// range — easier to firewall.
|
|
85
|
+
const candidates = [];
|
|
86
|
+
if (hint >= this.basePort && hint < this.basePort + this.rangeSize) {
|
|
87
|
+
candidates.push(hint);
|
|
88
|
+
}
|
|
89
|
+
for (let i = 0; i < this.rangeSize; i++) {
|
|
90
|
+
const p = this.basePort + i;
|
|
91
|
+
if (!candidates.includes(p))
|
|
92
|
+
candidates.push(p);
|
|
93
|
+
}
|
|
94
|
+
// Skip ports already assigned to OTHER serials (in-memory). The current
|
|
95
|
+
// serial's own existing mapping is allowed (sticky re-acquire).
|
|
96
|
+
const occupiedByOthers = new Set();
|
|
97
|
+
for (const [s, p] of this.map) {
|
|
98
|
+
if (s !== serial)
|
|
99
|
+
occupiedByOthers.add(p);
|
|
100
|
+
}
|
|
101
|
+
for (const port of candidates) {
|
|
102
|
+
if (occupiedByOthers.has(port))
|
|
103
|
+
continue;
|
|
104
|
+
const free = await this.probe(port);
|
|
105
|
+
if (free)
|
|
106
|
+
return port;
|
|
107
|
+
}
|
|
108
|
+
return FALLBACK_PORT;
|
|
109
|
+
}
|
|
110
|
+
async load() {
|
|
111
|
+
let raw;
|
|
112
|
+
try {
|
|
113
|
+
raw = await fs.promises.readFile(this.filePath, "utf8");
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
const parsed = JSON.parse(raw);
|
|
120
|
+
if (!parsed || parsed.v !== 1 || !parsed.ports)
|
|
121
|
+
return;
|
|
122
|
+
for (const [serial, port] of Object.entries(parsed.ports)) {
|
|
123
|
+
if (typeof port === "number" && port >= 1024 && port < 65536) {
|
|
124
|
+
this.map.set(serial, port);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
/* corrupt — start clean */
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
flush() {
|
|
133
|
+
const snap = {
|
|
134
|
+
v: 1,
|
|
135
|
+
ports: Object.fromEntries(this.map.entries()),
|
|
136
|
+
};
|
|
137
|
+
const dir = path.dirname(this.filePath);
|
|
138
|
+
const data = JSON.stringify(snap, null, 2);
|
|
139
|
+
this.writeQueue = this.writeQueue.then(async () => {
|
|
140
|
+
try {
|
|
141
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
142
|
+
await fs.promises.writeFile(this.filePath, data, "utf8");
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
/* best-effort */
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// ── Pure helpers (exported for tests) ────────────────────────────────────────
|
|
151
|
+
export function defaultFleetStatePath() {
|
|
152
|
+
const override = process.env.BEEOS_HOME;
|
|
153
|
+
const base = override && override.length > 0
|
|
154
|
+
? override
|
|
155
|
+
: path.join(os.homedir(), ".beeos");
|
|
156
|
+
return path.join(base, "fleet.json");
|
|
157
|
+
}
|
|
158
|
+
async function defaultProbe(port) {
|
|
159
|
+
return await new Promise((resolve) => {
|
|
160
|
+
const srv = net.createServer();
|
|
161
|
+
srv.once("error", () => resolve(false));
|
|
162
|
+
srv.once("listening", () => {
|
|
163
|
+
srv.close(() => resolve(true));
|
|
164
|
+
});
|
|
165
|
+
try {
|
|
166
|
+
srv.listen(port, "127.0.0.1");
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
resolve(false);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=port-allocator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-allocator.js","sourceRoot":"","sources":["../../../../src/fleet/adapters/state/port-allocator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,aAAa,GAAG,IAAI,CAAC;AAiB3B,MAAM,OAAO,mBAAmB;IACb,QAAQ,CAAS;IACjB,QAAQ,CAAS;IACjB,SAAS,CAAS;IAClB,KAAK,CAAqC;IACnD,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChC,UAAU,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAC9C,OAAO,GAAG,KAAK,CAAC;IAExB,YAAY,OAA6B,EAAE;QACzC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,qBAAqB,EAAE,CAAC;QACzD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,YAAY,CAAC;QAC9C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,aAAa,CAAC;QACjD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,MAAM,IAAI,CAAC,UAAU,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QAEtC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAEpD,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;YAClC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,sEAAsE;QACtE,gEAAgE;QAChE,KAAK,MAAM,CAAC;QACZ,OAAO;IACT,CAAC;IAED,wEAAwE;IACxE,MAAM,CAAC,MAAc;QACnB,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;YAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IAC5C,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,4EAA4E;IAEpE,OAAO,CAAC,MAAc;QAC5B,0EAA0E;QAC1E,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC,SAAS;QAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC1B,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;IACxD,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,MAAc,EAAE,IAAY;QACtD,yEAAyE;QACzE,yEAAyE;QACzE,8BAA8B;QAC9B,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,IAAI,IAAI,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;YACnE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC;QAED,wEAAwE;QACxE,gEAAgE;QAChE,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;QAC3C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YAC9B,IAAI,CAAC,KAAK,MAAM;gBAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5C,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAS;YACzC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,IAAI;gBAAE,OAAO,IAAI,CAAC;QACxB,CAAC;QAED,OAAO,aAAa,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;YACjD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK;gBAAE,OAAO;YACvD,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1D,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;oBAC7D,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,2BAA2B;QAC7B,CAAC;IACH,CAAC;IAEO,KAAK;QACX,MAAM,IAAI,GAAmB;YAC3B,CAAC,EAAE,CAAC;YACJ,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;SAC9C,CAAC;QACF,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAE3C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;YAChD,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAClD,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;YAC3D,CAAC;YAAC,MAAM,CAAC;gBACP,iBAAiB;YACnB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED,gFAAgF;AAEhF,MAAM,UAAU,qBAAqB;IACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACxC,MAAM,IAAI,GAAG,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAC1C,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;IACtC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;AACvC,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAY;IACtC,OAAO,MAAM,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;QAC5C,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAC/B,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;YACzB,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC;YACH,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fleet domain — `Device` entity and lifecycle state.
|
|
3
|
+
*
|
|
4
|
+
* A `Device` represents one ADB-connected target (real phone, ReDroid container,
|
|
5
|
+
* remote `host:port`) under fleet supervision. Each device transitions through
|
|
6
|
+
* the FSM defined in `./fsm.ts` driven by ADB / process / config / timer events.
|
|
7
|
+
*
|
|
8
|
+
* The FSM has 9 named states; see the lifecycle diagram in
|
|
9
|
+
* `agents/device-agent/CHANGELOG.md` (or the v4 plan) for the full picture.
|
|
10
|
+
*
|
|
11
|
+
* Layered decay (HEALTHY → GRACE → DEGRADED → GONE):
|
|
12
|
+
* - GRACE keeps mcp + daemon alive for a short window so USB jitter is
|
|
13
|
+
* transparent to the user.
|
|
14
|
+
* - DEGRADED tears down mcp (which is tightly coupled to ADB pipes) but
|
|
15
|
+
* retains the daemon so the BeeOS session and Centrifugo subscription
|
|
16
|
+
* survive transient outages.
|
|
17
|
+
* - GONE is reached only after a long absence; the daemon is finally killed
|
|
18
|
+
* and the user-side session is paused.
|
|
19
|
+
*
|
|
20
|
+
* Tunables (`grace_ms`, `keep_ms`) come from env vars or per-device entries in
|
|
21
|
+
* `~/.beeos/devices.json`; see {@link DeviceBinding}.
|
|
22
|
+
*/
|
|
23
|
+
/** All FSM states a device can occupy. */
|
|
24
|
+
export type FleetState = "adb_offline" | "adb_unauthorized" | "awaiting_bind" | "spawning" | "healthy" | "grace" | "degraded" | "gone" | "crashed";
|
|
25
|
+
/**
|
|
26
|
+
* Whether a state owns child processes (mcp/daemon) at all. Useful for the
|
|
27
|
+
* supervisor to decide whether `kill_*` effects are no-ops.
|
|
28
|
+
*/
|
|
29
|
+
export declare function stateExpectsMcp(s: FleetState): boolean;
|
|
30
|
+
export declare function stateExpectsDaemon(s: FleetState): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Per-device binding loaded from `~/.beeos/devices.json` (the file owned by
|
|
33
|
+
* `web/packages/cli` `attach` / `detach`). Fleet treats the file as read-only;
|
|
34
|
+
* `beeos device attach` is the writer. `instance_id === null` means the user
|
|
35
|
+
* started attach but didn't complete the platform bind step — fleet must NOT
|
|
36
|
+
* spawn anything for those entries (treat as `awaiting_bind`).
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* Canonical backend names used by `device-mcp-server` (and forwarded as
|
|
40
|
+
* `--backend <name>` by the fleet's process manager). Pre-self-hosted
|
|
41
|
+
* `devices.json` files don't carry this field; the supervisor treats
|
|
42
|
+
* `undefined` as `adb` for back-compat with v0.1 ADB-only attaches.
|
|
43
|
+
*
|
|
44
|
+
* Aliases (`android`/`mac`/`win`/`desktop-{linux,windows,macos}`) are
|
|
45
|
+
* accepted on read and normalized to the canonical short name in
|
|
46
|
+
* `toBinding`. See plan §3.4.
|
|
47
|
+
*/
|
|
48
|
+
export type FleetBackend = "adb" | "macos" | "linux" | "windows" | "desktop" | "mock-desktop";
|
|
49
|
+
export interface DeviceBinding {
|
|
50
|
+
serial: string;
|
|
51
|
+
name: string;
|
|
52
|
+
instanceId: string | null;
|
|
53
|
+
keyFile: string;
|
|
54
|
+
/** Persisted http_port from `web/packages/cli`. Fleet honours it for the daemon's HTTP debug port (sticky). */
|
|
55
|
+
httpPort?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Video backend selection inherited from `devices.json#video_mode`. Drives
|
|
58
|
+
* whether the supervisor co-spawns `scrcpy-bridge` alongside mcp + daemon.
|
|
59
|
+
*
|
|
60
|
+
* - `"scrcpy"` — Android/ADB device (default for ADB serials)
|
|
61
|
+
* - `"vnc"` — desktop/macOS/Linux device with a VNC server (vnc-bridge
|
|
62
|
+
* is OS-service-managed, not fleet-managed)
|
|
63
|
+
* - `"none"` — explicit opt-out (e.g. CI)
|
|
64
|
+
* - `undefined` — fleet treats as "no scrcpy" to stay backwards
|
|
65
|
+
* compatible with older devices.json entries
|
|
66
|
+
*/
|
|
67
|
+
videoMode?: "scrcpy" | "vnc" | "none";
|
|
68
|
+
/**
|
|
69
|
+
* `device-mcp-server --backend <name>` selection. Drives which capability
|
|
70
|
+
* set the spawned MCP server exposes. `undefined` is interpreted as `adb`
|
|
71
|
+
* by the fleet for back-compat (the v0.1 attach flow only ever bound ADB
|
|
72
|
+
* devices). See {@link FleetBackend}.
|
|
73
|
+
*/
|
|
74
|
+
backend?: FleetBackend;
|
|
75
|
+
/** Optional per-device override of `FLEET_ADB_GRACE_MS` (HEALTHY → DEGRADED). */
|
|
76
|
+
graceMs?: number;
|
|
77
|
+
/** Optional per-device override of `FLEET_DAEMON_KEEP_MS` (DEGRADED → GONE). */
|
|
78
|
+
keepMs?: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* In-memory FSM record for a single device. The supervisor mutates this via
|
|
82
|
+
* the pure `step()` function in `./fsm.ts`. PIDs and timer handles live
|
|
83
|
+
* outside the FSM (the supervisor manages them) so the FSM stays pure /
|
|
84
|
+
* snapshottable.
|
|
85
|
+
*/
|
|
86
|
+
export interface DeviceRecord {
|
|
87
|
+
serial: string;
|
|
88
|
+
name: string;
|
|
89
|
+
state: FleetState;
|
|
90
|
+
binding: DeviceBinding | null;
|
|
91
|
+
/** Monotonic ms timestamp when `state` was last entered. */
|
|
92
|
+
enteredAt: number;
|
|
93
|
+
/** Increments on each unexpected child-process exit while ADB was online. */
|
|
94
|
+
restartCount: number;
|
|
95
|
+
/** Allocated mcp-server port (sticky across restarts). `0` means unallocated. */
|
|
96
|
+
mcpPort: number;
|
|
97
|
+
}
|
|
98
|
+
/** Convenient initial value for a freshly-discovered ADB device. */
|
|
99
|
+
export declare function newDeviceRecord(args: {
|
|
100
|
+
serial: string;
|
|
101
|
+
name?: string;
|
|
102
|
+
binding?: DeviceBinding | null;
|
|
103
|
+
state?: FleetState;
|
|
104
|
+
now: number;
|
|
105
|
+
}): DeviceRecord;
|
|
106
|
+
/** Liveness summary for the optional scrcpy-bridge sibling. */
|
|
107
|
+
export interface ScrcpyStatus {
|
|
108
|
+
/**
|
|
109
|
+
* Whether the device's binding requested scrcpy at all (i.e. `videoMode
|
|
110
|
+
* === "scrcpy"`). When `false`, all other fields are meaningless and the
|
|
111
|
+
* supervisor does not co-spawn scrcpy-bridge.
|
|
112
|
+
*/
|
|
113
|
+
enabled: boolean;
|
|
114
|
+
/** True iff the supervisor currently observes the scrcpy-bridge child as alive. */
|
|
115
|
+
running: boolean;
|
|
116
|
+
pid: number | null;
|
|
117
|
+
/** Last error/reason recorded for scrcpy-bridge (binary missing, startup_failed, …). */
|
|
118
|
+
lastError: string | null;
|
|
119
|
+
}
|
|
120
|
+
/** A snapshot exported through the HTTP `/fleet/devices` endpoint. */
|
|
121
|
+
export interface DeviceSnapshot {
|
|
122
|
+
serial: string;
|
|
123
|
+
name: string;
|
|
124
|
+
instanceId: string | null;
|
|
125
|
+
state: FleetState;
|
|
126
|
+
mcpUrl: string | null;
|
|
127
|
+
mcpPid: number | null;
|
|
128
|
+
daemonPid: number | null;
|
|
129
|
+
/**
|
|
130
|
+
* scrcpy-bridge sibling status. Always present (even when scrcpy is
|
|
131
|
+
* disabled for the device) so that consumers can render a stable shape.
|
|
132
|
+
*/
|
|
133
|
+
scrcpy: ScrcpyStatus;
|
|
134
|
+
enteredAt: number;
|
|
135
|
+
/** ms since the FSM entered the current state, computed at read time. */
|
|
136
|
+
sinceMs: number;
|
|
137
|
+
restartCount: number;
|
|
138
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fleet domain — `Device` entity and lifecycle state.
|
|
3
|
+
*
|
|
4
|
+
* A `Device` represents one ADB-connected target (real phone, ReDroid container,
|
|
5
|
+
* remote `host:port`) under fleet supervision. Each device transitions through
|
|
6
|
+
* the FSM defined in `./fsm.ts` driven by ADB / process / config / timer events.
|
|
7
|
+
*
|
|
8
|
+
* The FSM has 9 named states; see the lifecycle diagram in
|
|
9
|
+
* `agents/device-agent/CHANGELOG.md` (or the v4 plan) for the full picture.
|
|
10
|
+
*
|
|
11
|
+
* Layered decay (HEALTHY → GRACE → DEGRADED → GONE):
|
|
12
|
+
* - GRACE keeps mcp + daemon alive for a short window so USB jitter is
|
|
13
|
+
* transparent to the user.
|
|
14
|
+
* - DEGRADED tears down mcp (which is tightly coupled to ADB pipes) but
|
|
15
|
+
* retains the daemon so the BeeOS session and Centrifugo subscription
|
|
16
|
+
* survive transient outages.
|
|
17
|
+
* - GONE is reached only after a long absence; the daemon is finally killed
|
|
18
|
+
* and the user-side session is paused.
|
|
19
|
+
*
|
|
20
|
+
* Tunables (`grace_ms`, `keep_ms`) come from env vars or per-device entries in
|
|
21
|
+
* `~/.beeos/devices.json`; see {@link DeviceBinding}.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Whether a state owns child processes (mcp/daemon) at all. Useful for the
|
|
25
|
+
* supervisor to decide whether `kill_*` effects are no-ops.
|
|
26
|
+
*/
|
|
27
|
+
export function stateExpectsMcp(s) {
|
|
28
|
+
return s === "healthy" || s === "grace" || s === "spawning" || s === "crashed";
|
|
29
|
+
}
|
|
30
|
+
export function stateExpectsDaemon(s) {
|
|
31
|
+
return (s === "healthy" ||
|
|
32
|
+
s === "grace" ||
|
|
33
|
+
s === "degraded" ||
|
|
34
|
+
s === "spawning" ||
|
|
35
|
+
s === "crashed");
|
|
36
|
+
}
|
|
37
|
+
/** Convenient initial value for a freshly-discovered ADB device. */
|
|
38
|
+
export function newDeviceRecord(args) {
|
|
39
|
+
return {
|
|
40
|
+
serial: args.serial,
|
|
41
|
+
name: args.name ?? args.binding?.name ?? args.serial,
|
|
42
|
+
state: args.state ?? "adb_offline",
|
|
43
|
+
binding: args.binding ?? null,
|
|
44
|
+
enteredAt: args.now,
|
|
45
|
+
restartCount: 0,
|
|
46
|
+
mcpPort: 0,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=device.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.js","sourceRoot":"","sources":["../../../src/fleet/domain/device.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAcH;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,CAAa;IAC3C,OAAO,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,UAAU,IAAI,CAAC,KAAK,SAAS,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,CAAa;IAC9C,OAAO,CACL,CAAC,KAAK,SAAS;QACf,CAAC,KAAK,OAAO;QACb,CAAC,KAAK,UAAU;QAChB,CAAC,KAAK,UAAU;QAChB,CAAC,KAAK,SAAS,CAChB,CAAC;AACJ,CAAC;AA8ED,oEAAoE;AACpE,MAAM,UAAU,eAAe,CAAC,IAM/B;IACC,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC,MAAM;QACpD,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,aAAa;QAClC,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI;QAC7B,SAAS,EAAE,IAAI,CAAC,GAAG;QACnB,YAAY,EAAE,CAAC;QACf,OAAO,EAAE,CAAC;KACX,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fleet domain — event types fed into the FSM (`./fsm.ts`).
|
|
3
|
+
*
|
|
4
|
+
* Events are produced by adapters:
|
|
5
|
+
* - `LocalAdbSource` / `RemoteAdbSource` → `AdbEvent` (online / offline / unauthorized)
|
|
6
|
+
* - `BeeosCliStore` watcher → `BindingEvent`
|
|
7
|
+
* - `ProcessManager` → `ProcessEvent` (spawn ack, exit, health)
|
|
8
|
+
* - In-process timers → `TimerEvent` (grace expiry, keep expiry, restart backoff)
|
|
9
|
+
*
|
|
10
|
+
* The FSM is purely a `(state, event) => { next, effects }` reducer; effects
|
|
11
|
+
* are descriptions (e.g. `{ kind: "spawn_mcp", serial }`) that the supervisor
|
|
12
|
+
* translates into real `child_process.spawn` calls and timer handles.
|
|
13
|
+
*/
|
|
14
|
+
export interface AdbOnlineEvent {
|
|
15
|
+
kind: "adb_online";
|
|
16
|
+
serial: string;
|
|
17
|
+
}
|
|
18
|
+
export interface AdbOfflineEvent {
|
|
19
|
+
kind: "adb_offline";
|
|
20
|
+
serial: string;
|
|
21
|
+
}
|
|
22
|
+
export interface AdbUnauthorizedEvent {
|
|
23
|
+
kind: "adb_unauthorized";
|
|
24
|
+
serial: string;
|
|
25
|
+
}
|
|
26
|
+
export type AdbEvent = AdbOnlineEvent | AdbOfflineEvent | AdbUnauthorizedEvent;
|
|
27
|
+
export interface BindingAddedEvent {
|
|
28
|
+
kind: "binding_added";
|
|
29
|
+
serial: string;
|
|
30
|
+
}
|
|
31
|
+
export interface BindingChangedEvent {
|
|
32
|
+
kind: "binding_changed";
|
|
33
|
+
serial: string;
|
|
34
|
+
}
|
|
35
|
+
export interface BindingRemovedEvent {
|
|
36
|
+
kind: "binding_removed";
|
|
37
|
+
serial: string;
|
|
38
|
+
}
|
|
39
|
+
export type BindingEvent = BindingAddedEvent | BindingChangedEvent | BindingRemovedEvent;
|
|
40
|
+
export interface McpStartedEvent {
|
|
41
|
+
kind: "mcp_started";
|
|
42
|
+
serial: string;
|
|
43
|
+
pid: number;
|
|
44
|
+
port: number;
|
|
45
|
+
}
|
|
46
|
+
export interface McpExitedEvent {
|
|
47
|
+
kind: "mcp_exited";
|
|
48
|
+
serial: string;
|
|
49
|
+
/** Process exit code (null when killed by signal). */
|
|
50
|
+
code: number | null;
|
|
51
|
+
/** UNIX signal name when killed by signal (`SIGTERM`, `SIGKILL`, …). */
|
|
52
|
+
signal: NodeJS.Signals | null;
|
|
53
|
+
/** True if fleet asked for the kill (so the FSM should not penalise restartCount). */
|
|
54
|
+
expected: boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface DaemonStartedEvent {
|
|
57
|
+
kind: "daemon_started";
|
|
58
|
+
serial: string;
|
|
59
|
+
pid: number;
|
|
60
|
+
}
|
|
61
|
+
export interface DaemonExitedEvent {
|
|
62
|
+
kind: "daemon_exited";
|
|
63
|
+
serial: string;
|
|
64
|
+
code: number | null;
|
|
65
|
+
signal: NodeJS.Signals | null;
|
|
66
|
+
expected: boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* `scrcpy-bridge` is an OPTIONAL sibling we co-supervise alongside
|
|
70
|
+
* mcp + daemon when `video_mode === "scrcpy"`. The pure FSM ignores
|
|
71
|
+
* these events (scrcpy lifecycle does not gate `healthy`); the
|
|
72
|
+
* supervisor uses them solely for the `/fleet/devices` snapshot.
|
|
73
|
+
*/
|
|
74
|
+
export interface ScrcpyStartedEvent {
|
|
75
|
+
kind: "scrcpy_started";
|
|
76
|
+
serial: string;
|
|
77
|
+
pid: number;
|
|
78
|
+
}
|
|
79
|
+
export interface ScrcpyExitedEvent {
|
|
80
|
+
kind: "scrcpy_exited";
|
|
81
|
+
serial: string;
|
|
82
|
+
code: number | null;
|
|
83
|
+
signal: NodeJS.Signals | null;
|
|
84
|
+
expected: boolean;
|
|
85
|
+
/** Optional human-readable reason (binary missing, spawn failure, …). */
|
|
86
|
+
reason?: string;
|
|
87
|
+
}
|
|
88
|
+
export type ProcessEvent = McpStartedEvent | McpExitedEvent | DaemonStartedEvent | DaemonExitedEvent | ScrcpyStartedEvent | ScrcpyExitedEvent;
|
|
89
|
+
export interface GraceExpiredEvent {
|
|
90
|
+
kind: "grace_expired";
|
|
91
|
+
serial: string;
|
|
92
|
+
}
|
|
93
|
+
export interface KeepExpiredEvent {
|
|
94
|
+
kind: "keep_expired";
|
|
95
|
+
serial: string;
|
|
96
|
+
}
|
|
97
|
+
export interface BackoffElapsedEvent {
|
|
98
|
+
kind: "backoff_elapsed";
|
|
99
|
+
serial: string;
|
|
100
|
+
}
|
|
101
|
+
export type TimerEvent = GraceExpiredEvent | KeepExpiredEvent | BackoffElapsedEvent;
|
|
102
|
+
export type FleetEvent = AdbEvent | BindingEvent | ProcessEvent | TimerEvent;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fleet domain — event types fed into the FSM (`./fsm.ts`).
|
|
3
|
+
*
|
|
4
|
+
* Events are produced by adapters:
|
|
5
|
+
* - `LocalAdbSource` / `RemoteAdbSource` → `AdbEvent` (online / offline / unauthorized)
|
|
6
|
+
* - `BeeosCliStore` watcher → `BindingEvent`
|
|
7
|
+
* - `ProcessManager` → `ProcessEvent` (spawn ack, exit, health)
|
|
8
|
+
* - In-process timers → `TimerEvent` (grace expiry, keep expiry, restart backoff)
|
|
9
|
+
*
|
|
10
|
+
* The FSM is purely a `(state, event) => { next, effects }` reducer; effects
|
|
11
|
+
* are descriptions (e.g. `{ kind: "spawn_mcp", serial }`) that the supervisor
|
|
12
|
+
* translates into real `child_process.spawn` calls and timer handles.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/fleet/domain/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fleet domain — pure FSM reducer.
|
|
3
|
+
*
|
|
4
|
+
* Single entry point: `step(record, event, ctx) => { record', effects }`.
|
|
5
|
+
*
|
|
6
|
+
* Effects are *intent descriptors* the supervisor (`fleet/supervisor.ts`)
|
|
7
|
+
* translates into actual side effects (process spawn, timer, log line). This
|
|
8
|
+
* keeps the FSM trivially testable — the M1 unit suite covers the entire
|
|
9
|
+
* lifecycle without any IO.
|
|
10
|
+
*
|
|
11
|
+
* Lifecycle (see also v4 plan):
|
|
12
|
+
* adb_offline ─► (adb_online + bound) ─► spawning ─► healthy
|
|
13
|
+
* (adb_online + unbound) ─► awaiting_bind
|
|
14
|
+
* (adb_online + unauthorized) ─► adb_unauthorized
|
|
15
|
+
* healthy ─► (adb_offline) ─► grace
|
|
16
|
+
* grace ─► (adb_online same serial) ─► healthy (USB jitter, transparent)
|
|
17
|
+
* (grace_expired) ─► degraded (kill mcp only, daemon survives)
|
|
18
|
+
* degraded ─► (adb_online same serial) ─► spawning (respawn mcp, daemon self-heals)
|
|
19
|
+
* (keep_expired) ─► gone (kill daemon, session paused)
|
|
20
|
+
* gone ─► (adb_online) ─► spawning
|
|
21
|
+
* healthy ─► (mcp_exited unexpected) ─► spawning (mcp_only_restart)
|
|
22
|
+
* (daemon_exited unexpected) ─► spawning (daemon_only_restart)
|
|
23
|
+
* (both crashed back-to-back) ─► crashed → spawning
|
|
24
|
+
*
|
|
25
|
+
* The reducer never reads outside its inputs (`record`, `event`, `ctx`) — pure.
|
|
26
|
+
*/
|
|
27
|
+
import type { DeviceRecord } from "./device.js";
|
|
28
|
+
import type { FleetEvent } from "./events.js";
|
|
29
|
+
export interface SpawnMcpEffect {
|
|
30
|
+
kind: "spawn_mcp";
|
|
31
|
+
serial: string;
|
|
32
|
+
}
|
|
33
|
+
export interface KillMcpEffect {
|
|
34
|
+
kind: "kill_mcp";
|
|
35
|
+
serial: string;
|
|
36
|
+
/** When true, supervisor records the kill as fleet-initiated → expected exit. */
|
|
37
|
+
expected: true;
|
|
38
|
+
}
|
|
39
|
+
export interface SpawnDaemonEffect {
|
|
40
|
+
kind: "spawn_daemon";
|
|
41
|
+
serial: string;
|
|
42
|
+
}
|
|
43
|
+
export interface KillDaemonEffect {
|
|
44
|
+
kind: "kill_daemon";
|
|
45
|
+
serial: string;
|
|
46
|
+
expected: true;
|
|
47
|
+
}
|
|
48
|
+
export interface StartGraceTimerEffect {
|
|
49
|
+
kind: "start_grace_timer";
|
|
50
|
+
serial: string;
|
|
51
|
+
}
|
|
52
|
+
export interface CancelGraceTimerEffect {
|
|
53
|
+
kind: "cancel_grace_timer";
|
|
54
|
+
serial: string;
|
|
55
|
+
}
|
|
56
|
+
export interface StartKeepTimerEffect {
|
|
57
|
+
kind: "start_keep_timer";
|
|
58
|
+
serial: string;
|
|
59
|
+
}
|
|
60
|
+
export interface CancelKeepTimerEffect {
|
|
61
|
+
kind: "cancel_keep_timer";
|
|
62
|
+
serial: string;
|
|
63
|
+
}
|
|
64
|
+
export interface StartBackoffTimerEffect {
|
|
65
|
+
kind: "start_backoff_timer";
|
|
66
|
+
serial: string;
|
|
67
|
+
/** How many failed restarts have already happened. */
|
|
68
|
+
attempt: number;
|
|
69
|
+
}
|
|
70
|
+
export interface CancelBackoffTimerEffect {
|
|
71
|
+
kind: "cancel_backoff_timer";
|
|
72
|
+
serial: string;
|
|
73
|
+
}
|
|
74
|
+
export interface AllocatePortEffect {
|
|
75
|
+
kind: "allocate_port";
|
|
76
|
+
serial: string;
|
|
77
|
+
}
|
|
78
|
+
export interface ReleasePortEffect {
|
|
79
|
+
kind: "release_port";
|
|
80
|
+
serial: string;
|
|
81
|
+
}
|
|
82
|
+
export interface LogEffect {
|
|
83
|
+
kind: "log";
|
|
84
|
+
level: "debug" | "info" | "warn" | "error";
|
|
85
|
+
serial: string;
|
|
86
|
+
msg: string;
|
|
87
|
+
data?: Record<string, unknown>;
|
|
88
|
+
}
|
|
89
|
+
export type FleetEffect = SpawnMcpEffect | KillMcpEffect | SpawnDaemonEffect | KillDaemonEffect | StartGraceTimerEffect | CancelGraceTimerEffect | StartKeepTimerEffect | CancelKeepTimerEffect | StartBackoffTimerEffect | CancelBackoffTimerEffect | AllocatePortEffect | ReleasePortEffect | LogEffect;
|
|
90
|
+
export interface StepContext {
|
|
91
|
+
/** Monotonic ms (used to set `enteredAt` on transitions). */
|
|
92
|
+
now: number;
|
|
93
|
+
}
|
|
94
|
+
export interface StepResult {
|
|
95
|
+
record: DeviceRecord;
|
|
96
|
+
effects: FleetEffect[];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Pure FSM reducer.
|
|
100
|
+
*
|
|
101
|
+
* Apply `event` to `record` and return the next `record` plus the effects the
|
|
102
|
+
* supervisor must enact. Events that the current state does not care about
|
|
103
|
+
* are no-ops (empty effects, identical record).
|
|
104
|
+
*
|
|
105
|
+
* Important: the supervisor MUST update `record.binding` before calling
|
|
106
|
+
* `step()` for binding events, because some transitions consult
|
|
107
|
+
* `record.binding.instanceId` to decide between `spawning` and
|
|
108
|
+
* `awaiting_bind`.
|
|
109
|
+
*/
|
|
110
|
+
export declare function step(record: DeviceRecord, event: FleetEvent, ctx: StepContext): StepResult;
|
|
111
|
+
/**
|
|
112
|
+
* Internal helper for the supervisor: when both children have been observed
|
|
113
|
+
* alive (mcp_started + daemon_started), the supervisor calls this to flip the
|
|
114
|
+
* record from `spawning` → `healthy`. Centralised here so the transition
|
|
115
|
+
* lives next to the rest of the state machine.
|
|
116
|
+
*/
|
|
117
|
+
export declare function markHealthy(record: DeviceRecord, ctx: StepContext): StepResult;
|
|
118
|
+
/**
|
|
119
|
+
* Backoff schedule used by the supervisor when arming the
|
|
120
|
+
* `start_backoff_timer` effect. Exponential with cap.
|
|
121
|
+
*/
|
|
122
|
+
export declare function backoffMs(attempt: number): number;
|