replicas-cli 0.2.751 → 0.2.753

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 +1106 -596
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -111,17 +111,17 @@ var require_visit = __commonJS({
111
111
  visit.BREAK = BREAK;
112
112
  visit.SKIP = SKIP;
113
113
  visit.REMOVE = REMOVE;
114
- function visit_(key, node, visitor, path6) {
115
- const ctrl = callVisitor(key, node, visitor, path6);
114
+ function visit_(key, node, visitor, path7) {
115
+ const ctrl = callVisitor(key, node, visitor, path7);
116
116
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
117
- replaceNode(key, path6, ctrl);
118
- return visit_(key, ctrl, visitor, path6);
117
+ replaceNode(key, path7, ctrl);
118
+ return visit_(key, ctrl, visitor, path7);
119
119
  }
120
120
  if (typeof ctrl !== "symbol") {
121
121
  if (identity.isCollection(node)) {
122
- path6 = Object.freeze(path6.concat(node));
122
+ path7 = Object.freeze(path7.concat(node));
123
123
  for (let i = 0; i < node.items.length; ++i) {
124
- const ci = visit_(i, node.items[i], visitor, path6);
124
+ const ci = visit_(i, node.items[i], visitor, path7);
125
125
  if (typeof ci === "number")
126
126
  i = ci - 1;
127
127
  else if (ci === BREAK)
@@ -132,13 +132,13 @@ var require_visit = __commonJS({
132
132
  }
133
133
  }
134
134
  } else if (identity.isPair(node)) {
135
- path6 = Object.freeze(path6.concat(node));
136
- const ck = visit_("key", node.key, visitor, path6);
135
+ path7 = Object.freeze(path7.concat(node));
136
+ const ck = visit_("key", node.key, visitor, path7);
137
137
  if (ck === BREAK)
138
138
  return BREAK;
139
139
  else if (ck === REMOVE)
140
140
  node.key = null;
141
- const cv = visit_("value", node.value, visitor, path6);
141
+ const cv = visit_("value", node.value, visitor, path7);
142
142
  if (cv === BREAK)
143
143
  return BREAK;
144
144
  else if (cv === REMOVE)
@@ -159,17 +159,17 @@ var require_visit = __commonJS({
159
159
  visitAsync.BREAK = BREAK;
160
160
  visitAsync.SKIP = SKIP;
161
161
  visitAsync.REMOVE = REMOVE;
162
- async function visitAsync_(key, node, visitor, path6) {
163
- const ctrl = await callVisitor(key, node, visitor, path6);
162
+ async function visitAsync_(key, node, visitor, path7) {
163
+ const ctrl = await callVisitor(key, node, visitor, path7);
164
164
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
165
- replaceNode(key, path6, ctrl);
166
- return visitAsync_(key, ctrl, visitor, path6);
165
+ replaceNode(key, path7, ctrl);
166
+ return visitAsync_(key, ctrl, visitor, path7);
167
167
  }
168
168
  if (typeof ctrl !== "symbol") {
169
169
  if (identity.isCollection(node)) {
170
- path6 = Object.freeze(path6.concat(node));
170
+ path7 = Object.freeze(path7.concat(node));
171
171
  for (let i = 0; i < node.items.length; ++i) {
172
- const ci = await visitAsync_(i, node.items[i], visitor, path6);
172
+ const ci = await visitAsync_(i, node.items[i], visitor, path7);
173
173
  if (typeof ci === "number")
174
174
  i = ci - 1;
175
175
  else if (ci === BREAK)
@@ -180,13 +180,13 @@ var require_visit = __commonJS({
180
180
  }
181
181
  }
182
182
  } else if (identity.isPair(node)) {
183
- path6 = Object.freeze(path6.concat(node));
184
- const ck = await visitAsync_("key", node.key, visitor, path6);
183
+ path7 = Object.freeze(path7.concat(node));
184
+ const ck = await visitAsync_("key", node.key, visitor, path7);
185
185
  if (ck === BREAK)
186
186
  return BREAK;
187
187
  else if (ck === REMOVE)
188
188
  node.key = null;
189
- const cv = await visitAsync_("value", node.value, visitor, path6);
189
+ const cv = await visitAsync_("value", node.value, visitor, path7);
190
190
  if (cv === BREAK)
191
191
  return BREAK;
192
192
  else if (cv === REMOVE)
@@ -213,23 +213,23 @@ var require_visit = __commonJS({
213
213
  }
214
214
  return visitor;
215
215
  }
216
- function callVisitor(key, node, visitor, path6) {
216
+ function callVisitor(key, node, visitor, path7) {
217
217
  if (typeof visitor === "function")
218
- return visitor(key, node, path6);
218
+ return visitor(key, node, path7);
219
219
  if (identity.isMap(node))
220
- return visitor.Map?.(key, node, path6);
220
+ return visitor.Map?.(key, node, path7);
221
221
  if (identity.isSeq(node))
222
- return visitor.Seq?.(key, node, path6);
222
+ return visitor.Seq?.(key, node, path7);
223
223
  if (identity.isPair(node))
224
- return visitor.Pair?.(key, node, path6);
224
+ return visitor.Pair?.(key, node, path7);
225
225
  if (identity.isScalar(node))
226
- return visitor.Scalar?.(key, node, path6);
226
+ return visitor.Scalar?.(key, node, path7);
227
227
  if (identity.isAlias(node))
228
- return visitor.Alias?.(key, node, path6);
228
+ return visitor.Alias?.(key, node, path7);
229
229
  return void 0;
230
230
  }
231
- function replaceNode(key, path6, node) {
232
- const parent = path6[path6.length - 1];
231
+ function replaceNode(key, path7, node) {
232
+ const parent = path7[path7.length - 1];
233
233
  if (identity.isCollection(parent)) {
234
234
  parent.items[key] = node;
235
235
  } else if (identity.isPair(parent)) {
@@ -839,10 +839,10 @@ var require_Collection = __commonJS({
839
839
  var createNode = require_createNode();
840
840
  var identity = require_identity();
841
841
  var Node = require_Node();
842
- function collectionFromPath(schema, path6, value) {
842
+ function collectionFromPath(schema, path7, value) {
843
843
  let v = value;
844
- for (let i = path6.length - 1; i >= 0; --i) {
845
- const k = path6[i];
844
+ for (let i = path7.length - 1; i >= 0; --i) {
845
+ const k = path7[i];
846
846
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
847
847
  const a = [];
848
848
  a[k] = v;
@@ -861,7 +861,7 @@ var require_Collection = __commonJS({
861
861
  sourceObjects: /* @__PURE__ */ new Map()
862
862
  });
863
863
  }
864
- var isEmptyPath = (path6) => path6 == null || typeof path6 === "object" && !!path6[Symbol.iterator]().next().done;
864
+ var isEmptyPath = (path7) => path7 == null || typeof path7 === "object" && !!path7[Symbol.iterator]().next().done;
865
865
  var Collection = class extends Node.NodeBase {
866
866
  constructor(type, schema) {
867
867
  super(type);
@@ -891,11 +891,11 @@ var require_Collection = __commonJS({
891
891
  * be a Pair instance or a `{ key, value }` object, which may not have a key
892
892
  * that already exists in the map.
893
893
  */
894
- addIn(path6, value) {
895
- if (isEmptyPath(path6))
894
+ addIn(path7, value) {
895
+ if (isEmptyPath(path7))
896
896
  this.add(value);
897
897
  else {
898
- const [key, ...rest] = path6;
898
+ const [key, ...rest] = path7;
899
899
  const node = this.get(key, true);
900
900
  if (identity.isCollection(node))
901
901
  node.addIn(rest, value);
@@ -909,8 +909,8 @@ var require_Collection = __commonJS({
909
909
  * Removes a value from the collection.
910
910
  * @returns `true` if the item was found and removed.
911
911
  */
912
- deleteIn(path6) {
913
- const [key, ...rest] = path6;
912
+ deleteIn(path7) {
913
+ const [key, ...rest] = path7;
914
914
  if (rest.length === 0)
915
915
  return this.delete(key);
916
916
  const node = this.get(key, true);
@@ -924,8 +924,8 @@ var require_Collection = __commonJS({
924
924
  * scalar values from their surrounding node; to disable set `keepScalar` to
925
925
  * `true` (collections are always returned intact).
926
926
  */
927
- getIn(path6, keepScalar) {
928
- const [key, ...rest] = path6;
927
+ getIn(path7, keepScalar) {
928
+ const [key, ...rest] = path7;
929
929
  const node = this.get(key, true);
930
930
  if (rest.length === 0)
931
931
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -943,8 +943,8 @@ var require_Collection = __commonJS({
943
943
  /**
944
944
  * Checks if the collection includes a value with the key `key`.
945
945
  */
946
- hasIn(path6) {
947
- const [key, ...rest] = path6;
946
+ hasIn(path7) {
947
+ const [key, ...rest] = path7;
948
948
  if (rest.length === 0)
949
949
  return this.has(key);
950
950
  const node = this.get(key, true);
@@ -954,8 +954,8 @@ var require_Collection = __commonJS({
954
954
  * Sets a value in this collection. For `!!set`, `value` needs to be a
955
955
  * boolean to add/remove the item from the set.
956
956
  */
957
- setIn(path6, value) {
958
- const [key, ...rest] = path6;
957
+ setIn(path7, value) {
958
+ const [key, ...rest] = path7;
959
959
  if (rest.length === 0) {
960
960
  this.set(key, value);
961
961
  } else {
@@ -3470,9 +3470,9 @@ var require_Document = __commonJS({
3470
3470
  this.contents.add(value);
3471
3471
  }
3472
3472
  /** Adds a value to the document. */
3473
- addIn(path6, value) {
3473
+ addIn(path7, value) {
3474
3474
  if (assertCollection(this.contents))
3475
- this.contents.addIn(path6, value);
3475
+ this.contents.addIn(path7, value);
3476
3476
  }
3477
3477
  /**
3478
3478
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -3547,14 +3547,14 @@ var require_Document = __commonJS({
3547
3547
  * Removes a value from the document.
3548
3548
  * @returns `true` if the item was found and removed.
3549
3549
  */
3550
- deleteIn(path6) {
3551
- if (Collection.isEmptyPath(path6)) {
3550
+ deleteIn(path7) {
3551
+ if (Collection.isEmptyPath(path7)) {
3552
3552
  if (this.contents == null)
3553
3553
  return false;
3554
3554
  this.contents = null;
3555
3555
  return true;
3556
3556
  }
3557
- return assertCollection(this.contents) ? this.contents.deleteIn(path6) : false;
3557
+ return assertCollection(this.contents) ? this.contents.deleteIn(path7) : false;
3558
3558
  }
3559
3559
  /**
3560
3560
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -3569,10 +3569,10 @@ var require_Document = __commonJS({
3569
3569
  * scalar values from their surrounding node; to disable set `keepScalar` to
3570
3570
  * `true` (collections are always returned intact).
3571
3571
  */
3572
- getIn(path6, keepScalar) {
3573
- if (Collection.isEmptyPath(path6))
3572
+ getIn(path7, keepScalar) {
3573
+ if (Collection.isEmptyPath(path7))
3574
3574
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
3575
- return identity.isCollection(this.contents) ? this.contents.getIn(path6, keepScalar) : void 0;
3575
+ return identity.isCollection(this.contents) ? this.contents.getIn(path7, keepScalar) : void 0;
3576
3576
  }
3577
3577
  /**
3578
3578
  * Checks if the document includes a value with the key `key`.
@@ -3583,10 +3583,10 @@ var require_Document = __commonJS({
3583
3583
  /**
3584
3584
  * Checks if the document includes a value at `path`.
3585
3585
  */
3586
- hasIn(path6) {
3587
- if (Collection.isEmptyPath(path6))
3586
+ hasIn(path7) {
3587
+ if (Collection.isEmptyPath(path7))
3588
3588
  return this.contents !== void 0;
3589
- return identity.isCollection(this.contents) ? this.contents.hasIn(path6) : false;
3589
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path7) : false;
3590
3590
  }
3591
3591
  /**
3592
3592
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -3603,13 +3603,13 @@ var require_Document = __commonJS({
3603
3603
  * Sets a value in this document. For `!!set`, `value` needs to be a
3604
3604
  * boolean to add/remove the item from the set.
3605
3605
  */
3606
- setIn(path6, value) {
3607
- if (Collection.isEmptyPath(path6)) {
3606
+ setIn(path7, value) {
3607
+ if (Collection.isEmptyPath(path7)) {
3608
3608
  this.contents = value;
3609
3609
  } else if (this.contents == null) {
3610
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path6), value);
3610
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path7), value);
3611
3611
  } else if (assertCollection(this.contents)) {
3612
- this.contents.setIn(path6, value);
3612
+ this.contents.setIn(path7, value);
3613
3613
  }
3614
3614
  }
3615
3615
  /**
@@ -5569,9 +5569,9 @@ var require_cst_visit = __commonJS({
5569
5569
  visit.BREAK = BREAK;
5570
5570
  visit.SKIP = SKIP;
5571
5571
  visit.REMOVE = REMOVE;
5572
- visit.itemAtPath = (cst, path6) => {
5572
+ visit.itemAtPath = (cst, path7) => {
5573
5573
  let item = cst;
5574
- for (const [field2, index] of path6) {
5574
+ for (const [field2, index] of path7) {
5575
5575
  const tok = item?.[field2];
5576
5576
  if (tok && "items" in tok) {
5577
5577
  item = tok.items[index];
@@ -5580,23 +5580,23 @@ var require_cst_visit = __commonJS({
5580
5580
  }
5581
5581
  return item;
5582
5582
  };
5583
- visit.parentCollection = (cst, path6) => {
5584
- const parent = visit.itemAtPath(cst, path6.slice(0, -1));
5585
- const field2 = path6[path6.length - 1][0];
5583
+ visit.parentCollection = (cst, path7) => {
5584
+ const parent = visit.itemAtPath(cst, path7.slice(0, -1));
5585
+ const field2 = path7[path7.length - 1][0];
5586
5586
  const coll = parent?.[field2];
5587
5587
  if (coll && "items" in coll)
5588
5588
  return coll;
5589
5589
  throw new Error("Parent collection not found");
5590
5590
  };
5591
- function _visit(path6, item, visitor) {
5592
- let ctrl = visitor(item, path6);
5591
+ function _visit(path7, item, visitor) {
5592
+ let ctrl = visitor(item, path7);
5593
5593
  if (typeof ctrl === "symbol")
5594
5594
  return ctrl;
5595
5595
  for (const field2 of ["key", "value"]) {
5596
5596
  const token = item[field2];
5597
5597
  if (token && "items" in token) {
5598
5598
  for (let i = 0; i < token.items.length; ++i) {
5599
- const ci = _visit(Object.freeze(path6.concat([[field2, i]])), token.items[i], visitor);
5599
+ const ci = _visit(Object.freeze(path7.concat([[field2, i]])), token.items[i], visitor);
5600
5600
  if (typeof ci === "number")
5601
5601
  i = ci - 1;
5602
5602
  else if (ci === BREAK)
@@ -5607,10 +5607,10 @@ var require_cst_visit = __commonJS({
5607
5607
  }
5608
5608
  }
5609
5609
  if (typeof ctrl === "function" && field2 === "key")
5610
- ctrl = ctrl(item, path6);
5610
+ ctrl = ctrl(item, path7);
5611
5611
  }
5612
5612
  }
5613
- return typeof ctrl === "function" ? ctrl(item, path6) : ctrl;
5613
+ return typeof ctrl === "function" ? ctrl(item, path7) : ctrl;
5614
5614
  }
5615
5615
  exports2.visit = visit;
5616
5616
  }
@@ -6912,14 +6912,14 @@ var require_parser = __commonJS({
6912
6912
  case "scalar":
6913
6913
  case "single-quoted-scalar":
6914
6914
  case "double-quoted-scalar": {
6915
- const fs6 = this.flowScalar(this.type);
6915
+ const fs7 = this.flowScalar(this.type);
6916
6916
  if (atNextItem || it.value) {
6917
- map2.items.push({ start, key: fs6, sep: [] });
6917
+ map2.items.push({ start, key: fs7, sep: [] });
6918
6918
  this.onKeyLine = true;
6919
6919
  } else if (it.sep) {
6920
- this.stack.push(fs6);
6920
+ this.stack.push(fs7);
6921
6921
  } else {
6922
- Object.assign(it, { key: fs6, sep: [] });
6922
+ Object.assign(it, { key: fs7, sep: [] });
6923
6923
  this.onKeyLine = true;
6924
6924
  }
6925
6925
  return;
@@ -7047,13 +7047,13 @@ var require_parser = __commonJS({
7047
7047
  case "scalar":
7048
7048
  case "single-quoted-scalar":
7049
7049
  case "double-quoted-scalar": {
7050
- const fs6 = this.flowScalar(this.type);
7050
+ const fs7 = this.flowScalar(this.type);
7051
7051
  if (!it || it.value)
7052
- fc.items.push({ start: [], key: fs6, sep: [] });
7052
+ fc.items.push({ start: [], key: fs7, sep: [] });
7053
7053
  else if (it.sep)
7054
- this.stack.push(fs6);
7054
+ this.stack.push(fs7);
7055
7055
  else
7056
- Object.assign(it, { key: fs6, sep: [] });
7056
+ Object.assign(it, { key: fs7, sep: [] });
7057
7057
  return;
7058
7058
  }
7059
7059
  case "flow-map-end":
@@ -7362,18 +7362,21 @@ var require_dist = __commonJS({
7362
7362
  });
7363
7363
 
7364
7364
  // src/index.ts
7365
- var import_config22 = require("dotenv/config");
7365
+ var import_config23 = require("dotenv/config");
7366
7366
  var import_node_child_process3 = require("child_process");
7367
7367
  var import_commander = require("commander");
7368
- var import_chalk24 = __toESM(require("chalk"));
7368
+ var import_chalk25 = __toESM(require("chalk"));
7369
7369
 
7370
7370
  // ../shared/src/urls.ts
7371
7371
  var DEFAULT_WEB_APP_URL = "https://app.replicas.dev";
7372
+ var DEFAULT_SUPABASE_URL = "https://mxeqiomwgdgaesecwtct.supabase.co";
7373
+ var DEFAULT_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im14ZXFpb213Z2RnYWVzZWN3dGN0Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTk4OTk2ODAsImV4cCI6MjA3NTQ3NTY4MH0.zLRoK4r9Zep-WaLNkvWcb7DXlJBZFH26QXWO1ljMctM";
7372
7374
  var DASHBOARD_PATH = "/dashboard";
7373
7375
  var WEB_APP_PATHS = {
7374
7376
  home: "/",
7375
7377
  onboarding: "/onboarding",
7376
7378
  workspaces: "/workspace",
7379
+ environmentSetup: "/workspace/setup",
7377
7380
  automations: "/automations",
7378
7381
  environment: "/environment",
7379
7382
  analytics: "/analytics",
@@ -7532,6 +7535,9 @@ function isAgentMode() {
7532
7535
  return false;
7533
7536
  }
7534
7537
  }
7538
+ function isEnvironmentSetupWorkspace() {
7539
+ return isAgentMode() && !!process.env.REPLICAS_ENVIRONMENT_SETUP_RUN_ID;
7540
+ }
7535
7541
  function readAgentConfig() {
7536
7542
  if (!import_fs.default.existsSync(CONFIG_FILE)) {
7537
7543
  return null;
@@ -7558,8 +7564,8 @@ var import_supabase_js2 = require("@supabase/supabase-js");
7558
7564
 
7559
7565
  // src/lib/supabase.ts
7560
7566
  var import_supabase_js = require("@supabase/supabase-js");
7561
- var supabaseUrl = process.env.REPLICAS_SUPABASE_URL || "https://mxeqiomwgdgaesecwtct.supabase.co";
7562
- var supabaseAnonKey = process.env.REPLICAS_SUPABASE_ANON_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im14ZXFpb213Z2RnYWVzZWN3dGN0Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTk4OTk2ODAsImV4cCI6MjA3NTQ3NTY4MH0.zLRoK4r9Zep-WaLNkvWcb7DXlJBZFH26QXWO1ljMctM";
7567
+ var supabaseUrl = process.env.REPLICAS_SUPABASE_URL || DEFAULT_SUPABASE_URL;
7568
+ var supabaseAnonKey = process.env.REPLICAS_SUPABASE_ANON_KEY || DEFAULT_SUPABASE_ANON_KEY;
7563
7569
  var supabase = (0, import_supabase_js.createClient)(supabaseUrl, supabaseAnonKey, {
7564
7570
  auth: {
7565
7571
  persistSession: true,
@@ -7647,6 +7653,9 @@ var import_prompts3 = __toESM(require("prompts"));
7647
7653
  function isRecord(value) {
7648
7654
  return typeof value === "object" && value !== null && !Array.isArray(value);
7649
7655
  }
7656
+ function isNonEmptyString(value) {
7657
+ return typeof value === "string" && value.trim().length > 0;
7658
+ }
7650
7659
 
7651
7660
  // ../shared/src/json.ts
7652
7661
  function safeJsonParse(str, fallback) {
@@ -8655,10 +8664,10 @@ function mergeDefs(...defs) {
8655
8664
  function cloneDef(schema) {
8656
8665
  return mergeDefs(schema._zod.def);
8657
8666
  }
8658
- function getElementAtPath(obj, path6) {
8659
- if (!path6)
8667
+ function getElementAtPath(obj, path7) {
8668
+ if (!path7)
8660
8669
  return obj;
8661
- return path6.reduce((acc, key) => acc?.[key], obj);
8670
+ return path7.reduce((acc, key) => acc?.[key], obj);
8662
8671
  }
8663
8672
  function promiseAllObject(promisesObj) {
8664
8673
  const keys = Object.keys(promisesObj);
@@ -9067,11 +9076,11 @@ function explicitlyAborted(x, startIndex = 0) {
9067
9076
  }
9068
9077
  return false;
9069
9078
  }
9070
- function prefixIssues(path6, issues) {
9079
+ function prefixIssues(path7, issues) {
9071
9080
  return issues.map((iss) => {
9072
9081
  var _a3;
9073
9082
  (_a3 = iss).path ?? (_a3.path = []);
9074
- iss.path.unshift(path6);
9083
+ iss.path.unshift(path7);
9075
9084
  return iss;
9076
9085
  });
9077
9086
  }
@@ -9218,16 +9227,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
9218
9227
  }
9219
9228
  function formatError(error51, mapper = (issue2) => issue2.message) {
9220
9229
  const fieldErrors = { _errors: [] };
9221
- const processError = (error52, path6 = []) => {
9230
+ const processError = (error52, path7 = []) => {
9222
9231
  for (const issue2 of error52.issues) {
9223
9232
  if (issue2.code === "invalid_union" && issue2.errors.length) {
9224
- issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
9233
+ issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
9225
9234
  } else if (issue2.code === "invalid_key") {
9226
- processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
9235
+ processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
9227
9236
  } else if (issue2.code === "invalid_element") {
9228
- processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
9237
+ processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
9229
9238
  } else {
9230
- const fullpath = [...path6, ...issue2.path];
9239
+ const fullpath = [...path7, ...issue2.path];
9231
9240
  if (fullpath.length === 0) {
9232
9241
  fieldErrors._errors.push(mapper(issue2));
9233
9242
  } else {
@@ -9254,17 +9263,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
9254
9263
  }
9255
9264
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
9256
9265
  const result = { errors: [] };
9257
- const processError = (error52, path6 = []) => {
9266
+ const processError = (error52, path7 = []) => {
9258
9267
  var _a3, _b;
9259
9268
  for (const issue2 of error52.issues) {
9260
9269
  if (issue2.code === "invalid_union" && issue2.errors.length) {
9261
- issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
9270
+ issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
9262
9271
  } else if (issue2.code === "invalid_key") {
9263
- processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
9272
+ processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
9264
9273
  } else if (issue2.code === "invalid_element") {
9265
- processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
9274
+ processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
9266
9275
  } else {
9267
- const fullpath = [...path6, ...issue2.path];
9276
+ const fullpath = [...path7, ...issue2.path];
9268
9277
  if (fullpath.length === 0) {
9269
9278
  result.errors.push(mapper(issue2));
9270
9279
  continue;
@@ -9296,8 +9305,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
9296
9305
  }
9297
9306
  function toDotPath(_path) {
9298
9307
  const segs = [];
9299
- const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
9300
- for (const seg of path6) {
9308
+ const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
9309
+ for (const seg of path7) {
9301
9310
  if (typeof seg === "number")
9302
9311
  segs.push(`[${seg}]`);
9303
9312
  else if (typeof seg === "symbol")
@@ -21989,13 +21998,13 @@ function resolveRef(ref, ctx) {
21989
21998
  if (!ref.startsWith("#")) {
21990
21999
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
21991
22000
  }
21992
- const path6 = ref.slice(1).split("/").filter(Boolean);
21993
- if (path6.length === 0) {
22001
+ const path7 = ref.slice(1).split("/").filter(Boolean);
22002
+ if (path7.length === 0) {
21994
22003
  return ctx.rootSchema;
21995
22004
  }
21996
22005
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
21997
- if (path6[0] === defsKey) {
21998
- const key = path6[1];
22006
+ if (path7[0] === defsKey) {
22007
+ const key = path7[1];
21999
22008
  if (!key || !ctx.defs[key]) {
22000
22009
  throw new Error(`Reference not found: ${ref}`);
22001
22010
  }
@@ -23204,11 +23213,11 @@ function parseShellScript(script, cwd) {
23204
23213
  parseUntil(scope, 0, false);
23205
23214
  return scope.commands;
23206
23215
  }
23207
- function resolveShellPath(dir, path6) {
23208
- if (path6.includes(SHELL_OPAQUE) || path6.startsWith("~")) return null;
23209
- if (!path6.startsWith("/") && dir === null) return null;
23216
+ function resolveShellPath(dir, path7) {
23217
+ if (path7.includes(SHELL_OPAQUE) || path7.startsWith("~")) return null;
23218
+ if (!path7.startsWith("/") && dir === null) return null;
23210
23219
  const parts = [];
23211
- for (const part of (path6.startsWith("/") ? path6 : `${dir}/${path6}`).split("/")) {
23220
+ for (const part of (path7.startsWith("/") ? path7 : `${dir}/${path7}`).split("/")) {
23212
23221
  if (part === "..") parts.pop();
23213
23222
  else if (part && part !== ".") parts.push(part);
23214
23223
  }
@@ -23558,16 +23567,16 @@ function parseSkillName(tool, input) {
23558
23567
  const skillName = parsedInput.skill ?? parsedInput.name;
23559
23568
  return typeof skillName === "string" && skillName ? skillName : null;
23560
23569
  }
23561
- function skillNameFromFilePath(path6) {
23562
- const skillName = skillNameFromSkillRootPath(path6);
23570
+ function skillNameFromFilePath(path7) {
23571
+ const skillName = skillNameFromSkillRootPath(path7);
23563
23572
  if (skillName) return skillName;
23564
- const parts = path6.split(/[\\/]+/).filter(Boolean);
23573
+ const parts = path7.split(/[\\/]+/).filter(Boolean);
23565
23574
  if (parts.length < 2 || parts[parts.length - 1].toLowerCase() !== "skill.md") return null;
23566
23575
  const fallbackSkillName = parts[parts.length - 2];
23567
23576
  return fallbackSkillName && fallbackSkillName.toLowerCase() !== "skills" ? fallbackSkillName : null;
23568
23577
  }
23569
- function skillNameFromSkillRootPath(path6) {
23570
- const parts = path6.split(/[\\/]+/).filter(Boolean);
23578
+ function skillNameFromSkillRootPath(path7) {
23579
+ const parts = path7.split(/[\\/]+/).filter(Boolean);
23571
23580
  const skillsIndex = parts.findLastIndex((part) => part.toLowerCase() === "skills");
23572
23581
  if (skillsIndex === -1) return null;
23573
23582
  const firstSkillPart = parts[skillsIndex + 1];
@@ -23577,9 +23586,9 @@ function skillNameFromSkillRootPath(path6) {
23577
23586
  function parseSkillFilePath(input) {
23578
23587
  const parsedInput = typeof input === "string" ? safeJsonParse(input, null) : input;
23579
23588
  if (!isRecord(parsedInput)) return null;
23580
- const path6 = [parsedInput.path, parsedInput.filePath, parsedInput.file_path].find((value) => typeof value === "string" && value.length > 0);
23581
- if (!path6) return null;
23582
- return skillNameFromFilePath(path6);
23589
+ const path7 = [parsedInput.path, parsedInput.filePath, parsedInput.file_path].find((value) => typeof value === "string" && value.length > 0);
23590
+ if (!path7) return null;
23591
+ return skillNameFromFilePath(path7);
23583
23592
  }
23584
23593
  function skillNameFromToolCall(tool, input) {
23585
23594
  const directSkillName = parseSkillName(tool, input);
@@ -23891,8 +23900,451 @@ var DOCKER_ABILITY = {
23891
23900
  referenceFile: { name: "DOCKER.md", content: REFERENCE2 }
23892
23901
  };
23893
23902
 
23903
+ // ../shared/src/uuid.ts
23904
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
23905
+
23906
+ // ../shared/src/routes/environment-setups.ts
23907
+ var ENVIRONMENT_SETUP_STEPS = [
23908
+ { key: "understand", label: "Understand the codebase" },
23909
+ { key: "install", label: "Install dependencies and run the app" },
23910
+ { key: "verify", label: "Verify checks and record a walkthrough" },
23911
+ { key: "configure", label: "Draft hooks, system prompt, and automations" },
23912
+ { key: "propose", label: "Propose the configuration for review" }
23913
+ ];
23914
+ var ENVIRONMENT_SETUP_STEP_STATUSES = ["pending", "in_progress", "completed", "skipped"];
23915
+ function isEnvironmentSetupStepKey(value) {
23916
+ return ENVIRONMENT_SETUP_STEPS.some((step) => step.key === value);
23917
+ }
23918
+ function isEnvironmentSetupStepStatus(value) {
23919
+ return ENVIRONMENT_SETUP_STEP_STATUSES.some((status) => status === value);
23920
+ }
23921
+ var ENVIRONMENT_SETUP_RUN_STATUSES = ["running", "proposed", "applied", "failed", "cancelled"];
23922
+ var ENVIRONMENT_SETUP_AUTOMATION_ACTIONS = ["create", "update", "keep", "disable"];
23923
+ var ENVIRONMENT_SETUP_VERIFICATION_STATUSES = ["passed", "failed", "skipped"];
23924
+ var ENVIRONMENT_SETUP_LIMITS = {
23925
+ summaryChars: 600,
23926
+ stackItems: 30,
23927
+ nameChars: 120,
23928
+ descriptionChars: 1e3,
23929
+ systemPromptChars: 2e4,
23930
+ hookChars: 5e4,
23931
+ variables: 50,
23932
+ variableKeyChars: 128,
23933
+ variableDescriptionChars: 500,
23934
+ automations: 8,
23935
+ automationKeyChars: 80,
23936
+ automationPromptChars: 1e4,
23937
+ automationTriggers: 5,
23938
+ automationNoteChars: 300,
23939
+ verificationItems: 8,
23940
+ verificationDetailChars: 300,
23941
+ mediaItems: 8,
23942
+ repositories: 20
23943
+ };
23944
+ var ENVIRONMENT_SETUP_VARIABLE_WAIT = { defaultMs: 5 * 6e4, maxMs: 15 * 6e4, pollMs: 5e3 };
23945
+ var VARIABLE_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
23946
+ var text = (max) => max === void 0 ? external_exports.string().trim() : external_exports.string().trim().max(max);
23947
+ var requiredText = (max) => text(max).min(1, "must not be empty");
23948
+ var optionalText = (max) => text(max).nullish().transform((value) => value || null);
23949
+ var clearableText = (max) => text(max).nullish().transform((value) => value === void 0 ? void 0 : value || null);
23950
+ var list = (item, max) => max === void 0 ? external_exports.array(item) : external_exports.array(item).max(max);
23951
+ var ENVIRONMENT_SETUP_AUTHORED_TRIGGER_TYPES = ["cron", "github", "gitlab"];
23952
+ function isEnvironmentSetupAuthoredTriggerType(type) {
23953
+ return ENVIRONMENT_SETUP_AUTHORED_TRIGGER_TYPES.some((authored) => authored === type);
23954
+ }
23955
+ var repositoryTriggerConfigSchema = external_exports.object({
23956
+ event: external_exports.string(),
23957
+ repository_ids: external_exports.array(external_exports.string().regex(UUID_RE, "must be a repository id")).optional(),
23958
+ group_pr_events: external_exports.boolean().optional(),
23959
+ excluded_actors: external_exports.array(external_exports.string()).optional()
23960
+ });
23961
+ var proposalTriggerSchema = external_exports.discriminatedUnion("type", [
23962
+ external_exports.object({ type: external_exports.literal("cron"), config: external_exports.object({ schedule: external_exports.string(), timezone: external_exports.string().optional() }) }),
23963
+ external_exports.object({ type: external_exports.literal("github"), config: repositoryTriggerConfigSchema }),
23964
+ external_exports.object({ type: external_exports.literal("gitlab"), config: repositoryTriggerConfigSchema })
23965
+ ]);
23966
+ var existingTriggerSchema = external_exports.custom(
23967
+ (value) => isRecord(value) && typeof value.type === "string" && isRecord(value.config),
23968
+ "must be an automation trigger"
23969
+ );
23970
+ var carriedTriggerSchema = existingTriggerSchema.refine(
23971
+ (trigger) => !isEnvironmentSetupAuthoredTriggerType(trigger.type)
23972
+ );
23973
+ function automationSchema(limits) {
23974
+ const authored = external_exports.object({
23975
+ name: text(limits.nameChars),
23976
+ description: text(limits.descriptionChars),
23977
+ prompt: text(limits.automationPromptChars),
23978
+ triggers: list(proposalTriggerSchema, limits.automationTriggers)
23979
+ });
23980
+ const updated = authored.extend({ triggers: list(external_exports.union([proposalTriggerSchema, carriedTriggerSchema]), limits.automationTriggers) });
23981
+ return external_exports.object({
23982
+ key: requiredText(limits.automationKeyChars),
23983
+ action: external_exports.enum(ENVIRONMENT_SETUP_AUTOMATION_ACTIONS).default("create"),
23984
+ automation_id: external_exports.string().regex(UUID_RE, "must be an automation id").nullable().default(null),
23985
+ name: text().default(""),
23986
+ description: optionalText().transform((value) => value ?? ""),
23987
+ prompt: text().default(""),
23988
+ triggers: list(existingTriggerSchema).default([]),
23989
+ note: optionalText(limits.automationNoteChars)
23990
+ }).superRefine((automation2, ctx) => {
23991
+ if (automation2.action === "create" && automation2.automation_id) {
23992
+ ctx.addIssue({ code: "custom", path: ["automation_id"], message: "belongs on an update, keep, or disable entry" });
23993
+ }
23994
+ if (automation2.action !== "create" && !automation2.automation_id) {
23995
+ ctx.addIssue({ code: "custom", path: ["automation_id"], message: "must be the id of an automation attached to this environment" });
23996
+ }
23997
+ if (automation2.action === "create" || automation2.action === "update") {
23998
+ if (!automation2.name) ctx.addIssue({ code: "custom", path: ["name"], message: "must not be empty" });
23999
+ if (!automation2.prompt) ctx.addIssue({ code: "custom", path: ["prompt"], message: "must not be empty" });
24000
+ if (automation2.triggers.length === 0) ctx.addIssue({ code: "custom", path: ["triggers"], message: "must not be empty" });
24001
+ }
24002
+ }).transform((automation2, ctx) => {
24003
+ if (automation2.action === "keep" || automation2.action === "disable") return automation2;
24004
+ const content = (automation2.action === "update" ? updated : authored).safeParse(automation2);
24005
+ if (content.success) return { ...automation2, ...content.data };
24006
+ for (const issue2 of content.error.issues) ctx.addIssue({ ...issue2, code: "custom" });
24007
+ return external_exports.NEVER;
24008
+ });
24009
+ }
24010
+ function automationListSchema(limits) {
24011
+ return list(automationSchema(limits)).default([]).superRefine((automations, ctx) => {
24012
+ if (new Set(automations.map((automation2) => automation2.key)).size !== automations.length) {
24013
+ ctx.addIssue({ code: "custom", message: "must have unique keys" });
24014
+ }
24015
+ const targets = automations.flatMap((automation2) => automation2.automation_id ?? []);
24016
+ if (new Set(targets).size !== targets.length) {
24017
+ ctx.addIssue({ code: "custom", message: "must mention each existing automation once" });
24018
+ }
24019
+ if (limits.automations !== void 0 && automations.filter((automation2) => automation2.action === "create").length > limits.automations) {
24020
+ ctx.addIssue({ code: "custom", message: `must create at most ${limits.automations} new automations` });
24021
+ }
24022
+ });
24023
+ }
24024
+ function environmentSchema(limits) {
24025
+ return external_exports.object({
24026
+ name: optionalText(limits.nameChars).transform((value) => value ?? void 0),
24027
+ description: clearableText(limits.descriptionChars),
24028
+ system_prompt: clearableText(limits.systemPromptChars),
24029
+ start_hook: clearableText(limits.hookChars),
24030
+ warm_hook: clearableText(limits.hookChars)
24031
+ });
24032
+ }
24033
+ function variableSchema(limits, requiredDefault) {
24034
+ return external_exports.object({
24035
+ key: external_exports.string().regex(VARIABLE_KEY_RE, "must be a valid environment variable name").max(limits.variableKeyChars ?? Number.POSITIVE_INFINITY),
24036
+ description: optionalText(limits.variableDescriptionChars).transform((value) => value ?? ""),
24037
+ required: external_exports.boolean().default(requiredDefault)
24038
+ });
24039
+ }
24040
+ function proposalSchema(limits) {
24041
+ return external_exports.object({
24042
+ summary: requiredText(limits.summaryChars),
24043
+ stack: list(text(), limits.stackItems).default([]).transform((items) => items.filter(Boolean)),
24044
+ environment: environmentSchema(limits),
24045
+ variables: list(variableSchema(limits, false), limits.variables).default([]),
24046
+ automations: automationListSchema(limits),
24047
+ verification: list(external_exports.object({
24048
+ label: requiredText(limits.nameChars),
24049
+ status: external_exports.enum(ENVIRONMENT_SETUP_VERIFICATION_STATUSES),
24050
+ detail: optionalText(limits.verificationDetailChars).transform((value) => value ?? void 0)
24051
+ }), limits.verificationItems).default([]),
24052
+ media: list(external_exports.object({
24053
+ media_id: external_exports.string().regex(UUID_RE, "must be a media id"),
24054
+ title: requiredText(limits.nameChars)
24055
+ }), limits.mediaItems).default([])
24056
+ });
24057
+ }
24058
+ var environmentSetupProposalSchema = proposalSchema({});
24059
+ var environmentSetupProposalSubmissionSchema = proposalSchema(ENVIRONMENT_SETUP_LIMITS);
24060
+ var environmentSetupVariableRequestSchema = variableSchema({}, false).extend({
24061
+ status: external_exports.enum(["pending", "provided", "skipped"]),
24062
+ requested_at: external_exports.string(),
24063
+ resolved_at: external_exports.string().nullable().default(null)
24064
+ });
24065
+ var environmentSetupRunStateSchema = external_exports.object({
24066
+ status: external_exports.enum(ENVIRONMENT_SETUP_RUN_STATUSES),
24067
+ steps: external_exports.partialRecord(external_exports.enum(ENVIRONMENT_SETUP_STEPS.map((step) => step.key)), external_exports.enum(ENVIRONMENT_SETUP_STEP_STATUSES)).default({}),
24068
+ proposal: environmentSetupProposalSchema.nullable().default(null),
24069
+ applied: external_exports.object({
24070
+ applied_at: external_exports.string(),
24071
+ automation_ids: external_exports.array(external_exports.string())
24072
+ }).nullable().default(null),
24073
+ variable_requests: external_exports.array(environmentSetupVariableRequestSchema).default([])
24074
+ });
24075
+ var applyEnvironmentSetupRequestSchema = external_exports.object({
24076
+ environment: environmentSchema(ENVIRONMENT_SETUP_LIMITS).extend({ name: requiredText(ENVIRONMENT_SETUP_LIMITS.nameChars) }),
24077
+ 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)),
24078
+ automations: automationListSchema(ENVIRONMENT_SETUP_LIMITS)
24079
+ });
24080
+ var requestEnvironmentSetupVariablesSchema = external_exports.object({
24081
+ variables: list(variableSchema(ENVIRONMENT_SETUP_LIMITS, true), ENVIRONMENT_SETUP_LIMITS.variables).min(1, "must not be empty")
24082
+ }).superRefine(({ variables }, ctx) => {
24083
+ if (new Set(variables.map((variable) => variable.key)).size !== variables.length) {
24084
+ ctx.addIssue({ code: "custom", path: ["variables"], message: "must have unique keys" });
24085
+ }
24086
+ });
24087
+ var respondEnvironmentSetupVariablesSchema = external_exports.object({
24088
+ values: external_exports.record(external_exports.string().regex(VARIABLE_KEY_RE), external_exports.string()).default({}),
24089
+ skipped: external_exports.array(external_exports.string().regex(VARIABLE_KEY_RE)).default([])
24090
+ });
24091
+
24092
+ // ../shared/src/default-skills/replicas-agent/abilities/environment-setup.ts
24093
+ var SECTION3 = `### Environment setup (agent-led)
24094
+ Explore a codebase, get it running in this workspace, verify it end to end, and propose the Replicas environment configuration (start hook, warm hook, system prompt, variables) plus a few automations for the user to review and save.
24095
+
24096
+ **Reference:** \`references/ENVIRONMENT-SETUP.md\`
24097
+
24098
+ Use this when:
24099
+ - This workspace was started as an environment setup run (\`replicas environment-setup status\` succeeds)
24100
+ - The user asks you to set up, configure, audit, or improve a Replicas environment for a repository
24101
+ - The user asks what should go in a start hook, warm hook, or environment system prompt`;
24102
+ var REFERENCE3 = `# Environment setup (agent-led)
24103
+
24104
+ Use this workflow to make a repository fully usable by Replicas background agents: agents booted from the environment should be able to install, run, test, verify, and demo changes without a human babysitting them. The result of the workflow is a **proposal**, never a direct change: the user reviews, edits, and saves it in the Environment panel next to the chat.
24105
+
24106
+ ## Mental model
24107
+
24108
+ Every Replicas workspace is a remote Linux VM. Repositories are cloned under \`~/workspaces/<repo-name>\`. An **environment** is the org-scoped template a workspace is built from. It binds one repository (or a repository set for monorepos and multi-repo stacks) and carries:
24109
+
24110
+ | Piece | When it runs | Put here |
24111
+ | --- | --- | --- |
24112
+ | **Warm hook** | Once, while Replicas builds the warm-pool snapshot for the environment. Its *filesystem* state is baked into every new workspace; its *processes* are not. Default timeout 60 minutes. | Slow, deterministic setup: dependency installs from the lockfile, toolchain downloads, \`docker pull\`, one-time builds, code generation. |
24113
+ | **Start hook** | On every workspace boot, before the agent starts working. Default timeout 5 minutes. | Fast per-boot reconciliation: start daemons and databases, run migrations against local services, launch dev servers with \`replicas service start\`, health checks. Must be idempotent. |
24114
+ | **System prompt** | Injected into the agent's instructions for every workspace in the environment. | Only what an agent cannot learn from the repository itself: team conventions, review expectations, how to verify, gotchas you hit while setting up. |
24115
+ | **Variables** | Exported into every workspace (and available inside hooks). Values are encrypted. | API keys, tokens, feature flags, local service URLs. |
24116
+ | **Files** | Materialized on the workspace filesystem at boot. | \`.env\` files, dotfiles, config that must not be committed. |
24117
+ | **Automations** | Saved prompts fired by triggers (cron, pull request events, Slack, Sentry, webhooks). Each run creates a workspace in an environment. | Recurring engineering work that fits this repository. |
24118
+
24119
+ Hooks run with \`bash -lc\` from \`~/workspaces\` (the parent of every repository checkout), so start scripts with \`cd ~/workspaces/<repo-name>\`. A repository may also ship its own \`replicas.json\` / \`replicas.yaml\` with \`startHook\`, \`warmHook\`, and \`systemPrompt\`; repository hooks run after the environment hooks. Prefer proposing environment hooks unless the repository already manages its own.
24120
+
24121
+ The Global environment applies to every workspace in the organization; never propose putting repository-specific setup there.
24122
+
24123
+ ## Progress and the setup run
24124
+
24125
+ When this workspace was started as a setup run, the dashboard shows a live checklist next to the chat. Keep it honest with:
24126
+
24127
+ \`\`\`bash
24128
+ replicas environment-setup status
24129
+ replicas environment-setup step <key> <status>
24130
+ replicas environment-setup request-variables -f <path>
24131
+ replicas environment-setup wait-variables [-t 5m]
24132
+ \`\`\`
24133
+
24134
+ \`status\` prints the environment, repositories, current steps, and variable requests. \`request-variables\` returns immediately; \`wait-variables\` blocks until the required values arrive, are skipped, or the time runs out. Step statuses are \`pending\`, \`in_progress\`, \`completed\`, and \`skipped\`. Step keys, in order: \`understand\`, \`install\`, \`verify\`, \`configure\`, \`propose\`. Mark the first step \`in_progress\` before your first tool call, keep exactly one step \`in_progress\`, and mark a step \`completed\` only after its work actually succeeded. Use \`skipped\` when something genuinely cannot run (for example no browser UI to record) and say so in the proposal.
24135
+
24136
+ If \`replicas environment-setup status\` reports that there is no active setup run, the user asked for this in an ordinary workspace. Follow the same discovery and verification steps, then present the configuration in chat; apply it with \`replicas environment ...\` and \`replicas automation ...\` only when the user explicitly asks you to.
24137
+
24138
+ ## 1. Understand the codebase
24139
+
24140
+ Investigate in parallel before changing anything:
24141
+
24142
+ 1. Identify the products and services in the repository. Separate what is required for an end-to-end development flow from what is optional.
24143
+ 2. Read setup entry points: \`README\`, \`CONTRIBUTING\`, \`AGENTS.md\`, \`CLAUDE.md\`, package-manager files, tool-version files (\`.nvmrc\`, \`.tool-versions\`, \`.python-version\`), Makefiles, setup scripts, devcontainer and Docker Compose files, CI workflows.
24144
+ 3. Find the canonical install, dev-server, lint, type-check, test, and build commands. CI workflows and pre-commit hooks encode the checks that matter.
24145
+ 4. Learn the team's conventions from history: \`git log --oneline -50\`, and \`gh pr list --state merged --limit 20\` plus \`gh pr view <n>\` on a few merged pull requests (or the GitLab equivalents). Note branch naming, commit style, review expectations, and recurring chores that could become automations.
24146
+ 5. Identify required secrets, test accounts, databases, queues, browser dependencies, and external services. Check \`.env.example\`, config loaders, and CI secrets for variable names. Never read or print secret values. As soon as you know the names, ask for them (see "Asking for variables") and keep going.
24147
+ 6. Inspect any existing \`replicas.json\` and the current environment (\`replicas environment get <name>\`, \`replicas environment start-hooks get <name>\`, \`replicas environment warm-hooks get <name>\`) so the proposal builds on what exists instead of competing with it. List the organization's automations with \`replicas automation list --owner org\` and read each one attached to this environment with \`replicas automation get <id>\` (the environment id is in \`replicas environment-setup status\`); every one of them needs a decision in the proposal.
24148
+
24149
+ Use subagents for broad, independent analysis when available, but read the files and run the commands yourself before adopting their conclusions.
24150
+
24151
+ ## Asking for variables
24152
+
24153
+ The user may be watching the panel or may have walked away, so ask early and wait late:
24154
+
24155
+ 1. Right after step 1, request every secret you found in one batch. \`required\` means the app cannot run locally without it; leave it \`false\` for anything you can work around.
24156
+
24157
+ \`\`\`bash
24158
+ replicas environment-setup request-variables --file /tmp/variables.json
24159
+ \`\`\`
24160
+
24161
+ \`\`\`json
24162
+ {
24163
+ "variables": [
24164
+ { "key": "DATABASE_URL", "description": "Postgres connection string; a local docker compose database works", "required": false },
24165
+ { "key": "STRIPE_SECRET_KEY", "description": "Stripe test-mode key; checkout cannot run without it", "required": true }
24166
+ ]
24167
+ }
24168
+ \`\`\`
24169
+
24170
+ 2. Keep working on everything that does not need the values. The request appears in the Environment panel next to the chat; the user types values there (stored encrypted on the environment, never in chat) or skips them.
24171
+ 3. At the point you actually need a value, block on it:
24172
+
24173
+ \`\`\`bash
24174
+ replicas environment-setup wait-variables --timeout 5m
24175
+ replicas environment-setup wait-variables --keys STRIPE_SECRET_KEY
24176
+ \`\`\`
24177
+
24178
+ Without \`--keys\` it waits for every pending required key. It returns when the keys are provided or skipped, or when the time runs out, and prints which happened. Provided keys are exported for every new shell; restart anything you started with \`replicas service start\` before that point so it picks them up. Never print the values.
24179
+ 4. For anything skipped or unanswered, use the safest local substitute (local database, mock, documented test value), say so in the verification rows, and list the key as required in the proposal. A key the user skipped is not asked again; do not resend it.
24180
+ 5. Values the user provided are already saved on the environment. Still list those keys in the proposal so the review shows them as set.
24181
+ 6. Requests are only accepted before you propose. Anything still missing after that goes into the proposal as a required variable, which the user fills in at review.
24182
+
24183
+ ## 2. Install and run
24184
+
24185
+ Work from the smallest failing layer, in this workspace:
24186
+
24187
+ 1. Install system dependencies and toolchains the repository pins.
24188
+ 2. Run the install command to completion, then run it a second time to prove idempotence.
24189
+ 3. Start infrastructure and long-running processes with \`replicas service start <name> "<command>"\` so they survive turn boundaries (see \`REPLICAS.md\`). Start the Docker daemon first if Compose is involved (see \`DOCKER.md\`).
24190
+ 4. Run the canonical lint, type-check, test, and build commands for the agreed scope. Record what passed, what failed, and why.
24191
+
24192
+ Use the repository's pinned package manager and lockfile. Do not upgrade dependencies, rewrite lockfiles, or change application code to make setup pass; environment configuration and narrowly necessary fixes to setup scripts are in scope. Do not deploy, publish, or touch production resources.
24193
+
24194
+ When something needs a secret you do not have, request it and run \`wait-variables\` at the point you need it (see "Asking for variables"). If it is skipped or unanswered, use the safest local substitute, keep going, and record the variable as required in the proposal with a clear description. Never invent or paste secret values anywhere.
24195
+
24196
+ ## 3. Verify and record
24197
+
24198
+ Loading a page is not verification. Perform a representative real action through the product: create a record, submit a form, run a CLI command against the running service, call an endpoint and check the response.
24199
+
24200
+ For anything with a UI, record it:
24201
+
24202
+ \`\`\`bash
24203
+ replicas computer record start /tmp/walkthrough.mp4
24204
+ replicas computer launch chrome http://localhost:<port>
24205
+ replicas computer browser-state /tmp/state.png --full
24206
+ replicas computer browser-click "<button that starts the core flow>"
24207
+ replicas computer record stop
24208
+ replicas media upload /tmp/walkthrough.mp4 --name "<Project> walkthrough"
24209
+ \`\`\`
24210
+
24211
+ Keep the recording short (one to three minutes) and focused on the flow that proves the environment works. \`replicas media upload\` prints a chat embed line and a \`View in Replicas\` link ending in \`?media=<media-id>\`; keep both. The media id goes into the proposal, and the embed line goes into your final message. Follow \`MEDIA.md\` for anything shared outside the dashboard.
24212
+
24213
+ Add screenshots of important states (a passing test run, the running app) with \`replicas computer screenshot\` and upload them the same way when they help the user trust the result.
24214
+
24215
+ ## 4. Draft the configuration
24216
+
24217
+ Design from what you verified, not from what the README promises.
24218
+
24219
+ **Warm hook** \u2014 everything slow and deterministic that produced files on disk during step 2: dependency install, toolchain setup, \`docker compose pull\`, one-time builds, code generation. Non-interactive, \`set -euo pipefail\`, safe to rerun.
24220
+
24221
+ **Start hook** \u2014 everything that must be alive when an agent starts: start Docker, start databases and caches, run migrations, launch dev servers with \`replicas service start\`, then wait for readiness (poll a health endpoint) and exit 0. Guard every step so a second run is a no-op. Keep it under a couple of minutes; anything heavier belongs in the warm hook.
24222
+
24223
+ **System prompt** \u2014 short, and only for what is not obvious from the repository. Agents read the README, CONTRIBUTING, AGENTS.md, and CLAUDE.md themselves, so do not repeat what the product is, how the code is organized, or the standard commands. Include what you learned from history and from running the app: commit and pull request style, review expectations, what to run before opening a pull request, how to verify a change (ports, non-secret test accounts), and gotchas that cost you time. Aim for under 200 words. Use \`null\` when the repository docs already cover everything. Never include secrets or anything Replicas already tells the agent.
24224
+
24225
+ **Variables** \u2014 every key the application or hooks need, with a one-line description and whether it is required to run locally. Keys only, never values.
24226
+
24227
+ **Automations** \u2014 the set that should exist for this repository after saving, usually two to four. Each entry has a \`key\` and an \`action\`. \`create\` (the default) adds a new automation and needs a name, one-sentence description, a complete prompt an agent can execute unattended, and triggers. For an automation that already exists, pass its \`automation_id\` and a one-sentence \`note\` the reviewer sees next to it, then choose: \`update\` rewrites it with the full new content (also how you replace it with something better, under a new name if needed), \`keep\` leaves it untouched, \`disable\` turns it off. Every automation already attached to the environment must appear with one of those three; ones you leave out are not shown to the reviewer. Good candidates for new ones: pull request review focused on this codebase's conventions (\`pull_request.opened\` + \`pull_request.synchronize\`), nightly or weekly health checks (cron), documentation sync when code changes, dependency or security review, flaky-test triage. Only propose what the repository evidence supports.
24228
+
24229
+ Trigger shapes:
24230
+
24231
+ \`\`\`json
24232
+ { "type": "github", "config": { "event": "pull_request.opened" } }
24233
+ { "type": "github", "config": { "event": "pull_request.synchronize", "excluded_actors": ["dependabot[bot]"] } }
24234
+ { "type": "gitlab", "config": { "event": "merge_request.opened" } }
24235
+ { "type": "cron", "config": { "schedule": "0 9 * * 1-5", "timezone": "UTC" } }
24236
+ \`\`\`
24237
+
24238
+ GitHub events: \`pull_request.opened\`, \`pull_request.synchronize\`, \`pull_request.merged\`, \`pull_request.closed\`. GitLab events: \`merge_request.opened\`, \`merge_request.updated\`, \`merge_request.merged\`, \`merge_request.closed\`. Use one trigger type family per automation and pick the code host the repositories actually live on.
24239
+
24240
+ Test the hooks before proposing them: run the drafted warm hook and start hook scripts in this workspace (from \`~/workspaces\`) and fix the earliest failure until both exit 0 on a second run.
24241
+
24242
+ ## 5. Propose
24243
+
24244
+ The \`summary\` and \`verification\` fields are read by a person in the Environment panel, so write them for a person:
24245
+
24246
+ - \`summary\`: two or three plain sentences. What the product is, what it takes to run it, and anything notable you found. No command names, file paths, or version numbers; those belong in the system prompt or in verification details.
24247
+ - \`verification\`: three to six rows, one per outcome, in plain words. Group related commands into one row ("Installed and built the app", "Ran the unit and browser tests") and keep each \`detail\` to one sentence with the specifics. Never use a raw command as a label.
24248
+ - Limits, enforced by \`propose\`: \`summary\` ${ENVIRONMENT_SETUP_LIMITS.summaryChars} characters; \`verification\` ${ENVIRONMENT_SETUP_LIMITS.verificationItems} rows with \`detail\` ${ENVIRONMENT_SETUP_LIMITS.verificationDetailChars} characters each; \`stack\` ${ENVIRONMENT_SETUP_LIMITS.stackItems} items; \`variables\` ${ENVIRONMENT_SETUP_LIMITS.variables}, descriptions ${ENVIRONMENT_SETUP_LIMITS.variableDescriptionChars} characters; \`automations\` ${ENVIRONMENT_SETUP_LIMITS.automations} new ones (decisions on existing automations do not count), each with ${ENVIRONMENT_SETUP_LIMITS.automationTriggers} triggers, a ${ENVIRONMENT_SETUP_LIMITS.automationPromptChars}-character prompt, and a ${ENVIRONMENT_SETUP_LIMITS.automationNoteChars}-character note; \`media\` ${ENVIRONMENT_SETUP_LIMITS.mediaItems} items; \`system_prompt\` ${ENVIRONMENT_SETUP_LIMITS.systemPromptChars} characters; each hook ${ENVIRONMENT_SETUP_LIMITS.hookChars} characters; names ${ENVIRONMENT_SETUP_LIMITS.nameChars} and \`description\` ${ENVIRONMENT_SETUP_LIMITS.descriptionChars} characters.
24249
+
24250
+ Write the proposal to a file and submit it:
24251
+
24252
+ \`\`\`bash
24253
+ replicas environment-setup propose --file /tmp/proposal.json
24254
+ \`\`\`
24255
+
24256
+ \`\`\`json
24257
+ {
24258
+ "summary": "An online storefront: a Next.js site backed by a small Bun API and a Postgres database. Everything runs locally with Docker Compose and no external accounts. Payments are optional and stay disabled without a Stripe test key.",
24259
+ "stack": ["Bun", "Next.js", "Postgres", "Docker Compose", "Vitest"],
24260
+ "environment": {
24261
+ "description": "Storefront web app and API",
24262
+ "system_prompt": "Pull requests use conventional commit titles (feat:, fix:, chore:) and need a passing \`bun run check\` before review. Verify UI changes in the browser at http://localhost:3000 with the seeded account listed in docs/testing.md; the API is on port 4000. Database changes go through a migration in db/migrations, never a direct schema edit.",
24263
+ "start_hook": "#!/usr/bin/env bash\\nset -euo pipefail\\n...",
24264
+ "warm_hook": "#!/usr/bin/env bash\\nset -euo pipefail\\n..."
24265
+ },
24266
+ "variables": [
24267
+ { "key": "STRIPE_SECRET_KEY", "description": "Stripe test-mode key used by checkout; omit to run with payments disabled", "required": false }
24268
+ ],
24269
+ "automations": [
24270
+ {
24271
+ "key": "pr-review",
24272
+ "name": "Review pull requests",
24273
+ "description": "Reviews every PR against this repository's conventions and leaves inline comments.",
24274
+ "prompt": "Review this pull request...",
24275
+ "triggers": [
24276
+ { "type": "github", "config": { "event": "pull_request.opened" } },
24277
+ { "type": "github", "config": { "event": "pull_request.synchronize" } }
24278
+ ]
24279
+ }
24280
+ ],
24281
+ "verification": [
24282
+ { "label": "Installed and built the app", "status": "passed", "detail": "A second install made no changes." },
24283
+ { "label": "Ran lint, type checks, and unit tests", "status": "passed", "detail": "142 tests passed, matching CI." },
24284
+ { "label": "Completed a checkout in the browser", "status": "passed", "detail": "Added an item and placed a test order." },
24285
+ { "label": "Payment webhooks", "status": "skipped", "detail": "Needs a Stripe test key." }
24286
+ ],
24287
+ "media": [
24288
+ { "media_id": "<media-id from replicas media upload>", "title": "Checkout walkthrough" }
24289
+ ]
24290
+ }
24291
+ \`\`\`
24292
+
24293
+ When the environment already has automations, their entries look like this:
24294
+
24295
+ \`\`\`json
24296
+ { "key": "nightly-tests", "action": "keep", "automation_id": "<id from replicas automation list>", "note": "Already runs the full suite on the schedule CI uses." },
24297
+ { "key": "pr-review", "action": "update", "automation_id": "<id>", "name": "Review pull requests", "description": "...", "prompt": "...", "triggers": [ ... ], "note": "Adds the migration checklist reviewers keep asking for." },
24298
+ { "key": "docs-sync", "action": "disable", "automation_id": "<id>", "note": "The docs folder it watched was removed in May." }
24299
+ \`\`\`
24300
+
24301
+ Rules:
24302
+ - Omit \`description\`, \`system_prompt\`, \`start_hook\`, or \`warm_hook\` to keep the environment's current value. Set one to \`null\` to remove it when the repository genuinely needs none; explain why in \`summary\` or \`verification\`.
24303
+ - Omit \`environment.name\` unless the current name is misleading.
24304
+ - Every verification row must reflect something you actually ran. Do not list checks you did not run as passed.
24305
+ - A proposal does not change anything. Do not call \`replicas environment edit\`, \`vars set\`, \`files set\`, \`start-hooks save\`, \`warm-hooks save\`, or \`replicas automation create\` during a setup run.
24306
+ - If the user asks for changes after reviewing, revise and run \`propose\` again; the panel shows the latest proposal.
24307
+
24308
+ ## 6. Final message
24309
+
24310
+ After \`propose\` succeeds, mark the \`propose\` step completed and send one message with this shape:
24311
+
24312
+ \`\`\`text
24313
+ <Project> is running and ready to review.
24314
+
24315
+ **What I tested**
24316
+ - <outcome in plain words> \u2014 <one-sentence result>
24317
+ - <outcome in plain words> \u2014 <one-sentence result>
24318
+
24319
+ **What I found**
24320
+ - <two to four findings about the codebase that shaped the configuration, written for a person>
24321
+
24322
+ ![<Project> walkthrough](<chat embed URL printed by replicas media upload>)
24323
+ [View in Canvas](<View in Replicas URL>)
24324
+
24325
+ **Proposed configuration**
24326
+ Review the start hook, warm hook, system prompt, variables, and automations in the Environment panel on the right. Edit anything inline, then select **Save configuration**. Ask me here if you want changes and I will revise the proposal.
24327
+ \`\`\`
24328
+
24329
+ Keep it under 250 words plus the lists. Do not paste the hooks or system prompt into chat; the panel shows them. Never imply the configuration was saved: saving is the user's action.
24330
+
24331
+ ## Safety
24332
+
24333
+ - Never put tokens, passwords, or private keys in hooks, prompts, files, logs, or chat. Values that arrive through \`wait-variables\` are exported to your shell; never echo, cat, or paste them.
24334
+ - Do not weaken network, certificate, or package-integrity settings to make setup pass.
24335
+ - Do not run destructive git operations, force pushes, or anything against production endpoints.
24336
+ - Do not change application code to hide an environment problem. Report it instead.
24337
+ `;
24338
+ var ENVIRONMENT_SETUP_ABILITY = {
24339
+ label: "Environment setup",
24340
+ description: "Explore a codebase, verify it runs, and propose environment hooks, a system prompt, variables, and automations for review.",
24341
+ bullet: "- Setting up, auditing, or improving a Replicas environment for a repository (hooks, system prompt, variables, automations)",
24342
+ section: SECTION3,
24343
+ referenceFile: { name: "ENVIRONMENT-SETUP.md", content: REFERENCE3 }
24344
+ };
24345
+
23894
24346
  // ../shared/src/default-skills/replicas-agent/abilities/github.ts
23895
- var SECTION3 = `### GitHub
24347
+ var SECTION4 = `### GitHub
23896
24348
  Use the pre-authenticated \`gh\` CLI for repository workflows and the workspace-scoped TypeScript SDK for GitHub API calls.
23897
24349
 
23898
24350
  **Reference:** \`references/GITHUB.md\`
@@ -23902,7 +24354,7 @@ Use this when:
23902
24354
  - You need to interact with GitHub issues or actions
23903
24355
  - You need to use the GitHub API for advanced operations
23904
24356
  - You need to include images in PR descriptions`;
23905
- var REFERENCE3 = `# GitHub Integration
24357
+ var REFERENCE4 = `# GitHub Integration
23906
24358
 
23907
24359
  This guide covers how to interact with GitHub from within your Replicas workspace. Prefer \`@replicas/sdk\` for API calls so batching and data processing stay in one TypeScript program. The \`gh\` CLI remains useful for ergonomic pull request and git-adjacent workflows.
23908
24360
 
@@ -24031,12 +24483,12 @@ var GITHUB_ABILITY = {
24031
24483
  label: "GitHub",
24032
24484
  description: "GitHub workflows through gh and API calls through @replicas/sdk.",
24033
24485
  bullet: "- Interacting with GitHub (creating PRs, managing issues, using the API, etc.)",
24034
- section: SECTION3,
24035
- referenceFile: { name: "GITHUB.md", content: REFERENCE3 }
24486
+ section: SECTION4,
24487
+ referenceFile: { name: "GITHUB.md", content: REFERENCE4 }
24036
24488
  };
24037
24489
 
24038
24490
  // ../shared/src/default-skills/replicas-agent/abilities/gitlab.ts
24039
- var SECTION4 = `### GitLab
24491
+ var SECTION5 = `### GitLab
24040
24492
  Use plain git for repository traffic and the workspace-scoped TypeScript SDK for GitLab API operations.
24041
24493
 
24042
24494
  **Reference:** \`references/GITLAB.md\`
@@ -24045,7 +24497,7 @@ Use this when:
24045
24497
  - A repository remote is on gitlab.com or a self-managed GitLab instance
24046
24498
  - You need to open or update a merge request
24047
24499
  - You need GitLab issues, pipelines, comments, or other API data`;
24048
- var REFERENCE4 = `# GitLab Integration
24500
+ var REFERENCE5 = `# GitLab Integration
24049
24501
 
24050
24502
  Git credentials are preconfigured for fetch, pull, and push. Use \`@replicas/sdk\` for API traffic; never inspect \`~/.git-credentials\`, request a token, or send a credential with curl.
24051
24503
 
@@ -24093,12 +24545,12 @@ var GITLAB_ABILITY = {
24093
24545
  label: "GitLab",
24094
24546
  description: "Git for repository traffic and @replicas/sdk for the GitLab API.",
24095
24547
  bullet: "- Interacting with GitLab (pushing to GitLab repos, opening merge requests)",
24096
- section: SECTION4,
24097
- referenceFile: { name: "GITLAB.md", content: REFERENCE4 }
24548
+ section: SECTION5,
24549
+ referenceFile: { name: "GITLAB.md", content: REFERENCE5 }
24098
24550
  };
24099
24551
 
24100
24552
  // ../shared/src/default-skills/replicas-agent/abilities/linear.ts
24101
- var SECTION5 = `### Linear
24553
+ var SECTION6 = `### Linear
24102
24554
  Create tickets, fetch issues, update state, add comments, and search through \`replicas.linear.graphql\` in \`@replicas/sdk\`. This works without a Linear MCP server and refreshes authentication automatically.
24103
24555
 
24104
24556
  **Reference:** \`references/LINEAR.md\`
@@ -24109,7 +24561,7 @@ Use this when:
24109
24561
  - You need to update an issue's state or add a comment
24110
24562
  - You need to search Linear issues
24111
24563
  - A Linear request failed with an authentication error`;
24112
- var REFERENCE5 = `# Linear Integration
24564
+ var REFERENCE6 = `# Linear Integration
24113
24565
 
24114
24566
  Use \`@replicas/sdk\`; never request or handle a Linear OAuth token. Replicas refreshes the organization credential behind the gateway.
24115
24567
 
@@ -24198,12 +24650,12 @@ var LINEAR_ABILITY = {
24198
24650
  label: "Linear",
24199
24651
  description: "Create tickets, fetch issues, comment, and update state through @replicas/sdk.",
24200
24652
  bullet: "- Interacting with Linear (creating tickets, fetching issues, updating state, commenting, or troubleshooting authentication): use replicas.linear.graphql from @replicas/sdk, which refreshes tokens automatically and needs no Linear MCP server. Read references/LINEAR.md before treating a rejected workspace token as a disconnected integration.",
24201
- section: SECTION5,
24202
- referenceFile: { name: "LINEAR.md", content: REFERENCE5 }
24653
+ section: SECTION6,
24654
+ referenceFile: { name: "LINEAR.md", content: REFERENCE6 }
24203
24655
  };
24204
24656
 
24205
24657
  // ../shared/src/default-skills/replicas-agent/abilities/media.ts
24206
- var SECTION6 = `### Media
24658
+ var SECTION7 = `### Media
24207
24659
  Deliver screenshots, screen recordings, generated diagrams, audio clips, and self-contained HTML pages to the Replicas dashboard and, when applicable, inline in the destination workflow.
24208
24660
 
24209
24661
  **Reference:** \`references/MEDIA.md\`
@@ -24214,7 +24666,7 @@ Use this when:
24214
24666
  - You produce a self-contained HTML report that should be linked from a pull request
24215
24667
  - You record video output (browser automation, screen capture) \u2014 including the recommended aspect ratio and FPS
24216
24668
  - You need to embed media in a Slack/Linear/GitHub/GitLab message AND keep a referenceable copy in the Replicas dashboard`;
24217
- var REFERENCE6 = `# Media (Screenshots, Recordings, Audio, HTML)
24669
+ var REFERENCE7 = `# Media (Screenshots, Recordings, Audio, HTML)
24218
24670
 
24219
24671
  This is the single source of truth for delivering screenshots, screen recordings, generated diagrams, audio clips, and self-contained HTML pages through Replicas and external surfaces (Slack, Linear, GitHub, GitLab).
24220
24672
 
@@ -24539,8 +24991,8 @@ var MEDIA_ABILITY = {
24539
24991
  label: "Media",
24540
24992
  description: "Deliver media to Replicas and destination workflows with inline uploads.",
24541
24993
  bullet: "- Producing or showing the user any media \u2014 screenshots, screen recordings, generated images or diagrams, audio clips, or HTML recap pages \u2014 including in your Replicas chat reply, PR descriptions/comments, and other external platforms",
24542
- section: SECTION6,
24543
- referenceFile: { name: "MEDIA.md", content: REFERENCE6 }
24994
+ section: SECTION7,
24995
+ referenceFile: { name: "MEDIA.md", content: REFERENCE7 }
24544
24996
  };
24545
24997
 
24546
24998
  // ../shared/src/sandbox.ts
@@ -24588,7 +25040,7 @@ var memoryGenerationManifestSchema = external_exports.object({
24588
25040
  });
24589
25041
 
24590
25042
  // ../shared/src/default-skills/replicas-agent/abilities/memory.ts
24591
- var SECTION7 = `### Memory
25043
+ var SECTION8 = `### Memory
24592
25044
  Check relevant long-term memory before substantive work when historical context could improve the result.
24593
25045
 
24594
25046
  **Reference:** \`references/MEMORY.md\`
@@ -24600,7 +25052,7 @@ Use this when:
24600
25052
  - Related work may explain an error or implementation choice
24601
25053
 
24602
25054
  When uncertain whether prior context could help, check memory. If you decide something is worth remembering for future sessions, follow the marker guidance in references/MEMORY.md.`;
24603
- var REFERENCE7 = `# Long-term memory
25055
+ var REFERENCE8 = `# Long-term memory
24604
25056
 
24605
25057
  Replicas memory is installed under \`~/.replicas/memories\`:
24606
25058
 
@@ -24623,13 +25075,13 @@ var MEMORY_ABILITY = {
24623
25075
  label: "Memory",
24624
25076
  description: "Check private and organization memory before substantive work.",
24625
25077
  bullet: "",
24626
- section: SECTION7,
24627
- referenceFile: { name: "MEMORY.md", content: REFERENCE7 },
25078
+ section: SECTION8,
25079
+ referenceFile: { name: "MEMORY.md", content: REFERENCE8 },
24628
25080
  locked: true
24629
25081
  };
24630
25082
 
24631
25083
  // ../shared/src/default-skills/replicas-agent/abilities/previews.ts
24632
- var SECTION8 = `### Previews
25084
+ var SECTION9 = `### Previews
24633
25085
  Expose locally running services (web apps, APIs, databases) as public preview URLs so humans can interact with them directly.
24634
25086
 
24635
25087
  **Reference:** \`references/PREVIEWS.md\`
@@ -24638,7 +25090,7 @@ Use this when:
24638
25090
  - You need to start a service that a human should view or interact with
24639
25091
  - The task involves UI work that benefits from human review
24640
25092
  - You are verifying frontend/backend integrations visually`;
24641
- var REFERENCE8 = `# Preview URLs
25093
+ var REFERENCE9 = `# Preview URLs
24642
25094
 
24643
25095
  When you run services on ports \u2014 such as a web app, API server, or database \u2014 humans may want to interact with them directly. You can expose your locally running services as public preview URLs.
24644
25096
 
@@ -24714,12 +25166,12 @@ var PREVIEWS_ABILITY = {
24714
25166
  label: "Previews",
24715
25167
  description: "Expose locally running services on public preview URLs for humans.",
24716
25168
  bullet: "- Creating preview URLs for locally running services",
24717
- section: SECTION8,
24718
- referenceFile: { name: "PREVIEWS.md", content: REFERENCE8 }
25169
+ section: SECTION9,
25170
+ referenceFile: { name: "PREVIEWS.md", content: REFERENCE9 }
24719
25171
  };
24720
25172
 
24721
25173
  // ../shared/src/default-skills/replicas-agent/abilities/plugins.ts
24722
- var SECTION9 = `### Plugins
25174
+ var SECTION10 = `### Plugins
24723
25175
  Discover and execute installed marketplace tools through the workspace-scoped TypeScript SDK.
24724
25176
 
24725
25177
  **Reference:** \`references/PLUGINS.md\`
@@ -24735,7 +25187,7 @@ Use this when:
24735
25187
  - The user asks to query or update a connected turbopuffer namespace
24736
25188
  - The user asks for PlanetScale organizations, databases, branches, or Insights data
24737
25189
  - The user asks to analyze text with Pangram`;
24738
- var REFERENCE9 = `# Plugins
25190
+ var REFERENCE10 = `# Plugins
24739
25191
 
24740
25192
  Plugins are TypeScript libraries, not MCP servers. Import \`@replicas/sdk\`; Replicas authenticates the workspace and selects the most specific environment the workspace inherits from, then Global. Provider credentials, sessions, and project keys are never exposed.
24741
25193
 
@@ -24906,12 +25358,12 @@ var PLUGINS_ABILITY = {
24906
25358
  label: "Plugins",
24907
25359
  description: "Use installed marketplace tools through @replicas/sdk.",
24908
25360
  bullet: "- Interacting with installed marketplace plugins through TypeScript",
24909
- section: SECTION9,
24910
- referenceFile: { name: "PLUGINS.md", content: REFERENCE9 }
25361
+ section: SECTION10,
25362
+ referenceFile: { name: "PLUGINS.md", content: REFERENCE10 }
24911
25363
  };
24912
25364
 
24913
25365
  // ../shared/src/default-skills/replicas-agent/abilities/replicas.ts
24914
- var SECTION10 = `### Replicas (in-workspace CLI)
25366
+ var SECTION11 = `### Replicas (in-workspace CLI)
24915
25367
  Take action *with* Replicas itself \u2014 manage automations, environments (variables, files), repos, and \`replicas.json\` config \u2014 using the pre-installed, pre-authenticated \`replicas\` CLI.
24916
25368
 
24917
25369
  **Reference:** \`references/REPLICAS.md\`
@@ -24922,7 +25374,7 @@ Use this when:
24922
25374
  - The user asks "what envs / repos / automations do I have?"
24923
25375
  - The user asks you to scaffold a \`replicas.json\` / \`replicas.yaml\` in a repo
24924
25376
  - You need to run a long-lived service (dev server, daemon) \u2014 always use \`replicas service start\` so it survives workspace sleep/wake`;
24925
- var REFERENCE10 = `# Replicas (in-workspace CLI)
25377
+ var REFERENCE11 = `# Replicas (in-workspace CLI)
24926
25378
 
24927
25379
  This guide covers how to take action *with* Replicas itself from inside a Replicas workspace \u2014 managing automations, environments (and their variables/files), repos, previews, and the user's \`replicas.json\` config \u2014 using the pre-installed \`replicas\` CLI.
24928
25380
 
@@ -24960,6 +25412,7 @@ In agent mode the CLI hides commands that don't make sense for in-workspace agen
24960
25412
  | \`replicas repos\` | List repos connected to the org |
24961
25413
  | \`replicas environment ...\` | Manage environments, env vars, env files |
24962
25414
  | \`replicas automation ...\` | Manage automations (cron + GitHub/GitLab event triggers) |
25415
+ | \`replicas environment-setup ...\` | Report progress and propose configuration during an agent-led environment setup run (covered in \`ENVIRONMENT-SETUP.md\`) |
24963
25416
  | \`replicas preview ...\` | Register / list preview URLs (covered in \`PREVIEWS.md\`) |
24964
25417
  | \`replicas service ...\` | Run long-lived services detached so they survive workspace sleep/wake (see below) |
24965
25418
  | \`replicas media ...\` | Upload, list, share, revoke, or delete workspace media; follow \`MEDIA.md\` for destination embedding |
@@ -25153,13 +25606,13 @@ var REPLICAS_ABILITY = {
25153
25606
  description: "Teach the agent about Replicas itself \u2014 automations, environments, the in-workspace CLI.",
25154
25607
  // No bullet — help_instructions covers the `replicas` CLI surface in detail.
25155
25608
  bullet: "",
25156
- section: SECTION10,
25157
- referenceFile: { name: "REPLICAS.md", content: REFERENCE10 },
25609
+ section: SECTION11,
25610
+ referenceFile: { name: "REPLICAS.md", content: REFERENCE11 },
25158
25611
  locked: true
25159
25612
  };
25160
25613
 
25161
25614
  // ../shared/src/default-skills/replicas-agent/abilities/sentry.ts
25162
- var SECTION11 = `### Sentry
25615
+ var SECTION12 = `### Sentry
25163
25616
  Read issues and project data through the workspace-scoped TypeScript SDK.
25164
25617
 
25165
25618
  **Reference:** \`references/SENTRY.md\`
@@ -25167,7 +25620,7 @@ Read issues and project data through the workspace-scoped TypeScript SDK.
25167
25620
  Use this when:
25168
25621
  - You need to inspect Sentry projects or issues
25169
25622
  - A user asks for error-monitoring context outside a webhook-triggered task`;
25170
- var REFERENCE11 = `# Sentry Integration
25623
+ var REFERENCE12 = `# Sentry Integration
25171
25624
 
25172
25625
  Use \`@replicas/sdk\`; never request or read a Sentry token. Sentry access is organization-scoped and read-only.
25173
25626
 
@@ -25185,8 +25638,8 @@ var SENTRY_ABILITY = {
25185
25638
  label: "Sentry",
25186
25639
  description: "Read Sentry projects and issues through @replicas/sdk.",
25187
25640
  bullet: "- Interacting with Sentry (reading projects, issues, and error context)",
25188
- section: SECTION11,
25189
- referenceFile: { name: "SENTRY.md", content: REFERENCE11 }
25641
+ section: SECTION12,
25642
+ referenceFile: { name: "SENTRY.md", content: REFERENCE12 }
25190
25643
  };
25191
25644
 
25192
25645
  // ../shared/src/slack-response-style.ts
@@ -25196,7 +25649,7 @@ var SLACK_BLOCK_KIT_GUIDANCE = "Use Block Kit whenever structure or a link would
25196
25649
  var SLACK_PR_BUTTON_GUIDANCE = 'The first time you share a given pull request or merge request link in a thread \u2014 the message announcing you opened it \u2014 attach a button for it: send `blocks` alongside `text` \u2014 a `section` block holding your message as `mrkdwn`, then an `actions` block with one element per newly shared link, `{"type": "button", "style": "primary", "text": {"type": "plain_text", "text": "View PR"}, "url": "<pr url>", "action_id": "view_pr"}`. Later messages about a pull request you already linked in this thread keep the link in the sentence and get no button, and never re-post a button for a link someone already has. Label it "View MR" for GitLab, and if there are several give each button a unique `action_id` and name its repository in the label ("View PR \xB7 web"). Always keep `text` populated with the same message \u2014 Slack uses it for notifications and fallback \u2014 and keep the link in the sentence too.';
25197
25650
 
25198
25651
  // ../shared/src/default-skills/replicas-agent/abilities/slack.ts
25199
- var SECTION12 = `### Slack
25652
+ var SECTION13 = `### Slack
25200
25653
  Send messages, read threads, search conversations, and transfer files through the workspace-scoped TypeScript SDK.
25201
25654
 
25202
25655
  **Reference:** \`references/SLACK.md\`
@@ -25206,7 +25659,7 @@ Use this when:
25206
25659
  - You need to read or search Slack conversations
25207
25660
  - You need to download a file attached to a Slack message
25208
25661
  - You encounter a Slack message link and need its full thread`;
25209
- var REFERENCE12 = `# Slack Integration
25662
+ var REFERENCE13 = `# Slack Integration
25210
25663
 
25211
25664
  Use \`@replicas/sdk\`; never read or send a Slack token directly. The SDK calls Replicas, which selects only this workspace's organization connection.
25212
25665
 
@@ -25284,8 +25737,8 @@ var SLACK_ABILITY = {
25284
25737
  label: "Slack",
25285
25738
  description: "Send messages, read threads, search, and transfer files through @replicas/sdk.",
25286
25739
  bullet: "- Interacting with Slack (listing channels, sending messages, reading threads, or searching): use replicas.slack.call from @replicas/sdk. Read references/SLACK.md; no Slack MCP server or provider token in the VM is required.",
25287
- section: SECTION12,
25288
- referenceFile: { name: "SLACK.md", content: REFERENCE12 }
25740
+ section: SECTION13,
25741
+ referenceFile: { name: "SLACK.md", content: REFERENCE13 }
25289
25742
  };
25290
25743
 
25291
25744
  // ../shared/src/default-skills/replicas-agent/registry.ts
@@ -25294,6 +25747,7 @@ var REPLICAS_AGENT_ABILITY_REGISTRY = {
25294
25747
  memory: MEMORY_ABILITY,
25295
25748
  computer: COMPUTER_ABILITY,
25296
25749
  docker: DOCKER_ABILITY,
25750
+ environment_setup: ENVIRONMENT_SETUP_ABILITY,
25297
25751
  github: GITHUB_ABILITY,
25298
25752
  gitlab: GITLAB_ABILITY,
25299
25753
  linear: LINEAR_ABILITY,
@@ -26260,7 +26714,7 @@ function parseOpencodeEvents(events) {
26260
26714
  upsertDisplayMessage(messages, {
26261
26715
  id,
26262
26716
  type: "file_change",
26263
- changes: files.map((path6) => ({ path: path6, kind: "update" })),
26717
+ changes: files.map((path7) => ({ path: path7, kind: "update" })),
26264
26718
  status: "completed",
26265
26719
  timestamp
26266
26720
  });
@@ -27365,6 +27819,75 @@ var EGRESS_WORKSPACE_SHELL_VARS = {
27365
27819
  EGRESS_EXIT_IP_ENDPOINTS: EGRESS_EXIT_IP_ENDPOINTS.join(" ")
27366
27820
  };
27367
27821
 
27822
+ // ../shared/src/runtime-env.ts
27823
+ function shellQuotePosix(value) {
27824
+ return `'${value.split("'").join("'\\''")}'`;
27825
+ }
27826
+ function serializePosixEnvFile(env, unsetKeys = []) {
27827
+ return `${[
27828
+ ...[...unsetKeys].map((key) => `unset ${key}`),
27829
+ ...Object.entries(env).filter(([, value]) => value.length > 0).map(([key, value]) => `export ${key}=${shellQuotePosix(value)}`)
27830
+ ].join("\n")}
27831
+ `;
27832
+ }
27833
+ function parsePosixEnvUnsetKeys(content) {
27834
+ return content.split("\n").filter((line) => line.startsWith("unset ")).map((line) => line.slice("unset ".length).trim());
27835
+ }
27836
+ function parsePosixEnvFile(content) {
27837
+ const result = {};
27838
+ let pos = 0;
27839
+ while (pos < content.length) {
27840
+ let lineStart;
27841
+ if (pos === 0 || content[pos - 1] === "\n") {
27842
+ lineStart = pos;
27843
+ } else {
27844
+ const nl2 = content.indexOf("\n", pos);
27845
+ if (nl2 === -1) break;
27846
+ lineStart = nl2 + 1;
27847
+ }
27848
+ if (!content.startsWith("export ", lineStart)) {
27849
+ const nl2 = content.indexOf("\n", lineStart);
27850
+ if (nl2 === -1) break;
27851
+ pos = nl2 + 1;
27852
+ continue;
27853
+ }
27854
+ const nameStart = lineStart + "export ".length;
27855
+ const eqIdx = content.indexOf("=", nameStart);
27856
+ if (eqIdx === -1) break;
27857
+ const name = content.slice(nameStart, eqIdx).trim();
27858
+ let cursor = eqIdx + 1;
27859
+ if (content[cursor] !== "'") {
27860
+ const nl2 = content.indexOf("\n", cursor);
27861
+ pos = nl2 === -1 ? content.length : nl2 + 1;
27862
+ continue;
27863
+ }
27864
+ cursor += 1;
27865
+ let value = "";
27866
+ let closed = false;
27867
+ while (cursor < content.length) {
27868
+ const ch = content[cursor];
27869
+ if (ch === "'") {
27870
+ if (content.startsWith("\\''", cursor + 1)) {
27871
+ value += "'";
27872
+ cursor += 4;
27873
+ continue;
27874
+ }
27875
+ cursor += 1;
27876
+ closed = true;
27877
+ break;
27878
+ }
27879
+ value += ch;
27880
+ cursor += 1;
27881
+ }
27882
+ if (closed && name) {
27883
+ result[name] = value;
27884
+ }
27885
+ const nl = content.indexOf("\n", cursor);
27886
+ pos = nl === -1 ? content.length : nl + 1;
27887
+ }
27888
+ return result;
27889
+ }
27890
+
27368
27891
  // ../shared/src/slash-commands.ts
27369
27892
  var SIDE_CHAT_COMMANDS = ["/btw", "/side"];
27370
27893
  var SLASH_COMMANDS = [
@@ -27416,9 +27939,6 @@ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
27416
27939
  // ../shared/src/replicas-config.ts
27417
27940
  var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
27418
27941
 
27419
- // ../shared/src/uuid.ts
27420
- var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
27421
-
27422
27942
  // ../shared/src/terminal.ts
27423
27943
  var CONTROL_CHARACTERS = /[\u0000-\u001F\u007F-\u009F]/g;
27424
27944
  function sanitizeTerminalLine(value) {
@@ -27479,7 +27999,7 @@ var headlessFilesystemAgentResultSchema = external_exports.object({
27479
27999
  });
27480
28000
 
27481
28001
  // ../shared/src/cli-version.ts
27482
- var CLI_VERSION = "0.2.751";
28002
+ var CLI_VERSION = "0.2.753";
27483
28003
 
27484
28004
  // ../shared/src/version.ts
27485
28005
  function compareVersions(v1, v2) {
@@ -28215,186 +28735,6 @@ function identityTokenUrl() {
28215
28735
  return `http://127.0.0.1:${IDENTITY_PROXY_PORT}${IDENTITY_TOKEN_PATH}`;
28216
28736
  }
28217
28737
 
28218
- // ../shared/src/routes/environment-setups.ts
28219
- var ENVIRONMENT_SETUP_STEPS = [
28220
- { key: "understand", label: "Understand the codebase" },
28221
- { key: "install", label: "Install dependencies and run the app" },
28222
- { key: "verify", label: "Verify checks and record a walkthrough" },
28223
- { key: "configure", label: "Draft hooks, system prompt, and automations" },
28224
- { key: "propose", label: "Propose the configuration for review" }
28225
- ];
28226
- var ENVIRONMENT_SETUP_STEP_STATUSES = ["pending", "in_progress", "completed", "skipped"];
28227
- var ENVIRONMENT_SETUP_RUN_STATUSES = ["running", "proposed", "applied", "failed", "cancelled"];
28228
- var ENVIRONMENT_SETUP_AUTOMATION_ACTIONS = ["create", "update", "keep", "disable"];
28229
- var ENVIRONMENT_SETUP_VERIFICATION_STATUSES = ["passed", "failed", "skipped"];
28230
- var ENVIRONMENT_SETUP_LIMITS = {
28231
- summaryChars: 600,
28232
- stackItems: 30,
28233
- nameChars: 120,
28234
- descriptionChars: 1e3,
28235
- systemPromptChars: 2e4,
28236
- hookChars: 5e4,
28237
- variables: 50,
28238
- variableKeyChars: 128,
28239
- variableDescriptionChars: 500,
28240
- automations: 8,
28241
- automationKeyChars: 80,
28242
- automationPromptChars: 1e4,
28243
- automationTriggers: 5,
28244
- automationNoteChars: 300,
28245
- verificationItems: 8,
28246
- verificationDetailChars: 300,
28247
- mediaItems: 8,
28248
- repositories: 20
28249
- };
28250
- var ENVIRONMENT_SETUP_VARIABLE_WAIT = { defaultMs: 5 * 6e4, maxMs: 15 * 6e4, pollMs: 5e3 };
28251
- var VARIABLE_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
28252
- var text = (max) => max === void 0 ? external_exports.string().trim() : external_exports.string().trim().max(max);
28253
- var requiredText = (max) => text(max).min(1, "must not be empty");
28254
- var optionalText = (max) => text(max).nullish().transform((value) => value || null);
28255
- var clearableText = (max) => text(max).nullish().transform((value) => value === void 0 ? void 0 : value || null);
28256
- var list = (item, max) => max === void 0 ? external_exports.array(item) : external_exports.array(item).max(max);
28257
- var ENVIRONMENT_SETUP_AUTHORED_TRIGGER_TYPES = ["cron", "github", "gitlab"];
28258
- function isEnvironmentSetupAuthoredTriggerType(type) {
28259
- return ENVIRONMENT_SETUP_AUTHORED_TRIGGER_TYPES.some((authored) => authored === type);
28260
- }
28261
- var repositoryTriggerConfigSchema = external_exports.object({
28262
- event: external_exports.string(),
28263
- repository_ids: external_exports.array(external_exports.string().regex(UUID_RE, "must be a repository id")).optional(),
28264
- group_pr_events: external_exports.boolean().optional(),
28265
- excluded_actors: external_exports.array(external_exports.string()).optional()
28266
- });
28267
- var proposalTriggerSchema = external_exports.discriminatedUnion("type", [
28268
- external_exports.object({ type: external_exports.literal("cron"), config: external_exports.object({ schedule: external_exports.string(), timezone: external_exports.string().optional() }) }),
28269
- external_exports.object({ type: external_exports.literal("github"), config: repositoryTriggerConfigSchema }),
28270
- external_exports.object({ type: external_exports.literal("gitlab"), config: repositoryTriggerConfigSchema })
28271
- ]);
28272
- var existingTriggerSchema = external_exports.custom(
28273
- (value) => isRecord(value) && typeof value.type === "string" && isRecord(value.config),
28274
- "must be an automation trigger"
28275
- );
28276
- var carriedTriggerSchema = existingTriggerSchema.refine(
28277
- (trigger) => !isEnvironmentSetupAuthoredTriggerType(trigger.type)
28278
- );
28279
- function automationSchema(limits) {
28280
- const authored = external_exports.object({
28281
- name: text(limits.nameChars),
28282
- description: text(limits.descriptionChars),
28283
- prompt: text(limits.automationPromptChars),
28284
- triggers: list(proposalTriggerSchema, limits.automationTriggers)
28285
- });
28286
- const updated = authored.extend({ triggers: list(external_exports.union([proposalTriggerSchema, carriedTriggerSchema]), limits.automationTriggers) });
28287
- return external_exports.object({
28288
- key: requiredText(limits.automationKeyChars),
28289
- action: external_exports.enum(ENVIRONMENT_SETUP_AUTOMATION_ACTIONS).default("create"),
28290
- automation_id: external_exports.string().regex(UUID_RE, "must be an automation id").nullable().default(null),
28291
- name: text().default(""),
28292
- description: optionalText().transform((value) => value ?? ""),
28293
- prompt: text().default(""),
28294
- triggers: list(existingTriggerSchema).default([]),
28295
- note: optionalText(limits.automationNoteChars)
28296
- }).superRefine((automation2, ctx) => {
28297
- if (automation2.action === "create" && automation2.automation_id) {
28298
- ctx.addIssue({ code: "custom", path: ["automation_id"], message: "belongs on an update, keep, or disable entry" });
28299
- }
28300
- if (automation2.action !== "create" && !automation2.automation_id) {
28301
- ctx.addIssue({ code: "custom", path: ["automation_id"], message: "must be the id of an automation attached to this environment" });
28302
- }
28303
- if (automation2.action === "create" || automation2.action === "update") {
28304
- if (!automation2.name) ctx.addIssue({ code: "custom", path: ["name"], message: "must not be empty" });
28305
- if (!automation2.prompt) ctx.addIssue({ code: "custom", path: ["prompt"], message: "must not be empty" });
28306
- if (automation2.triggers.length === 0) ctx.addIssue({ code: "custom", path: ["triggers"], message: "must not be empty" });
28307
- }
28308
- }).transform((automation2, ctx) => {
28309
- if (automation2.action === "keep" || automation2.action === "disable") return automation2;
28310
- const content = (automation2.action === "update" ? updated : authored).safeParse(automation2);
28311
- if (content.success) return { ...automation2, ...content.data };
28312
- for (const issue2 of content.error.issues) ctx.addIssue({ ...issue2, code: "custom" });
28313
- return external_exports.NEVER;
28314
- });
28315
- }
28316
- function automationListSchema(limits) {
28317
- return list(automationSchema(limits)).default([]).superRefine((automations, ctx) => {
28318
- if (new Set(automations.map((automation2) => automation2.key)).size !== automations.length) {
28319
- ctx.addIssue({ code: "custom", message: "must have unique keys" });
28320
- }
28321
- const targets = automations.flatMap((automation2) => automation2.automation_id ?? []);
28322
- if (new Set(targets).size !== targets.length) {
28323
- ctx.addIssue({ code: "custom", message: "must mention each existing automation once" });
28324
- }
28325
- if (limits.automations !== void 0 && automations.filter((automation2) => automation2.action === "create").length > limits.automations) {
28326
- ctx.addIssue({ code: "custom", message: `must create at most ${limits.automations} new automations` });
28327
- }
28328
- });
28329
- }
28330
- function environmentSchema(limits) {
28331
- return external_exports.object({
28332
- name: optionalText(limits.nameChars).transform((value) => value ?? void 0),
28333
- description: clearableText(limits.descriptionChars),
28334
- system_prompt: clearableText(limits.systemPromptChars),
28335
- start_hook: clearableText(limits.hookChars),
28336
- warm_hook: clearableText(limits.hookChars)
28337
- });
28338
- }
28339
- function variableSchema(limits, requiredDefault) {
28340
- return external_exports.object({
28341
- key: external_exports.string().regex(VARIABLE_KEY_RE, "must be a valid environment variable name").max(limits.variableKeyChars ?? Number.POSITIVE_INFINITY),
28342
- description: optionalText(limits.variableDescriptionChars).transform((value) => value ?? ""),
28343
- required: external_exports.boolean().default(requiredDefault)
28344
- });
28345
- }
28346
- function proposalSchema(limits) {
28347
- return external_exports.object({
28348
- summary: requiredText(limits.summaryChars),
28349
- stack: list(text(), limits.stackItems).default([]).transform((items) => items.filter(Boolean)),
28350
- environment: environmentSchema(limits),
28351
- variables: list(variableSchema(limits, false), limits.variables).default([]),
28352
- automations: automationListSchema(limits),
28353
- verification: list(external_exports.object({
28354
- label: requiredText(limits.nameChars),
28355
- status: external_exports.enum(ENVIRONMENT_SETUP_VERIFICATION_STATUSES),
28356
- detail: optionalText(limits.verificationDetailChars).transform((value) => value ?? void 0)
28357
- }), limits.verificationItems).default([]),
28358
- media: list(external_exports.object({
28359
- media_id: external_exports.string().regex(UUID_RE, "must be a media id"),
28360
- title: requiredText(limits.nameChars)
28361
- }), limits.mediaItems).default([])
28362
- });
28363
- }
28364
- var environmentSetupProposalSchema = proposalSchema({});
28365
- var environmentSetupProposalSubmissionSchema = proposalSchema(ENVIRONMENT_SETUP_LIMITS);
28366
- var environmentSetupVariableRequestSchema = variableSchema({}, false).extend({
28367
- status: external_exports.enum(["pending", "provided", "skipped"]),
28368
- requested_at: external_exports.string(),
28369
- resolved_at: external_exports.string().nullable().default(null)
28370
- });
28371
- var environmentSetupRunStateSchema = external_exports.object({
28372
- status: external_exports.enum(ENVIRONMENT_SETUP_RUN_STATUSES),
28373
- steps: external_exports.partialRecord(external_exports.enum(ENVIRONMENT_SETUP_STEPS.map((step) => step.key)), external_exports.enum(ENVIRONMENT_SETUP_STEP_STATUSES)).default({}),
28374
- proposal: environmentSetupProposalSchema.nullable().default(null),
28375
- applied: external_exports.object({
28376
- applied_at: external_exports.string(),
28377
- automation_ids: external_exports.array(external_exports.string())
28378
- }).nullable().default(null),
28379
- variable_requests: external_exports.array(environmentSetupVariableRequestSchema).default([])
28380
- });
28381
- var applyEnvironmentSetupRequestSchema = external_exports.object({
28382
- environment: environmentSchema(ENVIRONMENT_SETUP_LIMITS).extend({ name: requiredText(ENVIRONMENT_SETUP_LIMITS.nameChars) }),
28383
- 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)),
28384
- automations: automationListSchema(ENVIRONMENT_SETUP_LIMITS)
28385
- });
28386
- var requestEnvironmentSetupVariablesSchema = external_exports.object({
28387
- variables: list(variableSchema(ENVIRONMENT_SETUP_LIMITS, true), ENVIRONMENT_SETUP_LIMITS.variables).min(1, "must not be empty")
28388
- }).superRefine(({ variables }, ctx) => {
28389
- if (new Set(variables.map((variable) => variable.key)).size !== variables.length) {
28390
- ctx.addIssue({ code: "custom", path: ["variables"], message: "must have unique keys" });
28391
- }
28392
- });
28393
- var respondEnvironmentSetupVariablesSchema = external_exports.object({
28394
- values: external_exports.record(external_exports.string().regex(VARIABLE_KEY_RE), external_exports.string()).default({}),
28395
- skipped: external_exports.array(external_exports.string().regex(VARIABLE_KEY_RE)).default([])
28396
- });
28397
-
28398
28738
  // src/lib/monolith-url.ts
28399
28739
  var MONOLITH_URL = process.env.REPLICAS_MONOLITH_URL || process.env.MONOLITH_URL || "https://api.replicas.dev";
28400
28740
 
@@ -29569,7 +29909,7 @@ async function configListCommand() {
29569
29909
  var import_http2 = __toESM(require("http"));
29570
29910
  var import_url4 = require("url");
29571
29911
 
29572
- // src/lib/pkce.ts
29912
+ // ../shared/src/pkce.ts
29573
29913
  var import_crypto = require("crypto");
29574
29914
  function generatePkceCodes() {
29575
29915
  const verifierBytes = (0, import_crypto.randomBytes)(32);
@@ -29974,8 +30314,8 @@ async function claudeAuthCommand(options = {}) {
29974
30314
  var CLIENT_ID = "1031625952748946";
29975
30315
  var AUTH_URL = "https://auth.meta.com";
29976
30316
  var API_KEY_URL = "https://api.meta.ai/muse-code/key";
29977
- async function post(path6, body) {
29978
- return fetch(`${AUTH_URL}${path6}`, {
30317
+ async function post(path7, body) {
30318
+ return fetch(`${AUTH_URL}${path7}`, {
29979
30319
  method: "POST",
29980
30320
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
29981
30321
  body
@@ -30650,14 +30990,163 @@ Repositories (${response.repositories.length}):
30650
30990
  }
30651
30991
  }
30652
30992
 
30653
- // src/commands/automation.ts
30993
+ // src/commands/environment-setup.ts
30994
+ var import_fs4 = __toESM(require("fs"));
30995
+ var import_os3 = __toESM(require("os"));
30996
+ var import_path5 = __toESM(require("path"));
30654
30997
  var import_chalk19 = __toESM(require("chalk"));
30998
+ var STEP_KEYS = ENVIRONMENT_SETUP_STEPS.map((step) => step.key).join(", ");
30999
+ async function fetchCurrentRun() {
31000
+ ensureOrgApiAuthenticated();
31001
+ if (!isEnvironmentSetupWorkspace()) {
31002
+ throw new Error("environment-setup commands run inside a Replicas setup workspace");
31003
+ }
31004
+ return orgAuthenticatedFetch("/v1/environment-setups/current");
31005
+ }
31006
+ async function environmentSetupStatusCommand() {
31007
+ const { run, environment: environment2, repositories } = await fetchCurrentRun();
31008
+ console.log(import_chalk19.default.bold(`
31009
+ Environment setup: ${environment2.name}
31010
+ `));
31011
+ console.log(` Run: ${run.id}`);
31012
+ console.log(` Status: ${run.status}${run.error ? import_chalk19.default.red(` (${run.error})`) : ""}`);
31013
+ console.log(` Environment: ${environment2.id}`);
31014
+ console.log(` Repositories: ${repositories.map((repo) => `${repo.name} (${repo.default_branch})`).join(", ") || "none"}`);
31015
+ console.log("\n Steps:");
31016
+ for (const step of ENVIRONMENT_SETUP_STEPS) {
31017
+ const status = run.steps[step.key] ?? "pending";
31018
+ const marker = status === "completed" ? import_chalk19.default.green("\u2713") : status === "in_progress" ? import_chalk19.default.cyan("\u25B8") : status === "skipped" ? import_chalk19.default.gray("\u2013") : import_chalk19.default.gray("\u25CB");
31019
+ console.log(` ${marker} ${step.key.padEnd(11)} ${import_chalk19.default.gray(step.label)} ${import_chalk19.default.gray(`[${status}]`)}`);
31020
+ }
31021
+ if (run.variable_requests.length > 0) {
31022
+ console.log("\n Variables:");
31023
+ printVariableRequests(run.variable_requests);
31024
+ }
31025
+ console.log(run.proposal ? import_chalk19.default.gray("\n A proposal has been submitted. Run `propose` again to replace it.\n") : import_chalk19.default.gray("\n No proposal yet. Submit one with `replicas environment-setup propose --file <path>`.\n"));
31026
+ }
31027
+ async function environmentSetupStepCommand(key, status) {
31028
+ if (!isEnvironmentSetupStepKey(key)) {
31029
+ throw new Error(`Unknown step "${key}". Use one of: ${STEP_KEYS}`);
31030
+ }
31031
+ if (!isEnvironmentSetupStepStatus(status)) {
31032
+ throw new Error(`Unknown status "${status}". Use one of: ${ENVIRONMENT_SETUP_STEP_STATUSES.join(", ")}`);
31033
+ }
31034
+ const { run } = await fetchCurrentRun();
31035
+ const body = { steps: { [key]: status } };
31036
+ await orgAuthenticatedFetch(`/v1/environment-setups/${run.id}/steps`, {
31037
+ method: "POST",
31038
+ body
31039
+ });
31040
+ console.log(import_chalk19.default.green(`
31041
+ \u2713 ${key} \u2192 ${status}
31042
+ `));
31043
+ }
31044
+ function readJsonFile(file2, label) {
31045
+ try {
31046
+ return JSON.parse(import_fs4.default.readFileSync(file2, "utf8"));
31047
+ } catch (error51) {
31048
+ throw new Error(`Could not read ${label} JSON from ${file2}: ${error51 instanceof Error ? error51.message : String(error51)}`);
31049
+ }
31050
+ }
31051
+ async function environmentSetupProposeCommand(options) {
31052
+ const proposal = readJsonFile(options.file, "proposal");
31053
+ const { run } = await fetchCurrentRun();
31054
+ const result = await orgAuthenticatedFetch(`/v1/environment-setups/${run.id}/proposal`, {
31055
+ method: "POST",
31056
+ body: { proposal }
31057
+ });
31058
+ const submitted = result.run.proposal;
31059
+ console.log(import_chalk19.default.green("\n\u2713 Proposal submitted.\n"));
31060
+ if (submitted) {
31061
+ console.log(` Automations: ${submitted.automations.length}`);
31062
+ console.log(` Variables: ${submitted.variables.length}`);
31063
+ console.log(` Checks: ${submitted.verification.length}`);
31064
+ console.log(` Media: ${submitted.media.length}`);
31065
+ }
31066
+ console.log(import_chalk19.default.gray("\n The user reviews and saves it from the Environment panel; nothing has been applied yet.\n"));
31067
+ }
31068
+ var RUNTIME_ENV_FILE = import_path5.default.join(import_os3.default.homedir(), ".replicas", "runtime-env.sh");
31069
+ var EXPORTED_KEYS_FILE = import_path5.default.join(import_os3.default.homedir(), ".replicas", "environment-setup-exported-keys.json");
31070
+ function printVariableRequests(requests) {
31071
+ for (const request of requests) {
31072
+ const marker = request.status === "provided" ? import_chalk19.default.green("\u2713") : request.status === "skipped" ? import_chalk19.default.gray("\u2013") : import_chalk19.default.cyan("\u2026");
31073
+ console.log(` ${marker} ${request.key.padEnd(32)} ${import_chalk19.default.gray(`[${request.status}${request.required ? ", required" : ""}]`)}`);
31074
+ }
31075
+ }
31076
+ async function environmentSetupRequestVariablesCommand(options) {
31077
+ const request = readJsonFile(options.file, "variable request");
31078
+ const { run } = await fetchCurrentRun();
31079
+ const result = await orgAuthenticatedFetch(`/v1/environment-setups/${run.id}/variable-requests`, {
31080
+ method: "POST",
31081
+ body: request
31082
+ });
31083
+ console.log(import_chalk19.default.green("\n\u2713 Variables requested.\n"));
31084
+ printVariableRequests(result.run.variable_requests);
31085
+ console.log(import_chalk19.default.gray("\n The user sees this in the Environment panel. Keep working and run `replicas environment-setup wait-variables` when you need a value.\n"));
31086
+ }
31087
+ function parseWaitTimeoutMs(raw) {
31088
+ if (!raw) return ENVIRONMENT_SETUP_VARIABLE_WAIT.defaultMs;
31089
+ const match = /^(\d+)(s|m)?$/.exec(raw.trim());
31090
+ if (!match) throw new Error(`Invalid timeout "${raw}". Use seconds or minutes, for example 90s or 5m`);
31091
+ const ms = Number(match[1]) * (match[2] === "m" ? 6e4 : 1e3);
31092
+ return Math.min(Math.max(ms, ENVIRONMENT_SETUP_VARIABLE_WAIT.pollMs), ENVIRONMENT_SETUP_VARIABLE_WAIT.maxMs);
31093
+ }
31094
+ function exportToRuntimeEnv(variables) {
31095
+ import_fs4.default.mkdirSync(import_path5.default.dirname(RUNTIME_ENV_FILE), { recursive: true });
31096
+ const existing = import_fs4.default.existsSync(RUNTIME_ENV_FILE) ? import_fs4.default.readFileSync(RUNTIME_ENV_FILE, "utf8") : "";
31097
+ const exportedKeys = import_fs4.default.existsSync(EXPORTED_KEYS_FILE) ? JSON.parse(import_fs4.default.readFileSync(EXPORTED_KEYS_FILE, "utf8")) : [];
31098
+ const owned = new Set(Array.isArray(exportedKeys) ? exportedKeys.filter(isNonEmptyString) : []);
31099
+ const env = parsePosixEnvFile(existing);
31100
+ for (const key of owned) delete env[key];
31101
+ const exported = variables.filter((variable) => !variable.key.startsWith("REPLICAS_"));
31102
+ for (const variable of exported) env[variable.key] = variable.value;
31103
+ const unsetKeys = new Set([...parsePosixEnvUnsetKeys(existing), ...owned].filter((key) => !env[key]));
31104
+ const content = serializePosixEnvFile(env, unsetKeys);
31105
+ if (content !== existing) {
31106
+ import_fs4.default.writeFileSync(RUNTIME_ENV_FILE, content, { mode: 384 });
31107
+ import_fs4.default.chmodSync(RUNTIME_ENV_FILE, 384);
31108
+ }
31109
+ import_fs4.default.writeFileSync(EXPORTED_KEYS_FILE, JSON.stringify(exported.map((variable) => variable.key)), { mode: 384 });
31110
+ return exported.map((variable) => variable.key);
31111
+ }
31112
+ var formatDuration = (ms) => ms >= 6e4 ? `${Math.round(ms / 6e4)} minute(s)` : `${Math.round(ms / 1e3)} seconds`;
31113
+ async function environmentSetupWaitVariablesCommand(options) {
31114
+ const timeoutMs = parseWaitTimeoutMs(options.timeout);
31115
+ const wanted = options.keys ? new Set(options.keys.split(",").map((key) => key.trim()).filter(Boolean)) : null;
31116
+ const blocking = (requests) => requests.filter((request) => request.status === "pending" && (wanted ? wanted.has(request.key) : request.required));
31117
+ let { run } = await fetchCurrentRun();
31118
+ const before = run.variable_requests;
31119
+ if (blocking(before).length > 0) {
31120
+ console.log(import_chalk19.default.gray(`
31121
+ Waiting up to ${formatDuration(timeoutMs)} for: ${blocking(before).map((request) => request.key).join(", ")}`));
31122
+ const deadline = Date.now() + timeoutMs;
31123
+ while (blocking(run.variable_requests).length > 0 && Date.now() < deadline) {
31124
+ await new Promise((resolve2) => setTimeout(resolve2, ENVIRONMENT_SETUP_VARIABLE_WAIT.pollMs));
31125
+ run = (await fetchCurrentRun()).run;
31126
+ }
31127
+ }
31128
+ const { variables } = await orgAuthenticatedFetch("/v1/environment-setups/current/variables");
31129
+ const exported = exportToRuntimeEnv(variables);
31130
+ const reserved = variables.map((variable) => variable.key).filter((key) => !exported.includes(key));
31131
+ const byStatus = (status) => run.variable_requests.filter((request) => request.status === status).map((request) => request.key);
31132
+ const timedOut = blocking(run.variable_requests).map((request) => request.key);
31133
+ console.log("");
31134
+ if (exported.length > 0) console.log(` ${import_chalk19.default.green("Available in new shells:")} ${exported.join(", ")}`);
31135
+ if (reserved.length > 0) console.log(` ${import_chalk19.default.yellow("Reserved by Replicas:")} ${reserved.join(", ")} (reserved names, not exported; rename these in the proposal)`);
31136
+ if (byStatus("skipped").length > 0) console.log(` ${import_chalk19.default.gray("Skipped by the user:")} ${byStatus("skipped").join(", ")}`);
31137
+ if (timedOut.length > 0) console.log(` ${import_chalk19.default.yellow("Not answered in time:")} ${timedOut.join(", ")}`);
31138
+ if (variables.length === 0 && byStatus("skipped").length === 0 && timedOut.length === 0) console.log(import_chalk19.default.gray(" No variables were requested."));
31139
+ console.log(import_chalk19.default.gray("\n Values are never printed. Restart services you started before this command so they pick the variables up. Use a local substitute for anything skipped or unanswered and list it as required in the proposal.\n"));
31140
+ }
31141
+
31142
+ // src/commands/automation.ts
31143
+ var import_chalk20 = __toESM(require("chalk"));
30655
31144
  var import_prompts7 = __toESM(require("prompts"));
30656
31145
  function parseScopeFilter(value) {
30657
31146
  if (!value) return void 0;
30658
31147
  if (value === "org" || value === "user" || value === "all") return value;
30659
- console.log(import_chalk19.default.red(`Invalid --owner: ${value}`));
30660
- console.log(import_chalk19.default.gray("Valid options: org, user, all"));
31148
+ console.log(import_chalk20.default.red(`Invalid --owner: ${value}`));
31149
+ console.log(import_chalk20.default.gray("Valid options: org, user, all"));
30661
31150
  process.exit(1);
30662
31151
  }
30663
31152
  function parseAgentProviderOption(value) {
@@ -30666,8 +31155,8 @@ function parseAgentProviderOption(value) {
30666
31155
  if (trimmed === "" || trimmed.toLowerCase() === "none") return null;
30667
31156
  const lower = trimmed.toLowerCase();
30668
31157
  if (!isValidAgentProvider(lower)) {
30669
- console.log(import_chalk19.default.red(`Invalid --agent-provider: ${value}`));
30670
- console.log(import_chalk19.default.gray(`Valid options: ${VALID_AGENT_PROVIDERS.join(", ")}, none`));
31158
+ console.log(import_chalk20.default.red(`Invalid --agent-provider: ${value}`));
31159
+ console.log(import_chalk20.default.gray(`Valid options: ${VALID_AGENT_PROVIDERS.join(", ")}, none`));
30671
31160
  process.exit(1);
30672
31161
  }
30673
31162
  return lower;
@@ -30678,8 +31167,8 @@ function parseThinkingLevelOption(value) {
30678
31167
  if (trimmed === "" || trimmed.toLowerCase() === "none") return null;
30679
31168
  const lower = trimmed.toLowerCase();
30680
31169
  if (!isValidThinkingLevel(lower)) {
30681
- console.log(import_chalk19.default.red(`Invalid --thinking-level: ${value}`));
30682
- console.log(import_chalk19.default.gray(`Valid options: ${VALID_THINKING_LEVELS.join(", ")}, none`));
31170
+ console.log(import_chalk20.default.red(`Invalid --thinking-level: ${value}`));
31171
+ console.log(import_chalk20.default.gray(`Valid options: ${VALID_THINKING_LEVELS.join(", ")}, none`));
30683
31172
  process.exit(1);
30684
31173
  }
30685
31174
  return lower;
@@ -30696,8 +31185,8 @@ function isAutomationLifecyclePolicy(value) {
30696
31185
  function parseWorkspaceLifecyclePolicyOption(value) {
30697
31186
  if (!value) return void 0;
30698
31187
  if (isAutomationLifecyclePolicy(value)) return value;
30699
- console.log(import_chalk19.default.red(`Invalid lifecycle policy: ${value}`));
30700
- console.log(import_chalk19.default.gray(`Valid options: ${AUTOMATION_LIFECYCLE_POLICIES.join(", ")}`));
31188
+ console.log(import_chalk20.default.red(`Invalid lifecycle policy: ${value}`));
31189
+ console.log(import_chalk20.default.gray(`Valid options: ${AUTOMATION_LIFECYCLE_POLICIES.join(", ")}`));
30701
31190
  process.exit(1);
30702
31191
  }
30703
31192
  function parseExcludedActorsOption(value) {
@@ -30716,7 +31205,7 @@ function withExcludedActors(config3, excludedActors) {
30716
31205
  }
30717
31206
  function parseAutomationLifecycleOptions(options) {
30718
31207
  if (options.sleepWhenDone && options.lifecycle && options.lifecycle !== "sleep_when_done") {
30719
- console.log(import_chalk19.default.red("--sleep-when-done cannot be combined with a different --lifecycle value"));
31208
+ console.log(import_chalk20.default.red("--sleep-when-done cannot be combined with a different --lifecycle value"));
30720
31209
  process.exit(1);
30721
31210
  }
30722
31211
  if (options.sleepWhenDone) return "sleep_when_done";
@@ -30725,7 +31214,7 @@ function parseAutomationLifecycleOptions(options) {
30725
31214
  function applyAgentSelection(body, existing) {
30726
31215
  const result = validateAgentSelection(body, existing, AGENT_MODELS);
30727
31216
  if (!result.ok) {
30728
- console.log(import_chalk19.default.red(result.error.message));
31217
+ console.log(import_chalk20.default.red(result.error.message));
30729
31218
  process.exit(1);
30730
31219
  }
30731
31220
  const out = {};
@@ -30766,8 +31255,8 @@ function resolveTriggerRepositoryIds(repositories, repoNamesInput, provider) {
30766
31255
  for (const repoName of repoNames) {
30767
31256
  const repo = providerRepos.find((r) => r.name === repoName);
30768
31257
  if (!repo) {
30769
- console.log(import_chalk19.default.red(`Repository not found for ${provider} trigger filter: ${repoName}`));
30770
- console.log(import_chalk19.default.gray(`Available: ${providerRepos.map((r) => r.name).join(", ")}`));
31258
+ console.log(import_chalk20.default.red(`Repository not found for ${provider} trigger filter: ${repoName}`));
31259
+ console.log(import_chalk20.default.gray(`Available: ${providerRepos.map((r) => r.name).join(", ")}`));
30771
31260
  process.exit(1);
30772
31261
  }
30773
31262
  repoIds.push(repo.id);
@@ -30800,43 +31289,43 @@ function formatModeSummary(automation2) {
30800
31289
  function resolveSelectableEnvironmentId(envInput, selectableEnvs) {
30801
31290
  const resolved = resolveByNameOrId(envInput, selectableEnvs);
30802
31291
  if (!resolved) {
30803
- console.log(import_chalk19.default.red(`Environment not found: ${envInput}`));
31292
+ console.log(import_chalk20.default.red(`Environment not found: ${envInput}`));
30804
31293
  const available = selectableEnvs.map((e) => e.name).join(", ");
30805
- console.log(import_chalk19.default.gray(`Available: ${available || "(none)"}`));
31294
+ console.log(import_chalk20.default.gray(`Available: ${available || "(none)"}`));
30806
31295
  process.exit(1);
30807
31296
  }
30808
31297
  return resolved.id;
30809
31298
  }
30810
31299
  function printAutomation(automation2) {
30811
- console.log(import_chalk19.default.white(` ${automation2.name}`));
30812
- console.log(import_chalk19.default.gray(` ID: ${automation2.id}`));
30813
- console.log(import_chalk19.default.gray(` Owner: ${automation2.user_id ? "personal" : "organization"}`));
31300
+ console.log(import_chalk20.default.white(` ${automation2.name}`));
31301
+ console.log(import_chalk20.default.gray(` ID: ${automation2.id}`));
31302
+ console.log(import_chalk20.default.gray(` Owner: ${automation2.user_id ? "personal" : "organization"}`));
30814
31303
  if (automation2.description) {
30815
- console.log(import_chalk19.default.gray(` Description: ${automation2.description}`));
31304
+ console.log(import_chalk20.default.gray(` Description: ${automation2.description}`));
30816
31305
  }
30817
- console.log(import_chalk19.default.gray(` Enabled: ${automation2.enabled ? import_chalk19.default.green("yes") : import_chalk19.default.red("no")}`));
31306
+ console.log(import_chalk20.default.gray(` Enabled: ${automation2.enabled ? import_chalk20.default.green("yes") : import_chalk20.default.red("no")}`));
30818
31307
  if (automation2.triggers.length > 0) {
30819
- console.log(import_chalk19.default.gray(` Triggers: ${automation2.triggers.map(formatTrigger).join(", ")}`));
31308
+ console.log(import_chalk20.default.gray(` Triggers: ${automation2.triggers.map(formatTrigger).join(", ")}`));
30820
31309
  }
30821
31310
  if (automation2.github_check_names.length > 0) {
30822
- console.log(import_chalk19.default.gray(` GitHub checks: ${automation2.github_check_names.join(", ")}`));
31311
+ console.log(import_chalk20.default.gray(` GitHub checks: ${automation2.github_check_names.join(", ")}`));
30823
31312
  }
30824
- console.log(import_chalk19.default.gray(` Prompt: ${truncate2(automation2.prompt, 80)}`));
31313
+ console.log(import_chalk20.default.gray(` Prompt: ${truncate2(automation2.prompt, 80)}`));
30825
31314
  if (automation2.cron_next_fire_at) {
30826
- console.log(import_chalk19.default.gray(` Next Run: ${formatDate2(automation2.cron_next_fire_at)}`));
31315
+ console.log(import_chalk20.default.gray(` Next Run: ${formatDate2(automation2.cron_next_fire_at)}`));
30827
31316
  }
30828
31317
  if (automation2.workspace_lifecycle_policy && automation2.workspace_lifecycle_policy !== "default") {
30829
- console.log(import_chalk19.default.gray(` Lifecycle: ${automation2.workspace_lifecycle_policy}`));
31318
+ console.log(import_chalk20.default.gray(` Lifecycle: ${automation2.workspace_lifecycle_policy}`));
30830
31319
  }
30831
31320
  if (automation2.agent_provider || automation2.model || automation2.thinking_level) {
30832
- console.log(import_chalk19.default.gray(` Agent: ${formatAgentSummary(automation2)}`));
31321
+ console.log(import_chalk20.default.gray(` Agent: ${formatAgentSummary(automation2)}`));
30833
31322
  }
30834
31323
  if (automation2.plan_mode || automation2.goal_mode || automation2.fast_mode) {
30835
- console.log(import_chalk19.default.gray(` Modes: ${formatModeSummary(automation2)}`));
31324
+ console.log(import_chalk20.default.gray(` Modes: ${formatModeSummary(automation2)}`));
30836
31325
  }
30837
- console.log(import_chalk19.default.gray(` PR Follow-ups: ${automation2.config.capabilities?.pr_followups === true ? import_chalk19.default.green("managed") : "read-only"}`));
30838
- console.log(import_chalk19.default.gray(` Created: ${formatDate2(automation2.created_at)}`));
30839
- console.log(import_chalk19.default.gray(` Updated: ${formatDate2(automation2.updated_at)}`));
31326
+ console.log(import_chalk20.default.gray(` PR Follow-ups: ${automation2.config.capabilities?.pr_followups === true ? import_chalk20.default.green("managed") : "read-only"}`));
31327
+ console.log(import_chalk20.default.gray(` Created: ${formatDate2(automation2.created_at)}`));
31328
+ console.log(import_chalk20.default.gray(` Updated: ${formatDate2(automation2.updated_at)}`));
30840
31329
  console.log();
30841
31330
  }
30842
31331
  async function automationListCommand(options) {
@@ -30855,17 +31344,17 @@ async function automationListCommand(options) {
30855
31344
  `/v1/automations${query ? "?" + query : ""}`
30856
31345
  );
30857
31346
  if (response.automations.length === 0) {
30858
- console.log(import_chalk19.default.yellow("\nNo automations found.\n"));
31347
+ console.log(import_chalk20.default.yellow("\nNo automations found.\n"));
30859
31348
  return;
30860
31349
  }
30861
- console.log(import_chalk19.default.green(`
31350
+ console.log(import_chalk20.default.green(`
30862
31351
  Automations (Page ${response.page} of ${response.totalPages}, Total: ${response.total}):
30863
31352
  `));
30864
31353
  for (const automation2 of response.automations) {
30865
31354
  printAutomation(automation2);
30866
31355
  }
30867
31356
  } catch (error51) {
30868
- console.error(import_chalk19.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
31357
+ console.error(import_chalk20.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
30869
31358
  process.exit(1);
30870
31359
  }
30871
31360
  }
@@ -30874,50 +31363,50 @@ async function automationGetCommand(id) {
30874
31363
  try {
30875
31364
  const response = await orgAuthenticatedFetch(`/v1/automations/${id}`);
30876
31365
  const automation2 = response.automation;
30877
- console.log(import_chalk19.default.green(`
31366
+ console.log(import_chalk20.default.green(`
30878
31367
  Automation: ${automation2.name}
30879
31368
  `));
30880
- console.log(import_chalk19.default.gray(` ID: ${automation2.id}`));
31369
+ console.log(import_chalk20.default.gray(` ID: ${automation2.id}`));
30881
31370
  if (automation2.description) {
30882
- console.log(import_chalk19.default.gray(` Description: ${automation2.description}`));
31371
+ console.log(import_chalk20.default.gray(` Description: ${automation2.description}`));
30883
31372
  }
30884
- console.log(import_chalk19.default.gray(` Enabled: ${automation2.enabled ? import_chalk19.default.green("yes") : import_chalk19.default.red("no")}`));
31373
+ console.log(import_chalk20.default.gray(` Enabled: ${automation2.enabled ? import_chalk20.default.green("yes") : import_chalk20.default.red("no")}`));
30885
31374
  if (automation2.triggers.length > 0) {
30886
- console.log(import_chalk19.default.gray(` Triggers:`));
31375
+ console.log(import_chalk20.default.gray(` Triggers:`));
30887
31376
  for (const trigger of automation2.triggers) {
30888
- console.log(import_chalk19.default.gray(` - ${formatTrigger(trigger)}`));
31377
+ console.log(import_chalk20.default.gray(` - ${formatTrigger(trigger)}`));
30889
31378
  }
30890
31379
  }
30891
31380
  if (automation2.github_check_names.length > 0) {
30892
- console.log(import_chalk19.default.gray(` GitHub checks: ${automation2.github_check_names.join(", ")}`));
31381
+ console.log(import_chalk20.default.gray(` GitHub checks: ${automation2.github_check_names.join(", ")}`));
30893
31382
  }
30894
- console.log(import_chalk19.default.gray(` Prompt: ${automation2.prompt}`));
30895
- console.log(import_chalk19.default.gray(` Environment: ${automation2.environment_id}`));
31383
+ console.log(import_chalk20.default.gray(` Prompt: ${automation2.prompt}`));
31384
+ console.log(import_chalk20.default.gray(` Environment: ${automation2.environment_id}`));
30896
31385
  if (automation2.cron_expression) {
30897
- console.log(import_chalk19.default.gray(` Cron: ${automation2.cron_expression}`));
31386
+ console.log(import_chalk20.default.gray(` Cron: ${automation2.cron_expression}`));
30898
31387
  }
30899
31388
  if (automation2.cron_timezone) {
30900
- console.log(import_chalk19.default.gray(` Timezone: ${automation2.cron_timezone}`));
31389
+ console.log(import_chalk20.default.gray(` Timezone: ${automation2.cron_timezone}`));
30901
31390
  }
30902
31391
  if (automation2.cron_next_fire_at) {
30903
- console.log(import_chalk19.default.gray(` Next Run: ${formatDate2(automation2.cron_next_fire_at)}`));
31392
+ console.log(import_chalk20.default.gray(` Next Run: ${formatDate2(automation2.cron_next_fire_at)}`));
30904
31393
  }
30905
31394
  if (automation2.workspace_lifecycle_policy) {
30906
- console.log(import_chalk19.default.gray(` Lifecycle Policy: ${automation2.workspace_lifecycle_policy}`));
31395
+ console.log(import_chalk20.default.gray(` Lifecycle Policy: ${automation2.workspace_lifecycle_policy}`));
30907
31396
  }
30908
31397
  if (automation2.workspace_auto_stop_minutes) {
30909
- console.log(import_chalk19.default.gray(` Auto-stop: ${automation2.workspace_auto_stop_minutes} minutes`));
30910
- }
30911
- console.log(import_chalk19.default.gray(` Agent: ${automation2.agent_provider ? getProviderDisplayName(automation2.agent_provider) : "organization default"}`));
30912
- console.log(import_chalk19.default.gray(` Model: ${automation2.model ? MODEL_LABELS[automation2.model] ?? automation2.model : "agent default"}`));
30913
- console.log(import_chalk19.default.gray(` Thinking Level: ${automation2.thinking_level ?? "agent default"}`));
30914
- console.log(import_chalk19.default.gray(` Modes: ${formatModeSummary(automation2)}`));
30915
- console.log(import_chalk19.default.gray(` PR Follow-ups: ${automation2.config.capabilities?.pr_followups === true ? "managed" : "read-only"}`));
30916
- console.log(import_chalk19.default.gray(` Created: ${formatDate2(automation2.created_at)}`));
30917
- console.log(import_chalk19.default.gray(` Updated: ${formatDate2(automation2.updated_at)}`));
31398
+ console.log(import_chalk20.default.gray(` Auto-stop: ${automation2.workspace_auto_stop_minutes} minutes`));
31399
+ }
31400
+ console.log(import_chalk20.default.gray(` Agent: ${automation2.agent_provider ? getProviderDisplayName(automation2.agent_provider) : "organization default"}`));
31401
+ console.log(import_chalk20.default.gray(` Model: ${automation2.model ? MODEL_LABELS[automation2.model] ?? automation2.model : "agent default"}`));
31402
+ console.log(import_chalk20.default.gray(` Thinking Level: ${automation2.thinking_level ?? "agent default"}`));
31403
+ console.log(import_chalk20.default.gray(` Modes: ${formatModeSummary(automation2)}`));
31404
+ console.log(import_chalk20.default.gray(` PR Follow-ups: ${automation2.config.capabilities?.pr_followups === true ? "managed" : "read-only"}`));
31405
+ console.log(import_chalk20.default.gray(` Created: ${formatDate2(automation2.created_at)}`));
31406
+ console.log(import_chalk20.default.gray(` Updated: ${formatDate2(automation2.updated_at)}`));
30918
31407
  console.log();
30919
31408
  } catch (error51) {
30920
- console.error(import_chalk19.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
31409
+ console.error(import_chalk20.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
30921
31410
  process.exit(1);
30922
31411
  }
30923
31412
  }
@@ -31042,22 +31531,22 @@ async function automationCreateCommand(name, options) {
31042
31531
  ensureOrgApiAuthenticated();
31043
31532
  const lifecyclePolicy = parseAutomationLifecycleOptions(options);
31044
31533
  if (options.autoStopMinutes && !lifecyclePolicySupportsAutoStop(lifecyclePolicy ?? "default")) {
31045
- console.log(import_chalk19.default.red("--auto-stop-minutes requires --lifecycle default"));
31534
+ console.log(import_chalk20.default.red("--auto-stop-minutes requires --lifecycle default"));
31046
31535
  process.exit(1);
31047
31536
  }
31048
31537
  if (options.autoStopMinutes) {
31049
31538
  const minutes = parseInt(options.autoStopMinutes, 10);
31050
31539
  if (isNaN(minutes) || minutes < 3 || minutes > 1440) {
31051
- console.log(import_chalk19.default.red("--auto-stop-minutes must be between 3 and 1440"));
31540
+ console.log(import_chalk20.default.red("--auto-stop-minutes must be between 3 and 1440"));
31052
31541
  process.exit(1);
31053
31542
  }
31054
31543
  }
31055
31544
  if (options.triggerGithubExcludeUsers !== void 0 && !options.triggerGithub) {
31056
- console.log(import_chalk19.default.red("--trigger-github-exclude-users requires --trigger-github"));
31545
+ console.log(import_chalk20.default.red("--trigger-github-exclude-users requires --trigger-github"));
31057
31546
  process.exit(1);
31058
31547
  }
31059
31548
  if (options.triggerGitlabExcludeUsers !== void 0 && !options.triggerGitlab) {
31060
- console.log(import_chalk19.default.red("--trigger-gitlab-exclude-users requires --trigger-gitlab"));
31549
+ console.log(import_chalk20.default.red("--trigger-gitlab-exclude-users requires --trigger-gitlab"));
31061
31550
  process.exit(1);
31062
31551
  }
31063
31552
  const hasConfirmation = options.confirmationChannel || options.confirmationThread || options.confirmationMessageTs || options.confirmationUser;
@@ -31084,7 +31573,7 @@ async function automationCreateCommand(name, options) {
31084
31573
  );
31085
31574
  const selectableEnvs = envResponse.environments;
31086
31575
  if (selectableEnvs.length === 0) {
31087
- console.log(import_chalk19.default.red("No environments found. Please create an environment first."));
31576
+ console.log(import_chalk20.default.red("No environments found. Please create an environment first."));
31088
31577
  process.exit(1);
31089
31578
  }
31090
31579
  const repoResponse = await orgAuthenticatedFetch("/v1/repositories");
@@ -31098,7 +31587,7 @@ async function automationCreateCommand(name, options) {
31098
31587
  validate: (value) => value.trim() ? true : "Name is required"
31099
31588
  });
31100
31589
  if (!response2.name) {
31101
- console.log(import_chalk19.default.yellow("\nCancelled."));
31590
+ console.log(import_chalk20.default.yellow("\nCancelled."));
31102
31591
  return;
31103
31592
  }
31104
31593
  automationName = response2.name;
@@ -31112,7 +31601,7 @@ async function automationCreateCommand(name, options) {
31112
31601
  validate: (value) => value.trim() ? true : "Prompt is required"
31113
31602
  });
31114
31603
  if (!response2.prompt) {
31115
- console.log(import_chalk19.default.yellow("\nCancelled."));
31604
+ console.log(import_chalk20.default.yellow("\nCancelled."));
31116
31605
  return;
31117
31606
  }
31118
31607
  automationPrompt = response2.prompt;
@@ -31132,7 +31621,7 @@ async function automationCreateCommand(name, options) {
31132
31621
  }))
31133
31622
  });
31134
31623
  if (!envResponse2.env) {
31135
- console.log(import_chalk19.default.yellow("\nCancelled."));
31624
+ console.log(import_chalk20.default.yellow("\nCancelled."));
31136
31625
  return;
31137
31626
  }
31138
31627
  selectedEnvironmentId = envResponse2.env;
@@ -31174,7 +31663,7 @@ async function automationCreateCommand(name, options) {
31174
31663
  if (triggers.length === 0) {
31175
31664
  triggers = await promptForTriggers(repositories.map((r) => ({ id: r.id, name: r.name, provider: r.provider })));
31176
31665
  if (triggers.length === 0) {
31177
- console.log(import_chalk19.default.red("At least one trigger is required."));
31666
+ console.log(import_chalk20.default.red("At least one trigger is required."));
31178
31667
  process.exit(1);
31179
31668
  }
31180
31669
  }
@@ -31205,25 +31694,25 @@ async function automationCreateCommand(name, options) {
31205
31694
  ...agentSelection,
31206
31695
  ...mothershipConfirmation ? { mothership_confirmation: mothershipConfirmation } : {}
31207
31696
  };
31208
- console.log(import_chalk19.default.gray("\nCreating automation..."));
31697
+ console.log(import_chalk20.default.gray("\nCreating automation..."));
31209
31698
  const response = await orgAuthenticatedFetch("/v1/automations", {
31210
31699
  method: "POST",
31211
31700
  body
31212
31701
  });
31213
31702
  const automation2 = response.automation;
31214
- console.log(import_chalk19.default.green(`
31703
+ console.log(import_chalk20.default.green(`
31215
31704
  Created automation: ${automation2.name}`));
31216
- console.log(import_chalk19.default.gray(` ID: ${automation2.id}`));
31217
- console.log(import_chalk19.default.gray(` Enabled: ${automation2.enabled ? "yes" : "no"}`));
31705
+ console.log(import_chalk20.default.gray(` ID: ${automation2.id}`));
31706
+ console.log(import_chalk20.default.gray(` Enabled: ${automation2.enabled ? "yes" : "no"}`));
31218
31707
  if (automation2.triggers.length > 0) {
31219
- console.log(import_chalk19.default.gray(` Triggers: ${automation2.triggers.map(formatTrigger).join(", ")}`));
31708
+ console.log(import_chalk20.default.gray(` Triggers: ${automation2.triggers.map(formatTrigger).join(", ")}`));
31220
31709
  }
31221
31710
  if (automation2.cron_next_fire_at) {
31222
- console.log(import_chalk19.default.gray(` Next Run: ${formatDate2(automation2.cron_next_fire_at)}`));
31711
+ console.log(import_chalk20.default.gray(` Next Run: ${formatDate2(automation2.cron_next_fire_at)}`));
31223
31712
  }
31224
31713
  console.log();
31225
31714
  } catch (error51) {
31226
- console.error(import_chalk19.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
31715
+ console.error(import_chalk20.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
31227
31716
  process.exit(1);
31228
31717
  }
31229
31718
  }
@@ -31233,17 +31722,17 @@ async function automationEditCommand(id, options) {
31233
31722
  if (options.autoStopMinutes) {
31234
31723
  const minutes = parseInt(options.autoStopMinutes, 10);
31235
31724
  if (isNaN(minutes) || minutes < 3 || minutes > 1440) {
31236
- console.log(import_chalk19.default.red("--auto-stop-minutes must be between 3 and 1440"));
31725
+ console.log(import_chalk20.default.red("--auto-stop-minutes must be between 3 and 1440"));
31237
31726
  process.exit(1);
31238
31727
  }
31239
31728
  }
31240
31729
  const replacingTriggers = Boolean(options.triggerCron || options.triggerGithub || options.triggerGitlab);
31241
31730
  if (replacingTriggers && options.triggerGithubExcludeUsers !== void 0 && !options.triggerGithub) {
31242
- console.log(import_chalk19.default.red("--trigger-github-exclude-users requires --trigger-github when replacing triggers"));
31731
+ console.log(import_chalk20.default.red("--trigger-github-exclude-users requires --trigger-github when replacing triggers"));
31243
31732
  process.exit(1);
31244
31733
  }
31245
31734
  if (replacingTriggers && options.triggerGitlabExcludeUsers !== void 0 && !options.triggerGitlab) {
31246
- console.log(import_chalk19.default.red("--trigger-gitlab-exclude-users requires --trigger-gitlab when replacing triggers"));
31735
+ console.log(import_chalk20.default.red("--trigger-gitlab-exclude-users requires --trigger-gitlab when replacing triggers"));
31247
31736
  process.exit(1);
31248
31737
  }
31249
31738
  const parsedAgent = {
@@ -31255,7 +31744,7 @@ async function automationEditCommand(id, options) {
31255
31744
  const existing = await orgAuthenticatedFetch(`/v1/automations/${id}`);
31256
31745
  const autoStopLifecyclePolicy = lifecyclePolicy ?? toAutomationLifecyclePolicy(existing.automation.workspace_lifecycle_policy);
31257
31746
  if (options.autoStopMinutes && !lifecyclePolicySupportsAutoStop(autoStopLifecyclePolicy)) {
31258
- console.log(import_chalk19.default.red("--auto-stop-minutes requires --lifecycle default"));
31747
+ console.log(import_chalk20.default.red("--auto-stop-minutes requires --lifecycle default"));
31259
31748
  process.exit(1);
31260
31749
  }
31261
31750
  const agentSelection = applyAgentSelection(parsedAgent, {
@@ -31395,11 +31884,11 @@ async function automationEditCommand(id, options) {
31395
31884
  return trigger;
31396
31885
  });
31397
31886
  if (!matchedGithub) {
31398
- console.log(import_chalk19.default.red("No existing GitHub trigger found. Pass --trigger-github to create one."));
31887
+ console.log(import_chalk20.default.red("No existing GitHub trigger found. Pass --trigger-github to create one."));
31399
31888
  process.exit(1);
31400
31889
  }
31401
31890
  if (!matchedGitlab) {
31402
- console.log(import_chalk19.default.red("No existing GitLab trigger found. Pass --trigger-gitlab to create one."));
31891
+ console.log(import_chalk20.default.red("No existing GitLab trigger found. Pass --trigger-gitlab to create one."));
31403
31892
  process.exit(1);
31404
31893
  }
31405
31894
  }
@@ -31424,25 +31913,25 @@ async function automationEditCommand(id, options) {
31424
31913
  Object.assign(body, agentSelection);
31425
31914
  }
31426
31915
  if (Object.keys(body).length === 0) {
31427
- console.log(import_chalk19.default.yellow("\nNo changes made.\n"));
31916
+ console.log(import_chalk20.default.yellow("\nNo changes made.\n"));
31428
31917
  return;
31429
31918
  }
31430
- console.log(import_chalk19.default.gray("\nUpdating automation..."));
31919
+ console.log(import_chalk20.default.gray("\nUpdating automation..."));
31431
31920
  const response = await orgAuthenticatedFetch(`/v1/automations/${id}`, {
31432
31921
  method: "PATCH",
31433
31922
  body
31434
31923
  });
31435
31924
  const automation2 = response.automation;
31436
- console.log(import_chalk19.default.green(`
31925
+ console.log(import_chalk20.default.green(`
31437
31926
  Updated automation: ${automation2.name}`));
31438
- console.log(import_chalk19.default.gray(` ID: ${automation2.id}`));
31439
- console.log(import_chalk19.default.gray(` Enabled: ${automation2.enabled ? "yes" : "no"}`));
31927
+ console.log(import_chalk20.default.gray(` ID: ${automation2.id}`));
31928
+ console.log(import_chalk20.default.gray(` Enabled: ${automation2.enabled ? "yes" : "no"}`));
31440
31929
  if (automation2.triggers.length > 0) {
31441
- console.log(import_chalk19.default.gray(` Triggers: ${automation2.triggers.map(formatTrigger).join(", ")}`));
31930
+ console.log(import_chalk20.default.gray(` Triggers: ${automation2.triggers.map(formatTrigger).join(", ")}`));
31442
31931
  }
31443
31932
  console.log();
31444
31933
  } catch (error51) {
31445
- console.error(import_chalk19.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
31934
+ console.error(import_chalk20.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
31446
31935
  process.exit(1);
31447
31936
  }
31448
31937
  }
@@ -31453,12 +31942,12 @@ async function automationRunCommand(id) {
31453
31942
  const automation2 = existing.automation;
31454
31943
  const hasCronTrigger = automation2.triggers.some((t) => t.type === "cron");
31455
31944
  if (!hasCronTrigger) {
31456
- console.log(import_chalk19.default.red("\nManual run is only allowed for automations with a cron trigger."));
31457
- console.log(import_chalk19.default.gray(`This automation has triggers: ${automation2.triggers.map(formatTrigger).join(", ")}`));
31945
+ console.log(import_chalk20.default.red("\nManual run is only allowed for automations with a cron trigger."));
31946
+ console.log(import_chalk20.default.gray(`This automation has triggers: ${automation2.triggers.map(formatTrigger).join(", ")}`));
31458
31947
  console.log();
31459
31948
  process.exit(1);
31460
31949
  }
31461
- console.log(import_chalk19.default.gray(`
31950
+ console.log(import_chalk20.default.gray(`
31462
31951
  Triggering automation "${automation2.name}"...`));
31463
31952
  const response = await orgAuthenticatedFetch(
31464
31953
  `/v1/automations/${id}/trigger`,
@@ -31468,20 +31957,20 @@ Triggering automation "${automation2.name}"...`));
31468
31957
  }
31469
31958
  );
31470
31959
  if (!response.execution_id) {
31471
- console.log(import_chalk19.default.red(`
31960
+ console.log(import_chalk20.default.red(`
31472
31961
  Automation trigger returned no execution ID. The automation may not have started.`));
31473
31962
  console.log();
31474
31963
  process.exit(1);
31475
31964
  }
31476
- console.log(import_chalk19.default.green(`
31965
+ console.log(import_chalk20.default.green(`
31477
31966
  Automation triggered successfully.`));
31478
- console.log(import_chalk19.default.gray(` Execution ID: ${response.execution_id}`));
31967
+ console.log(import_chalk20.default.gray(` Execution ID: ${response.execution_id}`));
31479
31968
  if (response.workspace_id) {
31480
- console.log(import_chalk19.default.gray(` Workspace ID: ${response.workspace_id}`));
31969
+ console.log(import_chalk20.default.gray(` Workspace ID: ${response.workspace_id}`));
31481
31970
  }
31482
31971
  console.log();
31483
31972
  } catch (error51) {
31484
- console.error(import_chalk19.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
31973
+ console.error(import_chalk20.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
31485
31974
  process.exit(1);
31486
31975
  }
31487
31976
  }
@@ -31498,38 +31987,38 @@ async function automationDeleteCommand(id, options) {
31498
31987
  initial: false
31499
31988
  });
31500
31989
  if (!response.confirm) {
31501
- console.log(import_chalk19.default.yellow("\nCancelled."));
31990
+ console.log(import_chalk20.default.yellow("\nCancelled."));
31502
31991
  return;
31503
31992
  }
31504
31993
  }
31505
31994
  await orgAuthenticatedFetch(`/v1/automations/${id}`, {
31506
31995
  method: "DELETE"
31507
31996
  });
31508
- console.log(import_chalk19.default.green(`
31997
+ console.log(import_chalk20.default.green(`
31509
31998
  Automation "${automationName}" (${id}) deleted.
31510
31999
  `));
31511
32000
  } catch (error51) {
31512
- console.error(import_chalk19.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
32001
+ console.error(import_chalk20.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
31513
32002
  process.exit(1);
31514
32003
  }
31515
32004
  }
31516
32005
  async function automationCheckCommand(checkRunId, options) {
31517
32006
  const id = Number(checkRunId);
31518
32007
  if (!Number.isSafeInteger(id)) {
31519
- console.error(import_chalk19.default.red("Error: check run ID must be an integer"));
32008
+ console.error(import_chalk20.default.red("Error: check run ID must be an integer"));
31520
32009
  process.exit(1);
31521
32010
  }
31522
32011
  if (!options.token) {
31523
- console.error(import_chalk19.default.red("Error: --token is required"));
32012
+ console.error(import_chalk20.default.red("Error: --token is required"));
31524
32013
  process.exit(1);
31525
32014
  }
31526
32015
  const { conclusion } = options;
31527
32016
  if (!isAutomationCheckConclusion(conclusion)) {
31528
- console.error(import_chalk19.default.red(`Error: --conclusion must be one of ${AUTOMATION_CHECK_CONCLUSIONS.join(", ")}`));
32017
+ console.error(import_chalk20.default.red(`Error: --conclusion must be one of ${AUTOMATION_CHECK_CONCLUSIONS.join(", ")}`));
31529
32018
  process.exit(1);
31530
32019
  }
31531
32020
  if (!options.title?.trim()) {
31532
- console.error(import_chalk19.default.red("Error: --title is required"));
32021
+ console.error(import_chalk20.default.red("Error: --title is required"));
31533
32022
  process.exit(1);
31534
32023
  }
31535
32024
  const body = {
@@ -31543,23 +32032,23 @@ async function automationCheckCommand(checkRunId, options) {
31543
32032
  `/v1/automations/checks/${id}`,
31544
32033
  { method: "POST", body }
31545
32034
  );
31546
- console.log(response.reported ? import_chalk19.default.green(`
32035
+ console.log(response.reported ? import_chalk20.default.green(`
31547
32036
  Reported ${conclusion} for "${response.name}".
31548
- `) : import_chalk19.default.yellow(`
32037
+ `) : import_chalk20.default.yellow(`
31549
32038
  Skipped "${response.name}" \u2014 a newer run of this automation owns it and will report the verdict.
31550
32039
  `));
31551
32040
  } catch (error51) {
31552
- console.error(import_chalk19.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
32041
+ console.error(import_chalk20.default.red(`Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
31553
32042
  process.exit(1);
31554
32043
  }
31555
32044
  }
31556
32045
 
31557
32046
  // src/commands/preview.ts
31558
- var import_chalk20 = __toESM(require("chalk"));
32047
+ var import_chalk21 = __toESM(require("chalk"));
31559
32048
 
31560
32049
  // src/lib/agent-api.ts
31561
32050
  var ENGINE_PORT = process.env.REPLICAS_ENGINE_PORT || "3737";
31562
- async function agentFetch(path6, options) {
32051
+ async function agentFetch(path7, options) {
31563
32052
  const config3 = readAgentConfig();
31564
32053
  if (!config3) {
31565
32054
  throw new Error("Agent mode config not found");
@@ -31573,7 +32062,7 @@ async function agentFetch(path6, options) {
31573
32062
  ...options?.headers || {}
31574
32063
  };
31575
32064
  const body = options?.body === void 0 ? void 0 : isFormData ? options.body : JSON.stringify(options.body);
31576
- const response = await fetch(`${MONOLITH_URL}${path6}`, {
32065
+ const response = await fetch(`${MONOLITH_URL}${path7}`, {
31577
32066
  ...options,
31578
32067
  headers,
31579
32068
  body
@@ -31584,7 +32073,7 @@ async function agentFetch(path6, options) {
31584
32073
  }
31585
32074
  return response.json();
31586
32075
  }
31587
- async function engineFetch(path6, options) {
32076
+ async function engineFetch(path7, options) {
31588
32077
  const config3 = readAgentConfig();
31589
32078
  if (!config3) {
31590
32079
  throw new Error("Agent mode config not found");
@@ -31594,7 +32083,7 @@ async function engineFetch(path6, options) {
31594
32083
  "Content-Type": "application/json",
31595
32084
  ...options?.headers || {}
31596
32085
  };
31597
- const response = await fetch(`http://localhost:${ENGINE_PORT}${path6}`, {
32086
+ const response = await fetch(`http://localhost:${ENGINE_PORT}${path7}`, {
31598
32087
  ...options,
31599
32088
  headers,
31600
32089
  body: options?.body !== void 0 ? JSON.stringify(options.body) : void 0
@@ -31649,11 +32138,11 @@ async function previewListCommand(workspaceId) {
31649
32138
  `/v1/workspaces/${workspaceId}/previews`
31650
32139
  );
31651
32140
  if (result.previews.length === 0) {
31652
- console.log(import_chalk20.default.dim("No active previews"));
32141
+ console.log(import_chalk21.default.dim("No active previews"));
31653
32142
  return;
31654
32143
  }
31655
32144
  for (const preview2 of result.previews) {
31656
- console.log(` ${import_chalk20.default.cyan(String(preview2.port))} \u2192 ${import_chalk20.default.underline(preview2.publicUrl)}`);
32145
+ console.log(` ${import_chalk21.default.cyan(String(preview2.port))} \u2192 ${import_chalk21.default.underline(preview2.publicUrl)}`);
31657
32146
  }
31658
32147
  }
31659
32148
  }
@@ -31666,7 +32155,7 @@ async function previewAddCommand(workspaceId, options) {
31666
32155
  body: { port: portNum, authenticated: options.authenticated ?? false }
31667
32156
  }
31668
32157
  );
31669
- console.log(import_chalk20.default.green(`Preview created: ${result.preview.publicUrl}`));
32158
+ console.log(import_chalk21.default.green(`Preview created: ${result.preview.publicUrl}`));
31670
32159
  }
31671
32160
  async function previewDeleteCommand(port) {
31672
32161
  const portNum = parsePreviewPort(port);
@@ -31679,12 +32168,12 @@ async function previewRemoveCommand(workspaceId, options) {
31679
32168
  `/v1/workspaces/${workspaceId}/previews/${portNum}`,
31680
32169
  { method: "DELETE" }
31681
32170
  );
31682
- console.log(import_chalk20.default.green(`Preview deleted on port ${portNum}`));
32171
+ console.log(import_chalk21.default.green(`Preview deleted on port ${portNum}`));
31683
32172
  }
31684
32173
 
31685
32174
  // src/commands/media.ts
31686
- var import_fs4 = __toESM(require("fs"));
31687
- var import_path5 = __toESM(require("path"));
32175
+ var import_fs5 = __toESM(require("fs"));
32176
+ var import_path6 = __toESM(require("path"));
31688
32177
  var MEDIA_ACCESS_VALUES = ["organization", "public"];
31689
32178
  function publicMediaUrl(mediaId, token) {
31690
32179
  return `${MONOLITH_URL}/v1/media/public/${mediaId}/${token}`;
@@ -31724,22 +32213,22 @@ function resolveKind(ext, override) {
31724
32213
  return inferred;
31725
32214
  }
31726
32215
  async function uploadOne(filePath, displayName, kind, options) {
31727
- const absPath = import_path5.default.resolve(filePath);
31728
- if (!import_fs4.default.existsSync(absPath)) {
32216
+ const absPath = import_path6.default.resolve(filePath);
32217
+ if (!import_fs5.default.existsSync(absPath)) {
31729
32218
  throw new Error(`File not found: ${absPath}`);
31730
32219
  }
31731
- const stat = import_fs4.default.statSync(absPath);
32220
+ const stat = import_fs5.default.statSync(absPath);
31732
32221
  if (!stat.isFile()) {
31733
32222
  throw new Error(`Not a file: ${absPath}`);
31734
32223
  }
31735
32224
  if (stat.size === 0) {
31736
32225
  throw new Error("File is empty");
31737
32226
  }
31738
- const fileName = import_path5.default.basename(absPath);
31739
- const ext = import_path5.default.extname(absPath).slice(1).toLowerCase();
32227
+ const fileName = import_path6.default.basename(absPath);
32228
+ const ext = import_path6.default.extname(absPath).slice(1).toLowerCase();
31740
32229
  const contentType = mediaInfo(ext)?.contentType ?? "application/octet-stream";
31741
32230
  const form = new FormData();
31742
- form.append("file", new Blob([import_fs4.default.readFileSync(absPath)], { type: contentType }), fileName);
32231
+ form.append("file", new Blob([import_fs5.default.readFileSync(absPath)], { type: contentType }), fileName);
31743
32232
  form.append("kind", kind);
31744
32233
  if (options.sessionId) form.append("session_id", options.sessionId);
31745
32234
  form.append("display_name", displayName);
@@ -31773,7 +32262,7 @@ async function mediaUploadCommand(filePaths, options) {
31773
32262
  }
31774
32263
  const publicAccess = options.share || options.access === "public";
31775
32264
  const kinds = filePaths.map((filePath) => {
31776
- const ext = import_path5.default.extname(filePath).slice(1).toLowerCase();
32265
+ const ext = import_path6.default.extname(filePath).slice(1).toLowerCase();
31777
32266
  return resolveKind(ext, options.kind);
31778
32267
  });
31779
32268
  if (publicAccess && kinds.some((kind) => !isPublicMediaKind(kind))) {
@@ -31859,7 +32348,7 @@ async function mediaListCommand(options) {
31859
32348
  }
31860
32349
 
31861
32350
  // src/commands/slack.ts
31862
- var import_chalk21 = __toESM(require("chalk"));
32351
+ var import_chalk22 = __toESM(require("chalk"));
31863
32352
  function getThreadOptions(options) {
31864
32353
  const channelId = options.channel || process.env.REPLICAS_SLACK_CHANNEL_ID || process.env.SLACK_CHANNEL_ID;
31865
32354
  const threadTs = options.threadTs || process.env.REPLICAS_SLACK_THREAD_TS || process.env.SLACK_THREAD_TS;
@@ -31876,10 +32365,10 @@ async function attachThread(request) {
31876
32365
  method: "POST",
31877
32366
  body: request
31878
32367
  });
31879
- console.log(import_chalk21.default.green("Slack thread attached."));
31880
- console.log(import_chalk21.default.gray(` Channel: ${response.thread.channel_id}`));
31881
- console.log(import_chalk21.default.gray(` Thread: ${response.thread.thread_ts}`));
31882
- console.log(import_chalk21.default.gray(` Workspace: ${response.workspace.name} (${response.workspace.id})`));
32368
+ console.log(import_chalk22.default.green("Slack thread attached."));
32369
+ console.log(import_chalk22.default.gray(` Channel: ${response.thread.channel_id}`));
32370
+ console.log(import_chalk22.default.gray(` Thread: ${response.thread.thread_ts}`));
32371
+ console.log(import_chalk22.default.gray(` Workspace: ${response.workspace.name} (${response.workspace.id})`));
31883
32372
  }
31884
32373
  async function slackThreadAttachCommand(options) {
31885
32374
  const agentConfig = readAgentConfig();
@@ -31908,7 +32397,7 @@ async function slackThreadSwitchCommand(workspace, options) {
31908
32397
  }
31909
32398
 
31910
32399
  // src/commands/service.ts
31911
- var import_chalk22 = __toESM(require("chalk"));
32400
+ var import_chalk23 = __toESM(require("chalk"));
31912
32401
  var import_node_child_process2 = require("child_process");
31913
32402
  var import_node_fs2 = require("fs");
31914
32403
  var import_node_os2 = require("os");
@@ -32051,7 +32540,7 @@ async function serviceListCommand() {
32051
32540
  return;
32052
32541
  }
32053
32542
  for (const state of states) {
32054
- const status = isRunning(state.pid) ? import_chalk22.default.green("running") : import_chalk22.default.red("stopped");
32543
+ const status = isRunning(state.pid) ? import_chalk23.default.green("running") : import_chalk23.default.red("stopped");
32055
32544
  console.log(`${state.name} ${status} pid ${state.pid} started ${state.startedAt}`);
32056
32545
  console.log(` command: ${state.command} (cwd: ${state.cwd})`);
32057
32546
  console.log(` logs: ${state.logFile}`);
@@ -32157,8 +32646,8 @@ Workspace: ${workspaceNameForOutput(result.workspace_name)} (${getWorkspaceDashb
32157
32646
  }
32158
32647
 
32159
32648
  // src/commands/environment.ts
32160
- var import_fs5 = __toESM(require("fs"));
32161
- var import_chalk23 = __toESM(require("chalk"));
32649
+ var import_fs6 = __toESM(require("fs"));
32650
+ var import_chalk24 = __toESM(require("chalk"));
32162
32651
  var import_prompts8 = __toESM(require("prompts"));
32163
32652
  function maskValue(value) {
32164
32653
  if (value.length <= 4) return "\u2022\u2022\u2022\u2022";
@@ -32170,38 +32659,38 @@ async function resolveEnvironmentId(input) {
32170
32659
  const response = await orgAuthenticatedFetch("/v1/environments");
32171
32660
  const resolved = resolveByNameOrId(input, response.environments);
32172
32661
  if (!resolved) {
32173
- console.log(import_chalk23.default.red(`Environment not found: ${input}`));
32662
+ console.log(import_chalk24.default.red(`Environment not found: ${input}`));
32174
32663
  const available = response.environments.map((e) => e.name).join(", ");
32175
- console.log(import_chalk23.default.gray(`Available: ${available || "(none)"}`));
32664
+ console.log(import_chalk24.default.gray(`Available: ${available || "(none)"}`));
32176
32665
  process.exit(1);
32177
32666
  }
32178
32667
  return resolved.id;
32179
32668
  }
32180
32669
  function printEnvironment(env) {
32181
- console.log(import_chalk23.default.white(` ${env.name}${env.is_global ? import_chalk23.default.gray(" (global)") : ""}`));
32182
- console.log(import_chalk23.default.gray(` ID: ${env.id}`));
32670
+ console.log(import_chalk24.default.white(` ${env.name}${env.is_global ? import_chalk24.default.gray(" (global)") : ""}`));
32671
+ console.log(import_chalk24.default.gray(` ID: ${env.id}`));
32183
32672
  if (env.description) {
32184
- console.log(import_chalk23.default.gray(` Description: ${env.description}`));
32673
+ console.log(import_chalk24.default.gray(` Description: ${env.description}`));
32185
32674
  }
32186
32675
  if (env.repository_id) {
32187
- console.log(import_chalk23.default.gray(` Repository: ${env.repository_id}`));
32676
+ console.log(import_chalk24.default.gray(` Repository: ${env.repository_id}`));
32188
32677
  } else if (env.repository_set_id) {
32189
- console.log(import_chalk23.default.gray(` Repository Set: ${env.repository_set_id}`));
32678
+ console.log(import_chalk24.default.gray(` Repository Set: ${env.repository_set_id}`));
32190
32679
  }
32191
32680
  if (env.variable_count !== void 0) {
32192
- console.log(import_chalk23.default.gray(` Variables: ${env.variable_count}, Files: ${env.file_count ?? 0}, Skills: ${env.skill_count ?? 0}, MCPs: ${env.mcp_count ?? 0}`));
32681
+ console.log(import_chalk24.default.gray(` Variables: ${env.variable_count}, Files: ${env.file_count ?? 0}, Skills: ${env.skill_count ?? 0}, MCPs: ${env.mcp_count ?? 0}`));
32193
32682
  }
32194
- console.log(import_chalk23.default.gray(` Updated: ${formatDate2(env.updated_at)}`));
32683
+ console.log(import_chalk24.default.gray(` Updated: ${formatDate2(env.updated_at)}`));
32195
32684
  console.log();
32196
32685
  }
32197
32686
  async function environmentListCommand() {
32198
32687
  ensureOrgApiAuthenticated();
32199
32688
  const response = await orgAuthenticatedFetch("/v1/environments");
32200
32689
  if (response.environments.length === 0) {
32201
- console.log(import_chalk23.default.yellow("\nNo environments found.\n"));
32690
+ console.log(import_chalk24.default.yellow("\nNo environments found.\n"));
32202
32691
  return;
32203
32692
  }
32204
- console.log(import_chalk23.default.green(`
32693
+ console.log(import_chalk24.default.green(`
32205
32694
  Environments (${response.environments.length}):
32206
32695
  `));
32207
32696
  for (const env of response.environments) {
@@ -32212,7 +32701,7 @@ async function environmentGetCommand(idOrName) {
32212
32701
  ensureOrgApiAuthenticated();
32213
32702
  const id = await resolveEnvironmentId(idOrName);
32214
32703
  const response = await orgAuthenticatedFetch(`/v1/environments/${id}`);
32215
- console.log(import_chalk23.default.green(`
32704
+ console.log(import_chalk24.default.green(`
32216
32705
  Environment: ${response.environment.name}
32217
32706
  `));
32218
32707
  printEnvironment(response.environment);
@@ -32228,7 +32717,7 @@ async function environmentCreateCommand(name, options) {
32228
32717
  validate: (v) => v.trim() ? true : "Name is required"
32229
32718
  });
32230
32719
  if (!r.name) {
32231
- console.log(import_chalk23.default.yellow("\nCancelled."));
32720
+ console.log(import_chalk24.default.yellow("\nCancelled."));
32232
32721
  return;
32233
32722
  }
32234
32723
  envName = r.name;
@@ -32241,8 +32730,8 @@ async function environmentCreateCommand(name, options) {
32241
32730
  const repos2 = await orgAuthenticatedFetch("/v1/repositories");
32242
32731
  const repo = repos2.repositories.find((r) => r.name === options.repository);
32243
32732
  if (!repo) {
32244
- console.log(import_chalk23.default.red(`Repository not found: ${options.repository}`));
32245
- console.log(import_chalk23.default.gray(`Available: ${repos2.repositories.map((r) => r.name).join(", ")}`));
32733
+ console.log(import_chalk24.default.red(`Repository not found: ${options.repository}`));
32734
+ console.log(import_chalk24.default.gray(`Available: ${repos2.repositories.map((r) => r.name).join(", ")}`));
32246
32735
  process.exit(1);
32247
32736
  }
32248
32737
  repositoryId = repo.id;
@@ -32272,9 +32761,9 @@ async function environmentCreateCommand(name, options) {
32272
32761
  method: "POST",
32273
32762
  body
32274
32763
  });
32275
- console.log(import_chalk23.default.green(`
32764
+ console.log(import_chalk24.default.green(`
32276
32765
  Created environment: ${response.environment.name}`));
32277
- console.log(import_chalk23.default.gray(` ID: ${response.environment.id}
32766
+ console.log(import_chalk24.default.gray(` ID: ${response.environment.id}
32278
32767
  `));
32279
32768
  }
32280
32769
  async function environmentEditCommand(idOrName, options) {
@@ -32293,21 +32782,21 @@ async function environmentEditCommand(idOrName, options) {
32293
32782
  const repos2 = await orgAuthenticatedFetch("/v1/repositories");
32294
32783
  const repo = repos2.repositories.find((r) => r.name === options.repository);
32295
32784
  if (!repo) {
32296
- console.log(import_chalk23.default.red(`Repository not found: ${options.repository}`));
32785
+ console.log(import_chalk24.default.red(`Repository not found: ${options.repository}`));
32297
32786
  process.exit(1);
32298
32787
  }
32299
32788
  body.repository_id = repo.id;
32300
32789
  }
32301
32790
  }
32302
32791
  if (Object.keys(body).length === 0) {
32303
- console.log(import_chalk23.default.yellow("\nNo changes specified. Pass --name, --description, --repository, or --system-prompt."));
32792
+ console.log(import_chalk24.default.yellow("\nNo changes specified. Pass --name, --description, --repository, or --system-prompt."));
32304
32793
  return;
32305
32794
  }
32306
32795
  const response = await orgAuthenticatedFetch(`/v1/environments/${id}`, {
32307
32796
  method: "PATCH",
32308
32797
  body
32309
32798
  });
32310
- console.log(import_chalk23.default.green(`
32799
+ console.log(import_chalk24.default.green(`
32311
32800
  Updated environment: ${response.environment.name}
32312
32801
  `));
32313
32802
  }
@@ -32322,20 +32811,20 @@ async function environmentDeleteCommand(idOrName, options) {
32322
32811
  initial: false
32323
32812
  });
32324
32813
  if (!r.confirm) {
32325
- console.log(import_chalk23.default.yellow("\nCancelled."));
32814
+ console.log(import_chalk24.default.yellow("\nCancelled."));
32326
32815
  return;
32327
32816
  }
32328
32817
  }
32329
32818
  await orgAuthenticatedFetch(`/v1/environments/${id}`, { method: "DELETE" });
32330
- console.log(import_chalk23.default.green(`
32819
+ console.log(import_chalk24.default.green(`
32331
32820
  Deleted environment ${idOrName}.
32332
32821
  `));
32333
32822
  }
32334
32823
  function printVariable(v, reveal) {
32335
- console.log(import_chalk23.default.white(` ${v.key}`));
32336
- console.log(import_chalk23.default.gray(` ID: ${v.id}`));
32337
- console.log(import_chalk23.default.gray(` Value: ${reveal ? v.value : maskValue(v.value)}`));
32338
- console.log(import_chalk23.default.gray(` Updated: ${formatDate2(v.updated_at)}`));
32824
+ console.log(import_chalk24.default.white(` ${v.key}`));
32825
+ console.log(import_chalk24.default.gray(` ID: ${v.id}`));
32826
+ console.log(import_chalk24.default.gray(` Value: ${reveal ? v.value : maskValue(v.value)}`));
32827
+ console.log(import_chalk24.default.gray(` Updated: ${formatDate2(v.updated_at)}`));
32339
32828
  console.log();
32340
32829
  }
32341
32830
  async function envVarsListCommand(envIdOrName, options) {
@@ -32345,14 +32834,14 @@ async function envVarsListCommand(envIdOrName, options) {
32345
32834
  `/v1/environments/${id}/variables`
32346
32835
  );
32347
32836
  if (response.environment_variables.length === 0) {
32348
- console.log(import_chalk23.default.yellow("\nNo variables.\n"));
32837
+ console.log(import_chalk24.default.yellow("\nNo variables.\n"));
32349
32838
  return;
32350
32839
  }
32351
- console.log(import_chalk23.default.green(`
32840
+ console.log(import_chalk24.default.green(`
32352
32841
  Variables (${response.environment_variables.length}):
32353
32842
  `));
32354
32843
  if (!options.reveal) {
32355
- console.log(import_chalk23.default.gray(" Values are masked. Pass --reveal to show full values.\n"));
32844
+ console.log(import_chalk24.default.gray(" Values are masked. Pass --reveal to show full values.\n"));
32356
32845
  }
32357
32846
  for (const v of response.environment_variables) printVariable(v, !!options.reveal);
32358
32847
  }
@@ -32369,7 +32858,7 @@ async function envVarsSetCommand(envIdOrName, key, value) {
32369
32858
  `/v1/environments/${id}/variables/${match.id}`,
32370
32859
  { method: "PATCH", body: body2 }
32371
32860
  );
32372
- console.log(import_chalk23.default.green(`
32861
+ console.log(import_chalk24.default.green(`
32373
32862
  Updated variable ${response2.environment_variable.key}.
32374
32863
  `));
32375
32864
  return;
@@ -32383,7 +32872,7 @@ Updated variable ${response2.environment_variable.key}.
32383
32872
  `/v1/environments/${id}/variables`,
32384
32873
  { method: "POST", body }
32385
32874
  );
32386
- console.log(import_chalk23.default.green(`
32875
+ console.log(import_chalk24.default.green(`
32387
32876
  Created variable ${response.environment_variable.key}.
32388
32877
  `));
32389
32878
  }
@@ -32397,7 +32886,7 @@ async function envVarsDeleteCommand(envIdOrName, keyOrId, options) {
32397
32886
  );
32398
32887
  const match = existing.environment_variables.find((v) => v.key === keyOrId);
32399
32888
  if (!match) {
32400
- console.log(import_chalk23.default.red(`Variable not found: ${keyOrId}`));
32889
+ console.log(import_chalk24.default.red(`Variable not found: ${keyOrId}`));
32401
32890
  process.exit(1);
32402
32891
  }
32403
32892
  variableId = match.id;
@@ -32410,23 +32899,23 @@ async function envVarsDeleteCommand(envIdOrName, keyOrId, options) {
32410
32899
  initial: false
32411
32900
  });
32412
32901
  if (!r.confirm) {
32413
- console.log(import_chalk23.default.yellow("\nCancelled."));
32902
+ console.log(import_chalk24.default.yellow("\nCancelled."));
32414
32903
  return;
32415
32904
  }
32416
32905
  }
32417
32906
  await orgAuthenticatedFetch(`/v1/environments/${id}/variables/${variableId}`, {
32418
32907
  method: "DELETE"
32419
32908
  });
32420
- console.log(import_chalk23.default.green(`
32909
+ console.log(import_chalk24.default.green(`
32421
32910
  Deleted variable ${keyOrId}.
32422
32911
  `));
32423
32912
  }
32424
32913
  function printFile(f) {
32425
- console.log(import_chalk23.default.white(` ${f.path}`));
32426
- console.log(import_chalk23.default.gray(` ID: ${f.id}`));
32427
- console.log(import_chalk23.default.gray(` Name: ${f.name}`));
32428
- console.log(import_chalk23.default.gray(` Size: ${f.content.length} bytes`));
32429
- console.log(import_chalk23.default.gray(` Updated: ${formatDate2(f.updated_at)}`));
32914
+ console.log(import_chalk24.default.white(` ${f.path}`));
32915
+ console.log(import_chalk24.default.gray(` ID: ${f.id}`));
32916
+ console.log(import_chalk24.default.gray(` Name: ${f.name}`));
32917
+ console.log(import_chalk24.default.gray(` Size: ${f.content.length} bytes`));
32918
+ console.log(import_chalk24.default.gray(` Updated: ${formatDate2(f.updated_at)}`));
32430
32919
  console.log();
32431
32920
  }
32432
32921
  async function envFilesListCommand(envIdOrName) {
@@ -32436,20 +32925,20 @@ async function envFilesListCommand(envIdOrName) {
32436
32925
  `/v1/environments/${id}/files`
32437
32926
  );
32438
32927
  if (response.environment_files.length === 0) {
32439
- console.log(import_chalk23.default.yellow("\nNo files.\n"));
32928
+ console.log(import_chalk24.default.yellow("\nNo files.\n"));
32440
32929
  return;
32441
32930
  }
32442
- console.log(import_chalk23.default.green(`
32931
+ console.log(import_chalk24.default.green(`
32443
32932
  Files (${response.environment_files.length}):
32444
32933
  `));
32445
32934
  for (const f of response.environment_files) printFile(f);
32446
32935
  }
32447
32936
  function readFileContent(options) {
32448
32937
  if (options.file) {
32449
- if (!import_fs5.default.existsSync(options.file)) {
32938
+ if (!import_fs6.default.existsSync(options.file)) {
32450
32939
  throw new Error(`Local file not found: ${options.file}`);
32451
32940
  }
32452
- return import_fs5.default.readFileSync(options.file, "utf-8");
32941
+ return import_fs6.default.readFileSync(options.file, "utf-8");
32453
32942
  }
32454
32943
  if (options.content !== void 0) return options.content;
32455
32944
  throw new Error('Pass either --content "..." or --file <local-path>');
@@ -32470,7 +32959,7 @@ async function envFilesSetCommand(envIdOrName, destinationPath, options) {
32470
32959
  `/v1/environments/${id}/files/${match.id}`,
32471
32960
  { method: "PATCH", body: body2 }
32472
32961
  );
32473
- console.log(import_chalk23.default.green(`
32962
+ console.log(import_chalk24.default.green(`
32474
32963
  Updated file ${response2.environment_file.path}.
32475
32964
  `));
32476
32965
  return;
@@ -32485,7 +32974,7 @@ Updated file ${response2.environment_file.path}.
32485
32974
  `/v1/environments/${id}/files`,
32486
32975
  { method: "POST", body }
32487
32976
  );
32488
- console.log(import_chalk23.default.green(`
32977
+ console.log(import_chalk24.default.green(`
32489
32978
  Created file ${response.environment_file.path}.
32490
32979
  `));
32491
32980
  }
@@ -32499,7 +32988,7 @@ async function envFilesDeleteCommand(envIdOrName, pathOrId, options) {
32499
32988
  );
32500
32989
  const match = existing.environment_files.find((f) => f.path === pathOrId);
32501
32990
  if (!match) {
32502
- console.log(import_chalk23.default.red(`File not found: ${pathOrId}`));
32991
+ console.log(import_chalk24.default.red(`File not found: ${pathOrId}`));
32503
32992
  process.exit(1);
32504
32993
  }
32505
32994
  fileId = match.id;
@@ -32512,14 +33001,14 @@ async function envFilesDeleteCommand(envIdOrName, pathOrId, options) {
32512
33001
  initial: false
32513
33002
  });
32514
33003
  if (!r.confirm) {
32515
- console.log(import_chalk23.default.yellow("\nCancelled."));
33004
+ console.log(import_chalk24.default.yellow("\nCancelled."));
32516
33005
  return;
32517
33006
  }
32518
33007
  }
32519
33008
  await orgAuthenticatedFetch(`/v1/environments/${id}/files/${fileId}`, {
32520
33009
  method: "DELETE"
32521
33010
  });
32522
- console.log(import_chalk23.default.green(`
33011
+ console.log(import_chalk24.default.green(`
32523
33012
  Deleted file ${pathOrId}.
32524
33013
  `));
32525
33014
  }
@@ -32528,16 +33017,16 @@ async function envHookGetCommand(envIdOrName, kind) {
32528
33017
  const id = await resolveEnvironmentId(envIdOrName);
32529
33018
  const hook = kind === "warm" ? (await orgAuthenticatedFetch(`/v1/environments/${id}/warm-hooks`)).warm_hook : (await orgAuthenticatedFetch(`/v1/environments/${id}/start-hooks`)).start_hook;
32530
33019
  if (!hook) {
32531
- console.log(import_chalk23.default.yellow(`
33020
+ console.log(import_chalk24.default.yellow(`
32532
33021
  No ${kind} hook configured.
32533
33022
  `));
32534
33023
  return;
32535
33024
  }
32536
- console.log(import_chalk23.default.green(`
33025
+ console.log(import_chalk24.default.green(`
32537
33026
  ${kind === "warm" ? "Warm" : "Start"} hook (v${hook.version}, ${hook.is_active ? "active" : "inactive"}):
32538
33027
  `));
32539
- console.log(import_chalk23.default.gray(` ID: ${hook.id}`));
32540
- console.log(import_chalk23.default.gray(` Created: ${formatDate2(hook.created_at)}
33028
+ console.log(import_chalk24.default.gray(` ID: ${hook.id}`));
33029
+ console.log(import_chalk24.default.gray(` Created: ${formatDate2(hook.created_at)}
32541
33030
  `));
32542
33031
  console.log(hook.content);
32543
33032
  console.log();
@@ -32552,7 +33041,7 @@ async function envHookSaveCommand(envIdOrName, options, kind) {
32552
33041
  `/v1/environments/${id}/warm-hooks/save`,
32553
33042
  { method: "POST", body: body2 }
32554
33043
  );
32555
- console.log(import_chalk23.default.green(`
33044
+ console.log(import_chalk24.default.green(`
32556
33045
  Saved warm hook v${response2.warm_hook.version}.
32557
33046
  `));
32558
33047
  return;
@@ -32562,7 +33051,7 @@ Saved warm hook v${response2.warm_hook.version}.
32562
33051
  `/v1/environments/${id}/start-hooks/save`,
32563
33052
  { method: "POST", body }
32564
33053
  );
32565
- console.log(import_chalk23.default.green(response.start_hook ? `
33054
+ console.log(import_chalk24.default.green(response.start_hook ? `
32566
33055
  Saved start hook v${response.start_hook.version}.
32567
33056
  ` : "\nCleared start hook.\n"));
32568
33057
  }
@@ -32579,7 +33068,7 @@ async function envHookTestCommand(envIdOrName, options, kind) {
32579
33068
  body: kind === "warm" ? { content, mode: options.save ? "save_test" : "test_only" } : { content },
32580
33069
  onEvent: (event) => {
32581
33070
  if (event.type === "progress" && event.message) {
32582
- console.log(import_chalk23.default.gray(event.message));
33071
+ console.log(import_chalk24.default.gray(event.message));
32583
33072
  } else if (event.type === "output" && event.output) {
32584
33073
  process.stdout.write(event.output);
32585
33074
  } else if (event.type === "complete") {
@@ -32592,23 +33081,23 @@ async function envHookTestCommand(envIdOrName, options, kind) {
32592
33081
  }
32593
33082
  );
32594
33083
  if (errorMessage) {
32595
- console.log(import_chalk23.default.red(`
33084
+ console.log(import_chalk24.default.red(`
32596
33085
  ${errorMessage}
32597
33086
  `));
32598
33087
  process.exit(1);
32599
33088
  }
32600
33089
  if (timedOut) {
32601
- console.log(import_chalk23.default.yellow(`
33090
+ console.log(import_chalk24.default.yellow(`
32602
33091
  ${kind === "warm" ? "Warm" : "Start"} hook timed out.
32603
33092
  `));
32604
33093
  process.exit(1);
32605
33094
  }
32606
33095
  if (exitCode === 0) {
32607
- console.log(import_chalk23.default.green(`
33096
+ console.log(import_chalk24.default.green(`
32608
33097
  ${kind === "warm" ? "Warm" : "Start"} hook passed${options.save ? " and was saved" : ""} (exit code ${exitCode}).
32609
33098
  `));
32610
33099
  } else {
32611
- console.log(import_chalk23.default.red(`
33100
+ console.log(import_chalk24.default.red(`
32612
33101
  ${kind === "warm" ? "Warm" : "Start"} hook failed (exit code ${exitCode ?? "unknown"}).
32613
33102
  `));
32614
33103
  process.exit(1);
@@ -32623,24 +33112,24 @@ async function envHookRepositoryHooksCommand(envIdOrName, kind) {
32623
33112
  `/v1/environments/${id}/start-hooks/repository-hooks`
32624
33113
  )).repositories.map((repository) => ({ ...repository, hook: repository.start_hook }));
32625
33114
  if (repositories.length === 0) {
32626
- console.log(import_chalk23.default.yellow("\nNo repositories bound to this environment.\n"));
33115
+ console.log(import_chalk24.default.yellow("\nNo repositories bound to this environment.\n"));
32627
33116
  return;
32628
33117
  }
32629
- console.log(import_chalk23.default.green(`
33118
+ console.log(import_chalk24.default.green(`
32630
33119
  Repository ${kind} hooks (${repositories.length}):
32631
33120
  `));
32632
33121
  for (const repo of repositories) {
32633
- console.log(import_chalk23.default.white(` ${repo.repository_name} @${repo.default_branch}`));
33122
+ console.log(import_chalk24.default.white(` ${repo.repository_name} @${repo.default_branch}`));
32634
33123
  if (repo.error) {
32635
- console.log(import_chalk23.default.red(` Error: ${repo.error}`));
33124
+ console.log(import_chalk24.default.red(` Error: ${repo.error}`));
32636
33125
  } else if (repo.hook) {
32637
- console.log(import_chalk23.default.gray(` Source: ${repo.filename ?? "(unknown)"}`));
32638
- console.log(import_chalk23.default.gray(` Commands (${repo.hook.commands.length}):`));
33126
+ console.log(import_chalk24.default.gray(` Source: ${repo.filename ?? "(unknown)"}`));
33127
+ console.log(import_chalk24.default.gray(` Commands (${repo.hook.commands.length}):`));
32639
33128
  for (const cmd of repo.hook.commands) {
32640
- console.log(import_chalk23.default.gray(` ${cmd}`));
33129
+ console.log(import_chalk24.default.gray(` ${cmd}`));
32641
33130
  }
32642
33131
  } else {
32643
- console.log(import_chalk23.default.gray(` No ${kind}Hook defined.`));
33132
+ console.log(import_chalk24.default.gray(` No ${kind}Hook defined.`));
32644
33133
  }
32645
33134
  console.log();
32646
33135
  }
@@ -32705,7 +33194,7 @@ program.hook("preAction", async (_command, actionCommand) => {
32705
33194
  throw new Error('No organization selected. Run "replicas org switch" to select one.');
32706
33195
  }
32707
33196
  } catch (error51) {
32708
- console.error(import_chalk24.default.red(`
33197
+ console.error(import_chalk25.default.red(`
32709
33198
  \u2717 ${error51 instanceof Error ? error51.message : "Unknown error"}
32710
33199
  `));
32711
33200
  process.exit(1);
@@ -32719,7 +33208,7 @@ function registerSlackCommands(parent) {
32719
33208
  await slackThreadAttachCommand(options);
32720
33209
  } catch (error51) {
32721
33210
  if (error51 instanceof Error) {
32722
- console.error(import_chalk24.default.red(`
33211
+ console.error(import_chalk25.default.red(`
32723
33212
  \u2717 ${error51.message}
32724
33213
  `));
32725
33214
  }
@@ -32731,7 +33220,7 @@ function registerSlackCommands(parent) {
32731
33220
  await slackThreadSwitchCommand(workspace, options);
32732
33221
  } catch (error51) {
32733
33222
  if (error51 instanceof Error) {
32734
- console.error(import_chalk24.default.red(`
33223
+ console.error(import_chalk25.default.red(`
32735
33224
  \u2717 ${error51.message}
32736
33225
  `));
32737
33226
  }
@@ -32745,7 +33234,7 @@ program.command("login").description("Authenticate with your Replicas account").
32745
33234
  await loginCommand();
32746
33235
  } catch (error51) {
32747
33236
  if (error51 instanceof Error) {
32748
- console.error(import_chalk24.default.red(`
33237
+ console.error(import_chalk25.default.red(`
32749
33238
  \u2717 ${error51.message}
32750
33239
  `));
32751
33240
  }
@@ -32757,7 +33246,7 @@ program.command("init").description("Create a replicas.json or replicas.yaml con
32757
33246
  initCommand(options);
32758
33247
  } catch (error51) {
32759
33248
  if (error51 instanceof Error) {
32760
- console.error(import_chalk24.default.red(`
33249
+ console.error(import_chalk25.default.red(`
32761
33250
  \u2717 ${error51.message}
32762
33251
  `));
32763
33252
  }
@@ -32769,7 +33258,7 @@ program.command("logout").description("Clear stored credentials").action(() => {
32769
33258
  logoutCommand();
32770
33259
  } catch (error51) {
32771
33260
  if (error51 instanceof Error) {
32772
- console.error(import_chalk24.default.red(`
33261
+ console.error(import_chalk25.default.red(`
32773
33262
  \u2717 ${error51.message}
32774
33263
  `));
32775
33264
  }
@@ -32780,7 +33269,7 @@ program.command("muse-auth").description("Connect your Muse Code subscription to
32780
33269
  try {
32781
33270
  await museAuthCommand(options);
32782
33271
  } catch (error51) {
32783
- if (error51 instanceof Error) console.error(import_chalk24.default.red(`
33272
+ if (error51 instanceof Error) console.error(import_chalk25.default.red(`
32784
33273
  \u2717 ${error51.message}
32785
33274
  `));
32786
33275
  process.exit(1);
@@ -32791,7 +33280,7 @@ program.command("whoami").description("Display current authenticated user").acti
32791
33280
  await whoamiCommand();
32792
33281
  } catch (error51) {
32793
33282
  if (error51 instanceof Error) {
32794
- console.error(import_chalk24.default.red(`
33283
+ console.error(import_chalk25.default.red(`
32795
33284
  \u2717 ${error51.message}
32796
33285
  `));
32797
33286
  }
@@ -32803,7 +33292,7 @@ program.command("codex-auth").description("Connect your Codex credentials to Rep
32803
33292
  await codexAuthCommand(options);
32804
33293
  } catch (error51) {
32805
33294
  if (error51 instanceof Error) {
32806
- console.error(import_chalk24.default.red(`
33295
+ console.error(import_chalk25.default.red(`
32807
33296
  \u2717 ${error51.message}
32808
33297
  `));
32809
33298
  }
@@ -32815,7 +33304,7 @@ program.command("claude-auth").description("Connect your Claude Code credentials
32815
33304
  await claudeAuthCommand(options);
32816
33305
  } catch (error51) {
32817
33306
  if (error51 instanceof Error) {
32818
- console.error(import_chalk24.default.red(`
33307
+ console.error(import_chalk25.default.red(`
32819
33308
  \u2717 ${error51.message}
32820
33309
  `));
32821
33310
  }
@@ -32828,7 +33317,7 @@ org.command("switch").description("Switch to a different organization").action(a
32828
33317
  await orgSwitchCommand();
32829
33318
  } catch (error51) {
32830
33319
  if (error51 instanceof Error) {
32831
- console.error(import_chalk24.default.red(`
33320
+ console.error(import_chalk25.default.red(`
32832
33321
  \u2717 ${error51.message}
32833
33322
  `));
32834
33323
  }
@@ -32840,7 +33329,7 @@ org.action(async () => {
32840
33329
  await orgCommand();
32841
33330
  } catch (error51) {
32842
33331
  if (error51 instanceof Error) {
32843
- console.error(import_chalk24.default.red(`
33332
+ console.error(import_chalk25.default.red(`
32844
33333
  \u2717 ${error51.message}
32845
33334
  `));
32846
33335
  }
@@ -32852,7 +33341,7 @@ program.command("connect <workspace-name...>").description("Connect to a workspa
32852
33341
  await connectCommand(workspaceName.join(" "));
32853
33342
  } catch (error51) {
32854
33343
  if (error51 instanceof Error) {
32855
- console.error(import_chalk24.default.red(`
33344
+ console.error(import_chalk25.default.red(`
32856
33345
  \u2717 ${error51.message}
32857
33346
  `));
32858
33347
  }
@@ -32863,7 +33352,7 @@ program.command("tunnel <workspace-name...>").description("Forward a workspace p
32863
33352
  try {
32864
33353
  await tunnelCommand(workspaceName.join(" "), options);
32865
33354
  } catch (error51) {
32866
- console.error(import_chalk24.default.red(`
33355
+ console.error(import_chalk25.default.red(`
32867
33356
  Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
32868
33357
  process.exit(1);
32869
33358
  }
@@ -32873,7 +33362,7 @@ program.command("code [workspace-name...]").description("Open a workspace in VSC
32873
33362
  await codeCommand(workspaceName.join(" "));
32874
33363
  } catch (error51) {
32875
33364
  if (error51 instanceof Error) {
32876
- console.error(import_chalk24.default.red(`
33365
+ console.error(import_chalk25.default.red(`
32877
33366
  \u2717 ${error51.message}
32878
33367
  `));
32879
33368
  }
@@ -32886,7 +33375,7 @@ config2.command("get <key>").description("Get a configuration value").action(asy
32886
33375
  await configGetCommand(key);
32887
33376
  } catch (error51) {
32888
33377
  if (error51 instanceof Error) {
32889
- console.error(import_chalk24.default.red(`
33378
+ console.error(import_chalk25.default.red(`
32890
33379
  \u2717 ${error51.message}
32891
33380
  `));
32892
33381
  }
@@ -32898,7 +33387,7 @@ config2.command("set <key> <value>").description("Set a configuration value").ac
32898
33387
  await configSetCommand(key, value);
32899
33388
  } catch (error51) {
32900
33389
  if (error51 instanceof Error) {
32901
- console.error(import_chalk24.default.red(`
33390
+ console.error(import_chalk25.default.red(`
32902
33391
  \u2717 ${error51.message}
32903
33392
  `));
32904
33393
  }
@@ -32910,7 +33399,7 @@ config2.command("list").description("List all configuration values").action(asyn
32910
33399
  await configListCommand();
32911
33400
  } catch (error51) {
32912
33401
  if (error51 instanceof Error) {
32913
- console.error(import_chalk24.default.red(`
33402
+ console.error(import_chalk25.default.red(`
32914
33403
  \u2717 ${error51.message}
32915
33404
  `));
32916
33405
  }
@@ -32922,7 +33411,7 @@ program.command("list").description("List all replicas").option("-p, --page <pag
32922
33411
  await replicaListCommand(options);
32923
33412
  } catch (error51) {
32924
33413
  if (error51 instanceof Error) {
32925
- console.error(import_chalk24.default.red(`
33414
+ console.error(import_chalk25.default.red(`
32926
33415
  \u2717 ${error51.message}
32927
33416
  `));
32928
33417
  }
@@ -32934,7 +33423,7 @@ program.command("get <id>").description("Get replica details by ID").action(asyn
32934
33423
  await replicaGetCommand(id);
32935
33424
  } catch (error51) {
32936
33425
  if (error51 instanceof Error) {
32937
- console.error(import_chalk24.default.red(`
33426
+ console.error(import_chalk25.default.red(`
32938
33427
  \u2717 ${error51.message}
32939
33428
  `));
32940
33429
  }
@@ -32946,7 +33435,7 @@ program.command("create [name]").description("Create a new replica").option("-m,
32946
33435
  await replicaCreateCommand(name, options);
32947
33436
  } catch (error51) {
32948
33437
  if (error51 instanceof Error) {
32949
- console.error(import_chalk24.default.red(`
33438
+ console.error(import_chalk25.default.red(`
32950
33439
  \u2717 ${error51.message}
32951
33440
  `));
32952
33441
  }
@@ -32958,7 +33447,7 @@ program.command("send <id>").description("Send a message to a replica").option("
32958
33447
  await replicaSendCommand(id, options);
32959
33448
  } catch (error51) {
32960
33449
  if (error51 instanceof Error) {
32961
- console.error(import_chalk24.default.red(`
33450
+ console.error(import_chalk25.default.red(`
32962
33451
  \u2717 ${error51.message}
32963
33452
  `));
32964
33453
  }
@@ -32970,7 +33459,7 @@ program.command("delete <id>").description("Delete a replica").option("-f, --for
32970
33459
  await replicaDeleteCommand(id, options);
32971
33460
  } catch (error51) {
32972
33461
  if (error51 instanceof Error) {
32973
- console.error(import_chalk24.default.red(`
33462
+ console.error(import_chalk25.default.red(`
32974
33463
  \u2717 ${error51.message}
32975
33464
  `));
32976
33465
  }
@@ -32982,7 +33471,7 @@ program.command("read <id>").description("Read conversation history of a replica
32982
33471
  await replicaReadCommand(id, options);
32983
33472
  } catch (error51) {
32984
33473
  if (error51 instanceof Error) {
32985
- console.error(import_chalk24.default.red(`
33474
+ console.error(import_chalk25.default.red(`
32986
33475
  \u2717 ${error51.message}
32987
33476
  `));
32988
33477
  }
@@ -32995,7 +33484,7 @@ automation.command("list").description("List all automations").option("-p, --pag
32995
33484
  await automationListCommand(options);
32996
33485
  } catch (error51) {
32997
33486
  if (error51 instanceof Error) {
32998
- console.error(import_chalk24.default.red(`
33487
+ console.error(import_chalk25.default.red(`
32999
33488
  \u2717 ${error51.message}
33000
33489
  `));
33001
33490
  }
@@ -33007,7 +33496,7 @@ automation.command("get <id>").description("Get automation details by ID").actio
33007
33496
  await automationGetCommand(id);
33008
33497
  } catch (error51) {
33009
33498
  if (error51 instanceof Error) {
33010
- console.error(import_chalk24.default.red(`
33499
+ console.error(import_chalk25.default.red(`
33011
33500
  \u2717 ${error51.message}
33012
33501
  `));
33013
33502
  }
@@ -33022,7 +33511,7 @@ automation.command("create [name]").description("Create a new automation").optio
33022
33511
  });
33023
33512
  } catch (error51) {
33024
33513
  if (error51 instanceof Error) {
33025
- console.error(import_chalk24.default.red(`
33514
+ console.error(import_chalk25.default.red(`
33026
33515
  \u2717 ${error51.message}
33027
33516
  `));
33028
33517
  }
@@ -33034,7 +33523,7 @@ automation.command("edit <id>").description("Edit an existing automation").optio
33034
33523
  await automationEditCommand(id, options);
33035
33524
  } catch (error51) {
33036
33525
  if (error51 instanceof Error) {
33037
- console.error(import_chalk24.default.red(`
33526
+ console.error(import_chalk25.default.red(`
33038
33527
  \u2717 ${error51.message}
33039
33528
  `));
33040
33529
  }
@@ -33046,7 +33535,7 @@ automation.command("run <id>").description("Manually trigger an automation (cron
33046
33535
  await automationRunCommand(id);
33047
33536
  } catch (error51) {
33048
33537
  if (error51 instanceof Error) {
33049
- console.error(import_chalk24.default.red(`
33538
+ console.error(import_chalk25.default.red(`
33050
33539
  \u2717 ${error51.message}
33051
33540
  `));
33052
33541
  }
@@ -33058,7 +33547,7 @@ automation.command("delete <id>").description("Delete an automation").option("-f
33058
33547
  await automationDeleteCommand(id, options);
33059
33548
  } catch (error51) {
33060
33549
  if (error51 instanceof Error) {
33061
- console.error(import_chalk24.default.red(`
33550
+ console.error(import_chalk25.default.red(`
33062
33551
  \u2717 ${error51.message}
33063
33552
  `));
33064
33553
  }
@@ -33070,7 +33559,7 @@ automation.command("check <checkRunId>").description("Report this automation run
33070
33559
  await automationCheckCommand(checkRunId, options);
33071
33560
  } catch (error51) {
33072
33561
  if (error51 instanceof Error) {
33073
- console.error(import_chalk24.default.red(`
33562
+ console.error(import_chalk25.default.red(`
33074
33563
  \u2717 ${error51.message}
33075
33564
  `));
33076
33565
  }
@@ -33082,7 +33571,7 @@ automation.action(async () => {
33082
33571
  await automationListCommand({});
33083
33572
  } catch (error51) {
33084
33573
  if (error51 instanceof Error) {
33085
- console.error(import_chalk24.default.red(`
33574
+ console.error(import_chalk25.default.red(`
33086
33575
  \u2717 ${error51.message}
33087
33576
  `));
33088
33577
  }
@@ -33095,7 +33584,7 @@ repos.command("list").description("List all repositories").action(async () => {
33095
33584
  await repositoriesListCommand();
33096
33585
  } catch (error51) {
33097
33586
  if (error51 instanceof Error) {
33098
- console.error(import_chalk24.default.red(`
33587
+ console.error(import_chalk25.default.red(`
33099
33588
  \u2717 ${error51.message}
33100
33589
  `));
33101
33590
  }
@@ -33107,7 +33596,7 @@ repos.action(async () => {
33107
33596
  await repositoriesListCommand();
33108
33597
  } catch (error51) {
33109
33598
  if (error51 instanceof Error) {
33110
- console.error(import_chalk24.default.red(`
33599
+ console.error(import_chalk25.default.red(`
33111
33600
  \u2717 ${error51.message}
33112
33601
  `));
33113
33602
  }
@@ -33120,7 +33609,7 @@ environment.command("list").description("List all environments").action(async ()
33120
33609
  await environmentListCommand();
33121
33610
  } catch (error51) {
33122
33611
  if (error51 instanceof Error) {
33123
- console.error(import_chalk24.default.red(`
33612
+ console.error(import_chalk25.default.red(`
33124
33613
  \u2717 ${error51.message}
33125
33614
  `));
33126
33615
  }
@@ -33132,7 +33621,7 @@ environment.command("get <id-or-name>").description('Get an environment by ID or
33132
33621
  await environmentGetCommand(idOrName);
33133
33622
  } catch (error51) {
33134
33623
  if (error51 instanceof Error) {
33135
- console.error(import_chalk24.default.red(`
33624
+ console.error(import_chalk25.default.red(`
33136
33625
  \u2717 ${error51.message}
33137
33626
  `));
33138
33627
  }
@@ -33144,7 +33633,7 @@ environment.command("create [name]").description("Create a new environment").opt
33144
33633
  await environmentCreateCommand(name, options);
33145
33634
  } catch (error51) {
33146
33635
  if (error51 instanceof Error) {
33147
- console.error(import_chalk24.default.red(`
33636
+ console.error(import_chalk25.default.red(`
33148
33637
  \u2717 ${error51.message}
33149
33638
  `));
33150
33639
  }
@@ -33156,7 +33645,7 @@ environment.command("edit <id-or-name>").description("Edit an environment").opti
33156
33645
  await environmentEditCommand(idOrName, options);
33157
33646
  } catch (error51) {
33158
33647
  if (error51 instanceof Error) {
33159
- console.error(import_chalk24.default.red(`
33648
+ console.error(import_chalk25.default.red(`
33160
33649
  \u2717 ${error51.message}
33161
33650
  `));
33162
33651
  }
@@ -33168,7 +33657,7 @@ environment.command("delete <id-or-name>").description("Delete an environment").
33168
33657
  await environmentDeleteCommand(idOrName, options);
33169
33658
  } catch (error51) {
33170
33659
  if (error51 instanceof Error) {
33171
- console.error(import_chalk24.default.red(`
33660
+ console.error(import_chalk25.default.red(`
33172
33661
  \u2717 ${error51.message}
33173
33662
  `));
33174
33663
  }
@@ -33181,7 +33670,7 @@ envVars.command("list <env>").description("List variables in an environment (val
33181
33670
  await envVarsListCommand(env, options);
33182
33671
  } catch (error51) {
33183
33672
  if (error51 instanceof Error) {
33184
- console.error(import_chalk24.default.red(`
33673
+ console.error(import_chalk25.default.red(`
33185
33674
  \u2717 ${error51.message}
33186
33675
  `));
33187
33676
  }
@@ -33193,7 +33682,7 @@ envVars.command("set <env> <key> <value>").description("Create or update a varia
33193
33682
  await envVarsSetCommand(env, key, value);
33194
33683
  } catch (error51) {
33195
33684
  if (error51 instanceof Error) {
33196
- console.error(import_chalk24.default.red(`
33685
+ console.error(import_chalk25.default.red(`
33197
33686
  \u2717 ${error51.message}
33198
33687
  `));
33199
33688
  }
@@ -33205,7 +33694,7 @@ envVars.command("delete <env> <key-or-id>").description("Delete a variable by ke
33205
33694
  await envVarsDeleteCommand(env, keyOrId, options);
33206
33695
  } catch (error51) {
33207
33696
  if (error51 instanceof Error) {
33208
- console.error(import_chalk24.default.red(`
33697
+ console.error(import_chalk25.default.red(`
33209
33698
  \u2717 ${error51.message}
33210
33699
  `));
33211
33700
  }
@@ -33218,7 +33707,7 @@ envFiles.command("list <env>").description("List files in an environment").actio
33218
33707
  await envFilesListCommand(env);
33219
33708
  } catch (error51) {
33220
33709
  if (error51 instanceof Error) {
33221
- console.error(import_chalk24.default.red(`
33710
+ console.error(import_chalk25.default.red(`
33222
33711
  \u2717 ${error51.message}
33223
33712
  `));
33224
33713
  }
@@ -33230,7 +33719,7 @@ envFiles.command("set <env> <destination-path>").description("Create or update a
33230
33719
  await envFilesSetCommand(env, destinationPath, options);
33231
33720
  } catch (error51) {
33232
33721
  if (error51 instanceof Error) {
33233
- console.error(import_chalk24.default.red(`
33722
+ console.error(import_chalk25.default.red(`
33234
33723
  \u2717 ${error51.message}
33235
33724
  `));
33236
33725
  }
@@ -33242,7 +33731,7 @@ envFiles.command("delete <env> <path-or-id>").description("Delete a file by dest
33242
33731
  await envFilesDeleteCommand(env, pathOrId, options);
33243
33732
  } catch (error51) {
33244
33733
  if (error51 instanceof Error) {
33245
- console.error(import_chalk24.default.red(`
33734
+ console.error(import_chalk25.default.red(`
33246
33735
  \u2717 ${error51.message}
33247
33736
  `));
33248
33737
  }
@@ -33255,7 +33744,7 @@ function registerEnvironmentHookCommands(parent, config3) {
33255
33744
  try {
33256
33745
  await command();
33257
33746
  } catch (error51) {
33258
- if (error51 instanceof Error) console.error(import_chalk24.default.red(`
33747
+ if (error51 instanceof Error) console.error(import_chalk25.default.red(`
33259
33748
  \u2717 ${error51.message}
33260
33749
  `));
33261
33750
  process.exit(1);
@@ -33291,7 +33780,7 @@ environment.action(async () => {
33291
33780
  await environmentListCommand();
33292
33781
  } catch (error51) {
33293
33782
  if (error51 instanceof Error) {
33294
- console.error(import_chalk24.default.red(`
33783
+ console.error(import_chalk25.default.red(`
33295
33784
  \u2717 ${error51.message}
33296
33785
  `));
33297
33786
  }
@@ -33342,7 +33831,7 @@ if (isAgentMode()) {
33342
33831
  await previewAddCommand(workspaceId, options);
33343
33832
  } catch (error51) {
33344
33833
  if (error51 instanceof Error) {
33345
- console.error(import_chalk24.default.red(`
33834
+ console.error(import_chalk25.default.red(`
33346
33835
  \u2717 ${error51.message}
33347
33836
  `));
33348
33837
  }
@@ -33354,7 +33843,7 @@ if (isAgentMode()) {
33354
33843
  await previewListCommand(workspaceId);
33355
33844
  } catch (error51) {
33356
33845
  if (error51 instanceof Error) {
33357
- console.error(import_chalk24.default.red(`
33846
+ console.error(import_chalk25.default.red(`
33358
33847
  \u2717 ${error51.message}
33359
33848
  `));
33360
33849
  }
@@ -33366,7 +33855,7 @@ if (isAgentMode()) {
33366
33855
  await previewRemoveCommand(workspaceId, options);
33367
33856
  } catch (error51) {
33368
33857
  if (error51 instanceof Error) {
33369
- console.error(import_chalk24.default.red(`
33858
+ console.error(import_chalk25.default.red(`
33370
33859
  \u2717 ${error51.message}
33371
33860
  `));
33372
33861
  }
@@ -33374,6 +33863,26 @@ if (isAgentMode()) {
33374
33863
  }
33375
33864
  });
33376
33865
  }
33866
+ if (isEnvironmentSetupWorkspace()) {
33867
+ const environmentSetup = program.command("environment-setup").description("Report progress and propose configuration for an agent-led environment setup run");
33868
+ const runEnvironmentSetupCommand = (action) => async () => {
33869
+ try {
33870
+ await action();
33871
+ } catch (error51) {
33872
+ if (error51 instanceof Error) {
33873
+ console.error(import_chalk25.default.red(`
33874
+ \u2717 ${error51.message}
33875
+ `));
33876
+ }
33877
+ process.exit(1);
33878
+ }
33879
+ };
33880
+ environmentSetup.command("status").description("Show the setup run attached to this workspace").action(runEnvironmentSetupCommand(() => environmentSetupStatusCommand()));
33881
+ environmentSetup.command("step <key> <status>").description("Update a checklist step (understand | install | verify | configure | propose) to pending | in_progress | completed | skipped").action((key, status) => runEnvironmentSetupCommand(() => environmentSetupStepCommand(key, status))());
33882
+ environmentSetup.command("propose").description("Submit the proposed configuration for the user to review and save").requiredOption("-f, --file <path>", "Path to the proposal JSON file").action((options) => runEnvironmentSetupCommand(() => environmentSetupProposeCommand(options))());
33883
+ environmentSetup.command("request-variables").description("Ask the user for variables the app needs; returns immediately so you can keep working").requiredOption("-f, --file <path>", 'Path to a JSON file: { "variables": [{ "key", "description", "required" }] }').action((options) => runEnvironmentSetupCommand(() => environmentSetupRequestVariablesCommand(options))());
33884
+ environmentSetup.command("wait-variables").description("Wait until requested required variables are provided or skipped, then export them for new shells (default 5m)").option("-t, --timeout <duration>", "How long to wait, e.g. 90s or 5m (max 15m)").option("-k, --keys <keys>", "Comma-separated keys to wait for instead of every pending required key").action((options) => runEnvironmentSetupCommand(() => environmentSetupWaitVariablesCommand(options))());
33885
+ }
33377
33886
  if (isAgentMode()) {
33378
33887
  const identity = program.command("identity").description("Obtain short-lived workspace identity tokens (OIDC) for the services this workspace calls");
33379
33888
  identity.command("token").description("Print a workspace token for an audience (defaults to replicas:workspace)").option("-a, --audience <audience>", "Audience (`aud`) the receiving service verifies, for example its URL").addOption(new import_commander.Option("--format <format>", "Output a raw token or Google executable credentials").choices(["text", "gcp"]).default("text")).action(identityTokenCommand);
@@ -33431,7 +33940,7 @@ if (isAgentMode()) {
33431
33940
  await mediaUploadCommand(files, options);
33432
33941
  } catch (error51) {
33433
33942
  if (error51 instanceof Error) {
33434
- console.error(import_chalk24.default.red(`
33943
+ console.error(import_chalk25.default.red(`
33435
33944
  \u2717 ${error51.message}
33436
33945
  `));
33437
33946
  }
@@ -33442,7 +33951,7 @@ if (isAgentMode()) {
33442
33951
  try {
33443
33952
  await mediaShareCommand(mediaId);
33444
33953
  } catch (error51) {
33445
- if (error51 instanceof Error) console.error(import_chalk24.default.red(`
33954
+ if (error51 instanceof Error) console.error(import_chalk25.default.red(`
33446
33955
  \u2717 ${error51.message}
33447
33956
  `));
33448
33957
  process.exit(1);
@@ -33452,7 +33961,7 @@ if (isAgentMode()) {
33452
33961
  try {
33453
33962
  await mediaRevokeCommand(mediaId);
33454
33963
  } catch (error51) {
33455
- if (error51 instanceof Error) console.error(import_chalk24.default.red(`
33964
+ if (error51 instanceof Error) console.error(import_chalk25.default.red(`
33456
33965
  \u2717 ${error51.message}
33457
33966
  `));
33458
33967
  process.exit(1);
@@ -33462,7 +33971,7 @@ if (isAgentMode()) {
33462
33971
  try {
33463
33972
  await mediaDeleteCommand(mediaId);
33464
33973
  } catch (error51) {
33465
- if (error51 instanceof Error) console.error(import_chalk24.default.red(`
33974
+ if (error51 instanceof Error) console.error(import_chalk25.default.red(`
33466
33975
  \u2717 ${error51.message}
33467
33976
  `));
33468
33977
  process.exit(1);
@@ -33473,7 +33982,7 @@ if (isAgentMode()) {
33473
33982
  await mediaListCommand(options);
33474
33983
  } catch (error51) {
33475
33984
  if (error51 instanceof Error) {
33476
- console.error(import_chalk24.default.red(`
33985
+ console.error(import_chalk25.default.red(`
33477
33986
  \u2717 ${error51.message}
33478
33987
  `));
33479
33988
  }
@@ -33486,7 +33995,7 @@ if (isAgentMode()) {
33486
33995
  await mothershipMonitorChannelCommand(options);
33487
33996
  } catch (error51) {
33488
33997
  if (error51 instanceof Error) {
33489
- console.error(import_chalk24.default.red(`
33998
+ console.error(import_chalk25.default.red(`
33490
33999
  \u2717 ${error51.message}
33491
34000
  `));
33492
34001
  }
@@ -33498,7 +34007,7 @@ if (isAgentMode()) {
33498
34007
  await mothershipSpawnCommand(options);
33499
34008
  } catch (error51) {
33500
34009
  if (error51 instanceof Error) {
33501
- console.error(import_chalk24.default.red(`
34010
+ console.error(import_chalk25.default.red(`
33502
34011
  \u2717 ${error51.message}
33503
34012
  `));
33504
34013
  }
@@ -33510,7 +34019,7 @@ if (isAgentMode()) {
33510
34019
  await mothershipRelayCommand(options);
33511
34020
  } catch (error51) {
33512
34021
  if (error51 instanceof Error) {
33513
- console.error(import_chalk24.default.red(`
34022
+ console.error(import_chalk25.default.red(`
33514
34023
  \u2717 ${error51.message}
33515
34024
  `));
33516
34025
  }
@@ -33532,6 +34041,7 @@ if (isAgentMode()) {
33532
34041
  "automation",
33533
34042
  "repos",
33534
34043
  "environment",
34044
+ "environment-setup",
33535
34045
  "mothership"
33536
34046
  ]);
33537
34047
  const kept = program.commands.filter((cmd) => allowed.has(cmd.name()));
@@ -33543,7 +34053,7 @@ async function main() {
33543
34053
  if (process.argv[2] === "computer" && isAgentMode()) {
33544
34054
  const result = (0, import_node_child_process3.spawnSync)("replicas-computer", process.argv.slice(3), { stdio: "inherit" });
33545
34055
  if (result.error) {
33546
- console.error(import_chalk24.default.red(`
34056
+ console.error(import_chalk25.default.red(`
33547
34057
  \u2717 replicas-computer is unavailable in this workspace image
33548
34058
  `));
33549
34059
  process.exitCode = 1;