@solidnumber/cli 1.0.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +24 -0
  2. package/dist/commands/agent.d.ts +9 -0
  3. package/dist/commands/agent.d.ts.map +1 -0
  4. package/dist/commands/agent.js +540 -0
  5. package/dist/commands/agent.js.map +1 -0
  6. package/dist/commands/ant.d.ts +8 -0
  7. package/dist/commands/ant.d.ts.map +1 -0
  8. package/dist/commands/ant.js +277 -0
  9. package/dist/commands/ant.js.map +1 -0
  10. package/dist/commands/auth.js +209 -25
  11. package/dist/commands/auth.js.map +1 -1
  12. package/dist/commands/blog.d.ts +8 -0
  13. package/dist/commands/blog.d.ts.map +1 -0
  14. package/dist/commands/blog.js +393 -0
  15. package/dist/commands/blog.js.map +1 -0
  16. package/dist/commands/brand.d.ts +8 -0
  17. package/dist/commands/brand.d.ts.map +1 -0
  18. package/dist/commands/brand.js +292 -0
  19. package/dist/commands/brand.js.map +1 -0
  20. package/dist/commands/clone.d.ts.map +1 -1
  21. package/dist/commands/clone.js.map +1 -1
  22. package/dist/commands/company.d.ts +11 -0
  23. package/dist/commands/company.d.ts.map +1 -0
  24. package/dist/commands/company.js +300 -0
  25. package/dist/commands/company.js.map +1 -0
  26. package/dist/commands/connect.d.ts +8 -0
  27. package/dist/commands/connect.d.ts.map +1 -0
  28. package/dist/commands/connect.js +632 -0
  29. package/dist/commands/connect.js.map +1 -0
  30. package/dist/commands/crm.d.ts +8 -0
  31. package/dist/commands/crm.d.ts.map +1 -0
  32. package/dist/commands/crm.js +493 -0
  33. package/dist/commands/crm.js.map +1 -0
  34. package/dist/commands/dev.d.ts.map +1 -1
  35. package/dist/commands/dev.js +11 -94
  36. package/dist/commands/dev.js.map +1 -1
  37. package/dist/commands/docs.d.ts.map +1 -1
  38. package/dist/commands/docs.js +48 -12
  39. package/dist/commands/docs.js.map +1 -1
  40. package/dist/commands/droplet.d.ts.map +1 -1
  41. package/dist/commands/droplet.js +21 -2
  42. package/dist/commands/droplet.js.map +1 -1
  43. package/dist/commands/explore.d.ts +23 -0
  44. package/dist/commands/explore.d.ts.map +1 -0
  45. package/dist/commands/explore.js +272 -0
  46. package/dist/commands/explore.js.map +1 -0
  47. package/dist/commands/flows.d.ts +8 -0
  48. package/dist/commands/flows.d.ts.map +1 -0
  49. package/dist/commands/flows.js +301 -0
  50. package/dist/commands/flows.js.map +1 -0
  51. package/dist/commands/inbox.d.ts +14 -0
  52. package/dist/commands/inbox.d.ts.map +1 -0
  53. package/dist/commands/inbox.js +397 -0
  54. package/dist/commands/inbox.js.map +1 -0
  55. package/dist/commands/inventory.d.ts +8 -0
  56. package/dist/commands/inventory.d.ts.map +1 -0
  57. package/dist/commands/inventory.js +263 -0
  58. package/dist/commands/inventory.js.map +1 -0
  59. package/dist/commands/pull.js +1 -1
  60. package/dist/commands/pull.js.map +1 -1
  61. package/dist/commands/reports.d.ts +8 -0
  62. package/dist/commands/reports.d.ts.map +1 -0
  63. package/dist/commands/reports.js +264 -0
  64. package/dist/commands/reports.js.map +1 -0
  65. package/dist/commands/schedule.d.ts +4 -0
  66. package/dist/commands/schedule.d.ts.map +1 -0
  67. package/dist/commands/schedule.js +249 -0
  68. package/dist/commands/schedule.js.map +1 -0
  69. package/dist/commands/services.js +4 -1
  70. package/dist/commands/services.js.map +1 -1
  71. package/dist/commands/switch.d.ts +10 -0
  72. package/dist/commands/switch.d.ts.map +1 -0
  73. package/dist/commands/switch.js +111 -0
  74. package/dist/commands/switch.js.map +1 -0
  75. package/dist/commands/train.js +3 -3
  76. package/dist/commands/train.js.map +1 -1
  77. package/dist/commands/voice.d.ts +9 -0
  78. package/dist/commands/voice.d.ts.map +1 -0
  79. package/dist/commands/voice.js +444 -0
  80. package/dist/commands/voice.js.map +1 -0
  81. package/dist/commands/widgets.d.ts +8 -0
  82. package/dist/commands/widgets.d.ts.map +1 -0
  83. package/dist/commands/widgets.js +205 -0
  84. package/dist/commands/widgets.js.map +1 -0
  85. package/dist/index.js +65 -11
  86. package/dist/index.js.map +1 -1
  87. package/dist/lib/api-client.d.ts +218 -0
  88. package/dist/lib/api-client.d.ts.map +1 -1
  89. package/dist/lib/api-client.js +133 -12
  90. package/dist/lib/api-client.js.map +1 -1
  91. package/dist/lib/config.d.ts +8 -0
  92. package/dist/lib/config.d.ts.map +1 -1
  93. package/dist/lib/config.js +15 -1
  94. package/dist/lib/config.js.map +1 -1
  95. package/package.json +6 -1
  96. package/platform-docs/ai.txt +324 -0
  97. package/platform-docs/llms.txt +191 -0
