@tryarcanist/cli 0.1.79 → 0.1.81
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 +81 -42
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -200,7 +200,7 @@ function validateApiUrl(url) {
|
|
|
200
200
|
// src/runtime.ts
|
|
201
201
|
import { randomUUID } from "crypto";
|
|
202
202
|
import { createInterface } from "readline/promises";
|
|
203
|
-
var ANSI_CONTROL_SEQUENCE = /\u001b\[[0-9
|
|
203
|
+
var ANSI_CONTROL_SEQUENCE = /\u001b\[[0-9:;<=>?]*[ -/]*[@-~]/g;
|
|
204
204
|
function getRuntimeOptions(command, options = {}) {
|
|
205
205
|
const globals = command?.optsWithGlobals?.();
|
|
206
206
|
const merged = { ...globals, ...options };
|
|
@@ -392,7 +392,15 @@ function sleep(ms) {
|
|
|
392
392
|
var MIN_WATCH_POLL_INTERVAL_MS = 1;
|
|
393
393
|
var DEFAULT_WATCH_POLL_INTERVAL_MS = 1e3;
|
|
394
394
|
var WATCH_REPLAY_PAGE_SIZE = 200;
|
|
395
|
-
var WATCH_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
395
|
+
var WATCH_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
396
|
+
"idle",
|
|
397
|
+
"completed",
|
|
398
|
+
"blocked",
|
|
399
|
+
"failed",
|
|
400
|
+
"stopped",
|
|
401
|
+
"stopped_resumable",
|
|
402
|
+
"archived"
|
|
403
|
+
]);
|
|
396
404
|
|
|
397
405
|
// src/uploads.ts
|
|
398
406
|
import { readFile } from "fs/promises";
|
|
@@ -426,6 +434,27 @@ function validateUploadedName(name, kind) {
|
|
|
426
434
|
function trimNamedItems(items) {
|
|
427
435
|
return items.map((item) => ({ ...item, name: item.name.trim() }));
|
|
428
436
|
}
|
|
437
|
+
function validateUploadItems({
|
|
438
|
+
items,
|
|
439
|
+
existingNames = [],
|
|
440
|
+
kind,
|
|
441
|
+
max,
|
|
442
|
+
label,
|
|
443
|
+
normalizeItems,
|
|
444
|
+
validateItem
|
|
445
|
+
}) {
|
|
446
|
+
const normalized = normalizeItems ? normalizeItems(items) : [...items];
|
|
447
|
+
const deduped = deduplicateByName(normalized, existingNames);
|
|
448
|
+
const capacityError = checkUploadCapacity(existingNames.length, deduped.length, max, label);
|
|
449
|
+
if (capacityError) return fail(capacityError);
|
|
450
|
+
for (const item of deduped) {
|
|
451
|
+
const nameError = validateUploadedName(item.name, kind);
|
|
452
|
+
if (nameError) return fail(nameError);
|
|
453
|
+
const itemError = validateItem(item);
|
|
454
|
+
if (itemError) return fail(itemError);
|
|
455
|
+
}
|
|
456
|
+
return ok(deduped);
|
|
457
|
+
}
|
|
429
458
|
function hasNullBytes(content) {
|
|
430
459
|
return content.slice(0, 8192).includes("\0");
|
|
431
460
|
}
|
|
@@ -447,22 +476,24 @@ function deduplicateByName(items, existingNames = []) {
|
|
|
447
476
|
return deduped;
|
|
448
477
|
}
|
|
449
478
|
function validateUploadedFilePayload(files, existingNames = []) {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
479
|
+
return validateUploadItems({
|
|
480
|
+
items: files,
|
|
481
|
+
existingNames,
|
|
482
|
+
kind: "file",
|
|
483
|
+
max: MAX_UPLOADED_FILES,
|
|
484
|
+
label: "uploaded files",
|
|
485
|
+
normalizeItems: trimNamedItems,
|
|
486
|
+
validateItem: (file) => {
|
|
487
|
+
const byteLength = new TextEncoder().encode(file.content).byteLength;
|
|
488
|
+
if (byteLength > MAX_UPLOADED_FILE_SIZE_BYTES) {
|
|
489
|
+
return `Uploaded file too large: ${file.name} (${byteLength} bytes, max ${MAX_UPLOADED_FILE_SIZE_BYTES})`;
|
|
490
|
+
}
|
|
491
|
+
if (hasNullBytes(file.content)) {
|
|
492
|
+
return `Binary files are not supported: ${file.name}`;
|
|
493
|
+
}
|
|
494
|
+
return null;
|
|
463
495
|
}
|
|
464
|
-
}
|
|
465
|
-
return ok(deduped);
|
|
496
|
+
});
|
|
466
497
|
}
|
|
467
498
|
|
|
468
499
|
// src/uploads.ts
|
|
@@ -708,11 +739,17 @@ function getRawSessionEventData(event) {
|
|
|
708
739
|
}
|
|
709
740
|
}
|
|
710
741
|
function normalizeRawSessionEvent(event) {
|
|
742
|
+
const data = getRawSessionEventData(event);
|
|
711
743
|
return {
|
|
744
|
+
raw: event,
|
|
712
745
|
type: getRawSessionEventKind(event),
|
|
713
|
-
data
|
|
746
|
+
data,
|
|
747
|
+
promptId: getRawSessionEventPromptId(event)
|
|
714
748
|
};
|
|
715
749
|
}
|
|
750
|
+
function normalizeRawSessionEvents(events) {
|
|
751
|
+
return events.map((event) => normalizeRawSessionEvent(event));
|
|
752
|
+
}
|
|
716
753
|
function shouldAppendTextDelta(existingText, incomingText) {
|
|
717
754
|
if (!incomingText) return false;
|
|
718
755
|
if (incomingText.length < DUPLICATE_TEXT_DELTA_MIN_CHARS) return true;
|
|
@@ -1106,8 +1143,7 @@ function applyTodoUpdate(data, state) {
|
|
|
1106
1143
|
}
|
|
1107
1144
|
function flattenSessionEvents(raw) {
|
|
1108
1145
|
const state = createFlattenState();
|
|
1109
|
-
for (const
|
|
1110
|
-
const normalized = normalizeRawSessionEvent(event);
|
|
1146
|
+
for (const normalized of normalizeRawSessionEvents(raw)) {
|
|
1111
1147
|
const { type } = normalized;
|
|
1112
1148
|
const data = normalized.data;
|
|
1113
1149
|
switch (type) {
|
|
@@ -1184,47 +1220,47 @@ function partitionEventsByPrompt(allEvents, promptIds) {
|
|
|
1184
1220
|
const promptSet = new Set(promptIds);
|
|
1185
1221
|
const buckets = new Map(promptIds.map((id) => [id, []]));
|
|
1186
1222
|
let currentPromptId = null;
|
|
1187
|
-
for (const event of allEvents) {
|
|
1188
|
-
const eventPromptId =
|
|
1223
|
+
for (const event of normalizeRawSessionEvents(allEvents)) {
|
|
1224
|
+
const eventPromptId = event.promptId;
|
|
1189
1225
|
const explicitPromptId = typeof eventPromptId === "string" && promptSet.has(eventPromptId) ? eventPromptId : null;
|
|
1190
|
-
if (
|
|
1226
|
+
if (event.type === "prompt_processing") {
|
|
1191
1227
|
currentPromptId = explicitPromptId;
|
|
1192
1228
|
}
|
|
1193
1229
|
const targetPromptId = explicitPromptId ?? currentPromptId;
|
|
1194
1230
|
if (targetPromptId) {
|
|
1195
1231
|
const bucket = buckets.get(targetPromptId);
|
|
1196
|
-
if (bucket) bucket.push(event);
|
|
1232
|
+
if (bucket) bucket.push(event.raw);
|
|
1197
1233
|
}
|
|
1198
1234
|
}
|
|
1199
1235
|
return buckets;
|
|
1200
1236
|
}
|
|
1201
|
-
function
|
|
1202
|
-
for (let index =
|
|
1203
|
-
const event =
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
const history = getRawSessionEventData(event)?.history;
|
|
1237
|
+
function getEmbeddedTerminalHistoryFromNormalized(normalizedEvents) {
|
|
1238
|
+
for (let index = normalizedEvents.length - 1; index >= 0; index--) {
|
|
1239
|
+
const event = normalizedEvents[index];
|
|
1240
|
+
if (event.type !== "prompt_completed" && event.type !== "prompt_failed") continue;
|
|
1241
|
+
const history = event.data?.history;
|
|
1207
1242
|
if (!Array.isArray(history) || history.length === 0) return null;
|
|
1208
1243
|
return history;
|
|
1209
1244
|
}
|
|
1210
1245
|
return null;
|
|
1211
1246
|
}
|
|
1212
1247
|
function promptActivityKey(event) {
|
|
1213
|
-
const data =
|
|
1248
|
+
const data = event.data;
|
|
1214
1249
|
return [
|
|
1215
|
-
|
|
1250
|
+
event.promptId ?? "",
|
|
1216
1251
|
typeof data?.phase === "string" ? data.phase : "",
|
|
1217
1252
|
typeof data?.detail === "string" ? data.detail : ""
|
|
1218
1253
|
].join("\0");
|
|
1219
1254
|
}
|
|
1220
1255
|
function agentProgressKey(event) {
|
|
1221
|
-
const data =
|
|
1222
|
-
return [
|
|
1256
|
+
const data = event.data;
|
|
1257
|
+
return [event.promptId ?? "", typeof data?.step === "string" ? data.step : ""].join("\0");
|
|
1223
1258
|
}
|
|
1224
1259
|
function resolveAuthoritativePromptEventsWithDiagnostics(raw) {
|
|
1225
|
-
const
|
|
1226
|
-
const
|
|
1227
|
-
const
|
|
1260
|
+
const normalizedRaw = normalizeRawSessionEvents(raw);
|
|
1261
|
+
const embeddedHistory = getEmbeddedTerminalHistoryFromNormalized(normalizedRaw);
|
|
1262
|
+
const durablePromptActivity = normalizedRaw.filter((event) => event.type === "prompt_activity");
|
|
1263
|
+
const durableAgentProgress = normalizedRaw.filter((event) => event.type === "agent_progress");
|
|
1228
1264
|
if (!embeddedHistory) {
|
|
1229
1265
|
return {
|
|
1230
1266
|
events: raw,
|
|
@@ -1241,8 +1277,9 @@ function resolveAuthoritativePromptEventsWithDiagnostics(raw) {
|
|
|
1241
1277
|
}
|
|
1242
1278
|
};
|
|
1243
1279
|
}
|
|
1244
|
-
const
|
|
1245
|
-
const
|
|
1280
|
+
const normalizedEmbeddedHistory = normalizeRawSessionEvents(embeddedHistory);
|
|
1281
|
+
const embeddedPromptActivity = normalizedEmbeddedHistory.filter((event) => event.type === "prompt_activity");
|
|
1282
|
+
const embeddedAgentProgress = normalizedEmbeddedHistory.filter((event) => event.type === "agent_progress");
|
|
1246
1283
|
const embeddedPromptActivityKeys = new Set(embeddedPromptActivity.map(promptActivityKey));
|
|
1247
1284
|
const embeddedAgentProgressKeys = new Set(embeddedAgentProgress.map(agentProgressKey));
|
|
1248
1285
|
const embeddedPromptActivityCount = embeddedPromptActivity.length;
|
|
@@ -1267,7 +1304,9 @@ function resolveAuthoritativePromptEventsWithDiagnostics(raw) {
|
|
|
1267
1304
|
embeddedAgentProgressKeys.add(key);
|
|
1268
1305
|
return true;
|
|
1269
1306
|
});
|
|
1270
|
-
const missingDurableSideChannelEvents = [...missingDurablePromptActivity, ...missingDurableAgentProgress]
|
|
1307
|
+
const missingDurableSideChannelEvents = [...missingDurablePromptActivity, ...missingDurableAgentProgress].map(
|
|
1308
|
+
(event) => event.raw
|
|
1309
|
+
);
|
|
1271
1310
|
return {
|
|
1272
1311
|
events: missingDurableSideChannelEvents.length > 0 ? [...missingDurableSideChannelEvents, ...embeddedHistory] : embeddedHistory,
|
|
1273
1312
|
diagnostics: {
|
|
@@ -1847,7 +1886,7 @@ async function waitForCreatedPrompt(sessionId, promptId, sessionUrl, pollInterva
|
|
|
1847
1886
|
createdPrompt = await fetchCreatedPromptStatus(config, sessionId, promptId);
|
|
1848
1887
|
}
|
|
1849
1888
|
if (!createdPrompt) {
|
|
1850
|
-
throw new CliError("server", `Prompt status was unavailable after session ${sessionId}
|
|
1889
|
+
throw new CliError("server", `Prompt status was unavailable after session ${sessionId} reached a terminal state.`, {
|
|
1851
1890
|
hint: `Inspect with: arcanist sessions transcript ${sessionId}`
|
|
1852
1891
|
});
|
|
1853
1892
|
}
|
|
@@ -1857,7 +1896,7 @@ async function waitForCreatedPrompt(sessionId, promptId, sessionUrl, pollInterva
|
|
|
1857
1896
|
if (createdPrompt.status !== "completed") {
|
|
1858
1897
|
throw new CliError(
|
|
1859
1898
|
"server",
|
|
1860
|
-
`Prompt ${createdPrompt.promptId} did not reach a terminal success state before session ${sessionId}
|
|
1899
|
+
`Prompt ${createdPrompt.promptId} did not reach a terminal success state before session ${sessionId} reached a terminal state (status: ${createdPrompt.status}).`,
|
|
1861
1900
|
{
|
|
1862
1901
|
hint: `Inspect with: arcanist sessions transcript ${sessionId}`
|
|
1863
1902
|
}
|