@tryarcanist/cli 0.1.163 → 0.1.164

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 (3) hide show
  1. package/README.md +3 -0
  2. package/dist/index.js +221 -161
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -272,10 +272,13 @@ Creates a scheduled automation for a GitHub repo. Create/delete require a write-
272
272
 
273
273
  ```bash
274
274
  arcanist automations create your-org/your-repo "summarize new regressions" --cron "*/15 * * * *"
275
+ arcanist automations create your-org/your-repo "audit N+1s" --cron "0 13 * * 5" --model gpt-5.5
275
276
  printf "summarize new regressions" | arcanist automations create your-org/your-repo --prompt-stdin --cron "*/15 * * * *" --json
276
277
  arcanist automations create https://github.com/your-org/your-repo - --cron "0 14 * * 1-5" --name "Weekday summary"
277
278
  ```
278
279
 
280
+ 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 or opencode are limited to Arcanist team businesses. When `--model` is omitted the codex backend default is used.
281
+
279
282
  JSON mode prints the created rule. Human-readable mode prints the rule ID, repo, normalized cron, and next fire time.
280
283
 
281
284
  ### `arcanist automations list`
package/dist/index.js CHANGED
@@ -495,161 +495,6 @@ async function whoamiCommand(options, command) {
495
495
  });
496
496
  }
497
497
 
