@inquir/compute-cli 0.3.0 → 0.4.1

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.
Files changed (106) hide show
  1. package/README.md +528 -406
  2. package/dist/commands/admin-tenants.d.ts +11 -0
  3. package/dist/commands/admin-tenants.d.ts.map +1 -0
  4. package/dist/commands/admin-tenants.js +318 -0
  5. package/dist/commands/admin-tenants.js.map +1 -0
  6. package/dist/commands/admin.d.ts +2 -0
  7. package/dist/commands/admin.d.ts.map +1 -0
  8. package/dist/commands/admin.js +445 -0
  9. package/dist/commands/admin.js.map +1 -0
  10. package/dist/commands/apps-describe.d.ts +9 -0
  11. package/dist/commands/apps-describe.d.ts.map +1 -0
  12. package/dist/commands/apps-describe.js +125 -0
  13. package/dist/commands/apps-describe.js.map +1 -0
  14. package/dist/commands/apps-instances.d.ts +18 -0
  15. package/dist/commands/apps-instances.d.ts.map +1 -0
  16. package/dist/commands/apps-instances.js +87 -0
  17. package/dist/commands/apps-instances.js.map +1 -0
  18. package/dist/commands/apps-observability.d.ts +15 -0
  19. package/dist/commands/apps-observability.d.ts.map +1 -0
  20. package/dist/commands/apps-observability.js +310 -0
  21. package/dist/commands/apps-observability.js.map +1 -0
  22. package/dist/commands/apps-promote.d.ts +31 -0
  23. package/dist/commands/apps-promote.d.ts.map +1 -0
  24. package/dist/commands/apps-promote.js +115 -0
  25. package/dist/commands/apps-promote.js.map +1 -0
  26. package/dist/commands/apps-resources.d.ts +6 -0
  27. package/dist/commands/apps-resources.d.ts.map +1 -0
  28. package/dist/commands/apps-resources.js +107 -0
  29. package/dist/commands/apps-resources.js.map +1 -0
  30. package/dist/commands/apps.d.ts +118 -2
  31. package/dist/commands/apps.d.ts.map +1 -1
  32. package/dist/commands/apps.js +999 -110
  33. package/dist/commands/apps.js.map +1 -1
  34. package/dist/commands/config.d.ts.map +1 -1
  35. package/dist/commands/config.js +7 -3
  36. package/dist/commands/config.js.map +1 -1
  37. package/dist/commands/delete.d.ts.map +1 -1
  38. package/dist/commands/delete.js +10 -2
  39. package/dist/commands/delete.js.map +1 -1
  40. package/dist/commands/deploy.js +3 -3
  41. package/dist/commands/deploy.js.map +1 -1
  42. package/dist/commands/init.js +15 -15
  43. package/dist/commands/login.d.ts.map +1 -1
  44. package/dist/commands/login.js +78 -33
  45. package/dist/commands/login.js.map +1 -1
  46. package/dist/commands/logout.d.ts.map +1 -1
  47. package/dist/commands/logout.js +37 -5
  48. package/dist/commands/logout.js.map +1 -1
  49. package/dist/commands/mcp.d.ts +13 -0
  50. package/dist/commands/mcp.d.ts.map +1 -1
  51. package/dist/commands/mcp.js +184 -77
  52. package/dist/commands/mcp.js.map +1 -1
  53. package/dist/commands/projects.d.ts.map +1 -1
  54. package/dist/commands/projects.js +107 -11
  55. package/dist/commands/projects.js.map +1 -1
  56. package/dist/index.js +9 -1
  57. package/dist/index.js.map +1 -1
  58. package/dist/lib/finite-source-command-client.d.ts +3 -0
  59. package/dist/lib/finite-source-command-client.d.ts.map +1 -0
  60. package/dist/lib/finite-source-command-client.js +3 -0
  61. package/dist/lib/finite-source-command-client.js.map +1 -0
  62. package/dist/lib/mcp-io.d.ts +23 -0
  63. package/dist/lib/mcp-io.d.ts.map +1 -0
  64. package/dist/lib/mcp-io.js +185 -0
  65. package/dist/lib/mcp-io.js.map +1 -0
  66. package/dist/lib/mcp-source-commands.d.ts +17 -0
  67. package/dist/lib/mcp-source-commands.d.ts.map +1 -0
  68. package/dist/lib/mcp-source-commands.js +345 -0
  69. package/dist/lib/mcp-source-commands.js.map +1 -0
  70. package/dist/utils/api.d.ts +39 -14
  71. package/dist/utils/api.d.ts.map +1 -1
  72. package/dist/utils/api.js +43 -6
  73. package/dist/utils/api.js.map +1 -1
  74. package/dist/utils/apps-presentation.d.ts +8 -1
  75. package/dist/utils/apps-presentation.d.ts.map +1 -1
  76. package/dist/utils/apps-presentation.js +35 -1
  77. package/dist/utils/apps-presentation.js.map +1 -1
  78. package/dist/utils/auth.d.ts +21 -1
  79. package/dist/utils/auth.d.ts.map +1 -1
  80. package/dist/utils/auth.js +119 -22
  81. package/dist/utils/auth.js.map +1 -1
  82. package/dist/utils/browser.d.ts +12 -0
  83. package/dist/utils/browser.d.ts.map +1 -1
  84. package/dist/utils/browser.js +37 -16
  85. package/dist/utils/browser.js.map +1 -1
  86. package/dist/utils/errors.d.ts.map +1 -1
  87. package/dist/utils/errors.js +41 -0
  88. package/dist/utils/errors.js.map +1 -1
  89. package/dist/utils/msys-path.d.ts +14 -0
  90. package/dist/utils/msys-path.d.ts.map +1 -0
  91. package/dist/utils/msys-path.js +55 -0
  92. package/dist/utils/msys-path.js.map +1 -0
  93. package/dist/utils/package-metadata.js +1 -1
  94. package/dist/utils/project-context.d.ts.map +1 -1
  95. package/dist/utils/project-context.js +7 -5
  96. package/dist/utils/project-context.js.map +1 -1
  97. package/dist/utils/project-lookup.d.ts +10 -0
  98. package/dist/utils/project-lookup.d.ts.map +1 -0
  99. package/dist/utils/project-lookup.js +52 -0
  100. package/dist/utils/project-lookup.js.map +1 -0
  101. package/dist/utils/source-pack.d.ts +24 -0
  102. package/dist/utils/source-pack.d.ts.map +1 -0
  103. package/dist/utils/source-pack.js +63 -0
  104. package/dist/utils/source-pack.js.map +1 -0
  105. package/package.json +26 -26
  106. package/skill/SKILL.md +73 -67
