replicas-cli 0.2.187 → 0.2.189

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 +152 -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
 
@@ -8079,6 +8099,8 @@ function getSandboxPaths(providerId) {
8079
8099
  return E2B_PATHS;
8080
8100
  }
8081
8101
  }
8102
+ var WORKSPACE_SIZES = ["small", "large"];
8103
+ var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
8082
8104
 
8083
8105
  // ../shared/src/urls.ts
8084
8106
  function getWorkspaceDashboardUrl(workspaceId, options = {}) {
@@ -9440,6 +9462,17 @@ function getInitialChatId(chats, preferredProvider = "claude") {
9440
9462
  }
9441
9463
  var CLAUDE_OPUS_1M_MODEL = "opus[1m]";
9442
9464
  var LEGACY_CLAUDE_OPUS_1M_MODEL = "opus-1m";
9465
+ function normalizeClaudeModel(model) {
9466
+ if (model === LEGACY_CLAUDE_OPUS_1M_MODEL) {
9467
+ return CLAUDE_OPUS_1M_MODEL;
9468
+ }
9469
+ return model;
9470
+ }
9471
+ var AGENT_MODELS = {
9472
+ claude: [CLAUDE_OPUS_1M_MODEL, "sonnet", "haiku"],
9473
+ 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"],
9474
+ relay: [CLAUDE_OPUS_1M_MODEL, "sonnet"]
9475
+ };
9443
9476
  var MODEL_LABELS = {
9444
9477
  sonnet: "Sonnet 4.5",
9445
9478
  opus: "Opus 4.7",
@@ -9494,6 +9527,42 @@ var AUDIT_LOG_ACTION = {
9494
9527
  };
9495
9528
  var AUDIT_LOG_ACTIONS = Object.values(AUDIT_LOG_ACTION);
9496
9529
 
9530
+ // ../shared/src/automations/agent-validation.ts
9531
+ function validateAgentSelection(body, existing) {
9532
+ const agentProvider = body.agent_provider;
9533
+ if (agentProvider !== void 0 && agentProvider !== null) {
9534
+ if (!isValidAgentProvider(agentProvider)) {
9535
+ return { ok: false, error: `Invalid agent_provider: must be one of ${VALID_AGENT_PROVIDERS.join(", ")}` };
9536
+ }
9537
+ }
9538
+ const effectiveAgent = agentProvider !== void 0 ? agentProvider : existing.agentProvider;
9539
+ const agentChanged = agentProvider !== void 0 && agentProvider !== existing.agentProvider;
9540
+ let model = body.model;
9541
+ if (agentChanged && model === void 0 && existing.model) {
9542
+ model = null;
9543
+ }
9544
+ if (model !== void 0 && model !== null) {
9545
+ if (typeof model !== "string" || model.trim().length === 0) {
9546
+ return { ok: false, error: "model must be a non-empty string" };
9547
+ }
9548
+ model = normalizeClaudeModel(model) ?? model;
9549
+ if (!effectiveAgent) {
9550
+ 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)" };
9551
+ }
9552
+ const allowed = AGENT_MODELS[effectiveAgent];
9553
+ if (!allowed.includes(model)) {
9554
+ return { ok: false, error: `Invalid model "${model}" for agent ${effectiveAgent}. Valid models: ${allowed.join(", ")}` };
9555
+ }
9556
+ }
9557
+ const thinkingLevel = body.thinking_level;
9558
+ if (thinkingLevel !== void 0 && thinkingLevel !== null) {
9559
+ if (!isValidThinkingLevel(thinkingLevel)) {
9560
+ return { ok: false, error: `Invalid thinking_level: must be one of ${VALID_THINKING_LEVELS.join(", ")}` };
9561
+ }
9562
+ }
9563
+ return { ok: true, selection: { agentProvider, model, thinkingLevel } };
9564
+ }
9565
+
9497
9566
  // ../shared/src/automations/github/index.ts
9498
9567
  var REPO_FILTER_PARAM = {
9499
9568
  id: "repository_ids",
@@ -11844,6 +11913,48 @@ Repositories (${response.repositories.length}):
11844
11913
  // src/commands/automation.ts
11845
11914
  import chalk17 from "chalk";
11846
11915
  import prompts4 from "prompts";
11916
+ function parseAgentProviderOption(value) {
11917
+ if (value === void 0) return void 0;
11918
+ const trimmed = value.trim();
11919
+ if (trimmed === "" || trimmed.toLowerCase() === "none") return null;
11920
+ const lower = trimmed.toLowerCase();
11921
+ if (!isValidAgentProvider(lower)) {
11922
+ console.log(chalk17.red(`Invalid --agent-provider: ${value}`));
11923
+ console.log(chalk17.gray(`Valid options: ${VALID_AGENT_PROVIDERS.join(", ")}, none`));
11924
+ process.exit(1);
11925
+ }
11926
+ return lower;
11927
+ }
11928
+ function parseThinkingLevelOption(value) {
11929
+ if (value === void 0) return void 0;
11930
+ const trimmed = value.trim();
11931
+ if (trimmed === "" || trimmed.toLowerCase() === "none") return null;
11932
+ const lower = trimmed.toLowerCase();
11933
+ if (!isValidThinkingLevel(lower)) {
11934
+ console.log(chalk17.red(`Invalid --thinking-level: ${value}`));
11935
+ console.log(chalk17.gray(`Valid options: ${VALID_THINKING_LEVELS.join(", ")}, none`));
11936
+ process.exit(1);
11937
+ }
11938
+ return lower;
11939
+ }
11940
+ function parseModelOption(value) {
11941
+ if (value === void 0) return void 0;
11942
+ const trimmed = value.trim();
11943
+ if (trimmed === "" || trimmed.toLowerCase() === "none") return null;
11944
+ return normalizeClaudeModel(trimmed) ?? trimmed;
11945
+ }
11946
+ function applyAgentSelection(body, existing) {
11947
+ const result = validateAgentSelection(body, existing);
11948
+ if (!result.ok) {
11949
+ console.log(chalk17.red(result.error));
11950
+ process.exit(1);
11951
+ }
11952
+ const out = {};
11953
+ if (result.selection.agentProvider !== void 0) out.agent_provider = result.selection.agentProvider;
11954
+ if (result.selection.model !== void 0) out.model = result.selection.model;
11955
+ if (result.selection.thinkingLevel !== void 0) out.thinking_level = result.selection.thinkingLevel;
11956
+ return out;
11957
+ }
11847
11958
  function formatTrigger(trigger) {
11848
11959
  if (trigger.type === "cron") {
11849
11960
  const config2 = trigger.config;
@@ -11861,6 +11972,17 @@ function truncate2(text, maxLength) {
11861
11972
  if (text.length <= maxLength) return text;
11862
11973
  return text.substring(0, maxLength) + "...";
11863
11974
  }
11975
+ function formatAgentSummary(automation2) {
11976
+ const parts = [];
11977
+ parts.push(automation2.agent_provider ? getProviderDisplayName(automation2.agent_provider) : "org default");
11978
+ if (automation2.model) {
11979
+ parts.push(MODEL_LABELS[automation2.model] ?? automation2.model);
11980
+ }
11981
+ if (automation2.thinking_level) {
11982
+ parts.push(`thinking: ${automation2.thinking_level}`);
11983
+ }
11984
+ return parts.join(" / ");
11985
+ }
11864
11986
  function resolveSelectableEnvironmentId(envInput, selectableEnvs) {
11865
11987
  const env = selectableEnvs.find((e) => e.name === envInput || e.id === envInput);
11866
11988
  if (!env) {
@@ -11889,6 +12011,9 @@ function printAutomation(automation2) {
11889
12011
  const lifecycle = automation2.workspace_lifecycle_policy === "delete_after_inactivity" ? `delete_after_inactivity (${automation2.workspace_auto_stop_minutes ?? 30}m)` : automation2.workspace_lifecycle_policy;
11890
12012
  console.log(chalk17.gray(` Lifecycle: ${lifecycle}`));
11891
12013
  }
12014
+ if (automation2.agent_provider || automation2.model || automation2.thinking_level) {
12015
+ console.log(chalk17.gray(` Agent: ${formatAgentSummary(automation2)}`));
12016
+ }
11892
12017
  console.log(chalk17.gray(` PR Follow-ups: ${automation2.config.capabilities?.pr_followups === true ? chalk17.green("managed") : "read-only"}`));
11893
12018
  console.log(chalk17.gray(` Created: ${formatDate2(automation2.created_at)}`));
11894
12019
  console.log(chalk17.gray(` Updated: ${formatDate2(automation2.updated_at)}`));
@@ -11955,6 +12080,9 @@ Automation: ${automation2.name}
11955
12080
  if (automation2.workspace_auto_stop_minutes) {
11956
12081
  console.log(chalk17.gray(` Auto-stop: ${automation2.workspace_auto_stop_minutes} minutes`));
11957
12082
  }
12083
+ console.log(chalk17.gray(` Agent: ${automation2.agent_provider ? getProviderDisplayName(automation2.agent_provider) : "organization default"}`));
12084
+ console.log(chalk17.gray(` Model: ${automation2.model ? MODEL_LABELS[automation2.model] ?? automation2.model : "agent default"}`));
12085
+ console.log(chalk17.gray(` Thinking Level: ${automation2.thinking_level ?? "agent default"}`));
11958
12086
  console.log(chalk17.gray(` PR Follow-ups: ${automation2.config.capabilities?.pr_followups === true ? "managed" : "read-only"}`));
11959
12087
  console.log(chalk17.gray(` Created: ${formatDate2(automation2.created_at)}`));
11960
12088
  console.log(chalk17.gray(` Updated: ${formatDate2(automation2.updated_at)}`));
@@ -12056,6 +12184,14 @@ async function automationCreateCommand(name, options) {
12056
12184
  process.exit(1);
12057
12185
  }
12058
12186
  }
12187
+ const agentSelection = applyAgentSelection(
12188
+ {
12189
+ agent_provider: parseAgentProviderOption(options.agentProvider),
12190
+ model: parseModelOption(options.model),
12191
+ thinking_level: parseThinkingLevelOption(options.thinkingLevel)
12192
+ },
12193
+ { agentProvider: void 0, model: void 0 }
12194
+ );
12059
12195
  try {
12060
12196
  const envResponse = await orgAuthenticatedFetch("/v1/environments");
12061
12197
  const allEnvs = envResponse.environments;
@@ -12172,7 +12308,8 @@ async function automationCreateCommand(name, options) {
12172
12308
  enabled: options.enabled !== false,
12173
12309
  config: workspaceConfigWithPrFollowups(void 0, prFollowups),
12174
12310
  ...options.lifecycle ? { workspace_lifecycle_policy: options.lifecycle } : {},
12175
- ...options.autoStopMinutes ? { workspace_auto_stop_minutes: parseInt(options.autoStopMinutes, 10) } : {}
12311
+ ...options.autoStopMinutes ? { workspace_auto_stop_minutes: parseInt(options.autoStopMinutes, 10) } : {},
12312
+ ...agentSelection
12176
12313
  };
12177
12314
  console.log(chalk17.gray("\nCreating automation..."));
12178
12315
  const response = await orgAuthenticatedFetch("/v1/automations", {
@@ -12215,10 +12352,19 @@ async function automationEditCommand(id, options) {
12215
12352
  process.exit(1);
12216
12353
  }
12217
12354
  }
12355
+ const parsedAgent = {
12356
+ agent_provider: parseAgentProviderOption(options.agentProvider),
12357
+ model: parseModelOption(options.model),
12358
+ thinking_level: parseThinkingLevelOption(options.thinkingLevel)
12359
+ };
12218
12360
  try {
12219
12361
  const existing = await orgAuthenticatedFetch(`/v1/automations/${id}`);
12362
+ const agentSelection = applyAgentSelection(parsedAgent, {
12363
+ agentProvider: existing.automation.agent_provider,
12364
+ model: existing.automation.model
12365
+ });
12220
12366
  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;
12367
+ 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
12368
  if (!hasOptions) {
12223
12369
  const nameResponse = await prompts4({
12224
12370
  type: "text",
@@ -12329,6 +12475,7 @@ async function automationEditCommand(id, options) {
12329
12475
  if (options.autoStopMinutes) {
12330
12476
  body.workspace_auto_stop_minutes = parseInt(options.autoStopMinutes, 10);
12331
12477
  }
12478
+ Object.assign(body, agentSelection);
12332
12479
  }
12333
12480
  if (Object.keys(body).length === 0) {
12334
12481
  console.log(chalk17.yellow("\nNo changes made.\n"));
@@ -16430,7 +16577,7 @@ Deleted file ${pathOrId}.
16430
16577
  }
16431
16578
 
16432
16579
  // src/index.ts
16433
- var CLI_VERSION = "0.2.187";
16580
+ var CLI_VERSION = "0.2.189";
16434
16581
  function parseBooleanOption(value) {
16435
16582
  if (value === "true") return true;
16436
16583
  if (value === "false") return false;
@@ -16693,7 +16840,7 @@ automation.command("get <id>").description("Get automation details by ID").actio
16693
16840
  process.exit(1);
16694
16841
  }
16695
16842
  });
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) => {
16843
+ 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
16844
  try {
16698
16845
  await automationCreateCommand(name, {
16699
16846
  ...options,
@@ -16708,7 +16855,7 @@ automation.command("create [name]").description("Create a new automation").optio
16708
16855
  process.exit(1);
16709
16856
  }
16710
16857
  });
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) => {
16858
+ 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
16859
  try {
16713
16860
  await automationEditCommand(id, options);
16714
16861
  } 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.189",
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": {