@khotan/cli 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/README.md +215 -0
- package/dist/khotan.js +2491 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Khotan CLI & MCP server
|
|
2
|
+
|
|
3
|
+
`@khotan/cli` is the first-party command-line interface and Model Context
|
|
4
|
+
Protocol (MCP) server for the Khotan API. Both surfaces are thin adapters over
|
|
5
|
+
the public `/api/v1` HTTP API, driven by the shared capability catalog in
|
|
6
|
+
[`@khotan/core`](../khotan-core). They add nothing the API cannot do — they make
|
|
7
|
+
the same operations ergonomic for humans (CLI) and agents (MCP).
|
|
8
|
+
|
|
9
|
+
## Install & run
|
|
10
|
+
|
|
11
|
+
The published CLI is a self-contained Node.js binary (no Bun required). Install
|
|
12
|
+
or invoke it with standard npm tooling:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @khotan/cli --help # zero-install
|
|
16
|
+
npm i -g @khotan/cli # global `khotan` binary
|
|
17
|
+
# or: bun add -g @khotan/cli / pnpm add -g @khotan/cli
|
|
18
|
+
khotan --help
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
From this repository (contributors), run it from source on Bun:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bun run khotan -- --help # via the root script
|
|
25
|
+
bun packages/khotan-cli/src/bin/khotan.ts --help # directly
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Scaffold a workspace
|
|
29
|
+
|
|
30
|
+
`khotan init` writes Khotan agent integration into the current directory so your
|
|
31
|
+
own agents (Cursor, Devin, …) can drive setup. It is non-destructive and
|
|
32
|
+
re-runnable, and never writes secrets.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
khotan init # Cursor: .cursor/mcp.json + .cursor/rules/khotan.mdc
|
|
36
|
+
khotan init --client generic # root mcp.json + khotan-agents.md
|
|
37
|
+
khotan init --force # regenerate managed assets, overwriting edits
|
|
38
|
+
khotan init --json # machine-readable summary on stdout
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
It writes an MCP config wired to `khotan mcp serve` (credentials referenced by
|
|
42
|
+
`KHOTAN_API_URL` / `KHOTAN_API_KEY`, placeholders only) plus agent guidance. The
|
|
43
|
+
MCP config merges into an existing one, preserving any other servers. Authenticate
|
|
44
|
+
separately with `khotan auth set-key` or environment variables — never commit a key.
|
|
45
|
+
|
|
46
|
+
## Authentication & profiles
|
|
47
|
+
|
|
48
|
+
The CLI authenticates with an organization-scoped **API key**. Credentials are
|
|
49
|
+
stored in an owner-only file at `${XDG_CONFIG_HOME:-~/.config}/khotan/profiles.json`
|
|
50
|
+
(`0600`, in a `0700` directory). You can keep several named profiles.
|
|
51
|
+
|
|
52
|
+
### Store an existing API key
|
|
53
|
+
|
|
54
|
+
Create a key in the dashboard, then:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
khotan auth set-key --api-url https://app.example.com --api-key khk_live_...
|
|
58
|
+
khotan whoami # verifies the key via GET /api/v1/me
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Exchange credentials for a key
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
khotan login \
|
|
65
|
+
--api-url https://app.example.com \
|
|
66
|
+
--email you@example.com \
|
|
67
|
+
--password '••••••' \
|
|
68
|
+
--organization-id org_123
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`login` calls `POST /api/v1/api-keys`, stores the minted key once, and verifies
|
|
72
|
+
it. The key itself is never printed to stdout.
|
|
73
|
+
|
|
74
|
+
### Profiles
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
khotan auth set-key --profile staging --api-url https://staging.example.com --api-key ...
|
|
78
|
+
khotan auth use staging # switch the active profile
|
|
79
|
+
khotan auth list # list profiles (never prints keys)
|
|
80
|
+
khotan apps list --profile staging # one-off override
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Environment variables (CI & agents)
|
|
84
|
+
|
|
85
|
+
Environment variables take precedence over stored profile values, so no on-disk
|
|
86
|
+
state is needed in CI or sandboxes:
|
|
87
|
+
|
|
88
|
+
| Variable | Purpose |
|
|
89
|
+
| ----------------- | ----------------------------------------- |
|
|
90
|
+
| `KHOTAN_API_URL` | API origin (e.g. `https://app.example.com`) |
|
|
91
|
+
| `KHOTAN_API_KEY` | Organization-scoped API key |
|
|
92
|
+
| `KHOTAN_PROFILE` | Select a stored profile by name |
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
export KHOTAN_API_URL=https://app.example.com
|
|
96
|
+
export KHOTAN_API_KEY=khk_live_...
|
|
97
|
+
khotan apps list --json | jq '.apps[].id'
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Command surface
|
|
101
|
+
|
|
102
|
+
Commands are grouped by domain and derived from the capability catalog, so the
|
|
103
|
+
documented surface and the executable surface cannot drift. Run `khotan help` or
|
|
104
|
+
`khotan <command> --help` for details.
|
|
105
|
+
|
|
106
|
+
| Domain | Examples |
|
|
107
|
+
| --------- | -------- |
|
|
108
|
+
| Apps | `apps list`, `apps get <id>`, `apps create --name web --env KEY=VALUE`, `apps delete <id>`, `apps redeploy <id>` |
|
|
109
|
+
| App env | `apps env list <id>`, `apps env set <id> <KEY> --value V`, `apps env reveal <id> <KEY>`, `apps env unset <id> <KEY>`, `apps env bulk-set <id> --var A=1 --var B=2` |
|
|
110
|
+
| Pipelines | same shape as apps under `pipelines …` |
|
|
111
|
+
| Databases | `databases list`, `databases create --name db`, `databases connection <id>`, `databases rotate-credentials <id>`, `databases delete <id>` |
|
|
112
|
+
| Files | `files list`, `files get <id>`, `files upload <path>`, `files download <id> --output <path>`, `files update <id> --name new.txt`, `files delete <id>` |
|
|
113
|
+
| Folders | `folders list`, `folders create --name docs`, `folders rename <id> --name new`, `folders delete <id>` |
|
|
114
|
+
| Context | `context list`, `context get <slug>`, `context raw <slug>`, `context create --title T --kind knowledge --content '...'`, `context update <slug> --expected-revision 3 --content '...'`, `context delete <slug>` |
|
|
115
|
+
|
|
116
|
+
### Output modes
|
|
117
|
+
|
|
118
|
+
- Human-readable tables/detail by default.
|
|
119
|
+
- `--json` emits the API-shaped JSON to **stdout**.
|
|
120
|
+
- Results go to **stdout**; diagnostics, prompts, and progress go to **stderr**,
|
|
121
|
+
so `khotan ... --json | jq` stays clean.
|
|
122
|
+
|
|
123
|
+
### Safety
|
|
124
|
+
|
|
125
|
+
Each capability has a safety class (`read`, `write`, `destructive`, `secret`):
|
|
126
|
+
|
|
127
|
+
- **Destructive** commands (`delete`, `env unset`) prompt for confirmation in a
|
|
128
|
+
terminal and **refuse** in non-interactive sessions unless you pass `--yes`.
|
|
129
|
+
- **Secret** values (`env reveal`, `databases connection`,
|
|
130
|
+
`databases rotate-credentials`) are only available via explicit commands and
|
|
131
|
+
are never included in list/table output.
|
|
132
|
+
|
|
133
|
+
### File transfer
|
|
134
|
+
|
|
135
|
+
Uploads and downloads move bytes directly between your machine and object
|
|
136
|
+
storage using presigned URLs:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
khotan files upload ./report.pdf --folder-path /reports/2026
|
|
140
|
+
khotan files download file_123 --output ./report.pdf
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## MCP server
|
|
144
|
+
|
|
145
|
+
`khotan mcp serve` starts a local stdio MCP server that reuses the same profile,
|
|
146
|
+
environment overrides, API client, and catalog as the CLI. It advertises
|
|
147
|
+
**tools** (operations) and **resources** (URI-addressed read data) during
|
|
148
|
+
initialization.
|
|
149
|
+
|
|
150
|
+
- Operations become tools (e.g. `khotan_apps_create`). Destructive tools require
|
|
151
|
+
`{ "confirm": true }`; secret tools are labelled `[secret]`. The password-bearing
|
|
152
|
+
credential exchange is **not** exposed as a tool.
|
|
153
|
+
- Durable read data is exposed as resource templates: `khotan://apps/{appId}`,
|
|
154
|
+
`khotan://pipelines/{pipelineId}`, `khotan://databases/{databaseId}`,
|
|
155
|
+
`khotan://files/{fileId}`, `khotan://context/{slug}`.
|
|
156
|
+
- Secret-bearing values (env var values, connection URIs) are never resources.
|
|
157
|
+
- stdout carries JSON-RPC only; all logs go to stderr.
|
|
158
|
+
|
|
159
|
+
Example MCP client configuration:
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"mcpServers": {
|
|
164
|
+
"khotan": {
|
|
165
|
+
"command": "khotan",
|
|
166
|
+
"args": ["mcp", "serve"],
|
|
167
|
+
"env": {
|
|
168
|
+
"KHOTAN_API_URL": "https://app.example.com",
|
|
169
|
+
"KHOTAN_API_KEY": "khk_live_..."
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Catalog ↔ OpenAPI consistency
|
|
177
|
+
|
|
178
|
+
`@khotan/core` validates that every catalog operation maps to a real `/api/v1`
|
|
179
|
+
operation (method, path, operationId) using a snapshot of the OpenAPI document at
|
|
180
|
+
[`packages/khotan-core/src/catalog/__fixtures__/openapi.snapshot.json`](../khotan-core/src/catalog/__fixtures__/openapi.snapshot.json).
|
|
181
|
+
|
|
182
|
+
Regenerate the snapshot when the API surface changes:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
curl -s "$KHOTAN_API_URL/api/v1/openapi.json" \
|
|
186
|
+
| jq '{openapi, info, paths: (.paths | map_values(map_values({operationId})))}' \
|
|
187
|
+
> packages/khotan-core/src/catalog/__fixtures__/openapi.snapshot.json
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Development
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
bun run khotan:typecheck # typecheck both packages
|
|
194
|
+
bun run khotan:test # run all Khotan tests
|
|
195
|
+
bun run khotan -- <args> # run the CLI from source
|
|
196
|
+
bun run khotan:build # bundle the publishable dist/khotan.js (Node target)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The build bundles `@khotan/core` into a single Node-executable ESM file at
|
|
200
|
+
`packages/khotan-cli/dist/khotan.js`. `@khotan/core` stays a private workspace
|
|
201
|
+
package; only the bundled `@khotan/cli` is published, so the published manifest
|
|
202
|
+
has no `workspace:*` dependencies.
|
|
203
|
+
|
|
204
|
+
## Release
|
|
205
|
+
|
|
206
|
+
Versioning and publishing use [changesets](https://github.com/changesets/changesets):
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
bun run changeset # author a changeset describing the change
|
|
210
|
+
bun run release:version # apply changesets: bump version + update changelog
|
|
211
|
+
bun run release:publish # build, then publish @khotan/cli to npm (public)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
`prepublishOnly` rebuilds the bundle, so the published `bin` always matches
|
|
215
|
+
source. Publishing requires the `@khotan` npm org and a publish token.
|