insta 0.0.23-rc.1 → 0.0.24

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 CHANGED
@@ -1,175 +1,220 @@
1
1
  # insta-cli
2
2
 
3
- InstaCloud CLI (`insta`) — a thin client of the [platform](../platform) control-plane API.
4
- Manages project / branch / secrets / deploy / governance — built for developers and agents.
3
+ [![npm](https://img.shields.io/npm/v/insta?color=blue)](https://www.npmjs.com/package/insta)
4
+ [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg)](LICENSE)
5
5
 
6
- Tech stack: Node 20 + TypeScript (ESM) + commander. Every command is a wrapper around the platform API.
6
+ The InstaCloud CLI. Provision Postgres, object storage and compute, fork the whole
7
+ environment per branch, and give your coding agent scoped credentials without pasting
8
+ secrets into a chat window.
7
9
 
8
- ## Installation
10
+ `insta` is a thin client over the InstaCloud control-plane API. Every command is one API
11
+ call, so anything you can do, an agent can do.
9
12
 
10
- **One-line install (native binary, no node required)** — macOS / Linux / WSL:
13
+ ## Install
14
+
15
+ Native binary, no Node required (macOS / Linux / WSL). Installs to `~/.insta/bin` and
16
+ verifies the download against `SHA256SUMS`:
11
17
 
12
18
  ```bash
13
19
  curl -fsSL https://raw.githubusercontent.com/InsForge/insta-cli/main/install.sh | sh
14
- # Installs to ~/.insta/bin/insta (override with INSTA_INSTALL_DIR); verifies SHA256SUMS.
15
- # Pin a version: curl -fsSL .../install.sh | INSTA_VERSION=v0.1.0 sh
16
- # Windows: download insta-windows-x64.exe from the releases page.
17
20
  ```
18
21
 
19
- **Agent one-liner** (CLI + agent skills + MCP registration, non-interactive):
22
+ From npm:
20
23
 
21
24
  ```bash
22
- curl -fsSL agents.instacloud.com | sh # production
23
- curl -fsSL agents.staging.instacloud.com | sh # staging
25
+ npm install -g insta
24
26
  ```
25
27
 
26
- Each installs a complete stack for its environment — CLI build, control plane, MCP registration and
27
- skill text all match. See [Environments](#environments).
28
-
29
- > The staging host serves this repo's `agents-staging.sh` from `main`, so it returns 404 until that
30
- > file is on `main`. Equivalent, and works regardless:
31
- >
32
- > ```bash
33
- > curl -fsSL https://raw.githubusercontent.com/InsForge/insta-cli/main/install.sh | sh -s -- --agents --staging -y
34
- > ```
35
- >
36
- > If the environment can't be applied (a CLI predating `insta env`), the installer exits non-zero
37
- > rather than silently leaving you on production.
38
-
39
- **Build from source (requires node):**
28
+ For coding agents. Installs the CLI, the `insta` skill for every agent on the machine, and
29
+ registers the MCP server:
40
30
 
41
31
  ```bash
42
- npm install
43
- npm run build # -> dist/index.js (bin: insta; pure JS, requires node to run)
44
- node dist/index.js --help
32
+ curl -fsSL agents.instacloud.com | sh
45
33
  ```
46
34
 
47
- ### Build your own binaries (Bun cross-compilation)
35
+ On Windows, download `insta-windows-x64.exe` from the
36
+ [releases page](https://github.com/InsForge/insta-cli/releases).
48
37
 
49
- The binaries that `install.sh` installs are cross-compiled with Bun by CI (tag `v*` → `.github/workflows/release.yml`)
50
- and published to GitHub releases. You can also build them locally: requires [Bun](https://bun.sh). The npm package still
51
- ships JS (`dist/index.js`) — binaries are a separate distribution channel.
38
+ Pin a version with `INSTA_VERSION=v0.0.22`; change the install directory with
39
+ `INSTA_INSTALL_DIR`. While the CLI is pre-1.0 it updates itself on new releases. Turn that
40
+ off with `insta autoupdate off`.
41
+
42
+ ## Quickstart
52
43
 
53
44
  ```bash
54
- npm run compile # compile for the current platform only -> dist/bin/insta
55
- npm run build:binaries # cross-compile all platforms -> dist/bin/insta-<os>-<arch>(.exe) + SHA256SUMS
56
- # The version (baked into `insta --version`) defaults to package.json, or pass it: bash scripts/build-binaries.sh 1.2.3
45
+ insta login --oauth github
46
+ insta project create my-app
47
+ insta services add postgres db
48
+ insta services add compute api
49
+ insta secrets
50
+ insta deploy .
57
51
  ```
58
52
 
59
- Artifacts look like `insta-darwin-arm64` / `insta-linux-x64` / `insta-windows-x64.exe` (`file` reports native Mach-O/ELF/PE executables).
60
- `dist/` is gitignored; binaries are not committed — CI publishes them to releases.
53
+ `project create` makes an empty project and links the current directory. Services are
54
+ opt-in, so you add only what you need. `secrets` writes the current branch's credentials to
55
+ `./.env`. `deploy .` builds the directory remotely and ships it to the branch's compute
56
+ service; it needs a `Dockerfile`, but no local Docker.
61
57
 
62
- ## Quickstart
58
+ ## Authentication
63
59
 
64
60
  ```bash
65
- # Point at the control plane (defaults to http://localhost:8080; override with $INSTA_API_URL or --api-url)
66
- insta login --email you@example.com --password ****** --api-url http://localhost:8080
67
- insta project create my-app # create an empty project and link the current directory (no services by default)
68
- insta services add postgres db # add services on demand (postgres/storage/compute)
69
- insta services add compute api # compute is used to deploy images
70
- insta secrets # write the current branch's credentials to ./.env (secret seam)
71
- insta deploy --image <registry/img> # deploy a container image to the current branch's compute service
72
- insta status # login state + linked project/branch
61
+ insta login --email you@example.com # password from $INSTA_PASSWORD or a prompt
62
+ insta login --oauth github # or google, through the browser
63
+ insta login --env staging --oauth github # log in to a specific deployment
73
64
  ```
74
65
 
66
+ Tokens are stored in `~/.insta/config.json` and refresh automatically.
67
+
68
+ `--oauth` starts a loopback listener on `127.0.0.1`, opens the browser at the control
69
+ plane's `/auth/cli/authorize`, and receives the token back on that listener once the
70
+ provider has authorized you. Nothing is pasted by hand.
71
+
72
+ If you operate your own control plane, the provider's OAuth app needs
73
+ `GITHUB_OAUTH_CLIENT_ID` / `GITHUB_OAUTH_CLIENT_SECRET` (or the `GOOGLE_*` equivalents), and
74
+ its callback URL must be `{INSTA_API_BASE_URL}/api/auth/callback/<provider>` — the control
75
+ plane's address, not the CLI's loopback address.
76
+
77
+ ## How it works
78
+
79
+ ### Services are branch-scoped
80
+
81
+ A project holds services (`postgres`, `storage`, `compute`) and each branch owns its own
82
+ set. `insta branch create feature-x` forks the parent's services: a Neon branch per
83
+ Postgres, a copy-on-write bucket per storage, a clone of every compute service. From there
84
+ the two branches diverge independently. A project is capped at 10 branches.
85
+
86
+ ### Credentials come from the secret seam, not a file you maintain
87
+
88
+ `insta secrets` fetches the current branch's bundle and writes `./.env`. `insta run <cmd>`
89
+ does the same without touching disk, injecting the bundle into the child process only.
90
+ Credential names are per service — `DATABASE_URL`, `BUCKET_NAME`, `AWS_ACCESS_KEY_ID` —
91
+ suffixed with the service name when a project has more than one service of a type.
92
+
93
+ ### Destructive actions can require approval
94
+
95
+ Reading secrets, deploying, deleting a project or branch, and changing services are
96
+ governed by a per-project policy. Where the policy says `approve`, the command stops and
97
+ prints an approval id for an admin to grant with `insta approvals approve <id>`. Run
98
+ `insta policy get` for the live policy.
99
+
100
+ ### Agents get the same surface
101
+
102
+ `insta manifest` prints an agent-legible view of every branch and its URLs. `insta setup
103
+ agent` installs the InstaCloud skill and registers the remote MCP server for the coding
104
+ agents on the machine.
105
+
75
106
  ## Environments
76
107
 
77
- `prod` and `staging` are **separate deployments** — different regions, different databases,
78
- different auth. A session from one cannot authenticate against the other, so switching drops the
79
- stored session and you log in again.
108
+ `prod` and `staging` are separate deployments, in different regions, with different
109
+ databases and different auth. A session minted by one cannot authenticate against the
110
+ other, so switching environments drops the stored session and you log in again.
80
111
 
81
112
  | | `prod` (default) | `staging` |
82
113
  |---|---|---|
83
- | control plane | `api.instacloud.com` (us-east-2) | `api.staging.instacloud.com` (us-west-1) |
114
+ | control plane | `api.instacloud.com` | `api.staging.instacloud.com` |
84
115
  | MCP server | `mcp.instacloud.com/mcp` | `mcp.staging.instacloud.com/mcp` |
85
- | registers as | `insta-cloud` | `insta-cloud-staging` |
86
- | agent skills | `InsForge/insta-skills` | `InsForge/insta-skills@devel` |
87
- | CLI channel | latest stable release | newest prerelease (`v*-rc.N`), else stable |
116
+ | MCP registers as | `insta-cloud` | `insta-cloud-staging` |
117
+ | agent skills | `InsForge/insta-skills` | `InsForge/insta-skills#devel` |
118
+ | CLI channel | latest stable release | newest prerelease, else stable |
88
119
 
89
120
  ```bash
90
- insta env # show the current environment and everything derived from it
91
- insta env use staging # switch (persisted to ~/.insta/config.json)
92
- insta login --env staging --oauth github
121
+ insta env # current environment and everything derived from it
122
+ insta env use staging # switch; persisted to ~/.insta/config.json
93
123
  ```
94
124
 
95
- Control plane, MCP host **and** skill source are all resolved from one switch, so a machine can
96
- never end up with its CLI on staging while its agents talk to prod and read prod's skill text.
97
- Distinct MCP registration names mean both environments can be installed side by side.
98
-
99
- Resolution order, most specific first:
100
-
101
- 1. `INSTA_API_URL` — a literal URL. The only way to reach a host no environment name covers
102
- (`insta-oss` on localhost, a preview deployment). `INSTA_MCP_URL` and `INSTA_SKILLS_REPO` do the
103
- same for the MCP host and the skill source.
104
- 2. `INSTA_ENV` — `prod` | `staging`. An unrecognised value is an error, never a silent fallback.
105
- 3. the persisted `apiUrl` in `~/.insta/config.json`.
106
- 4. `prod`.
107
-
108
- Prereleases never take the `latest` GitHub release or the `latest` npm dist-tag — they publish with
109
- `--prerelease` and under npm's `next` tag — so a staging build can't reach production installers.
110
-
111
- ## Commands
125
+ The control plane, the MCP host and the skill source all resolve from that one switch, so a
126
+ machine cannot end up running staging while its agents read production's skill text. The
127
+ two MCP registrations use different names, so both environments can be installed side by
128
+ side.
112
129
 
113
- | Command | Description |
114
- |------|------|
115
- | `insta login [--email --password --api-url --env]` | Log in (email/password; tokens auto-refresh) |
116
- | `insta env [--json]` / `insta env use <prod\|staging>` | Show or switch deployment environment |
117
- | `insta login --oauth <github\|google>` | Browser OAuth login (starts a local loopback port; the token is carried back automatically after browser authorization) |
118
- | `insta logout` / `insta status [--json]` | Log out / show status |
119
- | `insta org list [--json]` / `org create <name>` | Organizations (each user may own only one free org) |
120
- | `insta project create <name> [--org]` | Create an empty project and link it (no services by default) |
121
- | `insta project list [--org] [--json]` / `link <id>` / `delete` | Project management |
122
- | `insta services add <postgres\|storage\|compute> <name>` | Provision a service on demand (postgres/compute get a default access domain) |
123
- | `insta services list [--json]` / `services remove <type> <name>` | List / remove services |
124
- | `insta services scale compute <name> <number> [region]` | Set the compute machine count (paid tiers; rejected on free) |
125
- | `insta services upgrade <compute\|postgres> <name> <spec>` | Upgrade the spec (paid tiers; upgrade only, no downgrade) |
126
- | `insta branch create <name> [--from]` | Create a branch environment (materializes the project's current services; up to 10 branches per project) |
127
- | `insta branch list [--json]` / `switch <name>` / `delete <name>` | Branch management |
128
- | `insta secrets [--branch -o --print --json]` | Secret seam: write credentials to `.env` |
129
- | `insta secrets list [--branch]` | List secret names only |
130
- | `insta deploy --image <url> [--branch --group --port]` | Deploy an image |
131
- | `insta manifest [--json]` | Agent-readable environment manifest |
132
- | `insta metrics <db\|compute> [group] [--branch --from --to --step --json]` | Resource metrics (compute=Fly; db limited) |
133
- | `insta logs <db\|compute> [group] [--branch --limit --region --instance --json]` | Runtime logs (compute=Fly; db limited) |
134
- | `insta events [--branch --limit --json]` | Audit + agent event timeline |
135
- | `insta usage [--from --to --json]` | Resource usage aggregated by meter (includes costUsd) |
136
- | `insta billing [--org --json]` | Current billing-cycle summary (tier / quota / used / overage / status) |
137
- | `insta billing upgrade <pro\|enterprise> [--org --no-open --json]` | Subscribe to a paid tier via Stripe Checkout; returns and opens the payment link |
138
- | `insta billing portal [--org --no-open --json]` | Open the Stripe Customer Portal (change plan / card / cancel) |
139
- | `insta approvals list [--status] [--json]` | Governance approval list |
140
- | `insta approvals approve <id> [--always]` / `deny <id>` | Approve / deny (admin) |
141
- | `insta policy get [--json]` / `policy set <action> <decision>` | Governance policy (actions include `service.add/remove/scale/upgrade`) |
142
-
143
- When a governance-gated operation (`secrets.read`/`deploy`/`project.delete`/`branch.delete`/`service.add`/`service.remove`/`service.scale`/`service.upgrade`) hits an approval,
144
- the CLI prompts `approval required — run: insta approvals approve <id>`.
145
-
146
- ## Configuration locations
147
-
148
- - Global: `~/.insta/config.json` (apiUrl + access/refresh token + user)
149
- - Project: `./.insta/project.json` (projectId / orgId / current branch)
150
-
151
- ## Local end-to-end run
152
-
153
- The platform provides a `dev:fake` mode (fake provider adapters, no Neon/Fly/Tigris credentials required):
130
+ To install against staging directly:
154
131
 
155
132
  ```bash
156
- # 1) Start Postgres + the platform dev server (see ../platform)
157
- docker run -d --name pg -e POSTGRES_PASSWORD=insta -e POSTGRES_DB=insta_dev -p 55432:5432 postgres:16-alpine
158
- cd ../platform && DATABASE_URL='postgres://postgres:insta@localhost:55432/insta_dev' PORT=8899 npm run dev:fake
159
-
160
- # 2) Run the full flow with the CLI (signup goes through /auth/signup + /auth/verify-email; in dev mode the verification code is printed in the server logs)
161
- INSTA_API_URL=http://localhost:8899 insta login --email you@x.com --password ...
133
+ curl -fsSL agents.staging.instacloud.com | sh
162
134
  ```
163
135
 
164
- ## OAuth browser login
136
+ That host is a CloudFront cache, so after a change to the installer it can serve the
137
+ previous copy for up to about a day. This form is equivalent and always current:
165
138
 
166
139
  ```bash
167
- insta login --oauth github # or google
168
- # CLI starts a local loopback port → opens the browser to /auth/cli/authorize → Better Auth runs provider authorization →
169
- # the platform reads the session cookie to exchange for a bearer token → carries it back to the loopback port → CLI stores it as login state
140
+ curl -fsSL https://raw.githubusercontent.com/InsForge/insta-cli/main/install.sh | sh -s -- --agents --staging -y
170
141
  ```
171
142
 
172
- > The platform must have an OAuth app configured for that provider (`GITHUB_OAUTH_CLIENT_ID/SECRET` or `GOOGLE_*`),
173
- > and the app's callback URL must be **`{INSTA_API_BASE_URL}/api/auth/callback/<provider>`** (not the loopback address).
143
+ If the environment cannot be applied — an installed CLI older than 0.0.23 has no `insta
144
+ env` — the installer exits non-zero and says so, rather than leaving you silently pointed
145
+ at production. The canonical usage is `curl … | sh && insta project create`, often run
146
+ unattended by an agent, and a silent fallback there would provision real production
147
+ infrastructure.
148
+
149
+ Resolution order, most specific first:
150
+
151
+ 1. `INSTA_API_URL` — a literal URL, and the only way to reach a host no environment name
152
+ covers, such as a local daemon or a preview deployment. `INSTA_MCP_URL` and
153
+ `INSTA_SKILLS_REPO` do the same for the MCP host and the skill source.
154
+ 2. `INSTA_ENV` — `prod` or `staging`. An unrecognised value is an error, never a fallback.
155
+ 3. The `apiUrl` persisted in `~/.insta/config.json`.
156
+ 4. `prod`.
157
+
158
+ Prereleases publish with `--prerelease` on GitHub and under npm's `next` tag, so a staging
159
+ build never reaches a production installer.
160
+
161
+ ## Commands
174
162
 
175
- > `metrics` / `logs` / `usage` are supported (usage is aggregated at the collection layer). Multiple compute services (`services add compute`) and `services scale/upgrade` are implemented; image building will come later. Multiple postgres/storage services (>1 per project) are currently constrained by the credential seam and remain future work.
163
+ `insta --help` is the authoritative list. For flags, approval gates and plan limits, see the
164
+ [full command reference](https://github.com/InsForge/insta-skills/blob/main/insta/cli-reference.md).
165
+
166
+ | Command | What it covers |
167
+ |---|---|
168
+ | `insta login` · `logout` · `status` | Email/password or `--oauth github\|google`; `status` shows the environment, login and linked project/branch |
169
+ | `insta env` | `show` · `use <prod\|staging>` |
170
+ | `insta setup` | `agent` — install the skill and register MCP for every coding agent |
171
+ | `insta mcp` | `install` — register the remote MCP server only |
172
+ | `insta org` | `list` · `create` (one free org per user) |
173
+ | `insta project` | `create` · `list` · `link` · `delete` |
174
+ | `insta branch` | `create` · `list` · `switch` · `delete` · `merge` |
175
+ | `insta services` | `add` · `list` · `remove` · `rename` · `set-access` · `scale` · `upgrade` · `secrets` |
176
+ | `insta secrets` | Write `.env`, plus `list` · `set` · `unset` · `tree` |
177
+ | `insta run <cmd>` | Run a command with the branch bundle injected, nothing written to disk |
178
+ | `insta deploy [dir]` | Deploy a source directory (built remotely) or `--image <url>` |
179
+ | `insta compute` | `start` · `stop` · `suspend` · `status` · `set-domain` · `check-domain` · `remove-domain` |
180
+ | `insta regions` | Regions available for postgres and compute |
181
+ | `insta manifest` | Agent-legible view of every branch and its URLs |
182
+ | `insta metrics` · `logs` · `events` | Service metrics; runtime logs (`--deploy` for deploy events); audit timeline |
183
+ | `insta usage` · `billing` | Usage by billing dimension; `billing upgrade` · `billing portal` |
184
+ | `insta approvals` | `list` · `approve` · `deny` |
185
+ | `insta policy` | `get` · `set <action> <decision>` |
186
+ | `insta observe` | `install` · `uninstall` · `report` · `sync` — local credential audit |
187
+ | `insta upgrade` · `autoupdate` | Update the CLI; show or set auto-update |
188
+
189
+ ## Configuration
190
+
191
+ | Location | Contents |
192
+ |---|---|
193
+ | `~/.insta/config.json` | API URL, access and refresh tokens, user, auto-update preference |
194
+ | `./.insta/project.json` | Project id, org id, current branch |
195
+
196
+ | Variable | Effect |
197
+ |---|---|
198
+ | `INSTA_API_URL` | Control-plane URL; outranks every other source |
199
+ | `INSTA_ENV` | `prod` or `staging` |
200
+ | `INSTA_MCP_URL` · `INSTA_SKILLS_REPO` | Override the MCP host and the agent-skill source |
201
+ | `INSTA_PROJECT_ID` · `INSTA_ORG_ID` · `INSTA_BRANCH` | Target a project, org or branch without linking |
202
+ | `INSTA_PASSWORD` | Password for non-interactive login |
203
+ | `INSTA_NO_AUTOUPDATE` | Disable self-update |
204
+
205
+ ## Agent skills
206
+
207
+ The `insta` skill and its task guides live in
208
+ [InsForge/insta-skills](https://github.com/InsForge/insta-skills). `insta setup agent`
209
+ installs it user-globally for every coding agent on the machine. `insta project create` and
210
+ `insta project link` additionally install the stack skills (Neon Postgres, Tigris, Better
211
+ Auth) into the project, along with the `insta observe` credential-audit hook.
212
+
213
+ ## Contributing
214
+
215
+ Dev loop, architecture, cross-compilation and the release process are in
216
+ [CONTRIBUTING.md](CONTRIBUTING.md). Issues and pull requests are welcome.
217
+
218
+ ## License
219
+
220
+ Apache 2.0. See [LICENSE](LICENSE).
@@ -70,4 +70,21 @@ export async function computeStatus(serviceName, opts) {
70
70
  return printJson(r);
71
71
  info(`compute ${serviceName ?? id}: desired=${r.desiredState} live=${r.state}`);
72
72
  }
73
+ // ---- always-on (opt out of scale-to-zero; all plans; billing is actual usage either way) ----
74
+ export async function computeAlwaysOn(mode, serviceName, opts) {
75
+ if (mode !== 'on' && mode !== 'off')
76
+ throw new Error('mode must be on|off');
77
+ const api = await ApiClient.load();
78
+ const p = await requireProject();
79
+ const branch = opts.branch ?? p.branch;
80
+ const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(branch)}`);
81
+ const id = resolveComputeServiceId(services, serviceName);
82
+ const res = await api.rawRequest('PUT', `/projects/${p.projectId}/services/${id}/always-on`, { enabled: mode === 'on' });
83
+ if (handleApproval(res))
84
+ return;
85
+ if (opts.json)
86
+ return printJson(res.body);
87
+ const on = res.body.service?.always_on;
88
+ info(`compute ${res.body.service?.name ?? id}: always-on ${on ? 'ENABLED — machines stay warm (no cold starts; idle RAM bills at actual usage)' : 'disabled — scales to zero when idle (default)'}`);
89
+ }
73
90
  //# sourceMappingURL=compute.js.map
@@ -0,0 +1,27 @@
1
+ import { ApiClient, requireProject } from '../api.js';
2
+ import { info, printJson, handleApproval } from '../util.js';
3
+ // Toggle a postgres service between scale-to-zero (the default: instance suspends when idle,
4
+ // cold-starts on the next connection) and always-on (instance stays warm; idle RAM bills at
5
+ // actual usage). Thin wrapper over PATCH /database/settings {scaleToZero} — insta-db-backed
6
+ // postgres only; Neon-backed services manage their own autosuspend and the platform returns an
7
+ // error for them.
8
+ export async function dbAlwaysOn(mode, opts) {
9
+ if (mode !== 'on' && mode !== 'off')
10
+ throw new Error('mode must be on|off');
11
+ const api = await ApiClient.load();
12
+ const p = await requireProject();
13
+ const qs = new URLSearchParams();
14
+ const branch = opts.branch ?? p.branch;
15
+ if (branch)
16
+ qs.set('branch', branch);
17
+ if (opts.group)
18
+ qs.set('group', opts.group);
19
+ const res = await api.rawRequest('PATCH', `/projects/${p.projectId}/database/settings${qs.toString() ? `?${qs}` : ''}`, { scaleToZero: mode !== 'on' });
20
+ if (handleApproval(res))
21
+ return;
22
+ if (opts.json)
23
+ return printJson(res.body);
24
+ const s2z = res.body?.scaleToZero;
25
+ info(`postgres ${opts.group ?? 'default'}: always-on ${s2z === false ? 'ENABLED — instance stays warm (no cold starts; idle RAM bills at actual usage)' : 'disabled — scales to zero when idle (default; first connection after idle cold-starts)'}`);
26
+ }
27
+ //# sourceMappingURL=db.js.map
@@ -53,6 +53,7 @@ export function servicesAddRequestBody(type, name, branch, opts) {
53
53
  type, name, ...(branch ? { branch } : {}), public: !!opts.public,
54
54
  ...(opts.image ? { image: opts.image } : {}), ...(opts.port ? { port: Number(opts.port) } : {}),
55
55
  ...(opts.region ? { region: opts.region } : {}),
56
+ ...(opts.alwaysOn ? { alwaysOn: true } : {}),
56
57
  };
57
58
  }
58
59
  export async function servicesAdd(type, name, opts = {}) {
@@ -65,6 +66,8 @@ export async function servicesAdd(type, name, opts = {}) {
65
66
  throw new Error('--image is only valid for compute services');
66
67
  if (opts.port && type !== 'compute')
67
68
  throw new Error('--port is only valid for compute services');
69
+ if (opts.alwaysOn && type !== 'compute')
70
+ throw new Error('--always-on is only valid for compute services (for postgres, use `insta db always-on on` after creation)');
68
71
  const api = await ApiClient.load();
69
72
  const p = await requireProject();
70
73
  const branch = opts.branch ?? p.branch;
package/dist/index.js CHANGED
@@ -17,6 +17,7 @@ import * as regions from './commands/regions.js';
17
17
  import * as secretsCmd from './commands/secrets.js';
18
18
  import { deploy } from './commands/deploy.js';
19
19
  import * as computeCmd from './commands/compute.js';
20
+ import * as dbCmd from './commands/db.js';
20
21
  import { manifest } from './commands/manifest.js';
21
22
  import * as govern from './commands/govern.js';
22
23
  import * as observe from './commands/observe.js';
@@ -111,6 +112,7 @@ svc.command('add <type> <name>').description('Provision a service on demand (ass
111
112
  .option('--public', 'storage only: serve the bucket with anonymous public-read (default private)')
112
113
  .option('--image <url>', 'compute only: run this container image at creation')
113
114
  .option('--port <n>', 'compute only: port the image listens on (default 8080)')
115
+ .option('--always-on', 'compute only: create as always-on — never scales to zero (all plans; billing is actual usage either way)')
114
116
  .action(guard((type, name, o) => services.servicesAdd(type, name, o)));
115
117
  svc.command('list').option('--json').option('--branch <branch>', 'branch (default: current)')
116
118
  .action(guard((o) => services.servicesList(o)));
@@ -161,6 +163,13 @@ compute.command('suspend [service]').description('Suspend a compute service (RAM
161
163
  .option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((service, o) => computeCmd.computeSuspend(service, o)));
162
164
  compute.command('status [service]').description("Show a compute service's desired vs. live state")
163
165
  .option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((service, o) => computeCmd.computeStatus(service, o)));
166
+ compute.command('always-on <mode> [service]').description('Set a compute service always-on (mode: on|off). on = machines never scale to zero; off = default scale-to-zero. All plans; billing is actual usage either way')
167
+ .option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((mode, service, o) => computeCmd.computeAlwaysOn(mode, service, o)));
168
+ // ---- db (postgres service controls) ----
169
+ const db = program.command('db').description('Postgres service controls (always-on / scale-to-zero)');
170
+ db.command('always-on <mode>').description('Set a postgres service always-on (mode: on|off). on = instance stays warm, no cold starts; off = default scale-to-zero (idle instance suspends; first connection cold-starts). insta-db-backed services only')
171
+ .option('--json').option('--branch <branch>', 'branch (default: current)').option('--group <g>', 'postgres service name (default: the sole/default one)')
172
+ .action(guard((mode, o) => dbCmd.dbAlwaysOn(mode, o)));
164
173
  // ---- manifest ----
165
174
  program.command('manifest').description('Print an agent-legible view of the project environments').option('--json').action(guard((o) => manifest(o)));
166
175
  // ---- regions ----
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insta",
3
- "version": "0.0.23-rc.1",
3
+ "version": "0.0.24",
4
4
  "type": "module",
5
5
  "description": "InstaCloud CLI — a thin client of the platform control-plane API.",
6
6
  "keywords": [