replicas-cli 0.2.752 → 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 +1101 -593
  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,10 +7362,10 @@ 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";
@@ -7376,6 +7376,7 @@ var WEB_APP_PATHS = {
7376
7376
  home: "/",
7377
7377
  onboarding: "/onboarding",
7378
7378
  workspaces: "/workspace",
7379
+ environmentSetup: "/workspace/setup",
7379
7380
  automations: "/automations",
7380
7381
  environment: "/environment",
7381
7382
  analytics: "/analytics",
@@ -7534,6 +7535,9 @@ function isAgentMode() {
7534
7535
  return false;
7535
7536
  }
7536
7537
  }
7538
+ function isEnvironmentSetupWorkspace() {
7539
+ return isAgentMode() && !!process.env.REPLICAS_ENVIRONMENT_SETUP_RUN_ID;
7540
+ }
7537
7541
  function readAgentConfig() {
7538
7542
  if (!import_fs.default.existsSync(CONFIG_FILE)) {
7539
7543
  return null;
@@ -7649,6 +7653,9 @@ var import_prompts3 = __toESM(require("prompts"));
7649
7653
  function isRecord(value) {
7650
7654
  return typeof value === "object" && value !== null && !Array.isArray(value);
7651
7655
  }
7656
+ function isNonEmptyString(value) {
7657
+ return typeof value === "string" && value.trim().length > 0;
7658
+ }
7652
7659
 
7653
7660
  // ../shared/src/json.ts
7654
7661
  function safeJsonParse(str, fallback) {
@@ -8657,10 +8664,10 @@ function mergeDefs(...defs) {
8657
8664
  function cloneDef(schema) {
8658
8665
  return mergeDefs(schema._zod.def);
8659
8666
  }
8660
- function getElementAtPath(obj, path6) {
8661
- if (!path6)
8667
+ function getElementAtPath(obj, path7) {
8668
+ if (!path7)
8662
8669
  return obj;
8663
- return path6.reduce((acc, key) => acc?.[key], obj);
8670
+ return path7.reduce((acc, key) => acc?.[key], obj);
8664
8671
  }
8665
8672
  function promiseAllObject(promisesObj) {
8666
8673
  const keys = Object.keys(promisesObj);
@@ -9069,11 +9076,11 @@ function explicitlyAborted(x, startIndex = 0) {
9069
9076
  }
9070
9077
  return false;
9071
9078
  }
9072
- function prefixIssues(path6, issues) {
9079
+ function prefixIssues(path7, issues) {
9073
9080
  return issues.map((iss) => {
9074
9081
  var _a3;
9075
9082
  (_a3 = iss).path ?? (_a3.path = []);
9076
- iss.path.unshift(path6);
9083
+ iss.path.unshift(path7);
9077
9084
  return iss;
9078
9085
  });
9079
9086
  }
@@ -9220,16 +9227,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
9220
9227
  }
9221
9228
  function formatError(error51, mapper = (issue2) => issue2.message) {
9222
9229
  const fieldErrors = { _errors: [] };
9223
- const processError = (error52, path6 = []) => {
9230
+ const processError = (error52, path7 = []) => {
9224
9231
  for (const issue2 of error52.issues) {
9225
9232
  if (issue2.code === "invalid_union" && issue2.errors.length) {
9226
- issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
9233
+ issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
9227
9234
  } else if (issue2.code === "invalid_key") {
9228
- processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
9235
+ processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
9229
9236
  } else if (issue2.code === "invalid_element") {
9230
- processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
9237
+ processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
9231
9238
  } else {
9232
- const fullpath = [...path6, ...issue2.path];
9239
+ const fullpath = [...path7, ...issue2.path];
9233
9240
  if (fullpath.length === 0) {
9234
9241
  fieldErrors._errors.push(mapper(issue2));
9235
9242
  } else {
@@ -9256,17 +9263,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
9256
9263
  }
9257
9264
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
9258
9265
  const result = { errors: [] };
9259
- const processError = (error52, path6 = []) => {
9266
+ const processError = (error52, path7 = []) => {
9260
9267
  var _a3, _b;
9261
9268
  for (const issue2 of error52.issues) {
9262
9269
  if (issue2.code === "invalid_union" && issue2.errors.length) {
9263
- issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
9270
+ issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
9264
9271
  } else if (issue2.code === "invalid_key") {
9265
- processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
9272
+ processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
9266
9273
  } else if (issue2.code === "invalid_element") {
9267
- processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
9274
+ processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
9268
9275
  } else {
9269
- const fullpath = [...path6, ...issue2.path];
9276
+ const fullpath = [...path7, ...issue2.path];
9270
9277
  if (fullpath.length === 0) {
9271
9278
  result.errors.push(mapper(issue2));
9272
9279
  continue;
@@ -9298,8 +9305,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
9298
9305
  }
9299
9306
  function toDotPath(_path) {
9300
9307
  const segs = [];
9301
- const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
9302
- for (const seg of path6) {
9308
+ const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
9309
+ for (const seg of path7) {
9303
9310
  if (typeof seg === "number")
9304
9311
  segs.push(`[${seg}]`);
9305
9312
  else if (typeof seg === "symbol")
@@ -21991,13 +21998,13 @@ function resolveRef(ref, ctx) {
21991
21998
  if (!ref.startsWith("#")) {
21992
21999
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
21993
22000
  }
21994
- const path6 = ref.slice(1).split("/").filter(Boolean);
21995
- if (path6.length === 0) {
22001
+ const path7 = ref.slice(1).split("/").filter(Boolean);
22002
+ if (path7.length === 0) {
21996
22003
  return ctx.rootSchema;
21997
22004
  }
21998
22005
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
21999
- if (path6[0] === defsKey) {
22000
- const key = path6[1];
22006
+ if (path7[0] === defsKey) {
22007
+ const key = path7[1];
22001
22008
  if (!key || !ctx.defs[key]) {
22002
22009
  throw new Error(`Reference not found: ${ref}`);
22003
22010
  }
@@ -23206,11 +23213,11 @@ function parseShellScript(script, cwd) {
23206
23213
  parseUntil(scope, 0, false);
23207
23214
  return scope.commands;
23208
23215
  }
23209
- function resolveShellPath(dir, path6) {
23210
- if (path6.includes(SHELL_OPAQUE) || path6.startsWith("~")) return null;
23211
- 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;
23212
23219
  const parts = [];
23213
- for (const part of (path6.startsWith("/") ? path6 : `${dir}/${path6}`).split("/")) {
23220
+ for (const part of (path7.startsWith("/") ? path7 : `${dir}/${path7}`).split("/")) {
23214
23221
  if (part === "..") parts.pop();
23215
23222
  else if (part && part !== ".") parts.push(part);
23216
23223
  }
@@ -23560,16 +23567,16 @@ function parseSkillName(tool, input) {
23560
23567
  const skillName = parsedInput.skill ?? parsedInput.name;
23561
23568
  return typeof skillName === "string" && skillName ? skillName : null;
23562
23569
  }
23563
- function skillNameFromFilePath(path6) {
23564
- const skillName = skillNameFromSkillRootPath(path6);
23570
+ function skillNameFromFilePath(path7) {
23571
+ const skillName = skillNameFromSkillRootPath(path7);
23565
23572
  if (skillName) return skillName;
23566
- const parts = path6.split(/[\\/]+/).filter(Boolean);
23573
+ const parts = path7.split(/[\\/]+/).filter(Boolean);
23567
23574
  if (parts.length < 2 || parts[parts.length - 1].toLowerCase() !== "skill.md") return null;
23568
23575
  const fallbackSkillName = parts[parts.length - 2];
23569
23576
  return fallbackSkillName && fallbackSkillName.toLowerCase() !== "skills" ? fallbackSkillName : null;
23570
23577
  }
23571
- function skillNameFromSkillRootPath(path6) {
23572
- const parts = path6.split(/[\\/]+/).filter(Boolean);
23578
+ function skillNameFromSkillRootPath(path7) {
23579
+ const parts = path7.split(/[\\/]+/).filter(Boolean);
23573
23580
  const skillsIndex = parts.findLastIndex((part) => part.toLowerCase() === "skills");
23574
23581
  if (skillsIndex === -1) return null;
23575
23582
  const firstSkillPart = parts[skillsIndex + 1];
@@ -23579,9 +23586,9 @@ function skillNameFromSkillRootPath(path6) {
23579
23586
  function parseSkillFilePath(input) {
23580
23587
  const parsedInput = typeof input === "string" ? safeJsonParse(input, null) : input;
23581
23588
  if (!isRecord(parsedInput)) return null;
23582
- const path6 = [parsedInput.path, parsedInput.filePath, parsedInput.file_path].find((value) => typeof value === "string" && value.length > 0);
23583
- if (!path6) return null;
23584
- 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);
23585
23592
  }
23586
23593
  function skillNameFromToolCall(tool, input) {
23587
23594
  const directSkillName = parseSkillName(tool, input);
@@ -23893,8 +23900,451 @@ var DOCKER_ABILITY = {
23893
23900
  referenceFile: { name: "DOCKER.md", content: REFERENCE2 }
23894
23901
  };
23895
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
+
23896
24346
  // ../shared/src/default-skills/replicas-agent/abilities/github.ts
23897
- var SECTION3 = `### GitHub
24347
+ var SECTION4 = `### GitHub
23898
24348
  Use the pre-authenticated \`gh\` CLI for repository workflows and the workspace-scoped TypeScript SDK for GitHub API calls.
23899
24349
 
23900
24350
  **Reference:** \`references/GITHUB.md\`
@@ -23904,7 +24354,7 @@ Use this when:
23904
24354
  - You need to interact with GitHub issues or actions
23905
24355
  - You need to use the GitHub API for advanced operations
23906
24356
  - You need to include images in PR descriptions`;
23907
- var REFERENCE3 = `# GitHub Integration
24357
+ var REFERENCE4 = `# GitHub Integration
23908
24358
 
23909
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.
23910
24360
 
@@ -24033,12 +24483,12 @@ var GITHUB_ABILITY = {
24033
24483
  label: "GitHub",
24034
24484
  description: "GitHub workflows through gh and API calls through @replicas/sdk.",
24035
24485
  bullet: "- Interacting with GitHub (creating PRs, managing issues, using the API, etc.)",
24036
- section: SECTION3,
24037
- referenceFile: { name: "GITHUB.md", content: REFERENCE3 }
24486
+ section: SECTION4,
24487
+ referenceFile: { name: "GITHUB.md", content: REFERENCE4 }
24038
24488
  };
24039
24489
 
24040
24490
  // ../shared/src/default-skills/replicas-agent/abilities/gitlab.ts
24041
- var SECTION4 = `### GitLab
24491
+ var SECTION5 = `### GitLab
24042
24492
  Use plain git for repository traffic and the workspace-scoped TypeScript SDK for GitLab API operations.
24043
24493
 
24044
24494
  **Reference:** \`references/GITLAB.md\`
@@ -24047,7 +24497,7 @@ Use this when:
24047
24497
  - A repository remote is on gitlab.com or a self-managed GitLab instance
24048
24498
  - You need to open or update a merge request
24049
24499
  - You need GitLab issues, pipelines, comments, or other API data`;
24050
- var REFERENCE4 = `# GitLab Integration
24500
+ var REFERENCE5 = `# GitLab Integration
24051
24501
 
24052
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.
24053
24503
 
@@ -24095,12 +24545,12 @@ var GITLAB_ABILITY = {
24095
24545
  label: "GitLab",
24096
24546
  description: "Git for repository traffic and @replicas/sdk for the GitLab API.",
24097
24547
  bullet: "- Interacting with GitLab (pushing to GitLab repos, opening merge requests)",
24098
- section: SECTION4,
24099
- referenceFile: { name: "GITLAB.md", content: REFERENCE4 }
24548
+ section: SECTION5,
24549
+ referenceFile: { name: "GITLAB.md", content: REFERENCE5 }
24100
24550
  };
24101
24551
 
24102
24552
  // ../shared/src/default-skills/replicas-agent/abilities/linear.ts
24103
- var SECTION5 = `### Linear
24553
+ var SECTION6 = `### Linear
24104
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.
24105
24555
 
24106
24556
  **Reference:** \`references/LINEAR.md\`
@@ -24111,7 +24561,7 @@ Use this when:
24111
24561
  - You need to update an issue's state or add a comment
24112
24562
  - You need to search Linear issues
24113
24563
  - A Linear request failed with an authentication error`;
24114
- var REFERENCE5 = `# Linear Integration
24564
+ var REFERENCE6 = `# Linear Integration
24115
24565
 
24116
24566
  Use \`@replicas/sdk\`; never request or handle a Linear OAuth token. Replicas refreshes the organization credential behind the gateway.
24117
24567
 
@@ -24200,12 +24650,12 @@ var LINEAR_ABILITY = {
24200
24650
  label: "Linear",
24201
24651
  description: "Create tickets, fetch issues, comment, and update state through @replicas/sdk.",
24202
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.",
24203
- section: SECTION5,
24204
- referenceFile: { name: "LINEAR.md", content: REFERENCE5 }
24653
+ section: SECTION6,
24654
+ referenceFile: { name: "LINEAR.md", content: REFERENCE6 }
24205
24655
  };
24206
24656
 
24207
24657
  // ../shared/src/default-skills/replicas-agent/abilities/media.ts
24208
- var SECTION6 = `### Media
24658
+ var SECTION7 = `### Media
24209
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.
24210
24660
 
24211
24661
  **Reference:** \`references/MEDIA.md\`
@@ -24216,7 +24666,7 @@ Use this when:
24216
24666
  - You produce a self-contained HTML report that should be linked from a pull request
24217
24667
  - You record video output (browser automation, screen capture) \u2014 including the recommended aspect ratio and FPS
24218
24668
  - You need to embed media in a Slack/Linear/GitHub/GitLab message AND keep a referenceable copy in the Replicas dashboard`;
24219
- var REFERENCE6 = `# Media (Screenshots, Recordings, Audio, HTML)
24669
+ var REFERENCE7 = `# Media (Screenshots, Recordings, Audio, HTML)
24220
24670
 
24221
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).
24222
24672
 
@@ -24541,8 +24991,8 @@ var MEDIA_ABILITY = {
24541
24991
  label: "Media",
24542
24992
  description: "Deliver media to Replicas and destination workflows with inline uploads.",
24543
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",
24544
- section: SECTION6,
24545
- referenceFile: { name: "MEDIA.md", content: REFERENCE6 }
24994
+ section: SECTION7,
24995
+ referenceFile: { name: "MEDIA.md", content: REFERENCE7 }
24546
24996
  };
24547
24997
 
24548
24998
  // ../shared/src/sandbox.ts
@@ -24590,7 +25040,7 @@ var memoryGenerationManifestSchema = external_exports.object({
24590
25040
  });
24591
25041
 
24592
25042
  // ../shared/src/default-skills/replicas-agent/abilities/memory.ts
24593
- var SECTION7 = `### Memory
25043
+ var SECTION8 = `### Memory
24594
25044
  Check relevant long-term memory before substantive work when historical context could improve the result.
24595
25045
 
24596
25046
  **Reference:** \`references/MEMORY.md\`
@@ -24602,7 +25052,7 @@ Use this when:
24602
25052
  - Related work may explain an error or implementation choice
24603
25053
 
24604
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.`;
24605
- var REFERENCE7 = `# Long-term memory
25055
+ var REFERENCE8 = `# Long-term memory
24606
25056
 
24607
25057
  Replicas memory is installed under \`~/.replicas/memories\`:
24608
25058
 
@@ -24625,13 +25075,13 @@ var MEMORY_ABILITY = {
24625
25075
  label: "Memory",
24626
25076
  description: "Check private and organization memory before substantive work.",
24627
25077
  bullet: "",
24628
- section: SECTION7,
24629
- referenceFile: { name: "MEMORY.md", content: REFERENCE7 },
25078
+ section: SECTION8,
25079
+ referenceFile: { name: "MEMORY.md", content: REFERENCE8 },
24630
25080
  locked: true
24631
25081
  };
24632
25082
 
24633
25083
  // ../shared/src/default-skills/replicas-agent/abilities/previews.ts
24634
- var SECTION8 = `### Previews
25084
+ var SECTION9 = `### Previews
24635
25085
  Expose locally running services (web apps, APIs, databases) as public preview URLs so humans can interact with them directly.
24636
25086
 
24637
25087
  **Reference:** \`references/PREVIEWS.md\`
@@ -24640,7 +25090,7 @@ Use this when:
24640
25090
  - You need to start a service that a human should view or interact with
24641
25091
  - The task involves UI work that benefits from human review
24642
25092
  - You are verifying frontend/backend integrations visually`;
24643
- var REFERENCE8 = `# Preview URLs
25093
+ var REFERENCE9 = `# Preview URLs
24644
25094
 
24645
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.
24646
25096
 
@@ -24716,12 +25166,12 @@ var PREVIEWS_ABILITY = {
24716
25166
  label: "Previews",
24717
25167
  description: "Expose locally running services on public preview URLs for humans.",
24718
25168
  bullet: "- Creating preview URLs for locally running services",
24719
- section: SECTION8,
24720
- referenceFile: { name: "PREVIEWS.md", content: REFERENCE8 }
25169
+ section: SECTION9,
25170
+ referenceFile: { name: "PREVIEWS.md", content: REFERENCE9 }
24721
25171
  };
24722
25172
 
24723
25173
  // ../shared/src/default-skills/replicas-agent/abilities/plugins.ts
24724
- var SECTION9 = `### Plugins
25174
+ var SECTION10 = `### Plugins
24725
25175
  Discover and execute installed marketplace tools through the workspace-scoped TypeScript SDK.
24726
25176
 
24727
25177
  **Reference:** \`references/PLUGINS.md\`
@@ -24737,7 +25187,7 @@ Use this when:
24737
25187
  - The user asks to query or update a connected turbopuffer namespace
24738
25188
  - The user asks for PlanetScale organizations, databases, branches, or Insights data
24739
25189
  - The user asks to analyze text with Pangram`;
24740
- var REFERENCE9 = `# Plugins
25190
+ var REFERENCE10 = `# Plugins
24741
25191
 
24742
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.
24743
25193
 
@@ -24908,12 +25358,12 @@ var PLUGINS_ABILITY = {
24908
25358
  label: "Plugins",
24909
25359
  description: "Use installed marketplace tools through @replicas/sdk.",
24910
25360
  bullet: "- Interacting with installed marketplace plugins through TypeScript",
24911
- section: SECTION9,
24912
- referenceFile: { name: "PLUGINS.md", content: REFERENCE9 }
25361
+ section: SECTION10,
25362
+ referenceFile: { name: "PLUGINS.md", content: REFERENCE10 }
24913
25363
  };
24914
25364
 
24915
25365
  // ../shared/src/default-skills/replicas-agent/abilities/replicas.ts
24916
- var SECTION10 = `### Replicas (in-workspace CLI)
25366
+ var SECTION11 = `### Replicas (in-workspace CLI)
24917
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.
24918
25368
 
24919
25369
  **Reference:** \`references/REPLICAS.md\`
@@ -24924,7 +25374,7 @@ Use this when:
24924
25374
  - The user asks "what envs / repos / automations do I have?"
24925
25375
  - The user asks you to scaffold a \`replicas.json\` / \`replicas.yaml\` in a repo
24926
25376
  - You need to run a long-lived service (dev server, daemon) \u2014 always use \`replicas service start\` so it survives workspace sleep/wake`;
24927
- var REFERENCE10 = `# Replicas (in-workspace CLI)
25377
+ var REFERENCE11 = `# Replicas (in-workspace CLI)
24928
25378
 
24929
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.
24930
25380
 
@@ -24962,6 +25412,7 @@ In agent mode the CLI hides commands that don't make sense for in-workspace agen
24962
25412
  | \`replicas repos\` | List repos connected to the org |
24963
25413
  | \`replicas environment ...\` | Manage environments, env vars, env files |
24964
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\`) |
24965
25416
  | \`replicas preview ...\` | Register / list preview URLs (covered in \`PREVIEWS.md\`) |
24966
25417
  | \`replicas service ...\` | Run long-lived services detached so they survive workspace sleep/wake (see below) |
24967
25418
  | \`replicas media ...\` | Upload, list, share, revoke, or delete workspace media; follow \`MEDIA.md\` for destination embedding |
@@ -25155,13 +25606,13 @@ var REPLICAS_ABILITY = {
25155
25606
  description: "Teach the agent about Replicas itself \u2014 automations, environments, the in-workspace CLI.",
25156
25607
  // No bullet — help_instructions covers the `replicas` CLI surface in detail.
25157
25608
  bullet: "",
25158
- section: SECTION10,
25159
- referenceFile: { name: "REPLICAS.md", content: REFERENCE10 },
25609
+ section: SECTION11,
25610
+ referenceFile: { name: "REPLICAS.md", content: REFERENCE11 },
25160
25611
  locked: true
25161
25612
  };
25162
25613
 
25163
25614
  // ../shared/src/default-skills/replicas-agent/abilities/sentry.ts
25164
- var SECTION11 = `### Sentry
25615
+ var SECTION12 = `### Sentry
25165
25616
  Read issues and project data through the workspace-scoped TypeScript SDK.
25166
25617
 
25167
25618
  **Reference:** \`references/SENTRY.md\`
@@ -25169,7 +25620,7 @@ Read issues and project data through the workspace-scoped TypeScript SDK.
25169
25620
  Use this when:
25170
25621
  - You need to inspect Sentry projects or issues
25171
25622
  - A user asks for error-monitoring context outside a webhook-triggered task`;
25172
- var REFERENCE11 = `# Sentry Integration
25623
+ var REFERENCE12 = `# Sentry Integration
25173
25624
 
25174
25625
  Use \`@replicas/sdk\`; never request or read a Sentry token. Sentry access is organization-scoped and read-only.
25175
25626
 
@@ -25187,8 +25638,8 @@ var SENTRY_ABILITY = {
25187
25638
  label: "Sentry",
25188
25639
  description: "Read Sentry projects and issues through @replicas/sdk.",
25189
25640
  bullet: "- Interacting with Sentry (reading projects, issues, and error context)",
25190
- section: SECTION11,
25191
- referenceFile: { name: "SENTRY.md", content: REFERENCE11 }
25641
+ section: SECTION12,
25642
+ referenceFile: { name: "SENTRY.md", content: REFERENCE12 }
25192
25643
  };
25193
25644
 
25194
25645
  // ../shared/src/slack-response-style.ts
@@ -25198,7 +25649,7 @@ var SLACK_BLOCK_KIT_GUIDANCE = "Use Block Kit whenever structure or a link would
25198
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.';
25199
25650
 
25200
25651
  // ../shared/src/default-skills/replicas-agent/abilities/slack.ts
25201
- var SECTION12 = `### Slack
25652
+ var SECTION13 = `### Slack
25202
25653
  Send messages, read threads, search conversations, and transfer files through the workspace-scoped TypeScript SDK.
25203
25654
 
25204
25655
  **Reference:** \`references/SLACK.md\`
@@ -25208,7 +25659,7 @@ Use this when:
25208
25659
  - You need to read or search Slack conversations
25209
25660
  - You need to download a file attached to a Slack message
25210
25661
  - You encounter a Slack message link and need its full thread`;
25211
- var REFERENCE12 = `# Slack Integration
25662
+ var REFERENCE13 = `# Slack Integration
25212
25663
 
25213
25664
  Use \`@replicas/sdk\`; never read or send a Slack token directly. The SDK calls Replicas, which selects only this workspace's organization connection.
25214
25665
 
@@ -25286,8 +25737,8 @@ var SLACK_ABILITY = {
25286
25737
  label: "Slack",
25287
25738
  description: "Send messages, read threads, search, and transfer files through @replicas/sdk.",
25288
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.",
25289
- section: SECTION12,
25290
- referenceFile: { name: "SLACK.md", content: REFERENCE12 }
25740
+ section: SECTION13,
25741
+ referenceFile: { name: "SLACK.md", content: REFERENCE13 }
25291
25742
  };
25292
25743
 
25293
25744
  // ../shared/src/default-skills/replicas-agent/registry.ts
@@ -25296,6 +25747,7 @@ var REPLICAS_AGENT_ABILITY_REGISTRY = {
25296
25747
  memory: MEMORY_ABILITY,
25297
25748
  computer: COMPUTER_ABILITY,
25298
25749
  docker: DOCKER_ABILITY,
25750
+ environment_setup: ENVIRONMENT_SETUP_ABILITY,
25299
25751
  github: GITHUB_ABILITY,
25300
25752
  gitlab: GITLAB_ABILITY,
25301
25753
  linear: LINEAR_ABILITY,
@@ -26262,7 +26714,7 @@ function parseOpencodeEvents(events) {
26262
26714
  upsertDisplayMessage(messages, {
26263
26715
  id,
26264
26716
  type: "file_change",
26265
- changes: files.map((path6) => ({ path: path6, kind: "update" })),
26717
+ changes: files.map((path7) => ({ path: path7, kind: "update" })),
26266
26718
  status: "completed",
26267
26719
  timestamp
26268
26720
  });
@@ -27367,6 +27819,75 @@ var EGRESS_WORKSPACE_SHELL_VARS = {
27367
27819
  EGRESS_EXIT_IP_ENDPOINTS: EGRESS_EXIT_IP_ENDPOINTS.join(" ")
27368
27820
  };
27369
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
+
27370
27891
  // ../shared/src/slash-commands.ts
27371
27892
  var SIDE_CHAT_COMMANDS = ["/btw", "/side"];
27372
27893
  var SLASH_COMMANDS = [
@@ -27418,9 +27939,6 @@ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
27418
27939
  // ../shared/src/replicas-config.ts
27419
27940
  var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
27420
27941
 
27421
- // ../shared/src/uuid.ts
27422
- var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
27423
-
27424
27942
  // ../shared/src/terminal.ts
27425
27943
  var CONTROL_CHARACTERS = /[\u0000-\u001F\u007F-\u009F]/g;
27426
27944
  function sanitizeTerminalLine(value) {
@@ -27481,7 +27999,7 @@ var headlessFilesystemAgentResultSchema = external_exports.object({
27481
27999
  });
27482
28000
 
27483
28001
  // ../shared/src/cli-version.ts
27484
- var CLI_VERSION = "0.2.752";
28002
+ var CLI_VERSION = "0.2.753";
27485
28003
 
27486
28004
  // ../shared/src/version.ts
27487
28005
  function compareVersions(v1, v2) {
@@ -28217,186 +28735,6 @@ function identityTokenUrl() {
28217
28735
  return `http://127.0.0.1:${IDENTITY_PROXY_PORT}${IDENTITY_TOKEN_PATH}`;
28218
28736
  }
28219
28737
 
28220
- // ../shared/src/routes/environment-setups.ts
28221
- var ENVIRONMENT_SETUP_STEPS = [
28222
- { key: "understand", label: "Understand the codebase" },
28223
- { key: "install", label: "Install dependencies and run the app" },
28224
- { key: "verify", label: "Verify checks and record a walkthrough" },
28225
- { key: "configure", label: "Draft hooks, system prompt, and automations" },
28226
- { key: "propose", label: "Propose the configuration for review" }
28227
- ];
28228
- var ENVIRONMENT_SETUP_STEP_STATUSES = ["pending", "in_progress", "completed", "skipped"];
28229
- var ENVIRONMENT_SETUP_RUN_STATUSES = ["running", "proposed", "applied", "failed", "cancelled"];
28230
- var ENVIRONMENT_SETUP_AUTOMATION_ACTIONS = ["create", "update", "keep", "disable"];
28231
- var ENVIRONMENT_SETUP_VERIFICATION_STATUSES = ["passed", "failed", "skipped"];
28232
- var ENVIRONMENT_SETUP_LIMITS = {
28233
- summaryChars: 600,
28234
- stackItems: 30,
28235
- nameChars: 120,
28236
- descriptionChars: 1e3,
28237
- systemPromptChars: 2e4,
28238
- hookChars: 5e4,
28239
- variables: 50,
28240
- variableKeyChars: 128,
28241
- variableDescriptionChars: 500,
28242
- automations: 8,
28243
- automationKeyChars: 80,
28244
- automationPromptChars: 1e4,
28245
- automationTriggers: 5,
28246
- automationNoteChars: 300,
28247
- verificationItems: 8,
28248
- verificationDetailChars: 300,
28249
- mediaItems: 8,
28250
- repositories: 20
28251
- };
28252
- var ENVIRONMENT_SETUP_VARIABLE_WAIT = { defaultMs: 5 * 6e4, maxMs: 15 * 6e4, pollMs: 5e3 };
28253
- var VARIABLE_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
28254
- var text = (max) => max === void 0 ? external_exports.string().trim() : external_exports.string().trim().max(max);
28255
- var requiredText = (max) => text(max).min(1, "must not be empty");
28256
- var optionalText = (max) => text(max).nullish().transform((value) => value || null);
28257
- var clearableText = (max) => text(max).nullish().transform((value) => value === void 0 ? void 0 : value || null);
28258
- var list = (item, max) => max === void 0 ? external_exports.array(item) : external_exports.array(item).max(max);
28259
- var ENVIRONMENT_SETUP_AUTHORED_TRIGGER_TYPES = ["cron", "github", "gitlab"];
28260
- function isEnvironmentSetupAuthoredTriggerType(type) {
28261
- return ENVIRONMENT_SETUP_AUTHORED_TRIGGER_TYPES.some((authored) => authored === type);
28262
- }
28263
- var repositoryTriggerConfigSchema = external_exports.object({
28264
- event: external_exports.string(),
28265
- repository_ids: external_exports.array(external_exports.string().regex(UUID_RE, "must be a repository id")).optional(),
28266
- group_pr_events: external_exports.boolean().optional(),
28267
- excluded_actors: external_exports.array(external_exports.string()).optional()
28268
- });
28269
- var proposalTriggerSchema = external_exports.discriminatedUnion("type", [
28270
- external_exports.object({ type: external_exports.literal("cron"), config: external_exports.object({ schedule: external_exports.string(), timezone: external_exports.string().optional() }) }),
28271
- external_exports.object({ type: external_exports.literal("github"), config: repositoryTriggerConfigSchema }),
28272
- external_exports.object({ type: external_exports.literal("gitlab"), config: repositoryTriggerConfigSchema })
28273
- ]);
28274
- var existingTriggerSchema = external_exports.custom(
28275
- (value) => isRecord(value) && typeof value.type === "string" && isRecord(value.config),
28276
- "must be an automation trigger"
28277
- );
28278
- var carriedTriggerSchema = existingTriggerSchema.refine(
28279
- (trigger) => !isEnvironmentSetupAuthoredTriggerType(trigger.type)
28280
- );
28281
- function automationSchema(limits) {
28282
- const authored = external_exports.object({
28283
- name: text(limits.nameChars),
28284
- description: text(limits.descriptionChars),
28285
- prompt: text(limits.automationPromptChars),
28286
- triggers: list(proposalTriggerSchema, limits.automationTriggers)
28287
- });
28288
- const updated = authored.extend({ triggers: list(external_exports.union([proposalTriggerSchema, carriedTriggerSchema]), limits.automationTriggers) });
28289
- return external_exports.object({
28290
- key: requiredText(limits.automationKeyChars),
28291
- action: external_exports.enum(ENVIRONMENT_SETUP_AUTOMATION_ACTIONS).default("create"),
28292
- automation_id: external_exports.string().regex(UUID_RE, "must be an automation id").nullable().default(null),
28293
- name: text().default(""),
28294
- description: optionalText().transform((value) => value ?? ""),
28295
- prompt: text().default(""),
28296
- triggers: list(existingTriggerSchema).default([]),
28297
- note: optionalText(limits.automationNoteChars)
28298
- }).superRefine((automation2, ctx) => {
28299
- if (automation2.action === "create" && automation2.automation_id) {
28300
- ctx.addIssue({ code: "custom", path: ["automation_id"], message: "belongs on an update, keep, or disable entry" });
28301
- }
28302
- if (automation2.action !== "create" && !automation2.automation_id) {
28303
- ctx.addIssue({ code: "custom", path: ["automation_id"], message: "must be the id of an automation attached to this environment" });
28304
- }
28305
- if (automation2.action === "create" || automation2.action === "update") {
28306
- if (!automation2.name) ctx.addIssue({ code: "custom", path: ["name"], message: "must not be empty" });
28307
- if (!automation2.prompt) ctx.addIssue({ code: "custom", path: ["prompt"], message: "must not be empty" });
28308
- if (automation2.triggers.length === 0) ctx.addIssue({ code: "custom", path: ["triggers"], message: "must not be empty" });
28309
- }
28310
- }).transform((automation2, ctx) => {
28311
- if (automation2.action === "keep" || automation2.action === "disable") return automation2;
28312
- const content = (automation2.action === "update" ? updated : authored).safeParse(automation2);
28313
- if (content.success) return { ...automation2, ...content.data };
28314
- for (const issue2 of content.error.issues) ctx.addIssue({ ...issue2, code: "custom" });
28315
- return external_exports.NEVER;
28316
- });
28317
- }
28318
- function automationListSchema(limits) {
28319
- return list(automationSchema(limits)).default([]).superRefine((automations, ctx) => {
28320
- if (new Set(automations.map((automation2) => automation2.key)).size !== automations.length) {
28321
- ctx.addIssue({ code: "custom", message: "must have unique keys" });
28322
- }
28323
- const targets = automations.flatMap((automation2) => automation2.automation_id ?? []);
28324
- if (new Set(targets).size !== targets.length) {
28325
- ctx.addIssue({ code: "custom", message: "must mention each existing automation once" });
28326
- }
28327
- if (limits.automations !== void 0 && automations.filter((automation2) => automation2.action === "create").length > limits.automations) {
28328
- ctx.addIssue({ code: "custom", message: `must create at most ${limits.automations} new automations` });
28329
- }
28330
- });
28331
- }
28332
- function environmentSchema(limits) {
28333
- return external_exports.object({
28334
- name: optionalText(limits.nameChars).transform((value) => value ?? void 0),
28335
- description: clearableText(limits.descriptionChars),
28336
- system_prompt: clearableText(limits.systemPromptChars),
28337
- start_hook: clearableText(limits.hookChars),
28338
- warm_hook: clearableText(limits.hookChars)
28339
- });
28340
- }
28341
- function variableSchema(limits, requiredDefault) {
28342
- return external_exports.object({
28343
- key: external_exports.string().regex(VARIABLE_KEY_RE, "must be a valid environment variable name").max(limits.variableKeyChars ?? Number.POSITIVE_INFINITY),
28344
- description: optionalText(limits.variableDescriptionChars).transform((value) => value ?? ""),
28345
- required: external_exports.boolean().default(requiredDefault)
28346
- });
28347
- }
28348
- function proposalSchema(limits) {
28349
- return external_exports.object({
28350
- summary: requiredText(limits.summaryChars),
28351
- stack: list(text(), limits.stackItems).default([]).transform((items) => items.filter(Boolean)),
28352
- environment: environmentSchema(limits),
28353
- variables: list(variableSchema(limits, false), limits.variables).default([]),
28354
- automations: automationListSchema(limits),
28355
- verification: list(external_exports.object({
28356
- label: requiredText(limits.nameChars),
28357
- status: external_exports.enum(ENVIRONMENT_SETUP_VERIFICATION_STATUSES),
28358
- detail: optionalText(limits.verificationDetailChars).transform((value) => value ?? void 0)
28359
- }), limits.verificationItems).default([]),
28360
- media: list(external_exports.object({
28361
- media_id: external_exports.string().regex(UUID_RE, "must be a media id"),
28362
- title: requiredText(limits.nameChars)
28363
- }), limits.mediaItems).default([])
28364
- });
28365
- }
28366
- var environmentSetupProposalSchema = proposalSchema({});
28367
- var environmentSetupProposalSubmissionSchema = proposalSchema(ENVIRONMENT_SETUP_LIMITS);
28368
- var environmentSetupVariableRequestSchema = variableSchema({}, false).extend({
28369
- status: external_exports.enum(["pending", "provided", "skipped"]),
28370
- requested_at: external_exports.string(),
28371
- resolved_at: external_exports.string().nullable().default(null)
28372
- });
28373
- var environmentSetupRunStateSchema = external_exports.object({
28374
- status: external_exports.enum(ENVIRONMENT_SETUP_RUN_STATUSES),
28375
- steps: external_exports.partialRecord(external_exports.enum(ENVIRONMENT_SETUP_STEPS.map((step) => step.key)), external_exports.enum(ENVIRONMENT_SETUP_STEP_STATUSES)).default({}),
28376
- proposal: environmentSetupProposalSchema.nullable().default(null),
28377
- applied: external_exports.object({
28378
- applied_at: external_exports.string(),
28379
- automation_ids: external_exports.array(external_exports.string())
28380
- }).nullable().default(null),
28381
- variable_requests: external_exports.array(environmentSetupVariableRequestSchema).default([])
28382
- });
28383
- var applyEnvironmentSetupRequestSchema = external_exports.object({
28384
- environment: environmentSchema(ENVIRONMENT_SETUP_LIMITS).extend({ name: requiredText(ENVIRONMENT_SETUP_LIMITS.nameChars) }),
28385
- 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)),
28386
- automations: automationListSchema(ENVIRONMENT_SETUP_LIMITS)
28387
- });
28388
- var requestEnvironmentSetupVariablesSchema = external_exports.object({
28389
- variables: list(variableSchema(ENVIRONMENT_SETUP_LIMITS, true), ENVIRONMENT_SETUP_LIMITS.variables).min(1, "must not be empty")
28390
- }).superRefine(({ variables }, ctx) => {
28391
- if (new Set(variables.map((variable) => variable.key)).size !== variables.length) {
28392
- ctx.addIssue({ code: "custom", path: ["variables"], message: "must have unique keys" });
28393
- }
28394
- });
28395
- var respondEnvironmentSetupVariablesSchema = external_exports.object({
28396
- values: external_exports.record(external_exports.string().regex(VARIABLE_KEY_RE), external_exports.string()).default({}),
28397
- skipped: external_exports.array(external_exports.string().regex(VARIABLE_KEY_RE)).default([])
28398
- });
28399
-
28400
28738
  // src/lib/monolith-url.ts
28401
28739
  var MONOLITH_URL = process.env.REPLICAS_MONOLITH_URL || process.env.MONOLITH_URL || "https://api.replicas.dev";
28402
28740
 
@@ -29976,8 +30314,8 @@ async function claudeAuthCommand(options = {}) {
29976
30314
  var CLIENT_ID = "1031625952748946";
29977
30315
  var AUTH_URL = "https://auth.meta.com";
29978
30316
  var API_KEY_URL = "https://api.meta.ai/muse-code/key";
29979
- async function post(path6, body) {
29980
- return fetch(`${AUTH_URL}${path6}`, {
30317
+ async function post(path7, body) {
30318
+ return fetch(`${AUTH_URL}${path7}`, {
29981
30319
  method: "POST",
29982
30320
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
29983
30321
  body
@@ -30652,14 +30990,163 @@ Repositories (${response.repositories.length}):
30652
30990
  }
30653
30991
  }
30654
30992
 
30655
- // 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"));
30656
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"));
30657
31144
  var import_prompts7 = __toESM(require("prompts"));
30658
31145
  function parseScopeFilter(value) {
30659
31146
  if (!value) return void 0;
30660
31147
  if (value === "org" || value === "user" || value === "all") return value;
30661
- console.log(import_chalk19.default.red(`Invalid --owner: ${value}`));
30662
- 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"));
30663
31150
  process.exit(1);
30664
31151
  }
30665
31152
  function parseAgentProviderOption(value) {
@@ -30668,8 +31155,8 @@ function parseAgentProviderOption(value) {
30668
31155
  if (trimmed === "" || trimmed.toLowerCase() === "none") return null;
30669
31156
  const lower = trimmed.toLowerCase();
30670
31157
  if (!isValidAgentProvider(lower)) {
30671
- console.log(import_chalk19.default.red(`Invalid --agent-provider: ${value}`));
30672
- 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`));
30673
31160
  process.exit(1);
30674
31161
  }
30675
31162
  return lower;
@@ -30680,8 +31167,8 @@ function parseThinkingLevelOption(value) {
30680
31167
  if (trimmed === "" || trimmed.toLowerCase() === "none") return null;
30681
31168
  const lower = trimmed.toLowerCase();
30682
31169
  if (!isValidThinkingLevel(lower)) {
30683
- console.log(import_chalk19.default.red(`Invalid --thinking-level: ${value}`));
30684
- 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`));
30685
31172
  process.exit(1);
30686
31173
  }
30687
31174
  return lower;
@@ -30698,8 +31185,8 @@ function isAutomationLifecyclePolicy(value) {
30698
31185
  function parseWorkspaceLifecyclePolicyOption(value) {
30699
31186
  if (!value) return void 0;
30700
31187
  if (isAutomationLifecyclePolicy(value)) return value;
30701
- console.log(import_chalk19.default.red(`Invalid lifecycle policy: ${value}`));
30702
- 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(", ")}`));
30703
31190
  process.exit(1);
30704
31191
  }
30705
31192
  function parseExcludedActorsOption(value) {
@@ -30718,7 +31205,7 @@ function withExcludedActors(config3, excludedActors) {
30718
31205
  }
30719
31206
  function parseAutomationLifecycleOptions(options) {
30720
31207
  if (options.sleepWhenDone && options.lifecycle && options.lifecycle !== "sleep_when_done") {
30721
- 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"));
30722
31209
  process.exit(1);
30723
31210
  }
30724
31211
  if (options.sleepWhenDone) return "sleep_when_done";
@@ -30727,7 +31214,7 @@ function parseAutomationLifecycleOptions(options) {
30727
31214
  function applyAgentSelection(body, existing) {
30728
31215
  const result = validateAgentSelection(body, existing, AGENT_MODELS);
30729
31216
  if (!result.ok) {
30730
- console.log(import_chalk19.default.red(result.error.message));
31217
+ console.log(import_chalk20.default.red(result.error.message));
30731
31218
  process.exit(1);
30732
31219
  }
30733
31220
  const out = {};
@@ -30768,8 +31255,8 @@ function resolveTriggerRepositoryIds(repositories, repoNamesInput, provider) {
30768
31255
  for (const repoName of repoNames) {
30769
31256
  const repo = providerRepos.find((r) => r.name === repoName);
30770
31257
  if (!repo) {
30771
- console.log(import_chalk19.default.red(`Repository not found for ${provider} trigger filter: ${repoName}`));
30772
- 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(", ")}`));
30773
31260
  process.exit(1);
30774
31261
  }
30775
31262
  repoIds.push(repo.id);
@@ -30802,43 +31289,43 @@ function formatModeSummary(automation2) {
30802
31289
  function resolveSelectableEnvironmentId(envInput, selectableEnvs) {
30803
31290
  const resolved = resolveByNameOrId(envInput, selectableEnvs);
30804
31291
  if (!resolved) {
30805
- console.log(import_chalk19.default.red(`Environment not found: ${envInput}`));
31292
+ console.log(import_chalk20.default.red(`Environment not found: ${envInput}`));
30806
31293
  const available = selectableEnvs.map((e) => e.name).join(", ");
30807
- console.log(import_chalk19.default.gray(`Available: ${available || "(none)"}`));
31294
+ console.log(import_chalk20.default.gray(`Available: ${available || "(none)"}`));
30808
31295
  process.exit(1);
30809
31296
  }
30810
31297
  return resolved.id;
30811
31298
  }
30812
31299
  function printAutomation(automation2) {
30813
- console.log(import_chalk19.default.white(` ${automation2.name}`));
30814
- console.log(import_chalk19.default.gray(` ID: ${automation2.id}`));
30815
- 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"}`));
30816
31303
  if (automation2.description) {
30817
- console.log(import_chalk19.default.gray(` Description: ${automation2.description}`));
31304
+ console.log(import_chalk20.default.gray(` Description: ${automation2.description}`));
30818
31305
  }
30819
- 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")}`));
30820
31307
  if (automation2.triggers.length > 0) {
30821
- 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(", ")}`));
30822
31309
  }
30823
31310
  if (automation2.github_check_names.length > 0) {
30824
- 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(", ")}`));
30825
31312
  }
30826
- console.log(import_chalk19.default.gray(` Prompt: ${truncate2(automation2.prompt, 80)}`));
31313
+ console.log(import_chalk20.default.gray(` Prompt: ${truncate2(automation2.prompt, 80)}`));
30827
31314
  if (automation2.cron_next_fire_at) {
30828
- 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)}`));
30829
31316
  }
30830
31317
  if (automation2.workspace_lifecycle_policy && automation2.workspace_lifecycle_policy !== "default") {
30831
- console.log(import_chalk19.default.gray(` Lifecycle: ${automation2.workspace_lifecycle_policy}`));
31318
+ console.log(import_chalk20.default.gray(` Lifecycle: ${automation2.workspace_lifecycle_policy}`));
30832
31319
  }
30833
31320
  if (automation2.agent_provider || automation2.model || automation2.thinking_level) {
30834
- console.log(import_chalk19.default.gray(` Agent: ${formatAgentSummary(automation2)}`));
31321
+ console.log(import_chalk20.default.gray(` Agent: ${formatAgentSummary(automation2)}`));
30835
31322
  }
30836
31323
  if (automation2.plan_mode || automation2.goal_mode || automation2.fast_mode) {
30837
- console.log(import_chalk19.default.gray(` Modes: ${formatModeSummary(automation2)}`));
31324
+ console.log(import_chalk20.default.gray(` Modes: ${formatModeSummary(automation2)}`));
30838
31325
  }
30839
- console.log(import_chalk19.default.gray(` PR Follow-ups: ${automation2.config.capabilities?.pr_followups === true ? import_chalk19.default.green("managed") : "read-only"}`));
30840
- console.log(import_chalk19.default.gray(` Created: ${formatDate2(automation2.created_at)}`));
30841
- 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)}`));
30842
31329
  console.log();
30843
31330
  }
30844
31331
  async function automationListCommand(options) {
@@ -30857,17 +31344,17 @@ async function automationListCommand(options) {
30857
31344
  `/v1/automations${query ? "?" + query : ""}`
30858
31345
  );
30859
31346
  if (response.automations.length === 0) {
30860
- console.log(import_chalk19.default.yellow("\nNo automations found.\n"));
31347
+ console.log(import_chalk20.default.yellow("\nNo automations found.\n"));
30861
31348
  return;
30862
31349
  }
30863
- console.log(import_chalk19.default.green(`
31350
+ console.log(import_chalk20.default.green(`
30864
31351
  Automations (Page ${response.page} of ${response.totalPages}, Total: ${response.total}):
30865
31352
  `));
30866
31353
  for (const automation2 of response.automations) {
30867
31354
  printAutomation(automation2);
30868
31355
  }
30869
31356
  } catch (error51) {
30870
- 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"}`));
30871
31358
  process.exit(1);
30872
31359
  }
30873
31360
  }
@@ -30876,50 +31363,50 @@ async function automationGetCommand(id) {
30876
31363
  try {
30877
31364
  const response = await orgAuthenticatedFetch(`/v1/automations/${id}`);
30878
31365
  const automation2 = response.automation;
30879
- console.log(import_chalk19.default.green(`
31366
+ console.log(import_chalk20.default.green(`
30880
31367
  Automation: ${automation2.name}
30881
31368
  `));
30882
- console.log(import_chalk19.default.gray(` ID: ${automation2.id}`));
31369
+ console.log(import_chalk20.default.gray(` ID: ${automation2.id}`));
30883
31370
  if (automation2.description) {
30884
- console.log(import_chalk19.default.gray(` Description: ${automation2.description}`));
31371
+ console.log(import_chalk20.default.gray(` Description: ${automation2.description}`));
30885
31372
  }
30886
- 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")}`));
30887
31374
  if (automation2.triggers.length > 0) {
30888
- console.log(import_chalk19.default.gray(` Triggers:`));
31375
+ console.log(import_chalk20.default.gray(` Triggers:`));
30889
31376
  for (const trigger of automation2.triggers) {
30890
- console.log(import_chalk19.default.gray(` - ${formatTrigger(trigger)}`));
31377
+ console.log(import_chalk20.default.gray(` - ${formatTrigger(trigger)}`));
30891
31378
  }
30892
31379
  }
30893
31380
  if (automation2.github_check_names.length > 0) {
30894
- 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(", ")}`));
30895
31382
  }
30896
- console.log(import_chalk19.default.gray(` Prompt: ${automation2.prompt}`));
30897
- 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}`));
30898
31385
  if (automation2.cron_expression) {
30899
- console.log(import_chalk19.default.gray(` Cron: ${automation2.cron_expression}`));
31386
+ console.log(import_chalk20.default.gray(` Cron: ${automation2.cron_expression}`));
30900
31387
  }
30901
31388
  if (automation2.cron_timezone) {
30902
- console.log(import_chalk19.default.gray(` Timezone: ${automation2.cron_timezone}`));
31389
+ console.log(import_chalk20.default.gray(` Timezone: ${automation2.cron_timezone}`));
30903
31390
  }
30904
31391
  if (automation2.cron_next_fire_at) {
30905
- 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)}`));
30906
31393
  }
30907
31394
  if (automation2.workspace_lifecycle_policy) {
30908
- 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}`));
30909
31396
  }
30910
31397
  if (automation2.workspace_auto_stop_minutes) {
30911
- console.log(import_chalk19.default.gray(` Auto-stop: ${automation2.workspace_auto_stop_minutes} minutes`));
30912
- }
30913
- console.log(import_chalk19.default.gray(` Agent: ${automation2.agent_provider ? getProviderDisplayName(automation2.agent_provider) : "organization default"}`));
30914
- console.log(import_chalk19.default.gray(` Model: ${automation2.model ? MODEL_LABELS[automation2.model] ?? automation2.model : "agent default"}`));
30915
- console.log(import_chalk19.default.gray(` Thinking Level: ${automation2.thinking_level ?? "agent default"}`));
30916
- console.log(import_chalk19.default.gray(` Modes: ${formatModeSummary(automation2)}`));
30917
- console.log(import_chalk19.default.gray(` PR Follow-ups: ${automation2.config.capabilities?.pr_followups === true ? "managed" : "read-only"}`));
30918
- console.log(import_chalk19.default.gray(` Created: ${formatDate2(automation2.created_at)}`));
30919
- 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)}`));
30920
31407
  console.log();
30921
31408
  } catch (error51) {
30922
- 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"}`));
30923
31410
  process.exit(1);
30924
31411
  }
30925
31412
  }
@@ -31044,22 +31531,22 @@ async function automationCreateCommand(name, options) {
31044
31531
  ensureOrgApiAuthenticated();
31045
31532
  const lifecyclePolicy = parseAutomationLifecycleOptions(options);
31046
31533
  if (options.autoStopMinutes && !lifecyclePolicySupportsAutoStop(lifecyclePolicy ?? "default")) {
31047
- 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"));
31048
31535
  process.exit(1);
31049
31536
  }
31050
31537
  if (options.autoStopMinutes) {
31051
31538
  const minutes = parseInt(options.autoStopMinutes, 10);
31052
31539
  if (isNaN(minutes) || minutes < 3 || minutes > 1440) {
31053
- 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"));
31054
31541
  process.exit(1);
31055
31542
  }
31056
31543
  }
31057
31544
  if (options.triggerGithubExcludeUsers !== void 0 && !options.triggerGithub) {
31058
- 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"));
31059
31546
  process.exit(1);
31060
31547
  }
31061
31548
  if (options.triggerGitlabExcludeUsers !== void 0 && !options.triggerGitlab) {
31062
- 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"));
31063
31550
  process.exit(1);
31064
31551
  }
31065
31552
  const hasConfirmation = options.confirmationChannel || options.confirmationThread || options.confirmationMessageTs || options.confirmationUser;
@@ -31086,7 +31573,7 @@ async function automationCreateCommand(name, options) {
31086
31573
  );
31087
31574
  const selectableEnvs = envResponse.environments;
31088
31575
  if (selectableEnvs.length === 0) {
31089
- 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."));
31090
31577
  process.exit(1);
31091
31578
  }
31092
31579
  const repoResponse = await orgAuthenticatedFetch("/v1/repositories");
@@ -31100,7 +31587,7 @@ async function automationCreateCommand(name, options) {
31100
31587
  validate: (value) => value.trim() ? true : "Name is required"
31101
31588
  });
31102
31589
  if (!response2.name) {
31103
- console.log(import_chalk19.default.yellow("\nCancelled."));
31590
+ console.log(import_chalk20.default.yellow("\nCancelled."));
31104
31591
  return;
31105
31592
  }
31106
31593
  automationName = response2.name;
@@ -31114,7 +31601,7 @@ async function automationCreateCommand(name, options) {
31114
31601
  validate: (value) => value.trim() ? true : "Prompt is required"
31115
31602
  });
31116
31603
  if (!response2.prompt) {
31117
- console.log(import_chalk19.default.yellow("\nCancelled."));
31604
+ console.log(import_chalk20.default.yellow("\nCancelled."));
31118
31605
  return;
31119
31606
  }
31120
31607
  automationPrompt = response2.prompt;
@@ -31134,7 +31621,7 @@ async function automationCreateCommand(name, options) {
31134
31621
  }))
31135
31622
  });
31136
31623
  if (!envResponse2.env) {
31137
- console.log(import_chalk19.default.yellow("\nCancelled."));
31624
+ console.log(import_chalk20.default.yellow("\nCancelled."));
31138
31625
  return;
31139
31626
  }
31140
31627
  selectedEnvironmentId = envResponse2.env;
@@ -31176,7 +31663,7 @@ async function automationCreateCommand(name, options) {
31176
31663
  if (triggers.length === 0) {
31177
31664
  triggers = await promptForTriggers(repositories.map((r) => ({ id: r.id, name: r.name, provider: r.provider })));
31178
31665
  if (triggers.length === 0) {
31179
- 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."));
31180
31667
  process.exit(1);
31181
31668
  }
31182
31669
  }
@@ -31207,25 +31694,25 @@ async function automationCreateCommand(name, options) {
31207
31694
  ...agentSelection,
31208
31695
  ...mothershipConfirmation ? { mothership_confirmation: mothershipConfirmation } : {}
31209
31696
  };
31210
- console.log(import_chalk19.default.gray("\nCreating automation..."));
31697
+ console.log(import_chalk20.default.gray("\nCreating automation..."));
31211
31698
  const response = await orgAuthenticatedFetch("/v1/automations", {
31212
31699
  method: "POST",
31213
31700
  body
31214
31701
  });
31215
31702
  const automation2 = response.automation;
31216
- console.log(import_chalk19.default.green(`
31703
+ console.log(import_chalk20.default.green(`
31217
31704
  Created automation: ${automation2.name}`));
31218
- console.log(import_chalk19.default.gray(` ID: ${automation2.id}`));
31219
- 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"}`));
31220
31707
  if (automation2.triggers.length > 0) {
31221
- 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(", ")}`));
31222
31709
  }
31223
31710
  if (automation2.cron_next_fire_at) {
31224
- 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)}`));
31225
31712
  }
31226
31713
  console.log();
31227
31714
  } catch (error51) {
31228
- 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"}`));
31229
31716
  process.exit(1);
31230
31717
  }
31231
31718
  }
@@ -31235,17 +31722,17 @@ async function automationEditCommand(id, options) {
31235
31722
  if (options.autoStopMinutes) {
31236
31723
  const minutes = parseInt(options.autoStopMinutes, 10);
31237
31724
  if (isNaN(minutes) || minutes < 3 || minutes > 1440) {
31238
- 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"));
31239
31726
  process.exit(1);
31240
31727
  }
31241
31728
  }
31242
31729
  const replacingTriggers = Boolean(options.triggerCron || options.triggerGithub || options.triggerGitlab);
31243
31730
  if (replacingTriggers && options.triggerGithubExcludeUsers !== void 0 && !options.triggerGithub) {
31244
- 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"));
31245
31732
  process.exit(1);
31246
31733
  }
31247
31734
  if (replacingTriggers && options.triggerGitlabExcludeUsers !== void 0 && !options.triggerGitlab) {
31248
- 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"));
31249
31736
  process.exit(1);
31250
31737
  }
31251
31738
  const parsedAgent = {
@@ -31257,7 +31744,7 @@ async function automationEditCommand(id, options) {
31257
31744
  const existing = await orgAuthenticatedFetch(`/v1/automations/${id}`);
31258
31745
  const autoStopLifecyclePolicy = lifecyclePolicy ?? toAutomationLifecyclePolicy(existing.automation.workspace_lifecycle_policy);
31259
31746
  if (options.autoStopMinutes && !lifecyclePolicySupportsAutoStop(autoStopLifecyclePolicy)) {
31260
- 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"));
31261
31748
  process.exit(1);
31262
31749
  }
31263
31750
  const agentSelection = applyAgentSelection(parsedAgent, {
@@ -31397,11 +31884,11 @@ async function automationEditCommand(id, options) {
31397
31884
  return trigger;
31398
31885
  });
31399
31886
  if (!matchedGithub) {
31400
- 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."));
31401
31888
  process.exit(1);
31402
31889
  }
31403
31890
  if (!matchedGitlab) {
31404
- 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."));
31405
31892
  process.exit(1);
31406
31893
  }
31407
31894
  }
@@ -31426,25 +31913,25 @@ async function automationEditCommand(id, options) {
31426
31913
  Object.assign(body, agentSelection);
31427
31914
  }
31428
31915
  if (Object.keys(body).length === 0) {
31429
- console.log(import_chalk19.default.yellow("\nNo changes made.\n"));
31916
+ console.log(import_chalk20.default.yellow("\nNo changes made.\n"));
31430
31917
  return;
31431
31918
  }
31432
- console.log(import_chalk19.default.gray("\nUpdating automation..."));
31919
+ console.log(import_chalk20.default.gray("\nUpdating automation..."));
31433
31920
  const response = await orgAuthenticatedFetch(`/v1/automations/${id}`, {
31434
31921
  method: "PATCH",
31435
31922
  body
31436
31923
  });
31437
31924
  const automation2 = response.automation;
31438
- console.log(import_chalk19.default.green(`
31925
+ console.log(import_chalk20.default.green(`
31439
31926
  Updated automation: ${automation2.name}`));
31440
- console.log(import_chalk19.default.gray(` ID: ${automation2.id}`));
31441
- 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"}`));
31442
31929
  if (automation2.triggers.length > 0) {
31443
- 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(", ")}`));
31444
31931
  }
31445
31932
  console.log();
31446
31933
  } catch (error51) {
31447
- 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"}`));
31448
31935
  process.exit(1);
31449
31936
  }
31450
31937
  }