@@ -0,0 +1,632 @@
1
+ "use strict";
2
+ /**
3
+ * Connect command — Import external data sources into Solid#
4
+ *
5
+ * Figma, Slack, Notion, WordPress, CSV, GitHub, Google Sheets, Google Docs
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.connectCommand = void 0;
45
+ const commander_1 = require("commander");
46
+ const ora_1 = __importDefault(require("ora"));
47
+ const chalk_1 = __importDefault(require("chalk"));
48
+ const config_1 = require("../lib/config");
49
+ const api_client_1 = require("../lib/api-client");
50
+ exports.connectCommand = new commander_1.Command('connect')
51
+ .alias('conn')
52
+ .description('Import external data into your Solid# business');
53
+ // Ensure logged in
54
+ function requireAuth() {
55
+ if (!config_1.config.isLoggedIn()) {
56
+ console.error(chalk_1.default.red('Not logged in. Run `solid auth login` first.'));
57
+ process.exit(1);
58
+ }
59
+ }
60
+ // ── Helpers ───────────────────────────────────────────────────────────
61
+ function formatDate(dateStr) {
62
+ return new Date(dateStr).toLocaleString();
63
+ }
64
+ function statusColor(status) {
65
+ switch (status) {
66
+ case 'completed': return chalk_1.default.green;
67
+ case 'running':
68
+ case 'in_progress': return chalk_1.default.cyan;
69
+ case 'queued':
70
+ case 'pending': return chalk_1.default.yellow;
71
+ case 'failed': return chalk_1.default.red;
72
+ case 'cancelled': return chalk_1.default.dim;
73
+ default: return chalk_1.default.white;
74
+ }
75
+ }
76
+ function statusIcon(status) {
77
+ switch (status) {
78
+ case 'completed': return chalk_1.default.green('✓');
79
+ case 'running':
80
+ case 'in_progress': return chalk_1.default.cyan('⟳');
81
+ case 'queued':
82
+ case 'pending': return chalk_1.default.yellow('○');
83
+ case 'failed': return chalk_1.default.red('✗');
84
+ case 'cancelled': return chalk_1.default.dim('—');
85
+ default: return chalk_1.default.dim('?');
86
+ }
87
+ }
88
+ function providerIcon(provider) {
89
+ const icons = {
90
+ figma: '◆',
91
+ slack: '#',
92
+ notion: '▪',
93
+ wordpress: 'W',
94
+ csv: '▤',
95
+ github: '⬡',
96
+ sheets: '▦',
97
+ docs: '▧',
98
+ };
99
+ return icons[provider] || '●';
100
+ }
101
+ function printImportSummary(data) {
102
+ console.log('');
103
+ console.log(chalk_1.default.bold(' Import Summary'));
104
+ console.log(chalk_1.default.dim(' ' + '─'.repeat(50)));
105
+ console.log(chalk_1.default.dim(' Import ID: ') + data.import_id);
106
+ console.log(chalk_1.default.dim(' Provider: ') + data.provider);
107
+ console.log(chalk_1.default.dim(' Status: ') + statusColor(data.status)(data.status));
108
+ if (data.items_imported !== undefined) {
109
+ console.log(chalk_1.default.dim(' Imported: ') + chalk_1.default.green(data.items_imported.toString()));
110
+ }
111
+ if (data.items_skipped !== undefined && data.items_skipped > 0) {
112
+ console.log(chalk_1.default.dim(' Skipped: ') + chalk_1.default.yellow(data.items_skipped.toString()));
113
+ }
114
+ if (data.items_failed !== undefined && data.items_failed > 0) {
115
+ console.log(chalk_1.default.dim(' Failed: ') + chalk_1.default.red(data.items_failed.toString()));
116
+ }
117
+ if (data.created_at) {
118
+ console.log(chalk_1.default.dim(' Started: ') + formatDate(data.created_at));
119
+ }
120
+ if (data.completed_at) {
121
+ console.log(chalk_1.default.dim(' Completed: ') + formatDate(data.completed_at));
122
+ }
123
+ if (data.details) {
124
+ console.log('');
125
+ console.log(chalk_1.default.dim(' Details:'));
126
+ for (const [key, value] of Object.entries(data.details)) {
127
+ const label = key.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
128
+ console.log(chalk_1.default.dim(` ${label}: `) + String(value));
129
+ }
130
+ }
131
+ }
132
+ // ── Figma ─────────────────────────────────────────────────────────────
133
+ exports.connectCommand
134
+ .command('figma <url>')
135
+ .description('Import Figma design → CMS pages + brand tokens')
136
+ .option('--pages-only', 'Import page layouts only (skip brand tokens)')
137
+ .option('--brand-only', 'Extract brand tokens only (skip page layouts)')
138
+ .option('--preview', 'Dry run — show what would be imported without making changes')
139
+ .action(async (url, options) => {
140
+ requireAuth();
141
+ let token = process.env.FIGMA_PAT;
142
+ if (!token) {
143
+ const answers = await (await Promise.resolve().then(() => __importStar(require('inquirer')))).default.prompt([{
144
+ type: 'password',
145
+ name: 'token',
146
+ message: 'Figma Personal Access Token:',
147
+ mask: '*',
148
+ validate: (input) => input.length > 0 || 'Token is required',
149
+ }]);
150
+ token = answers.token;
151
+ }
152
+ if (!token) {
153
+ console.error(chalk_1.default.red('Figma token required. Set FIGMA_PAT env var or enter when prompted.'));
154
+ console.error(chalk_1.default.dim(' Get your token at: https://www.figma.com/developers/api#access-tokens'));
155
+ process.exit(1);
156
+ }
157
+ const mode = options.pagesOnly ? 'pages' : options.brandOnly ? 'brand' : 'all';
158
+ const label = options.preview ? 'Analyzing Figma design...' : `Importing Figma design (${mode})...`;
159
+ const spinner = (0, ora_1.default)(label).start();
160
+ try {
161
+ const response = await api_client_1.apiClient.post('/api/v1/connections/figma/import', {
162
+ url,
163
+ token,
164
+ mode,
165
+ preview: options.preview || false,
166
+ });
167
+ if (options.preview) {
168
+ spinner.succeed('Figma design analyzed (dry run)');
169
+ const preview = response.data.preview;
170
+ if (preview) {
171
+ console.log('');
172
+ if (preview.pages && preview.pages.length > 0) {
173
+ console.log(chalk_1.default.bold(' Pages found:'));
174
+ for (const page of preview.pages) {
175
+ console.log(` ${chalk_1.default.cyan(providerIcon('figma'))} ${page.name} ${chalk_1.default.dim(`(${page.type}, ${page.components} components)`)}`);
176
+ }
177
+ }
178
+ if (preview.brand_tokens) {
179
+ console.log('');
180
+ console.log(chalk_1.default.bold(' Brand tokens:'));
181
+ console.log(chalk_1.default.dim(` Colors: ${preview.brand_tokens.colors}`));
182
+ console.log(chalk_1.default.dim(` Typography: ${preview.brand_tokens.typography}`));
183
+ console.log(chalk_1.default.dim(` Spacing: ${preview.brand_tokens.spacing}`));
184
+ }
185
+ console.log('');
186
+ console.log(chalk_1.default.dim(' Run without --preview to import.'));
187
+ }
188
+ }
189
+ else {
190
+ spinner.succeed(chalk_1.default.green('Figma import complete'));
191
+ printImportSummary(response.data);
192
+ }
193
+ }
194
+ catch (error) {
195
+ spinner.fail(chalk_1.default.red('Figma import failed'));
196
+ const apiError = (0, api_client_1.handleApiError)(error);
197
+ console.error(chalk_1.default.red(` ${apiError.message}`));
198
+ }
199
+ });
200
+ // ── Slack ─────────────────────────────────────────────────────────────
201
+ exports.connectCommand
202
+ .command('slack <channel>')
203
+ .description('Import Slack channel messages → KB articles')
204
+ .option('--faq', 'Extract FAQ-style question/answer pairs')
205
+ .option('--train', 'Import as AI training data')
206
+ .option('--all', 'Import all messages (not just highlighted/pinned)')
207
+ .option('--since <date>', 'Import messages since date (YYYY-MM-DD)')
208
+ .option('--until <date>', 'Import messages until date (YYYY-MM-DD)')
209
+ .option('--anonymize', 'Strip usernames and personal info from imported content')
210
+ .action(async (channel, options) => {
211
+ requireAuth();
212
+ const importMode = options.faq ? 'faq' : options.train ? 'training' : 'kb';
213
+ const spinner = (0, ora_1.default)(`Importing Slack channel #${channel} as ${importMode}...`).start();
214
+ try {
215
+ const response = await api_client_1.apiClient.post('/api/v1/connections/slack/import', {
216
+ channel,
217
+ mode: importMode,
218
+ include_all: options.all || false,
219
+ since: options.since,
220
+ until: options.until,
221
+ anonymize: options.anonymize || false,
222
+ });
223
+ spinner.succeed(chalk_1.default.green(`Slack #${channel} import complete`));
224
+ printImportSummary(response.data);
225
+ if (importMode === 'faq') {
226
+ console.log('');
227
+ console.log(chalk_1.default.dim(' FAQ pairs are available in your KB. Run `solid kb list` to view.'));
228
+ }
229
+ else if (importMode === 'training') {
230
+ console.log('');
231
+ console.log(chalk_1.default.dim(' Training data queued. Run `solid train status` to check progress.'));
232
+ }
233
+ }
234
+ catch (error) {
235
+ spinner.fail(chalk_1.default.red('Slack import failed'));
236
+ const apiError = (0, api_client_1.handleApiError)(error);
237
+ console.error(chalk_1.default.red(` ${apiError.message}`));
238
+ }
239
+ });
240
+ // ── Notion ────────────────────────────────────────────────────────────
241
+ exports.connectCommand
242
+ .command('notion <url>')
243
+ .description('Import Notion page or database → KB or entity data')
244
+ .option('--as <entity>', 'Import as entity type: kb, contacts, services, inventory', 'kb')
245
+ .action(async (url, options) => {
246
+ requireAuth();
247
+ const entity = options.as;
248
+ const validEntities = ['kb', 'contacts', 'services', 'inventory'];
249
+ if (!validEntities.includes(entity)) {
250
+ console.error(chalk_1.default.red(`Invalid entity type: ${entity}`));
251
+ console.error(chalk_1.default.dim(` Valid types: ${validEntities.join(', ')}`));
252
+ process.exit(1);
253
+ }
254
+ const spinner = (0, ora_1.default)(`Importing Notion content as ${entity}...`).start();
255
+ try {
256
+ const response = await api_client_1.apiClient.post('/api/v1/connections/notion/import', {
257
+ url,
258
+ entity_type: entity,
259
+ });
260
+ spinner.succeed(chalk_1.default.green('Notion import complete'));
261
+ printImportSummary(response.data);
262
+ if (entity === 'kb') {
263
+ console.log('');
264
+ console.log(chalk_1.default.dim(' KB articles created. Run `solid kb list` to view.'));
265
+ }
266
+ else {
267
+ console.log('');
268
+ console.log(chalk_1.default.dim(` ${entity} records created. Run \`solid ${entity === 'contacts' ? 'crm contacts' : entity} list\` to view.`));
269
+ }
270
+ }
271
+ catch (error) {
272
+ spinner.fail(chalk_1.default.red('Notion import failed'));
273
+ const apiError = (0, api_client_1.handleApiError)(error);
274
+ console.error(chalk_1.default.red(` ${apiError.message}`));
275
+ }
276
+ });
277
+ // ── WordPress ─────────────────────────────────────────────────────────
278
+ exports.connectCommand
279
+ .command('wordpress <url>')
280
+ .description('Import WordPress site → CMS pages')
281
+ .option('--pages-only', 'Import pages only (skip blog posts)')
282
+ .option('--blog-only', 'Import blog posts only (skip pages)')
283
+ .option('--media', 'Also import media/images')
284
+ .action(async (url, options) => {
285
+ requireAuth();
286
+ const mode = options.pagesOnly ? 'pages' : options.blogOnly ? 'blog' : 'all';
287
+ const spinner = (0, ora_1.default)(`Importing WordPress site (${mode})...`).start();
288
+ try {
289
+ const response = await api_client_1.apiClient.post('/api/v1/connections/wordpress/import', {
290
+ url,
291
+ mode,
292
+ include_media: options.media || false,
293
+ });
294
+ spinner.succeed(chalk_1.default.green('WordPress import complete'));
295
+ printImportSummary(response.data);
296
+ console.log('');
297
+ if (mode === 'blog' || mode === 'all') {
298
+ console.log(chalk_1.default.dim(' Blog posts created. Run `solid blog list` to view.'));
299
+ }
300
+ if (mode === 'pages' || mode === 'all') {
301
+ console.log(chalk_1.default.dim(' CMS pages created. Run `solid pages list` to view.'));
302
+ }
303
+ }
304
+ catch (error) {
305
+ spinner.fail(chalk_1.default.red('WordPress import failed'));
306
+ const apiError = (0, api_client_1.handleApiError)(error);
307
+ console.error(chalk_1.default.red(` ${apiError.message}`));
308
+ }
309
+ });
310
+ // ── CSV ───────────────────────────────────────────────────────────────
311
+ exports.connectCommand
312
+ .command('csv <file>')
313
+ .description('Import CSV/Excel file → entity data')
314
+ .option('--entity <type>', 'Entity type: contacts, services, inventory, products', 'contacts')
315
+ .option('--preview', 'Preview column mapping without importing')
316
+ .action(async (file, options) => {
317
+ requireAuth();
318
+ const entity = options.entity;
319
+ const validEntities = ['contacts', 'services', 'inventory', 'products'];
320
+ if (!validEntities.includes(entity)) {
321
+ console.error(chalk_1.default.red(`Invalid entity type: ${entity}`));
322
+ console.error(chalk_1.default.dim(` Valid types: ${validEntities.join(', ')}`));
323
+ process.exit(1);
324
+ }
325
+ const label = options.preview ? 'Analyzing CSV structure...' : `Importing CSV as ${entity}...`;
326
+ const spinner = (0, ora_1.default)(label).start();
327
+ try {
328
+ const response = await api_client_1.apiClient.post('/api/v1/connections/csv/import', {
329
+ file_path: file,
330
+ entity_type: entity,
331
+ preview: options.preview || false,
332
+ });
333
+ if (options.preview) {
334
+ spinner.succeed('CSV structure analyzed (dry run)');
335
+ const preview = response.data.preview;
336
+ if (preview) {
337
+ console.log('');
338
+ console.log(chalk_1.default.bold(' Column Mapping:'));
339
+ console.log('');
340
+ console.log(chalk_1.default.bold(' SOURCE'.padEnd(24)) +
341
+ chalk_1.default.bold('MAPPED TO'.padEnd(24)) +
342
+ chalk_1.default.bold('SAMPLE'));
343
+ console.log(chalk_1.default.dim(' ' + '─'.repeat(65)));
344
+ for (const col of preview.columns) {
345
+ const mapped = col.mapped_to === 'unmapped' ? chalk_1.default.yellow('unmapped') : chalk_1.default.green(col.mapped_to);
346
+ const sample = col.sample_values.slice(0, 2).join(', ');
347
+ console.log(` ${col.source.padEnd(24)}` +
348
+ `${mapped}`.padEnd(24 + (col.mapped_to === 'unmapped' ? 10 : 0)) +
349
+ chalk_1.default.dim(sample.slice(0, 30)));
350
+ }
351
+ console.log('');
352
+ console.log(chalk_1.default.dim(` Total rows: ${preview.total_rows} | Valid: ${chalk_1.default.green(String(preview.valid_rows))} | Invalid: ${preview.invalid_rows > 0 ? chalk_1.default.red(String(preview.invalid_rows)) : chalk_1.default.dim('0')}`));
353
+ console.log('');
354
+ console.log(chalk_1.default.dim(' Run without --preview to import.'));
355
+ }
356
+ }
357
+ else {
358
+ spinner.succeed(chalk_1.default.green('CSV import complete'));
359
+ printImportSummary(response.data);
360
+ }
361
+ }
362
+ catch (error) {
363
+ spinner.fail(chalk_1.default.red('CSV import failed'));
364
+ const apiError = (0, api_client_1.handleApiError)(error);
365
+ console.error(chalk_1.default.red(` ${apiError.message}`));
366
+ }
367
+ });
368
+ // ── GitHub ────────────────────────────────────────────────────────────
369
+ exports.connectCommand
370
+ .command('github <url>')
371
+ .description('Import GitHub repo documentation → developer KB')
372
+ .option('--docs-only', 'Import only /docs directory')
373
+ .option('--readme', 'Import README.md only')
374
+ .action(async (url, options) => {
375
+ requireAuth();
376
+ const mode = options.docsOnly ? 'docs' : options.readme ? 'readme' : 'all';
377
+ const spinner = (0, ora_1.default)(`Importing GitHub repo documentation (${mode})...`).start();
378
+ try {
379
+ const response = await api_client_1.apiClient.post('/api/v1/connections/github/import', {
380
+ url,
381
+ mode,
382
+ });
383
+ spinner.succeed(chalk_1.default.green('GitHub import complete'));
384
+ printImportSummary(response.data);
385
+ console.log('');
386
+ console.log(chalk_1.default.dim(' Documentation added to KB. Run `solid kb list` to view.'));
387
+ }
388
+ catch (error) {
389
+ spinner.fail(chalk_1.default.red('GitHub import failed'));
390
+ const apiError = (0, api_client_1.handleApiError)(error);
391
+ console.error(chalk_1.default.red(` ${apiError.message}`));
392
+ }
393
+ });
394
+ // ── Google Sheets ─────────────────────────────────────────────────────
395
+ exports.connectCommand
396
+ .command('sheets <id>')
397
+ .description('Transform Google Sheet → entity data (uses existing Google OAuth)')
398
+ .option('--as <entity>', 'Import as entity type: contacts, services, inventory, products', 'contacts')
399
+ .action(async (id, options) => {
400
+ requireAuth();
401
+ const entity = options.as;
402
+ const validEntities = ['contacts', 'services', 'inventory', 'products'];
403
+ if (!validEntities.includes(entity)) {
404
+ console.error(chalk_1.default.red(`Invalid entity type: ${entity}`));
405
+ console.error(chalk_1.default.dim(` Valid types: ${validEntities.join(', ')}`));
406
+ process.exit(1);
407
+ }
408
+ const spinner = (0, ora_1.default)(`Importing Google Sheet as ${entity}...`).start();
409
+ try {
410
+ const response = await api_client_1.apiClient.post('/api/v1/connections/sheets/import', {
411
+ sheet_id: id,
412
+ entity_type: entity,
413
+ });
414
+ spinner.succeed(chalk_1.default.green('Google Sheets import complete'));
415
+ printImportSummary(response.data);
416
+ console.log('');
417
+ console.log(chalk_1.default.dim(` ${entity} records created. Run \`solid ${entity === 'contacts' ? 'crm contacts' : entity} list\` to view.`));
418
+ }
419
+ catch (error) {
420
+ spinner.fail(chalk_1.default.red('Google Sheets import failed'));
421
+ const apiError = (0, api_client_1.handleApiError)(error);
422
+ console.error(chalk_1.default.red(` ${apiError.message}`));
423
+ if (apiError.status === 403) {
424
+ console.error('');
425
+ console.error(chalk_1.default.dim(' Google OAuth may not be connected. Check your Google integration in the dashboard.'));
426
+ }
427
+ }
428
+ });
429
+ // ── Google Docs ───────────────────────────────────────────────────────
430
+ exports.connectCommand
431
+ .command('docs <id>')
432
+ .description('Transform Google Doc → KB article (uses existing Google OAuth)')
433
+ .action(async (id) => {
434
+ requireAuth();
435
+ const spinner = (0, ora_1.default)('Importing Google Doc as KB article...').start();
436
+ try {
437
+ const response = await api_client_1.apiClient.post('/api/v1/connections/docs/import', {
438
+ doc_id: id,
439
+ });
440
+ spinner.succeed(chalk_1.default.green('Google Doc import complete'));
441
+ printImportSummary(response.data);
442
+ console.log('');
443
+ console.log(chalk_1.default.dim(' KB article created. Run `solid kb list` to view.'));
444
+ }
445
+ catch (error) {
446
+ spinner.fail(chalk_1.default.red('Google Doc import failed'));
447
+ const apiError = (0, api_client_1.handleApiError)(error);
448
+ console.error(chalk_1.default.red(` ${apiError.message}`));
449
+ if (apiError.status === 403) {
450
+ console.error('');
451
+ console.error(chalk_1.default.dim(' Google OAuth may not be connected. Check your Google integration in the dashboard.'));
452
+ }
453
+ }
454
+ });
455
+ // ── List ──────────────────────────────────────────────────────────────
456
+ exports.connectCommand
457
+ .command('list')
458
+ .alias('ls')
459
+ .description('Show active connections + recent import history')
460
+ .action(async () => {
461
+ requireAuth();
462
+ const spinner = (0, ora_1.default)('Fetching connections...').start();
463
+ try {
464
+ const response = await api_client_1.apiClient.get('/api/v1/connections/history', { params: { limit: 10 } });
465
+ spinner.succeed('Connections loaded');
466
+ console.log('');
467
+ // Active connections
468
+ const connections = response.data.connections;
469
+ if (connections && connections.length > 0) {
470
+ console.log(chalk_1.default.bold(' Active Connections'));
471
+ console.log(chalk_1.default.dim(' ' + '─'.repeat(60)));
472
+ for (const conn of connections) {
473
+ const icon = conn.status === 'active' ? chalk_1.default.green('●') : chalk_1.default.dim('○');
474
+ const lastImport = conn.last_import_at ? formatDate(conn.last_import_at) : 'never';
475
+ console.log(` ${icon} ${chalk_1.default.cyan(providerIcon(conn.provider))} ${conn.provider.padEnd(14)}` +
476
+ chalk_1.default.dim(`${conn.total_imports} imports | last: ${lastImport}`));
477
+ }
478
+ }
479
+ else {
480
+ console.log(chalk_1.default.dim(' No active connections.'));
481
+ console.log(chalk_1.default.dim(' Connect a source: solid connect figma|slack|notion|wordpress|csv|github|sheets|docs'));
482
+ }
483
+ // Recent imports
484
+ const imports = response.data.recent_imports;
485
+ if (imports && imports.length > 0) {
486
+ console.log('');
487
+ console.log(chalk_1.default.bold(' Recent Imports'));
488
+ console.log(chalk_1.default.dim(' ' + '─'.repeat(60)));
489
+ console.log(chalk_1.default.bold(' ').padEnd(4) +
490
+ chalk_1.default.bold('ID'.padEnd(14)) +
491
+ chalk_1.default.bold('PROVIDER'.padEnd(14)) +
492
+ chalk_1.default.bold('ITEMS'.padEnd(10)) +
493
+ chalk_1.default.bold('STATUS'.padEnd(14)) +
494
+ chalk_1.default.bold('DATE'));
495
+ for (const imp of imports) {
496
+ console.log(` ${statusIcon(imp.status)} ` +
497
+ `${imp.import_id.slice(0, 12).padEnd(14)}` +
498
+ `${imp.provider.padEnd(14)}` +
499
+ `${String(imp.items_imported).padEnd(10)}` +
500
+ `${statusColor(imp.status)(imp.status).padEnd(14)}` +
501
+ chalk_1.default.dim(formatDate(imp.created_at)));
502
+ }
503
+ }
504
+ console.log('');
505
+ console.log(chalk_1.default.dim(' Full history: solid connect history'));
506
+ }
507
+ catch (error) {
508
+ spinner.fail(chalk_1.default.red('Failed to fetch connections'));
509
+ const apiError = (0, api_client_1.handleApiError)(error);
510
+ console.error(chalk_1.default.red(` ${apiError.message}`));
511
+ }
512
+ });
513
+ // ── History ───────────────────────────────────────────────────────────
514
+ exports.connectCommand
515
+ .command('history')
516
+ .description('Full import history')
517
+ .option('-n, --limit <number>', 'Number of entries to show', '25')
518
+ .option('-p, --provider <provider>', 'Filter by provider (figma, slack, notion, etc.)')
519
+ .option('-s, --status <status>', 'Filter by status (completed, failed, running)')
520
+ .action(async (options) => {
521
+ requireAuth();
522
+ const spinner = (0, ora_1.default)('Fetching import history...').start();
523
+ try {
524
+ const params = { limit: parseInt(options.limit) };
525
+ if (options.provider)
526
+ params.provider = options.provider;
527
+ if (options.status)
528
+ params.status = options.status;
529
+ const response = await api_client_1.apiClient.get('/api/v1/connections/history', { params });
530
+ const imports = response.data.imports;
531
+ spinner.succeed(`${response.data.total} total imports`);
532
+ if (!imports || imports.length === 0) {
533
+ console.log('');
534
+ console.log(chalk_1.default.dim(' No import history found.'));
535
+ return;
536
+ }
537
+ console.log('');
538
+ console.log(chalk_1.default.bold(' ').padEnd(4) +
539
+ chalk_1.default.bold('ID'.padEnd(14)) +
540
+ chalk_1.default.bold('PROVIDER'.padEnd(12)) +
541
+ chalk_1.default.bold('ENTITY'.padEnd(12)) +
542
+ chalk_1.default.bold('ITEMS'.padEnd(8)) +
543
+ chalk_1.default.bold('SKIP'.padEnd(7)) +
544
+ chalk_1.default.bold('FAIL'.padEnd(7)) +
545
+ chalk_1.default.bold('STATUS'.padEnd(12)) +
546
+ chalk_1.default.bold('DATE'));
547
+ console.log(chalk_1.default.dim(' ' + '─'.repeat(90)));
548
+ for (const imp of imports) {
549
+ const failStr = imp.items_failed > 0 ? chalk_1.default.red(String(imp.items_failed)) : chalk_1.default.dim('0');
550
+ const skipStr = imp.items_skipped > 0 ? chalk_1.default.yellow(String(imp.items_skipped)) : chalk_1.default.dim('0');
551
+ console.log(` ${statusIcon(imp.status)} ` +
552
+ `${imp.import_id.slice(0, 12).padEnd(14)}` +
553
+ `${imp.provider.padEnd(12)}` +
554
+ `${(imp.entity_type || '—').padEnd(12)}` +
555
+ `${chalk_1.default.green(String(imp.items_imported)).padEnd(8)}` +
556
+ `${skipStr.padEnd(7)}` +
557
+ `${failStr.padEnd(7)}` +
558
+ `${statusColor(imp.status)(imp.status).padEnd(12)}` +
559
+ chalk_1.default.dim(formatDate(imp.created_at)));
560
+ }
561
+ if (response.data.total > imports.length) {
562
+ console.log('');
563
+ console.log(chalk_1.default.dim(` Showing ${imports.length} of ${response.data.total}. Use --limit to see more.`));
564
+ }
565
+ }
566
+ catch (error) {
567
+ spinner.fail(chalk_1.default.red('Failed to fetch history'));
568
+ const apiError = (0, api_client_1.handleApiError)(error);
569
+ console.error(chalk_1.default.red(` ${apiError.message}`));
570
+ }
571
+ });
572
+ // ── Status ────────────────────────────────────────────────────────────
573
+ exports.connectCommand
574
+ .command('status <id>')
575
+ .description('Check import progress')
576
+ .action(async (id) => {
577
+ requireAuth();
578
+ const spinner = (0, ora_1.default)('Checking import status...').start();
579
+ try {
580
+ const response = await api_client_1.apiClient.get(`/api/v1/connections/${id}/status`);
581
+ const data = response.data;
582
+ if (data.status === 'completed') {
583
+ spinner.succeed(chalk_1.default.green('Import completed'));
584
+ }
585
+ else if (data.status === 'failed') {
586
+ spinner.fail(chalk_1.default.red('Import failed'));
587
+ }
588
+ else if (data.status === 'running' || data.status === 'in_progress') {
589
+ spinner.info(chalk_1.default.cyan(`Import in progress (${data.progress}%)`));
590
+ }
591
+ else {
592
+ spinner.info(`Import status: ${data.status}`);
593
+ }
594
+ printImportSummary({
595
+ import_id: data.import_id,
596
+ provider: data.provider,
597
+ status: data.status,
598
+ items_imported: data.items_imported,
599
+ items_skipped: data.items_skipped,
600
+ items_failed: data.items_failed,
601
+ created_at: data.created_at,
602
+ completed_at: data.completed_at || undefined,
603
+ details: data.details,
604
+ });
605
+ // Progress bar for in-progress imports
606
+ if (data.status === 'running' || data.status === 'in_progress') {
607
+ console.log('');
608
+ const barWidth = 40;
609
+ const filled = Math.round((data.progress / 100) * barWidth);
610
+ const empty = barWidth - filled;
611
+ const bar = chalk_1.default.cyan('█'.repeat(filled)) + chalk_1.default.dim('░'.repeat(empty));
612
+ console.log(` [${bar}] ${data.progress}%`);
613
+ }
614
+ // Show errors if any
615
+ if (data.errors && data.errors.length > 0) {
616
+ console.log('');
617
+ console.log(chalk_1.default.red(' Errors:'));
618
+ for (const err of data.errors.slice(0, 10)) {
619
+ console.log(chalk_1.default.red(` ✗ ${err.item}: ${err.message}`));
620
+ }
621
+ if (data.errors.length > 10) {
622
+ console.log(chalk_1.default.dim(` ... and ${data.errors.length - 10} more errors`));
623
+ }
624
+ }
625
+ }
626
+ catch (error) {
627
+ spinner.fail(chalk_1.default.red('Failed to check status'));
628
+ const apiError = (0, api_client_1.handleApiError)(error);
629
+ console.error(chalk_1.default.red(` ${apiError.message}`));
630
+ }
631
+ });
632
+ //# sourceMappingURL=connect.js.map