@hasna/domains 0.0.36 → 0.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/cli/commands/alerts.d.ts.map +1 -1
  2. package/dist/cli/commands/brandsight.d.ts.map +1 -1
  3. package/dist/cli/commands/config.d.ts.map +1 -1
  4. package/dist/cli/commands/db.d.ts.map +1 -1
  5. package/dist/cli/commands/dns.d.ts +4 -1
  6. package/dist/cli/commands/dns.d.ts.map +1 -1
  7. package/dist/cli/commands/doctor.d.ts.map +1 -1
  8. package/dist/cli/commands/domain.d.ts.map +1 -1
  9. package/dist/cli/commands/history.d.ts.map +1 -1
  10. package/dist/cli/commands/interactive.d.ts +7 -1
  11. package/dist/cli/commands/interactive.d.ts.map +1 -1
  12. package/dist/cli/commands/mcp-install.d.ts.map +1 -1
  13. package/dist/cli/commands/monitor.d.ts.map +1 -1
  14. package/dist/cli/commands/outreach.d.ts.map +1 -1
  15. package/dist/cli/commands/owner.d.ts.map +1 -1
  16. package/dist/cli/commands/provider.d.ts.map +1 -1
  17. package/dist/cli/commands/providers.d.ts.map +1 -1
  18. package/dist/cli/commands/provision.d.ts.map +1 -1
  19. package/dist/cli/commands/reconcile-expiry.d.ts.map +1 -1
  20. package/dist/cli/commands/research.d.ts.map +1 -1
  21. package/dist/cli/commands/route53.d.ts.map +1 -1
  22. package/dist/cli/commands/sedo.d.ts.map +1 -1
  23. package/dist/cli/commands/serve.d.ts.map +1 -1
  24. package/dist/cli/commands/ssl.d.ts.map +1 -1
  25. package/dist/cli/commands/wallet.d.ts.map +1 -1
  26. package/dist/cli/commands/zone.d.ts.map +1 -1
  27. package/dist/cli/index.js +906 -749
  28. package/dist/db/dns-tools.d.ts.map +1 -1
  29. package/dist/index.js +74 -16
  30. package/dist/lib/cloudflare.d.ts.map +1 -1
  31. package/dist/lib/cloudflare.js +57 -7
  32. package/dist/lib/dns-plan.d.ts +1 -0
  33. package/dist/lib/dns-plan.d.ts.map +1 -1
  34. package/dist/lib/registrar.d.ts +4 -0
  35. package/dist/lib/registrar.d.ts.map +1 -1
  36. package/dist/lib/registrar.js +58 -7
  37. package/dist/lib/route53.d.ts.map +1 -1
  38. package/dist/lib/route53.js +1 -0
  39. package/dist/lib/stdout.d.ts +54 -0
  40. package/dist/lib/stdout.d.ts.map +1 -0
  41. package/dist/mcp/index.js +74 -16
  42. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -16256,6 +16256,9 @@ function normalizeDnsRecordType(value) {
16256
16256
  }
16257
16257
  return recordType3;
16258
16258
  }
