@tankpkg/cli 0.9.0 → 0.10.1

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.
@@ -4,7 +4,7 @@ import os from "node:os";
4
4
  import path from "node:path";
5
5
  import pino from "pino";
6
6
  //#region src/lib/config.ts
7
- const DEFAULT_CONFIG = { registry: "https://tankpkg.dev" };
7
+ const DEFAULT_CONFIG = { registry: process.env.TANK_REGISTRY_URL || "https://www.tankpkg.dev" };
8
8
  /**
9
9
  * Get the path to the tank config directory.
10
10
  * Override with configDir parameter for testing.
@@ -74,7 +74,7 @@ const logger = {
74
74
  };
75
75
  //#endregion
76
76
  //#region src/version.ts
77
- const VERSION = "0.9.0";
77
+ const VERSION = "0.10.1";
78
78
  const USER_AGENT = `tank-cli/${VERSION}`;
79
79
  //#endregion
80
80
  //#region src/lib/debug-logger.ts
@@ -137,4 +137,4 @@ async function flushLogs() {
137
137
  //#endregion
138
138
  export { VERSION as a, getConfigDir as c, USER_AGENT as i, getConfigPath as l, flushLogs as n, logger as o, httpLog as r, getConfig as s, authFlowLog as t, setConfig as u };
139
139
 
140
- //# sourceMappingURL=debug-logger-BJzuguP3.js.map
140
+ //# sourceMappingURL=debug-logger-DnEQXtQC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-logger-DnEQXtQC.js","names":["pkg.version"],"sources":["../src/lib/config.ts","../src/lib/logger.ts","../package.json","../src/version.ts","../src/lib/debug-logger.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport interface TankConfig {\n token?: string;\n user?: { name: string; email: string };\n registry: string;\n}\n\nconst DEFAULT_CONFIG: TankConfig = {\n registry: process.env.TANK_REGISTRY_URL || 'https://www.tankpkg.dev'\n};\n\n/**\n * Get the path to the tank config directory.\n * Override with configDir parameter for testing.\n */\nexport function getConfigDir(configDir?: string): string {\n return configDir ?? path.join(os.homedir(), '.tank');\n}\n\n/**\n * Get the path to the tank config file.\n * Override with configDir parameter for testing.\n */\nexport function getConfigPath(configDir?: string): string {\n return path.join(getConfigDir(configDir), 'config.json');\n}\n\n/**\n * Read the tank config file. Returns defaults if file doesn't exist.\n * Override configDir for testing (avoids writing to real ~/.tank/).\n */\nexport function getConfig(configDir?: string): TankConfig {\n const configPath = getConfigPath(configDir);\n\n try {\n const raw = fs.readFileSync(configPath, 'utf-8');\n const parsed = JSON.parse(raw) as Partial<TankConfig>;\n const merged = { ...DEFAULT_CONFIG, ...parsed };\n const envToken = process.env.TANK_TOKEN?.trim();\n if (envToken) {\n merged.token = envToken;\n }\n return merged;\n } catch {\n const envToken = process.env.TANK_TOKEN?.trim();\n return {\n ...DEFAULT_CONFIG,\n ...(envToken ? { token: envToken } : {})\n };\n }\n}\n\n/**\n * Write config to disk. Merges with existing config.\n * Creates ~/.tank/ directory if it doesn't exist.\n * Sets file permissions to 0600 (owner read/write only) on Unix.\n */\nexport function setConfig(partial: Partial<TankConfig>, configDir?: string): void {\n const dir = getConfigDir(configDir);\n const configPath = getConfigPath(configDir);\n\n // Create directory with 0700 permissions if it doesn't exist\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n\n // Merge with existing config\n const existing = getConfig(configDir);\n const merged = { ...existing, ...partial };\n\n // Write config file\n fs.writeFileSync(configPath, `${JSON.stringify(merged, null, 2)}\\n`, {\n encoding: 'utf-8',\n mode: 0o600\n });\n}\n","import chalk from 'chalk';\n\nexport const logger = {\n info: (msg: string) => console.log(chalk.blue('ℹ'), msg),\n success: (msg: string) => console.log(chalk.green('✓'), msg),\n warn: (msg: string) => console.log(chalk.yellow('⚠'), msg),\n error: (msg: string) => console.error(chalk.red('✗'), msg)\n};\n","","import pkg from '../package.json' with { type: 'json' };\n\nexport const VERSION = pkg.version ?? '0.0.0';\nexport const USER_AGENT = `tank-cli/${VERSION}`;\n","import { appendFileSync } from 'node:fs';\n\nimport pino from 'pino';\n\nconst lokiUrl = process.env.TANK_LOKI_URL || 'http://localhost:3100';\nconst debugEnabled = process.env.TANK_DEBUG === '1' || process.env.TANK_DEBUG === 'true';\n\n// Buffer logs and push to Loki via HTTP (avoids pino.transport() worker thread serialization issues)\nconst logBuffer: string[] = [];\nlet flushTimer: ReturnType<typeof setInterval> | null = null;\n\nasync function flushToLoki() {\n if (logBuffer.length === 0) return;\n\n const logs = logBuffer.splice(0);\n const values: [string, string][] = logs.map((line) => {\n try {\n const parsed = JSON.parse(line);\n const ts = parsed.time ? String(new Date(parsed.time).getTime() * 1_000_000) : String(Date.now() * 1_000_000);\n return [ts, line];\n } catch {\n return [String(Date.now() * 1_000_000), line];\n }\n });\n\n try {\n await fetch(`${lokiUrl}/loki/api/v1/push`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n streams: [{ stream: { app: 'tank-cli' }, values }]\n })\n });\n } catch {\n logBuffer.unshift(...logs);\n }\n}\n\nconst lokiStream = {\n write(line: string) {\n const trimmed = line.trimEnd();\n logBuffer.push(trimmed);\n\n if (debugEnabled) {\n try {\n appendFileSync('/tmp/tank-cli-debug.log', `${trimmed}\\n`);\n } catch {\n // intentionally empty\n }\n }\n\n if (!flushTimer) {\n flushTimer = setInterval(flushToLoki, 2000);\n }\n if (logBuffer.length >= 50) {\n void flushToLoki();\n }\n }\n};\n\nexport const debugLog = pino(\n {\n level: 'debug',\n timestamp: pino.stdTimeFunctions.isoTime,\n formatters: {\n level(label: string) {\n return { level: label };\n }\n }\n },\n lokiStream as unknown as pino.DestinationStream\n);\n\nexport const httpLog = debugLog.child({ module: 'http' });\nexport const authFlowLog = debugLog.child({ module: 'auth-flow' });\n\n/**\n * Flush pending logs before process exit.\n * Call this at the end of CLI commands to ensure logs are delivered.\n */\nexport async function flushLogs(): Promise<void> {\n if (flushTimer) {\n clearInterval(flushTimer);\n flushTimer = null;\n }\n await flushToLoki();\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/lib/config.ts","../src/lib/api-client.ts","../src/lib/logger.ts","../src/version.ts"],"mappings":";UAIiB,UAAA;EACf,KAAA;EACA,IAAA;IAAS,IAAA;IAAc,KAAA;EAAA;EACvB,QAAA;AAAA;;;;;iBAWc,YAAA,CAAa,SAAA;;;;;iBAQb,aAAA,CAAc,SAAA;;;;;iBAQd,SAAA,CAAU,SAAA,YAAqB,UAAA;;;;;AA0B/C;iBAAgB,SAAA,CAAU,OAAA,EAAS,OAAA,CAAQ,UAAA,GAAa,SAAA;;;cCxD3C,SAAA;EAAA,QACH,OAAA;EAAA,QACA,KAAA;cAEI,MAAA,EAAQ,UAAA;EAAA,QAKZ,OAAA;EAgBF,GAAA,CAAI,IAAA,WAAe,OAAA,CAAQ,QAAA;EAW3B,IAAA,CAAK,IAAA,UAAc,IAAA,YAAgB,OAAA,CAAQ,QAAA;EAe3C,GAAA,CAAI,IAAA,UAAc,IAAA,YAAgB,OAAA,CAAQ,QAAA;AAAA;;;ADrClD;iBCwDgB,eAAA,CAAgB,SAAA,YAAqB,SAAA;;;cCxExC,MAAA;;;;;;;;cCAA,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/lib/config.ts","../src/lib/api-client.ts","../src/lib/logger.ts","../src/version.ts"],"mappings":";UAIiB,UAAA;EACf,KAAA;EACA,IAAA;IAAS,IAAA;IAAc,KAAA;EAAA;EACvB,QAAA;AAAA;;;;;iBAWc,YAAA,CAAa,SAAA;;;;;iBAQb,aAAA,CAAc,SAAA;;;;;iBAQd,SAAA,CAAU,SAAA,YAAqB,UAAA;;;;;AA0B/C;iBAAgB,SAAA,CAAU,OAAA,EAAS,OAAA,CAAQ,UAAA,GAAa,SAAA;;;cCvD3C,SAAA;EAAA,QACH,OAAA;EAAA,QACA,KAAA;cAEI,MAAA,EAAQ,UAAA;EAAA,QAKZ,OAAA;EAgBF,GAAA,CAAI,IAAA,WAAe,OAAA,CAAQ,QAAA;EAW3B,IAAA,CAAK,IAAA,UAAc,IAAA,YAAgB,OAAA,CAAQ,QAAA;EAe3C,GAAA,CAAI,IAAA,UAAc,IAAA,YAAgB,OAAA,CAAQ,QAAA;AAAA;;;ADtClD;iBCyDgB,eAAA,CAAgB,SAAA,YAAqB,SAAA;;;cCzExC,MAAA;;;;;;;;cCAA,OAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as VERSION, c as getConfigDir, i as USER_AGENT, l as getConfigPath, o as logger, r as httpLog, s as getConfig, u as setConfig } from "./debug-logger-BJzuguP3.js";
1
+ import { a as VERSION, c as getConfigDir, i as USER_AGENT, l as getConfigPath, o as logger, r as httpLog, s as getConfig, u as setConfig } from "./debug-logger-DnEQXtQC.js";
2
2
  //#region src/lib/api-client.ts
3
3
  var ApiClient = class {
4
4
  baseUrl;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/lib/api-client.ts"],"sourcesContent":["import { USER_AGENT } from '../version.js';\nimport { getConfig, type TankConfig } from './config.js';\nimport { httpLog } from './debug-logger.js';\n\nexport class ApiClient {\n private baseUrl: string;\n private token?: string;\n\n constructor(config: TankConfig) {\n this.baseUrl = config.registry;\n this.token = config.token;\n }\n\n private headers(hasBody: boolean): Record<string, string> {\n const h: Record<string, string> = {\n 'User-Agent': USER_AGENT\n };\n\n if (this.token) {\n h.Authorization = `Bearer ${this.token}`;\n }\n\n if (hasBody) {\n h['Content-Type'] = 'application/json';\n }\n\n return h;\n }\n\n async get(path: string): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n httpLog.info({ method: 'GET', url }, 'Request');\n const res = await fetch(url, {\n method: 'GET',\n headers: this.headers(false)\n });\n httpLog.info({ method: 'GET', url, status: res.status, ok: res.ok }, 'Response');\n return res;\n }\n\n async post(path: string, body: unknown): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n httpLog.info(\n { method: 'POST', url, bodyKeys: body && typeof body === 'object' ? Object.keys(body) : undefined },\n 'Request'\n );\n const res = await fetch(url, {\n method: 'POST',\n headers: this.headers(true),\n body: JSON.stringify(body)\n });\n httpLog.info({ method: 'POST', url, status: res.status, ok: res.ok }, 'Response');\n return res;\n }\n\n async put(path: string, body: unknown): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n httpLog.info(\n { method: 'PUT', url, bodyKeys: body && typeof body === 'object' ? Object.keys(body) : undefined },\n 'Request'\n );\n const res = await fetch(url, {\n method: 'PUT',\n headers: this.headers(true),\n body: JSON.stringify(body)\n });\n httpLog.info({ method: 'PUT', url, status: res.status, ok: res.ok }, 'Response');\n return res;\n }\n}\n\n/**\n * Factory: reads config and returns an ApiClient instance.\n */\nexport function createApiClient(configDir?: string): ApiClient {\n const config = getConfig(configDir);\n return new ApiClient(config);\n}\n"],"mappings":";;AAIA,IAAa,YAAb,MAAuB;CACrB;CACA;CAEA,YAAY,QAAoB;AAC9B,OAAK,UAAU,OAAO;AACtB,OAAK,QAAQ,OAAO;;CAGtB,QAAgB,SAA0C;EACxD,MAAM,IAA4B,EAChC,cAAc,YACf;AAED,MAAI,KAAK,MACP,GAAE,gBAAgB,UAAU,KAAK;AAGnC,MAAI,QACF,GAAE,kBAAkB;AAGtB,SAAO;;CAGT,MAAM,IAAI,MAAiC;EACzC,MAAM,MAAM,GAAG,KAAK,UAAU;AAC9B,UAAQ,KAAK;GAAE,QAAQ;GAAO;GAAK,EAAE,UAAU;EAC/C,MAAM,MAAM,MAAM,MAAM,KAAK;GAC3B,QAAQ;GACR,SAAS,KAAK,QAAQ,MAAM;GAC7B,CAAC;AACF,UAAQ,KAAK;GAAE,QAAQ;GAAO;GAAK,QAAQ,IAAI;GAAQ,IAAI,IAAI;GAAI,EAAE,WAAW;AAChF,SAAO;;CAGT,MAAM,KAAK,MAAc,MAAkC;EACzD,MAAM,MAAM,GAAG,KAAK,UAAU;AAC9B,UAAQ,KACN;GAAE,QAAQ;GAAQ;GAAK,UAAU,QAAQ,OAAO,SAAS,WAAW,OAAO,KAAK,KAAK,GAAG,KAAA;GAAW,EACnG,UACD;EACD,MAAM,MAAM,MAAM,MAAM,KAAK;GAC3B,QAAQ;GACR,SAAS,KAAK,QAAQ,KAAK;GAC3B,MAAM,KAAK,UAAU,KAAK;GAC3B,CAAC;AACF,UAAQ,KAAK;GAAE,QAAQ;GAAQ;GAAK,QAAQ,IAAI;GAAQ,IAAI,IAAI;GAAI,EAAE,WAAW;AACjF,SAAO;;CAGT,MAAM,IAAI,MAAc,MAAkC;EACxD,MAAM,MAAM,GAAG,KAAK,UAAU;AAC9B,UAAQ,KACN;GAAE,QAAQ;GAAO;GAAK,UAAU,QAAQ,OAAO,SAAS,WAAW,OAAO,KAAK,KAAK,GAAG,KAAA;GAAW,EAClG,UACD;EACD,MAAM,MAAM,MAAM,MAAM,KAAK;GAC3B,QAAQ;GACR,SAAS,KAAK,QAAQ,KAAK;GAC3B,MAAM,KAAK,UAAU,KAAK;GAC3B,CAAC;AACF,UAAQ,KAAK;GAAE,QAAQ;GAAO;GAAK,QAAQ,IAAI;GAAQ,IAAI,IAAI;GAAI,EAAE,WAAW;AAChF,SAAO;;;;;;AAOX,SAAgB,gBAAgB,WAA+B;AAE7D,QAAO,IAAI,UADI,UAAU,UAAU,CACP"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/lib/api-client.ts"],"sourcesContent":["import { USER_AGENT } from '~/version.js';\n\nimport { getConfig, type TankConfig } from './config.js';\nimport { httpLog } from './debug-logger.js';\n\nexport class ApiClient {\n private baseUrl: string;\n private token?: string;\n\n constructor(config: TankConfig) {\n this.baseUrl = config.registry;\n this.token = config.token;\n }\n\n private headers(hasBody: boolean): Record<string, string> {\n const h: Record<string, string> = {\n 'User-Agent': USER_AGENT\n };\n\n if (this.token) {\n h.Authorization = `Bearer ${this.token}`;\n }\n\n if (hasBody) {\n h['Content-Type'] = 'application/json';\n }\n\n return h;\n }\n\n async get(path: string): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n httpLog.info({ method: 'GET', url }, 'Request');\n const res = await fetch(url, {\n method: 'GET',\n headers: this.headers(false)\n });\n httpLog.info({ method: 'GET', url, status: res.status, ok: res.ok }, 'Response');\n return res;\n }\n\n async post(path: string, body: unknown): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n httpLog.info(\n { method: 'POST', url, bodyKeys: body && typeof body === 'object' ? Object.keys(body) : undefined },\n 'Request'\n );\n const res = await fetch(url, {\n method: 'POST',\n headers: this.headers(true),\n body: JSON.stringify(body)\n });\n httpLog.info({ method: 'POST', url, status: res.status, ok: res.ok }, 'Response');\n return res;\n }\n\n async put(path: string, body: unknown): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n httpLog.info(\n { method: 'PUT', url, bodyKeys: body && typeof body === 'object' ? Object.keys(body) : undefined },\n 'Request'\n );\n const res = await fetch(url, {\n method: 'PUT',\n headers: this.headers(true),\n body: JSON.stringify(body)\n });\n httpLog.info({ method: 'PUT', url, status: res.status, ok: res.ok }, 'Response');\n return res;\n }\n}\n\n/**\n * Factory: reads config and returns an ApiClient instance.\n */\nexport function createApiClient(configDir?: string): ApiClient {\n const config = getConfig(configDir);\n return new ApiClient(config);\n}\n"],"mappings":";;AAKA,IAAa,YAAb,MAAuB;CACrB;CACA;CAEA,YAAY,QAAoB;AAC9B,OAAK,UAAU,OAAO;AACtB,OAAK,QAAQ,OAAO;;CAGtB,QAAgB,SAA0C;EACxD,MAAM,IAA4B,EAChC,cAAc,YACf;AAED,MAAI,KAAK,MACP,GAAE,gBAAgB,UAAU,KAAK;AAGnC,MAAI,QACF,GAAE,kBAAkB;AAGtB,SAAO;;CAGT,MAAM,IAAI,MAAiC;EACzC,MAAM,MAAM,GAAG,KAAK,UAAU;AAC9B,UAAQ,KAAK;GAAE,QAAQ;GAAO;GAAK,EAAE,UAAU;EAC/C,MAAM,MAAM,MAAM,MAAM,KAAK;GAC3B,QAAQ;GACR,SAAS,KAAK,QAAQ,MAAM;GAC7B,CAAC;AACF,UAAQ,KAAK;GAAE,QAAQ;GAAO;GAAK,QAAQ,IAAI;GAAQ,IAAI,IAAI;GAAI,EAAE,WAAW;AAChF,SAAO;;CAGT,MAAM,KAAK,MAAc,MAAkC;EACzD,MAAM,MAAM,GAAG,KAAK,UAAU;AAC9B,UAAQ,KACN;GAAE,QAAQ;GAAQ;GAAK,UAAU,QAAQ,OAAO,SAAS,WAAW,OAAO,KAAK,KAAK,GAAG,KAAA;GAAW,EACnG,UACD;EACD,MAAM,MAAM,MAAM,MAAM,KAAK;GAC3B,QAAQ;GACR,SAAS,KAAK,QAAQ,KAAK;GAC3B,MAAM,KAAK,UAAU,KAAK;GAC3B,CAAC;AACF,UAAQ,KAAK;GAAE,QAAQ;GAAQ;GAAK,QAAQ,IAAI;GAAQ,IAAI,IAAI;GAAI,EAAE,WAAW;AACjF,SAAO;;CAGT,MAAM,IAAI,MAAc,MAAkC;EACxD,MAAM,MAAM,GAAG,KAAK,UAAU;AAC9B,UAAQ,KACN;GAAE,QAAQ;GAAO;GAAK,UAAU,QAAQ,OAAO,SAAS,WAAW,OAAO,KAAK,KAAK,GAAG,KAAA;GAAW,EAClG,UACD;EACD,MAAM,MAAM,MAAM,MAAM,KAAK;GAC3B,QAAQ;GACR,SAAS,KAAK,QAAQ,KAAK;GAC3B,MAAM,KAAK,UAAU,KAAK;GAC3B,CAAC;AACF,UAAQ,KAAK;GAAE,QAAQ;GAAO;GAAK,QAAQ,IAAI;GAAQ,IAAI,IAAI;GAAI,EAAE,WAAW;AAChF,SAAO;;;;;;AAOX,SAAgB,gBAAgB,WAA+B;AAE7D,QAAO,IAAI,UADI,UAAU,UAAU,CACP"}
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tankpkg/cli",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "description": "Security-first package manager for AI agent skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,21 +17,22 @@
17
17
  "build:bundle": "esbuild dist/bin/tank.js --bundle --platform=node --format=esm --outfile=build/tank-bundle.mjs --external:fsevents",
