terse-cli 0.1.36 → 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/dist/api.d.ts.map +1 -1
  2. package/dist/api.js +9 -9
  3. package/dist/api.js.map +1 -1
  4. package/dist/assertProjectRoot.d.ts +1 -1
  5. package/dist/assertProjectRoot.d.ts.map +1 -1
  6. package/dist/assertProjectRoot.js +5 -4
  7. package/dist/assertProjectRoot.js.map +1 -1
  8. package/dist/cliError.d.ts +22 -0
  9. package/dist/cliError.d.ts.map +1 -0
  10. package/dist/cliError.js +67 -0
  11. package/dist/cliError.js.map +1 -0
  12. package/dist/cliHelpers.d.ts +20 -0
  13. package/dist/cliHelpers.d.ts.map +1 -0
  14. package/dist/cliHelpers.js +69 -0
  15. package/dist/cliHelpers.js.map +1 -0
  16. package/dist/commands/attach.d.ts +2 -1
  17. package/dist/commands/attach.d.ts.map +1 -1
  18. package/dist/commands/attach.js +7 -5
  19. package/dist/commands/attach.js.map +1 -1
  20. package/dist/commands/auth.d.ts +2 -1
  21. package/dist/commands/auth.d.ts.map +1 -1
  22. package/dist/commands/auth.js +20 -1
  23. package/dist/commands/auth.js.map +1 -1
  24. package/dist/commands/deploy.d.ts.map +1 -1
  25. package/dist/commands/deploy.js +14 -14
  26. package/dist/commands/deploy.js.map +1 -1
  27. package/dist/commands/generate.d.ts +1 -5
  28. package/dist/commands/generate.d.ts.map +1 -1
  29. package/dist/commands/generate.js +13 -16
  30. package/dist/commands/generate.js.map +1 -1
  31. package/dist/commands/history.d.ts +1 -1
  32. package/dist/commands/history.d.ts.map +1 -1
  33. package/dist/commands/history.js +4 -3
  34. package/dist/commands/history.js.map +1 -1
  35. package/dist/commands/improvements.d.ts +4 -0
  36. package/dist/commands/improvements.d.ts.map +1 -0
  37. package/dist/commands/improvements.js +246 -0
  38. package/dist/commands/improvements.js.map +1 -0
  39. package/dist/commands/init.d.ts +2 -1
  40. package/dist/commands/init.d.ts.map +1 -1
  41. package/dist/commands/init.js +11 -10
  42. package/dist/commands/init.js.map +1 -1
  43. package/dist/commands/integrate.d.ts +32 -2
  44. package/dist/commands/integrate.d.ts.map +1 -1
  45. package/dist/commands/integrate.js +228 -5
  46. package/dist/commands/integrate.js.map +1 -1
  47. package/dist/commands/replay.d.ts.map +1 -1
  48. package/dist/commands/replay.js +5 -6
  49. package/dist/commands/replay.js.map +1 -1
  50. package/dist/commands/run.d.ts.map +1 -1
  51. package/dist/commands/run.js +14 -17
  52. package/dist/commands/run.js.map +1 -1
  53. package/dist/commands/test.d.ts +47 -0
  54. package/dist/commands/test.d.ts.map +1 -1
  55. package/dist/commands/test.js +214 -58
  56. package/dist/commands/test.js.map +1 -1
  57. package/dist/index.js +183 -14
  58. package/dist/index.js.map +1 -1
  59. package/dist/jsonOutput.d.ts +19 -0
  60. package/dist/jsonOutput.d.ts.map +1 -0
  61. package/dist/jsonOutput.js +25 -0
  62. package/dist/jsonOutput.js.map +1 -0
  63. package/dist/loadJob.d.ts +2 -1
  64. package/dist/loadJob.d.ts.map +1 -1
  65. package/dist/loadJob.js +16 -13
  66. package/dist/loadJob.js.map +1 -1
  67. package/dist/nonInteractive.d.ts +18 -0
  68. package/dist/nonInteractive.d.ts.map +1 -0
  69. package/dist/nonInteractive.js +57 -0
  70. package/dist/nonInteractive.js.map +1 -0
  71. package/dist/projectConfig.d.ts.map +1 -1
  72. package/dist/projectConfig.js +17 -10
  73. package/dist/projectConfig.js.map +1 -1
  74. package/dist/providers/python/PythonProvider.d.ts.map +1 -1
  75. package/dist/providers/python/PythonProvider.js +24 -14
  76. package/dist/providers/python/PythonProvider.js.map +1 -1
  77. package/dist/providers/resolveProvider.d.ts.map +1 -1
  78. package/dist/providers/resolveProvider.js +7 -9
  79. package/dist/providers/resolveProvider.js.map +1 -1
  80. package/dist/providers/shared/entryFileGuidance.d.ts.map +1 -1
  81. package/dist/providers/shared/entryFileGuidance.js +7 -12
  82. package/dist/providers/shared/entryFileGuidance.js.map +1 -1
  83. package/dist/providers/typescript/TypeScriptProvider.d.ts.map +1 -1
  84. package/dist/providers/typescript/TypeScriptProvider.js +30 -27
  85. package/dist/providers/typescript/TypeScriptProvider.js.map +1 -1
  86. package/dist/replay.d.ts +3 -0
  87. package/dist/replay.d.ts.map +1 -0
  88. package/dist/replay.js +20 -0
  89. package/dist/replay.js.map +1 -0
  90. package/dist/run.d.ts.map +1 -1
  91. package/dist/run.js +12 -36
  92. package/dist/run.js.map +1 -1
  93. package/dist/sampleEventCache.d.ts +9 -0
  94. package/dist/sampleEventCache.d.ts.map +1 -0
  95. package/dist/sampleEventCache.js +47 -0
  96. package/dist/sampleEventCache.js.map +1 -0
  97. package/dist/sampleEventId.d.ts +13 -0
  98. package/dist/sampleEventId.d.ts.map +1 -0
  99. package/dist/sampleEventId.js +20 -0
  100. package/dist/sampleEventId.js.map +1 -0
  101. package/dist/shared/ToolDisplayUtils.js +1 -1
  102. package/dist/shared/ToolDisplayUtils.js.map +1 -1
  103. package/dist/urls.d.ts +3 -0
  104. package/dist/urls.d.ts.map +1 -0
  105. package/dist/urls.js +27 -0
  106. package/dist/urls.js.map +1 -0
  107. package/package.json +3 -3
  108. package/dist/commands/deployTheme.d.ts +0 -28
  109. package/dist/commands/deployTheme.d.ts.map +0 -1
  110. package/dist/commands/deployTheme.js +0 -68
  111. package/dist/commands/deployTheme.js.map +0 -1
  112. package/dist/commands/dev.d.ts +0 -3
  113. package/dist/commands/dev.d.ts.map +0 -1
  114. package/dist/commands/dev.js +0 -47
  115. package/dist/commands/dev.js.map +0 -1
  116. package/dist/commands/serve.d.ts +0 -1
  117. package/dist/commands/serve.d.ts.map +0 -1
  118. package/dist/commands/serve.js +0 -2
  119. package/dist/commands/serve.js.map +0 -1
  120. package/dist/commands/terseCliTheme.d.ts +0 -28
  121. package/dist/commands/terseCliTheme.d.ts.map +0 -1
  122. package/dist/commands/terseCliTheme.js +0 -68
  123. package/dist/commands/terseCliTheme.js.map +0 -1
  124. package/dist/perf.d.ts +0 -9
  125. package/dist/perf.d.ts.map +0 -1
  126. package/dist/perf.js +0 -59
  127. package/dist/perf.js.map +0 -1
  128. package/dist/providers/codegen.test.d.ts +0 -2
  129. package/dist/providers/codegen.test.d.ts.map +0 -1
  130. package/dist/providers/codegen.test.js +0 -45
  131. package/dist/providers/codegen.test.js.map +0 -1
  132. package/dist/providers/python/PythonProvider.test.d.ts +0 -2
  133. package/dist/providers/python/PythonProvider.test.d.ts.map +0 -1
  134. package/dist/providers/python/PythonProvider.test.js +0 -169
  135. package/dist/providers/python/PythonProvider.test.js.map +0 -1
  136. package/dist/providers/typescript/prepareCodegenData.test.d.ts +0 -2
  137. package/dist/providers/typescript/prepareCodegenData.test.d.ts.map +0 -1
  138. package/dist/providers/typescript/prepareCodegenData.test.js +0 -54
  139. package/dist/providers/typescript/prepareCodegenData.test.js.map +0 -1