@@ -31455,12 +31942,12 @@ async function automationRunCommand(id) {
31455
31942
  const automation2 = existing.automation;
31456
31943
  const hasCronTrigger = automation2.triggers.some((t) => t.type === "cron");
31457
31944
  if (!hasCronTrigger) {
31458
- console.log(import_chalk19.default.red("\nManual run is only allowed for automations with a cron trigger."));
31459
- 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(", ")}`));
31460
31947
  console.log();
31461
31948
  process.exit(1);
31462
31949
  }
31463
- console.log(import_chalk19.default.gray(`
31950
+ console.log(import_chalk20.default.gray(`
31464
31951
  Triggering automation "${automation2.name}"...`));
31465
31952
  const response = await orgAuthenticatedFetch(
31466
31953
  `/v1/automations/${id}/trigger`,
@@ -31470,20 +31957,20 @@ Triggering automation "${automation2.name}"...`));
31470
31957
  }
31471
31958
  );
31472
31959
  if (!response.execution_id) {
31473
- console.log(import_chalk19.default.red(`
31960
+ console.log(import_chalk20.default.red(`
31474
31961
  Automation trigger returned no execution ID. The automation may not have started.`));
31475
31962
  console.log();
31476
31963
  process.exit(1);
31477
31964
  }
31478
- console.log(import_chalk19.default.green(`
31965
+ console.log(import_chalk20.default.green(`
31479
31966
  Automation triggered successfully.`));
31480
- console.log(import_chalk19.default.gray(` Execution ID: ${response.execution_id}`));
31967
+ console.log(import_chalk20.default.gray(` Execution ID: ${response.execution_id}`));
31481
31968
  if (response.workspace_id) {
31482
- console.log(import_chalk19.default.gray(` Workspace ID: ${response.workspace_id}`));
31969
+ console.log(import_chalk20.default.gray(` Workspace ID: ${response.workspace_id}`));
31483
31970
  }
31484
31971
  console.log();
31485
31972
  } catch (error51) {
31486
- 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"}`));
31487
31974
  process.exit(1);
31488
31975
  }
