@tryarcanist/cli 0.1.221 → 0.1.222
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 +167 -187
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -69,6 +69,15 @@ function parseApiErrorBody(body) {
|
|
|
69
69
|
return null;
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
+
function parseConflictBody(err) {
|
|
73
|
+
if (!(err instanceof ApiError) || err.status !== 409) return null;
|
|
74
|
+
try {
|
|
75
|
+
const parsed = JSON.parse(err.body);
|
|
76
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
77
|
+
} catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
72
81
|
|
|
73
82
|
// src/errors.ts
|
|
74
83
|
var EXIT_CODE_INTERRUPTED = 130;
|
|
@@ -1842,6 +1851,26 @@ var SESSION_START_MODEL_PROVIDER_GROUPS_BY_SUBSCRIPTIONS = {
|
|
|
1842
1851
|
"true:true": buildSubscriptionAwareGroups({ codexSubscription: true, grokSubscription: true })
|
|
1843
1852
|
};
|
|
1844
1853
|
|
|
1854
|
+
// src/utils/pagination.ts
|
|
1855
|
+
var MAX_ALL_PAGES = 1e3;
|
|
1856
|
+
async function fetchPages(label, all, initialCursor, fetchPage) {
|
|
1857
|
+
const items = [];
|
|
1858
|
+
let cursor2 = initialCursor;
|
|
1859
|
+
let nextCursor = null;
|
|
1860
|
+
let pageCount = 0;
|
|
1861
|
+
do {
|
|
1862
|
+
pageCount += 1;
|
|
1863
|
+
if (all && pageCount > MAX_ALL_PAGES) {
|
|
1864
|
+
throw new CliError("user", `${label} exceeded ${MAX_ALL_PAGES} pages without reaching the end.`);
|
|
1865
|
+
}
|
|
1866
|
+
const page = await fetchPage(cursor2);
|
|
1867
|
+
items.push(...page.items);
|
|
1868
|
+
nextCursor = page.nextCursor;
|
|
1869
|
+
cursor2 = nextCursor ?? void 0;
|
|
1870
|
+
} while (all && nextCursor);
|
|
1871
|
+
return { items, nextCursor: all ? null : nextCursor };
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1845
1874
|
// ../../shared/github/repo-url.ts
|
|
1846
1875
|
function parseGithubRepoFullName(value) {
|
|
1847
1876
|
const shorthand = value.match(/^([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)$/);
|
|
@@ -1853,6 +1882,32 @@ function parseGithubRepoFullName(value) {
|
|
|
1853
1882
|
return null;
|
|
1854
1883
|
}
|
|
1855
1884
|
|
|
1885
|
+
// src/git.ts
|
|
1886
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
1887
|
+
function git(args) {
|
|
1888
|
+
try {
|
|
1889
|
+
return execFileSync2("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
1890
|
+
} catch (err) {
|
|
1891
|
+
throw new CliError("user", `git ${args.join(" ")} failed: ${stringifyError(err)}`);
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
function currentRepo() {
|
|
1895
|
+
const parsed = parseGithubRepoFullName(git(["remote", "get-url", "origin"]));
|
|
1896
|
+
if (!parsed) throw new CliError("user", "origin remote must point at a GitHub repository");
|
|
1897
|
+
return { owner: parsed.owner, repo: parsed.repo };
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
// src/utils/repo-arg.ts
|
|
1901
|
+
function parseRepoArg(value, argName = "repo") {
|
|
1902
|
+
const parsed = parseGithubRepoFullName(value);
|
|
1903
|
+
if (!parsed) throw new CliError("user", `${argName} must be owner/name or a GitHub URL`);
|
|
1904
|
+
return { owner: parsed.owner, repo: parsed.repo.replace(/\.git$/, "") };
|
|
1905
|
+
}
|
|
1906
|
+
function parseRepoArgOrCurrent(value, argName = "repo") {
|
|
1907
|
+
if (value === void 0) return currentRepo();
|
|
1908
|
+
return parseRepoArg(value, argName);
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1856
1911
|
// src/commands/automations.ts
|
|
1857
1912
|
var AUTOMATION_ERROR_HINTS = {
|
|
1858
1913
|
invalid_cron: "Use a standard five-field cron expression, for example: */15 * * * *",
|
|
@@ -1869,9 +1924,8 @@ var AUTOMATION_ERROR_HINTS = {
|
|
|
1869
1924
|
repo_skills_unavailable: "Arcanist could not verify the repo's skills right now. Retry once GitHub skill discovery is healthy.",
|
|
1870
1925
|
unknown_skill: "That leading slash skill does not exist in the selected repository."
|
|
1871
1926
|
};
|
|
1872
|
-
var MAX_ALL_PAGES = 1e3;
|
|
1873
1927
|
async function createAutomationCommand(repoUrl, promptArg, options, command) {
|
|
1874
|
-
const repo =
|
|
1928
|
+
const repo = parseRepoArg(repoUrl, "repo-url");
|
|
1875
1929
|
const prompt = await resolvePromptInput(promptArg, options);
|
|
1876
1930
|
const slackTeamId = options.slackTeamId?.trim();
|
|
1877
1931
|
const slackChannelId = options.slackChannelId?.trim();
|
|
@@ -1918,27 +1972,22 @@ async function createAutomationCommand(repoUrl, promptArg, options, command) {
|
|
|
1918
1972
|
async function listAutomationsCommand(options, command) {
|
|
1919
1973
|
const runtime = getRuntimeOptions(command, options);
|
|
1920
1974
|
const config = requireConfig(runtime);
|
|
1921
|
-
const items =
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1975
|
+
const { items, nextCursor } = await fetchPages(
|
|
1976
|
+
"automations list --all",
|
|
1977
|
+
options.all === true,
|
|
1978
|
+
options.cursor,
|
|
1979
|
+
async (cursor2) => {
|
|
1980
|
+
const query = new URLSearchParams();
|
|
1981
|
+
if (options.limit) query.set("limit", options.limit);
|
|
1982
|
+
if (cursor2) query.set("cursor", cursor2);
|
|
1983
|
+
const payload = await automationApiFetch(
|
|
1984
|
+
config,
|
|
1985
|
+
`/api/automation/schedules${query.size ? `?${query.toString()}` : ""}`
|
|
1986
|
+
);
|
|
1987
|
+
return { items: payload.data.items, nextCursor: payload.data.nextCursor };
|
|
1929
1988
|
}
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
if (cursor2) query.set("cursor", cursor2);
|
|
1933
|
-
const payload = await automationApiFetch(
|
|
1934
|
-
config,
|
|
1935
|
-
`/api/automation/schedules${query.size ? `?${query.toString()}` : ""}`
|
|
1936
|
-
);
|
|
1937
|
-
items.push(...payload.data.items);
|
|
1938
|
-
nextCursor = payload.data.nextCursor;
|
|
1939
|
-
cursor2 = nextCursor ?? void 0;
|
|
1940
|
-
} while (options.all === true && nextCursor);
|
|
1941
|
-
const output = { items, nextCursor: options.all === true ? null : nextCursor };
|
|
1989
|
+
);
|
|
1990
|
+
const output = { items, nextCursor };
|
|
1942
1991
|
if (isJson(command, options)) {
|
|
1943
1992
|
writeJson(output);
|
|
1944
1993
|
return;
|
|
@@ -1970,14 +2019,6 @@ async function deleteAutomationCommand(id, options, command) {
|
|
|
1970
2019
|
}
|
|
1971
2020
|
console.log(`Deleted automation ${id}.`);
|
|
1972
2021
|
}
|
|
1973
|
-
function parseAutomationRepo(value) {
|
|
1974
|
-
if (/^git@/i.test(value) && !/^git@github\.com:/i.test(value)) {
|
|
1975
|
-
throw new CliError("user", "repo-url must be owner/name or a GitHub URL.");
|
|
1976
|
-
}
|
|
1977
|
-
const parsed = parseGithubRepoFullName(value);
|
|
1978
|
-
if (!parsed) throw new CliError("user", "repo-url must be owner/name or a GitHub URL.");
|
|
1979
|
-
return { owner: parsed.owner, repo: parsed.repo };
|
|
1980
|
-
}
|
|
1981
2022
|
function resolveAutomationModelBackend(rawModel, normalizedModel) {
|
|
1982
2023
|
if (normalizedModel) {
|
|
1983
2024
|
const backend = getAgentRuntimeBackendForModel(normalizedModel);
|
|
@@ -2386,6 +2427,21 @@ function normalizeUploadedFileOptions(files) {
|
|
|
2386
2427
|
function clampPollInterval(ms, minimum) {
|
|
2387
2428
|
return Math.max(ms, minimum);
|
|
2388
2429
|
}
|
|
2430
|
+
function parsePollInterval(raw, opts = {}) {
|
|
2431
|
+
const defaultMs = opts.defaultMs ?? DEFAULT_WATCH_POLL_INTERVAL_MS;
|
|
2432
|
+
const minMs = opts.minMs ?? MIN_WATCH_POLL_INTERVAL_MS;
|
|
2433
|
+
const maxMs = opts.maxMs === void 0 ? MAX_WATCH_POLL_INTERVAL_MS : opts.maxMs;
|
|
2434
|
+
if (!raw) return defaultMs;
|
|
2435
|
+
if (!/^\d+$/.test(raw)) {
|
|
2436
|
+
throw new CliError("user", "Polling interval must be a non-negative integer.");
|
|
2437
|
+
}
|
|
2438
|
+
const value = Number(raw);
|
|
2439
|
+
if (value < minMs || maxMs !== null && value > maxMs) {
|
|
2440
|
+
const range = maxMs === null ? `at least ${minMs}` : `between ${minMs} and ${maxMs}`;
|
|
2441
|
+
throw new CliError("user", `Polling interval must be ${range} milliseconds.`);
|
|
2442
|
+
}
|
|
2443
|
+
return value;
|
|
2444
|
+
}
|
|
2389
2445
|
|
|
2390
2446
|
// ../../shared/session/no-change-outcome.ts
|
|
2391
2447
|
function isNoChangesPromptResult(result) {
|
|
@@ -3889,20 +3945,6 @@ function applyDisconnectMask(view, mask, now) {
|
|
|
3889
3945
|
}
|
|
3890
3946
|
|
|
3891
3947
|
// src/commands/watch.ts
|
|
3892
|
-
function parsePollInterval(raw) {
|
|
3893
|
-
if (!raw) return DEFAULT_WATCH_POLL_INTERVAL_MS;
|
|
3894
|
-
if (!/^\d+$/.test(raw)) {
|
|
3895
|
-
throw new CliError("user", "Polling interval must be a non-negative integer.");
|
|
3896
|
-
}
|
|
3897
|
-
const value = Number(raw);
|
|
3898
|
-
if (value < MIN_WATCH_POLL_INTERVAL_MS || value > MAX_WATCH_POLL_INTERVAL_MS) {
|
|
3899
|
-
throw new CliError(
|
|
3900
|
-
"user",
|
|
3901
|
-
`Polling interval must be between ${MIN_WATCH_POLL_INTERVAL_MS} and ${MAX_WATCH_POLL_INTERVAL_MS} milliseconds.`
|
|
3902
|
-
);
|
|
3903
|
-
}
|
|
3904
|
-
return value;
|
|
3905
|
-
}
|
|
3906
3948
|
function parseNonNegativeInteger(raw, name, defaultValue) {
|
|
3907
3949
|
if (!raw) return defaultValue;
|
|
3908
3950
|
if (!/^\d+$/.test(raw)) {
|
|
@@ -4327,16 +4369,6 @@ function parseEgressAllowlistSourceFile(content, key = EGRESS_ALLOWLIST_SOURCE_P
|
|
|
4327
4369
|
}
|
|
4328
4370
|
|
|
4329
4371
|
// src/commands/egress.ts
|
|
4330
|
-
function parseRepoArg(value) {
|
|
4331
|
-
const parsed = parseGithubRepoFullName(value);
|
|
4332
|
-
if (!parsed) throw new CliError("user", "repo must be owner/name or a GitHub URL");
|
|
4333
|
-
return {
|
|
4334
|
-
...parsed,
|
|
4335
|
-
// Preserve the legacy shorthand contract while URLs and SSH remotes are
|
|
4336
|
-
// normalized by the shared parser itself.
|
|
4337
|
-
repo: /^[^/:]+\/[^/]+\.git$/.test(value.trim()) ? parsed.repo.slice(0, -4) : parsed.repo
|
|
4338
|
-
};
|
|
4339
|
-
}
|
|
4340
4372
|
async function egressSourceSetCommand(sourceRepoArg, options = {}, command) {
|
|
4341
4373
|
const { config } = resolveBusinessContext(command, options);
|
|
4342
4374
|
const businessId = await resolveBusinessId(config, options);
|
|
@@ -4569,13 +4601,13 @@ function parseCreateConflict(error) {
|
|
|
4569
4601
|
let message = error.message;
|
|
4570
4602
|
let sessionId;
|
|
4571
4603
|
let sessionUrl;
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
const
|
|
4604
|
+
const parsed = parseConflictBody(error);
|
|
4605
|
+
if (parsed) {
|
|
4606
|
+
const rawError = parsed.error;
|
|
4607
|
+
const parsedMessage = typeof rawError === "string" ? rawError : rawError && typeof rawError === "object" && typeof rawError.message === "string" ? rawError.message : void 0;
|
|
4575
4608
|
if (parsedMessage) message = parsedMessage;
|
|
4576
4609
|
if (typeof parsed.sessionId === "string") sessionId = parsed.sessionId;
|
|
4577
4610
|
if (typeof parsed.sessionUrl === "string") sessionUrl = parsed.sessionUrl;
|
|
4578
|
-
} catch {
|
|
4579
4611
|
}
|
|
4580
4612
|
const location = sessionUrl ? ` (${sessionUrl})` : "";
|
|
4581
4613
|
const existing = sessionId ? ` Existing verifier session: ${sessionId}${location}.` : "";
|
|
@@ -4667,28 +4699,7 @@ async function qaCommand(prUrl, options, command) {
|
|
|
4667
4699
|
console.log(`Follow with: arcanist sessions events ${sessionId} --follow --json`);
|
|
4668
4700
|
}
|
|
4669
4701
|
|
|
4670
|
-
// src/git.ts
|
|
4671
|
-
import { execFileSync as execFileSync2 } from "child_process";
|
|
4672
|
-
function git(args) {
|
|
4673
|
-
try {
|
|
4674
|
-
return execFileSync2("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
4675
|
-
} catch (err) {
|
|
4676
|
-
throw new CliError("user", `git ${args.join(" ")} failed: ${stringifyError(err)}`);
|
|
4677
|
-
}
|
|
4678
|
-
}
|
|
4679
|
-
function currentRepo() {
|
|
4680
|
-
const parsed = parseGithubRepoFullName(git(["remote", "get-url", "origin"]));
|
|
4681
|
-
if (!parsed) throw new CliError("user", "origin remote must point at a GitHub repository");
|
|
4682
|
-
return { owner: parsed.owner, repo: parsed.repo };
|
|
4683
|
-
}
|
|
4684
|
-
|
|
4685
4702
|
// src/commands/repos.ts
|
|
4686
|
-
function parseRepoArg2(value) {
|
|
4687
|
-
if (value === void 0) return currentRepo();
|
|
4688
|
-
const parsed = parseGithubRepoFullName(value);
|
|
4689
|
-
if (!parsed) throw new CliError("user", "repo must be owner/name or a GitHub URL");
|
|
4690
|
-
return { owner: parsed.owner, repo: parsed.repo };
|
|
4691
|
-
}
|
|
4692
4703
|
async function reposListCommand(options = {}, command) {
|
|
4693
4704
|
const { config } = resolveBusinessContext(command, options);
|
|
4694
4705
|
const payload = await apiFetch(
|
|
@@ -4704,8 +4715,7 @@ async function reposListCommand(options = {}, command) {
|
|
|
4704
4715
|
}
|
|
4705
4716
|
async function repoBranchesCommand(repoArg, options = {}, command) {
|
|
4706
4717
|
const { config } = resolveBusinessContext(command, options);
|
|
4707
|
-
const repo =
|
|
4708
|
-
await apiFetch(config, "/api/repos");
|
|
4718
|
+
const repo = parseRepoArgOrCurrent(repoArg);
|
|
4709
4719
|
const payload = await apiFetch(
|
|
4710
4720
|
config,
|
|
4711
4721
|
`/api/repos/${encodeURIComponent(repo.owner)}/${encodeURIComponent(repo.repo)}/branches`
|
|
@@ -4716,7 +4726,7 @@ async function repoBranchesCommand(repoArg, options = {}, command) {
|
|
|
4716
4726
|
}
|
|
4717
4727
|
async function repoSkillsCommand(repoArg, options = {}, command) {
|
|
4718
4728
|
const { config } = resolveBusinessContext(command, options);
|
|
4719
|
-
const repo =
|
|
4729
|
+
const repo = parseRepoArgOrCurrent(repoArg);
|
|
4720
4730
|
const payload = await apiFetch(
|
|
4721
4731
|
config,
|
|
4722
4732
|
`/api/repos/${encodeURIComponent(repo.owner)}/${encodeURIComponent(repo.repo)}/skills`
|
|
@@ -4764,17 +4774,13 @@ async function respondCommand(sessionId, answerArg, options = {}, command) {
|
|
|
4764
4774
|
}
|
|
4765
4775
|
}
|
|
4766
4776
|
function parseRespondConflict(err) {
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
};
|
|
4775
|
-
} catch {
|
|
4776
|
-
return null;
|
|
4777
|
-
}
|
|
4777
|
+
const body = parseConflictBody(err);
|
|
4778
|
+
if (!body || body.error !== "session_not_respondable") return null;
|
|
4779
|
+
const reason = typeof body.reason === "string" ? body.reason : void 0;
|
|
4780
|
+
return {
|
|
4781
|
+
message: reason ? `Session cannot be answered from phase=${reason}.` : "Session does not have a pending question.",
|
|
4782
|
+
reason: reason ?? "session_not_respondable"
|
|
4783
|
+
};
|
|
4778
4784
|
}
|
|
4779
4785
|
|
|
4780
4786
|
// src/commands/sandbox.ts
|
|
@@ -5327,23 +5333,9 @@ function assertCleanAndPushed() {
|
|
|
5327
5333
|
function assertManifestExists(path) {
|
|
5328
5334
|
if (!existsSync3(path)) throw new CliError("user", `Missing sandbox manifest: ${path}`);
|
|
5329
5335
|
}
|
|
5330
|
-
function parseRepoArg3(value, fallback) {
|
|
5331
|
-
if (!value) return fallback();
|
|
5332
|
-
const parsed = parseGithubRepoFullName(value);
|
|
5333
|
-
if (!parsed) throw new CliError("user", "repo must be owner/name or a GitHub URL");
|
|
5334
|
-
return { owner: parsed.owner, repo: parsed.repo };
|
|
5335
|
-
}
|
|
5336
5336
|
function repoPath(repo) {
|
|
5337
5337
|
return `${repo.owner}/${repo.repo}`;
|
|
5338
5338
|
}
|
|
5339
|
-
function parsePollInterval2(value) {
|
|
5340
|
-
if (!value) return DEFAULT_POLL_INTERVAL_MS;
|
|
5341
|
-
const parsed = Number(value);
|
|
5342
|
-
if (!Number.isInteger(parsed) || parsed < MIN_POLL_INTERVAL_MS) {
|
|
5343
|
-
throw new CliError("user", `--poll-interval must be an integer >= ${MIN_POLL_INTERVAL_MS}.`);
|
|
5344
|
-
}
|
|
5345
|
-
return parsed;
|
|
5346
|
-
}
|
|
5347
5339
|
function printBuildRequest(buildRequest) {
|
|
5348
5340
|
console.log(
|
|
5349
5341
|
[
|
|
@@ -5615,8 +5607,8 @@ async function sandboxBuildCommand(sourceRepoArg, options = {}, command) {
|
|
|
5615
5607
|
const manifestPath = options.manifest ?? DEFAULT_MANIFEST_PATH;
|
|
5616
5608
|
assertManifestExists(manifestPath);
|
|
5617
5609
|
if (!options.ref) assertCleanAndPushed();
|
|
5618
|
-
const sourceRepo =
|
|
5619
|
-
const targetRepo = options.targetRepo ?
|
|
5610
|
+
const sourceRepo = parseRepoArgOrCurrent(sourceRepoArg);
|
|
5611
|
+
const targetRepo = options.targetRepo ? parseRepoArgOrCurrent(options.targetRepo) : null;
|
|
5620
5612
|
const businessId = await resolveBusinessId(config, options);
|
|
5621
5613
|
const ref = options.ref ?? currentRef();
|
|
5622
5614
|
let payload;
|
|
@@ -5654,7 +5646,11 @@ async function sandboxBuildCommand(sourceRepoArg, options = {}, command) {
|
|
|
5654
5646
|
if (!options.wait && !options.follow) return;
|
|
5655
5647
|
const finalBuild = await waitForBuild(config, businessId, payload.buildRequest.id, {
|
|
5656
5648
|
follow: options.follow,
|
|
5657
|
-
pollIntervalMs:
|
|
5649
|
+
pollIntervalMs: parsePollInterval(options.pollInterval, {
|
|
5650
|
+
defaultMs: DEFAULT_POLL_INTERVAL_MS,
|
|
5651
|
+
minMs: MIN_POLL_INTERVAL_MS,
|
|
5652
|
+
maxMs: null
|
|
5653
|
+
}),
|
|
5658
5654
|
json
|
|
5659
5655
|
});
|
|
5660
5656
|
if (json)
|
|
@@ -5667,7 +5663,7 @@ async function sandboxBuildCommand(sourceRepoArg, options = {}, command) {
|
|
|
5667
5663
|
async function sandboxStatusCommand(repoArg, options = {}, command) {
|
|
5668
5664
|
const { config } = resolveBusinessContext(command, options);
|
|
5669
5665
|
const businessId = await resolveBusinessId(config, options);
|
|
5670
|
-
const repo =
|
|
5666
|
+
const repo = parseRepoArgOrCurrent(repoArg);
|
|
5671
5667
|
const payload = await apiFetch(
|
|
5672
5668
|
config,
|
|
5673
5669
|
`/api/businesses/${encodeURIComponent(businessId)}/repos/${encodeURIComponent(repo.owner)}/${encodeURIComponent(
|
|
@@ -5679,9 +5675,9 @@ async function sandboxStatusCommand(repoArg, options = {}, command) {
|
|
|
5679
5675
|
async function sandboxHistoryCommand(sourceRepoArg, options = {}, command) {
|
|
5680
5676
|
const { config } = resolveBusinessContext(command, options);
|
|
5681
5677
|
const businessId = await resolveBusinessId(config, options);
|
|
5682
|
-
const sourceRepo =
|
|
5678
|
+
const sourceRepo = parseRepoArgOrCurrent(sourceRepoArg);
|
|
5683
5679
|
const params = new URLSearchParams({ sourceRepo: repoPath(sourceRepo) });
|
|
5684
|
-
if (options.targetRepo) params.set("targetRepo", repoPath(
|
|
5680
|
+
if (options.targetRepo) params.set("targetRepo", repoPath(parseRepoArgOrCurrent(options.targetRepo)));
|
|
5685
5681
|
if (options.status) params.set("status", options.status);
|
|
5686
5682
|
if (options.limit) {
|
|
5687
5683
|
const limit = Number(options.limit);
|
|
@@ -5776,13 +5772,19 @@ async function sandboxLogsCommand(buildId, options = {}, command) {
|
|
|
5776
5772
|
}
|
|
5777
5773
|
if (!options.follow) return;
|
|
5778
5774
|
if (payload.logs.length > 0) afterSequence = payload.logs[payload.logs.length - 1].sequence;
|
|
5779
|
-
await sleep(
|
|
5775
|
+
await sleep(
|
|
5776
|
+
parsePollInterval(options.pollInterval, {
|
|
5777
|
+
defaultMs: DEFAULT_POLL_INTERVAL_MS,
|
|
5778
|
+
minMs: MIN_POLL_INTERVAL_MS,
|
|
5779
|
+
maxMs: null
|
|
5780
|
+
})
|
|
5781
|
+
);
|
|
5780
5782
|
}
|
|
5781
5783
|
}
|
|
5782
5784
|
async function sandboxAssignDefaultCommand(sourceRepoArg, options = {}, command) {
|
|
5783
5785
|
const { config } = resolveBusinessContext(command, options);
|
|
5784
5786
|
const businessId = await resolveBusinessId(config, options);
|
|
5785
|
-
const sourceRepo =
|
|
5787
|
+
const sourceRepo = parseRepoArgOrCurrent(sourceRepoArg);
|
|
5786
5788
|
const manifestPath = options.manifest ?? DEFAULT_MANIFEST_PATH;
|
|
5787
5789
|
const payload = await apiFetch(
|
|
5788
5790
|
config,
|
|
@@ -5799,8 +5801,8 @@ async function sandboxAssignDefaultCommand(sourceRepoArg, options = {}, command)
|
|
|
5799
5801
|
async function sandboxAssignRepoCommand(targetRepoArg, sourceRepoArg, options = {}, command) {
|
|
5800
5802
|
const { config } = resolveBusinessContext(command, options);
|
|
5801
5803
|
const businessId = await resolveBusinessId(config, options);
|
|
5802
|
-
const targetRepo =
|
|
5803
|
-
const sourceRepo =
|
|
5804
|
+
const targetRepo = parseRepoArgOrCurrent(targetRepoArg);
|
|
5805
|
+
const sourceRepo = parseRepoArgOrCurrent(sourceRepoArg);
|
|
5804
5806
|
const manifestPath = options.manifest ?? DEFAULT_MANIFEST_PATH;
|
|
5805
5807
|
const payload = await apiFetch(
|
|
5806
5808
|
config,
|
|
@@ -5838,7 +5840,7 @@ async function sandboxUnassignRepoCommand(targetRepoArg, options = {}, command)
|
|
|
5838
5840
|
}
|
|
5839
5841
|
const { config } = resolveBusinessContext(command, options);
|
|
5840
5842
|
const businessId = await resolveBusinessId(config, options);
|
|
5841
|
-
const targetRepo =
|
|
5843
|
+
const targetRepo = parseRepoArgOrCurrent(targetRepoArg);
|
|
5842
5844
|
if (!options.yes) await confirmOrThrow(`Clear sandbox layer assignment for ${repoPath(targetRepo)}?`);
|
|
5843
5845
|
const payload = await apiFetch(
|
|
5844
5846
|
config,
|
|
@@ -5851,35 +5853,29 @@ async function sandboxUnassignRepoCommand(targetRepoArg, options = {}, command)
|
|
|
5851
5853
|
}
|
|
5852
5854
|
|
|
5853
5855
|
// src/commands/sessions.ts
|
|
5854
|
-
var MAX_ALL_PAGES2 = 1e3;
|
|
5855
5856
|
async function listSessionsCommand(options, command) {
|
|
5856
5857
|
const runtime = getRuntimeOptions(command, options);
|
|
5857
5858
|
const config = requireConfig(runtime);
|
|
5858
|
-
const sessions2 =
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
sessions2.push(...payload2.sessions);
|
|
5879
|
-
nextCursor = payload2.nextCursor;
|
|
5880
|
-
cursor2 = nextCursor ?? void 0;
|
|
5881
|
-
} while (options.all === true && nextCursor);
|
|
5882
|
-
const payload = { sessions: sessions2, nextCursor: options.all === true ? null : nextCursor };
|
|
5859
|
+
const { items: sessions2, nextCursor } = await fetchPages(
|
|
5860
|
+
"sessions list --all",
|
|
5861
|
+
options.all === true,
|
|
5862
|
+
options.cursor,
|
|
5863
|
+
async (cursor2) => {
|
|
5864
|
+
const query = new URLSearchParams();
|
|
5865
|
+
if (options.status) query.set("status", options.status);
|
|
5866
|
+
if (options.scope) query.set("scope", options.scope);
|
|
5867
|
+
if (options.search) query.set("q", options.search);
|
|
5868
|
+
if (options.repo) query.set("repo", options.repo);
|
|
5869
|
+
if (options.limit) query.set("limit", options.limit);
|
|
5870
|
+
if (cursor2) query.set("cursor", cursor2);
|
|
5871
|
+
const payload2 = await apiFetch(
|
|
5872
|
+
config,
|
|
5873
|
+
`/api/sessions${query.size ? `?${query.toString()}` : ""}`
|
|
5874
|
+
);
|
|
5875
|
+
return { items: payload2.sessions, nextCursor: payload2.nextCursor };
|
|
5876
|
+
}
|
|
5877
|
+
);
|
|
5878
|
+
const payload = { sessions: sessions2, nextCursor };
|
|
5883
5879
|
if (isJson(command, options)) {
|
|
5884
5880
|
writeJson(payload);
|
|
5885
5881
|
return;
|
|
@@ -6021,25 +6017,15 @@ async function stopCommand(sessionId, options = {}, command) {
|
|
|
6021
6017
|
});
|
|
6022
6018
|
}
|
|
6023
6019
|
function parseStopBlocked(err) {
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
if (body.error !== "session_not_stoppable") return null;
|
|
6028
|
-
return { reason: body.reason ?? "not_stoppable" };
|
|
6029
|
-
} catch {
|
|
6030
|
-
return null;
|
|
6031
|
-
}
|
|
6020
|
+
const body = parseConflictBody(err);
|
|
6021
|
+
if (!body || body.error !== "session_not_stoppable") return null;
|
|
6022
|
+
return { reason: typeof body.reason === "string" ? body.reason : "not_stoppable" };
|
|
6032
6023
|
}
|
|
6033
6024
|
|
|
6034
6025
|
// src/commands/test-creds.ts
|
|
6035
6026
|
import { readFileSync as readFileSync4 } from "fs";
|
|
6036
|
-
function parseRepoArg4(value) {
|
|
6037
|
-
const parsed = parseGithubRepoFullName(value);
|
|
6038
|
-
if (!parsed) throw new CliError("user", "repo must be owner/name or a GitHub URL");
|
|
6039
|
-
return { owner: parsed.owner, name: parsed.repo };
|
|
6040
|
-
}
|
|
6041
6027
|
function basePath(businessId, repo) {
|
|
6042
|
-
return `/api/businesses/${encodeURIComponent(businessId)}/repos/${encodeURIComponent(repo.owner)}/${encodeURIComponent(repo.
|
|
6028
|
+
return `/api/businesses/${encodeURIComponent(businessId)}/repos/${encodeURIComponent(repo.owner)}/${encodeURIComponent(repo.repo)}/test-credentials`;
|
|
6043
6029
|
}
|
|
6044
6030
|
function readValue(options) {
|
|
6045
6031
|
const sources = [options.value, options.valueFile, options.valueStdin].filter((v) => v !== void 0 && v !== false);
|
|
@@ -6052,11 +6038,11 @@ function readValue(options) {
|
|
|
6052
6038
|
}
|
|
6053
6039
|
async function listTestCredentialsCommand(repo, options, command) {
|
|
6054
6040
|
const { config } = resolveBusinessContext(command, options);
|
|
6055
|
-
const repoArg =
|
|
6041
|
+
const repoArg = parseRepoArg(repo);
|
|
6056
6042
|
const payload = await apiFetch(config, basePath(options.business, repoArg));
|
|
6057
6043
|
emit(command, options, payload, (listPayload) => {
|
|
6058
6044
|
if (listPayload.credentials.length === 0) {
|
|
6059
|
-
console.log(`No test credentials configured for ${repoArg.owner}/${repoArg.
|
|
6045
|
+
console.log(`No test credentials configured for ${repoArg.owner}/${repoArg.repo}.`);
|
|
6060
6046
|
return;
|
|
6061
6047
|
}
|
|
6062
6048
|
for (const cred of listPayload.credentials) {
|
|
@@ -6067,7 +6053,7 @@ async function listTestCredentialsCommand(repo, options, command) {
|
|
|
6067
6053
|
}
|
|
6068
6054
|
async function setTestCredentialCommand(repo, name, options, command) {
|
|
6069
6055
|
const { config } = resolveBusinessContext(command, options);
|
|
6070
|
-
const repoArg =
|
|
6056
|
+
const repoArg = parseRepoArg(repo);
|
|
6071
6057
|
const value = readValue(options);
|
|
6072
6058
|
const payload = await apiFetch(
|
|
6073
6059
|
config,
|
|
@@ -6078,7 +6064,7 @@ async function setTestCredentialCommand(repo, name, options, command) {
|
|
|
6078
6064
|
command,
|
|
6079
6065
|
options,
|
|
6080
6066
|
payload,
|
|
6081
|
-
() => console.log(`Set test credential '${name}' for ${repoArg.owner}/${repoArg.
|
|
6067
|
+
() => console.log(`Set test credential '${name}' for ${repoArg.owner}/${repoArg.repo}.`)
|
|
6082
6068
|
);
|
|
6083
6069
|
}
|
|
6084
6070
|
async function deleteTestCredentialCommand(repo, name, options, command) {
|
|
@@ -6086,11 +6072,11 @@ async function deleteTestCredentialCommand(repo, name, options, command) {
|
|
|
6086
6072
|
throw new CliError("user", "`test-creds delete --json` requires --yes.");
|
|
6087
6073
|
}
|
|
6088
6074
|
if (options.yes !== true) {
|
|
6089
|
-
const repoArg2 =
|
|
6090
|
-
await confirmOrThrow(`Delete test credential '${name}' for ${repoArg2.owner}/${repoArg2.
|
|
6075
|
+
const repoArg2 = parseRepoArg(repo);
|
|
6076
|
+
await confirmOrThrow(`Delete test credential '${name}' for ${repoArg2.owner}/${repoArg2.repo}?`);
|
|
6091
6077
|
}
|
|
6092
6078
|
const { config } = resolveBusinessContext(command, options);
|
|
6093
|
-
const repoArg =
|
|
6079
|
+
const repoArg = parseRepoArg(repo);
|
|
6094
6080
|
const payload = await apiFetch(
|
|
6095
6081
|
config,
|
|
6096
6082
|
`${basePath(options.business, repoArg)}/${encodeURIComponent(name)}`,
|
|
@@ -6100,35 +6086,29 @@ async function deleteTestCredentialCommand(repo, name, options, command) {
|
|
|
6100
6086
|
command,
|
|
6101
6087
|
options,
|
|
6102
6088
|
payload,
|
|
6103
|
-
() => console.log(`Deleted test credential '${name}' for ${repoArg.owner}/${repoArg.
|
|
6089
|
+
() => console.log(`Deleted test credential '${name}' for ${repoArg.owner}/${repoArg.repo}.`)
|
|
6104
6090
|
);
|
|
6105
6091
|
}
|
|
6106
6092
|
|
|
6107
6093
|
// src/commands/tokens.ts
|
|
6108
|
-
var MAX_ALL_PAGES3 = 1e3;
|
|
6109
6094
|
async function listTokensCommand(options, command) {
|
|
6110
6095
|
const { config } = resolveBusinessContext(command, options);
|
|
6111
|
-
const data =
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6096
|
+
const { items: data, nextCursor } = await fetchPages(
|
|
6097
|
+
"tokens list --all",
|
|
6098
|
+
options.all === true,
|
|
6099
|
+
options.cursor,
|
|
6100
|
+
async (cursor2) => {
|
|
6101
|
+
const query = new URLSearchParams();
|
|
6102
|
+
if (options.limit) query.set("limit", options.limit);
|
|
6103
|
+
if (cursor2) query.set("cursor", cursor2);
|
|
6104
|
+
const payload2 = await apiFetch(
|
|
6105
|
+
config,
|
|
6106
|
+
`/api/cli-tokens${query.size ? `?${query.toString()}` : ""}`
|
|
6107
|
+
);
|
|
6108
|
+
return { items: payload2.data, nextCursor: payload2.nextCursor };
|
|
6119
6109
|
}
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
if (cursor2) query.set("cursor", cursor2);
|
|
6123
|
-
const payload2 = await apiFetch(
|
|
6124
|
-
config,
|
|
6125
|
-
`/api/cli-tokens${query.size ? `?${query.toString()}` : ""}`
|
|
6126
|
-
);
|
|
6127
|
-
data.push(...payload2.data);
|
|
6128
|
-
nextCursor = payload2.nextCursor;
|
|
6129
|
-
cursor2 = nextCursor ?? void 0;
|
|
6130
|
-
} while (options.all === true && nextCursor);
|
|
6131
|
-
const payload = { data, nextCursor: options.all === true ? null : nextCursor };
|
|
6110
|
+
);
|
|
6111
|
+
const payload = { data, nextCursor };
|
|
6132
6112
|
emit(command, options, payload, (listPayload) => {
|
|
6133
6113
|
if (listPayload.data.length === 0) {
|
|
6134
6114
|
console.log("No CLI tokens found.");
|