@tryarcanist/cli 0.1.178 → 0.1.179

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.
Files changed (2) hide show
  1. package/dist/index.js +31 -51
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -295,7 +295,6 @@ function validateApiUrl(url) {
295
295
  if (parsed.username || parsed.password) {
296
296
  return "API URL must not include embedded credentials. Use --token or ARCANIST_TOKEN to authenticate.";
297
297
  }
298
- const host = parsed.hostname.replace(/^\[|\]$/g, "");
299
298
  if (parsed.protocol !== "https:" && !isLoopbackHost(parsed)) {
300
299
  return "API URL must use HTTPS for non-local hosts";
301
300
  }
@@ -1005,6 +1004,7 @@ var AUTOMATION_ERROR_HINTS = {
1005
1004
  installation_unresolved: "Reconnect or reinstall the GitHub integration for that repository, then retry.",
1006
1005
  model_not_available: "That model's backend (Claude/opencode) is limited to Arcanist team businesses; use the codex default or a codex model."
1007
1006
  };
1007
+ var MAX_ALL_PAGES = 1e3;
1008
1008
  async function createAutomationCommand(repoUrl, promptArg, options, command) {
1009
1009
  const repo = parseAutomationRepo(repoUrl);
1010
1010
  const prompt = await resolvePromptInput(promptArg, options);
@@ -1043,7 +1043,12 @@ async function listAutomationsCommand(options, command) {
1043
1043
  const items = [];
1044
1044
  let cursor = options.cursor;
1045
1045
  let nextCursor = null;
1046
+ let pageCount = 0;
1046
1047
  do {
1048
+ pageCount += 1;
1049
+ if (options.all === true && pageCount > MAX_ALL_PAGES) {
1050
+ throw new CliError("user", `automations list --all exceeded ${MAX_ALL_PAGES} pages without reaching the end.`);
1051
+ }
1047
1052
  const query = new URLSearchParams();
1048
1053
  if (options.limit) query.set("limit", options.limit);
1049
1054
  if (cursor) query.set("cursor", cursor);
@@ -1125,7 +1130,7 @@ function mapAutomationApiError(err) {
1125
1130
  }
1126
1131
  const parsed = parseApiErrorBody2(err.body);
1127
1132
  const serverCode = parsed?.error;
1128
- return new CliError(codeForStatus(err.status), parsed?.message || serverCode || err.message, {
1133
+ return new CliError(codeForHttpStatus(err.status), parsed?.message || serverCode || err.message, {
1129
1134
  exitCode: err.exitCode,
1130
1135
  hint: serverCode ? AUTOMATION_ERROR_HINTS[serverCode] : void 0,
1131
1136
  requestId: err.requestId
@@ -1144,13 +1149,6 @@ function parseApiErrorBody2(body) {
1144
1149
  return null;
1145
1150
  }
1146
1151
  }
1147
- function codeForStatus(status) {
1148
- if (status === 401 || status === 403) return "auth";
1149
- if (status === 404) return "not_found";
1150
- if (status === 409) return "conflict";
1151
- if (status >= 500) return "server";
1152
- return "user";
1153
- }
1154
1152
  function printAutomationRule(rule) {
1155
1153
  console.log(`ID: ${rule.id}`);
1156
1154
  console.log(`Repo: ${rule.repoOwner}/${rule.repoName}`);
@@ -3305,13 +3303,7 @@ async function loginCommand(options, command) {
3305
3303
  if (!token.startsWith("arc_")) {
3306
3304
  throw new CliError("user", "Invalid token format. Token must start with 'arc_'.");
3307
3305
  }
3308
- if (runtime.apiUrl) {
3309
- const urlError = validateApiUrl(runtime.apiUrl);
3310
- if (urlError) {
3311
- throw new CliError("user", urlError);
3312
- }
3313
- }
3314
- const apiUrl = normalizeBaseUrl(resolveLoginApiUrl(runtime.apiUrl));
3306
+ const apiUrl = resolveLoginApiUrl(runtime.apiUrl);
3315
3307
  saveConfig({ apiUrl, token });
3316
3308
  if (runtime.json) {
3317
3309
  writeJson({ ok: true, apiUrl });
@@ -3536,7 +3528,7 @@ async function qaCommand(prUrl, options, command) {
3536
3528
  console.log(`Follow with: arcanist sessions events ${sessionId} --follow --json`);
3537
3529
  }
3538
3530
 
3539
- // src/commands/repos.ts
3531
+ // src/git.ts
3540
3532
  import { execFileSync } from "child_process";
3541
3533
  function git(args) {
3542
3534
  try {
@@ -3550,6 +3542,8 @@ function currentRepo() {
3550
3542
  if (!parsed) throw new CliError("user", "origin remote must point at a GitHub repository");
3551
3543
  return { owner: parsed.owner, repo: parsed.repo };
3552
3544
  }
3545
+
3546
+ // src/commands/repos.ts
3553
3547
  function parseRepoArg2(value) {
3554
3548
  if (!value) return currentRepo();
3555
3549
  const parsed = parseGithubRepoFullName(value);
@@ -3645,7 +3639,6 @@ function parseRespondConflict(err) {
3645
3639
  }
3646
3640
 
3647
3641
  // src/commands/sandbox.ts
3648
- import { execFileSync as execFileSync2 } from "child_process";
3649
3642
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
3650
3643
  import { dirname as dirname2 } from "path";
3651
3644
 
@@ -4181,27 +4174,14 @@ var DEFAULT_MANIFEST_PATH = SANDBOX_LAYER_MANIFEST_PATH;
4181
4174
  var DEFAULT_POLL_INTERVAL_MS = 2500;
4182
4175
  var MIN_POLL_INTERVAL_MS = 250;
4183
4176
  var TERMINAL_BUILD_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "canceled"]);
4184
- function git2(args) {
4185
- try {
4186
- return execFileSync2("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
4187
- } catch (err) {
4188
- throw new CliError("user", `git ${args.join(" ")} failed: ${stringifyError(err)}`);
4189
- }
4190
- }
4191
- function currentRepo2() {
4192
- const remote = git2(["remote", "get-url", "origin"]);
4193
- const parsed = parseGithubRepoFullName(remote);
4194
- if (!parsed) throw new CliError("user", "origin remote must point at a GitHub repository");
4195
- return { owner: parsed.owner, repo: parsed.repo };
4196
- }
4197
4177
  function currentRef() {
4198
- return git2(["rev-parse", "--abbrev-ref", "HEAD"]);
4178
+ return git(["rev-parse", "--abbrev-ref", "HEAD"]);
4199
4179
  }
4200
4180
  function assertCleanAndPushed() {
4201
- const dirty = git2(["status", "--porcelain"]);
4181
+ const dirty = git(["status", "--porcelain"]);
4202
4182
  if (dirty) throw new CliError("user", "Sandbox layer source must be committed before build.");
4203
- const upstream = git2(["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"]);
4204
- const ahead = git2(["rev-list", "--count", `${upstream}..HEAD`]);
4183
+ const upstream = git(["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"]);
4184
+ const ahead = git(["rev-list", "--count", `${upstream}..HEAD`]);
4205
4185
  if (ahead !== "0")
4206
4186
  throw new CliError("user", "Current commit is not pushed; push before building the sandbox layer.");
4207
4187
  }
@@ -4385,7 +4365,7 @@ function formatValidationPayload(input) {
4385
4365
  }
4386
4366
  function nextBuildCommand(manifestPath) {
4387
4367
  try {
4388
- const repo = currentRepo2();
4368
+ const repo = currentRepo();
4389
4369
  const manifestArg = manifestPath === DEFAULT_MANIFEST_PATH ? "" : ` --manifest ${manifestPath}`;
4390
4370
  return `arcanist sandbox build ${repoPath(repo)} --wait --follow${manifestArg}`;
4391
4371
  } catch {
@@ -4475,8 +4455,8 @@ async function sandboxBuildCommand(sourceRepoArg, options = {}, command) {
4475
4455
  const manifestPath = options.manifest ?? DEFAULT_MANIFEST_PATH;
4476
4456
  assertManifestExists(manifestPath);
4477
4457
  if (!options.ref) assertCleanAndPushed();
4478
- const sourceRepo = parseRepoArg3(sourceRepoArg, currentRepo2);
4479
- const targetRepo = options.targetRepo ? parseRepoArg3(options.targetRepo, currentRepo2) : null;
4458
+ const sourceRepo = parseRepoArg3(sourceRepoArg, currentRepo);
4459
+ const targetRepo = options.targetRepo ? parseRepoArg3(options.targetRepo, currentRepo) : null;
4480
4460
  const businessId = await resolveBusinessId(config, options);
4481
4461
  const ref = options.ref ?? currentRef();
4482
4462
  let payload;
@@ -4527,7 +4507,7 @@ async function sandboxBuildCommand(sourceRepoArg, options = {}, command) {
4527
4507
  async function sandboxStatusCommand(repoArg, options = {}, command) {
4528
4508
  const { config } = resolveBusinessContext(command, options);
4529
4509
  const businessId = await resolveBusinessId(config, options);
4530
- const repo = parseRepoArg3(repoArg, currentRepo2);
4510
+ const repo = parseRepoArg3(repoArg, currentRepo);
4531
4511
  const payload = await apiFetch(
4532
4512
  config,
4533
4513
  `/api/businesses/${encodeURIComponent(businessId)}/repos/${encodeURIComponent(repo.owner)}/${encodeURIComponent(
@@ -4539,9 +4519,9 @@ async function sandboxStatusCommand(repoArg, options = {}, command) {
4539
4519
  async function sandboxHistoryCommand(sourceRepoArg, options = {}, command) {
4540
4520
  const { config } = resolveBusinessContext(command, options);
4541
4521
  const businessId = await resolveBusinessId(config, options);
4542
- const sourceRepo = parseRepoArg3(sourceRepoArg, currentRepo2);
4522
+ const sourceRepo = parseRepoArg3(sourceRepoArg, currentRepo);
4543
4523
  const params = new URLSearchParams({ sourceRepo: repoPath(sourceRepo) });
4544
- if (options.targetRepo) params.set("targetRepo", repoPath(parseRepoArg3(options.targetRepo, currentRepo2)));
4524
+ if (options.targetRepo) params.set("targetRepo", repoPath(parseRepoArg3(options.targetRepo, currentRepo)));
4545
4525
  if (options.status) params.set("status", options.status);
4546
4526
  if (options.limit) {
4547
4527
  const limit = Number(options.limit);
@@ -4642,7 +4622,7 @@ async function sandboxLogsCommand(buildId, options = {}, command) {
4642
4622
  async function sandboxAssignDefaultCommand(sourceRepoArg, options = {}, command) {
4643
4623
  const { config } = resolveBusinessContext(command, options);
4644
4624
  const businessId = await resolveBusinessId(config, options);
4645
- const sourceRepo = parseRepoArg3(sourceRepoArg, currentRepo2);
4625
+ const sourceRepo = parseRepoArg3(sourceRepoArg, currentRepo);
4646
4626
  const manifestPath = options.manifest ?? DEFAULT_MANIFEST_PATH;
4647
4627
  const payload = await apiFetch(
4648
4628
  config,
@@ -4659,8 +4639,8 @@ async function sandboxAssignDefaultCommand(sourceRepoArg, options = {}, command)
4659
4639
  async function sandboxAssignRepoCommand(targetRepoArg, sourceRepoArg, options = {}, command) {
4660
4640
  const { config } = resolveBusinessContext(command, options);
4661
4641
  const businessId = await resolveBusinessId(config, options);
4662
- const targetRepo = parseRepoArg3(targetRepoArg, currentRepo2);
4663
- const sourceRepo = parseRepoArg3(sourceRepoArg, currentRepo2);
4642
+ const targetRepo = parseRepoArg3(targetRepoArg, currentRepo);
4643
+ const sourceRepo = parseRepoArg3(sourceRepoArg, currentRepo);
4664
4644
  const manifestPath = options.manifest ?? DEFAULT_MANIFEST_PATH;
4665
4645
  const payload = await apiFetch(
4666
4646
  config,
@@ -4698,7 +4678,7 @@ async function sandboxUnassignRepoCommand(targetRepoArg, options = {}, command)
4698
4678
  }
4699
4679
  const { config } = resolveBusinessContext(command, options);
4700
4680
  const businessId = await resolveBusinessId(config, options);
4701
- const targetRepo = parseRepoArg3(targetRepoArg, currentRepo2);
4681
+ const targetRepo = parseRepoArg3(targetRepoArg, currentRepo);
4702
4682
  if (!options.yes) await confirmOrThrow(`Clear sandbox layer assignment for ${repoPath(targetRepo)}?`);
4703
4683
  const payload = await apiFetch(
4704
4684
  config,
@@ -4711,7 +4691,7 @@ async function sandboxUnassignRepoCommand(targetRepoArg, options = {}, command)
4711
4691
  }
4712
4692
 
4713
4693
  // src/commands/sessions.ts
4714
- var MAX_ALL_PAGES = 1e3;
4694
+ var MAX_ALL_PAGES2 = 1e3;
4715
4695
  async function listSessionsCommand(options, command) {
4716
4696
  const runtime = getRuntimeOptions(command, options);
4717
4697
  const config = requireConfig(runtime);
@@ -4721,8 +4701,8 @@ async function listSessionsCommand(options, command) {
4721
4701
  let pageCount = 0;
4722
4702
  do {
4723
4703
  pageCount += 1;
4724
- if (options.all === true && pageCount > MAX_ALL_PAGES) {
4725
- throw new CliError("user", `sessions list --all exceeded ${MAX_ALL_PAGES} pages without reaching the end.`);
4704
+ if (options.all === true && pageCount > MAX_ALL_PAGES2) {
4705
+ throw new CliError("user", `sessions list --all exceeded ${MAX_ALL_PAGES2} pages without reaching the end.`);
4726
4706
  }
4727
4707
  const query = new URLSearchParams();
4728
4708
  if (options.status) query.set("status", options.status);
@@ -4968,7 +4948,7 @@ async function deleteTestCredentialCommand(repo, name, options, command) {
4968
4948
  }
4969
4949
 
4970
4950
  // src/commands/tokens.ts
4971
- var MAX_ALL_PAGES2 = 1e3;
4951
+ var MAX_ALL_PAGES3 = 1e3;
4972
4952
  async function listTokensCommand(options, command) {
4973
4953
  const { config } = resolveBusinessContext(command, options);
4974
4954
  const data = [];
@@ -4977,8 +4957,8 @@ async function listTokensCommand(options, command) {
4977
4957
  let pageCount = 0;
4978
4958
  do {
4979
4959
  pageCount += 1;
4980
- if (options.all === true && pageCount > MAX_ALL_PAGES2) {
4981
- throw new CliError("user", `tokens list --all exceeded ${MAX_ALL_PAGES2} pages without reaching the end.`);
4960
+ if (options.all === true && pageCount > MAX_ALL_PAGES3) {
4961
+ throw new CliError("user", `tokens list --all exceeded ${MAX_ALL_PAGES3} pages without reaching the end.`);
4982
4962
  }
4983
4963
  const query = new URLSearchParams();
4984
4964
  if (options.limit) query.set("limit", options.limit);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryarcanist/cli",
3
- "version": "0.1.178",
3
+ "version": "0.1.179",
4
4
  "description": "CLI for Arcanist — create and manage coding agent sessions",
5
5
  "type": "module",
6
6
  "bin": {