replicas-cli 0.2.739 → 0.2.741

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 +258 -73
  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);
@@ -22527,7 +22527,11 @@ var fallbackHarnessStepSchema = external_exports.object({
22527
22527
  thinkingLevel: external_exports.enum(VALID_THINKING_LEVELS).optional()
22528
22528
  });
22529
22529
  var fallbackPlanStepSchema = external_exports.discriminatedUnion("kind", [
22530
- external_exports.object({ kind: external_exports.literal("credentials"), methods: external_exports.array(external_exports.custom(isAuthMethod)).min(1) }),
22530
+ external_exports.object({
22531
+ kind: external_exports.literal("credentials"),
22532
+ methods: external_exports.array(external_exports.custom(isAuthMethod)).min(1),
22533
+ models: external_exports.record(external_exports.string(), external_exports.string().min(1)).optional()
22534
+ }),
22531
22535
  fallbackHarnessStepSchema
22532
22536
  ]);
22533
22537
  var fallbackPlanResponseSchema = external_exports.object({ steps: external_exports.array(fallbackPlanStepSchema) });
@@ -22873,13 +22877,13 @@ function coerceClaudePartialMessagePayload(payload) {
22873
22877
  const streamId = payload.streamId;
22874
22878
  if (typeof streamId !== "string" || !streamId) return null;
22875
22879
  const parentToolUseId = payload.parent_tool_use_id;
22876
- 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;
22877
22881
  const thinking = typeof payload.thinking === "string" && payload.thinking ? payload.thinking : void 0;
22878
- if (!text && !thinking) return null;
22882
+ if (!text2 && !thinking) return null;
22879
22883
  return {
22880
22884
  streamId,
22881
22885
  parent_tool_use_id: typeof parentToolUseId === "string" ? parentToolUseId : null,
22882
- ...text ? { text } : {},
22886
+ ...text2 ? { text: text2 } : {},
22883
22887
  ...thinking ? { thinking } : {},
22884
22888
  status: payload.status === "completed" ? "completed" : "in_progress"
22885
22889
  };
@@ -25060,12 +25064,12 @@ var DEFAULT_DEFAULT_SKILLS = {
25060
25064
 
25061
25065
  // ../shared/src/prompts.ts
25062
25066
  var REPLICAS_INSTRUCTIONS_TAG = "replicas_instructions";
25063
- function removeTag(text, tag) {
25067
+ function removeTag(text2, tag) {
25064
25068
  const regex = new RegExp(`<${tag}>[\\s\\S]*?</${tag}>`, "g");
25065
- return text.replace(regex, "").trim();
25069
+ return text2.replace(regex, "").trim();
25066
25070
  }
25067
- function removeReplicasInstructions(text) {
25068
- return removeTag(text, REPLICAS_INSTRUCTIONS_TAG);
25071
+ function removeReplicasInstructions(text2) {
25072
+ return removeTag(text2, REPLICAS_INSTRUCTIONS_TAG);
25069
25073
  }
25070
25074
 
25071
25075
  // ../shared/src/user-message-matching.ts
@@ -25118,7 +25122,7 @@ function messagesForCodexTurn(turn) {
25118
25122
  return [{
25119
25123
  type: "reasoning",
25120
25124
  id: turn.id,
25121
- text: reasoning.map(({ text }) => text.trim()).join("\n\n"),
25125
+ text: reasoning.map(({ text: text2 }) => text2.trim()).join("\n\n"),
25122
25126
  timestamp: reasoning[0].timestamp,
25123
25127
  status: reasoning.at(-1)?.status ?? "completed"
25124
25128
  }];
@@ -25594,8 +25598,8 @@ function getCursorAssistantText(event) {
25594
25598
  return getTextContent(message?.content);
25595
25599
  }
25596
25600
  function getCursorThinkingText(event) {
25597
- const text = event.payload.text;
25598
- if (typeof text === "string") return text;
25601
+ const text2 = event.payload.text;
25602
+ if (typeof text2 === "string") return text2;
25599
25603
  const message = isRecord(event.payload.message) ? event.payload.message : null;
25600
25604
  return typeof message?.text === "string" ? message.text : "";
25601
25605
  }
@@ -25646,8 +25650,8 @@ function parseCursorEvents(events) {
25646
25650
  continue;
25647
25651
  }
25648
25652
  if (event.type === "cursor-assistant") {
25649
- const text = getCursorAssistantText(event);
25650
- if (text) {
25653
+ const text2 = getCursorAssistantText(event);
25654
+ if (text2) {
25651
25655
  const runId = cursorRunId(event);
25652
25656
  if (!activeAssistant || activeAssistant.runId !== runId) {
25653
25657
  const segment = runAssistantSegments.get(runId) ?? 0;
@@ -25666,15 +25670,15 @@ function parseCursorEvents(events) {
25666
25670
  if (message?.type === "agent") {
25667
25671
  messages[activeAssistant.index] = {
25668
25672
  ...message,
25669
- content: `${message.content}${text}`
25673
+ content: `${message.content}${text2}`
25670
25674
  };
25671
25675
  }
25672
25676
  }
25673
25677
  continue;
25674
25678
  }
25675
25679
  if (event.type === "cursor-thinking") {
25676
- const text = getCursorThinkingText(event);
25677
- if (text.trim()) {
25680
+ const text2 = getCursorThinkingText(event);
25681
+ if (text2.trim()) {
25678
25682
  const runId = cursorRunId(event);
25679
25683
  if (!activeThinking || activeThinking.runId !== runId) {
25680
25684
  const segment = runThinkingSegments.get(runId) ?? 0;
@@ -25694,7 +25698,7 @@ function parseCursorEvents(events) {
25694
25698
  if (message?.type === "reasoning") {
25695
25699
  messages[activeThinking.index] = {
25696
25700
  ...message,
25697
- content: `${message.content}${text}`,
25701
+ content: `${message.content}${text2}`,
25698
25702
  status: "in_progress"
25699
25703
  };
25700
25704
  }
@@ -25726,12 +25730,12 @@ function parseCursorEvents(events) {
25726
25730
  }
25727
25731
  if (event.type === "cursor-task") {
25728
25732
  activeAssistant = null;
25729
- const text = event.payload.text;
25730
- if (typeof text === "string" && text.trim()) {
25733
+ const text2 = event.payload.text;
25734
+ if (typeof text2 === "string" && text2.trim()) {
25731
25735
  messages.push({
25732
25736
  id: `cursor-task-${event.timestamp}-${messages.length}`,
25733
25737
  type: "agent",
25734
- content: text,
25738
+ content: text2,
25735
25739
  timestamp: event.timestamp
25736
25740
  });
25737
25741
  }
@@ -25786,8 +25790,8 @@ var TRANSIENT_NETWORK_ERROR_PATTERNS = [
25786
25790
  ];
25787
25791
  var HTTP_CONTEXT_PATTERN = /(api error|request|response|status|http)/;
25788
25792
  var HTTP_STATUS_PATTERN = /(^|[^0-9])([1-5][0-9]{2})(?=$|[^0-9])/g;
25789
- function isTransientErrorText(text, options = {}) {
25790
- const normalized = text.toLowerCase();
25793
+ function isTransientErrorText(text2, options = {}) {
25794
+ const normalized = text2.toLowerCase();
25791
25795
  if (!normalized) return false;
25792
25796
  if (TRANSIENT_NETWORK_ERROR_PATTERNS.some((pattern) => pattern.test(normalized))) return true;
25793
25797
  if (options.includeRateLimit && /rate limit/.test(normalized)) return true;
@@ -25910,24 +25914,24 @@ function parseOpencodeEvents(events) {
25910
25914
  const time3 = isRecord(part.time) ? part.time : null;
25911
25915
  const timestamp = timestampFromMs(time3?.start, event.timestamp);
25912
25916
  if (part.type === "text") {
25913
- const text = typeof part.text === "string" ? part.text : "";
25914
- if (text.trim()) {
25917
+ const text2 = typeof part.text === "string" ? part.text : "";
25918
+ if (text2.trim()) {
25915
25919
  upsertDisplayMessage(messages, {
25916
25920
  id,
25917
25921
  type: "agent",
25918
- content: text,
25922
+ content: text2,
25919
25923
  timestamp
25920
25924
  });
25921
25925
  }
25922
25926
  continue;
25923
25927
  }
25924
25928
  if (part.type === "reasoning") {
25925
- const text = typeof part.text === "string" ? part.text : "";
25926
- if (text.trim()) {
25929
+ const text2 = typeof part.text === "string" ? part.text : "";
25930
+ if (text2.trim()) {
25927
25931
  upsertDisplayMessage(messages, {
25928
25932
  id,
25929
25933
  type: "reasoning",
25930
- content: text,
25934
+ content: text2,
25931
25935
  status: time3?.end ? "completed" : "in_progress",
25932
25936
  timestamp
25933
25937
  });
@@ -26086,7 +26090,7 @@ function assistantErrorMessage(value) {
26086
26090
  }
26087
26091
  function parsePiEvents(events) {
26088
26092
  const messages = [];
26089
- const text = /* @__PURE__ */ new Map();
26093
+ const text2 = /* @__PURE__ */ new Map();
26090
26094
  const thinking = /* @__PURE__ */ new Map();
26091
26095
  let activeMessageId = "assistant";
26092
26096
  for (const event of events) {
@@ -26117,9 +26121,9 @@ function parsePiEvents(events) {
26117
26121
  if (event.type === "pi-message_update") {
26118
26122
  const payload = nestedPayload(event);
26119
26123
  const id = typeof payload.id === "string" ? payload.id : activeMessageId;
26120
- 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}`);
26121
26125
  if (payload.type === "thinking_delta" && typeof payload.delta === "string") thinking.set(id, `${thinking.get(id) ?? ""}${payload.delta}`);
26122
- const textContent = text.get(id);
26126
+ const textContent = text2.get(id);
26123
26127
  const thinkingContent = thinking.get(id);
26124
26128
  if (textContent !== void 0) upsertDisplayMessage(messages, { id: `pi-${id}`, type: "agent", content: textContent, timestamp: event.timestamp });
26125
26129
  if (thinkingContent !== void 0) upsertDisplayMessage(messages, { id: `pi-thinking-${id}`, type: "reasoning", content: thinkingContent, status: "in_progress", timestamp: event.timestamp });
@@ -27073,6 +27077,9 @@ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
27073
27077
  // ../shared/src/replicas-config.ts
27074
27078
  var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
27075
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
+
27076
27083
  // ../shared/src/terminal.ts
27077
27084
  var CONTROL_CHARACTERS = /[\u0000-\u001F\u007F-\u009F]/g;
27078
27085
  function sanitizeTerminalLine(value) {
@@ -27122,7 +27129,7 @@ var headlessFilesystemAgentResultSchema = external_exports.object({
27122
27129
  });
27123
27130
 
27124
27131
  // ../shared/src/cli-version.ts
27125
- var CLI_VERSION = "0.2.739";
27132
+ var CLI_VERSION = "0.2.741";
27126
27133
 
27127
27134
  // ../shared/src/version.ts
27128
27135
  function compareVersions(v1, v2) {
@@ -27833,6 +27840,185 @@ function identityTokenUrl() {
27833
27840
  return `http://127.0.0.1:${IDENTITY_PROXY_PORT}${IDENTITY_TOKEN_PATH}`;
27834
27841
  }
27835
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
+
27836
28022
  // src/lib/monolith-url.ts
27837
28023
  var MONOLITH_URL = process.env.REPLICAS_MONOLITH_URL || process.env.MONOLITH_URL || "https://api.replicas.dev";
27838
28024
 
@@ -28046,8 +28232,8 @@ function renderAuthFlowStep(step, total, title) {
28046
28232
  console.log(import_chalk.default.bold(`
28047
28233
  ${step}/${total} ${title}`));
28048
28234
  }
28049
- function renderAuthFlowDetail(text) {
28050
- console.log(import_chalk.default.gray(` ${text}`));
28235
+ function renderAuthFlowDetail(text2) {
28236
+ console.log(import_chalk.default.gray(` ${text2}`));
28051
28237
  }
28052
28238
  function renderAuthFlowSuccess(providerLabel, summary, target) {
28053
28239
  console.log(brand.bold(`
@@ -29350,8 +29536,8 @@ async function exchangeCodeForTokens2(code, state, expectedState, codeVerifier)
29350
29536
  body: JSON.stringify(payload)
29351
29537
  });
29352
29538
  if (!response.ok) {
29353
- const text = await response.text();
29354
- 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}`);
29355
29541
  }
29356
29542
  const data = await response.json();
29357
29543
  const now = Date.now();
@@ -29634,9 +29820,9 @@ function formatStatus(status) {
29634
29820
  if (isWorkspaceSuspendedStatus(status)) return import_chalk16.default.gray(status);
29635
29821
  return status;
29636
29822
  }
29637
- function truncate(text, maxLength) {
29638
- if (text.length <= maxLength) return text;
29639
- return text.substring(0, maxLength) + "...";
29823
+ function truncate(text2, maxLength) {
29824
+ if (text2.length <= maxLength) return text2;
29825
+ return text2.substring(0, maxLength) + "...";
29640
29826
  }
29641
29827
  function formatDisplayMessage(message) {
29642
29828
  const time3 = new Date(message.timestamp).toLocaleTimeString();
@@ -30212,9 +30398,9 @@ function resolveTriggerRepositoryIds(repositories, repoNamesInput, provider) {
30212
30398
  }
30213
30399
  return repoIds;
30214
30400
  }
30215
- function truncate2(text, maxLength) {
30216
- if (text.length <= maxLength) return text;
30217
- return text.substring(0, maxLength) + "...";
30401
+ function truncate2(text2, maxLength) {
30402
+ if (text2.length <= maxLength) return text2;
30403
+ return text2.substring(0, maxLength) + "...";
30218
30404
  }
30219
30405
  function formatAgentSummary(automation2) {
30220
30406
  const parts = [];
@@ -31598,7 +31784,6 @@ Workspace: ${workspaceNameForOutput(result.workspace_name)} (${getWorkspaceDashb
31598
31784
  var import_fs5 = __toESM(require("fs"));
31599
31785
  var import_chalk23 = __toESM(require("chalk"));
31600
31786
  var import_prompts8 = __toESM(require("prompts"));
31601
- 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}$/;
31602
31787
  function maskValue(value) {
31603
31788
  if (value.length <= 4) return "\u2022\u2022\u2022\u2022";
31604
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.739",
3
+ "version": "0.2.741",
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": {