498
- // ../../shared/github/repo-url.ts
499
- function parseGithubRepoFullName(value) {
500
- const shorthand = value.match(/^([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)$/);
501
- if (shorthand) return { owner: shorthand[1], repo: shorthand[2] };
502
- const ssh = value.match(/git@[^:]+:([^/]+)\/([^/]+?)(?:\.git)?$/);
503
- if (ssh) return { owner: ssh[1], repo: ssh[2] };
504
- const https = value.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
505
- if (https) return { owner: https[1], repo: https[2] };
506
- return null;
507
- }
508
-
509
- // src/commands/automations.ts
510
- var AUTOMATION_ERROR_HINTS = {
511
- invalid_cron: "Use a standard five-field cron expression, for example: */15 * * * *",
512
- repo_not_available: "Check that the token owner has GitHub access and Arcanist is installed for that repo.",
513
- duplicate_rule: "An enabled automation already exists for this repo, cron, and prompt.",
514
- rule_cap_reached: "Delete or disable an existing automation before creating another one. The cap is 20 enabled rules.",
515
- installation_unresolved: "Reconnect or reinstall the GitHub integration for that repository, then retry."
516
- };
517
- async function createAutomationCommand(repoUrl, promptArg, options, command) {
518
- const repo = parseAutomationRepo(repoUrl);
519
- const prompt = await resolvePromptInput(promptArg, options);
520
- const runtime = getRuntimeOptions(command, options);
521
- const config = requireConfig(runtime);
522
- const body = {
523
- repoOwner: repo.owner,
524
- repoName: repo.repo,
525
- cron: options.cron,
526
- prompt
527
- };
528
- if (options.name !== void 0) body.name = options.name;
529
- const payload = await automationApiFetch(config, "/api/automation/schedules", {
530
- method: "POST",
531
- body: JSON.stringify(body)
532
- });
533
- if (isJson(command, options)) {
534
- writeJson(payload.data);
535
- return;
536
- }
537
- printAutomationRule(payload.data);
538
- }
539
- async function listAutomationsCommand(options, command) {
540
- const runtime = getRuntimeOptions(command, options);
541
- const config = requireConfig(runtime);
542
- const items = [];
543
- let cursor = options.cursor;
544
- let nextCursor = null;
545
- do {
546
- const query = new URLSearchParams();
547
- if (options.limit) query.set("limit", options.limit);
548
- if (cursor) query.set("cursor", cursor);
549
- const payload = await automationApiFetch(
550
- config,
551
- `/api/automation/schedules${query.size ? `?${query.toString()}` : ""}`
552
- );
553
- items.push(...payload.data.items);
554
- nextCursor = payload.data.nextCursor;
555
- cursor = nextCursor ?? void 0;
556
- } while (options.all === true && nextCursor);
557
- const output = { items, nextCursor: options.all === true ? null : nextCursor };
558
- if (isJson(command, options)) {
559
- writeJson(output);
560
- return;
561
- }
562
- if (items.length === 0) {
563
- console.log("No automations found.");
564
- return;
565
- }
566
- for (const rule of items) {
567
- console.log(
568
- `${rule.id} ${rule.repoOwner}/${rule.repoName} ${rule.normalizedCron} ${String(rule.enabled)} ${formatTime(rule.nextFireAt)}`
569
- );
570
- }
571
- if (output.nextCursor) console.log(`Next cursor: ${output.nextCursor}`);
572
- }
573
- async function deleteAutomationCommand(id, options, command) {
574
- if (isJson(command, options) && options.yes !== true) {
575
- throw new CliError("user", "`automations delete --json` requires --yes.");
576
- }
577
- if (options.yes !== true) {
578
- await confirmOrThrow(`Delete automation ${id}?`);
579
- }
580
- const runtime = getRuntimeOptions(command, options);
581
- const config = requireConfig(runtime);
582
- await automationApiFetchText(config, `/api/automation/schedules/${encodeURIComponent(id)}`, { method: "DELETE" });
583
- if (isJson(command, options)) {
584
- writeJson({ ok: true, id });
585
- return;
586
- }
587
- console.log(`Deleted automation ${id}.`);
588
- }
589
- function parseAutomationRepo(value) {
590
- if (/^git@/i.test(value) && !/^git@github\.com:/i.test(value)) {
591
- throw new CliError("user", "repo-url must be owner/name or a GitHub URL.");
592
- }
593
- const parsed = parseGithubRepoFullName(value);
594
- if (!parsed) throw new CliError("user", "repo-url must be owner/name or a GitHub URL.");
595
- return { owner: parsed.owner, repo: parsed.repo };
596
- }
597
- async function automationApiFetch(config, path, init) {
598
- try {
599
- return await apiFetch(config, path, init);
600
- } catch (err) {
601
- throw mapAutomationApiError(err);
602
- }
603
- }
604
- async function automationApiFetchText(config, path, init) {
605
- try {
606
- return await apiFetchText(config, path, init);
607
- } catch (err) {
608
- throw mapAutomationApiError(err);
609
- }
610
- }
611
- function mapAutomationApiError(err) {
612
- if (!(err instanceof ApiError)) {
613
- return err instanceof CliError ? err : new CliError("server", err instanceof Error ? err.message : String(err));
614
- }
615
- const parsed = parseApiErrorBody2(err.body);
616
- const serverCode = parsed?.error;
617
- return new CliError(codeForStatus(err.status), parsed?.message || serverCode || err.message, {
618
- exitCode: err.exitCode,
619
- hint: serverCode ? AUTOMATION_ERROR_HINTS[serverCode] : void 0,
620
- requestId: err.requestId
621
- });
622
- }
623
- function parseApiErrorBody2(body) {
624
- try {
625
- const parsed = JSON.parse(body);
626
- if (!parsed || typeof parsed !== "object") return null;
627
- const record = parsed;
628
- return {
629
- error: typeof record.error === "string" ? record.error : void 0,
630
- message: typeof record.message === "string" ? record.message : void 0
631
- };
632
- } catch {
633
- return null;
634
- }
635
- }
636
- function codeForStatus(status) {
637
- if (status === 401 || status === 403) return "auth";
638
- if (status === 404) return "not_found";
639
- if (status === 409) return "conflict";
640
- if (status >= 500) return "server";
641
- return "user";
642
- }
643
- function printAutomationRule(rule) {
644
- console.log(`ID: ${rule.id}`);
645
- console.log(`Repo: ${rule.repoOwner}/${rule.repoName}`);
646
- console.log(`Cron: ${rule.normalizedCron}`);
647
- console.log(`Next fire: ${formatTime(rule.nextFireAt)}`);
648
- }
649
- function formatTime(value) {
650
- return typeof value === "number" ? new Date(value).toISOString() : "none";
651
- }
652
-
653
498
  // ../../shared/agent/agent-runtime-backend.ts
654
499
  var CODEX_AGENT_RUNTIME_BACKEND = "codex";
655
500
  var CLAUDE_CODE_AGENT_RUNTIME_BACKEND = "claude_code";
@@ -953,12 +798,18 @@ function extractModelId(raw) {
953
798
  if (!value) return void 0;
954
799
  return splitModelIdentifier(value)?.modelID;
955
800
  }
801
+ function getAgentRuntimeBackendForModel(modelId) {
802
+ return getBackendsForModel(modelId)?.[0];
803
+ }
956
804
  function getSessionStartModelIdsForBackend(backend) {
957
805
  return SESSION_START_MODEL_IDS_BY_BACKEND[backend];
958
806
  }
959
807
  function isSessionStartModelAllowedForBackend(modelId, backend) {
960
808
  return VALID_SESSION_START_MODEL_IDS_BY_BACKEND[backend].has(modelId);
961
809
  }
810
+ function getBackendsForModel(modelId) {
811
+ return MODEL_DEFINITIONS_BY_ID[modelId]?.backends;
812
+ }
962
813
  function getProviderForModel(modelId) {
963
814
  return MODEL_PROVIDERS[modelId] ?? "openai";
964
815
  }
@@ -1018,6 +869,183 @@ var CODEX_SUBSCRIPTION_SESSION_START_MODEL_PROVIDER_GROUPS = buildModelProviderG
1018
869
  )
