@hasna/skills 0.1.18 → 0.1.19

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 (187) hide show
  1. package/README.md +25 -407
  2. package/bin/index.js +4260 -3040
  3. package/bin/mcp.js +4608 -3318
  4. package/package.json +3 -3
  5. package/skills/skill-academic-journal-matcher/bin/cli.ts +0 -34
  6. package/skills/skill-action-item-router/bin/cli.ts +0 -34
  7. package/skills/skill-ad-creative-generator/bin/cli.ts +0 -34
  8. package/skills/skill-advanced-math/bin/cli.ts +0 -34
  9. package/skills/skill-analyze-data/bin/cli.ts +0 -19
  10. package/skills/skill-anomaly-investigator/bin/cli.ts +0 -34
  11. package/skills/skill-api-test-suite/bin/cli.ts +0 -34
  12. package/skills/skill-apidocs/bin/cli.ts +0 -87
  13. package/skills/skill-audio-cleanup-lab/bin/cli.ts +0 -6
  14. package/skills/skill-audiobook-chapter-proofer/bin/cli.ts +0 -34
  15. package/skills/skill-banner-ad-suite/bin/cli.ts +0 -34
  16. package/skills/skill-benchmark-finder/bin/cli.ts +0 -34
  17. package/skills/skill-bio-sequence-tool/bin/cli.ts +0 -34
  18. package/skills/skill-blog-topic-cluster/bin/cli.ts +0 -34
  19. package/skills/skill-brand-style-guide/bin/cli.ts +0 -19
  20. package/skills/skill-brand-voice-audit/bin/cli.ts +0 -34
  21. package/skills/skill-budget-variance-analyzer/bin/cli.ts +0 -6
  22. package/skills/skill-businessactivity/bin/cli.ts +0 -28
  23. package/skills/skill-calendar-events/bin/cli.ts +0 -34
  24. package/skills/skill-campaign-metric-brief/bin/cli.ts +0 -34
  25. package/skills/skill-campaign-moodboard/bin/cli.ts +0 -34
  26. package/skills/skill-caption-style-stylist/bin/cli.ts +0 -34
  27. package/skills/skill-chemistry-calculator/bin/cli.ts +0 -34
  28. package/skills/skill-churn-risk-notifier/bin/cli.ts +0 -34
  29. package/skills/skill-citation-formatter/bin/cli.ts +0 -34
  30. package/skills/skill-classroom-newsletter-kit/bin/cli.ts +0 -34
  31. package/skills/skill-color-palette-harmonizer/bin/cli.ts +0 -34
  32. package/skills/skill-competitor-ad-analyzer/bin/cli.ts +0 -34
  33. package/skills/skill-compliance-copy-check/bin/cli.ts +0 -34
  34. package/skills/skill-compliance-report-pack/bin/cli.ts +0 -34
  35. package/skills/skill-compress-video/bin/cli.ts +0 -19
  36. package/skills/skill-consolelog/bin/cli.ts +0 -884
  37. package/skills/skill-contract-plainlanguage/bin/cli.ts +0 -34
  38. package/skills/skill-copytone-translator/bin/cli.ts +0 -34
  39. package/skills/skill-create-blog-article/bin/cli.ts +0 -34
  40. package/skills/skill-create-ebook/bin/cli.ts +0 -34
  41. package/skills/skill-crm-note-enhancer/bin/cli.ts +0 -34
  42. package/skills/skill-customer-journey-mapper/bin/cli.ts +0 -34
  43. package/skills/skill-dashboard-builder/bin/cli.ts +0 -34
  44. package/skills/skill-dashboard-narrator/bin/cli.ts +0 -34
  45. package/skills/skill-data-anonymizer/bin/cli.ts +0 -34
  46. package/skills/skill-database-explorer/bin/cli.ts +0 -34
  47. package/skills/skill-dataset-health-check/bin/cli.ts +0 -34
  48. package/skills/skill-decision-journal/bin/cli.ts +0 -34
  49. package/skills/skill-delegation-brief-writer/bin/cli.ts +0 -34
  50. package/skills/skill-destination-briefing/bin/cli.ts +0 -34
  51. package/skills/skill-diff-viewer/bin/cli.ts +0 -34
  52. package/skills/skill-domainpurchase/bin/cli.ts +0 -683
  53. package/skills/skill-domainsearch/bin/cli.ts +0 -410
  54. package/skills/skill-educational-resource-finder/bin/cli.ts +0 -34
  55. package/skills/skill-email-campaign/bin/cli.ts +0 -34
  56. package/skills/skill-exam-readiness-check/bin/cli.ts +0 -34
  57. package/skills/skill-experiment-power-calculator/bin/cli.ts +0 -34
  58. package/skills/skill-extract-audio/bin/cli.ts +0 -19
  59. package/skills/skill-extract-frames/bin/cli.ts +0 -34
  60. package/skills/skill-extract-invoice/bin/cli.ts +0 -34
  61. package/skills/skill-family-activity-curator/bin/cli.ts +0 -34
  62. package/skills/skill-faq-packager/bin/cli.ts +0 -34
  63. package/skills/skill-feedback-survey-designer/bin/cli.ts +0 -34
  64. package/skills/skill-field-trip-planner/bin/cli.ts +0 -34
  65. package/skills/skill-file-organizer/bin/cli.ts +0 -34
  66. package/skills/skill-folder-tree/bin/cli.ts +0 -34
  67. package/skills/skill-forecast-scenario-lab/bin/cli.ts +0 -34
  68. package/skills/skill-form-filler/bin/cli.ts +0 -34
  69. package/skills/skill-generate-api-client/bin/cli.ts +0 -34
  70. package/skills/skill-generate-book-cover/bin/cli.ts +0 -34
  71. package/skills/skill-generate-chart/bin/cli.ts +0 -34
  72. package/skills/skill-generate-diagram/bin/cli.ts +0 -34
  73. package/skills/skill-generate-dockerfile/bin/cli.ts +0 -34
  74. package/skills/skill-generate-documentation/bin/cli.ts +0 -34
  75. package/skills/skill-generate-docx/bin/cli.ts +0 -6
  76. package/skills/skill-generate-env/bin/cli.ts +0 -34
  77. package/skills/skill-generate-excel/bin/cli.ts +0 -34
  78. package/skills/skill-generate-favicon/bin/cli.ts +0 -34
  79. package/skills/skill-generate-mock-data/bin/cli.ts +0 -34
  80. package/skills/skill-generate-pdf/bin/cli.ts +0 -6
  81. package/skills/skill-generate-pr-description/bin/cli.ts +0 -34
  82. package/skills/skill-generate-presentation/bin/cli.ts +0 -34
  83. package/skills/skill-generate-qrcode/bin/cli.ts +0 -34
  84. package/skills/skill-generate-regex/bin/cli.ts +0 -34
  85. package/skills/skill-generate-resume/bin/cli.ts +0 -34
  86. package/skills/skill-generate-sitemap/bin/cli.ts +0 -34
  87. package/skills/skill-generate-social-posts/bin/cli.ts +0 -34
  88. package/skills/skill-generate-sql/bin/cli.ts +0 -34
  89. package/skills/skill-gif-maker/bin/cli.ts +0 -34
  90. package/skills/skill-github-manager/bin/cli.ts +0 -34
  91. package/skills/skill-gmail/bin/cli.ts +0 -34
  92. package/skills/skill-goal-quarterly-roadmap/bin/cli.ts +0 -34
  93. package/skills/skill-grant-application-drafter/bin/cli.ts +0 -34
  94. package/skills/skill-grocery-basket-optimizer/bin/cli.ts +0 -34
  95. package/skills/skill-guest-communication-suite/bin/cli.ts +0 -34
  96. package/skills/skill-habit-reflection-digest/bin/cli.ts +0 -34
  97. package/skills/skill-highlight-reel-generator/bin/cli.ts +0 -34
  98. package/skills/skill-homework-feedback-coach/bin/cli.ts +0 -34
  99. package/skills/skill-household-maintenance-mgr/bin/cli.ts +0 -34
  100. package/skills/skill-http-server/bin/cli.ts +0 -34
  101. package/skills/skill-implementation-agent/bin/cli.ts +0 -34
  102. package/skills/skill-implementation-plan/bin/cli.ts +0 -34
  103. package/skills/skill-implementation-todo/bin/cli.ts +0 -34
  104. package/skills/skill-inbox-priority-planner/bin/cli.ts +0 -34
  105. package/skills/skill-invoice/bin/cli.ts +0 -20
  106. package/skills/skill-invoice-dispute-helper/bin/cli.ts +0 -34
  107. package/skills/skill-itinerary-architect/bin/cli.ts +0 -34
  108. package/skills/skill-jingle-composer/bin/cli.ts +0 -34
  109. package/skills/skill-kpi-digest-generator/bin/cli.ts +0 -34
  110. package/skills/skill-lab-notebook-formatter/bin/cli.ts +0 -34
  111. package/skills/skill-landing-page-copy/bin/cli.ts +0 -34
  112. package/skills/skill-latex-table-generator/bin/cli.ts +0 -34
  113. package/skills/skill-learning-style-profiler/bin/cli.ts +0 -34
  114. package/skills/skill-lesson-plan-customizer/bin/cli.ts +0 -34
  115. package/skills/skill-livestream-runofshow/bin/cli.ts +0 -34
  116. package/skills/skill-longform-structurer/bin/cli.ts +0 -34
  117. package/skills/skill-lorem-generator/bin/cli.ts +0 -34
  118. package/skills/skill-managehook/bin/cli.ts +0 -241
  119. package/skills/skill-managemcp/bin/cli.ts +0 -241
  120. package/skills/skill-manageskill/bin/cli.ts +0 -241
  121. package/skills/skill-markdown-validator/bin/cli.ts +0 -34
  122. package/skills/skill-mcp-builder/bin/cli.ts +0 -34
  123. package/skills/skill-meal-plan-designer/bin/cli.ts +0 -34
  124. package/skills/skill-meeting-insight-summarizer/bin/cli.ts +0 -34
  125. package/skills/skill-merge-pdfs/bin/cli.ts +0 -34
  126. package/skills/skill-microcopy-generator/bin/cli.ts +0 -34
  127. package/skills/skill-mindfulness-prompt-cache/bin/cli.ts +0 -34
  128. package/skills/skill-notion-manager/bin/cli.ts +0 -34
  129. package/skills/skill-onboarding-sequence-builder/bin/cli.ts +0 -34
  130. package/skills/skill-onsite-ops-checklist/bin/cli.ts +0 -34
  131. package/skills/skill-outreach-cadence-designer/bin/cli.ts +0 -34
  132. package/skills/skill-packaging-concept-studio/bin/cli.ts +0 -34
  133. package/skills/skill-packing-plan-pro/bin/cli.ts +0 -34
  134. package/skills/skill-parent-teacher-brief/bin/cli.ts +0 -34
  135. package/skills/skill-partner-kit-assembler/bin/cli.ts +0 -34
  136. package/skills/skill-payroll-change-prepper/bin/cli.ts +0 -34
  137. package/skills/skill-persona-based-adwriter/bin/cli.ts +0 -34
  138. package/skills/skill-persona-generator/bin/cli.ts +0 -34
  139. package/skills/skill-personal-daily-ops/bin/cli.ts +0 -34
  140. package/skills/skill-pet-care-scheduler/bin/cli.ts +0 -34
  141. package/skills/skill-podcast-show-notes/bin/cli.ts +0 -34
  142. package/skills/skill-presentation-theme-maker/bin/cli.ts +0 -34
  143. package/skills/skill-press-release-drafter/bin/cli.ts +0 -34
  144. package/skills/skill-print-collateral-designer/bin/cli.ts +0 -34
  145. package/skills/skill-procurement-scorecard/bin/cli.ts +0 -34
  146. package/skills/skill-product-demo-script/bin/cli.ts +0 -34
  147. package/skills/skill-product-mockup/bin/cli.ts +0 -34
  148. package/skills/skill-project-retro-companion/bin/cli.ts +0 -34
  149. package/skills/skill-proposal-redline-advisor/bin/cli.ts +0 -34
  150. package/skills/skill-regex-tester/bin/cli.ts +0 -34
  151. package/skills/skill-remove-background/bin/cli.ts +0 -34
  152. package/skills/skill-risk-disclosure-kit/bin/cli.ts +0 -34
  153. package/skills/skill-roi-comparison-tool/bin/cli.ts +0 -34
  154. package/skills/skill-sales-call-recapper/bin/cli.ts +0 -34
  155. package/skills/skill-salescopy/bin/cli.ts +0 -20
  156. package/skills/skill-scaffold-project/bin/cli.ts +0 -34
  157. package/skills/skill-scholarship-tracker/bin/cli.ts +0 -34
  158. package/skills/skill-scientific-figure-check/bin/cli.ts +0 -34
  159. package/skills/skill-seating-chart-maker/bin/cli.ts +0 -34
  160. package/skills/skill-security-audit/bin/cli.ts +0 -34
  161. package/skills/skill-seo-brief-builder/bin/cli.ts +0 -34
  162. package/skills/skill-slack-assistant/bin/cli.ts +0 -34
  163. package/skills/skill-sleep-routine-analyzer/bin/cli.ts +0 -34
  164. package/skills/skill-social-media-kit/bin/cli.ts +0 -34
  165. package/skills/skill-split-pdf/bin/cli.ts +0 -34
  166. package/skills/skill-sponsorship-proposal-lab/bin/cli.ts +0 -34
  167. package/skills/skill-spreadsheet-cleanroom/bin/cli.ts +0 -34
  168. package/skills/skill-statistical-test-selector/bin/cli.ts +0 -34
  169. package/skills/skill-stress-relief-playbook/bin/cli.ts +0 -34
  170. package/skills/skill-study-guide-builder/bin/cli.ts +0 -34
  171. package/skills/skill-subscription-spend-watcher/bin/cli.ts +0 -34
  172. package/skills/skill-subtitle/bin/cli.ts +0 -20
  173. package/skills/skill-survey-insight-extractor/bin/cli.ts +0 -34
  174. package/skills/skill-terraform-generator/bin/cli.ts +0 -34
  175. package/skills/skill-testimonial-graphics/bin/cli.ts +0 -34
  176. package/skills/skill-timesheet/bin/cli.ts +0 -47
  177. package/skills/skill-travel-budget-balancer/bin/cli.ts +0 -34
  178. package/skills/skill-validate-config/bin/cli.ts +0 -34
  179. package/skills/skill-video-cut-suggester/bin/cli.ts +0 -34
  180. package/skills/skill-video-downloader/bin/cli.ts +0 -34
  181. package/skills/skill-video-thumbnail/bin/cli.ts +0 -34
  182. package/skills/skill-voiceover-casting-assistant/bin/cli.ts +0 -34
  183. package/skills/skill-watermark/bin/cli.ts +0 -34
  184. package/skills/skill-webcrawling/bin/cli.ts +0 -21
  185. package/skills/skill-webinar-script-coach/bin/cli.ts +0 -34
  186. package/skills/skill-wellness-progress-reporter/bin/cli.ts +0 -34
  187. package/skills/skill-workout-cycle-planner/bin/cli.ts +0 -34