16259
+ function getVcardPropertyValue(entry) {
16260
+ return entry.length >= 4 ? entry[3] : entry[2];
16261
+ }
16259
16262
  async function rdapLookup(domainName) {
16260
16263
  const domain = normalizeDomainName(domainName);
16261
16264
  const url = `https://rdap.org/domain/${encodeURIComponent(domain)}`;
@@ -16304,17 +16307,19 @@ function extractRegistrantFromRdap(rdap) {
16304
16307
  for (const entry of vcard) {
16305
16308
  if (!Array.isArray(entry) || entry.length < 3)
16306
16309
  continue;
16307
- const [prop, _params, type] = entry;
16310
+ const [prop] = entry;
16311
+ const value = getVcardPropertyValue(entry);
16308
16312
  if (prop === "fn")
16309
- result.name = type ?? null;
16313
+ result.name = typeof value === "string" ? value : null;
16310
16314
  else if (prop === "email")
16311
- result.email = type ?? null;
16315
+ result.email = typeof value === "string" ? value : null;
16312
16316
  else if (prop === "tel")
16313
- result.phone = type ?? null;
16317
+ result.phone = typeof value === "string" ? value : null;
16314
16318
  else if (prop === "org") {
16315
- result.organization = Array.isArray(type) ? type[0] ?? null : type ?? null;
16319
+ const organization = Array.isArray(value) ? value[0] : value;
16320
+ result.organization = typeof organization === "string" ? organization : null;
16316
16321
  } else if (prop === "n" && !result.name) {
16317
- const parts = Array.isArray(type) ? type.filter(Boolean) : [type];
16322
+ const parts = Array.isArray(value) ? value.filter((part) => typeof part === "string" && part.length > 0) : typeof value === "string" ? [value] : [];
16318
16323
  result.name = parts.reverse().join(" ").trim() || null;
16319
16324
  }
16320
16325
  }
@@ -16331,8 +16336,10 @@ function extractRegistrarFromRdap(rdap) {
16331
16336
  if (entity.vcardArray?.[1]) {
16332
16337
  const vcard = entity.vcardArray[1];
16333
16338
  for (const entry of vcard) {
16334
- if (Array.isArray(entry) && entry[0] === "fn")
16335
- return entry[2] ?? null;
16339
+ if (Array.isArray(entry) && entry[0] === "fn") {
16340
+ const value = getVcardPropertyValue(entry);
16341
+ return typeof value === "string" ? value : null;
16342
+ }
16336
16343
  }
16337
16344
  }
16338
16345
  if (entity.remarks) {
@@ -28939,7 +28946,7 @@ var init_bowser = __esm(() => {
28939
28946
 
28940
28947
  // node_modules/@aws-sdk/core/dist-cjs/submodules/client/index.js
28941
28948
  var require_client2 = __commonJS((exports) => {
28942
- var __dirname = "/home/hasna/.hasna/repos/worktrees/open-domains/282f5cec-baae-438a-beed-bdf090475f02/node_modules/@aws-sdk/core/dist-cjs/submodules/client";
28949
+ var __dirname = "/home/hasna/.hasna/repos/worktrees/domains/0a933b3e-a459-4bcb-b94d-6ab12a2ec235/node_modules/@aws-sdk/core/dist-cjs/submodules/client";
28943
28950
  var retry = require_retry();
28944
28951
  var protocols = require_protocols();
28945
28952
  var lambdaInvokeStore = require_invoke_store();
@@ -50208,6 +50215,7 @@ function createRoute53Provider(config2) {
50208
50215
  }
50209
50216
  return {
50210
50217
  name: "route53",
50218
+ dnsWriteScope: "changed-groups",
50211
50219
  async listDomains() {
50212
50220
  return listDomainInventory();
50213
50221
  },
@@ -50577,16 +50585,51 @@ async function listRecordsByNameType(zoneId, type, name, config2) {
50577
50585
  proxied: r4.proxied
50578
50586
  }));
50579
50587
  }
50580
- async function replaceRecordsByNameType(zoneId, records, config2) {
50588
+ function sameRecordIdentity(a4, b4) {
50589
+ return a4.type === b4.type && a4.name === b4.name && a4.content === b4.content && (a4.priority ?? undefined) === (b4.priority ?? undefined);
50590
+ }
50591
+ function resolveDesiredProxied(records, existing) {
50592
+ const omitted = records.filter((record) => record.proxied === undefined);
50593
+ if (omitted.length === 0)
50594
+ return records;
50595
+ const { type, name } = records[0];
50596
+ if (omitted.length === records.length) {
50597
+ const proxyStates = new Set(existing.map((record) => record.proxied));
50598
+ if (proxyStates.size > 1) {
50599
+ throw new Error(`Cannot safely preserve Cloudflare proxied state for ${type} ${name}: ` + "existing records have mixed proxied values while desired records omit proxied; " + "set proxied explicitly on every desired record");
50600
+ }
50601
+ const inherited = existing[0]?.proxied;
50602
+ return inherited === undefined ? records : records.map((record) => ({ ...record, proxied: inherited }));
50603
+ }
50604
+ const existingHasProxyState = existing.some((record) => record.proxied !== undefined);
50605
+ return records.map((record) => {
50606
+ if (record.proxied !== undefined)
50607
+ return record;
50608
+ const matches = existing.filter((candidate) => sameRecordIdentity(candidate, record));
50609
+ if (matches.length === 1 && matches[0].proxied !== undefined) {
50610
+ return { ...record, proxied: matches[0].proxied };
50611
+ }
50612
+ if (!existingHasProxyState)
50613
+ return record;
50614
+ throw new Error(`Cannot safely preserve Cloudflare proxied state for ${type} ${name} record ${record.content}: ` + "omitted proxied does not resolve to exactly one existing value; " + "set proxied explicitly on this desired record");
50615
+ });
50616
+ }
50617
+ async function prepareRecordsByNameType(zoneId, records, config2) {
50581
50618
  if (records.length === 0)
50582
50619
  return;
50583
50620
  const { type, name } = records[0];
50584
50621
  const existing = await listRecordsByNameType(zoneId, type, name, config2);
50585
- for (const record of existing) {
50622
+ if (existing.length === records.length && records.every((record) => existing.some((candidate) => sameRecordIdentity(candidate, record) && candidate.ttl === record.ttl && (record.proxied === undefined || candidate.proxied === record.proxied)))) {
50623
+ return;
50624
+ }
50625
+ return { existing, desired: resolveDesiredProxied(records, existing) };
50626
+ }
50627
+ async function replaceRecordsByNameType(zoneId, replacement, config2) {
50628
+ for (const record of replacement.existing) {
50586
50629
  if (record.id)
50587
50630
  await deleteRecord2(zoneId, record.id, config2);
50588
50631
  }
50589
- for (const record of records) {
50632
+ for (const record of replacement.desired) {
50590
50633
  await cfFetch(`/zones/${zoneId}/dns_records`, {
50591
50634
  method: "POST",
50592
50635
  body: {
@@ -50595,7 +50638,7 @@ async function replaceRecordsByNameType(zoneId, records, config2) {
50595
50638
  content: record.content,
50596
50639
  ttl: record.ttl ?? 1,
50597
50640
  priority: record.priority,
50598
- proxied: record.proxied ?? false
50641
+ ...record.proxied === undefined ? {} : { proxied: record.proxied }
50599
50642
  },
50600
50643
  config: config2
50601
50644
  });
@@ -50630,6 +50673,7 @@ function createCloudflareProvider(config2) {
50630
50673
  const cfg = config2 ?? getConfig3();
50631
50674
  return {
50632
50675
  name: "cloudflare",
50676
+ dnsWriteScope: "changed-groups",
50633
50677
  async listDomains() {
50634
50678
  const zones = await listZones(cfg);
50635
50679
  return zones.map(zoneToDomainInfo);
@@ -50680,7 +50724,8 @@ function createCloudflareProvider(config2) {
50680
50724
  name: r4.name,
50681
50725
  value: r4.content,
50682
50726
  ttl: r4.ttl === 1 ? 0 : r4.ttl,
50683
- priority: r4.priority
50727
+ priority: r4.priority,
50728
+ ...r4.proxied === undefined ? {} : { proxied: r4.proxied }
50684
50729
  }));
50685
50730
  },
50686
50731
  async setDnsRecords(domain, records) {
@@ -50691,11 +50736,24 @@ function createCloudflareProvider(config2) {
50691
50736
  for (const r4 of records) {
50692
50737
  const key = `${r4.type}|${r4.name}`;
50693
50738
  const existing = grouped.get(key) ?? [];
50694
- existing.push({ type: r4.type, name: r4.name, content: r4.value, ttl: r4.ttl || 1, priority: r4.priority });
50739
+ existing.push({
50740
+ type: r4.type,
50741
+ name: r4.name,
50742
+ content: r4.value,
50743
+ ttl: r4.ttl || 1,
50744
+ priority: r4.priority,
50745
+ ...r4.proxied === undefined ? {} : { proxied: r4.proxied }
50746
+ });
50695
50747
  grouped.set(key, existing);
50696
50748
  }
50749
+ const replacements = [];
50697
50750
  for (const group of grouped.values()) {
50698
- await replaceRecordsByNameType(zone.id, group, cfg);
50751
+ const replacement = await prepareRecordsByNameType(zone.id, group, cfg);
50752
+ if (replacement)
50753
+ replacements.push(replacement);
50754
+ }
50755
+ for (const replacement of replacements) {
50756
+ await replaceRecordsByNameType(zone.id, replacement, cfg);
50699
50757
  }
50700
50758
  return true;
50701
50759
  }
@@ -51383,6 +51441,65 @@ function compactHint(page, noun, detailHint, options = {}) {
51383
51441
  }
51384
51442
  var DEFAULT_LIST_LIMIT = 20, MAX_LIST_LIMIT = 200;
51385
51443
 
51444
+ // src/lib/stdout.ts
51445
+ import { writeSync } from "fs";
51446
+ import { format } from "util";
51447
+ function awaitDrain() {
51448
+ Atomics.wait(backpressureWait, 0, 0, BACKPRESSURE_WAIT_MS);
51449
+ }
51450
+ function errorCodeOf(error) {
51451
+ if (typeof error !== "object" || error === null)
51452
+ return null;
51453
+ const code = error.code;
51454
+ return typeof code === "string" ? code : null;
51455
+ }
51456
+ function writeAllBytesSync(bytes, writer) {
51457
+ let offset = 0;
51458
+ while (offset < bytes.length) {
51459
+ let accepted;
51460
+ try {
51461
+ accepted = writer(bytes.subarray(offset));
51462
+ } catch (error) {
51463
+ const code = errorCodeOf(error);
51464
+ if (code === "EAGAIN" || code === "EWOULDBLOCK") {
51465
+ awaitDrain();
51466
+ continue;
51467
+ }
51468
+ if (code === "EPIPE" || code === "ERR_STREAM_DESTROYED")
51469
+ return "reader-closed";
51470
+ throw error;
51471
+ }
51472
+ if (accepted <= 0) {
51473
+ awaitDrain();
51474
+ continue;
51475
+ }
51476
+ offset += accepted;
51477
+ }
51478
+ return "complete";
51479
+ }
51480
+ function writeAllSync(text, writer) {
51481
+ return writeAllBytesSync(Buffer.from(text, "utf8"), writer);
51482
+ }
51483
+ function writeStdout(text, writer = stdoutWriter) {
51484
+ return writeAllSync(text, writer);
51485
+ }
51486
+ function formatLine(...args) {
51487
+ return `${format(...args)}
51488
+ `;
51489
+ }
51490
+ function printLine(...args) {
51491
+ return writeStdout(formatLine(...args));
51492
+ }
51493
+ function printErrorLine(...args) {
51494
+ return writeAllSync(formatLine(...args), stderrWriter);
51495
+ }
51496
+ var BACKPRESSURE_WAIT_MS = 1, backpressureWait, fdWriter = (fd) => (chunk) => writeSync(fd, chunk), stdoutWriter, stderrWriter;
51497
+ var init_stdout = __esm(() => {
51498
+ backpressureWait = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
51499
+ stdoutWriter = fdWriter(1);
51500
+ stderrWriter = fdWriter(2);
51501
+ });
51502
+
51386
51503
  // src/db/history.ts
51387
51504
  function createHistoryEntry2(input) {
51388
51505
  return getStore().createHistoryEntry(input);
@@ -51772,22 +51889,22 @@ function registerMonitorCommand(program2) {
51772
51889
  try {
51773
51890
  const result = await monitorBrand(brand);
51774
51891
  if (opts.json) {
51775
- console.log(JSON.stringify(result, null, 2));
51892
+ printLine(JSON.stringify(result, null, 2));
51776
51893
  return;
51777
51894
  }
51778
51895
  const page = pageItemsOrExit(result.alerts, { limit: opts.limit, all: opts.all });
51779
- console.log(`Monitor: ${result.brand}${result.stub ? " [stub]" : ""}`);
51896
+ printLine(`Monitor: ${result.brand}${result.stub ? " [stub]" : ""}`);
51780
51897
  if (page.items.length === 0) {
51781
- console.log("No alerts.");
51898
+ printLine("No alerts.");
51782
51899
  return;
51783
51900
  }
51784
51901
  for (const alert of page.items) {
51785
- console.log(` ${alert.domain} [${alert.type}] registered:${alert.registered_at}`);
51902
+ printLine(` ${alert.domain} [${alert.type}] registered:${alert.registered_at}`);
51786
51903
  }
51787
- console.log(`
51904
+ printLine(`
51788
51905
  ${compactHint(page, "alert(s)", "Use --all for every alert or --json for full monitor details.", { paging: "limit" })}`);
51789
51906
  } catch (e4) {
51790
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
51907
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
51791
51908
  process.exit(1);
51792
51909
  }
51793
51910
  });
@@ -51795,21 +51912,21 @@ ${compactHint(page, "alert(s)", "Use --all for every alert or --json for full mo
51795
51912
  try {
51796
51913
  const result = await getSimilarDomains(domain);
51797
51914
  if (opts.json) {
51798
- console.log(JSON.stringify(result, null, 2));
51915
+ printLine(JSON.stringify(result, null, 2));
51799
51916
  return;
51800
51917
  }
51801
51918
  const page = pageItemsOrExit(result.similar, { limit: opts.limit, all: opts.all });
51802
- console.log(`Similar domains for ${result.domain}${result.stub ? " [stub]" : ""}:`);
51919
+ printLine(`Similar domains for ${result.domain}${result.stub ? " [stub]" : ""}:`);
51803
51920
  if (page.items.length === 0) {
51804
- console.log("No similar domains found.");
51921
+ printLine("No similar domains found.");
51805
51922
  return;
51806
51923
  }
51807
51924
  for (const name of page.items)
51808
- console.log(` ${name}`);
51809
- console.log(`
51925
+ printLine(` ${name}`);
51926
+ printLine(`
51810
51927
  ${compactHint(page, "domain(s)", "Use --all for every result or --json for full response metadata.", { paging: "limit" })}`);
51811
51928
  } catch (e4) {
51812
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
51929
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
51813
51930
  process.exit(1);
51814
51931
  }
51815
51932
  });
@@ -51817,28 +51934,29 @@ ${compactHint(page, "domain(s)", "Use --all for every result or --json for full
51817
51934
  try {
51818
51935
  const result = await getThreatAssessment(domain);
51819
51936
  if (opts.json) {
51820
- console.log(JSON.stringify(result, null, 2));
51937
+ printLine(JSON.stringify(result, null, 2));
51821
51938
  return;
51822
51939
  }
51823
51940
  const page = pageItemsOrExit(result.threats, { limit: opts.limit, all: opts.all });
51824
- console.log(`Threat assessment for ${result.domain}${result.stub ? " [stub]" : ""}: ${result.risk_level}`);
51941
+ printLine(`Threat assessment for ${result.domain}${result.stub ? " [stub]" : ""}: ${result.risk_level}`);
51825
51942
  if (page.items.length === 0) {
51826
- console.log("No immediate threats detected.");
51943
+ printLine("No immediate threats detected.");
51827
51944
  } else {
51828
51945
  for (const threat of page.items)
51829
- console.log(` - ${truncateText(threat, 100)}`);
51946
+ printLine(` - ${truncateText(threat, 100)}`);
51830
51947
  }
51831
- console.log(`Recommendation: ${truncateText(result.recommendation, 140)}`);
51832
- console.log(`
51948
+ printLine(`Recommendation: ${truncateText(result.recommendation, 140)}`);
51949
+ printLine(`
51833
51950
  ${compactHint(page, "threat(s)", "Use --all for every threat or --json for the full assessment.", { paging: "limit" })}`);
51834
51951
  } catch (e4) {
51835
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
51952
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
51836
51953
  process.exit(1);
51837
51954
  }
51838
51955
  });
51839
51956
  }
51840
51957
  var init_monitor = __esm(() => {
51841
51958
  init_brandsight();
51959
+ init_stdout();
51842
51960
  });
51843
51961
 
51844
51962
  // src/cli/commands/sedo.ts
@@ -51851,7 +51969,7 @@ function parseSedoLimit(value, fallback) {
51851
51969
  return fallback;
51852
51970
  const parsed = Number(value);
51853
51971
  if (!Number.isInteger(parsed) || parsed < 0) {
51854
- console.error("--limit must be a non-negative integer");
51972
+ printErrorLine("--limit must be a non-negative integer");
51855
51973
  process.exit(1);
51856
51974
  }
51857
51975
  return parsed;
@@ -51868,19 +51986,19 @@ function registerSedoCommand(program2) {
51868
51986
  maxPrice: opts.maxPrice ? parseInt(opts.maxPrice) : undefined
51869
51987
  });
51870
51988
  if (opts.json) {
51871
- console.log(JSON.stringify(result, null, 2));
51989
+ printLine(JSON.stringify(result, null, 2));
51872
51990
  } else {
51873
51991
  if (result.domains.length === 0) {
51874
- console.log(`No domains found for "${keyword}".`);
51992
+ printLine(`No domains found for "${keyword}".`);
51875
51993
  return;
51876
51994
  }
51877
- console.log(`Sedo marketplace \u2014 "${keyword}" (${result.total} total):`);
51995
+ printLine(`Sedo marketplace \u2014 "${keyword}" (${result.total} total):`);
51878
51996
  for (const d4 of result.domains) {
51879
51997
  const price = d4.price ? ` \u2014 ${d4.price.toLocaleString()} ${d4.currency || ""}`.trimEnd() : " \u2014 make offer";
51880
51998
  const premium = d4.isPremium ? " [PREMIUM]" : "";
51881
- console.log(` ${d4.domain}${price}${premium}`);
51999
+ printLine(` ${d4.domain}${price}${premium}`);
51882
52000
  }
51883
- console.log(`
52001
+ printLine(`
51884
52002
  Showing ${result.domains.length}/${result.total} marketplace result(s). Use --limit <n> for more or --json for full fields.`);
51885
52003
  }
51886
52004
  });
@@ -51888,12 +52006,12 @@ Showing ${result.domains.length}/${result.total} marketplace result(s). Use --li
51888
52006
  const { checkSedoStatus: checkSedoStatus2 } = await Promise.resolve().then(() => (init_sedo(), exports_sedo));
51889
52007
  const results = await checkSedoStatus2(domains);
51890
52008
  if (opts.json) {
51891
- console.log(JSON.stringify(results, null, 2));
52009
+ printLine(JSON.stringify(results, null, 2));
51892
52010
  } else {
51893
52011
  for (const r4 of results) {
51894
52012
  const listed = r4.listed ? "listed" : "not listed";
51895
52013
  const sale = r4.forSale ? ` for sale (${r4.price || "?"} ${r4.currency || ""})` : "";
51896
- console.log(` ${r4.domain}: ${listed}${sale}`);
52014
+ printLine(` ${r4.domain}: ${listed}${sale}`);
51897
52015
  }
51898
52016
  }
51899
52017
  });
@@ -51902,19 +52020,19 @@ Showing ${result.domains.length}/${result.total} marketplace result(s). Use --li
51902
52020
  const limit = parseSedoLimit(opts.limit, opts.json || opts.all ? 100 : 20);
51903
52021
  const domains = await listSedoPortfolio2({ limit });
51904
52022
  if (opts.json) {
51905
- console.log(JSON.stringify(domains, null, 2));
52023
+ printLine(JSON.stringify(domains, null, 2));
51906
52024
  } else {
51907
52025
  if (domains.length === 0) {
51908
- console.log("No domains in your Sedo portfolio.");
52026
+ printLine("No domains in your Sedo portfolio.");
51909
52027
  return;
51910
52028
  }
51911
52029
  const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
51912
- console.log(`Sedo Portfolio:`);
52030
+ printLine(`Sedo Portfolio:`);
51913
52031
  for (const d4 of page.items) {
51914
52032
  const sale = d4.forSale ? `[for sale ${d4.price || "?"} ${d4.currency || ""}]` : "";
51915
- console.log(` ${d4.domain} ${sale}`);
52033
+ printLine(` ${d4.domain} ${sale}`);
51916
52034
  }
51917
- console.log(`
52035
+ printLine(`
51918
52036
  ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full marketplace fields.", { paging: "limit" })}`);
51919
52037
  }
51920
52038
  });
@@ -51929,9 +52047,9 @@ ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full ma
51929
52047
  buyNowPrice: opts.buyNowPrice ? parseInt(opts.buyNowPrice) : undefined
51930
52048
  });
51931
52049
  if (opts.json) {
51932
- console.log(JSON.stringify(result, null, 2));
52050
+ printLine(JSON.stringify(result, null, 2));
51933
52051
  } else {
51934
- console.log(`Added ${domain} to Sedo marketplace`);
52052
+ printLine(`Added ${domain} to Sedo marketplace`);
51935
52053
  }
51936
52054
  });
51937
52055
  sedo.command("edit").description("Update an existing domain on Sedo").argument("<domain>", "Domain name to update").option("--price <n>", "New asking price").option("--currency <currency>", "Currency").option("--buy-now-price <n>", "New buy-it-now price").option("--json", "Output as JSON", false).action(async (domain, opts) => {
@@ -51943,18 +52061,18 @@ ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full ma
51943
52061
  buyNowPrice: opts.buyNowPrice ? parseInt(opts.buyNowPrice) : undefined
51944
52062
  });
51945
52063
  if (opts.json) {
51946
- console.log(JSON.stringify(result, null, 2));
52064
+ printLine(JSON.stringify(result, null, 2));
51947
52065
  } else {
51948
- console.log(`Updated ${domain} on Sedo`);
52066
+ printLine(`Updated ${domain} on Sedo`);
51949
52067
  }
51950
52068
  });
51951
52069
  sedo.command("remove").description("Remove a domain from Sedo marketplace").argument("<domain>", "Domain name to remove").action(async (domain) => {
51952
52070
  const { removeDomainFromSedo: removeDomainFromSedo2 } = await Promise.resolve().then(() => (init_sedo(), exports_sedo));
51953
52071
  const removed = await removeDomainFromSedo2(domain);
51954
52072
  if (removed) {
51955
- console.log(`Removed ${domain} from Sedo marketplace`);
52073
+ printLine(`Removed ${domain} from Sedo marketplace`);
51956
52074
  } else {
51957
- console.error(`Failed to remove ${domain} from Sedo`);
52075
+ printErrorLine(`Failed to remove ${domain} from Sedo`);
51958
52076
  process.exit(1);
51959
52077
  }
51960
52078
  });
@@ -51962,10 +52080,10 @@ ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full ma
51962
52080
  const { checkSedoBlacklist: checkSedoBlacklist2 } = await Promise.resolve().then(() => (init_sedo(), exports_sedo));
51963
52081
  const results = await checkSedoBlacklist2(domains);
51964
52082
  if (opts.json) {
51965
- console.log(JSON.stringify(results, null, 2));
52083
+ printLine(JSON.stringify(results, null, 2));
51966
52084
  } else {
51967
52085
  for (const r4 of results) {
51968
- console.log(` ${r4.domain}: ${r4.blacklisted ? "BLACKLISTED" : "clean"}`);
52086
+ printLine(` ${r4.domain}: ${r4.blacklisted ? "BLACKLISTED" : "clean"}`);
51969
52087
  }
51970
52088
  }
51971
52089
  });
@@ -51974,13 +52092,15 @@ ${compactHint(page, "domain(s)", "Use --limit <n> for more or --json for full ma
51974
52092
  const price = parseInt(opts.price);
51975
52093
  const created = recordSedoPurchase2(domain, price, opts.orderId);
51976
52094
  if (opts.json) {
51977
- console.log(JSON.stringify(created, null, 2));
52095
+ printLine(JSON.stringify(created, null, 2));
51978
52096
  } else {
51979
- console.log(`Recorded Sedo purchase: ${domain} for $${price}`);
52097
+ printLine(`Recorded Sedo purchase: ${domain} for $${price}`);
51980
52098
  }
51981
52099
  });
51982
52100
  }
51983
- var init_sedo2 = () => {};
52101
+ var init_sedo2 = __esm(() => {
52102
+ init_stdout();
52103
+ });
51984
52104
 
51985
52105
  // src/db/owners.ts
51986
52106
  function createDomainOwner2(input) {
@@ -52073,7 +52193,7 @@ __export(exports_owner, {
52073
52193
  async function requireDomain2(identifier) {
52074
52194
  const details = await getDomainDetails2(identifier);
52075
52195
  if (!details) {
52076
- console.error(`Domain '${identifier}' not found.`);
52196
+ printErrorLine(`Domain '${identifier}' not found.`);
52077
52197
  process.exit(1);
52078
52198
  }
52079
52199
  return details;
@@ -52084,21 +52204,21 @@ function registerOwnerCommand(program2) {
52084
52204
  if (opts.withDomains) {
52085
52205
  const results = await listDomainsWithOwners2();
52086
52206
  if (opts.json) {
52087
- console.log(JSON.stringify({ owners: results, count: results.length }, null, 2));
52207
+ printLine(JSON.stringify({ owners: results, count: results.length }, null, 2));
52088
52208
  return;
52089
52209
  }
52090
52210
  const page2 = pageItemsOrExit(results, { limit: opts.limit, all: opts.all });
52091
52211
  if (page2.items.length === 0) {
52092
- console.log("No premium domain owners found.");
52212
+ printLine("No premium domain owners found.");
52093
52213
  return;
52094
52214
  }
52095
52215
  for (const r4 of page2.items) {
52096
52216
  const verified = r4.verified ? " [verified]" : "";
52097
52217
  const org = r4.owner_organization ? ` @ ${r4.owner_organization}` : "";
52098
52218
  const email = opts.verbose && r4.owner_email ? ` email:${r4.owner_email}` : "";
52099
- console.log(` ${r4.domain_name} (${r4.domain_status}) \u2014 ${r4.owner_name ?? r4.owner_email ?? "unknown"}${org}${verified}${email}`);
52219
+ printLine(` ${r4.domain_name} (${r4.domain_status}) \u2014 ${r4.owner_name ?? r4.owner_email ?? "unknown"}${org}${verified}${email}`);
52100
52220
  }
52101
- console.log(`
52221
+ printLine(`
52102
52222
  ${compactHint(page2, "domain(s) with owner info", "Use --verbose for email details or owner info <domain> for full details.", { paging: "limit" })}`);
52103
52223
  return;
52104
52224
  }
@@ -52108,87 +52228,87 @@ ${compactHint(page2, "domain(s) with owner info", "Use --verbose for email detai
52108
52228
  verified: opts.verifiedOnly ? true : undefined
52109
52229
  });
52110
52230
  if (opts.json) {
52111
- console.log(JSON.stringify({ owners, count: owners.length }, null, 2));
52231
+ printLine(JSON.stringify({ owners, count: owners.length }, null, 2));
52112
52232
  return;
52113
52233
  }
52114
52234
  const page = pageItemsOrExit(owners, { limit: opts.limit, all: opts.all });
52115
52235
  if (page.items.length === 0) {
52116
- console.log("No owners found.");
52236
+ printLine("No owners found.");
52117
52237
  return;
52118
52238
  }
52119
52239
  for (const o2 of page.items) {
52120
52240
  const verified = o2.verified ? " [verified]" : "";
52121
52241
  const org = o2.owner_organization ? ` @ ${o2.owner_organization}` : "";
52122
- console.log(` ${truncateText(o2.owner_name ?? o2.owner_email ?? "unknown", 48)}${org} [${o2.source}]${verified}`);
52242
+ printLine(` ${truncateText(o2.owner_name ?? o2.owner_email ?? "unknown", 48)}${org} [${o2.source}]${verified}`);
52123
52243
  if (opts.verbose && o2.owner_email)
52124
- console.log(` email: ${o2.owner_email}`);
52244
+ printLine(` email: ${o2.owner_email}`);
52125
52245
  if (opts.verbose && o2.owner_phone)
52126
- console.log(` phone: ${o2.owner_phone}`);
52246
+ printLine(` phone: ${o2.owner_phone}`);
52127
52247
  }
52128
- console.log(`
52248
+ printLine(`
52129
52249
  ${compactHint(page, "owner(s)", "Use --verbose for contact fields or owner get <id> for details.", { paging: "limit" })}`);
52130
52250
  });
52131
52251
  owner.command("get <ownerId>").description("Get owner details by ID").option("-j, --json", "Output JSON").action(async (ownerId, opts) => {
52132
52252
  const o2 = await getDomainOwner2(ownerId);
52133
52253
  if (!o2) {
52134
- console.error(`Owner '${ownerId}' not found.`);
52254
+ printErrorLine(`Owner '${ownerId}' not found.`);
52135
52255
  process.exit(1);
52136
52256
  }
52137
52257
  if (opts.json) {
52138
- console.log(JSON.stringify(o2, null, 2));
52258
+ printLine(JSON.stringify(o2, null, 2));
52139
52259
  return;
52140
52260
  }
52141
- console.log(`
52261
+ printLine(`
52142
52262
  Owner: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
52143
52263
  if (o2.owner_organization)
52144
- console.log(` Organization: ${o2.owner_organization}`);
52264
+ printLine(` Organization: ${o2.owner_organization}`);
52145
52265
  if (o2.owner_email)
52146
- console.log(` Email: ${o2.owner_email}`);
52266
+ printLine(` Email: ${o2.owner_email}`);
52147
52267
  if (o2.owner_phone)
52148
- console.log(` Phone: ${o2.owner_phone}`);
52149
- console.log(` Source: ${o2.source}`);
52150
- console.log(` Verified: ${o2.verified ? "yes" : "no"}`);
52268
+ printLine(` Phone: ${o2.owner_phone}`);
52269
+ printLine(` Source: ${o2.source}`);
52270
+ printLine(` Verified: ${o2.verified ? "yes" : "no"}`);
52151
52271
  if (o2.contact_id)
52152
- console.log(` Contacts ID: ${o2.contact_id}`);
52272
+ printLine(` Contacts ID: ${o2.contact_id}`);
52153
52273
  if (o2.notes)
52154
- console.log(` Notes: ${truncateText(o2.notes, 160)}`);
52155
- console.log();
52274
+ printLine(` Notes: ${truncateText(o2.notes, 160)}`);
52275
+ printLine();
52156
52276
  });
52157
52277
  owner.command("info <identifier>").description("Show owner info for a specific domain").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
52158
52278
  const details = await requireDomain2(identifier);
52159
52279
  const o2 = await getDomainOwnerByDomain2(details.domain.id);
52160
52280
  if (!o2) {
52161
52281
  if (opts.json) {
52162
- console.log(JSON.stringify({ domain: details.domain.name, owner: null }, null, 2));
52282
+ printLine(JSON.stringify({ domain: details.domain.name, owner: null }, null, 2));
52163
52283
  return;
52164
52284
  }
52165
- console.log(`No owner info for ${details.domain.name}.`);
52285
+ printLine(`No owner info for ${details.domain.name}.`);
52166
52286
  return;
52167
52287
  }
52168
52288
  const result = { domain: details.domain.name, owner: o2 };
52169
52289
  if (opts.json) {
52170
- console.log(JSON.stringify(result, null, 2));
52290
+ printLine(JSON.stringify(result, null, 2));
52171
52291
  return;
52172
52292
  }
52173
- console.log(`
52293
+ printLine(`
52174
52294
  Domain: ${details.domain.name} [${details.domain.status}]`);
52175
- console.log(` Owner: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
52295
+ printLine(` Owner: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
52176
52296
  if (o2.owner_organization)
52177
- console.log(` Organization: ${o2.owner_organization}`);
52297
+ printLine(` Organization: ${o2.owner_organization}`);
52178
52298
  if (o2.owner_email)
52179
- console.log(` Email: ${o2.owner_email}`);
52299
+ printLine(` Email: ${o2.owner_email}`);
52180
52300
  if (o2.owner_phone)
52181
- console.log(` Phone: ${o2.owner_phone}`);
52182
- console.log(` Source: ${o2.source}`);
52183
- console.log(` Verified: ${o2.verified ? "yes" : "no"}`);
52301
+ printLine(` Phone: ${o2.owner_phone}`);
52302
+ printLine(` Source: ${o2.source}`);
52303
+ printLine(` Verified: ${o2.verified ? "yes" : "no"}`);
52184
52304
  if (o2.contact_id)
52185
- console.log(` Contacts ID: ${o2.contact_id}`);
52186
- console.log();
52305
+ printLine(` Contacts ID: ${o2.contact_id}`);
52306
+ printLine();
52187
52307
  });
52188
52308
  owner.command("add <identifier>").description("Add owner info for a domain").option("--name <name>", "Owner name").option("--email <email>", "Owner email").option("--phone <phone>", "Owner phone").option("--organization <org>", "Owner organization").option("--source <source>", "Source (whois/manual/brandsight/import)", "manual").option("--contact-id <id>", "Link to existing open-contacts contact ID").option("--verified", "Mark as verified").option("--notes <text>", "Notes").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
52189
52309
  const details = await requireDomain2(identifier);
52190
52310
  if (!opts.name && !opts.email && !opts.organization && !opts.contactId) {
52191
- console.error("At least one of --name, --email, --organization, or --contact-id is required.");
52311
+ printErrorLine("At least one of --name, --email, --organization, or --contact-id is required.");
52192
52312
  process.exit(1);
52193
52313
  }
52194
52314
  const input = {
@@ -52204,15 +52324,15 @@ Domain: ${details.domain.name} [${details.domain.status}]`);
52204
52324
  };
52205
52325
  const o2 = await createDomainOwner2(input);
52206
52326
  if (opts.json) {
52207
- console.log(JSON.stringify(o2, null, 2));
52327
+ printLine(JSON.stringify(o2, null, 2));
52208
52328
  return;
52209
52329
  }
52210
- console.log(`Added owner for ${details.domain.name}: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
52330
+ printLine(`Added owner for ${details.domain.name}: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
52211
52331
  });
52212
52332
  owner.command("update <ownerId>").description("Update owner info").option("--name <name>", "Owner name").option("--email <email>", "Owner email").option("--phone <phone>", "Owner phone").option("--organization <org>", "Owner organization").option("--contact-id <id>", "Link to open-contacts contact ID").option("--verified", "Mark as verified").option("--unverify", "Unmark as verified").option("--notes <text>", "Notes").option("-j, --json", "Output JSON").action(async (ownerId, opts) => {
52213
52333
  const existing = await getDomainOwner2(ownerId);
52214
52334
  if (!existing) {
52215
- console.error(`Owner '${ownerId}' not found.`);
52335
+ printErrorLine(`Owner '${ownerId}' not found.`);
52216
52336
  process.exit(1);
52217
52337
  }
52218
52338
  const update = {};
@@ -52234,72 +52354,72 @@ Domain: ${details.domain.name} [${details.domain.status}]`);
52234
52354
  update.notes = opts.notes;
52235
52355
  const o2 = await updateDomainOwner2(ownerId, update);
52236
52356
  if (!o2) {
52237
- console.error("Update failed.");
52357
+ printErrorLine("Update failed.");
52238
52358
  process.exit(1);
52239
52359
  }
52240
52360
  if (opts.json) {
52241
- console.log(JSON.stringify(o2, null, 2));
52361
+ printLine(JSON.stringify(o2, null, 2));
52242
52362
  return;
52243
52363
  }
52244
- console.log(`Updated owner: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
52364
+ printLine(`Updated owner: ${o2.owner_name ?? o2.owner_email ?? "unknown"}`);
52245
52365
  });
52246
52366
  owner.command("delete <ownerId>").description("Delete an owner record").option("-f, --force", "Required confirmation").action(async (ownerId, opts) => {
52247
52367
  if (!opts.force) {
52248
- console.error(`Refusing to delete owner '${ownerId}' without --force.`);
52368
+ printErrorLine(`Refusing to delete owner '${ownerId}' without --force.`);
52249
52369
  process.exit(1);
52250
52370
  }
52251
52371
  const deleted = await deleteDomainOwner2(ownerId);
52252
52372
  if (!deleted) {
52253
- console.error(`Owner '${ownerId}' not found.`);
52373
+ printErrorLine(`Owner '${ownerId}' not found.`);
52254
52374
  process.exit(1);
52255
52375
  }
52256
- console.log(`Deleted owner ${ownerId}`);
52376
+ printLine(`Deleted owner ${ownerId}`);
52257
52377
  });
52258
52378
  owner.command("extract <identifier>").description("Extract owner info from WHOIS lookup").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
52259
52379
  const details = await requireDomain2(identifier);
52260
52380
  const whois = await whoisLookup(details.domain.name);
52261
52381
  if (!whois.raw) {
52262
- console.error("WHOIS returned no data.");
52382
+ printErrorLine("WHOIS returned no data.");
52263
52383
  process.exit(1);
52264
52384
  }
52265
52385
  const o2 = await extractOwnerFromWhois(details.domain.name, whois.raw);
52266
52386
  if (!o2) {
52267
- console.log("No owner information found in WHOIS data.");
52387
+ printLine("No owner information found in WHOIS data.");
52268
52388
  return;
52269
52389
  }
52270
52390
  if (opts.json) {
52271
- console.log(JSON.stringify(o2, null, 2));
52391
+ printLine(JSON.stringify(o2, null, 2));
52272
52392
  return;
52273
52393
  }
52274
- console.log(`Extracted owner for ${details.domain.name}:`);
52394
+ printLine(`Extracted owner for ${details.domain.name}:`);
52275
52395
  if (o2.owner_name)
52276
- console.log(` Name: ${o2.owner_name}`);
52396
+ printLine(` Name: ${o2.owner_name}`);
52277
52397
  if (o2.owner_email)
52278
- console.log(` Email: ${o2.owner_email}`);
52398
+ printLine(` Email: ${o2.owner_email}`);
52279
52399
  if (o2.owner_phone)
52280
- console.log(` Phone: ${o2.owner_phone}`);
52400
+ printLine(` Phone: ${o2.owner_phone}`);
52281
52401
  if (o2.owner_organization)
52282
- console.log(` Organization: ${o2.owner_organization}`);
52283
- console.log();
52402
+ printLine(` Organization: ${o2.owner_organization}`);
52403
+ printLine();
52284
52404
  });
52285
52405
  owner.command("link <identifier>").description("Link domain owner to open-contacts contact").option("--contact-id <id>", "Existing contact ID in open-contacts").option("--auto", "Auto-create contact from owner info").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
52286
52406
  const details = await requireDomain2(identifier);
52287
52407
  const o2 = await getDomainOwnerByDomain2(details.domain.id);
52288
52408
  if (!o2) {
52289
- console.error(`No owner record for ${details.domain.name}. Add one first.`);
52409
+ printErrorLine(`No owner record for ${details.domain.name}. Add one first.`);
52290
52410
  process.exit(1);
52291
52411
  }
52292
52412
  if (opts.contactId) {
52293
52413
  const updated = await updateDomainOwner2(o2.id, { contact_id: opts.contactId });
52294
52414
  if (!updated) {
52295
- console.error("Link failed.");
52415
+ printErrorLine("Link failed.");
52296
52416
  process.exit(1);
52297
52417
  }
52298
52418
  if (opts.json) {
52299
- console.log(JSON.stringify(updated, null, 2));
52419
+ printLine(JSON.stringify(updated, null, 2));
52300
52420
  return;
52301
52421
  }
52302
- console.log(`Linked ${details.domain.name} to contact ${opts.contactId}`);
52422
+ printLine(`Linked ${details.domain.name} to contact ${opts.contactId}`);
52303
52423
  return;
52304
52424
  }
52305
52425
  if (opts.auto) {
@@ -52311,64 +52431,65 @@ Domain: ${details.domain.name} [${details.domain.status}]`);
52311
52431
  getContactByEmail: (email) => contacts.getContactByEmail(email)
52312
52432
  });
52313
52433
  if (!contactId) {
52314
- console.error("Could not create/find contact \u2014 owner has no email.");
52434
+ printErrorLine("Could not create/find contact \u2014 owner has no email.");
52315
52435
  process.exit(1);
52316
52436
  }
52317
52437
  if (opts.json) {
52318
- console.log(JSON.stringify({ domain: details.domain.name, contact_id: contactId }, null, 2));
52438
+ printLine(JSON.stringify({ domain: details.domain.name, contact_id: contactId }, null, 2));
52319
52439
  return;
52320
52440
  }
52321
- console.log(`Created/linked contact ${contactId} for ${details.domain.name}`);
52441
+ printLine(`Created/linked contact ${contactId} for ${details.domain.name}`);
52322
52442
  } catch (e4) {
52323
52443
  const message = e4 instanceof Error ? e4.message : String(e4);
52324
52444
  if (typeof e4 === "object" && e4 !== null && "code" in e4 && e4.code === "MODULE_NOT_FOUND" || message.includes("@hasna/contacts")) {
52325
- console.error("@hasna/contacts is not installed. Install it alongside @hasna/domains, or pass --contact-id to link an existing contact ID.");
52445
+ printErrorLine("@hasna/contacts is not installed. Install it alongside @hasna/domains, or pass --contact-id to link an existing contact ID.");
52326
52446
  } else {
52327
- console.error(`Failed to link to open-contacts: ${message}`);
52447
+ printErrorLine(`Failed to link to open-contacts: ${message}`);
52328
52448
  }
52329
52449
  process.exit(1);
52330
52450
  }
52331
52451
  return;
52332
52452
  }
52333
- console.error("Use --contact-id <id> or --auto to link.");
52453
+ printErrorLine("Use --contact-id <id> or --auto to link.");
52334
52454
  process.exit(1);
52335
52455
  });
52336
52456
  owner.command("whois <identifier>").description("WHOIS lookup and save owner info").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
52337
52457
  const details = await requireDomain2(identifier);
52338
52458
  const whois = await whoisLookup(details.domain.name);
52339
52459
  if (!whois.raw) {
52340
- console.error("WHOIS returned no data.");
52460
+ printErrorLine("WHOIS returned no data.");
52341
52461
  process.exit(1);
52342
52462
  }
52343
52463
  const o2 = await extractOwnerFromWhois(details.domain.name, whois.raw);
52344
52464
  if (!o2) {
52345
52465
  if (opts.json) {
52346
- console.log(JSON.stringify({ domain: details.domain.name, owner: null }, null, 2));
52466
+ printLine(JSON.stringify({ domain: details.domain.name, owner: null }, null, 2));
52347
52467
  return;
52348
52468
  }
52349
- console.log("No owner information found in WHOIS data.");
52469
+ printLine("No owner information found in WHOIS data.");
52350
52470
  return;
52351
52471
  }
52352
52472
  if (opts.json) {
52353
- console.log(JSON.stringify(o2, null, 2));
52473
+ printLine(JSON.stringify(o2, null, 2));
52354
52474
  return;
52355
52475
  }
52356
- console.log(`WHOIS owner for ${details.domain.name}:`);
52476
+ printLine(`WHOIS owner for ${details.domain.name}:`);
52357
52477
  if (o2.owner_name)
52358
- console.log(` Name: ${o2.owner_name}`);
52478
+ printLine(` Name: ${o2.owner_name}`);
52359
52479
  if (o2.owner_email)
52360
- console.log(` Email: ${o2.owner_email}`);
52480
+ printLine(` Email: ${o2.owner_email}`);
52361
52481
  if (o2.owner_phone)
52362
- console.log(` Phone: ${o2.owner_phone}`);
52482
+ printLine(` Phone: ${o2.owner_phone}`);
52363
52483
  if (o2.owner_organization)
52364
- console.log(` Organization: ${o2.owner_organization}`);
52365
- console.log(` Source: ${o2.source}`);
52366
- console.log();
52484
+ printLine(` Organization: ${o2.owner_organization}`);
52485
+ printLine(` Source: ${o2.source}`);
52486
+ printLine();
52367
52487
  });
52368
52488
  }
52369
52489
  var init_owner = __esm(() => {
52370
52490
  init_owners();
52371
52491
  init_domains();
52492
+ init_stdout();
52372
52493
  });
52373
52494
 
52374
52495
  // src/cli/commands/history.ts
@@ -52381,7 +52502,7 @@ function registerHistoryCommand(program2) {
52381
52502
  history.command("list <identifier>").description("List history entries for a domain").option("--type <type>", "Filter by type (whois/rdap/dns/ssl/reputation/exa_research)").option("--limit <n>", "Limit results", "20").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
52382
52503
  const domain = await getDomainDetails2(identifier);
52383
52504
  if (!domain) {
52384
- console.error(`Domain '${identifier}' not found.`);
52505
+ printErrorLine(`Domain '${identifier}' not found.`);
52385
52506
  process.exit(1);
52386
52507
  }
52387
52508
  const entries = await getHistoryByDomain2(domain.domain.id, {
@@ -52389,94 +52510,95 @@ function registerHistoryCommand(program2) {
52389
52510
  limit: opts.limit ? parseInt(opts.limit) : undefined
52390
52511
  });
52391
52512
  if (opts.json) {
52392
- console.log(JSON.stringify({ domain: domain.domain.name, history: entries, count: entries.length }, null, 2));
52513
+ printLine(JSON.stringify({ domain: domain.domain.name, history: entries, count: entries.length }, null, 2));
52393
52514
  return;
52394
52515
  }
52395
52516
  if (entries.length === 0) {
52396
- console.log(`No history entries for ${domain.domain.name}.`);
52517
+ printLine(`No history entries for ${domain.domain.name}.`);
52397
52518
  return;
52398
52519
  }
52399
- console.log(`History for ${domain.domain.name}:`);
52520
+ printLine(`History for ${domain.domain.name}:`);
52400
52521
  for (const e4 of entries) {
52401
- console.log(` [${e4.created_at}] ${e4.snapshot_type} \u2014 ${e4.registrant_name ?? e4.registrant_email ?? "no owner info"}`);
52522
+ printLine(` [${e4.created_at}] ${e4.snapshot_type} \u2014 ${e4.registrant_name ?? e4.registrant_email ?? "no owner info"}`);
52402
52523
  if (e4.registrar)
52403
- console.log(` Registrar: ${e4.registrar}`);
52524
+ printLine(` Registrar: ${e4.registrar}`);
52404
52525
  if (e4.notes)
52405
- console.log(` Notes: ${truncateText(e4.notes, 120)}`);
52526
+ printLine(` Notes: ${truncateText(e4.notes, 120)}`);
52406
52527
  }
52407
- console.log(`
52528
+ printLine(`
52408
52529
  ${entries.length} entry(ies). Use --limit <n> for a different page size or --json for full snapshots.`);
52409
52530
  });
52410
52531
  history.command("timeline").description("Show all domains with history changes").option("--limit <n>", "Limit number of displayed domains").option("--all", "Show all domains with history").option("-j, --json", "Output JSON").action(async (opts) => {
52411
52532
  const results = await listDomainsWithHistoryChanges2();
52412
52533
  if (opts.json) {
52413
- console.log(JSON.stringify({ domains: results, count: results.length }, null, 2));
52534
+ printLine(JSON.stringify({ domains: results, count: results.length }, null, 2));
52414
52535
  return;
52415
52536
  }
52416
52537
  if (results.length === 0) {
52417
- console.log("No domains with history entries.");
52538
+ printLine("No domains with history entries.");
52418
52539
  return;
52419
52540
  }
52420
52541
  const page = pageItemsOrExit(results, { limit: opts.limit, all: opts.all });
52421
- console.log("Domain History Timeline:");
52542
+ printLine("Domain History Timeline:");
52422
52543
  for (const r4 of page.items) {
52423
- console.log(` ${r4.domain_name} \u2014 ${r4.snapshot_count} snapshots, latest: ${r4.latest_snapshot_type} at ${r4.latest_snapshot_at}`);
52544
+ printLine(` ${r4.domain_name} \u2014 ${r4.snapshot_count} snapshots, latest: ${r4.latest_snapshot_type} at ${r4.latest_snapshot_at}`);
52424
52545
  }
52425
- console.log(`
52546
+ printLine(`
52426
52547
  ${compactHint(page, "domain(s) with history", "Use history list <domain> for domain details or --json for full data.", { paging: "limit" })}`);
52427
52548
  });
52428
52549
  history.command("range").description("List history entries within a date range").requiredOption("--from <date>", "Start date (ISO)").requiredOption("--to <date>", "End date (ISO)").option("--domain <name>", "Filter by domain name").option("--limit <n>", "Limit number of displayed entries").option("--all", "Show all entries in range").option("--verbose", "Show truncated notes and registrar details").option("-j, --json", "Output JSON").action(async (opts) => {
52429
52550
  const entries = await getHistoryByDateRange2(opts.from, opts.to, opts.domain);
52430
52551
  if (opts.json) {
52431
- console.log(JSON.stringify({ history: entries, count: entries.length }, null, 2));
52552
+ printLine(JSON.stringify({ history: entries, count: entries.length }, null, 2));
52432
52553
  return;
52433
52554
  }
52434
52555
  if (entries.length === 0) {
52435
- console.log(`No history entries between ${opts.from} and ${opts.to}.`);
52556
+ printLine(`No history entries between ${opts.from} and ${opts.to}.`);
52436
52557
  return;
52437
52558
  }
52438
52559
  const page = pageItemsOrExit(entries, { limit: opts.limit, all: opts.all });
52439
- console.log(`History from ${opts.from} to ${opts.to}:`);
52560
+ printLine(`History from ${opts.from} to ${opts.to}:`);
52440
52561
  for (const e4 of page.items) {
52441
52562
  const extra = opts.verbose ? ` registrar:${truncateText(e4.registrar ?? "-", 40)} notes:${truncateText(e4.notes ?? "-", 80)}` : "";
52442
- console.log(` [${e4.created_at}] ${e4.snapshot_type} \u2014 domain ${e4.domain_id}${extra}`);
52563
+ printLine(` [${e4.created_at}] ${e4.snapshot_type} \u2014 domain ${e4.domain_id}${extra}`);
52443
52564
  }
52444
- console.log(`
52565
+ printLine(`
52445
52566
  ${compactHint(page, "entry(s)", "Use --verbose for more columns or --json for full snapshots.", { paging: "limit" })}`);
52446
52567
  });
52447
52568
  history.command("delete <entryId>").description("Delete a history entry").option("-f, --force", "Required confirmation").action(async (entryId, opts) => {
52448
52569
  if (!opts.force) {
52449
- console.error(`Refusing to delete history '${entryId}' without --force.`);
52570
+ printErrorLine(`Refusing to delete history '${entryId}' without --force.`);
52450
52571
  process.exit(1);
52451
52572
  }
52452
52573
  const deleted = await deleteHistoryEntry2(entryId);
52453
52574
  if (!deleted) {
52454
- console.error(`History entry '${entryId}' not found.`);
52575
+ printErrorLine(`History entry '${entryId}' not found.`);
52455
52576
  process.exit(1);
52456
52577
  }
52457
- console.log(`Deleted history entry ${entryId}`);
52578
+ printLine(`Deleted history entry ${entryId}`);
52458
52579
  });
52459
52580
  history.command("purge <identifier>").description("Delete all history for a domain").option("-f, --force", "Required confirmation").action(async (identifier, opts) => {
52460
52581
  if (!opts.force) {
52461
- console.error(`Refusing to purge history for '${identifier}' without --force.`);
52582
+ printErrorLine(`Refusing to purge history for '${identifier}' without --force.`);
52462
52583
  process.exit(1);
52463
52584
  }
52464
52585
  const domain = await getDomainDetails2(identifier);
52465
52586
  if (!domain) {
52466
- console.error(`Domain '${identifier}' not found.`);
52587
+ printErrorLine(`Domain '${identifier}' not found.`);
52467
52588
  process.exit(1);
52468
52589
  }
52469
52590
  const deleted = await deleteHistoryByDomain2(domain.domain.id);
52470
52591
  if (!deleted) {
52471
- console.error(`No history to purge for ${domain.domain.name}.`);
52592
+ printErrorLine(`No history to purge for ${domain.domain.name}.`);
52472
52593
  process.exit(1);
52473
52594
  }
52474
- console.log(`Purged all history for ${domain.domain.name}`);
52595
+ printLine(`Purged all history for ${domain.domain.name}`);
52475
52596
  });
52476
52597
  }
52477
52598
  var init_history2 = __esm(() => {
52478
52599
  init_history();
52479
52600
  init_domains();
52601
+ init_stdout();
52480
52602
  });
52481
52603
 
52482
52604
  // src/db/domain-research.ts
@@ -52643,13 +52765,13 @@ function registerResearchCommand(program2) {
52643
52765
  research.command("exa <identifier>").description("Research a domain using Exa AI (ownership, company info, history)").option("--limit <n>", "Limit number of displayed web/company results").option("--all", "Show all returned research results").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
52644
52766
  const domain = await getDomainDetails2(identifier);
52645
52767
  if (!domain) {
52646
- console.error(`Domain '${identifier}' not found.`);
52768
+ printErrorLine(`Domain '${identifier}' not found.`);
52647
52769
  process.exit(1);
52648
52770
  }
52649
52771
  try {
52650
52772
  const result = await researchDomain(domain.domain.name);
52651
52773
  if (opts.json) {
52652
- console.log(JSON.stringify({
52774
+ printLine(JSON.stringify({
52653
52775
  domain: result.domain,
52654
52776
  summary: result.summary,
52655
52777
  results: result.results.map((r4) => ({ title: r4.title, url: r4.url, score: r4.score })),
@@ -52658,124 +52780,124 @@ function registerResearchCommand(program2) {
52658
52780
  }, null, 2));
52659
52781
  return;
52660
52782
  }
52661
- console.log(`Exa Research for ${result.domain}:`);
52783
+ printLine(`Exa Research for ${result.domain}:`);
52662
52784
  if (result.summary)
52663
- console.log(`
52785
+ printLine(`
52664
52786
  Summary: ${truncateText(result.summary, 240)}`);
52665
52787
  if (result.results.length > 0) {
52666
52788
  const page = pageItemsOrExit(result.results, { limit: opts.limit, all: opts.all });
52667
- console.log(`
52789
+ printLine(`
52668
52790
  Web Results:`);
52669
52791
  for (const r4 of page.items) {
52670
- console.log(` - ${truncateText(r4.title, 100)} (${r4.score.toFixed(2)})`);
52671
- console.log(` ${r4.url}`);
52792
+ printLine(` - ${truncateText(r4.title, 100)} (${r4.score.toFixed(2)})`);
52793
+ printLine(` ${r4.url}`);
52672
52794
  }
52673
- console.log(` ${compactHint(page, "web result(s)", "Use --all for every result or --json for structured output.", { paging: "limit" })}`);
52795
+ printLine(` ${compactHint(page, "web result(s)", "Use --all for every result or --json for structured output.", { paging: "limit" })}`);
52674
52796
  }
52675
52797
  if (result.companies.length > 0) {
52676
52798
  const page = pageItemsOrExit(result.companies, { limit: opts.limit, all: opts.all });
52677
- console.log(`
52799
+ printLine(`
52678
52800
  Companies:`);
52679
52801
  for (const c4 of page.items) {
52680
- console.log(` - ${c4.name}: ${c4.domain}`);
52802
+ printLine(` - ${c4.name}: ${c4.domain}`);
52681
52803
  }
52682
- console.log(` ${compactHint(page, "company result(s)", "Use --all for every company or --json for structured output.", { paging: "limit" })}`);
52804
+ printLine(` ${compactHint(page, "company result(s)", "Use --all for every company or --json for structured output.", { paging: "limit" })}`);
52683
52805
  }
52684
52806
  if (result.savedHistory) {
52685
- console.log(`
52807
+ printLine(`
52686
52808
  Saved to history: ${result.savedHistory.id}`);
52687
52809
  }
52688
- console.log();
52810
+ printLine();
52689
52811
  } catch (error) {
52690
- console.error(`Research failed: ${error instanceof Error ? error.message : String(error)}`);
52812
+ printErrorLine(`Research failed: ${error instanceof Error ? error.message : String(error)}`);
52691
52813
  process.exit(1);
52692
52814
  }
52693
52815
  });
52694
52816
  research.command("answer <identifier> <question>").description("Ask a specific question about a domain using Exa AI").option("-j, --json", "Output JSON").action(async (identifier, question, opts) => {
52695
52817
  const domain = await getDomainDetails2(identifier);
52696
52818
  if (!domain) {
52697
- console.error(`Domain '${identifier}' not found.`);
52819
+ printErrorLine(`Domain '${identifier}' not found.`);
52698
52820
  process.exit(1);
52699
52821
  }
52700
52822
  try {
52701
52823
  const answer = await answerAboutDomain(domain.domain.name, question);
52702
52824
  if (opts.json) {
52703
- console.log(JSON.stringify({ domain: domain.domain.name, question, answer }, null, 2));
52825
+ printLine(JSON.stringify({ domain: domain.domain.name, question, answer }, null, 2));
52704
52826
  return;
52705
52827
  }
52706
52828
  if (!answer) {
52707
- console.log("No answer found.");
52829
+ printLine("No answer found.");
52708
52830
  return;
52709
52831
  }
52710
- console.log(`Q: ${question}`);
52711
- console.log(`A: ${answer}`);
52832
+ printLine(`Q: ${question}`);
52833
+ printLine(`A: ${answer}`);
52712
52834
  } catch (error) {
52713
- console.error(`Answer failed: ${error instanceof Error ? error.message : String(error)}`);
52835
+ printErrorLine(`Answer failed: ${error instanceof Error ? error.message : String(error)}`);
52714
52836
  process.exit(1);
52715
52837
  }
52716
52838
  });
52717
52839
  research.command("reputation <identifier>").description("Check domain reputation and blacklist status").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
52718
52840
  const domain = await getDomainDetails2(identifier);
52719
52841
  if (!domain) {
52720
- console.error(`Domain '${identifier}' not found.`);
52842
+ printErrorLine(`Domain '${identifier}' not found.`);
52721
52843
  process.exit(1);
52722
52844
  }
52723
52845
  const { reputation, dnsBlacklist } = await checkDomainReputation(domain.domain.name);
52724
52846
  if (opts.json) {
52725
- console.log(JSON.stringify({ domain: domain.domain.name, reputation, dnsBlacklist }, null, 2));
52847
+ printLine(JSON.stringify({ domain: domain.domain.name, reputation, dnsBlacklist }, null, 2));
52726
52848
  return;
52727
52849
  }
52728
- console.log(`Reputation for ${domain.domain.name}:`);
52850
+ printLine(`Reputation for ${domain.domain.name}:`);
52729
52851
  if (reputation) {
52730
- console.log(` Blacklisted: ${reputation.is_blacklisted ? "yes" : "no"}`);
52852
+ printLine(` Blacklisted: ${reputation.is_blacklisted ? "yes" : "no"}`);
52731
52853
  if (reputation.threat_score !== null)
52732
- console.log(` Threat Score: ${reputation.threat_score}`);
52854
+ printLine(` Threat Score: ${reputation.threat_score}`);
52733
52855
  if (reputation.spam_score !== null)
52734
- console.log(` Spam Score: ${reputation.spam_score}`);
52735
- console.log(` Malware: ${reputation.malware_detected ? "detected" : "clean"}`);
52736
- console.log(` Phishing: ${reputation.phishing_detected ? "detected" : "clean"}`);
52856
+ printLine(` Spam Score: ${reputation.spam_score}`);
52857
+ printLine(` Malware: ${reputation.malware_detected ? "detected" : "clean"}`);
52858
+ printLine(` Phishing: ${reputation.phishing_detected ? "detected" : "clean"}`);
52737
52859
  if (reputation.last_checked_at)
52738
- console.log(` Last Checked: ${reputation.last_checked_at}`);
52860
+ printLine(` Last Checked: ${reputation.last_checked_at}`);
52739
52861
  } else {
52740
- console.log(" No reputation data yet.");
52862
+ printLine(" No reputation data yet.");
52741
52863
  }
52742
- console.log(` DNS Blacklist: ${dnsBlacklist.listed ? `listed in ${dnsBlacklist.zones.join(", ")}` : "clean"}`);
52864
+ printLine(` DNS Blacklist: ${dnsBlacklist.listed ? `listed in ${dnsBlacklist.zones.join(", ")}` : "clean"}`);
52743
52865
  });
52744
52866
  research.command("blacklisted").description("List all blacklisted domains in the database").option("--limit <n>", "Limit number of displayed domains").option("--all", "Show all blacklisted domains").option("-j, --json", "Output JSON").action(async (opts) => {
52745
52867
  const domains = await listBlacklistedDomains2();
52746
52868
  if (opts.json) {
52747
- console.log(JSON.stringify({ domains, count: domains.length }, null, 2));
52869
+ printLine(JSON.stringify({ domains, count: domains.length }, null, 2));
52748
52870
  return;
52749
52871
  }
52750
52872
  if (domains.length === 0) {
52751
- console.log("No blacklisted domains.");
52873
+ printLine("No blacklisted domains.");
52752
52874
  return;
52753
52875
  }
52754
52876
  const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
52755
- console.log("Blacklisted domains:");
52877
+ printLine("Blacklisted domains:");
52756
52878
  for (const d4 of page.items) {
52757
- console.log(` domain_id: ${d4.domain_id} (sources: ${truncateText(d4.blacklist_sources.join(", "), 100)})`);
52879
+ printLine(` domain_id: ${d4.domain_id} (sources: ${truncateText(d4.blacklist_sources.join(", "), 100)})`);
52758
52880
  }
52759
- console.log(`
52881
+ printLine(`
52760
52882
  ${compactHint(page, "blacklisted domain(s)", "Use --all for every domain or --json for full source arrays.", { paging: "limit" })}`);
52761
52883
  });
52762
52884
  research.command("threats").description("List domains with high threat scores").option("--threshold <n>", "Minimum threat score", "70").option("--limit <n>", "Limit number of displayed domains").option("--all", "Show all matching domains").option("-j, --json", "Output JSON").action(async (opts) => {
52763
52885
  const threshold = parseInt(opts.threshold ?? "70");
52764
52886
  const domains = await listHighThreatDomains2(threshold);
52765
52887
  if (opts.json) {
52766
- console.log(JSON.stringify({ domains, threshold, count: domains.length }, null, 2));
52888
+ printLine(JSON.stringify({ domains, threshold, count: domains.length }, null, 2));
52767
52889
  return;
52768
52890
  }
52769
52891
  if (domains.length === 0) {
52770
- console.log(`No domains with threat score >= ${threshold}.`);
52892
+ printLine(`No domains with threat score >= ${threshold}.`);
52771
52893
  return;
52772
52894
  }
52773
52895
  const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
52774
- console.log(`Domains with threat score >= ${threshold}:`);
52896
+ printLine(`Domains with threat score >= ${threshold}:`);
52775
52897
  for (const d4 of page.items) {
52776
- console.log(` domain_id: ${d4.domain_id} \u2014 score: ${d4.threat_score ?? "?"}`);
52898
+ printLine(` domain_id: ${d4.domain_id} \u2014 score: ${d4.threat_score ?? "?"}`);
52777
52899
  }
52778
- console.log(`
52900
+ printLine(`
52779
52901
  ${compactHint(page, "domain(s)", "Use --all for every domain or --json for full reputation records.", { paging: "limit" })}`);
52780
52902
  });
52781
52903
  }
@@ -52783,6 +52905,7 @@ var init_research = __esm(() => {
52783
52905
  init_domain_research();
52784
52906
  init_domains();
52785
52907
  init_reputation();
52908
+ init_stdout();
52786
52909
  });
52787
52910
 
52788
52911
  // src/cli/commands/outreach.ts
@@ -52795,7 +52918,7 @@ import { promisify as promisify3 } from "util";
52795
52918
  async function requireDomainOwner(identifier) {
52796
52919
  const owner = await getDomainOwnerByDomainName2(identifier);
52797
52920
  if (!owner) {
52798
- console.error(`No owner info found for '${identifier}'.`);
52921
+ printErrorLine(`No owner info found for '${identifier}'.`);
52799
52922
  process.exit(1);
52800
52923
  }
52801
52924
  return owner;
@@ -52805,7 +52928,7 @@ function registerOutreachCommand(program2) {
52805
52928
  outreach.command("sms <identifier>").description("Send SMS to a domain owner").requiredOption("--message <text>", "SMS message body").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
52806
52929
  const owner = await requireDomainOwner(identifier);
52807
52930
  if (!owner.owner_phone) {
52808
- console.error(`No phone number for '${identifier}'.`);
52931
+ printErrorLine(`No phone number for '${identifier}'.`);
52809
52932
  process.exit(1);
52810
52933
  }
52811
52934
  try {
@@ -52821,20 +52944,20 @@ function registerOutreachCommand(program2) {
52821
52944
  ], { encoding: "utf-8" });
52822
52945
  const result = JSON.parse(stdout);
52823
52946
  if (opts.json) {
52824
- console.log(JSON.stringify({ domain: identifier, to: owner.owner_phone, result }, null, 2));
52947
+ printLine(JSON.stringify({ domain: identifier, to: owner.owner_phone, result }, null, 2));
52825
52948
  } else {
52826
- console.log(`SMS sent to ${owner.owner_name ?? owner.owner_email} (${owner.owner_phone}): "${opts.message}"`);
52949
+ printLine(`SMS sent to ${owner.owner_name ?? owner.owner_email} (${owner.owner_phone}): "${opts.message}"`);
52827
52950
  }
52828
52951
  } catch (error) {
52829
52952
  const msg = error instanceof Error ? error.message : String(error);
52830
- console.error(`SMS send failed: ${msg}`);
52953
+ printErrorLine(`SMS send failed: ${msg}`);
52831
52954
  process.exit(1);
52832
52955
  }
52833
52956
  });
52834
52957
  outreach.command("whatsapp <identifier>").description("Send WhatsApp message to a domain owner").requiredOption("--message <text>", "Message body").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
52835
52958
  const owner = await requireDomainOwner(identifier);
52836
52959
  if (!owner.owner_phone) {
52837
- console.error(`No phone number for '${identifier}'.`);
52960
+ printErrorLine(`No phone number for '${identifier}'.`);
52838
52961
  process.exit(1);
52839
52962
  }
52840
52963
  try {
@@ -52850,20 +52973,20 @@ function registerOutreachCommand(program2) {
52850
52973
  ], { encoding: "utf-8" });
52851
52974
  const result = JSON.parse(stdout);
52852
52975
  if (opts.json) {
52853
- console.log(JSON.stringify({ domain: identifier, to: owner.owner_phone, result }, null, 2));
52976
+ printLine(JSON.stringify({ domain: identifier, to: owner.owner_phone, result }, null, 2));
52854
52977
  } else {
52855
- console.log(`WhatsApp sent to ${owner.owner_name ?? owner.owner_email} (${owner.owner_phone}): "${opts.message}"`);
52978
+ printLine(`WhatsApp sent to ${owner.owner_name ?? owner.owner_email} (${owner.owner_phone}): "${opts.message}"`);
52856
52979
  }
52857
52980
  } catch (error) {
52858
52981
  const msg = error instanceof Error ? error.message : String(error);
52859
- console.error(`WhatsApp send failed: ${msg}`);
52982
+ printErrorLine(`WhatsApp send failed: ${msg}`);
52860
52983
  process.exit(1);
52861
52984
  }
52862
52985
  });
52863
52986
  outreach.command("email <identifier>").description("Send email to a domain owner").requiredOption("--subject <text>", "Email subject").requiredOption("--body <text>", "Email body (plain text)").option("--template <name>", "Use a template by name instead of --body").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
52864
52987
  const owner = await requireDomainOwner(identifier);
52865
52988
  if (!owner.owner_email) {
52866
- console.error(`No email for '${identifier}'.`);
52989
+ printErrorLine(`No email for '${identifier}'.`);
52867
52990
  process.exit(1);
52868
52991
  }
52869
52992
  try {
@@ -52881,13 +53004,13 @@ function registerOutreachCommand(program2) {
52881
53004
  ], { encoding: "utf-8" });
52882
53005
  const result = JSON.parse(stdout);
52883
53006
  if (opts.json) {
52884
- console.log(JSON.stringify({ domain: identifier, to: owner.owner_email, result }, null, 2));
53007
+ printLine(JSON.stringify({ domain: identifier, to: owner.owner_email, result }, null, 2));
52885
53008
  } else {
52886
- console.log(`Email sent to ${owner.owner_name ?? owner.owner_email} (${owner.owner_email}): "${opts.subject}"`);
53009
+ printLine(`Email sent to ${owner.owner_name ?? owner.owner_email} (${owner.owner_email}): "${opts.subject}"`);
52887
53010
  }
52888
53011
  } catch (error) {
52889
53012
  const msg = error instanceof Error ? error.message : String(error);
52890
- console.error(`Email send failed: ${msg}`);
53013
+ printErrorLine(`Email send failed: ${msg}`);
52891
53014
  process.exit(1);
52892
53015
  }
52893
53016
  });
