@meterapp/car-image 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -0
  3. package/dist/agent-config.js +104 -0
  4. package/dist/agent-config.js.map +1 -0
  5. package/dist/args.js +145 -0
  6. package/dist/args.js.map +1 -0
  7. package/dist/bin.js +9 -0
  8. package/dist/bin.js.map +1 -0
  9. package/dist/browser.js +20 -0
  10. package/dist/browser.js.map +1 -0
  11. package/dist/client.js +38 -0
  12. package/dist/client.js.map +1 -0
  13. package/dist/commands/agents.js +38 -0
  14. package/dist/commands/agents.js.map +1 -0
  15. package/dist/commands/billing.js +41 -0
  16. package/dist/commands/billing.js.map +1 -0
  17. package/dist/commands/catalog.js +169 -0
  18. package/dist/commands/catalog.js.map +1 -0
  19. package/dist/commands/describe.js +52 -0
  20. package/dist/commands/describe.js.map +1 -0
  21. package/dist/commands/doctor.js +53 -0
  22. package/dist/commands/doctor.js.map +1 -0
  23. package/dist/commands/help.js +58 -0
  24. package/dist/commands/help.js.map +1 -0
  25. package/dist/commands/images.js +168 -0
  26. package/dist/commands/images.js.map +1 -0
  27. package/dist/commands/index.js +44 -0
  28. package/dist/commands/index.js.map +1 -0
  29. package/dist/commands/login.js +64 -0
  30. package/dist/commands/login.js.map +1 -0
  31. package/dist/commands/maintenance.js +156 -0
  32. package/dist/commands/maintenance.js.map +1 -0
  33. package/dist/commands/onboard.js +42 -0
  34. package/dist/commands/onboard.js.map +1 -0
  35. package/dist/commands/whoami.js +41 -0
  36. package/dist/commands/whoami.js.map +1 -0
  37. package/dist/config.js +84 -0
  38. package/dist/config.js.map +1 -0
  39. package/dist/context.js +2 -0
  40. package/dist/context.js.map +1 -0
  41. package/dist/describe.js +226 -0
  42. package/dist/describe.js.map +1 -0
  43. package/dist/device-login.js +42 -0
  44. package/dist/device-login.js.map +1 -0
  45. package/dist/doctor.js +280 -0
  46. package/dist/doctor.js.map +1 -0
  47. package/dist/errors.js +54 -0
  48. package/dist/errors.js.map +1 -0
  49. package/dist/main.js +170 -0
  50. package/dist/main.js.map +1 -0
  51. package/dist/mcp/server.js +149 -0
  52. package/dist/mcp/server.js.map +1 -0
  53. package/dist/output.js +90 -0
  54. package/dist/output.js.map +1 -0
  55. package/dist/prompts.js +29 -0
  56. package/dist/prompts.js.map +1 -0
  57. package/dist/telemetry.js +50 -0
  58. package/dist/telemetry.js.map +1 -0
  59. package/dist/update.js +142 -0
  60. package/dist/update.js.map +1 -0
  61. package/dist/version.js +5 -0
  62. package/dist/version.js.map +1 -0
  63. package/package.json +56 -0