@@ -1,13 +1,21 @@
1
1
  import { cancel, intro, isCancel, log, outro, select } from "@clack/prompts";
2
2
  import chalk from "chalk";
3
+ import fs from "node:fs";
3
4
  import { IntegrationType } from "terse-sdk";
4
- import { ApiRoutes, debugTrigger, displayTrigger, formatTriggerForAgent } from "terse-types";
5
+ import { ApiRoutes, debugTrigger, displayTrigger, formatTriggerForAgent, serializedEventSchema } from "terse-types";
5
6
  import { fetchWithAuth, readApiKeyOrBail } from "../api.js";
6
7
  import { assertProjectRoot } from "../assertProjectRoot.js";
8
+ import { CliError } from "../cliError.js";
9
+ import { isNonInteractive } from "../cliHelpers.js";
7
10
  import { createSpinner } from "../cliUi.js";
8
11
  import { loadJob } from "../loadJob.js";
9
12
  import { resolveProvider } from "../providers/resolveProvider.js";
10
13
  export async function test(jobName, verbose, provider = resolveProvider(), entryFile) {
14
+ if (isNonInteractive()) {
15
+ throw new CliError("test_requires_interactive", "`terse test` needs a terminal.", {
16
+ detail: "In non-interactive contexts, use `terse test list` to enumerate sample events and `terse test run --id <id>` to execute one."
17
+ });
18
+ }
11
19
  intro("terse test");
12
20
  assertProjectRoot(provider);
13
21
  const { job } = await loadJob(provider, jobName, entryFile);
@@ -15,61 +23,30 @@ export async function test(jobName, verbose, provider = resolveProvider(), entry
15
23
  title: "Error: Not authenticated. Unable to fetch sample events.",
16
24
  detail: "Run `terse login` to authenticate, or set TERSE_API_KEY in your environment."
17
25
  });
