@tryarcanist/cli 0.1.219 → 0.1.220

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 (2) hide show
  1. package/dist/index.js +118 -49
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -580,7 +580,7 @@ function assertArcanistSessionMutationAllowed(subcommand) {
580
580
  }
581
581
  );
582
582
  }
583
- const commandName = subcommand === "review" ? "review" : `sessions ${subcommand}`;
583
+ const commandName = subcommand === "review" || subcommand === "anubis" ? subcommand : `sessions ${subcommand}`;
584
584
  throw new CliError(
585
585
  "user",
586
586
  `\`arcanist ${commandName}\` is disabled inside ${role} sessions because nested Arcanist work is not observable to read-only agents.`,
@@ -967,6 +967,94 @@ async function agentSubscriptionLogoutCommand(config, options, command) {
967
967
  );
968
968
  }
969
969
 
970
+ // src/commands/review.ts
971
+ var PR_REVIEW_POLL_INTERVAL_MS = 1e4;
972
+ var PR_REVIEW_WAIT_TIMEOUT_MS = 30 * 60 * 1e3;
973
+ async function reviewCommand(prUrl, options = {}, command) {
974
+ assertArcanistSessionMutationAllowed("review");
975
+ const { config } = resolveBusinessContext(command, options);
976
+ const trigger = await apiFetch(config, "/api/pr-reviews", {
977
+ method: "POST",
978
+ body: JSON.stringify({ prUrl, ...options.focus ? { focus: options.focus } : {} })
979
+ });
980
+ if (!options.wait || trigger.cached) {
981
+ emit(command, options, trigger, (payload) => {
982
+ if (payload.cached) console.log(`Zeus review already completed: ${payload.verdict ?? "unknown"}.`);
983
+ else console.log(`Started Zeus review${payload.sessionId ? ` (${payload.sessionId})` : ""}.`);
984
+ });
985
+ return;
986
+ }
987
+ const result = await waitForReview(config, prUrl, trigger.sessionId ?? null);
988
+ emit(command, options, result, (payload) => {
989
+ console.log(`Zeus review: ${sanitizeTerminalText(payload.verdict)}. ${payload.findings.length} finding(s).`);
990
+ for (const finding of payload.findings) {
991
+ console.log(
992
+ `${sanitizeTerminalText(finding.severity)} ${sanitizeTerminalText(finding.file)}:${finding.line} - ${sanitizeTerminalText(finding.title)}`
993
+ );
994
+ }
995
+ });
996
+ }
997
+ function sanitizeTerminalText(value) {
998
+ return value.replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g, "").replace(/\u001b\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\u0000-\u001f\u007f]/g, "");
999
+ }
1000
+ async function waitForReview(config, prUrl, sessionId) {
1001
+ const deadline = Date.now() + PR_REVIEW_WAIT_TIMEOUT_MS;
1002
+ while (Date.now() < deadline) {
1003
+ const status = await apiFetch(
1004
+ config,
1005
+ `/api/pr-reviews/status?prUrl=${encodeURIComponent(prUrl)}`
1006
+ );
1007
+ if (status.status === "completed") {
1008
+ if (sessionId && status.sessionId !== sessionId) {
1009
+ throw new CliError("conflict", "PR review completed for a different attempt; retry the command.");
1010
+ }
1011
+ return { ...status, sessionId: status.sessionId ?? sessionId };
1012
+ }
1013
+ await new Promise((resolve2) => setTimeout(resolve2, PR_REVIEW_POLL_INTERVAL_MS));
1014
+ }
1015
+ throw new CliError("server", "Timed out waiting for Zeus review results.");
1016
+ }
1017
+
1018
+ // src/commands/anubis.ts
1019
+ var ANUBIS_POLL_INTERVAL_MS = 15e3;
1020
+ var ANUBIS_WAIT_TIMEOUT_MS = 45 * 60 * 1e3;
1021
+ async function anubisCommand(prUrl, options = {}, command) {
1022
+ assertArcanistSessionMutationAllowed("anubis");
1023
+ const { config } = resolveBusinessContext(command, options);
1024
+ const trigger = await apiFetch(config, "/api/anubis-runs", {
1025
+ method: "POST",
1026
+ body: JSON.stringify({ prUrl })
1027
+ });
1028
+ if (!options.wait) {
1029
+ emit(command, options, trigger, (payload) => {
1030
+ console.log(`${payload.duplicate ? "Attached to existing" : "Started"} Anubis run (${payload.sessionId}).`);
1031
+ });
1032
+ return;
1033
+ }
1034
+ const result = await waitForAnubis(config, prUrl, trigger.sessionId);
1035
+ emit(command, options, result, (payload) => {
1036
+ console.log(`Anubis: ${sanitizeTerminalText(payload.verdict ?? "could-not-verify")}.`);
1037
+ if (payload.summary) console.log(sanitizeTerminalText(payload.summary));
1038
+ });
1039
+ }
1040
+ async function waitForAnubis(config, prUrl, sessionId) {
1041
+ const deadline = Date.now() + ANUBIS_WAIT_TIMEOUT_MS;
1042
+ while (Date.now() < deadline) {
1043
+ const status = await apiFetch(
1044
+ config,
1045
+ `/api/anubis-runs/status?prUrl=${encodeURIComponent(prUrl)}`
1046
+ );
1047
+ if (status.sessionStatus !== "active") {
1048
+ if (status.sessionId !== sessionId) {
1049
+ throw new CliError("conflict", "Anubis completed for a different attempt; retry the command.");
1050
+ }
1051
+ return status;
1052
+ }
1053
+ await new Promise((resolve2) => setTimeout(resolve2, ANUBIS_POLL_INTERVAL_MS));
1054
+ }
1055
+ throw new CliError("server", "Timed out waiting for Anubis results.");
1056
+ }
1057
+
970
1058
  // src/commands/auth.ts