package/dist/errors.js ADDED
@@ -0,0 +1,54 @@
1
+ import { isCarImageError } from "@meterapp/car-image-sdk";
2
+ export class CliError extends Error {
3
+ exitCode;
4
+ hint;
5
+ constructor(message, exitCode = 1, hint) {
6
+ super(message);
7
+ this.name = "CliError";
8
+ this.exitCode = exitCode;
9
+ this.hint = hint;
10
+ }
11
+ }
12
+ /** Actionable next step for an API status code. */
13
+ export function fixHintFor(status, retryAfterSeconds) {
14
+ switch (status) {
15
+ case 401:
16
+ return "Run `car-image login` (or set CAR_IMAGE_API_KEY) to authenticate.";
17
+ case 402:
18
+ return "Out of credits. Run `car-image billing` to buy a pack (human approval required).";
19
+ case 403:
20
+ return "This key lacks the required scope. Create a key with the right scopes in the dashboard, or run `car-image login` for a CLI key.";
21
+ case 404:
22
+ return "Vehicle not in the catalog? Try `car-image search <make model>` or `car-image resolve <free text>`.";
23
+ case 429:
24
+ return `Rate limited. Wait ${retryAfterSeconds ?? "a few"} seconds and retry.`;
25
+ case 0:
26
+ return "Network problem. Check connectivity and --base-url / CAR_IMAGE_API_URL.";
27
+ case 502:
28
+ case 503:
29
+ return "Temporary upstream problem; credits for failed renders are refunded. Retry shortly.";
30
+ default:
31
+ return undefined;
32
+ }
33
+ }
34
+ /** Turns any thrown value into a user-facing message, hint and exit code. */
35
+ export function describeError(error) {
36
+ if (error instanceof CliError) {
37
+ return { message: error.message, hint: error.hint, exitCode: error.exitCode };
38
+ }
39
+ if (isCarImageError(error)) {
40
+ const typed = error;
41
+ return {
42
+ message: `${typed.title}: ${typed.detail}`,
43
+ hint: fixHintFor(typed.status, typed.retryAfterSeconds),
44
+ requestId: typed.requestId,
45
+ exitCode: 1,
46
+ status: typed.status,
47
+ };
48
+ }
49
+ if (error instanceof Error) {
50
+ return { message: error.message || error.name, exitCode: 1 };
51
+ }
52
+ return { message: String(error), exitCode: 1 };
53
+ }
54
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAK9E,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,QAAQ,CAAW;IACnB,IAAI,CAAqB;IAElC,YAAY,OAAe,EAAE,WAAqB,CAAC,EAAE,IAAa;QAChE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,mDAAmD;AACnD,MAAM,UAAU,UAAU,CAAC,MAAiC,EAAE,iBAAiC;IAC7F,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,GAAG;YACN,OAAO,mEAAmE,CAAC;QAC7E,KAAK,GAAG;YACN,OAAO,kFAAkF,CAAC;QAC5F,KAAK,GAAG;YACN,OAAO,iIAAiI,CAAC;QAC3I,KAAK,GAAG;YACN,OAAO,qGAAqG,CAAC;QAC/G,KAAK,GAAG;YACN,OAAO,sBAAsB,iBAAiB,IAAI,OAAO,qBAAqB,CAAC;QACjF,KAAK,CAAC;YACJ,OAAO,yEAAyE,CAAC;QACnF,KAAK,GAAG,CAAC;QACT,KAAK,GAAG;YACN,OAAO,qFAAqF,CAAC;QAC/F;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAUD,6EAA6E;AAC7E,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;IAChF,CAAC;IACD,IAAI,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAkB,KAAK,CAAC;QACnC,OAAO;YACL,OAAO,EAAE,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM,EAAE;YAC1C,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,iBAAiB,CAAC;YACvD,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,QAAQ,EAAE,CAAC;YACX,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IAC/D,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AACjD,CAAC"}
package/dist/main.js ADDED
@@ -0,0 +1,170 @@
1
+ import { parseArgs } from "./args.js";
2
+ import { createClientContext } from "./client.js";
3
+ import { COMMANDS, findCommand, helpEntries } from "./commands/index.js";
4
+ import { helpText } from "./commands/help.js";
5
+ import { configPath as resolveConfigPath, readConfig, updateCachePath, updateConfig } from "./config.js";
6
+ import { describeError } from "./errors.js";
7
+ import { createIo, paint } from "./output.js";
8
+ import { confirm } from "./prompts.js";
9
+ import { TELEMETRY_DISCLOSURE, commandEvent, newAnonymousId, sendEvents, simpleEvent, telemetryEnabled } from "./telemetry.js";
10
+ import { checkForUpdate, decideUpdate, detectPackageManager, isNpxInvocation, markNoticeShown, performUpdate } from "./update.js";
11
+ import { CLI_VERSION, PACKAGE_NAME } from "./version.js";
12
+ export function renderError(error, io) {
13
+ const described = describeError(error);
14
+ if (io.json) {
15
+ io.stdout(`${JSON.stringify({ error: { message: described.message, hint: described.hint ?? null, request_id: described.requestId ?? null, status: described.status ?? null } }, null, 2)}\n`);
16
+ }
17
+ else {
18
+ io.stderr(`${paint(io, "red", "✗")} ${described.message}\n`);
19
+ if (described.hint)
20
+ io.stderr(` ${paint(io, "yellow", "→")} ${described.hint}\n`);
21
+ if (described.requestId)
22
+ io.stderr(` ${paint(io, "dim", `request id: ${described.requestId}`)}\n`);
23
+ }
24
+ return described.exitCode;
25
+ }
26
+ async function setupTelemetry(config, cfgPath, env, io, commandName) {
27
+ if (!telemetryEnabled(config, env))
28
+ return { state: { enabled: false, anonymousId: null }, events: [] };
29
+ const events = [];
30
+ const patch = {};
31
+ let anonymousId = config.anonymousId ?? null;
32
+ if (!anonymousId) {
33
+ anonymousId = newAnonymousId();
34
+ patch.anonymousId = anonymousId;
35
+ events.push(simpleEvent(anonymousId, "cli_install", { command: commandName }));
36
+ }
37
+ if (!config.telemetryDisclosed && commandName !== "mcp") {
38
+ if (!io.quiet)
39
+ io.stderr(`${paint(io, "dim", TELEMETRY_DISCLOSURE)}\n`);
40
+ patch.telemetryDisclosed = true;
41
+ }
42
+ if (Object.keys(patch).length) {
43
+ await updateConfig(patch, cfgPath).catch(() => undefined);
44
+ }
45
+ return { state: { enabled: true, anonymousId }, events };
46
+ }
47
+ async function passiveUpdateCheck(config, env, io, commandName) {
48
+ try {
49
+ const cachePath = updateCachePath(env);
50
+ const { latest, cache } = await checkForUpdate({ cachePath });
51
+ const decision = decideUpdate({
52
+ current: CLI_VERSION,
53
+ latest,
54
+ isTTY: io.isTTY,
55
+ viaNpx: isNpxInvocation(env),
56
+ autoUpdate: config.autoUpdate ?? "ask",
57
+ lastNoticeAt: cache.lastNoticeAt ?? null,
58
+ now: Date.now(),
59
+ quiet: io.quiet,
60
+ command: commandName,
61
+ });
62
+ if (decision.action === "none")
63
+ return;
64
+ const manager = detectPackageManager(env);
65
+ if (decision.action === "notice") {
66
+ io.stderr(`${paint(io, "yellow", `Update available: ${CLI_VERSION} → ${decision.latest}.`)} Run \`car-image update\`${isNpxInvocation(env) ? ` (or \`npx ${PACKAGE_NAME}@latest\`)` : ""}. Silence with \`car-image config set autoUpdate never\`.\n`);
67
+ }
68
+ else if (decision.action === "ask") {
69
+ const yes = await confirm(io, `Update car-image ${CLI_VERSION} → ${decision.latest} now? (config: car-image config set autoUpdate always|never)`, false);
70
+ if (yes)
71
+ await performUpdate(manager, (line) => io.stderr(line));
72
+ }
73
+ else {
74
+ io.stderr(`${paint(io, "dim", `Auto-updating car-image ${CLI_VERSION} → ${decision.latest}…`)}\n`);
75
+ await performUpdate(manager, () => undefined);
76
+ }
77
+ await markNoticeShown(cachePath, cache);
78
+ }
79
+ catch {
80
+ // Update checks are best-effort and never block a command.
81
+ }
82
+ }
83
+ /** Entry point shared by the binary and tests. Resolves with the process exit code. */
84
+ export async function main(argv, deps = {}) {
85
+ const env = deps.env ?? process.env;
86
+ let args;
87
+ try {
88
+ args = parseArgs(argv);
89
+ }
90
+ catch (error) {
91
+ const io = { ...createIo({}, env), ...deps.io };
92
+ return renderError(error, io);
93
+ }
94
+ const io = { ...createIo(args.flags, env), ...deps.io };
95
+ if (args.flags.version === true) {
96
+ io.stdout(`${CLI_VERSION}\n`);
97
+ return 0;
98
+ }
99
+ const requested = args.command;
100
+ let command = requested ? findCommand(requested) : undefined;
101
+ if (args.flags.help === true) {
102
+ io.stdout(helpText(helpEntries(), command?.name ?? null));
103
+ return 0;
104
+ }
105
+ if (!requested) {
106
+ if (io.isTTY && io.stdinTTY)
107
+ command = findCommand("onboard");
108
+ else {
109
+ io.stdout(helpText(helpEntries()));
110
+ return 0;
111
+ }
112
+ }
113
+ if (!command) {
114
+ io.stderr(`Unknown command "${requested}". Commands: ${COMMANDS.filter((entry) => entry.name !== "onboard").map((entry) => entry.name).join(", ")}\n`);
115
+ return 2;
116
+ }
117
+ const cfgPath = resolveConfigPath(env);
118
+ const config = await readConfig(cfgPath);
119
+ const clientContext = createClientContext(args.flags, env, config, { fetch: deps.fetch });
120
+ const telemetry = await setupTelemetry(config, cfgPath, env, io, command.name);
121
+ const queued = [...telemetry.events];
122
+ if (!deps.skipUpdateCheck && command.name !== "mcp" && command.name !== "update" && io.isTTY) {
123
+ await passiveUpdateCheck(config, env, io, command.name);
124
+ }
125
+ const buildContext = (definition, parsed) => ({
126
+ args: parsed,
127
+ io,
128
+ env,
129
+ config,
130
+ configPath: cfgPath,
131
+ clientContext: definition.name === "onboard" || definition.name === "whoami" ? createClientContext(parsed.flags, env, config, { fetch: deps.fetch }) : clientContext,
132
+ telemetry: telemetry.state,
133
+ emit: (event) => {
134
+ queued.push(event);
135
+ },
136
+ runCommand: async (name, extra) => {
137
+ const target = findCommand(name);
138
+ if (!target)
139
+ return 2;
140
+ // Re-read config so a fresh login is visible to the next step.
141
+ const latest = await readConfig(cfgPath);
142
+ const nested = parseArgs(extra);
143
+ const merged = { command: name, positionals: nested.positionals, flags: { ...args.flags, ...nested.flags } };
144
+ const nestedContext = {
145
+ ...buildContext(target, merged),
146
+ config: latest,
147
+ clientContext: createClientContext(merged.flags, env, latest, { fetch: deps.fetch }),
148
+ };
149
+ try {
150
+ return await target.run(nestedContext);
151
+ }
152
+ catch (error) {
153
+ return renderError(error, io);
154
+ }
155
+ },
156
+ });
157
+ let code;
158
+ try {
159
+ code = await command.run(buildContext(command, args));
160
+ }
161
+ catch (error) {
162
+ code = renderError(error, io);
163
+ }
164
+ if (telemetry.state.enabled && telemetry.state.anonymousId && command.name !== "mcp") {
165
+ queued.push(commandEvent(telemetry.state.anonymousId, command.name, code));
166
+ void sendEvents(clientContext.client, queued);
167
+ }
168
+ return code;
169
+ }
170
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ import { McpServer } from "@modelcontextprotocol/server";
2
+ import { serveStdio } from "@modelcontextprotocol/server/stdio";
3
+ import { isCarImageError } from "@meterapp/car-image-sdk";
4
+ import { MCP_INSTRUCTIONS, MCP_SERVER_INFO, MCP_TOOLS, errorToolResult, formatApiReference, jsonToolResult, nextStepFor, } from "@meterapp/car-image-sdk/mcp";
5
+ /** Converts the zod-parsed tool input into SDK params (drops undefined optionals). */
6
+ export function toImageParams(input) {
7
+ const params = { make: input.make, model: input.model, year: input.year, view: input.view, color: input.color, format: input.format };
8
+ if (input.size)
9
+ params.size = input.size;
10
+ if (input.width !== undefined)
11
+ params.width = input.width;
12
+ if (input.height !== undefined)
13
+ params.height = input.height;
14
+ return params;
15
+ }
16
+ /** Maps any thrown value onto an `isError` tool result with guidance for the agent. */
17
+ export function toolErrorResult(error) {
18
+ if (isCarImageError(error)) {
19
+ const extra = { status: error.status, request_id: error.requestId };
20
+ if (error.retryAfterSeconds !== null)
21
+ extra.retry_after = error.retryAfterSeconds;
22
+ if (error.problem?.balance !== undefined)
23
+ extra.balance = error.problem.balance;
24
+ if (error.problem?.required_credits !== undefined)
25
+ extra.required_credits = error.problem.required_credits;
26
+ return errorToolResult(`${error.title}: ${error.detail}\n${nextStepFor(error.status)}`, extra);
27
+ }
28
+ return errorToolResult(error instanceof Error ? error.message : String(error));
29
+ }
30
+ export function cliCommandFor(params) {
31
+ const quote = (value) => (/[^A-Za-z0-9._-]/.test(value) ? JSON.stringify(value) : value);
32
+ const parts = [`car-image get --make ${quote(params.make)} --model ${quote(params.model)} --year ${params.year}`];
33
+ if (params.view)
34
+ parts.push(`--view ${params.view}`);
35
+ if (params.color)
36
+ parts.push(`--color ${params.color}`);
37
+ return parts.join(" ");
38
+ }
39
+ function register(server, name, handler) {
40
+ const definition = MCP_TOOLS[name];
41
+ server.registerTool(definition.name, {
42
+ title: definition.title,
43
+ description: definition.description,
44
+ inputSchema: definition.inputSchema,
45
+ annotations: definition.annotations,
46
+ }, async (args) => {
47
+ try {
48
+ return await handler(args);
49
+ }
50
+ catch (error) {
51
+ return toolErrorResult(error);
52
+ }
53
+ });
54
+ }
55
+ /**
56
+ * Builds the stdio MCP server. Tools call the REST API through the SDK with
57
+ * the configured key, so this process is the only place the key lives.
58
+ */
59
+ export function buildStdioMcpServer(client) {
60
+ const server = new McpServer({ ...MCP_SERVER_INFO }, { capabilities: { tools: {} }, instructions: MCP_INSTRUCTIONS });
61
+ register(server, "get_car_image", async (input) => {
62
+ const params = toImageParams(input);
63
+ const image = await client.getImage(params);
64
+ const usage = {
65
+ credits_charged: image.creditsCharged,
66
+ credits_remaining: image.creditsRemaining,
67
+ source: image.source,
68
+ width: image.width,
69
+ height: image.height,
70
+ content_type: image.contentType,
71
+ request_id: image.requestId,
72
+ vehicle: { make: input.make, model: input.model, year: input.year, view: input.view, color: input.color, format: input.format },
73
+ };
74
+ return {
75
+ content: [
76
+ { type: "image", data: Buffer.from(image.bytes).toString("base64"), mimeType: image.contentType.split(";")[0] ?? "image/png" },
77
+ { type: "text", text: JSON.stringify(usage) },
78
+ ],
79
+ structuredContent: usage,
80
+ };
81
+ });
82
+ register(server, "create_car_image_urls", async (input) => {
83
+ const result = await client.createImageUrls(input.images.map(toImageParams), { ttlSeconds: input.ttl_seconds, maxUses: input.max_uses });
84
+ const summary = `Created ${result.data.length} signed URL${result.data.length === 1 ? "" : "s"}; charged ${result.billing.credits_charged} credit(s), ${result.billing.credits_remaining} remaining. Embed the url values directly; they need no key.`;
85
+ return jsonToolResult({ ...result }, summary);
86
+ });
87
+ register(server, "search_vehicles", async (input) => {
88
+ const result = await client.searchVehicles(input.query, { limit: input.limit, year: input.year });
89
+ return jsonToolResult({ ...result }, `${result.data.results.length} result(s) for "${input.query}".`);
90
+ });
91
+ register(server, "resolve_vehicle", async (input) => {
92
+ const result = await client.resolve(input.query);
93
+ const params = result.data.params;
94
+ const payload = { ...result, cli: cliCommandFor(params) };
95
+ return jsonToolResult(payload, `Resolved to ${params.make} ${params.model} ${params.year}, view ${params.view}, color ${params.color} (confidence ${result.data.confidence}).`);
96
+ });
97
+ register(server, "list_image_options", async () => {
98
+ const result = await client.options();
99
+ return jsonToolResult({ ...result });
100
+ });
101
+ register(server, "get_account", async () => {
102
+ const result = await client.account();
103
+ const perDollar = result.data.pricing?.credits_per_dollar ?? 1000;
104
+ const payload = { ...result, credits_usd: Number((result.data.credits / perDollar).toFixed(2)) };
105
+ return jsonToolResult(payload, `${result.data.credits.toLocaleString("en-US")} credits ≈ $${(result.data.credits / perDollar).toFixed(2)}.`);
106
+ });
107
+ register(server, "rate_image", async (input) => {
108
+ const feedback = { rating: input.rating, verdict: input.verdict, reason: input.reason };
109
+ if (input.rating === undefined && input.verdict === undefined) {
110
+ return errorToolResult("Provide verdict (good|bad) or rating (1-5).");
111
+ }
112
+ let result;
113
+ if (input.request_id) {
114
+ result = await client.feedback({ requestId: input.request_id, ...feedback });
115
+ }
116
+ else if (input.make && input.model && input.year !== undefined) {
117
+ result = await client.feedback({ make: input.make, model: input.model, year: input.year, view: input.view, color: input.color, ...feedback });
118
+ }
119
+ else {
120
+ return errorToolResult("Identify the image with request_id, or with make, model and year.");
121
+ }
122
+ return jsonToolResult({ ...result }, "Feedback recorded. Thank you.");
123
+ });
124
+ register(server, "describe_api", async (input) => {
125
+ const text = formatApiReference(input.endpoint);
126
+ return { content: [{ type: "text", text }] };
127
+ });
128
+ return server;
129
+ }
130
+ /** Serves MCP over stdio until the client disconnects or the process is signalled. */
131
+ export function serveMcpStdio(client, log = (line) => process.stderr.write(line)) {
132
+ return new Promise((resolve) => {
133
+ const handle = serveStdio(() => buildStdioMcpServer(client), {
134
+ onerror: (error) => log(`car-image mcp: ${error.message}\n`),
135
+ });
136
+ let closed = false;
137
+ const shutdown = () => {
138
+ if (closed)
139
+ return;
140
+ closed = true;
141
+ void handle.close().finally(resolve);
142
+ };
143
+ process.once("SIGINT", shutdown);
144
+ process.once("SIGTERM", shutdown);
145
+ process.stdin.once("end", shutdown);
146
+ process.stdin.once("close", shutdown);
147
+ });
148
+ }
149
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
package/dist/output.js ADDED
@@ -0,0 +1,90 @@
1
+ import { styleText } from "node:util";
2
+ export function createIo(flags, env = process.env) {
3
+ const isTTY = Boolean(process.stdout.isTTY);
4
+ const colorFlag = flags["color-output"];
5
+ const color = colorFlag === false
6
+ ? false
7
+ : env.NO_COLOR !== undefined
8
+ ? false
9
+ : env.FORCE_COLOR !== undefined && env.FORCE_COLOR !== "0"
10
+ ? true
11
+ : isTTY;
12
+ return {
13
+ stdout: (text) => {
14
+ process.stdout.write(text);
15
+ },
16
+ stderr: (text) => {
17
+ process.stderr.write(text);
18
+ },
19
+ isTTY,
20
+ stdinTTY: Boolean(process.stdin.isTTY),
21
+ color,
22
+ json: flags.json === true,
23
+ quiet: flags.quiet === true,
24
+ };
25
+ }
26
+ /** Colors via `util.styleText` (Node 20.12+); plain text elsewhere or when disabled. */
27
+ export function paint(io, style, text) {
28
+ if (!io.color || typeof styleText !== "function")
29
+ return text;
30
+ try {
31
+ return styleText(style, text);
32
+ }
33
+ catch {
34
+ return text;
35
+ }
36
+ }
37
+ const ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
38
+ export function visibleLength(text) {
39
+ return text.replace(ANSI_PATTERN, "").length;
40
+ }
41
+ function pad(text, width) {
42
+ const missing = width - visibleLength(text);
43
+ return missing > 0 ? text + " ".repeat(missing) : text;
44
+ }
45
+ /** Fixed-width table via padEnd; header row underlined with dashes. */
46
+ export function table(rows, header) {
47
+ const all = header ? [header, ...rows] : rows;
48
+ if (all.length === 0)
49
+ return "";
50
+ const columns = Math.max(...all.map((row) => row.length));
51
+ const widths = Array.from({ length: columns }, (_, column) => Math.max(...all.map((row) => visibleLength(String(row[column] ?? "")))));
52
+ const render = (row) => row.map((cell, column) => (column === columns - 1 ? String(cell ?? "") : pad(String(cell ?? ""), widths[column] ?? 0))).join(" ").trimEnd();
53
+ const lines = [];
54
+ if (header) {
55
+ lines.push(render(header));
56
+ lines.push(widths.map((width) => "-".repeat(width)).join(" "));
57
+ }
58
+ for (const row of rows)
59
+ lines.push(render(row));
60
+ return lines.join("\n");
61
+ }
62
+ /** Two-column key/value block. */
63
+ export function keyValues(io, entries) {
64
+ const width = Math.max(...entries.map(([key]) => key.length));
65
+ return entries.map(([key, value]) => `${paint(io, "dim", pad(key, width))} ${value}`).join("\n");
66
+ }
67
+ export function formatInteger(value) {
68
+ if (value === null || value === undefined || !Number.isFinite(value))
69
+ return "—";
70
+ return value.toLocaleString("en-US");
71
+ }
72
+ /** `1234` credits → `$1.23`. */
73
+ export function creditsToUsd(credits, creditsPerDollar = 1000) {
74
+ if (credits === null || credits === undefined || !Number.isFinite(credits))
75
+ return "—";
76
+ return `$${(credits / creditsPerDollar).toFixed(2)}`;
77
+ }
78
+ export function printJson(io, value) {
79
+ io.stdout(`${JSON.stringify(value, null, 2)}\n`);
80
+ }
81
+ export function ok(io, text) {
82
+ return `${paint(io, "green", "✓")} ${text}`;
83
+ }
84
+ export function warn(io, text) {
85
+ return `${paint(io, "yellow", "!")} ${text}`;
86
+ }
87
+ export function fail(io, text) {
88
+ return `${paint(io, "red", "✗")} ${text}`;
89
+ }
90
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { createInterface } from "node:readline/promises";
2
+ /** y/N confirmation on a TTY; returns `fallback` when stdin is not interactive. */
3
+ export async function confirm(io, question, fallback = false) {
4
+ if (!io.stdinTTY)
5
+ return fallback;
6
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
7
+ try {
8
+ const answer = (await rl.question(`${question} ${fallback ? "[Y/n]" : "[y/N]"} `)).trim().toLowerCase();
9
+ if (!answer)
10
+ return fallback;
11
+ return answer === "y" || answer === "yes";
12
+ }
13
+ finally {
14
+ rl.close();
15
+ }
16
+ }
17
+ export async function ask(io, question, fallback = "") {
18
+ if (!io.stdinTTY)
19
+ return fallback;
20
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
21
+ try {
22
+ const answer = (await rl.question(`${question} `)).trim();
23
+ return answer || fallback;
24
+ }
25
+ finally {
26
+ rl.close();
27
+ }
28
+ }
29
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAAmC,EAAE,QAAgB,EAAE,QAAQ,GAAG,KAAK;IACnG,IAAI,CAAC,EAAE,CAAC,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAClC,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,QAAQ,IAAI,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACxG,IAAI,CAAC,MAAM;YAAE,OAAO,QAAQ,CAAC;QAC7B,OAAO,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,KAAK,CAAC;IAC5C,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,EAAmC,EAAE,QAAgB,EAAE,QAAQ,GAAG,EAAE;IAC5F,IAAI,CAAC,EAAE,CAAC,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAClC,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1D,OAAO,MAAM,IAAI,QAAQ,CAAC;IAC5B,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { platform, release } from "node:os";
3
+ import { CLI_VERSION } from "./version.js";
4
+ export const TELEMETRY_TIMEOUT_MS = 1500;
5
+ export const TELEMETRY_DISCLOSURE = "car-image sends anonymous usage events (command name, version, OS, Node version, exit code; never keys, vehicles or file names). Disable with `car-image telemetry off` or CAR_IMAGE_TELEMETRY=0.";
6
+ /** `CAR_IMAGE_TELEMETRY=0` (or `false`/`off`) wins; otherwise the config flag; default on. */
7
+ export function telemetryEnabled(config, env = process.env) {
8
+ const raw = env.CAR_IMAGE_TELEMETRY?.trim().toLowerCase();
9
+ if (raw === "0" || raw === "false" || raw === "off" || raw === "no")
10
+ return false;
11
+ if (raw === "1" || raw === "true" || raw === "on" || raw === "yes")
12
+ return true;
13
+ if (env.DO_NOT_TRACK === "1")
14
+ return false;
15
+ return config.telemetry !== false;
16
+ }
17
+ export function newAnonymousId() {
18
+ return randomUUID();
19
+ }
20
+ export function baseProperties() {
21
+ return {
22
+ version: CLI_VERSION,
23
+ os: `${platform()} ${release()}`.trim(),
24
+ node: process.version,
25
+ };
26
+ }
27
+ export function commandEvent(anonymousId, command, exitCode, extra = {}) {
28
+ return {
29
+ event: "cli_command",
30
+ anonymous_id: anonymousId,
31
+ source: "cli",
32
+ properties: { ...baseProperties(), command, exit_code: exitCode, ...extra },
33
+ };
34
+ }
35
+ export function simpleEvent(anonymousId, event, extra = {}) {
36
+ return { event, anonymous_id: anonymousId, source: "cli", properties: { ...baseProperties(), ...extra } };
37
+ }
38
+ /**
39
+ * Fire-and-forget: never throws, never blocks the command for more than
40
+ * `TELEMETRY_TIMEOUT_MS` (the abort also releases the socket so the process
41
+ * can exit).
42
+ */
43
+ export function sendEvents(client, events, timeoutMs = TELEMETRY_TIMEOUT_MS) {
44
+ if (events.length === 0)
45
+ return Promise.resolve();
46
+ return client
47
+ .trackEvents(events, { retries: 0, timeoutMs })
48
+ .then(() => undefined, () => undefined);
49
+ }
50
+ //# sourceMappingURL=telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAEzC,MAAM,CAAC,MAAM,oBAAoB,GAC/B,mMAAmM,CAAC;AAEtM,8FAA8F;AAC9F,MAAM,UAAU,gBAAgB,CAAC,MAAoC,EAAE,MAAW,OAAO,CAAC,GAAG;IAC3F,MAAM,GAAG,GAAG,GAAG,CAAC,mBAAmB,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1D,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAClF,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAChF,IAAI,GAAG,CAAC,YAAY,KAAK,GAAG;QAAE,OAAO,KAAK,CAAC;IAC3C,OAAO,MAAM,CAAC,SAAS,KAAK,KAAK,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,OAAO,EAAE,WAAW;QACpB,EAAE,EAAE,GAAG,QAAQ,EAAE,IAAI,OAAO,EAAE,EAAE,CAAC,IAAI,EAAE;QACvC,IAAI,EAAE,OAAO,CAAC,OAAO;KACtB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,WAAmB,EAAE,OAAe,EAAE,QAAgB,EAAE,QAAiC,EAAE;IACtH,OAAO;QACL,KAAK,EAAE,aAAa;QACpB,YAAY,EAAE,WAAW;QACzB,MAAM,EAAE,KAAK;QACb,UAAU,EAAE,EAAE,GAAG,cAAc,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE;KAC5E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,KAAiD,EAAE,QAAiC,EAAE;IACrI,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,GAAG,cAAc,EAAE,EAAE,GAAG,KAAK,EAAE,EAAE,CAAC;AAC5G,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAA2C,EAAE,MAAwB,EAAE,SAAS,GAAG,oBAAoB;IAChI,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAClD,OAAO,MAAM;SACV,WAAW,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC;SAC9C,IAAI,CACH,GAAG,EAAE,CAAC,SAAS,EACf,GAAG,EAAE,CAAC,SAAS,CAChB,CAAC;AACN,CAAC"}