1019
870
  );
1020
871
 
872
+ // ../../shared/github/repo-url.ts
873
+ function parseGithubRepoFullName(value) {
874
+ const shorthand = value.match(/^([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)$/);
875
+ if (shorthand) return { owner: shorthand[1], repo: shorthand[2] };
876
+ const ssh = value.match(/git@[^:]+:([^/]+)\/([^/]+?)(?:\.git)?$/);
877
+ if (ssh) return { owner: ssh[1], repo: ssh[2] };
878
+ const https = value.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
879
+ if (https) return { owner: https[1], repo: https[2] };
880
+ return null;
881
+ }
882
+
883
+ // src/commands/automations.ts
884
+ var AUTOMATION_ERROR_HINTS = {
885
+ invalid_cron: "Use a standard five-field cron expression, for example: */15 * * * *",
886
+ invalid_model: "Model is unknown or not selectable for its backend. Run `arcanist automations create --help` for allowed models.",
887
+ repo_not_available: "Check that the token owner has GitHub access and Arcanist is installed for that repo.",
888
+ duplicate_rule: "An enabled automation already exists for this repo, cron, and prompt.",
889
+ rule_cap_reached: "Delete or disable an existing automation before creating another one. The cap is 20 enabled rules.",
890
+ installation_unresolved: "Reconnect or reinstall the GitHub integration for that repository, then retry.",
891
+ model_not_available: "That model's backend (Claude/opencode) is limited to Arcanist team businesses; use the codex default or a codex model."
892
+ };
893
+ async function createAutomationCommand(repoUrl, promptArg, options, command) {
894
+ const repo = parseAutomationRepo(repoUrl);
895
+ const prompt = await resolvePromptInput(promptArg, options);
896
+ const runtime = getRuntimeOptions(command, options);
897
+ const config = requireConfig(runtime);
898
+ let normalizedModel;
899
+ if (options.model !== void 0) {
900
+ normalizedModel = extractModelId(options.model);
901
+ const backend = resolveAutomationModelBackend(options.model, normalizedModel);
902
+ if (normalizedModel === void 0 || !isSessionStartModelAllowedForBackend(normalizedModel, backend)) {
903
+ const allowed = getSessionStartModelIdsForBackend(backend).join(", ");
904
+ throw new CliError("user", `Model '${options.model}' is not selectable. Allowed: ${allowed}.`);
905
+ }
906
+ }
907
+ const body = {
908
+ repoOwner: repo.owner,
909
+ repoName: repo.repo,
910
+ cron: options.cron,
911
+ prompt
912
+ };
913
+ if (options.name !== void 0) body.name = options.name;
914
+ if (options.model !== void 0) body.modelId = normalizedModel;
915
+ const payload = await automationApiFetch(config, "/api/automation/schedules", {
916
+ method: "POST",
917
+ body: JSON.stringify(body)
918
+ });
919
+ if (isJson(command, options)) {
920
+ writeJson(payload.data);
921
+ return;
922
+ }
923
+ printAutomationRule(payload.data);
924
+ }
925
+ async function listAutomationsCommand(options, command) {
926
+ const runtime = getRuntimeOptions(command, options);
927
+ const config = requireConfig(runtime);
928
+ const items = [];
929
+ let cursor = options.cursor;
930
+ let nextCursor = null;
931
+ do {
932
+ const query = new URLSearchParams();
933
+ if (options.limit) query.set("limit", options.limit);
934
+ if (cursor) query.set("cursor", cursor);
935
+ const payload = await automationApiFetch(
936
+ config,
937
+ `/api/automation/schedules${query.size ? `?${query.toString()}` : ""}`
938
+ );
939
+ items.push(...payload.data.items);
940
+ nextCursor = payload.data.nextCursor;
941
+ cursor = nextCursor ?? void 0;
942
+ } while (options.all === true && nextCursor);
943
+ const output = { items, nextCursor: options.all === true ? null : nextCursor };
944
+ if (isJson(command, options)) {
945
+ writeJson(output);
946
+ return;
947
+ }
948
+ if (items.length === 0) {
949
+ console.log("No automations found.");
950
+ return;
951
+ }
952
+ for (const rule of items) {
953
+ console.log(
954
+ `${rule.id} ${rule.repoOwner}/${rule.repoName} ${rule.normalizedCron} ${String(rule.enabled)} ${formatTime(rule.nextFireAt)}`
955
+ );
956
+ }
957
+ if (output.nextCursor) console.log(`Next cursor: ${output.nextCursor}`);
958
+ }
959
+ async function deleteAutomationCommand(id, options, command) {
960
+ if (isJson(command, options) && options.yes !== true) {
961
+ throw new CliError("user", "`automations delete --json` requires --yes.");
962
+ }
963
+ if (options.yes !== true) {
964
+ await confirmOrThrow(`Delete automation ${id}?`);
965
+ }
966
+ const runtime = getRuntimeOptions(command, options);
967
+ const config = requireConfig(runtime);
968
+ await automationApiFetchText(config, `/api/automation/schedules/${encodeURIComponent(id)}`, { method: "DELETE" });
969
+ if (isJson(command, options)) {
970
+ writeJson({ ok: true, id });
971
+ return;
972
+ }
973
+ console.log(`Deleted automation ${id}.`);
974
+ }
975
+ function parseAutomationRepo(value) {
976
+ if (/^git@/i.test(value) && !/^git@github\.com:/i.test(value)) {
977
+ throw new CliError("user", "repo-url must be owner/name or a GitHub URL.");
978
+ }
979
+ const parsed = parseGithubRepoFullName(value);
980
+ if (!parsed) throw new CliError("user", "repo-url must be owner/name or a GitHub URL.");
981
+ return { owner: parsed.owner, repo: parsed.repo };
982
+ }
983
+ function resolveAutomationModelBackend(rawModel, normalizedModel) {
984
+ if (normalizedModel) {
985
+ const backend = getAgentRuntimeBackendForModel(normalizedModel);
986
+ if (backend) return backend;
987
+ }
988
+ const provider = rawModel.match(/^([a-z]+)[/:]/i)?.[1]?.toLowerCase();
989
+ if (provider === "anthropic") return CLAUDE_CODE_AGENT_RUNTIME_BACKEND;
990
+ if (provider === "baseten") return OPENCODE_AGENT_RUNTIME_BACKEND;
991
+ return CODEX_AGENT_RUNTIME_BACKEND;
992
+ }
993
+ async function automationApiFetch(config, path, init) {
994
+ try {
995
+ return await apiFetch(config, path, init);
996
+ } catch (err) {
997
+ throw mapAutomationApiError(err);
998
+ }
999
+ }
1000
+ async function automationApiFetchText(config, path, init) {
1001
+ try {
1002
+ return await apiFetchText(config, path, init);
1003
+ } catch (err) {
1004
+ throw mapAutomationApiError(err);
1005
+ }
1006
+ }
1007
+ function mapAutomationApiError(err) {
1008
+ if (!(err instanceof ApiError)) {
1009
+ return err instanceof CliError ? err : new CliError("server", err instanceof Error ? err.message : String(err));
1010
+ }
1011
+ const parsed = parseApiErrorBody2(err.body);
1012
+ const serverCode = parsed?.error;
1013
+ return new CliError(codeForStatus(err.status), parsed?.message || serverCode || err.message, {
1014
+ exitCode: err.exitCode,
1015
+ hint: serverCode ? AUTOMATION_ERROR_HINTS[serverCode] : void 0,
1016
+ requestId: err.requestId
1017
+ });
1018
+ }
1019
+ function parseApiErrorBody2(body) {
1020
+ try {
1021
+ const parsed = JSON.parse(body);
1022
+ if (!parsed || typeof parsed !== "object") return null;
1023
+ const record = parsed;
1024
+ return {
1025
+ error: typeof record.error === "string" ? record.error : void 0,
1026
+ message: typeof record.message === "string" ? record.message : void 0
1027
+ };
1028
+ } catch {
1029
+ return null;
1030
+ }
1031
+ }
1032
+ function codeForStatus(status) {
1033
+ if (status === 401 || status === 403) return "auth";
1034
+ if (status === 404) return "not_found";
1035
+ if (status === 409) return "conflict";
1036
+ if (status >= 500) return "server";
1037
+ return "user";
1038
+ }
1039
+ function printAutomationRule(rule) {
1040
+ console.log(`ID: ${rule.id}`);
1041
+ console.log(`Repo: ${rule.repoOwner}/${rule.repoName}`);
1042
+ console.log(`Cron: ${rule.normalizedCron}`);
1043
+ console.log(`Next fire: ${formatTime(rule.nextFireAt)}`);
1044
+ }
1045
+ function formatTime(value) {
1046
+ return typeof value === "number" ? new Date(value).toISOString() : "none";
1047
+ }
1048
+
1021
1049
  // ../../shared/utils/timing.ts
1022
1050
  function sleep(ms) {
1023
1051
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -1351,6 +1379,28 @@ function getRawSessionEventKind(event) {
1351
1379
  return bridgeEventType ?? event.phase;
1352
1380
  }
1353
1381
  }
1382
+ function getRawSessionEventTimestamp(event) {
1383
+ if (isCanonicalRawSessionEvent(event)) {
1384
+ return Number.isFinite(event.timestampMs) && Number.isFinite(new Date(event.timestampMs).getTime()) ? new Date(event.timestampMs).toISOString() : void 0;
1385
+ }
1386
+ const dataTimestamp = event.data?.timestamp;
1387
+ if (typeof dataTimestamp === "string" && dataTimestamp.length > 0 || typeof dataTimestamp === "number") {
1388
+ const parsed = new Date(dataTimestamp);
1389
+ if (Number.isFinite(parsed.getTime())) return parsed.toISOString();
1390
+ }
1391
+ const topLevelTimestamp = event.timestamp;
1392
+ if (typeof topLevelTimestamp === "string" && topLevelTimestamp.length > 0 || typeof topLevelTimestamp === "number") {
1393
+ const parsed = new Date(topLevelTimestamp);
1394
+ if (Number.isFinite(parsed.getTime())) return parsed.toISOString();
1395
+ }
1396
+ return void 0;
1397
+ }
1398
+ function getRawSessionEventTimestampMs(event) {
1399
+ const iso = getRawSessionEventTimestamp(event);
1400
+ if (!iso) return void 0;
1401
+ const ms = Date.parse(iso);
1402
+ return Number.isFinite(ms) ? ms : void 0;
1403
+ }
1354
1404
  function getRawSessionEventData(event) {
1355
1405
  if (!isCanonicalRawSessionEvent(event)) {
1356
1406
  return isRecord(event.data) ? event.data : void 0;
@@ -1500,7 +1550,7 @@ function canAppendAcrossNonContentInterstitials(events, state, key, existingIdx)
1500
1550
  function resolvePromptId(data) {
1501
1551
  return typeof data?.promptId === "string" ? data.promptId : void 0;
1502
1552
  }
1503
- function coalesceStreamDelta(events, state, type, streamId, text, promptId) {
1553
+ function coalesceStreamDelta(events, state, type, streamId, text, promptId, timestampMs) {
1504
1554
  const key = streamableKey(type, streamId);
1505
1555
  const existingText = state.concatByStreamId.get(key) ?? "";
1506
1556
  const existingIdx = state.streamableIndexById.get(key);
@@ -1511,6 +1561,10 @@ function coalesceStreamDelta(events, state, type, streamId, text, promptId) {
1511
1561
  existing.text += text;
1512
1562
  state.concatByStreamId.set(key, existingText + text);
1513
1563
  if (!existing.promptId && promptId) existing.promptId = promptId;
1564
+ if (existing.type === "reasoning" && timestampMs !== void 0) {
1565
+ if (existing.startedAtMs === void 0) existing.startedAtMs = timestampMs;
1566
+ existing.endedAtMs = timestampMs;
1567
+ }
1514
1568
  return true;
1515
1569
  }
1516
1570
  if (existingIdx === events.length - 1 || !appendableText) return false;
@@ -1536,7 +1590,8 @@ function coalesceStreamDelta(events, state, type, streamId, text, promptId) {
1536
1590
  id: resolveSegmentId(streamId, segmentOrdinal),
1537
1591
  ...segmentOrdinal > 0 ? { streamId } : {},
1538
1592
  text,
1539
- ...promptId ? { promptId } : {}
1593
+ ...promptId ? { promptId } : {},
1594
+ ...timestampMs !== void 0 ? { startedAtMs: timestampMs, endedAtMs: timestampMs } : {}
1540
1595
  });
1541
1596
  }
1542
1597
  return true;
@@ -1810,14 +1865,15 @@ function projectPatch(data, index) {
1810
1865
  ...resolvePromptId(data) ? { promptId: resolvePromptId(data) } : {}
1811
1866
  };
1812
1867
  }
1813
- function projectStream(type, data, state) {
1868
+ function projectStream(type, data, state, timestampMs) {
1814
1869
  coalesceStreamDelta(
1815
1870
  state.merged,
1816
1871
  state.streams,
1817
1872
  type,
1818
1873
  resolveEventId(data, type, state.merged.length),
1819
1874
  resolveTextValue(data),
1820
- resolvePromptId(data)
1875
+ resolvePromptId(data),
1876
+ timestampMs
1821
1877
  );
1822
1878
  }
1823
1879
  function projectToolCall(data, state) {
@@ -1959,7 +2015,7 @@ function flattenSessionEvents(raw) {
1959
2015
  pushEvent(state, projectRawCodex(data, state.merged.length));
1960
2016
  break;
1961
2017
  case "reasoning":
1962
- projectStream("reasoning", data, state);
2018
+ projectStream("reasoning", data, state, getRawSessionEventTimestampMs(normalized.raw));
1963
2019
  break;
1964
2020
  case "text":
1965
2021
  projectStream("text", data, state);
@@ -4697,11 +4753,15 @@ Examples:
4697
4753
  `
4698
4754
  ).action((sessionId, options, command) => usageCommand(sessionId, options, command));
4699
4755
  var automations = program.command("automations").description("Automation commands");
4700
- automations.command("create").description("Create a scheduled automation").argument("<repo-url>", "Repository URL").argument("[prompt]", "Prompt to run, or '-' to read stdin").requiredOption("--cron <expr>", "Cron expression").option("--name <name>", "Automation display name").option("--prompt-stdin", "Read prompt from stdin").addHelpText(
4756
+ automations.command("create").description("Create a scheduled automation").argument("<repo-url>", "Repository URL").argument("[prompt]", "Prompt to run, or '-' to read stdin").requiredOption("--cron <expr>", "Cron expression").option("--name <name>", "Automation display name").option(
4757
+ "--model <model>",
4758
+ "Model to pin for this automation's sessions (e.g. gpt-5.5, claude-opus-4-8). Defaults to the codex backend default."
4759
+ ).option("--prompt-stdin", "Read prompt from stdin").addHelpText(
4701
4760
  "after",
4702
4761
  `
4703
4762
  Examples:
4704
4763
  arcanist automations create tryarcanist/arcanist "summarize regressions" --cron "*/15 * * * *"
4764
+ arcanist automations create tryarcanist/arcanist "audit N+1s" --cron "0 13 * * 5" --model gpt-5.5
4705
4765
  printf "summarize regressions" | arcanist automations create tryarcanist/arcanist --prompt-stdin --cron "*/15 * * * *" --json
4706
4766
  `
4707
4767
  ).action((repoUrl, prompt, options, command) => createAutomationCommand(repoUrl, prompt, options, command));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryarcanist/cli",
3
- "version": "0.1.163",
3
+ "version": "0.1.164",
4
4
  "description": "CLI for Arcanist — create and manage coding agent sessions",
5
5
  "type": "module",
6
6
  "bin": {