terse-cli 0.9.19 → 0.9.21
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.
- package/README.md +2 -2
- package/dist/cliUi.d.ts +3 -1
- package/dist/cliUi.d.ts.map +1 -1
- package/dist/cliUi.js +3 -2
- package/dist/cliUi.js.map +1 -1
- package/dist/commands/actor.d.ts.map +1 -1
- package/dist/commands/actor.js +32 -5
- package/dist/commands/actor.js.map +1 -1
- package/dist/commands/actorGenerate.d.ts.map +1 -1
- package/dist/commands/actorGenerate.js +22 -86
- package/dist/commands/actorGenerate.js.map +1 -1
- package/dist/commands/attach.d.ts +0 -7
- package/dist/commands/attach.d.ts.map +1 -1
- package/dist/commands/attach.js +220 -189
- package/dist/commands/attach.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +15 -3
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/generate.d.ts +0 -4
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +161 -127
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/history.d.ts +0 -15
- package/dist/commands/history.d.ts.map +1 -1
- package/dist/commands/history.js +139 -105
- package/dist/commands/history.js.map +1 -1
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +6 -4
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/integrate.d.ts +0 -48
- package/dist/commands/integrate.d.ts.map +1 -1
- package/dist/commands/integrate.js +897 -699
- package/dist/commands/integrate.js.map +1 -1
- package/dist/commands/integrateUse.d.ts +0 -12
- package/dist/commands/integrateUse.d.ts.map +1 -1
- package/dist/commands/integrateUse.js +132 -98
- package/dist/commands/integrateUse.js.map +1 -1
- package/dist/commands/listen.d.ts +0 -7
- package/dist/commands/listen.d.ts.map +1 -1
- package/dist/commands/listen.js +98 -81
- package/dist/commands/listen.js.map +1 -1
- package/dist/commands/memory.d.ts +0 -21
- package/dist/commands/memory.d.ts.map +1 -1
- package/dist/commands/memory.js +147 -128
- package/dist/commands/memory.js.map +1 -1
- package/dist/commands/replay.d.ts +0 -2
- package/dist/commands/replay.d.ts.map +1 -1
- package/dist/commands/replay.js +37 -28
- package/dist/commands/replay.js.map +1 -1
- package/dist/commands/resume.d.ts +0 -4
- package/dist/commands/resume.d.ts.map +1 -1
- package/dist/commands/resume.js +34 -28
- package/dist/commands/resume.js.map +1 -1
- package/dist/commands/run.d.ts +0 -2
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +78 -70
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/state.d.ts +0 -18
- package/dist/commands/state.d.ts.map +1 -1
- package/dist/commands/state.js +129 -108
- package/dist/commands/state.js.map +1 -1
- package/dist/commands/test.d.ts +0 -28
- package/dist/commands/test.d.ts.map +1 -1
- package/dist/commands/test.js +509 -403
- package/dist/commands/test.js.map +1 -1
- package/dist/commands/toolRun.d.ts +0 -6
- package/dist/commands/toolRun.d.ts.map +1 -1
- package/dist/commands/toolRun.js +149 -134
- package/dist/commands/toolRun.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/integrationApi.d.ts +0 -15
- package/dist/integrationApi.d.ts.map +1 -1
- package/dist/integrationApi.js +75 -49
- package/dist/integrationApi.js.map +1 -1
- package/dist/loadJob.d.ts +0 -11
- package/dist/loadJob.d.ts.map +1 -1
- package/dist/loadJob.js +54 -46
- package/dist/loadJob.js.map +1 -1
- package/dist/providers/LanguageProvider.d.ts +0 -29
- package/dist/providers/LanguageProvider.d.ts.map +1 -1
- package/dist/providers/LanguageProvider.js +3 -0
- package/dist/providers/LanguageProvider.js.map +1 -1
- package/dist/providers/typescript/TypeScriptProvider.d.ts +0 -24
- package/dist/providers/typescript/TypeScriptProvider.d.ts.map +1 -1
- package/dist/providers/typescript/TypeScriptProvider.js +113 -113
- package/dist/providers/typescript/TypeScriptProvider.js.map +1 -1
- package/dist/providers/typescript/runtimes/JobRuntime.d.ts +0 -26
- package/dist/providers/typescript/runtimes/JobRuntime.d.ts.map +1 -1
- package/dist/providers/typescript/runtimes/JobRuntime.js +51 -18
- package/dist/providers/typescript/runtimes/JobRuntime.js.map +1 -1
- package/dist/providers/typescript/runtimes/directJobRuntime.d.ts +0 -2
- package/dist/providers/typescript/runtimes/directJobRuntime.d.ts.map +1 -1
- package/dist/providers/typescript/runtimes/directJobRuntime.js +60 -49
- package/dist/providers/typescript/runtimes/directJobRuntime.js.map +1 -1
- package/dist/providers/typescript/runtimes/durableJobRuntime.d.ts +0 -2
- package/dist/providers/typescript/runtimes/durableJobRuntime.d.ts.map +1 -1
- package/dist/providers/typescript/runtimes/durableJobRuntime.js +168 -146
- package/dist/providers/typescript/runtimes/durableJobRuntime.js.map +1 -1
- package/dist/providers/typescript/runtimes/index.d.ts +0 -3
- package/dist/providers/typescript/runtimes/index.d.ts.map +1 -1
- package/dist/providers/typescript/runtimes/index.js +5 -2
- package/dist/providers/typescript/runtimes/index.js.map +1 -1
- package/dist/providers/typescript/runtimes/session.d.ts +0 -4
- package/dist/providers/typescript/runtimes/session.d.ts.map +1 -1
- package/dist/providers/typescript/runtimes/session.js +78 -64
- package/dist/providers/typescript/runtimes/session.js.map +1 -1
- package/dist/providers/typescript/terseWorkflow.d.ts +0 -7
- package/dist/providers/typescript/terseWorkflow.d.ts.map +1 -1
- package/dist/providers/typescript/terseWorkflow.js +12 -7
- package/dist/providers/typescript/terseWorkflow.js.map +1 -1
- package/dist/runLocalTestJob.d.ts +0 -19
- package/dist/runLocalTestJob.d.ts.map +1 -1
- package/dist/runLocalTestJob.js +55 -29
- package/dist/runLocalTestJob.js.map +1 -1
- package/dist/setup.js +1 -1
- package/dist/setup.js.map +1 -1
- package/dist/sourceArchive.d.ts +1 -1
- package/dist/sourceArchive.d.ts.map +1 -1
- package/dist/sourceArchive.js +1 -0
- package/dist/sourceArchive.js.map +1 -1
- package/package.json +3 -4
- package/templates/typescript/init/package.json.hbs +1 -2
- package/templates/typescript/terse-transport.d.ts +25 -0
- package/templates/typescript/terse-transport.js +117 -0
- package/templates/typescript/tsconfig.json +13 -0
|
@@ -1,700 +1,898 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
//
|
|
399
|
-
//
|
|
400
|
-
//
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
}
|
|
1
|
+
"use strict";
|
|
2
|
+
// LEGACY-JOBS: Commented out while Terse is actors-only. Uncomment to restore; see the note in terse-sdk/src/index.ts.
|
|
3
|
+
// import { cancel, confirm, group, intro, isCancel, log, outro, password, select, text } from "@clack/prompts"
|
|
4
|
+
// import { input } from "@inquirer/prompts"
|
|
5
|
+
// import chalk from "chalk"
|
|
6
|
+
// import type { CliIntegrationDisplayState, FormIntegrationSetup, IntegrationWithStatus } from "terse-types"
|
|
7
|
+
// import { INTEGRATION_METADATA, IntegrationType } from "terse-types"
|
|
8
|
+
// import { InstallationOptionsSchemas } from "terse-types/Integrations"
|
|
9
|
+
//
|
|
10
|
+
// import { readApiKey, readApiKeyOrBail } from "../api.js"
|
|
11
|
+
// import { CliError } from "../cliError.js"
|
|
12
|
+
// import { type NonInteractiveOpts, coerceAndValidateForSchema, isNonInteractive, parseKeyValueFlags, readFieldsFromStdin } from "../cliHelpers.js"
|
|
13
|
+
// import { createSpinner, formatSummaryList } from "../cliUi.js"
|
|
14
|
+
// import {
|
|
15
|
+
// ConfigurationFieldDefinition,
|
|
16
|
+
// FormFieldDefinition,
|
|
17
|
+
// disconnectIntegration,
|
|
18
|
+
// fetchInstallationUrl,
|
|
19
|
+
// fetchIntegrationConnections,
|
|
20
|
+
// fetchIntegrationFields,
|
|
21
|
+
// fetchIntegrations,
|
|
22
|
+
// pollForConnection,
|
|
23
|
+
// submitIntegrationForm
|
|
24
|
+
// } from "../integrationApi.js"
|
|
25
|
+
// import { openUrlInBrowser } from "../openBrowser.js"
|
|
26
|
+
// import { readProjectConfig } from "../projectConfig.js"
|
|
27
|
+
// import { type ToolDetails, fetchToolDetails } from "../toolCatalog.js"
|
|
28
|
+
//
|
|
29
|
+
// import { generate } from "./generate.js"
|
|
30
|
+
//
|
|
31
|
+
// const INTERNAL_INTEGRATION_TYPES = new Set<string>([IntegrationType.TERSE, IntegrationType.CRON_JOB, IntegrationType.WEBMONITOR])
|
|
32
|
+
//
|
|
33
|
+
// const SKIP_VALUE = "skip" as const
|
|
34
|
+
//
|
|
35
|
+
// export async function integrate(options: IntegrateOptions = {}): Promise<void> {
|
|
36
|
+
// const showLifecycle = options.showLifecycle ?? true
|
|
37
|
+
// const runGenerateAfterChange = options.runGenerateAfterChange ?? true
|
|
38
|
+
//
|
|
39
|
+
// if (showLifecycle) {
|
|
40
|
+
// intro("terse integrate")
|
|
41
|
+
// }
|
|
42
|
+
//
|
|
43
|
+
// const apiKey = options.apiKey?.trim() || readApiKeyOrBail()
|
|
44
|
+
// let didChangeAnyIntegration = false
|
|
45
|
+
//
|
|
46
|
+
// let continueLoop = true
|
|
47
|
+
// while (continueLoop) {
|
|
48
|
+
// const result = await connectOneIntegration(apiKey)
|
|
49
|
+
// didChangeAnyIntegration = didChangeAnyIntegration || (result.status !== "unchanged" && result.status !== "skipped")
|
|
50
|
+
// if (result.status === "skipped") break
|
|
51
|
+
// continueLoop = abortIfCancelled(
|
|
52
|
+
// await confirm({
|
|
53
|
+
// message: "Connect another integration?",
|
|
54
|
+
// initialValue: false
|
|
55
|
+
// })
|
|
56
|
+
// )
|
|
57
|
+
// }
|
|
58
|
+
//
|
|
59
|
+
// if (didChangeAnyIntegration && runGenerateAfterChange) {
|
|
60
|
+
// await generate(undefined, { apiKey })
|
|
61
|
+
// }
|
|
62
|
+
//
|
|
63
|
+
// if (showLifecycle) {
|
|
64
|
+
// outro("Done")
|
|
65
|
+
// }
|
|
66
|
+
// }
|
|
67
|
+
//
|
|
68
|
+
// export async function listAndPromptIntegrations(options: IntegrateOptions = {}): Promise<void> {
|
|
69
|
+
// const apiKey = options.apiKey?.trim() || readApiKey()
|
|
70
|
+
// if (!apiKey) return
|
|
71
|
+
//
|
|
72
|
+
// const s = createSpinner()
|
|
73
|
+
// s.start("Fetching integrations")
|
|
74
|
+
//
|
|
75
|
+
// let integrations
|
|
76
|
+
// try {
|
|
77
|
+
// integrations = await fetchIntegrations(apiKey)
|
|
78
|
+
// s.stop("Fetched integrations")
|
|
79
|
+
// } catch {
|
|
80
|
+
// s.stop("Failed to fetch integrations")
|
|
81
|
+
// console.error(chalk.red("Failed to fetch integrations"))
|
|
82
|
+
// return
|
|
83
|
+
// }
|
|
84
|
+
//
|
|
85
|
+
// const active = integrations.filter(i => i.isActive && !INTERNAL_INTEGRATION_TYPES.has(i.integrationType))
|
|
86
|
+
//
|
|
87
|
+
// if (options.nonInteractive || isNonInteractive()) {
|
|
88
|
+
// if (active.length > 0) {
|
|
89
|
+
// const names = active.map(i => INTEGRATION_METADATA[i.integrationType]?.name || i.integrationType)
|
|
90
|
+
// console.log(chalk.dim(`Connected integrations (${active.length}): ${formatSummaryList(names)}`))
|
|
91
|
+
// } else {
|
|
92
|
+
// console.log(chalk.dim("No integrated tools yet. Run `terse integrate` in an interactive terminal to connect some."))
|
|
93
|
+
// }
|
|
94
|
+
// return
|
|
95
|
+
// }
|
|
96
|
+
//
|
|
97
|
+
// if (active.length > 0) {
|
|
98
|
+
// const names = active.map(i => INTEGRATION_METADATA[i.integrationType]?.name || i.integrationType)
|
|
99
|
+
// console.log(chalk.dim(`Connected integrations (${active.length}): ${formatSummaryList(names)}`))
|
|
100
|
+
// const addMore = abortIfCancelled(
|
|
101
|
+
// await confirm({
|
|
102
|
+
// message: "Connect another integration?",
|
|
103
|
+
// initialValue: false
|
|
104
|
+
// })
|
|
105
|
+
// )
|
|
106
|
+
// if (addMore) await integrate({ showLifecycle: false, runGenerateAfterChange: options.runGenerateAfterChange, apiKey })
|
|
107
|
+
// } else {
|
|
108
|
+
// log.warn(`${chalk.yellow.bold("No integrations connected.")} Jobs that depend on GitHub, Slack, Linear, etc. won't run until you connect one.`)
|
|
109
|
+
// const shouldConnect = abortIfCancelled(
|
|
110
|
+
// await confirm({
|
|
111
|
+
// message: "Connect an integration now?",
|
|
112
|
+
// initialValue: true
|
|
113
|
+
// })
|
|
114
|
+
// )
|
|
115
|
+
// if (shouldConnect) {
|
|
116
|
+
// await integrate({ showLifecycle: false, runGenerateAfterChange: options.runGenerateAfterChange, apiKey })
|
|
117
|
+
// } else {
|
|
118
|
+
// log.info(`Skipped. Run ${chalk.cyan("terse integrate")} anytime to connect one.`)
|
|
119
|
+
// }
|
|
120
|
+
// }
|
|
121
|
+
// }
|
|
122
|
+
//
|
|
123
|
+
// async function connectOneIntegration(apiKey: string): Promise<IntegrationChangeResult> {
|
|
124
|
+
// while (true) {
|
|
125
|
+
// const integrations = await fetchUserFacingIntegrations(apiKey)
|
|
126
|
+
//
|
|
127
|
+
// if (integrations.length === 0) {
|
|
128
|
+
// log.warn("No integrations available.")
|
|
129
|
+
// return { status: "unchanged" }
|
|
130
|
+
// }
|
|
131
|
+
//
|
|
132
|
+
// const selection = await promptForIntegrationSelection(integrations)
|
|
133
|
+
// if (selection.action === "skip") {
|
|
134
|
+
// return { status: "skipped" }
|
|
135
|
+
// }
|
|
136
|
+
// if (selection.action === "back") {
|
|
137
|
+
// continue
|
|
138
|
+
// }
|
|
139
|
+
//
|
|
140
|
+
// const selectedIntegration = integrations.find(integration => integration.integrationType === selection.integrationType)
|
|
141
|
+
// if (!selectedIntegration) {
|
|
142
|
+
// log.warn(`Integration '${selection.integrationType}' is no longer available.`)
|
|
143
|
+
// return { status: "unchanged" }
|
|
144
|
+
// }
|
|
145
|
+
//
|
|
146
|
+
// switch (selection.action) {
|
|
147
|
+
// case "keep":
|
|
148
|
+
// return { status: "unchanged", integrationType: selection.integrationType }
|
|
149
|
+
// case "disconnect": {
|
|
150
|
+
// const didDisconnect = await handleDisconnect(apiKey, selection.integrationType)
|
|
151
|
+
// return {
|
|
152
|
+
// status: didDisconnect ? "modified" : "unchanged",
|
|
153
|
+
// integrationType: selection.integrationType
|
|
154
|
+
// }
|
|
155
|
+
// }
|
|
156
|
+
// case "connect":
|
|
157
|
+
// case "refresh_permissions": {
|
|
158
|
+
// const didUpdate = await runInstallationFlow(apiKey, selection.integrationType)
|
|
159
|
+
// return {
|
|
160
|
+
// status: didUpdate ? (selectedIntegration.isActive ? "modified" : "added") : "unchanged",
|
|
161
|
+
// integrationType: selection.integrationType
|
|
162
|
+
// }
|
|
163
|
+
// }
|
|
164
|
+
// }
|
|
165
|
+
// }
|
|
166
|
+
// }
|
|
167
|
+
//
|
|
168
|
+
// async function fetchUserFacingIntegrations(apiKey: string): Promise<UserFacingIntegration[]> {
|
|
169
|
+
// const s = createSpinner()
|
|
170
|
+
// s.start("Fetching integrations")
|
|
171
|
+
//
|
|
172
|
+
// try {
|
|
173
|
+
// const integrations = await fetchIntegrations(apiKey)
|
|
174
|
+
// s.stop("Fetched integrations")
|
|
175
|
+
// return applyProjectPins(
|
|
176
|
+
// integrations.filter(i => !INTERNAL_INTEGRATION_TYPES.has(i.integrationType)),
|
|
177
|
+
// apiKey
|
|
178
|
+
// )
|
|
179
|
+
// } catch (err: any) {
|
|
180
|
+
// s.stop("Failed to fetch integrations")
|
|
181
|
+
// throw new CliError("fetch_integrations_failed", err?.message ?? "Failed to fetch integrations.")
|
|
182
|
+
// }
|
|
183
|
+
// }
|
|
184
|
+
//
|
|
185
|
+
// async function applyProjectPins(integrations: IntegrationWithStatus[], apiKey: string): Promise<PinAwareIntegration[]> {
|
|
186
|
+
// const pins = readProjectConfig()?.connections
|
|
187
|
+
// if (!pins) return integrations
|
|
188
|
+
//
|
|
189
|
+
// return Promise.all(
|
|
190
|
+
// integrations.map(async integration => {
|
|
191
|
+
// const pinnedId = pins[integration.integrationType]
|
|
192
|
+
// if (!pinnedId || integration.cliDisplayState.status !== "connected") return integration
|
|
193
|
+
// if (integration.cliDisplayState.integrationId === pinnedId) return { ...integration, pin: "ok" as const }
|
|
194
|
+
//
|
|
195
|
+
// const connections = await fetchIntegrationConnections(apiKey, integration.integrationType).catch(() => [])
|
|
196
|
+
// const pinned = connections.find(connection => connection.id === pinnedId)
|
|
197
|
+
// return {
|
|
198
|
+
// ...integration,
|
|
199
|
+
// pin: pinned ? ("ok" as const) : ("missing" as const),
|
|
200
|
+
// cliDisplayState: {
|
|
201
|
+
// ...integration.cliDisplayState,
|
|
202
|
+
// connectionName: pinned?.name ?? pinnedId,
|
|
203
|
+
// integrationId: pinnedId
|
|
204
|
+
// }
|
|
205
|
+
// }
|
|
206
|
+
// })
|
|
207
|
+
// )
|
|
208
|
+
// }
|
|
209
|
+
//
|
|
210
|
+
// async function promptForIntegrationSelection(integrations: UserFacingIntegration[]): Promise<GroupedIntegrationSelection> {
|
|
211
|
+
// const longestName = integrations.reduce((max, integration) => Math.max(max, getIntegrationDisplayName(integration).length), 0)
|
|
212
|
+
//
|
|
213
|
+
// return group(
|
|
214
|
+
// {
|
|
215
|
+
// integrationType: () =>
|
|
216
|
+
// select<IntegrationType | typeof SKIP_VALUE>({
|
|
217
|
+
// message: "Choose an integration",
|
|
218
|
+
// options: [
|
|
219
|
+
// ...integrations.map(integration => ({
|
|
220
|
+
// value: integration.integrationType,
|
|
221
|
+
// label: formatIntegrationPickerLabel(integration, longestName)
|
|
222
|
+
// })),
|
|
223
|
+
// { value: SKIP_VALUE, label: chalk.dim("Skip — don't connect anything") }
|
|
224
|
+
// ]
|
|
225
|
+
// }),
|
|
226
|
+
// action: ({ results }) => {
|
|
227
|
+
// const selectedType = results.integrationType as IntegrationType | typeof SKIP_VALUE
|
|
228
|
+
// if (selectedType === SKIP_VALUE) {
|
|
229
|
+
// return Promise.resolve(SKIP_VALUE)
|
|
230
|
+
// }
|
|
231
|
+
// const selectedIntegration = integrations.find(integration => integration.integrationType === selectedType)
|
|
232
|
+
// if (!selectedIntegration) {
|
|
233
|
+
// throw new Error(`Integration '${selectedType}' is no longer available`)
|
|
234
|
+
// }
|
|
235
|
+
//
|
|
236
|
+
// return select({
|
|
237
|
+
// message: getIntegrationDisplayName(selectedIntegration),
|
|
238
|
+
// options: getIntegrationActions(selectedIntegration).map(action => ({
|
|
239
|
+
// value: action,
|
|
240
|
+
// label: formatIntegrationActionLabel(action)
|
|
241
|
+
// }))
|
|
242
|
+
// })
|
|
243
|
+
// }
|
|
244
|
+
// },
|
|
245
|
+
// {
|
|
246
|
+
// onCancel: () => {
|
|
247
|
+
// cancel("Operation cancelled.")
|
|
248
|
+
// process.exit(0)
|
|
249
|
+
// }
|
|
250
|
+
// }
|
|
251
|
+
// ) as Promise<GroupedIntegrationSelection>
|
|
252
|
+
// }
|
|
253
|
+
//
|
|
254
|
+
// function getIntegrationActions(integration: UserFacingIntegration): IntegrationAction[] {
|
|
255
|
+
// if (integration.cliDisplayState.status === "connected") {
|
|
256
|
+
// return ["keep", "disconnect", "refresh_permissions"]
|
|
257
|
+
// }
|
|
258
|
+
//
|
|
259
|
+
// return ["connect", "back"]
|
|
260
|
+
// }
|
|
261
|
+
//
|
|
262
|
+
// function formatIntegrationActionLabel(action: IntegrationAction): string {
|
|
263
|
+
// switch (action) {
|
|
264
|
+
// case "keep":
|
|
265
|
+
// return "Keep this connection"
|
|
266
|
+
// case "disconnect":
|
|
267
|
+
// return "Disconnect"
|
|
268
|
+
// case "refresh_permissions":
|
|
269
|
+
// return "Refresh permissions"
|
|
270
|
+
// case "connect":
|
|
271
|
+
// return "Connect"
|
|
272
|
+
// case "back":
|
|
273
|
+
// return "Back"
|
|
274
|
+
// default:
|
|
275
|
+
// const exhaustiveCheck: never = action
|
|
276
|
+
// throw new Error(`Unhandled integration action: ${exhaustiveCheck}`)
|
|
277
|
+
// }
|
|
278
|
+
// }
|
|
279
|
+
//
|
|
280
|
+
// function formatIntegrationPickerLabel(integration: UserFacingIntegration, longestName: number): string {
|
|
281
|
+
// const name = getIntegrationDisplayName(integration).padEnd(longestName)
|
|
282
|
+
// const summary = formatIntegrationDisplaySummary(integration)
|
|
283
|
+
// return `${name} ${chalk.dim(summary)}`
|
|
284
|
+
// }
|
|
285
|
+
//
|
|
286
|
+
// function formatIntegrationDisplaySummary(integration: PinAwareIntegration): string {
|
|
287
|
+
// const displayState = integration.cliDisplayState
|
|
288
|
+
// if (displayState.status === "connected") {
|
|
289
|
+
// return `${displayState.connectionLabel}: ${displayState.connectionName}${pinSuffix(integration.pin)}`
|
|
290
|
+
// }
|
|
291
|
+
//
|
|
292
|
+
// return "Not connected"
|
|
293
|
+
// }
|
|
294
|
+
//
|
|
295
|
+
// function pinSuffix(pin: PinState | undefined): string {
|
|
296
|
+
// if (pin === "missing") return " (pinned, missing)"
|
|
297
|
+
// if (pin === "ok") return " (pinned)"
|
|
298
|
+
// return ""
|
|
299
|
+
// }
|
|
300
|
+
//
|
|
301
|
+
// function getIntegrationDisplayName(integration: UserFacingIntegration): string {
|
|
302
|
+
// return INTEGRATION_METADATA[integration.integrationType]?.name || integration.integrationType
|
|
303
|
+
// }
|
|
304
|
+
//
|
|
305
|
+
// async function runInstallationFlow(apiKey: string, integrationType: IntegrationType): Promise<boolean> {
|
|
306
|
+
// const s = createSpinner()
|
|
307
|
+
// s.start("Loading integration details")
|
|
308
|
+
//
|
|
309
|
+
// try {
|
|
310
|
+
// const fieldsResponse = await fetchIntegrationFields(apiKey, integrationType)
|
|
311
|
+
// s.stop("Loaded integration details")
|
|
312
|
+
//
|
|
313
|
+
// if (fieldsResponse.installationType === "form") {
|
|
314
|
+
// return handleFormIntegration(apiKey, integrationType, fieldsResponse.fields as FormFieldDefinition[], fieldsResponse.setup)
|
|
315
|
+
// }
|
|
316
|
+
//
|
|
317
|
+
// if (fieldsResponse.installationType === "oauth") {
|
|
318
|
+
// return handleOAuthIntegration(apiKey, integrationType, fieldsResponse.fields as ConfigurationFieldDefinition[])
|
|
319
|
+
// }
|
|
320
|
+
// } catch (err: any) {
|
|
321
|
+
// s.stop("Failed to load integration details")
|
|
322
|
+
// console.error(chalk.red(` ${err.message}`))
|
|
323
|
+
// return false
|
|
324
|
+
// }
|
|
325
|
+
//
|
|
326
|
+
// log.warn(`Integration '${integrationType}' has an unsupported installation type.`)
|
|
327
|
+
// return false
|
|
328
|
+
// }
|
|
329
|
+
//
|
|
330
|
+
// async function handleFormIntegration(apiKey: string, integrationType: IntegrationType, fields: FormFieldDefinition[], setup?: FormIntegrationSetup): Promise<boolean> {
|
|
331
|
+
// await showFormSetupGuidance(integrationType, setup)
|
|
332
|
+
//
|
|
333
|
+
// const formValues: Record<string, string> = {}
|
|
334
|
+
// for (const field of fields) {
|
|
335
|
+
// const promptMessage = buildFieldPromptMessage(field)
|
|
336
|
+
//
|
|
337
|
+
// if (field.type === "password") {
|
|
338
|
+
// formValues[field.name] = abortIfCancelled(
|
|
339
|
+
// await password({
|
|
340
|
+
// message: promptMessage,
|
|
341
|
+
// validate: field.required ? value => ((value?.length ?? 0) > 0 ? undefined : `${field.label} is required`) : undefined
|
|
342
|
+
// })
|
|
343
|
+
// )
|
|
344
|
+
// continue
|
|
345
|
+
// }
|
|
346
|
+
//
|
|
347
|
+
// if (field.type === "textarea") {
|
|
348
|
+
// formValues[field.name] = await input({
|
|
349
|
+
// message: promptMessage,
|
|
350
|
+
// default: field.placeholder,
|
|
351
|
+
// validate: field.required ? value => (value.length > 0 ? true : `${field.label} is required`) : undefined
|
|
352
|
+
// })
|
|
353
|
+
// continue
|
|
354
|
+
// }
|
|
355
|
+
//
|
|
356
|
+
// formValues[field.name] = abortIfCancelled(
|
|
357
|
+
// await text({
|
|
358
|
+
// message: promptMessage,
|
|
359
|
+
// placeholder: field.placeholder,
|
|
360
|
+
// validate: field.required ? value => ((value?.length ?? 0) > 0 ? undefined : `${field.label} is required`) : undefined
|
|
361
|
+
// })
|
|
362
|
+
// )
|
|
363
|
+
// }
|
|
364
|
+
//
|
|
365
|
+
// const s = createSpinner()
|
|
366
|
+
// s.start("Connecting integration")
|
|
367
|
+
// try {
|
|
368
|
+
// const result = await submitIntegrationForm(apiKey, integrationType, formValues)
|
|
369
|
+
// if (result.success) {
|
|
370
|
+
// s.stop("Integration connected successfully")
|
|
371
|
+
// return true
|
|
372
|
+
// }
|
|
373
|
+
// s.stop(`Failed to connect: ${result.error || "Unknown error"}`)
|
|
374
|
+
// return false
|
|
375
|
+
// } catch (err: any) {
|
|
376
|
+
// s.stop("Failed to connect integration")
|
|
377
|
+
// console.error(chalk.red(` ${err.message}`))
|
|
378
|
+
// return false
|
|
379
|
+
// }
|
|
380
|
+
// }
|
|
381
|
+
//
|
|
382
|
+
// async function showFormSetupGuidance(integrationType: IntegrationType, setup?: FormIntegrationSetup): Promise<void> {
|
|
383
|
+
// if (!setup) return
|
|
384
|
+
//
|
|
385
|
+
// log.info(chalk.bold(`${INTEGRATION_METADATA[integrationType]?.name || integrationType} setup`))
|
|
386
|
+
// console.log(chalk.cyan(setup.url))
|
|
387
|
+
// console.log(chalk.dim(setup.title))
|
|
388
|
+
//
|
|
389
|
+
// for (const instruction of setup.instructions) {
|
|
390
|
+
// console.log(` ${chalk.dim("•")} ${instruction}`)
|
|
391
|
+
// }
|
|
392
|
+
//
|
|
393
|
+
// console.log("")
|
|
394
|
+
//
|
|
395
|
+
// const shouldOpenSetupUrl = abortIfCancelled(
|
|
396
|
+
// await confirm({
|
|
397
|
+
// message: "Open setup instructions in your browser?",
|
|
398
|
+
// initialValue: false
|
|
399
|
+
// })
|
|
400
|
+
// )
|
|
401
|
+
//
|
|
402
|
+
// if (shouldOpenSetupUrl) {
|
|
403
|
+
// openUrlInBrowser(setup.url)
|
|
404
|
+
// }
|
|
405
|
+
// }
|
|
406
|
+
//
|
|
407
|
+
// function buildFieldPromptMessage(field: FormFieldDefinition): string {
|
|
408
|
+
// return field.hint ? `${field.label} ${chalk.dim(`(${field.hint})`)}` : field.label
|
|
409
|
+
// }
|
|
410
|
+
//
|
|
411
|
+
// async function handleOAuthIntegration(apiKey: string, integrationType: IntegrationType, configFields: ConfigurationFieldDefinition[]): Promise<boolean> {
|
|
412
|
+
// let options: Record<string, unknown> | undefined
|
|
413
|
+
// if (configFields.length > 0) {
|
|
414
|
+
// const raw: Record<string, string> = {}
|
|
415
|
+
// for (const field of configFields) {
|
|
416
|
+
// const value = abortIfCancelled(
|
|
417
|
+
// await select({
|
|
418
|
+
// message: field.label,
|
|
419
|
+
// options: field.options.map(option => ({ value: option.value, label: option.label }))
|
|
420
|
+
// })
|
|
421
|
+
// )
|
|
422
|
+
// raw[field.name] = value
|
|
423
|
+
// }
|
|
424
|
+
// options = coerceAndValidateForSchema(raw, InstallationOptionsSchemas[integrationType], { integrationType })
|
|
425
|
+
// }
|
|
426
|
+
//
|
|
427
|
+
// const s = createSpinner()
|
|
428
|
+
// s.start("Getting authorization URL")
|
|
429
|
+
//
|
|
430
|
+
// let installationDetails
|
|
431
|
+
// try {
|
|
432
|
+
// installationDetails = await fetchInstallationUrl(apiKey, integrationType, options)
|
|
433
|
+
// s.stop("Authorization URL ready")
|
|
434
|
+
// } catch (err: any) {
|
|
435
|
+
// s.stop("Failed to get authorization URL")
|
|
436
|
+
// console.error(chalk.red(` ${err.message}`))
|
|
437
|
+
// return false
|
|
438
|
+
// }
|
|
439
|
+
//
|
|
440
|
+
// log.info(`Complete authorization in your browser: ${chalk.cyan(installationDetails.oauthUrl)}`)
|
|
441
|
+
// openUrlInBrowser(installationDetails.oauthUrl)
|
|
442
|
+
//
|
|
443
|
+
// s.start("Waiting for authorization to complete")
|
|
444
|
+
// const connected = await pollForConnection(apiKey, integrationType)
|
|
445
|
+
//
|
|
446
|
+
// if (connected) {
|
|
447
|
+
// s.stop("Integration connected successfully")
|
|
448
|
+
// return true
|
|
449
|
+
// }
|
|
450
|
+
//
|
|
451
|
+
// s.stop("Authorization timed out — please try again")
|
|
452
|
+
// return false
|
|
453
|
+
// }
|
|
454
|
+
//
|
|
455
|
+
// async function handleDisconnect(apiKey: string, integrationType: IntegrationType): Promise<boolean> {
|
|
456
|
+
// const s = createSpinner()
|
|
457
|
+
// s.start("Disconnecting integration")
|
|
458
|
+
//
|
|
459
|
+
// try {
|
|
460
|
+
// const result = await disconnectIntegration(apiKey, integrationType)
|
|
461
|
+
// if (result.success) {
|
|
462
|
+
// s.stop("Integration disconnected successfully")
|
|
463
|
+
// return true
|
|
464
|
+
// }
|
|
465
|
+
//
|
|
466
|
+
// s.stop(`Failed to disconnect: ${result.error || "Unknown error"}`)
|
|
467
|
+
// return false
|
|
468
|
+
// } catch (err: any) {
|
|
469
|
+
// s.stop("Failed to disconnect integration")
|
|
470
|
+
// console.error(chalk.red(` ${err.message}`))
|
|
471
|
+
// return false
|
|
472
|
+
// }
|
|
473
|
+
// }
|
|
474
|
+
//
|
|
475
|
+
// export function abortIfCancelled<T>(value: T | symbol): T {
|
|
476
|
+
// if (isCancel(value)) {
|
|
477
|
+
// cancel("Operation cancelled.")
|
|
478
|
+
// process.exit(0)
|
|
479
|
+
// }
|
|
480
|
+
//
|
|
481
|
+
// return value
|
|
482
|
+
// }
|
|
483
|
+
//
|
|
484
|
+
// // -------------------------------------------------------------------------
|
|
485
|
+
// // Non-interactive subcommands
|
|
486
|
+
// // -------------------------------------------------------------------------
|
|
487
|
+
//
|
|
488
|
+
// export function parseIntegrationTypeOrThrow(value: string): IntegrationType {
|
|
489
|
+
// const normalized = value.toLowerCase()
|
|
490
|
+
// const match = Object.values(IntegrationType).find(v => v === normalized)
|
|
491
|
+
// if (!match) {
|
|
492
|
+
// throw new CliError("unknown_integration_type", `Unknown integration type "${value}".`, {
|
|
493
|
+
// detail: `Supported: ${Object.values(IntegrationType)
|
|
494
|
+
// .filter(v => !INTERNAL_INTEGRATION_TYPES.has(v))
|
|
495
|
+
// .join(", ")}`
|
|
496
|
+
// })
|
|
497
|
+
// }
|
|
498
|
+
// return match as IntegrationType
|
|
499
|
+
// }
|
|
500
|
+
//
|
|
501
|
+
// function summaryFor(displayState: CliIntegrationDisplayState): { connectionLabel: string | null; connectionName: string | null } {
|
|
502
|
+
// if (displayState.status === "connected") {
|
|
503
|
+
// return { connectionLabel: displayState.connectionLabel, connectionName: displayState.connectionName }
|
|
504
|
+
// }
|
|
505
|
+
// return { connectionLabel: null, connectionName: null }
|
|
506
|
+
// }
|
|
507
|
+
//
|
|
508
|
+
// export async function integrateList(opts: IntegrateListOpts = {}): Promise<void> {
|
|
509
|
+
// const apiKey = readApiKeyOrBail()
|
|
510
|
+
// const integrations = await applyProjectPins(
|
|
511
|
+
// (await fetchIntegrations(apiKey)).filter(i => !INTERNAL_INTEGRATION_TYPES.has(i.integrationType)),
|
|
512
|
+
// apiKey
|
|
513
|
+
// )
|
|
514
|
+
//
|
|
515
|
+
// const filtered = integrations.filter(i => {
|
|
516
|
+
// if (opts.status === "connected") return i.isActive
|
|
517
|
+
// if (opts.status === "disconnected") return !i.isActive
|
|
518
|
+
// return true
|
|
519
|
+
// })
|
|
520
|
+
//
|
|
521
|
+
// if (opts.json) {
|
|
522
|
+
// const payload = {
|
|
523
|
+
// integrations: await Promise.all(
|
|
524
|
+
// filtered.map(async integration => {
|
|
525
|
+
// const { connectionLabel, connectionName } = summaryFor(integration.cliDisplayState)
|
|
526
|
+
// return {
|
|
527
|
+
// type: integration.integrationType,
|
|
528
|
+
// status: integration.isActive ? "connected" : "disconnected",
|
|
529
|
+
// name: INTEGRATION_METADATA[integration.integrationType]?.name ?? integration.integrationType,
|
|
530
|
+
// connectionLabel,
|
|
531
|
+
// connectionName,
|
|
532
|
+
// ...(integration.pin ? { pin: integration.pin } : {})
|
|
533
|
+
// }
|
|
534
|
+
// })
|
|
535
|
+
// )
|
|
536
|
+
// }
|
|
537
|
+
// process.stdout.write(JSON.stringify(payload, null, 2) + "\n")
|
|
538
|
+
// return
|
|
539
|
+
// }
|
|
540
|
+
//
|
|
541
|
+
// if (filtered.length === 0) {
|
|
542
|
+
// process.stdout.write("No integrations.\n")
|
|
543
|
+
// return
|
|
544
|
+
// }
|
|
545
|
+
//
|
|
546
|
+
// const longest = filtered.reduce((max, i) => Math.max(max, (INTEGRATION_METADATA[i.integrationType]?.name ?? i.integrationType).length), 0)
|
|
547
|
+
// for (const integration of filtered) {
|
|
548
|
+
// const name = (INTEGRATION_METADATA[integration.integrationType]?.name ?? integration.integrationType).padEnd(longest)
|
|
549
|
+
// const status = integration.isActive ? chalk.green("connected") : chalk.dim("not connected")
|
|
550
|
+
// const { connectionLabel, connectionName } = summaryFor(integration.cliDisplayState)
|
|
551
|
+
// const summary = connectionLabel && connectionName ? ` ${chalk.dim(`${connectionLabel}: ${connectionName}${pinSuffix(integration.pin)}`)}` : ""
|
|
552
|
+
// process.stdout.write(` ${name} ${status}${summary}\n`)
|
|
553
|
+
// }
|
|
554
|
+
// }
|
|
555
|
+
//
|
|
556
|
+
// export async function integrateDescribe(opts: IntegrateDescribeOpts): Promise<void> {
|
|
557
|
+
// const type = parseIntegrationTypeOrThrow(opts.integrationType)
|
|
558
|
+
// const apiKey = readApiKeyOrBail()
|
|
559
|
+
//
|
|
560
|
+
// const [integrations, fieldsResponse, toolCatalog] = await Promise.all([fetchIntegrations(apiKey), fetchIntegrationFields(apiKey, type), fetchToolDetails(apiKey).catch(() => null)])
|
|
561
|
+
// const match = integrations.find(i => i.integrationType === type)
|
|
562
|
+
//
|
|
563
|
+
// const payload = {
|
|
564
|
+
// type,
|
|
565
|
+
// name: INTEGRATION_METADATA[type]?.name ?? type,
|
|
566
|
+
// status: match?.isActive ? "connected" : "disconnected",
|
|
567
|
+
// installationType: fieldsResponse.installationType,
|
|
568
|
+
// fields: fieldsResponse.fields,
|
|
569
|
+
// setup: fieldsResponse.setup ?? null,
|
|
570
|
+
// tools: toolCatalog ? toolCatalog.filter(tool => tool.integration === type).map(toToolSummary) : null
|
|
571
|
+
// }
|
|
572
|
+
//
|
|
573
|
+
// if (opts.json) {
|
|
574
|
+
// process.stdout.write(JSON.stringify(payload, null, 2) + "\n")
|
|
575
|
+
// return
|
|
576
|
+
// }
|
|
577
|
+
//
|
|
578
|
+
// process.stdout.write(`${chalk.bold(payload.name)} ${payload.status === "connected" ? chalk.green("connected") : chalk.dim("not connected")}\n`)
|
|
579
|
+
// process.stdout.write(`Installation: ${payload.installationType}\n\n`)
|
|
580
|
+
// if (payload.installationType === "form") {
|
|
581
|
+
// process.stdout.write("Fields:\n")
|
|
582
|
+
// for (const field of payload.fields as FormFieldDefinition[]) {
|
|
583
|
+
// const req = field.required ? chalk.yellow(" (required)") : chalk.dim(" (optional)")
|
|
584
|
+
// const hint = field.hint ? ` — ${field.hint}` : ""
|
|
585
|
+
// process.stdout.write(` ${chalk.cyan(field.name)} [${field.type}]${req}${chalk.dim(hint)}\n`)
|
|
586
|
+
// }
|
|
587
|
+
// if (payload.setup) {
|
|
588
|
+
// process.stdout.write(`\n${chalk.yellow(payload.setup.title)}\n`)
|
|
589
|
+
// process.stdout.write(`${chalk.cyan(payload.setup.url)}\n`)
|
|
590
|
+
// for (const instruction of payload.setup.instructions) {
|
|
591
|
+
// process.stdout.write(` ${chalk.dim("•")} ${instruction}\n`)
|
|
592
|
+
// }
|
|
593
|
+
// }
|
|
594
|
+
// } else {
|
|
595
|
+
// process.stdout.write("OAuth — use `terse integrate connect <type>` in an interactive terminal, or open the auth URL manually and poll with `terse integrate wait`.\n")
|
|
596
|
+
// }
|
|
597
|
+
// printToolSummary(payload.tools)
|
|
598
|
+
// }
|
|
599
|
+
//
|
|
600
|
+
// export async function integrateTool(opts: IntegrateToolOpts): Promise<void> {
|
|
601
|
+
// const type = parseIntegrationTypeOrThrow(opts.integrationType)
|
|
602
|
+
// const apiKey = readApiKeyOrBail()
|
|
603
|
+
//
|
|
604
|
+
// const catalog = await fetchToolDetails(apiKey)
|
|
605
|
+
// const tools = catalog.filter(tool => tool.integration === type)
|
|
606
|
+
//
|
|
607
|
+
// if (opts.toolName === undefined) {
|
|
608
|
+
// printToolList(type, tools, opts.json)
|
|
609
|
+
// return
|
|
610
|
+
// }
|
|
611
|
+
//
|
|
612
|
+
// const match = tools.find(tool => tool.name === opts.toolName)
|
|
613
|
+
// if (!match) {
|
|
614
|
+
// throw new CliError("unknown_tool", `Unknown tool '${opts.toolName}' for integration '${type}'.`, {
|
|
615
|
+
// detail: tools.length > 0 ? `Available tools: ${tools.map(tool => tool.name).join(", ")}` : `Integration '${type}' exposes no tools.`
|
|
616
|
+
// })
|
|
617
|
+
// }
|
|
618
|
+
//
|
|
619
|
+
// if (opts.json) {
|
|
620
|
+
// process.stdout.write(JSON.stringify(match, null, 2) + "\n")
|
|
621
|
+
// return
|
|
622
|
+
// }
|
|
623
|
+
//
|
|
624
|
+
// printToolDetails(match)
|
|
625
|
+
// }
|
|
626
|
+
//
|
|
627
|
+
// function printToolList(type: IntegrationType, tools: ToolDetails[], json: boolean | undefined): void {
|
|
628
|
+
// if (json) {
|
|
629
|
+
// process.stdout.write(JSON.stringify({ type, tools: tools.map(toToolSummary) }, null, 2) + "\n")
|
|
630
|
+
// return
|
|
631
|
+
// }
|
|
632
|
+
//
|
|
633
|
+
// if (tools.length === 0) {
|
|
634
|
+
// process.stdout.write(`Integration '${type}' exposes no tools.\n`)
|
|
635
|
+
// return
|
|
636
|
+
// }
|
|
637
|
+
//
|
|
638
|
+
// process.stdout.write("Tools:\n")
|
|
639
|
+
// for (const tool of tools) {
|
|
640
|
+
// const readOnly = tool.isReadOnly ? chalk.dim(" (read-only)") : chalk.dim(" (write)")
|
|
641
|
+
// process.stdout.write(` ${chalk.cyan(tool.name)}${readOnly} — ${tool.description}\n`)
|
|
642
|
+
// }
|
|
643
|
+
// process.stdout.write(chalk.dim(`\nRun \`terse integrate tool ${type} <tool-name> --json\` for a tool's input/output schemas.\n`))
|
|
644
|
+
// }
|
|
645
|
+
//
|
|
646
|
+
// function printToolDetails(tool: ToolDetails): void {
|
|
647
|
+
// const readOnly = tool.isReadOnly ? chalk.dim(" (read-only)") : chalk.dim(" (write)")
|
|
648
|
+
// process.stdout.write(`${chalk.bold(tool.displayName)} ${chalk.dim(`[${tool.name}]`)}${readOnly}\n`)
|
|
649
|
+
// process.stdout.write(`Integration: ${tool.integration}\n`)
|
|
650
|
+
// process.stdout.write(`Supports approval: ${tool.supportsApproval ? "yes" : "no"}\n\n`)
|
|
651
|
+
// process.stdout.write(`${tool.description}\n`)
|
|
652
|
+
// process.stdout.write(`\nInput schema:\n${formatToolSchema(tool.inputSchema)}\n`)
|
|
653
|
+
// process.stdout.write(`\nOutput schema:\n${formatToolSchema(tool.outputSchema)}\n`)
|
|
654
|
+
// }
|
|
655
|
+
//
|
|
656
|
+
// function formatToolSchema(schema: unknown): string {
|
|
657
|
+
// if (schema === null) return chalk.dim(" (not available in this CLI version — update terse-cli)")
|
|
658
|
+
// return JSON.stringify(schema, null, 2)
|
|
659
|
+
// }
|
|
660
|
+
//
|
|
661
|
+
// function toToolSummary(tool: ToolDetails): ToolSummary {
|
|
662
|
+
// return {
|
|
663
|
+
// name: tool.name,
|
|
664
|
+
// displayName: tool.displayName,
|
|
665
|
+
// description: tool.description,
|
|
666
|
+
// isReadOnly: tool.isReadOnly,
|
|
667
|
+
// supportsApproval: tool.supportsApproval
|
|
668
|
+
// }
|
|
669
|
+
// }
|
|
670
|
+
//
|
|
671
|
+
// function printToolSummary(tools: ToolSummary[] | null): void {
|
|
672
|
+
// if (tools === null) {
|
|
673
|
+
// process.stdout.write(chalk.dim("\nTools: unavailable (tool definitions could not be fetched)\n"))
|
|
674
|
+
// return
|
|
675
|
+
// }
|
|
676
|
+
// if (tools.length === 0) return
|
|
677
|
+
//
|
|
678
|
+
// process.stdout.write("\nTools:\n")
|
|
679
|
+
// for (const tool of tools) {
|
|
680
|
+
// const readOnly = tool.isReadOnly ? chalk.dim(" (read-only)") : ""
|
|
681
|
+
// process.stdout.write(` ${chalk.cyan(tool.name)}${readOnly} — ${tool.description}\n`)
|
|
682
|
+
// }
|
|
683
|
+
// process.stdout.write(chalk.dim("\nRun `terse integrate tool <type> <tool-name> --json` for a tool's input/output schemas.\n"))
|
|
684
|
+
// }
|
|
685
|
+
//
|
|
686
|
+
// async function collectRawFields(opts: Pick<IntegrateConnectOpts, "fieldFlags" | "fieldsStdin">): Promise<Record<string, string>> {
|
|
687
|
+
// const fromFlags = parseKeyValueFlags(opts.fieldFlags)
|
|
688
|
+
// const fromStdin = opts.fieldsStdin ? await readFieldsFromStdin() : {}
|
|
689
|
+
// return { ...fromFlags, ...fromStdin }
|
|
690
|
+
// }
|
|
691
|
+
//
|
|
692
|
+
// function validateFormFields(type: IntegrationType, declaredFields: FormFieldDefinition[], provided: Record<string, string>): Record<string, string> {
|
|
693
|
+
// const knownFieldNames = new Set(declaredFields.map(f => f.name))
|
|
694
|
+
// const unknown = Object.keys(provided).filter(name => !knownFieldNames.has(name))
|
|
695
|
+
// if (unknown.length > 0) {
|
|
696
|
+
// throw new CliError("unknown_fields", `Unknown field(s): ${unknown.join(", ")}`, {
|
|
697
|
+
// detail: `Valid fields: ${declaredFields.map(f => f.name).join(", ") || "(none)"}`
|
|
698
|
+
// })
|
|
699
|
+
// }
|
|
700
|
+
//
|
|
701
|
+
// const missing = declaredFields.filter(f => f.required && !provided[f.name]).map(f => f.name)
|
|
702
|
+
// if (missing.length > 0) {
|
|
703
|
+
// throw new CliError("missing_fields", `Missing required field(s): ${missing.join(", ")}`, {
|
|
704
|
+
// detail: `Run \`terse integrate describe ${type} --json\` to see the full field schema.`
|
|
705
|
+
// })
|
|
706
|
+
// }
|
|
707
|
+
//
|
|
708
|
+
// return provided
|
|
709
|
+
// }
|
|
710
|
+
//
|
|
711
|
+
// export async function integrateConnect(opts: IntegrateConnectOpts): Promise<void> {
|
|
712
|
+
// const type = parseIntegrationTypeOrThrow(opts.integrationType)
|
|
713
|
+
// const apiKey = readApiKeyOrBail()
|
|
714
|
+
//
|
|
715
|
+
// const [integrations, fieldsResponse] = await Promise.all([fetchIntegrations(apiKey), fetchIntegrationFields(apiKey, type)])
|
|
716
|
+
// const existing = integrations.find(i => i.integrationType === type)
|
|
717
|
+
//
|
|
718
|
+
// if (existing?.isActive && !opts.force) {
|
|
719
|
+
// const message = `${INTEGRATION_METADATA[type]?.name ?? type} is already connected. Pass --force to refresh.`
|
|
720
|
+
// if (opts.json) {
|
|
721
|
+
// process.stdout.write(JSON.stringify({ type, status: "connected", changed: false, message }, null, 2) + "\n")
|
|
722
|
+
// } else {
|
|
723
|
+
// process.stdout.write(chalk.dim(message) + "\n")
|
|
724
|
+
// }
|
|
725
|
+
// return
|
|
726
|
+
// }
|
|
727
|
+
//
|
|
728
|
+
// const raw = await collectRawFields(opts)
|
|
729
|
+
//
|
|
730
|
+
// if (fieldsResponse.installationType === "oauth") {
|
|
731
|
+
// const optionsSchema = InstallationOptionsSchemas[type]
|
|
732
|
+
// const parsed = coerceAndValidateForSchema(raw, optionsSchema, { integrationType: type })
|
|
733
|
+
// const optionsArg = Object.keys(parsed as Record<string, unknown>).length > 0 ? (parsed as Record<string, unknown>) : undefined
|
|
734
|
+
//
|
|
735
|
+
// const installation = await fetchInstallationUrl(apiKey, type, optionsArg)
|
|
736
|
+
// openUrlInBrowser(installation.oauthUrl)
|
|
737
|
+
//
|
|
738
|
+
// const waitCommand = `terse integrate wait ${type}`
|
|
739
|
+
//
|
|
740
|
+
// if (opts.json) {
|
|
741
|
+
// const payload = {
|
|
742
|
+
// handoff: "oauth",
|
|
743
|
+
// type,
|
|
744
|
+
// status: "disconnected" as const,
|
|
745
|
+
// url: installation.oauthUrl,
|
|
746
|
+
// waitCommand,
|
|
747
|
+
// message: `Browser opened. Run \`${waitCommand}\` to block until authorization completes.`
|
|
748
|
+
// }
|
|
749
|
+
// process.stdout.write(JSON.stringify(payload, null, 2) + "\n")
|
|
750
|
+
// process.exitCode = 2
|
|
751
|
+
// return
|
|
752
|
+
// }
|
|
753
|
+
//
|
|
754
|
+
// const name = INTEGRATION_METADATA[type]?.name ?? type
|
|
755
|
+
// process.stdout.write(chalk.yellow(`ACTION REQUIRED: authorize ${name} in your browser.`) + "\n")
|
|
756
|
+
// process.stdout.write(chalk.cyan(` ${installation.oauthUrl}`) + "\n")
|
|
757
|
+
// process.stdout.write(chalk.dim(` Browser opened. Run \`${waitCommand}\` to block until authorization completes.`) + "\n")
|
|
758
|
+
// process.exitCode = 2
|
|
759
|
+
// return
|
|
760
|
+
// }
|
|
761
|
+
//
|
|
762
|
+
// const declaredFields = (fieldsResponse.fields ?? []) as FormFieldDefinition[]
|
|
763
|
+
// const provided = validateFormFields(type, declaredFields, raw)
|
|
764
|
+
// const result = await submitIntegrationForm(apiKey, type, provided)
|
|
765
|
+
// if (!result.success) {
|
|
766
|
+
// throw new CliError("connect_failed", result.error ?? "Failed to connect integration.")
|
|
767
|
+
// }
|
|
768
|
+
//
|
|
769
|
+
// const message = existing?.isActive ? `${type} refreshed.` : `${type} connected.`
|
|
770
|
+
// if (opts.json) {
|
|
771
|
+
// process.stdout.write(JSON.stringify({ type, status: "connected", changed: true, message }, null, 2) + "\n")
|
|
772
|
+
// } else {
|
|
773
|
+
// process.stdout.write(chalk.green(message) + "\n")
|
|
774
|
+
// }
|
|
775
|
+
// }
|
|
776
|
+
//
|
|
777
|
+
// export async function integrateDisconnect(opts: IntegrateDisconnectOpts): Promise<void> {
|
|
778
|
+
// const type = parseIntegrationTypeOrThrow(opts.integrationType)
|
|
779
|
+
// const apiKey = readApiKeyOrBail()
|
|
780
|
+
//
|
|
781
|
+
// const result = await disconnectIntegration(apiKey, type)
|
|
782
|
+
// if (!result.success) {
|
|
783
|
+
// throw new CliError("disconnect_failed", result.error ?? "Failed to disconnect integration.")
|
|
784
|
+
// }
|
|
785
|
+
//
|
|
786
|
+
// const message = `${type} disconnected.`
|
|
787
|
+
// if (opts.json) {
|
|
788
|
+
// process.stdout.write(JSON.stringify({ type, status: "disconnected", changed: true, message }, null, 2) + "\n")
|
|
789
|
+
// } else {
|
|
790
|
+
// process.stdout.write(chalk.green(message) + "\n")
|
|
791
|
+
// }
|
|
792
|
+
// }
|
|
793
|
+
//
|
|
794
|
+
// const WAIT_DEFAULT_TIMEOUT_S = 300
|
|
795
|
+
// const WAIT_MAX_TIMEOUT_S = 900
|
|
796
|
+
// const WAIT_INTERVAL_MS = 2000
|
|
797
|
+
//
|
|
798
|
+
// export async function integrateWait(opts: IntegrateWaitOpts): Promise<void> {
|
|
799
|
+
// const type = parseIntegrationTypeOrThrow(opts.integrationType)
|
|
800
|
+
// const requested = opts.timeoutSeconds ?? WAIT_DEFAULT_TIMEOUT_S
|
|
801
|
+
// const timeoutSeconds = Math.max(1, Math.min(WAIT_MAX_TIMEOUT_S, requested))
|
|
802
|
+
// const apiKey = readApiKeyOrBail()
|
|
803
|
+
//
|
|
804
|
+
// const deadline = Date.now() + timeoutSeconds * 1000
|
|
805
|
+
// let lastError: string | null = null
|
|
806
|
+
//
|
|
807
|
+
// while (Date.now() < deadline) {
|
|
808
|
+
// try {
|
|
809
|
+
// const integrations = await fetchIntegrations(apiKey)
|
|
810
|
+
// const match = integrations.find(i => i.integrationType === type)
|
|
811
|
+
// if (match?.isActive) {
|
|
812
|
+
// const message = `${type} is connected.`
|
|
813
|
+
// if (opts.json) {
|
|
814
|
+
// process.stdout.write(JSON.stringify({ type, status: "connected", message }, null, 2) + "\n")
|
|
815
|
+
// } else {
|
|
816
|
+
// process.stdout.write(chalk.green(message) + "\n")
|
|
817
|
+
// }
|
|
818
|
+
// return
|
|
819
|
+
// }
|
|
820
|
+
// } catch (err) {
|
|
821
|
+
// lastError = err instanceof Error ? err.message : String(err)
|
|
822
|
+
// }
|
|
823
|
+
// await new Promise(resolve => setTimeout(resolve, WAIT_INTERVAL_MS))
|
|
824
|
+
// }
|
|
825
|
+
//
|
|
826
|
+
// throw new CliError("wait_timeout", `Timed out after ${timeoutSeconds}s waiting for ${type} to connect.`, {
|
|
827
|
+
// detail: lastError ? `Last error: ${lastError}` : "Check the integration's connection status with `terse integrate list`."
|
|
828
|
+
// })
|
|
829
|
+
// }
|
|
830
|
+
//
|
|
831
|
+
// // Types
|
|
832
|
+
//
|
|
833
|
+
// type IntegrationChangeResult = {
|
|
834
|
+
// status: "added" | "modified" | "skipped" | "unchanged"
|
|
835
|
+
// integrationType?: IntegrationType
|
|
836
|
+
// }
|
|
837
|
+
//
|
|
838
|
+
// type IntegrateOptions = {
|
|
839
|
+
// /** When set (e.g. during `terse attach`), all integration calls use this key instead of `readApiKey()`. */
|
|
840
|
+
// apiKey?: string
|
|
841
|
+
// showLifecycle?: boolean
|
|
842
|
+
// runGenerateAfterChange?: boolean
|
|
843
|
+
// nonInteractive?: boolean
|
|
844
|
+
// }
|
|
845
|
+
//
|
|
846
|
+
// type IntegrationAction = "back" | "connect" | "disconnect" | "keep" | "refresh_permissions"
|
|
847
|
+
//
|
|
848
|
+
// type GroupedIntegrationSelection = { action: IntegrationAction; integrationType: IntegrationType } | { action: typeof SKIP_VALUE; integrationType: typeof SKIP_VALUE }
|
|
849
|
+
//
|
|
850
|
+
// type PinState = "ok" | "missing"
|
|
851
|
+
//
|
|
852
|
+
// type PinAwareIntegration = IntegrationWithStatus & { pin?: PinState }
|
|
853
|
+
//
|
|
854
|
+
// type UserFacingIntegration = PinAwareIntegration
|
|
855
|
+
//
|
|
856
|
+
// export type IntegrateListOpts = {
|
|
857
|
+
// json?: boolean
|
|
858
|
+
// status?: "connected" | "disconnected"
|
|
859
|
+
// }
|
|
860
|
+
//
|
|
861
|
+
// export type IntegrateDescribeOpts = {
|
|
862
|
+
// integrationType: string
|
|
863
|
+
// json?: boolean
|
|
864
|
+
// }
|
|
865
|
+
//
|
|
866
|
+
// export type IntegrateToolOpts = {
|
|
867
|
+
// integrationType: string
|
|
868
|
+
// toolName?: string
|
|
869
|
+
// json?: boolean
|
|
870
|
+
// }
|
|
871
|
+
//
|
|
872
|
+
// type ToolSummary = {
|
|
873
|
+
// name: string
|
|
874
|
+
// displayName: string
|
|
875
|
+
// description: string
|
|
876
|
+
// isReadOnly: boolean
|
|
877
|
+
// supportsApproval: boolean
|
|
878
|
+
// }
|
|
879
|
+
//
|
|
880
|
+
// export type IntegrateConnectOpts = {
|
|
881
|
+
// integrationType: string
|
|
882
|
+
// fieldFlags?: string[]
|
|
883
|
+
// fieldsStdin?: boolean
|
|
884
|
+
// force?: boolean
|
|
885
|
+
// json?: boolean
|
|
886
|
+
// }
|
|
887
|
+
//
|
|
888
|
+
// export type IntegrateDisconnectOpts = {
|
|
889
|
+
// integrationType: string
|
|
890
|
+
// json?: boolean
|
|
891
|
+
// }
|
|
892
|
+
//
|
|
893
|
+
// export type IntegrateWaitOpts = {
|
|
894
|
+
// integrationType: string
|
|
895
|
+
// timeoutSeconds?: number
|
|
896
|
+
// json?: boolean
|
|
897
|
+
// }
|
|
700
898
|
//# sourceMappingURL=integrate.js.map
|