@autonoma-ai/planner 0.1.4 → 0.1.5
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/dist/index.js +330 -144
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -84,6 +84,195 @@ var init_model = __esm({
|
|
|
84
84
|
}
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
+
// src/core/analytics.ts
|
|
88
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
89
|
+
import { join as join5 } from "path";
|
|
90
|
+
import { homedir as homedir3 } from "os";
|
|
91
|
+
import { randomUUID } from "crypto";
|
|
92
|
+
function resolveKey() {
|
|
93
|
+
return (process.env.AUTONOMA_POSTHOG_KEY ?? POSTHOG_PUBLIC_KEY).trim();
|
|
94
|
+
}
|
|
95
|
+
function resolveHost() {
|
|
96
|
+
return (process.env.AUTONOMA_POSTHOG_HOST ?? DEFAULT_HOST).replace(/\/+$/, "");
|
|
97
|
+
}
|
|
98
|
+
function trackingDisabled() {
|
|
99
|
+
const v = process.env.DONT_TRACK;
|
|
100
|
+
return v === "1" || v === "true";
|
|
101
|
+
}
|
|
102
|
+
function getIdentity() {
|
|
103
|
+
const id = process.env.AUTONOMA_DISTINCT_ID?.trim();
|
|
104
|
+
return id && id.length > 0 ? id : void 0;
|
|
105
|
+
}
|
|
106
|
+
function getDeviceId() {
|
|
107
|
+
if (cachedDeviceId) return cachedDeviceId;
|
|
108
|
+
try {
|
|
109
|
+
cachedDeviceId = readFileSync3(DEVICE_ID_PATH, "utf-8").trim();
|
|
110
|
+
if (cachedDeviceId) return cachedDeviceId;
|
|
111
|
+
} catch {
|
|
112
|
+
}
|
|
113
|
+
cachedDeviceId = randomUUID();
|
|
114
|
+
try {
|
|
115
|
+
mkdirSync2(AUTONOMA_HOME3, { recursive: true });
|
|
116
|
+
writeFileSync2(DEVICE_ID_PATH, cachedDeviceId, { encoding: "utf-8", mode: 384 });
|
|
117
|
+
} catch {
|
|
118
|
+
}
|
|
119
|
+
return cachedDeviceId;
|
|
120
|
+
}
|
|
121
|
+
function isEnabled() {
|
|
122
|
+
if (enabled === null) {
|
|
123
|
+
enabled = !trackingDisabled() && resolveKey().length > 0;
|
|
124
|
+
}
|
|
125
|
+
return enabled;
|
|
126
|
+
}
|
|
127
|
+
function track(event, properties = {}) {
|
|
128
|
+
if (!isEnabled()) return;
|
|
129
|
+
const identity = getIdentity();
|
|
130
|
+
const body = JSON.stringify({
|
|
131
|
+
api_key: resolveKey(),
|
|
132
|
+
event,
|
|
133
|
+
distinct_id: identity ?? getDeviceId(),
|
|
134
|
+
properties: {
|
|
135
|
+
...properties,
|
|
136
|
+
run_id: RUN_ID,
|
|
137
|
+
// Only build a person profile when we have a real identity from the app,
|
|
138
|
+
// so the CLI joins the existing funnel person instead of creating a new one.
|
|
139
|
+
$process_person_profile: identity != null,
|
|
140
|
+
cli_version: process.env.npm_package_version
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
const promise = fetch(`${resolveHost()}/capture/`, {
|
|
144
|
+
method: "POST",
|
|
145
|
+
headers: { "Content-Type": "application/json" },
|
|
146
|
+
body
|
|
147
|
+
}).catch(() => {
|
|
148
|
+
}).finally(() => pending.delete(promise));
|
|
149
|
+
pending.add(promise);
|
|
150
|
+
}
|
|
151
|
+
function trackError(error, properties = {}, handled = true) {
|
|
152
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
153
|
+
track("$exception", {
|
|
154
|
+
...properties,
|
|
155
|
+
$exception_list: [
|
|
156
|
+
{
|
|
157
|
+
type: err.name,
|
|
158
|
+
value: err.message,
|
|
159
|
+
mechanism: { handled, synthetic: !(error instanceof Error) }
|
|
160
|
+
}
|
|
161
|
+
],
|
|
162
|
+
error_stack: err.stack
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async function flushAnalytics(timeoutMs = 1500) {
|
|
166
|
+
if (pending.size === 0) return;
|
|
167
|
+
await Promise.race([
|
|
168
|
+
Promise.allSettled([...pending]),
|
|
169
|
+
new Promise((resolve5) => setTimeout(resolve5, timeoutMs))
|
|
170
|
+
]);
|
|
171
|
+
}
|
|
172
|
+
var AUTONOMA_HOME3, DEVICE_ID_PATH, POSTHOG_PUBLIC_KEY, DEFAULT_HOST, RUN_ID, cachedDeviceId, enabled, pending;
|
|
173
|
+
var init_analytics = __esm({
|
|
174
|
+
"src/core/analytics.ts"() {
|
|
175
|
+
"use strict";
|
|
176
|
+
init_esm_shims();
|
|
177
|
+
AUTONOMA_HOME3 = join5(homedir3(), ".autonoma");
|
|
178
|
+
DEVICE_ID_PATH = join5(AUTONOMA_HOME3, ".device-id");
|
|
179
|
+
POSTHOG_PUBLIC_KEY = "phc_mUOwUj62r8vyiisFPvXLC3G5RftETIBMnKNSHqTBdka";
|
|
180
|
+
DEFAULT_HOST = "https://us.i.posthog.com";
|
|
181
|
+
RUN_ID = randomUUID();
|
|
182
|
+
cachedDeviceId = null;
|
|
183
|
+
enabled = null;
|
|
184
|
+
pending = /* @__PURE__ */ new Set();
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// src/core/errors.ts
|
|
189
|
+
import { APICallError, RetryError, LoadAPIKeyError, InvalidPromptError, NoSuchModelError } from "ai";
|
|
190
|
+
function sleep(ms) {
|
|
191
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
192
|
+
}
|
|
193
|
+
function formatException(err) {
|
|
194
|
+
if (!(err instanceof Error)) return String(err);
|
|
195
|
+
let out = err.stack ?? `${err.name}: ${err.message}`;
|
|
196
|
+
if (err.cause != null) {
|
|
197
|
+
out += `
|
|
198
|
+
Caused by: ${formatException(err.cause)}`;
|
|
199
|
+
}
|
|
200
|
+
return out;
|
|
201
|
+
}
|
|
202
|
+
function classifyAgentError(err) {
|
|
203
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
204
|
+
const msg = message.toLowerCase();
|
|
205
|
+
if (msg.includes("timed out") || msg.includes("timeout") || msg.includes("abort")) {
|
|
206
|
+
return "timeout";
|
|
207
|
+
}
|
|
208
|
+
if (APICallError.isInstance(err)) {
|
|
209
|
+
if (err.statusCode != null && FATAL_STATUS_CODES.has(err.statusCode)) return "fatal";
|
|
210
|
+
return "transient";
|
|
211
|
+
}
|
|
212
|
+
if (LoadAPIKeyError.isInstance(err) || InvalidPromptError.isInstance(err) || NoSuchModelError.isInstance(err)) {
|
|
213
|
+
return "fatal";
|
|
214
|
+
}
|
|
215
|
+
if (RetryError.isInstance(err)) {
|
|
216
|
+
if (err.reason === "errorNotRetryable" && err.lastError !== err) {
|
|
217
|
+
return classifyAgentError(err.lastError);
|
|
218
|
+
}
|
|
219
|
+
return "transient";
|
|
220
|
+
}
|
|
221
|
+
if (TRANSIENT_MESSAGE_PATTERNS.some((pattern) => msg.includes(pattern))) {
|
|
222
|
+
return "transient";
|
|
223
|
+
}
|
|
224
|
+
return "transient";
|
|
225
|
+
}
|
|
226
|
+
var FATAL_STATUS_CODES, TRANSIENT_MESSAGE_PATTERNS;
|
|
227
|
+
var init_errors = __esm({
|
|
228
|
+
"src/core/errors.ts"() {
|
|
229
|
+
"use strict";
|
|
230
|
+
init_esm_shims();
|
|
231
|
+
FATAL_STATUS_CODES = /* @__PURE__ */ new Set([400, 401, 403, 404, 422]);
|
|
232
|
+
TRANSIENT_MESSAGE_PATTERNS = [
|
|
233
|
+
"econnreset",
|
|
234
|
+
"econnrefused",
|
|
235
|
+
"etimedout",
|
|
236
|
+
"socket hang up",
|
|
237
|
+
"fetch failed",
|
|
238
|
+
"network",
|
|
239
|
+
"overloaded",
|
|
240
|
+
"rate limit",
|
|
241
|
+
"too many requests",
|
|
242
|
+
"429",
|
|
243
|
+
"500",
|
|
244
|
+
"502",
|
|
245
|
+
"503",
|
|
246
|
+
"529"
|
|
247
|
+
];
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// src/core/notify.ts
|
|
252
|
+
import { platform } from "os";
|
|
253
|
+
import { execFile } from "child_process";
|
|
254
|
+
function notify(title, message) {
|
|
255
|
+
process.stderr.write("\x07");
|
|
256
|
+
const os = platform();
|
|
257
|
+
if (os === "darwin") {
|
|
258
|
+
execFile(
|
|
259
|
+
"osascript",
|
|
260
|
+
["-e", `display notification "${message.replace(/"/g, '\\"')}" with title "${title.replace(/"/g, '\\"')}"`],
|
|
261
|
+
() => {
|
|
262
|
+
}
|
|
263
|
+
);
|
|
264
|
+
} else if (os === "linux") {
|
|
265
|
+
execFile("notify-send", [title, message], () => {
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
var init_notify = __esm({
|
|
270
|
+
"src/core/notify.ts"() {
|
|
271
|
+
"use strict";
|
|
272
|
+
init_esm_shims();
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
|
|
87
276
|
// src/core/display.ts
|
|
88
277
|
function formatArgs(input, keys) {
|
|
89
278
|
const parts = [];
|
|
@@ -243,6 +432,13 @@ import {
|
|
|
243
432
|
hasToolCall,
|
|
244
433
|
stepCountIs
|
|
245
434
|
} from "ai";
|
|
435
|
+
function formatRetryGuidance(guidance) {
|
|
436
|
+
if (!guidance?.trim()) return "";
|
|
437
|
+
return `
|
|
438
|
+
A previous attempt at this task did not complete successfully. The user provided this guidance for the retry:
|
|
439
|
+
"${guidance.trim()}"
|
|
440
|
+
`;
|
|
441
|
+
}
|
|
246
442
|
function buildDefaultStepLogger(agentId, maxSteps) {
|
|
247
443
|
const logger = createStepLogger(agentId, maxSteps);
|
|
248
444
|
return {
|
|
@@ -302,26 +498,49 @@ async function runAgent(config, prompt, extractResult) {
|
|
|
302
498
|
onStepFinish: buildStepHandler(config)
|
|
303
499
|
});
|
|
304
500
|
try {
|
|
305
|
-
|
|
306
|
-
|
|
501
|
+
const messages = [{ role: "user", content: prompt }];
|
|
502
|
+
let generation = await agent.generate({
|
|
503
|
+
messages,
|
|
307
504
|
timeout: { stepMs: stepTimeout }
|
|
308
505
|
});
|
|
506
|
+
let nudges = 0;
|
|
507
|
+
while (extractResult() === void 0 && nudges < MAX_NUDGES) {
|
|
508
|
+
nudges++;
|
|
509
|
+
console.log(
|
|
510
|
+
` ${YELLOW5}[${config.id}] agent stopped without finishing \u2014 nudging (${nudges}/${MAX_NUDGES})...${RESET8}`
|
|
511
|
+
);
|
|
512
|
+
track("cli_agent_nudged", { agent: config.id, nudge: nudges });
|
|
513
|
+
messages.push(...generation.response.messages);
|
|
514
|
+
messages.push({ role: "user", content: NUDGE_PROMPT });
|
|
515
|
+
generation = await agent.generate({
|
|
516
|
+
messages,
|
|
517
|
+
timeout: { stepMs: stepTimeout }
|
|
518
|
+
});
|
|
519
|
+
}
|
|
309
520
|
return extractResult();
|
|
310
521
|
} catch (err) {
|
|
522
|
+
const errorClass = classifyAgentError(err);
|
|
523
|
+
if (errorClass === "fatal") throw err;
|
|
311
524
|
const msg = err instanceof Error ? err.message : String(err);
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
525
|
+
if (errorClass === "timeout") {
|
|
526
|
+
console.log(` ${YELLOW5}[${config.id}] step timed out after ${stepTimeout / 1e3}s${RESET8}`);
|
|
527
|
+
} else {
|
|
528
|
+
console.log(` ${YELLOW5}[${config.id}] provider error: ${msg}${RESET8}`);
|
|
529
|
+
}
|
|
530
|
+
track("cli_agent_retryable_error", { agent: config.id, error_class: errorClass, retry });
|
|
315
531
|
if (retry < RETRIES_BEFORE_FALLBACK - 1) {
|
|
316
532
|
console.log(
|
|
317
533
|
` ${YELLOW5}[${config.id}] retrying (${retry + 1}/${RETRIES_BEFORE_FALLBACK})...${RESET8}`
|
|
318
534
|
);
|
|
535
|
+
if (errorClass === "transient") {
|
|
536
|
+
await sleep(Math.min(2e3 * 2 ** retry, 1e4));
|
|
537
|
+
}
|
|
319
538
|
continue;
|
|
320
539
|
}
|
|
321
540
|
if (modelIdx < modelsToTry.length - 1) {
|
|
322
541
|
const nextModel = FALLBACK_MODELS[modelIdx];
|
|
323
542
|
console.log(
|
|
324
|
-
` ${YELLOW5}[${config.id}] ${RETRIES_BEFORE_FALLBACK}
|
|
543
|
+
` ${YELLOW5}[${config.id}] ${RETRIES_BEFORE_FALLBACK} failed attempts, switching to ${nextModel}${RESET8}`
|
|
325
544
|
);
|
|
326
545
|
break;
|
|
327
546
|
}
|
|
@@ -331,12 +550,14 @@ async function runAgent(config, prompt, extractResult) {
|
|
|
331
550
|
}
|
|
332
551
|
return extractResult();
|
|
333
552
|
}
|
|
334
|
-
var FALLBACK_MODELS, RETRIES_BEFORE_FALLBACK, STEP_TIMEOUT_MS;
|
|
553
|
+
var FALLBACK_MODELS, RETRIES_BEFORE_FALLBACK, STEP_TIMEOUT_MS, MAX_NUDGES, NUDGE_PROMPT;
|
|
335
554
|
var init_agent = __esm({
|
|
336
555
|
"src/core/agent.ts"() {
|
|
337
556
|
"use strict";
|
|
338
557
|
init_esm_shims();
|
|
558
|
+
init_analytics();
|
|
339
559
|
init_display();
|
|
560
|
+
init_errors();
|
|
340
561
|
init_model();
|
|
341
562
|
FALLBACK_MODELS = [
|
|
342
563
|
"moonshotai/kimi-k2.6",
|
|
@@ -345,6 +566,8 @@ var init_agent = __esm({
|
|
|
345
566
|
];
|
|
346
567
|
RETRIES_BEFORE_FALLBACK = 3;
|
|
347
568
|
STEP_TIMEOUT_MS = 12e4;
|
|
569
|
+
MAX_NUDGES = 2;
|
|
570
|
+
NUDGE_PROMPT = "You stopped before completing the task. The task is only complete once the finish tool has been called and succeeded. If your last finish call returned an error, fix exactly what it reported. Otherwise, continue where you left off and call the finish tool when done.";
|
|
348
571
|
}
|
|
349
572
|
});
|
|
350
573
|
|
|
@@ -412,7 +635,7 @@ var init_gitignore = __esm({
|
|
|
412
635
|
});
|
|
413
636
|
|
|
414
637
|
// src/tools/bash.ts
|
|
415
|
-
import { execFile as
|
|
638
|
+
import { execFile as execFile3 } from "child_process";
|
|
416
639
|
import { promisify as promisify2 } from "util";
|
|
417
640
|
import { tool } from "ai";
|
|
418
641
|
import { z } from "zod";
|
|
@@ -479,7 +702,7 @@ var init_bash = __esm({
|
|
|
479
702
|
"src/tools/bash.ts"() {
|
|
480
703
|
"use strict";
|
|
481
704
|
init_esm_shims();
|
|
482
|
-
execFileAsync2 = promisify2(
|
|
705
|
+
execFileAsync2 = promisify2(execFile3);
|
|
483
706
|
CHAINING_OPERATORS = /;|&&|\|\||`|\$\(|>>|<<|&\s*$/;
|
|
484
707
|
DEFAULT_ALLOWED = /* @__PURE__ */ new Set([
|
|
485
708
|
"git",
|
|
@@ -540,7 +763,7 @@ var init_glob = __esm({
|
|
|
540
763
|
});
|
|
541
764
|
|
|
542
765
|
// src/tools/grep.ts
|
|
543
|
-
import { execFile as
|
|
766
|
+
import { execFile as execFile4 } from "child_process";
|
|
544
767
|
import { promisify as promisify3 } from "util";
|
|
545
768
|
import { tool as tool3 } from "ai";
|
|
546
769
|
import { z as z3 } from "zod";
|
|
@@ -585,7 +808,7 @@ var init_grep = __esm({
|
|
|
585
808
|
"src/tools/grep.ts"() {
|
|
586
809
|
"use strict";
|
|
587
810
|
init_esm_shims();
|
|
588
|
-
execFileAsync3 = promisify3(
|
|
811
|
+
execFileAsync3 = promisify3(execFile4);
|
|
589
812
|
inputSchema3 = z3.object({
|
|
590
813
|
pattern: z3.string().describe("Regex pattern to search for in file contents"),
|
|
591
814
|
glob: z3.string().optional().describe("Glob to filter files (e.g. '*.ts')"),
|
|
@@ -1062,31 +1285,6 @@ var init_pages_finder = __esm({
|
|
|
1062
1285
|
}
|
|
1063
1286
|
});
|
|
1064
1287
|
|
|
1065
|
-
// src/core/notify.ts
|
|
1066
|
-
import { platform } from "os";
|
|
1067
|
-
import { execFile as execFile4 } from "child_process";
|
|
1068
|
-
function notify(title, message) {
|
|
1069
|
-
process.stderr.write("\x07");
|
|
1070
|
-
const os = platform();
|
|
1071
|
-
if (os === "darwin") {
|
|
1072
|
-
execFile4(
|
|
1073
|
-
"osascript",
|
|
1074
|
-
["-e", `display notification "${message.replace(/"/g, '\\"')}" with title "${title.replace(/"/g, '\\"')}"`],
|
|
1075
|
-
() => {
|
|
1076
|
-
}
|
|
1077
|
-
);
|
|
1078
|
-
} else if (os === "linux") {
|
|
1079
|
-
execFile4("notify-send", [title, message], () => {
|
|
1080
|
-
});
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
var init_notify = __esm({
|
|
1084
|
-
"src/core/notify.ts"() {
|
|
1085
|
-
"use strict";
|
|
1086
|
-
init_esm_shims();
|
|
1087
|
-
}
|
|
1088
|
-
});
|
|
1089
|
-
|
|
1090
1288
|
// src/core/review.ts
|
|
1091
1289
|
import * as p3 from "@clack/prompts";
|
|
1092
1290
|
import { access } from "fs/promises";
|
|
@@ -1540,7 +1738,7 @@ async function runKBGenerator(input) {
|
|
|
1540
1738
|
let result;
|
|
1541
1739
|
const tracker = new PageTracker();
|
|
1542
1740
|
const { logger, onStepFinish } = buildDefaultStepLogger("kb", 150);
|
|
1543
|
-
const contextBlock = input.projectContext ? "\n" + formatContext(input.projectContext) + "\n" : "";
|
|
1741
|
+
const contextBlock = (input.projectContext ? "\n" + formatContext(input.projectContext) + "\n" : "") + formatRetryGuidance(input.retryGuidance);
|
|
1544
1742
|
const pages = input.projectContext?.pages;
|
|
1545
1743
|
if (pages?.length) {
|
|
1546
1744
|
tracker.register(pages.map((p10) => p10.path));
|
|
@@ -1644,7 +1842,7 @@ Call page_coverage to see current state. When done with changes, call finish aga
|
|
|
1644
1842
|
return reviewed ?? {
|
|
1645
1843
|
success: false,
|
|
1646
1844
|
artifacts: [],
|
|
1647
|
-
summary: "KB generator
|
|
1845
|
+
summary: "KB generator agent stopped without producing AUTONOMA.md"
|
|
1648
1846
|
};
|
|
1649
1847
|
}
|
|
1650
1848
|
var PageTracker;
|
|
@@ -2211,7 +2409,7 @@ async function runEntityAudit(input) {
|
|
|
2211
2409
|
preRegisteredCount = detection.models.length;
|
|
2212
2410
|
}
|
|
2213
2411
|
const { logger, onStepFinish } = buildDefaultStepLogger("entity-audit", 200);
|
|
2214
|
-
const contextBlock = input.projectContext ? "\n" + formatContext(input.projectContext) + "\n" : "";
|
|
2412
|
+
const contextBlock = (input.projectContext ? "\n" + formatContext(input.projectContext) + "\n" : "") + formatRetryGuidance(input.retryGuidance);
|
|
2215
2413
|
const preRegBlock = preRegisteredCount > 0 ? `
|
|
2216
2414
|
## Pre-registered models (${preRegisteredCount} found via ${detection.framework} schema at ${detection.schemaFile})
|
|
2217
2415
|
|
|
@@ -2260,11 +2458,13 @@ write_file already targets the output directory \u2014 use just the filename.`;
|
|
|
2260
2458
|
},
|
|
2261
2459
|
onStepFinish
|
|
2262
2460
|
};
|
|
2461
|
+
let agentError;
|
|
2263
2462
|
try {
|
|
2264
2463
|
await runAgent(agentConfig, prompt, () => result);
|
|
2265
2464
|
} catch (err) {
|
|
2266
|
-
|
|
2267
|
-
console.error(`Entity audit agent error:
|
|
2465
|
+
agentError = err instanceof Error ? err.message : String(err);
|
|
2466
|
+
console.error(`Entity audit agent error:
|
|
2467
|
+
${formatException(err)}`);
|
|
2268
2468
|
}
|
|
2269
2469
|
logger.summary();
|
|
2270
2470
|
if (!result && tracker.auditedModels.size > 0) {
|
|
@@ -2316,7 +2516,7 @@ When done with changes, call finish again.`;
|
|
|
2316
2516
|
return reviewed ?? {
|
|
2317
2517
|
success: false,
|
|
2318
2518
|
artifacts: [],
|
|
2319
|
-
summary: "Entity audit
|
|
2519
|
+
summary: agentError ? `Entity audit failed: ${agentError}` : "Entity audit agent stopped without producing entity-audit.md"
|
|
2320
2520
|
};
|
|
2321
2521
|
}
|
|
2322
2522
|
var ModelTracker;
|
|
@@ -2325,6 +2525,7 @@ var init_entity_audit = __esm({
|
|
|
2325
2525
|
"use strict";
|
|
2326
2526
|
init_esm_shims();
|
|
2327
2527
|
init_agent();
|
|
2528
|
+
init_errors();
|
|
2328
2529
|
init_context();
|
|
2329
2530
|
init_model();
|
|
2330
2531
|
init_review();
|
|
@@ -2653,7 +2854,7 @@ async function runScenarioRecipe(input) {
|
|
|
2653
2854
|
const model = getModel(input.modelId);
|
|
2654
2855
|
let result;
|
|
2655
2856
|
const { logger, onStepFinish } = buildDefaultStepLogger("scenario", 40);
|
|
2656
|
-
const contextBlock = input.projectContext ? "\n" + formatContext(input.projectContext) + "\n" : "";
|
|
2857
|
+
const contextBlock = (input.projectContext ? "\n" + formatContext(input.projectContext) + "\n" : "") + formatRetryGuidance(input.retryGuidance);
|
|
2657
2858
|
const requiredEntities = await parseEntityNames(input.outputDir);
|
|
2658
2859
|
const entityListBlock = requiredEntities.length > 0 ? `
|
|
2659
2860
|
## Required entities (${requiredEntities.length} total \u2014 ALL must appear in the scenario)
|
|
@@ -2726,7 +2927,7 @@ When done with changes, call finish again.`;
|
|
|
2726
2927
|
return reviewed ?? {
|
|
2727
2928
|
success: false,
|
|
2728
2929
|
artifacts: [],
|
|
2729
|
-
summary: "Scenario
|
|
2930
|
+
summary: "Scenario agent stopped without producing scenarios.md"
|
|
2730
2931
|
};
|
|
2731
2932
|
}
|
|
2732
2933
|
async function feedbackToScenario(input, feedback) {
|
|
@@ -2920,7 +3121,8 @@ async function rankEntitiesByImportance(models, auditMarkdown, model) {
|
|
|
2920
3121
|
return new Map(reconciled.order.map((name, i) => [name, i]));
|
|
2921
3122
|
} catch (err) {
|
|
2922
3123
|
console.warn(
|
|
2923
|
-
`[recipe-builder] Importance ranking failed, falling back to alphabetical order:
|
|
3124
|
+
`[recipe-builder] Importance ranking failed, falling back to alphabetical order:
|
|
3125
|
+
${formatException(err)}`
|
|
2924
3126
|
);
|
|
2925
3127
|
return /* @__PURE__ */ new Map();
|
|
2926
3128
|
}
|
|
@@ -2930,6 +3132,7 @@ var init_entity_relevance = __esm({
|
|
|
2930
3132
|
"src/agents/04-recipe-builder/entity-relevance.ts"() {
|
|
2931
3133
|
"use strict";
|
|
2932
3134
|
init_esm_shims();
|
|
3135
|
+
init_errors();
|
|
2933
3136
|
rankedSchema = z13.object({
|
|
2934
3137
|
ranked: z13.array(z13.string()).describe("Every entity name, ordered most-important first.")
|
|
2935
3138
|
});
|
|
@@ -3478,7 +3681,8 @@ async function testUpDown(entityName, entityIndex, totalEntities, sdkConfig, rec
|
|
|
3478
3681
|
try {
|
|
3479
3682
|
upResult = await up(sdkConfig, recipe, testRunId);
|
|
3480
3683
|
} catch (err) {
|
|
3481
|
-
p5.log.error(`UP request failed:
|
|
3684
|
+
p5.log.error(`UP request failed:
|
|
3685
|
+
${formatException(err)}`);
|
|
3482
3686
|
const action = await promptOnFailure(entityName, null);
|
|
3483
3687
|
if (action === "skip") return "skip";
|
|
3484
3688
|
if (action === "retry") continue;
|
|
@@ -3506,7 +3710,8 @@ async function testUpDown(entityName, entityIndex, totalEntities, sdkConfig, rec
|
|
|
3506
3710
|
try {
|
|
3507
3711
|
downResult = await down(sdkConfig, refsToken);
|
|
3508
3712
|
} catch (err) {
|
|
3509
|
-
p5.log.error(`DOWN request failed:
|
|
3713
|
+
p5.log.error(`DOWN request failed:
|
|
3714
|
+
${formatException(err)}`);
|
|
3510
3715
|
const action = await promptOnFailure(entityName, null);
|
|
3511
3716
|
if (action === "skip") return "skip";
|
|
3512
3717
|
if (action === "retry") continue;
|
|
@@ -3707,6 +3912,7 @@ var init_entity_loop = __esm({
|
|
|
3707
3912
|
"use strict";
|
|
3708
3913
|
init_esm_shims();
|
|
3709
3914
|
init_agent();
|
|
3915
|
+
init_errors();
|
|
3710
3916
|
init_tools();
|
|
3711
3917
|
init_ask_user();
|
|
3712
3918
|
init_gitignore();
|
|
@@ -3809,7 +4015,8 @@ async function teardown(sdkConfig, refsToken, successMessage) {
|
|
|
3809
4015
|
try {
|
|
3810
4016
|
downResult = await down(sdkConfig, refsToken);
|
|
3811
4017
|
} catch (err) {
|
|
3812
|
-
p6.log.error(`Full DOWN request failed:
|
|
4018
|
+
p6.log.error(`Full DOWN request failed:
|
|
4019
|
+
${formatException(err)}`);
|
|
3813
4020
|
return false;
|
|
3814
4021
|
}
|
|
3815
4022
|
if (!downResult.ok) {
|
|
@@ -3847,7 +4054,8 @@ async function runFullValidation(state, _models, outputDir, model) {
|
|
|
3847
4054
|
try {
|
|
3848
4055
|
upResult = await up(sdkConfig, fullRecipe, testRunId);
|
|
3849
4056
|
} catch (err) {
|
|
3850
|
-
p6.log.error(`Full UP request failed:
|
|
4057
|
+
p6.log.error(`Full UP request failed:
|
|
4058
|
+
${formatException(err)}`);
|
|
3851
4059
|
notify("Autonoma", "Full validation UP failed, action needed");
|
|
3852
4060
|
const action = await p6.select({
|
|
3853
4061
|
message: "What would you like to do?",
|
|
@@ -3934,6 +4142,7 @@ var init_full_validation = __esm({
|
|
|
3934
4142
|
init_esm_shims();
|
|
3935
4143
|
init_notify();
|
|
3936
4144
|
init_agent();
|
|
4145
|
+
init_errors();
|
|
3937
4146
|
init_tools();
|
|
3938
4147
|
init_highlight();
|
|
3939
4148
|
init_state();
|
|
@@ -5543,7 +5752,7 @@ ${scenariosMd}
|
|
|
5543
5752
|
const preseedContext = existingState ? "" : await preseedQueue(state, input.projectRoot, input.pages, features ?? void 0);
|
|
5544
5753
|
const resumeContext = existingState ? `
|
|
5545
5754
|
You are RESUMING a previous run. ${existingState.summary().tested} nodes tested, ${existingState.summary().totalTests} tests written. Call next_node to continue.` : "";
|
|
5546
|
-
const contextBlock = input.projectContext ? "\n" + formatContext(input.projectContext) + "\n" : "";
|
|
5755
|
+
const contextBlock = (input.projectContext ? "\n" + formatContext(input.projectContext) + "\n" : "") + formatRetryGuidance(input.retryGuidance);
|
|
5547
5756
|
let prompt = `Generate E2E test cases by processing every node in the queue.
|
|
5548
5757
|
${contextBlock}${kbContext}${resumeContext}${preseedContext}
|
|
5549
5758
|
|
|
@@ -5608,8 +5817,8 @@ Do NOT try to finish early. Process EVERY node via next_node until it returns do
|
|
|
5608
5817
|
try {
|
|
5609
5818
|
await runAgent(agentConfig, prompt, () => result);
|
|
5610
5819
|
} catch (err) {
|
|
5611
|
-
|
|
5612
|
-
|
|
5820
|
+
console.log(` [chunk] Agent error (will retry next chunk):
|
|
5821
|
+
${formatException(err)}`);
|
|
5613
5822
|
}
|
|
5614
5823
|
totalSteps += CHUNK_STEPS;
|
|
5615
5824
|
if (result) break;
|
|
@@ -5970,8 +6179,8 @@ Write 5-8 journey tests using the write_test tool with folder "journeys". Then c
|
|
|
5970
6179
|
try {
|
|
5971
6180
|
await runAgent(config, journeyPrompt, () => journeyResult);
|
|
5972
6181
|
} catch (err) {
|
|
5973
|
-
|
|
5974
|
-
|
|
6182
|
+
console.error(`Journey generator error:
|
|
6183
|
+
${formatException(err)}`);
|
|
5975
6184
|
}
|
|
5976
6185
|
logger.summary();
|
|
5977
6186
|
return journeyState.allTestPaths().length;
|
|
@@ -5982,6 +6191,7 @@ var init_test_generator = __esm({
|
|
|
5982
6191
|
"use strict";
|
|
5983
6192
|
init_esm_shims();
|
|
5984
6193
|
init_agent();
|
|
6194
|
+
init_errors();
|
|
5985
6195
|
init_context();
|
|
5986
6196
|
init_display();
|
|
5987
6197
|
init_gitignore();
|
|
@@ -6197,86 +6407,10 @@ function restoreTerminal() {
|
|
|
6197
6407
|
process.stdout.write(SHOW_CURSOR);
|
|
6198
6408
|
}
|
|
6199
6409
|
|
|
6200
|
-
// src/
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
import { homedir as homedir3 } from "os";
|
|
6205
|
-
import { randomUUID } from "crypto";
|
|
6206
|
-
var AUTONOMA_HOME3 = join5(homedir3(), ".autonoma");
|
|
6207
|
-
var DEVICE_ID_PATH = join5(AUTONOMA_HOME3, ".device-id");
|
|
6208
|
-
var POSTHOG_PUBLIC_KEY = "phc_mUOwUj62r8vyiisFPvXLC3G5RftETIBMnKNSHqTBdka";
|
|
6209
|
-
var DEFAULT_HOST = "https://us.i.posthog.com";
|
|
6210
|
-
function resolveKey() {
|
|
6211
|
-
return (process.env.AUTONOMA_POSTHOG_KEY ?? POSTHOG_PUBLIC_KEY).trim();
|
|
6212
|
-
}
|
|
6213
|
-
function resolveHost() {
|
|
6214
|
-
return (process.env.AUTONOMA_POSTHOG_HOST ?? DEFAULT_HOST).replace(/\/+$/, "");
|
|
6215
|
-
}
|
|
6216
|
-
function trackingDisabled() {
|
|
6217
|
-
const v = process.env.DONT_TRACK;
|
|
6218
|
-
return v === "1" || v === "true";
|
|
6219
|
-
}
|
|
6220
|
-
function getIdentity() {
|
|
6221
|
-
const id = process.env.AUTONOMA_DISTINCT_ID?.trim();
|
|
6222
|
-
return id && id.length > 0 ? id : void 0;
|
|
6223
|
-
}
|
|
6224
|
-
var RUN_ID = randomUUID();
|
|
6225
|
-
var cachedDeviceId = null;
|
|
6226
|
-
function getDeviceId() {
|
|
6227
|
-
if (cachedDeviceId) return cachedDeviceId;
|
|
6228
|
-
try {
|
|
6229
|
-
cachedDeviceId = readFileSync3(DEVICE_ID_PATH, "utf-8").trim();
|
|
6230
|
-
if (cachedDeviceId) return cachedDeviceId;
|
|
6231
|
-
} catch {
|
|
6232
|
-
}
|
|
6233
|
-
cachedDeviceId = randomUUID();
|
|
6234
|
-
try {
|
|
6235
|
-
mkdirSync2(AUTONOMA_HOME3, { recursive: true });
|
|
6236
|
-
writeFileSync2(DEVICE_ID_PATH, cachedDeviceId, { encoding: "utf-8", mode: 384 });
|
|
6237
|
-
} catch {
|
|
6238
|
-
}
|
|
6239
|
-
return cachedDeviceId;
|
|
6240
|
-
}
|
|
6241
|
-
var enabled = null;
|
|
6242
|
-
function isEnabled() {
|
|
6243
|
-
if (enabled === null) {
|
|
6244
|
-
enabled = !trackingDisabled() && resolveKey().length > 0;
|
|
6245
|
-
}
|
|
6246
|
-
return enabled;
|
|
6247
|
-
}
|
|
6248
|
-
var pending = /* @__PURE__ */ new Set();
|
|
6249
|
-
function track(event, properties = {}) {
|
|
6250
|
-
if (!isEnabled()) return;
|
|
6251
|
-
const identity = getIdentity();
|
|
6252
|
-
const body = JSON.stringify({
|
|
6253
|
-
api_key: resolveKey(),
|
|
6254
|
-
event,
|
|
6255
|
-
distinct_id: identity ?? getDeviceId(),
|
|
6256
|
-
properties: {
|
|
6257
|
-
...properties,
|
|
6258
|
-
run_id: RUN_ID,
|
|
6259
|
-
// Only build a person profile when we have a real identity from the app,
|
|
6260
|
-
// so the CLI joins the existing funnel person instead of creating a new one.
|
|
6261
|
-
$process_person_profile: identity != null,
|
|
6262
|
-
cli_version: process.env.npm_package_version
|
|
6263
|
-
}
|
|
6264
|
-
});
|
|
6265
|
-
const promise = fetch(`${resolveHost()}/capture/`, {
|
|
6266
|
-
method: "POST",
|
|
6267
|
-
headers: { "Content-Type": "application/json" },
|
|
6268
|
-
body
|
|
6269
|
-
}).catch(() => {
|
|
6270
|
-
}).finally(() => pending.delete(promise));
|
|
6271
|
-
pending.add(promise);
|
|
6272
|
-
}
|
|
6273
|
-
async function flushAnalytics(timeoutMs = 1500) {
|
|
6274
|
-
if (pending.size === 0) return;
|
|
6275
|
-
await Promise.race([
|
|
6276
|
-
Promise.allSettled([...pending]),
|
|
6277
|
-
new Promise((resolve5) => setTimeout(resolve5, timeoutMs))
|
|
6278
|
-
]);
|
|
6279
|
-
}
|
|
6410
|
+
// src/index.ts
|
|
6411
|
+
init_analytics();
|
|
6412
|
+
init_errors();
|
|
6413
|
+
init_notify();
|
|
6280
6414
|
|
|
6281
6415
|
// src/core/upload.ts
|
|
6282
6416
|
init_esm_shims();
|
|
@@ -6287,11 +6421,11 @@ import { glob } from "glob";
|
|
|
6287
6421
|
|
|
6288
6422
|
// src/core/git.ts
|
|
6289
6423
|
init_esm_shims();
|
|
6290
|
-
import { execFile } from "child_process";
|
|
6424
|
+
import { execFile as execFile2 } from "child_process";
|
|
6291
6425
|
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
6292
6426
|
import { join as join6 } from "path";
|
|
6293
6427
|
import { promisify } from "util";
|
|
6294
|
-
var execFileAsync = promisify(
|
|
6428
|
+
var execFileAsync = promisify(execFile2);
|
|
6295
6429
|
var GIT_INFO_FILE = ".git-info.json";
|
|
6296
6430
|
async function git(projectRoot, args) {
|
|
6297
6431
|
try {
|
|
@@ -6506,7 +6640,7 @@ var STEP_INTROS = {
|
|
|
6506
6640
|
recipeBuilder: "Helping you wire up small helpers that create and clean up test data in your own database. We give you a copy-paste guide for each one and test it live against your app running locally - you deploy later, once everything passes.",
|
|
6507
6641
|
testGenerator: "Writing the actual end-to-end tests, covering every page and feature with depth proportional to its complexity."
|
|
6508
6642
|
};
|
|
6509
|
-
async function runStep(step, outputDir, state, config, projectContext, nonInteractive) {
|
|
6643
|
+
async function runStep(step, outputDir, state, config, projectContext, nonInteractive, retryGuidance) {
|
|
6510
6644
|
const label = STEP_LABELS[step];
|
|
6511
6645
|
p9.note(STEP_INTROS[step], `Step: ${label}`);
|
|
6512
6646
|
const stepStartedAt = Date.now();
|
|
@@ -6539,7 +6673,8 @@ async function runStep(step, outputDir, state, config, projectContext, nonIntera
|
|
|
6539
6673
|
outputDir,
|
|
6540
6674
|
modelId: config.modelId,
|
|
6541
6675
|
projectContext,
|
|
6542
|
-
nonInteractive
|
|
6676
|
+
nonInteractive,
|
|
6677
|
+
retryGuidance
|
|
6543
6678
|
});
|
|
6544
6679
|
break;
|
|
6545
6680
|
}
|
|
@@ -6550,7 +6685,8 @@ async function runStep(step, outputDir, state, config, projectContext, nonIntera
|
|
|
6550
6685
|
outputDir,
|
|
6551
6686
|
modelId: config.modelId,
|
|
6552
6687
|
projectContext,
|
|
6553
|
-
nonInteractive
|
|
6688
|
+
nonInteractive,
|
|
6689
|
+
retryGuidance
|
|
6554
6690
|
});
|
|
6555
6691
|
break;
|
|
6556
6692
|
}
|
|
@@ -6562,7 +6698,8 @@ async function runStep(step, outputDir, state, config, projectContext, nonIntera
|
|
|
6562
6698
|
modelId: config.modelId,
|
|
6563
6699
|
config,
|
|
6564
6700
|
projectContext,
|
|
6565
|
-
nonInteractive
|
|
6701
|
+
nonInteractive,
|
|
6702
|
+
retryGuidance
|
|
6566
6703
|
});
|
|
6567
6704
|
break;
|
|
6568
6705
|
}
|
|
@@ -6574,7 +6711,8 @@ async function runStep(step, outputDir, state, config, projectContext, nonIntera
|
|
|
6574
6711
|
modelId: config.modelId,
|
|
6575
6712
|
config,
|
|
6576
6713
|
projectContext,
|
|
6577
|
-
nonInteractive
|
|
6714
|
+
nonInteractive,
|
|
6715
|
+
retryGuidance
|
|
6578
6716
|
});
|
|
6579
6717
|
break;
|
|
6580
6718
|
}
|
|
@@ -6588,7 +6726,8 @@ async function runStep(step, outputDir, state, config, projectContext, nonIntera
|
|
|
6588
6726
|
config,
|
|
6589
6727
|
projectContext,
|
|
6590
6728
|
nonInteractive,
|
|
6591
|
-
pages
|
|
6729
|
+
pages,
|
|
6730
|
+
retryGuidance
|
|
6592
6731
|
});
|
|
6593
6732
|
break;
|
|
6594
6733
|
}
|
|
@@ -6600,6 +6739,7 @@ async function runStep(step, outputDir, state, config, projectContext, nonIntera
|
|
|
6600
6739
|
} else {
|
|
6601
6740
|
state = await markStep(outputDir, state, step, "failed");
|
|
6602
6741
|
p9.log.error(`Failed: ${label} \u2014 ${result.summary}`);
|
|
6742
|
+
trackError(new Error(result.summary), { step, source: "step_result" });
|
|
6603
6743
|
}
|
|
6604
6744
|
} else {
|
|
6605
6745
|
state = await markStep(outputDir, state, step, "done");
|
|
@@ -6609,6 +6749,9 @@ async function runStep(step, outputDir, state, config, projectContext, nonIntera
|
|
|
6609
6749
|
state = await markStep(outputDir, state, step, "failed");
|
|
6610
6750
|
const message = err instanceof Error ? err.message : String(err);
|
|
6611
6751
|
p9.log.error(`Failed: ${label} \u2014 ${message}`);
|
|
6752
|
+
console.error(`\x1B[2m${formatException(err)}\x1B[0m`);
|
|
6753
|
+
p9.log.info("If you report this, please include the error output above.");
|
|
6754
|
+
trackError(err, { step, source: "step_exception" });
|
|
6612
6755
|
}
|
|
6613
6756
|
track("cli_step_completed", {
|
|
6614
6757
|
step,
|
|
@@ -6617,6 +6760,37 @@ async function runStep(step, outputDir, state, config, projectContext, nonIntera
|
|
|
6617
6760
|
});
|
|
6618
6761
|
return state;
|
|
6619
6762
|
}
|
|
6763
|
+
async function promptStepFailure(label) {
|
|
6764
|
+
notify("Autonoma", `${label} failed \u2014 action needed`);
|
|
6765
|
+
const action = await p9.select({
|
|
6766
|
+
message: "This step failed. What would you like to do?",
|
|
6767
|
+
options: [
|
|
6768
|
+
{ value: "retry", label: "Retry this step", hint: "Run it again from the top" },
|
|
6769
|
+
{ value: "guidance", label: "Retry with guidance", hint: "Tell the agent what went wrong or what to focus on" },
|
|
6770
|
+
{ value: "exit", label: "Stop here (progress saved)", hint: "Resume later with --resume" }
|
|
6771
|
+
]
|
|
6772
|
+
});
|
|
6773
|
+
if (p9.isCancel(action) || action === "exit") return { kind: "exit" };
|
|
6774
|
+
if (action === "retry") return { kind: "retry" };
|
|
6775
|
+
const guidance = await p9.text({
|
|
6776
|
+
message: "What should the agent do differently?",
|
|
6777
|
+
placeholder: "e.g. the part that failed, or what to focus on"
|
|
6778
|
+
});
|
|
6779
|
+
if (p9.isCancel(guidance)) return { kind: "exit" };
|
|
6780
|
+
const trimmed = guidance.trim();
|
|
6781
|
+
return { kind: "retry", guidance: trimmed || void 0 };
|
|
6782
|
+
}
|
|
6783
|
+
async function runStepWithRecovery(step, outputDir, state, config, projectContext, nonInteractive) {
|
|
6784
|
+
let guidance;
|
|
6785
|
+
while (true) {
|
|
6786
|
+
state = await runStep(step, outputDir, state, config, projectContext, nonInteractive, guidance);
|
|
6787
|
+
if (state.steps[step] !== "failed" || nonInteractive) return state;
|
|
6788
|
+
const action = await promptStepFailure(STEP_LABELS[step]);
|
|
6789
|
+
if (action.kind === "exit") return state;
|
|
6790
|
+
guidance = action.guidance;
|
|
6791
|
+
track("cli_step_retried", { step, with_guidance: guidance != null });
|
|
6792
|
+
}
|
|
6793
|
+
}
|
|
6620
6794
|
async function showStatus(outputDir) {
|
|
6621
6795
|
const state = await loadState(outputDir);
|
|
6622
6796
|
console.log("\nPipeline Status:");
|
|
@@ -6794,7 +6968,13 @@ or reveal hidden files (macOS: Cmd+Shift+. ) to see it.`,
|
|
|
6794
6968
|
p9.log.error("Cannot run test generation yet \u2014 the scenario recipe step must complete first.");
|
|
6795
6969
|
return;
|
|
6796
6970
|
}
|
|
6797
|
-
state = await
|
|
6971
|
+
state = await runStepWithRecovery(targetStep, outputDir, state, config, projectContext, nonInteractive);
|
|
6972
|
+
if (state.steps[targetStep] === "failed") {
|
|
6973
|
+
const retryCommand = `autonoma-planner --step ${targetStep}` + (args.project ? ` --project ${args.project}` : "");
|
|
6974
|
+
p9.log.warn(`Your progress is saved. To retry this step, run:
|
|
6975
|
+
${retryCommand}`);
|
|
6976
|
+
process.exitCode = 1;
|
|
6977
|
+
}
|
|
6798
6978
|
p9.outro("Done");
|
|
6799
6979
|
return;
|
|
6800
6980
|
}
|
|
@@ -6812,12 +6992,15 @@ or reveal hidden files (macOS: Cmd+Shift+. ) to see it.`,
|
|
|
6812
6992
|
try {
|
|
6813
6993
|
for (let i = startIdx; i < steps.length; i++) {
|
|
6814
6994
|
const step = steps[i];
|
|
6815
|
-
state = await
|
|
6995
|
+
state = await runStepWithRecovery(step, outputDir, state, config, projectContext, nonInteractive);
|
|
6816
6996
|
if (state.steps[step] === "paused") {
|
|
6817
6997
|
break;
|
|
6818
6998
|
}
|
|
6819
6999
|
if (state.steps[step] === "failed") {
|
|
6820
7000
|
p9.log.error("Pipeline stopped due to failure.");
|
|
7001
|
+
p9.log.warn(`Your progress is saved. To retry this step, run:
|
|
7002
|
+
${resumeCommand}`);
|
|
7003
|
+
process.exitCode = 1;
|
|
6821
7004
|
break;
|
|
6822
7005
|
}
|
|
6823
7006
|
const skipConfirmAfter = ["pagesFinder"];
|
|
@@ -6850,14 +7033,17 @@ Continue?`
|
|
|
6850
7033
|
} catch (err) {
|
|
6851
7034
|
const message = err instanceof Error ? err.message : String(err);
|
|
6852
7035
|
p9.log.error(`Failed to upload artifacts: ${message}`);
|
|
7036
|
+
console.error(`\x1B[2m${formatException(err)}\x1B[0m`);
|
|
6853
7037
|
p9.log.info(`Your artifacts are saved in ${outputDir}. Re-run the CLI to retry the upload.`);
|
|
6854
7038
|
track("cli_artifacts_upload_failed", { message });
|
|
7039
|
+
trackError(err, { source: "artifact_upload" });
|
|
6855
7040
|
}
|
|
6856
7041
|
}
|
|
6857
7042
|
p9.outro("Done");
|
|
6858
7043
|
}
|
|
6859
7044
|
main().then(() => flushAnalytics()).catch(async (err) => {
|
|
6860
7045
|
console.error(err);
|
|
7046
|
+
trackError(err, { source: "uncaught" }, false);
|
|
6861
7047
|
await flushAnalytics();
|
|
6862
7048
|
process.exit(1);
|
|
6863
7049
|
});
|