@tryarcanist/cli 0.1.141 → 0.1.143

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 +14 -11
  2. package/dist/index.js +111 -15
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -132,7 +132,7 @@ arcanist sessions create your-org/your-repo "retry-safe create" --idempotency-ke
132
132
 
133
133
  `--backend` picks the agent runtime backend: `codex` (default) or `claude_code`. `--model` must be valid for the chosen backend — codex runs OpenAI models (`gpt-5.4` default, `gpt-5.5`), `claude_code` runs Anthropic models (`claude-opus-4-8` default, `claude-sonnet-4-6`) — and the CLI rejects a mismatch before any network call. `claude_code` sessions require an Anthropic API key configured in Settings.
134
134
 
135
- `--wait` blocks until the created prompt finishes, prints the resulting PR/branch line in human-readable mode when it is already available, and exits non-zero if the prompt finishes with `status: failed`, making it suitable for cron or other schedulers that alert on command failure. `--poll-interval <ms>` tunes the completion check frequency.
135
+ `--wait` blocks until the created prompt finishes, prints the resulting PR/branch line in human-readable mode when it is already available, and exits non-zero if the prompt finishes with `status: failed`, making it suitable for cron or other schedulers that alert on command failure. JSON mode waits quietly and prints the create payload after the prompt completes successfully. `--poll-interval <ms>` tunes the completion check frequency.
136
136
 
137
137
  Use `--base-branch <branch>` to target a non-default base branch. The CLI only validates that the branch value is non-empty; branch existence is checked later by the session runtime.
138
138
 
@@ -146,7 +146,7 @@ Repeatable `--uploaded-file <path>` flags attach local UTF-8 text files to the p
146
146
 
147
147
  `--onboarding` creates an onboarding session: the agent authors the repo's `.arcanist.json`, `.arcanist/` runtime files, `ARCANIST.md`, and conditionally `.arcanist/sandbox.yaml` + `.arcanist/sandbox.layer.Dockerfile` (when the base sandbox lacks a needed toolchain), proves what it can inside its sandbox, and opens the setup PR ready for review. The onboarding behavior is driven by the bridge's canonical onboarding playbook, not the prompt, so `--onboarding` needs no prompt: `arcanist sessions create <repo> --onboarding --wait`. Any prompt supplied alongside `--onboarding` is ignored. Team use; not part of the external API surface.
148
148
 
149
- JSON mode returns `{sessionId, sessionUrl?, repoUrl, model?, agentRuntimeBackend?, reasoningEffort?, baseBranch?, promptId?}`. `sessionUrl` is emitted only when the server returns it; `agentRuntimeBackend` only when `--backend` is passed.
149
+ JSON mode returns `{sessionId, sessionUrl?, repoUrl, model?, agentRuntimeBackend?, reasoningEffort?, baseBranch?, startBranch?, onboarding?, promptId?}`. `sessionUrl` is emitted only when the server returns it; `agentRuntimeBackend` only when `--backend` is passed. With `--wait`, JSON mode also includes best-effort result fields when available: `prUrl?`, `publishedBranch?`, and `lastBranch?`.
150
150
 
151
151
  ### `arcanist sessions send <session-id> [prompt]`
152
152
 
@@ -170,7 +170,7 @@ arcanist sessions stop abc123
170
170
  arcanist sessions stop abc123 --json