18
- // Split triggers into time-based, webhook, and integration-based
19
- const timeTriggers = job.triggers.filter(t => t.integrationType === IntegrationType.CRON_JOB);
20
- const webhookTriggers = job.triggers.filter(t => t.integrationType === IntegrationType.WEBHOOK);
21
- const integrationTriggers = job.triggers.filter(t => t.integrationType !== IntegrationType.CRON_JOB && t.integrationType !== IntegrationType.WEBHOOK);
22
- let events = [];
23
- // Fetch sample events for integration triggers (time triggers have no sample events)
24
- if (integrationTriggers.length > 0) {
25
- const spinner = createSpinner();
26
- spinner.start("Fetching sample events");
27
- try {
28
- const result = await fetchWithAuth(ApiRoutes.SDK.SAMPLE_EVENTS, apiKey, {
29
- triggers: integrationTriggers.map(trigger => ({
30
- triggerId: undefined,
31
- integrationId: trigger.integrationId,
32
- integrationType: trigger.integrationType,
33
- config: trigger
34
- }))
35
- }, "POST");
36
- events = result.events;
37
- spinner.stop(`Fetched ${events.length} sample event${events.length === 1 ? "" : "s"}`);
38
- }
39
- catch (err) {
40
- spinner.stop(err instanceof Error ? err.message : "Failed to fetch sample events.");
41
- }
42
- }
43
- // Add a synthetic manual trigger event for each time trigger
44
- for (const trigger of timeTriggers) {
45
- events.push(serializeEvent({
46
- integrationType: IntegrationType.CRON_JOB,
47
- eventType: "cron",
48
- inputId: trigger.integrationId,
49
- isManualTrigger: true,
50
- manualContext: `Manual trigger from terse test (schedule: ${trigger.cronExpression ?? "unknown"})`
51
- }));
26
+ const spinner = createSpinner();
27
+ spinner.start("Fetching sample events");
28
+ let candidates = [];
29
+ try {
30
+ candidates = await fetchSampleEventCandidatesForJob(job, apiKey);
31
+ spinner.stop(`Fetched ${candidates.length} sample event${candidates.length === 1 ? "" : "s"}`);
52
32
  }
53
- // Add a synthetic manual trigger event for each webhook trigger
54
- for (const trigger of webhookTriggers) {
55
- events.push(serializeEvent({
56
- integrationType: IntegrationType.WEBHOOK,
57
- eventType: "webhook",
58
- body: {},
59
- headers: {},
60
- method: "POST"
61
- }));
33
+ catch (err) {
34
+ spinner.stop(err instanceof Error ? err.message : "Failed to fetch sample events.");
62
35
  }
63
- if (events.length === 0) {
64
- log.error("No sample events available. Make sure your triggers are configured and events have been received.");
65
- process.exit(1);
36
+ if (candidates.length === 0) {
37
+ const webhookHint = hasWebhookTrigger(job);
38
+ throw new CliError("no_sample_events", "No sample events available.", {
39
+ detail: webhookHint
40
+ ? "Webhook triggers do not provide sample events yet. Use `--event` / `--event-file` with a concrete payload."
41
+ : "Make sure your triggers are configured and events have been received."
42
+ });
66
43
  }
67
44
  log.info(`Testing job ${chalk.cyan(job.name)}`);
68
- const choice = await chooseSampleEvent(events);
45
+ const event = await chooseSampleEvent(candidates, apiKey);
69
46
  const runSpinner = createSpinner();
70
- runSpinner.start(`Running ${formatEventLabel(events[choice])}`);
47
+ runSpinner.start(`Running ${formatEventLabel(event)}`);
71
48
  try {
72
- await provider.executeJob(job, null, events[choice], { verbose: !!verbose, entryFile });
49
+ await provider.executeJob(job, null, event, { verbose: !!verbose, entryFile });
73
50
  runSpinner.stop("Run completed");
74
51
  outro("Done");
75
52
  }
@@ -78,11 +55,175 @@ export async function test(jobName, verbose, provider = resolveProvider(), entry
78
55
  throw error;
79
56
  }
80
57
  }
58
+ export async function testList(opts = {}) {
59
+ const provider = opts.provider ?? resolveProvider();
60
+ assertProjectRoot(provider);
61
+ const { job } = await loadJob(provider, opts.jobName, opts.entryFile, { nonInteractive: true });
62
+ const apiKey = readApiKeyOrBail();
63
+ const candidates = await fetchSampleEventCandidatesForJob(job, apiKey);
64
+ if (opts.json) {
65
+ const payload = {
66
+ job: job.name,
67
+ events: candidates.map(candidate => ({
68
+ id: candidate.id,
69
+ integrationType: candidate.integrationType,
70
+ eventType: candidate.eventType,
71
+ label: candidate.label,
72
+ subtitle: candidate.subtitle,
73
+ entityType: candidate.kind === "ref" ? candidate.entityType : null,
74
+ entityId: candidate.kind === "ref" ? candidate.entityId : null
75
+ }))
76
+ };
77
+ process.stdout.write(JSON.stringify(payload, null, 2) + "\n");
78
+ return;
79
+ }
80
+ if (candidates.length === 0) {
81
+ if (hasWebhookTrigger(job)) {
82
+ process.stdout.write("No sample events available. Webhook triggers are not supported for test samples.\n");
83
+ }
84
+ else {
85
+ process.stdout.write("No sample events available.\n");
86
+ }
87
+ return;
88
+ }
89
+ process.stdout.write(`Sample events for job ${job.name}:\n\n`);
90
+ for (const candidate of candidates) {
91
+ const subtitle = candidate.subtitle ? ` — ${normalizeSingleLine(candidate.subtitle)}` : "";
92
+ process.stdout.write(` ${chalk.cyan(candidate.id)} ${candidate.integrationType}/${candidate.eventType} ${candidate.label}${chalk.dim(subtitle)}\n`);
93
+ }
94
+ process.stdout.write("\n");
95
+ process.stdout.write(chalk.dim(`Run one with: terse test run --id <id>\n`));
96
+ }
97
+ export async function testShow(opts) {
98
+ const provider = opts.provider ?? resolveProvider();
99
+ assertProjectRoot(provider);
100
+ const event = await resolveEventById(provider, opts.id, opts.jobName, opts.entryFile);
101
+ if (opts.json) {
102
+ process.stdout.write(JSON.stringify({ id: opts.id, event }, null, 2) + "\n");
103
+ return;
104
+ }
105
+ process.stdout.write(`${chalk.bold(formatEventLabel(event))}\n`);
106
+ if (event.display?.subtitle)
107
+ process.stdout.write(chalk.dim(event.display.subtitle) + "\n");
108
+ process.stdout.write(`\n${event.formattedContent}\n`);
109
+ }
110
+ export async function testRun(opts) {
111
+ const provider = opts.provider ?? resolveProvider();
112
+ assertProjectRoot(provider);
113
+ const modeCount = [opts.id, opts.eventJson, opts.eventFile].filter(Boolean).length;
114
+ if (modeCount === 0) {
115
+ throw new CliError("missing_event", "Provide one of --id, --event, or --event-file.", {
116
+ detail: "Run `terse test list --json` to see available sample ids."
117
+ });
118
+ }
119
+ if (modeCount > 1) {
120
+ throw new CliError("conflicting_flags", "--id, --event, and --event-file are mutually exclusive.");
121
+ }
122
+ const { job } = await loadJob(provider, opts.jobName, opts.entryFile, { nonInteractive: true });
123
+ let event;
124
+ if (opts.id) {
125
+ event = await resolveEventByIdForJob(job, opts.id);
126
+ }
127
+ else {
128
+ const rawJson = opts.eventJson ?? readEventFile(opts.eventFile);
129
+ event = parseEventJson(rawJson);
130
+ }
131
+ await provider.executeJob(job, null, event, { verbose: !!opts.verbose, entryFile: opts.entryFile });
132
+ }
133
+ async function resolveEventById(provider, id, jobNameHint, entryFile) {
134
+ const { job } = await loadJob(provider, jobNameHint, entryFile, { nonInteractive: true });
135
+ return resolveEventByIdForJob(job, id);
136
+ }
137
+ async function resolveEventByIdForJob(job, id) {
138
+ const apiKey = readApiKeyOrBail();
139
+ const candidates = await fetchSampleEventCandidatesForJob(job, apiKey);
140
+ const match = candidates.find(candidate => candidate.id === id);
141
+ if (match)
142
+ return hydrateCandidateEvent(match, apiKey);
143
+ throw new CliError("sample_not_found", `No sample event matches id ${id}.`, {
144
+ detail: "Run `terse test list` to refresh — the event may have rotated out of the sample buffer."
145
+ });
146
+ }
147
+ function readEventFile(filePath) {
148
+ try {
149
+ return fs.readFileSync(filePath, "utf-8");
150
+ }
151
+ catch (err) {
152
+ throw new CliError("event_file_unreadable", `Could not read event file: ${filePath}`, {
153
+ detail: err instanceof Error ? err.message : String(err)
154
+ });
155
+ }
156
+ }
157
+ function parseEventJson(raw) {
158
+ let parsed;
159
+ try {
160
+ parsed = JSON.parse(raw);
161
+ }
162
+ catch (err) {
163
+ throw new CliError("invalid_event_json", "--event / --event-file must be valid JSON.", {
164
+ detail: err instanceof Error ? err.message : String(err)
165
+ });
166
+ }
167
+ try {
168
+ return serializedEventSchema.parse(parsed);
169
+ }
170
+ catch (err) {
171
+ throw new CliError("invalid_event_shape", "Event JSON does not match the canonical Trigger schema.", {
172
+ detail: err instanceof Error ? err.message : String(err)
173
+ });
174
+ }
175
+ }
176
+ export async function fetchSampleEventCandidatesForJob(job, apiKey) {
177
+ const timeTriggers = job.triggers.filter(t => t.integrationType === IntegrationType.CRON_JOB);
178
+ const integrationTriggers = job.triggers.filter(t => t.integrationType !== IntegrationType.CRON_JOB && t.integrationType !== IntegrationType.WEBHOOK);
179
+ const candidates = [];
180
+ if (integrationTriggers.length > 0) {
181
+ const result = await fetchWithAuth(ApiRoutes.SDK.SAMPLE_EVENTS, apiKey, {
182
+ triggers: integrationTriggers.map(trigger => ({
183
+ triggerId: undefined,
184
+ integrationId: trigger.integrationId,
185
+ integrationType: trigger.integrationType,
186
+ config: trigger
187
+ }))
188
+ }, "POST");
189
+ candidates.push(...result.events.map(event => ({
190
+ id: encodeRefId(event.entity.entityType, event.entity.entityId),
191
+ kind: "ref",
192
+ integrationType: event.serializedEvent.integrationType,
193
+ eventType: event.serializedEvent.eventType,
194
+ label: normalizeSingleLine(event.serializedEvent.display?.title || `${event.serializedEvent.integrationType} / ${event.serializedEvent.eventType}`),
195
+ subtitle: event.serializedEvent.display?.subtitle ?? null,
196
+ entityType: event.entity.entityType,
197
+ entityId: event.entity.entityId
198
+ })));
199
+ }
200
+ for (const [index, trigger] of timeTriggers.entries()) {
201
+ const event = serializeEvent({
202
+ integrationType: IntegrationType.CRON_JOB,
203
+ eventType: "cron",
204
+ inputId: trigger.integrationId,
205
+ isManualTrigger: true,
206
+ manualContext: `Manual trigger from terse test (schedule: ${trigger.cronExpression})`
207
+ });
208
+ candidates.push({
209
+ id: `synthetic:cron:${index}`,
210
+ kind: "synthetic",
211
+ integrationType: event.integrationType,
212
+ eventType: event.eventType,
213
+ label: formatEventLabel(event),
214
+ subtitle: event.display?.subtitle ?? null,
215
+ event
216
+ });
217
+ }
218
+ return candidates;
219
+ }
81
220
  function formatEventLabel(event) {
82
221
  return normalizeSingleLine(event.display?.title || `${event.integrationType} / ${event.eventType}`);
83
222
  }
84
- function formatEventHint(event) {
85
- return truncate(normalizeSingleLine(event.display?.subtitle || event.debugLog), 120);
223
+ function formatEventHint(candidate) {
224
+ if (candidate.subtitle)
225
+ return truncate(normalizeSingleLine(candidate.subtitle), 120);
226
+ return candidate.kind === "ref" ? truncate(`${candidate.integrationType}/${candidate.eventType}`, 120) : "Synthetic sample event";
86
227
  }
87
228
  function truncate(value, maxLength) {
88
229
  if (value.length <= maxLength) {
@@ -103,22 +244,37 @@ function abortIfCancelled(value) {
103
244
  }
104
245
  return value;
105
246
  }
106
- async function chooseSampleEvent(events) {
247
+ async function chooseSampleEvent(candidates, apiKey) {
107
248
  while (true) {
108
249
  const choice = abortIfCancelled(await select({
109
250
  message: "Choose a sample event",
110
- options: events.map((event, index) => ({
111
- label: `${formatEventLabel(event)} ${chalk.dim("›")}`,
112
- hint: formatEventHint(event),
251
+ options: candidates.map((candidate, index) => ({
252
+ label: `${candidate.label} ${chalk.dim("›")}`,
253
+ hint: formatEventHint(candidate),
113
254
  value: index
114
255
  }))
115
256
  }));
116
- const action = await inspectSampleEvent(events[choice]);
257
+ const event = await hydrateCandidateEvent(candidates[choice], apiKey);
258
+ const action = await inspectSampleEvent(event);
117
259
  if (action === "run") {
118
- return choice;
260
+ return event;
119
261
  }
120
262
  }
121
263
  }
264
+ async function hydrateCandidateEvent(candidate, apiKey) {
265
+ if (candidate.kind === "synthetic") {
266
+ return candidate.event;
267
+ }
268
+ const payload = await fetchWithAuth(ApiRoutes.SDK.HYDRATE_SAMPLE_EVENT, apiKey, { entityType: candidate.entityType, entityId: candidate.entityId }, "POST");
269
+ return payload.event;
270
+ }
271
+ function encodeRefId(entityType, entityId) {
272
+ const token = Buffer.from(JSON.stringify({ entityType, entityId }), "utf8").toString("base64url");
273
+ return `ref:${token}`;
274
+ }
275
+ function hasWebhookTrigger(job) {
276
+ return job.triggers.some(trigger => trigger.integrationType === IntegrationType.WEBHOOK);
277
+ }
122
278
  async function inspectSampleEvent(event) {
123
279
  log.info(chalk.bold(formatEventLabel(event)));
124
280
  if (event.display?.subtitle) {
@@ -1 +1 @@
1
- {"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/commands/test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/commands/test.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import chalk from "chalk";
3
3
  import { Command } from "commander";
4
+ import { CliError, emitCliError, isCliError, setErrorOutputJson } from "./cliError.js";
5
+ import { collectKeyValue, parseIntFlag } from "./cliHelpers.js";
4
6
  import { getCliVersion } from "./cliVersion.js";
5
7
  import { attach } from "./commands/attach.js";
6
8
  import { loginAndPersist, logout } from "./commands/auth.js";
@@ -9,55 +11,197 @@ import { deploy } from "./commands/deploy.js";
9
11
  import { openDocs } from "./commands/docs.js";
10
12
  import { generate } from "./commands/generate.js";
11
13
  import { history } from "./commands/history.js";
14
+ import { applyImprovement, listImprovements } from "./commands/improvements.js";
12
15
  import { init } from "./commands/init.js";
13
- import { integrate } from "./commands/integrate.js";
16
+ import { integrate, integrateConnect, integrateDescribe, integrateDisconnect, integrateList, integrateWait } from "./commands/integrate.js";
14
17
  import { replay } from "./commands/replay.js";
15
18
  import { run } from "./commands/run.js";
16
- import { test } from "./commands/test.js";
19
+ import { test, testList, testRun, testShow } from "./commands/test.js";
17
20
  import { isCliRunCommandEnabled } from "./env.js";
18
21
  import { isPromptCancellationError } from "./promptErrors.js";
19
22
  import { resolveProvider } from "./providers/resolveProvider.js";
20
23
  const program = new Command();
24
+ const NON_INTERACTIVE_OPTION = ["-y, --non-interactive", "Run non-interactively; fail fast if authentication or choices are required"];
25
+ const ENTRY_FILE_OPTION = ["--entry-file <path>", "Path to the job entry file (overrides default)"];
26
+ function syncJsonErrorOutput(command) {
27
+ const { json } = command.opts();
28
+ setErrorOutputJson(Boolean(json));
29
+ }
21
30
  program.name("terse").description("The Terse CLI — create and manage Terse projects").version(getCliVersion());
31
+ program.hook("preAction", (_thisCommand, actionCommand) => {
32
+ syncJsonErrorOutput(actionCommand);
33
+ });
22
34
  program.commandsGroup("Getting started:");
23
35
  program
24
36
  .command("init")
25
37
  .description("Create a new Terse project")
26
38
  .argument("[project-name]", "Name for the project directory")
27
- .action(async (projectName) => {
39
+ .option(...NON_INTERACTIVE_OPTION)
40
+ .addHelpText("after", `
41
+ Examples:
42
+ $ terse init myproj # interactive scaffold
43
+ $ terse init myproj --non-interactive # non-interactive; requires prior \`terse login\`
44
+ $ terse init myproj < /dev/null # auto non-interactive (no TTY)
45
+ `)
46
+ .action(async (projectName, opts) => {
28
47
  const language = "ts";
29
48
  const provider = resolveProvider({ command: "init", language });
30
- await init(projectName, provider);
49
+ await init(projectName, provider, opts);
31
50
  });
32
51
  program
33
52
  .command("attach")
34
53
  .description("Add Terse to an existing project (self-hosted)")
35
- .action(async () => {
36
- await attach();
54
+ .option(...NON_INTERACTIVE_OPTION)
55
+ .action(async (opts) => {
56
+ await attach(resolveProvider(), opts);
37
57
  });
38
- program
58
+ const testCommand = program
39
59
  .command("test")
40
60
  .description("Fetch sample events and run a job interactively")
41
61
  .argument("[job-name]", "Name of the job to test (auto-selects if only one exists)")
42
62
  .option("-v, --verbose", "Show agent stream output", true)
43
- .option("--entry-file <path>", "Path to the job entry file (overrides default)")
63
+ .option(...ENTRY_FILE_OPTION)
64
+ .addHelpText("after", `
65
+ Examples:
66
+ $ terse test # interactive picker
67
+ $ terse test my-job # test a specific job
68
+
69
+ Non-interactive subcommands (for AI agents and CI):
70
+ $ terse test list --json # enumerate sample events with ids
71
+ $ terse test show <id> # inspect a specific sample
72
+ $ terse test run --id <id> # run a cached sample by content hash
73
+ $ terse test run --event-file sample.json # run a sample event from disk
74
+ `)
44
75
  .action(async (jobName, opts) => {
45
76
  await test(jobName, opts?.verbose, resolveProvider(), opts?.entryFile);
46
77
  });
78
+ testCommand
79
+ .command("list")
80
+ .description("List sample events for a job with content-addressed ids")
81
+ .argument("[job-name]", "Name of the job (auto-selects if only one exists)")
82
+ .option("--json", "Emit JSON with the full event payload for each id")
83
+ .option(...ENTRY_FILE_OPTION)
84
+ .action(async (jobName, opts) => {
85
+ await testList({ jobName, json: opts?.json, entryFile: opts?.entryFile });
86
+ });
87
+ testCommand
88
+ .command("show")
89
+ .description("Show the full contents of a cached sample event")
90
+ .argument("<id>", "Sample event id from `terse test list`")
91
+ .argument("[job-name]", "Name of the job (auto-selects if only one exists)")
92
+ .option("--json", "Emit JSON instead of rendered text")
93
+ .option(...ENTRY_FILE_OPTION)
94
+ .action(async (id, jobName, opts) => {
95
+ await testShow({ id, jobName, json: opts?.json, entryFile: opts?.entryFile });
96
+ });
97
+ testCommand
98
+ .command("run")
99
+ .description("Run a job against a sample event non-interactively")
100
+ .argument("[job-name]", "Name of the job (auto-selects if only one exists)")
101
+ .option("--id <id>", "Sample event id from `terse test list`")
102
+ .option("--event <json>", "Inline serialized event JSON string")
103
+ .option("--event-file <path>", "Path to a JSON file containing the serialized event")
104
+ .option("-v, --verbose", "Show agent stream output", true)
105
+ .option(...ENTRY_FILE_OPTION)
106
+ .addHelpText("after", `
107
+ Examples:
108
+ $ terse test list --json | jq -r '.events[0].id' | xargs -I{} terse test run --id {}
109
+ $ terse test run --event-file fixture.json
110
+ `)
111
+ .action(async (jobName, opts) => {
112
+ await testRun({
113
+ jobName,
114
+ id: opts?.id,
115
+ eventJson: opts?.event,
116
+ eventFile: opts?.eventFile,
117
+ verbose: opts?.verbose,
118
+ entryFile: opts?.entryFile
119
+ });
120
+ });
47
121
  program
48
122
  .command("deploy")
49
123
  .description("Deploy all jobs to Terse (syncs with server — removed jobs are deleted)")
50
- .option("--entry-file <path>", "Path to the job entry file (overrides default)")
124
+ .option(...ENTRY_FILE_OPTION)
51
125
  .action(async (opts) => {
52
126
  await deploy(resolveProvider(), opts?.entryFile);
53
127
  });
54
128
  program.commandsGroup("Build with workspace context:");
55
- program
129
+ const integrateCommand = program
56
130
  .command("integrate")
57
- .description("Open the integrations page in the Terse Web UI")
131
+ .description("Connect and manage integrations")
132
+ .addHelpText("after", `
133
+ Examples:
134
+ $ terse integrate # interactive picker
135
+ $ terse integrate list --json # enumerate integrations
136
+ $ terse integrate describe snowflake --json # see required fields
137
+ $ terse integrate connect snowflake --field account=x --field username=y --fields-stdin <<< '{"password":"'"$PW"'"}'
138
+ $ terse integrate connect slack # OAuth → opens browser, exit 2 (follow up with 'wait')
139
+ $ terse integrate wait slack --timeout 300 # block until OAuth completes
140
+ $ terse integrate disconnect snowflake
141
+ `)
58
142
  .action(async () => {
59
143
  await integrate();
60
144
  });
145
+ integrateCommand
146
+ .command("list")
147
+ .description("List integrations and their connection status")
148
+ .option("--json", "Emit JSON")
149
+ .option("--status <status>", "Filter to `connected` or `disconnected`")
150
+ .action(async (opts) => {
151
+ if (opts.status && opts.status !== "connected" && opts.status !== "disconnected") {
152
+ throw new CliError("invalid_status_filter", `--status must be "connected" or "disconnected", got "${opts.status}".`);
153
+ }
154
+ await integrateList({ json: opts.json, status: opts.status });
155
+ });
156
+ integrateCommand
157
+ .command("describe")
158
+ .description("Show schema and status for an integration type")
159
+ .argument("<type>", "Integration type (e.g. slack, snowflake)")
160
+ .option("--json", "Emit JSON")
161
+ .action(async (type, opts) => {
162
+ await integrateDescribe({ integrationType: type, json: opts.json });
163
+ });
164
+ integrateCommand
165
+ .command("connect")
166
+ .description("Connect (or refresh) an integration. OAuth types open a browser and exit 2 — follow up with `wait` to block.")
167
+ .argument("<type>", "Integration type (e.g. slack, gmail, snowflake)")
168
+ .option("--field <key=value>", "Form field value (repeatable). Never put secrets here — use --fields-stdin.", collectKeyValue, [])
169
+ .option("--fields-stdin", "Read a JSON object of additional fields from stdin (secrets go here)")
170
+ .option("-f, --force", "Re-run the install even if the integration is already connected")
171
+ .option("--json", "Emit JSON")
172
+ .addHelpText("after", `
173
+ Examples:
174
+ $ terse integrate connect snowflake --field account=xyz --field username=foo --fields-stdin <<< '{"password":"'"$PW"'"}'
175
+ $ terse integrate connect slack # OAuth: opens browser, prints URL + wait command, exit 2
176
+ $ terse integrate connect slack --json # OAuth: opens browser, emits handoff JSON, exit 2
177
+ $ terse integrate connect snowflake --force # refresh an existing connection
178
+ `)
179
+ .action(async (type, opts) => {
180
+ await integrateConnect({
181
+ integrationType: type,
182
+ fieldFlags: opts.field,
183
+ fieldsStdin: opts.fieldsStdin,
184
+ force: opts.force,
185
+ json: opts.json
186
+ });
187
+ });
188
+ integrateCommand
189
+ .command("disconnect")
190
+ .description("Disconnect an integration")
191
+ .argument("<type>", "Integration type (e.g. slack, snowflake)")
192
+ .option("--json", "Emit JSON")
193
+ .action(async (type, opts) => {
194
+ await integrateDisconnect({ integrationType: type, json: opts.json });
195
+ });
196
+ integrateCommand
197
+ .command("wait")
198
+ .description("Block until an OAuth integration finishes connecting (run after `connect` emits a handoff)")
199
+ .argument("<type>", "Integration type (e.g. slack, gmail)")
200
+ .option("--timeout <seconds>", "Timeout in seconds (default 300, max 900)", parseIntFlag)
201
+ .option("--json", "Emit JSON")
202
+ .action(async (type, opts) => {
203
+ await integrateWait({ integrationType: type, timeoutSeconds: opts.timeout, json: opts.json });
204
+ });
61
205
  program
62
206
  .command("generate")
63
207
  .description("Autogenerate context from your connected workspaces")
@@ -72,11 +216,32 @@ if (isCliRunCommandEnabled()) {
72
216
  .argument("[job-name]", "Name of the job to run (auto-selects if only one exists)")
73
217
  .option("--event <json>", "Serialized event JSON string")
74
218
  .option("--event-file <path>", "Path to a JSON file containing the serialized event")
75
- .option("--entry-file <path>", "Path to the job entry file (overrides default)")
219
+ .option(...ENTRY_FILE_OPTION)
76
220
  .action(async (jobName, opts) => {
77
221
  await run(jobName, opts?.event, opts?.eventFile, resolveProvider(), opts?.entryFile);
78
222
  });
79
223
  }
224
+ program.commandsGroup("Improvements:");
225
+ program
226
+ .command("apply")
227
+ .description("Apply a suggested improvement patch locally (runs `git apply`)")
228
+ .argument("[improvement-id]", "ID of the improvement to apply (prompts if omitted)")
229
+ .option(...NON_INTERACTIVE_OPTION)
230
+ .addHelpText("after", `
231
+ Examples:
232
+ $ terse apply # interactive picker
233
+ $ terse apply <improvement-id> # apply a specific improvement
234
+ $ terse apply <improvement-id> --non-interactive # fail fast on prompts (CI/agents)
235
+ `)
236
+ .action(async (improvementId, opts) => {
237
+ await applyImprovement(improvementId, opts);
238
+ });
239
+ program
240
+ .command("list")
241
+ .description("List Terse resources")
242
+ .addCommand(new Command("improvements").description("List pending improvements across all agents").action(async () => {
243
+ await listImprovements();
244
+ }));
80
245
  program.commandsGroup("Observability:");
81
246
  program
82
247
  .command("replay")
@@ -90,8 +255,8 @@ program
90
255
  .description("View past run events for a job (use --json to pipe into tooling like the Claude Code /improve skill)")
91
256
  .argument("[job-name]", "Name of the job to view the history of")
92
257
  .option("--json", "Output runs as JSON for machine consumption")
93
- .option("--limit <n>", "Max runs to fetch (default 20, max 100)", v => parseInt(v, 10))
94
- .option("--page <n>", "Page number (1-indexed)", v => parseInt(v, 10))
258
+ .option("--limit <n>", "Max runs to fetch (default 20, max 100)", parseIntFlag)
259
+ .option("--page <n>", "Page number (1-indexed)", parseIntFlag)
95
260
  .option("--status <list>", "Comma-separated statuses (success,failed,cancelled,skipped,in_progress,awaiting_approval)")
96
261
  .option("--since <iso>", "Only include runs at or after this ISO timestamp")
97
262
  .option("--until <iso>", "Only include runs at or before this ISO timestamp")
@@ -145,6 +310,10 @@ catch (error) {
145
310
  console.log(chalk.yellow("\n Cancelled.\n"));
146
311
  process.exit(130);
147
312
  }
313
+ if (isCliError(error)) {
314
+ emitCliError(error);
315
+ process.exit(error.exitCode);
316
+ }
148
317
  throw error;
149
318
  }
150
319
  //# sourceMappingURL=index.js.map