@defend-tech/opencode-optima 0.1.75 → 0.1.77

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.
package/dist/index.js CHANGED
@@ -108,17 +108,17 @@ var require_visit = __commonJS({
108
108
  visit.BREAK = BREAK;
109
109
  visit.SKIP = SKIP;
110
110
  visit.REMOVE = REMOVE;
111
- function visit_(key, node, visitor, path7) {
112
- const ctrl = callVisitor(key, node, visitor, path7);
111
+ function visit_(key, node, visitor, path9) {
112
+ const ctrl = callVisitor(key, node, visitor, path9);
113
113
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
114
- replaceNode(key, path7, ctrl);
115
- return visit_(key, ctrl, visitor, path7);
114
+ replaceNode(key, path9, ctrl);
115
+ return visit_(key, ctrl, visitor, path9);
116
116
  }
117
117
  if (typeof ctrl !== "symbol") {
118
118
  if (identity.isCollection(node)) {
119
- path7 = Object.freeze(path7.concat(node));
119
+ path9 = Object.freeze(path9.concat(node));
120
120
  for (let i = 0; i < node.items.length; ++i) {
121
- const ci = visit_(i, node.items[i], visitor, path7);
121
+ const ci = visit_(i, node.items[i], visitor, path9);
122
122
  if (typeof ci === "number")
123
123
  i = ci - 1;
124
124
  else if (ci === BREAK)
@@ -129,13 +129,13 @@ var require_visit = __commonJS({
129
129
  }
130
130
  }
131
131
  } else if (identity.isPair(node)) {
132
- path7 = Object.freeze(path7.concat(node));
133
- const ck = visit_("key", node.key, visitor, path7);
132
+ path9 = Object.freeze(path9.concat(node));
133
+ const ck = visit_("key", node.key, visitor, path9);
134
134
  if (ck === BREAK)
135
135
  return BREAK;
136
136
  else if (ck === REMOVE)
137
137
  node.key = null;
138
- const cv = visit_("value", node.value, visitor, path7);
138
+ const cv = visit_("value", node.value, visitor, path9);
139
139
  if (cv === BREAK)
140
140
  return BREAK;
141
141
  else if (cv === REMOVE)
@@ -156,17 +156,17 @@ var require_visit = __commonJS({
156
156
  visitAsync.BREAK = BREAK;
157
157
  visitAsync.SKIP = SKIP;
158
158
  visitAsync.REMOVE = REMOVE;
159
- async function visitAsync_(key, node, visitor, path7) {
160
- const ctrl = await callVisitor(key, node, visitor, path7);
159
+ async function visitAsync_(key, node, visitor, path9) {
160
+ const ctrl = await callVisitor(key, node, visitor, path9);
161
161
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
162
- replaceNode(key, path7, ctrl);
163
- return visitAsync_(key, ctrl, visitor, path7);
162
+ replaceNode(key, path9, ctrl);
163
+ return visitAsync_(key, ctrl, visitor, path9);
164
164
  }
165
165
  if (typeof ctrl !== "symbol") {
166
166
  if (identity.isCollection(node)) {
167
- path7 = Object.freeze(path7.concat(node));
167
+ path9 = Object.freeze(path9.concat(node));
168
168
  for (let i = 0; i < node.items.length; ++i) {
169
- const ci = await visitAsync_(i, node.items[i], visitor, path7);
169
+ const ci = await visitAsync_(i, node.items[i], visitor, path9);
170
170
  if (typeof ci === "number")
171
171
  i = ci - 1;
172
172
  else if (ci === BREAK)
@@ -177,13 +177,13 @@ var require_visit = __commonJS({
177
177
  }
178
178
  }
179
179
  } else if (identity.isPair(node)) {
180
- path7 = Object.freeze(path7.concat(node));
181
- const ck = await visitAsync_("key", node.key, visitor, path7);
180
+ path9 = Object.freeze(path9.concat(node));
181
+ const ck = await visitAsync_("key", node.key, visitor, path9);
182
182
  if (ck === BREAK)
183
183
  return BREAK;
184
184
  else if (ck === REMOVE)
185
185
  node.key = null;
186
- const cv = await visitAsync_("value", node.value, visitor, path7);
186
+ const cv = await visitAsync_("value", node.value, visitor, path9);
187
187
  if (cv === BREAK)
188
188
  return BREAK;
189
189
  else if (cv === REMOVE)
@@ -210,23 +210,23 @@ var require_visit = __commonJS({
210
210
  }
211
211
  return visitor;
212
212
  }
213
- function callVisitor(key, node, visitor, path7) {
213
+ function callVisitor(key, node, visitor, path9) {
214
214
  if (typeof visitor === "function")
215
- return visitor(key, node, path7);
215
+ return visitor(key, node, path9);
216
216
  if (identity.isMap(node))
217
- return visitor.Map?.(key, node, path7);
217
+ return visitor.Map?.(key, node, path9);
218
218
  if (identity.isSeq(node))
219
- return visitor.Seq?.(key, node, path7);
219
+ return visitor.Seq?.(key, node, path9);
220
220
  if (identity.isPair(node))
221
- return visitor.Pair?.(key, node, path7);
221
+ return visitor.Pair?.(key, node, path9);
222
222
  if (identity.isScalar(node))
223
- return visitor.Scalar?.(key, node, path7);
223
+ return visitor.Scalar?.(key, node, path9);
224
224
  if (identity.isAlias(node))
225
- return visitor.Alias?.(key, node, path7);
225
+ return visitor.Alias?.(key, node, path9);
226
226
  return void 0;
227
227
  }
228
- function replaceNode(key, path7, node) {
229
- const parent = path7[path7.length - 1];
228
+ function replaceNode(key, path9, node) {
229
+ const parent = path9[path9.length - 1];
230
230
  if (identity.isCollection(parent)) {
231
231
  parent.items[key] = node;
232
232
  } else if (identity.isPair(parent)) {
@@ -834,10 +834,10 @@ var require_Collection = __commonJS({
834
834
  var createNode = require_createNode();
835
835
  var identity = require_identity();
836
836
  var Node = require_Node();
837
- function collectionFromPath(schema, path7, value) {
837
+ function collectionFromPath(schema, path9, value) {
838
838
  let v = value;
839
- for (let i = path7.length - 1; i >= 0; --i) {
840
- const k = path7[i];
839
+ for (let i = path9.length - 1; i >= 0; --i) {
840
+ const k = path9[i];
841
841
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
842
842
  const a = [];
843
843
  a[k] = v;
@@ -856,7 +856,7 @@ var require_Collection = __commonJS({
856
856
  sourceObjects: /* @__PURE__ */ new Map()
857
857
  });
858
858
  }
859
- var isEmptyPath = (path7) => path7 == null || typeof path7 === "object" && !!path7[Symbol.iterator]().next().done;
859
+ var isEmptyPath = (path9) => path9 == null || typeof path9 === "object" && !!path9[Symbol.iterator]().next().done;
860
860
  var Collection = class extends Node.NodeBase {
861
861
  constructor(type, schema) {
862
862
  super(type);
@@ -886,11 +886,11 @@ var require_Collection = __commonJS({
886
886
  * be a Pair instance or a `{ key, value }` object, which may not have a key
887
887
  * that already exists in the map.
888
888
  */
889
- addIn(path7, value) {
890
- if (isEmptyPath(path7))
889
+ addIn(path9, value) {
890
+ if (isEmptyPath(path9))
891
891
  this.add(value);
892
892
  else {
893
- const [key, ...rest] = path7;
893
+ const [key, ...rest] = path9;
894
894
  const node = this.get(key, true);
895
895
  if (identity.isCollection(node))
896
896
  node.addIn(rest, value);
@@ -904,8 +904,8 @@ var require_Collection = __commonJS({
904
904
  * Removes a value from the collection.
905
905
  * @returns `true` if the item was found and removed.
906
906
  */
907
- deleteIn(path7) {
908
- const [key, ...rest] = path7;
907
+ deleteIn(path9) {
908
+ const [key, ...rest] = path9;
909
909
  if (rest.length === 0)
910
910
  return this.delete(key);
911
911
  const node = this.get(key, true);
@@ -919,8 +919,8 @@ var require_Collection = __commonJS({
919
919
  * scalar values from their surrounding node; to disable set `keepScalar` to
920
920
  * `true` (collections are always returned intact).
921
921
  */
922
- getIn(path7, keepScalar) {
923
- const [key, ...rest] = path7;
922
+ getIn(path9, keepScalar) {
923
+ const [key, ...rest] = path9;
924
924
  const node = this.get(key, true);
925
925
  if (rest.length === 0)
926
926
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -938,8 +938,8 @@ var require_Collection = __commonJS({
938
938
  /**
939
939
  * Checks if the collection includes a value with the key `key`.
940
940
  */
941
- hasIn(path7) {
942
- const [key, ...rest] = path7;
941
+ hasIn(path9) {
942
+ const [key, ...rest] = path9;
943
943
  if (rest.length === 0)
944
944
  return this.has(key);
945
945
  const node = this.get(key, true);
@@ -949,8 +949,8 @@ var require_Collection = __commonJS({
949
949
  * Sets a value in this collection. For `!!set`, `value` needs to be a
950
950
  * boolean to add/remove the item from the set.
951
951
  */
952
- setIn(path7, value) {
953
- const [key, ...rest] = path7;
952
+ setIn(path9, value) {
953
+ const [key, ...rest] = path9;
954
954
  if (rest.length === 0) {
955
955
  this.set(key, value);
956
956
  } else {
@@ -3454,9 +3454,9 @@ var require_Document = __commonJS({
3454
3454
  this.contents.add(value);
3455
3455
  }
3456
3456
  /** Adds a value to the document. */
3457
- addIn(path7, value) {
3457
+ addIn(path9, value) {
3458
3458
  if (assertCollection(this.contents))
3459
- this.contents.addIn(path7, value);
3459
+ this.contents.addIn(path9, value);
3460
3460
  }
3461
3461
  /**
3462
3462
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -3531,14 +3531,14 @@ var require_Document = __commonJS({
3531
3531
  * Removes a value from the document.
3532
3532
  * @returns `true` if the item was found and removed.
3533
3533
  */
3534
- deleteIn(path7) {
3535
- if (Collection.isEmptyPath(path7)) {
3534
+ deleteIn(path9) {
3535
+ if (Collection.isEmptyPath(path9)) {
3536
3536
  if (this.contents == null)
3537
3537
  return false;
3538
3538
  this.contents = null;
3539
3539
  return true;
3540
3540
  }
3541
- return assertCollection(this.contents) ? this.contents.deleteIn(path7) : false;
3541
+ return assertCollection(this.contents) ? this.contents.deleteIn(path9) : false;
3542
3542
  }
3543
3543
  /**
3544
3544
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -3553,10 +3553,10 @@ var require_Document = __commonJS({
3553
3553
  * scalar values from their surrounding node; to disable set `keepScalar` to
3554
3554
  * `true` (collections are always returned intact).
3555
3555
  */
3556
- getIn(path7, keepScalar) {
3557
- if (Collection.isEmptyPath(path7))
3556
+ getIn(path9, keepScalar) {
3557
+ if (Collection.isEmptyPath(path9))
3558
3558
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
3559
- return identity.isCollection(this.contents) ? this.contents.getIn(path7, keepScalar) : void 0;
3559
+ return identity.isCollection(this.contents) ? this.contents.getIn(path9, keepScalar) : void 0;
3560
3560
  }
3561
3561
  /**
3562
3562
  * Checks if the document includes a value with the key `key`.
@@ -3567,10 +3567,10 @@ var require_Document = __commonJS({
3567
3567
  /**
3568
3568
  * Checks if the document includes a value at `path`.
3569
3569
  */
3570
- hasIn(path7) {
3571
- if (Collection.isEmptyPath(path7))
3570
+ hasIn(path9) {
3571
+ if (Collection.isEmptyPath(path9))
3572
3572
  return this.contents !== void 0;
3573
- return identity.isCollection(this.contents) ? this.contents.hasIn(path7) : false;
3573
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path9) : false;
3574
3574
  }
3575
3575
  /**
3576
3576
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -3587,13 +3587,13 @@ var require_Document = __commonJS({
3587
3587
  * Sets a value in this document. For `!!set`, `value` needs to be a
3588
3588
  * boolean to add/remove the item from the set.
3589
3589
  */
3590
- setIn(path7, value) {
3591
- if (Collection.isEmptyPath(path7)) {
3590
+ setIn(path9, value) {
3591
+ if (Collection.isEmptyPath(path9)) {
3592
3592
  this.contents = value;
3593
3593
  } else if (this.contents == null) {
3594
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path7), value);
3594
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path9), value);
3595
3595
  } else if (assertCollection(this.contents)) {
3596
- this.contents.setIn(path7, value);
3596
+ this.contents.setIn(path9, value);
3597
3597
  }
3598
3598
  }
3599
3599
  /**
@@ -5545,9 +5545,9 @@ var require_cst_visit = __commonJS({
5545
5545
  visit.BREAK = BREAK;
5546
5546
  visit.SKIP = SKIP;
5547
5547
  visit.REMOVE = REMOVE;
5548
- visit.itemAtPath = (cst, path7) => {
5548
+ visit.itemAtPath = (cst, path9) => {
5549
5549
  let item = cst;
5550
- for (const [field, index] of path7) {
5550
+ for (const [field, index] of path9) {
5551
5551
  const tok = item?.[field];
5552
5552
  if (tok && "items" in tok) {
5553
5553
  item = tok.items[index];
@@ -5556,23 +5556,23 @@ var require_cst_visit = __commonJS({
5556
5556
  }
5557
5557
  return item;
5558
5558
  };
5559
- visit.parentCollection = (cst, path7) => {
5560
- const parent = visit.itemAtPath(cst, path7.slice(0, -1));
5561
- const field = path7[path7.length - 1][0];
5559
+ visit.parentCollection = (cst, path9) => {
5560
+ const parent = visit.itemAtPath(cst, path9.slice(0, -1));
5561
+ const field = path9[path9.length - 1][0];
5562
5562
  const coll = parent?.[field];
5563
5563
  if (coll && "items" in coll)
5564
5564
  return coll;
5565
5565
  throw new Error("Parent collection not found");
5566
5566
  };
5567
- function _visit(path7, item, visitor) {
5568
- let ctrl = visitor(item, path7);
5567
+ function _visit(path9, item, visitor) {
5568
+ let ctrl = visitor(item, path9);
5569
5569
  if (typeof ctrl === "symbol")
5570
5570
  return ctrl;
5571
5571
  for (const field of ["key", "value"]) {
5572
5572
  const token = item[field];
5573
5573
  if (token && "items" in token) {
5574
5574
  for (let i = 0; i < token.items.length; ++i) {
5575
- const ci = _visit(Object.freeze(path7.concat([[field, i]])), token.items[i], visitor);
5575
+ const ci = _visit(Object.freeze(path9.concat([[field, i]])), token.items[i], visitor);
5576
5576
  if (typeof ci === "number")
5577
5577
  i = ci - 1;
5578
5578
  else if (ci === BREAK)
@@ -5583,10 +5583,10 @@ var require_cst_visit = __commonJS({
5583
5583
  }
5584
5584
  }
5585
5585
  if (typeof ctrl === "function" && field === "key")
5586
- ctrl = ctrl(item, path7);
5586
+ ctrl = ctrl(item, path9);
5587
5587
  }
5588
5588
  }
5589
- return typeof ctrl === "function" ? ctrl(item, path7) : ctrl;
5589
+ return typeof ctrl === "function" ? ctrl(item, path9) : ctrl;
5590
5590
  }
5591
5591
  exports.visit = visit;
5592
5592
  }
@@ -6871,14 +6871,14 @@ var require_parser = __commonJS({
6871
6871
  case "scalar":
6872
6872
  case "single-quoted-scalar":
6873
6873
  case "double-quoted-scalar": {
6874
- const fs6 = this.flowScalar(this.type);
6874
+ const fs9 = this.flowScalar(this.type);
6875
6875
  if (atNextItem || it.value) {
6876
- map.items.push({ start, key: fs6, sep: [] });
6876
+ map.items.push({ start, key: fs9, sep: [] });
6877
6877
  this.onKeyLine = true;
6878
6878
  } else if (it.sep) {
6879
- this.stack.push(fs6);
6879
+ this.stack.push(fs9);
6880
6880
  } else {
6881
- Object.assign(it, { key: fs6, sep: [] });
6881
+ Object.assign(it, { key: fs9, sep: [] });
6882
6882
  this.onKeyLine = true;
6883
6883
  }
6884
6884
  return;
@@ -7006,13 +7006,13 @@ var require_parser = __commonJS({
7006
7006
  case "scalar":
7007
7007
  case "single-quoted-scalar":
7008
7008
  case "double-quoted-scalar": {
7009
- const fs6 = this.flowScalar(this.type);
7009
+ const fs9 = this.flowScalar(this.type);
7010
7010
  if (!it || it.value)
7011
- fc.items.push({ start: [], key: fs6, sep: [] });
7011
+ fc.items.push({ start: [], key: fs9, sep: [] });
7012
7012
  else if (it.sep)
7013
- this.stack.push(fs6);
7013
+ this.stack.push(fs9);
7014
7014
  else
7015
- Object.assign(it, { key: fs6, sep: [] });
7015
+ Object.assign(it, { key: fs9, sep: [] });
7016
7016
  return;
7017
7017
  }
7018
7018
  case "flow-map-end":
@@ -7550,17 +7550,17 @@ var require_ignore = __commonJS({
7550
7550
  var throwError = (message, Ctor) => {
7551
7551
  throw new Ctor(message);
7552
7552
  };
7553
- var checkPath = (path7, originalPath, doThrow) => {
7554
- if (!isString(path7)) {
7553
+ var checkPath = (path9, originalPath, doThrow) => {
7554
+ if (!isString(path9)) {
7555
7555
  return doThrow(
7556
7556
  `path must be a string, but got \`${originalPath}\``,
7557
7557
  TypeError
7558
7558
  );
7559
7559
  }
7560
- if (!path7) {
7560
+ if (!path9) {
7561
7561
  return doThrow(`path must not be empty`, TypeError);
7562
7562
  }
7563
- if (checkPath.isNotRelative(path7)) {
7563
+ if (checkPath.isNotRelative(path9)) {
7564
7564
  const r = "`path.relative()`d";
7565
7565
  return doThrow(
7566
7566
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -7569,7 +7569,7 @@ var require_ignore = __commonJS({
7569
7569
  }
7570
7570
  return true;
7571
7571
  };
7572
- var isNotRelative = (path7) => REGEX_TEST_INVALID_PATH.test(path7);
7572
+ var isNotRelative = (path9) => REGEX_TEST_INVALID_PATH.test(path9);
7573
7573
  checkPath.isNotRelative = isNotRelative;
7574
7574
  checkPath.convert = (p) => p;
7575
7575
  var Ignore = class {
@@ -7628,7 +7628,7 @@ var require_ignore = __commonJS({
7628
7628
  // setting `checkUnignored` to `false` could reduce additional
7629
7629
  // path matching.
7630
7630
  // @returns {TestResult} true if a file is ignored
7631
- _testOne(path7, checkUnignored) {
7631
+ _testOne(path9, checkUnignored) {
7632
7632
  let ignored = false;
7633
7633
  let unignored = false;
7634
7634
  this._rules.forEach((rule) => {
@@ -7636,7 +7636,7 @@ var require_ignore = __commonJS({
7636
7636
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
7637
7637
  return;
7638
7638
  }
7639
- const matched = rule.regex.test(path7);
7639
+ const matched = rule.regex.test(path9);
7640
7640
  if (matched) {
7641
7641
  ignored = !negative;
7642
7642
  unignored = negative;
@@ -7649,24 +7649,24 @@ var require_ignore = __commonJS({
7649
7649
  }
7650
7650
  // @returns {TestResult}
7651
7651
  _test(originalPath, cache, checkUnignored, slices) {
7652
- const path7 = originalPath && checkPath.convert(originalPath);
7652
+ const path9 = originalPath && checkPath.convert(originalPath);
7653
7653
  checkPath(
7654
- path7,
7654
+ path9,
7655
7655
  originalPath,
7656
7656
  this._allowRelativePaths ? RETURN_FALSE : throwError
7657
7657
  );
7658
- return this._t(path7, cache, checkUnignored, slices);
7658
+ return this._t(path9, cache, checkUnignored, slices);
7659
7659
  }
7660
- _t(path7, cache, checkUnignored, slices) {
7661
- if (path7 in cache) {
7662
- return cache[path7];
7660
+ _t(path9, cache, checkUnignored, slices) {
7661
+ if (path9 in cache) {
7662
+ return cache[path9];
7663
7663
  }
7664
7664
  if (!slices) {
7665
- slices = path7.split(SLASH);
7665
+ slices = path9.split(SLASH);
7666
7666
  }
7667
7667
  slices.pop();
7668
7668
  if (!slices.length) {
7669
- return cache[path7] = this._testOne(path7, checkUnignored);
7669
+ return cache[path9] = this._testOne(path9, checkUnignored);
7670
7670
  }
7671
7671
  const parent = this._t(
7672
7672
  slices.join(SLASH) + SLASH,
@@ -7674,24 +7674,24 @@ var require_ignore = __commonJS({
7674
7674
  checkUnignored,
7675
7675
  slices
7676
7676
  );
7677
- return cache[path7] = parent.ignored ? parent : this._testOne(path7, checkUnignored);
7677
+ return cache[path9] = parent.ignored ? parent : this._testOne(path9, checkUnignored);
7678
7678
  }
7679
- ignores(path7) {
7680
- return this._test(path7, this._ignoreCache, false).ignored;
7679
+ ignores(path9) {
7680
+ return this._test(path9, this._ignoreCache, false).ignored;
7681
7681
  }
7682
7682
  createFilter() {
7683
- return (path7) => !this.ignores(path7);
7683
+ return (path9) => !this.ignores(path9);
7684
7684
  }
7685
7685
  filter(paths) {
7686
7686
  return makeArray(paths).filter(this.createFilter());
7687
7687
  }
7688
7688
  // @returns {TestResult}
7689
- test(path7) {
7690
- return this._test(path7, this._testCache, true);
7689
+ test(path9) {
7690
+ return this._test(path9, this._testCache, true);
7691
7691
  }
7692
7692
  };
7693
7693
  var factory = (options) => new Ignore(options);
7694
- var isPathValid = (path7) => checkPath(path7 && checkPath.convert(path7), path7, RETURN_FALSE);
7694
+ var isPathValid = (path9) => checkPath(path9 && checkPath.convert(path9), path9, RETURN_FALSE);
7695
7695
  factory.isPathValid = isPathValid;
7696
7696
  factory.default = factory;
7697
7697
  module.exports = factory;
@@ -7702,7 +7702,7 @@ var require_ignore = __commonJS({
7702
7702
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
7703
7703
  checkPath.convert = makePosix;
7704
7704
  const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
7705
- checkPath.isNotRelative = (path7) => REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path7) || isNotRelative(path7);
7705
+ checkPath.isNotRelative = (path9) => REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path9) || isNotRelative(path9);
7706
7706
  }
7707
7707
  }
7708
7708
  });
@@ -7710,13 +7710,45 @@ var require_ignore = __commonJS({
7710
7710
  // src/index.js
7711
7711
  var import_yaml3 = __toESM(require_dist(), 1);
7712
7712
  var import_ignore3 = __toESM(require_ignore(), 1);
7713
- import crypto from "node:crypto";
7714
- import fs5 from "node:fs";
7713
+ import crypto2 from "node:crypto";
7714
+ import fs8 from "node:fs";
7715
7715
  import http from "node:http";
7716
- import os from "node:os";
7717
- import path6 from "node:path";
7716
+ import os2 from "node:os";
7717
+ import path8 from "node:path";
7718
7718
  import { tool } from "@opencode-ai/plugin/tool";
7719
7719
 
7720
+ // src/clickup_comments.js
7721
+ var COMMENT_TEXT_KEYS = /* @__PURE__ */ new Set(["comment", "body", "description"]);
7722
+ function normalizeClickUpMarkdown(value = "") {
7723
+ return String(value ?? "").replace(/\\r\\n/g, "\n").replace(/\\n/g, "\n").replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => line.trimEnd()).join("\n").replace(/\n{3,}/g, "\n\n").trim();
7724
+ }
7725
+ function formatClickUpStatusComment({ title = "", summary = "", sections = [], context = [] } = {}) {
7726
+ const lines = [];
7727
+ const heading = normalizeClickUpMarkdown(title);
7728
+ if (heading) lines.push(`## ${heading}`, "");
7729
+ const intro = normalizeClickUpMarkdown(summary);
7730
+ if (intro) lines.push(intro, "");
7731
+ for (const section of sections) {
7732
+ const sectionTitle = normalizeClickUpMarkdown(section?.title);
7733
+ const sectionBody = normalizeClickUpMarkdown(section?.body);
7734
+ if (!sectionTitle || !sectionBody) continue;
7735
+ lines.push(`### ${sectionTitle}`, sectionBody, "");
7736
+ }
7737
+ const contextLines = context.map(normalizeClickUpMarkdown).filter(Boolean);
7738
+ if (contextLines.length > 0) lines.push("### Context", contextLines.map((item) => item.startsWith("- ") ? item : `- ${item}`).join("\n"));
7739
+ return normalizeClickUpMarkdown(lines.join("\n"));
7740
+ }
7741
+ function normalizeClickUpPayloadComments(value) {
7742
+ if (Array.isArray(value)) return value.map(normalizeClickUpPayloadComments);
7743
+ if (!value || typeof value !== "object") return value;
7744
+ return Object.fromEntries(
7745
+ Object.entries(value).map(([key, entry]) => [
7746
+ key,
7747
+ COMMENT_TEXT_KEYS.has(key) && typeof entry === "string" ? normalizeClickUpMarkdown(entry) : normalizeClickUpPayloadComments(entry)
7748
+ ])
7749
+ );
7750
+ }
7751
+
7720
7752
  // src/git_utils.js
7721
7753
  import fs from "node:fs";
7722
7754
  import path from "node:path";
@@ -7795,24 +7827,438 @@ function stageGitAwareMerge(sourcePath, destinationPath, gitState) {
7795
7827
  }
7796
7828
  }
7797
7829
 
7798
- // src/include_resolver.js
7830
+ // src/github.js
7831
+ import crypto from "node:crypto";
7832
+ import fs3 from "node:fs";
7833
+ import path3 from "node:path";
7834
+
7835
+ // src/secrets.js
7799
7836
  import fs2 from "node:fs";
7837
+ import os from "node:os";
7800
7838
  import path2 from "node:path";
7839
+ function expandHomePath(value = "") {
7840
+ const input = String(value || "").trim();
7841
+ if (input === "~") return os.homedir();
7842
+ if (input.startsWith("~/")) return path2.join(os.homedir(), input.slice(2));
7843
+ return input;
7844
+ }
7845
+ function resolveSecretReference(value = "") {
7846
+ const raw = String(value || "").trim();
7847
+ const envMatch = raw.match(/^\{env:([A-Za-z_][A-Za-z0-9_]*)\}$/);
7848
+ if (envMatch) return process.env[envMatch[1]] || "";
7849
+ const fileMatch = raw.match(/^\{file:(.+)\}$/);
7850
+ if (fileMatch) {
7851
+ try {
7852
+ return fs2.readFileSync(expandHomePath(fileMatch[1]), "utf8").trim();
7853
+ } catch {
7854
+ return "";
7855
+ }
7856
+ }
7857
+ return raw;
7858
+ }
7859
+
7860
+ // src/github.js
7861
+ function base64UrlJson(value) {
7862
+ return Buffer.from(JSON.stringify(value)).toString("base64url");
7863
+ }
7864
+ function resolveGitHubAppPrivateKey(app = {}) {
7865
+ const direct = resolveSecretReference(app.privateKey || "");
7866
+ if (direct) return direct.replace(/\\n/g, "\n");
7867
+ const file = expandHomePath(app.privateKeyFile || "");
7868
+ if (!file) return "";
7869
+ try {
7870
+ return fs3.readFileSync(file, "utf8").trim().replace(/\\n/g, "\n");
7871
+ } catch {
7872
+ return "";
7873
+ }
7874
+ }
7875
+ function createGitHubAppJwt({ appId, privateKey, now = () => /* @__PURE__ */ new Date() } = {}) {
7876
+ const key = String(privateKey || "").trim();
7877
+ const issuer = String(appId || "").trim();
7878
+ if (!issuer || !key) throw new Error("GitHub App app_id and private key are required");
7879
+ const nowSeconds = Math.floor(now().getTime() / 1e3);
7880
+ const header = base64UrlJson({ alg: "RS256", typ: "JWT" });
7881
+ const payload = base64UrlJson({ iat: nowSeconds - 60, exp: nowSeconds + 540, iss: issuer });
7882
+ const unsigned = `${header}.${payload}`;
7883
+ const signature = crypto.createSign("RSA-SHA256").update(unsigned).end().sign(key, "base64url");
7884
+ return `${unsigned}.${signature}`;
7885
+ }
7886
+ function encodeGitHubPathSegment(value) {
7887
+ return encodeURIComponent(String(value || ""));
7888
+ }
7889
+ function encodeGitHubBranchRef(branch = "") {
7890
+ return String(branch || "").split("/").map(encodeGitHubPathSegment).join("/");
7891
+ }
7892
+ function parseNullSeparatedGitOutput(output = "") {
7893
+ return String(output || "").split("\0").map((item) => item.trim()).filter(Boolean);
7894
+ }
7895
+ function listWorktreeChangedPaths(worktree, runGitFn = runGit) {
7896
+ const tracked = parseNullSeparatedGitOutput(runGitFn(worktree, ["diff", "--name-only", "-z", "HEAD", "--"]));
7897
+ const untracked = parseNullSeparatedGitOutput(runGitFn(worktree, ["ls-files", "--others", "--exclude-standard", "-z", "--"]));
7898
+ return [.../* @__PURE__ */ new Set([...tracked, ...untracked])].filter((item) => item && !item.startsWith("../") && !path3.isAbsolute(item));
7899
+ }
7900
+ function currentGitBranch(worktree, runGitFn = runGit) {
7901
+ return String(runGitFn(worktree, ["rev-parse", "--abbrev-ref", "HEAD"]) || "").trim();
7902
+ }
7903
+ function treeEntryForWorktreePath(worktree, gitPath) {
7904
+ const absolutePath = path3.join(worktree, ...String(gitPath || "").split("/"));
7905
+ if (!fs3.existsSync(absolutePath)) return { path: gitPath, mode: "100644", type: "blob", sha: null, deleted: true };
7906
+ const stat = fs3.lstatSync(absolutePath);
7907
+ if (stat.isDirectory()) return null;
7908
+ if (stat.isSymbolicLink()) {
7909
+ return {
7910
+ path: gitPath,
7911
+ mode: "120000",
7912
+ type: "blob",
7913
+ content: fs3.readlinkSync(absolutePath),
7914
+ encoding: "utf-8"
7915
+ };
7916
+ }
7917
+ return {
7918
+ path: gitPath,
7919
+ mode: stat.mode & 73 ? "100755" : "100644",
7920
+ type: "blob",
7921
+ content: fs3.readFileSync(absolutePath).toString("base64"),
7922
+ encoding: "base64"
7923
+ };
7924
+ }
7925
+ function appendGitHubQuery(pathname, params = {}) {
7926
+ const query = new URLSearchParams();
7927
+ for (const [key, value] of Object.entries(params || {})) {
7928
+ if (value === void 0 || value === null || value === "") continue;
7929
+ query.set(key, String(value));
7930
+ }
7931
+ const suffix = query.toString();
7932
+ return suffix ? `${pathname}?${suffix}` : pathname;
7933
+ }
7934
+ function timestampMs(value = "") {
7935
+ const parsed = Date.parse(String(value || ""));
7936
+ return Number.isFinite(parsed) ? parsed : 0;
7937
+ }
7938
+ function sortNewestFirst(items = []) {
7939
+ return [...items].sort((a, b) => {
7940
+ const bTime = Math.max(timestampMs(b?.updated_at), timestampMs(b?.created_at));
7941
+ const aTime = Math.max(timestampMs(a?.updated_at), timestampMs(a?.created_at));
7942
+ return bTime - aTime;
7943
+ });
7944
+ }
7945
+ function matchesVercelStatusContext(context = "", expected = "") {
7946
+ const actual = String(context || "").trim();
7947
+ const wanted = String(expected || "").trim();
7948
+ if (wanted && actual === wanted) return true;
7949
+ const lower = actual.toLowerCase();
7950
+ if (!lower.includes("vercel")) return false;
7951
+ if (!wanted) return lower.includes("preproduction") || lower.includes("defend-preproduction");
7952
+ const wantedLower = wanted.toLowerCase();
7953
+ return wantedLower.split(/\s+|–|-/).filter((part) => part && part !== "vercel").every((part) => lower.includes(part));
7954
+ }
7955
+ function selectFunctionalDeploymentUrl(status = {}, deployment = {}) {
7956
+ for (const candidate of [
7957
+ status?.environment_url,
7958
+ deployment?.environment_url,
7959
+ status?.target_url,
7960
+ deployment?.target_url
7961
+ ]) {
7962
+ const value = String(candidate || "").trim();
7963
+ if (!value) continue;
7964
+ try {
7965
+ const url = new URL(value);
7966
+ if (url.protocol === "http:" || url.protocol === "https:") return value;
7967
+ } catch {
7968
+ }
7969
+ }
7970
+ return "";
7971
+ }
7972
+ async function checkFunctionalDeploymentUrl(url, fetchImpl = globalThis.fetch) {
7973
+ const target = String(url || "").trim();
7974
+ if (!target) return { ok: false, reason: "url_missing" };
7975
+ if (typeof fetchImpl !== "function") return { ok: false, reason: "fetch_unavailable", url: target };
7976
+ const signal = typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(8e3) : void 0;
7977
+ const probe = async (method) => {
7978
+ const response = await fetchImpl(target, { method, redirect: "follow", signal });
7979
+ return {
7980
+ ok: response.status >= 200 && response.status < 400,
7981
+ status: response.status,
7982
+ statusText: response.statusText || "",
7983
+ url: response.url || target,
7984
+ method
7985
+ };
7986
+ };
7987
+ try {
7988
+ const head = await probe("HEAD");
7989
+ if (head.ok) return head;
7990
+ const get = await probe("GET");
7991
+ return get.ok ? get : { ...get, reason: "http_not_ok" };
7992
+ } catch (error) {
7993
+ try {
7994
+ const get = await probe("GET");
7995
+ return get.ok ? get : { ...get, reason: "http_not_ok" };
7996
+ } catch (secondError) {
7997
+ return { ok: false, reason: "request_failed", url: target, error: secondError.message || error.message };
7998
+ }
7999
+ }
8000
+ }
8001
+ function createGitHubApiClient(config = {}, fetchImpl = globalThis.fetch) {
8002
+ const staticToken = resolveSecretReference(config?.apiToken);
8003
+ const appConfig = typeof config?.app === "object" && config.app !== null ? config.app : {};
8004
+ const appId = resolveSecretReference(appConfig.appId || appConfig.app_id || "");
8005
+ const installationId = resolveSecretReference(appConfig.installationId || appConfig.installation_id || "");
8006
+ const appEnabled = appConfig.enabled === true || Boolean(appId && installationId && (appConfig.privateKey || appConfig.privateKeyFile));
8007
+ const privateKey = resolveGitHubAppPrivateKey(appConfig);
8008
+ const owner = String(config?.owner || "").trim();
8009
+ const repo = String(config?.repo || "").trim();
8010
+ let installationToken = null;
8011
+ let installationTokenExpiresAt = 0;
8012
+ const requestJson = async (url, { method = "GET", headers = {}, body = void 0 } = {}) => {
8013
+ if (typeof fetchImpl !== "function") throw new Error("fetch is unavailable; inject a GitHub client for live PR lookup");
8014
+ const response = await fetchImpl(url, {
8015
+ method,
8016
+ headers: {
8017
+ Accept: "application/vnd.github+json",
8018
+ "X-GitHub-Api-Version": "2022-11-28",
8019
+ ...body === void 0 ? {} : { "Content-Type": "application/json" },
8020
+ ...headers
8021
+ },
8022
+ ...body === void 0 ? {} : { body: JSON.stringify(body) }
8023
+ });
8024
+ if (!response.ok) throw new Error(`GitHub API request failed: ${response.status}`);
8025
+ return response.status === 204 ? null : response.json();
8026
+ };
8027
+ const getAuthToken = async () => {
8028
+ if (!appEnabled) return staticToken || "";
8029
+ const nowMs = Date.now();
8030
+ if (installationToken && installationTokenExpiresAt - 6e4 > nowMs) return installationToken;
8031
+ const jwt = createGitHubAppJwt({ appId, privateKey });
8032
+ const installation = await requestJson(`https://api.github.com/app/installations/${encodeURIComponent(installationId)}/access_tokens`, {
8033
+ method: "POST",
8034
+ headers: { Authorization: `Bearer ${jwt}` }
8035
+ });
8036
+ installationToken = String(installation?.token || "").trim();
8037
+ installationTokenExpiresAt = Date.parse(installation?.expires_at || "") || nowMs + 3e6;
8038
+ if (!installationToken) throw new Error("GitHub App installation token response did not include a token");
8039
+ return installationToken;
8040
+ };
8041
+ const request = async (pathname, { method = "GET", body = void 0 } = {}) => {
8042
+ if (!owner || !repo) throw new Error("GitHub repository owner/repo is not configured");
8043
+ const token = await getAuthToken();
8044
+ return requestJson(`https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}${pathname}`, {
8045
+ method,
8046
+ body,
8047
+ headers: token ? { Authorization: `Bearer ${token}` } : {}
8048
+ });
8049
+ };
8050
+ const getRef = async (branch) => request(`/git/ref/heads/${encodeGitHubBranchRef(branch)}`);
8051
+ const getCommitObject = async (sha) => request(`/git/commits/${encodeURIComponent(sha)}`);
8052
+ const createBlob = async ({ content, encoding }) => request("/git/blobs", { method: "POST", body: { content, encoding } });
8053
+ const createTree = async ({ baseTree, tree }) => request("/git/trees", { method: "POST", body: { base_tree: baseTree, tree } });
8054
+ const createCommit = async ({ message, treeSha, parents }) => request("/git/commits", { method: "POST", body: { message, tree: treeSha, parents } });
8055
+ const updateRef = async ({ branch, sha, force = false }) => request(`/git/refs/heads/${encodeGitHubBranchRef(branch)}`, { method: "PATCH", body: { sha, force } });
8056
+ return {
8057
+ async getPullRequest(number) {
8058
+ return request(`/pulls/${encodeURIComponent(number)}`);
8059
+ },
8060
+ async createPullRequest({ title, head, base, body = "", draft = false, maintainerCanModify = true }) {
8061
+ return request("/pulls", {
8062
+ method: "POST",
8063
+ body: {
8064
+ title: String(title || ""),
8065
+ head: String(head || ""),
8066
+ base: String(base || ""),
8067
+ body: String(body || ""),
8068
+ draft: draft === true,
8069
+ maintainer_can_modify: maintainerCanModify !== false
8070
+ }
8071
+ });
8072
+ },
8073
+ async createIssueComment({ issueNumber, body }) {
8074
+ return request(`/issues/${encodeURIComponent(issueNumber)}/comments`, { method: "POST", body: { body: String(body || "") } });
8075
+ },
8076
+ async replyToReviewComment({ commentId, body }) {
8077
+ return request(`/pulls/comments/${encodeURIComponent(commentId)}/replies`, { method: "POST", body: { body: String(body || "") } });
8078
+ },
8079
+ async createPullRequestReview({ pullNumber, body, event = "COMMENT" }) {
8080
+ return request(`/pulls/${encodeURIComponent(pullNumber)}/reviews`, { method: "POST", body: { body: String(body || ""), event: String(event || "COMMENT").toUpperCase() } });
8081
+ },
8082
+ async mergePullRequest({ pullNumber, commitTitle = "", commitMessage = "", mergeMethod = "squash" }) {
8083
+ const body = { merge_method: String(mergeMethod || "squash") };
8084
+ if (commitTitle) body.commit_title = String(commitTitle);
8085
+ if (commitMessage) body.commit_message = String(commitMessage);
8086
+ return request(`/pulls/${encodeURIComponent(pullNumber)}/merge`, { method: "PUT", body });
8087
+ },
8088
+ async getCombinedStatus(ref) {
8089
+ return request(`/commits/${encodeURIComponent(String(ref || ""))}/status`);
8090
+ },
8091
+ async listDeployments({ sha = "", ref = "", environment = "", perPage = 30 } = {}) {
8092
+ return request(appendGitHubQuery("/deployments", { sha, ref, environment, per_page: perPage }));
8093
+ },
8094
+ async listDeploymentStatuses(deploymentId) {
8095
+ return request(`/deployments/${encodeURIComponent(deploymentId)}/statuses`);
8096
+ },
8097
+ async verifyVercelPullRequestDeployment({
8098
+ pullNumber,
8099
+ context = "Vercel \u2013 defend-preproduction",
8100
+ environment = "Preview \u2013 defend-preproduction",
8101
+ requireFunctionalUrl = true
8102
+ } = {}) {
8103
+ const pr = await this.getPullRequest(pullNumber);
8104
+ const headSha = String(pr?.head?.sha || "").trim();
8105
+ if (!headSha) return { ok: true, ready: false, reason: "pr_head_sha_missing", pull_request: { number: pullNumber } };
8106
+ const combined = await this.getCombinedStatus(headSha);
8107
+ const statuses = Array.isArray(combined?.statuses) ? combined.statuses : [];
8108
+ const selectedStatus = sortNewestFirst(statuses.filter((status) => matchesVercelStatusContext(status?.context, context)))[0] || null;
8109
+ if (!selectedStatus) {
8110
+ return {
8111
+ ok: true,
8112
+ ready: false,
8113
+ reason: "vercel_status_missing",
8114
+ pull_request: { number: pr.number, url: pr.html_url, head_sha: headSha },
8115
+ required_context: context,
8116
+ combined_state: combined?.state || null
8117
+ };
8118
+ }
8119
+ if (String(selectedStatus.state || "").toLowerCase() !== "success") {
8120
+ return {
8121
+ ok: true,
8122
+ ready: false,
8123
+ reason: "vercel_status_not_success",
8124
+ pull_request: { number: pr.number, url: pr.html_url, head_sha: headSha },
8125
+ required_context: context,
8126
+ status: selectedStatus,
8127
+ combined_state: combined?.state || null
8128
+ };
8129
+ }
8130
+ let deployments = await this.listDeployments({ sha: headSha, environment });
8131
+ if (!Array.isArray(deployments) || deployments.length === 0) deployments = await this.listDeployments({ sha: headSha });
8132
+ const newestDeployments = sortNewestFirst(Array.isArray(deployments) ? deployments : []);
8133
+ const selectedDeployment = newestDeployments.find((deployment) => !environment || String(deployment?.environment || "") === environment) || newestDeployments[0] || null;
8134
+ if (!selectedDeployment?.id) {
8135
+ return {
8136
+ ok: true,
8137
+ ready: false,
8138
+ reason: "vercel_deployment_missing",
8139
+ pull_request: { number: pr.number, url: pr.html_url, head_sha: headSha },
8140
+ required_environment: environment,
8141
+ status: selectedStatus
8142
+ };
8143
+ }
8144
+ const deploymentStatuses = await this.listDeploymentStatuses(selectedDeployment.id);
8145
+ const selectedDeploymentStatus = sortNewestFirst(Array.isArray(deploymentStatuses) ? deploymentStatuses : [])[0] || null;
8146
+ if (!selectedDeploymentStatus || String(selectedDeploymentStatus.state || "").toLowerCase() !== "success") {
8147
+ return {
8148
+ ok: true,
8149
+ ready: false,
8150
+ reason: "vercel_deployment_not_success",
8151
+ pull_request: { number: pr.number, url: pr.html_url, head_sha: headSha },
8152
+ required_environment: environment,
8153
+ status: selectedStatus,
8154
+ deployment: selectedDeployment,
8155
+ deployment_status: selectedDeploymentStatus
8156
+ };
8157
+ }
8158
+ const url = selectFunctionalDeploymentUrl(selectedDeploymentStatus, selectedDeployment);
8159
+ const urlCheck = requireFunctionalUrl ? await checkFunctionalDeploymentUrl(url, fetchImpl) : { ok: Boolean(url), reason: url ? void 0 : "url_missing", url };
8160
+ if (requireFunctionalUrl && !urlCheck.ok) {
8161
+ return {
8162
+ ok: true,
8163
+ ready: false,
8164
+ reason: "vercel_url_not_functional",
8165
+ pull_request: { number: pr.number, url: pr.html_url, head_sha: headSha },
8166
+ required_environment: environment,
8167
+ status: selectedStatus,
8168
+ deployment: selectedDeployment,
8169
+ deployment_status: selectedDeploymentStatus,
8170
+ url,
8171
+ url_check: urlCheck
8172
+ };
8173
+ }
8174
+ return {
8175
+ ok: true,
8176
+ ready: true,
8177
+ reason: "vercel_pr_deployment_ready",
8178
+ pull_request: { number: pr.number, url: pr.html_url, head_sha: headSha },
8179
+ required_context: context,
8180
+ required_environment: environment,
8181
+ status: selectedStatus,
8182
+ deployment: selectedDeployment,
8183
+ deployment_status: selectedDeploymentStatus,
8184
+ url,
8185
+ url_check: urlCheck
8186
+ };
8187
+ },
8188
+ async commitWorktree({ worktree, branch = "", message = "", runGitFn = runGit, syncLocal = false } = {}) {
8189
+ const directory = path3.resolve(String(worktree || ""));
8190
+ if (!directory || !fs3.existsSync(directory)) throw new Error("worktree does not exist");
8191
+ const targetBranch = String(branch || currentGitBranch(directory, runGitFn)).trim();
8192
+ if (!targetBranch || targetBranch === "HEAD") throw new Error("target branch is required for GitHub API commit");
8193
+ const commitMessage = String(message || "").trim();
8194
+ if (!commitMessage) throw new Error("commit message is required");
8195
+ const changedPaths = listWorktreeChangedPaths(directory, runGitFn);
8196
+ if (changedPaths.length === 0) return { ok: true, action: "no_changes", branch: targetBranch, changedPaths: [] };
8197
+ const ref = await getRef(targetBranch);
8198
+ const headSha = ref?.object?.sha;
8199
+ if (!headSha) throw new Error(`GitHub ref for ${targetBranch} did not include a head sha`);
8200
+ const headCommit = await getCommitObject(headSha);
8201
+ const baseTree = headCommit?.tree?.sha;
8202
+ if (!baseTree) throw new Error(`GitHub commit ${headSha} did not include a tree sha`);
8203
+ const tree = [];
8204
+ for (const gitPath of changedPaths) {
8205
+ const entry = treeEntryForWorktreePath(directory, gitPath);
8206
+ if (!entry) continue;
8207
+ if (entry.deleted) {
8208
+ tree.push({ path: entry.path, mode: entry.mode, type: entry.type, sha: null });
8209
+ continue;
8210
+ }
8211
+ const blob = await createBlob({ content: entry.content, encoding: entry.encoding });
8212
+ if (!blob?.sha) throw new Error(`GitHub blob creation failed for ${gitPath}`);
8213
+ tree.push({ path: entry.path, mode: entry.mode, type: entry.type, sha: blob.sha });
8214
+ }
8215
+ if (tree.length === 0) return { ok: true, action: "no_changes", branch: targetBranch, changedPaths: [] };
8216
+ const nextTree = await createTree({ baseTree, tree });
8217
+ const nextCommit = await createCommit({ message: commitMessage, treeSha: nextTree.sha, parents: [headSha] });
8218
+ if (!nextCommit?.sha) throw new Error("GitHub commit creation did not return a sha");
8219
+ const updatedRef = await updateRef({ branch: targetBranch, sha: nextCommit.sha, force: false });
8220
+ if (syncLocal) {
8221
+ runGitFn(directory, ["fetch", "origin", targetBranch]);
8222
+ runGitFn(directory, ["reset", "--hard", "FETCH_HEAD"]);
8223
+ }
8224
+ return {
8225
+ ok: true,
8226
+ action: "committed",
8227
+ branch: targetBranch,
8228
+ before: headSha,
8229
+ after: nextCommit.sha,
8230
+ changedPaths,
8231
+ treeEntries: tree.length,
8232
+ verification: nextCommit.verification || null,
8233
+ ref: updatedRef
8234
+ };
8235
+ },
8236
+ async authMode() {
8237
+ if (appEnabled) return { mode: "github_app", appId, installationId };
8238
+ if (staticToken) return { mode: "token" };
8239
+ return { mode: "anonymous" };
8240
+ }
8241
+ };
8242
+ }
8243
+
8244
+ // src/include_resolver.js
8245
+ import fs4 from "node:fs";
8246
+ import path4 from "node:path";
7801
8247
  function compactPromptPath(filePath) {
7802
8248
  if (!filePath.endsWith(".md") || filePath.endsWith(".prompt.md")) return null;
7803
8249
  return filePath.replace(/\.md$/, ".prompt.md");
7804
8250
  }
7805
8251
  function isSameOrNestedPath(candidate, root) {
7806
8252
  if (typeof candidate !== "string" || typeof root !== "string" || !candidate.trim() || !root.trim()) return false;
7807
- const resolvedCandidate = path2.resolve(candidate);
7808
- const resolvedRoot = path2.resolve(root);
7809
- const relative = path2.relative(resolvedRoot, resolvedCandidate);
7810
- return relative === "" || !!relative && !relative.startsWith("..") && !path2.isAbsolute(relative);
8253
+ const resolvedCandidate = path4.resolve(candidate);
8254
+ const resolvedRoot = path4.resolve(root);
8255
+ const relative = path4.relative(resolvedRoot, resolvedCandidate);
8256
+ return relative === "" || !!relative && !relative.startsWith("..") && !path4.isAbsolute(relative);
7811
8257
  }
7812
8258
  function resolveWithin(baseDir, relativePath) {
7813
8259
  if (!relativePath) return null;
7814
- if (path2.isAbsolute(relativePath)) return null;
7815
- const resolved = path2.resolve(baseDir, relativePath);
8260
+ if (path4.isAbsolute(relativePath)) return null;
8261
+ const resolved = path4.resolve(baseDir, relativePath);
7816
8262
  return isSameOrNestedPath(resolved, baseDir) ? resolved : null;
7817
8263
  }
7818
8264
  function withCompactPreference(paths, options = {}) {
@@ -7825,18 +8271,18 @@ function resolveIncludeFile(includeRef, repoRoot, bundleRoot, options = {}) {
7825
8271
  const scopedMatch = trimmed.match(/^([a-z]+):(.*)$/i);
7826
8272
  const scope = scopedMatch?.[1]?.toLowerCase();
7827
8273
  const target = scopedMatch ? scopedMatch[2].trim() : trimmed;
7828
- const optimaRoot = options.optimaRoot || path2.join(repoRoot, ".optima");
7829
- const repoPolicyRoot = options.repoPolicyRoot || path2.join(optimaRoot, "policies");
7830
- const bundlePolicyRoot = options.bundlePolicyRoot || path2.join(bundleRoot, "assets", "policies");
8274
+ const optimaRoot = options.optimaRoot || path4.join(repoRoot, ".optima");
8275
+ const repoPolicyRoot = options.repoPolicyRoot || path4.join(optimaRoot, "policies");
8276
+ const bundlePolicyRoot = options.bundlePolicyRoot || path4.join(bundleRoot, "assets", "policies");
7831
8277
  if (scope === "plugin") {
7832
8278
  for (const filePath of withCompactPreference([resolveWithin(bundleRoot, target)], options)) {
7833
- if (filePath && fs2.existsSync(filePath)) return filePath;
8279
+ if (filePath && fs4.existsSync(filePath)) return filePath;
7834
8280
  }
7835
8281
  return null;
7836
8282
  }
7837
8283
  if (scope === "repo") {
7838
8284
  for (const filePath of withCompactPreference([resolveWithin(optimaRoot, target)], options)) {
7839
- if (filePath && fs2.existsSync(filePath)) return filePath;
8285
+ if (filePath && fs4.existsSync(filePath)) return filePath;
7840
8286
  }
7841
8287
  return null;
7842
8288
  }
@@ -7846,7 +8292,7 @@ function resolveIncludeFile(includeRef, repoRoot, bundleRoot, options = {}) {
7846
8292
  resolveWithin(bundlePolicyRoot, target)
7847
8293
  ], options);
7848
8294
  for (const filePath of candidates2) {
7849
- if (filePath && fs2.existsSync(filePath)) return filePath;
8295
+ if (filePath && fs4.existsSync(filePath)) return filePath;
7850
8296
  }
7851
8297
  return null;
7852
8298
  }
@@ -7855,7 +8301,7 @@ function resolveIncludeFile(includeRef, repoRoot, bundleRoot, options = {}) {
7855
8301
  resolveWithin(bundleRoot, target)
7856
8302
  ], options);
7857
8303
  for (const filePath of candidates) {
7858
- if (filePath && fs2.existsSync(filePath)) return filePath;
8304
+ if (filePath && fs4.existsSync(filePath)) return filePath;
7859
8305
  }
7860
8306
  return null;
7861
8307
  }
@@ -7876,16 +8322,69 @@ function resolveIncludes(text, repoRoot, bundleRoot, options = {}) {
7876
8322
 
7877
8323
  `;
7878
8324
  }
7879
- const content = fs2.readFileSync(filePath, "utf8");
8325
+ const content = fs4.readFileSync(filePath, "utf8");
7880
8326
  return resolveIncludes(content, repoRoot, bundleRoot, { ...options, includeDepth: includeDepth + 1, maxIncludeDepth });
7881
8327
  });
7882
8328
  }
7883
8329
 
8330
+ // src/markdown_artifacts.js
8331
+ import fs5 from "node:fs";
8332
+ var CLICKUP_REQUIRED_SUMMARY_SECTIONS = [
8333
+ "Summary",
8334
+ "Work Performed",
8335
+ "AC Coverage",
8336
+ "Verification Results",
8337
+ "Documentation Impact",
8338
+ "Open Risks",
8339
+ "Recommended Next Step"
8340
+ ];
8341
+ var RAW_LOG_SECTION_NAMES = /* @__PURE__ */ new Set(["Raw Logs", "Logs", "Full Logs", "Command Output", "Transcript"]);
8342
+ function parseMarkdownSections(markdown = "") {
8343
+ const sections = {};
8344
+ let current = null;
8345
+ let buffer = [];
8346
+ const flush = () => {
8347
+ if (!current) return;
8348
+ sections[current] = buffer.join("\n").trim();
8349
+ };
8350
+ for (const line of String(markdown).split(/\r?\n/)) {
8351
+ const heading = /^(#{2,3})\s+(.+?)\s*$/.exec(line);
8352
+ if (heading) {
8353
+ flush();
8354
+ current = heading[2].trim();
8355
+ buffer = [];
8356
+ continue;
8357
+ }
8358
+ if (current) buffer.push(line);
8359
+ }
8360
+ flush();
8361
+ return sections;
8362
+ }
8363
+ function parseMarkdownArtifact(markdown = "", { requiredSections = [] } = {}) {
8364
+ const sections = parseMarkdownSections(markdown);
8365
+ const missing = requiredSections.filter((section) => !sections[section]);
8366
+ return {
8367
+ ok: missing.length === 0,
8368
+ sections,
8369
+ missing,
8370
+ message: missing.length ? `Missing required section(s): ${missing.join(", ")}` : "ok"
8371
+ };
8372
+ }
8373
+ function readMarkdownArtifact(filePath, options = {}) {
8374
+ const markdown = fs5.readFileSync(filePath, "utf8");
8375
+ return parseMarkdownArtifact(markdown, options);
8376
+ }
8377
+ function stripRawLogSections(sections = {}) {
8378
+ return Object.fromEntries(
8379
+ Object.entries(sections).filter(([name]) => !RAW_LOG_SECTION_NAMES.has(name))
8380
+ );
8381
+ }
8382
+
7884
8383
  // src/repair.js
7885
8384
  var import_yaml = __toESM(require_dist(), 1);
7886
8385
  var import_ignore = __toESM(require_ignore(), 1);
7887
- import fs3 from "node:fs";
7888
- import path3 from "node:path";
8386
+ import fs6 from "node:fs";
8387
+ import path5 from "node:path";
7889
8388
  var CODEMAP_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
7890
8389
  ".js",
7891
8390
  ".ts",
@@ -7923,10 +8422,10 @@ var LEGACY_OPERATIONAL_ROOTS = /* @__PURE__ */ new Set([
7923
8422
  ]);
7924
8423
  var OPTIMA_OPERATIONAL_FOLDERS = [".optima", "templates", "dist"];
7925
8424
  function relPath(worktree, targetPath) {
7926
- return path3.relative(worktree, targetPath).split(path3.sep).join("/") || ".";
8425
+ return path5.relative(worktree, targetPath).split(path5.sep).join("/") || ".";
7927
8426
  }
7928
8427
  function normalizeCodemapRelPath(relPathValue) {
7929
- return path3.normalize(relPathValue).replace(/\\/g, "/").replace(/\/$/, "");
8428
+ return path5.normalize(relPathValue).replace(/\\/g, "/").replace(/\/$/, "");
7930
8429
  }
7931
8430
  function firstPathSegment(relPathValue) {
7932
8431
  return normalizeCodemapRelPath(relPathValue).split("/").filter(Boolean)[0] || "";
@@ -7945,8 +8444,8 @@ function isHiddenTree(relPathValue) {
7945
8444
  function loadGitIgnoreMatcher(worktree) {
7946
8445
  const ig = (0, import_ignore.default)();
7947
8446
  ig.add(".git");
7948
- const gitignorePath = path3.join(worktree, ".gitignore");
7949
- if (fs3.existsSync(gitignorePath)) ig.add(fs3.readFileSync(gitignorePath, "utf8"));
8447
+ const gitignorePath = path5.join(worktree, ".gitignore");
8448
+ if (fs6.existsSync(gitignorePath)) ig.add(fs6.readFileSync(gitignorePath, "utf8"));
7950
8449
  return ig;
7951
8450
  }
7952
8451
  function codemapSectionEntries(value) {
@@ -7965,7 +8464,7 @@ function codemapIndexedPaths(map) {
7965
8464
  }
7966
8465
  function readCodemap(filePath, unresolved, worktree) {
7967
8466
  try {
7968
- const parsed = import_yaml.default.parse(fs3.readFileSync(filePath, "utf8"));
8467
+ const parsed = import_yaml.default.parse(fs6.readFileSync(filePath, "utf8"));
7969
8468
  if (!parsed || typeof parsed !== "object") {
7970
8469
  unresolved.push({ category: "codemap", path: relPath(worktree, filePath), message: "CodeMap is empty or invalid; manual repair required." });
7971
8470
  return null;
@@ -7977,42 +8476,42 @@ function readCodemap(filePath, unresolved, worktree) {
7977
8476
  }
7978
8477
  }
7979
8478
  function writeCodemap(filePath, map) {
7980
- fs3.writeFileSync(filePath, import_yaml.default.stringify(map), "utf8");
8479
+ fs6.writeFileSync(filePath, import_yaml.default.stringify(map), "utf8");
7981
8480
  }
7982
8481
  function isIgnoredPath(ig, relativePath) {
7983
8482
  const normalized = normalizeCodemapRelPath(relativePath);
7984
8483
  return Boolean(normalized) && ig.ignores(normalized);
7985
8484
  }
7986
8485
  function hasImmediateSourceFile(dirPath, ig, worktree) {
7987
- if (!fs3.existsSync(dirPath)) return false;
7988
- for (const item of fs3.readdirSync(dirPath, { withFileTypes: true })) {
7989
- const childPath = path3.join(dirPath, item.name);
7990
- const relative = path3.relative(worktree, childPath);
8486
+ if (!fs6.existsSync(dirPath)) return false;
8487
+ for (const item of fs6.readdirSync(dirPath, { withFileTypes: true })) {
8488
+ const childPath = path5.join(dirPath, item.name);
8489
+ const relative = path5.relative(worktree, childPath);
7991
8490
  if (isIgnoredPath(ig, relative) || isOperationalRelPath(relative)) continue;
7992
- if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(path3.extname(item.name))) return true;
8491
+ if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(path5.extname(item.name))) return true;
7993
8492
  }
7994
8493
  return false;
7995
8494
  }
7996
8495
  function containsSource(dirPath, ig, worktree) {
7997
- if (!fs3.existsSync(dirPath)) return false;
7998
- const dirRelPath = path3.relative(worktree, dirPath);
8496
+ if (!fs6.existsSync(dirPath)) return false;
8497
+ const dirRelPath = path5.relative(worktree, dirPath);
7999
8498
  if (isOperationalRelPath(dirRelPath) || isHiddenTree(dirRelPath)) return false;
8000
- for (const item of fs3.readdirSync(dirPath, { withFileTypes: true })) {
8001
- const childPath = path3.join(dirPath, item.name);
8002
- const relative = path3.relative(worktree, childPath);
8499
+ for (const item of fs6.readdirSync(dirPath, { withFileTypes: true })) {
8500
+ const childPath = path5.join(dirPath, item.name);
8501
+ const relative = path5.relative(worktree, childPath);
8003
8502
  if (isIgnoredPath(ig, relative) || isOperationalRelPath(relative) || isHiddenTree(relative)) continue;
8004
- if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(path3.extname(item.name))) return true;
8503
+ if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(path5.extname(item.name))) return true;
8005
8504
  if (item.isDirectory() && containsSource(childPath, ig, worktree)) return true;
8006
8505
  }
8007
8506
  return false;
8008
8507
  }
8009
8508
  function createModuleCodemap(dirPath, worktree, deps) {
8010
- const entries = fs3.readdirSync(dirPath, { withFileTypes: true });
8509
+ const entries = fs6.readdirSync(dirPath, { withFileTypes: true });
8011
8510
  const entrypoints = [];
8012
8511
  const internals = [];
8013
- const relToRoot = path3.relative(dirPath, deps.optimaCodemapPath(worktree)).split(path3.sep).join("/");
8512
+ const relToRoot = path5.relative(dirPath, deps.optimaCodemapPath(worktree)).split(path5.sep).join("/");
8014
8513
  for (const item of entries) {
8015
- if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(path3.extname(item.name))) continue;
8514
+ if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(path5.extname(item.name))) continue;
8016
8515
  const bucket = /^index\.(js|ts|tsx|jsx)$|^main\.(js|ts|tsx|jsx|py|go|rs|java)$/.test(item.name) ? entrypoints : internals;
8017
8516
  bucket.push({ path: item.name });
8018
8517
  }
@@ -8025,7 +8524,7 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
8025
8524
  const map = readCodemap(codemapPath, unresolved, worktree);
8026
8525
  if (!map) return;
8027
8526
  const isRootMap = codemapPath === deps.optimaCodemapPath(worktree);
8028
- const mapDir = path3.dirname(codemapPath);
8527
+ const mapDir = path5.dirname(codemapPath);
8029
8528
  const pathBase = isRootMap ? worktree : mapDir;
8030
8529
  let changed = false;
8031
8530
  for (const section of ["modules", "entrypoints", "sources_of_truth", "links", "internals"]) {
@@ -8036,13 +8535,13 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
8036
8535
  }
8037
8536
  const nextEntries = [];
8038
8537
  for (const entry of originalEntries) {
8039
- if (!entry?.path || entry.path.startsWith("http://") || entry.path.startsWith("https://") || path3.isAbsolute(entry.path)) {
8538
+ if (!entry?.path || entry.path.startsWith("http://") || entry.path.startsWith("https://") || path5.isAbsolute(entry.path)) {
8040
8539
  nextEntries.push(entry);
8041
8540
  continue;
8042
8541
  }
8043
8542
  const normalizedPath = normalizeCodemapRelPath(entry.path);
8044
- const absPath = path3.join(pathBase, normalizedPath);
8045
- if (!fs3.existsSync(absPath)) {
8543
+ const absPath = path5.join(pathBase, normalizedPath);
8544
+ if (!fs6.existsSync(absPath)) {
8046
8545
  registerAction({ category: "codemap", action: apply ? "removed" : "would_remove", path: relPath(worktree, codemapPath), detail: `Remove broken ${section.slice(0, -1)} reference '${entry.path}'.` });
8047
8546
  changed = true;
8048
8547
  continue;
@@ -8051,8 +8550,8 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
8051
8550
  const maxParts = isRootMap ? 2 : 1;
8052
8551
  if (parts.length > maxParts) {
8053
8552
  const localPath = isRootMap ? parts.slice(0, 2).join("/") : parts[0];
8054
- const localAbs = path3.join(pathBase, localPath);
8055
- if (fs3.existsSync(localAbs)) {
8553
+ const localAbs = path5.join(pathBase, localPath);
8554
+ if (fs6.existsSync(localAbs)) {
8056
8555
  nextEntries.push({ ...entry, path: localPath });
8057
8556
  changed = true;
8058
8557
  registerAction({ category: "codemap", action: apply ? "updated" : "would_update", path: relPath(worktree, codemapPath), detail: `Shorten '${entry.path}' to local path '${localPath}'.` });
@@ -8066,11 +8565,11 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
8066
8565
  }
8067
8566
  if (Array.isArray(map[section])) map[section] = nextEntries;
8068
8567
  }
8069
- if (map.scope === "module" && !isOperationalRelPath(path3.relative(worktree, mapDir))) {
8568
+ if (map.scope === "module" && !isOperationalRelPath(path5.relative(worktree, mapDir))) {
8070
8569
  const indexed = codemapIndexedPaths(map);
8071
8570
  const internals = Array.isArray(map.internals) ? map.internals : [];
8072
- for (const item of fs3.readdirSync(mapDir, { withFileTypes: true })) {
8073
- if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(path3.extname(item.name))) continue;
8571
+ for (const item of fs6.readdirSync(mapDir, { withFileTypes: true })) {
8572
+ if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(path5.extname(item.name))) continue;
8074
8573
  if (indexed.has(item.name)) continue;
8075
8574
  internals.push({ path: item.name });
8076
8575
  indexed.add(item.name);
@@ -8084,13 +8583,13 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
8084
8583
  function repairCodemaps(worktree, apply, actions, unresolved, deps) {
8085
8584
  const ig = loadGitIgnoreMatcher(worktree);
8086
8585
  const rootCodemapPath = deps.optimaCodemapPath(worktree);
8087
- const rootCodemapMissing = !fs3.existsSync(rootCodemapPath);
8586
+ const rootCodemapMissing = !fs6.existsSync(rootCodemapPath);
8088
8587
  if (rootCodemapMissing) {
8089
8588
  actions.push({ category: "codemap", action: apply ? "created" : "would_create", path: ".optima/codemap.yml", detail: "Create missing root CodeMap from template." });
8090
8589
  if (apply) deps.scaffoldOptimaRootCodemap(worktree);
8091
8590
  }
8092
- if (fs3.existsSync(rootCodemapPath)) repairSingleCodemap(rootCodemapPath, worktree, apply, (action) => actions.push(action), unresolved, deps);
8093
- const rootMap = fs3.existsSync(rootCodemapPath) ? readCodemap(rootCodemapPath, unresolved, worktree) : null;
8591
+ if (fs6.existsSync(rootCodemapPath)) repairSingleCodemap(rootCodemapPath, worktree, apply, (action) => actions.push(action), unresolved, deps);
8592
+ const rootMap = fs6.existsSync(rootCodemapPath) ? readCodemap(rootCodemapPath, unresolved, worktree) : null;
8094
8593
  let rootChanged = false;
8095
8594
  const rootModulesRepairable = rootMap && (rootMap.modules === void 0 || Array.isArray(rootMap.modules));
8096
8595
  if (rootMap) {
@@ -8102,10 +8601,10 @@ function repairCodemaps(worktree, apply, actions, unresolved, deps) {
8102
8601
  }
8103
8602
  }
8104
8603
  function walk(dirPath) {
8105
- const relative = path3.relative(worktree, dirPath);
8604
+ const relative = path5.relative(worktree, dirPath);
8106
8605
  if (relative && (isIgnoredPath(ig, relative) || isOperationalRelPath(relative) || isHiddenTree(relative))) return;
8107
- const codemapPath = path3.join(dirPath, "codemap.yml");
8108
- const hasCodemap = fs3.existsSync(codemapPath);
8606
+ const codemapPath = path5.join(dirPath, "codemap.yml");
8607
+ const hasCodemap = fs6.existsSync(codemapPath);
8109
8608
  const sourceDir = relative && containsSource(dirPath, ig, worktree);
8110
8609
  if (sourceDir && !hasCodemap && dirPath !== worktree) {
8111
8610
  if (hasImmediateSourceFile(dirPath, ig, worktree)) {
@@ -8124,19 +8623,19 @@ function repairCodemaps(worktree, apply, actions, unresolved, deps) {
8124
8623
  actions.push({ category: "codemap", action: apply ? "updated" : "would_update", path: ".optima/codemap.yml", detail: `Register top-level source module '${normalizeCodemapRelPath(relative)}'.` });
8125
8624
  }
8126
8625
  }
8127
- if (fs3.existsSync(codemapPath) && codemapPath !== rootCodemapPath) repairSingleCodemap(codemapPath, worktree, apply, (action) => actions.push(action), unresolved, deps);
8128
- for (const item of fs3.readdirSync(dirPath, { withFileTypes: true })) {
8129
- if (item.isDirectory()) walk(path3.join(dirPath, item.name));
8626
+ if (fs6.existsSync(codemapPath) && codemapPath !== rootCodemapPath) repairSingleCodemap(codemapPath, worktree, apply, (action) => actions.push(action), unresolved, deps);
8627
+ for (const item of fs6.readdirSync(dirPath, { withFileTypes: true })) {
8628
+ if (item.isDirectory()) walk(path5.join(dirPath, item.name));
8130
8629
  }
8131
8630
  }
8132
- if (fs3.existsSync(worktree)) walk(worktree);
8631
+ if (fs6.existsSync(worktree)) walk(worktree);
8133
8632
  if (rootMap && rootChanged && apply) writeCodemap(rootCodemapPath, rootMap);
8134
8633
  }
8135
8634
  function walkMarkdownFiles(dirPath) {
8136
- if (!fs3.existsSync(dirPath)) return [];
8635
+ if (!fs6.existsSync(dirPath)) return [];
8137
8636
  const files = [];
8138
- for (const entry of fs3.readdirSync(dirPath, { withFileTypes: true })) {
8139
- const entryPath = path3.join(dirPath, entry.name);
8637
+ for (const entry of fs6.readdirSync(dirPath, { withFileTypes: true })) {
8638
+ const entryPath = path5.join(dirPath, entry.name);
8140
8639
  if (entry.isDirectory()) {
8141
8640
  files.push(...walkMarkdownFiles(entryPath));
8142
8641
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -8175,7 +8674,7 @@ function rewriteOptimaMarkdownReferences(content, evidenceBasePath = null) {
8175
8674
  }
8176
8675
  function optimaEvidenceBaseForFile(worktree, filePath, deps) {
8177
8676
  const evidenceRoot = deps.optimaEvidencesDir(worktree);
8178
- const relative = path3.relative(evidenceRoot, filePath).split(path3.sep).join("/");
8677
+ const relative = path5.relative(evidenceRoot, filePath).split(path5.sep).join("/");
8179
8678
  const [taskId] = relative.split("/");
8180
8679
  if (!taskId || taskId === ".." || relative.startsWith("../")) return null;
8181
8680
  return `.optima/evidences/${taskId}`;
@@ -8188,11 +8687,11 @@ function normalizeOptimaMarkdownReferences(worktree, deps) {
8188
8687
  ];
8189
8688
  const changed = [];
8190
8689
  for (const filePath of scanRoots.flatMap(walkMarkdownFiles)) {
8191
- const raw = fs3.readFileSync(filePath, "utf8");
8192
- const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) + path3.sep) ? optimaEvidenceBaseForFile(worktree, filePath, deps) : null;
8690
+ const raw = fs6.readFileSync(filePath, "utf8");
8691
+ const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) + path5.sep) ? optimaEvidenceBaseForFile(worktree, filePath, deps) : null;
8193
8692
  const rewritten = rewriteOptimaMarkdownReferences(raw, evidenceBasePath);
8194
8693
  if (rewritten !== raw) {
8195
- fs3.writeFileSync(filePath, rewritten, "utf8");
8694
+ fs6.writeFileSync(filePath, rewritten, "utf8");
8196
8695
  changed.push(relPath(worktree, filePath));
8197
8696
  }
8198
8697
  }
@@ -8200,8 +8699,8 @@ function normalizeOptimaMarkdownReferences(worktree, deps) {
8200
8699
  }
8201
8700
  function missingOptimaGitignoreRules(worktree, deps) {
8202
8701
  if (!deps.isGitRepository(worktree)) return [];
8203
- const gitignorePath = path3.join(worktree, ".gitignore");
8204
- const existing = fs3.existsSync(gitignorePath) ? fs3.readFileSync(gitignorePath, "utf8") : "";
8702
+ const gitignorePath = path5.join(worktree, ".gitignore");
8703
+ const existing = fs6.existsSync(gitignorePath) ? fs6.readFileSync(gitignorePath, "utf8") : "";
8205
8704
  const existingRules = new Set(existing.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
8206
8705
  return deps.optimaGitignoreRules.filter((rule) => !existingRules.has(rule));
8207
8706
  }
@@ -8218,11 +8717,11 @@ function planOptimaRepair(worktree, args = {}, deps) {
8218
8717
  const apply = mode === "apply";
8219
8718
  const actions = [];
8220
8719
  const unresolved = [];
8221
- const hadOptima = fs3.existsSync(deps.optimaDir(worktree));
8720
+ const hadOptima = fs6.existsSync(deps.optimaDir(worktree));
8222
8721
  const missingGitignoreRules = missingOptimaGitignoreRules(worktree, deps);
8223
8722
  const markdownBefore = apply ? [] : walkMarkdownFiles(deps.optimaDir(worktree)).filter((filePath) => {
8224
- const raw = fs3.readFileSync(filePath, "utf8");
8225
- const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) + path3.sep) ? optimaEvidenceBaseForFile(worktree, filePath, deps) : null;
8723
+ const raw = fs6.readFileSync(filePath, "utf8");
8724
+ const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) + path5.sep) ? optimaEvidenceBaseForFile(worktree, filePath, deps) : null;
8226
8725
  return rewriteOptimaMarkdownReferences(raw, evidenceBasePath) !== raw;
8227
8726
  }).map((filePath) => relPath(worktree, filePath));
8228
8727
  if (!hadOptima) pushRepairAction(actions, "operational", apply ? "created" : "would_create", ".optima/", "Create Optima operational root.");
@@ -8231,31 +8730,31 @@ function planOptimaRepair(worktree, args = {}, deps) {
8231
8730
  [".staticeng/", deps.legacyStaticEngDir(worktree)],
8232
8731
  [".nomadwork/", deps.legacyNomadworkDir(worktree)],
8233
8732
  [".nomadworks/", deps.legacyNomadworksDir(worktree)],
8234
- ["tasks/", path3.join(worktree, "tasks")],
8235
- ["evidences/", path3.join(worktree, "evidences")],
8236
- ["docs/scrs/", path3.join(worktree, "docs", "scrs")],
8237
- ["codemap.yml", path3.join(worktree, "codemap.yml")],
8238
- ["codemap.yaml", path3.join(worktree, "codemap.yaml")]
8733
+ ["tasks/", path5.join(worktree, "tasks")],
8734
+ ["evidences/", path5.join(worktree, "evidences")],
8735
+ ["docs/scrs/", path5.join(worktree, "docs", "scrs")],
8736
+ ["codemap.yml", path5.join(worktree, "codemap.yml")],
8737
+ ["codemap.yaml", path5.join(worktree, "codemap.yaml")]
8239
8738
  ];
8240
- if (!deps.isOptimaPluginPackageWorktree(worktree)) legacySources.push(["policies/", path3.join(worktree, "policies")]);
8739
+ if (!deps.isOptimaPluginPackageWorktree(worktree)) legacySources.push(["policies/", path5.join(worktree, "policies")]);
8241
8740
  for (const [display, sourcePath] of legacySources) {
8242
- if (fs3.existsSync(sourcePath)) pushRepairAction(actions, "legacy", apply ? "migrated" : "would_migrate", display, "Move or merge legacy/root Optima artifact into .optima using preservation safeguards.");
8741
+ if (fs6.existsSync(sourcePath)) pushRepairAction(actions, "legacy", apply ? "migrated" : "would_migrate", display, "Move or merge legacy/root Optima artifact into .optima using preservation safeguards.");
8243
8742
  }
8244
8743
  if (apply) deps.migrateLegacyOptimaLayout(worktree);
8245
- const configMissing = !fs3.existsSync(deps.repoConfigPath(worktree));
8744
+ const configMissing = !fs6.existsSync(deps.repoConfigPath(worktree));
8246
8745
  if (configMissing) pushRepairAction(actions, "config", apply ? "created" : "would_create", ".optima/.config/optima.yaml", "Create missing local Optima config from template.");
8247
8746
  if (apply) deps.scaffoldOptimaConfig(worktree, args.team_mode || "full");
8248
8747
  const requiredFiles = [
8249
- [path3.join(deps.optimaTasksDir(worktree), "current.md"), "registry", ".optima/tasks/current.md", deps.currentTasksRegistryContent()],
8250
- [path3.join(deps.optimaTasksDir(worktree), "done.md"), "registry", ".optima/tasks/done.md", deps.doneTasksRegistryContent()],
8251
- [path3.join(deps.optimaScrsDir(worktree), "current.md"), "registry", ".optima/docs/scrs/current.md", deps.currentScrRegistryContent()],
8252
- [path3.join(deps.optimaScrsDir(worktree), "done.md"), "registry", ".optima/docs/scrs/done.md", deps.doneScrRegistryContent()],
8253
- [path3.join(deps.optimaTasksDir(worktree), "task-template.md"), "template", ".optima/tasks/task-template.md", deps.taskTemplateContent()],
8254
- [path3.join(deps.optimaTasksDir(worktree), "subtask-template.md"), "template", ".optima/tasks/subtask-template.md", deps.subtaskTemplateContent()],
8255
- [path3.join(deps.repoPoliciesDir(worktree), "README.md"), "policy", ".optima/policies/README.md", deps.repoLocalPoliciesReadme]
8748
+ [path5.join(deps.optimaTasksDir(worktree), "current.md"), "registry", ".optima/tasks/current.md", deps.currentTasksRegistryContent()],
8749
+ [path5.join(deps.optimaTasksDir(worktree), "done.md"), "registry", ".optima/tasks/done.md", deps.doneTasksRegistryContent()],
8750
+ [path5.join(deps.optimaScrsDir(worktree), "current.md"), "registry", ".optima/docs/scrs/current.md", deps.currentScrRegistryContent()],
8751
+ [path5.join(deps.optimaScrsDir(worktree), "done.md"), "registry", ".optima/docs/scrs/done.md", deps.doneScrRegistryContent()],
8752
+ [path5.join(deps.optimaTasksDir(worktree), "task-template.md"), "template", ".optima/tasks/task-template.md", deps.taskTemplateContent()],
8753
+ [path5.join(deps.optimaTasksDir(worktree), "subtask-template.md"), "template", ".optima/tasks/subtask-template.md", deps.subtaskTemplateContent()],
8754
+ [path5.join(deps.repoPoliciesDir(worktree), "README.md"), "policy", ".optima/policies/README.md", deps.repoLocalPoliciesReadme]
8256
8755
  ];
8257
8756
  for (const [filePath, category, displayPath, content] of requiredFiles) {
8258
- if (!fs3.existsSync(filePath)) {
8757
+ if (!fs6.existsSync(filePath)) {
8259
8758
  pushRepairAction(actions, category, apply ? "created" : "would_create", displayPath, "Create missing Optima scaffold file without overwriting existing content.");
8260
8759
  if (apply) deps.ensureFileIfMissing(filePath, content);
8261
8760
  }
@@ -8309,18 +8808,18 @@ function formatRepairResult(plan, validationResult = null, formatValidationResul
8309
8808
  // src/validate_logic.js
8310
8809
  var import_yaml2 = __toESM(require_dist(), 1);
8311
8810
  var import_ignore2 = __toESM(require_ignore(), 1);
8312
- import fs4 from "node:fs";
8313
- import path4 from "node:path";
8811
+ import fs7 from "node:fs";
8812
+ import path6 from "node:path";
8314
8813
  async function optima_validate_logic(worktree) {
8315
- const rootCodemapPath = path4.join(worktree, ".optima", "codemap.yml");
8316
- if (!fs4.existsSync(rootCodemapPath)) return { ok: false, errors: [".optima/codemap.yml not found."], warnings: [] };
8814
+ const rootCodemapPath = path6.join(worktree, ".optima", "codemap.yml");
8815
+ if (!fs7.existsSync(rootCodemapPath)) return { ok: false, errors: [".optima/codemap.yml not found."], warnings: [] };
8317
8816
  const errors = [];
8318
8817
  const warnings = [];
8319
8818
  const ig = (0, import_ignore2.default)();
8320
8819
  ig.add(".git");
8321
- const gitignorePath = path4.join(worktree, ".gitignore");
8322
- if (fs4.existsSync(gitignorePath)) {
8323
- ig.add(fs4.readFileSync(gitignorePath, "utf8"));
8820
+ const gitignorePath = path6.join(worktree, ".gitignore");
8821
+ if (fs7.existsSync(gitignorePath)) {
8822
+ ig.add(fs7.readFileSync(gitignorePath, "utf8"));
8324
8823
  }
8325
8824
  const sourceExtensions = [
8326
8825
  ".js",
@@ -8360,30 +8859,30 @@ async function optima_validate_logic(worktree) {
8360
8859
  const operationalFolders = [".optima", "templates", "dist"];
8361
8860
  const isHiddenTree2 = (relPath2) => {
8362
8861
  if (!relPath2) return false;
8363
- return relPath2.split(path4.sep).some((part) => part.startsWith("."));
8862
+ return relPath2.split(path6.sep).some((part) => part.startsWith("."));
8364
8863
  };
8365
- const firstPathSegment2 = (relPath2) => relPath2.split(path4.sep).filter(Boolean)[0] || "";
8864
+ const firstPathSegment2 = (relPath2) => relPath2.split(path6.sep).filter(Boolean)[0] || "";
8366
8865
  const isOperationalRelPath2 = (relPath2) => {
8367
8866
  if (!relPath2) return false;
8368
8867
  const firstSegment = firstPathSegment2(relPath2);
8369
8868
  if (legacyOperationalRoots.has(firstSegment)) return true;
8370
- return operationalFolders.some((f) => relPath2 === f || relPath2.startsWith(f + path4.sep));
8869
+ return operationalFolders.some((f) => relPath2 === f || relPath2.startsWith(f + path6.sep));
8371
8870
  };
8372
8871
  const getSectionEntries = (value) => {
8373
8872
  if (Array.isArray(value)) return value;
8374
8873
  if (value && typeof value === "object") return Object.values(value);
8375
8874
  return [];
8376
8875
  };
8377
- const normalizeRelativePath = (relPath2) => path4.normalize(relPath2).replace(/\\/g, "/").replace(/\/$/, "");
8876
+ const normalizeRelativePath = (relPath2) => path6.normalize(relPath2).replace(/\\/g, "/").replace(/\/$/, "");
8378
8877
  const isSourceDir = (dirPath) => {
8379
- const dirRelPath = path4.relative(worktree, dirPath);
8878
+ const dirRelPath = path6.relative(worktree, dirPath);
8380
8879
  if (isOperationalRelPath2(dirRelPath)) return false;
8381
- const items = fs4.readdirSync(dirPath, { withFileTypes: true });
8880
+ const items = fs7.readdirSync(dirPath, { withFileTypes: true });
8382
8881
  for (const item of items) {
8383
- const childPath = path4.join(dirPath, item.name);
8384
- const relPath2 = path4.relative(worktree, childPath);
8882
+ const childPath = path6.join(dirPath, item.name);
8883
+ const relPath2 = path6.relative(worktree, childPath);
8385
8884
  if (ig.ignores(relPath2) || isOperationalRelPath2(relPath2)) continue;
8386
- if (item.isFile() && sourceExtensions.includes(path4.extname(item.name))) return true;
8885
+ if (item.isFile() && sourceExtensions.includes(path6.extname(item.name))) return true;
8387
8886
  if (item.isDirectory()) {
8388
8887
  if (isSourceDir(childPath)) return true;
8389
8888
  }
@@ -8391,7 +8890,7 @@ async function optima_validate_logic(worktree) {
8391
8890
  return false;
8392
8891
  };
8393
8892
  function validateMap(filePath) {
8394
- const content = fs4.readFileSync(filePath, "utf8");
8893
+ const content = fs7.readFileSync(filePath, "utf8");
8395
8894
  let map;
8396
8895
  try {
8397
8896
  map = import_yaml2.default.parse(content);
@@ -8403,32 +8902,32 @@ async function optima_validate_logic(worktree) {
8403
8902
  errors.push(`${filePath}: Invalid YAML.`);
8404
8903
  return;
8405
8904
  }
8406
- const dir = path4.dirname(filePath);
8905
+ const dir = path6.dirname(filePath);
8407
8906
  const pathBase = filePath === rootCodemapPath ? worktree : dir;
8408
8907
  const indexedPaths = /* @__PURE__ */ new Set();
8409
8908
  const sectionsToVerify = ["modules", "entrypoints", "sources_of_truth", "links", "internals"];
8410
8909
  for (const section of sectionsToVerify) {
8411
8910
  for (const item of getSectionEntries(map[section])) {
8412
8911
  if (item?.path) {
8413
- indexedPaths.add(path4.normalize(item.path));
8912
+ indexedPaths.add(path6.normalize(item.path));
8414
8913
  if (section === "links" && (item.path.startsWith("http://") || item.path.startsWith("https://"))) {
8415
8914
  continue;
8416
8915
  }
8417
- const absPath = path4.isAbsolute(item.path) ? item.path : path4.join(pathBase, item.path);
8418
- if (!fs4.existsSync(absPath)) {
8916
+ const absPath = path6.isAbsolute(item.path) ? item.path : path6.join(pathBase, item.path);
8917
+ if (!fs7.existsSync(absPath)) {
8419
8918
  errors.push(`${filePath}: ${section.slice(0, -1)} path does not exist: ${item.path}`);
8420
8919
  }
8421
8920
  }
8422
8921
  }
8423
8922
  }
8424
- const relDir = path4.relative(worktree, dir);
8923
+ const relDir = path6.relative(worktree, dir);
8425
8924
  const isOperational = isOperationalRelPath2(relDir);
8426
8925
  if (map.scope === "module" && !isOperational) {
8427
- const items = fs4.readdirSync(dir, { withFileTypes: true });
8926
+ const items = fs7.readdirSync(dir, { withFileTypes: true });
8428
8927
  for (const item of items) {
8429
- if (item.isFile() && sourceExtensions.includes(path4.extname(item.name))) {
8928
+ if (item.isFile() && sourceExtensions.includes(path6.extname(item.name))) {
8430
8929
  if (item.name === "codemap.yml") continue;
8431
- if (!indexedPaths.has(path4.normalize(item.name))) {
8930
+ if (!indexedPaths.has(path6.normalize(item.name))) {
8432
8931
  errors.push(`${filePath}: Unindexed source file found: '${item.name}'. Every source file must be categorized in a section (e.g., 'internals').`);
8433
8932
  }
8434
8933
  }
@@ -8438,7 +8937,7 @@ async function optima_validate_logic(worktree) {
8438
8937
  for (const key of pathKeys) {
8439
8938
  for (const entry of getSectionEntries(map[key])) {
8440
8939
  if (!entry?.path || entry.path.startsWith("http://") || entry.path.startsWith("https://")) continue;
8441
- if (path4.isAbsolute(entry.path)) continue;
8940
+ if (path6.isAbsolute(entry.path)) continue;
8442
8941
  const normalizedPath = normalizeRelativePath(entry.path);
8443
8942
  if (!normalizedPath || normalizedPath === ".") continue;
8444
8943
  const parts = normalizedPath.split("/").filter((p) => p && p !== ".");
@@ -8450,18 +8949,18 @@ async function optima_validate_logic(worktree) {
8450
8949
  }
8451
8950
  }
8452
8951
  const walk = (dir) => {
8453
- const relDir = path4.relative(worktree, dir);
8952
+ const relDir = path6.relative(worktree, dir);
8454
8953
  if (relDir && ig.ignores(relDir)) return;
8455
8954
  if (isOperationalRelPath2(relDir)) return;
8456
8955
  if (isHiddenTree2(relDir)) return;
8457
- const hasCodemap = fs4.existsSync(path4.join(dir, "codemap.yml"));
8458
- const items = fs4.readdirSync(dir, { withFileTypes: true });
8459
- if (!relDir.startsWith(path4.join(".optima", "tasks", "done"))) {
8956
+ const hasCodemap = fs7.existsSync(path6.join(dir, "codemap.yml"));
8957
+ const items = fs7.readdirSync(dir, { withFileTypes: true });
8958
+ if (!relDir.startsWith(path6.join(".optima", "tasks", "done"))) {
8460
8959
  for (const item of items) {
8461
8960
  if (item.isFile() && item.name.endsWith(".md")) {
8462
- const content = fs4.readFileSync(path4.join(dir, item.name), "utf8");
8961
+ const content = fs7.readFileSync(path6.join(dir, item.name), "utf8");
8463
8962
  if (content.includes("[To be defined]") || content.includes("[Insert ")) {
8464
- const relFilePath = path4.join(relDir, item.name);
8963
+ const relFilePath = path6.join(relDir, item.name);
8465
8964
  errors.push(`Documentation Placeholder found: '${relFilePath}' still contains [To be defined] or [Insert ...] placeholders.`);
8466
8965
  }
8467
8966
  }
@@ -8471,9 +8970,9 @@ async function optima_validate_logic(worktree) {
8471
8970
  if (relDir !== "" && !hasCodemap && isSourceDir(dir) && !isOperational) {
8472
8971
  errors.push(`Missing CodeMap: Directory '${relDir}' contains source but has no codemap.yml.`);
8473
8972
  }
8474
- if (hasCodemap) validateMap(path4.join(dir, "codemap.yml"));
8973
+ if (hasCodemap) validateMap(path6.join(dir, "codemap.yml"));
8475
8974
  for (const item of items) {
8476
- if (item.isDirectory()) walk(path4.join(dir, item.name));
8975
+ if (item.isDirectory()) walk(path6.join(dir, item.name));
8477
8976
  }
8478
8977
  };
8479
8978
  validateMap(rootCodemapPath);
@@ -8486,14 +8985,14 @@ async function optima_validate_logic(worktree) {
8486
8985
  }
8487
8986
 
8488
8987
  // src/constants.js
8489
- import path5 from "node:path";
8988
+ import path7 from "node:path";
8490
8989
  import { fileURLToPath } from "node:url";
8491
- var PKG_ROOT = path5.resolve(path5.dirname(fileURLToPath(import.meta.url)), "..");
8492
- var BUNDLE_ASSETS_DIR = path5.join(PKG_ROOT, "assets");
8493
- var BUNDLE_AGENTS_DIR = path5.join(BUNDLE_ASSETS_DIR, "agents");
8494
- var BUNDLE_POLICIES_DIR = path5.join(BUNDLE_ASSETS_DIR, "policies");
8495
- var TEMPLATES_DIR = path5.join(PKG_ROOT, "templates");
8496
- var HUMANS_REGISTRY_PATH = path5.join(PKG_ROOT, "docs", "core", "humans.md");
8990
+ var PKG_ROOT = path7.resolve(path7.dirname(fileURLToPath(import.meta.url)), "..");
8991
+ var BUNDLE_ASSETS_DIR = path7.join(PKG_ROOT, "assets");
8992
+ var BUNDLE_AGENTS_DIR = path7.join(BUNDLE_ASSETS_DIR, "agents");
8993
+ var BUNDLE_POLICIES_DIR = path7.join(BUNDLE_ASSETS_DIR, "policies");
8994
+ var TEMPLATES_DIR = path7.join(PKG_ROOT, "templates");
8995
+ var HUMANS_REGISTRY_PATH = path7.join(PKG_ROOT, "docs", "core", "humans.md");
8497
8996
  var MANDATORY_AGENTS = /* @__PURE__ */ new Set(["product_manager", "business_analyst", "tech_lead"]);
8498
8997
  var MINI_MODE_AGENTS = /* @__PURE__ */ new Set(["product_manager", "business_analyst", "tech_lead"]);
8499
8998
  var CLICKUP_IGNORED_TASK_TYPES = ["Idea", "Backlog", "Hito", "Nota de reuni\xF3n", "Respuesta del formulario"];
@@ -8631,18 +9130,18 @@ var GITHUB_WEBHOOK_EVENTS = ["pull_request", "pull_request_review", "pull_reques
8631
9130
  var OPTIMA_GITHUB_COMMITTER_NAME = "Optima Product Manager";
8632
9131
  var OPTIMA_GITHUB_COMMITTER_EMAIL = "optima-product-manager[bot]@users.noreply.github.com";
8633
9132
  function isRootDirectory(candidate) {
8634
- const resolved = path6.resolve(candidate);
8635
- return resolved === path6.parse(resolved).root;
9133
+ const resolved = path8.resolve(candidate);
9134
+ return resolved === path8.parse(resolved).root;
8636
9135
  }
8637
9136
  function isSafeWritableDirectory(candidate) {
8638
9137
  if (typeof candidate !== "string" || !candidate.trim()) return false;
8639
- if (!path6.isAbsolute(candidate)) return false;
8640
- const resolved = path6.resolve(candidate);
9138
+ if (!path8.isAbsolute(candidate)) return false;
9139
+ const resolved = path8.resolve(candidate);
8641
9140
  if (isRootDirectory(resolved)) return false;
8642
9141
  try {
8643
- const stat = fs5.statSync(resolved);
9142
+ const stat = fs8.statSync(resolved);
8644
9143
  if (!stat.isDirectory()) return false;
8645
- fs5.accessSync(resolved, fs5.constants.W_OK);
9144
+ fs8.accessSync(resolved, fs8.constants.W_OK);
8646
9145
  return true;
8647
9146
  } catch {
8648
9147
  return false;
@@ -8654,11 +9153,11 @@ function resolveSafeWorktree(context = {}, pluginWorktree = null) {
8654
9153
  context?.directory,
8655
9154
  pluginWorktree,
8656
9155
  process.cwd(),
8657
- os.homedir()
9156
+ os2.homedir()
8658
9157
  ];
8659
9158
  for (const candidate of candidates) {
8660
9159
  if (typeof candidate !== "string" || !candidate.trim()) continue;
8661
- const resolved = path6.resolve(candidate);
9160
+ const resolved = path8.resolve(candidate);
8662
9161
  if (isSafeWritableDirectory(resolved)) return resolved;
8663
9162
  }
8664
9163
  throw new Error(SAFE_WORKTREE_FAILURE);
@@ -8673,13 +9172,13 @@ function safeWorktreeOrFailure(context, pluginWorktree) {
8673
9172
  function explicitSafeInputWorktree(input = {}) {
8674
9173
  for (const candidate of [input?.worktree, input?.directory]) {
8675
9174
  if (typeof candidate !== "string" || !candidate.trim()) continue;
8676
- const resolved = path6.resolve(candidate);
9175
+ const resolved = path8.resolve(candidate);
8677
9176
  if (isSafeWritableDirectory(resolved)) return resolved;
8678
9177
  }
8679
9178
  return null;
8680
9179
  }
8681
9180
  function isGitRepository(worktree) {
8682
- return fs5.existsSync(path6.join(worktree, ".git"));
9181
+ return fs8.existsSync(path8.join(worktree, ".git"));
8683
9182
  }
8684
9183
  function normalizeLooseToken(value) {
8685
9184
  return String(value ?? "").trim().normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -8713,8 +9212,8 @@ function parseHumansRegistry(markdown = "") {
8713
9212
  return roles;
8714
9213
  }
8715
9214
  function loadHumansRegistry(registryPath = HUMANS_REGISTRY_PATH) {
8716
- if (!fs5.existsSync(registryPath)) return {};
8717
- return parseHumansRegistry(fs5.readFileSync(registryPath, "utf8"));
9215
+ if (!fs8.existsSync(registryPath)) return {};
9216
+ return parseHumansRegistry(fs8.readFileSync(registryPath, "utf8"));
8718
9217
  }
8719
9218
  function resolveHumanRoles(roles = CLICKUP_FINAL_APPROVER_ROLES, registry = loadHumansRegistry()) {
8720
9219
  return [...new Set(roles.map((role) => registry[String(role ?? "").trim()] || "").filter(Boolean))];
@@ -8886,78 +9385,28 @@ function buildClickUpReviewAutomationPlan({ isSubtask = false, humanApprover = "
8886
9385
  }
8887
9386
  };
8888
9387
  }
8889
- function validateMainWorkspaceBranchSafety({ currentBranch, requiredBranch = "dev", forbiddenBranch = "main" } = {}) {
8890
- const normalized = String(currentBranch ?? "").trim();
8891
- if (!normalized) {
8892
- return { ok: false, branch: normalized, message: "Unable to determine the current branch; expected main workspace on dev." };
8893
- }
8894
- if (normalized === forbiddenBranch) {
8895
- return { ok: false, branch: normalized, message: "Unsafe workspace branch: main is never allowed for Optima delivery work." };
8896
- }
8897
- if (normalized !== requiredBranch) {
8898
- return { ok: false, branch: normalized, message: `Unsafe workspace branch: expected ${requiredBranch}, got ${normalized}.` };
8899
- }
8900
- return { ok: true, branch: normalized, message: `Workspace branch is safe on ${requiredBranch}.` };
8901
- }
8902
- var CLICKUP_REQUIRED_SUMMARY_SECTIONS = [
8903
- "Summary",
8904
- "Work Performed",
8905
- "AC Coverage",
8906
- "Verification Results",
8907
- "Documentation Impact",
8908
- "Open Risks",
8909
- "Recommended Next Step"
8910
- ];
8911
- var CLICKUP_RAW_LOG_SECTION_NAMES = /* @__PURE__ */ new Set(["Raw Logs", "Logs", "Full Logs", "Command Output", "Transcript"]);
8912
- var CLICKUP_TRANSITIONS = /* @__PURE__ */ new Map([
8913
- ["plan->in progress", { status: "in progress", comment: "Plan complete; moving to implementation without generic CTO/PO assignment." }],
8914
- ["in progress->validation", { status: "validation", comment: "Implementation complete; ready for validation." }],
8915
- ["validation->merge", { status: "merge", assignFinalApprovers: true, parentOnlyFinalApproval: true, comment: "Parent validation passed with a functional preview URL; ready for CTO/PO approval flow." }],
8916
- ["validation->in progress", { status: "in progress", comment: "Validation failed; returning to implementation." }],
8917
- ["merge->completed", { status: "completed", comment: "Merge complete; closing delivery task." }],
8918
- ["completed->in progress", { status: "in progress", comment: "Task reopened; returning to implementation." }],
8919
- ["closed->in progress", { status: "in progress", comment: "Task reopened; returning to implementation." }]
8920
- ]);
8921
- function parseMarkdownSections(markdown = "") {
8922
- const sections = {};
8923
- let current = null;
8924
- let buffer = [];
8925
- const flush = () => {
8926
- if (!current) return;
8927
- sections[current] = buffer.join("\n").trim();
8928
- };
8929
- for (const line of String(markdown).split(/\r?\n/)) {
8930
- const heading = /^(#{2,3})\s+(.+?)\s*$/.exec(line);
8931
- if (heading) {
8932
- flush();
8933
- current = heading[2].trim();
8934
- buffer = [];
8935
- continue;
8936
- }
8937
- if (current) buffer.push(line);
8938
- }
8939
- flush();
8940
- return sections;
8941
- }
8942
- function parseMarkdownArtifact(markdown = "", { requiredSections = [] } = {}) {
8943
- const sections = parseMarkdownSections(markdown);
8944
- const missing = requiredSections.filter((section) => !sections[section]);
8945
- return {
8946
- ok: missing.length === 0,
8947
- sections,
8948
- missing,
8949
- message: missing.length ? `Missing required section(s): ${missing.join(", ")}` : "ok"
8950
- };
8951
- }
8952
- function readMarkdownArtifact(filePath, options = {}) {
8953
- const markdown = fs5.readFileSync(filePath, "utf8");
8954
- return parseMarkdownArtifact(markdown, options);
8955
- }
8956
- function stripRawLogSections(sections = {}) {
8957
- return Object.fromEntries(
8958
- Object.entries(sections).filter(([name]) => !CLICKUP_RAW_LOG_SECTION_NAMES.has(name))
8959
- );
9388
+ function validateMainWorkspaceBranchSafety({ currentBranch, requiredBranch = "dev", forbiddenBranch = "main" } = {}) {
9389
+ const normalized = String(currentBranch ?? "").trim();
9390
+ if (!normalized) {
9391
+ return { ok: false, branch: normalized, message: "Unable to determine the current branch; expected main workspace on dev." };
9392
+ }
9393
+ if (normalized === forbiddenBranch) {
9394
+ return { ok: false, branch: normalized, message: "Unsafe workspace branch: main is never allowed for Optima delivery work." };
9395
+ }
9396
+ if (normalized !== requiredBranch) {
9397
+ return { ok: false, branch: normalized, message: `Unsafe workspace branch: expected ${requiredBranch}, got ${normalized}.` };
9398
+ }
9399
+ return { ok: true, branch: normalized, message: `Workspace branch is safe on ${requiredBranch}.` };
8960
9400
  }
9401
+ var CLICKUP_TRANSITIONS = /* @__PURE__ */ new Map([
9402
+ ["plan->in progress", { status: "in progress", comment: "Plan complete; moving to implementation without generic CTO/PO assignment." }],
9403
+ ["in progress->validation", { status: "validation", comment: "Implementation complete; ready for validation." }],
9404
+ ["validation->merge", { status: "merge", assignFinalApprovers: true, parentOnlyFinalApproval: true, comment: "Parent validation passed with a functional preview URL; ready for CTO/PO approval flow." }],
9405
+ ["validation->in progress", { status: "in progress", comment: "Validation failed; returning to implementation." }],
9406
+ ["merge->completed", { status: "completed", comment: "Merge complete; closing delivery task." }],
9407
+ ["completed->in progress", { status: "in progress", comment: "Task reopened; returning to implementation." }],
9408
+ ["closed->in progress", { status: "in progress", comment: "Task reopened; returning to implementation." }]
9409
+ ]);
8961
9410
  var CLICKUP_SUBTASK_REQUIRED_FIELDS = ["Type", "Owner Role", "Story Points", "Slice", "Acceptance Criteria"];
8962
9411
  var CLICKUP_SUBTASK_OPTIONAL_FIELDS = ["Depends On", "Branch", "Description", "Definition", "Documentation"];
8963
9412
  var CLICKUP_SUBTASK_KNOWN_FIELDS = /* @__PURE__ */ new Set([...CLICKUP_SUBTASK_REQUIRED_FIELDS, ...CLICKUP_SUBTASK_OPTIONAL_FIELDS]);
@@ -9161,7 +9610,7 @@ function buildClickUpApplyPayloadResult({ payload, apply = false } = {}) {
9161
9610
  noop: true,
9162
9611
  applied: false,
9163
9612
  message: "Dry-run only. Payload validated; no ClickUp calls were made.",
9164
- payload: parsed
9613
+ payload: normalizeClickUpPayloadComments(parsed)
9165
9614
  };
9166
9615
  }
9167
9616
  return {
@@ -9171,7 +9620,7 @@ function buildClickUpApplyPayloadResult({ payload, apply = false } = {}) {
9171
9620
  applyRequested: true,
9172
9621
  applied: false,
9173
9622
  message: "Live ClickUp execution is not implemented/configured in this safe boundary; no ClickUp calls were made.",
9174
- payload: parsed
9623
+ payload: normalizeClickUpPayloadComments(parsed)
9175
9624
  };
9176
9625
  }
9177
9626
  function sectionValue(sections, names) {
@@ -9181,7 +9630,7 @@ function sectionValue(sections, names) {
9181
9630
  return "";
9182
9631
  }
9183
9632
  function compactMarkdownValue(value = "") {
9184
- return String(value).split(/\r?\n/).map((line) => line.trimEnd()).join("\n").replace(/\n{3,}/g, "\n\n").trim();
9633
+ return normalizeClickUpMarkdown(value);
9185
9634
  }
9186
9635
  function buildClickUpSummaryPayload({ summaryMarkdown = "", summaryPath = "", taskMarkdown = "", taskPath = "", branch = "", worktree = "", pr = "" } = {}) {
9187
9636
  const parsedSummary = parseMarkdownArtifact(summaryMarkdown, { requiredSections: CLICKUP_REQUIRED_SUMMARY_SECTIONS });
@@ -9206,13 +9655,12 @@ function buildClickUpSummaryPayload({ summaryMarkdown = "", summaryPath = "", ta
9206
9655
  deliveryPath ? `- Delivery evidence: ${compactMarkdownValue(deliveryPath)}` : null,
9207
9656
  prValue ? `- PR: ${compactMarkdownValue(prValue)}` : null
9208
9657
  ].filter(Boolean);
9209
- const comment = [
9210
- "ClickUp sync payload generated from Optima Markdown artifacts.",
9211
- "",
9212
- ...commentParts.flatMap(([title, value]) => [`## ${title}`, compactMarkdownValue(value) || "Not specified.", ""]),
9213
- contextParts.length ? "## PR/Branch/Worktree" : null,
9214
- contextParts.length ? contextParts.join("\n") : null
9215
- ].filter((part) => part !== null).join("\n").trim();
9658
+ const comment = formatClickUpStatusComment({
9659
+ title: "Optima Delivery Summary",
9660
+ summary: "ClickUp sync payload generated from Optima Markdown artifacts.",
9661
+ sections: commentParts.map(([title, value]) => ({ title, body: compactMarkdownValue(value) || "Not specified." })),
9662
+ context: contextParts
9663
+ });
9216
9664
  return {
9217
9665
  ok: true,
9218
9666
  mode: "payload",
@@ -9238,7 +9686,7 @@ function buildClickUpSummaryPayload({ summaryMarkdown = "", summaryPath = "", ta
9238
9686
  function deriveClickUpWorktree({ baseWorktree = "", taskId, taskType, parentTaskId, subtaskId } = {}) {
9239
9687
  const branch = deriveClickUpBranchName({ taskType, parentTaskId, subtaskId, taskId });
9240
9688
  const root = baseWorktree || process.cwd();
9241
- return path6.join(path6.dirname(root), `${path6.basename(root)}-${branch.replace(/\//g, "-")}`);
9689
+ return path8.join(path8.dirname(root), `${path8.basename(root)}-${branch.replace(/\//g, "-")}`);
9242
9690
  }
9243
9691
  function clickUpCustomFieldValue(task = {}, names = []) {
9244
9692
  const fields = Array.isArray(task.custom_fields) ? task.custom_fields : [];
@@ -9262,12 +9710,12 @@ function safeExistingClickUpWorktree({ metadata = {}, branch = "" } = {}) {
9262
9710
  const taskMetadata = metadataTaskRouting(metadata);
9263
9711
  const existingWorktree = typeof taskMetadata.worktree === "string" ? taskMetadata.worktree.trim() : "";
9264
9712
  const existingBranch = typeof taskMetadata.branch === "string" ? taskMetadata.branch.trim() : "";
9265
- if (!existingWorktree || !path6.isAbsolute(existingWorktree) || !fs5.existsSync(existingWorktree)) return null;
9713
+ if (!existingWorktree || !path8.isAbsolute(existingWorktree) || !fs8.existsSync(existingWorktree)) return null;
9266
9714
  try {
9267
- const stat = fs5.statSync(existingWorktree);
9715
+ const stat = fs8.statSync(existingWorktree);
9268
9716
  if (!stat.isDirectory()) return null;
9269
9717
  if (branch && existingBranch && existingBranch !== branch) return null;
9270
- return { branch: existingBranch || branch, worktree: path6.resolve(existingWorktree), reused: true };
9718
+ return { branch: existingBranch || branch, worktree: path8.resolve(existingWorktree), reused: true };
9271
9719
  } catch {
9272
9720
  return null;
9273
9721
  }
@@ -9301,7 +9749,7 @@ function normalizeOptimaGitIdentity(identity = {}) {
9301
9749
  };
9302
9750
  }
9303
9751
  function configureOptimaWorktreeGitIdentity({ worktreePath, identity = {}, runGitFn = runGit } = {}) {
9304
- if (!worktreePath || !fs5.existsSync(worktreePath)) return { configured: false, reason: "worktree_missing" };
9752
+ if (!worktreePath || !fs8.existsSync(worktreePath)) return { configured: false, reason: "worktree_missing" };
9305
9753
  const normalized = normalizeOptimaGitIdentity(identity);
9306
9754
  if (!normalized.name || !normalized.email) return { configured: false, reason: "identity_missing" };
9307
9755
  try {
@@ -9387,17 +9835,17 @@ function openChamberEntryBranch(entry) {
9387
9835
  return String(entry?.branch || entry?.branchName || entry?.branch_name || entry?.worktree?.branch || "").replace(/^refs\/heads\//, "");
9388
9836
  }
9389
9837
  function openChamberListIncludesDirectory(list, directory) {
9390
- const resolved = path6.resolve(directory);
9838
+ const resolved = path8.resolve(directory);
9391
9839
  return normalizeOpenChamberCollection(list).some((entry) => {
9392
9840
  const entryDirectory = openChamberEntryDirectory(entry);
9393
- return entryDirectory && path6.resolve(entryDirectory) === resolved;
9841
+ return entryDirectory && path8.resolve(entryDirectory) === resolved;
9394
9842
  });
9395
9843
  }
9396
9844
  function openChamberListIncludesBranch(list, directory, branch) {
9397
- const resolved = path6.resolve(directory);
9845
+ const resolved = path8.resolve(directory);
9398
9846
  return normalizeOpenChamberCollection(list).some((entry) => {
9399
9847
  const entryDirectory = openChamberEntryDirectory(entry);
9400
- if (!entryDirectory || path6.resolve(entryDirectory) !== resolved) return false;
9848
+ if (!entryDirectory || path8.resolve(entryDirectory) !== resolved) return false;
9401
9849
  const entryBranch = openChamberEntryBranch(entry);
9402
9850
  return !entryBranch || entryBranch === branch;
9403
9851
  });
@@ -9405,8 +9853,8 @@ function openChamberListIncludesBranch(list, directory, branch) {
9405
9853
  async function findOpenChamberProject({ opencodeBaseUrl, baseWorktree, fetchImpl = globalThis.fetch } = {}) {
9406
9854
  const projects = await requestOpenCodeJson({ baseUrl: opencodeBaseUrl, endpoint: "/project", directory: baseWorktree, fetchImpl });
9407
9855
  if (!Array.isArray(projects)) return null;
9408
- const resolvedBase = path6.resolve(baseWorktree);
9409
- return projects.find((project) => path6.resolve(String(project?.worktree || project?.path || "")) === resolvedBase) || null;
9856
+ const resolvedBase = path8.resolve(baseWorktree);
9857
+ return projects.find((project) => path8.resolve(String(project?.worktree || project?.path || "")) === resolvedBase) || null;
9410
9858
  }
9411
9859
  async function refreshOpenChamberProjectCopy({ opencodeBaseUrl, projectId, fetchImpl = globalThis.fetch } = {}) {
9412
9860
  if (!projectId) return { refreshed: false, reason: "project_id_unavailable" };
@@ -9461,18 +9909,18 @@ async function createOpenChamberClickUpWorktree({ openchamberBaseUrl, baseUrl, b
9461
9909
  }
9462
9910
  const createdDirectory = openChamberEntryDirectory(created);
9463
9911
  const createdBranch = openChamberEntryBranch(created);
9464
- if (!createdDirectory || !path6.isAbsolute(createdDirectory)) {
9912
+ if (!createdDirectory || !path8.isAbsolute(createdDirectory)) {
9465
9913
  throw new Error(`OpenChamber did not return an absolute worktree path for ${branch}.`);
9466
9914
  }
9467
9915
  if (createdBranch !== branch) {
9468
9916
  throw new Error(`OpenChamber created unexpected branch ${createdBranch || "<unknown>"}; expected ${branch}.`);
9469
9917
  }
9470
9918
  const verified = await verifyOpenChamberGitWorktree({ openchamberBaseUrl: effectiveOpenChamberBaseUrl, baseWorktree, worktreePath: createdDirectory, branch, fetchImpl });
9471
- return { created, worktree: path6.resolve(createdDirectory), branch: createdBranch, verified };
9919
+ return { created, worktree: path8.resolve(createdDirectory), branch: createdBranch, verified };
9472
9920
  }
9473
9921
  async function registerOpenChamberClickUpWorktree({ openchamberBaseUrl, opencodeBaseUrl, baseUrl, baseWorktree, branch, worktreePath, fetchImpl = globalThis.fetch, source = "reuse" } = {}) {
9474
9922
  const visibility = await syncOpenChamberWorktreeVisibility({ openchamberBaseUrl: openchamberBaseUrl || baseUrl, opencodeBaseUrl: opencodeBaseUrl || baseUrl, baseWorktree, worktreePath, branch, fetchImpl });
9475
- return { branch, worktree: path6.resolve(worktreePath), reused: true, provider: "openchamber", openChamber: { source, visibility } };
9923
+ return { branch, worktree: path8.resolve(worktreePath), reused: true, provider: "openchamber", openChamber: { source, visibility } };
9476
9924
  }
9477
9925
  async function ensureClickUpTaskWorktreeOpenChamber({ baseWorktree = "", taskId, taskType = "Tarea", parentTaskId = "", subtaskId = "", existingMetadata = {}, runGitFn = runGit, openchamberBaseUrl = "", opencodeBaseUrl = "", baseUrl = "", fetchImpl = globalThis.fetch, log = null, gitIdentity = {} } = {}) {
9478
9926
  const effectiveOpenChamberBaseUrl = openchamberBaseUrl || baseUrl;
@@ -9490,7 +9938,7 @@ async function ensureClickUpTaskWorktreeOpenChamber({ baseWorktree = "", taskId,
9490
9938
  return { ...registered, parentBranch: parentBranch || void 0, prTarget, gitIdentity: identity2 };
9491
9939
  }
9492
9940
  const worktreePath = deriveClickUpWorktree({ baseWorktree, taskId, taskType, parentTaskId: effectiveParent, subtaskId });
9493
- if (fs5.existsSync(worktreePath)) {
9941
+ if (fs8.existsSync(worktreePath)) {
9494
9942
  const registered = await registerOpenChamberClickUpWorktree({ openchamberBaseUrl: effectiveOpenChamberBaseUrl, opencodeBaseUrl: effectiveOpenCodeBaseUrl, baseWorktree, branch, worktreePath, fetchImpl, source: "existing_directory" });
9495
9943
  const identity2 = configureOptimaWorktreeGitIdentity({ worktreePath: registered.worktree, identity: gitIdentity, runGitFn });
9496
9944
  log?.({ type: "openchamber_worktree_registered", taskId, branch, worktree: registered.worktree, source: "existing_directory", visibility: registered.openChamber.visibility });
@@ -9499,7 +9947,7 @@ async function ensureClickUpTaskWorktreeOpenChamber({ baseWorktree = "", taskId,
9499
9947
  let parentBootstrap = null;
9500
9948
  if (isSubtask) {
9501
9949
  const parentWorktree = deriveClickUpWorktree({ baseWorktree, taskId: effectiveParent, taskType, parentTaskId: effectiveParent });
9502
- if (fs5.existsSync(parentWorktree)) {
9950
+ if (fs8.existsSync(parentWorktree)) {
9503
9951
  const registeredParent = await registerOpenChamberClickUpWorktree({ openchamberBaseUrl: effectiveOpenChamberBaseUrl, opencodeBaseUrl: effectiveOpenCodeBaseUrl, baseWorktree, branch: parentBranch, worktreePath: parentWorktree, fetchImpl, source: "parent_existing_directory" });
9504
9952
  const parentIdentity = configureOptimaWorktreeGitIdentity({ worktreePath: registeredParent.worktree, identity: gitIdentity, runGitFn });
9505
9953
  parentBootstrap = { branch: parentBranch, worktree: registeredParent.worktree, reused: true, provider: "openchamber", visibility: registeredParent.openChamber.visibility };
@@ -9542,33 +9990,33 @@ function ensureClickUpTaskWorktree({ baseWorktree = "", taskId, taskType = "Tare
9542
9990
  const existing = safeExistingClickUpWorktree({ metadata: existingMetadata, branch });
9543
9991
  if (existing) return { ...existing, branch, parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev", gitIdentity: configureOptimaWorktreeGitIdentity({ worktreePath: existing.worktree, identity: gitIdentity, runGitFn }) };
9544
9992
  const worktreePath = deriveClickUpWorktree({ baseWorktree, taskId, taskType, parentTaskId: effectiveParent, subtaskId });
9545
- if (fs5.existsSync(worktreePath)) {
9546
- const resolvedWorktree2 = path6.resolve(worktreePath);
9993
+ if (fs8.existsSync(worktreePath)) {
9994
+ const resolvedWorktree2 = path8.resolve(worktreePath);
9547
9995
  return { branch, worktree: resolvedWorktree2, reused: true, parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev", gitIdentity: configureOptimaWorktreeGitIdentity({ worktreePath: resolvedWorktree2, identity: gitIdentity, runGitFn }) };
9548
9996
  }
9549
9997
  if (allowNonGitFallback) {
9550
- fs5.mkdirSync(worktreePath, { recursive: true });
9551
- return { branch, worktree: path6.resolve(worktreePath), reused: false, fallback: "non_git", parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev", startPoint: parentBranch || "dev" };
9998
+ fs8.mkdirSync(worktreePath, { recursive: true });
9999
+ return { branch, worktree: path8.resolve(worktreePath), reused: false, fallback: "non_git", parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev", startPoint: parentBranch || "dev" };
9552
10000
  }
9553
10001
  let parentBootstrap = null;
9554
10002
  if (isSubtask) {
9555
10003
  const parentWorktree = deriveClickUpWorktree({ baseWorktree, taskId: effectiveParent, taskType, parentTaskId: effectiveParent });
9556
- if (!fs5.existsSync(parentWorktree)) {
10004
+ if (!fs8.existsSync(parentWorktree)) {
9557
10005
  const parentStartPoint = resolveClickUpDevStartPoint(baseWorktree, runGitFn);
9558
10006
  const parentBranchExists = clickUpGitRefExists(baseWorktree, parentBranch, runGitFn);
9559
10007
  addClickUpWorktreeForBranch({ baseWorktree, branch: parentBranch, worktreePath: parentWorktree, startPoint: parentStartPoint, runGitFn });
9560
- parentBootstrap = { branch: parentBranch, worktree: path6.resolve(parentWorktree), startPoint: parentBranchExists ? parentBranch : parentStartPoint, reused: parentBranchExists };
10008
+ parentBootstrap = { branch: parentBranch, worktree: path8.resolve(parentWorktree), startPoint: parentBranchExists ? parentBranch : parentStartPoint, reused: parentBranchExists };
9561
10009
  const parentIdentity = configureOptimaWorktreeGitIdentity({ worktreePath: parentBootstrap.worktree, identity: gitIdentity, runGitFn });
9562
10010
  if (parentIdentity.configured) parentBootstrap.gitIdentity = parentIdentity;
9563
10011
  } else {
9564
- parentBootstrap = { branch: parentBranch, worktree: path6.resolve(parentWorktree), reused: true };
10012
+ parentBootstrap = { branch: parentBranch, worktree: path8.resolve(parentWorktree), reused: true };
9565
10013
  const parentIdentity = configureOptimaWorktreeGitIdentity({ worktreePath: parentBootstrap.worktree, identity: gitIdentity, runGitFn });
9566
10014
  if (parentIdentity.configured) parentBootstrap.gitIdentity = parentIdentity;
9567
10015
  }
9568
10016
  }
9569
10017
  const startPoint = isSubtask ? parentBranch : resolveClickUpDevStartPoint(baseWorktree, runGitFn);
9570
10018
  addClickUpWorktreeForBranch({ baseWorktree, branch, worktreePath, startPoint, runGitFn });
9571
- const resolvedWorktree = path6.resolve(worktreePath);
10019
+ const resolvedWorktree = path8.resolve(worktreePath);
9572
10020
  return { branch, worktree: resolvedWorktree, reused: false, startPoint, parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev", parentBootstrap: parentBootstrap || void 0, gitIdentity: configureOptimaWorktreeGitIdentity({ worktreePath: resolvedWorktree, identity: gitIdentity, runGitFn }) };
9573
10021
  }
9574
10022
  function normalizeClickUpDefinitionDocParent(parent = {}) {
@@ -9651,7 +10099,17 @@ function buildClickUpStartTaskPayload({ taskId, taskType = "Tarea", parentTaskId
9651
10099
  wouldCreate: true
9652
10100
  },
9653
10101
  clickup: {
9654
- comment: `Starting task from ${startFrom}. Branch: ${branch}. Worktree: ${worktree}. Validation PR target: ${requiredPullRequest.targetBranch}. Delivery evidence: ${deliveryEvidencePathForClickUpTask(taskId || subtaskId || effectiveParent)}.`,
10102
+ comment: formatClickUpStatusComment({
10103
+ title: "Task Workspace Ready",
10104
+ summary: "Optima prepared the task workspace and validation target.",
10105
+ context: [
10106
+ `Branch: ${branch}`,
10107
+ `Start from: ${startFrom}`,
10108
+ `Worktree: ${worktree}`,
10109
+ `Validation PR target: ${requiredPullRequest.targetBranch}`,
10110
+ `Delivery evidence: ${deliveryEvidencePathForClickUpTask(taskId || subtaskId || effectiveParent)}`
10111
+ ]
10112
+ }),
9655
10113
  description,
9656
10114
  fields: {
9657
10115
  Definition: definitionContent,
@@ -9737,7 +10195,18 @@ function buildClickUpTransitionPayload({ fromStatus, toStatus, validationPassed
9737
10195
  remove: removalTargets,
9738
10196
  objective: assignsFinalApprovers ? "zero_product_manager_assigned_tasks" : "preserve_existing_owner_policy"
9739
10197
  },
9740
- comment: rule.comment,
10198
+ comment: formatClickUpStatusComment({
10199
+ title: "Workflow Status Update",
10200
+ summary: rule.comment,
10201
+ context: [
10202
+ `From: ${from}`,
10203
+ `To: ${rule.status}`,
10204
+ requiredPullRequest?.prUrl ? `PR: ${requiredPullRequest.prUrl}` : null,
10205
+ requiredPullRequest?.prNumber ? `PR number: ${requiredPullRequest.prNumber}` : null,
10206
+ requiredPullRequest?.sourceBranch ? `Source branch: ${requiredPullRequest.sourceBranch}` : null,
10207
+ requiredPullRequest?.targetBranch ? `Target branch: ${requiredPullRequest.targetBranch}` : null
10208
+ ].filter(Boolean)
10209
+ }),
9741
10210
  description,
9742
10211
  fields,
9743
10212
  definition_doc: definitionContent ? {
@@ -9750,8 +10219,8 @@ function buildClickUpTransitionPayload({ fromStatus, toStatus, validationPassed
9750
10219
  }
9751
10220
  function ensureOptimaGitignoreRules(worktree) {
9752
10221
  if (!isGitRepository(worktree)) return { touched: false, added: [] };
9753
- const gitignorePath = path6.join(worktree, ".gitignore");
9754
- const existing = fs5.existsSync(gitignorePath) ? fs5.readFileSync(gitignorePath, "utf8") : "";
10222
+ const gitignorePath = path8.join(worktree, ".gitignore");
10223
+ const existing = fs8.existsSync(gitignorePath) ? fs8.readFileSync(gitignorePath, "utf8") : "";
9755
10224
  const existingRules = new Set(existing.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
9756
10225
  const missingRules = OPTIMA_GITIGNORE_RULES.filter((rule) => !existingRules.has(rule));
9757
10226
  if (missingRules.length === 0) return { touched: false, added: [] };
@@ -9761,45 +10230,45 @@ function ensureOptimaGitignoreRules(worktree) {
9761
10230
  "# Optima local/private state",
9762
10231
  ...missingRules
9763
10232
  ].join("\n");
9764
- fs5.writeFileSync(gitignorePath, `${existing}${prefix}${separator}${block}
10233
+ fs8.writeFileSync(gitignorePath, `${existing}${prefix}${separator}${block}
9765
10234
  `, "utf8");
9766
10235
  return { touched: true, added: missingRules };
9767
10236
  }
9768
10237
  function optimaDir(worktree) {
9769
- return path6.join(worktree, OPTIMA_DIRNAME);
10238
+ return path8.join(worktree, OPTIMA_DIRNAME);
9770
10239
  }
9771
10240
  function optimaLocalConfigDir(worktree) {
9772
- return path6.join(optimaDir(worktree), ".config");
10241
+ return path8.join(optimaDir(worktree), ".config");
9773
10242
  }
9774
10243
  function optimaConfigDir(worktree) {
9775
10244
  return optimaLocalConfigDir(worktree);
9776
10245
  }
9777
10246
  function optimaCodemapPath(worktree) {
9778
- return path6.join(optimaDir(worktree), "codemap.yml");
10247
+ return path8.join(optimaDir(worktree), "codemap.yml");
9779
10248
  }
9780
10249
  function optimaTasksDir(worktree) {
9781
- return path6.join(optimaDir(worktree), "tasks");
10250
+ return path8.join(optimaDir(worktree), "tasks");
9782
10251
  }
9783
10252
  function optimaEvidencesDir(worktree) {
9784
- return path6.join(optimaDir(worktree), "evidences");
10253
+ return path8.join(optimaDir(worktree), "evidences");
9785
10254
  }
9786
10255
  function optimaScrsDir(worktree) {
9787
- return path6.join(optimaDir(worktree), "docs", "scrs");
10256
+ return path8.join(optimaDir(worktree), "docs", "scrs");
9788
10257
  }
9789
10258
  function legacyNomadworkDir(worktree) {
9790
- return path6.join(worktree, LEGACY_NOMADWORK_DIRNAME);
10259
+ return path8.join(worktree, LEGACY_NOMADWORK_DIRNAME);
9791
10260
  }
9792
10261
  function legacyNomadworksDir(worktree) {
9793
- return path6.join(worktree, LEGACY_NOMADWORKS_DIRNAME);
10262
+ return path8.join(worktree, LEGACY_NOMADWORKS_DIRNAME);
9794
10263
  }
9795
10264
  function legacyOrbitaDir(worktree) {
9796
- return path6.join(worktree, LEGACY_ORBITA_DIRNAME);
10265
+ return path8.join(worktree, LEGACY_ORBITA_DIRNAME);
9797
10266
  }
9798
10267
  function legacyStaticEngDir(worktree) {
9799
- return path6.join(worktree, LEGACY_STATICENG_DIRNAME);
10268
+ return path8.join(worktree, LEGACY_STATICENG_DIRNAME);
9800
10269
  }
9801
10270
  function repoConfigPath(worktree) {
9802
- return path6.join(optimaConfigDir(worktree), "optima.yaml");
10271
+ return path8.join(optimaConfigDir(worktree), "optima.yaml");
9803
10272
  }
9804
10273
  function normalizeLegacyDiscussionEntry(entry) {
9805
10274
  if (!entry || typeof entry !== "object") return entry;
@@ -9812,25 +10281,25 @@ function normalizeLegacyDiscussionEntry(entry) {
9812
10281
  return next;
9813
10282
  }
9814
10283
  function repoPoliciesDir(worktree) {
9815
- return path6.join(optimaDir(worktree), "policies");
10284
+ return path8.join(optimaDir(worktree), "policies");
9816
10285
  }
9817
10286
  function generatedPoliciesDir(worktree) {
9818
- return path6.join(optimaLocalConfigDir(worktree), "generated", "policies");
10287
+ return path8.join(optimaLocalConfigDir(worktree), "generated", "policies");
9819
10288
  }
9820
10289
  function generatedAgentsDir(worktree) {
9821
- return path6.join(optimaLocalConfigDir(worktree), "generated", "agents");
10290
+ return path8.join(optimaLocalConfigDir(worktree), "generated", "agents");
9822
10291
  }
9823
10292
  function repoAgentsDir(worktree) {
9824
- return path6.join(optimaDir(worktree), "agents");
10293
+ return path8.join(optimaDir(worktree), "agents");
9825
10294
  }
9826
10295
  function repoAgentAdditionsDir(worktree) {
9827
- return path6.join(optimaDir(worktree), "agent-additions");
10296
+ return path8.join(optimaDir(worktree), "agent-additions");
9828
10297
  }
9829
10298
  function legacyRepoAgentsDir(worktree) {
9830
- return path6.join(legacyNomadworksDir(worktree), "agents");
10299
+ return path8.join(legacyNomadworksDir(worktree), "agents");
9831
10300
  }
9832
10301
  function runtimeDiscussionRegistryPath(worktree) {
9833
- return path6.join(optimaLocalConfigDir(worktree), "runtime", "discussions.json");
10302
+ return path8.join(optimaLocalConfigDir(worktree), "runtime", "discussions.json");
9834
10303
  }
9835
10304
  function resolveConfigPath(worktree) {
9836
10305
  return repoConfigPath(worktree);
@@ -9873,32 +10342,32 @@ function mergeClickUpAgentMetadata(existing, update = {}) {
9873
10342
  return JSON.stringify(sortJsonValue(merged), null, 2);
9874
10343
  }
9875
10344
  function optimaRuntimeDir(worktree) {
9876
- return path6.join(optimaLocalConfigDir(worktree), "runtime");
10345
+ return path8.join(optimaLocalConfigDir(worktree), "runtime");
9877
10346
  }
9878
10347
  function clickUpWebhookStatePath(worktree) {
9879
- return path6.join(optimaRuntimeDir(worktree), "clickup-webhook.json");
10348
+ return path8.join(optimaRuntimeDir(worktree), "clickup-webhook.json");
9880
10349
  }
9881
10350
  function clickUpCommentLedgerPath(worktree) {
9882
- return path6.join(optimaRuntimeDir(worktree), "clickup-comment-ledger.jsonl");
10351
+ return path8.join(optimaRuntimeDir(worktree), "clickup-comment-ledger.jsonl");
9883
10352
  }
9884
10353
  function clickUpWebhookLogPath(worktree) {
9885
- return path6.join(optimaRuntimeDir(worktree), "clickup-webhook.log.jsonl");
10354
+ return path8.join(optimaRuntimeDir(worktree), "clickup-webhook.log.jsonl");
9886
10355
  }
9887
10356
  function normalizeClickUpWebhookLogLevel(value) {
9888
10357
  const level = String(value || "info").trim().toLowerCase();
9889
10358
  return CLICKUP_WEBHOOK_LOG_LEVELS.has(level) ? level : "info";
9890
10359
  }
9891
10360
  function clickUpWebhookAuditLogDir() {
9892
- const dataHome = process.env.XDG_DATA_HOME && path6.isAbsolute(process.env.XDG_DATA_HOME) ? process.env.XDG_DATA_HOME : path6.join(os.homedir(), ".local", "share", "opencode");
9893
- return path6.join(dataHome, "opencode-optima");
10361
+ const dataHome = process.env.XDG_DATA_HOME && path8.isAbsolute(process.env.XDG_DATA_HOME) ? process.env.XDG_DATA_HOME : path8.join(os2.homedir(), ".local", "share", "opencode");
10362
+ return path8.join(dataHome, "opencode-optima");
9894
10363
  }
9895
10364
  function clickUpWebhookAuditLogPath(at = /* @__PURE__ */ new Date(), logDir = clickUpWebhookAuditLogDir()) {
9896
- return path6.join(logDir, `clickup-webhook-${at.toISOString().slice(0, 10)}.jsonl`);
10365
+ return path8.join(logDir, `clickup-webhook-${at.toISOString().slice(0, 10)}.jsonl`);
9897
10366
  }
9898
10367
  function clickUpWebhookRequestFilePath(at = /* @__PURE__ */ new Date(), logDir = clickUpWebhookAuditLogDir()) {
9899
10368
  const stamp = at.toISOString().replace(/:/g, "-").replace(/\./g, "-");
9900
- const shortId = crypto.randomBytes(4).toString("hex");
9901
- return path6.join(logDir, "requests", `clickup-webhook-${stamp}-${shortId}.json`);
10369
+ const shortId = crypto2.randomBytes(4).toString("hex");
10370
+ return path8.join(logDir, "requests", `clickup-webhook-${stamp}-${shortId}.json`);
9902
10371
  }
9903
10372
  function findOptimaPluginTupleOptions(pluginEntries = []) {
9904
10373
  if (!Array.isArray(pluginEntries)) return null;
@@ -10058,7 +10527,7 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
10058
10527
  };
10059
10528
  const errors = [];
10060
10529
  if (!config.enabled) errors.push("clickup.enabled must be true");
10061
- if (!config.basePath || !path6.isAbsolute(config.basePath)) errors.push("clickup.base_path must be an absolute path");
10530
+ if (!config.basePath || !path8.isAbsolute(config.basePath)) errors.push("clickup.base_path must be an absolute path");
10062
10531
  if (!config.teamId) errors.push("clickup.team_id is required");
10063
10532
  if (!config.apiToken) errors.push("clickup.api_token is required");
10064
10533
  if (!config.webhook.publicUrl) errors.push("clickup.webhook.public_url is required");
@@ -10121,21 +10590,21 @@ function sanitizeClickUpWebhookState(state = {}, config = null) {
10121
10590
  }
10122
10591
  function readClickUpWebhookState(worktree, config = null) {
10123
10592
  const statePath = clickUpWebhookStatePath(worktree);
10124
- if (!fs5.existsSync(statePath)) return sanitizeClickUpWebhookState({}, config);
10593
+ if (!fs8.existsSync(statePath)) return sanitizeClickUpWebhookState({}, config);
10125
10594
  try {
10126
- return sanitizeClickUpWebhookState(JSON.parse(fs5.readFileSync(statePath, "utf8")), config);
10595
+ return sanitizeClickUpWebhookState(JSON.parse(fs8.readFileSync(statePath, "utf8")), config);
10127
10596
  } catch {
10128
10597
  return sanitizeClickUpWebhookState({}, config);
10129
10598
  }
10130
10599
  }
10131
10600
  function writeClickUpWebhookState(worktree, state, config = null) {
10132
10601
  const statePath = clickUpWebhookStatePath(worktree);
10133
- fs5.mkdirSync(path6.dirname(statePath), { recursive: true, mode: 448 });
10602
+ fs8.mkdirSync(path8.dirname(statePath), { recursive: true, mode: 448 });
10134
10603
  const next = sanitizeClickUpWebhookState(state, config);
10135
- fs5.writeFileSync(statePath, `${JSON.stringify(next, null, 2)}
10604
+ fs8.writeFileSync(statePath, `${JSON.stringify(next, null, 2)}
10136
10605
  `, { encoding: "utf8", mode: 384 });
10137
10606
  try {
10138
- fs5.chmodSync(statePath, 384);
10607
+ fs8.chmodSync(statePath, 384);
10139
10608
  } catch {
10140
10609
  }
10141
10610
  return next;
@@ -10148,26 +10617,6 @@ function isClickUpWebhookStateActive(state, config) {
10148
10617
  state?.active && state?.webhookId && state?.secret && state?.publicUrl === config?.webhook?.publicUrl && hasEvents
10149
10618
  );
10150
10619
  }
10151
- function expandHomePath(value = "") {
10152
- const input = String(value || "").trim();
10153
- if (input === "~") return os.homedir();
10154
- if (input.startsWith("~/")) return path6.join(os.homedir(), input.slice(2));
10155
- return input;
10156
- }
10157
- function resolveSecretReference(value = "") {
10158
- const raw = String(value || "").trim();
10159
- const envMatch = raw.match(/^\{env:([A-Za-z_][A-Za-z0-9_]*)\}$/);
10160
- if (envMatch) return process.env[envMatch[1]] || "";
10161
- const fileMatch = raw.match(/^\{file:(.+)\}$/);
10162
- if (fileMatch) {
10163
- try {
10164
- return fs5.readFileSync(expandHomePath(fileMatch[1]), "utf8").trim();
10165
- } catch {
10166
- return "";
10167
- }
10168
- }
10169
- return raw;
10170
- }
10171
10620
  function createClickUpApiClient(config, fetchImpl = globalThis.fetch) {
10172
10621
  const token = resolveSecretReference(config?.apiToken);
10173
10622
  const request = async (url, options = {}) => {
@@ -10232,212 +10681,6 @@ function createClickUpApiClient(config, fetchImpl = globalThis.fetch) {
10232
10681
  }
10233
10682
  };
10234
10683
  }
10235
- function base64UrlJson(value) {
10236
- return Buffer.from(JSON.stringify(value)).toString("base64url");
10237
- }
10238
- function resolveGitHubAppPrivateKey(app = {}) {
10239
- const direct = resolveSecretReference(app.privateKey || "");
10240
- if (direct) return direct.replace(/\\n/g, "\n");
10241
- const file = expandHomePath(app.privateKeyFile || "");
10242
- if (!file) return "";
10243
- try {
10244
- return fs5.readFileSync(file, "utf8").trim().replace(/\\n/g, "\n");
10245
- } catch {
10246
- return "";
10247
- }
10248
- }
10249
- function createGitHubAppJwt({ appId, privateKey, now = () => /* @__PURE__ */ new Date() } = {}) {
10250
- const key = String(privateKey || "").trim();
10251
- const issuer = String(appId || "").trim();
10252
- if (!issuer || !key) throw new Error("GitHub App app_id and private key are required");
10253
- const nowSeconds = Math.floor(now().getTime() / 1e3);
10254
- const header = base64UrlJson({ alg: "RS256", typ: "JWT" });
10255
- const payload = base64UrlJson({ iat: nowSeconds - 60, exp: nowSeconds + 540, iss: issuer });
10256
- const unsigned = `${header}.${payload}`;
10257
- const signature = crypto.createSign("RSA-SHA256").update(unsigned).end().sign(key, "base64url");
10258
- return `${unsigned}.${signature}`;
10259
- }
10260
- function encodeGitHubPathSegment(value) {
10261
- return encodeURIComponent(String(value || ""));
10262
- }
10263
- function encodeGitHubBranchRef(branch = "") {
10264
- return String(branch || "").split("/").map(encodeGitHubPathSegment).join("/");
10265
- }
10266
- function parseNullSeparatedGitOutput(output = "") {
10267
- return String(output || "").split("\0").map((item) => item.trim()).filter(Boolean);
10268
- }
10269
- function listWorktreeChangedPaths(worktree, runGitFn = runGit) {
10270
- const tracked = parseNullSeparatedGitOutput(runGitFn(worktree, ["diff", "--name-only", "-z", "HEAD", "--"]));
10271
- const untracked = parseNullSeparatedGitOutput(runGitFn(worktree, ["ls-files", "--others", "--exclude-standard", "-z", "--"]));
10272
- return [.../* @__PURE__ */ new Set([...tracked, ...untracked])].filter((item) => item && !item.startsWith("../") && !path6.isAbsolute(item));
10273
- }
10274
- function currentGitBranch(worktree, runGitFn = runGit) {
10275
- return String(runGitFn(worktree, ["rev-parse", "--abbrev-ref", "HEAD"]) || "").trim();
10276
- }
10277
- function treeEntryForWorktreePath(worktree, gitPath) {
10278
- const absolutePath = path6.join(worktree, ...String(gitPath || "").split("/"));
10279
- if (!fs5.existsSync(absolutePath)) return { path: gitPath, mode: "100644", type: "blob", sha: null, deleted: true };
10280
- const stat = fs5.lstatSync(absolutePath);
10281
- if (stat.isDirectory()) return null;
10282
- if (stat.isSymbolicLink()) {
10283
- return {
10284
- path: gitPath,
10285
- mode: "120000",
10286
- type: "blob",
10287
- content: fs5.readlinkSync(absolutePath),
10288
- encoding: "utf-8"
10289
- };
10290
- }
10291
- return {
10292
- path: gitPath,
10293
- mode: stat.mode & 73 ? "100755" : "100644",
10294
- type: "blob",
10295
- content: fs5.readFileSync(absolutePath).toString("base64"),
10296
- encoding: "base64"
10297
- };
10298
- }
10299
- function createGitHubApiClient(config = {}, fetchImpl = globalThis.fetch) {
10300
- const staticToken = resolveSecretReference(config?.apiToken);
10301
- const appConfig = isPlainObject(config?.app) ? config.app : {};
10302
- const appEnabled = appConfig.enabled === true || Boolean(appConfig.appId && appConfig.installationId && (appConfig.privateKey || appConfig.privateKeyFile));
10303
- const privateKey = resolveGitHubAppPrivateKey(appConfig);
10304
- const owner = String(config?.owner || "").trim();
10305
- const repo = String(config?.repo || "").trim();
10306
- let installationToken = null;
10307
- let installationTokenExpiresAt = 0;
10308
- const requestJson = async (url, { method = "GET", headers = {}, body = void 0 } = {}) => {
10309
- if (typeof fetchImpl !== "function") throw new Error("fetch is unavailable; inject a GitHub client for live PR lookup");
10310
- const response = await fetchImpl(url, {
10311
- method,
10312
- headers: {
10313
- Accept: "application/vnd.github+json",
10314
- "X-GitHub-Api-Version": "2022-11-28",
10315
- ...body === void 0 ? {} : { "Content-Type": "application/json" },
10316
- ...headers
10317
- },
10318
- ...body === void 0 ? {} : { body: JSON.stringify(body) }
10319
- });
10320
- if (!response.ok) throw new Error(`GitHub API request failed: ${response.status}`);
10321
- return response.status === 204 ? null : response.json();
10322
- };
10323
- const getAuthToken = async () => {
10324
- if (!appEnabled) return staticToken || "";
10325
- const nowMs = Date.now();
10326
- if (installationToken && installationTokenExpiresAt - 6e4 > nowMs) return installationToken;
10327
- const jwt = createGitHubAppJwt({ appId: appConfig.appId, privateKey });
10328
- const installation = await requestJson(`https://api.github.com/app/installations/${encodeURIComponent(appConfig.installationId)}/access_tokens`, {
10329
- method: "POST",
10330
- headers: { Authorization: `Bearer ${jwt}` }
10331
- });
10332
- installationToken = String(installation?.token || "").trim();
10333
- installationTokenExpiresAt = Date.parse(installation?.expires_at || "") || nowMs + 3e6;
10334
- if (!installationToken) throw new Error("GitHub App installation token response did not include a token");
10335
- return installationToken;
10336
- };
10337
- const request = async (pathname, { method = "GET", body = void 0 } = {}) => {
10338
- if (!owner || !repo) throw new Error("GitHub repository owner/repo is not configured");
10339
- const token = await getAuthToken();
10340
- return requestJson(`https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}${pathname}`, {
10341
- method,
10342
- body,
10343
- headers: token ? { Authorization: `Bearer ${token}` } : {}
10344
- });
10345
- };
10346
- const getRef = async (branch) => request(`/git/ref/heads/${encodeGitHubBranchRef(branch)}`);
10347
- const getCommitObject = async (sha) => request(`/git/commits/${encodeURIComponent(sha)}`);
10348
- const createBlob = async ({ content, encoding }) => request("/git/blobs", { method: "POST", body: { content, encoding } });
10349
- const createTree = async ({ baseTree, tree }) => request("/git/trees", { method: "POST", body: { base_tree: baseTree, tree } });
10350
- const createCommit = async ({ message, treeSha, parents }) => request("/git/commits", { method: "POST", body: { message, tree: treeSha, parents } });
10351
- const updateRef = async ({ branch, sha, force = false }) => request(`/git/refs/heads/${encodeGitHubBranchRef(branch)}`, { method: "PATCH", body: { sha, force } });
10352
- return {
10353
- async getPullRequest(number) {
10354
- return request(`/pulls/${encodeURIComponent(number)}`);
10355
- },
10356
- async createPullRequest({ title, head, base, body = "", draft = false, maintainerCanModify = true }) {
10357
- return request("/pulls", {
10358
- method: "POST",
10359
- body: {
10360
- title: String(title || ""),
10361
- head: String(head || ""),
10362
- base: String(base || ""),
10363
- body: String(body || ""),
10364
- draft: draft === true,
10365
- maintainer_can_modify: maintainerCanModify !== false
10366
- }
10367
- });
10368
- },
10369
- async createIssueComment({ issueNumber, body }) {
10370
- return request(`/issues/${encodeURIComponent(issueNumber)}/comments`, { method: "POST", body: { body: String(body || "") } });
10371
- },
10372
- async replyToReviewComment({ commentId, body }) {
10373
- return request(`/pulls/comments/${encodeURIComponent(commentId)}/replies`, { method: "POST", body: { body: String(body || "") } });
10374
- },
10375
- async createPullRequestReview({ pullNumber, body, event = "COMMENT" }) {
10376
- return request(`/pulls/${encodeURIComponent(pullNumber)}/reviews`, { method: "POST", body: { body: String(body || ""), event: String(event || "COMMENT").toUpperCase() } });
10377
- },
10378
- async mergePullRequest({ pullNumber, commitTitle = "", commitMessage = "", mergeMethod = "squash" }) {
10379
- const body = {
10380
- merge_method: String(mergeMethod || "squash")
10381
- };
10382
- if (commitTitle) body.commit_title = String(commitTitle);
10383
- if (commitMessage) body.commit_message = String(commitMessage);
10384
- return request(`/pulls/${encodeURIComponent(pullNumber)}/merge`, { method: "PUT", body });
10385
- },
10386
- async commitWorktree({ worktree, branch = "", message = "", runGitFn = runGit, syncLocal = false } = {}) {
10387
- const directory = path6.resolve(String(worktree || ""));
10388
- if (!directory || !fs5.existsSync(directory)) throw new Error("worktree does not exist");
10389
- const targetBranch = String(branch || currentGitBranch(directory, runGitFn)).trim();
10390
- if (!targetBranch || targetBranch === "HEAD") throw new Error("target branch is required for GitHub API commit");
10391
- const commitMessage = String(message || "").trim();
10392
- if (!commitMessage) throw new Error("commit message is required");
10393
- const changedPaths = listWorktreeChangedPaths(directory, runGitFn);
10394
- if (changedPaths.length === 0) return { ok: true, action: "no_changes", branch: targetBranch, changedPaths: [] };
10395
- const ref = await getRef(targetBranch);
10396
- const headSha = ref?.object?.sha;
10397
- if (!headSha) throw new Error(`GitHub ref for ${targetBranch} did not include a head sha`);
10398
- const headCommit = await getCommitObject(headSha);
10399
- const baseTree = headCommit?.tree?.sha;
10400
- if (!baseTree) throw new Error(`GitHub commit ${headSha} did not include a tree sha`);
10401
- const tree = [];
10402
- for (const gitPath of changedPaths) {
10403
- const entry = treeEntryForWorktreePath(directory, gitPath);
10404
- if (!entry) continue;
10405
- if (entry.deleted) {
10406
- tree.push({ path: entry.path, mode: entry.mode, type: entry.type, sha: null });
10407
- continue;
10408
- }
10409
- const blob = await createBlob({ content: entry.content, encoding: entry.encoding });
10410
- if (!blob?.sha) throw new Error(`GitHub blob creation failed for ${gitPath}`);
10411
- tree.push({ path: entry.path, mode: entry.mode, type: entry.type, sha: blob.sha });
10412
- }
10413
- if (tree.length === 0) return { ok: true, action: "no_changes", branch: targetBranch, changedPaths: [] };
10414
- const nextTree = await createTree({ baseTree, tree });
10415
- const nextCommit = await createCommit({ message: commitMessage, treeSha: nextTree.sha, parents: [headSha] });
10416
- if (!nextCommit?.sha) throw new Error("GitHub commit creation did not return a sha");
10417
- const updatedRef = await updateRef({ branch: targetBranch, sha: nextCommit.sha, force: false });
10418
- if (syncLocal) {
10419
- runGitFn(directory, ["fetch", "origin", targetBranch]);
10420
- runGitFn(directory, ["reset", "--hard", "FETCH_HEAD"]);
10421
- }
10422
- return {
10423
- ok: true,
10424
- action: "committed",
10425
- branch: targetBranch,
10426
- before: headSha,
10427
- after: nextCommit.sha,
10428
- changedPaths,
10429
- treeEntries: tree.length,
10430
- verification: nextCommit.verification || null,
10431
- ref: updatedRef
10432
- };
10433
- },
10434
- async authMode() {
10435
- if (appEnabled) return { mode: "github_app", appId: String(appConfig.appId || ""), installationId: String(appConfig.installationId || "") };
10436
- if (staticToken) return { mode: "token" };
10437
- return { mode: "anonymous" };
10438
- }
10439
- };
10440
- }
10441
10684
  function createTestClickUpApiClient(config) {
10442
10685
  const metadata = /* @__PURE__ */ new Map();
10443
10686
  return {
@@ -10663,10 +10906,10 @@ async function ensureClickUpWebhookSubscription({ validation, worktree, clickupC
10663
10906
  function verifyClickUpSignature(rawBody, signatureHeader, secret) {
10664
10907
  const signature = String(signatureHeader || "").replace(/^sha256=/i, "").trim();
10665
10908
  if (!signature || !secret) return false;
10666
- const expected = crypto.createHmac("sha256", secret).update(Buffer.isBuffer(rawBody) ? rawBody : String(rawBody || ""), "utf8").digest("hex");
10909
+ const expected = crypto2.createHmac("sha256", secret).update(Buffer.isBuffer(rawBody) ? rawBody : String(rawBody || ""), "utf8").digest("hex");
10667
10910
  const given = Buffer.from(signature, "hex");
10668
10911
  const wanted = Buffer.from(expected, "hex");
10669
- return given.length === wanted.length && crypto.timingSafeEqual(given, wanted);
10912
+ return given.length === wanted.length && crypto2.timingSafeEqual(given, wanted);
10670
10913
  }
10671
10914
  function verifyGitHubSignature(rawBody, signatureHeader, secret) {
10672
10915
  return verifyClickUpSignature(rawBody, signatureHeader, secret);
@@ -10720,9 +10963,9 @@ function rememberClickUpWebhookEvent(state = {}, eventKey, limit = 200) {
10720
10963
  return { duplicate: false, state: { ...state, recentEventKeys: [...recent, eventKey].slice(-limit) } };
10721
10964
  }
10722
10965
  function readClickUpCommentLedgerEntries(ledgerPath) {
10723
- if (!ledgerPath || !fs5.existsSync(ledgerPath)) return [];
10966
+ if (!ledgerPath || !fs8.existsSync(ledgerPath)) return [];
10724
10967
  try {
10725
- const raw = fs5.readFileSync(ledgerPath, "utf8");
10968
+ const raw = fs8.readFileSync(ledgerPath, "utf8");
10726
10969
  const entries = [];
10727
10970
  for (const [index, line] of raw.split(/\r?\n/).entries()) {
10728
10971
  if (!line.trim()) continue;
@@ -10746,11 +10989,11 @@ function readClickUpCommentLedger(ledgerPath) {
10746
10989
  }
10747
10990
  function appendClickUpCommentLedgerEntry(ledgerPath, entry = {}) {
10748
10991
  if (!ledgerPath || !entry.key) return;
10749
- fs5.mkdirSync(path6.dirname(ledgerPath), { recursive: true, mode: 448 });
10750
- fs5.appendFileSync(ledgerPath, `${JSON.stringify(entry)}
10992
+ fs8.mkdirSync(path8.dirname(ledgerPath), { recursive: true, mode: 448 });
10993
+ fs8.appendFileSync(ledgerPath, `${JSON.stringify(entry)}
10751
10994
  `, { encoding: "utf8", mode: 384 });
10752
10995
  try {
10753
- fs5.chmodSync(ledgerPath, 384);
10996
+ fs8.chmodSync(ledgerPath, 384);
10754
10997
  } catch {
10755
10998
  }
10756
10999
  }
@@ -10769,7 +11012,7 @@ function stableClickUpCommentVersionMarker(value) {
10769
11012
  const direct = value.version ?? value.date_updated ?? value.updated_at ?? value.revision ?? value.modified_at;
10770
11013
  const directMarker = stableClickUpCommentVersionMarker(direct);
10771
11014
  if (directMarker) return directMarker;
10772
- return `json:${crypto.createHash("sha256").update(JSON.stringify(value, Object.keys(value).sort())).digest("hex").slice(0, 16)}`;
11015
+ return `json:${crypto2.createHash("sha256").update(JSON.stringify(value, Object.keys(value).sort())).digest("hex").slice(0, 16)}`;
10773
11016
  }
10774
11017
  function clickUpCommentLedgerKey({ taskId, eventType, payload }) {
10775
11018
  const history = Array.isArray(payload?.history_items) ? payload.history_items[0] : payload?.history_item;
@@ -10779,7 +11022,7 @@ function clickUpCommentLedgerKey({ taskId, eventType, payload }) {
10779
11022
  const explicitVersion = stableClickUpCommentVersionMarker(
10780
11023
  comment?.date_updated || comment?.dateUpdated || comment?.updated_at || comment?.updatedAt || comment?._version_vector || comment?.version_vector || comment?.versionVector || comment?.version || comment?.revision || comment?.modified_at || comment?.modifiedAt || ""
10781
11024
  );
10782
- const contentVersion = crypto.createHash("sha256").update(JSON.stringify({ text: clickUpCommentText(comment), parts: Array.isArray(comment.comment) ? comment.comment : null })).digest("hex").slice(0, 16);
11025
+ const contentVersion = crypto2.createHash("sha256").update(JSON.stringify({ text: clickUpCommentText(comment), parts: Array.isArray(comment.comment) ? comment.comment : null })).digest("hex").slice(0, 16);
10783
11026
  return [String(taskId || "").trim(), "comment", commentId, explicitVersion || `sha256-${contentVersion}`].filter(Boolean).join(":");
10784
11027
  }
10785
11028
  function isClickUpCommentVersionProcessed({ ledgerPath, key, ledger = null, worktree = process.cwd() } = {}) {
@@ -11309,7 +11552,7 @@ function clampOpenCodeSessionText(text = "", maxLength = 12e3) {
11309
11552
  return value.length > maxLength ? value.slice(0, maxLength) : value;
11310
11553
  }
11311
11554
  function hashOpenCodeSessionText(text = "") {
11312
- return crypto.createHash("sha256").update(String(text ?? "")).digest("hex");
11555
+ return crypto2.createHash("sha256").update(String(text ?? "")).digest("hex");
11313
11556
  }
11314
11557
  async function readOpenCodeSessionMessages(client, { sessionId, directory, limit = 20 } = {}) {
11315
11558
  if (typeof client?.session?.messages !== "function") return null;
@@ -11547,7 +11790,7 @@ async function readOpenCodeSessionControl(client, { sessionId, directory, limit
11547
11790
  };
11548
11791
  }
11549
11792
  async function probeOpenCodeSessionControl(client, { directory, agent, omitAgentOnPrompt = false, text = "" } = {}) {
11550
- const requestedMarker = text || `optima-session-probe-${crypto.randomUUID()}`;
11793
+ const requestedMarker = text || `optima-session-probe-${crypto2.randomUUID()}`;
11551
11794
  const marker = clampOpenCodeSessionText(requestedMarker);
11552
11795
  const create = await createOpenCodeSessionControl(client, {
11553
11796
  directory,
@@ -11775,9 +12018,9 @@ function formatClickUpWebhookPrompt({ eventType, taskId, payload, branch = "", w
11775
12018
  }
11776
12019
  function appendClickUpWebhookLocalLog(worktree, entry) {
11777
12020
  const logPath = clickUpWebhookLogPath(worktree);
11778
- fs5.mkdirSync(path6.dirname(logPath), { recursive: true });
12021
+ fs8.mkdirSync(path8.dirname(logPath), { recursive: true });
11779
12022
  const safeEntry = { ...entry, at: entry.at || (/* @__PURE__ */ new Date()).toISOString() };
11780
- fs5.appendFileSync(logPath, `${JSON.stringify(safeEntry)}
12023
+ fs8.appendFileSync(logPath, `${JSON.stringify(safeEntry)}
11781
12024
  `, "utf8");
11782
12025
  }
11783
12026
  function clickUpWebhookLifecycleLog(worktree, entry) {
@@ -11806,7 +12049,7 @@ function closeClickUpWebhookServer(server) {
11806
12049
  });
11807
12050
  }
11808
12051
  function managedClickUpWebhookKey({ worktree, state, config } = {}) {
11809
- return [path6.resolve(worktree || process.cwd()), state?.webhookId || "", config?.webhook?.publicUrl || ""].join("|");
12052
+ return [path8.resolve(worktree || process.cwd()), state?.webhookId || "", config?.webhook?.publicUrl || ""].join("|");
11810
12053
  }
11811
12054
  async function deleteClickUpWebhookBestEffort({ webhookId, clickupClient, worktree, reason = "cleanup" } = {}) {
11812
12055
  const id = String(webhookId || "").trim();
@@ -11906,7 +12149,7 @@ function writeClickUpWebhookAuditLog({ method, url, headers = {}, rawBody = "",
11906
12149
  const failed = Boolean(error || !handled?.ok || (handled?.status || 500) >= 400);
11907
12150
  if (level === "error" && !failed) return;
11908
12151
  const logDir = clickUpWebhookAuditLogDir();
11909
- fs5.mkdirSync(logDir, { recursive: true });
12152
+ fs8.mkdirSync(logDir, { recursive: true });
11910
12153
  const secretValues = [
11911
12154
  resolveSecretReference(config?.apiToken),
11912
12155
  resolveSecretReference(config?.github?.apiToken),
@@ -11917,8 +12160,8 @@ function writeClickUpWebhookAuditLog({ method, url, headers = {}, rawBody = "",
11917
12160
  let requestFile;
11918
12161
  if (level === "verbose") {
11919
12162
  const absoluteRequestFile = clickUpWebhookRequestFilePath(at, logDir);
11920
- fs5.mkdirSync(path6.dirname(absoluteRequestFile), { recursive: true });
11921
- requestFile = path6.relative(logDir, absoluteRequestFile).split(path6.sep).join("/");
12163
+ fs8.mkdirSync(path8.dirname(absoluteRequestFile), { recursive: true });
12164
+ requestFile = path8.relative(logDir, absoluteRequestFile).split(path8.sep).join("/");
11922
12165
  const parsedBody = payload || (() => {
11923
12166
  try {
11924
12167
  return JSON.parse(Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : String(rawBody || ""));
@@ -11934,11 +12177,11 @@ function writeClickUpWebhookAuditLog({ method, url, headers = {}, rawBody = "",
11934
12177
  headers,
11935
12178
  body: parsedBody === void 0 ? Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : String(rawBody || "") : parsedBody
11936
12179
  }, secretValues);
11937
- fs5.writeFileSync(absoluteRequestFile, `${JSON.stringify(requestArtifact, null, 2)}
12180
+ fs8.writeFileSync(absoluteRequestFile, `${JSON.stringify(requestArtifact, null, 2)}
11938
12181
  `, "utf8");
11939
12182
  }
11940
12183
  const summary = redactClickUpWebhookAuditValue(buildClickUpWebhookAuditSummary({ method, url, config, handled, error, payload, requestFile, at }), secretValues);
11941
- fs5.appendFileSync(clickUpWebhookAuditLogPath(at, logDir), `${JSON.stringify(summary)}
12184
+ fs8.appendFileSync(clickUpWebhookAuditLogPath(at, logDir), `${JSON.stringify(summary)}
11942
12185
  `, "utf8");
11943
12186
  } catch {
11944
12187
  }
@@ -11956,7 +12199,7 @@ async function withClickUpTaskRouteLock(taskId, operation) {
11956
12199
  if (activeClickUpTaskRoutes.get(key) === current) activeClickUpTaskRoutes.delete(key);
11957
12200
  }
11958
12201
  }
11959
- async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, worktree = process.cwd(), clickupClient, openCodeClient, sessionExists = openCodeSessionExists, createSession = createOpenCodeSession, sendSessionEvent = sendOpenCodeSessionEvent, ensureTaskWorktree = ensureClickUpTaskWorktreeForWebhook, verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, saveState = null, now = () => /* @__PURE__ */ new Date(), host = os.hostname(), commentLedgerPath = clickUpCommentLedgerPath(worktree) } = {}) {
12202
+ async function routeClickUpWebhookEventUnlocked({ payload, config, state = {}, worktree = process.cwd(), clickupClient, openCodeClient, sessionExists = openCodeSessionExists, createSession = createOpenCodeSession, sendSessionEvent = sendOpenCodeSessionEvent, ensureTaskWorktree = ensureClickUpTaskWorktreeForWebhook, verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, saveState = null, now = () => /* @__PURE__ */ new Date(), host = os2.hostname(), commentLedgerPath = clickUpCommentLedgerPath(worktree) } = {}) {
11960
12203
  const eventType = clickUpEventType(payload);
11961
12204
  const eventKey = clickUpWebhookEventKey(payload);
11962
12205
  const isStartupAssignmentReconciliation = payload?.startup_reconciliation === true && eventType === "taskAssigneeUpdated";
@@ -12725,17 +12968,17 @@ function startClickUpWebhookListener({ config, state, worktree, clickupClient, g
12725
12968
  return result;
12726
12969
  }
12727
12970
  function legacyVariantPath(destinationPath) {
12728
- const parsed = path6.parse(destinationPath);
12971
+ const parsed = path8.parse(destinationPath);
12729
12972
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:TZ.]/g, "").slice(0, 14);
12730
- if (parsed.ext) return path6.join(parsed.dir, `${parsed.name}.legacy-${stamp}${parsed.ext}`);
12731
- return path6.join(parsed.dir, `${parsed.base}.legacy-${stamp}`);
12973
+ if (parsed.ext) return path8.join(parsed.dir, `${parsed.name}.legacy-${stamp}${parsed.ext}`);
12974
+ return path8.join(parsed.dir, `${parsed.base}.legacy-${stamp}`);
12732
12975
  }
12733
12976
  function normalizeWorkflowTaskPath(taskPath) {
12734
12977
  if (typeof taskPath !== "string") return { ok: false, message: "Error: task_path is required." };
12735
12978
  const trimmed = taskPath.trim();
12736
12979
  if (!trimmed) return { ok: false, message: "Error: task_path is required." };
12737
12980
  const normalized = trimmed.replace(/\\/g, "/");
12738
- if (path6.isAbsolute(trimmed)) return { ok: true, taskPath: trimmed };
12981
+ if (path8.isAbsolute(trimmed)) return { ok: true, taskPath: trimmed };
12739
12982
  if (normalized === "tasks" || normalized.startsWith("tasks/")) {
12740
12983
  return {
12741
12984
  ok: false,
@@ -12753,78 +12996,78 @@ function normalizeWorkflowTaskPath(taskPath) {
12753
12996
  function mergeFileIntoDestination(sourcePath, destinationPath, relativeSource, gitState = null) {
12754
12997
  const sourceWasTracked = isGitTracked(gitState, sourcePath);
12755
12998
  if (gitAwareMoveIfTracked(sourcePath, destinationPath, gitState)) return;
12756
- if (!fs5.existsSync(destinationPath)) {
12757
- fs5.mkdirSync(path6.dirname(destinationPath), { recursive: true });
12758
- fs5.renameSync(sourcePath, destinationPath);
12999
+ if (!fs8.existsSync(destinationPath)) {
13000
+ fs8.mkdirSync(path8.dirname(destinationPath), { recursive: true });
13001
+ fs8.renameSync(sourcePath, destinationPath);
12759
13002
  if (sourceWasTracked) stageGitAwareMerge(sourcePath, destinationPath, gitState);
12760
13003
  return;
12761
13004
  }
12762
- const ext = path6.extname(destinationPath).toLowerCase();
13005
+ const ext = path8.extname(destinationPath).toLowerCase();
12763
13006
  if ([".yaml", ".yml", ".json"].includes(ext)) {
12764
- const sourceRaw = fs5.readFileSync(sourcePath, "utf8");
12765
- const destRaw = fs5.readFileSync(destinationPath, "utf8");
13007
+ const sourceRaw = fs8.readFileSync(sourcePath, "utf8");
13008
+ const destRaw = fs8.readFileSync(destinationPath, "utf8");
12766
13009
  const parser = ext === ".json" ? JSON : import_yaml3.default;
12767
13010
  const sourceValue = parser.parse(sourceRaw) || {};
12768
13011
  const destValue = parser.parse(destRaw) || {};
12769
13012
  const merged = mergeStructuredValues(sourceValue, destValue);
12770
13013
  const serialized = ext === ".json" ? `${JSON.stringify(merged, null, 2)}
12771
13014
  ` : import_yaml3.default.stringify(merged);
12772
- fs5.writeFileSync(destinationPath, serialized, "utf8");
12773
- fs5.unlinkSync(sourcePath);
13015
+ fs8.writeFileSync(destinationPath, serialized, "utf8");
13016
+ fs8.unlinkSync(sourcePath);
12774
13017
  stageGitAwareMerge(sourcePath, destinationPath, gitState);
12775
13018
  return;
12776
13019
  }
12777
13020
  if (ext === ".md") {
12778
- const sourceRaw = fs5.readFileSync(sourcePath, "utf8").trimEnd();
12779
- const destRaw = fs5.readFileSync(destinationPath, "utf8").trimEnd();
13021
+ const sourceRaw = fs8.readFileSync(sourcePath, "utf8").trimEnd();
13022
+ const destRaw = fs8.readFileSync(destinationPath, "utf8").trimEnd();
12780
13023
  if (sourceRaw && !destRaw.includes(sourceRaw)) {
12781
13024
  const marker = `## Legacy Content From ${relativeSource}`;
12782
- fs5.writeFileSync(destinationPath, `${destRaw}
13025
+ fs8.writeFileSync(destinationPath, `${destRaw}
12783
13026
 
12784
13027
  ${marker}
12785
13028
 
12786
13029
  ${sourceRaw}
12787
13030
  `, "utf8");
12788
13031
  }
12789
- fs5.unlinkSync(sourcePath);
13032
+ fs8.unlinkSync(sourcePath);
12790
13033
  stageGitAwareMerge(sourcePath, destinationPath, gitState);
12791
13034
  return;
12792
13035
  }
12793
13036
  const preservedPath = legacyVariantPath(destinationPath);
12794
- fs5.renameSync(sourcePath, preservedPath);
13037
+ fs8.renameSync(sourcePath, preservedPath);
12795
13038
  stageGitAwareMerge(sourcePath, preservedPath, gitState);
12796
13039
  }
12797
- function mergePathIntoDestination(sourcePath, destinationPath, relativeSource = path6.basename(sourcePath), gitState = null) {
12798
- if (!fs5.existsSync(sourcePath)) return;
12799
- const stat = fs5.statSync(sourcePath);
13040
+ function mergePathIntoDestination(sourcePath, destinationPath, relativeSource = path8.basename(sourcePath), gitState = null) {
13041
+ if (!fs8.existsSync(sourcePath)) return;
13042
+ const stat = fs8.statSync(sourcePath);
12800
13043
  if (stat.isDirectory()) {
12801
13044
  const sourceWasTracked = isGitTracked(gitState, sourcePath) || hasGitTrackedChildren(gitState, sourcePath);
12802
13045
  if (gitAwareMoveIfTracked(sourcePath, destinationPath, gitState)) return;
12803
- if (!fs5.existsSync(destinationPath)) {
12804
- fs5.mkdirSync(path6.dirname(destinationPath), { recursive: true });
12805
- fs5.renameSync(sourcePath, destinationPath);
13046
+ if (!fs8.existsSync(destinationPath)) {
13047
+ fs8.mkdirSync(path8.dirname(destinationPath), { recursive: true });
13048
+ fs8.renameSync(sourcePath, destinationPath);
12806
13049
  if (sourceWasTracked) stageGitAwareMerge(sourcePath, destinationPath, gitState);
12807
13050
  return;
12808
13051
  }
12809
- fs5.mkdirSync(destinationPath, { recursive: true });
12810
- for (const entry of fs5.readdirSync(sourcePath)) {
13052
+ fs8.mkdirSync(destinationPath, { recursive: true });
13053
+ for (const entry of fs8.readdirSync(sourcePath)) {
12811
13054
  mergePathIntoDestination(
12812
- path6.join(sourcePath, entry),
12813
- path6.join(destinationPath, entry),
12814
- path6.join(relativeSource, entry),
13055
+ path8.join(sourcePath, entry),
13056
+ path8.join(destinationPath, entry),
13057
+ path8.join(relativeSource, entry),
12815
13058
  gitState
12816
13059
  );
12817
13060
  }
12818
- fs5.rmSync(sourcePath, { recursive: true, force: true });
13061
+ fs8.rmSync(sourcePath, { recursive: true, force: true });
12819
13062
  return;
12820
13063
  }
12821
13064
  mergeFileIntoDestination(sourcePath, destinationPath, relativeSource, gitState);
12822
13065
  }
12823
13066
  function isOptimaPluginPackageWorktree(worktree) {
12824
- const packageJsonPath = path6.join(worktree, "package.json");
12825
- if (!fs5.existsSync(packageJsonPath)) return false;
13067
+ const packageJsonPath = path8.join(worktree, "package.json");
13068
+ if (!fs8.existsSync(packageJsonPath)) return false;
12826
13069
  try {
12827
- const pkg = JSON.parse(fs5.readFileSync(packageJsonPath, "utf8"));
13070
+ const pkg = JSON.parse(fs8.readFileSync(packageJsonPath, "utf8"));
12828
13071
  return pkg?.name === "@defend-tech/opencode-optima";
12829
13072
  } catch {
12830
13073
  return false;
@@ -12833,59 +13076,59 @@ function isOptimaPluginPackageWorktree(worktree) {
12833
13076
  function migrateLegacyOptimaLayout(worktree) {
12834
13077
  const gitState = gitMigrationState(worktree);
12835
13078
  const migrations = [
12836
- [path6.join(legacyOrbitaDir(worktree), "orbita.yaml"), repoConfigPath(worktree), path6.join(".orbita", "orbita.yaml")],
12837
- [path6.join(legacyOrbitaDir(worktree), "staticeng.yaml"), repoConfigPath(worktree), path6.join(".orbita", "staticeng.yaml")],
12838
- [path6.join(legacyOrbitaDir(worktree), ".config"), optimaLocalConfigDir(worktree), path6.join(".orbita", ".config")],
12839
- [path6.join(legacyOrbitaDir(worktree), "config"), optimaLocalConfigDir(worktree), path6.join(".orbita", "config")],
12840
- [path6.join(legacyOrbitaDir(worktree), "runtime"), path6.join(optimaLocalConfigDir(worktree), "runtime"), path6.join(".orbita", "runtime")],
12841
- [path6.join(legacyOrbitaDir(worktree), "generated"), path6.join(optimaLocalConfigDir(worktree), "generated"), path6.join(".orbita", "generated")],
13079
+ [path8.join(legacyOrbitaDir(worktree), "orbita.yaml"), repoConfigPath(worktree), path8.join(".orbita", "orbita.yaml")],
13080
+ [path8.join(legacyOrbitaDir(worktree), "staticeng.yaml"), repoConfigPath(worktree), path8.join(".orbita", "staticeng.yaml")],
13081
+ [path8.join(legacyOrbitaDir(worktree), ".config"), optimaLocalConfigDir(worktree), path8.join(".orbita", ".config")],
13082
+ [path8.join(legacyOrbitaDir(worktree), "config"), optimaLocalConfigDir(worktree), path8.join(".orbita", "config")],
13083
+ [path8.join(legacyOrbitaDir(worktree), "runtime"), path8.join(optimaLocalConfigDir(worktree), "runtime"), path8.join(".orbita", "runtime")],
13084
+ [path8.join(legacyOrbitaDir(worktree), "generated"), path8.join(optimaLocalConfigDir(worktree), "generated"), path8.join(".orbita", "generated")],
12842
13085
  [legacyOrbitaDir(worktree), optimaDir(worktree), ".orbita"],
12843
- [path6.join(legacyStaticEngDir(worktree), "staticeng.yaml"), repoConfigPath(worktree), path6.join(".staticeng", "staticeng.yaml")],
12844
- [path6.join(legacyStaticEngDir(worktree), "orbita.yaml"), repoConfigPath(worktree), path6.join(".staticeng", "orbita.yaml")],
12845
- [path6.join(legacyStaticEngDir(worktree), ".config"), optimaLocalConfigDir(worktree), path6.join(".staticeng", ".config")],
12846
- [path6.join(legacyStaticEngDir(worktree), "config"), optimaLocalConfigDir(worktree), path6.join(".staticeng", "config")],
12847
- [path6.join(legacyStaticEngDir(worktree), "runtime"), path6.join(optimaLocalConfigDir(worktree), "runtime"), path6.join(".staticeng", "runtime")],
12848
- [path6.join(legacyStaticEngDir(worktree), "generated"), path6.join(optimaLocalConfigDir(worktree), "generated"), path6.join(".staticeng", "generated")],
13086
+ [path8.join(legacyStaticEngDir(worktree), "staticeng.yaml"), repoConfigPath(worktree), path8.join(".staticeng", "staticeng.yaml")],
13087
+ [path8.join(legacyStaticEngDir(worktree), "orbita.yaml"), repoConfigPath(worktree), path8.join(".staticeng", "orbita.yaml")],
13088
+ [path8.join(legacyStaticEngDir(worktree), ".config"), optimaLocalConfigDir(worktree), path8.join(".staticeng", ".config")],
13089
+ [path8.join(legacyStaticEngDir(worktree), "config"), optimaLocalConfigDir(worktree), path8.join(".staticeng", "config")],
13090
+ [path8.join(legacyStaticEngDir(worktree), "runtime"), path8.join(optimaLocalConfigDir(worktree), "runtime"), path8.join(".staticeng", "runtime")],
13091
+ [path8.join(legacyStaticEngDir(worktree), "generated"), path8.join(optimaLocalConfigDir(worktree), "generated"), path8.join(".staticeng", "generated")],
12849
13092
  [legacyStaticEngDir(worktree), optimaDir(worktree), ".staticeng"],
12850
- [path6.join(legacyNomadworkDir(worktree), "nomadworks.yaml"), repoConfigPath(worktree), path6.join(".nomadwork", "nomadworks.yaml")],
12851
- [path6.join(legacyNomadworksDir(worktree), "nomadworks.yaml"), repoConfigPath(worktree), path6.join(".nomadworks", "nomadworks.yaml")],
12852
- [path6.join(legacyNomadworkDir(worktree), "staticeng.yaml"), repoConfigPath(worktree), path6.join(".nomadwork", "staticeng.yaml")],
12853
- [path6.join(legacyNomadworksDir(worktree), "staticeng.yaml"), repoConfigPath(worktree), path6.join(".nomadworks", "staticeng.yaml")],
12854
- [path6.join(legacyNomadworkDir(worktree), "orbita.yaml"), repoConfigPath(worktree), path6.join(".nomadwork", "orbita.yaml")],
12855
- [path6.join(legacyNomadworksDir(worktree), "orbita.yaml"), repoConfigPath(worktree), path6.join(".nomadworks", "orbita.yaml")],
12856
- [path6.join(legacyNomadworkDir(worktree), "runtime"), path6.join(optimaLocalConfigDir(worktree), "runtime"), path6.join(".nomadwork", "runtime")],
12857
- [path6.join(legacyNomadworksDir(worktree), "runtime"), path6.join(optimaLocalConfigDir(worktree), "runtime"), path6.join(".nomadworks", "runtime")],
12858
- [path6.join(legacyNomadworkDir(worktree), "generated"), path6.join(optimaLocalConfigDir(worktree), "generated"), path6.join(".nomadwork", "generated")],
12859
- [path6.join(legacyNomadworksDir(worktree), "generated"), path6.join(optimaLocalConfigDir(worktree), "generated"), path6.join(".nomadworks", "generated")],
12860
- [path6.join(legacyNomadworkDir(worktree), "config"), optimaLocalConfigDir(worktree), path6.join(".nomadwork", "config")],
12861
- [path6.join(legacyNomadworksDir(worktree), "config"), optimaLocalConfigDir(worktree), path6.join(".nomadworks", "config")],
13093
+ [path8.join(legacyNomadworkDir(worktree), "nomadworks.yaml"), repoConfigPath(worktree), path8.join(".nomadwork", "nomadworks.yaml")],
13094
+ [path8.join(legacyNomadworksDir(worktree), "nomadworks.yaml"), repoConfigPath(worktree), path8.join(".nomadworks", "nomadworks.yaml")],
13095
+ [path8.join(legacyNomadworkDir(worktree), "staticeng.yaml"), repoConfigPath(worktree), path8.join(".nomadwork", "staticeng.yaml")],
13096
+ [path8.join(legacyNomadworksDir(worktree), "staticeng.yaml"), repoConfigPath(worktree), path8.join(".nomadworks", "staticeng.yaml")],
13097
+ [path8.join(legacyNomadworkDir(worktree), "orbita.yaml"), repoConfigPath(worktree), path8.join(".nomadwork", "orbita.yaml")],
13098
+ [path8.join(legacyNomadworksDir(worktree), "orbita.yaml"), repoConfigPath(worktree), path8.join(".nomadworks", "orbita.yaml")],
13099
+ [path8.join(legacyNomadworkDir(worktree), "runtime"), path8.join(optimaLocalConfigDir(worktree), "runtime"), path8.join(".nomadwork", "runtime")],
13100
+ [path8.join(legacyNomadworksDir(worktree), "runtime"), path8.join(optimaLocalConfigDir(worktree), "runtime"), path8.join(".nomadworks", "runtime")],
13101
+ [path8.join(legacyNomadworkDir(worktree), "generated"), path8.join(optimaLocalConfigDir(worktree), "generated"), path8.join(".nomadwork", "generated")],
13102
+ [path8.join(legacyNomadworksDir(worktree), "generated"), path8.join(optimaLocalConfigDir(worktree), "generated"), path8.join(".nomadworks", "generated")],
13103
+ [path8.join(legacyNomadworkDir(worktree), "config"), optimaLocalConfigDir(worktree), path8.join(".nomadwork", "config")],
13104
+ [path8.join(legacyNomadworksDir(worktree), "config"), optimaLocalConfigDir(worktree), path8.join(".nomadworks", "config")],
12862
13105
  [legacyNomadworkDir(worktree), optimaDir(worktree), ".nomadwork"],
12863
13106
  [legacyNomadworksDir(worktree), optimaDir(worktree), ".nomadworks"],
12864
- [path6.join(worktree, "tasks"), optimaTasksDir(worktree), "tasks"],
12865
- [path6.join(worktree, "evidences"), optimaEvidencesDir(worktree), "evidences"],
12866
- [path6.join(worktree, "docs", "scrs"), optimaScrsDir(worktree), path6.join("docs", "scrs")],
12867
- [path6.join(worktree, "codemap.yml"), optimaCodemapPath(worktree), "codemap.yml"],
12868
- [path6.join(worktree, "codemap.yaml"), optimaCodemapPath(worktree), "codemap.yaml"]
13107
+ [path8.join(worktree, "tasks"), optimaTasksDir(worktree), "tasks"],
13108
+ [path8.join(worktree, "evidences"), optimaEvidencesDir(worktree), "evidences"],
13109
+ [path8.join(worktree, "docs", "scrs"), optimaScrsDir(worktree), path8.join("docs", "scrs")],
13110
+ [path8.join(worktree, "codemap.yml"), optimaCodemapPath(worktree), "codemap.yml"],
13111
+ [path8.join(worktree, "codemap.yaml"), optimaCodemapPath(worktree), "codemap.yaml"]
12869
13112
  ];
12870
13113
  if (!isOptimaPluginPackageWorktree(worktree)) {
12871
- migrations.push([path6.join(worktree, "policies"), repoPoliciesDir(worktree), "policies"]);
13114
+ migrations.push([path8.join(worktree, "policies"), repoPoliciesDir(worktree), "policies"]);
12872
13115
  }
12873
13116
  for (const [source, destination, relativeSource] of migrations) {
12874
- if (fs5.existsSync(source)) mergePathIntoDestination(source, destination, relativeSource, gitState);
13117
+ if (fs8.existsSync(source)) mergePathIntoDestination(source, destination, relativeSource, gitState);
12875
13118
  }
12876
13119
  for (const [source, destination, relativeSource] of [
12877
- [path6.join(optimaDir(worktree), "optima.yaml"), repoConfigPath(worktree), path6.join(".optima", "optima.yaml")],
12878
- [path6.join(optimaDir(worktree), "config"), optimaLocalConfigDir(worktree), path6.join(".optima", "config")],
12879
- [path6.join(optimaDir(worktree), "runtime"), path6.join(optimaLocalConfigDir(worktree), "runtime"), path6.join(".optima", "runtime")],
12880
- [path6.join(optimaDir(worktree), "generated"), path6.join(optimaLocalConfigDir(worktree), "generated"), path6.join(".optima", "generated")]
13120
+ [path8.join(optimaDir(worktree), "optima.yaml"), repoConfigPath(worktree), path8.join(".optima", "optima.yaml")],
13121
+ [path8.join(optimaDir(worktree), "config"), optimaLocalConfigDir(worktree), path8.join(".optima", "config")],
13122
+ [path8.join(optimaDir(worktree), "runtime"), path8.join(optimaLocalConfigDir(worktree), "runtime"), path8.join(".optima", "runtime")],
13123
+ [path8.join(optimaDir(worktree), "generated"), path8.join(optimaLocalConfigDir(worktree), "generated"), path8.join(".optima", "generated")]
12881
13124
  ]) {
12882
- if (fs5.existsSync(source)) mergePathIntoDestination(source, destination, relativeSource, gitState);
13125
+ if (fs8.existsSync(source)) mergePathIntoDestination(source, destination, relativeSource, gitState);
12883
13126
  }
12884
13127
  }
12885
13128
  function listMarkdownFiles(dirPath) {
12886
- if (!fs5.existsSync(dirPath)) return [];
13129
+ if (!fs8.existsSync(dirPath)) return [];
12887
13130
  try {
12888
- return fs5.readdirSync(dirPath).filter((file) => file.endsWith(".md") && file.toLowerCase() !== "readme.md");
13131
+ return fs8.readdirSync(dirPath).filter((file) => file.endsWith(".md") && file.toLowerCase() !== "readme.md");
12889
13132
  } catch (e) {
12890
13133
  console.error(`[Optima] Failed to read markdown files from ${dirPath}:`, e);
12891
13134
  return [];
@@ -12926,10 +13169,10 @@ function toModelString(provider, model) {
12926
13169
  }
12927
13170
  function readTaskMetadata(taskPath, worktree) {
12928
13171
  if (!taskPath) return {};
12929
- const absoluteTaskPath = path6.isAbsolute(taskPath) ? taskPath : path6.join(worktree, taskPath);
12930
- if (!fs5.existsSync(absoluteTaskPath)) return {};
13172
+ const absoluteTaskPath = path8.isAbsolute(taskPath) ? taskPath : path8.join(worktree, taskPath);
13173
+ if (!fs8.existsSync(absoluteTaskPath)) return {};
12931
13174
  try {
12932
- const raw = fs5.readFileSync(absoluteTaskPath, "utf8");
13175
+ const raw = fs8.readFileSync(absoluteTaskPath, "utf8");
12933
13176
  const { data } = parseFrontmatter(raw);
12934
13177
  return {
12935
13178
  complexity: typeof data.complexity === "string" ? data.complexity.trim().toLowerCase() : void 0,
@@ -12954,11 +13197,11 @@ function slugifyTitle(input) {
12954
13197
  }
12955
13198
  function loadDiscussionRegistry(worktree) {
12956
13199
  const registryPath = runtimeDiscussionRegistryPath(worktree);
12957
- if (!fs5.existsSync(registryPath)) {
13200
+ if (!fs8.existsSync(registryPath)) {
12958
13201
  return { version: 1, active: {} };
12959
13202
  }
12960
13203
  try {
12961
- const parsed = JSON.parse(fs5.readFileSync(registryPath, "utf8"));
13204
+ const parsed = JSON.parse(fs8.readFileSync(registryPath, "utf8"));
12962
13205
  const registry = {
12963
13206
  version: 1,
12964
13207
  active: Object.fromEntries(Object.entries(parsed.active || {}).map(([key, value]) => [key, normalizeLegacyDiscussionEntry(value)]))
@@ -12971,34 +13214,34 @@ function loadDiscussionRegistry(worktree) {
12971
13214
  }
12972
13215
  function saveDiscussionRegistry(worktree, registry) {
12973
13216
  const registryPath = runtimeDiscussionRegistryPath(worktree);
12974
- const runtimeDir = path6.dirname(registryPath);
12975
- if (!fs5.existsSync(runtimeDir)) fs5.mkdirSync(runtimeDir, { recursive: true });
12976
- fs5.writeFileSync(registryPath, JSON.stringify(registry, null, 2), "utf8");
13217
+ const runtimeDir = path8.dirname(registryPath);
13218
+ if (!fs8.existsSync(runtimeDir)) fs8.mkdirSync(runtimeDir, { recursive: true });
13219
+ fs8.writeFileSync(registryPath, JSON.stringify(registry, null, 2), "utf8");
12977
13220
  }
12978
13221
  function runtimeDiscussionsDir(worktree) {
12979
- return path6.join(optimaLocalConfigDir(worktree), "runtime", "discussions");
13222
+ return path8.join(optimaLocalConfigDir(worktree), "runtime", "discussions");
12980
13223
  }
12981
13224
  function archivedRuntimeDiscussionsDir(worktree) {
12982
- return path6.join(runtimeDiscussionsDir(worktree), "archive");
13225
+ return path8.join(runtimeDiscussionsDir(worktree), "archive");
12983
13226
  }
12984
13227
  function finalDiscussionsDir(worktree) {
12985
- return path6.join(optimaTasksDir(worktree), "discussions");
13228
+ return path8.join(optimaTasksDir(worktree), "discussions");
12986
13229
  }
12987
13230
  function nextDiscussionIdentity(worktree, title) {
12988
13231
  const discussionsDir = finalDiscussionsDir(worktree);
12989
13232
  const runtimeDir = runtimeDiscussionsDir(worktree);
12990
- if (!fs5.existsSync(discussionsDir)) fs5.mkdirSync(discussionsDir, { recursive: true });
12991
- if (!fs5.existsSync(runtimeDir)) fs5.mkdirSync(runtimeDir, { recursive: true });
13233
+ if (!fs8.existsSync(discussionsDir)) fs8.mkdirSync(discussionsDir, { recursive: true });
13234
+ if (!fs8.existsSync(runtimeDir)) fs8.mkdirSync(runtimeDir, { recursive: true });
12992
13235
  let sequence = 1;
12993
13236
  while (true) {
12994
13237
  const id = `DISCUSSION-${String(sequence).padStart(3, "0")}`;
12995
13238
  const filename = `${id}-${slugifyTitle(title)}.md`;
12996
- const summaryRelativePath = path6.join(".optima", "tasks", "discussions", filename);
12997
- const summaryAbsolutePath = path6.join(worktree, summaryRelativePath);
13239
+ const summaryRelativePath = path8.join(".optima", "tasks", "discussions", filename);
13240
+ const summaryAbsolutePath = path8.join(worktree, summaryRelativePath);
12998
13241
  const transcriptFilename = `${id}-transcript.md`;
12999
- const transcriptRelativePath = path6.join(".optima", ".config", "runtime", "discussions", transcriptFilename);
13000
- const transcriptAbsolutePath = path6.join(worktree, transcriptRelativePath);
13001
- if (!fs5.existsSync(summaryAbsolutePath) && !fs5.existsSync(transcriptAbsolutePath)) {
13242
+ const transcriptRelativePath = path8.join(".optima", ".config", "runtime", "discussions", transcriptFilename);
13243
+ const transcriptAbsolutePath = path8.join(worktree, transcriptRelativePath);
13244
+ if (!fs8.existsSync(summaryAbsolutePath) && !fs8.existsSync(transcriptAbsolutePath)) {
13002
13245
  return {
13003
13246
  id,
13004
13247
  filename,
@@ -13014,23 +13257,23 @@ function nextDiscussionIdentity(worktree, title) {
13014
13257
  }
13015
13258
  function findDiscussionById(worktree, discussionID) {
13016
13259
  const discussionsDir = finalDiscussionsDir(worktree);
13017
- if (!fs5.existsSync(discussionsDir)) return null;
13018
- const entries = fs5.readdirSync(discussionsDir).filter((name) => name.startsWith(`${discussionID}-`) && name.endsWith(".md"));
13260
+ if (!fs8.existsSync(discussionsDir)) return null;
13261
+ const entries = fs8.readdirSync(discussionsDir).filter((name) => name.startsWith(`${discussionID}-`) && name.endsWith(".md"));
13019
13262
  if (entries.length === 0) return null;
13020
13263
  const filename = entries.sort()[0];
13021
13264
  const transcriptFilename = `${discussionID}-transcript.md`;
13022
13265
  return {
13023
13266
  id: discussionID,
13024
13267
  filename,
13025
- summaryRelativePath: path6.join(".optima", "tasks", "discussions", filename),
13026
- summaryAbsolutePath: path6.join(discussionsDir, filename),
13268
+ summaryRelativePath: path8.join(".optima", "tasks", "discussions", filename),
13269
+ summaryAbsolutePath: path8.join(discussionsDir, filename),
13027
13270
  transcriptFilename,
13028
- transcriptRelativePath: path6.join(".optima", ".config", "runtime", "discussions", transcriptFilename),
13029
- transcriptAbsolutePath: path6.join(runtimeDiscussionsDir(worktree), transcriptFilename)
13271
+ transcriptRelativePath: path8.join(".optima", ".config", "runtime", "discussions", transcriptFilename),
13272
+ transcriptAbsolutePath: path8.join(runtimeDiscussionsDir(worktree), transcriptFilename)
13030
13273
  };
13031
13274
  }
13032
13275
  function parseDiscussionFile(filePath) {
13033
- const raw = fs5.readFileSync(filePath, "utf8");
13276
+ const raw = fs8.readFileSync(filePath, "utf8");
13034
13277
  const { data, body } = parseFrontmatter(raw);
13035
13278
  return { data, body: body.trimStart() };
13036
13279
  }
@@ -13041,10 +13284,10 @@ ${import_yaml3.default.stringify(frontmatter).trim()}
13041
13284
 
13042
13285
  ${body.trimEnd()}
13043
13286
  `;
13044
- fs5.writeFileSync(filePath, serialized, "utf8");
13287
+ fs8.writeFileSync(filePath, serialized, "utf8");
13045
13288
  }
13046
13289
  function setDiscussionStatus(filePath, status) {
13047
- if (!fs5.existsSync(filePath)) return;
13290
+ if (!fs8.existsSync(filePath)) return;
13048
13291
  const { data, body } = parseDiscussionFile(filePath);
13049
13292
  writeDiscussionFile(filePath, { ...data, status }, body);
13050
13293
  }
@@ -13109,18 +13352,18 @@ async function appendMessageIfNeeded(client, worktree, registry, sessionID, mess
13109
13352
  });
13110
13353
  const text = extractTextParts(response.data.parts || []);
13111
13354
  if (!text) return;
13112
- appendDiscussionMessage(path6.join(worktree, discussion.transcriptPath), speaker, text, messageID);
13355
+ appendDiscussionMessage(path8.join(worktree, discussion.transcriptPath), speaker, text, messageID);
13113
13356
  discussion.appendedMessageIDs ??= [];
13114
13357
  discussion.appendedMessageIDs.push(messageID);
13115
13358
  saveDiscussionRegistry(worktree, registry);
13116
13359
  }
13117
13360
  async function summarizeDiscussionWithBA(client, worktree, discussion) {
13118
- const transcriptPath = path6.join(worktree, discussion.transcriptPath);
13119
- const summaryPath = path6.join(worktree, discussion.summaryPath);
13120
- const summaryDir = path6.dirname(summaryPath);
13121
- if (!fs5.existsSync(summaryDir)) fs5.mkdirSync(summaryDir, { recursive: true });
13122
- const hasExistingSummary = fs5.existsSync(summaryPath);
13123
- const priorMtimeMs = hasExistingSummary ? fs5.statSync(summaryPath).mtimeMs : null;
13361
+ const transcriptPath = path8.join(worktree, discussion.transcriptPath);
13362
+ const summaryPath = path8.join(worktree, discussion.summaryPath);
13363
+ const summaryDir = path8.dirname(summaryPath);
13364
+ if (!fs8.existsSync(summaryDir)) fs8.mkdirSync(summaryDir, { recursive: true });
13365
+ const hasExistingSummary = fs8.existsSync(summaryPath);
13366
+ const priorMtimeMs = hasExistingSummary ? fs8.statSync(summaryPath).mtimeMs : null;
13124
13367
  const summarizerSession = await client.session.create({
13125
13368
  body: { title: `Discussion Summary: ${discussion.id}` }
13126
13369
  });
@@ -13220,30 +13463,30 @@ async function summarizeDiscussionWithBA(client, worktree, discussion) {
13220
13463
  return { confirmation, summaryPath, transcriptPath, hasExistingSummary, priorMtimeMs };
13221
13464
  }
13222
13465
  function archiveDiscussionTranscript(worktree, transcriptRelativePath) {
13223
- const sourcePath = path6.join(worktree, transcriptRelativePath);
13224
- if (!fs5.existsSync(sourcePath)) return null;
13466
+ const sourcePath = path8.join(worktree, transcriptRelativePath);
13467
+ if (!fs8.existsSync(sourcePath)) return null;
13225
13468
  const archiveDir = archivedRuntimeDiscussionsDir(worktree);
13226
- if (!fs5.existsSync(archiveDir)) fs5.mkdirSync(archiveDir, { recursive: true });
13227
- const targetPath = path6.join(archiveDir, path6.basename(sourcePath));
13228
- fs5.renameSync(sourcePath, targetPath);
13469
+ if (!fs8.existsSync(archiveDir)) fs8.mkdirSync(archiveDir, { recursive: true });
13470
+ const targetPath = path8.join(archiveDir, path8.basename(sourcePath));
13471
+ fs8.renameSync(sourcePath, targetPath);
13229
13472
  return targetPath;
13230
13473
  }
13231
13474
  async function finalizeClosingDiscussion(client, worktree, registry, sessionID, discussion) {
13232
13475
  const { confirmation, summaryPath, hasExistingSummary, priorMtimeMs } = await summarizeDiscussionWithBA(client, worktree, discussion);
13233
- if (!fs5.existsSync(summaryPath)) {
13476
+ if (!fs8.existsSync(summaryPath)) {
13234
13477
  throw new Error(`Discussion summary was not written to ${discussion.summaryPath}`);
13235
13478
  }
13236
13479
  if (hasExistingSummary) {
13237
- const currentMtimeMs = fs5.statSync(summaryPath).mtimeMs;
13480
+ const currentMtimeMs = fs8.statSync(summaryPath).mtimeMs;
13238
13481
  if (currentMtimeMs <= priorMtimeMs) {
13239
13482
  throw new Error(`Discussion summary file was not updated at ${discussion.summaryPath}`);
13240
13483
  }
13241
13484
  }
13242
- const summaryContent = fs5.readFileSync(summaryPath, "utf8").trim();
13485
+ const summaryContent = fs8.readFileSync(summaryPath, "utf8").trim();
13243
13486
  if (!summaryContent) {
13244
13487
  throw new Error(`Discussion summary file is empty at ${discussion.summaryPath}`);
13245
13488
  }
13246
- const transcriptPath = path6.join(worktree, discussion.transcriptPath);
13489
+ const transcriptPath = path8.join(worktree, discussion.transcriptPath);
13247
13490
  setDiscussionStatus(transcriptPath, "closed");
13248
13491
  const archivedTranscriptPath = archiveDiscussionTranscript(worktree, discussion.transcriptPath);
13249
13492
  delete registry.active[sessionID];
@@ -13251,7 +13494,7 @@ async function finalizeClosingDiscussion(client, worktree, registry, sessionID,
13251
13494
  return {
13252
13495
  confirmation,
13253
13496
  summaryPath: discussion.summaryPath,
13254
- archivedTranscriptPath: archivedTranscriptPath ? path6.relative(worktree, archivedTranscriptPath) : path6.join(".optima", ".config", "runtime", "discussions", "archive", path6.basename(discussion.transcriptPath))
13497
+ archivedTranscriptPath: archivedTranscriptPath ? path8.relative(worktree, archivedTranscriptPath) : path8.join(".optima", ".config", "runtime", "discussions", "archive", path8.basename(discussion.transcriptPath))
13255
13498
  };
13256
13499
  }
13257
13500
  function normalizeTeamMode(value) {
@@ -13290,13 +13533,13 @@ function getOperatingTeamMode(repoCfg) {
13290
13533
  }
13291
13534
  function readResolvedFile(relativePath, worktree, options = {}) {
13292
13535
  const filePath = resolveIncludeFile(`plugin:${relativePath}`, worktree, PKG_ROOT, options);
13293
- if (!filePath || !fs5.existsSync(filePath)) return "";
13294
- return resolveIncludes(fs5.readFileSync(filePath, "utf8"), worktree, PKG_ROOT, options).trim();
13536
+ if (!filePath || !fs8.existsSync(filePath)) return "";
13537
+ return resolveIncludes(fs8.readFileSync(filePath, "utf8"), worktree, PKG_ROOT, options).trim();
13295
13538
  }
13296
13539
  function loadMarkdownFragment(filePath, worktree) {
13297
- if (!fs5.existsSync(filePath)) return "";
13540
+ if (!fs8.existsSync(filePath)) return "";
13298
13541
  try {
13299
- const raw = fs5.readFileSync(filePath, "utf8");
13542
+ const raw = fs8.readFileSync(filePath, "utf8");
13300
13543
  const { body } = parseFrontmatter(raw);
13301
13544
  return resolveIncludes(body.trim(), worktree, PKG_ROOT);
13302
13545
  } catch (e) {
@@ -13305,9 +13548,9 @@ function loadMarkdownFragment(filePath, worktree) {
13305
13548
  }
13306
13549
  }
13307
13550
  function loadAgentDefinition(filePath, worktree, options = {}) {
13308
- if (!fs5.existsSync(filePath)) return null;
13551
+ if (!fs8.existsSync(filePath)) return null;
13309
13552
  try {
13310
- const rawContent = fs5.readFileSync(filePath, "utf8");
13553
+ const rawContent = fs8.readFileSync(filePath, "utf8");
13311
13554
  const { data, body } = parseFrontmatter(rawContent);
13312
13555
  const prompt = resolveIncludes(body.trim(), worktree, PKG_ROOT, options);
13313
13556
  return { data, prompt };
@@ -13318,13 +13561,13 @@ function loadAgentDefinition(filePath, worktree, options = {}) {
13318
13561
  }
13319
13562
  function syncGeneratedPolicies(worktree, repoCfg) {
13320
13563
  if (repoCfg.policies?.extract_defaults !== "all") return;
13321
- if (!fs5.existsSync(BUNDLE_POLICIES_DIR)) return;
13564
+ if (!fs8.existsSync(BUNDLE_POLICIES_DIR)) return;
13322
13565
  const generatedDir = generatedPoliciesDir(worktree);
13323
- if (!fs5.existsSync(generatedDir)) fs5.mkdirSync(generatedDir, { recursive: true });
13324
- const policyFiles = fs5.readdirSync(BUNDLE_POLICIES_DIR).filter((file) => file.endsWith(".md") && file !== "README.md");
13566
+ if (!fs8.existsSync(generatedDir)) fs8.mkdirSync(generatedDir, { recursive: true });
13567
+ const policyFiles = fs8.readdirSync(BUNDLE_POLICIES_DIR).filter((file) => file.endsWith(".md") && file !== "README.md");
13325
13568
  for (const file of policyFiles) {
13326
- const sourcePath = path6.join(BUNDLE_POLICIES_DIR, file);
13327
- const source = fs5.readFileSync(sourcePath, "utf8").trimEnd();
13569
+ const sourcePath = path8.join(BUNDLE_POLICIES_DIR, file);
13570
+ const source = fs8.readFileSync(sourcePath, "utf8").trimEnd();
13328
13571
  const generated = [
13329
13572
  "<!--",
13330
13573
  "Generated from Optima plugin defaults.",
@@ -13335,19 +13578,19 @@ function syncGeneratedPolicies(worktree, repoCfg) {
13335
13578
  source,
13336
13579
  ""
13337
13580
  ].join("\n");
13338
- fs5.writeFileSync(path6.join(generatedDir, file), generated, "utf8");
13581
+ fs8.writeFileSync(path8.join(generatedDir, file), generated, "utf8");
13339
13582
  }
13340
13583
  }
13341
13584
  function ensureReadmeFile(dirPath, content) {
13342
- if (!fs5.existsSync(dirPath)) fs5.mkdirSync(dirPath, { recursive: true });
13343
- const readmePath = path6.join(dirPath, "README.md");
13344
- if (!fs5.existsSync(readmePath)) {
13345
- fs5.writeFileSync(readmePath, content, "utf8");
13585
+ if (!fs8.existsSync(dirPath)) fs8.mkdirSync(dirPath, { recursive: true });
13586
+ const readmePath = path8.join(dirPath, "README.md");
13587
+ if (!fs8.existsSync(readmePath)) {
13588
+ fs8.writeFileSync(readmePath, content, "utf8");
13346
13589
  }
13347
13590
  }
13348
13591
  function ensureFileIfMissing(filePath, content) {
13349
- if (!fs5.existsSync(path6.dirname(filePath))) fs5.mkdirSync(path6.dirname(filePath), { recursive: true });
13350
- if (!fs5.existsSync(filePath)) fs5.writeFileSync(filePath, content, "utf8");
13592
+ if (!fs8.existsSync(path8.dirname(filePath))) fs8.mkdirSync(path8.dirname(filePath), { recursive: true });
13593
+ if (!fs8.existsSync(filePath)) fs8.writeFileSync(filePath, content, "utf8");
13351
13594
  }
13352
13595
  function currentTasksRegistryContent() {
13353
13596
  return "# Current Tasks (Backlog)\n\n## \u{1F4AC} Active Discussions\n- (None)\n\n## \u{1F680} Active\n- (None)\n\n## \u{1F4CB} Todo\n- (None)\n\n## \u{1F6D1} Blocked\n- (None)\n";
@@ -13433,16 +13676,16 @@ Never place implementation evidence under root \`evidences/\`.
13433
13676
  }
13434
13677
  function ensureOptimaTaskTemplates(worktree) {
13435
13678
  const tasksDir = optimaTasksDir(worktree);
13436
- ensureFileIfMissing(path6.join(tasksDir, "task-template.md"), taskTemplateContent());
13437
- ensureFileIfMissing(path6.join(tasksDir, "subtask-template.md"), subtaskTemplateContent());
13679
+ ensureFileIfMissing(path8.join(tasksDir, "task-template.md"), taskTemplateContent());
13680
+ ensureFileIfMissing(path8.join(tasksDir, "subtask-template.md"), subtaskTemplateContent());
13438
13681
  }
13439
13682
  function scaffoldOptimaConfig(worktree, teamMode = "full") {
13440
13683
  const configPath = repoConfigPath(worktree);
13441
- if (fs5.existsSync(configPath)) return false;
13442
- const templatePath = path6.join(TEMPLATES_DIR, "optima.yaml.template");
13443
- if (!fs5.existsSync(templatePath)) return false;
13444
- const agentIds = fs5.existsSync(BUNDLE_AGENTS_DIR) ? fs5.readdirSync(BUNDLE_AGENTS_DIR).filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", "")) : [];
13445
- let optimaConfig = fs5.readFileSync(templatePath, "utf8");
13684
+ if (fs8.existsSync(configPath)) return false;
13685
+ const templatePath = path8.join(TEMPLATES_DIR, "optima.yaml.template");
13686
+ if (!fs8.existsSync(templatePath)) return false;
13687
+ const agentIds = fs8.existsSync(BUNDLE_AGENTS_DIR) ? fs8.readdirSync(BUNDLE_AGENTS_DIR).filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", "")) : [];
13688
+ let optimaConfig = fs8.readFileSync(templatePath, "utf8");
13446
13689
  optimaConfig = optimaConfig.replace("{{teamMode}}", normalizeTeamMode(teamMode));
13447
13690
  let agentsSection = "";
13448
13691
  for (const id of agentIds) {
@@ -13453,26 +13696,26 @@ function scaffoldOptimaConfig(worktree, teamMode = "full") {
13453
13696
  }
13454
13697
  optimaConfig = optimaConfig.replace(/^agents:/m, "agents:\n" + agentsSection);
13455
13698
  ensureFileIfMissing(configPath, optimaConfig);
13456
- return fs5.existsSync(configPath);
13699
+ return fs8.existsSync(configPath);
13457
13700
  }
13458
13701
  function scaffoldOptimaRootCodemap(worktree) {
13459
13702
  const rootCodemapPath = optimaCodemapPath(worktree);
13460
- if (fs5.existsSync(rootCodemapPath)) return false;
13461
- const templatePath = path6.join(TEMPLATES_DIR, "codemap.yml.template");
13462
- if (!fs5.existsSync(templatePath)) return false;
13463
- const codemapConfig = fs5.readFileSync(templatePath, "utf8").replace("{{projectName}}", path6.basename(worktree));
13703
+ if (fs8.existsSync(rootCodemapPath)) return false;
13704
+ const templatePath = path8.join(TEMPLATES_DIR, "codemap.yml.template");
13705
+ if (!fs8.existsSync(templatePath)) return false;
13706
+ const codemapConfig = fs8.readFileSync(templatePath, "utf8").replace("{{projectName}}", path8.basename(worktree));
13464
13707
  ensureFileIfMissing(rootCodemapPath, codemapConfig);
13465
- return fs5.existsSync(rootCodemapPath);
13708
+ return fs8.existsSync(rootCodemapPath);
13466
13709
  }
13467
13710
  function ensureOptimaRegistries(worktree) {
13468
13711
  const tasksDir = optimaTasksDir(worktree);
13469
13712
  const scrsDir = optimaScrsDir(worktree);
13470
- if (!fs5.existsSync(tasksDir)) fs5.mkdirSync(tasksDir, { recursive: true });
13471
- if (!fs5.existsSync(scrsDir)) fs5.mkdirSync(scrsDir, { recursive: true });
13472
- ensureFileIfMissing(path6.join(tasksDir, "current.md"), currentTasksRegistryContent());
13473
- ensureFileIfMissing(path6.join(tasksDir, "done.md"), doneTasksRegistryContent());
13474
- ensureFileIfMissing(path6.join(scrsDir, "current.md"), currentScrRegistryContent());
13475
- ensureFileIfMissing(path6.join(scrsDir, "done.md"), doneScrRegistryContent());
13713
+ if (!fs8.existsSync(tasksDir)) fs8.mkdirSync(tasksDir, { recursive: true });
13714
+ if (!fs8.existsSync(scrsDir)) fs8.mkdirSync(scrsDir, { recursive: true });
13715
+ ensureFileIfMissing(path8.join(tasksDir, "current.md"), currentTasksRegistryContent());
13716
+ ensureFileIfMissing(path8.join(tasksDir, "done.md"), doneTasksRegistryContent());
13717
+ ensureFileIfMissing(path8.join(scrsDir, "current.md"), currentScrRegistryContent());
13718
+ ensureFileIfMissing(path8.join(scrsDir, "done.md"), doneScrRegistryContent());
13476
13719
  }
13477
13720
  function scaffoldOptimaReadmes(worktree) {
13478
13721
  ensureReadmeFile(repoPoliciesDir(worktree), REPO_LOCAL_POLICIES_README);
@@ -13634,12 +13877,12 @@ function shouldRegisterWorkflowProductManager(options = {}, worktree = process.c
13634
13877
  }
13635
13878
  function isClickUpDerivedWorktreeSibling(candidate, basePath) {
13636
13879
  if (typeof candidate !== "string" || typeof basePath !== "string" || !candidate.trim() || !basePath.trim()) return false;
13637
- const resolvedCandidate = path6.resolve(candidate);
13638
- const resolvedBase = path6.resolve(basePath);
13639
- const baseParent = path6.dirname(resolvedBase);
13640
- if (path6.dirname(resolvedCandidate) !== baseParent) return false;
13641
- const baseName = path6.basename(resolvedBase);
13642
- const candidateName = path6.basename(resolvedCandidate);
13880
+ const resolvedCandidate = path8.resolve(candidate);
13881
+ const resolvedBase = path8.resolve(basePath);
13882
+ const baseParent = path8.dirname(resolvedBase);
13883
+ if (path8.dirname(resolvedCandidate) !== baseParent) return false;
13884
+ const baseName = path8.basename(resolvedBase);
13885
+ const candidateName = path8.basename(resolvedCandidate);
13643
13886
  if (!candidateName.startsWith(`${baseName}-`)) return false;
13644
13887
  const branchSlug = candidateName.slice(baseName.length + 1);
13645
13888
  const parts = branchSlug.split("-").filter(Boolean);
@@ -13647,11 +13890,11 @@ function isClickUpDerivedWorktreeSibling(candidate, basePath) {
13647
13890
  if (!(/* @__PURE__ */ new Set(["tarea", "bug", "doc", "poc", "idea"])).has(parts[0])) return false;
13648
13891
  if (!parts.slice(1).every((part) => /^[a-z0-9][a-z0-9-]*$/.test(part))) return false;
13649
13892
  try {
13650
- const candidateStat = fs5.lstatSync(resolvedCandidate);
13893
+ const candidateStat = fs8.lstatSync(resolvedCandidate);
13651
13894
  if (!candidateStat.isDirectory() || candidateStat.isSymbolicLink()) return false;
13652
- const realCandidate = fs5.realpathSync.native(resolvedCandidate);
13653
- const realBaseParent = fs5.realpathSync.native(baseParent);
13654
- return path6.dirname(realCandidate) === realBaseParent && path6.basename(realCandidate) === candidateName;
13895
+ const realCandidate = fs8.realpathSync.native(resolvedCandidate);
13896
+ const realBaseParent = fs8.realpathSync.native(baseParent);
13897
+ return path8.dirname(realCandidate) === realBaseParent && path8.basename(realCandidate) === candidateName;
13655
13898
  } catch {
13656
13899
  return false;
13657
13900
  }
@@ -13659,15 +13902,15 @@ function isClickUpDerivedWorktreeSibling(candidate, basePath) {
13659
13902
  function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktree, clickUpWebhookValidation } = {}) {
13660
13903
  const safe = safeWorktreeOrFailure(context, pluginWorktree);
13661
13904
  if (!safe.ok) return { ok: false, error: safe.message };
13662
- const requested = String(requestedDirectory || "").trim() ? path6.resolve(safe.worktree, String(requestedDirectory).trim()) : safe.worktree;
13905
+ const requested = String(requestedDirectory || "").trim() ? path8.resolve(safe.worktree, String(requestedDirectory).trim()) : safe.worktree;
13663
13906
  if (!isSafeWritableDirectory(requested)) return { ok: false, error: `Directory is not a safe writable directory: ${requested}` };
13664
13907
  if (isSameOrNestedPath(requested, safe.worktree)) return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "context_worktree" };
13665
13908
  const clickUpBasePath = clickUpWebhookValidation?.complete === true && clickUpWebhookValidation?.ok !== false ? clickUpWebhookValidation.config?.basePath : "";
13666
13909
  if (clickUpBasePath && isSameOrNestedPath(requested, clickUpBasePath)) {
13667
- return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path6.resolve(clickUpBasePath) };
13910
+ return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path8.resolve(clickUpBasePath) };
13668
13911
  }
13669
13912
  if (clickUpBasePath && isClickUpDerivedWorktreeSibling(requested, clickUpBasePath)) {
13670
- return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_derived_worktree", clickupBasePath: path6.resolve(clickUpBasePath) };
13913
+ return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_derived_worktree", clickupBasePath: path8.resolve(clickUpBasePath) };
13671
13914
  }
13672
13915
  return {
13673
13916
  ok: false,
@@ -13701,8 +13944,8 @@ function buildOptimaAgents(repoCfg, operatingTeamMode, worktree, debugDir, optio
13701
13944
  if (!enabled) continue;
13702
13945
  }
13703
13946
  const promptOptions = { preferCompactPromptDocs: repoCfg.features?.compact_prompt_docs !== false };
13704
- const bundledDefinition = loadAgentDefinition(path6.join(BUNDLE_AGENTS_DIR, file), worktree, promptOptions);
13705
- const repoDefinition = loadAgentDefinition(path6.join(repoAgentDefinitions, file), worktree, promptOptions) || loadAgentDefinition(path6.join(legacyAgentsDir, file), worktree, promptOptions);
13947
+ const bundledDefinition = loadAgentDefinition(path8.join(BUNDLE_AGENTS_DIR, file), worktree, promptOptions);
13948
+ const repoDefinition = loadAgentDefinition(path8.join(repoAgentDefinitions, file), worktree, promptOptions) || loadAgentDefinition(path8.join(legacyAgentsDir, file), worktree, promptOptions);
13706
13949
  const activeDefinition = repoDefinition || bundledDefinition;
13707
13950
  if (!activeDefinition) continue;
13708
13951
  const { data } = activeDefinition;
@@ -13711,7 +13954,7 @@ function buildOptimaAgents(repoCfg, operatingTeamMode, worktree, debugDir, optio
13711
13954
  if (modePromptFragment) finalPrompt = `${finalPrompt}
13712
13955
 
13713
13956
  ${modePromptFragment}`;
13714
- const additionFragment = loadMarkdownFragment(path6.join(repoAgentAdditions, file), worktree);
13957
+ const additionFragment = loadMarkdownFragment(path8.join(repoAgentAdditions, file), worktree);
13715
13958
  if (additionFragment) {
13716
13959
  finalPrompt = `${finalPrompt}
13717
13960
 
@@ -13764,14 +14007,14 @@ Use this Optima-provided fallback when the current task worktree lacks docs/core
13764
14007
  }
13765
14008
  ourAgents[id] = agentConfig;
13766
14009
  if (repoCfg.features?.debug_dumps !== false) {
13767
- const debugPath = path6.join(debugDir, `${id}.md`);
14010
+ const debugPath = path8.join(debugDir, `${id}.md`);
13768
14011
  const { prompt, ...dumpConfig } = agentConfig;
13769
14012
  const debugHeader = `---
13770
14013
  ${import_yaml3.default.stringify(dumpConfig).trim()}
13771
14014
  ---`;
13772
14015
  try {
13773
- if (!fs5.existsSync(debugDir)) fs5.mkdirSync(debugDir, { recursive: true });
13774
- fs5.writeFileSync(debugPath, `${debugHeader}
14016
+ if (!fs8.existsSync(debugDir)) fs8.mkdirSync(debugDir, { recursive: true });
14017
+ fs8.writeFileSync(debugPath, `${debugHeader}
13775
14018
 
13776
14019
  ${prompt}`, "utf8");
13777
14020
  } catch (e) {
@@ -13795,9 +14038,9 @@ async function OptimaPlugin(input = {}, pluginOptions = {}) {
13795
14038
  const configPath = resolveConfigPath(worktree);
13796
14039
  const discussionRegistry = loadDiscussionRegistry(worktree);
13797
14040
  let repoCfg = { agents: {}, defaults: {}, features: {} };
13798
- if (fs5.existsSync(configPath)) {
14041
+ if (fs8.existsSync(configPath)) {
13799
14042
  try {
13800
- repoCfg = import_yaml3.default.parse(fs5.readFileSync(configPath, "utf8")) || repoCfg;
14043
+ repoCfg = import_yaml3.default.parse(fs8.readFileSync(configPath, "utf8")) || repoCfg;
13801
14044
  } catch (e) {
13802
14045
  console.error(`[Optima] Failed to parse config at ${configPath}:`, e);
13803
14046
  }
@@ -13925,10 +14168,10 @@ async function OptimaPlugin(input = {}, pluginOptions = {}) {
13925
14168
  }
13926
14169
  migrateLegacyOptimaLayout(toolWorktree);
13927
14170
  const cfgDir = optimaConfigDir(toolWorktree);
13928
- if (!fs5.existsSync(cfgDir)) fs5.mkdirSync(cfgDir, { recursive: true });
13929
- const optimaTmplPath = path6.join(TEMPLATES_DIR, "optima.yaml.template");
13930
- const codemapTmplPath = path6.join(TEMPLATES_DIR, "codemap.yml.template");
13931
- if (!fs5.existsSync(optimaTmplPath) || !fs5.existsSync(codemapTmplPath)) {
14171
+ if (!fs8.existsSync(cfgDir)) fs8.mkdirSync(cfgDir, { recursive: true });
14172
+ const optimaTmplPath = path8.join(TEMPLATES_DIR, "optima.yaml.template");
14173
+ const codemapTmplPath = path8.join(TEMPLATES_DIR, "codemap.yml.template");
14174
+ if (!fs8.existsSync(optimaTmplPath) || !fs8.existsSync(codemapTmplPath)) {
13932
14175
  return "Error: Initialization templates not found in plugin.";
13933
14176
  }
13934
14177
  scaffoldOptimaConfig(toolWorktree, requestedTeamMode);
@@ -14049,14 +14292,14 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
14049
14292
  async execute(args, context) {
14050
14293
  const safe = safeWorktreeOrFailure(context, worktree);
14051
14294
  if (!safe.ok) return safe.message;
14052
- const summaryPath = path6.resolve(safe.worktree, args.summary_path || "");
14053
- if (!fs5.existsSync(summaryPath)) return `FAIL: summary_path not found: ${summaryPath}`;
14054
- const taskPath = args.task_path ? path6.resolve(safe.worktree, args.task_path) : "";
14295
+ const summaryPath = path8.resolve(safe.worktree, args.summary_path || "");
14296
+ if (!fs8.existsSync(summaryPath)) return `FAIL: summary_path not found: ${summaryPath}`;
14297
+ const taskPath = args.task_path ? path8.resolve(safe.worktree, args.task_path) : "";
14055
14298
  const payload = buildClickUpSummaryPayload({
14056
- summaryMarkdown: fs5.readFileSync(summaryPath, "utf8"),
14057
- summaryPath: path6.relative(safe.worktree, summaryPath),
14058
- taskMarkdown: taskPath && fs5.existsSync(taskPath) ? fs5.readFileSync(taskPath, "utf8") : "",
14059
- taskPath: taskPath ? path6.relative(safe.worktree, taskPath) : "",
14299
+ summaryMarkdown: fs8.readFileSync(summaryPath, "utf8"),
14300
+ summaryPath: path8.relative(safe.worktree, summaryPath),
14301
+ taskMarkdown: taskPath && fs8.existsSync(taskPath) ? fs8.readFileSync(taskPath, "utf8") : "",
14302
+ taskPath: taskPath ? path8.relative(safe.worktree, taskPath) : "",
14060
14303
  branch: args.branch,
14061
14304
  worktree: args.worktree,
14062
14305
  pr: args.pr
@@ -14135,12 +14378,12 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
14135
14378
  async execute(args, context) {
14136
14379
  const safe = safeWorktreeOrFailure(context, worktree);
14137
14380
  if (!safe.ok) return safe.message;
14138
- const markdownPath = path6.resolve(safe.worktree, args.markdown_path || "");
14139
- if (!fs5.existsSync(markdownPath)) return `FAIL: markdown_path not found: ${markdownPath}`;
14381
+ const markdownPath = path8.resolve(safe.worktree, args.markdown_path || "");
14382
+ if (!fs8.existsSync(markdownPath)) return `FAIL: markdown_path not found: ${markdownPath}`;
14140
14383
  const payload = buildClickUpCreateSubtasksPayload({
14141
14384
  parentTaskId: args.parent_task_id,
14142
- markdown: fs5.readFileSync(markdownPath, "utf8"),
14143
- sourcePath: path6.relative(safe.worktree, markdownPath),
14385
+ markdown: fs8.readFileSync(markdownPath, "utf8"),
14386
+ sourcePath: path8.relative(safe.worktree, markdownPath),
14144
14387
  parentBranch: args.parent_branch,
14145
14388
  parentTaskType: args.parent_task_type || "Tarea",
14146
14389
  apply: String(args.apply || "").toLowerCase() === "true"
@@ -14256,6 +14499,31 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
14256
14499
  }
14257
14500
  }
14258
14501
  }),
14502
+ optima_github_verify_vercel_pr: tool({
14503
+ description: "Verify that a PR head commit has a successful Vercel preproduction deployment and a functional deployment URL before validation/handoff",
14504
+ args: {
14505
+ pr_number: tool.schema.number().describe("Pull request number"),
14506
+ context: tool.schema.string().describe("Required GitHub status context; defaults to 'Vercel \u2013 defend-preproduction'"),
14507
+ environment: tool.schema.string().describe("Required GitHub deployment environment; defaults to 'Preview \u2013 defend-preproduction'"),
14508
+ require_functional_url: tool.schema.string().describe("Set to 'false' to skip HTTP probing of the deployment URL")
14509
+ },
14510
+ async execute(args) {
14511
+ try {
14512
+ const auth = await requireGitHubAppClient();
14513
+ if (!auth.ok) return JSON.stringify(auth, null, 2);
14514
+ if (!runtimeGitHubClient?.verifyVercelPullRequestDeployment) return JSON.stringify({ ok: false, error: "github_client_unavailable" }, null, 2);
14515
+ const result = await runtimeGitHubClient.verifyVercelPullRequestDeployment({
14516
+ pullNumber: args.pr_number,
14517
+ context: args.context || "Vercel \u2013 defend-preproduction",
14518
+ environment: args.environment || "Preview \u2013 defend-preproduction",
14519
+ requireFunctionalUrl: String(args.require_functional_url || "true").toLowerCase() !== "false"
14520
+ });
14521
+ return JSON.stringify(result, null, 2);
14522
+ } catch (error) {
14523
+ return JSON.stringify({ ok: false, error: error.message }, null, 2);
14524
+ }
14525
+ }
14526
+ }),
14259
14527
  optima_github_merge_pr: tool({
14260
14528
  description: "Merge a GitHub PR through the Optima GitHub App identity after required human approval gates pass",
14261
14529
  args: {
@@ -14485,7 +14753,7 @@ Backfilled messages: ${backfilled}`;
14485
14753
  if (!existing) {
14486
14754
  return "FAIL: No active discussion exists for this session.";
14487
14755
  }
14488
- const discussionPath = path6.join(toolWorktree, existing.transcriptPath);
14756
+ const discussionPath = path8.join(toolWorktree, existing.transcriptPath);
14489
14757
  setDiscussionStatus(discussionPath, "summarizing");
14490
14758
  existing.status = "summarizing";
14491
14759
  saveDiscussionRegistry(toolWorktree, toolRegistry);
@@ -14537,7 +14805,7 @@ Reason: ${err.message}`;
14537
14805
  try {
14538
14806
  const sessionResult = await client.session.create({
14539
14807
  query: { directory: workflowDirectory },
14540
- body: { title: `Workflow Run: ${path6.basename(workflowTaskPath)}` }
14808
+ body: { title: `Workflow Run: ${path8.basename(workflowTaskPath)}` }
14541
14809
  });
14542
14810
  const sessionId = sessionResult.data.id;
14543
14811
  activeWorkflows.set(sessionId, { pmaSessionId, taskPath: workflowTaskPath, track: workflowTrack, directory: workflowDirectory });