171
171
  ```
172
172
 
173
- JSON mode returns `{sessionId, status}` where status is `stopping` or `already_stopped`.
173
+ JSON mode returns `{sessionId, status}`. `status` is the server stop status or, on a 409 stop-block, the block reason; it is an open set. Known values include `stopping`, `stopped`, `already_stopped`, `not_stoppable`, and lifecycle phase names.
174
174
 
175
175
  ### `arcanist sessions get <session-id>`
176
176
 
@@ -216,7 +216,13 @@ arcanist sessions events abc123 --follow --json
216
216
 
217
217
  `--after` and `--before` are aliases for `--after-sequence` and `--before-sequence`.
218
218
 
219
- Follow mode emits NDJSON, one replay event per line, until the session becomes idle.
219
+ JSON mode without `--follow` returns one JSON object from `/events/history`: `{events: [...], ...}`. Canonical events carry `phase`.
220
+
221
+ Follow mode emits NDJSON, one `{sequence, type, data}` object per line, until the session becomes idle. Actionable follow-mode signals:
222
+
223
+ - PR opened or updated: `pr_created` / `pr_updated`; URL at `data.prUrl`.
224
+ - Waiting for human input: `question`; question text at `data.question`.
225
+ - Terminal: `prompt_completed`, `prompt_failed`, and `session_idle`. Follow JSON mode suppresses lifecycle `status` frames, so key on these event names rather than `waiting_for_input`.
220
226
 
221
227
  ### `arcanist sessions transcript <session-id>`
222
228
 
@@ -329,15 +335,12 @@ arcanist sessions create your-org/your-repo "verify the new rate limiter is acti
329
335
 
330
336
  For cron, prefer `ARCANIST_TOKEN` or a logged-in `~/.arcanist/config.json` over passing `--token` on the command line.
331
337
 
332
- To capture the PR URL after a successful run, use `create --wait` for the exit code, then read the session state:
338
+ To capture the PR URL after a successful run, read the best-effort result fields from `create --wait --json`:
333
339
 
334
340
  ```bash
335
- SESSION_ID=$(arcanist sessions create your-org/your-repo "fix the flaky test" --wait --json | jq -r .sessionId)
336
- for _ in {1..20}; do
337
- PR_URL=$(arcanist sessions get "$SESSION_ID" --json | jq -r '.session.prUrl // empty')
338
- [ -n "$PR_URL" ] && break
339
- sleep 5
340
- done
341
+ RESULT=$(arcanist sessions create your-org/your-repo "fix the flaky test" --wait --json)
342
+ PR_URL=$(jq -r '.prUrl // empty' <<<"$RESULT")
343
+ SESSION_ID=$(jq -r '.sessionId' <<<"$RESULT")
341
344
  [ -n "$PR_URL" ] || { echo "PR URL not ready for $SESSION_ID" >&2; exit 1; }
