@tryarcanist/cli 0.1.176 → 0.1.177

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 (3) hide show
  1. package/README.md +12 -2
  2. package/dist/index.js +94 -25
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -266,9 +266,12 @@ arcanist sessions list
266
266
  arcanist sessions list --status idle --limit 20 --json
267
267
  arcanist sessions list --search "architect agent" --repo your-org/your-repo
268
268
  arcanist sessions list --scope business --cursor <cursor>
269
+ arcanist sessions list --all --json
269
270
  ```
270
271
 
271
- JSON mode returns `{sessions, nextCursor}`. Search is metadata-only: generated titles and repo metadata.
272
+ JSON mode returns `{sessions, nextCursor}`.
273
+ `--all` follows cursors until completion and returns `nextCursor: null`.
274
+ Search is metadata-only: generated titles and repo metadata.
272
275
 
273
276
  ### `arcanist sessions search <query>`
274
277
 
@@ -276,9 +279,10 @@ JSON mode returns `{sessions, nextCursor}`. Search is metadata-only: generated t
276
279
  arcanist sessions search "architect agent"
277
280
  arcanist sessions search "mcp debugging" --repo your-org/your-repo --json
278
281
  arcanist sessions search "repo access" --status idle --scope business --limit 20 --cursor <cursor>
282
+ arcanist sessions search "repo access" --all --json
279
283
  ```
280
284
 
281
- Uses the same metadata-only index and filters as `sessions list`: `--status`, `--scope`, `--repo`, `--limit`, and `--cursor`.
285
+ Uses the same metadata-only index and filters as `sessions list`: `--status`, `--scope`, `--repo`, `--limit`, `--cursor`, and `--all`.
282
286
 
283
287
  ### `arcanist sessions events <session-id>`
284
288
 
@@ -309,8 +313,11 @@ Renders a session transcript from the stored session export.
309
313
  ```bash
310
314
  arcanist sessions transcript abc123
311
315
  arcanist sessions transcript abc123 --json
316
+ arcanist sessions transcript abc123 --last 20
312
317
  ```
313
318
 
319
+ `--last <n>` renders only the last `n` stored transcript events after fetching the session export.
320
+
314
321
  ### `arcanist sessions watch <session-id>`
315
322
 
316
323
  Watches session activity until the session becomes idle. For machine-readable streaming, prefer `arcanist sessions events --follow --json`.
@@ -404,8 +411,11 @@ arcanist automations delete rule_123 --yes --json
404
411
  arcanist tokens list
405
412
  arcanist tokens list --limit 10 --json
406
413
  arcanist tokens list --cursor <cursor> --json
