@oriva/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,117 @@
1
+ # @oriva/cli
2
+
3
+ Spec-driven CLI for the Oriva public API. Every endpoint in the OpenAPI spec becomes an `oriva <command>` subcommand — zero CLI code changes when new endpoints ship.
4
+
5
+ For shell scripts, Claude Code agents, ops one-offs, and humans who'd rather not write Node TypeScript to hit the API.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm i -g @oriva/cli
11
+ # or
12
+ npx @oriva/cli <command>
13
+ ```
14
+
15
+ Requires Node ≥ 18.
16
+
17
+ ## Auth
18
+
19
+ The CLI looks for an API key in this order (highest precedence first):
20
+
21
+ 1. `--api-key=<value>` flag
22
+ 2. `ORIVA_API_KEY` env var
23
+ 3. `~/.config/oriva/config.json` → `profiles[<active>].apiKey`
24
+
25
+ For most uses, export the env var:
26
+
27
+ ```sh
28
+ export ORIVA_API_KEY=oriva_pk_live_…
29
+ oriva getCurrentUser
30
+ ```
31
+
32
+ For multi-environment work, write `~/.config/oriva/config.json`:
33
+
34
+ ```json
35
+ {
36
+ "activeProfile": "default",
37
+ "profiles": {
38
+ "default": { "apiKey": "oriva_pk_live_…" },
39
+ "staging": {
40
+ "apiKey": "oriva_pk_test_…",
41
+ "baseUrl": "https://staging.api.oriva.io"
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ Switch with `--profile=staging` or `ORIVA_PROFILE=staging`.
48
+
49
+ ## Usage
50
+
51
+ ```sh
52
+ oriva --help # List all commands (grouped by OpenAPI tag)
53
+ oriva <command> --help # Per-command help: required + optional params
54
+ oriva --version # CLI + spec version
55
+
56
+ oriva getCurrentUser # GET — pretty JSON
57
+ oriva getCurrentUser --json # Structured envelope { ok, status, data, error, request_id }
58
+ oriva listProfiles --json | jq .
59
+
60
+ # Request bodies — three input modes
61
+ oriva createDeveloperApp --body='{"name":"my app"}'
62
+ oriva createDeveloperApp --body=@app.json
63
+ echo '{"name":"my app"}' | oriva createDeveloperApp --body=-
64
+ ```
65
+
66
+ ## Global flags
67
+
68
+ | Flag | Purpose |
69
+ | -------------------- | -------------------------------------------------------------------- |
70
+ | `--api-key=<value>` | One-off override of `ORIVA_API_KEY` |
71
+ | `--profile=<name>` | Use a different config-file profile |
72
+ | `--base-url=<url>` | Override the API base URL |
73
+ | `--spec=<url\|path>` | Use a different OpenAPI spec (default: bundled snapshot) |
74
+ | `--json` | Emit `{ ok, status, data, error, request_id }` envelope (for agents) |
75
+ | `--raw` | Print body unchanged — no JSON pretty-print |
76
+ | `--show-status` | Print `HTTP <code> (request_id=<id>)` to stderr |
77
+ | `--quiet` | Suppress stderr progress lines |
78
+ | `--help`, `-h` | Show this help (or per-command) |
79
+ | `--version`, `-V` | Print CLI + spec version |
80
+
81
+ ## Exit codes
82
+
83
+ | Code | Meaning |
84
+ | ---- | --------------------------- |
85
+ | 0 | HTTP 2xx |
86
+ | 1 | HTTP 4xx (client error) |
87
+ | 2 | HTTP 5xx or network failure |
88
+ | 3 | Usage/parse error |
89
+ | 4 | Spec load failure |
90
+
91
+ ## Error envelope (with `--json`)
92
+
93
+ ```json
94
+ {
95
+ "ok": false,
96
+ "status": 401,
97
+ "data": null,
98
+ "error": { "code": "unauthenticated", "message": "..." },
99
+ "request_id": "req_ABC"
100
+ }
101
+ ```
102
+
103
+ Always parseable — same shape regardless of success/failure. Network errors return `status: 0`.
104
+
105
+ ## CLI vs SDK
106
+
107
+ | Use case | Tool |
108
+ | ---------------------------------- | ----------------------------------------------------------------------------------------- |
109
+ | Node/TypeScript application code | [`@oriva/sdk`](https://www.npmjs.com/package/@oriva/sdk) — typed client, IDE autocomplete |
110
+ | Shell scripts, CI/CD, ops one-offs | `@oriva/cli` — no Node project needed |
111
+ | Claude Code agents, MCP servers | Either — CLI for general invocation, SDK for typed Node code |
112
+
113
+ The CLI bundles its own OpenAPI snapshot so it works offline with sub-second cold start. The `peerDependency` on `@oriva/sdk` is optional and only declared for version-pinning hints — the CLI doesn't import the SDK at runtime.
114
+
115
+ ## License
116
+
117
+ MIT
package/bin/oriva.js ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `oriva` CLI bin shim.
4
+ *
5
+ * The compiled entry lives in dist/cli.js (ESM). We dynamic-import it so
6
+ * the shim itself stays valid CJS-safe Node script — works whether the
7
+ * installed Node uses ESM or CJS resolution.
8
+ */
9
+ import('../dist/cli.js')
10
+ .then(({ run }) => run())
11
+ .then((code) => process.exit(code))
12
+ .catch((err) => {
13
+ process.stderr.write(`[oriva] fatal: ${err && err.message ? err.message : err}\n`);
14
+ process.exit(2);
15
+ });
package/dist/auth.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ export interface ResolvedAuth {
2
+ apiKey?: string;
3
+ baseUrl?: string;
4
+ /** Provenance for diagnostics — "flag" | "env" | "config:<profile>" | "none". */
5
+ source: string;
6
+ }
7
+ export interface ConfigProfile {
8
+ apiKey?: string;
9
+ baseUrl?: string;
10
+ }
11
+ export interface ConfigFile {
12
+ activeProfile?: string;
13
+ profiles?: Record<string, ConfigProfile>;
14
+ }
15
+ export interface ResolveAuthOptions {
16
+ flagApiKey?: string;
17
+ envApiKey?: string;
18
+ profile?: string;
19
+ /** Custom config path for tests. Defaults to ~/.config/oriva/config.json. */
20
+ configPath?: string;
21
+ }
22
+ export declare function resolveAuth(opts: ResolveAuthOptions): Promise<ResolvedAuth>;
23
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAqBjF"}
package/dist/auth.js ADDED
@@ -0,0 +1,49 @@
1
+ /**
2
+ * API-key resolution for the `oriva` CLI.
3
+ *
4
+ * Precedence (highest wins):
5
+ * 1. --api-key=<key> (flag)
6
+ * 2. ORIVA_API_KEY env var
7
+ * 3. ~/.config/oriva/config.json
8
+ * - if --profile=<name> set: profiles[<name>].apiKey
9
+ * - else: profiles[activeProfile].apiKey
10
+ * - else: profiles.default.apiKey
11
+ * 4. undefined (caller decides whether to warn)
12
+ *
13
+ * Config-file schema:
14
+ * {
15
+ * "activeProfile": "staging",
16
+ * "profiles": {
17
+ * "default": { "apiKey": "oriva_pk_live_..." },
18
+ * "staging": { "apiKey": "oriva_pk_test_...", "baseUrl": "https://staging.api.oriva.io" }
19
+ * }
20
+ * }
21
+ *
22
+ * `baseUrl` can also live on a profile and is returned alongside the key.
23
+ */
24
+ import { readFile } from 'node:fs/promises';
25
+ import { homedir } from 'node:os';
26
+ import { resolve } from 'node:path';
27
+ export async function resolveAuth(opts) {
28
+ if (opts.flagApiKey)
29
+ return { apiKey: opts.flagApiKey, source: 'flag' };
30
+ if (opts.envApiKey)
31
+ return { apiKey: opts.envApiKey, source: 'env' };
32
+ const cfgPath = opts.configPath ?? resolve(homedir(), '.config', 'oriva', 'config.json');
33
+ let cfg;
34
+ try {
35
+ const text = await readFile(cfgPath, 'utf8');
36
+ cfg = JSON.parse(text);
37
+ }
38
+ catch {
39
+ // No config file or unreadable — fall through to "none".
40
+ return { source: 'none' };
41
+ }
42
+ const profiles = cfg.profiles ?? {};
43
+ const want = opts.profile ?? cfg.activeProfile ?? 'default';
44
+ const picked = profiles[want] ?? profiles.default;
45
+ if (picked?.apiKey) {
46
+ return { apiKey: picked.apiKey, baseUrl: picked.baseUrl, source: `config:${want}` };
47
+ }
48
+ return { source: 'none' };
49
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * `oriva` CLI entry point.
3
+ *
4
+ * Boot sequence:
5
+ * 1. parseArgs(process.argv.slice(2))
6
+ * 2. resolveAuth (flag → env → config-file)
7
+ * 3. Load OpenAPI spec (--spec / ORIVA_API_SPEC / bundled snapshot)
8
+ * 4. Extract operations
9
+ * 5. Dispatch:
10
+ * - help → top-level help
11
+ * - command-help → per-command help
12
+ * - version → CLI + spec version
13
+ * - command → coerce flags, read body, executeOperation, print result
14
+ *
15
+ * Exit codes:
16
+ * 0 2xx response (or help/version)
17
+ * 1 4xx response
18
+ * 2 5xx response or network failure
19
+ * 3 usage/parse error (bad flags, unknown command, missing required input)
20
+ * 4 spec load failure
21
+ *
22
+ * Ported from ultra-cli (~/ultra-network/packages/ultra-cli/src/cli.ts).
23
+ * Adds: --json envelope output, --profile + --api-key, config-file auth,
24
+ * bundled-snapshot default spec source.
25
+ */
26
+ import { type MinimalOpenApiDoc } from './shared/loadSpec.js';
27
+ import { renderEnvelope } from './output.js';
28
+ export interface RunDeps {
29
+ argv?: string[];
30
+ env?: NodeJS.ProcessEnv;
31
+ stdin?: NodeJS.ReadableStream;
32
+ stdout?: NodeJS.WritableStream;
33
+ stderr?: NodeJS.WritableStream;
34
+ fetchImpl?: typeof fetch;
35
+ /** Inject a spec for tests; skips loadSpec. */
36
+ specOverride?: MinimalOpenApiDoc;
37
+ /** Override the config-file path for tests. */
38
+ configPath?: string;
39
+ }
40
+ export declare function run(deps?: RunDeps): Promise<number>;
41
+ export { renderEnvelope };
42
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAiC,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAS7F,OAAO,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAC;AAK3D,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,GAAG,CAAC,IAAI,GAAE,OAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAuI7D;AA6BD,OAAO,EAAE,cAAc,EAAE,CAAC"}
package/dist/cli.js ADDED
@@ -0,0 +1,177 @@
1
+ /**
2
+ * `oriva` CLI entry point.
3
+ *
4
+ * Boot sequence:
5
+ * 1. parseArgs(process.argv.slice(2))
6
+ * 2. resolveAuth (flag → env → config-file)
7
+ * 3. Load OpenAPI spec (--spec / ORIVA_API_SPEC / bundled snapshot)
8
+ * 4. Extract operations
9
+ * 5. Dispatch:
10
+ * - help → top-level help
11
+ * - command-help → per-command help
12
+ * - version → CLI + spec version
13
+ * - command → coerce flags, read body, executeOperation, print result
14
+ *
15
+ * Exit codes:
16
+ * 0 2xx response (or help/version)
17
+ * 1 4xx response
18
+ * 2 5xx response or network failure
19
+ * 3 usage/parse error (bad flags, unknown command, missing required input)
20
+ * 4 spec load failure
21
+ *
22
+ * Ported from ultra-cli (~/ultra-network/packages/ultra-cli/src/cli.ts).
23
+ * Adds: --json envelope output, --profile + --api-key, config-file auth,
24
+ * bundled-snapshot default spec source.
25
+ */
26
+ import { loadSpec, bundledSnapshotPath } from './shared/loadSpec.js';
27
+ import { extractOperations } from './shared/toolGenerator.js';
28
+ import { executeOperation } from './shared/httpExecutor.js';
29
+ import { parseArgs } from './parseArgs.js';
30
+ import { renderTopLevelHelp, renderCommandHelp, renderVersion } from './help.js';
31
+ import { coerceArgs } from './coerce.js';
32
+ import { readBody } from './readBody.js';
33
+ import { resolveAuth } from './auth.js';
34
+ import { renderOutput, renderEnvelope } from './output.js';
35
+ const CLI_VERSION = '0.1.0';
36
+ const DEFAULT_BASE_URL = 'https://api.oriva.io';
37
+ export async function run(deps = {}) {
38
+ const argv = deps.argv ?? process.argv.slice(2);
39
+ const env = deps.env ?? process.env;
40
+ const stdout = deps.stdout ?? process.stdout;
41
+ const stderr = deps.stderr ?? process.stderr;
42
+ const stdin = deps.stdin ?? process.stdin;
43
+ let parsed;
44
+ try {
45
+ parsed = parseArgs(argv);
46
+ }
47
+ catch (err) {
48
+ stderr.write(`Error: ${err.message}\n`);
49
+ return 3;
50
+ }
51
+ // Spec source precedence: --spec > ORIVA_API_SPEC > bundled snapshot.
52
+ const specSource = parsed.global.spec || (env.ORIVA_API_SPEC || '').trim() || bundledSnapshotPath();
53
+ const tagFilter = (env.ORIVA_API_TAGS || '')
54
+ .split(',')
55
+ .map((t) => t.trim())
56
+ .filter(Boolean);
57
+ let doc;
58
+ try {
59
+ doc = deps.specOverride ?? (await loadSpec(specSource));
60
+ }
61
+ catch (err) {
62
+ stderr.write(`Failed to load OpenAPI spec from ${specSource}: ${err.message}\n`);
63
+ return 4;
64
+ }
65
+ const operations = extractOperations(doc, { tagFilter });
66
+ const opsByName = new Map(operations.map((o) => [o.name, o]));
67
+ if (parsed.kind === 'help') {
68
+ stdout.write(renderTopLevelHelp(operations));
69
+ stdout.write('\n');
70
+ return 0;
71
+ }
72
+ if (parsed.kind === 'version') {
73
+ stdout.write(renderVersion(CLI_VERSION, doc.info?.version));
74
+ stdout.write('\n');
75
+ return 0;
76
+ }
77
+ if (parsed.kind === 'command-help') {
78
+ const op = opsByName.get(parsed.command);
79
+ if (!op)
80
+ return unknownCommand(parsed.command, operations, stderr);
81
+ stdout.write(renderCommandHelp(op));
82
+ stdout.write('\n');
83
+ return 0;
84
+ }
85
+ // kind === 'command'
86
+ const op = opsByName.get(parsed.command);
87
+ if (!op)
88
+ return unknownCommand(parsed.command, operations, stderr);
89
+ // Resolve auth: flag > env > config-file.
90
+ const auth = await resolveAuth({
91
+ flagApiKey: parsed.global.apiKey,
92
+ envApiKey: (env.ORIVA_API_KEY || '').trim() || undefined,
93
+ profile: parsed.global.profile,
94
+ configPath: deps.configPath,
95
+ });
96
+ if (!auth.apiKey && !parsed.global.quiet) {
97
+ stderr.write('[oriva] WARNING: no API key resolved (flag → ORIVA_API_KEY → ~/.config/oriva/config.json) — call will likely 401.\n');
98
+ }
99
+ let args;
100
+ try {
101
+ args = coerceArgs(parsed.flags, op.inputSchema);
102
+ }
103
+ catch (err) {
104
+ stderr.write(`Argument error: ${err.message}\n`);
105
+ return 3;
106
+ }
107
+ try {
108
+ const body = await readBody(parsed.bodySource, stdin);
109
+ if (body !== undefined)
110
+ args.body = body;
111
+ }
112
+ catch (err) {
113
+ stderr.write(`Body error: ${err.message}\n`);
114
+ return 3;
115
+ }
116
+ if (op.hasBody && args.body === undefined && requiresBody(op)) {
117
+ stderr.write(`This command requires --body=<json|@file|->. Run \`oriva ${op.name} --help\`.\n`);
118
+ return 3;
119
+ }
120
+ const baseUrl = parsed.global.baseUrl ||
121
+ (env.ORIVA_API_BASE_URL || '').trim() ||
122
+ auth.baseUrl ||
123
+ doc.servers?.[0]?.url ||
124
+ DEFAULT_BASE_URL;
125
+ let result;
126
+ try {
127
+ result = await executeOperation(op, args, { baseUrl, apiKey: auth.apiKey, userAgent: `oriva-cli/${CLI_VERSION}` }, deps.fetchImpl);
128
+ }
129
+ catch (err) {
130
+ if (parsed.global.json) {
131
+ // Emit envelope-shaped error so agents can parse network failures uniformly.
132
+ const envelope = {
133
+ ok: false,
134
+ status: 0,
135
+ data: null,
136
+ error: { message: err.message, kind: 'network' },
137
+ request_id: undefined,
138
+ };
139
+ stdout.write(JSON.stringify(envelope, null, 2));
140
+ stdout.write('\n');
141
+ }
142
+ else {
143
+ stderr.write(`Network error: ${err.message}\n`);
144
+ }
145
+ return 2;
146
+ }
147
+ if (parsed.global.showStatus && !parsed.global.quiet) {
148
+ stderr.write(`HTTP ${result.status}${result.request_id ? ` (request_id=${result.request_id})` : ''}\n`);
149
+ }
150
+ stdout.write(renderOutput(result, { raw: parsed.global.raw, json: parsed.global.json }));
151
+ stdout.write('\n');
152
+ if (result.status >= 500)
153
+ return 2;
154
+ if (result.status >= 400)
155
+ return 1;
156
+ return 0;
157
+ }
158
+ function unknownCommand(name, operations, stderr) {
159
+ stderr.write(`Unknown command: ${name}\n`);
160
+ const suggestions = operations
161
+ .map((o) => o.name)
162
+ .filter((n) => n
163
+ .toLowerCase()
164
+ .startsWith(name.toLowerCase().slice(0, Math.max(3, Math.floor(name.length / 2)))))
165
+ .slice(0, 5);
166
+ if (suggestions.length) {
167
+ stderr.write(`Did you mean: ${suggestions.join(', ')}?\n`);
168
+ }
169
+ stderr.write('Run `oriva --help` to list commands.\n');
170
+ return 3;
171
+ }
172
+ function requiresBody(op) {
173
+ const required = op.inputSchema.required ?? [];
174
+ return required.includes('body');
175
+ }
176
+ // Re-export for tests + bin shim.
177
+ export { renderEnvelope };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Coerce string CLI flags to the JSON types the API expects.
3
+ *
4
+ * Ported verbatim from ultra-cli (~/ultra-network/packages/ultra-cli/src/coerce.ts) —
5
+ * type-coercion semantics are universal.
6
+ */
7
+ export declare function coerceArgs(rawFlags: Record<string, string | string[] | boolean>, inputSchema: Record<string, unknown>): Record<string, unknown>;
8
+ //# sourceMappingURL=coerce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coerce.d.ts","sourceRoot":"","sources":["../src/coerce.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,EACrD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB"}
package/dist/coerce.js ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Coerce string CLI flags to the JSON types the API expects.
3
+ *
4
+ * Ported verbatim from ultra-cli (~/ultra-network/packages/ultra-cli/src/coerce.ts) —
5
+ * type-coercion semantics are universal.
6
+ */
7
+ export function coerceArgs(rawFlags, inputSchema) {
8
+ const props = inputSchema.properties ?? {};
9
+ const out = {};
10
+ for (const [k, v] of Object.entries(rawFlags)) {
11
+ const schema = props[k];
12
+ out[k] = coerceOne(v, schema);
13
+ }
14
+ return out;
15
+ }
16
+ function coerceOne(v, schema) {
17
+ if (typeof v === 'boolean')
18
+ return v;
19
+ if (Array.isArray(v))
20
+ return v.map((x) => coerceScalar(x, schema?.items ?? schema));
21
+ return coerceScalar(v, schema);
22
+ }
23
+ function coerceScalar(s, schema) {
24
+ const t = schema?.type;
25
+ if (t === 'integer') {
26
+ const n = Number.parseInt(s, 10);
27
+ if (Number.isNaN(n))
28
+ throw new Error(`Expected integer, got: ${s}`);
29
+ return n;
30
+ }
31
+ if (t === 'number') {
32
+ const n = Number(s);
33
+ if (Number.isNaN(n))
34
+ throw new Error(`Expected number, got: ${s}`);
35
+ return n;
36
+ }
37
+ if (t === 'boolean') {
38
+ if (s === 'true' || s === '1')
39
+ return true;
40
+ if (s === 'false' || s === '0')
41
+ return false;
42
+ throw new Error(`Expected boolean, got: ${s}`);
43
+ }
44
+ return s;
45
+ }
package/dist/help.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Help text rendering for the `oriva` CLI.
3
+ *
4
+ * Ported from ultra-cli (~/ultra-network/packages/ultra-cli/src/help.ts);
5
+ * key deviation: group commands by OpenAPI `tags[0]` instead of path segment.
6
+ * The Oriva spec has 13 clean tags (Auth/Profiles/Groups/Entries/…) that map
7
+ * cleaner than path roots (which all start with `/api/v1/...`).
8
+ */
9
+ import type { ExtractedOperation } from './shared/types.js';
10
+ export declare function renderTopLevelHelp(operations: ExtractedOperation[]): string;
11
+ export declare function renderCommandHelp(op: ExtractedOperation): string;
12
+ export declare function renderVersion(cliVersion: string, specVersion: string | undefined): string;
13
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AA8B5D,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,kBAAkB,EAAE,GAAG,MAAM,CA4B3E;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,kBAAkB,GAAG,MAAM,CA2ChE;AAsBD,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAEzF"}
package/dist/help.js ADDED
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Help text rendering for the `oriva` CLI.
3
+ *
4
+ * Ported from ultra-cli (~/ultra-network/packages/ultra-cli/src/help.ts);
5
+ * key deviation: group commands by OpenAPI `tags[0]` instead of path segment.
6
+ * The Oriva spec has 13 clean tags (Auth/Profiles/Groups/Entries/…) that map
7
+ * cleaner than path roots (which all start with `/api/v1/...`).
8
+ */
9
+ const HEADER = `oriva — Oriva public API CLI
10
+
11
+ A spec-driven wrapper over every operation in the @oriva/sdk surface. Every
12
+ endpoint becomes a subcommand. Use \`oriva <command> --help\` for per-command
13
+ flags. Command names match @oriva/sdk function names 1:1.
14
+
15
+ ENVIRONMENT
16
+ ORIVA_API_KEY Bearer key (oriva_pk_live_… / oriva_pk_test_…)
17
+ ORIVA_API_SPEC OpenAPI source (default: bundled snapshot)
18
+ ORIVA_API_BASE_URL Override server base URL (default: https://api.oriva.io)
19
+ ORIVA_API_TAGS CSV tag filter for which operations are exposed
20
+
21
+ CONFIG FILE
22
+ ~/.config/oriva/config.json Multi-profile auth — see README
23
+
24
+ GLOBAL FLAGS
25
+ --api-key=<key> Override ORIVA_API_KEY for this invocation
26
+ --profile=<name> Select a config-file profile (default: activeProfile)
27
+ --spec=<url|path> Override the spec source for this invocation
28
+ --base-url=<url> Override the base URL for this invocation
29
+ --show-status Print HTTP status + request_id to stderr
30
+ --raw Print response body unchanged (no JSON pretty-print)
31
+ --json Emit { ok, status, data, error, request_id } envelope
32
+ --quiet Suppress progress lines on stderr
33
+ --help, -h Show this help (or per-command help)
34
+ --version, -V Print CLI + spec version
35
+ `;
36
+ export function renderTopLevelHelp(operations) {
37
+ const out = [HEADER, 'COMMANDS'];
38
+ if (operations.length === 0) {
39
+ out.push(' (no operations available — check ORIVA_API_SPEC)');
40
+ return out.join('\n');
41
+ }
42
+ // Group by first OpenAPI tag; ops without tags go to 'misc'.
43
+ const groups = new Map();
44
+ for (const op of operations) {
45
+ const group = op.tags?.[0] || 'misc';
46
+ if (!groups.has(group))
47
+ groups.set(group, []);
48
+ groups.get(group).push(op);
49
+ }
50
+ const nameWidth = Math.min(40, Math.max(...operations.map((o) => o.name.length)));
51
+ for (const [group, ops] of [...groups.entries()].sort()) {
52
+ out.push('');
53
+ out.push(` ${group}`);
54
+ for (const op of ops.sort((a, b) => a.name.localeCompare(b.name))) {
55
+ const padded = op.name.padEnd(nameWidth);
56
+ out.push(` ${padded} ${op.description}`);
57
+ }
58
+ }
59
+ out.push('');
60
+ out.push('Run `oriva <command> --help` for input details.');
61
+ return out.join('\n');
62
+ }
63
+ export function renderCommandHelp(op) {
64
+ const out = [];
65
+ out.push(`oriva ${op.name}`);
66
+ out.push('');
67
+ out.push(` ${op.description}`);
68
+ out.push(` ${op.method.toUpperCase()} ${op.pathTemplate}`);
69
+ if (op.tags?.length) {
70
+ out.push(` tags: ${op.tags.join(', ')}`);
71
+ }
72
+ out.push('');
73
+ const schema = op.inputSchema;
74
+ const required = new Set(schema.required ?? []);
75
+ const props = schema.properties ?? {};
76
+ if (op.pathParams.length) {
77
+ out.push('PATH PARAMETERS (required)');
78
+ for (const name of op.pathParams) {
79
+ out.push(formatParam(name, props[name], required.has(name)));
80
+ }
81
+ out.push('');
82
+ }
83
+ if (op.queryParams.length) {
84
+ out.push('QUERY PARAMETERS');
85
+ for (const name of op.queryParams) {
86
+ out.push(formatParam(name, props[name], required.has(name)));
87
+ }
88
+ out.push('');
89
+ }
90
+ if (op.hasBody) {
91
+ out.push('REQUEST BODY');
92
+ out.push(` --body=<json> | --body=@path/to/file.json | --body=- (stdin)`);
93
+ out.push(` Content-Type: ${op.bodyContentType || 'application/json'}`);
94
+ if (required.has('body'))
95
+ out.push(' (required)');
96
+ out.push('');
97
+ }
98
+ out.push('EXAMPLE');
99
+ out.push(formatExample(op));
100
+ return out.join('\n');
101
+ }
102
+ function formatParam(name, schema, isRequired) {
103
+ const tag = isRequired ? ' (required)' : '';
104
+ const type = schema?.type ? ` <${schema.type}>` : '';
105
+ const desc = schema?.description ? ` — ${schema.description}` : '';
106
+ const enumVals = schema?.enum?.length ? ` [${schema.enum.join('|')}]` : '';
107
+ return ` --${name}${type}${tag}${enumVals}${desc}`;
108
+ }
109
+ function formatExample(op) {
110
+ const parts = [' oriva', op.name];
111
+ for (const p of op.pathParams)
112
+ parts.push(`--${p}=<${p}>`);
113
+ for (const q of op.queryParams.slice(0, 2))
114
+ parts.push(`--${q}=<value>`);
115
+ if (op.hasBody)
116
+ parts.push(`--body='{"…":"…"}'`);
117
+ return parts.join(' ');
118
+ }
119
+ export function renderVersion(cliVersion, specVersion) {
120
+ return `oriva ${cliVersion}\nspec ${specVersion ?? '(unknown)'}`;
121
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Output rendering for the `oriva` CLI.
3
+ *
4
+ * Three modes:
5
+ * default: pretty-printed JSON of the response body
6
+ * --raw: response body unchanged (no re-serialization)
7
+ * --json: agent-friendly envelope
8
+ * { ok, status, data, error, request_id, url?, method? }
9
+ *
10
+ * The envelope is always parseable regardless of HTTP status — agents calling
11
+ * the CLI in tight loops want `JSON.parse(stdout).ok` not `if (exit === 0) ...`.
12
+ */
13
+ import type { ExecuteResult } from './shared/httpExecutor.js';
14
+ export interface OutputOptions {
15
+ raw?: boolean;
16
+ json?: boolean;
17
+ }
18
+ export interface Envelope {
19
+ ok: boolean;
20
+ status: number;
21
+ data: unknown;
22
+ error: unknown;
23
+ request_id?: string;
24
+ url?: string;
25
+ method?: string;
26
+ }
27
+ export declare function renderEnvelope(result: ExecuteResult): Envelope;
28
+ export declare function renderOutput(result: ExecuteResult, opts: OutputOptions): string;
29
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ,CAyB9D;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,CAQ/E"}