@tryarcanist/cli 0.1.218 → 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.
- package/dist/index.js +118 -49
- 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"
|
|
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
|
);
|