@@ -52895,6 +53018,7 @@ function registerOutreachCommand(program2) {
52895
53018
  var execFileAsync2;
52896
53019
  var init_outreach = __esm(() => {
52897
53020
  init_owners();
53021
+ init_stdout();
52898
53022
  execFileAsync2 = promisify3(execFile2);
52899
53023
  });
52900
53024
 
@@ -52934,22 +53058,22 @@ function registerWalletCommand(program2) {
52934
53058
  try {
52935
53059
  const cards = await getAvailableCards();
52936
53060
  if (opts.json) {
52937
- console.log(JSON.stringify(cards, null, 2));
53061
+ printLine(JSON.stringify(cards, null, 2));
52938
53062
  } else {
52939
53063
  if (cards.length === 0) {
52940
- console.log("No active wallet cards found.");
53064
+ printLine("No active wallet cards found.");
52941
53065
  return;
52942
53066
  }
52943
53067
  const page = pageItemsOrExit(cards, { limit: opts.limit, all: opts.all });
52944
- console.log("Available wallet cards:");
53068
+ printLine("Available wallet cards:");
52945
53069
  for (const c4 of page.items) {
52946
- console.log(` ${c4.brand} \u2022\u2022\u2022\u2022 ${c4.last_four} \u2014 ${c4.name} (${c4.balance} ${c4.currency})`);
53070
+ printLine(` ${c4.brand} \u2022\u2022\u2022\u2022 ${c4.last_four} \u2014 ${c4.name} (${c4.balance} ${c4.currency})`);
52947
53071
  }
52948
- console.log(`
53072
+ printLine(`
52949
53073
  ${compactHint(page, "card(s)", "Use --all for every card or --json for full card fields.", { paging: "limit" })}`);
52950
53074
  }
52951
53075
  } catch (error) {
52952
- console.error(`Failed to list cards: ${error instanceof Error ? error.message : String(error)}`);
53076
+ printErrorLine(`Failed to list cards: ${error instanceof Error ? error.message : String(error)}`);
52953
53077
  process.exit(1);
52954
53078
  }
52955
53079
  });
@@ -52961,15 +53085,15 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
52961
53085
  if (!cardId) {
52962
53086
  const cards = await getAvailableCards();
52963
53087
  if (cards.length === 0) {
52964
- console.error("No active wallet cards found. Add a card first.");
53088
+ printErrorLine("No active wallet cards found. Add a card first.");
52965
53089
  process.exit(1);
52966
53090
  }
52967
53091
  if (cards.length === 1) {
52968
53092
  cardId = cards[0].external_id;
52969
53093
  } else {
52970
- console.error("Multiple cards available. Specify --card-id:");
53094
+ printErrorLine("Multiple cards available. Specify --card-id:");
52971
53095
  for (const c4 of cards) {
52972
- console.log(` ${c4.id}: ${c4.brand} \u2022\u2022\u2022\u2022 ${c4.last_four} (${c4.balance} ${c4.currency})`);
53096
+ printLine(` ${c4.id}: ${c4.brand} \u2022\u2022\u2022\u2022 ${c4.last_four} (${c4.balance} ${c4.currency})`);
52973
53097
  }
52974
53098
  process.exit(1);
52975
53099
  }
@@ -52977,16 +53101,16 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
52977
53101
  const wallets = getWalletsModule();
52978
53102
  const card = wallets.getCard(cardId);
52979
53103
  if (!card) {
52980
- console.error(`Card '${cardId}' not found.`);
53104
+ printErrorLine(`Card '${cardId}' not found.`);
52981
53105
  process.exit(1);
52982
53106
  }
52983
53107
  if (card.balance < price) {
52984
- console.error(`Insufficient funds: need ${price} ${currency}, have ${card.balance} ${card.currency}`);
53108
+ printErrorLine(`Insufficient funds: need ${price} ${currency}, have ${card.balance} ${card.currency}`);
52985
53109
  process.exit(1);
52986
53110
  }
52987
53111
  const existing = await getDomainByName2(name);
52988
53112
  if (existing) {
52989
- console.error(`Domain '${name}' already exists in portfolio.`);
53113
+ printErrorLine(`Domain '${name}' already exists in portfolio.`);
52990
53114
  process.exit(1);
52991
53115
  }
52992
53116
  const domain = await createDomain2({
@@ -53010,13 +53134,13 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
53010
53134
  notes: `Purchased ${name} for ${price} ${currency} via wallet card ${cardId}`
53011
53135
  });
53012
53136
  if (opts.json) {
53013
- console.log(JSON.stringify({ domain, card_id: cardId, price, currency }, null, 2));
53137
+ printLine(JSON.stringify({ domain, card_id: cardId, price, currency }, null, 2));
53014
53138
  } else {
53015
- console.log(`Purchased ${name} for ${price} ${currency} via wallet card`);
53016
- console.log(` Added to portfolio as ${domain.id}`);
53139
+ printLine(`Purchased ${name} for ${price} ${currency} via wallet card`);
53140
+ printLine(` Added to portfolio as ${domain.id}`);
53017
53141
  }
53018
53142
  } catch (error) {
53019
- console.error(`Wallet purchase failed: ${error instanceof Error ? error.message : String(error)}`);
53143
+ printErrorLine(`Wallet purchase failed: ${error instanceof Error ? error.message : String(error)}`);
53020
53144
  process.exit(1);
53021
53145
  }
53022
53146
  });
@@ -53024,7 +53148,7 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
53024
53148
  const price = parseFloat(opts.price);
53025
53149
  const domain = await getDomainByName2(name);
53026
53150
  if (!domain) {
53027
- console.error(`Domain '${name}' not found in portfolio.`);
53151
+ printErrorLine(`Domain '${name}' not found in portfolio.`);
53028
53152
  process.exit(1);
53029
53153
  }
53030
53154
  try {
@@ -53032,7 +53156,7 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
53032
53156
  if (!cardId) {
53033
53157
  const cards = await getAvailableCards();
53034
53158
  if (cards.length === 0) {
53035
- console.error("No active wallet cards found.");
53159
+ printErrorLine("No active wallet cards found.");
53036
53160
  process.exit(1);
53037
53161
  }
53038
53162
  cardId = cards[0].external_id;
@@ -53040,11 +53164,11 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
53040
53164
  const wallets = getWalletsModule();
53041
53165
  const card = wallets.getCard(cardId);
53042
53166
  if (!card) {
53043
- console.error(`Card '${cardId}' not found.`);
53167
+ printErrorLine(`Card '${cardId}' not found.`);
53044
53168
  process.exit(1);
53045
53169
  }
53046
53170
  if (card.balance < price) {
53047
- console.error(`Insufficient funds: need ${price} ${opts.currency}, have ${card.balance} ${card.currency}`);
53171
+ printErrorLine(`Insufficient funds: need ${price} ${opts.currency}, have ${card.balance} ${card.currency}`);
53048
53172
  process.exit(1);
53049
53173
  }
53050
53174
  await createHistoryEntry2({
@@ -53060,13 +53184,13 @@ ${compactHint(page, "card(s)", "Use --all for every card or --json for full card
53060
53184
  purchase_price: price
53061
53185
  });
53062
53186
  if (opts.json) {
53063
- console.log(JSON.stringify({ domain: name, card_id: cardId, price, new_expiry: expiryDate.toISOString() }, null, 2));
53187
+ printLine(JSON.stringify({ domain: name, card_id: cardId, price, new_expiry: expiryDate.toISOString() }, null, 2));
53064
53188
  } else {
53065
- console.log(`Renewed ${name} for ${price} ${opts.currency} via wallet card`);
53066
- console.log(` New expiry: ${expiryDate.toISOString().split("T")[0]}`);
53189
+ printLine(`Renewed ${name} for ${price} ${opts.currency} via wallet card`);
53190
+ printLine(` New expiry: ${expiryDate.toISOString().split("T")[0]}`);
53067
53191
  }
53068
53192
  } catch (error) {
53069
- console.error(`Wallet renewal failed: ${error instanceof Error ? error.message : String(error)}`);
53193
+ printErrorLine(`Wallet renewal failed: ${error instanceof Error ? error.message : String(error)}`);
53070
53194
  process.exit(1);
53071
53195
  }
53072
53196
  });
@@ -53075,6 +53199,7 @@ var WALLET_MODULE_ENV = "DOMAINS_WALLET_MODULE";
53075
53199
  var init_wallet = __esm(() => {
53076
53200
  init_domains();
53077
53201
  init_history();
53202
+ init_stdout();
53078
53203
  });
53079
53204
 
53080
53205
  // src/lib/provision-state.ts
@@ -53249,23 +53374,23 @@ function registerProvisionCommand(program2) {
53249
53374
  signals["publicNsAreCloudflare"] = false;
53250
53375
  }
53251
53376
  } catch (e4) {
53252
- console.error(`Error gathering signals: ${e4 instanceof Error ? e4.message : String(e4)}`);
53377
+ printErrorLine(`Error gathering signals: ${e4 instanceof Error ? e4.message : String(e4)}`);
53253
53378
  }
53254
53379
  const state = deriveDomainState(signals);
53255
- console.log(`
53380
+ printLine(`
53256
53381
  Domain: ${name}`);
53257
- console.log(`State: ${state}`);
53258
- console.log(`Signals: ${JSON.stringify(signals)}`);
53382
+ printLine(`State: ${state}`);
53383
+ printLine(`Signals: ${JSON.stringify(signals)}`);
53259
53384
  const path = domainHappyPath();
53260
53385
  const idx = path.indexOf(state);
53261
- console.log(`Progress: ${idx >= 0 ? idx + 1 : "?"}/${path.length} [${path.join(" \u2192 ")}]`);
53386
+ printLine(`Progress: ${idx >= 0 ? idx + 1 : "?"}/${path.length} [${path.join(" \u2192 ")}]`);
53262
53387
  });
53263
53388
  provision.command("daemon").description("Reconcile domains toward ready (CF zone + NS delegation + propagation)").option("--domains <list>", "Comma-separated domains (default: all active in the portfolio)").option("--once", "Run a single reconcile tick and exit").option("--interval <sec>", "Seconds between ticks", "30").option("--max-ticks <n>", "Stop after N ticks").action(async (opts) => {
53264
53389
  const { applyPurchaseProfile: applyPurchaseProfile2 } = await Promise.resolve().then(() => (init_config(), exports_config));
53265
53390
  applyPurchaseProfile2();
53266
53391
  const { makeDomainDaemonDeps: makeDomainDaemonDeps2 } = await Promise.resolve().then(() => (init_domain_daemon_deps(), exports_domain_daemon_deps));
53267
53392
  const { reconcileDomainTick: reconcileDomainTick2, runDomainDaemon: runDomainDaemon2 } = await Promise.resolve().then(() => (init_domain_daemon(), exports_domain_daemon));
53268
- const deps = { ...makeDomainDaemonDeps2(), log: (e4, d4) => console.log(`[${e4}] ${JSON.stringify(d4)}`) };
53393
+ const deps = { ...makeDomainDaemonDeps2(), log: (e4, d4) => printLine(`[${e4}] ${JSON.stringify(d4)}`) };
53269
53394
  const listDomains4 = async () => {
53270
53395
  if (opts.domains)
53271
53396
  return opts.domains.split(",").map((d4) => d4.trim());
@@ -53274,16 +53399,16 @@ Domain: ${name}`);
53274
53399
  };
53275
53400
  if (opts.once) {
53276
53401
  const s2 = await reconcileDomainTick2(await listDomains4(), deps);
53277
- console.log(`\u2713 tick: ${s2.advanced} advanced, ${s2.ready} ready, ${s2.errors} errors (${s2.processed} processed)`);
53402
+ printLine(`\u2713 tick: ${s2.advanced} advanced, ${s2.ready} ready, ${s2.errors} errors (${s2.processed} processed)`);
53278
53403
  return;
53279
53404
  }
53280
- console.log(`Domain provisioning daemon started (interval ${opts.interval}s). Ctrl-C to stop.`);
53405
+ printLine(`Domain provisioning daemon started (interval ${opts.interval}s). Ctrl-C to stop.`);
53281
53406
  const total = await runDomainDaemon2(listDomains4, {
53282
53407
  ...deps,
53283
53408
  intervalSec: parseInt(opts.interval, 10),
53284
53409
  maxTicks: opts.maxTicks ? parseInt(opts.maxTicks, 10) : undefined
53285
53410
  });
53286
- console.log(`daemon stopped: ${total.advanced} advanced, ${total.ready} ready, ${total.errors} errors`);
53411
+ printLine(`daemon stopped: ${total.advanced} advanced, ${total.ready} ready, ${total.errors} errors`);
53287
53412
  });
53288
53413
  }
53289
53414
  var CF_NS_SUFFIX2 = ".ns.cloudflare.com";
@@ -53291,6 +53416,7 @@ var init_provision = __esm(() => {
53291
53416
  init_provision_state();
53292
53417
  init_route53();
53293
53418
  init_cloudflare();
53419
+ init_stdout();
53294
53420
  });
53295
53421
 
53296
53422
  // src/cli/tui/format.ts
@@ -54012,10 +54138,12 @@ __export(exports_interactive, {
54012
54138
  import chalk from "chalk";
54013
54139
  import { render } from "ink";
54014
54140
  import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
54015
- function assertInteractiveTty() {
54141
+ function assertInteractiveTty(emit = (line) => {
54142
+ printErrorLine(line);
54143
+ }) {
54016
54144
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
54017
- console.error(chalk.red("Interactive mode requires a TTY terminal."));
54018
- console.error(chalk.dim("Use `domains domain list` or `domains domain get <name>` for non-interactive use."));
54145
+ emit(chalk.red("Interactive mode requires a TTY terminal."));
54146
+ emit(chalk.dim("Use `domains domain list` or `domains domain get <name>` for non-interactive use."));
54019
54147
  process.exit(1);
54020
54148
  }
54021
54149
  }
@@ -54029,6 +54157,7 @@ function registerInteractiveCommand(program2) {
54029
54157
  }
54030
54158
  var init_interactive = __esm(() => {
54031
54159
  init_App();
54160
+ init_stdout();
54032
54161
  });
54033
54162
 
54034
54163
  // node_modules/@hasna/events/dist/commander.js
@@ -55589,6 +55718,7 @@ function getCapability(name) {
55589
55718
  }
55590
55719
 
55591
55720
  // src/cli/commands/domain.ts
55721
+ init_stdout();
55592
55722
  var DOMAIN_STATUS_HELP = DOMAIN_STATUSES.join("/");
55593
55723
  var DOMAIN_OFFER_STATUS_HELP = DOMAIN_OFFER_STATUSES.join("/");
55594
55724
  var DOMAIN_EMAIL_TYPE_HELP = DOMAIN_EMAIL_TYPES.join("/");
@@ -55615,7 +55745,7 @@ async function createDnsZoneForProvider(domain, provider) {
55615
55745
  async function requireDomain(identifier) {
55616
55746
  const details = await getDomainDetails2(identifier);
55617
55747
  if (!details) {
55618
- console.error(`Domain '${identifier}' not found.`);
55748
+ printErrorLine(`Domain '${identifier}' not found.`);
55619
55749
  process.exit(1);
55620
55750
  }
55621
55751
  return details;
@@ -55631,7 +55761,7 @@ function registerDomainCommand(program2) {
55631
55761
  jsonLimit = opts.limit === undefined ? undefined : parseLimit(opts.limit, undefined, Infinity);
55632
55762
  offset = parseOffset(opts.offset);
55633
55763
  } catch (error) {
55634
- console.error(error instanceof Error ? error.message : String(error));
55764
+ printErrorLine(error instanceof Error ? error.message : String(error));
55635
55765
  process.exit(1);
55636
55766
  }
55637
55767
  const filters = {
@@ -55648,7 +55778,7 @@ function registerDomainCommand(program2) {
55648
55778
  fallbackLimit: Infinity,
55649
55779
  maxLimit: Infinity
55650
55780
  });
55651
- console.log(JSON.stringify({
55781
+ printLine(JSON.stringify({
55652
55782
  domains: jsonPage.items,
55653
55783
  count: jsonPage.shown,
55654
55784
  total: jsonPage.total,
@@ -55661,7 +55791,7 @@ function registerDomainCommand(program2) {
55661
55791
  }
55662
55792
  const page = pageItemsOrExit(domains, { limit, offset, all: opts.all });
55663
55793
  if (page.items.length === 0) {
55664
- console.log("No domains found.");
55794
+ printLine("No domains found.");
55665
55795
  return;
55666
55796
  }
55667
55797
  for (const d4 of page.items) {
@@ -55670,47 +55800,47 @@ function registerDomainCommand(program2) {
55670
55800
  if (opts.verbose) {
55671
55801
  const registrar = d4.registrar ? ` reg:${truncateText(d4.registrar, 24)}` : "";
55672
55802
  const notes = d4.notes ? ` notes:${truncateText(d4.notes, 60)}` : "";
55673
- console.log(` ${d4.name} [${d4.status}]${registrar}${exp}${premium}${notes}`);
55803
+ printLine(` ${d4.name} [${d4.status}]${registrar}${exp}${premium}${notes}`);
55674
55804
  } else {
55675
- console.log(` ${d4.name} [${d4.status}]${exp}${premium}`);
55805
+ printLine(` ${d4.name} [${d4.status}]${exp}${premium}`);
55676
55806
  }
55677
55807
  }
55678
- console.log(`
55808
+ printLine(`
55679
55809
  ${compactHint(page, "domain(s)", "Use --verbose for registrar/notes or domain get <id|name> for details.")}`);
55680
55810
  });
55681
55811
  domain.command("get <identifier>").description("Get a domain by ID or name").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
55682
55812
  const details = await getDomainDetails2(identifier);
55683
55813
  if (!details) {
55684
- console.error(`Domain '${identifier}' not found.`);
55814
+ printErrorLine(`Domain '${identifier}' not found.`);
55685
55815
  process.exit(1);
55686
55816
  }
55687
55817
  if (opts.json) {
55688
- console.log(JSON.stringify(details, null, 2));
55818
+ printLine(JSON.stringify(details, null, 2));
55689
55819
  return;
55690
55820
  }
55691
55821
  const d4 = details.domain;
55692
- console.log(`
55822
+ printLine(`
55693
55823
  ${d4.name} [${d4.status}]`);
55694
55824
  if (d4.registrar)
55695
- console.log(` Registrar: ${d4.registrar}`);
55825
+ printLine(` Registrar: ${d4.registrar}`);
55696
55826
  if (d4.expires_at)
55697
- console.log(` Expires: ${formatDate(d4.expires_at)}`);
55827
+ printLine(` Expires: ${formatDate(d4.expires_at)}`);
55698
55828
  if (d4.purchase_date)
55699
- console.log(` Purchased: ${formatDate(d4.purchase_date)}`);
55829
+ printLine(` Purchased: ${formatDate(d4.purchase_date)}`);
55700
55830
  if (d4.purchase_price !== null)
55701
- console.log(` Purchase price: ${d4.purchase_price}`);
55702
- console.log(` Auto-renew: ${d4.auto_renew ? "yes" : "no"}`);
55831
+ printLine(` Purchase price: ${d4.purchase_price}`);
55832
+ printLine(` Auto-renew: ${d4.auto_renew ? "yes" : "no"}`);
55703
55833
  if (d4.is_premium) {
55704
- console.log(` Premium: yes`);
55834
+ printLine(` Premium: yes`);
55705
55835
  if (d4.premium_price !== null)
55706
- console.log(` Premium ask: ${d4.premium_price}`);
55836
+ printLine(` Premium ask: ${d4.premium_price}`);
55707
55837
  }
55708
55838
  if (d4.standard_price !== null)
55709
- console.log(` Standard price: ${d4.standard_price}`);
55839
+ printLine(` Standard price: ${d4.standard_price}`);
55710
55840
  if (d4.notes)
55711
- console.log(` Notes: ${truncateText(d4.notes, 160)}`);
55841
+ printLine(` Notes: ${truncateText(d4.notes, 160)}`);
55712
55842
  if (details.offers.length > 0) {
55713
- console.log(`
55843
+ printLine(`
55714
55844
  Offers:`);
55715
55845
  const offerPage = pageItemsOrExit(details.offers, { fallbackLimit: 5 });
55716
55846
  for (const offer of offerPage.items) {
@@ -55721,23 +55851,23 @@ Offers:`);
55721
55851
  offer.their_ask !== null ? `their=${offer.their_ask}` : null,
55722
55852
  offer.notes
55723
55853
  ].filter(Boolean);
55724
- console.log(` - ${parts.join(" | ")}`);
55854
+ printLine(` - ${parts.join(" | ")}`);
55725
55855
  }
55726
55856
  if (offerPage.hasMore)
55727
- console.log(` ${compactHint(offerPage, "offer(s)", "Use --json for the full offer history.", { paging: "none" })}`);
55857
+ printLine(` ${compactHint(offerPage, "offer(s)", "Use --json for the full offer history.", { paging: "none" })}`);
55728
55858
  }
55729
55859
  if (details.emails.length > 0) {
55730
- console.log(`
55860
+ printLine(`
55731
55861
  Emails:`);
55732
55862
  const emailPage = pageItemsOrExit(details.emails, { fallbackLimit: 5 });
55733
55863
  for (const email of emailPage.items) {
55734
55864
  const threadPart = email.thread_id ? ` thread=${email.thread_id}` : "";
55735
- console.log(` - ${email.type}: ${email.email_id}${threadPart}`);
55865
+ printLine(` - ${email.type}: ${email.email_id}${threadPart}`);
55736
55866
  }
55737
55867
  if (emailPage.hasMore)
55738
- console.log(` ${compactHint(emailPage, "email link(s)", "Use --json for the full email list.", { paging: "none" })}`);
55868
+ printLine(` ${compactHint(emailPage, "email link(s)", "Use --json for the full email list.", { paging: "none" })}`);
55739
55869
  }
55740
- console.log();
55870
+ printLine();
55741
55871
  });
55742
55872
  domain.command("add").description("Add a domain to the portfolio").requiredOption("--name <name>", "Domain name").option("--registrar <name>", "Registrar name").option("--status <s>", `Status (${DOMAIN_STATUS_HELP})`, "active").option("--expires <date>", "Expiry date (YYYY-MM-DD)").option("--premium", "Mark the domain as premium").option("--premium-price <price>", "Premium asking price").option("--standard-price <price>", "Standard registration price").option("--purchase-price <price>", "Acquisition price paid").option("--purchase-date <date>", "Purchase date (ISO or YYYY-MM-DD)").option("--notes <text>", "Notes").option("-j, --json", "Output JSON").action(async (opts) => {
55743
55873
  const premiumPrice = parseOptionalNumber(opts.premiumPrice, "--premium-price");
@@ -55756,10 +55886,10 @@ Emails:`);
55756
55886
  notes: opts.notes
55757
55887
  });
55758
55888
  if (opts.json) {
55759
- console.log(JSON.stringify(d4, null, 2));
55889
+ printLine(JSON.stringify(d4, null, 2));
55760
55890
  return;
55761
55891
  }
55762
- console.log(`Created domain: ${d4.name} (${d4.id})`);
55892
+ printLine(`Created domain: ${d4.name} (${d4.id})`);
55763
55893
  });
55764
55894
  domain.command("update <id>").description("Update a domain").option("--registrar <name>", "Registrar").option("--status <s>", `Status (${DOMAIN_STATUS_HELP})`).option("--expires <date>", "Expiry date").option("--premium <bool>", "Premium flag (true/false)").option("--premium-price <price>", "Premium asking price").option("--standard-price <price>", "Standard registration price").option("--purchase-price <price>", "Purchase price paid").option("--purchase-date <date>", "Purchase date").option("--notes <text>", "Notes").option("-j, --json", "Output JSON").action(async (id, opts) => {
55765
55895
  const premiumPrice = parseOptionalNumber(opts.premiumPrice, "--premium-price");
@@ -55777,23 +55907,23 @@ Emails:`);
55777
55907
  notes: opts.notes
55778
55908
  });
55779
55909
  if (!d4) {
55780
- console.error(`Domain '${id}' not found.`);
55910
+ printErrorLine(`Domain '${id}' not found.`);
55781
55911
  process.exit(1);
55782
55912
  }
55783
55913
  if (opts.json) {
55784
- console.log(JSON.stringify(d4, null, 2));
55914
+ printLine(JSON.stringify(d4, null, 2));
55785
55915
  return;
55786
55916
  }
55787
- console.log(`Updated: ${d4.name}`);
55917
+ printLine(`Updated: ${d4.name}`);
55788
55918
  });
