@picahq/cli 0.2.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.
@@ -1,196 +0,0 @@
1
- import * as p from '@clack/prompts';
2
- import pc from 'picocolors';
3
- import { getApiKey } from '../lib/config.js';
4
- import { PicaApi, TimeoutError } from '../lib/api.js';
5
- import { openConnectionPage, getConnectionUrl } from '../lib/browser.js';
6
- import { findPlatform, findSimilarPlatforms } from '../lib/platforms.js';
7
- import { printTable } from '../lib/table.js';
8
- import type { Connection } from '../lib/types.js';
9
-
10
- export async function connectionAddCommand(platformArg?: string): Promise<void> {
11
- p.intro(pc.bgCyan(pc.black(' Pica ')));
12
-
13
- const apiKey = getApiKey();
14
- if (!apiKey) {
15
- p.cancel('Not configured. Run `pica init` first.');
16
- process.exit(1);
17
- }
18
-
19
- const api = new PicaApi(apiKey);
20
-
21
- // Get platform list for validation
22
- const spinner = p.spinner();
23
- spinner.start('Loading platforms...');
24
-
25
- let platforms;
26
- try {
27
- platforms = await api.listPlatforms();
28
- spinner.stop(`${platforms.length} platforms available`);
29
- } catch (error) {
30
- spinner.stop('Failed to load platforms');
31
- p.cancel(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
32
- process.exit(1);
33
- }
34
-
35
- // Get or prompt for platform
36
- let platform: string;
37
-
38
- if (platformArg) {
39
- const found = findPlatform(platforms, platformArg);
40
- if (found) {
41
- platform = found.platform;
42
- } else {
43
- const similar = findSimilarPlatforms(platforms, platformArg);
44
- if (similar.length > 0) {
45
- p.log.warn(`Unknown platform: ${platformArg}`);
46
- const suggestion = await p.select({
47
- message: 'Did you mean:',
48
- options: [
49
- ...similar.map(s => ({ value: s.platform, label: `${s.name} (${s.platform})` })),
50
- { value: '__other__', label: 'None of these' },
51
- ],
52
- });
53
-
54
- if (p.isCancel(suggestion) || suggestion === '__other__') {
55
- p.note(`Run ${pc.cyan('pica platforms')} to see all available platforms.`);
56
- p.cancel('Connection cancelled.');
57
- process.exit(0);
58
- }
59
-
60
- platform = suggestion as string;
61
- } else {
62
- p.cancel(`Unknown platform: ${platformArg}\n\nRun ${pc.cyan('pica platforms')} to see available platforms.`);
63
- process.exit(1);
64
- }
65
- }
66
- } else {
67
- const platformInput = await p.text({
68
- message: 'Which platform do you want to connect?',
69
- placeholder: 'gmail, slack, hubspot...',
70
- validate: (value) => {
71
- if (!value.trim()) return 'Platform name is required';
72
- return undefined;
73
- },
74
- });
75
-
76
- if (p.isCancel(platformInput)) {
77
- p.cancel('Connection cancelled.');
78
- process.exit(0);
79
- }
80
-
81
- const found = findPlatform(platforms, platformInput);
82
- if (found) {
83
- platform = found.platform;
84
- } else {
85
- p.cancel(`Unknown platform: ${platformInput}\n\nRun ${pc.cyan('pica platforms')} to see available platforms.`);
86
- process.exit(1);
87
- }
88
- }
89
-
90
- // Open browser
91
- const url = getConnectionUrl(platform);
92
- p.log.info(`Opening browser to connect ${pc.cyan(platform)}...`);
93
- p.note(pc.dim(url), 'URL');
94
-
95
- try {
96
- await openConnectionPage(platform);
97
- } catch {
98
- p.log.warn('Could not open browser automatically.');
99
- p.note(`Open this URL manually:\n${url}`);
100
- }
101
-
102
- // Poll for connection
103
- const pollSpinner = p.spinner();
104
- pollSpinner.start('Waiting for connection... (complete auth in browser)');
105
-
106
- try {
107
- const connection = await api.waitForConnection(platform, 5 * 60 * 1000, 5000);
108
- pollSpinner.stop(`${platform} connected!`);
109
-
110
- p.log.success(`${pc.green('✓')} ${connection.platform} is now available to your AI agents.`);
111
- p.outro('Connection complete!');
112
- } catch (error) {
113
- pollSpinner.stop('Connection timed out');
114
-
115
- if (error instanceof TimeoutError) {
116
- p.note(
117
- `Possible issues:\n` +
118
- ` - OAuth flow was not completed in the browser\n` +
119
- ` - Browser popup was blocked\n` +
120
- ` - Wrong account selected\n\n` +
121
- `Try again with: ${pc.cyan(`pica connection add ${platform}`)}`,
122
- 'Timed Out'
123
- );
124
- } else {
125
- p.log.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
126
- }
127
-
128
- process.exit(1);
129
- }
130
- }
131
-
132
- export async function connectionListCommand(): Promise<void> {
133
- const apiKey = getApiKey();
134
- if (!apiKey) {
135
- p.cancel('Not configured. Run `pica init` first.');
136
- process.exit(1);
137
- }
138
-
139
- const api = new PicaApi(apiKey);
140
-
141
- const spinner = p.spinner();
142
- spinner.start('Loading connections...');
143
-
144
- try {
145
- const connections = await api.listConnections();
146
- spinner.stop(`${connections.length} connection${connections.length === 1 ? '' : 's'} found`);
147
-
148
- if (connections.length === 0) {
149
- p.note(
150
- `No connections yet.\n\n` +
151
- `Add one with: ${pc.cyan('pica connection add gmail')}`,
152
- 'No Connections'
153
- );
154
- return;
155
- }
156
-
157
- console.log();
158
-
159
- const rows = connections.map(conn => ({
160
- status: getStatusIndicator(conn.state),
161
- platform: conn.platform,
162
- state: conn.state,
163
- key: conn.key,
164
- }));
165
-
166
- printTable(
167
- [
168
- { key: 'status', label: '' },
169
- { key: 'platform', label: 'Platform' },
170
- { key: 'state', label: 'Status' },
171
- { key: 'key', label: 'Connection Key', color: pc.dim },
172
- ],
173
- rows
174
- );
175
-
176
- console.log();
177
- p.note(`Add more with: ${pc.cyan('pica connection add <platform>')}`, 'Tip');
178
- } catch (error) {
179
- spinner.stop('Failed to load connections');
180
- p.cancel(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
181
- process.exit(1);
182
- }
183
- }
184
-
185
- function getStatusIndicator(state: Connection['state']): string {
186
- switch (state) {
187
- case 'operational':
188
- return pc.green('●');
189
- case 'degraded':
190
- return pc.yellow('●');
191
- case 'failed':
192
- return pc.red('●');
193
- default:
194
- return pc.dim('○');
195
- }
196
- }