@garuhq/cli 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,75 @@
3
3
  All notable changes to `@garuhq/cli` are documented in this file. Format:
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning: [SemVer](https://semver.org/).
5
5
 
6
+ ## [0.1.2] — 2026-04-08
7
+
8
+ Post-review batch — addresses all findings from an internal code review.
9
+
10
+ ### Security
11
+
12
+ - **`install.sh` now verifies binaries against `SHA256SUMS.txt`.** The installer
13
+ downloads the checksum file from the same release, grep's the expected hash
14
+ for the target asset, and fails the install if the binary has been tampered
15
+ with. Supports both `sha256sum` (Linux) and `shasum -a 256` (macOS).
16
+ - **Credentials file path now uses `node:path`'s `dirname`** instead of a
17
+ `lastIndexOf('/')` slice, fixing `garu login` on Windows (`npm i -g @garuhq/cli`).
18
+ - Upgrade dev dependencies to clear `npm audit` findings:
19
+ - `vitest` 1.5.0 → 4.1.3 (closes critical vitest RCE advisory)
20
+ - `tsup` 8.0.2 → 8.5.1, `tsx` 4.7.2 → 4.21.0
21
+ - `@inquirer/prompts` 5.0.2 → 8.4.1 (clears the `tmp` symlink chain)
22
+
23
+ ### Fixed
24
+
25
+ - **`garu login` no longer claims to validate the API key.** The prompt now
26
+ says "Checking connectivity to Garu..." instead of "Validating key with
27
+ Garu..." — a key that passes the `sk_(live|test)_...` regex will still be
28
+ saved even if the backend would reject it. A real authenticated probe lands
29
+ once the backend exposes `GET /api/v1/me`.
30
+ - **`garu logout --profile <name>` now deletes the credentials file** when the
31
+ removed profile was the last one, instead of leaving an orphaned
32
+ `activeProfile` pointing at nothing.
33
+ - **SDK errors are now classified via `instanceof GaruError`** instead of
34
+ `.name.startsWith('Garu')` duck-typing.
35
+
36
+ ### Changed
37
+
38
+ - Removed non-null assertions on credit-card fields in `charges create`;
39
+ replaced with a type-guard assertion so the TypeScript narrowing is
40
+ compile-time enforced.
41
+ - Collapsed `globalsToOutput` + `globalFlagsToCommandOptions` into one
42
+ `toCommandOptions` helper. `src/index.ts` is ~25 lines shorter.
43
+ - Removed unused `cliUserAgent()` dead code from `src/lib/client.ts`.
44
+
45
+ ### Infrastructure
46
+
47
+ - **All third-party GitHub Actions are now SHA-pinned** in both `ci.yml` and
48
+ `release.yml`: `actions/checkout`, `actions/setup-node`,
49
+ `actions/upload-artifact`, `actions/download-artifact`, `oven-sh/setup-bun`,
50
+ `ludeeus/action-shellcheck`. Human-readable version as trailing comment.
51
+ - **Release workflow asserts `package.json .version == $TAG_NAME`** before
52
+ publishing to npm. Mismatched tags fail fast with a clear error instead of
53
+ hitting `npm publish` with a stale version.
54
+
55
+ ### Tests
56
+
57
+ - Added 6 new tests for `logoutCommand` covering: removing the last profile
58
+ deletes the file, removing a non-active profile preserves the active one,
59
+ removing the active profile elects a remaining profile, and the not-found
60
+ error path.
61
+ - Total: 42 tests across 6 files (previously 36 across 5).
62
+
63
+ ## [0.1.1] — 2026-04-08
64
+
65
+ ### Fixed
66
+
67
+ - Compiled binaries (produced by `bun build --compile`) now run correctly when
68
+ distributed under names like `garu-darwin-arm64` before being renamed by the
69
+ installer. v0.1.0 had an entry-point guard that only matched filenames ending
70
+ in `garu`/`garu.cjs`, so the downloaded binary was a no-op until renamed.
71
+ - The npm package `0.1.0` is not affected because the `bin/garu.cjs` wrapper
72
+ always matched the guard. 0.1.0 remains published; 0.1.1 is the first release
73
+ where both `curl | bash` and `npm install -g` ship a working CLI.
74
+
6
75
  ## [0.1.0] — 2026-04-08
7
76
 
8
77
  ### Added
package/dist/index.cjs CHANGED
@@ -4,10 +4,9 @@ var commander = require('commander');
4
4
  var os = require('os');
5
5
  var path = require('path');
6
6
  var promises = require('fs/promises');
7
- var pc = require('picocolors');
8
7
  var node = require('@garuhq/node');
8
+ var pc = require('picocolors');
9
9
  var fs = require('fs');
10
- var prompts = require('@inquirer/prompts');
11
10
 
12
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
12
 
@@ -15,7 +14,8 @@ var pc__default = /*#__PURE__*/_interopDefault(pc);
15
14
 
16
15
  // src/index.ts
17
16
 
18
- // src/lib/errors.ts
17
+ // src/version.ts
18
+ var CLI_VERSION = "0.1.2";
19
19
  var CliError = class extends Error {
20
20
  code;
21
21
  exitCode;
@@ -27,16 +27,11 @@ var CliError = class extends Error {
27
27
  }
28
28
  };
29
29
  function toCliError(err) {
30
- if (err instanceof CliError)
31
- return err;
32
- if (err && typeof err === "object" && "name" in err && "code" in err) {
33
- const e = err;
34
- if (typeof e.name === "string" && e.name.startsWith("Garu")) {
35
- return new CliError(mapSdkCodeToCliCode(e.code), e.message ?? "Request failed", 1);
36
- }
30
+ if (err instanceof CliError) return err;
31
+ if (err instanceof node.GaruError) {
32
+ return new CliError(mapSdkCodeToCliCode(err.code), err.message, 1);
37
33
  }
38
- if (err instanceof Error)
39
- return new CliError("unknown_error", err.message);
34
+ if (err instanceof Error) return new CliError("unknown_error", err.message);
40
35
  return new CliError("unknown_error", String(err));
41
36
  }
42
37
  function mapSdkCodeToCliCode(sdkCode) {
@@ -68,8 +63,7 @@ var DEFAULT_FILE = {
68
63
  profiles: {}
69
64
  };
70
65
  function credentialsPath(env = process.env) {
71
- if (env.GARU_CREDENTIALS_PATH)
72
- return env.GARU_CREDENTIALS_PATH;
66
+ if (env.GARU_CREDENTIALS_PATH) return env.GARU_CREDENTIALS_PATH;
73
67
  const base = env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
74
68
  return path.join(base, "garu", "credentials.json");
75
69
  }
@@ -90,18 +84,16 @@ async function loadCredentials(env = process.env) {
90
84
  }
91
85
  }
92
86
  async function saveCredentials(file, env = process.env) {
93
- const path = credentialsPath(env);
94
- const dir = path.slice(0, path.lastIndexOf("/"));
95
- await promises.mkdir(dir, { recursive: true, mode: 448 });
96
- await promises.writeFile(path, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
87
+ const path$1 = credentialsPath(env);
88
+ await promises.mkdir(path.dirname(path$1), { recursive: true, mode: 448 });
89
+ await promises.writeFile(path$1, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
97
90
  }
98
91
  async function deleteCredentials(env = process.env) {
99
92
  const path = credentialsPath(env);
100
93
  try {
101
94
  await promises.rm(path);
102
95
  } catch (err) {
103
- if (err.code !== "ENOENT")
104
- throw err;
96
+ if (err.code !== "ENOENT") throw err;
105
97
  }
106
98
  }
107
99
  function upsertProfile(file, name, profile) {
@@ -120,8 +112,7 @@ async function credentialsFileMode(env = process.env) {
120
112
  }
121
113
  }
122
114
  function normalize(raw) {
123
- if (!raw || typeof raw !== "object")
124
- return { ...DEFAULT_FILE };
115
+ if (!raw || typeof raw !== "object") return { ...DEFAULT_FILE };
125
116
  const obj = raw;
126
117
  return {
127
118
  version: 1,
@@ -130,8 +121,7 @@ function normalize(raw) {
130
121
  };
131
122
  }
132
123
  function resolveMode(opts = {}, stdout = process.stdout) {
133
- if (opts.mode)
134
- return opts.mode;
124
+ if (opts.mode) return opts.mode;
135
125
  return stdout.isTTY ? "pretty" : "json";
136
126
  }
137
127
  function printResult(value, opts = {}) {
@@ -150,18 +140,14 @@ function printResult(value, opts = {}) {
150
140
  `);
151
141
  }
152
142
  function printStatus(message, opts = {}) {
153
- if (opts.quiet)
154
- return;
155
- if (resolveMode(opts) === "json")
156
- return;
143
+ if (opts.quiet) return;
144
+ if (resolveMode(opts) === "json") return;
157
145
  process.stderr.write(`${pc__default.default.dim("\u2192")} ${message}
158
146
  `);
159
147
  }
160
148
  function printSuccess(message, opts = {}) {
161
- if (opts.quiet)
162
- return;
163
- if (resolveMode(opts) === "json")
164
- return;
149
+ if (opts.quiet) return;
150
+ if (resolveMode(opts) === "json") return;
165
151
  process.stderr.write(`${pc__default.default.green("\u2713")} ${message}
166
152
  `);
167
153
  }
@@ -220,16 +206,10 @@ async function resolveAuthOptional(opts = {}) {
220
206
  try {
221
207
  return await resolveAuth(opts);
222
208
  } catch (err) {
223
- if (err instanceof CliError && err.code === "auth_error")
224
- return null;
209
+ if (err instanceof CliError && err.code === "auth_error") return null;
225
210
  throw err;
226
211
  }
227
212
  }
228
-
229
- // src/version.ts
230
- var CLI_VERSION = "0.1.0";
231
-
232
- // src/lib/client.ts
233
213
  function createGaruClient(opts) {
234
214
  return new node.Garu({
235
215
  apiKey: opts.auth.apiKey,
@@ -239,8 +219,7 @@ function createGaruClient(opts) {
239
219
 
240
220
  // src/commands/charges.ts
241
221
  async function getClient(opts) {
242
- if (opts.garu)
243
- return opts.garu;
222
+ if (opts.garu) return opts.garu;
244
223
  const auth = await resolveAuth({
245
224
  ...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
246
225
  ...opts.profile !== void 0 ? { profile: opts.profile } : {}
@@ -250,8 +229,17 @@ async function getClient(opts) {
250
229
  ...opts.baseUrl !== void 0 ? { baseUrl: opts.baseUrl } : {}
251
230
  });
252
231
  }
232
+ function assertCardFieldsPresent(opts) {
233
+ const missing = [];
234
+ if (!opts.cardNumber) missing.push("--card-number");
235
+ if (!opts.cardCvv) missing.push("--card-cvv");
236
+ if (!opts.cardExpiration) missing.push("--card-expiration");
237
+ if (!opts.cardHolder) missing.push("--card-holder");
238
+ if (missing.length) {
239
+ throw new CliError("invalid_input", `Credit-card charges require: ${missing.join(", ")}`);
240
+ }
241
+ }
253
242
  async function chargesCreateCommand(opts) {
254
- validateCreate(opts);
255
243
  const garu = await getClient(opts);
256
244
  const customer = {
257
245
  name: opts.customerName,
@@ -259,13 +247,18 @@ async function chargesCreateCommand(opts) {
259
247
  document: opts.customerDocument,
260
248
  phone: opts.customerPhone
261
249
  };
262
- const charge = await garu.charges.create({
250
+ const base = {
263
251
  productId: opts.productId,
264
252
  paymentMethod: opts.type,
265
253
  customer,
266
- ...opts.additionalInfo !== void 0 ? { additionalInfo: opts.additionalInfo } : {},
267
- ...opts.idempotencyKey !== void 0 ? { idempotencyKey: opts.idempotencyKey } : {},
268
- ...opts.type === "credit_card" && opts.cardNumber ? {
254
+ additionalInfo: opts.additionalInfo,
255
+ idempotencyKey: opts.idempotencyKey
256
+ };
257
+ let charge;
258
+ if (opts.type === "credit_card") {
259
+ assertCardFieldsPresent(opts);
260
+ charge = await garu.charges.create({
261
+ ...base,
269
262
  cardInfo: {
270
263
  cardNumber: opts.cardNumber,
271
264
  cvv: opts.cardCvv,
@@ -273,8 +266,10 @@ async function chargesCreateCommand(opts) {
273
266
  holderName: opts.cardHolder,
274
267
  installments: opts.installments ?? 1
275
268
  }
276
- } : {}
277
- });
269
+ });
270
+ } else {
271
+ charge = await garu.charges.create(base);
272
+ }
278
273
  printResult(charge, { ...opts, prettyPrint: prettyCharge });
279
274
  return charge;
280
275
  }
@@ -287,32 +282,13 @@ async function chargesGetCommand(opts) {
287
282
  async function chargesRefundCommand(opts) {
288
283
  const garu = await getClient(opts);
289
284
  const params = {};
290
- if (opts.amount !== void 0)
291
- params.amount = opts.amount;
292
- if (opts.reason !== void 0)
293
- params.reason = opts.reason;
294
- if (opts.idempotencyKey !== void 0)
295
- params.idempotencyKey = opts.idempotencyKey;
285
+ if (opts.amount !== void 0) params.amount = opts.amount;
286
+ if (opts.reason !== void 0) params.reason = opts.reason;
287
+ if (opts.idempotencyKey !== void 0) params.idempotencyKey = opts.idempotencyKey;
296
288
  const charge = await garu.charges.refund(opts.id, params);
297
289
  printResult(charge, { ...opts, prettyPrint: prettyCharge });
298
290
  return charge;
299
291
  }
300
- function validateCreate(opts) {
301
- if (opts.type === "credit_card") {
302
- const missing = [];
303
- if (!opts.cardNumber)
304
- missing.push("--card-number");
305
- if (!opts.cardCvv)
306
- missing.push("--card-cvv");
307
- if (!opts.cardExpiration)
308
- missing.push("--card-expiration");
309
- if (!opts.cardHolder)
310
- missing.push("--card-holder");
311
- if (missing.length) {
312
- throw new CliError("invalid_input", `Credit-card charges require: ${missing.join(", ")}`);
313
- }
314
- }
315
- }
316
292
  function prettyCharge(charge) {
317
293
  const lines = [
318
294
  `Charge ${charge.id}`,
@@ -321,8 +297,7 @@ function prettyCharge(charge) {
321
297
  ` method: ${charge.paymentMethodId}`,
322
298
  ` date: ${charge.date}`
323
299
  ];
324
- if (charge.deadline)
325
- lines.push(` deadline: ${charge.deadline}`);
300
+ if (charge.deadline) lines.push(` deadline: ${charge.deadline}`);
326
301
  return lines.join("\n");
327
302
  }
328
303
  async function doctorCommand(opts = {}) {
@@ -351,8 +326,7 @@ async function reportCredentials(opts) {
351
326
  return { path, source: "none" };
352
327
  }
353
328
  const out = { path, source: resolved.source };
354
- if (resolved.profile)
355
- out.profile = resolved.profile;
329
+ if (resolved.profile) out.profile = resolved.profile;
356
330
  if (resolved.source === "file") {
357
331
  const mode = await credentialsFileMode();
358
332
  if (mode !== null) {
@@ -420,20 +394,19 @@ function prettyDoctor(r) {
420
394
  }
421
395
  async function loginCommand(opts = {}) {
422
396
  const profile = opts.profile ?? "default";
423
- const apiKey = opts.apiKey ?? await prompts.password({
424
- message: "Paste your Garu API key (sk_live_... or sk_test_...)",
425
- mask: "*"
426
- }).catch(() => {
397
+ const apiKey = opts.apiKey ?? await import('@inquirer/prompts').then(
398
+ ({ password }) => password({
399
+ message: "Paste your Garu API key (sk_live_... or sk_test_...)",
400
+ mask: "*"
401
+ })
402
+ ).catch(() => {
427
403
  throw new CliError("user_cancelled", "Login cancelled.");
428
404
  });
429
405
  if (!apiKey || !/^sk_(live|test)_[A-Za-z0-9_]+$/.test(apiKey)) {
430
406
  throw new CliError("invalid_input", "API key must look like `sk_live_...` or `sk_test_...`.");
431
407
  }
432
- printStatus("Validating key with Garu...", opts);
433
- const garu = new node.Garu({
434
- apiKey,
435
- ...opts.baseUrl !== void 0 ? { baseUrl: opts.baseUrl } : {}
436
- });
408
+ printStatus("Checking connectivity to Garu...", opts);
409
+ const garu = new node.Garu({ apiKey, baseUrl: opts.baseUrl });
437
410
  await garu.meta.get();
438
411
  const file = await loadCredentials();
439
412
  const updated = upsertProfile(file, profile, { apiKey });
@@ -454,7 +427,12 @@ async function logoutCommand(opts = {}) {
454
427
  throw new CliError("not_found", `Profile '${opts.profile}' not found.`);
455
428
  }
456
429
  const { [opts.profile]: _removed, ...rest } = file.profiles;
457
- const nextActive = file.activeProfile === opts.profile ? Object.keys(rest)[0] ?? "default" : file.activeProfile;
430
+ if (Object.keys(rest).length === 0) {
431
+ await deleteCredentials();
432
+ printSuccess(`Profile '${opts.profile}' removed (credentials file deleted).`, opts);
433
+ return { cleared: opts.profile };
434
+ }
435
+ const nextActive = file.activeProfile === opts.profile ? Object.keys(rest)[0] : file.activeProfile;
458
436
  await saveCredentials({ ...file, activeProfile: nextActive, profiles: rest });
459
437
  printSuccess(`Profile '${opts.profile}' removed.`, opts);
460
438
  return { cleared: opts.profile };
@@ -463,27 +441,29 @@ async function logoutCommand(opts = {}) {
463
441
  // src/index.ts
464
442
  function buildCli() {
465
443
  const program = new commander.Command();
466
- program.name("garu").description("Command-line interface for the Garu payment gateway.").version(getVersion(), "-v, --version").addOption(new commander.Option("--api-key <key>", "Garu API key (overrides env and credentials file)")).addOption(new commander.Option("-p, --profile <name>", "credentials profile name")).addOption(new commander.Option("--json", "emit strict JSON on stdout (forced in pipes)")).addOption(new commander.Option("-q, --quiet", "suppress status output; only print results and errors")).showHelpAfterError();
444
+ program.name("garu").description("Command-line interface for the Garu payment gateway.").version(CLI_VERSION, "-v, --version").addOption(new commander.Option("--api-key <key>", "Garu API key (overrides env and credentials file)")).addOption(new commander.Option("-p, --profile <name>", "credentials profile name")).addOption(new commander.Option("--json", "emit strict JSON on stdout (forced in pipes)")).addOption(new commander.Option("-q, --quiet", "suppress status output; only print results and errors")).showHelpAfterError();
467
445
  program.command("login").description("Save a Garu API key to the credentials file").option("--api-key <key>", "pre-supply the key instead of prompting").option("-p, --profile <name>", "profile name to store under", "default").action(async (cmdOpts) => {
468
- const globals = getGlobals(program);
446
+ const base = toCommandOptions(program);
469
447
  await loginCommand({
470
- ...cmdOpts.apiKey !== void 0 ? { apiKey: cmdOpts.apiKey } : {},
448
+ apiKey: cmdOpts.apiKey,
471
449
  profile: cmdOpts.profile,
472
- ...globalsToOutput(globals)
473
- }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));
450
+ mode: base.mode,
451
+ quiet: base.quiet
452
+ }).catch((err) => printErrorAndExit(err, base));
474
453
  });
475
454
  program.command("logout").description("Remove saved credentials").option("-p, --profile <name>", "only remove this profile instead of the whole file").action(async (cmdOpts) => {
476
- const globals = getGlobals(program);
455
+ const base = toCommandOptions(program);
477
456
  await logoutCommand({
478
- ...cmdOpts.profile !== void 0 ? { profile: cmdOpts.profile } : {},
479
- ...globalsToOutput(globals)
480
- }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));
457
+ profile: cmdOpts.profile,
458
+ mode: base.mode,
459
+ quiet: base.quiet
460
+ }).catch((err) => printErrorAndExit(err, base));
481
461
  });
482
462
  const auth = program.command("auth").description("Manage credentials profiles");
483
463
  auth.command("switch <profile>").description("Set the active credentials profile").action(async (profile) => {
484
- const globals = getGlobals(program);
485
- await authSwitchCommand({ profile, ...globalsToOutput(globals) }).catch(
486
- (err) => printErrorAndExit(err, globalsToOutput(globals))
464
+ const base = toCommandOptions(program);
465
+ await authSwitchCommand({ profile, mode: base.mode, quiet: base.quiet }).catch(
466
+ (err) => printErrorAndExit(err, base)
487
467
  );
488
468
  });
489
469
  const charges = program.command("charges").description("Create, fetch, and refund charges");
@@ -491,76 +471,57 @@ function buildCli() {
491
471
  "--customer-document <document>",
492
472
  "CPF (11 digits) or CNPJ (14 digits), digits only"
493
473
  ).requiredOption("--customer-phone <phone>", "customer phone with area code, digits only").option("--card-number <number>", "credit-card number (required for credit_card)").option("--card-cvv <cvv>", "credit-card CVV").option("--card-expiration <yyyy-mm>", "credit-card expiration date (YYYY-MM)").option("--card-holder <name>", "credit-card holder name").option("--installments <n>", "number of installments (1-12)", (v) => parseInt(v, 10), 1).option("--additional-info <text>", "free-form metadata attached to the charge").option("--idempotency-key <key>", "idempotency key (auto-generated if omitted)").action(async (cmdOpts) => {
494
- const globals = getGlobals(program);
495
- const type = parsePaymentMethod(cmdOpts.type);
474
+ const base = toCommandOptions(program);
496
475
  await chargesCreateCommand({
497
- type,
476
+ ...base,
477
+ type: parsePaymentMethod(cmdOpts.type),
498
478
  productId: cmdOpts.productId,
499
479
  customerName: cmdOpts.customerName,
500
480
  customerEmail: cmdOpts.customerEmail,
501
481
  customerDocument: cmdOpts.customerDocument,
502
482
  customerPhone: cmdOpts.customerPhone,
503
- ...cmdOpts.cardNumber !== void 0 ? { cardNumber: cmdOpts.cardNumber } : {},
504
- ...cmdOpts.cardCvv !== void 0 ? { cardCvv: cmdOpts.cardCvv } : {},
505
- ...cmdOpts.cardExpiration !== void 0 ? { cardExpiration: cmdOpts.cardExpiration } : {},
506
- ...cmdOpts.cardHolder !== void 0 ? { cardHolder: cmdOpts.cardHolder } : {},
507
- ...cmdOpts.installments !== void 0 ? { installments: cmdOpts.installments } : {},
508
- ...cmdOpts.additionalInfo !== void 0 ? { additionalInfo: cmdOpts.additionalInfo } : {},
509
- ...cmdOpts.idempotencyKey !== void 0 ? { idempotencyKey: cmdOpts.idempotencyKey } : {},
510
- ...globalFlagsToCommandOptions(globals)
511
- }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));
483
+ cardNumber: cmdOpts.cardNumber,
484
+ cardCvv: cmdOpts.cardCvv,
485
+ cardExpiration: cmdOpts.cardExpiration,
486
+ cardHolder: cmdOpts.cardHolder,
487
+ installments: cmdOpts.installments,
488
+ additionalInfo: cmdOpts.additionalInfo,
489
+ idempotencyKey: cmdOpts.idempotencyKey
490
+ }).catch((err) => printErrorAndExit(err, base));
512
491
  });
513
492
  charges.command("get <id>").description("Fetch a single charge by ID").action(async (id) => {
514
- const globals = getGlobals(program);
515
- await chargesGetCommand({
516
- id: parseId(id),
517
- ...globalFlagsToCommandOptions(globals)
518
- }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));
493
+ const base = toCommandOptions(program);
494
+ await chargesGetCommand({ ...base, id: parseId(id) }).catch(
495
+ (err) => printErrorAndExit(err, base)
496
+ );
519
497
  });
520
498
  charges.command("refund <id>").description("Refund a charge (full or partial)").option("--amount <centavos>", "partial refund amount in centavos", (v) => parseInt(v, 10)).option("--reason <text>", "optional refund reason").option("--idempotency-key <key>", "idempotency key (auto-generated if omitted)").action(async (id, cmdOpts) => {
521
- const globals = getGlobals(program);
499
+ const base = toCommandOptions(program);
522
500
  await chargesRefundCommand({
501
+ ...base,
523
502
  id: parseId(id),
524
- ...cmdOpts.amount !== void 0 ? { amount: cmdOpts.amount } : {},
525
- ...cmdOpts.reason !== void 0 ? { reason: cmdOpts.reason } : {},
526
- ...cmdOpts.idempotencyKey !== void 0 ? { idempotencyKey: cmdOpts.idempotencyKey } : {},
527
- ...globalFlagsToCommandOptions(globals)
528
- }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));
503
+ amount: cmdOpts.amount,
504
+ reason: cmdOpts.reason,
505
+ idempotencyKey: cmdOpts.idempotencyKey
506
+ }).catch((err) => printErrorAndExit(err, base));
529
507
  });
530
508
  program.command("doctor").description("Environment diagnostic").action(async () => {
531
- const globals = getGlobals(program);
532
- await doctorCommand({
533
- ...globalFlagsToCommandOptions(globals)
534
- }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));
509
+ const base = toCommandOptions(program);
510
+ await doctorCommand(base).catch((err) => printErrorAndExit(err, base));
535
511
  });
536
512
  return program;
537
513
  }
538
- function getGlobals(program) {
539
- return program.opts();
540
- }
541
- function globalsToOutput(globals) {
514
+ function toCommandOptions(program) {
515
+ const g = program.opts();
542
516
  const out = {};
543
- if (globals.json)
544
- out.mode = "json";
545
- if (globals.quiet)
546
- out.quiet = true;
547
- return out;
548
- }
549
- function globalFlagsToCommandOptions(globals) {
550
- const out = {};
551
- if (globals.apiKey)
552
- out.apiKey = globals.apiKey;
553
- if (globals.profile)
554
- out.profile = globals.profile;
555
- if (globals.json)
556
- out.mode = "json";
557
- if (globals.quiet)
558
- out.quiet = true;
517
+ if (g.apiKey) out.apiKey = g.apiKey;
518
+ if (g.profile) out.profile = g.profile;
519
+ if (g.json) out.mode = "json";
520
+ if (g.quiet) out.quiet = true;
559
521
  return out;
560
522
  }
561
523
  function parsePaymentMethod(raw) {
562
- if (raw === "pix" || raw === "credit_card" || raw === "boleto")
563
- return raw;
524
+ if (raw === "pix" || raw === "credit_card" || raw === "boleto") return raw;
564
525
  throw new CliError(
565
526
  "invalid_input",
566
527
  `--type must be 'pix', 'credit_card', or 'boleto' (got '${raw}')`
@@ -573,19 +534,13 @@ function parseId(raw) {
573
534
  }
574
535
  return id;
575
536
  }
576
- function getVersion() {
577
- return "0.1.0";
578
- }
579
537
  async function main(argv = process.argv) {
580
538
  const program = buildCli();
581
539
  await program.parseAsync(argv);
582
540
  }
583
- var invokedDirectly = typeof process !== "undefined" && Array.isArray(process.argv) && process.argv[1] !== void 0 && /garu(-cli)?(\.(cjs|js|ts))?$/.test(process.argv[1] ?? "");
584
- if (invokedDirectly) {
585
- main().catch((err) => printErrorAndExit(err));
586
- }
541
+ main().catch((err) => printErrorAndExit(err));
587
542
 
588
543
  exports.buildCli = buildCli;
589
544
  exports.main = main;
590
- //# sourceMappingURL=out.js.map
545
+ //# sourceMappingURL=index.cjs.map
591
546
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/lib/credentials.ts","../src/lib/errors.ts","../src/lib/output.ts","../src/commands/auth-switch.ts","../src/lib/auth.ts","../src/lib/client.ts","../src/version.ts","../src/commands/charges.ts","../src/commands/doctor.ts","../src/commands/login.ts","../src/commands/logout.ts"],"names":["homedir","join","Garu"],"mappings":"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","sourcesContent":["import { Command, Option } from 'commander';\n\nimport { authSwitchCommand } from './commands/auth-switch.js';\nimport {\n chargesCreateCommand,\n chargesGetCommand,\n chargesRefundCommand\n} from './commands/charges.js';\nimport { doctorCommand } from './commands/doctor.js';\nimport { loginCommand } from './commands/login.js';\nimport { logoutCommand } from './commands/logout.js';\nimport type { PaymentMethod } from '@garuhq/node';\nimport { CliError } from './lib/errors.js';\nimport { printErrorAndExit, type OutputMode } from './lib/output.js';\n\ninterface GlobalFlags {\n apiKey?: string;\n profile?: string;\n json?: boolean;\n quiet?: boolean;\n}\n\n/** Build the top-level command tree. Exposed so tests can exercise the router. */\nexport function buildCli(): Command {\n const program = new Command();\n\n program\n .name('garu')\n .description('Command-line interface for the Garu payment gateway.')\n .version(getVersion(), '-v, --version')\n .addOption(new Option('--api-key <key>', 'Garu API key (overrides env and credentials file)'))\n .addOption(new Option('-p, --profile <name>', 'credentials profile name'))\n .addOption(new Option('--json', 'emit strict JSON on stdout (forced in pipes)'))\n .addOption(new Option('-q, --quiet', 'suppress status output; only print results and errors'))\n .showHelpAfterError();\n\n // login\n program\n .command('login')\n .description('Save a Garu API key to the credentials file')\n .option('--api-key <key>', 'pre-supply the key instead of prompting')\n .option('-p, --profile <name>', 'profile name to store under', 'default')\n .action(async (cmdOpts: { apiKey?: string; profile: string }) => {\n const globals = getGlobals(program);\n await loginCommand({\n ...(cmdOpts.apiKey !== undefined ? { apiKey: cmdOpts.apiKey } : {}),\n profile: cmdOpts.profile,\n ...globalsToOutput(globals)\n }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));\n });\n\n // logout\n program\n .command('logout')\n .description('Remove saved credentials')\n .option('-p, --profile <name>', 'only remove this profile instead of the whole file')\n .action(async (cmdOpts: { profile?: string }) => {\n const globals = getGlobals(program);\n await logoutCommand({\n ...(cmdOpts.profile !== undefined ? { profile: cmdOpts.profile } : {}),\n ...globalsToOutput(globals)\n }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));\n });\n\n // auth switch\n const auth = program.command('auth').description('Manage credentials profiles');\n auth\n .command('switch <profile>')\n .description('Set the active credentials profile')\n .action(async (profile: string) => {\n const globals = getGlobals(program);\n await authSwitchCommand({ profile, ...globalsToOutput(globals) }).catch((err) =>\n printErrorAndExit(err, globalsToOutput(globals))\n );\n });\n\n // charges\n const charges = program.command('charges').description('Create, fetch, and refund charges');\n\n charges\n .command('create')\n .description('Create a charge (PIX, credit card, or boleto)')\n .requiredOption('--type <type>', 'payment method: pix | credit_card | boleto')\n .requiredOption('--product-id <uuid>', 'product UUID')\n .requiredOption('--customer-name <name>', 'customer full name')\n .requiredOption('--customer-email <email>', 'customer email')\n .requiredOption(\n '--customer-document <document>',\n 'CPF (11 digits) or CNPJ (14 digits), digits only'\n )\n .requiredOption('--customer-phone <phone>', 'customer phone with area code, digits only')\n .option('--card-number <number>', 'credit-card number (required for credit_card)')\n .option('--card-cvv <cvv>', 'credit-card CVV')\n .option('--card-expiration <yyyy-mm>', 'credit-card expiration date (YYYY-MM)')\n .option('--card-holder <name>', 'credit-card holder name')\n .option('--installments <n>', 'number of installments (1-12)', (v) => parseInt(v, 10), 1)\n .option('--additional-info <text>', 'free-form metadata attached to the charge')\n .option('--idempotency-key <key>', 'idempotency key (auto-generated if omitted)')\n .action(async (cmdOpts) => {\n const globals = getGlobals(program);\n const type = parsePaymentMethod(cmdOpts.type);\n await chargesCreateCommand({\n type,\n productId: cmdOpts.productId,\n customerName: cmdOpts.customerName,\n customerEmail: cmdOpts.customerEmail,\n customerDocument: cmdOpts.customerDocument,\n customerPhone: cmdOpts.customerPhone,\n ...(cmdOpts.cardNumber !== undefined ? { cardNumber: cmdOpts.cardNumber } : {}),\n ...(cmdOpts.cardCvv !== undefined ? { cardCvv: cmdOpts.cardCvv } : {}),\n ...(cmdOpts.cardExpiration !== undefined ? { cardExpiration: cmdOpts.cardExpiration } : {}),\n ...(cmdOpts.cardHolder !== undefined ? { cardHolder: cmdOpts.cardHolder } : {}),\n ...(cmdOpts.installments !== undefined ? { installments: cmdOpts.installments } : {}),\n ...(cmdOpts.additionalInfo !== undefined ? { additionalInfo: cmdOpts.additionalInfo } : {}),\n ...(cmdOpts.idempotencyKey !== undefined ? { idempotencyKey: cmdOpts.idempotencyKey } : {}),\n ...globalFlagsToCommandOptions(globals)\n }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));\n });\n\n charges\n .command('get <id>')\n .description('Fetch a single charge by ID')\n .action(async (id: string) => {\n const globals = getGlobals(program);\n await chargesGetCommand({\n id: parseId(id),\n ...globalFlagsToCommandOptions(globals)\n }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));\n });\n\n charges\n .command('refund <id>')\n .description('Refund a charge (full or partial)')\n .option('--amount <centavos>', 'partial refund amount in centavos', (v) => parseInt(v, 10))\n .option('--reason <text>', 'optional refund reason')\n .option('--idempotency-key <key>', 'idempotency key (auto-generated if omitted)')\n .action(async (id: string, cmdOpts) => {\n const globals = getGlobals(program);\n await chargesRefundCommand({\n id: parseId(id),\n ...(cmdOpts.amount !== undefined ? { amount: cmdOpts.amount } : {}),\n ...(cmdOpts.reason !== undefined ? { reason: cmdOpts.reason } : {}),\n ...(cmdOpts.idempotencyKey !== undefined ? { idempotencyKey: cmdOpts.idempotencyKey } : {}),\n ...globalFlagsToCommandOptions(globals)\n }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));\n });\n\n // doctor\n program\n .command('doctor')\n .description('Environment diagnostic')\n .action(async () => {\n const globals = getGlobals(program);\n await doctorCommand({\n ...globalFlagsToCommandOptions(globals)\n }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));\n });\n\n return program;\n}\n\nfunction getGlobals(program: Command): GlobalFlags {\n return program.opts<GlobalFlags>();\n}\n\nfunction globalsToOutput(globals: GlobalFlags): { mode?: OutputMode; quiet?: boolean } {\n const out: { mode?: OutputMode; quiet?: boolean } = {};\n if (globals.json) out.mode = 'json';\n if (globals.quiet) out.quiet = true;\n return out;\n}\n\nfunction globalFlagsToCommandOptions(globals: GlobalFlags): {\n apiKey?: string;\n profile?: string;\n mode?: OutputMode;\n quiet?: boolean;\n} {\n const out: { apiKey?: string; profile?: string; mode?: OutputMode; quiet?: boolean } = {};\n if (globals.apiKey) out.apiKey = globals.apiKey;\n if (globals.profile) out.profile = globals.profile;\n if (globals.json) out.mode = 'json';\n if (globals.quiet) out.quiet = true;\n return out;\n}\n\nfunction parsePaymentMethod(raw: string): PaymentMethod {\n if (raw === 'pix' || raw === 'credit_card' || raw === 'boleto') return raw;\n throw new CliError(\n 'invalid_input',\n `--type must be 'pix', 'credit_card', or 'boleto' (got '${raw}')`\n );\n}\n\nfunction parseId(raw: string): number {\n const id = Number.parseInt(raw, 10);\n if (!Number.isFinite(id) || id <= 0) {\n throw new CliError('invalid_input', `Charge ID must be a positive integer (got '${raw}')`);\n }\n return id;\n}\n\nfunction getVersion(): string {\n // Statically imported so `bun build --compile` can inline it.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return '0.1.0';\n}\n\n/** Main entry invoked by `bin/garu.js` and `src/index.ts` when run directly. */\nexport async function main(argv: string[] = process.argv): Promise<void> {\n const program = buildCli();\n await program.parseAsync(argv);\n}\n\n// Auto-run when invoked directly (not imported).\nconst invokedDirectly =\n typeof process !== 'undefined' &&\n Array.isArray(process.argv) &&\n process.argv[1] !== undefined &&\n /garu(-cli)?(\\.(cjs|js|ts))?$/.test(process.argv[1] ?? '');\n\nif (invokedDirectly) {\n main().catch((err) => printErrorAndExit(err));\n}\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { mkdir, readFile, writeFile, rm, stat } from 'node:fs/promises';\n\nimport { CliError } from './errors.js';\n\nexport interface CredentialProfile {\n apiKey: string;\n /** Optional seller ID to render in `garu doctor` output. */\n sellerId?: number;\n /** Human-readable label for multi-profile setups. */\n label?: string;\n}\n\nexport interface CredentialsFile {\n version: 1;\n activeProfile: string;\n profiles: Record<string, CredentialProfile>;\n}\n\nconst DEFAULT_FILE: CredentialsFile = {\n version: 1,\n activeProfile: 'default',\n profiles: {}\n};\n\n/**\n * Resolve the credentials file path.\n *\n * Honors `$XDG_CONFIG_HOME` per the XDG base-dir spec, falling back to\n * `~/.config/garu/credentials.json`. Override with `$GARU_CREDENTIALS_PATH`\n * (primarily for tests).\n */\nexport function credentialsPath(env: NodeJS.ProcessEnv = process.env): string {\n if (env.GARU_CREDENTIALS_PATH) return env.GARU_CREDENTIALS_PATH;\n const base = env.XDG_CONFIG_HOME || join(homedir(), '.config');\n return join(base, 'garu', 'credentials.json');\n}\n\n/** Read the credentials file. Returns the default (empty) file if it doesn't exist. */\nexport async function loadCredentials(\n env: NodeJS.ProcessEnv = process.env\n): Promise<CredentialsFile> {\n const path = credentialsPath(env);\n try {\n const raw = await readFile(path, 'utf8');\n const parsed = JSON.parse(raw);\n return normalize(parsed);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { ...DEFAULT_FILE };\n }\n throw new CliError(\n 'invalid_input',\n `Failed to read credentials at ${path}: ${(err as Error).message}`\n );\n }\n}\n\n/**\n * Write the credentials file atomically with tight file-mode (0600) and\n * directory-mode (0700).\n */\nexport async function saveCredentials(\n file: CredentialsFile,\n env: NodeJS.ProcessEnv = process.env\n): Promise<void> {\n const path = credentialsPath(env);\n const dir = path.slice(0, path.lastIndexOf('/'));\n await mkdir(dir, { recursive: true, mode: 0o700 });\n await writeFile(path, JSON.stringify(file, null, 2) + '\\n', { mode: 0o600 });\n}\n\n/** Delete the credentials file. No-op if it doesn't exist. */\nexport async function deleteCredentials(env: NodeJS.ProcessEnv = process.env): Promise<void> {\n const path = credentialsPath(env);\n try {\n await rm(path);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n}\n\n/** Add or replace a profile and set it active. */\nexport function upsertProfile(\n file: CredentialsFile,\n name: string,\n profile: CredentialProfile\n): CredentialsFile {\n return {\n ...file,\n activeProfile: name,\n profiles: { ...file.profiles, [name]: profile }\n };\n}\n\n/** Check whether the credentials file has the expected 0600 mode. Returns null on any error. */\nexport async function credentialsFileMode(\n env: NodeJS.ProcessEnv = process.env\n): Promise<number | null> {\n try {\n const s = await stat(credentialsPath(env));\n return s.mode & 0o777;\n } catch {\n return null;\n }\n}\n\nfunction normalize(raw: unknown): CredentialsFile {\n if (!raw || typeof raw !== 'object') return { ...DEFAULT_FILE };\n const obj = raw as Partial<CredentialsFile>;\n return {\n version: 1,\n activeProfile: obj.activeProfile ?? 'default',\n profiles: obj.profiles && typeof obj.profiles === 'object' ? obj.profiles : {}\n };\n}\n","/**\n * CLI error model. All user-visible failures flow through these types so that\n * the output layer can render them consistently — pretty with a red prefix in\n * TTY mode, strict `{\"error\":{\"code\",\"message\"}}` on stdout + exit 1 in JSON mode.\n */\n\nexport type CliErrorCode =\n | 'auth_error'\n | 'not_found'\n | 'validation_error'\n | 'rate_limited'\n | 'server_error'\n | 'connection_error'\n | 'signature_verification_failed'\n | 'user_cancelled'\n | 'invalid_input'\n | 'unknown_error';\n\nexport class CliError extends Error {\n public readonly code: CliErrorCode;\n public readonly exitCode: number;\n\n constructor(code: CliErrorCode, message: string, exitCode = 1) {\n super(message);\n this.name = 'CliError';\n this.code = code;\n this.exitCode = exitCode;\n }\n}\n\n/** Wrap an unknown thrown value as a {@link CliError}. */\nexport function toCliError(err: unknown): CliError {\n if (err instanceof CliError) return err;\n // Duck-type the SDK's GaruError — avoids importing the SDK class hierarchy\n // just for instanceof checks, and keeps this module dependency-free.\n if (err && typeof err === 'object' && 'name' in err && 'code' in err) {\n const e = err as { name: string; code: string; message?: string };\n if (typeof e.name === 'string' && e.name.startsWith('Garu')) {\n return new CliError(mapSdkCodeToCliCode(e.code), e.message ?? 'Request failed', 1);\n }\n }\n if (err instanceof Error) return new CliError('unknown_error', err.message);\n return new CliError('unknown_error', String(err));\n}\n\nfunction mapSdkCodeToCliCode(sdkCode: string): CliErrorCode {\n switch (sdkCode) {\n case 'authentication_error':\n case 'permission_error':\n return 'auth_error';\n case 'not_found':\n return 'not_found';\n case 'validation_error':\n return 'validation_error';\n case 'rate_limited':\n return 'rate_limited';\n case 'server_error':\n return 'server_error';\n case 'connection_error':\n return 'connection_error';\n case 'signature_verification_failed':\n return 'signature_verification_failed';\n default:\n return 'unknown_error';\n }\n}\n","import pc from 'picocolors';\n\nimport { CliError, toCliError } from './errors.js';\n\nexport type OutputMode = 'pretty' | 'json';\n\nexport interface OutputOptions {\n /** Force a mode. If omitted, auto-detect from TTY. */\n mode?: OutputMode;\n /** Passed by `--quiet`; suppresses everything except errors and the final value. */\n quiet?: boolean;\n}\n\n/**\n * Resolve the output mode. Rules:\n * - Explicit `--json` (or `opts.mode === 'json'`) wins.\n * - Non-TTY stdout (pipe, CI) → `json`.\n * - Everything else → `pretty`.\n */\nexport function resolveMode(\n opts: OutputOptions = {},\n stdout: NodeJS.WriteStream = process.stdout\n): OutputMode {\n if (opts.mode) return opts.mode;\n return stdout.isTTY ? 'pretty' : 'json';\n}\n\n/**\n * Print a successful command result. In JSON mode the full object is written\n * to stdout with a trailing newline. In pretty mode the caller's `prettyPrint`\n * fallback (if provided) is used; otherwise the JSON is indented.\n */\nexport function printResult<T>(\n value: T,\n opts: OutputOptions & { prettyPrint?: (value: T) => string } = {}\n): void {\n const mode = resolveMode(opts);\n if (mode === 'json') {\n process.stdout.write(`${JSON.stringify(value)}\\n`);\n return;\n }\n if (opts.prettyPrint) {\n process.stdout.write(`${opts.prettyPrint(value)}\\n`);\n return;\n }\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\n/** Print a short status line — suppressed in JSON mode and when `--quiet`. */\nexport function printStatus(message: string, opts: OutputOptions = {}): void {\n if (opts.quiet) return;\n if (resolveMode(opts) === 'json') return;\n process.stderr.write(`${pc.dim('→')} ${message}\\n`);\n}\n\n/** Print a success line — suppressed in JSON mode and when `--quiet`. */\nexport function printSuccess(message: string, opts: OutputOptions = {}): void {\n if (opts.quiet) return;\n if (resolveMode(opts) === 'json') return;\n process.stderr.write(`${pc.green('✓')} ${message}\\n`);\n}\n\n/**\n * Print an error and exit with the appropriate code. Always uses the\n * CLI-standard shape `{\"error\":{\"code\",\"message\"}}` on stdout in JSON mode,\n * or a red `Error:` line on stderr in pretty mode.\n */\nexport function printErrorAndExit(err: unknown, opts: OutputOptions = {}): never {\n const cliErr: CliError = toCliError(err);\n const payload = { error: { code: cliErr.code, message: cliErr.message } };\n\n if (resolveMode(opts) === 'json') {\n process.stdout.write(`${JSON.stringify(payload)}\\n`);\n } else {\n process.stderr.write(`${pc.red('Error:')} ${cliErr.message}\\n`);\n if (cliErr.code !== 'unknown_error') {\n process.stderr.write(`${pc.dim(` code: ${cliErr.code}`)}\\n`);\n }\n }\n process.exit(cliErr.exitCode);\n}\n","import { loadCredentials, saveCredentials } from '../lib/credentials.js';\nimport { CliError } from '../lib/errors.js';\nimport { printSuccess, type OutputOptions } from '../lib/output.js';\n\nexport interface AuthSwitchOptions extends OutputOptions {\n profile: string;\n}\n\nexport async function authSwitchCommand(\n opts: AuthSwitchOptions\n): Promise<{ activeProfile: string }> {\n const file = await loadCredentials();\n if (!file.profiles[opts.profile]) {\n const available = Object.keys(file.profiles).join(', ') || '(none)';\n throw new CliError('not_found', `Profile '${opts.profile}' not found. Available: ${available}`);\n }\n\n await saveCredentials({ ...file, activeProfile: opts.profile });\n printSuccess(`Active profile set to '${opts.profile}'.`, opts);\n return { activeProfile: opts.profile };\n}\n","import { loadCredentials, type CredentialProfile } from './credentials.js';\nimport { CliError } from './errors.js';\n\nexport interface ResolvedAuth {\n apiKey: string;\n /** Where the key came from, for `doctor` and debug output. */\n source: 'flag' | 'env' | 'file';\n /** Profile name if resolved from file; undefined otherwise. */\n profile?: string;\n fileProfile?: CredentialProfile;\n}\n\nexport interface ResolveAuthOptions {\n /** `--api-key` flag value. Highest precedence. */\n apiKey?: string;\n /** `--profile` flag value. When set, reads that profile instead of the active one. */\n profile?: string;\n env?: NodeJS.ProcessEnv;\n}\n\n/**\n * Resolve the API key following SPEC §7 auth priority:\n *\n * 1. `--api-key` flag\n * 2. `GARU_API_KEY` environment variable\n * 3. credentials file active profile (or profile selected with `--profile`)\n *\n * Throws {@link CliError} with code `auth_error` if no key is found. Never logs.\n */\nexport async function resolveAuth(opts: ResolveAuthOptions = {}): Promise<ResolvedAuth> {\n const env = opts.env ?? process.env;\n\n if (opts.apiKey) {\n return { apiKey: opts.apiKey, source: 'flag' };\n }\n\n if (env.GARU_API_KEY) {\n return { apiKey: env.GARU_API_KEY, source: 'env' };\n }\n\n const file = await loadCredentials(env);\n const profileName = opts.profile ?? file.activeProfile;\n const profile = file.profiles[profileName];\n if (profile && profile.apiKey) {\n return {\n apiKey: profile.apiKey,\n source: 'file',\n profile: profileName,\n fileProfile: profile\n };\n }\n\n throw new CliError('auth_error', 'No API key found. Run `garu login` or set GARU_API_KEY.');\n}\n\n/**\n * Same as {@link resolveAuth} but returns `null` instead of throwing when no\n * credentials are available. Used by `garu doctor`.\n */\nexport async function resolveAuthOptional(\n opts: ResolveAuthOptions = {}\n): Promise<ResolvedAuth | null> {\n try {\n return await resolveAuth(opts);\n } catch (err) {\n if (err instanceof CliError && err.code === 'auth_error') return null;\n throw err;\n }\n}\n","import { Garu } from '@garuhq/node';\n\nimport type { ResolvedAuth } from './auth.js';\nimport { CLI_VERSION } from '../version.js';\n\nexport interface GaruClientOptions {\n auth: ResolvedAuth;\n baseUrl?: string;\n}\n\n/**\n * Construct a `Garu` SDK instance from resolved auth.\n *\n * The CLI dogfoods `@garuhq/node` — every HTTP call flows through the SDK we\n * shipped in Chunk 3. This keeps retries, idempotency, and error mapping\n * consistent between the CLI, MCP server, and any user-written integration.\n */\nexport function createGaruClient(opts: GaruClientOptions): Garu {\n return new Garu({\n apiKey: opts.auth.apiKey,\n baseUrl: opts.baseUrl\n });\n}\n\n/** User-Agent used for CLI requests. Surfaces the CLI version in backend logs. */\nexport function cliUserAgent(): string {\n return `garu-cli/${CLI_VERSION}`;\n}\n","/**\n * CLI version.\n *\n * Kept as a plain string so `bun build --compile` can inline it at compile time\n * and the resulting binary has no runtime dependency on `package.json`.\n * The release workflow bumps this in lockstep with `package.json` on `v*` tags.\n */\nexport const CLI_VERSION = '0.1.0';\n","import type { Charge, Customer, Garu, PaymentMethod, RefundChargeParams } from '@garuhq/node';\n\nimport { resolveAuth } from '../lib/auth.js';\nimport { createGaruClient } from '../lib/client.js';\nimport { CliError } from '../lib/errors.js';\nimport { printResult, type OutputOptions } from '../lib/output.js';\n\nexport interface ChargesGlobalOptions extends OutputOptions {\n apiKey?: string;\n profile?: string;\n baseUrl?: string;\n /** Injectable for tests — bypass auth resolution + SDK construction. */\n garu?: Garu;\n}\n\nexport interface ChargesCreateOptions extends ChargesGlobalOptions {\n type: PaymentMethod;\n productId: string;\n customerName: string;\n customerEmail: string;\n customerDocument: string;\n customerPhone: string;\n cardNumber?: string;\n cardCvv?: string;\n cardExpiration?: string;\n cardHolder?: string;\n installments?: number;\n idempotencyKey?: string;\n additionalInfo?: string;\n}\n\nexport interface ChargesByIdOptions extends ChargesGlobalOptions {\n id: number;\n}\n\nexport interface ChargesRefundOptions extends ChargesByIdOptions {\n /** Amount in centavos. Omit for full refund. */\n amount?: number;\n reason?: string;\n idempotencyKey?: string;\n}\n\nasync function getClient(opts: ChargesGlobalOptions): Promise<Garu> {\n if (opts.garu) return opts.garu;\n const auth = await resolveAuth({\n ...(opts.apiKey !== undefined ? { apiKey: opts.apiKey } : {}),\n ...(opts.profile !== undefined ? { profile: opts.profile } : {})\n });\n return createGaruClient({\n auth,\n ...(opts.baseUrl !== undefined ? { baseUrl: opts.baseUrl } : {})\n });\n}\n\nexport async function chargesCreateCommand(opts: ChargesCreateOptions): Promise<Charge> {\n validateCreate(opts);\n const garu = await getClient(opts);\n\n const customer: Customer = {\n name: opts.customerName,\n email: opts.customerEmail,\n document: opts.customerDocument,\n phone: opts.customerPhone\n };\n\n const charge = await garu.charges.create({\n productId: opts.productId,\n paymentMethod: opts.type,\n customer,\n ...(opts.additionalInfo !== undefined ? { additionalInfo: opts.additionalInfo } : {}),\n ...(opts.idempotencyKey !== undefined ? { idempotencyKey: opts.idempotencyKey } : {}),\n ...(opts.type === 'credit_card' && opts.cardNumber\n ? {\n cardInfo: {\n cardNumber: opts.cardNumber,\n cvv: opts.cardCvv!,\n expirationDate: opts.cardExpiration!,\n holderName: opts.cardHolder!,\n installments: opts.installments ?? 1\n }\n }\n : {})\n });\n\n printResult(charge, { ...opts, prettyPrint: prettyCharge });\n return charge;\n}\n\nexport async function chargesGetCommand(opts: ChargesByIdOptions): Promise<Charge> {\n const garu = await getClient(opts);\n const charge = await garu.charges.get(opts.id);\n printResult(charge, { ...opts, prettyPrint: prettyCharge });\n return charge;\n}\n\nexport async function chargesRefundCommand(opts: ChargesRefundOptions): Promise<Charge> {\n const garu = await getClient(opts);\n const params: RefundChargeParams = {};\n if (opts.amount !== undefined) params.amount = opts.amount;\n if (opts.reason !== undefined) params.reason = opts.reason;\n if (opts.idempotencyKey !== undefined) params.idempotencyKey = opts.idempotencyKey;\n const charge = await garu.charges.refund(opts.id, params);\n printResult(charge, { ...opts, prettyPrint: prettyCharge });\n return charge;\n}\n\nfunction validateCreate(opts: ChargesCreateOptions): void {\n if (opts.type === 'credit_card') {\n const missing: string[] = [];\n if (!opts.cardNumber) missing.push('--card-number');\n if (!opts.cardCvv) missing.push('--card-cvv');\n if (!opts.cardExpiration) missing.push('--card-expiration');\n if (!opts.cardHolder) missing.push('--card-holder');\n if (missing.length) {\n throw new CliError('invalid_input', `Credit-card charges require: ${missing.join(', ')}`);\n }\n }\n}\n\nfunction prettyCharge(charge: Charge): string {\n const lines = [\n `Charge ${charge.id}`,\n ` status: ${charge.status}`,\n ` amount: ${charge.amount}`,\n ` method: ${charge.paymentMethodId}`,\n ` date: ${charge.date}`\n ];\n if (charge.deadline) lines.push(` deadline: ${charge.deadline}`);\n return lines.join('\\n');\n}\n","import { existsSync } from 'node:fs';\nimport { homedir, platform } from 'node:os';\nimport { join } from 'node:path';\n\nimport { Garu } from '@garuhq/node';\n\nimport { resolveAuthOptional } from '../lib/auth.js';\nimport { credentialsFileMode, credentialsPath } from '../lib/credentials.js';\nimport { printResult, type OutputOptions } from '../lib/output.js';\nimport { CLI_VERSION } from '../version.js';\n\nexport interface DoctorReport {\n cli: { version: string };\n api: { reachable: boolean; url: string; version?: string; error?: string };\n credentials: {\n path: string;\n source: 'flag' | 'env' | 'file' | 'none';\n profile?: string;\n fileMode?: string;\n warning?: string;\n };\n agents: {\n claudeCode: boolean;\n cursor: boolean;\n codex: boolean;\n windsurf: boolean;\n claudeDesktop: boolean;\n vscodeMcpInCwd: boolean;\n };\n}\n\nexport interface DoctorOptions extends OutputOptions {\n apiKey?: string;\n profile?: string;\n baseUrl?: string;\n /** Injectable for tests — bypass the real HTTP call. */\n garu?: Garu;\n /** Injectable HOME, for tests. */\n home?: string;\n /** Injectable cwd, for tests. */\n cwd?: string;\n /** Injectable platform, for tests. */\n platform?: NodeJS.Platform;\n}\n\n/**\n * Run a full environment diagnostic.\n *\n * Never throws on expected failures — bad auth, unreachable API, missing\n * credentials all become structured report fields. Only genuinely unexpected\n * errors (programming bugs) bubble up.\n */\nexport async function doctorCommand(opts: DoctorOptions = {}): Promise<DoctorReport> {\n const home = opts.home ?? homedir();\n const cwd = opts.cwd ?? process.cwd();\n const plat = opts.platform ?? platform();\n\n const credentials = await reportCredentials(opts);\n const api = await reportApi(opts);\n const agents = detectAgents(home, cwd, plat);\n\n const report: DoctorReport = {\n cli: { version: CLI_VERSION },\n api,\n credentials,\n agents\n };\n\n printResult(report, { ...opts, prettyPrint: prettyDoctor });\n return report;\n}\n\nasync function reportCredentials(opts: DoctorOptions): Promise<DoctorReport['credentials']> {\n const path = credentialsPath();\n const resolved = await resolveAuthOptional({\n ...(opts.apiKey !== undefined ? { apiKey: opts.apiKey } : {}),\n ...(opts.profile !== undefined ? { profile: opts.profile } : {})\n });\n\n if (!resolved) {\n return { path, source: 'none' };\n }\n\n const out: DoctorReport['credentials'] = { path, source: resolved.source };\n if (resolved.profile) out.profile = resolved.profile;\n\n if (resolved.source === 'file') {\n const mode = await credentialsFileMode();\n if (mode !== null) {\n out.fileMode = `0${mode.toString(8)}`;\n if (mode !== 0o600) {\n out.warning = `credentials file mode is 0${mode.toString(8)}; expected 0600`;\n }\n }\n }\n\n return out;\n}\n\nasync function reportApi(opts: DoctorOptions): Promise<DoctorReport['api']> {\n const url = opts.baseUrl ?? 'https://garu.com.br';\n const garu =\n opts.garu ??\n new Garu({\n ...(opts.baseUrl !== undefined ? { baseUrl: opts.baseUrl } : {})\n });\n\n try {\n const meta = await garu.meta.get();\n return { reachable: true, url, version: meta.version };\n } catch (err) {\n return {\n reachable: false,\n url,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n}\n\nfunction detectAgents(home: string, cwd: string, plat: NodeJS.Platform): DoctorReport['agents'] {\n return {\n claudeCode: existsSync(join(home, '.claude')),\n cursor: existsSync(join(home, '.cursor')),\n codex: existsSync(join(home, '.codex')),\n windsurf: existsSync(join(home, '.windsurf')),\n claudeDesktop: existsSync(claudeDesktopConfigPath(home, plat)),\n vscodeMcpInCwd: existsSync(join(cwd, '.vscode', 'mcp.json'))\n };\n}\n\nfunction claudeDesktopConfigPath(home: string, plat: NodeJS.Platform): string {\n if (plat === 'darwin') {\n return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');\n }\n if (plat === 'win32') {\n return join(home, 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json');\n }\n return join(home, '.config', 'Claude', 'claude_desktop_config.json');\n}\n\nfunction prettyDoctor(r: DoctorReport): string {\n const check = (ok: boolean) => (ok ? 'yes' : 'no ');\n const lines = [\n `CLI: garu ${r.cli.version}`,\n `API: ${r.api.reachable ? `reachable (${r.api.url}, backend ${r.api.version ?? '?'})` : `unreachable (${r.api.url})`}`,\n r.api.error ? ` ${r.api.error}` : undefined,\n `Credentials: source=${r.credentials.source}${r.credentials.profile ? ` profile=${r.credentials.profile}` : ''}${r.credentials.fileMode ? ` mode=${r.credentials.fileMode}` : ''}`,\n r.credentials.warning ? ` ⚠ ${r.credentials.warning}` : undefined,\n '',\n 'Detected agents:',\n ` Claude Code: ${check(r.agents.claudeCode)}`,\n ` Cursor: ${check(r.agents.cursor)}`,\n ` Codex: ${check(r.agents.codex)}`,\n ` Windsurf: ${check(r.agents.windsurf)}`,\n ` Claude Desktop: ${check(r.agents.claudeDesktop)}`,\n ` VS Code MCP: ${check(r.agents.vscodeMcpInCwd)} (.vscode/mcp.json in cwd)`\n ].filter((l): l is string => l !== undefined);\n return lines.join('\\n');\n}\n","import { password as promptPassword } from '@inquirer/prompts';\n\nimport { Garu } from '@garuhq/node';\n\nimport { loadCredentials, saveCredentials, upsertProfile } from '../lib/credentials.js';\nimport { CliError } from '../lib/errors.js';\nimport { printStatus, printSuccess, type OutputOptions } from '../lib/output.js';\n\nexport interface LoginOptions extends OutputOptions {\n /** Profile name to create/update. Default: `default`. */\n profile?: string;\n /** Pre-supplied API key (for scripting). When set, no interactive prompt. */\n apiKey?: string;\n /** Override base URL (tests). */\n baseUrl?: string;\n}\n\nexport async function loginCommand(opts: LoginOptions = {}): Promise<{ profile: string }> {\n const profile = opts.profile ?? 'default';\n\n const apiKey =\n opts.apiKey ??\n (await promptPassword({\n message: 'Paste your Garu API key (sk_live_... or sk_test_...)',\n mask: '*'\n }).catch(() => {\n throw new CliError('user_cancelled', 'Login cancelled.');\n }));\n\n if (!apiKey || !/^sk_(live|test)_[A-Za-z0-9_]+$/.test(apiKey)) {\n throw new CliError('invalid_input', 'API key must look like `sk_live_...` or `sk_test_...`.');\n }\n\n printStatus('Validating key with Garu...', opts);\n const garu = new Garu({\n apiKey,\n ...(opts.baseUrl !== undefined ? { baseUrl: opts.baseUrl } : {})\n });\n\n // Hit an unauthenticated endpoint first to confirm connectivity, then use\n // the authenticated path to prove the key works. `meta.get` tests reachability;\n // we don't yet have a light authed endpoint to verify the key, so the key is\n // stored after basic format + reachability checks. A real auth probe will\n // land once the backend exposes `GET /api/v1/me`.\n await garu.meta.get();\n\n const file = await loadCredentials();\n const updated = upsertProfile(file, profile, { apiKey });\n await saveCredentials(updated);\n\n printSuccess(`Saved profile '${profile}' to ~/.config/garu/credentials.json`, opts);\n return { profile };\n}\n","import { deleteCredentials, loadCredentials, saveCredentials } from '../lib/credentials.js';\nimport { CliError } from '../lib/errors.js';\nimport { printSuccess, type OutputOptions } from '../lib/output.js';\n\nexport interface LogoutOptions extends OutputOptions {\n /**\n * Profile to remove. If omitted, the entire credentials file is deleted.\n */\n profile?: string;\n}\n\nexport async function logoutCommand(opts: LogoutOptions = {}): Promise<{ cleared: string }> {\n if (!opts.profile) {\n await deleteCredentials();\n printSuccess('All saved credentials deleted.', opts);\n return { cleared: 'all' };\n }\n\n const file = await loadCredentials();\n if (!file.profiles[opts.profile]) {\n throw new CliError('not_found', `Profile '${opts.profile}' not found.`);\n }\n\n const { [opts.profile]: _removed, ...rest } = file.profiles;\n void _removed;\n\n const nextActive =\n file.activeProfile === opts.profile ? (Object.keys(rest)[0] ?? 'default') : file.activeProfile;\n\n await saveCredentials({ ...file, activeProfile: nextActive, profiles: rest });\n printSuccess(`Profile '${opts.profile}' removed.`, opts);\n return { cleared: opts.profile };\n}\n"]}
1
+ {"version":3,"sources":["../src/version.ts","../src/lib/errors.ts","../src/lib/credentials.ts","../src/lib/output.ts","../src/commands/auth-switch.ts","../src/lib/auth.ts","../src/lib/client.ts","../src/commands/charges.ts","../src/commands/doctor.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/index.ts"],"names":["GaruError","join","homedir","readFile","path","mkdir","dirname","writeFile","rm","stat","pc","Garu","platform","existsSync","Command","Option"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * CLI version.\n *\n * Kept as a plain string so `bun build --compile` can inline it at compile time\n * and the resulting binary has no runtime dependency on `package.json`.\n * The release workflow bumps this in lockstep with `package.json` on `v*` tags.\n */\nexport const CLI_VERSION = '0.1.2';\n","/**\n * CLI error model. All user-visible failures flow through these types so that\n * the output layer can render them consistently — pretty with a red prefix in\n * TTY mode, strict `{\"error\":{\"code\",\"message\"}}` on stdout + exit 1 in JSON mode.\n */\n\nimport { GaruError } from '@garuhq/node';\n\nexport type CliErrorCode =\n | 'auth_error'\n | 'not_found'\n | 'validation_error'\n | 'rate_limited'\n | 'server_error'\n | 'connection_error'\n | 'signature_verification_failed'\n | 'user_cancelled'\n | 'invalid_input'\n | 'unknown_error';\n\nexport class CliError extends Error {\n public readonly code: CliErrorCode;\n public readonly exitCode: number;\n\n constructor(code: CliErrorCode, message: string, exitCode = 1) {\n super(message);\n this.name = 'CliError';\n this.code = code;\n this.exitCode = exitCode;\n }\n}\n\n/** Wrap an unknown thrown value as a {@link CliError}. */\nexport function toCliError(err: unknown): CliError {\n if (err instanceof CliError) return err;\n if (err instanceof GaruError) {\n return new CliError(mapSdkCodeToCliCode(err.code), err.message, 1);\n }\n if (err instanceof Error) return new CliError('unknown_error', err.message);\n return new CliError('unknown_error', String(err));\n}\n\nfunction mapSdkCodeToCliCode(sdkCode: string): CliErrorCode {\n switch (sdkCode) {\n case 'authentication_error':\n case 'permission_error':\n return 'auth_error';\n case 'not_found':\n return 'not_found';\n case 'validation_error':\n return 'validation_error';\n case 'rate_limited':\n return 'rate_limited';\n case 'server_error':\n return 'server_error';\n case 'connection_error':\n return 'connection_error';\n case 'signature_verification_failed':\n return 'signature_verification_failed';\n default:\n return 'unknown_error';\n }\n}\n","import { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { mkdir, readFile, writeFile, rm, stat } from 'node:fs/promises';\n\nimport { CliError } from './errors.js';\n\nexport interface CredentialProfile {\n apiKey: string;\n /** Optional seller ID to render in `garu doctor` output. */\n sellerId?: number;\n /** Human-readable label for multi-profile setups. */\n label?: string;\n}\n\nexport interface CredentialsFile {\n version: 1;\n activeProfile: string;\n profiles: Record<string, CredentialProfile>;\n}\n\nconst DEFAULT_FILE: CredentialsFile = {\n version: 1,\n activeProfile: 'default',\n profiles: {}\n};\n\n/**\n * Resolve the credentials file path.\n *\n * Honors `$XDG_CONFIG_HOME` per the XDG base-dir spec, falling back to\n * `~/.config/garu/credentials.json`. Override with `$GARU_CREDENTIALS_PATH`\n * (primarily for tests).\n */\nexport function credentialsPath(env: NodeJS.ProcessEnv = process.env): string {\n if (env.GARU_CREDENTIALS_PATH) return env.GARU_CREDENTIALS_PATH;\n const base = env.XDG_CONFIG_HOME || join(homedir(), '.config');\n return join(base, 'garu', 'credentials.json');\n}\n\n/** Read the credentials file. Returns the default (empty) file if it doesn't exist. */\nexport async function loadCredentials(\n env: NodeJS.ProcessEnv = process.env\n): Promise<CredentialsFile> {\n const path = credentialsPath(env);\n try {\n const raw = await readFile(path, 'utf8');\n const parsed = JSON.parse(raw);\n return normalize(parsed);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { ...DEFAULT_FILE };\n }\n throw new CliError(\n 'invalid_input',\n `Failed to read credentials at ${path}: ${(err as Error).message}`\n );\n }\n}\n\n/**\n * Write the credentials file atomically with tight file-mode (0600) and\n * directory-mode (0700).\n */\nexport async function saveCredentials(\n file: CredentialsFile,\n env: NodeJS.ProcessEnv = process.env\n): Promise<void> {\n const path = credentialsPath(env);\n await mkdir(dirname(path), { recursive: true, mode: 0o700 });\n await writeFile(path, JSON.stringify(file, null, 2) + '\\n', { mode: 0o600 });\n}\n\n/** Delete the credentials file. No-op if it doesn't exist. */\nexport async function deleteCredentials(env: NodeJS.ProcessEnv = process.env): Promise<void> {\n const path = credentialsPath(env);\n try {\n await rm(path);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n}\n\n/** Add or replace a profile and set it active. */\nexport function upsertProfile(\n file: CredentialsFile,\n name: string,\n profile: CredentialProfile\n): CredentialsFile {\n return {\n ...file,\n activeProfile: name,\n profiles: { ...file.profiles, [name]: profile }\n };\n}\n\n/** Check whether the credentials file has the expected 0600 mode. Returns null on any error. */\nexport async function credentialsFileMode(\n env: NodeJS.ProcessEnv = process.env\n): Promise<number | null> {\n try {\n const s = await stat(credentialsPath(env));\n return s.mode & 0o777;\n } catch {\n return null;\n }\n}\n\nfunction normalize(raw: unknown): CredentialsFile {\n if (!raw || typeof raw !== 'object') return { ...DEFAULT_FILE };\n const obj = raw as Partial<CredentialsFile>;\n return {\n version: 1,\n activeProfile: obj.activeProfile ?? 'default',\n profiles: obj.profiles && typeof obj.profiles === 'object' ? obj.profiles : {}\n };\n}\n","import pc from 'picocolors';\n\nimport { CliError, toCliError } from './errors.js';\n\nexport type OutputMode = 'pretty' | 'json';\n\nexport interface OutputOptions {\n /** Force a mode. If omitted, auto-detect from TTY. */\n mode?: OutputMode;\n /** Passed by `--quiet`; suppresses everything except errors and the final value. */\n quiet?: boolean;\n}\n\n/**\n * Resolve the output mode. Rules:\n * - Explicit `--json` (or `opts.mode === 'json'`) wins.\n * - Non-TTY stdout (pipe, CI) → `json`.\n * - Everything else → `pretty`.\n */\nexport function resolveMode(\n opts: OutputOptions = {},\n stdout: NodeJS.WriteStream = process.stdout\n): OutputMode {\n if (opts.mode) return opts.mode;\n return stdout.isTTY ? 'pretty' : 'json';\n}\n\n/**\n * Print a successful command result. In JSON mode the full object is written\n * to stdout with a trailing newline. In pretty mode the caller's `prettyPrint`\n * fallback (if provided) is used; otherwise the JSON is indented.\n */\nexport function printResult<T>(\n value: T,\n opts: OutputOptions & { prettyPrint?: (value: T) => string } = {}\n): void {\n const mode = resolveMode(opts);\n if (mode === 'json') {\n process.stdout.write(`${JSON.stringify(value)}\\n`);\n return;\n }\n if (opts.prettyPrint) {\n process.stdout.write(`${opts.prettyPrint(value)}\\n`);\n return;\n }\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\n/** Print a short status line — suppressed in JSON mode and when `--quiet`. */\nexport function printStatus(message: string, opts: OutputOptions = {}): void {\n if (opts.quiet) return;\n if (resolveMode(opts) === 'json') return;\n process.stderr.write(`${pc.dim('→')} ${message}\\n`);\n}\n\n/** Print a success line — suppressed in JSON mode and when `--quiet`. */\nexport function printSuccess(message: string, opts: OutputOptions = {}): void {\n if (opts.quiet) return;\n if (resolveMode(opts) === 'json') return;\n process.stderr.write(`${pc.green('✓')} ${message}\\n`);\n}\n\n/**\n * Print an error and exit with the appropriate code. Always uses the\n * CLI-standard shape `{\"error\":{\"code\",\"message\"}}` on stdout in JSON mode,\n * or a red `Error:` line on stderr in pretty mode.\n */\nexport function printErrorAndExit(err: unknown, opts: OutputOptions = {}): never {\n const cliErr: CliError = toCliError(err);\n const payload = { error: { code: cliErr.code, message: cliErr.message } };\n\n if (resolveMode(opts) === 'json') {\n process.stdout.write(`${JSON.stringify(payload)}\\n`);\n } else {\n process.stderr.write(`${pc.red('Error:')} ${cliErr.message}\\n`);\n if (cliErr.code !== 'unknown_error') {\n process.stderr.write(`${pc.dim(` code: ${cliErr.code}`)}\\n`);\n }\n }\n process.exit(cliErr.exitCode);\n}\n","import { loadCredentials, saveCredentials } from '../lib/credentials.js';\nimport { CliError } from '../lib/errors.js';\nimport { printSuccess, type OutputOptions } from '../lib/output.js';\n\nexport interface AuthSwitchOptions extends OutputOptions {\n profile: string;\n}\n\nexport async function authSwitchCommand(\n opts: AuthSwitchOptions\n): Promise<{ activeProfile: string }> {\n const file = await loadCredentials();\n if (!file.profiles[opts.profile]) {\n const available = Object.keys(file.profiles).join(', ') || '(none)';\n throw new CliError('not_found', `Profile '${opts.profile}' not found. Available: ${available}`);\n }\n\n await saveCredentials({ ...file, activeProfile: opts.profile });\n printSuccess(`Active profile set to '${opts.profile}'.`, opts);\n return { activeProfile: opts.profile };\n}\n","import { loadCredentials, type CredentialProfile } from './credentials.js';\nimport { CliError } from './errors.js';\n\nexport interface ResolvedAuth {\n apiKey: string;\n /** Where the key came from, for `doctor` and debug output. */\n source: 'flag' | 'env' | 'file';\n /** Profile name if resolved from file; undefined otherwise. */\n profile?: string;\n fileProfile?: CredentialProfile;\n}\n\nexport interface ResolveAuthOptions {\n /** `--api-key` flag value. Highest precedence. */\n apiKey?: string;\n /** `--profile` flag value. When set, reads that profile instead of the active one. */\n profile?: string;\n env?: NodeJS.ProcessEnv;\n}\n\n/**\n * Resolve the API key following SPEC §7 auth priority:\n *\n * 1. `--api-key` flag\n * 2. `GARU_API_KEY` environment variable\n * 3. credentials file active profile (or profile selected with `--profile`)\n *\n * Throws {@link CliError} with code `auth_error` if no key is found. Never logs.\n */\nexport async function resolveAuth(opts: ResolveAuthOptions = {}): Promise<ResolvedAuth> {\n const env = opts.env ?? process.env;\n\n if (opts.apiKey) {\n return { apiKey: opts.apiKey, source: 'flag' };\n }\n\n if (env.GARU_API_KEY) {\n return { apiKey: env.GARU_API_KEY, source: 'env' };\n }\n\n const file = await loadCredentials(env);\n const profileName = opts.profile ?? file.activeProfile;\n const profile = file.profiles[profileName];\n if (profile && profile.apiKey) {\n return {\n apiKey: profile.apiKey,\n source: 'file',\n profile: profileName,\n fileProfile: profile\n };\n }\n\n throw new CliError('auth_error', 'No API key found. Run `garu login` or set GARU_API_KEY.');\n}\n\n/**\n * Same as {@link resolveAuth} but returns `null` instead of throwing when no\n * credentials are available. Used by `garu doctor`.\n */\nexport async function resolveAuthOptional(\n opts: ResolveAuthOptions = {}\n): Promise<ResolvedAuth | null> {\n try {\n return await resolveAuth(opts);\n } catch (err) {\n if (err instanceof CliError && err.code === 'auth_error') return null;\n throw err;\n }\n}\n","import { Garu } from '@garuhq/node';\n\nimport type { ResolvedAuth } from './auth.js';\n\nexport interface GaruClientOptions {\n auth: ResolvedAuth;\n baseUrl?: string;\n}\n\n/**\n * Construct a `Garu` SDK instance from resolved auth.\n *\n * The CLI dogfoods `@garuhq/node` — every HTTP call flows through the SDK we\n * shipped in Chunk 3. This keeps retries, idempotency, and error mapping\n * consistent between the CLI, MCP server, and any user-written integration.\n */\nexport function createGaruClient(opts: GaruClientOptions): Garu {\n return new Garu({\n apiKey: opts.auth.apiKey,\n baseUrl: opts.baseUrl\n });\n}\n","import type { Charge, Customer, Garu, PaymentMethod, RefundChargeParams } from '@garuhq/node';\n\nimport { resolveAuth } from '../lib/auth.js';\nimport { createGaruClient } from '../lib/client.js';\nimport { CliError } from '../lib/errors.js';\nimport { printResult, type OutputOptions } from '../lib/output.js';\n\nexport interface ChargesGlobalOptions extends OutputOptions {\n apiKey?: string;\n profile?: string;\n baseUrl?: string;\n /** Injectable for tests — bypass auth resolution + SDK construction. */\n garu?: Garu;\n}\n\nexport interface ChargesCreateOptions extends ChargesGlobalOptions {\n type: PaymentMethod;\n productId: string;\n customerName: string;\n customerEmail: string;\n customerDocument: string;\n customerPhone: string;\n cardNumber?: string;\n cardCvv?: string;\n cardExpiration?: string;\n cardHolder?: string;\n installments?: number;\n idempotencyKey?: string;\n additionalInfo?: string;\n}\n\nexport interface ChargesByIdOptions extends ChargesGlobalOptions {\n id: number;\n}\n\nexport interface ChargesRefundOptions extends ChargesByIdOptions {\n /** Amount in centavos. Omit for full refund. */\n amount?: number;\n reason?: string;\n idempotencyKey?: string;\n}\n\nasync function getClient(opts: ChargesGlobalOptions): Promise<Garu> {\n if (opts.garu) return opts.garu;\n const auth = await resolveAuth({\n ...(opts.apiKey !== undefined ? { apiKey: opts.apiKey } : {}),\n ...(opts.profile !== undefined ? { profile: opts.profile } : {})\n });\n return createGaruClient({\n auth,\n ...(opts.baseUrl !== undefined ? { baseUrl: opts.baseUrl } : {})\n });\n}\n\ntype ValidatedCardFields = ChargesCreateOptions & {\n cardNumber: string;\n cardCvv: string;\n cardExpiration: string;\n cardHolder: string;\n};\n\n/**\n * Assert that a credit-card charge request has every required card field.\n * Narrows the type so downstream code doesn't need `!` assertions.\n */\nfunction assertCardFieldsPresent(opts: ChargesCreateOptions): asserts opts is ValidatedCardFields {\n const missing: string[] = [];\n if (!opts.cardNumber) missing.push('--card-number');\n if (!opts.cardCvv) missing.push('--card-cvv');\n if (!opts.cardExpiration) missing.push('--card-expiration');\n if (!opts.cardHolder) missing.push('--card-holder');\n if (missing.length) {\n throw new CliError('invalid_input', `Credit-card charges require: ${missing.join(', ')}`);\n }\n}\n\nexport async function chargesCreateCommand(opts: ChargesCreateOptions): Promise<Charge> {\n const garu = await getClient(opts);\n\n const customer: Customer = {\n name: opts.customerName,\n email: opts.customerEmail,\n document: opts.customerDocument,\n phone: opts.customerPhone\n };\n\n const base = {\n productId: opts.productId,\n paymentMethod: opts.type,\n customer,\n additionalInfo: opts.additionalInfo,\n idempotencyKey: opts.idempotencyKey\n };\n\n let charge: Charge;\n if (opts.type === 'credit_card') {\n assertCardFieldsPresent(opts);\n charge = await garu.charges.create({\n ...base,\n cardInfo: {\n cardNumber: opts.cardNumber,\n cvv: opts.cardCvv,\n expirationDate: opts.cardExpiration,\n holderName: opts.cardHolder,\n installments: opts.installments ?? 1\n }\n });\n } else {\n charge = await garu.charges.create(base);\n }\n\n printResult(charge, { ...opts, prettyPrint: prettyCharge });\n return charge;\n}\n\nexport async function chargesGetCommand(opts: ChargesByIdOptions): Promise<Charge> {\n const garu = await getClient(opts);\n const charge = await garu.charges.get(opts.id);\n printResult(charge, { ...opts, prettyPrint: prettyCharge });\n return charge;\n}\n\nexport async function chargesRefundCommand(opts: ChargesRefundOptions): Promise<Charge> {\n const garu = await getClient(opts);\n const params: RefundChargeParams = {};\n if (opts.amount !== undefined) params.amount = opts.amount;\n if (opts.reason !== undefined) params.reason = opts.reason;\n if (opts.idempotencyKey !== undefined) params.idempotencyKey = opts.idempotencyKey;\n const charge = await garu.charges.refund(opts.id, params);\n printResult(charge, { ...opts, prettyPrint: prettyCharge });\n return charge;\n}\n\nfunction prettyCharge(charge: Charge): string {\n const lines = [\n `Charge ${charge.id}`,\n ` status: ${charge.status}`,\n ` amount: ${charge.amount}`,\n ` method: ${charge.paymentMethodId}`,\n ` date: ${charge.date}`\n ];\n if (charge.deadline) lines.push(` deadline: ${charge.deadline}`);\n return lines.join('\\n');\n}\n","import { existsSync } from 'node:fs';\nimport { homedir, platform } from 'node:os';\nimport { join } from 'node:path';\n\nimport { Garu } from '@garuhq/node';\n\nimport { resolveAuthOptional } from '../lib/auth.js';\nimport { credentialsFileMode, credentialsPath } from '../lib/credentials.js';\nimport { printResult, type OutputOptions } from '../lib/output.js';\nimport { CLI_VERSION } from '../version.js';\n\nexport interface DoctorReport {\n cli: { version: string };\n api: { reachable: boolean; url: string; version?: string; error?: string };\n credentials: {\n path: string;\n source: 'flag' | 'env' | 'file' | 'none';\n profile?: string;\n fileMode?: string;\n warning?: string;\n };\n agents: {\n claudeCode: boolean;\n cursor: boolean;\n codex: boolean;\n windsurf: boolean;\n claudeDesktop: boolean;\n vscodeMcpInCwd: boolean;\n };\n}\n\nexport interface DoctorOptions extends OutputOptions {\n apiKey?: string;\n profile?: string;\n baseUrl?: string;\n /** Injectable for tests — bypass the real HTTP call. */\n garu?: Garu;\n /** Injectable HOME, for tests. */\n home?: string;\n /** Injectable cwd, for tests. */\n cwd?: string;\n /** Injectable platform, for tests. */\n platform?: NodeJS.Platform;\n}\n\n/**\n * Run a full environment diagnostic.\n *\n * Never throws on expected failures — bad auth, unreachable API, missing\n * credentials all become structured report fields. Only genuinely unexpected\n * errors (programming bugs) bubble up.\n */\nexport async function doctorCommand(opts: DoctorOptions = {}): Promise<DoctorReport> {\n const home = opts.home ?? homedir();\n const cwd = opts.cwd ?? process.cwd();\n const plat = opts.platform ?? platform();\n\n const credentials = await reportCredentials(opts);\n const api = await reportApi(opts);\n const agents = detectAgents(home, cwd, plat);\n\n const report: DoctorReport = {\n cli: { version: CLI_VERSION },\n api,\n credentials,\n agents\n };\n\n printResult(report, { ...opts, prettyPrint: prettyDoctor });\n return report;\n}\n\nasync function reportCredentials(opts: DoctorOptions): Promise<DoctorReport['credentials']> {\n const path = credentialsPath();\n const resolved = await resolveAuthOptional({\n ...(opts.apiKey !== undefined ? { apiKey: opts.apiKey } : {}),\n ...(opts.profile !== undefined ? { profile: opts.profile } : {})\n });\n\n if (!resolved) {\n return { path, source: 'none' };\n }\n\n const out: DoctorReport['credentials'] = { path, source: resolved.source };\n if (resolved.profile) out.profile = resolved.profile;\n\n if (resolved.source === 'file') {\n const mode = await credentialsFileMode();\n if (mode !== null) {\n out.fileMode = `0${mode.toString(8)}`;\n if (mode !== 0o600) {\n out.warning = `credentials file mode is 0${mode.toString(8)}; expected 0600`;\n }\n }\n }\n\n return out;\n}\n\nasync function reportApi(opts: DoctorOptions): Promise<DoctorReport['api']> {\n const url = opts.baseUrl ?? 'https://garu.com.br';\n const garu =\n opts.garu ??\n new Garu({\n ...(opts.baseUrl !== undefined ? { baseUrl: opts.baseUrl } : {})\n });\n\n try {\n const meta = await garu.meta.get();\n return { reachable: true, url, version: meta.version };\n } catch (err) {\n return {\n reachable: false,\n url,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n}\n\nfunction detectAgents(home: string, cwd: string, plat: NodeJS.Platform): DoctorReport['agents'] {\n return {\n claudeCode: existsSync(join(home, '.claude')),\n cursor: existsSync(join(home, '.cursor')),\n codex: existsSync(join(home, '.codex')),\n windsurf: existsSync(join(home, '.windsurf')),\n claudeDesktop: existsSync(claudeDesktopConfigPath(home, plat)),\n vscodeMcpInCwd: existsSync(join(cwd, '.vscode', 'mcp.json'))\n };\n}\n\nfunction claudeDesktopConfigPath(home: string, plat: NodeJS.Platform): string {\n if (plat === 'darwin') {\n return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');\n }\n if (plat === 'win32') {\n return join(home, 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json');\n }\n return join(home, '.config', 'Claude', 'claude_desktop_config.json');\n}\n\nfunction prettyDoctor(r: DoctorReport): string {\n const check = (ok: boolean) => (ok ? 'yes' : 'no ');\n const lines = [\n `CLI: garu ${r.cli.version}`,\n `API: ${r.api.reachable ? `reachable (${r.api.url}, backend ${r.api.version ?? '?'})` : `unreachable (${r.api.url})`}`,\n r.api.error ? ` ${r.api.error}` : undefined,\n `Credentials: source=${r.credentials.source}${r.credentials.profile ? ` profile=${r.credentials.profile}` : ''}${r.credentials.fileMode ? ` mode=${r.credentials.fileMode}` : ''}`,\n r.credentials.warning ? ` ⚠ ${r.credentials.warning}` : undefined,\n '',\n 'Detected agents:',\n ` Claude Code: ${check(r.agents.claudeCode)}`,\n ` Cursor: ${check(r.agents.cursor)}`,\n ` Codex: ${check(r.agents.codex)}`,\n ` Windsurf: ${check(r.agents.windsurf)}`,\n ` Claude Desktop: ${check(r.agents.claudeDesktop)}`,\n ` VS Code MCP: ${check(r.agents.vscodeMcpInCwd)} (.vscode/mcp.json in cwd)`\n ].filter((l): l is string => l !== undefined);\n return lines.join('\\n');\n}\n","import { Garu } from '@garuhq/node';\n\nimport { loadCredentials, saveCredentials, upsertProfile } from '../lib/credentials.js';\nimport { CliError } from '../lib/errors.js';\nimport { printStatus, printSuccess, type OutputOptions } from '../lib/output.js';\n\nexport interface LoginOptions extends OutputOptions {\n /** Profile name to create/update. Default: `default`. */\n profile?: string;\n /** Pre-supplied API key (for scripting). When set, no interactive prompt. */\n apiKey?: string;\n /** Override base URL (tests). */\n baseUrl?: string;\n}\n\nexport async function loginCommand(opts: LoginOptions = {}): Promise<{ profile: string }> {\n const profile = opts.profile ?? 'default';\n\n // `@inquirer/prompts` is ESM-only; we lazy-load it via dynamic import so the\n // tsup-built CJS entry works on Node 18 (where require-of-ESM is forbidden).\n const apiKey =\n opts.apiKey ??\n (await import('@inquirer/prompts')\n .then(({ password }) =>\n password({\n message: 'Paste your Garu API key (sk_live_... or sk_test_...)',\n mask: '*'\n })\n )\n .catch(() => {\n throw new CliError('user_cancelled', 'Login cancelled.');\n }));\n\n if (!apiKey || !/^sk_(live|test)_[A-Za-z0-9_]+$/.test(apiKey)) {\n throw new CliError('invalid_input', 'API key must look like `sk_live_...` or `sk_test_...`.');\n }\n\n printStatus('Checking connectivity to Garu...', opts);\n const garu = new Garu({ apiKey, baseUrl: opts.baseUrl });\n\n // We hit the unauthenticated `/api/meta` to verify the SDK can reach the\n // backend. We do NOT yet verify the key is accepted — that requires an\n // authenticated probe endpoint (tracked as a Chunk 2b backend follow-up:\n // expose `GET /api/v1/me`). Until then, a malformed-but-valid-shape key\n // will be saved and fail on the next real command.\n await garu.meta.get();\n\n const file = await loadCredentials();\n const updated = upsertProfile(file, profile, { apiKey });\n await saveCredentials(updated);\n\n printSuccess(`Saved profile '${profile}' to ~/.config/garu/credentials.json`, opts);\n return { profile };\n}\n","import { deleteCredentials, loadCredentials, saveCredentials } from '../lib/credentials.js';\nimport { CliError } from '../lib/errors.js';\nimport { printSuccess, type OutputOptions } from '../lib/output.js';\n\nexport interface LogoutOptions extends OutputOptions {\n /**\n * Profile to remove. If omitted, the entire credentials file is deleted.\n */\n profile?: string;\n}\n\nexport async function logoutCommand(opts: LogoutOptions = {}): Promise<{ cleared: string }> {\n if (!opts.profile) {\n await deleteCredentials();\n printSuccess('All saved credentials deleted.', opts);\n return { cleared: 'all' };\n }\n\n const file = await loadCredentials();\n if (!file.profiles[opts.profile]) {\n throw new CliError('not_found', `Profile '${opts.profile}' not found.`);\n }\n\n const { [opts.profile]: _removed, ...rest } = file.profiles;\n void _removed;\n\n // If this was the only profile, delete the file entirely instead of writing\n // back an orphaned activeProfile pointing at nothing. Matches what users\n // would expect from `logout` — no credentials left on disk.\n if (Object.keys(rest).length === 0) {\n await deleteCredentials();\n printSuccess(`Profile '${opts.profile}' removed (credentials file deleted).`, opts);\n return { cleared: opts.profile };\n }\n\n const nextActive =\n file.activeProfile === opts.profile ? Object.keys(rest)[0]! : file.activeProfile;\n\n await saveCredentials({ ...file, activeProfile: nextActive, profiles: rest });\n printSuccess(`Profile '${opts.profile}' removed.`, opts);\n return { cleared: opts.profile };\n}\n","import { Command, Option } from 'commander';\n\nimport { CLI_VERSION } from './version.js';\nimport { authSwitchCommand } from './commands/auth-switch.js';\nimport {\n chargesCreateCommand,\n chargesGetCommand,\n chargesRefundCommand\n} from './commands/charges.js';\nimport { doctorCommand } from './commands/doctor.js';\nimport { loginCommand } from './commands/login.js';\nimport { logoutCommand } from './commands/logout.js';\nimport type { PaymentMethod } from '@garuhq/node';\nimport { CliError } from './lib/errors.js';\nimport { printErrorAndExit, type OutputMode } from './lib/output.js';\n\ninterface GlobalFlags {\n apiKey?: string;\n profile?: string;\n json?: boolean;\n quiet?: boolean;\n}\n\ninterface CommandBaseOptions {\n apiKey?: string;\n profile?: string;\n mode?: OutputMode;\n quiet?: boolean;\n}\n\n/** Build the top-level command tree. Exposed so tests can exercise the router. */\nexport function buildCli(): Command {\n const program = new Command();\n\n program\n .name('garu')\n .description('Command-line interface for the Garu payment gateway.')\n .version(CLI_VERSION, '-v, --version')\n .addOption(new Option('--api-key <key>', 'Garu API key (overrides env and credentials file)'))\n .addOption(new Option('-p, --profile <name>', 'credentials profile name'))\n .addOption(new Option('--json', 'emit strict JSON on stdout (forced in pipes)'))\n .addOption(new Option('-q, --quiet', 'suppress status output; only print results and errors'))\n .showHelpAfterError();\n\n // login\n program\n .command('login')\n .description('Save a Garu API key to the credentials file')\n .option('--api-key <key>', 'pre-supply the key instead of prompting')\n .option('-p, --profile <name>', 'profile name to store under', 'default')\n .action(async (cmdOpts: { apiKey?: string; profile: string }) => {\n const base = toCommandOptions(program);\n await loginCommand({\n apiKey: cmdOpts.apiKey,\n profile: cmdOpts.profile,\n mode: base.mode,\n quiet: base.quiet\n }).catch((err) => printErrorAndExit(err, base));\n });\n\n // logout\n program\n .command('logout')\n .description('Remove saved credentials')\n .option('-p, --profile <name>', 'only remove this profile instead of the whole file')\n .action(async (cmdOpts: { profile?: string }) => {\n const base = toCommandOptions(program);\n await logoutCommand({\n profile: cmdOpts.profile,\n mode: base.mode,\n quiet: base.quiet\n }).catch((err) => printErrorAndExit(err, base));\n });\n\n // auth switch\n const auth = program.command('auth').description('Manage credentials profiles');\n auth\n .command('switch <profile>')\n .description('Set the active credentials profile')\n .action(async (profile: string) => {\n const base = toCommandOptions(program);\n await authSwitchCommand({ profile, mode: base.mode, quiet: base.quiet }).catch((err) =>\n printErrorAndExit(err, base)\n );\n });\n\n // charges\n const charges = program.command('charges').description('Create, fetch, and refund charges');\n\n charges\n .command('create')\n .description('Create a charge (PIX, credit card, or boleto)')\n .requiredOption('--type <type>', 'payment method: pix | credit_card | boleto')\n .requiredOption('--product-id <uuid>', 'product UUID')\n .requiredOption('--customer-name <name>', 'customer full name')\n .requiredOption('--customer-email <email>', 'customer email')\n .requiredOption(\n '--customer-document <document>',\n 'CPF (11 digits) or CNPJ (14 digits), digits only'\n )\n .requiredOption('--customer-phone <phone>', 'customer phone with area code, digits only')\n .option('--card-number <number>', 'credit-card number (required for credit_card)')\n .option('--card-cvv <cvv>', 'credit-card CVV')\n .option('--card-expiration <yyyy-mm>', 'credit-card expiration date (YYYY-MM)')\n .option('--card-holder <name>', 'credit-card holder name')\n .option('--installments <n>', 'number of installments (1-12)', (v) => parseInt(v, 10), 1)\n .option('--additional-info <text>', 'free-form metadata attached to the charge')\n .option('--idempotency-key <key>', 'idempotency key (auto-generated if omitted)')\n .action(async (cmdOpts) => {\n const base = toCommandOptions(program);\n await chargesCreateCommand({\n ...base,\n type: parsePaymentMethod(cmdOpts.type),\n productId: cmdOpts.productId,\n customerName: cmdOpts.customerName,\n customerEmail: cmdOpts.customerEmail,\n customerDocument: cmdOpts.customerDocument,\n customerPhone: cmdOpts.customerPhone,\n cardNumber: cmdOpts.cardNumber,\n cardCvv: cmdOpts.cardCvv,\n cardExpiration: cmdOpts.cardExpiration,\n cardHolder: cmdOpts.cardHolder,\n installments: cmdOpts.installments,\n additionalInfo: cmdOpts.additionalInfo,\n idempotencyKey: cmdOpts.idempotencyKey\n }).catch((err) => printErrorAndExit(err, base));\n });\n\n charges\n .command('get <id>')\n .description('Fetch a single charge by ID')\n .action(async (id: string) => {\n const base = toCommandOptions(program);\n await chargesGetCommand({ ...base, id: parseId(id) }).catch((err) =>\n printErrorAndExit(err, base)\n );\n });\n\n charges\n .command('refund <id>')\n .description('Refund a charge (full or partial)')\n .option('--amount <centavos>', 'partial refund amount in centavos', (v) => parseInt(v, 10))\n .option('--reason <text>', 'optional refund reason')\n .option('--idempotency-key <key>', 'idempotency key (auto-generated if omitted)')\n .action(async (id: string, cmdOpts) => {\n const base = toCommandOptions(program);\n await chargesRefundCommand({\n ...base,\n id: parseId(id),\n amount: cmdOpts.amount,\n reason: cmdOpts.reason,\n idempotencyKey: cmdOpts.idempotencyKey\n }).catch((err) => printErrorAndExit(err, base));\n });\n\n // doctor\n program\n .command('doctor')\n .description('Environment diagnostic')\n .action(async () => {\n const base = toCommandOptions(program);\n await doctorCommand(base).catch((err) => printErrorAndExit(err, base));\n });\n\n return program;\n}\n\n/**\n * Collapse the root-command's global flags into the shape every command takes.\n * Commander never passes `undefined` for unset flags — they're just absent — so\n * we can forward this object to command handlers via spread without polluting\n * their signatures with `undefined` props.\n */\nfunction toCommandOptions(program: Command): CommandBaseOptions {\n const g = program.opts<GlobalFlags>();\n const out: CommandBaseOptions = {};\n if (g.apiKey) out.apiKey = g.apiKey;\n if (g.profile) out.profile = g.profile;\n if (g.json) out.mode = 'json';\n if (g.quiet) out.quiet = true;\n return out;\n}\n\nfunction parsePaymentMethod(raw: string): PaymentMethod {\n if (raw === 'pix' || raw === 'credit_card' || raw === 'boleto') return raw;\n throw new CliError(\n 'invalid_input',\n `--type must be 'pix', 'credit_card', or 'boleto' (got '${raw}')`\n );\n}\n\nfunction parseId(raw: string): number {\n const id = Number.parseInt(raw, 10);\n if (!Number.isFinite(id) || id <= 0) {\n throw new CliError('invalid_input', `Charge ID must be a positive integer (got '${raw}')`);\n }\n return id;\n}\n\n/** Main entry invoked by `bin/garu.cjs` and the compiled binary. */\nexport async function main(argv: string[] = process.argv): Promise<void> {\n const program = buildCli();\n await program.parseAsync(argv);\n}\n\n// This module is only ever loaded as the CLI entry point — either through the\n// `bin/garu.cjs` shim for npm installs or as the compiled binary produced by\n// `bun build --compile`. No test imports `src/index.ts`, so it's safe to call\n// `main()` unconditionally at module load time.\nmain().catch((err) => printErrorAndExit(err));\n"]}
package/dist/index.d.cts CHANGED
@@ -2,7 +2,7 @@ import { Command } from 'commander';
2
2
 
3
3
  /** Build the top-level command tree. Exposed so tests can exercise the router. */
4
4
  declare function buildCli(): Command;
5
- /** Main entry invoked by `bin/garu.js` and `src/index.ts` when run directly. */
5
+ /** Main entry invoked by `bin/garu.cjs` and the compiled binary. */
6
6
  declare function main(argv?: string[]): Promise<void>;
7
7
 
8
8
  export { buildCli, main };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garuhq/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Official command-line interface for the Garu payment gateway.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://garu.com.br",
@@ -45,15 +45,15 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@garuhq/node": "0.1.0",
48
- "@inquirer/prompts": "5.0.2",
48
+ "@inquirer/prompts": "8.4.1",
49
49
  "commander": "12.0.0",
50
50
  "picocolors": "1.0.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/node": "20.12.7",
54
- "tsup": "8.0.2",
55
- "tsx": "4.7.2",
54
+ "tsup": "8.5.1",
55
+ "tsx": "4.21.0",
56
56
  "typescript": "5.4.5",
57
- "vitest": "1.5.0"
57
+ "vitest": "3.2.4"
58
58
  }
59
59
  }