55789
55919
  domain.command("delete <id>").description("Delete a domain from the portfolio").option("-f, --force", "Required confirmation for destructive delete").option("-j, --json", "Output JSON").action(async (id, opts) => {
55790
55920
  if (!opts.force) {
55791
55921
  const message = `Refusing to delete domain '${id}' without --force.`;
55792
55922
  if (opts.json) {
55793
- console.log(JSON.stringify({ deleted: false, id, error: message }, null, 2));
55923
+ printLine(JSON.stringify({ deleted: false, id, error: message }, null, 2));
55794
55924
  } else {
55795
- console.error(message);
55796
- console.error("Re-run with --force to confirm deletion.");
55925
+ printErrorLine(message);
55926
+ printErrorLine("Re-run with --force to confirm deletion.");
55797
55927
  }
55798
55928
  process.exit(1);
55799
55929
  }
@@ -55801,105 +55931,105 @@ Emails:`);
55801
55931
  if (!deleted) {
55802
55932
  const message = `Domain '${id}' not found.`;
55803
55933
  if (opts.json) {
55804
- console.log(JSON.stringify({ deleted: false, id, error: message }, null, 2));
55934
+ printLine(JSON.stringify({ deleted: false, id, error: message }, null, 2));
55805
55935
  } else {
55806
- console.error(message);
55936
+ printErrorLine(message);
55807
55937
  }
55808
55938
  process.exit(1);
55809
55939
  }
55810
55940
  if (opts.json) {
55811
- console.log(JSON.stringify({ deleted: true, id }, null, 2));
55941
+ printLine(JSON.stringify({ deleted: true, id }, null, 2));
55812
55942
  return;
55813
55943
  }
55814
- console.log(`Deleted domain ${id}`);
55944
+ printLine(`Deleted domain ${id}`);
55815
55945
  });
55816
55946
  domain.command("search <query>").description("Search domains by name, registrar, or notes").option("--limit <n>", "Limit number of displayed domains").option("--offset <n>", "Skip first N domains", "0").option("--all", "Show all matching domains").option("--verbose", "Show registrar and truncated notes").option("-j, --json", "Output JSON").action(async (query, opts) => {
55817
55947
  const results = await searchDomains2(query);
55818
55948
  if (opts.json) {
55819
- console.log(JSON.stringify({ results, count: results.length }, null, 2));
55949
+ printLine(JSON.stringify({ results, count: results.length }, null, 2));
55820
55950
  return;
55821
55951
  }
55822
55952
  let page;
55823
55953
  try {
55824
55954
  page = pageItemsOrExit(results, { limit: opts.limit, offset: opts.offset, all: opts.all });
55825
55955
  } catch (error) {
55826
- console.error(error instanceof Error ? error.message : String(error));
55956
+ printErrorLine(error instanceof Error ? error.message : String(error));
55827
55957
  process.exit(1);
55828
55958
  }
55829
55959
  for (const d4 of page.items) {
55830
55960
  const notes = opts.verbose && d4.notes ? ` \u2014 ${truncateText(d4.notes, 80)}` : "";
55831
- console.log(` ${d4.name} [${d4.status}]${notes}`);
55961
+ printLine(` ${d4.name} [${d4.status}]${notes}`);
55832
55962
  }
55833
55963
  if (results.length === 0)
55834
- console.log("No results.");
55964
+ printLine("No results.");
55835
55965
  else
55836
- console.log(`
55966
+ printLine(`
55837
55967
  ${compactHint(page, "result(s)", "Use --verbose for notes or domain get <id|name> for details.")}`);
55838
55968
  });
55839
55969
  domain.command("expiring").description("List domains expiring soon").option("--days <n>", "Days threshold", "30").option("--limit <n>", "Limit number of displayed domains").option("--all", "Show all matching domains").option("-j, --json", "Output JSON").action(async (opts) => {
55840
55970
  const domains = await listExpiring2(parseInt(opts.days));
55841
55971
  if (opts.json) {
55842
- console.log(JSON.stringify(domains, null, 2));
55972
+ printLine(JSON.stringify(domains, null, 2));
55843
55973
  return;
55844
55974
  }
55845
55975
  const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
55846
55976
  if (page.items.length === 0) {
55847
- console.log(`No domains expiring within ${opts.days} days.`);
55977
+ printLine(`No domains expiring within ${opts.days} days.`);
55848
55978
  return;
55849
55979
  }
55850
- console.log(`
55980
+ printLine(`
55851
55981
  Expiring within ${opts.days} days:`);
55852
55982
  for (const d4 of page.items)
55853
- console.log(` ${d4.name.padEnd(40)} expires ${formatDate(d4.expires_at)}`);
55854
- console.log(`
55983
+ printLine(` ${d4.name.padEnd(40)} expires ${formatDate(d4.expires_at)}`);
55984
+ printLine(`
55855
55985
  ${compactHint(page, "domain(s)", "Use --all to display every expiring domain.", { paging: "limit" })}`);
55856
55986
  });
55857
55987
  domain.command("stats").description("Show portfolio statistics").option("-j, --json", "Output JSON").action(async (opts) => {
55858
55988
  const stats = await getDomainStats2();
55859
55989
  if (opts.json) {
55860
- console.log(JSON.stringify(stats, null, 2));
55990
+ printLine(JSON.stringify(stats, null, 2));
55861
55991
  return;
55862
55992
  }
55863
- console.log("Domain Portfolio Stats:");
55993
+ printLine("Domain Portfolio Stats:");
55864
55994
  for (const [k4, v2] of Object.entries(stats)) {
55865
- console.log(` ${k4.replace(/_/g, " ")}: ${v2}`);
55995
+ printLine(` ${k4.replace(/_/g, " ")}: ${v2}`);
55866
55996
  }
55867
55997
  });
55868
55998
  domain.command("whois <name>").description("Run WHOIS lookup and update local DB record").option("-j, --json", "Output JSON").action(async (name, opts) => {
55869
55999
  try {
55870
56000
  const result = await whoisLookup(name);
55871
56001
  if (opts.json) {
55872
- console.log(JSON.stringify(result, null, 2));
56002
+ printLine(JSON.stringify(result, null, 2));
55873
56003
  return;
55874
56004
  }
55875
- console.log(`
56005
+ printLine(`
55876
56006
  WHOIS for ${result.domain} [${result.source}]:`);
55877
- console.log(` Registrar: ${result.registrar ?? "unknown"}`);
55878
- console.log(` Expires: ${result.expires_at ?? "unknown"}`);
56007
+ printLine(` Registrar: ${result.registrar ?? "unknown"}`);
56008
+ printLine(` Expires: ${result.expires_at ?? "unknown"}`);
55879
56009
  if (result.nameservers.length) {
55880
- console.log(` NS: ${result.nameservers.join(", ")}`);
56010
+ printLine(` NS: ${result.nameservers.join(", ")}`);
55881
56011
  }
55882
56012
  const r4 = result.registrant;
55883
56013
  if (r4?.name || r4?.email || r4?.organization) {
55884
- console.log(` Registrant:`);
56014
+ printLine(` Registrant:`);
55885
56015
  if (r4.name)
55886
- console.log(` Name: ${r4.name}`);
56016
+ printLine(` Name: ${r4.name}`);
55887
56017
  if (r4.email)
55888
- console.log(` Email: ${r4.email}`);
56018
+ printLine(` Email: ${r4.email}`);
55889
56019
  if (r4.phone)
55890
- console.log(` Phone: ${r4.phone}`);
56020
+ printLine(` Phone: ${r4.phone}`);
55891
56021
  if (r4.organization)
55892
- console.log(` Org: ${r4.organization}`);
56022
+ printLine(` Org: ${r4.organization}`);
55893
56023
  }
55894
- console.log();
56024
+ printLine();
55895
56025
  } catch (error) {
55896
- console.error(`WHOIS lookup failed: ${error instanceof Error ? error.message : String(error)}`);
56026
+ printErrorLine(`WHOIS lookup failed: ${error instanceof Error ? error.message : String(error)}`);
55897
56027
  process.exit(1);
55898
56028
  }
55899
56029
  });
55900
56030
  domain.command("export").description("Export all domains as CSV or JSON").option("--format <fmt>", "Format: csv or json", "json").action(async (opts) => {
55901
56031
  const output = await exportPortfolio(opts.format);
55902
- console.log(output);
56032
+ printLine(output);
55903
56033
  });
55904
56034
  domain.command("check <domains...>").description("Check domain availability via configured registrar").option("--provider <name>", "Registrar provider to use").option("-j, --json", "Output JSON").action(async (domains, opts) => {
55905
56035
  const cfg = loadConfig3();
@@ -55917,19 +56047,19 @@ WHOIS for ${result.domain} [${result.source}]:`);
55917
56047
  const error = reason instanceof Error ? reason.message : String(reason);
55918
56048
  output.push({ domain: domains[i4], error });
55919
56049
  if (!opts.json) {
55920
- console.error(`\u2717 ${domains[i4]}: ${error}`);
56050
+ printErrorLine(`\u2717 ${domains[i4]}: ${error}`);
55921
56051
  }
55922
56052
  anyError = true;
55923
56053
  } else {
55924
56054
  const result = r4.value;
55925
56055
  output.push({ domain: result.domain, available: result.available });
55926
56056
  if (!opts.json) {
55927
- console.log(`${result.available ? "\u2713" : "\u2717"} ${result.domain} is ${result.available ? "available" : "not available"}`);
56057
+ printLine(`${result.available ? "\u2713" : "\u2717"} ${result.domain} is ${result.available ? "available" : "not available"}`);
55928
56058
  }
55929
56059
  }
55930
56060
  }
55931
56061
  if (opts.json) {
55932
- console.log(JSON.stringify({
56062
+ printLine(JSON.stringify({
55933
56063
  provider: providerName,
55934
56064
  count: output.length,
55935
56065
  ok: !anyError,
@@ -55938,11 +56068,11 @@ WHOIS for ${result.domain} [${result.source}]:`);
55938
56068
  } else {
55939
56069
  for (const result of output) {
55940
56070
  if (result.available !== undefined && "is_premium" in result && result.is_premium) {
55941
- console.log(` Premium ask: ${result.premium_price ?? "unknown"}`);
56071
+ printLine(` Premium ask: ${result.premium_price ?? "unknown"}`);
55942
56072
  }
55943
56073
  if ("standard_price" in result && result.standard_price !== undefined) {
55944
56074
  const currency = "currency" in result && result.currency ? ` ${result.currency}` : "";
55945
- console.log(` Standard price: ${result.standard_price}${currency}`);
56075
+ printLine(` Standard price: ${result.standard_price}${currency}`);
55946
56076
  }
55947
56077
  }
55948
56078
  }
@@ -55968,11 +56098,11 @@ WHOIS for ${result.domain} [${result.source}]:`);
55968
56098
  try {
55969
56099
  const provider = getDomainInventoryProvider(name);
55970
56100
  const result = await provider.syncToLocalDb({ getDomainByName: getDomainByName2, createDomain: createDomain2, updateDomain: updateDomain2 });
55971
- console.log(`\u2713 [${name}] Synced ${result.synced} (${result.created} new, ${result.updated} updated)`);
56101
+ printLine(`\u2713 [${name}] Synced ${result.synced} (${result.created} new, ${result.updated} updated)`);
55972
56102
  if (result.errors.length > 0)
55973
- console.log(` Errors: ${result.errors.join(", ")}`);
56103
+ printLine(` Errors: ${result.errors.join(", ")}`);
55974
56104
  } catch (e4) {
55975
- console.error(`\u2717 [${name}] ${e4 instanceof Error ? e4.message : String(e4)}`);
56105
+ printErrorLine(`\u2717 [${name}] ${e4 instanceof Error ? e4.message : String(e4)}`);
55976
56106
  }
55977
56107
  }
55978
56108
  });
@@ -55981,14 +56111,14 @@ WHOIS for ${result.domain} [${result.source}]:`);
55981
56111
  const standardPrice = parseOptionalNumber(opts.standard, "--standard");
55982
56112
  const updated = await markDomainPremium2(identifier, premiumPrice, standardPrice);
55983
56113
  if (!updated) {
55984
- console.error(`Domain '${identifier}' not found.`);
56114
+ printErrorLine(`Domain '${identifier}' not found.`);
55985
56115
  process.exit(1);
55986
56116
  }
55987
56117
  if (opts.json) {
55988
- console.log(JSON.stringify(updated, null, 2));
56118
+ printLine(JSON.stringify(updated, null, 2));
55989
56119
  return;
55990
56120
  }
55991
- console.log(`Marked ${updated.name} as premium at ${premiumPrice}`);
56121
+ printLine(`Marked ${updated.name} as premium at ${premiumPrice}`);
55992
56122
  });
55993
56123
  domain.command("offer <identifier>").description("Record a negotiation step for a domain").option("--our <price>", "Our offer").option("--their <price>", "Their asking price").option("--status <status>", `Offer status (${DOMAIN_OFFER_STATUS_HELP})`, "pending").option("--notes <text>", "Negotiation notes").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
55994
56124
  const details = await requireDomain(identifier);
@@ -56003,37 +56133,37 @@ WHOIS for ${result.domain} [${result.source}]:`);
56003
56133
  await updateDomainLifecycleStatus2(details.domain.id, opts.their || opts.our ? "negotiating" : "offered");
56004
56134
  }
56005
56135
  if (opts.json) {
56006
- console.log(JSON.stringify(offer, null, 2));
56136
+ printLine(JSON.stringify(offer, null, 2));
56007
56137
  return;
56008
56138
  }
56009
- console.log(`Logged offer for ${details.domain.name}: ${offer.status}`);
56139
+ printLine(`Logged offer for ${details.domain.name}: ${offer.status}`);
56010
56140
  });
56011
56141
  domain.command("status <identifier> <status>").description("Update the lifecycle status of a domain").option("--notes <text>", "Optional note to store with the status change").option("-j, --json", "Output JSON").action(async (identifier, status, opts) => {
56012
56142
  const updated = await updateDomainLifecycleStatus2(identifier, status, opts.notes);
56013
56143
  if (!updated) {
56014
- console.error(`Domain '${identifier}' not found.`);
56144
+ printErrorLine(`Domain '${identifier}' not found.`);
56015
56145
  process.exit(1);
56016
56146
  }
56017
56147
  if (opts.json) {
56018
- console.log(JSON.stringify(updated, null, 2));
56148
+ printLine(JSON.stringify(updated, null, 2));
56019
56149
  return;
56020
56150
  }
56021
- console.log(`Updated ${updated.name} to ${updated.status}`);
56151
+ printLine(`Updated ${updated.name} to ${updated.status}`);
56022
56152
  });
56023
56153
  domain.command("emails <identifier>").description("Show email threads linked to a domain").option("-j, --json", "Output JSON").action(async (identifier, opts) => {
56024
56154
  const details = await requireDomain(identifier);
56025
56155
  const emails = await listDomainEmailLinks2(details.domain.id);
56026
56156
  if (opts.json) {
56027
- console.log(JSON.stringify({ domain: details.domain.name, emails, count: emails.length }, null, 2));
56157
+ printLine(JSON.stringify({ domain: details.domain.name, emails, count: emails.length }, null, 2));
56028
56158
  return;
56029
56159
  }
56030
56160
  if (emails.length === 0) {
56031
- console.log(`No linked emails for ${details.domain.name}.`);
56161
+ printLine(`No linked emails for ${details.domain.name}.`);
56032
56162
  return;
56033
56163
  }
56034
56164
  for (const email of emails) {
56035
56165
  const threadPart = email.thread_id ? ` (${email.thread_id})` : "";
56036
- console.log(` ${email.type}: ${email.email_id}${threadPart}`);
56166
+ printLine(` ${email.type}: ${email.email_id}${threadPart}`);
56037
56167
  }
56038
56168
  });
56039
56169
  domain.command("link-email <identifier> <emailId>").description("Link an email or email thread to a domain").requiredOption("--type <type>", `Link type (${DOMAIN_EMAIL_TYPE_HELP})`).option("--thread-id <threadId>", "Email thread ID").option("-j, --json", "Output JSON").action(async (identifier, emailId, opts) => {
@@ -56045,25 +56175,25 @@ WHOIS for ${result.domain} [${result.source}]:`);
56045
56175
  type: opts.type
56046
56176
  });
56047
56177
  if (opts.json) {
56048
- console.log(JSON.stringify(link, null, 2));
56178
+ printLine(JSON.stringify(link, null, 2));
56049
56179
  return;
56050
56180
  }
56051
- console.log(`Linked ${emailId} to ${details.domain.name}`);
56181
+ printLine(`Linked ${emailId} to ${details.domain.name}`);
56052
56182
  });
56053
56183
  domain.command("renew <name>").description("Renew a domain via its registrar provider").option("--provider <name>", "Override provider").option("--years <n>", "Number of years to renew", "1").action(async (name, opts) => {
56054
56184
  const providerName = opts.provider ?? await autoDetectRegistrar(name, getDomainByName2) ?? loadConfig3().default_registrar;
56055
56185
  if (!providerName) {
56056
- console.error("Could not detect provider. Use --provider.");
56186
+ printErrorLine("Could not detect provider. Use --provider.");
56057
56187
  process.exit(1);
56058
56188
  }
56059
56189
  const provider = getRegistrarProvider(providerName);
56060
56190
  const result = await provider.renewDomain(name, parseInt(opts.years, 10));
56061
56191
  if (result.success) {
56062
- console.log(`\u2713 Renewed: ${name}`);
56192
+ printLine(`\u2713 Renewed: ${name}`);
56063
56193
  if (result.orderId)
56064
- console.log(` Order: ${result.orderId}`);
56194
+ printLine(` Order: ${result.orderId}`);
56065
56195
  } else {
56066
- console.error(`\u2717 Renewal failed or not supported for ${providerName}`);
56196
+ printErrorLine(`\u2717 Renewal failed or not supported for ${providerName}`);
56067
56197
  process.exit(1);
56068
56198
  }
56069
56199
  });
@@ -56080,13 +56210,13 @@ WHOIS for ${result.domain} [${result.source}]:`);
56080
56210
  auto_renew: opts.autoRenew ? opts.autoRenew === "true" : domainRecord.auto_renew
56081
56211
  });
56082
56212
  if (!purchased) {
56083
- console.error(`Domain '${name}' not found.`);
56213
+ printErrorLine(`Domain '${name}' not found.`);
56084
56214
  process.exit(1);
56085
56215
  }
56086
56216
  if (opts.wait) {
56087
56217
  await updateDomainLifecycleStatus2(purchased.id, "active");
56088
56218
  }
56089
- console.log(`Recorded purchase for ${purchased.name} at ${recordedPrice}`);
56219
+ printLine(`Recorded purchase for ${purchased.name} at ${recordedPrice}`);
56090
56220
  return;
56091
56221
  }
56092
56222
  const cfg = loadConfig3();
@@ -56094,44 +56224,44 @@ WHOIS for ${result.domain} [${result.source}]:`);
56094
56224
  const dnsProvider = opts.dns ?? cfg.default_dns ?? "cloudflare";
56095
56225
  const purchaseProfile = providerName === "route53" ? applyPurchaseProfile() : undefined;
56096
56226
  if (purchaseProfile)
56097
- console.log(`Using purchase AWS profile: ${purchaseProfile}`);
56227
+ printLine(`Using purchase AWS profile: ${purchaseProfile}`);
56098
56228
  if (providerName !== "route53") {
56099
56229
  try {
56100
56230
  const capability = getCapability(providerName);
56101
56231
  if (!capability.canBuy) {
56102
- console.error(`Direct domain purchase is not supported for ${providerName}. ${capability.notes} Use route53 or record a marketplace/manual purchase with --price.`);
56232
+ printErrorLine(`Direct domain purchase is not supported for ${providerName}. ${capability.notes} Use route53 or record a marketplace/manual purchase with --price.`);
56103
56233
  process.exit(1);
56104
56234
  }
56105
56235
  if (capability.gated && !opts.allowGated) {
56106
- console.error(`Registrar '${providerName}' is gated/enterprise-only. Pass --allow-gated only when this account is contract-approved. ${capability.notes}`);
56236
+ printErrorLine(`Registrar '${providerName}' is gated/enterprise-only. Pass --allow-gated only when this account is contract-approved. ${capability.notes}`);
56107
56237
  process.exit(1);
56108
56238
  }
56109
56239
  const provider = getRegistrarProvider(providerName);
56110
56240
  if (!provider.registerDomain) {
56111
- console.error(`Direct domain purchase is not supported for ${providerName}. Use route53 or record a marketplace/manual purchase with --price.`);
56241
+ printErrorLine(`Direct domain purchase is not supported for ${providerName}. Use route53 or record a marketplace/manual purchase with --price.`);
56112
56242
  process.exit(1);
56113
56243
  }
56114
56244
  const avail = await provider.checkAvailability(name);
56115
56245
  if (!avail.available) {
56116
- console.error(`\u2717 ${name} is not available`);
56246
+ printErrorLine(`\u2717 ${name} is not available`);
56117
56247
  process.exit(1);
56118
56248
  }
56119
- console.log(`\u2713 Available via ${providerName}`);
56249
+ printLine(`\u2713 Available via ${providerName}`);
56120
56250
  let contact;
56121
56251
  try {
56122
56252
  contact = resolveContact(opts);
56123
56253
  } catch (e4) {
56124
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56254
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56125
56255
  process.exit(1);
56126
56256
  }
56127
- console.log(`Registering ${name} via ${providerName}...`);
56257
+ printLine(`Registering ${name} via ${providerName}...`);
56128
56258
  const reg = await provider.registerDomain(name, contact, {
56129
56259
  years: parseInt(opts.years, 10),
56130
56260
  premiumPrice: avail.premium_price,
56131
56261
  autoRenew: opts.autoRenew ? opts.autoRenew === "true" : true
56132
56262
  });
56133
56263
  if (!reg.success) {
56134
- console.error(`\u2717 Registration failed via ${providerName}`);
56264
+ printErrorLine(`\u2717 Registration failed via ${providerName}`);
56135
56265
  process.exit(1);
56136
56266
  }
56137
56267
  const existing = await getDomainByName2(name);
@@ -56149,45 +56279,45 @@ WHOIS for ${result.domain} [${result.source}]:`);
56149
56279
  await updateDomain2(existing.id, dbInput);
