@defend-tech/opencode-optima 0.1.83 → 0.1.84

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.
@@ -109,17 +109,17 @@ var require_visit = __commonJS({
109
109
  visit.BREAK = BREAK;
110
110
  visit.SKIP = SKIP;
111
111
  visit.REMOVE = REMOVE;
112
- function visit_(key, node, visitor, path20) {
113
- const ctrl = callVisitor(key, node, visitor, path20);
112
+ function visit_(key, node, visitor, path22) {
113
+ const ctrl = callVisitor(key, node, visitor, path22);
114
114
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
115
- replaceNode(key, path20, ctrl);
116
- return visit_(key, ctrl, visitor, path20);
115
+ replaceNode(key, path22, ctrl);
116
+ return visit_(key, ctrl, visitor, path22);
117
117
  }
118
118
  if (typeof ctrl !== "symbol") {
119
119
  if (identity.isCollection(node)) {
120
- path20 = Object.freeze(path20.concat(node));
120
+ path22 = Object.freeze(path22.concat(node));
121
121
  for (let i = 0; i < node.items.length; ++i) {
122
- const ci = visit_(i, node.items[i], visitor, path20);
122
+ const ci = visit_(i, node.items[i], visitor, path22);
123
123
  if (typeof ci === "number")
124
124
  i = ci - 1;
125
125
  else if (ci === BREAK)
@@ -130,13 +130,13 @@ var require_visit = __commonJS({
130
130
  }
131
131
  }
132
132
  } else if (identity.isPair(node)) {
133
- path20 = Object.freeze(path20.concat(node));
134
- const ck = visit_("key", node.key, visitor, path20);
133
+ path22 = Object.freeze(path22.concat(node));
134
+ const ck = visit_("key", node.key, visitor, path22);
135
135
  if (ck === BREAK)
136
136
  return BREAK;
137
137
  else if (ck === REMOVE)
138
138
  node.key = null;
139
- const cv = visit_("value", node.value, visitor, path20);
139
+ const cv = visit_("value", node.value, visitor, path22);
140
140
  if (cv === BREAK)
141
141
  return BREAK;
142
142
  else if (cv === REMOVE)
@@ -157,17 +157,17 @@ var require_visit = __commonJS({
157
157
  visitAsync.BREAK = BREAK;
158
158
  visitAsync.SKIP = SKIP;
159
159
  visitAsync.REMOVE = REMOVE;
160
- async function visitAsync_(key, node, visitor, path20) {
161
- const ctrl = await callVisitor(key, node, visitor, path20);
160
+ async function visitAsync_(key, node, visitor, path22) {
161
+ const ctrl = await callVisitor(key, node, visitor, path22);
162
162
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
163
- replaceNode(key, path20, ctrl);
164
- return visitAsync_(key, ctrl, visitor, path20);
163
+ replaceNode(key, path22, ctrl);
164
+ return visitAsync_(key, ctrl, visitor, path22);
165
165
  }
166
166
  if (typeof ctrl !== "symbol") {
167
167
  if (identity.isCollection(node)) {
168
- path20 = Object.freeze(path20.concat(node));
168
+ path22 = Object.freeze(path22.concat(node));
169
169
  for (let i = 0; i < node.items.length; ++i) {
170
- const ci = await visitAsync_(i, node.items[i], visitor, path20);
170
+ const ci = await visitAsync_(i, node.items[i], visitor, path22);
171
171
  if (typeof ci === "number")
172
172
  i = ci - 1;
173
173
  else if (ci === BREAK)
@@ -178,13 +178,13 @@ var require_visit = __commonJS({
178
178
  }
179
179
  }
180
180
  } else if (identity.isPair(node)) {
181
- path20 = Object.freeze(path20.concat(node));
182
- const ck = await visitAsync_("key", node.key, visitor, path20);
181
+ path22 = Object.freeze(path22.concat(node));
182
+ const ck = await visitAsync_("key", node.key, visitor, path22);
183
183
  if (ck === BREAK)
184
184
  return BREAK;
185
185
  else if (ck === REMOVE)
186
186
  node.key = null;
187
- const cv = await visitAsync_("value", node.value, visitor, path20);
187
+ const cv = await visitAsync_("value", node.value, visitor, path22);
188
188
  if (cv === BREAK)
189
189
  return BREAK;
190
190
  else if (cv === REMOVE)
@@ -211,23 +211,23 @@ var require_visit = __commonJS({
211
211
  }
212
212
  return visitor;
213
213
  }
214
- function callVisitor(key, node, visitor, path20) {
214
+ function callVisitor(key, node, visitor, path22) {
215
215
  if (typeof visitor === "function")
216
- return visitor(key, node, path20);
216
+ return visitor(key, node, path22);
217
217
  if (identity.isMap(node))
218
- return visitor.Map?.(key, node, path20);
218
+ return visitor.Map?.(key, node, path22);
219
219
  if (identity.isSeq(node))
220
- return visitor.Seq?.(key, node, path20);
220
+ return visitor.Seq?.(key, node, path22);
221
221
  if (identity.isPair(node))
222
- return visitor.Pair?.(key, node, path20);
222
+ return visitor.Pair?.(key, node, path22);
223
223
  if (identity.isScalar(node))
224
- return visitor.Scalar?.(key, node, path20);
224
+ return visitor.Scalar?.(key, node, path22);
225
225
  if (identity.isAlias(node))
226
- return visitor.Alias?.(key, node, path20);
226
+ return visitor.Alias?.(key, node, path22);
227
227
  return void 0;
228
228
  }
229
- function replaceNode(key, path20, node) {
230
- const parent = path20[path20.length - 1];
229
+ function replaceNode(key, path22, node) {
230
+ const parent = path22[path22.length - 1];
231
231
  if (identity.isCollection(parent)) {
232
232
  parent.items[key] = node;
233
233
  } else if (identity.isPair(parent)) {
@@ -835,10 +835,10 @@ var require_Collection = __commonJS({
835
835
  var createNode = require_createNode();
836
836
  var identity = require_identity();
837
837
  var Node = require_Node();
838
- function collectionFromPath(schema, path20, value) {
838
+ function collectionFromPath(schema, path22, value) {
839
839
  let v = value;
840
- for (let i = path20.length - 1; i >= 0; --i) {
841
- const k = path20[i];
840
+ for (let i = path22.length - 1; i >= 0; --i) {
841
+ const k = path22[i];
842
842
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
843
843
  const a = [];
844
844
  a[k] = v;
@@ -857,7 +857,7 @@ var require_Collection = __commonJS({
857
857
  sourceObjects: /* @__PURE__ */ new Map()
858
858
  });
859
859
  }
860
- var isEmptyPath = (path20) => path20 == null || typeof path20 === "object" && !!path20[Symbol.iterator]().next().done;
860
+ var isEmptyPath = (path22) => path22 == null || typeof path22 === "object" && !!path22[Symbol.iterator]().next().done;
861
861
  var Collection = class extends Node.NodeBase {
862
862
  constructor(type, schema) {
863
863
  super(type);
@@ -887,11 +887,11 @@ var require_Collection = __commonJS({
887
887
  * be a Pair instance or a `{ key, value }` object, which may not have a key
888
888
  * that already exists in the map.
889
889
  */
890
- addIn(path20, value) {
891
- if (isEmptyPath(path20))
890
+ addIn(path22, value) {
891
+ if (isEmptyPath(path22))
892
892
  this.add(value);
893
893
  else {
894
- const [key, ...rest] = path20;
894
+ const [key, ...rest] = path22;
895
895
  const node = this.get(key, true);
896
896
  if (identity.isCollection(node))
897
897
  node.addIn(rest, value);
@@ -905,8 +905,8 @@ var require_Collection = __commonJS({
905
905
  * Removes a value from the collection.
906
906
  * @returns `true` if the item was found and removed.
907
907
  */
908
- deleteIn(path20) {
909
- const [key, ...rest] = path20;
908
+ deleteIn(path22) {
909
+ const [key, ...rest] = path22;
910
910
  if (rest.length === 0)
911
911
  return this.delete(key);
912
912
  const node = this.get(key, true);
@@ -920,8 +920,8 @@ var require_Collection = __commonJS({
920
920
  * scalar values from their surrounding node; to disable set `keepScalar` to
921
921
  * `true` (collections are always returned intact).
922
922
  */
923
- getIn(path20, keepScalar) {
924
- const [key, ...rest] = path20;
923
+ getIn(path22, keepScalar) {
924
+ const [key, ...rest] = path22;
925
925
  const node = this.get(key, true);
926
926
  if (rest.length === 0)
927
927
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -939,8 +939,8 @@ var require_Collection = __commonJS({
939
939
  /**
940
940
  * Checks if the collection includes a value with the key `key`.
941
941
  */
942
- hasIn(path20) {
943
- const [key, ...rest] = path20;
942
+ hasIn(path22) {
943
+ const [key, ...rest] = path22;
944
944
  if (rest.length === 0)
945
945
  return this.has(key);
946
946
  const node = this.get(key, true);
@@ -950,8 +950,8 @@ var require_Collection = __commonJS({
950
950
  * Sets a value in this collection. For `!!set`, `value` needs to be a
951
951
  * boolean to add/remove the item from the set.
952
952
  */
953
- setIn(path20, value) {
954
- const [key, ...rest] = path20;
953
+ setIn(path22, value) {
954
+ const [key, ...rest] = path22;
955
955
  if (rest.length === 0) {
956
956
  this.set(key, value);
957
957
  } else {
@@ -3455,9 +3455,9 @@ var require_Document = __commonJS({
3455
3455
  this.contents.add(value);
3456
3456
  }
3457
3457
  /** Adds a value to the document. */
3458
- addIn(path20, value) {
3458
+ addIn(path22, value) {
3459
3459
  if (assertCollection(this.contents))
3460
- this.contents.addIn(path20, value);
3460
+ this.contents.addIn(path22, value);
3461
3461
  }
3462
3462
  /**
3463
3463
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -3532,14 +3532,14 @@ var require_Document = __commonJS({
3532
3532
  * Removes a value from the document.
3533
3533
  * @returns `true` if the item was found and removed.
3534
3534
  */
3535
- deleteIn(path20) {
3536
- if (Collection.isEmptyPath(path20)) {
3535
+ deleteIn(path22) {
3536
+ if (Collection.isEmptyPath(path22)) {
3537
3537
  if (this.contents == null)
3538
3538
  return false;
3539
3539
  this.contents = null;
3540
3540
  return true;
3541
3541
  }
3542
- return assertCollection(this.contents) ? this.contents.deleteIn(path20) : false;
3542
+ return assertCollection(this.contents) ? this.contents.deleteIn(path22) : false;
3543
3543
  }
3544
3544
  /**
3545
3545
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -3554,10 +3554,10 @@ var require_Document = __commonJS({
3554
3554
  * scalar values from their surrounding node; to disable set `keepScalar` to
3555
3555
  * `true` (collections are always returned intact).
3556
3556
  */
3557
- getIn(path20, keepScalar) {
3558
- if (Collection.isEmptyPath(path20))
3557
+ getIn(path22, keepScalar) {
3558
+ if (Collection.isEmptyPath(path22))
3559
3559
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
3560
- return identity.isCollection(this.contents) ? this.contents.getIn(path20, keepScalar) : void 0;
3560
+ return identity.isCollection(this.contents) ? this.contents.getIn(path22, keepScalar) : void 0;
3561
3561
  }
3562
3562
  /**
3563
3563
  * Checks if the document includes a value with the key `key`.
@@ -3568,10 +3568,10 @@ var require_Document = __commonJS({
3568
3568
  /**
3569
3569
  * Checks if the document includes a value at `path`.
3570
3570
  */
3571
- hasIn(path20) {
3572
- if (Collection.isEmptyPath(path20))
3571
+ hasIn(path22) {
3572
+ if (Collection.isEmptyPath(path22))
3573
3573
  return this.contents !== void 0;
3574
- return identity.isCollection(this.contents) ? this.contents.hasIn(path20) : false;
3574
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path22) : false;
3575
3575
  }
3576
3576
  /**
3577
3577
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -3588,13 +3588,13 @@ var require_Document = __commonJS({
3588
3588
  * Sets a value in this document. For `!!set`, `value` needs to be a
3589
3589
  * boolean to add/remove the item from the set.
3590
3590
  */
3591
- setIn(path20, value) {
3592
- if (Collection.isEmptyPath(path20)) {
3591
+ setIn(path22, value) {
3592
+ if (Collection.isEmptyPath(path22)) {
3593
3593
  this.contents = value;
3594
3594
  } else if (this.contents == null) {
3595
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path20), value);
3595
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path22), value);
3596
3596
  } else if (assertCollection(this.contents)) {
3597
- this.contents.setIn(path20, value);
3597
+ this.contents.setIn(path22, value);
3598
3598
  }
3599
3599
  }
3600
3600
  /**
@@ -5546,9 +5546,9 @@ var require_cst_visit = __commonJS({
5546
5546
  visit.BREAK = BREAK;
5547
5547
  visit.SKIP = SKIP;
5548
5548
  visit.REMOVE = REMOVE;
5549
- visit.itemAtPath = (cst, path20) => {
5549
+ visit.itemAtPath = (cst, path22) => {
5550
5550
  let item = cst;
5551
- for (const [field, index] of path20) {
5551
+ for (const [field, index] of path22) {
5552
5552
  const tok = item?.[field];
5553
5553
  if (tok && "items" in tok) {
5554
5554
  item = tok.items[index];
@@ -5557,23 +5557,23 @@ var require_cst_visit = __commonJS({
5557
5557
  }
5558
5558
  return item;
5559
5559
  };
5560
- visit.parentCollection = (cst, path20) => {
5561
- const parent = visit.itemAtPath(cst, path20.slice(0, -1));
5562
- const field = path20[path20.length - 1][0];
5560
+ visit.parentCollection = (cst, path22) => {
5561
+ const parent = visit.itemAtPath(cst, path22.slice(0, -1));
5562
+ const field = path22[path22.length - 1][0];
5563
5563
  const coll = parent?.[field];
5564
5564
  if (coll && "items" in coll)
5565
5565
  return coll;
5566
5566
  throw new Error("Parent collection not found");
5567
5567
  };
5568
- function _visit(path20, item, visitor) {
5569
- let ctrl = visitor(item, path20);
5568
+ function _visit(path22, item, visitor) {
5569
+ let ctrl = visitor(item, path22);
5570
5570
  if (typeof ctrl === "symbol")
5571
5571
  return ctrl;
5572
5572
  for (const field of ["key", "value"]) {
5573
5573
  const token = item[field];
5574
5574
  if (token && "items" in token) {
5575
5575
  for (let i = 0; i < token.items.length; ++i) {
5576
- const ci = _visit(Object.freeze(path20.concat([[field, i]])), token.items[i], visitor);
5576
+ const ci = _visit(Object.freeze(path22.concat([[field, i]])), token.items[i], visitor);
5577
5577
  if (typeof ci === "number")
5578
5578
  i = ci - 1;
5579
5579
  else if (ci === BREAK)
@@ -5584,10 +5584,10 @@ var require_cst_visit = __commonJS({
5584
5584
  }
5585
5585
  }
5586
5586
  if (typeof ctrl === "function" && field === "key")
5587
- ctrl = ctrl(item, path20);
5587
+ ctrl = ctrl(item, path22);
5588
5588
  }
5589
5589
  }
5590
- return typeof ctrl === "function" ? ctrl(item, path20) : ctrl;
5590
+ return typeof ctrl === "function" ? ctrl(item, path22) : ctrl;
5591
5591
  }
5592
5592
  exports.visit = visit;
5593
5593
  }
@@ -6872,14 +6872,14 @@ var require_parser = __commonJS({
6872
6872
  case "scalar":
6873
6873
  case "single-quoted-scalar":
6874
6874
  case "double-quoted-scalar": {
6875
- const fs19 = this.flowScalar(this.type);
6875
+ const fs21 = this.flowScalar(this.type);
6876
6876
  if (atNextItem || it.value) {
6877
- map.items.push({ start, key: fs19, sep: [] });
6877
+ map.items.push({ start, key: fs21, sep: [] });
6878
6878
  this.onKeyLine = true;
6879
6879
  } else if (it.sep) {
6880
- this.stack.push(fs19);
6880
+ this.stack.push(fs21);
6881
6881
  } else {
6882
- Object.assign(it, { key: fs19, sep: [] });
6882
+ Object.assign(it, { key: fs21, sep: [] });
6883
6883
  this.onKeyLine = true;
6884
6884
  }
6885
6885
  return;
@@ -7007,13 +7007,13 @@ var require_parser = __commonJS({
7007
7007
  case "scalar":
7008
7008
  case "single-quoted-scalar":
7009
7009
  case "double-quoted-scalar": {
7010
- const fs19 = this.flowScalar(this.type);
7010
+ const fs21 = this.flowScalar(this.type);
7011
7011
  if (!it || it.value)
7012
- fc.items.push({ start: [], key: fs19, sep: [] });
7012
+ fc.items.push({ start: [], key: fs21, sep: [] });
7013
7013
  else if (it.sep)
7014
- this.stack.push(fs19);
7014
+ this.stack.push(fs21);
7015
7015
  else
7016
- Object.assign(it, { key: fs19, sep: [] });
7016
+ Object.assign(it, { key: fs21, sep: [] });
7017
7017
  return;
7018
7018
  }
7019
7019
  case "flow-map-end":
@@ -7551,17 +7551,17 @@ var require_ignore = __commonJS({
7551
7551
  var throwError = (message, Ctor) => {
7552
7552
  throw new Ctor(message);
7553
7553
  };
7554
- var checkPath = (path20, originalPath, doThrow) => {
7555
- if (!isString(path20)) {
7554
+ var checkPath = (path22, originalPath, doThrow) => {
7555
+ if (!isString(path22)) {
7556
7556
  return doThrow(
7557
7557
  `path must be a string, but got \`${originalPath}\``,
7558
7558
  TypeError
7559
7559
  );
7560
7560
  }
7561
- if (!path20) {
7561
+ if (!path22) {
7562
7562
  return doThrow(`path must not be empty`, TypeError);
7563
7563
  }
7564
- if (checkPath.isNotRelative(path20)) {
7564
+ if (checkPath.isNotRelative(path22)) {
7565
7565
  const r = "`path.relative()`d";
7566
7566
  return doThrow(
7567
7567
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -7570,7 +7570,7 @@ var require_ignore = __commonJS({
7570
7570
  }
7571
7571
  return true;
7572
7572
  };
7573
- var isNotRelative = (path20) => REGEX_TEST_INVALID_PATH.test(path20);
7573
+ var isNotRelative = (path22) => REGEX_TEST_INVALID_PATH.test(path22);
7574
7574
  checkPath.isNotRelative = isNotRelative;
7575
7575
  checkPath.convert = (p) => p;
7576
7576
  var Ignore = class {
@@ -7629,7 +7629,7 @@ var require_ignore = __commonJS({
7629
7629
  // setting `checkUnignored` to `false` could reduce additional
7630
7630
  // path matching.
7631
7631
  // @returns {TestResult} true if a file is ignored
7632
- _testOne(path20, checkUnignored) {
7632
+ _testOne(path22, checkUnignored) {
7633
7633
  let ignored = false;
7634
7634
  let unignored = false;
7635
7635
  this._rules.forEach((rule) => {
@@ -7637,7 +7637,7 @@ var require_ignore = __commonJS({
7637
7637
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
7638
7638
  return;
7639
7639
  }
7640
- const matched = rule.regex.test(path20);
7640
+ const matched = rule.regex.test(path22);
7641
7641
  if (matched) {
7642
7642
  ignored = !negative;
7643
7643
  unignored = negative;
@@ -7650,24 +7650,24 @@ var require_ignore = __commonJS({
7650
7650
  }
7651
7651
  // @returns {TestResult}
7652
7652
  _test(originalPath, cache, checkUnignored, slices) {
7653
- const path20 = originalPath && checkPath.convert(originalPath);
7653
+ const path22 = originalPath && checkPath.convert(originalPath);
7654
7654
  checkPath(
7655
- path20,
7655
+ path22,
7656
7656
  originalPath,
7657
7657
  this._allowRelativePaths ? RETURN_FALSE : throwError
7658
7658
  );
7659
- return this._t(path20, cache, checkUnignored, slices);
7659
+ return this._t(path22, cache, checkUnignored, slices);
7660
7660
  }
7661
- _t(path20, cache, checkUnignored, slices) {
7662
- if (path20 in cache) {
7663
- return cache[path20];
7661
+ _t(path22, cache, checkUnignored, slices) {
7662
+ if (path22 in cache) {
7663
+ return cache[path22];
7664
7664
  }
7665
7665
  if (!slices) {
7666
- slices = path20.split(SLASH);
7666
+ slices = path22.split(SLASH);
7667
7667
  }
7668
7668
  slices.pop();
7669
7669
  if (!slices.length) {
7670
- return cache[path20] = this._testOne(path20, checkUnignored);
7670
+ return cache[path22] = this._testOne(path22, checkUnignored);
7671
7671
  }
7672
7672
  const parent = this._t(
7673
7673
  slices.join(SLASH) + SLASH,
@@ -7675,24 +7675,24 @@ var require_ignore = __commonJS({
7675
7675
  checkUnignored,
7676
7676
  slices
7677
7677
  );
7678
- return cache[path20] = parent.ignored ? parent : this._testOne(path20, checkUnignored);
7678
+ return cache[path22] = parent.ignored ? parent : this._testOne(path22, checkUnignored);
7679
7679
  }
7680
- ignores(path20) {
7681
- return this._test(path20, this._ignoreCache, false).ignored;
7680
+ ignores(path22) {
7681
+ return this._test(path22, this._ignoreCache, false).ignored;
7682
7682
  }
7683
7683
  createFilter() {
7684
- return (path20) => !this.ignores(path20);
7684
+ return (path22) => !this.ignores(path22);
7685
7685
  }
7686
7686
  filter(paths) {
7687
7687
  return makeArray(paths).filter(this.createFilter());
7688
7688
  }
7689
7689
  // @returns {TestResult}
7690
- test(path20) {
7691
- return this._test(path20, this._testCache, true);
7690
+ test(path22) {
7691
+ return this._test(path22, this._testCache, true);
7692
7692
  }
7693
7693
  };
7694
7694
  var factory = (options) => new Ignore(options);
7695
- var isPathValid = (path20) => checkPath(path20 && checkPath.convert(path20), path20, RETURN_FALSE);
7695
+ var isPathValid = (path22) => checkPath(path22 && checkPath.convert(path22), path22, RETURN_FALSE);
7696
7696
  factory.isPathValid = isPathValid;
7697
7697
  factory.default = factory;
7698
7698
  module.exports = factory;
@@ -7703,22 +7703,22 @@ var require_ignore = __commonJS({
7703
7703
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
7704
7704
  checkPath.convert = makePosix;
7705
7705
  const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
7706
- checkPath.isNotRelative = (path20) => REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path20) || isNotRelative(path20);
7706
+ checkPath.isNotRelative = (path22) => REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path22) || isNotRelative(path22);
7707
7707
  }
7708
7708
  }
7709
7709
  });
7710
7710
 
7711
7711
  // src/sanitize_cli.js
7712
- import fs18 from "node:fs";
7713
- import os5 from "node:os";
7714
- import path19 from "node:path";
7712
+ import fs20 from "node:fs";
7713
+ import os7 from "node:os";
7714
+ import path21 from "node:path";
7715
7715
  import { execFileSync as execFileSync2, spawnSync } from "node:child_process";
7716
7716
 
7717
7717
  // src/plugin.js
7718
- import fs17 from "node:fs";
7718
+ import fs19 from "node:fs";
7719
7719
  var import_yaml6 = __toESM(require_dist(), 1);
7720
7720
  var import_ignore3 = __toESM(require_ignore(), 1);
7721
- import path18 from "node:path";
7721
+ import path20 from "node:path";
7722
7722
  import { tool } from "@opencode-ai/plugin/tool";
7723
7723
 
7724
7724
  // src/agents.js
@@ -9962,8 +9962,8 @@ function clickUpWebhookLogPath(worktree) {
9962
9962
  return path7.join(optimaRuntimeDir(worktree), "clickup-webhook.log.jsonl");
9963
9963
  }
9964
9964
  function clickUpWebhookAuditLogDir() {
9965
- const dataHome = process.env.XDG_DATA_HOME && path7.isAbsolute(process.env.XDG_DATA_HOME) ? process.env.XDG_DATA_HOME : path7.join(os2.homedir(), ".local", "share", "opencode");
9966
- return path7.join(dataHome, "opencode-optima");
9965
+ const dataHome2 = process.env.XDG_DATA_HOME && path7.isAbsolute(process.env.XDG_DATA_HOME) ? process.env.XDG_DATA_HOME : path7.join(os2.homedir(), ".local", "share", "opencode");
9966
+ return path7.join(dataHome2, "opencode-optima");
9967
9967
  }
9968
9968
  function clickUpWebhookAuditLogPath(at = /* @__PURE__ */ new Date(), logDir = clickUpWebhookAuditLogDir()) {
9969
9969
  return path7.join(logDir, `clickup-webhook-${at.toISOString().slice(0, 10)}.jsonl`);
@@ -13506,11 +13506,392 @@ function createGitHubApiClient(config = {}, fetchImpl = globalThis.fetch) {
13506
13506
  };
13507
13507
  }
13508
13508
 
13509
+ // src/qa/chrome.js
13510
+ import fs16 from "node:fs";
13511
+ import os6 from "node:os";
13512
+ import path17 from "node:path";
13513
+
13514
+ // src/qa/queue.js
13515
+ import fs15 from "node:fs";
13516
+ import os5 from "node:os";
13517
+ import path16 from "node:path";
13518
+ var DEFAULT_QA_LEASE_MS = 5 * 60 * 1e3;
13519
+ var DEFAULT_QA_PROVIDER = "chatgpt";
13520
+ function dataHome() {
13521
+ return process.env.XDG_DATA_HOME && path16.isAbsolute(process.env.XDG_DATA_HOME) ? process.env.XDG_DATA_HOME : path16.join(os5.homedir(), ".local", "share", "opencode");
13522
+ }
13523
+ function qaRuntimeDir() {
13524
+ return path16.join(dataHome(), "opencode-optima", "qa");
13525
+ }
13526
+ function normalizeQaProvider(provider = DEFAULT_QA_PROVIDER) {
13527
+ const normalized = String(provider || DEFAULT_QA_PROVIDER).trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-");
13528
+ return normalized || DEFAULT_QA_PROVIDER;
13529
+ }
13530
+ function qaQueueStatePath(provider = DEFAULT_QA_PROVIDER) {
13531
+ return path16.join(qaRuntimeDir(), `${normalizeQaProvider(provider)}-queue.json`);
13532
+ }
13533
+ function nowIso(now = /* @__PURE__ */ new Date()) {
13534
+ return now instanceof Date ? now.toISOString() : new Date(now).toISOString();
13535
+ }
13536
+ function normalizeClickUpTaskId(value = "") {
13537
+ return String(value || "").trim();
13538
+ }
13539
+ function emptyQaQueueState(provider = DEFAULT_QA_PROVIDER) {
13540
+ return {
13541
+ provider: normalizeQaProvider(provider),
13542
+ active: null,
13543
+ queue: [],
13544
+ history: []
13545
+ };
13546
+ }
13547
+ function readQaQueueState(provider = DEFAULT_QA_PROVIDER, statePath = qaQueueStatePath(provider)) {
13548
+ try {
13549
+ const raw = fs15.readFileSync(statePath, "utf8");
13550
+ const parsed = JSON.parse(raw);
13551
+ if (!isPlainObject(parsed)) return emptyQaQueueState(provider);
13552
+ return {
13553
+ ...emptyQaQueueState(provider),
13554
+ ...parsed,
13555
+ provider: normalizeQaProvider(parsed.provider || provider),
13556
+ queue: Array.isArray(parsed.queue) ? parsed.queue.filter(isPlainObject) : [],
13557
+ history: Array.isArray(parsed.history) ? parsed.history.filter(isPlainObject).slice(-50) : []
13558
+ };
13559
+ } catch {
13560
+ return emptyQaQueueState(provider);
13561
+ }
13562
+ }
13563
+ function writeQaQueueState(state, statePath = qaQueueStatePath(state?.provider)) {
13564
+ const normalized = {
13565
+ ...emptyQaQueueState(state?.provider),
13566
+ ...state,
13567
+ provider: normalizeQaProvider(state?.provider),
13568
+ queue: Array.isArray(state?.queue) ? state.queue.filter(isPlainObject) : [],
13569
+ history: Array.isArray(state?.history) ? state.history.filter(isPlainObject).slice(-50) : []
13570
+ };
13571
+ fs15.mkdirSync(path16.dirname(statePath), { recursive: true });
13572
+ fs15.writeFileSync(statePath, `${JSON.stringify(normalized, null, 2)}
13573
+ `, { mode: 384 });
13574
+ return normalized;
13575
+ }
13576
+ function activeExpired(active, nowMs, leaseMs) {
13577
+ if (!active?.clickupTaskId) return false;
13578
+ const last = Date.parse(active.lastActivityAt || active.grantedAt || "");
13579
+ return Number.isFinite(last) && nowMs - last > leaseMs;
13580
+ }
13581
+ function queuedIndex(state, clickupTaskId) {
13582
+ return state.queue.findIndex((entry) => entry.clickupTaskId === clickupTaskId);
13583
+ }
13584
+ function queueEntry({ clickupTaskId, sessionId = "", worktree = "", reason = "", now = /* @__PURE__ */ new Date() } = {}) {
13585
+ return {
13586
+ clickupTaskId,
13587
+ sessionId: String(sessionId || "").trim(),
13588
+ worktree: String(worktree || "").trim(),
13589
+ reason: String(reason || "").trim(),
13590
+ queuedAt: nowIso(now),
13591
+ lastRequestAt: nowIso(now)
13592
+ };
13593
+ }
13594
+ function activeEntry({ provider, clickupTaskId, sessionId = "", worktree = "", leaseMs = DEFAULT_QA_LEASE_MS, now = /* @__PURE__ */ new Date() } = {}) {
13595
+ return {
13596
+ provider: normalizeQaProvider(provider),
13597
+ clickupTaskId,
13598
+ sessionId: String(sessionId || "").trim(),
13599
+ worktree: String(worktree || "").trim(),
13600
+ grantedAt: nowIso(now),
13601
+ lastActivityAt: nowIso(now),
13602
+ leaseMs
13603
+ };
13604
+ }
13605
+ function releaseExpiredQaSlot(state, { now = /* @__PURE__ */ new Date(), leaseMs = DEFAULT_QA_LEASE_MS } = {}) {
13606
+ const normalized = { ...emptyQaQueueState(state?.provider), ...state, queue: Array.isArray(state?.queue) ? [...state.queue] : [] };
13607
+ if (!activeExpired(normalized.active, now.getTime(), leaseMs)) return { state: normalized, expired: null, promoted: null };
13608
+ const expired = normalized.active;
13609
+ normalized.history = [...normalized.history || [], { action: "expired", clickupTaskId: expired.clickupTaskId, at: nowIso(now) }].slice(-50);
13610
+ normalized.active = null;
13611
+ const promoted = normalized.queue.shift() || null;
13612
+ if (promoted) {
13613
+ normalized.active = activeEntry({ ...promoted, provider: normalized.provider, leaseMs, now });
13614
+ normalized.history = [...normalized.history || [], { action: "promoted", clickupTaskId: promoted.clickupTaskId, at: nowIso(now), reason: "expired_previous_slot" }].slice(-50);
13615
+ }
13616
+ return { state: normalized, expired, promoted };
13617
+ }
13618
+ function requestQaSlot(state, { clickupTaskId, sessionId = "", worktree = "", reason = "", now = /* @__PURE__ */ new Date(), leaseMs = DEFAULT_QA_LEASE_MS } = {}) {
13619
+ const taskId = normalizeClickUpTaskId(clickupTaskId);
13620
+ if (!taskId) return { state, ok: false, action: "invalid", reason: "clickup_task_id_required" };
13621
+ let next = { ...emptyQaQueueState(state?.provider), ...state, queue: Array.isArray(state?.queue) ? [...state.queue] : [] };
13622
+ const expiredResult = releaseExpiredQaSlot(next, { now, leaseMs });
13623
+ next = expiredResult.state;
13624
+ if (!next.active) {
13625
+ next.active = activeEntry({ provider: next.provider, clickupTaskId: taskId, sessionId, worktree, leaseMs, now });
13626
+ next.queue = next.queue.filter((entry) => entry.clickupTaskId !== taskId);
13627
+ next.history = [...next.history || [], { action: "granted", clickupTaskId: taskId, at: nowIso(now) }].slice(-50);
13628
+ return { state: next, ok: true, action: "granted", active: next.active, expired: expiredResult.expired, promoted: expiredResult.promoted };
13629
+ }
13630
+ if (next.active.clickupTaskId === taskId) {
13631
+ next.active = { ...next.active, sessionId: sessionId || next.active.sessionId || "", worktree: worktree || next.active.worktree || "", lastActivityAt: nowIso(now), leaseMs };
13632
+ next.history = [...next.history || [], { action: "renewed", clickupTaskId: taskId, at: nowIso(now) }].slice(-50);
13633
+ return { state: next, ok: true, action: "granted_existing", active: next.active, expired: expiredResult.expired, promoted: expiredResult.promoted };
13634
+ }
13635
+ const index = queuedIndex(next, taskId);
13636
+ if (index >= 0) {
13637
+ next.queue[index] = { ...next.queue[index], sessionId: sessionId || next.queue[index].sessionId || "", worktree: worktree || next.queue[index].worktree || "", reason: reason || next.queue[index].reason || "", lastRequestAt: nowIso(now) };
13638
+ } else {
13639
+ next.queue.push(queueEntry({ clickupTaskId: taskId, sessionId, worktree, reason, now }));
13640
+ }
13641
+ return {
13642
+ state: next,
13643
+ ok: false,
13644
+ action: "queued",
13645
+ active: next.active,
13646
+ position: queuedIndex(next, taskId) + 1,
13647
+ expired: expiredResult.expired,
13648
+ promoted: expiredResult.promoted
13649
+ };
13650
+ }
13651
+ function touchQaSlot(state, { clickupTaskId, now = /* @__PURE__ */ new Date(), leaseMs = DEFAULT_QA_LEASE_MS } = {}) {
13652
+ const taskId = normalizeClickUpTaskId(clickupTaskId);
13653
+ let next = { ...emptyQaQueueState(state?.provider), ...state, queue: Array.isArray(state?.queue) ? [...state.queue] : [] };
13654
+ const expiredResult = releaseExpiredQaSlot(next, { now, leaseMs });
13655
+ next = expiredResult.state;
13656
+ if (!next.active || next.active.clickupTaskId !== taskId) return { state: next, ok: false, action: "not_active_holder", active: next.active, expired: expiredResult.expired, promoted: expiredResult.promoted };
13657
+ next.active = { ...next.active, lastActivityAt: nowIso(now), leaseMs };
13658
+ return { state: next, ok: true, action: "touched", active: next.active, expired: expiredResult.expired, promoted: expiredResult.promoted };
13659
+ }
13660
+ function finishQaSlot(state, { clickupTaskId, now = /* @__PURE__ */ new Date(), leaseMs = DEFAULT_QA_LEASE_MS } = {}) {
13661
+ const taskId = normalizeClickUpTaskId(clickupTaskId);
13662
+ let next = { ...emptyQaQueueState(state?.provider), ...state, queue: Array.isArray(state?.queue) ? [...state.queue] : [] };
13663
+ const expiredResult = releaseExpiredQaSlot(next, { now, leaseMs });
13664
+ next = expiredResult.state;
13665
+ if (!next.active || next.active.clickupTaskId !== taskId) return { state: next, ok: false, action: "not_active_holder", active: next.active, expired: expiredResult.expired, promoted: expiredResult.promoted };
13666
+ const released = next.active;
13667
+ next.active = null;
13668
+ next.history = [...next.history || [], { action: "finished", clickupTaskId: taskId, at: nowIso(now) }].slice(-50);
13669
+ const promoted = next.queue.shift() || null;
13670
+ if (promoted) {
13671
+ next.active = activeEntry({ ...promoted, provider: next.provider, leaseMs, now });
13672
+ next.history = [...next.history || [], { action: "promoted", clickupTaskId: promoted.clickupTaskId, at: nowIso(now), reason: "previous_finished" }].slice(-50);
13673
+ }
13674
+ return { state: next, ok: true, action: "finished", released, promoted };
13675
+ }
13676
+
13677
+ // src/qa/chrome.js
13678
+ var DEFAULT_QA_CDP_URL = "http://127.0.0.1:9222";
13679
+ function providerDir(provider = DEFAULT_QA_PROVIDER) {
13680
+ return path17.join(qaRuntimeDir(), normalizeQaProvider(provider));
13681
+ }
13682
+ function defaultQaExtensionStageDir(provider = DEFAULT_QA_PROVIDER) {
13683
+ return path17.join(providerDir(provider), "extension-under-test");
13684
+ }
13685
+ function defaultQaArtifactsDir(provider = DEFAULT_QA_PROVIDER, clickupTaskId = "unknown") {
13686
+ return path17.join(providerDir(provider), "artifacts", String(clickupTaskId || "unknown"));
13687
+ }
13688
+ function normalizeCdpUrl(value = "") {
13689
+ return String(value || process.env.OPTIMA_QA_CHROME_CDP_URL || DEFAULT_QA_CDP_URL).trim() || DEFAULT_QA_CDP_URL;
13690
+ }
13691
+ async function loadPlaywrightChromium() {
13692
+ try {
13693
+ const mod = await import("playwright-core");
13694
+ return mod.chromium;
13695
+ } catch (error) {
13696
+ throw new Error(`playwright-core is required for Optima QA browser tools: ${error.message}`);
13697
+ }
13698
+ }
13699
+ function qaWindowName(clickupTaskId) {
13700
+ return `optima-qa:${String(clickupTaskId || "").trim()}`;
13701
+ }
13702
+ async function safePageWindowName(page) {
13703
+ try {
13704
+ return await page.evaluate(() => window.name || "");
13705
+ } catch {
13706
+ return "";
13707
+ }
13708
+ }
13709
+ async function findQaPage(context, clickupTaskId) {
13710
+ const expected = qaWindowName(clickupTaskId);
13711
+ const pages = context.pages();
13712
+ for (let index = 1; index < pages.length; index += 1) {
13713
+ const page = pages[index];
13714
+ if (await safePageWindowName(page) === expected) return page;
13715
+ }
13716
+ return null;
13717
+ }
13718
+ async function ensurePersistentTab(context, url = "https://chatgpt.com/") {
13719
+ const pages = context.pages();
13720
+ if (pages[0]) return pages[0];
13721
+ const page = await context.newPage();
13722
+ await page.goto(url, { waitUntil: "domcontentloaded", timeout: 3e4 }).catch(() => {
13723
+ });
13724
+ return page;
13725
+ }
13726
+ async function ensureQaPage(context, { clickupTaskId, startUrl = "https://chatgpt.com/" } = {}) {
13727
+ await ensurePersistentTab(context, startUrl);
13728
+ const existing = await findQaPage(context, clickupTaskId);
13729
+ if (existing) return existing;
13730
+ const page = await context.newPage();
13731
+ await page.goto(startUrl, { waitUntil: "domcontentloaded", timeout: 3e4 }).catch(() => {
13732
+ });
13733
+ await page.evaluate((name) => {
13734
+ window.name = name;
13735
+ }, qaWindowName(clickupTaskId)).catch(() => {
13736
+ });
13737
+ return page;
13738
+ }
13739
+ function copyExtensionSource(sourcePath, stageDir) {
13740
+ const source = String(sourcePath || "").trim();
13741
+ if (!source) return { ok: true, skipped: true, reason: "extension_path_not_provided", stageDir };
13742
+ const resolved = path17.resolve(source.replace(/^~(?=$|\/)/, os6.homedir()));
13743
+ if (!fs16.existsSync(resolved)) return { ok: false, error: `extension_path_not_found: ${resolved}`, stageDir };
13744
+ fs16.rmSync(stageDir, { recursive: true, force: true });
13745
+ fs16.mkdirSync(path17.dirname(stageDir), { recursive: true });
13746
+ fs16.cpSync(resolved, stageDir, {
13747
+ recursive: true,
13748
+ filter: (src) => !/[/\\](node_modules|\.git|dist|build|test-results)([/\\]|$)/.test(src)
13749
+ });
13750
+ return { ok: true, source: resolved, stageDir };
13751
+ }
13752
+ function extensionIdFromWorkerUrl(url = "") {
13753
+ const match = String(url || "").match(/^chrome-extension:\/\/([^/]+)/);
13754
+ return match?.[1] || "";
13755
+ }
13756
+ async function findExtensionWorker(context, extensionId = "") {
13757
+ const workers = context.serviceWorkers ? context.serviceWorkers() : [];
13758
+ const normalized = String(extensionId || "").trim();
13759
+ if (normalized) return workers.find((worker) => worker.url().startsWith(`chrome-extension://${normalized}/`)) || null;
13760
+ return workers.find((worker) => String(worker.url()).startsWith("chrome-extension://")) || null;
13761
+ }
13762
+ async function resetExtensionState(context, { extensionId = "" } = {}) {
13763
+ const worker = await findExtensionWorker(context, extensionId);
13764
+ if (!worker) return { ok: false, error: "extension_service_worker_not_found" };
13765
+ const id = extensionIdFromWorkerUrl(worker.url());
13766
+ const result = await worker.evaluate(async () => {
13767
+ const deletedCaches = [];
13768
+ const deletedDbs = [];
13769
+ if (globalThis.chrome?.storage?.local) await chrome.storage.local.clear();
13770
+ if (globalThis.chrome?.storage?.session?.clear) await chrome.storage.session.clear();
13771
+ if (globalThis.chrome?.storage?.sync) await chrome.storage.sync.clear();
13772
+ if (globalThis.caches?.keys) {
13773
+ for (const name of await caches.keys()) {
13774
+ await caches.delete(name);
13775
+ deletedCaches.push(name);
13776
+ }
13777
+ }
13778
+ if (globalThis.indexedDB?.databases) {
13779
+ for (const db of await indexedDB.databases()) {
13780
+ if (db.name) {
13781
+ indexedDB.deleteDatabase(db.name);
13782
+ deletedDbs.push(db.name);
13783
+ }
13784
+ }
13785
+ }
13786
+ return { ok: true, deletedCaches, deletedDbs };
13787
+ });
13788
+ return { extensionId: id, ...result };
13789
+ }
13790
+ async function reloadExtension(context, { extensionId = "" } = {}) {
13791
+ const worker = await findExtensionWorker(context, extensionId);
13792
+ if (!worker) return { ok: false, error: "extension_service_worker_not_found" };
13793
+ const id = extensionIdFromWorkerUrl(worker.url());
13794
+ await worker.evaluate(() => chrome.runtime.reload()).catch(() => {
13795
+ });
13796
+ return { ok: true, extensionId: id };
13797
+ }
13798
+ async function summarizeBrowser(context, { clickupTaskId = "" } = {}) {
13799
+ const pages = context.pages();
13800
+ const pageSummaries = [];
13801
+ for (let index = 0; index < pages.length; index += 1) {
13802
+ const page = pages[index];
13803
+ pageSummaries.push({
13804
+ index,
13805
+ role: index === 0 ? "persistent_session_tab" : await safePageWindowName(page) === qaWindowName(clickupTaskId) ? "qa_task_tab" : "other",
13806
+ url: page.url(),
13807
+ title: await page.title().catch(() => "")
13808
+ });
13809
+ }
13810
+ const workers = context.serviceWorkers ? context.serviceWorkers().map((worker) => worker.url()) : [];
13811
+ return { pages: pageSummaries, serviceWorkers: workers };
13812
+ }
13813
+ function parseQaCommand(commandJson = "") {
13814
+ if (!String(commandJson || "").trim()) return { action: "status" };
13815
+ try {
13816
+ const parsed = JSON.parse(commandJson);
13817
+ return parsed && typeof parsed === "object" ? parsed : { action: "invalid", error: "command_json_must_be_object" };
13818
+ } catch (error) {
13819
+ return { action: "script", script: String(commandJson || "") };
13820
+ }
13821
+ }
13822
+ async function runQaCommandOnPage(page, context, browser, command, { artifactsDir }) {
13823
+ const action = String(command.action || "status").trim().toLowerCase();
13824
+ if (action === "status") return { ok: true, page: { url: page.url(), title: await page.title().catch(() => "") } };
13825
+ if (action === "goto") {
13826
+ await page.goto(String(command.url || "https://chatgpt.com/"), { waitUntil: command.wait_until || "domcontentloaded", timeout: Number(command.timeout_ms || 3e4) });
13827
+ return { ok: true, url: page.url(), title: await page.title().catch(() => "") };
13828
+ }
13829
+ if (action === "evaluate") {
13830
+ const result = await page.evaluate(String(command.expression || "() => null"));
13831
+ return { ok: true, result };
13832
+ }
13833
+ if (action === "screenshot") {
13834
+ const name = String(command.name || `screenshot-${Date.now()}.png`).replace(/[^a-zA-Z0-9._-]+/g, "-");
13835
+ const outPath = path17.join(artifactsDir, name);
13836
+ fs16.mkdirSync(path17.dirname(outPath), { recursive: true });
13837
+ await page.screenshot({ path: outPath, fullPage: command.full_page !== false });
13838
+ return { ok: true, path: outPath };
13839
+ }
13840
+ if (action === "set_input_files") {
13841
+ const selector = String(command.selector || "input[type=file]");
13842
+ await page.setInputFiles(selector, command.files);
13843
+ return { ok: true, selector };
13844
+ }
13845
+ if (action === "script") {
13846
+ const script = String(command.script || "");
13847
+ if (!script.trim()) return { ok: false, error: "script_required" };
13848
+ const fn = new Function("page", "context", "browser", "artifactsDir", `return (async () => {
13849
+ ${script}
13850
+ })()`);
13851
+ const result = await fn(page, context, browser, artifactsDir);
13852
+ return { ok: true, result };
13853
+ }
13854
+ return { ok: false, error: `unsupported_qa_command_action: ${action}` };
13855
+ }
13856
+ async function withQaBrowser({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "", clickupTaskId = "", startUrl = "https://chatgpt.com/" } = {}, callback) {
13857
+ const chromium = await loadPlaywrightChromium();
13858
+ const browser = await chromium.connectOverCDP(normalizeCdpUrl(cdpUrl));
13859
+ try {
13860
+ const context = browser.contexts()[0] || await browser.newContext();
13861
+ const page = clickupTaskId ? await ensureQaPage(context, { clickupTaskId, startUrl }) : null;
13862
+ return await callback({ browser, context, page });
13863
+ } finally {
13864
+ await browser.close().catch(() => {
13865
+ });
13866
+ }
13867
+ }
13868
+ async function qaBrowserStatus(options = {}) {
13869
+ return withQaBrowser(options, async ({ context }) => ({ ok: true, ...await summarizeBrowser(context, { clickupTaskId: options.clickupTaskId }) })).catch((error) => ({ ok: false, error: error.message, cdpUrl: normalizeCdpUrl(options.cdpUrl) }));
13870
+ }
13871
+ async function qaPrepareExtension({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "", extensionPath = "", extensionId = "", reset = true, reload = true } = {}) {
13872
+ const stageDir = defaultQaExtensionStageDir(provider);
13873
+ const sync = copyExtensionSource(extensionPath, stageDir);
13874
+ const browserResult = await withQaBrowser({ provider, cdpUrl }, async ({ context }) => {
13875
+ const resetResult = reset ? await resetExtensionState(context, { extensionId }).catch((error) => ({ ok: false, error: error.message })) : { ok: true, skipped: true };
13876
+ const reloadResult = reload ? await reloadExtension(context, { extensionId }).catch((error) => ({ ok: false, error: error.message })) : { ok: true, skipped: true };
13877
+ return { reset: resetResult, reload: reloadResult, browser: await summarizeBrowser(context) };
13878
+ }).catch((error) => ({ ok: false, error: error.message }));
13879
+ return { sync, ...browserResult };
13880
+ }
13881
+ async function qaRunChromeCommand({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "", clickupTaskId = "", commandJson = "", startUrl = "https://chatgpt.com/" } = {}) {
13882
+ const command = parseQaCommand(commandJson);
13883
+ const artifactsDir = defaultQaArtifactsDir(provider, clickupTaskId);
13884
+ return withQaBrowser({ provider, cdpUrl, clickupTaskId, startUrl }, async ({ browser, context, page }) => {
13885
+ const result = await runQaCommandOnPage(page, context, browser, command, { artifactsDir });
13886
+ return { ok: result.ok !== false, command: command.action || "script", tab: { windowName: qaWindowName(clickupTaskId), url: page.url(), title: await page.title().catch(() => "") }, artifactsDir, result };
13887
+ });
13888
+ }
13889
+
13509
13890
  // src/repair.js
13510
13891
  var import_yaml4 = __toESM(require_dist(), 1);
13511
13892
  var import_ignore = __toESM(require_ignore(), 1);
13512
- import fs15 from "node:fs";
13513
- import path16 from "node:path";
13893
+ import fs17 from "node:fs";
13894
+ import path18 from "node:path";
13514
13895
  var CODEMAP_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
13515
13896
  ".js",
13516
13897
  ".ts",
@@ -13548,10 +13929,10 @@ var LEGACY_OPERATIONAL_ROOTS = /* @__PURE__ */ new Set([
13548
13929
  ]);
13549
13930
  var OPTIMA_OPERATIONAL_FOLDERS = [".optima", "templates", "dist"];
13550
13931
  function relPath(worktree, targetPath) {
13551
- return path16.relative(worktree, targetPath).split(path16.sep).join("/") || ".";
13932
+ return path18.relative(worktree, targetPath).split(path18.sep).join("/") || ".";
13552
13933
  }
13553
13934
  function normalizeCodemapRelPath(relPathValue) {
13554
- return path16.normalize(relPathValue).replace(/\\/g, "/").replace(/\/$/, "");
13935
+ return path18.normalize(relPathValue).replace(/\\/g, "/").replace(/\/$/, "");
13555
13936
  }
13556
13937
  function firstPathSegment(relPathValue) {
13557
13938
  return normalizeCodemapRelPath(relPathValue).split("/").filter(Boolean)[0] || "";
@@ -13570,8 +13951,8 @@ function isHiddenTree(relPathValue) {
13570
13951
  function loadGitIgnoreMatcher(worktree) {
13571
13952
  const ig = (0, import_ignore.default)();
13572
13953
  ig.add(".git");
13573
- const gitignorePath = path16.join(worktree, ".gitignore");
13574
- if (fs15.existsSync(gitignorePath)) ig.add(fs15.readFileSync(gitignorePath, "utf8"));
13954
+ const gitignorePath = path18.join(worktree, ".gitignore");
13955
+ if (fs17.existsSync(gitignorePath)) ig.add(fs17.readFileSync(gitignorePath, "utf8"));
13575
13956
  return ig;
13576
13957
  }
13577
13958
  function codemapSectionEntries(value) {
@@ -13590,7 +13971,7 @@ function codemapIndexedPaths(map) {
13590
13971
  }
13591
13972
  function readCodemap(filePath, unresolved, worktree) {
13592
13973
  try {
13593
- const parsed = import_yaml4.default.parse(fs15.readFileSync(filePath, "utf8"));
13974
+ const parsed = import_yaml4.default.parse(fs17.readFileSync(filePath, "utf8"));
13594
13975
  if (!parsed || typeof parsed !== "object") {
13595
13976
  unresolved.push({ category: "codemap", path: relPath(worktree, filePath), message: "CodeMap is empty or invalid; manual repair required." });
13596
13977
  return null;
@@ -13602,42 +13983,42 @@ function readCodemap(filePath, unresolved, worktree) {
13602
13983
  }
13603
13984
  }
13604
13985
  function writeCodemap(filePath, map) {
13605
- fs15.writeFileSync(filePath, import_yaml4.default.stringify(map), "utf8");
13986
+ fs17.writeFileSync(filePath, import_yaml4.default.stringify(map), "utf8");
13606
13987
  }
13607
13988
  function isIgnoredPath(ig, relativePath) {
13608
13989
  const normalized = normalizeCodemapRelPath(relativePath);
13609
13990
  return Boolean(normalized) && ig.ignores(normalized);
13610
13991
  }
13611
13992
  function hasImmediateSourceFile(dirPath, ig, worktree) {
13612
- if (!fs15.existsSync(dirPath)) return false;
13613
- for (const item of fs15.readdirSync(dirPath, { withFileTypes: true })) {
13614
- const childPath = path16.join(dirPath, item.name);
13615
- const relative = path16.relative(worktree, childPath);
13993
+ if (!fs17.existsSync(dirPath)) return false;
13994
+ for (const item of fs17.readdirSync(dirPath, { withFileTypes: true })) {
13995
+ const childPath = path18.join(dirPath, item.name);
13996
+ const relative = path18.relative(worktree, childPath);
13616
13997
  if (isIgnoredPath(ig, relative) || isOperationalRelPath(relative)) continue;
13617
- if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(path16.extname(item.name))) return true;
13998
+ if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(path18.extname(item.name))) return true;
13618
13999
  }
13619
14000
  return false;
13620
14001
  }
13621
14002
  function containsSource(dirPath, ig, worktree) {
13622
- if (!fs15.existsSync(dirPath)) return false;
13623
- const dirRelPath = path16.relative(worktree, dirPath);
14003
+ if (!fs17.existsSync(dirPath)) return false;
14004
+ const dirRelPath = path18.relative(worktree, dirPath);
13624
14005
  if (isOperationalRelPath(dirRelPath) || isHiddenTree(dirRelPath)) return false;
13625
- for (const item of fs15.readdirSync(dirPath, { withFileTypes: true })) {
13626
- const childPath = path16.join(dirPath, item.name);
13627
- const relative = path16.relative(worktree, childPath);
14006
+ for (const item of fs17.readdirSync(dirPath, { withFileTypes: true })) {
14007
+ const childPath = path18.join(dirPath, item.name);
14008
+ const relative = path18.relative(worktree, childPath);
13628
14009
  if (isIgnoredPath(ig, relative) || isOperationalRelPath(relative) || isHiddenTree(relative)) continue;
13629
- if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(path16.extname(item.name))) return true;
14010
+ if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(path18.extname(item.name))) return true;
13630
14011
  if (item.isDirectory() && containsSource(childPath, ig, worktree)) return true;
13631
14012
  }
13632
14013
  return false;
13633
14014
  }
13634
14015
  function createModuleCodemap(dirPath, worktree, deps) {
13635
- const entries = fs15.readdirSync(dirPath, { withFileTypes: true });
14016
+ const entries = fs17.readdirSync(dirPath, { withFileTypes: true });
13636
14017
  const entrypoints = [];
13637
14018
  const internals = [];
13638
- const relToRoot = path16.relative(dirPath, deps.optimaCodemapPath(worktree)).split(path16.sep).join("/");
14019
+ const relToRoot = path18.relative(dirPath, deps.optimaCodemapPath(worktree)).split(path18.sep).join("/");
13639
14020
  for (const item of entries) {
13640
- if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(path16.extname(item.name))) continue;
14021
+ if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(path18.extname(item.name))) continue;
13641
14022
  const bucket = /^index\.(js|ts|tsx|jsx)$|^main\.(js|ts|tsx|jsx|py|go|rs|java)$/.test(item.name) ? entrypoints : internals;
13642
14023
  bucket.push({ path: item.name });
13643
14024
  }
@@ -13650,7 +14031,7 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
13650
14031
  const map = readCodemap(codemapPath, unresolved, worktree);
13651
14032
  if (!map) return;
13652
14033
  const isRootMap = codemapPath === deps.optimaCodemapPath(worktree);
13653
- const mapDir = path16.dirname(codemapPath);
14034
+ const mapDir = path18.dirname(codemapPath);
13654
14035
  const pathBase = isRootMap ? worktree : mapDir;
13655
14036
  let changed = false;
13656
14037
  for (const section of ["modules", "entrypoints", "sources_of_truth", "links", "internals"]) {
@@ -13661,13 +14042,13 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
13661
14042
  }
13662
14043
  const nextEntries = [];
13663
14044
  for (const entry of originalEntries) {
13664
- if (!entry?.path || entry.path.startsWith("http://") || entry.path.startsWith("https://") || path16.isAbsolute(entry.path)) {
14045
+ if (!entry?.path || entry.path.startsWith("http://") || entry.path.startsWith("https://") || path18.isAbsolute(entry.path)) {
13665
14046
  nextEntries.push(entry);
13666
14047
  continue;
13667
14048
  }
13668
14049
  const normalizedPath = normalizeCodemapRelPath(entry.path);
13669
- const absPath = path16.join(pathBase, normalizedPath);
13670
- if (!fs15.existsSync(absPath)) {
14050
+ const absPath = path18.join(pathBase, normalizedPath);
14051
+ if (!fs17.existsSync(absPath)) {
13671
14052
  registerAction({ category: "codemap", action: apply ? "removed" : "would_remove", path: relPath(worktree, codemapPath), detail: `Remove broken ${section.slice(0, -1)} reference '${entry.path}'.` });
13672
14053
  changed = true;
13673
14054
  continue;
@@ -13676,8 +14057,8 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
13676
14057
  const maxParts = isRootMap ? 2 : 1;
13677
14058
  if (parts.length > maxParts) {
13678
14059
  const localPath = isRootMap ? parts.slice(0, 2).join("/") : parts[0];
13679
- const localAbs = path16.join(pathBase, localPath);
13680
- if (fs15.existsSync(localAbs)) {
14060
+ const localAbs = path18.join(pathBase, localPath);
14061
+ if (fs17.existsSync(localAbs)) {
13681
14062
  nextEntries.push({ ...entry, path: localPath });
13682
14063
  changed = true;
13683
14064
  registerAction({ category: "codemap", action: apply ? "updated" : "would_update", path: relPath(worktree, codemapPath), detail: `Shorten '${entry.path}' to local path '${localPath}'.` });
@@ -13691,11 +14072,11 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
13691
14072
  }
13692
14073
  if (Array.isArray(map[section])) map[section] = nextEntries;
13693
14074
  }
13694
- if (map.scope === "module" && !isOperationalRelPath(path16.relative(worktree, mapDir))) {
14075
+ if (map.scope === "module" && !isOperationalRelPath(path18.relative(worktree, mapDir))) {
13695
14076
  const indexed = codemapIndexedPaths(map);
13696
14077
  const internals = Array.isArray(map.internals) ? map.internals : [];
13697
- for (const item of fs15.readdirSync(mapDir, { withFileTypes: true })) {
13698
- if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(path16.extname(item.name))) continue;
14078
+ for (const item of fs17.readdirSync(mapDir, { withFileTypes: true })) {
14079
+ if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(path18.extname(item.name))) continue;
13699
14080
  if (indexed.has(item.name)) continue;
13700
14081
  internals.push({ path: item.name });
13701
14082
  indexed.add(item.name);
@@ -13709,13 +14090,13 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
13709
14090
  function repairCodemaps(worktree, apply, actions, unresolved, deps) {
13710
14091
  const ig = loadGitIgnoreMatcher(worktree);
13711
14092
  const rootCodemapPath = deps.optimaCodemapPath(worktree);
13712
- const rootCodemapMissing = !fs15.existsSync(rootCodemapPath);
14093
+ const rootCodemapMissing = !fs17.existsSync(rootCodemapPath);
13713
14094
  if (rootCodemapMissing) {
13714
14095
  actions.push({ category: "codemap", action: apply ? "created" : "would_create", path: ".optima/codemap.yml", detail: "Create missing root CodeMap from template." });
13715
14096
  if (apply) deps.scaffoldOptimaRootCodemap(worktree);
13716
14097
  }
13717
- if (fs15.existsSync(rootCodemapPath)) repairSingleCodemap(rootCodemapPath, worktree, apply, (action) => actions.push(action), unresolved, deps);
13718
- const rootMap = fs15.existsSync(rootCodemapPath) ? readCodemap(rootCodemapPath, unresolved, worktree) : null;
14098
+ if (fs17.existsSync(rootCodemapPath)) repairSingleCodemap(rootCodemapPath, worktree, apply, (action) => actions.push(action), unresolved, deps);
14099
+ const rootMap = fs17.existsSync(rootCodemapPath) ? readCodemap(rootCodemapPath, unresolved, worktree) : null;
13719
14100
  let rootChanged = false;
13720
14101
  const rootModulesRepairable = rootMap && (rootMap.modules === void 0 || Array.isArray(rootMap.modules));
13721
14102
  if (rootMap) {
@@ -13727,10 +14108,10 @@ function repairCodemaps(worktree, apply, actions, unresolved, deps) {
13727
14108
  }
13728
14109
  }
13729
14110
  function walk(dirPath) {
13730
- const relative = path16.relative(worktree, dirPath);
14111
+ const relative = path18.relative(worktree, dirPath);
13731
14112
  if (relative && (isIgnoredPath(ig, relative) || isOperationalRelPath(relative) || isHiddenTree(relative))) return;
13732
- const codemapPath = path16.join(dirPath, "codemap.yml");
13733
- const hasCodemap = fs15.existsSync(codemapPath);
14113
+ const codemapPath = path18.join(dirPath, "codemap.yml");
14114
+ const hasCodemap = fs17.existsSync(codemapPath);
13734
14115
  const sourceDir = relative && containsSource(dirPath, ig, worktree);
13735
14116
  if (sourceDir && !hasCodemap && dirPath !== worktree) {
13736
14117
  if (hasImmediateSourceFile(dirPath, ig, worktree)) {
@@ -13749,19 +14130,19 @@ function repairCodemaps(worktree, apply, actions, unresolved, deps) {
13749
14130
  actions.push({ category: "codemap", action: apply ? "updated" : "would_update", path: ".optima/codemap.yml", detail: `Register top-level source module '${normalizeCodemapRelPath(relative)}'.` });
13750
14131
  }
13751
14132
  }
13752
- if (fs15.existsSync(codemapPath) && codemapPath !== rootCodemapPath) repairSingleCodemap(codemapPath, worktree, apply, (action) => actions.push(action), unresolved, deps);
13753
- for (const item of fs15.readdirSync(dirPath, { withFileTypes: true })) {
13754
- if (item.isDirectory()) walk(path16.join(dirPath, item.name));
14133
+ if (fs17.existsSync(codemapPath) && codemapPath !== rootCodemapPath) repairSingleCodemap(codemapPath, worktree, apply, (action) => actions.push(action), unresolved, deps);
14134
+ for (const item of fs17.readdirSync(dirPath, { withFileTypes: true })) {
14135
+ if (item.isDirectory()) walk(path18.join(dirPath, item.name));
13755
14136
  }
13756
14137
  }
13757
- if (fs15.existsSync(worktree)) walk(worktree);
14138
+ if (fs17.existsSync(worktree)) walk(worktree);
13758
14139
  if (rootMap && rootChanged && apply) writeCodemap(rootCodemapPath, rootMap);
13759
14140
  }
13760
14141
  function walkMarkdownFiles(dirPath) {
13761
- if (!fs15.existsSync(dirPath)) return [];
14142
+ if (!fs17.existsSync(dirPath)) return [];
13762
14143
  const files = [];
13763
- for (const entry of fs15.readdirSync(dirPath, { withFileTypes: true })) {
13764
- const entryPath = path16.join(dirPath, entry.name);
14144
+ for (const entry of fs17.readdirSync(dirPath, { withFileTypes: true })) {
14145
+ const entryPath = path18.join(dirPath, entry.name);
13765
14146
  if (entry.isDirectory()) {
13766
14147
  files.push(...walkMarkdownFiles(entryPath));
13767
14148
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -13800,7 +14181,7 @@ function rewriteOptimaMarkdownReferences(content, evidenceBasePath = null) {
13800
14181
  }
13801
14182
  function optimaEvidenceBaseForFile(worktree, filePath, deps) {
13802
14183
  const evidenceRoot = deps.optimaEvidencesDir(worktree);
13803
- const relative = path16.relative(evidenceRoot, filePath).split(path16.sep).join("/");
14184
+ const relative = path18.relative(evidenceRoot, filePath).split(path18.sep).join("/");
13804
14185
  const [taskId] = relative.split("/");
13805
14186
  if (!taskId || taskId === ".." || relative.startsWith("../")) return null;
13806
14187
  return `.optima/evidences/${taskId}`;
@@ -13813,11 +14194,11 @@ function normalizeOptimaMarkdownReferences(worktree, deps) {
13813
14194
  ];
13814
14195
  const changed = [];
13815
14196
  for (const filePath of scanRoots.flatMap(walkMarkdownFiles)) {
13816
- const raw = fs15.readFileSync(filePath, "utf8");
13817
- const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) + path16.sep) ? optimaEvidenceBaseForFile(worktree, filePath, deps) : null;
14197
+ const raw = fs17.readFileSync(filePath, "utf8");
14198
+ const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) + path18.sep) ? optimaEvidenceBaseForFile(worktree, filePath, deps) : null;
13818
14199
  const rewritten = rewriteOptimaMarkdownReferences(raw, evidenceBasePath);
13819
14200
  if (rewritten !== raw) {
13820
- fs15.writeFileSync(filePath, rewritten, "utf8");
14201
+ fs17.writeFileSync(filePath, rewritten, "utf8");
13821
14202
  changed.push(relPath(worktree, filePath));
13822
14203
  }
13823
14204
  }
@@ -13825,8 +14206,8 @@ function normalizeOptimaMarkdownReferences(worktree, deps) {
13825
14206
  }
13826
14207
  function missingOptimaGitignoreRules(worktree, deps) {
13827
14208
  if (!deps.isGitRepository(worktree)) return [];
13828
- const gitignorePath = path16.join(worktree, ".gitignore");
13829
- const existing = fs15.existsSync(gitignorePath) ? fs15.readFileSync(gitignorePath, "utf8") : "";
14209
+ const gitignorePath = path18.join(worktree, ".gitignore");
14210
+ const existing = fs17.existsSync(gitignorePath) ? fs17.readFileSync(gitignorePath, "utf8") : "";
13830
14211
  const existingRules = new Set(existing.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
13831
14212
  return deps.optimaGitignoreRules.filter((rule) => !existingRules.has(rule));
13832
14213
  }
@@ -13843,11 +14224,11 @@ function planOptimaRepair(worktree, args = {}, deps) {
13843
14224
  const apply = mode === "apply";
13844
14225
  const actions = [];
13845
14226
  const unresolved = [];
13846
- const hadOptima = fs15.existsSync(deps.optimaDir(worktree));
14227
+ const hadOptima = fs17.existsSync(deps.optimaDir(worktree));
13847
14228
  const missingGitignoreRules = missingOptimaGitignoreRules(worktree, deps);
13848
14229
  const markdownBefore = apply ? [] : walkMarkdownFiles(deps.optimaDir(worktree)).filter((filePath) => {
13849
- const raw = fs15.readFileSync(filePath, "utf8");
13850
- const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) + path16.sep) ? optimaEvidenceBaseForFile(worktree, filePath, deps) : null;
14230
+ const raw = fs17.readFileSync(filePath, "utf8");
14231
+ const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) + path18.sep) ? optimaEvidenceBaseForFile(worktree, filePath, deps) : null;
13851
14232
  return rewriteOptimaMarkdownReferences(raw, evidenceBasePath) !== raw;
13852
14233
  }).map((filePath) => relPath(worktree, filePath));
13853
14234
  if (!hadOptima) pushRepairAction(actions, "operational", apply ? "created" : "would_create", ".optima/", "Create Optima operational root.");
@@ -13856,31 +14237,31 @@ function planOptimaRepair(worktree, args = {}, deps) {
13856
14237
  [".staticeng/", deps.legacyStaticEngDir(worktree)],
13857
14238
  [".nomadwork/", deps.legacyNomadworkDir(worktree)],
13858
14239
  [".nomadworks/", deps.legacyNomadworksDir(worktree)],
13859
- ["tasks/", path16.join(worktree, "tasks")],
13860
- ["evidences/", path16.join(worktree, "evidences")],
13861
- ["docs/scrs/", path16.join(worktree, "docs", "scrs")],
13862
- ["codemap.yml", path16.join(worktree, "codemap.yml")],
13863
- ["codemap.yaml", path16.join(worktree, "codemap.yaml")]
14240
+ ["tasks/", path18.join(worktree, "tasks")],
14241
+ ["evidences/", path18.join(worktree, "evidences")],
14242
+ ["docs/scrs/", path18.join(worktree, "docs", "scrs")],
14243
+ ["codemap.yml", path18.join(worktree, "codemap.yml")],
14244
+ ["codemap.yaml", path18.join(worktree, "codemap.yaml")]
13864
14245
  ];
13865
- if (!deps.isOptimaPluginPackageWorktree(worktree)) legacySources.push(["policies/", path16.join(worktree, "policies")]);
14246
+ if (!deps.isOptimaPluginPackageWorktree(worktree)) legacySources.push(["policies/", path18.join(worktree, "policies")]);
13866
14247
  for (const [display, sourcePath] of legacySources) {
13867
- if (fs15.existsSync(sourcePath)) pushRepairAction(actions, "legacy", apply ? "migrated" : "would_migrate", display, "Move or merge legacy/root Optima artifact into .optima using preservation safeguards.");
14248
+ if (fs17.existsSync(sourcePath)) pushRepairAction(actions, "legacy", apply ? "migrated" : "would_migrate", display, "Move or merge legacy/root Optima artifact into .optima using preservation safeguards.");
13868
14249
  }
13869
14250
  if (apply) deps.migrateLegacyOptimaLayout(worktree);
13870
- const configMissing = !fs15.existsSync(deps.repoConfigPath(worktree));
14251
+ const configMissing = !fs17.existsSync(deps.repoConfigPath(worktree));
13871
14252
  if (configMissing) pushRepairAction(actions, "config", apply ? "created" : "would_create", ".optima/.config/optima.yaml", "Create missing local Optima config from template.");
13872
14253
  if (apply) deps.scaffoldOptimaConfig(worktree, args.team_mode || "full");
13873
14254
  const requiredFiles = [
13874
- [path16.join(deps.optimaTasksDir(worktree), "current.md"), "registry", ".optima/tasks/current.md", deps.currentTasksRegistryContent()],
13875
- [path16.join(deps.optimaTasksDir(worktree), "done.md"), "registry", ".optima/tasks/done.md", deps.doneTasksRegistryContent()],
13876
- [path16.join(deps.optimaScrsDir(worktree), "current.md"), "registry", ".optima/docs/scrs/current.md", deps.currentScrRegistryContent()],
13877
- [path16.join(deps.optimaScrsDir(worktree), "done.md"), "registry", ".optima/docs/scrs/done.md", deps.doneScrRegistryContent()],
13878
- [path16.join(deps.optimaTasksDir(worktree), "task-template.md"), "template", ".optima/tasks/task-template.md", deps.taskTemplateContent()],
13879
- [path16.join(deps.optimaTasksDir(worktree), "subtask-template.md"), "template", ".optima/tasks/subtask-template.md", deps.subtaskTemplateContent()],
13880
- [path16.join(deps.repoPoliciesDir(worktree), "README.md"), "policy", ".optima/policies/README.md", deps.repoLocalPoliciesReadme]
14255
+ [path18.join(deps.optimaTasksDir(worktree), "current.md"), "registry", ".optima/tasks/current.md", deps.currentTasksRegistryContent()],
14256
+ [path18.join(deps.optimaTasksDir(worktree), "done.md"), "registry", ".optima/tasks/done.md", deps.doneTasksRegistryContent()],
14257
+ [path18.join(deps.optimaScrsDir(worktree), "current.md"), "registry", ".optima/docs/scrs/current.md", deps.currentScrRegistryContent()],
14258
+ [path18.join(deps.optimaScrsDir(worktree), "done.md"), "registry", ".optima/docs/scrs/done.md", deps.doneScrRegistryContent()],
14259
+ [path18.join(deps.optimaTasksDir(worktree), "task-template.md"), "template", ".optima/tasks/task-template.md", deps.taskTemplateContent()],
14260
+ [path18.join(deps.optimaTasksDir(worktree), "subtask-template.md"), "template", ".optima/tasks/subtask-template.md", deps.subtaskTemplateContent()],
14261
+ [path18.join(deps.repoPoliciesDir(worktree), "README.md"), "policy", ".optima/policies/README.md", deps.repoLocalPoliciesReadme]
13881
14262
  ];
13882
14263
  for (const [filePath, category, displayPath, content] of requiredFiles) {
13883
- if (!fs15.existsSync(filePath)) {
14264
+ if (!fs17.existsSync(filePath)) {
13884
14265
  pushRepairAction(actions, category, apply ? "created" : "would_create", displayPath, "Create missing Optima scaffold file without overwriting existing content.");
13885
14266
  if (apply) deps.ensureFileIfMissing(filePath, content);
13886
14267
  }
@@ -13934,18 +14315,18 @@ function formatRepairResult(plan, validationResult = null, formatValidationResul
13934
14315
  // src/validate_logic.js
13935
14316
  var import_yaml5 = __toESM(require_dist(), 1);
13936
14317
  var import_ignore2 = __toESM(require_ignore(), 1);
13937
- import fs16 from "node:fs";
13938
- import path17 from "node:path";
14318
+ import fs18 from "node:fs";
14319
+ import path19 from "node:path";
13939
14320
  async function optima_validate_logic(worktree) {
13940
- const rootCodemapPath = path17.join(worktree, ".optima", "codemap.yml");
13941
- if (!fs16.existsSync(rootCodemapPath)) return { ok: false, errors: [".optima/codemap.yml not found."], warnings: [] };
14321
+ const rootCodemapPath = path19.join(worktree, ".optima", "codemap.yml");
14322
+ if (!fs18.existsSync(rootCodemapPath)) return { ok: false, errors: [".optima/codemap.yml not found."], warnings: [] };
13942
14323
  const errors = [];
13943
14324
  const warnings = [];
13944
14325
  const ig = (0, import_ignore2.default)();
13945
14326
  ig.add(".git");
13946
- const gitignorePath = path17.join(worktree, ".gitignore");
13947
- if (fs16.existsSync(gitignorePath)) {
13948
- ig.add(fs16.readFileSync(gitignorePath, "utf8"));
14327
+ const gitignorePath = path19.join(worktree, ".gitignore");
14328
+ if (fs18.existsSync(gitignorePath)) {
14329
+ ig.add(fs18.readFileSync(gitignorePath, "utf8"));
13949
14330
  }
13950
14331
  const sourceExtensions = [
13951
14332
  ".js",
@@ -13985,30 +14366,30 @@ async function optima_validate_logic(worktree) {
13985
14366
  const operationalFolders = [".optima", "templates", "dist"];
13986
14367
  const isHiddenTree2 = (relPath2) => {
13987
14368
  if (!relPath2) return false;
13988
- return relPath2.split(path17.sep).some((part) => part.startsWith("."));
14369
+ return relPath2.split(path19.sep).some((part) => part.startsWith("."));
13989
14370
  };
13990
- const firstPathSegment2 = (relPath2) => relPath2.split(path17.sep).filter(Boolean)[0] || "";
14371
+ const firstPathSegment2 = (relPath2) => relPath2.split(path19.sep).filter(Boolean)[0] || "";
13991
14372
  const isOperationalRelPath2 = (relPath2) => {
13992
14373
  if (!relPath2) return false;
13993
14374
  const firstSegment = firstPathSegment2(relPath2);
13994
14375
  if (legacyOperationalRoots.has(firstSegment)) return true;
13995
- return operationalFolders.some((f) => relPath2 === f || relPath2.startsWith(f + path17.sep));
14376
+ return operationalFolders.some((f) => relPath2 === f || relPath2.startsWith(f + path19.sep));
13996
14377
  };
13997
14378
  const getSectionEntries = (value) => {
13998
14379
  if (Array.isArray(value)) return value;
13999
14380
  if (value && typeof value === "object") return Object.values(value);
14000
14381
  return [];
14001
14382
  };
14002
- const normalizeRelativePath = (relPath2) => path17.normalize(relPath2).replace(/\\/g, "/").replace(/\/$/, "");
14383
+ const normalizeRelativePath = (relPath2) => path19.normalize(relPath2).replace(/\\/g, "/").replace(/\/$/, "");
14003
14384
  const isSourceDir = (dirPath) => {
14004
- const dirRelPath = path17.relative(worktree, dirPath);
14385
+ const dirRelPath = path19.relative(worktree, dirPath);
14005
14386
  if (isOperationalRelPath2(dirRelPath)) return false;
14006
- const items = fs16.readdirSync(dirPath, { withFileTypes: true });
14387
+ const items = fs18.readdirSync(dirPath, { withFileTypes: true });
14007
14388
  for (const item of items) {
14008
- const childPath = path17.join(dirPath, item.name);
14009
- const relPath2 = path17.relative(worktree, childPath);
14389
+ const childPath = path19.join(dirPath, item.name);
14390
+ const relPath2 = path19.relative(worktree, childPath);
14010
14391
  if (ig.ignores(relPath2) || isOperationalRelPath2(relPath2)) continue;
14011
- if (item.isFile() && sourceExtensions.includes(path17.extname(item.name))) return true;
14392
+ if (item.isFile() && sourceExtensions.includes(path19.extname(item.name))) return true;
14012
14393
  if (item.isDirectory()) {
14013
14394
  if (isSourceDir(childPath)) return true;
14014
14395
  }
@@ -14016,7 +14397,7 @@ async function optima_validate_logic(worktree) {
14016
14397
  return false;
14017
14398
  };
14018
14399
  function validateMap(filePath) {
14019
- const content = fs16.readFileSync(filePath, "utf8");
14400
+ const content = fs18.readFileSync(filePath, "utf8");
14020
14401
  let map;
14021
14402
  try {
14022
14403
  map = import_yaml5.default.parse(content);
@@ -14028,32 +14409,32 @@ async function optima_validate_logic(worktree) {
14028
14409
  errors.push(`${filePath}: Invalid YAML.`);
14029
14410
  return;
14030
14411
  }
14031
- const dir = path17.dirname(filePath);
14412
+ const dir = path19.dirname(filePath);
14032
14413
  const pathBase = filePath === rootCodemapPath ? worktree : dir;
14033
14414
  const indexedPaths = /* @__PURE__ */ new Set();
14034
14415
  const sectionsToVerify = ["modules", "entrypoints", "sources_of_truth", "links", "internals"];
14035
14416
  for (const section of sectionsToVerify) {
14036
14417
  for (const item of getSectionEntries(map[section])) {
14037
14418
  if (item?.path) {
14038
- indexedPaths.add(path17.normalize(item.path));
14419
+ indexedPaths.add(path19.normalize(item.path));
14039
14420
  if (section === "links" && (item.path.startsWith("http://") || item.path.startsWith("https://"))) {
14040
14421
  continue;
14041
14422
  }
14042
- const absPath = path17.isAbsolute(item.path) ? item.path : path17.join(pathBase, item.path);
14043
- if (!fs16.existsSync(absPath)) {
14423
+ const absPath = path19.isAbsolute(item.path) ? item.path : path19.join(pathBase, item.path);
14424
+ if (!fs18.existsSync(absPath)) {
14044
14425
  errors.push(`${filePath}: ${section.slice(0, -1)} path does not exist: ${item.path}`);
14045
14426
  }
14046
14427
  }
14047
14428
  }
14048
14429
  }
14049
- const relDir = path17.relative(worktree, dir);
14430
+ const relDir = path19.relative(worktree, dir);
14050
14431
  const isOperational = isOperationalRelPath2(relDir);
14051
14432
  if (map.scope === "module" && !isOperational) {
14052
- const items = fs16.readdirSync(dir, { withFileTypes: true });
14433
+ const items = fs18.readdirSync(dir, { withFileTypes: true });
14053
14434
  for (const item of items) {
14054
- if (item.isFile() && sourceExtensions.includes(path17.extname(item.name))) {
14435
+ if (item.isFile() && sourceExtensions.includes(path19.extname(item.name))) {
14055
14436
  if (item.name === "codemap.yml") continue;
14056
- if (!indexedPaths.has(path17.normalize(item.name))) {
14437
+ if (!indexedPaths.has(path19.normalize(item.name))) {
14057
14438
  errors.push(`${filePath}: Unindexed source file found: '${item.name}'. Every source file must be categorized in a section (e.g., 'internals').`);
14058
14439
  }
14059
14440
  }
@@ -14063,7 +14444,7 @@ async function optima_validate_logic(worktree) {
14063
14444
  for (const key of pathKeys) {
14064
14445
  for (const entry of getSectionEntries(map[key])) {
14065
14446
  if (!entry?.path || entry.path.startsWith("http://") || entry.path.startsWith("https://")) continue;
14066
- if (path17.isAbsolute(entry.path)) continue;
14447
+ if (path19.isAbsolute(entry.path)) continue;
14067
14448
  const normalizedPath = normalizeRelativePath(entry.path);
14068
14449
  if (!normalizedPath || normalizedPath === ".") continue;
14069
14450
  const parts = normalizedPath.split("/").filter((p) => p && p !== ".");
@@ -14075,18 +14456,18 @@ async function optima_validate_logic(worktree) {
14075
14456
  }
14076
14457
  }
14077
14458
  const walk = (dir) => {
14078
- const relDir = path17.relative(worktree, dir);
14459
+ const relDir = path19.relative(worktree, dir);
14079
14460
  if (relDir && ig.ignores(relDir)) return;
14080
14461
  if (isOperationalRelPath2(relDir)) return;
14081
14462
  if (isHiddenTree2(relDir)) return;
14082
- const hasCodemap = fs16.existsSync(path17.join(dir, "codemap.yml"));
14083
- const items = fs16.readdirSync(dir, { withFileTypes: true });
14084
- if (!relDir.startsWith(path17.join(".optima", "tasks", "done"))) {
14463
+ const hasCodemap = fs18.existsSync(path19.join(dir, "codemap.yml"));
14464
+ const items = fs18.readdirSync(dir, { withFileTypes: true });
14465
+ if (!relDir.startsWith(path19.join(".optima", "tasks", "done"))) {
14085
14466
  for (const item of items) {
14086
14467
  if (item.isFile() && item.name.endsWith(".md")) {
14087
- const content = fs16.readFileSync(path17.join(dir, item.name), "utf8");
14468
+ const content = fs18.readFileSync(path19.join(dir, item.name), "utf8");
14088
14469
  if (content.includes("[To be defined]") || content.includes("[Insert ")) {
14089
- const relFilePath = path17.join(relDir, item.name);
14470
+ const relFilePath = path19.join(relDir, item.name);
14090
14471
  errors.push(`Documentation Placeholder found: '${relFilePath}' still contains [To be defined] or [Insert ...] placeholders.`);
14091
14472
  }
14092
14473
  }
@@ -14096,9 +14477,9 @@ async function optima_validate_logic(worktree) {
14096
14477
  if (relDir !== "" && !hasCodemap && isSourceDir(dir) && !isOperational) {
14097
14478
  errors.push(`Missing CodeMap: Directory '${relDir}' contains source but has no codemap.yml.`);
14098
14479
  }
14099
- if (hasCodemap) validateMap(path17.join(dir, "codemap.yml"));
14480
+ if (hasCodemap) validateMap(path19.join(dir, "codemap.yml"));
14100
14481
  for (const item of items) {
14101
- if (item.isDirectory()) walk(path17.join(dir, item.name));
14482
+ if (item.isDirectory()) walk(path19.join(dir, item.name));
14102
14483
  }
14103
14484
  };
14104
14485
  validateMap(rootCodemapPath);
@@ -14112,12 +14493,13 @@ async function optima_validate_logic(worktree) {
14112
14493
 
14113
14494
  // src/plugin.js
14114
14495
  var activeWorkflows = /* @__PURE__ */ new Map();
14496
+ var activeQaQueueSchedulers = /* @__PURE__ */ new Map();
14115
14497
  function normalizeWorkflowTaskPath(taskPath) {
14116
14498
  if (typeof taskPath !== "string") return { ok: false, message: "Error: task_path is required." };
14117
14499
  const trimmed = taskPath.trim();
14118
14500
  if (!trimmed) return { ok: false, message: "Error: task_path is required." };
14119
14501
  const normalized = trimmed.replace(/\\/g, "/");
14120
- if (path18.isAbsolute(trimmed)) return { ok: true, taskPath: trimmed };
14502
+ if (path20.isAbsolute(trimmed)) return { ok: true, taskPath: trimmed };
14121
14503
  if (normalized === "tasks" || normalized.startsWith("tasks/")) {
14122
14504
  return {
14123
14505
  ok: false,
@@ -14134,10 +14516,10 @@ function normalizeWorkflowTaskPath(taskPath) {
14134
14516
  }
14135
14517
  function readTaskMetadata(taskPath, worktree) {
14136
14518
  if (!taskPath) return {};
14137
- const absoluteTaskPath = path18.isAbsolute(taskPath) ? taskPath : path18.join(worktree, taskPath);
14138
- if (!fs17.existsSync(absoluteTaskPath)) return {};
14519
+ const absoluteTaskPath = path20.isAbsolute(taskPath) ? taskPath : path20.join(worktree, taskPath);
14520
+ if (!fs19.existsSync(absoluteTaskPath)) return {};
14139
14521
  try {
14140
- const raw = fs17.readFileSync(absoluteTaskPath, "utf8");
14522
+ const raw = fs19.readFileSync(absoluteTaskPath, "utf8");
14141
14523
  const { data } = parseFrontmatter(raw);
14142
14524
  return {
14143
14525
  complexity: typeof data.complexity === "string" ? data.complexity.trim().toLowerCase() : void 0,
@@ -14160,15 +14542,15 @@ function hasActiveImplementationWorkflow() {
14160
14542
  function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktree, clickUpWebhookValidation } = {}) {
14161
14543
  const safe = safeWorktreeOrFailure(context, pluginWorktree);
14162
14544
  if (!safe.ok) return { ok: false, error: safe.message };
14163
- const requested = String(requestedDirectory || "").trim() ? path18.resolve(safe.worktree, String(requestedDirectory).trim()) : safe.worktree;
14545
+ const requested = String(requestedDirectory || "").trim() ? path20.resolve(safe.worktree, String(requestedDirectory).trim()) : safe.worktree;
14164
14546
  if (!isSafeWritableDirectory(requested)) return { ok: false, error: `Directory is not a safe writable directory: ${requested}` };
14165
14547
  if (isSameOrNestedPath(requested, safe.worktree)) return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "context_worktree" };
14166
14548
  const clickUpBasePath = clickUpWebhookValidation?.complete === true && clickUpWebhookValidation?.ok !== false ? clickUpWebhookValidation.config?.basePath : "";
14167
14549
  if (clickUpBasePath && isSameOrNestedPath(requested, clickUpBasePath)) {
14168
- return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path18.resolve(clickUpBasePath) };
14550
+ return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path20.resolve(clickUpBasePath) };
14169
14551
  }
14170
14552
  if (clickUpBasePath && isClickUpDerivedWorktreeSibling(requested, clickUpBasePath)) {
14171
- return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_derived_worktree", clickupBasePath: path18.resolve(clickUpBasePath) };
14553
+ return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_derived_worktree", clickupBasePath: path20.resolve(clickUpBasePath) };
14172
14554
  }
14173
14555
  return {
14174
14556
  ok: false,
@@ -14183,9 +14565,9 @@ async function OptimaPlugin(input = {}, pluginOptions = {}) {
14183
14565
  const configPath = resolveConfigPath(worktree);
14184
14566
  const discussionRegistry = loadDiscussionRegistry(worktree);
14185
14567
  let repoCfg = { agents: {}, defaults: {}, features: {} };
14186
- if (fs17.existsSync(configPath)) {
14568
+ if (fs19.existsSync(configPath)) {
14187
14569
  try {
14188
- repoCfg = import_yaml6.default.parse(fs17.readFileSync(configPath, "utf8")) || repoCfg;
14570
+ repoCfg = import_yaml6.default.parse(fs19.readFileSync(configPath, "utf8")) || repoCfg;
14189
14571
  } catch (e) {
14190
14572
  console.error(`[Optima] Failed to parse config at ${configPath}:`, e);
14191
14573
  }
@@ -14346,6 +14728,134 @@ Evidencia: ${evidencePath}` : ""
14346
14728
  applied
14347
14729
  };
14348
14730
  };
14731
+ const qaLeaseMs = Number(repoCfg.qa?.lease_ms || repoCfg.qa?.leaseMs || DEFAULT_QA_LEASE_MS) || DEFAULT_QA_LEASE_MS;
14732
+ const qaProvider = String(repoCfg.qa?.provider || DEFAULT_QA_PROVIDER);
14733
+ const qaCdpUrl = String(repoCfg.qa?.cdp_url || repoCfg.qa?.cdpUrl || process.env.OPTIMA_QA_CHROME_CDP_URL || "").trim();
14734
+ const qaTaskMetadata = async (taskId) => {
14735
+ if (!taskId || typeof runtimeClickUpClient?.getTask !== "function") return { task: null, metadata: {} };
14736
+ const task = await runtimeClickUpClient.getTask(taskId);
14737
+ const metadata = normalizeAgentMetadataJson(clickUpTaskAgentMetadata(task, clickUpWebhookValidation.config?.routing?.metadataFieldId));
14738
+ return { task, metadata };
14739
+ };
14740
+ const qaSessionFromMetadata = (metadata = {}) => {
14741
+ return metadata.optima?.sessions?.product_manager || metadata.task?.product_manager || metadata.sessions?.product_manager || "";
14742
+ };
14743
+ const qaWorktreeFromMetadata = (metadata = {}) => {
14744
+ return metadata.task?.worktree || metadata.worktree || "";
14745
+ };
14746
+ const applyQaQueuedClickUpState = async (taskId) => {
14747
+ const applied = [];
14748
+ const errors = [];
14749
+ const pmId = String(clickUpWebhookValidation.config?.routing?.productManagerAssigneeId || "").trim();
14750
+ if (!taskId || !clickUpWebhookValidation.complete || !runtimeClickUpClient) return { applied, errors };
14751
+ if (runtimeClickUpClient.updateTaskStatus) {
14752
+ try {
14753
+ await runtimeClickUpClient.updateTaskStatus({ taskId, status: "waiting QA slot" });
14754
+ applied.push("status:waiting QA slot");
14755
+ } catch (error) {
14756
+ errors.push(`status:${error.message}`);
14757
+ }
14758
+ }
14759
+ if (pmId && runtimeClickUpClient.updateTaskAssignees) {
14760
+ try {
14761
+ await runtimeClickUpClient.updateTaskAssignees({ taskId, remove: [pmId] });
14762
+ applied.push("remove_product_manager");
14763
+ } catch (error) {
14764
+ errors.push(`assignees:${error.message}`);
14765
+ }
14766
+ }
14767
+ return { applied, errors };
14768
+ };
14769
+ const wakePromotedQaTask = async (entry, { provider = qaProvider, reason = "qa_slot_available" } = {}) => {
14770
+ const taskId = String(entry?.clickupTaskId || "").trim();
14771
+ const applied = [];
14772
+ const errors = [];
14773
+ if (!taskId || !clickUpWebhookValidation.complete) return { ok: false, reason: "missing_task_or_clickup_config" };
14774
+ const pmId = String(clickUpWebhookValidation.config?.routing?.productManagerAssigneeId || "").trim();
14775
+ const humanIds = Object.values(clickUpWebhookValidation.config?.routing?.humanRoleClickUpIds || {}).map((id) => String(id || "").trim()).filter(Boolean);
14776
+ try {
14777
+ if (runtimeClickUpClient.updateTaskStatus) {
14778
+ await runtimeClickUpClient.updateTaskStatus({ taskId, status: "in progress" });
14779
+ applied.push("status:in progress");
14780
+ }
14781
+ } catch (error) {
14782
+ errors.push(`status:${error.message}`);
14783
+ }
14784
+ try {
14785
+ if (pmId && runtimeClickUpClient.updateTaskAssignees) {
14786
+ await runtimeClickUpClient.updateTaskAssignees({ taskId, add: [pmId], remove: humanIds });
14787
+ applied.push("assign_product_manager");
14788
+ }
14789
+ } catch (error) {
14790
+ errors.push(`assignees:${error.message}`);
14791
+ }
14792
+ let metadata = {};
14793
+ try {
14794
+ metadata = (await qaTaskMetadata(taskId)).metadata;
14795
+ } catch (error) {
14796
+ errors.push(`metadata:${error.message}`);
14797
+ }
14798
+ const sessionId = entry.sessionId || qaSessionFromMetadata(metadata);
14799
+ const directory = entry.worktree || qaWorktreeFromMetadata(metadata);
14800
+ if (sessionId && input.client && typeof sendOpenCodeSessionEvent === "function") {
14801
+ try {
14802
+ const prompt = [
14803
+ `[Optima QA Slot Granted]`,
14804
+ `Provider: ${provider}`,
14805
+ `ClickUp task: ${taskId}`,
14806
+ `Reason: ${reason}`,
14807
+ "",
14808
+ "Ya tienes plaza exclusiva para usar el Chrome QA. Debes llamar a `optima_qa_chrome_command` en menos de 5 minutos para conservar la plaza.",
14809
+ "Puedes conservarla mientras hagas al menos una llamada QA cada 5 minutos.",
14810
+ "Cuando termines, llama obligatoriamente a `optima_qa_finish` para resetear la extensi\xF3n y liberar la cola.",
14811
+ "La pesta\xF1a 0 es intocable: usa \xFAnicamente la pesta\xF1a QA que Optima crea para esta tarea."
14812
+ ].join("\n");
14813
+ await sendOpenCodeSessionEvent(input.client, {
14814
+ sessionId,
14815
+ agent: clickUpWebhookValidation.config.routing?.targetAgent || "workflow_product_manager",
14816
+ text: prompt,
14817
+ directory,
14818
+ opencodeBaseUrl: clickUpWebhookValidation.config.opencode?.baseUrl,
14819
+ fetchImpl: input.fetch,
14820
+ directDelivery: "steer"
14821
+ });
14822
+ applied.push("session_prompt");
14823
+ } catch (error) {
14824
+ errors.push(`session_prompt:${error.message}`);
14825
+ }
14826
+ } else {
14827
+ errors.push("session_prompt:missing_session_or_client");
14828
+ }
14829
+ return { ok: errors.length === 0, taskId, sessionId, directory, applied, errors };
14830
+ };
14831
+ const persistQaState = async (provider, state, transitions = {}) => {
14832
+ const written = writeQaQueueState(state, qaQueueStatePath(provider));
14833
+ const notifications = [];
14834
+ const promoted = transitions.promoted || null;
14835
+ if (promoted?.clickupTaskId) notifications.push(await wakePromotedQaTask(promoted, { provider, reason: transitions.reason || "qa_slot_available" }));
14836
+ return { state: written, notifications };
14837
+ };
14838
+ const scheduleQaQueueReaper = () => {
14839
+ if (input.startQaQueueScheduler === false) return;
14840
+ const provider = qaProvider || DEFAULT_QA_PROVIDER;
14841
+ const schedulerKey = `${provider}:${clickUpWebhookValidation.config?.basePath || worktree}`;
14842
+ if (activeQaQueueSchedulers.has(schedulerKey)) return;
14843
+ const interval = setInterval(async () => {
14844
+ try {
14845
+ const statePath = qaQueueStatePath(provider);
14846
+ const current = readQaQueueState(provider, statePath);
14847
+ const result = releaseExpiredQaSlot(current, { leaseMs: qaLeaseMs });
14848
+ if (result.expired || result.promoted) {
14849
+ await persistQaState(provider, result.state, { promoted: result.promoted, reason: result.expired ? "previous_slot_expired" : "qa_slot_available" });
14850
+ }
14851
+ } catch (error) {
14852
+ appendClickUpWebhookLocalLog(worktree, { type: "qa_queue_reaper_failed", provider, message: error.message });
14853
+ }
14854
+ }, Math.min(6e4, Math.max(1e4, Math.floor(qaLeaseMs / 5))));
14855
+ interval.unref?.();
14856
+ activeQaQueueSchedulers.set(schedulerKey, interval);
14857
+ };
14858
+ scheduleQaQueueReaper();
14349
14859
  const tools = {
14350
14860
  optima_init: tool({
14351
14861
  description: "Initialize the Optima workflow and CodeMap in the current repository",
@@ -14362,10 +14872,10 @@ Evidencia: ${evidencePath}` : ""
14362
14872
  }
14363
14873
  migrateLegacyOptimaLayout(toolWorktree);
14364
14874
  const cfgDir = optimaConfigDir(toolWorktree);
14365
- if (!fs17.existsSync(cfgDir)) fs17.mkdirSync(cfgDir, { recursive: true });
14366
- const optimaTmplPath = path18.join(TEMPLATES_DIR, "optima.yaml.template");
14367
- const codemapTmplPath = path18.join(TEMPLATES_DIR, "codemap.yml.template");
14368
- if (!fs17.existsSync(optimaTmplPath) || !fs17.existsSync(codemapTmplPath)) {
14875
+ if (!fs19.existsSync(cfgDir)) fs19.mkdirSync(cfgDir, { recursive: true });
14876
+ const optimaTmplPath = path20.join(TEMPLATES_DIR, "optima.yaml.template");
14877
+ const codemapTmplPath = path20.join(TEMPLATES_DIR, "codemap.yml.template");
14878
+ if (!fs19.existsSync(optimaTmplPath) || !fs19.existsSync(codemapTmplPath)) {
14369
14879
  return "Error: Initialization templates not found in plugin.";
14370
14880
  }
14371
14881
  scaffoldOptimaConfig(toolWorktree, requestedTeamMode);
@@ -14486,14 +14996,14 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
14486
14996
  async execute(args, context) {
14487
14997
  const safe = safeWorktreeOrFailure(context, worktree);
14488
14998
  if (!safe.ok) return safe.message;
14489
- const summaryPath = path18.resolve(safe.worktree, args.summary_path || "");
14490
- if (!fs17.existsSync(summaryPath)) return `FAIL: summary_path not found: ${summaryPath}`;
14491
- const taskPath = args.task_path ? path18.resolve(safe.worktree, args.task_path) : "";
14999
+ const summaryPath = path20.resolve(safe.worktree, args.summary_path || "");
15000
+ if (!fs19.existsSync(summaryPath)) return `FAIL: summary_path not found: ${summaryPath}`;
15001
+ const taskPath = args.task_path ? path20.resolve(safe.worktree, args.task_path) : "";
14492
15002
  const payload = buildClickUpSummaryPayload({
14493
- summaryMarkdown: fs17.readFileSync(summaryPath, "utf8"),
14494
- summaryPath: path18.relative(safe.worktree, summaryPath),
14495
- taskMarkdown: taskPath && fs17.existsSync(taskPath) ? fs17.readFileSync(taskPath, "utf8") : "",
14496
- taskPath: taskPath ? path18.relative(safe.worktree, taskPath) : "",
15003
+ summaryMarkdown: fs19.readFileSync(summaryPath, "utf8"),
15004
+ summaryPath: path20.relative(safe.worktree, summaryPath),
15005
+ taskMarkdown: taskPath && fs19.existsSync(taskPath) ? fs19.readFileSync(taskPath, "utf8") : "",
15006
+ taskPath: taskPath ? path20.relative(safe.worktree, taskPath) : "",
14497
15007
  branch: args.branch,
14498
15008
  worktree: args.worktree,
14499
15009
  pr: args.pr
@@ -14586,6 +15096,116 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
14586
15096
  }
14587
15097
  }
14588
15098
  }),
15099
+ optima_qa_browser_status: tool({
15100
+ description: "Inspect the shared Optima QA browser and queue state for a provider such as chatgpt.",
15101
+ args: {
15102
+ provider: tool.schema.string().optional().describe("QA provider. Defaults to chatgpt."),
15103
+ clickup_task_id: tool.schema.string().optional().describe("Optional ClickUp task id to identify its QA tab."),
15104
+ cdp_url: tool.schema.string().optional().describe("Optional Chrome DevTools URL. Defaults to configured QA URL or http://127.0.0.1:9222.")
15105
+ },
15106
+ async execute(args = {}) {
15107
+ const provider = String(args.provider || qaProvider || DEFAULT_QA_PROVIDER);
15108
+ const state = readQaQueueState(provider);
15109
+ const browser = await qaBrowserStatus({ provider, cdpUrl: args.cdp_url || qaCdpUrl, clickupTaskId: args.clickup_task_id || "" });
15110
+ return JSON.stringify({ ok: browser.ok !== false, provider, leaseMs: qaLeaseMs, queue: state, browser }, null, 2);
15111
+ }
15112
+ }),
15113
+ optima_qa_request_slot: tool({
15114
+ description: "Request the exclusive QA browser slot for a ClickUp task. If busy, Optima queues the task, marks it waiting QA slot, and removes Product Manager assignment.",
15115
+ args: {
15116
+ clickup_task_id: tool.schema.string().describe("ClickUp task id requesting the QA slot"),
15117
+ provider: tool.schema.string().optional().describe("QA provider. Defaults to chatgpt."),
15118
+ session_id: tool.schema.string().optional().describe("Optional OpenCode session id to wake when the slot is granted later"),
15119
+ worktree: tool.schema.string().optional().describe("Optional task worktree/directory for session wakeups"),
15120
+ reason: tool.schema.string().optional().describe("Short reason/scenario for requesting the QA slot")
15121
+ },
15122
+ async execute(args = {}) {
15123
+ const provider = String(args.provider || qaProvider || DEFAULT_QA_PROVIDER);
15124
+ const pathToState = qaQueueStatePath(provider);
15125
+ const current = readQaQueueState(provider, pathToState);
15126
+ const result = requestQaSlot(current, {
15127
+ clickupTaskId: args.clickup_task_id,
15128
+ sessionId: args.session_id,
15129
+ worktree: args.worktree,
15130
+ reason: args.reason,
15131
+ leaseMs: qaLeaseMs
15132
+ });
15133
+ let queuedClickUp = null;
15134
+ if (result.action === "queued") queuedClickUp = await applyQaQueuedClickUpState(args.clickup_task_id);
15135
+ const persisted = await persistQaState(provider, result.state, { promoted: result.promoted, reason: result.expired ? "previous_slot_expired" : "qa_slot_available" });
15136
+ const guidance = result.ok ? "QA slot granted. Use optima_qa_chrome_command within 5 minutes and then at least once every 5 minutes. Use optima_qa_finish when done." : "QA slot busy. Task has been queued; stop work on QA, wait for Optima to reassign/wake the session when your slot is granted.";
15137
+ return JSON.stringify({ ...result, state: persisted.state, notifications: persisted.notifications, queuedClickUp, guidance }, null, 2);
15138
+ }
15139
+ }),
15140
+ optima_qa_chrome_command: tool({
15141
+ description: "Run one flexible Playwright/CDP command against the shared QA Chrome for the active ClickUp task. The persistent tab 0 is never used; Optima creates/reuses a task QA tab.",
15142
+ args: {
15143
+ clickup_task_id: tool.schema.string().describe("ClickUp task id that currently owns the QA slot"),
15144
+ provider: tool.schema.string().optional().describe("QA provider. Defaults to chatgpt."),
15145
+ command_json: tool.schema.string().describe("JSON command object, or raw async JS script. Actions: status, goto, evaluate, screenshot, set_input_files, script."),
15146
+ cdp_url: tool.schema.string().optional().describe("Optional Chrome DevTools URL"),
15147
+ start_url: tool.schema.string().optional().describe("Initial URL for a new QA tab. Defaults to https://chatgpt.com/")
15148
+ },
15149
+ async execute(args = {}) {
15150
+ const provider = String(args.provider || qaProvider || DEFAULT_QA_PROVIDER);
15151
+ const pathToState = qaQueueStatePath(provider);
15152
+ const current = readQaQueueState(provider, pathToState);
15153
+ const touched = touchQaSlot(current, { clickupTaskId: args.clickup_task_id, leaseMs: qaLeaseMs });
15154
+ const persisted = await persistQaState(provider, touched.state, { promoted: touched.promoted, reason: touched.expired ? "previous_slot_expired" : "qa_slot_available" });
15155
+ if (!touched.ok) {
15156
+ return JSON.stringify({
15157
+ ok: false,
15158
+ action: touched.action,
15159
+ active: persisted.state.active,
15160
+ queue: persisted.state.queue,
15161
+ notifications: persisted.notifications,
15162
+ guidance: "You do not own the QA slot. Call optima_qa_request_slot and stop if queued."
15163
+ }, null, 2);
15164
+ }
15165
+ try {
15166
+ const result = await qaRunChromeCommand({
15167
+ provider,
15168
+ cdpUrl: args.cdp_url || qaCdpUrl,
15169
+ clickupTaskId: args.clickup_task_id,
15170
+ commandJson: args.command_json,
15171
+ startUrl: args.start_url || "https://chatgpt.com/"
15172
+ });
15173
+ return JSON.stringify({ ok: true, lease: persisted.state.active, notifications: persisted.notifications, chrome: result }, null, 2);
15174
+ } catch (error) {
15175
+ return JSON.stringify({ ok: false, error: error.message, lease: persisted.state.active, notifications: persisted.notifications }, null, 2);
15176
+ }
15177
+ }
15178
+ }),
15179
+ optima_qa_finish: tool({
15180
+ description: "Finish the active QA browser slot, reset/reload the extension, release the slot, and wake the next queued ClickUp task if any.",
15181
+ args: {
15182
+ clickup_task_id: tool.schema.string().describe("ClickUp task id finishing QA"),
15183
+ provider: tool.schema.string().optional().describe("QA provider. Defaults to chatgpt."),
15184
+ cdp_url: tool.schema.string().optional().describe("Optional Chrome DevTools URL"),
15185
+ extension_path: tool.schema.string().optional().describe("Optional extension path to sync into the stable QA extension-under-test directory before reset/reload"),
15186
+ extension_id: tool.schema.string().optional().describe("Optional Chrome extension id when multiple extension service workers exist"),
15187
+ reset_extension: tool.schema.boolean().optional().describe("Defaults true. Clear extension storage/caches/IndexedDB."),
15188
+ reload_extension: tool.schema.boolean().optional().describe("Defaults true. Reload the extension service worker after reset.")
15189
+ },
15190
+ async execute(args = {}) {
15191
+ const provider = String(args.provider || qaProvider || DEFAULT_QA_PROVIDER);
15192
+ const reset = args.reset_extension !== false;
15193
+ const reload = args.reload_extension !== false;
15194
+ const extension = await qaPrepareExtension({
15195
+ provider,
15196
+ cdpUrl: args.cdp_url || qaCdpUrl,
15197
+ extensionPath: args.extension_path || "",
15198
+ extensionId: args.extension_id || "",
15199
+ reset,
15200
+ reload
15201
+ }).catch((error) => ({ ok: false, error: error.message }));
15202
+ const pathToState = qaQueueStatePath(provider);
15203
+ const current = readQaQueueState(provider, pathToState);
15204
+ const result = finishQaSlot(current, { clickupTaskId: args.clickup_task_id, leaseMs: qaLeaseMs });
15205
+ const persisted = await persistQaState(provider, result.state, { promoted: result.promoted, reason: "previous_finished" });
15206
+ return JSON.stringify({ ...result, state: persisted.state, notifications: persisted.notifications, extension }, null, 2);
15207
+ }
15208
+ }),
14589
15209
  optima_clickup_create_subtasks: tool({
14590
15210
  description: "Generate dry-run ClickUp subtask creation payloads from a strict Markdown ## Subtasks section",
14591
15211
  args: {
@@ -14598,12 +15218,12 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
14598
15218
  async execute(args, context) {
14599
15219
  const safe = safeWorktreeOrFailure(context, worktree);
14600
15220
  if (!safe.ok) return safe.message;
14601
- const markdownPath = path18.resolve(safe.worktree, args.markdown_path || "");
14602
- if (!fs17.existsSync(markdownPath)) return `FAIL: markdown_path not found: ${markdownPath}`;
15221
+ const markdownPath = path20.resolve(safe.worktree, args.markdown_path || "");
15222
+ if (!fs19.existsSync(markdownPath)) return `FAIL: markdown_path not found: ${markdownPath}`;
14603
15223
  const payload = buildClickUpCreateSubtasksPayload({
14604
15224
  parentTaskId: args.parent_task_id,
14605
- markdown: fs17.readFileSync(markdownPath, "utf8"),
14606
- sourcePath: path18.relative(safe.worktree, markdownPath),
15225
+ markdown: fs19.readFileSync(markdownPath, "utf8"),
15226
+ sourcePath: path20.relative(safe.worktree, markdownPath),
14607
15227
  parentBranch: args.parent_branch,
14608
15228
  parentTaskType: args.parent_task_type || "Tarea",
14609
15229
  apply: String(args.apply || "").toLowerCase() === "true"
@@ -14973,7 +15593,7 @@ Backfilled messages: ${backfilled}`;
14973
15593
  if (!existing) {
14974
15594
  return "FAIL: No active discussion exists for this session.";
14975
15595
  }
14976
- const discussionPath = path18.join(toolWorktree, existing.transcriptPath);
15596
+ const discussionPath = path20.join(toolWorktree, existing.transcriptPath);
14977
15597
  setDiscussionStatus(discussionPath, "summarizing");
14978
15598
  existing.status = "summarizing";
14979
15599
  saveDiscussionRegistry(toolWorktree, toolRegistry);
@@ -15025,7 +15645,7 @@ Reason: ${err.message}`;
15025
15645
  try {
15026
15646
  const sessionResult = await client.session.create({
15027
15647
  query: { directory: workflowDirectory },
15028
- body: { title: `Workflow Run: ${path18.basename(workflowTaskPath)}` }
15648
+ body: { title: `Workflow Run: ${path20.basename(workflowTaskPath)}` }
15029
15649
  });
15030
15650
  const sessionId = sessionResult.data.id;
15031
15651
  activeWorkflows.set(sessionId, { pmaSessionId, taskPath: workflowTaskPath, track: workflowTrack, directory: workflowDirectory });
@@ -15209,14 +15829,14 @@ function usage() {
15209
15829
  ].join("\n");
15210
15830
  }
15211
15831
  function expandHome(inputPath) {
15212
- if (!inputPath || inputPath === "~") return os5.homedir();
15213
- if (inputPath.startsWith("~/")) return path19.join(os5.homedir(), inputPath.slice(2));
15832
+ if (!inputPath || inputPath === "~") return os7.homedir();
15833
+ if (inputPath.startsWith("~/")) return path21.join(os7.homedir(), inputPath.slice(2));
15214
15834
  return inputPath;
15215
15835
  }
15216
15836
  function resolveOpenCodeDbPath(inputPath = null) {
15217
15837
  const expanded = expandHome(inputPath || process.env.OPTIMA_OPENCODE_DB_PATH || DEFAULT_DB_PATH);
15218
15838
  try {
15219
- if (fs18.existsSync(expanded) && fs18.statSync(expanded).isDirectory()) return path19.join(expanded, "opencode.db");
15839
+ if (fs20.existsSync(expanded) && fs20.statSync(expanded).isDirectory()) return path21.join(expanded, "opencode.db");
15220
15840
  } catch {
15221
15841
  return expanded;
15222
15842
  }
@@ -15280,12 +15900,12 @@ function extractOpenedPathValue(value) {
15280
15900
  }
15281
15901
  function normalizePathCandidate(candidate) {
15282
15902
  const expanded = expandHome(candidate);
15283
- if (!path19.isAbsolute(expanded)) return null;
15284
- return path19.resolve(expanded);
15903
+ if (!path21.isAbsolute(expanded)) return null;
15904
+ return path21.resolve(expanded);
15285
15905
  }
15286
15906
  function discoverOpenCodePaths(dbPath) {
15287
15907
  const resolvedDb = resolveOpenCodeDbPath(dbPath);
15288
- if (!fs18.existsSync(resolvedDb)) throw new Error(`OpenCode database not found: ${resolvedDb}`);
15908
+ if (!fs20.existsSync(resolvedDb)) throw new Error(`OpenCode database not found: ${resolvedDb}`);
15289
15909
  const tables = sqliteJson(resolvedDb, "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name");
15290
15910
  const discovered = /* @__PURE__ */ new Set();
15291
15911
  for (const table of tables) {
@@ -15310,27 +15930,27 @@ function discoverOpenCodePaths(dbPath) {
15310
15930
  function collectMarkdownOverridesFrom(baseDir) {
15311
15931
  const files = [];
15312
15932
  for (const dirName of OVERRIDE_DIRS) {
15313
- const dirPath = path19.join(baseDir, dirName);
15314
- if (!fs18.existsSync(dirPath)) continue;
15315
- for (const entry of fs18.readdirSync(dirPath, { withFileTypes: true })) {
15933
+ const dirPath = path21.join(baseDir, dirName);
15934
+ if (!fs20.existsSync(dirPath)) continue;
15935
+ for (const entry of fs20.readdirSync(dirPath, { withFileTypes: true })) {
15316
15936
  if (!entry.isFile()) continue;
15317
15937
  if (!entry.name.endsWith(".md")) continue;
15318
15938
  if (entry.name.toLowerCase() === "readme.md") continue;
15319
- files.push(path19.join(dirPath, entry.name));
15939
+ files.push(path21.join(dirPath, entry.name));
15320
15940
  }
15321
15941
  }
15322
15942
  return files;
15323
15943
  }
15324
15944
  function collectOverrideFiles(worktree) {
15325
- return collectMarkdownOverridesFrom(path19.join(worktree, ".optima")).sort();
15945
+ return collectMarkdownOverridesFrom(path21.join(worktree, ".optima")).sort();
15326
15946
  }
15327
15947
  function collectPlannedOverrideFiles(worktree) {
15328
15948
  return [
15329
15949
  ...collectOverrideFiles(worktree),
15330
- ...collectMarkdownOverridesFrom(path19.join(worktree, ".staticeng")),
15331
- ...collectMarkdownOverridesFrom(path19.join(worktree, ".orbita")),
15332
- ...collectMarkdownOverridesFrom(path19.join(worktree, ".nomadwork")),
15333
- ...collectMarkdownOverridesFrom(path19.join(worktree, ".nomadworks"))
15950
+ ...collectMarkdownOverridesFrom(path21.join(worktree, ".staticeng")),
15951
+ ...collectMarkdownOverridesFrom(path21.join(worktree, ".orbita")),
15952
+ ...collectMarkdownOverridesFrom(path21.join(worktree, ".nomadwork")),
15953
+ ...collectMarkdownOverridesFrom(path21.join(worktree, ".nomadworks"))
15334
15954
  ].sort();
15335
15955
  }
15336
15956
  var CRC_TABLE = (() => {
@@ -15363,14 +15983,14 @@ function writeUInt16LE(value) {
15363
15983
  return buffer;
15364
15984
  }
15365
15985
  function createZipBackup(files, backupPath) {
15366
- fs18.mkdirSync(path19.dirname(backupPath), { recursive: true });
15986
+ fs20.mkdirSync(path21.dirname(backupPath), { recursive: true });
15367
15987
  const localParts = [];
15368
15988
  const centralParts = [];
15369
15989
  let offset = 0;
15370
15990
  const now = dosTimeDate();
15371
15991
  for (const filePath of files) {
15372
- const data = fs18.readFileSync(filePath);
15373
- const name = path19.resolve(filePath).replace(/^\//, "").split(path19.sep).join("/");
15992
+ const data = fs20.readFileSync(filePath);
15993
+ const name = path21.resolve(filePath).replace(/^\//, "").split(path21.sep).join("/");
15374
15994
  const nameBuffer = Buffer.from(name, "utf8");
15375
15995
  const crc = crc32(data);
15376
15996
  const local = Buffer.concat([
@@ -15422,7 +16042,7 @@ function createZipBackup(files, backupPath) {
15422
16042
  writeUInt32LE(offset),
15423
16043
  writeUInt16LE(0)
15424
16044
  ]);
15425
- fs18.writeFileSync(backupPath, Buffer.concat([...localParts, ...centralParts, end]));
16045
+ fs20.writeFileSync(backupPath, Buffer.concat([...localParts, ...centralParts, end]));
15426
16046
  }
15427
16047
  function timestamp() {
15428
16048
  return (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
@@ -15432,17 +16052,17 @@ function validationStatus(result) {
15432
16052
  return result.ok ? "passed" : "failed";
15433
16053
  }
15434
16054
  function hasLegacyMarker(worktree) {
15435
- return fs18.existsSync(path19.join(worktree, ".staticeng")) || fs18.existsSync(path19.join(worktree, ".orbita")) || fs18.existsSync(path19.join(worktree, ".nomadwork")) || fs18.existsSync(path19.join(worktree, ".nomadworks"));
16055
+ return fs20.existsSync(path21.join(worktree, ".staticeng")) || fs20.existsSync(path21.join(worktree, ".orbita")) || fs20.existsSync(path21.join(worktree, ".nomadwork")) || fs20.existsSync(path21.join(worktree, ".nomadworks"));
15436
16056
  }
15437
16057
  function rootOptimaArtifacts(worktree) {
15438
16058
  const artifacts = [
15439
- ["tasks/", path19.join(worktree, "tasks")],
15440
- ["evidences/", path19.join(worktree, "evidences")],
15441
- ["docs/scrs/", path19.join(worktree, "docs", "scrs")],
15442
- ["codemap.yml", path19.join(worktree, "codemap.yml")],
15443
- ["codemap.yaml", path19.join(worktree, "codemap.yaml")]
16059
+ ["tasks/", path21.join(worktree, "tasks")],
16060
+ ["evidences/", path21.join(worktree, "evidences")],
16061
+ ["docs/scrs/", path21.join(worktree, "docs", "scrs")],
16062
+ ["codemap.yml", path21.join(worktree, "codemap.yml")],
16063
+ ["codemap.yaml", path21.join(worktree, "codemap.yaml")]
15444
16064
  ];
15445
- return artifacts.map(([display, artifactPath]) => ({ display, path: artifactPath })).filter((item) => fs18.existsSync(item.path));
16065
+ return artifacts.map(([display, artifactPath]) => ({ display, path: artifactPath })).filter((item) => fs20.existsSync(item.path));
15446
16066
  }
15447
16067
  function hasSanitizableOverrides(worktree) {
15448
16068
  return collectPlannedOverrideFiles(worktree).length > 0;
@@ -15468,7 +16088,7 @@ function planOptimaMigration(worktree, dryRun) {
15468
16088
  ...overrides.map((file) => ({
15469
16089
  category: "override",
15470
16090
  action: dryRun ? "would_remove_after_backup" : "removed_after_backup",
15471
- path: path19.relative(worktree, file).split(path19.sep).join("/"),
16091
+ path: path21.relative(worktree, file).split(path21.sep).join("/"),
15472
16092
  detail: "Remove implicit agent/policy override after host-level backup."
15473
16093
  }))
15474
16094
  ],
@@ -15489,12 +16109,12 @@ async function sanitizeHost(options = {}) {
15489
16109
  const repoStates = [];
15490
16110
  for (const candidate of paths) {
15491
16111
  try {
15492
- if (!fs18.existsSync(candidate)) {
16112
+ if (!fs20.existsSync(candidate)) {
15493
16113
  report.totals.skipped += 1;
15494
16114
  report.repos.push({ path: candidate, status: "skipped", reason: "missing" });
15495
16115
  continue;
15496
16116
  }
15497
- if (!fs18.statSync(candidate).isDirectory()) {
16117
+ if (!fs20.statSync(candidate).isDirectory()) {
15498
16118
  report.totals.skipped += 1;
15499
16119
  report.repos.push({ path: candidate, status: "skipped", reason: "not_directory" });
15500
16120
  continue;
@@ -15516,7 +16136,7 @@ async function sanitizeHost(options = {}) {
15516
16136
  const overrides = repoStates.flatMap((state) => state.overrideFiles.map((file) => ({ repo: state.repo, file })));
15517
16137
  report.totals.overrideFiles = overrides.length;
15518
16138
  if (!dryRun && overrides.length > 0) {
15519
- const backupPath = path19.join(os5.homedir(), BACKUP_DIRNAME, `${timestamp()}.zip`);
16139
+ const backupPath = path21.join(os7.homedir(), BACKUP_DIRNAME, `${timestamp()}.zip`);
15520
16140
  try {
15521
16141
  createZipBackup(overrides.map((item) => item.file), backupPath);
15522
16142
  report.backupPath = backupPath;
@@ -15532,7 +16152,7 @@ async function sanitizeHost(options = {}) {
15532
16152
  for (const state of repoStates) {
15533
16153
  try {
15534
16154
  if (!dryRun) {
15535
- for (const file of state.overrideFiles) fs18.rmSync(file, { force: true });
16155
+ for (const file of state.overrideFiles) fs20.rmSync(file, { force: true });
15536
16156
  }
15537
16157
  const validation = !dryRun && hasLegacyMarker(state.repo) ? await optima_validate_logic(state.repo) : null;
15538
16158
  const status = (!validation || validation.ok) && state.plan.unresolved.length === 0 ? "repaired" : "failed";
@@ -15545,7 +16165,7 @@ async function sanitizeHost(options = {}) {
15545
16165
  repairActions: state.plan.actions.length,
15546
16166
  repairSkipped: state.plan.skippedRepair === true,
15547
16167
  overrideFiles: state.overrideFiles.length,
15548
- overridePaths: state.overrideFiles.map((file) => path19.relative(state.repo, file).split(path19.sep).join("/")),
16168
+ overridePaths: state.overrideFiles.map((file) => path21.relative(state.repo, file).split(path21.sep).join("/")),
15549
16169
  validation: validation ? validationStatus(validation) : "skipped",
15550
16170
  unresolved: state.plan.unresolved
15551
16171
  });