terse-cli 0.9.20 → 0.9.22
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 +1 -1
- 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/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/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +86 -28
- package/dist/commands/init.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 +2 -0
- 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 +115 -121
- 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/dist/templates.d.ts +6 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +78 -0
- package/dist/templates.js.map +1 -0
- package/package.json +3 -4
- package/templates/typescript/init/package.json.hbs +1 -2
package/dist/commands/test.js
CHANGED
|
@@ -1,404 +1,510 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
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
|
-
function
|
|
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
|
-
|
|
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, intro, isCancel, log, outro, select } from "@clack/prompts"
|
|
4
|
+
// import chalk from "chalk"
|
|
5
|
+
// import { DateTime } from "luxon"
|
|
6
|
+
// import fs from "node:fs"
|
|
7
|
+
// import type { CreateJobParameters } from "terse-sdk"
|
|
8
|
+
// import { IntegrationType } from "terse-sdk"
|
|
9
|
+
// import { ApiRoutes, hydrateSerializedEvent, toEventFixture } from "terse-types"
|
|
10
|
+
// import type { RunHistoryAction, SdkSampleEventsResponse, SerializedEvent } from "terse-types"
|
|
11
|
+
//
|
|
12
|
+
// import { fetchWithAuth, readApiKeyOrBail } from "../api.js"
|
|
13
|
+
// import { assertProjectRoot } from "../assertProjectRoot.js"
|
|
14
|
+
// import { CliError } from "../cliError.js"
|
|
15
|
+
// import { isNonInteractive } from "../cliHelpers.js"
|
|
16
|
+
// import { createRunIndicator, createSpinner, interceptConsole } from "../cliUi.js"
|
|
17
|
+
// import { parseEventFixtureJson } from "../eventFixture.js"
|
|
18
|
+
// import { loadJob } from "../loadJob.js"
|
|
19
|
+
// import { readProjectConfig, readProjectConfigOrBail } from "../projectConfig.js"
|
|
20
|
+
// import type { LanguageProvider } from "../providers/LanguageProvider.js"
|
|
21
|
+
// import { resolveProvider } from "../providers/resolveProvider.js"
|
|
22
|
+
// import { remoteDispatchNotice, runLocalTestJob } from "../runLocalTestJob.js"
|
|
23
|
+
// import { parseSerializedEventJson } from "../serializedEvent.js"
|
|
24
|
+
//
|
|
25
|
+
// export async function test(jobName?: string, verbose?: boolean, provider: LanguageProvider = resolveProvider(), entryFile?: string, freshState?: boolean): Promise<void> {
|
|
26
|
+
// if (isNonInteractive()) {
|
|
27
|
+
// throw new CliError("test_requires_interactive", "`terse test` needs a terminal.", {
|
|
28
|
+
// detail: "In non-interactive contexts, use `terse test list` to enumerate sample events and `terse test run --id <id>` to execute one."
|
|
29
|
+
// })
|
|
30
|
+
// }
|
|
31
|
+
//
|
|
32
|
+
// intro("terse test")
|
|
33
|
+
// assertProjectRoot(provider)
|
|
34
|
+
//
|
|
35
|
+
// const { job } = await loadJob(provider, jobName, entryFile)
|
|
36
|
+
//
|
|
37
|
+
// const apiKey = readApiKeyOrBail({
|
|
38
|
+
// title: "Error: Not authenticated. Unable to fetch sample events.",
|
|
39
|
+
// detail: "Run `terse auth login` to authenticate, or set TERSE_API_KEY in your environment."
|
|
40
|
+
// })
|
|
41
|
+
//
|
|
42
|
+
// const spinner = createSpinner()
|
|
43
|
+
// spinner.start("Fetching sample events")
|
|
44
|
+
// let candidates: SampleEventCandidate[] = []
|
|
45
|
+
// let webhookEndpoints: SampleEventCandidatesResult["webhookEndpoints"] = []
|
|
46
|
+
// try {
|
|
47
|
+
// const result = await fetchSampleEventCandidatesForJob(job, apiKey)
|
|
48
|
+
// candidates = result.candidates
|
|
49
|
+
// webhookEndpoints = result.webhookEndpoints
|
|
50
|
+
// spinner.stop(`Fetched ${candidates.length} sample event${candidates.length === 1 ? "" : "s"}`)
|
|
51
|
+
// } catch (err) {
|
|
52
|
+
// spinner.stop(err instanceof Error ? err.message : "Failed to fetch sample events.")
|
|
53
|
+
// }
|
|
54
|
+
//
|
|
55
|
+
// if (candidates.length === 0) {
|
|
56
|
+
// if (webhookEndpoints.length > 0) {
|
|
57
|
+
// log.info(emptyWebhookCurlHint(job.name, webhookEndpoints))
|
|
58
|
+
// outro("Done")
|
|
59
|
+
// return
|
|
60
|
+
// }
|
|
61
|
+
// throw new CliError("no_sample_events", "No sample events available.", {
|
|
62
|
+
// detail: "Make sure your triggers are configured and events have been received."
|
|
63
|
+
// })
|
|
64
|
+
// }
|
|
65
|
+
//
|
|
66
|
+
// log.info(`Testing job ${chalk.cyan(job.name)} on the ${chalk.cyan(provider.runtimeName(job))} runtime`)
|
|
67
|
+
//
|
|
68
|
+
// const event = await chooseSampleEvent(candidates, apiKey)
|
|
69
|
+
//
|
|
70
|
+
// const projectId = readProjectConfigOrBail().projectId
|
|
71
|
+
// const runView = createRunIndicator(`Running ${formatEventLabel(event)}`)
|
|
72
|
+
// const restoreConsole = interceptConsole(line => runView.logLine(line))
|
|
73
|
+
// runView.start()
|
|
74
|
+
// try {
|
|
75
|
+
// const { runId, local } = await runLocalTestJob(provider, job, event, {
|
|
76
|
+
// projectId,
|
|
77
|
+
// apiKey,
|
|
78
|
+
// verbose: !!verbose,
|
|
79
|
+
// entryFile,
|
|
80
|
+
// freshState,
|
|
81
|
+
// pauseUiAround: async fn => {
|
|
82
|
+
// runView.pause("Awaiting input")
|
|
83
|
+
// try {
|
|
84
|
+
// return await fn()
|
|
85
|
+
// } finally {
|
|
86
|
+
// runView.start()
|
|
87
|
+
// }
|
|
88
|
+
// }
|
|
89
|
+
// })
|
|
90
|
+
// restoreConsole()
|
|
91
|
+
// if (local) runView.succeed("Run completed")
|
|
92
|
+
// else runView.succeed(remoteDispatchNotice(runId))
|
|
93
|
+
// outro("Done")
|
|
94
|
+
// } catch (error) {
|
|
95
|
+
// restoreConsole()
|
|
96
|
+
// runView.fail("Run failed")
|
|
97
|
+
// throw error
|
|
98
|
+
// }
|
|
99
|
+
// }
|
|
100
|
+
//
|
|
101
|
+
// export async function testList(opts: TestListOpts = {}): Promise<void> {
|
|
102
|
+
// const provider = opts.provider ?? resolveProvider()
|
|
103
|
+
// assertProjectRoot(provider)
|
|
104
|
+
//
|
|
105
|
+
// const { job } = await loadJob(provider, opts.jobName, opts.entryFile, { nonInteractive: true })
|
|
106
|
+
// const apiKey = readApiKeyOrBail()
|
|
107
|
+
//
|
|
108
|
+
// const { candidates, webhookEndpoints } = await fetchSampleEventCandidatesForJob(job, apiKey)
|
|
109
|
+
//
|
|
110
|
+
// if (opts.json) {
|
|
111
|
+
// const payload = {
|
|
112
|
+
// job: job.name,
|
|
113
|
+
// events: candidates.map(candidate => ({
|
|
114
|
+
// id: candidate.id,
|
|
115
|
+
// integrationType: candidate.integrationType,
|
|
116
|
+
// eventType: candidate.eventType,
|
|
117
|
+
// label: candidate.label,
|
|
118
|
+
// subtitle: candidate.subtitle,
|
|
119
|
+
// entityType: candidate.kind === "ref" ? candidate.entityType : null,
|
|
120
|
+
// entityId: candidate.kind === "ref" ? candidate.entityId : null
|
|
121
|
+
// })),
|
|
122
|
+
// webhookEndpoints
|
|
123
|
+
// }
|
|
124
|
+
// process.stdout.write(JSON.stringify(payload, null, 2) + "\n")
|
|
125
|
+
// return
|
|
126
|
+
// }
|
|
127
|
+
//
|
|
128
|
+
// if (candidates.length === 0) {
|
|
129
|
+
// if (webhookEndpoints.length > 0) {
|
|
130
|
+
// process.stdout.write(emptyWebhookCurlHint(job.name, webhookEndpoints) + "\n")
|
|
131
|
+
// } else {
|
|
132
|
+
// process.stdout.write("No sample events available.\n")
|
|
133
|
+
// }
|
|
134
|
+
// return
|
|
135
|
+
// }
|
|
136
|
+
//
|
|
137
|
+
// process.stdout.write(`Sample events for job ${job.name}:\n\n`)
|
|
138
|
+
// for (const candidate of candidates) {
|
|
139
|
+
// const subtitle = candidate.subtitle ? ` — ${normalizeSingleLine(candidate.subtitle)}` : ""
|
|
140
|
+
// process.stdout.write(` ${chalk.cyan(candidate.id)} ${candidate.integrationType}/${candidate.eventType} ${candidate.label}${chalk.dim(subtitle)}\n`)
|
|
141
|
+
// }
|
|
142
|
+
// process.stdout.write("\n")
|
|
143
|
+
// process.stdout.write(chalk.dim(`Run one with: terse test run --id <id>\n`))
|
|
144
|
+
// }
|
|
145
|
+
//
|
|
146
|
+
// export async function testShow(opts: TestShowOpts): Promise<void> {
|
|
147
|
+
// const provider = opts.provider ?? resolveProvider()
|
|
148
|
+
// assertProjectRoot(provider)
|
|
149
|
+
//
|
|
150
|
+
// const event = await resolveEventById(provider, opts.id, opts.jobName, opts.entryFile)
|
|
151
|
+
//
|
|
152
|
+
// if (opts.json) {
|
|
153
|
+
// process.stdout.write(JSON.stringify({ id: opts.id, event: toEventFixture(event) }, null, 2) + "\n")
|
|
154
|
+
// return
|
|
155
|
+
// }
|
|
156
|
+
//
|
|
157
|
+
// process.stdout.write(`${chalk.bold(formatEventLabel(event))}\n`)
|
|
158
|
+
// if (event.display?.subtitle) process.stdout.write(chalk.dim(event.display.subtitle) + "\n")
|
|
159
|
+
// process.stdout.write(`\n${event.formattedContent}\n`)
|
|
160
|
+
// }
|
|
161
|
+
//
|
|
162
|
+
// export async function testRun(opts: TestRunOpts): Promise<void> {
|
|
163
|
+
// const provider = opts.provider ?? resolveProvider()
|
|
164
|
+
// assertProjectRoot(provider)
|
|
165
|
+
//
|
|
166
|
+
// const modeCount = [opts.id, opts.eventJson, opts.eventFile].filter(Boolean).length
|
|
167
|
+
// if (modeCount === 0) {
|
|
168
|
+
// throw new CliError("missing_event", "Provide one of --id, --event, or --event-file.", {
|
|
169
|
+
// detail: "Run `terse test list --json` to see available sample ids."
|
|
170
|
+
// })
|
|
171
|
+
// }
|
|
172
|
+
// if (modeCount > 1) {
|
|
173
|
+
// throw new CliError("conflicting_flags", "--id, --event, and --event-file are mutually exclusive.")
|
|
174
|
+
// }
|
|
175
|
+
//
|
|
176
|
+
// const { job } = await loadJob(provider, opts.jobName, opts.entryFile, { nonInteractive: true })
|
|
177
|
+
//
|
|
178
|
+
// let event: SerializedEvent
|
|
179
|
+
// if (opts.id) {
|
|
180
|
+
// event = await resolveEventByIdForJob(job, opts.id)
|
|
181
|
+
// } else {
|
|
182
|
+
// const rawJson = opts.eventJson ?? readEventFile(opts.eventFile!)
|
|
183
|
+
// event = parseEventFixtureJson(rawJson, "--event / --event-file")
|
|
184
|
+
// }
|
|
185
|
+
//
|
|
186
|
+
// const apiKey = readApiKeyOrBail()
|
|
187
|
+
// const projectId = readProjectConfigOrBail().projectId
|
|
188
|
+
// const sideEffects: RunHistoryAction[] = []
|
|
189
|
+
// try {
|
|
190
|
+
// const { runId, local } = await runLocalTestJob(provider, job, event, {
|
|
191
|
+
// projectId,
|
|
192
|
+
// apiKey,
|
|
193
|
+
// verbose: !!opts.verbose,
|
|
194
|
+
// entryFile: opts.entryFile,
|
|
195
|
+
// freshState: opts.freshState,
|
|
196
|
+
// onSessionEvent: sessionEvent => {
|
|
197
|
+
// if (sessionEvent.type === "action" && isSideEffect(sessionEvent.action)) sideEffects.push(sessionEvent.action)
|
|
198
|
+
// }
|
|
199
|
+
// })
|
|
200
|
+
// if (!local) console.log(chalk.cyan(` ${remoteDispatchNotice(runId)}`))
|
|
201
|
+
// if (isNonInteractive()) printAgentTestReport(job.name, local ? "passed" : "dispatched", sideEffects)
|
|
202
|
+
// } catch (error) {
|
|
203
|
+
// if (isNonInteractive()) printAgentTestReport(job.name, "failed", sideEffects, error)
|
|
204
|
+
// throw error
|
|
205
|
+
// }
|
|
206
|
+
// }
|
|
207
|
+
//
|
|
208
|
+
// function isSideEffect(action: RunHistoryAction): boolean {
|
|
209
|
+
// return action.type === "create" || action.type === "update" || action.type === "delete" || action.type === "approve"
|
|
210
|
+
// }
|
|
211
|
+
//
|
|
212
|
+
// function printAgentTestReport(jobName: string, result: "passed" | "failed" | "dispatched", sideEffects: RunHistoryAction[], error?: unknown): void {
|
|
213
|
+
// const lines = ["--- TERSE TEST REPORT: surface this to the user ---", `Tested: ${jobName}`, `Result: ${result}`]
|
|
214
|
+
// if (sideEffects.length > 0) {
|
|
215
|
+
// lines.push("Observed side effects:")
|
|
216
|
+
// for (const effect of sideEffects) lines.push(`- ${effect.action} — ${effect.details}${effect.url ? ` (${effect.url})` : ""}`)
|
|
217
|
+
// }
|
|
218
|
+
// if (error instanceof CliError) lines.push(`Error: ${error.message}${error.opts.detail ? ` — ${normalizeSingleLine(error.opts.detail)}` : ""}`)
|
|
219
|
+
// else if (error instanceof Error) lines.push(`Error: ${error.message}`)
|
|
220
|
+
// lines.push(
|
|
221
|
+
// 'CODING AGENT: Your first sentence after this command must be either "The test ran as expected" or "The test did not run as expected." Then list the observed side effects exactly and explain any mismatch with the expectation you stated before the run.'
|
|
222
|
+
// )
|
|
223
|
+
// process.stdout.write(`\n${lines.join("\n")}\n`)
|
|
224
|
+
// }
|
|
225
|
+
//
|
|
226
|
+
// async function resolveEventById(provider: LanguageProvider, id: string, jobNameHint: string | undefined, entryFile: string | undefined): Promise<SerializedEvent> {
|
|
227
|
+
// const { job } = await loadJob(provider, jobNameHint, entryFile, { nonInteractive: true })
|
|
228
|
+
// return resolveEventByIdForJob(job, id)
|
|
229
|
+
// }
|
|
230
|
+
//
|
|
231
|
+
// async function resolveEventByIdForJob(job: CreateJobParameters, id: string): Promise<SerializedEvent> {
|
|
232
|
+
// const apiKey = readApiKeyOrBail()
|
|
233
|
+
// const { candidates } = await fetchSampleEventCandidatesForJob(job, apiKey)
|
|
234
|
+
// const match = candidates.find(candidate => candidate.id === id)
|
|
235
|
+
// if (match) return hydrateCandidateEvent(match, apiKey)
|
|
236
|
+
//
|
|
237
|
+
// throw new CliError("sample_not_found", `No sample event matches id ${id}.`, {
|
|
238
|
+
// detail: "Run `terse test list` to refresh — the event may have rotated out of the sample buffer."
|
|
239
|
+
// })
|
|
240
|
+
// }
|
|
241
|
+
//
|
|
242
|
+
// function readEventFile(filePath: string): string {
|
|
243
|
+
// try {
|
|
244
|
+
// return fs.readFileSync(filePath, "utf-8")
|
|
245
|
+
// } catch (err) {
|
|
246
|
+
// throw new CliError("event_file_unreadable", `Could not read event file: ${filePath}`, {
|
|
247
|
+
// detail: err instanceof Error ? err.message : String(err)
|
|
248
|
+
// })
|
|
249
|
+
// }
|
|
250
|
+
// }
|
|
251
|
+
//
|
|
252
|
+
// async function fetchSampleEventCandidatesForJob(job: CreateJobParameters, apiKey: string): Promise<SampleEventCandidatesResult> {
|
|
253
|
+
// const timeTriggers = job.triggers.filter(t => t.integrationType === IntegrationType.CRON_JOB)
|
|
254
|
+
// const sampleEventTriggers = job.triggers.filter(t => t.integrationType !== IntegrationType.CRON_JOB)
|
|
255
|
+
//
|
|
256
|
+
// const candidates: SampleEventCandidate[] = []
|
|
257
|
+
// const webhookEndpoints: NonNullable<SdkSampleEventsResponse["webhookEndpoints"]> = []
|
|
258
|
+
//
|
|
259
|
+
// if (sampleEventTriggers.length > 0) {
|
|
260
|
+
// const projectId = readProjectConfig()?.projectId
|
|
261
|
+
// const result = await fetchWithAuth<SdkSampleEventsResponse>(
|
|
262
|
+
// ApiRoutes.SDK.SAMPLE_EVENTS,
|
|
263
|
+
// apiKey,
|
|
264
|
+
// {
|
|
265
|
+
// projectId,
|
|
266
|
+
// jobName: job.name,
|
|
267
|
+
// triggers: sampleEventTriggers.map(trigger => ({
|
|
268
|
+
// triggerId: undefined,
|
|
269
|
+
// integrationId: trigger.integrationId,
|
|
270
|
+
// integrationType: trigger.integrationType,
|
|
271
|
+
// config: trigger
|
|
272
|
+
// }))
|
|
273
|
+
// },
|
|
274
|
+
// "POST"
|
|
275
|
+
// )
|
|
276
|
+
// let storedIndex = 0
|
|
277
|
+
// for (const event of result.events) {
|
|
278
|
+
// if (event.entity) {
|
|
279
|
+
// candidates.push({
|
|
280
|
+
// id: encodeRefId(event.entity.entityType, event.entity.entityId),
|
|
281
|
+
// kind: "ref",
|
|
282
|
+
// integrationType: event.serializedEvent.integrationType,
|
|
283
|
+
// eventType: event.serializedEvent.eventType,
|
|
284
|
+
// label: normalizeSingleLine(event.serializedEvent.display?.title || `${event.serializedEvent.integrationType} / ${event.serializedEvent.eventType}`),
|
|
285
|
+
// subtitle: event.serializedEvent.display?.subtitle ?? null,
|
|
286
|
+
// entityType: event.entity.entityType,
|
|
287
|
+
// entityId: event.entity.entityId
|
|
288
|
+
// })
|
|
289
|
+
// } else {
|
|
290
|
+
// const time = event.recordedAt ? (DateTime.fromISO(event.recordedAt).toRelative() ?? null) : null
|
|
291
|
+
// const method = event.serializedEvent.display?.subtitle ?? null
|
|
292
|
+
// const labelParts = [event.serializedEvent.integrationType === IntegrationType.WEBHOOK ? "Webhook" : event.serializedEvent.integrationType, method, time].filter(Boolean) as string[]
|
|
293
|
+
// candidates.push({
|
|
294
|
+
// id: `stored:${storedIndex++}`,
|
|
295
|
+
// kind: "stored",
|
|
296
|
+
// integrationType: event.serializedEvent.integrationType,
|
|
297
|
+
// eventType: event.serializedEvent.eventType,
|
|
298
|
+
// label: labelParts.join(" · "),
|
|
299
|
+
// subtitle: event.serializedEvent.display?.subtitle ?? null,
|
|
300
|
+
// recordedAt: event.recordedAt ?? null,
|
|
301
|
+
// event: event.serializedEvent
|
|
302
|
+
// })
|
|
303
|
+
// }
|
|
304
|
+
// }
|
|
305
|
+
// if (result.webhookEndpoints) webhookEndpoints.push(...result.webhookEndpoints)
|
|
306
|
+
// }
|
|
307
|
+
//
|
|
308
|
+
// for (const [index, trigger] of timeTriggers.entries()) {
|
|
309
|
+
// const event = hydrateSerializedEvent({
|
|
310
|
+
// integrationType: IntegrationType.CRON_JOB,
|
|
311
|
+
// eventType: "cron",
|
|
312
|
+
// inputId: trigger.integrationId,
|
|
313
|
+
// isManualTrigger: true,
|
|
314
|
+
// manualContext: `Manual trigger from terse test (schedule: ${trigger.cronExpression})`
|
|
315
|
+
// })
|
|
316
|
+
// candidates.push({
|
|
317
|
+
// id: `synthetic:cron:${index}`,
|
|
318
|
+
// kind: "synthetic",
|
|
319
|
+
// integrationType: event.integrationType,
|
|
320
|
+
// eventType: event.eventType,
|
|
321
|
+
// label: formatEventLabel(event),
|
|
322
|
+
// subtitle: event.display?.subtitle ?? null,
|
|
323
|
+
// event
|
|
324
|
+
// })
|
|
325
|
+
// }
|
|
326
|
+
//
|
|
327
|
+
// return { candidates, webhookEndpoints }
|
|
328
|
+
// }
|
|
329
|
+
//
|
|
330
|
+
// function formatEventLabel(event: SerializedEvent): string {
|
|
331
|
+
// return normalizeSingleLine(event.display?.title || `${event.integrationType} / ${event.eventType}`)
|
|
332
|
+
// }
|
|
333
|
+
//
|
|
334
|
+
// function formatEventHint(candidate: SampleEventCandidate): string {
|
|
335
|
+
// if (candidate.kind === "stored") {
|
|
336
|
+
// const preview = previewPayload(candidate.event)
|
|
337
|
+
// if (preview) return truncate(preview, 120)
|
|
338
|
+
// if (candidate.subtitle) return truncate(normalizeSingleLine(candidate.subtitle), 120)
|
|
339
|
+
// return truncate(`${candidate.integrationType}/${candidate.eventType}`, 120)
|
|
340
|
+
// }
|
|
341
|
+
// if (candidate.subtitle) return truncate(normalizeSingleLine(candidate.subtitle), 120)
|
|
342
|
+
// if (candidate.kind === "ref") return truncate(`${candidate.integrationType}/${candidate.eventType}`, 120)
|
|
343
|
+
// return "Synthetic sample event"
|
|
344
|
+
// }
|
|
345
|
+
//
|
|
346
|
+
// function previewPayload(event: SerializedEvent): string | null {
|
|
347
|
+
// const data = event.data as Record<string, unknown> | undefined
|
|
348
|
+
// const body = data && "body" in data ? data.body : data
|
|
349
|
+
// if (body == null) return null
|
|
350
|
+
// try {
|
|
351
|
+
// return normalizeSingleLine(JSON.stringify(body))
|
|
352
|
+
// } catch {
|
|
353
|
+
// return null
|
|
354
|
+
// }
|
|
355
|
+
// }
|
|
356
|
+
//
|
|
357
|
+
// function truncate(value: string, maxLength: number): string {
|
|
358
|
+
// if (value.length <= maxLength) {
|
|
359
|
+
// return value
|
|
360
|
+
// }
|
|
361
|
+
//
|
|
362
|
+
// return `${value.slice(0, maxLength - 1)}…`
|
|
363
|
+
// }
|
|
364
|
+
//
|
|
365
|
+
// function normalizeSingleLine(value: string): string {
|
|
366
|
+
// return value
|
|
367
|
+
// .replace(/\s*\n+\s*/g, " ")
|
|
368
|
+
// .replace(/\s+/g, " ")
|
|
369
|
+
// .trim()
|
|
370
|
+
// }
|
|
371
|
+
//
|
|
372
|
+
// function abortIfCancelled<T>(value: T | symbol): T {
|
|
373
|
+
// if (isCancel(value)) {
|
|
374
|
+
// cancel("Operation cancelled.")
|
|
375
|
+
// process.exit(0)
|
|
376
|
+
// }
|
|
377
|
+
//
|
|
378
|
+
// return value as T
|
|
379
|
+
// }
|
|
380
|
+
//
|
|
381
|
+
// async function chooseSampleEvent(candidates: SampleEventCandidate[], apiKey: string): Promise<SerializedEvent> {
|
|
382
|
+
// while (true) {
|
|
383
|
+
// const choice = abortIfCancelled(
|
|
384
|
+
// await select<number>({
|
|
385
|
+
// message: "Choose a sample event",
|
|
386
|
+
// options: candidates.map((candidate, index) => ({
|
|
387
|
+
// label: `${candidate.label} ${chalk.dim("›")}`,
|
|
388
|
+
// hint: formatEventHint(candidate),
|
|
389
|
+
// value: index
|
|
390
|
+
// }))
|
|
391
|
+
// })
|
|
392
|
+
// )
|
|
393
|
+
//
|
|
394
|
+
// const event = await hydrateCandidateEvent(candidates[choice], apiKey)
|
|
395
|
+
// const action = await inspectSampleEvent(event)
|
|
396
|
+
// if (action === "run") {
|
|
397
|
+
// return event
|
|
398
|
+
// }
|
|
399
|
+
// }
|
|
400
|
+
// }
|
|
401
|
+
//
|
|
402
|
+
// async function hydrateCandidateEvent(candidate: SampleEventCandidate, apiKey: string): Promise<SerializedEvent> {
|
|
403
|
+
// if (candidate.kind === "synthetic" || candidate.kind === "stored") {
|
|
404
|
+
// return candidate.event
|
|
405
|
+
// }
|
|
406
|
+
// const payload = await fetchWithAuth<{ event: SerializedEvent }>(ApiRoutes.SDK.HYDRATE_SAMPLE_EVENT, apiKey, { entityType: candidate.entityType, entityId: candidate.entityId }, "POST")
|
|
407
|
+
// return payload.event
|
|
408
|
+
// }
|
|
409
|
+
//
|
|
410
|
+
// function encodeRefId(entityType: string, entityId: string): string {
|
|
411
|
+
// const token = Buffer.from(JSON.stringify({ entityType, entityId }), "utf8").toString("base64url")
|
|
412
|
+
// return `ref:${token}`
|
|
413
|
+
// }
|
|
414
|
+
//
|
|
415
|
+
// function emptyWebhookCurlHint(jobName: string, endpoints: NonNullable<SdkSampleEventsResponse["webhookEndpoints"]>): string {
|
|
416
|
+
// const lines = [`No past webhook events for ${chalk.cyan(jobName)} yet. Trigger one with:`, ""]
|
|
417
|
+
// for (const { webhookUrl } of endpoints) {
|
|
418
|
+
// lines.push(` curl -X POST ${chalk.cyan(webhookUrl)} \\`)
|
|
419
|
+
// lines.push(` -H 'Content-Type: application/json' \\`)
|
|
420
|
+
// lines.push(` -d '{ "your": "payload" }'`)
|
|
421
|
+
// lines.push("")
|
|
422
|
+
// }
|
|
423
|
+
// lines.push(chalk.dim("After the first event lands, `terse test` will pick it up automatically."))
|
|
424
|
+
// return lines.join("\n")
|
|
425
|
+
// }
|
|
426
|
+
//
|
|
427
|
+
// async function inspectSampleEvent(event: SerializedEvent): Promise<"back" | "run"> {
|
|
428
|
+
// log.info(chalk.bold(formatEventLabel(event)))
|
|
429
|
+
// if (event.display?.subtitle) {
|
|
430
|
+
// console.log(chalk.dim(event.display.subtitle))
|
|
431
|
+
// }
|
|
432
|
+
// console.log("")
|
|
433
|
+
// console.log(chalk.dim(truncate(normalizeSingleLine(event.formattedContent), 300)))
|
|
434
|
+
// console.log("")
|
|
435
|
+
//
|
|
436
|
+
// return abortIfCancelled(
|
|
437
|
+
// await select<"back" | "run">({
|
|
438
|
+
// message: "Run this event?",
|
|
439
|
+
// options: [
|
|
440
|
+
// { label: "Run this sample event", value: "run" },
|
|
441
|
+
// { label: "Choose another event", value: "back" }
|
|
442
|
+
// ]
|
|
443
|
+
// })
|
|
444
|
+
// )
|
|
445
|
+
// }
|
|
446
|
+
//
|
|
447
|
+
// // Types
|
|
448
|
+
//
|
|
449
|
+
// export type TestListOpts = {
|
|
450
|
+
// jobName?: string
|
|
451
|
+
// json?: boolean
|
|
452
|
+
// entryFile?: string
|
|
453
|
+
// provider?: LanguageProvider
|
|
454
|
+
// }
|
|
455
|
+
//
|
|
456
|
+
// export type TestShowOpts = {
|
|
457
|
+
// id: string
|
|
458
|
+
// jobName?: string
|
|
459
|
+
// json?: boolean
|
|
460
|
+
// entryFile?: string
|
|
461
|
+
// provider?: LanguageProvider
|
|
462
|
+
// }
|
|
463
|
+
//
|
|
464
|
+
// export type TestRunOpts = {
|
|
465
|
+
// jobName?: string
|
|
466
|
+
// id?: string
|
|
467
|
+
// eventJson?: string
|
|
468
|
+
// eventFile?: string
|
|
469
|
+
// verbose?: boolean
|
|
470
|
+
// entryFile?: string
|
|
471
|
+
// provider?: LanguageProvider
|
|
472
|
+
// freshState?: boolean
|
|
473
|
+
// }
|
|
474
|
+
//
|
|
475
|
+
// type SampleEventCandidate =
|
|
476
|
+
// | {
|
|
477
|
+
// id: string
|
|
478
|
+
// kind: "ref"
|
|
479
|
+
// integrationType: string
|
|
480
|
+
// eventType: string
|
|
481
|
+
// label: string
|
|
482
|
+
// subtitle: string | null
|
|
483
|
+
// entityType: string
|
|
484
|
+
// entityId: string
|
|
485
|
+
// }
|
|
486
|
+
// | {
|
|
487
|
+
// id: string
|
|
488
|
+
// kind: "synthetic"
|
|
489
|
+
// integrationType: string
|
|
490
|
+
// eventType: string
|
|
491
|
+
// label: string
|
|
492
|
+
// subtitle: string | null
|
|
493
|
+
// event: SerializedEvent
|
|
494
|
+
// }
|
|
495
|
+
// | {
|
|
496
|
+
// id: string
|
|
497
|
+
// kind: "stored"
|
|
498
|
+
// integrationType: string
|
|
499
|
+
// eventType: string
|
|
500
|
+
// label: string
|
|
501
|
+
// subtitle: string | null
|
|
502
|
+
// recordedAt: string | null
|
|
503
|
+
// event: SerializedEvent
|
|
504
|
+
// }
|
|
505
|
+
//
|
|
506
|
+
// type SampleEventCandidatesResult = {
|
|
507
|
+
// candidates: SampleEventCandidate[]
|
|
508
|
+
// webhookEndpoints: NonNullable<SdkSampleEventsResponse["webhookEndpoints"]>
|
|
509
|
+
// }
|
|
404
510
|
//# sourceMappingURL=test.js.map
|