971
1059
  async function whoamiCommand(options, command) {
972
1060
  const { config } = resolveBusinessContext(command, options);
@@ -1031,6 +1119,7 @@ var OpenAIModel = {
1031
1119
  };
1032
1120
  var AnthropicModel = {
1033
1121
  Opus48: "claude-opus-4-8",
1122
+ Opus5: "claude-opus-5",
1034
1123
  Sonnet46: "claude-sonnet-4-6",
1035
1124
  Sonnet5: "claude-sonnet-5",
1036
1125
  Fable5: "claude-fable-5"
@@ -1307,6 +1396,18 @@ var MODEL_REGISTRY = [
1307
1396
  pricing: { inputPerMillion: 5, outputPerMillion: 25, cacheReadPerMillion: 0.5, cacheWritePerMillion: 6.25 },
1308
1397
  sessionStart: { eligible: true, isDefault: true }
1309
1398
  },
1399
+ {
1400
+ id: AnthropicModel.Opus5,
1401
+ name: "Claude Opus 5",
1402
+ provider: "anthropic",
1403
+ backends: [CLAUDE_CODE_AGENT_RUNTIME_BACKEND],
1404
+ contextWindow: 1e6,
1405
+ reasoning: { efforts: ["none", "low", "medium", "high", "xhigh", "max"], default: "high" },
1406
+ // Bridge cost estimate; authoritative Anthropic Messages pricing lives in
1407
+ // apps/control-plane-worker/src/anthropic/cost.ts.
1408
+ pricing: { inputPerMillion: 5, outputPerMillion: 25, cacheReadPerMillion: 0.5, cacheWritePerMillion: 6.25 },
1409
+ sessionStart: { eligible: true }
1410
+ },
1310
1411
  {
1311
1412
  id: AnthropicModel.Sonnet46,
1312
1413
  name: "Claude Sonnet 4.6",
@@ -4670,54 +4771,6 @@ function parseRespondConflict(err) {
4670
4771
  }
4671
4772
  }
4672
4773
 
4673
- // src/commands/review.ts
4674
- var PR_REVIEW_POLL_INTERVAL_MS = 1e4;
4675
- var PR_REVIEW_WAIT_TIMEOUT_MS = 30 * 60 * 1e3;
4676
- async function reviewCommand(prUrl, options = {}, command) {
4677
- assertArcanistSessionMutationAllowed("review");
4678
- const { config } = resolveBusinessContext(command, options);
4679
- const trigger = await apiFetch(config, "/api/pr-reviews", {
4680
- method: "POST",
4681
- body: JSON.stringify({ prUrl, ...options.focus ? { focus: options.focus } : {} })
4682
- });
4683
- if (!options.wait || trigger.cached) {
4684
- emit(command, options, trigger, (payload) => {
4685
- if (payload.cached) console.log(`Zeus review already completed: ${payload.verdict ?? "unknown"}.`);
4686
- else console.log(`Started Zeus review${payload.sessionId ? ` (${payload.sessionId})` : ""}.`);
4687
- });
4688
- return;
4689
- }
4690
- const result = await waitForReview(config, prUrl, trigger.sessionId ?? null);
4691
- emit(command, options, result, (payload) => {
4692
- console.log(`Zeus review: ${sanitizeTerminalText(payload.verdict)}. ${payload.findings.length} finding(s).`);
4693
- for (const finding of payload.findings) {
4694
- console.log(
4695
- `${sanitizeTerminalText(finding.severity)} ${sanitizeTerminalText(finding.file)}:${finding.line} - ${sanitizeTerminalText(finding.title)}`
4696
- );
4697
- }
4698
- });
4699
- }
4700
- function sanitizeTerminalText(value) {
4701
- return value.replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g, "").replace(/\u001b\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\u0000-\u001f\u007f]/g, "");
4702
- }
4703
- async function waitForReview(config, prUrl, sessionId) {
4704
- const deadline = Date.now() + PR_REVIEW_WAIT_TIMEOUT_MS;
4705
- while (Date.now() < deadline) {
4706
- const status = await apiFetch(
4707
- config,
4708
- `/api/pr-reviews/status?prUrl=${encodeURIComponent(prUrl)}`
4709
- );
4710
- if (status.status === "completed") {
4711
- if (sessionId && status.sessionId !== sessionId) {
4712
- throw new CliError("conflict", "PR review completed for a different attempt; retry the command.");
4713
- }
4714
- return { ...status, sessionId: status.sessionId ?? sessionId };
4715
- }
4716
- await new Promise((resolve2) => setTimeout(resolve2, PR_REVIEW_POLL_INTERVAL_MS));
4717
- }
4718
- throw new CliError("server", "Timed out waiting for Zeus review results.");
4719
- }
4720
-
4721
4774
  // src/commands/sandbox.ts
