@azx-pbc/helix-cli 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +180 -7
  3. package/dist/helix.js +1185 -0
  4. package/package.json +32 -6
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AZX, PBC
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 CHANGED
@@ -1,14 +1,187 @@
1
- # `@azx-pbc/helix-cli` — 0.0.0 placeholder
1
+ # `helix` — Helix deploy CLI
2
2
 
3
- This version is an empty placeholder. It exists only because npm requires a
4
- package to exist before a [trusted publisher](https://docs.npmjs.com/trusted-publishers/)
5
- (OIDC) can be attached to it, and we wanted every real release to carry a
6
- provenance attestation rather than starting with a hand-published one.
3
+ `helix` is a **per-app CLI**, like `git` or `vercel`: you run it **from inside an
4
+ app's directory**. It reads that app's `helix.json`, zips the build output, uploads
5
+ it to the portal as a new version, and manages the live pointer.
7
6
 
8
- **Install `0.1.0` or later** — that is the actual CLI, published from CI:
7
+ ## The mental model
9
8
 
10
9
  ```
10
+ my-app/
11
+ helix.json ← helix reads this from the current working directory
12
+ dist/ ← the folder helix zips and uploads (configurable)
13
+ ```
14
+
15
+ Everything keys off the **current working directory**. `cd` into your app, then
16
+ run `helix <command>`. There is no "select an app" flag you normally need — the app
17
+ is wherever you're standing.
18
+
19
+ ## Configuration
20
+
21
+ Each setting is resolved **flags → environment → `helix.json` → built-in default**
22
+ (first match wins):
23
+
24
+ | Setting | Flag | Env | `helix.json` key | Default |
25
+ | ---------- | -------------- | ------------------ | ---------------- | -------------------------- |
26
+ | App slug | `--slug` | — | `slug` | _(required)_ |
27
+ | Portal URL | `--portal-url` | `HELIX_PORTAL_URL` | `portalUrl` | `http://localhost:3001` |
28
+ | Build dir | `--dir` | — | `dir` | `dist` |
29
+ | Auth token | `--token` | `HELIX_TOKEN` | — | _(`helix login` if unset)_ |
30
+
31
+ A minimal `helix.json` is just:
32
+
33
+ ```json
34
+ { "slug": "my-app" }
35
+ ```
36
+
37
+ `--dir` is resolved **relative to the current working directory**, and so is
38
+ `helix.json` — another reason to run `helix` from the app directory.
39
+
40
+ ## Commands
41
+
42
+ ```
43
+ helix login # browser sign-in (OIDC device flow)
44
+ helix logout # forget the cached tokens
45
+ helix whoami # who the portal thinks you are
46
+ helix create [--display-name <name>] [--visibility <v>] # register the app
47
+ helix deploy [--dir <dir>] [--bundle <zip>] [--promote] # upload a version
48
+ helix versions # list versions
49
+ helix promote <number> # make a version live
50
+ helix rollback [number] # revert the live pointer
51
+ ```
52
+
53
+ `deploy` uploads the bundle as a **preview**; `--promote` flips it live in the
54
+ same step (architecture §5.1). `visibility` is `private | group:<id> | password
55
+ | public`.
56
+
57
+ ## Authentication (M3)
58
+
59
+ Two paths, in precedence order:
60
+
61
+ 1. **Static token** — `HELIX_TOKEN` / `--token`. Sends the value as a bearer
62
+ token verbatim. This is the CI/scripts path, and also how the portal's
63
+ dev-token stub keeps working (`HELIX_TOKEN=$PORTAL_DEV_TOKEN`). It is never
64
+ accepted by a production portal.
65
+ 2. **`helix login`** — the OIDC device flow. The CLI asks the portal
66
+ (`GET /api/v1/auth/config`) which issuer to use (the local dev IdP on
67
+ `:3002` in dev; Entra later), prints a verification URL + code, and polls
68
+ while you approve in a browser. Tokens land in
69
+ `~/.config/helix/tokens.json` (mode 0600, keyed by issuer) and are silently
70
+ renewed with the refresh token. On 401, nothing is auto-launched — agents
71
+ run headless; the error says to run `helix login`.
72
+
73
+ ## Running it
74
+
75
+ ### Installed from npm
76
+
77
+ ```bash
11
78
  npm i -g @azx-pbc/helix-cli
79
+ cd my-app
80
+ export HELIX_TOKEN="…"
81
+ helix deploy --promote
12
82
  ```
13
83
 
14
- Source: https://github.com/AZX-PBC-OSS/helix/tree/main/packages/cli
84
+ Needs **Node 24+** — the bundle is emitted at that target, so older runtimes
85
+ may not merely warn, they may fail to parse it.
86
+
87
+ `0.0.0` is a deprecated placeholder that exists only because npm requires a
88
+ package to exist before a trusted publisher can be attached to it. Every real
89
+ version is `0.1.0` or later and carries a provenance attestation.
90
+
91
+ ### From this monorepo today
92
+
93
+ Build the real binary once and link it; from then on `helix` behaves exactly as
94
+ it will when installed from npm:
95
+
96
+ ```bash
97
+ pnpm --filter @azx-pbc/helix-cli build
98
+ npm link ./packages/cli # puts `helix` on your PATH
99
+
100
+ cd examples/hello-world
101
+ export HELIX_TOKEN="$PORTAL_DEV_TOKEN" # the portal's dev-token stub
102
+ helix create --display-name "Hello World"
103
+ helix deploy --promote
104
+ helix versions
105
+ ```
106
+
107
+ Run it **from your app directory** so `helix.json` and a relative `--dir`
108
+ resolve against the app, not the repo.
109
+
110
+ Without linking, `node packages/cli/dist/helix.js <cmd>` works the same way. To
111
+ skip the build during CLI development, `node --import tsx packages/cli/src/bin.ts <cmd>`
112
+ runs straight from source.
113
+
114
+ ## About `pnpm --filter @azx-pbc/helix-cli helix -- <cmd>`
115
+
116
+ This form runs the CLI's dev script through pnpm. It works for flags now (the
117
+ CLI strips the `--` that pnpm forwards — see `src/args.ts`), **but pnpm runs the
118
+ script in `packages/cli`, not your app**. So it will not find your app's
119
+ `helix.json`, and a relative `--dir` resolves against `packages/cli`. Use it only
120
+ for `--help` or with explicit `--slug` + an absolute `--dir`:
121
+
122
+ ```bash
123
+ pnpm --filter @azx-pbc/helix-cli helix -- deploy --slug my-app \
124
+ --dir /abs/path/to/my-app/dist --promote
125
+ ```
126
+
127
+ For real deploys, prefer running from the app directory (`npm link`, above).
128
+
129
+ ## Packaging
130
+
131
+ This is the **only package in the repo that emits JS**. Everything else runs
132
+ from TypeScript source via `tsx` and is `private: true`; a published CLI can't.
133
+
134
+ `pnpm build` runs `scripts/build.mjs`, which esbuild-bundles `src/bin.ts` into a
135
+ single `dist/helix.js` with a `#!/usr/bin/env node` banner. Two things make that
136
+ the right shape rather than a `tsc --outDir`:
137
+
138
+ - **`@azx-pbc/shared` gets inlined.** It's a private `workspace:*` package whose
139
+ `exports` point straight at `./src/index.ts`, and the edge/portal/egress all
140
+ consume it as raw TS deliberately. Publishing must not force a build+dist+d.ts
141
+ onto `shared` for one consumer, and must not ship a manifest depending on
142
+ `@azx-pbc/shared@0.0.0` — a version no registry has. Bundling solves both, so
143
+ `shared` is a **devDependency** here, not a dependency.
144
+ - **No tsx at runtime.** The `bin` used to point at `src/bin.ts` behind a
145
+ `#!/usr/bin/env -S tsx` shebang while `tsx` was only a devDependency, so a real
146
+ global install would have been broken on arrival.
147
+
148
+ `archiver`, `openid-client`, and `zod` stay external and install from the
149
+ registry — bundling archiver's transitive tree buys nothing.
150
+
151
+ CI's `package` job builds, runs `pnpm pack`, asserts the tarball ships `dist/`
152
+ and no `src/`, then globally installs the tarball in a clean prefix **with tsx
153
+ off `PATH`** and runs `helix --help`. That last step is what actually proves
154
+ publishability; the unit tests never touch the bundle. It runs on every PR, so
155
+ a broken artifact fails before a release is ever cut.
156
+
157
+ ## Releasing
158
+
159
+ Releases are cut by tag and published by
160
+ [`.github/workflows/release-cli.yml`](../../.github/workflows/release-cli.yml):
161
+
162
+ ```bash
163
+ cd packages/cli
164
+ npm version patch # or minor — edits package.json only
165
+ cd ../.. && git commit -am "release(cli): v0.1.1"
166
+ git tag cli-v0.1.1 && git push && git push --tags
167
+ ```
168
+
169
+ The workflow re-runs the whole build → pack → assert → global-install sequence
170
+ against the tag, refuses to publish if the tag and `package.json` disagree, and
171
+ then publishes with provenance.
172
+
173
+ Three things to know before touching it:
174
+
175
+ - **The tag prefix is `cli-v`, not `v`.** `v*` is the platform's version and
176
+ already drives the container-image builds in `ci.yml`. The CLI versions
177
+ independently.
178
+ - **There is no `NPM_TOKEN`.** Auth is npm trusted publishing (OIDC): npmjs.com
179
+ has a registered trust relationship with `AZX-PBC-OSS/helix` +
180
+ `release-cli.yml`. Renaming or moving that workflow file breaks publishing
181
+ until the registration is updated — that narrowness is the point.
182
+ - **It packs with pnpm and publishes with npm.** Only pnpm rewrites `catalog:`
183
+ and `workspace:*` into real ranges; npm is the client whose OIDC support is
184
+ documented and reliable. Each does the half it's good at.
185
+
186
+ See [ADR-0032](../../docs/adr/0032-cli-naming-and-distribution.md) for why
187
+ public npm rather than GitHub Packages.