342
345
  ```
343
346
 
package/dist/index.js CHANGED
@@ -83,7 +83,7 @@ function parseApiErrorBody(body) {
83
83
  }
84
84
  }
85
85
  function hintForHttpStatus(status) {
86
- if (status === 401 || status === 403) return "Run `arcanist login` or set `ARCANIST_TOKEN`.";
86
+ if (status === 401 || status === 403) return "Run `arcanist auth login` or set `ARCANIST_TOKEN`.";
87
87
  if (status === 404) return "List sessions with `arcanist sessions list`.";
88
88
  if (status === 409) return "Check the current resource state and retry the command when it is ready.";
89
89
  if (status >= 500) return "Retry later or check the control-plane logs.";
@@ -172,7 +172,7 @@ function saveConfig(config) {
172
172
  function requireConfig(overrides) {
173
173
  const config = loadConfig(overrides);
174
174
  if (!config) {
175
- throw new CliError("auth", "Not logged in.", { hint: "Run `arcanist login` or set `ARCANIST_TOKEN`." });
175
+ throw new CliError("auth", "Not logged in.", { hint: "Run `arcanist auth login` or set `ARCANIST_TOKEN`." });
176
176
  }
177
177
  return config;
178
178
  }
@@ -536,9 +536,11 @@ function formatTime(value) {
536
536
  // ../../shared/agent/agent-runtime-backend.ts
537
537
  var CODEX_AGENT_RUNTIME_BACKEND = "codex";
538
538
  var CLAUDE_CODE_AGENT_RUNTIME_BACKEND = "claude_code";
539
+ var OPENCODE_AGENT_RUNTIME_BACKEND = "opencode";
539
540
  var AGENT_RUNTIME_BACKENDS = [
540
541
  CODEX_AGENT_RUNTIME_BACKEND,
541
- CLAUDE_CODE_AGENT_RUNTIME_BACKEND
542
+ CLAUDE_CODE_AGENT_RUNTIME_BACKEND,
543
+ OPENCODE_AGENT_RUNTIME_BACKEND
542
544
  ];
543
545
  function isAgentRuntimeBackend(value) {
544
546
  return AGENT_RUNTIME_BACKENDS.includes(value);
@@ -570,14 +572,23 @@ var AnthropicModel = {
570
572
  Opus48: "claude-opus-4-8",
571
573
  Sonnet46: "claude-sonnet-4-6"
572
574
  };
573
- var MODEL_PROVIDERS_SET = /* @__PURE__ */ new Set(["openai", "anthropic"]);
575
+ var BasetenModel = {
576
+ GptOss120B: "gpt-oss-120b"
577
+ };
578
+ var MODEL_PROVIDERS_SET = /* @__PURE__ */ new Set([
579
+ "openai",
580
+ "anthropic",
581
+ "baseten"
582
+ ]);
574
583
  var SESSION_START_MODEL_IDS_BY_BACKEND = {
575
584
  [CODEX_AGENT_RUNTIME_BACKEND]: [OpenAIModel.GPT55, OpenAIModel.GPT54, OpenAIModel.GPT54Nano],
576
- [CLAUDE_CODE_AGENT_RUNTIME_BACKEND]: [AnthropicModel.Opus48, AnthropicModel.Sonnet46]
585
+ [CLAUDE_CODE_AGENT_RUNTIME_BACKEND]: [AnthropicModel.Opus48, AnthropicModel.Sonnet46],
586
+ [OPENCODE_AGENT_RUNTIME_BACKEND]: [BasetenModel.GptOss120B]
577
587
  };
578
588
  var DEFAULT_SESSION_START_MODEL_ID_BY_BACKEND = {
579
589
  [CODEX_AGENT_RUNTIME_BACKEND]: OpenAIModel.GPT54,
580
- [CLAUDE_CODE_AGENT_RUNTIME_BACKEND]: AnthropicModel.Opus48
590
+ [CLAUDE_CODE_AGENT_RUNTIME_BACKEND]: AnthropicModel.Opus48,
591
+ [OPENCODE_AGENT_RUNTIME_BACKEND]: BasetenModel.GptOss120B
581
592
  };
582
593
  var DEFAULT_SESSION_START_MODEL_ID = DEFAULT_SESSION_START_MODEL_ID_BY_BACKEND[CODEX_AGENT_RUNTIME_BACKEND];
583
594
  var MODEL_REGISTRY = [
@@ -662,18 +673,31 @@ var MODEL_REGISTRY = [
662
673
  provider: "anthropic",
663
674
  backends: [CLAUDE_CODE_AGENT_RUNTIME_BACKEND],
664
675
  contextWindow: 1e6
676
+ },
677
+ {
678
+ id: BasetenModel.GptOss120B,
679
+ name: "GPT-OSS 120B",
680
+ provider: "baseten",
681
+ backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
682
+ contextWindow: 128e3,
683
+ visibility: "internal_probe",
684
+ // Verified 2026-06-26 against GET https://inference.baseten.co/v1/models:
685
+ // the served id is namespaced `openai/gpt-oss-120b`, not bare `gpt-oss-120b`.
686
+ providerModelId: "openai/gpt-oss-120b"
665
687
  }
666
688
  ];
667
689
  var MODEL_PROVIDER_NAMES = {
668
690
  openai: "OpenAI",
669
- anthropic: "Anthropic"
691
+ anthropic: "Anthropic",
692
+ baseten: "Baseten"
670
693
  };
671
694
  var VALID_MODEL_IDS = new Set(MODEL_REGISTRY.map((model) => model.id));
672
695
  var VALID_SESSION_START_MODEL_IDS_BY_BACKEND = {
673
696
  [CODEX_AGENT_RUNTIME_BACKEND]: new Set(SESSION_START_MODEL_IDS_BY_BACKEND[CODEX_AGENT_RUNTIME_BACKEND]),
674
697
  [CLAUDE_CODE_AGENT_RUNTIME_BACKEND]: new Set(
675
698
  SESSION_START_MODEL_IDS_BY_BACKEND[CLAUDE_CODE_AGENT_RUNTIME_BACKEND]
676
- )
699
+ ),
700
+ [OPENCODE_AGENT_RUNTIME_BACKEND]: new Set(SESSION_START_MODEL_IDS_BY_BACKEND[OPENCODE_AGENT_RUNTIME_BACKEND])
677
701
  };
678
702
  var MODEL_CONTEXT_WINDOWS = {
679
703
  ...Object.fromEntries(
@@ -736,7 +760,8 @@ var MODEL_TIER_BY_ID = {
736
760
  [OpenAIModel.GPT54]: "mid",
737
761
  [OpenAIModel.GPT54Nano]: "mid",
738
762
  [AnthropicModel.Opus48]: "frontier",
739
- [AnthropicModel.Sonnet46]: "mid"
763
+ [AnthropicModel.Sonnet46]: "mid",
764
+ [BasetenModel.GptOss120B]: "mid"
740
765
  };
741
766
  var CODEX_MODEL_ID_BY_TIER = {
742
767
  // Single source of truth: the frontier codex model follows the codex default,
@@ -796,6 +821,11 @@ var SESSION_START_MODEL_ID_SET_ANY_BACKEND = new Set(
796
821
  var SESSION_START_MODEL_PROVIDER_GROUPS = buildModelProviderGroups(
797
822
  MODEL_REGISTRY.filter((model) => SESSION_START_MODEL_ID_SET_ANY_BACKEND.has(model.id))
798
823
  );
824
+ var PUBLIC_SESSION_START_MODEL_PROVIDER_GROUPS = buildModelProviderGroups(
825
+ MODEL_REGISTRY.filter(
826
+ (model) => SESSION_START_MODEL_ID_SET_ANY_BACKEND.has(model.id) && model.visibility !== "internal_probe"
827
+ )
828
+ );
799
829
 
800
830
  // ../../shared/utils/timing.ts
801
831
  function sleep(ms) {
@@ -2051,9 +2081,7 @@ function stringField(value) {
2051
2081
  return typeof value === "string" && value.trim() ? value : null;
2052
2082
  }
2053
2083
  function formatSessionResult(session) {
2054
- const prUrl = stringField(session.prUrl);
2055
- const publishedBranch = stringField(session.publishedBranch);
2056
- const lastBranch = stringField(session.lastBranch);
2084
+ const { prUrl, publishedBranch, lastBranch } = extractSessionResultFields(session);
2057
2085
  const baseBranch = stringField(session.baseBranch);
2058
2086
  const branch = publishedBranch ?? (lastBranch && lastBranch !== baseBranch ? lastBranch : null);
2059
2087
  if (prUrl) {
@@ -2064,6 +2092,16 @@ function formatSessionResult(session) {
2064
2092
  }
2065
2093
  return null;
2066
2094
  }
2095
+ function extractSessionResultFields(session) {
2096
+ const result = {};
2097
+ const prUrl = stringField(session.prUrl);
2098
+ const publishedBranch = stringField(session.publishedBranch);
2099
+ const lastBranch = stringField(session.lastBranch);
2100
+ if (prUrl) result.prUrl = prUrl;
2101
+ if (publishedBranch) result.publishedBranch = publishedBranch;
2102
+ if (lastBranch) result.lastBranch = lastBranch;
2103
+ return result;
2104
+ }
2067
2105
  function latestCompletedPromptResult(prompts) {
2068
2106
  for (let i = prompts.length - 1; i >= 0; i--) {
2069
2107
  if (prompts[i].status === "completed") return prompts[i].result;
@@ -2501,6 +2539,7 @@ function validateRepoUrl(url) {
2501
2539
  return `Invalid repo URL: "${url}". Expected a GitHub URL (https://github.com/owner/repo) or owner/repo shorthand.`;
2502
2540
  }
