@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.
- package/LICENSE +21 -0
- package/README.md +180 -7
- package/dist/helix.js +1185 -0
- 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
|
-
#
|
|
1
|
+
# `helix` — Helix deploy CLI
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|