56150
56280
  else
56151
56281
  await createDomain2({ name, ...dbInput });
56152
- console.log(`\u2713 Registered and added to portfolio`);
56282
+ printLine(`\u2713 Registered and added to portfolio`);
56153
56283
  if (reg.orderId)
56154
- console.log(` Order: ${reg.orderId}`);
56284
+ printLine(` Order: ${reg.orderId}`);
56155
56285
  if (opts.delegate !== false) {
56156
56286
  if (!provider.updateNameservers) {
56157
- console.log(` DNS: ${providerName} registration succeeded, but nameserver updates are not implemented for this provider.`);
56287
+ printLine(` DNS: ${providerName} registration succeeded, but nameserver updates are not implemented for this provider.`);
56158
56288
  } else {
56159
56289
  const zone = await createDnsZoneForProvider(name, dnsProvider);
56160
56290
  const nsUpdate = await provider.updateNameservers(name, zone.nameservers);
56161
56291
  const existing2 = await getDomainByName2(name);
56162
56292
  if (existing2)
56163
56293
  await updateDomain2(existing2.id, { nameservers: zone.nameservers });
56164
- console.log(`\u2713 ${dnsProvider} zone ${zone.zoneId}; nameservers updated${nsUpdate.operationId ? ` (op ${nsUpdate.operationId})` : ""}`);
56294
+ printLine(`\u2713 ${dnsProvider} zone ${zone.zoneId}; nameservers updated${nsUpdate.operationId ? ` (op ${nsUpdate.operationId})` : ""}`);
56165
56295
  }
56166
56296
  }
56167
56297
  return;
56168
56298
  } catch (e4) {
56169
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56299
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56170
56300
  process.exit(1);
56171
56301
  }
56172
56302
  }
56173
56303
  try {
56174
56304
  const avail = await checkAvailability3(name);
56175
56305
  if (!avail.available) {
56176
- console.error(`\u2717 ${name} is not available`);
56306
+ printErrorLine(`\u2717 ${name} is not available`);
56177
56307
  process.exit(1);
56178
56308
  }
56179
56309
  const price = avail.price ? ` (USD ${avail.price}/yr)` : "";
56180
- console.log(`\u2713 Available${price}`);
56310
+ printLine(`\u2713 Available${price}`);
56181
56311
  let contact;
56182
56312
  try {
56183
56313
  contact = resolveContact(opts);
56184
56314
  } catch (e4) {
56185
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56315
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56186
56316
  process.exit(1);
56187
56317
  }
56188
- console.log(`Registering ${name}...`);
56318
+ printLine(`Registering ${name}...`);
56189
56319
  const reg = await registerDomain2(name, contact, parseInt(opts.years));
56190
- console.log(`\u2713 Submitted (operation: ${reg.operationId})`);
56320
+ printLine(`\u2713 Submitted (operation: ${reg.operationId})`);
56191
56321
  if (opts.wait) {
56192
56322
  let status = "IN_PROGRESS";
56193
56323
  while (status === "IN_PROGRESS" || status === "SUBMITTED") {
@@ -56196,12 +56326,12 @@ WHOIS for ${result.domain} [${result.source}]:`);
56196
56326
  status = s2.status;
56197
56327
  process.stdout.write(` Status: ${status}\r`);
56198
56328
  }
56199
- console.log();
56329
+ printLine();
56200
56330
  if (status !== "SUCCESSFUL") {
56201
- console.error(`\u2717 Registration ${status}`);
56331
+ printErrorLine(`\u2717 Registration ${status}`);
56202
56332
  process.exit(1);
56203
56333
  }
56204
- console.log(`\u2713 Registration complete`);
56334
+ printLine(`\u2713 Registration complete`);
56205
56335
  }
56206
56336
  const existing = await getDomainByName2(name);
56207
56337
  if (existing) {
@@ -56224,13 +56354,13 @@ WHOIS for ${result.domain} [${result.source}]:`);
56224
56354
  standard_price: avail.price ? Number(avail.price) : undefined
56225
56355
  });
56226
56356
  }
56227
- console.log(`\u2713 Added to portfolio`);
56357
+ printLine(`\u2713 Added to portfolio`);
56228
56358
  if (opts.delegate !== false) {
56229
56359
  if (!opts.wait) {
56230
- console.log(` DNS: run 'domains domain buy ${name} --wait' or delegate later \u2014 registration must finish before NS can change.`);
56360
+ printLine(` DNS: run 'domains domain buy ${name} --wait' or delegate later \u2014 registration must finish before NS can change.`);
56231
56361
  } else {
56232
56362
  try {
56233
- console.log(`Delegating DNS to ${dnsProvider}...`);
56363
+ printLine(`Delegating DNS to ${dnsProvider}...`);
56234
56364
  const del = dnsProvider === "cloudflare" ? await delegateDomainToCloudflare(name, {
56235
56365
  createCloudflareZone: async (d4) => {
56236
56366
  const z = await ensureZone(d4);
@@ -56245,17 +56375,17 @@ WHOIS for ${result.domain} [${result.source}]:`);
56245
56375
  const existing2 = await getDomainByName2(name);
56246
56376
  if (existing2)
56247
56377
  await updateDomain2(existing2.id, { nameservers: del.nameservers });
56248
- console.log(`\u2713 ${dnsProvider} zone ${del.zoneId}; nameservers \u2192 ${del.nameservers.join(", ")} (op ${del.operationId})`);
56378
+ printLine(`\u2713 ${dnsProvider} zone ${del.zoneId}; nameservers \u2192 ${del.nameservers.join(", ")} (op ${del.operationId})`);
56249
56379
  } catch (e4) {
56250
- console.error(`\u26A0 DNS delegation failed (domain is registered): ${e4 instanceof Error ? e4.message : String(e4)}`);
56251
- console.error(` Retry: create the DNS zone and point Route53 NS at it.`);
56380
+ printErrorLine(`\u26A0 DNS delegation failed (domain is registered): ${e4 instanceof Error ? e4.message : String(e4)}`);
56381
+ printErrorLine(` Retry: create the DNS zone and point Route53 NS at it.`);
56252
56382
  }
56253
56383
  }
56254
56384
  }
56255
56385
  if (!opts.wait)
56256
- console.log(` Check: domains r53 status ${reg.operationId}`);
56386
+ printLine(` Check: domains r53 status ${reg.operationId}`);
56257
56387
  } catch (e4) {
56258
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56388
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56259
56389
  process.exit(1);
56260
56390
  }
56261
56391
  });
@@ -56263,34 +56393,34 @@ WHOIS for ${result.domain} [${result.source}]:`);
56263
56393
  const cfg = loadConfig3();
56264
56394
  const registrarName = opts.registrar ?? cfg.default_registrar ?? "route53";
56265
56395
  const dnsName = opts.dns ?? cfg.default_dns ?? "cloudflare";
56266
- console.log(`
56396
+ printLine(`
56267
56397
  Setting up ${name}`);
56268
- console.log(` Registrar: ${registrarName} | DNS: ${dnsName}
56398
+ printLine(` Registrar: ${registrarName} | DNS: ${dnsName}
56269
56399
  `);
56270
56400
  try {
56271
56401
  process.stdout.write(opts.wait ? "[1/5] Checking availability... " : "[1/4] Checking availability... ");
56272
56402
  const avail = await checkAvailability3(name);
56273
56403
  if (!avail.available) {
56274
- console.log("not available");
56275
- console.error(`\u2717 ${name} is not available`);
56404
+ printLine("not available");
56405
+ printErrorLine(`\u2717 ${name} is not available`);
56276
56406
  process.exit(1);
56277
56407
  }
56278
56408
  const price = avail.price ? `(USD ${avail.price}/yr)` : "";
56279
- console.log(`available ${price}`);
56409
+ printLine(`available ${price}`);
56280
56410
  if (registrarName !== "route53") {
56281
- console.error("Direct domain purchase currently only supported via route53.");
56411
+ printErrorLine("Direct domain purchase currently only supported via route53.");
56282
56412
  process.exit(1);
56283
56413
  }
56284
56414
  let contact;
56285
56415
  try {
56286
56416
  contact = resolveContact(opts);
56287
56417
  } catch (e4) {
56288
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56418
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56289
56419
  process.exit(1);
56290
56420
  }
56291
56421
  process.stdout.write(opts.wait ? "[2/5] Registering domain... " : "[2/4] Registering domain... ");
56292
56422
  const reg = await registerDomain2(name, contact, parseInt(opts.years));
56293
- console.log(`submitted (${reg.operationId})`);
56423
+ printLine(`submitted (${reg.operationId})`);
56294
56424
  if (opts.wait) {
56295
56425
  let status = "IN_PROGRESS";
56296
56426
  while (status === "IN_PROGRESS" || status === "SUBMITTED") {
@@ -56299,36 +56429,36 @@ Setting up ${name}`);
56299
56429
  status = s2.status;
56300
56430
  process.stdout.write(` Waiting: ${status}...\r`);
56301
56431
  }
56302
- console.log();
56432
+ printLine();
56303
56433
  if (status !== "SUCCESSFUL") {
56304
- console.error(`\u2717 Registration ${status}`);
56434
+ printErrorLine(`\u2717 Registration ${status}`);
56305
56435
  process.exit(1);
56306
56436
  }
56307
- console.log(" Registration confirmed");
56437
+ printLine(" Registration confirmed");
56308
56438
  }
56309
56439
  process.stdout.write(opts.wait ? "[3/5] Creating DNS zone... " : "[3/4] Creating DNS zone... ");
56310
56440
  let nameservers = [];
56311
56441
  if (dnsName === "cloudflare") {
56312
56442
  const zone = await ensureZone(name);
56313
56443
  nameservers = zone.nameservers ?? [];
56314
- console.log("ready (" + zone.id + ")");
56444
+ printLine("ready (" + zone.id + ")");
56315
56445
  } else {
56316
56446
  const zone = await createHostedZone(name, "Managed by domains CLI");
56317
56447
  nameservers = zone.name_servers ?? [];
56318
- console.log(`created (${zone.id})`);
56448
+ printLine(`created (${zone.id})`);
56319
56449
  }
56320
56450
  if (nameservers.length > 0) {
56321
56451
  if (opts.wait) {
56322
56452
  process.stdout.write("[4/5] Updating registrar nameservers... ");
56323
56453
  if (registrarName !== "route53") {
56324
- console.log("skipped");
56325
- console.error("Only Route53 nameserver delegation is currently implemented for setup.");
56454
+ printLine("skipped");
56455
+ printErrorLine("Only Route53 nameserver delegation is currently implemented for setup.");
56326
56456
  process.exit(1);
56327
56457
  }
56328
56458
  const nsUpdate = await updateNameservers2(name, nameservers);
56329
- console.log("submitted (" + nsUpdate.operationId + ")");
56459
+ printLine("submitted (" + nsUpdate.operationId + ")");
56330
56460
  } else {
56331
- console.log(" Nameserver delegation skipped until registration completes; re-run with --wait or use domains r53 domain-info/status first.");
56461
+ printLine(" Nameserver delegation skipped until registration completes; re-run with --wait or use domains r53 domain-info/status first.");
56332
56462
  }
56333
56463
  }
56334
56464
  process.stdout.write(opts.wait ? "[5/5] Adding to portfolio... " : "[4/4] Adding to portfolio... ");
@@ -56338,22 +56468,22 @@ Setting up ${name}`);
56338
56468
  await updateDomain2(existing.id, dbInput);
56339
56469
  else
56340
56470
  await createDomain2({ name, ...dbInput });
56341
- console.log("done");
56342
- console.log(`
56471
+ printLine("done");
56472
+ printLine(`
56343
56473
  \u2713 Setup complete for ${name}`);
56344
56474
  if (!opts.wait) {
56345
- console.log(` \u26A0 Registration pending \u2014 check: domains r53 status ${reg.operationId}`);
56346
- console.log(` \u26A0 If registration fails, clean up: domains zone delete <zoneId> --force`);
56475
+ printLine(` \u26A0 Registration pending \u2014 check: domains r53 status ${reg.operationId}`);
56476
+ printLine(` \u26A0 If registration fails, clean up: domains zone delete <zoneId> --force`);
56347
56477
  }
56348
56478
  if (nameservers.length > 0) {
56349
- console.log(`
56479
+ printLine(`
56350
56480
  Point your registrar to these name servers:`);
56351
56481
  for (const ns of nameservers)
56352
- console.log(` ${ns}`);
56482
+ printLine(` ${ns}`);
56353
56483
  }
56354
- console.log();
56484
+ printLine();
56355
56485
  } catch (e4) {
56356
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56486
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56357
56487
  process.exit(1);
56358
56488
  }
56359
56489
  });
@@ -56378,13 +56508,16 @@ function normalizeDnsRecord(record, domain) {
56378
56508
  } else if (lowerName.endsWith(`.${normalizedDomain}`)) {
56379
56509
  name = name.replace(/\.$/, "").slice(0, -(normalizedDomain.length + 1));
56380
56510
  }
56381
- return {
56511
+ const normalized = {
56382
56512
  type,
56383
56513
  name,
56384
56514
  value: String(record.value).trim(),
56385
56515
  ttl: Number.isFinite(record.ttl) && record.ttl > 0 ? Math.trunc(record.ttl) : 300,
56386
56516
  priority: record.priority
56387
56517
  };
56518
+ if (record.proxied !== undefined)
56519
+ normalized.proxied = record.proxied;
56520
+ return normalized;
56388
56521
  }
56389
56522
  function parseDesiredDnsState(input, domainHint) {
56390
56523
  let parsed;
@@ -56415,7 +56548,8 @@ function parseDesiredDnsState(input, domainHint) {
56415
56548
  name: r4["name"],
56416
56549
  value: r4["value"],
56417
56550
  ttl: typeof r4["ttl"] === "number" ? r4["ttl"] : Number(r4["ttl"] ?? 300),
56418
- priority: r4["priority"] == null ? undefined : Number(r4["priority"])
56551
+ priority: r4["priority"] == null ? undefined : Number(r4["priority"]),
56552
+ proxied: typeof r4["proxied"] === "boolean" ? r4["proxied"] : undefined
56419
56553
  }, domain);
56420
56554
  })
56421
56555
  };
@@ -56424,7 +56558,7 @@ function identity(record) {
56424
56558
  return [record.type, record.name, record.value, record.priority ?? ""].join("\x00");
56425
56559
  }
56426
56560
  function sameMutableFields(a4, b4) {
56427
- return a4.ttl === b4.ttl;
56561
+ return a4.ttl === b4.ttl && (b4.proxied === undefined || a4.proxied === b4.proxied);
56428
56562
  }
56429
56563
  function createDnsPlan(domain, current, desired) {
56430
56564
  const normalizedCurrent = current.map((record) => normalizeDnsRecord(record, domain));
@@ -56459,6 +56593,13 @@ function createDnsPlan(domain, current, desired) {
56459
56593
  function planHasChanges(plan) {
56460
56594
  return plan.creates + plan.updates + plan.deletes > 0;
56461
56595
  }
56596
+ function dnsRecordGroupKey(record) {
56597
+ return `${record.type}\x00${record.name}`;
56598
+ }
56599
+ function selectChangedDnsRecords(plan, desired) {
56600
+ const changedGroups = new Set(plan.operations.filter((operation) => operation.op !== "unchanged").map((operation) => dnsRecordGroupKey(operation.record)));
56601
+ return desired.filter((record) => changedGroups.has(dnsRecordGroupKey(normalizeDnsRecord(record, plan.domain))));
56602
+ }
56462
56603
  function getDnsApplyBlockReason(plan, opts) {
56463
56604
  if (!planHasChanges(plan))
56464
56605
  return;
@@ -56472,6 +56613,7 @@ function getDnsApplyBlockReason(plan, opts) {
56472
56613
  }
56473
56614
 
56474
56615
  // src/cli/commands/dns.ts
56616
+ init_stdout();
56475
56617
  var SUPPORTED_DNS_TYPES = new Set(["A", "AAAA", "CNAME", "MX", "TXT", "NS", "SRV"]);
56476
56618
  function partitionPullableRecords(records) {
56477
56619
  const keep = [];
@@ -56486,49 +56628,50 @@ function partitionPullableRecords(records) {
56486
56628
  return { keep, skipped };
56487
56629
  }
56488
56630
  function printDnsPlan(plan) {
56489
- console.log(`DNS plan for ${plan.domain}: ${plan.creates} create, ${plan.updates} update, ${plan.deletes} delete, ${plan.unchanged} unchanged`);
56631
+ printLine(`DNS plan for ${plan.domain}: ${plan.creates} create, ${plan.updates} update, ${plan.deletes} delete, ${plan.unchanged} unchanged`);
56490
56632
  for (const op of plan.operations) {
56491
56633
  if (op.op === "unchanged")
56492
56634
  continue;
56493
56635
  const priority = op.record.priority == null ? "" : ` priority=${op.record.priority}`;
56494
56636
  const currentTtl = op.current && op.current.ttl !== op.record.ttl ? ` ttl ${op.current.ttl}->${op.record.ttl}` : "";
56495
- console.log(` ${op.op.toUpperCase()} ${op.record.type} ${op.record.name} ${op.record.value} ttl=${op.record.ttl}${priority}${currentTtl}`);
56637
+ printLine(` ${op.op.toUpperCase()} ${op.record.type} ${op.record.name} ${op.record.value} ttl=${op.record.ttl}${priority}${currentTtl}`);
56496
56638
  }
56497
56639
  }
56498
- async function loadDnsPlan(domain, providerName, file) {
56640
+ async function loadDnsPlan(domain, providerName, file, resolveDnsProvider = getDnsProvider) {
56499
56641
  const desired = parseDesiredDnsState(readFileSync4(file, "utf-8"), domain);
56500
56642
  const planDomain = desired.domain ?? domain;
56501
- const provider = getDnsProvider(providerName);
56643
+ const provider = resolveDnsProvider(providerName);
56502
56644
  const current = await provider.getDnsRecords(planDomain);
56503
56645
  return createDnsPlan(planDomain, current, desired.records);
56504
56646
  }
56505
- function registerDnsCommands(program2) {
56647
+ function registerDnsCommands(program2, deps = {}) {
56648
+ const resolveDnsProvider = deps.getDnsProvider ?? getDnsProvider;
56506
56649
  const dnsCmd = program2.command("dns").description("DNS record management");
56507
56650
  dnsCmd.command("plan <domain>").description("Preview desired DNS state changes from a JSON file without mutating provider records").requiredOption("--file <path>", "Desired DNS state JSON file").option("--provider <name>", "DNS provider \u2014 defaults to config default-dns").option("--json", "Output as JSON", false).action(async (domain, opts) => {
56508
56651
  const providerName = opts.provider ?? loadConfig3().default_dns ?? "route53";
56509
56652
  try {
56510
- const plan = await loadDnsPlan(domain, providerName, opts.file);
56653
+ const plan = await loadDnsPlan(domain, providerName, opts.file, resolveDnsProvider);
56511
56654
  if (opts.json)
56512
- console.log(JSON.stringify(plan, null, 2));
56655
+ printLine(JSON.stringify(plan, null, 2));
56513
56656
  else
56514
56657
  printDnsPlan(plan);
56515
56658
  } catch (e4) {
56516
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56659
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56517
56660
  process.exit(1);
56518
56661
  }
56519
56662
  });
56520
56663
  dnsCmd.command("diff <domain>").description("Alias of dns plan: show live provider DNS drift against desired JSON state").requiredOption("--file <path>", "Desired DNS state JSON file").option("--provider <name>", "DNS provider \u2014 defaults to config default-dns").option("--json", "Output as JSON", false).action(async (domain, opts) => {
56521
56664
  const providerName = opts.provider ?? loadConfig3().default_dns ?? "route53";
56522
56665
  try {
56523
- const plan = await loadDnsPlan(domain, providerName, opts.file);
56666
+ const plan = await loadDnsPlan(domain, providerName, opts.file, resolveDnsProvider);
56524
56667
  if (opts.json)
56525
- console.log(JSON.stringify(plan, null, 2));
56668
+ printLine(JSON.stringify(plan, null, 2));
56526
56669
  else
56527
56670
  printDnsPlan(plan);
56528
56671
  if (planHasChanges(plan))
56529
56672
  process.exitCode = 2;
56530
56673
  } catch (e4) {
56531
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56674
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56532
56675
  process.exit(1);
56533
56676
  }
56534
56677
  });
@@ -56537,12 +56680,12 @@ function registerDnsCommands(program2) {
56537
56680
  try {
56538
56681
  const desired = parseDesiredDnsState(readFileSync4(opts.file, "utf-8"), domain);
56539
56682
  const planDomain = desired.domain ?? domain;
56540
- const provider = getDnsProvider(providerName);
56683
+ const provider = resolveDnsProvider(providerName);
56541
56684
  const current = await provider.getDnsRecords(planDomain);
56542
56685
  const plan = createDnsPlan(planDomain, current, desired.records);
56543
56686
  if (!planHasChanges(plan)) {
56544
56687
  if (opts.json)
56545
- console.log(JSON.stringify({ applied: false, reason: "no-changes", plan }, null, 2));
56688
+ printLine(JSON.stringify({ applied: false, reason: "no-changes", plan }, null, 2));
56546
56689
  else
56547
56690
  printDnsPlan(plan);
56548
56691
  return;
@@ -56550,55 +56693,56 @@ function registerDnsCommands(program2) {
56550
56693
  const blockReason = getDnsApplyBlockReason(plan, { yes: opts.yes, allowDelete: opts.allowDelete });
56551
56694
  if (blockReason) {
56552
56695
  if (opts.json)
56553
- console.log(JSON.stringify({ applied: false, reason: blockReason, plan }, null, 2));
56696
+ printLine(JSON.stringify({ applied: false, reason: blockReason, plan }, null, 2));
56554
56697
  else {
56555
56698
  printDnsPlan(plan);
56556
56699
  if (blockReason === "confirmation-required")
56557
- console.error("Refusing to apply without --yes.");
56700
+ printErrorLine("Refusing to apply without --yes.");
56558
56701
  if (blockReason === "delete-confirmation-required")
56559
- console.error("Refusing to delete DNS records without --allow-delete.");
56702
+ printErrorLine("Refusing to delete DNS records without --allow-delete.");
56560
56703
  if (blockReason === "delete-apply-unsupported")
56561
- console.error(`Refusing to apply delete plan on ${providerName}: this provider path cannot guarantee delete convergence without partial mutation yet.`);
56704
+ printErrorLine(`Refusing to apply delete plan on ${providerName}: this provider path cannot guarantee delete convergence without partial mutation yet.`);
56562
56705
  }
56563
56706
  process.exit(1);
56564
56707
  }
56565
- await provider.setDnsRecords(planDomain, desired.records);
56708
+ const recordsToApply = provider.dnsWriteScope === "changed-groups" ? selectChangedDnsRecords(plan, desired.records) : desired.records;
56709
+ await provider.setDnsRecords(planDomain, recordsToApply);
56566
56710
  const verified = createDnsPlan(planDomain, await provider.getDnsRecords(planDomain), desired.records);
56567
56711
  if (planHasChanges(verified)) {
56568
56712
  if (opts.json)
56569
- console.log(JSON.stringify({ applied: false, provider: providerName, reason: "verification-failed", plan, verification: verified }, null, 2));
56713
+ printLine(JSON.stringify({ applied: false, provider: providerName, reason: "verification-failed", plan, verification: verified }, null, 2));
56570
56714
  else {
56571
56715
  printDnsPlan(verified);
56572
- console.error(`Provider ${providerName} did not converge to the desired DNS state for ${planDomain}.`);
56716
+ printErrorLine(`Provider ${providerName} did not converge to the desired DNS state for ${planDomain}.`);
56573
56717
  }
56574
56718
  process.exit(1);
56575
56719
  }
56576
56720
  if (opts.json)
56577
- console.log(JSON.stringify({ applied: true, provider: providerName, plan, verification: verified }, null, 2));
56721
+ printLine(JSON.stringify({ applied: true, provider: providerName, plan, verification: verified }, null, 2));
56578
56722
  else {
56579
56723
  printDnsPlan(plan);
56580
- console.log(`\u2713 Applied and verified desired DNS state on ${providerName} for ${planDomain}`);
56724
+ printLine(`\u2713 Applied and verified desired DNS state on ${providerName} for ${planDomain}`);
56581
56725
  }
56582
56726
  } catch (e4) {
56583
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56727
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56584
56728
  process.exit(1);
56585
56729
  }
56586
56730
  });
56587
56731
  dnsCmd.command("list").description("List DNS records for a domain").argument("<domain-id>", "Domain ID").option("--type <type>", "Filter by record type (A/AAAA/CNAME/MX/TXT/NS/SRV)").option("--limit <n>", "Limit number of displayed records").option("--all", "Show all matching records").option("--json", "Output as JSON", false).action(async (domainId, opts) => {
56588
56732
  const records = await listDnsRecords2(domainId, opts.type);
56589
56733
  if (opts.json) {
56590
- console.log(JSON.stringify(records, null, 2));
56734
+ printLine(JSON.stringify(records, null, 2));
56591
56735
  } else {
56592
56736
  const page = pageItemsOrExit(records, { limit: opts.limit, all: opts.all });
56593
56737
  if (page.items.length === 0) {
56594
- console.log("No DNS records found.");
56738
+ printLine("No DNS records found.");
56595
56739
  return;
56596
56740
  }
56597
56741
  for (const r4 of page.items) {
56598
56742
  const priority = r4.priority !== null ? ` (priority: ${r4.priority})` : "";
56599
- console.log(` ${r4.type} ${r4.name} ${truncateText(r4.value, 80)} TTL:${r4.ttl}${priority}`);
56743
+ printLine(` ${r4.type} ${r4.name} ${truncateText(r4.value, 80)} TTL:${r4.ttl}${priority}`);
56600
56744
  }
56601
- console.log(`
56745
+ printLine(`
56602
56746
  ${compactHint(page, "record(s)", "Use --all for every record or --json for full values.", { paging: "limit" })}`);
56603
56747
  }
56604
56748
  });
@@ -56612,9 +56756,9 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
56612
56756
  priority: opts.priority ? parseInt(opts.priority) : undefined
56613
56757
  });
56614
56758
  if (opts.json) {
56615
- console.log(JSON.stringify(record, null, 2));
56759
+ printLine(JSON.stringify(record, null, 2));
56616
56760
  } else {
56617
- console.log(`Created DNS record: ${record.type} ${record.name} -> ${record.value} (${record.id})`);
56761
+ printLine(`Created DNS record: ${record.type} ${record.name} -> ${record.value} (${record.id})`);
56618
56762
  }
56619
56763
  });
56620
56764
  dnsCmd.command("update").description("Update a DNS record").argument("<id>", "Record ID").option("--type <type>", "Record type").option("--name <name>", "Record name").option("--value <value>", "Record value").option("--ttl <ttl>", "TTL in seconds").option("--priority <n>", "Priority").option("--json", "Output as JSON", false).action(async (id, opts) => {
@@ -56631,21 +56775,21 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
56631
56775
  input.priority = parseInt(opts.priority);
56632
56776
  const record = await updateDnsRecord2(id, input);
56633
56777
  if (!record) {
56634
- console.error(`DNS record '${id}' not found.`);
56778
+ printErrorLine(`DNS record '${id}' not found.`);
56635
56779
  process.exit(1);
56636
56780
  }
56637
56781
  if (opts.json) {
56638
- console.log(JSON.stringify(record, null, 2));
56782
+ printLine(JSON.stringify(record, null, 2));
56639
56783
  } else {
56640
- console.log(`Updated DNS record: ${record.type} ${record.name} -> ${record.value}`);
56784
+ printLine(`Updated DNS record: ${record.type} ${record.name} -> ${record.value}`);
56641
56785
  }
56642
56786
  });
56643
56787
  dnsCmd.command("remove").description("Remove a DNS record").argument("<id>", "Record ID").action(async (id) => {
56644
56788
  const deleted = await deleteDnsRecord2(id);
56645
56789
  if (deleted) {
56646
- console.log(`Deleted DNS record ${id}`);
56790
+ printLine(`Deleted DNS record ${id}`);
56647
56791
  } else {
56648
- console.error(`DNS record '${id}' not found.`);
56792
+ printErrorLine(`DNS record '${id}' not found.`);
56649
56793
  process.exit(1);
56650
56794
  }
56651
56795
  });
@@ -56653,32 +56797,32 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
56653
56797
  try {
56654
56798
  const result = await checkDnsPropagation(domain, opts.record);
56655
56799
  if (opts.json) {
56656
- console.log(JSON.stringify(result, null, 2));
56800
+ printLine(JSON.stringify(result, null, 2));
56657
56801
  } else {
56658
- console.log(`DNS Propagation for ${result.domain} (${result.record_type}):`);
56659
- console.log(` Consistent: ${result.consistent ? "yes" : "NO"}`);
56802
+ printLine(`DNS Propagation for ${result.domain} (${result.record_type}):`);
56803
+ printLine(` Consistent: ${result.consistent ? "yes" : "NO"}`);
56660
56804
  for (const s2 of result.servers) {
56661
56805
  const values = s2.values.length > 0 ? s2.values.join(", ") : "(empty)";
56662
56806
  const status = s2.status === "error" ? ` [ERROR: ${s2.error}]` : "";
56663
- console.log(` ${s2.name} (${s2.server}): ${values}${status}`);
56807
+ printLine(` ${s2.name} (${s2.server}): ${values}${status}`);
56664
56808
  }
56665
56809
  }
56666
56810
  } catch (error) {
56667
- console.error(`DNS propagation check failed: ${error instanceof Error ? error.message : String(error)}`);
56811
+ printErrorLine(`DNS propagation check failed: ${error instanceof Error ? error.message : String(error)}`);
56668
56812
  process.exit(1);
56669
56813
  }
56670
56814
  });
56671
56815
  dnsCmd.command("export").description("Export DNS records as BIND zone file").argument("<domain-id>", "Domain ID").option("--output <file>", "Write to file instead of stdout").action(async (domainId, opts) => {
56672
56816
  const zone = await exportZoneFile(domainId);
56673
56817
  if (!zone) {
56674
- console.error(`Domain '${domainId}' not found.`);
56818
+ printErrorLine(`Domain '${domainId}' not found.`);
56675
56819
  process.exit(1);
56676
56820
  }
56677
56821
  if (opts.output) {
56678
56822
  writeFileSync2(opts.output, zone, "utf-8");
56679
- console.log(`Exported zone file to ${opts.output}`);
56823
+ printLine(`Exported zone file to ${opts.output}`);
56680
56824
  } else {
56681
- console.log(zone);
56825
+ printLine(zone);
56682
56826
  }
56683
56827
  });
56684
56828
  dnsCmd.command("import").description("Import DNS records from a BIND zone file").argument("<domain-id>", "Domain ID").requiredOption("--file <path>", "Path to zone file").option("--json", "Output as JSON", false).action(async (domainId, opts) => {
@@ -56686,22 +56830,22 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
56686
56830
  try {
56687
56831
  content = readFileSync4(opts.file, "utf-8");
56688
56832
  } catch {
56689
- console.error(`Could not read file: ${opts.file}`);
56833
+ printErrorLine(`Could not read file: ${opts.file}`);
56690
56834
  process.exit(1);
56691
56835
  }
56692
56836
  const result = await importZoneFile(domainId, content);
56693
56837
  if (!result) {
56694
- console.error(`Domain '${domainId}' not found.`);
56838
+ printErrorLine(`Domain '${domainId}' not found.`);
56695
56839
  process.exit(1);
56696
56840
  }
56697
56841
  if (opts.json) {
56698
- console.log(JSON.stringify(result, null, 2));
56842
+ printLine(JSON.stringify(result, null, 2));
56699
56843
  } else {
56700
- console.log(`Imported ${result.imported} record(s), skipped ${result.skipped}`);
56844
+ printLine(`Imported ${result.imported} record(s), skipped ${result.skipped}`);
56701
56845
  if (result.errors.length > 0) {
56702
- console.log("Errors:");
56846
+ printLine("Errors:");
56703
56847
  for (const e4 of result.errors) {
56704
- console.log(` - ${e4}`);
56848
+ printLine(` - ${e4}`);
56705
56849
  }
56706
56850
  }
56707
56851
  }
@@ -56709,42 +56853,42 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
56709
56853
  dnsCmd.command("discover-subdomains").description("Discover subdomains via certificate transparency logs (crt.sh)").argument("<domain>", "Domain name").option("--limit <n>", "Limit number of displayed subdomains").option("--all", "Show all discovered subdomains").option("--json", "Output as JSON", false).action(async (domain, opts) => {
56710
56854
  const result = await discoverSubdomains(domain);
56711
56855
  if (opts.json) {
56712
- console.log(JSON.stringify(result, null, 2));
56856
+ printLine(JSON.stringify(result, null, 2));
56713
56857
  } else {
56714
56858
  if (result.error) {
56715
- console.error(`Discovery failed: ${result.error}`);
56859
+ printErrorLine(`Discovery failed: ${result.error}`);
56716
56860
  process.exit(1);
56717
56861
  }
56718
56862
  if (result.subdomains.length === 0) {
56719
- console.log(`No subdomains found for ${domain}.`);
56863
+ printLine(`No subdomains found for ${domain}.`);
56720
56864
  return;
56721
56865
  }
56722
56866
  const page = pageItemsOrExit(result.subdomains, { limit: opts.limit, all: opts.all });
56723
- console.log(`Subdomains for ${domain} (source: ${result.source}):`);
56867
+ printLine(`Subdomains for ${domain} (source: ${result.source}):`);
56724
56868
  for (const s2 of page.items) {
56725
- console.log(` ${s2}`);
56869
+ printLine(` ${s2}`);
56726
56870
  }
56727
- console.log(`
56871
+ printLine(`
56728
56872
  ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --json for the full result.", { paging: "limit" })}`);
56729
56873
  }
56730
56874
  });
56731
56875
  dnsCmd.command("validate").description("Validate DNS records for common issues").argument("<domain-id>", "Domain ID").option("--json", "Output as JSON", false).action(async (domainId, opts) => {
56732
56876
  const result = await validateDns(domainId);
56733
56877
  if (!result) {
56734
- console.error(`Domain '${domainId}' not found.`);
56878
+ printErrorLine(`Domain '${domainId}' not found.`);
56735
56879
  process.exit(1);
56736
56880
  }
56737
56881
  if (opts.json) {
56738
- console.log(JSON.stringify(result, null, 2));
56882
+ printLine(JSON.stringify(result, null, 2));
56739
56883
  } else {
56740
- console.log(`DNS Validation for ${result.domain_name}:`);
56741
- console.log(` Valid: ${result.valid ? "yes" : "NO"}`);
56884
+ printLine(`DNS Validation for ${result.domain_name}:`);
56885
+ printLine(` Valid: ${result.valid ? "yes" : "NO"}`);
56742
56886
  if (result.issues.length === 0) {
56743
- console.log(" No issues found.");
56887
+ printLine(" No issues found.");
56744
56888
  } else {
56745
56889
  for (const issue of result.issues) {
56746
56890
  const prefix = issue.type === "error" ? "ERROR" : "WARN";
56747
- console.log(` [${prefix}] ${issue.message}`);
56891
+ printLine(` [${prefix}] ${issue.message}`);
56748
56892
  }
56749
56893
  }
56750
56894
  }
@@ -56752,11 +56896,11 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
56752
56896
  dnsCmd.command("pull <domain>").description("Pull live DNS records from provider into local DB").option("--provider <name>", "DNS provider (route53, cloudflare) \u2014 defaults to config default-dns").action(async (domain, opts) => {
56753
56897
  const providerName = opts.provider ?? loadConfig3().default_dns ?? "route53";
56754
56898
  try {
56755
- const provider = getDnsProvider(providerName);
56899
+ const provider = resolveDnsProvider(providerName);
56756
56900
  const records = await provider.getDnsRecords(domain);
56757
56901
  const dbDomain = await getDomainByName2(domain);
56758
56902
  if (!dbDomain) {
56759
- console.error(`Domain '${domain}' not found in local DB. Add it first: domains domain add --name ${domain}`);
56903
+ printErrorLine(`Domain '${domain}' not found in local DB. Add it first: domains domain add --name ${domain}`);
56760
56904
  process.exit(1);
56761
56905
  }
56762
56906
  const { keep, skipped } = partitionPullableRecords(records);
@@ -56765,13 +56909,13 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
56765
56909
  await createDnsRecord2({ domain_id: dbDomain.id, type: r4.type, name: r4.name, value: r4.value, ttl: r4.ttl, priority: r4.priority });
56766
56910
  count++;
56767
56911
  }
56768
- console.log(`\u2713 Pulled ${count} record(s) from ${providerName} into local DB for ${domain}`);
56912
+ printLine(`\u2713 Pulled ${count} record(s) from ${providerName} into local DB for ${domain}`);
56769
56913
  if (skipped.size > 0) {
56770
56914
  const summary = Array.from(skipped.entries()).map(([t2, n2]) => `${n2} ${t2}`).join(", ");
56771
- console.log(` Skipped ${summary} record(s) (unsupported/provider-managed type).`);
56915
+ printLine(` Skipped ${summary} record(s) (unsupported/provider-managed type).`);
56772
56916
  }
56773
56917
  } catch (e4) {
56774
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56918
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56775
56919
  process.exit(1);
56776
56920
  }
56777
56921
  });
@@ -56780,13 +56924,13 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
56780
56924
  try {
56781
56925
  const records = await listDnsRecords2(domainId);
56782
56926
  if (records.length === 0) {
56783
- console.log("No local DNS records to push.");
56927
+ printLine("No local DNS records to push.");
56784
56928
  return;
56785
56929
  }
56786
56930
  const dbDomain = await getDomain2(domainId) ?? (() => {
56787
56931
  throw new Error(`Domain '${domainId}' not found`);
56788
56932
  })();
56789
- const provider = getDnsProvider(providerName);
56933
+ const provider = resolveDnsProvider(providerName);
56790
56934
  await provider.setDnsRecords(dbDomain.name, records.map((r4) => ({
56791
56935
  type: r4.type,
56792
56936
  name: r4.name,
@@ -56794,9 +56938,9 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
56794
56938
  ttl: r4.ttl,
56795
56939
  priority: r4.priority ?? undefined
56796
56940
  })));
56797
- console.log(`\u2713 Pushed ${records.length} record(s) to ${providerName} for ${dbDomain.name}`);
56941
+ printLine(`\u2713 Pushed ${records.length} record(s) to ${providerName} for ${dbDomain.name}`);
56798
56942
  } catch (e4) {
56799
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56943
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56800
56944
  process.exit(1);
56801
56945
  }
56802
56946
  });
@@ -56806,6 +56950,7 @@ ${compactHint(page, "subdomain(s)", "Use --all for every discovered name or --js
56806
56950
  init_config();
56807
56951
  init_route53();
56808
56952
  init_cloudflare();
56953
+ init_stdout();
56809
56954
  function resolveProvider(flag) {
56810
56955
  return flag ?? loadConfig3().default_dns ?? "route53";
56811
56956
  }
@@ -56821,24 +56966,24 @@ function registerZoneCommand(program2) {
56821
56966
  zones = await listHostedZones();
56822
56967
  }
56823
56968
  if (opts.json) {
56824
- console.log(JSON.stringify(zones, null, 2));
56969
+ printLine(JSON.stringify(zones, null, 2));
56825
56970
  return;
56826
56971
  }
56827
56972
  const page = pageItemsOrExit(zones, { limit: opts.limit, all: opts.all });
56828
56973
  if (page.items.length === 0) {
56829
- console.log("No hosted zones.");
56974
+ printLine("No hosted zones.");
56830
56975
  return;
56831
56976
  }
56832
- console.log(`
56977
+ printLine(`
56833
56978
  Hosted Zones (${provider}):`);
56834
56979
  for (const z of page.items) {
56835
56980
  const extra = z.record_count !== undefined ? ` ${z.record_count} records` : "";
56836
- console.log(` ${z.id.padEnd(32)} ${z.name}${extra}`);
56981
+ printLine(` ${z.id.padEnd(32)} ${z.name}${extra}`);
56837
56982
  }
56838
- console.log(`
56983
+ printLine(`
56839
56984
  ${compactHint(page, "zone(s)", "Use --all for every zone or zone info <zoneId> for details.", { paging: "limit" })}`);
56840
56985
  } catch (e4) {
56841
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56986
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56842
56987
  process.exit(1);
56843
56988
  }
56844
56989
  });
@@ -56847,23 +56992,23 @@ ${compactHint(page, "zone(s)", "Use --all for every zone or zone info <zoneId> f
56847
56992
  try {
56848
56993
  if (provider === "cloudflare") {
56849
56994
  const z = await createZone(domain);
56850
- console.log(`\u2713 Zone created: ${domain} (${z.id})`);
56995
+ printLine(`\u2713 Zone created: ${domain} (${z.id})`);
56851
56996
  if (z.nameservers?.length) {
56852
- console.log(` Name servers:`);
56997
+ printLine(` Name servers:`);
56853
56998
  for (const ns of z.nameservers)
56854
- console.log(` ${ns}`);
56999
+ printLine(` ${ns}`);
56855
57000
  }
56856
57001
  } else {
56857
57002
  const z = await createHostedZone(domain, opts.comment);
56858
- console.log(`\u2713 Zone created: ${domain} (${z.id})`);
57003
+ printLine(`\u2713 Zone created: ${domain} (${z.id})`);
56859
57004
  if (z.name_servers?.length) {
56860
- console.log(` Name servers:`);
57005
+ printLine(` Name servers:`);
56861
57006
  for (const ns of z.name_servers)
56862
- console.log(` ${ns}`);
57007
+ printLine(` ${ns}`);
56863
57008
  }
56864
57009
  }
56865
57010
  } catch (e4) {
56866
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
57011
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56867
57012
  process.exit(1);
56868
57013
  }
56869
57014
  });
@@ -56874,44 +57019,44 @@ ${compactHint(page, "zone(s)", "Use --all for every zone or zone info <zoneId> f
56874
57019
  const zones = await listZones();
56875
57020
  const z = zones.find((z2) => z2.id === zoneId || z2.name === zoneId);
56876
57021
  if (!z) {
56877
- console.error(`Zone not found: ${zoneId}`);
57022
+ printErrorLine(`Zone not found: ${zoneId}`);
56878
57023
  process.exit(1);
56879
57024
  }
56880
57025
  if (opts.json) {
56881
- console.log(JSON.stringify(z, null, 2));
57026
+ printLine(JSON.stringify(z, null, 2));
56882
57027
  return;
56883
57028
  }
56884
- console.log(`
57029
+ printLine(`
56885
57030
  Zone: ${z.name}`);
56886
- console.log(` ID: ${z.id}`);
56887
- console.log(` Status: ${z.status}`);
57031
+ printLine(` ID: ${z.id}`);
57032
+ printLine(` Status: ${z.status}`);
56888
57033
  if (z.nameservers?.length) {
56889
- console.log(` Name servers:`);
57034
+ printLine(` Name servers:`);
56890
57035
  for (const ns of z.nameservers)
56891
- console.log(` ${ns}`);
57036
+ printLine(` ${ns}`);
56892
57037
  }
56893
- console.log();
57038
+ printLine();
56894
57039
  } else {
56895
57040
  const z = await getHostedZone(zoneId);
56896
57041
  if (opts.json) {
56897
- console.log(JSON.stringify(z, null, 2));
57042
+ printLine(JSON.stringify(z, null, 2));
56898
57043
  return;
56899
57044
  }
56900
- console.log(`
57045
+ printLine(`
56901
57046
  Zone: ${z.name}`);
56902
- console.log(` ID: ${z.id}`);
56903
- console.log(` Records: ${z.record_count}`);
57047
+ printLine(` ID: ${z.id}`);
57048
+ printLine(` Records: ${z.record_count}`);
56904
57049
  if (z.comment)
56905
- console.log(` Comment: ${z.comment}`);
57050
+ printLine(` Comment: ${z.comment}`);
56906
57051
  if (z.name_servers?.length) {
56907
- console.log(` Name servers:`);
57052
+ printLine(` Name servers:`);
56908
57053
  for (const ns of z.name_servers)
56909
- console.log(` ${ns}`);
57054
+ printLine(` ${ns}`);
56910
57055
  }
56911
- console.log();
57056
+ printLine();
56912
57057
  }
56913
57058
  } catch (e4) {
56914
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
57059
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56915
57060
  process.exit(1);
56916
57061
  }
56917
57062
  });
@@ -56919,8 +57064,8 @@ Zone: ${z.name}`);
56919
57064
  const provider = resolveProvider(opts.provider);
56920
57065
  try {
56921
57066
  if (!opts.force) {
56922
- console.log(`Would delete zone: ${zoneId} (${provider})`);
56923
- console.log("Re-run with --force to confirm.");
57067
+ printLine(`Would delete zone: ${zoneId} (${provider})`);
57068
+ printLine("Re-run with --force to confirm.");
56924
57069
  return;
56925
57070
  }
56926
57071
  if (provider === "cloudflare") {
@@ -56928,9 +57073,9 @@ Zone: ${z.name}`);
56928
57073
  } else {
56929
57074
  await deleteHostedZone(zoneId);
56930
57075
  }
56931
- console.log(`\u2713 Zone deleted: ${zoneId}`);
57076
+ printLine(`\u2713 Zone deleted: ${zoneId}`);
56932
57077
  } catch (e4) {
56933
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
57078
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
56934
57079
  process.exit(1);
56935
57080
  }
56936
57081
  });
@@ -56938,52 +57083,54 @@ Zone: ${z.name}`);
56938
57083
 
56939
57084
  // src/cli/commands/ssl.ts
56940
57085
  init_domains();
57086
+ init_stdout();
56941
57087
  function registerSslCommand(program2) {
56942
57088
  const ssl = program2.command("ssl").description("SSL certificate management");
56943
57089
  ssl.command("check <domain>").description("Check SSL certificate for a domain and update the local DB record").option("--json", "Output JSON").action(async (domain, opts) => {
56944
57090
  try {
56945
57091
  const result = await checkSsl(domain);
56946
57092
  if (opts.json) {
56947
- console.log(JSON.stringify(result, null, 2));
57093
+ printLine(JSON.stringify(result, null, 2));
56948
57094
  return;
56949
57095
  }
56950
- console.log(`
57096
+ printLine(`
56951
57097
  SSL Certificate for ${result.domain}:`);
56952
57098
  if (result.error) {
56953
- console.log(` Error: ${result.error}`);
57099
+ printLine(` Error: ${result.error}`);
56954
57100
  } else {
56955
- console.log(` Issuer: ${result.issuer ?? "unknown"}`);
56956
- console.log(` Expires: ${result.expires_at ? result.expires_at.split("T")[0] : "unknown"}`);
57101
+ printLine(` Issuer: ${result.issuer ?? "unknown"}`);
57102
+ printLine(` Expires: ${result.expires_at ? result.expires_at.split("T")[0] : "unknown"}`);
56957
57103
  }
56958
- console.log();
57104
+ printLine();
56959
57105
  } catch (error) {
56960
- console.error(`SSL check failed: ${error instanceof Error ? error.message : String(error)}`);
57106
+ printErrorLine(`SSL check failed: ${error instanceof Error ? error.message : String(error)}`);
56961
57107
  process.exit(1);
56962
57108
  }
56963
57109
  });
56964
57110
  ssl.command("expiring").description("List domains with SSL certificates expiring soon").option("--days <n>", "Days threshold", "30").option("--limit <n>", "Limit number of displayed domains").option("--all", "Show all matching domains").option("--json", "Output JSON").action(async (opts) => {
56965
57111
  const domains = await listSslExpiring2(parseInt(opts.days));
56966
57112
  if (opts.json) {
56967
- console.log(JSON.stringify(domains, null, 2));
57113
+ printLine(JSON.stringify(domains, null, 2));
56968
57114
  return;
56969
57115
  }
56970
57116
  const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
56971
57117
  if (page.items.length === 0) {
56972
- console.log(`No SSL certificates expiring within ${opts.days} days.`);
57118
+ printLine(`No SSL certificates expiring within ${opts.days} days.`);
56973
57119
  return;
56974
57120
  }
56975
- console.log(`
57121
+ printLine(`
56976
57122
  SSL expiring within ${opts.days} days:`);
56977
57123
  for (const d4 of page.items) {
56978
57124
  const exp = d4.ssl_expires_at ? formatDate(d4.ssl_expires_at) : "unknown";
56979
- console.log(` ${d4.name.padEnd(40)} expires ${exp}`);
57125
+ printLine(` ${d4.name.padEnd(40)} expires ${exp}`);
56980
57126
  }
56981
- console.log(`
57127
+ printLine(`
56982
57128
  ${compactHint(page, "domain(s)", "Use --all to display every matching SSL certificate.", { paging: "limit" })}`);
56983
57129
  });
56984
57130
  }
56985
57131
 
56986
57132
  // src/cli/commands/alerts.ts
57133
+ init_stdout();
56987
57134
  init_domains();
56988
57135
  function registerAlertCommands(program2) {
56989
57136
  const alertCmd = program2.command("alert").description("Alert management");
@@ -56994,40 +57141,41 @@ function registerAlertCommands(program2) {
56994
57141
  trigger_days_before: opts.daysBefore ? parseInt(opts.daysBefore) : undefined
56995
57142
  });
56996
57143
  if (opts.json) {
56997
- console.log(JSON.stringify(alert, null, 2));
57144
+ printLine(JSON.stringify(alert, null, 2));
56998
57145
  } else {
56999
57146
  const daysBefore = alert.trigger_days_before ? ` (${alert.trigger_days_before} days before)` : "";
57000
- console.log(`Created alert: ${alert.type}${daysBefore} for domain ${alert.domain_id} (${alert.id})`);
57147
+ printLine(`Created alert: ${alert.type}${daysBefore} for domain ${alert.domain_id} (${alert.id})`);
57001
57148
  }
57002
57149
  });