2503
2541
  var PROMPT_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed"]);
2542
+ var RESULT_FETCH_ATTEMPTS = 5;
2504
2543
  var ONBOARDING_PROMPT = "Onboard this repository onto Arcanist.";
2505
2544
  function selectCreatedPrompt(prompts, promptId) {
2506
2545
  if (prompts.length === 0) return null;
@@ -2563,13 +2602,35 @@ async function waitForCreatedPrompt(sessionId, promptId, sessionUrl, pollInterva
2563
2602
  );
2564
2603
  }
2565
2604
  }
2605
+ function unwrapSessionState(payload) {
2606
+ return payload.session && typeof payload.session === "object" ? payload.session : payload;
2607
+ }
2608
+ async function fetchSessionResultFields(config, sessionId) {
2609
+ const sessionPayload = await apiFetch(config, `/api/sessions/${sessionId}`);
2610
+ return extractSessionResultFields(unwrapSessionState(sessionPayload));
2611
+ }
2612
+ async function fetchSettledSessionResultFields(config, sessionId, pollIntervalMs) {
2613
+ const effectivePollIntervalMs = Math.max(pollIntervalMs, MIN_WATCH_POLL_INTERVAL_MS);
2614
+ let latest = {};
2615
+ for (let attempt = 0; attempt < RESULT_FETCH_ATTEMPTS; attempt++) {
2616
+ latest = await fetchSessionResultFields(config, sessionId);
2617
+ if (latest.prUrl || latest.publishedBranch) return latest;
2618
+ if (attempt < RESULT_FETCH_ATTEMPTS - 1) {
2619
+ await sleep(effectivePollIntervalMs);
2620
+ }
2621
+ }
2622
+ return latest;
2623
+ }
2566
2624
  async function createCommand(repoUrl, promptArg, options, command) {
2567
2625
  const runtime = getRuntimeOptions(command, options);
2568
2626
  const config = requireConfig(runtime);
2569
2627
  let agentRuntimeBackend = CODEX_AGENT_RUNTIME_BACKEND;
2570
2628
  if (options.backend !== void 0) {
2571
2629
  if (!isAgentRuntimeBackend(options.backend)) {
2572
- throw new CliError("user", `Invalid --backend '${options.backend}'. Expected codex or claude_code.`);
2630
+ throw new CliError(
2631
+ "user",
2632
+ `Invalid --backend '${options.backend}'. Expected ${AGENT_RUNTIME_BACKENDS.join(", ")}.`
2633
+ );
2573
2634
  }
2574
2635
  agentRuntimeBackend = options.backend;
2575
2636
  }
@@ -2616,6 +2677,7 @@ async function createCommand(repoUrl, promptArg, options, command) {
2616
2677
  });
