lmnr-cli 0.1.11 → 0.1.12

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
@@ -97,7 +97,7 @@ is the data API and carries **no port** — pass the port separately with `--por
97
97
  lmnr-cli sql schema --base-url http://localhost --port 8000
98
98
  ```
99
99
 
100
- `LMNR_FRONTEND_URL` (default `https://www.laminar.sh`), `LMNR_BASE_URL`
100
+ `LMNR_FRONTEND_URL` (default `https://laminar.sh`), `LMNR_BASE_URL`
101
101
  (default `https://api.lmnr.ai`), and `LMNR_HTTP_PORT` (default `443`) are also
102
102
  honored, and are auto-loaded from a `.env` / `.env.local` in the working directory.
103
103
 
package/dist/index.cjs CHANGED
@@ -52,7 +52,7 @@ let giget = require("giget");
52
52
  const errorMessage = (error) => error instanceof Error ? error.message : String(error);
53
53
  //#endregion
54
54
  //#region package.json
55
- var version$1 = "0.1.11";
55
+ var version$1 = "0.1.12";
56
56
  //#endregion
57
57
  //#region ../../node_modules/.pnpm/dotenv@17.4.2/node_modules/dotenv/lib/main.js
58
58
  var require_main = /* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -1207,7 +1207,7 @@ function outputJsonError(error, exitCode = 1) {
1207
1207
  }
1208
1208
  //#endregion
1209
1209
  //#region src/constants.ts
1210
- const DEFAULT_FRONTEND_URL$1 = "https://www.laminar.sh";
1210
+ const DEFAULT_FRONTEND_URL$1 = "https://laminar.sh";
1211
1211
  const DEFAULT_BASE_URL$1 = "https://api.lmnr.ai";
1212
1212
  //#endregion
1213
1213
  //#region src/utils/project-link.ts
@@ -2531,7 +2531,7 @@ function describeError$1(err) {
2531
2531
  }
2532
2532
  //#endregion
2533
2533
  //#region src/commands/setup/index.ts
2534
- const DEFAULT_FRONTEND_URL = "https://www.laminar.sh";
2534
+ const DEFAULT_FRONTEND_URL = "https://laminar.sh";
2535
2535
  const DEFAULT_BASE_URL = "https://api.lmnr.ai";
2536
2536
  const EXIT_NO_ACCESS = 4;
2537
2537
  const EXIT_LOGIN_FAILED = 6;
@@ -3005,7 +3005,7 @@ Examples:
3005
3005
  process.stdout.write(SQL_SCHEMA_HELP);
3006
3006
  });
3007
3007
  program.command("project").description("Work with Laminar projects").command("list").description("List the projects you can access (● = linked to this directory)").option("--base-url <url>", "Base URL for the Laminar API. Defaults to the logged-in session or LMNR_BASE_URL").option("--port <port>", "Port for the Laminar API. Defaults to 443", (val) => parseInt(val, 10)).option("--json", "Output structured JSON to stdout").action(withUserToken(handleProjectsList));
3008
- program.command("login").description("Authenticate the CLI via OAuth Device Flow").option("--frontend-url <url>", "Frontend URL (issuer). Defaults to https://www.laminar.sh or LMNR_FRONTEND_URL env variable").option("--no-browser", "Do not open the verification URL in a browser").action(async (options) => {
3008
+ program.command("login").description("Authenticate the CLI via OAuth Device Flow").option("--frontend-url <url>", "Frontend URL (issuer). Defaults to https://laminar.sh or LMNR_FRONTEND_URL env variable").option("--no-browser", "Do not open the verification URL in a browser").action(async (options) => {
3009
3009
  const result = await handleLogin(options);
3010
3010
  process.stderr.write(`${pc.green("✓")} Logged in as ${result.userEmail ?? "<unknown>"}.\n`);
3011
3011
  process.stderr.write(pc.dim("Client: lmnr-cli. Tokens stored at ~/.config/lmnr/credentials.json (mode 0600).\n"));
@@ -3014,7 +3014,7 @@ Examples:
3014
3014
  program.command("logout").description("Log out and remove the stored credentials").action(async () => {
3015
3015
  await handleLogout();
3016
3016
  });
3017
- program.command("setup").description("One-shot onboarding: login, select a project, write its key to .env, link .lmnr, and install the Laminar agent skill").option("--write-env", "Write LMNR_PROJECT_API_KEY to ./.env (default)", true).option("--no-write-env", "Do not write to ./.env").option("--project-id <id>", "Project to link when you can access more than one (disambiguates the project_ambiguous case in --json mode)").option("--json", "Emit a machine-readable JSON line on stdout").option("--no-browser", "Do not auto-open the device-flow URL").option("--frontend-url <url>", "Frontend URL (issuer). Defaults to LMNR_FRONTEND_URL or https://www.laminar.sh").option("--base-url <url>", "Base URL for the Laminar API. Defaults to LMNR_BASE_URL or https://api.lmnr.ai").action(async (options) => {
3017
+ program.command("setup").description("One-shot onboarding: login, select a project, write its key to .env, link .lmnr, and install the Laminar agent skill").option("--write-env", "Write LMNR_PROJECT_API_KEY to ./.env (default)", true).option("--no-write-env", "Do not write to ./.env").option("--project-id <id>", "Project to link when you can access more than one (disambiguates the project_ambiguous case in --json mode)").option("--json", "Emit a machine-readable JSON line on stdout").option("--no-browser", "Do not auto-open the device-flow URL").option("--frontend-url <url>", "Frontend URL (issuer). Defaults to LMNR_FRONTEND_URL or https://laminar.sh").option("--base-url <url>", "Base URL for the Laminar API. Defaults to LMNR_BASE_URL or https://api.lmnr.ai").action(async (options) => {
3018
3018
  await handleSetup(options);
3019
3019
  });
3020
3020
  program.command("trace").description("Inspect and operate on traces").option("--project-id <id>", "Target project id. Defaults to the linked .lmnr/project.json. Run `lmnr-cli login` first.").option("--base-url <url>", "Base URL for the Laminar API. Defaults to https://api.lmnr.ai or LMNR_BASE_URL env variable").option("--port <port>", "Port for the Laminar API. Defaults to 443", (val) => parseInt(val, 10)).option("--json", "Output structured JSON to stdout").command("append-note").description("Append a free-text note to a trace (stored in trace metadata)").argument("<trace-id>", "Trace ID (UUID or 32-char OTel hex trace id)").argument("<note>", "Note text (may contain markdown)").action(withProjectClient(handleTraceAppendNote)).addHelpText("after", `
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["fs","path","crypto","initializeLogger","logger$4","path","logger$3","DEFAULT_DATASET_PUSH_BATCH_SIZE","logger$2","logger$1","logger","DEFAULT_FRONTEND_URL","DEFAULT_BASE_URL","trimSlash","logger","logger","fs","readFile","Table","logger","logger","pick","DEFAULT_FRONTEND_URL","trimSlash","trimSlash","DEFAULT_BASE_URL","execFile","describeError","version","Command","version"],"sources":["../../types/dist/index.mjs","../package.json","../../../node_modules/.pnpm/dotenv@17.4.2/node_modules/dotenv/lib/main.js","../../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/stringify.js","../../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/rng.js","../../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/v4.js","../../client/dist/index.mjs","../src/utils/logger.ts","../src/utils/output.ts","../src/constants.ts","../src/utils/project-link.ts","../src/auth/credentials.ts","../src/auth/device.ts","../src/auth/resolve.ts","../src/auth/client.ts","../src/auth/with-client.ts","../src/utils/file.ts","../src/utils/table.ts","../src/commands/dataset/index.ts","../src/utils/trace-note.ts","../src/commands/debug/index.ts","../src/utils/colors.ts","../src/commands/login/index.ts","../src/commands/logout/index.ts","../src/commands/project/index.ts","../src/auth/project-id.ts","../src/utils/env-file.ts","../src/skill/laminar-skill.ts","../src/skill/fetch-skill.ts","../src/utils/install-skill.ts","../src/commands/setup/index.ts","../src/commands/sql/index.ts","../src/commands/sql/schema.ts","../src/commands/trace/index.ts","../src/index.ts"],"sourcesContent":["//#region src/tracing.ts\n/**\n* Tracing levels to conditionally disable tracing.\n*\n* OFF - No tracing is sent.\n* META_ONLY - Only metadata is sent (e.g. tokens, costs, etc.).\n* ALL - All data is sent.\n*/\nlet TracingLevel = /* @__PURE__ */ function(TracingLevel) {\n\tTracingLevel[\"OFF\"] = \"off\";\n\tTracingLevel[\"META_ONLY\"] = \"meta_only\";\n\tTracingLevel[\"ALL\"] = \"all\";\n\treturn TracingLevel;\n}({});\n//#endregion\n//#region src/utils.ts\nconst errorMessage = (error) => error instanceof Error ? error.message : String(error);\n//#endregion\nexport { TracingLevel, errorMessage };\n\n//# sourceMappingURL=index.mjs.map","","const fs = require('fs')\nconst path = require('path')\nconst os = require('os')\nconst crypto = require('crypto')\n\n// Array of tips to display randomly\nconst TIPS = [\n '◈ encrypted .env [www.dotenvx.com]',\n '◈ secrets for agents [www.dotenvx.com]',\n '⌁ auth for agents [www.vestauth.com]',\n '⌘ custom filepath { path: \\'/custom/path/.env\\' }',\n '⌘ enable debugging { debug: true }',\n '⌘ override existing { override: true }',\n '⌘ suppress logs { quiet: true }',\n '⌘ multiple files { path: [\\'.env.local\\', \\'.env\\'] }'\n]\n\n// Get a random tip from the tips array\nfunction _getRandomTip () {\n return TIPS[Math.floor(Math.random() * TIPS.length)]\n}\n\nfunction parseBoolean (value) {\n if (typeof value === 'string') {\n return !['false', '0', 'no', 'off', ''].includes(value.toLowerCase())\n }\n return Boolean(value)\n}\n\nfunction supportsAnsi () {\n return process.stdout.isTTY // && process.env.TERM !== 'dumb'\n}\n\nfunction dim (text) {\n return supportsAnsi() ? `\\x1b[2m${text}\\x1b[0m` : text\n}\n\nconst LINE = /(?:^|^)\\s*(?:export\\s+)?([\\w.-]+)(?:\\s*=\\s*?|:\\s+?)(\\s*'(?:\\\\'|[^'])*'|\\s*\"(?:\\\\\"|[^\"])*\"|\\s*`(?:\\\\`|[^`])*`|[^#\\r\\n]+)?\\s*(?:#.*)?(?:$|$)/mg\n\n// Parse src into an Object\nfunction parse (src) {\n const obj = {}\n\n // Convert buffer to string\n let lines = src.toString()\n\n // Convert line breaks to same format\n lines = lines.replace(/\\r\\n?/mg, '\\n')\n\n let match\n while ((match = LINE.exec(lines)) != null) {\n const key = match[1]\n\n // Default undefined or null to empty string\n let value = (match[2] || '')\n\n // Remove whitespace\n value = value.trim()\n\n // Check if double quoted\n const maybeQuote = value[0]\n\n // Remove surrounding quotes\n value = value.replace(/^(['\"`])([\\s\\S]*)\\1$/mg, '$2')\n\n // Expand newlines if double quoted\n if (maybeQuote === '\"') {\n value = value.replace(/\\\\n/g, '\\n')\n value = value.replace(/\\\\r/g, '\\r')\n }\n\n // Add to object\n obj[key] = value\n }\n\n return obj\n}\n\nfunction _parseVault (options) {\n options = options || {}\n\n const vaultPath = _vaultPath(options)\n options.path = vaultPath // parse .env.vault\n const result = DotenvModule.configDotenv(options)\n if (!result.parsed) {\n const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`)\n err.code = 'MISSING_DATA'\n throw err\n }\n\n // handle scenario for comma separated keys - for use with key rotation\n // example: DOTENV_KEY=\"dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=prod,dotenv://:key_7890@dotenvx.com/vault/.env.vault?environment=prod\"\n const keys = _dotenvKey(options).split(',')\n const length = keys.length\n\n let decrypted\n for (let i = 0; i < length; i++) {\n try {\n // Get full key\n const key = keys[i].trim()\n\n // Get instructions for decrypt\n const attrs = _instructions(result, key)\n\n // Decrypt\n decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key)\n\n break\n } catch (error) {\n // last key\n if (i + 1 >= length) {\n throw error\n }\n // try next key\n }\n }\n\n // Parse decrypted .env string\n return DotenvModule.parse(decrypted)\n}\n\nfunction _warn (message) {\n console.error(`⚠ ${message}`)\n}\n\nfunction _debug (message) {\n console.log(`┆ ${message}`)\n}\n\nfunction _log (message) {\n console.log(`◇ ${message}`)\n}\n\nfunction _dotenvKey (options) {\n // prioritize developer directly setting options.DOTENV_KEY\n if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {\n return options.DOTENV_KEY\n }\n\n // secondary infra already contains a DOTENV_KEY environment variable\n if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {\n return process.env.DOTENV_KEY\n }\n\n // fallback to empty string\n return ''\n}\n\nfunction _instructions (result, dotenvKey) {\n // Parse DOTENV_KEY. Format is a URI\n let uri\n try {\n uri = new URL(dotenvKey)\n } catch (error) {\n if (error.code === 'ERR_INVALID_URL') {\n const err = new Error('INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development')\n err.code = 'INVALID_DOTENV_KEY'\n throw err\n }\n\n throw error\n }\n\n // Get decrypt key\n const key = uri.password\n if (!key) {\n const err = new Error('INVALID_DOTENV_KEY: Missing key part')\n err.code = 'INVALID_DOTENV_KEY'\n throw err\n }\n\n // Get environment\n const environment = uri.searchParams.get('environment')\n if (!environment) {\n const err = new Error('INVALID_DOTENV_KEY: Missing environment part')\n err.code = 'INVALID_DOTENV_KEY'\n throw err\n }\n\n // Get ciphertext payload\n const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`\n const ciphertext = result.parsed[environmentKey] // DOTENV_VAULT_PRODUCTION\n if (!ciphertext) {\n const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`)\n err.code = 'NOT_FOUND_DOTENV_ENVIRONMENT'\n throw err\n }\n\n return { ciphertext, key }\n}\n\nfunction _vaultPath (options) {\n let possibleVaultPath = null\n\n if (options && options.path && options.path.length > 0) {\n if (Array.isArray(options.path)) {\n for (const filepath of options.path) {\n if (fs.existsSync(filepath)) {\n possibleVaultPath = filepath.endsWith('.vault') ? filepath : `${filepath}.vault`\n }\n }\n } else {\n possibleVaultPath = options.path.endsWith('.vault') ? options.path : `${options.path}.vault`\n }\n } else {\n possibleVaultPath = path.resolve(process.cwd(), '.env.vault')\n }\n\n if (fs.existsSync(possibleVaultPath)) {\n return possibleVaultPath\n }\n\n return null\n}\n\nfunction _resolveHome (envPath) {\n return envPath[0] === '~' ? path.join(os.homedir(), envPath.slice(1)) : envPath\n}\n\nfunction _configVault (options) {\n const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || (options && options.debug))\n const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || (options && options.quiet))\n\n if (debug || !quiet) {\n _log('loading env from encrypted .env.vault')\n }\n\n const parsed = DotenvModule._parseVault(options)\n\n let processEnv = process.env\n if (options && options.processEnv != null) {\n processEnv = options.processEnv\n }\n\n DotenvModule.populate(processEnv, parsed, options)\n\n return { parsed }\n}\n\nfunction configDotenv (options) {\n const dotenvPath = path.resolve(process.cwd(), '.env')\n let encoding = 'utf8'\n let processEnv = process.env\n if (options && options.processEnv != null) {\n processEnv = options.processEnv\n }\n let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || (options && options.debug))\n let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || (options && options.quiet))\n\n if (options && options.encoding) {\n encoding = options.encoding\n } else {\n if (debug) {\n _debug('no encoding is specified (UTF-8 is used by default)')\n }\n }\n\n let optionPaths = [dotenvPath] // default, look for .env\n if (options && options.path) {\n if (!Array.isArray(options.path)) {\n optionPaths = [_resolveHome(options.path)]\n } else {\n optionPaths = [] // reset default\n for (const filepath of options.path) {\n optionPaths.push(_resolveHome(filepath))\n }\n }\n }\n\n // Build the parsed data in a temporary object (because we need to return it). Once we have the final\n // parsed data, we will combine it with process.env (or options.processEnv if provided).\n let lastError\n const parsedAll = {}\n for (const path of optionPaths) {\n try {\n // Specifying an encoding returns a string instead of a buffer\n const parsed = DotenvModule.parse(fs.readFileSync(path, { encoding }))\n\n DotenvModule.populate(parsedAll, parsed, options)\n } catch (e) {\n if (debug) {\n _debug(`failed to load ${path} ${e.message}`)\n }\n lastError = e\n }\n }\n\n const populated = DotenvModule.populate(processEnv, parsedAll, options)\n\n // handle user settings DOTENV_CONFIG_ options inside .env file(s)\n debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug)\n quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet)\n\n if (debug || !quiet) {\n const keysCount = Object.keys(populated).length\n const shortPaths = []\n for (const filePath of optionPaths) {\n try {\n const relative = path.relative(process.cwd(), filePath)\n shortPaths.push(relative)\n } catch (e) {\n if (debug) {\n _debug(`failed to load ${filePath} ${e.message}`)\n }\n lastError = e\n }\n }\n\n _log(`injected env (${keysCount}) from ${shortPaths.join(',')} ${dim(`// tip: ${_getRandomTip()}`)}`)\n }\n\n if (lastError) {\n return { parsed: parsedAll, error: lastError }\n } else {\n return { parsed: parsedAll }\n }\n}\n\n// Populates process.env from .env file\nfunction config (options) {\n // fallback to original dotenv if DOTENV_KEY is not set\n if (_dotenvKey(options).length === 0) {\n return DotenvModule.configDotenv(options)\n }\n\n const vaultPath = _vaultPath(options)\n\n // dotenvKey exists but .env.vault file does not exist\n if (!vaultPath) {\n _warn(`you set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}`)\n\n return DotenvModule.configDotenv(options)\n }\n\n return DotenvModule._configVault(options)\n}\n\nfunction decrypt (encrypted, keyStr) {\n const key = Buffer.from(keyStr.slice(-64), 'hex')\n let ciphertext = Buffer.from(encrypted, 'base64')\n\n const nonce = ciphertext.subarray(0, 12)\n const authTag = ciphertext.subarray(-16)\n ciphertext = ciphertext.subarray(12, -16)\n\n try {\n const aesgcm = crypto.createDecipheriv('aes-256-gcm', key, nonce)\n aesgcm.setAuthTag(authTag)\n return `${aesgcm.update(ciphertext)}${aesgcm.final()}`\n } catch (error) {\n const isRange = error instanceof RangeError\n const invalidKeyLength = error.message === 'Invalid key length'\n const decryptionFailed = error.message === 'Unsupported state or unable to authenticate data'\n\n if (isRange || invalidKeyLength) {\n const err = new Error('INVALID_DOTENV_KEY: It must be 64 characters long (or more)')\n err.code = 'INVALID_DOTENV_KEY'\n throw err\n } else if (decryptionFailed) {\n const err = new Error('DECRYPTION_FAILED: Please check your DOTENV_KEY')\n err.code = 'DECRYPTION_FAILED'\n throw err\n } else {\n throw error\n }\n }\n}\n\n// Populate process.env with parsed values\nfunction populate (processEnv, parsed, options = {}) {\n const debug = Boolean(options && options.debug)\n const override = Boolean(options && options.override)\n const populated = {}\n\n if (typeof parsed !== 'object') {\n const err = new Error('OBJECT_REQUIRED: Please check the processEnv argument being passed to populate')\n err.code = 'OBJECT_REQUIRED'\n throw err\n }\n\n // Set process.env\n for (const key of Object.keys(parsed)) {\n if (Object.prototype.hasOwnProperty.call(processEnv, key)) {\n if (override === true) {\n processEnv[key] = parsed[key]\n populated[key] = parsed[key]\n }\n\n if (debug) {\n if (override === true) {\n _debug(`\"${key}\" is already defined and WAS overwritten`)\n } else {\n _debug(`\"${key}\" is already defined and was NOT overwritten`)\n }\n }\n } else {\n processEnv[key] = parsed[key]\n populated[key] = parsed[key]\n }\n }\n\n return populated\n}\n\nconst DotenvModule = {\n configDotenv,\n _configVault,\n _parseVault,\n config,\n decrypt,\n parse,\n populate\n}\n\nmodule.exports.configDotenv = DotenvModule.configDotenv\nmodule.exports._configVault = DotenvModule._configVault\nmodule.exports._parseVault = DotenvModule._parseVault\nmodule.exports.config = DotenvModule.config\nmodule.exports.decrypt = DotenvModule.decrypt\nmodule.exports.parse = DotenvModule.parse\nmodule.exports.populate = DotenvModule.populate\n\nmodule.exports = DotenvModule\n","import validate from './validate.js';\nconst byteToHex = [];\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).slice(1));\n}\nexport function unsafeStringify(arr, offset = 0) {\n return (byteToHex[arr[offset + 0]] +\n byteToHex[arr[offset + 1]] +\n byteToHex[arr[offset + 2]] +\n byteToHex[arr[offset + 3]] +\n '-' +\n byteToHex[arr[offset + 4]] +\n byteToHex[arr[offset + 5]] +\n '-' +\n byteToHex[arr[offset + 6]] +\n byteToHex[arr[offset + 7]] +\n '-' +\n byteToHex[arr[offset + 8]] +\n byteToHex[arr[offset + 9]] +\n '-' +\n byteToHex[arr[offset + 10]] +\n byteToHex[arr[offset + 11]] +\n byteToHex[arr[offset + 12]] +\n byteToHex[arr[offset + 13]] +\n byteToHex[arr[offset + 14]] +\n byteToHex[arr[offset + 15]]).toLowerCase();\n}\nfunction stringify(arr, offset = 0) {\n const uuid = unsafeStringify(arr, offset);\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n return uuid;\n}\nexport default stringify;\n","const rnds8 = new Uint8Array(16);\nexport default function rng() {\n return crypto.getRandomValues(rnds8);\n}\n","import rng from './rng.js';\nimport { unsafeStringify } from './stringify.js';\nfunction v4(options, buf, offset) {\n if (!buf && !options && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return _v4(options, buf, offset);\n}\nfunction _v4(options, buf, offset) {\n options = options || {};\n const rnds = options.random ?? options.rng?.() ?? rng();\n if (rnds.length < 16) {\n throw new Error('Random bytes length must be >= 16');\n }\n rnds[6] = (rnds[6] & 0x0f) | 0x40;\n rnds[8] = (rnds[8] & 0x3f) | 0x80;\n if (buf) {\n offset = offset || 0;\n if (offset < 0 || offset + 16 > buf.length) {\n throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);\n }\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n return buf;\n }\n return unsafeStringify(rnds);\n}\nexport default v4;\n","import { config } from \"dotenv\";\nimport * as path from \"path\";\nimport pino from \"pino\";\nimport { PinoPretty } from \"pino-pretty\";\nimport { v4 } from \"uuid\";\nimport { errorMessage } from \"@lmnr-ai/types\";\n//#region package.json\nvar version = \"0.8.29\";\n//#endregion\n//#region src/version.ts\nfunction getLangVersion() {\n\tif (typeof process !== \"undefined\" && process.versions && process.versions.node) return `node-${process.versions.node}`;\n\tif (typeof navigator !== \"undefined\" && navigator.userAgent) return `browser-${navigator.userAgent}`;\n\treturn null;\n}\n//#endregion\n//#region src/resources/index.ts\nvar BaseResource = class {\n\tconstructor(baseHttpUrl, auth) {\n\t\tthis.baseHttpUrl = baseHttpUrl;\n\t\tthis.auth = auth;\n\t\tthis.credential = auth.type === \"apiKey\" ? auth.key : auth.token;\n\t}\n\t/** API path prefix: `/v1/cli` for CLI user-token auth, `/v1` otherwise. */\n\tget apiPrefix() {\n\t\treturn this.auth.type === \"userToken\" ? \"/v1/cli\" : \"/v1\";\n\t}\n\theaders() {\n\t\treturn {\n\t\t\tAuthorization: `Bearer ${this.credential}`,\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\tAccept: \"application/json\",\n\t\t\t...this.auth.type === \"userToken\" ? { \"x-lmnr-project-id\": this.auth.projectId } : {}\n\t\t};\n\t}\n\tasync handleError(response) {\n\t\tconst errorMsg = await response.text();\n\t\tthrow new Error(`${response.status} ${errorMsg}`);\n\t}\n};\n//#endregion\n//#region src/resources/browser-events.ts\nvar BrowserEventsResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\tasync send({ sessionId, traceId, events }) {\n\t\tconst payload = {\n\t\t\tsessionId,\n\t\t\ttraceId,\n\t\t\tevents,\n\t\t\tsource: getLangVersion() ?? \"javascript\",\n\t\t\tsdkVersion: version\n\t\t};\n\t\tconst jsonString = JSON.stringify(payload);\n\t\tconst compressedStream = new Blob([jsonString], { type: \"application/json\" }).stream().pipeThrough(new CompressionStream(\"gzip\"));\n\t\tconst compressedData = await new Response(compressedStream).arrayBuffer();\n\t\tconst response = await fetch(this.baseHttpUrl + \"/v1/browser-sessions/events\", {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t...this.headers(),\n\t\t\t\t\"Content-Encoding\": \"gzip\"\n\t\t\t},\n\t\t\tbody: compressedData\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n};\n//#endregion\n//#region src/resources/cli.ts\n/**\n* User-scoped CLI endpoints that don't target a specific project. Authed by the\n* BetterAuth user JWT (the `credential`); deliberately does NOT send an\n* `x-lmnr-project-id` header (these routes are project discovery, pre-selection).\n*\n* Discovery exception: this resource always hits `/v1/cli/projects` with the\n* bare bearer and overrides `BaseResource.headers()`/`apiPrefix`, so it works\n* even when constructed with a `userToken` auth that has no real project id yet.\n*/\nvar CliResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/** Workspaces + projects the authenticated user can access. */\n\tasync listProjects() {\n\t\tconst response = await fetch(`${this.baseHttpUrl}/v1/cli/projects`, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${this.credential}`,\n\t\t\t\tAccept: \"application/json\"\n\t\t\t}\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\tconst body = await response.json();\n\t\treturn Array.isArray(body?.projects) ? body.projects : [];\n\t}\n};\n//#endregion\n//#region src/utils.ts\nfunction initializeLogger(options) {\n\tconst colorize = options?.colorize ?? true;\n\tconst level = options?.level ?? process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() ?? \"info\";\n\treturn pino({ level }, PinoPretty({\n\t\tcolorize,\n\t\tminimumLevel: level\n\t}));\n}\nconst logger$4 = initializeLogger();\nconst isStringUUID = (id) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);\nconst newUUID = () => {\n\tif (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") return crypto.randomUUID();\n\telse return v4();\n};\nconst otelSpanIdToUUID = (spanId) => {\n\tlet id = spanId.toLowerCase();\n\tif (id.startsWith(\"0x\")) id = id.slice(2);\n\tif (id.length !== 16) logger$4.warn(`Span ID ${spanId} is not 16 hex chars long. This is not a valid OpenTelemetry span ID.`);\n\tif (!/^[0-9a-f]+$/.test(id)) {\n\t\tlogger$4.error(`Span ID ${spanId} is not a valid hex string. Generating a random UUID instead.`);\n\t\treturn newUUID();\n\t}\n\treturn id.padStart(32, \"0\").replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, \"$1-$2-$3-$4-$5\");\n};\nconst otelTraceIdToUUID = (traceId) => {\n\tlet id = traceId.toLowerCase();\n\tif (id.startsWith(\"0x\")) id = id.slice(2);\n\tif (id.length !== 32) logger$4.warn(`Trace ID ${traceId} is not 32 hex chars long. This is not a valid OpenTelemetry trace ID.`);\n\tif (!/^[0-9a-f]+$/.test(id)) {\n\t\tlogger$4.error(`Trace ID ${traceId} is not a valid hex string. Generating a random UUID instead.`);\n\t\treturn newUUID();\n\t}\n\treturn id.replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, \"$1-$2-$3-$4-$5\");\n};\nconst slicePayload = (value, length) => {\n\tif (value === null || value === void 0) return value;\n\tconst str = JSON.stringify(value);\n\tif (str.length <= length) return value;\n\treturn str.slice(0, length) + \"...\";\n};\nconst loadEnv = (options) => {\n\tconst nodeEnv = process.env.NODE_ENV || \"development\";\n\tconst envDir = process.cwd();\n\tconst envFiles = [\n\t\t\".env\",\n\t\t\".env.local\",\n\t\t`.env.${nodeEnv}`,\n\t\t`.env.${nodeEnv}.local`\n\t];\n\tconst logLevel = process.env.LMNR_LOG_LEVEL ?? \"info\";\n\tconst verbose = [\"debug\", \"trace\"].includes(logLevel.trim().toLowerCase());\n\tconst quiet = options?.quiet ?? !verbose;\n\tconfig({\n\t\tpath: options?.paths ?? envFiles.map((envFile) => path.resolve(envDir, envFile)),\n\t\tquiet\n\t});\n};\n//#endregion\n//#region src/resources/datasets.ts\nconst logger$3 = initializeLogger();\nconst DEFAULT_DATASET_PULL_LIMIT = 100;\nconst DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;\nvar DatasetsResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/**\n\t* List all datasets.\n\t*\n\t* @returns {Promise<Dataset[]>} Array of datasets\n\t*/\n\tasync listDatasets() {\n\t\tconst response = await fetch(this.baseHttpUrl + this.apiPrefix + \"/datasets\", {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: this.headers()\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn response.json();\n\t}\n\t/**\n\t* Get a dataset by name.\n\t*\n\t* @param {string} name - Name of the dataset\n\t* @returns {Promise<Dataset[]>} Array of datasets with matching name\n\t*/\n\tasync getDatasetByName(name) {\n\t\tconst params = new URLSearchParams({ name });\n\t\tconst response = await fetch(this.baseHttpUrl + `${this.apiPrefix}/datasets?${params.toString()}`, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: this.headers()\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn response.json();\n\t}\n\t/**\n\t* Push datapoints to a dataset.\n\t*\n\t* @param {Object} options - Push options\n\t* @param {Datapoint<D, T>[]} options.points - Datapoints to push\n\t* @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n\t* @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n\t* @param {number} [options.batchSize] - Batch size for pushing (default: 100)\n\t* @param {boolean} [options.createDataset] - Whether to create the dataset if it doesn't exist\n\t* @returns {Promise<PushDatapointsResponse | undefined>}\n\t*/\n\tasync push({ points, name, id, batchSize = DEFAULT_DATASET_PUSH_BATCH_SIZE, createDataset = false }) {\n\t\tif (!name && !id) throw new Error(\"Either name or id must be provided\");\n\t\tif (name && id) throw new Error(\"Only one of name or id must be provided\");\n\t\tif (createDataset && !name) throw new Error(\"Name must be provided when creating a new dataset\");\n\t\tconst identifier = name ? { name } : { datasetId: id };\n\t\tconst totalBatches = Math.ceil(points.length / batchSize);\n\t\tlet response;\n\t\tfor (let i = 0; i < points.length; i += batchSize) {\n\t\t\tconst batchNum = Math.floor(i / batchSize) + 1;\n\t\t\tlogger$3.debug(`Pushing batch ${batchNum} of ${totalBatches}`);\n\t\t\tconst batch = points.slice(i, i + batchSize);\n\t\t\tconst fetchResponse = await fetch(this.baseHttpUrl + this.apiPrefix + \"/datasets/datapoints\", {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: this.headers(),\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t...identifier,\n\t\t\t\t\tdatapoints: batch.map((point) => ({\n\t\t\t\t\t\tdata: point.data,\n\t\t\t\t\t\ttarget: point.target ?? {},\n\t\t\t\t\t\tmetadata: point.metadata ?? {}\n\t\t\t\t\t})),\n\t\t\t\t\tcreateDataset\n\t\t\t\t})\n\t\t\t});\n\t\t\tif (fetchResponse.status !== 200 && fetchResponse.status !== 201) await this.handleError(fetchResponse);\n\t\t\tresponse = await fetchResponse.json();\n\t\t}\n\t\treturn response;\n\t}\n\t/**\n\t* Pull datapoints from a dataset.\n\t*\n\t* @param {Object} options - Pull options\n\t* @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n\t* @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n\t* @param {number} [options.limit] - Maximum number of datapoints to return (default: 100)\n\t* @param {number} [options.offset] - Offset for pagination (default: 0)\n\t* @returns {Promise<GetDatapointsResponse<D, T>>}\n\t*/\n\tasync pull({ name, id, limit = DEFAULT_DATASET_PULL_LIMIT, offset = 0 }) {\n\t\tif (!name && !id) throw new Error(\"Either name or id must be provided\");\n\t\tif (name && id) throw new Error(\"Only one of name or id must be provided\");\n\t\tconst paramsObj = {\n\t\t\toffset: offset.toString(),\n\t\t\tlimit: limit.toString()\n\t\t};\n\t\tif (name) paramsObj.name = name;\n\t\telse paramsObj.datasetId = id;\n\t\tconst params = new URLSearchParams(paramsObj);\n\t\tconst response = await fetch(this.baseHttpUrl + `${this.apiPrefix}/datasets/datapoints?${params.toString()}`, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: this.headers()\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn response.json();\n\t}\n};\n//#endregion\n//#region src/resources/evals.ts\nconst logger$2 = initializeLogger();\nconst INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16e6;\nvar EvalsResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/**\n\t* Initialize an evaluation.\n\t*\n\t* @param {string} name - Name of the evaluation\n\t* @param {string} groupName - Group name of the evaluation\n\t* @param {Record<string, any>} metadata - Optional metadata\n\t* @returns {Promise<InitEvaluationResponse>} Response from the evaluation initialization\n\t*/\n\tasync init(name, groupName, metadata) {\n\t\tconst response = await fetch(this.baseHttpUrl + \"/v1/evals\", {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify({\n\t\t\t\tname: name ?? null,\n\t\t\t\tgroupName: groupName ?? null,\n\t\t\t\tmetadata: metadata ?? null\n\t\t\t})\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn response.json();\n\t}\n\t/**\n\t* Create a new evaluation and return its ID.\n\t*\n\t* @param {string} [name] - Optional name of the evaluation\n\t* @param {string} [groupName] - An identifier to group evaluations\n\t* @param {Record<string, any>} [metadata] - Optional metadata\n\t* @returns {Promise<StringUUID>} The evaluation ID\n\t*/\n\tasync create(args) {\n\t\treturn (await this.init(args?.name, args?.groupName, args?.metadata)).id;\n\t}\n\t/**\n\t* Create a new evaluation and return its ID.\n\t* @deprecated use `create` instead.\n\t*/\n\tasync createEvaluation(name, groupName, metadata) {\n\t\treturn (await this.init(name, groupName, metadata)).id;\n\t}\n\t/**\n\t* Create a datapoint for an evaluation.\n\t*\n\t* @param {Object} options - Create datapoint options\n\t* @param {string} options.evalId - The evaluation ID\n\t* @param {D} options.data - The input data for the executor\n\t* @param {T} [options.target] - The target/expected output for evaluators\n\t* @param {Record<string, any>} [options.metadata] - Optional metadata\n\t* @param {number} [options.index] - Optional index of the datapoint\n\t* @param {string} [options.traceId] - Optional trace ID\n\t* @returns {Promise<StringUUID>} The datapoint ID\n\t*/\n\tasync createDatapoint({ evalId, data, target, metadata, index, traceId }) {\n\t\tconst datapointId = newUUID();\n\t\tconst partialDatapoint = {\n\t\t\tid: datapointId,\n\t\t\tdata,\n\t\t\ttarget,\n\t\t\tindex: index ?? 0,\n\t\t\ttraceId: traceId ?? newUUID(),\n\t\t\texecutorSpanId: newUUID(),\n\t\t\tmetadata\n\t\t};\n\t\tawait this.saveDatapoints({\n\t\t\tevalId,\n\t\t\tdatapoints: [partialDatapoint]\n\t\t});\n\t\treturn datapointId;\n\t}\n\t/**\n\t* Update a datapoint with evaluation results.\n\t*\n\t* @param {Object} options - Update datapoint options\n\t* @param {string} options.evalId - The evaluation ID\n\t* @param {string} options.datapointId - The datapoint ID\n\t* @param {Record<string, number>} options.scores - The scores\n\t* @param {O} [options.executorOutput] - The executor output\n\t* @returns {Promise<void>}\n\t*/\n\tasync updateDatapoint({ evalId, datapointId, scores, executorOutput }) {\n\t\tconst response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints/${datapointId}`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify({\n\t\t\t\texecutorOutput,\n\t\t\t\tscores\n\t\t\t})\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n\t/**\n\t* Save evaluation datapoints.\n\t*\n\t* @param {Object} options - Save datapoints options\n\t* @param {string} options.evalId - ID of the evaluation\n\t* @param {EvaluationDatapoint<D, T, O>[]} options.datapoints - Datapoint to add\n\t* @param {string} [options.groupName] - Group name of the evaluation\n\t* @returns {Promise<void>} Response from the datapoint addition\n\t*/\n\tasync saveDatapoints({ evalId, datapoints, groupName }) {\n\t\tconst response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify({\n\t\t\t\tpoints: datapoints.map((d) => ({\n\t\t\t\t\t...d,\n\t\t\t\t\tdata: slicePayload(d.data, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n\t\t\t\t\ttarget: slicePayload(d.target, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n\t\t\t\t\texecutorOutput: slicePayload(d.executorOutput, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH)\n\t\t\t\t})),\n\t\t\t\tgroupName: groupName ?? null\n\t\t\t})\n\t\t});\n\t\tif (response.status === 413) return await this.retrySaveDatapoints({\n\t\t\tevalId,\n\t\t\tdatapoints,\n\t\t\tgroupName\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n\t/**\n\t* Get evaluation datapoints.\n\t*\n\t* @deprecated Use `client.datasets.pull()` instead.\n\t* @param {Object} options - Get datapoints options\n\t* @param {string} options.datasetName - Name of the dataset\n\t* @param {number} options.offset - Offset at which to start the query\n\t* @param {number} options.limit - Maximum number of datapoints to return\n\t* @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval\n\t*/\n\tasync getDatapoints({ datasetName, offset, limit }) {\n\t\tlogger$2.warn(\"evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.\");\n\t\tconst params = new URLSearchParams({\n\t\t\tname: datasetName,\n\t\t\toffset: offset.toString(),\n\t\t\tlimit: limit.toString()\n\t\t});\n\t\tconst response = await fetch(this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: this.headers()\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn await response.json();\n\t}\n\tasync retrySaveDatapoints({ evalId, datapoints, groupName, maxRetries = 25, initialLength = INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH }) {\n\t\tlet length = initialLength;\n\t\tlet lastResponse = null;\n\t\tfor (let i = 0; i < maxRetries; i++) {\n\t\t\tlogger$2.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);\n\t\t\tconst response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: this.headers(),\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tpoints: datapoints.map((d) => ({\n\t\t\t\t\t\t...d,\n\t\t\t\t\t\tdata: slicePayload(d.data, length),\n\t\t\t\t\t\ttarget: slicePayload(d.target, length),\n\t\t\t\t\t\texecutorOutput: slicePayload(d.executorOutput, length)\n\t\t\t\t\t})),\n\t\t\t\t\tgroupName: groupName ?? null\n\t\t\t\t})\n\t\t\t});\n\t\t\tlastResponse = response;\n\t\t\tlength = Math.floor(length / 2);\n\t\t\tif (response.status !== 413) break;\n\t\t}\n\t\tif (lastResponse && !lastResponse.ok) await this.handleError(lastResponse);\n\t}\n};\n//#endregion\n//#region src/resources/evaluators.ts\n/**\n* Resource for creating evaluator scores\n*/\nvar EvaluatorsResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/**\n\t* Create a score for a span or trace\n\t*\n\t* @param {ScoreOptions} options - Score creation options\n\t* @param {string} options.name - Name of the score\n\t* @param {string} [options.traceId] - The trace ID to score (will be attached to top-level span)\n\t* @param {string} [options.spanId] - The span ID to score\n\t* @param {Record<string, any>} [options.metadata] - Additional metadata\n\t* @param {number} options.score - The score value (float)\n\t* @returns {Promise<void>}\n\t*\n\t* @example\n\t* // Score by trace ID (will attach to root span)\n\t* await evaluators.score({\n\t* name: \"quality\",\n\t* traceId: \"trace-id-here\",\n\t* score: 0.95,\n\t* metadata: { model: \"gpt-4\" }\n\t* });\n\t*\n\t* @example\n\t* // Score by span ID\n\t* await evaluators.score({\n\t* name: \"relevance\",\n\t* spanId: \"span-id-here\",\n\t* score: 0.87\n\t* });\n\t*/\n\tasync score(options) {\n\t\tconst { name, metadata, score } = options;\n\t\tlet payload;\n\t\tif (\"traceId\" in options && options.traceId) payload = {\n\t\t\tname,\n\t\t\tmetadata,\n\t\t\tscore,\n\t\t\tsource: \"Code\",\n\t\t\ttraceId: isStringUUID(options.traceId) ? options.traceId : otelTraceIdToUUID(options.traceId)\n\t\t};\n\t\telse if (\"spanId\" in options && options.spanId) payload = {\n\t\t\tname,\n\t\t\tmetadata,\n\t\t\tscore,\n\t\t\tsource: \"Code\",\n\t\t\tspanId: isStringUUID(options.spanId) ? options.spanId : otelSpanIdToUUID(options.spanId)\n\t\t};\n\t\telse throw new Error(\"Either 'traceId' or 'spanId' must be provided.\");\n\t\tconst response = await fetch(this.baseHttpUrl + \"/v1/evaluators/score\", {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify(payload)\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n};\n//#endregion\n//#region src/resources/rollout-sessions.ts\nconst logger$1 = initializeLogger();\n/**\n* Map the opaque HIT `response` payload onto a {@link CachedSpan} the provider\n* wrappers can replay. The server-side shape of `response` is not yet frozen\n* (app-server plan 01 leaves it as a `serde_json::Value`), so this stays\n* deliberately tolerant: the whole payload is serialized into `output` (the only\n* field the AI SDK wrapper's `parseCachedSpan` actually reads, via\n* `JSON.parse`), and a `finishReason` is surfaced into `attributes` when the\n* payload carries one. `name`/`input` are irrelevant to replay and left empty.\n*/\nconst toCachedSpan = (response) => {\n\tconst output = typeof response === \"string\" ? response : JSON.stringify(response ?? null);\n\tconst attributes = {};\n\tif (response !== null && typeof response === \"object\" && typeof response.finishReason === \"string\") attributes[\"ai.response.finishReason\"] = response.finishReason;\n\treturn {\n\t\tname: \"\",\n\t\tinput: \"\",\n\t\toutput,\n\t\tattributes\n\t};\n};\nvar RolloutSessionsResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/**\n\t* Idempotently register (upsert) a debug session on the backend, keyed on the\n\t* SDK-supplied session id. The backend stores the row so the session is\n\t* visible in the UI; a null/omitted name never clobbers a name set elsewhere.\n\t*\n\t* Returns the backend-resolved `projectId` (derived from the API key) so the\n\t* caller can build the debugger URL; null if the body can't be parsed.\n\t*/\n\tasync register({ sessionId, name }) {\n\t\tconst response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify({ name })\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\ttry {\n\t\t\treturn (await response.json()).projectId ?? null;\n\t\t} catch (e) {\n\t\t\tlogger$1.warn(`Failed to parse rollout register response: ${errorMessage(e)}`);\n\t\t\treturn null;\n\t\t}\n\t}\n\t/**\n\t* Rename an existing debug session. Update-only: the backend returns 404 (and\n\t* this throws) when the session id is unknown for the project, so a mistyped\n\t* id surfaces as an error rather than silently creating a session. Creation\n\t* stays the SDK's job via {@link register}.\n\t*/\n\tasync setName({ sessionId, name }) {\n\t\tconst response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/name`, {\n\t\t\tmethod: \"PATCH\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify({ name })\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n\t/**\n\t* Look up the debug-replay cache for a single LLM call (debug-replay v2).\n\t*\n\t* The server is keyed by `inputHash` (hex blake3 of the canonicalized,\n\t* system-stripped input messages). It returns one of three outcomes:\n\t* - `{ outcome: \"hit\", response }` — a cached response to replay.\n\t* - `{ outcome: \"miss\" }` — no entry; caller latches live mode.\n\t* - `{ outcome: \"live\" }` — run this call live (COLD degrade).\n\t*\n\t* Error posture: a non-OK response or a transport error degrades to\n\t* `{ kind: \"live\" }` for THIS call only — it never throws and never latches\n\t* the process-wide live flag (only a real MISS does that). This keeps a flaky\n\t* cache backend from turning a replay into a crash.\n\t*/\n\tasync cache({ sessionId, replayTraceId, cacheUntil, inputHash }) {\n\t\tlet response;\n\t\ttry {\n\t\t\tresponse = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/cache`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: this.headers(),\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\treplayTraceId,\n\t\t\t\t\tcacheUntil,\n\t\t\t\t\tinputHash\n\t\t\t\t})\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tlogger$1.warn(`Debug cache lookup failed, running live: ${errorMessage(e)}`);\n\t\t\treturn { kind: \"live\" };\n\t\t}\n\t\tif (!response.ok) {\n\t\t\tlogger$1.warn(`Debug cache lookup returned ${response.status}, running live`);\n\t\t\treturn { kind: \"live\" };\n\t\t}\n\t\tlet body;\n\t\ttry {\n\t\t\tbody = await response.json();\n\t\t} catch (e) {\n\t\t\tlogger$1.warn(`Failed to parse debug cache response, running live: ${errorMessage(e)}`);\n\t\t\treturn { kind: \"live\" };\n\t\t}\n\t\tswitch (body.outcome) {\n\t\t\tcase \"hit\":\n\t\t\t\tif (body.response === null || body.response === void 0) {\n\t\t\t\t\tlogger$1.warn(\"Debug cache HIT had no response payload, running live\");\n\t\t\t\t\treturn { kind: \"live\" };\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"hit\",\n\t\t\t\t\tcached: toCachedSpan(body.response)\n\t\t\t\t};\n\t\t\tcase \"miss\": return { kind: \"miss\" };\n\t\t\tcase \"live\": return { kind: \"live\" };\n\t\t\tdefault:\n\t\t\t\tlogger$1.warn(`Unknown debug cache outcome \"${body.outcome}\", running live`);\n\t\t\t\treturn { kind: \"live\" };\n\t\t}\n\t}\n\tasync delete({ sessionId }) {\n\t\tconst response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}`, {\n\t\t\tmethod: \"DELETE\",\n\t\t\theaders: this.headers()\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n};\n//#endregion\n//#region src/resources/sql.ts\nvar SqlResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\tasync query(sql, parameters = {}) {\n\t\tconst response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/sql/query`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { ...this.headers() },\n\t\t\tbody: JSON.stringify({\n\t\t\t\tquery: sql,\n\t\t\t\tparameters\n\t\t\t})\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn (await response.json()).data;\n\t}\n};\n//#endregion\n//#region src/resources/tags.ts\n/** Resource for tagging traces. */\nvar TagsResource = class extends BaseResource {\n\t/** Resource for tagging traces. */\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/**\n\t* Tag a trace with a list of tags. Note that the trace must be ended before\n\t* tagging it. You may want to call `await Laminar.flush()` after the trace\n\t* that you want to tag.\n\t*\n\t* @param {string | StringUUID} trace_id - The trace id to tag.\n\t* @param {string[] | string} tags - The tag or list of tags to add to the trace.\n\t* @returns {Promise<any>} The response from the server.\n\t* @example\n\t* ```javascript\n\t* import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n\t* Laminar.initialize();\n\t* const client = new LaminarClient();\n\t* let traceId: StringUUID | null = null;\n\t* // Make sure this is called outside of traced context.\n\t* await observe(\n\t* {\n\t* name: \"my-trace\",\n\t* },\n\t* async () => {\n\t* traceId = await Laminar.getTraceId();\n\t* await foo();\n\t* },\n\t* );\n\t*\n\t* // or make sure the trace is ended by this point.\n\t* await Laminar.flush();\n\t* if (traceId) {\n\t* await client.tags.tag(traceId, [\"tag1\", \"tag2\"]);\n\t* }\n\t* ```\n\t*/\n\tasync tag(trace_id, tags) {\n\t\tconst traceTags = Array.isArray(tags) ? tags : [tags];\n\t\tconst formattedTraceId = isStringUUID(trace_id) ? trace_id : otelTraceIdToUUID(trace_id);\n\t\tconst url = this.baseHttpUrl + \"/v1/tag\";\n\t\tconst payload = {\n\t\t\t\"traceId\": formattedTraceId,\n\t\t\t\"names\": traceTags\n\t\t};\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify(payload)\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn response.json();\n\t}\n};\n//#endregion\n//#region src/resources/traces.ts\n/** Resource for post-factum operations on existing traces. */\nconst logger = initializeLogger();\nvar TracesResource = class extends BaseResource {\n\t/** Resource for post-factum operations on existing traces. */\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/**\n\t* Push a metadata patch to an existing trace.\n\t*\n\t* The patch is shallow-merged server-side into the trace's existing metadata\n\t* (`existing || patch`, last-write-wins per top-level key). Useful for\n\t* attaching post-factum signals — quality scores, human edits, triage labels —\n\t* to a trace that has already finished. The patch does NOT extend `endTime`\n\t* or change tokens / cost / top span / tags / span names. `numSpans` is\n\t* incremented by 1 (paid by the virtual span that carried the patch through\n\t* the ingestion queue) so the new ClickHouse row beats the prior version on\n\t* `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.\n\t*\n\t* Compared to `Laminar.setTraceMetadata` (which sets metadata on the\n\t* currently in-flight trace via OpenTelemetry attributes), this method\n\t* operates on a finished trace by trace id, so it must be called after the\n\t* trace has been flushed.\n\t*\n\t* A 404 response (the trace was not found in the project — typically because\n\t* it has not been flushed yet) is logged as a warning and the call returns\n\t* without throwing, since the 404 may be expected when pushing too soon\n\t* after the trace run. Pass `failOnNotFound: true` to throw instead (e.g.\n\t* CLI callers that must report the failure). Any other non-OK status throws.\n\t*\n\t* @param traceId - The trace id to push metadata to. Accepts a UUID string\n\t* or a 32-char OTel hex trace id.\n\t* @param metadata - The metadata patch. Top-level keys are merged into the\n\t* trace's existing metadata. Must be non-empty (the server rejects empty\n\t* patches with 400).\n\t* @param options - `failOnNotFound`: throw on 404 instead of warn-and-return.\n\t* @example\n\t* ```typescript\n\t* import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n\t* Laminar.initialize();\n\t* const client = new LaminarClient();\n\t*\n\t* let traceId: string | null = null;\n\t* await observe({ name: \"generate\" }, async () => {\n\t* traceId = await Laminar.getTraceId();\n\t* });\n\t* await Laminar.flush();\n\t*\n\t* if (traceId) {\n\t* await client.traces.pushMetadata(traceId, {\n\t* score: 0.85,\n\t* reviewer: \"alice\",\n\t* needsReview: false,\n\t* });\n\t* }\n\t* ```\n\t*/\n\tasync pushMetadata(traceId, metadata, options) {\n\t\tif (!metadata || Object.keys(metadata).length === 0) throw new Error(\"metadata must be a non-empty object\");\n\t\tconst formattedTraceId = isStringUUID(traceId) ? traceId : otelTraceIdToUUID(traceId);\n\t\tconst url = this.baseHttpUrl + this.apiPrefix + \"/traces/metadata\";\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify({\n\t\t\t\ttraceId: formattedTraceId,\n\t\t\t\tmetadata\n\t\t\t})\n\t\t});\n\t\tif (response.status === 404) {\n\t\t\tconst message = `Trace ${formattedTraceId} not found. The trace may not have been flushed yet — call await Laminar.flush() and retry.`;\n\t\t\tif (options?.failOnNotFound) throw new Error(message);\n\t\t\tlogger.warn(message);\n\t\t\treturn;\n\t\t}\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n};\n//#endregion\n//#region src/index.ts\nvar LaminarClient = class LaminarClient {\n\tconstructor({ baseUrl, port, auth, projectApiKey, cliUserProjectId } = {}) {\n\t\tloadEnv();\n\t\tthis.auth = LaminarClient.normalizeAuth(auth, projectApiKey, cliUserProjectId);\n\t\tconst httpPort = port ?? (baseUrl?.match(/:\\d{1,5}$/g) ? parseInt(baseUrl.match(/:\\d{1,5}$/g)[0].slice(1)) : 443);\n\t\tconst baseUrlNoPort = (baseUrl ?? process.env.LMNR_BASE_URL)?.replace(/\\/$/, \"\").replace(/:\\d{1,5}$/g, \"\");\n\t\tthis.baseUrl = `${baseUrlNoPort ?? \"https://api.lmnr.ai\"}:${httpPort}`;\n\t\tthis._browserEvents = new BrowserEventsResource(this.baseUrl, this.auth);\n\t\tthis._cli = new CliResource(this.baseUrl, this.auth);\n\t\tthis._datasets = new DatasetsResource(this.baseUrl, this.auth);\n\t\tthis._evals = new EvalsResource(this.baseUrl, this.auth);\n\t\tthis._evaluators = new EvaluatorsResource(this.baseUrl, this.auth);\n\t\tthis._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.auth);\n\t\tthis._sql = new SqlResource(this.baseUrl, this.auth);\n\t\tthis._tags = new TagsResource(this.baseUrl, this.auth);\n\t\tthis._traces = new TracesResource(this.baseUrl, this.auth);\n\t}\n\t/**\n\t* Normalize the constructor's auth inputs into a {@link LaminarAuth} union.\n\t* Precedence: an explicit `auth` wins; otherwise the legacy\n\t* `projectApiKey` (+ optional `cliUserProjectId`) is mapped — a present\n\t* `cliUserProjectId` selects the user-token surface, otherwise the project\n\t* key surface. Falls back to `LMNR_PROJECT_API_KEY` as a project key.\n\t*/\n\tstatic normalizeAuth(auth, projectApiKey, cliUserProjectId) {\n\t\tif (auth) return auth;\n\t\tconst key = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY;\n\t\tif (cliUserProjectId) return {\n\t\t\ttype: \"userToken\",\n\t\t\ttoken: key,\n\t\t\tprojectId: cliUserProjectId\n\t\t};\n\t\treturn {\n\t\t\ttype: \"apiKey\",\n\t\t\tkey\n\t\t};\n\t}\n\tget browserEvents() {\n\t\treturn this._browserEvents;\n\t}\n\tget cli() {\n\t\treturn this._cli;\n\t}\n\tget datasets() {\n\t\treturn this._datasets;\n\t}\n\tget evals() {\n\t\treturn this._evals;\n\t}\n\tget evaluators() {\n\t\treturn this._evaluators;\n\t}\n\tget rolloutSessions() {\n\t\treturn this._rolloutSessions;\n\t}\n\tget sql() {\n\t\treturn this._sql;\n\t}\n\tget tags() {\n\t\treturn this._tags;\n\t}\n\tget traces() {\n\t\treturn this._traces;\n\t}\n};\n//#endregion\nexport { LaminarClient, RolloutSessionsResource };\n\n//# sourceMappingURL=index.mjs.map","import pino, { Level } from 'pino';\nimport { PinoPretty } from 'pino-pretty';\n\nexport function initializeLogger(options?: { colorize?: boolean; level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level =\n options?.level ??\n (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level) ??\n 'info';\n\n return pino(\n {\n level,\n },\n PinoPretty({\n colorize,\n minimumLevel: level,\n destination: 2,\n }),\n );\n}\n","import { errorMessage } from '@lmnr-ai/types';\n\n/**\n * Write structured JSON to stdout. Use this for machine-readable output\n * when --json is set.\n */\nexport function outputJson(data: unknown): void {\n console.log(JSON.stringify(data));\n}\n\n/**\n * Write a JSON error to stdout and exit with code 1.\n * Use this in --json mode so agents can parse the failure.\n */\nexport function outputJsonError(error: unknown, exitCode: number = 1): never {\n console.log(JSON.stringify({\n error: errorMessage(error),\n }));\n process.exit(exitCode);\n}\n","// Default Laminar endpoints, shared across commands. Override per-invocation\n// via the --frontend-url / --base-url flags or the LMNR_FRONTEND_URL /\n// LMNR_BASE_URL env vars; these are the final fallback.\nexport const DEFAULT_FRONTEND_URL = \"https://www.laminar.sh\";\nexport const DEFAULT_BASE_URL = \"https://api.lmnr.ai\";\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join, parse } from \"node:path\";\n\n/**\n * Directory-scoped project link, written by `setup` to `.lmnr/project.json`.\n * The project the CLI operates on is inferred from the directory you're in\n * (Vercel/Supabase style), overridable with --project-id.\n * Holds the project id plus small display details — never secrets (the API key\n * lives in .env).\n */\nexport interface ProjectLink {\n projectId: string;\n projectName?: string;\n workspaceId?: string;\n workspaceName?: string;\n}\n\nconst LINK_DIR = \".lmnr\";\nconst LINK_FILE = \"project.json\";\n\n/**\n * Find the nearest `.lmnr/project.json`, walking up from `startDir` to the\n * filesystem root (so commands work from subdirectories of a linked project).\n * Returns null if none is found.\n */\nexport async function readProjectLink(\n startDir: string = process.cwd(),\n): Promise<ProjectLink | null> {\n let dir = startDir;\n const root = parse(dir).root;\n\n while (true) {\n const candidate = join(dir, LINK_DIR, LINK_FILE);\n try {\n const parsed = JSON.parse(await readFile(candidate, \"utf8\")) as ProjectLink;\n if (parsed && typeof parsed.projectId === \"string\" && parsed.projectId.length > 0) {\n return parsed;\n }\n } catch {\n // Not here (missing / unreadable / malformed) — keep walking up.\n }\n const parent = dirname(dir);\n if (parent === dir || dir === root) break;\n dir = parent;\n }\n return null;\n}\n\n/** Write `.lmnr/project.json` under `dir` (default cwd). Returns the file path. */\nexport async function writeProjectLink(\n link: ProjectLink,\n dir: string = process.cwd(),\n): Promise<string> {\n const linkDir = join(dir, LINK_DIR);\n await mkdir(linkDir, { recursive: true });\n const path = join(linkDir, LINK_FILE);\n await writeFile(path, JSON.stringify(link, null, 2) + \"\\n\", \"utf8\");\n return path;\n}\n","import { mkdir, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nexport const CREDENTIALS_VERSION = 1;\n\n/**\n * The signed-in user's BetterAuth tokens. The CLI is single-user — one account\n * at a time, so the file is flat (no profiles map / active pointer).\n * Pre-release: version stays 1, no backcompat with any earlier shape.\n * - `sessionToken` is the durable BetterAuth session token (the refresh token).\n * - `accessToken` is the short-lived (15m) EdDSA JWT minted from the session.\n */\nexport interface Credentials {\n version: 1;\n issuer: string;\n // No `baseUrl` here on purpose: the data-API endpoint is resolved fresh on\n // every command (`--base-url` flag → LMNR_BASE_URL → default) so a self-host\n // .env change takes effect without re-login. `issuer` (the frontend URL,\n // used for token refresh) stays cached because refresh has no flag/env.\n sessionToken: string;\n accessToken: string;\n accessTokenExpiresAt: string;\n sessionExpiresAt?: string;\n userEmail?: string;\n userId: string;\n createdAt: string;\n lastUsedAt?: string;\n}\n\n// The lmnr config dir: `XDG_CONFIG_HOME` when set, else `%APPDATA%\\lmnr` on\n// Windows and `~/.config/lmnr` elsewhere.\nexport function globalLmnrDirectory(): string {\n const xdg = process.env.XDG_CONFIG_HOME?.trim();\n if (xdg && xdg.length > 0) {\n return join(xdg, \"lmnr\");\n }\n const appData = process.env.APPDATA?.trim();\n if (process.platform === \"win32\" && appData && appData.length > 0) {\n return join(appData, \"lmnr\");\n }\n return join(homedir(), \".config\", \"lmnr\");\n}\n\nexport function credentialsPath(): string {\n return join(globalLmnrDirectory(), \"credentials.json\");\n}\n\n/**\n * Read the credentials file. Returns null when missing or not the current flat\n * v1 shape (treated as \"not logged in\" — `lmnr-cli login` overwrites).\n */\nexport async function readCredentials(): Promise<Credentials | null> {\n const path = credentialsPath();\n let raw: string;\n try {\n raw = await readFile(path, \"utf-8\");\n } catch (e: unknown) {\n if (isNotFound(e)) return null;\n throw e;\n }\n let parsed: Partial<Credentials>;\n try {\n parsed = JSON.parse(raw) as Partial<Credentials>;\n } catch {\n return null;\n }\n if (parsed.version === CREDENTIALS_VERSION && typeof parsed.sessionToken === \"string\") {\n return parsed as Credentials;\n }\n return null;\n}\n\nexport async function writeCredentials(creds: Credentials): Promise<void> {\n const path = credentialsPath();\n const parent = dirname(path);\n await mkdir(parent, { recursive: true, mode: 0o700 });\n\n // Preserve a tighter user-set mode (e.g. 0o600) across token-refresh writes;\n // default 0o600 for new files. The temp adopts this mode and the rename\n // carries it onto the canonical file.\n let mode = 0o600;\n try {\n const existing = await stat(path);\n mode = existing.mode & 0o777;\n } catch (e: unknown) {\n if (!isNotFound(e)) throw e;\n }\n\n // Atomic temp+rename so a crashed write can't corrupt the canonical file.\n const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;\n await writeFile(tmp, JSON.stringify(creds, null, 2), { mode, flag: \"wx\" });\n await rename(tmp, path);\n}\n\nexport async function deleteCredentials(): Promise<boolean> {\n const path = credentialsPath();\n try {\n await stat(path);\n } catch (e: unknown) {\n if (isNotFound(e)) return false;\n throw e;\n }\n await rm(path, { force: true });\n return true;\n}\n\nfunction isNotFound(e: unknown): boolean {\n return (\n typeof e === \"object\" &&\n e !== null &&\n \"code\" in e &&\n (e as { code?: string }).code === \"ENOENT\"\n );\n}\n","// Hand-rolled fetch against BetterAuth's RFC 8628 device-flow endpoints. Login\n// is user-scoped: the device token endpoint returns a session token (the\n// refresh token); the access token is a short-lived JWT minted separately via\n// GET /api/auth/token.\n\nimport {\n type DeviceCodeResponse,\n type DeviceTokenResponse,\n type PollOptions,\n type SessionUser,\n} from \"./types\";\n\nexport const CLI_CLIENT_ID = \"lmnr-cli\";\nexport const CLI_SCOPE = \"projects:rw\";\n\nconst DEVICE_CODE_ENDPOINT = \"/api/auth/device/code\";\nconst DEVICE_TOKEN_ENDPOINT = \"/api/auth/device/token\";\nconst TOKEN_ENDPOINT = \"/api/auth/token\";\nconst SESSION_ENDPOINT = \"/api/auth/get-session\";\n\ntype PollErrorCode =\n | \"authorization_pending\"\n | \"slow_down\"\n | \"access_denied\"\n | \"expired_token\"\n | \"invalid_grant\"\n | \"invalid_request\"\n | \"invalid_client\"\n | \"server_error\";\n\nexport class DeviceFlowError extends Error {\n constructor(public readonly code: string, message: string) {\n super(message);\n }\n}\n\nfunction trimSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nexport async function initiateDevice(\n issuer: string,\n scope: string = CLI_SCOPE,\n): Promise<DeviceCodeResponse> {\n const url = `${trimSlash(issuer)}${DEVICE_CODE_ENDPOINT}`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ client_id: CLI_CLIENT_ID, scope }),\n });\n if (!res.ok) {\n const body = (await safeJson(res)) ?? {};\n throw new DeviceFlowError(\n typeof body.error === \"string\" ? body.error : `http_${res.status}`,\n typeof body.error_description === \"string\"\n ? body.error_description\n : `Device authorization request failed (${res.status})`,\n );\n }\n return (await res.json()) as DeviceCodeResponse;\n}\n\n/**\n * Poll BetterAuth's native token endpoint until the user approves. Returns the\n * full token response (whose `access_token` is the durable session token).\n */\nexport async function pollDevice(\n issuer: string,\n deviceCode: string,\n opts: PollOptions = {},\n): Promise<DeviceTokenResponse> {\n let intervalSeconds = Math.max(1, opts.intervalSeconds ?? 5);\n const timeoutMs = (opts.timeoutSeconds ?? 900) * 1000;\n const deadline = Date.now() + timeoutMs;\n\n while (true) {\n if (Date.now() > deadline) {\n throw new DeviceFlowError(\"expired_token\", \"Timed out waiting for authorization\");\n }\n const url = `${trimSlash(issuer)}${DEVICE_TOKEN_ENDPOINT}`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: deviceCode,\n client_id: CLI_CLIENT_ID,\n }),\n });\n if (res.ok) {\n const body = (await res.json()) as DeviceTokenResponse;\n if (!body.access_token) {\n throw new DeviceFlowError(\"server_error\", \"Device token response missing access_token\");\n }\n // The browser-selected project (and any future CLI metadata) rides back on\n // the x-lmnr-metadata response header, NOT the OAuth scope. Attach it so\n // callers can parse it via parseProjectFromMetadata.\n body.metadata = res.headers.get(\"x-lmnr-metadata\");\n return body;\n }\n const body = (await safeJson(res)) ?? {};\n const code = (\n typeof body.error === \"string\" ? body.error : `http_${res.status}`\n ) as PollErrorCode;\n const description = typeof body.error_description === \"string\" ? body.error_description : code;\n if (code === \"authorization_pending\") {\n opts.onTick?.();\n await sleep(intervalSeconds * 1000);\n continue;\n }\n if (code === \"slow_down\") {\n intervalSeconds += 5;\n await sleep(intervalSeconds * 1000);\n continue;\n }\n // access_denied / expired_token / invalid_grant / server_error — terminal.\n throw new DeviceFlowError(code, description);\n }\n}\n\n/**\n * Mint a fresh 15m EdDSA JWT from a session token. Throws DeviceFlowError\n * \"invalid_grant\" on 401 (session expired/revoked).\n */\nexport async function mintAccessJwt(issuer: string, sessionToken: string): Promise<string> {\n const url = `${trimSlash(issuer)}${TOKEN_ENDPOINT}`;\n const res = await fetch(url, {\n method: \"GET\",\n headers: { authorization: `Bearer ${sessionToken}` },\n });\n if (res.status === 401) {\n throw new DeviceFlowError(\"invalid_grant\", \"Session expired or revoked\");\n }\n if (!res.ok) {\n const body = (await safeJson(res)) ?? {};\n throw new DeviceFlowError(\n typeof body.error === \"string\" ? body.error : `http_${res.status}`,\n `Failed to mint access token (${res.status})`,\n );\n }\n const body = (await res.json()) as { token?: string };\n if (!body.token) {\n throw new DeviceFlowError(\"server_error\", \"Token endpoint response missing token\");\n }\n return body.token;\n}\n\n/** Fetch the BetterAuth session for profile metadata (userId, email). */\nexport async function fetchSession(issuer: string, sessionToken: string): Promise<SessionUser> {\n const url = `${trimSlash(issuer)}${SESSION_ENDPOINT}`;\n const res = await fetch(url, {\n method: \"GET\",\n headers: { authorization: `Bearer ${sessionToken}` },\n });\n if (!res.ok) {\n throw new DeviceFlowError(`http_${res.status}`, `Failed to fetch session (${res.status})`);\n }\n const body = (await res.json()) as { user?: { id?: string; email?: string } } | null;\n const user = body?.user;\n if (!user?.id) {\n throw new DeviceFlowError(\"server_error\", \"Session response missing user\");\n }\n return { id: user.id, email: user.email ?? \"\" };\n}\n\n/**\n * Decode a JWT's `exp` (seconds since epoch) → ISO string. No signature\n * verification — the CLI trusts a token it just received over TLS. Returns null\n * when the token is malformed or carries no numeric `exp`.\n */\nexport function decodeJwtExp(jwt: string): string | null {\n const parts = jwt.split(\".\");\n if (parts.length < 2) return null;\n try {\n const json = Buffer.from(parts[1], \"base64url\").toString(\"utf-8\");\n const payload = JSON.parse(json) as { exp?: unknown };\n if (typeof payload.exp !== \"number\") return null;\n return new Date(payload.exp * 1000).toISOString();\n } catch {\n return null;\n }\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Extract the browser-selected projectId from the device-token `x-lmnr-metadata`\n * response header — a JSON string, e.g. `{\"projectId\":\"<uuid>\"}`, forwarded by\n * the server's /device/token route wrapper. Returns null when absent or malformed.\n */\nexport function parseProjectFromMetadata(metadata?: string | null): string | null {\n if (!metadata) return null;\n try {\n const obj = JSON.parse(metadata) as { projectId?: unknown };\n const pid = obj?.projectId;\n return typeof pid === \"string\" && UUID_RE.test(pid) ? pid : null;\n } catch {\n return null;\n }\n}\n\nasync function safeJson(res: Response): Promise<Record<string, unknown> | null> {\n try {\n return (await res.json()) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","import { DEFAULT_BASE_URL } from \"../constants\";\nimport { readProjectLink } from \"../utils/project-link\";\nimport { type Credentials, readCredentials, writeCredentials } from \"./credentials\";\nimport { decodeJwtExp, DeviceFlowError, mintAccessJwt } from \"./device\";\nimport { type AuthInputs, type ResolvedAuth } from \"./types\";\n\n// Re-mint the JWT when it's within this window of expiry.\nconst REFRESH_SKEW_MS = 30_000;\n\n/**\n * HTTP port from `LMNR_HTTP_PORT`. The Laminar convention is that `baseUrl`\n * carries NO port and the port is supplied separately (mirrors the SDK's\n * `LMNR_HTTP_PORT` / `LMNR_GRPC_PORT`). Returns undefined when unset/invalid so\n * the client keeps its 443 default for Cloud. An explicit `--port` flag still\n * wins (callers do `opts.port ?? envHttpPort()`).\n */\nexport function envHttpPort(): number | undefined {\n const raw = process.env.LMNR_HTTP_PORT?.trim();\n if (!raw) return undefined;\n const n = Number.parseInt(raw, 10);\n return Number.isFinite(n) ? n : undefined;\n}\n\n/**\n * Resolve the data-API base URL: `--base-url` flag → `LMNR_BASE_URL` env →\n * default. Intentionally NOT read from credentials.json — the endpoint is not\n * persisted at login, so a self-host `.env` change applies to every command\n * without re-logging-in (and base URL behaves symmetrically with the port).\n */\nexport function resolveBaseUrl(optBaseUrl?: string): string {\n return optBaseUrl?.trim() || process.env.LMNR_BASE_URL?.trim() || DEFAULT_BASE_URL;\n}\n\n/**\n * CLI auth is **user-token only** — the CLI authenticates as the single\n * signed-in user via the stored BetterAuth session (refreshed access JWT),\n * never via a project API key.\n *\n * Project precedence (directory-scoped): `--project-id` flag > the nearest\n * `.lmnr/project.json` (written by `setup`). The project is NOT stored in\n * credentials.json — that holds only user auth.\n */\nexport async function resolveAuth(opts: AuthInputs): Promise<ResolvedAuth> {\n const creds = await readCredentials();\n if (!creds) {\n throw new Error(\"Not authenticated. Run `lmnr-cli login`.\");\n }\n\n let projectId = opts.projectId;\n if (!projectId || projectId.length === 0) {\n projectId = (await readProjectLink())?.projectId;\n }\n if (!projectId || projectId.length === 0) {\n throw new Error(\n \"No project for this directory. Run `lmnr-cli setup` here, \" +\n \"or pass --project-id <id>.\",\n );\n }\n\n const updated = await refreshIfNeeded(creds);\n return {\n bearer: updated.accessToken,\n baseUrl: resolveBaseUrl(opts.baseUrl),\n port: opts.port ?? envHttpPort(),\n projectId,\n };\n}\n\n/**\n * Resolve only the user-scoped access token (no project) — for discovery\n * endpoints like listing projects, which run BEFORE a project is selected.\n */\nexport async function resolveUserToken(opts: {\n baseUrl?: string;\n port?: number;\n}): Promise<{ bearer: string; baseUrl?: string; port?: number }> {\n const creds = await readCredentials();\n if (!creds) {\n throw new Error(\"Not authenticated. Run `lmnr-cli login`.\");\n }\n const updated = await refreshIfNeeded(creds);\n return {\n bearer: updated.accessToken,\n baseUrl: resolveBaseUrl(opts.baseUrl),\n port: opts.port ?? envHttpPort(),\n };\n}\n\n/**\n * Re-mint the access JWT when it's near expiry and persist it. A 401 from the\n * token endpoint means the session is gone — surface a clear \"run login\" error.\n *\n * Logout race guard: we write credentials ONLY when we actually re-minted. The\n * old code unconditionally rewrote the file (just to bump lastUsedAt) on every\n * command, so a concurrent `logout` that deleted the file mid-flight could have\n * its delete clobbered by this in-flight atomic rename — logout would appear to\n * succeed while tokens remained on disk. For a fresh (not-near-expiry) token we\n * now do no write at all, eliminating that window for the common case.\n */\nexport async function refreshIfNeeded(creds: Credentials): Promise<Credentials> {\n const expMs = new Date(creds.accessTokenExpiresAt).getTime();\n const nearExpiry = !Number.isFinite(expMs) || expMs - Date.now() <= REFRESH_SKEW_MS;\n if (!nearExpiry) {\n return creds;\n }\n\n const next: Credentials = { ...creds };\n try {\n const jwt = await mintAccessJwt(creds.issuer, creds.sessionToken);\n next.accessToken = jwt;\n next.accessTokenExpiresAt = decodeJwtExp(jwt) ?? new Date().toISOString();\n } catch (e) {\n if (e instanceof DeviceFlowError && e.code === \"invalid_grant\") {\n throw new Error(\"Session expired — run `lmnr-cli login`.\");\n }\n throw e;\n }\n next.lastUsedAt = new Date().toISOString();\n await writeCredentials(next);\n return next;\n}\n","import { LaminarClient } from \"@lmnr-ai/client\";\n\nimport { resolveAuth } from \"./resolve\";\nimport { type AuthInputs } from \"./types\";\n\n/**\n * Build a LaminarClient for CLI commands. Auth is user-token only: the bearer\n * is the stored BetterAuth access JWT (auto-refreshed near expiry) and requests\n * route to `/v1/cli/*` with the resolved project in `x-lmnr-project-id`.\n */\nexport async function buildLaminarClient(opts: AuthInputs): Promise<LaminarClient> {\n const auth = await resolveAuth(opts);\n return new LaminarClient({\n baseUrl: auth.baseUrl,\n port: auth.port,\n // User-token auth → routes to /v1/cli/* with the resolved project in the\n // x-lmnr-project-id header.\n auth: { type: \"userToken\", token: auth.bearer, projectId: auth.projectId },\n });\n}\n","import { LaminarClient } from \"@lmnr-ai/client\";\nimport { errorMessage } from \"@lmnr-ai/types\";\nimport type { Command } from \"commander\";\n\nimport { initializeLogger } from \"../utils/logger\";\nimport { outputJsonError } from \"../utils/output\";\nimport { buildLaminarClient } from \"./client\";\nimport { resolveUserToken } from \"./resolve\";\n\nconst logger = initializeLogger();\n\n/**\n * Global options every wrapped command shares (from `cmd.optsWithGlobals()`).\n * `projectId` is consumed by the project-client path; discovery commands ignore\n * it (the user-token surface has no project to scope at discovery time).\n */\nexport interface GlobalOpts {\n projectId?: string;\n baseUrl?: string;\n port?: number;\n json?: boolean;\n}\n\n/**\n * Map a thrown error to a process exit code. The default is 1; pass a custom\n * mapper to a wrapper to surface distinct machine-readable codes (Phase 6).\n */\nexport type ExitCodeMapper = (error: unknown) => number;\n\nconst defaultExitCode: ExitCodeMapper = () => 1;\n\n/**\n * Pull the commander positionals out of an `.action(...)` argument list.\n * Commander invokes the handler as `(arg1, ..., argN, options, command)`, so\n * the positionals are everything except the trailing `(options, command)`.\n */\nfunction splitCommanderArgs(cmdArgs: unknown[]): {\n positionals: unknown[];\n command: Command;\n opts: GlobalOpts;\n} {\n const command = cmdArgs.at(-1) as Command;\n const positionals = cmdArgs.slice(0, -2);\n const opts = command.optsWithGlobals();\n return { positionals, command, opts };\n}\n\n/**\n * The error envelope shared by both wrappers: in `--json` mode emit a structured\n * error line and exit with the mapped code; otherwise log and exit. Owning this\n * here lets handlers stay pure `(client, ...args) => work` with no try/catch.\n */\nfunction runWithEnvelope(\n work: () => Promise<void>,\n opts: GlobalOpts,\n exitCodeFor: ExitCodeMapper,\n): Promise<void> {\n return work().catch((error: unknown) => {\n const code = exitCodeFor(error);\n if (opts.json) {\n // outputJsonError exits with `code` (never returns).\n outputJsonError(error, code);\n }\n logger.error(errorMessage(error));\n process.exit(code);\n });\n}\n\n/**\n * The handler shape both wrappers accept: a pure function of the resolved\n * client, the commander positionals, and the parsed options (so it can read\n * `--json` for output mode). All auth resolution + the error envelope live in\n * the wrapper, so handlers contain only the work.\n */\nexport type ClientAction<A extends unknown[]> = (\n client: LaminarClient,\n ...args: [...A, GlobalOpts]\n) => Promise<void>;\n\n/**\n * Wrap a project-scoped command handler. Resolves a user-token\n * {@link LaminarClient} (routes to `/v1/cli/*` with the resolved project),\n * threads the commander positionals + options through, and owns the error\n * envelope.\n *\n * @example\n * sqlCmd.command(\"query\")\n * .argument(\"<query>\")\n * .action(withProjectClient(handleSqlQuery)); // (client, query, opts) => work\n */\nexport const withProjectClient =\n <A extends unknown[]>(\n action: ClientAction<A>,\n exitCodeFor: ExitCodeMapper = defaultExitCode,\n ) =>\n async (...cmdArgs: unknown[]): Promise<void> => {\n const { positionals, opts } = splitCommanderArgs(cmdArgs);\n await runWithEnvelope(\n async () => {\n const client = await buildLaminarClient({\n projectId: opts.projectId,\n baseUrl: opts.baseUrl,\n port: opts.port,\n });\n await action(client, ...(positionals as A), opts);\n },\n opts,\n exitCodeFor,\n );\n };\n\n/**\n * Wrap a discovery command handler. Resolves a user-token\n * {@link LaminarClient} with NO project (the discovery surface — e.g. listing\n * projects — runs before a project is selected), threads positionals +\n * options, and owns the error envelope.\n */\nexport const withUserToken =\n <A extends unknown[]>(\n action: ClientAction<A>,\n exitCodeFor: ExitCodeMapper = defaultExitCode,\n ) =>\n async (...cmdArgs: unknown[]): Promise<void> => {\n const { positionals, opts } = splitCommanderArgs(cmdArgs);\n await runWithEnvelope(\n async () => {\n const token = await resolveUserToken({\n baseUrl: opts.baseUrl,\n port: opts.port,\n });\n const client = new LaminarClient({\n baseUrl: token.baseUrl,\n // token.port carries the --port flag OR the LMNR_HTTP_PORT fallback\n // (resolveUserToken applies it); using opts.port here would drop it.\n port: token.port,\n // Discovery: no project id yet. CliResource overrides its own\n // URL/headers, so the empty projectId is never sent.\n auth: { type: \"userToken\", token: token.bearer, projectId: \"\" },\n });\n await action(client, ...(positionals as A), opts);\n },\n opts,\n exitCodeFor,\n );\n };\n","import { Datapoint, errorMessage } from '@lmnr-ai/types';\nimport csv from 'csv-parser';\nimport { asString, generateCsv, mkConfig } from 'export-to-csv';\nimport { createReadStream } from 'fs';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\n\nimport { initializeLogger } from './logger';\n\nconst logger = initializeLogger();\n\n/**\n * Check if a file has a supported extension.\n */\nconst isSupportedFile = (file: string): boolean => {\n const ext = path.extname(file).toLowerCase();\n return ['.json', '.csv', '.jsonl'].includes(ext);\n};\n\n/**\n * Collect all supported files from the given paths.\n * Handles both files and directories.\n */\nexport const collectFiles = async (\n paths: string[],\n recursive: boolean = false,\n): Promise<string[]> => {\n const collectedFiles: string[] = [];\n\n for (const filepath of paths) {\n try {\n const stats = await fs.stat(filepath);\n\n if (stats.isFile()) {\n if (isSupportedFile(filepath)) {\n collectedFiles.push(filepath);\n } else {\n logger.warn(`Skipping unsupported file type: ${filepath}`);\n }\n } else if (stats.isDirectory()) {\n const entries = await fs.readdir(filepath);\n\n for (const entry of entries) {\n const fullPath = path.join(filepath, entry);\n const entryStats = await fs.stat(fullPath);\n\n if (entryStats.isFile() && isSupportedFile(fullPath)) {\n collectedFiles.push(fullPath);\n } else if (recursive && entryStats.isDirectory()) {\n const subFiles = await collectFiles([fullPath], true);\n collectedFiles.push(...subFiles);\n }\n }\n }\n } catch (error) {\n logger.warn(\n `Path does not exist or is not accessible: ${filepath}. `\n + `Error: ${errorMessage(error)}`,\n );\n }\n }\n\n return collectedFiles;\n};\n\n/**\n * Read a JSON file and return its contents.\n */\nconst readJsonFile = async (filepath: string): Promise<any[]> => {\n const content = await fs.readFile(filepath, 'utf-8');\n const parsed = JSON.parse(content);\n return Array.isArray(parsed) ? parsed : [parsed];\n};\n\n/**\n * Try to parse a string as JSON. If it fails, return the original string.\n */\nconst tryParseJson = (content: string): any => {\n // Don't try to parse if it's not a string or doesn't look like JSON\n if (typeof content !== 'string') {\n return content;\n }\n\n // If it doesn't start with { or [, it's probably not JSON\n const trimmed = content.trim();\n if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {\n return content;\n }\n\n try {\n return JSON.parse(content);\n } catch (error) {\n logger.debug(\n `Error parsing JSON: ${errorMessage(error)}`,\n );\n return content;\n }\n};\n\n/**\n * Parse each field in a CSV row, attempting to convert JSON strings back to objects.\n */\nconst parseCsvRow = (row: Record<string, string>): any => {\n const parsed: any = {};\n for (const [key, value] of Object.entries(row)) {\n parsed[key] = tryParseJson(value);\n }\n return parsed;\n};\n\n/**\n * Read a CSV file and return its contents as an array of objects.\n */\nconst readCsvFile = async (filepath: string): Promise<any[]> => new Promise((resolve, reject) => {\n const results: any[] = [];\n createReadStream(filepath)\n .pipe(csv())\n .on('data', (data) => results.push(parseCsvRow(data)))\n .on('end', () => resolve(results))\n .on('error', reject);\n});\n\n/**\n * Read a JSONL file and return its contents as an array of objects.\n */\nasync function readJsonlFile(filepath: string): Promise<any[]> {\n const content = await fs.readFile(filepath, 'utf-8');\n const lines = content.split('\\n').filter((line) => line.trim());\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return lines.map((line) => JSON.parse(line));\n}\n\n/**\n * Read a single file and return its contents.\n */\nasync function readFile(filepath: string): Promise<any[]> {\n const ext = path.extname(filepath).toLowerCase();\n\n if (ext === '.json') {\n return readJsonFile(filepath);\n } else if (ext === '.csv') {\n return readCsvFile(filepath);\n } else if (ext === '.jsonl') {\n return readJsonlFile(filepath);\n } else {\n throw new Error(`Unsupported file type: ${ext}`);\n }\n}\n\n/**\n * Load data from all files in the specified paths.\n */\nexport const loadFromPaths = async <D = any, T = any>(\n paths: string[],\n recursive: boolean = false,\n): Promise<Datapoint<D, T>[]> => {\n const files = await collectFiles(paths, recursive);\n\n if (files.length === 0) {\n logger.warn('No supported files found in the specified paths');\n return [];\n }\n\n logger.info(`Found ${files.length} file(s) to read`);\n\n const result: Datapoint<D, T>[] = [];\n\n for (const file of files) {\n try {\n const data = await readFile(file);\n result.push(...data);\n logger.info(`Read ${data.length} record(s) from ${file}`);\n } catch (error) {\n logger.error(\n `Error reading file ${file}: ${errorMessage(error)}`,\n );\n throw error;\n }\n }\n\n return result;\n};\n\n/**\n * Write data to a JSON file.\n */\nconst writeJsonFile = async <D, T>(\n filepath: string,\n data: Datapoint<D, T>[],\n): Promise<void> => {\n const content = JSON.stringify(data, null, 2);\n await fs.writeFile(filepath, content, 'utf-8');\n};\n\n/**\n * Format data as a CSV string.\n */\nconst formatCsv = <D, T>(data: Datapoint<D, T>[]): string => {\n const formattedData = data.map(item =>\n Object.fromEntries(Object.entries(item).map(([key, value]) => [key, stringifyForCsv(value)]),\n ));\n\n const csvConfig = mkConfig({ useKeysAsHeaders: true });\n const csvOutput = generateCsv(csvConfig)(formattedData);\n return asString(csvOutput);\n};\n\n/**\n * Write data to a CSV file.\n */\nconst writeCsvFile = async <D, T>(\n filepath: string,\n data: Datapoint<D, T>[],\n): Promise<void> => {\n if (data.length === 0) {\n throw new Error('No data to write to CSV');\n }\n\n await fs.writeFile(filepath, formatCsv(data), 'utf-8');\n};\n\n/**\n * Write data to a JSONL file.\n */\nconst writeJsonlFile = async <D, T>(\n filepath: string,\n data: Datapoint<D, T>[],\n): Promise<void> => {\n const lines = data.map((item) => JSON.stringify(item)).join('\\n');\n await fs.writeFile(filepath, lines + '\\n', 'utf-8');\n};\n\n/**\n * Write data to a file based on the file extension.\n */\nexport const writeToFile = async <D, T>(\n filepath: string,\n data: Datapoint<D, T>[],\n format?: 'json' | 'csv' | 'jsonl',\n): Promise<void> => {\n // Create parent directories if they don't exist\n const dir = path.dirname(filepath);\n await fs.mkdir(dir, { recursive: true });\n\n // Determine the format\n const ext = format ?? path.extname(filepath).slice(1);\n\n if (format && format !== path.extname(filepath).slice(1)) {\n logger.warn(\n `Output format ${format} does not match file extension ${path.extname(filepath).slice(1)}`,\n );\n }\n\n if (ext === 'json') {\n await writeJsonFile(filepath, data);\n } else if (ext === 'csv') {\n await writeCsvFile(filepath, data);\n } else if (ext === 'jsonl') {\n await writeJsonlFile(filepath, data);\n } else {\n throw new Error(`Unsupported output format: ${ext}`);\n }\n};\n\n/**\n * Convert a value to a CSV-safe string.\n * - Strings and numbers pass through\n * - null/undefined become empty strings\n * - Objects and arrays are stringified to JSON\n */\nconst stringifyForCsv = (value: any): string => {\n if (value === null || value === undefined) {\n return '';\n }\n if (typeof value === 'string') {\n return value;\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n // For objects and arrays, stringify to JSON\n return JSON.stringify(value);\n};\n\n/**\n * Print data to console in the specified format.\n */\nexport const printToConsole = <D, T>(\n data: Datapoint<D, T>[],\n format: 'json' | 'csv' | 'jsonl' = 'json',\n) => {\n if (format === 'json') {\n console.log(JSON.stringify(data, null, 2));\n } else if (format === 'csv') {\n if (data.length === 0) {\n logger.error('No data to print');\n return;\n }\n\n console.log(formatCsv(data));\n } else if (format === 'jsonl') {\n data.forEach((item) => console.log(JSON.stringify(item)));\n } else {\n throw new Error(\n `Unsupported output format: ${String(format)}. `\n + \"(supported formats: json, csv, jsonl)\",\n );\n }\n};\n\n","import Table from \"cli-table3\";\n\nconst DEFAULT_TERMINAL_WIDTH = 80;\nconst PADDING_RIGHT = 2;\n\nconst noBorderChars = {\n top: \"\", \"top-mid\": \"\", \"top-left\": \"\", \"top-right\": \"\",\n bottom: \"\", \"bottom-mid\": \"\", \"bottom-left\": \"\", \"bottom-right\": \"\",\n left: \"\", \"left-mid\": \"\", mid: \"\", \"mid-mid\": \"\",\n right: \"\", \"right-mid\": \"\", middle: \"\",\n};\n\nfunction getTerminalWidth(): number {\n return process.stdout.columns || DEFAULT_TERMINAL_WIDTH;\n}\n\n/**\n * Calculate column widths that fit within the terminal width.\n * Distributes available space proportionally based on content width.\n */\nfunction fitColumnWidths(\n contentWidths: number[],\n terminalWidth: number,\n): number[] | undefined {\n // With no borders, overhead is just padding-right per column\n const overhead = contentWidths.length * PADDING_RIGHT;\n const totalContentWidth = contentWidths.reduce((sum, w) => sum + w, 0);\n\n if (totalContentWidth + overhead <= terminalWidth) {\n return undefined;\n }\n\n const availableContent = terminalWidth - overhead;\n const minColWidth = 5;\n\n // Return widths including padding, since cli-table3's colWidths includes padding\n return contentWidths.map((w) =>\n Math.max(\n minColWidth + PADDING_RIGHT,\n Math.floor((w / totalContentWidth) * availableContent) + PADDING_RIGHT,\n ),\n );\n}\n\nfunction truncate(str: string, maxLen: number): string {\n if (maxLen < 1) return str;\n if (str.length <= maxLen) return str;\n return str.slice(0, maxLen - 1) + \"\\u2026\";\n}\n\n/**\n * Render a borderless table from column headers and row data.\n * Automatically truncates content when the table exceeds terminal width.\n */\nexport function renderTable(head: string[], rows: string[][]): string {\n const terminalWidth = getTerminalWidth();\n\n const contentWidths = head.map((h, i) =>\n rows.reduce((max, row) => Math.max(max, (row[i] ?? \"\").length), h.length),\n );\n\n const colWidths = fitColumnWidths(contentWidths, terminalWidth);\n\n const truncatedHead = colWidths\n ? head.map((h, i) => truncate(h, colWidths[i] - PADDING_RIGHT))\n : head;\n\n const table = new Table({\n head: truncatedHead,\n chars: noBorderChars,\n style: {\n \"padding-left\": 0,\n \"padding-right\": PADDING_RIGHT,\n },\n ...(colWidths && { colWidths }),\n });\n\n if (colWidths) {\n for (const row of rows) {\n table.push(row.map((cell, i) => truncate(cell, colWidths[i] - PADDING_RIGHT)));\n }\n } else {\n for (const row of rows) {\n table.push(row);\n }\n }\n\n return table.toString();\n}\n","import { LaminarClient } from \"@lmnr-ai/client\";\nimport { Datapoint, type StringUUID } from \"@lmnr-ai/types\";\n\nimport type { GlobalOpts } from \"../../auth/with-client\";\nimport { loadFromPaths, printToConsole, writeToFile } from \"../../utils/file\";\nimport { initializeLogger } from \"../../utils/logger\";\nimport { outputJson } from \"../../utils/output\";\nimport { renderTable } from \"../../utils/table\";\n\nconst logger = initializeLogger();\nconst DEFAULT_DATASET_PULL_BATCH_SIZE = 100;\nconst DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;\n\ninterface DatasetIdentifierOptions extends GlobalOpts {\n name?: string;\n id?: StringUUID;\n}\n\n/** Throw on the name/id mutual-exclusion rule. The wrapper renders the error. */\nfunction requireSingleIdentifier(opts: { name?: string; id?: StringUUID }): void {\n if (!opts.name && !opts.id) {\n throw new Error(\"Either name or id must be provided\");\n }\n if (opts.name && opts.id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n}\n\n/**\n * Pull all data from a dataset in batches.\n */\nconst pullAllData = async <D = any, T = any>(\n client: LaminarClient,\n identifier: { name?: string; id?: StringUUID },\n batchSize: number = DEFAULT_DATASET_PULL_BATCH_SIZE,\n offset: number = 0,\n limit?: number,\n): Promise<Datapoint<D, T>[]> => {\n let hasMore = true;\n let currentOffset = offset;\n const stopAt = limit !== undefined ? offset + limit : undefined;\n\n const result: Datapoint<D, T>[] = [];\n\n while (hasMore && (stopAt === undefined || currentOffset < stopAt)) {\n const data = await client.datasets.pull<D, T>({\n ...identifier,\n offset: currentOffset,\n limit: batchSize,\n });\n\n result.push(...data.items);\n\n // Stop if we received no items or fewer items than requested (end of data)\n if (data.items.length === 0 || data.items.length < batchSize) {\n hasMore = false;\n } else if (stopAt !== undefined && currentOffset + batchSize >= stopAt) {\n hasMore = false;\n } else if (data.totalCount !== undefined && currentOffset + batchSize >= data.totalCount) {\n hasMore = false;\n }\n\n currentOffset += batchSize;\n }\n\n if (limit !== undefined) {\n return result.slice(0, limit);\n }\n\n return result;\n};\n\n/**\n * Handle datasets list command. Pure handler — `withProjectClient` resolves the\n * client and owns the error envelope.\n */\nexport const handleDatasetsList = async (\n client: LaminarClient,\n opts: GlobalOpts,\n): Promise<void> => {\n const datasets = await client.datasets.listDatasets();\n\n if (opts.json) {\n outputJson(datasets);\n return;\n }\n\n if (datasets.length === 0) {\n console.log(\"No datasets found.\");\n return;\n }\n\n const rows = datasets.map((dataset) => {\n const createdAt = new Date(dataset.createdAt);\n const createdAtStr = createdAt.toISOString().replace('T', ' ').substring(0, 19);\n return [dataset.id, createdAtStr, dataset.name];\n });\n\n console.log(renderTable(['ID', 'Created At', 'Name'], rows));\n console.log(`\\nTotal: ${datasets.length} dataset(s)\\n`);\n};\n\n/**\n * Handle datasets push command.\n */\nexport const handleDatasetsPush = async (\n client: LaminarClient,\n paths: string[],\n opts: DatasetIdentifierOptions & {\n recursive?: boolean;\n batchSize?: number;\n },\n): Promise<void> => {\n requireSingleIdentifier(opts);\n\n const data = await loadFromPaths(paths, opts.recursive);\n\n if (data.length === 0) {\n throw new Error(\"No data to push\");\n }\n\n const identifier = opts.name ? { name: opts.name } : { id: opts.id };\n\n const result = await client.datasets.push({\n points: data,\n ...identifier,\n batchSize: opts.batchSize ?? DEFAULT_DATASET_PUSH_BATCH_SIZE,\n });\n\n if (opts.json) {\n outputJson({ datasetId: result?.datasetId, count: data.length });\n return;\n }\n\n logger.info(`Pushed ${data.length} data points to dataset ${opts.name || opts.id}`);\n};\n\n/**\n * Handle datasets pull command.\n */\nexport const handleDatasetsPull = async (\n client: LaminarClient,\n outputPath: string | undefined,\n opts: DatasetIdentifierOptions & {\n outputFormat?: 'json' | 'csv' | 'jsonl';\n batchSize?: number;\n limit?: number;\n offset?: number;\n },\n): Promise<void> => {\n requireSingleIdentifier(opts);\n\n const identifier = opts.name ? { name: opts.name } : { id: opts.id };\n\n const result = await pullAllData(\n client,\n identifier,\n opts.batchSize ?? DEFAULT_DATASET_PULL_BATCH_SIZE,\n opts.offset ?? 0,\n opts.limit,\n );\n\n if (outputPath) {\n await writeToFile(outputPath, result, opts.outputFormat);\n if (opts.json) {\n outputJson({ path: outputPath, count: result.length });\n } else {\n logger.info(`Successfully pulled ${result.length} data points to ${outputPath}`);\n }\n } else {\n if (opts.json) {\n outputJson(result);\n } else {\n printToConsole(result, opts.outputFormat ?? 'json');\n }\n }\n};\n\n/**\n * Handle datasets create command.\n */\nexport const handleDatasetsCreate = async (\n client: LaminarClient,\n name: string,\n paths: string[],\n opts: GlobalOpts & {\n outputFile: string;\n outputFormat?: 'json' | 'csv' | 'jsonl';\n recursive?: boolean;\n batchSize?: number;\n },\n): Promise<void> => {\n // Load data from input files\n const data = await loadFromPaths(paths, opts.recursive);\n\n if (data.length === 0) {\n throw new Error(\"No data to push\");\n }\n\n // Push data to create/populate the dataset\n logger.info(`Pushing ${data.length} data points to dataset '${name}'...`);\n\n await client.datasets.push({\n points: data,\n name,\n batchSize: opts.batchSize ?? DEFAULT_DATASET_PUSH_BATCH_SIZE,\n createDataset: true,\n });\n logger.info(`Successfully pushed ${data.length} data points to dataset '${name}'`);\n\n // Pull data back from the dataset\n logger.info(`Pulling data from dataset '${name}'...`);\n\n const result = await pullAllData(\n client,\n { name },\n opts.batchSize ?? DEFAULT_DATASET_PULL_BATCH_SIZE,\n 0,\n undefined,\n );\n\n // Save to output file\n await writeToFile(opts.outputFile, result, opts.outputFormat);\n\n if (opts.json) {\n outputJson({ name, path: opts.outputFile, count: result.length });\n } else {\n logger.info(\n `Successfully created dataset '${name}' `\n + `and saved ${result.length} datapoints to ${opts.outputFile}`,\n );\n }\n};\n","// Trace-metadata key the debugger UI reads the agent's note from. Metadata\n// naming stays `rollout.*` (matching `rollout.session_id`); the value is an\n// opaque string the frontend renders as markdown.\nexport const NOTE_METADATA_KEY = \"rollout.note\";\n\n/**\n * Normalize a user-supplied trace id (UUID or 32-char OTel hex, optionally\n * 0x-prefixed) to the dashed UUID form used by the SQL endpoint. Throws on\n * anything else so a typo fails loudly instead of querying nothing.\n */\nexport const normalizeTraceId = (traceId: string): string => {\n const id = traceId.trim().toLowerCase().replace(/^0x/, \"\");\n if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id)) {\n return id;\n }\n if (/^[0-9a-f]{32}$/.test(id)) {\n return id.replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n \"$1-$2-$3-$4-$5\",\n );\n }\n throw new Error(\n `Invalid trace id \"${traceId}\". Expected a UUID or a 32-char OTel hex trace id.`,\n );\n};\n\n/**\n * Extract the note from a trace's `metadata` column as returned by the SQL\n * endpoint (a JSON string; tolerate an already-parsed object too). Missing /\n * malformed metadata reads as \"no note\".\n */\nexport const readNoteFromMetadata = (metadata: unknown): string => {\n let parsed: unknown = metadata;\n if (typeof metadata === \"string\") {\n if (metadata === \"\") {\n return \"\";\n }\n try {\n parsed = JSON.parse(metadata);\n } catch {\n return \"\";\n }\n }\n if (typeof parsed !== \"object\" || parsed === null) {\n return \"\";\n }\n const note = (parsed as Record<string, unknown>)[NOTE_METADATA_KEY];\n return typeof note === \"string\" ? note : \"\";\n};\n","import { LaminarClient } from \"@lmnr-ai/client\";\n\nimport type { GlobalOpts } from \"../../auth/with-client\";\nimport { initializeLogger } from \"../../utils/logger\";\nimport { outputJson } from \"../../utils/output\";\nimport { readNoteFromMetadata } from \"../../utils/trace-note\";\n\nconst logger = initializeLogger();\n\n/**\n * Upsert the display name of a debug session. Update-only on the backend: a\n * session id unknown to the project 404s rather than creating a ghost session.\n *\n * Pure handler: the command wrapper (`withProjectClient`) resolves a user-token\n * {@link LaminarClient} (routes to `/v1/cli/*` with the resolved project) and\n * owns the error envelope.\n */\nexport const handleDebugSessionSetName = async (\n client: LaminarClient,\n sessionId: string,\n name: string,\n opts: GlobalOpts,\n): Promise<void> => {\n await client.rolloutSessions.setName({ sessionId, name });\n\n if (opts.json) {\n outputJson({ sessionId, name });\n return;\n }\n\n logger.info(`Set name of session ${sessionId} to \"${name}\".`);\n};\n\ninterface SessionTraceSummary {\n note: string;\n traceId: string;\n // Trace `end_time` — the closest thing to \"last updated\" on a trace (it\n // advances as spans keep arriving for the trace).\n endTime: string;\n}\n\n/**\n * Print a per-trace summary of a debug session: every trace whose metadata\n * groups it to the session (`rollout.session_id`), oldest first, with the\n * agent-authored note (`rollout.note`) attached to each.\n *\n * Pure handler: the command wrapper (`withProjectClient`) resolves a user-token\n * {@link LaminarClient} (routes to `/v1/cli/*` with the resolved project) and\n * owns the error envelope.\n */\nexport const handleDebugSessionSummary = async (\n client: LaminarClient,\n sessionId: string,\n opts: GlobalOpts,\n): Promise<void> => {\n // formatDateTime pins end_time to unambiguous ISO-8601 UTC — the raw\n // column serializes as ClickHouse's space-separated local-looking format.\n const rows = await client.sql.query(\n \"SELECT id, \" +\n \"formatDateTime(end_time, '%Y-%m-%dT%H:%i:%S.%fZ') AS end_time, \" +\n \"metadata FROM traces \" +\n \"WHERE simpleJSONExtractString(metadata, 'rollout.session_id') \" +\n \"= {session_id:String} \" +\n \"ORDER BY start_time\",\n { session_id: sessionId },\n );\n const traces: SessionTraceSummary[] = rows.map((row) => ({\n note: readNoteFromMetadata(row.metadata),\n traceId: String(row.id ?? \"\"),\n endTime: String(row.end_time ?? \"\"),\n }));\n\n if (opts.json) {\n outputJson(traces);\n return;\n }\n\n if (traces.length === 0) {\n console.log(`No traces found for session ${sessionId}.`);\n return;\n }\n\n const blocks = traces.map((trace) => {\n const tag = `<trace id=\"${trace.traceId}\" end-time=\"${trace.endTime}\"/>`;\n return trace.note ? `${trace.note}\\n${tag}` : tag;\n });\n console.log(blocks.join(\"\\n\\n\"));\n};\n","import { createColors } from \"picocolors\";\n\n// Decide color support per stream: NO_COLOR (present at any value) disables,\n// FORCE_COLOR (present and not \"0\") forces on, otherwise fall back to that\n// stream's own TTY-ness. We key each stream independently because the CLI writes\n// human status to STDERR (stdout is reserved for the `--json` contract) but ALSO\n// prints a human summary to STDOUT in non-json mode — each should follow its own\n// stream's redirection (e.g. `setup > out.txt` must not get ANSI in the file).\nfunction enabledFor(stream: NodeJS.WriteStream): boolean {\n if (\"NO_COLOR\" in process.env) return false;\n if (\"FORCE_COLOR\" in process.env && process.env.FORCE_COLOR !== \"0\") return true;\n return Boolean(stream.isTTY);\n}\n\n// Human status lines (✓ / ⚠ / errors) → stderr.\nexport const pc = createColors(enabledFor(process.stderr));\n// The non-json human summary (\"Next steps\") → stdout.\nexport const pcOut = createColors(enabledFor(process.stdout));\n\n// Laminar brand orange (#D0754E = rgb(208,117,78)). picocolors only ships the 16\n// ANSI colors, so wrap a truecolor escape ourselves — gated on stderr color\n// support (the brand banner is a stderr line, same as `pc`).\nconst stderrColorEnabled = enabledFor(process.stderr);\nexport const orange = (text: string): string =>\n stderrColorEnabled ? `\\x1b[38;2;208;117;78m${text}\\x1b[39m` : text;\n","import open from \"open\";\n\nimport { type Credentials, writeCredentials } from \"../../auth/credentials\";\nimport {\n CLI_SCOPE,\n decodeJwtExp,\n fetchSession,\n initiateDevice,\n mintAccessJwt,\n parseProjectFromMetadata,\n pollDevice,\n} from \"../../auth/device\";\nimport { DEFAULT_FRONTEND_URL } from \"../../constants\";\nimport { pc } from \"../../utils/colors\";\n\nexport interface LoginOptions {\n frontendUrl?: string;\n noBrowser?: boolean;\n}\n\nexport interface LoginResult {\n /** The signed-in user's id (from the BetterAuth session). */\n userId: string;\n /** The signed-in user's email, when present on the session. */\n userEmail: string | null;\n /**\n * The projectId the user selected/created in the browser, delivered back via\n * the device-token `x-lmnr-metadata` response header (see\n * `parseProjectFromMetadata`). Null when the browser had nothing to select.\n */\n projectId: string | null;\n}\n\nexport async function handleLogin(options: LoginOptions): Promise<LoginResult> {\n const issuer = pick(options.frontendUrl, process.env.LMNR_FRONTEND_URL, DEFAULT_FRONTEND_URL);\n // NOTE: login does NOT resolve/store a data-API baseUrl — the device flow,\n // JWT mint and session fetch all hit `issuer` (frontend). `--base-url` on\n // login is accepted but inert (candidate for removal); data commands resolve\n // baseUrl themselves via resolveBaseUrl.\n\n const da = await initiateDevice(issuer, CLI_SCOPE);\n const completeUri = da.verification_uri_complete ?? da.verification_uri;\n process.stderr.write(\n `\\nOpen this URL in your browser to authorize:\\n ${pc.cyan(completeUri)}\\n`,\n );\n if (da.user_code) {\n process.stderr.write(`Code: ${pc.bold(pc.cyan(da.user_code))}\\n\\n`);\n }\n\n if (!options.noBrowser) {\n try {\n await open(completeUri);\n } catch {\n // Best-effort. The user can copy/paste the URL.\n }\n }\n\n process.stderr.write(pc.dim(\"Waiting for authorization...\\n\"));\n const token = await pollDevice(issuer, da.device_code, {\n intervalSeconds: da.interval,\n timeoutSeconds: da.expires_in,\n });\n\n // The device token's access_token is the durable session token (refresh).\n const sessionToken = token.access_token;\n const jwt = await mintAccessJwt(issuer, sessionToken);\n const session = await fetchSession(issuer, sessionToken);\n\n const now = new Date().toISOString();\n const creds: Credentials = {\n version: 1,\n issuer,\n sessionToken,\n accessToken: jwt,\n accessTokenExpiresAt: decodeJwtExp(jwt) ?? now,\n sessionExpiresAt:\n typeof token.expires_in === \"number\"\n ? new Date(Date.now() + token.expires_in * 1000).toISOString()\n : undefined,\n userEmail: session.email || undefined,\n userId: session.id,\n createdAt: now,\n lastUsedAt: now,\n };\n await writeCredentials(creds);\n\n // NOTE: the user-facing \"logged in / next steps\" summary is intentionally NOT\n // printed here — handleLogin is shared with `setup`, which prints its own\n // summary. The `login` command prints the summary itself (see src/index.ts).\n\n return {\n userId: session.id,\n userEmail: session.email || null,\n projectId: parseProjectFromMetadata(token.metadata),\n };\n}\n\nfunction pick(...candidates: (string | undefined)[]): string {\n for (const c of candidates) {\n if (c && c.length > 0) return c;\n }\n return \"\";\n}\n","import {\n type Credentials,\n credentialsPath,\n deleteCredentials,\n readCredentials,\n} from \"../../auth/credentials\";\n\n/**\n * Best-effort server-side session revoke via POST /api/auth/sign-out with the\n * session token as Bearer. Logout MUST complete locally even if the server is\n * unreachable — the user expects \"log me out\" to remove the file. On any\n * failure we log to stderr and continue.\n */\nexport async function revokeSession(creds: Credentials): Promise<void> {\n if (!creds.sessionToken || creds.sessionToken.length === 0) {\n return;\n }\n const url = `${trimSlash(creds.issuer)}/api/auth/sign-out`;\n try {\n // BetterAuth's sign-out 500s on an empty body (JSON parse fails); send `{}`.\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${creds.sessionToken}`,\n \"content-type\": \"application/json\",\n },\n body: \"{}\",\n });\n if (!res.ok) {\n process.stderr.write(\n `warning: session revoke at ${url} returned ${res.status}; ` +\n \"local credentials still removed.\\n\",\n );\n }\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(\n `warning: session revoke at ${url} failed (${msg}); local credentials still removed.\\n`,\n );\n }\n}\n\nexport async function handleLogout(): Promise<void> {\n const creds = await readCredentials();\n if (!creds) {\n process.stderr.write(\"Already logged out.\\n\");\n return;\n }\n const label = creds.userEmail ?? creds.userId;\n // Delete the local file FIRST, then best-effort revoke the server session.\n // \"Log me out\" must remove the credentials even if the network revoke hangs\n // or fails. Accepted residual race: a concurrent near-expiry refresh may\n // re-write creds just after this delete (durable token + inert JWT; no lock).\n await deleteCredentials();\n await revokeSession(creds);\n process.stderr.write(`Logged out of ${label}. Removed ${credentialsPath()}.\\n`);\n}\n\nfunction trimSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n","import { LaminarClient } from \"@lmnr-ai/client\";\n\nimport type { GlobalOpts } from \"../../auth/with-client\";\nimport { outputJson } from \"../../utils/output\";\nimport { readProjectLink } from \"../../utils/project-link\";\nimport { renderTable } from \"../../utils/table\";\n\n/**\n * List the projects the signed-in user can access (discovery — no project\n * scope). Pure handler: the `withUserToken` wrapper resolves the user-token\n * client and owns the error envelope.\n */\nexport const handleProjectsList = async (\n client: LaminarClient,\n opts: GlobalOpts,\n): Promise<void> => {\n const projects = await client.cli.listProjects();\n\n // Mark the project linked to the current directory (.lmnr/project.json).\n const linked = (await readProjectLink())?.projectId;\n\n if (opts.json) {\n outputJson(projects.map((p) => ({ ...p, linked: p.id === linked })));\n return;\n }\n\n if (projects.length === 0) {\n console.log(\"No projects found. Create one in the dashboard, then run `lmnr-cli setup`.\");\n return;\n }\n\n const columns = [\"\", \"Workspace\", \"Project\", \"Project ID\"];\n const rows = projects.map((p) => [p.id === linked ? \"●\" : \"\", p.workspaceName, p.name, p.id]);\n console.log(renderTable(columns, rows));\n console.log(\n linked\n ? \"\\n● = linked to this directory (lmnr-cli setup). \" +\n \"Override per-command with --project-id.\\n\"\n : \"\\nNot linked here. Run `lmnr-cli setup` in your project directory, \" +\n \"or pass --project-id.\\n\",\n );\n};\n","// Standalone `GET /v1/project` probe authed by a PROJECT API KEY (not the\n// user JWT). It's a separate helper rather than a `CliResource` method because\n// `CliResource` is keyed by the user JWT, while this probe is keyed by the\n// project key already sitting in the environment — overloading the resource's\n// single-key model would be confusing.\n\nimport { DEFAULT_BASE_URL } from \"../constants\";\n\nfunction trimSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/**\n * Outcome of probing which project an `LMNR_PROJECT_API_KEY` belongs to. These\n * are deliberately distinct so the caller doesn't conflate \"key is bad\" with\n * \"couldn't reach the server\":\n * - `ok` → key verified; `projectId` is its owner.\n * - `invalid` → 401: key revoked/invalid. Safe to mint a fresh one.\n * - `unverifiable` → network error / non-401 / malformed body. The key may be\n * perfectly valid — caller MUST NOT mint (minting would clobber it on a blip).\n */\nexport type KeyProbe =\n | { status: \"ok\"; projectId: string }\n | { status: \"invalid\" }\n | { status: \"unverifiable\" };\n\nexport async function probeProjectKey(\n projectApiKey: string,\n baseUrl: string = DEFAULT_BASE_URL,\n port?: number,\n): Promise<KeyProbe> {\n // Compose host + port the same way the real CLI clients do (baseUrl carries\n // no port by convention; LMNR_HTTP_PORT/--port is separate). new URL().port\n // rather than `:${port}` concat so a baseUrl with a path still works.\n const url = new URL(trimSlash(baseUrl));\n if (port) url.port = String(port);\n url.pathname = \"/v1/project\";\n let res: Response;\n try {\n res = await fetch(url.toString(), {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${projectApiKey}`,\n Accept: \"application/json\",\n },\n });\n } catch {\n return { status: \"unverifiable\" };\n }\n if (res.status === 401) return { status: \"invalid\" };\n if (!res.ok) return { status: \"unverifiable\" };\n const body = (await res.json().catch(() => null)) as { projectId?: string } | null;\n return body?.projectId ? { status: \"ok\", projectId: body.projectId } : { status: \"unverifiable\" };\n}\n","import { execFile } from \"node:child_process\";\nimport {\n access,\n readFile,\n rename,\n stat,\n writeFile,\n} from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nconst DEFAULT_VAR_NAME = \"LMNR_PROJECT_API_KEY\";\n\n// Env files we inspect, highest precedence first (Next.js-style, minus the\n// NODE_ENV-specific rungs). `.env.local` is the JS/Next secret convention\n// (gitignored); `.env` is the cross-ecosystem default every loader reads —\n// including Python's python-dotenv / pydantic, which don't know `.env.local`.\nconst CANDIDATE_FILES = [\".env.local\", \".env\"] as const;\n\nexport interface WriteEnvResult {\n /** Absolute path of the .env file. */\n path: string;\n /** True when the file did not exist before this call. */\n created: boolean;\n /** True when an existing `<varName>=` line was overwritten. */\n replaced: boolean;\n}\n\n/**\n * Write/replace `<varName>=<value>` in the .env file at `envPath`.\n *\n * Semantics:\n * - If the file does not exist: create it with mode 0o600 and a single line.\n * - If the file exists:\n * - Replace an existing `^<varName>\\s*=.*` line in place (preserves comments,\n * ordering, and other keys).\n * - Otherwise append the line (with a leading newline if the file does not\n * end in one).\n * - DO NOT change the file mode on existing files — the user may have set\n * a deliberate mode and changing it surprises them.\n * - Writes are atomic: write to `<envPath>.tmp`, then rename.\n */\nexport async function writeEnvFile(\n envPath: string,\n value: string,\n varName: string = DEFAULT_VAR_NAME,\n): Promise<WriteEnvResult> {\n const exists = await fileExists(envPath);\n\n if (!exists) {\n const contents = `${varName}=${value}\\n`;\n await atomicWrite(envPath, contents, 0o600);\n return { path: envPath, created: true, replaced: false };\n }\n\n const original = await readFile(envPath, \"utf-8\");\n // ^ at line start, m flag so . doesn't match newlines.\n const regex = new RegExp(`^${escapeRegex(varName)}\\\\s*=.*$`, \"m\");\n let next: string;\n let replaced = false;\n if (regex.test(original)) {\n next = original.replace(regex, `${varName}=${value}`);\n replaced = true;\n } else {\n const prefix = original.endsWith(\"\\n\") || original.length === 0 ? original : `${original}\\n`;\n next = `${prefix}${varName}=${value}\\n`;\n }\n // Capture existing mode so the tmp inherits dest's perms — POSIX `rename`\n // adopts the source inode's permissions, so without this an existing 0o600\n // .env would silently widen to the umask default (0o644) on every rerun.\n const existingMode = (await stat(envPath)).mode & 0o777;\n await atomicWrite(envPath, next, existingMode);\n return { path: envPath, created: false, replaced };\n}\n\n/**\n * Read a single env var's value from a .env file. Returns null when the file\n * is missing, the var is absent, or its value is empty/whitespace.\n */\nexport async function readEnvVar(\n envPath: string,\n varName: string = DEFAULT_VAR_NAME,\n): Promise<string | null> {\n if (!(await fileExists(envPath))) return null;\n const original = await readFile(envPath, \"utf-8\");\n const regex = new RegExp(`^${escapeRegex(varName)}\\\\s*=(.*)$`, \"m\");\n const match = original.match(regex);\n if (!match) return null;\n const value = match[1].trim().replace(/^[\"']|[\"']$/g, \"\");\n return value.length > 0 ? value : null;\n}\n\n/** Where an existing key was found: the process environment, or a specific file. */\nexport type EnvKeySource = { type: \"process-env\" } | { type: \"file\"; path: string };\n\nexport interface EnvKeyLocation {\n value: string;\n source: EnvKeySource;\n}\n\n/**\n * Find an already-configured key, checking `process.env` → `.env.local` → `.env`\n * (first match wins, mirroring Next.js precedence). `process.env` comes first\n * because an exported var is what actually runs, regardless of language.\n */\nexport async function findEnvKey(\n cwd: string,\n varName: string = DEFAULT_VAR_NAME,\n): Promise<EnvKeyLocation | null> {\n const fromProcess = process.env[varName]?.trim();\n if (fromProcess) return { value: fromProcess, source: { type: \"process-env\" } };\n for (const name of CANDIDATE_FILES) {\n const path = resolve(cwd, name);\n const value = await readEnvVar(path, varName);\n if (value) return { value, source: { type: \"file\", path } };\n }\n return null;\n}\n\n/**\n * LMNR_* config keys the CLI hydrates from a project `.env.local` / `.env`.\n * Curated on purpose — we do NOT slurp the whole file, so unrelated app secrets\n * (model API keys, etc.) never enter the CLI process. Notable exclusions:\n * - `LMNR_GRPC_PORT`: the CLI is REST-only (no gRPC), so it has no use for it.\n * - `LMNR_LOG_LEVEL`: loggers are built at module-import time (before\n * `loadLocalEnv` runs), so hydrating it here would silently have no effect.\n * - `LMNR_PROJECT_ID`: the project comes from `--project-id` or\n * `.lmnr/project.json` only; `resolveAuth` ignores the env var, so loading\n * it here would just contradict that.\n */\nexport const AUTOLOADED_ENV_KEYS = [\n \"LMNR_BASE_URL\",\n \"LMNR_HTTP_PORT\",\n \"LMNR_FRONTEND_URL\",\n] as const;\n\n/**\n * Hydrate `process.env` from `.env.local` / `.env` in `cwd` for the curated\n * {@link AUTOLOADED_ENV_KEYS}, WITHOUT overriding values already present in the\n * environment (a real exported var / Claude Code `settings.json` env always\n * wins — `findEnvKey` checks `process.env` first and we skip those).\n *\n * Why this exists: Claude Code and many other runners do NOT inject a project\n * `.env` into a spawned subprocess's environment, so self-hosters who put\n * `LMNR_BASE_URL` / `LMNR_HTTP_PORT` in `.env` previously had to export them or\n * pass flags on every call. cwd-only, no upward directory walk (mirrors\n * dotenv's default) — the CLI must be invoked from the dir holding the `.env`.\n */\nexport async function loadLocalEnv(\n cwd: string,\n keys: readonly string[] = AUTOLOADED_ENV_KEYS,\n): Promise<void> {\n for (const key of keys) {\n const found = await findEnvKey(cwd, key);\n // Only hydrate from a file; a process-env hit means it's already set.\n if (found?.source.type === \"file\") {\n process.env[key] = found.value;\n }\n }\n}\n\n/**\n * Pick the file to write a freshly-minted key into:\n * - rewrite in place if the key already lives in a file,\n * - else prefer an existing `.env.local` (its presence proves the project opted\n * into the gitignored-secret convention) — but never CREATE one, since Python\n * loaders ignore it,\n * - else `.env` (the default every ecosystem loads).\n */\nexport async function resolveEnvWriteTarget(\n cwd: string,\n existing: EnvKeyLocation | null,\n): Promise<string> {\n if (existing?.source.type === \"file\") return existing.source.path;\n const local = resolve(cwd, \".env.local\");\n if (await fileExists(local)) return local;\n return resolve(cwd, \".env\");\n}\n\n/**\n * Whether `path` is gitignored. Returns null when it can't be determined (not a\n * git repo / git absent) so callers can stay silent rather than warn wrongly.\n */\nexport async function isPathGitIgnored(path: string): Promise<boolean | null> {\n try {\n await execFileAsync(\"git\", [\"check-ignore\", \"-q\", path]);\n return true; // exit 0 = ignored\n } catch (err) {\n // exit 1 = definitely not ignored; 128 (not a repo) / ENOENT (no git) = unknown\n return (err as { code?: number }).code === 1 ? false : null;\n }\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function atomicWrite(\n path: string,\n contents: string,\n mode: number | undefined,\n): Promise<void> {\n const tmp = `${path}.tmp`;\n await writeFile(tmp, contents, mode === undefined ? undefined : { mode });\n await rename(tmp, path);\n}\n\nfunction escapeRegex(raw: string): string {\n return raw.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","// Source coordinates for the Laminar agent skill, fetched from the public\n// lmnr-skills repo at `lmnr-cli setup` time via giget (see\n// ../utils/install-skill.ts).\n\nexport const SKILL_REPO = \"lmnr-ai/lmnr-skills\";\nexport const SKILL_REF = \"main\";\nexport const SKILL_NAME = \"laminar\";\n\n/**\n * giget source for the pinned skill subdir: `github:<owner>/<repo>/<subdir>#<ref>`.\n * giget resolves this against codeload.github.com, gunzips, untars, strips the\n * `repo-<ref>/` prefix, and extracts only the subdir — all the mechanics we'd\n * otherwise hand-roll.\n */\nexport function skillSource(): string {\n return `github:${SKILL_REPO}/skills/${SKILL_NAME}#${SKILL_REF}`;\n}\n","import { downloadTemplate } from \"giget\";\n\nimport { skillSource } from \"./laminar-skill\";\n\n/**\n * Download the pinned Laminar skill subtree into `dir` using giget.\n *\n * giget owns every quirk we'd otherwise hand-roll: the codeload tarball URL,\n * gunzip, untar, stripping the `repo-<ref>/` leading segment, subdir filtering,\n * and ref pinning. `force` overwrites `dir` so reruns are idempotent.\n *\n * We deliberately do NOT pass `preferOffline`: giget caches the tarball keyed by\n * REF name, and SKILL_REF is a moving branch (`main` / a feature branch), so\n * `preferOffline` would reuse a stale cached tarball forever — reinstalling\n * files that were since deleted upstream. Without it, giget revalidates via the\n * stored etag and re-downloads when the branch moved.\n *\n * Throws on network / resolve / extract errors — callers (skill install is\n * best-effort) catch and skip.\n */\nexport async function downloadSkill(dir: string): Promise<void> {\n await downloadTemplate(skillSource(), {\n dir,\n force: true,\n });\n}\n","import { access, cp, mkdir, mkdtemp, readdir, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join, relative } from \"node:path\";\n\nimport { downloadSkill } from \"../skill/fetch-skill\";\nimport { SKILL_NAME, skillSource } from \"../skill/laminar-skill\";\n\n// Agent dirs we look for in the project root. Order matters only for the\n// \"none present\" default below.\nconst AGENT_DIRS = [\".claude\", \".cursor\", \".codex\", \".agents\"] as const;\n\n// When NO agent dir exists we default to writing the skill into BOTH\n// `.claude/` (Claude Code reads `.claude/skills/`) and `.agents/`, so whichever\n// agent the project later adopts can find it.\nconst DEFAULT_AGENT_DIRS = [\".claude\", \".agents\"];\n\nexport interface InstallSkillResult {\n /** Absolute paths of every written file (SKILL.md + references/...). */\n written: string[];\n /** True when no agent dir existed and we defaulted to `.claude/` + `.agents/`. */\n defaulted: boolean;\n /**\n * True when the skill could not be fetched (network failure) and install was\n * skipped. `written` is empty and `defaulted` is false.\n */\n skipped: boolean;\n}\n\n/**\n * Fetch the pinned Laminar skill (`SKILL_NAME`) from the lmnr-skills repo and\n * write its full tree into every present agent dir under `cwd`\n * (`<dir>/skills/<SKILL_NAME>/SKILL.md`, `.../references/*.md`, ...). If none\n * are present, default to BOTH `.claude/` and `.agents/`. Idempotent —\n * overwrites on rerun.\n *\n * We download ONCE into a temp staging dir (one network hit) and copy it into\n * each agent dir. Skill install is the last, best-effort step of `setup`: a\n * download failure MUST NOT break setup — on error we log a warning and return\n * `{ written: [], defaulted: false, skipped: true }`.\n *\n * For .cursor/.codex the skills layout is not guaranteed to match CC; we write\n * the CC-guaranteed `skills/<SKILL_NAME>/` shape there too rather than\n * inventing a path that silently loads nothing.\n */\nexport async function installSkill(\n cwd: string = process.cwd(),\n): Promise<InstallSkillResult> {\n const staging = await mkdtemp(join(tmpdir(), \"lmnr-skill-\"));\n try {\n try {\n await downloadSkill(staging);\n } catch (err) {\n process.stderr.write(\n `Warning: could not fetch the Laminar skill (${skillSource()}): ` +\n `${describeError(err)}; skipping skill install.\\n`,\n );\n return { written: [], defaulted: false, skipped: true };\n }\n\n // Files relative to the staging root (e.g. \"SKILL.md\", \"references/x.md\").\n const relFiles = (await readdir(staging, { recursive: true, withFileTypes: true }))\n .filter((d) => d.isFile())\n .map((d) => relative(staging, join(d.parentPath, d.name)));\n\n const present: string[] = [];\n for (const dir of AGENT_DIRS) {\n if (await dirExists(join(cwd, dir))) present.push(dir);\n }\n\n const targets = present.length > 0 ? present : DEFAULT_AGENT_DIRS;\n const written: string[] = [];\n for (const dir of targets) {\n const skillRoot = join(cwd, dir, \"skills\", SKILL_NAME);\n // Replace, don't merge: `cp` alone would leave behind files that were\n // deleted upstream (e.g. a removed reference doc) from a prior install.\n await rm(skillRoot, { recursive: true, force: true });\n await mkdir(skillRoot, { recursive: true });\n await cp(staging, skillRoot, { recursive: true });\n for (const rel of relFiles) written.push(join(skillRoot, rel));\n }\n\n return { written, defaulted: present.length === 0, skipped: false };\n } finally {\n await rm(staging, { recursive: true, force: true });\n }\n}\n\nasync function dirExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction describeError(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n","import { hostname } from \"node:os\";\nimport { relative } from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\n\nimport { type CliProject, LaminarClient } from \"@lmnr-ai/client\";\n\nimport { version } from \"../../../package.json\";\nimport { type Credentials, readCredentials } from \"../../auth/credentials\";\nimport { probeProjectKey } from \"../../auth/project-id\";\nimport { envHttpPort, refreshIfNeeded } from \"../../auth/resolve\";\nimport { orange, pc, pcOut } from \"../../utils/colors\";\nimport {\n findEnvKey,\n isPathGitIgnored,\n resolveEnvWriteTarget,\n writeEnvFile,\n} from \"../../utils/env-file\";\nimport { installSkill } from \"../../utils/install-skill\";\nimport { type ProjectLink, readProjectLink, writeProjectLink } from \"../../utils/project-link\";\nimport { handleLogin } from \"../login\";\n\nconst DEFAULT_FRONTEND_URL = \"https://www.laminar.sh\";\nconst DEFAULT_BASE_URL = \"https://api.lmnr.ai\";\n\n// Exit codes (machine-readable contract — each distinct so automation can\n// branch on the failure mode):\n// 4 no_access — user lacks access to the linked project\n// 6 login_failed — device-flow login failed / no creds after login\n// 7 no_project — no project to select (and none could be created)\n// 8 env_write_failed — minted a key but couldn't write ./.env\n// 9 setup_key_failed — POST /api/cli/api-key failed\n// 10 list_projects_failed — GET /v1/cli/projects (discovery) failed\n// 11 key_probe_failed — couldn't verify the existing key (network/server error)\n// 12 key_mismatch — existing key belongs to a different project\nconst EXIT_NO_ACCESS = 4;\nconst EXIT_LOGIN_FAILED = 6;\nconst EXIT_NO_PROJECT = 7;\nconst EXIT_ENV_WRITE_FAILED = 8;\nconst EXIT_SETUP_KEY_FAILED = 9;\nconst EXIT_LIST_PROJECTS_FAILED = 10;\nconst EXIT_KEY_PROBE_FAILED = 11;\nconst EXIT_KEY_MISMATCH = 12;\n\nexport interface SetupOptions {\n writeEnv?: boolean;\n json?: boolean;\n noBrowser?: boolean;\n frontendUrl?: string;\n baseUrl?: string;\n /**\n * Explicit project id. Disambiguates when the user can access >1 project\n * (otherwise --json setup errors `project_ambiguous`). Validated against the\n * user's accessible projects before linking.\n */\n projectId?: string;\n}\n\ninterface SetupKeyResponse {\n apiKey: string;\n apiKeyId: string;\n projectId: string;\n projectName: string;\n workspaceId: string;\n workspaceName: string;\n}\n\nexport interface SetupResult {\n projectId: string;\n projectName: string | null;\n workspaceId: string | null;\n workspaceName: string | null;\n /** The key written to .env, or null when an existing matching key was reused. */\n apiKey: string | null;\n envFileUpdated: string | null;\n /** SKILL.md paths written by the skill installer. */\n skillsInstalled: string[];\n frontendUrl: string;\n userEmail: string | null;\n}\n\n/**\n * Directory-scoped onboarding (SPEC decision tree):\n * - log in if needed (browser picks/creates the project; its id rides back on\n * the device-token metadata, see parseProjectFromMetadata),\n * - resolve a project for this directory (`.lmnr/project.json`), enforcing\n * access,\n * - mint a project API key only when one isn't already configured for this\n * project (checked across process.env → .env.local → .env), then write it to\n * an existing .env.local or else .env,\n * - install the Laminar skill into present agent dirs,\n * - print a summary.\n *\n * The minted key goes ONLY into the project's env file, never into\n * credentials.json (which stores user-scoped BetterAuth tokens).\n */\nexport async function handleSetup(options: SetupOptions): Promise<void> {\n const writeEnv = options.writeEnv !== false;\n const frontendUrl = pick(\n options.frontendUrl,\n process.env.LMNR_FRONTEND_URL,\n DEFAULT_FRONTEND_URL,\n );\n const baseUrl = pick(options.baseUrl, process.env.LMNR_BASE_URL, DEFAULT_BASE_URL);\n const isJson = options.json === true;\n\n if (!isJson) {\n process.stderr.write(`\\n${orange(\"Laminar CLI\")} ${pc.dim(`v${version}`)}\\n\\n`);\n }\n\n const cwd = process.cwd();\n // Detect an already-configured key across process.env → .env.local → .env.\n const existingKey = await findEnvKey(cwd);\n\n let creds: Credentials | null = await safeReadCredentials();\n let link = await readProjectLink();\n\n // --- 1. Login + project resolution ---------------------------------------\n\n if (!creds) {\n // Not logged in: run the device flow. The browser is where the project is\n // chosen/created (when there's no link), and the chosen id rides back on\n // the device-token metadata (parseProjectFromMetadata).\n let login;\n try {\n login = await handleLogin({ frontendUrl, noBrowser: options.noBrowser });\n } catch (err) {\n emitError(isJson, \"login_failed\", describeError(err));\n process.exit(EXIT_LOGIN_FAILED);\n }\n creds = await safeReadCredentials();\n if (!creds) {\n emitError(isJson, \"login_failed\", \"credentials missing after login\");\n process.exit(EXIT_LOGIN_FAILED);\n }\n\n const issuer = creds.issuer || frontendUrl;\n const userBaseUrl = baseUrl;\n\n if (link) {\n // Directory already declares the project — ignore the metadata-borne id\n // and assert the freshly-authenticated user can access the linked project.\n await assertAccess(creds, userBaseUrl, link.projectId, isJson);\n } else if (login.projectId) {\n // Browser-selected (or just-created) project. Trust it and write the link.\n link = await writeLink(issuer, userBaseUrl, login.projectId, isJson);\n } else {\n // Defensive: fall back to the CLI picker if the browser didn't attach a\n // project via metadata.\n link = await resolveProjectViaCli(creds, userBaseUrl, issuer, isJson, options);\n }\n } else {\n // Already logged in.\n const userBaseUrl = baseUrl;\n const issuer = creds.issuer || frontendUrl;\n if (link) {\n await assertAccess(creds, userBaseUrl, link.projectId, isJson);\n } else {\n link = await resolveProjectViaCli(creds, userBaseUrl, issuer, isJson, options);\n }\n }\n\n if (!isJson) {\n process.stderr.write(`${pc.green(\"✓\")} Logged in as ${creds.userEmail ?? \"<unknown>\"}\\n`);\n process.stderr.write(\n `${pc.green(\"✓\")} Project: ${link.projectName ?? link.projectId}` +\n (link.workspaceName ? pc.dim(` (${link.workspaceName})`) : \"\") +\n \"\\n\",\n );\n }\n\n // --- 2. Assert invariants -------------------------------------------------\n\n if (!creds || !link.projectId) {\n emitError(isJson, \"setup_invariant\", \"missing credentials or project after resolution\");\n process.exit(EXIT_NO_PROJECT);\n }\n\n const issuer = creds.issuer || frontendUrl;\n const userBaseUrl = baseUrl;\n\n // --- 3. Key handling (SPEC 36-42) -----------------------------------------\n\n let apiKey: string | null = null;\n let envPath: string | null = null;\n let keyMeta: SetupKeyResponse | null = null;\n\n let needMint = true;\n if (existingKey) {\n const probe = await probeProjectKey(existingKey.value, userBaseUrl, envHttpPort());\n const where =\n existingKey.source.type === \"process-env\"\n ? \"your environment\"\n : relative(cwd, existingKey.source.path);\n\n if (probe.status === \"unverifiable\") {\n // Couldn't verify the key (network/server error). Do NOT mint — that would\n // clobber a possibly-valid key on a transient blip. Abort so the user retries.\n emitError(\n isJson,\n \"key_probe_failed\",\n `Couldn't verify the existing Project API Key in ${where} (network or server error). ` +\n \"Check your connection and re-run.\",\n );\n process.exit(EXIT_KEY_PROBE_FAILED);\n } else if (probe.status === \"ok\" && probe.projectId === link.projectId) {\n // Already configured for this project. Respect the user's setup: no mint,\n // no write (option a) — including when the key only lives in process.env.\n needMint = false;\n if (!isJson) {\n process.stderr.write(`${pc.green(\"✓\")} Project API Key already set in ${where}\\n`);\n }\n } else if (probe.status === \"ok\") {\n // Valid key, but for a DIFFERENT project. Refuse to clobber it — abort so the\n // user resolves the conflict deliberately rather than silently overwriting.\n emitError(\n isJson,\n \"key_mismatch\",\n `The Project API Key in ${where} belongs to a different project (${probe.projectId}), ` +\n `not the one linked here (${link.projectId}). Remove or update it, then re-run.`,\n );\n process.exit(EXIT_KEY_MISMATCH);\n } else if (!isJson) {\n // invalid / revoked (401) — minting a fresh key is the correct recovery.\n process.stderr.write(\n `${pc.yellow(\"⚠\")} Existing Project API Key in ${where} is invalid or revoked, ` +\n `minting a new one\\n`,\n );\n }\n }\n\n if (needMint) {\n try {\n keyMeta = await mintSetupKey(issuer, creds.sessionToken, link.projectId);\n } catch (err) {\n emitError(isJson, \"setup_key_failed\", describeError(err));\n process.exit(EXIT_SETUP_KEY_FAILED);\n }\n apiKey = keyMeta.apiKey;\n\n // Backfill display details onto the link if we learned them while minting.\n if (!link.projectName && keyMeta.projectName) link.projectName = keyMeta.projectName;\n if (!link.workspaceName && keyMeta.workspaceName) link.workspaceName = keyMeta.workspaceName;\n if (!link.workspaceId && keyMeta.workspaceId) link.workspaceId = keyMeta.workspaceId;\n\n if (writeEnv) {\n const target = await resolveEnvWriteTarget(cwd, existingKey);\n try {\n const result = await writeEnvFile(target, apiKey);\n envPath = result.path;\n if (!isJson) {\n const rel = relative(cwd, result.path);\n const verb = result.created\n ? \"Created\"\n : result.replaced\n ? \"Updated LMNR_PROJECT_API_KEY in\"\n : \"Added LMNR_PROJECT_API_KEY to\";\n process.stderr.write(`${pc.green(\"✓\")} ${verb} ${rel}\\n`);\n // The key is a secret; nudge if it landed in a tracked file.\n if ((await isPathGitIgnored(result.path)) === false) {\n process.stderr.write(\n `${pc.yellow(\"⚠\")} ${rel} isn't gitignored; add it so the key isn't committed\\n`,\n );\n }\n }\n } catch (err) {\n process.stderr.write(\n `\\n${pc.red(\"ERROR\")}: failed to write ${target}: ${describeError(err)}\\n` +\n pc.dim(\"Your API key (set it manually):\") +\n `\\n LMNR_PROJECT_API_KEY=${apiKey}\\n\\n`,\n );\n if (isJson) {\n process.stdout.write(\n JSON.stringify({\n error: \"env_write_failed\",\n apiKey,\n projectId: link.projectId,\n message: describeError(err),\n }) + \"\\n\",\n );\n }\n process.exit(EXIT_ENV_WRITE_FAILED);\n }\n }\n }\n\n // --- 4. Skill install -----------------------------------------------------\n\n let skillsInstalled: string[] = [];\n try {\n // installSkill fetches the skill from the lmnr-skills repo and is\n // best-effort: it logs + returns `skipped: true` on network/codeload\n // failure rather than throwing, so setup never breaks here.\n const skillResult = await installSkill(process.cwd());\n skillsInstalled = skillResult.written;\n if (!isJson) {\n if (skillResult.skipped) {\n process.stderr.write(pc.dim(\" Laminar skill install skipped\\n\"));\n } else if (skillResult.written.length > 0) {\n // One mark for the whole skill, not one per file (SKILL.md + references).\n const note = skillResult.defaulted\n ? pc.dim(\" (no agent dir found; defaulted to .claude and .agents)\")\n : \"\";\n process.stderr.write(`${pc.green(\"✓\")} Installed Laminar skill${note}\\n`);\n }\n }\n } catch (err) {\n if (!isJson) {\n process.stderr.write(\n `${pc.yellow(\"Warning\")}: could not install Laminar skill (${describeError(err)}).\\n`,\n );\n }\n }\n\n // --- 5. Summary -----------------------------------------------------------\n\n const frontendLink = `${trimSlash(issuer)}/project/${link.projectId}/traces`;\n\n const result: SetupResult = {\n projectId: link.projectId,\n projectName: link.projectName ?? null,\n workspaceId: link.workspaceId ?? null,\n workspaceName: link.workspaceName ?? null,\n apiKey,\n envFileUpdated: envPath,\n skillsInstalled,\n frontendUrl: frontendLink,\n userEmail: creds.userEmail ?? null,\n };\n\n if (isJson) {\n process.stdout.write(JSON.stringify(result) + \"\\n\");\n } else {\n const docsUrl = \"https://laminar.sh/docs/tracing/integrations/overview\";\n const verifyCmd =\n 'lmnr-cli sql query \"SELECT * FROM traces ORDER BY start_time DESC LIMIT 1\" --json';\n process.stdout.write(\n \"\\nNext steps:\\n\" +\n \" 1. Instrument your project with Laminar using the installed skill or the docs:\\n\" +\n ` ${pcOut.cyan(docsUrl)}\\n` +\n \" 2. Run your project.\\n\" +\n \" 3. Verify instrumentation:\\n\" +\n ` ${pcOut.green(verifyCmd)}\\n` +\n \" 4. View your traces in the browser:\\n\" +\n ` ${pcOut.cyan(frontendLink)}\\n`,\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Project resolution helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a project via the CLI (logged-in, no link). 0 projects routes to the\n * browser create flow (gap A): we re-run the device flow, which lands on the\n * /device picker → first-project create UI, and the new project's id rides back\n * on the device-token metadata. >1 prompts a CLI choice; ==1 auto-selects.\n */\nasync function resolveProjectViaCli(\n creds: Credentials,\n userBaseUrl: string,\n issuer: string,\n isJson: boolean,\n options: SetupOptions,\n): Promise<ProjectLink> {\n let projects: CliProject[];\n try {\n projects = await listProjects(creds, userBaseUrl);\n } catch (err) {\n emitError(isJson, \"list_projects_failed\", describeError(err));\n process.exit(EXIT_LIST_PROJECTS_FAILED);\n }\n\n if (projects.length === 0) {\n // Gap A: no project to select and the CLI can't create one. Drive the\n // browser create flow — same path the not-logged-in 0-project user takes —\n // so project creation lives in ONE place (the /device picker).\n if (isJson) {\n emitError(\n isJson,\n \"no_projects\",\n `No projects found. Run \\`lmnr-cli setup\\` interactively (it opens the browser ` +\n `to create your first project) or create one at ${trimSlash(issuer)}/onboarding.`,\n );\n process.exit(EXIT_NO_PROJECT);\n }\n process.stderr.write(\n \"\\nYou have no projects yet. Opening the browser to create your first one...\\n\",\n );\n let login;\n try {\n login = await handleLogin({\n frontendUrl: issuer,\n noBrowser: options.noBrowser,\n });\n } catch (err) {\n emitError(isJson, \"login_failed\", describeError(err));\n process.exit(EXIT_LOGIN_FAILED);\n }\n if (!login.projectId) {\n emitError(\n isJson,\n \"no_projects\",\n `No project was created. Create one at ${trimSlash(issuer)}/onboarding then re-run setup.`,\n );\n process.exit(EXIT_NO_PROJECT);\n }\n return writeLink(issuer, userBaseUrl, login.projectId, isJson);\n }\n\n let chosen: CliProject;\n if (options.projectId) {\n // Explicit --project-id disambiguates. Validate against the accessible set.\n const match = projects.find((p) => p.id === options.projectId);\n if (!match) {\n emitError(\n isJson,\n \"no_access\",\n `You don't have access to project ${options.projectId}. Accessible: ` +\n projects.map((p) => `${p.id} (${p.workspaceName}/${p.name})`).join(\", \"),\n );\n process.exit(EXIT_NO_ACCESS);\n }\n chosen = match;\n } else if (projects.length === 1) {\n chosen = projects[0];\n } else {\n if (isJson) {\n emitError(\n isJson,\n \"project_ambiguous\",\n `Multiple projects: pass --project-id <id>, or run setup interactively. ` +\n projects.map((p) => `${p.id} (${p.workspaceName}/${p.name})`).join(\", \"),\n );\n process.exit(EXIT_NO_PROJECT);\n }\n chosen = await promptProjectChoice(projects);\n }\n\n const linkPath = await writeProjectLink({\n projectId: chosen.id,\n projectName: chosen.name,\n workspaceId: chosen.workspaceId,\n workspaceName: chosen.workspaceName,\n });\n if (!isJson) process.stderr.write(`${pc.green(\"✓\")} Linked ${linkPath}\\n`);\n return {\n projectId: chosen.id,\n projectName: chosen.name,\n workspaceId: chosen.workspaceId,\n workspaceName: chosen.workspaceName,\n };\n}\n\n/** Write `.lmnr/project.json`, enriching display details from listProjects when possible. */\nasync function writeLink(\n issuer: string,\n userBaseUrl: string,\n projectId: string,\n isJson: boolean,\n): Promise<ProjectLink> {\n let link: ProjectLink = { projectId };\n try {\n const creds = await safeReadCredentials();\n if (creds) {\n const projects = await listProjects(creds, userBaseUrl);\n const match = projects.find((p) => p.id === projectId);\n if (match) {\n link = {\n projectId,\n projectName: match.name,\n workspaceId: match.workspaceId,\n workspaceName: match.workspaceName,\n };\n }\n }\n } catch {\n // Best-effort enrichment — the id is enough to proceed.\n }\n try {\n const linkPath = await writeProjectLink(link);\n if (!isJson) process.stderr.write(`${pc.green(\"✓\")} Linked ${linkPath}\\n`);\n } catch (err) {\n if (!isJson) {\n process.stderr.write(\n `${pc.yellow(\"Warning\")}: could not write .lmnr/project.json (${describeError(err)}). ` +\n `CLI commands will need --project-id ${projectId}.\\n`,\n );\n }\n }\n return link;\n}\n\n/**\n * Access check: the user must be a member of `projectId`. Calls\n * GET /v1/cli/projects (user JWT) and asserts the id is present; aborts\n * otherwise (SPEC: \"You don't have access to the project in this directory\").\n */\nasync function assertAccess(\n creds: Credentials,\n userBaseUrl: string,\n projectId: string,\n isJson: boolean,\n): Promise<void> {\n let projects: CliProject[];\n try {\n projects = await listProjects(creds, userBaseUrl);\n } catch (err) {\n // Discovery FAILED (network/5xx) — we couldn't determine access. Report it\n // as a transient list failure (exit 10), NOT no_access (exit 4): automation\n // must be able to retry instead of concluding the user lacks access.\n emitError(isJson, \"list_projects_failed\", describeError(err));\n process.exit(EXIT_LIST_PROJECTS_FAILED);\n }\n if (!projects.some((p) => p.id === projectId)) {\n emitError(\n isJson,\n \"no_access\",\n \"You don't have access to the project in this directory\",\n );\n process.exit(EXIT_NO_ACCESS);\n }\n}\n\n/** List the projects the user can access (user-JWT-authed discovery). */\nasync function listProjects(creds: Credentials, baseUrl: string): Promise<CliProject[]> {\n const updated = await refreshIfNeeded(creds);\n // Discovery client: CliResource hits /v1/cli/projects with the bare bearer,\n // no project id needed (it overrides BaseResource's headers/prefix).\n const client = new LaminarClient({\n baseUrl,\n // setup has no --port flag, so honor LMNR_HTTP_PORT for local self-host\n // (baseUrl carries no port by convention). Cloud falls back to 443.\n port: envHttpPort(),\n auth: { type: \"userToken\", token: updated.accessToken, projectId: \"\" },\n });\n return client.cli.listProjects();\n}\n\nasync function safeReadCredentials(): Promise<Credentials | null> {\n try {\n return await readCredentials();\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Key minting\n// ---------------------------------------------------------------------------\n\n/** POST /api/cli/api-key with the session bearer for an explicit project. */\nasync function mintSetupKey(\n issuer: string,\n sessionToken: string,\n projectId: string,\n): Promise<SetupKeyResponse> {\n const url = `${trimSlash(issuer)}/api/cli/api-key`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { authorization: `Bearer ${sessionToken}`, \"content-type\": \"application/json\" },\n body: JSON.stringify({ deviceName: hostname(), projectId }),\n });\n if (res.ok) {\n return (await res.json()) as SetupKeyResponse;\n }\n const body = (await res.json().catch(() => ({}))) as { error?: string };\n throw new Error(body.error ?? `api-key request failed (${res.status})`);\n}\n\nasync function promptProjectChoice(projects: CliProject[]): Promise<CliProject> {\n process.stderr.write(\"\\nMultiple projects available. Choose one:\\n\");\n projects.forEach((p, i) => {\n process.stderr.write(` ${i + 1}) ${p.workspaceName} / ${p.name}\\n`);\n });\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n try {\n while (true) {\n const answer = (await rl.question(`Select [1-${projects.length}]: `)).trim();\n const idx = Number.parseInt(answer, 10);\n if (Number.isInteger(idx) && idx >= 1 && idx <= projects.length) {\n return projects[idx - 1];\n }\n process.stderr.write(`${pc.red(\"Invalid selection.\")}\\n`);\n }\n } finally {\n rl.close();\n }\n}\n\nfunction pick(...candidates: (string | undefined)[]): string {\n for (const c of candidates) {\n if (c && c.length > 0) return c;\n }\n return \"\";\n}\n\nfunction trimSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nfunction describeError(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\nfunction emitError(json: boolean, code: string, detail: string): void {\n if (json) {\n process.stdout.write(JSON.stringify({ error: code, detail }) + \"\\n\");\n } else {\n process.stderr.write(`\\n${pc.red(`ERROR (${code})`)}: ${detail}\\n`);\n }\n}\n","import { LaminarClient } from \"@lmnr-ai/client\";\n\nimport type { GlobalOpts } from \"../../auth/with-client\";\nimport { outputJson } from \"../../utils/output\";\nimport { renderTable } from \"../../utils/table\";\n\n/**\n * Run a SQL query against the project's data and print the rows. Pure handler:\n * the command wrapper (`withProjectClient`) resolves the client and owns the\n * error envelope (`--json` → structured error + exit, otherwise log + exit).\n */\nexport const handleSqlQuery = async (\n client: LaminarClient,\n query: string,\n opts: GlobalOpts,\n): Promise<void> => {\n const rows = await client.sql.query(query);\n\n if (opts.json) {\n outputJson(rows);\n return;\n }\n\n if (rows.length === 0) {\n console.log(\"No rows returned.\");\n return;\n }\n\n const columns = Object.keys(rows[0]);\n const tableRows = rows.map((row) =>\n columns.map((col) => String(row[col] ?? \"\")),\n );\n\n console.log(renderTable(columns, tableRows));\n console.log(`\\n${rows.length} row(s)\\n`);\n};\n","export const SQL_SCHEMA_HELP = `\nAvailable tables:\n spans\n span_id (UUID), name (String), span_type (String: DEFAULT|LLM|TOOL),\n start_time (DateTime64), end_time (DateTime64), duration (Float64),\n input_cost (Float64), output_cost (Float64), total_cost (Float64),\n input_tokens (Int64), output_tokens (Int64), total_tokens (Int64),\n request_model (String), response_model (String), model (String),\n trace_id (UUID), provider (String), path (String),\n input (String), output (String), status (String),\n parent_span_id (UUID), attributes (String), tags (Array(String))\n\n traces\n id (UUID), start_time (DateTime64), end_time (DateTime64),\n input_tokens (Int64), output_tokens (Int64), total_tokens (Int64),\n input_cost (Float64), output_cost (Float64), total_cost (Float64),\n duration (Float64), metadata (String), session_id (String),\n user_id (String), status (String), top_span_id (UUID),\n top_span_name (String), top_span_type (String), trace_type (String),\n tags (Array(String)), has_browser_session (Bool)\n\n events\n id (UUID), type (String), name (String), span_id (UUID),\n timestamp (DateTime64), attributes (String)\n\n signal_events\n id (UUID), signal_id (UUID), trace_id (UUID), run_id (UUID),\n name (String), payload (String), timestamp (DateTime64)\n\n signal_runs\n signal_id (UUID), job_id (UUID), trigger_id (UUID), run_id (UUID),\n trace_id (UUID), status (String), event_id (UUID), updated_at (DateTime64)\n\n evaluation_datapoints\n id (UUID), evaluation_id (UUID), data (String), target (String),\n metadata (String), executor_output (String), index (UInt64),\n trace_id (UUID), group_id (String), scores (String),\n created_at (DateTime64), dataset_id (UUID),\n dataset_datapoint_id (UUID), dataset_datapoint_created_at (DateTime64)\n\n dataset_datapoints\n id (UUID), created_at (DateTime64), dataset_id (UUID),\n data (String), target (String), metadata (String)\n`;\n","import { LaminarClient } from \"@lmnr-ai/client\";\n\nimport type { GlobalOpts } from \"../../auth/with-client\";\nimport { initializeLogger } from \"../../utils/logger\";\nimport { outputJson } from \"../../utils/output\";\nimport {\n normalizeTraceId,\n NOTE_METADATA_KEY,\n readNoteFromMetadata,\n} from \"../../utils/trace-note\";\n\nconst logger = initializeLogger();\n\n// Separator between appended note entries. The note is rendered as markdown,\n// so a blank line keeps each appended entry its own paragraph.\nconst NOTE_SEPARATOR = \"\\n\\n\";\n\n/**\n * Append a free-text note to an existing trace. Stored under the\n * `rollout.note` trace-metadata key via the post-factum metadata patch\n * endpoint. The patch endpoint is last-write-wins per key, so the current\n * note is read back first (via the SQL endpoint) and the new text is pushed\n * as `existing + \"\\n\\n\" + note`. The note may contain markdown /\n * span-reference links.\n *\n * Pure handler: the command wrapper (`withProjectClient`) resolves a user-token\n * {@link LaminarClient} (routes to `/v1/cli/*` with the resolved project) and\n * owns the error envelope (`--json` → structured error + exit, else log + exit).\n *\n * The read-modify-write is not transactional: the patch lands via the async\n * ingestion queue, so a second append issued within ~a second of the first\n * can read the pre-patch note and drop the first append. Fine for the\n * intended cadence (one note per investigation step), not for concurrent\n * writers.\n *\n * TODO: revisit — make the append atomic server-side (e.g. an append mode on\n * the metadata patch endpoint that concatenates within the Postgres UPDATE,\n * which already serializes on the trace row lock).\n */\nexport const handleTraceAppendNote = async (\n client: LaminarClient,\n traceId: string,\n note: string,\n opts: GlobalOpts,\n): Promise<void> => {\n const id = normalizeTraceId(traceId);\n\n const rows = await client.sql.query(\n \"SELECT metadata FROM traces WHERE id = {trace_id:UUID} LIMIT 1\",\n { trace_id: id },\n );\n if (rows.length === 0) {\n throw new Error(\n `Trace ${id} not found. If the run just finished, the trace may not ` +\n \"be flushed yet. Retry in a few seconds.\",\n );\n }\n\n const existing = readNoteFromMetadata(rows[0].metadata);\n const updated = existing ? `${existing}${NOTE_SEPARATOR}${note}` : note;\n // failOnNotFound: the SQL pre-read can race a trace deletion, and a CLI\n // exit 0 must mean the note actually landed.\n await client.traces.pushMetadata(\n id,\n { [NOTE_METADATA_KEY]: updated },\n { failOnNotFound: true },\n );\n\n if (opts.json) {\n outputJson({ traceId: id, note: updated });\n return;\n }\n\n logger.info(`Appended note to trace ${id}.`);\n};\n","#!/usr/bin/env node\n\nimport { errorMessage } from \"@lmnr-ai/types\";\nimport { Command } from \"commander\";\n\nimport { version } from \"../package.json\";\nimport { withProjectClient, withUserToken } from \"./auth/with-client\";\nimport {\n handleDatasetsCreate,\n handleDatasetsList,\n handleDatasetsPull,\n handleDatasetsPush,\n} from \"./commands/dataset\";\nimport { handleDebugSessionSetName, handleDebugSessionSummary } from \"./commands/debug\";\nimport { handleLogin } from \"./commands/login\";\nimport { handleLogout } from \"./commands/logout\";\nimport { handleProjectsList } from \"./commands/project\";\nimport { handleSetup } from \"./commands/setup\";\nimport { handleSqlQuery } from \"./commands/sql\";\nimport { SQL_SCHEMA_HELP } from \"./commands/sql/schema\";\nimport { handleTraceAppendNote } from \"./commands/trace\";\nimport { pc } from \"./utils/colors\";\nimport { loadLocalEnv } from \"./utils/env-file\";\n\nasync function main() {\n // Hydrate LMNR_* config from a project .env(.local) before anything reads it\n // (login/setup/resolve read process.env at command-execution time, which is\n // after this). Runners like Claude Code don't inject .env into the subprocess\n // env, so this is how a local self-host config gets picked up.\n await loadLocalEnv(process.cwd());\n\n const program = new Command();\n\n program\n .name(\"lmnr-cli\")\n .description(\"CLI for the Laminar agent observability platform\")\n .version(version, \"-v, --version\", \"display version number\");\n\n const datasetsCmd = program\n .command(\"dataset\")\n .description(\"Manage datasets\")\n .option(\n \"--project-id <id>\",\n \"Target project id. Defaults to the linked .lmnr/project.json. \" +\n \"Run `lmnr-cli login` first.\",\n )\n .option(\n \"--base-url <url>\",\n \"Base URL for the Laminar API. Defaults to https://api.lmnr.ai or LMNR_BASE_URL env variable\",\n )\n .option(\n \"--port <port>\",\n \"Port for the Laminar API. Defaults to 443\",\n (val) => parseInt(val, 10),\n )\n .option(\"--json\", \"Output structured JSON to stdout\");\n\n // Datasets list command\n datasetsCmd\n .command(\"list\")\n .description(\"List all datasets\")\n .action(withProjectClient(handleDatasetsList));\n\n // Datasets push command\n datasetsCmd\n .command(\"push\")\n .description(\"Push datapoints to an existing dataset\")\n .argument(\n \"<paths...>\",\n \"Paths to files or directories containing data to push\",\n )\n .option(\n \"-n, --name <name>\",\n \"Name of the dataset (either name or id must be provided)\",\n )\n .option(\n \"--id <id>\",\n \"ID of the dataset (either name or id must be provided)\",\n )\n .option(\"-r, --recursive\", \"Recursively read files in directories\", false)\n .option(\n \"--batch-size <size>\",\n \"Batch size for pushing data\",\n (val) => parseInt(val, 10),\n 100,\n )\n .action(withProjectClient(handleDatasetsPush));\n\n // Datasets pull command\n datasetsCmd\n .command(\"pull\")\n .description(\"Pull data from a dataset\")\n .argument(\n \"[output-path]\",\n \"Path to save the data. If not provided, prints to console\",\n )\n .option(\n \"-n, --name <name>\",\n \"Name of the dataset (either name or id must be provided)\",\n )\n .option(\n \"--id <id>\",\n \"ID of the dataset (either name or id must be provided)\",\n )\n .option(\n \"--output-format <format>\",\n \"Output format (json, csv, jsonl). Inferred from file extension if not provided\",\n )\n .option(\n \"--batch-size <size>\",\n \"Batch size for pulling data\",\n (val) => parseInt(val, 10),\n 100,\n )\n .option(\"--limit <limit>\", \"Limit number of datapoints to pull\", (val) =>\n parseInt(val, 10),\n )\n .option(\n \"--offset <offset>\",\n \"Offset for pagination\",\n (val) => parseInt(val, 10),\n 0,\n )\n .action(withProjectClient(handleDatasetsPull));\n\n // Datasets create command\n datasetsCmd\n .command(\"create\")\n .description(\"Create a dataset from input files\")\n .argument(\"<name>\", \"Name of the dataset to create\")\n .argument(\n \"<paths...>\",\n \"Paths to files or directories containing data to push\",\n )\n .requiredOption(\"-o, --output-file <file>\", \"Path to save the pulled data\")\n .option(\n \"--output-format <format>\",\n \"Output format (json, csv, jsonl). Inferred from file extension if not provided\",\n )\n .option(\"-r, --recursive\", \"Recursively read files in directories\", false)\n .option(\n \"--batch-size <size>\",\n \"Batch size for pushing/pulling data\",\n (val) => parseInt(val, 10),\n 100,\n )\n .action(withProjectClient(handleDatasetsCreate));\n\n const sqlCmd = program\n .command(\"sql\")\n .description(\"Run SQL queries against your Laminar project data\")\n .option(\n \"--project-id <id>\",\n \"Target project id. Defaults to the linked .lmnr/project.json. \" +\n \"Run `lmnr-cli login` first.\",\n )\n .option(\n \"--base-url <url>\",\n \"Base URL for the Laminar API. Defaults to https://api.lmnr.ai or LMNR_BASE_URL env variable\",\n )\n .option(\n \"--port <port>\",\n \"Port for the Laminar API. Defaults to 443\",\n (val) => parseInt(val, 10),\n )\n .option(\"--json\", \"Output structured JSON to stdout\");\n\n sqlCmd\n .command(\"query\")\n .description(\"Execute a SQL query\")\n .argument(\"<query>\", \"SQL query string\")\n .action(withProjectClient(handleSqlQuery))\n .addHelpText(\n \"after\",\n SQL_SCHEMA_HELP +\n `\nExamples:\n $ lmnr-cli sql query \"SELECT * FROM spans LIMIT 10\"\n $ lmnr-cli sql query \"SELECT id, total_cost, status FROM traces LIMIT 20\"\n $ lmnr-cli sql query \"SELECT * FROM spans LIMIT 10\" --json\n`,\n );\n\n sqlCmd\n .command(\"schema\")\n .description(\"Show available tables and their columns\")\n .action(() => {\n process.stdout.write(SQL_SCHEMA_HELP);\n });\n\n const projectCmd = program.command(\"project\").description(\"Work with Laminar projects\");\n\n projectCmd\n .command(\"list\")\n .description(\"List the projects you can access (● = linked to this directory)\")\n .option(\n \"--base-url <url>\",\n \"Base URL for the Laminar API. Defaults to the logged-in session or LMNR_BASE_URL\",\n )\n .option(\n \"--port <port>\",\n \"Port for the Laminar API. Defaults to 443\",\n (val) => parseInt(val, 10),\n )\n .option(\"--json\", \"Output structured JSON to stdout\")\n .action(withUserToken(handleProjectsList));\n\n program\n .command(\"login\")\n .description(\"Authenticate the CLI via OAuth Device Flow\")\n .option(\n \"--frontend-url <url>\",\n \"Frontend URL (issuer). Defaults to https://www.laminar.sh or LMNR_FRONTEND_URL env variable\",\n )\n .option(\"--no-browser\", \"Do not open the verification URL in a browser\")\n .action(async (options) => {\n const result = await handleLogin(options);\n process.stderr.write(`${pc.green(\"✓\")} Logged in as ${result.userEmail ?? \"<unknown>\"}.\\n`);\n process.stderr.write(\n pc.dim(\"Client: lmnr-cli. Tokens stored at ~/.config/lmnr/credentials.json (mode 0600).\\n\"),\n );\n process.stderr.write(\n pc.dim(\"Run `lmnr-cli setup` in a project directory to link it and write its API key.\\n\"),\n );\n });\n\n program\n .command(\"logout\")\n .description(\"Log out and remove the stored credentials\")\n .action(async () => {\n await handleLogout();\n });\n\n program\n .command(\"setup\")\n .description(\n \"One-shot onboarding: login, select a project, write its key to .env, \" +\n \"link .lmnr, and install the Laminar agent skill\",\n )\n .option(\"--write-env\", \"Write LMNR_PROJECT_API_KEY to ./.env (default)\", true)\n .option(\"--no-write-env\", \"Do not write to ./.env\")\n .option(\n \"--project-id <id>\",\n \"Project to link when you can access more than one (disambiguates the \" +\n \"project_ambiguous case in --json mode)\",\n )\n .option(\"--json\", \"Emit a machine-readable JSON line on stdout\")\n .option(\"--no-browser\", \"Do not auto-open the device-flow URL\")\n .option(\n \"--frontend-url <url>\",\n \"Frontend URL (issuer). Defaults to LMNR_FRONTEND_URL or https://www.laminar.sh\",\n )\n .option(\n \"--base-url <url>\",\n \"Base URL for the Laminar API. Defaults to LMNR_BASE_URL or https://api.lmnr.ai\",\n )\n .action(async (options) => {\n await handleSetup(options);\n });\n\n const traceCmd = program\n .command(\"trace\")\n .description(\"Inspect and operate on traces\")\n .option(\n \"--project-id <id>\",\n \"Target project id. Defaults to the linked .lmnr/project.json. \" +\n \"Run `lmnr-cli login` first.\",\n )\n .option(\n \"--base-url <url>\",\n \"Base URL for the Laminar API. Defaults to https://api.lmnr.ai or LMNR_BASE_URL env variable\",\n )\n .option(\n \"--port <port>\",\n \"Port for the Laminar API. Defaults to 443\",\n (val) => parseInt(val, 10),\n )\n .option(\"--json\", \"Output structured JSON to stdout\");\n\n traceCmd\n .command(\"append-note\")\n .description(\"Append a free-text note to a trace (stored in trace metadata)\")\n .argument(\"<trace-id>\", \"Trace ID (UUID or 32-char OTel hex trace id)\")\n .argument(\"<note>\", \"Note text (may contain markdown)\")\n .action(withProjectClient(handleTraceAppendNote))\n .addHelpText(\n \"after\",\n `\nNotes accumulate: each call appends a new paragraph to the trace's existing\nnote rather than overwriting it.\n\nExamples:\n $ lmnr-cli trace append-note <trace-id> \"Reproduced the timeout on the search tool.\"\n`,\n );\n\n const debugCmd = program\n .command(\"debug\")\n .description(\"Operate on debug sessions\")\n .option(\n \"--project-id <id>\",\n \"Target project id. Defaults to the linked .lmnr/project.json. \" +\n \"Run `lmnr-cli login` first.\",\n )\n .option(\n \"--base-url <url>\",\n \"Base URL for the Laminar API. Defaults to https://api.lmnr.ai or LMNR_BASE_URL env variable\",\n )\n .option(\n \"--port <port>\",\n \"Port for the Laminar API. Defaults to 443\",\n (val) => parseInt(val, 10),\n )\n .option(\"--json\", \"Output structured JSON to stdout\")\n .addHelpText(\n \"after\",\n `\nLearn more about debugging features at https://laminar.sh/docs/platform/debugger\n`,\n );\n\n const debugSessionCmd = debugCmd\n .command(\"session\")\n .description(\"Manage debug sessions\")\n .addHelpText(\n \"after\",\n `\nLearn more about debugging features at https://laminar.sh/docs/platform/debugger\n`,\n );\n\n debugSessionCmd\n .command(\"set-name\")\n .description(\"Set the display name of a debug session\")\n .argument(\"<session-id>\", \"Debug session ID\")\n .argument(\"<name>\", \"Session display name\")\n .action(withProjectClient(handleDebugSessionSetName))\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lmnr-cli debug session set-name <session-id> \"Fix report length + search tool\"\n`,\n );\n\n debugSessionCmd\n .command(\"summary\")\n .description(\"Print every trace in a debug session with its note, oldest first\")\n .argument(\"<session-id>\", \"Debug session ID\")\n .action(withProjectClient(handleDebugSessionSummary))\n .addHelpText(\n \"after\",\n `\nOutput is one block per trace (oldest first), the trace's note followed by a\nself-closing tag carrying the trace id and end time:\n\n {note}\n <trace id=\"{trace-id}\" end-time=\"{end-time}\"/>\n\nWith --json, prints an array of {\"note\", \"traceId\", \"endTime\"} objects.\n\nExamples:\n $ lmnr-cli debug session summary <session-id>\n $ lmnr-cli debug session summary <session-id> --json\n`,\n );\n\n program.addHelpText(\n \"after\",\n `\nAuthentication:\n Run \\`lmnr-cli setup\\` to login, link this directory, write a project API key to\n ./.env, and install the Laminar skill \n \\`lmnr-cli login\\` authenticates as a user. Every project command\n (sql / dataset / project / trace / debug) runs on that user session and\n targets a project via --project-id or the linked .lmnr/project.json.\n\nExamples:\n lmnr-cli setup # Logs in and prepares directory\n lmnr-cli login # Authenticate (user)\n lmnr-cli project list # Projects you can access\n lmnr-cli logout # Log out\n lmnr-cli dataset list --json # List all datasets\n lmnr-cli dataset push data.jsonl -n my-dataset --json # Push data to a dataset\n lmnr-cli dataset pull output.jsonl -n my-dataset --json # Pull data from a dataset\n lmnr-cli sql query \"SELECT * FROM spans LIMIT 10\" --json # Query spans\n lmnr-cli sql schema # Show available tables\n lmnr-cli trace append-note <trace-id> \"note text\" # Append a note to a trace\n lmnr-cli debug session set-name <session-id> \"title\" # Rename a debug session\n lmnr-cli debug session summary <session-id> # Notes for each trace in a session\n\nFor more information about the Laminar platfrom:\n Documentation: https://laminar.sh/docs\n`,\n );\n\n await program.parseAsync();\n}\n\nmain().catch((err) => {\n console.error(errorMessage(err));\n process.exit(1);\n});\n"],"x_google_ignoreList":[2,3,4,5],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["fs","path","crypto","initializeLogger","logger$4","path","logger$3","DEFAULT_DATASET_PUSH_BATCH_SIZE","logger$2","logger$1","logger","DEFAULT_FRONTEND_URL","DEFAULT_BASE_URL","trimSlash","logger","logger","fs","readFile","Table","logger","logger","pick","DEFAULT_FRONTEND_URL","trimSlash","trimSlash","DEFAULT_BASE_URL","execFile","describeError","version","Command","version"],"sources":["../../types/dist/index.mjs","../package.json","../../../node_modules/.pnpm/dotenv@17.4.2/node_modules/dotenv/lib/main.js","../../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/stringify.js","../../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/rng.js","../../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/v4.js","../../client/dist/index.mjs","../src/utils/logger.ts","../src/utils/output.ts","../src/constants.ts","../src/utils/project-link.ts","../src/auth/credentials.ts","../src/auth/device.ts","../src/auth/resolve.ts","../src/auth/client.ts","../src/auth/with-client.ts","../src/utils/file.ts","../src/utils/table.ts","../src/commands/dataset/index.ts","../src/utils/trace-note.ts","../src/commands/debug/index.ts","../src/utils/colors.ts","../src/commands/login/index.ts","../src/commands/logout/index.ts","../src/commands/project/index.ts","../src/auth/project-id.ts","../src/utils/env-file.ts","../src/skill/laminar-skill.ts","../src/skill/fetch-skill.ts","../src/utils/install-skill.ts","../src/commands/setup/index.ts","../src/commands/sql/index.ts","../src/commands/sql/schema.ts","../src/commands/trace/index.ts","../src/index.ts"],"sourcesContent":["//#region src/tracing.ts\n/**\n* Tracing levels to conditionally disable tracing.\n*\n* OFF - No tracing is sent.\n* META_ONLY - Only metadata is sent (e.g. tokens, costs, etc.).\n* ALL - All data is sent.\n*/\nlet TracingLevel = /* @__PURE__ */ function(TracingLevel) {\n\tTracingLevel[\"OFF\"] = \"off\";\n\tTracingLevel[\"META_ONLY\"] = \"meta_only\";\n\tTracingLevel[\"ALL\"] = \"all\";\n\treturn TracingLevel;\n}({});\n//#endregion\n//#region src/utils.ts\nconst errorMessage = (error) => error instanceof Error ? error.message : String(error);\n//#endregion\nexport { TracingLevel, errorMessage };\n\n//# sourceMappingURL=index.mjs.map","","const fs = require('fs')\nconst path = require('path')\nconst os = require('os')\nconst crypto = require('crypto')\n\n// Array of tips to display randomly\nconst TIPS = [\n '◈ encrypted .env [www.dotenvx.com]',\n '◈ secrets for agents [www.dotenvx.com]',\n '⌁ auth for agents [www.vestauth.com]',\n '⌘ custom filepath { path: \\'/custom/path/.env\\' }',\n '⌘ enable debugging { debug: true }',\n '⌘ override existing { override: true }',\n '⌘ suppress logs { quiet: true }',\n '⌘ multiple files { path: [\\'.env.local\\', \\'.env\\'] }'\n]\n\n// Get a random tip from the tips array\nfunction _getRandomTip () {\n return TIPS[Math.floor(Math.random() * TIPS.length)]\n}\n\nfunction parseBoolean (value) {\n if (typeof value === 'string') {\n return !['false', '0', 'no', 'off', ''].includes(value.toLowerCase())\n }\n return Boolean(value)\n}\n\nfunction supportsAnsi () {\n return process.stdout.isTTY // && process.env.TERM !== 'dumb'\n}\n\nfunction dim (text) {\n return supportsAnsi() ? `\\x1b[2m${text}\\x1b[0m` : text\n}\n\nconst LINE = /(?:^|^)\\s*(?:export\\s+)?([\\w.-]+)(?:\\s*=\\s*?|:\\s+?)(\\s*'(?:\\\\'|[^'])*'|\\s*\"(?:\\\\\"|[^\"])*\"|\\s*`(?:\\\\`|[^`])*`|[^#\\r\\n]+)?\\s*(?:#.*)?(?:$|$)/mg\n\n// Parse src into an Object\nfunction parse (src) {\n const obj = {}\n\n // Convert buffer to string\n let lines = src.toString()\n\n // Convert line breaks to same format\n lines = lines.replace(/\\r\\n?/mg, '\\n')\n\n let match\n while ((match = LINE.exec(lines)) != null) {\n const key = match[1]\n\n // Default undefined or null to empty string\n let value = (match[2] || '')\n\n // Remove whitespace\n value = value.trim()\n\n // Check if double quoted\n const maybeQuote = value[0]\n\n // Remove surrounding quotes\n value = value.replace(/^(['\"`])([\\s\\S]*)\\1$/mg, '$2')\n\n // Expand newlines if double quoted\n if (maybeQuote === '\"') {\n value = value.replace(/\\\\n/g, '\\n')\n value = value.replace(/\\\\r/g, '\\r')\n }\n\n // Add to object\n obj[key] = value\n }\n\n return obj\n}\n\nfunction _parseVault (options) {\n options = options || {}\n\n const vaultPath = _vaultPath(options)\n options.path = vaultPath // parse .env.vault\n const result = DotenvModule.configDotenv(options)\n if (!result.parsed) {\n const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`)\n err.code = 'MISSING_DATA'\n throw err\n }\n\n // handle scenario for comma separated keys - for use with key rotation\n // example: DOTENV_KEY=\"dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=prod,dotenv://:key_7890@dotenvx.com/vault/.env.vault?environment=prod\"\n const keys = _dotenvKey(options).split(',')\n const length = keys.length\n\n let decrypted\n for (let i = 0; i < length; i++) {\n try {\n // Get full key\n const key = keys[i].trim()\n\n // Get instructions for decrypt\n const attrs = _instructions(result, key)\n\n // Decrypt\n decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key)\n\n break\n } catch (error) {\n // last key\n if (i + 1 >= length) {\n throw error\n }\n // try next key\n }\n }\n\n // Parse decrypted .env string\n return DotenvModule.parse(decrypted)\n}\n\nfunction _warn (message) {\n console.error(`⚠ ${message}`)\n}\n\nfunction _debug (message) {\n console.log(`┆ ${message}`)\n}\n\nfunction _log (message) {\n console.log(`◇ ${message}`)\n}\n\nfunction _dotenvKey (options) {\n // prioritize developer directly setting options.DOTENV_KEY\n if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {\n return options.DOTENV_KEY\n }\n\n // secondary infra already contains a DOTENV_KEY environment variable\n if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {\n return process.env.DOTENV_KEY\n }\n\n // fallback to empty string\n return ''\n}\n\nfunction _instructions (result, dotenvKey) {\n // Parse DOTENV_KEY. Format is a URI\n let uri\n try {\n uri = new URL(dotenvKey)\n } catch (error) {\n if (error.code === 'ERR_INVALID_URL') {\n const err = new Error('INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development')\n err.code = 'INVALID_DOTENV_KEY'\n throw err\n }\n\n throw error\n }\n\n // Get decrypt key\n const key = uri.password\n if (!key) {\n const err = new Error('INVALID_DOTENV_KEY: Missing key part')\n err.code = 'INVALID_DOTENV_KEY'\n throw err\n }\n\n // Get environment\n const environment = uri.searchParams.get('environment')\n if (!environment) {\n const err = new Error('INVALID_DOTENV_KEY: Missing environment part')\n err.code = 'INVALID_DOTENV_KEY'\n throw err\n }\n\n // Get ciphertext payload\n const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`\n const ciphertext = result.parsed[environmentKey] // DOTENV_VAULT_PRODUCTION\n if (!ciphertext) {\n const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`)\n err.code = 'NOT_FOUND_DOTENV_ENVIRONMENT'\n throw err\n }\n\n return { ciphertext, key }\n}\n\nfunction _vaultPath (options) {\n let possibleVaultPath = null\n\n if (options && options.path && options.path.length > 0) {\n if (Array.isArray(options.path)) {\n for (const filepath of options.path) {\n if (fs.existsSync(filepath)) {\n possibleVaultPath = filepath.endsWith('.vault') ? filepath : `${filepath}.vault`\n }\n }\n } else {\n possibleVaultPath = options.path.endsWith('.vault') ? options.path : `${options.path}.vault`\n }\n } else {\n possibleVaultPath = path.resolve(process.cwd(), '.env.vault')\n }\n\n if (fs.existsSync(possibleVaultPath)) {\n return possibleVaultPath\n }\n\n return null\n}\n\nfunction _resolveHome (envPath) {\n return envPath[0] === '~' ? path.join(os.homedir(), envPath.slice(1)) : envPath\n}\n\nfunction _configVault (options) {\n const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || (options && options.debug))\n const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || (options && options.quiet))\n\n if (debug || !quiet) {\n _log('loading env from encrypted .env.vault')\n }\n\n const parsed = DotenvModule._parseVault(options)\n\n let processEnv = process.env\n if (options && options.processEnv != null) {\n processEnv = options.processEnv\n }\n\n DotenvModule.populate(processEnv, parsed, options)\n\n return { parsed }\n}\n\nfunction configDotenv (options) {\n const dotenvPath = path.resolve(process.cwd(), '.env')\n let encoding = 'utf8'\n let processEnv = process.env\n if (options && options.processEnv != null) {\n processEnv = options.processEnv\n }\n let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || (options && options.debug))\n let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || (options && options.quiet))\n\n if (options && options.encoding) {\n encoding = options.encoding\n } else {\n if (debug) {\n _debug('no encoding is specified (UTF-8 is used by default)')\n }\n }\n\n let optionPaths = [dotenvPath] // default, look for .env\n if (options && options.path) {\n if (!Array.isArray(options.path)) {\n optionPaths = [_resolveHome(options.path)]\n } else {\n optionPaths = [] // reset default\n for (const filepath of options.path) {\n optionPaths.push(_resolveHome(filepath))\n }\n }\n }\n\n // Build the parsed data in a temporary object (because we need to return it). Once we have the final\n // parsed data, we will combine it with process.env (or options.processEnv if provided).\n let lastError\n const parsedAll = {}\n for (const path of optionPaths) {\n try {\n // Specifying an encoding returns a string instead of a buffer\n const parsed = DotenvModule.parse(fs.readFileSync(path, { encoding }))\n\n DotenvModule.populate(parsedAll, parsed, options)\n } catch (e) {\n if (debug) {\n _debug(`failed to load ${path} ${e.message}`)\n }\n lastError = e\n }\n }\n\n const populated = DotenvModule.populate(processEnv, parsedAll, options)\n\n // handle user settings DOTENV_CONFIG_ options inside .env file(s)\n debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug)\n quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet)\n\n if (debug || !quiet) {\n const keysCount = Object.keys(populated).length\n const shortPaths = []\n for (const filePath of optionPaths) {\n try {\n const relative = path.relative(process.cwd(), filePath)\n shortPaths.push(relative)\n } catch (e) {\n if (debug) {\n _debug(`failed to load ${filePath} ${e.message}`)\n }\n lastError = e\n }\n }\n\n _log(`injected env (${keysCount}) from ${shortPaths.join(',')} ${dim(`// tip: ${_getRandomTip()}`)}`)\n }\n\n if (lastError) {\n return { parsed: parsedAll, error: lastError }\n } else {\n return { parsed: parsedAll }\n }\n}\n\n// Populates process.env from .env file\nfunction config (options) {\n // fallback to original dotenv if DOTENV_KEY is not set\n if (_dotenvKey(options).length === 0) {\n return DotenvModule.configDotenv(options)\n }\n\n const vaultPath = _vaultPath(options)\n\n // dotenvKey exists but .env.vault file does not exist\n if (!vaultPath) {\n _warn(`you set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}`)\n\n return DotenvModule.configDotenv(options)\n }\n\n return DotenvModule._configVault(options)\n}\n\nfunction decrypt (encrypted, keyStr) {\n const key = Buffer.from(keyStr.slice(-64), 'hex')\n let ciphertext = Buffer.from(encrypted, 'base64')\n\n const nonce = ciphertext.subarray(0, 12)\n const authTag = ciphertext.subarray(-16)\n ciphertext = ciphertext.subarray(12, -16)\n\n try {\n const aesgcm = crypto.createDecipheriv('aes-256-gcm', key, nonce)\n aesgcm.setAuthTag(authTag)\n return `${aesgcm.update(ciphertext)}${aesgcm.final()}`\n } catch (error) {\n const isRange = error instanceof RangeError\n const invalidKeyLength = error.message === 'Invalid key length'\n const decryptionFailed = error.message === 'Unsupported state or unable to authenticate data'\n\n if (isRange || invalidKeyLength) {\n const err = new Error('INVALID_DOTENV_KEY: It must be 64 characters long (or more)')\n err.code = 'INVALID_DOTENV_KEY'\n throw err\n } else if (decryptionFailed) {\n const err = new Error('DECRYPTION_FAILED: Please check your DOTENV_KEY')\n err.code = 'DECRYPTION_FAILED'\n throw err\n } else {\n throw error\n }\n }\n}\n\n// Populate process.env with parsed values\nfunction populate (processEnv, parsed, options = {}) {\n const debug = Boolean(options && options.debug)\n const override = Boolean(options && options.override)\n const populated = {}\n\n if (typeof parsed !== 'object') {\n const err = new Error('OBJECT_REQUIRED: Please check the processEnv argument being passed to populate')\n err.code = 'OBJECT_REQUIRED'\n throw err\n }\n\n // Set process.env\n for (const key of Object.keys(parsed)) {\n if (Object.prototype.hasOwnProperty.call(processEnv, key)) {\n if (override === true) {\n processEnv[key] = parsed[key]\n populated[key] = parsed[key]\n }\n\n if (debug) {\n if (override === true) {\n _debug(`\"${key}\" is already defined and WAS overwritten`)\n } else {\n _debug(`\"${key}\" is already defined and was NOT overwritten`)\n }\n }\n } else {\n processEnv[key] = parsed[key]\n populated[key] = parsed[key]\n }\n }\n\n return populated\n}\n\nconst DotenvModule = {\n configDotenv,\n _configVault,\n _parseVault,\n config,\n decrypt,\n parse,\n populate\n}\n\nmodule.exports.configDotenv = DotenvModule.configDotenv\nmodule.exports._configVault = DotenvModule._configVault\nmodule.exports._parseVault = DotenvModule._parseVault\nmodule.exports.config = DotenvModule.config\nmodule.exports.decrypt = DotenvModule.decrypt\nmodule.exports.parse = DotenvModule.parse\nmodule.exports.populate = DotenvModule.populate\n\nmodule.exports = DotenvModule\n","import validate from './validate.js';\nconst byteToHex = [];\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).slice(1));\n}\nexport function unsafeStringify(arr, offset = 0) {\n return (byteToHex[arr[offset + 0]] +\n byteToHex[arr[offset + 1]] +\n byteToHex[arr[offset + 2]] +\n byteToHex[arr[offset + 3]] +\n '-' +\n byteToHex[arr[offset + 4]] +\n byteToHex[arr[offset + 5]] +\n '-' +\n byteToHex[arr[offset + 6]] +\n byteToHex[arr[offset + 7]] +\n '-' +\n byteToHex[arr[offset + 8]] +\n byteToHex[arr[offset + 9]] +\n '-' +\n byteToHex[arr[offset + 10]] +\n byteToHex[arr[offset + 11]] +\n byteToHex[arr[offset + 12]] +\n byteToHex[arr[offset + 13]] +\n byteToHex[arr[offset + 14]] +\n byteToHex[arr[offset + 15]]).toLowerCase();\n}\nfunction stringify(arr, offset = 0) {\n const uuid = unsafeStringify(arr, offset);\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n return uuid;\n}\nexport default stringify;\n","const rnds8 = new Uint8Array(16);\nexport default function rng() {\n return crypto.getRandomValues(rnds8);\n}\n","import rng from './rng.js';\nimport { unsafeStringify } from './stringify.js';\nfunction v4(options, buf, offset) {\n if (!buf && !options && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return _v4(options, buf, offset);\n}\nfunction _v4(options, buf, offset) {\n options = options || {};\n const rnds = options.random ?? options.rng?.() ?? rng();\n if (rnds.length < 16) {\n throw new Error('Random bytes length must be >= 16');\n }\n rnds[6] = (rnds[6] & 0x0f) | 0x40;\n rnds[8] = (rnds[8] & 0x3f) | 0x80;\n if (buf) {\n offset = offset || 0;\n if (offset < 0 || offset + 16 > buf.length) {\n throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);\n }\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n return buf;\n }\n return unsafeStringify(rnds);\n}\nexport default v4;\n","import { config } from \"dotenv\";\nimport * as path from \"path\";\nimport pino from \"pino\";\nimport { PinoPretty } from \"pino-pretty\";\nimport { v4 } from \"uuid\";\nimport { errorMessage } from \"@lmnr-ai/types\";\n//#region package.json\nvar version = \"0.8.29\";\n//#endregion\n//#region src/version.ts\nfunction getLangVersion() {\n\tif (typeof process !== \"undefined\" && process.versions && process.versions.node) return `node-${process.versions.node}`;\n\tif (typeof navigator !== \"undefined\" && navigator.userAgent) return `browser-${navigator.userAgent}`;\n\treturn null;\n}\n//#endregion\n//#region src/resources/index.ts\nvar BaseResource = class {\n\tconstructor(baseHttpUrl, auth) {\n\t\tthis.baseHttpUrl = baseHttpUrl;\n\t\tthis.auth = auth;\n\t\tthis.credential = auth.type === \"apiKey\" ? auth.key : auth.token;\n\t}\n\t/** API path prefix: `/v1/cli` for CLI user-token auth, `/v1` otherwise. */\n\tget apiPrefix() {\n\t\treturn this.auth.type === \"userToken\" ? \"/v1/cli\" : \"/v1\";\n\t}\n\theaders() {\n\t\treturn {\n\t\t\tAuthorization: `Bearer ${this.credential}`,\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\tAccept: \"application/json\",\n\t\t\t...this.auth.type === \"userToken\" ? { \"x-lmnr-project-id\": this.auth.projectId } : {}\n\t\t};\n\t}\n\tasync handleError(response) {\n\t\tconst errorMsg = await response.text();\n\t\tthrow new Error(`${response.status} ${errorMsg}`);\n\t}\n};\n//#endregion\n//#region src/resources/browser-events.ts\nvar BrowserEventsResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\tasync send({ sessionId, traceId, events }) {\n\t\tconst payload = {\n\t\t\tsessionId,\n\t\t\ttraceId,\n\t\t\tevents,\n\t\t\tsource: getLangVersion() ?? \"javascript\",\n\t\t\tsdkVersion: version\n\t\t};\n\t\tconst jsonString = JSON.stringify(payload);\n\t\tconst compressedStream = new Blob([jsonString], { type: \"application/json\" }).stream().pipeThrough(new CompressionStream(\"gzip\"));\n\t\tconst compressedData = await new Response(compressedStream).arrayBuffer();\n\t\tconst response = await fetch(this.baseHttpUrl + \"/v1/browser-sessions/events\", {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t...this.headers(),\n\t\t\t\t\"Content-Encoding\": \"gzip\"\n\t\t\t},\n\t\t\tbody: compressedData\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n};\n//#endregion\n//#region src/resources/cli.ts\n/**\n* User-scoped CLI endpoints that don't target a specific project. Authed by the\n* BetterAuth user JWT (the `credential`); deliberately does NOT send an\n* `x-lmnr-project-id` header (these routes are project discovery, pre-selection).\n*\n* Discovery exception: this resource always hits `/v1/cli/projects` with the\n* bare bearer and overrides `BaseResource.headers()`/`apiPrefix`, so it works\n* even when constructed with a `userToken` auth that has no real project id yet.\n*/\nvar CliResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/** Workspaces + projects the authenticated user can access. */\n\tasync listProjects() {\n\t\tconst response = await fetch(`${this.baseHttpUrl}/v1/cli/projects`, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${this.credential}`,\n\t\t\t\tAccept: \"application/json\"\n\t\t\t}\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\tconst body = await response.json();\n\t\treturn Array.isArray(body?.projects) ? body.projects : [];\n\t}\n};\n//#endregion\n//#region src/utils.ts\nfunction initializeLogger(options) {\n\tconst colorize = options?.colorize ?? true;\n\tconst level = options?.level ?? process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() ?? \"info\";\n\treturn pino({ level }, PinoPretty({\n\t\tcolorize,\n\t\tminimumLevel: level\n\t}));\n}\nconst logger$4 = initializeLogger();\nconst isStringUUID = (id) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);\nconst newUUID = () => {\n\tif (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") return crypto.randomUUID();\n\telse return v4();\n};\nconst otelSpanIdToUUID = (spanId) => {\n\tlet id = spanId.toLowerCase();\n\tif (id.startsWith(\"0x\")) id = id.slice(2);\n\tif (id.length !== 16) logger$4.warn(`Span ID ${spanId} is not 16 hex chars long. This is not a valid OpenTelemetry span ID.`);\n\tif (!/^[0-9a-f]+$/.test(id)) {\n\t\tlogger$4.error(`Span ID ${spanId} is not a valid hex string. Generating a random UUID instead.`);\n\t\treturn newUUID();\n\t}\n\treturn id.padStart(32, \"0\").replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, \"$1-$2-$3-$4-$5\");\n};\nconst otelTraceIdToUUID = (traceId) => {\n\tlet id = traceId.toLowerCase();\n\tif (id.startsWith(\"0x\")) id = id.slice(2);\n\tif (id.length !== 32) logger$4.warn(`Trace ID ${traceId} is not 32 hex chars long. This is not a valid OpenTelemetry trace ID.`);\n\tif (!/^[0-9a-f]+$/.test(id)) {\n\t\tlogger$4.error(`Trace ID ${traceId} is not a valid hex string. Generating a random UUID instead.`);\n\t\treturn newUUID();\n\t}\n\treturn id.replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, \"$1-$2-$3-$4-$5\");\n};\nconst slicePayload = (value, length) => {\n\tif (value === null || value === void 0) return value;\n\tconst str = JSON.stringify(value);\n\tif (str.length <= length) return value;\n\treturn str.slice(0, length) + \"...\";\n};\nconst loadEnv = (options) => {\n\tconst nodeEnv = process.env.NODE_ENV || \"development\";\n\tconst envDir = process.cwd();\n\tconst envFiles = [\n\t\t\".env\",\n\t\t\".env.local\",\n\t\t`.env.${nodeEnv}`,\n\t\t`.env.${nodeEnv}.local`\n\t];\n\tconst logLevel = process.env.LMNR_LOG_LEVEL ?? \"info\";\n\tconst verbose = [\"debug\", \"trace\"].includes(logLevel.trim().toLowerCase());\n\tconst quiet = options?.quiet ?? !verbose;\n\tconfig({\n\t\tpath: options?.paths ?? envFiles.map((envFile) => path.resolve(envDir, envFile)),\n\t\tquiet\n\t});\n};\n//#endregion\n//#region src/resources/datasets.ts\nconst logger$3 = initializeLogger();\nconst DEFAULT_DATASET_PULL_LIMIT = 100;\nconst DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;\nvar DatasetsResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/**\n\t* List all datasets.\n\t*\n\t* @returns {Promise<Dataset[]>} Array of datasets\n\t*/\n\tasync listDatasets() {\n\t\tconst response = await fetch(this.baseHttpUrl + this.apiPrefix + \"/datasets\", {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: this.headers()\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn response.json();\n\t}\n\t/**\n\t* Get a dataset by name.\n\t*\n\t* @param {string} name - Name of the dataset\n\t* @returns {Promise<Dataset[]>} Array of datasets with matching name\n\t*/\n\tasync getDatasetByName(name) {\n\t\tconst params = new URLSearchParams({ name });\n\t\tconst response = await fetch(this.baseHttpUrl + `${this.apiPrefix}/datasets?${params.toString()}`, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: this.headers()\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn response.json();\n\t}\n\t/**\n\t* Push datapoints to a dataset.\n\t*\n\t* @param {Object} options - Push options\n\t* @param {Datapoint<D, T>[]} options.points - Datapoints to push\n\t* @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n\t* @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n\t* @param {number} [options.batchSize] - Batch size for pushing (default: 100)\n\t* @param {boolean} [options.createDataset] - Whether to create the dataset if it doesn't exist\n\t* @returns {Promise<PushDatapointsResponse | undefined>}\n\t*/\n\tasync push({ points, name, id, batchSize = DEFAULT_DATASET_PUSH_BATCH_SIZE, createDataset = false }) {\n\t\tif (!name && !id) throw new Error(\"Either name or id must be provided\");\n\t\tif (name && id) throw new Error(\"Only one of name or id must be provided\");\n\t\tif (createDataset && !name) throw new Error(\"Name must be provided when creating a new dataset\");\n\t\tconst identifier = name ? { name } : { datasetId: id };\n\t\tconst totalBatches = Math.ceil(points.length / batchSize);\n\t\tlet response;\n\t\tfor (let i = 0; i < points.length; i += batchSize) {\n\t\t\tconst batchNum = Math.floor(i / batchSize) + 1;\n\t\t\tlogger$3.debug(`Pushing batch ${batchNum} of ${totalBatches}`);\n\t\t\tconst batch = points.slice(i, i + batchSize);\n\t\t\tconst fetchResponse = await fetch(this.baseHttpUrl + this.apiPrefix + \"/datasets/datapoints\", {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: this.headers(),\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t...identifier,\n\t\t\t\t\tdatapoints: batch.map((point) => ({\n\t\t\t\t\t\tdata: point.data,\n\t\t\t\t\t\ttarget: point.target ?? {},\n\t\t\t\t\t\tmetadata: point.metadata ?? {}\n\t\t\t\t\t})),\n\t\t\t\t\tcreateDataset\n\t\t\t\t})\n\t\t\t});\n\t\t\tif (fetchResponse.status !== 200 && fetchResponse.status !== 201) await this.handleError(fetchResponse);\n\t\t\tresponse = await fetchResponse.json();\n\t\t}\n\t\treturn response;\n\t}\n\t/**\n\t* Pull datapoints from a dataset.\n\t*\n\t* @param {Object} options - Pull options\n\t* @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n\t* @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n\t* @param {number} [options.limit] - Maximum number of datapoints to return (default: 100)\n\t* @param {number} [options.offset] - Offset for pagination (default: 0)\n\t* @returns {Promise<GetDatapointsResponse<D, T>>}\n\t*/\n\tasync pull({ name, id, limit = DEFAULT_DATASET_PULL_LIMIT, offset = 0 }) {\n\t\tif (!name && !id) throw new Error(\"Either name or id must be provided\");\n\t\tif (name && id) throw new Error(\"Only one of name or id must be provided\");\n\t\tconst paramsObj = {\n\t\t\toffset: offset.toString(),\n\t\t\tlimit: limit.toString()\n\t\t};\n\t\tif (name) paramsObj.name = name;\n\t\telse paramsObj.datasetId = id;\n\t\tconst params = new URLSearchParams(paramsObj);\n\t\tconst response = await fetch(this.baseHttpUrl + `${this.apiPrefix}/datasets/datapoints?${params.toString()}`, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: this.headers()\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn response.json();\n\t}\n};\n//#endregion\n//#region src/resources/evals.ts\nconst logger$2 = initializeLogger();\nconst INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16e6;\nvar EvalsResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/**\n\t* Initialize an evaluation.\n\t*\n\t* @param {string} name - Name of the evaluation\n\t* @param {string} groupName - Group name of the evaluation\n\t* @param {Record<string, any>} metadata - Optional metadata\n\t* @returns {Promise<InitEvaluationResponse>} Response from the evaluation initialization\n\t*/\n\tasync init(name, groupName, metadata) {\n\t\tconst response = await fetch(this.baseHttpUrl + \"/v1/evals\", {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify({\n\t\t\t\tname: name ?? null,\n\t\t\t\tgroupName: groupName ?? null,\n\t\t\t\tmetadata: metadata ?? null\n\t\t\t})\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn response.json();\n\t}\n\t/**\n\t* Create a new evaluation and return its ID.\n\t*\n\t* @param {string} [name] - Optional name of the evaluation\n\t* @param {string} [groupName] - An identifier to group evaluations\n\t* @param {Record<string, any>} [metadata] - Optional metadata\n\t* @returns {Promise<StringUUID>} The evaluation ID\n\t*/\n\tasync create(args) {\n\t\treturn (await this.init(args?.name, args?.groupName, args?.metadata)).id;\n\t}\n\t/**\n\t* Create a new evaluation and return its ID.\n\t* @deprecated use `create` instead.\n\t*/\n\tasync createEvaluation(name, groupName, metadata) {\n\t\treturn (await this.init(name, groupName, metadata)).id;\n\t}\n\t/**\n\t* Create a datapoint for an evaluation.\n\t*\n\t* @param {Object} options - Create datapoint options\n\t* @param {string} options.evalId - The evaluation ID\n\t* @param {D} options.data - The input data for the executor\n\t* @param {T} [options.target] - The target/expected output for evaluators\n\t* @param {Record<string, any>} [options.metadata] - Optional metadata\n\t* @param {number} [options.index] - Optional index of the datapoint\n\t* @param {string} [options.traceId] - Optional trace ID\n\t* @returns {Promise<StringUUID>} The datapoint ID\n\t*/\n\tasync createDatapoint({ evalId, data, target, metadata, index, traceId }) {\n\t\tconst datapointId = newUUID();\n\t\tconst partialDatapoint = {\n\t\t\tid: datapointId,\n\t\t\tdata,\n\t\t\ttarget,\n\t\t\tindex: index ?? 0,\n\t\t\ttraceId: traceId ?? newUUID(),\n\t\t\texecutorSpanId: newUUID(),\n\t\t\tmetadata\n\t\t};\n\t\tawait this.saveDatapoints({\n\t\t\tevalId,\n\t\t\tdatapoints: [partialDatapoint]\n\t\t});\n\t\treturn datapointId;\n\t}\n\t/**\n\t* Update a datapoint with evaluation results.\n\t*\n\t* @param {Object} options - Update datapoint options\n\t* @param {string} options.evalId - The evaluation ID\n\t* @param {string} options.datapointId - The datapoint ID\n\t* @param {Record<string, number>} options.scores - The scores\n\t* @param {O} [options.executorOutput] - The executor output\n\t* @returns {Promise<void>}\n\t*/\n\tasync updateDatapoint({ evalId, datapointId, scores, executorOutput }) {\n\t\tconst response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints/${datapointId}`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify({\n\t\t\t\texecutorOutput,\n\t\t\t\tscores\n\t\t\t})\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n\t/**\n\t* Save evaluation datapoints.\n\t*\n\t* @param {Object} options - Save datapoints options\n\t* @param {string} options.evalId - ID of the evaluation\n\t* @param {EvaluationDatapoint<D, T, O>[]} options.datapoints - Datapoint to add\n\t* @param {string} [options.groupName] - Group name of the evaluation\n\t* @returns {Promise<void>} Response from the datapoint addition\n\t*/\n\tasync saveDatapoints({ evalId, datapoints, groupName }) {\n\t\tconst response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify({\n\t\t\t\tpoints: datapoints.map((d) => ({\n\t\t\t\t\t...d,\n\t\t\t\t\tdata: slicePayload(d.data, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n\t\t\t\t\ttarget: slicePayload(d.target, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n\t\t\t\t\texecutorOutput: slicePayload(d.executorOutput, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH)\n\t\t\t\t})),\n\t\t\t\tgroupName: groupName ?? null\n\t\t\t})\n\t\t});\n\t\tif (response.status === 413) return await this.retrySaveDatapoints({\n\t\t\tevalId,\n\t\t\tdatapoints,\n\t\t\tgroupName\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n\t/**\n\t* Get evaluation datapoints.\n\t*\n\t* @deprecated Use `client.datasets.pull()` instead.\n\t* @param {Object} options - Get datapoints options\n\t* @param {string} options.datasetName - Name of the dataset\n\t* @param {number} options.offset - Offset at which to start the query\n\t* @param {number} options.limit - Maximum number of datapoints to return\n\t* @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval\n\t*/\n\tasync getDatapoints({ datasetName, offset, limit }) {\n\t\tlogger$2.warn(\"evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.\");\n\t\tconst params = new URLSearchParams({\n\t\t\tname: datasetName,\n\t\t\toffset: offset.toString(),\n\t\t\tlimit: limit.toString()\n\t\t});\n\t\tconst response = await fetch(this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: this.headers()\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn await response.json();\n\t}\n\tasync retrySaveDatapoints({ evalId, datapoints, groupName, maxRetries = 25, initialLength = INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH }) {\n\t\tlet length = initialLength;\n\t\tlet lastResponse = null;\n\t\tfor (let i = 0; i < maxRetries; i++) {\n\t\t\tlogger$2.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);\n\t\t\tconst response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: this.headers(),\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tpoints: datapoints.map((d) => ({\n\t\t\t\t\t\t...d,\n\t\t\t\t\t\tdata: slicePayload(d.data, length),\n\t\t\t\t\t\ttarget: slicePayload(d.target, length),\n\t\t\t\t\t\texecutorOutput: slicePayload(d.executorOutput, length)\n\t\t\t\t\t})),\n\t\t\t\t\tgroupName: groupName ?? null\n\t\t\t\t})\n\t\t\t});\n\t\t\tlastResponse = response;\n\t\t\tlength = Math.floor(length / 2);\n\t\t\tif (response.status !== 413) break;\n\t\t}\n\t\tif (lastResponse && !lastResponse.ok) await this.handleError(lastResponse);\n\t}\n};\n//#endregion\n//#region src/resources/evaluators.ts\n/**\n* Resource for creating evaluator scores\n*/\nvar EvaluatorsResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/**\n\t* Create a score for a span or trace\n\t*\n\t* @param {ScoreOptions} options - Score creation options\n\t* @param {string} options.name - Name of the score\n\t* @param {string} [options.traceId] - The trace ID to score (will be attached to top-level span)\n\t* @param {string} [options.spanId] - The span ID to score\n\t* @param {Record<string, any>} [options.metadata] - Additional metadata\n\t* @param {number} options.score - The score value (float)\n\t* @returns {Promise<void>}\n\t*\n\t* @example\n\t* // Score by trace ID (will attach to root span)\n\t* await evaluators.score({\n\t* name: \"quality\",\n\t* traceId: \"trace-id-here\",\n\t* score: 0.95,\n\t* metadata: { model: \"gpt-4\" }\n\t* });\n\t*\n\t* @example\n\t* // Score by span ID\n\t* await evaluators.score({\n\t* name: \"relevance\",\n\t* spanId: \"span-id-here\",\n\t* score: 0.87\n\t* });\n\t*/\n\tasync score(options) {\n\t\tconst { name, metadata, score } = options;\n\t\tlet payload;\n\t\tif (\"traceId\" in options && options.traceId) payload = {\n\t\t\tname,\n\t\t\tmetadata,\n\t\t\tscore,\n\t\t\tsource: \"Code\",\n\t\t\ttraceId: isStringUUID(options.traceId) ? options.traceId : otelTraceIdToUUID(options.traceId)\n\t\t};\n\t\telse if (\"spanId\" in options && options.spanId) payload = {\n\t\t\tname,\n\t\t\tmetadata,\n\t\t\tscore,\n\t\t\tsource: \"Code\",\n\t\t\tspanId: isStringUUID(options.spanId) ? options.spanId : otelSpanIdToUUID(options.spanId)\n\t\t};\n\t\telse throw new Error(\"Either 'traceId' or 'spanId' must be provided.\");\n\t\tconst response = await fetch(this.baseHttpUrl + \"/v1/evaluators/score\", {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify(payload)\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n};\n//#endregion\n//#region src/resources/rollout-sessions.ts\nconst logger$1 = initializeLogger();\n/**\n* Map the opaque HIT `response` payload onto a {@link CachedSpan} the provider\n* wrappers can replay. The server-side shape of `response` is not yet frozen\n* (app-server plan 01 leaves it as a `serde_json::Value`), so this stays\n* deliberately tolerant: the whole payload is serialized into `output` (the only\n* field the AI SDK wrapper's `parseCachedSpan` actually reads, via\n* `JSON.parse`), and a `finishReason` is surfaced into `attributes` when the\n* payload carries one. `name`/`input` are irrelevant to replay and left empty.\n*/\nconst toCachedSpan = (response) => {\n\tconst output = typeof response === \"string\" ? response : JSON.stringify(response ?? null);\n\tconst attributes = {};\n\tif (response !== null && typeof response === \"object\" && typeof response.finishReason === \"string\") attributes[\"ai.response.finishReason\"] = response.finishReason;\n\treturn {\n\t\tname: \"\",\n\t\tinput: \"\",\n\t\toutput,\n\t\tattributes\n\t};\n};\nvar RolloutSessionsResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/**\n\t* Idempotently register (upsert) a debug session on the backend, keyed on the\n\t* SDK-supplied session id. The backend stores the row so the session is\n\t* visible in the UI; a null/omitted name never clobbers a name set elsewhere.\n\t*\n\t* Returns the backend-resolved `projectId` (derived from the API key) so the\n\t* caller can build the debugger URL; null if the body can't be parsed.\n\t*/\n\tasync register({ sessionId, name }) {\n\t\tconst response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify({ name })\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\ttry {\n\t\t\treturn (await response.json()).projectId ?? null;\n\t\t} catch (e) {\n\t\t\tlogger$1.warn(`Failed to parse rollout register response: ${errorMessage(e)}`);\n\t\t\treturn null;\n\t\t}\n\t}\n\t/**\n\t* Rename an existing debug session. Update-only: the backend returns 404 (and\n\t* this throws) when the session id is unknown for the project, so a mistyped\n\t* id surfaces as an error rather than silently creating a session. Creation\n\t* stays the SDK's job via {@link register}.\n\t*/\n\tasync setName({ sessionId, name }) {\n\t\tconst response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/name`, {\n\t\t\tmethod: \"PATCH\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify({ name })\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n\t/**\n\t* Look up the debug-replay cache for a single LLM call (debug-replay v2).\n\t*\n\t* The server is keyed by `inputHash` (hex blake3 of the canonicalized,\n\t* system-stripped input messages). It returns one of three outcomes:\n\t* - `{ outcome: \"hit\", response }` — a cached response to replay.\n\t* - `{ outcome: \"miss\" }` — no entry; caller latches live mode.\n\t* - `{ outcome: \"live\" }` — run this call live (COLD degrade).\n\t*\n\t* Error posture: a non-OK response or a transport error degrades to\n\t* `{ kind: \"live\" }` for THIS call only — it never throws and never latches\n\t* the process-wide live flag (only a real MISS does that). This keeps a flaky\n\t* cache backend from turning a replay into a crash.\n\t*/\n\tasync cache({ sessionId, replayTraceId, cacheUntil, inputHash }) {\n\t\tlet response;\n\t\ttry {\n\t\t\tresponse = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/cache`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: this.headers(),\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\treplayTraceId,\n\t\t\t\t\tcacheUntil,\n\t\t\t\t\tinputHash\n\t\t\t\t})\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tlogger$1.warn(`Debug cache lookup failed, running live: ${errorMessage(e)}`);\n\t\t\treturn { kind: \"live\" };\n\t\t}\n\t\tif (!response.ok) {\n\t\t\tlogger$1.warn(`Debug cache lookup returned ${response.status}, running live`);\n\t\t\treturn { kind: \"live\" };\n\t\t}\n\t\tlet body;\n\t\ttry {\n\t\t\tbody = await response.json();\n\t\t} catch (e) {\n\t\t\tlogger$1.warn(`Failed to parse debug cache response, running live: ${errorMessage(e)}`);\n\t\t\treturn { kind: \"live\" };\n\t\t}\n\t\tswitch (body.outcome) {\n\t\t\tcase \"hit\":\n\t\t\t\tif (body.response === null || body.response === void 0) {\n\t\t\t\t\tlogger$1.warn(\"Debug cache HIT had no response payload, running live\");\n\t\t\t\t\treturn { kind: \"live\" };\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"hit\",\n\t\t\t\t\tcached: toCachedSpan(body.response)\n\t\t\t\t};\n\t\t\tcase \"miss\": return { kind: \"miss\" };\n\t\t\tcase \"live\": return { kind: \"live\" };\n\t\t\tdefault:\n\t\t\t\tlogger$1.warn(`Unknown debug cache outcome \"${body.outcome}\", running live`);\n\t\t\t\treturn { kind: \"live\" };\n\t\t}\n\t}\n\tasync delete({ sessionId }) {\n\t\tconst response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}`, {\n\t\t\tmethod: \"DELETE\",\n\t\t\theaders: this.headers()\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n};\n//#endregion\n//#region src/resources/sql.ts\nvar SqlResource = class extends BaseResource {\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\tasync query(sql, parameters = {}) {\n\t\tconst response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/sql/query`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { ...this.headers() },\n\t\t\tbody: JSON.stringify({\n\t\t\t\tquery: sql,\n\t\t\t\tparameters\n\t\t\t})\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn (await response.json()).data;\n\t}\n};\n//#endregion\n//#region src/resources/tags.ts\n/** Resource for tagging traces. */\nvar TagsResource = class extends BaseResource {\n\t/** Resource for tagging traces. */\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/**\n\t* Tag a trace with a list of tags. Note that the trace must be ended before\n\t* tagging it. You may want to call `await Laminar.flush()` after the trace\n\t* that you want to tag.\n\t*\n\t* @param {string | StringUUID} trace_id - The trace id to tag.\n\t* @param {string[] | string} tags - The tag or list of tags to add to the trace.\n\t* @returns {Promise<any>} The response from the server.\n\t* @example\n\t* ```javascript\n\t* import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n\t* Laminar.initialize();\n\t* const client = new LaminarClient();\n\t* let traceId: StringUUID | null = null;\n\t* // Make sure this is called outside of traced context.\n\t* await observe(\n\t* {\n\t* name: \"my-trace\",\n\t* },\n\t* async () => {\n\t* traceId = await Laminar.getTraceId();\n\t* await foo();\n\t* },\n\t* );\n\t*\n\t* // or make sure the trace is ended by this point.\n\t* await Laminar.flush();\n\t* if (traceId) {\n\t* await client.tags.tag(traceId, [\"tag1\", \"tag2\"]);\n\t* }\n\t* ```\n\t*/\n\tasync tag(trace_id, tags) {\n\t\tconst traceTags = Array.isArray(tags) ? tags : [tags];\n\t\tconst formattedTraceId = isStringUUID(trace_id) ? trace_id : otelTraceIdToUUID(trace_id);\n\t\tconst url = this.baseHttpUrl + \"/v1/tag\";\n\t\tconst payload = {\n\t\t\t\"traceId\": formattedTraceId,\n\t\t\t\"names\": traceTags\n\t\t};\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify(payload)\n\t\t});\n\t\tif (!response.ok) await this.handleError(response);\n\t\treturn response.json();\n\t}\n};\n//#endregion\n//#region src/resources/traces.ts\n/** Resource for post-factum operations on existing traces. */\nconst logger = initializeLogger();\nvar TracesResource = class extends BaseResource {\n\t/** Resource for post-factum operations on existing traces. */\n\tconstructor(baseHttpUrl, auth) {\n\t\tsuper(baseHttpUrl, auth);\n\t}\n\t/**\n\t* Push a metadata patch to an existing trace.\n\t*\n\t* The patch is shallow-merged server-side into the trace's existing metadata\n\t* (`existing || patch`, last-write-wins per top-level key). Useful for\n\t* attaching post-factum signals — quality scores, human edits, triage labels —\n\t* to a trace that has already finished. The patch does NOT extend `endTime`\n\t* or change tokens / cost / top span / tags / span names. `numSpans` is\n\t* incremented by 1 (paid by the virtual span that carried the patch through\n\t* the ingestion queue) so the new ClickHouse row beats the prior version on\n\t* `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.\n\t*\n\t* Compared to `Laminar.setTraceMetadata` (which sets metadata on the\n\t* currently in-flight trace via OpenTelemetry attributes), this method\n\t* operates on a finished trace by trace id, so it must be called after the\n\t* trace has been flushed.\n\t*\n\t* A 404 response (the trace was not found in the project — typically because\n\t* it has not been flushed yet) is logged as a warning and the call returns\n\t* without throwing, since the 404 may be expected when pushing too soon\n\t* after the trace run. Pass `failOnNotFound: true` to throw instead (e.g.\n\t* CLI callers that must report the failure). Any other non-OK status throws.\n\t*\n\t* @param traceId - The trace id to push metadata to. Accepts a UUID string\n\t* or a 32-char OTel hex trace id.\n\t* @param metadata - The metadata patch. Top-level keys are merged into the\n\t* trace's existing metadata. Must be non-empty (the server rejects empty\n\t* patches with 400).\n\t* @param options - `failOnNotFound`: throw on 404 instead of warn-and-return.\n\t* @example\n\t* ```typescript\n\t* import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n\t* Laminar.initialize();\n\t* const client = new LaminarClient();\n\t*\n\t* let traceId: string | null = null;\n\t* await observe({ name: \"generate\" }, async () => {\n\t* traceId = await Laminar.getTraceId();\n\t* });\n\t* await Laminar.flush();\n\t*\n\t* if (traceId) {\n\t* await client.traces.pushMetadata(traceId, {\n\t* score: 0.85,\n\t* reviewer: \"alice\",\n\t* needsReview: false,\n\t* });\n\t* }\n\t* ```\n\t*/\n\tasync pushMetadata(traceId, metadata, options) {\n\t\tif (!metadata || Object.keys(metadata).length === 0) throw new Error(\"metadata must be a non-empty object\");\n\t\tconst formattedTraceId = isStringUUID(traceId) ? traceId : otelTraceIdToUUID(traceId);\n\t\tconst url = this.baseHttpUrl + this.apiPrefix + \"/traces/metadata\";\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: this.headers(),\n\t\t\tbody: JSON.stringify({\n\t\t\t\ttraceId: formattedTraceId,\n\t\t\t\tmetadata\n\t\t\t})\n\t\t});\n\t\tif (response.status === 404) {\n\t\t\tconst message = `Trace ${formattedTraceId} not found. The trace may not have been flushed yet — call await Laminar.flush() and retry.`;\n\t\t\tif (options?.failOnNotFound) throw new Error(message);\n\t\t\tlogger.warn(message);\n\t\t\treturn;\n\t\t}\n\t\tif (!response.ok) await this.handleError(response);\n\t}\n};\n//#endregion\n//#region src/index.ts\nvar LaminarClient = class LaminarClient {\n\tconstructor({ baseUrl, port, auth, projectApiKey, cliUserProjectId } = {}) {\n\t\tloadEnv();\n\t\tthis.auth = LaminarClient.normalizeAuth(auth, projectApiKey, cliUserProjectId);\n\t\tconst httpPort = port ?? (baseUrl?.match(/:\\d{1,5}$/g) ? parseInt(baseUrl.match(/:\\d{1,5}$/g)[0].slice(1)) : 443);\n\t\tconst baseUrlNoPort = (baseUrl ?? process.env.LMNR_BASE_URL)?.replace(/\\/$/, \"\").replace(/:\\d{1,5}$/g, \"\");\n\t\tthis.baseUrl = `${baseUrlNoPort ?? \"https://api.lmnr.ai\"}:${httpPort}`;\n\t\tthis._browserEvents = new BrowserEventsResource(this.baseUrl, this.auth);\n\t\tthis._cli = new CliResource(this.baseUrl, this.auth);\n\t\tthis._datasets = new DatasetsResource(this.baseUrl, this.auth);\n\t\tthis._evals = new EvalsResource(this.baseUrl, this.auth);\n\t\tthis._evaluators = new EvaluatorsResource(this.baseUrl, this.auth);\n\t\tthis._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.auth);\n\t\tthis._sql = new SqlResource(this.baseUrl, this.auth);\n\t\tthis._tags = new TagsResource(this.baseUrl, this.auth);\n\t\tthis._traces = new TracesResource(this.baseUrl, this.auth);\n\t}\n\t/**\n\t* Normalize the constructor's auth inputs into a {@link LaminarAuth} union.\n\t* Precedence: an explicit `auth` wins; otherwise the legacy\n\t* `projectApiKey` (+ optional `cliUserProjectId`) is mapped — a present\n\t* `cliUserProjectId` selects the user-token surface, otherwise the project\n\t* key surface. Falls back to `LMNR_PROJECT_API_KEY` as a project key.\n\t*/\n\tstatic normalizeAuth(auth, projectApiKey, cliUserProjectId) {\n\t\tif (auth) return auth;\n\t\tconst key = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY;\n\t\tif (cliUserProjectId) return {\n\t\t\ttype: \"userToken\",\n\t\t\ttoken: key,\n\t\t\tprojectId: cliUserProjectId\n\t\t};\n\t\treturn {\n\t\t\ttype: \"apiKey\",\n\t\t\tkey\n\t\t};\n\t}\n\tget browserEvents() {\n\t\treturn this._browserEvents;\n\t}\n\tget cli() {\n\t\treturn this._cli;\n\t}\n\tget datasets() {\n\t\treturn this._datasets;\n\t}\n\tget evals() {\n\t\treturn this._evals;\n\t}\n\tget evaluators() {\n\t\treturn this._evaluators;\n\t}\n\tget rolloutSessions() {\n\t\treturn this._rolloutSessions;\n\t}\n\tget sql() {\n\t\treturn this._sql;\n\t}\n\tget tags() {\n\t\treturn this._tags;\n\t}\n\tget traces() {\n\t\treturn this._traces;\n\t}\n};\n//#endregion\nexport { LaminarClient, RolloutSessionsResource };\n\n//# sourceMappingURL=index.mjs.map","import pino, { Level } from 'pino';\nimport { PinoPretty } from 'pino-pretty';\n\nexport function initializeLogger(options?: { colorize?: boolean; level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level =\n options?.level ??\n (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level) ??\n 'info';\n\n return pino(\n {\n level,\n },\n PinoPretty({\n colorize,\n minimumLevel: level,\n destination: 2,\n }),\n );\n}\n","import { errorMessage } from '@lmnr-ai/types';\n\n/**\n * Write structured JSON to stdout. Use this for machine-readable output\n * when --json is set.\n */\nexport function outputJson(data: unknown): void {\n console.log(JSON.stringify(data));\n}\n\n/**\n * Write a JSON error to stdout and exit with code 1.\n * Use this in --json mode so agents can parse the failure.\n */\nexport function outputJsonError(error: unknown, exitCode: number = 1): never {\n console.log(JSON.stringify({\n error: errorMessage(error),\n }));\n process.exit(exitCode);\n}\n","// Default Laminar endpoints, shared across commands. Override per-invocation\n// via the --frontend-url / --base-url flags or the LMNR_FRONTEND_URL /\n// LMNR_BASE_URL env vars; these are the final fallback.\nexport const DEFAULT_FRONTEND_URL = \"https://laminar.sh\";\nexport const DEFAULT_BASE_URL = \"https://api.lmnr.ai\";\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join, parse } from \"node:path\";\n\n/**\n * Directory-scoped project link, written by `setup` to `.lmnr/project.json`.\n * The project the CLI operates on is inferred from the directory you're in\n * (Vercel/Supabase style), overridable with --project-id.\n * Holds the project id plus small display details — never secrets (the API key\n * lives in .env).\n */\nexport interface ProjectLink {\n projectId: string;\n projectName?: string;\n workspaceId?: string;\n workspaceName?: string;\n}\n\nconst LINK_DIR = \".lmnr\";\nconst LINK_FILE = \"project.json\";\n\n/**\n * Find the nearest `.lmnr/project.json`, walking up from `startDir` to the\n * filesystem root (so commands work from subdirectories of a linked project).\n * Returns null if none is found.\n */\nexport async function readProjectLink(\n startDir: string = process.cwd(),\n): Promise<ProjectLink | null> {\n let dir = startDir;\n const root = parse(dir).root;\n\n while (true) {\n const candidate = join(dir, LINK_DIR, LINK_FILE);\n try {\n const parsed = JSON.parse(await readFile(candidate, \"utf8\")) as ProjectLink;\n if (parsed && typeof parsed.projectId === \"string\" && parsed.projectId.length > 0) {\n return parsed;\n }\n } catch {\n // Not here (missing / unreadable / malformed) — keep walking up.\n }\n const parent = dirname(dir);\n if (parent === dir || dir === root) break;\n dir = parent;\n }\n return null;\n}\n\n/** Write `.lmnr/project.json` under `dir` (default cwd). Returns the file path. */\nexport async function writeProjectLink(\n link: ProjectLink,\n dir: string = process.cwd(),\n): Promise<string> {\n const linkDir = join(dir, LINK_DIR);\n await mkdir(linkDir, { recursive: true });\n const path = join(linkDir, LINK_FILE);\n await writeFile(path, JSON.stringify(link, null, 2) + \"\\n\", \"utf8\");\n return path;\n}\n","import { mkdir, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nexport const CREDENTIALS_VERSION = 1;\n\n/**\n * The signed-in user's BetterAuth tokens. The CLI is single-user — one account\n * at a time, so the file is flat (no profiles map / active pointer).\n * Pre-release: version stays 1, no backcompat with any earlier shape.\n * - `sessionToken` is the durable BetterAuth session token (the refresh token).\n * - `accessToken` is the short-lived (15m) EdDSA JWT minted from the session.\n */\nexport interface Credentials {\n version: 1;\n issuer: string;\n // No `baseUrl` here on purpose: the data-API endpoint is resolved fresh on\n // every command (`--base-url` flag → LMNR_BASE_URL → default) so a self-host\n // .env change takes effect without re-login. `issuer` (the frontend URL,\n // used for token refresh) stays cached because refresh has no flag/env.\n sessionToken: string;\n accessToken: string;\n accessTokenExpiresAt: string;\n sessionExpiresAt?: string;\n userEmail?: string;\n userId: string;\n createdAt: string;\n lastUsedAt?: string;\n}\n\n// The lmnr config dir: `XDG_CONFIG_HOME` when set, else `%APPDATA%\\lmnr` on\n// Windows and `~/.config/lmnr` elsewhere.\nexport function globalLmnrDirectory(): string {\n const xdg = process.env.XDG_CONFIG_HOME?.trim();\n if (xdg && xdg.length > 0) {\n return join(xdg, \"lmnr\");\n }\n const appData = process.env.APPDATA?.trim();\n if (process.platform === \"win32\" && appData && appData.length > 0) {\n return join(appData, \"lmnr\");\n }\n return join(homedir(), \".config\", \"lmnr\");\n}\n\nexport function credentialsPath(): string {\n return join(globalLmnrDirectory(), \"credentials.json\");\n}\n\n/**\n * Read the credentials file. Returns null when missing or not the current flat\n * v1 shape (treated as \"not logged in\" — `lmnr-cli login` overwrites).\n */\nexport async function readCredentials(): Promise<Credentials | null> {\n const path = credentialsPath();\n let raw: string;\n try {\n raw = await readFile(path, \"utf-8\");\n } catch (e: unknown) {\n if (isNotFound(e)) return null;\n throw e;\n }\n let parsed: Partial<Credentials>;\n try {\n parsed = JSON.parse(raw) as Partial<Credentials>;\n } catch {\n return null;\n }\n if (parsed.version === CREDENTIALS_VERSION && typeof parsed.sessionToken === \"string\") {\n return parsed as Credentials;\n }\n return null;\n}\n\nexport async function writeCredentials(creds: Credentials): Promise<void> {\n const path = credentialsPath();\n const parent = dirname(path);\n await mkdir(parent, { recursive: true, mode: 0o700 });\n\n // Preserve a tighter user-set mode (e.g. 0o600) across token-refresh writes;\n // default 0o600 for new files. The temp adopts this mode and the rename\n // carries it onto the canonical file.\n let mode = 0o600;\n try {\n const existing = await stat(path);\n mode = existing.mode & 0o777;\n } catch (e: unknown) {\n if (!isNotFound(e)) throw e;\n }\n\n // Atomic temp+rename so a crashed write can't corrupt the canonical file.\n const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;\n await writeFile(tmp, JSON.stringify(creds, null, 2), { mode, flag: \"wx\" });\n await rename(tmp, path);\n}\n\nexport async function deleteCredentials(): Promise<boolean> {\n const path = credentialsPath();\n try {\n await stat(path);\n } catch (e: unknown) {\n if (isNotFound(e)) return false;\n throw e;\n }\n await rm(path, { force: true });\n return true;\n}\n\nfunction isNotFound(e: unknown): boolean {\n return (\n typeof e === \"object\" &&\n e !== null &&\n \"code\" in e &&\n (e as { code?: string }).code === \"ENOENT\"\n );\n}\n","// Hand-rolled fetch against BetterAuth's RFC 8628 device-flow endpoints. Login\n// is user-scoped: the device token endpoint returns a session token (the\n// refresh token); the access token is a short-lived JWT minted separately via\n// GET /api/auth/token.\n\nimport {\n type DeviceCodeResponse,\n type DeviceTokenResponse,\n type PollOptions,\n type SessionUser,\n} from \"./types\";\n\nexport const CLI_CLIENT_ID = \"lmnr-cli\";\nexport const CLI_SCOPE = \"projects:rw\";\n\nconst DEVICE_CODE_ENDPOINT = \"/api/auth/device/code\";\nconst DEVICE_TOKEN_ENDPOINT = \"/api/auth/device/token\";\nconst TOKEN_ENDPOINT = \"/api/auth/token\";\nconst SESSION_ENDPOINT = \"/api/auth/get-session\";\n\ntype PollErrorCode =\n | \"authorization_pending\"\n | \"slow_down\"\n | \"access_denied\"\n | \"expired_token\"\n | \"invalid_grant\"\n | \"invalid_request\"\n | \"invalid_client\"\n | \"server_error\";\n\nexport class DeviceFlowError extends Error {\n constructor(public readonly code: string, message: string) {\n super(message);\n }\n}\n\nfunction trimSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nexport async function initiateDevice(\n issuer: string,\n scope: string = CLI_SCOPE,\n): Promise<DeviceCodeResponse> {\n const url = `${trimSlash(issuer)}${DEVICE_CODE_ENDPOINT}`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ client_id: CLI_CLIENT_ID, scope }),\n });\n if (!res.ok) {\n const body = (await safeJson(res)) ?? {};\n throw new DeviceFlowError(\n typeof body.error === \"string\" ? body.error : `http_${res.status}`,\n typeof body.error_description === \"string\"\n ? body.error_description\n : `Device authorization request failed (${res.status})`,\n );\n }\n return (await res.json()) as DeviceCodeResponse;\n}\n\n/**\n * Poll BetterAuth's native token endpoint until the user approves. Returns the\n * full token response (whose `access_token` is the durable session token).\n */\nexport async function pollDevice(\n issuer: string,\n deviceCode: string,\n opts: PollOptions = {},\n): Promise<DeviceTokenResponse> {\n let intervalSeconds = Math.max(1, opts.intervalSeconds ?? 5);\n const timeoutMs = (opts.timeoutSeconds ?? 900) * 1000;\n const deadline = Date.now() + timeoutMs;\n\n while (true) {\n if (Date.now() > deadline) {\n throw new DeviceFlowError(\"expired_token\", \"Timed out waiting for authorization\");\n }\n const url = `${trimSlash(issuer)}${DEVICE_TOKEN_ENDPOINT}`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: deviceCode,\n client_id: CLI_CLIENT_ID,\n }),\n });\n if (res.ok) {\n const body = (await res.json()) as DeviceTokenResponse;\n if (!body.access_token) {\n throw new DeviceFlowError(\"server_error\", \"Device token response missing access_token\");\n }\n // The browser-selected project (and any future CLI metadata) rides back on\n // the x-lmnr-metadata response header, NOT the OAuth scope. Attach it so\n // callers can parse it via parseProjectFromMetadata.\n body.metadata = res.headers.get(\"x-lmnr-metadata\");\n return body;\n }\n const body = (await safeJson(res)) ?? {};\n const code = (\n typeof body.error === \"string\" ? body.error : `http_${res.status}`\n ) as PollErrorCode;\n const description = typeof body.error_description === \"string\" ? body.error_description : code;\n if (code === \"authorization_pending\") {\n opts.onTick?.();\n await sleep(intervalSeconds * 1000);\n continue;\n }\n if (code === \"slow_down\") {\n intervalSeconds += 5;\n await sleep(intervalSeconds * 1000);\n continue;\n }\n // access_denied / expired_token / invalid_grant / server_error — terminal.\n throw new DeviceFlowError(code, description);\n }\n}\n\n/**\n * Mint a fresh 15m EdDSA JWT from a session token. Throws DeviceFlowError\n * \"invalid_grant\" on 401 (session expired/revoked).\n */\nexport async function mintAccessJwt(issuer: string, sessionToken: string): Promise<string> {\n const url = `${trimSlash(issuer)}${TOKEN_ENDPOINT}`;\n const res = await fetch(url, {\n method: \"GET\",\n headers: { authorization: `Bearer ${sessionToken}` },\n });\n if (res.status === 401) {\n throw new DeviceFlowError(\"invalid_grant\", \"Session expired or revoked\");\n }\n if (!res.ok) {\n const body = (await safeJson(res)) ?? {};\n throw new DeviceFlowError(\n typeof body.error === \"string\" ? body.error : `http_${res.status}`,\n `Failed to mint access token (${res.status})`,\n );\n }\n const body = (await res.json()) as { token?: string };\n if (!body.token) {\n throw new DeviceFlowError(\"server_error\", \"Token endpoint response missing token\");\n }\n return body.token;\n}\n\n/** Fetch the BetterAuth session for profile metadata (userId, email). */\nexport async function fetchSession(issuer: string, sessionToken: string): Promise<SessionUser> {\n const url = `${trimSlash(issuer)}${SESSION_ENDPOINT}`;\n const res = await fetch(url, {\n method: \"GET\",\n headers: { authorization: `Bearer ${sessionToken}` },\n });\n if (!res.ok) {\n throw new DeviceFlowError(`http_${res.status}`, `Failed to fetch session (${res.status})`);\n }\n const body = (await res.json()) as { user?: { id?: string; email?: string } } | null;\n const user = body?.user;\n if (!user?.id) {\n throw new DeviceFlowError(\"server_error\", \"Session response missing user\");\n }\n return { id: user.id, email: user.email ?? \"\" };\n}\n\n/**\n * Decode a JWT's `exp` (seconds since epoch) → ISO string. No signature\n * verification — the CLI trusts a token it just received over TLS. Returns null\n * when the token is malformed or carries no numeric `exp`.\n */\nexport function decodeJwtExp(jwt: string): string | null {\n const parts = jwt.split(\".\");\n if (parts.length < 2) return null;\n try {\n const json = Buffer.from(parts[1], \"base64url\").toString(\"utf-8\");\n const payload = JSON.parse(json) as { exp?: unknown };\n if (typeof payload.exp !== \"number\") return null;\n return new Date(payload.exp * 1000).toISOString();\n } catch {\n return null;\n }\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Extract the browser-selected projectId from the device-token `x-lmnr-metadata`\n * response header — a JSON string, e.g. `{\"projectId\":\"<uuid>\"}`, forwarded by\n * the server's /device/token route wrapper. Returns null when absent or malformed.\n */\nexport function parseProjectFromMetadata(metadata?: string | null): string | null {\n if (!metadata) return null;\n try {\n const obj = JSON.parse(metadata) as { projectId?: unknown };\n const pid = obj?.projectId;\n return typeof pid === \"string\" && UUID_RE.test(pid) ? pid : null;\n } catch {\n return null;\n }\n}\n\nasync function safeJson(res: Response): Promise<Record<string, unknown> | null> {\n try {\n return (await res.json()) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","import { DEFAULT_BASE_URL } from \"../constants\";\nimport { readProjectLink } from \"../utils/project-link\";\nimport { type Credentials, readCredentials, writeCredentials } from \"./credentials\";\nimport { decodeJwtExp, DeviceFlowError, mintAccessJwt } from \"./device\";\nimport { type AuthInputs, type ResolvedAuth } from \"./types\";\n\n// Re-mint the JWT when it's within this window of expiry.\nconst REFRESH_SKEW_MS = 30_000;\n\n/**\n * HTTP port from `LMNR_HTTP_PORT`. The Laminar convention is that `baseUrl`\n * carries NO port and the port is supplied separately (mirrors the SDK's\n * `LMNR_HTTP_PORT` / `LMNR_GRPC_PORT`). Returns undefined when unset/invalid so\n * the client keeps its 443 default for Cloud. An explicit `--port` flag still\n * wins (callers do `opts.port ?? envHttpPort()`).\n */\nexport function envHttpPort(): number | undefined {\n const raw = process.env.LMNR_HTTP_PORT?.trim();\n if (!raw) return undefined;\n const n = Number.parseInt(raw, 10);\n return Number.isFinite(n) ? n : undefined;\n}\n\n/**\n * Resolve the data-API base URL: `--base-url` flag → `LMNR_BASE_URL` env →\n * default. Intentionally NOT read from credentials.json — the endpoint is not\n * persisted at login, so a self-host `.env` change applies to every command\n * without re-logging-in (and base URL behaves symmetrically with the port).\n */\nexport function resolveBaseUrl(optBaseUrl?: string): string {\n return optBaseUrl?.trim() || process.env.LMNR_BASE_URL?.trim() || DEFAULT_BASE_URL;\n}\n\n/**\n * CLI auth is **user-token only** — the CLI authenticates as the single\n * signed-in user via the stored BetterAuth session (refreshed access JWT),\n * never via a project API key.\n *\n * Project precedence (directory-scoped): `--project-id` flag > the nearest\n * `.lmnr/project.json` (written by `setup`). The project is NOT stored in\n * credentials.json — that holds only user auth.\n */\nexport async function resolveAuth(opts: AuthInputs): Promise<ResolvedAuth> {\n const creds = await readCredentials();\n if (!creds) {\n throw new Error(\"Not authenticated. Run `lmnr-cli login`.\");\n }\n\n let projectId = opts.projectId;\n if (!projectId || projectId.length === 0) {\n projectId = (await readProjectLink())?.projectId;\n }\n if (!projectId || projectId.length === 0) {\n throw new Error(\n \"No project for this directory. Run `lmnr-cli setup` here, \" +\n \"or pass --project-id <id>.\",\n );\n }\n\n const updated = await refreshIfNeeded(creds);\n return {\n bearer: updated.accessToken,\n baseUrl: resolveBaseUrl(opts.baseUrl),\n port: opts.port ?? envHttpPort(),\n projectId,\n };\n}\n\n/**\n * Resolve only the user-scoped access token (no project) — for discovery\n * endpoints like listing projects, which run BEFORE a project is selected.\n */\nexport async function resolveUserToken(opts: {\n baseUrl?: string;\n port?: number;\n}): Promise<{ bearer: string; baseUrl?: string; port?: number }> {\n const creds = await readCredentials();\n if (!creds) {\n throw new Error(\"Not authenticated. Run `lmnr-cli login`.\");\n }\n const updated = await refreshIfNeeded(creds);\n return {\n bearer: updated.accessToken,\n baseUrl: resolveBaseUrl(opts.baseUrl),\n port: opts.port ?? envHttpPort(),\n };\n}\n\n/**\n * Re-mint the access JWT when it's near expiry and persist it. A 401 from the\n * token endpoint means the session is gone — surface a clear \"run login\" error.\n *\n * Logout race guard: we write credentials ONLY when we actually re-minted. The\n * old code unconditionally rewrote the file (just to bump lastUsedAt) on every\n * command, so a concurrent `logout` that deleted the file mid-flight could have\n * its delete clobbered by this in-flight atomic rename — logout would appear to\n * succeed while tokens remained on disk. For a fresh (not-near-expiry) token we\n * now do no write at all, eliminating that window for the common case.\n */\nexport async function refreshIfNeeded(creds: Credentials): Promise<Credentials> {\n const expMs = new Date(creds.accessTokenExpiresAt).getTime();\n const nearExpiry = !Number.isFinite(expMs) || expMs - Date.now() <= REFRESH_SKEW_MS;\n if (!nearExpiry) {\n return creds;\n }\n\n const next: Credentials = { ...creds };\n try {\n const jwt = await mintAccessJwt(creds.issuer, creds.sessionToken);\n next.accessToken = jwt;\n next.accessTokenExpiresAt = decodeJwtExp(jwt) ?? new Date().toISOString();\n } catch (e) {\n if (e instanceof DeviceFlowError && e.code === \"invalid_grant\") {\n throw new Error(\"Session expired — run `lmnr-cli login`.\");\n }\n throw e;\n }\n next.lastUsedAt = new Date().toISOString();\n await writeCredentials(next);\n return next;\n}\n","import { LaminarClient } from \"@lmnr-ai/client\";\n\nimport { resolveAuth } from \"./resolve\";\nimport { type AuthInputs } from \"./types\";\n\n/**\n * Build a LaminarClient for CLI commands. Auth is user-token only: the bearer\n * is the stored BetterAuth access JWT (auto-refreshed near expiry) and requests\n * route to `/v1/cli/*` with the resolved project in `x-lmnr-project-id`.\n */\nexport async function buildLaminarClient(opts: AuthInputs): Promise<LaminarClient> {\n const auth = await resolveAuth(opts);\n return new LaminarClient({\n baseUrl: auth.baseUrl,\n port: auth.port,\n // User-token auth → routes to /v1/cli/* with the resolved project in the\n // x-lmnr-project-id header.\n auth: { type: \"userToken\", token: auth.bearer, projectId: auth.projectId },\n });\n}\n","import { LaminarClient } from \"@lmnr-ai/client\";\nimport { errorMessage } from \"@lmnr-ai/types\";\nimport type { Command } from \"commander\";\n\nimport { initializeLogger } from \"../utils/logger\";\nimport { outputJsonError } from \"../utils/output\";\nimport { buildLaminarClient } from \"./client\";\nimport { resolveUserToken } from \"./resolve\";\n\nconst logger = initializeLogger();\n\n/**\n * Global options every wrapped command shares (from `cmd.optsWithGlobals()`).\n * `projectId` is consumed by the project-client path; discovery commands ignore\n * it (the user-token surface has no project to scope at discovery time).\n */\nexport interface GlobalOpts {\n projectId?: string;\n baseUrl?: string;\n port?: number;\n json?: boolean;\n}\n\n/**\n * Map a thrown error to a process exit code. The default is 1; pass a custom\n * mapper to a wrapper to surface distinct machine-readable codes (Phase 6).\n */\nexport type ExitCodeMapper = (error: unknown) => number;\n\nconst defaultExitCode: ExitCodeMapper = () => 1;\n\n/**\n * Pull the commander positionals out of an `.action(...)` argument list.\n * Commander invokes the handler as `(arg1, ..., argN, options, command)`, so\n * the positionals are everything except the trailing `(options, command)`.\n */\nfunction splitCommanderArgs(cmdArgs: unknown[]): {\n positionals: unknown[];\n command: Command;\n opts: GlobalOpts;\n} {\n const command = cmdArgs.at(-1) as Command;\n const positionals = cmdArgs.slice(0, -2);\n const opts = command.optsWithGlobals();\n return { positionals, command, opts };\n}\n\n/**\n * The error envelope shared by both wrappers: in `--json` mode emit a structured\n * error line and exit with the mapped code; otherwise log and exit. Owning this\n * here lets handlers stay pure `(client, ...args) => work` with no try/catch.\n */\nfunction runWithEnvelope(\n work: () => Promise<void>,\n opts: GlobalOpts,\n exitCodeFor: ExitCodeMapper,\n): Promise<void> {\n return work().catch((error: unknown) => {\n const code = exitCodeFor(error);\n if (opts.json) {\n // outputJsonError exits with `code` (never returns).\n outputJsonError(error, code);\n }\n logger.error(errorMessage(error));\n process.exit(code);\n });\n}\n\n/**\n * The handler shape both wrappers accept: a pure function of the resolved\n * client, the commander positionals, and the parsed options (so it can read\n * `--json` for output mode). All auth resolution + the error envelope live in\n * the wrapper, so handlers contain only the work.\n */\nexport type ClientAction<A extends unknown[]> = (\n client: LaminarClient,\n ...args: [...A, GlobalOpts]\n) => Promise<void>;\n\n/**\n * Wrap a project-scoped command handler. Resolves a user-token\n * {@link LaminarClient} (routes to `/v1/cli/*` with the resolved project),\n * threads the commander positionals + options through, and owns the error\n * envelope.\n *\n * @example\n * sqlCmd.command(\"query\")\n * .argument(\"<query>\")\n * .action(withProjectClient(handleSqlQuery)); // (client, query, opts) => work\n */\nexport const withProjectClient =\n <A extends unknown[]>(\n action: ClientAction<A>,\n exitCodeFor: ExitCodeMapper = defaultExitCode,\n ) =>\n async (...cmdArgs: unknown[]): Promise<void> => {\n const { positionals, opts } = splitCommanderArgs(cmdArgs);\n await runWithEnvelope(\n async () => {\n const client = await buildLaminarClient({\n projectId: opts.projectId,\n baseUrl: opts.baseUrl,\n port: opts.port,\n });\n await action(client, ...(positionals as A), opts);\n },\n opts,\n exitCodeFor,\n );\n };\n\n/**\n * Wrap a discovery command handler. Resolves a user-token\n * {@link LaminarClient} with NO project (the discovery surface — e.g. listing\n * projects — runs before a project is selected), threads positionals +\n * options, and owns the error envelope.\n */\nexport const withUserToken =\n <A extends unknown[]>(\n action: ClientAction<A>,\n exitCodeFor: ExitCodeMapper = defaultExitCode,\n ) =>\n async (...cmdArgs: unknown[]): Promise<void> => {\n const { positionals, opts } = splitCommanderArgs(cmdArgs);\n await runWithEnvelope(\n async () => {\n const token = await resolveUserToken({\n baseUrl: opts.baseUrl,\n port: opts.port,\n });\n const client = new LaminarClient({\n baseUrl: token.baseUrl,\n // token.port carries the --port flag OR the LMNR_HTTP_PORT fallback\n // (resolveUserToken applies it); using opts.port here would drop it.\n port: token.port,\n // Discovery: no project id yet. CliResource overrides its own\n // URL/headers, so the empty projectId is never sent.\n auth: { type: \"userToken\", token: token.bearer, projectId: \"\" },\n });\n await action(client, ...(positionals as A), opts);\n },\n opts,\n exitCodeFor,\n );\n };\n","import { Datapoint, errorMessage } from '@lmnr-ai/types';\nimport csv from 'csv-parser';\nimport { asString, generateCsv, mkConfig } from 'export-to-csv';\nimport { createReadStream } from 'fs';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\n\nimport { initializeLogger } from './logger';\n\nconst logger = initializeLogger();\n\n/**\n * Check if a file has a supported extension.\n */\nconst isSupportedFile = (file: string): boolean => {\n const ext = path.extname(file).toLowerCase();\n return ['.json', '.csv', '.jsonl'].includes(ext);\n};\n\n/**\n * Collect all supported files from the given paths.\n * Handles both files and directories.\n */\nexport const collectFiles = async (\n paths: string[],\n recursive: boolean = false,\n): Promise<string[]> => {\n const collectedFiles: string[] = [];\n\n for (const filepath of paths) {\n try {\n const stats = await fs.stat(filepath);\n\n if (stats.isFile()) {\n if (isSupportedFile(filepath)) {\n collectedFiles.push(filepath);\n } else {\n logger.warn(`Skipping unsupported file type: ${filepath}`);\n }\n } else if (stats.isDirectory()) {\n const entries = await fs.readdir(filepath);\n\n for (const entry of entries) {\n const fullPath = path.join(filepath, entry);\n const entryStats = await fs.stat(fullPath);\n\n if (entryStats.isFile() && isSupportedFile(fullPath)) {\n collectedFiles.push(fullPath);\n } else if (recursive && entryStats.isDirectory()) {\n const subFiles = await collectFiles([fullPath], true);\n collectedFiles.push(...subFiles);\n }\n }\n }\n } catch (error) {\n logger.warn(\n `Path does not exist or is not accessible: ${filepath}. `\n + `Error: ${errorMessage(error)}`,\n );\n }\n }\n\n return collectedFiles;\n};\n\n/**\n * Read a JSON file and return its contents.\n */\nconst readJsonFile = async (filepath: string): Promise<any[]> => {\n const content = await fs.readFile(filepath, 'utf-8');\n const parsed = JSON.parse(content);\n return Array.isArray(parsed) ? parsed : [parsed];\n};\n\n/**\n * Try to parse a string as JSON. If it fails, return the original string.\n */\nconst tryParseJson = (content: string): any => {\n // Don't try to parse if it's not a string or doesn't look like JSON\n if (typeof content !== 'string') {\n return content;\n }\n\n // If it doesn't start with { or [, it's probably not JSON\n const trimmed = content.trim();\n if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {\n return content;\n }\n\n try {\n return JSON.parse(content);\n } catch (error) {\n logger.debug(\n `Error parsing JSON: ${errorMessage(error)}`,\n );\n return content;\n }\n};\n\n/**\n * Parse each field in a CSV row, attempting to convert JSON strings back to objects.\n */\nconst parseCsvRow = (row: Record<string, string>): any => {\n const parsed: any = {};\n for (const [key, value] of Object.entries(row)) {\n parsed[key] = tryParseJson(value);\n }\n return parsed;\n};\n\n/**\n * Read a CSV file and return its contents as an array of objects.\n */\nconst readCsvFile = async (filepath: string): Promise<any[]> => new Promise((resolve, reject) => {\n const results: any[] = [];\n createReadStream(filepath)\n .pipe(csv())\n .on('data', (data) => results.push(parseCsvRow(data)))\n .on('end', () => resolve(results))\n .on('error', reject);\n});\n\n/**\n * Read a JSONL file and return its contents as an array of objects.\n */\nasync function readJsonlFile(filepath: string): Promise<any[]> {\n const content = await fs.readFile(filepath, 'utf-8');\n const lines = content.split('\\n').filter((line) => line.trim());\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return lines.map((line) => JSON.parse(line));\n}\n\n/**\n * Read a single file and return its contents.\n */\nasync function readFile(filepath: string): Promise<any[]> {\n const ext = path.extname(filepath).toLowerCase();\n\n if (ext === '.json') {\n return readJsonFile(filepath);\n } else if (ext === '.csv') {\n return readCsvFile(filepath);\n } else if (ext === '.jsonl') {\n return readJsonlFile(filepath);\n } else {\n throw new Error(`Unsupported file type: ${ext}`);\n }\n}\n\n/**\n * Load data from all files in the specified paths.\n */\nexport const loadFromPaths = async <D = any, T = any>(\n paths: string[],\n recursive: boolean = false,\n): Promise<Datapoint<D, T>[]> => {\n const files = await collectFiles(paths, recursive);\n\n if (files.length === 0) {\n logger.warn('No supported files found in the specified paths');\n return [];\n }\n\n logger.info(`Found ${files.length} file(s) to read`);\n\n const result: Datapoint<D, T>[] = [];\n\n for (const file of files) {\n try {\n const data = await readFile(file);\n result.push(...data);\n logger.info(`Read ${data.length} record(s) from ${file}`);\n } catch (error) {\n logger.error(\n `Error reading file ${file}: ${errorMessage(error)}`,\n );\n throw error;\n }\n }\n\n return result;\n};\n\n/**\n * Write data to a JSON file.\n */\nconst writeJsonFile = async <D, T>(\n filepath: string,\n data: Datapoint<D, T>[],\n): Promise<void> => {\n const content = JSON.stringify(data, null, 2);\n await fs.writeFile(filepath, content, 'utf-8');\n};\n\n/**\n * Format data as a CSV string.\n */\nconst formatCsv = <D, T>(data: Datapoint<D, T>[]): string => {\n const formattedData = data.map(item =>\n Object.fromEntries(Object.entries(item).map(([key, value]) => [key, stringifyForCsv(value)]),\n ));\n\n const csvConfig = mkConfig({ useKeysAsHeaders: true });\n const csvOutput = generateCsv(csvConfig)(formattedData);\n return asString(csvOutput);\n};\n\n/**\n * Write data to a CSV file.\n */\nconst writeCsvFile = async <D, T>(\n filepath: string,\n data: Datapoint<D, T>[],\n): Promise<void> => {\n if (data.length === 0) {\n throw new Error('No data to write to CSV');\n }\n\n await fs.writeFile(filepath, formatCsv(data), 'utf-8');\n};\n\n/**\n * Write data to a JSONL file.\n */\nconst writeJsonlFile = async <D, T>(\n filepath: string,\n data: Datapoint<D, T>[],\n): Promise<void> => {\n const lines = data.map((item) => JSON.stringify(item)).join('\\n');\n await fs.writeFile(filepath, lines + '\\n', 'utf-8');\n};\n\n/**\n * Write data to a file based on the file extension.\n */\nexport const writeToFile = async <D, T>(\n filepath: string,\n data: Datapoint<D, T>[],\n format?: 'json' | 'csv' | 'jsonl',\n): Promise<void> => {\n // Create parent directories if they don't exist\n const dir = path.dirname(filepath);\n await fs.mkdir(dir, { recursive: true });\n\n // Determine the format\n const ext = format ?? path.extname(filepath).slice(1);\n\n if (format && format !== path.extname(filepath).slice(1)) {\n logger.warn(\n `Output format ${format} does not match file extension ${path.extname(filepath).slice(1)}`,\n );\n }\n\n if (ext === 'json') {\n await writeJsonFile(filepath, data);\n } else if (ext === 'csv') {\n await writeCsvFile(filepath, data);\n } else if (ext === 'jsonl') {\n await writeJsonlFile(filepath, data);\n } else {\n throw new Error(`Unsupported output format: ${ext}`);\n }\n};\n\n/**\n * Convert a value to a CSV-safe string.\n * - Strings and numbers pass through\n * - null/undefined become empty strings\n * - Objects and arrays are stringified to JSON\n */\nconst stringifyForCsv = (value: any): string => {\n if (value === null || value === undefined) {\n return '';\n }\n if (typeof value === 'string') {\n return value;\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n // For objects and arrays, stringify to JSON\n return JSON.stringify(value);\n};\n\n/**\n * Print data to console in the specified format.\n */\nexport const printToConsole = <D, T>(\n data: Datapoint<D, T>[],\n format: 'json' | 'csv' | 'jsonl' = 'json',\n) => {\n if (format === 'json') {\n console.log(JSON.stringify(data, null, 2));\n } else if (format === 'csv') {\n if (data.length === 0) {\n logger.error('No data to print');\n return;\n }\n\n console.log(formatCsv(data));\n } else if (format === 'jsonl') {\n data.forEach((item) => console.log(JSON.stringify(item)));\n } else {\n throw new Error(\n `Unsupported output format: ${String(format)}. `\n + \"(supported formats: json, csv, jsonl)\",\n );\n }\n};\n\n","import Table from \"cli-table3\";\n\nconst DEFAULT_TERMINAL_WIDTH = 80;\nconst PADDING_RIGHT = 2;\n\nconst noBorderChars = {\n top: \"\", \"top-mid\": \"\", \"top-left\": \"\", \"top-right\": \"\",\n bottom: \"\", \"bottom-mid\": \"\", \"bottom-left\": \"\", \"bottom-right\": \"\",\n left: \"\", \"left-mid\": \"\", mid: \"\", \"mid-mid\": \"\",\n right: \"\", \"right-mid\": \"\", middle: \"\",\n};\n\nfunction getTerminalWidth(): number {\n return process.stdout.columns || DEFAULT_TERMINAL_WIDTH;\n}\n\n/**\n * Calculate column widths that fit within the terminal width.\n * Distributes available space proportionally based on content width.\n */\nfunction fitColumnWidths(\n contentWidths: number[],\n terminalWidth: number,\n): number[] | undefined {\n // With no borders, overhead is just padding-right per column\n const overhead = contentWidths.length * PADDING_RIGHT;\n const totalContentWidth = contentWidths.reduce((sum, w) => sum + w, 0);\n\n if (totalContentWidth + overhead <= terminalWidth) {\n return undefined;\n }\n\n const availableContent = terminalWidth - overhead;\n const minColWidth = 5;\n\n // Return widths including padding, since cli-table3's colWidths includes padding\n return contentWidths.map((w) =>\n Math.max(\n minColWidth + PADDING_RIGHT,\n Math.floor((w / totalContentWidth) * availableContent) + PADDING_RIGHT,\n ),\n );\n}\n\nfunction truncate(str: string, maxLen: number): string {\n if (maxLen < 1) return str;\n if (str.length <= maxLen) return str;\n return str.slice(0, maxLen - 1) + \"\\u2026\";\n}\n\n/**\n * Render a borderless table from column headers and row data.\n * Automatically truncates content when the table exceeds terminal width.\n */\nexport function renderTable(head: string[], rows: string[][]): string {\n const terminalWidth = getTerminalWidth();\n\n const contentWidths = head.map((h, i) =>\n rows.reduce((max, row) => Math.max(max, (row[i] ?? \"\").length), h.length),\n );\n\n const colWidths = fitColumnWidths(contentWidths, terminalWidth);\n\n const truncatedHead = colWidths\n ? head.map((h, i) => truncate(h, colWidths[i] - PADDING_RIGHT))\n : head;\n\n const table = new Table({\n head: truncatedHead,\n chars: noBorderChars,\n style: {\n \"padding-left\": 0,\n \"padding-right\": PADDING_RIGHT,\n },\n ...(colWidths && { colWidths }),\n });\n\n if (colWidths) {\n for (const row of rows) {\n table.push(row.map((cell, i) => truncate(cell, colWidths[i] - PADDING_RIGHT)));\n }\n } else {\n for (const row of rows) {\n table.push(row);\n }\n }\n\n return table.toString();\n}\n","import { LaminarClient } from \"@lmnr-ai/client\";\nimport { Datapoint, type StringUUID } from \"@lmnr-ai/types\";\n\nimport type { GlobalOpts } from \"../../auth/with-client\";\nimport { loadFromPaths, printToConsole, writeToFile } from \"../../utils/file\";\nimport { initializeLogger } from \"../../utils/logger\";\nimport { outputJson } from \"../../utils/output\";\nimport { renderTable } from \"../../utils/table\";\n\nconst logger = initializeLogger();\nconst DEFAULT_DATASET_PULL_BATCH_SIZE = 100;\nconst DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;\n\ninterface DatasetIdentifierOptions extends GlobalOpts {\n name?: string;\n id?: StringUUID;\n}\n\n/** Throw on the name/id mutual-exclusion rule. The wrapper renders the error. */\nfunction requireSingleIdentifier(opts: { name?: string; id?: StringUUID }): void {\n if (!opts.name && !opts.id) {\n throw new Error(\"Either name or id must be provided\");\n }\n if (opts.name && opts.id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n}\n\n/**\n * Pull all data from a dataset in batches.\n */\nconst pullAllData = async <D = any, T = any>(\n client: LaminarClient,\n identifier: { name?: string; id?: StringUUID },\n batchSize: number = DEFAULT_DATASET_PULL_BATCH_SIZE,\n offset: number = 0,\n limit?: number,\n): Promise<Datapoint<D, T>[]> => {\n let hasMore = true;\n let currentOffset = offset;\n const stopAt = limit !== undefined ? offset + limit : undefined;\n\n const result: Datapoint<D, T>[] = [];\n\n while (hasMore && (stopAt === undefined || currentOffset < stopAt)) {\n const data = await client.datasets.pull<D, T>({\n ...identifier,\n offset: currentOffset,\n limit: batchSize,\n });\n\n result.push(...data.items);\n\n // Stop if we received no items or fewer items than requested (end of data)\n if (data.items.length === 0 || data.items.length < batchSize) {\n hasMore = false;\n } else if (stopAt !== undefined && currentOffset + batchSize >= stopAt) {\n hasMore = false;\n } else if (data.totalCount !== undefined && currentOffset + batchSize >= data.totalCount) {\n hasMore = false;\n }\n\n currentOffset += batchSize;\n }\n\n if (limit !== undefined) {\n return result.slice(0, limit);\n }\n\n return result;\n};\n\n/**\n * Handle datasets list command. Pure handler — `withProjectClient` resolves the\n * client and owns the error envelope.\n */\nexport const handleDatasetsList = async (\n client: LaminarClient,\n opts: GlobalOpts,\n): Promise<void> => {\n const datasets = await client.datasets.listDatasets();\n\n if (opts.json) {\n outputJson(datasets);\n return;\n }\n\n if (datasets.length === 0) {\n console.log(\"No datasets found.\");\n return;\n }\n\n const rows = datasets.map((dataset) => {\n const createdAt = new Date(dataset.createdAt);\n const createdAtStr = createdAt.toISOString().replace('T', ' ').substring(0, 19);\n return [dataset.id, createdAtStr, dataset.name];\n });\n\n console.log(renderTable(['ID', 'Created At', 'Name'], rows));\n console.log(`\\nTotal: ${datasets.length} dataset(s)\\n`);\n};\n\n/**\n * Handle datasets push command.\n */\nexport const handleDatasetsPush = async (\n client: LaminarClient,\n paths: string[],\n opts: DatasetIdentifierOptions & {\n recursive?: boolean;\n batchSize?: number;\n },\n): Promise<void> => {\n requireSingleIdentifier(opts);\n\n const data = await loadFromPaths(paths, opts.recursive);\n\n if (data.length === 0) {\n throw new Error(\"No data to push\");\n }\n\n const identifier = opts.name ? { name: opts.name } : { id: opts.id };\n\n const result = await client.datasets.push({\n points: data,\n ...identifier,\n batchSize: opts.batchSize ?? DEFAULT_DATASET_PUSH_BATCH_SIZE,\n });\n\n if (opts.json) {\n outputJson({ datasetId: result?.datasetId, count: data.length });\n return;\n }\n\n logger.info(`Pushed ${data.length} data points to dataset ${opts.name || opts.id}`);\n};\n\n/**\n * Handle datasets pull command.\n */\nexport const handleDatasetsPull = async (\n client: LaminarClient,\n outputPath: string | undefined,\n opts: DatasetIdentifierOptions & {\n outputFormat?: 'json' | 'csv' | 'jsonl';\n batchSize?: number;\n limit?: number;\n offset?: number;\n },\n): Promise<void> => {\n requireSingleIdentifier(opts);\n\n const identifier = opts.name ? { name: opts.name } : { id: opts.id };\n\n const result = await pullAllData(\n client,\n identifier,\n opts.batchSize ?? DEFAULT_DATASET_PULL_BATCH_SIZE,\n opts.offset ?? 0,\n opts.limit,\n );\n\n if (outputPath) {\n await writeToFile(outputPath, result, opts.outputFormat);\n if (opts.json) {\n outputJson({ path: outputPath, count: result.length });\n } else {\n logger.info(`Successfully pulled ${result.length} data points to ${outputPath}`);\n }\n } else {\n if (opts.json) {\n outputJson(result);\n } else {\n printToConsole(result, opts.outputFormat ?? 'json');\n }\n }\n};\n\n/**\n * Handle datasets create command.\n */\nexport const handleDatasetsCreate = async (\n client: LaminarClient,\n name: string,\n paths: string[],\n opts: GlobalOpts & {\n outputFile: string;\n outputFormat?: 'json' | 'csv' | 'jsonl';\n recursive?: boolean;\n batchSize?: number;\n },\n): Promise<void> => {\n // Load data from input files\n const data = await loadFromPaths(paths, opts.recursive);\n\n if (data.length === 0) {\n throw new Error(\"No data to push\");\n }\n\n // Push data to create/populate the dataset\n logger.info(`Pushing ${data.length} data points to dataset '${name}'...`);\n\n await client.datasets.push({\n points: data,\n name,\n batchSize: opts.batchSize ?? DEFAULT_DATASET_PUSH_BATCH_SIZE,\n createDataset: true,\n });\n logger.info(`Successfully pushed ${data.length} data points to dataset '${name}'`);\n\n // Pull data back from the dataset\n logger.info(`Pulling data from dataset '${name}'...`);\n\n const result = await pullAllData(\n client,\n { name },\n opts.batchSize ?? DEFAULT_DATASET_PULL_BATCH_SIZE,\n 0,\n undefined,\n );\n\n // Save to output file\n await writeToFile(opts.outputFile, result, opts.outputFormat);\n\n if (opts.json) {\n outputJson({ name, path: opts.outputFile, count: result.length });\n } else {\n logger.info(\n `Successfully created dataset '${name}' `\n + `and saved ${result.length} datapoints to ${opts.outputFile}`,\n );\n }\n};\n","// Trace-metadata key the debugger UI reads the agent's note from. Metadata\n// naming stays `rollout.*` (matching `rollout.session_id`); the value is an\n// opaque string the frontend renders as markdown.\nexport const NOTE_METADATA_KEY = \"rollout.note\";\n\n/**\n * Normalize a user-supplied trace id (UUID or 32-char OTel hex, optionally\n * 0x-prefixed) to the dashed UUID form used by the SQL endpoint. Throws on\n * anything else so a typo fails loudly instead of querying nothing.\n */\nexport const normalizeTraceId = (traceId: string): string => {\n const id = traceId.trim().toLowerCase().replace(/^0x/, \"\");\n if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id)) {\n return id;\n }\n if (/^[0-9a-f]{32}$/.test(id)) {\n return id.replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n \"$1-$2-$3-$4-$5\",\n );\n }\n throw new Error(\n `Invalid trace id \"${traceId}\". Expected a UUID or a 32-char OTel hex trace id.`,\n );\n};\n\n/**\n * Extract the note from a trace's `metadata` column as returned by the SQL\n * endpoint (a JSON string; tolerate an already-parsed object too). Missing /\n * malformed metadata reads as \"no note\".\n */\nexport const readNoteFromMetadata = (metadata: unknown): string => {\n let parsed: unknown = metadata;\n if (typeof metadata === \"string\") {\n if (metadata === \"\") {\n return \"\";\n }\n try {\n parsed = JSON.parse(metadata);\n } catch {\n return \"\";\n }\n }\n if (typeof parsed !== \"object\" || parsed === null) {\n return \"\";\n }\n const note = (parsed as Record<string, unknown>)[NOTE_METADATA_KEY];\n return typeof note === \"string\" ? note : \"\";\n};\n","import { LaminarClient } from \"@lmnr-ai/client\";\n\nimport type { GlobalOpts } from \"../../auth/with-client\";\nimport { initializeLogger } from \"../../utils/logger\";\nimport { outputJson } from \"../../utils/output\";\nimport { readNoteFromMetadata } from \"../../utils/trace-note\";\n\nconst logger = initializeLogger();\n\n/**\n * Upsert the display name of a debug session. Update-only on the backend: a\n * session id unknown to the project 404s rather than creating a ghost session.\n *\n * Pure handler: the command wrapper (`withProjectClient`) resolves a user-token\n * {@link LaminarClient} (routes to `/v1/cli/*` with the resolved project) and\n * owns the error envelope.\n */\nexport const handleDebugSessionSetName = async (\n client: LaminarClient,\n sessionId: string,\n name: string,\n opts: GlobalOpts,\n): Promise<void> => {\n await client.rolloutSessions.setName({ sessionId, name });\n\n if (opts.json) {\n outputJson({ sessionId, name });\n return;\n }\n\n logger.info(`Set name of session ${sessionId} to \"${name}\".`);\n};\n\ninterface SessionTraceSummary {\n note: string;\n traceId: string;\n // Trace `end_time` — the closest thing to \"last updated\" on a trace (it\n // advances as spans keep arriving for the trace).\n endTime: string;\n}\n\n/**\n * Print a per-trace summary of a debug session: every trace whose metadata\n * groups it to the session (`rollout.session_id`), oldest first, with the\n * agent-authored note (`rollout.note`) attached to each.\n *\n * Pure handler: the command wrapper (`withProjectClient`) resolves a user-token\n * {@link LaminarClient} (routes to `/v1/cli/*` with the resolved project) and\n * owns the error envelope.\n */\nexport const handleDebugSessionSummary = async (\n client: LaminarClient,\n sessionId: string,\n opts: GlobalOpts,\n): Promise<void> => {\n // formatDateTime pins end_time to unambiguous ISO-8601 UTC — the raw\n // column serializes as ClickHouse's space-separated local-looking format.\n const rows = await client.sql.query(\n \"SELECT id, \" +\n \"formatDateTime(end_time, '%Y-%m-%dT%H:%i:%S.%fZ') AS end_time, \" +\n \"metadata FROM traces \" +\n \"WHERE simpleJSONExtractString(metadata, 'rollout.session_id') \" +\n \"= {session_id:String} \" +\n \"ORDER BY start_time\",\n { session_id: sessionId },\n );\n const traces: SessionTraceSummary[] = rows.map((row) => ({\n note: readNoteFromMetadata(row.metadata),\n traceId: String(row.id ?? \"\"),\n endTime: String(row.end_time ?? \"\"),\n }));\n\n if (opts.json) {\n outputJson(traces);\n return;\n }\n\n if (traces.length === 0) {\n console.log(`No traces found for session ${sessionId}.`);\n return;\n }\n\n const blocks = traces.map((trace) => {\n const tag = `<trace id=\"${trace.traceId}\" end-time=\"${trace.endTime}\"/>`;\n return trace.note ? `${trace.note}\\n${tag}` : tag;\n });\n console.log(blocks.join(\"\\n\\n\"));\n};\n","import { createColors } from \"picocolors\";\n\n// Decide color support per stream: NO_COLOR (present at any value) disables,\n// FORCE_COLOR (present and not \"0\") forces on, otherwise fall back to that\n// stream's own TTY-ness. We key each stream independently because the CLI writes\n// human status to STDERR (stdout is reserved for the `--json` contract) but ALSO\n// prints a human summary to STDOUT in non-json mode — each should follow its own\n// stream's redirection (e.g. `setup > out.txt` must not get ANSI in the file).\nfunction enabledFor(stream: NodeJS.WriteStream): boolean {\n if (\"NO_COLOR\" in process.env) return false;\n if (\"FORCE_COLOR\" in process.env && process.env.FORCE_COLOR !== \"0\") return true;\n return Boolean(stream.isTTY);\n}\n\n// Human status lines (✓ / ⚠ / errors) → stderr.\nexport const pc = createColors(enabledFor(process.stderr));\n// The non-json human summary (\"Next steps\") → stdout.\nexport const pcOut = createColors(enabledFor(process.stdout));\n\n// Laminar brand orange (#D0754E = rgb(208,117,78)). picocolors only ships the 16\n// ANSI colors, so wrap a truecolor escape ourselves — gated on stderr color\n// support (the brand banner is a stderr line, same as `pc`).\nconst stderrColorEnabled = enabledFor(process.stderr);\nexport const orange = (text: string): string =>\n stderrColorEnabled ? `\\x1b[38;2;208;117;78m${text}\\x1b[39m` : text;\n","import open from \"open\";\n\nimport { type Credentials, writeCredentials } from \"../../auth/credentials\";\nimport {\n CLI_SCOPE,\n decodeJwtExp,\n fetchSession,\n initiateDevice,\n mintAccessJwt,\n parseProjectFromMetadata,\n pollDevice,\n} from \"../../auth/device\";\nimport { DEFAULT_FRONTEND_URL } from \"../../constants\";\nimport { pc } from \"../../utils/colors\";\n\nexport interface LoginOptions {\n frontendUrl?: string;\n noBrowser?: boolean;\n}\n\nexport interface LoginResult {\n /** The signed-in user's id (from the BetterAuth session). */\n userId: string;\n /** The signed-in user's email, when present on the session. */\n userEmail: string | null;\n /**\n * The projectId the user selected/created in the browser, delivered back via\n * the device-token `x-lmnr-metadata` response header (see\n * `parseProjectFromMetadata`). Null when the browser had nothing to select.\n */\n projectId: string | null;\n}\n\nexport async function handleLogin(options: LoginOptions): Promise<LoginResult> {\n const issuer = pick(options.frontendUrl, process.env.LMNR_FRONTEND_URL, DEFAULT_FRONTEND_URL);\n // NOTE: login does NOT resolve/store a data-API baseUrl — the device flow,\n // JWT mint and session fetch all hit `issuer` (frontend). `--base-url` on\n // login is accepted but inert (candidate for removal); data commands resolve\n // baseUrl themselves via resolveBaseUrl.\n\n const da = await initiateDevice(issuer, CLI_SCOPE);\n const completeUri = da.verification_uri_complete ?? da.verification_uri;\n process.stderr.write(\n `\\nOpen this URL in your browser to authorize:\\n ${pc.cyan(completeUri)}\\n`,\n );\n if (da.user_code) {\n process.stderr.write(`Code: ${pc.bold(pc.cyan(da.user_code))}\\n\\n`);\n }\n\n if (!options.noBrowser) {\n try {\n await open(completeUri);\n } catch {\n // Best-effort. The user can copy/paste the URL.\n }\n }\n\n process.stderr.write(pc.dim(\"Waiting for authorization...\\n\"));\n const token = await pollDevice(issuer, da.device_code, {\n intervalSeconds: da.interval,\n timeoutSeconds: da.expires_in,\n });\n\n // The device token's access_token is the durable session token (refresh).\n const sessionToken = token.access_token;\n const jwt = await mintAccessJwt(issuer, sessionToken);\n const session = await fetchSession(issuer, sessionToken);\n\n const now = new Date().toISOString();\n const creds: Credentials = {\n version: 1,\n issuer,\n sessionToken,\n accessToken: jwt,\n accessTokenExpiresAt: decodeJwtExp(jwt) ?? now,\n sessionExpiresAt:\n typeof token.expires_in === \"number\"\n ? new Date(Date.now() + token.expires_in * 1000).toISOString()\n : undefined,\n userEmail: session.email || undefined,\n userId: session.id,\n createdAt: now,\n lastUsedAt: now,\n };\n await writeCredentials(creds);\n\n // NOTE: the user-facing \"logged in / next steps\" summary is intentionally NOT\n // printed here — handleLogin is shared with `setup`, which prints its own\n // summary. The `login` command prints the summary itself (see src/index.ts).\n\n return {\n userId: session.id,\n userEmail: session.email || null,\n projectId: parseProjectFromMetadata(token.metadata),\n };\n}\n\nfunction pick(...candidates: (string | undefined)[]): string {\n for (const c of candidates) {\n if (c && c.length > 0) return c;\n }\n return \"\";\n}\n","import {\n type Credentials,\n credentialsPath,\n deleteCredentials,\n readCredentials,\n} from \"../../auth/credentials\";\n\n/**\n * Best-effort server-side session revoke via POST /api/auth/sign-out with the\n * session token as Bearer. Logout MUST complete locally even if the server is\n * unreachable — the user expects \"log me out\" to remove the file. On any\n * failure we log to stderr and continue.\n */\nexport async function revokeSession(creds: Credentials): Promise<void> {\n if (!creds.sessionToken || creds.sessionToken.length === 0) {\n return;\n }\n const url = `${trimSlash(creds.issuer)}/api/auth/sign-out`;\n try {\n // BetterAuth's sign-out 500s on an empty body (JSON parse fails); send `{}`.\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${creds.sessionToken}`,\n \"content-type\": \"application/json\",\n },\n body: \"{}\",\n });\n if (!res.ok) {\n process.stderr.write(\n `warning: session revoke at ${url} returned ${res.status}; ` +\n \"local credentials still removed.\\n\",\n );\n }\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(\n `warning: session revoke at ${url} failed (${msg}); local credentials still removed.\\n`,\n );\n }\n}\n\nexport async function handleLogout(): Promise<void> {\n const creds = await readCredentials();\n if (!creds) {\n process.stderr.write(\"Already logged out.\\n\");\n return;\n }\n const label = creds.userEmail ?? creds.userId;\n // Delete the local file FIRST, then best-effort revoke the server session.\n // \"Log me out\" must remove the credentials even if the network revoke hangs\n // or fails. Accepted residual race: a concurrent near-expiry refresh may\n // re-write creds just after this delete (durable token + inert JWT; no lock).\n await deleteCredentials();\n await revokeSession(creds);\n process.stderr.write(`Logged out of ${label}. Removed ${credentialsPath()}.\\n`);\n}\n\nfunction trimSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n","import { LaminarClient } from \"@lmnr-ai/client\";\n\nimport type { GlobalOpts } from \"../../auth/with-client\";\nimport { outputJson } from \"../../utils/output\";\nimport { readProjectLink } from \"../../utils/project-link\";\nimport { renderTable } from \"../../utils/table\";\n\n/**\n * List the projects the signed-in user can access (discovery — no project\n * scope). Pure handler: the `withUserToken` wrapper resolves the user-token\n * client and owns the error envelope.\n */\nexport const handleProjectsList = async (\n client: LaminarClient,\n opts: GlobalOpts,\n): Promise<void> => {\n const projects = await client.cli.listProjects();\n\n // Mark the project linked to the current directory (.lmnr/project.json).\n const linked = (await readProjectLink())?.projectId;\n\n if (opts.json) {\n outputJson(projects.map((p) => ({ ...p, linked: p.id === linked })));\n return;\n }\n\n if (projects.length === 0) {\n console.log(\"No projects found. Create one in the dashboard, then run `lmnr-cli setup`.\");\n return;\n }\n\n const columns = [\"\", \"Workspace\", \"Project\", \"Project ID\"];\n const rows = projects.map((p) => [p.id === linked ? \"●\" : \"\", p.workspaceName, p.name, p.id]);\n console.log(renderTable(columns, rows));\n console.log(\n linked\n ? \"\\n● = linked to this directory (lmnr-cli setup). \" +\n \"Override per-command with --project-id.\\n\"\n : \"\\nNot linked here. Run `lmnr-cli setup` in your project directory, \" +\n \"or pass --project-id.\\n\",\n );\n};\n","// Standalone `GET /v1/project` probe authed by a PROJECT API KEY (not the\n// user JWT). It's a separate helper rather than a `CliResource` method because\n// `CliResource` is keyed by the user JWT, while this probe is keyed by the\n// project key already sitting in the environment — overloading the resource's\n// single-key model would be confusing.\n\nimport { DEFAULT_BASE_URL } from \"../constants\";\n\nfunction trimSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/**\n * Outcome of probing which project an `LMNR_PROJECT_API_KEY` belongs to. These\n * are deliberately distinct so the caller doesn't conflate \"key is bad\" with\n * \"couldn't reach the server\":\n * - `ok` → key verified; `projectId` is its owner.\n * - `invalid` → 401: key revoked/invalid. Safe to mint a fresh one.\n * - `unverifiable` → network error / non-401 / malformed body. The key may be\n * perfectly valid — caller MUST NOT mint (minting would clobber it on a blip).\n */\nexport type KeyProbe =\n | { status: \"ok\"; projectId: string }\n | { status: \"invalid\" }\n | { status: \"unverifiable\" };\n\nexport async function probeProjectKey(\n projectApiKey: string,\n baseUrl: string = DEFAULT_BASE_URL,\n port?: number,\n): Promise<KeyProbe> {\n // Compose host + port the same way the real CLI clients do (baseUrl carries\n // no port by convention; LMNR_HTTP_PORT/--port is separate). new URL().port\n // rather than `:${port}` concat so a baseUrl with a path still works.\n const url = new URL(trimSlash(baseUrl));\n if (port) url.port = String(port);\n url.pathname = \"/v1/project\";\n let res: Response;\n try {\n res = await fetch(url.toString(), {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${projectApiKey}`,\n Accept: \"application/json\",\n },\n });\n } catch {\n return { status: \"unverifiable\" };\n }\n if (res.status === 401) return { status: \"invalid\" };\n if (!res.ok) return { status: \"unverifiable\" };\n const body = (await res.json().catch(() => null)) as { projectId?: string } | null;\n return body?.projectId ? { status: \"ok\", projectId: body.projectId } : { status: \"unverifiable\" };\n}\n","import { execFile } from \"node:child_process\";\nimport {\n access,\n readFile,\n rename,\n stat,\n writeFile,\n} from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nconst DEFAULT_VAR_NAME = \"LMNR_PROJECT_API_KEY\";\n\n// Env files we inspect, highest precedence first (Next.js-style, minus the\n// NODE_ENV-specific rungs). `.env.local` is the JS/Next secret convention\n// (gitignored); `.env` is the cross-ecosystem default every loader reads —\n// including Python's python-dotenv / pydantic, which don't know `.env.local`.\nconst CANDIDATE_FILES = [\".env.local\", \".env\"] as const;\n\nexport interface WriteEnvResult {\n /** Absolute path of the .env file. */\n path: string;\n /** True when the file did not exist before this call. */\n created: boolean;\n /** True when an existing `<varName>=` line was overwritten. */\n replaced: boolean;\n}\n\n/**\n * Write/replace `<varName>=<value>` in the .env file at `envPath`.\n *\n * Semantics:\n * - If the file does not exist: create it with mode 0o600 and a single line.\n * - If the file exists:\n * - Replace an existing `^<varName>\\s*=.*` line in place (preserves comments,\n * ordering, and other keys).\n * - Otherwise append the line (with a leading newline if the file does not\n * end in one).\n * - DO NOT change the file mode on existing files — the user may have set\n * a deliberate mode and changing it surprises them.\n * - Writes are atomic: write to `<envPath>.tmp`, then rename.\n */\nexport async function writeEnvFile(\n envPath: string,\n value: string,\n varName: string = DEFAULT_VAR_NAME,\n): Promise<WriteEnvResult> {\n const exists = await fileExists(envPath);\n\n if (!exists) {\n const contents = `${varName}=${value}\\n`;\n await atomicWrite(envPath, contents, 0o600);\n return { path: envPath, created: true, replaced: false };\n }\n\n const original = await readFile(envPath, \"utf-8\");\n // ^ at line start, m flag so . doesn't match newlines.\n const regex = new RegExp(`^${escapeRegex(varName)}\\\\s*=.*$`, \"m\");\n let next: string;\n let replaced = false;\n if (regex.test(original)) {\n next = original.replace(regex, `${varName}=${value}`);\n replaced = true;\n } else {\n const prefix = original.endsWith(\"\\n\") || original.length === 0 ? original : `${original}\\n`;\n next = `${prefix}${varName}=${value}\\n`;\n }\n // Capture existing mode so the tmp inherits dest's perms — POSIX `rename`\n // adopts the source inode's permissions, so without this an existing 0o600\n // .env would silently widen to the umask default (0o644) on every rerun.\n const existingMode = (await stat(envPath)).mode & 0o777;\n await atomicWrite(envPath, next, existingMode);\n return { path: envPath, created: false, replaced };\n}\n\n/**\n * Read a single env var's value from a .env file. Returns null when the file\n * is missing, the var is absent, or its value is empty/whitespace.\n */\nexport async function readEnvVar(\n envPath: string,\n varName: string = DEFAULT_VAR_NAME,\n): Promise<string | null> {\n if (!(await fileExists(envPath))) return null;\n const original = await readFile(envPath, \"utf-8\");\n const regex = new RegExp(`^${escapeRegex(varName)}\\\\s*=(.*)$`, \"m\");\n const match = original.match(regex);\n if (!match) return null;\n const value = match[1].trim().replace(/^[\"']|[\"']$/g, \"\");\n return value.length > 0 ? value : null;\n}\n\n/** Where an existing key was found: the process environment, or a specific file. */\nexport type EnvKeySource = { type: \"process-env\" } | { type: \"file\"; path: string };\n\nexport interface EnvKeyLocation {\n value: string;\n source: EnvKeySource;\n}\n\n/**\n * Find an already-configured key, checking `process.env` → `.env.local` → `.env`\n * (first match wins, mirroring Next.js precedence). `process.env` comes first\n * because an exported var is what actually runs, regardless of language.\n */\nexport async function findEnvKey(\n cwd: string,\n varName: string = DEFAULT_VAR_NAME,\n): Promise<EnvKeyLocation | null> {\n const fromProcess = process.env[varName]?.trim();\n if (fromProcess) return { value: fromProcess, source: { type: \"process-env\" } };\n for (const name of CANDIDATE_FILES) {\n const path = resolve(cwd, name);\n const value = await readEnvVar(path, varName);\n if (value) return { value, source: { type: \"file\", path } };\n }\n return null;\n}\n\n/**\n * LMNR_* config keys the CLI hydrates from a project `.env.local` / `.env`.\n * Curated on purpose — we do NOT slurp the whole file, so unrelated app secrets\n * (model API keys, etc.) never enter the CLI process. Notable exclusions:\n * - `LMNR_GRPC_PORT`: the CLI is REST-only (no gRPC), so it has no use for it.\n * - `LMNR_LOG_LEVEL`: loggers are built at module-import time (before\n * `loadLocalEnv` runs), so hydrating it here would silently have no effect.\n * - `LMNR_PROJECT_ID`: the project comes from `--project-id` or\n * `.lmnr/project.json` only; `resolveAuth` ignores the env var, so loading\n * it here would just contradict that.\n */\nexport const AUTOLOADED_ENV_KEYS = [\n \"LMNR_BASE_URL\",\n \"LMNR_HTTP_PORT\",\n \"LMNR_FRONTEND_URL\",\n] as const;\n\n/**\n * Hydrate `process.env` from `.env.local` / `.env` in `cwd` for the curated\n * {@link AUTOLOADED_ENV_KEYS}, WITHOUT overriding values already present in the\n * environment (a real exported var / Claude Code `settings.json` env always\n * wins — `findEnvKey` checks `process.env` first and we skip those).\n *\n * Why this exists: Claude Code and many other runners do NOT inject a project\n * `.env` into a spawned subprocess's environment, so self-hosters who put\n * `LMNR_BASE_URL` / `LMNR_HTTP_PORT` in `.env` previously had to export them or\n * pass flags on every call. cwd-only, no upward directory walk (mirrors\n * dotenv's default) — the CLI must be invoked from the dir holding the `.env`.\n */\nexport async function loadLocalEnv(\n cwd: string,\n keys: readonly string[] = AUTOLOADED_ENV_KEYS,\n): Promise<void> {\n for (const key of keys) {\n const found = await findEnvKey(cwd, key);\n // Only hydrate from a file; a process-env hit means it's already set.\n if (found?.source.type === \"file\") {\n process.env[key] = found.value;\n }\n }\n}\n\n/**\n * Pick the file to write a freshly-minted key into:\n * - rewrite in place if the key already lives in a file,\n * - else prefer an existing `.env.local` (its presence proves the project opted\n * into the gitignored-secret convention) — but never CREATE one, since Python\n * loaders ignore it,\n * - else `.env` (the default every ecosystem loads).\n */\nexport async function resolveEnvWriteTarget(\n cwd: string,\n existing: EnvKeyLocation | null,\n): Promise<string> {\n if (existing?.source.type === \"file\") return existing.source.path;\n const local = resolve(cwd, \".env.local\");\n if (await fileExists(local)) return local;\n return resolve(cwd, \".env\");\n}\n\n/**\n * Whether `path` is gitignored. Returns null when it can't be determined (not a\n * git repo / git absent) so callers can stay silent rather than warn wrongly.\n */\nexport async function isPathGitIgnored(path: string): Promise<boolean | null> {\n try {\n await execFileAsync(\"git\", [\"check-ignore\", \"-q\", path]);\n return true; // exit 0 = ignored\n } catch (err) {\n // exit 1 = definitely not ignored; 128 (not a repo) / ENOENT (no git) = unknown\n return (err as { code?: number }).code === 1 ? false : null;\n }\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function atomicWrite(\n path: string,\n contents: string,\n mode: number | undefined,\n): Promise<void> {\n const tmp = `${path}.tmp`;\n await writeFile(tmp, contents, mode === undefined ? undefined : { mode });\n await rename(tmp, path);\n}\n\nfunction escapeRegex(raw: string): string {\n return raw.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","// Source coordinates for the Laminar agent skill, fetched from the public\n// lmnr-skills repo at `lmnr-cli setup` time via giget (see\n// ../utils/install-skill.ts).\n\nexport const SKILL_REPO = \"lmnr-ai/lmnr-skills\";\nexport const SKILL_REF = \"main\";\nexport const SKILL_NAME = \"laminar\";\n\n/**\n * giget source for the pinned skill subdir: `github:<owner>/<repo>/<subdir>#<ref>`.\n * giget resolves this against codeload.github.com, gunzips, untars, strips the\n * `repo-<ref>/` prefix, and extracts only the subdir — all the mechanics we'd\n * otherwise hand-roll.\n */\nexport function skillSource(): string {\n return `github:${SKILL_REPO}/skills/${SKILL_NAME}#${SKILL_REF}`;\n}\n","import { downloadTemplate } from \"giget\";\n\nimport { skillSource } from \"./laminar-skill\";\n\n/**\n * Download the pinned Laminar skill subtree into `dir` using giget.\n *\n * giget owns every quirk we'd otherwise hand-roll: the codeload tarball URL,\n * gunzip, untar, stripping the `repo-<ref>/` leading segment, subdir filtering,\n * and ref pinning. `force` overwrites `dir` so reruns are idempotent.\n *\n * We deliberately do NOT pass `preferOffline`: giget caches the tarball keyed by\n * REF name, and SKILL_REF is a moving branch (`main` / a feature branch), so\n * `preferOffline` would reuse a stale cached tarball forever — reinstalling\n * files that were since deleted upstream. Without it, giget revalidates via the\n * stored etag and re-downloads when the branch moved.\n *\n * Throws on network / resolve / extract errors — callers (skill install is\n * best-effort) catch and skip.\n */\nexport async function downloadSkill(dir: string): Promise<void> {\n await downloadTemplate(skillSource(), {\n dir,\n force: true,\n });\n}\n","import { access, cp, mkdir, mkdtemp, readdir, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join, relative } from \"node:path\";\n\nimport { downloadSkill } from \"../skill/fetch-skill\";\nimport { SKILL_NAME, skillSource } from \"../skill/laminar-skill\";\n\n// Agent dirs we look for in the project root. Order matters only for the\n// \"none present\" default below.\nconst AGENT_DIRS = [\".claude\", \".cursor\", \".codex\", \".agents\"] as const;\n\n// When NO agent dir exists we default to writing the skill into BOTH\n// `.claude/` (Claude Code reads `.claude/skills/`) and `.agents/`, so whichever\n// agent the project later adopts can find it.\nconst DEFAULT_AGENT_DIRS = [\".claude\", \".agents\"];\n\nexport interface InstallSkillResult {\n /** Absolute paths of every written file (SKILL.md + references/...). */\n written: string[];\n /** True when no agent dir existed and we defaulted to `.claude/` + `.agents/`. */\n defaulted: boolean;\n /**\n * True when the skill could not be fetched (network failure) and install was\n * skipped. `written` is empty and `defaulted` is false.\n */\n skipped: boolean;\n}\n\n/**\n * Fetch the pinned Laminar skill (`SKILL_NAME`) from the lmnr-skills repo and\n * write its full tree into every present agent dir under `cwd`\n * (`<dir>/skills/<SKILL_NAME>/SKILL.md`, `.../references/*.md`, ...). If none\n * are present, default to BOTH `.claude/` and `.agents/`. Idempotent —\n * overwrites on rerun.\n *\n * We download ONCE into a temp staging dir (one network hit) and copy it into\n * each agent dir. Skill install is the last, best-effort step of `setup`: a\n * download failure MUST NOT break setup — on error we log a warning and return\n * `{ written: [], defaulted: false, skipped: true }`.\n *\n * For .cursor/.codex the skills layout is not guaranteed to match CC; we write\n * the CC-guaranteed `skills/<SKILL_NAME>/` shape there too rather than\n * inventing a path that silently loads nothing.\n */\nexport async function installSkill(\n cwd: string = process.cwd(),\n): Promise<InstallSkillResult> {\n const staging = await mkdtemp(join(tmpdir(), \"lmnr-skill-\"));\n try {\n try {\n await downloadSkill(staging);\n } catch (err) {\n process.stderr.write(\n `Warning: could not fetch the Laminar skill (${skillSource()}): ` +\n `${describeError(err)}; skipping skill install.\\n`,\n );\n return { written: [], defaulted: false, skipped: true };\n }\n\n // Files relative to the staging root (e.g. \"SKILL.md\", \"references/x.md\").\n const relFiles = (await readdir(staging, { recursive: true, withFileTypes: true }))\n .filter((d) => d.isFile())\n .map((d) => relative(staging, join(d.parentPath, d.name)));\n\n const present: string[] = [];\n for (const dir of AGENT_DIRS) {\n if (await dirExists(join(cwd, dir))) present.push(dir);\n }\n\n const targets = present.length > 0 ? present : DEFAULT_AGENT_DIRS;\n const written: string[] = [];\n for (const dir of targets) {\n const skillRoot = join(cwd, dir, \"skills\", SKILL_NAME);\n // Replace, don't merge: `cp` alone would leave behind files that were\n // deleted upstream (e.g. a removed reference doc) from a prior install.\n await rm(skillRoot, { recursive: true, force: true });\n await mkdir(skillRoot, { recursive: true });\n await cp(staging, skillRoot, { recursive: true });\n for (const rel of relFiles) written.push(join(skillRoot, rel));\n }\n\n return { written, defaulted: present.length === 0, skipped: false };\n } finally {\n await rm(staging, { recursive: true, force: true });\n }\n}\n\nasync function dirExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction describeError(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n","import { hostname } from \"node:os\";\nimport { relative } from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\n\nimport { type CliProject, LaminarClient } from \"@lmnr-ai/client\";\n\nimport { version } from \"../../../package.json\";\nimport { type Credentials, readCredentials } from \"../../auth/credentials\";\nimport { probeProjectKey } from \"../../auth/project-id\";\nimport { envHttpPort, refreshIfNeeded } from \"../../auth/resolve\";\nimport { orange, pc, pcOut } from \"../../utils/colors\";\nimport {\n findEnvKey,\n isPathGitIgnored,\n resolveEnvWriteTarget,\n writeEnvFile,\n} from \"../../utils/env-file\";\nimport { installSkill } from \"../../utils/install-skill\";\nimport { type ProjectLink, readProjectLink, writeProjectLink } from \"../../utils/project-link\";\nimport { handleLogin } from \"../login\";\n\nconst DEFAULT_FRONTEND_URL = \"https://laminar.sh\";\nconst DEFAULT_BASE_URL = \"https://api.lmnr.ai\";\n\n// Exit codes (machine-readable contract — each distinct so automation can\n// branch on the failure mode):\n// 4 no_access — user lacks access to the linked project\n// 6 login_failed — device-flow login failed / no creds after login\n// 7 no_project — no project to select (and none could be created)\n// 8 env_write_failed — minted a key but couldn't write ./.env\n// 9 setup_key_failed — POST /api/cli/api-key failed\n// 10 list_projects_failed — GET /v1/cli/projects (discovery) failed\n// 11 key_probe_failed — couldn't verify the existing key (network/server error)\n// 12 key_mismatch — existing key belongs to a different project\nconst EXIT_NO_ACCESS = 4;\nconst EXIT_LOGIN_FAILED = 6;\nconst EXIT_NO_PROJECT = 7;\nconst EXIT_ENV_WRITE_FAILED = 8;\nconst EXIT_SETUP_KEY_FAILED = 9;\nconst EXIT_LIST_PROJECTS_FAILED = 10;\nconst EXIT_KEY_PROBE_FAILED = 11;\nconst EXIT_KEY_MISMATCH = 12;\n\nexport interface SetupOptions {\n writeEnv?: boolean;\n json?: boolean;\n noBrowser?: boolean;\n frontendUrl?: string;\n baseUrl?: string;\n /**\n * Explicit project id. Disambiguates when the user can access >1 project\n * (otherwise --json setup errors `project_ambiguous`). Validated against the\n * user's accessible projects before linking.\n */\n projectId?: string;\n}\n\ninterface SetupKeyResponse {\n apiKey: string;\n apiKeyId: string;\n projectId: string;\n projectName: string;\n workspaceId: string;\n workspaceName: string;\n}\n\nexport interface SetupResult {\n projectId: string;\n projectName: string | null;\n workspaceId: string | null;\n workspaceName: string | null;\n /** The key written to .env, or null when an existing matching key was reused. */\n apiKey: string | null;\n envFileUpdated: string | null;\n /** SKILL.md paths written by the skill installer. */\n skillsInstalled: string[];\n frontendUrl: string;\n userEmail: string | null;\n}\n\n/**\n * Directory-scoped onboarding (SPEC decision tree):\n * - log in if needed (browser picks/creates the project; its id rides back on\n * the device-token metadata, see parseProjectFromMetadata),\n * - resolve a project for this directory (`.lmnr/project.json`), enforcing\n * access,\n * - mint a project API key only when one isn't already configured for this\n * project (checked across process.env → .env.local → .env), then write it to\n * an existing .env.local or else .env,\n * - install the Laminar skill into present agent dirs,\n * - print a summary.\n *\n * The minted key goes ONLY into the project's env file, never into\n * credentials.json (which stores user-scoped BetterAuth tokens).\n */\nexport async function handleSetup(options: SetupOptions): Promise<void> {\n const writeEnv = options.writeEnv !== false;\n const frontendUrl = pick(\n options.frontendUrl,\n process.env.LMNR_FRONTEND_URL,\n DEFAULT_FRONTEND_URL,\n );\n const baseUrl = pick(options.baseUrl, process.env.LMNR_BASE_URL, DEFAULT_BASE_URL);\n const isJson = options.json === true;\n\n if (!isJson) {\n process.stderr.write(`\\n${orange(\"Laminar CLI\")} ${pc.dim(`v${version}`)}\\n\\n`);\n }\n\n const cwd = process.cwd();\n // Detect an already-configured key across process.env → .env.local → .env.\n const existingKey = await findEnvKey(cwd);\n\n let creds: Credentials | null = await safeReadCredentials();\n let link = await readProjectLink();\n\n // --- 1. Login + project resolution ---------------------------------------\n\n if (!creds) {\n // Not logged in: run the device flow. The browser is where the project is\n // chosen/created (when there's no link), and the chosen id rides back on\n // the device-token metadata (parseProjectFromMetadata).\n let login;\n try {\n login = await handleLogin({ frontendUrl, noBrowser: options.noBrowser });\n } catch (err) {\n emitError(isJson, \"login_failed\", describeError(err));\n process.exit(EXIT_LOGIN_FAILED);\n }\n creds = await safeReadCredentials();\n if (!creds) {\n emitError(isJson, \"login_failed\", \"credentials missing after login\");\n process.exit(EXIT_LOGIN_FAILED);\n }\n\n const issuer = creds.issuer || frontendUrl;\n const userBaseUrl = baseUrl;\n\n if (link) {\n // Directory already declares the project — ignore the metadata-borne id\n // and assert the freshly-authenticated user can access the linked project.\n await assertAccess(creds, userBaseUrl, link.projectId, isJson);\n } else if (login.projectId) {\n // Browser-selected (or just-created) project. Trust it and write the link.\n link = await writeLink(issuer, userBaseUrl, login.projectId, isJson);\n } else {\n // Defensive: fall back to the CLI picker if the browser didn't attach a\n // project via metadata.\n link = await resolveProjectViaCli(creds, userBaseUrl, issuer, isJson, options);\n }\n } else {\n // Already logged in.\n const userBaseUrl = baseUrl;\n const issuer = creds.issuer || frontendUrl;\n if (link) {\n await assertAccess(creds, userBaseUrl, link.projectId, isJson);\n } else {\n link = await resolveProjectViaCli(creds, userBaseUrl, issuer, isJson, options);\n }\n }\n\n if (!isJson) {\n process.stderr.write(`${pc.green(\"✓\")} Logged in as ${creds.userEmail ?? \"<unknown>\"}\\n`);\n process.stderr.write(\n `${pc.green(\"✓\")} Project: ${link.projectName ?? link.projectId}` +\n (link.workspaceName ? pc.dim(` (${link.workspaceName})`) : \"\") +\n \"\\n\",\n );\n }\n\n // --- 2. Assert invariants -------------------------------------------------\n\n if (!creds || !link.projectId) {\n emitError(isJson, \"setup_invariant\", \"missing credentials or project after resolution\");\n process.exit(EXIT_NO_PROJECT);\n }\n\n const issuer = creds.issuer || frontendUrl;\n const userBaseUrl = baseUrl;\n\n // --- 3. Key handling (SPEC 36-42) -----------------------------------------\n\n let apiKey: string | null = null;\n let envPath: string | null = null;\n let keyMeta: SetupKeyResponse | null = null;\n\n let needMint = true;\n if (existingKey) {\n const probe = await probeProjectKey(existingKey.value, userBaseUrl, envHttpPort());\n const where =\n existingKey.source.type === \"process-env\"\n ? \"your environment\"\n : relative(cwd, existingKey.source.path);\n\n if (probe.status === \"unverifiable\") {\n // Couldn't verify the key (network/server error). Do NOT mint — that would\n // clobber a possibly-valid key on a transient blip. Abort so the user retries.\n emitError(\n isJson,\n \"key_probe_failed\",\n `Couldn't verify the existing Project API Key in ${where} (network or server error). ` +\n \"Check your connection and re-run.\",\n );\n process.exit(EXIT_KEY_PROBE_FAILED);\n } else if (probe.status === \"ok\" && probe.projectId === link.projectId) {\n // Already configured for this project. Respect the user's setup: no mint,\n // no write (option a) — including when the key only lives in process.env.\n needMint = false;\n if (!isJson) {\n process.stderr.write(`${pc.green(\"✓\")} Project API Key already set in ${where}\\n`);\n }\n } else if (probe.status === \"ok\") {\n // Valid key, but for a DIFFERENT project. Refuse to clobber it — abort so the\n // user resolves the conflict deliberately rather than silently overwriting.\n emitError(\n isJson,\n \"key_mismatch\",\n `The Project API Key in ${where} belongs to a different project (${probe.projectId}), ` +\n `not the one linked here (${link.projectId}). Remove or update it, then re-run.`,\n );\n process.exit(EXIT_KEY_MISMATCH);\n } else if (!isJson) {\n // invalid / revoked (401) — minting a fresh key is the correct recovery.\n process.stderr.write(\n `${pc.yellow(\"⚠\")} Existing Project API Key in ${where} is invalid or revoked, ` +\n `minting a new one\\n`,\n );\n }\n }\n\n if (needMint) {\n try {\n keyMeta = await mintSetupKey(issuer, creds.sessionToken, link.projectId);\n } catch (err) {\n emitError(isJson, \"setup_key_failed\", describeError(err));\n process.exit(EXIT_SETUP_KEY_FAILED);\n }\n apiKey = keyMeta.apiKey;\n\n // Backfill display details onto the link if we learned them while minting.\n if (!link.projectName && keyMeta.projectName) link.projectName = keyMeta.projectName;\n if (!link.workspaceName && keyMeta.workspaceName) link.workspaceName = keyMeta.workspaceName;\n if (!link.workspaceId && keyMeta.workspaceId) link.workspaceId = keyMeta.workspaceId;\n\n if (writeEnv) {\n const target = await resolveEnvWriteTarget(cwd, existingKey);\n try {\n const result = await writeEnvFile(target, apiKey);\n envPath = result.path;\n if (!isJson) {\n const rel = relative(cwd, result.path);\n const verb = result.created\n ? \"Created\"\n : result.replaced\n ? \"Updated LMNR_PROJECT_API_KEY in\"\n : \"Added LMNR_PROJECT_API_KEY to\";\n process.stderr.write(`${pc.green(\"✓\")} ${verb} ${rel}\\n`);\n // The key is a secret; nudge if it landed in a tracked file.\n if ((await isPathGitIgnored(result.path)) === false) {\n process.stderr.write(\n `${pc.yellow(\"⚠\")} ${rel} isn't gitignored; add it so the key isn't committed\\n`,\n );\n }\n }\n } catch (err) {\n process.stderr.write(\n `\\n${pc.red(\"ERROR\")}: failed to write ${target}: ${describeError(err)}\\n` +\n pc.dim(\"Your API key (set it manually):\") +\n `\\n LMNR_PROJECT_API_KEY=${apiKey}\\n\\n`,\n );\n if (isJson) {\n process.stdout.write(\n JSON.stringify({\n error: \"env_write_failed\",\n apiKey,\n projectId: link.projectId,\n message: describeError(err),\n }) + \"\\n\",\n );\n }\n process.exit(EXIT_ENV_WRITE_FAILED);\n }\n }\n }\n\n // --- 4. Skill install -----------------------------------------------------\n\n let skillsInstalled: string[] = [];\n try {\n // installSkill fetches the skill from the lmnr-skills repo and is\n // best-effort: it logs + returns `skipped: true` on network/codeload\n // failure rather than throwing, so setup never breaks here.\n const skillResult = await installSkill(process.cwd());\n skillsInstalled = skillResult.written;\n if (!isJson) {\n if (skillResult.skipped) {\n process.stderr.write(pc.dim(\" Laminar skill install skipped\\n\"));\n } else if (skillResult.written.length > 0) {\n // One mark for the whole skill, not one per file (SKILL.md + references).\n const note = skillResult.defaulted\n ? pc.dim(\" (no agent dir found; defaulted to .claude and .agents)\")\n : \"\";\n process.stderr.write(`${pc.green(\"✓\")} Installed Laminar skill${note}\\n`);\n }\n }\n } catch (err) {\n if (!isJson) {\n process.stderr.write(\n `${pc.yellow(\"Warning\")}: could not install Laminar skill (${describeError(err)}).\\n`,\n );\n }\n }\n\n // --- 5. Summary -----------------------------------------------------------\n\n const frontendLink = `${trimSlash(issuer)}/project/${link.projectId}/traces`;\n\n const result: SetupResult = {\n projectId: link.projectId,\n projectName: link.projectName ?? null,\n workspaceId: link.workspaceId ?? null,\n workspaceName: link.workspaceName ?? null,\n apiKey,\n envFileUpdated: envPath,\n skillsInstalled,\n frontendUrl: frontendLink,\n userEmail: creds.userEmail ?? null,\n };\n\n if (isJson) {\n process.stdout.write(JSON.stringify(result) + \"\\n\");\n } else {\n const docsUrl = \"https://laminar.sh/docs/tracing/integrations/overview\";\n const verifyCmd =\n 'lmnr-cli sql query \"SELECT * FROM traces ORDER BY start_time DESC LIMIT 1\" --json';\n process.stdout.write(\n \"\\nNext steps:\\n\" +\n \" 1. Instrument your project with Laminar using the installed skill or the docs:\\n\" +\n ` ${pcOut.cyan(docsUrl)}\\n` +\n \" 2. Run your project.\\n\" +\n \" 3. Verify instrumentation:\\n\" +\n ` ${pcOut.green(verifyCmd)}\\n` +\n \" 4. View your traces in the browser:\\n\" +\n ` ${pcOut.cyan(frontendLink)}\\n`,\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Project resolution helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a project via the CLI (logged-in, no link). 0 projects routes to the\n * browser create flow (gap A): we re-run the device flow, which lands on the\n * /device picker → first-project create UI, and the new project's id rides back\n * on the device-token metadata. >1 prompts a CLI choice; ==1 auto-selects.\n */\nasync function resolveProjectViaCli(\n creds: Credentials,\n userBaseUrl: string,\n issuer: string,\n isJson: boolean,\n options: SetupOptions,\n): Promise<ProjectLink> {\n let projects: CliProject[];\n try {\n projects = await listProjects(creds, userBaseUrl);\n } catch (err) {\n emitError(isJson, \"list_projects_failed\", describeError(err));\n process.exit(EXIT_LIST_PROJECTS_FAILED);\n }\n\n if (projects.length === 0) {\n // Gap A: no project to select and the CLI can't create one. Drive the\n // browser create flow — same path the not-logged-in 0-project user takes —\n // so project creation lives in ONE place (the /device picker).\n if (isJson) {\n emitError(\n isJson,\n \"no_projects\",\n `No projects found. Run \\`lmnr-cli setup\\` interactively (it opens the browser ` +\n `to create your first project) or create one at ${trimSlash(issuer)}/onboarding.`,\n );\n process.exit(EXIT_NO_PROJECT);\n }\n process.stderr.write(\n \"\\nYou have no projects yet. Opening the browser to create your first one...\\n\",\n );\n let login;\n try {\n login = await handleLogin({\n frontendUrl: issuer,\n noBrowser: options.noBrowser,\n });\n } catch (err) {\n emitError(isJson, \"login_failed\", describeError(err));\n process.exit(EXIT_LOGIN_FAILED);\n }\n if (!login.projectId) {\n emitError(\n isJson,\n \"no_projects\",\n `No project was created. Create one at ${trimSlash(issuer)}/onboarding then re-run setup.`,\n );\n process.exit(EXIT_NO_PROJECT);\n }\n return writeLink(issuer, userBaseUrl, login.projectId, isJson);\n }\n\n let chosen: CliProject;\n if (options.projectId) {\n // Explicit --project-id disambiguates. Validate against the accessible set.\n const match = projects.find((p) => p.id === options.projectId);\n if (!match) {\n emitError(\n isJson,\n \"no_access\",\n `You don't have access to project ${options.projectId}. Accessible: ` +\n projects.map((p) => `${p.id} (${p.workspaceName}/${p.name})`).join(\", \"),\n );\n process.exit(EXIT_NO_ACCESS);\n }\n chosen = match;\n } else if (projects.length === 1) {\n chosen = projects[0];\n } else {\n if (isJson) {\n emitError(\n isJson,\n \"project_ambiguous\",\n `Multiple projects: pass --project-id <id>, or run setup interactively. ` +\n projects.map((p) => `${p.id} (${p.workspaceName}/${p.name})`).join(\", \"),\n );\n process.exit(EXIT_NO_PROJECT);\n }\n chosen = await promptProjectChoice(projects);\n }\n\n const linkPath = await writeProjectLink({\n projectId: chosen.id,\n projectName: chosen.name,\n workspaceId: chosen.workspaceId,\n workspaceName: chosen.workspaceName,\n });\n if (!isJson) process.stderr.write(`${pc.green(\"✓\")} Linked ${linkPath}\\n`);\n return {\n projectId: chosen.id,\n projectName: chosen.name,\n workspaceId: chosen.workspaceId,\n workspaceName: chosen.workspaceName,\n };\n}\n\n/** Write `.lmnr/project.json`, enriching display details from listProjects when possible. */\nasync function writeLink(\n issuer: string,\n userBaseUrl: string,\n projectId: string,\n isJson: boolean,\n): Promise<ProjectLink> {\n let link: ProjectLink = { projectId };\n try {\n const creds = await safeReadCredentials();\n if (creds) {\n const projects = await listProjects(creds, userBaseUrl);\n const match = projects.find((p) => p.id === projectId);\n if (match) {\n link = {\n projectId,\n projectName: match.name,\n workspaceId: match.workspaceId,\n workspaceName: match.workspaceName,\n };\n }\n }\n } catch {\n // Best-effort enrichment — the id is enough to proceed.\n }\n try {\n const linkPath = await writeProjectLink(link);\n if (!isJson) process.stderr.write(`${pc.green(\"✓\")} Linked ${linkPath}\\n`);\n } catch (err) {\n if (!isJson) {\n process.stderr.write(\n `${pc.yellow(\"Warning\")}: could not write .lmnr/project.json (${describeError(err)}). ` +\n `CLI commands will need --project-id ${projectId}.\\n`,\n );\n }\n }\n return link;\n}\n\n/**\n * Access check: the user must be a member of `projectId`. Calls\n * GET /v1/cli/projects (user JWT) and asserts the id is present; aborts\n * otherwise (SPEC: \"You don't have access to the project in this directory\").\n */\nasync function assertAccess(\n creds: Credentials,\n userBaseUrl: string,\n projectId: string,\n isJson: boolean,\n): Promise<void> {\n let projects: CliProject[];\n try {\n projects = await listProjects(creds, userBaseUrl);\n } catch (err) {\n // Discovery FAILED (network/5xx) — we couldn't determine access. Report it\n // as a transient list failure (exit 10), NOT no_access (exit 4): automation\n // must be able to retry instead of concluding the user lacks access.\n emitError(isJson, \"list_projects_failed\", describeError(err));\n process.exit(EXIT_LIST_PROJECTS_FAILED);\n }\n if (!projects.some((p) => p.id === projectId)) {\n emitError(\n isJson,\n \"no_access\",\n \"You don't have access to the project in this directory\",\n );\n process.exit(EXIT_NO_ACCESS);\n }\n}\n\n/** List the projects the user can access (user-JWT-authed discovery). */\nasync function listProjects(creds: Credentials, baseUrl: string): Promise<CliProject[]> {\n const updated = await refreshIfNeeded(creds);\n // Discovery client: CliResource hits /v1/cli/projects with the bare bearer,\n // no project id needed (it overrides BaseResource's headers/prefix).\n const client = new LaminarClient({\n baseUrl,\n // setup has no --port flag, so honor LMNR_HTTP_PORT for local self-host\n // (baseUrl carries no port by convention). Cloud falls back to 443.\n port: envHttpPort(),\n auth: { type: \"userToken\", token: updated.accessToken, projectId: \"\" },\n });\n return client.cli.listProjects();\n}\n\nasync function safeReadCredentials(): Promise<Credentials | null> {\n try {\n return await readCredentials();\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Key minting\n// ---------------------------------------------------------------------------\n\n/** POST /api/cli/api-key with the session bearer for an explicit project. */\nasync function mintSetupKey(\n issuer: string,\n sessionToken: string,\n projectId: string,\n): Promise<SetupKeyResponse> {\n const url = `${trimSlash(issuer)}/api/cli/api-key`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { authorization: `Bearer ${sessionToken}`, \"content-type\": \"application/json\" },\n body: JSON.stringify({ deviceName: hostname(), projectId }),\n });\n if (res.ok) {\n return (await res.json()) as SetupKeyResponse;\n }\n const body = (await res.json().catch(() => ({}))) as { error?: string };\n throw new Error(body.error ?? `api-key request failed (${res.status})`);\n}\n\nasync function promptProjectChoice(projects: CliProject[]): Promise<CliProject> {\n process.stderr.write(\"\\nMultiple projects available. Choose one:\\n\");\n projects.forEach((p, i) => {\n process.stderr.write(` ${i + 1}) ${p.workspaceName} / ${p.name}\\n`);\n });\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n try {\n while (true) {\n const answer = (await rl.question(`Select [1-${projects.length}]: `)).trim();\n const idx = Number.parseInt(answer, 10);\n if (Number.isInteger(idx) && idx >= 1 && idx <= projects.length) {\n return projects[idx - 1];\n }\n process.stderr.write(`${pc.red(\"Invalid selection.\")}\\n`);\n }\n } finally {\n rl.close();\n }\n}\n\nfunction pick(...candidates: (string | undefined)[]): string {\n for (const c of candidates) {\n if (c && c.length > 0) return c;\n }\n return \"\";\n}\n\nfunction trimSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nfunction describeError(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\nfunction emitError(json: boolean, code: string, detail: string): void {\n if (json) {\n process.stdout.write(JSON.stringify({ error: code, detail }) + \"\\n\");\n } else {\n process.stderr.write(`\\n${pc.red(`ERROR (${code})`)}: ${detail}\\n`);\n }\n}\n","import { LaminarClient } from \"@lmnr-ai/client\";\n\nimport type { GlobalOpts } from \"../../auth/with-client\";\nimport { outputJson } from \"../../utils/output\";\nimport { renderTable } from \"../../utils/table\";\n\n/**\n * Run a SQL query against the project's data and print the rows. Pure handler:\n * the command wrapper (`withProjectClient`) resolves the client and owns the\n * error envelope (`--json` → structured error + exit, otherwise log + exit).\n */\nexport const handleSqlQuery = async (\n client: LaminarClient,\n query: string,\n opts: GlobalOpts,\n): Promise<void> => {\n const rows = await client.sql.query(query);\n\n if (opts.json) {\n outputJson(rows);\n return;\n }\n\n if (rows.length === 0) {\n console.log(\"No rows returned.\");\n return;\n }\n\n const columns = Object.keys(rows[0]);\n const tableRows = rows.map((row) =>\n columns.map((col) => String(row[col] ?? \"\")),\n );\n\n console.log(renderTable(columns, tableRows));\n console.log(`\\n${rows.length} row(s)\\n`);\n};\n","export const SQL_SCHEMA_HELP = `\nAvailable tables:\n spans\n span_id (UUID), name (String), span_type (String: DEFAULT|LLM|TOOL),\n start_time (DateTime64), end_time (DateTime64), duration (Float64),\n input_cost (Float64), output_cost (Float64), total_cost (Float64),\n input_tokens (Int64), output_tokens (Int64), total_tokens (Int64),\n request_model (String), response_model (String), model (String),\n trace_id (UUID), provider (String), path (String),\n input (String), output (String), status (String),\n parent_span_id (UUID), attributes (String), tags (Array(String))\n\n traces\n id (UUID), start_time (DateTime64), end_time (DateTime64),\n input_tokens (Int64), output_tokens (Int64), total_tokens (Int64),\n input_cost (Float64), output_cost (Float64), total_cost (Float64),\n duration (Float64), metadata (String), session_id (String),\n user_id (String), status (String), top_span_id (UUID),\n top_span_name (String), top_span_type (String), trace_type (String),\n tags (Array(String)), has_browser_session (Bool)\n\n events\n id (UUID), type (String), name (String), span_id (UUID),\n timestamp (DateTime64), attributes (String)\n\n signal_events\n id (UUID), signal_id (UUID), trace_id (UUID), run_id (UUID),\n name (String), payload (String), timestamp (DateTime64)\n\n signal_runs\n signal_id (UUID), job_id (UUID), trigger_id (UUID), run_id (UUID),\n trace_id (UUID), status (String), event_id (UUID), updated_at (DateTime64)\n\n evaluation_datapoints\n id (UUID), evaluation_id (UUID), data (String), target (String),\n metadata (String), executor_output (String), index (UInt64),\n trace_id (UUID), group_id (String), scores (String),\n created_at (DateTime64), dataset_id (UUID),\n dataset_datapoint_id (UUID), dataset_datapoint_created_at (DateTime64)\n\n dataset_datapoints\n id (UUID), created_at (DateTime64), dataset_id (UUID),\n data (String), target (String), metadata (String)\n`;\n","import { LaminarClient } from \"@lmnr-ai/client\";\n\nimport type { GlobalOpts } from \"../../auth/with-client\";\nimport { initializeLogger } from \"../../utils/logger\";\nimport { outputJson } from \"../../utils/output\";\nimport {\n normalizeTraceId,\n NOTE_METADATA_KEY,\n readNoteFromMetadata,\n} from \"../../utils/trace-note\";\n\nconst logger = initializeLogger();\n\n// Separator between appended note entries. The note is rendered as markdown,\n// so a blank line keeps each appended entry its own paragraph.\nconst NOTE_SEPARATOR = \"\\n\\n\";\n\n/**\n * Append a free-text note to an existing trace. Stored under the\n * `rollout.note` trace-metadata key via the post-factum metadata patch\n * endpoint. The patch endpoint is last-write-wins per key, so the current\n * note is read back first (via the SQL endpoint) and the new text is pushed\n * as `existing + \"\\n\\n\" + note`. The note may contain markdown /\n * span-reference links.\n *\n * Pure handler: the command wrapper (`withProjectClient`) resolves a user-token\n * {@link LaminarClient} (routes to `/v1/cli/*` with the resolved project) and\n * owns the error envelope (`--json` → structured error + exit, else log + exit).\n *\n * The read-modify-write is not transactional: the patch lands via the async\n * ingestion queue, so a second append issued within ~a second of the first\n * can read the pre-patch note and drop the first append. Fine for the\n * intended cadence (one note per investigation step), not for concurrent\n * writers.\n *\n * TODO: revisit — make the append atomic server-side (e.g. an append mode on\n * the metadata patch endpoint that concatenates within the Postgres UPDATE,\n * which already serializes on the trace row lock).\n */\nexport const handleTraceAppendNote = async (\n client: LaminarClient,\n traceId: string,\n note: string,\n opts: GlobalOpts,\n): Promise<void> => {\n const id = normalizeTraceId(traceId);\n\n const rows = await client.sql.query(\n \"SELECT metadata FROM traces WHERE id = {trace_id:UUID} LIMIT 1\",\n { trace_id: id },\n );\n if (rows.length === 0) {\n throw new Error(\n `Trace ${id} not found. If the run just finished, the trace may not ` +\n \"be flushed yet. Retry in a few seconds.\",\n );\n }\n\n const existing = readNoteFromMetadata(rows[0].metadata);\n const updated = existing ? `${existing}${NOTE_SEPARATOR}${note}` : note;\n // failOnNotFound: the SQL pre-read can race a trace deletion, and a CLI\n // exit 0 must mean the note actually landed.\n await client.traces.pushMetadata(\n id,\n { [NOTE_METADATA_KEY]: updated },\n { failOnNotFound: true },\n );\n\n if (opts.json) {\n outputJson({ traceId: id, note: updated });\n return;\n }\n\n logger.info(`Appended note to trace ${id}.`);\n};\n","#!/usr/bin/env node\n\nimport { errorMessage } from \"@lmnr-ai/types\";\nimport { Command } from \"commander\";\n\nimport { version } from \"../package.json\";\nimport { withProjectClient, withUserToken } from \"./auth/with-client\";\nimport {\n handleDatasetsCreate,\n handleDatasetsList,\n handleDatasetsPull,\n handleDatasetsPush,\n} from \"./commands/dataset\";\nimport { handleDebugSessionSetName, handleDebugSessionSummary } from \"./commands/debug\";\nimport { handleLogin } from \"./commands/login\";\nimport { handleLogout } from \"./commands/logout\";\nimport { handleProjectsList } from \"./commands/project\";\nimport { handleSetup } from \"./commands/setup\";\nimport { handleSqlQuery } from \"./commands/sql\";\nimport { SQL_SCHEMA_HELP } from \"./commands/sql/schema\";\nimport { handleTraceAppendNote } from \"./commands/trace\";\nimport { pc } from \"./utils/colors\";\nimport { loadLocalEnv } from \"./utils/env-file\";\n\nasync function main() {\n // Hydrate LMNR_* config from a project .env(.local) before anything reads it\n // (login/setup/resolve read process.env at command-execution time, which is\n // after this). Runners like Claude Code don't inject .env into the subprocess\n // env, so this is how a local self-host config gets picked up.\n await loadLocalEnv(process.cwd());\n\n const program = new Command();\n\n program\n .name(\"lmnr-cli\")\n .description(\"CLI for the Laminar agent observability platform\")\n .version(version, \"-v, --version\", \"display version number\");\n\n const datasetsCmd = program\n .command(\"dataset\")\n .description(\"Manage datasets\")\n .option(\n \"--project-id <id>\",\n \"Target project id. Defaults to the linked .lmnr/project.json. \" +\n \"Run `lmnr-cli login` first.\",\n )\n .option(\n \"--base-url <url>\",\n \"Base URL for the Laminar API. Defaults to https://api.lmnr.ai or LMNR_BASE_URL env variable\",\n )\n .option(\n \"--port <port>\",\n \"Port for the Laminar API. Defaults to 443\",\n (val) => parseInt(val, 10),\n )\n .option(\"--json\", \"Output structured JSON to stdout\");\n\n // Datasets list command\n datasetsCmd\n .command(\"list\")\n .description(\"List all datasets\")\n .action(withProjectClient(handleDatasetsList));\n\n // Datasets push command\n datasetsCmd\n .command(\"push\")\n .description(\"Push datapoints to an existing dataset\")\n .argument(\n \"<paths...>\",\n \"Paths to files or directories containing data to push\",\n )\n .option(\n \"-n, --name <name>\",\n \"Name of the dataset (either name or id must be provided)\",\n )\n .option(\n \"--id <id>\",\n \"ID of the dataset (either name or id must be provided)\",\n )\n .option(\"-r, --recursive\", \"Recursively read files in directories\", false)\n .option(\n \"--batch-size <size>\",\n \"Batch size for pushing data\",\n (val) => parseInt(val, 10),\n 100,\n )\n .action(withProjectClient(handleDatasetsPush));\n\n // Datasets pull command\n datasetsCmd\n .command(\"pull\")\n .description(\"Pull data from a dataset\")\n .argument(\n \"[output-path]\",\n \"Path to save the data. If not provided, prints to console\",\n )\n .option(\n \"-n, --name <name>\",\n \"Name of the dataset (either name or id must be provided)\",\n )\n .option(\n \"--id <id>\",\n \"ID of the dataset (either name or id must be provided)\",\n )\n .option(\n \"--output-format <format>\",\n \"Output format (json, csv, jsonl). Inferred from file extension if not provided\",\n )\n .option(\n \"--batch-size <size>\",\n \"Batch size for pulling data\",\n (val) => parseInt(val, 10),\n 100,\n )\n .option(\"--limit <limit>\", \"Limit number of datapoints to pull\", (val) =>\n parseInt(val, 10),\n )\n .option(\n \"--offset <offset>\",\n \"Offset for pagination\",\n (val) => parseInt(val, 10),\n 0,\n )\n .action(withProjectClient(handleDatasetsPull));\n\n // Datasets create command\n datasetsCmd\n .command(\"create\")\n .description(\"Create a dataset from input files\")\n .argument(\"<name>\", \"Name of the dataset to create\")\n .argument(\n \"<paths...>\",\n \"Paths to files or directories containing data to push\",\n )\n .requiredOption(\"-o, --output-file <file>\", \"Path to save the pulled data\")\n .option(\n \"--output-format <format>\",\n \"Output format (json, csv, jsonl). Inferred from file extension if not provided\",\n )\n .option(\"-r, --recursive\", \"Recursively read files in directories\", false)\n .option(\n \"--batch-size <size>\",\n \"Batch size for pushing/pulling data\",\n (val) => parseInt(val, 10),\n 100,\n )\n .action(withProjectClient(handleDatasetsCreate));\n\n const sqlCmd = program\n .command(\"sql\")\n .description(\"Run SQL queries against your Laminar project data\")\n .option(\n \"--project-id <id>\",\n \"Target project id. Defaults to the linked .lmnr/project.json. \" +\n \"Run `lmnr-cli login` first.\",\n )\n .option(\n \"--base-url <url>\",\n \"Base URL for the Laminar API. Defaults to https://api.lmnr.ai or LMNR_BASE_URL env variable\",\n )\n .option(\n \"--port <port>\",\n \"Port for the Laminar API. Defaults to 443\",\n (val) => parseInt(val, 10),\n )\n .option(\"--json\", \"Output structured JSON to stdout\");\n\n sqlCmd\n .command(\"query\")\n .description(\"Execute a SQL query\")\n .argument(\"<query>\", \"SQL query string\")\n .action(withProjectClient(handleSqlQuery))\n .addHelpText(\n \"after\",\n SQL_SCHEMA_HELP +\n `\nExamples:\n $ lmnr-cli sql query \"SELECT * FROM spans LIMIT 10\"\n $ lmnr-cli sql query \"SELECT id, total_cost, status FROM traces LIMIT 20\"\n $ lmnr-cli sql query \"SELECT * FROM spans LIMIT 10\" --json\n`,\n );\n\n sqlCmd\n .command(\"schema\")\n .description(\"Show available tables and their columns\")\n .action(() => {\n process.stdout.write(SQL_SCHEMA_HELP);\n });\n\n const projectCmd = program.command(\"project\").description(\"Work with Laminar projects\");\n\n projectCmd\n .command(\"list\")\n .description(\"List the projects you can access (● = linked to this directory)\")\n .option(\n \"--base-url <url>\",\n \"Base URL for the Laminar API. Defaults to the logged-in session or LMNR_BASE_URL\",\n )\n .option(\n \"--port <port>\",\n \"Port for the Laminar API. Defaults to 443\",\n (val) => parseInt(val, 10),\n )\n .option(\"--json\", \"Output structured JSON to stdout\")\n .action(withUserToken(handleProjectsList));\n\n program\n .command(\"login\")\n .description(\"Authenticate the CLI via OAuth Device Flow\")\n .option(\n \"--frontend-url <url>\",\n \"Frontend URL (issuer). Defaults to https://laminar.sh or LMNR_FRONTEND_URL env variable\",\n )\n .option(\"--no-browser\", \"Do not open the verification URL in a browser\")\n .action(async (options) => {\n const result = await handleLogin(options);\n process.stderr.write(`${pc.green(\"✓\")} Logged in as ${result.userEmail ?? \"<unknown>\"}.\\n`);\n process.stderr.write(\n pc.dim(\"Client: lmnr-cli. Tokens stored at ~/.config/lmnr/credentials.json (mode 0600).\\n\"),\n );\n process.stderr.write(\n pc.dim(\"Run `lmnr-cli setup` in a project directory to link it and write its API key.\\n\"),\n );\n });\n\n program\n .command(\"logout\")\n .description(\"Log out and remove the stored credentials\")\n .action(async () => {\n await handleLogout();\n });\n\n program\n .command(\"setup\")\n .description(\n \"One-shot onboarding: login, select a project, write its key to .env, \" +\n \"link .lmnr, and install the Laminar agent skill\",\n )\n .option(\"--write-env\", \"Write LMNR_PROJECT_API_KEY to ./.env (default)\", true)\n .option(\"--no-write-env\", \"Do not write to ./.env\")\n .option(\n \"--project-id <id>\",\n \"Project to link when you can access more than one (disambiguates the \" +\n \"project_ambiguous case in --json mode)\",\n )\n .option(\"--json\", \"Emit a machine-readable JSON line on stdout\")\n .option(\"--no-browser\", \"Do not auto-open the device-flow URL\")\n .option(\n \"--frontend-url <url>\",\n \"Frontend URL (issuer). Defaults to LMNR_FRONTEND_URL or https://laminar.sh\",\n )\n .option(\n \"--base-url <url>\",\n \"Base URL for the Laminar API. Defaults to LMNR_BASE_URL or https://api.lmnr.ai\",\n )\n .action(async (options) => {\n await handleSetup(options);\n });\n\n const traceCmd = program\n .command(\"trace\")\n .description(\"Inspect and operate on traces\")\n .option(\n \"--project-id <id>\",\n \"Target project id. Defaults to the linked .lmnr/project.json. \" +\n \"Run `lmnr-cli login` first.\",\n )\n .option(\n \"--base-url <url>\",\n \"Base URL for the Laminar API. Defaults to https://api.lmnr.ai or LMNR_BASE_URL env variable\",\n )\n .option(\n \"--port <port>\",\n \"Port for the Laminar API. Defaults to 443\",\n (val) => parseInt(val, 10),\n )\n .option(\"--json\", \"Output structured JSON to stdout\");\n\n traceCmd\n .command(\"append-note\")\n .description(\"Append a free-text note to a trace (stored in trace metadata)\")\n .argument(\"<trace-id>\", \"Trace ID (UUID or 32-char OTel hex trace id)\")\n .argument(\"<note>\", \"Note text (may contain markdown)\")\n .action(withProjectClient(handleTraceAppendNote))\n .addHelpText(\n \"after\",\n `\nNotes accumulate: each call appends a new paragraph to the trace's existing\nnote rather than overwriting it.\n\nExamples:\n $ lmnr-cli trace append-note <trace-id> \"Reproduced the timeout on the search tool.\"\n`,\n );\n\n const debugCmd = program\n .command(\"debug\")\n .description(\"Operate on debug sessions\")\n .option(\n \"--project-id <id>\",\n \"Target project id. Defaults to the linked .lmnr/project.json. \" +\n \"Run `lmnr-cli login` first.\",\n )\n .option(\n \"--base-url <url>\",\n \"Base URL for the Laminar API. Defaults to https://api.lmnr.ai or LMNR_BASE_URL env variable\",\n )\n .option(\n \"--port <port>\",\n \"Port for the Laminar API. Defaults to 443\",\n (val) => parseInt(val, 10),\n )\n .option(\"--json\", \"Output structured JSON to stdout\")\n .addHelpText(\n \"after\",\n `\nLearn more about debugging features at https://laminar.sh/docs/platform/debugger\n`,\n );\n\n const debugSessionCmd = debugCmd\n .command(\"session\")\n .description(\"Manage debug sessions\")\n .addHelpText(\n \"after\",\n `\nLearn more about debugging features at https://laminar.sh/docs/platform/debugger\n`,\n );\n\n debugSessionCmd\n .command(\"set-name\")\n .description(\"Set the display name of a debug session\")\n .argument(\"<session-id>\", \"Debug session ID\")\n .argument(\"<name>\", \"Session display name\")\n .action(withProjectClient(handleDebugSessionSetName))\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lmnr-cli debug session set-name <session-id> \"Fix report length + search tool\"\n`,\n );\n\n debugSessionCmd\n .command(\"summary\")\n .description(\"Print every trace in a debug session with its note, oldest first\")\n .argument(\"<session-id>\", \"Debug session ID\")\n .action(withProjectClient(handleDebugSessionSummary))\n .addHelpText(\n \"after\",\n `\nOutput is one block per trace (oldest first), the trace's note followed by a\nself-closing tag carrying the trace id and end time:\n\n {note}\n <trace id=\"{trace-id}\" end-time=\"{end-time}\"/>\n\nWith --json, prints an array of {\"note\", \"traceId\", \"endTime\"} objects.\n\nExamples:\n $ lmnr-cli debug session summary <session-id>\n $ lmnr-cli debug session summary <session-id> --json\n`,\n );\n\n program.addHelpText(\n \"after\",\n `\nAuthentication:\n Run \\`lmnr-cli setup\\` to login, link this directory, write a project API key to\n ./.env, and install the Laminar skill \n \\`lmnr-cli login\\` authenticates as a user. Every project command\n (sql / dataset / project / trace / debug) runs on that user session and\n targets a project via --project-id or the linked .lmnr/project.json.\n\nExamples:\n lmnr-cli setup # Logs in and prepares directory\n lmnr-cli login # Authenticate (user)\n lmnr-cli project list # Projects you can access\n lmnr-cli logout # Log out\n lmnr-cli dataset list --json # List all datasets\n lmnr-cli dataset push data.jsonl -n my-dataset --json # Push data to a dataset\n lmnr-cli dataset pull output.jsonl -n my-dataset --json # Pull data from a dataset\n lmnr-cli sql query \"SELECT * FROM spans LIMIT 10\" --json # Query spans\n lmnr-cli sql schema # Show available tables\n lmnr-cli trace append-note <trace-id> \"note text\" # Append a note to a trace\n lmnr-cli debug session set-name <session-id> \"title\" # Rename a debug session\n lmnr-cli debug session summary <session-id> # Notes for each trace in a session\n\nFor more information about the Laminar platfrom:\n Documentation: https://laminar.sh/docs\n`,\n );\n\n await program.parseAsync();\n}\n\nmain().catch((err) => {\n console.error(errorMessage(err));\n process.exit(1);\n});\n"],"x_google_ignoreList":[2,3,4,5],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,MAAM,gBAAgB,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;;;;;;;CEhBtF,MAAMA,OAAK,QAAQ,KAAK;CACxB,MAAMC,SAAO,QAAQ,OAAO;CAC5B,MAAM,KAAK,QAAQ,KAAK;CACxB,MAAMC,WAAS,QAAQ,SAAS;CAGhC,MAAM,OAAO;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;CAGD,SAAS,gBAAiB;EACxB,OAAO,KAAK,KAAK,MAAM,KAAK,QAAQ,GAAG,KAAK,OAAO;;CAGrD,SAAS,aAAc,OAAO;EAC5B,IAAI,OAAO,UAAU,UACnB,OAAO,CAAC;GAAC;GAAS;GAAK;GAAM;GAAO;GAAG,CAAC,SAAS,MAAM,aAAa,CAAC;EAEvE,OAAO,QAAQ,MAAM;;CAGvB,SAAS,eAAgB;EACvB,OAAO,QAAQ,OAAO;;CAGxB,SAAS,IAAK,MAAM;EAClB,OAAO,cAAc,GAAG,UAAU,KAAK,WAAW;;CAGpD,MAAM,OAAO;CAGb,SAAS,MAAO,KAAK;EACnB,MAAM,MAAM,EAAE;EAGd,IAAI,QAAQ,IAAI,UAAU;EAG1B,QAAQ,MAAM,QAAQ,WAAW,KAAK;EAEtC,IAAI;EACJ,QAAQ,QAAQ,KAAK,KAAK,MAAM,KAAK,MAAM;GACzC,MAAM,MAAM,MAAM;GAGlB,IAAI,QAAS,MAAM,MAAM;GAGzB,QAAQ,MAAM,MAAM;GAGpB,MAAM,aAAa,MAAM;GAGzB,QAAQ,MAAM,QAAQ,0BAA0B,KAAK;GAGrD,IAAI,eAAe,MAAK;IACtB,QAAQ,MAAM,QAAQ,QAAQ,KAAK;IACnC,QAAQ,MAAM,QAAQ,QAAQ,KAAK;;GAIrC,IAAI,OAAO;;EAGb,OAAO;;CAGT,SAAS,YAAa,SAAS;EAC7B,UAAU,WAAW,EAAE;EAEvB,MAAM,YAAY,WAAW,QAAQ;EACrC,QAAQ,OAAO;EACf,MAAM,SAAS,aAAa,aAAa,QAAQ;EACjD,IAAI,CAAC,OAAO,QAAQ;GAClB,MAAM,sBAAM,IAAI,MAAM,8BAA8B,UAAU,wBAAwB;GACtF,IAAI,OAAO;GACX,MAAM;;EAKR,MAAM,OAAO,WAAW,QAAQ,CAAC,MAAM,IAAI;EAC3C,MAAM,SAAS,KAAK;EAEpB,IAAI;EACJ,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAC1B,IAAI;GAKF,MAAM,QAAQ,cAAc,QAHhB,KAAK,GAAG,MAGmB,CAAC;GAGxC,YAAY,aAAa,QAAQ,MAAM,YAAY,MAAM,IAAI;GAE7D;WACO,OAAO;GAEd,IAAI,IAAI,KAAK,QACX,MAAM;;EAOZ,OAAO,aAAa,MAAM,UAAU;;CAGtC,SAAS,MAAO,SAAS;EACvB,QAAQ,MAAM,KAAK,UAAU;;CAG/B,SAAS,OAAQ,SAAS;EACxB,QAAQ,IAAI,KAAK,UAAU;;CAG7B,SAAS,KAAM,SAAS;EACtB,QAAQ,IAAI,KAAK,UAAU;;CAG7B,SAAS,WAAY,SAAS;EAE5B,IAAI,WAAW,QAAQ,cAAc,QAAQ,WAAW,SAAS,GAC/D,OAAO,QAAQ;EAIjB,IAAI,QAAQ,IAAI,cAAc,QAAQ,IAAI,WAAW,SAAS,GAC5D,OAAO,QAAQ,IAAI;EAIrB,OAAO;;CAGT,SAAS,cAAe,QAAQ,WAAW;EAEzC,IAAI;EACJ,IAAI;GACF,MAAM,IAAI,IAAI,UAAU;WACjB,OAAO;GACd,IAAI,MAAM,SAAS,mBAAmB;IACpC,MAAM,sBAAM,IAAI,MAAM,6IAA6I;IACnK,IAAI,OAAO;IACX,MAAM;;GAGR,MAAM;;EAIR,MAAM,MAAM,IAAI;EAChB,IAAI,CAAC,KAAK;GACR,MAAM,sBAAM,IAAI,MAAM,uCAAuC;GAC7D,IAAI,OAAO;GACX,MAAM;;EAIR,MAAM,cAAc,IAAI,aAAa,IAAI,cAAc;EACvD,IAAI,CAAC,aAAa;GAChB,MAAM,sBAAM,IAAI,MAAM,+CAA+C;GACrE,IAAI,OAAO;GACX,MAAM;;EAIR,MAAM,iBAAiB,gBAAgB,YAAY,aAAa;EAChE,MAAM,aAAa,OAAO,OAAO;EACjC,IAAI,CAAC,YAAY;GACf,MAAM,sBAAM,IAAI,MAAM,2DAA2D,eAAe,2BAA2B;GAC3H,IAAI,OAAO;GACX,MAAM;;EAGR,OAAO;GAAE;GAAY;GAAK;;CAG5B,SAAS,WAAY,SAAS;EAC5B,IAAI,oBAAoB;EAExB,IAAI,WAAW,QAAQ,QAAQ,QAAQ,KAAK,SAAS,GACnD,IAAI,MAAM,QAAQ,QAAQ,KAAK;QACxB,MAAM,YAAY,QAAQ,MAC7B,IAAIF,KAAG,WAAW,SAAS,EACzB,oBAAoB,SAAS,SAAS,SAAS,GAAG,WAAW,GAAG,SAAS;SAI7E,oBAAoB,QAAQ,KAAK,SAAS,SAAS,GAAG,QAAQ,OAAO,GAAG,QAAQ,KAAK;OAGvF,oBAAoBC,OAAK,QAAQ,QAAQ,KAAK,EAAE,aAAa;EAG/D,IAAID,KAAG,WAAW,kBAAkB,EAClC,OAAO;EAGT,OAAO;;CAGT,SAAS,aAAc,SAAS;EAC9B,OAAO,QAAQ,OAAO,MAAMC,OAAK,KAAK,GAAG,SAAS,EAAE,QAAQ,MAAM,EAAE,CAAC,GAAG;;CAG1E,SAAS,aAAc,SAAS;EAC9B,MAAM,QAAQ,aAAa,QAAQ,IAAI,uBAAwB,WAAW,QAAQ,MAAO;EACzF,MAAM,QAAQ,aAAa,QAAQ,IAAI,uBAAwB,WAAW,QAAQ,MAAO;EAEzF,IAAI,SAAS,CAAC,OACZ,KAAK,wCAAwC;EAG/C,MAAM,SAAS,aAAa,YAAY,QAAQ;EAEhD,IAAI,aAAa,QAAQ;EACzB,IAAI,WAAW,QAAQ,cAAc,MACnC,aAAa,QAAQ;EAGvB,aAAa,SAAS,YAAY,QAAQ,QAAQ;EAElD,OAAO,EAAE,QAAQ;;CAGnB,SAAS,aAAc,SAAS;EAC9B,MAAM,aAAaA,OAAK,QAAQ,QAAQ,KAAK,EAAE,OAAO;EACtD,IAAI,WAAW;EACf,IAAI,aAAa,QAAQ;EACzB,IAAI,WAAW,QAAQ,cAAc,MACnC,aAAa,QAAQ;EAEvB,IAAI,QAAQ,aAAa,WAAW,uBAAwB,WAAW,QAAQ,MAAO;EACtF,IAAI,QAAQ,aAAa,WAAW,uBAAwB,WAAW,QAAQ,MAAO;EAEtF,IAAI,WAAW,QAAQ,UACrB,WAAW,QAAQ;OAEnB,IAAI,OACF,OAAO,sDAAsD;EAIjE,IAAI,cAAc,CAAC,WAAW;EAC9B,IAAI,WAAW,QAAQ,MACrB,IAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,EAC9B,cAAc,CAAC,aAAa,QAAQ,KAAK,CAAC;OACrC;GACL,cAAc,EAAE;GAChB,KAAK,MAAM,YAAY,QAAQ,MAC7B,YAAY,KAAK,aAAa,SAAS,CAAC;;EAO9C,IAAI;EACJ,MAAM,YAAY,EAAE;EACpB,KAAK,MAAMA,UAAQ,aACjB,IAAI;GAEF,MAAM,SAAS,aAAa,MAAMD,KAAG,aAAaC,QAAM,EAAE,UAAU,CAAC,CAAC;GAEtE,aAAa,SAAS,WAAW,QAAQ,QAAQ;WAC1C,GAAG;GACV,IAAI,OACF,OAAO,kBAAkBA,OAAK,GAAG,EAAE,UAAU;GAE/C,YAAY;;EAIhB,MAAM,YAAY,aAAa,SAAS,YAAY,WAAW,QAAQ;EAGvE,QAAQ,aAAa,WAAW,uBAAuB,MAAM;EAC7D,QAAQ,aAAa,WAAW,uBAAuB,MAAM;EAE7D,IAAI,SAAS,CAAC,OAAO;GACnB,MAAM,YAAY,OAAO,KAAK,UAAU,CAAC;GACzC,MAAM,aAAa,EAAE;GACrB,KAAK,MAAM,YAAY,aACrB,IAAI;IACF,MAAM,WAAWA,OAAK,SAAS,QAAQ,KAAK,EAAE,SAAS;IACvD,WAAW,KAAK,SAAS;YAClB,GAAG;IACV,IAAI,OACF,OAAO,kBAAkB,SAAS,GAAG,EAAE,UAAU;IAEnD,YAAY;;GAIhB,KAAK,iBAAiB,UAAU,SAAS,WAAW,KAAK,IAAI,CAAC,GAAG,IAAI,WAAW,eAAe,GAAG,GAAG;;EAGvG,IAAI,WACF,OAAO;GAAE,QAAQ;GAAW,OAAO;GAAW;OAE9C,OAAO,EAAE,QAAQ,WAAW;;CAKhC,SAAS,OAAQ,SAAS;EAExB,IAAI,WAAW,QAAQ,CAAC,WAAW,GACjC,OAAO,aAAa,aAAa,QAAQ;EAG3C,MAAM,YAAY,WAAW,QAAQ;EAGrC,IAAI,CAAC,WAAW;GACd,MAAM,+DAA+D,YAAY;GAEjF,OAAO,aAAa,aAAa,QAAQ;;EAG3C,OAAO,aAAa,aAAa,QAAQ;;CAG3C,SAAS,QAAS,WAAW,QAAQ;EACnC,MAAM,MAAM,OAAO,KAAK,OAAO,MAAM,IAAI,EAAE,MAAM;EACjD,IAAI,aAAa,OAAO,KAAK,WAAW,SAAS;EAEjD,MAAM,QAAQ,WAAW,SAAS,GAAG,GAAG;EACxC,MAAM,UAAU,WAAW,SAAS,IAAI;EACxC,aAAa,WAAW,SAAS,IAAI,IAAI;EAEzC,IAAI;GACF,MAAM,SAASC,SAAO,iBAAiB,eAAe,KAAK,MAAM;GACjE,OAAO,WAAW,QAAQ;GAC1B,OAAO,GAAG,OAAO,OAAO,WAAW,GAAG,OAAO,OAAO;WAC7C,OAAO;GACd,MAAM,UAAU,iBAAiB;GACjC,MAAM,mBAAmB,MAAM,YAAY;GAC3C,MAAM,mBAAmB,MAAM,YAAY;GAE3C,IAAI,WAAW,kBAAkB;IAC/B,MAAM,sBAAM,IAAI,MAAM,8DAA8D;IACpF,IAAI,OAAO;IACX,MAAM;UACD,IAAI,kBAAkB;IAC3B,MAAM,sBAAM,IAAI,MAAM,kDAAkD;IACxE,IAAI,OAAO;IACX,MAAM;UAEN,MAAM;;;CAMZ,SAAS,SAAU,YAAY,QAAQ,UAAU,EAAE,EAAE;EACnD,MAAM,QAAQ,QAAQ,WAAW,QAAQ,MAAM;EAC/C,MAAM,WAAW,QAAQ,WAAW,QAAQ,SAAS;EACrD,MAAM,YAAY,EAAE;EAEpB,IAAI,OAAO,WAAW,UAAU;GAC9B,MAAM,sBAAM,IAAI,MAAM,iFAAiF;GACvG,IAAI,OAAO;GACX,MAAM;;EAIR,KAAK,MAAM,OAAO,OAAO,KAAK,OAAO,EACnC,IAAI,OAAO,UAAU,eAAe,KAAK,YAAY,IAAI,EAAE;GACzD,IAAI,aAAa,MAAM;IACrB,WAAW,OAAO,OAAO;IACzB,UAAU,OAAO,OAAO;;GAG1B,IAAI,OACF,IAAI,aAAa,MACf,OAAO,IAAI,IAAI,0CAA0C;QAEzD,OAAO,IAAI,IAAI,8CAA8C;SAG5D;GACL,WAAW,OAAO,OAAO;GACzB,UAAU,OAAO,OAAO;;EAI5B,OAAO;;CAGT,MAAM,eAAe;EACnB;EACA;EACA;EACA;EACA;EACA;EACA;EACD;CAED,OAAO,QAAQ,eAAe,aAAa;CAC3C,OAAO,QAAQ,eAAe,aAAa;CAC3C,OAAO,QAAQ,cAAc,aAAa;CAC1C,OAAO,QAAQ,SAAS,aAAa;CACrC,OAAO,QAAQ,UAAU,aAAa;CACtC,OAAO,QAAQ,QAAQ,aAAa;CACpC,OAAO,QAAQ,WAAW,aAAa;CAEvC,OAAO,UAAU;;;;ACrajB,MAAM,YAAY,EAAE;AACpB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,EAAE,GACvB,UAAU,MAAM,IAAI,KAAO,SAAS,GAAG,CAAC,MAAM,EAAE,CAAC;AAErD,SAAgB,gBAAgB,KAAK,SAAS,GAAG;CAC7C,QAAQ,UAAU,IAAI,SAAS,MAC3B,UAAU,IAAI,SAAS,MACvB,UAAU,IAAI,SAAS,MACvB,UAAU,IAAI,SAAS,MACvB,MACA,UAAU,IAAI,SAAS,MACvB,UAAU,IAAI,SAAS,MACvB,MACA,UAAU,IAAI,SAAS,MACvB,UAAU,IAAI,SAAS,MACvB,MACA,UAAU,IAAI,SAAS,MACvB,UAAU,IAAI,SAAS,MACvB,MACA,UAAU,IAAI,SAAS,OACvB,UAAU,IAAI,SAAS,OACvB,UAAU,IAAI,SAAS,OACvB,UAAU,IAAI,SAAS,OACvB,UAAU,IAAI,SAAS,OACvB,UAAU,IAAI,SAAS,MAAM,aAAa;;;;ACzBlD,MAAM,QAAQ,IAAI,WAAW,GAAG;AAChC,SAAwB,MAAM;CAC1B,OAAO,OAAO,gBAAgB,MAAM;;;;ACAxC,SAAS,GAAG,SAAS,KAAK,QAAQ;CAC9B,IAAI,CAAC,OAAO,CAAC,WAAW,OAAO,YAC3B,OAAO,OAAO,YAAY;CAE9B,OAAO,IAAI,SAAS,KAAK,OAAO;;AAEpC,SAAS,IAAI,SAAS,KAAK,QAAQ;CAC/B,UAAU,WAAW,EAAE;CACvB,MAAM,OAAO,QAAQ,UAAU,QAAQ,OAAO,IAAI,KAAK;CACvD,IAAI,KAAK,SAAS,IACd,MAAM,IAAI,MAAM,oCAAoC;CAExD,KAAK,KAAM,KAAK,KAAK,KAAQ;CAC7B,KAAK,KAAM,KAAK,KAAK,KAAQ;CAC7B,IAAI,KAAK;EACL,SAAS,UAAU;EACnB,IAAI,SAAS,KAAK,SAAS,KAAK,IAAI,QAChC,MAAM,IAAI,WAAW,mBAAmB,OAAO,GAAG,SAAS,GAAG,0BAA0B;EAE5F,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,EAAE,GACtB,IAAI,SAAS,KAAK,KAAK;EAE3B,OAAO;;CAEX,OAAO,gBAAgB,KAAK;;;;;ACnBhC,IAAI,UAAU;AAGd,SAAS,iBAAiB;CACzB,IAAI,OAAO,YAAY,eAAe,QAAQ,YAAY,QAAQ,SAAS,MAAM,OAAO,QAAQ,QAAQ,SAAS;CACjH,IAAI,OAAO,cAAc,eAAe,UAAU,WAAW,OAAO,WAAW,UAAU;CACzF,OAAO;;AAIR,IAAI,eAAe,MAAM;CACxB,YAAY,aAAa,MAAM;EAC9B,KAAK,cAAc;EACnB,KAAK,OAAO;EACZ,KAAK,aAAa,KAAK,SAAS,WAAW,KAAK,MAAM,KAAK;;;CAG5D,IAAI,YAAY;EACf,OAAO,KAAK,KAAK,SAAS,cAAc,YAAY;;CAErD,UAAU;EACT,OAAO;GACN,eAAe,UAAU,KAAK;GAC9B,gBAAgB;GAChB,QAAQ;GACR,GAAG,KAAK,KAAK,SAAS,cAAc,EAAE,qBAAqB,KAAK,KAAK,WAAW,GAAG,EAAE;GACrF;;CAEF,MAAM,YAAY,UAAU;EAC3B,MAAM,WAAW,MAAM,SAAS,MAAM;EACtC,MAAM,IAAI,MAAM,GAAG,SAAS,OAAO,GAAG,WAAW;;;AAKnD,IAAI,wBAAwB,cAAc,aAAa;CACtD,YAAY,aAAa,MAAM;EAC9B,MAAM,aAAa,KAAK;;CAEzB,MAAM,KAAK,EAAE,WAAW,SAAS,UAAU;EAC1C,MAAM,UAAU;GACf;GACA;GACA;GACA,QAAQ,gBAAgB,IAAI;GAC5B,YAAY;GACZ;EACD,MAAM,aAAa,KAAK,UAAU,QAAQ;EAC1C,MAAM,mBAAmB,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,MAAM,oBAAoB,CAAC,CAAC,QAAQ,CAAC,YAAY,IAAI,kBAAkB,OAAO,CAAC;EACjI,MAAM,iBAAiB,MAAM,IAAI,SAAS,iBAAiB,CAAC,aAAa;EACzE,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,+BAA+B;GAC9E,QAAQ;GACR,SAAS;IACR,GAAG,KAAK,SAAS;IACjB,oBAAoB;IACpB;GACD,MAAM;GACN,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;;;;;;;;;;;;AAcpD,IAAI,cAAc,cAAc,aAAa;CAC5C,YAAY,aAAa,MAAM;EAC9B,MAAM,aAAa,KAAK;;;CAGzB,MAAM,eAAe;EACpB,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,mBAAmB;GACnE,QAAQ;GACR,SAAS;IACR,eAAe,UAAU,KAAK;IAC9B,QAAQ;IACR;GACD,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;EAClD,MAAM,OAAO,MAAM,SAAS,MAAM;EAClC,OAAO,MAAM,QAAQ,MAAM,SAAS,GAAG,KAAK,WAAW,EAAE;;;AAK3D,SAASC,mBAAiB,SAAS;CAClC,MAAM,WAAW,SAAS,YAAY;CACtC,MAAM,QAAQ,SAAS,SAAS,QAAQ,IAAI,gBAAgB,aAAa,EAAE,MAAM,IAAI;CACrF,QAAA,GAAA,OAAA,SAAY,EAAE,OAAO,GAAA,GAAA,YAAA,YAAa;EACjC;EACA,cAAc;EACd,CAAC,CAAC;;AAEJ,MAAMC,aAAWD,oBAAkB;AACnC,MAAM,gBAAgB,OAAO,iEAAiE,KAAK,GAAG;AACtG,MAAM,gBAAgB;CACrB,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY,OAAO,OAAO,YAAY;MACnG,OAAO,IAAI;;AAEjB,MAAM,oBAAoB,WAAW;CACpC,IAAI,KAAK,OAAO,aAAa;CAC7B,IAAI,GAAG,WAAW,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE;CACzC,IAAI,GAAG,WAAW,IAAI,WAAS,KAAK,WAAW,OAAO,uEAAuE;CAC7H,IAAI,CAAC,cAAc,KAAK,GAAG,EAAE;EAC5B,WAAS,MAAM,WAAW,OAAO,+DAA+D;EAChG,OAAO,SAAS;;CAEjB,OAAO,GAAG,SAAS,IAAI,IAAI,CAAC,QAAQ,wEAAwE,iBAAiB;;AAE9H,MAAM,qBAAqB,YAAY;CACtC,IAAI,KAAK,QAAQ,aAAa;CAC9B,IAAI,GAAG,WAAW,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE;CACzC,IAAI,GAAG,WAAW,IAAI,WAAS,KAAK,YAAY,QAAQ,wEAAwE;CAChI,IAAI,CAAC,cAAc,KAAK,GAAG,EAAE;EAC5B,WAAS,MAAM,YAAY,QAAQ,+DAA+D;EAClG,OAAO,SAAS;;CAEjB,OAAO,GAAG,QAAQ,wEAAwE,iBAAiB;;AAE5G,MAAM,gBAAgB,OAAO,WAAW;CACvC,IAAI,UAAU,QAAQ,UAAU,KAAK,GAAG,OAAO;CAC/C,MAAM,MAAM,KAAK,UAAU,MAAM;CACjC,IAAI,IAAI,UAAU,QAAQ,OAAO;CACjC,OAAO,IAAI,MAAM,GAAG,OAAO,GAAG;;AAE/B,MAAM,WAAW,YAAY;CAC5B,MAAM,UAAU,QAAQ,IAAI,YAAY;CACxC,MAAM,SAAS,QAAQ,KAAK;CAC5B,MAAM,WAAW;EAChB;EACA;EACA,QAAQ;EACR,QAAQ,QAAQ;EAChB;CACD,MAAM,WAAW,QAAQ,IAAI,kBAAkB;CAC/C,MAAM,UAAU,CAAC,SAAS,QAAQ,CAAC,SAAS,SAAS,MAAM,CAAC,aAAa,CAAC;CAC1E,MAAM,QAAQ,SAAS,SAAS,CAAC;CACjC,CAAA,GAAA,YAAA,QAAO;EACN,MAAM,SAAS,SAAS,SAAS,KAAK,YAAYE,OAAK,QAAQ,QAAQ,QAAQ,CAAC;EAChF;EACA,CAAC;;AAIH,MAAMC,aAAWH,oBAAkB;AACnC,MAAM,6BAA6B;AACnC,MAAMI,oCAAkC;AACxC,IAAI,mBAAmB,cAAc,aAAa;CACjD,YAAY,aAAa,MAAM;EAC9B,MAAM,aAAa,KAAK;;;;;;;CAOzB,MAAM,eAAe;EACpB,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,KAAK,YAAY,aAAa;GAC7E,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;EAClD,OAAO,SAAS,MAAM;;;;;;;;CAQvB,MAAM,iBAAiB,MAAM;EAC5B,MAAM,SAAS,IAAI,gBAAgB,EAAE,MAAM,CAAC;EAC5C,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,GAAG,KAAK,UAAU,YAAY,OAAO,UAAU,IAAI;GAClG,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;EAClD,OAAO,SAAS,MAAM;;;;;;;;;;;;;CAavB,MAAM,KAAK,EAAE,QAAQ,MAAM,IAAI,YAAYA,mCAAiC,gBAAgB,SAAS;EACpG,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,IAAI,MAAM,qCAAqC;EACvE,IAAI,QAAQ,IAAI,MAAM,IAAI,MAAM,0CAA0C;EAC1E,IAAI,iBAAiB,CAAC,MAAM,MAAM,IAAI,MAAM,oDAAoD;EAChG,MAAM,aAAa,OAAO,EAAE,MAAM,GAAG,EAAE,WAAW,IAAI;EACtD,MAAM,eAAe,KAAK,KAAK,OAAO,SAAS,UAAU;EACzD,IAAI;EACJ,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,WAAW;GAClD,MAAM,WAAW,KAAK,MAAM,IAAI,UAAU,GAAG;GAC7C,WAAS,MAAM,iBAAiB,SAAS,MAAM,eAAe;GAC9D,MAAM,QAAQ,OAAO,MAAM,GAAG,IAAI,UAAU;GAC5C,MAAM,gBAAgB,MAAM,MAAM,KAAK,cAAc,KAAK,YAAY,wBAAwB;IAC7F,QAAQ;IACR,SAAS,KAAK,SAAS;IACvB,MAAM,KAAK,UAAU;KACpB,GAAG;KACH,YAAY,MAAM,KAAK,WAAW;MACjC,MAAM,MAAM;MACZ,QAAQ,MAAM,UAAU,EAAE;MAC1B,UAAU,MAAM,YAAY,EAAE;MAC9B,EAAE;KACH;KACA,CAAC;IACF,CAAC;GACF,IAAI,cAAc,WAAW,OAAO,cAAc,WAAW,KAAK,MAAM,KAAK,YAAY,cAAc;GACvG,WAAW,MAAM,cAAc,MAAM;;EAEtC,OAAO;;;;;;;;;;;;CAYR,MAAM,KAAK,EAAE,MAAM,IAAI,QAAQ,4BAA4B,SAAS,KAAK;EACxE,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,IAAI,MAAM,qCAAqC;EACvE,IAAI,QAAQ,IAAI,MAAM,IAAI,MAAM,0CAA0C;EAC1E,MAAM,YAAY;GACjB,QAAQ,OAAO,UAAU;GACzB,OAAO,MAAM,UAAU;GACvB;EACD,IAAI,MAAM,UAAU,OAAO;OACtB,UAAU,YAAY;EAC3B,MAAM,SAAS,IAAI,gBAAgB,UAAU;EAC7C,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,GAAG,KAAK,UAAU,uBAAuB,OAAO,UAAU,IAAI;GAC7G,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;EAClD,OAAO,SAAS,MAAM;;;AAKxB,MAAMC,aAAWL,oBAAkB;AACnC,MAAM,+CAA+C;AACrD,IAAI,gBAAgB,cAAc,aAAa;CAC9C,YAAY,aAAa,MAAM;EAC9B,MAAM,aAAa,KAAK;;;;;;;;;;CAUzB,MAAM,KAAK,MAAM,WAAW,UAAU;EACrC,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa;GAC5D,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACpB,MAAM,QAAQ;IACd,WAAW,aAAa;IACxB,UAAU,YAAY;IACtB,CAAC;GACF,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;EAClD,OAAO,SAAS,MAAM;;;;;;;;;;CAUvB,MAAM,OAAO,MAAM;EAClB,QAAQ,MAAM,KAAK,KAAK,MAAM,MAAM,MAAM,WAAW,MAAM,SAAS,EAAE;;;;;;CAMvE,MAAM,iBAAiB,MAAM,WAAW,UAAU;EACjD,QAAQ,MAAM,KAAK,KAAK,MAAM,WAAW,SAAS,EAAE;;;;;;;;;;;;;;CAcrD,MAAM,gBAAgB,EAAE,QAAQ,MAAM,QAAQ,UAAU,OAAO,WAAW;EACzE,MAAM,cAAc,SAAS;EAC7B,MAAM,mBAAmB;GACxB,IAAI;GACJ;GACA;GACA,OAAO,SAAS;GAChB,SAAS,WAAW,SAAS;GAC7B,gBAAgB,SAAS;GACzB;GACA;EACD,MAAM,KAAK,eAAe;GACzB;GACA,YAAY,CAAC,iBAAiB;GAC9B,CAAC;EACF,OAAO;;;;;;;;;;;;CAYR,MAAM,gBAAgB,EAAE,QAAQ,aAAa,QAAQ,kBAAkB;EACtE,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa,OAAO,cAAc,eAAe;GAChG,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACpB;IACA;IACA,CAAC;GACF,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;;;;;;;;;;;CAWnD,MAAM,eAAe,EAAE,QAAQ,YAAY,aAAa;EACvD,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa,OAAO,cAAc;GACjF,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACpB,QAAQ,WAAW,KAAK,OAAO;KAC9B,GAAG;KACH,MAAM,aAAa,EAAE,MAAM,6CAA6C;KACxE,QAAQ,aAAa,EAAE,QAAQ,6CAA6C;KAC5E,gBAAgB,aAAa,EAAE,gBAAgB,6CAA6C;KAC5F,EAAE;IACH,WAAW,aAAa;IACxB,CAAC;GACF,CAAC;EACF,IAAI,SAAS,WAAW,KAAK,OAAO,MAAM,KAAK,oBAAoB;GAClE;GACA;GACA;GACA,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;;;;;;;;;;;;CAYnD,MAAM,cAAc,EAAE,aAAa,QAAQ,SAAS;EACnD,WAAS,KAAK,2EAA2E;EACzF,MAAM,SAAS,IAAI,gBAAgB;GAClC,MAAM;GACN,QAAQ,OAAO,UAAU;GACzB,OAAO,MAAM,UAAU;GACvB,CAAC;EACF,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,2BAA2B,OAAO,UAAU,IAAI;GAC/F,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;EAClD,OAAO,MAAM,SAAS,MAAM;;CAE7B,MAAM,oBAAoB,EAAE,QAAQ,YAAY,WAAW,aAAa,IAAI,gBAAgB,gDAAgD;EAC3I,IAAI,SAAS;EACb,IAAI,eAAe;EACnB,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;GACpC,WAAS,MAAM,+BAA+B,IAAI,EAAE,MAAM,WAAW,YAAY,SAAS;GAC1F,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa,OAAO,cAAc;IACjF,QAAQ;IACR,SAAS,KAAK,SAAS;IACvB,MAAM,KAAK,UAAU;KACpB,QAAQ,WAAW,KAAK,OAAO;MAC9B,GAAG;MACH,MAAM,aAAa,EAAE,MAAM,OAAO;MAClC,QAAQ,aAAa,EAAE,QAAQ,OAAO;MACtC,gBAAgB,aAAa,EAAE,gBAAgB,OAAO;MACtD,EAAE;KACH,WAAW,aAAa;KACxB,CAAC;IACF,CAAC;GACF,eAAe;GACf,SAAS,KAAK,MAAM,SAAS,EAAE;GAC/B,IAAI,SAAS,WAAW,KAAK;;EAE9B,IAAI,gBAAgB,CAAC,aAAa,IAAI,MAAM,KAAK,YAAY,aAAa;;;;;;AAQ5E,IAAI,qBAAqB,cAAc,aAAa;CACnD,YAAY,aAAa,MAAM;EAC9B,MAAM,aAAa,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BzB,MAAM,MAAM,SAAS;EACpB,MAAM,EAAE,MAAM,UAAU,UAAU;EAClC,IAAI;EACJ,IAAI,aAAa,WAAW,QAAQ,SAAS,UAAU;GACtD;GACA;GACA;GACA,QAAQ;GACR,SAAS,aAAa,QAAQ,QAAQ,GAAG,QAAQ,UAAU,kBAAkB,QAAQ,QAAQ;GAC7F;OACI,IAAI,YAAY,WAAW,QAAQ,QAAQ,UAAU;GACzD;GACA;GACA;GACA,QAAQ;GACR,QAAQ,aAAa,QAAQ,OAAO,GAAG,QAAQ,SAAS,iBAAiB,QAAQ,OAAO;GACxF;OACI,MAAM,IAAI,MAAM,iDAAiD;EACtE,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,wBAAwB;GACvE,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,QAAQ;GAC7B,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;;;AAKpD,MAAMM,aAAWN,oBAAkB;;;;;;;;;;AAUnC,MAAM,gBAAgB,aAAa;CAClC,MAAM,SAAS,OAAO,aAAa,WAAW,WAAW,KAAK,UAAU,YAAY,KAAK;CACzF,MAAM,aAAa,EAAE;CACrB,IAAI,aAAa,QAAQ,OAAO,aAAa,YAAY,OAAO,SAAS,iBAAiB,UAAU,WAAW,8BAA8B,SAAS;CACtJ,OAAO;EACN,MAAM;EACN,OAAO;EACP;EACA;EACA;;AAEF,IAAI,0BAA0B,cAAc,aAAa;CACxD,YAAY,aAAa,MAAM;EAC9B,MAAM,aAAa,KAAK;;;;;;;;;;CAUzB,MAAM,SAAS,EAAE,WAAW,QAAQ;EACnC,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,cAAc,KAAK,UAAU,YAAY,aAAa;GAC1F,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,EAAE,MAAM,CAAC;GAC9B,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;EAClD,IAAI;GACH,QAAQ,MAAM,SAAS,MAAM,EAAE,aAAa;WACpC,GAAG;GACX,WAAS,KAAK,8CAA8C,aAAa,EAAE,GAAG;GAC9E,OAAO;;;;;;;;;CAST,MAAM,QAAQ,EAAE,WAAW,QAAQ;EAClC,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,cAAc,KAAK,UAAU,YAAY,UAAU,QAAQ;GAC/F,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,EAAE,MAAM,CAAC;GAC9B,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;;;;;;;;;;;;;;;;CAgBnD,MAAM,MAAM,EAAE,WAAW,eAAe,YAAY,aAAa;EAChE,IAAI;EACJ,IAAI;GACH,WAAW,MAAM,MAAM,GAAG,KAAK,cAAc,KAAK,UAAU,YAAY,UAAU,SAAS;IAC1F,QAAQ;IACR,SAAS,KAAK,SAAS;IACvB,MAAM,KAAK,UAAU;KACpB;KACA;KACA;KACA,CAAC;IACF,CAAC;WACM,GAAG;GACX,WAAS,KAAK,4CAA4C,aAAa,EAAE,GAAG;GAC5E,OAAO,EAAE,MAAM,QAAQ;;EAExB,IAAI,CAAC,SAAS,IAAI;GACjB,WAAS,KAAK,+BAA+B,SAAS,OAAO,gBAAgB;GAC7E,OAAO,EAAE,MAAM,QAAQ;;EAExB,IAAI;EACJ,IAAI;GACH,OAAO,MAAM,SAAS,MAAM;WACpB,GAAG;GACX,WAAS,KAAK,uDAAuD,aAAa,EAAE,GAAG;GACvF,OAAO,EAAE,MAAM,QAAQ;;EAExB,QAAQ,KAAK,SAAb;GACC,KAAK;IACJ,IAAI,KAAK,aAAa,QAAQ,KAAK,aAAa,KAAK,GAAG;KACvD,WAAS,KAAK,wDAAwD;KACtE,OAAO,EAAE,MAAM,QAAQ;;IAExB,OAAO;KACN,MAAM;KACN,QAAQ,aAAa,KAAK,SAAS;KACnC;GACF,KAAK,QAAQ,OAAO,EAAE,MAAM,QAAQ;GACpC,KAAK,QAAQ,OAAO,EAAE,MAAM,QAAQ;GACpC;IACC,WAAS,KAAK,gCAAgC,KAAK,QAAQ,iBAAiB;IAC5E,OAAO,EAAE,MAAM,QAAQ;;;CAG1B,MAAM,OAAO,EAAE,aAAa;EAC3B,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,cAAc,KAAK,UAAU,YAAY,aAAa;GAC1F,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;;;AAKpD,IAAI,cAAc,cAAc,aAAa;CAC5C,YAAY,aAAa,MAAM;EAC9B,MAAM,aAAa,KAAK;;CAEzB,MAAM,MAAM,KAAK,aAAa,EAAE,EAAE;EACjC,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,cAAc,KAAK,UAAU,aAAa;GAC9E,QAAQ;GACR,SAAS,EAAE,GAAG,KAAK,SAAS,EAAE;GAC9B,MAAM,KAAK,UAAU;IACpB,OAAO;IACP;IACA,CAAC;GACF,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;EAClD,QAAQ,MAAM,SAAS,MAAM,EAAE;;;;AAMjC,IAAI,eAAe,cAAc,aAAa;;CAE7C,YAAY,aAAa,MAAM;EAC9B,MAAM,aAAa,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCzB,MAAM,IAAI,UAAU,MAAM;EACzB,MAAM,YAAY,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC,KAAK;EACrD,MAAM,mBAAmB,aAAa,SAAS,GAAG,WAAW,kBAAkB,SAAS;EACxF,MAAM,MAAM,KAAK,cAAc;EAC/B,MAAM,UAAU;GACf,WAAW;GACX,SAAS;GACT;EACD,MAAM,WAAW,MAAM,MAAM,KAAK;GACjC,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,QAAQ;GAC7B,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;EAClD,OAAO,SAAS,MAAM;;;;AAMxB,MAAMO,WAASP,oBAAkB;AACjC,IAAI,iBAAiB,cAAc,aAAa;;CAE/C,YAAY,aAAa,MAAM;EAC9B,MAAM,aAAa,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDzB,MAAM,aAAa,SAAS,UAAU,SAAS;EAC9C,IAAI,CAAC,YAAY,OAAO,KAAK,SAAS,CAAC,WAAW,GAAG,MAAM,IAAI,MAAM,sCAAsC;EAC3G,MAAM,mBAAmB,aAAa,QAAQ,GAAG,UAAU,kBAAkB,QAAQ;EACrF,MAAM,MAAM,KAAK,cAAc,KAAK,YAAY;EAChD,MAAM,WAAW,MAAM,MAAM,KAAK;GACjC,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACpB,SAAS;IACT;IACA,CAAC;GACF,CAAC;EACF,IAAI,SAAS,WAAW,KAAK;GAC5B,MAAM,UAAU,SAAS,iBAAiB;GAC1C,IAAI,SAAS,gBAAgB,MAAM,IAAI,MAAM,QAAQ;GACrD,SAAO,KAAK,QAAQ;GACpB;;EAED,IAAI,CAAC,SAAS,IAAI,MAAM,KAAK,YAAY,SAAS;;;AAKpD,IAAI,gBAAgB,MAAM,cAAc;CACvC,YAAY,EAAE,SAAS,MAAM,MAAM,eAAe,qBAAqB,EAAE,EAAE;EAC1E,SAAS;EACT,KAAK,OAAO,cAAc,cAAc,MAAM,eAAe,iBAAiB;EAC9E,MAAM,WAAW,SAAS,SAAS,MAAM,aAAa,GAAG,SAAS,QAAQ,MAAM,aAAa,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG;EAC7G,MAAM,iBAAiB,WAAW,QAAQ,IAAI,gBAAgB,QAAQ,OAAO,GAAG,CAAC,QAAQ,cAAc,GAAG;EAC1G,KAAK,UAAU,GAAG,iBAAiB,sBAAsB,GAAG;EAC5D,KAAK,iBAAiB,IAAI,sBAAsB,KAAK,SAAS,KAAK,KAAK;EACxE,KAAK,OAAO,IAAI,YAAY,KAAK,SAAS,KAAK,KAAK;EACpD,KAAK,YAAY,IAAI,iBAAiB,KAAK,SAAS,KAAK,KAAK;EAC9D,KAAK,SAAS,IAAI,cAAc,KAAK,SAAS,KAAK,KAAK;EACxD,KAAK,cAAc,IAAI,mBAAmB,KAAK,SAAS,KAAK,KAAK;EAClE,KAAK,mBAAmB,IAAI,wBAAwB,KAAK,SAAS,KAAK,KAAK;EAC5E,KAAK,OAAO,IAAI,YAAY,KAAK,SAAS,KAAK,KAAK;EACpD,KAAK,QAAQ,IAAI,aAAa,KAAK,SAAS,KAAK,KAAK;EACtD,KAAK,UAAU,IAAI,eAAe,KAAK,SAAS,KAAK,KAAK;;;;;;;;;CAS3D,OAAO,cAAc,MAAM,eAAe,kBAAkB;EAC3D,IAAI,MAAM,OAAO;EACjB,MAAM,MAAM,iBAAiB,QAAQ,IAAI;EACzC,IAAI,kBAAkB,OAAO;GAC5B,MAAM;GACN,OAAO;GACP,WAAW;GACX;EACD,OAAO;GACN,MAAM;GACN;GACA;;CAEF,IAAI,gBAAgB;EACnB,OAAO,KAAK;;CAEb,IAAI,MAAM;EACT,OAAO,KAAK;;CAEb,IAAI,WAAW;EACd,OAAO,KAAK;;CAEb,IAAI,QAAQ;EACX,OAAO,KAAK;;CAEb,IAAI,aAAa;EAChB,OAAO,KAAK;;CAEb,IAAI,kBAAkB;EACrB,OAAO,KAAK;;CAEb,IAAI,MAAM;EACT,OAAO,KAAK;;CAEb,IAAI,OAAO;EACV,OAAO,KAAK;;CAEb,IAAI,SAAS;EACZ,OAAO,KAAK;;;;;AC90Bd,SAAgB,iBAAiB,SAAiD;CAChF,MAAM,WAAW,SAAS,YAAY;CACtC,MAAM,QACJ,SAAS,SACR,QAAQ,IAAI,gBAAgB,aAAa,EAAE,MAAM,IAClD;CAEF,QAAA,GAAA,KAAA,SACE,EACE,OACD,GAAA,GAAA,YAAA,YACU;EACT;EACA,cAAc;EACd,aAAa;EACd,CAAC,CACH;;;;;;;;ACbH,SAAgB,WAAW,MAAqB;CAC9C,QAAQ,IAAI,KAAK,UAAU,KAAK,CAAC;;;;;;AAOnC,SAAgB,gBAAgB,OAAgB,WAAmB,GAAU;CAC3E,QAAQ,IAAI,KAAK,UAAU,EACzB,OAAO,aAAa,MAAM,EAC3B,CAAC,CAAC;CACH,QAAQ,KAAK,SAAS;;;;ACfxB,MAAaQ,yBAAuB;AACpC,MAAaC,qBAAmB;;;ACahC,MAAM,WAAW;AACjB,MAAM,YAAY;;;;;;AAOlB,eAAsB,gBACpB,WAAmB,QAAQ,KAAK,EACH;CAC7B,IAAI,MAAM;CACV,MAAM,QAAA,GAAA,UAAA,OAAa,IAAI,CAAC;CAExB,OAAO,MAAM;EACX,MAAM,aAAA,GAAA,UAAA,MAAiB,KAAK,UAAU,UAAU;EAChD,IAAI;GACF,MAAM,SAAS,KAAK,MAAM,OAAA,GAAA,iBAAA,UAAe,WAAW,OAAO,CAAC;GAC5D,IAAI,UAAU,OAAO,OAAO,cAAc,YAAY,OAAO,UAAU,SAAS,GAC9E,OAAO;UAEH;EAGR,MAAM,UAAA,GAAA,UAAA,SAAiB,IAAI;EAC3B,IAAI,WAAW,OAAO,QAAQ,MAAM;EACpC,MAAM;;CAER,OAAO;;;AAIT,eAAsB,iBACpB,MACA,MAAc,QAAQ,KAAK,EACV;CACjB,MAAM,WAAA,GAAA,UAAA,MAAe,KAAK,SAAS;CACnC,OAAA,GAAA,iBAAA,OAAY,SAAS,EAAE,WAAW,MAAM,CAAC;CACzC,MAAM,QAAA,GAAA,UAAA,MAAY,SAAS,UAAU;CACrC,OAAA,GAAA,iBAAA,WAAgB,MAAM,KAAK,UAAU,MAAM,MAAM,EAAE,GAAG,MAAM,OAAO;CACnE,OAAO;;ACzBT,SAAgB,sBAA8B;CAC5C,MAAM,MAAM,QAAQ,IAAI,iBAAiB,MAAM;CAC/C,IAAI,OAAO,IAAI,SAAS,GACtB,QAAA,GAAA,UAAA,MAAY,KAAK,OAAO;CAE1B,MAAM,UAAU,QAAQ,IAAI,SAAS,MAAM;CAC3C,IAAI,QAAQ,aAAa,WAAW,WAAW,QAAQ,SAAS,GAC9D,QAAA,GAAA,UAAA,MAAY,SAAS,OAAO;CAE9B,QAAA,GAAA,UAAA,OAAA,GAAA,QAAA,UAAqB,EAAE,WAAW,OAAO;;AAG3C,SAAgB,kBAA0B;CACxC,QAAA,GAAA,UAAA,MAAY,qBAAqB,EAAE,mBAAmB;;;;;;AAOxD,eAAsB,kBAA+C;CACnE,MAAM,OAAO,iBAAiB;CAC9B,IAAI;CACJ,IAAI;EACF,MAAM,OAAA,GAAA,iBAAA,UAAe,MAAM,QAAQ;UAC5B,GAAY;EACnB,IAAI,WAAW,EAAE,EAAE,OAAO;EAC1B,MAAM;;CAER,IAAI;CACJ,IAAI;EACF,SAAS,KAAK,MAAM,IAAI;SAClB;EACN,OAAO;;CAET,IAAI,OAAO,YAAA,KAAmC,OAAO,OAAO,iBAAiB,UAC3E,OAAO;CAET,OAAO;;AAGT,eAAsB,iBAAiB,OAAmC;CACxE,MAAM,OAAO,iBAAiB;CAE9B,OAAA,GAAA,iBAAA,QAAA,GAAA,UAAA,SADuB,KACL,EAAE;EAAE,WAAW;EAAM,MAAM;EAAO,CAAC;CAKrD,IAAI,OAAO;CACX,IAAI;EAEF,QAAO,OAAA,GAAA,iBAAA,MADqB,KAAK,EACjB,OAAO;UAChB,GAAY;EACnB,IAAI,CAAC,WAAW,EAAE,EAAE,MAAM;;CAI5B,MAAM,MAAM,GAAG,KAAK,OAAO,QAAQ,IAAI,GAAG,KAAK,KAAK;CACpD,OAAA,GAAA,iBAAA,WAAgB,KAAK,KAAK,UAAU,OAAO,MAAM,EAAE,EAAE;EAAE;EAAM,MAAM;EAAM,CAAC;CAC1E,OAAA,GAAA,iBAAA,QAAa,KAAK,KAAK;;AAGzB,eAAsB,oBAAsC;CAC1D,MAAM,OAAO,iBAAiB;CAC9B,IAAI;EACF,OAAA,GAAA,iBAAA,MAAW,KAAK;UACT,GAAY;EACnB,IAAI,WAAW,EAAE,EAAE,OAAO;EAC1B,MAAM;;CAER,OAAA,GAAA,iBAAA,IAAS,MAAM,EAAE,OAAO,MAAM,CAAC;CAC/B,OAAO;;AAGT,SAAS,WAAW,GAAqB;CACvC,OACE,OAAO,MAAM,YACb,MAAM,QACN,UAAU,KACT,EAAwB,SAAS;;;;ACpGtC,MAAa,gBAAgB;AAC7B,MAAa,YAAY;AAEzB,MAAM,uBAAuB;AAC7B,MAAM,wBAAwB;AAC9B,MAAM,iBAAiB;AACvB,MAAM,mBAAmB;AAYzB,IAAa,kBAAb,cAAqC,MAAM;CACzC,YAAY,MAA8B,SAAiB;EACzD,MAAM,QAAQ;EADY,KAAA,OAAA;;;AAK9B,SAASC,YAAU,KAAqB;CACtC,OAAO,IAAI,QAAQ,QAAQ,GAAG;;AAGhC,eAAsB,eACpB,QACA,QAAgB,WACa;CAC7B,MAAM,MAAM,GAAGA,YAAU,OAAO,GAAG;CACnC,MAAM,MAAM,MAAM,MAAM,KAAK;EAC3B,QAAQ;EACR,SAAS,EAAE,gBAAgB,oBAAoB;EAC/C,MAAM,KAAK,UAAU;GAAE,WAAW;GAAe;GAAO,CAAC;EAC1D,CAAC;CACF,IAAI,CAAC,IAAI,IAAI;EACX,MAAM,OAAQ,MAAM,SAAS,IAAI,IAAK,EAAE;EACxC,MAAM,IAAI,gBACR,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,QAAQ,IAAI,UAC1D,OAAO,KAAK,sBAAsB,WAC9B,KAAK,oBACL,wCAAwC,IAAI,OAAO,GACxD;;CAEH,OAAQ,MAAM,IAAI,MAAM;;;;;;AAO1B,eAAsB,WACpB,QACA,YACA,OAAoB,EAAE,EACQ;CAC9B,IAAI,kBAAkB,KAAK,IAAI,GAAG,KAAK,mBAAmB,EAAE;CAC5D,MAAM,aAAa,KAAK,kBAAkB,OAAO;CACjD,MAAM,WAAW,KAAK,KAAK,GAAG;CAE9B,OAAO,MAAM;EACX,IAAI,KAAK,KAAK,GAAG,UACf,MAAM,IAAI,gBAAgB,iBAAiB,sCAAsC;EAEnF,MAAM,MAAM,GAAGA,YAAU,OAAO,GAAG;EACnC,MAAM,MAAM,MAAM,MAAM,KAAK;GAC3B,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,MAAM,KAAK,UAAU;IACnB,YAAY;IACZ,aAAa;IACb,WAAW;IACZ,CAAC;GACH,CAAC;EACF,IAAI,IAAI,IAAI;GACV,MAAM,OAAQ,MAAM,IAAI,MAAM;GAC9B,IAAI,CAAC,KAAK,cACR,MAAM,IAAI,gBAAgB,gBAAgB,6CAA6C;GAKzF,KAAK,WAAW,IAAI,QAAQ,IAAI,kBAAkB;GAClD,OAAO;;EAET,MAAM,OAAQ,MAAM,SAAS,IAAI,IAAK,EAAE;EACxC,MAAM,OACJ,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,QAAQ,IAAI;EAE5D,MAAM,cAAc,OAAO,KAAK,sBAAsB,WAAW,KAAK,oBAAoB;EAC1F,IAAI,SAAS,yBAAyB;GACpC,KAAK,UAAU;GACf,MAAM,MAAM,kBAAkB,IAAK;GACnC;;EAEF,IAAI,SAAS,aAAa;GACxB,mBAAmB;GACnB,MAAM,MAAM,kBAAkB,IAAK;GACnC;;EAGF,MAAM,IAAI,gBAAgB,MAAM,YAAY;;;;;;;AAQhD,eAAsB,cAAc,QAAgB,cAAuC;CACzF,MAAM,MAAM,GAAGA,YAAU,OAAO,GAAG;CACnC,MAAM,MAAM,MAAM,MAAM,KAAK;EAC3B,QAAQ;EACR,SAAS,EAAE,eAAe,UAAU,gBAAgB;EACrD,CAAC;CACF,IAAI,IAAI,WAAW,KACjB,MAAM,IAAI,gBAAgB,iBAAiB,6BAA6B;CAE1E,IAAI,CAAC,IAAI,IAAI;EACX,MAAM,OAAQ,MAAM,SAAS,IAAI,IAAK,EAAE;EACxC,MAAM,IAAI,gBACR,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,QAAQ,IAAI,UAC1D,gCAAgC,IAAI,OAAO,GAC5C;;CAEH,MAAM,OAAQ,MAAM,IAAI,MAAM;CAC9B,IAAI,CAAC,KAAK,OACR,MAAM,IAAI,gBAAgB,gBAAgB,wCAAwC;CAEpF,OAAO,KAAK;;;AAId,eAAsB,aAAa,QAAgB,cAA4C;CAC7F,MAAM,MAAM,GAAGA,YAAU,OAAO,GAAG;CACnC,MAAM,MAAM,MAAM,MAAM,KAAK;EAC3B,QAAQ;EACR,SAAS,EAAE,eAAe,UAAU,gBAAgB;EACrD,CAAC;CACF,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,gBAAgB,QAAQ,IAAI,UAAU,4BAA4B,IAAI,OAAO,GAAG;CAG5F,MAAM,QAAO,MADO,IAAI,MAAM,GACX;CACnB,IAAI,CAAC,MAAM,IACT,MAAM,IAAI,gBAAgB,gBAAgB,gCAAgC;CAE5E,OAAO;EAAE,IAAI,KAAK;EAAI,OAAO,KAAK,SAAS;EAAI;;;;;;;AAQjD,SAAgB,aAAa,KAA4B;CACvD,MAAM,QAAQ,IAAI,MAAM,IAAI;CAC5B,IAAI,MAAM,SAAS,GAAG,OAAO;CAC7B,IAAI;EACF,MAAM,OAAO,OAAO,KAAK,MAAM,IAAI,YAAY,CAAC,SAAS,QAAQ;EACjE,MAAM,UAAU,KAAK,MAAM,KAAK;EAChC,IAAI,OAAO,QAAQ,QAAQ,UAAU,OAAO;EAC5C,wBAAO,IAAI,KAAK,QAAQ,MAAM,IAAK,EAAC,aAAa;SAC3C;EACN,OAAO;;;AAIX,MAAM,UAAU;;;;;;AAOhB,SAAgB,yBAAyB,UAAyC;CAChF,IAAI,CAAC,UAAU,OAAO;CACtB,IAAI;EAEF,MAAM,MADM,KAAK,MAAM,SACR,EAAE;EACjB,OAAO,OAAO,QAAQ,YAAY,QAAQ,KAAK,IAAI,GAAG,MAAM;SACtD;EACN,OAAO;;;AAIX,eAAe,SAAS,KAAwD;CAC9E,IAAI;EACF,OAAQ,MAAM,IAAI,MAAM;SAClB;EACN,OAAO;;;AAIX,SAAS,MAAM,IAA2B;CACxC,OAAO,IAAI,SAAS,MAAM,WAAW,GAAG,GAAG,CAAC;;;;AC3M9C,MAAM,kBAAkB;;;;;;;;AASxB,SAAgB,cAAkC;CAChD,MAAM,MAAM,QAAQ,IAAI,gBAAgB,MAAM;CAC9C,IAAI,CAAC,KAAK,OAAO,KAAA;CACjB,MAAM,IAAI,OAAO,SAAS,KAAK,GAAG;CAClC,OAAO,OAAO,SAAS,EAAE,GAAG,IAAI,KAAA;;;;;;;;AASlC,SAAgB,eAAe,YAA6B;CAC1D,OAAO,YAAY,MAAM,IAAI,QAAQ,IAAI,eAAe,MAAM,IAAA;;;;;;;;;;;AAYhE,eAAsB,YAAY,MAAyC;CACzE,MAAM,QAAQ,MAAM,iBAAiB;CACrC,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,2CAA2C;CAG7D,IAAI,YAAY,KAAK;CACrB,IAAI,CAAC,aAAa,UAAU,WAAW,GACrC,aAAa,MAAM,iBAAiB,GAAG;CAEzC,IAAI,CAAC,aAAa,UAAU,WAAW,GACrC,MAAM,IAAI,MACR,uFAED;CAIH,OAAO;EACL,SAAQ,MAFY,gBAAgB,MAAM,EAE1B;EAChB,SAAS,eAAe,KAAK,QAAQ;EACrC,MAAM,KAAK,QAAQ,aAAa;EAChC;EACD;;;;;;AAOH,eAAsB,iBAAiB,MAG0B;CAC/D,MAAM,QAAQ,MAAM,iBAAiB;CACrC,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,2CAA2C;CAG7D,OAAO;EACL,SAAQ,MAFY,gBAAgB,MAAM,EAE1B;EAChB,SAAS,eAAe,KAAK,QAAQ;EACrC,MAAM,KAAK,QAAQ,aAAa;EACjC;;;;;;;;;;;;;AAcH,eAAsB,gBAAgB,OAA0C;CAC9E,MAAM,QAAQ,IAAI,KAAK,MAAM,qBAAqB,CAAC,SAAS;CAE5D,IAAI,EADe,CAAC,OAAO,SAAS,MAAM,IAAI,QAAQ,KAAK,KAAK,IAAI,kBAElE,OAAO;CAGT,MAAM,OAAoB,EAAE,GAAG,OAAO;CACtC,IAAI;EACF,MAAM,MAAM,MAAM,cAAc,MAAM,QAAQ,MAAM,aAAa;EACjE,KAAK,cAAc;EACnB,KAAK,uBAAuB,aAAa,IAAI,qBAAI,IAAI,MAAM,EAAC,aAAa;UAClE,GAAG;EACV,IAAI,aAAa,mBAAmB,EAAE,SAAS,iBAC7C,MAAM,IAAI,MAAM,0CAA0C;EAE5D,MAAM;;CAER,KAAK,8BAAa,IAAI,MAAM,EAAC,aAAa;CAC1C,MAAM,iBAAiB,KAAK;CAC5B,OAAO;;;;;;;;;AC7GT,eAAsB,mBAAmB,MAA0C;CACjF,MAAM,OAAO,MAAM,YAAY,KAAK;CACpC,OAAO,IAAI,cAAc;EACvB,SAAS,KAAK;EACd,MAAM,KAAK;EAGX,MAAM;GAAE,MAAM;GAAa,OAAO,KAAK;GAAQ,WAAW,KAAK;GAAW;EAC3E,CAAC;;;;ACTJ,MAAMC,WAAS,kBAAkB;AAoBjC,MAAM,wBAAwC;;;;;;AAO9C,SAAS,mBAAmB,SAI1B;CACA,MAAM,UAAU,QAAQ,GAAG,GAAG;CAG9B,OAAO;EAAE,aAFW,QAAQ,MAAM,GAAG,GAEjB;EAAE;EAAS,MADlB,QAAQ,iBACc;EAAE;;;;;;;AAQvC,SAAS,gBACP,MACA,MACA,aACe;CACf,OAAO,MAAM,CAAC,OAAO,UAAmB;EACtC,MAAM,OAAO,YAAY,MAAM;EAC/B,IAAI,KAAK,MAEP,gBAAgB,OAAO,KAAK;EAE9B,SAAO,MAAM,aAAa,MAAM,CAAC;EACjC,QAAQ,KAAK,KAAK;GAClB;;;;;;;;;;;;;AAyBJ,MAAa,qBAET,QACA,cAA8B,oBAE9B,OAAO,GAAG,YAAsC;CAC9C,MAAM,EAAE,aAAa,SAAS,mBAAmB,QAAQ;CACzD,MAAM,gBACJ,YAAY;EAMV,MAAM,OAAO,MALQ,mBAAmB;GACtC,WAAW,KAAK;GAChB,SAAS,KAAK;GACd,MAAM,KAAK;GACZ,CAAC,EACmB,GAAI,aAAmB,KAAK;IAEnD,MACA,YACD;;;;;;;;AASP,MAAa,iBAET,QACA,cAA8B,oBAE9B,OAAO,GAAG,YAAsC;CAC9C,MAAM,EAAE,aAAa,SAAS,mBAAmB,QAAQ;CACzD,MAAM,gBACJ,YAAY;EACV,MAAM,QAAQ,MAAM,iBAAiB;GACnC,SAAS,KAAK;GACd,MAAM,KAAK;GACZ,CAAC;EAUF,MAAM,OAAO,IATM,cAAc;GAC/B,SAAS,MAAM;GAGf,MAAM,MAAM;GAGZ,MAAM;IAAE,MAAM;IAAa,OAAO,MAAM;IAAQ,WAAW;IAAI;GAChE,CACkB,EAAE,GAAI,aAAmB,KAAK;IAEnD,MACA,YACD;;;;ACtIP,MAAMC,WAAS,kBAAkB;;;;AAKjC,MAAM,mBAAmB,SAA0B;CACjD,MAAM,MAAM,KAAK,QAAQ,KAAK,CAAC,aAAa;CAC5C,OAAO;EAAC;EAAS;EAAQ;EAAS,CAAC,SAAS,IAAI;;;;;;AAOlD,MAAa,eAAe,OAC1B,OACA,YAAqB,UACC;CACtB,MAAM,iBAA2B,EAAE;CAEnC,KAAK,MAAM,YAAY,OACrB,IAAI;EACF,MAAM,QAAQ,MAAMC,YAAG,KAAK,SAAS;EAErC,IAAI,MAAM,QAAQ,EAChB,IAAI,gBAAgB,SAAS,EAC3B,eAAe,KAAK,SAAS;OAE7B,SAAO,KAAK,mCAAmC,WAAW;OAEvD,IAAI,MAAM,aAAa,EAAE;GAC9B,MAAM,UAAU,MAAMA,YAAG,QAAQ,SAAS;GAE1C,KAAK,MAAM,SAAS,SAAS;IAC3B,MAAM,WAAW,KAAK,KAAK,UAAU,MAAM;IAC3C,MAAM,aAAa,MAAMA,YAAG,KAAK,SAAS;IAE1C,IAAI,WAAW,QAAQ,IAAI,gBAAgB,SAAS,EAClD,eAAe,KAAK,SAAS;SACxB,IAAI,aAAa,WAAW,aAAa,EAAE;KAChD,MAAM,WAAW,MAAM,aAAa,CAAC,SAAS,EAAE,KAAK;KACrD,eAAe,KAAK,GAAG,SAAS;;;;UAI/B,OAAO;EACd,SAAO,KACL,6CAA6C,SAAS,WAC1C,aAAa,MAAM,GAChC;;CAIL,OAAO;;;;;AAMT,MAAM,eAAe,OAAO,aAAqC;CAC/D,MAAM,UAAU,MAAMA,YAAG,SAAS,UAAU,QAAQ;CACpD,MAAM,SAAS,KAAK,MAAM,QAAQ;CAClC,OAAO,MAAM,QAAQ,OAAO,GAAG,SAAS,CAAC,OAAO;;;;;AAMlD,MAAM,gBAAgB,YAAyB;CAE7C,IAAI,OAAO,YAAY,UACrB,OAAO;CAIT,MAAM,UAAU,QAAQ,MAAM;CAC9B,IAAI,CAAC,QAAQ,WAAW,IAAI,IAAI,CAAC,QAAQ,WAAW,IAAI,EACtD,OAAO;CAGT,IAAI;EACF,OAAO,KAAK,MAAM,QAAQ;UACnB,OAAO;EACd,SAAO,MACL,uBAAuB,aAAa,MAAM,GAC3C;EACD,OAAO;;;;;;AAOX,MAAM,eAAe,QAAqC;CACxD,MAAM,SAAc,EAAE;CACtB,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,EAC5C,OAAO,OAAO,aAAa,MAAM;CAEnC,OAAO;;;;;AAMT,MAAM,cAAc,OAAO,aAAqC,IAAI,SAAS,SAAS,WAAW;CAC/F,MAAM,UAAiB,EAAE;CACzB,CAAA,GAAA,GAAA,kBAAiB,SAAS,CACvB,MAAA,GAAA,WAAA,UAAU,CAAC,CACX,GAAG,SAAS,SAAS,QAAQ,KAAK,YAAY,KAAK,CAAC,CAAC,CACrD,GAAG,aAAa,QAAQ,QAAQ,CAAC,CACjC,GAAG,SAAS,OAAO;EACtB;;;;AAKF,eAAe,cAAc,UAAkC;CAI7D,QAFc,MADQA,YAAG,SAAS,UAAU,QAAQ,EAC9B,MAAM,KAAK,CAAC,QAAQ,SAAS,KAAK,MAAM,CAElD,CAAC,KAAK,SAAS,KAAK,MAAM,KAAK,CAAC;;;;;AAM9C,eAAeC,WAAS,UAAkC;CACxD,MAAM,MAAM,KAAK,QAAQ,SAAS,CAAC,aAAa;CAEhD,IAAI,QAAQ,SACV,OAAO,aAAa,SAAS;MACxB,IAAI,QAAQ,QACjB,OAAO,YAAY,SAAS;MACvB,IAAI,QAAQ,UACjB,OAAO,cAAc,SAAS;MAE9B,MAAM,IAAI,MAAM,0BAA0B,MAAM;;;;;AAOpD,MAAa,gBAAgB,OAC3B,OACA,YAAqB,UACU;CAC/B,MAAM,QAAQ,MAAM,aAAa,OAAO,UAAU;CAElD,IAAI,MAAM,WAAW,GAAG;EACtB,SAAO,KAAK,kDAAkD;EAC9D,OAAO,EAAE;;CAGX,SAAO,KAAK,SAAS,MAAM,OAAO,kBAAkB;CAEpD,MAAM,SAA4B,EAAE;CAEpC,KAAK,MAAM,QAAQ,OACjB,IAAI;EACF,MAAM,OAAO,MAAMA,WAAS,KAAK;EACjC,OAAO,KAAK,GAAG,KAAK;EACpB,SAAO,KAAK,QAAQ,KAAK,OAAO,kBAAkB,OAAO;UAClD,OAAO;EACd,SAAO,MACL,sBAAsB,KAAK,IAAI,aAAa,MAAM,GACnD;EACD,MAAM;;CAIV,OAAO;;;;;AAMT,MAAM,gBAAgB,OACpB,UACA,SACkB;CAClB,MAAM,UAAU,KAAK,UAAU,MAAM,MAAM,EAAE;CAC7C,MAAMD,YAAG,UAAU,UAAU,SAAS,QAAQ;;;;;AAMhD,MAAM,aAAmB,SAAoC;CAC3D,MAAM,gBAAgB,KAAK,KAAI,SAC7B,OAAO,YAAY,OAAO,QAAQ,KAAK,CAAC,KAAK,CAAC,KAAK,WAAW,CAAC,KAAK,gBAAgB,MAAM,CAAC,CAAC,CAC3F,CAAC;CAIJ,QAAA,GAAA,cAAA,WAAA,GAAA,cAAA,cAAA,GAAA,cAAA,UAF2B,EAAE,kBAAkB,MAAM,CACd,CAAC,CAAC,cAChB,CAAC;;;;;AAM5B,MAAM,eAAe,OACnB,UACA,SACkB;CAClB,IAAI,KAAK,WAAW,GAClB,MAAM,IAAI,MAAM,0BAA0B;CAG5C,MAAMA,YAAG,UAAU,UAAU,UAAU,KAAK,EAAE,QAAQ;;;;;AAMxD,MAAM,iBAAiB,OACrB,UACA,SACkB;CAClB,MAAM,QAAQ,KAAK,KAAK,SAAS,KAAK,UAAU,KAAK,CAAC,CAAC,KAAK,KAAK;CACjE,MAAMA,YAAG,UAAU,UAAU,QAAQ,MAAM,QAAQ;;;;;AAMrD,MAAa,cAAc,OACzB,UACA,MACA,WACkB;CAElB,MAAM,MAAM,KAAK,QAAQ,SAAS;CAClC,MAAMA,YAAG,MAAM,KAAK,EAAE,WAAW,MAAM,CAAC;CAGxC,MAAM,MAAM,UAAU,KAAK,QAAQ,SAAS,CAAC,MAAM,EAAE;CAErD,IAAI,UAAU,WAAW,KAAK,QAAQ,SAAS,CAAC,MAAM,EAAE,EACtD,SAAO,KACL,iBAAiB,OAAO,iCAAiC,KAAK,QAAQ,SAAS,CAAC,MAAM,EAAE,GACzF;CAGH,IAAI,QAAQ,QACV,MAAM,cAAc,UAAU,KAAK;MAC9B,IAAI,QAAQ,OACjB,MAAM,aAAa,UAAU,KAAK;MAC7B,IAAI,QAAQ,SACjB,MAAM,eAAe,UAAU,KAAK;MAEpC,MAAM,IAAI,MAAM,8BAA8B,MAAM;;;;;;;;AAUxD,MAAM,mBAAmB,UAAuB;CAC9C,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;CAET,IAAI,OAAO,UAAU,UACnB,OAAO;CAET,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,WAChD,OAAO,OAAO,MAAM;CAGtB,OAAO,KAAK,UAAU,MAAM;;;;;AAM9B,MAAa,kBACX,MACA,SAAmC,WAChC;CACH,IAAI,WAAW,QACb,QAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;MACrC,IAAI,WAAW,OAAO;EAC3B,IAAI,KAAK,WAAW,GAAG;GACrB,SAAO,MAAM,mBAAmB;GAChC;;EAGF,QAAQ,IAAI,UAAU,KAAK,CAAC;QACvB,IAAI,WAAW,SACpB,KAAK,SAAS,SAAS,QAAQ,IAAI,KAAK,UAAU,KAAK,CAAC,CAAC;MAEzD,MAAM,IAAI,MACR,8BAA8B,OAAO,OAAO,CAAC,yCAE9C;;;;AChTL,MAAM,yBAAyB;AAC/B,MAAM,gBAAgB;AAEtB,MAAM,gBAAgB;CACpB,KAAK;CAAI,WAAW;CAAI,YAAY;CAAI,aAAa;CACrD,QAAQ;CAAI,cAAc;CAAI,eAAe;CAAI,gBAAgB;CACjE,MAAM;CAAI,YAAY;CAAI,KAAK;CAAI,WAAW;CAC9C,OAAO;CAAI,aAAa;CAAI,QAAQ;CACrC;AAED,SAAS,mBAA2B;CAClC,OAAO,QAAQ,OAAO,WAAW;;;;;;AAOnC,SAAS,gBACP,eACA,eACsB;CAEtB,MAAM,WAAW,cAAc,SAAS;CACxC,MAAM,oBAAoB,cAAc,QAAQ,KAAK,MAAM,MAAM,GAAG,EAAE;CAEtE,IAAI,oBAAoB,YAAY,eAClC;CAGF,MAAM,mBAAmB,gBAAgB;CACzC,MAAM,cAAc;CAGpB,OAAO,cAAc,KAAK,MACxB,KAAK,IACH,cAAc,eACd,KAAK,MAAO,IAAI,oBAAqB,iBAAiB,GAAG,cAC1D,CACF;;AAGH,SAAS,SAAS,KAAa,QAAwB;CACrD,IAAI,SAAS,GAAG,OAAO;CACvB,IAAI,IAAI,UAAU,QAAQ,OAAO;CACjC,OAAO,IAAI,MAAM,GAAG,SAAS,EAAE,GAAG;;;;;;AAOpC,SAAgB,YAAY,MAAgB,MAA0B;CACpE,MAAM,gBAAgB,kBAAkB;CAMxC,MAAM,YAAY,gBAJI,KAAK,KAAK,GAAG,MACjC,KAAK,QAAQ,KAAK,QAAQ,KAAK,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,EAAE,EAAE,OAAO,CAG5B,EAAE,cAAc;CAM/D,MAAM,QAAQ,IAAIE,WAAAA,QAAM;EACtB,MALoB,YAClB,KAAK,KAAK,GAAG,MAAM,SAAS,GAAG,UAAU,KAAK,cAAc,CAAC,GAC7D;EAIF,OAAO;EACP,OAAO;GACL,gBAAgB;GAChB,iBAAiB;GAClB;EACD,GAAI,aAAa,EAAE,WAAW;EAC/B,CAAC;CAEF,IAAI,WACF,KAAK,MAAM,OAAO,MAChB,MAAM,KAAK,IAAI,KAAK,MAAM,MAAM,SAAS,MAAM,UAAU,KAAK,cAAc,CAAC,CAAC;MAGhF,KAAK,MAAM,OAAO,MAChB,MAAM,KAAK,IAAI;CAInB,OAAO,MAAM,UAAU;;;;AC9EzB,MAAMC,WAAS,kBAAkB;AACjC,MAAM,kCAAkC;AACxC,MAAM,kCAAkC;;AAQxC,SAAS,wBAAwB,MAAgD;CAC/E,IAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,IACtB,MAAM,IAAI,MAAM,qCAAqC;CAEvD,IAAI,KAAK,QAAQ,KAAK,IACpB,MAAM,IAAI,MAAM,0CAA0C;;;;;AAO9D,MAAM,cAAc,OAClB,QACA,YACA,YAAoB,iCACpB,SAAiB,GACjB,UAC+B;CAC/B,IAAI,UAAU;CACd,IAAI,gBAAgB;CACpB,MAAM,SAAS,UAAU,KAAA,IAAY,SAAS,QAAQ,KAAA;CAEtD,MAAM,SAA4B,EAAE;CAEpC,OAAO,YAAY,WAAW,KAAA,KAAa,gBAAgB,SAAS;EAClE,MAAM,OAAO,MAAM,OAAO,SAAS,KAAW;GAC5C,GAAG;GACH,QAAQ;GACR,OAAO;GACR,CAAC;EAEF,OAAO,KAAK,GAAG,KAAK,MAAM;EAG1B,IAAI,KAAK,MAAM,WAAW,KAAK,KAAK,MAAM,SAAS,WACjD,UAAU;OACL,IAAI,WAAW,KAAA,KAAa,gBAAgB,aAAa,QAC9D,UAAU;OACL,IAAI,KAAK,eAAe,KAAA,KAAa,gBAAgB,aAAa,KAAK,YAC5E,UAAU;EAGZ,iBAAiB;;CAGnB,IAAI,UAAU,KAAA,GACZ,OAAO,OAAO,MAAM,GAAG,MAAM;CAG/B,OAAO;;;;;;AAOT,MAAa,qBAAqB,OAChC,QACA,SACkB;CAClB,MAAM,WAAW,MAAM,OAAO,SAAS,cAAc;CAErD,IAAI,KAAK,MAAM;EACb,WAAW,SAAS;EACpB;;CAGF,IAAI,SAAS,WAAW,GAAG;EACzB,QAAQ,IAAI,qBAAqB;EACjC;;CAGF,MAAM,OAAO,SAAS,KAAK,YAAY;EAErC,MAAM,eAAe,IADC,KAAK,QAAQ,UACL,CAAC,aAAa,CAAC,QAAQ,KAAK,IAAI,CAAC,UAAU,GAAG,GAAG;EAC/E,OAAO;GAAC,QAAQ;GAAI;GAAc,QAAQ;GAAK;GAC/C;CAEF,QAAQ,IAAI,YAAY;EAAC;EAAM;EAAc;EAAO,EAAE,KAAK,CAAC;CAC5D,QAAQ,IAAI,YAAY,SAAS,OAAO,eAAe;;;;;AAMzD,MAAa,qBAAqB,OAChC,QACA,OACA,SAIkB;CAClB,wBAAwB,KAAK;CAE7B,MAAM,OAAO,MAAM,cAAc,OAAO,KAAK,UAAU;CAEvD,IAAI,KAAK,WAAW,GAClB,MAAM,IAAI,MAAM,kBAAkB;CAGpC,MAAM,aAAa,KAAK,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK,IAAI;CAEpE,MAAM,SAAS,MAAM,OAAO,SAAS,KAAK;EACxC,QAAQ;EACR,GAAG;EACH,WAAW,KAAK,aAAa;EAC9B,CAAC;CAEF,IAAI,KAAK,MAAM;EACb,WAAW;GAAE,WAAW,QAAQ;GAAW,OAAO,KAAK;GAAQ,CAAC;EAChE;;CAGF,SAAO,KAAK,UAAU,KAAK,OAAO,0BAA0B,KAAK,QAAQ,KAAK,KAAK;;;;;AAMrF,MAAa,qBAAqB,OAChC,QACA,YACA,SAMkB;CAClB,wBAAwB,KAAK;CAI7B,MAAM,SAAS,MAAM,YACnB,QAHiB,KAAK,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK,IAAI,EAKlE,KAAK,aAAa,iCAClB,KAAK,UAAU,GACf,KAAK,MACN;CAED,IAAI,YAAY;EACd,MAAM,YAAY,YAAY,QAAQ,KAAK,aAAa;EACxD,IAAI,KAAK,MACP,WAAW;GAAE,MAAM;GAAY,OAAO,OAAO;GAAQ,CAAC;OAEtD,SAAO,KAAK,uBAAuB,OAAO,OAAO,kBAAkB,aAAa;QAGlF,IAAI,KAAK,MACP,WAAW,OAAO;MAElB,eAAe,QAAQ,KAAK,gBAAgB,OAAO;;;;;AAQzD,MAAa,uBAAuB,OAClC,QACA,MACA,OACA,SAMkB;CAElB,MAAM,OAAO,MAAM,cAAc,OAAO,KAAK,UAAU;CAEvD,IAAI,KAAK,WAAW,GAClB,MAAM,IAAI,MAAM,kBAAkB;CAIpC,SAAO,KAAK,WAAW,KAAK,OAAO,2BAA2B,KAAK,MAAM;CAEzE,MAAM,OAAO,SAAS,KAAK;EACzB,QAAQ;EACR;EACA,WAAW,KAAK,aAAa;EAC7B,eAAe;EAChB,CAAC;CACF,SAAO,KAAK,uBAAuB,KAAK,OAAO,2BAA2B,KAAK,GAAG;CAGlF,SAAO,KAAK,8BAA8B,KAAK,MAAM;CAErD,MAAM,SAAS,MAAM,YACnB,QACA,EAAE,MAAM,EACR,KAAK,aAAa,iCAClB,GACA,KAAA,EACD;CAGD,MAAM,YAAY,KAAK,YAAY,QAAQ,KAAK,aAAa;CAE7D,IAAI,KAAK,MACP,WAAW;EAAE;EAAM,MAAM,KAAK;EAAY,OAAO,OAAO;EAAQ,CAAC;MAEjE,SAAO,KACL,iCAAiC,KAAK,cACvB,OAAO,OAAO,iBAAiB,KAAK,aACpD;;;;ACnOL,MAAa,oBAAoB;;;;;;AAOjC,MAAa,oBAAoB,YAA4B;CAC3D,MAAM,KAAK,QAAQ,MAAM,CAAC,aAAa,CAAC,QAAQ,OAAO,GAAG;CAC1D,IAAI,iEAAiE,KAAK,GAAG,EAC3E,OAAO;CAET,IAAI,iBAAiB,KAAK,GAAG,EAC3B,OAAO,GAAG,QACR,wEACA,iBACD;CAEH,MAAM,IAAI,MACR,qBAAqB,QAAQ,oDAC9B;;;;;;;AAQH,MAAa,wBAAwB,aAA8B;CACjE,IAAI,SAAkB;CACtB,IAAI,OAAO,aAAa,UAAU;EAChC,IAAI,aAAa,IACf,OAAO;EAET,IAAI;GACF,SAAS,KAAK,MAAM,SAAS;UACvB;GACN,OAAO;;;CAGX,IAAI,OAAO,WAAW,YAAY,WAAW,MAC3C,OAAO;CAET,MAAM,OAAQ,OAAmC;CACjD,OAAO,OAAO,SAAS,WAAW,OAAO;;;;ACxC3C,MAAMC,WAAS,kBAAkB;;;;;;;;;AAUjC,MAAa,4BAA4B,OACvC,QACA,WACA,MACA,SACkB;CAClB,MAAM,OAAO,gBAAgB,QAAQ;EAAE;EAAW;EAAM,CAAC;CAEzD,IAAI,KAAK,MAAM;EACb,WAAW;GAAE;GAAW;GAAM,CAAC;EAC/B;;CAGF,SAAO,KAAK,uBAAuB,UAAU,OAAO,KAAK,IAAI;;;;;;;;;;;AAoB/D,MAAa,4BAA4B,OACvC,QACA,WACA,SACkB;CAYlB,MAAM,UAAgC,MATnB,OAAO,IAAI,MAC5B,0MAMA,EAAE,YAAY,WAAW,CAC1B,EAC0C,KAAK,SAAS;EACvD,MAAM,qBAAqB,IAAI,SAAS;EACxC,SAAS,OAAO,IAAI,MAAM,GAAG;EAC7B,SAAS,OAAO,IAAI,YAAY,GAAG;EACpC,EAAE;CAEH,IAAI,KAAK,MAAM;EACb,WAAW,OAAO;EAClB;;CAGF,IAAI,OAAO,WAAW,GAAG;EACvB,QAAQ,IAAI,+BAA+B,UAAU,GAAG;EACxD;;CAGF,MAAM,SAAS,OAAO,KAAK,UAAU;EACnC,MAAM,MAAM,cAAc,MAAM,QAAQ,cAAc,MAAM,QAAQ;EACpE,OAAO,MAAM,OAAO,GAAG,MAAM,KAAK,IAAI,QAAQ;GAC9C;CACF,QAAQ,IAAI,OAAO,KAAK,OAAO,CAAC;;;;AC9ElC,SAAS,WAAW,QAAqC;CACvD,IAAI,cAAc,QAAQ,KAAK,OAAO;CACtC,IAAI,iBAAiB,QAAQ,OAAO,QAAQ,IAAI,gBAAgB,KAAK,OAAO;CAC5E,OAAO,QAAQ,OAAO,MAAM;;AAI9B,MAAa,MAAA,GAAA,WAAA,cAAkB,WAAW,QAAQ,OAAO,CAAC;AAE1D,MAAa,SAAA,GAAA,WAAA,cAAqB,WAAW,QAAQ,OAAO,CAAC;AAK7D,MAAM,qBAAqB,WAAW,QAAQ,OAAO;AACrD,MAAa,UAAU,SACrB,qBAAqB,wBAAwB,KAAK,YAAY;;;ACShE,eAAsB,YAAY,SAA6C;CAC7E,MAAM,SAASC,OAAK,QAAQ,aAAa,QAAQ,IAAI,mBAAmBC,uBAAqB;CAM7F,MAAM,KAAK,MAAM,eAAe,QAAQ,UAAU;CAClD,MAAM,cAAc,GAAG,6BAA6B,GAAG;CACvD,QAAQ,OAAO,MACb,oDAAoD,GAAG,KAAK,YAAY,CAAC,IAC1E;CACD,IAAI,GAAG,WACL,QAAQ,OAAO,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,UAAU,CAAC,CAAC,MAAM;CAGrE,IAAI,CAAC,QAAQ,WACX,IAAI;EACF,OAAA,GAAA,KAAA,SAAW,YAAY;SACjB;CAKV,QAAQ,OAAO,MAAM,GAAG,IAAI,iCAAiC,CAAC;CAC9D,MAAM,QAAQ,MAAM,WAAW,QAAQ,GAAG,aAAa;EACrD,iBAAiB,GAAG;EACpB,gBAAgB,GAAG;EACpB,CAAC;CAGF,MAAM,eAAe,MAAM;CAC3B,MAAM,MAAM,MAAM,cAAc,QAAQ,aAAa;CACrD,MAAM,UAAU,MAAM,aAAa,QAAQ,aAAa;CAExD,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;CAgBpC,MAAM,iBAAiB;EAdrB,SAAS;EACT;EACA;EACA,aAAa;EACb,sBAAsB,aAAa,IAAI,IAAI;EAC3C,kBACE,OAAO,MAAM,eAAe,WACxB,IAAI,KAAK,KAAK,KAAK,GAAG,MAAM,aAAa,IAAK,CAAC,aAAa,GAC5D,KAAA;EACN,WAAW,QAAQ,SAAS,KAAA;EAC5B,QAAQ,QAAQ;EAChB,WAAW;EACX,YAAY;EAEc,CAAC;CAM7B,OAAO;EACL,QAAQ,QAAQ;EAChB,WAAW,QAAQ,SAAS;EAC5B,WAAW,yBAAyB,MAAM,SAAS;EACpD;;AAGH,SAASD,OAAK,GAAG,YAA4C;CAC3D,KAAK,MAAM,KAAK,YACd,IAAI,KAAK,EAAE,SAAS,GAAG,OAAO;CAEhC,OAAO;;;;;;;;;;ACxFT,eAAsB,cAAc,OAAmC;CACrE,IAAI,CAAC,MAAM,gBAAgB,MAAM,aAAa,WAAW,GACvD;CAEF,MAAM,MAAM,GAAGE,YAAU,MAAM,OAAO,CAAC;CACvC,IAAI;EAEF,MAAM,MAAM,MAAM,MAAM,KAAK;GAC3B,QAAQ;GACR,SAAS;IACP,eAAe,UAAU,MAAM;IAC/B,gBAAgB;IACjB;GACD,MAAM;GACP,CAAC;EACF,IAAI,CAAC,IAAI,IACP,QAAQ,OAAO,MACb,8BAA8B,IAAI,YAAY,IAAI,OAAO;EAE1D;UAEI,GAAG;EACV,MAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;EACtD,QAAQ,OAAO,MACb,8BAA8B,IAAI,WAAW,IAAI,uCAClD;;;AAIL,eAAsB,eAA8B;CAClD,MAAM,QAAQ,MAAM,iBAAiB;CACrC,IAAI,CAAC,OAAO;EACV,QAAQ,OAAO,MAAM,wBAAwB;EAC7C;;CAEF,MAAM,QAAQ,MAAM,aAAa,MAAM;CAKvC,MAAM,mBAAmB;CACzB,MAAM,cAAc,MAAM;CAC1B,QAAQ,OAAO,MAAM,iBAAiB,MAAM,YAAY,iBAAiB,CAAC,KAAK;;AAGjF,SAASA,YAAU,KAAqB;CACtC,OAAO,IAAI,QAAQ,QAAQ,GAAG;;;;;;;;;AC/ChC,MAAa,qBAAqB,OAChC,QACA,SACkB;CAClB,MAAM,WAAW,MAAM,OAAO,IAAI,cAAc;CAGhD,MAAM,UAAU,MAAM,iBAAiB,GAAG;CAE1C,IAAI,KAAK,MAAM;EACb,WAAW,SAAS,KAAK,OAAO;GAAE,GAAG;GAAG,QAAQ,EAAE,OAAO;GAAQ,EAAE,CAAC;EACpE;;CAGF,IAAI,SAAS,WAAW,GAAG;EACzB,QAAQ,IAAI,6EAA6E;EACzF;;CAGF,MAAM,UAAU;EAAC;EAAI;EAAa;EAAW;EAAa;CAC1D,MAAM,OAAO,SAAS,KAAK,MAAM;EAAC,EAAE,OAAO,SAAS,MAAM;EAAI,EAAE;EAAe,EAAE;EAAM,EAAE;EAAG,CAAC;CAC7F,QAAQ,IAAI,YAAY,SAAS,KAAK,CAAC;CACvC,QAAQ,IACN,SACI,+FAEA,6FAEL;;;;AChCH,SAASC,YAAU,KAAqB;CACtC,OAAO,IAAI,QAAQ,QAAQ,GAAG;;AAiBhC,eAAsB,gBACpB,eACA,UAAkBC,oBAClB,MACmB;CAInB,MAAM,MAAM,IAAI,IAAID,YAAU,QAAQ,CAAC;CACvC,IAAI,MAAM,IAAI,OAAO,OAAO,KAAK;CACjC,IAAI,WAAW;CACf,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,MAAM,IAAI,UAAU,EAAE;GAChC,QAAQ;GACR,SAAS;IACP,eAAe,UAAU;IACzB,QAAQ;IACT;GACF,CAAC;SACI;EACN,OAAO,EAAE,QAAQ,gBAAgB;;CAEnC,IAAI,IAAI,WAAW,KAAK,OAAO,EAAE,QAAQ,WAAW;CACpD,IAAI,CAAC,IAAI,IAAI,OAAO,EAAE,QAAQ,gBAAgB;CAC9C,MAAM,OAAQ,MAAM,IAAI,MAAM,CAAC,YAAY,KAAK;CAChD,OAAO,MAAM,YAAY;EAAE,QAAQ;EAAM,WAAW,KAAK;EAAW,GAAG,EAAE,QAAQ,gBAAgB;;;;ACzCnG,MAAM,iBAAA,GAAA,UAAA,WAA0BE,mBAAAA,SAAS;AAEzC,MAAM,mBAAmB;AAMzB,MAAM,kBAAkB,CAAC,cAAc,OAAO;;;;;;;;;;;;;;;AAyB9C,eAAsB,aACpB,SACA,OACA,UAAkB,kBACO;CAGzB,IAAI,CAAC,MAFgB,WAAW,QAAQ,EAE3B;EAEX,MAAM,YAAY,SAAS,GADP,QAAQ,GAAG,MAAM,KACA,IAAM;EAC3C,OAAO;GAAE,MAAM;GAAS,SAAS;GAAM,UAAU;GAAO;;CAG1D,MAAM,WAAW,OAAA,GAAA,iBAAA,UAAe,SAAS,QAAQ;CAEjD,MAAM,QAAQ,IAAI,OAAO,IAAI,YAAY,QAAQ,CAAC,WAAW,IAAI;CACjE,IAAI;CACJ,IAAI,WAAW;CACf,IAAI,MAAM,KAAK,SAAS,EAAE;EACxB,OAAO,SAAS,QAAQ,OAAO,GAAG,QAAQ,GAAG,QAAQ;EACrD,WAAW;QAGX,OAAO,GADQ,SAAS,SAAS,KAAK,IAAI,SAAS,WAAW,IAAI,WAAW,GAAG,SAAS,MACtE,QAAQ,GAAG,MAAM;CAKtC,MAAM,gBAAgB,OAAA,GAAA,iBAAA,MAAW,QAAQ,EAAE,OAAO;CAClD,MAAM,YAAY,SAAS,MAAM,aAAa;CAC9C,OAAO;EAAE,MAAM;EAAS,SAAS;EAAO;EAAU;;;;;;AAOpD,eAAsB,WACpB,SACA,UAAkB,kBACM;CACxB,IAAI,CAAE,MAAM,WAAW,QAAQ,EAAG,OAAO;CACzC,MAAM,WAAW,OAAA,GAAA,iBAAA,UAAe,SAAS,QAAQ;CACjD,MAAM,QAAQ,IAAI,OAAO,IAAI,YAAY,QAAQ,CAAC,aAAa,IAAI;CACnE,MAAM,QAAQ,SAAS,MAAM,MAAM;CACnC,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,QAAQ,MAAM,GAAG,MAAM,CAAC,QAAQ,gBAAgB,GAAG;CACzD,OAAO,MAAM,SAAS,IAAI,QAAQ;;;;;;;AAgBpC,eAAsB,WACpB,KACA,UAAkB,kBACc;CAChC,MAAM,cAAc,QAAQ,IAAI,UAAU,MAAM;CAChD,IAAI,aAAa,OAAO;EAAE,OAAO;EAAa,QAAQ,EAAE,MAAM,eAAe;EAAE;CAC/E,KAAK,MAAM,QAAQ,iBAAiB;EAClC,MAAM,QAAA,GAAA,UAAA,SAAe,KAAK,KAAK;EAC/B,MAAM,QAAQ,MAAM,WAAW,MAAM,QAAQ;EAC7C,IAAI,OAAO,OAAO;GAAE;GAAO,QAAQ;IAAE,MAAM;IAAQ;IAAM;GAAE;;CAE7D,OAAO;;;;;;;;;;;;;AAcT,MAAa,sBAAsB;CACjC;CACA;CACA;CACD;;;;;;;;;;;;;AAcD,eAAsB,aACpB,KACA,OAA0B,qBACX;CACf,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,QAAQ,MAAM,WAAW,KAAK,IAAI;EAExC,IAAI,OAAO,OAAO,SAAS,QACzB,QAAQ,IAAI,OAAO,MAAM;;;;;;;;;;;AAa/B,eAAsB,sBACpB,KACA,UACiB;CACjB,IAAI,UAAU,OAAO,SAAS,QAAQ,OAAO,SAAS,OAAO;CAC7D,MAAM,SAAA,GAAA,UAAA,SAAgB,KAAK,aAAa;CACxC,IAAI,MAAM,WAAW,MAAM,EAAE,OAAO;CACpC,QAAA,GAAA,UAAA,SAAe,KAAK,OAAO;;;;;;AAO7B,eAAsB,iBAAiB,MAAuC;CAC5E,IAAI;EACF,MAAM,cAAc,OAAO;GAAC;GAAgB;GAAM;GAAK,CAAC;EACxD,OAAO;UACA,KAAK;EAEZ,OAAQ,IAA0B,SAAS,IAAI,QAAQ;;;AAI3D,eAAe,WAAW,MAAgC;CACxD,IAAI;EACF,OAAA,GAAA,iBAAA,QAAa,KAAK;EAClB,OAAO;SACD;EACN,OAAO;;;AAIX,eAAe,YACb,MACA,UACA,MACe;CACf,MAAM,MAAM,GAAG,KAAK;CACpB,OAAA,GAAA,iBAAA,WAAgB,KAAK,UAAU,SAAS,KAAA,IAAY,KAAA,IAAY,EAAE,MAAM,CAAC;CACzE,OAAA,GAAA,iBAAA,QAAa,KAAK,KAAK;;AAGzB,SAAS,YAAY,KAAqB;CACxC,OAAO,IAAI,QAAQ,uBAAuB,OAAO;;;;ACnNnD,MAAa,aAAa;AAC1B,MAAa,YAAY;AACzB,MAAa,aAAa;;;;;;;AAQ1B,SAAgB,cAAsB;CACpC,OAAO,UAAU,WAAW,UAAU,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;ACKtD,eAAsB,cAAc,KAA4B;CAC9D,OAAA,GAAA,MAAA,kBAAuB,aAAa,EAAE;EACpC;EACA,OAAO;EACR,CAAC;;;;ACfJ,MAAM,aAAa;CAAC;CAAW;CAAW;CAAU;CAAU;AAK9D,MAAM,qBAAqB,CAAC,WAAW,UAAU;;;;;;;;;;;;;;;;;AA8BjD,eAAsB,aACpB,MAAc,QAAQ,KAAK,EACE;CAC7B,MAAM,UAAU,OAAA,GAAA,iBAAA,UAAA,GAAA,UAAA,OAAA,GAAA,QAAA,SAA2B,EAAE,cAAc,CAAC;CAC5D,IAAI;EACF,IAAI;GACF,MAAM,cAAc,QAAQ;WACrB,KAAK;GACZ,QAAQ,OAAO,MACb,+CAA+C,aAAa,CAAC,KAC1DC,gBAAc,IAAI,CAAC,6BACvB;GACD,OAAO;IAAE,SAAS,EAAE;IAAE,WAAW;IAAO,SAAS;IAAM;;EAIzD,MAAM,YAAY,OAAA,GAAA,iBAAA,SAAc,SAAS;GAAE,WAAW;GAAM,eAAe;GAAM,CAAC,EAC/E,QAAQ,MAAM,EAAE,QAAQ,CAAC,CACzB,KAAK,OAAA,GAAA,UAAA,UAAe,UAAA,GAAA,UAAA,MAAc,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;EAE5D,MAAM,UAAoB,EAAE;EAC5B,KAAK,MAAM,OAAO,YAChB,IAAI,MAAM,WAAA,GAAA,UAAA,MAAe,KAAK,IAAI,CAAC,EAAE,QAAQ,KAAK,IAAI;EAGxD,MAAM,UAAU,QAAQ,SAAS,IAAI,UAAU;EAC/C,MAAM,UAAoB,EAAE;EAC5B,KAAK,MAAM,OAAO,SAAS;GACzB,MAAM,aAAA,GAAA,UAAA,MAAiB,KAAK,KAAK,UAAU,WAAW;GAGtD,OAAA,GAAA,iBAAA,IAAS,WAAW;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;GACrD,OAAA,GAAA,iBAAA,OAAY,WAAW,EAAE,WAAW,MAAM,CAAC;GAC3C,OAAA,GAAA,iBAAA,IAAS,SAAS,WAAW,EAAE,WAAW,MAAM,CAAC;GACjD,KAAK,MAAM,OAAO,UAAU,QAAQ,MAAA,GAAA,UAAA,MAAU,WAAW,IAAI,CAAC;;EAGhE,OAAO;GAAE;GAAS,WAAW,QAAQ,WAAW;GAAG,SAAS;GAAO;WAC3D;EACR,OAAA,GAAA,iBAAA,IAAS,SAAS;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC;;;AAIvD,eAAe,UAAU,MAAgC;CACvD,IAAI;EACF,OAAA,GAAA,iBAAA,QAAa,KAAK;EAClB,OAAO;SACD;EACN,OAAO;;;AAIX,SAASA,gBAAc,KAAsB;CAC3C,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;;;;AC5EzD,MAAM,uBAAuB;AAC7B,MAAM,mBAAmB;AAYzB,MAAM,iBAAiB;AACvB,MAAM,oBAAoB;AAC1B,MAAM,kBAAkB;AACxB,MAAM,wBAAwB;AAC9B,MAAM,wBAAwB;AAC9B,MAAM,4BAA4B;AAClC,MAAM,wBAAwB;AAC9B,MAAM,oBAAoB;;;;;;;;;;;;;;;;AAsD1B,eAAsB,YAAY,SAAsC;CACtE,MAAM,WAAW,QAAQ,aAAa;CACtC,MAAM,cAAc,KAClB,QAAQ,aACR,QAAQ,IAAI,mBACZ,qBACD;CACD,MAAM,UAAU,KAAK,QAAQ,SAAS,QAAQ,IAAI,eAAe,iBAAiB;CAClF,MAAM,SAAS,QAAQ,SAAS;CAEhC,IAAI,CAAC,QACH,QAAQ,OAAO,MAAM,KAAK,OAAO,cAAc,CAAC,GAAG,GAAG,IAAI,IAAIC,YAAU,CAAC,MAAM;CAGjF,MAAM,MAAM,QAAQ,KAAK;CAEzB,MAAM,cAAc,MAAM,WAAW,IAAI;CAEzC,IAAI,QAA4B,MAAM,qBAAqB;CAC3D,IAAI,OAAO,MAAM,iBAAiB;CAIlC,IAAI,CAAC,OAAO;EAIV,IAAI;EACJ,IAAI;GACF,QAAQ,MAAM,YAAY;IAAE;IAAa,WAAW,QAAQ;IAAW,CAAC;WACjE,KAAK;GACZ,UAAU,QAAQ,gBAAgB,cAAc,IAAI,CAAC;GACrD,QAAQ,KAAK,kBAAkB;;EAEjC,QAAQ,MAAM,qBAAqB;EACnC,IAAI,CAAC,OAAO;GACV,UAAU,QAAQ,gBAAgB,kCAAkC;GACpE,QAAQ,KAAK,kBAAkB;;EAGjC,MAAM,SAAS,MAAM,UAAU;EAC/B,MAAM,cAAc;EAEpB,IAAI,MAGF,MAAM,aAAa,OAAO,aAAa,KAAK,WAAW,OAAO;OACzD,IAAI,MAAM,WAEf,OAAO,MAAM,UAAU,QAAQ,aAAa,MAAM,WAAW,OAAO;OAIpE,OAAO,MAAM,qBAAqB,OAAO,aAAa,QAAQ,QAAQ,QAAQ;QAE3E;EAEL,MAAM,cAAc;EACpB,MAAM,SAAS,MAAM,UAAU;EAC/B,IAAI,MACF,MAAM,aAAa,OAAO,aAAa,KAAK,WAAW,OAAO;OAE9D,OAAO,MAAM,qBAAqB,OAAO,aAAa,QAAQ,QAAQ,QAAQ;;CAIlF,IAAI,CAAC,QAAQ;EACX,QAAQ,OAAO,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,gBAAgB,MAAM,aAAa,YAAY,IAAI;EACzF,QAAQ,OAAO,MACb,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,KAAK,eAAe,KAAK,eACnD,KAAK,gBAAgB,GAAG,IAAI,KAAK,KAAK,cAAc,GAAG,GAAG,MAC3D,KACH;;CAKH,IAAI,CAAC,SAAS,CAAC,KAAK,WAAW;EAC7B,UAAU,QAAQ,mBAAmB,kDAAkD;EACvF,QAAQ,KAAK,gBAAgB;;CAG/B,MAAM,SAAS,MAAM,UAAU;CAC/B,MAAM,cAAc;CAIpB,IAAI,SAAwB;CAC5B,IAAI,UAAyB;CAC7B,IAAI,UAAmC;CAEvC,IAAI,WAAW;CACf,IAAI,aAAa;EACf,MAAM,QAAQ,MAAM,gBAAgB,YAAY,OAAO,aAAa,aAAa,CAAC;EAClF,MAAM,QACJ,YAAY,OAAO,SAAS,gBACxB,sBAAA,GAAA,UAAA,UACS,KAAK,YAAY,OAAO,KAAK;EAE5C,IAAI,MAAM,WAAW,gBAAgB;GAGnC,UACE,QACA,oBACA,mDAAmD,MAAM,+DAE1D;GACD,QAAQ,KAAK,sBAAsB;SAC9B,IAAI,MAAM,WAAW,QAAQ,MAAM,cAAc,KAAK,WAAW;GAGtE,WAAW;GACX,IAAI,CAAC,QACH,QAAQ,OAAO,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,kCAAkC,MAAM,IAAI;SAE/E,IAAI,MAAM,WAAW,MAAM;GAGhC,UACE,QACA,gBACA,0BAA0B,MAAM,mCAAmC,MAAM,UAAU,8BACrD,KAAK,UAAU,sCAC9C;GACD,QAAQ,KAAK,kBAAkB;SAC1B,IAAI,CAAC,QAEV,QAAQ,OAAO,MACb,GAAG,GAAG,OAAO,IAAI,CAAC,+BAA+B,MAAM,6CAExD;;CAIL,IAAI,UAAU;EACZ,IAAI;GACF,UAAU,MAAM,aAAa,QAAQ,MAAM,cAAc,KAAK,UAAU;WACjE,KAAK;GACZ,UAAU,QAAQ,oBAAoB,cAAc,IAAI,CAAC;GACzD,QAAQ,KAAK,sBAAsB;;EAErC,SAAS,QAAQ;EAGjB,IAAI,CAAC,KAAK,eAAe,QAAQ,aAAa,KAAK,cAAc,QAAQ;EACzE,IAAI,CAAC,KAAK,iBAAiB,QAAQ,eAAe,KAAK,gBAAgB,QAAQ;EAC/E,IAAI,CAAC,KAAK,eAAe,QAAQ,aAAa,KAAK,cAAc,QAAQ;EAEzE,IAAI,UAAU;GACZ,MAAM,SAAS,MAAM,sBAAsB,KAAK,YAAY;GAC5D,IAAI;IACF,MAAM,SAAS,MAAM,aAAa,QAAQ,OAAO;IACjD,UAAU,OAAO;IACjB,IAAI,CAAC,QAAQ;KACX,MAAM,OAAA,GAAA,UAAA,UAAe,KAAK,OAAO,KAAK;KACtC,MAAM,OAAO,OAAO,UAChB,YACA,OAAO,WACL,oCACA;KACN,QAAQ,OAAO,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,KAAK,GAAG,IAAI,IAAI;KAEzD,IAAK,MAAM,iBAAiB,OAAO,KAAK,KAAM,OAC5C,QAAQ,OAAO,MACb,GAAG,GAAG,OAAO,IAAI,CAAC,GAAG,IAAI,wDAC1B;;YAGE,KAAK;IACZ,QAAQ,OAAO,MACb,KAAK,GAAG,IAAI,QAAQ,CAAC,oBAAoB,OAAO,IAAI,cAAc,IAAI,CAAC,MACrE,GAAG,IAAI,kCAAkC,GACzC,4BAA4B,OAAO,MACtC;IACD,IAAI,QACF,QAAQ,OAAO,MACb,KAAK,UAAU;KACb,OAAO;KACP;KACA,WAAW,KAAK;KAChB,SAAS,cAAc,IAAI;KAC5B,CAAC,GAAG,KACN;IAEH,QAAQ,KAAK,sBAAsB;;;;CAOzC,IAAI,kBAA4B,EAAE;CAClC,IAAI;EAIF,MAAM,cAAc,MAAM,aAAa,QAAQ,KAAK,CAAC;EACrD,kBAAkB,YAAY;EAC9B,IAAI,CAAC;OACC,YAAY,SACd,QAAQ,OAAO,MAAM,GAAG,IAAI,oCAAoC,CAAC;QAC5D,IAAI,YAAY,QAAQ,SAAS,GAAG;IAEzC,MAAM,OAAO,YAAY,YACrB,GAAG,IAAI,0DAA0D,GACjE;IACJ,QAAQ,OAAO,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,0BAA0B,KAAK,IAAI;;;UAGtE,KAAK;EACZ,IAAI,CAAC,QACH,QAAQ,OAAO,MACb,GAAG,GAAG,OAAO,UAAU,CAAC,qCAAqC,cAAc,IAAI,CAAC,MACjF;;CAML,MAAM,eAAe,GAAG,UAAU,OAAO,CAAC,WAAW,KAAK,UAAU;CAEpE,MAAM,SAAsB;EAC1B,WAAW,KAAK;EAChB,aAAa,KAAK,eAAe;EACjC,aAAa,KAAK,eAAe;EACjC,eAAe,KAAK,iBAAiB;EACrC;EACA,gBAAgB;EAChB;EACA,aAAa;EACb,WAAW,MAAM,aAAa;EAC/B;CAED,IAAI,QACF,QAAQ,OAAO,MAAM,KAAK,UAAU,OAAO,GAAG,KAAK;MAKnD,QAAQ,OAAO,MACb;;;OAEU,MAAM,KAAK,wDAAQ,CAAC;;OAGpB,MAAM,MAAM,sFAAU,CAAC;OAEvB,MAAM,KAAK,aAAa,CAAC,IACpC;;;;;;;;AAcL,eAAe,qBACb,OACA,aACA,QACA,QACA,SACsB;CACtB,IAAI;CACJ,IAAI;EACF,WAAW,MAAM,aAAa,OAAO,YAAY;UAC1C,KAAK;EACZ,UAAU,QAAQ,wBAAwB,cAAc,IAAI,CAAC;EAC7D,QAAQ,KAAK,0BAA0B;;CAGzC,IAAI,SAAS,WAAW,GAAG;EAIzB,IAAI,QAAQ;GACV,UACE,QACA,eACA,gIACoD,UAAU,OAAO,CAAC,cACvE;GACD,QAAQ,KAAK,gBAAgB;;EAE/B,QAAQ,OAAO,MACb,gFACD;EACD,IAAI;EACJ,IAAI;GACF,QAAQ,MAAM,YAAY;IACxB,aAAa;IACb,WAAW,QAAQ;IACpB,CAAC;WACK,KAAK;GACZ,UAAU,QAAQ,gBAAgB,cAAc,IAAI,CAAC;GACrD,QAAQ,KAAK,kBAAkB;;EAEjC,IAAI,CAAC,MAAM,WAAW;GACpB,UACE,QACA,eACA,yCAAyC,UAAU,OAAO,CAAC,gCAC5D;GACD,QAAQ,KAAK,gBAAgB;;EAE/B,OAAO,UAAU,QAAQ,aAAa,MAAM,WAAW,OAAO;;CAGhE,IAAI;CACJ,IAAI,QAAQ,WAAW;EAErB,MAAM,QAAQ,SAAS,MAAM,MAAM,EAAE,OAAO,QAAQ,UAAU;EAC9D,IAAI,CAAC,OAAO;GACV,UACE,QACA,aACA,oCAAoC,QAAQ,UAAU,kBACpD,SAAS,KAAK,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,cAAc,GAAG,EAAE,KAAK,GAAG,CAAC,KAAK,KAAK,CAC3E;GACD,QAAQ,KAAK,eAAe;;EAE9B,SAAS;QACJ,IAAI,SAAS,WAAW,GAC7B,SAAS,SAAS;MACb;EACL,IAAI,QAAQ;GACV,UACE,QACA,qBACA,4EACE,SAAS,KAAK,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,cAAc,GAAG,EAAE,KAAK,GAAG,CAAC,KAAK,KAAK,CAC3E;GACD,QAAQ,KAAK,gBAAgB;;EAE/B,SAAS,MAAM,oBAAoB,SAAS;;CAG9C,MAAM,WAAW,MAAM,iBAAiB;EACtC,WAAW,OAAO;EAClB,aAAa,OAAO;EACpB,aAAa,OAAO;EACpB,eAAe,OAAO;EACvB,CAAC;CACF,IAAI,CAAC,QAAQ,QAAQ,OAAO,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,UAAU,SAAS,IAAI;CAC1E,OAAO;EACL,WAAW,OAAO;EAClB,aAAa,OAAO;EACpB,aAAa,OAAO;EACpB,eAAe,OAAO;EACvB;;;AAIH,eAAe,UACb,QACA,aACA,WACA,QACsB;CACtB,IAAI,OAAoB,EAAE,WAAW;CACrC,IAAI;EACF,MAAM,QAAQ,MAAM,qBAAqB;EACzC,IAAI,OAAO;GAET,MAAM,SAAQ,MADS,aAAa,OAAO,YAAY,EAChC,MAAM,MAAM,EAAE,OAAO,UAAU;GACtD,IAAI,OACF,OAAO;IACL;IACA,aAAa,MAAM;IACnB,aAAa,MAAM;IACnB,eAAe,MAAM;IACtB;;SAGC;CAGR,IAAI;EACF,MAAM,WAAW,MAAM,iBAAiB,KAAK;EAC7C,IAAI,CAAC,QAAQ,QAAQ,OAAO,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,UAAU,SAAS,IAAI;UACnE,KAAK;EACZ,IAAI,CAAC,QACH,QAAQ,OAAO,MACb,GAAG,GAAG,OAAO,UAAU,CAAC,wCAAwC,cAAc,IAAI,CAAC,yCAC1C,UAAU,KACpD;;CAGL,OAAO;;;;;;;AAQT,eAAe,aACb,OACA,aACA,WACA,QACe;CACf,IAAI;CACJ,IAAI;EACF,WAAW,MAAM,aAAa,OAAO,YAAY;UAC1C,KAAK;EAIZ,UAAU,QAAQ,wBAAwB,cAAc,IAAI,CAAC;EAC7D,QAAQ,KAAK,0BAA0B;;CAEzC,IAAI,CAAC,SAAS,MAAM,MAAM,EAAE,OAAO,UAAU,EAAE;EAC7C,UACE,QACA,aACA,yDACD;EACD,QAAQ,KAAK,eAAe;;;;AAKhC,eAAe,aAAa,OAAoB,SAAwC;CACtF,MAAM,UAAU,MAAM,gBAAgB,MAAM;CAU5C,OAAO,IAPY,cAAc;EAC/B;EAGA,MAAM,aAAa;EACnB,MAAM;GAAE,MAAM;GAAa,OAAO,QAAQ;GAAa,WAAW;GAAI;EACvE,CACY,CAAC,IAAI,cAAc;;AAGlC,eAAe,sBAAmD;CAChE,IAAI;EACF,OAAO,MAAM,iBAAiB;SACxB;EACN,OAAO;;;;AASX,eAAe,aACb,QACA,cACA,WAC2B;CAC3B,MAAM,MAAM,GAAG,UAAU,OAAO,CAAC;CACjC,MAAM,MAAM,MAAM,MAAM,KAAK;EAC3B,QAAQ;EACR,SAAS;GAAE,eAAe,UAAU;GAAgB,gBAAgB;GAAoB;EACxF,MAAM,KAAK,UAAU;GAAE,aAAA,GAAA,QAAA,WAAsB;GAAE;GAAW,CAAC;EAC5D,CAAC;CACF,IAAI,IAAI,IACN,OAAQ,MAAM,IAAI,MAAM;CAE1B,MAAM,OAAQ,MAAM,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;CAChD,MAAM,IAAI,MAAM,KAAK,SAAS,2BAA2B,IAAI,OAAO,GAAG;;AAGzE,eAAe,oBAAoB,UAA6C;CAC9E,QAAQ,OAAO,MAAM,+CAA+C;CACpE,SAAS,SAAS,GAAG,MAAM;EACzB,QAAQ,OAAO,MAAM,KAAK,IAAI,EAAE,IAAI,EAAE,cAAc,KAAK,EAAE,KAAK,IAAI;GACpE;CACF,MAAM,MAAA,GAAA,uBAAA,iBAAqB;EAAE,OAAO,QAAQ;EAAO,QAAQ,QAAQ;EAAQ,CAAC;CAC5E,IAAI;EACF,OAAO,MAAM;GACX,MAAM,UAAU,MAAM,GAAG,SAAS,aAAa,SAAS,OAAO,KAAK,EAAE,MAAM;GAC5E,MAAM,MAAM,OAAO,SAAS,QAAQ,GAAG;GACvC,IAAI,OAAO,UAAU,IAAI,IAAI,OAAO,KAAK,OAAO,SAAS,QACvD,OAAO,SAAS,MAAM;GAExB,QAAQ,OAAO,MAAM,GAAG,GAAG,IAAI,qBAAqB,CAAC,IAAI;;WAEnD;EACR,GAAG,OAAO;;;AAId,SAAS,KAAK,GAAG,YAA4C;CAC3D,KAAK,MAAM,KAAK,YACd,IAAI,KAAK,EAAE,SAAS,GAAG,OAAO;CAEhC,OAAO;;AAGT,SAAS,UAAU,KAAqB;CACtC,OAAO,IAAI,QAAQ,QAAQ,GAAG;;AAGhC,SAAS,cAAc,KAAsB;CAC3C,IAAI,eAAe,OAAO,OAAO,IAAI;CACrC,OAAO,OAAO,IAAI;;AAGpB,SAAS,UAAU,MAAe,MAAc,QAAsB;CACpE,IAAI,MACF,QAAQ,OAAO,MAAM,KAAK,UAAU;EAAE,OAAO;EAAM;EAAQ,CAAC,GAAG,KAAK;MAEpE,QAAQ,OAAO,MAAM,KAAK,GAAG,IAAI,UAAU,KAAK,GAAG,CAAC,IAAI,OAAO,IAAI;;;;;;;;;ACvlBvE,MAAa,iBAAiB,OAC5B,QACA,OACA,SACkB;CAClB,MAAM,OAAO,MAAM,OAAO,IAAI,MAAM,MAAM;CAE1C,IAAI,KAAK,MAAM;EACb,WAAW,KAAK;EAChB;;CAGF,IAAI,KAAK,WAAW,GAAG;EACrB,QAAQ,IAAI,oBAAoB;EAChC;;CAGF,MAAM,UAAU,OAAO,KAAK,KAAK,GAAG;CACpC,MAAM,YAAY,KAAK,KAAK,QAC1B,QAAQ,KAAK,QAAQ,OAAO,IAAI,QAAQ,GAAG,CAAC,CAC7C;CAED,QAAQ,IAAI,YAAY,SAAS,UAAU,CAAC;CAC5C,QAAQ,IAAI,KAAK,KAAK,OAAO,WAAW;;;;AClC1C,MAAa,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACW/B,MAAM,SAAS,kBAAkB;AAIjC,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;AAwBvB,MAAa,wBAAwB,OACnC,QACA,SACA,MACA,SACkB;CAClB,MAAM,KAAK,iBAAiB,QAAQ;CAEpC,MAAM,OAAO,MAAM,OAAO,IAAI,MAC5B,kEACA,EAAE,UAAU,IAAI,CACjB;CACD,IAAI,KAAK,WAAW,GAClB,MAAM,IAAI,MACR,SAAS,GAAG,iGAEb;CAGH,MAAM,WAAW,qBAAqB,KAAK,GAAG,SAAS;CACvD,MAAM,UAAU,WAAW,GAAG,WAAW,iBAAiB,SAAS;CAGnE,MAAM,OAAO,OAAO,aAClB,IACA,GAAG,oBAAoB,SAAS,EAChC,EAAE,gBAAgB,MAAM,CACzB;CAED,IAAI,KAAK,MAAM;EACb,WAAW;GAAE,SAAS;GAAI,MAAM;GAAS,CAAC;EAC1C;;CAGF,OAAO,KAAK,0BAA0B,GAAG,GAAG;;;;ACjD9C,eAAe,OAAO;CAKpB,MAAM,aAAa,QAAQ,KAAK,CAAC;CAEjC,MAAM,UAAU,IAAIC,UAAAA,SAAS;CAE7B,QACG,KAAK,WAAW,CAChB,YAAY,mDAAmD,CAC/D,QAAQC,WAAS,iBAAiB,yBAAyB;CAE9D,MAAM,cAAc,QACjB,QAAQ,UAAU,CAClB,YAAY,kBAAkB,CAC9B,OACC,qBACA,4FAED,CACA,OACC,oBACA,8FACD,CACA,OACC,iBACA,8CACC,QAAQ,SAAS,KAAK,GAAG,CAC3B,CACA,OAAO,UAAU,mCAAmC;CAGvD,YACG,QAAQ,OAAO,CACf,YAAY,oBAAoB,CAChC,OAAO,kBAAkB,mBAAmB,CAAC;CAGhD,YACG,QAAQ,OAAO,CACf,YAAY,yCAAyC,CACrD,SACC,cACA,wDACD,CACA,OACC,qBACA,2DACD,CACA,OACC,aACA,yDACD,CACA,OAAO,mBAAmB,yCAAyC,MAAM,CACzE,OACC,uBACA,gCACC,QAAQ,SAAS,KAAK,GAAG,EAC1B,IACD,CACA,OAAO,kBAAkB,mBAAmB,CAAC;CAGhD,YACG,QAAQ,OAAO,CACf,YAAY,2BAA2B,CACvC,SACC,iBACA,4DACD,CACA,OACC,qBACA,2DACD,CACA,OACC,aACA,yDACD,CACA,OACC,4BACA,iFACD,CACA,OACC,uBACA,gCACC,QAAQ,SAAS,KAAK,GAAG,EAC1B,IACD,CACA,OAAO,mBAAmB,uCAAuC,QAChE,SAAS,KAAK,GAAG,CAClB,CACA,OACC,qBACA,0BACC,QAAQ,SAAS,KAAK,GAAG,EAC1B,EACD,CACA,OAAO,kBAAkB,mBAAmB,CAAC;CAGhD,YACG,QAAQ,SAAS,CACjB,YAAY,oCAAoC,CAChD,SAAS,UAAU,gCAAgC,CACnD,SACC,cACA,wDACD,CACA,eAAe,4BAA4B,+BAA+B,CAC1E,OACC,4BACA,iFACD,CACA,OAAO,mBAAmB,yCAAyC,MAAM,CACzE,OACC,uBACA,wCACC,QAAQ,SAAS,KAAK,GAAG,EAC1B,IACD,CACA,OAAO,kBAAkB,qBAAqB,CAAC;CAElD,MAAM,SAAS,QACZ,QAAQ,MAAM,CACd,YAAY,oDAAoD,CAChE,OACC,qBACA,4FAED,CACA,OACC,oBACA,8FACD,CACA,OACC,iBACA,8CACC,QAAQ,SAAS,KAAK,GAAG,CAC3B,CACA,OAAO,UAAU,mCAAmC;CAEvD,OACG,QAAQ,QAAQ,CAChB,YAAY,sBAAsB,CAClC,SAAS,WAAW,mBAAmB,CACvC,OAAO,kBAAkB,eAAe,CAAC,CACzC,YACC,SACA,kBACA;;;;;EAMD;CAEH,OACG,QAAQ,SAAS,CACjB,YAAY,0CAA0C,CACtD,aAAa;EACZ,QAAQ,OAAO,MAAM,gBAAgB;GACrC;CAIJ,QAF2B,QAAQ,UAAU,CAAC,YAAY,6BAEhD,CACP,QAAQ,OAAO,CACf,YAAY,kEAAkE,CAC9E,OACC,oBACA,mFACD,CACA,OACC,iBACA,8CACC,QAAQ,SAAS,KAAK,GAAG,CAC3B,CACA,OAAO,UAAU,mCAAmC,CACpD,OAAO,cAAc,mBAAmB,CAAC;CAE5C,QACG,QAAQ,QAAQ,CAChB,YAAY,6CAA6C,CACzD,OACC,wBACA,0FACD,CACA,OAAO,gBAAgB,gDAAgD,CACvE,OAAO,OAAO,YAAY;EACzB,MAAM,SAAS,MAAM,YAAY,QAAQ;EACzC,QAAQ,OAAO,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,gBAAgB,OAAO,aAAa,YAAY,KAAK;EAC3F,QAAQ,OAAO,MACb,GAAG,IAAI,oFAAoF,CAC5F;EACD,QAAQ,OAAO,MACb,GAAG,IAAI,kFAAkF,CAC1F;GACD;CAEJ,QACG,QAAQ,SAAS,CACjB,YAAY,4CAA4C,CACxD,OAAO,YAAY;EAClB,MAAM,cAAc;GACpB;CAEJ,QACG,QAAQ,QAAQ,CAChB,YACC,uHAED,CACA,OAAO,eAAe,kDAAkD,KAAK,CAC7E,OAAO,kBAAkB,yBAAyB,CAClD,OACC,qBACA,8GAED,CACA,OAAO,UAAU,8CAA8C,CAC/D,OAAO,gBAAgB,uCAAuC,CAC9D,OACC,wBACA,6EACD,CACA,OACC,oBACA,iFACD,CACA,OAAO,OAAO,YAAY;EACzB,MAAM,YAAY,QAAQ;GAC1B;CAqBJ,QAlBG,QAAQ,QAAQ,CAChB,YAAY,gCAAgC,CAC5C,OACC,qBACA,4FAED,CACA,OACC,oBACA,8FACD,CACA,OACC,iBACA,8CACC,QAAQ,SAAS,KAAK,GAAG,CAC3B,CACA,OAAO,UAAU,mCAEZ,CACL,QAAQ,cAAc,CACtB,YAAY,gEAAgE,CAC5E,SAAS,cAAc,+CAA+C,CACtE,SAAS,UAAU,mCAAmC,CACtD,OAAO,kBAAkB,sBAAsB,CAAC,CAChD,YACC,SACA;;;;;;EAOD;CA2BH,MAAM,kBAzBW,QACd,QAAQ,QAAQ,CAChB,YAAY,4BAA4B,CACxC,OACC,qBACA,4FAED,CACA,OACC,oBACA,8FACD,CACA,OACC,iBACA,8CACC,QAAQ,SAAS,KAAK,GAAG,CAC3B,CACA,OAAO,UAAU,mCAAmC,CACpD,YACC,SACA;;EAK4B,CAC7B,QAAQ,UAAU,CAClB,YAAY,wBAAwB,CACpC,YACC,SACA;;EAGD;CAEH,gBACG,QAAQ,WAAW,CACnB,YAAY,0CAA0C,CACtD,SAAS,gBAAgB,mBAAmB,CAC5C,SAAS,UAAU,uBAAuB,CAC1C,OAAO,kBAAkB,0BAA0B,CAAC,CACpD,YACC,SACA;;;EAID;CAEH,gBACG,QAAQ,UAAU,CAClB,YAAY,mEAAmE,CAC/E,SAAS,gBAAgB,mBAAmB,CAC5C,OAAO,kBAAkB,0BAA0B,CAAC,CACpD,YACC,SACA;;;;;;;;;;;;EAaD;CAEH,QAAQ,YACN,SACA;;;;;;;;;;;;;;;;;;;;;;;;EAyBD;CAED,MAAM,QAAQ,YAAY;;AAG5B,MAAM,CAAC,OAAO,QAAQ;CACpB,QAAQ,MAAM,aAAa,IAAI,CAAC;CAChC,QAAQ,KAAK,EAAE;EACf"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lmnr-cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "CLI for the Laminar agent observability platform",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {