@kaiba-cloud/cli 0.1.0 → 0.2.1

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kaiba-cloud/cli",
3
- "version": "0.1.0",
4
- "description": "Kaiba CLI build and deploy your apps from CI or a terminal.",
3
+ "version": "0.2.1",
4
+ "description": "Kaiba CLI \u2014 build and deploy your apps from CI or a terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
7
7
  "bin": {
@@ -10,19 +10,26 @@
10
10
  "files": [
11
11
  "dist",
12
12
  "action.yml",
13
- "README.md"
13
+ "README.md",
14
+ "skills"
14
15
  ],
15
16
  "publishConfig": {
16
17
  "access": "public"
17
18
  },
18
19
  "scripts": {
19
- "build": "tsc -p tsconfig.json",
20
- "prepublishOnly": "tsc -p tsconfig.json",
21
- "check-types": "tsc --noEmit"
20
+ "build": "node scripts/build.mjs",
21
+ "check-types": "tsc --noEmit -p tsconfig.json",
22
+ "test": "vitest run",
23
+ "prepublishOnly": "node scripts/build.mjs && node scripts/verify-tarball.mjs"
22
24
  },
23
25
  "devDependencies": {
26
+ "@ai-agents/redis-protocol": "workspace:*",
27
+ "@kaiba/sdk": "workspace:*",
24
28
  "@types/node": "^20.19.43",
25
- "typescript": "^5.9.3"
29
+ "typescript": "^5.9.3",
30
+ "esbuild": "^0.25.0",
31
+ "vitest": "^4.1.10",
32
+ "tsx": "^4.19.2"
26
33
  },
27
34
  "engines": {
28
35
  "node": ">=18"
@@ -0,0 +1,239 @@
1
+ ---
2
+ name: kaiba-cli
3
+ description: Use when working with the Kaiba platform from a shell — dispatching a managed agent and waiting for its result, deploying campus skills, agents or blueprints, operating a dev environment, uploading or fetching artifacts, running workflows, or diagnosing a `kaiba` command that failed. Prefer this over the Kaiba MCP tools for anything that has to wait.
4
+ ---
5
+
6
+ # The Kaiba CLI
7
+
8
+ `kaiba` reaches the Kaiba platform as **you**, not as an organisation key. One
9
+ login covers every organisation you belong to, and the platform's own permissions
10
+ decide each request.
11
+
12
+ ## First moves
13
+
14
+ Never guess a flag. The CLI describes itself, and the description is generated
15
+ from the same declarations that parse your arguments, so it cannot be out of date:
16
+
17
+ ```bash
18
+ kaiba describe # the top-level commands, one line each
19
+ kaiba describe campus agents # one group's commands
20
+ kaiba schema campus agents sessions run # one command's full schema
21
+ ```
22
+
23
+ `describe` and `schema` need no credential and make no network call. They are
24
+ safe to run first, before you know whether you are logged in.
25
+
26
+ ## The shape of the tree
27
+
28
+ Two trees, and everything sits in one of them.
29
+
30
+ ```
31
+ campus agents the agent definitions list get create update delete sync
32
+ campus agents sessions the runs of one run list get result history logs message stop close delete
33
+ campus skills what an agent loads list get sync
34
+ campus blueprints a skill plus a scaffold list get sync
35
+ campus artifacts the files agents make list get upload replace download delete tags
36
+ campus workflows graphs that dispatch list get pull push run runs status cancel delete
37
+
38
+ env the dev environment status services logs exec query deploy compose vars …
39
+ ```
40
+
41
+ `login`, `logout`, `whoami`, `orgs` and `org` sit outside both, and so do the
42
+ four CI commands, which take a different credential.
43
+
44
+ ## The output contract
45
+
46
+ Output is **JSON whenever stdout is not a terminal**, so a pipe, a CI job or an
47
+ agent gets machine-readable output with no flag. Add `--output json` to force it,
48
+ or `--output ndjson` for a stream.
49
+
50
+ **Exit codes:**
51
+
52
+ | Code | Meaning |
53
+ |---|---|
54
+ | 0 | Success. Under `--wait`, the agent run also succeeded. |
55
+ | 1 | The CLI or the hub failed. State may be partly changed. |
56
+ | 2 | Auth: no credential, the wrong one, or refused. |
57
+ | 3 | Validation. Refused **before** anything happened. |
58
+ | 4 | Confirmation required. Nothing changed. |
59
+ | 5 | Every write landed, and something a human must fix remains. |
60
+
61
+ Branch on the exit code first. For the sub-case, read `error.code` — it is a
62
+ closed, documented set.
63
+
64
+ Errors go to **stderr** and carry a `hint`, and often a `nextCommand`. **When
65
+ `nextCommand` is present, run it.** It is exact and already quoted.
66
+
67
+ ```json
68
+ {"ok":false,"command":"agents.get",
69
+ "error":{"code":"not-found","message":"Managed agent not found.",
70
+ "hint":"List the agents in this organisation.",
71
+ "nextCommand":"kaiba campus agents list --output json","exitCode":1}}
72
+ ```
73
+
74
+ **NDJSON streams:** read lines, ignore a `type` you do not recognise, stop at
75
+ `type:"result"`, then read the exit code. That one sentence is the whole contract.
76
+
77
+ ## Credentials
78
+
79
+ ```bash
80
+ kaiba login # prints a code, you approve it in a browser, done
81
+ kaiba whoami # which credential, from where, which organisation
82
+ ```
83
+
84
+ `login` uses a device code, so it works over SSH, in a container and in a sandbox
85
+ — anywhere without a browser. The credential is stored in your OS keychain where
86
+ one is available, and `whoami` always tells you which store was used.
87
+
88
+ **Never pass a token as a flag.** There is no flag for one. A token on a command
89
+ line reaches your shell history, the process table, and an agent's transcript. For
90
+ CI, set `KAIBA_API_TOKEN`.
91
+
92
+ There are two credential classes and they are not interchangeable. `kaiba login`
93
+ gives you a **user** credential for everything under `campus` and `env`. `build`,
94
+ `deploy`, `registry-login` and `status` are the **CI** commands and want a `kaiba_deploy_` token in
95
+ `KAIBA_API_TOKEN`. Present the wrong one and the CLI exits 2 and names the command
96
+ that wants the other.
97
+
98
+ ## Choosing an organisation
99
+
100
+ One rule: `--org` beats `KAIBA_ORG_ID`, which beats the stored default, which is
101
+ used only when you belong to exactly one organisation.
102
+
103
+ If none of those resolves and you belong to several, the CLI **refuses** rather
104
+ than picking. Every command reports `data.org.resolvedFrom`, so which source won
105
+ is never a guess.
106
+
107
+ ```bash
108
+ kaiba orgs # list them
109
+ kaiba org use acme # set a default once
110
+ ```
111
+
112
+ ## Recipe: run an agent and get its answer
113
+
114
+ This is what the CLI is for. An MCP tool call cannot block for twenty minutes;
115
+ this can.
116
+
117
+ ```bash
118
+ kaiba campus agents sessions run --agent ag-123 --message-file task.md --wait
119
+ ```
120
+
121
+ **There is no timeout.** It waits until the run is done, however long that takes,
122
+ and heartbeats every minute so you can see it is alive. Read the exit code:
123
+
124
+ - **0** — the agent finished and succeeded. The answer is in `data.result`.
125
+ - **1** with `error.code: "agent-failed"` — it ran and failed. Read the transcript:
126
+ `kaiba campus agents sessions history <id>`.
127
+ - **1** with `error.code: "timeout"` — only possible if you passed `--timeout`.
128
+ `data.sessionId` comes back, so **resume rather than starting again**:
129
+ `kaiba campus agents sessions result <id> --wait`.
130
+
131
+ To start work and collect it later, drop `--wait`: you get a `sessionId`
132
+ immediately.
133
+
134
+ ## Recipe: watch a run as it happens
135
+
136
+ ```bash
137
+ kaiba campus agents sessions run --agent ag-123 --message "check the build" --follow --wait --output ndjson
138
+ ```
139
+
140
+ `--follow` narrates, `--wait` decides. With both, the exit code comes from the
141
+ result, never from the stream — a terminated session with no result is a failure.
142
+ A dropped connection resumes from the last event with nothing lost or repeated.
143
+
144
+ ## Recipe: deploy campus artifacts
145
+
146
+ **Always dry-run first.**
147
+
148
+ ```bash
149
+ kaiba campus skills sync --dry-run # read the plan
150
+ kaiba campus skills sync # then do it
151
+ ```
152
+
153
+ `--scope system` targets the platform registry and is update-only: it never
154
+ creates. If a sync refuses because an artifact was promoted to system scope, that
155
+ is the cross-scope guard doing its job — do not work around it, use `--scope system`.
156
+
157
+ ## Recipe: workflows as files in git
158
+
159
+ ```bash
160
+ kaiba campus workflows pull # graphs to *.trigger.json
161
+ kaiba campus workflows push --dry-run # preview
162
+ kaiba campus workflows push # deploy
163
+ kaiba campus workflows run wf-1 --node dispatch --wait # run from ONE node
164
+ ```
165
+
166
+ `push` never arms or disarms anything. Deploying a graph and turning it on are two
167
+ decisions, and the file's `enabled` key is reported against the live state rather
168
+ than applied.
169
+
170
+ ## Recipe: operate a dev environment
171
+
172
+ Every `devEnv*` MCP tool has a command here:
173
+
174
+ | MCP tool | Command |
175
+ |---|---|
176
+ | `devEnvConnect`, `devEnvServiceStatus` | `kaiba env status` |
177
+ | `devEnvGetCompose` / `devEnvSetCompose` | `kaiba env compose get` / `set` |
178
+ | `devEnvSetVars` | `kaiba env vars set` |
179
+ | `devEnvDeploy` | `kaiba env deploy` |
180
+ | `devEnvServiceLogs` | `kaiba env logs --service X` |
181
+ | `devEnvExec` | `kaiba env exec --service X -- <cmd>` |
182
+ | `devEnvQuery` | `kaiba env query --service X --engine postgres --sql "..."` |
183
+ | `devEnvRestartService` | `kaiba env restart --service X` |
184
+ | `devEnvResetVolume` / `devEnvResizeVolume` | `kaiba env volume reset` / `resize` |
185
+ | `devEnvRunJob` / `devEnvListJobs` | `kaiba env jobs run` / `list` |
186
+
187
+ `env exec` is one shot and returns captured output. **Its exit code is the remote
188
+ command's**, labelled `exitCodeSource: "remote"` — the one place the exit code is
189
+ not from the table above.
190
+
191
+ ## Recipe: artifacts
192
+
193
+ ```bash
194
+ kaiba campus artifacts upload --file report.md --title "Q3 report" --tags finance
195
+ kaiba campus artifacts download art-1 --output-file report.md
196
+ ```
197
+
198
+ Upload is a two-step presigned PUT and the CLI handles both steps. If it reports
199
+ `error.code: "transport"`, the row exists with no bytes — run the
200
+ `kaiba campus artifacts replace` command it gives you.
201
+
202
+ ## Destructive commands
203
+
204
+ There is no interactive prompt, because you cannot answer one. Instead a
205
+ destructive command **exits 4 and changes nothing**, printing what it would do:
206
+
207
+ ```json
208
+ {"ok":false,"command":"env.volume.reset",
209
+ "error":{"code":"confirmation-required","exitCode":4},
210
+ "confirmation":{
211
+ "changes":[{"action":"delete","resource":"volume","target":"db",
212
+ "detail":"Every byte in db's volume is lost. This cannot be undone."}],
213
+ "confirmCommand":"kaiba env volume reset --service db --confirm --output json"}}
214
+ ```
215
+
216
+ **Show `confirmation.changes` to your human. If they approve, run
217
+ `confirmation.confirmCommand` verbatim.** Do not reconstruct it and do not add
218
+ `--confirm` yourself to a command they have not seen.
219
+
220
+ ## What introspection cannot tell you
221
+
222
+ - **Prefer this CLI over the Kaiba MCP tools for anything that waits.** An MCP
223
+ call cannot block and has no cursor to resume from.
224
+ - **A managed-agent pod has no `kaiba` binary.** Inside a pod, use the MCP tools.
225
+ This CLI is for a developer machine, a CI runner, or an agent with a shell.
226
+ - **Always `--dry-run` a campus sync first.**
227
+ - **Never put a token on a command line.**
228
+
229
+ ## When something fails
230
+
231
+ | Symptom | What it means |
232
+ |---|---|
233
+ | exit 2, `no-credential` | Run `kaiba login`. |
234
+ | exit 2, `wrong-credential-class` | You have the CI token and want the user one, or the reverse. The error names the right command. |
235
+ | exit 3, no organisation | Pass `--org`, or run `kaiba org use <id>` once. |
236
+ | exit 3, `invalid-input` with a `codePoint` | A value contains a control character. It is refused, not cleaned, because cleaning would change what you named. |
237
+ | exit 3, `cli-too-old` | The platform needs a newer CLI. The hint carries the upgrade command. |
238
+ | exit 4 | Nothing happened. See the confirmation section above. |
239
+ | exit 5 | Every write landed. Something still needs a human — read `data`. |
package/dist/client.js DELETED
@@ -1,52 +0,0 @@
1
- /**
2
- * HTTP client for the Kaiba CI surface (`/ci/*` on the hub). Authenticates with
3
- * a scoped deploy token via `x-api-key`. Uses only the Node 18+ global `fetch`,
4
- * so the CLI ships with no runtime dependencies.
5
- */
6
- export class KaibaApiError extends Error {
7
- status;
8
- constructor(status, message) {
9
- super(message);
10
- this.status = status;
11
- this.name = 'KaibaApiError';
12
- }
13
- }
14
- export class KaibaClient {
15
- base;
16
- token;
17
- constructor(opts) {
18
- this.base = opts.hubUrl.replace(/\/$/, '');
19
- this.token = opts.token;
20
- }
21
- async request(method, path, body) {
22
- const res = await fetch(`${this.base}${path}`, {
23
- method,
24
- headers: {
25
- 'x-api-key': this.token,
26
- ...(body ? { 'content-type': 'application/json' } : {}),
27
- },
28
- ...(body ? { body: JSON.stringify(body) } : {}),
29
- });
30
- const text = await res.text();
31
- const data = text ? JSON.parse(text) : {};
32
- if (!res.ok) {
33
- throw new KaibaApiError(res.status, data.error ?? `${res.status} ${res.statusText}`);
34
- }
35
- return data;
36
- }
37
- startBuild(req) {
38
- return this.request('POST', '/ci/builds', req);
39
- }
40
- getBuild(buildId, clusterId) {
41
- return this.request('GET', `/ci/builds/${encodeURIComponent(buildId)}?clusterId=${encodeURIComponent(clusterId)}`);
42
- }
43
- getBuildLogs(buildId, clusterId) {
44
- return this.request('GET', `/ci/builds/${encodeURIComponent(buildId)}/logs?clusterId=${encodeURIComponent(clusterId)}`);
45
- }
46
- deploy(service, image) {
47
- return this.request('POST', '/ci/deploy', { service, image });
48
- }
49
- status() {
50
- return this.request('GET', '/ci/status');
51
- }
52
- }