@pokelo/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 ADDED
@@ -0,0 +1,121 @@
1
+ # pokelo
2
+
3
+ Official CLI for [Pokelo](https://pokelo.bearly.pro) — a thin client over the **public REST API** (`/v1`), designed for AI agents, skills, CI, and shell automation.
4
+
5
+ CLI does **not** call MCP. MCP remains a separate adapter for IDEs that support it.
6
+
7
+ | npm package | Binary |
8
+ |-------------|--------|
9
+ | `@pokelo/cli` | `pokelo` |
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install -g @pokelo/cli
15
+ pokelo --help
16
+ ```
17
+
18
+ From this monorepo (before publish / local dev):
19
+
20
+ ```bash
21
+ pnpm --filter @pokelo/cli exec pokelo --help
22
+ # or
23
+ node tools/pokelo-cli/bin/pokelo.mjs --help
24
+
25
+ cd tools/pokelo-cli && pnpm link --global
26
+ pokelo --help
27
+ ```
28
+
29
+ Requires Node.js ≥ 18 (uses global `fetch`).
30
+
31
+ Agent skill (Cursor): [`.cursor/skills/pokelo-cli/`](../../.cursor/skills/pokelo-cli/) — also shipped under `skill/` in the npm package.
32
+
33
+ ## Auth (agents)
34
+
35
+ Non-interactive (required for headless agents):
36
+
37
+ ```bash
38
+ pokelo auth login \
39
+ --url https://pokelo.example.com \
40
+ --token "$POKELO_TOKEN"
41
+ ```
42
+
43
+ Safer token input (not visible in `ps`):
44
+
45
+ ```bash
46
+ printenv POKELO_TOKEN | pokelo auth login --url https://pokelo.example.com --token-stdin
47
+ ```
48
+
49
+ Or skip the config file entirely:
50
+
51
+ ```bash
52
+ export POKELO_URL=https://pokelo.example.com
53
+ export POKELO_TOKEN=mcp_…
54
+ export POKELO_PROJECT=my-project-slug # optional default
55
+ pokelo projects list
56
+ ```
57
+
58
+ Interactive (TTY):
59
+
60
+ ```bash
61
+ pokelo auth login
62
+ ```
63
+
64
+ Check config (never prints the full token):
65
+
66
+ ```bash
67
+ pokelo auth status
68
+ ```
69
+
70
+ ### Config priority
71
+
72
+ ```text
73
+ CLI flags (--url, --token, --project)
74
+ > environment (POKELO_URL, POKELO_TOKEN, POKELO_PROJECT)
75
+ > ~/.config/pokelo/config.json
76
+ > legacy ~/.pokelo-cli.json (read-only migrate of url/token)
77
+ ```
78
+
79
+ URL may be `https://host` or `https://host/v1` — normalized to `…/v1`.
80
+
81
+ Create a Personal Access Token in the Pokelo UI (Settings → MCP / PAT). Prefix is `mcp_`; the same token works for REST and MCP.
82
+
83
+ ## Commands
84
+
85
+ ```bash
86
+ pokelo projects list
87
+ pokelo projects get <project-id-or-slug>
88
+
89
+ pokelo search "how does auth work" --project <ref> --limit 5
90
+
91
+ pokelo docs list --project <ref>
92
+ pokelo docs get <document-id-or-slug> --project <ref>
93
+ pokelo docs create --title "Note" --type Note --content "# Hi" --project <ref>
94
+ pokelo docs update <id> --content-file ./body.md --project <ref>
95
+
96
+ pokelo assets list --project <ref>
97
+ pokelo assets get <asset-id> --project <ref>
98
+ pokelo assets upload ./shot.png --project <ref> --description "screenshot"
99
+ pokelo assets download <asset-id> --out ./shot.png --project <ref>
100
+ pokelo assets update <asset-id> --name "renamed.png" --project <ref>
101
+ pokelo assets delete <asset-id> --project <ref>
102
+ ```
103
+
104
+ `assets upload` uses `POST …/assets/base64` for files ≤ 8 MiB; larger files use init → PUT → complete.
105
+
106
+ Stdout is always JSON. Errors go to stderr.
107
+
108
+ Exit codes: `0` ok, `1` usage/config, `2` API/network.
109
+
110
+ ## Agent happy path
111
+
112
+ ```bash
113
+ pokelo auth login --url https://pokelo.example.com --token "$TOKEN"
114
+ pokelo search "jak działa auth" --project khirby --limit 5
115
+ pokelo docs get <document-id> --project khirby
116
+ pokelo assets upload ./diagram.png --project khirby
117
+ ```
118
+
119
+ ## Spec
120
+
121
+ Product SSOT: *Pokelo CLI — public API client for agents (Single Source of Truth)* in the Pokelo project.
package/bin/pokelo.mjs ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import { main } from '../src/cli.mjs';
3
+
4
+ main(process.argv.slice(2)).catch((err) => {
5
+ const msg = err instanceof Error ? err.message : String(err);
6
+ process.stderr.write(`Error: ${msg}\n`);
7
+ process.exit(1);
8
+ });
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@pokelo/cli",
3
+ "version": "0.1.0",
4
+ "description": "Official Pokelo CLI — public REST client for agents and developers",
5
+ "type": "module",
6
+ "bin": {
7
+ "pokelo": "./bin/pokelo.mjs"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "src",
12
+ "README.md",
13
+ "skill"
14
+ ],
15
+ "engines": {
16
+ "node": ">=18"
17
+ },
18
+ "keywords": [
19
+ "pokelo",
20
+ "knowledge-base",
21
+ "cli",
22
+ "rag",
23
+ "agents"
24
+ ],
25
+ "license": "MIT",
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "scripts": {
30
+ "start": "node ./bin/pokelo.mjs",
31
+ "pokelo": "node ./bin/pokelo.mjs"
32
+ }
33
+ }
package/skill/SKILL.md ADDED
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: pokelo-cli
3
+ description: >-
4
+ Uses the Pokelo CLI (`pokelo` binary from npm package `@pokelo/cli`) over the
5
+ public REST API for auth, projects, semantic search, documents, and assets.
6
+ Use when working with Pokelo knowledge bases from the shell, provisioning
7
+ agents without MCP, or when the user mentions pokelo CLI, @pokelo/cli, or
8
+ PAT-based Pokelo access.
9
+ disable-model-invocation: false
10
+ ---
11
+
12
+ # Pokelo CLI
13
+
14
+ Official shell client for Pokelo. Speaks **public REST `/v1` + Personal Access Token** — never MCP.
15
+
16
+ | Concept | Value |
17
+ |---------|--------|
18
+ | npm package | `@pokelo/cli` |
19
+ | Command on PATH | `pokelo` |
20
+ | Config | flags > `POKELO_*` env > `~/.config/pokelo/config.json` |
21
+
22
+ ## 1. Ensure installed (idempotent)
23
+
24
+ Run before the first `pokelo` call in a session:
25
+
26
+ ```bash
27
+ # From package install or checkout:
28
+ bash skill/scripts/ensure-pokelo.sh
29
+ # Or: command -v pokelo || npm install -g @pokelo/cli
30
+ ```
31
+
32
+ Or manually:
33
+
34
+ 1. If `command -v pokelo` succeeds → **do not install**; use it.
35
+ 2. Else: `npm install -g @pokelo/cli` (exposes the `pokelo` binary).
36
+ 3. In this monorepo only, if npm package is unpublished: use
37
+ `node tools/pokelo-cli/bin/pokelo.mjs` or symlink it to `~/.local/bin/pokelo`.
38
+
39
+ Never reinstall when `pokelo` is already available.
40
+
41
+ ## 2. Auth
42
+
43
+ Prefer env in CI / ephemeral sandboxes (no disk write):
44
+
45
+ ```bash
46
+ export POKELO_URL=https://<host> # or http://localhost:3001 for local API
47
+ export POKELO_TOKEN=mcp_… # Personal Access Token
48
+ export POKELO_PROJECT=<slug-or-uuid> # optional default
49
+ ```
50
+
51
+ Or persist config (agents, headless):
52
+
53
+ ```bash
54
+ pokelo auth login --url "$POKELO_URL" --token-stdin <<< "$POKELO_TOKEN"
55
+ # or: pokelo auth login --url … --token "$TOKEN"
56
+ pokelo auth status # never prints the full token
57
+ ```
58
+
59
+ Local Vite (`:5173`) does **not** proxy `/v1` — point `POKELO_URL` at the API (`:3001`), not the frontend.
60
+
61
+ ## 3. Commands (stdout = JSON)
62
+
63
+ ```bash
64
+ pokelo projects list
65
+ pokelo projects get <project-ref>
66
+
67
+ pokelo search "<query>" --project <ref> [--limit n]
68
+
69
+ pokelo docs list --project <ref>
70
+ pokelo docs get <doc-ref> --project <ref>
71
+ pokelo docs create --title "…" [--type] [--content|--content-file] [--parent] --project <ref>
72
+ pokelo docs update <doc-ref> [--title] [--content|--content-file] --project <ref>
73
+
74
+ pokelo assets list --project <ref>
75
+ pokelo assets get <asset-id> --project <ref>
76
+ pokelo assets upload <file> [--name] [--mime] [--visibility] [--document] [--description] --project <ref>
77
+ pokelo assets download <asset-id> --out <path> --project <ref>
78
+ pokelo assets update <asset-id> [--name] [--description] … --project <ref>
79
+ pokelo assets delete <asset-id> --project <ref>
80
+ ```
81
+
82
+ Exit codes: `0` ok, `1` usage/config, `2` API/network. Errors on stderr.
83
+
84
+ `assets upload`: ≤ 8 MiB → `POST …/base64`; larger → init → PUT → complete.
85
+
86
+ ## 4. Agent workflow
87
+
88
+ 1. Ensure `pokelo` is installed (step 1).
89
+ 2. Confirm auth (`auth status` or env vars).
90
+ 3. Resolve project (`projects list` / known slug).
91
+ 4. `search` → if snippets are thin, `docs get`.
92
+ 5. Write only when asked (`docs create/update`, `assets upload`).
93
+ 6. Do **not** echo tokens; do **not** call MCP from this skill.
94
+
95
+ ## 5. Extra detail
96
+
97
+ - Command cheat sheet: [reference.md](reference.md)
98
+ - This directory is the copy shipped inside the `@pokelo/cli` npm package (`skill/`).
@@ -0,0 +1,59 @@
1
+ # Pokelo CLI reference
2
+
3
+ ## Package vs binary
4
+
5
+ ```text
6
+ npm i -g @pokelo/cli → installs package @pokelo/cli
7
+ → binary name: pokelo
8
+ ```
9
+
10
+ ## Config priority
11
+
12
+ ```text
13
+ --url / --token / --project
14
+ > POKELO_URL / POKELO_TOKEN / POKELO_PROJECT
15
+ > ~/.config/pokelo/config.json
16
+ > legacy ~/.pokelo-cli.json (read for migration on login)
17
+ ```
18
+
19
+ URL forms `https://host` and `https://host/v1` both normalize to `…/v1`.
20
+
21
+ ## Auth
22
+
23
+ | Command | Notes |
24
+ |---------|--------|
25
+ | `pokelo auth login --url U --token T` | Persist config; never echo T |
26
+ | `pokelo auth login --url U --token-stdin` | Token from stdin |
27
+ | `pokelo auth login` | Interactive TTY only |
28
+ | `pokelo auth status` | Masked preview `mcp_…****` |
29
+
30
+ ## Projects / search / docs
31
+
32
+ | Command | REST |
33
+ |---------|------|
34
+ | `projects list` | `GET /projects` |
35
+ | `projects get <ref>` | `GET /projects/:id` |
36
+ | `search "q" -p <ref> -l n` | `POST /projects/:id/documents/search` |
37
+ | `docs list -p <ref>` | `GET /projects/:id/documents` |
38
+ | `docs get <ref> -p <ref>` | `GET /projects/:id/documents/:id` |
39
+ | `docs create --title …` | `POST /projects/:id/documents` |
40
+ | `docs update <ref> …` | `PATCH /projects/:id/documents/:id` |
41
+
42
+ ## Assets
43
+
44
+ | Command | REST |
45
+ |---------|------|
46
+ | `assets list` | `GET /projects/:id/assets` |
47
+ | `assets get <id>` | `GET /projects/:id/assets/:id` |
48
+ | `assets upload <file>` | `POST …/base64` or uploads+complete |
49
+ | `assets download <id> --out F` | get + downloadUrl / content redirect |
50
+ | `assets update <id>` | `PATCH /projects/:id/assets/:id` |
51
+ | `assets delete <id>` | `DELETE /projects/:id/assets/:id` |
52
+
53
+ Filters for list: `--type`, `--source`, `--visibility`, `--document`, `--page`, `--limit`.
54
+
55
+ ## Safety
56
+
57
+ - Never print the full PAT.
58
+ - Prefer `--token-stdin` or env over `--token` when possible.
59
+ - Do not commit `~/.config/pokelo/config.json`.
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env bash
2
+ # Ensure the `pokelo` binary is on PATH. No-op if already available.
3
+ # npm package name: @pokelo/cli → CLI command: pokelo
4
+ set -euo pipefail
5
+
6
+ if command -v pokelo >/dev/null 2>&1; then
7
+ echo "pokelo already available: $(command -v pokelo)"
8
+ exit 0
9
+ fi
10
+
11
+ if command -v npm >/dev/null 2>&1; then
12
+ echo "Installing @pokelo/cli (provides \`pokelo\` binary)…"
13
+ if npm install -g @pokelo/cli; then
14
+ if command -v pokelo >/dev/null 2>&1; then
15
+ echo "Installed: $(command -v pokelo)"
16
+ exit 0
17
+ fi
18
+ echo "Package installed but \`pokelo\` not on PATH; check npm global bin." >&2
19
+ else
20
+ echo "npm install -g @pokelo/cli failed (package may be unpublished)." >&2
21
+ fi
22
+ fi
23
+
24
+ # Monorepo / package-local fallbacks
25
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
26
+ CANDIDATES=(
27
+ # skill shipped inside tools/pokelo-cli/skill/scripts
28
+ "$SCRIPT_DIR/../../bin/pokelo.mjs"
29
+ # .cursor/skills/pokelo-cli/scripts → repo tools/pokelo-cli
30
+ "$SCRIPT_DIR/../../../tools/pokelo-cli/bin/pokelo.mjs"
31
+ )
32
+
33
+ mkdir -p "${HOME}/.local/bin"
34
+ for candidate in "${CANDIDATES[@]}"; do
35
+ if [[ -f "$candidate" ]]; then
36
+ ln -sfn "$candidate" "${HOME}/.local/bin/pokelo"
37
+ export PATH="${HOME}/.local/bin:${PATH}"
38
+ if command -v pokelo >/dev/null 2>&1; then
39
+ echo "Linked local CLI: $candidate → ~/.local/bin/pokelo"
40
+ exit 0
41
+ fi
42
+ fi
43
+ done
44
+
45
+ echo "Error: could not locate or install pokelo." >&2
46
+ echo "Fix: npm install -g @pokelo/cli OR symlink tools/pokelo-cli/bin/pokelo.mjs" >&2
47
+ exit 1
package/src/cli.mjs ADDED
@@ -0,0 +1,256 @@
1
+ import { fail } from './exit.mjs';
2
+ import { runAssets } from './commands/assets.mjs';
3
+ import { runAuth } from './commands/auth.mjs';
4
+ import { runDocs } from './commands/docs.mjs';
5
+ import { runProjects } from './commands/projects.mjs';
6
+ import { runSearch } from './commands/search.mjs';
7
+
8
+ function printHelp() {
9
+ process.stdout.write(
10
+ `pokelo — Pokelo public API CLI for agents and developers
11
+
12
+ Usage:
13
+ pokelo auth login --url <url> --token <token>
14
+ pokelo auth login --url <url> --token-stdin
15
+ pokelo auth login
16
+ pokelo auth status
17
+
18
+ pokelo projects list
19
+ pokelo projects get <project-id-or-slug>
20
+
21
+ pokelo search "<query>" [--project <ref>] [--limit <n>]
22
+
23
+ pokelo docs list [--project <ref>]
24
+ pokelo docs get <document-id-or-slug> [--project <ref>]
25
+ pokelo docs create --title <t> [--type] [--content|--content-file] [--parent] [--project]
26
+ pokelo docs update <document-id-or-slug> [options]
27
+
28
+ pokelo assets list [--project] [--type] [--visibility] [--document]
29
+ pokelo assets get <asset-id> [--project]
30
+ pokelo assets upload <file> [--name] [--mime] [--visibility] [--document] [--description]
31
+ pokelo assets download <asset-id> --out <path> [--project]
32
+ pokelo assets update <asset-id> [--name] [--description] [--visibility] [--document]
33
+ pokelo assets delete <asset-id> [--project]
34
+
35
+ Global options:
36
+ --project, -p <ref> Project UUID or slug (or POKELO_PROJECT / config default)
37
+ --url <url> Instance URL (overrides env/config)
38
+ --token <token> Personal Access Token (overrides env/config; prefer env/--token-stdin)
39
+ --json Accepted for compatibility (stdout is always JSON)
40
+ --help, -h Show help
41
+
42
+ Config (priority: flags > env > file):
43
+ POKELO_URL, POKELO_TOKEN, POKELO_PROJECT
44
+ ~/.config/pokelo/config.json
45
+
46
+ Exit codes: 0 ok, 1 usage/config, 2 API/network error
47
+ `,
48
+ );
49
+ }
50
+
51
+ /**
52
+ * Minimal argv parser: supports long flags, -p/-l/-h, and --flag=value.
53
+ * @param {string[]} argv
54
+ */
55
+ export function parseArgs(argv) {
56
+ /** @type {Record<string, unknown>} */
57
+ const flags = {};
58
+ const positional = [];
59
+
60
+ for (let i = 0; i < argv.length; i++) {
61
+ const arg = argv[i];
62
+ if (arg === '--') {
63
+ positional.push(...argv.slice(i + 1));
64
+ break;
65
+ }
66
+ if (arg === '--help' || arg === '-h') {
67
+ flags.help = true;
68
+ continue;
69
+ }
70
+ if (arg === '--json') {
71
+ flags.json = true;
72
+ continue;
73
+ }
74
+ if (arg === '--token-stdin') {
75
+ flags.tokenStdin = true;
76
+ continue;
77
+ }
78
+ if (arg === '--tree') {
79
+ flags.tree = true;
80
+ continue;
81
+ }
82
+
83
+ const eq = arg.match(/^--([a-zA-Z0-9-]+)=(.*)$/);
84
+ if (eq) {
85
+ setFlag(flags, eq[1], eq[2]);
86
+ continue;
87
+ }
88
+
89
+ if (arg === '--project' || arg === '-p') {
90
+ flags.project = needValue(argv, ++i, arg);
91
+ continue;
92
+ }
93
+ if (arg === '--limit' || arg === '-l') {
94
+ flags.limit = parseInt(needValue(argv, ++i, arg), 10);
95
+ continue;
96
+ }
97
+ if (arg === '--page') {
98
+ flags.page = parseInt(needValue(argv, ++i, arg), 10);
99
+ continue;
100
+ }
101
+ if (arg === '--url') {
102
+ flags.url = needValue(argv, ++i, arg);
103
+ continue;
104
+ }
105
+ if (arg === '--token') {
106
+ flags.token = needValue(argv, ++i, arg);
107
+ continue;
108
+ }
109
+ if (arg === '--title') {
110
+ flags.title = needValue(argv, ++i, arg);
111
+ continue;
112
+ }
113
+ if (arg === '--type') {
114
+ flags.type = needValue(argv, ++i, arg);
115
+ continue;
116
+ }
117
+ if (arg === '--content') {
118
+ flags.content = needValue(argv, ++i, arg);
119
+ continue;
120
+ }
121
+ if (arg === '--content-file') {
122
+ flags.contentFile = needValue(argv, ++i, arg);
123
+ continue;
124
+ }
125
+ if (arg === '--parent') {
126
+ flags.parent = needValue(argv, ++i, arg);
127
+ continue;
128
+ }
129
+ if (arg === '--status') {
130
+ flags.status = needValue(argv, ++i, arg);
131
+ continue;
132
+ }
133
+ if (arg === '--search' || arg === '-q') {
134
+ flags.search = needValue(argv, ++i, arg);
135
+ continue;
136
+ }
137
+ if (arg === '--name') {
138
+ flags.name = needValue(argv, ++i, arg);
139
+ continue;
140
+ }
141
+ if (arg === '--mime' || arg === '--mime-type') {
142
+ flags.mime = needValue(argv, ++i, arg);
143
+ continue;
144
+ }
145
+ if (arg === '--visibility') {
146
+ flags.visibility = needValue(argv, ++i, arg);
147
+ continue;
148
+ }
149
+ if (arg === '--document' || arg === '--document-id') {
150
+ flags.document = needValue(argv, ++i, arg);
151
+ continue;
152
+ }
153
+ if (arg === '--description') {
154
+ flags.description = needValue(argv, ++i, arg);
155
+ continue;
156
+ }
157
+ if (arg === '--source') {
158
+ flags.source = needValue(argv, ++i, arg);
159
+ continue;
160
+ }
161
+ if (arg === '--out') {
162
+ flags.out = needValue(argv, ++i, arg);
163
+ continue;
164
+ }
165
+
166
+ if (arg.startsWith('-')) {
167
+ fail(`unknown option: ${arg}`);
168
+ }
169
+ positional.push(arg);
170
+ }
171
+
172
+ return { flags, positional };
173
+ }
174
+
175
+ function needValue(argv, index, flag) {
176
+ if (index >= argv.length) fail(`missing value for ${flag}`);
177
+ return argv[index];
178
+ }
179
+
180
+ function setFlag(flags, name, value) {
181
+ const map = {
182
+ project: 'project',
183
+ limit: 'limit',
184
+ page: 'page',
185
+ url: 'url',
186
+ token: 'token',
187
+ title: 'title',
188
+ type: 'type',
189
+ content: 'content',
190
+ 'content-file': 'contentFile',
191
+ parent: 'parent',
192
+ status: 'status',
193
+ search: 'search',
194
+ name: 'name',
195
+ mime: 'mime',
196
+ 'mime-type': 'mime',
197
+ visibility: 'visibility',
198
+ document: 'document',
199
+ 'document-id': 'document',
200
+ description: 'description',
201
+ source: 'source',
202
+ out: 'out',
203
+ };
204
+ const key = map[name];
205
+ if (!key) fail(`unknown option: --${name}`);
206
+ if (key === 'limit' || key === 'page') {
207
+ flags[key] = parseInt(value, 10);
208
+ } else {
209
+ flags[key] = value;
210
+ }
211
+ }
212
+
213
+ /**
214
+ * @param {string[]} argv
215
+ */
216
+ export async function main(argv) {
217
+ const { flags, positional } = parseArgs(argv);
218
+
219
+ if (flags.help || positional.length === 0) {
220
+ printHelp();
221
+ process.exit(0);
222
+ }
223
+
224
+ const cmd = positional[0];
225
+ const rest = positional.slice(1);
226
+
227
+ switch (cmd) {
228
+ case 'help':
229
+ printHelp();
230
+ break;
231
+ case 'auth':
232
+ await runAuth(rest, flags);
233
+ break;
234
+ case 'projects':
235
+ await runProjects(rest, flags);
236
+ break;
237
+ case 'search':
238
+ await runSearch(rest, flags);
239
+ break;
240
+ case 'docs':
241
+ await runDocs(rest, flags);
242
+ break;
243
+ case 'assets':
244
+ await runAssets(rest, flags);
245
+ break;
246
+ // Back-compat aliases from MCP PoC
247
+ case 'list':
248
+ await runDocs(['list', ...rest], flags);
249
+ break;
250
+ case 'get':
251
+ await runDocs(['get', ...rest], flags);
252
+ break;
253
+ default:
254
+ fail(`unknown command: ${cmd}\nRun: pokelo --help`);
255
+ }
256
+ }