@nordsym/apiclaw 2.1.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/README.md +15 -2
  2. package/dist/bin-http.js +0 -0
  3. package/dist/bin.bundled.js +79288 -0
  4. package/dist/funnel-client.d.ts +24 -0
  5. package/dist/funnel-client.d.ts.map +1 -0
  6. package/dist/funnel-client.js +131 -0
  7. package/dist/funnel-client.js.map +1 -0
  8. package/dist/funnel.test.d.ts +2 -0
  9. package/dist/funnel.test.d.ts.map +1 -0
  10. package/dist/funnel.test.js +145 -0
  11. package/dist/funnel.test.js.map +1 -0
  12. package/dist/gateway-client.d.ts.map +1 -1
  13. package/dist/gateway-client.js +24 -2
  14. package/dist/gateway-client.js.map +1 -1
  15. package/dist/index.bundled.js +61263 -0
  16. package/dist/index.js +161 -74
  17. package/dist/index.js.map +1 -1
  18. package/dist/postinstall.d.ts +0 -5
  19. package/dist/postinstall.d.ts.map +1 -1
  20. package/dist/postinstall.js +24 -3
  21. package/dist/postinstall.js.map +1 -1
  22. package/dist/registration-guard.d.ts +29 -0
  23. package/dist/registration-guard.d.ts.map +1 -0
  24. package/dist/registration-guard.js +87 -0
  25. package/dist/registration-guard.js.map +1 -0
  26. package/package.json +7 -2
  27. package/.claude/settings.local.json +0 -9
  28. package/.env.prod +0 -1
  29. package/apiclaw-README.md +0 -494
  30. package/convex/_generated/api.d.ts +0 -137
  31. package/convex/_generated/api.js +0 -23
  32. package/convex/_generated/dataModel.d.ts +0 -60
  33. package/convex/_generated/server.d.ts +0 -143
  34. package/convex/_generated/server.js +0 -93
  35. package/convex/adminActivate.ts +0 -53
  36. package/convex/adminStats.ts +0 -306
  37. package/convex/agents.ts +0 -939
  38. package/convex/analytics.ts +0 -187
  39. package/convex/apiKeys.ts +0 -220
  40. package/convex/backfillAnalytics.ts +0 -272
  41. package/convex/backfillSearchLogs.ts +0 -35
  42. package/convex/billing.ts +0 -834
  43. package/convex/capabilities.ts +0 -157
  44. package/convex/chains.ts +0 -1318
  45. package/convex/credits.ts +0 -211
  46. package/convex/crons.ts +0 -50
  47. package/convex/debugFilestackLogs.ts +0 -16
  48. package/convex/debugGetToken.ts +0 -18
  49. package/convex/directCall.ts +0 -713
  50. package/convex/earnProgress.ts +0 -753
  51. package/convex/email.ts +0 -329
  52. package/convex/feedback.ts +0 -265
  53. package/convex/http.ts +0 -3430
  54. package/convex/inbound.ts +0 -32
  55. package/convex/logs.ts +0 -701
  56. package/convex/migrateFilestack.ts +0 -81
  57. package/convex/migratePartnersProd.ts +0 -174
  58. package/convex/migratePratham.ts +0 -126
  59. package/convex/migrateProviderWorkspaces.ts +0 -175
  60. package/convex/mou.ts +0 -91
  61. package/convex/providerKeys.ts +0 -289
  62. package/convex/providers.ts +0 -1135
  63. package/convex/purchases.ts +0 -183
  64. package/convex/ratelimit.ts +0 -104
  65. package/convex/schema.ts +0 -869
  66. package/convex/searchLogs.ts +0 -265
  67. package/convex/seedAPILayerAPIs.ts +0 -191
  68. package/convex/seedDirectCallConfigs.ts +0 -336
  69. package/convex/seedPratham.ts +0 -149
  70. package/convex/spendAlerts.ts +0 -442
  71. package/convex/stripeActions.ts +0 -607
  72. package/convex/teams.ts +0 -243
  73. package/convex/telemetry.ts +0 -81
  74. package/convex/tsconfig.json +0 -25
  75. package/convex/updateAPIStatus.ts +0 -44
  76. package/convex/usage.ts +0 -260
  77. package/convex/usageReports.ts +0 -357
  78. package/convex/waitlist.ts +0 -55
  79. package/convex/webhooks.ts +0 -494
  80. package/convex/workspaceSettings.ts +0 -143
  81. package/convex/workspaces.ts +0 -1331
  82. package/convex.json +0 -3
  83. package/direct-test.mjs +0 -51
  84. package/email-templates/filestack-provider-outreach.html +0 -162
  85. package/email-templates/partnership-template.html +0 -116
  86. package/email-templates/pratham-draft-preview.txt +0 -57
  87. package/email-templates/pratham-partnership-draft.html +0 -141
  88. package/reports/APIClaw-Session-Report-2026-04-05.pdf +0 -0
  89. package/reports/pipeline/PIPELINE-REPORT.json +0 -153
  90. package/reports/pipeline/acquire_apisguru.json +0 -17
  91. package/reports/pipeline/capabilities.json +0 -38
  92. package/reports/pipeline/discover_azure_recursive.json +0 -1551
  93. package/reports/pipeline/discover_github.json +0 -25
  94. package/reports/pipeline/discover_github_repos.json +0 -49
  95. package/reports/pipeline/discover_swaggerhub.json +0 -24
  96. package/reports/pipeline/discover_well_known.json +0 -23
  97. package/reports/pipeline/fetch_specs.json +0 -19
  98. package/reports/pipeline/generate_providers.json +0 -14
  99. package/reports/pipeline/match_registry.json +0 -11
  100. package/reports/pipeline/parse_specs.json +0 -17
  101. package/reports/pipeline/promote_candidates.json +0 -34
  102. package/reports/pipeline/validate.json +0 -30
  103. package/reports/pipeline/validate_smoke_details.json +0 -3835
  104. package/reports/session-report-2026-04-05.html +0 -433
  105. package/seed-apis-direct.mjs +0 -106
  106. package/src/access-control.ts +0 -174
  107. package/src/adapters/base.ts +0 -364
  108. package/src/adapters/claude-desktop.ts +0 -41
  109. package/src/adapters/cline.ts +0 -88
  110. package/src/adapters/continue.ts +0 -91
  111. package/src/adapters/cursor.ts +0 -43
  112. package/src/adapters/custom.ts +0 -188
  113. package/src/adapters/detect.ts +0 -202
  114. package/src/adapters/index.ts +0 -47
  115. package/src/adapters/windsurf.ts +0 -44
  116. package/src/bin-http.ts +0 -45
  117. package/src/bin.ts +0 -34
  118. package/src/capability-router.ts +0 -331
  119. package/src/chainExecutor.ts +0 -730
  120. package/src/chainResolver.test.ts +0 -246
  121. package/src/chainResolver.ts +0 -658
  122. package/src/cli/commands/demo.ts +0 -109
  123. package/src/cli/commands/doctor.ts +0 -435
  124. package/src/cli/commands/index.ts +0 -9
  125. package/src/cli/commands/login.ts +0 -203
  126. package/src/cli/commands/mcp-install.ts +0 -373
  127. package/src/cli/commands/restore.ts +0 -333
  128. package/src/cli/commands/setup.ts +0 -297
  129. package/src/cli/commands/uninstall.ts +0 -240
  130. package/src/cli/index.ts +0 -148
  131. package/src/cli.ts +0 -370
  132. package/src/confirmation.ts +0 -296
  133. package/src/credentials.ts +0 -455
  134. package/src/credits.ts +0 -329
  135. package/src/crypto.ts +0 -75
  136. package/src/discovery.ts +0 -568
  137. package/src/enterprise/env.ts +0 -156
  138. package/src/enterprise/index.ts +0 -7
  139. package/src/enterprise/script-generator.ts +0 -481
  140. package/src/execute-dynamic.ts +0 -617
  141. package/src/execute.ts +0 -2386
  142. package/src/gateway-client.ts +0 -192
  143. package/src/hivr-whitelist.ts +0 -110
  144. package/src/http-api.ts +0 -286
  145. package/src/http-server-minimal.ts +0 -154
  146. package/src/index.ts +0 -2611
  147. package/src/intelligent-gateway.ts +0 -339
  148. package/src/mcp-analytics.ts +0 -156
  149. package/src/metered.ts +0 -149
  150. package/src/open-apis-generated.ts +0 -157
  151. package/src/open-apis.ts +0 -558
  152. package/src/postinstall.ts +0 -18
  153. package/src/product-whitelist.ts +0 -246
  154. package/src/proxy.ts +0 -36
  155. package/src/session.ts +0 -129
  156. package/src/stripe.ts +0 -497
  157. package/src/telemetry.ts +0 -71
  158. package/src/test.ts +0 -135
  159. package/src/types/convex-api.d.ts +0 -20
  160. package/src/types/convex-api.ts +0 -21
  161. package/src/types.ts +0 -109
  162. package/src/ui/colors.ts +0 -219
  163. package/src/ui/errors.ts +0 -394
  164. package/src/ui/index.ts +0 -17
  165. package/src/ui/prompts.ts +0 -390
  166. package/src/ui/spinner.ts +0 -325
  167. package/src/utils/backup.ts +0 -224
  168. package/src/utils/config.ts +0 -318
  169. package/src/utils/os.ts +0 -124
  170. package/src/utils/paths.ts +0 -203
  171. package/src/webhook.ts +0 -107
  172. package/test-10-working.cjs +0 -97
  173. package/test-14-final.cjs +0 -96
  174. package/test-actual-handlers.ts +0 -92
  175. package/test-apilayer-all-14.ts +0 -249
  176. package/test-apilayer-fixed.ts +0 -248
  177. package/test-direct-endpoints.ts +0 -174
  178. package/test-exact-endpoints.ts +0 -144
  179. package/test-final.ts +0 -83
  180. package/test-full-routing.ts +0 -100
  181. package/test-handlers-correct.ts +0 -217
  182. package/test-numverify-key.ts +0 -41
  183. package/test-via-handlers.ts +0 -92
  184. package/test-worldnews.mjs +0 -26
  185. package/tsconfig.json +0 -20