package/README.md CHANGED
@@ -1,69 +1,73 @@
1
- # @inquir/compute-cli
2
-
3
- CLI for workspace-first Inquir Compute development.
4
-
5
- ## Install
6
-
7
- Global (recommended). `@latest` also upgrades an existing install to the newest
8
- published version:
9
-
10
- ```bash
11
- npm install -g @inquir/compute-cli@latest
12
- ```
13
-
14
- Verify it's on your `PATH`:
15
-
16
- ```bash
17
- inquir --version
18
- inquir --help
19
- ```
20
-
21
- Or run without installing:
22
-
23
- ```bash
24
- npx @inquir/compute-cli@latest --help
25
- ```
26
-
27
- > Requires **Node.js 22+**. To upgrade later, re-run the install command above. On
28
- > macOS/Linux you may need `sudo` for a global install, or use a Node version
29
- > manager (nvm/fnm) to avoid it. To remove: `npm uninstall -g @inquir/compute-cli`.
30
-
31
- ## Concepts
32
-
33
- - **Function**: a single compute unit with typed input/output (Zod schemas). Defined with `defineFunction()`. Run locally with `inquir run`, deployed and invoked remotely with `inquir deploy` / `inquir invoke`.
34
- - **Pipeline**: a declarative DAG of functions defined with `definePipeline()`. Registered in the codegen registry for client use; remote run/deploy for pipelines is handled by the backend.
35
- - **Client**: the generated TypeScript module at `.inquir/generated/client.ts`. Wraps remote invocation with schemas inferred from your source. Import it in your application code.
36
- - **Source of truth**: your local files under `functionsDir` and `pipelinesDir`. `registry.json` is a derived artifact rebuilt by `inquir codegen` — never hand-edit it.
37
- - **Local ↔ remote link**: each deployed remote function stores a `linkedLocalName` (your local asset name) and a `sourceHash`. `inquir sync status` compares hashes to detect drift.
38
-
39
- ## Quick Start
40
-
41
- ```bash
42
- inquir init
43
- inquir codegen
44
- inquir list
45
- inquir run hello --payload '{"name":"World"}'
46
- ```
47
-
48
- ## Authentication
49
-
50
- The recommended way to authenticate on your own machine is a browser login,
51
- which mints a user-scoped **Personal Access Token** (PAT) bound to your account
52
- and stores it in `~/.inquir/config.json`:
53
-
54
- ```bash
55
- inquir login # opens your browser to approve this device
56
- inquir whoami # show the signed-in user + active workspace
57
- ```
58
-
59
- `inquir login` prints a short code and opens a dashboard page; confirm the code
60
- matches and click **Authorize**. The CLI then receives its token automatically.
61
-
62
- Other login modes:
63
-
64
- ```bash
65
- inquir login --browserless # print the URL + code instead of opening a browser
66
- inquir login --token <pat> # non-interactive (CI): use a PAT created in the dashboard
1
+ # @inquir/compute-cli
2
+
3
+ CLI for workspace-first Inquir Compute development.
4
+
5
+ ## Install
6
+
7
+ Global (recommended). `@latest` also upgrades an existing install to the newest
8
+ published version:
9
+
10
+ ```bash
11
+ npm install -g @inquir/compute-cli@latest
12
+ ```
13
+
14
+ Verify it's on your `PATH`:
15
+
16
+ ```bash
17
+ inquir --version
18
+ inquir --help
19
+ ```
20
+
21
+ Or run without installing:
22
+
23
+ ```bash
24
+ npx @inquir/compute-cli@latest --help
25
+ ```
26
+
27
+ > Requires **Node.js 22+**. To upgrade later, re-run the install command above. On
28
+ > macOS/Linux you may need `sudo` for a global install, or use a Node version
29
+ > manager (nvm/fnm) to avoid it. To remove: `npm uninstall -g @inquir/compute-cli`.
30
+
31
+ ## Concepts
32
+
33
+ - **Function**: a single compute unit with typed input/output (Zod schemas). Defined with `defineFunction()`. Run locally with `inquir run`, deployed and invoked remotely with `inquir deploy` / `inquir invoke`.
34
+ - **Pipeline**: a declarative DAG of functions defined with `definePipeline()`. Registered in the codegen registry for client use; remote run/deploy for pipelines is handled by the backend.
35
+ - **Client**: the generated TypeScript module at `.inquir/generated/client.ts`. Wraps remote invocation with schemas inferred from your source. Import it in your application code.
36
+ - **Source of truth**: your local files under `functionsDir` and `pipelinesDir`. `registry.json` is a derived artifact rebuilt by `inquir codegen` — never hand-edit it.
37
+ - **Local ↔ remote link**: each deployed remote function stores a `linkedLocalName` (your local asset name) and a `sourceHash`. `inquir sync status` compares hashes to detect drift.
38
+
39
+ ## Quick Start
40
+
41
+ ```bash
42
+ inquir init
43
+ inquir codegen
44
+ inquir list
45
+ inquir run hello --payload '{"name":"World"}'
46
+ ```
47
+
48
+ ## Authentication
49
+
50
+ The recommended way to authenticate on your own machine is a browser login,
51
+ which mints a user-scoped **Personal Access Token** (PAT) bound to your account
52
+ and stores it in `~/.inquir/config.json`:
53
+
54
+ ```bash
55
+ inquir login # opens your browser to approve this device
56
+ inquir whoami # show the signed-in user + active workspace
57
+ ```
58
+
59
+ `inquir login` prints a short code and opens a dashboard page; confirm the code
60
+ matches and click **Authorize**. The CLI then receives its token automatically.
61
+ Browser-issued CLI sessions expire (90 days by default; the server can configure
62
+ a shorter lifetime). The CLI records the issuing API and expiry with the token.
63
+ Logging in again saves the new session before revoking the previous session owned
64
+ by that profile, unless another stored profile or environment variable still uses it.
65
+
66
+ Other login modes:
67
+
68
+ ```bash
69
+ inquir login --browserless # print the URL + code instead of opening a browser
70
+ inquir login --token <pat> # non-interactive (CI): use a PAT created in the dashboard
67
71
  inquir login --name "my CI" # label the device/token shown in the dashboard
68
72
  ```
69
73
 
@@ -82,30 +86,37 @@ the token remains saved and subsequent commands do not reuse the previous
82
86
  account's stored workspace.
83
87
 
84
88
  Create and revoke PATs from the dashboard under **API Keys → Personal Access
85
- Tokens**. To sign out and remove the stored token: `inquir logout`.
86
-
87
- > A PAT can deploy to **any workspace you belong to**. A workspace-scoped **API
88
- > key** is pinned to a single workspace and ignores workspace switching.
89
-
90
- ## Workspaces
91
-
92
- A single login works across every workspace you're a member of. List them and
93
- choose a default:
94
-
95
- ```bash
96
- inquir workspaces # list workspaces (active one marked with *)
97
- inquir use <slug|id> # set the active workspace for subsequent commands
98
- ```
99
-
100
- Target a different workspace for a single command with `--workspace`:
101
-
102
- ```bash
103
- inquir deploy hello --workspace acme-prod
104
- inquir deploys hello --workspace acme-prod
105
- inquir whoami --workspace acme-prod
106
- ```
107
-
108
- Under the hood, user-scoped credentials send an `X-Inquir-Workspace` header; the
89
+ Tokens**. `inquir logout` revokes its browser-issued CLI session at the API that
90
+ issued it, then clears the local credentials and workspace. If the API is offline,
91
+ the local logout still completes and warns that server revocation was not confirmed.
92
+ Imported PATs (`--token`), tokens saved by older CLI versions, and credentials shared
93
+ with another profile are only cleared locally; revoke them in the dashboard when
94
+ they are no longer needed. Shell environment variables are never removed by logout.
95
+ `inquir logout --env staging` leaves the default profile intact and prevents the
96
+ logged-out profile from inheriting its credentials again.
97
+
98
+ > A PAT can deploy to **any workspace you belong to**. A workspace-scoped **API
99
+ > key** is pinned to a single workspace and ignores workspace switching.
100
+
101
+ ## Workspaces
102
+
103
+ A single login works across every workspace you're a member of. List them and
104
+ choose a default:
105
+
106
+ ```bash
107
+ inquir workspaces # list workspaces (active one marked with *)
108
+ inquir use <slug|id> # set the active workspace for subsequent commands
109
+ ```
110
+
111
+ Target a different workspace for a single command with `--workspace`:
112
+
113
+ ```bash
114
+ inquir deploy hello --workspace acme-prod
115
+ inquir deploys hello --workspace acme-prod
116
+ inquir whoami --workspace acme-prod
117
+ ```
118
+
119
+ Under the hood, user-scoped credentials send an `X-Inquir-Workspace` header; the
109
120
  server verifies your membership before honoring it.
110
121
 
111
122
  ## Application projects
@@ -122,6 +133,8 @@ inquir projects use shop
122
133
  inquir apps create api --port 3000
123
134
  inquir apps create db --template postgres --project shop
124
135
  inquir projects add shop existing-app
136
+ inquir projects move shop db # file it in shop, take it out of its other projects
137
+ inquir projects remove shop old-api # unfile it; it keeps running
125
138
  inquir projects current
126
139
  inquir projects use --clear
127
140
  ```