57003
57150
  alertCmd.command("list").description("List alerts for a domain").argument("<domain-id>", "Domain ID").option("--json", "Output as JSON", false).action(async (domainId, opts) => {
57004
57151
  const alerts = await listAlerts2(domainId);
57005
57152
  if (opts.json) {
57006
- console.log(JSON.stringify(alerts, null, 2));
57153
+ printLine(JSON.stringify(alerts, null, 2));
57007
57154
  } else {
57008
57155
  if (alerts.length === 0) {
57009
- console.log("No alerts set.");
57156
+ printLine("No alerts set.");
57010
57157
  return;
57011
57158
  }
57012
57159
  for (const a4 of alerts) {
57013
57160
  const daysBefore = a4.trigger_days_before ? ` (${a4.trigger_days_before} days before)` : "";
57014
57161
  const sent = a4.sent_at ? ` \u2014 sent ${a4.sent_at}` : "";
57015
- console.log(` ${a4.type}${daysBefore}${sent}`);
57162
+ printLine(` ${a4.type}${daysBefore}${sent}`);
57016
57163
  }
57017
57164
  }
57018
57165
  });
57019
57166
  alertCmd.command("remove").description("Remove an alert").argument("<id>", "Alert ID").action(async (id) => {
57020
57167
  const deleted = await deleteAlert2(id);
57021
57168
  if (deleted) {
57022
- console.log(`Deleted alert ${id}`);
57169
+ printLine(`Deleted alert ${id}`);
57023
57170
  } else {
57024
- console.error(`Alert '${id}' not found.`);
57171
+ printErrorLine(`Alert '${id}' not found.`);
57025
57172
  process.exit(1);
57026
57173
  }
57027
57174
  });
57028
57175
  }
57029
57176
 
57030
57177
  // src/cli/commands/provider.ts