2617
2678
  const sessionId = sessionData.sessionId;
2618
2679
  let promptId;
2680
+ let waitResultFields = {};
2619
2681
  try {
2620
2682
  const promptData = await apiFetch(
2621
2683
  config,
@@ -2644,10 +2706,16 @@ async function createCommand(repoUrl, promptArg, options, command) {
2644
2706
  if (sessionData.sessionUrl) console.log(`URL: ${sessionData.sessionUrl}`);
2645
2707
  }
2646
2708
  await waitForCreatedPrompt(sessionId, promptId, sessionData.sessionUrl, waitPollIntervalMs, runtime, command);
2709
+ if (isJson(command, options)) {
2710
+ try {
2711
+ waitResultFields = await fetchSettledSessionResultFields(config, sessionId, waitPollIntervalMs);
2712
+ } catch {
2713
+ }
2714
+ }
2647
2715
  if (!isJson(command, options)) {
2648
2716
  try {
2649
2717
  const sessionPayload = await apiFetch(config, `/api/sessions/${sessionId}`);
2650
- const sessionState = sessionPayload.session && typeof sessionPayload.session === "object" ? sessionPayload.session : sessionPayload;
2718
+ const sessionState = unwrapSessionState(sessionPayload);
2651
2719
  const resultLine = formatSessionResult(sessionState);
2652
2720
  if (resultLine) console.log(resultLine);
2653
2721
  } catch {
@@ -2665,12 +2733,14 @@ async function createCommand(repoUrl, promptArg, options, command) {
2665
2733
  if (startBranch) output.startBranch = startBranch;
2666
2734
  if (options.onboarding) output.onboarding = true;
2667
2735
  if (promptId) output.promptId = promptId;
2736
+ Object.assign(output, waitResultFields);
2668
2737
  writeJson(output);
2669
2738
  return;
2670
2739
  }
2671
2740
  if (options.wait) return;
2672
2741
  console.log(`Session: ${sessionId}`);
2673
2742
  if (sessionData.sessionUrl) console.log(`URL: ${sessionData.sessionUrl}`);
2743
+ console.log(`Follow with: arcanist sessions events ${sessionId} --follow --json`);
2674
2744
  }
2675
2745
 
2676
2746
  // src/commands/egress.ts
@@ -4336,7 +4406,7 @@ program.hook("preAction", (_thisCommand, actionCommand) => {
4336
4406
  applyColorEnvironment(getRuntimeOptions(actionCommand));
4337
4407
  });
4338
4408
  function addCreateOptions(cmd) {
4339
- return cmd.argument("<repo-url>", "Repository URL").argument("[prompt]", "Prompt to send, or '-' to read stdin").option("--model <model>", "Model to use").option("--backend <backend>", "Agent runtime backend: codex (default) or claude_code").option("--reasoning-effort <effort>", "Reasoning effort to use for models that support it").option("--base-branch <branch>", "Base branch to create the session against (defaults to the repo default branch)").option(
4409
+ return cmd.argument("<repo-url>", "Repository URL").argument("[prompt]", "Prompt to send, or '-' to read stdin").option("--model <model>", "Model to use").option("--backend <backend>", "Agent runtime backend: codex (default), claude_code, or opencode").option("--reasoning-effort <effort>", "Reasoning effort to use for models that support it").option("--base-branch <branch>", "Base branch to create the session against (defaults to the repo default branch)").option(
4340
4410
  "--start-branch <branch>",
4341
4411
  "Resume an existing branch with its history instead of forking a new one off base"
4342
4412
  ).option("--prompt-stdin", "Read prompt from stdin").option(
@@ -4356,6 +4426,11 @@ Examples:
4356
4426
  printf "fix bug" | arcanist sessions create https://github.com/org/repo --prompt-stdin --json
4357
4427
  printf "fix bug" | arcanist sessions create https://github.com/org/repo --prompt-stdin --wait
4358
4428
  arcanist sessions create https://github.com/org/repo - --json | jq -r .sessionId | xargs -I{} arcanist sessions events {} --follow --json
4429
+
4430
+ JSON:
4431
+ JSON mode returns {sessionId, sessionUrl?, repoUrl, model?, agentRuntimeBackend?, reasoningEffort?, baseBranch?, startBranch?, onboarding?, promptId?}
4432
+ --wait --json also includes best-effort result fields when available: prUrl?, publishedBranch?, lastBranch?
4433
+ Follow async progress with: arcanist sessions events <session-id> --follow --json
4359
4434
  `
4360
4435
  );
4361
4436
  }
@@ -4371,6 +4446,9 @@ Examples:
4371
4446
  arcanist sessions send <session-id> "also update tests"
4372
4447
  arcanist sessions send <session-id> "use this log" --uploaded-file failing.log
4373
4448
  printf "also update tests" | arcanist sessions send <session-id> --prompt-stdin --json
4449
+
4450
+ JSON:
4451
+ JSON mode returns {sessionId, promptId?}
4374
4452
  `
4375
4453
  );
4376
4454
  }
@@ -4405,6 +4483,10 @@ sessions.command("stop").description("Stop the active run for a session").argume
4405
4483
  Examples:
4406
4484
  arcanist sessions stop <session-id>
4407
4485
  arcanist sessions stop <session-id> --json
4486
+
4487
+ JSON:
4488
+ JSON mode returns {sessionId, status}
4489
+ status is the server stop status or 409 stop-block reason. Known values include stopping, stopped, already_stopped, not_stoppable, and lifecycle phase names.
4408
4490
  `
4409
4491
  ).action((sessionId, options, command) => stopCommand(sessionId, options, command));
4410
4492
  sessions.command("get").description("Get session details").argument("<session-id>", "Session ID").addHelpText(
@@ -4413,6 +4495,9 @@ sessions.command("get").description("Get session details").argument("<session-id
4413
4495
  Examples:
4414
4496
  arcanist sessions get <session-id>
4415
4497
  arcanist sessions get <session-id> --json
4498
+
4499
+ JSON:
4500
+ JSON mode returns the raw session payload. Result fields are at .session.prUrl, .session.publishedBranch, and .session.lastBranch.
4416
4501
  `
4417
4502
  ).action((sessionId, options, command) => getSessionCommand(sessionId, options, command));
4418
4503
  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(
@@ -4422,6 +4507,9 @@ Examples:
4422
4507
  arcanist sessions list
4423
4508
  arcanist sessions list --status idle --json
4424
4509
  arcanist sessions list --search "architect agent" --repo owner/repo
4510
+
4511
+ JSON:
4512
+ JSON mode returns {sessions, nextCursor}
4425
4513
  `
4426
4514
  ).action((options, command) => listSessionsCommand(options, command));
4427
4515
  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(
@@ -4430,6 +4518,9 @@ sessions.command("search").description("Search sessions by title and repo metada
4430
4518
  Examples:
4431
4519
  arcanist sessions search "architect agent"
4432
4520
  arcanist sessions search "mcp debugging" --repo owner/repo --json
4521
+
4522
+ JSON:
4523
+ JSON mode returns {sessions, nextCursor}
4433
4524
  `
4434
4525
  ).action((query, options, command) => searchSessionsCommand(query, options, command));
4435
4526
  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(
@@ -4440,6 +4531,11 @@ Examples:
4440
4531
  arcanist sessions events <session-id> --after-sequence 540 --limit 250 --json
4441
4532
  arcanist sessions events <session-id> --after 540 --limit 250 --json
4442
4533
  arcanist sessions events <session-id> --follow --json
4534
+
4535
+ JSON:
4536
+ JSON mode without --follow returns one JSON object from /events/history: {events: [...], ...}; canonical events carry phase.
4537
+ --follow --json emits NDJSON, one {sequence, type, data} object per line.
4538
+ Actionable follow types: pr_created/pr_updated use data.prUrl; question uses data.question; terminal types are prompt_completed, prompt_failed, and session_idle.
4443
4539
  `
4444
4540
  ).action((sessionId, options, command) => sessionEventsCommand(sessionId, options, command));
4445
4541
  sessions.command("transcript").description("Render a session transcript").argument("<session-id>", "Session ID").addHelpText(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryarcanist/cli",
3
- "version": "0.1.141",
3
+ "version": "0.1.143",
4
4
  "description": "CLI for Arcanist — create and manage coding agent sessions",
5
5
  "type": "module",
6
6
  "bin": {