kylon-cli 0.1.0-next.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +472 -0
- package/dist/kylon-bundle.mjs +2 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
# kylon-cli
|
|
2
|
+
|
|
3
|
+
Gateway CLI for connecting local agent providers to a P2 workspace.
|
|
4
|
+
|
|
5
|
+
Requires Node.js 22 or newer.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
The CLI is published to npm as
|
|
10
|
+
[`kylon-cli`](https://www.npmjs.com/package/kylon-cli). The Web UI
|
|
11
|
+
generates two separate commands — an **install** step and a **run**
|
|
12
|
+
step — each with its own Copy button. Operators paste the install
|
|
13
|
+
once per host (and any time they want to upgrade) and the run
|
|
14
|
+
whenever they want to start the daemon.
|
|
15
|
+
|
|
16
|
+
### Step 1 — Install kylon (once per host, re-paste to upgrade)
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g kylon-cli@latest
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Installs the CLI globally so the `kylon` binary lands on PATH — the
|
|
23
|
+
gateway daemon's child `kylon workspace …` calls (issued by the
|
|
24
|
+
provider subprocess) resolve it there. Re-run to upgrade to whatever
|
|
25
|
+
the dist-tag now points to. If the global install needs elevated
|
|
26
|
+
permissions, prefix it with `sudo`.
|
|
27
|
+
|
|
28
|
+
The dist-tag tracks the environment: production installs `@latest`,
|
|
29
|
+
dev installs `@next` (newest prerelease). To pin a specific build,
|
|
30
|
+
install `kylon-cli@X.Y.Z`.
|
|
31
|
+
|
|
32
|
+
Requirements: Node.js 22+ (npm ships with Node). Linux / macOS only
|
|
33
|
+
(Windows operators should use WSL).
|
|
34
|
+
|
|
35
|
+
### Step 2 — Start the gateway daemon
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
kylon gateway run \
|
|
39
|
+
--server-url https://<origin>/api \
|
|
40
|
+
--provider codex \
|
|
41
|
+
--api-key <agent-api-key>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`gateway run` registers the session (writing `~/.kylon/gateway-session.json`
|
|
45
|
+
with mode `0600`) and starts the daemon in one step. On the next
|
|
46
|
+
invocation, if a session already exists, plain `kylon gateway run`
|
|
47
|
+
without flags picks it up and jumps straight to start. See
|
|
48
|
+
[Usage → Run](#run) for the full decision table. The daemon runs
|
|
49
|
+
in the foreground until you stop it with `Ctrl+C`; hosts that want a
|
|
50
|
+
supervised daemon typically wrap the same command in
|
|
51
|
+
`launchd` / `systemd` / `supervisord`.
|
|
52
|
+
|
|
53
|
+
### Local development (contributors)
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pnpm install
|
|
57
|
+
pnpm --filter kylon-cli build
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
See [Development → Exposing `kylon` to provider subprocesses](#exposing-kylon-to-provider-subprocesses)
|
|
61
|
+
for the debugger-friendly tsx-based dev loop.
|
|
62
|
+
|
|
63
|
+
### Release channels
|
|
64
|
+
|
|
65
|
+
npm dist-tags are the version pointer — there is no server-side version
|
|
66
|
+
policy. Every merge to `main` publishes a prerelease to the `next` tag
|
|
67
|
+
(`.github/workflows/cli-publish.yml`); cutting a `kylon-cli-vX.Y.Z`
|
|
68
|
+
release tag publishes a stable to `latest`. dev installs `@next` and prd
|
|
69
|
+
installs `@latest`, so each environment tracks its own train.
|
|
70
|
+
|
|
71
|
+
Cutting a stable is a manual, when-ready step: tag a validated build
|
|
72
|
+
`kylon-cli-vX.Y.Z` and push the tag; CI publishes it to `latest`. Don't
|
|
73
|
+
`npm publish` ad-hoc — releases go through the CI workflow so the OIDC
|
|
74
|
+
publish path is exercised end-to-end.
|
|
75
|
+
|
|
76
|
+
## Usage
|
|
77
|
+
|
|
78
|
+
### Run
|
|
79
|
+
|
|
80
|
+
`gateway run` is the recommended entrypoint for external agent operators.
|
|
81
|
+
It composes `connect` + `start` into a single command.
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
kylon gateway run \
|
|
85
|
+
--server-url https://api.p2.ai \
|
|
86
|
+
--provider codex \
|
|
87
|
+
--api-key pak_xxxxx
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Decision table:
|
|
91
|
+
|
|
92
|
+
| Saved session? | Flags passed? | What `run` does |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| no | `--server-url` + `--api-key` + `--provider` | connect, persist session, start daemon |
|
|
95
|
+
| no | any field missing | error — lists the missing flag |
|
|
96
|
+
| yes | none | start the daemon from the saved session |
|
|
97
|
+
| yes | any | reconnect with the overrides (falls back to saved values for fields you didn't pass), persist the refreshed session, start the daemon |
|
|
98
|
+
|
|
99
|
+
Only CLI flags count as overrides. Setting `KYLON_API_KEY` in the
|
|
100
|
+
environment does **not** trigger a reconnect on a saved session —
|
|
101
|
+
it still feeds the normal API-key resolution inside `gateway start`.
|
|
102
|
+
|
|
103
|
+
### Connect
|
|
104
|
+
|
|
105
|
+
Register this machine as the gateway client for an external agent.
|
|
106
|
+
Most operators should prefer `gateway run` above. Use `connect` on its
|
|
107
|
+
own when scripting or when you need to register a session without
|
|
108
|
+
immediately starting the daemon.
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
kylon gateway connect \
|
|
112
|
+
--server-url https://api.p2.ai \
|
|
113
|
+
--api-key pak_xxxxx \
|
|
114
|
+
--provider codex
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The agent's API key identifies which agent the daemon will serve;
|
|
118
|
+
channels are bound separately via the "invite agent into channel" flow
|
|
119
|
+
in the web UI.
|
|
120
|
+
|
|
121
|
+
### Bind
|
|
122
|
+
|
|
123
|
+
Create or update a logical session binding for an agent. Run from the
|
|
124
|
+
target working directory:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
kylon gateway bind \
|
|
128
|
+
--agent agent_123 \
|
|
129
|
+
--provider codex
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Switch an existing binding to a different directory:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
cd /path/to/other/repo
|
|
136
|
+
kylon gateway bind --agent agent_123 --workdir .
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Bindings are keyed by `(gateway session, agent)`. The same agent
|
|
140
|
+
behaves the same way regardless of which channel an assignment
|
|
141
|
+
arrives on — see
|
|
142
|
+
[`docs/journal_docs/05_27_gateway_routing_simplification.md`](../../docs/journal_docs/05_27_gateway_routing_simplification.md).
|
|
143
|
+
|
|
144
|
+
### Commands
|
|
145
|
+
|
|
146
|
+
| Command | Description |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `kylon gateway run` | **Recommended.** Connect + start in one step; idempotent when a session already exists. |
|
|
149
|
+
| `kylon gateway connect` | Register this machine as the gateway client for an agent (API key identifies which), without starting the daemon. |
|
|
150
|
+
| `kylon gateway bind` | Create or update a logical session binding. |
|
|
151
|
+
| `kylon gateway start` | Start the gateway daemon from a saved session — opens the SSE stream and executes assignments. Reads the API key from the saved session. |
|
|
152
|
+
|
|
153
|
+
### Run Options
|
|
154
|
+
|
|
155
|
+
| Flag | Description |
|
|
156
|
+
|---|---|
|
|
157
|
+
| `--server-url <url>` | P2 server URL (required for the first run; override otherwise) |
|
|
158
|
+
| `--api-key <key>` | Agent API key, e.g. `pak_xxx` (required for first run; override otherwise. `KYLON_API_KEY` env var satisfies the first-run requirement but does not count as an override on subsequent runs) |
|
|
159
|
+
| `--provider <name>` | Provider CLI: `codex`, `claude-code`, `hermes`, `openclaw`, `generic` (required for first run; override otherwise) |
|
|
160
|
+
|
|
161
|
+
### Connect Options
|
|
162
|
+
|
|
163
|
+
| Flag | Description |
|
|
164
|
+
|---|---|
|
|
165
|
+
| `--server-url <url>` | P2 server URL (required) |
|
|
166
|
+
| `--api-key <key>` | Agent API key, e.g. `pak_xxx` (required, or set `KYLON_API_KEY`) |
|
|
167
|
+
| `--provider <name>` | Provider CLI: `codex`, `claude-code`, `hermes`, `openclaw`, `generic` (required) |
|
|
168
|
+
|
|
169
|
+
### Bind Options
|
|
170
|
+
|
|
171
|
+
| Flag | Description |
|
|
172
|
+
|---|---|
|
|
173
|
+
| `--agent <id>` | Agent ID (required) |
|
|
174
|
+
| `--provider <name>` | Provider CLI (required for new, optional for update) |
|
|
175
|
+
| `--workdir <path>` | Working directory (default: current directory) |
|
|
176
|
+
|
|
177
|
+
### Supported Providers
|
|
178
|
+
|
|
179
|
+
- `codex` — OpenAI Codex CLI
|
|
180
|
+
- `claude-code` — Anthropic Claude Code CLI
|
|
181
|
+
- `hermes` — Hermes CLI using `hermes -z <prompt>`
|
|
182
|
+
- `openclaw` — OpenClaw CLI using `openclaw agent --message <prompt> --json`
|
|
183
|
+
- `generic` - provider-neutral wrapper. Runs a `kylon-provider`
|
|
184
|
+
executable on `PATH` and expects newline-delimited JSON events matching
|
|
185
|
+
`docs/journal_docs/05_25_external_agent_provider_adapter_contract.md`.
|
|
186
|
+
|
|
187
|
+
## State Model
|
|
188
|
+
|
|
189
|
+
The CLI uses a three-layer state model:
|
|
190
|
+
|
|
191
|
+
- **GatewaySession** — authenticated connection to the P2 server (one per machine)
|
|
192
|
+
- **LogicalSessionState** — per-`(gateway session, agent)` binding holding the current workdir and provider
|
|
193
|
+
- **ProviderRuntimeEntry** — per-conversation provider resume cache, keyed by `(gateway session, channel, agent, scope, provider, workdir)` (disposable)
|
|
194
|
+
|
|
195
|
+
Switching workdir updates the logical session without creating a new one. Provider runtimes are cached per workdir + conversation scope — switching back resumes the old runtime.
|
|
196
|
+
|
|
197
|
+
State is persisted to `~/.kylon/` (or `$XDG_CONFIG_HOME/kylon/`).
|
|
198
|
+
|
|
199
|
+
## Development
|
|
200
|
+
|
|
201
|
+
> This section assumes you cloned `fre-so/p2` and ran `pnpm install` at the
|
|
202
|
+
> repo root. All commands are run from anywhere in the monorepo unless
|
|
203
|
+
> otherwise noted.
|
|
204
|
+
|
|
205
|
+
### Inner loop
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
# type-check without emitting
|
|
209
|
+
pnpm --filter kylon-cli typecheck
|
|
210
|
+
|
|
211
|
+
# tsc build — emits dist/bin/kylon.js and other .js files
|
|
212
|
+
pnpm --filter kylon-cli build
|
|
213
|
+
|
|
214
|
+
# unit tests (no network, no DB)
|
|
215
|
+
pnpm --filter kylon-cli test
|
|
216
|
+
|
|
217
|
+
# run the locally built CLI
|
|
218
|
+
node packages/cli/dist/bin/kylon.js --help
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The Web agent-settings "Local dev" block generates the same
|
|
222
|
+
`node packages/cli/dist/bin/kylon.js …` invocation from the logged-in
|
|
223
|
+
agent's API key. If you change `src/bin/kylon.ts` or anything it
|
|
224
|
+
imports, rerun `pnpm --filter kylon-cli build` before re-executing.
|
|
225
|
+
|
|
226
|
+
### Exposing `kylon` to provider subprocesses
|
|
227
|
+
|
|
228
|
+
`node packages/cli/dist/bin/kylon.js gateway run …` starts the daemon
|
|
229
|
+
but leaves **no `kylon` binary on PATH**. When the provider subprocess
|
|
230
|
+
(claude-code / codex) then tries `kylon workspace …` via its Bash tool,
|
|
231
|
+
the shell fails with `command not found`. Two ways to fix this:
|
|
232
|
+
|
|
233
|
+
**Option 1 — `pnpm link` (persistent).** Symlink kylon's published
|
|
234
|
+
`bin.kylon` into pnpm's global bin dir:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
pnpm --filter kylon-cli bundle # or bundle:minify for a prod-shaped build
|
|
238
|
+
pnpm --filter kylon-cli link --global
|
|
239
|
+
|
|
240
|
+
which kylon
|
|
241
|
+
# → ~/Library/pnpm/kylon (or similar) → packages/cli/dist/kylon-bundle.mjs
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
From here on, start the daemon via the linked binary instead of the
|
|
245
|
+
raw `node dist/bin/kylon.js`:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
kylon gateway run --server-url http://localhost:5173/api --provider codex --api-key pak_…
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Every provider call to `kylon workspace …` resolves to the linked
|
|
252
|
+
binary. Edit source → `pnpm --filter kylon-cli bundle` → next provider
|
|
253
|
+
call picks it up (each workspace invocation is a fresh process;
|
|
254
|
+
restart the daemon only for *daemon*-side edits). Clean up with
|
|
255
|
+
`pnpm --filter kylon-cli unlink --global`.
|
|
256
|
+
|
|
257
|
+
**Option 2 — `--dev-cli-shim` (ephemeral, IDE-friendly).** The daemon
|
|
258
|
+
can install a temporary bash shim that execs the TS source through
|
|
259
|
+
tsx. Pass `--dev-cli-shim <abs-path-to-p2-repo>` on `gateway run` or
|
|
260
|
+
`gateway start`:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
node packages/cli/dist/bin/kylon.js gateway run \
|
|
264
|
+
--server-url http://localhost:5173/api \
|
|
265
|
+
--provider codex \
|
|
266
|
+
--api-key pak_… \
|
|
267
|
+
--dev-cli-shim "$(pwd)"
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
The daemon prints the shim location on startup:
|
|
271
|
+
|
|
272
|
+
```text
|
|
273
|
+
[dev] kylon shim: /tmp/kylon-dev-shim-abc123/kylon
|
|
274
|
+
[dev] provider calls will exec: node --import tsx /abs/path/packages/cli/src/bin/kylon.ts
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
The tmpdir is prepended to the daemon's `PATH`, so the provider
|
|
278
|
+
subprocess (and the bash shell it spawns) resolves `kylon` to the
|
|
279
|
+
shim. The shim execs `node --import tsx <src>`, so:
|
|
280
|
+
|
|
281
|
+
- Every `kylon workspace …` invocation reads the current `src/*.ts` —
|
|
282
|
+
no bundle rebuild needed between edits.
|
|
283
|
+
- A Node debugger attached to the daemon is inherited by each shim
|
|
284
|
+
invocation (they exec `node`, so `NODE_OPTIONS` and VS Code's
|
|
285
|
+
Auto-Attach loader pass through).
|
|
286
|
+
- On SIGINT/SIGTERM the tmpdir is wiped.
|
|
287
|
+
|
|
288
|
+
This flag is **only compiled into local (non-minified) builds**. The
|
|
289
|
+
npm package and any `bundle:release` output reject `--dev-cli-shim` as
|
|
290
|
+
an unknown argument and omit it from `--help`, so it can never
|
|
291
|
+
accidentally ship.
|
|
292
|
+
|
|
293
|
+
### Debugging both the daemon and `kylon workspace` calls
|
|
294
|
+
|
|
295
|
+
Combine `--dev-cli-shim` with a Node debugger to step through the
|
|
296
|
+
full chain — daemon → provider subprocess → `kylon workspace …` — in
|
|
297
|
+
one IDE session.
|
|
298
|
+
|
|
299
|
+
**VS Code**:
|
|
300
|
+
|
|
301
|
+
1. Enable `Debug: Toggle Auto Attach → Always` (or `Only With Flag`).
|
|
302
|
+
VS Code prepends its `js-debug` bootloader to `NODE_OPTIONS`, which
|
|
303
|
+
every child Node process — including the ones launched by the
|
|
304
|
+
shim — inherits.
|
|
305
|
+
2. Open an integrated terminal and run:
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
node packages/cli/dist/bin/kylon.js gateway run \
|
|
309
|
+
--server-url http://localhost:5173/api \
|
|
310
|
+
--provider codex \
|
|
311
|
+
--api-key pak_… \
|
|
312
|
+
--dev-cli-shim "$(pwd)"
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
3. Set breakpoints in both `packages/cli/src/commands/gateway-start.ts`
|
|
316
|
+
(daemon) and `packages/cli/src/commands/workspace/*.ts` (child
|
|
317
|
+
commands). Both fire the next time the provider issues a workspace
|
|
318
|
+
call.
|
|
319
|
+
|
|
320
|
+
**JetBrains / others**: export `NODE_OPTIONS=--inspect=0.0.0.0:0`
|
|
321
|
+
before launching the daemon. Every subsequent Node process — daemon
|
|
322
|
+
and every `kylon workspace …` invocation — opens its own inspector
|
|
323
|
+
port. Attach your IDE to the process list.
|
|
324
|
+
|
|
325
|
+
No debugger attach? The shim still works — source edits are picked up
|
|
326
|
+
on the next provider call, but breakpoints just don't fire.
|
|
327
|
+
|
|
328
|
+
### Bundles
|
|
329
|
+
|
|
330
|
+
The release artifact is a single-file ESM bundle produced by
|
|
331
|
+
`scripts/bundle.mjs`. Three variants:
|
|
332
|
+
|
|
333
|
+
| Script | Output | Passes to `bundle.mjs` | Use when |
|
|
334
|
+
|---|---|---|---|
|
|
335
|
+
| `pnpm --filter kylon-cli bundle` | `dist/kylon-bundle.mjs` | _(none)_ | debugging the bundled shape while keeping readable names — not shipped |
|
|
336
|
+
| `pnpm --filter kylon-cli bundle:minify` | `dist/kylon-bundle.mjs` | `--minify` | reproducing the pre-obfuscation size and behavior for a bisect |
|
|
337
|
+
| `pnpm --filter kylon-cli bundle:release` | `dist/kylon-bundle.mjs` | `--minify --obfuscate` | what ships on npm |
|
|
338
|
+
|
|
339
|
+
The `bundle:release` path runs esbuild with `--minify`, then passes the
|
|
340
|
+
output through `javascript-obfuscator`. It's also what the `prepack` hook
|
|
341
|
+
runs, so `pnpm pack` / `npm publish` always produce the obfuscated shape
|
|
342
|
+
even if you forget to call `bundle:release` explicitly.
|
|
343
|
+
|
|
344
|
+
Run the bundle directly to sanity-check it:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
pnpm --filter kylon-cli bundle:release
|
|
348
|
+
node packages/cli/dist/kylon-bundle.mjs --help
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Testing
|
|
352
|
+
|
|
353
|
+
Unit tests run against Node's built-in test runner (`node:test`) plus
|
|
354
|
+
`tsx`. They touch the filesystem inside temp dirs but never the
|
|
355
|
+
network or a database, so `pnpm --filter kylon-cli test` is safe to
|
|
356
|
+
run anywhere.
|
|
357
|
+
|
|
358
|
+
E2E tests drive the CLI as a subprocess against a configurable mock
|
|
359
|
+
or live server:
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
# headless e2e (mock provider processes spawned from scripts/mock-*.mjs)
|
|
363
|
+
pnpm --filter kylon-cli test:e2e
|
|
364
|
+
|
|
365
|
+
# live e2e against a real P2 environment — requires doppler secrets
|
|
366
|
+
doppler run --project p2 --config prd -- pnpm --filter kylon-cli test:e2e:live
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Live E2E tests provision a throwaway workspace via the REST API, so
|
|
370
|
+
expect them to take several minutes and to leave audit trail rows in
|
|
371
|
+
the target environment. Do not point them at production casually.
|
|
372
|
+
|
|
373
|
+
Before shipping a release, also smoke-test the packaged artifact
|
|
374
|
+
exactly as operators will receive it:
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
# 1. produce the release bundle + tarball
|
|
378
|
+
pnpm --filter kylon-cli bundle:release
|
|
379
|
+
cd packages/cli && pnpm pack --pack-destination /tmp/kylon-out
|
|
380
|
+
|
|
381
|
+
# 2. install the tarball in a clean directory
|
|
382
|
+
WORK=$(mktemp -d) && cd "$WORK"
|
|
383
|
+
npm init -y >/dev/null
|
|
384
|
+
npm install /tmp/kylon-out/kylon-cli-*.tgz
|
|
385
|
+
|
|
386
|
+
# 3. the published shape should have only three entries
|
|
387
|
+
ls node_modules/kylon-cli # dist/ package.json README.md
|
|
388
|
+
ls node_modules/kylon-cli/dist # kylon-bundle.mjs
|
|
389
|
+
|
|
390
|
+
# 4. verify the binary is runnable
|
|
391
|
+
node_modules/.bin/kylon --help
|
|
392
|
+
|
|
393
|
+
# 5. confirm the bundle is actually obfuscated
|
|
394
|
+
head -c 200 node_modules/kylon-cli/dist/kylon-bundle.mjs
|
|
395
|
+
# expect `#!/usr/bin/env node` followed by hexadecimal identifier soup,
|
|
396
|
+
# not recognizable function names or source strings
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Obfuscation
|
|
400
|
+
|
|
401
|
+
`bundle:release` and `prepack` run `javascript-obfuscator` with a
|
|
402
|
+
conservative preset chosen for runtime safety:
|
|
403
|
+
|
|
404
|
+
- **On:** `compact`, `identifierNamesGenerator: "hexadecimal"`,
|
|
405
|
+
`stringArray` with `base64` encoding + rotate + shuffle, two
|
|
406
|
+
wrapper function layers.
|
|
407
|
+
- **Off:** `controlFlowFlattening`, `deadCodeInjection`,
|
|
408
|
+
`selfDefending`, `debugProtection`, `unicodeEscapeSequence`. These
|
|
409
|
+
trade correctness and startup latency for marginal protection — do
|
|
410
|
+
not turn them on without measuring startup and rerunning the full
|
|
411
|
+
test:e2e suite.
|
|
412
|
+
- `renameGlobals` stays off so Node built-ins keep their names.
|
|
413
|
+
|
|
414
|
+
Startup stays under 100 ms on modern hardware; bundle grows from
|
|
415
|
+
~85 KB (minify only) to ~230 KB (obfuscated). Obfuscation is a
|
|
416
|
+
tampering and casual-reading deterrent, not a security control — the
|
|
417
|
+
API server is the security boundary.
|
|
418
|
+
|
|
419
|
+
## Release
|
|
420
|
+
|
|
421
|
+
The CLI ships via **npm dist-tags** — there is no server-side version policy.
|
|
422
|
+
`cli-verify.yml` validates on PRs and pushes; `cli-publish.yml` publishes via
|
|
423
|
+
OIDC (no token): a prerelease to the `next` tag on every merge to `main`, and a
|
|
424
|
+
stable to `latest` when a `kylon-cli-vX.Y.Z` tag is pushed. dev installs
|
|
425
|
+
`@next`, prd installs `@latest`.
|
|
426
|
+
|
|
427
|
+
### Versioning
|
|
428
|
+
|
|
429
|
+
Use explicit semver in `packages/cli/package.json`:
|
|
430
|
+
|
|
431
|
+
| Bump | When |
|
|
432
|
+
|---|---|
|
|
433
|
+
| patch (`0.1.0 → 0.1.1`) | bug fix, no new flags, no behavior change |
|
|
434
|
+
| minor (`0.1.x → 0.2.0`) | backward-compatible capability (new command, new flag) |
|
|
435
|
+
| major (`0.x.x → 1.0.0`) | breaking change to CLI contract or runtime behavior |
|
|
436
|
+
|
|
437
|
+
Prerelease builds are versioned `0.1.0-next.<run>` automatically by
|
|
438
|
+
`cli-publish.yml`; a stable release is whatever you tag — bump
|
|
439
|
+
`packages/cli/package.json` to the target semver, then push the matching
|
|
440
|
+
`kylon-cli-vX.Y.Z` tag.
|
|
441
|
+
|
|
442
|
+
### Publishing
|
|
443
|
+
|
|
444
|
+
- **Prerelease (automatic):** every merge to `main` touching the CLI publishes
|
|
445
|
+
`0.1.0-next.<run>` to the `next` tag via `cli-publish.yml` (OIDC, no
|
|
446
|
+
`NPM_TOKEN`). dev tracks this tag, so dev always dogfoods the newest build.
|
|
447
|
+
- **Stable (manual, when ready):** bump `packages/cli/package.json` to the
|
|
448
|
+
target version, merge, then tag the commit on `main`:
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
git pull
|
|
452
|
+
git tag kylon-cli-v0.1.1
|
|
453
|
+
git push origin kylon-cli-v0.1.1 # cli-publish.yml publishes it to `latest`
|
|
454
|
+
npm view kylon-cli dist-tags # verify
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
Do not `npm publish` ad-hoc — releases go through the workflow so the OIDC
|
|
458
|
+
provenance path is exercised end to end.
|
|
459
|
+
|
|
460
|
+
### Rollback
|
|
461
|
+
|
|
462
|
+
npm publishes are immutable; roll back by re-pointing the tag, not by
|
|
463
|
+
unpublishing:
|
|
464
|
+
|
|
465
|
+
```bash
|
|
466
|
+
npm dist-tag add kylon-cli@<last-good> latest # move the channel back
|
|
467
|
+
npm deprecate kylon-cli@<bad> "Broken release — use <last-good>."
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Operators on `@latest` pick up the re-pointed version the next time they
|
|
471
|
+
`npm install -g kylon-cli@latest`; in-flight daemons keep their current CLI
|
|
472
|
+
until they restart. Do not `npm unpublish`.
|