@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
@@ -0,0 +1,59 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { basename, extname } from "node:path";
3
+ const MIME_TYPES = {
4
+ ".pdf": "application/pdf",
5
+ ".doc": "application/msword",
6
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
7
+ ".xls": "application/vnd.ms-excel",
8
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
9
+ ".ppt": "application/vnd.ms-powerpoint",
10
+ ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
11
+ ".odt": "application/vnd.oasis.opendocument.text",
12
+ ".ods": "application/vnd.oasis.opendocument.spreadsheet",
13
+ ".odp": "application/vnd.oasis.opendocument.presentation",
14
+ ".rtf": "application/rtf",
15
+ ".csv": "text/csv",
16
+ ".tsv": "text/tab-separated-values",
17
+ ".txt": "text/plain",
18
+ ".md": "text/markdown",
19
+ ".html": "text/html",
20
+ ".xml": "application/xml",
21
+ ".json": "application/json",
22
+ ".yaml": "application/yaml",
23
+ ".yml": "application/yaml",
24
+ ".png": "image/png",
25
+ ".jpg": "image/jpeg",
26
+ ".jpeg": "image/jpeg",
27
+ ".gif": "image/gif",
28
+ ".bmp": "image/bmp",
29
+ ".tiff": "image/tiff",
30
+ ".webp": "image/webp",
31
+ ".svg": "image/svg+xml",
32
+ ".eml": "message/rfc822",
33
+ ".msg": "application/vnd.ms-outlook",
34
+ ".epub": "application/epub+zip",
35
+ ".flac": "audio/flac",
36
+ ".mp3": "audio/mpeg",
37
+ ".mp4": "audio/mp4",
38
+ ".m4a": "audio/mp4",
39
+ ".ogg": "audio/ogg",
40
+ ".wav": "audio/wav",
41
+ ".webm": "audio/webm",
42
+ ".dxf": "image/vnd.dxf",
43
+ ".geo": "application/vnd.trumpf.geo",
44
+ };
45
+ export function getMimeType(filename) {
46
+ const ext = extname(filename).toLowerCase();
47
+ return MIME_TYPES[ext] ?? "application/octet-stream";
48
+ }
49
+ /**
50
+ * Read a local file and return a Blob suitable for FormData.
51
+ */
52
+ export function fileToBlob(filePath) {
53
+ const buffer = readFileSync(filePath);
54
+ const filename = basename(filePath);
55
+ const mimeType = getMimeType(filename);
56
+ const blob = new Blob([buffer], { type: mimeType });
57
+ return { blob, filename, mimeType };
58
+ }
59
+ //# sourceMappingURL=multipart.js.map
@@ -0,0 +1,29 @@
1
+ import type { Command } from "commander";
2
+ type AnyRecord = Record<string, any>;
3
+ /**
4
+ * Format and display a paginated list (Spring Data Page<T>).
5
+ */
6
+ export declare function formatPage(page: {
7
+ content?: AnyRecord[];
8
+ totalElements?: number;
9
+ number?: number;
10
+ totalPages?: number;
11
+ } | undefined, command: Command, columns: string[]): void;
12
+ /**
13
+ * Format and display a single record as key-value pairs.
14
+ */
15
+ export declare function formatDetail(record: AnyRecord | undefined, command: Command): void;
16
+ /**
17
+ * Format and display a list of records (non-paginated).
18
+ */
19
+ export declare function formatList(items: AnyRecord[] | undefined, command: Command, columns: string[]): void;
20
+ /**
21
+ * Display a success message.
22
+ */
23
+ export declare function formatSuccess(message: string, command: Command): void;
24
+ /**
25
+ * Run an async action with a spinner.
26
+ */
27
+ export declare function withSpinner<T>(text: string, action: () => Promise<T>): Promise<T>;
28
+ export {};
29
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1,107 @@
1
+ import chalk from "chalk";
2
+ import Table from "cli-table3";
3
+ import ora from "ora";
4
+ import { isJsonOutput } from "./config.js";
5
+ /**
6
+ * Format and display a paginated list (Spring Data Page<T>).
7
+ */
8
+ export function formatPage(page, command, columns) {
9
+ if (!page) {
10
+ console.error(chalk.yellow("No data returned."));
11
+ return;
12
+ }
13
+ if (isJsonOutput(command)) {
14
+ console.log(JSON.stringify(page, null, 2));
15
+ return;
16
+ }
17
+ if (!page.content || page.content.length === 0) {
18
+ console.log(chalk.dim("No results found."));
19
+ return;
20
+ }
21
+ const table = new Table({
22
+ head: columns.map((c) => chalk.cyan(c)),
23
+ wordWrap: true,
24
+ });
25
+ for (const item of page.content) {
26
+ table.push(columns.map((col) => formatValue(item[col])));
27
+ }
28
+ console.log(table.toString());
29
+ console.log(chalk.dim(`Page ${(page.number ?? 0) + 1} of ${page.totalPages ?? 0} (${page.totalElements ?? 0} total)`));
30
+ }
31
+ /**
32
+ * Format and display a single record as key-value pairs.
33
+ */
34
+ export function formatDetail(record, command) {
35
+ if (!record) {
36
+ console.error(chalk.yellow("No data returned."));
37
+ return;
38
+ }
39
+ if (isJsonOutput(command)) {
40
+ console.log(JSON.stringify(record, null, 2));
41
+ return;
42
+ }
43
+ const table = new Table();
44
+ for (const [key, value] of Object.entries(record)) {
45
+ table.push({ [chalk.cyan(key)]: formatValue(value) });
46
+ }
47
+ console.log(table.toString());
48
+ }
49
+ /**
50
+ * Format and display a list of records (non-paginated).
51
+ */
52
+ export function formatList(items, command, columns) {
53
+ if (!items) {
54
+ console.error(chalk.yellow("No data returned."));
55
+ return;
56
+ }
57
+ if (isJsonOutput(command)) {
58
+ console.log(JSON.stringify(items, null, 2));
59
+ return;
60
+ }
61
+ if (items.length === 0) {
62
+ console.log(chalk.dim("No results found."));
63
+ return;
64
+ }
65
+ const table = new Table({
66
+ head: columns.map((c) => chalk.cyan(c)),
67
+ wordWrap: true,
68
+ });
69
+ for (const item of items) {
70
+ table.push(columns.map((col) => formatValue(item[col])));
71
+ }
72
+ console.log(table.toString());
73
+ }
74
+ /**
75
+ * Display a success message.
76
+ */
77
+ export function formatSuccess(message, command) {
78
+ if (isJsonOutput(command)) {
79
+ console.log(JSON.stringify({ success: true, message }));
80
+ }
81
+ else {
82
+ console.log(chalk.green(message));
83
+ }
84
+ }
85
+ /**
86
+ * Run an async action with a spinner.
87
+ */
88
+ export async function withSpinner(text, action) {
89
+ const spinner = ora(text).start();
90
+ try {
91
+ const result = await action();
92
+ spinner.succeed();
93
+ return result;
94
+ }
95
+ catch (err) {
96
+ spinner.fail();
97
+ throw err;
98
+ }
99
+ }
100
+ function formatValue(value) {
101
+ if (value === null || value === undefined)
102
+ return chalk.dim("—");
103
+ if (typeof value === "object")
104
+ return JSON.stringify(value);
105
+ return String(value);
106
+ }
107
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1,21 @@
1
+ import type { Command } from "commander";
2
+ /**
3
+ * Add standard pagination options to a command.
4
+ * Spring Data uses page (0-indexed), size, and sort.
5
+ */
6
+ export declare function addPaginationOptions(cmd: Command): Command;
7
+ /** Parse pagination options into query params.
8
+ * Spring Data accepts flat page/size/sort params directly. We cast to satisfy
9
+ * the generated types which expect a nested `pageable` object. */
10
+ export declare function paginationParams(opts: {
11
+ page?: string;
12
+ size?: string;
13
+ sort?: string[];
14
+ }): {
15
+ pageable: {
16
+ page?: number;
17
+ size?: number;
18
+ sort?: string[];
19
+ };
20
+ };
21
+ //# sourceMappingURL=pagination.d.ts.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Add standard pagination options to a command.
3
+ * Spring Data uses page (0-indexed), size, and sort.
4
+ */
5
+ export function addPaginationOptions(cmd) {
6
+ return cmd
7
+ .option("-p, --page <number>", "Page number (0-indexed)", "0")
8
+ .option("--size <number>", "Page size", "20")
9
+ .option("--sort <fields...>", "Sort fields (e.g., name,asc)");
10
+ }
11
+ /** Parse pagination options into query params.
12
+ * Spring Data accepts flat page/size/sort params directly. We cast to satisfy
13
+ * the generated types which expect a nested `pageable` object. */
14
+ export function paginationParams(opts) {
15
+ return {
16
+ page: opts.page !== undefined ? parseInt(opts.page, 10) : undefined,
17
+ size: opts.size !== undefined ? parseInt(opts.size, 10) : undefined,
18
+ sort: opts.sort,
19
+ };
20
+ }
21
+ //# sourceMappingURL=pagination.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Sanitize a JSON Schema to be compatible with OpenAI's structured output requirements.
3
+ *
4
+ * OpenAI requires:
5
+ * - Every object type must have `additionalProperties: false`
6
+ * - Every object must list all properties in `required`
7
+ *
8
+ * This function recursively walks the schema and applies these constraints.
9
+ */
10
+ export declare function ensureOpenAiCompatible(schema: unknown): unknown;
11
+ //# sourceMappingURL=schema-compat.d.ts.map
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Sanitize a JSON Schema to be compatible with OpenAI's structured output requirements.
3
+ *
4
+ * OpenAI requires:
5
+ * - Every object type must have `additionalProperties: false`
6
+ * - Every object must list all properties in `required`
7
+ *
8
+ * This function recursively walks the schema and applies these constraints.
9
+ */
10
+ export function ensureOpenAiCompatible(schema) {
11
+ if (schema === null || schema === undefined || typeof schema !== "object") {
12
+ return schema;
13
+ }
14
+ if (Array.isArray(schema)) {
15
+ return schema.map(ensureOpenAiCompatible);
16
+ }
17
+ const obj = schema;
18
+ const result = {};
19
+ for (const [key, value] of Object.entries(obj)) {
20
+ if (key === "properties" && typeof value === "object" && value !== null) {
21
+ // Recurse into each property definition
22
+ const props = {};
23
+ for (const [propName, propValue] of Object.entries(value)) {
24
+ props[propName] = ensureOpenAiCompatible(propValue);
25
+ }
26
+ result[key] = props;
27
+ }
28
+ else if (key === "items") {
29
+ // Recurse into array items
30
+ result[key] = ensureOpenAiCompatible(value);
31
+ }
32
+ else if (key === "anyOf" || key === "oneOf" || key === "allOf") {
33
+ // Recurse into combinators
34
+ result[key] = Array.isArray(value) ? value.map(ensureOpenAiCompatible) : value;
35
+ }
36
+ else {
37
+ result[key] = value;
38
+ }
39
+ }
40
+ // If this node is an object type with properties, enforce OpenAI constraints
41
+ if (obj.type === "object" && obj.properties && typeof obj.properties === "object") {
42
+ result.additionalProperties = false;
43
+ // Ensure all properties are in required
44
+ const propNames = Object.keys(obj.properties);
45
+ const existing = Array.isArray(obj.required) ? obj.required : [];
46
+ const merged = [...new Set([...existing, ...propNames])];
47
+ result.required = merged;
48
+ }
49
+ return result;
50
+ }
51
+ //# sourceMappingURL=schema-compat.js.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Check for updates in the background. Call early so the fetch
3
+ * runs concurrently with the actual command, then call `notify()`
4
+ * after the command finishes to print the message (if any).
5
+ */
6
+ export declare function checkForUpdates(currentVersion: string): {
7
+ notify: () => void;
8
+ };
9
+ //# sourceMappingURL=update-notifier.d.ts.map
@@ -0,0 +1,96 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
4
+ import chalk from "chalk";
5
+ const PKG_NAME = "@manfred-kunze-dev/backbone-cli";
6
+ const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 1 day
7
+ const CACHE_DIR = join(homedir(), ".config", "backbone");
8
+ const CACHE_FILE = join(CACHE_DIR, "update-check.json");
9
+ function readCache() {
10
+ try {
11
+ return JSON.parse(readFileSync(CACHE_FILE, "utf-8"));
12
+ }
13
+ catch {
14
+ return null;
15
+ }
16
+ }
17
+ function writeCache(data) {
18
+ try {
19
+ mkdirSync(CACHE_DIR, { recursive: true });
20
+ writeFileSync(CACHE_FILE, JSON.stringify(data));
21
+ }
22
+ catch {
23
+ // Ignore write errors
24
+ }
25
+ }
26
+ async function fetchLatestVersion() {
27
+ try {
28
+ const controller = new AbortController();
29
+ const timeout = setTimeout(() => controller.abort(), 3000);
30
+ const res = await fetch(`https://registry.npmjs.org/${PKG_NAME}/latest`, { signal: controller.signal });
31
+ clearTimeout(timeout);
32
+ if (!res.ok)
33
+ return null;
34
+ const data = (await res.json());
35
+ return data.version ?? null;
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ function compareVersions(current, latest) {
42
+ const parse = (v) => v.replace(/^v/, "").split(".").map(Number);
43
+ const [cMaj, cMin, cPat] = parse(current);
44
+ const [lMaj, lMin, lPat] = parse(latest);
45
+ if (lMaj !== cMaj)
46
+ return lMaj > cMaj;
47
+ if (lMin !== cMin)
48
+ return lMin > cMin;
49
+ return lPat > cPat;
50
+ }
51
+ /**
52
+ * Check for updates in the background. Call early so the fetch
53
+ * runs concurrently with the actual command, then call `notify()`
54
+ * after the command finishes to print the message (if any).
55
+ */
56
+ export function checkForUpdates(currentVersion) {
57
+ let message = null;
58
+ // Skip for pre-release versions
59
+ if (currentVersion.includes("-")) {
60
+ return { notify: () => { } };
61
+ }
62
+ const cache = readCache();
63
+ const now = Date.now();
64
+ // Use cached result if recent enough
65
+ if (cache && now - cache.lastCheck < CHECK_INTERVAL_MS) {
66
+ if (compareVersions(currentVersion, cache.latestVersion)) {
67
+ message = formatMessage(currentVersion, cache.latestVersion);
68
+ }
69
+ return { notify: () => message && console.error(message) };
70
+ }
71
+ // Fire off the check in the background
72
+ const pending = fetchLatestVersion().then((latest) => {
73
+ if (latest) {
74
+ writeCache({ lastCheck: now, latestVersion: latest });
75
+ if (compareVersions(currentVersion, latest)) {
76
+ message = formatMessage(currentVersion, latest);
77
+ }
78
+ }
79
+ });
80
+ return {
81
+ notify: async () => {
82
+ await pending;
83
+ if (message)
84
+ console.error(message);
85
+ },
86
+ };
87
+ }
88
+ function formatMessage(current, latest) {
89
+ return [
90
+ "",
91
+ chalk.yellow(`Update available: ${chalk.dim(current)} → ${chalk.green(latest)}`),
92
+ chalk.yellow(`Run ${chalk.cyan(`npm i -g ${PKG_NAME}`)} to update`),
93
+ "",
94
+ ].join("\n");
95
+ }
96
+ //# sourceMappingURL=update-notifier.js.map
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@2kw/ai",
3
+ "version": "4.0.0-dev.2",
4
+ "description": "CLI for the 2kw.ai platform (engineering name: Backbone)",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "2kw": "dist/index.js",
9
+ "backbone": "dist/index.js",
10
+ "bb": "dist/index.js"
11
+ },
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsc --watch",
15
+ "start": "node dist/index.js",
16
+ "generate:spec": "tsx --env-file=.env openapi/scripts/fetch-spec.ts",
17
+ "generate:types": "openapi-typescript openapi/openapi.json -o src/generated/openapi.d.ts",
18
+ "generate": "npm run generate:spec && npm run generate:types",
19
+ "check:spec": "tsx --env-file=.env openapi/scripts/check-drift.ts",
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "dependencies": {
23
+ "chalk": "^5.6.2",
24
+ "cli-table3": "^0.6.5",
25
+ "commander": "^13.1.0",
26
+ "conf": "^13.1.0",
27
+ "openapi-fetch": "^0.13.5",
28
+ "ora": "^8.2.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^22.19.17",
32
+ "openapi-typescript": "^7.13.0",
33
+ "tsx": "^4.21.0",
34
+ "typescript": "^5.9.3"
35
+ },
36
+ "engines": {
37
+ "node": ">=18.20.8"
38
+ },
39
+ "license": "SEE LICENSE IN LICENSE",
40
+ "publishConfig": {
41
+ "registry": "https://registry.npmjs.org",
42
+ "access": "public"
43
+ },
44
+ "homepage": "https://2kw.ai",
45
+ "files": [
46
+ "dist/**/*.js",
47
+ "dist/**/*.d.ts"
48
+ ]
49
+ }