@2kw/ai 5.2.0-dev.6 → 5.2.0-dev.8

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 CHANGED
@@ -1,31 +1,40 @@
1
- # Backbone CLI
1
+ # 2kw.ai CLI
2
2
 
3
- A command-line interface for the [Backbone AI](https://backbone.manfred-kunze.dev) platform. Manage schemas, prompts, extractions, documents, and morestraight from your terminal.
3
+ The command-line interface for [2kw.ai](https://2kw.ai) — the EU-hosted AI integration platform. Run [schema-driven document extraction](https://2kw.ai/extraction), route LLM calls through an [OpenAI-compatible gateway](https://2kw.ai/gateway), transcribe audio, and manage prompts, datasets, and experiments — from your terminal or inside agentic workflows.
4
+
5
+ Installs three equivalent binaries: `2kw`, `backbone`, and `bb`.
4
6
 
5
7
  ## Installation
6
8
 
7
9
  ```bash
8
10
  # Latest stable release
9
- npm install -g @manfred-kunze-dev/backbone-cli
11
+ npm install -g @2kw/ai
10
12
 
11
13
  # Pre-release (dev channel)
12
- npm install -g @manfred-kunze-dev/backbone-cli@dev
14
+ npm install -g @2kw/ai@dev
13
15
  ```
14
16
 
15
- The CLI will notify you when a newer version is available.
17
+ The CLI notifies you when a newer version is available.
16
18
 
17
19
  ## Quick Start
18
20
 
19
21
  ```bash
20
- # Authenticate
21
- backbone auth login
22
+ # Authenticate (get an API key from your 2kw.ai dashboard — 7-day free trial)
23
+ 2kw auth login
22
24
 
23
25
  # 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
+ 2kw schemas create -n "Invoice"
27
+ 2kw extractions create --schema <id> -m gpt-4o --text "Invoice #123, Total: 500"
28
+
29
+ # Convert and transcribe
30
+ 2kw convert file report.docx --format md
31
+ 2kw transcribe call.mp3 --format srt
32
+
33
+ # Chat through the gateway
34
+ 2kw ai chat -m gpt-4o --message "Draft a summary of this quarter's extraction volume"
26
35
  ```
27
36
 
28
- The CLI is also available as `bb` for quick access — e.g. `bb schemas list`.
37
+ All commands work identically as `bb` for quick access — e.g. `bb schemas list`.
29
38
 
30
39
  ## Authentication
31
40
 
@@ -34,27 +43,24 @@ The CLI supports multiple authentication methods (highest priority first):
34
43
  | Method | Example |
35
44
  |--------|---------|
36
45
  | 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`) |
46
+ | Environment variables | `AI_2KW_API_KEY`, `AI_2KW_BASE_URL` (legacy: `BACKBONE_*`) |
47
+ | Local `.2kw` file | JSON file in the current directory (legacy: `.backbone`) |
48
+ | Config store | Set via `2kw auth login` |
40
49
 
41
50
  ```bash
42
- backbone auth login # Interactive setup
43
- backbone auth status # Verify credentials
44
- backbone auth logout # Clear stored credentials
51
+ 2kw auth login # Interactive setup
52
+ 2kw auth status # Verify credentials
53
+ 2kw auth logout # Clear stored credentials
45
54
  ```
46
55
 
47
56
  ## Contexts
48
57
 
49
- The CLI supports kubectl-style contexts for switching between organizations and environments:
58
+ kubectl-style contexts switch between organizations and environments:
50
59
 
51
60
  ```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
61
+ 2kw context list # List all contexts
62
+ 2kw context use acme-corp # Switch active context
63
+ 2kw context create staging # Create a new context
58
64
  ```
59
65
 
60
66
  ## Commands
@@ -63,15 +69,20 @@ backbone context delete old # Remove a context
63
69
  |---------|-------------|
64
70
  | `auth` | Login, logout, and check auth status |
65
71
  | `config` | Get, set, and list configuration values |
66
- | `context` | Manage CLI contexts for multiple environments |
72
+ | `context` | Manage contexts for multiple orgs/environments |
67
73
  | `schemas` | Manage schemas, versions, labels, validation, and testing |
68
- | `prompts` | Manage prompts, versions, labels, compilation, and testing |
74
+ | `prompts` | Versioned prompt management, labels, compilation, testing |
69
75
  | `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.) |
76
+ | `convert` | Convert PDF, DOCX, XLSX, images, and 20+ formats to Markdown/text/HTML/JSON |
77
+ | `ai` | Chat completions and model listing via the OpenAI-compatible gateway |
78
+ | `transcribe` | Transcribe audio (FLAC, MP3, MP4, OGG, WAV, WebM) |
79
+ | `datasets` | Build datasets and dataset versions for evaluation |
80
+ | `experiments` | Run experiments against datasets |
81
+ | `evaluators` | Manage evaluator templates |
82
+ | `scores` | Record and inspect quality scores |
83
+ | `tracing` | Inspect request traces and tracing settings |
73
84
  | `providers` | Manage BYOK AI providers |
74
- | `analytics` | View organization usage analytics |
85
+ | `analytics` | Usage analytics: spend, quality, providers, errors |
75
86
  | `billing` | Check subscription tier and usage limits |
76
87
  | `docs` | Browse API documentation from the terminal |
77
88
 
@@ -80,11 +91,21 @@ backbone context delete old # Remove a context
80
91
  | Flag | Description |
81
92
  |------|-------------|
82
93
  | `--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 |
94
+ | `--base-url <url>` | Override the base URL (defaults to the 2kw.ai cloud API) |
95
+ | `--json` | Output raw JSON instead of formatted tables — built for scripting and agents |
85
96
  | `--no-color` | Disable colored output |
86
97
 
87
- For full command documentation, see the [Backbone docs](https://backbone.manfred-kunze.dev).
98
+ ## Why 2kw.ai
99
+
100
+ - **EU data residency** — built-in models run GDPR-compliant and EU-hosted, operated by Manfred Kunze Development GmbH (Germany)
101
+ - **Grounding scores** — every extracted value links back to where it came from in the source document
102
+ - **One platform** — gateway, extraction, transcription, and observability share one API and one bill
103
+
104
+ ## Related
105
+
106
+ - [2kw.ai](https://2kw.ai) — platform overview and pricing
107
+ - [Documentation](https://docs.2kw.ai) — full command and API reference
108
+ - [`@2kw/ai-mcp-server`](https://www.npmjs.com/package/@2kw/ai-mcp-server) — the 2kw.ai MCP server for Claude Code, Cursor, and Windsurf
88
109
 
89
110
  ## License
90
111
 
@@ -2,7 +2,15 @@ import { Command } from "commander";
2
2
  import chalk from "chalk";
3
3
  import { store, resolveConfig, isJsonOutput, getActiveContextName, getActiveContext, getContextCount, setContext, setActiveContext, deleteContext, DEFAULT_BASE_URL, } from "../lib/config.js";
4
4
  import { getClient, runAction } from "../lib/client.js";
5
+ import { classifyAuthFailure } from "../lib/errors.js";
5
6
  import { createInterface } from "node:readline/promises";
7
+ // Human-readable, actionable line per failure kind for the non-JSON output.
8
+ const FAILURE_HINTS = {
9
+ UNAUTHORIZED: 'Key rejected. Run "2kw auth login" to re-authenticate.',
10
+ FORBIDDEN: "Key is valid but lacks access. Check the key's organization in the 2kw UI.",
11
+ UNREACHABLE: "Could not reach the host. Check the base URL and your connection.",
12
+ UNKNOWN: 'Validation failed. Run "2kw auth login" and, if it persists, check the base URL.',
13
+ };
6
14
  export function makeAuthCommand() {
7
15
  const cmd = new Command("auth").description("Manage authentication");
8
16
  cmd
@@ -71,6 +79,8 @@ export function makeAuthCommand() {
71
79
  config = resolveConfig(command);
72
80
  }
73
81
  catch {
82
+ // No credentials configured at all — distinct from a rejected key.
83
+ process.exitCode = 1;
74
84
  if (json) {
75
85
  console.log(JSON.stringify({ authenticated: false }));
76
86
  }
@@ -108,13 +118,19 @@ export function makeAuthCommand() {
108
118
  console.log(` Models: ${modelCount} available`);
109
119
  }
110
120
  }
111
- catch {
121
+ catch (err) {
122
+ // Credentials are present but the check failed. Surface WHY, so
123
+ // callers stop guessing among a bad key, missing permissions, and an
124
+ // unreachable host.
125
+ const failureKind = classifyAuthFailure(err);
126
+ process.exitCode = 1;
112
127
  if (json) {
113
128
  console.log(JSON.stringify({
114
129
  authenticated: false,
115
130
  ...(multiContext ? { context: contextName } : {}),
116
131
  baseUrl,
117
132
  apiKeyPreview: keyPreview,
133
+ failureKind,
118
134
  error: "Failed to validate credentials",
119
135
  }));
120
136
  }
@@ -125,6 +141,7 @@ export function makeAuthCommand() {
125
141
  }
126
142
  console.log(` Base URL: ${baseUrl}`);
127
143
  console.log(` API Key: ${keyPreview}`);
144
+ console.log(chalk.yellow(` ${FAILURE_HINTS[failureKind]}`));
128
145
  }
129
146
  }
130
147
  });
@@ -10,5 +10,22 @@ export declare class BackboneApiError extends Error {
10
10
  readonly timestamp: string;
11
11
  constructor(body: ApiErrorBody);
12
12
  }
13
+ /**
14
+ * Discriminated cause of a failed credential check. Lets callers give a
15
+ * precise message instead of guessing, because `2kw auth status` otherwise
16
+ * collapses every failure into one string.
17
+ */
18
+ export type AuthFailureKind = "UNAUTHORIZED" | "FORBIDDEN" | "UNREACHABLE" | "UNKNOWN";
19
+ /**
20
+ * Classify why a credential check failed, from the thrown error alone.
21
+ *
22
+ * - An HTTP rejection arrives as {@link BackboneApiError}: 401 → UNAUTHORIZED,
23
+ * 403 → FORBIDDEN, anything else → UNKNOWN.
24
+ * - A network fault (fetch throws before any response) → UNREACHABLE, detected
25
+ * by undici's `fetch failed` TypeError or a known network error code on the
26
+ * error or its `cause`.
27
+ * - Everything else → UNKNOWN.
28
+ */
29
+ export declare function classifyAuthFailure(err: unknown): AuthFailureKind;
13
30
  export declare function handleError(err: unknown, json: boolean): void;
14
31
  //# sourceMappingURL=errors.d.ts.map
@@ -11,6 +11,53 @@ export class BackboneApiError extends Error {
11
11
  this.timestamp = body.timestamp;
12
12
  }
13
13
  }
14
+ // Node/undici surface network faults through the error's `code`. A DNS or
15
+ // connection failure means the host was never reached — distinct from the
16
+ // API rejecting the key.
17
+ const NETWORK_ERROR_CODES = new Set([
18
+ "ENOTFOUND",
19
+ "ECONNREFUSED",
20
+ "EAI_AGAIN",
21
+ "ETIMEDOUT",
22
+ "ECONNRESET",
23
+ "ENETUNREACH",
24
+ "EHOSTUNREACH",
25
+ ]);
26
+ /**
27
+ * Classify why a credential check failed, from the thrown error alone.
28
+ *
29
+ * - An HTTP rejection arrives as {@link BackboneApiError}: 401 → UNAUTHORIZED,
30
+ * 403 → FORBIDDEN, anything else → UNKNOWN.
31
+ * - A network fault (fetch throws before any response) → UNREACHABLE, detected
32
+ * by undici's `fetch failed` TypeError or a known network error code on the
33
+ * error or its `cause`.
34
+ * - Everything else → UNKNOWN.
35
+ */
36
+ export function classifyAuthFailure(err) {
37
+ if (err instanceof BackboneApiError) {
38
+ if (err.status === 401)
39
+ return "UNAUTHORIZED";
40
+ if (err.status === 403)
41
+ return "FORBIDDEN";
42
+ return "UNKNOWN";
43
+ }
44
+ if (isNetworkError(err))
45
+ return "UNREACHABLE";
46
+ return "UNKNOWN";
47
+ }
48
+ function isNetworkError(err) {
49
+ if (!(err instanceof Error))
50
+ return false;
51
+ // undici throws `TypeError: fetch failed` when the request never completes.
52
+ if (err instanceof TypeError && /fetch failed/i.test(err.message))
53
+ return true;
54
+ const code = err.code;
55
+ if (typeof code === "string" && NETWORK_ERROR_CODES.has(code))
56
+ return true;
57
+ const cause = err.cause;
58
+ const causeCode = cause?.code;
59
+ return typeof causeCode === "string" && NETWORK_ERROR_CODES.has(causeCode);
60
+ }
14
61
  const HINTS = {
15
62
  401: 'Invalid or missing API key. Run "backbone auth login" to configure credentials.',
16
63
  402: "Billing limit reached. Check your plan limits or upgrade at the dashboard.",
@@ -2,7 +2,7 @@ import { homedir } from "node:os";
2
2
  import { join } from "node:path";
3
3
  import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
4
4
  import chalk from "chalk";
5
- const PKG_NAME = "@manfred-kunze-dev/backbone-cli";
5
+ const PKG_NAME = "@2kw/ai";
6
6
  const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 1 day
7
7
  const CACHE_DIR = join(homedir(), ".config", "backbone");
8
8
  const CACHE_FILE = join(CACHE_DIR, "update-check.json");
package/package.json CHANGED
@@ -1,7 +1,25 @@
1
1
  {
2
2
  "name": "@2kw/ai",
3
- "version": "5.2.0-dev.6",
4
- "description": "CLI for the 2kw.ai platform (engineering name: Backbone)",
3
+ "version": "5.2.0-dev.8",
4
+ "description": "CLI for 2kw.ai schema-driven document extraction, an OpenAI-compatible EU LLM gateway, transcription, prompts, datasets, and experiments from your terminal or agentic workflows. Ships as 2kw, backbone, and bb.",
5
+ "keywords": [
6
+ "cli",
7
+ "llm-gateway",
8
+ "ai-gateway",
9
+ "document-extraction",
10
+ "structured-data-extraction",
11
+ "pdf-extraction",
12
+ "openai-compatible",
13
+ "transcription",
14
+ "prompt-management",
15
+ "llm-evaluation",
16
+ "llm-observability",
17
+ "agentic-workflows",
18
+ "gdpr",
19
+ "eu-data-residency",
20
+ "2kw",
21
+ "backbone"
22
+ ],
5
23
  "type": "module",
6
24
  "main": "dist/index.js",
7
25
  "bin": {