@@ -132,268 +145,293 @@ selection is kept locally under `~/.inquir/project-contexts` and isolated by API
132
145
  the actual workspace, and signed-in user (or API key). Switching workspace or
133
146
  account therefore cannot silently reuse another context's project.
134
147
 
135
- `apps create --project <id|slug>` overrides the selection for one command.
136
- `projects use --clear` returns to automatic project creation. Selecting or adding
137
- to a project accepts its ID or slug; adding an application accepts its ID or name.
138
- All project commands support `--json`. Deploying an existing container application
139
- with `apps deploy` keeps its project membership; use `projects add` to file an
140
- existing application. This selection does not change the serverless `inquir deploy`
148
+ `apps create --project <project>` overrides the selection for one command.
149
+ `projects use --clear` returns to automatic project creation. Every project command
150
+ accepts a project's ID, slug, or unique display name, and an application's ID or
151
+ name. `apps create` prints the project an application landed in. All project
152
+ commands support `--json`. Deploying an existing container application with
153
+ `apps deploy` keeps its project membership. `projects add` files an application in
154
+ one more project; `projects move` files it and takes it out of every other one.
155
+ No project command archives a project: the API does not record which were created
156
+ automatically, so an emptied one is reported and left for you to archive in the
157
+ dashboard. This selection does not change the serverless `inquir deploy`
141
158
  workflow or local source/configuration project discovery.
