@tryarcanist/cli 0.1.230 → 0.1.231
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 +3 -3
- package/dist/index.js +108 -704
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -197,7 +197,7 @@ arcanist sessions create your-org/your-repo "review the trace" --uploaded-file t
|
|
|
197
197
|
arcanist sessions create your-org/your-repo "retry-safe create" --idempotency-key 1f0e6f1a-...
|
|
198
198
|
```
|
|
199
199
|
|
|
200
|
-
`--backend` picks the agent runtime backend: `codex` (default)
|
|
200
|
+
`--backend` picks the agent runtime backend: `codex` (default) or `claude_code`. `--model` must be valid for the chosen backend and the CLI rejects a mismatch before any network call; run `arcanist models list` for the selectable models per backend. When `--model` is omitted the backend default is used. Non-codex backends require the matching provider credential configured in Settings.
|
|
201
201
|
|
|
202
202
|
`--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.
|
|
203
203
|
|
|
@@ -242,7 +242,7 @@ The PR URL must be `https://github.com/<owner>/<repo>/pull/<number>`.
|
|
|
242
242
|
The CLI derives the repo from that URL, creates a QA session with `qa: true` and `targetPrUrl`, then enqueues the verifier prompt (skipped when the server signals `promptAlreadyEnqueued`).
|
|
243
243
|
Inspect progress with the session URL or the session events stream.
|
|
244
244
|
|
|
245
|
-
`--backend` picks the agent runtime backend: `codex` (default)
|
|
245
|
+
`--backend` picks the agent runtime backend: `codex` (default) or `claude_code`.
|
|
246
246
|
`--model` must be valid for the chosen backend, and the CLI rejects mismatches before any network call.
|
|
247
247
|
When `--model` is omitted, the backend default is used.
|
|
248
248
|
|
|
@@ -435,7 +435,7 @@ printf "summarize new regressions" | arcanist automations create your-org/your-r
|
|
|
435
435
|
arcanist automations create https://github.com/your-org/your-repo - --cron "0 14 * * 1-5" --name "Weekday summary"
|
|
436
436
|
```
|
|
437
437
|
|
|
438
|
-
Use `--model <model>` to pin the model for sessions started by the automation. Backend is derived from the model; non-codex backends such as Claude
|
|
438
|
+
Use `--model <model>` to pin the model for sessions started by the automation. Backend is derived from the model; non-codex backends such as Claude are limited to Arcanist team businesses. When `--model` is omitted the codex backend default is used.
|
|
439
439
|
|
|
440
440
|
Use `--slack-team-id <team-id>` together with `--slack-channel-id <channel-id>` to deliver each completed automation digest into a Slack channel. Both flags are required together; the target workspace must already be connected to Arcanist and the bot must already be in the channel.
|
|
441
441
|
|
package/dist/index.js
CHANGED
|
@@ -7,36 +7,18 @@ import { Command } from "commander";
|
|
|
7
7
|
// ../../shared/agent/agent-runtime-backend.ts
|
|
8
8
|
var CODEX_AGENT_RUNTIME_BACKEND = "codex";
|
|
9
9
|
var CLAUDE_CODE_AGENT_RUNTIME_BACKEND = "claude_code";
|
|
10
|
-
var OPENCODE_AGENT_RUNTIME_BACKEND = "opencode";
|
|
11
|
-
var CURSOR_AGENT_RUNTIME_BACKEND = "cursor";
|
|
12
|
-
var GROK_AGENT_RUNTIME_BACKEND = "grok";
|
|
13
10
|
var AGENT_RUNTIME_BACKENDS = [
|
|
14
11
|
CODEX_AGENT_RUNTIME_BACKEND,
|
|
15
|
-
CLAUDE_CODE_AGENT_RUNTIME_BACKEND
|
|
16
|
-
OPENCODE_AGENT_RUNTIME_BACKEND,
|
|
17
|
-
CURSOR_AGENT_RUNTIME_BACKEND,
|
|
18
|
-
GROK_AGENT_RUNTIME_BACKEND
|
|
12
|
+
CLAUDE_CODE_AGENT_RUNTIME_BACKEND
|
|
19
13
|
];
|
|
20
14
|
var AGENT_RUNTIME_BACKEND_NAMES = {
|
|
21
15
|
[CODEX_AGENT_RUNTIME_BACKEND]: "Codex",
|
|
22
|
-
[CLAUDE_CODE_AGENT_RUNTIME_BACKEND]: "Claude Code"
|
|
23
|
-
// "opencode" is intentionally lowercase to match the project's brand name.
|
|
24
|
-
[OPENCODE_AGENT_RUNTIME_BACKEND]: "opencode",
|
|
25
|
-
[CURSOR_AGENT_RUNTIME_BACKEND]: "Cursor",
|
|
26
|
-
[GROK_AGENT_RUNTIME_BACKEND]: "Grok Build"
|
|
16
|
+
[CLAUDE_CODE_AGENT_RUNTIME_BACKEND]: "Claude Code"
|
|
27
17
|
};
|
|
28
18
|
function isAgentRuntimeBackend(value) {
|
|
29
19
|
return AGENT_RUNTIME_BACKENDS.includes(value);
|
|
30
20
|
}
|
|
31
21
|
|
|
32
|
-
// src/commands/agent-subscription.ts
|
|
33
|
-
import { execFileSync, spawn as spawn2 } from "child_process";
|
|
34
|
-
import { existsSync as existsSync2 } from "fs";
|
|
35
|
-
import { readFile } from "fs/promises";
|
|
36
|
-
import { homedir as homedir2 } from "os";
|
|
37
|
-
import { join as join3 } from "path";
|
|
38
|
-
import { createInterface as createInterface2 } from "readline/promises";
|
|
39
|
-
|
|
40
22
|
// src/api.ts
|
|
41
23
|
import { createRequire } from "module";
|
|
42
24
|
|
|
@@ -668,364 +650,6 @@ function isControlCharacter(char) {
|
|
|
668
650
|
return code < ASCII_FIRST_PRINTABLE || code === ASCII_DELETE;
|
|
669
651
|
}
|
|
670
652
|
|
|
671
|
-
// src/vendor-login.ts
|
|
672
|
-
import { spawn } from "child_process";
|
|
673
|
-
import { rmSync } from "fs";
|
|
674
|
-
import { mkdtemp, rm } from "fs/promises";
|
|
675
|
-
import { tmpdir } from "os";
|
|
676
|
-
import { join as join2 } from "path";
|
|
677
|
-
var VendorBinaryMissingError = class extends CliError {
|
|
678
|
-
constructor(binPath, hint) {
|
|
679
|
-
super("user", `Could not find the \`${binPath}\` executable.`, { hint });
|
|
680
|
-
this.name = "VendorBinaryMissingError";
|
|
681
|
-
}
|
|
682
|
-
};
|
|
683
|
-
function runVendorLoginProcess(spec) {
|
|
684
|
-
return new Promise((resolve3, reject) => {
|
|
685
|
-
const child = spawn(spec.binPath, spec.args, {
|
|
686
|
-
stdio: "inherit",
|
|
687
|
-
env: { ...process.env, ...spec.env }
|
|
688
|
-
});
|
|
689
|
-
child.on("error", (err) => {
|
|
690
|
-
if (err.code === "ENOENT") {
|
|
691
|
-
reject(new VendorBinaryMissingError(spec.binPath, spec.missingBinaryHint));
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
694
|
-
reject(new CliError("user", `Failed to launch \`${spec.binPath} ${spec.args.join(" ")}\`: ${err.message}`));
|
|
695
|
-
});
|
|
696
|
-
child.on("close", (code) => {
|
|
697
|
-
if (code === 0) {
|
|
698
|
-
resolve3();
|
|
699
|
-
return;
|
|
700
|
-
}
|
|
701
|
-
reject(
|
|
702
|
-
new CliError("user", `\`${spec.binPath} ${spec.args.join(" ")}\` exited with code ${code ?? "unknown"}.`, {
|
|
703
|
-
hint: `Complete the ${spec.displayName} login, then re-run \`${spec.retryCommand}\`.`
|
|
704
|
-
})
|
|
705
|
-
);
|
|
706
|
-
});
|
|
707
|
-
});
|
|
708
|
-
}
|
|
709
|
-
async function withIsolatedLoginDir(prefix, fn) {
|
|
710
|
-
let tempDir;
|
|
711
|
-
const handleSigint = () => {
|
|
712
|
-
if (tempDir) {
|
|
713
|
-
try {
|
|
714
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
715
|
-
} catch {
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
process.exit(EXIT_CODE_INTERRUPTED);
|
|
719
|
-
};
|
|
720
|
-
process.on("SIGINT", handleSigint);
|
|
721
|
-
try {
|
|
722
|
-
tempDir = await mkdtemp(join2(tmpdir(), prefix));
|
|
723
|
-
return await fn(tempDir);
|
|
724
|
-
} finally {
|
|
725
|
-
try {
|
|
726
|
-
if (tempDir) {
|
|
727
|
-
await rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
728
|
-
});
|
|
729
|
-
}
|
|
730
|
-
} finally {
|
|
731
|
-
process.off("SIGINT", handleSigint);
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
// src/commands/agent-subscription.ts
|
|
737
|
-
var GROK_SUBSCRIPTION_CLI_CONFIG = {
|
|
738
|
-
harness: "grok",
|
|
739
|
-
displayName: "Grok",
|
|
740
|
-
defaultBin: "grok",
|
|
741
|
-
binEnvVar: "ARCANIST_GROK_BIN",
|
|
742
|
-
// RFC 8628 device flow: prints a verification URL + code, usable from a
|
|
743
|
-
// terminal without a local browser.
|
|
744
|
-
loginArgs: ["login", "--device-auth"],
|
|
745
|
-
loginEnv: () => ({}),
|
|
746
|
-
authJsonCandidates: [join3(".grok", "auth.json")],
|
|
747
|
-
// Grok Build's auth.json is issuer-keyed (observed 2026-07-15 against the
|
|
748
|
-
// installed CLI's embedded docs): {"https://accounts.x.ai/sign-in": {"key":
|
|
749
|
-
// "…"}} — so the credential fields live one level down and the token field
|
|
750
|
-
// is named `key`. Token detection scans nested objects.
|
|
751
|
-
tokenFields: ["access_token", "refresh_token", "key"],
|
|
752
|
-
installHint: "Install the Grok CLI (https://x.ai/cli), or point at it with --grok-path <path> or ARCANIST_GROK_BIN.",
|
|
753
|
-
// Official Grok Build installer: installs `grok` (plus an `agent` alias)
|
|
754
|
-
// under ~/.grok/bin, symlinks into ~/.local/bin or /usr/local/bin when
|
|
755
|
-
// writable, and appends PATH exports to shell rc files itself.
|
|
756
|
-
installer: {
|
|
757
|
-
command: "curl -fsSL https://x.ai/cli/install.sh | bash",
|
|
758
|
-
binCandidates: (home) => [
|
|
759
|
-
join3(home, ".grok", "bin", "grok"),
|
|
760
|
-
join3(home, ".local", "bin", "grok"),
|
|
761
|
-
"/usr/local/bin/grok"
|
|
762
|
-
],
|
|
763
|
-
postInstallNote: "Grok CLI installed. Restart your shell if `grok` is not found on PATH later."
|
|
764
|
-
}
|
|
765
|
-
};
|
|
766
|
-
var CURSOR_SUBSCRIPTION_CLI_CONFIG = {
|
|
767
|
-
harness: "cursor",
|
|
768
|
-
displayName: "Cursor",
|
|
769
|
-
defaultBin: "cursor-agent",
|
|
770
|
-
binEnvVar: "ARCANIST_CURSOR_AGENT_BIN",
|
|
771
|
-
loginArgs: ["login"],
|
|
772
|
-
// Cursor's CLI stores login state under its config dir; the location is not
|
|
773
|
-
// formally documented, so pin every documented override at the throwaway
|
|
774
|
-
// HOME and search the known spots afterwards.
|
|
775
|
-
loginEnv: (tempHome) => ({
|
|
776
|
-
CURSOR_CONFIG_DIR: join3(tempHome, ".cursor"),
|
|
777
|
-
XDG_CONFIG_HOME: join3(tempHome, ".config")
|
|
778
|
-
}),
|
|
779
|
-
authJsonCandidates: [
|
|
780
|
-
join3(".cursor", "auth.json"),
|
|
781
|
-
join3(".cursor", "cli-config.json"),
|
|
782
|
-
join3(".config", "cursor", "auth.json"),
|
|
783
|
-
join3(".config", "cursor", "cli-config.json")
|
|
784
|
-
],
|
|
785
|
-
tokenFields: ["accessToken", "access_token", "refreshToken", "refresh_token", "token"],
|
|
786
|
-
installHint: "Install the Cursor CLI (https://cursor.com/docs/cli/installation), or point at it with --cursor-path <path> or ARCANIST_CURSOR_AGENT_BIN. If login-token capture keeps failing, use a Cursor API key in Settings instead.",
|
|
787
|
-
// Entry names observed 2026-07-15 after `cursor-agent login` on macOS
|
|
788
|
-
// (login keychain, account "cursor-user").
|
|
789
|
-
darwinKeychain: {
|
|
790
|
-
entries: [
|
|
791
|
-
{ service: "cursor-access-token", field: "accessToken", required: true },
|
|
792
|
-
{ service: "cursor-refresh-token", field: "refreshToken", required: false }
|
|
793
|
-
]
|
|
794
|
-
},
|
|
795
|
-
// Official Cursor CLI installer: installs to ~/.local/bin. Installers have
|
|
796
|
-
// shipped the binary as both `cursor-agent` and `agent` (the 2026-07
|
|
797
|
-
// installer's success message says `agent`), so probe both — unambiguous
|
|
798
|
-
// name first, since `agent` is also Grok's alias.
|
|
799
|
-
installer: {
|
|
800
|
-
command: "curl https://cursor.com/install -fsS | bash",
|
|
801
|
-
binCandidates: (home) => [join3(home, ".local", "bin", "cursor-agent"), join3(home, ".local", "bin", "agent")],
|
|
802
|
-
postInstallNote: 'Cursor CLI installed to ~/.local/bin. Add it to your PATH for future shells: export PATH="$HOME/.local/bin:$PATH"'
|
|
803
|
-
}
|
|
804
|
-
};
|
|
805
|
-
function subscriptionBasePath(harness) {
|
|
806
|
-
return `/api/settings/agent-subscriptions/${harness}`;
|
|
807
|
-
}
|
|
808
|
-
function resolveVendorBin(config, optionPath) {
|
|
809
|
-
return optionPath?.trim() || process.env[config.binEnvVar]?.trim() || config.defaultBin;
|
|
810
|
-
}
|
|
811
|
-
function runVendorInstall(config, command) {
|
|
812
|
-
return new Promise((resolve3, reject) => {
|
|
813
|
-
const child = spawn2("bash", ["-c", command], { stdio: ["inherit", 2, "inherit"] });
|
|
814
|
-
child.on("error", (err) => {
|
|
815
|
-
reject(
|
|
816
|
-
new CliError("user", `Failed to run the ${config.displayName} CLI installer: ${err.message}`, {
|
|
817
|
-
hint: config.installHint
|
|
818
|
-
})
|
|
819
|
-
);
|
|
820
|
-
});
|
|
821
|
-
child.on("close", (code) => {
|
|
822
|
-
if (code === 0) {
|
|
823
|
-
resolve3();
|
|
824
|
-
return;
|
|
825
|
-
}
|
|
826
|
-
reject(
|
|
827
|
-
new CliError("user", `The ${config.displayName} CLI installer exited with code ${code ?? "unknown"}.`, {
|
|
828
|
-
hint: config.installHint
|
|
829
|
-
})
|
|
830
|
-
);
|
|
831
|
-
});
|
|
832
|
-
});
|
|
833
|
-
}
|
|
834
|
-
async function offerVendorInstall(config, explicitBinPath) {
|
|
835
|
-
const installer = config.installer;
|
|
836
|
-
if (!installer || explicitBinPath) return null;
|
|
837
|
-
if (process.platform !== "linux" && process.platform !== "darwin") return null;
|
|
838
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) return null;
|
|
839
|
-
console.error(`Could not find the \`${config.defaultBin}\` executable.`);
|
|
840
|
-
console.error(`Install it now by running: ${installer.command}`);
|
|
841
|
-
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
842
|
-
let answer;
|
|
843
|
-
try {
|
|
844
|
-
answer = (await rl.question("Proceed? [y/N] ")).trim().toLowerCase();
|
|
845
|
-
} finally {
|
|
846
|
-
rl.close();
|
|
847
|
-
}
|
|
848
|
-
if (answer !== "y" && answer !== "yes") return null;
|
|
849
|
-
await runVendorInstall(config, installer.command);
|
|
850
|
-
for (const candidate of installer.binCandidates(homedir2())) {
|
|
851
|
-
if (existsSync2(candidate)) {
|
|
852
|
-
if (installer.postInstallNote) console.error(installer.postInstallNote);
|
|
853
|
-
return candidate;
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
return config.defaultBin;
|
|
857
|
-
}
|
|
858
|
-
async function runVendorLoginWithInstallOffer(config, binPath, tempHome, explicitBinPath) {
|
|
859
|
-
try {
|
|
860
|
-
await runVendorLogin(config, binPath, tempHome);
|
|
861
|
-
} catch (err) {
|
|
862
|
-
if (!(err instanceof VendorBinaryMissingError)) throw err;
|
|
863
|
-
const installedBin = await offerVendorInstall(config, explicitBinPath);
|
|
864
|
-
if (!installedBin) throw err;
|
|
865
|
-
await runVendorLogin(config, installedBin, tempHome);
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
function runVendorLogin(config, binPath, tempHome) {
|
|
869
|
-
return runVendorLoginProcess({
|
|
870
|
-
displayName: config.displayName,
|
|
871
|
-
binPath,
|
|
872
|
-
args: config.loginArgs,
|
|
873
|
-
env: tempHome ? { HOME: tempHome, ...config.loginEnv(tempHome) } : {},
|
|
874
|
-
missingBinaryHint: config.installHint,
|
|
875
|
-
retryCommand: `arcanist ${config.harness} login`
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
function hasTokenField(value, tokenFields, depth = 0) {
|
|
879
|
-
if (!value || typeof value !== "object" || Array.isArray(value) || depth > 2) return false;
|
|
880
|
-
const record = value;
|
|
881
|
-
if (tokenFields.some((field) => typeof record[field] === "string" && record[field].trim().length > 0)) {
|
|
882
|
-
return true;
|
|
883
|
-
}
|
|
884
|
-
return Object.values(record).some((nested) => hasTokenField(nested, tokenFields, depth + 1));
|
|
885
|
-
}
|
|
886
|
-
function readDarwinKeychainAuthJson(config) {
|
|
887
|
-
const record = {};
|
|
888
|
-
for (const entry of config.darwinKeychain?.entries ?? []) {
|
|
889
|
-
let value = "";
|
|
890
|
-
try {
|
|
891
|
-
value = execFileSync("security", ["find-generic-password", "-s", entry.service, "-w"], {
|
|
892
|
-
encoding: "utf8"
|
|
893
|
-
}).trim();
|
|
894
|
-
} catch {
|
|
895
|
-
}
|
|
896
|
-
if (value) {
|
|
897
|
-
record[entry.field] = value;
|
|
898
|
-
} else if (entry.required) {
|
|
899
|
-
throw new CliError(
|
|
900
|
-
"user",
|
|
901
|
-
`${config.displayName} login completed but the '${entry.service}' Keychain item could not be read.`,
|
|
902
|
-
{
|
|
903
|
-
hint: `Approve the macOS Keychain access prompt if one appeared, then re-run \`arcanist ${config.harness} login\`.`
|
|
904
|
-
}
|
|
905
|
-
);
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
return JSON.stringify(record);
|
|
909
|
-
}
|
|
910
|
-
async function readLoginAuthJson(config, tempHome) {
|
|
911
|
-
for (const candidate of config.authJsonCandidates) {
|
|
912
|
-
const path = join3(tempHome, candidate);
|
|
913
|
-
if (!existsSync2(path)) continue;
|
|
914
|
-
let raw;
|
|
915
|
-
try {
|
|
916
|
-
raw = await readFile(path, "utf8");
|
|
917
|
-
} catch {
|
|
918
|
-
continue;
|
|
919
|
-
}
|
|
920
|
-
try {
|
|
921
|
-
if (hasTokenField(JSON.parse(raw), config.tokenFields)) return raw;
|
|
922
|
-
} catch {
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
throw new CliError("user", `${config.displayName} login completed but no auth credential file was found.`, {
|
|
926
|
-
hint: `Verify \`${config.defaultBin} ${config.loginArgs.join(" ")}\` succeeds on its own, then re-run \`arcanist ${config.harness} login\`.`
|
|
927
|
-
});
|
|
928
|
-
}
|
|
929
|
-
async function setSubscriptionEnabled(apiConfig, harness, enabled) {
|
|
930
|
-
return apiFetch(apiConfig, `${subscriptionBasePath(harness)}/enabled`, {
|
|
931
|
-
method: "PUT",
|
|
932
|
-
body: JSON.stringify({ enabled })
|
|
933
|
-
});
|
|
934
|
-
}
|
|
935
|
-
async function agentSubscriptionLoginCommand(config, options, command) {
|
|
936
|
-
const { config: apiConfig } = resolveBusinessContext(command, options);
|
|
937
|
-
const binPath = resolveVendorBin(config, options.binPath);
|
|
938
|
-
const explicitBinPath = Boolean(options.binPath?.trim() || process.env[config.binEnvVar]?.trim());
|
|
939
|
-
const captureViaKeychain = process.platform === "darwin" && config.darwinKeychain !== void 0;
|
|
940
|
-
let authJson;
|
|
941
|
-
if (captureViaKeychain) {
|
|
942
|
-
await runVendorLoginWithInstallOffer(config, binPath, null, explicitBinPath);
|
|
943
|
-
authJson = readDarwinKeychainAuthJson(config);
|
|
944
|
-
} else {
|
|
945
|
-
authJson = await withIsolatedLoginDir(`arcanist-${config.harness}-`, async (tempHome) => {
|
|
946
|
-
await runVendorLoginWithInstallOffer(config, binPath, tempHome, explicitBinPath);
|
|
947
|
-
return readLoginAuthJson(config, tempHome);
|
|
948
|
-
});
|
|
949
|
-
}
|
|
950
|
-
const state = await apiFetch(
|
|
951
|
-
apiConfig,
|
|
952
|
-
`${subscriptionBasePath(config.harness)}/auth-json`,
|
|
953
|
-
{
|
|
954
|
-
method: "PUT",
|
|
955
|
-
body: JSON.stringify({ authJson })
|
|
956
|
-
}
|
|
957
|
-
);
|
|
958
|
-
let activated = false;
|
|
959
|
-
let activationError;
|
|
960
|
-
try {
|
|
961
|
-
await setSubscriptionEnabled(apiConfig, config.harness, true);
|
|
962
|
-
activated = true;
|
|
963
|
-
} catch (err) {
|
|
964
|
-
activationError = err instanceof Error ? err.message : String(err);
|
|
965
|
-
}
|
|
966
|
-
emit(command, options, { ...state, enabled: activated }, (payload) => {
|
|
967
|
-
console.log(
|
|
968
|
-
activated ? `${config.displayName} subscription auth saved and activated.` : `${config.displayName} subscription auth saved.`
|
|
969
|
-
);
|
|
970
|
-
if (payload.lastValidationStatus) console.log(`Status: ${payload.lastValidationStatus}`);
|
|
971
|
-
if (!activated) {
|
|
972
|
-
console.log(`Could not activate it automatically${activationError ? ` (${activationError})` : ""}.`);
|
|
973
|
-
console.log(`Run \`arcanist ${config.harness} use on\` to start using it.`);
|
|
974
|
-
}
|
|
975
|
-
console.log(
|
|
976
|
-
`${config.displayName} sessions will use your subscription auth while the selector is on; run \`arcanist ${config.harness} use off\` to switch back.`
|
|
977
|
-
);
|
|
978
|
-
if (captureViaKeychain) {
|
|
979
|
-
console.log(
|
|
980
|
-
`Your local ${config.defaultBin} login also remains active (Keychain-backed); run \`${config.defaultBin} logout\` to remove it.`
|
|
981
|
-
);
|
|
982
|
-
}
|
|
983
|
-
});
|
|
984
|
-
}
|
|
985
|
-
async function agentSubscriptionUseCommand(config, state, options, command) {
|
|
986
|
-
const normalized = state.trim().toLowerCase();
|
|
987
|
-
if (normalized !== "on" && normalized !== "off") {
|
|
988
|
-
throw new CliError("user", `Usage: arcanist ${config.harness} use <on|off>`);
|
|
989
|
-
}
|
|
990
|
-
const enabled = normalized === "on";
|
|
991
|
-
const { config: apiConfig } = resolveBusinessContext(command, options);
|
|
992
|
-
const result = await setSubscriptionEnabled(apiConfig, config.harness, enabled);
|
|
993
|
-
emit(
|
|
994
|
-
command,
|
|
995
|
-
options,
|
|
996
|
-
result,
|
|
997
|
-
() => console.log(
|
|
998
|
-
result.enabled ? `${config.displayName} subscription auth is now selected for ${config.displayName} sessions.` : `${config.displayName} subscription auth is no longer selected.`
|
|
999
|
-
)
|
|
1000
|
-
);
|
|
1001
|
-
}
|
|
1002
|
-
async function agentSubscriptionStatusCommand(config, options, command) {
|
|
1003
|
-
const { config: apiConfig } = resolveBusinessContext(command, options);
|
|
1004
|
-
const payload = await apiFetch(apiConfig, subscriptionBasePath(config.harness));
|
|
1005
|
-
emit(command, options, payload, (state) => {
|
|
1006
|
-
console.log(`Eligible: ${state.eligible ? "yes" : "no"}`);
|
|
1007
|
-
console.log(`Auth saved: ${state.credential.isSet ? "yes" : "no"}`);
|
|
1008
|
-
console.log(`Selected: ${state.enabled ? "yes" : "no"}`);
|
|
1009
|
-
if (state.credential.lastValidationStatus) console.log(`Status: ${state.credential.lastValidationStatus}`);
|
|
1010
|
-
});
|
|
1011
|
-
}
|
|
1012
|
-
async function agentSubscriptionLogoutCommand(config, options, command) {
|
|
1013
|
-
const { config: apiConfig } = resolveBusinessContext(command, options);
|
|
1014
|
-
await setSubscriptionEnabled(apiConfig, config.harness, false).catch(() => {
|
|
1015
|
-
});
|
|
1016
|
-
const payload = await apiFetch(
|
|
1017
|
-
apiConfig,
|
|
1018
|
-
`${subscriptionBasePath(config.harness)}/auth-json`,
|
|
1019
|
-
{ method: "DELETE" }
|
|
1020
|
-
);
|
|
1021
|
-
emit(
|
|
1022
|
-
command,
|
|
1023
|
-
options,
|
|
1024
|
-
payload,
|
|
1025
|
-
() => console.log(`${config.displayName} subscription auth deactivated and cleared.`)
|
|
1026
|
-
);
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
653
|
// ../../shared/utils/timing.ts
|
|
1030
654
|
function sleep(ms) {
|
|
1031
655
|
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
@@ -1157,8 +781,8 @@ async function anubisCommand(prUrl, options = {}, command) {
|
|
|
1157
781
|
}
|
|
1158
782
|
|
|
1159
783
|
// src/commands/artifacts.ts
|
|
1160
|
-
import { existsSync as
|
|
1161
|
-
import { basename, join as
|
|
784
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
785
|
+
import { basename, join as join2, resolve as resolve2 } from "path";
|
|
1162
786
|
async function fetchArtifacts(config, sessionId) {
|
|
1163
787
|
const payload = await apiFetch(
|
|
1164
788
|
config,
|
|
@@ -1173,14 +797,14 @@ function artifactFilename(artifact) {
|
|
|
1173
797
|
}
|
|
1174
798
|
async function downloadArtifact(config, sessionId, artifact, outputDir, usedNames) {
|
|
1175
799
|
const filename = artifactFilename(artifact);
|
|
1176
|
-
const taken = usedNames.has(filename) ||
|
|
800
|
+
const taken = usedNames.has(filename) || existsSync2(join2(outputDir, filename));
|
|
1177
801
|
const targetName = taken ? `${artifact.artifactId}-${filename}` : filename;
|
|
1178
802
|
usedNames.add(targetName);
|
|
1179
803
|
const bytes = await apiFetchBytes(
|
|
1180
804
|
config,
|
|
1181
805
|
`/api/sessions/${encodeURIComponent(sessionId)}/artifacts/${encodeURIComponent(artifact.artifactId)}/view?filename=${encodeURIComponent(filename)}`
|
|
1182
806
|
);
|
|
1183
|
-
const targetPath =
|
|
807
|
+
const targetPath = join2(outputDir, targetName);
|
|
1184
808
|
writeFileSync2(targetPath, bytes);
|
|
1185
809
|
return targetPath;
|
|
1186
810
|
}
|
|
@@ -1266,7 +890,7 @@ async function whoamiCommand(options, command) {
|
|
|
1266
890
|
var MAX_ALL_PAGES = 1e3;
|
|
1267
891
|
async function fetchPages(label, all, initialCursor, fetchPage) {
|
|
1268
892
|
const items = [];
|
|
1269
|
-
let
|
|
893
|
+
let cursor = initialCursor;
|
|
1270
894
|
let nextCursor = null;
|
|
1271
895
|
let pageCount = 0;
|
|
1272
896
|
do {
|
|
@@ -1274,10 +898,10 @@ async function fetchPages(label, all, initialCursor, fetchPage) {
|
|
|
1274
898
|
if (all && pageCount > MAX_ALL_PAGES) {
|
|
1275
899
|
throw new CliError("user", `${label} exceeded ${MAX_ALL_PAGES} pages without reaching the end.`);
|
|
1276
900
|
}
|
|
1277
|
-
const page = await fetchPage(
|
|
901
|
+
const page = await fetchPage(cursor);
|
|
1278
902
|
items.push(...page.items);
|
|
1279
903
|
nextCursor = page.nextCursor;
|
|
1280
|
-
|
|
904
|
+
cursor = nextCursor ?? void 0;
|
|
1281
905
|
} while (all && nextCursor);
|
|
1282
906
|
return { items, nextCursor: all ? null : nextCursor };
|
|
1283
907
|
}
|
|
@@ -1294,10 +918,10 @@ function parseGithubRepoFullName(value) {
|
|
|
1294
918
|
}
|
|
1295
919
|
|
|
1296
920
|
// src/git.ts
|
|
1297
|
-
import { execFileSync
|
|
921
|
+
import { execFileSync } from "child_process";
|
|
1298
922
|
function git(args) {
|
|
1299
923
|
try {
|
|
1300
|
-
return
|
|
924
|
+
return execFileSync("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
1301
925
|
} catch (err) {
|
|
1302
926
|
throw new CliError("user", `git ${args.join(" ")} failed: ${stringifyError(err)}`);
|
|
1303
927
|
}
|
|
@@ -1353,32 +977,7 @@ var AnthropicModel = {
|
|
|
1353
977
|
Sonnet5: "claude-sonnet-5",
|
|
1354
978
|
Fable5: "claude-fable-5"
|
|
1355
979
|
};
|
|
1356
|
-
var
|
|
1357
|
-
KimiK27Code: "kimi-k2.7-code"
|
|
1358
|
-
};
|
|
1359
|
-
var XaiModel = {
|
|
1360
|
-
Grok45: "grok-4.5",
|
|
1361
|
-
Grok43: "grok-4.3",
|
|
1362
|
-
Grok420Reasoning: "grok-4.20-0309-reasoning",
|
|
1363
|
-
Grok420NonReasoning: "grok-4.20-0309-non-reasoning",
|
|
1364
|
-
Grok420MultiAgent: "grok-4.20-multi-agent-0309",
|
|
1365
|
-
GrokBuild01: "grok-build-0.1"
|
|
1366
|
-
};
|
|
1367
|
-
var CursorModel = {
|
|
1368
|
-
Composer25: "composer-2.5"
|
|
1369
|
-
};
|
|
1370
|
-
var GrokBuildModel = {
|
|
1371
|
-
Grok45Byos: "grok-4.5-byos",
|
|
1372
|
-
GrokComposer25Fast: "grok-composer-2.5-fast"
|
|
1373
|
-
};
|
|
1374
|
-
var MODEL_PROVIDERS_SET = /* @__PURE__ */ new Set([
|
|
1375
|
-
"openai",
|
|
1376
|
-
"anthropic",
|
|
1377
|
-
"baseten",
|
|
1378
|
-
"xai",
|
|
1379
|
-
"cursor",
|
|
1380
|
-
"grok"
|
|
1381
|
-
]);
|
|
980
|
+
var MODEL_PROVIDERS_SET = /* @__PURE__ */ new Set(["openai", "anthropic"]);
|
|
1382
981
|
var BACKEND_DESKTOP_IMAGE_FEEDBACK_CONFIGS = {
|
|
1383
982
|
[CODEX_AGENT_RUNTIME_BACKEND]: {
|
|
1384
983
|
backend: CODEX_AGENT_RUNTIME_BACKEND,
|
|
@@ -1623,7 +1222,7 @@ var MODEL_REGISTRY = [
|
|
|
1623
1222
|
// billing. `anthropic/cost.ts` ANTHROPIC_MESSAGES_MODEL_PRICING owns that
|
|
1624
1223
|
// and is intentionally ~3x divergent until Phase 5.
|
|
1625
1224
|
pricing: { inputPerMillion: 5, outputPerMillion: 25, cacheReadPerMillion: 0.5, cacheWritePerMillion: 6.25 },
|
|
1626
|
-
sessionStart: { eligible: true
|
|
1225
|
+
sessionStart: { eligible: true }
|
|
1627
1226
|
},
|
|
1628
1227
|
{
|
|
1629
1228
|
id: AnthropicModel.Opus5,
|
|
@@ -1631,11 +1230,15 @@ var MODEL_REGISTRY = [
|
|
|
1631
1230
|
provider: "anthropic",
|
|
1632
1231
|
backends: [CLAUDE_CODE_AGENT_RUNTIME_BACKEND],
|
|
1633
1232
|
contextWindow: 1e6,
|
|
1233
|
+
// Verified 2026-07-26 against @anthropic-ai/claude-agent-sdk 0.3.219
|
|
1234
|
+
// EffortLevel: Opus 5 supports low/medium/high/xhigh/max. "none" maps to
|
|
1235
|
+
// omitting SDK Options.effort so Claude keeps its adaptive default.
|
|
1634
1236
|
reasoning: { efforts: ["none", "low", "medium", "high", "xhigh", "max"], default: "high" },
|
|
1635
1237
|
// Bridge cost estimate; authoritative Anthropic Messages pricing lives in
|
|
1636
|
-
// apps/control-plane-worker/src/anthropic/cost.ts
|
|
1238
|
+
// apps/control-plane-worker/src/anthropic/cost.ts, where Opus 5 carries the
|
|
1239
|
+
// same rates as Opus 4.8, so this default move has no modeled cost delta.
|
|
1637
1240
|
pricing: { inputPerMillion: 5, outputPerMillion: 25, cacheReadPerMillion: 0.5, cacheWritePerMillion: 6.25 },
|
|
1638
|
-
sessionStart: { eligible: true }
|
|
1241
|
+
sessionStart: { eligible: true, isDefault: true }
|
|
1639
1242
|
},
|
|
1640
1243
|
{
|
|
1641
1244
|
id: AnthropicModel.Sonnet46,
|
|
@@ -1683,212 +1286,11 @@ var MODEL_REGISTRY = [
|
|
|
1683
1286
|
// verified Messages API table.
|
|
1684
1287
|
pricing: { inputPerMillion: 10, outputPerMillion: 50, cacheReadPerMillion: 1, cacheWritePerMillion: 12.5 },
|
|
1685
1288
|
sessionStart: { eligible: true }
|
|
1686
|
-
},
|
|
1687
|
-
{
|
|
1688
|
-
id: BasetenModel.KimiK27Code,
|
|
1689
|
-
name: "Kimi K2.7 Code",
|
|
1690
|
-
provider: "baseten",
|
|
1691
|
-
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1692
|
-
contextWindow: 262e3,
|
|
1693
|
-
// Verified 2026-07-04 against Baseten Model APIs docs, model library, and
|
|
1694
|
-
// changelog: wire id `moonshotai/Kimi-K2.7-Code`, 262k served
|
|
1695
|
-
// context/output, OpenAI SDK compatible, MIT license, tool calling
|
|
1696
|
-
// supported for all Model APIs.
|
|
1697
|
-
providerModelId: "moonshotai/Kimi-K2.7-Code",
|
|
1698
|
-
desktopImageFeedback: {
|
|
1699
|
-
backend: OPENCODE_AGENT_RUNTIME_BACKEND,
|
|
1700
|
-
fixture: "known_image_fixture",
|
|
1701
|
-
deliveryPath: "native_mcp_tool_result_image",
|
|
1702
|
-
verifiedAt: "2026-07-07"
|
|
1703
|
-
},
|
|
1704
|
-
pricing: { inputPerMillion: 0.95, outputPerMillion: 4, cacheReadPerMillion: 0.16 },
|
|
1705
|
-
sessionStart: { eligible: true, isDefault: true }
|
|
1706
|
-
},
|
|
1707
|
-
// xAI models (all text/chat models from https://docs.x.ai/docs/models,
|
|
1708
|
-
// verified 2026-07-15). All run on the opencode backend through the
|
|
1709
|
-
// OpenAI-compatible Chat Completions API at api.x.ai. No reasoning config
|
|
1710
|
-
// for any of them: xAI documents `reasoning_effort` for grok-4.3 only
|
|
1711
|
-
// (https://docs.x.ai/docs/api-reference), AND the opencode backend
|
|
1712
|
-
// intentionally passes no reasoning parameters to OSS providers
|
|
1713
|
-
// (variantReasoning: intentional in backend-capabilities.ts) — grok-4.3's
|
|
1714
|
-
// server-side default (`low`) applies. Pricing records both tiers: xAI
|
|
1715
|
-
// bills the whole request at long-context rates once the prompt crosses
|
|
1716
|
-
// 200k tokens, expressed via `longContext` (bridge cost estimates only).
|
|
1717
|
-
{
|
|
1718
|
-
id: XaiModel.Grok45,
|
|
1719
|
-
name: "Grok 4.5",
|
|
1720
|
-
provider: "xai",
|
|
1721
|
-
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1722
|
-
contextWindow: 5e5,
|
|
1723
|
-
// Verified 2026-07-15 against https://docs.x.ai/docs/pricing: $2/M in,
|
|
1724
|
-
// $6/M out, $0.50/M cached input below 200k prompt tokens; $4/$12/$1.00
|
|
1725
|
-
// at or above it. 500k context.
|
|
1726
|
-
pricing: {
|
|
1727
|
-
inputPerMillion: 2,
|
|
1728
|
-
outputPerMillion: 6,
|
|
1729
|
-
cacheReadPerMillion: 0.5,
|
|
1730
|
-
longContext: { thresholdTokens: 2e5, inputPerMillion: 4, outputPerMillion: 12, cacheReadPerMillion: 1 }
|
|
1731
|
-
},
|
|
1732
|
-
sessionStart: { eligible: true }
|
|
1733
|
-
},
|
|
1734
|
-
{
|
|
1735
|
-
id: XaiModel.Grok43,
|
|
1736
|
-
name: "Grok 4.3",
|
|
1737
|
-
provider: "xai",
|
|
1738
|
-
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1739
|
-
contextWindow: 1e6,
|
|
1740
|
-
// Verified 2026-07-15 against https://docs.x.ai/docs/pricing: $1.25/M in,
|
|
1741
|
-
// $2.50/M out, $0.20/M cached input below 200k prompt tokens;
|
|
1742
|
-
// $2.50/$5.00/$0.40 at or above it. 1M context.
|
|
1743
|
-
pricing: {
|
|
1744
|
-
inputPerMillion: 1.25,
|
|
1745
|
-
outputPerMillion: 2.5,
|
|
1746
|
-
cacheReadPerMillion: 0.2,
|
|
1747
|
-
longContext: { thresholdTokens: 2e5, inputPerMillion: 2.5, outputPerMillion: 5, cacheReadPerMillion: 0.4 }
|
|
1748
|
-
},
|
|
1749
|
-
sessionStart: { eligible: true }
|
|
1750
|
-
},
|
|
1751
|
-
{
|
|
1752
|
-
id: XaiModel.Grok420Reasoning,
|
|
1753
|
-
name: "Grok 4.20 Reasoning",
|
|
1754
|
-
provider: "xai",
|
|
1755
|
-
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1756
|
-
contextWindow: 1e6,
|
|
1757
|
-
// xAI encodes reasoning in distinct model ids for the 4.20 line (like
|
|
1758
|
-
// Cursor), not a per-request parameter. Verified 2026-07-15 against
|
|
1759
|
-
// https://docs.x.ai/docs/pricing: $1.25/M in, $2.50/M out, $0.20/M cached
|
|
1760
|
-
// input below 200k prompt tokens; $2.50/$5.00/$0.40 at or above it. 1M context.
|
|
1761
|
-
pricing: {
|
|
1762
|
-
inputPerMillion: 1.25,
|
|
1763
|
-
outputPerMillion: 2.5,
|
|
1764
|
-
cacheReadPerMillion: 0.2,
|
|
1765
|
-
longContext: { thresholdTokens: 2e5, inputPerMillion: 2.5, outputPerMillion: 5, cacheReadPerMillion: 0.4 }
|
|
1766
|
-
},
|
|
1767
|
-
sessionStart: { eligible: true }
|
|
1768
|
-
},
|
|
1769
|
-
{
|
|
1770
|
-
id: XaiModel.Grok420NonReasoning,
|
|
1771
|
-
name: "Grok 4.20 Non-Reasoning",
|
|
1772
|
-
provider: "xai",
|
|
1773
|
-
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1774
|
-
contextWindow: 1e6,
|
|
1775
|
-
// Verified 2026-07-15 against https://docs.x.ai/docs/pricing: $1.25/M in,
|
|
1776
|
-
// $2.50/M out, $0.20/M cached input below 200k prompt tokens;
|
|
1777
|
-
// $2.50/$5.00/$0.40 at or above it. 1M context.
|
|
1778
|
-
pricing: {
|
|
1779
|
-
inputPerMillion: 1.25,
|
|
1780
|
-
outputPerMillion: 2.5,
|
|
1781
|
-
cacheReadPerMillion: 0.2,
|
|
1782
|
-
longContext: { thresholdTokens: 2e5, inputPerMillion: 2.5, outputPerMillion: 5, cacheReadPerMillion: 0.4 }
|
|
1783
|
-
},
|
|
1784
|
-
sessionStart: { eligible: true }
|
|
1785
|
-
},
|
|
1786
|
-
{
|
|
1787
|
-
id: XaiModel.Grok420MultiAgent,
|
|
1788
|
-
name: "Grok 4.20 Multi-Agent",
|
|
1789
|
-
provider: "xai",
|
|
1790
|
-
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1791
|
-
contextWindow: 1e6,
|
|
1792
|
-
// Verified 2026-07-15 against https://docs.x.ai/docs/pricing: $1.25/M in,
|
|
1793
|
-
// $2.50/M out, $0.20/M cached input below 200k prompt tokens;
|
|
1794
|
-
// $2.50/$5.00/$0.40 at or above it. 1M context.
|
|
1795
|
-
pricing: {
|
|
1796
|
-
inputPerMillion: 1.25,
|
|
1797
|
-
outputPerMillion: 2.5,
|
|
1798
|
-
cacheReadPerMillion: 0.2,
|
|
1799
|
-
longContext: { thresholdTokens: 2e5, inputPerMillion: 2.5, outputPerMillion: 5, cacheReadPerMillion: 0.4 }
|
|
1800
|
-
},
|
|
1801
|
-
sessionStart: { eligible: true },
|
|
1802
|
-
// Cannot run a coding-agent session on a standard xAI key (verified
|
|
1803
|
-
// 2026-07-15 against api.x.ai with our production key): chat completions
|
|
1804
|
-
// rejects the model outright ("Multi Agent requests are not allowed on
|
|
1805
|
-
// chat completions") and the Responses API 400s any request carrying
|
|
1806
|
-
// client-side tools ("Client-side tools for multi-agent models require
|
|
1807
|
-
// beta access") — and the harness always sends tools. Hidden from the
|
|
1808
|
-
// picker until xAI grants beta access; CLI/API selection stays open for
|
|
1809
|
-
// retesting.
|
|
1810
|
-
visibility: "internal_probe"
|
|
1811
|
-
},
|
|
1812
|
-
{
|
|
1813
|
-
id: XaiModel.GrokBuild01,
|
|
1814
|
-
name: "Grok Build 0.1",
|
|
1815
|
-
provider: "xai",
|
|
1816
|
-
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1817
|
-
contextWindow: 256e3,
|
|
1818
|
-
// Verified 2026-07-15 against https://docs.x.ai/docs/pricing: $1/M in,
|
|
1819
|
-
// $2/M out, $0.20/M cached input below 200k prompt tokens; $2/$4/$0.40 at
|
|
1820
|
-
// or above it. 256k context.
|
|
1821
|
-
pricing: {
|
|
1822
|
-
inputPerMillion: 1,
|
|
1823
|
-
outputPerMillion: 2,
|
|
1824
|
-
cacheReadPerMillion: 0.2,
|
|
1825
|
-
longContext: { thresholdTokens: 2e5, inputPerMillion: 2, outputPerMillion: 4, cacheReadPerMillion: 0.4 }
|
|
1826
|
-
},
|
|
1827
|
-
sessionStart: { eligible: true }
|
|
1828
|
-
},
|
|
1829
|
-
{
|
|
1830
|
-
id: CursorModel.Composer25,
|
|
1831
|
-
name: "Composer 2.5",
|
|
1832
|
-
provider: "cursor",
|
|
1833
|
-
backends: [CURSOR_AGENT_RUNTIME_BACKEND],
|
|
1834
|
-
// Cursor bills Composer usage through the user's Cursor account (API key
|
|
1835
|
-
// or subscription); Arcanist does not meter it, so no registry pricing is
|
|
1836
|
-
// recorded (costTracked: false requires pricing to stay undefined). No
|
|
1837
|
-
// reasoning config: Cursor encodes effort in distinct model ids
|
|
1838
|
-
// (`--list-models`), not a per-request parameter. Context window is not
|
|
1839
|
-
// published for Composer 2.5 (checked cursor.com/docs/models 2026-07-15),
|
|
1840
|
-
// so none is recorded.
|
|
1841
|
-
costTracked: false,
|
|
1842
|
-
sessionStart: { eligible: true, isDefault: true }
|
|
1843
|
-
},
|
|
1844
|
-
{
|
|
1845
|
-
id: GrokBuildModel.Grok45Byos,
|
|
1846
|
-
name: "Grok 4.5 (Subscription)",
|
|
1847
|
-
provider: "grok",
|
|
1848
|
-
backends: [GROK_AGENT_RUNTIME_BACKEND],
|
|
1849
|
-
// Wire id `grok-4.5` (the CLI's subscription default) collides with the
|
|
1850
|
-
// xai/opencode registry id, so the Arcanist id is suffixed and the wire id
|
|
1851
|
-
// rides providerModelId. Billed through the user's Grok subscription via
|
|
1852
|
-
// the Grok Build CLI (cli-chat-proxy.grok.com); Arcanist does not meter it
|
|
1853
|
-
// (costTracked: false requires pricing to stay undefined). Context window
|
|
1854
|
-
// verified 2026-07-15 against https://docs.x.ai/docs/models (grok-4.5,
|
|
1855
|
-
// 500k). No reasoning config: the CLI's --reasoning-effort is documented
|
|
1856
|
-
// for reasoning models only and grok-4.5 is classified no-reasoning per
|
|
1857
|
-
// the xai registry entries above.
|
|
1858
|
-
providerModelId: "grok-4.5",
|
|
1859
|
-
contextWindow: 5e5,
|
|
1860
|
-
costTracked: false,
|
|
1861
|
-
sessionStart: { eligible: true, isDefault: true },
|
|
1862
|
-
// Internal probe (ARC-1704): hidden from the public model picker except
|
|
1863
|
-
// for users with an active Grok subscription (Codex Spark precedent);
|
|
1864
|
-
// CLI/API-selectable and session-startable by internal Arcanist
|
|
1865
|
-
// businesses only.
|
|
1866
|
-
visibility: "internal_probe",
|
|
1867
|
-
requiresGrokSubscriptionAuth: true
|
|
1868
|
-
},
|
|
1869
|
-
{
|
|
1870
|
-
id: GrokBuildModel.GrokComposer25Fast,
|
|
1871
|
-
name: "Grok Composer 2.5 Fast",
|
|
1872
|
-
provider: "grok",
|
|
1873
|
-
backends: [GROK_AGENT_RUNTIME_BACKEND],
|
|
1874
|
-
// Cursor's Composer 2.5 Fast served through Grok Build (verified in
|
|
1875
|
-
// `grok models` 0.2.101 under a live subscription, 2026-07-15). Wire id
|
|
1876
|
-
// matches the registry id, so no providerModelId. Context window is not
|
|
1877
|
-
// published for Composer variants (cursor.com/docs/models), so none is
|
|
1878
|
-
// recorded. Subscription-billed, not metered by Arcanist.
|
|
1879
|
-
costTracked: false,
|
|
1880
|
-
sessionStart: { eligible: true },
|
|
1881
|
-
visibility: "internal_probe",
|
|
1882
|
-
requiresGrokSubscriptionAuth: true
|
|
1883
1289
|
}
|
|
1884
1290
|
];
|
|
1885
1291
|
var MODEL_PROVIDER_NAMES = {
|
|
1886
1292
|
openai: "OpenAI",
|
|
1887
|
-
anthropic: "Anthropic"
|
|
1888
|
-
baseten: "Baseten",
|
|
1889
|
-
xai: "xAI",
|
|
1890
|
-
cursor: "Cursor",
|
|
1891
|
-
grok: "Grok Build"
|
|
1293
|
+
anthropic: "Anthropic"
|
|
1892
1294
|
};
|
|
1893
1295
|
function buildSessionStartModelIdsByBackend() {
|
|
1894
1296
|
const byBackend = Object.fromEntries(AGENT_RUNTIME_BACKENDS.map((backend) => [backend, []]));
|
|
@@ -1926,10 +1328,7 @@ var VALID_SESSION_START_MODEL_IDS_BY_BACKEND = {
|
|
|
1926
1328
|
[CODEX_AGENT_RUNTIME_BACKEND]: new Set(SESSION_START_MODEL_IDS_BY_BACKEND[CODEX_AGENT_RUNTIME_BACKEND]),
|
|
1927
1329
|
[CLAUDE_CODE_AGENT_RUNTIME_BACKEND]: new Set(
|
|
1928
1330
|
SESSION_START_MODEL_IDS_BY_BACKEND[CLAUDE_CODE_AGENT_RUNTIME_BACKEND]
|
|
1929
|
-
)
|
|
1930
|
-
[OPENCODE_AGENT_RUNTIME_BACKEND]: new Set(SESSION_START_MODEL_IDS_BY_BACKEND[OPENCODE_AGENT_RUNTIME_BACKEND]),
|
|
1931
|
-
[CURSOR_AGENT_RUNTIME_BACKEND]: new Set(SESSION_START_MODEL_IDS_BY_BACKEND[CURSOR_AGENT_RUNTIME_BACKEND]),
|
|
1932
|
-
[GROK_AGENT_RUNTIME_BACKEND]: new Set(SESSION_START_MODEL_IDS_BY_BACKEND[GROK_AGENT_RUNTIME_BACKEND])
|
|
1331
|
+
)
|
|
1933
1332
|
};
|
|
1934
1333
|
var MODEL_CONTEXT_WINDOWS = {
|
|
1935
1334
|
...Object.fromEntries(
|
|
@@ -2036,6 +1435,12 @@ function buildModelProviderGroups(models2) {
|
|
|
2036
1435
|
reasoning: model.reasoning
|
|
2037
1436
|
});
|
|
2038
1437
|
}
|
|
1438
|
+
const defaultModelIds = new Set(
|
|
1439
|
+
models2.filter((model) => model.sessionStart?.isDefault === true).map((model) => model.id)
|
|
1440
|
+
);
|
|
1441
|
+
for (const group of groups.values()) {
|
|
1442
|
+
group.models.sort((a, b) => Number(defaultModelIds.has(b.id)) - Number(defaultModelIds.has(a.id)));
|
|
1443
|
+
}
|
|
2039
1444
|
return [...groups.values()];
|
|
2040
1445
|
}
|
|
2041
1446
|
var SESSION_START_MODEL_ID_SET_ANY_BACKEND = new Set(
|
|
@@ -2051,27 +1456,11 @@ var CODEX_SUBSCRIPTION_SESSION_START_MODEL_PROVIDER_GROUPS = buildModelProviderG
|
|
|
2051
1456
|
(model) => SESSION_START_MODEL_ID_SET_ANY_BACKEND.has(model.id) && (model.visibility !== "internal_probe" || model.requiresCodexSubscriptionAuth === true)
|
|
2052
1457
|
)
|
|
2053
1458
|
);
|
|
2054
|
-
function buildSubscriptionAwareGroups(include) {
|
|
2055
|
-
return buildModelProviderGroups(
|
|
2056
|
-
MODEL_REGISTRY.filter(
|
|
2057
|
-
(model) => SESSION_START_MODEL_ID_SET_ANY_BACKEND.has(model.id) && (model.visibility !== "internal_probe" || include.codexSubscription && model.requiresCodexSubscriptionAuth === true || include.grokSubscription && model.requiresGrokSubscriptionAuth === true)
|
|
2058
|
-
)
|
|
2059
|
-
);
|
|
2060
|
-
}
|
|
2061
|
-
var SESSION_START_MODEL_PROVIDER_GROUPS_BY_SUBSCRIPTIONS = {
|
|
2062
|
-
"false:false": PUBLIC_SESSION_START_MODEL_PROVIDER_GROUPS,
|
|
2063
|
-
"false:true": buildSubscriptionAwareGroups({ codexSubscription: false, grokSubscription: true }),
|
|
2064
|
-
"true:false": CODEX_SUBSCRIPTION_SESSION_START_MODEL_PROVIDER_GROUPS,
|
|
2065
|
-
"true:true": buildSubscriptionAwareGroups({ codexSubscription: true, grokSubscription: true })
|
|
2066
|
-
};
|
|
2067
1459
|
|
|
2068
1460
|
// src/commands/model-options.ts
|
|
2069
1461
|
function backendForProviderPrefix(rawModel) {
|
|
2070
1462
|
const provider = rawModel.match(/^([a-z]+)[/:]/i)?.[1]?.toLowerCase();
|
|
2071
1463
|
if (provider === "anthropic") return CLAUDE_CODE_AGENT_RUNTIME_BACKEND;
|
|
2072
|
-
if (provider === "baseten" || provider === "xai") return OPENCODE_AGENT_RUNTIME_BACKEND;
|
|
2073
|
-
if (provider === "cursor") return CURSOR_AGENT_RUNTIME_BACKEND;
|
|
2074
|
-
if (provider === "grok") return GROK_AGENT_RUNTIME_BACKEND;
|
|
2075
1464
|
return void 0;
|
|
2076
1465
|
}
|
|
2077
1466
|
function resolveModelAndBackend(options) {
|
|
@@ -2113,7 +1502,7 @@ var AUTOMATION_ERROR_HINTS = {
|
|
|
2113
1502
|
slack_channel_unavailable: "Check the Slack channel ID and confirm the bot can see the channel.",
|
|
2114
1503
|
slack_bot_not_in_channel: "Invite the Arcanist bot to the channel, then retry.",
|
|
2115
1504
|
rule_cap_reached: "Delete or disable an existing automation before creating another one. The cap is 20 enabled rules.",
|
|
2116
|
-
model_not_available: "That model's backend (Claude
|
|
1505
|
+
model_not_available: "That model's backend (Claude) is limited to Arcanist team businesses; use the codex default or a codex model.",
|
|
2117
1506
|
repo_skills_unavailable: "Arcanist could not verify the repo's skills right now. Retry once GitHub skill discovery is healthy.",
|
|
2118
1507
|
unknown_skill: "That leading slash skill does not exist in the selected repository."
|
|
2119
1508
|
};
|
|
@@ -2161,10 +1550,10 @@ async function listAutomationsCommand(options, command) {
|
|
|
2161
1550
|
"automations list --all",
|
|
2162
1551
|
options.all === true,
|
|
2163
1552
|
options.cursor,
|
|
2164
|
-
async (
|
|
1553
|
+
async (cursor) => {
|
|
2165
1554
|
const query = new URLSearchParams();
|
|
2166
1555
|
if (options.limit) query.set("limit", options.limit);
|
|
2167
|
-
if (
|
|
1556
|
+
if (cursor) query.set("cursor", cursor);
|
|
2168
1557
|
const payload = await automationApiFetch(
|
|
2169
1558
|
config,
|
|
2170
1559
|
`/api/automation/schedules${query.size ? `?${query.toString()}` : ""}`
|
|
@@ -2245,8 +1634,73 @@ function formatTime(value) {
|
|
|
2245
1634
|
}
|
|
2246
1635
|
|
|
2247
1636
|
// src/commands/codex.ts
|
|
2248
|
-
import { readFile
|
|
2249
|
-
import { join as
|
|
1637
|
+
import { readFile } from "fs/promises";
|
|
1638
|
+
import { join as join4 } from "path";
|
|
1639
|
+
|
|
1640
|
+
// src/vendor-login.ts
|
|
1641
|
+
import { spawn } from "child_process";
|
|
1642
|
+
import { rmSync } from "fs";
|
|
1643
|
+
import { mkdtemp, rm } from "fs/promises";
|
|
1644
|
+
import { tmpdir } from "os";
|
|
1645
|
+
import { join as join3 } from "path";
|
|
1646
|
+
function runVendorLoginProcess(spec) {
|
|
1647
|
+
return new Promise((resolve3, reject) => {
|
|
1648
|
+
const child = spawn(spec.binPath, spec.args, {
|
|
1649
|
+
stdio: "inherit",
|
|
1650
|
+
env: { ...process.env, ...spec.env }
|
|
1651
|
+
});
|
|
1652
|
+
child.on("error", (err) => {
|
|
1653
|
+
if (err.code === "ENOENT") {
|
|
1654
|
+
reject(
|
|
1655
|
+
new CliError("user", `Could not find the \`${spec.binPath}\` executable.`, {
|
|
1656
|
+
hint: spec.missingBinaryHint
|
|
1657
|
+
})
|
|
1658
|
+
);
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
reject(new CliError("user", `Failed to launch \`${spec.binPath} ${spec.args.join(" ")}\`: ${err.message}`));
|
|
1662
|
+
});
|
|
1663
|
+
child.on("close", (code) => {
|
|
1664
|
+
if (code === 0) {
|
|
1665
|
+
resolve3();
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
reject(
|
|
1669
|
+
new CliError("user", `\`${spec.binPath} ${spec.args.join(" ")}\` exited with code ${code ?? "unknown"}.`, {
|
|
1670
|
+
hint: `Complete the ${spec.displayName} login, then re-run \`${spec.retryCommand}\`.`
|
|
1671
|
+
})
|
|
1672
|
+
);
|
|
1673
|
+
});
|
|
1674
|
+
});
|
|
1675
|
+
}
|
|
1676
|
+
async function withIsolatedLoginDir(prefix, fn) {
|
|
1677
|
+
let tempDir;
|
|
1678
|
+
const handleSigint = () => {
|
|
1679
|
+
if (tempDir) {
|
|
1680
|
+
try {
|
|
1681
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
1682
|
+
} catch {
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
process.exit(EXIT_CODE_INTERRUPTED);
|
|
1686
|
+
};
|
|
1687
|
+
process.on("SIGINT", handleSigint);
|
|
1688
|
+
try {
|
|
1689
|
+
tempDir = await mkdtemp(join3(tmpdir(), prefix));
|
|
1690
|
+
return await fn(tempDir);
|
|
1691
|
+
} finally {
|
|
1692
|
+
try {
|
|
1693
|
+
if (tempDir) {
|
|
1694
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
} finally {
|
|
1698
|
+
process.off("SIGINT", handleSigint);
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
// src/commands/codex.ts
|
|
2250
1704
|
var CODEX_SUBSCRIPTION_PATH = "/api/settings/codex-subscription";
|
|
2251
1705
|
var CODEX_SUBSCRIPTION_AUTH_JSON_PATH = "/api/settings/codex-subscription/auth-json";
|
|
2252
1706
|
var CODEX_SUBSCRIPTION_ENABLED_PATH = "/api/settings/codex-subscription/enabled";
|
|
@@ -2284,7 +1738,7 @@ async function codexLoginCommand(options, command) {
|
|
|
2284
1738
|
await runCodexDeviceLogin(codexPath, codexHome);
|
|
2285
1739
|
let raw;
|
|
2286
1740
|
try {
|
|
2287
|
-
raw = await
|
|
1741
|
+
raw = await readFile(join4(codexHome, "auth.json"), "utf8");
|
|
2288
1742
|
} catch {
|
|
2289
1743
|
throw new CliError("user", "Codex login completed but no auth.json was written.", {
|
|
2290
1744
|
hint: "Verify `codex login --device-auth` succeeds on its own, then re-run `arcanist codex login`."
|
|
@@ -2357,7 +1811,7 @@ async function codexLogoutCommand(options, command) {
|
|
|
2357
1811
|
}
|
|
2358
1812
|
|
|
2359
1813
|
// src/uploads.ts
|
|
2360
|
-
import { readFile as
|
|
1814
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
2361
1815
|
import { basename as basename2, extname } from "path";
|
|
2362
1816
|
|
|
2363
1817
|
// ../../shared/constants/uploads.ts
|
|
@@ -2460,7 +1914,7 @@ async function resolveUploadedFileOptions(files) {
|
|
|
2460
1914
|
paths.map(async (path) => {
|
|
2461
1915
|
const name = basename2(path);
|
|
2462
1916
|
try {
|
|
2463
|
-
return { name, content: await
|
|
1917
|
+
return { name, content: await readFile2(path, "utf8") };
|
|
2464
1918
|
} catch (err) {
|
|
2465
1919
|
const message = stringifyError(err);
|
|
2466
1920
|
throw new CliError("user", `Failed to read uploaded file ${path}: ${message}`);
|
|
@@ -4863,7 +4317,7 @@ async function reviewCommand(prUrl, options = {}, command) {
|
|
|
4863
4317
|
}
|
|
4864
4318
|
|
|
4865
4319
|
// src/commands/sandbox.ts
|
|
4866
|
-
import { existsSync as
|
|
4320
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
4867
4321
|
import { dirname as dirname2 } from "path";
|
|
4868
4322
|
|
|
4869
4323
|
// ../../shared/sandbox-layer/parser.ts
|
|
@@ -5410,7 +4864,7 @@ function assertCleanAndPushed() {
|
|
|
5410
4864
|
throw new CliError("user", "Current commit is not pushed; push before building the sandbox layer.");
|
|
5411
4865
|
}
|
|
5412
4866
|
function assertManifestExists(path) {
|
|
5413
|
-
if (!
|
|
4867
|
+
if (!existsSync3(path)) throw new CliError("user", `Missing sandbox manifest: ${path}`);
|
|
5414
4868
|
}
|
|
5415
4869
|
function repoPath(repo) {
|
|
5416
4870
|
return `${repo.owner}/${repo.repo}`;
|
|
@@ -5627,9 +5081,9 @@ function sourceBody(sourceRepo, manifestPath) {
|
|
|
5627
5081
|
}
|
|
5628
5082
|
async function sandboxInitCommand(options = {}, command) {
|
|
5629
5083
|
const runtime = getRuntimeOptions(command, options);
|
|
5630
|
-
if (
|
|
5084
|
+
if (existsSync3(DEFAULT_MANIFEST_PATH)) throw new CliError("conflict", `${DEFAULT_MANIFEST_PATH} already exists`);
|
|
5631
5085
|
const layerPath = ".arcanist/sandbox.layer.Dockerfile";
|
|
5632
|
-
if (
|
|
5086
|
+
if (existsSync3(layerPath)) throw new CliError("conflict", `${layerPath} already exists`);
|
|
5633
5087
|
mkdirSync3(dirname2(DEFAULT_MANIFEST_PATH), { recursive: true });
|
|
5634
5088
|
writeFileSync3(
|
|
5635
5089
|
DEFAULT_MANIFEST_PATH,
|
|
@@ -5939,14 +5393,14 @@ async function listSessionsCommand(options, command) {
|
|
|
5939
5393
|
"sessions list --all",
|
|
5940
5394
|
options.all === true,
|
|
5941
5395
|
options.cursor,
|
|
5942
|
-
async (
|
|
5396
|
+
async (cursor) => {
|
|
5943
5397
|
const query = new URLSearchParams();
|
|
5944
5398
|
if (options.status) query.set("status", options.status);
|
|
5945
5399
|
if (options.scope) query.set("scope", options.scope);
|
|
5946
5400
|
if (options.search) query.set("q", options.search);
|
|
5947
5401
|
if (options.repo) query.set("repo", options.repo);
|
|
5948
5402
|
if (options.limit) query.set("limit", options.limit);
|
|
5949
|
-
if (
|
|
5403
|
+
if (cursor) query.set("cursor", cursor);
|
|
5950
5404
|
const payload2 = await apiFetch(
|
|
5951
5405
|
config,
|
|
5952
5406
|
`/api/sessions${query.size ? `?${query.toString()}` : ""}`
|
|
@@ -6173,10 +5627,10 @@ async function listTokensCommand(options, command) {
|
|
|
6173
5627
|
"tokens list --all",
|
|
6174
5628
|
options.all === true,
|
|
6175
5629
|
options.cursor,
|
|
6176
|
-
async (
|
|
5630
|
+
async (cursor) => {
|
|
6177
5631
|
const query = new URLSearchParams();
|
|
6178
5632
|
if (options.limit) query.set("limit", options.limit);
|
|
6179
|
-
if (
|
|
5633
|
+
if (cursor) query.set("cursor", cursor);
|
|
6180
5634
|
const payload2 = await apiFetch(
|
|
6181
5635
|
config,
|
|
6182
5636
|
`/api/cli-tokens${query.size ? `?${query.toString()}` : ""}`
|
|
@@ -6416,56 +5870,6 @@ Examples:
|
|
|
6416
5870
|
codex.command("use <state>").description("Turn using your saved Codex subscription auth for OpenAI sessions on or off (state: on|off)").action((state, options, command) => codexUseCommand(state, options, command));
|
|
6417
5871
|
codex.command("status").description("Show Codex subscription availability and whether auth is saved").action((options, command) => codexStatusCommand(options, command));
|
|
6418
5872
|
codex.command("logout").description("Deactivate the selector and remove the stored Codex subscription auth for your user").action((options, command) => codexLogoutCommand(options, command));
|
|
6419
|
-
var grok = program.command("grok").description("Grok (xAI) subscription (bring-your-own-subscription) commands");
|
|
6420
|
-
grok.command("login").description("Authenticate a Grok (xAI) subscription and store it for future Grok BYOS sessions").option("--grok-path <path>", "Path to the grok executable (default: grok on PATH, or ARCANIST_GROK_BIN)").addHelpText(
|
|
6421
|
-
"after",
|
|
6422
|
-
`
|
|
6423
|
-
Runs the Grok CLI device-authorization login locally under a temporary HOME, then uploads the
|
|
6424
|
-
resulting auth.json to Arcanist (encrypted, per user) and activates the selector. Your workspace
|
|
6425
|
-
must have Grok subscription auth enabled. The credential is never written to your default ~/.grok.
|
|
6426
|
-
While the selector is on, Grok Build sessions run on your subscription auth.
|
|
6427
|
-
If the grok CLI is not installed, you will be offered its official install script ([y/N] prompt,
|
|
6428
|
-
interactive terminals only).
|
|
6429
|
-
|
|
6430
|
-
Examples:
|
|
6431
|
-
arcanist grok login
|
|
6432
|
-
arcanist grok login --grok-path /usr/local/bin/grok
|
|
6433
|
-
`
|
|
6434
|
-
).action(
|
|
6435
|
-
(options, command) => agentSubscriptionLoginCommand(GROK_SUBSCRIPTION_CLI_CONFIG, { ...options, binPath: options.grokPath }, command)
|
|
6436
|
-
);
|
|
6437
|
-
grok.command("use <state>").description("Turn using your saved Grok subscription auth on or off (state: on|off)").action(
|
|
6438
|
-
(state, options, command) => agentSubscriptionUseCommand(GROK_SUBSCRIPTION_CLI_CONFIG, state, options, command)
|
|
6439
|
-
);
|
|
6440
|
-
grok.command("status").description("Show whether your workspace is eligible and whether a Grok subscription auth is saved").action((options, command) => agentSubscriptionStatusCommand(GROK_SUBSCRIPTION_CLI_CONFIG, options, command));
|
|
6441
|
-
grok.command("logout").description("Deactivate the selector and remove the stored Grok subscription auth for your user").action((options, command) => agentSubscriptionLogoutCommand(GROK_SUBSCRIPTION_CLI_CONFIG, options, command));
|
|
6442
|
-
var cursor = program.command("cursor").description("Cursor subscription (bring-your-own-subscription) commands");
|
|
6443
|
-
cursor.command("login").description("Authenticate a Cursor subscription and store it for future Cursor BYOS sessions").option(
|
|
6444
|
-
"--cursor-path <path>",
|
|
6445
|
-
"Path to the cursor-agent executable (default: cursor-agent on PATH, or ARCANIST_CURSOR_AGENT_BIN)"
|
|
6446
|
-
).addHelpText(
|
|
6447
|
-
"after",
|
|
6448
|
-
`
|
|
6449
|
-
Runs the Cursor CLI login locally under a temporary HOME/CURSOR_CONFIG_DIR, then uploads the
|
|
6450
|
-
captured auth credential to Arcanist (encrypted, per user) and activates the selector. Your
|
|
6451
|
-
workspace must have Cursor subscription auth enabled. Cursor's login-token location is not
|
|
6452
|
-
formally documented; if capture fails, use a Cursor API key in Settings instead. While the
|
|
6453
|
-
selector is on, Cursor sessions run on your subscription auth instead of a Cursor API key.
|
|
6454
|
-
If the cursor-agent CLI is not installed, you will be offered its official install script
|
|
6455
|
-
([y/N] prompt, interactive terminals only).
|
|
6456
|
-
|
|
6457
|
-
Examples:
|
|
6458
|
-
arcanist cursor login
|
|
6459
|
-
arcanist cursor login --cursor-path /usr/local/bin/cursor-agent
|
|
6460
|
-
`
|
|
6461
|
-
).action(
|
|
6462
|
-
(options, command) => agentSubscriptionLoginCommand(CURSOR_SUBSCRIPTION_CLI_CONFIG, { ...options, binPath: options.cursorPath }, command)
|
|
6463
|
-
);
|
|
6464
|
-
cursor.command("use <state>").description("Turn using your saved Cursor subscription auth on or off (state: on|off)").action(
|
|
6465
|
-
(state, options, command) => agentSubscriptionUseCommand(CURSOR_SUBSCRIPTION_CLI_CONFIG, state, options, command)
|
|
6466
|
-
);
|
|
6467
|
-
cursor.command("status").description("Show whether your workspace is eligible and whether a Cursor subscription auth is saved").action((options, command) => agentSubscriptionStatusCommand(CURSOR_SUBSCRIPTION_CLI_CONFIG, options, command));
|
|
6468
|
-
cursor.command("logout").description("Deactivate the selector and remove the stored Cursor subscription auth for your user").action((options, command) => agentSubscriptionLogoutCommand(CURSOR_SUBSCRIPTION_CLI_CONFIG, options, command));
|
|
6469
5873
|
var sessions = program.command("sessions").description("Session commands");
|
|
6470
5874
|
program.command("review <pr-url>").description("Run a Zeus review for a GitHub pull request").option("--focus <text>", "Focus the review on a specific concern").option("--model <model>", "Pin the reviewer model (Arcanist members only); defaults to automatic routing").option("--wait", "Wait for the review and print its verdict and findings").option("--poll-interval <ms>", "Polling interval in milliseconds while waiting (default 10000)").addHelpText(
|
|
6471
5875
|
"after",
|