18
18
  "build:sea": "bash scripts/build-binary.sh",
19
19
  "build:binary": "bun run build && bun run build:bundle && bun run build:sea",
20
+ "typecheck": "tsc --noEmit",
20
21
  "test": "vitest run",
21
- "lint": "biome check src/",
22
- "lint:fix": "biome check --fix src/",
23
- "format": "biome format --write src/"
22
+ "lint": "biome check .",
23
+ "lint:fix": "biome check --write ."
24
24
  },
25
25
  "devDependencies": {
26
- "@internal/shared": "workspace:*",
27
- "@types/node": "^25",
28
- "@types/tar": "^6.1.13",
29
- "esbuild": "^0.25.9",
30
- "tsdown": "^0.21.0",
31
- "vitest": "^4"
26
+ "@internals/helpers": "workspace:*",
27
+ "@internals/schemas": "workspace:*",
28
+ "@types/node": "^25.5.0",
29
+ "@types/tar": "^7.0.87",
30
+ "esbuild": "^0.27.4",
31
+ "tsdown": "^0.21.3",
32
+ "vitest": "^4.1.0"
32
33
  },
33
34
  "dependencies": {
34
- "@inquirer/prompts": "^8.2.0",
35
+ "@inquirer/prompts": "^8.3.0",
35
36
  "chalk": "^5.6.2",
36
37
  "commander": "^14.0.3",
37
38
  "ignore": "^7.0.5",
@@ -40,7 +41,7 @@
40
41
  "pino": "^10.3.1",
41
42
  "pino-loki": "^3.0.0",
42
43
  "semver": "^7.7.4",
43
- "tar": "^7.5.8",
44
+ "tar": "^7.5.11",
44
45
  "zod": "^4.3.6"
45
46
  }
