replicas-cli 0.2.279 → 0.2.281

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.mjs +133 -47
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -50,6 +50,9 @@ Connect to a workspace via SSH.
50
50
  ### `replicas interact`
51
51
  Launch the interactive terminal dashboard — a full TUI alternative to the web dashboard. View workspaces, chat with agents, monitor environment status, and create workspaces without leaving the terminal.
52
52
 
53
+ ### Coding agents
54
+ Use `replicas claude-auth` or `replicas codex-auth` to connect Claude Code or Codex credentials. Cursor uses a Cursor API key configured in Coding Agents settings.
55
+
53
56
  ## Configuration
54
57
 
55
58
  Create a `replicas.json` or `replicas.yaml` file in your repository root:
package/dist/index.mjs CHANGED
@@ -7559,11 +7559,33 @@ var VALID_AGENT_PROVIDERS = ["claude", "codex", "cursor", "relay"];
7559
7559
  function isValidAgentProvider(value) {
7560
7560
  return VALID_AGENT_PROVIDERS.some((p) => p === value);
7561
7561
  }
7562
+ var AGENT_PROVIDER_OPTIONS = [
7563
+ {
7564
+ value: "claude",
7565
+ label: "Claude Code",
7566
+ description: "Use Claude Code for tasks"
7567
+ },
7568
+ {
7569
+ value: "codex",
7570
+ label: "OpenAI Codex",
7571
+ description: "Use OpenAI Codex for tasks"
7572
+ },
7573
+ {
7574
+ value: "cursor",
7575
+ label: "Cursor",
7576
+ description: "Use Cursor for tasks"
7577
+ },
7578
+ {
7579
+ value: "relay",
7580
+ label: "Relay",
7581
+ description: "Orchestrating agent that delegates to Claude Code and Codex subagents"
7582
+ }
7583
+ ];
7562
7584
  var VALID_THINKING_LEVELS = ["low", "medium", "high", "max"];
7563
7585
  function isValidThinkingLevel(value) {
7564
7586
  return VALID_THINKING_LEVELS.some((l) => l === value);
7565
7587
  }