57178
+ init_stdout();
57031
57179
  function isAwsAccessDenied(error) {
57032
57180
  const msg = error instanceof Error ? error.message : String(error);
57033
57181
  return msg.includes("AccessDenied") || msg.includes("route53domains:ListDomains");
@@ -57037,21 +57185,21 @@ function registerProviderCommand(program2) {
57037
57185
  provider.command("list").description("Show all providers and their configuration status").option("-j, --json", "Output JSON").action((opts) => {
57038
57186
  const providers = getAvailableProviders();
57039
57187
  if (opts.json) {
57040
- console.log(JSON.stringify(providers, null, 2));
57188
+ printLine(JSON.stringify(providers, null, 2));
57041
57189
  return;
57042
57190
  }
57043
- console.log(`
57191
+ printLine(`
57044
57192
  Registrar / DNS Providers:`);
57045
57193
  for (const p2 of providers) {
57046
57194
  const status = p2.configured ? "\u2713 configured" : "\u2717 not configured";
57047
57195
  const type = p2.type === "full" ? "registrar + dns" : p2.type;
57048
57196
  const capabilities = [type, p2.inventory ? "inventory" : null].filter(Boolean).join(", ");
57049
- console.log(` ${p2.name.padEnd(12)} [${capabilities}] ${status}`);
57197
+ printLine(` ${p2.name.padEnd(12)} [${capabilities}] ${status}`);
57050
57198
  if (!p2.configured) {
57051
- console.log(` Missing: ${p2.envVars.join(", ")}`);
57199
+ printLine(` Missing: ${p2.envVars.join(", ")}`);
57052
57200
  }
57053
57201
  }
57054
- console.log();
57202
+ printLine();
57055
57203
  });
57056
57204
  provider.command("test <name>").description("Live-test a provider's credentials").option("-j, --json", "Output JSON").action(async (name, opts) => {
57057
57205
  const providerName = name.toLowerCase();
@@ -57060,16 +57208,16 @@ Registrar / DNS Providers:`);
57060
57208
  if (!info) {
57061
57209
  const error = `Unknown provider: ${name}`;
57062
57210
  if (opts.json) {
57063
- console.log(JSON.stringify({ provider: providerName, ok: false, error }, null, 2));
57211
+ printLine(JSON.stringify({ provider: providerName, ok: false, error }, null, 2));
57064
57212
  } else {
57065
- console.error(error);
57213
+ printErrorLine(error);
57066
57214
  }
57067
57215
  process.exit(1);
57068
57216
  }
57069
57217
  if (!info.configured) {
57070
57218
  const error = `${providerName} is not configured. Set: ${info.envVars.join(", ")}`;
57071
57219
  if (opts.json) {
57072
- console.log(JSON.stringify({
57220
+ printLine(JSON.stringify({
57073
57221
  provider: providerName,
57074
57222
  ok: false,
57075
57223
  configured: false,
@@ -57077,12 +57225,12 @@ Registrar / DNS Providers:`);
57077
57225
  error
57078
57226
  }, null, 2));
57079
57227
  } else {
57080
- console.error(`\u2717 ${error}`);
57228
+ printErrorLine(`\u2717 ${error}`);
57081
57229
  }
57082
57230
  process.exit(1);
57083
57231
  }
57084
57232
  if (!opts.json) {
57085
- console.log(`Testing ${providerName}...`);
57233
+ printLine(`Testing ${providerName}...`);
57086
57234
  }
57087
57235
  let registrarOk = null;
57088
57236
  let dnsOk = null;
@@ -57096,21 +57244,21 @@ Registrar / DNS Providers:`);
57096
57244
  await listRegisteredDomains2();
57097
57245
  registrarOk = true;
57098
57246
  if (!opts.json)
57099
- console.log("\u2713 Registrar connection OK");
57247
+ printLine("\u2713 Registrar connection OK");
57100
57248
  } catch (error) {
57101
57249
  if (!isAwsAccessDenied(error))
57102
57250
  throw error;
57103
57251
  registrarOk = false;
57104
57252
  notes.push("route53domains-listdomains-access-denied");
57105
57253
  if (!opts.json)
57106
- console.log("\u2022 Route53 Domains registrar API is not available for these AWS credentials");
57254
+ printLine("\u2022 Route53 Domains registrar API is not available for these AWS credentials");
57107
57255
  }
57108
57256
  } else {
57109
57257
  const reg = getRegistrarProvider(providerName);
57110
57258
  await reg.listDomains();
57111
57259
  registrarOk = true;
57112
57260
  if (!opts.json)
57113
- console.log("\u2713 Registrar connection OK");
57261
+ printLine("\u2713 Registrar connection OK");
57114
57262
  }
57115
57263
  }
57116
57264
  if (info.type === "dns" || info.type === "full") {
@@ -57118,13 +57266,13 @@ Registrar / DNS Providers:`);
57118
57266
  dnsOk = null;
57119
57267
  notes.push("dns-not-probed-with-synthetic-invalid-domain");
57120
57268
  if (!opts.json)
57121
- console.log("\u2022 DNS not probed with synthetic invalid domain");
57269
+ printLine("\u2022 DNS not probed with synthetic invalid domain");
57122
57270
  } else {
57123
57271
  const dns = getDnsProvider(providerName);
57124
57272
  await dns.getDnsRecords("__test_nonexistent_domain__.invalid");
57125
57273
  dnsOk = true;
57126
57274
  if (!opts.json)
57127
- console.log("\u2713 DNS connection OK");
57275
+ printLine("\u2713 DNS connection OK");
57128
57276
  }
57129
57277
  }
57130
57278
  if (info.type === "marketplace") {
@@ -57134,10 +57282,10 @@ Registrar / DNS Providers:`);
57134
57282
  await listSedoPortfolio2({ limit: 1 });
57135
57283
  marketplaceOk = true;
57136
57284
  if (!opts.json)
57137
- console.log("\u2713 Marketplace connection OK");
57285
+ printLine("\u2713 Marketplace connection OK");
57138
57286
  }
57139
57287
  if (opts.json) {
57140
- console.log(JSON.stringify({
57288
+ printLine(JSON.stringify({
57141
57289
  provider: providerName,
57142
57290
  ok: true,
57143
57291
  configured: true,
@@ -57152,7 +57300,7 @@ Registrar / DNS Providers:`);
57152
57300
  const msg = e4 instanceof Error ? e4.message : String(e4);
57153
57301
  if (msg.includes("not found") || msg.includes("No hosted zone") || msg.includes("NXDOMAIN")) {
57154
57302
  if (opts.json) {
57155
- console.log(JSON.stringify({
57303
+ printLine(JSON.stringify({
57156
57304
  provider: providerName,
57157
57305
  ok: true,
57158
57306
  configured: true,
@@ -57164,12 +57312,12 @@ Registrar / DNS Providers:`);
57164
57312
  ...notes.length > 0 ? { notes } : {}
57165
57313
  }, null, 2));
57166
57314
  } else {
57167
- console.log("\u2713 Connection OK (no domains yet)");
57315
+ printLine("\u2713 Connection OK (no domains yet)");
57168
57316
  }
57169
57317
  return;
57170
57318
  }
57171
57319
  if (opts.json) {
57172
- console.log(JSON.stringify({
57320
+ printLine(JSON.stringify({
57173
57321
  provider: providerName,
57174
57322
  ok: false,
57175
57323
  configured: true,
@@ -57180,7 +57328,7 @@ Registrar / DNS Providers:`);
57180
57328
  error: msg
57181
57329
  }, null, 2));
57182
57330
  } else {
57183
- console.error(`\u2717 ${providerName} test failed: ${msg}`);
57331
+ printErrorLine(`\u2717 ${providerName} test failed: ${msg}`);
57184
57332
  }
57185
57333
  process.exit(1);
57186
57334
  }
@@ -57189,6 +57337,7 @@ Registrar / DNS Providers:`);
57189
57337
 
57190
57338
  // src/cli/commands/providers.ts
57191
57339
  init_config();
57340
+ init_stdout();
57192
57341
  init_domains();
57193
57342
  function registrarProviderNames() {
57194
57343
  return getAvailableProviders().filter((p2) => providerHasRegistrar(p2.name)).map((p2) => p2.name).join(", ");
@@ -57218,15 +57367,15 @@ function registerProviderCommands(program2) {
57218
57367
  program2.command("providers").description("Show which providers are configured").option("--json", "Output as JSON", false).action((opts) => {
57219
57368
  const providers = getAvailableProviders();
57220
57369
  if (opts.json) {
57221
- console.log(JSON.stringify(providers, null, 2));
57370
+ printLine(JSON.stringify(providers, null, 2));
57222
57371
  } else {
57223
- console.log("Providers:");
57372
+ printLine("Providers:");
57224
57373
  for (const p2 of providers) {
57225
57374
  const status = p2.configured ? "CONFIGURED" : "not configured";
57226
57375
  const capabilities = [p2.type, p2.inventory ? "inventory" : null].filter(Boolean).join(", ");
57227
- console.log(` ${p2.name} [${capabilities}]: ${status}`);
57376
+ printLine(` ${p2.name} [${capabilities}]: ${status}`);
57228
57377
  if (!p2.configured) {
57229
- console.log(` Accepted env: ${p2.envVars.join(", ")}`);
57378
+ printLine(` Accepted env: ${p2.envVars.join(", ")}`);
57230
57379
  }
57231
57380
  }
57232
57381
  }
@@ -57240,28 +57389,28 @@ function registerProviderCommands(program2) {
57240
57389
  updateDomain: updateDomain2
57241
57390
  });
57242
57391
  if (opts.json) {
57243
- console.log(JSON.stringify(result, null, 2));
57392
+ printLine(JSON.stringify(result, null, 2));
57244
57393
  } else {
57245
- console.log(`Synced ${result.totalSynced} domain(s) from ${result.providers.length} provider(s)`);
57394
+ printLine(`Synced ${result.totalSynced} domain(s) from ${result.providers.length} provider(s)`);
57246
57395
  for (const p2 of result.providers) {
57247
- console.log(` ${p2.name}: ${p2.result.synced} synced (${p2.result.created} new, ${p2.result.updated} updated)`);
57396
+ printLine(` ${p2.name}: ${p2.result.synced} synced (${p2.result.created} new, ${p2.result.updated} updated)`);
57248
57397
  }
57249
57398
  if (result.totalErrors.length > 0) {
57250
- console.log("Errors:");
57399
+ printLine("Errors:");
57251
57400
  for (const e4 of result.totalErrors) {
57252
- console.log(` - ${e4}`);
57401
+ printLine(` - ${e4}`);
57253
57402
  }
57254
57403
  }
57255
57404
  }
57256
57405
  } catch (error) {
57257
- console.error(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
57406
+ printErrorLine(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
57258
57407
  process.exit(1);
57259
57408
  }
57260
57409
  return;
57261
57410
  }
57262
57411
  const provider = (opts.provider || "").toLowerCase();
57263
57412
  if (!provider) {
57264
- console.error("Specify --provider <name> or --all");
57413
+ printErrorLine("Specify --provider <name> or --all");
57265
57414
  process.exit(1);
57266
57415
  }
57267
57416
  try {
@@ -57272,17 +57421,17 @@ function registerProviderCommands(program2) {
57272
57421
  updateDomain: updateDomain2
57273
57422
  });
57274
57423
  if (opts.json) {
57275
- console.log(JSON.stringify({ provider, ...result }, null, 2));
57424
+ printLine(JSON.stringify({ provider, ...result }, null, 2));
57276
57425
  } else {
57277
- console.log(`Synced ${result.synced} domain(s) from ${provider} (${result.created} new, ${result.updated} updated)`);
57426
+ printLine(`Synced ${result.synced} domain(s) from ${provider} (${result.created} new, ${result.updated} updated)`);
57278
57427
  if (result.errors.length > 0) {
57279
- console.log("Errors:");
57428
+ printLine("Errors:");
57280
57429
  for (const e4 of result.errors)
57281
- console.log(` - ${e4}`);
57430
+ printLine(` - ${e4}`);
57282
57431
  }
57283
57432
  }
57284
57433
  } catch (error) {
57285
- console.error(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
57434
+ printErrorLine(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
57286
57435
  process.exit(1);
57287
57436
  }
57288
57437
  });
@@ -57291,12 +57440,12 @@ function registerProviderCommands(program2) {
57291
57440
  if (!provider) {
57292
57441
  const detected = autoDetectRegistrar(name, getDomainByName2);
57293
57442
  if (!detected) {
57294
- console.error(`Could not auto-detect registrar for '${name}'. Use --provider.`);
57443
+ printErrorLine(`Could not auto-detect registrar for '${name}'. Use --provider.`);
57295
57444
  process.exit(1);
57296
57445
  }
57297
57446
  provider = detected;
57298
57447
  if (!opts.json)
57299
- console.log(`Auto-detected registrar: ${provider}`);
57448
+ printLine(`Auto-detected registrar: ${provider}`);
57300
57449
  }
57301
57450
  try {
57302
57451
  requireRegistrarProvider(provider);
@@ -57305,16 +57454,16 @@ function registerProviderCommands(program2) {
57305
57454
  throw new Error(`Renewal failed or is not supported for ${provider}`);
57306
57455
  }
57307
57456
  if (opts.json) {
57308
- console.log(JSON.stringify({ provider, ...result }, null, 2));
57457
+ printLine(JSON.stringify({ provider, ...result }, null, 2));
57309
57458
  } else {
57310
- console.log(`Renewed ${result.domain} successfully via ${provider}`);
57459
+ printLine(`Renewed ${result.domain} successfully via ${provider}`);
57311
57460
  if (result.chargedAmount)
57312
- console.log(` Charged: $${result.chargedAmount}`);
57461
+ printLine(` Charged: $${result.chargedAmount}`);
57313
57462
  if (result.orderId)
57314
- console.log(` Order ID: ${result.orderId}`);
57463
+ printLine(` Order ID: ${result.orderId}`);
57315
57464
  }
57316
57465
  } catch (error) {
57317
- console.error(`Renewal failed: ${error instanceof Error ? error.message : String(error)}`);
57466
+ printErrorLine(`Renewal failed: ${error instanceof Error ? error.message : String(error)}`);
57318
57467
  process.exit(1);
57319
57468
  }
57320
57469
  });
@@ -57324,18 +57473,18 @@ function registerProviderCommands(program2) {
57324
57473
  requireRegistrarProvider(providerName);
57325
57474
  const result = await getRegistrarProvider(providerName).checkAvailability(name);
57326
57475
  if (opts.json) {
57327
- console.log(JSON.stringify({ provider: providerName, ...result }, null, 2));
57476
+ printLine(JSON.stringify({ provider: providerName, ...result }, null, 2));
57328
57477
  } else {
57329
- console.log(`${result.domain} is ${result.available ? "AVAILABLE" : "NOT available"} (via ${providerName})`);
57478
+ printLine(`${result.domain} is ${result.available ? "AVAILABLE" : "NOT available"} (via ${providerName})`);
57330
57479
  if (result.is_premium)
57331
- console.log(` Premium ask: ${result.premium_price ?? "unknown"}`);
57480
+ printLine(` Premium ask: ${result.premium_price ?? "unknown"}`);
57332
57481
  if (result.standard_price !== undefined) {
57333
57482
  const currency = result.currency ? ` ${result.currency}` : "";
57334
- console.log(` Standard price: ${result.standard_price}${currency}`);
57483
+ printLine(` Standard price: ${result.standard_price}${currency}`);
57335
57484
  }
57336
57485
  }
57337
57486
  } catch (error) {
57338
- console.error(`Availability check failed: ${error instanceof Error ? error.message : String(error)}`);
57487
+ printErrorLine(`Availability check failed: ${error instanceof Error ? error.message : String(error)}`);
57339
57488
  process.exit(1);
57340
57489
  }
57341
57490
  });
@@ -57343,6 +57492,7 @@ function registerProviderCommands(program2) {
57343
57492
 
57344
57493
  // src/cli/commands/config.ts
57345
57494
  init_config();
57495
+ init_stdout();
57346
57496
  var VALID_KEYS = [
57347
57497
  "default-registrar",
57348
57498
  "default-dns",
@@ -57363,33 +57513,33 @@ function registerConfigCommands(program2) {
57363
57513
  config2.command("show").description("Show current configuration").option("--json", "Output JSON").action((opts) => {
57364
57514
  const cfg = loadConfig3();
57365
57515
  if (opts.json) {
57366
- console.log(JSON.stringify(cfg, null, 2));
57516
+ printLine(JSON.stringify(cfg, null, 2));
57367
57517
  return;
57368
57518
  }
57369
- console.log(`
57519
+ printLine(`
57370
57520
  Configuration:`);
57371
- console.log(` default-registrar: ${cfg.default_registrar ?? "(not set)"}`);
57372
- console.log(` default-dns: ${cfg.default_dns ?? "(not set)"}`);
57373
- console.log(` purchase-aws-profile: ${cfg.purchase_aws_profile ?? "(not set)"}`);
57521
+ printLine(` default-registrar: ${cfg.default_registrar ?? "(not set)"}`);
57522
+ printLine(` default-dns: ${cfg.default_dns ?? "(not set)"}`);
57523
+ printLine(` purchase-aws-profile: ${cfg.purchase_aws_profile ?? "(not set)"}`);
57374
57524
  if (cfg.contact && Object.keys(cfg.contact).length > 0) {
57375
- console.log(`
57525
+ printLine(`
57376
57526
  contact:`);
57377
57527
  for (const [k4, v2] of Object.entries(cfg.contact)) {
57378
57528
  if (v2)
57379
- console.log(` ${k4}: ${v2}`);
57529
+ printLine(` ${k4}: ${v2}`);
57380
57530
  }
57381
57531
  } else {
57382
- console.log(" contact: (not set)");
57532
+ printLine(" contact: (not set)");
57383
57533
  }
57384
- console.log();
57534
+ printLine();
57385
57535
  });
57386
57536
  config2.command("set <key> <value>").description(`Set a config value. Keys: ${VALID_KEYS.join(", ")}`).action((key, value) => {
57387
57537
  const normalized = key.replace(/-/g, "_");
57388
57538
  try {
57389
57539
  setConfigKey(normalized, value);
57390
- console.log(`\u2713 Set ${key} = ${value}`);
57540
+ printLine(`\u2713 Set ${key} = ${value}`);
57391
57541
  } catch (e4) {
57392
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
57542
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
57393
57543
  process.exit(1);
57394
57544
  }
57395
57545
  });
@@ -57403,13 +57553,14 @@ Configuration:`);
57403
57553
  delete cfg.contact[parts[1]];
57404
57554
  }
57405
57555
  saveConfig(cfg);
57406
- console.log(`\u2713 Unset ${key}`);
57556
+ printLine(`\u2713 Unset ${key}`);
57407
57557
  });
57408
57558
  }
57409
57559
 
57410
57560
  // src/cli/commands/doctor.ts
57411
57561
  init_config();
57412
57562
  init_domains();
57563
+ init_stdout();
57413
57564
  import { execSync } from "child_process";
57414
57565
  function registerDoctorCommand(program2) {
57415
57566
  program2.command("doctor").description("Run diagnostics \u2014 check credentials, DB, and provider connectivity").option("--json", "Output structured JSON").action(async (opts) => {
@@ -57420,22 +57571,22 @@ function registerDoctorCommand(program2) {
57420
57571
  function section(name) {
57421
57572
  currentSection = name;
57422
57573
  if (!opts.json) {
57423
- console.log(`
57574
+ printLine(`
57424
57575
  \u2500\u2500 ${name} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
57425
57576
  }
57426
57577
  }
57427
57578
  function ok(msg) {
57428
57579
  checks.push({ section: currentSection, status: "pass", message: msg });
57429
57580
  if (!opts.json)
57430
- console.log(` \u2713 ${msg}`);
57581
+ printLine(` \u2713 ${msg}`);
57431
57582
  passed++;
57432
57583
  }
57433
57584
  function fail(msg, fix) {
57434
57585
  checks.push({ section: currentSection, status: "fail", message: msg, fix });
57435
57586
  if (!opts.json) {
57436
- console.log(` \u2717 ${msg}`);
57587
+ printLine(` \u2717 ${msg}`);
57437
57588
  if (fix)
57438
- console.log(` \u2192 ${fix}`);
57589
+ printLine(` \u2192 ${fix}`);
57439
57590
  }
57440
57591
  failed++;
57441
57592
  }
@@ -57514,16 +57665,16 @@ function registerDoctorCommand(program2) {
57514
57665
  fail("whois not installed", "apt install whois / brew install whois");
57515
57666
  }
57516
57667
  if (opts.json) {
57517
- console.log(JSON.stringify({
57668
+ printLine(JSON.stringify({
57518
57669
  passed,
57519
57670
  failed,
57520
57671
  healthy: failed === 0,
57521
57672
  checks
57522
57673
  }, null, 2));
57523
57674
  } else {
57524
- console.log(`
57675
+ printLine(`
57525
57676
  ${"\u2500".repeat(45)}`);
57526
- console.log(` ${passed} passed / ${failed} failed
57677
+ printLine(` ${passed} passed / ${failed} failed
57527
57678
  `);
57528
57679
  }
57529
57680
  if (failed > 0)
@@ -57532,6 +57683,7 @@ ${"\u2500".repeat(45)}`);
57532
57683
  }
57533
57684
 
57534
57685
  // src/cli/commands/mcp-install.ts
57686
+ init_stdout();
57535
57687
  import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
57536
57688
  import { homedir as homedir4 } from "os";
57537
57689
  import { dirname as dirname5, join as join4 } from "path";
@@ -57577,28 +57729,28 @@ function registerMcpCommand(program2) {
57577
57729
  mcpServers[MCP_SERVER_NAME] = { command: binary, args: [] };
57578
57730
  config2.mcpServers = mcpServers;
57579
57731
  writeFileSync3(configPath2, JSON.stringify(config2, null, 2), "utf-8");
57580
- console.log(`\u2713 MCP server registered: ${MCP_SERVER_NAME}`);
57581
- console.log(` Config: ${configPath2}`);
57582
- console.log(` Binary: ${binary}`);
57583
- console.log(`
57732
+ printLine(`\u2713 MCP server registered: ${MCP_SERVER_NAME}`);
57733
+ printLine(` Config: ${configPath2}`);
57734
+ printLine(` Binary: ${binary}`);
57735
+ printLine(`
57584
57736
  Restart Claude Code to activate.`);
57585
57737
  });
57586
57738
  mcp.command("uninstall").description("Remove domains MCP server from Claude Code config").option("--project", "Remove from project config instead of global").action((opts) => {
57587
57739
  const paths = getClaudeConfigPaths();
57588
57740
  const configPath2 = opts.project ? paths.project : paths.global;
57589
57741
  if (!existsSync3(configPath2)) {
57590
- console.log("Config file not found \u2014 nothing to remove.");
57742
+ printLine("Config file not found \u2014 nothing to remove.");
57591
57743
  return;
57592
57744
  }
57593
57745
  const config2 = readConfig(configPath2);
57594
57746
  const mcpServers = config2.mcpServers;
57595
57747
  if (!mcpServers?.[MCP_SERVER_NAME]) {
57596
- console.log(`MCP server '${MCP_SERVER_NAME}' is not registered.`);
57748
+ printLine(`MCP server '${MCP_SERVER_NAME}' is not registered.`);
57597
57749
  return;
57598
57750
  }
57599
57751
  delete mcpServers[MCP_SERVER_NAME];
57600
57752
  writeFileSync3(configPath2, JSON.stringify(config2, null, 2), "utf-8");
57601
- console.log(`\u2713 MCP server removed: ${MCP_SERVER_NAME}`);
57753
+ printLine(`\u2713 MCP server removed: ${MCP_SERVER_NAME}`);
57602
57754
  });
57603
57755
  mcp.command("status").description("Check if domains MCP server is registered").option("-j, --json", "Output JSON").action((opts) => {
57604
57756
  const paths = getClaudeConfigPaths();
@@ -57628,22 +57780,22 @@ function registerMcpCommand(program2) {
57628
57780
  }
57629
57781
  }
57630
57782
  if (opts.json) {
57631
- console.log(JSON.stringify({ server: MCP_SERVER_NAME, checks: status }, null, 2));
57783
+ printLine(JSON.stringify({ server: MCP_SERVER_NAME, checks: status }, null, 2));
57632
57784
  return;
57633
57785
  }
57634
57786
  for (const item of status) {
57635
57787
  if (!item.exists) {
57636
- console.log(` ${item.scope}: not found`);
57788
+ printLine(` ${item.scope}: not found`);
57637
57789
  continue;
57638
57790
  }
57639
57791
  if (item.error) {
57640
- console.log(` ${item.scope}: error reading config`);
57792
+ printLine(` ${item.scope}: error reading config`);
57641
57793
  continue;
57642
57794
  }
57643
57795
  if (item.registered) {
57644
- console.log(` ${item.scope}: \u2713 registered`);
57796
+ printLine(` ${item.scope}: \u2713 registered`);
57645
57797
  } else {
57646
- console.log(` ${item.scope}: \u2717 not registered`);
57798
+ printLine(` ${item.scope}: \u2717 not registered`);
57647
57799
  }
57648
57800
  }
57649
57801
  });
@@ -57652,6 +57804,7 @@ function registerMcpCommand(program2) {
57652
57804
  // src/cli/commands/serve.ts
57653
57805
  init_domains();
57654
57806
  init_version();
57807
+ init_stdout();
57655
57808
  function registerServeCommand(program2) {
57656
57809
  const packageVersion = getPackageVersion();
57657
57810
  program2.command("serve").description("Start HTTP API server").option("--port <n>", "Port to listen on", "3000").option("--host <h>", "Host to bind to", "127.0.0.1").action(async (opts) => {
@@ -57719,16 +57872,16 @@ function registerServeCommand(program2) {
57719
57872
  }
57720
57873
  }
57721
57874
  });
57722
- console.log(`\u2713 domains API server running at http://${opts.host}:${port}`);
57723
- console.log(` GET /health`);
57724
- console.log(` GET /domains`);
57725
- console.log(` POST /domains`);
57726
- console.log(` GET /domains/:id`);
57727
- console.log(` PUT /domains/:id`);
57728
- console.log(` DELETE /domains/:id`);
57729
- console.log(` GET /domains/:id/dns`);
57730
- console.log(` POST /domains/:id/dns`);
57731
- console.log(`
57875
+ printLine(`\u2713 domains API server running at http://${opts.host}:${port}`);
57876
+ printLine(` GET /health`);
57877
+ printLine(` GET /domains`);
57878
+ printLine(` POST /domains`);
57879
+ printLine(` GET /domains/:id`);
57880
+ printLine(` PUT /domains/:id`);
57881
+ printLine(` DELETE /domains/:id`);
57882
+ printLine(` GET /domains/:id/dns`);
57883
+ printLine(` POST /domains/:id/dns`);
57884
+ printLine(`
57732
57885
  Press Ctrl+C to stop.`);
57733
57886
  await new Promise(() => {});
57734
57887
  });
@@ -58104,6 +58257,7 @@ async function runMigrations(opts = {}) {
58104
58257
  }
58105
58258
 
58106
58259
  // src/cli/commands/db.ts
58260
+ init_stdout();
58107
58261
  function registerDbCommands(program2) {
58108
58262
  const db = program2.command("db").description("Cloud database migrations (Postgres / RDS)");
58109
58263
  db.command("migrate").description("Apply all pending migrations to the cloud Postgres (owner DSN)").option("--dry-run", "Report the plan without applying", false).option("--json", "Output JSON", false).action(async (opts) => {
@@ -58112,22 +58266,22 @@ function registerDbCommands(program2) {
58112
58266
  const pending = result.plan.filter((p2) => p2.state === "pending").map((p2) => p2.migration.id);
58113
58267
  const applied = result.applied.map((a4) => a4.id);
58114
58268
  if (opts.json) {
58115
- console.log(JSON.stringify({ ok: true, dryRun: result.dryRun, pending, applied }, null, 2));
58269
+ printLine(JSON.stringify({ ok: true, dryRun: result.dryRun, pending, applied }, null, 2));
58116
58270
  } else if (result.dryRun) {
58117
- console.log(`Dry run \u2014 ${pending.length} pending migration(s):`);
58271
+ printLine(`Dry run \u2014 ${pending.length} pending migration(s):`);
58118
58272
  for (const id of pending)
58119
- console.log(` \u2022 ${id}`);
58273
+ printLine(` \u2022 ${id}`);
58120
58274
  if (pending.length === 0)
58121
- console.log(" (schema up to date)");
58275
+ printLine(" (schema up to date)");
58122
58276
  } else {
58123
- console.log(`\u2713 migrations applied \u2014 ${applied.length} total, ${pending.length} were pending`);
58277
+ printLine(`\u2713 migrations applied \u2014 ${applied.length} total, ${pending.length} were pending`);
58124
58278
  }
58125
58279
  } catch (e4) {
58126
58280
  const msg = e4 instanceof Error ? e4.message : String(e4);
58127
58281
  if (opts.json)
58128
- console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
58282
+ printLine(JSON.stringify({ ok: false, error: msg }, null, 2));
58129
58283
  else
58130
- console.error(`\u2717 migration failed: ${msg}`);
58284
+ printErrorLine(`\u2717 migration failed: ${msg}`);
58131
58285
  process.exitCode = 1;
58132
58286
  }
58133
58287
  });
@@ -58137,18 +58291,18 @@ function registerDbCommands(program2) {
58137
58291
  const pending = result.plan.filter((p2) => p2.state === "pending").map((p2) => p2.migration.id);
58138
58292
  const applied = result.applied.map((a4) => a4.id);
58139
58293
  if (opts.json) {
58140
- console.log(JSON.stringify({ ok: true, pending, applied }, null, 2));
58294
+ printLine(JSON.stringify({ ok: true, pending, applied }, null, 2));
58141
58295
  } else {
58142
- console.log(`Applied: ${applied.length} Pending: ${pending.length}`);
58296
+ printLine(`Applied: ${applied.length} Pending: ${pending.length}`);
58143
58297
  for (const id of pending)
58144
- console.log(` pending: ${id}`);
58298
+ printLine(` pending: ${id}`);
58145
58299
  }
58146
58300
  } catch (e4) {
58147
58301
  const msg = e4 instanceof Error ? e4.message : String(e4);
58148
58302
  if (opts.json)
58149
- console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
58303
+ printLine(JSON.stringify({ ok: false, error: msg }, null, 2));
58150
58304
  else
58151
- console.error(`\u2717 ${msg}`);
58305
+ printErrorLine(`\u2717 ${msg}`);
58152
58306
  process.exitCode = 1;
58153
58307
  }
58154
58308
  });
@@ -58197,6 +58351,7 @@ async function setupDomainZone(domain, deps) {
58197
58351
  // src/cli/commands/route53.ts
58198
58352
  init_domains();
58199
58353
  init_config();
58354
+ init_stdout();
58200
58355
  function registerRoute53Commands(program2) {
58201
58356
  const r53 = program2.command("r53").description("AWS Route 53 \u2014 domain purchase, hosted zones & DNS");
58202
58357
  r53.command("check <domains...>").description("Check if one or more domains are available for purchase").action(async (domains) => {
@@ -58207,7 +58362,7 @@ function registerRoute53Commands(program2) {
58207
58362
  const r4 = results[i4];
58208
58363
  if (r4.status === "rejected") {
58209
58364
  const reason = r4.reason;
58210
- console.error(`\u2717 ${domains[i4]}: ${reason instanceof Error ? reason.message : String(reason)}`);
58365
+ printErrorLine(`\u2717 ${domains[i4]}: ${reason instanceof Error ? reason.message : String(reason)}`);
58211
58366
  anyError = true;
58212
58367
  continue;
58213
58368
  }
@@ -58218,15 +58373,15 @@ function registerRoute53Commands(program2) {
58218
58373
  const ren = result.renewal_price ? `renew ${cur} ${result.renewal_price}` : "";
58219
58374
  const xfr = result.transfer_price ? `transfer ${cur} ${result.transfer_price}` : "";
58220
58375
  const pricing = [reg, ren, xfr].filter(Boolean).join(" / ");
58221
- console.log(`\u2713 ${result.domain} is available${pricing ? ` (${pricing})` : ""}`);
58376
+ printLine(`\u2713 ${result.domain} is available${pricing ? ` (${pricing})` : ""}`);
58222
58377
  } else {
58223
- console.log(`\u2717 ${result.domain} is not available`);
58378
+ printLine(`\u2717 ${result.domain} is not available`);
58224
58379
  }
58225
58380
  }
58226
58381
  if (anyError)
58227
58382
  process.exit(1);
58228
58383
  } catch (e4) {
58229
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58384
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58230
58385
  process.exit(1);
58231
58386
  }
58232
58387
  });
@@ -58234,36 +58389,36 @@ function registerRoute53Commands(program2) {
58234
58389
  try {
58235
58390
  const avail = await checkAvailability3(domain);
58236
58391
  if (!avail.available) {
58237
- console.error(`\u2717 ${domain} is not available for registration`);
58392
+ printErrorLine(`\u2717 ${domain} is not available for registration`);
58238
58393
  process.exit(1);
58239
58394
  }
58240
58395
  let contact;
58241
58396
  try {
58242
58397
  contact = resolveContact(opts);
58243
58398
  } catch (e4) {
58244
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58399
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58245
58400
  process.exit(1);
58246
58401
  }
58247
- console.log(`Registering ${domain}...`);
58402
+ printLine(`Registering ${domain}...`);
58248
58403
  const result = await registerDomain2(domain, contact, parseInt(opts.years), opts.autoRenew);
58249
- console.log(`\u2713 Registration submitted: ${domain}`);
58250
- console.log(` Operation ID: ${result.operationId}`);
58251
- console.log(` Check status: domains r53 status ${result.operationId}`);
58404
+ printLine(`\u2713 Registration submitted: ${domain}`);
58405
+ printLine(` Operation ID: ${result.operationId}`);
58406
+ printLine(` Check status: domains r53 status ${result.operationId}`);
58252
58407
  } catch (e4) {
58253
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58408
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58254
58409
  process.exit(1);
58255
58410
  }
58256
58411
  });
58257
58412
  r53.command("status <operationId>").description("Check domain registration status").action(async (operationId) => {
58258
58413
  try {
58259
58414
  const result = await getRegistrationStatus(operationId);
58260
- console.log(`Status: ${result.status}`);
58415
+ printLine(`Status: ${result.status}`);
58261
58416
  if (result.domain)
58262
- console.log(`Domain: ${result.domain}`);
58417
+ printLine(`Domain: ${result.domain}`);
58263
58418
  if (result.message)
58264
- console.log(`Message: ${result.message}`);
58419
+ printLine(`Message: ${result.message}`);
58265
58420
  } catch (e4) {
58266
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58421
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58267
58422
  process.exit(1);
58268
58423
  }
58269
58424
  });
@@ -58271,26 +58426,26 @@ function registerRoute53Commands(program2) {
58271
58426
  try {
58272
58427
  const domains = await listRegisteredDomains();
58273
58428
  if (opts.json) {
58274
- console.log(JSON.stringify(domains, null, 2));
58429
+ printLine(JSON.stringify(domains, null, 2));
58275
58430
  return;
58276
58431
  }
58277
58432
  const page = pageItemsOrExit(domains, { limit: opts.limit, all: opts.all });
58278
58433
  if (page.items.length === 0) {
58279
- console.log("No registered domains.");
58434
+ printLine("No registered domains.");
58280
58435
  return;
58281
58436
  }
58282
- console.log(`
58437
+ printLine(`
58283
58438
  Registered Domains:`);
58284
58439
  for (const d4 of page.items) {
58285
58440
  const expiry = d4.expiry ? ` (expires ${d4.expiry.split("T")[0]})` : "";
58286
58441
  const renew = d4.auto_renew ? " [auto-renew]" : "";
58287
58442
  const lock = d4.transfer_lock ? " [locked]" : "";
58288
- console.log(` ${d4.domain}${expiry}${renew}${lock}`);
58443
+ printLine(` ${d4.domain}${expiry}${renew}${lock}`);
58289
58444
  }
58290
- console.log(`
58445
+ printLine(`
58291
58446
  ${compactHint(page, "domain(s)", "Use --all for every Route53 domain or r53 domain-info <domain> for details.", { paging: "limit" })}`);
58292
58447
  } catch (e4) {
58293
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58448
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58294
58449
  process.exit(1);
58295
58450
  }
58296
58451
  });
@@ -58298,41 +58453,41 @@ ${compactHint(page, "domain(s)", "Use --all for every Route53 domain or r53 doma
58298
58453
  try {
58299
58454
  const detail = await getDomainDetail(domain);
58300
58455
  if (opts.json) {
58301
- console.log(JSON.stringify(detail, null, 2));
58456
+ printLine(JSON.stringify(detail, null, 2));
58302
58457
  return;
58303
58458
  }
58304
- console.log(`
58459
+ printLine(`
58305
58460
  Domain: ${detail.domain}`);
58306
- console.log(` Created: ${detail.created ? detail.created.split("T")[0] : "\u2014"}`);
58307
- console.log(` Expires: ${detail.expiry ? detail.expiry.split("T")[0] : "\u2014"}`);
58308
- console.log(` Auto-renew: ${detail.auto_renew ? "yes" : "no"}`);
58309
- console.log(` Transfer lock: ${detail.transfer_lock ? "yes" : "no"}`);
58461
+ printLine(` Created: ${detail.created ? detail.created.split("T")[0] : "\u2014"}`);
58462
+ printLine(` Expires: ${detail.expiry ? detail.expiry.split("T")[0] : "\u2014"}`);
58463
+ printLine(` Auto-renew: ${detail.auto_renew ? "yes" : "no"}`);
58464
+ printLine(` Transfer lock: ${detail.transfer_lock ? "yes" : "no"}`);
58310
58465
  if (detail.nameservers.length > 0) {
58311
- console.log(` Name servers:`);
58466
+ printLine(` Name servers:`);
58312
58467
  for (const ns of detail.nameservers)
58313
- console.log(` ${ns}`);
58468
+ printLine(` ${ns}`);
58314
58469
  }
58315
- console.log();
58470
+ printLine();
58316
58471
  } catch (e4) {
58317
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58472
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58318
58473
  process.exit(1);
58319
58474
  }
58320
58475
  });
58321
58476
  r53.command("zone-create <domain>").description("Create a hosted zone").option("--comment <text>", "Zone comment").action(async (domain, opts) => {
58322
58477
  try {
58323
58478
  const zone = await createHostedZone(domain, opts.comment);
58324
- console.log(`\u2713 Hosted zone created: ${domain}`);
58325
- console.log(` Zone ID: ${zone.id}`);
58479
+ printLine(`\u2713 Hosted zone created: ${domain}`);
58480
+ printLine(` Zone ID: ${zone.id}`);
58326
58481
  if (zone.name_servers && zone.name_servers.length > 0) {
58327
- console.log(`
58482
+ printLine(`
58328
58483
  Name servers (set at your registrar):`);
58329
58484
  for (const ns of zone.name_servers) {
58330
- console.log(` ${ns}`);
58485
+ printLine(` ${ns}`);
58331
58486
  }
58332
58487
  }
58333
- console.log();
58488
+ printLine();
58334
58489
  } catch (e4) {
58335
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58490
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58336
58491
  process.exit(1);
58337
58492
  }
58338
58493
  });
@@ -58340,24 +58495,24 @@ Domain: ${detail.domain}`);
58340
58495
  try {
58341
58496
  const zones = await listHostedZones();
58342
58497
  if (opts.json) {
58343
- console.log(JSON.stringify(zones, null, 2));
58498
+ printLine(JSON.stringify(zones, null, 2));
58344
58499
  return;
58345
58500
  }
58346
58501
  const page = pageItemsOrExit(zones, { limit: opts.limit, all: opts.all });
58347
58502
  if (page.items.length === 0) {
58348
- console.log("No hosted zones.");
58503
+ printLine("No hosted zones.");
58349
58504
  return;
58350
58505
  }
58351
- console.log(`
58506
+ printLine(`
58352
58507
  Hosted Zones:`);
58353
58508
  for (const z of page.items) {
58354
58509
  const comment = z.comment ? ` \u2014 ${truncateText(z.comment, 60)}` : "";
58355
- console.log(` ${z.id} ${z.name} ${z.record_count} records${comment}`);
58510
+ printLine(` ${z.id} ${z.name} ${z.record_count} records${comment}`);
58356
58511
  }
58357
- console.log(`
58512
+ printLine(`
58358
58513
  ${compactHint(page, "zone(s)", "Use --all for every zone or r53 zone-info <zoneId> for details.", { paging: "limit" })}`);
58359
58514
  } catch (e4) {
58360
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58515
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58361
58516
  process.exit(1);
58362
58517
  }
58363
58518
  });
@@ -58365,24 +58520,24 @@ ${compactHint(page, "zone(s)", "Use --all for every zone or r53 zone-info <zoneI
58365
58520
  try {
58366
58521
  const zone = await getHostedZone(zoneId);
58367
58522
  if (opts.json) {
58368
- console.log(JSON.stringify(zone, null, 2));
58523
+ printLine(JSON.stringify(zone, null, 2));
58369
58524
  return;
58370
58525
  }
58371
- console.log(`
58526
+ printLine(`
58372
58527
  Hosted Zone: ${zone.name}`);
58373
- console.log(` ID: ${zone.id}`);
58374
- console.log(` Records: ${zone.record_count}`);
58528
+ printLine(` ID: ${zone.id}`);
58529
+ printLine(` Records: ${zone.record_count}`);
58375
58530
  if (zone.comment)
58376
- console.log(` Comment: ${zone.comment}`);
58531
+ printLine(` Comment: ${zone.comment}`);
58377
58532
  if (zone.name_servers && zone.name_servers.length > 0) {
58378
- console.log(` Name servers:`);
58533
+ printLine(` Name servers:`);
58379
58534
  for (const ns of zone.name_servers) {
58380
- console.log(` ${ns}`);
58535
+ printLine(` ${ns}`);
58381
58536
  }
58382
58537
  }
58383
- console.log();
58538
+ printLine();
58384
58539
  } catch (e4) {
58385
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58540
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58386
58541
  process.exit(1);
58387
58542
  }
58388
58543
  });
@@ -58390,18 +58545,18 @@ Hosted Zone: ${zone.name}`);
58390
58545
  try {
58391
58546
  const zone = await getHostedZone(zoneId);
58392
58547
  if (!opts.force) {
58393
- console.log(`Would delete hosted zone:`);
58394
- console.log(` ID: ${zone.id}`);
58395
- console.log(` Domain: ${zone.name}`);
58396
- console.log(` Records: ${zone.record_count}`);
58397
- console.log(`
58548
+ printLine(`Would delete hosted zone:`);
58549
+ printLine(` ID: ${zone.id}`);
58550
+ printLine(` Domain: ${zone.name}`);
58551
+ printLine(` Records: ${zone.record_count}`);
58552
+ printLine(`
58398
58553
  This is irreversible. Re-run with --force to confirm.`);
58399
58554
  process.exit(0);
58400
58555
  }
58401
58556
  await deleteHostedZone(zoneId);
58402
- console.log(`\u2713 Hosted zone deleted: ${zone.name} (${zone.id})`);
58557
+ printLine(`\u2713 Hosted zone deleted: ${zone.name} (${zone.id})`);
58403
58558
  } catch (e4) {
58404
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58559
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58405
58560
  process.exit(1);
58406
58561
  }
58407
58562
  });
@@ -58409,30 +58564,30 @@ This is irreversible. Re-run with --force to confirm.`);
58409
58564
  try {
58410
58565
  const zone = await findHostedZoneByDomain(domain);
58411
58566
  if (!zone) {
58412
- console.error(`No hosted zone found for ${domain}`);
58567
+ printErrorLine(`No hosted zone found for ${domain}`);
58413
58568
  process.exit(1);
58414
58569
  }
58415
58570
  const records = await listRecords(zone.id);
58416
58571
  if (opts.json) {
58417
- console.log(JSON.stringify(records, null, 2));
58572
+ printLine(JSON.stringify(records, null, 2));
58418
58573
  return;
58419
58574
  }
58420
58575
  const page = pageItemsOrExit(records, { limit: opts.limit, all: opts.all });
58421
58576
  if (page.items.length === 0) {
58422
- console.log("No records.");
58577
+ printLine("No records.");
58423
58578
  return;
58424
58579
  }
58425
- console.log(`
58580
+ printLine(`
58426
58581
  DNS Records for ${domain}:`);
58427
58582
  for (const r4 of page.items) {
58428
58583
  const val = r4.alias_target ? `ALIAS \u2192 ${r4.alias_target.dns_name}` : truncateText(r4.values.join(", "), 90);
58429
58584
  const ttl = r4.alias_target ? "" : ` TTL:${r4.ttl}`;
58430
- console.log(` ${r4.type.padEnd(6)} ${r4.name.padEnd(40)}${ttl} ${val}`);
58585
+ printLine(` ${r4.type.padEnd(6)} ${r4.name.padEnd(40)}${ttl} ${val}`);
58431
58586
  }
58432
- console.log(`
58587
+ printLine(`
58433
58588
  ${compactHint(page, "record(s)", "Use --all for every record or --json for full values.", { paging: "limit" })}`);
58434
58589
  } catch (e4) {
58435
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58590
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58436
58591
  process.exit(1);
58437
58592
  }
58438
58593
  });
@@ -58443,20 +58598,20 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
58443
58598
  try {
58444
58599
  const isAlias = !!(opts.aliasZone && opts.aliasDns);
58445
58600
  if (!isAlias && (!opts.value || opts.value.length === 0)) {
58446
- console.error("Error: provide --value (repeatable) or both --alias-zone and --alias-dns");
58601
+ printErrorLine("Error: provide --value (repeatable) or both --alias-zone and --alias-dns");
58447
58602
  process.exit(1);
58448
58603
  }
58449
58604
  const zone = await findHostedZoneByDomain(domain);
58450
58605
  if (!zone) {
58451
- console.error(`No hosted zone found for ${domain}`);
58606
+ printErrorLine(`No hosted zone found for ${domain}`);
58452
58607
  process.exit(1);
58453
58608
  }
58454
58609
  const aliasTarget = isAlias ? { hosted_zone_id: opts.aliasZone, dns_name: opts.aliasDns } : undefined;
58455
58610
  await upsertRecord(zone.id, { name: opts.name, type: opts.type, ttl: parseInt(opts.ttl), values: opts.value, alias_target: aliasTarget });
58456
58611
  const desc = isAlias ? `alias \u2192 ${opts.aliasDns}` : `${opts.value.length} value(s)`;
58457
- console.log(`\u2713 Record upserted: ${opts.type} ${opts.name} (${desc})`);
58612
+ printLine(`\u2713 Record upserted: ${opts.type} ${opts.name} (${desc})`);
58458
58613
  } catch (e4) {
58459
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58614
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58460
58615
  process.exit(1);
58461
58616
  }
58462
58617
  });
@@ -58464,14 +58619,14 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
58464
58619
  try {
58465
58620
  const zone = await findHostedZoneByDomain(domain);
58466
58621
  if (!zone) {
58467
- console.error(`No hosted zone found for ${domain}`);
58622
+ printErrorLine(`No hosted zone found for ${domain}`);
58468
58623
  process.exit(1);
58469
58624
  }
58470
58625
  const records = await listRecords(zone.id);
58471
58626
  const normName = opts.name.endsWith(".") ? opts.name : `${opts.name}.`;
58472
58627
  const existing = records.find((r4) => r4.type === opts.type.toUpperCase() && (r4.name === opts.name || r4.name === normName));
58473
58628
  if (!existing) {
58474
- console.error(`\u2717 No ${opts.type} record found for ${opts.name} in zone ${domain}`);
58629
+ printErrorLine(`\u2717 No ${opts.type} record found for ${opts.name} in zone ${domain}`);
58475
58630
  process.exit(1);
58476
58631
  }
58477
58632
  await deleteRecord(zone.id, {
@@ -58481,9 +58636,9 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
58481
58636
  values: existing.values,
58482
58637
  alias_target: existing.alias_target
58483
58638
  });
58484
- console.log(`\u2713 Record deleted: ${existing.type} ${existing.name}`);
58639
+ printLine(`\u2713 Record deleted: ${existing.type} ${existing.name}`);
58485
58640
  } catch (e4) {
58486
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58641
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58487
58642
  process.exit(1);
58488
58643
  }
58489
58644
  });
@@ -58493,23 +58648,23 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
58493
58648
  try {
58494
58649
  raw = readFileSync7(opts.file, "utf-8");
58495
58650
  } catch {
58496
- console.error(`Could not read file: ${opts.file}`);
58651
+ printErrorLine(`Could not read file: ${opts.file}`);
58497
58652
  process.exit(1);
58498
58653
  }
58499
58654
  const records = JSON.parse(raw);
58500
58655
  if (!Array.isArray(records)) {
58501
- console.error("JSON file must be an array of record objects");
58656
+ printErrorLine("JSON file must be an array of record objects");
58502
58657
  process.exit(1);
58503
58658
  }
58504
58659
  const zone = await findHostedZoneByDomain(domain);
58505
58660
  if (!zone) {
58506
- console.error(`No hosted zone found for ${domain}`);
58661
+ printErrorLine(`No hosted zone found for ${domain}`);
58507
58662
  process.exit(1);
58508
58663
  }
58509
58664
  await upsertRecords(zone.id, records);
58510
- console.log(`\u2713 Upserted ${records.length} record(s) in ${domain}`);
58665
+ printLine(`\u2713 Upserted ${records.length} record(s) in ${domain}`);
58511
58666
  } catch (e4) {
58512
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58667
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58513
58668
  process.exit(1);
58514
58669
  }
58515
58670
  });
@@ -58521,36 +58676,36 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
58521
58676
  createDomain: createDomain2,
58522
58677
  updateDomain: updateDomain2
58523
58678
  });
58524
- console.log(`\u2713 Synced ${result.synced} domains (${result.created} new, ${result.updated} updated)`);
58679
+ printLine(`\u2713 Synced ${result.synced} domains (${result.created} new, ${result.updated} updated)`);
58525
58680
  if (result.errors.length > 0) {
58526
- console.log(` Errors: ${result.errors.join(", ")}`);
58681
+ printLine(` Errors: ${result.errors.join(", ")}`);
58527
58682
  }
58528
58683
  } catch (e4) {
58529
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58684
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58530
58685
  process.exit(1);
58531
58686
  }
58532
58687
  });
58533
58688
  r53.command("full-setup <domain>").description("Buy domain + create zone + sync to DB \u2014 all in one (contact defaults from: domains config set contact.*)").option("--email <email>", "Registrant email").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").option("--phone <phone>", "Phone").option("--address <addr>", "Street address").option("--city <city>", "City").option("--state <state>", "State/province").option("--country <code>", "Country code").option("--zip <zip>", "ZIP code").option("--org <name>", "Organization name").option("--years <n>", "Registration years", "1").option("--wait", "Poll until registration completes (or fails)").action(async (domain, opts) => {
58534
58689
  try {
58535
- console.log(`[1/4] Checking availability...`);
58690
+ printLine(`[1/4] Checking availability...`);
58536
58691
  const avail = await checkAvailability3(domain);
58537
58692
  if (!avail.available) {
58538
- console.error(`\u2717 ${domain} is not available`);
58693
+ printErrorLine(`\u2717 ${domain} is not available`);
58539
58694
  process.exit(1);
58540
58695
  }
58541
58696
  const price = avail.price ? ` (${avail.currency ?? "USD"} ${avail.price}/yr)` : "";
58542
- console.log(` \u2713 Available${price}`);
58543
- console.log(`[2/4] Registering domain...`);
58697
+ printLine(` \u2713 Available${price}`);
58698
+ printLine(`[2/4] Registering domain...`);
58544
58699
  let contact;
58545
58700
  try {
58546
58701
  contact = resolveContact(opts);
58547
58702
  } catch (e4) {
58548
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58703
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58549
58704
  process.exit(1);
58550
58705
  }
58551
58706
  const reg = await registerDomain2(domain, contact, parseInt(opts.years));
58552
- console.log(` \u2713 Submitted (operation: ${reg.operationId})`);
58553
- console.log(` Waiting for registration to complete...`);
58707
+ printLine(` \u2713 Submitted (operation: ${reg.operationId})`);
58708
+ printLine(` Waiting for registration to complete...`);
58554
58709
  let status = "IN_PROGRESS";
58555
58710
  while (status === "IN_PROGRESS" || status === "SUBMITTED") {
58556
58711
  await new Promise((r4) => setTimeout(r4, 1e4));
@@ -58558,13 +58713,13 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
58558
58713
  status = s2.status;
58559
58714
  process.stdout.write(` Status: ${status}\r`);
58560
58715
  }
58561
- console.log();
58716
+ printLine();
58562
58717
  if (status !== "SUCCESSFUL") {
58563
- console.error(`\u2717 Registration ${status}`);
58718
+ printErrorLine(`\u2717 Registration ${status}`);
58564
58719
  process.exit(1);
58565
58720
  }
58566
- console.log(` \u2713 Registration complete`);
58567
- console.log(`[3/4] Configuring hosted zone...`);
58721
+ printLine(` \u2713 Registration complete`);
58722
+ printLine(`[3/4] Configuring hosted zone...`);
58568
58723
  const setup = await setupDomainZone(domain, {
58569
58724
  findExistingZone: async (d4) => {
58570
58725
  const z = await findHostedZoneByDomain(d4);
@@ -58582,8 +58737,8 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
58582
58737
  await updateNameservers2(d4, ns);
58583
58738
  }
58584
58739
  });
58585
- console.log(` \u2713 Zone ${setup.created ? "created" : "reused"} (${setup.zoneId})` + (setup.nsUpdated ? ` \u2014 registry NS repointed to this zone` : ``));
58586
- console.log(`[4/4] Adding to local database...`);
58740
+ printLine(` \u2713 Zone ${setup.created ? "created" : "reused"} (${setup.zoneId})` + (setup.nsUpdated ? ` \u2014 registry NS repointed to this zone` : ``));
58741
+ printLine(`[4/4] Adding to local database...`);
58587
58742
  createDomain2({
58588
58743
  name: domain,
58589
58744
  registrar: "AWS Route 53",
@@ -58591,20 +58746,20 @@ ${compactHint(page, "record(s)", "Use --all for every record or --json for full
58591
58746
  auto_renew: true,
58592
58747
  nameservers: setup.nameServers
58593
58748
  });
58594
- console.log(` \u2713 Added to portfolio`);
58595
- console.log(`
58749
+ printLine(` \u2713 Added to portfolio`);
58750
+ printLine(`
58596
58751
  \u2713 Full setup complete for ${domain}`);
58597
- console.log(` Check: domains r53 status ${reg.operationId}`);
58752
+ printLine(` Check: domains r53 status ${reg.operationId}`);
58598
58753
  if (setup.nameServers && setup.nameServers.length > 0) {
58599
- console.log(`
58754
+ printLine(`
58600
58755
  Name servers:`);
58601
58756
  for (const ns of setup.nameServers) {
58602
- console.log(` ${ns}`);
58757
+ printLine(` ${ns}`);
58603
58758
  }
58604
58759
  }
58605
- console.log();
58760
+ printLine();
58606
58761
  } catch (e4) {
58607
- console.error(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58762
+ printErrorLine(`Error: ${e4 instanceof Error ? e4.message : String(e4)}`);
58608
58763
  process.exit(1);
58609
58764
  }
58610
58765
  });
@@ -58971,6 +59126,7 @@ function coverageRegressions(current, baseline) {
58971
59126
  }
58972
59127
 
58973
59128
  // src/cli/commands/reconcile-expiry.ts
59129
+ init_stdout();
58974
59130
  var IANA_RDAP_BOOTSTRAP = "https://data.iana.org/rdap/dns.json";
58975
59131
  var TLD_WHOIS = {
58976
59132
  ag: "whois.nic.ag",
@@ -59065,18 +59221,18 @@ function registerReconcileExpiryCommand(program2) {
59065
59221
  program2.command("reconcile-expiry").description("READ-ONLY: compare each domain's REGISTRAR expiry against the REGISTRY's own expiry").option("--from <file>", "Registrar dump JSON (array of {domain, expiresAt, status, registrar})").option("--provider <name>", "Read the registrar inventory live via a configured provider").option("--bootstrap <file>", "Local RDAP bootstrap JSON (default: fetch from IANA)").option("--baseline <file>", "Prior run's JSON; enables coverage-regression detection").option("--only <list>", "Comma-separated domains, or a TLD like '.md'").option("--limit <n>", "Cap the number of domains checked").option("--sample <n>", "Deterministic every-Nth sample across the population").option("--rdap-delay <ms>", "Delay between RDAP queries", "1100").option("--whois-delay <ms>", "Delay between WHOIS queries", "2500").option("--self-test", "Run the pre-arm self-test and exit").option("--json", "Output JSON").action(async (opts) => {
59066
59222
  const arm = prearm();
59067
59223
  if (!opts.json) {
59068
- console.log("=== PRE-ARM SELF-TEST (two-sided) ===");
59224
+ printLine("=== PRE-ARM SELF-TEST (two-sided) ===");
59069
59225
  for (const c4 of arm.cases)
59070
- console.log(` [${c4.passed ? "PASS" : "FAIL"}] ${c4.name.padEnd(58)} -> ${c4.got}`);
59071
- console.log(`=== PRE-ARM ${arm.ok ? "PASS - instrument can fire AND can stay silent" : "FAIL - DO NOT TRUST ANY RESULT"} ===`);
59226
+ printLine(` [${c4.passed ? "PASS" : "FAIL"}] ${c4.name.padEnd(58)} -> ${c4.got}`);
59227
+ printLine(`=== PRE-ARM ${arm.ok ? "PASS - instrument can fire AND can stay silent" : "FAIL - DO NOT TRUST ANY RESULT"} ===`);
59072
59228
  }
59073
59229
  if (!arm.ok) {
59074
- console.error("REFUSING TO RUN: pre-arm failed.");
59230
+ printErrorLine("REFUSING TO RUN: pre-arm failed.");
59075
59231
  process.exit(3);
59076
59232
  }
59077
59233
  if (opts.selfTest) {
59078
59234
  if (opts.json)
59079
- console.log(JSON.stringify({ prearm: arm }, null, 2));
59235
+ printLine(JSON.stringify({ prearm: arm }, null, 2));
59080
59236
  process.exit(0);
59081
59237
  }
59082
59238
  let rows;
@@ -59084,8 +59240,8 @@ function registerReconcileExpiryCommand(program2) {
59084
59240
  rows = await loadRows(opts);
59085
59241
  } catch (e4) {
59086
59242
  const configured = getAvailableProviders().filter((p2) => p2.configured).map((p2) => p2.name).join(", ") || "none";
59087
- console.error(`${e4 instanceof Error ? e4.message : String(e4)}`);
59088
- console.error(`configured providers: ${configured}`);
59243
+ printErrorLine(`${e4 instanceof Error ? e4.message : String(e4)}`);
59244
+ printErrorLine(`configured providers: ${configured}`);
59089
59245
  process.exit(2);
59090
59246
  return;
59091
59247
  }
@@ -59124,9 +59280,9 @@ function registerReconcileExpiryCommand(program2) {
59124
59280
  }
59125
59281
  };
59126
59282
  if (!opts.json) {
59127
- console.log(`
59283
+ printLine(`
59128
59284
  REGISTRAR rows=${rows.length} unique=${unique.length} dupes_removed=${dupesRemoved}`);
59129
- console.log(`SELECTED=${selected.length}`);
59285
+ printLine(`SELECTED=${selected.length}`);
59130
59286
  }
59131
59287
  const report = await reconcileExpiry(selected, deps);
59132
59288
  let regressed = [];
@@ -59137,40 +59293,40 @@ REGISTRAR rows=${rows.length} unique=${unique.length} dupes_removed=${dupesRemov
59137
59293
  report.exitCode = Math.max(report.exitCode, 2);
59138
59294
  }
59139
59295
  if (opts.json) {
59140
- console.log(JSON.stringify({ ...report, coverageRegressions: regressed, queries }, null, 2));
59296
+ printLine(JSON.stringify({ ...report, coverageRegressions: regressed, queries }, null, 2));
59141
59297
  process.exit(report.exitCode);
59142
59298
  return;
59143
59299
  }
59144
59300
  const order = ["MATCH", "MISMATCH", "NOT_AT_REGISTRY", "UNVERIFIABLE_EXPECTED", "UNVERIFIABLE_UNEXPECTED"];
59145
- console.log(`
59301
+ printLine(`
59146
59302
  === VERDICT TALLY (n=${report.records.length}) ===`);
59147
59303
  for (const k4 of order)
59148
- console.log(` ${k4.padEnd(24)} ${String(report.tally[k4]).padStart(5)}`);
59304
+ printLine(` ${k4.padEnd(24)} ${String(report.tally[k4]).padStart(5)}`);
59149
59305
  const pct = report.records.length ? (100 * report.comparable / report.records.length).toFixed(1) : "0.0";
59150
- console.log(`COMPARABLE = ${report.comparable} of ${report.records.length} (${pct}%)`);
59306
+ printLine(`COMPARABLE = ${report.comparable} of ${report.records.length} (${pct}%)`);
59151
59307
  const show = (title, rs) => {
59152
59308
  if (rs.length === 0)
59153
59309
  return;
59154
- console.log(`
59310
+ printLine(`
59155
59311
  === ${title} ===`);
59156
59312
  for (const r4 of rs)
59157
- console.log(` ${r4.domain.padEnd(26)} ${r4.why.slice(0, 120)}`);
59313
+ printLine(` ${r4.domain.padEnd(26)} ${r4.why.slice(0, 120)}`);
59158
59314
  };
59159
59315
  show("MISMATCHES", report.records.filter((r4) => r4.verdict === "MISMATCH"));
59160
59316
  show("NOT AT REGISTRY", report.records.filter((r4) => r4.verdict === "NOT_AT_REGISTRY"));
59161
59317
  show("UNVERIFIABLE / UNEXPECTED (coverage loss - these are NOT clean)", report.records.filter((r4) => r4.verdict === "UNVERIFIABLE_UNEXPECTED"));
59162
- console.log(`
59318
+ printLine(`
59163
59319
  REGISTRY EXPIRY WITHIN ${STALE_SOON_DAYS}d: ${report.expiringSoon.length}`);
59164
59320
  for (const r4 of report.expiringSoon) {
59165
- console.log(` ${r4.domain.padEnd(26)} registry=${r4.registry} in ${r4.daysToRegistryExpiry}d verdict=${r4.verdict}`);
59321
+ printLine(` ${r4.domain.padEnd(26)} registry=${r4.registry} in ${r4.daysToRegistryExpiry}d verdict=${r4.verdict}`);
59166
59322
  }
59167
59323
  if (opts.baseline) {
59168
- console.log(`
59324
+ printLine(`
59169
59325
  COVERAGE REGRESSION vs baseline: ${regressed.length}`);
59170
59326
  for (const d4 of regressed.slice(0, 20))
59171
- console.log(` ${d4} was comparable, now unverifiable`);
59327
+ printLine(` ${d4} was comparable, now unverifiable`);
59172
59328
  }
59173
- console.log(`
59329
+ printLine(`
59174
59330
  EXIT=${report.exitCode}`);
59175
59331
  process.exit(report.exitCode);
59176
59332
  });
@@ -59178,6 +59334,7 @@ EXIT=${report.exitCode}`);
59178
59334
 
59179
59335
  // src/cli/index.ts
59180
59336
  init_version();
59337
+ init_stdout();
59181
59338
  var OPTIONAL_GROUPS = [
59182
59339
  "brandsight",
59183
59340
  "events",
@@ -59238,7 +59395,7 @@ async function registerOptionalCommands(program2, groups) {
59238
59395
  const { registerEventsCommands: registerEventsCommands2 } = await Promise.resolve().then(() => (init_commander(), exports_commander));
59239
59396
  registerEventsCommands2(program2, { source: "domains" });
59240
59397
  } catch (error) {
59241
- console.error(`Events command group is enabled but @hasna/events could not be loaded: ${error instanceof Error ? error.message : String(error)}`);
59398
+ printErrorLine(`Events command group is enabled but @hasna/events could not be loaded: ${error instanceof Error ? error.message : String(error)}`);
59242
59399
  }
59243
59400
  }
59244
59401
  }
@@ -59252,15 +59409,15 @@ function registerOptionalHelp(program2) {
59252
59409
  enable_some: "DOMAINS_COMMAND_GROUPS=marketplace,owner domains <command>"
59253
59410
  };
59254
59411
  if (opts.json) {
59255
- console.log(JSON.stringify(body, null, 2));
59412
+ printLine(JSON.stringify(body, null, 2));
59256
59413
  return;
59257
59414
  }
59258
- console.log("Optional command groups:");
59415
+ printLine("Optional command groups:");
59259
59416
  for (const group of body.available)
59260
- console.log(` ${groups.has(group) ? "\u2713" : " "} ${group}`);
59261
- console.log(`
59417
+ printLine(` ${groups.has(group) ? "\u2713" : " "} ${group}`);
59418
+ printLine(`
59262
59419
  Enable all: DOMAINS_ENABLE_EXTRAS=1 domains <command>`);
59263
- console.log("Enable some: DOMAINS_COMMAND_GROUPS=marketplace,owner domains <command>");
59420
+ printLine("Enable some: DOMAINS_COMMAND_GROUPS=marketplace,owner domains <command>");
59264
59421
  });
59265
59422
  }
59266
59423
  var program2 = new Command;