142
-
143
- ## Deploy a function (remote)
144
-
145
- Once installed globally, deploying takes three steps:
146
-
147
- ```bash
148
- # 1. Authenticate. Easiest on a workstation:
149
- inquir login
150
- # For CI / scripts, export env vars for a one-off instead:
151
- # export INQUIR_API_URL="https://api.inquir.org"
152
- # export INQUIR_API_KEY="<api-key>" # workspace-scoped key, or
153
- # export INQUIR_TOKEN="<personal-access-token>"
154
-
155
- # 2. From your workspace (created by `inquir init`), deploy an asset by name.
156
- inquir deploy hello # streams build/deploy logs, exits non-zero on failure
157
-
158
- # 3. Invoke it remotely.
159
- inquir invoke hello --payload '{"name":"World"}'
160
- ```
161
-
162
- Get an API key from your Inquir Compute workspace settings. For CI, prefer the
163
- [`inquir-compute/deploy-action`](../deploy-action) GitHub Action (supports keyless
164
- OIDC auth), or run `inquir deploy --ci`.
165
-
166
- ## Commands
167
-
168
- **Project & local dev**
169
-
170
- - `inquir init [--name <name>] [--skip-install]` - scaffold `inquir.config.json`, folders, and a sample function. Interactive on a TTY (prompts for the project name); guides you to `login`/`run`/`deploy` afterward.
171
- - `inquir codegen` - discover assets and generate `.inquir/generated/client.ts` + `registry.json`.
172
- - `inquir list [--remote]` - list local assets, or deployed remote functions with `--remote`.
173
- - `inquir run <asset>` - run a local asset.
174
- - `inquir debug <asset>` - run locally with inspector enabled.
175
- - `inquir sync status` - compare local hashes with remote hashes (`in-sync`, `drift`, `missing`).
176
-
177
- **Auth & workspaces**
178
-
179
- - `inquir login` - authenticate the CLI (browser pairing, `--browserless`, or `--token`).
180
- - `inquir logout` - remove the stored token + active workspace for the current environment.
181
- - `inquir whoami` - show the signed-in user, active workspace, and role.
182
- - `inquir workspaces` - list the workspaces you belong to.
183
- - `inquir use <slug|id> [--local]` - set the active workspace; `--local` links *this project* by writing `workspace` into `inquir.config.json`.
184
-
185
- **Deploy & run remotely**
186
-
187
- - `inquir deploy <asset>` - package, upload, and deploy a function (async; streams build logs).
188
- - `inquir invoke <asset>` - invoke remote function by name / linked local name.
189
- - `inquir logs <asset>` - show recent remote invocation history.
190
- - `inquir deploys <function>` - list deploy history for a remote function.
191
- - `inquir status <deployId>` - show a deploy's status (`--follow` to stream logs).
192
- - `inquir rollback <function> [deployId]` - roll back to a previous successful deploy.
193
- - `inquir delete <function>` - delete a remote function (asks for confirmation; `--yes` to skip).
194
-
195
- **Container services (apps)**
196
-
197
- Long-lived containers from any OCI image — the counterpart to functions. HTTP
198
- ports are served over a hostname; TCP ports are published and dialled directly,
199
- so a database, SMTP relay or SSH endpoint is a first-class service with no
200
- runtime adapter involved.
201
-
202
- - `inquir apps list` - list applications.
203
- - `inquir apps create <name> [--port <n>] [--tcp …] [--set K=V]` - create an application.
204
- - `inquir apps deploy <app> [--image <ref>]` - start a release and wait until it is healthy. Without `--image` the current directory (or `--dir`) is built from its Dockerfile first; `--build <id>` releases an existing build.
205
- - `inquir apps build <app> [--dir <path>] [--dockerfile <f>] [--context <dir>] [--build-arg K=V]` - build an image from source without releasing it.
206
- - `inquir apps builds <app>` - build history (`--cancel <buildId>` drops a queued build).
207
- - `inquir apps status <app>` - endpoints (public and private), hostnames and recent releases. The `private:` lines are what another app in the workspace dials (`{slug}.apps.internal`, port per TCP service); they appear once the platform has verified the route.
208
- - `inquir apps logs <app|release|build> [--tail <n>]` - stream container (or build) logs.
209
- - `inquir apps promote <release>` - send production traffic to a release (needs a login, not an API key).
210
- - `inquir apps rollback <app>` - return production to the previous release.
211
- - `inquir apps stop <release>` - stop any release that is not serving production.
212
- - `inquir apps exec <app> -- <command>` - run a command inside the container (owner/admin login only — it can read every secret).
213
- - `inquir apps update <app> [--set K=V] [--port …] [--egress none|full] [--ingress private|public] …` - change settings; applies to the next release. `--ingress public` creates the generated public domain, `--ingress private` removes it (the private address is unaffected). New apps are private unless created with `--ingress public`.
214
- - `inquir apps domain <app> [hostname] [--verify|--remove]` - bind a custom hostname; publish the printed TXT record and point DNS at the platform, then `--verify`.
215
- - `inquir apps delete <app> --yes` - archive an application (stops every release, unbinds every hostname).
216
-
217
- ```bash
218
- # an HTTP service built from the Dockerfile in the current directory
219
- inquir apps create web --port 3000
220
- inquir apps deploy web
221
- inquir apps promote <releaseId>
222
-
223
- # ...or from a prebuilt image
224
- inquir apps deploy web --image nginx:alpine
225
-
226
- # a database: no HTTP port at all, published on a pinned port,
227
- # health-checked by asking the service itself
228
- inquir apps create db \
229
- --tcp postgres:5432:public:25432 \
230
- --health-command "pg_isready -h 127.0.0.1" \
231
- --set POSTGRES_PASSWORD=secret
232
- inquir apps deploy db --image postgres:16-alpine
233
- ```
234
-
235
- `--tcp name:port[:public][:hostPort]` — `public` publishes beyond loopback,
236
- and a pinned `hostPort` keeps a connection string valid across restarts (an
237
- unpinned port is reassigned every time the container is recreated). A public
238
- TCP port is reachable by anyone who can reach the host: the platform
239
- terminates no TLS and checks no credentials on raw TCP, so the service must
240
- authenticate its own clients.
241
-
242
- **Databases**
243
-
244
- - `inquir apps create <name> --template postgres|redis` - create a database: image, persistent volume, pinned public TCP port, generated password and its first release, in one command.
245
- - `inquir apps connection-url <db>` - print the live connection URL, credentials included (it lands in your shell history).
246
- - `inquir apps connect <db> <app>` - write that URL into another application's env as `DATABASE_URL` / `REDIS_URL` without it passing through your terminal; it applies on that application's next release.
247
- - `inquir apps backups <app> [list|create|restore <id>|delete <id>]` - volume snapshots. `restore` **overwrites the volume** with the snapshot and stops the application while it runs, so it asks for confirmation — pass `--yes` in a script.
248
-
249
- ```bash
250
- inquir apps create mydb --template postgres
251
- inquir apps connect mydb web # web gets DATABASE_URL on its next release
252
- inquir apps backups mydb create # snapshot every volume, wait for it to settle
253
- inquir apps backups mydb restore 3f9c1a2b --yes
254
- ```
255
-
256
- An application that declares a volume deploys by stopping its container before
257
- starting the new one, so two containers never write the same data — expect a
258
- short outage on every deploy. Backups are crash-consistent (the container is
259
- paused while it is copied) and need an artifact store configured on the
260
- deployment; without one the backup commands report that they are unavailable.
261
-
262
- **Staying up to date**
263
-
264
- The CLI keeps itself in step with the platform. On start it checks — at most
265
- every 12 hours, with a 2.5 s network timeout, never failing your command — the
266
- npm registry for the latest `@inquir/compute-cli` and the API for the minimum
267
- version it still supports (`GET /v1/cli/version`). When a newer version exists
268
- and the CLI is a global npm install running in an interactive terminal, it
269
- updates itself and re-runs your command; in CI, under `--json`, without a TTY,
270
- via `npx` or from a source checkout it only prints a one-line notice. If the
271
- API's *minimum* is not met, the command stops with the exact fix instead of
272
- failing later on a changed wire contract.
273
-
274
- - `inquir upgrade` - update now (`--check` only reports).
275
- - Opt out: `inquir config set autoUpdate false`, `INQUIR_NO_AUTO_UPDATE=1`, or `--no-update` on one command.
276
-
277
- **Diagnostics & config**
278
-
279
- - `inquir doctor` - diagnose environment, credentials, and API connectivity (`--json` for a report).
280
- - `inquir config [show|get <key>|set <key> <value>|path]` - view/edit CLI configuration.
281
- - `inquir help [command]` - show grouped help, or help for one command.
282
-
283
- ### `deploy` flags
284
-
285
- ```bash
286
- inquir deploy hello # package + async deploy, stream build logs
287
- inquir deploy hello --stage staging # target a deploy stage (alias: --environment)
288
- inquir deploy hello --set KEY=val --set OTHER=val # set environment variables (repeatable)
289
- inquir deploy hello --env-file .env.production # load env vars from a dotenv file
290
- inquir deploy hello --memory 512 --timeout 60000 # memory (MB) / timeout (ms)
291
- inquir deploy hello --layer <layerId> --layer <id2> # attach layers (repeatable)
292
- inquir deploy hello --no-logs # queue and wait for completion without streaming
293
- inquir deploy hello --ci # plain output, non-zero exit on failure (for CI)
294
- inquir deploy hello --dry-run # validate + package only; no create/deploy
295
- inquir deploy hello --json # machine-readable result
296
- ```
297
-
298
- > Note: `--env` selects a named **credential environment** from your config; `--stage`
299
- > (alias `--environment`) selects the **deploy stage** (production/staging/preview). They
300
- > are different — don't confuse them.
301
-
302
- ## Global Flags
303
-
304
- Global flags work in **any position** (before or after the command) and accept both
305
- `--flag value` and `--flag=value`:
306
-
307
- - `--json` - machine-readable output (implies no color).
308
- - `--debug` - verbose diagnostics + stack traces (also `INQUIR_DEBUG=1`).
309
- - `--quiet` - suppress status chatter (errors + requested results only).
310
- - `--no-color` - disable ANSI color (also honoured: `NO_COLOR`, `FORCE_COLOR`).
311
- - `--yes`, `-y` - assume "yes" for confirmations (required for destructive ops in CI).
312
- - `--cwd <path>` - run as if from this directory (alias: `--config`, which also accepts a config file path).
313
- - `--env <name>` - select a named credential environment from the config.
314
- - `--workspace <slug|id>` - target a specific workspace for this command (user-scoped login).
315
- - `--api-url <url>` - override the API base URL.
316
- - `--token <pat>` - use a Personal Access Token (non-interactive / CI).
317
-
318
- ```bash
319
- inquir run hello --cwd ./services/api
320
- inquir --workspace acme-prod deploy hello
321
- ```
322
-
323
- ## Exit codes
324
-
325
- | Code | Meaning |
326
- |------|---------|
327
- | `0` | success |
328
- | `1` | runtime error (build failed, not found, server error) |
329
- | `2` | usage / validation error (bad flags, missing args) |
330
- | `3` | network / timeout |
331
- | `4` | authentication required / forbidden |
332
- | `130` | interrupted (Ctrl+C / SIGINT) |
333
-
334
- A bare `Ctrl+C` aborts cleanly — the CLI prints `Aborted (SIGINT).` to stderr and
335
- exits `130`, leaving stdout untouched (safe for piping) and no stack trace.
336
-
337
- With `--json`, errors are emitted as a structured envelope on stdout:
338
-
339
- ```json
340
- { "ok": false, "error": { "code": "AUTH_REQUIRED", "title": "You are not logged in", "message": "…", "requestId": "…" } }
341
- ```
342
-
343
- ## CI usage
344
-
345
- In CI / non-TTY, the CLI never prompts; supply credentials via env and use `--ci`/`--yes`:
346
-
347
- ```bash
348
- export INQUIR_TOKEN="$INQUIR_PAT" # or INQUIR_API_KEY for a workspace key
349
- export INQUIR_WORKSPACE="acme-prod" # optional: target workspace
350
- inquir deploy hello --ci --json
351
- ```
352
-
353
- For GitHub Actions, prefer the [`@inquir/deploy-action`](../deploy-action) GitHub Action
354
- (supports keyless OIDC auth).
355
-
356
- ## Payload Input
357
-
358
- `run` and `invoke` support:
359
-
360
- - `--payload '{"k":"v"}'`
361
- - `--payload-file ./payload.json`
362
- - stdin piping
363
-
364
- Shell quoting differs by platform. To pass inline JSON:
365
-
366
- ```bash
367
- # macOS / Linux (bash, zsh) — single-quote the JSON:
368
- inquir invoke hello --payload '{"name":"World"}'
369
- ```
370
-
371
- ```powershell
372
- # Windows PowerShell — single-quote the JSON:
373
- inquir invoke hello --payload '{"name":"World"}'
374
- ```
375
-
376
- ```bat
377
- :: Windows cmd.exe — escape the inner double quotes:
378
- inquir invoke hello --payload "{\"name\":\"World\"}"
379
- ```
380
-
381
- When quoting gets awkward (especially on Windows), prefer `--payload-file ./payload.json`
382
- or pipe via stdin: `type payload.json | inquir invoke hello`.
383
-
384
- ## Remote Auth / Environment
385
-
386
- The CLI resolves each credential field independently, in this order (first match
387
- wins):
388
-
389
- 1. CLI flags (`--api-url`, `--token`, `--workspace`) / `--env <name>` selection
390
- 2. Environment variables (`LAMBDA_*` are legacy fallbacks):
391
- - `INQUIR_API_URL`, `INQUIR_API_KEY`
392
- - `INQUIR_TOKEN` — a Personal Access Token (takes precedence over `apiKey`)
393
- - `INQUIR_WORKSPACE` — active workspace (slug or id)
394
- - `INQUIR_ENV` — pick a named environment
395
- 3. Selected environment in the config file
396
- 4. Project link — `workspace` in the local `inquir.config.json` (set by `inquir use --local`); applies to the workspace only, below flags/env
159
+
160
+ ## Deploy a function (remote)
161
+
162
+ Once installed globally, deploying takes three steps:
163
+
164
+ ```bash
165
+ # 1. Authenticate. Easiest on a workstation:
166
+ inquir login
167
+ # For CI / scripts, export env vars for a one-off instead:
168
+ # export INQUIR_API_URL="https://api.inquir.org"
169
+ # export INQUIR_API_KEY="<api-key>" # workspace-scoped key, or
170
+ # export INQUIR_TOKEN="<personal-access-token>"
171
+
172
+ # 2. From your workspace (created by `inquir init`), deploy an asset by name.
173
+ inquir deploy hello # streams build/deploy logs, exits non-zero on failure
174
+
175
+ # 3. Invoke it remotely.
176
+ inquir invoke hello --payload '{"name":"World"}'
177
+ ```
178
+
179
+ Get an API key from your Inquir Compute workspace settings. For CI, prefer the
180
+ [`inquir-compute/deploy-action`](../deploy-action) GitHub Action (supports keyless
181
+ OIDC auth), or run `inquir deploy --ci`.
182
+
183
+ ## Commands
184
+
185
+ **Project & local dev**
186
+
187
+ - `inquir init [--name <name>] [--skip-install]` - scaffold `inquir.config.json`, folders, and a sample function. Interactive on a TTY (prompts for the project name); guides you to `login`/`run`/`deploy` afterward.
188
+ - `inquir codegen` - discover assets and generate `.inquir/generated/client.ts` + `registry.json`.
189
+ - `inquir list [--remote]` - list local assets, or deployed remote functions with `--remote`.
190
+ - `inquir run <asset>` - run a local asset.
191
+ - `inquir debug <asset>` - run locally with inspector enabled.
192
+ - `inquir sync status` - compare local hashes with remote hashes (`in-sync`, `drift`, `missing`).
193
+
194
+ **Auth & workspaces**
195
+
196
+ - `inquir login` - authenticate the CLI (browser pairing, `--browserless`, or `--token`).
197
+ - `inquir logout` - revoke the current browser-issued CLI session and clear its local credentials and workspace.
198
+ - `inquir whoami` - show the signed-in user, active workspace, and role.
199
+ - `inquir workspaces` - list the workspaces you belong to.
200
+ - `inquir use <slug|id> [--local]` - set the active workspace; `--local` links *this project* by writing `workspace` into `inquir.config.json`.
201
+
202
+ **Deploy & run remotely**
203
+
204
+ - `inquir deploy <asset>` - package, upload, and deploy a function (async; streams build logs).
205
+ - `inquir invoke <asset>` - invoke remote function by name / linked local name.
206
+ - `inquir logs <asset>` - show recent remote invocation history.
207
+ - `inquir deploys <function>` - list deploy history for a remote function.
208
+ - `inquir status <deployId>` - show a deploy's status (`--follow` to stream logs).
209
+ - `inquir rollback <function> [deployId]` - roll back to a previous successful deploy.
210
+ - `inquir delete <function>` - delete a remote function (asks for confirmation; `--yes` to skip).
211
+
212
+ **Container services (apps)**
213
+
214
+ Long-lived containers from any OCI image — the counterpart to functions. HTTP
215
+ ports are served over a hostname; TCP ports are published and dialled directly,
216
+ so a database, SMTP relay or SSH endpoint is a first-class service with no
217
+ runtime adapter involved.
218
+
219
+ - `inquir apps list` - list applications.
220
+ - `inquir apps create <name> [--port <n>] [--tcp …] [--set K=V]` - create an application.
221
+ - `inquir apps deploy <app> [--image <ref>]` - start a release and wait until it is healthy. Without `--image` the current directory (or `--dir`) is built from its Dockerfile first; `--build <id>` releases an existing build.
222
+ - `inquir apps build <app> [--dir <path>] [--dockerfile <f>] [--context <dir>] [--build-arg K=V]` - build an image from source without releasing it.
223
+ - `inquir apps builds <app>` - build history (`--cancel <buildId>` drops a queued build).
224
+ - `inquir apps status <app>` - endpoints (public and private), hostnames and recent releases. The `private:` lines are what another app in the workspace dials (`{slug}.apps.internal`, port per TCP service); they appear once the platform has verified the route.
225
+ - `inquir apps instances <app> [--json]` - the application's replicas, like pods: name (`<app>-<index>-<id8>`), state, ready, restarts, runner, region, CPU/RAM now.
226
+ - `inquir apps logs <app|release|build> [--tail <n>] [--replica <name|index>]` - stream container (or build) logs; `--replica` follows one replica.
227
+ - `inquir apps promote <release>` - send production traffic to a release (needs a login, not an API key).
228
+ - `inquir apps rollback <app>` - return production to the previous release.
229
+ - `inquir apps stop <release>` - stop any release that is not serving production.
230
+ - `inquir apps exec <app> [--replica <name|index>] -- <command>` - run a command inside the container (owner/admin login only — it can read every secret). `--replica` picks one serving replica; without it the server picks the production container.
231
+ - `inquir apps update <app> [--set K=V] [--port …] [--egress none|full] [--ingress private|public] …` - change settings; applies to the next release. `--ingress public` creates the generated public domain, `--ingress private` removes it (the private address is unaffected). New apps are private unless created with `--ingress public`.
232
+ - `inquir apps update <app> --node-selector inquir.io/region=eu [--node-selector tier=fast]` - run the next releases only on servers carrying every one of these node labels (`--clear-node-selector` removes it). Well-known labels: `inquir.io/region`, `inquir.io/zone`, `inquir.io/runtime`, `inquir.io/arch`, `inquir.io/gpu`, `inquir.io/gpu-count`; operator labels the platform publishes work too. Needs node placement enabled on the platform (`COMPUTE_NODE_AFFINITY=enforce`); a selector no server matches yet is accepted with a warning, and `inquir apps describe` says why a replica waits. Full Kubernetes-style `runtime.nodeAffinity` goes through the API or `inquir.yaml`.
233
+ - `inquir apps update <app> --location <id|auto>` (experimental) - run the next releases in one of the platform's locations (`nl`, `ru`, ...); `auto` runs wherever there is capacity. Shown by `inquir apps status` and `inquir apps describe`; offered only where the platform enables it (`COMPUTE_SERVICE_LOCATIONS=on`). A service whose volume data lives in another location is refused: the data does not move.
234
+ - `inquir apps domain <app> [hostname] [--verify|--remove]` - bind a custom hostname; publish the printed TXT record and point DNS at the platform, then `--verify`.
235
+ - `inquir apps delete <app> --yes` - archive an application (stops every release, unbinds every hostname).
236
+
237
+ Project archive in the dashboard also archives every application in the project, including applications shared with another project. It requires production permissions (`projects:write` and `apps:promote`). Clearing the local project selection with `inquir projects use --clear` only changes where future applications are created; it does not archive applications.
238
+
239
+
240
+ ```bash
241
+ # an HTTP service built from the Dockerfile in the current directory
242
+ inquir apps create web --port 3000
243
+ inquir apps deploy web
244
+ inquir apps promote <releaseId>
245
+
246
+ # ...or from a prebuilt image
247
+ inquir apps deploy web --image nginx:alpine
248
+
249
+ # a database: no HTTP port at all, published on a pinned port,
250
+ # health-checked by asking the service itself
251
+ inquir apps create db \
252
+ --tcp postgres:5432:public:25432 \
253
+ --health-command "pg_isready -h 127.0.0.1" \
254
+ --set POSTGRES_PASSWORD=secret
255
+ inquir apps deploy db --image postgres:16-alpine
256
+ ```
257
+
258
+ `--tcp name:port[:public][:hostPort]` — `public` publishes beyond loopback,
259
+ and a pinned `hostPort` keeps a connection string valid across restarts (an
260
+ unpinned port is reassigned every time the container is recreated). A public
261
+ TCP port is reachable by anyone who can reach the host: the platform
262
+ terminates no TLS and checks no credentials on raw TCP, so the service must
263
+ authenticate its own clients.
264
+
265
+ `--drain-grace <seconds>` (`create`, `deploy`, `update`; 0–3600) — the time the
266
+ old container gets after SIGTERM before it is killed (`runtimeSpec.drainGraceSeconds`).
267
+ Like `--memory` or `--cpu` it is saved on the application by `create`/`update`
268
+ and carried into every release built from the saved runtime.
269
+
270
+ **Databases**
271
+
272
+ - `inquir apps create <name> --template postgres|redis` - create a database: image, persistent volume, private TCP port, generated password and its first release, in one command. Add `--volume-runner <runner>` to keep its data and container on a worker; the worker runs the operator's digest-pinned mirror of the template image, and without one the create is refused (`APP_TEMPLATE_IMAGE_NOT_MIRRORED`).
273
+ - `inquir apps connection-url <db>` - print the live connection URL, credentials included (it lands in your shell history).
274
+ - `inquir apps connect <db> <app>` - write that URL into another application's env as `DATABASE_URL` / `REDIS_URL` without it passing through your terminal; it applies on that application's next release.
275
+ - `inquir apps backups <app> [list|create|restore <id>|delete <id>]` - volume snapshots. `restore` **overwrites the volume** with the snapshot and stops the application while it runs, so it asks for confirmation — pass `--yes` in a script.
276
+
277
+ ```bash
278
+ inquir apps create mydb --template postgres
279
+ inquir apps connect mydb web # web gets DATABASE_URL on its next release
280
+ inquir apps backups mydb create # snapshot every volume, wait for it to settle
281
+ inquir apps backups mydb restore 3f9c1a2b --yes
282
+ ```
283
+
284
+ An application that declares a volume deploys by stopping its container before
285
+ starting the new one, so two containers never write the same data — expect a
286
+ short outage on every deploy. Backups are crash-consistent (the container is
287
+ paused while it is copied) and need an artifact store configured on the
288
+ deployment; without one the backup commands report that they are unavailable.
289
+
290
+ **Staying up to date**
291
+
292
+ The CLI keeps itself in step with the platform. On start it checks — at most
293
+ every 12 hours, with a 2.5 s network timeout, never failing your command — the
294
+ npm registry for the latest `@inquir/compute-cli` and the API for the minimum
295
+ version it still supports (`GET /v1/cli/version`). When a newer version exists
296
+ and the CLI is a global npm install running in an interactive terminal, it
297
+ updates itself and re-runs your command; in CI, under `--json`, without a TTY,
298
+ via `npx` or from a source checkout it only prints a one-line notice. If the
299
+ API's *minimum* is not met, the command stops with the exact fix instead of
300
+ failing later on a changed wire contract.
301
+
302
+ - `inquir upgrade` - update now (`--check` only reports).
303
+ - Opt out: `inquir config set autoUpdate false`, `INQUIR_NO_AUTO_UPDATE=1`, or `--no-update` on one command.
304
+
305
+ **Diagnostics & config**
306
+
307
+ - `inquir doctor` - diagnose environment, credentials, and API connectivity (`--json` for a report).
308
+ - `inquir config [show|get <key>|set <key> <value>|path]` - view/edit CLI configuration.
309
+ - `inquir help [command]` - show grouped help, or help for one command.
310
+
311
+ **Platform operators**
312
+
313
+ - `inquir admin cluster [status|hold|release|move <memberId>|host register|grant <host> <capability>|revoke <host> <capability>]` -
314
+ the multi-master control plane (docs/roadmap/R4_MULTI_MASTER.md §6.2). It authenticates with the platform admin token in
315
+ `INQUIR_ADMIN_TOKEN`, never with your login; changes need the full token and land in the admin audit log.
316
+ - `inquir admin allocations relocate <allocationId> --reason <text> [--target <runnerId>]` - move one serving replica
317
+ make-before-break: its replacement starts (on the target, which must pass every placement filter and have room), takes
318
+ the traffic, and only then is the replica stopped. Pinned, volume, preview and TCP-pinned replicas are refused, as is an
319
+ application in a deployment handoff. `inquir admin allocations relocation <operationId>` shows where it is. Same token.
320
+
321
+ ### `deploy` flags
322
+
323
+ ```bash
324
+ inquir deploy hello # package + async deploy, stream build logs
325
+ inquir deploy hello --stage staging # target a deploy stage (alias: --environment)
326
+ inquir deploy hello --set KEY=val --set OTHER=val # set environment variables (repeatable)
327
+ inquir deploy hello --env-file .env.production # load env vars from a dotenv file
328
+ inquir deploy hello --memory 512 --timeout 60000 # memory (MB) / timeout (ms)
329
+ inquir deploy hello --layer <layerId> --layer <id2> # attach layers (repeatable)
330
+ inquir deploy hello --no-logs # queue and wait for completion without streaming
331
+ inquir deploy hello --ci # plain output, non-zero exit on failure (for CI)
332
+ inquir deploy hello --dry-run # validate + package only; no create/deploy
333
+ inquir deploy hello --json # machine-readable result
334
+ ```
335
+
336
+ > Note: `--env` selects a named **credential environment** from your config; `--stage`
337
+ > (alias `--environment`) selects the **deploy stage** (production/staging/preview). They
338
+ > are different — don't confuse them.
339
+
340
+ ## Global Flags
341
+
342
+ Global flags work in **any position** (before or after the command) and accept both
343
+ `--flag value` and `--flag=value`:
344
+
345
+ - `--json` - machine-readable output (implies no color).
346
+ - `--debug` - verbose diagnostics + stack traces (also `INQUIR_DEBUG=1`).
347
+ - `--quiet` - suppress status chatter (errors + requested results only).
348
+ - `--no-color` - disable ANSI color (also honoured: `NO_COLOR`, `FORCE_COLOR`).
349
+ - `--yes`, `-y` - assume "yes" for confirmations (required for destructive ops in CI).
350
+ - `--cwd <path>` - run as if from this directory (alias: `--config`, which also accepts a config file path).
351
+ - `--env <name>` - select a named credential environment from the config.
352
+ - `--workspace <slug|id>` - target a specific workspace for this command (user-scoped login).
353
+ - `--api-url <url>` - override the API base URL.
354
+ - `--token <pat>` - use a Personal Access Token (non-interactive / CI).
355
+
356
+ ```bash
357
+ inquir run hello --cwd ./services/api
358
+ inquir --workspace acme-prod deploy hello
359
+ ```
360
+
361
+ ## Exit codes
362
+
363
+ | Code | Meaning |
364
+ |------|---------|
365
+ | `0` | success |
366
+ | `1` | runtime error (build failed, not found, server error) |
367
+ | `2` | usage / validation error (bad flags, missing args) |
368
+ | `3` | network / timeout |
369
+ | `4` | authentication required / forbidden |
370
+ | `130` | interrupted (Ctrl+C / SIGINT) |
371
+
372
+ A bare `Ctrl+C` aborts cleanly — the CLI prints `Aborted (SIGINT).` to stderr and
373
+ exits `130`, leaving stdout untouched (safe for piping) and no stack trace.
374
+
375
+ With `--json`, errors are emitted as a structured envelope on stdout:
376
+
377
+ ```json
378
+ { "ok": false, "error": { "code": "AUTH_REQUIRED", "title": "You are not logged in", "message": "…", "requestId": "…" } }
379
+ ```
380
+
381
+ ## CI usage
382
+
383
+ In CI / non-TTY, the CLI never prompts; supply credentials via env and use `--ci`/`--yes`:
384
+
385
+ ```bash
386
+ export INQUIR_TOKEN="$INQUIR_PAT" # or INQUIR_API_KEY for a workspace key
387
+ export INQUIR_WORKSPACE="acme-prod" # optional: target workspace
388
+ inquir deploy hello --ci --json
389
+ ```
390
+
391
+ For GitHub Actions, prefer the [`@inquir/deploy-action`](../deploy-action) GitHub Action
392
+ (supports keyless OIDC auth).
393
+
394
+ ## Payload Input
395
+
396
+ `run` and `invoke` support:
397
+
398
+ - `--payload '{"k":"v"}'`
399
+ - `--payload-file ./payload.json`
400
+ - stdin piping
401
+
402
+ Shell quoting differs by platform. To pass inline JSON:
403
+
404
+ ```bash
405
+ # macOS / Linux (bash, zsh) — single-quote the JSON:
406
+ inquir invoke hello --payload '{"name":"World"}'
407
+ ```
408
+
409
+ ```powershell
410
+ # Windows PowerShell — single-quote the JSON:
411
+ inquir invoke hello --payload '{"name":"World"}'
412
+ ```
413
+
414
+ ```bat
415
+ :: Windows cmd.exe — escape the inner double quotes:
416
+ inquir invoke hello --payload "{\"name\":\"World\"}"
417
+ ```
418
+
419
+ When quoting gets awkward (especially on Windows), prefer `--payload-file ./payload.json`
420
+ or pipe via stdin: `type payload.json | inquir invoke hello`.
421
+
422
+ ## Remote Auth / Environment
423
+
424
+ The CLI resolves each credential field independently, in this order (first match
425
+ wins):
426
+
427
+ 1. CLI flags (`--api-url`, `--token`, `--workspace`) / `--env <name>` selection
428
+ 2. Environment variables (`LAMBDA_*` are legacy fallbacks):
429
+ - `INQUIR_API_URL`, `INQUIR_API_KEY`
430
+ - `INQUIR_TOKEN` — a Personal Access Token (takes precedence over `apiKey`)
431
+ - `INQUIR_WORKSPACE` — active workspace (slug or id)
432
+ - `INQUIR_ENV` — pick a named environment
433
+ 3. Selected environment in the config file
434
+ 4. Project link — `workspace` in the local `inquir.config.json` (set by `inquir use --local`); applies to the workspace only, below flags/env
397
435
  5. Top-level config file values (credentials and workspace only when the named environment uses the same API)
