@kahunalabs/cli 0.0.0-stage → 0.0.14

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 +144 -2
  3. package/dist/index.js +79 -0
  4. package/package.json +43 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kalle Hansson
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,3 +1,145 @@
1
- # Temporary Holding Version
1
+ # `kahuna` — the Kahuna command line
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ ```
4
+ kahuna <noun> [<sub-noun>] <verb> [target] [--flags]
5
+ ```
6
+
7
+ ```bash
8
+ kahuna auth login --host https://kahuna.example.com
9
+ kahuna record list vendor --where status=active --json | jq '.[].label'
10
+ kahuna record import vendor vendors.csv --key name
11
+ kahuna concept create Supplier
12
+ kahuna access check --user <id> --action edit --resource concept --id <id>
13
+ ```
14
+
15
+ ## The grammar
16
+
17
+ **Every command names the thing that owns the row.** A relation edge belongs to
18
+ a record, so it is `record relation add`; a relation *type* is a field on a
19
+ concept, so it is `concept field add --kind relation`.
20
+
21
+ **The first token after a noun is a verb or a sub-noun — never an id.** Ids come
22
+ after the verb. That is what makes `task status list` (the status catalogue)
23
+ unambiguous next to `task update <id> --status done` (one task's status).
24
+
25
+ **One verb set:** `list · get · create · update · delete · archive · restore`,
26
+ plus domain verbs where the domain has one (`publish`, `transition`, `sync`,
27
+ `assign`, `deactivate`). A verb means the same thing under every noun: `delete`
28
+ always purges, `archive` is always reversible.
29
+
30
+ Run `kahuna help` for the full list, `kahuna <command> --help` for one, and
31
+ `kahuna --version` (or `-v`) for the CLI's own version — no network and no
32
+ sign-in. That last one is deliberately not `kahuna system version`, which asks the
33
+ DEPLOYMENT what it is running and warns if the two have drifted.
34
+
35
+ ## Output
36
+
37
+ Data on **stdout**, everything else on **stderr** — `kahuna … --json | jq` never has
38
+ to filter our chatter. `--json`, `--csv`, or an aligned table by default.
39
+
40
+ | exit | meaning |
41
+ | --- | --- |
42
+ | 0 | fine |
43
+ | 1 | failed |
44
+ | 2 | you typed something wrong |
45
+ | 3 | not signed in |
46
+ | 4 | not allowed |
47
+ | 5 | not found |
48
+ | 6 | conflict (something changed underneath, or is still in use) |
49
+
50
+ ## Configuration
51
+
52
+ One deployment, stored in `$XDG_CONFIG_HOME/kahuna/config.json` (mode 0600):
53
+
54
+ ```json
55
+ { "host": "https://kahuna.example.com", "cookie": "…", "email": "you@example.com" }
56
+ ```
57
+
58
+ `kahuna auth login --host <url>` writes it; every later command reads it. **There is
59
+ no default host** — an unconfigured CLI says so rather than quietly trying
60
+ `localhost`. `KAHUNA_HOST` overrides it without touching the file, which is what CI
61
+ wants.
62
+
63
+ ## Signing in through the browser
64
+
65
+ ```bash
66
+ kahuna auth login --browser # or --sso, which is the same thing
67
+ ```
68
+
69
+ ```
70
+ Open: https://kahuna.example.com/api/cli/device?code=WDJB-MJHT
71
+ ```
72
+
73
+ The CLI prints a link and waits. Open it in **any browser, on any machine** —
74
+ your laptop, your phone — and sign in however this deployment allows (password,
75
+ SSO, anything). Opening the link is the approval; there is nothing to type. The
76
+ CLI is polling, and continues on its own.
77
+
78
+ Nothing is redirected anywhere and nothing listens on a local port, which is
79
+ deliberate: the usual loopback-redirect flow needs the browser and the CLI on
80
+ the same machine, so it breaks over ssh, in a devcontainer, or any time you would
81
+ rather open the link on your phone. The CLI never talks to your identity
82
+ provider either, which is why this works where a CLI-driven SSO flow cannot.
83
+
84
+ The credential is the browser's session, so **signing out in the browser signs
85
+ the CLI out too**. That goes away when token credentials land.
86
+
87
+ ## Keeping the CLI current
88
+
89
+ ```bash
90
+ kahuna cli update # upgrade to the newest published version
91
+ kahuna cli update --dry-run # print what it would run, change nothing
92
+ ```
93
+
94
+ **Why this matters more than it looks.** The CLI carries a *copy* of the wire
95
+ contract, compiled in at build time. Against a deployment built from newer
96
+ sources, a procedure whose shape changed fails inside a schema decode with a
97
+ message about a field nobody typed. `kahuna system version` detects that skew and
98
+ says "update the CLI first"; this is how you do it.
99
+
100
+ `kahuna cli update` asks **npm** what the newest `@kahunalabs/cli` is and upgrades a
101
+ global install in place, with no prompt. `kahuna system version` asks your
102
+ **deployment** what image it runs — different artifact, different registry. Set
103
+ `KAHUNA_REGISTRY` to point at a mirror.
104
+
105
+ It works out which package manager owns the install from where the binary
106
+ actually lives (`npm`, `bun`, `pnpm`, `yarn`) and **refuses** in three cases,
107
+ naming the command to run instead:
108
+
109
+ | where it is | why it refuses |
110
+ | --- | --- |
111
+ | a source checkout or `npm link` | installing would write over a working tree |
112
+ | a project dependency | it would rewrite that project's lockfile, and the CLI's CWD is not reliably that project's root |
113
+ | an `npx` cache | it is ephemeral; there is nothing installed to update |
114
+
115
+ The package manager's output goes to **stderr** with all other chatter, so
116
+ `kahuna cli update --json` stays parseable.
117
+
118
+ ## What it cannot do yet
119
+
120
+ - **Unattended CI.** A session expires, and `kahuna auth token create` needs
121
+ BetterAuth's API-key plugin server-side. Until then, CI needs a
122
+ password-capable account and `kahuna auth login --email --password`.
123
+ - **Filter or sort on the server.** `listRecords` takes a concept and nothing
124
+ else, so `--where` / `--sort` / `--limit` run client-side over the whole set,
125
+ which the server caps at 50 000 records. Above that the CLI says so rather
126
+ than returning a truncated list that looks complete.
127
+
128
+ ## Development
129
+
130
+ ```bash
131
+ bun run --cwd packages/cli test # unit tests, no server needed
132
+ bun run cli:build # bundle for Node -> dist/index.js
133
+ bun run --cwd packages/app scripts/verify-cli.ts # end-to-end, needs a live server
134
+ ```
135
+
136
+ The bundle is ~620 KB, ~190 KB installed, with no dependencies. Effect is about
137
+ 80% of that: the wire contract is defined with `effect/Schema` and the client is
138
+ `@effect/rpc`, so the CLI carries the server's runtime in order to speak its
139
+ format. That is the price of one shared contract and no drift, and it is a price
140
+ paid once at install.
141
+
142
+ The CLI targets **Node**, not Bun: `@types/bun` is deliberately absent, and
143
+ TypeScript that emits (parameter properties, enums) breaks
144
+ `node --experimental-strip-types` even though it typechecks. CI builds the
145
+ bundle and smoke-tests it with plain `node` for exactly that reason.