414
+ arcanist tokens list --all --json
407
415
  ```
408
416
 
417
+ `--all` follows cursors until completion and returns `nextCursor: null` in JSON mode.
418
+
409
419
  ### `arcanist tokens create`
410
420
 
411
421
  Creates a CLI token and prints the plaintext token exactly once.
package/dist/index.js CHANGED
@@ -4711,20 +4711,35 @@ async function sandboxUnassignRepoCommand(targetRepoArg, options = {}, command)
4711
4711
  }
4712
4712
 
4713
4713
  // src/commands/sessions.ts
4714
+ var MAX_ALL_PAGES = 1e3;
4714
4715
  async function listSessionsCommand(options, command) {
4715
4716
  const runtime = getRuntimeOptions(command, options);
4716
4717
  const config = requireConfig(runtime);
4717
- const query = new URLSearchParams();
4718
- if (options.status) query.set("status", options.status);
4719
- if (options.scope) query.set("scope", options.scope);
4720
- if (options.search) query.set("q", options.search);
4721
- if (options.repo) query.set("repo", options.repo);
4722
- if (options.limit) query.set("limit", options.limit);
4723
- if (options.cursor) query.set("cursor", options.cursor);
4724
- const payload = await apiFetch(
4725
- config,
4726
- `/api/sessions${query.size ? `?${query.toString()}` : ""}`
4727
- );
4718
+ const sessions2 = [];
4719
+ let cursor = options.cursor;
4720
+ let nextCursor = null;
4721
+ let pageCount = 0;
4722
+ do {
4723
+ pageCount += 1;
4724
+ if (options.all === true && pageCount > MAX_ALL_PAGES) {
4725
+ throw new CliError("user", `sessions list --all exceeded ${MAX_ALL_PAGES} pages without reaching the end.`);
4726
+ }
4727
+ const query = new URLSearchParams();
4728
+ if (options.status) query.set("status", options.status);
4729
+ if (options.scope) query.set("scope", options.scope);
4730
+ if (options.search) query.set("q", options.search);
4731
+ if (options.repo) query.set("repo", options.repo);
4732
+ if (options.limit) query.set("limit", options.limit);
4733
+ if (cursor) query.set("cursor", cursor);
4734
+ const payload2 = await apiFetch(
4735
+ config,
4736
+ `/api/sessions${query.size ? `?${query.toString()}` : ""}`
4737
+ );
4738
+ sessions2.push(...payload2.sessions);
4739
+ nextCursor = payload2.nextCursor;
4740
+ cursor = nextCursor ?? void 0;
4741
+ } while (options.all === true && nextCursor);
4742
+ const payload = { sessions: sessions2, nextCursor: options.all === true ? null : nextCursor };
4728
4743
  if (isJson(command, options)) {
4729
4744
  writeJson(payload);
4730
4745
  return;
@@ -4953,15 +4968,30 @@ async function deleteTestCredentialCommand(repo, name, options, command) {
4953
4968
  }
4954
4969
 
4955
4970
  // src/commands/tokens.ts
4971
+ var MAX_ALL_PAGES2 = 1e3;
4956
4972
  async function listTokensCommand(options, command) {
4957
4973
  const { config } = resolveBusinessContext(command, options);
4958
- const query = new URLSearchParams();
4959
- if (options.limit) query.set("limit", options.limit);
4960
- if (options.cursor) query.set("cursor", options.cursor);
4961
- const payload = await apiFetch(
4962
- config,
4963
- `/api/cli-tokens${query.size ? `?${query.toString()}` : ""}`
4964
- );
4974
+ const data = [];
4975
+ let cursor = options.cursor;
4976
+ let nextCursor = null;
4977
+ let pageCount = 0;
4978
+ do {
4979
+ pageCount += 1;
4980
+ if (options.all === true && pageCount > MAX_ALL_PAGES2) {
4981
+ throw new CliError("user", `tokens list --all exceeded ${MAX_ALL_PAGES2} pages without reaching the end.`);
4982
+ }
4983
+ const query = new URLSearchParams();
4984
+ if (options.limit) query.set("limit", options.limit);
4985
+ if (cursor) query.set("cursor", cursor);
4986
+ const payload2 = await apiFetch(
4987
+ config,
4988
+ `/api/cli-tokens${query.size ? `?${query.toString()}` : ""}`
4989
+ );
4990
+ data.push(...payload2.data);
4991
+ nextCursor = payload2.nextCursor;
4992
+ cursor = nextCursor ?? void 0;
4993
+ } while (options.all === true && nextCursor);
4994
+ const payload = { data, nextCursor: options.all === true ? null : nextCursor };
4965
4995
  emit(command, options, payload, (listPayload) => {
4966
4996
  if (listPayload.data.length === 0) {
4967
4997
  console.log("No CLI tokens found.");
@@ -5025,8 +5055,44 @@ async function revokeTokenCommand(tokenId, options, command) {
5025
5055
  // src/commands/transcript.ts
5026
5056
  async function transcriptCommand(sessionId, options, command) {
5027
5057
  const { config } = resolveBusinessContext(command, options);
5058
+ const last = parseLast(options.last);
5028
5059
  const exportData = await apiFetch(config, `/api/sessions/${sessionId}/export`);
5029
- emit(command, options, exportData, (payload) => console.log(renderSessionTranscript(payload)));
5060
+ const payload = last == null ? exportData : sliceTranscript(exportData, last, { includeBoundaryEvent: !isJson(command, options) });
5061
+ emit(command, options, payload, (data) => console.log(renderSessionTranscript(data)));
5062
+ }
5063
+ function parseLast(raw) {
5064
+ if (raw === void 0) return null;
5065
+ const parsed = Number(raw);
5066
+ if (!Number.isInteger(parsed) || parsed <= 0) throw new CliError("user", "--last must be a positive integer.");
5067
+ return parsed;
5068
+ }
5069
+ function sliceTranscript(exportData, last, options) {
5070
+ const start = Math.max(0, exportData.events.length - last);
5071
+ const boundary = findPromptBoundary(exportData.events, start);
5072
+ const tail = exportData.events.slice(start);
5073
+ const events = options.includeBoundaryEvent && boundary !== null && boundary < start ? [exportData.events[boundary], ...tail] : tail;
5074
+ const promptIds = promptIdsForEvents(events);
5075
+ if (boundary !== null) {
5076
+ const boundaryPromptId = getRawSessionEventPromptId(exportData.events[boundary]);
5077
+ if (boundaryPromptId) promptIds.add(boundaryPromptId);
5078
+ }
5079
+ const prompts = exportData.prompts.filter((prompt) => promptIds.has(prompt.id));
5080
+ return { ...exportData, prompts, events };
5081
+ }
5082
+ function findPromptBoundary(events, start) {
5083
+ for (let index = start; index >= 0; index--) {
5084
+ const event = events[index];
5085
+ if (event && getRawSessionEventKind(event) === "prompt_processing") return index;
5086
+ }
5087
+ return null;
5088
+ }
5089
+ function promptIdsForEvents(events) {
5090
+ const promptIds = /* @__PURE__ */ new Set();
5091
+ for (const event of events) {
5092
+ const promptId = getRawSessionEventPromptId(event);
5093
+ if (promptId) promptIds.add(promptId);
5094
+ }
5095
+ return promptIds;
5030
5096
  }
5031
5097
 
5032
5098
  // src/index.ts
@@ -5185,27 +5251,29 @@ JSON:
5185
5251
  JSON mode returns the raw session payload. Result fields are at .session.prUrl, .session.publishedBranch, and .session.lastBranch.
5186
5252
  `
