@tryarcanist/cli 0.1.194 → 0.1.196
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 +80 -67
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -17,6 +17,36 @@ function normalizeBaseUrl(url) {
|
|
|
17
17
|
return url.replace(/\/+$/, "");
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
// src/utils/api-error.ts
|
|
21
|
+
function parseApiErrorBody(body) {
|
|
22
|
+
try {
|
|
23
|
+
const parsed = JSON.parse(body);
|
|
24
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
25
|
+
const record = parsed;
|
|
26
|
+
const topLevelMessage = typeof record.message === "string" && record.message ? record.message : void 0;
|
|
27
|
+
if (typeof record.error === "string" && record.error) {
|
|
28
|
+
return {
|
|
29
|
+
serverCode: typeof record.code === "string" && record.code ? record.code : record.error,
|
|
30
|
+
rawError: record.error,
|
|
31
|
+
message: topLevelMessage ?? record.error
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (record.error && typeof record.error === "object") {
|
|
35
|
+
const error = record.error;
|
|
36
|
+
const message = typeof error.message === "string" && error.message ? error.message : topLevelMessage;
|
|
37
|
+
const serverCode = typeof error.code === "string" && error.code ? error.code : void 0;
|
|
38
|
+
return message || serverCode ? {
|
|
39
|
+
...message ? { message } : {},
|
|
40
|
+
...serverCode ? { serverCode } : {},
|
|
41
|
+
...serverCode ? { rawError: serverCode } : {}
|
|
42
|
+
} : null;
|
|
43
|
+
}
|
|
44
|
+
return topLevelMessage ? { message: topLevelMessage } : null;
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
20
50
|
// src/errors.ts
|
|
21
51
|
var EXIT_CODE_INTERRUPTED = 130;
|
|
22
52
|
var CliError = class extends Error {
|
|
@@ -82,33 +112,6 @@ function messageForApiError(status, body, parsed = parseApiErrorBody(body)) {
|
|
|
82
112
|
if (parsed?.serverCode) return parsed.serverCode;
|
|
83
113
|
return body ? `API error ${status}: ${body}` : `API error ${status}`;
|
|
84
114
|
}
|
|
85
|
-
function parseApiErrorBody(body) {
|
|
86
|
-
try {
|
|
87
|
-
const parsed = JSON.parse(body);
|
|
88
|
-
if (!parsed || typeof parsed !== "object") return null;
|
|
89
|
-
const error = parsed.error;
|
|
90
|
-
if (typeof error === "string" && error.length > 0) {
|
|
91
|
-
const message2 = parsed.message;
|
|
92
|
-
const code = parsed.code;
|
|
93
|
-
return {
|
|
94
|
-
serverCode: typeof code === "string" && code ? code : error,
|
|
95
|
-
...typeof message2 === "string" && message2 ? { message: message2 } : { message: error }
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
if (error && typeof error === "object") {
|
|
99
|
-
const code = error.code;
|
|
100
|
-
const message2 = error.message;
|
|
101
|
-
return {
|
|
102
|
-
...typeof message2 === "string" && message2 ? { message: message2 } : {},
|
|
103
|
-
...typeof code === "string" && code ? { serverCode: code } : {}
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
const message = parsed.message;
|
|
107
|
-
return typeof message === "string" && message.length > 0 ? { message } : null;
|
|
108
|
-
} catch {
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
115
|
function hintForHttpStatus(status, resourceNoun) {
|
|
113
116
|
if (status === 401 || status === 403) return "Run `arcanist auth login` or set `ARCANIST_TOKEN`.";
|
|
114
117
|
if (status === 404) {
|
|
@@ -1062,7 +1065,7 @@ var CODEX_SUBSCRIPTION_SESSION_START_MODEL_PROVIDER_GROUPS = buildModelProviderG
|
|
|
1062
1065
|
function parseGithubRepoFullName(value) {
|
|
1063
1066
|
const shorthand = value.match(/^([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)$/);
|
|
1064
1067
|
if (shorthand) return { owner: shorthand[1], repo: shorthand[2] };
|
|
1065
|
-
const ssh = value.match(
|
|
1068
|
+
const ssh = value.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
1066
1069
|
if (ssh) return { owner: ssh[1], repo: ssh[2] };
|
|
1067
1070
|
const https = value.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
|
|
1068
1071
|
if (https) return { owner: https[1], repo: https[2] };
|
|
@@ -1206,27 +1209,14 @@ function mapAutomationApiError(err) {
|
|
|
1206
1209
|
if (!(err instanceof ApiError)) {
|
|
1207
1210
|
return err instanceof CliError ? err : new CliError("server", stringifyError(err));
|
|
1208
1211
|
}
|
|
1209
|
-
const parsed =
|
|
1210
|
-
const serverCode = parsed?.
|
|
1212
|
+
const parsed = parseApiErrorBody(err.body);
|
|
1213
|
+
const serverCode = parsed?.rawError ?? parsed?.serverCode;
|
|
1211
1214
|
return new CliError(codeForHttpStatus(err.status), parsed?.message || serverCode || err.message, {
|
|
1212
1215
|
exitCode: err.exitCode,
|
|
1213
1216
|
hint: serverCode ? AUTOMATION_ERROR_HINTS[serverCode] : void 0,
|
|
1214
1217
|
requestId: err.requestId
|
|
1215
1218
|
});
|
|
1216
1219
|
}
|
|
1217
|
-
function parseApiErrorBody2(body) {
|
|
1218
|
-
try {
|
|
1219
|
-
const parsed = JSON.parse(body);
|
|
1220
|
-
if (!parsed || typeof parsed !== "object") return null;
|
|
1221
|
-
const record = parsed;
|
|
1222
|
-
return {
|
|
1223
|
-
error: typeof record.error === "string" ? record.error : void 0,
|
|
1224
|
-
message: typeof record.message === "string" ? record.message : void 0
|
|
1225
|
-
};
|
|
1226
|
-
} catch {
|
|
1227
|
-
return null;
|
|
1228
|
-
}
|
|
1229
|
-
}
|
|
1230
1220
|
function printAutomationRule(rule) {
|
|
1231
1221
|
console.log(`ID: ${rule.id}`);
|
|
1232
1222
|
console.log(`Repo: ${rule.repoOwner}/${rule.repoName}`);
|
|
@@ -1240,6 +1230,7 @@ function formatTime(value) {
|
|
|
1240
1230
|
|
|
1241
1231
|
// src/commands/codex.ts
|
|
1242
1232
|
import { spawn } from "child_process";
|
|
1233
|
+
import { rmSync } from "fs";
|
|
1243
1234
|
import { mkdtemp, readFile, rm } from "fs/promises";
|
|
1244
1235
|
import { tmpdir } from "os";
|
|
1245
1236
|
import { join as join2 } from "path";
|
|
@@ -1288,8 +1279,19 @@ async function setCodexSubscriptionEnabled(config, enabled) {
|
|
|
1288
1279
|
async function codexLoginCommand(options, command) {
|
|
1289
1280
|
const { config } = resolveBusinessContext(command, options);
|
|
1290
1281
|
const codexPath = resolveCodexPath(options.codexPath);
|
|
1291
|
-
|
|
1282
|
+
let codexHome;
|
|
1283
|
+
const handleSigint = () => {
|
|
1284
|
+
if (codexHome) {
|
|
1285
|
+
try {
|
|
1286
|
+
rmSync(codexHome, { recursive: true, force: true });
|
|
1287
|
+
} catch {
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
process.exit(EXIT_CODE_INTERRUPTED);
|
|
1291
|
+
};
|
|
1292
|
+
process.on("SIGINT", handleSigint);
|
|
1292
1293
|
try {
|
|
1294
|
+
codexHome = await mkdtemp(join2(tmpdir(), "arcanist-codex-"));
|
|
1293
1295
|
await runCodexDeviceLogin(codexPath, codexHome);
|
|
1294
1296
|
let authJson;
|
|
1295
1297
|
try {
|
|
@@ -1325,8 +1327,14 @@ async function codexLoginCommand(options, command) {
|
|
|
1325
1327
|
}
|
|
1326
1328
|
});
|
|
1327
1329
|
} finally {
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
+
try {
|
|
1331
|
+
if (codexHome) {
|
|
1332
|
+
await rm(codexHome, { recursive: true, force: true }).catch(() => {
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
} finally {
|
|
1336
|
+
process.off("SIGINT", handleSigint);
|
|
1337
|
+
}
|
|
1330
1338
|
}
|
|
1331
1339
|
}
|
|
1332
1340
|
async function codexUseCommand(state, options, command) {
|
|
@@ -1560,6 +1568,11 @@ function normalizeUploadedFileOptions(files) {
|
|
|
1560
1568
|
return Array.isArray(files) ? files : [files];
|
|
1561
1569
|
}
|
|
1562
1570
|
|
|
1571
|
+
// src/utils/poll-interval.ts
|
|
1572
|
+
function clampPollInterval(ms, minimum) {
|
|
1573
|
+
return Math.max(ms, minimum);
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1563
1576
|
// ../../shared/session/no-change-outcome.ts
|
|
1564
1577
|
function isNoChangesPromptResult(result) {
|
|
1565
1578
|
return typeof result === "object" && result !== null && "noChanges" in result && result.noChanges === true;
|
|
@@ -2985,6 +2998,11 @@ function renderWatchEvent(event, state) {
|
|
|
2985
2998
|
}
|
|
2986
2999
|
}
|
|
2987
3000
|
|
|
3001
|
+
// src/utils/session-payload.ts
|
|
3002
|
+
function unwrapSessionState(payload) {
|
|
3003
|
+
return payload.session && typeof payload.session === "object" ? payload.session : payload;
|
|
3004
|
+
}
|
|
3005
|
+
|
|
2988
3006
|
// src/commands/model-options.ts
|
|
2989
3007
|
function resolveModelAndBackend(options) {
|
|
2990
3008
|
let agentRuntimeBackend = CODEX_AGENT_RUNTIME_BACKEND;
|
|
@@ -3228,7 +3246,7 @@ async function fetchCreatedPromptStatus(config, sessionId, promptId) {
|
|
|
3228
3246
|
return selectCreatedPrompt(promptList.prompts, promptId);
|
|
3229
3247
|
}
|
|
3230
3248
|
async function waitForCreatedPromptToSettle(config, sessionId, promptId, pollIntervalMs) {
|
|
3231
|
-
const effectivePollIntervalMs =
|
|
3249
|
+
const effectivePollIntervalMs = clampPollInterval(pollIntervalMs, MIN_WATCH_POLL_INTERVAL_MS);
|
|
3232
3250
|
while (true) {
|
|
3233
3251
|
const createdPrompt = await fetchCreatedPromptStatus(config, sessionId, promptId);
|
|
3234
3252
|
if (createdPrompt && PROMPT_TERMINAL_STATUSES.has(createdPrompt.status)) {
|
|
@@ -3270,15 +3288,12 @@ async function waitForCreatedPrompt(sessionId, promptId, sessionUrl, pollInterva
|
|
|
3270
3288
|
);
|
|
3271
3289
|
}
|
|
3272
3290
|
}
|
|
3273
|
-
function unwrapSessionState(payload) {
|
|
3274
|
-
return payload.session && typeof payload.session === "object" ? payload.session : payload;
|
|
3275
|
-
}
|
|
3276
3291
|
async function fetchSessionResultFields(config, sessionId) {
|
|
3277
3292
|
const sessionPayload = await apiFetch(config, `/api/sessions/${sessionId}`);
|
|
3278
3293
|
return extractSessionResultFields(unwrapSessionState(sessionPayload));
|
|
3279
3294
|
}
|
|
3280
3295
|
async function fetchSettledSessionResultFields(config, sessionId, pollIntervalMs) {
|
|
3281
|
-
const effectivePollIntervalMs =
|
|
3296
|
+
const effectivePollIntervalMs = clampPollInterval(pollIntervalMs, MIN_WATCH_POLL_INTERVAL_MS);
|
|
3282
3297
|
let latest = {};
|
|
3283
3298
|
for (let attempt = 0; attempt < RESULT_FETCH_ATTEMPTS; attempt++) {
|
|
3284
3299
|
latest = await fetchSessionResultFields(config, sessionId);
|
|
@@ -3457,10 +3472,14 @@ function parseEgressAllowlistSourceFile(content, key = EGRESS_ALLOWLIST_SOURCE_P
|
|
|
3457
3472
|
|
|
3458
3473
|
// src/commands/egress.ts
|
|
3459
3474
|
function parseRepoArg(value) {
|
|
3460
|
-
const
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3475
|
+
const parsed = parseGithubRepoFullName(value);
|
|
3476
|
+
if (!parsed) throw new CliError("user", "repo must be owner/name or a GitHub URL");
|
|
3477
|
+
return {
|
|
3478
|
+
...parsed,
|
|
3479
|
+
// Preserve the legacy shorthand contract while URLs and SSH remotes are
|
|
3480
|
+
// normalized by the shared parser itself.
|
|
3481
|
+
repo: /^[^/:]+\/[^/]+\.git$/.test(value.trim()) ? parsed.repo.slice(0, -4) : parsed.repo
|
|
3482
|
+
};
|
|
3464
3483
|
}
|
|
3465
3484
|
async function egressSourceSetCommand(sourceRepoArg, options = {}, command) {
|
|
3466
3485
|
const { config } = resolveBusinessContext(command, options);
|
|
@@ -3585,9 +3604,6 @@ async function loginCommand(options, command) {
|
|
|
3585
3604
|
}
|
|
3586
3605
|
|
|
3587
3606
|
// src/commands/message.ts
|
|
3588
|
-
function unwrapSessionState2(payload) {
|
|
3589
|
-
return payload.session && typeof payload.session === "object" ? payload.session : payload;
|
|
3590
|
-
}
|
|
3591
3607
|
async function messageCommand(sessionId, promptArg, options = {}, command) {
|
|
3592
3608
|
const runtime = getRuntimeOptions(command, options);
|
|
3593
3609
|
assertArcanistSessionMutationAllowed("send");
|
|
@@ -3619,7 +3635,7 @@ async function messageCommand(sessionId, promptArg, options = {}, command) {
|
|
|
3619
3635
|
}
|
|
3620
3636
|
try {
|
|
3621
3637
|
const sessionPayload = await apiFetch(config, `/api/sessions/${sessionId}`);
|
|
3622
|
-
const resultLine = formatSessionResult(
|
|
3638
|
+
const resultLine = formatSessionResult(unwrapSessionState(sessionPayload));
|
|
3623
3639
|
if (resultLine) console.log(resultLine);
|
|
3624
3640
|
} catch {
|
|
3625
3641
|
}
|
|
@@ -3812,7 +3828,7 @@ function currentRepo() {
|
|
|
3812
3828
|
|
|
3813
3829
|
// src/commands/repos.ts
|
|
3814
3830
|
function parseRepoArg2(value) {
|
|
3815
|
-
if (
|
|
3831
|
+
if (value === void 0) return currentRepo();
|
|
3816
3832
|
const parsed = parseGithubRepoFullName(value);
|
|
3817
3833
|
if (!parsed) throw new CliError("user", "repo must be owner/name or a GitHub URL");
|
|
3818
3834
|
return { owner: parsed.owner, repo: parsed.repo };
|
|
@@ -5161,13 +5177,10 @@ function parseStopBlocked(err) {
|
|
|
5161
5177
|
|
|
5162
5178
|
// src/commands/test-creds.ts
|
|
5163
5179
|
import { readFileSync as readFileSync4 } from "fs";
|
|
5164
|
-
function parseRepoArg4(
|
|
5165
|
-
const
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
throw new CliError("user", `repo must be in the form 'owner/name' (got: '${repo}')`);
|
|
5169
|
-
}
|
|
5170
|
-
return { owner: trimmed.slice(0, slashIndex), name: trimmed.slice(slashIndex + 1) };
|
|
5180
|
+
function parseRepoArg4(value) {
|
|
5181
|
+
const parsed = parseGithubRepoFullName(value);
|
|
5182
|
+
if (!parsed) throw new CliError("user", "repo must be owner/name or a GitHub URL");
|
|
5183
|
+
return { owner: parsed.owner, name: parsed.repo };
|
|
5171
5184
|
}
|
|
5172
5185
|
function basePath(businessId, repo) {
|
|
5173
5186
|
return `/api/businesses/${encodeURIComponent(businessId)}/repos/${encodeURIComponent(repo.owner)}/${encodeURIComponent(repo.name)}/test-credentials`;
|