46
47
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tankpkg/cli",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "description": "Security-first package manager for AI agent skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,21 +17,22 @@
17
17
  "build:bundle": "esbuild dist/bin/tank.js --bundle --platform=node --format=esm --outfile=build/tank-bundle.mjs --external:fsevents",
18
18
  "build:sea": "bash scripts/build-binary.sh",
19
19
  "build:binary": "bun run build && bun run build:bundle && bun run build:sea",
20
+ "typecheck": "tsc --noEmit",
20
21
  "test": "vitest run",
21
- "lint": "biome check src/",
22
- "lint:fix": "biome check --fix src/",
23
- "format": "biome format --write src/"
22
+ "lint": "biome check .",
23
+ "lint:fix": "biome check --write ."
24
24
  },
25
25
  "devDependencies": {
26
- "@internal/shared": "workspace:*",
27
- "@types/node": "^25",
28
- "@types/tar": "^6.1.13",
29
- "esbuild": "^0.25.9",
30
- "tsdown": "^0.21.0",
31
- "vitest": "^4"
26
+ "@internals/helpers": "workspace:*",
27
+ "@internals/schemas": "workspace:*",
28
+ "@types/node": "^25.5.0",
29
+ "@types/tar": "^7.0.87",
30
+ "esbuild": "^0.27.4",
31
+ "tsdown": "^0.21.3",
32
+ "vitest": "^4.1.0"
32
33
  },
