@2kw/ai 4.0.0-dev.2

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.
Files changed (69) hide show
  1. package/LICENSE +19 -0
  2. package/README.md +91 -0
  3. package/dist/commands/ai.d.ts +3 -0
  4. package/dist/commands/ai.js +72 -0
  5. package/dist/commands/analytics.d.ts +3 -0
  6. package/dist/commands/analytics.js +161 -0
  7. package/dist/commands/auth.d.ts +3 -0
  8. package/dist/commands/auth.js +134 -0
  9. package/dist/commands/billing.d.ts +3 -0
  10. package/dist/commands/billing.js +102 -0
  11. package/dist/commands/config.d.ts +3 -0
  12. package/dist/commands/config.js +90 -0
  13. package/dist/commands/context.d.ts +3 -0
  14. package/dist/commands/context.js +149 -0
  15. package/dist/commands/convert.d.ts +3 -0
  16. package/dist/commands/convert.js +291 -0
  17. package/dist/commands/dataset-versions.d.ts +3 -0
  18. package/dist/commands/dataset-versions.js +90 -0
  19. package/dist/commands/datasets.d.ts +3 -0
  20. package/dist/commands/datasets.js +150 -0
  21. package/dist/commands/docs.d.ts +3 -0
  22. package/dist/commands/docs.js +166 -0
  23. package/dist/commands/evaluators.d.ts +3 -0
  24. package/dist/commands/evaluators.js +124 -0
  25. package/dist/commands/experiments.d.ts +3 -0
  26. package/dist/commands/experiments.js +255 -0
  27. package/dist/commands/extractions.d.ts +3 -0
  28. package/dist/commands/extractions.js +134 -0
  29. package/dist/commands/prompt-labels.d.ts +3 -0
  30. package/dist/commands/prompt-labels.js +67 -0
  31. package/dist/commands/prompt-versions.d.ts +3 -0
  32. package/dist/commands/prompt-versions.js +65 -0
  33. package/dist/commands/prompts.d.ts +3 -0
  34. package/dist/commands/prompts.js +159 -0
  35. package/dist/commands/providers.d.ts +3 -0
  36. package/dist/commands/providers.js +115 -0
  37. package/dist/commands/schema-labels.d.ts +3 -0
  38. package/dist/commands/schema-labels.js +67 -0
  39. package/dist/commands/schema-versions.d.ts +3 -0
  40. package/dist/commands/schema-versions.js +66 -0
  41. package/dist/commands/schemas.d.ts +3 -0
  42. package/dist/commands/schemas.js +178 -0
  43. package/dist/commands/scores.d.ts +3 -0
  44. package/dist/commands/scores.js +31 -0
  45. package/dist/commands/tracing.d.ts +3 -0
  46. package/dist/commands/tracing.js +85 -0
  47. package/dist/commands/transcribe.d.ts +3 -0
  48. package/dist/commands/transcribe.js +65 -0
  49. package/dist/index.d.ts +3 -0
  50. package/dist/index.js +54 -0
  51. package/dist/lib/client.d.ts +12 -0
  52. package/dist/lib/client.js +52 -0
  53. package/dist/lib/config.d.ts +44 -0
  54. package/dist/lib/config.js +217 -0
  55. package/dist/lib/datasets.d.ts +6 -0
  56. package/dist/lib/datasets.js +10 -0
  57. package/dist/lib/errors.d.ts +14 -0
  58. package/dist/lib/errors.js +54 -0
  59. package/dist/lib/multipart.d.ts +10 -0
  60. package/dist/lib/multipart.js +59 -0
  61. package/dist/lib/output.d.ts +29 -0
  62. package/dist/lib/output.js +107 -0
  63. package/dist/lib/pagination.d.ts +21 -0
  64. package/dist/lib/pagination.js +21 -0
  65. package/dist/lib/schema-compat.d.ts +11 -0
  66. package/dist/lib/schema-compat.js +51 -0
  67. package/dist/lib/update-notifier.d.ts +9 -0
  68. package/dist/lib/update-notifier.js +96 -0
  69. package/package.json +49 -0