5187
5253
  ).action((sessionId, options, command) => getSessionCommand(sessionId, options, command));
5188
- sessions.command("list").description("List sessions").option("--status <status>", "Filter by session status").option("--scope <scope>", "Session scope: mine or business").option("--search <query>", "Search session titles and repo metadata").option("--repo <repo>", "Filter by repo metadata").option("--limit <n>", "Maximum sessions to return").option("--cursor <cursor>", "Pagination cursor").addHelpText(
5254
+ sessions.command("list").description("List sessions").option("--status <status>", "Filter by session status").option("--scope <scope>", "Session scope: mine or business").option("--search <query>", "Search session titles and repo metadata").option("--repo <repo>", "Filter by repo metadata").option("--limit <n>", "Maximum sessions to return").option("--cursor <cursor>", "Pagination cursor").option("--all", "Fetch all pages").addHelpText(
5189
5255
  "after",
5190
5256
  `
5191
5257
  Examples:
5192
5258
  arcanist sessions list
5193
5259
  arcanist sessions list --status idle --json
5194
5260
  arcanist sessions list --search "architect agent" --repo owner/repo
5261
+ arcanist sessions list --all --json
5195
5262
 
5196
5263
  JSON:
5197
- JSON mode returns {sessions, nextCursor}
5264
+ JSON mode returns {sessions, nextCursor}. --all follows cursors until nextCursor is null.
5198
5265
  `
5199
5266
  ).action((options, command) => listSessionsCommand(options, command));
5200
- sessions.command("search").description("Search sessions by title and repo metadata").argument("<query>", "Search query").option("--status <status>", "Filter by session status").option("--scope <scope>", "Session scope: mine or business").option("--repo <repo>", "Filter by repo metadata").option("--limit <n>", "Maximum sessions to return").option("--cursor <cursor>", "Pagination cursor").addHelpText(
5267
+ sessions.command("search").description("Search sessions by title and repo metadata").argument("<query>", "Search query").option("--status <status>", "Filter by session status").option("--scope <scope>", "Session scope: mine or business").option("--repo <repo>", "Filter by repo metadata").option("--limit <n>", "Maximum sessions to return").option("--cursor <cursor>", "Pagination cursor").option("--all", "Fetch all pages").addHelpText(
5201
5268
  "after",
5202
5269
  `
5203
5270
  Examples:
5204
5271
  arcanist sessions search "architect agent"
5205
5272
  arcanist sessions search "mcp debugging" --repo owner/repo --json
5273
+ arcanist sessions search "repo access" --all --json
5206
5274
 
5207
5275
  JSON:
5208
- JSON mode returns {sessions, nextCursor}
5276
+ JSON mode returns {sessions, nextCursor}. --all follows cursors until nextCursor is null.
5209
5277
  `
5210
5278
  ).action((query, options, command) => searchSessionsCommand(query, options, command));
5211
5279
  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 the session is idle").option("--poll-interval <ms>", "Polling interval in milliseconds", String(DEFAULT_WATCH_POLL_INTERVAL_MS)).addHelpText(
@@ -5223,12 +5291,13 @@ JSON mode without --follow returns one JSON object from /events/history: {events
5223
5291
  Actionable follow types: pr_created/pr_updated use data.prUrl; question uses data.question; terminal types are prompt_completed, prompt_failed, and session_idle.
5224
5292
  `
5225
5293
  ).action((sessionId, options, command) => sessionEventsCommand(sessionId, options, command));
5226
- sessions.command("transcript").description("Render a session transcript").argument("<session-id>", "Session ID").addHelpText(
5294
+ sessions.command("transcript").description("Render a session transcript").argument("<session-id>", "Session ID").option("--last <n>", "Render only the last n transcript entries").addHelpText(
5227
5295
  "after",
5228
5296
  `
5229
5297
  Examples:
5230
5298
  arcanist sessions transcript <session-id>
5231
5299
  arcanist sessions transcript <session-id> --json
5300
+ arcanist sessions transcript <session-id> --last 20
5232
5301
  `
5233
5302
  ).action((sessionId, options, command) => transcriptCommand(sessionId, options, command));
5234
5303
  sessions.command("watch").description("Watch session activity until it becomes idle").argument("<session-id>", "Session ID").option("--poll-interval <ms>", "Polling interval in milliseconds", String(DEFAULT_WATCH_POLL_INTERVAL_MS)).addHelpText(
@@ -5348,7 +5417,7 @@ egress.command("add").description("Open or update a PR adding domains to the egr
5348
5417
  egress.command("sync").description("Apply the merged egress allowlist source file to the runtime business policy").option("--business <id>", "Business ID; defaults to authenticated user's business").action((options, command) => egressSyncCommand(options, command));
5349
5418
  egress.command("validate").description("Validate a local egress allowlist source file").argument("[path]", "Path to validate", ".arcanist/egress-allowlist.txt").action((path, options, command) => egressValidateCommand(path, options, command));
5350
5419
  var tokens = program.command("tokens").description("CLI token commands");
5351
- tokens.command("list").description("List CLI tokens").option("--limit <n>", "Maximum tokens to return").option("--cursor <cursor>", "Pagination cursor").action((options, command) => listTokensCommand(options, command));
5420
+ tokens.command("list").description("List CLI tokens").option("--limit <n>", "Maximum tokens to return").option("--cursor <cursor>", "Pagination cursor").option("--all", "Fetch all pages").action((options, command) => listTokensCommand(options, command));
5352
5421
  tokens.command("create").description("Create a CLI token and print it once").option("--scope <scope>", "Token scope: read or write", "read").option("--expires-in-days <days>", "Token expiry in days").option("--idempotency-key <uuid>", "Request idempotency key for safe manual retries").addHelpText(
5353
5422
  "after",
5354
5423
  `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryarcanist/cli",
3
- "version": "0.1.176",
3
+ "version": "0.1.177",
4
4
  "description": "CLI for Arcanist — create and manage coding agent sessions",
5
5
  "type": "module",
6
6
  "bin": {