replicas-cli 0.2.740 → 0.2.742

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.cjs +253 -72
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -999,14 +999,14 @@ var require_foldFlowLines = __commonJS({
999
999
  var FOLD_FLOW = "flow";
1000
1000
  var FOLD_BLOCK = "block";
1001
1001
  var FOLD_QUOTED = "quoted";
1002
- function foldFlowLines(text, indent, mode = "flow", { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) {
1002
+ function foldFlowLines(text2, indent, mode = "flow", { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) {
1003
1003
  if (!lineWidth || lineWidth < 0)
1004
- return text;
1004
+ return text2;
1005
1005
  if (lineWidth < minContentWidth)
1006
1006
  minContentWidth = 0;
1007
1007
  const endStep = Math.max(1 + minContentWidth, 1 + lineWidth - indent.length);
1008
- if (text.length <= endStep)
1009
- return text;
1008
+ if (text2.length <= endStep)
1009
+ return text2;
1010
1010
  const folds = [];
1011
1011
  const escapedFolds = {};
1012
1012
  let end = lineWidth - indent.length;
@@ -1023,14 +1023,14 @@ var require_foldFlowLines = __commonJS({
1023
1023
  let escStart = -1;
1024
1024
  let escEnd = -1;
1025
1025
  if (mode === FOLD_BLOCK) {
1026
- i = consumeMoreIndentedLines(text, i, indent.length);
1026
+ i = consumeMoreIndentedLines(text2, i, indent.length);
1027
1027
  if (i !== -1)
1028
1028
  end = i + endStep;
1029
1029
  }
1030
- for (let ch; ch = text[i += 1]; ) {
1030
+ for (let ch; ch = text2[i += 1]; ) {
1031
1031
  if (mode === FOLD_QUOTED && ch === "\\") {
1032
1032
  escStart = i;
1033
- switch (text[i + 1]) {
1033
+ switch (text2[i + 1]) {
1034
1034
  case "x":
1035
1035
  i += 3;
1036
1036
  break;
@@ -1047,12 +1047,12 @@ var require_foldFlowLines = __commonJS({
1047
1047
  }
1048
1048
  if (ch === "\n") {
1049
1049
  if (mode === FOLD_BLOCK)
1050
- i = consumeMoreIndentedLines(text, i, indent.length);
1050
+ i = consumeMoreIndentedLines(text2, i, indent.length);
1051
1051
  end = i + indent.length + endStep;
1052
1052
  split = void 0;
1053
1053
  } else {
1054
1054
  if (ch === " " && prev && prev !== " " && prev !== "\n" && prev !== " ") {
1055
- const next = text[i + 1];
1055
+ const next = text2[i + 1];
1056
1056
  if (next && next !== " " && next !== "\n" && next !== " ")
1057
1057
  split = i;
1058
1058
  }
@@ -1064,12 +1064,12 @@ var require_foldFlowLines = __commonJS({
1064
1064
  } else if (mode === FOLD_QUOTED) {
1065
1065
  while (prev === " " || prev === " ") {
1066
1066
  prev = ch;
1067
- ch = text[i += 1];
1067
+ ch = text2[i += 1];
1068
1068
  overflow = true;
1069
1069
  }
1070
1070
  const j = i > escEnd + 1 ? i - 2 : escStart - 1;
1071
1071
  if (escapedFolds[j])
1072
- return text;
1072
+ return text2;
1073
1073
  folds.push(j);
1074
1074
  escapedFolds[j] = true;
1075
1075
  end = j + endStep;
@@ -1084,39 +1084,39 @@ var require_foldFlowLines = __commonJS({
1084
1084
  if (overflow && onOverflow)
1085
1085
  onOverflow();
1086
1086
  if (folds.length === 0)
1087
- return text;
1087
+ return text2;
1088
1088
  if (onFold)
1089
1089
  onFold();
1090
- let res = text.slice(0, folds[0]);
1090
+ let res = text2.slice(0, folds[0]);
1091
1091
  for (let i2 = 0; i2 < folds.length; ++i2) {
1092
1092
  const fold = folds[i2];
1093
- const end2 = folds[i2 + 1] || text.length;
1093
+ const end2 = folds[i2 + 1] || text2.length;
1094
1094
  if (fold === 0)
1095
1095
  res = `
1096
- ${indent}${text.slice(0, end2)}`;
1096
+ ${indent}${text2.slice(0, end2)}`;
1097
1097
  else {
1098
1098
  if (mode === FOLD_QUOTED && escapedFolds[fold])
1099
- res += `${text[fold]}\\`;
1099
+ res += `${text2[fold]}\\`;
1100
1100
  res += `
1101
- ${indent}${text.slice(fold + 1, end2)}`;
1101
+ ${indent}${text2.slice(fold + 1, end2)}`;
1102
1102
  }
1103
1103
  }
1104
1104
  return res;
1105
1105
  }
1106
- function consumeMoreIndentedLines(text, i, indent) {
1106
+ function consumeMoreIndentedLines(text2, i, indent) {
1107
1107
  let end = i;
1108
1108
  let start = i + 1;
1109
- let ch = text[start];
1109
+ let ch = text2[start];
1110
1110
  while (ch === " " || ch === " ") {
1111
1111
  if (i < start + indent) {
1112
- ch = text[++i];
1112
+ ch = text2[++i];
1113
1113
  } else {
1114
1114
  do {
1115
- ch = text[++i];
1115
+ ch = text2[++i];
1116
1116
  } while (ch && ch !== "\n");
1117
1117
  end = i;
1118
1118
  start = i + 1;
1119
- ch = text[start];
1119
+ ch = text2[start];
1120
1120
  }
1121
1121
  }
1122
1122
  return end;
@@ -6345,15 +6345,15 @@ var require_parser = __commonJS({
6345
6345
  var node_process = require("process");
6346
6346
  var cst = require_cst();
6347
6347
  var lexer = require_lexer();
6348
- function includesToken(list, type) {
6349
- for (let i = 0; i < list.length; ++i)
6350
- if (list[i].type === type)
6348
+ function includesToken(list2, type) {
6349
+ for (let i = 0; i < list2.length; ++i)
6350
+ if (list2[i].type === type)
6351
6351
  return true;
6352
6352
  return false;
6353
6353
  }
6354
- function findNonEmptyIndex(list) {
6355
- for (let i = 0; i < list.length; ++i) {
6356
- switch (list[i].type) {
6354
+ function findNonEmptyIndex(list2) {
6355
+ for (let i = 0; i < list2.length; ++i) {
6356
+ switch (list2[i].type) {
6357
6357
  case "space":
6358
6358
  case "comment":
6359
6359
  case "newline":
@@ -15527,8 +15527,8 @@ function ko_default() {
15527
15527
  }
15528
15528
 
15529
15529
  // ../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/locales/lt.js
15530
- var capitalizeFirstCharacter = (text) => {
15531
- return text.charAt(0).toUpperCase() + text.slice(1);
15530
+ var capitalizeFirstCharacter = (text2) => {
15531
+ return text2.charAt(0).toUpperCase() + text2.slice(1);
15532
15532
  };
15533
15533
  function getUnitTypeFromNumber(number4) {
15534
15534
  const abs = Math.abs(number4);
@@ -22877,13 +22877,13 @@ function coerceClaudePartialMessagePayload(payload) {
22877
22877
  const streamId = payload.streamId;
22878
22878
  if (typeof streamId !== "string" || !streamId) return null;
22879
22879
  const parentToolUseId = payload.parent_tool_use_id;
22880
- const text = typeof payload.text === "string" && payload.text ? payload.text : void 0;
22880
+ const text2 = typeof payload.text === "string" && payload.text ? payload.text : void 0;
22881
22881
  const thinking = typeof payload.thinking === "string" && payload.thinking ? payload.thinking : void 0;
22882
- if (!text && !thinking) return null;
22882
+ if (!text2 && !thinking) return null;
22883
22883
  return {
22884
22884
  streamId,
22885
22885
  parent_tool_use_id: typeof parentToolUseId === "string" ? parentToolUseId : null,
22886
- ...text ? { text } : {},
22886
+ ...text2 ? { text: text2 } : {},
22887
22887
  ...thinking ? { thinking } : {},
22888
22888
  status: payload.status === "completed" ? "completed" : "in_progress"
22889
22889
  };
@@ -25064,12 +25064,12 @@ var DEFAULT_DEFAULT_SKILLS = {
25064
25064
 
25065
25065
  // ../shared/src/prompts.ts
25066
25066
  var REPLICAS_INSTRUCTIONS_TAG = "replicas_instructions";
25067
- function removeTag(text, tag) {
25067
+ function removeTag(text2, tag) {
25068
25068
  const regex = new RegExp(`<${tag}>[\\s\\S]*?</${tag}>`, "g");
25069
- return text.replace(regex, "").trim();
25069
+ return text2.replace(regex, "").trim();
25070
25070
  }
25071
- function removeReplicasInstructions(text) {
25072
- return removeTag(text, REPLICAS_INSTRUCTIONS_TAG);
25071
+ function removeReplicasInstructions(text2) {
25072
+ return removeTag(text2, REPLICAS_INSTRUCTIONS_TAG);
25073
25073
  }
25074
25074
 
25075
25075
  // ../shared/src/user-message-matching.ts
@@ -25122,7 +25122,7 @@ function messagesForCodexTurn(turn) {
25122
25122
  return [{
25123
25123
  type: "reasoning",
25124
25124
  id: turn.id,
25125
- text: reasoning.map(({ text }) => text.trim()).join("\n\n"),
25125
+ text: reasoning.map(({ text: text2 }) => text2.trim()).join("\n\n"),
25126
25126
  timestamp: reasoning[0].timestamp,
25127
25127
  status: reasoning.at(-1)?.status ?? "completed"
25128
25128
  }];
@@ -25598,8 +25598,8 @@ function getCursorAssistantText(event) {
25598
25598
  return getTextContent(message?.content);
25599
25599
  }
25600
25600
  function getCursorThinkingText(event) {
25601
- const text = event.payload.text;
25602
- if (typeof text === "string") return text;
25601
+ const text2 = event.payload.text;
25602
+ if (typeof text2 === "string") return text2;
25603
25603
  const message = isRecord(event.payload.message) ? event.payload.message : null;
25604
25604
  return typeof message?.text === "string" ? message.text : "";
25605
25605
  }
@@ -25650,8 +25650,8 @@ function parseCursorEvents(events) {
25650
25650
  continue;
25651
25651
  }
25652
25652
  if (event.type === "cursor-assistant") {
25653
- const text = getCursorAssistantText(event);
25654
- if (text) {
25653
+ const text2 = getCursorAssistantText(event);
25654
+ if (text2) {
25655
25655
  const runId = cursorRunId(event);
25656
25656
  if (!activeAssistant || activeAssistant.runId !== runId) {
25657
25657
  const segment = runAssistantSegments.get(runId) ?? 0;
@@ -25670,15 +25670,15 @@ function parseCursorEvents(events) {
25670
25670
  if (message?.type === "agent") {
25671
25671
  messages[activeAssistant.index] = {
25672
25672
  ...message,
25673
- content: `${message.content}${text}`
25673
+ content: `${message.content}${text2}`
25674
25674
  };
25675
25675
  }
25676
25676
  }
25677
25677
  continue;
25678
25678
  }
25679
25679
  if (event.type === "cursor-thinking") {
25680
- const text = getCursorThinkingText(event);
25681
- if (text.trim()) {
25680
+ const text2 = getCursorThinkingText(event);
25681
+ if (text2.trim()) {
25682
25682
  const runId = cursorRunId(event);
25683
25683
  if (!activeThinking || activeThinking.runId !== runId) {
25684
25684
  const segment = runThinkingSegments.get(runId) ?? 0;
@@ -25698,7 +25698,7 @@ function parseCursorEvents(events) {
25698
25698
  if (message?.type === "reasoning") {
25699
25699
  messages[activeThinking.index] = {
25700
25700
  ...message,
25701
- content: `${message.content}${text}`,
25701
+ content: `${message.content}${text2}`,
25702
25702
  status: "in_progress"
25703
25703
  };
25704
25704
  }
@@ -25730,12 +25730,12 @@ function parseCursorEvents(events) {
25730
25730
  }
25731
25731
  if (event.type === "cursor-task") {
25732
25732
  activeAssistant = null;
25733
- const text = event.payload.text;
25734
- if (typeof text === "string" && text.trim()) {
25733
+ const text2 = event.payload.text;
25734
+ if (typeof text2 === "string" && text2.trim()) {
25735
25735
  messages.push({
25736
25736
  id: `cursor-task-${event.timestamp}-${messages.length}`,
25737
25737
  type: "agent",
25738
- content: text,
25738
+ content: text2,
25739
25739
  timestamp: event.timestamp
25740
25740
  });
25741
25741
  }
@@ -25790,8 +25790,8 @@ var TRANSIENT_NETWORK_ERROR_PATTERNS = [
25790
25790
  ];
25791
25791
  var HTTP_CONTEXT_PATTERN = /(api error|request|response|status|http)/;
25792
25792
  var HTTP_STATUS_PATTERN = /(^|[^0-9])([1-5][0-9]{2})(?=$|[^0-9])/g;
25793
- function isTransientErrorText(text, options = {}) {
25794
- const normalized = text.toLowerCase();
25793
+ function isTransientErrorText(text2, options = {}) {
25794
+ const normalized = text2.toLowerCase();
25795
25795
  if (!normalized) return false;
25796
25796
  if (TRANSIENT_NETWORK_ERROR_PATTERNS.some((pattern) => pattern.test(normalized))) return true;
25797
25797
  if (options.includeRateLimit && /rate limit/.test(normalized)) return true;
@@ -25914,24 +25914,24 @@ function parseOpencodeEvents(events) {
25914
25914
  const time3 = isRecord(part.time) ? part.time : null;
25915
25915
  const timestamp = timestampFromMs(time3?.start, event.timestamp);
25916
25916
  if (part.type === "text") {
25917
- const text = typeof part.text === "string" ? part.text : "";
25918
- if (text.trim()) {
25917
+ const text2 = typeof part.text === "string" ? part.text : "";
25918
+ if (text2.trim()) {
25919
25919
  upsertDisplayMessage(messages, {
25920
25920
  id,
25921
25921
  type: "agent",
25922
- content: text,
25922
+ content: text2,
25923
25923
  timestamp
25924
25924
  });
25925
25925
  }
25926
25926
  continue;
25927
25927
  }
25928
25928
  if (part.type === "reasoning") {
25929
- const text = typeof part.text === "string" ? part.text : "";
25930
- if (text.trim()) {
25929
+ const text2 = typeof part.text === "string" ? part.text : "";
25930
+ if (text2.trim()) {
25931
25931
  upsertDisplayMessage(messages, {
25932
25932
  id,
25933
25933
  type: "reasoning",
25934
- content: text,
25934
+ content: text2,
25935
25935
  status: time3?.end ? "completed" : "in_progress",
25936
25936
  timestamp
25937
25937
  });
@@ -26090,7 +26090,7 @@ function assistantErrorMessage(value) {
26090
26090
  }
26091
26091
  function parsePiEvents(events) {
26092
26092
  const messages = [];
26093
- const text = /* @__PURE__ */ new Map();
26093
+ const text2 = /* @__PURE__ */ new Map();
26094
26094
  const thinking = /* @__PURE__ */ new Map();
26095
26095
  let activeMessageId = "assistant";
26096
26096
  for (const event of events) {
@@ -26121,9 +26121,9 @@ function parsePiEvents(events) {
26121
26121
  if (event.type === "pi-message_update") {
26122
26122
  const payload = nestedPayload(event);
26123
26123
  const id = typeof payload.id === "string" ? payload.id : activeMessageId;
26124
- if (payload.type === "text_delta" && typeof payload.delta === "string") text.set(id, `${text.get(id) ?? ""}${payload.delta}`);
26124
+ if (payload.type === "text_delta" && typeof payload.delta === "string") text2.set(id, `${text2.get(id) ?? ""}${payload.delta}`);
26125
26125
  if (payload.type === "thinking_delta" && typeof payload.delta === "string") thinking.set(id, `${thinking.get(id) ?? ""}${payload.delta}`);
26126
- const textContent = text.get(id);
26126
+ const textContent = text2.get(id);
26127
26127
  const thinkingContent = thinking.get(id);
26128
26128
  if (textContent !== void 0) upsertDisplayMessage(messages, { id: `pi-${id}`, type: "agent", content: textContent, timestamp: event.timestamp });
26129
26129
  if (thinkingContent !== void 0) upsertDisplayMessage(messages, { id: `pi-thinking-${id}`, type: "reasoning", content: thinkingContent, status: "in_progress", timestamp: event.timestamp });
@@ -27077,6 +27077,9 @@ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
27077
27077
  // ../shared/src/replicas-config.ts
27078
27078
  var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
27079
27079
 
27080
+ // ../shared/src/uuid.ts
27081
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
27082
+
27080
27083
  // ../shared/src/terminal.ts
27081
27084
  var CONTROL_CHARACTERS = /[\u0000-\u001F\u007F-\u009F]/g;
27082
27085
  function sanitizeTerminalLine(value) {
@@ -27126,7 +27129,7 @@ var headlessFilesystemAgentResultSchema = external_exports.object({
27126
27129
  });
27127
27130
 
27128
27131
  // ../shared/src/cli-version.ts
27129
- var CLI_VERSION = "0.2.740";
27132
+ var CLI_VERSION = "0.2.742";
27130
27133
 
27131
27134
  // ../shared/src/version.ts
27132
27135
  function compareVersions(v1, v2) {
@@ -27837,6 +27840,185 @@ function identityTokenUrl() {
27837
27840
  return `http://127.0.0.1:${IDENTITY_PROXY_PORT}${IDENTITY_TOKEN_PATH}`;
27838
27841
  }
27839
27842
 
27843
+ // ../shared/src/routes/environment-setups.ts
27844
+ var ENVIRONMENT_SETUP_STEPS = [
27845
+ { key: "understand", label: "Understand the codebase" },
27846
+ { key: "install", label: "Install dependencies and run the app" },
27847
+ { key: "verify", label: "Verify checks and record a walkthrough" },
27848
+ { key: "configure", label: "Draft hooks, system prompt, and automations" },
27849
+ { key: "propose", label: "Propose the configuration for review" }
27850
+ ];
27851
+ var ENVIRONMENT_SETUP_STEP_STATUSES = ["pending", "in_progress", "completed", "skipped"];
27852
+ var ENVIRONMENT_SETUP_RUN_STATUSES = ["running", "proposed", "applied", "failed", "cancelled"];
27853
+ var ENVIRONMENT_SETUP_AUTOMATION_ACTIONS = ["create", "update", "keep", "disable"];
27854
+ var ENVIRONMENT_SETUP_VERIFICATION_STATUSES = ["passed", "failed", "skipped"];
27855
+ var ENVIRONMENT_SETUP_LIMITS = {
27856
+ summaryChars: 600,
27857
+ stackItems: 30,
27858
+ nameChars: 120,
27859
+ descriptionChars: 1e3,
27860
+ systemPromptChars: 2e4,
27861
+ hookChars: 5e4,
27862
+ variables: 50,
27863
+ variableKeyChars: 128,
27864
+ variableDescriptionChars: 500,
27865
+ automations: 8,
27866
+ automationKeyChars: 80,
27867
+ automationPromptChars: 1e4,
27868
+ automationTriggers: 5,
27869
+ automationNoteChars: 300,
27870
+ verificationItems: 8,
27871
+ verificationDetailChars: 300,
27872
+ mediaItems: 8
27873
+ };
27874
+ var ENVIRONMENT_SETUP_VARIABLE_WAIT = { defaultMs: 5 * 6e4, maxMs: 15 * 6e4, pollMs: 5e3 };
27875
+ var VARIABLE_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
27876
+ var text = (max) => max === void 0 ? external_exports.string().trim() : external_exports.string().trim().max(max);
27877
+ var requiredText = (max) => text(max).min(1, "must not be empty");
27878
+ var optionalText = (max) => text(max).nullish().transform((value) => value || null);
27879
+ var clearableText = (max) => text(max).nullish().transform((value) => value === void 0 ? void 0 : value || null);
27880
+ var list = (item, max) => max === void 0 ? external_exports.array(item) : external_exports.array(item).max(max);
27881
+ var ENVIRONMENT_SETUP_AUTHORED_TRIGGER_TYPES = ["cron", "github", "gitlab"];
27882
+ function isEnvironmentSetupAuthoredTriggerType(type) {
27883
+ return ENVIRONMENT_SETUP_AUTHORED_TRIGGER_TYPES.some((authored) => authored === type);
27884
+ }
27885
+ var repositoryTriggerConfigSchema = external_exports.object({
27886
+ event: external_exports.string(),
27887
+ repository_ids: external_exports.array(external_exports.string().regex(UUID_RE, "must be a repository id")).optional(),
27888
+ group_pr_events: external_exports.boolean().optional(),
27889
+ excluded_actors: external_exports.array(external_exports.string()).optional()
27890
+ });
27891
+ var proposalTriggerSchema = external_exports.discriminatedUnion("type", [
27892
+ external_exports.object({ type: external_exports.literal("cron"), config: external_exports.object({ schedule: external_exports.string(), timezone: external_exports.string().optional() }) }),
27893
+ external_exports.object({ type: external_exports.literal("github"), config: repositoryTriggerConfigSchema }),
27894
+ external_exports.object({ type: external_exports.literal("gitlab"), config: repositoryTriggerConfigSchema })
27895
+ ]);
27896
+ var existingTriggerSchema = external_exports.custom(
27897
+ (value) => isRecord(value) && typeof value.type === "string" && isRecord(value.config),
27898
+ "must be an automation trigger"
27899
+ );
27900
+ var carriedTriggerSchema = existingTriggerSchema.refine(
27901
+ (trigger) => !isEnvironmentSetupAuthoredTriggerType(trigger.type)
27902
+ );
27903
+ function automationSchema(limits) {
27904
+ const authored = external_exports.object({
27905
+ name: text(limits.nameChars),
27906
+ description: text(limits.descriptionChars),
27907
+ prompt: text(limits.automationPromptChars),
27908
+ triggers: list(proposalTriggerSchema, limits.automationTriggers)
27909
+ });
27910
+ const updated = authored.extend({ triggers: list(external_exports.union([proposalTriggerSchema, carriedTriggerSchema]), limits.automationTriggers) });
27911
+ return external_exports.object({
27912
+ key: requiredText(limits.automationKeyChars),
27913
+ action: external_exports.enum(ENVIRONMENT_SETUP_AUTOMATION_ACTIONS).default("create"),
27914
+ automation_id: external_exports.string().regex(UUID_RE, "must be an automation id").nullable().default(null),
27915
+ name: text().default(""),
27916
+ description: optionalText().transform((value) => value ?? ""),
27917
+ prompt: text().default(""),
27918
+ triggers: list(existingTriggerSchema).default([]),
27919
+ note: optionalText(limits.automationNoteChars)
27920
+ }).superRefine((automation2, ctx) => {
27921
+ if (automation2.action === "create" && automation2.automation_id) {
27922
+ ctx.addIssue({ code: "custom", path: ["automation_id"], message: "belongs on an update, keep, or disable entry" });
27923
+ }
27924
+ if (automation2.action !== "create" && !automation2.automation_id) {
27925
+ ctx.addIssue({ code: "custom", path: ["automation_id"], message: "must be the id of an automation attached to this environment" });
27926
+ }
27927
+ if (automation2.action === "create" || automation2.action === "update") {
27928
+ if (!automation2.name) ctx.addIssue({ code: "custom", path: ["name"], message: "must not be empty" });
27929
+ if (!automation2.prompt) ctx.addIssue({ code: "custom", path: ["prompt"], message: "must not be empty" });
27930
+ if (automation2.triggers.length === 0) ctx.addIssue({ code: "custom", path: ["triggers"], message: "must not be empty" });
27931
+ }
27932
+ }).transform((automation2, ctx) => {
27933
+ if (automation2.action === "keep" || automation2.action === "disable") return automation2;
27934
+ const content = (automation2.action === "update" ? updated : authored).safeParse(automation2);
27935
+ if (content.success) return { ...automation2, ...content.data };
27936
+ for (const issue2 of content.error.issues) ctx.addIssue({ ...issue2, code: "custom" });
27937
+ return external_exports.NEVER;
27938
+ });
27939
+ }
27940
+ function automationListSchema(limits) {
27941
+ return list(automationSchema(limits)).default([]).superRefine((automations, ctx) => {
27942
+ if (new Set(automations.map((automation2) => automation2.key)).size !== automations.length) {
27943
+ ctx.addIssue({ code: "custom", message: "must have unique keys" });
27944
+ }
27945
+ const targets = automations.flatMap((automation2) => automation2.automation_id ?? []);
27946
+ if (new Set(targets).size !== targets.length) {
27947
+ ctx.addIssue({ code: "custom", message: "must mention each existing automation once" });
27948
+ }
27949
+ if (limits.automations !== void 0 && automations.filter((automation2) => automation2.action === "create").length > limits.automations) {
27950
+ ctx.addIssue({ code: "custom", message: `must create at most ${limits.automations} new automations` });
27951
+ }
27952
+ });
27953
+ }
27954
+ function environmentSchema(limits) {
27955
+ return external_exports.object({
27956
+ name: optionalText(limits.nameChars).transform((value) => value ?? void 0),
27957
+ description: clearableText(limits.descriptionChars),
27958
+ system_prompt: clearableText(limits.systemPromptChars),
27959
+ start_hook: clearableText(limits.hookChars),
27960
+ warm_hook: clearableText(limits.hookChars)
27961
+ });
27962
+ }
27963
+ function variableSchema(limits, requiredDefault) {
27964
+ return external_exports.object({
27965
+ key: external_exports.string().regex(VARIABLE_KEY_RE, "must be a valid environment variable name").max(limits.variableKeyChars ?? Number.POSITIVE_INFINITY),
27966
+ description: optionalText(limits.variableDescriptionChars).transform((value) => value ?? ""),
27967
+ required: external_exports.boolean().default(requiredDefault)
27968
+ });
27969
+ }
27970
+ function proposalSchema(limits) {
27971
+ return external_exports.object({
27972
+ summary: requiredText(limits.summaryChars),
27973
+ stack: list(text(), limits.stackItems).default([]).transform((items) => items.filter(Boolean)),
27974
+ environment: environmentSchema(limits),
27975
+ variables: list(variableSchema(limits, false), limits.variables).default([]),
27976
+ automations: automationListSchema(limits),
27977
+ verification: list(external_exports.object({
27978
+ label: requiredText(limits.nameChars),
27979
+ status: external_exports.enum(ENVIRONMENT_SETUP_VERIFICATION_STATUSES),
27980
+ detail: optionalText(limits.verificationDetailChars).transform((value) => value ?? void 0)
27981
+ }), limits.verificationItems).default([]),
27982
+ media: list(external_exports.object({
27983
+ media_id: external_exports.string().regex(UUID_RE, "must be a media id"),
27984
+ title: requiredText(limits.nameChars)
27985
+ }), limits.mediaItems).default([])
27986
+ });
27987
+ }
27988
+ var environmentSetupProposalSchema = proposalSchema({});
27989
+ var environmentSetupProposalSubmissionSchema = proposalSchema(ENVIRONMENT_SETUP_LIMITS);
27990
+ var environmentSetupVariableRequestSchema = variableSchema({}, false).extend({
27991
+ status: external_exports.enum(["pending", "provided", "skipped"]),
27992
+ requested_at: external_exports.string(),
27993
+ resolved_at: external_exports.string().nullable().default(null)
27994
+ });
27995
+ var environmentSetupRunStateSchema = external_exports.object({
27996
+ status: external_exports.enum(ENVIRONMENT_SETUP_RUN_STATUSES),
27997
+ steps: external_exports.partialRecord(external_exports.enum(ENVIRONMENT_SETUP_STEPS.map((step) => step.key)), external_exports.enum(ENVIRONMENT_SETUP_STEP_STATUSES)).default({}),
27998
+ proposal: environmentSetupProposalSchema.nullable().default(null),
27999
+ applied: external_exports.object({
28000
+ applied_at: external_exports.string(),
28001
+ automation_ids: external_exports.array(external_exports.string())
28002
+ }).nullable().default(null),
28003
+ variable_requests: external_exports.array(environmentSetupVariableRequestSchema).default([])
28004
+ });
28005
+ var applyEnvironmentSetupRequestSchema = external_exports.object({
28006
+ environment: environmentSchema(ENVIRONMENT_SETUP_LIMITS).extend({ name: requiredText(ENVIRONMENT_SETUP_LIMITS.nameChars) }),
28007
+ variables: list(external_exports.object({ key: external_exports.string().regex(VARIABLE_KEY_RE), value: external_exports.string() }), ENVIRONMENT_SETUP_LIMITS.variables).default([]).refine((variables) => new Set(variables.map((variable) => variable.key)).size === variables.length, "must have unique keys").transform((variables) => variables.filter((variable) => variable.value.length > 0)),
28008
+ automations: automationListSchema(ENVIRONMENT_SETUP_LIMITS)
28009
+ });
28010
+ var requestEnvironmentSetupVariablesSchema = external_exports.object({
28011
+ variables: list(variableSchema(ENVIRONMENT_SETUP_LIMITS, true), ENVIRONMENT_SETUP_LIMITS.variables).min(1, "must not be empty")
28012
+ }).superRefine(({ variables }, ctx) => {
28013
+ if (new Set(variables.map((variable) => variable.key)).size !== variables.length) {
28014
+ ctx.addIssue({ code: "custom", path: ["variables"], message: "must have unique keys" });
28015
+ }
28016
+ });
28017
+ var respondEnvironmentSetupVariablesSchema = external_exports.object({
28018
+ values: external_exports.record(external_exports.string().regex(VARIABLE_KEY_RE), external_exports.string()).default({}),
28019
+ skipped: external_exports.array(external_exports.string().regex(VARIABLE_KEY_RE)).default([])
28020
+ });
28021
+
27840
28022
  // src/lib/monolith-url.ts
27841
28023
  var MONOLITH_URL = process.env.REPLICAS_MONOLITH_URL || process.env.MONOLITH_URL || "https://api.replicas.dev";
27842
28024
 
@@ -28050,8 +28232,8 @@ function renderAuthFlowStep(step, total, title) {
28050
28232
  console.log(import_chalk.default.bold(`
28051
28233
  ${step}/${total} ${title}`));
28052
28234
  }
28053
- function renderAuthFlowDetail(text) {
28054
- console.log(import_chalk.default.gray(` ${text}`));
28235
+ function renderAuthFlowDetail(text2) {
28236
+ console.log(import_chalk.default.gray(` ${text2}`));
28055
28237
  }
28056
28238
  function renderAuthFlowSuccess(providerLabel, summary, target) {
28057
28239
  console.log(brand.bold(`
@@ -29354,8 +29536,8 @@ async function exchangeCodeForTokens2(code, state, expectedState, codeVerifier)
29354
29536
  body: JSON.stringify(payload)
29355
29537
  });
29356
29538
  if (!response.ok) {
29357
- const text = await response.text();
29358
- throw new Error(`Failed to exchange authorization code: ${response.status} ${text}`);
29539
+ const text2 = await response.text();
29540
+ throw new Error(`Failed to exchange authorization code: ${response.status} ${text2}`);
29359
29541
  }
29360
29542
  const data = await response.json();
29361
29543
  const now = Date.now();
@@ -29638,9 +29820,9 @@ function formatStatus(status) {
29638
29820
  if (isWorkspaceSuspendedStatus(status)) return import_chalk16.default.gray(status);
29639
29821
  return status;
29640
29822
  }
29641
- function truncate(text, maxLength) {
29642
- if (text.length <= maxLength) return text;
29643
- return text.substring(0, maxLength) + "...";
29823
+ function truncate(text2, maxLength) {
29824
+ if (text2.length <= maxLength) return text2;
29825
+ return text2.substring(0, maxLength) + "...";
29644
29826
  }
29645
29827
  function formatDisplayMessage(message) {
29646
29828
  const time3 = new Date(message.timestamp).toLocaleTimeString();
@@ -30216,9 +30398,9 @@ function resolveTriggerRepositoryIds(repositories, repoNamesInput, provider) {
30216
30398
  }
30217
30399
  return repoIds;
30218
30400
  }
30219
- function truncate2(text, maxLength) {
30220
- if (text.length <= maxLength) return text;
30221
- return text.substring(0, maxLength) + "...";
30401
+ function truncate2(text2, maxLength) {
30402
+ if (text2.length <= maxLength) return text2;
30403
+ return text2.substring(0, maxLength) + "...";
30222
30404
  }
30223
30405
  function formatAgentSummary(automation2) {
30224
30406
  const parts = [];
@@ -31602,7 +31784,6 @@ Workspace: ${workspaceNameForOutput(result.workspace_name)} (${getWorkspaceDashb
31602
31784
  var import_fs5 = __toESM(require("fs"));
31603
31785
  var import_chalk23 = __toESM(require("chalk"));
31604
31786
  var import_prompts8 = __toESM(require("prompts"));
31605
- var UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
31606
31787
  function maskValue(value) {
31607
31788
  if (value.length <= 4) return "\u2022\u2022\u2022\u2022";
31608
31789
  return `${value.slice(0, 2)}${"\u2022".repeat(Math.min(value.length - 4, 12))}${value.slice(-2)} (${value.length} chars)`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.740",
3
+ "version": "0.2.742",
4
4
  "description": "CLI for managing Replicas workspaces - SSH into cloud dev environments with automatic port forwarding",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {