@miosa/cli 1.3.4 → 2.1.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/README.md +20 -835
- package/bin/miosa.js +75 -0
- package/lib/archive.js +88 -0
- package/lib/checksums.js +29 -0
- package/lib/platforms.js +31 -0
- package/lib/resolve.js +47 -0
- package/package.json +26 -41
- package/scripts/postinstall.js +68 -0
- package/CHANGELOG.md +0 -110
- package/dist/action-authority.d.ts +0 -106
- package/dist/action-authority.d.ts.map +0 -1
- package/dist/action-authority.js +0 -116
- package/dist/action-authority.js.map +0 -1
- package/dist/app-advisor.d.ts +0 -80
- package/dist/app-advisor.d.ts.map +0 -1
- package/dist/app-advisor.js +0 -486
- package/dist/app-advisor.js.map +0 -1
- package/dist/app-contract.d.ts +0 -92
- package/dist/app-contract.d.ts.map +0 -1
- package/dist/app-contract.js +0 -218
- package/dist/app-contract.js.map +0 -1
- package/dist/app-document.d.ts +0 -23
- package/dist/app-document.d.ts.map +0 -1
- package/dist/app-document.js +0 -180
- package/dist/app-document.js.map +0 -1
- package/dist/app-manifest.d.ts +0 -140
- package/dist/app-manifest.d.ts.map +0 -1
- package/dist/app-manifest.js +0 -377
- package/dist/app-manifest.js.map +0 -1
- package/dist/app-operation.d.ts +0 -23
- package/dist/app-operation.d.ts.map +0 -1
- package/dist/app-operation.js +0 -49
- package/dist/app-operation.js.map +0 -1
- package/dist/app-release.d.ts +0 -132
- package/dist/app-release.d.ts.map +0 -1
- package/dist/app-release.js +0 -294
- package/dist/app-release.js.map +0 -1
- package/dist/bin/miosa.d.ts +0 -3
- package/dist/bin/miosa.d.ts.map +0 -1
- package/dist/bin/miosa.js +0 -288
- package/dist/bin/miosa.js.map +0 -1
- package/dist/cli-env.d.ts +0 -12
- package/dist/cli-env.d.ts.map +0 -1
- package/dist/cli-env.js +0 -34
- package/dist/cli-env.js.map +0 -1
- package/dist/client.d.ts +0 -155
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -865
- package/dist/client.js.map +0 -1
- package/dist/commands/actions.d.ts +0 -3
- package/dist/commands/actions.d.ts.map +0 -1
- package/dist/commands/actions.js +0 -222
- package/dist/commands/actions.js.map +0 -1
- package/dist/commands/agent-runtime-profiles.d.ts +0 -3
- package/dist/commands/agent-runtime-profiles.d.ts.map +0 -1
- package/dist/commands/agent-runtime-profiles.js +0 -198
- package/dist/commands/agent-runtime-profiles.js.map +0 -1
- package/dist/commands/agent.d.ts +0 -18
- package/dist/commands/agent.d.ts.map +0 -1
- package/dist/commands/agent.js +0 -737
- package/dist/commands/agent.js.map +0 -1
- package/dist/commands/alerts.d.ts +0 -3
- package/dist/commands/alerts.d.ts.map +0 -1
- package/dist/commands/alerts.js +0 -41
- package/dist/commands/alerts.js.map +0 -1
- package/dist/commands/api-keys.d.ts +0 -3
- package/dist/commands/api-keys.d.ts.map +0 -1
- package/dist/commands/api-keys.js +0 -160
- package/dist/commands/api-keys.js.map +0 -1
- package/dist/commands/api-resource.d.ts +0 -20
- package/dist/commands/api-resource.d.ts.map +0 -1
- package/dist/commands/api-resource.js +0 -120
- package/dist/commands/api-resource.js.map +0 -1
- package/dist/commands/app.d.ts +0 -38
- package/dist/commands/app.d.ts.map +0 -1
- package/dist/commands/app.js +0 -1182
- package/dist/commands/app.js.map +0 -1
- package/dist/commands/apps.d.ts +0 -3
- package/dist/commands/apps.d.ts.map +0 -1
- package/dist/commands/apps.js +0 -218
- package/dist/commands/apps.js.map +0 -1
- package/dist/commands/audit.d.ts +0 -3
- package/dist/commands/audit.d.ts.map +0 -1
- package/dist/commands/audit.js +0 -25
- package/dist/commands/audit.js.map +0 -1
- package/dist/commands/auth.d.ts +0 -3
- package/dist/commands/auth.d.ts.map +0 -1
- package/dist/commands/auth.js +0 -282
- package/dist/commands/auth.js.map +0 -1
- package/dist/commands/backups.d.ts +0 -3
- package/dist/commands/backups.d.ts.map +0 -1
- package/dist/commands/backups.js +0 -23
- package/dist/commands/backups.js.map +0 -1
- package/dist/commands/billing.d.ts +0 -3
- package/dist/commands/billing.d.ts.map +0 -1
- package/dist/commands/billing.js +0 -208
- package/dist/commands/billing.js.map +0 -1
- package/dist/commands/builds.d.ts +0 -3
- package/dist/commands/builds.d.ts.map +0 -1
- package/dist/commands/builds.js +0 -198
- package/dist/commands/builds.js.map +0 -1
- package/dist/commands/capabilities.d.ts +0 -3
- package/dist/commands/capabilities.d.ts.map +0 -1
- package/dist/commands/capabilities.js +0 -1002
- package/dist/commands/capabilities.js.map +0 -1
- package/dist/commands/checkpoints.d.ts +0 -3
- package/dist/commands/checkpoints.d.ts.map +0 -1
- package/dist/commands/checkpoints.js +0 -193
- package/dist/commands/checkpoints.js.map +0 -1
- package/dist/commands/cleanup.d.ts +0 -3
- package/dist/commands/cleanup.d.ts.map +0 -1
- package/dist/commands/cleanup.js +0 -65
- package/dist/commands/cleanup.js.map +0 -1
- package/dist/commands/cloud.d.ts +0 -3
- package/dist/commands/cloud.d.ts.map +0 -1
- package/dist/commands/cloud.js +0 -192
- package/dist/commands/cloud.js.map +0 -1
- package/dist/commands/command-overview.d.ts +0 -13
- package/dist/commands/command-overview.d.ts.map +0 -1
- package/dist/commands/command-overview.js +0 -50
- package/dist/commands/command-overview.js.map +0 -1
- package/dist/commands/completion.d.ts +0 -3
- package/dist/commands/completion.d.ts.map +0 -1
- package/dist/commands/completion.js +0 -183
- package/dist/commands/completion.js.map +0 -1
- package/dist/commands/computers.d.ts +0 -3
- package/dist/commands/computers.d.ts.map +0 -1
- package/dist/commands/computers.js +0 -706
- package/dist/commands/computers.js.map +0 -1
- package/dist/commands/config.d.ts +0 -3
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/config.js +0 -114
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/connect.d.ts +0 -6
- package/dist/commands/connect.d.ts.map +0 -1
- package/dist/commands/connect.js +0 -127
- package/dist/commands/connect.js.map +0 -1
- package/dist/commands/connectors.d.ts +0 -3
- package/dist/commands/connectors.d.ts.map +0 -1
- package/dist/commands/connectors.js +0 -172
- package/dist/commands/connectors.js.map +0 -1
- package/dist/commands/containers.d.ts +0 -3
- package/dist/commands/containers.d.ts.map +0 -1
- package/dist/commands/containers.js +0 -20
- package/dist/commands/containers.js.map +0 -1
- package/dist/commands/context.d.ts +0 -3
- package/dist/commands/context.d.ts.map +0 -1
- package/dist/commands/context.js +0 -233
- package/dist/commands/context.js.map +0 -1
- package/dist/commands/cp.d.ts +0 -3
- package/dist/commands/cp.d.ts.map +0 -1
- package/dist/commands/cp.js +0 -319
- package/dist/commands/cp.js.map +0 -1
- package/dist/commands/cron.d.ts +0 -3
- package/dist/commands/cron.d.ts.map +0 -1
- package/dist/commands/cron.js +0 -65
- package/dist/commands/cron.js.map +0 -1
- package/dist/commands/dashboard.d.ts +0 -13
- package/dist/commands/dashboard.d.ts.map +0 -1
- package/dist/commands/dashboard.js +0 -54
- package/dist/commands/dashboard.js.map +0 -1
- package/dist/commands/databases.d.ts +0 -3
- package/dist/commands/databases.d.ts.map +0 -1
- package/dist/commands/databases.js +0 -714
- package/dist/commands/databases.js.map +0 -1
- package/dist/commands/db.d.ts +0 -3
- package/dist/commands/db.d.ts.map +0 -1
- package/dist/commands/db.js +0 -385
- package/dist/commands/db.js.map +0 -1
- package/dist/commands/deploy.d.ts +0 -3
- package/dist/commands/deploy.d.ts.map +0 -1
- package/dist/commands/deploy.js +0 -1234
- package/dist/commands/deploy.js.map +0 -1
- package/dist/commands/desktop.d.ts +0 -3
- package/dist/commands/desktop.d.ts.map +0 -1
- package/dist/commands/desktop.js +0 -277
- package/dist/commands/desktop.js.map +0 -1
- package/dist/commands/dev.d.ts +0 -3
- package/dist/commands/dev.d.ts.map +0 -1
- package/dist/commands/dev.js +0 -245
- package/dist/commands/dev.js.map +0 -1
- package/dist/commands/devices.d.ts +0 -3
- package/dist/commands/devices.d.ts.map +0 -1
- package/dist/commands/devices.js +0 -279
- package/dist/commands/devices.js.map +0 -1
- package/dist/commands/docker-deploy.d.ts +0 -3
- package/dist/commands/docker-deploy.d.ts.map +0 -1
- package/dist/commands/docker-deploy.js +0 -659
- package/dist/commands/docker-deploy.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -69
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js +0 -596
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/domains.d.ts +0 -3
- package/dist/commands/domains.d.ts.map +0 -1
- package/dist/commands/domains.js +0 -307
- package/dist/commands/domains.js.map +0 -1
- package/dist/commands/enterprise-util.d.ts +0 -39
- package/dist/commands/enterprise-util.d.ts.map +0 -1
- package/dist/commands/enterprise-util.js +0 -217
- package/dist/commands/enterprise-util.js.map +0 -1
- package/dist/commands/env-input.d.ts +0 -26
- package/dist/commands/env-input.d.ts.map +0 -1
- package/dist/commands/env-input.js +0 -68
- package/dist/commands/env-input.js.map +0 -1
- package/dist/commands/env.d.ts +0 -3
- package/dist/commands/env.d.ts.map +0 -1
- package/dist/commands/env.js +0 -189
- package/dist/commands/env.js.map +0 -1
- package/dist/commands/exec.d.ts +0 -3
- package/dist/commands/exec.d.ts.map +0 -1
- package/dist/commands/exec.js +0 -110
- package/dist/commands/exec.js.map +0 -1
- package/dist/commands/forge.d.ts +0 -3
- package/dist/commands/forge.d.ts.map +0 -1
- package/dist/commands/forge.js +0 -254
- package/dist/commands/forge.js.map +0 -1
- package/dist/commands/functions.d.ts +0 -3
- package/dist/commands/functions.d.ts.map +0 -1
- package/dist/commands/functions.js +0 -47
- package/dist/commands/functions.js.map +0 -1
- package/dist/commands/gha-runners.d.ts +0 -3
- package/dist/commands/gha-runners.d.ts.map +0 -1
- package/dist/commands/gha-runners.js +0 -33
- package/dist/commands/gha-runners.js.map +0 -1
- package/dist/commands/groups.d.ts +0 -3
- package/dist/commands/groups.d.ts.map +0 -1
- package/dist/commands/groups.js +0 -38
- package/dist/commands/groups.js.map +0 -1
- package/dist/commands/host.d.ts +0 -3
- package/dist/commands/host.d.ts.map +0 -1
- package/dist/commands/host.js +0 -74
- package/dist/commands/host.js.map +0 -1
- package/dist/commands/hosts.d.ts +0 -7
- package/dist/commands/hosts.d.ts.map +0 -1
- package/dist/commands/hosts.js +0 -91
- package/dist/commands/hosts.js.map +0 -1
- package/dist/commands/link.d.ts +0 -8
- package/dist/commands/link.d.ts.map +0 -1
- package/dist/commands/link.js +0 -124
- package/dist/commands/link.js.map +0 -1
- package/dist/commands/login.d.ts +0 -10
- package/dist/commands/login.d.ts.map +0 -1
- package/dist/commands/login.js +0 -263
- package/dist/commands/login.js.map +0 -1
- package/dist/commands/logout.d.ts +0 -3
- package/dist/commands/logout.d.ts.map +0 -1
- package/dist/commands/logout.js +0 -43
- package/dist/commands/logout.js.map +0 -1
- package/dist/commands/logs.d.ts +0 -3
- package/dist/commands/logs.d.ts.map +0 -1
- package/dist/commands/logs.js +0 -401
- package/dist/commands/logs.js.map +0 -1
- package/dist/commands/ls.d.ts +0 -3
- package/dist/commands/ls.d.ts.map +0 -1
- package/dist/commands/ls.js +0 -121
- package/dist/commands/ls.js.map +0 -1
- package/dist/commands/mcp.d.ts +0 -46
- package/dist/commands/mcp.d.ts.map +0 -1
- package/dist/commands/mcp.js +0 -3413
- package/dist/commands/mcp.js.map +0 -1
- package/dist/commands/menu.d.ts +0 -29
- package/dist/commands/menu.d.ts.map +0 -1
- package/dist/commands/menu.js +0 -147
- package/dist/commands/menu.js.map +0 -1
- package/dist/commands/meshes.d.ts +0 -3
- package/dist/commands/meshes.d.ts.map +0 -1
- package/dist/commands/meshes.js +0 -27
- package/dist/commands/meshes.js.map +0 -1
- package/dist/commands/network-policy.d.ts +0 -3
- package/dist/commands/network-policy.d.ts.map +0 -1
- package/dist/commands/network-policy.js +0 -155
- package/dist/commands/network-policy.js.map +0 -1
- package/dist/commands/new.d.ts +0 -3
- package/dist/commands/new.d.ts.map +0 -1
- package/dist/commands/new.js +0 -296
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/opencomputers.d.ts +0 -10
- package/dist/commands/opencomputers.d.ts.map +0 -1
- package/dist/commands/opencomputers.js +0 -25
- package/dist/commands/opencomputers.js.map +0 -1
- package/dist/commands/operating-contract.d.ts +0 -3
- package/dist/commands/operating-contract.d.ts.map +0 -1
- package/dist/commands/operating-contract.js +0 -651
- package/dist/commands/operating-contract.js.map +0 -1
- package/dist/commands/project.d.ts +0 -4
- package/dist/commands/project.d.ts.map +0 -1
- package/dist/commands/project.js +0 -25
- package/dist/commands/project.js.map +0 -1
- package/dist/commands/pull.d.ts +0 -14
- package/dist/commands/pull.d.ts.map +0 -1
- package/dist/commands/pull.js +0 -156
- package/dist/commands/pull.js.map +0 -1
- package/dist/commands/regions.d.ts +0 -3
- package/dist/commands/regions.d.ts.map +0 -1
- package/dist/commands/regions.js +0 -103
- package/dist/commands/regions.js.map +0 -1
- package/dist/commands/releases.d.ts +0 -3
- package/dist/commands/releases.d.ts.map +0 -1
- package/dist/commands/releases.js +0 -365
- package/dist/commands/releases.js.map +0 -1
- package/dist/commands/rm.d.ts +0 -3
- package/dist/commands/rm.d.ts.map +0 -1
- package/dist/commands/rm.js +0 -42
- package/dist/commands/rm.js.map +0 -1
- package/dist/commands/rollback.d.ts +0 -3
- package/dist/commands/rollback.d.ts.map +0 -1
- package/dist/commands/rollback.js +0 -62
- package/dist/commands/rollback.js.map +0 -1
- package/dist/commands/run-groups.d.ts +0 -3
- package/dist/commands/run-groups.d.ts.map +0 -1
- package/dist/commands/run-groups.js +0 -364
- package/dist/commands/run-groups.js.map +0 -1
- package/dist/commands/run.d.ts +0 -3
- package/dist/commands/run.d.ts.map +0 -1
- package/dist/commands/run.js +0 -130
- package/dist/commands/run.js.map +0 -1
- package/dist/commands/runs.d.ts +0 -3
- package/dist/commands/runs.d.ts.map +0 -1
- package/dist/commands/runs.js +0 -365
- package/dist/commands/runs.js.map +0 -1
- package/dist/commands/runtime-env.d.ts +0 -3
- package/dist/commands/runtime-env.d.ts.map +0 -1
- package/dist/commands/runtime-env.js +0 -114
- package/dist/commands/runtime-env.js.map +0 -1
- package/dist/commands/sandbox-delete-guard.d.ts +0 -4
- package/dist/commands/sandbox-delete-guard.d.ts.map +0 -1
- package/dist/commands/sandbox-delete-guard.js +0 -32
- package/dist/commands/sandbox-delete-guard.js.map +0 -1
- package/dist/commands/sandbox-dev.d.ts +0 -20
- package/dist/commands/sandbox-dev.d.ts.map +0 -1
- package/dist/commands/sandbox-dev.js +0 -583
- package/dist/commands/sandbox-dev.js.map +0 -1
- package/dist/commands/sandbox.d.ts +0 -36
- package/dist/commands/sandbox.d.ts.map +0 -1
- package/dist/commands/sandbox.js +0 -3796
- package/dist/commands/sandbox.js.map +0 -1
- package/dist/commands/scale.d.ts +0 -3
- package/dist/commands/scale.d.ts.map +0 -1
- package/dist/commands/scale.js +0 -61
- package/dist/commands/scale.js.map +0 -1
- package/dist/commands/schedules.d.ts +0 -3
- package/dist/commands/schedules.d.ts.map +0 -1
- package/dist/commands/schedules.js +0 -37
- package/dist/commands/schedules.js.map +0 -1
- package/dist/commands/secrets.d.ts +0 -3
- package/dist/commands/secrets.d.ts.map +0 -1
- package/dist/commands/secrets.js +0 -200
- package/dist/commands/secrets.js.map +0 -1
- package/dist/commands/services.d.ts +0 -3
- package/dist/commands/services.d.ts.map +0 -1
- package/dist/commands/services.js +0 -70
- package/dist/commands/services.js.map +0 -1
- package/dist/commands/shell.d.ts +0 -16
- package/dist/commands/shell.d.ts.map +0 -1
- package/dist/commands/shell.js +0 -555
- package/dist/commands/shell.js.map +0 -1
- package/dist/commands/snapshot.d.ts +0 -10
- package/dist/commands/snapshot.d.ts.map +0 -1
- package/dist/commands/snapshot.js +0 -181
- package/dist/commands/snapshot.js.map +0 -1
- package/dist/commands/ssh.d.ts +0 -3
- package/dist/commands/ssh.d.ts.map +0 -1
- package/dist/commands/ssh.js +0 -93
- package/dist/commands/ssh.js.map +0 -1
- package/dist/commands/status.d.ts +0 -3
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js +0 -302
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/storage.d.ts +0 -3
- package/dist/commands/storage.d.ts.map +0 -1
- package/dist/commands/storage.js +0 -456
- package/dist/commands/storage.js.map +0 -1
- package/dist/commands/teams.d.ts +0 -3
- package/dist/commands/teams.d.ts.map +0 -1
- package/dist/commands/teams.js +0 -169
- package/dist/commands/teams.js.map +0 -1
- package/dist/commands/templates.d.ts +0 -3
- package/dist/commands/templates.d.ts.map +0 -1
- package/dist/commands/templates.js +0 -690
- package/dist/commands/templates.js.map +0 -1
- package/dist/commands/tenant.d.ts +0 -3
- package/dist/commands/tenant.d.ts.map +0 -1
- package/dist/commands/tenant.js +0 -95
- package/dist/commands/tenant.js.map +0 -1
- package/dist/commands/tunnel.d.ts +0 -3
- package/dist/commands/tunnel.d.ts.map +0 -1
- package/dist/commands/tunnel.js +0 -418
- package/dist/commands/tunnel.js.map +0 -1
- package/dist/commands/up.d.ts +0 -14
- package/dist/commands/up.d.ts.map +0 -1
- package/dist/commands/up.js +0 -720
- package/dist/commands/up.js.map +0 -1
- package/dist/commands/update.d.ts +0 -3
- package/dist/commands/update.d.ts.map +0 -1
- package/dist/commands/update.js +0 -166
- package/dist/commands/update.js.map +0 -1
- package/dist/commands/util.d.ts +0 -25
- package/dist/commands/util.d.ts.map +0 -1
- package/dist/commands/util.js +0 -199
- package/dist/commands/util.js.map +0 -1
- package/dist/commands/volumes.d.ts +0 -3
- package/dist/commands/volumes.d.ts.map +0 -1
- package/dist/commands/volumes.js +0 -196
- package/dist/commands/volumes.js.map +0 -1
- package/dist/commands/watch.d.ts +0 -6
- package/dist/commands/watch.d.ts.map +0 -1
- package/dist/commands/watch.js +0 -414
- package/dist/commands/watch.js.map +0 -1
- package/dist/commands/webhooks.d.ts +0 -3
- package/dist/commands/webhooks.d.ts.map +0 -1
- package/dist/commands/webhooks.js +0 -23
- package/dist/commands/webhooks.js.map +0 -1
- package/dist/commands/whoami.d.ts +0 -3
- package/dist/commands/whoami.d.ts.map +0 -1
- package/dist/commands/whoami.js +0 -156
- package/dist/commands/whoami.js.map +0 -1
- package/dist/commands/workspaces.d.ts +0 -3
- package/dist/commands/workspaces.d.ts.map +0 -1
- package/dist/commands/workspaces.js +0 -147
- package/dist/commands/workspaces.js.map +0 -1
- package/dist/config.d.ts +0 -54
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -275
- package/dist/config.js.map +0 -1
- package/dist/errors.d.ts +0 -30
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -92
- package/dist/errors.js.map +0 -1
- package/dist/framework-detector.d.ts +0 -22
- package/dist/framework-detector.d.ts.map +0 -1
- package/dist/framework-detector.js +0 -373
- package/dist/framework-detector.js.map +0 -1
- package/dist/generated/action-capabilities.d.ts +0 -826
- package/dist/generated/action-capabilities.d.ts.map +0 -1
- package/dist/generated/action-capabilities.js +0 -1035
- package/dist/generated/action-capabilities.js.map +0 -1
- package/dist/net-diagnosis.d.ts +0 -87
- package/dist/net-diagnosis.d.ts.map +0 -1
- package/dist/net-diagnosis.js +0 -408
- package/dist/net-diagnosis.js.map +0 -1
- package/dist/pty/raw-mode.d.ts +0 -7
- package/dist/pty/raw-mode.d.ts.map +0 -1
- package/dist/pty/raw-mode.js +0 -22
- package/dist/pty/raw-mode.js.map +0 -1
- package/dist/pty/ws-pty-client.d.ts +0 -13
- package/dist/pty/ws-pty-client.d.ts.map +0 -1
- package/dist/pty/ws-pty-client.js +0 -73
- package/dist/pty/ws-pty-client.js.map +0 -1
- package/dist/tui/dashboard.d.ts +0 -35
- package/dist/tui/dashboard.d.ts.map +0 -1
- package/dist/tui/dashboard.js +0 -191
- package/dist/tui/dashboard.js.map +0 -1
- package/dist/tui/logs.d.ts +0 -26
- package/dist/tui/logs.d.ts.map +0 -1
- package/dist/tui/logs.js +0 -276
- package/dist/tui/logs.js.map +0 -1
- package/dist/types.d.ts +0 -362
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -16
- package/dist/types.js.map +0 -1
- package/dist/ui/picker.d.ts +0 -41
- package/dist/ui/picker.d.ts.map +0 -1
- package/dist/ui/picker.js +0 -77
- package/dist/ui/picker.js.map +0 -1
- package/dist/ui/progress.d.ts +0 -10
- package/dist/ui/progress.d.ts.map +0 -1
- package/dist/ui/progress.js +0 -36
- package/dist/ui/progress.js.map +0 -1
- package/dist/ui/render.d.ts +0 -91
- package/dist/ui/render.d.ts.map +0 -1
- package/dist/ui/render.js +0 -138
- package/dist/ui/render.js.map +0 -1
- package/dist/ui/spinner.d.ts +0 -4
- package/dist/ui/spinner.d.ts.map +0 -1
- package/dist/ui/spinner.js +0 -7
- package/dist/ui/spinner.js.map +0 -1
- package/dist/ui/table.d.ts +0 -8
- package/dist/ui/table.d.ts.map +0 -1
- package/dist/ui/table.js +0 -46
- package/dist/ui/table.js.map +0 -1
- package/dist/update-check.d.ts +0 -13
- package/dist/update-check.d.ts.map +0 -1
- package/dist/update-check.js +0 -94
- package/dist/update-check.js.map +0 -1
- package/dist/version.d.ts +0 -3
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js +0 -5
- package/dist/version.js.map +0 -1
package/dist/commands/deploy.js
DELETED
|
@@ -1,1234 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { execSync } from "node:child_process";
|
|
4
|
-
import chalk from "chalk";
|
|
5
|
-
import { request } from "undici";
|
|
6
|
-
import { loadConfig } from "../config.js";
|
|
7
|
-
import { MiosaClient, parseSse } from "../client.js";
|
|
8
|
-
import { ENV_FILE_OPTION_HELP, ENV_INLINE_SHELL_WARNING, ENV_STDIN_OPTION_HELP, resolveEnvInputs, } from "./env-input.js";
|
|
9
|
-
import { errorExitCode, handleError, isJsonMode, jsonErrorPayload, } from "./util.js";
|
|
10
|
-
import { spin } from "../ui/spinner.js";
|
|
11
|
-
import { renderTable } from "../ui/table.js";
|
|
12
|
-
import { errorEnvelope, hintBlock, icon, kvPanel, printBanner, printElapsed, formatDuration, } from "../ui/render.js";
|
|
13
|
-
import { formatBytes } from "../ui/progress.js";
|
|
14
|
-
import { detectFramework, FRAMEWORK_LABELS, } from "../framework-detector.js";
|
|
15
|
-
import { UserError } from "../errors.js";
|
|
16
|
-
import { toDeploymentId } from "../types.js";
|
|
17
|
-
// ── .miosa.json helpers ───────────────────────────────────────────────────────
|
|
18
|
-
const PROJECT_CONFIG_FILE = ".miosa.json";
|
|
19
|
-
function loadProjectConfig(dir) {
|
|
20
|
-
const p = path.join(dir, PROJECT_CONFIG_FILE);
|
|
21
|
-
if (!fs.existsSync(p))
|
|
22
|
-
return null;
|
|
23
|
-
try {
|
|
24
|
-
return JSON.parse(fs.readFileSync(p, "utf8"));
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function saveProjectConfig(dir, cfg) {
|
|
31
|
-
const p = path.join(dir, PROJECT_CONFIG_FILE);
|
|
32
|
-
fs.writeFileSync(p, JSON.stringify(cfg, null, 2) + "\n");
|
|
33
|
-
}
|
|
34
|
-
function getGitInfo(dir) {
|
|
35
|
-
try {
|
|
36
|
-
execSync("git rev-parse --git-dir", { cwd: dir, stdio: "ignore" });
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
throw new UserError("Not a git repository.", "Run `git init && git remote add origin <url>` first, then `miosa deploy`.");
|
|
40
|
-
}
|
|
41
|
-
let repoUrl;
|
|
42
|
-
try {
|
|
43
|
-
repoUrl = execSync("git remote get-url origin", {
|
|
44
|
-
cwd: dir,
|
|
45
|
-
encoding: "utf8",
|
|
46
|
-
}).trim();
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
throw new UserError("No git remote named 'origin' found.", "Add one with: git remote add origin https://github.com/you/your-repo");
|
|
50
|
-
}
|
|
51
|
-
// Normalize SSH remote → HTTPS
|
|
52
|
-
if (repoUrl.startsWith("git@github.com:")) {
|
|
53
|
-
repoUrl = repoUrl
|
|
54
|
-
.replace("git@github.com:", "https://github.com/")
|
|
55
|
-
.replace(/\.git$/, "");
|
|
56
|
-
}
|
|
57
|
-
repoUrl = repoUrl.replace(/\.git$/, "");
|
|
58
|
-
let currentBranch = "main";
|
|
59
|
-
try {
|
|
60
|
-
currentBranch = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
61
|
-
cwd: dir,
|
|
62
|
-
encoding: "utf8",
|
|
63
|
-
}).trim();
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
// default to main
|
|
67
|
-
}
|
|
68
|
-
return { repoUrl, currentBranch };
|
|
69
|
-
}
|
|
70
|
-
// ── URL helpers ───────────────────────────────────────────────────────────────
|
|
71
|
-
function deploymentUrl(deployment, tenantSlug) {
|
|
72
|
-
if (deployment.public_url)
|
|
73
|
-
return deployment.public_url;
|
|
74
|
-
if (deployment.auto_subdomain)
|
|
75
|
-
return deployment.auto_subdomain;
|
|
76
|
-
if (tenantSlug && deployment.slug) {
|
|
77
|
-
return `https://${deployment.slug}.${tenantSlug}.miosa.app`;
|
|
78
|
-
}
|
|
79
|
-
return null;
|
|
80
|
-
}
|
|
81
|
-
function parsePositiveInteger(value) {
|
|
82
|
-
const parsed = Number.parseInt(value, 10);
|
|
83
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
84
|
-
throw new Error(`Invalid positive integer: ${value}`);
|
|
85
|
-
}
|
|
86
|
-
return parsed;
|
|
87
|
-
}
|
|
88
|
-
function deploymentProduct(deployment) {
|
|
89
|
-
const metadataProduct = deployment.metadata?.["deployment_product"];
|
|
90
|
-
if (typeof deployment.deployment_product === "string") {
|
|
91
|
-
return deployment.deployment_product;
|
|
92
|
-
}
|
|
93
|
-
if (typeof metadataProduct === "string")
|
|
94
|
-
return metadataProduct;
|
|
95
|
-
return "miosa_deploy";
|
|
96
|
-
}
|
|
97
|
-
function productLabel(product) {
|
|
98
|
-
return product === "docker_deploy" ? "App Engine" : "MIOSA Deploy";
|
|
99
|
-
}
|
|
100
|
-
function asRecord(value) {
|
|
101
|
-
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
102
|
-
? value
|
|
103
|
-
: {};
|
|
104
|
-
}
|
|
105
|
-
function stringField(value, key) {
|
|
106
|
-
const raw = asRecord(value)[key];
|
|
107
|
-
return typeof raw === "string" && raw.trim() ? raw.trim() : null;
|
|
108
|
-
}
|
|
109
|
-
function numberField(value, key) {
|
|
110
|
-
const raw = asRecord(value)[key];
|
|
111
|
-
if (typeof raw === "number" && Number.isFinite(raw))
|
|
112
|
-
return raw;
|
|
113
|
-
if (typeof raw === "string" && /^\d+$/.test(raw))
|
|
114
|
-
return Number(raw);
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
function addProofCheck(checks, id, ok, message, details, recovery) {
|
|
118
|
-
checks.push({
|
|
119
|
-
id,
|
|
120
|
-
ok,
|
|
121
|
-
message,
|
|
122
|
-
...(details ? { details } : {}),
|
|
123
|
-
...(recovery ? { recovery } : {}),
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
function dockerDeployApp(deployment) {
|
|
127
|
-
const app = asRecord(deployment).docker_deploy_app;
|
|
128
|
-
if (app && typeof app === "object" && !Array.isArray(app)) {
|
|
129
|
-
return app;
|
|
130
|
-
}
|
|
131
|
-
const metadataApp = asRecord(deployment.metadata?.["docker_deploy"]);
|
|
132
|
-
return Object.keys(metadataApp).length > 0 ? metadataApp : null;
|
|
133
|
-
}
|
|
134
|
-
function dockerDeployRuntime(deployment) {
|
|
135
|
-
const app = dockerDeployApp(deployment);
|
|
136
|
-
const runtime = asRecord(deployment.metadata?.["runtime"]);
|
|
137
|
-
return {
|
|
138
|
-
ip: stringField(app, "runtime_ip") ?? stringField(runtime, "ip"),
|
|
139
|
-
port: numberField(app, "runtime_port") ?? numberField(runtime, "port"),
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
async function probePublicUrl(publicUrl, probePath, timeoutMs) {
|
|
143
|
-
if (!publicUrl) {
|
|
144
|
-
return { ok: false, error: "missing_public_url" };
|
|
145
|
-
}
|
|
146
|
-
const url = new URL(publicUrl);
|
|
147
|
-
url.pathname = probePath.startsWith("/") ? probePath : `/${probePath}`;
|
|
148
|
-
const controller = new AbortController();
|
|
149
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
150
|
-
try {
|
|
151
|
-
const res = await request(url.toString(), {
|
|
152
|
-
method: "GET",
|
|
153
|
-
signal: controller.signal,
|
|
154
|
-
});
|
|
155
|
-
res.body.resume();
|
|
156
|
-
return {
|
|
157
|
-
ok: res.statusCode >= 200 && res.statusCode < 500,
|
|
158
|
-
status: res.statusCode,
|
|
159
|
-
url: url.toString(),
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
catch (error) {
|
|
163
|
-
return {
|
|
164
|
-
ok: false,
|
|
165
|
-
error: error instanceof Error ? error.message : String(error),
|
|
166
|
-
url: url.toString(),
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
finally {
|
|
170
|
-
clearTimeout(timeout);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
async function proveDeployment(client, deploymentId, opts) {
|
|
174
|
-
const deployment = await client.getDeployment(deploymentId);
|
|
175
|
-
const product = deploymentProduct(deployment);
|
|
176
|
-
const publicUrl = deploymentUrl(deployment);
|
|
177
|
-
const checks = [];
|
|
178
|
-
addProofCheck(checks, "deployment_row", true, `Deployment ${deployment.id} exists with state=${deployment.state}.`, { state: deployment.state });
|
|
179
|
-
addProofCheck(checks, "deployment_running", deployment.state === "running", deployment.state === "running"
|
|
180
|
-
? "Deployment is marked running."
|
|
181
|
-
: `Deployment state is ${deployment.state}, expected running.`, { state: deployment.state }, [
|
|
182
|
-
"miosa deploy logs <deployment-id>",
|
|
183
|
-
"miosa deploy redeploy <deployment-id>",
|
|
184
|
-
]);
|
|
185
|
-
addProofCheck(checks, "public_url_present", Boolean(publicUrl), publicUrl ? `Public URL is ${publicUrl}.` : "Deployment has no public URL.", { public_url: publicUrl });
|
|
186
|
-
if (product === "docker_deploy") {
|
|
187
|
-
const app = dockerDeployApp(deployment);
|
|
188
|
-
const runtime = dockerDeployRuntime(deployment);
|
|
189
|
-
const hostId = deployment.docker_deploy_host_id ??
|
|
190
|
-
stringField(deployment.metadata, "docker_deploy_host_id") ??
|
|
191
|
-
stringField(app, "docker_deploy_host_id") ??
|
|
192
|
-
stringField(app, "host_id");
|
|
193
|
-
addProofCheck(checks, "docker_deploy_host_link", Boolean(hostId), hostId
|
|
194
|
-
? `Deployment links App Engine host ${hostId}.`
|
|
195
|
-
: "Deployment has no App Engine host id.", { docker_deploy_host_id: hostId }, ["miosa docker-deploy ensure --wait --json"]);
|
|
196
|
-
if (hostId) {
|
|
197
|
-
try {
|
|
198
|
-
const host = await client.apiGet(`/api/v1/docker-deploy/hosts/${encodeURIComponent(hostId)}`);
|
|
199
|
-
const hostRecord = asRecord(asRecord(host).host ?? asRecord(host).data ?? host);
|
|
200
|
-
const status = stringField(hostRecord, "status");
|
|
201
|
-
const applianceStatus = stringField(hostRecord, "appliance_status");
|
|
202
|
-
addProofCheck(checks, "docker_deploy_host_ready", status === "active" && applianceStatus === "healthy", `Host status=${status ?? "unknown"}, appliance=${applianceStatus ?? "unknown"}.`, { status, appliance_status: applianceStatus }, [
|
|
203
|
-
"miosa docker-deploy show <host-id> --json",
|
|
204
|
-
"miosa docker-deploy ensure --wait --json",
|
|
205
|
-
]);
|
|
206
|
-
}
|
|
207
|
-
catch (error) {
|
|
208
|
-
addProofCheck(checks, "docker_deploy_host_ready", false, error instanceof Error ? error.message : String(error), { docker_deploy_host_id: hostId });
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
addProofCheck(checks, "docker_deploy_app_row", Boolean(app), app
|
|
212
|
-
? `App Engine app status=${stringField(app, "status") ?? "unknown"}.`
|
|
213
|
-
: "App Engine app row is missing.", app
|
|
214
|
-
? {
|
|
215
|
-
status: stringField(app, "status"),
|
|
216
|
-
app_id: stringField(app, "app_id"),
|
|
217
|
-
container_id: stringField(app, "container_id"),
|
|
218
|
-
}
|
|
219
|
-
: undefined, ["Re-publish with --docker-deploy --wait."]);
|
|
220
|
-
addProofCheck(checks, "docker_deploy_container_route", Boolean(app &&
|
|
221
|
-
stringField(app, "container_id") &&
|
|
222
|
-
stringField(app, "status") === "running" &&
|
|
223
|
-
runtime.ip &&
|
|
224
|
-
runtime.port), app
|
|
225
|
-
? `Container=${stringField(app, "container_id") ?? "missing"}, route=${runtime.ip ?? "missing"}:${runtime.port ?? "missing"}.`
|
|
226
|
-
: "Cannot verify container route without App Engine app row.", {
|
|
227
|
-
container_id: app ? stringField(app, "container_id") : null,
|
|
228
|
-
runtime_ip: runtime.ip,
|
|
229
|
-
runtime_port: runtime.port,
|
|
230
|
-
}, ["miosa docker-deploy doctor <deployment-id> --json"]);
|
|
231
|
-
}
|
|
232
|
-
if (opts.probe) {
|
|
233
|
-
const probe = await probePublicUrl(publicUrl, opts.probePath, opts.timeoutMs);
|
|
234
|
-
addProofCheck(checks, "public_url_probe", probe.ok, probe.ok
|
|
235
|
-
? `Public URL returned HTTP ${probe.status}.`
|
|
236
|
-
: `Public URL probe failed: ${probe.error ?? `HTTP ${probe.status}`}.`, probe, [
|
|
237
|
-
"Check DNS/custom domain routing.",
|
|
238
|
-
"Check app logs and container health.",
|
|
239
|
-
]);
|
|
240
|
-
}
|
|
241
|
-
const nextActions = checks
|
|
242
|
-
.filter((check) => !check.ok)
|
|
243
|
-
.flatMap((check) => check.recovery ?? [])
|
|
244
|
-
.filter((action, index, all) => all.indexOf(action) === index);
|
|
245
|
-
return {
|
|
246
|
-
ok: checks.every((check) => check.ok),
|
|
247
|
-
deployment_id: deployment.id,
|
|
248
|
-
deployment_product: product,
|
|
249
|
-
public_url: publicUrl,
|
|
250
|
-
checks,
|
|
251
|
-
next_actions: nextActions,
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
// ── Deployment ID resolution ──────────────────────────────────────────────────
|
|
255
|
-
function resolveDeploymentId(idArg, cwd) {
|
|
256
|
-
if (idArg)
|
|
257
|
-
return toDeploymentId(idArg);
|
|
258
|
-
const proj = loadProjectConfig(cwd);
|
|
259
|
-
if (proj)
|
|
260
|
-
return proj.deploymentId;
|
|
261
|
-
throw new UserError("No deployment ID provided and no .miosa.json found in current directory.", "Pass a deployment ID or run from a project with .miosa.json");
|
|
262
|
-
}
|
|
263
|
-
// ── Log stream renderer ───────────────────────────────────────────────────────
|
|
264
|
-
async function streamLogs(client, deploymentId) {
|
|
265
|
-
const res = await client.streamDeploymentLogs(deploymentId);
|
|
266
|
-
let lastState = "success";
|
|
267
|
-
for await (const event of parseSse(res.body)) {
|
|
268
|
-
switch (event.type) {
|
|
269
|
-
case "stdout": {
|
|
270
|
-
process.stdout.write(chalk.dim(" ") + event.data);
|
|
271
|
-
break;
|
|
272
|
-
}
|
|
273
|
-
case "stderr": {
|
|
274
|
-
process.stderr.write(chalk.red(" ") + event.data);
|
|
275
|
-
break;
|
|
276
|
-
}
|
|
277
|
-
case "error": {
|
|
278
|
-
console.error(chalk.red(` [error] ${event.message}`));
|
|
279
|
-
lastState = "failure";
|
|
280
|
-
break;
|
|
281
|
-
}
|
|
282
|
-
case "done": {
|
|
283
|
-
// done event may carry build state
|
|
284
|
-
if (event.result && typeof event.result === "object") {
|
|
285
|
-
const r = event.result;
|
|
286
|
-
if (r["state"] === "failed")
|
|
287
|
-
lastState = "failure";
|
|
288
|
-
}
|
|
289
|
-
return lastState;
|
|
290
|
-
}
|
|
291
|
-
case "unknown": {
|
|
292
|
-
// Try to parse log_line events from the deployment SSE format
|
|
293
|
-
// event: log_line data: {"stream":"stdout","line":"...","ts":"..."}
|
|
294
|
-
try {
|
|
295
|
-
const parsed = JSON.parse(event.raw);
|
|
296
|
-
if (typeof parsed["line"] === "string") {
|
|
297
|
-
const stream = parsed["stream"] ?? "stdout";
|
|
298
|
-
const line = parsed["line"];
|
|
299
|
-
if (stream === "stderr") {
|
|
300
|
-
process.stderr.write(chalk.red(" ") + line + "\n");
|
|
301
|
-
}
|
|
302
|
-
else {
|
|
303
|
-
process.stdout.write(chalk.dim(" ") + line + "\n");
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
catch {
|
|
308
|
-
// ignore unparseable frames
|
|
309
|
-
}
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
default:
|
|
313
|
-
break;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return lastState;
|
|
317
|
-
}
|
|
318
|
-
// ── Sub-command helpers ───────────────────────────────────────────────────────
|
|
319
|
-
function fmtBuildState(state) {
|
|
320
|
-
switch (state) {
|
|
321
|
-
case "succeeded":
|
|
322
|
-
return chalk.green(state);
|
|
323
|
-
case "failed":
|
|
324
|
-
return chalk.red(state);
|
|
325
|
-
case "building":
|
|
326
|
-
return chalk.yellow(state);
|
|
327
|
-
case "queued":
|
|
328
|
-
return chalk.dim(state);
|
|
329
|
-
case "cancelled":
|
|
330
|
-
return chalk.dim(state);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
function fmtDeployState(state) {
|
|
334
|
-
switch (state) {
|
|
335
|
-
case "running":
|
|
336
|
-
return chalk.green(state);
|
|
337
|
-
case "failed":
|
|
338
|
-
return chalk.red(state);
|
|
339
|
-
case "building":
|
|
340
|
-
return chalk.yellow(state);
|
|
341
|
-
case "stopped":
|
|
342
|
-
return chalk.dim(state);
|
|
343
|
-
case "pending":
|
|
344
|
-
return chalk.dim(state);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
function unwrapMetrics(raw) {
|
|
348
|
-
if (raw && typeof raw === "object" && "data" in raw) {
|
|
349
|
-
const data = raw["data"];
|
|
350
|
-
if (data && typeof data === "object")
|
|
351
|
-
return data;
|
|
352
|
-
}
|
|
353
|
-
if (raw && typeof raw === "object")
|
|
354
|
-
return raw;
|
|
355
|
-
return {};
|
|
356
|
-
}
|
|
357
|
-
function metricCurrent(raw) {
|
|
358
|
-
const root = unwrapMetrics(raw);
|
|
359
|
-
const current = root["current"];
|
|
360
|
-
return current && typeof current === "object"
|
|
361
|
-
? current
|
|
362
|
-
: {};
|
|
363
|
-
}
|
|
364
|
-
function renderDeploymentMetrics(raw) {
|
|
365
|
-
const root = unwrapMetrics(raw);
|
|
366
|
-
const current = metricCurrent(raw);
|
|
367
|
-
const instances = current["runtime_instances"] &&
|
|
368
|
-
typeof current["runtime_instances"] === "object"
|
|
369
|
-
? current["runtime_instances"]
|
|
370
|
-
: {};
|
|
371
|
-
const usage = current["usage"] && typeof current["usage"] === "object"
|
|
372
|
-
? current["usage"]
|
|
373
|
-
: {};
|
|
374
|
-
printBanner({ subtitle: "Deployment metrics" });
|
|
375
|
-
console.log(kvPanel([
|
|
376
|
-
{
|
|
377
|
-
label: "deployment_id",
|
|
378
|
-
value: String(root["deployment_id"] ?? root["resource_id"] ?? "-"),
|
|
379
|
-
},
|
|
380
|
-
{ label: "window", value: String(root["window"] ?? "1h") },
|
|
381
|
-
{ label: "state", value: formatMetricState(current["state"]) },
|
|
382
|
-
{
|
|
383
|
-
label: "runtime_instances",
|
|
384
|
-
value: `${formatMetricValue(instances["active"])} active / ${formatMetricValue(instances["total"])} total`,
|
|
385
|
-
},
|
|
386
|
-
{ label: "healthy", value: formatMetricValue(instances["healthy"]) },
|
|
387
|
-
{ label: "unhealthy", value: formatMetricValue(instances["unhealthy"]) },
|
|
388
|
-
{ label: "errors", value: formatMetricValue(instances["error"]) },
|
|
389
|
-
{ label: "restarts", value: formatMetricValue(instances["restarts"]) },
|
|
390
|
-
{
|
|
391
|
-
label: "cpu_limit",
|
|
392
|
-
value: formatMillicores(current["cpu_limit_millicores"]),
|
|
393
|
-
},
|
|
394
|
-
{ label: "memory_limit", value: formatMb(current["memory_limit_mb"]) },
|
|
395
|
-
{ label: "runtime", value: formatSeconds(usage["runtime_sec"]) },
|
|
396
|
-
{ label: "cost_cents", value: formatMetricValue(usage["cost_cents"]) },
|
|
397
|
-
{
|
|
398
|
-
label: "last_health_check",
|
|
399
|
-
value: formatMetricValue(current["last_health_check_at"]),
|
|
400
|
-
},
|
|
401
|
-
{
|
|
402
|
-
label: "last_heartbeat",
|
|
403
|
-
value: formatMetricValue(current["last_heartbeat_at"]),
|
|
404
|
-
},
|
|
405
|
-
]));
|
|
406
|
-
}
|
|
407
|
-
function formatMetricState(value) {
|
|
408
|
-
const state = String(value ?? "unknown");
|
|
409
|
-
if (["running", "active", "healthy", "ready"].includes(state)) {
|
|
410
|
-
return chalk.green(state);
|
|
411
|
-
}
|
|
412
|
-
if (["provisioning", "starting", "building", "pending"].includes(state)) {
|
|
413
|
-
return chalk.yellow(state);
|
|
414
|
-
}
|
|
415
|
-
if (["failed", "error", "unhealthy"].includes(state)) {
|
|
416
|
-
return chalk.red(state);
|
|
417
|
-
}
|
|
418
|
-
return state;
|
|
419
|
-
}
|
|
420
|
-
function formatMetricValue(value) {
|
|
421
|
-
if (value === null || value === undefined || value === "")
|
|
422
|
-
return chalk.dim("-");
|
|
423
|
-
return String(value);
|
|
424
|
-
}
|
|
425
|
-
function formatMb(value) {
|
|
426
|
-
if (typeof value !== "number")
|
|
427
|
-
return formatMetricValue(value);
|
|
428
|
-
return formatBytes(value * 1024 * 1024);
|
|
429
|
-
}
|
|
430
|
-
function formatMillicores(value) {
|
|
431
|
-
if (typeof value !== "number")
|
|
432
|
-
return formatMetricValue(value);
|
|
433
|
-
return `${(value / 1000).toFixed(value % 1000 === 0 ? 0 : 2)} vCPU`;
|
|
434
|
-
}
|
|
435
|
-
function formatSeconds(value) {
|
|
436
|
-
if (typeof value !== "number")
|
|
437
|
-
return formatMetricValue(value);
|
|
438
|
-
return formatDuration(value * 1000);
|
|
439
|
-
}
|
|
440
|
-
export function register(program) {
|
|
441
|
-
const deploy = program
|
|
442
|
-
.command("deploy")
|
|
443
|
-
.alias("launch")
|
|
444
|
-
.description("Deploy a GitHub repo; use --docker-deploy for the recommended production runtime")
|
|
445
|
-
.option("--docker-deploy", "Create the deployment on this workspace's dedicated App Engine runtime")
|
|
446
|
-
.option("--name <name>", "Deployment name (defaults to the directory name)")
|
|
447
|
-
.option("--branch <branch>", "Git branch to deploy (defaults to the current branch)")
|
|
448
|
-
.option("--build-command <cmd>", "Build command (defaults to framework detection)")
|
|
449
|
-
.option("--run-command <cmd>", "Run command (defaults to framework detection)")
|
|
450
|
-
.option("--static", "Deploy static files without build or run commands")
|
|
451
|
-
.option("-y, --yes", "Accept detected defaults and skip interactive confirmation")
|
|
452
|
-
.addHelpText("after", `
|
|
453
|
-
Examples:
|
|
454
|
-
miosa deploy --docker-deploy Recommended: deploy current directory to App Engine
|
|
455
|
-
miosa deploy --docker-deploy --json Prompt-free deploy for CI and agents
|
|
456
|
-
miosa deploy --docker-deploy --static --name report --branch main --yes --json
|
|
457
|
-
miosa deploy --name app --branch main --build-command "npm run build" --run-command "npm start" --yes --json
|
|
458
|
-
miosa deploy Deploy current directory (auto-detects framework)
|
|
459
|
-
miosa deploy list List all deployments
|
|
460
|
-
miosa deploy logs Tail build logs for this project
|
|
461
|
-
miosa deploy redeploy Trigger a new build
|
|
462
|
-
miosa deploy env set NODE_ENV=production
|
|
463
|
-
miosa deploy env list
|
|
464
|
-
miosa deploy domain add example.com
|
|
465
|
-
miosa deploy destroy Tear down this deployment
|
|
466
|
-
`)
|
|
467
|
-
.action(async (opts) => {
|
|
468
|
-
// Default action: interactive deploy flow
|
|
469
|
-
try {
|
|
470
|
-
const cwd = process.cwd();
|
|
471
|
-
const config = loadConfig();
|
|
472
|
-
const client = new MiosaClient(config);
|
|
473
|
-
const json = isJsonMode(opts);
|
|
474
|
-
// ── Check for existing .miosa.json first (skip git for redeploys) ──
|
|
475
|
-
let projectCfg = loadProjectConfig(cwd);
|
|
476
|
-
let deploymentId;
|
|
477
|
-
let queuedBuild = null;
|
|
478
|
-
let createdDeployment = null;
|
|
479
|
-
let webhookSecret = null;
|
|
480
|
-
let buildQueueError = null;
|
|
481
|
-
if (projectCfg) {
|
|
482
|
-
// ── Re-deploy from existing .miosa.json ──────────────────────
|
|
483
|
-
const firstDeployOnlyFlags = [
|
|
484
|
-
opts.name !== undefined ? "--name" : null,
|
|
485
|
-
opts.branch !== undefined ? "--branch" : null,
|
|
486
|
-
opts.buildCommand !== undefined ? "--build-command" : null,
|
|
487
|
-
opts.runCommand !== undefined ? "--run-command" : null,
|
|
488
|
-
opts.static ? "--static" : null,
|
|
489
|
-
].filter((flag) => flag !== null);
|
|
490
|
-
if (firstDeployOnlyFlags.length > 0) {
|
|
491
|
-
throw new UserError(`.miosa.json already exists; ${firstDeployOnlyFlags.join(", ")} only apply when creating a deployment.`, "Remove these flags to redeploy the saved configuration, or delete .miosa.json to create a new deployment.");
|
|
492
|
-
}
|
|
493
|
-
if (!json) {
|
|
494
|
-
console.log();
|
|
495
|
-
console.log(chalk.dim(" Found .miosa.json — redeploying existing deployment"));
|
|
496
|
-
console.log(` ${chalk.bold("Project")} ${projectCfg.name} (${projectCfg.framework})`);
|
|
497
|
-
console.log(` ${chalk.bold("Branch")} ${projectCfg.branch}`);
|
|
498
|
-
console.log();
|
|
499
|
-
}
|
|
500
|
-
deploymentId = projectCfg.deploymentId;
|
|
501
|
-
const buildSpinner = json ? null : spin("Queuing build...");
|
|
502
|
-
try {
|
|
503
|
-
queuedBuild = await client.redeployDeployment(deploymentId);
|
|
504
|
-
buildSpinner?.succeed("Build queued");
|
|
505
|
-
}
|
|
506
|
-
catch (err) {
|
|
507
|
-
buildSpinner?.fail("Failed to queue build");
|
|
508
|
-
handleError(err);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
else {
|
|
512
|
-
// ── First deploy: verify git repo + remote, then detect ───────
|
|
513
|
-
const { repoUrl, currentBranch } = getGitInfo(cwd);
|
|
514
|
-
if (!json)
|
|
515
|
-
console.log();
|
|
516
|
-
const detection = detectFramework(cwd);
|
|
517
|
-
let framework = "unknown";
|
|
518
|
-
let buildCommand = "npm run build";
|
|
519
|
-
let runCommand = "npm start";
|
|
520
|
-
if (detection) {
|
|
521
|
-
const label = FRAMEWORK_LABELS[detection.framework] ??
|
|
522
|
-
detection.framework;
|
|
523
|
-
if (!json) {
|
|
524
|
-
console.log(` Detected: ${chalk.cyan(label)} (confidence ${detection.confidence}%)`);
|
|
525
|
-
}
|
|
526
|
-
framework = detection.framework;
|
|
527
|
-
buildCommand = detection.buildCommand;
|
|
528
|
-
runCommand = detection.runCommand;
|
|
529
|
-
}
|
|
530
|
-
else {
|
|
531
|
-
if (!json) {
|
|
532
|
-
console.log(chalk.yellow(" Could not auto-detect framework. You can set build/run commands manually."));
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
if (!json) {
|
|
536
|
-
console.log(` Repo: ${chalk.dim(repoUrl)}`);
|
|
537
|
-
console.log(` Branch: ${chalk.dim(currentBranch)}`);
|
|
538
|
-
console.log();
|
|
539
|
-
}
|
|
540
|
-
const requiresNonInteractiveInputs = !process.stdin.isTTY || json || Boolean(opts.yes);
|
|
541
|
-
if (opts.static &&
|
|
542
|
-
(opts.buildCommand !== undefined || opts.runCommand !== undefined)) {
|
|
543
|
-
throw new UserError("--static cannot be combined with build or run commands.", "Remove --build-command and --run-command, or remove --static.");
|
|
544
|
-
}
|
|
545
|
-
if (requiresNonInteractiveInputs &&
|
|
546
|
-
!opts.static &&
|
|
547
|
-
!detection &&
|
|
548
|
-
(!opts.buildCommand || !opts.runCommand)) {
|
|
549
|
-
throw new UserError("Could not determine deployment commands non-interactively.", "Pass both --build-command <cmd> and --run-command <cmd>, or use --static for static sites.");
|
|
550
|
-
}
|
|
551
|
-
const projectName = path.basename(cwd).replace(/[^a-z0-9-]/gi, "-");
|
|
552
|
-
let answers;
|
|
553
|
-
if (!requiresNonInteractiveInputs) {
|
|
554
|
-
const { default: inquirer } = await import("inquirer");
|
|
555
|
-
const identityQuestions = [
|
|
556
|
-
{
|
|
557
|
-
type: "input",
|
|
558
|
-
name: "name",
|
|
559
|
-
message: "Deployment name:",
|
|
560
|
-
default: opts.name ?? projectName,
|
|
561
|
-
validate: (v) => v.length > 0 ? true : "Name is required",
|
|
562
|
-
},
|
|
563
|
-
{
|
|
564
|
-
type: "input",
|
|
565
|
-
name: "branch",
|
|
566
|
-
message: "Branch to deploy:",
|
|
567
|
-
default: opts.branch ?? currentBranch,
|
|
568
|
-
},
|
|
569
|
-
];
|
|
570
|
-
const confirmQuestion = {
|
|
571
|
-
type: "confirm",
|
|
572
|
-
name: "confirm",
|
|
573
|
-
message: "Create deployment?",
|
|
574
|
-
default: true,
|
|
575
|
-
};
|
|
576
|
-
if (opts.static) {
|
|
577
|
-
const staticAnswers = await inquirer.prompt([...identityQuestions, confirmQuestion]);
|
|
578
|
-
answers = {
|
|
579
|
-
...staticAnswers,
|
|
580
|
-
buildCommand: "",
|
|
581
|
-
runCommand: "",
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
else {
|
|
585
|
-
answers = await inquirer.prompt([
|
|
586
|
-
...identityQuestions,
|
|
587
|
-
{
|
|
588
|
-
type: "input",
|
|
589
|
-
name: "buildCommand",
|
|
590
|
-
message: "Build command:",
|
|
591
|
-
default: opts.buildCommand ?? buildCommand,
|
|
592
|
-
},
|
|
593
|
-
{
|
|
594
|
-
type: "input",
|
|
595
|
-
name: "runCommand",
|
|
596
|
-
message: "Run command:",
|
|
597
|
-
default: opts.runCommand ?? runCommand,
|
|
598
|
-
},
|
|
599
|
-
confirmQuestion,
|
|
600
|
-
]);
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
else {
|
|
604
|
-
answers = {
|
|
605
|
-
name: opts.name ?? projectName,
|
|
606
|
-
branch: opts.branch ?? currentBranch,
|
|
607
|
-
buildCommand: opts.static
|
|
608
|
-
? ""
|
|
609
|
-
: (opts.buildCommand ?? buildCommand),
|
|
610
|
-
runCommand: opts.static ? "" : (opts.runCommand ?? runCommand),
|
|
611
|
-
confirm: true,
|
|
612
|
-
};
|
|
613
|
-
}
|
|
614
|
-
if (!answers.confirm) {
|
|
615
|
-
console.log(chalk.dim(" Cancelled."));
|
|
616
|
-
process.exit(0);
|
|
617
|
-
}
|
|
618
|
-
// ── Step 3: POST /api/v1/deployments ─────────────────────────
|
|
619
|
-
const createSpinner = json
|
|
620
|
-
? null
|
|
621
|
-
: spin(`Creating deployment "${answers.name}"...`);
|
|
622
|
-
let deployment;
|
|
623
|
-
try {
|
|
624
|
-
const metadata = opts.dockerDeploy
|
|
625
|
-
? { deployment_product: "docker_deploy" }
|
|
626
|
-
: undefined;
|
|
627
|
-
const result = await client.createDeployment({
|
|
628
|
-
name: answers.name,
|
|
629
|
-
repo_url: repoUrl,
|
|
630
|
-
branch: answers.branch,
|
|
631
|
-
build_command: answers.buildCommand || undefined,
|
|
632
|
-
run_command: answers.runCommand || undefined,
|
|
633
|
-
auto_deploy: true,
|
|
634
|
-
metadata,
|
|
635
|
-
});
|
|
636
|
-
deployment = result.data;
|
|
637
|
-
webhookSecret = result.webhook_secret;
|
|
638
|
-
createdDeployment = deployment;
|
|
639
|
-
createSpinner?.succeed(`${productLabel(deploymentProduct(deployment))} deployment "${deployment.name}" created (slug: ${deployment.slug})`);
|
|
640
|
-
}
|
|
641
|
-
catch (err) {
|
|
642
|
-
createSpinner?.fail("Failed to create deployment");
|
|
643
|
-
handleError(err);
|
|
644
|
-
}
|
|
645
|
-
deploymentId = deployment.id;
|
|
646
|
-
framework = framework !== "unknown" ? framework : "unknown";
|
|
647
|
-
// ── Step 4: Save .miosa.json ──────────────────────────────────
|
|
648
|
-
projectCfg = {
|
|
649
|
-
version: 1,
|
|
650
|
-
deploymentId: deployment.id,
|
|
651
|
-
name: deployment.name,
|
|
652
|
-
framework,
|
|
653
|
-
buildCommand: answers.buildCommand,
|
|
654
|
-
runCommand: answers.runCommand,
|
|
655
|
-
branch: answers.branch,
|
|
656
|
-
};
|
|
657
|
-
saveProjectConfig(cwd, projectCfg);
|
|
658
|
-
if (!json)
|
|
659
|
-
console.log(chalk.dim(` Saved .miosa.json`));
|
|
660
|
-
// ── Step 4b: Print webhook secret (one-time) ─────────────────
|
|
661
|
-
if (!json) {
|
|
662
|
-
console.log();
|
|
663
|
-
console.log(chalk.bold.yellow(" ACTION REQUIRED — GitHub Webhook"));
|
|
664
|
-
console.log(chalk.dim(" The webhook secret below is shown ONCE. Store it now."));
|
|
665
|
-
console.log();
|
|
666
|
-
console.log(` ${chalk.bold("Webhook URL:")} https://api.miosa.ai/api/v1/integrations/github/webhook`);
|
|
667
|
-
console.log(` ${chalk.bold("Content type:")} application/json`);
|
|
668
|
-
console.log(` ${chalk.bold("Secret:")} ${chalk.green(webhookSecret)}`);
|
|
669
|
-
console.log(` ${chalk.bold("Events:")} push`);
|
|
670
|
-
console.log();
|
|
671
|
-
console.log(chalk.dim(" Add this at: " + repoUrl + "/settings/hooks/new"));
|
|
672
|
-
console.log();
|
|
673
|
-
}
|
|
674
|
-
// ── Step 5: Trigger initial build ─────────────────────────────
|
|
675
|
-
const buildSpinner = json ? null : spin("Queuing initial build...");
|
|
676
|
-
try {
|
|
677
|
-
queuedBuild = await client.redeployDeployment(deploymentId);
|
|
678
|
-
buildSpinner?.succeed("Initial build queued");
|
|
679
|
-
}
|
|
680
|
-
catch (err) {
|
|
681
|
-
buildSpinner?.fail("Failed to queue build");
|
|
682
|
-
if (!json)
|
|
683
|
-
handleError(err);
|
|
684
|
-
buildQueueError = err;
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
if (json) {
|
|
688
|
-
let deployment = createdDeployment;
|
|
689
|
-
if (!deployment) {
|
|
690
|
-
try {
|
|
691
|
-
deployment = await client.getDeployment(deploymentId);
|
|
692
|
-
}
|
|
693
|
-
catch {
|
|
694
|
-
deployment = null;
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
console.log(JSON.stringify({
|
|
698
|
-
ok: buildQueueError === null,
|
|
699
|
-
deployment: deployment
|
|
700
|
-
? {
|
|
701
|
-
id: deployment.id,
|
|
702
|
-
name: deployment.name,
|
|
703
|
-
slug: deployment.slug,
|
|
704
|
-
state: deployment.state,
|
|
705
|
-
deployment_product: deploymentProduct(deployment),
|
|
706
|
-
docker_deploy_host_id: deployment.docker_deploy_host_id ?? null,
|
|
707
|
-
public_url: deploymentUrl(deployment),
|
|
708
|
-
}
|
|
709
|
-
: {
|
|
710
|
-
id: deploymentId,
|
|
711
|
-
name: projectCfg.name,
|
|
712
|
-
slug: null,
|
|
713
|
-
state: null,
|
|
714
|
-
deployment_product: null,
|
|
715
|
-
docker_deploy_host_id: null,
|
|
716
|
-
public_url: null,
|
|
717
|
-
},
|
|
718
|
-
build: queuedBuild
|
|
719
|
-
? { id: queuedBuild.id, state: queuedBuild.state }
|
|
720
|
-
: null,
|
|
721
|
-
webhook: webhookSecret
|
|
722
|
-
? {
|
|
723
|
-
url: "https://api.miosa.ai/api/v1/integrations/github/webhook",
|
|
724
|
-
secret: webhookSecret,
|
|
725
|
-
events: ["push"],
|
|
726
|
-
}
|
|
727
|
-
: null,
|
|
728
|
-
project_config: path.join(cwd, PROJECT_CONFIG_FILE),
|
|
729
|
-
...(buildQueueError === null
|
|
730
|
-
? {}
|
|
731
|
-
: { error: jsonErrorPayload(buildQueueError) }),
|
|
732
|
-
}, null, 2));
|
|
733
|
-
if (buildQueueError !== null) {
|
|
734
|
-
process.exit(errorExitCode(buildQueueError));
|
|
735
|
-
}
|
|
736
|
-
return;
|
|
737
|
-
}
|
|
738
|
-
// ── Step 6: Stream build logs ─────────────────────────────────────
|
|
739
|
-
console.log();
|
|
740
|
-
console.log(chalk.bold(" Build log:"));
|
|
741
|
-
console.log(chalk.dim(" " + "─".repeat(60)));
|
|
742
|
-
const buildResult = await streamLogs(client, deploymentId);
|
|
743
|
-
console.log(chalk.dim(" " + "─".repeat(60)));
|
|
744
|
-
console.log();
|
|
745
|
-
// ── Step 7: Final status ──────────────────────────────────────────
|
|
746
|
-
if (buildResult === "success") {
|
|
747
|
-
// Fetch the deployment to get the slug + tenant slug
|
|
748
|
-
const spinner = spin("Fetching deployment info...");
|
|
749
|
-
try {
|
|
750
|
-
const dep = await client.getDeployment(deploymentId);
|
|
751
|
-
const tenant = await client.getTenant();
|
|
752
|
-
spinner.stop();
|
|
753
|
-
const url = deploymentUrl(dep, tenant.slug);
|
|
754
|
-
console.log(chalk.green(" Deployed"));
|
|
755
|
-
console.log();
|
|
756
|
-
console.log(` ${chalk.bold("URL:")} ${chalk.cyan(url ?? "—")}`);
|
|
757
|
-
console.log(` ${chalk.bold("Type:")} ${productLabel(deploymentProduct(dep))}`);
|
|
758
|
-
if (dep.docker_deploy_host_id) {
|
|
759
|
-
console.log(` ${chalk.bold("Host:")} ${chalk.dim(dep.docker_deploy_host_id)}`);
|
|
760
|
-
}
|
|
761
|
-
console.log();
|
|
762
|
-
console.log(chalk.dim(" Next steps:"));
|
|
763
|
-
console.log(chalk.dim(` miosa deploy logs — tail logs`));
|
|
764
|
-
console.log(chalk.dim(` miosa deploy domain add example.com — add custom domain`));
|
|
765
|
-
console.log(chalk.dim(` miosa deploy env set KEY=VALUE — set env var`));
|
|
766
|
-
}
|
|
767
|
-
catch {
|
|
768
|
-
spinner.stop();
|
|
769
|
-
console.log(chalk.green(" Deployed"));
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
else {
|
|
773
|
-
console.log(chalk.red(" Build failed."));
|
|
774
|
-
console.log();
|
|
775
|
-
console.log(chalk.dim(" View full logs: miosa deploy logs"));
|
|
776
|
-
console.log(chalk.dim(` Dashboard: https://app.miosa.ai/deploy/${deploymentId}`));
|
|
777
|
-
process.exit(1);
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
catch (err) {
|
|
781
|
-
handleError(err);
|
|
782
|
-
}
|
|
783
|
-
});
|
|
784
|
-
// ── deploy list ─────────────────────────────────────────────────────────────
|
|
785
|
-
deploy
|
|
786
|
-
.command("list")
|
|
787
|
-
.description("List all deployments for this tenant")
|
|
788
|
-
.option("--state <state>", "Filter by deployment state")
|
|
789
|
-
.option("--workspace <id>", "Filter by workspace ID")
|
|
790
|
-
.option("--limit <n>", "Maximum number of deployments to return", parsePositiveInteger)
|
|
791
|
-
.option("--json", "Output raw JSON")
|
|
792
|
-
.action(async (opts) => {
|
|
793
|
-
try {
|
|
794
|
-
const config = loadConfig();
|
|
795
|
-
const client = new MiosaClient(config);
|
|
796
|
-
const json = isJsonMode(opts);
|
|
797
|
-
const spinner = json ? null : spin("Fetching deployments...");
|
|
798
|
-
const deployments = await client.listDeployments({
|
|
799
|
-
state: opts.state,
|
|
800
|
-
workspace: opts.workspace,
|
|
801
|
-
limit: opts.limit,
|
|
802
|
-
});
|
|
803
|
-
spinner?.stop();
|
|
804
|
-
if (json) {
|
|
805
|
-
console.log(JSON.stringify(deployments, null, 2));
|
|
806
|
-
return;
|
|
807
|
-
}
|
|
808
|
-
const n = deployments.length;
|
|
809
|
-
console.log();
|
|
810
|
-
console.log(` ${icon.info} ${chalk.bold(String(n))} ${chalk.dim(n === 1 ? "deployment" : "deployment(s)")}`);
|
|
811
|
-
console.log();
|
|
812
|
-
if (n === 0) {
|
|
813
|
-
console.log(kvPanel([{ label: "Deployments", value: chalk.dim("none yet") }]));
|
|
814
|
-
console.log();
|
|
815
|
-
console.log(hintBlock("Try", [
|
|
816
|
-
"miosa deploy # deploy a project from the current directory",
|
|
817
|
-
]));
|
|
818
|
-
console.log();
|
|
819
|
-
return;
|
|
820
|
-
}
|
|
821
|
-
renderTable(deployments, [
|
|
822
|
-
{ header: "ID", key: (d) => d.id.slice(0, 8), width: 10 },
|
|
823
|
-
{ header: "NAME", key: "name", width: 24 },
|
|
824
|
-
{
|
|
825
|
-
header: "TYPE",
|
|
826
|
-
key: (d) => productLabel(deploymentProduct(d)),
|
|
827
|
-
width: 14,
|
|
828
|
-
},
|
|
829
|
-
{ header: "SLUG", key: "slug", width: 24 },
|
|
830
|
-
{ header: "BRANCH", key: "branch", width: 12 },
|
|
831
|
-
{
|
|
832
|
-
header: "STATE",
|
|
833
|
-
key: (d) => fmtDeployState(d.state),
|
|
834
|
-
width: 10,
|
|
835
|
-
},
|
|
836
|
-
{
|
|
837
|
-
header: "UPDATED",
|
|
838
|
-
key: (d) => new Date(d.updated_at).toLocaleString(),
|
|
839
|
-
width: 20,
|
|
840
|
-
},
|
|
841
|
-
]);
|
|
842
|
-
console.log();
|
|
843
|
-
console.log(hintBlock("Try", [
|
|
844
|
-
"miosa deploy show <id>",
|
|
845
|
-
"miosa deploy redeploy <id> # redeploy",
|
|
846
|
-
"miosa deploy rollback <id>",
|
|
847
|
-
]));
|
|
848
|
-
console.log();
|
|
849
|
-
}
|
|
850
|
-
catch (err) {
|
|
851
|
-
handleError(err);
|
|
852
|
-
}
|
|
853
|
-
});
|
|
854
|
-
// ── deploy show ─────────────────────────────────────────────────────────────
|
|
855
|
-
deploy
|
|
856
|
-
.command("show <id>")
|
|
857
|
-
.description("Show details for a single deployment")
|
|
858
|
-
.option("--json", "Output raw JSON")
|
|
859
|
-
.action(async (id, opts) => {
|
|
860
|
-
try {
|
|
861
|
-
const config = loadConfig();
|
|
862
|
-
const client = new MiosaClient(config);
|
|
863
|
-
const deploymentId = toDeploymentId(id);
|
|
864
|
-
const json = isJsonMode(opts);
|
|
865
|
-
const spinner = json ? null : spin("Fetching deployment...");
|
|
866
|
-
const dep = await client.getDeployment(deploymentId);
|
|
867
|
-
spinner?.stop();
|
|
868
|
-
if (json) {
|
|
869
|
-
console.log(JSON.stringify(dep, null, 2));
|
|
870
|
-
return;
|
|
871
|
-
}
|
|
872
|
-
const truncate = (s, max) => {
|
|
873
|
-
if (!s)
|
|
874
|
-
return chalk.dim("—");
|
|
875
|
-
return s.length > max ? s.slice(0, max - 1) + "…" : s;
|
|
876
|
-
};
|
|
877
|
-
const colorizeState = (state) => {
|
|
878
|
-
switch (state) {
|
|
879
|
-
case "running":
|
|
880
|
-
return chalk.green(state);
|
|
881
|
-
case "building":
|
|
882
|
-
return chalk.yellow(state);
|
|
883
|
-
case "failed":
|
|
884
|
-
return chalk.red(state);
|
|
885
|
-
default:
|
|
886
|
-
return chalk.dim(state);
|
|
887
|
-
}
|
|
888
|
-
};
|
|
889
|
-
const tenant = await client.getTenant().catch(() => null);
|
|
890
|
-
const publicUrl = deploymentUrl(dep, tenant?.slug) ?? chalk.dim("—");
|
|
891
|
-
printBanner({ subtitle: "Deployment" });
|
|
892
|
-
console.log(kvPanel([
|
|
893
|
-
{ label: "id", value: chalk.dim(dep.id) },
|
|
894
|
-
{ label: "name", value: chalk.bold(dep.name) },
|
|
895
|
-
{ label: "type", value: productLabel(deploymentProduct(dep)) },
|
|
896
|
-
{ label: "state", value: colorizeState(dep.state) },
|
|
897
|
-
{
|
|
898
|
-
label: "docker_deploy_host_id",
|
|
899
|
-
value: dep.docker_deploy_host_id
|
|
900
|
-
? chalk.dim(dep.docker_deploy_host_id)
|
|
901
|
-
: chalk.dim("—"),
|
|
902
|
-
},
|
|
903
|
-
{
|
|
904
|
-
label: "current_build_id",
|
|
905
|
-
value: dep.current_build_id
|
|
906
|
-
? chalk.dim(dep.current_build_id)
|
|
907
|
-
: chalk.dim("—"),
|
|
908
|
-
},
|
|
909
|
-
{ label: "repo_url", value: chalk.cyan(dep.repo_url) },
|
|
910
|
-
{ label: "branch", value: dep.branch },
|
|
911
|
-
{
|
|
912
|
-
label: "build_command",
|
|
913
|
-
value: truncate(dep.build_command, 60),
|
|
914
|
-
},
|
|
915
|
-
{ label: "run_command", value: truncate(dep.run_command, 60) },
|
|
916
|
-
{
|
|
917
|
-
label: "created_at",
|
|
918
|
-
value: chalk.dim(new Date(dep.created_at).toLocaleString()),
|
|
919
|
-
},
|
|
920
|
-
{ label: "public_url", value: chalk.cyan(publicUrl) },
|
|
921
|
-
]));
|
|
922
|
-
console.log();
|
|
923
|
-
console.log(hintBlock("Try", [
|
|
924
|
-
"miosa deploy redeploy <id> # redeploy",
|
|
925
|
-
"miosa logs <id> # tail build/runtime logs",
|
|
926
|
-
"miosa deploy rollback <id>",
|
|
927
|
-
]));
|
|
928
|
-
console.log();
|
|
929
|
-
}
|
|
930
|
-
catch (err) {
|
|
931
|
-
handleError(err);
|
|
932
|
-
}
|
|
933
|
-
});
|
|
934
|
-
// ── deploy prove ───────────────────────────────────────────────────────────
|
|
935
|
-
deploy
|
|
936
|
-
.command("prove [id]")
|
|
937
|
-
.description("Prove a deployment is real, live, routed, and not metadata-only")
|
|
938
|
-
.option("--probe-path <path>", "HTTP path to probe on the public URL", "/")
|
|
939
|
-
.option("--timeout <seconds>", "Public probe timeout in seconds", parsePositiveInteger, 20)
|
|
940
|
-
.option("--no-probe", "Skip public HTTP probe")
|
|
941
|
-
.option("--json", "Output stable proof JSON")
|
|
942
|
-
.action(async (id, opts) => {
|
|
943
|
-
try {
|
|
944
|
-
const cwd = process.cwd();
|
|
945
|
-
const config = loadConfig();
|
|
946
|
-
const client = new MiosaClient(config);
|
|
947
|
-
const deploymentId = resolveDeploymentId(id, cwd);
|
|
948
|
-
const json = isJsonMode(opts);
|
|
949
|
-
const spinner = json ? null : spin("Proving deployment...");
|
|
950
|
-
const result = await proveDeployment(client, deploymentId, {
|
|
951
|
-
probePath: opts.probePath,
|
|
952
|
-
timeoutMs: opts.timeout * 1000,
|
|
953
|
-
probe: opts.probe !== false,
|
|
954
|
-
});
|
|
955
|
-
spinner?.stop();
|
|
956
|
-
if (!result.ok)
|
|
957
|
-
process.exitCode = 1;
|
|
958
|
-
if (json) {
|
|
959
|
-
console.log(JSON.stringify(result, null, 2));
|
|
960
|
-
return;
|
|
961
|
-
}
|
|
962
|
-
printBanner({ subtitle: "Deployment proof" });
|
|
963
|
-
console.log(kvPanel([
|
|
964
|
-
{
|
|
965
|
-
label: "deployment_id",
|
|
966
|
-
value: chalk.dim(result.deployment_id),
|
|
967
|
-
},
|
|
968
|
-
{ label: "type", value: productLabel(result.deployment_product) },
|
|
969
|
-
{
|
|
970
|
-
label: "public_url",
|
|
971
|
-
value: result.public_url
|
|
972
|
-
? chalk.cyan(result.public_url)
|
|
973
|
-
: chalk.dim("missing"),
|
|
974
|
-
},
|
|
975
|
-
{
|
|
976
|
-
label: "proof",
|
|
977
|
-
value: result.ok ? chalk.green("passed") : chalk.red("failed"),
|
|
978
|
-
},
|
|
979
|
-
]));
|
|
980
|
-
console.log();
|
|
981
|
-
for (const check of result.checks) {
|
|
982
|
-
console.log(` ${check.ok ? chalk.green("✓") : chalk.red("✗")} ${check.id}: ${check.message}`);
|
|
983
|
-
}
|
|
984
|
-
if (result.next_actions.length > 0) {
|
|
985
|
-
console.log();
|
|
986
|
-
console.log(hintBlock("Next", result.next_actions));
|
|
987
|
-
}
|
|
988
|
-
console.log();
|
|
989
|
-
}
|
|
990
|
-
catch (err) {
|
|
991
|
-
handleError(err);
|
|
992
|
-
}
|
|
993
|
-
});
|
|
994
|
-
// ── deploy metrics ──────────────────────────────────────────────────────────
|
|
995
|
-
deploy
|
|
996
|
-
.command("metrics [id]")
|
|
997
|
-
.description("Show deployment runtime instance, usage, and health metrics")
|
|
998
|
-
.option("--window <window>", "Metrics window: 1h, 24h, or 7d", "1h")
|
|
999
|
-
.option("--json", "Output raw JSON")
|
|
1000
|
-
.action(async (id, opts) => {
|
|
1001
|
-
try {
|
|
1002
|
-
const cwd = process.cwd();
|
|
1003
|
-
const config = loadConfig();
|
|
1004
|
-
const client = new MiosaClient(config);
|
|
1005
|
-
const deploymentId = resolveDeploymentId(id, cwd);
|
|
1006
|
-
const json = isJsonMode(opts);
|
|
1007
|
-
const spinner = json ? null : spin("Fetching deployment metrics...");
|
|
1008
|
-
const metrics = await client.apiGet(`/api/v1/deployments/${encodeURIComponent(deploymentId)}/metrics?window=${encodeURIComponent(opts.window)}`);
|
|
1009
|
-
spinner?.stop();
|
|
1010
|
-
if (json) {
|
|
1011
|
-
console.log(JSON.stringify(metrics, null, 2));
|
|
1012
|
-
return;
|
|
1013
|
-
}
|
|
1014
|
-
renderDeploymentMetrics(metrics);
|
|
1015
|
-
}
|
|
1016
|
-
catch (err) {
|
|
1017
|
-
handleError(err);
|
|
1018
|
-
}
|
|
1019
|
-
});
|
|
1020
|
-
// ── deploy logs ─────────────────────────────────────────────────────────────
|
|
1021
|
-
deploy
|
|
1022
|
-
.command("logs [id]")
|
|
1023
|
-
.description("Tail live build logs for a deployment (auto-detected from .miosa.json)")
|
|
1024
|
-
.action(async (id) => {
|
|
1025
|
-
try {
|
|
1026
|
-
const cwd = process.cwd();
|
|
1027
|
-
const config = loadConfig();
|
|
1028
|
-
const client = new MiosaClient(config);
|
|
1029
|
-
const deploymentId = resolveDeploymentId(id, cwd);
|
|
1030
|
-
console.log(chalk.dim(` Streaming logs for ${deploymentId}...`));
|
|
1031
|
-
console.log(chalk.dim(" " + "─".repeat(60)));
|
|
1032
|
-
await streamLogs(client, deploymentId);
|
|
1033
|
-
console.log(chalk.dim(" " + "─".repeat(60)));
|
|
1034
|
-
}
|
|
1035
|
-
catch (err) {
|
|
1036
|
-
handleError(err);
|
|
1037
|
-
}
|
|
1038
|
-
});
|
|
1039
|
-
// ── deploy redeploy ──────────────────────────────────────────────────────────
|
|
1040
|
-
deploy
|
|
1041
|
-
.command("redeploy [id]")
|
|
1042
|
-
.description("Trigger a manual rebuild (auto-detected from .miosa.json)")
|
|
1043
|
-
.option("--no-follow", "Queue the build without tailing logs")
|
|
1044
|
-
.action(async (id, opts) => {
|
|
1045
|
-
const actionStart = Date.now();
|
|
1046
|
-
try {
|
|
1047
|
-
const cwd = process.cwd();
|
|
1048
|
-
const config = loadConfig();
|
|
1049
|
-
const client = new MiosaClient(config);
|
|
1050
|
-
const deploymentId = resolveDeploymentId(id, cwd);
|
|
1051
|
-
const spinner = spin("Queuing build...");
|
|
1052
|
-
let build;
|
|
1053
|
-
try {
|
|
1054
|
-
build = await client.redeployDeployment(deploymentId);
|
|
1055
|
-
spinner.stop();
|
|
1056
|
-
}
|
|
1057
|
-
catch (err) {
|
|
1058
|
-
spinner.stop();
|
|
1059
|
-
console.log();
|
|
1060
|
-
console.log(errorEnvelope({
|
|
1061
|
-
title: "Redeploy failed",
|
|
1062
|
-
body: err instanceof Error ? err.message : String(err),
|
|
1063
|
-
suggest: [
|
|
1064
|
-
"miosa deploy show <id> # check deployment state",
|
|
1065
|
-
"miosa deploy list # list all deployments",
|
|
1066
|
-
],
|
|
1067
|
-
withDebugHint: true,
|
|
1068
|
-
}));
|
|
1069
|
-
console.log();
|
|
1070
|
-
process.exit(4);
|
|
1071
|
-
}
|
|
1072
|
-
printBanner({ subtitle: "Redeploy queued" });
|
|
1073
|
-
console.log(kvPanel([
|
|
1074
|
-
{
|
|
1075
|
-
icon: icon.ok,
|
|
1076
|
-
label: "deployment_id",
|
|
1077
|
-
value: chalk.dim(deploymentId),
|
|
1078
|
-
},
|
|
1079
|
-
{ label: "new_build_id", value: chalk.dim(build.id) },
|
|
1080
|
-
{ label: "state", value: chalk.yellow("queued") },
|
|
1081
|
-
]));
|
|
1082
|
-
console.log();
|
|
1083
|
-
console.log(hintBlock("Watch", [
|
|
1084
|
-
`miosa logs ${deploymentId} --follow`,
|
|
1085
|
-
`miosa deploy show ${deploymentId}`,
|
|
1086
|
-
]));
|
|
1087
|
-
printElapsed(formatDuration(Date.now() - actionStart));
|
|
1088
|
-
if (opts?.follow !== false) {
|
|
1089
|
-
console.log();
|
|
1090
|
-
console.log(chalk.bold(" Build log:"));
|
|
1091
|
-
console.log(chalk.dim(" " + "─".repeat(60)));
|
|
1092
|
-
await streamLogs(client, deploymentId);
|
|
1093
|
-
console.log(chalk.dim(" " + "─".repeat(60)));
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
catch (err) {
|
|
1097
|
-
handleError(err);
|
|
1098
|
-
}
|
|
1099
|
-
});
|
|
1100
|
-
// ── deploy env ───────────────────────────────────────────────────────────────
|
|
1101
|
-
const envCmd = deploy
|
|
1102
|
-
.command("env")
|
|
1103
|
-
.description("Manage environment variables for a deployment");
|
|
1104
|
-
envCmd
|
|
1105
|
-
.command("set [pairs...]")
|
|
1106
|
-
.description(`Set one or more env vars (KEY=VALUE). ${ENV_INLINE_SHELL_WARNING}`)
|
|
1107
|
-
.option("--env-file <path>", ENV_FILE_OPTION_HELP)
|
|
1108
|
-
.option("--env-stdin", ENV_STDIN_OPTION_HELP)
|
|
1109
|
-
.option("--id <id>", "Deployment ID (overrides .miosa.json)")
|
|
1110
|
-
.action(async (pairs, opts) => {
|
|
1111
|
-
try {
|
|
1112
|
-
const cwd = process.cwd();
|
|
1113
|
-
const config = loadConfig();
|
|
1114
|
-
const client = new MiosaClient(config);
|
|
1115
|
-
const deploymentId = resolveDeploymentId(opts.id, cwd);
|
|
1116
|
-
const inline = {};
|
|
1117
|
-
for (const pair of pairs ?? []) {
|
|
1118
|
-
const eq = pair.indexOf("=");
|
|
1119
|
-
if (eq === -1) {
|
|
1120
|
-
inline[pair] = "";
|
|
1121
|
-
}
|
|
1122
|
-
else {
|
|
1123
|
-
inline[pair.slice(0, eq)] = pair.slice(eq + 1);
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
const env = await resolveEnvInputs(inline, opts);
|
|
1127
|
-
if (Object.keys(env).length === 0) {
|
|
1128
|
-
throw new UserError("No env vars provided.", "Pass KEY=VALUE pairs, --env-file <path>, or --env-stdin.");
|
|
1129
|
-
}
|
|
1130
|
-
const spinner = spin("Setting env vars...");
|
|
1131
|
-
const vars = await client.setDeploymentEnv(deploymentId, env);
|
|
1132
|
-
spinner.succeed(`Set ${vars.length} env var(s)`);
|
|
1133
|
-
for (const v of vars) {
|
|
1134
|
-
console.log(` ${chalk.bold(v.name)} ${chalk.dim(v.preview)}`);
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
catch (err) {
|
|
1138
|
-
handleError(err);
|
|
1139
|
-
}
|
|
1140
|
-
});
|
|
1141
|
-
envCmd
|
|
1142
|
-
.command("list [id]")
|
|
1143
|
-
.description("List env var names and masked previews")
|
|
1144
|
-
.action(async (id) => {
|
|
1145
|
-
try {
|
|
1146
|
-
const cwd = process.cwd();
|
|
1147
|
-
const config = loadConfig();
|
|
1148
|
-
const client = new MiosaClient(config);
|
|
1149
|
-
const deploymentId = resolveDeploymentId(id, cwd);
|
|
1150
|
-
const spinner = spin("Fetching env vars...");
|
|
1151
|
-
const vars = await client.getDeploymentEnv(deploymentId);
|
|
1152
|
-
spinner.stop();
|
|
1153
|
-
if (vars.length === 0) {
|
|
1154
|
-
console.log(chalk.dim(" No env vars set."));
|
|
1155
|
-
return;
|
|
1156
|
-
}
|
|
1157
|
-
renderTable(vars, [
|
|
1158
|
-
{ header: "NAME", key: "name", width: 32 },
|
|
1159
|
-
{ header: "VALUE", key: (v) => chalk.dim(v.preview), width: 20 },
|
|
1160
|
-
{
|
|
1161
|
-
header: "UPDATED",
|
|
1162
|
-
key: (v) => new Date(v.updated_at).toLocaleString(),
|
|
1163
|
-
width: 20,
|
|
1164
|
-
},
|
|
1165
|
-
]);
|
|
1166
|
-
}
|
|
1167
|
-
catch (err) {
|
|
1168
|
-
handleError(err);
|
|
1169
|
-
}
|
|
1170
|
-
});
|
|
1171
|
-
// ── deploy domain ────────────────────────────────────────────────────────────
|
|
1172
|
-
const domainCmd = deploy
|
|
1173
|
-
.command("domain")
|
|
1174
|
-
.description("Manage custom domains for a deployment");
|
|
1175
|
-
domainCmd
|
|
1176
|
-
.command("add <domain> [id]")
|
|
1177
|
-
.description("Add a custom domain to a deployment")
|
|
1178
|
-
.action(async (domain, id) => {
|
|
1179
|
-
try {
|
|
1180
|
-
const cwd = process.cwd();
|
|
1181
|
-
resolveDeploymentId(id, cwd); // validate — actual domain API is v2
|
|
1182
|
-
// Domain management endpoints are in the next sprint.
|
|
1183
|
-
// Point the user to the dashboard in the interim.
|
|
1184
|
-
console.log();
|
|
1185
|
-
console.log(chalk.yellow(` Custom domain management is not yet available via the CLI.`));
|
|
1186
|
-
console.log(chalk.dim(` Configure "${domain}" at: https://app.miosa.ai/deploy`));
|
|
1187
|
-
console.log();
|
|
1188
|
-
}
|
|
1189
|
-
catch (err) {
|
|
1190
|
-
handleError(err);
|
|
1191
|
-
}
|
|
1192
|
-
});
|
|
1193
|
-
// ── deploy destroy ───────────────────────────────────────────────────────────
|
|
1194
|
-
deploy
|
|
1195
|
-
.command("destroy [id]")
|
|
1196
|
-
.description("Permanently delete a deployment and all build history")
|
|
1197
|
-
.option("-f, --force", "Skip confirmation prompt")
|
|
1198
|
-
.action(async (id, opts) => {
|
|
1199
|
-
try {
|
|
1200
|
-
const cwd = process.cwd();
|
|
1201
|
-
const config = loadConfig();
|
|
1202
|
-
const client = new MiosaClient(config);
|
|
1203
|
-
const deploymentId = resolveDeploymentId(id, cwd);
|
|
1204
|
-
if (!opts?.force) {
|
|
1205
|
-
const { default: inquirer } = await import("inquirer");
|
|
1206
|
-
const { ok } = await inquirer.prompt([
|
|
1207
|
-
{
|
|
1208
|
-
type: "confirm",
|
|
1209
|
-
name: "ok",
|
|
1210
|
-
message: chalk.red(`Destroy deployment ${deploymentId.slice(0, 8)}? This is irreversible.`),
|
|
1211
|
-
default: false,
|
|
1212
|
-
},
|
|
1213
|
-
]);
|
|
1214
|
-
if (!ok) {
|
|
1215
|
-
console.log(chalk.dim(" Cancelled."));
|
|
1216
|
-
process.exit(0);
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
const spinner = spin("Destroying deployment...");
|
|
1220
|
-
await client.deleteDeployment(deploymentId);
|
|
1221
|
-
spinner.succeed("Deployment destroyed");
|
|
1222
|
-
// Remove local .miosa.json if it references this deployment
|
|
1223
|
-
const proj = loadProjectConfig(cwd);
|
|
1224
|
-
if (proj?.deploymentId === deploymentId) {
|
|
1225
|
-
fs.unlinkSync(path.join(cwd, PROJECT_CONFIG_FILE));
|
|
1226
|
-
console.log(chalk.dim(" Removed .miosa.json"));
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
catch (err) {
|
|
1230
|
-
handleError(err);
|
|
1231
|
-
}
|
|
1232
|
-
});
|
|
1233
|
-
}
|
|
1234
|
-
//# sourceMappingURL=deploy.js.map
|