7566
- function getProviderDisplayName(provider) {
7588
+ function getProviderDisplayName(provider, variant = "short") {
7567
7589
  switch (provider) {
7568
7590
  case "codex":
7569
7591
  return "Codex";
@@ -7572,7 +7594,7 @@ function getProviderDisplayName(provider) {
7572
7594
  case "relay":
7573
7595
  return "Relay";
7574
7596
  case "claude":
7575
- return "Claude";
7597
+ return variant === "long" ? "Claude Code" : "Claude";
7576
7598
  }
7577
7599
  }
7578
7600
 
@@ -7713,9 +7735,61 @@ function parsePrUrl(url) {
7713
7735
  if (!Number.isFinite(number)) return null;
7714
7736
  return { owner, repo, number };
7715
7737
  }
7716
- function extractPrNumber(url) {
7717
- const parsed = parsePrUrl(url);
7718
- return parsed ? String(parsed.number) : null;
7738
+ function parseCodeHostPrUrl(url) {
7739
+ const github = parsePrUrl(url);
7740
+ if (github) {
7741
+ return {
7742
+ ...github,
7743
+ provider: "github",
7744
+ host: "github.com",
7745
+ repositoryPath: `${github.owner}/${github.repo}`,
7746
+ repoUrl: `https://github.com/${github.owner}/${github.repo}`
7747
+ };
7748
+ }
7749
+ let parsed;
7750
+ try {
7751
+ parsed = new URL(url);
7752
+ } catch {
7753
+ return null;
7754
+ }
7755
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
7756
+ const segments = parsed.pathname.split("/").filter(Boolean);
7757
+ const separatorIndex = segments.indexOf("-");
7758
+ if (separatorIndex <= 0 || segments[separatorIndex + 1] !== "merge_requests") return null;
7759
+ const number = Number.parseInt(segments[separatorIndex + 2] ?? "", 10);
7760
+ if (!Number.isFinite(number)) return null;
7761
+ const repositorySegments = decodePathSegments(segments.slice(0, separatorIndex));
7762
+ const repo = repositorySegments[repositorySegments.length - 1];
7763
+ const owner = repositorySegments[0];
7764
+ if (!owner || !repo) return null;
7765
+ const repositoryPath = repositorySegments.join("/");
7766
+ return {
7767
+ provider: "gitlab",
7768
+ host: parsed.host.toLowerCase(),
7769
+ owner,
7770
+ repo,
7771
+ number,
7772
+ repositoryPath,
7773
+ repoUrl: `${parsed.origin}/${repositoryPath}`
7774
+ };
7775
+ }
7776
+ function decodePathSegments(segments) {
7777
+ return segments.map((segment) => {
7778
+ try {
7779
+ return decodeURIComponent(segment);
7780
+ } catch {
7781
+ return segment;
7782
+ }
7783
+ });
7784
+ }
7785
+ function getCodeHostRequestNoun(url) {
7786
+ return parseCodeHostPrUrl(url)?.provider === "gitlab" ? "MR" : "PR";
7787
+ }
7788
+ function formatCodeHostRequestRef(url, number) {
7789
+ const parsed = parseCodeHostPrUrl(url);
7790
+ const requestNumber = number ?? parsed?.number;
7791
+ if (!requestNumber) return null;
7792
+ return `${parsed?.provider === "gitlab" ? "!" : "#"}${requestNumber}`;
7719
7793
  }
7720
7794
 
7721
7795
  // ../shared/src/default-skills/replicas-agent/abilities/computer.ts
@@ -9242,7 +9316,7 @@ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
9242
9316
  var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
9243
9317
 
9244
9318
  // ../shared/src/cli-version.ts
9245
- var CLI_VERSION = "0.2.279";
9319
+ var CLI_VERSION = "0.2.281";
9246
9320
 
9247
9321
  // ../shared/src/engine/environment.ts
9248
9322
  var DESKTOP_NOVNC_PORT = 6080;
@@ -12589,6 +12663,16 @@ Update available: ${currentVersion} \u2192 ${latestVersion}`));
12589
12663
  // src/commands/replica.ts
12590
12664
  import chalk15 from "chalk";
12591
12665
  import prompts3 from "prompts";
12666
+ var REPLICA_AGENT_PROVIDERS = VALID_AGENT_PROVIDERS.filter((provider) => provider !== "relay");
12667
+ function parseReplicaAgent(value) {
12668
+ if (!value) return void 0;
12669
+ const normalized = value.trim().toLowerCase();
12670
+ if (isValidAgentProvider(normalized) && normalized !== "relay") {
12671
+ return normalized;
12672
+ }
12673
+ console.log(chalk15.red(`Invalid coding agent: ${value}. Must be one of: ${REPLICA_AGENT_PROVIDERS.join(", ")}`));
12674
+ process.exit(1);
12675
+ }
12592
12676
  function formatDate(dateString) {
12593
12677
  return new Date(dateString).toLocaleString();
12594
12678
  }
@@ -12789,7 +12873,7 @@ async function replicaCreateCommand(name, options) {
12789
12873
  let replicaName = name;
12790
12874
  let message = options.message;
12791
12875
  let selectedEnvironmentId = options.environment?.trim();
12792
- let codingAgent = options.agent;
12876
+ let codingAgent = parseReplicaAgent(options.agent);
12793
12877
  if (replicaName && /\s/.test(replicaName)) {
12794
12878
  console.log(chalk15.red("Replica name cannot contain spaces."));
12795
12879
  process.exit(1);
@@ -12846,21 +12930,14 @@ async function replicaCreateCommand(name, options) {
12846
12930
  type: "select",
12847
12931
  name: "agent",
12848
12932
  message: "Select coding agent:",
12849
- choices: [
12850
- { title: "Claude", value: "claude" },
12851
- { title: "Codex", value: "codex" }
12852
- ],
12933
+ choices: AGENT_PROVIDER_OPTIONS.filter((option) => option.value !== "relay").map((option) => ({ title: option.label, value: option.value })),
12853
12934
  initial: 0
12854
12935
  });
12855
12936
  if (!response2.agent) {
12856
12937
  console.log(chalk15.yellow("\nCancelled."));
12857
12938
  return;
12858
12939
  }
12859
- codingAgent = response2.agent;
12860
- }
12861
- if (!codingAgent || !["claude", "codex"].includes(codingAgent)) {
12862
- console.log(chalk15.red(`Invalid coding agent: ${codingAgent}. Must be one of: claude, codex`));
12863
- process.exit(1);
12940
+ codingAgent = parseReplicaAgent(response2.agent);
12864
12941
  }
12865
12942
  const body = {
12866
12943
  name: replicaName,
@@ -12911,11 +12988,7 @@ async function replicaSendCommand(id, options) {
12911
12988
  message
12912
12989
  };
12913
12990
  if (options.agent) {
12914
- if (!["claude", "codex"].includes(options.agent)) {
12915
- console.log(chalk15.red(`Invalid coding agent: ${options.agent}. Must be one of: claude, codex`));
12916
- process.exit(1);
12917
- }
12918
- body.coding_agent = options.agent;
12991
+ body.coding_agent = parseReplicaAgent(options.agent);
12919
12992
  }
12920
12993
  const response = await orgAuthenticatedFetch(
12921
12994
  `/v1/replica/${id}/send`,
@@ -15938,11 +16011,6 @@ ${parsed.userPrompt}` });
15938
16011
 
15939
16012
  // src/interactive/components/ChatMessage.tsx
15940
16013
  import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "@opentui/react/jsx-runtime";
15941
- var AGENT_LABELS = {
15942
- claude: "Claude",
15943
- codex: "Codex",
15944
- relay: "Relay"
15945
- };
15946
16014
  function truncate4(text, maxLen) {
15947
16015
  return text.length > maxLen ? text.slice(0, maxLen - 1) + "\u2026" : text;
15948
16016
  }
@@ -16089,7 +16157,7 @@ function ChatMessage({ message, provider }) {
16089
16157
  }
16090
16158
  case "agent":
16091
16159
  return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", paddingX: 1, children: [
16092
- /* @__PURE__ */ jsx6("text", { children: /* @__PURE__ */ jsx6("span", { fg: "#3eeba3", children: /* @__PURE__ */ jsx6("strong", { children: AGENT_LABELS[provider] }) }) }),
16160
+ /* @__PURE__ */ jsx6("text", { children: /* @__PURE__ */ jsx6("span", { fg: "#3eeba3", children: /* @__PURE__ */ jsx6("strong", { children: getProviderDisplayName(provider) }) }) }),
16093
16161
  /* @__PURE__ */ jsx6(
16094
16162
  "markdown",
16095
16163
  {
@@ -16197,7 +16265,8 @@ function ChatArea({
16197
16265
  isProcessing,
16198
16266
  loading,
16199
16267
  agentAvailable,
16200
- agentLabel
16268
+ agentLabel,
16269
+ agentConnectHelp
16201
16270
  }) {
16202
16271
  const textareaRef = useRef2(null);
16203
16272
  const scrollboxRef = useRef2(null);
@@ -16349,9 +16418,8 @@ function ChatArea({
16349
16418
  ) }),
16350
16419
  !agentAvailable && /* @__PURE__ */ jsx7("box", { paddingX: 1, height: 1, children: /* @__PURE__ */ jsx7("text", { children: /* @__PURE__ */ jsxs7("span", { fg: "#d97706", children: [
16351
16420
  agentLabel,
16352
- " is not connected. Run `replicas ",
16353
- agentLabel === "Codex" ? "codex-auth" : "claude-auth",
16354
- "` to connect."
16421
+ " is not connected. ",
16422
+ agentConnectHelp
16355
16423
  ] }) }) }),
16356
16424
  /* @__PURE__ */ jsxs7(
16357
16425
  "box",
@@ -16429,9 +16497,10 @@ function getItemLabel(item) {
16429
16497
  case "preview":
16430
16498
  return `\u2197 Preview :${item.port}`;
16431
16499
  case "pr": {
16432
- const prNumber = extractPrNumber(item.url);
16433
- const suffix = prNumber ? ` #${prNumber}` : "";
16434
- return `\u2197 View PR (${item.repoName})${suffix}`;
16500
+ const noun = getCodeHostRequestNoun(item.url);
16501
+ const ref = formatCodeHostRequestRef(item.url);
16502
+ const suffix = ref ? ` ${ref}` : "";
16503
+ return `\u2197 View ${noun} (${item.repoName})${suffix}`;
16435
16504
  }
16436
16505
  case "diff":
16437
16506
  return `\u25B8 Diff +${item.added} -${item.removed}`;
@@ -16452,8 +16521,8 @@ function getItemId(item) {
16452
16521
  case "preview":
16453
16522
  return `info-preview-${item.port}`;
16454
16523
  case "pr": {
16455
- const prNumber = extractPrNumber(item.url);
16456
- return `info-pr-${item.repoName}-${prNumber ?? item.url}`;
16524
+ const parsed = parseCodeHostPrUrl(item.url);
16525
+ return `info-pr-${item.repoName}-${parsed?.number ?? item.url}`;
16457
16526
  }
16458
16527
  case "diff":
16459
16528
  return `info-diff-${item.repoName}`;
@@ -16711,7 +16780,8 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, a
16711
16780
  const env = rawEnv && agentAvailability ? {
16712
16781
  ...rawEnv,
16713
16782
  claudeAuthMethod: agentAvailability.claude.available ? rawEnv.claudeAuthMethod : "none",
16714
- codexAuthMethod: agentAvailability.codex.available ? rawEnv.codexAuthMethod : "none"
16783
+ codexAuthMethod: agentAvailability.codex.available ? rawEnv.codexAuthMethod : "none",
16784
+ cursorAuthMethod: agentAvailability.cursor.available ? rawEnv.cursorAuthMethod : "none"
16715
16785
  } : rawEnv;
16716
16786
  const dashboardItem = findItem("dashboard");
16717
16787
  const wakeItem = findItem("wake");
@@ -16772,7 +16842,7 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, a
16772
16842
  onClick: () => handleAction(wakeItem)
16773
16843
  }
16774
16844
  ),
16775
- (status.isClaudeProcessing || status.isCodexProcessing || status.isRelayProcessing) && /* @__PURE__ */ jsxs8("box", { backgroundColor: "#1a1500", paddingX: 1, marginX: 1, marginBottom: 1, children: [
16845
+ (status.isClaudeProcessing || status.isCodexProcessing || status.isCursorProcessing || status.isRelayProcessing) && /* @__PURE__ */ jsxs8("box", { backgroundColor: "#1a1500", paddingX: 1, marginX: 1, marginBottom: 1, children: [
16776
16846
  status.isClaudeProcessing && /* @__PURE__ */ jsx8("text", { children: /* @__PURE__ */ jsxs8("span", { fg: "#ffaa00", children: [
16777
16847
  "\u25C6",
16778
16848
  " Claude thinking..."
@@ -16781,6 +16851,10 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, a
16781
16851
  "\u25C6",
16782
16852
  " Codex thinking..."
16783
16853
  ] }) }),
16854
+ status.isCursorProcessing && /* @__PURE__ */ jsx8("text", { children: /* @__PURE__ */ jsxs8("span", { fg: "#ffaa00", children: [
16855
+ "\u25C6",
16856
+ " Cursor thinking..."
16857
+ ] }) }),
16784
16858
  status.isRelayProcessing && /* @__PURE__ */ jsx8("text", { children: /* @__PURE__ */ jsxs8("span", { fg: "#ffaa00", children: [
16785
16859
  "\u25C6",
16786
16860
  " Relay thinking..."
@@ -16794,6 +16868,10 @@ function WorkspaceInfo({ status, workspaceName, workspaceId, focused, loading, a
16794
16868
  /* @__PURE__ */ jsxs8("box", { flexDirection: "row", justifyContent: "space-between", paddingX: 1, backgroundColor: "#111111", children: [
16795
16869
  /* @__PURE__ */ jsx8("text", { children: /* @__PURE__ */ jsx8("span", { fg: "#cccccc", children: "Codex" }) }),
16796
16870
  /* @__PURE__ */ jsx8("text", { children: AUTH_METHOD_LABELS[env.codexAuthMethod] ? /* @__PURE__ */ jsx8("span", { fg: "#3eeba3", children: AUTH_METHOD_LABELS[env.codexAuthMethod] }) : /* @__PURE__ */ jsx8("span", { fg: "#ff4444", children: "\u2717" }) })
16871
+ ] }),
16872
+ /* @__PURE__ */ jsxs8("box", { flexDirection: "row", justifyContent: "space-between", paddingX: 1, backgroundColor: "#111111", children: [
16873
+ /* @__PURE__ */ jsx8("text", { children: /* @__PURE__ */ jsx8("span", { fg: "#cccccc", children: "Cursor" }) }),
16874
+ /* @__PURE__ */ jsx8("text", { children: AUTH_METHOD_LABELS[env.cursorAuthMethod] ? /* @__PURE__ */ jsx8("span", { fg: "#3eeba3", children: AUTH_METHOD_LABELS[env.cursorAuthMethod] }) : /* @__PURE__ */ jsx8("span", { fg: "#ff4444", children: "\u2717" }) })
16797
16875
  ] })
16798
16876
  ] }),
16799
16877
  /* @__PURE__ */ jsx8(Section, { title: "View", children: (() => {
@@ -17031,6 +17109,12 @@ var authValue = {
17031
17109
  monolithUrl: MONOLITH_URL5,
17032
17110
  queryClient
17033
17111
  };
17112
+ function getAgentConnectHelp(provider) {
17113
+ if (provider === "codex") return "Run `replicas codex-auth` to connect.";
17114
+ if (provider === "cursor") return "Add a Cursor API key in Coding Agents settings.";
17115
+ if (provider === "relay") return "Configure Relay in Coding Agents settings.";
17116
+ return "Run `replicas claude-auth` to connect.";
17117
+ }
17034
17118
  function App() {
17035
17119
  return /* @__PURE__ */ jsx11(ReplicasAuthProvider, { value: authValue, children: /* @__PURE__ */ jsxs9(ToastProvider, { children: [
17036
17120
  /* @__PURE__ */ jsx11(AppInner, {}),
@@ -17116,8 +17200,9 @@ function AppInner() {
17116
17200
  const selectedChat = chats.find((c) => c.id === resolvedChatId) ?? null;
17117
17201
  const isProcessing = mockThinking || (selectedChat?.processing ?? false);
17118
17202
  const selectedAgent = selectedChat?.provider ?? "claude";
17119
- const agentAvailable = agentAvailability ? selectedAgent === "codex" ? agentAvailability.codex.available : agentAvailability.claude.available : true;
17120
- const agentLabel = selectedAgent === "codex" ? "Codex" : "Claude Code";
17203
+ const agentAvailable = agentAvailability ? selectedAgent === "codex" ? agentAvailability.codex.available : selectedAgent === "cursor" ? agentAvailability.cursor.available : selectedAgent === "relay" ? agentAvailability.relay.available : agentAvailability.claude.available : true;
17204
+ const agentLabel = getProviderDisplayName(selectedAgent, "long");
17205
+ const agentConnectHelp = getAgentConnectHelp(selectedAgent);
17121
17206
  const displayMessages = useMemo6(() => {
17122
17207
  if (isMockSelected) return mockMessages;
17123
17208
  const rawEvents = historyData?.events ?? [];
@@ -17313,7 +17398,7 @@ function AppInner() {
17313
17398
  return;
17314
17399
  }
17315
17400
  if (!agentAvailable) {
17316
- toast.error(new Error(`${agentLabel} is not connected. Run \`replicas ${selectedAgent === "codex" ? "codex-auth" : "claude-auth"}\` to connect.`));
17401
+ toast.error(new Error(`${agentLabel} is not connected. ${agentConnectHelp}`));
17317
17402
  return;
17318
17403
  }
17319
17404
  sendMessageMutation.mutate({
@@ -17321,7 +17406,7 @@ function AppInner() {
17321
17406
  planMode: taskMode === "plan"
17322
17407
  });
17323
17408
  },
17324
- [selectedWorkspaceId, resolvedChatId, isMockSelected, sendMessageMutation, taskMode, agentAvailable, agentLabel, selectedAgent, toast.error]
17409
+ [selectedWorkspaceId, resolvedChatId, isMockSelected, sendMessageMutation, taskMode, agentAvailable, agentLabel, agentConnectHelp, toast.error]
17325
17410
  );
17326
17411
  return /* @__PURE__ */ jsxs9("box", { flexDirection: "column", width: "100%", height: "100%", backgroundColor: "#000000", children: [
17327
17412
  /* @__PURE__ */ jsxs9("box", { flexDirection: "row", flexGrow: 1, backgroundColor: "#000000", children: [
@@ -17366,7 +17451,8 @@ function AppInner() {
17366
17451
  isProcessing,
17367
17452
  loading: loadingMessages,
17368
17453
  agentAvailable,
17369
- agentLabel
17454
+ agentLabel,
17455
+ agentConnectHelp
17370
17456
  }
17371
17457
  ) : selectedWorkspaceId && statusData?.status === "sleeping" ? /* @__PURE__ */ jsxs9(
17372
17458
  "box",
@@ -18134,7 +18220,7 @@ program.command("get <id>").description("Get replica details by ID").action(asyn
18134
18220
  process.exit(1);
18135
18221
  }
18136
18222
  });
18137
- program.command("create [name]").description("Create a new replica").option("-m, --message <message>", "Initial message for the replica").option("-e, --environment <environment>", "Environment ID").option("-a, --agent <agent>", "Coding agent (claude, codex)").action(async (name, options) => {
18223
+ program.command("create [name]").description("Create a new replica").option("-m, --message <message>", "Initial message for the replica").option("-e, --environment <environment>", "Environment ID").option("-a, --agent <agent>", "Coding agent (claude, codex, cursor)").action(async (name, options) => {
18138
18224
  try {
18139
18225
  await replicaCreateCommand(name, options);
18140
18226
  } catch (error) {
@@ -18146,7 +18232,7 @@ program.command("create [name]").description("Create a new replica").option("-m,
18146
18232
  process.exit(1);
18147
18233
  }
18148
18234
  });
18149
- program.command("send <id>").description("Send a message to a replica").option("-m, --message <message>", "Message to send").option("-a, --agent <agent>", "Coding agent (claude, codex)").action(async (id, options) => {
18235
+ program.command("send <id>").description("Send a message to a replica").option("-m, --message <message>", "Message to send").option("-a, --agent <agent>", "Coding agent (claude, codex, cursor)").action(async (id, options) => {
18150
18236
  try {
18151
18237
  await replicaSendCommand(id, options);
18152
18238
  } catch (error) {
@@ -18207,7 +18293,7 @@ automation.command("get <id>").description("Get automation details by ID").actio
18207
18293
  process.exit(1);
18208
18294
  }
18209
18295
  });
18210
- 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("--plan-mode", "Run automation messages in plan mode").option("--goal-mode", "Set automation messages as Codex goals").option("--fast-mode", "Run automation messages in fast mode").option("--personal", "Create a personal automation owned by the authenticated user").option("--disabled", "Create in disabled state").action(async (name, options) => {
18296
+ 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, cursor, 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("--plan-mode", "Run automation messages in plan mode").option("--goal-mode", "Set automation messages as Codex goals").option("--fast-mode", "Run automation messages in fast mode").option("--personal", "Create a personal automation owned by the authenticated user").option("--disabled", "Create in disabled state").action(async (name, options) => {
18211
18297
  try {
18212
18298
  await automationCreateCommand(name, {
18213
18299
  ...options,
@@ -18222,7 +18308,7 @@ automation.command("create [name]").description("Create a new automation").optio
18222
18308
  process.exit(1);
18223
18309
  }
18224
18310
  });
18225
- 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)').option("--plan-mode <enabled>", "Run automation messages in plan mode (true/false)", parseBooleanOption).option("--goal-mode <enabled>", "Set automation messages as Codex goals (true/false)", parseBooleanOption).option("--fast-mode <enabled>", "Run automation messages in fast mode (true/false)", parseBooleanOption).action(async (id, options) => {
18311
+ 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, cursor, 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("--plan-mode <enabled>", "Run automation messages in plan mode (true/false)", parseBooleanOption).option("--goal-mode <enabled>", "Set automation messages as Codex goals (true/false)", parseBooleanOption).option("--fast-mode <enabled>", "Run automation messages in fast mode (true/false)", parseBooleanOption).action(async (id, options) => {
18226
18312
  try {
18227
18313
  await automationEditCommand(id, options);
18228
18314
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.279",
3
+ "version": "0.2.281",
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": {