replicas-cli 0.2.187 → 0.2.188

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.mjs +150 -5
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -7980,6 +7980,26 @@ Error: ${error instanceof Error ? error.message : "Unknown error"}`));
7980
7980
  import chalk6 from "chalk";
7981
7981
  import { spawn as spawn2 } from "child_process";
7982
7982
 
7983
+ // ../shared/src/agent.ts
7984
+ var VALID_AGENT_PROVIDERS = ["claude", "codex", "relay"];
7985
+ function isValidAgentProvider(value) {
7986
+ return VALID_AGENT_PROVIDERS.some((p) => p === value);
7987
+ }
7988
+ var VALID_THINKING_LEVELS = ["low", "medium", "high", "max"];
7989
+ function isValidThinkingLevel(value) {
7990
+ return VALID_THINKING_LEVELS.some((l) => l === value);
7991
+ }
7992
+ function getProviderDisplayName(provider) {
7993
+ switch (provider) {
7994
+ case "codex":
7995
+ return "Codex";
7996
+ case "relay":
7997
+ return "Relay";
7998
+ case "claude":
7999
+ return "Claude";
8000
+ }
8001
+ }
8002
+
7983
8003
  // ../shared/src/event.ts
7984
8004
  var CODEX_QUOTA_STATUS_EVENT_TYPE = "codex-quota-status";
7985
8005
 
@@ -9440,6 +9460,17 @@ function getInitialChatId(chats, preferredProvider = "claude") {
9440
9460
  }
9441
9461
  var CLAUDE_OPUS_1M_MODEL = "opus[1m]";
9442
9462
  var LEGACY_CLAUDE_OPUS_1M_MODEL = "opus-1m";
9463
+ function normalizeClaudeModel(model) {
9464
+ if (model === LEGACY_CLAUDE_OPUS_1M_MODEL) {
9465
+ return CLAUDE_OPUS_1M_MODEL;
9466
+ }
9467
+ return model;
9468
+ }
9469
+ var AGENT_MODELS = {
9470
+ claude: [CLAUDE_OPUS_1M_MODEL, "sonnet", "haiku"],
9471
+ codex: ["gpt-5.5", "gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex", "gpt-5.3-codex-spark", "gpt-5.2-codex", "gpt-5.2", "gpt-5.1-codex-max", "gpt-5.1-codex", "gpt-5.1", "gpt-5-codex", "gpt-5"],
9472
+ relay: [CLAUDE_OPUS_1M_MODEL, "sonnet"]
9473
+ };
9443
9474
  var MODEL_LABELS = {
9444
9475
  sonnet: "Sonnet 4.5",
9445
9476
  opus: "Opus 4.7",
@@ -9494,6 +9525,42 @@ var AUDIT_LOG_ACTION = {
9494
9525
  };
9495
9526
  var AUDIT_LOG_ACTIONS = Object.values(AUDIT_LOG_ACTION);
9496
9527
 
9528
+ // ../shared/src/automations/agent-validation.ts
9529
+ function validateAgentSelection(body, existing) {
9530
+ const agentProvider = body.agent_provider;
9531
+ if (agentProvider !== void 0 && agentProvider !== null) {
9532
+ if (!isValidAgentProvider(agentProvider)) {
9533
+ return { ok: false, error: `Invalid agent_provider: must be one of ${VALID_AGENT_PROVIDERS.join(", ")}` };
9534
+ }
9535
+ }
9536
+ const effectiveAgent = agentProvider !== void 0 ? agentProvider : existing.agentProvider;
9537
+ const agentChanged = agentProvider !== void 0 && agentProvider !== existing.agentProvider;
9538
+ let model = body.model;
9539
+ if (agentChanged && model === void 0 && existing.model) {
9540
+ model = null;
9541
+ }
9542
+ if (model !== void 0 && model !== null) {
9543
+ if (typeof model !== "string" || model.trim().length === 0) {
9544
+ return { ok: false, error: "model must be a non-empty string" };
9545
+ }
9546
+ model = normalizeClaudeModel(model) ?? model;
9547
+ if (!effectiveAgent) {
9548
+ return { ok: false, error: "Cannot set model without an agent_provider (the model would be applied against the org default agent and may not be valid for it)" };
9549
+ }
9550
+ const allowed = AGENT_MODELS[effectiveAgent];
9551
+ if (!allowed.includes(model)) {
9552
+ return { ok: false, error: `Invalid model "${model}" for agent ${effectiveAgent}. Valid models: ${allowed.join(", ")}` };
9553
+ }
9554
+ }
9555
+ const thinkingLevel = body.thinking_level;
9556
+ if (thinkingLevel !== void 0 && thinkingLevel !== null) {
9557
+ if (!isValidThinkingLevel(thinkingLevel)) {
9558
+ return { ok: false, error: `Invalid thinking_level: must be one of ${VALID_THINKING_LEVELS.join(", ")}` };
9559
+ }
9560
+ }
9561
+ return { ok: true, selection: { agentProvider, model, thinkingLevel } };
9562
+ }
9563
+
9497
9564
  // ../shared/src/automations/github/index.ts
9498
9565
  var REPO_FILTER_PARAM = {
9499
9566
  id: "repository_ids",
@@ -11844,6 +11911,48 @@ Repositories (${response.repositories.length}):
11844
11911
  // src/commands/automation.ts
11845
11912
  import chalk17 from "chalk";
11846
11913
  import prompts4 from "prompts";
11914
+ function parseAgentProviderOption(value) {
11915
+ if (value === void 0) return void 0;
11916
+ const trimmed = value.trim();
11917
+ if (trimmed === "" || trimmed.toLowerCase() === "none") return null;
11918
+ const lower = trimmed.toLowerCase();
11919
+ if (!isValidAgentProvider(lower)) {
11920
+ console.log(chalk17.red(`Invalid --agent-provider: ${value}`));
11921
+ console.log(chalk17.gray(`Valid options: ${VALID_AGENT_PROVIDERS.join(", ")}, none`));
11922
+ process.exit(1);
11923
+ }
11924
+ return lower;
11925
+ }
11926
+ function parseThinkingLevelOption(value) {
11927
+ if (value === void 0) return void 0;
11928
+ const trimmed = value.trim();
11929
+ if (trimmed === "" || trimmed.toLowerCase() === "none") return null;
11930
+ const lower = trimmed.toLowerCase();
11931
+ if (!isValidThinkingLevel(lower)) {
11932
+ console.log(chalk17.red(`Invalid --thinking-level: ${value}`));
11933
+ console.log(chalk17.gray(`Valid options: ${VALID_THINKING_LEVELS.join(", ")}, none`));
11934
+ process.exit(1);
11935
+ }
11936
+ return lower;
11937
+ }
11938
+ function parseModelOption(value) {
11939
+ if (value === void 0) return void 0;
11940
+ const trimmed = value.trim();
11941
+ if (trimmed === "" || trimmed.toLowerCase() === "none") return null;
11942
+ return normalizeClaudeModel(trimmed) ?? trimmed;
11943
+ }
11944
+ function applyAgentSelection(body, existing) {
11945
+ const result = validateAgentSelection(body, existing);
11946
+ if (!result.ok) {
11947
+ console.log(chalk17.red(result.error));
11948
+ process.exit(1);
11949
+ }
11950
+ const out = {};
11951
+ if (result.selection.agentProvider !== void 0) out.agent_provider = result.selection.agentProvider;
11952
+ if (result.selection.model !== void 0) out.model = result.selection.model;
11953
+ if (result.selection.thinkingLevel !== void 0) out.thinking_level = result.selection.thinkingLevel;
11954
+ return out;
11955
+ }
11847
11956
  function formatTrigger(trigger) {
11848
11957
  if (trigger.type === "cron") {
11849
11958
  const config2 = trigger.config;
@@ -11861,6 +11970,17 @@ function truncate2(text, maxLength) {
11861
11970
  if (text.length <= maxLength) return text;
11862
11971
  return text.substring(0, maxLength) + "...";
11863
11972
  }
11973
+ function formatAgentSummary(automation2) {
11974
+ const parts = [];
11975
+ parts.push(automation2.agent_provider ? getProviderDisplayName(automation2.agent_provider) : "org default");
11976
+ if (automation2.model) {
11977
+ parts.push(MODEL_LABELS[automation2.model] ?? automation2.model);
11978
+ }
11979
+ if (automation2.thinking_level) {
11980
+ parts.push(`thinking: ${automation2.thinking_level}`);
11981
+ }
11982
+ return parts.join(" / ");
11983
+ }
11864
11984
  function resolveSelectableEnvironmentId(envInput, selectableEnvs) {
11865
11985
  const env = selectableEnvs.find((e) => e.name === envInput || e.id === envInput);
11866
11986
  if (!env) {
@@ -11889,6 +12009,9 @@ function printAutomation(automation2) {
11889
12009
  const lifecycle = automation2.workspace_lifecycle_policy === "delete_after_inactivity" ? `delete_after_inactivity (${automation2.workspace_auto_stop_minutes ?? 30}m)` : automation2.workspace_lifecycle_policy;
11890
12010
  console.log(chalk17.gray(` Lifecycle: ${lifecycle}`));
11891
12011
  }
12012
+ if (automation2.agent_provider || automation2.model || automation2.thinking_level) {
12013
+ console.log(chalk17.gray(` Agent: ${formatAgentSummary(automation2)}`));
12014
+ }
11892
12015
  console.log(chalk17.gray(` PR Follow-ups: ${automation2.config.capabilities?.pr_followups === true ? chalk17.green("managed") : "read-only"}`));
11893
12016
  console.log(chalk17.gray(` Created: ${formatDate2(automation2.created_at)}`));
11894
12017
  console.log(chalk17.gray(` Updated: ${formatDate2(automation2.updated_at)}`));
@@ -11955,6 +12078,9 @@ Automation: ${automation2.name}
11955
12078
  if (automation2.workspace_auto_stop_minutes) {
11956
12079
  console.log(chalk17.gray(` Auto-stop: ${automation2.workspace_auto_stop_minutes} minutes`));
11957
12080
  }
12081
+ console.log(chalk17.gray(` Agent: ${automation2.agent_provider ? getProviderDisplayName(automation2.agent_provider) : "organization default"}`));
12082
+ console.log(chalk17.gray(` Model: ${automation2.model ? MODEL_LABELS[automation2.model] ?? automation2.model : "agent default"}`));
12083
+ console.log(chalk17.gray(` Thinking Level: ${automation2.thinking_level ?? "agent default"}`));
11958
12084
  console.log(chalk17.gray(` PR Follow-ups: ${automation2.config.capabilities?.pr_followups === true ? "managed" : "read-only"}`));
11959
12085
  console.log(chalk17.gray(` Created: ${formatDate2(automation2.created_at)}`));
11960
12086
  console.log(chalk17.gray(` Updated: ${formatDate2(automation2.updated_at)}`));
@@ -12056,6 +12182,14 @@ async function automationCreateCommand(name, options) {
12056
12182
  process.exit(1);
12057
12183
  }
12058
12184
  }
12185
+ const agentSelection = applyAgentSelection(
12186
+ {
12187
+ agent_provider: parseAgentProviderOption(options.agentProvider),
12188
+ model: parseModelOption(options.model),
12189
+ thinking_level: parseThinkingLevelOption(options.thinkingLevel)
12190
+ },
12191
+ { agentProvider: void 0, model: void 0 }
12192
+ );
12059
12193
  try {
12060
12194
  const envResponse = await orgAuthenticatedFetch("/v1/environments");
12061
12195
  const allEnvs = envResponse.environments;
@@ -12172,7 +12306,8 @@ async function automationCreateCommand(name, options) {
12172
12306
  enabled: options.enabled !== false,
12173
12307
  config: workspaceConfigWithPrFollowups(void 0, prFollowups),
12174
12308
  ...options.lifecycle ? { workspace_lifecycle_policy: options.lifecycle } : {},
12175
- ...options.autoStopMinutes ? { workspace_auto_stop_minutes: parseInt(options.autoStopMinutes, 10) } : {}
12309
+ ...options.autoStopMinutes ? { workspace_auto_stop_minutes: parseInt(options.autoStopMinutes, 10) } : {},
12310
+ ...agentSelection
12176
12311
  };
12177
12312
  console.log(chalk17.gray("\nCreating automation..."));
12178
12313
  const response = await orgAuthenticatedFetch("/v1/automations", {
@@ -12215,10 +12350,19 @@ async function automationEditCommand(id, options) {
12215
12350
  process.exit(1);
12216
12351
  }
12217
12352
  }
12353
+ const parsedAgent = {
12354
+ agent_provider: parseAgentProviderOption(options.agentProvider),
12355
+ model: parseModelOption(options.model),
12356
+ thinking_level: parseThinkingLevelOption(options.thinkingLevel)
12357
+ };
12218
12358
  try {
12219
12359
  const existing = await orgAuthenticatedFetch(`/v1/automations/${id}`);
12360
+ const agentSelection = applyAgentSelection(parsedAgent, {
12361
+ agentProvider: existing.automation.agent_provider,
12362
+ model: existing.automation.model
12363
+ });
12220
12364
  const body = {};
12221
- const hasOptions = options.name || options.prompt || options.enabled !== void 0 || options.prFollowups !== void 0 || options.triggerCron || options.triggerGithub || options.environment || options.lifecycle || options.autoStopMinutes;
12365
+ const hasOptions = options.name || options.prompt || options.enabled !== void 0 || options.prFollowups !== void 0 || options.triggerCron || options.triggerGithub || options.environment || options.lifecycle || options.autoStopMinutes || options.agentProvider !== void 0 || options.model !== void 0 || options.thinkingLevel !== void 0;
12222
12366
  if (!hasOptions) {
12223
12367
  const nameResponse = await prompts4({
12224
12368
  type: "text",
@@ -12329,6 +12473,7 @@ async function automationEditCommand(id, options) {
12329
12473
  if (options.autoStopMinutes) {
12330
12474
  body.workspace_auto_stop_minutes = parseInt(options.autoStopMinutes, 10);
12331
12475
  }
12476
+ Object.assign(body, agentSelection);
12332
12477
  }
12333
12478
  if (Object.keys(body).length === 0) {
12334
12479
  console.log(chalk17.yellow("\nNo changes made.\n"));
@@ -16430,7 +16575,7 @@ Deleted file ${pathOrId}.
16430
16575
  }
16431
16576
 
16432
16577
  // src/index.ts
16433
- var CLI_VERSION = "0.2.187";
16578
+ var CLI_VERSION = "0.2.188";
16434
16579
  function parseBooleanOption(value) {
16435
16580
  if (value === "true") return true;
16436
16581
  if (value === "false") return false;
@@ -16693,7 +16838,7 @@ automation.command("get <id>").description("Get automation details by ID").actio
16693
16838
  process.exit(1);
16694
16839
  }
16695
16840
  });
16696
- automation.command("create [name]").description("Create a new automation").option("-p, --prompt <prompt>", "Prompt for the automation").option("-e, --environment <environment>", "Environment name or ID").option("--trigger-cron <schedule>", 'Cron schedule expression (e.g. "0 9 * * 1-5")').option("--trigger-cron-timezone <timezone>", "Timezone for cron trigger (default: UTC)").option("--trigger-github <event>", 'GitHub event (e.g. "pull_request.opened")').option("--trigger-github-repos <repos>", "Comma-separated repo names to filter GitHub trigger").option("--lifecycle <policy>", "Workspace lifecycle: delete_when_done, delete_after_inactivity, default").option("--auto-stop-minutes <minutes>", "Inactivity timeout in minutes (3-1440, requires --lifecycle delete_after_inactivity)").option("--pr-followups", "Allow follow-up actions on matching PRs").option("--disabled", "Create in disabled state").action(async (name, options) => {
16841
+ automation.command("create [name]").description("Create a new automation").option("-p, --prompt <prompt>", "Prompt for the automation").option("-e, --environment <environment>", "Environment name or ID").option("--trigger-cron <schedule>", 'Cron schedule expression (e.g. "0 9 * * 1-5")').option("--trigger-cron-timezone <timezone>", "Timezone for cron trigger (default: UTC)").option("--trigger-github <event>", 'GitHub event (e.g. "pull_request.opened")').option("--trigger-github-repos <repos>", "Comma-separated repo names to filter GitHub trigger").option("--lifecycle <policy>", "Workspace lifecycle: delete_when_done, delete_after_inactivity, default").option("--auto-stop-minutes <minutes>", "Inactivity timeout in minutes (3-1440, requires --lifecycle delete_after_inactivity)").option("--pr-followups", "Allow follow-up actions on matching PRs").option("--agent-provider <provider>", 'Coding agent to use: claude, codex, relay (or "none" to inherit org default)').option("--model <model>", 'Model identifier (must be valid for --agent-provider; pass "none" to clear)').option("--thinking-level <level>", 'Thinking/reasoning level: low, medium, high, max (or "none" to clear)').option("--disabled", "Create in disabled state").action(async (name, options) => {
16697
16842
  try {
16698
16843
  await automationCreateCommand(name, {
16699
16844
  ...options,
@@ -16708,7 +16853,7 @@ automation.command("create [name]").description("Create a new automation").optio
16708
16853
  process.exit(1);
16709
16854
  }
16710
16855
  });
16711
- automation.command("edit <id>").description("Edit an existing automation").option("-n, --name <name>", "New name").option("-p, --prompt <prompt>", "New prompt").option("-e, --enabled <enabled>", "Enable or disable (true/false)").option("--trigger-cron <schedule>", "Set cron schedule (replaces existing triggers)").option("--trigger-cron-timezone <timezone>", "Timezone for cron trigger").option("--trigger-github <event>", "Set GitHub event (replaces existing triggers)").option("--trigger-github-repos <repos>", "Comma-separated repo names to filter GitHub trigger").option("--environment <environment>", "Environment name or ID").option("--lifecycle <policy>", "Workspace lifecycle: delete_when_done, delete_after_inactivity, default").option("--auto-stop-minutes <minutes>", "Inactivity timeout in minutes (3-1440, requires --lifecycle delete_after_inactivity)").option("--pr-followups <enabled>", "Allow follow-up actions on matching PRs (true/false)", parseBooleanOption).action(async (id, options) => {
16856
+ automation.command("edit <id>").description("Edit an existing automation").option("-n, --name <name>", "New name").option("-p, --prompt <prompt>", "New prompt").option("-e, --enabled <enabled>", "Enable or disable (true/false)").option("--trigger-cron <schedule>", "Set cron schedule (replaces existing triggers)").option("--trigger-cron-timezone <timezone>", "Timezone for cron trigger").option("--trigger-github <event>", "Set GitHub event (replaces existing triggers)").option("--trigger-github-repos <repos>", "Comma-separated repo names to filter GitHub trigger").option("--environment <environment>", "Environment name or ID").option("--lifecycle <policy>", "Workspace lifecycle: delete_when_done, delete_after_inactivity, default").option("--auto-stop-minutes <minutes>", "Inactivity timeout in minutes (3-1440, requires --lifecycle delete_after_inactivity)").option("--pr-followups <enabled>", "Allow follow-up actions on matching PRs (true/false)", parseBooleanOption).option("--agent-provider <provider>", 'Coding agent to use: claude, codex, relay (or "none" to inherit org default)').option("--model <model>", 'Model identifier (must be valid for --agent-provider; pass "none" to clear)').option("--thinking-level <level>", 'Thinking/reasoning level: low, medium, high, max (or "none" to clear)').action(async (id, options) => {
16712
16857
  try {
16713
16858
  await automationEditCommand(id, options);
16714
16859
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.187",
3
+ "version": "0.2.188",
4
4
  "description": "CLI for managing Replicas workspaces - SSH into cloud dev environments with automatic port forwarding",
5
5
  "main": "dist/index.mjs",
6
6
  "bin": {