4722
4775
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
4723
4776
  import { dirname as dirname2 } from "path";
@@ -6359,9 +6412,25 @@ Examples:
6359
6412
  arcanist review https://github.com/org/repo/pull/123 --wait --json
6360
6413
  arcanist review https://github.com/org/repo/pull/123 --focus "Check auth" --wait
6361
6414
 
6415
+ Zeus always runs the platform-managed Codex reviewer; --model and --backend do not apply to reviews.
6362
6416
  Zeus review is currently available to Arcanist members only.
6363
6417
  `
6364
6418
  ).action((prUrl, options, command) => reviewCommand(prUrl, options, command));
6419
+ program.command("anubis <pr-url>").description("Run an Anubis QA verification for a GitHub pull request").option("--wait", "Wait for the verdict").addHelpText(
6420
+ "after",
6421
+ `
6422
+ Examples:
6423
+ arcanist anubis https://github.com/org/repo/pull/123 --wait --json
6424
+ arcanist anubis https://github.com/org/repo/pull/123
6425
+
6426
+ --json without --wait returns { sessionId, claimed? | duplicate? }.
6427
+ --wait --json returns { sessionId, sessionStatus, verdict, summary? }.
6428
+ Known verdicts are works, broken, and could-not-verify.
6429
+ Anubis deduplicates active runs server-side; it does not use --idempotency-key.
6430
+ The result is posted as a PR comment marked arcanist-anubis:v1.
6431
+ Anubis is currently available to Arcanist members only.
6432
+ `
6433
+ ).action((prUrl, options, command) => anubisCommand(prUrl, options, command));
6365
6434
  addCreateOptions(sessions.command("create").description("Create a session and send a prompt")).action(
6366
6435
  (repoUrl, prompt, options, command) => createCommand(repoUrl, prompt, options, command)
6367
6436
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryarcanist/cli",
3
- "version": "0.1.219",
3
+ "version": "0.1.220",
4
4
  "description": "CLI for Arcanist — create and manage coding agent sessions",
5
5
  "type": "module",
6
6
  "bin": {