@tryarcanist/cli 0.1.346 → 0.1.348
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 -33
- 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.348",
|
|
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
|
});
|
|
@@ -23874,13 +23884,6 @@ async function reviewCommand(prUrl, options = {}, command) {
|
|
|
23874
23884
|
...sandboxRuntimeBackend !== null ? { sandboxRuntimeBackend } : {}
|
|
23875
23885
|
})
|
|
23876
23886
|
});
|
|
23877
|
-
if (trigger.skipped && trigger.reason === "duplicate_diff") {
|
|
23878
|
-
emit(command, options, trigger, (payload) => {
|
|
23879
|
-
const source = payload.sourcePrUrl ? sanitizeTerminalText(payload.sourcePrUrl) : "a prior pull request";
|
|
23880
|
-
console.log(`Zeus review skipped: this pull request has the same diff as ${source}.`);
|
|
23881
|
-
});
|
|
23882
|
-
return;
|
|
23883
|
-
}
|
|
23884
23887
|
if (!options.wait || trigger.cached) {
|
|
23885
23888
|
emit(command, options, trigger, (payload) => {
|
|
23886
23889
|
if (payload.cached) console.log(`Zeus review already completed: ${payload.verdict ?? "unknown"}.`);
|
|
@@ -24727,10 +24730,14 @@ async function drainTerminalBuildLogs(config2, businessId, buildId, options) {
|
|
|
24727
24730
|
}
|
|
24728
24731
|
}
|
|
24729
24732
|
async function waitForBuild(config2, businessId, buildId, options) {
|
|
24730
|
-
let afterSequence;
|
|
24733
|
+
let afterSequence = options.afterSequence;
|
|
24731
24734
|
for (; ; ) {
|
|
24732
24735
|
if (options.follow) {
|
|
24733
|
-
const result = await fetchAndEmitBuildLogs(config2, businessId, buildId, {
|
|
24736
|
+
const result = await fetchAndEmitBuildLogs(config2, businessId, buildId, {
|
|
24737
|
+
afterSequence,
|
|
24738
|
+
limit: options.limit,
|
|
24739
|
+
json: options.json
|
|
24740
|
+
});
|
|
24734
24741
|
afterSequence = result.afterSequence;
|
|
24735
24742
|
}
|
|
24736
24743
|
const status = sandboxLayerCliBuildRequestResponseSchema.parse(
|
|
@@ -25009,24 +25016,29 @@ async function sandboxLogsCommand(buildId, options = {}, command) {
|
|
|
25009
25016
|
if (limit != null && (!Number.isInteger(limit) || limit < 1)) {
|
|
25010
25017
|
throw new CliError("user", "--limit must be a positive integer.");
|
|
25011
25018
|
}
|
|
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, {
|
|
25019
|
+
const json2 = isJson(command, options);
|
|
25020
|
+
if (options.follow) {
|
|
25021
|
+
const finalBuild = await waitForBuild(config2, businessId, buildId, {
|
|
25022
|
+
follow: true,
|
|
25023
|
+
pollIntervalMs: parsePollInterval(options.pollInterval, {
|
|
25024
25024
|
defaultMs: DEFAULT_POLL_INTERVAL_MS,
|
|
25025
25025
|
minMs: MIN_POLL_INTERVAL_MS,
|
|
25026
25026
|
maxMs: null
|
|
25027
|
-
})
|
|
25028
|
-
|
|
25027
|
+
}),
|
|
25028
|
+
json: json2,
|
|
25029
|
+
afterSequence,
|
|
25030
|
+
limit
|
|
25031
|
+
});
|
|
25032
|
+
if (json2) writeJson({ type: "build", buildRequest: finalBuild });
|
|
25033
|
+
else printTerminalBuildSummary(finalBuild);
|
|
25034
|
+
if (finalBuild.status !== "completed") process.exitCode = 1;
|
|
25035
|
+
return;
|
|
25029
25036
|
}
|
|
25037
|
+
const payload = sandboxLayerCliBuildLogsResponseSchema.parse(
|
|
25038
|
+
await apiFetch(config2, buildLogsPath(businessId, buildId, { afterSequence, limit }))
|
|
25039
|
+
);
|
|
25040
|
+
if (json2) writeJson(payload);
|
|
25041
|
+
else printLogs(payload.logs);
|
|
25030
25042
|
}
|
|
25031
25043
|
async function sandboxAssignDefaultCommand(sourceRepoArg, options = {}, command) {
|
|
25032
25044
|
const { config: config2 } = resolveBusinessContext(command, options);
|
|
@@ -26640,7 +26652,20 @@ function parseNonNegativeInteger(raw, name, defaultValue) {
|
|
|
26640
26652
|
if (!/^\d+$/.test(raw)) {
|
|
26641
26653
|
throw new CliError("user", `${name} must be a non-negative integer.`);
|
|
26642
26654
|
}
|
|
26643
|
-
|
|
26655
|
+
const value = Number(raw);
|
|
26656
|
+
if (!Number.isSafeInteger(value)) {
|
|
26657
|
+
throw new CliError("user", `${name} must be a non-negative integer.`);
|
|
26658
|
+
}
|
|
26659
|
+
return value;
|
|
26660
|
+
}
|
|
26661
|
+
function throwIfFollowTimedOut(deadline) {
|
|
26662
|
+
if (deadline !== null && Date.now() >= deadline) {
|
|
26663
|
+
throw new CliError("server", "Timed out waiting for session events.");
|
|
26664
|
+
}
|
|
26665
|
+
}
|
|
26666
|
+
function remainingFollowMs(deadline) {
|
|
26667
|
+
if (deadline === null) return void 0;
|
|
26668
|
+
return Math.max(0, deadline - Date.now());
|
|
26644
26669
|
}
|
|
26645
26670
|
function formatStatusLine(status) {
|
|
26646
26671
|
const label = status.phase ?? "unknown";
|
|
@@ -26690,6 +26715,8 @@ async function watchCommand(sessionId, options, command) {
|
|
|
26690
26715
|
const pollIntervalMs = parsePollInterval(options.pollInterval);
|
|
26691
26716
|
const initialAfterSequence = parseNonNegativeInteger(options.afterSequence, "--after-sequence", 0);
|
|
26692
26717
|
const pageSize = parseNonNegativeInteger(options.limit, "--limit", WATCH_REPLAY_PAGE_SIZE);
|
|
26718
|
+
const timeoutMs = parseNonNegativeInteger(options.timeout, "--timeout", 0);
|
|
26719
|
+
const deadline = timeoutMs > 0 ? Date.now() + timeoutMs : null;
|
|
26693
26720
|
if (pageSize === 0) {
|
|
26694
26721
|
throw new CliError("user", "--limit must be greater than 0.");
|
|
26695
26722
|
}
|
|
@@ -26714,11 +26741,23 @@ async function watchCommand(sessionId, options, command) {
|
|
|
26714
26741
|
if (!json2) console.log(`Watching session ${sessionId}...`);
|
|
26715
26742
|
try {
|
|
26716
26743
|
while (true) {
|
|
26744
|
+
throwIfFollowTimedOut(deadline);
|
|
26717
26745
|
const query = new URLSearchParams({
|
|
26718
26746
|
afterSequence: String(afterSequence),
|
|
26719
26747
|
limit: String(pageSize)
|
|
26720
26748
|
});
|
|
26721
|
-
const
|
|
26749
|
+
const remainingMs = remainingFollowMs(deadline);
|
|
26750
|
+
let payload;
|
|
26751
|
+
try {
|
|
26752
|
+
payload = await apiFetchText(
|
|
26753
|
+
config2,
|
|
26754
|
+
`/api/sessions/${sessionId}/events?${query}`,
|
|
26755
|
+
remainingMs === void 0 ? void 0 : { timeoutMs: remainingMs }
|
|
26756
|
+
);
|
|
26757
|
+
} catch (err) {
|
|
26758
|
+
throwIfFollowTimedOut(deadline);
|
|
26759
|
+
throw err;
|
|
26760
|
+
}
|
|
26722
26761
|
const parsed = parseSsePayload(payload);
|
|
26723
26762
|
const receivedFullPage = parsed.events.length >= pageSize;
|
|
26724
26763
|
if (!json2 && parsed.status) {
|
|
@@ -26759,7 +26798,10 @@ async function watchCommand(sessionId, options, command) {
|
|
|
26759
26798
|
}
|
|
26760
26799
|
console.log(rendered.line);
|
|
26761
26800
|
}
|
|
26762
|
-
if (receivedFullPage)
|
|
26801
|
+
if (receivedFullPage) {
|
|
26802
|
+
throwIfFollowTimedOut(deadline);
|
|
26803
|
+
continue;
|
|
26804
|
+
}
|
|
26763
26805
|
if (parsed.status?.phase && isWatchTerminal(parsed.status.phase)) {
|
|
26764
26806
|
if (!json2 && parsed.status.phase === "completed") {
|
|
26765
26807
|
if (textOpen) {
|
|
@@ -26770,7 +26812,10 @@ async function watchCommand(sessionId, options, command) {
|
|
|
26770
26812
|
}
|
|
26771
26813
|
break;
|
|
26772
26814
|
}
|
|
26773
|
-
|
|
26815
|
+
throwIfFollowTimedOut(deadline);
|
|
26816
|
+
const sleepMs = remainingFollowMs(deadline);
|
|
26817
|
+
await sleep(sleepMs === void 0 ? pollIntervalMs : Math.min(pollIntervalMs, sleepMs));
|
|
26818
|
+
throwIfFollowTimedOut(deadline);
|
|
26774
26819
|
}
|
|
26775
26820
|
} finally {
|
|
26776
26821
|
if (textOpen) process.stdout.write("\n");
|
|
@@ -27565,7 +27610,7 @@ JSON:
|
|
|
27565
27610
|
JSON mode returns {sessions, nextCursor}. --all follows cursors until nextCursor is null.
|
|
27566
27611
|
`
|
|
27567
27612
|
).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(
|
|
27613
|
+
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
27614
|
"after",
|
|
27570
27615
|
`
|
|
27571
27616
|
Examples:
|
|
@@ -27573,10 +27618,12 @@ Examples:
|
|
|
27573
27618
|
arcanist sessions events <session-id> --after-sequence 540 --limit 250 --json
|
|
27574
27619
|
arcanist sessions events <session-id> --after 540 --limit 250 --json
|
|
27575
27620
|
arcanist sessions events <session-id> --follow --json
|
|
27621
|
+
arcanist sessions events <session-id> --follow --timeout 60000 --json
|
|
27576
27622
|
|
|
27577
27623
|
JSON:
|
|
27578
27624
|
JSON mode without --follow returns one JSON object from /events/history: {events: [...], ...}; canonical events carry phase.
|
|
27579
27625
|
--follow --json emits NDJSON, one {sequence, type, data} object per line, until a terminal phase: ${formatTerminalPhaseHelpList(TERMINAL_PHASES_ARRAY)}.
|
|
27626
|
+
--timeout bounds follow; 0 or omitted means unbounded. Process exit is a terminal phase, not session_idle.
|
|
27580
27627
|
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
27628
|
`
|
|
27582
27629
|
).action((sessionId, options, command) => sessionEventsCommand(sessionId, options, command));
|
|
@@ -27683,7 +27730,7 @@ sandbox.command("logs").description("Print sandbox layer build logs").argument("
|
|
|
27683
27730
|
`
|
|
27684
27731
|
JSON:
|
|
27685
27732
|
Without --follow, --json prints one object: {ok, logs}
|
|
27686
|
-
With --follow, --json emits
|
|
27733
|
+
With --follow, --json emits {type:"logs"} lines, then a terminal {type:"build"} line, and exits.
|
|
27687
27734
|
`
|
|
27688
27735
|
).action((buildId, options, command) => sandboxLogsCommand(buildId, options, command));
|
|
27689
27736
|
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));
|