31489
31976
  }
@@ -31500,38 +31987,38 @@ async function automationDeleteCommand(id, options) {
31500
31987
  initial: false
31501
31988
  });
31502
31989
  if (!response.confirm) {
31503
- console.log(import_chalk19.default.yellow("\nCancelled."));
31990
+ console.log(import_chalk20.default.yellow("\nCancelled."));
31504
31991
  return;
31505
31992
  }
31506
31993
  }
31507
31994
  await orgAuthenticatedFetch(`/v1/automations/${id}`, {
31508
31995
  method: "DELETE"
31509
31996
  });
31510
- console.log(import_chalk19.default.green(`
31997
+ console.log(import_chalk20.default.green(`
31511
31998
  Automation "${automationName}" (${id}) deleted.
31512
31999
  `));
31513
32000
  } catch (error51) {
31514
- 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"}`));
31515
32002
  process.exit(1);
31516
32003
  }
31517
32004
  }
31518
32005
  async function automationCheckCommand(checkRunId, options) {
31519
32006
  const id = Number(checkRunId);
31520
32007
  if (!Number.isSafeInteger(id)) {
31521
- 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"));
31522
32009
  process.exit(1);
31523
32010
  }
31524
32011
  if (!options.token) {
31525
- console.error(import_chalk19.default.red("Error: --token is required"));
32012
+ console.error(import_chalk20.default.red("Error: --token is required"));
31526
32013
  process.exit(1);
31527
32014
  }
31528
32015
  const { conclusion } = options;
31529
32016
  if (!isAutomationCheckConclusion(conclusion)) {
31530
- 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(", ")}`));
31531
32018
  process.exit(1);
31532
32019
  }
31533
32020
  if (!options.title?.trim()) {
31534
- console.error(import_chalk19.default.red("Error: --title is required"));
32021
+ console.error(import_chalk20.default.red("Error: --title is required"));
31535
32022
  process.exit(1);
31536
32023
  }
31537
32024
  const body = {
@@ -31545,23 +32032,23 @@ async function automationCheckCommand(checkRunId, options) {
31545
32032
  `/v1/automations/checks/${id}`,
31546
32033
  { method: "POST", body }
31547
32034
  );
31548
- console.log(response.reported ? import_chalk19.default.green(`
32035
+ console.log(response.reported ? import_chalk20.default.green(`
31549
32036
  Reported ${conclusion} for "${response.name}".
31550
- `) : import_chalk19.default.yellow(`
32037
+ `) : import_chalk20.default.yellow(`
31551
32038
  Skipped "${response.name}" \u2014 a newer run of this automation owns it and will report the verdict.
31552
32039
  `));
31553
32040
  } catch (error51) {
31554
- 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"}`));
31555
32042
  process.exit(1);
31556
32043
  }