package/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2025-present Manfred Kunze Dev
2
+
3
+ All rights reserved.
4
+
5
+ This software and associated documentation files (the "Software") are proprietary
6
+ and confidential. No part of the Software may be reproduced, distributed, or
7
+ transmitted in any form or by any means, including photocopying, recording, or
8
+ other electronic or mechanical methods, without the prior written permission of
9
+ the copyright holder.
10
+
11
+ The Software is provided "as is", without warranty of any kind, express or implied,
12
+ including but not limited to the warranties of merchantability, fitness for a
13
+ particular purpose, and noninfringement. In no event shall the authors or copyright
14
+ holders be liable for any claim, damages, or other liability, whether in an action
15
+ of contract, tort, or otherwise, arising from, out of, or in connection with the
16
+ Software or the use or other dealings in the Software.
17
+
18
+ Usage of this Software is permitted only in accordance with the terms and conditions
19
+ set forth by Manfred Kunze Dev.
package/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # Backbone CLI
2
+
3
+ A command-line interface for the [Backbone AI](https://backbone.manfred-kunze.dev) platform. Manage schemas, prompts, extractions, documents, and more — straight from your terminal.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # Latest stable release
9
+ npm install -g @manfred-kunze-dev/backbone-cli
10
+
11
+ # Pre-release (dev channel)
12
+ npm install -g @manfred-kunze-dev/backbone-cli@dev
13
+ ```
14
+
15
+ The CLI will notify you when a newer version is available.
16
+
17
+ ## Quick Start
18
+
19
+ ```bash
20
+ # Authenticate
21
+ backbone auth login
22
+
23
+ # Define a schema and run an extraction
24
+ backbone schemas create -n "Invoice"
25
+ backbone extractions create --schema <id> -m gpt-4o --text "Invoice #123, Total: $500"
26
+ ```
27
+
28
+ The CLI is also available as `bb` for quick access — e.g. `bb schemas list`.
29
+
30
+ ## Authentication
31
+
32
+ The CLI supports multiple authentication methods (highest priority first):
33
+
34
+ | Method | Example |
35
+ |--------|---------|
36
+ | CLI flags | `--api-key sk_... --base-url https://...` |
37
+ | Environment variables | `BACKBONE_API_KEY`, `BACKBONE_BASE_URL` |
38
+ | Local `.backbone` file | JSON file in the current directory |
39
+ | Config store | `~/.config/backbone/config.json` (set via `backbone auth login`) |
40
+
41
+ ```bash
42
+ backbone auth login # Interactive setup
43
+ backbone auth status # Verify credentials
44
+ backbone auth logout # Clear stored credentials
45
+ ```
46
+
47
+ ## Contexts
48
+
49
+ The CLI supports kubectl-style contexts for switching between organizations and environments:
50
+
51
+ ```bash
52
+ # Contexts are created automatically via `backbone auth login`
53
+ backbone context list # List all contexts
54
+ backbone context use acme-corp # Switch active context
55
+ backbone context create staging # Create a new context
56
+ backbone context rename old new # Rename a context
57
+ backbone context delete old # Remove a context
58
+ ```
59
+
60
+ ## Commands
61
+
62
+ | Command | Description |
63
+ |---------|-------------|
64
+ | `auth` | Login, logout, and check auth status |
65
+ | `config` | Get, set, and list configuration values |
66
+ | `context` | Manage CLI contexts for multiple environments |
67
+ | `schemas` | Manage schemas, versions, labels, validation, and testing |
68
+ | `prompts` | Manage prompts, versions, labels, compilation, and testing |
69
+ | `extractions` | Create extractions (text, file, images), list, re-run, estimate tokens |
70
+ | `convert` | Convert documents (PDF, DOCX, images) to Markdown/text/HTML/JSON |
71
+ | `ai` | Chat completions and model listing via the LLM Gateway |
72
+ | `transcribe` | Transcribe audio files (mp3, wav, flac, ogg, etc.) |
73
+ | `providers` | Manage BYOK AI providers |
74
+ | `analytics` | View organization usage analytics |
75
+ | `billing` | Check subscription tier and usage limits |
76
+ | `docs` | Browse API documentation from the terminal |
77
+
78
+ ### Global Options
79
+
80
+ | Flag | Description |
81
+ |------|-------------|
82
+ | `--api-key <key>` | Override the API key |
83
+ | `--base-url <url>` | Override the base URL (default: `https://backbone.manfred-kunze.dev/api`) |
84
+ | `--json` | Output raw JSON instead of formatted tables |
85
+ | `--no-color` | Disable colored output |
86
+
87
+ For full command documentation, see the [Backbone docs](https://backbone.manfred-kunze.dev).
88
+
89
+ ## License
90
+
91
+ Proprietary — see [LICENSE](./LICENSE) for details.
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function makeAiCommand(): Command;
3
+ //# sourceMappingURL=ai.d.ts.map
@@ -0,0 +1,72 @@
1
+ import { Command } from "commander";
2
+ import { getClient, runAction } from "../lib/client.js";
3
+ import { isJsonOutput } from "../lib/config.js";
4
+ import { formatList, withSpinner } from "../lib/output.js";
5
+ import chalk from "chalk";
6
+ export function makeAiCommand() {
7
+ const cmd = new Command("ai").description("AI gateway operations");
8
+ cmd
9
+ .command("chat")
10
+ .description("Send a chat completion request")
11
+ .requiredOption("-m, --model <model>", "Model (provider/model format)")
12
+ .requiredOption("--message <text>", "User message")
13
+ .option("--system <text>", "System message")
14
+ .option("--temperature <n>", "Temperature (0-2)")
15
+ .option("--max-tokens <n>", "Max tokens")
16
+ .option("--top-p <n>", "Top-p sampling")
17
+ .action(async (opts, command) => {
18
+ await runAction(command, async () => {
19
+ const client = getClient(command);
20
+ const messages = [];
21
+ if (opts.system) {
22
+ messages.push({ role: "system", content: opts.system });
23
+ }
24
+ messages.push({ role: "user", content: opts.message });
25
+ const body = {
26
+ model: opts.model,
27
+ messages,
28
+ stream: false,
29
+ temperature: opts.temperature ? parseFloat(opts.temperature) : undefined,
30
+ max_tokens: opts.maxTokens ? parseInt(opts.maxTokens, 10) : undefined,
31
+ top_p: opts.topP ? parseFloat(opts.topP) : undefined,
32
+ };
33
+ const { data } = await withSpinner("Thinking...", () => client.POST("/v1/chat/completions", { body }));
34
+ // Response type is untyped in OpenAPI spec (OpenAI-compatible format)
35
+ const result = data;
36
+ const json = isJsonOutput(command);
37
+ if (json) {
38
+ console.log(JSON.stringify(result, null, 2));
39
+ }
40
+ else {
41
+ const choices = result?.choices;
42
+ const content = choices?.[0]?.message?.content;
43
+ if (content) {
44
+ console.log(content);
45
+ }
46
+ const usage = result?.usage;
47
+ if (usage) {
48
+ console.log(chalk.dim(`\n[${result?.model} | ${usage.prompt_tokens} in / ${usage.completion_tokens} out / ${usage.total_tokens} total tokens]`));
49
+ }
50
+ }
51
+ });
52
+ });
53
+ cmd
54
+ .command("models")
55
+ .description("List available AI models")
56
+ .action(async (_opts, command) => {
57
+ await runAction(command, async () => {
58
+ const client = getClient(command);
59
+ const { data } = await client.GET("/v1/models");
60
+ const json = isJsonOutput(command);
61
+ if (json) {
62
+ console.log(JSON.stringify(data, null, 2));
63
+ }
64
+ else {
65
+ const models = data?.data ?? [];
66
+ formatList(models, command, ["id", "owned_by"]);
67
+ }
68
+ });
69
+ });
70
+ return cmd;
71
+ }
72
+ //# sourceMappingURL=ai.js.map
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function makeAnalyticsCommand(): Command;
3
+ //# sourceMappingURL=analytics.d.ts.map
@@ -0,0 +1,161 @@
1
+ import { Command } from "commander";
2
+ import { getClient, runAction } from "../lib/client.js";
3
+ import { formatDetail, formatList } from "../lib/output.js";
4
+ function addDateOptions(cmd) {
5
+ return cmd
6
+ .option("--start <date>", "Start date (YYYY-MM-DD)")
7
+ .option("--end <date>", "End date (YYYY-MM-DD)");
8
+ }
9
+ export function makeAnalyticsCommand() {
10
+ const cmd = new Command("analytics").description("Organization analytics");
11
+ const summary = new Command("summary").description("Cross-surface summary (total ops, spend, p95, per-surface breakdown)");
12
+ addDateOptions(summary);
13
+ summary.action(async (opts, command) => {
14
+ await runAction(command, async () => {
15
+ const client = getClient(command);
16
+ const { data } = await client.GET("/v1/analytics/summary", {
17
+ params: {
18
+ query: { startDate: opts.start, endDate: opts.end },
19
+ },
20
+ });
21
+ formatDetail(data, command);
22
+ });
23
+ });
24
+ cmd.addCommand(summary);
25
+ const timeSeries = new Command("time-series").description("Daily / weekly / monthly operations grouped by surface");
26
+ addDateOptions(timeSeries);
27
+ timeSeries.option("--group-by <interval>", "Group by: day, week, month", "day");
28
+ timeSeries.action(async (opts, command) => {
29
+ await runAction(command, async () => {
30
+ const client = getClient(command);
31
+ const { data } = await client.GET("/v1/analytics/time-series", {
32
+ params: {
33
+ query: {
34
+ startDate: opts.start,
35
+ endDate: opts.end,
36
+ groupBy: opts.groupBy,
37
+ },
38
+ },
39
+ });
40
+ // Rows carry `date` + `bySurface` (map keyed by Surface). Nothing
41
+ // sensible to tabulate across rows of different surface sets, so
42
+ // fall through to the JSON view via formatDetail per row.
43
+ formatList(data, command, ["date", "bySurface"]);
44
+ });
45
+ });
46
+ cmd.addCommand(timeSeries);
47
+ const schemas = new Command("schemas").description("Top schemas by extraction count (extraction surface only)");
48
+ addDateOptions(schemas);
49
+ schemas.option("--limit <n>", "Max results", "10");
50
+ schemas.action(async (opts, command) => {
51
+ await runAction(command, async () => {
52
+ const client = getClient(command);
53
+ const { data } = await client.GET("/v1/analytics/schemas", {
54
+ params: {
55
+ query: {
56
+ startDate: opts.start,
57
+ endDate: opts.end,
58
+ limit: parseInt(opts.limit, 10),
59
+ },
60
+ },
61
+ });
62
+ formatList(data, command, [
63
+ "schemaVersionId",
64
+ "schemaName",
65
+ "totalExtractions",
66
+ "successfulExtractions",
67
+ "successRate",
68
+ "totalTokens",
69
+ "totalCost",
70
+ "avgDurationMs",
71
+ ]);
72
+ });
73
+ });
74
+ cmd.addCommand(schemas);
75
+ const providers = new Command("providers").description("Provider usage breakdown (extraction surface only)");
76
+ addDateOptions(providers);
77
+ providers.action(async (opts, command) => {
78
+ await runAction(command, async () => {
79
+ const client = getClient(command);
80
+ const { data } = await client.GET("/v1/analytics/providers", {
81
+ params: {
82
+ query: { startDate: opts.start, endDate: opts.end },
83
+ },
84
+ });
85
+ formatList(data, command, [
86
+ "providerId",
87
+ "providerName",
88
+ "totalExtractions",
89
+ "successfulExtractions",
90
+ "successRate",
91
+ "totalTokens",
92
+ "totalCost",
93
+ "avgDurationMs",
94
+ ]);
95
+ });
96
+ });
97
+ cmd.addCommand(providers);
98
+ const errors = new Command("errors").description("Top failures grouped by surface + error message");
99
+ addDateOptions(errors);
100
+ errors.option("--limit <n>", "Max results", "10");
101
+ errors.action(async (opts, command) => {
102
+ await runAction(command, async () => {
103
+ const client = getClient(command);
104
+ const { data } = await client.GET("/v1/analytics/errors", {
105
+ params: {
106
+ query: {
107
+ startDate: opts.start,
108
+ endDate: opts.end,
109
+ limit: parseInt(opts.limit, 10),
110
+ },
111
+ },
112
+ });
113
+ formatList(data, command, [
114
+ "surface",
115
+ "errorMessage",
116
+ "count",
117
+ "lastOccurrence",
118
+ ]);
119
+ });
120
+ });
121
+ cmd.addCommand(errors);
122
+ const quality = new Command("quality").description("Total experiment runs in range + average evaluator score");
123
+ addDateOptions(quality);
124
+ quality.action(async (opts, command) => {
125
+ await runAction(command, async () => {
126
+ const client = getClient(command);
127
+ const { data } = await client.GET("/v1/analytics/quality", {
128
+ params: {
129
+ query: { startDate: opts.start, endDate: opts.end },
130
+ },
131
+ });
132
+ formatDetail(data, command);
133
+ });
134
+ });
135
+ cmd.addCommand(quality);
136
+ const qualityTrend = new Command("quality-trend").description("Average evaluator score over time");
137
+ addDateOptions(qualityTrend);
138
+ qualityTrend.option("--group-by <interval>", "Group by: day, week, month", "day");
139
+ qualityTrend.action(async (opts, command) => {
140
+ await runAction(command, async () => {
141
+ const client = getClient(command);
142
+ const { data } = await client.GET("/v1/analytics/quality/trend", {
143
+ params: {
144
+ query: {
145
+ startDate: opts.start,
146
+ endDate: opts.end,
147
+ groupBy: opts.groupBy,
148
+ },
149
+ },
150
+ });
151
+ formatList(data, command, [
152
+ "date",
153
+ "runs",
154
+ "avgScore",
155
+ ]);
156
+ });
157
+ });
158
+ cmd.addCommand(qualityTrend);
159
+ return cmd;
160
+ }
161
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function makeAuthCommand(): Command;
3
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1,134 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import { store, resolveConfig, isJsonOutput, getActiveContextName, getActiveContext, getContextCount, setContext, setActiveContext, deleteContext, DEFAULT_BASE_URL, } from "../lib/config.js";
4
+ import { getClient, runAction } from "../lib/client.js";
5
+ import { createInterface } from "node:readline/promises";
6
+ export function makeAuthCommand() {
7
+ const cmd = new Command("auth").description("Manage authentication");
8
+ cmd
9
+ .command("login")
10
+ .description("Configure API credentials")
11
+ .option("--api-key <key>", "API key")
12
+ .option("--base-url <url>", "Base URL")
13
+ .action(async (opts) => {
14
+ let apiKey = opts.apiKey;
15
+ let baseUrl = opts.baseUrl;
16
+ const contextName = getActiveContextName();
17
+ const currentCtx = getActiveContext();
18
+ if (!apiKey || !baseUrl) {
19
+ const rl = createInterface({
20
+ input: process.stdin,
21
+ output: process.stdout,
22
+ });
23
+ try {
24
+ if (!baseUrl) {
25
+ const defaultUrl = currentCtx?.baseUrl ?? DEFAULT_BASE_URL;
26
+ baseUrl = await rl.question(`Base URL [${defaultUrl}]: `);
27
+ if (!baseUrl)
28
+ baseUrl = defaultUrl;
29
+ }
30
+ if (!apiKey) {
31
+ apiKey = await rl.question("API Key (sk_...): ");
32
+ }
33
+ }
34
+ finally {
35
+ rl.close();
36
+ }
37
+ }
38
+ if (!apiKey) {
39
+ console.error(chalk.red("API key is required."));
40
+ process.exit(1);
41
+ }
42
+ setContext(contextName, { apiKey, baseUrl });
43
+ setActiveContext(contextName);
44
+ console.log(chalk.green("Credentials saved successfully."));
45
+ console.log(chalk.dim(`Config stored at: ${store.path}`));
46
+ });
47
+ cmd
48
+ .command("logout")
49
+ .description("Clear stored credentials")
50
+ .action(() => {
51
+ const contextName = getActiveContextName();
52
+ const count = getContextCount();
53
+ if (count <= 1) {
54
+ // Last context — clear it by resetting the store
55
+ store.store = { activeContext: "default", contexts: {} };
56
+ }
57
+ else {
58
+ deleteContext(contextName);
59
+ console.log(chalk.dim(`Removed context "${contextName}". Switched to "${getActiveContextName()}".`));
60
+ }
61
+ console.log(chalk.green("Credentials cleared."));
62
+ });
63
+ cmd
64
+ .command("status")
65
+ .description("Show current authentication status")
66
+ .action(async (_opts, command) => {
67
+ await runAction(command, async () => {
68
+ const json = isJsonOutput(command);
69
+ let config;
70
+ try {
71
+ config = resolveConfig(command);
72
+ }
73
+ catch {
74
+ if (json) {
75
+ console.log(JSON.stringify({ authenticated: false }));
76
+ }
77
+ else {
78
+ console.log(chalk.yellow("Not authenticated."));
79
+ console.log(chalk.dim('Run "2kw auth login" to configure.'));
80
+ }
81
+ return;
82
+ }
83
+ const { apiKey, baseUrl } = config;
84
+ const keyPreview = apiKey.slice(0, 7) + "..." + apiKey.slice(-4);
85
+ const multiContext = getContextCount() > 1;
86
+ const contextName = getActiveContextName();
87
+ // Try to validate by listing models (lightweight call)
88
+ try {
89
+ const client = getClient(command);
90
+ const { data } = await client.GET("/v1/models");
91
+ const modelCount = data?.data?.length ?? 0;
92
+ if (json) {
93
+ console.log(JSON.stringify({
94
+ authenticated: true,
95
+ ...(multiContext ? { context: contextName } : {}),
96
+ baseUrl,
97
+ apiKeyPreview: keyPreview,
98
+ modelCount,
99
+ }));
100
+ }
101
+ else {
102
+ console.log(chalk.green("Authenticated"));
103
+ if (multiContext) {
104
+ console.log(` Context: ${contextName}`);
105
+ }
106
+ console.log(` Base URL: ${baseUrl}`);
107
+ console.log(` API Key: ${keyPreview}`);
108
+ console.log(` Models: ${modelCount} available`);
109
+ }
110
+ }
111
+ catch {
112
+ if (json) {
113
+ console.log(JSON.stringify({
114
+ authenticated: false,
115
+ ...(multiContext ? { context: contextName } : {}),
116
+ baseUrl,
117
+ apiKeyPreview: keyPreview,
118
+ error: "Failed to validate credentials",
119
+ }));
120
+ }
121
+ else {
122
+ console.log(chalk.yellow("Credentials configured but validation failed."));
123
+ if (multiContext) {
124
+ console.log(` Context: ${contextName}`);
125
+ }
126
+ console.log(` Base URL: ${baseUrl}`);
127
+ console.log(` API Key: ${keyPreview}`);
128
+ }
129
+ }
130
+ });
131
+ });
132
+ return cmd;
133
+ }
134
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function makeBillingCommand(): Command;
3
+ //# sourceMappingURL=billing.d.ts.map
@@ -0,0 +1,102 @@
1
+ import { Command } from "commander";
2
+ import { getClient, runAction } from "../lib/client.js";
3
+ import { isJsonOutput } from "../lib/config.js";
4
+ import { formatDetail, formatList } from "../lib/output.js";
5
+ import chalk from "chalk";
6
+ export function makeBillingCommand() {
7
+ const cmd = new Command("billing").description("Billing and subscription management");
8
+ cmd
9
+ .command("tiers")
10
+ .description("List available subscription tiers")
11
+ .action(async (_opts, command) => {
12
+ await runAction(command, async () => {
13
+ const client = getClient(command);
14
+ const { data } = await client.GET("/v1/billing/tiers");
15
+ formatList(data, command, ["name", "displayName", "maxProjects", "maxSchemas", "monthlyExtractionCredits", "monthlyGatewayTokens"]);
16
+ });
17
+ });
18
+ cmd
19
+ .command("tier")
20
+ .description("Show current organization tier")
21
+ .action(async (_opts, command) => {
22
+ await runAction(command, async () => {
23
+ const client = getClient(command);
24
+ const { data } = await client.GET("/v1/billing/tier");
25
+ formatDetail(data, command);
26
+ });
27
+ });
28
+ cmd
29
+ .command("limits")
30
+ .description("Show current usage and limits")
31
+ .action(async (_opts, command) => {
32
+ await runAction(command, async () => {
33
+ const client = getClient(command);
34
+ const { data } = await client.GET("/v1/billing/limits");
35
+ if (isJsonOutput(command)) {
36
+ console.log(JSON.stringify(data, null, 2));
37
+ }
38
+ else {
39
+ console.log(chalk.cyan(`Tier: ${data?.tier ?? "unknown"}`));
40
+ console.log();
41
+ if (data?.resources?.length) {
42
+ console.log(chalk.bold("Resources:"));
43
+ for (const r of data.resources) {
44
+ const label = r.displayName ?? r.resourceType;
45
+ const bar = r.limit === -1
46
+ ? chalk.green("unlimited")
47
+ : `${r.used ?? 0} / ${r.limit ?? 0} (${r.remaining ?? 0} remaining)`;
48
+ console.log(` ${chalk.bold(String(label))}: ${bar}`);
49
+ }
50
+ console.log();
51
+ }
52
+ console.log(chalk.bold("Usage:"));
53
+ console.log(` Schemas: ${data?.currentSchemas ?? 0} / ${data?.maxSchemas ?? 0}`);
54
+ console.log(` Prompts: ${data?.currentPrompts ?? 0} / ${data?.maxPrompts ?? 0}`);
55
+ console.log(` Team members: ${data?.currentTeamMembers ?? 0} / ${data?.maxTeamMembers ?? 0}`);
56
+ console.log();
57
+ console.log(chalk.bold("Features:"));
58
+ console.log(` BYOK: ${data?.byokEnabled ? chalk.green("yes") : chalk.dim("no")}`);
59
+ console.log(` Priority support: ${data?.prioritySupport ? chalk.green("yes") : chalk.dim("no")}`);
60
+ if (data?.periodStart || data?.periodEnd) {
61
+ console.log();
62
+ console.log(chalk.dim(`Period: ${data.periodStart?.slice(0, 10) ?? "?"} \u2192 ${data.periodEnd?.slice(0, 10) ?? "?"}`));
63
+ }
64
+ }
65
+ });
66
+ });
67
+ cmd
68
+ .command("check")
69
+ .description("Check if a resource can be created")
70
+ .argument("<resource>", "Resource type: schema, prompt, team-member")
71
+ .action(async (resource, _opts, command) => {
72
+ await runAction(command, async () => {
73
+ const client = getClient(command);
74
+ let response;
75
+ switch (resource) {
76
+ case "schema":
77
+ response = await client.GET("/v1/billing/can-create-schema");
78
+ break;
79
+ case "prompt":
80
+ response = await client.GET("/v1/billing/can-create-prompt");
81
+ break;
82
+ case "team-member":
83
+ response = await client.GET("/v1/billing/can-add-team-member");
84
+ break;
85
+ default:
86
+ throw new Error(`Unknown resource: "${resource}". Use: schema, prompt, team-member`);
87
+ }
88
+ const result = response.data?.result;
89
+ if (isJsonOutput(command)) {
90
+ console.log(JSON.stringify({ resource, canCreate: result }));
91
+ }
92
+ else if (result) {
93
+ console.log(chalk.green(`You can create a new ${resource}.`));
94
+ }
95
+ else {
96
+ console.log(chalk.yellow(`You cannot create a new ${resource}. Upgrade your tier or check limits.`));
97
+ }
98
+ });
99
+ });
100
+ return cmd;
101
+ }
102
+ //# sourceMappingURL=billing.js.map
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function makeConfigCommand(): Command;
3
+ //# sourceMappingURL=config.d.ts.map