@tryarcanist/cli 0.1.199 → 0.1.201
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/README.md +3 -0
- package/dist/index.js +103 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -419,12 +419,15 @@ Creates a scheduled automation for a GitHub repo. Create/delete require a write-
|
|
|
419
419
|
```bash
|
|
420
420
|
arcanist automations create your-org/your-repo "summarize new regressions" --cron "*/15 * * * *"
|
|
421
421
|
arcanist automations create your-org/your-repo "audit N+1s" --cron "0 13 * * 5" --model gpt-5.5
|
|
422
|
+
arcanist automations create your-org/your-repo "/audit-prod-docs https://docs.tryarcanist.com/" --cron "0 8 * * *" --slack-team-id T0123ABC --slack-channel-id C0456DEF
|
|
422
423
|
printf "summarize new regressions" | arcanist automations create your-org/your-repo --prompt-stdin --cron "*/15 * * * *" --json
|
|
423
424
|
arcanist automations create https://github.com/your-org/your-repo - --cron "0 14 * * 1-5" --name "Weekday summary"
|
|
424
425
|
```
|
|
425
426
|
|
|
426
427
|
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.
|
|
427
428
|
|
|
429
|
+
Use `--slack-team-id <team-id>` together with `--slack-channel-id <channel-id>` to deliver each completed automation digest into a Slack channel. Both flags are required together; the target workspace must already be connected to Arcanist and the bot must already be in the channel.
|
|
430
|
+
|
|
428
431
|
JSON mode prints the created rule. Human-readable mode prints the rule ID, repo, normalized cron, and next fire time.
|
|
429
432
|
|
|
430
433
|
### `arcanist automations list`
|
package/dist/index.js
CHANGED
|
@@ -17,31 +17,46 @@ function normalizeBaseUrl(url) {
|
|
|
17
17
|
return url.replace(/\/+$/, "");
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
// ../../shared/utils/api-error-envelope.ts
|
|
21
|
+
function parseApiErrorEnvelope(body) {
|
|
22
|
+
if (!body || typeof body !== "object") return null;
|
|
23
|
+
const record = body;
|
|
24
|
+
const topLevelCode = typeof record.code === "string" && record.code ? record.code : null;
|
|
25
|
+
const topLevelMessage = typeof record.message === "string" && record.message ? record.message : null;
|
|
26
|
+
if (typeof record.error === "string" && record.error) {
|
|
27
|
+
return {
|
|
28
|
+
code: topLevelCode ?? record.error,
|
|
29
|
+
message: topLevelMessage ?? record.error,
|
|
30
|
+
raw: record.error
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (record.error && typeof record.error === "object") {
|
|
34
|
+
const nested = record.error;
|
|
35
|
+
const code = typeof nested.code === "string" && nested.code ? nested.code : topLevelCode;
|
|
36
|
+
const message = typeof nested.message === "string" && nested.message ? nested.message : topLevelMessage;
|
|
37
|
+
return code || message ? { code, message, raw: record.error } : null;
|
|
38
|
+
}
|
|
39
|
+
return topLevelCode || topLevelMessage ? { code: topLevelCode, message: topLevelMessage, raw: body } : null;
|
|
40
|
+
}
|
|
41
|
+
|
|
20
42
|
// src/utils/api-error.ts
|
|
21
43
|
function parseApiErrorBody(body) {
|
|
22
44
|
try {
|
|
23
45
|
const parsed = JSON.parse(body);
|
|
24
46
|
if (!parsed || typeof parsed !== "object") return null;
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
if (typeof
|
|
47
|
+
const envelope = parseApiErrorEnvelope(parsed);
|
|
48
|
+
if (!envelope) return null;
|
|
49
|
+
if (typeof envelope.raw === "string" && envelope.raw) {
|
|
28
50
|
return {
|
|
29
|
-
|
|
30
|
-
rawError:
|
|
31
|
-
message:
|
|
51
|
+
...envelope.code ? { serverCode: envelope.code } : {},
|
|
52
|
+
rawError: envelope.raw,
|
|
53
|
+
...envelope.message ? { message: envelope.message } : {}
|
|
32
54
|
};
|
|
33
55
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return message || serverCode ? {
|
|
39
|
-
...message ? { message } : {},
|
|
40
|
-
...serverCode ? { serverCode } : {},
|
|
41
|
-
...serverCode ? { rawError: serverCode } : {}
|
|
42
|
-
} : null;
|
|
43
|
-
}
|
|
44
|
-
return topLevelMessage ? { message: topLevelMessage } : null;
|
|
56
|
+
return envelope.message || envelope.code ? {
|
|
57
|
+
...envelope.message ? { message: envelope.message } : {},
|
|
58
|
+
...envelope.code ? { serverCode: envelope.code, rawError: envelope.code } : {}
|
|
59
|
+
} : null;
|
|
45
60
|
} catch {
|
|
46
61
|
return null;
|
|
47
62
|
}
|
|
@@ -705,9 +720,20 @@ var MODEL_REGISTRY = [
|
|
|
705
720
|
capabilities: { codexToolSearch: true },
|
|
706
721
|
contextWindow: 105e4,
|
|
707
722
|
// Verified 2026-07-09 against OpenAI's GPT-5.6 migration guide and model
|
|
708
|
-
// catalog: the alias routes to gpt-5.6-sol and supports max effort.
|
|
723
|
+
// catalog: the alias routes to gpt-5.6-sol and supports max effort. Pricing
|
|
724
|
+
// mirrors gpt-5.6-sol since the alias resolves to it.
|
|
709
725
|
reasoning: { efforts: ["none", "low", "medium", "high", "xhigh", "max"], default: "medium" },
|
|
710
|
-
|
|
726
|
+
pricing: {
|
|
727
|
+
inputPerMillion: 5,
|
|
728
|
+
outputPerMillion: 30,
|
|
729
|
+
cacheReadPerMillion: 0.5,
|
|
730
|
+
longContext: {
|
|
731
|
+
thresholdTokens: 272e3,
|
|
732
|
+
inputPerMillion: 10,
|
|
733
|
+
outputPerMillion: 45,
|
|
734
|
+
cacheReadPerMillion: 1
|
|
735
|
+
}
|
|
736
|
+
},
|
|
711
737
|
sessionStart: { eligible: true }
|
|
712
738
|
},
|
|
713
739
|
{
|
|
@@ -718,7 +744,17 @@ var MODEL_REGISTRY = [
|
|
|
718
744
|
capabilities: { codexToolSearch: true },
|
|
719
745
|
contextWindow: 105e4,
|
|
720
746
|
reasoning: { efforts: ["none", "low", "medium", "high", "xhigh", "max"], default: "medium" },
|
|
721
|
-
|
|
747
|
+
pricing: {
|
|
748
|
+
inputPerMillion: 5,
|
|
749
|
+
outputPerMillion: 30,
|
|
750
|
+
cacheReadPerMillion: 0.5,
|
|
751
|
+
longContext: {
|
|
752
|
+
thresholdTokens: 272e3,
|
|
753
|
+
inputPerMillion: 10,
|
|
754
|
+
outputPerMillion: 45,
|
|
755
|
+
cacheReadPerMillion: 1
|
|
756
|
+
}
|
|
757
|
+
},
|
|
722
758
|
sessionStart: { eligible: true }
|
|
723
759
|
},
|
|
724
760
|
{
|
|
@@ -729,7 +765,17 @@ var MODEL_REGISTRY = [
|
|
|
729
765
|
capabilities: { codexToolSearch: true },
|
|
730
766
|
contextWindow: 105e4,
|
|
731
767
|
reasoning: { efforts: ["none", "low", "medium", "high", "xhigh", "max"], default: "medium" },
|
|
732
|
-
|
|
768
|
+
pricing: {
|
|
769
|
+
inputPerMillion: 2.5,
|
|
770
|
+
outputPerMillion: 15,
|
|
771
|
+
cacheReadPerMillion: 0.25,
|
|
772
|
+
longContext: {
|
|
773
|
+
thresholdTokens: 272e3,
|
|
774
|
+
inputPerMillion: 5,
|
|
775
|
+
outputPerMillion: 22.5,
|
|
776
|
+
cacheReadPerMillion: 0.5
|
|
777
|
+
}
|
|
778
|
+
},
|
|
733
779
|
sessionStart: { eligible: true }
|
|
734
780
|
},
|
|
735
781
|
{
|
|
@@ -740,7 +786,17 @@ var MODEL_REGISTRY = [
|
|
|
740
786
|
capabilities: { codexToolSearch: true },
|
|
741
787
|
contextWindow: 105e4,
|
|
742
788
|
reasoning: { efforts: ["none", "low", "medium", "high", "xhigh", "max"], default: "medium" },
|
|
743
|
-
|
|
789
|
+
pricing: {
|
|
790
|
+
inputPerMillion: 1,
|
|
791
|
+
outputPerMillion: 6,
|
|
792
|
+
cacheReadPerMillion: 0.1,
|
|
793
|
+
longContext: {
|
|
794
|
+
thresholdTokens: 272e3,
|
|
795
|
+
inputPerMillion: 2,
|
|
796
|
+
outputPerMillion: 9,
|
|
797
|
+
cacheReadPerMillion: 0.2
|
|
798
|
+
}
|
|
799
|
+
},
|
|
744
800
|
sessionStart: { eligible: true }
|
|
745
801
|
},
|
|
746
802
|
{
|
|
@@ -1115,6 +1171,10 @@ var AUTOMATION_ERROR_HINTS = {
|
|
|
1115
1171
|
repo_not_available: "Check that the token owner has GitHub access and Arcanist is installed for that repo.",
|
|
1116
1172
|
duplicate_rule: "An enabled automation already exists for this repo, cron, and prompt.",
|
|
1117
1173
|
invalid_skill: "Use a leading slash skill that exists in the selected repo, for example: /audit-prod-docs",
|
|
1174
|
+
invalid_slack_target: "Pass both --slack-team-id and --slack-channel-id to enable Slack delivery.",
|
|
1175
|
+
slack_workspace_not_connected: "Connect that Slack workspace to Arcanist before creating the automation.",
|
|
1176
|
+
slack_channel_unavailable: "Check the Slack channel ID and confirm the bot can see the channel.",
|
|
1177
|
+
slack_bot_not_in_channel: "Invite the Arcanist bot to the channel, then retry.",
|
|
1118
1178
|
rule_cap_reached: "Delete or disable an existing automation before creating another one. The cap is 20 enabled rules.",
|
|
1119
1179
|
installation_unresolved: "Reconnect or reinstall the GitHub integration for that repository, then retry.",
|
|
1120
1180
|
model_not_available: "That model's backend (Claude/opencode) is limited to Arcanist team businesses; use the codex default or a codex model.",
|
|
@@ -1125,6 +1185,15 @@ var MAX_ALL_PAGES = 1e3;
|
|
|
1125
1185
|
async function createAutomationCommand(repoUrl, promptArg, options, command) {
|
|
1126
1186
|
const repo = parseAutomationRepo(repoUrl);
|
|
1127
1187
|
const prompt = await resolvePromptInput(promptArg, options);
|
|
1188
|
+
const slackTeamId = options.slackTeamId?.trim();
|
|
1189
|
+
const slackChannelId = options.slackChannelId?.trim();
|
|
1190
|
+
const slackDeliveryRequested = options.slackTeamId !== void 0 || options.slackChannelId !== void 0;
|
|
1191
|
+
if (slackDeliveryRequested && (!slackTeamId || !slackChannelId)) {
|
|
1192
|
+
throw new CliError(
|
|
1193
|
+
"user",
|
|
1194
|
+
"Slack delivery requires both --slack-team-id and --slack-channel-id with non-empty values."
|
|
1195
|
+
);
|
|
1196
|
+
}
|
|
1128
1197
|
const runtime = getRuntimeOptions(command, options);
|
|
1129
1198
|
const config = requireConfig(runtime);
|
|
1130
1199
|
let normalizedModel;
|
|
@@ -1144,6 +1213,10 @@ async function createAutomationCommand(repoUrl, promptArg, options, command) {
|
|
|
1144
1213
|
};
|
|
1145
1214
|
if (options.name !== void 0) body.name = options.name;
|
|
1146
1215
|
if (options.model !== void 0) body.modelId = normalizedModel;
|
|
1216
|
+
if (slackDeliveryRequested) {
|
|
1217
|
+
body.slackTeamId = slackTeamId;
|
|
1218
|
+
body.slackChannelId = slackChannelId;
|
|
1219
|
+
}
|
|
1147
1220
|
const payload = await automationApiFetch(config, "/api/automation/schedules", {
|
|
1148
1221
|
method: "POST",
|
|
1149
1222
|
body: JSON.stringify(body)
|
|
@@ -1258,6 +1331,9 @@ function printAutomationRule(rule) {
|
|
|
1258
1331
|
console.log(`Repo: ${rule.repoOwner}/${rule.repoName}`);
|
|
1259
1332
|
console.log(`Cron: ${rule.normalizedCron}`);
|
|
1260
1333
|
if (rule.modelId) console.log(`Model: ${rule.modelId}`);
|
|
1334
|
+
if (rule.slackTeamId && rule.slackChannelId) {
|
|
1335
|
+
console.log(`Slack delivery: ${rule.slackTeamId}/${rule.slackChannelId}`);
|
|
1336
|
+
}
|
|
1261
1337
|
console.log(`Next fire: ${formatTime(rule.nextFireAt)}`);
|
|
1262
1338
|
}
|
|
1263
1339
|
function formatTime(value) {
|
|
@@ -5683,12 +5759,16 @@ var automations = program.command("automations").description("Automation command
|
|
|
5683
5759
|
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(
|
|
5684
5760
|
"--model <model>",
|
|
5685
5761
|
"Model to pin for this automation's sessions (e.g. gpt-5.5, claude-opus-4-8). Defaults to the codex backend default."
|
|
5686
|
-
).option(
|
|
5762
|
+
).option(
|
|
5763
|
+
"--slack-team-id <team-id>",
|
|
5764
|
+
"Slack workspace/team ID for final digest delivery (requires --slack-channel-id)"
|
|
5765
|
+
).option("--slack-channel-id <channel-id>", "Slack channel ID for final digest delivery (requires --slack-team-id)").option("--prompt-stdin", "Read prompt from stdin").addHelpText(
|
|
5687
5766
|
"after",
|
|
5688
5767
|
`
|
|
5689
5768
|
Examples:
|
|
5690
5769
|
arcanist automations create tryarcanist/arcanist "summarize regressions" --cron "*/15 * * * *"
|
|
5691
5770
|
arcanist automations create tryarcanist/arcanist "audit N+1s" --cron "0 13 * * 5" --model gpt-5.5
|
|
5771
|
+
arcanist automations create tryarcanist/arcanist "/audit-prod-docs https://docs.tryarcanist.com/" --cron "0 8 * * *" --slack-team-id T0123ABC --slack-channel-id C0456DEF
|
|
5692
5772
|
printf "summarize regressions" | arcanist automations create tryarcanist/arcanist --prompt-stdin --cron "*/15 * * * *" --json
|
|
5693
5773
|
`
|
|
5694
5774
|
).action((repoUrl, prompt, options, command) => createAutomationCommand(repoUrl, prompt, options, command));
|