@@ -1,683 +0,0 @@
1
- #!/usr/bin/env bun
2
-
3
- import { Command } from "commander";
4
- import {
5
- loadConfig,
6
- saveConfig,
7
- CONFIG_FILE,
8
- getApiKey,
9
- getApiSecret,
10
- getCustomerId,
11
- } from "../src/lib/config";
12
- import { purchaseApi, domainApi, formatPrice, type Contact, type DomainPurchaseRequestV2 } from "../src/lib/api-client";
13
- import { ensureInstalled } from "../src/lib/installer";
14
-
15
- // Ensure service directory exists on startup
16
- ensureInstalled();
17
-
18
- const program = new Command();
19
-
20
- program
21
- .name("service-domainpurchase")
22
- .description("CLI tool for purchasing and managing domains via Brandsight/GoDaddy API")
23
- .version("1.0.0");
24
-
25
- // ============ CONFIG COMMANDS ============
26
-
27
- program
28
- .command("config")
29
- .description("Show or set configuration")
30
- .option("--api-key <key>", "Set GoDaddy API key (direct mode)")
31
- .option("--api-secret <secret>", "Set GoDaddy API secret (direct mode)")
32
- .option("--customer-id <id>", "Set GoDaddy customer ID (direct mode)")
33
- .option("--api-url <url>", "Set GoDaddy API URL (direct mode)")
34
- .option("--use-remote <bool>", "Use remote server instead of direct API (true/false)")
35
- .option("--remote-url <url>", "Set remote server URL")
36
- .option("--remote-api-key <key>", "Set remote server API key")
37
- .option("--show", "Show current configuration")
38
- .action(async (options) => {
39
- const config = loadConfig();
40
-
41
- if (options.apiKey) {
42
- saveConfig({ apiKey: options.apiKey });
43
- console.log("API key saved");
44
- }
45
-
46
- if (options.apiSecret) {
47
- saveConfig({ apiSecret: options.apiSecret });
48
- console.log("API secret saved");
49
- }
50
-
51
- if (options.customerId) {
52
- saveConfig({ customerId: options.customerId });
53
- console.log("Customer ID saved");
54
- }
55
-
56
- if (options.apiUrl) {
57
- saveConfig({ apiUrl: options.apiUrl });
58
- console.log(`API URL set to: ${options.apiUrl}`);
59
- }
60
-
61
- if (options.useRemote !== undefined) {
62
- const useRemote = options.useRemote === "true";
63
- saveConfig({ useRemoteServer: useRemote });
64
- console.log(`Remote server mode: ${useRemote ? "ENABLED" : "DISABLED"}`);
65
- }
66
-
67
- if (options.remoteUrl) {
68
- saveConfig({ remoteServerUrl: options.remoteUrl });
69
- console.log(`Remote server URL set to: ${options.remoteUrl}`);
70
- }
71
-
72
- if (options.remoteApiKey) {
73
- saveConfig({ remoteApiKey: options.remoteApiKey });
74
- console.log("Remote API key saved");
75
- }
76
-
77
- const hasOptions = options.apiKey || options.apiSecret || options.customerId ||
78
- options.apiUrl || options.useRemote !== undefined ||
79
- options.remoteUrl || options.remoteApiKey;
80
-
81
- if (options.show || !hasOptions) {
82
- const currentConfig = loadConfig();
83
- console.log("\nConfiguration:");
84
- console.log(` Config file: ${CONFIG_FILE}`);
85
- console.log("");
86
- console.log(" Mode: " + (currentConfig.useRemoteServer ? "REMOTE SERVER" : "DIRECT API"));
87
- console.log("");
88
-
89
- if (currentConfig.useRemoteServer) {
90
- console.log(" Remote Server Settings:");
91
- console.log(` URL: ${currentConfig.remoteServerUrl}`);
92
- console.log(` API Key: ${currentConfig.remoteApiKey ? "***" + currentConfig.remoteApiKey.slice(-4) : "(auto from AWS)"}`);
93
- } else {
94
- console.log(" Direct API Settings:");
95
- console.log(` API URL: ${currentConfig.apiUrl}`);
96
- console.log(` API Key: ${currentConfig.apiKey ? "***" + currentConfig.apiKey.slice(-4) : "(not set)"}`);
97
- console.log(` API Secret: ${currentConfig.apiSecret ? "***" + currentConfig.apiSecret.slice(-4) : "(not set)"}`);
98
- console.log(` Customer ID: ${currentConfig.customerId || "(not set)"}`);
99
- }
100
-
101
- console.log("\n Tip: Use --use-remote true to switch to remote server mode");
102
- }
103
- });
104
-
105
- // ============ CHECK COMMAND ============
106
-
107
- program
108
- .command("check <domain>")
109
- .description("Check domain availability and pricing")
110
- .option("--transfer", "Check for transfer instead of registration")
111
- .option("--json", "Output as JSON")
112
- .action(async (domain, options) => {
113
- try {
114
- const result = await domainApi.checkAvailability(domain, options.transfer);
115
-
116
- if (options.json) {
117
- console.log(JSON.stringify(result, null, 2));
118
- return;
119
- }
120
-
121
- const status = result.available ? "AVAILABLE" : "TAKEN";
122
- const price = result.price
123
- ? formatPrice(result.price, result.currency)
124
- : "N/A";
125
- const premium = result.registryPremiumPricing ? " [PREMIUM]" : "";
126
-
127
- console.log(`\nDomain: ${domain}`);
128
- console.log(`Status: ${status}`);
129
- if (result.available) {
130
- console.log(`Price: ${price}${premium}`);
131
- console.log(`Period: ${result.period || 1} year(s)`);
132
- }
133
- } catch (error) {
134
- console.error("Error:", error instanceof Error ? error.message : error);
135
- process.exit(1);
136
- }
137
- });
138
-
139
- // ============ AGREEMENTS COMMAND ============
140
-
141
- program
142
- .command("agreements <tlds...>")
143
- .description("Get legal agreements for TLDs (required before purchase)")
144
- .option("--privacy", "Include privacy agreements")
145
- .option("--json", "Output as JSON")
146
- .action(async (tlds, options) => {
147
- try {
148
- const agreements = await domainApi.getAgreements(tlds, options.privacy);
149
-
150
- if (options.json) {
151
- console.log(JSON.stringify(agreements, null, 2));
152
- return;
153
- }
154
-
155
- console.log(`\nAgreements for: ${tlds.join(", ")}\n`);
156
-
157
- for (const a of agreements) {
158
- console.log(` [${a.agreementKey}] ${a.title}`);
159
- console.log(` URL: ${a.url}\n`);
160
- }
161
-
162
- console.log(`\nTotal: ${agreements.length} agreement(s)`);
163
- console.log(`\nUse these agreement keys when purchasing domains.`);
164
- } catch (error) {
165
- console.error("Error:", error instanceof Error ? error.message : error);
166
- process.exit(1);
167
- }
168
- });
169
-
170
- // ============ VALIDATE COMMAND ============
171
-
172
- program
173
- .command("validate <domain>")
174
- .description("Validate a domain purchase request (dry run)")
175
- .option("--contact-json <path>", "Path to JSON file with contact info")
176
- .option("--period <years>", "Registration period in years", "1")
177
- .option("--privacy", "Enable WHOIS privacy")
178
- .option("--auto-renew", "Enable auto renewal")
179
- .option("--json", "Output as JSON")
180
- .action(async (domain, options) => {
181
- try {
182
- // Check availability first to get price
183
- console.log(`Checking availability for ${domain}...`);
184
- const availability = await domainApi.checkAvailability(domain);
185
-
186
- if (!availability.available) {
187
- console.error(`\nError: ${domain} is not available for registration.`);
188
- process.exit(1);
189
- }
190
-
191
- const price = availability.price || 0;
192
- const currency = availability.currency || "USD";
193
- console.log(`Domain available! Price: ${formatPrice(price, currency)}\n`);
194
-
195
- // Get TLD from domain
196
- const tld = domain.split(".").slice(1).join(".");
197
-
198
- // Get agreements
199
- console.log(`Fetching agreements for .${tld}...`);
200
- const agreements = await domainApi.getAgreements([tld], options.privacy);
201
- const agreementKeys = agreements.map((a) => a.agreementKey);
202
-
203
- // Load contact info
204
- let contact: Contact;
205
- if (options.contactJson) {
206
- const file = await Bun.file(options.contactJson);
207
- contact = await file.json();
208
- } else {
209
- // Use placeholder contact for validation
210
- contact = {
211
- nameFirst: "Test",
212
- nameLast: "User",
213
- email: "test@example.com",
214
- phone: "+1.5555555555",
215
- addressMailing: {
216
- address1: "123 Test St",
217
- city: "Test City",
218
- state: "CA",
219
- postalCode: "90210",
220
- country: "US",
221
- },
222
- encoding: "ASCII",
223
- };
224
- console.log("\nUsing placeholder contact info for validation.");
225
- console.log("For actual purchase, provide --contact-json <path>\n");
226
- }
227
-
228
- // Ensure contact has encoding
229
- if (!contact.encoding) {
230
- contact.encoding = "ASCII";
231
- }
232
-
233
- // Get public IP for consent
234
- const ipResponse = await fetch("https://api.ipify.org?format=json");
235
- const ipData = await ipResponse.json() as { ip: string };
236
-
237
- // Build V2 API request format with all contacts
238
- const request: DomainPurchaseRequestV2 = {
239
- domain,
240
- consent: {
241
- agreedAt: new Date().toISOString(),
242
- agreedBy: ipData.ip,
243
- agreementKeys,
244
- price,
245
- currency,
246
- },
247
- contacts: {
248
- registrant: contact,
249
- admin: contact,
250
- billing: contact,
251
- tech: contact,
252
- },
253
- period: parseInt(options.period),
254
- privacy: options.privacy || false,
255
- renewAuto: options.autoRenew || false,
256
- };
257
-
258
- console.log("Validating purchase request...\n");
259
- const result = await domainApi.validatePurchase(request);
260
-
261
- if (options.json) {
262
- console.log(JSON.stringify(result, null, 2));
263
- return;
264
- }
265
-
266
- if (result.valid) {
267
- console.log("Validation: PASSED");
268
- console.log("\nThe domain purchase request is valid.");
269
- console.log("Use the 'purchase' command to complete the purchase.");
270
- } else {
271
- console.log("Validation: FAILED");
272
- console.log(`Status: ${result.status}`);
273
- console.log(`Response: ${JSON.stringify(result.data, null, 2)}`);
274
- }
275
- } catch (error) {
276
- console.error("Error:", error instanceof Error ? error.message : error);
277
- process.exit(1);
278
- }
279
- });
280
-
281
- // ============ PURCHASE COMMAND ============
282
-
283
- program
284
- .command("purchase <domain>")
285
- .description("Purchase a domain")
286
- .requiredOption("--contact-json <path>", "Path to JSON file with contact info")
287
- .option("--period <years>", "Registration period in years", "1")
288
- .option("--privacy", "Enable WHOIS privacy")
289
- .option("--auto-renew", "Enable auto renewal")
290
- .option("--nameservers <ns>", "Comma-separated nameservers (max 2)")
291
- .option("--dry-run", "Validate only, don't actually purchase")
292
- .option("--json", "Output as JSON")
293
- .action(async (domain, options) => {
294
- try {
295
- // Check availability first
296
- console.log(`Checking availability for ${domain}...`);
297
- const availability = await domainApi.checkAvailability(domain);
298
-
299
- if (!availability.available) {
300
- console.error(`\nError: ${domain} is not available for registration.`);
301
- process.exit(1);
302
- }
303
-
304
- const price = availability.price || 0;
305
- const currency = availability.currency || "USD";
306
- console.log(`Domain available! Price: ${formatPrice(price, currency)}\n`);
307
-
308
- // Get TLD from domain
309
- const tld = domain.split(".").slice(1).join(".");
310
-
311
- // Get agreements
312
- console.log(`Fetching agreements for .${tld}...`);
313
- const agreements = await domainApi.getAgreements([tld], options.privacy);
314
- const agreementKeys = agreements.map((a) => a.agreementKey);
315
- console.log(`Found ${agreements.length} agreement(s)\n`);
316
-
317
- // Load contact info
318
- const contactFile = await Bun.file(options.contactJson);
319
- const contact: Contact = await contactFile.json();
320
-
321
- // Ensure contact has encoding
322
- if (!contact.encoding) {
323
- contact.encoding = "ASCII";
324
- }
325
-
326
- // Get public IP for consent
327
- const ipResponse = await fetch("https://api.ipify.org?format=json");
328
- const ipData = await ipResponse.json() as { ip: string };
329
-
330
- // Build V2 API request format with all contacts
331
- const request: DomainPurchaseRequestV2 = {
332
- domain,
333
- consent: {
334
- agreedAt: new Date().toISOString(),
335
- agreedBy: ipData.ip,
336
- agreementKeys,
337
- price,
338
- currency,
339
- },
340
- contacts: {
341
- registrant: contact,
342
- admin: contact,
343
- billing: contact,
344
- tech: contact,
345
- },
346
- period: parseInt(options.period),
347
- privacy: options.privacy || false,
348
- renewAuto: options.autoRenew || false,
349
- ...(options.nameservers && {
350
- nameServers: options.nameservers.split(",").map((ns: string) => ns.trim()).slice(0, 2),
351
- }),
352
- };
353
-
354
- if (options.dryRun) {
355
- console.log("Validating purchase request (dry run)...\n");
356
- const result = await domainApi.validatePurchase(request);
357
-
358
- if (options.json) {
359
- console.log(JSON.stringify(result, null, 2));
360
- return;
361
- }
362
-
363
- if (result.valid) {
364
- console.log("Validation: PASSED");
365
- console.log("\nRemove --dry-run to complete the purchase.");
366
- } else {
367
- console.log("Validation: FAILED");
368
- console.log(`Response: ${JSON.stringify(result.data, null, 2)}`);
369
- }
370
- return;
371
- }
372
-
373
- // Actual purchase
374
- console.log("Processing purchase...\n");
375
- const result = await domainApi.purchaseDomain(request);
376
-
377
- if (options.json) {
378
- console.log(JSON.stringify(result, null, 2));
379
- return;
380
- }
381
-
382
- console.log("Purchase completed!");
383
- console.log(`Domain: ${domain}`);
384
- console.log(`Order ID: ${result.orderId || "N/A"}`);
385
- console.log(`\nUse 'service-domainpurchase info ${domain}' to view details.`);
386
- } catch (error) {
387
- console.error("Error:", error instanceof Error ? error.message : error);
388
- process.exit(1);
389
- }
390
- });
391
-
392
- // ============ LIST COMMAND ============
393
-
394
- program
395
- .command("list")
396
- .description("List domains owned by your account")
397
- .option("-l, --limit <count>", "Maximum domains to list", "100")
398
- .option("--json", "Output as JSON")
399
- .action(async (options) => {
400
- try {
401
- const domains = await domainApi.listOwnedDomains(parseInt(options.limit));
402
-
403
- if (options.json) {
404
- console.log(JSON.stringify(domains, null, 2));
405
- return;
406
- }
407
-
408
- console.log(`\nOwned Domains (${domains.length}):\n`);
409
-
410
- for (const d of domains) {
411
- const expires = d.expires
412
- ? new Date(d.expires).toLocaleDateString()
413
- : "N/A";
414
- const autoRenew = d.renewAuto ? "[AUTO]" : "";
415
- const privacy = d.privacy ? "[PRIVATE]" : "";
416
- console.log(
417
- ` ${d.domain.padEnd(35)} expires: ${expires} ${autoRenew} ${privacy}`
418
- );
419
- }
420
- } catch (error) {
421
- console.error("Error:", error instanceof Error ? error.message : error);
422
- process.exit(1);
423
- }
424
- });
425
-
426
- // ============ INFO COMMAND ============
427
-
428
- program
429
- .command("info <domain>")
430
- .description("Get detailed information about an owned domain")
431
- .option("--json", "Output as JSON")
432
- .action(async (domain, options) => {
433
- try {
434
- const details = await domainApi.getDomainDetails(domain);
435
-
436
- if (options.json) {
437
- console.log(JSON.stringify(details, null, 2));
438
- return;
439
- }
440
-
441
- console.log(`\nDomain: ${details.domain}`);
442
- console.log(`Status: ${details.status}`);
443
- console.log(`Created: ${details.createdAt}`);
444
- console.log(`Expires: ${details.expires}`);
445
- console.log(`Auto Renew: ${details.renewAuto ? "Yes" : "No"}`);
446
- console.log(`Privacy: ${details.privacy ? "Yes" : "No"}`);
447
-
448
- if (details.nameServers?.length) {
449
- console.log(`\nNameservers:`);
450
- for (const ns of details.nameServers) {
451
- console.log(` - ${ns}`);
452
- }
453
- }
454
-
455
- if (details.contactRegistrant) {
456
- console.log(`\nRegistrant:`);
457
- console.log(
458
- ` ${details.contactRegistrant.nameFirst} ${details.contactRegistrant.nameLast}`
459
- );
460
- console.log(` ${details.contactRegistrant.email}`);
461
- }
462
- } catch (error) {
463
- console.error("Error:", error instanceof Error ? error.message : error);
464
- process.exit(1);
465
- }
466
- });
467
-
468
- // ============ UPDATE COMMAND ============
469
-
470
- program
471
- .command("update <domain>")
472
- .description("Update domain settings")
473
- .option("--auto-renew <bool>", "Enable/disable auto renewal (true/false)")
474
- .option("--privacy <bool>", "Enable/disable WHOIS privacy (true/false)")
475
- .option("--nameservers <ns>", "Comma-separated nameservers")
476
- .option("--json", "Output as JSON")
477
- .action(async (domain, options) => {
478
- try {
479
- const updates: any = {};
480
-
481
- if (options.autoRenew !== undefined) {
482
- updates.renewAuto = options.autoRenew === "true";
483
- }
484
-
485
- if (options.privacy !== undefined) {
486
- updates.privacy = options.privacy === "true";
487
- }
488
-
489
- if (options.nameservers) {
490
- updates.nameServers = options.nameservers
491
- .split(",")
492
- .map((ns: string) => ns.trim());
493
- }
494
-
495
- if (Object.keys(updates).length === 0) {
496
- console.error("Error: No updates specified.");
497
- console.log("\nOptions:");
498
- console.log(" --auto-renew <true|false>");
499
- console.log(" --privacy <true|false>");
500
- console.log(" --nameservers <ns1,ns2,...>");
501
- process.exit(1);
502
- }
503
-
504
- console.log(`Updating ${domain}...`);
505
- const result = await domainApi.updateDomain(domain, updates);
506
-
507
- if (options.json) {
508
- console.log(JSON.stringify(result, null, 2));
509
- return;
510
- }
511
-
512
- console.log("\nDomain updated successfully!");
513
- console.log(`Applied changes: ${JSON.stringify(updates)}`);
514
- } catch (error) {
515
- console.error("Error:", error instanceof Error ? error.message : error);
516
- process.exit(1);
517
- }
518
- });
519
-
520
- // ============ RENEW COMMAND ============
521
-
522
- program
523
- .command("renew <domain>")
524
- .description("Renew a domain registration")
525
- .option("-p, --period <years>", "Renewal period in years", "1")
526
- .option("--json", "Output as JSON")
527
- .action(async (domain, options) => {
528
- try {
529
- console.log(`Renewing ${domain} for ${options.period} year(s)...`);
530
- const result = await domainApi.renewDomain(domain, parseInt(options.period));
531
-
532
- if (options.json) {
533
- console.log(JSON.stringify(result, null, 2));
534
- return;
535
- }
536
-
537
- console.log("\nRenewal completed!");
538
- console.log(`Domain: ${domain}`);
539
- console.log(`Period: ${options.period} year(s)`);
540
- } catch (error) {
541
- console.error("Error:", error instanceof Error ? error.message : error);
542
- process.exit(1);
543
- }
544
- });
545
-
546
- // ============ TRANSFER COMMAND ============
547
-
548
- program
549
- .command("transfer <domain>")
550
- .description("Transfer a domain to your account")
551
- .requiredOption("--auth-code <code>", "Authorization/EPP code from current registrar")
552
- .requiredOption("--contact-json <path>", "Path to JSON file with contact info")
553
- .option("--json", "Output as JSON")
554
- .action(async (domain, options) => {
555
- try {
556
- // Get TLD from domain
557
- const tld = domain.split(".").slice(1).join(".");
558
-
559
- // Get agreements
560
- console.log(`Fetching transfer agreements for .${tld}...`);
561
- const agreements = await purchaseApi.getAgreements([tld], false);
562
- const agreementKeys = agreements.map((a) => a.agreementKey);
563
-
564
- // Load contact info
565
- const contactFile = await Bun.file(options.contactJson);
566
- const contact: Contact = await contactFile.json();
567
-
568
- // Get public IP for consent
569
- const ipResponse = await fetch("https://api.ipify.org?format=json");
570
- const ipData = await ipResponse.json() as { ip: string };
571
-
572
- const consent = {
573
- agreedAt: new Date().toISOString(),
574
- agreedBy: ipData.ip,
575
- agreementKeys,
576
- };
577
-
578
- console.log(`Initiating transfer of ${domain}...`);
579
- const result = await purchaseApi.initiateTransfer(
580
- domain,
581
- options.authCode,
582
- consent,
583
- contact
584
- );
585
-
586
- if (options.json) {
587
- console.log(JSON.stringify(result, null, 2));
588
- return;
589
- }
590
-
591
- console.log("\nTransfer initiated!");
592
- console.log(`Domain: ${domain}`);
593
- console.log(
594
- "\nNote: The transfer may take several days to complete."
595
- );
596
- console.log("Check your email for any required confirmations.");
597
- } catch (error) {
598
- console.error("Error:", error instanceof Error ? error.message : error);
599
- process.exit(1);
600
- }
601
- });
602
-
603
- // ============ CONTACT-TEMPLATE COMMAND ============
604
-
605
- program
606
- .command("contact-template")
607
- .description("Generate a contact info JSON template")
608
- .option("-o, --output <path>", "Output file path")
609
- .action(async (options) => {
610
- const template = {
611
- nameFirst: "John",
612
- nameLast: "Doe",
613
- email: "john.doe@example.com",
614
- phone: "+1.5551234567",
615
- organization: "Example Corp",
616
- addressMailing: {
617
- address1: "123 Main Street",
618
- address2: "Suite 100",
619
- city: "San Francisco",
620
- state: "CA",
621
- postalCode: "94102",
622
- country: "US",
623
- },
624
- encoding: "UTF-8",
625
- };
626
-
627
- const json = JSON.stringify(template, null, 2);
628
-
629
- if (options.output) {
630
- await Bun.write(options.output, json);
631
- console.log(`Contact template saved to: ${options.output}`);
632
- } else {
633
- console.log("\nContact Info Template:\n");
634
- console.log(json);
635
- console.log("\nSave this to a file and use with --contact-json <path>");
636
- }
637
- });
638
-
639
- // ============ SETUP COMMAND ============
640
-
641
- program
642
- .command("setup")
643
- .description("Interactive setup for service-domainpurchase")
644
- .action(async () => {
645
- console.log("\nservice-domainpurchase Setup\n");
646
- console.log("This will configure your Brandsight/GoDaddy API credentials.\n");
647
-
648
- const config = loadConfig();
649
-
650
- if (!config.apiKey || !config.apiSecret) {
651
- console.log("API credentials not configured.\n");
652
- console.log("Get your API key and secret from:");
653
- console.log(" https://developer.godaddy.com/keys\n");
654
- console.log("Then run:");
655
- console.log(" service-domainpurchase config --api-key <key> --api-secret <secret>");
656
- console.log(" service-domainpurchase config --customer-id <id>\n");
657
- } else {
658
- console.log(`API Key: ***${config.apiKey.slice(-4)}`);
659
- console.log(`API Secret: ***${config.apiSecret.slice(-4)}`);
660
- console.log(`Customer ID: ${config.customerId || "(not set)"}`);
661
- console.log(`API URL: ${config.apiUrl}\n`);
662
-
663
- // Test connection
664
- console.log("Testing connection...");
665
- try {
666
- const domains = await domainApi.listOwnedDomains(5);
667
- console.log(` Connected! Found ${domains.length} domains in your account.\n`);
668
-
669
- console.log("Quick commands:");
670
- console.log(" service-domainpurchase check example.com");
671
- console.log(" service-domainpurchase list");
672
- console.log(" service-domainpurchase contact-template -o contact.json");
673
- console.log(" service-domainpurchase purchase example.com --contact-json contact.json --dry-run");
674
- } catch (error) {
675
- console.error(
676
- " Connection failed:",
677
- error instanceof Error ? error.message : error
678
- );
679
- }
680
- }
681
- });
682
-
683
- program.parse();