31557
32044
  }
31558
32045
 
31559
32046
  // src/commands/preview.ts
31560
- var import_chalk20 = __toESM(require("chalk"));
32047
+ var import_chalk21 = __toESM(require("chalk"));
31561
32048
 
31562
32049
  // src/lib/agent-api.ts
31563
32050
  var ENGINE_PORT = process.env.REPLICAS_ENGINE_PORT || "3737";
31564
- async function agentFetch(path6, options) {
32051
+ async function agentFetch(path7, options) {
31565
32052
  const config3 = readAgentConfig();
31566
32053
  if (!config3) {
31567
32054
  throw new Error("Agent mode config not found");
@@ -31575,7 +32062,7 @@ async function agentFetch(path6, options) {
31575
32062
  ...options?.headers || {}
31576
32063
  };
31577
32064
  const body = options?.body === void 0 ? void 0 : isFormData ? options.body : JSON.stringify(options.body);
31578
- const response = await fetch(`${MONOLITH_URL}${path6}`, {
32065
+ const response = await fetch(`${MONOLITH_URL}${path7}`, {
31579
32066
  ...options,
31580
32067
  headers,
31581
32068
  body
@@ -31586,7 +32073,7 @@ async function agentFetch(path6, options) {
31586
32073
  }
31587
32074
  return response.json();
31588
32075
  }
31589
- async function engineFetch(path6, options) {
32076
+ async function engineFetch(path7, options) {
31590
32077
  const config3 = readAgentConfig();
31591
32078
  if (!config3) {
31592
32079
  throw new Error("Agent mode config not found");
@@ -31596,7 +32083,7 @@ async function engineFetch(path6, options) {
31596
32083
  "Content-Type": "application/json",
31597
32084
  ...options?.headers || {}
31598
32085
  };
31599
- const response = await fetch(`http://localhost:${ENGINE_PORT}${path6}`, {
32086
+ const response = await fetch(`http://localhost:${ENGINE_PORT}${path7}`, {
31600
32087
  ...options,
31601
32088
  headers,
31602
32089
  body: options?.body !== void 0 ? JSON.stringify(options.body) : void 0
@@ -31651,11 +32138,11 @@ async function previewListCommand(workspaceId) {
31651
32138
  `/v1/workspaces/${workspaceId}/previews`
31652
32139
  );
31653
32140
  if (result.previews.length === 0) {
31654
- console.log(import_chalk20.default.dim("No active previews"));
32141
+ console.log(import_chalk21.default.dim("No active previews"));
31655
32142
  return;
31656
32143
  }
31657
32144
  for (const preview2 of result.previews) {
31658
- 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)}`);
31659
32146
  }
31660
32147
  }
31661
32148
  }
@@ -31668,7 +32155,7 @@ async function previewAddCommand(workspaceId, options) {
31668
32155
  body: { port: portNum, authenticated: options.authenticated ?? false }
31669
32156
  }
31670
32157
  );
31671
- console.log(import_chalk20.default.green(`Preview created: ${result.preview.publicUrl}`));
32158
+ console.log(import_chalk21.default.green(`Preview created: ${result.preview.publicUrl}`));
31672
32159
  }
31673
32160
  async function previewDeleteCommand(port) {
31674
32161
  const portNum = parsePreviewPort(port);
@@ -31681,12 +32168,12 @@ async function previewRemoveCommand(workspaceId, options) {
31681
32168
  `/v1/workspaces/${workspaceId}/previews/${portNum}`,
31682
32169
  { method: "DELETE" }
31683
32170
  );
31684
- console.log(import_chalk20.default.green(`Preview deleted on port ${portNum}`));
32171
+ console.log(import_chalk21.default.green(`Preview deleted on port ${portNum}`));
31685
32172
  }
31686
32173
 
31687
32174
  // src/commands/media.ts
31688
- var import_fs4 = __toESM(require("fs"));
31689
- var import_path5 = __toESM(require("path"));
32175
+ var import_fs5 = __toESM(require("fs"));
32176
+ var import_path6 = __toESM(require("path"));
31690
32177
  var MEDIA_ACCESS_VALUES = ["organization", "public"];
31691
32178
  function publicMediaUrl(mediaId, token) {
31692
32179
  return `${MONOLITH_URL}/v1/media/public/${mediaId}/${token}`;
@@ -31726,22 +32213,22 @@ function resolveKind(ext, override) {
31726
32213
  return inferred;
31727
32214
  }
31728
32215
  async function uploadOne(filePath, displayName, kind, options) {
31729
- const absPath = import_path5.default.resolve(filePath);
31730
- if (!import_fs4.default.existsSync(absPath)) {
32216
+ const absPath = import_path6.default.resolve(filePath);
32217
+ if (!import_fs5.default.existsSync(absPath)) {
31731
32218
  throw new Error(`File not found: ${absPath}`);
31732
32219
  }
31733
- const stat = import_fs4.default.statSync(absPath);
32220
+ const stat = import_fs5.default.statSync(absPath);
31734
32221
  if (!stat.isFile()) {
31735
32222
  throw new Error(`Not a file: ${absPath}`);
31736
32223
  }
31737
32224
  if (stat.size === 0) {
31738
32225
  throw new Error("File is empty");
31739
32226
  }
31740
- const fileName = import_path5.default.basename(absPath);
31741
- 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();
31742
32229
  const contentType = mediaInfo(ext)?.contentType ?? "application/octet-stream";
31743
32230
  const form = new FormData();
31744
- 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);
31745
32232
  form.append("kind", kind);
31746
32233
  if (options.sessionId) form.append("session_id", options.sessionId);
31747
32234
  form.append("display_name", displayName);
@@ -31775,7 +32262,7 @@ async function mediaUploadCommand(filePaths, options) {
31775
32262
  }
31776
32263
  const publicAccess = options.share || options.access === "public";
31777
32264
  const kinds = filePaths.map((filePath) => {
31778
- const ext = import_path5.default.extname(filePath).slice(1).toLowerCase();
32265
+ const ext = import_path6.default.extname(filePath).slice(1).toLowerCase();
31779
32266
  return resolveKind(ext, options.kind);
31780
32267
  });
31781
32268
  if (publicAccess && kinds.some((kind) => !isPublicMediaKind(kind))) {
@@ -31861,7 +32348,7 @@ async function mediaListCommand(options) {
31861
32348
  }
31862
32349
 
31863
32350
  // src/commands/slack.ts
31864
- var import_chalk21 = __toESM(require("chalk"));
32351
+ var import_chalk22 = __toESM(require("chalk"));
31865
32352
  function getThreadOptions(options) {
31866
32353
  const channelId = options.channel || process.env.REPLICAS_SLACK_CHANNEL_ID || process.env.SLACK_CHANNEL_ID;
31867
32354
  const threadTs = options.threadTs || process.env.REPLICAS_SLACK_THREAD_TS || process.env.SLACK_THREAD_TS;
@@ -31878,10 +32365,10 @@ async function attachThread(request) {
31878
32365
  method: "POST",
31879
32366
  body: request
31880
32367
  });
31881
- console.log(import_chalk21.default.green("Slack thread attached."));
31882
- console.log(import_chalk21.default.gray(` Channel: ${response.thread.channel_id}`));
31883
- console.log(import_chalk21.default.gray(` Thread: ${response.thread.thread_ts}`));
31884
- 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})`));
31885
32372
  }
31886
32373
  async function slackThreadAttachCommand(options) {
31887
32374
  const agentConfig = readAgentConfig();
@@ -31910,7 +32397,7 @@ async function slackThreadSwitchCommand(workspace, options) {
31910
32397
  }
31911
32398
 
31912
32399
  // src/commands/service.ts
31913
- var import_chalk22 = __toESM(require("chalk"));
32400
+ var import_chalk23 = __toESM(require("chalk"));
31914
32401
  var import_node_child_process2 = require("child_process");
31915
32402
  var import_node_fs2 = require("fs");
31916
32403
  var import_node_os2 = require("os");
@@ -32053,7 +32540,7 @@ async function serviceListCommand() {
32053
32540
  return;
32054
32541
  }
32055
32542
  for (const state of states) {
32056
- 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");
32057
32544
  console.log(`${state.name} ${status} pid ${state.pid} started ${state.startedAt}`);
32058
32545
  console.log(` command: ${state.command} (cwd: ${state.cwd})`);
32059
32546
  console.log(` logs: ${state.logFile}`);
@@ -32159,8 +32646,8 @@ Workspace: ${workspaceNameForOutput(result.workspace_name)} (${getWorkspaceDashb
32159
32646
  }
32160
32647
 
32161
32648
  // src/commands/environment.ts
32162
- var import_fs5 = __toESM(require("fs"));
32163
- var import_chalk23 = __toESM(require("chalk"));
32649
+ var import_fs6 = __toESM(require("fs"));
32650
+ var import_chalk24 = __toESM(require("chalk"));
32164
32651
  var import_prompts8 = __toESM(require("prompts"));
32165
32652
  function maskValue(value) {
32166
32653
  if (value.length <= 4) return "\u2022\u2022\u2022\u2022";
@@ -32172,38 +32659,38 @@ async function resolveEnvironmentId(input) {
32172
32659
  const response = await orgAuthenticatedFetch("/v1/environments");
32173
32660
  const resolved = resolveByNameOrId(input, response.environments);
32174
32661
  if (!resolved) {
32175
- console.log(import_chalk23.default.red(`Environment not found: ${input}`));
32662
+ console.log(import_chalk24.default.red(`Environment not found: ${input}`));
32176
32663
  const available = response.environments.map((e) => e.name).join(", ");
32177
- console.log(import_chalk23.default.gray(`Available: ${available || "(none)"}`));
32664
+ console.log(import_chalk24.default.gray(`Available: ${available || "(none)"}`));
32178
32665
  process.exit(1);
32179
32666
  }
32180
32667
  return resolved.id;
32181
32668
  }
32182
32669
  function printEnvironment(env) {
32183
- console.log(import_chalk23.default.white(` ${env.name}${env.is_global ? import_chalk23.default.gray(" (global)") : ""}`));
32184
- 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}`));
32185
32672
  if (env.description) {
32186
- console.log(import_chalk23.default.gray(` Description: ${env.description}`));
32673
+ console.log(import_chalk24.default.gray(` Description: ${env.description}`));
32187
32674
  }
32188
32675
  if (env.repository_id) {
32189
- console.log(import_chalk23.default.gray(` Repository: ${env.repository_id}`));
32676
+ console.log(import_chalk24.default.gray(` Repository: ${env.repository_id}`));
32190
32677
  } else if (env.repository_set_id) {
32191
- 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}`));
32192
32679
  }
32193
32680
  if (env.variable_count !== void 0) {
32194
- 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}`));
32195
32682
  }
32196
- console.log(import_chalk23.default.gray(` Updated: ${formatDate2(env.updated_at)}`));
32683
+ console.log(import_chalk24.default.gray(` Updated: ${formatDate2(env.updated_at)}`));
32197
32684
  console.log();
32198
32685
  }
32199
32686
  async function environmentListCommand() {
32200
32687
  ensureOrgApiAuthenticated();
32201
32688
  const response = await orgAuthenticatedFetch("/v1/environments");
32202
32689
  if (response.environments.length === 0) {
32203
- console.log(import_chalk23.default.yellow("\nNo environments found.\n"));
32690
+ console.log(import_chalk24.default.yellow("\nNo environments found.\n"));
32204
32691
  return;
32205
32692
  }
32206
- console.log(import_chalk23.default.green(`
32693
+ console.log(import_chalk24.default.green(`
32207
32694
  Environments (${response.environments.length}):
32208
32695
  `));
32209
32696
  for (const env of response.environments) {
@@ -32214,7 +32701,7 @@ async function environmentGetCommand(idOrName) {
32214
32701
  ensureOrgApiAuthenticated();
32215
32702
  const id = await resolveEnvironmentId(idOrName);
32216
32703
  const response = await orgAuthenticatedFetch(`/v1/environments/${id}`);
32217
- console.log(import_chalk23.default.green(`
32704
+ console.log(import_chalk24.default.green(`
32218
32705
  Environment: ${response.environment.name}
32219
32706
  `));
32220
32707
  printEnvironment(response.environment);
@@ -32230,7 +32717,7 @@ async function environmentCreateCommand(name, options) {
32230
32717
  validate: (v) => v.trim() ? true : "Name is required"
32231
32718
  });
32232
32719
  if (!r.name) {
32233
- console.log(import_chalk23.default.yellow("\nCancelled."));
32720
+ console.log(import_chalk24.default.yellow("\nCancelled."));
32234
32721
  return;
32235
32722
  }
32236
32723
  envName = r.name;
@@ -32243,8 +32730,8 @@ async function environmentCreateCommand(name, options) {
32243
32730
  const repos2 = await orgAuthenticatedFetch("/v1/repositories");
32244
32731
  const repo = repos2.repositories.find((r) => r.name === options.repository);
32245
32732
  if (!repo) {
32246
- console.log(import_chalk23.default.red(`Repository not found: ${options.repository}`));
32247
- 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(", ")}`));
32248
32735
  process.exit(1);
32249
32736
  }
32250
32737
  repositoryId = repo.id;
@@ -32274,9 +32761,9 @@ async function environmentCreateCommand(name, options) {
32274
32761
  method: "POST",
32275
32762
  body
32276
32763
  });
32277
- console.log(import_chalk23.default.green(`
32764
+ console.log(import_chalk24.default.green(`
32278
32765
  Created environment: ${response.environment.name}`));
32279
- console.log(import_chalk23.default.gray(` ID: ${response.environment.id}
32766
+ console.log(import_chalk24.default.gray(` ID: ${response.environment.id}
32280
32767
  `));
32281
32768
  }
32282
32769
  async function environmentEditCommand(idOrName, options) {
@@ -32295,21 +32782,21 @@ async function environmentEditCommand(idOrName, options) {
32295
32782
  const repos2 = await orgAuthenticatedFetch("/v1/repositories");
32296
32783
  const repo = repos2.repositories.find((r) => r.name === options.repository);
32297
32784
  if (!repo) {
32298
- console.log(import_chalk23.default.red(`Repository not found: ${options.repository}`));
32785
+ console.log(import_chalk24.default.red(`Repository not found: ${options.repository}`));
32299
32786
  process.exit(1);
32300
32787
  }
32301
32788
  body.repository_id = repo.id;
32302
32789
  }
32303
32790
  }
32304
32791
  if (Object.keys(body).length === 0) {
32305
- 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."));
32306
32793
  return;
32307
32794
  }
32308
32795
  const response = await orgAuthenticatedFetch(`/v1/environments/${id}`, {
32309
32796
  method: "PATCH",
32310
32797
  body
32311
32798
  });
32312
- console.log(import_chalk23.default.green(`
32799
+ console.log(import_chalk24.default.green(`
32313
32800
  Updated environment: ${response.environment.name}
32314
32801
  `));
32315
32802
  }
@@ -32324,20 +32811,20 @@ async function environmentDeleteCommand(idOrName, options) {
32324
32811
  initial: false
32325
32812
  });
32326
32813
  if (!r.confirm) {
32327
- console.log(import_chalk23.default.yellow("\nCancelled."));
32814
+ console.log(import_chalk24.default.yellow("\nCancelled."));
32328
32815
  return;
32329
32816
  }
32330
32817
  }
32331
32818
  await orgAuthenticatedFetch(`/v1/environments/${id}`, { method: "DELETE" });
32332
- console.log(import_chalk23.default.green(`
32819
+ console.log(import_chalk24.default.green(`
32333
32820
  Deleted environment ${idOrName}.
32334
32821
  `));
32335
32822
  }
32336
32823
  function printVariable(v, reveal) {
32337
- console.log(import_chalk23.default.white(` ${v.key}`));
32338
- console.log(import_chalk23.default.gray(` ID: ${v.id}`));
32339
- console.log(import_chalk23.default.gray(` Value: ${reveal ? v.value : maskValue(v.value)}`));
32340
- 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)}`));
32341
32828
  console.log();
32342
32829
  }
32343
32830
  async function envVarsListCommand(envIdOrName, options) {
@@ -32347,14 +32834,14 @@ async function envVarsListCommand(envIdOrName, options) {
32347
32834
  `/v1/environments/${id}/variables`
32348
32835
  );
32349
32836
  if (response.environment_variables.length === 0) {
32350
- console.log(import_chalk23.default.yellow("\nNo variables.\n"));
32837
+ console.log(import_chalk24.default.yellow("\nNo variables.\n"));
32351
32838
  return;
32352
32839
  }
32353
- console.log(import_chalk23.default.green(`
32840
+ console.log(import_chalk24.default.green(`
32354
32841
  Variables (${response.environment_variables.length}):
32355
32842
  `));
32356
32843
  if (!options.reveal) {
32357
- 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"));
32358
32845
  }
32359
32846
  for (const v of response.environment_variables) printVariable(v, !!options.reveal);
32360
32847
  }
@@ -32371,7 +32858,7 @@ async function envVarsSetCommand(envIdOrName, key, value) {
32371
32858
  `/v1/environments/${id}/variables/${match.id}`,
32372
32859
  { method: "PATCH", body: body2 }
32373
32860
  );
32374
- console.log(import_chalk23.default.green(`
32861
+ console.log(import_chalk24.default.green(`
32375
32862
  Updated variable ${response2.environment_variable.key}.
32376
32863
  `));
32377
32864
  return;
@@ -32385,7 +32872,7 @@ Updated variable ${response2.environment_variable.key}.
32385
32872
  `/v1/environments/${id}/variables`,
32386
32873
  { method: "POST", body }
32387
32874
  );
32388
- console.log(import_chalk23.default.green(`
32875
+ console.log(import_chalk24.default.green(`
32389
32876
  Created variable ${response.environment_variable.key}.
32390
32877
  `));
32391
32878
  }
@@ -32399,7 +32886,7 @@ async function envVarsDeleteCommand(envIdOrName, keyOrId, options) {
32399
32886
  );
32400
32887
  const match = existing.environment_variables.find((v) => v.key === keyOrId);
32401
32888
  if (!match) {
32402
- console.log(import_chalk23.default.red(`Variable not found: ${keyOrId}`));
32889
+ console.log(import_chalk24.default.red(`Variable not found: ${keyOrId}`));
32403
32890
  process.exit(1);
32404
32891
  }
32405
32892
  variableId = match.id;
@@ -32412,23 +32899,23 @@ async function envVarsDeleteCommand(envIdOrName, keyOrId, options) {
32412
32899
  initial: false
32413
32900
  });
32414
32901
  if (!r.confirm) {
32415
- console.log(import_chalk23.default.yellow("\nCancelled."));
32902
+ console.log(import_chalk24.default.yellow("\nCancelled."));
32416
32903
  return;
32417
32904
  }
32418
32905
  }
32419
32906
  await orgAuthenticatedFetch(`/v1/environments/${id}/variables/${variableId}`, {
32420
32907
  method: "DELETE"
32421
32908
  });
32422
- console.log(import_chalk23.default.green(`
32909
+ console.log(import_chalk24.default.green(`
32423
32910
  Deleted variable ${keyOrId}.
32424
32911
  `));
32425
32912
  }
32426
32913
  function printFile(f) {
32427
- console.log(import_chalk23.default.white(` ${f.path}`));
32428
- console.log(import_chalk23.default.gray(` ID: ${f.id}`));
32429
- console.log(import_chalk23.default.gray(` Name: ${f.name}`));
32430
- console.log(import_chalk23.default.gray(` Size: ${f.content.length} bytes`));
32431
- 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)}`));
32432
32919
  console.log();
32433
32920
  }
32434
32921
  async function envFilesListCommand(envIdOrName) {
@@ -32438,20 +32925,20 @@ async function envFilesListCommand(envIdOrName) {
32438
32925
  `/v1/environments/${id}/files`
32439
32926
  );
32440
32927
  if (response.environment_files.length === 0) {
32441
- console.log(import_chalk23.default.yellow("\nNo files.\n"));
32928
+ console.log(import_chalk24.default.yellow("\nNo files.\n"));
32442
32929
  return;
32443
32930
  }
32444
- console.log(import_chalk23.default.green(`
32931
+ console.log(import_chalk24.default.green(`
32445
32932
  Files (${response.environment_files.length}):
32446
32933
  `));
32447
32934
  for (const f of response.environment_files) printFile(f);
32448
32935
  }
32449
32936
  function readFileContent(options) {
32450
32937
  if (options.file) {
32451
- if (!import_fs5.default.existsSync(options.file)) {
32938
+ if (!import_fs6.default.existsSync(options.file)) {
32452
32939
  throw new Error(`Local file not found: ${options.file}`);
32453
32940
  }
32454
- return import_fs5.default.readFileSync(options.file, "utf-8");
32941
+ return import_fs6.default.readFileSync(options.file, "utf-8");
32455
32942
  }
32456
32943
  if (options.content !== void 0) return options.content;
32457
32944
  throw new Error('Pass either --content "..." or --file <local-path>');
@@ -32472,7 +32959,7 @@ async function envFilesSetCommand(envIdOrName, destinationPath, options) {
32472
32959
  `/v1/environments/${id}/files/${match.id}`,
32473
32960
  { method: "PATCH", body: body2 }
32474
32961
  );
32475
- console.log(import_chalk23.default.green(`
32962
+ console.log(import_chalk24.default.green(`
32476
32963
  Updated file ${response2.environment_file.path}.
32477
32964
  `));
32478
32965
  return;
@@ -32487,7 +32974,7 @@ Updated file ${response2.environment_file.path}.
32487
32974
  `/v1/environments/${id}/files`,
32488
32975
  { method: "POST", body }
32489
32976
  );
32490
- console.log(import_chalk23.default.green(`
32977
+ console.log(import_chalk24.default.green(`
32491
32978
  Created file ${response.environment_file.path}.
32492
32979
  `));
32493
32980
  }
@@ -32501,7 +32988,7 @@ async function envFilesDeleteCommand(envIdOrName, pathOrId, options) {
32501
32988
  );
32502
32989
  const match = existing.environment_files.find((f) => f.path === pathOrId);
32503
32990
  if (!match) {
32504
- console.log(import_chalk23.default.red(`File not found: ${pathOrId}`));
32991
+ console.log(import_chalk24.default.red(`File not found: ${pathOrId}`));
32505
32992
  process.exit(1);
32506
32993
  }
32507
32994
  fileId = match.id;
@@ -32514,14 +33001,14 @@ async function envFilesDeleteCommand(envIdOrName, pathOrId, options) {
32514
33001
  initial: false
32515
33002
  });
32516
33003
  if (!r.confirm) {
32517
- console.log(import_chalk23.default.yellow("\nCancelled."));
33004
+ console.log(import_chalk24.default.yellow("\nCancelled."));
32518
33005
  return;
32519
33006
  }
32520
33007
  }
32521
33008
  await orgAuthenticatedFetch(`/v1/environments/${id}/files/${fileId}`, {
32522
33009
  method: "DELETE"
32523
33010
  });
32524
- console.log(import_chalk23.default.green(`
33011
+ console.log(import_chalk24.default.green(`
32525
33012
  Deleted file ${pathOrId}.
32526
33013
  `));
32527
33014
  }
@@ -32530,16 +33017,16 @@ async function envHookGetCommand(envIdOrName, kind) {
32530
33017
  const id = await resolveEnvironmentId(envIdOrName);
32531
33018
  const hook = kind === "warm" ? (await orgAuthenticatedFetch(`/v1/environments/${id}/warm-hooks`)).warm_hook : (await orgAuthenticatedFetch(`/v1/environments/${id}/start-hooks`)).start_hook;
32532
33019
  if (!hook) {
32533
- console.log(import_chalk23.default.yellow(`
33020
+ console.log(import_chalk24.default.yellow(`
32534
33021
  No ${kind} hook configured.
32535
33022
  `));
32536
33023
  return;
32537
33024
  }
32538
- console.log(import_chalk23.default.green(`
33025
+ console.log(import_chalk24.default.green(`
32539
33026
  ${kind === "warm" ? "Warm" : "Start"} hook (v${hook.version}, ${hook.is_active ? "active" : "inactive"}):
32540
33027
  `));
32541
- console.log(import_chalk23.default.gray(` ID: ${hook.id}`));
32542
- 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)}
32543
33030
  `));
32544
33031
  console.log(hook.content);
32545
33032
  console.log();
@@ -32554,7 +33041,7 @@ async function envHookSaveCommand(envIdOrName, options, kind) {
32554
33041
  `/v1/environments/${id}/warm-hooks/save`,
32555
33042
  { method: "POST", body: body2 }
32556
33043
  );
32557
- console.log(import_chalk23.default.green(`
33044
+ console.log(import_chalk24.default.green(`
32558
33045
  Saved warm hook v${response2.warm_hook.version}.
32559
33046
  `));
32560
33047
  return;
@@ -32564,7 +33051,7 @@ Saved warm hook v${response2.warm_hook.version}.
32564
33051
  `/v1/environments/${id}/start-hooks/save`,
32565
33052
  { method: "POST", body }
32566
33053
  );
32567
- console.log(import_chalk23.default.green(response.start_hook ? `
33054
+ console.log(import_chalk24.default.green(response.start_hook ? `
32568
33055
  Saved start hook v${response.start_hook.version}.
32569
33056
  ` : "\nCleared start hook.\n"));
32570
33057
  }
@@ -32581,7 +33068,7 @@ async function envHookTestCommand(envIdOrName, options, kind) {
32581
33068
  body: kind === "warm" ? { content, mode: options.save ? "save_test" : "test_only" } : { content },
32582
33069
  onEvent: (event) => {
32583
33070
  if (event.type === "progress" && event.message) {
32584
- console.log(import_chalk23.default.gray(event.message));
33071
+ console.log(import_chalk24.default.gray(event.message));
32585
33072
  } else if (event.type === "output" && event.output) {
32586
33073
  process.stdout.write(event.output);
32587
33074
  } else if (event.type === "complete") {
@@ -32594,23 +33081,23 @@ async function envHookTestCommand(envIdOrName, options, kind) {
32594
33081
  }
32595
33082
  );
32596
33083
  if (errorMessage) {
32597
- console.log(import_chalk23.default.red(`
33084
+ console.log(import_chalk24.default.red(`
32598
33085
  ${errorMessage}
32599
33086
  `));
32600
33087
  process.exit(1);
32601
33088
  }
32602
33089
  if (timedOut) {
32603
- console.log(import_chalk23.default.yellow(`
33090
+ console.log(import_chalk24.default.yellow(`
32604
33091
  ${kind === "warm" ? "Warm" : "Start"} hook timed out.
32605
33092
  `));
32606
33093
  process.exit(1);
32607
33094
  }
32608
33095
  if (exitCode === 0) {
32609
- console.log(import_chalk23.default.green(`
33096
+ console.log(import_chalk24.default.green(`
32610
33097
  ${kind === "warm" ? "Warm" : "Start"} hook passed${options.save ? " and was saved" : ""} (exit code ${exitCode}).
32611
33098
  `));
32612
33099
  } else {
32613
- console.log(import_chalk23.default.red(`
33100
+ console.log(import_chalk24.default.red(`
32614
33101
  ${kind === "warm" ? "Warm" : "Start"} hook failed (exit code ${exitCode ?? "unknown"}).
32615
33102
  `));
32616
33103
  process.exit(1);
@@ -32625,24 +33112,24 @@ async function envHookRepositoryHooksCommand(envIdOrName, kind) {
32625
33112
  `/v1/environments/${id}/start-hooks/repository-hooks`
32626
33113
  )).repositories.map((repository) => ({ ...repository, hook: repository.start_hook }));
32627
33114
  if (repositories.length === 0) {
32628
- 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"));
32629
33116
  return;
32630
33117
  }
32631
- console.log(import_chalk23.default.green(`
33118
+ console.log(import_chalk24.default.green(`
32632
33119
  Repository ${kind} hooks (${repositories.length}):
32633
33120
  `));
32634
33121
  for (const repo of repositories) {
32635
- 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}`));
32636
33123
  if (repo.error) {
32637
- console.log(import_chalk23.default.red(` Error: ${repo.error}`));
33124
+ console.log(import_chalk24.default.red(` Error: ${repo.error}`));
32638
33125
  } else if (repo.hook) {
32639
- console.log(import_chalk23.default.gray(` Source: ${repo.filename ?? "(unknown)"}`));
32640
- 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}):`));
32641
33128
  for (const cmd of repo.hook.commands) {
32642
- console.log(import_chalk23.default.gray(` ${cmd}`));
33129
+ console.log(import_chalk24.default.gray(` ${cmd}`));
32643
33130
  }
32644
33131
  } else {
32645
- console.log(import_chalk23.default.gray(` No ${kind}Hook defined.`));
33132
+ console.log(import_chalk24.default.gray(` No ${kind}Hook defined.`));
32646
33133
  }
32647
33134
  console.log();
32648
33135
  }
@@ -32707,7 +33194,7 @@ program.hook("preAction", async (_command, actionCommand) => {
32707
33194
  throw new Error('No organization selected. Run "replicas org switch" to select one.');
32708
33195
  }
32709
33196
  } catch (error51) {
32710
- console.error(import_chalk24.default.red(`
33197
+ console.error(import_chalk25.default.red(`
32711
33198
  \u2717 ${error51 instanceof Error ? error51.message : "Unknown error"}
32712
33199
  `));
32713
33200
  process.exit(1);
@@ -32721,7 +33208,7 @@ function registerSlackCommands(parent) {
32721
33208
  await slackThreadAttachCommand(options);
32722
33209
  } catch (error51) {
32723
33210
  if (error51 instanceof Error) {
32724
- console.error(import_chalk24.default.red(`
33211
+ console.error(import_chalk25.default.red(`
32725
33212
  \u2717 ${error51.message}
32726
33213
  `));
32727
33214
  }
@@ -32733,7 +33220,7 @@ function registerSlackCommands(parent) {
32733
33220
  await slackThreadSwitchCommand(workspace, options);
32734
33221
  } catch (error51) {
32735
33222
  if (error51 instanceof Error) {
32736
- console.error(import_chalk24.default.red(`
33223
+ console.error(import_chalk25.default.red(`
32737
33224
  \u2717 ${error51.message}
32738
33225
  `));
32739
33226
  }
@@ -32747,7 +33234,7 @@ program.command("login").description("Authenticate with your Replicas account").
32747
33234
  await loginCommand();
32748
33235
  } catch (error51) {
32749
33236
  if (error51 instanceof Error) {
32750
- console.error(import_chalk24.default.red(`
33237
+ console.error(import_chalk25.default.red(`
32751
33238
  \u2717 ${error51.message}
32752
33239
  `));
32753
33240
  }
@@ -32759,7 +33246,7 @@ program.command("init").description("Create a replicas.json or replicas.yaml con
32759
33246
  initCommand(options);
32760
33247
  } catch (error51) {
32761
33248
  if (error51 instanceof Error) {
32762
- console.error(import_chalk24.default.red(`
33249
+ console.error(import_chalk25.default.red(`
32763
33250
  \u2717 ${error51.message}
32764
33251
  `));
32765
33252
  }
@@ -32771,7 +33258,7 @@ program.command("logout").description("Clear stored credentials").action(() => {
32771
33258
  logoutCommand();
32772
33259
  } catch (error51) {
32773
33260
  if (error51 instanceof Error) {
32774
- console.error(import_chalk24.default.red(`
33261
+ console.error(import_chalk25.default.red(`
32775
33262
  \u2717 ${error51.message}
32776
33263
  `));
32777
33264
  }
@@ -32782,7 +33269,7 @@ program.command("muse-auth").description("Connect your Muse Code subscription to
32782
33269
  try {
32783
33270
  await museAuthCommand(options);
32784
33271
  } catch (error51) {
32785
- if (error51 instanceof Error) console.error(import_chalk24.default.red(`
33272
+ if (error51 instanceof Error) console.error(import_chalk25.default.red(`
32786
33273
  \u2717 ${error51.message}
32787
33274
  `));
32788
33275
  process.exit(1);
@@ -32793,7 +33280,7 @@ program.command("whoami").description("Display current authenticated user").acti
32793
33280
  await whoamiCommand();
32794
33281
  } catch (error51) {
32795
33282
  if (error51 instanceof Error) {
32796
- console.error(import_chalk24.default.red(`
33283
+ console.error(import_chalk25.default.red(`
32797
33284
  \u2717 ${error51.message}
32798
33285
  `));
32799
33286
  }
@@ -32805,7 +33292,7 @@ program.command("codex-auth").description("Connect your Codex credentials to Rep
32805
33292
  await codexAuthCommand(options);
32806
33293
  } catch (error51) {
32807
33294
  if (error51 instanceof Error) {
32808
- console.error(import_chalk24.default.red(`
33295
+ console.error(import_chalk25.default.red(`
32809
33296
  \u2717 ${error51.message}
32810
33297
  `));
32811
33298
  }
@@ -32817,7 +33304,7 @@ program.command("claude-auth").description("Connect your Claude Code credentials
32817
33304
  await claudeAuthCommand(options);
32818
33305
  } catch (error51) {
32819
33306
  if (error51 instanceof Error) {
32820
- console.error(import_chalk24.default.red(`
33307
+ console.error(import_chalk25.default.red(`
32821
33308
  \u2717 ${error51.message}
32822
33309
  `));
32823
33310
  }
@@ -32830,7 +33317,7 @@ org.command("switch").description("Switch to a different organization").action(a
32830
33317
  await orgSwitchCommand();
32831
33318
  } catch (error51) {
32832
33319
  if (error51 instanceof Error) {
32833
- console.error(import_chalk24.default.red(`
33320
+ console.error(import_chalk25.default.red(`
32834
33321
  \u2717 ${error51.message}
32835
33322
  `));
32836
33323
  }
@@ -32842,7 +33329,7 @@ org.action(async () => {
32842
33329
  await orgCommand();
32843
33330
  } catch (error51) {
32844
33331
  if (error51 instanceof Error) {
32845
- console.error(import_chalk24.default.red(`
33332
+ console.error(import_chalk25.default.red(`
32846
33333
  \u2717 ${error51.message}
32847
33334
  `));
32848
33335
  }
@@ -32854,7 +33341,7 @@ program.command("connect <workspace-name...>").description("Connect to a workspa
32854
33341
  await connectCommand(workspaceName.join(" "));
32855
33342
  } catch (error51) {
32856
33343
  if (error51 instanceof Error) {
32857
- console.error(import_chalk24.default.red(`
33344
+ console.error(import_chalk25.default.red(`
32858
33345
  \u2717 ${error51.message}
32859
33346
  `));
32860
33347
  }
@@ -32865,7 +33352,7 @@ program.command("tunnel <workspace-name...>").description("Forward a workspace p
32865
33352
  try {
32866
33353
  await tunnelCommand(workspaceName.join(" "), options);
32867
33354
  } catch (error51) {
32868
- console.error(import_chalk24.default.red(`
33355
+ console.error(import_chalk25.default.red(`
32869
33356
  Error: ${error51 instanceof Error ? error51.message : "Unknown error"}`));
32870
33357
  process.exit(1);
32871
33358
  }
@@ -32875,7 +33362,7 @@ program.command("code [workspace-name...]").description("Open a workspace in VSC
32875
33362
  await codeCommand(workspaceName.join(" "));
32876
33363
  } catch (error51) {
32877
33364
  if (error51 instanceof Error) {
32878
- console.error(import_chalk24.default.red(`
33365
+ console.error(import_chalk25.default.red(`
32879
33366
  \u2717 ${error51.message}
32880
33367
  `));
32881
33368
  }
@@ -32888,7 +33375,7 @@ config2.command("get <key>").description("Get a configuration value").action(asy
32888
33375
  await configGetCommand(key);
32889
33376
  } catch (error51) {
32890
33377
  if (error51 instanceof Error) {
32891
- console.error(import_chalk24.default.red(`
33378
+ console.error(import_chalk25.default.red(`
32892
33379
  \u2717 ${error51.message}
32893
33380
  `));
32894
33381
  }
@@ -32900,7 +33387,7 @@ config2.command("set <key> <value>").description("Set a configuration value").ac
32900
33387
  await configSetCommand(key, value);
32901
33388
  } catch (error51) {
32902
33389
  if (error51 instanceof Error) {
32903
- console.error(import_chalk24.default.red(`
33390
+ console.error(import_chalk25.default.red(`
32904
33391
  \u2717 ${error51.message}
32905
33392
  `));
32906
33393
  }
@@ -32912,7 +33399,7 @@ config2.command("list").description("List all configuration values").action(asyn
32912
33399
  await configListCommand();
32913
33400
  } catch (error51) {
32914
33401
  if (error51 instanceof Error) {
32915
- console.error(import_chalk24.default.red(`
33402
+ console.error(import_chalk25.default.red(`
32916
33403
  \u2717 ${error51.message}
32917
33404
  `));
32918
33405
  }
@@ -32924,7 +33411,7 @@ program.command("list").description("List all replicas").option("-p, --page <pag
32924
33411
  await replicaListCommand(options);
32925
33412
  } catch (error51) {
32926
33413
  if (error51 instanceof Error) {
32927
- console.error(import_chalk24.default.red(`
33414
+ console.error(import_chalk25.default.red(`
32928
33415
  \u2717 ${error51.message}
32929
33416
  `));
32930
33417
  }
@@ -32936,7 +33423,7 @@ program.command("get <id>").description("Get replica details by ID").action(asyn
32936
33423
  await replicaGetCommand(id);
32937
33424
  } catch (error51) {
32938
33425
  if (error51 instanceof Error) {
32939
- console.error(import_chalk24.default.red(`
33426
+ console.error(import_chalk25.default.red(`
32940
33427
  \u2717 ${error51.message}
32941
33428
  `));
32942
33429
  }
@@ -32948,7 +33435,7 @@ program.command("create [name]").description("Create a new replica").option("-m,
32948
33435
  await replicaCreateCommand(name, options);
32949
33436
  } catch (error51) {
32950
33437
  if (error51 instanceof Error) {
32951
- console.error(import_chalk24.default.red(`
33438
+ console.error(import_chalk25.default.red(`
32952
33439
  \u2717 ${error51.message}
32953
33440
  `));
32954
33441
  }
@@ -32960,7 +33447,7 @@ program.command("send <id>").description("Send a message to a replica").option("
32960
33447
  await replicaSendCommand(id, options);
32961
33448
  } catch (error51) {
32962
33449
  if (error51 instanceof Error) {
32963
- console.error(import_chalk24.default.red(`
33450
+ console.error(import_chalk25.default.red(`
32964
33451
  \u2717 ${error51.message}
32965
33452
  `));
32966
33453
  }
@@ -32972,7 +33459,7 @@ program.command("delete <id>").description("Delete a replica").option("-f, --for
32972
33459
  await replicaDeleteCommand(id, options);
32973
33460
  } catch (error51) {
32974
33461
  if (error51 instanceof Error) {
32975
- console.error(import_chalk24.default.red(`
33462
+ console.error(import_chalk25.default.red(`
32976
33463
  \u2717 ${error51.message}
32977
33464
  `));
32978
33465
  }
@@ -32984,7 +33471,7 @@ program.command("read <id>").description("Read conversation history of a replica
32984
33471
  await replicaReadCommand(id, options);
32985
33472
  } catch (error51) {
32986
33473
  if (error51 instanceof Error) {
32987
- console.error(import_chalk24.default.red(`
33474
+ console.error(import_chalk25.default.red(`
32988
33475
  \u2717 ${error51.message}
32989
33476
  `));
32990
33477
  }
@@ -32997,7 +33484,7 @@ automation.command("list").description("List all automations").option("-p, --pag
32997
33484
  await automationListCommand(options);
32998
33485
  } catch (error51) {
32999
33486
  if (error51 instanceof Error) {
33000
- console.error(import_chalk24.default.red(`
33487
+ console.error(import_chalk25.default.red(`
33001
33488
  \u2717 ${error51.message}
33002
33489
  `));
33003
33490
  }
@@ -33009,7 +33496,7 @@ automation.command("get <id>").description("Get automation details by ID").actio
33009
33496
  await automationGetCommand(id);
33010
33497
  } catch (error51) {
33011
33498
  if (error51 instanceof Error) {
33012
- console.error(import_chalk24.default.red(`
33499
+ console.error(import_chalk25.default.red(`
33013
33500
  \u2717 ${error51.message}
33014
33501
  `));
33015
33502
  }
@@ -33024,7 +33511,7 @@ automation.command("create [name]").description("Create a new automation").optio
33024
33511
  });
33025
33512
  } catch (error51) {
33026
33513
  if (error51 instanceof Error) {
33027
- console.error(import_chalk24.default.red(`
33514
+ console.error(import_chalk25.default.red(`
33028
33515
  \u2717 ${error51.message}
33029
33516
  `));
33030
33517
  }
@@ -33036,7 +33523,7 @@ automation.command("edit <id>").description("Edit an existing automation").optio
33036
33523
  await automationEditCommand(id, options);
33037
33524
  } catch (error51) {
33038
33525
  if (error51 instanceof Error) {
33039
- console.error(import_chalk24.default.red(`
33526
+ console.error(import_chalk25.default.red(`
33040
33527
  \u2717 ${error51.message}
33041
33528
  `));
33042
33529
  }
@@ -33048,7 +33535,7 @@ automation.command("run <id>").description("Manually trigger an automation (cron
33048
33535
  await automationRunCommand(id);
33049
33536
  } catch (error51) {
33050
33537
  if (error51 instanceof Error) {
33051
- console.error(import_chalk24.default.red(`
33538
+ console.error(import_chalk25.default.red(`
33052
33539
  \u2717 ${error51.message}
33053
33540
  `));
33054
33541
  }
@@ -33060,7 +33547,7 @@ automation.command("delete <id>").description("Delete an automation").option("-f
33060
33547
  await automationDeleteCommand(id, options);
33061
33548
  } catch (error51) {
33062
33549
  if (error51 instanceof Error) {
33063
- console.error(import_chalk24.default.red(`
33550
+ console.error(import_chalk25.default.red(`
33064
33551
  \u2717 ${error51.message}
33065
33552
  `));
33066
33553
  }
@@ -33072,7 +33559,7 @@ automation.command("check <checkRunId>").description("Report this automation run
33072
33559
  await automationCheckCommand(checkRunId, options);
33073
33560
  } catch (error51) {
33074
33561
  if (error51 instanceof Error) {
33075
- console.error(import_chalk24.default.red(`
33562
+ console.error(import_chalk25.default.red(`
33076
33563
  \u2717 ${error51.message}
33077
33564
  `));
33078
33565
  }
@@ -33084,7 +33571,7 @@ automation.action(async () => {
33084
33571
  await automationListCommand({});
33085
33572
  } catch (error51) {
33086
33573
  if (error51 instanceof Error) {
33087
- console.error(import_chalk24.default.red(`
33574
+ console.error(import_chalk25.default.red(`
33088
33575
  \u2717 ${error51.message}
33089
33576
  `));
33090
33577
  }
@@ -33097,7 +33584,7 @@ repos.command("list").description("List all repositories").action(async () => {
33097
33584
  await repositoriesListCommand();
33098
33585
  } catch (error51) {
33099
33586
  if (error51 instanceof Error) {
33100
- console.error(import_chalk24.default.red(`
33587
+ console.error(import_chalk25.default.red(`
33101
33588
  \u2717 ${error51.message}
33102
33589
  `));
33103
33590
  }
@@ -33109,7 +33596,7 @@ repos.action(async () => {
33109
33596
  await repositoriesListCommand();
33110
33597
  } catch (error51) {
33111
33598
  if (error51 instanceof Error) {
33112
- console.error(import_chalk24.default.red(`
33599
+ console.error(import_chalk25.default.red(`
33113
33600
  \u2717 ${error51.message}
33114
33601
  `));
33115
33602
  }
@@ -33122,7 +33609,7 @@ environment.command("list").description("List all environments").action(async ()
33122
33609
  await environmentListCommand();
33123
33610
  } catch (error51) {
33124
33611
  if (error51 instanceof Error) {
33125
- console.error(import_chalk24.default.red(`
33612
+ console.error(import_chalk25.default.red(`
33126
33613
  \u2717 ${error51.message}
33127
33614
  `));
33128
33615
  }
@@ -33134,7 +33621,7 @@ environment.command("get <id-or-name>").description('Get an environment by ID or
33134
33621
  await environmentGetCommand(idOrName);
33135
33622
  } catch (error51) {
33136
33623
  if (error51 instanceof Error) {
33137
- console.error(import_chalk24.default.red(`
33624
+ console.error(import_chalk25.default.red(`
33138
33625
  \u2717 ${error51.message}
33139
33626
  `));
33140
33627
  }
@@ -33146,7 +33633,7 @@ environment.command("create [name]").description("Create a new environment").opt
33146
33633
  await environmentCreateCommand(name, options);
33147
33634
  } catch (error51) {
33148
33635
  if (error51 instanceof Error) {
33149
- console.error(import_chalk24.default.red(`
33636
+ console.error(import_chalk25.default.red(`
33150
33637
  \u2717 ${error51.message}
33151
33638
  `));
33152
33639
  }
@@ -33158,7 +33645,7 @@ environment.command("edit <id-or-name>").description("Edit an environment").opti
33158
33645
  await environmentEditCommand(idOrName, options);
33159
33646
  } catch (error51) {
33160
33647
  if (error51 instanceof Error) {
33161
- console.error(import_chalk24.default.red(`
33648
+ console.error(import_chalk25.default.red(`
33162
33649
  \u2717 ${error51.message}
33163
33650
  `));
33164
33651
  }
@@ -33170,7 +33657,7 @@ environment.command("delete <id-or-name>").description("Delete an environment").
33170
33657
  await environmentDeleteCommand(idOrName, options);
33171
33658
  } catch (error51) {
33172
33659
  if (error51 instanceof Error) {
33173
- console.error(import_chalk24.default.red(`
33660
+ console.error(import_chalk25.default.red(`
33174
33661
  \u2717 ${error51.message}
33175
33662
  `));
33176
33663
  }
@@ -33183,7 +33670,7 @@ envVars.command("list <env>").description("List variables in an environment (val
33183
33670
  await envVarsListCommand(env, options);
33184
33671
  } catch (error51) {
33185
33672
  if (error51 instanceof Error) {
33186
- console.error(import_chalk24.default.red(`
33673
+ console.error(import_chalk25.default.red(`
33187
33674
  \u2717 ${error51.message}
33188
33675
  `));
33189
33676
  }
@@ -33195,7 +33682,7 @@ envVars.command("set <env> <key> <value>").description("Create or update a varia
33195
33682
  await envVarsSetCommand(env, key, value);
33196
33683
  } catch (error51) {
33197
33684
  if (error51 instanceof Error) {
33198
- console.error(import_chalk24.default.red(`
33685
+ console.error(import_chalk25.default.red(`
33199
33686
  \u2717 ${error51.message}
33200
33687
  `));
33201
33688
  }
@@ -33207,7 +33694,7 @@ envVars.command("delete <env> <key-or-id>").description("Delete a variable by ke
33207
33694
  await envVarsDeleteCommand(env, keyOrId, options);
33208
33695
  } catch (error51) {
33209
33696
  if (error51 instanceof Error) {
33210
- console.error(import_chalk24.default.red(`
33697
+ console.error(import_chalk25.default.red(`
33211
33698
  \u2717 ${error51.message}
33212
33699
  `));
33213
33700
  }
@@ -33220,7 +33707,7 @@ envFiles.command("list <env>").description("List files in an environment").actio
33220
33707
  await envFilesListCommand(env);
33221
33708
  } catch (error51) {
33222
33709
  if (error51 instanceof Error) {
33223
- console.error(import_chalk24.default.red(`
33710
+ console.error(import_chalk25.default.red(`
33224
33711
  \u2717 ${error51.message}
33225
33712
  `));
33226
33713
  }
@@ -33232,7 +33719,7 @@ envFiles.command("set <env> <destination-path>").description("Create or update a
33232
33719
  await envFilesSetCommand(env, destinationPath, options);
33233
33720
  } catch (error51) {
33234
33721
  if (error51 instanceof Error) {
33235
- console.error(import_chalk24.default.red(`
33722
+ console.error(import_chalk25.default.red(`
33236
33723
  \u2717 ${error51.message}
33237
33724
  `));
33238
33725
  }
@@ -33244,7 +33731,7 @@ envFiles.command("delete <env> <path-or-id>").description("Delete a file by dest
33244
33731
  await envFilesDeleteCommand(env, pathOrId, options);
33245
33732
  } catch (error51) {
33246
33733
  if (error51 instanceof Error) {
33247
- console.error(import_chalk24.default.red(`
33734
+ console.error(import_chalk25.default.red(`
33248
33735
  \u2717 ${error51.message}
33249
33736
  `));
33250
33737
  }
@@ -33257,7 +33744,7 @@ function registerEnvironmentHookCommands(parent, config3) {
33257
33744
  try {
33258
33745
  await command();
33259
33746
  } catch (error51) {
33260
- if (error51 instanceof Error) console.error(import_chalk24.default.red(`
33747
+ if (error51 instanceof Error) console.error(import_chalk25.default.red(`
33261
33748
  \u2717 ${error51.message}
33262
33749
  `));
33263
33750
  process.exit(1);
@@ -33293,7 +33780,7 @@ environment.action(async () => {
33293
33780
  await environmentListCommand();
33294
33781
  } catch (error51) {
33295
33782
  if (error51 instanceof Error) {
33296
- console.error(import_chalk24.default.red(`
33783
+ console.error(import_chalk25.default.red(`
33297
33784
  \u2717 ${error51.message}
33298
33785
  `));
33299
33786
  }
@@ -33344,7 +33831,7 @@ if (isAgentMode()) {
33344
33831
  await previewAddCommand(workspaceId, options);
33345
33832
  } catch (error51) {
33346
33833
  if (error51 instanceof Error) {
33347
- console.error(import_chalk24.default.red(`
33834
+ console.error(import_chalk25.default.red(`
33348
33835
  \u2717 ${error51.message}
33349
33836
  `));
33350
33837
  }
@@ -33356,7 +33843,7 @@ if (isAgentMode()) {
33356
33843
  await previewListCommand(workspaceId);
33357
33844
  } catch (error51) {
33358
33845
  if (error51 instanceof Error) {
33359
- console.error(import_chalk24.default.red(`
33846
+ console.error(import_chalk25.default.red(`
33360
33847
  \u2717 ${error51.message}
33361
33848
  `));
33362
33849
  }
@@ -33368,7 +33855,7 @@ if (isAgentMode()) {
33368
33855
  await previewRemoveCommand(workspaceId, options);
33369
33856
  } catch (error51) {
33370
33857
  if (error51 instanceof Error) {
33371
- console.error(import_chalk24.default.red(`
33858
+ console.error(import_chalk25.default.red(`
33372
33859
  \u2717 ${error51.message}
33373
33860
  `));
33374
33861
  }
@@ -33376,6 +33863,26 @@ if (isAgentMode()) {
33376
33863
  }
33377
33864
  });
33378
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
+ }
33379
33886
  if (isAgentMode()) {
33380
33887
  const identity = program.command("identity").description("Obtain short-lived workspace identity tokens (OIDC) for the services this workspace calls");
33381
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);
@@ -33433,7 +33940,7 @@ if (isAgentMode()) {
33433
33940
  await mediaUploadCommand(files, options);
33434
33941
  } catch (error51) {
33435
33942
  if (error51 instanceof Error) {
33436
- console.error(import_chalk24.default.red(`
33943
+ console.error(import_chalk25.default.red(`
33437
33944
  \u2717 ${error51.message}
33438
33945
  `));
33439
33946
  }
@@ -33444,7 +33951,7 @@ if (isAgentMode()) {
33444
33951
  try {
33445
33952
  await mediaShareCommand(mediaId);
33446
33953
  } catch (error51) {
33447
- if (error51 instanceof Error) console.error(import_chalk24.default.red(`
33954
+ if (error51 instanceof Error) console.error(import_chalk25.default.red(`
33448
33955
  \u2717 ${error51.message}
33449
33956
  `));
33450
33957
  process.exit(1);
@@ -33454,7 +33961,7 @@ if (isAgentMode()) {
33454
33961
  try {
33455
33962
  await mediaRevokeCommand(mediaId);
33456
33963
  } catch (error51) {
33457
- if (error51 instanceof Error) console.error(import_chalk24.default.red(`
33964
+ if (error51 instanceof Error) console.error(import_chalk25.default.red(`
33458
33965
  \u2717 ${error51.message}
33459
33966
  `));
33460
33967
  process.exit(1);
@@ -33464,7 +33971,7 @@ if (isAgentMode()) {
33464
33971
  try {
33465
33972
  await mediaDeleteCommand(mediaId);
33466
33973
  } catch (error51) {
33467
- if (error51 instanceof Error) console.error(import_chalk24.default.red(`
33974
+ if (error51 instanceof Error) console.error(import_chalk25.default.red(`
33468
33975
  \u2717 ${error51.message}
33469
33976
  `));
33470
33977
  process.exit(1);
@@ -33475,7 +33982,7 @@ if (isAgentMode()) {
33475
33982
  await mediaListCommand(options);
33476
33983
  } catch (error51) {
33477
33984
  if (error51 instanceof Error) {
33478
- console.error(import_chalk24.default.red(`
33985
+ console.error(import_chalk25.default.red(`
33479
33986
  \u2717 ${error51.message}
33480
33987
  `));
33481
33988
  }
@@ -33488,7 +33995,7 @@ if (isAgentMode()) {
33488
33995
  await mothershipMonitorChannelCommand(options);
33489
33996
  } catch (error51) {
33490
33997
  if (error51 instanceof Error) {
33491
- console.error(import_chalk24.default.red(`
33998
+ console.error(import_chalk25.default.red(`
33492
33999
  \u2717 ${error51.message}
33493
34000
  `));
33494
34001
  }
@@ -33500,7 +34007,7 @@ if (isAgentMode()) {
33500
34007
  await mothershipSpawnCommand(options);
33501
34008
  } catch (error51) {
33502
34009
  if (error51 instanceof Error) {
33503
- console.error(import_chalk24.default.red(`
34010
+ console.error(import_chalk25.default.red(`
33504
34011
  \u2717 ${error51.message}
33505
34012
  `));
33506
34013
  }
@@ -33512,7 +34019,7 @@ if (isAgentMode()) {
33512
34019
  await mothershipRelayCommand(options);
33513
34020
  } catch (error51) {
33514
34021
  if (error51 instanceof Error) {
33515
- console.error(import_chalk24.default.red(`
34022
+ console.error(import_chalk25.default.red(`
33516
34023
  \u2717 ${error51.message}
33517
34024
  `));
33518
34025
  }
@@ -33534,6 +34041,7 @@ if (isAgentMode()) {
33534
34041
  "automation",
33535
34042
  "repos",
33536
34043
  "environment",
34044
+ "environment-setup",
33537
34045
  "mothership"
33538
34046
  ]);
33539
34047
  const kept = program.commands.filter((cmd) => allowed.has(cmd.name()));
@@ -33545,7 +34053,7 @@ async function main() {
33545
34053
  if (process.argv[2] === "computer" && isAgentMode()) {
33546
34054
  const result = (0, import_node_child_process3.spawnSync)("replicas-computer", process.argv.slice(3), { stdio: "inherit" });
33547
34055
  if (result.error) {
33548
- console.error(import_chalk24.default.red(`
34056
+ console.error(import_chalk25.default.red(`
33549
34057
  \u2717 replicas-computer is unavailable in this workspace image
33550
34058
  `));
33551
34059
  process.exitCode = 1;