@defend-tech/opencode-optima 0.1.67 → 0.1.69
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/Agents_Common.md +3 -1
- package/Agents_Common.prompt.md +3 -1
- package/assets/agents/workflow_product_manager.md +6 -4
- package/dist/index.js +426 -279
- package/dist/sanitize_cli.js +449 -302
- package/package.json +1 -1
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,
|
|
112
|
-
const ctrl = callVisitor(key, node, visitor,
|
|
111
|
+
function visit_(key, node, visitor, path7) {
|
|
112
|
+
const ctrl = callVisitor(key, node, visitor, path7);
|
|
113
113
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
114
|
-
replaceNode(key,
|
|
115
|
-
return visit_(key, ctrl, visitor,
|
|
114
|
+
replaceNode(key, path7, ctrl);
|
|
115
|
+
return visit_(key, ctrl, visitor, path7);
|
|
116
116
|
}
|
|
117
117
|
if (typeof ctrl !== "symbol") {
|
|
118
118
|
if (identity.isCollection(node)) {
|
|
119
|
-
|
|
119
|
+
path7 = Object.freeze(path7.concat(node));
|
|
120
120
|
for (let i = 0; i < node.items.length; ++i) {
|
|
121
|
-
const ci = visit_(i, node.items[i], visitor,
|
|
121
|
+
const ci = visit_(i, node.items[i], visitor, path7);
|
|
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
|
-
|
|
133
|
-
const ck = visit_("key", node.key, visitor,
|
|
132
|
+
path7 = Object.freeze(path7.concat(node));
|
|
133
|
+
const ck = visit_("key", node.key, visitor, path7);
|
|
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,
|
|
138
|
+
const cv = visit_("value", node.value, visitor, path7);
|
|
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,
|
|
160
|
-
const ctrl = await callVisitor(key, node, visitor,
|
|
159
|
+
async function visitAsync_(key, node, visitor, path7) {
|
|
160
|
+
const ctrl = await callVisitor(key, node, visitor, path7);
|
|
161
161
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
162
|
-
replaceNode(key,
|
|
163
|
-
return visitAsync_(key, ctrl, visitor,
|
|
162
|
+
replaceNode(key, path7, ctrl);
|
|
163
|
+
return visitAsync_(key, ctrl, visitor, path7);
|
|
164
164
|
}
|
|
165
165
|
if (typeof ctrl !== "symbol") {
|
|
166
166
|
if (identity.isCollection(node)) {
|
|
167
|
-
|
|
167
|
+
path7 = Object.freeze(path7.concat(node));
|
|
168
168
|
for (let i = 0; i < node.items.length; ++i) {
|
|
169
|
-
const ci = await visitAsync_(i, node.items[i], visitor,
|
|
169
|
+
const ci = await visitAsync_(i, node.items[i], visitor, path7);
|
|
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
|
-
|
|
181
|
-
const ck = await visitAsync_("key", node.key, visitor,
|
|
180
|
+
path7 = Object.freeze(path7.concat(node));
|
|
181
|
+
const ck = await visitAsync_("key", node.key, visitor, path7);
|
|
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,
|
|
186
|
+
const cv = await visitAsync_("value", node.value, visitor, path7);
|
|
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,
|
|
213
|
+
function callVisitor(key, node, visitor, path7) {
|
|
214
214
|
if (typeof visitor === "function")
|
|
215
|
-
return visitor(key, node,
|
|
215
|
+
return visitor(key, node, path7);
|
|
216
216
|
if (identity.isMap(node))
|
|
217
|
-
return visitor.Map?.(key, node,
|
|
217
|
+
return visitor.Map?.(key, node, path7);
|
|
218
218
|
if (identity.isSeq(node))
|
|
219
|
-
return visitor.Seq?.(key, node,
|
|
219
|
+
return visitor.Seq?.(key, node, path7);
|
|
220
220
|
if (identity.isPair(node))
|
|
221
|
-
return visitor.Pair?.(key, node,
|
|
221
|
+
return visitor.Pair?.(key, node, path7);
|
|
222
222
|
if (identity.isScalar(node))
|
|
223
|
-
return visitor.Scalar?.(key, node,
|
|
223
|
+
return visitor.Scalar?.(key, node, path7);
|
|
224
224
|
if (identity.isAlias(node))
|
|
225
|
-
return visitor.Alias?.(key, node,
|
|
225
|
+
return visitor.Alias?.(key, node, path7);
|
|
226
226
|
return void 0;
|
|
227
227
|
}
|
|
228
|
-
function replaceNode(key,
|
|
229
|
-
const parent =
|
|
228
|
+
function replaceNode(key, path7, node) {
|
|
229
|
+
const parent = path7[path7.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,
|
|
837
|
+
function collectionFromPath(schema, path7, value) {
|
|
838
838
|
let v = value;
|
|
839
|
-
for (let i =
|
|
840
|
-
const k =
|
|
839
|
+
for (let i = path7.length - 1; i >= 0; --i) {
|
|
840
|
+
const k = path7[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 = (
|
|
859
|
+
var isEmptyPath = (path7) => path7 == null || typeof path7 === "object" && !!path7[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(
|
|
890
|
-
if (isEmptyPath(
|
|
889
|
+
addIn(path7, value) {
|
|
890
|
+
if (isEmptyPath(path7))
|
|
891
891
|
this.add(value);
|
|
892
892
|
else {
|
|
893
|
-
const [key, ...rest] =
|
|
893
|
+
const [key, ...rest] = path7;
|
|
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(
|
|
908
|
-
const [key, ...rest] =
|
|
907
|
+
deleteIn(path7) {
|
|
908
|
+
const [key, ...rest] = path7;
|
|
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(
|
|
923
|
-
const [key, ...rest] =
|
|
922
|
+
getIn(path7, keepScalar) {
|
|
923
|
+
const [key, ...rest] = path7;
|
|
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(
|
|
942
|
-
const [key, ...rest] =
|
|
941
|
+
hasIn(path7) {
|
|
942
|
+
const [key, ...rest] = path7;
|
|
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(
|
|
953
|
-
const [key, ...rest] =
|
|
952
|
+
setIn(path7, value) {
|
|
953
|
+
const [key, ...rest] = path7;
|
|
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(
|
|
3457
|
+
addIn(path7, value) {
|
|
3458
3458
|
if (assertCollection(this.contents))
|
|
3459
|
-
this.contents.addIn(
|
|
3459
|
+
this.contents.addIn(path7, 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(
|
|
3535
|
-
if (Collection.isEmptyPath(
|
|
3534
|
+
deleteIn(path7) {
|
|
3535
|
+
if (Collection.isEmptyPath(path7)) {
|
|
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(
|
|
3541
|
+
return assertCollection(this.contents) ? this.contents.deleteIn(path7) : 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(
|
|
3557
|
-
if (Collection.isEmptyPath(
|
|
3556
|
+
getIn(path7, keepScalar) {
|
|
3557
|
+
if (Collection.isEmptyPath(path7))
|
|
3558
3558
|
return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
|
|
3559
|
-
return identity.isCollection(this.contents) ? this.contents.getIn(
|
|
3559
|
+
return identity.isCollection(this.contents) ? this.contents.getIn(path7, 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(
|
|
3571
|
-
if (Collection.isEmptyPath(
|
|
3570
|
+
hasIn(path7) {
|
|
3571
|
+
if (Collection.isEmptyPath(path7))
|
|
3572
3572
|
return this.contents !== void 0;
|
|
3573
|
-
return identity.isCollection(this.contents) ? this.contents.hasIn(
|
|
3573
|
+
return identity.isCollection(this.contents) ? this.contents.hasIn(path7) : 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(
|
|
3591
|
-
if (Collection.isEmptyPath(
|
|
3590
|
+
setIn(path7, value) {
|
|
3591
|
+
if (Collection.isEmptyPath(path7)) {
|
|
3592
3592
|
this.contents = value;
|
|
3593
3593
|
} else if (this.contents == null) {
|
|
3594
|
-
this.contents = Collection.collectionFromPath(this.schema, Array.from(
|
|
3594
|
+
this.contents = Collection.collectionFromPath(this.schema, Array.from(path7), value);
|
|
3595
3595
|
} else if (assertCollection(this.contents)) {
|
|
3596
|
-
this.contents.setIn(
|
|
3596
|
+
this.contents.setIn(path7, 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,
|
|
5548
|
+
visit.itemAtPath = (cst, path7) => {
|
|
5549
5549
|
let item = cst;
|
|
5550
|
-
for (const [field, index] of
|
|
5550
|
+
for (const [field, index] of path7) {
|
|
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,
|
|
5560
|
-
const parent = visit.itemAtPath(cst,
|
|
5561
|
-
const field =
|
|
5559
|
+
visit.parentCollection = (cst, path7) => {
|
|
5560
|
+
const parent = visit.itemAtPath(cst, path7.slice(0, -1));
|
|
5561
|
+
const field = path7[path7.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(
|
|
5568
|
-
let ctrl = visitor(item,
|
|
5567
|
+
function _visit(path7, item, visitor) {
|
|
5568
|
+
let ctrl = visitor(item, path7);
|
|
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(
|
|
5575
|
+
const ci = _visit(Object.freeze(path7.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,
|
|
5586
|
+
ctrl = ctrl(item, path7);
|
|
5587
5587
|
}
|
|
5588
5588
|
}
|
|
5589
|
-
return typeof ctrl === "function" ? ctrl(item,
|
|
5589
|
+
return typeof ctrl === "function" ? ctrl(item, path7) : ctrl;
|
|
5590
5590
|
}
|
|
5591
5591
|
exports.visit = visit;
|
|
5592
5592
|
}
|
|
@@ -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 = (
|
|
7554
|
-
if (!isString(
|
|
7553
|
+
var checkPath = (path7, originalPath, doThrow) => {
|
|
7554
|
+
if (!isString(path7)) {
|
|
7555
7555
|
return doThrow(
|
|
7556
7556
|
`path must be a string, but got \`${originalPath}\``,
|
|
7557
7557
|
TypeError
|
|
7558
7558
|
);
|
|
7559
7559
|
}
|
|
7560
|
-
if (!
|
|
7560
|
+
if (!path7) {
|
|
7561
7561
|
return doThrow(`path must not be empty`, TypeError);
|
|
7562
7562
|
}
|
|
7563
|
-
if (checkPath.isNotRelative(
|
|
7563
|
+
if (checkPath.isNotRelative(path7)) {
|
|
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 = (
|
|
7572
|
+
var isNotRelative = (path7) => REGEX_TEST_INVALID_PATH.test(path7);
|
|
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(
|
|
7631
|
+
_testOne(path7, 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(
|
|
7639
|
+
const matched = rule.regex.test(path7);
|
|
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
|
|
7652
|
+
const path7 = originalPath && checkPath.convert(originalPath);
|
|
7653
7653
|
checkPath(
|
|
7654
|
-
|
|
7654
|
+
path7,
|
|
7655
7655
|
originalPath,
|
|
7656
7656
|
this._allowRelativePaths ? RETURN_FALSE : throwError
|
|
7657
7657
|
);
|
|
7658
|
-
return this._t(
|
|
7658
|
+
return this._t(path7, cache, checkUnignored, slices);
|
|
7659
7659
|
}
|
|
7660
|
-
_t(
|
|
7661
|
-
if (
|
|
7662
|
-
return cache[
|
|
7660
|
+
_t(path7, cache, checkUnignored, slices) {
|
|
7661
|
+
if (path7 in cache) {
|
|
7662
|
+
return cache[path7];
|
|
7663
7663
|
}
|
|
7664
7664
|
if (!slices) {
|
|
7665
|
-
slices =
|
|
7665
|
+
slices = path7.split(SLASH);
|
|
7666
7666
|
}
|
|
7667
7667
|
slices.pop();
|
|
7668
7668
|
if (!slices.length) {
|
|
7669
|
-
return cache[
|
|
7669
|
+
return cache[path7] = this._testOne(path7, 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[
|
|
7677
|
+
return cache[path7] = parent.ignored ? parent : this._testOne(path7, checkUnignored);
|
|
7678
7678
|
}
|
|
7679
|
-
ignores(
|
|
7680
|
-
return this._test(
|
|
7679
|
+
ignores(path7) {
|
|
7680
|
+
return this._test(path7, this._ignoreCache, false).ignored;
|
|
7681
7681
|
}
|
|
7682
7682
|
createFilter() {
|
|
7683
|
-
return (
|
|
7683
|
+
return (path7) => !this.ignores(path7);
|
|
7684
7684
|
}
|
|
7685
7685
|
filter(paths) {
|
|
7686
7686
|
return makeArray(paths).filter(this.createFilter());
|
|
7687
7687
|
}
|
|
7688
7688
|
// @returns {TestResult}
|
|
7689
|
-
test(
|
|
7690
|
-
return this._test(
|
|
7689
|
+
test(path7) {
|
|
7690
|
+
return this._test(path7, this._testCache, true);
|
|
7691
7691
|
}
|
|
7692
7692
|
};
|
|
7693
7693
|
var factory = (options) => new Ignore(options);
|
|
7694
|
-
var isPathValid = (
|
|
7694
|
+
var isPathValid = (path7) => checkPath(path7 && checkPath.convert(path7), path7, 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 = (
|
|
7705
|
+
checkPath.isNotRelative = (path7) => REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path7) || isNotRelative(path7);
|
|
7706
7706
|
}
|
|
7707
7707
|
}
|
|
7708
7708
|
});
|
|
@@ -7714,8 +7714,7 @@ import crypto from "node:crypto";
|
|
|
7714
7714
|
import fs5 from "node:fs";
|
|
7715
7715
|
import http from "node:http";
|
|
7716
7716
|
import os from "node:os";
|
|
7717
|
-
import
|
|
7718
|
-
import { fileURLToPath } from "node:url";
|
|
7717
|
+
import path6 from "node:path";
|
|
7719
7718
|
import { tool } from "@opencode-ai/plugin/tool";
|
|
7720
7719
|
|
|
7721
7720
|
// src/git_utils.js
|
|
@@ -8486,7 +8485,9 @@ async function optima_validate_logic(worktree) {
|
|
|
8486
8485
|
};
|
|
8487
8486
|
}
|
|
8488
8487
|
|
|
8489
|
-
// src/
|
|
8488
|
+
// src/constants.js
|
|
8489
|
+
import path5 from "node:path";
|
|
8490
|
+
import { fileURLToPath } from "node:url";
|
|
8490
8491
|
var PKG_ROOT = path5.resolve(path5.dirname(fileURLToPath(import.meta.url)), "..");
|
|
8491
8492
|
var BUNDLE_ASSETS_DIR = path5.join(PKG_ROOT, "assets");
|
|
8492
8493
|
var BUNDLE_AGENTS_DIR = path5.join(BUNDLE_ASSETS_DIR, "agents");
|
|
@@ -8527,6 +8528,8 @@ var CLICKUP_WEBHOOK_REQUEST_TIMEOUT_MS = 1e4;
|
|
|
8527
8528
|
var CLICKUP_WEBHOOK_STARTUP_TASK_LIMIT = 50;
|
|
8528
8529
|
var CLICKUP_WEBHOOK_STARTUP_COMMENT_LIMIT = 100;
|
|
8529
8530
|
var CLICKUP_WEBHOOK_STARTUP_RECONCILIATION_DELAY_MS = 3e4;
|
|
8531
|
+
var CLICKUP_WEBHOOK_STARTUP_COMMENT_LOOKBACK_MS = 6 * 60 * 60 * 1e3;
|
|
8532
|
+
var CLICKUP_ASSIGNMENT_WATCHDOG_INTERVAL_MS = 5 * 60 * 1e3;
|
|
8530
8533
|
var CLICKUP_WORKTREE_FAILURE_COMMENT_DEDUPE_MS = 10 * 60 * 1e3;
|
|
8531
8534
|
var CLICKUP_WEBHOOK_LOG_LEVELS = /* @__PURE__ */ new Set(["error", "info", "verbose"]);
|
|
8532
8535
|
var CLICKUP_WEBHOOK_REDACTED = "[REDACTED]";
|
|
@@ -8615,20 +8618,22 @@ var REPO_LOCAL_POLICIES_README = [
|
|
|
8615
8618
|
"Only files in `.optima/policies/` affect runtime prompt behavior.",
|
|
8616
8619
|
""
|
|
8617
8620
|
].join("\n");
|
|
8621
|
+
var CLICKUP_WEBHOOK_CLEANUP_TIMEOUT_MS = 8e3;
|
|
8622
|
+
var CLICKUP_WEBHOOK_SIGNAL_STATE = Symbol.for("opencode-optima.clickup-webhook.signal-state");
|
|
8623
|
+
|
|
8624
|
+
// src/index.js
|
|
8618
8625
|
var activeWorkflows = /* @__PURE__ */ new Map();
|
|
8619
8626
|
var activeClickUpWebhookListeners = /* @__PURE__ */ new Map();
|
|
8620
8627
|
var activeClickUpWebhookLifecycleRegistry = /* @__PURE__ */ new Map();
|
|
8621
|
-
var CLICKUP_WEBHOOK_CLEANUP_TIMEOUT_MS = 8e3;
|
|
8622
|
-
var CLICKUP_WEBHOOK_SIGNAL_STATE = Symbol.for("opencode-optima.clickup-webhook.signal-state");
|
|
8623
8628
|
var activeClickUpTaskRoutes = /* @__PURE__ */ new Map();
|
|
8624
8629
|
function isRootDirectory(candidate) {
|
|
8625
|
-
const resolved =
|
|
8626
|
-
return resolved ===
|
|
8630
|
+
const resolved = path6.resolve(candidate);
|
|
8631
|
+
return resolved === path6.parse(resolved).root;
|
|
8627
8632
|
}
|
|
8628
8633
|
function isSafeWritableDirectory(candidate) {
|
|
8629
8634
|
if (typeof candidate !== "string" || !candidate.trim()) return false;
|
|
8630
|
-
if (!
|
|
8631
|
-
const resolved =
|
|
8635
|
+
if (!path6.isAbsolute(candidate)) return false;
|
|
8636
|
+
const resolved = path6.resolve(candidate);
|
|
8632
8637
|
if (isRootDirectory(resolved)) return false;
|
|
8633
8638
|
try {
|
|
8634
8639
|
const stat = fs5.statSync(resolved);
|
|
@@ -8649,7 +8654,7 @@ function resolveSafeWorktree(context = {}, pluginWorktree = null) {
|
|
|
8649
8654
|
];
|
|
8650
8655
|
for (const candidate of candidates) {
|
|
8651
8656
|
if (typeof candidate !== "string" || !candidate.trim()) continue;
|
|
8652
|
-
const resolved =
|
|
8657
|
+
const resolved = path6.resolve(candidate);
|
|
8653
8658
|
if (isSafeWritableDirectory(resolved)) return resolved;
|
|
8654
8659
|
}
|
|
8655
8660
|
throw new Error(SAFE_WORKTREE_FAILURE);
|
|
@@ -8664,13 +8669,13 @@ function safeWorktreeOrFailure(context, pluginWorktree) {
|
|
|
8664
8669
|
function explicitSafeInputWorktree(input = {}) {
|
|
8665
8670
|
for (const candidate of [input?.worktree, input?.directory]) {
|
|
8666
8671
|
if (typeof candidate !== "string" || !candidate.trim()) continue;
|
|
8667
|
-
const resolved =
|
|
8672
|
+
const resolved = path6.resolve(candidate);
|
|
8668
8673
|
if (isSafeWritableDirectory(resolved)) return resolved;
|
|
8669
8674
|
}
|
|
8670
8675
|
return null;
|
|
8671
8676
|
}
|
|
8672
8677
|
function isGitRepository(worktree) {
|
|
8673
|
-
return fs5.existsSync(
|
|
8678
|
+
return fs5.existsSync(path6.join(worktree, ".git"));
|
|
8674
8679
|
}
|
|
8675
8680
|
function normalizeLooseToken(value) {
|
|
8676
8681
|
return String(value ?? "").trim().normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -9165,7 +9170,7 @@ function buildClickUpSummaryPayload({ summaryMarkdown = "", summaryPath = "", ta
|
|
|
9165
9170
|
function deriveClickUpWorktree({ baseWorktree = "", taskId, taskType, parentTaskId, subtaskId } = {}) {
|
|
9166
9171
|
const branch = deriveClickUpBranchName({ taskType, parentTaskId, subtaskId, taskId });
|
|
9167
9172
|
const root = baseWorktree || process.cwd();
|
|
9168
|
-
return
|
|
9173
|
+
return path6.join(path6.dirname(root), `${path6.basename(root)}-${branch.replace(/\//g, "-")}`);
|
|
9169
9174
|
}
|
|
9170
9175
|
function clickUpCustomFieldValue(task = {}, names = []) {
|
|
9171
9176
|
const fields = Array.isArray(task.custom_fields) ? task.custom_fields : [];
|
|
@@ -9189,12 +9194,12 @@ function safeExistingClickUpWorktree({ metadata = {}, branch = "" } = {}) {
|
|
|
9189
9194
|
const taskMetadata = metadataTaskRouting(metadata);
|
|
9190
9195
|
const existingWorktree = typeof taskMetadata.worktree === "string" ? taskMetadata.worktree.trim() : "";
|
|
9191
9196
|
const existingBranch = typeof taskMetadata.branch === "string" ? taskMetadata.branch.trim() : "";
|
|
9192
|
-
if (!existingWorktree || !
|
|
9197
|
+
if (!existingWorktree || !path6.isAbsolute(existingWorktree) || !fs5.existsSync(existingWorktree)) return null;
|
|
9193
9198
|
try {
|
|
9194
9199
|
const stat = fs5.statSync(existingWorktree);
|
|
9195
9200
|
if (!stat.isDirectory()) return null;
|
|
9196
9201
|
if (branch && existingBranch && existingBranch !== branch) return null;
|
|
9197
|
-
return { branch: existingBranch || branch, worktree:
|
|
9202
|
+
return { branch: existingBranch || branch, worktree: path6.resolve(existingWorktree), reused: true };
|
|
9198
9203
|
} catch {
|
|
9199
9204
|
return null;
|
|
9200
9205
|
}
|
|
@@ -9280,17 +9285,17 @@ function openChamberEntryBranch(entry) {
|
|
|
9280
9285
|
return String(entry?.branch || entry?.branchName || entry?.branch_name || entry?.worktree?.branch || "").replace(/^refs\/heads\//, "");
|
|
9281
9286
|
}
|
|
9282
9287
|
function openChamberListIncludesDirectory(list, directory) {
|
|
9283
|
-
const resolved =
|
|
9288
|
+
const resolved = path6.resolve(directory);
|
|
9284
9289
|
return normalizeOpenChamberCollection(list).some((entry) => {
|
|
9285
9290
|
const entryDirectory = openChamberEntryDirectory(entry);
|
|
9286
|
-
return entryDirectory &&
|
|
9291
|
+
return entryDirectory && path6.resolve(entryDirectory) === resolved;
|
|
9287
9292
|
});
|
|
9288
9293
|
}
|
|
9289
9294
|
function openChamberListIncludesBranch(list, directory, branch) {
|
|
9290
|
-
const resolved =
|
|
9295
|
+
const resolved = path6.resolve(directory);
|
|
9291
9296
|
return normalizeOpenChamberCollection(list).some((entry) => {
|
|
9292
9297
|
const entryDirectory = openChamberEntryDirectory(entry);
|
|
9293
|
-
if (!entryDirectory ||
|
|
9298
|
+
if (!entryDirectory || path6.resolve(entryDirectory) !== resolved) return false;
|
|
9294
9299
|
const entryBranch = openChamberEntryBranch(entry);
|
|
9295
9300
|
return !entryBranch || entryBranch === branch;
|
|
9296
9301
|
});
|
|
@@ -9298,8 +9303,8 @@ function openChamberListIncludesBranch(list, directory, branch) {
|
|
|
9298
9303
|
async function findOpenChamberProject({ opencodeBaseUrl, baseWorktree, fetchImpl = globalThis.fetch } = {}) {
|
|
9299
9304
|
const projects = await requestOpenCodeJson({ baseUrl: opencodeBaseUrl, endpoint: "/project", directory: baseWorktree, fetchImpl });
|
|
9300
9305
|
if (!Array.isArray(projects)) return null;
|
|
9301
|
-
const resolvedBase =
|
|
9302
|
-
return projects.find((project) =>
|
|
9306
|
+
const resolvedBase = path6.resolve(baseWorktree);
|
|
9307
|
+
return projects.find((project) => path6.resolve(String(project?.worktree || project?.path || "")) === resolvedBase) || null;
|
|
9303
9308
|
}
|
|
9304
9309
|
async function refreshOpenChamberProjectCopy({ opencodeBaseUrl, projectId, fetchImpl = globalThis.fetch } = {}) {
|
|
9305
9310
|
if (!projectId) return { refreshed: false, reason: "project_id_unavailable" };
|
|
@@ -9354,18 +9359,18 @@ async function createOpenChamberClickUpWorktree({ openchamberBaseUrl, baseUrl, b
|
|
|
9354
9359
|
}
|
|
9355
9360
|
const createdDirectory = openChamberEntryDirectory(created);
|
|
9356
9361
|
const createdBranch = openChamberEntryBranch(created);
|
|
9357
|
-
if (!createdDirectory || !
|
|
9362
|
+
if (!createdDirectory || !path6.isAbsolute(createdDirectory)) {
|
|
9358
9363
|
throw new Error(`OpenChamber did not return an absolute worktree path for ${branch}.`);
|
|
9359
9364
|
}
|
|
9360
9365
|
if (createdBranch !== branch) {
|
|
9361
9366
|
throw new Error(`OpenChamber created unexpected branch ${createdBranch || "<unknown>"}; expected ${branch}.`);
|
|
9362
9367
|
}
|
|
9363
9368
|
const verified = await verifyOpenChamberGitWorktree({ openchamberBaseUrl: effectiveOpenChamberBaseUrl, baseWorktree, worktreePath: createdDirectory, branch, fetchImpl });
|
|
9364
|
-
return { created, worktree:
|
|
9369
|
+
return { created, worktree: path6.resolve(createdDirectory), branch: createdBranch, verified };
|
|
9365
9370
|
}
|
|
9366
9371
|
async function registerOpenChamberClickUpWorktree({ openchamberBaseUrl, opencodeBaseUrl, baseUrl, baseWorktree, branch, worktreePath, fetchImpl = globalThis.fetch, source = "reuse" } = {}) {
|
|
9367
9372
|
const visibility = await syncOpenChamberWorktreeVisibility({ openchamberBaseUrl: openchamberBaseUrl || baseUrl, opencodeBaseUrl: opencodeBaseUrl || baseUrl, baseWorktree, worktreePath, branch, fetchImpl });
|
|
9368
|
-
return { branch, worktree:
|
|
9373
|
+
return { branch, worktree: path6.resolve(worktreePath), reused: true, provider: "openchamber", openChamber: { source, visibility } };
|
|
9369
9374
|
}
|
|
9370
9375
|
async function ensureClickUpTaskWorktreeOpenChamber({ baseWorktree = "", taskId, taskType = "Tarea", parentTaskId = "", subtaskId = "", existingMetadata = {}, runGitFn = runGit, openchamberBaseUrl = "", opencodeBaseUrl = "", baseUrl = "", fetchImpl = globalThis.fetch, log = null } = {}) {
|
|
9371
9376
|
const effectiveOpenChamberBaseUrl = openchamberBaseUrl || baseUrl;
|
|
@@ -9428,10 +9433,10 @@ function ensureClickUpTaskWorktree({ baseWorktree = "", taskId, taskType = "Tare
|
|
|
9428
9433
|
const existing = safeExistingClickUpWorktree({ metadata: existingMetadata, branch });
|
|
9429
9434
|
if (existing) return { ...existing, branch, parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev" };
|
|
9430
9435
|
const worktreePath = deriveClickUpWorktree({ baseWorktree, taskId, taskType, parentTaskId: effectiveParent, subtaskId });
|
|
9431
|
-
if (fs5.existsSync(worktreePath)) return { branch, worktree:
|
|
9436
|
+
if (fs5.existsSync(worktreePath)) return { branch, worktree: path6.resolve(worktreePath), reused: true, parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev" };
|
|
9432
9437
|
if (allowNonGitFallback) {
|
|
9433
9438
|
fs5.mkdirSync(worktreePath, { recursive: true });
|
|
9434
|
-
return { branch, worktree:
|
|
9439
|
+
return { branch, worktree: path6.resolve(worktreePath), reused: false, fallback: "non_git", parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev", startPoint: parentBranch || "dev" };
|
|
9435
9440
|
}
|
|
9436
9441
|
let parentBootstrap = null;
|
|
9437
9442
|
if (isSubtask) {
|
|
@@ -9440,14 +9445,14 @@ function ensureClickUpTaskWorktree({ baseWorktree = "", taskId, taskType = "Tare
|
|
|
9440
9445
|
const parentStartPoint = resolveClickUpDevStartPoint(baseWorktree, runGitFn);
|
|
9441
9446
|
const parentBranchExists = clickUpGitRefExists(baseWorktree, parentBranch, runGitFn);
|
|
9442
9447
|
addClickUpWorktreeForBranch({ baseWorktree, branch: parentBranch, worktreePath: parentWorktree, startPoint: parentStartPoint, runGitFn });
|
|
9443
|
-
parentBootstrap = { branch: parentBranch, worktree:
|
|
9448
|
+
parentBootstrap = { branch: parentBranch, worktree: path6.resolve(parentWorktree), startPoint: parentBranchExists ? parentBranch : parentStartPoint, reused: parentBranchExists };
|
|
9444
9449
|
} else {
|
|
9445
|
-
parentBootstrap = { branch: parentBranch, worktree:
|
|
9450
|
+
parentBootstrap = { branch: parentBranch, worktree: path6.resolve(parentWorktree), reused: true };
|
|
9446
9451
|
}
|
|
9447
9452
|
}
|
|
9448
9453
|
const startPoint = isSubtask ? parentBranch : resolveClickUpDevStartPoint(baseWorktree, runGitFn);
|
|
9449
9454
|
addClickUpWorktreeForBranch({ baseWorktree, branch, worktreePath, startPoint, runGitFn });
|
|
9450
|
-
return { branch, worktree:
|
|
9455
|
+
return { branch, worktree: path6.resolve(worktreePath), reused: false, startPoint, parentBranch: parentBranch || void 0, prTarget: parentBranch || "dev", parentBootstrap: parentBootstrap || void 0 };
|
|
9451
9456
|
}
|
|
9452
9457
|
function normalizeClickUpDefinitionDocParent(parent = {}) {
|
|
9453
9458
|
const docId = String(parent.doc_id || parent.docId || CLICKUP_DEFINITION_DOC_PARENT.doc_id).trim();
|
|
@@ -9597,7 +9602,7 @@ function buildClickUpTransitionPayload({ fromStatus, toStatus, validationPassed
|
|
|
9597
9602
|
}
|
|
9598
9603
|
function ensureOptimaGitignoreRules(worktree) {
|
|
9599
9604
|
if (!isGitRepository(worktree)) return { touched: false, added: [] };
|
|
9600
|
-
const gitignorePath =
|
|
9605
|
+
const gitignorePath = path6.join(worktree, ".gitignore");
|
|
9601
9606
|
const existing = fs5.existsSync(gitignorePath) ? fs5.readFileSync(gitignorePath, "utf8") : "";
|
|
9602
9607
|
const existingRules = new Set(existing.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
|
|
9603
9608
|
const missingRules = OPTIMA_GITIGNORE_RULES.filter((rule) => !existingRules.has(rule));
|
|
@@ -9613,40 +9618,40 @@ function ensureOptimaGitignoreRules(worktree) {
|
|
|
9613
9618
|
return { touched: true, added: missingRules };
|
|
9614
9619
|
}
|
|
9615
9620
|
function optimaDir(worktree) {
|
|
9616
|
-
return
|
|
9621
|
+
return path6.join(worktree, OPTIMA_DIRNAME);
|
|
9617
9622
|
}
|
|
9618
9623
|
function optimaLocalConfigDir(worktree) {
|
|
9619
|
-
return
|
|
9624
|
+
return path6.join(optimaDir(worktree), ".config");
|
|
9620
9625
|
}
|
|
9621
9626
|
function optimaConfigDir(worktree) {
|
|
9622
9627
|
return optimaLocalConfigDir(worktree);
|
|
9623
9628
|
}
|
|
9624
9629
|
function optimaCodemapPath(worktree) {
|
|
9625
|
-
return
|
|
9630
|
+
return path6.join(optimaDir(worktree), "codemap.yml");
|
|
9626
9631
|
}
|
|
9627
9632
|
function optimaTasksDir(worktree) {
|
|
9628
|
-
return
|
|
9633
|
+
return path6.join(optimaDir(worktree), "tasks");
|
|
9629
9634
|
}
|
|
9630
9635
|
function optimaEvidencesDir(worktree) {
|
|
9631
|
-
return
|
|
9636
|
+
return path6.join(optimaDir(worktree), "evidences");
|
|
9632
9637
|
}
|
|
9633
9638
|
function optimaScrsDir(worktree) {
|
|
9634
|
-
return
|
|
9639
|
+
return path6.join(optimaDir(worktree), "docs", "scrs");
|
|
9635
9640
|
}
|
|
9636
9641
|
function legacyNomadworkDir(worktree) {
|
|
9637
|
-
return
|
|
9642
|
+
return path6.join(worktree, LEGACY_NOMADWORK_DIRNAME);
|
|
9638
9643
|
}
|
|
9639
9644
|
function legacyNomadworksDir(worktree) {
|
|
9640
|
-
return
|
|
9645
|
+
return path6.join(worktree, LEGACY_NOMADWORKS_DIRNAME);
|
|
9641
9646
|
}
|
|
9642
9647
|
function legacyOrbitaDir(worktree) {
|
|
9643
|
-
return
|
|
9648
|
+
return path6.join(worktree, LEGACY_ORBITA_DIRNAME);
|
|
9644
9649
|
}
|
|
9645
9650
|
function legacyStaticEngDir(worktree) {
|
|
9646
|
-
return
|
|
9651
|
+
return path6.join(worktree, LEGACY_STATICENG_DIRNAME);
|
|
9647
9652
|
}
|
|
9648
9653
|
function repoConfigPath(worktree) {
|
|
9649
|
-
return
|
|
9654
|
+
return path6.join(optimaConfigDir(worktree), "optima.yaml");
|
|
9650
9655
|
}
|
|
9651
9656
|
function normalizeLegacyDiscussionEntry(entry) {
|
|
9652
9657
|
if (!entry || typeof entry !== "object") return entry;
|
|
@@ -9659,25 +9664,25 @@ function normalizeLegacyDiscussionEntry(entry) {
|
|
|
9659
9664
|
return next;
|
|
9660
9665
|
}
|
|
9661
9666
|
function repoPoliciesDir(worktree) {
|
|
9662
|
-
return
|
|
9667
|
+
return path6.join(optimaDir(worktree), "policies");
|
|
9663
9668
|
}
|
|
9664
9669
|
function generatedPoliciesDir(worktree) {
|
|
9665
|
-
return
|
|
9670
|
+
return path6.join(optimaLocalConfigDir(worktree), "generated", "policies");
|
|
9666
9671
|
}
|
|
9667
9672
|
function generatedAgentsDir(worktree) {
|
|
9668
|
-
return
|
|
9673
|
+
return path6.join(optimaLocalConfigDir(worktree), "generated", "agents");
|
|
9669
9674
|
}
|
|
9670
9675
|
function repoAgentsDir(worktree) {
|
|
9671
|
-
return
|
|
9676
|
+
return path6.join(optimaDir(worktree), "agents");
|
|
9672
9677
|
}
|
|
9673
9678
|
function repoAgentAdditionsDir(worktree) {
|
|
9674
|
-
return
|
|
9679
|
+
return path6.join(optimaDir(worktree), "agent-additions");
|
|
9675
9680
|
}
|
|
9676
9681
|
function legacyRepoAgentsDir(worktree) {
|
|
9677
|
-
return
|
|
9682
|
+
return path6.join(legacyNomadworksDir(worktree), "agents");
|
|
9678
9683
|
}
|
|
9679
9684
|
function runtimeDiscussionRegistryPath(worktree) {
|
|
9680
|
-
return
|
|
9685
|
+
return path6.join(optimaLocalConfigDir(worktree), "runtime", "discussions.json");
|
|
9681
9686
|
}
|
|
9682
9687
|
function resolveConfigPath(worktree) {
|
|
9683
9688
|
return repoConfigPath(worktree);
|
|
@@ -9720,32 +9725,32 @@ function mergeClickUpAgentMetadata(existing, update = {}) {
|
|
|
9720
9725
|
return JSON.stringify(sortJsonValue(merged), null, 2);
|
|
9721
9726
|
}
|
|
9722
9727
|
function optimaRuntimeDir(worktree) {
|
|
9723
|
-
return
|
|
9728
|
+
return path6.join(optimaLocalConfigDir(worktree), "runtime");
|
|
9724
9729
|
}
|
|
9725
9730
|
function clickUpWebhookStatePath(worktree) {
|
|
9726
|
-
return
|
|
9731
|
+
return path6.join(optimaRuntimeDir(worktree), "clickup-webhook.json");
|
|
9727
9732
|
}
|
|
9728
9733
|
function clickUpCommentLedgerPath(worktree) {
|
|
9729
|
-
return
|
|
9734
|
+
return path6.join(optimaRuntimeDir(worktree), "clickup-comment-ledger.jsonl");
|
|
9730
9735
|
}
|
|
9731
9736
|
function clickUpWebhookLogPath(worktree) {
|
|
9732
|
-
return
|
|
9737
|
+
return path6.join(optimaRuntimeDir(worktree), "clickup-webhook.log.jsonl");
|
|
9733
9738
|
}
|
|
9734
9739
|
function normalizeClickUpWebhookLogLevel(value) {
|
|
9735
9740
|
const level = String(value || "info").trim().toLowerCase();
|
|
9736
9741
|
return CLICKUP_WEBHOOK_LOG_LEVELS.has(level) ? level : "info";
|
|
9737
9742
|
}
|
|
9738
9743
|
function clickUpWebhookAuditLogDir() {
|
|
9739
|
-
const dataHome = process.env.XDG_DATA_HOME &&
|
|
9740
|
-
return
|
|
9744
|
+
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");
|
|
9745
|
+
return path6.join(dataHome, "opencode-optima");
|
|
9741
9746
|
}
|
|
9742
9747
|
function clickUpWebhookAuditLogPath(at = /* @__PURE__ */ new Date(), logDir = clickUpWebhookAuditLogDir()) {
|
|
9743
|
-
return
|
|
9748
|
+
return path6.join(logDir, `clickup-webhook-${at.toISOString().slice(0, 10)}.jsonl`);
|
|
9744
9749
|
}
|
|
9745
9750
|
function clickUpWebhookRequestFilePath(at = /* @__PURE__ */ new Date(), logDir = clickUpWebhookAuditLogDir()) {
|
|
9746
9751
|
const stamp = at.toISOString().replace(/:/g, "-").replace(/\./g, "-");
|
|
9747
9752
|
const shortId = crypto.randomBytes(4).toString("hex");
|
|
9748
|
-
return
|
|
9753
|
+
return path6.join(logDir, "requests", `clickup-webhook-${stamp}-${shortId}.json`);
|
|
9749
9754
|
}
|
|
9750
9755
|
function findOptimaPluginTupleOptions(pluginEntries = []) {
|
|
9751
9756
|
if (!Array.isArray(pluginEntries)) return null;
|
|
@@ -9807,6 +9812,10 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
|
|
|
9807
9812
|
startupReconciliationDelayMs: normalizeNonNegativeInteger(
|
|
9808
9813
|
opencode.startup_reconciliation_delay_ms ?? opencode.startupReconciliationDelayMs ?? raw.startup_reconciliation_delay_ms ?? raw.startupReconciliationDelayMs,
|
|
9809
9814
|
CLICKUP_WEBHOOK_STARTUP_RECONCILIATION_DELAY_MS
|
|
9815
|
+
),
|
|
9816
|
+
assignmentWatchdogIntervalMs: normalizeNonNegativeInteger(
|
|
9817
|
+
opencode.assignment_watchdog_interval_ms ?? opencode.assignmentWatchdogIntervalMs ?? raw.assignment_watchdog_interval_ms ?? raw.assignmentWatchdogIntervalMs,
|
|
9818
|
+
CLICKUP_ASSIGNMENT_WATCHDOG_INTERVAL_MS
|
|
9810
9819
|
)
|
|
9811
9820
|
},
|
|
9812
9821
|
openchamber: {
|
|
@@ -9840,7 +9849,7 @@ function normalizeClickUpWebhookConfig(rawClickUp = null, worktree = process.cwd
|
|
|
9840
9849
|
};
|
|
9841
9850
|
const errors = [];
|
|
9842
9851
|
if (!config.enabled) errors.push("clickup.enabled must be true");
|
|
9843
|
-
if (!config.basePath || !
|
|
9852
|
+
if (!config.basePath || !path6.isAbsolute(config.basePath)) errors.push("clickup.base_path must be an absolute path");
|
|
9844
9853
|
if (!config.teamId) errors.push("clickup.team_id is required");
|
|
9845
9854
|
if (!config.apiToken) errors.push("clickup.api_token is required");
|
|
9846
9855
|
if (!config.webhook.publicUrl) errors.push("clickup.webhook.public_url is required");
|
|
@@ -9898,7 +9907,7 @@ function readClickUpWebhookState(worktree, config = null) {
|
|
|
9898
9907
|
}
|
|
9899
9908
|
function writeClickUpWebhookState(worktree, state, config = null) {
|
|
9900
9909
|
const statePath = clickUpWebhookStatePath(worktree);
|
|
9901
|
-
fs5.mkdirSync(
|
|
9910
|
+
fs5.mkdirSync(path6.dirname(statePath), { recursive: true, mode: 448 });
|
|
9902
9911
|
const next = sanitizeClickUpWebhookState(state, config);
|
|
9903
9912
|
fs5.writeFileSync(statePath, `${JSON.stringify(next, null, 2)}
|
|
9904
9913
|
`, { encoding: "utf8", mode: 384 });
|
|
@@ -9919,7 +9928,7 @@ function isClickUpWebhookStateActive(state, config) {
|
|
|
9919
9928
|
function expandHomePath(value = "") {
|
|
9920
9929
|
const input = String(value || "").trim();
|
|
9921
9930
|
if (input === "~") return os.homedir();
|
|
9922
|
-
if (input.startsWith("~/")) return
|
|
9931
|
+
if (input.startsWith("~/")) return path6.join(os.homedir(), input.slice(2));
|
|
9923
9932
|
return input;
|
|
9924
9933
|
}
|
|
9925
9934
|
function resolveSecretReference(value = "") {
|
|
@@ -10295,7 +10304,7 @@ function readClickUpCommentLedger(ledgerPath) {
|
|
|
10295
10304
|
}
|
|
10296
10305
|
function appendClickUpCommentLedgerEntry(ledgerPath, entry = {}) {
|
|
10297
10306
|
if (!ledgerPath || !entry.key) return;
|
|
10298
|
-
fs5.mkdirSync(
|
|
10307
|
+
fs5.mkdirSync(path6.dirname(ledgerPath), { recursive: true, mode: 448 });
|
|
10299
10308
|
fs5.appendFileSync(ledgerPath, `${JSON.stringify(entry)}
|
|
10300
10309
|
`, { encoding: "utf8", mode: 384 });
|
|
10301
10310
|
try {
|
|
@@ -10772,17 +10781,87 @@ function openCodeResultSummary(result) {
|
|
|
10772
10781
|
status: result?.status || result?.response?.status || null
|
|
10773
10782
|
};
|
|
10774
10783
|
}
|
|
10784
|
+
function openCodeMessagePayload(message = {}) {
|
|
10785
|
+
if (!isPlainObject(message)) return {};
|
|
10786
|
+
const rawData = message.data;
|
|
10787
|
+
if (isPlainObject(rawData)) {
|
|
10788
|
+
return {
|
|
10789
|
+
...rawData,
|
|
10790
|
+
id: rawData.id || message.id,
|
|
10791
|
+
time_created: rawData.time_created ?? message.time_created,
|
|
10792
|
+
time_updated: rawData.time_updated ?? message.time_updated
|
|
10793
|
+
};
|
|
10794
|
+
}
|
|
10795
|
+
if (typeof rawData === "string" && rawData.trim()) {
|
|
10796
|
+
try {
|
|
10797
|
+
const parsed = JSON.parse(rawData);
|
|
10798
|
+
if (isPlainObject(parsed)) {
|
|
10799
|
+
return {
|
|
10800
|
+
...parsed,
|
|
10801
|
+
id: parsed.id || message.id,
|
|
10802
|
+
time_created: parsed.time_created ?? message.time_created,
|
|
10803
|
+
time_updated: parsed.time_updated ?? message.time_updated
|
|
10804
|
+
};
|
|
10805
|
+
}
|
|
10806
|
+
} catch {
|
|
10807
|
+
}
|
|
10808
|
+
}
|
|
10809
|
+
return message;
|
|
10810
|
+
}
|
|
10775
10811
|
function normalizeOpenCodeMessageRole(message = {}) {
|
|
10776
|
-
|
|
10812
|
+
const payload = openCodeMessagePayload(message);
|
|
10813
|
+
return payload.role || payload.info?.role || payload.author?.role || payload.type || "";
|
|
10777
10814
|
}
|
|
10778
10815
|
function normalizeOpenCodeMessageAgent(message = {}) {
|
|
10779
|
-
|
|
10816
|
+
const payload = openCodeMessagePayload(message);
|
|
10817
|
+
return payload.agent || payload.info?.agent || payload.mode?.agent || payload.author?.agent || "";
|
|
10780
10818
|
}
|
|
10781
10819
|
function normalizeOpenCodeMessageMode(message = {}) {
|
|
10782
|
-
|
|
10820
|
+
const payload = openCodeMessagePayload(message);
|
|
10821
|
+
return payload.mode || payload.info?.mode || payload.metadata?.mode || "";
|
|
10783
10822
|
}
|
|
10784
10823
|
function normalizeOpenCodeMessageId(message = {}) {
|
|
10785
|
-
|
|
10824
|
+
const payload = openCodeMessagePayload(message);
|
|
10825
|
+
return payload.id || payload.messageID || payload.messageId || payload.info?.id || payload.data?.id || message.id || null;
|
|
10826
|
+
}
|
|
10827
|
+
function openCodeMessageTimestampMs(message = {}, key = "updated") {
|
|
10828
|
+
const payload = openCodeMessagePayload(message);
|
|
10829
|
+
const time = payload.time || payload.info?.time || {};
|
|
10830
|
+
const value = key === "completed" ? payload.time_completed ?? payload.timeCompleted ?? time.completed : key === "created" ? payload.time_created ?? payload.timeCreated ?? time.created : payload.time_updated ?? payload.timeUpdated ?? time.updated ?? payload.time_created ?? payload.timeCreated ?? time.created;
|
|
10831
|
+
const number = Number(value);
|
|
10832
|
+
return Number.isFinite(number) && number > 0 ? number : 0;
|
|
10833
|
+
}
|
|
10834
|
+
function isOpenCodeAssistantMessageRunning(message = {}) {
|
|
10835
|
+
if (normalizeLooseToken(normalizeOpenCodeMessageRole(message)) !== "assistant") return false;
|
|
10836
|
+
const started = openCodeMessageTimestampMs(message, "created") > 0;
|
|
10837
|
+
if (!started) return false;
|
|
10838
|
+
return openCodeMessageTimestampMs(message, "completed") === 0;
|
|
10839
|
+
}
|
|
10840
|
+
async function inspectOpenCodeSessionActivity(client, { sessionId, directory, limit = 10 } = {}) {
|
|
10841
|
+
const messages = await readOpenCodeSessionMessages(client, { sessionId, directory, limit });
|
|
10842
|
+
if (!messages) return { ok: false, reason: "message_inspection_unavailable", sessionId, directory };
|
|
10843
|
+
const enriched = messages.map((message, index) => ({
|
|
10844
|
+
message,
|
|
10845
|
+
index,
|
|
10846
|
+
sortTime: openCodeMessageTimestampMs(message, "updated") || index,
|
|
10847
|
+
createdAt: openCodeMessageTimestampMs(message, "created"),
|
|
10848
|
+
completedAt: openCodeMessageTimestampMs(message, "completed")
|
|
10849
|
+
})).sort((a, b) => a.sortTime - b.sortTime || a.index - b.index);
|
|
10850
|
+
const assistantMessages = enriched.filter((entry) => normalizeLooseToken(normalizeOpenCodeMessageRole(entry.message)) === "assistant");
|
|
10851
|
+
const latestAssistant = assistantMessages.at(-1) || null;
|
|
10852
|
+
const latest = enriched.at(-1) || null;
|
|
10853
|
+
const running = latestAssistant ? isOpenCodeAssistantMessageRunning(latestAssistant.message) : false;
|
|
10854
|
+
return {
|
|
10855
|
+
ok: true,
|
|
10856
|
+
sessionId,
|
|
10857
|
+
directory,
|
|
10858
|
+
count: messages.length,
|
|
10859
|
+
running,
|
|
10860
|
+
latestMessageId: latest ? normalizeOpenCodeMessageId(latest.message) : null,
|
|
10861
|
+
latestAssistantMessageId: latestAssistant ? normalizeOpenCodeMessageId(latestAssistant.message) : null,
|
|
10862
|
+
latestAssistantCreatedAt: latestAssistant?.createdAt || 0,
|
|
10863
|
+
latestAssistantCompletedAt: latestAssistant?.completedAt || 0
|
|
10864
|
+
};
|
|
10786
10865
|
}
|
|
10787
10866
|
function summarizeOpenCodeMessages(messages = [], { snippetLength = 160, maxMessages = 50 } = {}) {
|
|
10788
10867
|
const list = Array.isArray(messages) ? messages.slice(0, maxMessages) : [];
|
|
@@ -10922,8 +11001,9 @@ async function probeOpenCodeSessionControl(client, { directory, agent, omitAgent
|
|
|
10922
11001
|
};
|
|
10923
11002
|
}
|
|
10924
11003
|
function openCodeMessageText(message) {
|
|
10925
|
-
const
|
|
10926
|
-
const
|
|
11004
|
+
const payload = openCodeMessagePayload(message);
|
|
11005
|
+
const parts = [payload?.text, payload?.content, payload?.message, payload?.body?.text, payload?.data?.text];
|
|
11006
|
+
const partList = Array.isArray(payload?.parts) ? payload.parts : Array.isArray(payload?.body?.parts) ? payload.body.parts : [];
|
|
10927
11007
|
for (const part of partList) parts.push(part?.text, part?.content);
|
|
10928
11008
|
return parts.filter((value) => typeof value === "string").join("\n");
|
|
10929
11009
|
}
|
|
@@ -11087,7 +11167,7 @@ function formatClickUpWebhookPrompt({ eventType, taskId, payload, branch = "", w
|
|
|
11087
11167
|
}
|
|
11088
11168
|
function appendClickUpWebhookLocalLog(worktree, entry) {
|
|
11089
11169
|
const logPath = clickUpWebhookLogPath(worktree);
|
|
11090
|
-
fs5.mkdirSync(
|
|
11170
|
+
fs5.mkdirSync(path6.dirname(logPath), { recursive: true });
|
|
11091
11171
|
const safeEntry = { ...entry, at: entry.at || (/* @__PURE__ */ new Date()).toISOString() };
|
|
11092
11172
|
fs5.appendFileSync(logPath, `${JSON.stringify(safeEntry)}
|
|
11093
11173
|
`, "utf8");
|
|
@@ -11118,7 +11198,7 @@ function closeClickUpWebhookServer(server) {
|
|
|
11118
11198
|
});
|
|
11119
11199
|
}
|
|
11120
11200
|
function managedClickUpWebhookKey({ worktree, state, config } = {}) {
|
|
11121
|
-
return [
|
|
11201
|
+
return [path6.resolve(worktree || process.cwd()), state?.webhookId || "", config?.webhook?.publicUrl || ""].join("|");
|
|
11122
11202
|
}
|
|
11123
11203
|
async function deleteClickUpWebhookBestEffort({ webhookId, clickupClient, worktree, reason = "cleanup" } = {}) {
|
|
11124
11204
|
const id = String(webhookId || "").trim();
|
|
@@ -11141,6 +11221,7 @@ async function cleanupManagedClickUpWebhook(entry = {}, { timeoutMs = CLICKUP_WE
|
|
|
11141
11221
|
entry.cleaning = true;
|
|
11142
11222
|
const cleanup = (async () => {
|
|
11143
11223
|
clickUpWebhookLifecycleLog(entry.worktree, { type: "cleanup_started", reason, key: entry.key, webhookId: entry.state?.webhookId });
|
|
11224
|
+
if (entry.assignmentWatchdog?.interval) clearInterval(entry.assignmentWatchdog.interval);
|
|
11144
11225
|
const closeResult = await closeClickUpWebhookServer(entry.listener?.server);
|
|
11145
11226
|
if (entry.listenerRegistry && entry.listener?.key) entry.listenerRegistry.delete(entry.listener.key);
|
|
11146
11227
|
const preservedResult = { ok: true, skipped: true, reason: "remote_webhook_preserved" };
|
|
@@ -11154,10 +11235,10 @@ async function cleanupManagedClickUpWebhook(entry = {}, { timeoutMs = CLICKUP_WE
|
|
|
11154
11235
|
if (result?.timeout) clickUpWebhookLifecycleLog(entry.worktree, { type: "cleanup_timeout", reason, webhookId: entry.state?.webhookId });
|
|
11155
11236
|
return result;
|
|
11156
11237
|
}
|
|
11157
|
-
function registerClickUpWebhookLifecycle({ config, state, worktree, clickupClient, listener, listenerRegistry = activeClickUpWebhookListeners } = {}) {
|
|
11238
|
+
function registerClickUpWebhookLifecycle({ config, state, worktree, clickupClient, listener, listenerRegistry = activeClickUpWebhookListeners, assignmentWatchdog = null } = {}) {
|
|
11158
11239
|
if (!isClickUpWebhookStateActive(state, config)) return null;
|
|
11159
11240
|
const key = managedClickUpWebhookKey({ worktree, state, config });
|
|
11160
|
-
const entry = { key, config, state, worktree, clickupClient, listener, listenerRegistry, registeredAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
11241
|
+
const entry = { key, config, state, worktree, clickupClient, listener, listenerRegistry, assignmentWatchdog, registeredAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
11161
11242
|
activeClickUpWebhookLifecycleRegistry.set(key, entry);
|
|
11162
11243
|
installClickUpWebhookSignalHandlers();
|
|
11163
11244
|
clickUpWebhookLifecycleLog(worktree, { type: "lifecycle_registered", key, webhookId: state.webhookId });
|
|
@@ -11222,8 +11303,8 @@ function writeClickUpWebhookAuditLog({ method, url, headers = {}, rawBody = "",
|
|
|
11222
11303
|
let requestFile;
|
|
11223
11304
|
if (level === "verbose") {
|
|
11224
11305
|
const absoluteRequestFile = clickUpWebhookRequestFilePath(at, logDir);
|
|
11225
|
-
fs5.mkdirSync(
|
|
11226
|
-
requestFile =
|
|
11306
|
+
fs5.mkdirSync(path6.dirname(absoluteRequestFile), { recursive: true });
|
|
11307
|
+
requestFile = path6.relative(logDir, absoluteRequestFile).split(path6.sep).join("/");
|
|
11227
11308
|
const parsedBody = payload || (() => {
|
|
11228
11309
|
try {
|
|
11229
11310
|
return JSON.parse(Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : String(rawBody || ""));
|
|
@@ -11447,19 +11528,54 @@ function scheduleClickUpStartupReconciliation({ config, state = {}, worktree = p
|
|
|
11447
11528
|
timer?.unref?.();
|
|
11448
11529
|
return { scheduled: true, delayMs: normalizedDelayMs, timer };
|
|
11449
11530
|
}
|
|
11450
|
-
|
|
11451
|
-
|
|
11531
|
+
function scheduleClickUpAssignmentWatchdog({ config, state = {}, worktree = process.cwd(), clickupClient, openCodeClient, scheduler = setInterval, intervalMs = config?.opencode?.assignmentWatchdogIntervalMs ?? CLICKUP_ASSIGNMENT_WATCHDOG_INTERVAL_MS, saveState = null, reconcile = reconcileClickUpStartup } = {}) {
|
|
11532
|
+
const normalizedIntervalMs = normalizeNonNegativeInteger(intervalMs, CLICKUP_ASSIGNMENT_WATCHDOG_INTERVAL_MS);
|
|
11533
|
+
if (!normalizedIntervalMs) {
|
|
11534
|
+
clickUpWebhookLifecycleLog(worktree, { type: "assignment_watchdog_disabled", webhookId: state?.webhookId || null });
|
|
11535
|
+
return { scheduled: false, intervalMs: 0, reason: "disabled" };
|
|
11536
|
+
}
|
|
11537
|
+
let running = false;
|
|
11538
|
+
const run = () => {
|
|
11539
|
+
if (running) {
|
|
11540
|
+
appendClickUpWebhookLocalLog(worktree, { type: "assignment_watchdog_tick_skipped", reason: "previous_tick_running" });
|
|
11541
|
+
return;
|
|
11542
|
+
}
|
|
11543
|
+
running = true;
|
|
11544
|
+
const latestState = readClickUpWebhookState(worktree, config);
|
|
11545
|
+
Promise.resolve().then(() => reconcile({
|
|
11546
|
+
config,
|
|
11547
|
+
state: latestState?.webhookId ? latestState : state,
|
|
11548
|
+
worktree,
|
|
11549
|
+
clickupClient,
|
|
11550
|
+
openCodeClient,
|
|
11551
|
+
saveState,
|
|
11552
|
+
assignmentMode: "watchdog"
|
|
11553
|
+
})).catch((error) => {
|
|
11554
|
+
clickUpWebhookLifecycleLog(worktree, { type: "assignment_watchdog_failed", message: error.message });
|
|
11555
|
+
appendClickUpWebhookLocalLog(worktree, { type: "assignment_watchdog_failed", message: error.message });
|
|
11556
|
+
}).finally(() => {
|
|
11557
|
+
running = false;
|
|
11558
|
+
});
|
|
11559
|
+
};
|
|
11560
|
+
const interval = scheduler(run, normalizedIntervalMs);
|
|
11561
|
+
interval?.unref?.();
|
|
11562
|
+
clickUpWebhookLifecycleLog(worktree, { type: "assignment_watchdog_scheduled", intervalMs: normalizedIntervalMs, webhookId: state?.webhookId || null });
|
|
11563
|
+
return { scheduled: true, intervalMs: normalizedIntervalMs, interval };
|
|
11564
|
+
}
|
|
11565
|
+
async function reconcileClickUpStartup({ config, state = {}, worktree = process.cwd(), clickupClient, openCodeClient, sessionExists = openCodeSessionExists, createSession = createOpenCodeSession, sendSessionEvent = sendOpenCodeSessionEvent, verifySessionEventDelivery = verifyOpenCodeSessionEventDelivery, waitForReadiness = waitForOpenCodeReadiness, saveState = null, now = () => /* @__PURE__ */ new Date(), limit = CLICKUP_WEBHOOK_STARTUP_TASK_LIMIT, assignmentMode = "startup" } = {}) {
|
|
11566
|
+
const watchdogMode = assignmentMode === "watchdog";
|
|
11567
|
+
clickUpWebhookLifecycleLog(worktree, { type: watchdogMode ? "assignment_watchdog_started" : "startup_reconciliation_started", lastWebhookAt: state.lastWebhookAt || null });
|
|
11452
11568
|
if (!config || !clickupClient?.listAssignedTasks) {
|
|
11453
11569
|
const skipped = { ok: true, skipped: true, reason: "clickup_task_listing_unavailable", assigned: 0, comments: 0 };
|
|
11454
|
-
clickUpWebhookLifecycleLog(worktree, { type: "startup_reconciliation_finished", ...skipped });
|
|
11570
|
+
clickUpWebhookLifecycleLog(worktree, { type: watchdogMode ? "assignment_watchdog_finished" : "startup_reconciliation_finished", ...skipped });
|
|
11455
11571
|
return skipped;
|
|
11456
11572
|
}
|
|
11457
11573
|
const readiness = await waitForReadiness(openCodeClient, { worktree, now, opencodeBaseUrl: config.opencode?.baseUrl });
|
|
11458
11574
|
appendClickUpWebhookLocalLog(worktree, { type: readiness.ok ? "startup_reconciliation_readiness_ready" : "startup_reconciliation_readiness_failed", ...readiness });
|
|
11459
11575
|
if (!readiness.ok) {
|
|
11460
11576
|
const failed = { ok: false, skipped: true, reason: "opencode_not_ready", readiness, assigned: 0, comments: 0, ignored: 0, errors: 1, undelivered: 1, tasks: [], validation: { undelivered: 1, emptyPromptSessions: [] } };
|
|
11461
|
-
clickUpWebhookLifecycleLog(worktree, { type: "startup_reconciliation_failed", reason: failed.reason, readiness });
|
|
11462
|
-
clickUpWebhookLifecycleLog(worktree, { type: "startup_reconciliation_finished", ...failed });
|
|
11577
|
+
clickUpWebhookLifecycleLog(worktree, { type: watchdogMode ? "assignment_watchdog_failed" : "startup_reconciliation_failed", reason: failed.reason, readiness });
|
|
11578
|
+
clickUpWebhookLifecycleLog(worktree, { type: watchdogMode ? "assignment_watchdog_finished" : "startup_reconciliation_finished", ...failed });
|
|
11463
11579
|
return failed;
|
|
11464
11580
|
}
|
|
11465
11581
|
let authorizedUserId = "";
|
|
@@ -11477,6 +11593,7 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
|
|
|
11477
11593
|
if (saveState) saveState(nextState);
|
|
11478
11594
|
};
|
|
11479
11595
|
const lastWebhookMs = clickUpTimestampMs(mutableState.lastWebhookAt);
|
|
11596
|
+
const startupCommentStartMs = lastWebhookMs || Math.max(0, now().getTime() - CLICKUP_WEBHOOK_STARTUP_COMMENT_LOOKBACK_MS);
|
|
11480
11597
|
const ignored = new Set((config.routing?.ignoredStatuses || CLICKUP_WEBHOOK_TERMINAL_STATUSES).map(normalizeClickUpStatus));
|
|
11481
11598
|
const routed = { assigned: 0, comments: 0, ignored: 0, errors: 0, undelivered: 0, tasks: [] };
|
|
11482
11599
|
const listed = await clickupClient.listAssignedTasks({ assigneeId: config.routing.productManagerAssigneeId, limit });
|
|
@@ -11495,9 +11612,29 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
|
|
|
11495
11612
|
routed.ignored += 1;
|
|
11496
11613
|
continue;
|
|
11497
11614
|
}
|
|
11615
|
+
if (watchdogMode) {
|
|
11616
|
+
const existingMetadata = clickUpTaskAgentMetadata(task, config.routing.metadataFieldId);
|
|
11617
|
+
const metadata = normalizeAgentMetadataJson(existingMetadata);
|
|
11618
|
+
const rawSessionId = getNestedMetadataValue(metadata, config.routing.metadataKey);
|
|
11619
|
+
const sessionId = typeof rawSessionId === "string" && rawSessionId.startsWith("ses_") ? rawSessionId : "";
|
|
11620
|
+
const directory = String(getNestedMetadataValue(metadata, "task.worktree") || "").trim();
|
|
11621
|
+
if (sessionId) {
|
|
11622
|
+
try {
|
|
11623
|
+
const activity = await inspectOpenCodeSessionActivity(openCodeClient, { sessionId, directory });
|
|
11624
|
+
appendClickUpWebhookLocalLog(worktree, { type: "assignment_watchdog_session_activity", taskId, sessionId, directory: directory || null, ...activity });
|
|
11625
|
+
if (activity.running) {
|
|
11626
|
+
routed.ignored += 1;
|
|
11627
|
+
routed.tasks.push({ taskId, action: "ignored", ok: true, sessionId, branch: getNestedMetadataValue(metadata, "task.branch") || null, worktree: directory || null, verification: "session_running", delivered: false });
|
|
11628
|
+
continue;
|
|
11629
|
+
}
|
|
11630
|
+
} catch (error) {
|
|
11631
|
+
appendClickUpWebhookLocalLog(worktree, { type: "assignment_watchdog_session_activity_failed", taskId, sessionId, directory: directory || null, message: error.message });
|
|
11632
|
+
}
|
|
11633
|
+
}
|
|
11634
|
+
}
|
|
11498
11635
|
try {
|
|
11499
11636
|
const result = await routeClickUpWebhookEvent({
|
|
11500
|
-
payload: { webhook_id: mutableState.webhookId || "startup", event: "taskAssigneeUpdated", task_id: taskId, task, startup_reconciliation: true },
|
|
11637
|
+
payload: { webhook_id: mutableState.webhookId || "startup", event: "taskAssigneeUpdated", task_id: taskId, task, startup_reconciliation: true, assignment_watchdog: watchdogMode },
|
|
11501
11638
|
config,
|
|
11502
11639
|
state: mutableState,
|
|
11503
11640
|
worktree,
|
|
@@ -11547,12 +11684,12 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
|
|
|
11547
11684
|
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_task_undelivered", taskId, action: "error", sessionId: null, reason: "startup_reconciliation_task_failed" });
|
|
11548
11685
|
await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "startup_reconciliation_task_failed", source: "startup_reconciliation_task" });
|
|
11549
11686
|
}
|
|
11550
|
-
if (!
|
|
11687
|
+
if (!startupCommentStartMs || !clickupClient?.getTaskComments) continue;
|
|
11551
11688
|
try {
|
|
11552
|
-
const commentsResponse = await clickupClient.getTaskComments({ taskId, start:
|
|
11689
|
+
const commentsResponse = await clickupClient.getTaskComments({ taskId, start: startupCommentStartMs, limit: CLICKUP_WEBHOOK_STARTUP_COMMENT_LIMIT });
|
|
11553
11690
|
for (const comment of clickUpCommentListItems(commentsResponse).slice(0, CLICKUP_WEBHOOK_STARTUP_COMMENT_LIMIT)) {
|
|
11554
11691
|
const commentMs = clickUpCommentUpdatedMs(comment);
|
|
11555
|
-
if (!commentMs || commentMs <=
|
|
11692
|
+
if (!commentMs || commentMs <= startupCommentStartMs) continue;
|
|
11556
11693
|
const authorId = clickUpCommentAuthorId(comment);
|
|
11557
11694
|
if (authorId && (authorId === config.routing.ignoredCommentAuthorId || authorId === authorizedUserId)) continue;
|
|
11558
11695
|
if (!clickUpCommentMentionsProductManager(comment, config.routing)) continue;
|
|
@@ -11579,11 +11716,11 @@ async function reconcileClickUpStartup({ config, state = {}, worktree = process.
|
|
|
11579
11716
|
await applyClickUpBlockerTag({ clickupClient, worktree, taskId, reason: "startup_reconciliation_comments_failed", source: "startup_reconciliation_comments" });
|
|
11580
11717
|
}
|
|
11581
11718
|
}
|
|
11582
|
-
const emptyPromptSessions = routed.tasks.filter((task) => task.delivered === false && task.sessionId);
|
|
11719
|
+
const emptyPromptSessions = routed.tasks.filter((task) => task.delivered === false && task.sessionId && task.verification !== "session_running");
|
|
11583
11720
|
if (emptyPromptSessions.length > 0) {
|
|
11584
11721
|
appendClickUpWebhookLocalLog(worktree, { type: "startup_reconciliation_validation_failed", tasks: emptyPromptSessions });
|
|
11585
11722
|
}
|
|
11586
|
-
clickUpWebhookLifecycleLog(worktree, { type: "startup_reconciliation_finished", ...routed });
|
|
11723
|
+
clickUpWebhookLifecycleLog(worktree, { type: watchdogMode ? "assignment_watchdog_finished" : "startup_reconciliation_finished", ...routed });
|
|
11587
11724
|
return { ok: routed.errors === 0 && routed.undelivered === 0, ...routed, validation: { undelivered: routed.undelivered, emptyPromptSessions } };
|
|
11588
11725
|
}
|
|
11589
11726
|
function clickUpWebhookExpectedPath(config) {
|
|
@@ -11778,17 +11915,17 @@ function startClickUpWebhookListener({ config, state, worktree, clickupClient, o
|
|
|
11778
11915
|
return result;
|
|
11779
11916
|
}
|
|
11780
11917
|
function legacyVariantPath(destinationPath) {
|
|
11781
|
-
const parsed =
|
|
11918
|
+
const parsed = path6.parse(destinationPath);
|
|
11782
11919
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:TZ.]/g, "").slice(0, 14);
|
|
11783
|
-
if (parsed.ext) return
|
|
11784
|
-
return
|
|
11920
|
+
if (parsed.ext) return path6.join(parsed.dir, `${parsed.name}.legacy-${stamp}${parsed.ext}`);
|
|
11921
|
+
return path6.join(parsed.dir, `${parsed.base}.legacy-${stamp}`);
|
|
11785
11922
|
}
|
|
11786
11923
|
function normalizeWorkflowTaskPath(taskPath) {
|
|
11787
11924
|
if (typeof taskPath !== "string") return { ok: false, message: "Error: task_path is required." };
|
|
11788
11925
|
const trimmed = taskPath.trim();
|
|
11789
11926
|
if (!trimmed) return { ok: false, message: "Error: task_path is required." };
|
|
11790
11927
|
const normalized = trimmed.replace(/\\/g, "/");
|
|
11791
|
-
if (
|
|
11928
|
+
if (path6.isAbsolute(trimmed)) return { ok: true, taskPath: trimmed };
|
|
11792
11929
|
if (normalized === "tasks" || normalized.startsWith("tasks/")) {
|
|
11793
11930
|
return {
|
|
11794
11931
|
ok: false,
|
|
@@ -11807,12 +11944,12 @@ function mergeFileIntoDestination(sourcePath, destinationPath, relativeSource, g
|
|
|
11807
11944
|
const sourceWasTracked = isGitTracked(gitState, sourcePath);
|
|
11808
11945
|
if (gitAwareMoveIfTracked(sourcePath, destinationPath, gitState)) return;
|
|
11809
11946
|
if (!fs5.existsSync(destinationPath)) {
|
|
11810
|
-
fs5.mkdirSync(
|
|
11947
|
+
fs5.mkdirSync(path6.dirname(destinationPath), { recursive: true });
|
|
11811
11948
|
fs5.renameSync(sourcePath, destinationPath);
|
|
11812
11949
|
if (sourceWasTracked) stageGitAwareMerge(sourcePath, destinationPath, gitState);
|
|
11813
11950
|
return;
|
|
11814
11951
|
}
|
|
11815
|
-
const ext =
|
|
11952
|
+
const ext = path6.extname(destinationPath).toLowerCase();
|
|
11816
11953
|
if ([".yaml", ".yml", ".json"].includes(ext)) {
|
|
11817
11954
|
const sourceRaw = fs5.readFileSync(sourcePath, "utf8");
|
|
11818
11955
|
const destRaw = fs5.readFileSync(destinationPath, "utf8");
|
|
@@ -11847,14 +11984,14 @@ ${sourceRaw}
|
|
|
11847
11984
|
fs5.renameSync(sourcePath, preservedPath);
|
|
11848
11985
|
stageGitAwareMerge(sourcePath, preservedPath, gitState);
|
|
11849
11986
|
}
|
|
11850
|
-
function mergePathIntoDestination(sourcePath, destinationPath, relativeSource =
|
|
11987
|
+
function mergePathIntoDestination(sourcePath, destinationPath, relativeSource = path6.basename(sourcePath), gitState = null) {
|
|
11851
11988
|
if (!fs5.existsSync(sourcePath)) return;
|
|
11852
11989
|
const stat = fs5.statSync(sourcePath);
|
|
11853
11990
|
if (stat.isDirectory()) {
|
|
11854
11991
|
const sourceWasTracked = isGitTracked(gitState, sourcePath) || hasGitTrackedChildren(gitState, sourcePath);
|
|
11855
11992
|
if (gitAwareMoveIfTracked(sourcePath, destinationPath, gitState)) return;
|
|
11856
11993
|
if (!fs5.existsSync(destinationPath)) {
|
|
11857
|
-
fs5.mkdirSync(
|
|
11994
|
+
fs5.mkdirSync(path6.dirname(destinationPath), { recursive: true });
|
|
11858
11995
|
fs5.renameSync(sourcePath, destinationPath);
|
|
11859
11996
|
if (sourceWasTracked) stageGitAwareMerge(sourcePath, destinationPath, gitState);
|
|
11860
11997
|
return;
|
|
@@ -11862,9 +11999,9 @@ function mergePathIntoDestination(sourcePath, destinationPath, relativeSource =
|
|
|
11862
11999
|
fs5.mkdirSync(destinationPath, { recursive: true });
|
|
11863
12000
|
for (const entry of fs5.readdirSync(sourcePath)) {
|
|
11864
12001
|
mergePathIntoDestination(
|
|
11865
|
-
|
|
11866
|
-
|
|
11867
|
-
|
|
12002
|
+
path6.join(sourcePath, entry),
|
|
12003
|
+
path6.join(destinationPath, entry),
|
|
12004
|
+
path6.join(relativeSource, entry),
|
|
11868
12005
|
gitState
|
|
11869
12006
|
);
|
|
11870
12007
|
}
|
|
@@ -11874,7 +12011,7 @@ function mergePathIntoDestination(sourcePath, destinationPath, relativeSource =
|
|
|
11874
12011
|
mergeFileIntoDestination(sourcePath, destinationPath, relativeSource, gitState);
|
|
11875
12012
|
}
|
|
11876
12013
|
function isOptimaPluginPackageWorktree(worktree) {
|
|
11877
|
-
const packageJsonPath =
|
|
12014
|
+
const packageJsonPath = path6.join(worktree, "package.json");
|
|
11878
12015
|
if (!fs5.existsSync(packageJsonPath)) return false;
|
|
11879
12016
|
try {
|
|
11880
12017
|
const pkg = JSON.parse(fs5.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -11886,51 +12023,51 @@ function isOptimaPluginPackageWorktree(worktree) {
|
|
|
11886
12023
|
function migrateLegacyOptimaLayout(worktree) {
|
|
11887
12024
|
const gitState = gitMigrationState(worktree);
|
|
11888
12025
|
const migrations = [
|
|
11889
|
-
[
|
|
11890
|
-
[
|
|
11891
|
-
[
|
|
11892
|
-
[
|
|
11893
|
-
[
|
|
11894
|
-
[
|
|
12026
|
+
[path6.join(legacyOrbitaDir(worktree), "orbita.yaml"), repoConfigPath(worktree), path6.join(".orbita", "orbita.yaml")],
|
|
12027
|
+
[path6.join(legacyOrbitaDir(worktree), "staticeng.yaml"), repoConfigPath(worktree), path6.join(".orbita", "staticeng.yaml")],
|
|
12028
|
+
[path6.join(legacyOrbitaDir(worktree), ".config"), optimaLocalConfigDir(worktree), path6.join(".orbita", ".config")],
|
|
12029
|
+
[path6.join(legacyOrbitaDir(worktree), "config"), optimaLocalConfigDir(worktree), path6.join(".orbita", "config")],
|
|
12030
|
+
[path6.join(legacyOrbitaDir(worktree), "runtime"), path6.join(optimaLocalConfigDir(worktree), "runtime"), path6.join(".orbita", "runtime")],
|
|
12031
|
+
[path6.join(legacyOrbitaDir(worktree), "generated"), path6.join(optimaLocalConfigDir(worktree), "generated"), path6.join(".orbita", "generated")],
|
|
11895
12032
|
[legacyOrbitaDir(worktree), optimaDir(worktree), ".orbita"],
|
|
11896
|
-
[
|
|
11897
|
-
[
|
|
11898
|
-
[
|
|
11899
|
-
[
|
|
11900
|
-
[
|
|
11901
|
-
[
|
|
12033
|
+
[path6.join(legacyStaticEngDir(worktree), "staticeng.yaml"), repoConfigPath(worktree), path6.join(".staticeng", "staticeng.yaml")],
|
|
12034
|
+
[path6.join(legacyStaticEngDir(worktree), "orbita.yaml"), repoConfigPath(worktree), path6.join(".staticeng", "orbita.yaml")],
|
|
12035
|
+
[path6.join(legacyStaticEngDir(worktree), ".config"), optimaLocalConfigDir(worktree), path6.join(".staticeng", ".config")],
|
|
12036
|
+
[path6.join(legacyStaticEngDir(worktree), "config"), optimaLocalConfigDir(worktree), path6.join(".staticeng", "config")],
|
|
12037
|
+
[path6.join(legacyStaticEngDir(worktree), "runtime"), path6.join(optimaLocalConfigDir(worktree), "runtime"), path6.join(".staticeng", "runtime")],
|
|
12038
|
+
[path6.join(legacyStaticEngDir(worktree), "generated"), path6.join(optimaLocalConfigDir(worktree), "generated"), path6.join(".staticeng", "generated")],
|
|
11902
12039
|
[legacyStaticEngDir(worktree), optimaDir(worktree), ".staticeng"],
|
|
11903
|
-
[
|
|
11904
|
-
[
|
|
11905
|
-
[
|
|
11906
|
-
[
|
|
11907
|
-
[
|
|
11908
|
-
[
|
|
11909
|
-
[
|
|
11910
|
-
[
|
|
11911
|
-
[
|
|
11912
|
-
[
|
|
11913
|
-
[
|
|
11914
|
-
[
|
|
12040
|
+
[path6.join(legacyNomadworkDir(worktree), "nomadworks.yaml"), repoConfigPath(worktree), path6.join(".nomadwork", "nomadworks.yaml")],
|
|
12041
|
+
[path6.join(legacyNomadworksDir(worktree), "nomadworks.yaml"), repoConfigPath(worktree), path6.join(".nomadworks", "nomadworks.yaml")],
|
|
12042
|
+
[path6.join(legacyNomadworkDir(worktree), "staticeng.yaml"), repoConfigPath(worktree), path6.join(".nomadwork", "staticeng.yaml")],
|
|
12043
|
+
[path6.join(legacyNomadworksDir(worktree), "staticeng.yaml"), repoConfigPath(worktree), path6.join(".nomadworks", "staticeng.yaml")],
|
|
12044
|
+
[path6.join(legacyNomadworkDir(worktree), "orbita.yaml"), repoConfigPath(worktree), path6.join(".nomadwork", "orbita.yaml")],
|
|
12045
|
+
[path6.join(legacyNomadworksDir(worktree), "orbita.yaml"), repoConfigPath(worktree), path6.join(".nomadworks", "orbita.yaml")],
|
|
12046
|
+
[path6.join(legacyNomadworkDir(worktree), "runtime"), path6.join(optimaLocalConfigDir(worktree), "runtime"), path6.join(".nomadwork", "runtime")],
|
|
12047
|
+
[path6.join(legacyNomadworksDir(worktree), "runtime"), path6.join(optimaLocalConfigDir(worktree), "runtime"), path6.join(".nomadworks", "runtime")],
|
|
12048
|
+
[path6.join(legacyNomadworkDir(worktree), "generated"), path6.join(optimaLocalConfigDir(worktree), "generated"), path6.join(".nomadwork", "generated")],
|
|
12049
|
+
[path6.join(legacyNomadworksDir(worktree), "generated"), path6.join(optimaLocalConfigDir(worktree), "generated"), path6.join(".nomadworks", "generated")],
|
|
12050
|
+
[path6.join(legacyNomadworkDir(worktree), "config"), optimaLocalConfigDir(worktree), path6.join(".nomadwork", "config")],
|
|
12051
|
+
[path6.join(legacyNomadworksDir(worktree), "config"), optimaLocalConfigDir(worktree), path6.join(".nomadworks", "config")],
|
|
11915
12052
|
[legacyNomadworkDir(worktree), optimaDir(worktree), ".nomadwork"],
|
|
11916
12053
|
[legacyNomadworksDir(worktree), optimaDir(worktree), ".nomadworks"],
|
|
11917
|
-
[
|
|
11918
|
-
[
|
|
11919
|
-
[
|
|
11920
|
-
[
|
|
11921
|
-
[
|
|
12054
|
+
[path6.join(worktree, "tasks"), optimaTasksDir(worktree), "tasks"],
|
|
12055
|
+
[path6.join(worktree, "evidences"), optimaEvidencesDir(worktree), "evidences"],
|
|
12056
|
+
[path6.join(worktree, "docs", "scrs"), optimaScrsDir(worktree), path6.join("docs", "scrs")],
|
|
12057
|
+
[path6.join(worktree, "codemap.yml"), optimaCodemapPath(worktree), "codemap.yml"],
|
|
12058
|
+
[path6.join(worktree, "codemap.yaml"), optimaCodemapPath(worktree), "codemap.yaml"]
|
|
11922
12059
|
];
|
|
11923
12060
|
if (!isOptimaPluginPackageWorktree(worktree)) {
|
|
11924
|
-
migrations.push([
|
|
12061
|
+
migrations.push([path6.join(worktree, "policies"), repoPoliciesDir(worktree), "policies"]);
|
|
11925
12062
|
}
|
|
11926
12063
|
for (const [source, destination, relativeSource] of migrations) {
|
|
11927
12064
|
if (fs5.existsSync(source)) mergePathIntoDestination(source, destination, relativeSource, gitState);
|
|
11928
12065
|
}
|
|
11929
12066
|
for (const [source, destination, relativeSource] of [
|
|
11930
|
-
[
|
|
11931
|
-
[
|
|
11932
|
-
[
|
|
11933
|
-
[
|
|
12067
|
+
[path6.join(optimaDir(worktree), "optima.yaml"), repoConfigPath(worktree), path6.join(".optima", "optima.yaml")],
|
|
12068
|
+
[path6.join(optimaDir(worktree), "config"), optimaLocalConfigDir(worktree), path6.join(".optima", "config")],
|
|
12069
|
+
[path6.join(optimaDir(worktree), "runtime"), path6.join(optimaLocalConfigDir(worktree), "runtime"), path6.join(".optima", "runtime")],
|
|
12070
|
+
[path6.join(optimaDir(worktree), "generated"), path6.join(optimaLocalConfigDir(worktree), "generated"), path6.join(".optima", "generated")]
|
|
11934
12071
|
]) {
|
|
11935
12072
|
if (fs5.existsSync(source)) mergePathIntoDestination(source, destination, relativeSource, gitState);
|
|
11936
12073
|
}
|
|
@@ -11979,7 +12116,7 @@ function toModelString(provider, model) {
|
|
|
11979
12116
|
}
|
|
11980
12117
|
function readTaskMetadata(taskPath, worktree) {
|
|
11981
12118
|
if (!taskPath) return {};
|
|
11982
|
-
const absoluteTaskPath =
|
|
12119
|
+
const absoluteTaskPath = path6.isAbsolute(taskPath) ? taskPath : path6.join(worktree, taskPath);
|
|
11983
12120
|
if (!fs5.existsSync(absoluteTaskPath)) return {};
|
|
11984
12121
|
try {
|
|
11985
12122
|
const raw = fs5.readFileSync(absoluteTaskPath, "utf8");
|
|
@@ -12024,18 +12161,18 @@ function loadDiscussionRegistry(worktree) {
|
|
|
12024
12161
|
}
|
|
12025
12162
|
function saveDiscussionRegistry(worktree, registry) {
|
|
12026
12163
|
const registryPath = runtimeDiscussionRegistryPath(worktree);
|
|
12027
|
-
const runtimeDir =
|
|
12164
|
+
const runtimeDir = path6.dirname(registryPath);
|
|
12028
12165
|
if (!fs5.existsSync(runtimeDir)) fs5.mkdirSync(runtimeDir, { recursive: true });
|
|
12029
12166
|
fs5.writeFileSync(registryPath, JSON.stringify(registry, null, 2), "utf8");
|
|
12030
12167
|
}
|
|
12031
12168
|
function runtimeDiscussionsDir(worktree) {
|
|
12032
|
-
return
|
|
12169
|
+
return path6.join(optimaLocalConfigDir(worktree), "runtime", "discussions");
|
|
12033
12170
|
}
|
|
12034
12171
|
function archivedRuntimeDiscussionsDir(worktree) {
|
|
12035
|
-
return
|
|
12172
|
+
return path6.join(runtimeDiscussionsDir(worktree), "archive");
|
|
12036
12173
|
}
|
|
12037
12174
|
function finalDiscussionsDir(worktree) {
|
|
12038
|
-
return
|
|
12175
|
+
return path6.join(optimaTasksDir(worktree), "discussions");
|
|
12039
12176
|
}
|
|
12040
12177
|
function nextDiscussionIdentity(worktree, title) {
|
|
12041
12178
|
const discussionsDir = finalDiscussionsDir(worktree);
|
|
@@ -12046,11 +12183,11 @@ function nextDiscussionIdentity(worktree, title) {
|
|
|
12046
12183
|
while (true) {
|
|
12047
12184
|
const id = `DISCUSSION-${String(sequence).padStart(3, "0")}`;
|
|
12048
12185
|
const filename = `${id}-${slugifyTitle(title)}.md`;
|
|
12049
|
-
const summaryRelativePath =
|
|
12050
|
-
const summaryAbsolutePath =
|
|
12186
|
+
const summaryRelativePath = path6.join(".optima", "tasks", "discussions", filename);
|
|
12187
|
+
const summaryAbsolutePath = path6.join(worktree, summaryRelativePath);
|
|
12051
12188
|
const transcriptFilename = `${id}-transcript.md`;
|
|
12052
|
-
const transcriptRelativePath =
|
|
12053
|
-
const transcriptAbsolutePath =
|
|
12189
|
+
const transcriptRelativePath = path6.join(".optima", ".config", "runtime", "discussions", transcriptFilename);
|
|
12190
|
+
const transcriptAbsolutePath = path6.join(worktree, transcriptRelativePath);
|
|
12054
12191
|
if (!fs5.existsSync(summaryAbsolutePath) && !fs5.existsSync(transcriptAbsolutePath)) {
|
|
12055
12192
|
return {
|
|
12056
12193
|
id,
|
|
@@ -12075,11 +12212,11 @@ function findDiscussionById(worktree, discussionID) {
|
|
|
12075
12212
|
return {
|
|
12076
12213
|
id: discussionID,
|
|
12077
12214
|
filename,
|
|
12078
|
-
summaryRelativePath:
|
|
12079
|
-
summaryAbsolutePath:
|
|
12215
|
+
summaryRelativePath: path6.join(".optima", "tasks", "discussions", filename),
|
|
12216
|
+
summaryAbsolutePath: path6.join(discussionsDir, filename),
|
|
12080
12217
|
transcriptFilename,
|
|
12081
|
-
transcriptRelativePath:
|
|
12082
|
-
transcriptAbsolutePath:
|
|
12218
|
+
transcriptRelativePath: path6.join(".optima", ".config", "runtime", "discussions", transcriptFilename),
|
|
12219
|
+
transcriptAbsolutePath: path6.join(runtimeDiscussionsDir(worktree), transcriptFilename)
|
|
12083
12220
|
};
|
|
12084
12221
|
}
|
|
12085
12222
|
function parseDiscussionFile(filePath) {
|
|
@@ -12162,15 +12299,15 @@ async function appendMessageIfNeeded(client, worktree, registry, sessionID, mess
|
|
|
12162
12299
|
});
|
|
12163
12300
|
const text = extractTextParts(response.data.parts || []);
|
|
12164
12301
|
if (!text) return;
|
|
12165
|
-
appendDiscussionMessage(
|
|
12302
|
+
appendDiscussionMessage(path6.join(worktree, discussion.transcriptPath), speaker, text, messageID);
|
|
12166
12303
|
discussion.appendedMessageIDs ??= [];
|
|
12167
12304
|
discussion.appendedMessageIDs.push(messageID);
|
|
12168
12305
|
saveDiscussionRegistry(worktree, registry);
|
|
12169
12306
|
}
|
|
12170
12307
|
async function summarizeDiscussionWithBA(client, worktree, discussion) {
|
|
12171
|
-
const transcriptPath =
|
|
12172
|
-
const summaryPath =
|
|
12173
|
-
const summaryDir =
|
|
12308
|
+
const transcriptPath = path6.join(worktree, discussion.transcriptPath);
|
|
12309
|
+
const summaryPath = path6.join(worktree, discussion.summaryPath);
|
|
12310
|
+
const summaryDir = path6.dirname(summaryPath);
|
|
12174
12311
|
if (!fs5.existsSync(summaryDir)) fs5.mkdirSync(summaryDir, { recursive: true });
|
|
12175
12312
|
const hasExistingSummary = fs5.existsSync(summaryPath);
|
|
12176
12313
|
const priorMtimeMs = hasExistingSummary ? fs5.statSync(summaryPath).mtimeMs : null;
|
|
@@ -12273,11 +12410,11 @@ async function summarizeDiscussionWithBA(client, worktree, discussion) {
|
|
|
12273
12410
|
return { confirmation, summaryPath, transcriptPath, hasExistingSummary, priorMtimeMs };
|
|
12274
12411
|
}
|
|
12275
12412
|
function archiveDiscussionTranscript(worktree, transcriptRelativePath) {
|
|
12276
|
-
const sourcePath =
|
|
12413
|
+
const sourcePath = path6.join(worktree, transcriptRelativePath);
|
|
12277
12414
|
if (!fs5.existsSync(sourcePath)) return null;
|
|
12278
12415
|
const archiveDir = archivedRuntimeDiscussionsDir(worktree);
|
|
12279
12416
|
if (!fs5.existsSync(archiveDir)) fs5.mkdirSync(archiveDir, { recursive: true });
|
|
12280
|
-
const targetPath =
|
|
12417
|
+
const targetPath = path6.join(archiveDir, path6.basename(sourcePath));
|
|
12281
12418
|
fs5.renameSync(sourcePath, targetPath);
|
|
12282
12419
|
return targetPath;
|
|
12283
12420
|
}
|
|
@@ -12296,7 +12433,7 @@ async function finalizeClosingDiscussion(client, worktree, registry, sessionID,
|
|
|
12296
12433
|
if (!summaryContent) {
|
|
12297
12434
|
throw new Error(`Discussion summary file is empty at ${discussion.summaryPath}`);
|
|
12298
12435
|
}
|
|
12299
|
-
const transcriptPath =
|
|
12436
|
+
const transcriptPath = path6.join(worktree, discussion.transcriptPath);
|
|
12300
12437
|
setDiscussionStatus(transcriptPath, "closed");
|
|
12301
12438
|
const archivedTranscriptPath = archiveDiscussionTranscript(worktree, discussion.transcriptPath);
|
|
12302
12439
|
delete registry.active[sessionID];
|
|
@@ -12304,7 +12441,7 @@ async function finalizeClosingDiscussion(client, worktree, registry, sessionID,
|
|
|
12304
12441
|
return {
|
|
12305
12442
|
confirmation,
|
|
12306
12443
|
summaryPath: discussion.summaryPath,
|
|
12307
|
-
archivedTranscriptPath: archivedTranscriptPath ?
|
|
12444
|
+
archivedTranscriptPath: archivedTranscriptPath ? path6.relative(worktree, archivedTranscriptPath) : path6.join(".optima", ".config", "runtime", "discussions", "archive", path6.basename(discussion.transcriptPath))
|
|
12308
12445
|
};
|
|
12309
12446
|
}
|
|
12310
12447
|
function normalizeTeamMode(value) {
|
|
@@ -12376,7 +12513,7 @@ function syncGeneratedPolicies(worktree, repoCfg) {
|
|
|
12376
12513
|
if (!fs5.existsSync(generatedDir)) fs5.mkdirSync(generatedDir, { recursive: true });
|
|
12377
12514
|
const policyFiles = fs5.readdirSync(BUNDLE_POLICIES_DIR).filter((file) => file.endsWith(".md") && file !== "README.md");
|
|
12378
12515
|
for (const file of policyFiles) {
|
|
12379
|
-
const sourcePath =
|
|
12516
|
+
const sourcePath = path6.join(BUNDLE_POLICIES_DIR, file);
|
|
12380
12517
|
const source = fs5.readFileSync(sourcePath, "utf8").trimEnd();
|
|
12381
12518
|
const generated = [
|
|
12382
12519
|
"<!--",
|
|
@@ -12388,18 +12525,18 @@ function syncGeneratedPolicies(worktree, repoCfg) {
|
|
|
12388
12525
|
source,
|
|
12389
12526
|
""
|
|
12390
12527
|
].join("\n");
|
|
12391
|
-
fs5.writeFileSync(
|
|
12528
|
+
fs5.writeFileSync(path6.join(generatedDir, file), generated, "utf8");
|
|
12392
12529
|
}
|
|
12393
12530
|
}
|
|
12394
12531
|
function ensureReadmeFile(dirPath, content) {
|
|
12395
12532
|
if (!fs5.existsSync(dirPath)) fs5.mkdirSync(dirPath, { recursive: true });
|
|
12396
|
-
const readmePath =
|
|
12533
|
+
const readmePath = path6.join(dirPath, "README.md");
|
|
12397
12534
|
if (!fs5.existsSync(readmePath)) {
|
|
12398
12535
|
fs5.writeFileSync(readmePath, content, "utf8");
|
|
12399
12536
|
}
|
|
12400
12537
|
}
|
|
12401
12538
|
function ensureFileIfMissing(filePath, content) {
|
|
12402
|
-
if (!fs5.existsSync(
|
|
12539
|
+
if (!fs5.existsSync(path6.dirname(filePath))) fs5.mkdirSync(path6.dirname(filePath), { recursive: true });
|
|
12403
12540
|
if (!fs5.existsSync(filePath)) fs5.writeFileSync(filePath, content, "utf8");
|
|
12404
12541
|
}
|
|
12405
12542
|
function currentTasksRegistryContent() {
|
|
@@ -12486,13 +12623,13 @@ Never place implementation evidence under root \`evidences/\`.
|
|
|
12486
12623
|
}
|
|
12487
12624
|
function ensureOptimaTaskTemplates(worktree) {
|
|
12488
12625
|
const tasksDir = optimaTasksDir(worktree);
|
|
12489
|
-
ensureFileIfMissing(
|
|
12490
|
-
ensureFileIfMissing(
|
|
12626
|
+
ensureFileIfMissing(path6.join(tasksDir, "task-template.md"), taskTemplateContent());
|
|
12627
|
+
ensureFileIfMissing(path6.join(tasksDir, "subtask-template.md"), subtaskTemplateContent());
|
|
12491
12628
|
}
|
|
12492
12629
|
function scaffoldOptimaConfig(worktree, teamMode = "full") {
|
|
12493
12630
|
const configPath = repoConfigPath(worktree);
|
|
12494
12631
|
if (fs5.existsSync(configPath)) return false;
|
|
12495
|
-
const templatePath =
|
|
12632
|
+
const templatePath = path6.join(TEMPLATES_DIR, "optima.yaml.template");
|
|
12496
12633
|
if (!fs5.existsSync(templatePath)) return false;
|
|
12497
12634
|
const agentIds = fs5.existsSync(BUNDLE_AGENTS_DIR) ? fs5.readdirSync(BUNDLE_AGENTS_DIR).filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", "")) : [];
|
|
12498
12635
|
let optimaConfig = fs5.readFileSync(templatePath, "utf8");
|
|
@@ -12511,9 +12648,9 @@ function scaffoldOptimaConfig(worktree, teamMode = "full") {
|
|
|
12511
12648
|
function scaffoldOptimaRootCodemap(worktree) {
|
|
12512
12649
|
const rootCodemapPath = optimaCodemapPath(worktree);
|
|
12513
12650
|
if (fs5.existsSync(rootCodemapPath)) return false;
|
|
12514
|
-
const templatePath =
|
|
12651
|
+
const templatePath = path6.join(TEMPLATES_DIR, "codemap.yml.template");
|
|
12515
12652
|
if (!fs5.existsSync(templatePath)) return false;
|
|
12516
|
-
const codemapConfig = fs5.readFileSync(templatePath, "utf8").replace("{{projectName}}",
|
|
12653
|
+
const codemapConfig = fs5.readFileSync(templatePath, "utf8").replace("{{projectName}}", path6.basename(worktree));
|
|
12517
12654
|
ensureFileIfMissing(rootCodemapPath, codemapConfig);
|
|
12518
12655
|
return fs5.existsSync(rootCodemapPath);
|
|
12519
12656
|
}
|
|
@@ -12522,10 +12659,10 @@ function ensureOptimaRegistries(worktree) {
|
|
|
12522
12659
|
const scrsDir = optimaScrsDir(worktree);
|
|
12523
12660
|
if (!fs5.existsSync(tasksDir)) fs5.mkdirSync(tasksDir, { recursive: true });
|
|
12524
12661
|
if (!fs5.existsSync(scrsDir)) fs5.mkdirSync(scrsDir, { recursive: true });
|
|
12525
|
-
ensureFileIfMissing(
|
|
12526
|
-
ensureFileIfMissing(
|
|
12527
|
-
ensureFileIfMissing(
|
|
12528
|
-
ensureFileIfMissing(
|
|
12662
|
+
ensureFileIfMissing(path6.join(tasksDir, "current.md"), currentTasksRegistryContent());
|
|
12663
|
+
ensureFileIfMissing(path6.join(tasksDir, "done.md"), doneTasksRegistryContent());
|
|
12664
|
+
ensureFileIfMissing(path6.join(scrsDir, "current.md"), currentScrRegistryContent());
|
|
12665
|
+
ensureFileIfMissing(path6.join(scrsDir, "done.md"), doneScrRegistryContent());
|
|
12529
12666
|
}
|
|
12530
12667
|
function scaffoldOptimaReadmes(worktree) {
|
|
12531
12668
|
ensureReadmeFile(repoPoliciesDir(worktree), REPO_LOCAL_POLICIES_README);
|
|
@@ -12687,12 +12824,12 @@ function shouldRegisterWorkflowProductManager(options = {}, worktree = process.c
|
|
|
12687
12824
|
}
|
|
12688
12825
|
function isClickUpDerivedWorktreeSibling(candidate, basePath) {
|
|
12689
12826
|
if (typeof candidate !== "string" || typeof basePath !== "string" || !candidate.trim() || !basePath.trim()) return false;
|
|
12690
|
-
const resolvedCandidate =
|
|
12691
|
-
const resolvedBase =
|
|
12692
|
-
const baseParent =
|
|
12693
|
-
if (
|
|
12694
|
-
const baseName =
|
|
12695
|
-
const candidateName =
|
|
12827
|
+
const resolvedCandidate = path6.resolve(candidate);
|
|
12828
|
+
const resolvedBase = path6.resolve(basePath);
|
|
12829
|
+
const baseParent = path6.dirname(resolvedBase);
|
|
12830
|
+
if (path6.dirname(resolvedCandidate) !== baseParent) return false;
|
|
12831
|
+
const baseName = path6.basename(resolvedBase);
|
|
12832
|
+
const candidateName = path6.basename(resolvedCandidate);
|
|
12696
12833
|
if (!candidateName.startsWith(`${baseName}-`)) return false;
|
|
12697
12834
|
const branchSlug = candidateName.slice(baseName.length + 1);
|
|
12698
12835
|
const parts = branchSlug.split("-").filter(Boolean);
|
|
@@ -12704,7 +12841,7 @@ function isClickUpDerivedWorktreeSibling(candidate, basePath) {
|
|
|
12704
12841
|
if (!candidateStat.isDirectory() || candidateStat.isSymbolicLink()) return false;
|
|
12705
12842
|
const realCandidate = fs5.realpathSync.native(resolvedCandidate);
|
|
12706
12843
|
const realBaseParent = fs5.realpathSync.native(baseParent);
|
|
12707
|
-
return
|
|
12844
|
+
return path6.dirname(realCandidate) === realBaseParent && path6.basename(realCandidate) === candidateName;
|
|
12708
12845
|
} catch {
|
|
12709
12846
|
return false;
|
|
12710
12847
|
}
|
|
@@ -12712,15 +12849,15 @@ function isClickUpDerivedWorktreeSibling(candidate, basePath) {
|
|
|
12712
12849
|
function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktree, clickUpWebhookValidation } = {}) {
|
|
12713
12850
|
const safe = safeWorktreeOrFailure(context, pluginWorktree);
|
|
12714
12851
|
if (!safe.ok) return { ok: false, error: safe.message };
|
|
12715
|
-
const requested = String(requestedDirectory || "").trim() ?
|
|
12852
|
+
const requested = String(requestedDirectory || "").trim() ? path6.resolve(safe.worktree, String(requestedDirectory).trim()) : safe.worktree;
|
|
12716
12853
|
if (!isSafeWritableDirectory(requested)) return { ok: false, error: `Directory is not a safe writable directory: ${requested}` };
|
|
12717
12854
|
if (isSameOrNestedPath(requested, safe.worktree)) return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "context_worktree" };
|
|
12718
12855
|
const clickUpBasePath = clickUpWebhookValidation?.complete === true && clickUpWebhookValidation?.ok !== false ? clickUpWebhookValidation.config?.basePath : "";
|
|
12719
12856
|
if (clickUpBasePath && isSameOrNestedPath(requested, clickUpBasePath)) {
|
|
12720
|
-
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath:
|
|
12857
|
+
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path6.resolve(clickUpBasePath) };
|
|
12721
12858
|
}
|
|
12722
12859
|
if (clickUpBasePath && isClickUpDerivedWorktreeSibling(requested, clickUpBasePath)) {
|
|
12723
|
-
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_derived_worktree", clickupBasePath:
|
|
12860
|
+
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_derived_worktree", clickupBasePath: path6.resolve(clickUpBasePath) };
|
|
12724
12861
|
}
|
|
12725
12862
|
return {
|
|
12726
12863
|
ok: false,
|
|
@@ -12754,8 +12891,8 @@ function buildOptimaAgents(repoCfg, operatingTeamMode, worktree, debugDir, optio
|
|
|
12754
12891
|
if (!enabled) continue;
|
|
12755
12892
|
}
|
|
12756
12893
|
const promptOptions = { preferCompactPromptDocs: repoCfg.features?.compact_prompt_docs !== false };
|
|
12757
|
-
const bundledDefinition = loadAgentDefinition(
|
|
12758
|
-
const repoDefinition = loadAgentDefinition(
|
|
12894
|
+
const bundledDefinition = loadAgentDefinition(path6.join(BUNDLE_AGENTS_DIR, file), worktree, promptOptions);
|
|
12895
|
+
const repoDefinition = loadAgentDefinition(path6.join(repoAgentDefinitions, file), worktree, promptOptions) || loadAgentDefinition(path6.join(legacyAgentsDir, file), worktree, promptOptions);
|
|
12759
12896
|
const activeDefinition = repoDefinition || bundledDefinition;
|
|
12760
12897
|
if (!activeDefinition) continue;
|
|
12761
12898
|
const { data } = activeDefinition;
|
|
@@ -12764,7 +12901,7 @@ function buildOptimaAgents(repoCfg, operatingTeamMode, worktree, debugDir, optio
|
|
|
12764
12901
|
if (modePromptFragment) finalPrompt = `${finalPrompt}
|
|
12765
12902
|
|
|
12766
12903
|
${modePromptFragment}`;
|
|
12767
|
-
const additionFragment = loadMarkdownFragment(
|
|
12904
|
+
const additionFragment = loadMarkdownFragment(path6.join(repoAgentAdditions, file), worktree);
|
|
12768
12905
|
if (additionFragment) {
|
|
12769
12906
|
finalPrompt = `${finalPrompt}
|
|
12770
12907
|
|
|
@@ -12817,7 +12954,7 @@ Use this Optima-provided fallback when the current task worktree lacks docs/core
|
|
|
12817
12954
|
}
|
|
12818
12955
|
ourAgents[id] = agentConfig;
|
|
12819
12956
|
if (repoCfg.features?.debug_dumps !== false) {
|
|
12820
|
-
const debugPath =
|
|
12957
|
+
const debugPath = path6.join(debugDir, `${id}.md`);
|
|
12821
12958
|
const { prompt, ...dumpConfig } = agentConfig;
|
|
12822
12959
|
const debugHeader = `---
|
|
12823
12960
|
${import_yaml3.default.stringify(dumpConfig).trim()}
|
|
@@ -12897,7 +13034,17 @@ async function OptimaPlugin(input = {}, pluginOptions = {}) {
|
|
|
12897
13034
|
...listenerState,
|
|
12898
13035
|
listener: { bindHost: clickUpWebhookValidation.config.webhook.bindHost, bindPort: clickUpWebhookValidation.config.webhook.bindPort, startedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
12899
13036
|
}, clickUpWebhookValidation.config);
|
|
12900
|
-
|
|
13037
|
+
const assignmentWatchdog = scheduleClickUpAssignmentWatchdog({
|
|
13038
|
+
config: clickUpWebhookValidation.config,
|
|
13039
|
+
state: activeState,
|
|
13040
|
+
worktree,
|
|
13041
|
+
clickupClient: lifecycleClickUpClient,
|
|
13042
|
+
openCodeClient: input.client,
|
|
13043
|
+
scheduler: input.assignmentWatchdogScheduler,
|
|
13044
|
+
intervalMs: input.assignmentWatchdogIntervalMs,
|
|
13045
|
+
saveState: (nextState) => writeClickUpWebhookState(worktree, nextState, clickUpWebhookValidation.config)
|
|
13046
|
+
});
|
|
13047
|
+
registerClickUpWebhookLifecycle({ config: clickUpWebhookValidation.config, state: activeState, worktree, clickupClient: lifecycleClickUpClient, listener: readyListener, listenerRegistry, assignmentWatchdog });
|
|
12901
13048
|
scheduleClickUpStartupReconciliation({
|
|
12902
13049
|
config: clickUpWebhookValidation.config,
|
|
12903
13050
|
state: activeState,
|
|
@@ -12959,8 +13106,8 @@ async function OptimaPlugin(input = {}, pluginOptions = {}) {
|
|
|
12959
13106
|
migrateLegacyOptimaLayout(toolWorktree);
|
|
12960
13107
|
const cfgDir = optimaConfigDir(toolWorktree);
|
|
12961
13108
|
if (!fs5.existsSync(cfgDir)) fs5.mkdirSync(cfgDir, { recursive: true });
|
|
12962
|
-
const optimaTmplPath =
|
|
12963
|
-
const codemapTmplPath =
|
|
13109
|
+
const optimaTmplPath = path6.join(TEMPLATES_DIR, "optima.yaml.template");
|
|
13110
|
+
const codemapTmplPath = path6.join(TEMPLATES_DIR, "codemap.yml.template");
|
|
12964
13111
|
if (!fs5.existsSync(optimaTmplPath) || !fs5.existsSync(codemapTmplPath)) {
|
|
12965
13112
|
return "Error: Initialization templates not found in plugin.";
|
|
12966
13113
|
}
|
|
@@ -13082,14 +13229,14 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
|
|
|
13082
13229
|
async execute(args, context) {
|
|
13083
13230
|
const safe = safeWorktreeOrFailure(context, worktree);
|
|
13084
13231
|
if (!safe.ok) return safe.message;
|
|
13085
|
-
const summaryPath =
|
|
13232
|
+
const summaryPath = path6.resolve(safe.worktree, args.summary_path || "");
|
|
13086
13233
|
if (!fs5.existsSync(summaryPath)) return `FAIL: summary_path not found: ${summaryPath}`;
|
|
13087
|
-
const taskPath = args.task_path ?
|
|
13234
|
+
const taskPath = args.task_path ? path6.resolve(safe.worktree, args.task_path) : "";
|
|
13088
13235
|
const payload = buildClickUpSummaryPayload({
|
|
13089
13236
|
summaryMarkdown: fs5.readFileSync(summaryPath, "utf8"),
|
|
13090
|
-
summaryPath:
|
|
13237
|
+
summaryPath: path6.relative(safe.worktree, summaryPath),
|
|
13091
13238
|
taskMarkdown: taskPath && fs5.existsSync(taskPath) ? fs5.readFileSync(taskPath, "utf8") : "",
|
|
13092
|
-
taskPath: taskPath ?
|
|
13239
|
+
taskPath: taskPath ? path6.relative(safe.worktree, taskPath) : "",
|
|
13093
13240
|
branch: args.branch,
|
|
13094
13241
|
worktree: args.worktree,
|
|
13095
13242
|
pr: args.pr
|
|
@@ -13168,12 +13315,12 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
|
|
|
13168
13315
|
async execute(args, context) {
|
|
13169
13316
|
const safe = safeWorktreeOrFailure(context, worktree);
|
|
13170
13317
|
if (!safe.ok) return safe.message;
|
|
13171
|
-
const markdownPath =
|
|
13318
|
+
const markdownPath = path6.resolve(safe.worktree, args.markdown_path || "");
|
|
13172
13319
|
if (!fs5.existsSync(markdownPath)) return `FAIL: markdown_path not found: ${markdownPath}`;
|
|
13173
13320
|
const payload = buildClickUpCreateSubtasksPayload({
|
|
13174
13321
|
parentTaskId: args.parent_task_id,
|
|
13175
13322
|
markdown: fs5.readFileSync(markdownPath, "utf8"),
|
|
13176
|
-
sourcePath:
|
|
13323
|
+
sourcePath: path6.relative(safe.worktree, markdownPath),
|
|
13177
13324
|
parentBranch: args.parent_branch,
|
|
13178
13325
|
parentTaskType: args.parent_task_type || "Tarea",
|
|
13179
13326
|
apply: String(args.apply || "").toLowerCase() === "true"
|
|
@@ -13372,7 +13519,7 @@ Backfilled messages: ${backfilled}`;
|
|
|
13372
13519
|
if (!existing) {
|
|
13373
13520
|
return "FAIL: No active discussion exists for this session.";
|
|
13374
13521
|
}
|
|
13375
|
-
const discussionPath =
|
|
13522
|
+
const discussionPath = path6.join(toolWorktree, existing.transcriptPath);
|
|
13376
13523
|
setDiscussionStatus(discussionPath, "summarizing");
|
|
13377
13524
|
existing.status = "summarizing";
|
|
13378
13525
|
saveDiscussionRegistry(toolWorktree, toolRegistry);
|
|
@@ -13424,7 +13571,7 @@ Reason: ${err.message}`;
|
|
|
13424
13571
|
try {
|
|
13425
13572
|
const sessionResult = await client.session.create({
|
|
13426
13573
|
query: { directory: workflowDirectory },
|
|
13427
|
-
body: { title: `Workflow Run: ${
|
|
13574
|
+
body: { title: `Workflow Run: ${path6.basename(workflowTaskPath)}` }
|
|
13428
13575
|
});
|
|
13429
13576
|
const sessionId = sessionResult.data.id;
|
|
13430
13577
|
activeWorkflows.set(sessionId, { pmaSessionId, taskPath: workflowTaskPath, track: workflowTrack, directory: workflowDirectory });
|
|
@@ -13553,7 +13700,7 @@ Follow-up: use optima_prompt_workflow with session_id '${sessionId}' to check in
|
|
|
13553
13700
|
}
|
|
13554
13701
|
};
|
|
13555
13702
|
}
|
|
13556
|
-
OptimaPlugin.__internals = { BUNDLE_AGENTS_DIR, BUNDLE_ASSETS_DIR, CLICKUP_DEFINITION_DOC_PARENT, activeClickUpWebhookLifecycleRegistry, cleanupManagedClickUpWebhook, deleteClickUpWebhookBestEffort, BUNDLE_POLICIES_DIR, buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentLedgerKey, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, compactPromptPath, createClickUpApiClient, createTestClickUpApiClient, createOpenCodeSession, createOpenCodeSessionControl, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpTaskWorktreeForWebhook, ensureClickUpTaskWorktreeOpenChamber, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, isClickUpDerivedWorktreeSibling, isClickUpSubtaskRoute, isClickUpWebhookStateActive, isSameOrNestedPath, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, openCodeSessionExists, promptOpenCodeSessionControl, probeOpenCodeSessionControl, readClickUpCommentLedger, readClickUpWebhookState, readOpenCodeSessionControl, readOpenCodeSessionMessages, reconcileClickUpStartup, registerOpenChamberClickUpWorktree, scheduleClickUpStartupReconciliation, syncOpenChamberWorktreeVisibility, waitForOpenCodeReadiness, recordClickUpCommentVersionProcessed, resyncClickUpWebhookForSignatureDrift, resolveIncludeFile, resolveIncludes, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, summarizeOpenCodeMessages, verifyOpenCodeSessionEventDelivery, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatRepairResult, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, optimaRepairDependencies, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, planOptimaRepair, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
|
|
13703
|
+
OptimaPlugin.__internals = { BUNDLE_AGENTS_DIR, BUNDLE_ASSETS_DIR, CLICKUP_DEFINITION_DOC_PARENT, activeClickUpWebhookLifecycleRegistry, cleanupManagedClickUpWebhook, deleteClickUpWebhookBestEffort, BUNDLE_POLICIES_DIR, buildClickUpApplyPayloadResult, buildClickUpCreateSubtasksPayload, buildClickUpStartTaskPayload, buildClickUpSummaryPayload, buildClickUpTransitionPayload, buildOptimaAgents, clickUpCommentLedgerKey, clickUpCommentMentionsProductManager, clickUpWebhookAuditLogDir, clickUpWebhookAuditLogPath, compactPromptPath, createClickUpApiClient, createTestClickUpApiClient, createOpenCodeSession, createOpenCodeSessionControl, deliveryEvidencePathForClickUpTask, ensureClickUpTaskWorktree, ensureClickUpTaskWorktreeForWebhook, ensureClickUpTaskWorktreeOpenChamber, ensureClickUpWebhookSubscription, handleClickUpWebhookRequest, inspectOpenCodeSessionActivity, isClickUpDerivedWorktreeSibling, isClickUpSubtaskRoute, isClickUpWebhookStateActive, isSameOrNestedPath, normalizeClickUpWebhookConfig, normalizeClickUpWebhookLogLevel, normalizeOpenCodeBaseUrl, openCodeSessionExists, promptOpenCodeSessionControl, probeOpenCodeSessionControl, readClickUpCommentLedger, readClickUpWebhookState, readOpenCodeSessionControl, readOpenCodeSessionMessages, reconcileClickUpStartup, registerOpenChamberClickUpWorktree, scheduleClickUpAssignmentWatchdog, scheduleClickUpStartupReconciliation, syncOpenChamberWorktreeVisibility, waitForOpenCodeReadiness, recordClickUpCommentVersionProcessed, resyncClickUpWebhookForSignatureDrift, resolveIncludeFile, resolveIncludes, resolveOptimaPluginOptions, resolveSecretReference, routeClickUpWebhookEvent, sendOpenCodeSessionEvent, sendOpenCodeSessionEventDirect, summarizeOpenCodeMessages, verifyOpenCodeSessionEventDelivery, stableClickUpCommentVersionMarker, startClickUpWebhookListener, validateClickUpWebhookState, verifyClickUpSignature, writeClickUpWebhookState, decideClickUpStatusAction, deriveClickUpBranchName, deriveClickUpPendingSubtaskBranch, deriveClickUpPrTarget, deriveClickUpWorktree, determineClickUpMergeAuthority, ensureOptimaGitignoreRules, explicitSafeInputWorktree, finalApprovalAssignees, formatRepairResult, formatValidationResult, isIgnoredClickUpTaskType, isOptimaPluginPackageWorktree, isSafeWritableDirectory, loadHumansRegistry, mergeClickUpAgentMetadata, mergeClickUpSessionMetadata, migrateLegacyOptimaLayout, normalizeAgentMetadataJson, normalizeClickUpStatus, normalizeClickUpTaskType, normalizePromptResponseParts, normalizeWorkflowTaskPath, optimaRepairDependencies, parseClickUpSubtasksMarkdown, parseHumansRegistry, parseMarkdownArtifact, parseMarkdownSections, planOptimaRepair, preEstimateClickUpWork, readMarkdownArtifact, resolveHumanRoles, resolveSafeWorktree, safeWorktreeOrFailure, stripRawLogSections, validateMainWorkspaceBranchSafety, workflowFinalMessageFromPromptResponse };
|
|
13557
13704
|
export {
|
|
13558
13705
|
OptimaPlugin as default
|
|
13559
13706
|
};
|