octarin-cli 0.2.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,202 @@
1
+ # octarin-cli
2
+
3
+ The per-user CLI for [Octarin](https://octarin.ai) AI-usage analytics (binary:
4
+ `octarin`). One
5
+ centralized, `npx`-based install path for AI-coding capture, plus a scoped,
6
+ **read-only SQL** layer over your own data.
7
+
8
+ ```bash
9
+ npx octarin-cli@latest init <oct_key> # personal capture install (this machine)
10
+ npx octarin-cli@latest init-repo <org/project> # team install (commits config, opens a PR)
11
+ npx octarin-cli@latest login # authorize a machine (team installs)
12
+ npx octarin-cli@latest sql query "<SELECT ...>" # read-only SQL over your own data
13
+ ```
14
+
15
+ No `curl | bash`, no sha256-verify dance — version pinning (`@latest` /
16
+ `@x.y.z`) and npm provenance are the integrity story. Requires Node.js >= 18
17
+ (uses the built-in `fetch`); `init`'s history import additionally uses the
18
+ system `python3`.
19
+
20
+ ## Capture install
21
+
22
+ `init` and `init-repo` install the Octarin capture hooks for Claude Code,
23
+ Cursor, and Codex entirely from the package's **bundled, version-pinned assets**
24
+ — nothing is fetched at install time.
25
+
26
+ ### `octarin init <oct_key>`
27
+
28
+ Personal, per-machine install. Writes your write-only ingest key to
29
+ `~/.octarin/octarin.env` (mode 600, never git), copies the hook files into each
30
+ detected tool's config dir, **merges** the hook registration into that tool's
31
+ settings (no hand-editing), and imports your existing history.
32
+
33
+ ```bash
34
+ npx octarin-cli@latest init oct_xxx # all detected tools, last 90 days
35
+ npx octarin-cli@latest init oct_xxx --backfill off # skip the history import
36
+ npx octarin-cli@latest init oct_xxx --tools cursor # only Cursor
37
+ ```
38
+
39
+ ### `octarin init-repo <org/project>`
40
+
41
+ Team install. Run at a repo root: commits shared hook config + the public
42
+ project slug to `.claude/.cursor/.codex` + `.octarin/project` (no key, ever),
43
+ and opens a PR. Each teammate then runs `octarin login` once.
44
+
45
+ ### `octarin login`
46
+
47
+ Device-code browser flow that mints a per-user ingest key into
48
+ `~/.octarin/octarin.env`. Reads the project from `.octarin/project` (or
49
+ `--project <org/project>`).
50
+
51
+ ## SQL
52
+
53
+ A scoped, **read-only SQL** layer over your own data. Run SELECTs against your
54
+ traces, spans, sessions, and events — or pipe machine-readable JSON into `jq`
55
+ and your agents.
56
+
57
+ The CLI holds **only your API key**, never database credentials. All query
58
+ safety (single read-only SELECT, table allowlist, no `system.*`) and tenant
59
+ scoping (every result is filtered to your organization's projects) are enforced
60
+ **server-side** by the Octarin API. A query can only ever see your own data.
61
+
62
+ ## Auth (SQL)
63
+
64
+ The `sql` commands authenticate with a read-only **query key** (`oct_...`) — a
65
+ key that can run scoped SELECTs over your org's data but can NEVER ingest. This
66
+ is a *distinct* key from the write-only **ingest key** used for capture (the one
67
+ `octarin init` writes to `~/.octarin/octarin.env`); an ingest key is rejected
68
+ here with a `403`.
69
+
70
+ Mint a query key in the dashboard under **Settings → CLI / Query keys** (it is
71
+ shown exactly once — copy it then). Then either:
72
+
73
+ ```bash
74
+ export OCTARIN_API_KEY=oct_xxxxxxxxxxxxxxxxxxxx
75
+ octarin sql query "SELECT count() FROM spans"
76
+ ```
77
+
78
+ or pass it per-command:
79
+
80
+ ```bash
81
+ octarin sql query "SELECT count() FROM spans" --api-key oct_xxxx
82
+ ```
83
+
84
+ ## Commands
85
+
86
+ ### `octarin sql schema`
87
+
88
+ List the tables you can query and their columns.
89
+
90
+ ```bash
91
+ octarin sql schema # human-readable tables
92
+ octarin sql schema --json # machine-readable JSON
93
+ ```
94
+
95
+ Queryable tables: `spans`, `traces`, `session_insights`, `span_vectors`,
96
+ `events` (all in the `octarin` database; you may write them qualified as
97
+ `octarin.spans` or bare as `spans`).
98
+
99
+ ### `octarin sql query "<SELECT ...>"`
100
+
101
+ Run a single **read-only** SELECT. Default output is a readable ASCII table;
102
+ `--json` emits structured JSON on stdout.
103
+
104
+ ```bash
105
+ # Top models by token-bearing spans
106
+ octarin sql query "SELECT model, count() AS c FROM spans GROUP BY model ORDER BY c DESC"
107
+
108
+ # Cap the rows
109
+ octarin sql query "SELECT * FROM traces ORDER BY start_time DESC" --limit 20
110
+
111
+ # JSON for piping
112
+ octarin sql query "SELECT model, count() AS c FROM spans GROUP BY model" --json
113
+ ```
114
+
115
+ #### Pipe into `jq`
116
+
117
+ Structured output goes to **stdout**; all progress/log/error messages go to
118
+ **stderr**, so JSON pipes cleanly:
119
+
120
+ ```bash
121
+ octarin sql query "SELECT model, count() AS c FROM spans GROUP BY model" --json \
122
+ | jq '.rows[] | {model: .[0], spans: .[1]}'
123
+ ```
124
+
125
+ The response shape is:
126
+
127
+ ```json
128
+ {
129
+ "columns": ["model", "c"],
130
+ "rows": [["claude-opus-4-8", 7594], ["claude-sonnet-4-6", 6188]],
131
+ "row_count": 2
132
+ }
133
+ ```
134
+
135
+ ## Options
136
+
137
+ | Option | Env var | Default | Description |
138
+ |--------|---------|---------|-------------|
139
+ | `--api-key <key>` | `OCTARIN_API_KEY` | — | Octarin **query** key (`oct_...`). Required. |
140
+ | `--base-url <url>` | `OCTARIN_BASE_URL` | `https://api.octarin.ai` | API base URL. |
141
+ | `--port <port>` | — | — | Override the port (self-host parity). |
142
+ | `--limit <N>` | — | server cap | Max rows (server caps at 10000). |
143
+ | `--json` | — | off | Emit JSON on stdout instead of a table. |
144
+ | `-h`, `--help` | — | — | Show help (on every command). |
145
+ | `--version` | — | — | Print the CLI version. |
146
+
147
+ Self-host example:
148
+
149
+ ```bash
150
+ octarin sql schema --base-url http://localhost:8000
151
+ octarin sql schema --port 8000 # shorthand for http://localhost:8000
152
+ ```
153
+
154
+ ## Agent-friendly I/O
155
+
156
+ - **stdout** — only the structured result (the table, or `--json` JSON).
157
+ - **stderr** — all human/progress/error messages.
158
+ - **exit code** — `0` on success, non-zero on failure (`2` for usage/auth
159
+ errors, `1` for request/execution errors).
160
+
161
+ This makes the CLI safe to drive from scripts and LLM agents: capture stdout,
162
+ check the exit code, read stderr for diagnostics.
163
+
164
+ ## What you can and can't query
165
+
166
+ You can run exactly **one read-only `SELECT`** (a `WITH ... SELECT` CTE is fine)
167
+ over the allowlisted `octarin.*` tables. The server rejects, with a clear `400`:
168
+
169
+ - anything that isn't a single SELECT (no `INSERT/UPDATE/DELETE/ALTER/DROP/...`),
170
+ - multiple `;`-separated statements,
171
+ - references to other databases or tables — especially `system.*` and
172
+ `information_schema.*`,
173
+ - table functions (`url`, `file`, `remote`, `s3`, `numbers`, ...).
174
+
175
+ Every result is automatically scoped to your organization's projects — you
176
+ never need to (and cannot) widen it.
177
+
178
+ ## Development
179
+
180
+ ```bash
181
+ npm install
182
+ npm run build # tsc -> dist/
183
+ node dist/index.js sql schema
184
+ # or run the local checkout via npx:
185
+ npx . sql schema
186
+ ```
187
+
188
+ ## Publishing (maintainers)
189
+
190
+ This package is publish-ready but not yet published. To release:
191
+
192
+ ```bash
193
+ npm version <patch|minor|major>
194
+ npm publish # runs prepublishOnly -> npm run build
195
+ ```
196
+
197
+ (`files` ships `dist/`, the bundled `assets/`, and this README; `prepublishOnly`
198
+ rebuilds, which re-stages `assets/` from `../clients` via `copy-assets`.)
199
+
200
+ ## License
201
+
202
+ MIT