@tryarcanist/cli 0.1.346 → 0.1.347
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/index.js +80 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -266,9 +266,11 @@ arcanist sessions events abc123 --after-sequence 50 --limit 250 --json
|
|
|
266
266
|
arcanist sessions events abc123 --before-sequence 100 --poll-interval 500 --json
|
|
267
267
|
arcanist sessions events abc123 --prompt-id p-123 --json
|
|
268
268
|
arcanist sessions events abc123 --follow --json
|
|
269
|
+
arcanist sessions events abc123 --follow --timeout 60000 --json
|
|
269
270
|
```
|
|
270
271
|
|
|
271
272
|
`--after` and `--before` are aliases for `--after-sequence` and `--before-sequence`.
|
|
273
|
+
`--timeout` bounds `--follow`; omit it or pass `0` for unbounded follow. Process exit is a terminal phase, not `session_idle`.
|
|
272
274
|
|
|
273
275
|
JSON mode without `--follow` returns one JSON object from `/events/history`: `{events: [...], ...}`. Canonical events carry `phase`.
|
|
274
276
|
|
package/dist/index.js
CHANGED
|
@@ -7409,7 +7409,7 @@ function isTerminalPhase(phase, _sessionKind) {
|
|
|
7409
7409
|
// package.json
|
|
7410
7410
|
var package_default = {
|
|
7411
7411
|
name: "@tryarcanist/cli",
|
|
7412
|
-
version: "0.1.
|
|
7412
|
+
version: "0.1.347",
|
|
7413
7413
|
description: "Command-line interface for Arcanist: inspect sessions, prepare Zeus environments, and trigger reviews",
|
|
7414
7414
|
type: "module",
|
|
7415
7415
|
bin: {
|
|
@@ -7659,17 +7659,27 @@ function timeoutError(timeoutMs) {
|
|
|
7659
7659
|
hint: `Increase ${HTTP_TIMEOUT_ENV} for slow links, or check the API connection.`
|
|
7660
7660
|
});
|
|
7661
7661
|
}
|
|
7662
|
+
function resolveApiTimeoutMs(init) {
|
|
7663
|
+
const httpTimeout = parseHttpTimeoutMs();
|
|
7664
|
+
if (!init) return { fetchInit: void 0, timeoutMs: httpTimeout };
|
|
7665
|
+
const { timeoutMs: requestedTimeoutMs, ...fetchInit } = init;
|
|
7666
|
+
if (requestedTimeoutMs === void 0) return { fetchInit, timeoutMs: httpTimeout };
|
|
7667
|
+
if (!Number.isFinite(requestedTimeoutMs) || requestedTimeoutMs <= 0) {
|
|
7668
|
+
return { fetchInit, timeoutMs: 1 };
|
|
7669
|
+
}
|
|
7670
|
+
return { fetchInit, timeoutMs: Math.max(1, Math.min(httpTimeout, requestedTimeoutMs)) };
|
|
7671
|
+
}
|
|
7662
7672
|
async function apiRequest(connection, path, init, read) {
|
|
7663
|
-
const timeoutMs =
|
|
7673
|
+
const { fetchInit, timeoutMs } = resolveApiTimeoutMs(init);
|
|
7664
7674
|
const controller = new AbortController();
|
|
7665
7675
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
7666
7676
|
try {
|
|
7667
|
-
const headers = new Headers(
|
|
7677
|
+
const headers = new Headers(fetchInit?.headers);
|
|
7668
7678
|
headers.set("Content-Type", "application/json");
|
|
7669
7679
|
headers.set("User-Agent", CLI_USER_AGENT);
|
|
7670
7680
|
if (connection.token) headers.set("Authorization", `Bearer ${connection.token}`);
|
|
7671
7681
|
const res = await fetch(`${normalizeBaseUrl(connection.apiUrl)}${path}`, {
|
|
7672
|
-
...
|
|
7682
|
+
...fetchInit,
|
|
7673
7683
|
headers,
|
|
7674
7684
|
signal: controller.signal
|
|
7675
7685
|
});
|
|
@@ -24727,10 +24737,14 @@ async function drainTerminalBuildLogs(config2, businessId, buildId, options) {
|
|
|
24727
24737
|
}
|
|
24728
24738
|
}
|
|
24729
24739
|
async function waitForBuild(config2, businessId, buildId, options) {
|
|
24730
|
-
let afterSequence;
|
|
24740
|
+
let afterSequence = options.afterSequence;
|
|
24731
24741
|
for (; ; ) {
|
|
24732
24742
|
if (options.follow) {
|
|
24733
|
-
const result = await fetchAndEmitBuildLogs(config2, businessId, buildId, {
|
|
24743
|
+
const result = await fetchAndEmitBuildLogs(config2, businessId, buildId, {
|
|
24744
|
+
afterSequence,
|
|
24745
|
+
limit: options.limit,
|
|
24746
|
+
json: options.json
|
|
24747
|
+
});
|
|
24734
24748
|
afterSequence = result.afterSequence;
|
|
24735
24749
|
}
|
|
24736
24750
|
const status = sandboxLayerCliBuildRequestResponseSchema.parse(
|
|
@@ -25009,24 +25023,29 @@ async function sandboxLogsCommand(buildId, options = {}, command) {
|
|
|
25009
25023
|
if (limit != null && (!Number.isInteger(limit) || limit < 1)) {
|
|
25010
25024
|
throw new CliError("user", "--limit must be a positive integer.");
|
|
25011
25025
|
}
|
|
25012
|
-
|
|
25013
|
-
|
|
25014
|
-
|
|
25015
|
-
|
|
25016
|
-
|
|
25017
|
-
if (isJson(command, options)) writeJson(options.follow ? { type: "logs", logs: payload.logs } : payload);
|
|
25018
|
-
else printLogs(payload.logs);
|
|
25019
|
-
}
|
|
25020
|
-
if (!options.follow) return;
|
|
25021
|
-
if (payload.logs.length > 0) afterSequence = payload.logs[payload.logs.length - 1].sequence;
|
|
25022
|
-
await sleep(
|
|
25023
|
-
parsePollInterval(options.pollInterval, {
|
|
25026
|
+
const json2 = isJson(command, options);
|
|
25027
|
+
if (options.follow) {
|
|
25028
|
+
const finalBuild = await waitForBuild(config2, businessId, buildId, {
|
|
25029
|
+
follow: true,
|
|
25030
|
+
pollIntervalMs: parsePollInterval(options.pollInterval, {
|
|
25024
25031
|
defaultMs: DEFAULT_POLL_INTERVAL_MS,
|
|
25025
25032
|
minMs: MIN_POLL_INTERVAL_MS,
|
|
25026
25033
|
maxMs: null
|
|
25027
|
-
})
|
|
25028
|
-
|
|
25034
|
+
}),
|
|
25035
|
+
json: json2,
|
|
25036
|
+
afterSequence,
|
|
25037
|
+
limit
|
|
25038
|
+
});
|
|
25039
|
+
if (json2) writeJson({ type: "build", buildRequest: finalBuild });
|
|
25040
|
+
else printTerminalBuildSummary(finalBuild);
|
|
25041
|
+
if (finalBuild.status !== "completed") process.exitCode = 1;
|
|
25042
|
+
return;
|
|
25029
25043
|
}
|
|
25044
|
+
const payload = sandboxLayerCliBuildLogsResponseSchema.parse(
|
|
25045
|
+
await apiFetch(config2, buildLogsPath(businessId, buildId, { afterSequence, limit }))
|
|
25046
|
+
);
|
|
25047
|
+
if (json2) writeJson(payload);
|
|
25048
|
+
else printLogs(payload.logs);
|
|
25030
25049
|
}
|
|
25031
25050
|
async function sandboxAssignDefaultCommand(sourceRepoArg, options = {}, command) {
|
|
25032
25051
|
const { config: config2 } = resolveBusinessContext(command, options);
|
|
@@ -26640,7 +26659,20 @@ function parseNonNegativeInteger(raw, name, defaultValue) {
|
|
|
26640
26659
|
if (!/^\d+$/.test(raw)) {
|
|
26641
26660
|
throw new CliError("user", `${name} must be a non-negative integer.`);
|
|
26642
26661
|
}
|
|
26643
|
-
|
|
26662
|
+
const value = Number(raw);
|
|
26663
|
+
if (!Number.isSafeInteger(value)) {
|
|
26664
|
+
throw new CliError("user", `${name} must be a non-negative integer.`);
|
|
26665
|
+
}
|
|
26666
|
+
return value;
|
|
26667
|
+
}
|
|
26668
|
+
function throwIfFollowTimedOut(deadline) {
|
|
26669
|
+
if (deadline !== null && Date.now() >= deadline) {
|
|
26670
|
+
throw new CliError("server", "Timed out waiting for session events.");
|
|
26671
|
+
}
|
|
26672
|
+
}
|
|
26673
|
+
function remainingFollowMs(deadline) {
|
|
26674
|
+
if (deadline === null) return void 0;
|
|
26675
|
+
return Math.max(0, deadline - Date.now());
|
|
26644
26676
|
}
|
|
26645
26677
|
function formatStatusLine(status) {
|
|
26646
26678
|
const label = status.phase ?? "unknown";
|
|
@@ -26690,6 +26722,8 @@ async function watchCommand(sessionId, options, command) {
|
|
|
26690
26722
|
const pollIntervalMs = parsePollInterval(options.pollInterval);
|
|
26691
26723
|
const initialAfterSequence = parseNonNegativeInteger(options.afterSequence, "--after-sequence", 0);
|
|
26692
26724
|
const pageSize = parseNonNegativeInteger(options.limit, "--limit", WATCH_REPLAY_PAGE_SIZE);
|
|
26725
|
+
const timeoutMs = parseNonNegativeInteger(options.timeout, "--timeout", 0);
|
|
26726
|
+
const deadline = timeoutMs > 0 ? Date.now() + timeoutMs : null;
|
|
26693
26727
|
if (pageSize === 0) {
|
|
26694
26728
|
throw new CliError("user", "--limit must be greater than 0.");
|
|
26695
26729
|
}
|
|
@@ -26714,11 +26748,23 @@ async function watchCommand(sessionId, options, command) {
|
|
|
26714
26748
|
if (!json2) console.log(`Watching session ${sessionId}...`);
|
|
26715
26749
|
try {
|
|
26716
26750
|
while (true) {
|
|
26751
|
+
throwIfFollowTimedOut(deadline);
|
|
26717
26752
|
const query = new URLSearchParams({
|
|
26718
26753
|
afterSequence: String(afterSequence),
|
|
26719
26754
|
limit: String(pageSize)
|
|
26720
26755
|
});
|
|
26721
|
-
const
|
|
26756
|
+
const remainingMs = remainingFollowMs(deadline);
|
|
26757
|
+
let payload;
|
|
26758
|
+
try {
|
|
26759
|
+
payload = await apiFetchText(
|
|
26760
|
+
config2,
|
|
26761
|
+
`/api/sessions/${sessionId}/events?${query}`,
|
|
26762
|
+
remainingMs === void 0 ? void 0 : { timeoutMs: remainingMs }
|
|
26763
|
+
);
|
|
26764
|
+
} catch (err) {
|
|
26765
|
+
throwIfFollowTimedOut(deadline);
|
|
26766
|
+
throw err;
|
|
26767
|
+
}
|
|
26722
26768
|
const parsed = parseSsePayload(payload);
|
|
26723
26769
|
const receivedFullPage = parsed.events.length >= pageSize;
|
|
26724
26770
|
if (!json2 && parsed.status) {
|
|
@@ -26759,7 +26805,10 @@ async function watchCommand(sessionId, options, command) {
|
|
|
26759
26805
|
}
|
|
26760
26806
|
console.log(rendered.line);
|
|
26761
26807
|
}
|
|
26762
|
-
if (receivedFullPage)
|
|
26808
|
+
if (receivedFullPage) {
|
|
26809
|
+
throwIfFollowTimedOut(deadline);
|
|
26810
|
+
continue;
|
|
26811
|
+
}
|
|
26763
26812
|
if (parsed.status?.phase && isWatchTerminal(parsed.status.phase)) {
|
|
26764
26813
|
if (!json2 && parsed.status.phase === "completed") {
|
|
26765
26814
|
if (textOpen) {
|
|
@@ -26770,7 +26819,10 @@ async function watchCommand(sessionId, options, command) {
|
|
|
26770
26819
|
}
|
|
26771
26820
|
break;
|
|
26772
26821
|
}
|
|
26773
|
-
|
|
26822
|
+
throwIfFollowTimedOut(deadline);
|
|
26823
|
+
const sleepMs = remainingFollowMs(deadline);
|
|
26824
|
+
await sleep(sleepMs === void 0 ? pollIntervalMs : Math.min(pollIntervalMs, sleepMs));
|
|
26825
|
+
throwIfFollowTimedOut(deadline);
|
|
26774
26826
|
}
|
|
26775
26827
|
} finally {
|
|
26776
26828
|
if (textOpen) process.stdout.write("\n");
|
|
@@ -27565,7 +27617,7 @@ JSON:
|
|
|
27565
27617
|
JSON mode returns {sessions, nextCursor}. --all follows cursors until nextCursor is null.
|
|
27566
27618
|
`
|
|
27567
27619
|
).action((options, command) => listSessionsCommand(options, command));
|
|
27568
|
-
sessions.command("events").description("Read or follow session replay events").argument("<session-id>", "Session ID").option("--after-sequence <n>", "Return events after this sequence").option("--after <n>", "Alias for --after-sequence").option("--before-sequence <n>", "Return events before this sequence").option("--before <n>", "Alias for --before-sequence").option("--prompt-id <id>", "Filter events by prompt ID").option("--limit <n>", "Maximum events to return").option("--follow", "Follow events until a terminal phase").option("--poll-interval <ms>", "Polling interval in milliseconds", String(DEFAULT_WATCH_POLL_INTERVAL_MS)).addHelpText(
|
|
27620
|
+
sessions.command("events").description("Read or follow session replay events").argument("<session-id>", "Session ID").option("--after-sequence <n>", "Return events after this sequence").option("--after <n>", "Alias for --after-sequence").option("--before-sequence <n>", "Return events before this sequence").option("--before <n>", "Alias for --before-sequence").option("--prompt-id <id>", "Filter events by prompt ID").option("--limit <n>", "Maximum events to return").option("--follow", "Follow events until a terminal phase").option("--poll-interval <ms>", "Polling interval in milliseconds", String(DEFAULT_WATCH_POLL_INTERVAL_MS)).option("--timeout <ms>", "Stop following after this many milliseconds; 0 or omitted means unbounded").addHelpText(
|
|
27569
27621
|
"after",
|
|
27570
27622
|
`
|
|
27571
27623
|
Examples:
|
|
@@ -27573,10 +27625,12 @@ Examples:
|
|
|
27573
27625
|
arcanist sessions events <session-id> --after-sequence 540 --limit 250 --json
|
|
27574
27626
|
arcanist sessions events <session-id> --after 540 --limit 250 --json
|
|
27575
27627
|
arcanist sessions events <session-id> --follow --json
|
|
27628
|
+
arcanist sessions events <session-id> --follow --timeout 60000 --json
|
|
27576
27629
|
|
|
27577
27630
|
JSON:
|
|
27578
27631
|
JSON mode without --follow returns one JSON object from /events/history: {events: [...], ...}; canonical events carry phase.
|
|
27579
27632
|
--follow --json emits NDJSON, one {sequence, type, data} object per line, until a terminal phase: ${formatTerminalPhaseHelpList(TERMINAL_PHASES_ARRAY)}.
|
|
27633
|
+
--timeout bounds follow; 0 or omitted means unbounded. Process exit is a terminal phase, not session_idle.
|
|
27580
27634
|
Actionable follow types are NDJSON signals, not process-exit conditions: pr_created/pr_updated use data.prUrl; question uses data.question; prompt_completed, prompt_failed, and session_idle do not exit the process.
|
|
27581
27635
|
`
|
|
27582
27636
|
).action((sessionId, options, command) => sessionEventsCommand(sessionId, options, command));
|
|
@@ -27683,7 +27737,7 @@ sandbox.command("logs").description("Print sandbox layer build logs").argument("
|
|
|
27683
27737
|
`
|
|
27684
27738
|
JSON:
|
|
27685
27739
|
Without --follow, --json prints one object: {ok, logs}
|
|
27686
|
-
With --follow, --json emits
|
|
27740
|
+
With --follow, --json emits {type:"logs"} lines, then a terminal {type:"build"} line, and exits.
|
|
27687
27741
|
`
|
|
27688
27742
|
).action((buildId, options, command) => sandboxLogsCommand(buildId, options, command));
|
|
27689
27743
|
sandbox.command("rebuild-stale").description("Create stale sandbox template rebuild campaigns").option("--business <id>", "Business ID to scan; defaults to authenticated user's business").option("--all", "Scan all businesses").option("--dry-run", "Preview stale rebuilds without queueing provider builds").option("--yes", "Start a rebuild campaign").option("--follow", "Follow campaign progress").action((options, command) => sandboxRebuildStaleCommand(options, command));
|