@@ -1,333 +0,0 @@
1
- /**
2
- * Restore Command
3
- * Rollback MCP client configs from backups
4
- */
5
-
6
- import { existsSync } from 'fs';
7
- import {
8
- listBackups,
9
- restoreBackup as doRestore,
10
- getLatestBackup,
11
- formatBackupInfo,
12
- BackupInfo
13
- } from '../../utils/backup.js';
14
- import { getAllClients, getClientConfig, MCPClient, parseClientArg } from '../../utils/paths.js';
15
-
16
- export interface RestoreOptions {
17
- client?: string; // Specific client to restore
18
- backup?: string; // Specific backup file path
19
- list?: boolean; // List available backups
20
- all?: boolean; // Restore all clients
21
- interactive?: boolean; // Interactive mode (future)
22
- dryRun?: boolean; // Show what would be done
23
- }
24
-
25
- export interface RestoreResult {
26
- success: boolean;
27
- client: string;
28
- message: string;
29
- backupUsed?: string;
30
- preRestoreBackup?: string;
31
- }
32
-
33
- /**
34
- * List all available backups for a client
35
- */
36
- function listClientBackups(client: MCPClient): BackupInfo[] {
37
- const config = getClientConfig(client);
38
- return listBackups(config.configPath);
39
- }
40
-
41
- /**
42
- * List all backups across all clients
43
- */
44
- export function listAllBackups(): Map<MCPClient, BackupInfo[]> {
45
- const results = new Map<MCPClient, BackupInfo[]>();
46
-
47
- for (const client of getAllClients()) {
48
- const backups = listClientBackups(client);
49
- if (backups.length > 0) {
50
- results.set(client, backups);
51
- }
52
- }
53
-
54
- return results;
55
- }
56
-
57
- /**
58
- * Format backup list for display
59
- */
60
- export function formatBackupList(backups: Map<MCPClient, BackupInfo[]>): string {
61
- const lines: string[] = [];
62
-
63
- lines.push('');
64
- lines.push('šŸ“¦ Available Backups');
65
- lines.push('====================');
66
- lines.push('');
67
-
68
- if (backups.size === 0) {
69
- lines.push('No backups found.');
70
- lines.push('');
71
- lines.push('Backups are created automatically when you run setup.');
72
- lines.push('');
73
- return lines.join('\n');
74
- }
75
-
76
- for (const [client, clientBackups] of backups) {
77
- const config = getClientConfig(client);
78
- lines.push(`${config.displayName}:`);
79
-
80
- for (let i = 0; i < clientBackups.length; i++) {
81
- const backup = clientBackups[i];
82
- const marker = i === 0 ? ' (latest)' : '';
83
- lines.push(` ${i + 1}. ${formatBackupInfo(backup)}${marker}`);
84
- }
85
-
86
- lines.push('');
87
- }
88
-
89
- lines.push('Usage:');
90
- lines.push(' npx @nordsym/apiclaw restore # Restore latest for all');
91
- lines.push(' npx @nordsym/apiclaw restore --client claude # Restore latest for Claude');
92
- lines.push(' npx @nordsym/apiclaw restore --backup <path> # Restore specific backup');
93
- lines.push('');
94
-
95
- return lines.join('\n');
96
- }
97
-
98
- /**
99
- * Restore a specific client to its latest backup
100
- */
101
- export function restoreClient(client: MCPClient): RestoreResult {
102
- const config = getClientConfig(client);
103
- const configPath = config.configPath;
104
-
105
- // Check if config exists
106
- if (!existsSync(configPath)) {
107
- return {
108
- success: false,
109
- client: config.displayName,
110
- message: 'No config file to restore',
111
- };
112
- }
113
-
114
- // Get latest backup
115
- const latest = getLatestBackup(configPath);
116
-
117
- if (!latest) {
118
- return {
119
- success: false,
120
- client: config.displayName,
121
- message: 'No backups available',
122
- };
123
- }
124
-
125
- // Perform restore
126
- const result = doRestore(latest.path, configPath);
127
-
128
- if (result.success) {
129
- return {
130
- success: true,
131
- client: config.displayName,
132
- message: 'Restored successfully',
133
- backupUsed: latest.filename,
134
- preRestoreBackup: result.backupPath || undefined,
135
- };
136
- }
137
-
138
- return {
139
- success: false,
140
- client: config.displayName,
141
- message: result.error || 'Unknown error',
142
- };
143
- }
144
-
145
- /**
146
- * Restore from a specific backup file
147
- */
148
- export function restoreFromFile(backupPath: string, client?: MCPClient): RestoreResult {
149
- // Validate backup exists
150
- if (!existsSync(backupPath)) {
151
- return {
152
- success: false,
153
- client: client ? getClientConfig(client).displayName : 'Unknown',
154
- message: `Backup file not found: ${backupPath}`,
155
- };
156
- }
157
-
158
- // If client not specified, try to detect from backup path
159
- if (!client) {
160
- for (const c of getAllClients()) {
161
- const config = getClientConfig(c);
162
- if (backupPath.includes(config.configDir)) {
163
- client = c;
164
- break;
165
- }
166
- }
167
- }
168
-
169
- if (!client) {
170
- return {
171
- success: false,
172
- client: 'Unknown',
173
- message: 'Could not determine target client. Use --client to specify.',
174
- };
175
- }
176
-
177
- const config = getClientConfig(client);
178
- const result = doRestore(backupPath, config.configPath);
179
-
180
- if (result.success) {
181
- return {
182
- success: true,
183
- client: config.displayName,
184
- message: 'Restored successfully',
185
- backupUsed: backupPath,
186
- preRestoreBackup: result.backupPath || undefined,
187
- };
188
- }
189
-
190
- return {
191
- success: false,
192
- client: config.displayName,
193
- message: result.error || 'Unknown error',
194
- };
195
- }
196
-
197
- /**
198
- * Restore all clients to their latest backups
199
- */
200
- export function restoreAll(): RestoreResult[] {
201
- const results: RestoreResult[] = [];
202
-
203
- for (const client of getAllClients()) {
204
- const config = getClientConfig(client);
205
-
206
- // Skip clients without backups
207
- const backups = listClientBackups(client);
208
- if (backups.length === 0) {
209
- continue;
210
- }
211
-
212
- results.push(restoreClient(client));
213
- }
214
-
215
- return results;
216
- }
217
-
218
- /**
219
- * Format restore results for display
220
- */
221
- export function formatRestoreResults(results: RestoreResult[]): string {
222
- const lines: string[] = [];
223
-
224
- lines.push('');
225
- lines.push('šŸ”„ Restore Results');
226
- lines.push('==================');
227
- lines.push('');
228
-
229
- if (results.length === 0) {
230
- lines.push('No clients had backups to restore.');
231
- lines.push('');
232
- return lines.join('\n');
233
- }
234
-
235
- for (const result of results) {
236
- const icon = result.success ? 'āœ“' : 'āœ—';
237
- lines.push(`${icon} ${result.client}: ${result.message}`);
238
-
239
- if (result.backupUsed) {
240
- lines.push(` Restored from: ${result.backupUsed}`);
241
- }
242
-
243
- if (result.preRestoreBackup) {
244
- lines.push(` Pre-restore backup: ${result.preRestoreBackup}`);
245
- }
246
- }
247
-
248
- lines.push('');
249
-
250
- const successful = results.filter(r => r.success).length;
251
- if (successful > 0) {
252
- lines.push(`āœ“ Restored ${successful} client(s). Restart your MCP clients to apply changes.`);
253
- }
254
-
255
- lines.push('');
256
-
257
- return lines.join('\n');
258
- }
259
-
260
- /**
261
- * Restore command handler
262
- */
263
- export async function restoreCommand(options: RestoreOptions = {}): Promise<void> {
264
- // List mode
265
- if (options.list) {
266
- const backups = listAllBackups();
267
- console.log(formatBackupList(backups));
268
- return;
269
- }
270
-
271
- // Dry run mode
272
- if (options.dryRun) {
273
- console.log('\nšŸ” Dry run - would restore:\n');
274
-
275
- if (options.backup) {
276
- console.log(` From file: ${options.backup}`);
277
- } else if (options.client) {
278
- const client = parseClientArg(options.client);
279
- if (client) {
280
- const latest = getLatestBackup(getClientConfig(client).configPath);
281
- console.log(` ${getClientConfig(client).displayName}: ${latest?.filename || 'No backup'}`);
282
- }
283
- } else {
284
- const backups = listAllBackups();
285
- for (const [client, clientBackups] of backups) {
286
- console.log(` ${getClientConfig(client).displayName}: ${clientBackups[0]?.filename || 'No backup'}`);
287
- }
288
- }
289
-
290
- console.log('\nRun without --dry-run to perform restore.\n');
291
- return;
292
- }
293
-
294
- // Restore from specific file
295
- if (options.backup) {
296
- const client = options.client ? parseClientArg(options.client) : undefined;
297
- const result = restoreFromFile(options.backup, client || undefined);
298
- console.log(formatRestoreResults([result]));
299
-
300
- if (!result.success) {
301
- process.exit(1);
302
- }
303
- return;
304
- }
305
-
306
- // Restore specific client
307
- if (options.client) {
308
- const client = parseClientArg(options.client);
309
-
310
- if (!client) {
311
- console.error(`\nāœ— Unknown client: ${options.client}\n`);
312
- console.error('Valid clients: claude, cursor, windsurf, cline, continue\n');
313
- process.exit(1);
314
- }
315
-
316
- const result = restoreClient(client);
317
- console.log(formatRestoreResults([result]));
318
-
319
- if (!result.success) {
320
- process.exit(1);
321
- }
322
- return;
323
- }
324
-
325
- // Restore all clients with backups
326
- const results = restoreAll();
327
- console.log(formatRestoreResults(results));
328
-
329
- const failures = results.filter(r => !r.success);
330
- if (failures.length > 0) {
331
- process.exit(1);
332
- }
333
- }
@@ -1,297 +0,0 @@
1
- /**
2
- * Setup Command
3
- * Configures APIClaw for MCP clients
4
- */
5
-
6
- import { existsSync } from 'fs';
7
- import { detectOS, getOSDisplayName } from '../../utils/os.js';
8
- import { readSession } from '../../session.js';
9
- import { loginCommand } from './login.js';
10
- import {
11
- getAllClients,
12
- getConfigPath,
13
- getClientConfig,
14
- parseClientArg,
15
- MCPClient,
16
- ClientPathConfig
17
- } from '../../utils/paths.js';
18
- import {
19
- readConfig,
20
- writeConfig,
21
- mergeApiclawConfig,
22
- mergeApiclawContinueConfig,
23
- hasApiclawConfig,
24
- isContinueFormat,
25
- MCPConfig,
26
- ContinueConfig
27
- } from '../../utils/config.js';
28
- import { createBackup, getLatestBackup } from '../../utils/backup.js';
29
-
30
- export interface SetupOptions {
31
- client?: string;
32
- config?: string;
33
- workspace?: string;
34
- dryRun?: boolean;
35
- force?: boolean;
36
- wizard?: boolean;
37
- all?: boolean;
38
- verbose?: boolean;
39
- }
40
-
41
- interface SetupResult {
42
- client: string;
43
- success: boolean;
44
- message: string;
45
- backupPath?: string | null;
46
- skipped?: boolean;
47
- }
48
-
49
- /**
50
- * Detect which MCP clients are installed
51
- */
52
- function detectInstalledClients(): MCPClient[] {
53
- const clients = getAllClients();
54
- const installed: MCPClient[] = [];
55
-
56
- for (const client of clients) {
57
- const configPath = getConfigPath(client);
58
- // Check if config exists OR if parent directory exists (client might be installed but not configured)
59
- if (existsSync(configPath)) {
60
- installed.push(client);
61
- }
62
- }
63
-
64
- return installed;
65
- }
66
-
67
- /**
68
- * Check if a client's config directory structure exists (might not have config yet)
69
- */
70
- function clientMightBeInstalled(client: MCPClient): boolean {
71
- const config = getClientConfig(client);
72
- const configDir = config.configDir;
73
-
74
- // Check a few levels up to see if the app is installed
75
- const pathParts = configDir.split('/').filter(Boolean);
76
- for (let i = pathParts.length; i >= Math.max(0, pathParts.length - 3); i--) {
77
- const checkPath = '/' + pathParts.slice(0, i).join('/');
78
- if (existsSync(checkPath)) {
79
- return true;
80
- }
81
- }
82
-
83
- return false;
84
- }
85
-
86
- /**
87
- * Setup a single client
88
- */
89
- async function setupClient(
90
- client: MCPClient | 'custom',
91
- configPath: string,
92
- options: SetupOptions
93
- ): Promise<SetupResult> {
94
- const displayName = client === 'custom' ? 'Custom' : getClientConfig(client as MCPClient).displayName;
95
-
96
- if (options.verbose) {
97
- console.log(`\nšŸ“ Configuring ${displayName}...`);
98
- console.log(` Config path: ${configPath}`);
99
- }
100
-
101
- // Read existing config
102
- const readResult = readConfig(configPath);
103
-
104
- if (!readResult.success) {
105
- return {
106
- client: displayName,
107
- success: false,
108
- message: readResult.error || 'Failed to read config',
109
- };
110
- }
111
-
112
- const existingConfig = readResult.config!;
113
-
114
- // Check if APIClaw is already configured
115
- if (hasApiclawConfig(existingConfig) && !options.force) {
116
- if (options.verbose) {
117
- console.log(` ā­ļø APIClaw already configured (use --force to update)`);
118
- }
119
- return {
120
- client: displayName,
121
- success: true,
122
- message: 'Already configured',
123
- skipped: true,
124
- };
125
- }
126
-
127
- // Merge APIClaw config
128
- let newConfig: MCPConfig | ContinueConfig;
129
-
130
- if (client === 'continue' || isContinueFormat(existingConfig)) {
131
- newConfig = mergeApiclawContinueConfig(existingConfig as ContinueConfig, {
132
- workspace: options.workspace,
133
- force: options.force,
134
- });
135
- } else {
136
- newConfig = mergeApiclawConfig(existingConfig as MCPConfig, {
137
- workspace: options.workspace,
138
- force: options.force,
139
- });
140
- }
141
-
142
- // Dry run - show what would happen
143
- if (options.dryRun) {
144
- console.log(`\nšŸ“‹ Would configure ${displayName}:`);
145
- console.log(` Path: ${configPath}`);
146
- console.log(` Changes:`);
147
- if (isContinueFormat(newConfig)) {
148
- const continueConfig = newConfig as ContinueConfig;
149
- const apiclaw = continueConfig.mcpServers?.find(s => s.name === 'apiclaw');
150
- console.log(JSON.stringify(apiclaw, null, 4).split('\n').map(l => ` ${l}`).join('\n'));
151
- } else {
152
- const mcpConfig = newConfig as MCPConfig;
153
- console.log(JSON.stringify({ apiclaw: mcpConfig.mcpServers?.apiclaw }, null, 4).split('\n').map(l => ` ${l}`).join('\n'));
154
- }
155
-
156
- return {
157
- client: displayName,
158
- success: true,
159
- message: 'Dry run - no changes made',
160
- skipped: true,
161
- };
162
- }
163
-
164
- // Write config
165
- const writeResult = writeConfig(configPath, newConfig, true);
166
-
167
- if (!writeResult.success) {
168
- return {
169
- client: displayName,
170
- success: false,
171
- message: writeResult.error || 'Failed to write config',
172
- };
173
- }
174
-
175
- return {
176
- client: displayName,
177
- success: true,
178
- message: readResult.isNew ? 'Created new config' : 'Updated existing config',
179
- backupPath: writeResult.backupPath,
180
- };
181
- }
182
-
183
- /**
184
- * Main setup command handler
185
- */
186
- export async function setupCommand(options: SetupOptions): Promise<void> {
187
- const os = detectOS();
188
- const osName = getOSDisplayName();
189
-
190
- console.log('\nšŸš€ APIClaw MCP Auto-Setup\n');
191
- console.log(`Platform: ${osName}\n`);
192
-
193
- // Step 0: Ensure user is signed in
194
- if (!options.workspace) {
195
- const session = readSession();
196
- if (!session) {
197
- console.log('First, sign in to link your workspace:\n');
198
- const loginResult = await loginCommand({});
199
- if (!loginResult) {
200
- console.error('\nāŒ Login failed. Setup cancelled.');
201
- process.exit(1);
202
- }
203
- // Use the session token as workspace identifier
204
- options.workspace = loginResult.workspaceId;
205
- console.log('');
206
- } else {
207
- console.log(`āœ“ Signed in as ${session.email}\n`);
208
- options.workspace = options.workspace || session.workspaceId;
209
- }
210
- }
211
-
212
- // Determine which clients to configure
213
- let clientsToSetup: Array<{ client: MCPClient | 'custom'; path: string }> = [];
214
-
215
- if (options.config) {
216
- // Custom config path
217
- clientsToSetup.push({ client: 'custom', path: options.config });
218
- } else if (options.client) {
219
- // Specific client
220
- const client = parseClientArg(options.client);
221
-
222
- if (!client) {
223
- console.error(`āŒ Unknown client: ${options.client}`);
224
- console.log(' Supported clients: claude-desktop, cursor, windsurf, cline, continue');
225
- process.exit(1);
226
- }
227
-
228
- clientsToSetup.push({ client, path: getConfigPath(client) });
229
- } else {
230
- // Auto-detect or all
231
- console.log('šŸ” Detecting MCP clients...\n');
232
-
233
- const allClients = getAllClients();
234
- const detected = detectInstalledClients();
235
-
236
- for (const client of allClients) {
237
- const config = getClientConfig(client);
238
- const isDetected = detected.includes(client);
239
- const icon = isDetected ? 'āœ“' : 'āœ—';
240
- const status = isDetected ? 'found' : 'not found';
241
- console.log(` ${icon} ${config.displayName} ${status}`);
242
-
243
- if (isDetected || options.all) {
244
- clientsToSetup.push({ client, path: config.configPath });
245
- }
246
- }
247
-
248
- console.log('');
249
-
250
- if (clientsToSetup.length === 0) {
251
- console.log('āš ļø No MCP clients detected. Use --client to specify manually.');
252
- console.log(' Example: npx @nordsym/apiclaw setup --client claude-desktop');
253
- process.exit(0);
254
- }
255
- }
256
-
257
- // Setup each client
258
- const results: SetupResult[] = [];
259
-
260
- for (const { client, path } of clientsToSetup) {
261
- const result = await setupClient(client, path, options);
262
- results.push(result);
263
-
264
- const icon = result.success ? (result.skipped ? 'ā­ļø' : 'āœ“') : 'āœ—';
265
- console.log(`${icon} ${result.client}: ${result.message}`);
266
-
267
- if (result.backupPath && options.verbose) {
268
- console.log(` Backup: ${result.backupPath}`);
269
- }
270
- }
271
-
272
- // Summary
273
- const succeeded = results.filter(r => r.success && !r.skipped).length;
274
- const skipped = results.filter(r => r.skipped).length;
275
- const failed = results.filter(r => !r.success).length;
276
-
277
- console.log('\n' + '═'.repeat(50));
278
-
279
- if (failed === 0) {
280
- if (options.dryRun) {
281
- console.log('\nāœ… Dry run complete! Use without --dry-run to apply changes.\n');
282
- } else if (succeeded > 0) {
283
- console.log('\nāœ… APIClaw configured successfully!\n');
284
- console.log('Next steps:');
285
- console.log(' 1. Restart your AI coding assistant');
286
- console.log(' 2. Ask your agent: "List available APIs"\n');
287
- console.log('Need help? https://apiclaw.cloud/docs/setup\n');
288
- } else if (skipped === results.length) {
289
- console.log('\nāœ… APIClaw already configured in all clients.\n');
290
- console.log('Use --force to reconfigure.\n');
291
- }
292
- } else {
293
- console.log(`\nāš ļø Setup completed with ${failed} error(s).\n`);
294
- console.log('For troubleshooting, visit: https://apiclaw.cloud/docs/setup/troubleshooting\n');
295
- process.exit(1);
296
- }
297
- }