398
436
  6. Default `apiUrl` of `https://api.inquir.org` (override with env/config for local dev)
399
437
 
@@ -411,63 +449,84 @@ continue to inherit defaults. Changing a profile's API also removes its stored A
411
449
  key, so logging out of the new PAT cannot reactivate a key from the previous API.
412
450
 
413
451
  When both a `token` (PAT) and an `apiKey` are present, the PAT wins. The active
414
- `workspaceId` is only applied to user-scoped credentials (PAT/session); for a
415
- workspace-scoped API key it is ignored unless you pass `--workspace` explicitly.
416
-
417
- Config file locations:
418
-
419
- - `~/.inquir/config.json` (preferred, written by `inquir login` / `use`; saved with `0600` permissions)
420
- - `~/.lambda-cli/config.json` (legacy fallback — **credentials only**; the legacy `apiUrl` is intentionally ignored so you aren't silently pinned to `localhost`)
421
-
422
- Example (written/managed by `inquir login`, `inquir use`, `inquir logout`):
423
-
424
- ```json
425
- {
426
- "apiUrl": "https://api.inquir.org",
427
- "token": "inq_pat_…",
428
- "workspaceId": "acme-prod",
429
- "user": { "id": "…", "email": "you@example.com", "name": "You" },
430
- "environments": {
431
- "staging": {
432
- "apiUrl": "https://staging.example.com",
433
- "apiKey": "staging-key"
434
- }
435
- }
436
- }
437
- ```
438
-
439
- ## Troubleshooting
440
-
441
- Start with `inquir doctor` — it checks the CLI/Node version, config file, credential,
442
- API connectivity + latency, active workspace, and local project, and prints a fix for any
443
- failing check.
444
-
445
- | Symptom | Likely cause / fix |
446
- |---------|--------------------|
447
- | `You are not logged in` (exit 4) | No credential resolved. Run `inquir login`, or set `INQUIR_TOKEN`/`INQUIR_API_KEY` in CI. |
448
- | `Permission denied` (exit 4) | Wrong workspace or insufficient role. Check `inquir whoami`; switch with `inquir use`. |
449
- | `Not found` for a function | Wrong name or workspace. `inquir list --remote` to see what exists in the active workspace. |
450
- | Commands hit `localhost` unexpectedly | A stale `apiUrl` in config/env. Check `inquir config show`; override with `--api-url` or `INQUIR_API_URL`. |
451
- | Network error (exit 3) | Can't reach the API. Verify connectivity and `--api-url`; re-run `inquir doctor`. |
452
- | Garbled output in logs/CI | Disable color with `--no-color` or `NO_COLOR=1` (color auto-disables when not a TTY and in `--json`). |
453
- | Need raw detail for a failure | Re-run with `--debug` for stack traces and the response body (secrets are redacted). |
454
-
455
- ## Publishing to npm (maintainers)
456
-
457
- The CLI (`@inquir/compute-cli`) depends on the SDK (`@inquir/compute`), so the
452
+ `workspaceId` is only applied to user-scoped credentials (PAT/session); for a
453
+ workspace-scoped API key it is ignored unless you pass `--workspace` explicitly.
454
+
455
+ Config file locations:
456
+
457
+ - `~/.inquir/config.json` (preferred, written by `inquir login` / `use`; saved with `0600` permissions)
458
+ - `~/.lambda-cli/config.json` (legacy fallback — **credentials only**; the legacy `apiUrl` is intentionally ignored so you aren't silently pinned to `localhost`)
459
+
460
+ Credential updates use an atomic file replacement and an exclusive
461
+ `~/.inquir/config.json.lock` while updating or revoking a session. A timed-out lock
462
+ is never stolen from a running command. If a command crashed and subsequent commands
463
+ report `AUTH_CONFIG_LOCKED`, stop all CLI commands before removing that lock file.
464
+ Older CLI versions do not participate in this locking protocol; avoid running old
465
+ and new versions concurrently against the same configuration.
466
+
467
+ Example (written/managed by `inquir login`, `inquir use`, `inquir logout`):
468
+
469
+ ```json
470
+ {
471
+ "apiUrl": "https://api.inquir.org",
472
+ "token": "inq_pat_…",
473
+ "workspaceId": "acme-prod",
474
+ "user": { "id": "…", "email": "you@example.com", "name": "You" },
475
+ "environments": {
476
+ "staging": {
477
+ "apiUrl": "https://staging.example.com",
478
+ "apiKey": "staging-key"
479
+ }
480
+ }
481
+ }
482
+ ```
483
+
484
+ ## Troubleshooting
485
+
486
+ Start with `inquir doctor` — it checks the CLI/Node version, config file, credential,
487
+ API connectivity + latency, active workspace, and local project, and prints a fix for any
488
+ failing check.
489
+
490
+ | Symptom | Likely cause / fix |
491
+ |---------|--------------------|
492
+ | `You are not logged in` (exit 4) | No credential resolved. Run `inquir login`, or set `INQUIR_TOKEN`/`INQUIR_API_KEY` in CI. |
493
+ | `Permission denied` (exit 4) | Wrong workspace or insufficient role. Check `inquir whoami`; switch with `inquir use`. |
494
+ | `Not found` for a function | Wrong name or workspace. `inquir list --remote` to see what exists in the active workspace. |
495
+ | Commands hit `localhost` unexpectedly | A stale `apiUrl` in config/env. Check `inquir config show`; override with `--api-url` or `INQUIR_API_URL`. |
496
+ | Network error (exit 3) | Can't reach the API. Verify connectivity and `--api-url`; re-run `inquir doctor`. |
497
+ | Garbled output in logs/CI | Disable color with `--no-color` or `NO_COLOR=1` (color auto-disables when not a TTY and in `--json`). |
498
+ | Need raw detail for a failure | Re-run with `--debug` for stack traces and the response body (secrets are redacted). |
499
+
500
+ ## Publishing to npm (maintainers)
501
+
502
+ The CLI (`@inquir/compute-cli`) depends on the SDK (`@inquir/compute`), so the
458
503
  SDK must be published **first** at a version satisfying the CLI's dependency
459
- range (`dependencies["@inquir/compute"]`, `^0.3.0` for CLI 0.3.0). Set the lower
504
+ range (`dependencies["@inquir/compute"]`, `^0.4.0` for CLI 0.4.0). Set the lower
460
505
  bound to the first SDK release containing every API the CLI imports. A workspace
461
506
  build uses the local SDK and cannot prove that an older published SDK works.
462
507
 
508
+ Release order for 0.4.0: CLI 0.4.0 imports `isPromoteAccepted` and
509
+ `getApplicationRollout` (the background promote, `inquir apps promote`), which
510
+ SDK 0.3.0 does not export. Publish SDK 0.4.0 first and confirm it on the
511
+ registry; a CLI published against SDK 0.3.0 would fail at startup.
512
+
513
+ Next release (CLI 0.4.1): the CLI imports `listAppInstances` and
514
+ `matchAppInstance` (`inquir apps instances`, `--replica`), which SDK 0.4.0 does
515
+ not export, and `createSourceArchive`, `manifestBuildContext` (source
516
+ uploads that honour the build context's .dockerignore/.inquirignore and keep
517
+ secret-like files out) and `getProductionReplacement` (the replacement phase
518
+ while a redeploy waits), which SDK 0.4.1 does not export; its dependency
519
+ floor is `^0.4.2`. Publish SDK 0.4.2 first and
520
+ confirm it on the registry, then the CLI.
521
+
463
522
  New `inquir init` scaffolds inherit this SDK range and require Node.js 22+.
464
523
  Existing `package.json` files are preserved; update their dependencies explicitly
465
524
  when adopting a newer SDK.
466
-
467
- Prerequisites:
468
-
469
- - An npm account with publish access to the `@inquir` scope (create the org/scope on npmjs.com), then `npm login`.
470
- - Both packages declare `"publishConfig": { "access": "public" }`, so scoped packages publish publicly.
525
+
526
+ Prerequisites:
527
+
528
+ - An npm account with publish access to the `@inquir` scope (create the org/scope on npmjs.com), then `npm login`.
529
+ - Both packages declare `"publishConfig": { "access": "public" }`, so scoped packages publish publicly.
471
530
  - Both packages build before packing or publishing from source. The SDK includes
472
531
  `dist/`; the CLI includes `dist/` and its bundled `skill/`. npm also includes
473
532
  package metadata and README files.
@@ -503,8 +562,71 @@ After building, preview package contents without publishing with
503
562
  `--ignore-scripts` skips build hooks, so only use it after the explicit build.
504
563
  The installed command is `inquir`, from `dist/index.js` with its Node shebang.
505
564
  After publishing, users can install it with:
506
-
507
- ```bash
508
- npm install -g @inquir/compute-cli@latest
509
- inquir --help
510
- ```
565
+
566
+ ```bash
567
+ npm install -g @inquir/compute-cli@latest
568
+ inquir --help
569
+ ```
570
+ ## Application observability
571
+
572
+ Read actual resource history for every release and replica, or HTTP gateway measurements:
573
+
574
+ ```sh
575
+ inquir apps metrics api --since 6h
576
+ inquir apps metrics api --since 30d --json
577
+ inquir apps metrics api --http --since 1d --json
578
+ ```
579
+
580
+ The resource table shows the latest point per replica in the selected window. JSON contains all returned points, their enforced CPU/RAM limits, network transfer rates, disk I/O rates and deployment markers. `null` means the measurement is unavailable; it is not zero. Disk I/O measures reads/writes, not occupied volume space. HTTP measurements cover gateway requests, including request counts, 5xx errors, response bytes and latency percentiles. Resource and HTTP history is retained for 30 days; resource points older than a day are rolled up to one per five minutes, and older than a week to one per hour, each keeping the bucket's last point plus its CPU and memory peak and mean. Inspect `status`, `latestSampleAt` and `truncated` in resource JSON before interpreting a range as current or complete.
581
+
582
+ Ask what the CPU and memory figures could be, from what the production replicas actually used:
583
+
584
+ ```sh
585
+ inquir apps resources recommend api
586
+ inquir apps resources recommend api --days 3 --json
587
+ ```
588
+
589
+ The recommendation is read-only. Memory is 1.2 × the peak working set in the window (default 7 days), at least 64 MB, at least 256 MB for a database, and never below the peak of the whole 30-day history plus 10%. The CPU limit follows the peak (1.5 ×, at least 0.1 vCPU); the reserved request shown is what the platform would reserve for that limit, next to the request the 95th percentile of five-minute averages alone would justify. A recommendation needs 24 hours of observed usage; `confidence` reports the days observed and the samples behind it, and `--json` adds each release (replica set) seen in the window. Apply one yourself with `inquir apps update api --memory <mb> --cpu <vcpus>` and `inquir apps redeploy api`.
590
+
591
+ Persisted container logs remain readable after the container is replaced. Select an app and optionally an exact release or runtime identity:
592
+
593
+ ```sh
594
+ inquir apps log-history api --since 1h --level error --json
595
+ inquir apps logs api --history --release <release-id> --replica <allocation-id> --allocation-fence 4
596
+ inquir apps log-history api --since 1h --replica api-1-b1b1b1b1 # a name or index from apps instances
597
+ inquir apps log-history api --runner <runner-id> --runner-epoch 0 --container <full-container-id>
598
+ inquir apps log-history api --http --since 7d --status 503 --search /api --json
599
+ ```
600
+
601
+ History returns one page, newest first. Runtime retention is 7 days; HTTP retention is 30 days. Use `--limit` (up to 200 runtime rows or 500 HTTP rows) and `--cursor` for older pages. Always reuse the response's `from` and `to` as `--from`/`--to`, plus the same filters, when using a cursor. `apps logs api` without `--history` still follows the current release; `apps logs <build-id>` still reads build output.
602
+
603
+ Configure alert rules using JSON files or stdin. Destinations are write-only and are omitted from command output:
604
+
605
+ ```sh
606
+ inquir apps alerts api list --json
607
+ inquir apps alerts api create --file cpu-alert.json
608
+ inquir apps alerts api update <rule-id> --file patch.json
609
+ inquir apps alerts api incidents --limit 25 --json
610
+ inquir apps alerts api delete <rule-id>
611
+ ```
612
+
613
+ Example `cpu-alert.json` (incident-only until a notification destination is configured):
614
+
615
+ ```json
616
+ {
617
+ "name": "High CPU",
618
+ "enabled": true,
619
+ "metric": "cpu_percent",
620
+ "threshold": 85,
621
+ "forSeconds": 120,
622
+ "recoveryThreshold": 65,
623
+ "recoveryForSeconds": 60,
624
+ "noDataSeconds": 180,
625
+ "noData": "alert",
626
+ "channels": []
627
+ }
628
+ ```
629
+
630
+ Use `memory_percent` for RAM or `deployment_failed` for failed production deployments. CPU/RAM rules evaluate the continuous maximum across current production replicas; the hot replica can change during the hold period. Percentage thresholds refer to each container's enforced limit. For deployment events, timing and threshold fields do not control the failure trigger. Notification channels have the shape `{"type":"webhook","url":"https://your-endpoint.example/alerts"}` or `{"type":"slack","url":"https://hooks.slack.com/..."}`. Keep secret URLs in a file outside version control, or pipe JSON to `--file -`. The server must have secret encryption configured to accept notification channels.
631
+
632
+ A patch such as `{"threshold":90}` keeps existing destinations. `{"channels":[]}` removes them. Deleting a rule disables it and resolves active incidents while preserving retained history. Incident results include notification delivery state and retry counts. All commands honor the existing `--workspace`, `--env`, `--api-url` and credential selection rules.