33
34
  "dependencies": {
34
- "@inquirer/prompts": "^8.2.0",
35
+ "@inquirer/prompts": "^8.3.0",
35
36
  "chalk": "^5.6.2",
36
37
  "commander": "^14.0.3",
37
38
  "ignore": "^7.0.5",
@@ -40,7 +41,7 @@
40
41
  "pino": "^10.3.1",
41
42
  "pino-loki": "^3.0.0",
42
43
  "semver": "^7.7.4",
43
- "tar": "^7.5.8",
44
+ "tar": "^7.5.11",
44
45
  "zod": "^4.3.6"
45
46
  }
46
47
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"debug-logger-BJzuguP3.js","names":["pkg.version"],"sources":["../src/lib/config.ts","../src/lib/logger.ts","../package.json","../src/version.ts","../src/lib/debug-logger.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport interface TankConfig {\n token?: string;\n user?: { name: string; email: string };\n registry: string;\n}\n\nconst DEFAULT_CONFIG: TankConfig = {\n registry: 'https://tankpkg.dev'\n};\n\n/**\n * Get the path to the tank config directory.\n * Override with configDir parameter for testing.\n */\nexport function getConfigDir(configDir?: string): string {\n return configDir ?? path.join(os.homedir(), '.tank');\n}\n\n/**\n * Get the path to the tank config file.\n * Override with configDir parameter for testing.\n */\nexport function getConfigPath(configDir?: string): string {\n return path.join(getConfigDir(configDir), 'config.json');\n}\n\n/**\n * Read the tank config file. Returns defaults if file doesn't exist.\n * Override configDir for testing (avoids writing to real ~/.tank/).\n */\nexport function getConfig(configDir?: string): TankConfig {\n const configPath = getConfigPath(configDir);\n\n try {\n const raw = fs.readFileSync(configPath, 'utf-8');\n const parsed = JSON.parse(raw) as Partial<TankConfig>;\n const merged = { ...DEFAULT_CONFIG, ...parsed };\n const envToken = process.env.TANK_TOKEN?.trim();\n if (envToken) {\n merged.token = envToken;\n }\n return merged;\n } catch {\n const envToken = process.env.TANK_TOKEN?.trim();\n return {\n ...DEFAULT_CONFIG,\n ...(envToken ? { token: envToken } : {})\n };\n }\n}\n\n/**\n * Write config to disk. Merges with existing config.\n * Creates ~/.tank/ directory if it doesn't exist.\n * Sets file permissions to 0600 (owner read/write only) on Unix.\n */\nexport function setConfig(partial: Partial<TankConfig>, configDir?: string): void {\n const dir = getConfigDir(configDir);\n const configPath = getConfigPath(configDir);\n\n // Create directory with 0700 permissions if it doesn't exist\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n\n // Merge with existing config\n const existing = getConfig(configDir);\n const merged = { ...existing, ...partial };\n\n // Write config file\n fs.writeFileSync(configPath, `${JSON.stringify(merged, null, 2)}\\n`, {\n encoding: 'utf-8',\n mode: 0o600\n });\n}\n","import chalk from 'chalk';\n\nexport const logger = {\n info: (msg: string) => console.log(chalk.blue('ℹ'), msg),\n success: (msg: string) => console.log(chalk.green('✓'), msg),\n warn: (msg: string) => console.log(chalk.yellow('⚠'), msg),\n error: (msg: string) => console.error(chalk.red('✗'), msg)\n};\n","","import pkg from '../package.json' with { type: 'json' };\n\nexport const VERSION = pkg.version ?? '0.0.0';\nexport const USER_AGENT = `tank-cli/${VERSION}`;\n","import { appendFileSync } from 'node:fs';\nimport pino from 'pino';\n\nconst lokiUrl = process.env.TANK_LOKI_URL || 'http://localhost:3100';\nconst debugEnabled = process.env.TANK_DEBUG === '1' || process.env.TANK_DEBUG === 'true';\n\n// Buffer logs and push to Loki via HTTP (avoids pino.transport() worker thread serialization issues)\nconst logBuffer: string[] = [];\nlet flushTimer: ReturnType<typeof setInterval> | null = null;\n\nasync function flushToLoki() {\n if (logBuffer.length === 0) return;\n\n const logs = logBuffer.splice(0);\n const values: [string, string][] = logs.map((line) => {\n try {\n const parsed = JSON.parse(line);\n const ts = parsed.time ? String(new Date(parsed.time).getTime() * 1_000_000) : String(Date.now() * 1_000_000);\n return [ts, line];\n } catch {\n return [String(Date.now() * 1_000_000), line];\n }\n });\n\n try {\n await fetch(`${lokiUrl}/loki/api/v1/push`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n streams: [{ stream: { app: 'tank-cli' }, values }]\n })\n });\n } catch {\n logBuffer.unshift(...logs);\n }\n}\n\nconst lokiStream = {\n write(line: string) {\n const trimmed = line.trimEnd();\n logBuffer.push(trimmed);\n\n if (debugEnabled) {\n try {\n appendFileSync('/tmp/tank-cli-debug.log', `${trimmed}\\n`);\n } catch {}\n }\n\n if (!flushTimer) {\n flushTimer = setInterval(flushToLoki, 2000);\n }\n if (logBuffer.length >= 50) {\n void flushToLoki();\n }\n }\n};\n\nexport const debugLog = pino(\n {\n level: 'debug',\n timestamp: pino.stdTimeFunctions.isoTime,\n formatters: {\n level(label: string) {\n return { level: label };\n }\n }\n },\n lokiStream as unknown as pino.DestinationStream\n);\n\nexport const httpLog = debugLog.child({ module: 'http' });\nexport const authFlowLog = debugLog.child({ module: 'auth-flow' });\n\n/**\n * Flush pending logs before process exit.\n * Call this at the end of CLI commands to ensure logs are delivered.\n */\nexport async function flushLogs(): Promise<void> {\n if (flushTimer) {\n clearInterval(flushTimer);\n flushTimer = null;\n }\n await flushToLoki();\n}\n"],"mappings":"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"}