@m8t-stack/cli 0.0.1-bootstrap

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Or Keren (m8t)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,213 @@
1
+ # `@m8t-stack/cli`
2
+
3
+ The `m8t` CLI for managing m8t-stack deployments.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ # npm (any OS with Node 20+)
9
+ npm install -g @m8t-stack/cli
10
+
11
+ # Homebrew (macOS / Linux)
12
+ brew install m8t-run/tap/m8t
13
+
14
+ # Scoop (Windows)
15
+ scoop bucket add m8t https://github.com/m8t-run/scoop-bucket
16
+ scoop install m8t
17
+
18
+ # Verify
19
+ m8t version
20
+ ```
21
+
22
+ The CLI bundles the shared workspace types into a single `dist/cli.js`, so the
23
+ npm install is self-contained (only the external runtime deps resolve from npm).
24
+ Publishing is automated by `.github/workflows/release-cli.yml` (OIDC trusted
25
+ publishing); see `publish/npm-trusted-publishing-setup.md`.
26
+
27
+ ### Build from source (contributors)
28
+
29
+ ```bash
30
+ pnpm --filter "@m8t-stack/cli" build # produces dist/cli.js with shebang
31
+ cd apps/cli && pnpm pack # produces m8t-stack-cli-<version>.tgz
32
+ npm install -g ./m8t-stack-cli-*.tgz
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ```bash
38
+ m8t version # CLI version
39
+ m8t whoami # Identity + which gateway you're talking to (probes the backend)
40
+ m8t status # Full local snapshot: az identity, config.yaml, gateway cache, azd mode
41
+ m8t doctor # Health checks (az · config · tenant align · gateway · Foundry data-plane · model-quota) + fixes
42
+ m8t doctor --agent <name> # + delivery-grant check: verifies the agent's MI holds Key Vault Secrets User
43
+ m8t open [webapp|foundry|portal] # Open the deployed app / Foundry portal / resource group in a browser
44
+
45
+ # Local config (~/.m8t-stack)
46
+ m8t config show # config.yaml (tenant/client/project) + the cached gateway
47
+ m8t config set <key> <value> # set tenantId | clientId | projectEndpoint
48
+ m8t config reset # clear the gateway discovery cache
49
+ m8t switch --subscription <id|name> # re-point local config at another deployment (snapshots first)
50
+ m8t switch <profile> # restore a saved profile; m8t switch --list
51
+
52
+ # Team management
53
+ m8t team add <handle> --display "<name>" [--telegram <id>] [--slack <id>] [--teams <upn>]
54
+ m8t team list
55
+ m8t team show <handle>
56
+ m8t team add-identity <handle> [--telegram <id>] [--slack <id>] [--teams <upn>]
57
+ m8t team remove-identity <handle> --telegram|--slack|--teams
58
+ m8t team remove <handle>
59
+
60
+ # Deploy / update the gateway stack (replaces the old deploy/setup.mjs)
61
+ m8t deploy [--client-id <appId>] [--image-ref <ref>] [--location <region>] [--resource-group <name>]
62
+
63
+ # Brain management
64
+ m8t brain link <name> --repo <owner>/<repo> [--persona <path>] [--allow-non-reasoning]
65
+ # --persona: override the recorded persona file (or use when no local agent yaml exists)
66
+ # --allow-non-reasoning: suppress the reasoning-model warning
67
+ ```
68
+
69
+ ### `--subscription <id>` flag
70
+
71
+ Available on all gateway-using commands (`whoami`, `config show`, `config reset`,
72
+ `team add`, `team list`, `team show`, `team add-identity`, `team remove-identity`,
73
+ `team remove`, `bind add`, `bind list`, `bind show`, `bind remove`, `bind cleanup`).
74
+ Pins gateway discovery to the named subscription, bypassing the active `az`
75
+ subscription. Useful when you manage multiple m8t-stack deployments across
76
+ subscriptions or when your shell's active subscription differs from the deployment
77
+ target.
78
+
79
+ ```bash
80
+ m8t team list --subscription <subscription-id-or-name>
81
+ ```
82
+
83
+ ## Local context & config — `status` / `doctor` / `switch`
84
+
85
+ The CLI reads two local files under `~/.m8t-stack/`: **`config.yaml`** (your `tenantId`, `clientId`, and Foundry `projectEndpoint` — used by the web app + architect) and **`cli-config.yaml`** (the auto-discovered gateway URL cache).
86
+
87
+ - **`m8t status`** — a read-only snapshot of everything local: your signed-in `az` identity + active subscription/tenant, `config.yaml` (tenant / client / project), the gateway cache, the `azd` auth mode, and whether your `az` tenant matches `config.yaml` (tenant alignment). `--output json` for scripting.
88
+ - **`m8t doctor`** — runs health checks and prints a fix for each failure; exits non-zero if any check FAILs. Checks: `az` signed in · `config.yaml` valid · tenant alignment · gateway reachable (`/api/me`) · **Foundry data-plane reachable** (a 401/403 prints the exact `az role assignment create … "Cognitive Services User"` command) · **model-quota check** (warns for any deployed model with 0 TPM quota in the region). Results stream as each check runs. Pass `--agent <name>` to add a targeted delivery-grant check: reads the agent's deployed env and verifies its managed identity holds `Key Vault Secrets User` on the configured vault.
89
+ - **`m8t config set <key> <value>`** — write `tenantId`, `clientId`, or `projectEndpoint` into `config.yaml` (validated). `m8t config show` now displays `config.yaml` alongside the gateway cache.
90
+ - **`m8t switch`** — re-point your local config at another deployment in one step. `--subscription <id|name>` discovers the gateway there and derives every `config.yaml` value from its container env (zero manual IDs); `<profile>` restores a saved profile; `--list` lists profiles. Every switch **snapshots the outgoing config to a profile first** (label it with `--as <name>`), so it's reversible — e.g. `m8t switch --subscription <new> --as work`, then later `m8t switch personal`.
91
+
92
+ ## Open in the browser — `m8t open`
93
+
94
+ ```bash
95
+ m8t open # the deployed webapp (gateway URL) — default
96
+ m8t open foundry # the Microsoft Foundry portal (ai.azure.com)
97
+ m8t open portal # the resource group in the Azure portal
98
+ m8t open --print # print the URL instead of launching a browser (pipe-friendly)
99
+ ```
100
+
101
+ ## Deploy / update the gateway — `m8t deploy`
102
+
103
+ Provisions (or updates) the gateway/webapp stack via Bicep — the successor to the old `node deploy/setup.mjs`. See [`deploy/README.md`](../../deploy/README.md) for the full flow.
104
+
105
+ ```bash
106
+ # Bring-your-own app registration (required if you can't create Entra app regs, e.g. a directory guest):
107
+ m8t deploy --client-id <appId> --image-ref <acr-or-ghcr-ref> --location <region>
108
+ ```
109
+
110
+ Key flags: `--client-id <appId>` (reuse an existing app reg + skip **all** Microsoft Graph writes), `--image-ref <ref>` (full image ref; default `ghcr.io/m8t-run/m8t:latest` — pass an `*.azurecr.io/...` ref for ACR images), `--resource-group` (default `rg-m8t-stack`), `--location`, `--suffix`, `--foundry-endpoint`, `--foundry-resource-id`.
111
+
112
+ > ⚠️ `m8t deploy` is **declarative** — it makes the live stack match the Bicep template. If a deployment was hand-modified after provisioning (e.g. switched to a private-ACR image with a UserAssigned pull identity), re-running the bicep can revert those changes. **Preview with `az deployment group create --what-if` before applying against a live stack.**
113
+
114
+ ## Binding management — `m8t bind`
115
+
116
+ Wire channel bots (Telegram, Slack, Teams) to Foundry workers. F4 ships
117
+ the management API + CLI scaffolding; the actual adapters (which deliver
118
+ inbound messages from each channel) ship in later features.
119
+
120
+ ```bash
121
+ # Create a binding (requires the channel adapter — Telegram ships in F6)
122
+ m8t bind add telegram \
123
+ --worker cmo \
124
+ --bot-token <from-botfather> \
125
+ --slug cmo-tg \
126
+ --bot-username "@startup_cmo_bot"
127
+
128
+ # List all bindings, optionally filtered
129
+ m8t bind list
130
+ m8t bind list --channel telegram
131
+ m8t bind list --status orphaned
132
+
133
+ # Inspect one binding (token NEVER returned — only the KV URI)
134
+ m8t bind show cmo-tg
135
+
136
+ # Remove a binding (cascade: unregister webhook → KV → conversations → row)
137
+ m8t bind remove cmo-tg
138
+ m8t bind remove cmo-tg --yes # skip confirm
139
+
140
+ # Orphan-only cleanup (refuses to act on active bindings)
141
+ m8t bind cleanup <bindingId>
142
+ m8t bind cleanup --all-orphaned
143
+ ```
144
+
145
+ > `--worker` is the **case-sensitive, lowercase** Foundry agent name as deployed (e.g. `cmo`). A wrong name isn't rejected at bind time — it surfaces later as an orphaned binding on the first message.
146
+
147
+ ### Pre-F6 behavior
148
+
149
+ `m8t bind add telegram ...` currently fails with:
150
+
151
+ ```
152
+ error: no adapter for channel 'telegram'. This is expected for F4 alone;
153
+ the channel-specific adapter ships in a later feature.
154
+ ```
155
+
156
+ This is correct. F6 (Telegram adapter) will register the adapter at
157
+ startup and unlock the create flow.
158
+
159
+ ### Cascade-delete idempotency
160
+
161
+ If `m8t bind remove` fails mid-cascade, it prints which steps completed
162
+ and which step failed, and recommends re-running the command. Each step
163
+ is independently idempotent — a re-run resumes safely from the failure
164
+ point.
165
+
166
+ ## Output modes
167
+
168
+ Pretty table or key-value block by default; pipe or redirect, and the CLI auto-switches to JSON:
169
+
170
+ ```bash
171
+ m8t team list # pretty
172
+ m8t team list | jq # auto-JSON
173
+ m8t team list --output json # explicit JSON
174
+ m8t team list --output pretty # force pretty even on pipe
175
+ ```
176
+
177
+ ## Exit codes
178
+
179
+ - `0` success
180
+ - `1` any failure (auth, network, validation, backend)
181
+ - `2` user-cancelled
182
+
183
+ Granular error info in stderr's structured JSON envelope.
184
+
185
+ ## Prerequisites
186
+
187
+ - Node 20+
188
+ - `az login` against the customer's Azure tenant. CLI uses `DefaultAzureCredential` — no per-admin pre-registration.
189
+
190
+ ## Troubleshooting
191
+
192
+ ### `error: You are not signed in to Azure.`
193
+ Run `az login` first. The CLI uses your active `az` session to acquire a token for the gateway.
194
+
195
+ ### `error: No m8t-stack deployment found in subscription <name>.`
196
+ The deployment is in a different subscription. Switch with:
197
+ ```bash
198
+ az account set --subscription <other-sub>
199
+ m8t config reset
200
+ m8t team list
201
+ ```
202
+
203
+ ### `error: Multiple m8t-stack deployments found ...`
204
+ You have more than one gateway in this subscription. The CLI prompts you to pick one when running interactively (e.g. `m8t whoami`). The choice is cached at `~/.m8t-stack/cli-config.yaml`. Or pass `--subscription <id>` to target a specific subscription and skip the picker entirely.
205
+
206
+ ### `(gateway is starting up...)`
207
+ The deployed gateway is configured with `min-replicas=0` (scale-to-zero). First request after idle pays ~10–20s cold start. The CLI retries once on 502/503/504.
208
+
209
+ ### `error: partial write — <channel-A> succeeded, <channel-B> failed.`
210
+ A multi-identity `m8t team add` partially succeeded. Run `m8t team show <handle>` to verify the current state, then `m8t team add-identity <handle> --<channel-B> <id>` to fill in the missing identity.
211
+
212
+ ### CLI version vs gateway version drift
213
+ The CLI and the gateway share `@m8t-stack/api-contract` types at compile time (the CLI bundles them at build). If the gateway is on an older version and returns a response in an unknown shape, the CLI surfaces `BAD_RESPONSE` with a "this may be a gateway version mismatch" hint.