@tryarcanist/cli 0.1.206 → 0.1.208
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 +291 -22
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,8 +8,9 @@ import { Command } from "commander";
|
|
|
8
8
|
import { execFileSync, spawn } from "child_process";
|
|
9
9
|
import { existsSync as existsSync2, rmSync } from "fs";
|
|
10
10
|
import { mkdtemp, readFile, rm } from "fs/promises";
|
|
11
|
-
import { tmpdir } from "os";
|
|
11
|
+
import { homedir as homedir2, tmpdir } from "os";
|
|
12
12
|
import { join as join2 } from "path";
|
|
13
|
+
import { createInterface as createInterface2 } from "readline/promises";
|
|
13
14
|
|
|
14
15
|
// src/api.ts
|
|
15
16
|
import { createRequire } from "module";
|
|
@@ -253,6 +254,8 @@ var CONFIG_DIR = join(homedir(), ".arcanist");
|
|
|
253
254
|
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
254
255
|
var PROJECT_CONFIG_FILE = ".arcanist-cli.json";
|
|
255
256
|
var DEFAULT_API_URL = "https://app.tryarcanist.com";
|
|
257
|
+
var SANDBOX_CLI_AUTH_WAIT_TIMEOUT_MS = 1e4;
|
|
258
|
+
var SANDBOX_CLI_AUTH_WAIT_INTERVAL_MS = 100;
|
|
256
259
|
function loadFileConfig() {
|
|
257
260
|
try {
|
|
258
261
|
return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
@@ -261,11 +264,11 @@ function loadFileConfig() {
|
|
|
261
264
|
}
|
|
262
265
|
}
|
|
263
266
|
function loadConfig(overrides = {}) {
|
|
264
|
-
const fileConfig = loadFileConfig();
|
|
265
267
|
const completeEnvOrFlagConfig = resolveCompleteEnvOrFlagConfig(overrides);
|
|
266
268
|
if (completeEnvOrFlagConfig) return validateAndNormalizeConfig(completeEnvOrFlagConfig);
|
|
267
269
|
const projectConfig = loadProjectConfig();
|
|
268
270
|
const envOrFlagConfig = resolveEnvOrFlagConfig(overrides, projectConfig !== null);
|
|
271
|
+
const fileConfig = !projectConfig && shouldWaitForSandboxCliAuth() ? waitForSandboxCliAuthConfig() : loadFileConfig();
|
|
269
272
|
const apiUrl = envOrFlagConfig?.apiUrl ?? projectConfig?.apiUrl ?? fileConfig?.apiUrl;
|
|
270
273
|
const token = envOrFlagConfig?.token ?? projectConfig?.token ?? fileConfig?.token;
|
|
271
274
|
if (!apiUrl || !token) return null;
|
|
@@ -352,6 +355,24 @@ function validateAndNormalizeConfig(config) {
|
|
|
352
355
|
if (urlError) throw new CliError("user", urlError);
|
|
353
356
|
return { apiUrl: normalizeBaseUrl(config.apiUrl), token: config.token };
|
|
354
357
|
}
|
|
358
|
+
function shouldWaitForSandboxCliAuth() {
|
|
359
|
+
const pendingPath = process.env.ARCANIST_CLI_AUTH_PENDING_PATH;
|
|
360
|
+
return Boolean(pendingPath && existsSync(pendingPath));
|
|
361
|
+
}
|
|
362
|
+
function waitForSandboxCliAuthConfig() {
|
|
363
|
+
const readyPath = process.env.ARCANIST_CLI_AUTH_READY_PATH;
|
|
364
|
+
const failedPath = process.env.ARCANIST_CLI_AUTH_FAILED_PATH;
|
|
365
|
+
const deadline = Date.now() + SANDBOX_CLI_AUTH_WAIT_TIMEOUT_MS;
|
|
366
|
+
while (Date.now() <= deadline) {
|
|
367
|
+
if (readyPath && existsSync(readyPath)) return loadFileConfig();
|
|
368
|
+
if (failedPath && existsSync(failedPath)) return null;
|
|
369
|
+
sleepSync(SANDBOX_CLI_AUTH_WAIT_INTERVAL_MS);
|
|
370
|
+
}
|
|
371
|
+
return readyPath && existsSync(readyPath) ? loadFileConfig() : null;
|
|
372
|
+
}
|
|
373
|
+
function sleepSync(ms) {
|
|
374
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
375
|
+
}
|
|
355
376
|
function findGitRoot(cwd) {
|
|
356
377
|
let current = cwd;
|
|
357
378
|
while (true) {
|
|
@@ -628,7 +649,19 @@ var GROK_SUBSCRIPTION_CLI_CONFIG = {
|
|
|
628
649
|
// "…"}} — so the credential fields live one level down and the token field
|
|
629
650
|
// is named `key`. Token detection scans nested objects.
|
|
630
651
|
tokenFields: ["access_token", "refresh_token", "key"],
|
|
631
|
-
installHint: "Install the Grok CLI (https://x.ai/cli), or point at it with --grok-path <path> or ARCANIST_GROK_BIN."
|
|
652
|
+
installHint: "Install the Grok CLI (https://x.ai/cli), or point at it with --grok-path <path> or ARCANIST_GROK_BIN.",
|
|
653
|
+
// Official Grok Build installer: installs `grok` (plus an `agent` alias)
|
|
654
|
+
// under ~/.grok/bin, symlinks into ~/.local/bin or /usr/local/bin when
|
|
655
|
+
// writable, and appends PATH exports to shell rc files itself.
|
|
656
|
+
installer: {
|
|
657
|
+
command: "curl -fsSL https://x.ai/cli/install.sh | bash",
|
|
658
|
+
binCandidates: (home) => [
|
|
659
|
+
join2(home, ".grok", "bin", "grok"),
|
|
660
|
+
join2(home, ".local", "bin", "grok"),
|
|
661
|
+
"/usr/local/bin/grok"
|
|
662
|
+
],
|
|
663
|
+
postInstallNote: "Grok CLI installed. Restart your shell if `grok` is not found on PATH later."
|
|
664
|
+
}
|
|
632
665
|
};
|
|
633
666
|
var CURSOR_SUBSCRIPTION_CLI_CONFIG = {
|
|
634
667
|
harness: "cursor",
|
|
@@ -659,6 +692,15 @@ var CURSOR_SUBSCRIPTION_CLI_CONFIG = {
|
|
|
659
692
|
{ service: "cursor-access-token", field: "accessToken", required: true },
|
|
660
693
|
{ service: "cursor-refresh-token", field: "refreshToken", required: false }
|
|
661
694
|
]
|
|
695
|
+
},
|
|
696
|
+
// Official Cursor CLI installer: installs to ~/.local/bin. Installers have
|
|
697
|
+
// shipped the binary as both `cursor-agent` and `agent` (the 2026-07
|
|
698
|
+
// installer's success message says `agent`), so probe both — unambiguous
|
|
699
|
+
// name first, since `agent` is also Grok's alias.
|
|
700
|
+
installer: {
|
|
701
|
+
command: "curl https://cursor.com/install -fsS | bash",
|
|
702
|
+
binCandidates: (home) => [join2(home, ".local", "bin", "cursor-agent"), join2(home, ".local", "bin", "agent")],
|
|
703
|
+
postInstallNote: 'Cursor CLI installed to ~/.local/bin. Add it to your PATH for future shells: export PATH="$HOME/.local/bin:$PATH"'
|
|
662
704
|
}
|
|
663
705
|
};
|
|
664
706
|
function subscriptionBasePath(harness) {
|
|
@@ -667,6 +709,69 @@ function subscriptionBasePath(harness) {
|
|
|
667
709
|
function resolveVendorBin(config, optionPath) {
|
|
668
710
|
return optionPath?.trim() || process.env[config.binEnvVar]?.trim() || config.defaultBin;
|
|
669
711
|
}
|
|
712
|
+
var VendorBinaryMissingError = class extends CliError {
|
|
713
|
+
constructor(config, binPath) {
|
|
714
|
+
super("user", `Could not find the \`${binPath}\` executable.`, { hint: config.installHint });
|
|
715
|
+
this.name = "VendorBinaryMissingError";
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
function runVendorInstall(config, command) {
|
|
719
|
+
return new Promise((resolve2, reject) => {
|
|
720
|
+
const child = spawn("bash", ["-c", command], { stdio: ["inherit", 2, "inherit"] });
|
|
721
|
+
child.on("error", (err) => {
|
|
722
|
+
reject(
|
|
723
|
+
new CliError("user", `Failed to run the ${config.displayName} CLI installer: ${err.message}`, {
|
|
724
|
+
hint: config.installHint
|
|
725
|
+
})
|
|
726
|
+
);
|
|
727
|
+
});
|
|
728
|
+
child.on("close", (code) => {
|
|
729
|
+
if (code === 0) {
|
|
730
|
+
resolve2();
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
reject(
|
|
734
|
+
new CliError("user", `The ${config.displayName} CLI installer exited with code ${code ?? "unknown"}.`, {
|
|
735
|
+
hint: config.installHint
|
|
736
|
+
})
|
|
737
|
+
);
|
|
738
|
+
});
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
async function offerVendorInstall(config, explicitBinPath) {
|
|
742
|
+
const installer = config.installer;
|
|
743
|
+
if (!installer || explicitBinPath) return null;
|
|
744
|
+
if (process.platform !== "linux" && process.platform !== "darwin") return null;
|
|
745
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) return null;
|
|
746
|
+
console.error(`Could not find the \`${config.defaultBin}\` executable.`);
|
|
747
|
+
console.error(`Install it now by running: ${installer.command}`);
|
|
748
|
+
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
749
|
+
let answer;
|
|
750
|
+
try {
|
|
751
|
+
answer = (await rl.question("Proceed? [y/N] ")).trim().toLowerCase();
|
|
752
|
+
} finally {
|
|
753
|
+
rl.close();
|
|
754
|
+
}
|
|
755
|
+
if (answer !== "y" && answer !== "yes") return null;
|
|
756
|
+
await runVendorInstall(config, installer.command);
|
|
757
|
+
for (const candidate of installer.binCandidates(homedir2())) {
|
|
758
|
+
if (existsSync2(candidate)) {
|
|
759
|
+
if (installer.postInstallNote) console.error(installer.postInstallNote);
|
|
760
|
+
return candidate;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
return config.defaultBin;
|
|
764
|
+
}
|
|
765
|
+
async function runVendorLoginWithInstallOffer(config, binPath, tempHome, explicitBinPath) {
|
|
766
|
+
try {
|
|
767
|
+
await runVendorLogin(config, binPath, tempHome);
|
|
768
|
+
} catch (err) {
|
|
769
|
+
if (!(err instanceof VendorBinaryMissingError)) throw err;
|
|
770
|
+
const installedBin = await offerVendorInstall(config, explicitBinPath);
|
|
771
|
+
if (!installedBin) throw err;
|
|
772
|
+
await runVendorLogin(config, installedBin, tempHome);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
670
775
|
function runVendorLogin(config, binPath, tempHome) {
|
|
671
776
|
return new Promise((resolve2, reject) => {
|
|
672
777
|
const child = spawn(binPath, config.loginArgs, {
|
|
@@ -675,7 +780,7 @@ function runVendorLogin(config, binPath, tempHome) {
|
|
|
675
780
|
});
|
|
676
781
|
child.on("error", (err) => {
|
|
677
782
|
if (err.code === "ENOENT") {
|
|
678
|
-
reject(new
|
|
783
|
+
reject(new VendorBinaryMissingError(config, binPath));
|
|
679
784
|
return;
|
|
680
785
|
}
|
|
681
786
|
reject(new CliError("user", `Failed to launch \`${binPath} ${config.loginArgs.join(" ")}\`: ${err.message}`));
|
|
@@ -753,6 +858,7 @@ async function setSubscriptionEnabled(apiConfig, harness, enabled) {
|
|
|
753
858
|
async function agentSubscriptionLoginCommand(config, options, command) {
|
|
754
859
|
const { config: apiConfig } = resolveBusinessContext(command, options);
|
|
755
860
|
const binPath = resolveVendorBin(config, options.binPath);
|
|
861
|
+
const explicitBinPath = Boolean(options.binPath?.trim() || process.env[config.binEnvVar]?.trim());
|
|
756
862
|
let tempHome;
|
|
757
863
|
const handleSigint = () => {
|
|
758
864
|
if (tempHome) {
|
|
@@ -768,11 +874,11 @@ async function agentSubscriptionLoginCommand(config, options, command) {
|
|
|
768
874
|
const captureViaKeychain = process.platform === "darwin" && config.darwinKeychain !== void 0;
|
|
769
875
|
let authJson;
|
|
770
876
|
if (captureViaKeychain) {
|
|
771
|
-
await
|
|
877
|
+
await runVendorLoginWithInstallOffer(config, binPath, null, explicitBinPath);
|
|
772
878
|
authJson = readDarwinKeychainAuthJson(config);
|
|
773
879
|
} else {
|
|
774
880
|
tempHome = await mkdtemp(join2(tmpdir(), `arcanist-${config.harness}-`));
|
|
775
|
-
await
|
|
881
|
+
await runVendorLoginWithInstallOffer(config, binPath, tempHome, explicitBinPath);
|
|
776
882
|
authJson = await readLoginAuthJson(config, tempHome);
|
|
777
883
|
}
|
|
778
884
|
const state = await apiFetch(
|
|
@@ -879,18 +985,21 @@ var CODEX_AGENT_RUNTIME_BACKEND = "codex";
|
|
|
879
985
|
var CLAUDE_CODE_AGENT_RUNTIME_BACKEND = "claude_code";
|
|
880
986
|
var OPENCODE_AGENT_RUNTIME_BACKEND = "opencode";
|
|
881
987
|
var CURSOR_AGENT_RUNTIME_BACKEND = "cursor";
|
|
988
|
+
var GROK_AGENT_RUNTIME_BACKEND = "grok";
|
|
882
989
|
var AGENT_RUNTIME_BACKENDS = [
|
|
883
990
|
CODEX_AGENT_RUNTIME_BACKEND,
|
|
884
991
|
CLAUDE_CODE_AGENT_RUNTIME_BACKEND,
|
|
885
992
|
OPENCODE_AGENT_RUNTIME_BACKEND,
|
|
886
|
-
CURSOR_AGENT_RUNTIME_BACKEND
|
|
993
|
+
CURSOR_AGENT_RUNTIME_BACKEND,
|
|
994
|
+
GROK_AGENT_RUNTIME_BACKEND
|
|
887
995
|
];
|
|
888
996
|
var AGENT_RUNTIME_BACKEND_NAMES = {
|
|
889
997
|
[CODEX_AGENT_RUNTIME_BACKEND]: "Codex",
|
|
890
998
|
[CLAUDE_CODE_AGENT_RUNTIME_BACKEND]: "Claude Code",
|
|
891
999
|
// "opencode" is intentionally lowercase to match the project's brand name.
|
|
892
1000
|
[OPENCODE_AGENT_RUNTIME_BACKEND]: "opencode",
|
|
893
|
-
[CURSOR_AGENT_RUNTIME_BACKEND]: "Cursor"
|
|
1001
|
+
[CURSOR_AGENT_RUNTIME_BACKEND]: "Cursor",
|
|
1002
|
+
[GROK_AGENT_RUNTIME_BACKEND]: "Grok Build"
|
|
894
1003
|
};
|
|
895
1004
|
function isAgentRuntimeBackend(value) {
|
|
896
1005
|
return AGENT_RUNTIME_BACKENDS.includes(value);
|
|
@@ -933,17 +1042,27 @@ var BasetenModel = {
|
|
|
933
1042
|
KimiK27Code: "kimi-k2.7-code"
|
|
934
1043
|
};
|
|
935
1044
|
var XaiModel = {
|
|
936
|
-
Grok45: "grok-4.5"
|
|
1045
|
+
Grok45: "grok-4.5",
|
|
1046
|
+
Grok43: "grok-4.3",
|
|
1047
|
+
Grok420Reasoning: "grok-4.20-0309-reasoning",
|
|
1048
|
+
Grok420NonReasoning: "grok-4.20-0309-non-reasoning",
|
|
1049
|
+
Grok420MultiAgent: "grok-4.20-multi-agent-0309",
|
|
1050
|
+
GrokBuild01: "grok-build-0.1"
|
|
937
1051
|
};
|
|
938
1052
|
var CursorModel = {
|
|
939
1053
|
Composer25: "composer-2.5"
|
|
940
1054
|
};
|
|
1055
|
+
var GrokBuildModel = {
|
|
1056
|
+
Grok45Byos: "grok-4.5-byos",
|
|
1057
|
+
GrokComposer25Fast: "grok-composer-2.5-fast"
|
|
1058
|
+
};
|
|
941
1059
|
var MODEL_PROVIDERS_SET = /* @__PURE__ */ new Set([
|
|
942
1060
|
"openai",
|
|
943
1061
|
"anthropic",
|
|
944
1062
|
"baseten",
|
|
945
1063
|
"xai",
|
|
946
|
-
"cursor"
|
|
1064
|
+
"cursor",
|
|
1065
|
+
"grok"
|
|
947
1066
|
]);
|
|
948
1067
|
var BACKEND_DESKTOP_IMAGE_FEEDBACK_CONFIGS = {
|
|
949
1068
|
[CODEX_AGENT_RUNTIME_BACKEND]: {
|
|
@@ -1258,19 +1377,126 @@ var MODEL_REGISTRY = [
|
|
|
1258
1377
|
pricing: { inputPerMillion: 0.95, outputPerMillion: 4, cacheReadPerMillion: 0.16 },
|
|
1259
1378
|
sessionStart: { eligible: true, isDefault: true }
|
|
1260
1379
|
},
|
|
1380
|
+
// xAI models (all text/chat models from https://docs.x.ai/docs/models,
|
|
1381
|
+
// verified 2026-07-15). All run on the opencode backend through the
|
|
1382
|
+
// OpenAI-compatible Chat Completions API at api.x.ai. No reasoning config
|
|
1383
|
+
// for any of them: xAI documents `reasoning_effort` for grok-4.3 only
|
|
1384
|
+
// (https://docs.x.ai/docs/api-reference), AND the opencode backend
|
|
1385
|
+
// intentionally passes no reasoning parameters to OSS providers
|
|
1386
|
+
// (variantReasoning: intentional in backend-capabilities.ts) — grok-4.3's
|
|
1387
|
+
// server-side default (`low`) applies. Pricing records both tiers: xAI
|
|
1388
|
+
// bills the whole request at long-context rates once the prompt crosses
|
|
1389
|
+
// 200k tokens, expressed via `longContext` (bridge cost estimates only).
|
|
1261
1390
|
{
|
|
1262
1391
|
id: XaiModel.Grok45,
|
|
1263
1392
|
name: "Grok 4.5",
|
|
1264
1393
|
provider: "xai",
|
|
1265
1394
|
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1266
1395
|
contextWindow: 5e5,
|
|
1267
|
-
//
|
|
1268
|
-
//
|
|
1269
|
-
//
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1396
|
+
// Verified 2026-07-15 against https://docs.x.ai/docs/pricing: $2/M in,
|
|
1397
|
+
// $6/M out, $0.50/M cached input below 200k prompt tokens; $4/$12/$1.00
|
|
1398
|
+
// at or above it. 500k context.
|
|
1399
|
+
pricing: {
|
|
1400
|
+
inputPerMillion: 2,
|
|
1401
|
+
outputPerMillion: 6,
|
|
1402
|
+
cacheReadPerMillion: 0.5,
|
|
1403
|
+
longContext: { thresholdTokens: 2e5, inputPerMillion: 4, outputPerMillion: 12, cacheReadPerMillion: 1 }
|
|
1404
|
+
},
|
|
1405
|
+
sessionStart: { eligible: true }
|
|
1406
|
+
},
|
|
1407
|
+
{
|
|
1408
|
+
id: XaiModel.Grok43,
|
|
1409
|
+
name: "Grok 4.3",
|
|
1410
|
+
provider: "xai",
|
|
1411
|
+
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1412
|
+
contextWindow: 1e6,
|
|
1413
|
+
// Verified 2026-07-15 against https://docs.x.ai/docs/pricing: $1.25/M in,
|
|
1414
|
+
// $2.50/M out, $0.20/M cached input below 200k prompt tokens;
|
|
1415
|
+
// $2.50/$5.00/$0.40 at or above it. 1M context.
|
|
1416
|
+
pricing: {
|
|
1417
|
+
inputPerMillion: 1.25,
|
|
1418
|
+
outputPerMillion: 2.5,
|
|
1419
|
+
cacheReadPerMillion: 0.2,
|
|
1420
|
+
longContext: { thresholdTokens: 2e5, inputPerMillion: 2.5, outputPerMillion: 5, cacheReadPerMillion: 0.4 }
|
|
1421
|
+
},
|
|
1422
|
+
sessionStart: { eligible: true }
|
|
1423
|
+
},
|
|
1424
|
+
{
|
|
1425
|
+
id: XaiModel.Grok420Reasoning,
|
|
1426
|
+
name: "Grok 4.20 Reasoning",
|
|
1427
|
+
provider: "xai",
|
|
1428
|
+
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1429
|
+
contextWindow: 1e6,
|
|
1430
|
+
// xAI encodes reasoning in distinct model ids for the 4.20 line (like
|
|
1431
|
+
// Cursor), not a per-request parameter. Verified 2026-07-15 against
|
|
1432
|
+
// https://docs.x.ai/docs/pricing: $1.25/M in, $2.50/M out, $0.20/M cached
|
|
1433
|
+
// input below 200k prompt tokens; $2.50/$5.00/$0.40 at or above it. 1M context.
|
|
1434
|
+
pricing: {
|
|
1435
|
+
inputPerMillion: 1.25,
|
|
1436
|
+
outputPerMillion: 2.5,
|
|
1437
|
+
cacheReadPerMillion: 0.2,
|
|
1438
|
+
longContext: { thresholdTokens: 2e5, inputPerMillion: 2.5, outputPerMillion: 5, cacheReadPerMillion: 0.4 }
|
|
1439
|
+
},
|
|
1440
|
+
sessionStart: { eligible: true }
|
|
1441
|
+
},
|
|
1442
|
+
{
|
|
1443
|
+
id: XaiModel.Grok420NonReasoning,
|
|
1444
|
+
name: "Grok 4.20 Non-Reasoning",
|
|
1445
|
+
provider: "xai",
|
|
1446
|
+
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1447
|
+
contextWindow: 1e6,
|
|
1448
|
+
// Verified 2026-07-15 against https://docs.x.ai/docs/pricing: $1.25/M in,
|
|
1449
|
+
// $2.50/M out, $0.20/M cached input below 200k prompt tokens;
|
|
1450
|
+
// $2.50/$5.00/$0.40 at or above it. 1M context.
|
|
1451
|
+
pricing: {
|
|
1452
|
+
inputPerMillion: 1.25,
|
|
1453
|
+
outputPerMillion: 2.5,
|
|
1454
|
+
cacheReadPerMillion: 0.2,
|
|
1455
|
+
longContext: { thresholdTokens: 2e5, inputPerMillion: 2.5, outputPerMillion: 5, cacheReadPerMillion: 0.4 }
|
|
1456
|
+
},
|
|
1457
|
+
sessionStart: { eligible: true }
|
|
1458
|
+
},
|
|
1459
|
+
{
|
|
1460
|
+
id: XaiModel.Grok420MultiAgent,
|
|
1461
|
+
name: "Grok 4.20 Multi-Agent",
|
|
1462
|
+
provider: "xai",
|
|
1463
|
+
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1464
|
+
contextWindow: 1e6,
|
|
1465
|
+
// Verified 2026-07-15 against https://docs.x.ai/docs/pricing: $1.25/M in,
|
|
1466
|
+
// $2.50/M out, $0.20/M cached input below 200k prompt tokens;
|
|
1467
|
+
// $2.50/$5.00/$0.40 at or above it. 1M context.
|
|
1468
|
+
pricing: {
|
|
1469
|
+
inputPerMillion: 1.25,
|
|
1470
|
+
outputPerMillion: 2.5,
|
|
1471
|
+
cacheReadPerMillion: 0.2,
|
|
1472
|
+
longContext: { thresholdTokens: 2e5, inputPerMillion: 2.5, outputPerMillion: 5, cacheReadPerMillion: 0.4 }
|
|
1473
|
+
},
|
|
1474
|
+
sessionStart: { eligible: true },
|
|
1475
|
+
// Cannot run a coding-agent session on a standard xAI key (verified
|
|
1476
|
+
// 2026-07-15 against api.x.ai with our production key): chat completions
|
|
1477
|
+
// rejects the model outright ("Multi Agent requests are not allowed on
|
|
1478
|
+
// chat completions") and the Responses API 400s any request carrying
|
|
1479
|
+
// client-side tools ("Client-side tools for multi-agent models require
|
|
1480
|
+
// beta access") — and the harness always sends tools. Hidden from the
|
|
1481
|
+
// picker until xAI grants beta access; CLI/API selection stays open for
|
|
1482
|
+
// retesting.
|
|
1483
|
+
visibility: "internal_probe"
|
|
1484
|
+
},
|
|
1485
|
+
{
|
|
1486
|
+
id: XaiModel.GrokBuild01,
|
|
1487
|
+
name: "Grok Build 0.1",
|
|
1488
|
+
provider: "xai",
|
|
1489
|
+
backends: [OPENCODE_AGENT_RUNTIME_BACKEND],
|
|
1490
|
+
contextWindow: 256e3,
|
|
1491
|
+
// Verified 2026-07-15 against https://docs.x.ai/docs/pricing: $1/M in,
|
|
1492
|
+
// $2/M out, $0.20/M cached input below 200k prompt tokens; $2/$4/$0.40 at
|
|
1493
|
+
// or above it. 256k context.
|
|
1494
|
+
pricing: {
|
|
1495
|
+
inputPerMillion: 1,
|
|
1496
|
+
outputPerMillion: 2,
|
|
1497
|
+
cacheReadPerMillion: 0.2,
|
|
1498
|
+
longContext: { thresholdTokens: 2e5, inputPerMillion: 2, outputPerMillion: 4, cacheReadPerMillion: 0.4 }
|
|
1499
|
+
},
|
|
1274
1500
|
sessionStart: { eligible: true }
|
|
1275
1501
|
},
|
|
1276
1502
|
{
|
|
@@ -1286,9 +1512,42 @@ var MODEL_REGISTRY = [
|
|
|
1286
1512
|
// published for Composer 2.5 (checked cursor.com/docs/models 2026-07-15),
|
|
1287
1513
|
// so none is recorded.
|
|
1288
1514
|
costTracked: false,
|
|
1515
|
+
sessionStart: { eligible: true, isDefault: true }
|
|
1516
|
+
},
|
|
1517
|
+
{
|
|
1518
|
+
id: GrokBuildModel.Grok45Byos,
|
|
1519
|
+
name: "Grok 4.5 (Subscription)",
|
|
1520
|
+
provider: "grok",
|
|
1521
|
+
backends: [GROK_AGENT_RUNTIME_BACKEND],
|
|
1522
|
+
// Wire id `grok-4.5` (the CLI's subscription default) collides with the
|
|
1523
|
+
// xai/opencode registry id, so the Arcanist id is suffixed and the wire id
|
|
1524
|
+
// rides providerModelId. Billed through the user's Grok subscription via
|
|
1525
|
+
// the Grok Build CLI (cli-chat-proxy.grok.com); Arcanist does not meter it
|
|
1526
|
+
// (costTracked: false requires pricing to stay undefined). Context window
|
|
1527
|
+
// verified 2026-07-15 against https://docs.x.ai/docs/models (grok-4.5,
|
|
1528
|
+
// 500k). No reasoning config: the CLI's --reasoning-effort is documented
|
|
1529
|
+
// for reasoning models only and grok-4.5 is classified no-reasoning per
|
|
1530
|
+
// the xai registry entries above.
|
|
1531
|
+
providerModelId: "grok-4.5",
|
|
1532
|
+
contextWindow: 5e5,
|
|
1533
|
+
costTracked: false,
|
|
1289
1534
|
sessionStart: { eligible: true, isDefault: true },
|
|
1290
|
-
// Internal probe: hidden from the public model picker;
|
|
1291
|
-
// CLI/API
|
|
1535
|
+
// Internal probe (ARC-1704): hidden from the public model picker;
|
|
1536
|
+
// CLI/API-selectable by internal Arcanist businesses only.
|
|
1537
|
+
visibility: "internal_probe"
|
|
1538
|
+
},
|
|
1539
|
+
{
|
|
1540
|
+
id: GrokBuildModel.GrokComposer25Fast,
|
|
1541
|
+
name: "Grok Composer 2.5 Fast",
|
|
1542
|
+
provider: "grok",
|
|
1543
|
+
backends: [GROK_AGENT_RUNTIME_BACKEND],
|
|
1544
|
+
// Cursor's Composer 2.5 Fast served through Grok Build (verified in
|
|
1545
|
+
// `grok models` 0.2.101 under a live subscription, 2026-07-15). Wire id
|
|
1546
|
+
// matches the registry id, so no providerModelId. Context window is not
|
|
1547
|
+
// published for Composer variants (cursor.com/docs/models), so none is
|
|
1548
|
+
// recorded. Subscription-billed, not metered by Arcanist.
|
|
1549
|
+
costTracked: false,
|
|
1550
|
+
sessionStart: { eligible: true },
|
|
1292
1551
|
visibility: "internal_probe"
|
|
1293
1552
|
}
|
|
1294
1553
|
];
|
|
@@ -1297,7 +1556,8 @@ var MODEL_PROVIDER_NAMES = {
|
|
|
1297
1556
|
anthropic: "Anthropic",
|
|
1298
1557
|
baseten: "Baseten",
|
|
1299
1558
|
xai: "xAI",
|
|
1300
|
-
cursor: "Cursor"
|
|
1559
|
+
cursor: "Cursor",
|
|
1560
|
+
grok: "Grok Build"
|
|
1301
1561
|
};
|
|
1302
1562
|
function buildSessionStartModelIdsByBackend() {
|
|
1303
1563
|
const byBackend = Object.fromEntries(AGENT_RUNTIME_BACKENDS.map((backend) => [backend, []]));
|
|
@@ -1337,7 +1597,8 @@ var VALID_SESSION_START_MODEL_IDS_BY_BACKEND = {
|
|
|
1337
1597
|
SESSION_START_MODEL_IDS_BY_BACKEND[CLAUDE_CODE_AGENT_RUNTIME_BACKEND]
|
|
1338
1598
|
),
|
|
1339
1599
|
[OPENCODE_AGENT_RUNTIME_BACKEND]: new Set(SESSION_START_MODEL_IDS_BY_BACKEND[OPENCODE_AGENT_RUNTIME_BACKEND]),
|
|
1340
|
-
[CURSOR_AGENT_RUNTIME_BACKEND]: new Set(SESSION_START_MODEL_IDS_BY_BACKEND[CURSOR_AGENT_RUNTIME_BACKEND])
|
|
1600
|
+
[CURSOR_AGENT_RUNTIME_BACKEND]: new Set(SESSION_START_MODEL_IDS_BY_BACKEND[CURSOR_AGENT_RUNTIME_BACKEND]),
|
|
1601
|
+
[GROK_AGENT_RUNTIME_BACKEND]: new Set(SESSION_START_MODEL_IDS_BY_BACKEND[GROK_AGENT_RUNTIME_BACKEND])
|
|
1341
1602
|
};
|
|
1342
1603
|
var MODEL_CONTEXT_WINDOWS = {
|
|
1343
1604
|
...Object.fromEntries(
|
|
@@ -1806,6 +2067,7 @@ var PHASES = [
|
|
|
1806
2067
|
"review_listening",
|
|
1807
2068
|
"completed",
|
|
1808
2069
|
"superseded",
|
|
2070
|
+
"needs_you",
|
|
1809
2071
|
"blocked",
|
|
1810
2072
|
"failed",
|
|
1811
2073
|
"stopped",
|
|
@@ -1814,6 +2076,7 @@ var PHASES = [
|
|
|
1814
2076
|
var TERMINAL_PHASES_ARRAY = [
|
|
1815
2077
|
"completed",
|
|
1816
2078
|
"superseded",
|
|
2079
|
+
"needs_you",
|
|
1817
2080
|
"blocked",
|
|
1818
2081
|
"failed",
|
|
1819
2082
|
"stopped",
|
|
@@ -1827,7 +2090,7 @@ var CHILD_SLOT_RELEASE_PHASES = new Set(
|
|
|
1827
2090
|
TERMINAL_PHASES_ARRAY.filter((phase) => phase !== "stopped")
|
|
1828
2091
|
);
|
|
1829
2092
|
var ARCHIVABLE_STALE_TERMINAL_PHASES_ARRAY = TERMINAL_PHASES_ARRAY.filter(
|
|
1830
|
-
(phase) => phase !== "archived" && phase !== "blocked" && phase !== "stopped"
|
|
2093
|
+
(phase) => phase !== "archived" && phase !== "needs_you" && phase !== "blocked" && phase !== "stopped"
|
|
1831
2094
|
);
|
|
1832
2095
|
function isTerminalPhase(phase, _sessionKind) {
|
|
1833
2096
|
return TERMINAL_PHASES.has(phase);
|
|
@@ -2944,6 +3207,7 @@ var SCAFFOLDING_LINE_PATTERNS = [
|
|
|
2944
3207
|
/^IMPORTANT: The content above is /i,
|
|
2945
3208
|
/^Previous Slack message\b/i,
|
|
2946
3209
|
/^Current Slack message author:/i,
|
|
3210
|
+
/^Current Slack channel:/i,
|
|
2947
3211
|
/^Thread context(?:\s*\([^)]*\))?\s*[.:]/i,
|
|
2948
3212
|
// Synthetic bootstrap prefix only: a single-token repo URL/ref value. A
|
|
2949
3213
|
// user's prose line like "Repository: our monorepo is huge" has spaces and
|
|
@@ -2960,6 +3224,7 @@ var SCAFFOLDING_MARKERS = [
|
|
|
2960
3224
|
/^IMPORTANT: The content above is /im,
|
|
2961
3225
|
/^Previous Slack message\b/im,
|
|
2962
3226
|
/^Current Slack message author:/im,
|
|
3227
|
+
/^Current Slack channel:/im,
|
|
2963
3228
|
/^Repository:\s+\S+$/im,
|
|
2964
3229
|
/^\[arcanist:review-loop\b/im
|
|
2965
3230
|
];
|
|
@@ -5971,6 +6236,8 @@ Runs the Grok CLI device-authorization login locally under a temporary HOME, the
|
|
|
5971
6236
|
resulting auth.json to Arcanist (encrypted, per user) and activates the selector. Your workspace
|
|
5972
6237
|
must have Grok subscription auth enabled. The credential is never written to your default ~/.grok.
|
|
5973
6238
|
Grok BYOS session execution is not live yet; the credential is stored for when it ships.
|
|
6239
|
+
If the grok CLI is not installed, you will be offered its official install script ([y/N] prompt,
|
|
6240
|
+
interactive terminals only).
|
|
5974
6241
|
|
|
5975
6242
|
Examples:
|
|
5976
6243
|
arcanist grok login
|
|
@@ -5996,6 +6263,8 @@ captured auth credential to Arcanist (encrypted, per user) and activates the sel
|
|
|
5996
6263
|
workspace must have Cursor subscription auth enabled. Cursor's login-token location is not
|
|
5997
6264
|
formally documented; if capture fails, use a Cursor API key in Settings instead. Cursor BYOS
|
|
5998
6265
|
session execution is not live yet; the credential is stored for when it ships.
|
|
6266
|
+
If the cursor-agent CLI is not installed, you will be offered its official install script
|
|
6267
|
+
([y/N] prompt, interactive terminals only).
|
|
5999
6268
|
|
|
6000
6269
|
Examples:
|
|
6001
6270
|
arcanist cursor login
|