@defend-tech/opencode-optima 0.1.84 → 0.1.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +529 -253
- package/dist/sanitize_cli.js +562 -286
- 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, path22) {
|
|
112
|
+
const ctrl = callVisitor(key, node, visitor, path22);
|
|
113
113
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
114
|
-
replaceNode(key,
|
|
115
|
-
return visit_(key, ctrl, visitor,
|
|
114
|
+
replaceNode(key, path22, ctrl);
|
|
115
|
+
return visit_(key, ctrl, visitor, path22);
|
|
116
116
|
}
|
|
117
117
|
if (typeof ctrl !== "symbol") {
|
|
118
118
|
if (identity.isCollection(node)) {
|
|
119
|
-
|
|
119
|
+
path22 = Object.freeze(path22.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, path22);
|
|
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
|
+
path22 = Object.freeze(path22.concat(node));
|
|
133
|
+
const ck = visit_("key", node.key, visitor, path22);
|
|
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, path22);
|
|
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, path22) {
|
|
160
|
+
const ctrl = await callVisitor(key, node, visitor, path22);
|
|
161
161
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
162
|
-
replaceNode(key,
|
|
163
|
-
return visitAsync_(key, ctrl, visitor,
|
|
162
|
+
replaceNode(key, path22, ctrl);
|
|
163
|
+
return visitAsync_(key, ctrl, visitor, path22);
|
|
164
164
|
}
|
|
165
165
|
if (typeof ctrl !== "symbol") {
|
|
166
166
|
if (identity.isCollection(node)) {
|
|
167
|
-
|
|
167
|
+
path22 = Object.freeze(path22.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, path22);
|
|
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
|
+
path22 = Object.freeze(path22.concat(node));
|
|
181
|
+
const ck = await visitAsync_("key", node.key, visitor, path22);
|
|
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, path22);
|
|
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, path22) {
|
|
214
214
|
if (typeof visitor === "function")
|
|
215
|
-
return visitor(key, node,
|
|
215
|
+
return visitor(key, node, path22);
|
|
216
216
|
if (identity.isMap(node))
|
|
217
|
-
return visitor.Map?.(key, node,
|
|
217
|
+
return visitor.Map?.(key, node, path22);
|
|
218
218
|
if (identity.isSeq(node))
|
|
219
|
-
return visitor.Seq?.(key, node,
|
|
219
|
+
return visitor.Seq?.(key, node, path22);
|
|
220
220
|
if (identity.isPair(node))
|
|
221
|
-
return visitor.Pair?.(key, node,
|
|
221
|
+
return visitor.Pair?.(key, node, path22);
|
|
222
222
|
if (identity.isScalar(node))
|
|
223
|
-
return visitor.Scalar?.(key, node,
|
|
223
|
+
return visitor.Scalar?.(key, node, path22);
|
|
224
224
|
if (identity.isAlias(node))
|
|
225
|
-
return visitor.Alias?.(key, node,
|
|
225
|
+
return visitor.Alias?.(key, node, path22);
|
|
226
226
|
return void 0;
|
|
227
227
|
}
|
|
228
|
-
function replaceNode(key,
|
|
229
|
-
const parent =
|
|
228
|
+
function replaceNode(key, path22, node) {
|
|
229
|
+
const parent = path22[path22.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, path22, value) {
|
|
838
838
|
let v = value;
|
|
839
|
-
for (let i =
|
|
840
|
-
const k =
|
|
839
|
+
for (let i = path22.length - 1; i >= 0; --i) {
|
|
840
|
+
const k = path22[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 = (path22) => path22 == null || typeof path22 === "object" && !!path22[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(path22, value) {
|
|
890
|
+
if (isEmptyPath(path22))
|
|
891
891
|
this.add(value);
|
|
892
892
|
else {
|
|
893
|
-
const [key, ...rest] =
|
|
893
|
+
const [key, ...rest] = path22;
|
|
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(path22) {
|
|
908
|
+
const [key, ...rest] = path22;
|
|
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(path22, keepScalar) {
|
|
923
|
+
const [key, ...rest] = path22;
|
|
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(path22) {
|
|
942
|
+
const [key, ...rest] = path22;
|
|
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(path22, value) {
|
|
953
|
+
const [key, ...rest] = path22;
|
|
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(path22, value) {
|
|
3458
3458
|
if (assertCollection(this.contents))
|
|
3459
|
-
this.contents.addIn(
|
|
3459
|
+
this.contents.addIn(path22, 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(path22) {
|
|
3535
|
+
if (Collection.isEmptyPath(path22)) {
|
|
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(path22) : 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(path22, keepScalar) {
|
|
3557
|
+
if (Collection.isEmptyPath(path22))
|
|
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(path22, 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(path22) {
|
|
3571
|
+
if (Collection.isEmptyPath(path22))
|
|
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(path22) : 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(path22, value) {
|
|
3591
|
+
if (Collection.isEmptyPath(path22)) {
|
|
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(path22), value);
|
|
3595
3595
|
} else if (assertCollection(this.contents)) {
|
|
3596
|
-
this.contents.setIn(
|
|
3596
|
+
this.contents.setIn(path22, 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, path22) => {
|
|
5549
5549
|
let item = cst;
|
|
5550
|
-
for (const [field, index] of
|
|
5550
|
+
for (const [field, index] of path22) {
|
|
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, path22) => {
|
|
5560
|
+
const parent = visit.itemAtPath(cst, path22.slice(0, -1));
|
|
5561
|
+
const field = path22[path22.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(path22, item, visitor) {
|
|
5568
|
+
let ctrl = visitor(item, path22);
|
|
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(path22.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, path22);
|
|
5587
5587
|
}
|
|
5588
5588
|
}
|
|
5589
|
-
return typeof ctrl === "function" ? ctrl(item,
|
|
5589
|
+
return typeof ctrl === "function" ? ctrl(item, path22) : ctrl;
|
|
5590
5590
|
}
|
|
5591
5591
|
exports.visit = visit;
|
|
5592
5592
|
}
|
|
@@ -6871,14 +6871,14 @@ var require_parser = __commonJS({
|
|
|
6871
6871
|
case "scalar":
|
|
6872
6872
|
case "single-quoted-scalar":
|
|
6873
6873
|
case "double-quoted-scalar": {
|
|
6874
|
-
const
|
|
6874
|
+
const fs21 = this.flowScalar(this.type);
|
|
6875
6875
|
if (atNextItem || it.value) {
|
|
6876
|
-
map.items.push({ start, key:
|
|
6876
|
+
map.items.push({ start, key: fs21, sep: [] });
|
|
6877
6877
|
this.onKeyLine = true;
|
|
6878
6878
|
} else if (it.sep) {
|
|
6879
|
-
this.stack.push(
|
|
6879
|
+
this.stack.push(fs21);
|
|
6880
6880
|
} else {
|
|
6881
|
-
Object.assign(it, { key:
|
|
6881
|
+
Object.assign(it, { key: fs21, sep: [] });
|
|
6882
6882
|
this.onKeyLine = true;
|
|
6883
6883
|
}
|
|
6884
6884
|
return;
|
|
@@ -7006,13 +7006,13 @@ var require_parser = __commonJS({
|
|
|
7006
7006
|
case "scalar":
|
|
7007
7007
|
case "single-quoted-scalar":
|
|
7008
7008
|
case "double-quoted-scalar": {
|
|
7009
|
-
const
|
|
7009
|
+
const fs21 = this.flowScalar(this.type);
|
|
7010
7010
|
if (!it || it.value)
|
|
7011
|
-
fc.items.push({ start: [], key:
|
|
7011
|
+
fc.items.push({ start: [], key: fs21, sep: [] });
|
|
7012
7012
|
else if (it.sep)
|
|
7013
|
-
this.stack.push(
|
|
7013
|
+
this.stack.push(fs21);
|
|
7014
7014
|
else
|
|
7015
|
-
Object.assign(it, { key:
|
|
7015
|
+
Object.assign(it, { key: fs21, sep: [] });
|
|
7016
7016
|
return;
|
|
7017
7017
|
}
|
|
7018
7018
|
case "flow-map-end":
|
|
@@ -7550,17 +7550,17 @@ var require_ignore = __commonJS({
|
|
|
7550
7550
|
var throwError = (message, Ctor) => {
|
|
7551
7551
|
throw new Ctor(message);
|
|
7552
7552
|
};
|
|
7553
|
-
var checkPath = (
|
|
7554
|
-
if (!isString(
|
|
7553
|
+
var checkPath = (path22, originalPath, doThrow) => {
|
|
7554
|
+
if (!isString(path22)) {
|
|
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 (!path22) {
|
|
7561
7561
|
return doThrow(`path must not be empty`, TypeError);
|
|
7562
7562
|
}
|
|
7563
|
-
if (checkPath.isNotRelative(
|
|
7563
|
+
if (checkPath.isNotRelative(path22)) {
|
|
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 = (path22) => REGEX_TEST_INVALID_PATH.test(path22);
|
|
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(path22, 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(path22);
|
|
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 path22 = originalPath && checkPath.convert(originalPath);
|
|
7653
7653
|
checkPath(
|
|
7654
|
-
|
|
7654
|
+
path22,
|
|
7655
7655
|
originalPath,
|
|
7656
7656
|
this._allowRelativePaths ? RETURN_FALSE : throwError
|
|
7657
7657
|
);
|
|
7658
|
-
return this._t(
|
|
7658
|
+
return this._t(path22, cache, checkUnignored, slices);
|
|
7659
7659
|
}
|
|
7660
|
-
_t(
|
|
7661
|
-
if (
|
|
7662
|
-
return cache[
|
|
7660
|
+
_t(path22, cache, checkUnignored, slices) {
|
|
7661
|
+
if (path22 in cache) {
|
|
7662
|
+
return cache[path22];
|
|
7663
7663
|
}
|
|
7664
7664
|
if (!slices) {
|
|
7665
|
-
slices =
|
|
7665
|
+
slices = path22.split(SLASH);
|
|
7666
7666
|
}
|
|
7667
7667
|
slices.pop();
|
|
7668
7668
|
if (!slices.length) {
|
|
7669
|
-
return cache[
|
|
7669
|
+
return cache[path22] = this._testOne(path22, 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[path22] = parent.ignored ? parent : this._testOne(path22, checkUnignored);
|
|
7678
7678
|
}
|
|
7679
|
-
ignores(
|
|
7680
|
-
return this._test(
|
|
7679
|
+
ignores(path22) {
|
|
7680
|
+
return this._test(path22, this._ignoreCache, false).ignored;
|
|
7681
7681
|
}
|
|
7682
7682
|
createFilter() {
|
|
7683
|
-
return (
|
|
7683
|
+
return (path22) => !this.ignores(path22);
|
|
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(path22) {
|
|
7690
|
+
return this._test(path22, this._testCache, true);
|
|
7691
7691
|
}
|
|
7692
7692
|
};
|
|
7693
7693
|
var factory = (options) => new Ignore(options);
|
|
7694
|
-
var isPathValid = (
|
|
7694
|
+
var isPathValid = (path22) => checkPath(path22 && checkPath.convert(path22), path22, RETURN_FALSE);
|
|
7695
7695
|
factory.isPathValid = isPathValid;
|
|
7696
7696
|
factory.default = factory;
|
|
7697
7697
|
module.exports = factory;
|
|
@@ -7702,16 +7702,16 @@ 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 = (path22) => REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path22) || isNotRelative(path22);
|
|
7706
7706
|
}
|
|
7707
7707
|
}
|
|
7708
7708
|
});
|
|
7709
7709
|
|
|
7710
7710
|
// src/plugin.js
|
|
7711
|
-
import
|
|
7711
|
+
import fs20 from "node:fs";
|
|
7712
7712
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
7713
7713
|
var import_ignore3 = __toESM(require_ignore(), 1);
|
|
7714
|
-
import
|
|
7714
|
+
import path21 from "node:path";
|
|
7715
7715
|
import { tool } from "@opencode-ai/plugin/tool";
|
|
7716
7716
|
|
|
7717
7717
|
// src/agents.js
|
|
@@ -13500,28 +13500,285 @@ function createGitHubApiClient(config = {}, fetchImpl = globalThis.fetch) {
|
|
|
13500
13500
|
}
|
|
13501
13501
|
|
|
13502
13502
|
// src/qa/chrome.js
|
|
13503
|
-
import
|
|
13503
|
+
import fs17 from "node:fs";
|
|
13504
13504
|
import os6 from "node:os";
|
|
13505
|
-
import
|
|
13505
|
+
import path18 from "node:path";
|
|
13506
13506
|
|
|
13507
|
-
// src/qa/
|
|
13507
|
+
// src/qa/cdp.js
|
|
13508
13508
|
import fs15 from "node:fs";
|
|
13509
|
-
import os5 from "node:os";
|
|
13510
13509
|
import path16 from "node:path";
|
|
13510
|
+
var DEFAULT_CDP_URL = "http://127.0.0.1:9222";
|
|
13511
|
+
function normalizeBaseUrl(cdpUrl = "") {
|
|
13512
|
+
return String(cdpUrl || process.env.OPTIMA_QA_CHROME_CDP_URL || DEFAULT_CDP_URL).trim().replace(/\/+$/, "");
|
|
13513
|
+
}
|
|
13514
|
+
async function cdpJson(baseUrl, route, options = {}) {
|
|
13515
|
+
const response = await fetch(`${baseUrl}${route}`, options);
|
|
13516
|
+
if (!response.ok) throw new Error(`cdp_http_${response.status}: ${route}`);
|
|
13517
|
+
return response.json();
|
|
13518
|
+
}
|
|
13519
|
+
async function listCdpTargets({ cdpUrl = "" } = {}) {
|
|
13520
|
+
const baseUrl = normalizeBaseUrl(cdpUrl);
|
|
13521
|
+
return cdpJson(baseUrl, "/json/list");
|
|
13522
|
+
}
|
|
13523
|
+
async function cdpBrowserStatus({ cdpUrl = "", clickupTaskId = "", qaWindowName: qaWindowName2 = null } = {}) {
|
|
13524
|
+
const targets = await listCdpTargets({ cdpUrl });
|
|
13525
|
+
const pages = [];
|
|
13526
|
+
for (let index = 0; index < targets.length; index += 1) {
|
|
13527
|
+
const target = targets[index];
|
|
13528
|
+
if (target.type !== "page") continue;
|
|
13529
|
+
let windowName = "";
|
|
13530
|
+
if (target.webSocketDebuggerUrl) {
|
|
13531
|
+
const session = await CdpSession.connect(target.webSocketDebuggerUrl).catch(() => null);
|
|
13532
|
+
if (session) {
|
|
13533
|
+
try {
|
|
13534
|
+
const evaluated = await session.evaluate("window.name || ''");
|
|
13535
|
+
windowName = String(evaluated?.value || "");
|
|
13536
|
+
} finally {
|
|
13537
|
+
session.close();
|
|
13538
|
+
}
|
|
13539
|
+
}
|
|
13540
|
+
}
|
|
13541
|
+
pages.push({
|
|
13542
|
+
index,
|
|
13543
|
+
id: target.id,
|
|
13544
|
+
role: index === 0 ? "persistent_session_tab" : qaWindowName2 && windowName === qaWindowName2(clickupTaskId) ? "qa_task_tab" : "other",
|
|
13545
|
+
url: target.url,
|
|
13546
|
+
title: target.title || "",
|
|
13547
|
+
windowName
|
|
13548
|
+
});
|
|
13549
|
+
}
|
|
13550
|
+
return { ok: true, pages, serviceWorkers: targets.filter((target) => target.type === "service_worker").map((target) => target.url) };
|
|
13551
|
+
}
|
|
13552
|
+
var CdpSession = class _CdpSession {
|
|
13553
|
+
constructor(ws) {
|
|
13554
|
+
this.ws = ws;
|
|
13555
|
+
this.nextId = 1;
|
|
13556
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
13557
|
+
this.ws.addEventListener("message", (event) => this.handleMessage(event));
|
|
13558
|
+
this.ws.addEventListener("close", () => this.rejectAll(new Error("cdp_websocket_closed")));
|
|
13559
|
+
this.ws.addEventListener("error", () => this.rejectAll(new Error("cdp_websocket_error")));
|
|
13560
|
+
}
|
|
13561
|
+
static connect(wsUrl, { timeoutMs = 1e4 } = {}) {
|
|
13562
|
+
return new Promise((resolve, reject) => {
|
|
13563
|
+
const ws = new WebSocket(wsUrl);
|
|
13564
|
+
const timer = setTimeout(() => {
|
|
13565
|
+
try {
|
|
13566
|
+
ws.close();
|
|
13567
|
+
} catch {
|
|
13568
|
+
}
|
|
13569
|
+
reject(new Error("cdp_websocket_connect_timeout"));
|
|
13570
|
+
}, timeoutMs);
|
|
13571
|
+
ws.addEventListener("open", () => {
|
|
13572
|
+
clearTimeout(timer);
|
|
13573
|
+
resolve(new _CdpSession(ws));
|
|
13574
|
+
}, { once: true });
|
|
13575
|
+
ws.addEventListener("error", () => {
|
|
13576
|
+
clearTimeout(timer);
|
|
13577
|
+
reject(new Error("cdp_websocket_connect_failed"));
|
|
13578
|
+
}, { once: true });
|
|
13579
|
+
});
|
|
13580
|
+
}
|
|
13581
|
+
handleMessage(event) {
|
|
13582
|
+
let message = null;
|
|
13583
|
+
try {
|
|
13584
|
+
message = JSON.parse(event.data);
|
|
13585
|
+
} catch {
|
|
13586
|
+
return;
|
|
13587
|
+
}
|
|
13588
|
+
if (!message?.id || !this.pending.has(message.id)) return;
|
|
13589
|
+
const pending = this.pending.get(message.id);
|
|
13590
|
+
this.pending.delete(message.id);
|
|
13591
|
+
clearTimeout(pending.timer);
|
|
13592
|
+
if (message.error) pending.reject(new Error(`${message.error.message || "cdp_error"}${message.error.data ? `: ${message.error.data}` : ""}`));
|
|
13593
|
+
else pending.resolve(message.result || {});
|
|
13594
|
+
}
|
|
13595
|
+
rejectAll(error) {
|
|
13596
|
+
for (const pending of this.pending.values()) {
|
|
13597
|
+
clearTimeout(pending.timer);
|
|
13598
|
+
pending.reject(error);
|
|
13599
|
+
}
|
|
13600
|
+
this.pending.clear();
|
|
13601
|
+
}
|
|
13602
|
+
send(method, params = {}, { timeoutMs = 3e4 } = {}) {
|
|
13603
|
+
const id = this.nextId;
|
|
13604
|
+
this.nextId += 1;
|
|
13605
|
+
return new Promise((resolve, reject) => {
|
|
13606
|
+
const timer = setTimeout(() => {
|
|
13607
|
+
this.pending.delete(id);
|
|
13608
|
+
reject(new Error(`cdp_command_timeout: ${method}`));
|
|
13609
|
+
}, timeoutMs);
|
|
13610
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
13611
|
+
this.ws.send(JSON.stringify({ id, method, params }));
|
|
13612
|
+
});
|
|
13613
|
+
}
|
|
13614
|
+
async evaluate(expression, { timeoutMs = 3e4 } = {}) {
|
|
13615
|
+
const result = await this.send("Runtime.evaluate", {
|
|
13616
|
+
expression,
|
|
13617
|
+
awaitPromise: true,
|
|
13618
|
+
returnByValue: true
|
|
13619
|
+
}, { timeoutMs });
|
|
13620
|
+
if (result.exceptionDetails) throw new Error(result.exceptionDetails.text || "runtime_evaluate_failed");
|
|
13621
|
+
return result.result || null;
|
|
13622
|
+
}
|
|
13623
|
+
close() {
|
|
13624
|
+
try {
|
|
13625
|
+
this.ws.close();
|
|
13626
|
+
} catch {
|
|
13627
|
+
}
|
|
13628
|
+
}
|
|
13629
|
+
};
|
|
13630
|
+
async function newCdpTarget({ cdpUrl = "", startUrl = "about:blank" } = {}) {
|
|
13631
|
+
const baseUrl = normalizeBaseUrl(cdpUrl);
|
|
13632
|
+
return cdpJson(baseUrl, `/json/new?${encodeURIComponent(startUrl)}`, { method: "PUT" });
|
|
13633
|
+
}
|
|
13634
|
+
async function targetWindowName(target) {
|
|
13635
|
+
if (!target.webSocketDebuggerUrl) return "";
|
|
13636
|
+
const session = await CdpSession.connect(target.webSocketDebuggerUrl);
|
|
13637
|
+
try {
|
|
13638
|
+
const value = await session.evaluate("window.name || ''");
|
|
13639
|
+
return String(value?.value || "");
|
|
13640
|
+
} finally {
|
|
13641
|
+
session.close();
|
|
13642
|
+
}
|
|
13643
|
+
}
|
|
13644
|
+
async function ensureCdpQaTarget({ cdpUrl = "", clickupTaskId = "", startUrl = "about:blank", qaWindowName: qaWindowName2 } = {}) {
|
|
13645
|
+
const expected = qaWindowName2(clickupTaskId);
|
|
13646
|
+
const targets = (await listCdpTargets({ cdpUrl })).filter((target2) => target2.type === "page");
|
|
13647
|
+
for (let index = 1; index < targets.length; index += 1) {
|
|
13648
|
+
if (await targetWindowName(targets[index]).catch(() => "") === expected) return targets[index];
|
|
13649
|
+
}
|
|
13650
|
+
const target = await newCdpTarget({ cdpUrl, startUrl });
|
|
13651
|
+
const session = await CdpSession.connect(target.webSocketDebuggerUrl);
|
|
13652
|
+
try {
|
|
13653
|
+
await session.evaluate(`window.name = ${JSON.stringify(expected)}`);
|
|
13654
|
+
} finally {
|
|
13655
|
+
session.close();
|
|
13656
|
+
}
|
|
13657
|
+
return target;
|
|
13658
|
+
}
|
|
13659
|
+
function parseCdpCommand(commandJson = "") {
|
|
13660
|
+
if (!String(commandJson || "").trim()) return { action: "status" };
|
|
13661
|
+
try {
|
|
13662
|
+
const parsed = JSON.parse(commandJson);
|
|
13663
|
+
return parsed && typeof parsed === "object" ? parsed : { action: "invalid" };
|
|
13664
|
+
} catch {
|
|
13665
|
+
return { action: "script", script: String(commandJson || "") };
|
|
13666
|
+
}
|
|
13667
|
+
}
|
|
13668
|
+
async function pageSnapshot(session) {
|
|
13669
|
+
const evaluated = await session.evaluate("({ url: location.href, title: document.title })");
|
|
13670
|
+
return evaluated?.value || { url: "", title: "" };
|
|
13671
|
+
}
|
|
13672
|
+
async function cdpRunChromeCommand({ cdpUrl = "", clickupTaskId = "", commandJson = "", startUrl = "about:blank", artifactsDir, qaWindowName: qaWindowName2 } = {}) {
|
|
13673
|
+
const command = parseCdpCommand(commandJson);
|
|
13674
|
+
const target = await ensureCdpQaTarget({ cdpUrl, clickupTaskId, startUrl, qaWindowName: qaWindowName2 });
|
|
13675
|
+
const session = await CdpSession.connect(target.webSocketDebuggerUrl);
|
|
13676
|
+
try {
|
|
13677
|
+
const action = String(command.action || "status").toLowerCase();
|
|
13678
|
+
let result = null;
|
|
13679
|
+
if (action === "status") {
|
|
13680
|
+
result = { ok: true, page: await pageSnapshot(session) };
|
|
13681
|
+
} else if (action === "goto") {
|
|
13682
|
+
await session.send("Page.enable");
|
|
13683
|
+
await session.send("Page.navigate", { url: String(command.url || startUrl || "about:blank") });
|
|
13684
|
+
if (command.wait_ms !== false) await new Promise((resolve) => setTimeout(resolve, Number(command.wait_ms || 1e3)));
|
|
13685
|
+
result = { ok: true, page: await pageSnapshot(session) };
|
|
13686
|
+
} else if (action === "evaluate") {
|
|
13687
|
+
const evaluated = await session.evaluate(String(command.expression || "undefined"), { timeoutMs: Number(command.timeout_ms || 3e4) });
|
|
13688
|
+
result = { ok: true, result: evaluated?.value ?? evaluated };
|
|
13689
|
+
} else if (action === "screenshot") {
|
|
13690
|
+
await session.send("Page.enable");
|
|
13691
|
+
const captured = await session.send("Page.captureScreenshot", { format: command.format || "png", captureBeyondViewport: command.full_page !== false });
|
|
13692
|
+
const name = String(command.name || `screenshot-${Date.now()}.png`).replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
13693
|
+
const outPath = path16.join(artifactsDir, name);
|
|
13694
|
+
fs15.mkdirSync(path16.dirname(outPath), { recursive: true });
|
|
13695
|
+
fs15.writeFileSync(outPath, Buffer.from(captured.data || "", "base64"));
|
|
13696
|
+
result = { ok: true, path: outPath };
|
|
13697
|
+
} else if (action === "script") {
|
|
13698
|
+
const script = String(command.script || "");
|
|
13699
|
+
if (!script.trim()) return { ok: false, error: "script_required" };
|
|
13700
|
+
const cdp = { send: (method, params = {}, options = {}) => session.send(method, params, options), evaluate: (expression, options = {}) => session.evaluate(expression, options) };
|
|
13701
|
+
const fn = new Function("cdp", "target", "artifactsDir", "command", `return (async () => {
|
|
13702
|
+
${script}
|
|
13703
|
+
})()`);
|
|
13704
|
+
result = { ok: true, result: await fn(cdp, target, artifactsDir, command) };
|
|
13705
|
+
} else {
|
|
13706
|
+
result = { ok: false, error: `unsupported_cdp_command_action: ${action}` };
|
|
13707
|
+
}
|
|
13708
|
+
return {
|
|
13709
|
+
ok: result.ok !== false,
|
|
13710
|
+
command: command.action || "script",
|
|
13711
|
+
tab: { windowName: qaWindowName2(clickupTaskId), ...await pageSnapshot(session) },
|
|
13712
|
+
artifactsDir,
|
|
13713
|
+
result,
|
|
13714
|
+
transport: "cdp"
|
|
13715
|
+
};
|
|
13716
|
+
} finally {
|
|
13717
|
+
session.close();
|
|
13718
|
+
}
|
|
13719
|
+
}
|
|
13720
|
+
async function cdpPrepareExtension({ cdpUrl = "", extensionId = "", reset = true, reload = true } = {}) {
|
|
13721
|
+
const targets = await listCdpTargets({ cdpUrl });
|
|
13722
|
+
const normalized = String(extensionId || "").trim();
|
|
13723
|
+
const worker = targets.find((target) => target.type === "service_worker" && (!normalized || String(target.url || "").startsWith(`chrome-extension://${normalized}/`)));
|
|
13724
|
+
if (!worker?.webSocketDebuggerUrl) return { ok: false, error: "extension_service_worker_not_found", serviceWorkers: targets.filter((target) => target.type === "service_worker").map((target) => target.url) };
|
|
13725
|
+
const session = await CdpSession.connect(worker.webSocketDebuggerUrl);
|
|
13726
|
+
try {
|
|
13727
|
+
let resetResult = { ok: true, skipped: true };
|
|
13728
|
+
let reloadResult = { ok: true, skipped: true };
|
|
13729
|
+
if (reset) {
|
|
13730
|
+
const evaluated = await session.evaluate(`(async () => {
|
|
13731
|
+
const deletedCaches = [];
|
|
13732
|
+
const deletedDbs = [];
|
|
13733
|
+
if (globalThis.chrome?.storage?.local) await chrome.storage.local.clear();
|
|
13734
|
+
if (globalThis.chrome?.storage?.session?.clear) await chrome.storage.session.clear();
|
|
13735
|
+
if (globalThis.chrome?.storage?.sync) await chrome.storage.sync.clear();
|
|
13736
|
+
if (globalThis.caches?.keys) {
|
|
13737
|
+
for (const name of await caches.keys()) {
|
|
13738
|
+
await caches.delete(name);
|
|
13739
|
+
deletedCaches.push(name);
|
|
13740
|
+
}
|
|
13741
|
+
}
|
|
13742
|
+
if (globalThis.indexedDB?.databases) {
|
|
13743
|
+
for (const db of await indexedDB.databases()) {
|
|
13744
|
+
if (db.name) {
|
|
13745
|
+
indexedDB.deleteDatabase(db.name);
|
|
13746
|
+
deletedDbs.push(db.name);
|
|
13747
|
+
}
|
|
13748
|
+
}
|
|
13749
|
+
}
|
|
13750
|
+
return { ok: true, deletedCaches, deletedDbs };
|
|
13751
|
+
})()`);
|
|
13752
|
+
resetResult = evaluated?.value || { ok: true };
|
|
13753
|
+
}
|
|
13754
|
+
if (reload) {
|
|
13755
|
+
await session.evaluate("chrome.runtime.reload()");
|
|
13756
|
+
reloadResult = { ok: true };
|
|
13757
|
+
}
|
|
13758
|
+
return { ok: true, reset: resetResult, reload: reloadResult };
|
|
13759
|
+
} finally {
|
|
13760
|
+
session.close();
|
|
13761
|
+
}
|
|
13762
|
+
}
|
|
13763
|
+
|
|
13764
|
+
// src/qa/queue.js
|
|
13765
|
+
import fs16 from "node:fs";
|
|
13766
|
+
import os5 from "node:os";
|
|
13767
|
+
import path17 from "node:path";
|
|
13511
13768
|
var DEFAULT_QA_LEASE_MS = 5 * 60 * 1e3;
|
|
13512
13769
|
var DEFAULT_QA_PROVIDER = "chatgpt";
|
|
13513
13770
|
function dataHome() {
|
|
13514
|
-
return process.env.XDG_DATA_HOME &&
|
|
13771
|
+
return process.env.XDG_DATA_HOME && path17.isAbsolute(process.env.XDG_DATA_HOME) ? process.env.XDG_DATA_HOME : path17.join(os5.homedir(), ".local", "share", "opencode");
|
|
13515
13772
|
}
|
|
13516
13773
|
function qaRuntimeDir() {
|
|
13517
|
-
return
|
|
13774
|
+
return path17.join(dataHome(), "opencode-optima", "qa");
|
|
13518
13775
|
}
|
|
13519
13776
|
function normalizeQaProvider(provider = DEFAULT_QA_PROVIDER) {
|
|
13520
13777
|
const normalized = String(provider || DEFAULT_QA_PROVIDER).trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-");
|
|
13521
13778
|
return normalized || DEFAULT_QA_PROVIDER;
|
|
13522
13779
|
}
|
|
13523
13780
|
function qaQueueStatePath(provider = DEFAULT_QA_PROVIDER) {
|
|
13524
|
-
return
|
|
13781
|
+
return path17.join(qaRuntimeDir(), `${normalizeQaProvider(provider)}-queue.json`);
|
|
13525
13782
|
}
|
|
13526
13783
|
function nowIso(now = /* @__PURE__ */ new Date()) {
|
|
13527
13784
|
return now instanceof Date ? now.toISOString() : new Date(now).toISOString();
|
|
@@ -13539,7 +13796,7 @@ function emptyQaQueueState(provider = DEFAULT_QA_PROVIDER) {
|
|
|
13539
13796
|
}
|
|
13540
13797
|
function readQaQueueState(provider = DEFAULT_QA_PROVIDER, statePath = qaQueueStatePath(provider)) {
|
|
13541
13798
|
try {
|
|
13542
|
-
const raw =
|
|
13799
|
+
const raw = fs16.readFileSync(statePath, "utf8");
|
|
13543
13800
|
const parsed = JSON.parse(raw);
|
|
13544
13801
|
if (!isPlainObject(parsed)) return emptyQaQueueState(provider);
|
|
13545
13802
|
return {
|
|
@@ -13561,8 +13818,8 @@ function writeQaQueueState(state, statePath = qaQueueStatePath(state?.provider))
|
|
|
13561
13818
|
queue: Array.isArray(state?.queue) ? state.queue.filter(isPlainObject) : [],
|
|
13562
13819
|
history: Array.isArray(state?.history) ? state.history.filter(isPlainObject).slice(-50) : []
|
|
13563
13820
|
};
|
|
13564
|
-
|
|
13565
|
-
|
|
13821
|
+
fs16.mkdirSync(path17.dirname(statePath), { recursive: true });
|
|
13822
|
+
fs16.writeFileSync(statePath, `${JSON.stringify(normalized, null, 2)}
|
|
13566
13823
|
`, { mode: 384 });
|
|
13567
13824
|
return normalized;
|
|
13568
13825
|
}
|
|
@@ -13669,14 +13926,15 @@ function finishQaSlot(state, { clickupTaskId, now = /* @__PURE__ */ new Date(),
|
|
|
13669
13926
|
|
|
13670
13927
|
// src/qa/chrome.js
|
|
13671
13928
|
var DEFAULT_QA_CDP_URL = "http://127.0.0.1:9222";
|
|
13929
|
+
var DEFAULT_QA_PLAYWRIGHT_CONNECT_TIMEOUT_MS = 5e3;
|
|
13672
13930
|
function providerDir(provider = DEFAULT_QA_PROVIDER) {
|
|
13673
|
-
return
|
|
13931
|
+
return path18.join(qaRuntimeDir(), normalizeQaProvider(provider));
|
|
13674
13932
|
}
|
|
13675
13933
|
function defaultQaExtensionStageDir(provider = DEFAULT_QA_PROVIDER) {
|
|
13676
|
-
return
|
|
13934
|
+
return path18.join(providerDir(provider), "extension-under-test");
|
|
13677
13935
|
}
|
|
13678
13936
|
function defaultQaArtifactsDir(provider = DEFAULT_QA_PROVIDER, clickupTaskId = "unknown") {
|
|
13679
|
-
return
|
|
13937
|
+
return path18.join(providerDir(provider), "artifacts", String(clickupTaskId || "unknown"));
|
|
13680
13938
|
}
|
|
13681
13939
|
function normalizeCdpUrl(value = "") {
|
|
13682
13940
|
return String(value || process.env.OPTIMA_QA_CHROME_CDP_URL || DEFAULT_QA_CDP_URL).trim() || DEFAULT_QA_CDP_URL;
|
|
@@ -13732,11 +13990,11 @@ async function ensureQaPage(context, { clickupTaskId, startUrl = "https://chatgp
|
|
|
13732
13990
|
function copyExtensionSource(sourcePath, stageDir) {
|
|
13733
13991
|
const source = String(sourcePath || "").trim();
|
|
13734
13992
|
if (!source) return { ok: true, skipped: true, reason: "extension_path_not_provided", stageDir };
|
|
13735
|
-
const resolved =
|
|
13736
|
-
if (!
|
|
13737
|
-
|
|
13738
|
-
|
|
13739
|
-
|
|
13993
|
+
const resolved = path18.resolve(source.replace(/^~(?=$|\/)/, os6.homedir()));
|
|
13994
|
+
if (!fs17.existsSync(resolved)) return { ok: false, error: `extension_path_not_found: ${resolved}`, stageDir };
|
|
13995
|
+
fs17.rmSync(stageDir, { recursive: true, force: true });
|
|
13996
|
+
fs17.mkdirSync(path18.dirname(stageDir), { recursive: true });
|
|
13997
|
+
fs17.cpSync(resolved, stageDir, {
|
|
13740
13998
|
recursive: true,
|
|
13741
13999
|
filter: (src) => !/[/\\](node_modules|\.git|dist|build|test-results)([/\\]|$)/.test(src)
|
|
13742
14000
|
});
|
|
@@ -13825,8 +14083,8 @@ async function runQaCommandOnPage(page, context, browser, command, { artifactsDi
|
|
|
13825
14083
|
}
|
|
13826
14084
|
if (action === "screenshot") {
|
|
13827
14085
|
const name = String(command.name || `screenshot-${Date.now()}.png`).replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
13828
|
-
const outPath =
|
|
13829
|
-
|
|
14086
|
+
const outPath = path18.join(artifactsDir, name);
|
|
14087
|
+
fs17.mkdirSync(path18.dirname(outPath), { recursive: true });
|
|
13830
14088
|
await page.screenshot({ path: outPath, fullPage: command.full_page !== false });
|
|
13831
14089
|
return { ok: true, path: outPath };
|
|
13832
14090
|
}
|
|
@@ -13848,7 +14106,9 @@ ${script}
|
|
|
13848
14106
|
}
|
|
13849
14107
|
async function withQaBrowser({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "", clickupTaskId = "", startUrl = "https://chatgpt.com/" } = {}, callback) {
|
|
13850
14108
|
const chromium = await loadPlaywrightChromium();
|
|
13851
|
-
const browser = await chromium.connectOverCDP(normalizeCdpUrl(cdpUrl)
|
|
14109
|
+
const browser = await chromium.connectOverCDP(normalizeCdpUrl(cdpUrl), {
|
|
14110
|
+
timeout: Number(process.env.OPTIMA_QA_PLAYWRIGHT_CONNECT_TIMEOUT_MS || DEFAULT_QA_PLAYWRIGHT_CONNECT_TIMEOUT_MS)
|
|
14111
|
+
});
|
|
13852
14112
|
try {
|
|
13853
14113
|
const context = browser.contexts()[0] || await browser.newContext();
|
|
13854
14114
|
const page = clickupTaskId ? await ensureQaPage(context, { clickupTaskId, startUrl }) : null;
|
|
@@ -13859,7 +14119,10 @@ async function withQaBrowser({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "", clic
|
|
|
13859
14119
|
}
|
|
13860
14120
|
}
|
|
13861
14121
|
async function qaBrowserStatus(options = {}) {
|
|
13862
|
-
return withQaBrowser(options, async ({ context }) => ({ ok: true, ...await summarizeBrowser(context, { clickupTaskId: options.clickupTaskId }) })).catch((error) =>
|
|
14122
|
+
return withQaBrowser(options, async ({ context }) => ({ ok: true, ...await summarizeBrowser(context, { clickupTaskId: options.clickupTaskId }) })).catch(async (error) => {
|
|
14123
|
+
const fallback = await cdpBrowserStatus({ cdpUrl: options.cdpUrl, clickupTaskId: options.clickupTaskId, qaWindowName }).catch((fallbackError) => ({ ok: false, error: fallbackError.message }));
|
|
14124
|
+
return fallback.ok ? { ...fallback, fallback: "cdp", playwrightError: error.message } : { ok: false, error: error.message, fallbackError: fallback.error, cdpUrl: normalizeCdpUrl(options.cdpUrl) };
|
|
14125
|
+
});
|
|
13863
14126
|
}
|
|
13864
14127
|
async function qaPrepareExtension({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "", extensionPath = "", extensionId = "", reset = true, reload = true } = {}) {
|
|
13865
14128
|
const stageDir = defaultQaExtensionStageDir(provider);
|
|
@@ -13868,7 +14131,10 @@ async function qaPrepareExtension({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "",
|
|
|
13868
14131
|
const resetResult = reset ? await resetExtensionState(context, { extensionId }).catch((error) => ({ ok: false, error: error.message })) : { ok: true, skipped: true };
|
|
13869
14132
|
const reloadResult = reload ? await reloadExtension(context, { extensionId }).catch((error) => ({ ok: false, error: error.message })) : { ok: true, skipped: true };
|
|
13870
14133
|
return { reset: resetResult, reload: reloadResult, browser: await summarizeBrowser(context) };
|
|
13871
|
-
}).catch((error) =>
|
|
14134
|
+
}).catch(async (error) => {
|
|
14135
|
+
const fallback = await cdpPrepareExtension({ cdpUrl, extensionId, reset, reload }).catch((fallbackError) => ({ ok: false, error: fallbackError.message }));
|
|
14136
|
+
return fallback.ok ? { ...fallback, fallback: "cdp", playwrightError: error.message } : { ok: false, error: error.message, fallbackError: fallback.error };
|
|
14137
|
+
});
|
|
13872
14138
|
return { sync, ...browserResult };
|
|
13873
14139
|
}
|
|
13874
14140
|
async function qaRunChromeCommand({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "", clickupTaskId = "", commandJson = "", startUrl = "https://chatgpt.com/" } = {}) {
|
|
@@ -13877,14 +14143,24 @@ async function qaRunChromeCommand({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "",
|
|
|
13877
14143
|
return withQaBrowser({ provider, cdpUrl, clickupTaskId, startUrl }, async ({ browser, context, page }) => {
|
|
13878
14144
|
const result = await runQaCommandOnPage(page, context, browser, command, { artifactsDir });
|
|
13879
14145
|
return { ok: result.ok !== false, command: command.action || "script", tab: { windowName: qaWindowName(clickupTaskId), url: page.url(), title: await page.title().catch(() => "") }, artifactsDir, result };
|
|
14146
|
+
}).catch(async (error) => {
|
|
14147
|
+
const fallback = await cdpRunChromeCommand({
|
|
14148
|
+
cdpUrl,
|
|
14149
|
+
clickupTaskId,
|
|
14150
|
+
commandJson,
|
|
14151
|
+
startUrl,
|
|
14152
|
+
artifactsDir,
|
|
14153
|
+
qaWindowName
|
|
14154
|
+
}).catch((fallbackError) => ({ ok: false, error: fallbackError.message }));
|
|
14155
|
+
return fallback.ok ? { ...fallback, fallback: "cdp", playwrightError: error.message } : { ok: false, error: error.message, fallbackError: fallback.error };
|
|
13880
14156
|
});
|
|
13881
14157
|
}
|
|
13882
14158
|
|
|
13883
14159
|
// src/repair.js
|
|
13884
14160
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
13885
14161
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
13886
|
-
import
|
|
13887
|
-
import
|
|
14162
|
+
import fs18 from "node:fs";
|
|
14163
|
+
import path19 from "node:path";
|
|
13888
14164
|
var CODEMAP_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
13889
14165
|
".js",
|
|
13890
14166
|
".ts",
|
|
@@ -13922,10 +14198,10 @@ var LEGACY_OPERATIONAL_ROOTS = /* @__PURE__ */ new Set([
|
|
|
13922
14198
|
]);
|
|
13923
14199
|
var OPTIMA_OPERATIONAL_FOLDERS = [".optima", "templates", "dist"];
|
|
13924
14200
|
function relPath(worktree, targetPath) {
|
|
13925
|
-
return
|
|
14201
|
+
return path19.relative(worktree, targetPath).split(path19.sep).join("/") || ".";
|
|
13926
14202
|
}
|
|
13927
14203
|
function normalizeCodemapRelPath(relPathValue) {
|
|
13928
|
-
return
|
|
14204
|
+
return path19.normalize(relPathValue).replace(/\\/g, "/").replace(/\/$/, "");
|
|
13929
14205
|
}
|
|
13930
14206
|
function firstPathSegment(relPathValue) {
|
|
13931
14207
|
return normalizeCodemapRelPath(relPathValue).split("/").filter(Boolean)[0] || "";
|
|
@@ -13944,8 +14220,8 @@ function isHiddenTree(relPathValue) {
|
|
|
13944
14220
|
function loadGitIgnoreMatcher(worktree) {
|
|
13945
14221
|
const ig = (0, import_ignore.default)();
|
|
13946
14222
|
ig.add(".git");
|
|
13947
|
-
const gitignorePath =
|
|
13948
|
-
if (
|
|
14223
|
+
const gitignorePath = path19.join(worktree, ".gitignore");
|
|
14224
|
+
if (fs18.existsSync(gitignorePath)) ig.add(fs18.readFileSync(gitignorePath, "utf8"));
|
|
13949
14225
|
return ig;
|
|
13950
14226
|
}
|
|
13951
14227
|
function codemapSectionEntries(value) {
|
|
@@ -13964,7 +14240,7 @@ function codemapIndexedPaths(map) {
|
|
|
13964
14240
|
}
|
|
13965
14241
|
function readCodemap(filePath, unresolved, worktree) {
|
|
13966
14242
|
try {
|
|
13967
|
-
const parsed = import_yaml4.default.parse(
|
|
14243
|
+
const parsed = import_yaml4.default.parse(fs18.readFileSync(filePath, "utf8"));
|
|
13968
14244
|
if (!parsed || typeof parsed !== "object") {
|
|
13969
14245
|
unresolved.push({ category: "codemap", path: relPath(worktree, filePath), message: "CodeMap is empty or invalid; manual repair required." });
|
|
13970
14246
|
return null;
|
|
@@ -13976,42 +14252,42 @@ function readCodemap(filePath, unresolved, worktree) {
|
|
|
13976
14252
|
}
|
|
13977
14253
|
}
|
|
13978
14254
|
function writeCodemap(filePath, map) {
|
|
13979
|
-
|
|
14255
|
+
fs18.writeFileSync(filePath, import_yaml4.default.stringify(map), "utf8");
|
|
13980
14256
|
}
|
|
13981
14257
|
function isIgnoredPath(ig, relativePath) {
|
|
13982
14258
|
const normalized = normalizeCodemapRelPath(relativePath);
|
|
13983
14259
|
return Boolean(normalized) && ig.ignores(normalized);
|
|
13984
14260
|
}
|
|
13985
14261
|
function hasImmediateSourceFile(dirPath, ig, worktree) {
|
|
13986
|
-
if (!
|
|
13987
|
-
for (const item of
|
|
13988
|
-
const childPath =
|
|
13989
|
-
const relative =
|
|
14262
|
+
if (!fs18.existsSync(dirPath)) return false;
|
|
14263
|
+
for (const item of fs18.readdirSync(dirPath, { withFileTypes: true })) {
|
|
14264
|
+
const childPath = path19.join(dirPath, item.name);
|
|
14265
|
+
const relative = path19.relative(worktree, childPath);
|
|
13990
14266
|
if (isIgnoredPath(ig, relative) || isOperationalRelPath(relative)) continue;
|
|
13991
|
-
if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(
|
|
14267
|
+
if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(path19.extname(item.name))) return true;
|
|
13992
14268
|
}
|
|
13993
14269
|
return false;
|
|
13994
14270
|
}
|
|
13995
14271
|
function containsSource(dirPath, ig, worktree) {
|
|
13996
|
-
if (!
|
|
13997
|
-
const dirRelPath =
|
|
14272
|
+
if (!fs18.existsSync(dirPath)) return false;
|
|
14273
|
+
const dirRelPath = path19.relative(worktree, dirPath);
|
|
13998
14274
|
if (isOperationalRelPath(dirRelPath) || isHiddenTree(dirRelPath)) return false;
|
|
13999
|
-
for (const item of
|
|
14000
|
-
const childPath =
|
|
14001
|
-
const relative =
|
|
14275
|
+
for (const item of fs18.readdirSync(dirPath, { withFileTypes: true })) {
|
|
14276
|
+
const childPath = path19.join(dirPath, item.name);
|
|
14277
|
+
const relative = path19.relative(worktree, childPath);
|
|
14002
14278
|
if (isIgnoredPath(ig, relative) || isOperationalRelPath(relative) || isHiddenTree(relative)) continue;
|
|
14003
|
-
if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(
|
|
14279
|
+
if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(path19.extname(item.name))) return true;
|
|
14004
14280
|
if (item.isDirectory() && containsSource(childPath, ig, worktree)) return true;
|
|
14005
14281
|
}
|
|
14006
14282
|
return false;
|
|
14007
14283
|
}
|
|
14008
14284
|
function createModuleCodemap(dirPath, worktree, deps) {
|
|
14009
|
-
const entries =
|
|
14285
|
+
const entries = fs18.readdirSync(dirPath, { withFileTypes: true });
|
|
14010
14286
|
const entrypoints = [];
|
|
14011
14287
|
const internals = [];
|
|
14012
|
-
const relToRoot =
|
|
14288
|
+
const relToRoot = path19.relative(dirPath, deps.optimaCodemapPath(worktree)).split(path19.sep).join("/");
|
|
14013
14289
|
for (const item of entries) {
|
|
14014
|
-
if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(
|
|
14290
|
+
if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(path19.extname(item.name))) continue;
|
|
14015
14291
|
const bucket = /^index\.(js|ts|tsx|jsx)$|^main\.(js|ts|tsx|jsx|py|go|rs|java)$/.test(item.name) ? entrypoints : internals;
|
|
14016
14292
|
bucket.push({ path: item.name });
|
|
14017
14293
|
}
|
|
@@ -14024,7 +14300,7 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
|
|
|
14024
14300
|
const map = readCodemap(codemapPath, unresolved, worktree);
|
|
14025
14301
|
if (!map) return;
|
|
14026
14302
|
const isRootMap = codemapPath === deps.optimaCodemapPath(worktree);
|
|
14027
|
-
const mapDir =
|
|
14303
|
+
const mapDir = path19.dirname(codemapPath);
|
|
14028
14304
|
const pathBase = isRootMap ? worktree : mapDir;
|
|
14029
14305
|
let changed = false;
|
|
14030
14306
|
for (const section of ["modules", "entrypoints", "sources_of_truth", "links", "internals"]) {
|
|
@@ -14035,13 +14311,13 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
|
|
|
14035
14311
|
}
|
|
14036
14312
|
const nextEntries = [];
|
|
14037
14313
|
for (const entry of originalEntries) {
|
|
14038
|
-
if (!entry?.path || entry.path.startsWith("http://") || entry.path.startsWith("https://") ||
|
|
14314
|
+
if (!entry?.path || entry.path.startsWith("http://") || entry.path.startsWith("https://") || path19.isAbsolute(entry.path)) {
|
|
14039
14315
|
nextEntries.push(entry);
|
|
14040
14316
|
continue;
|
|
14041
14317
|
}
|
|
14042
14318
|
const normalizedPath = normalizeCodemapRelPath(entry.path);
|
|
14043
|
-
const absPath =
|
|
14044
|
-
if (!
|
|
14319
|
+
const absPath = path19.join(pathBase, normalizedPath);
|
|
14320
|
+
if (!fs18.existsSync(absPath)) {
|
|
14045
14321
|
registerAction({ category: "codemap", action: apply ? "removed" : "would_remove", path: relPath(worktree, codemapPath), detail: `Remove broken ${section.slice(0, -1)} reference '${entry.path}'.` });
|
|
14046
14322
|
changed = true;
|
|
14047
14323
|
continue;
|
|
@@ -14050,8 +14326,8 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
|
|
|
14050
14326
|
const maxParts = isRootMap ? 2 : 1;
|
|
14051
14327
|
if (parts.length > maxParts) {
|
|
14052
14328
|
const localPath = isRootMap ? parts.slice(0, 2).join("/") : parts[0];
|
|
14053
|
-
const localAbs =
|
|
14054
|
-
if (
|
|
14329
|
+
const localAbs = path19.join(pathBase, localPath);
|
|
14330
|
+
if (fs18.existsSync(localAbs)) {
|
|
14055
14331
|
nextEntries.push({ ...entry, path: localPath });
|
|
14056
14332
|
changed = true;
|
|
14057
14333
|
registerAction({ category: "codemap", action: apply ? "updated" : "would_update", path: relPath(worktree, codemapPath), detail: `Shorten '${entry.path}' to local path '${localPath}'.` });
|
|
@@ -14065,11 +14341,11 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
|
|
|
14065
14341
|
}
|
|
14066
14342
|
if (Array.isArray(map[section])) map[section] = nextEntries;
|
|
14067
14343
|
}
|
|
14068
|
-
if (map.scope === "module" && !isOperationalRelPath(
|
|
14344
|
+
if (map.scope === "module" && !isOperationalRelPath(path19.relative(worktree, mapDir))) {
|
|
14069
14345
|
const indexed = codemapIndexedPaths(map);
|
|
14070
14346
|
const internals = Array.isArray(map.internals) ? map.internals : [];
|
|
14071
|
-
for (const item of
|
|
14072
|
-
if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(
|
|
14347
|
+
for (const item of fs18.readdirSync(mapDir, { withFileTypes: true })) {
|
|
14348
|
+
if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(path19.extname(item.name))) continue;
|
|
14073
14349
|
if (indexed.has(item.name)) continue;
|
|
14074
14350
|
internals.push({ path: item.name });
|
|
14075
14351
|
indexed.add(item.name);
|
|
@@ -14083,13 +14359,13 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
|
|
|
14083
14359
|
function repairCodemaps(worktree, apply, actions, unresolved, deps) {
|
|
14084
14360
|
const ig = loadGitIgnoreMatcher(worktree);
|
|
14085
14361
|
const rootCodemapPath = deps.optimaCodemapPath(worktree);
|
|
14086
|
-
const rootCodemapMissing = !
|
|
14362
|
+
const rootCodemapMissing = !fs18.existsSync(rootCodemapPath);
|
|
14087
14363
|
if (rootCodemapMissing) {
|
|
14088
14364
|
actions.push({ category: "codemap", action: apply ? "created" : "would_create", path: ".optima/codemap.yml", detail: "Create missing root CodeMap from template." });
|
|
14089
14365
|
if (apply) deps.scaffoldOptimaRootCodemap(worktree);
|
|
14090
14366
|
}
|
|
14091
|
-
if (
|
|
14092
|
-
const rootMap =
|
|
14367
|
+
if (fs18.existsSync(rootCodemapPath)) repairSingleCodemap(rootCodemapPath, worktree, apply, (action) => actions.push(action), unresolved, deps);
|
|
14368
|
+
const rootMap = fs18.existsSync(rootCodemapPath) ? readCodemap(rootCodemapPath, unresolved, worktree) : null;
|
|
14093
14369
|
let rootChanged = false;
|
|
14094
14370
|
const rootModulesRepairable = rootMap && (rootMap.modules === void 0 || Array.isArray(rootMap.modules));
|
|
14095
14371
|
if (rootMap) {
|
|
@@ -14101,10 +14377,10 @@ function repairCodemaps(worktree, apply, actions, unresolved, deps) {
|
|
|
14101
14377
|
}
|
|
14102
14378
|
}
|
|
14103
14379
|
function walk(dirPath) {
|
|
14104
|
-
const relative =
|
|
14380
|
+
const relative = path19.relative(worktree, dirPath);
|
|
14105
14381
|
if (relative && (isIgnoredPath(ig, relative) || isOperationalRelPath(relative) || isHiddenTree(relative))) return;
|
|
14106
|
-
const codemapPath =
|
|
14107
|
-
const hasCodemap =
|
|
14382
|
+
const codemapPath = path19.join(dirPath, "codemap.yml");
|
|
14383
|
+
const hasCodemap = fs18.existsSync(codemapPath);
|
|
14108
14384
|
const sourceDir = relative && containsSource(dirPath, ig, worktree);
|
|
14109
14385
|
if (sourceDir && !hasCodemap && dirPath !== worktree) {
|
|
14110
14386
|
if (hasImmediateSourceFile(dirPath, ig, worktree)) {
|
|
@@ -14123,19 +14399,19 @@ function repairCodemaps(worktree, apply, actions, unresolved, deps) {
|
|
|
14123
14399
|
actions.push({ category: "codemap", action: apply ? "updated" : "would_update", path: ".optima/codemap.yml", detail: `Register top-level source module '${normalizeCodemapRelPath(relative)}'.` });
|
|
14124
14400
|
}
|
|
14125
14401
|
}
|
|
14126
|
-
if (
|
|
14127
|
-
for (const item of
|
|
14128
|
-
if (item.isDirectory()) walk(
|
|
14402
|
+
if (fs18.existsSync(codemapPath) && codemapPath !== rootCodemapPath) repairSingleCodemap(codemapPath, worktree, apply, (action) => actions.push(action), unresolved, deps);
|
|
14403
|
+
for (const item of fs18.readdirSync(dirPath, { withFileTypes: true })) {
|
|
14404
|
+
if (item.isDirectory()) walk(path19.join(dirPath, item.name));
|
|
14129
14405
|
}
|
|
14130
14406
|
}
|
|
14131
|
-
if (
|
|
14407
|
+
if (fs18.existsSync(worktree)) walk(worktree);
|
|
14132
14408
|
if (rootMap && rootChanged && apply) writeCodemap(rootCodemapPath, rootMap);
|
|
14133
14409
|
}
|
|
14134
14410
|
function walkMarkdownFiles(dirPath) {
|
|
14135
|
-
if (!
|
|
14411
|
+
if (!fs18.existsSync(dirPath)) return [];
|
|
14136
14412
|
const files = [];
|
|
14137
|
-
for (const entry of
|
|
14138
|
-
const entryPath =
|
|
14413
|
+
for (const entry of fs18.readdirSync(dirPath, { withFileTypes: true })) {
|
|
14414
|
+
const entryPath = path19.join(dirPath, entry.name);
|
|
14139
14415
|
if (entry.isDirectory()) {
|
|
14140
14416
|
files.push(...walkMarkdownFiles(entryPath));
|
|
14141
14417
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -14174,7 +14450,7 @@ function rewriteOptimaMarkdownReferences(content, evidenceBasePath = null) {
|
|
|
14174
14450
|
}
|
|
14175
14451
|
function optimaEvidenceBaseForFile(worktree, filePath, deps) {
|
|
14176
14452
|
const evidenceRoot = deps.optimaEvidencesDir(worktree);
|
|
14177
|
-
const relative =
|
|
14453
|
+
const relative = path19.relative(evidenceRoot, filePath).split(path19.sep).join("/");
|
|
14178
14454
|
const [taskId] = relative.split("/");
|
|
14179
14455
|
if (!taskId || taskId === ".." || relative.startsWith("../")) return null;
|
|
14180
14456
|
return `.optima/evidences/${taskId}`;
|
|
@@ -14187,11 +14463,11 @@ function normalizeOptimaMarkdownReferences(worktree, deps) {
|
|
|
14187
14463
|
];
|
|
14188
14464
|
const changed = [];
|
|
14189
14465
|
for (const filePath of scanRoots.flatMap(walkMarkdownFiles)) {
|
|
14190
|
-
const raw =
|
|
14191
|
-
const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) +
|
|
14466
|
+
const raw = fs18.readFileSync(filePath, "utf8");
|
|
14467
|
+
const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) + path19.sep) ? optimaEvidenceBaseForFile(worktree, filePath, deps) : null;
|
|
14192
14468
|
const rewritten = rewriteOptimaMarkdownReferences(raw, evidenceBasePath);
|
|
14193
14469
|
if (rewritten !== raw) {
|
|
14194
|
-
|
|
14470
|
+
fs18.writeFileSync(filePath, rewritten, "utf8");
|
|
14195
14471
|
changed.push(relPath(worktree, filePath));
|
|
14196
14472
|
}
|
|
14197
14473
|
}
|
|
@@ -14199,8 +14475,8 @@ function normalizeOptimaMarkdownReferences(worktree, deps) {
|
|
|
14199
14475
|
}
|
|
14200
14476
|
function missingOptimaGitignoreRules(worktree, deps) {
|
|
14201
14477
|
if (!deps.isGitRepository(worktree)) return [];
|
|
14202
|
-
const gitignorePath =
|
|
14203
|
-
const existing =
|
|
14478
|
+
const gitignorePath = path19.join(worktree, ".gitignore");
|
|
14479
|
+
const existing = fs18.existsSync(gitignorePath) ? fs18.readFileSync(gitignorePath, "utf8") : "";
|
|
14204
14480
|
const existingRules = new Set(existing.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
|
|
14205
14481
|
return deps.optimaGitignoreRules.filter((rule) => !existingRules.has(rule));
|
|
14206
14482
|
}
|
|
@@ -14217,11 +14493,11 @@ function planOptimaRepair(worktree, args = {}, deps) {
|
|
|
14217
14493
|
const apply = mode === "apply";
|
|
14218
14494
|
const actions = [];
|
|
14219
14495
|
const unresolved = [];
|
|
14220
|
-
const hadOptima =
|
|
14496
|
+
const hadOptima = fs18.existsSync(deps.optimaDir(worktree));
|
|
14221
14497
|
const missingGitignoreRules = missingOptimaGitignoreRules(worktree, deps);
|
|
14222
14498
|
const markdownBefore = apply ? [] : walkMarkdownFiles(deps.optimaDir(worktree)).filter((filePath) => {
|
|
14223
|
-
const raw =
|
|
14224
|
-
const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) +
|
|
14499
|
+
const raw = fs18.readFileSync(filePath, "utf8");
|
|
14500
|
+
const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) + path19.sep) ? optimaEvidenceBaseForFile(worktree, filePath, deps) : null;
|
|
14225
14501
|
return rewriteOptimaMarkdownReferences(raw, evidenceBasePath) !== raw;
|
|
14226
14502
|
}).map((filePath) => relPath(worktree, filePath));
|
|
14227
14503
|
if (!hadOptima) pushRepairAction(actions, "operational", apply ? "created" : "would_create", ".optima/", "Create Optima operational root.");
|
|
@@ -14230,31 +14506,31 @@ function planOptimaRepair(worktree, args = {}, deps) {
|
|
|
14230
14506
|
[".staticeng/", deps.legacyStaticEngDir(worktree)],
|
|
14231
14507
|
[".nomadwork/", deps.legacyNomadworkDir(worktree)],
|
|
14232
14508
|
[".nomadworks/", deps.legacyNomadworksDir(worktree)],
|
|
14233
|
-
["tasks/",
|
|
14234
|
-
["evidences/",
|
|
14235
|
-
["docs/scrs/",
|
|
14236
|
-
["codemap.yml",
|
|
14237
|
-
["codemap.yaml",
|
|
14509
|
+
["tasks/", path19.join(worktree, "tasks")],
|
|
14510
|
+
["evidences/", path19.join(worktree, "evidences")],
|
|
14511
|
+
["docs/scrs/", path19.join(worktree, "docs", "scrs")],
|
|
14512
|
+
["codemap.yml", path19.join(worktree, "codemap.yml")],
|
|
14513
|
+
["codemap.yaml", path19.join(worktree, "codemap.yaml")]
|
|
14238
14514
|
];
|
|
14239
|
-
if (!deps.isOptimaPluginPackageWorktree(worktree)) legacySources.push(["policies/",
|
|
14515
|
+
if (!deps.isOptimaPluginPackageWorktree(worktree)) legacySources.push(["policies/", path19.join(worktree, "policies")]);
|
|
14240
14516
|
for (const [display, sourcePath] of legacySources) {
|
|
14241
|
-
if (
|
|
14517
|
+
if (fs18.existsSync(sourcePath)) pushRepairAction(actions, "legacy", apply ? "migrated" : "would_migrate", display, "Move or merge legacy/root Optima artifact into .optima using preservation safeguards.");
|
|
14242
14518
|
}
|
|
14243
14519
|
if (apply) deps.migrateLegacyOptimaLayout(worktree);
|
|
14244
|
-
const configMissing = !
|
|
14520
|
+
const configMissing = !fs18.existsSync(deps.repoConfigPath(worktree));
|
|
14245
14521
|
if (configMissing) pushRepairAction(actions, "config", apply ? "created" : "would_create", ".optima/.config/optima.yaml", "Create missing local Optima config from template.");
|
|
14246
14522
|
if (apply) deps.scaffoldOptimaConfig(worktree, args.team_mode || "full");
|
|
14247
14523
|
const requiredFiles = [
|
|
14248
|
-
[
|
|
14249
|
-
[
|
|
14250
|
-
[
|
|
14251
|
-
[
|
|
14252
|
-
[
|
|
14253
|
-
[
|
|
14254
|
-
[
|
|
14524
|
+
[path19.join(deps.optimaTasksDir(worktree), "current.md"), "registry", ".optima/tasks/current.md", deps.currentTasksRegistryContent()],
|
|
14525
|
+
[path19.join(deps.optimaTasksDir(worktree), "done.md"), "registry", ".optima/tasks/done.md", deps.doneTasksRegistryContent()],
|
|
14526
|
+
[path19.join(deps.optimaScrsDir(worktree), "current.md"), "registry", ".optima/docs/scrs/current.md", deps.currentScrRegistryContent()],
|
|
14527
|
+
[path19.join(deps.optimaScrsDir(worktree), "done.md"), "registry", ".optima/docs/scrs/done.md", deps.doneScrRegistryContent()],
|
|
14528
|
+
[path19.join(deps.optimaTasksDir(worktree), "task-template.md"), "template", ".optima/tasks/task-template.md", deps.taskTemplateContent()],
|
|
14529
|
+
[path19.join(deps.optimaTasksDir(worktree), "subtask-template.md"), "template", ".optima/tasks/subtask-template.md", deps.subtaskTemplateContent()],
|
|
14530
|
+
[path19.join(deps.repoPoliciesDir(worktree), "README.md"), "policy", ".optima/policies/README.md", deps.repoLocalPoliciesReadme]
|
|
14255
14531
|
];
|
|
14256
14532
|
for (const [filePath, category, displayPath, content] of requiredFiles) {
|
|
14257
|
-
if (!
|
|
14533
|
+
if (!fs18.existsSync(filePath)) {
|
|
14258
14534
|
pushRepairAction(actions, category, apply ? "created" : "would_create", displayPath, "Create missing Optima scaffold file without overwriting existing content.");
|
|
14259
14535
|
if (apply) deps.ensureFileIfMissing(filePath, content);
|
|
14260
14536
|
}
|
|
@@ -14308,18 +14584,18 @@ function formatRepairResult(plan, validationResult = null, formatValidationResul
|
|
|
14308
14584
|
// src/validate_logic.js
|
|
14309
14585
|
var import_yaml5 = __toESM(require_dist(), 1);
|
|
14310
14586
|
var import_ignore2 = __toESM(require_ignore(), 1);
|
|
14311
|
-
import
|
|
14312
|
-
import
|
|
14587
|
+
import fs19 from "node:fs";
|
|
14588
|
+
import path20 from "node:path";
|
|
14313
14589
|
async function optima_validate_logic(worktree) {
|
|
14314
|
-
const rootCodemapPath =
|
|
14315
|
-
if (!
|
|
14590
|
+
const rootCodemapPath = path20.join(worktree, ".optima", "codemap.yml");
|
|
14591
|
+
if (!fs19.existsSync(rootCodemapPath)) return { ok: false, errors: [".optima/codemap.yml not found."], warnings: [] };
|
|
14316
14592
|
const errors = [];
|
|
14317
14593
|
const warnings = [];
|
|
14318
14594
|
const ig = (0, import_ignore2.default)();
|
|
14319
14595
|
ig.add(".git");
|
|
14320
|
-
const gitignorePath =
|
|
14321
|
-
if (
|
|
14322
|
-
ig.add(
|
|
14596
|
+
const gitignorePath = path20.join(worktree, ".gitignore");
|
|
14597
|
+
if (fs19.existsSync(gitignorePath)) {
|
|
14598
|
+
ig.add(fs19.readFileSync(gitignorePath, "utf8"));
|
|
14323
14599
|
}
|
|
14324
14600
|
const sourceExtensions = [
|
|
14325
14601
|
".js",
|
|
@@ -14359,30 +14635,30 @@ async function optima_validate_logic(worktree) {
|
|
|
14359
14635
|
const operationalFolders = [".optima", "templates", "dist"];
|
|
14360
14636
|
const isHiddenTree2 = (relPath2) => {
|
|
14361
14637
|
if (!relPath2) return false;
|
|
14362
|
-
return relPath2.split(
|
|
14638
|
+
return relPath2.split(path20.sep).some((part) => part.startsWith("."));
|
|
14363
14639
|
};
|
|
14364
|
-
const firstPathSegment2 = (relPath2) => relPath2.split(
|
|
14640
|
+
const firstPathSegment2 = (relPath2) => relPath2.split(path20.sep).filter(Boolean)[0] || "";
|
|
14365
14641
|
const isOperationalRelPath2 = (relPath2) => {
|
|
14366
14642
|
if (!relPath2) return false;
|
|
14367
14643
|
const firstSegment = firstPathSegment2(relPath2);
|
|
14368
14644
|
if (legacyOperationalRoots.has(firstSegment)) return true;
|
|
14369
|
-
return operationalFolders.some((f) => relPath2 === f || relPath2.startsWith(f +
|
|
14645
|
+
return operationalFolders.some((f) => relPath2 === f || relPath2.startsWith(f + path20.sep));
|
|
14370
14646
|
};
|
|
14371
14647
|
const getSectionEntries = (value) => {
|
|
14372
14648
|
if (Array.isArray(value)) return value;
|
|
14373
14649
|
if (value && typeof value === "object") return Object.values(value);
|
|
14374
14650
|
return [];
|
|
14375
14651
|
};
|
|
14376
|
-
const normalizeRelativePath = (relPath2) =>
|
|
14652
|
+
const normalizeRelativePath = (relPath2) => path20.normalize(relPath2).replace(/\\/g, "/").replace(/\/$/, "");
|
|
14377
14653
|
const isSourceDir = (dirPath) => {
|
|
14378
|
-
const dirRelPath =
|
|
14654
|
+
const dirRelPath = path20.relative(worktree, dirPath);
|
|
14379
14655
|
if (isOperationalRelPath2(dirRelPath)) return false;
|
|
14380
|
-
const items =
|
|
14656
|
+
const items = fs19.readdirSync(dirPath, { withFileTypes: true });
|
|
14381
14657
|
for (const item of items) {
|
|
14382
|
-
const childPath =
|
|
14383
|
-
const relPath2 =
|
|
14658
|
+
const childPath = path20.join(dirPath, item.name);
|
|
14659
|
+
const relPath2 = path20.relative(worktree, childPath);
|
|
14384
14660
|
if (ig.ignores(relPath2) || isOperationalRelPath2(relPath2)) continue;
|
|
14385
|
-
if (item.isFile() && sourceExtensions.includes(
|
|
14661
|
+
if (item.isFile() && sourceExtensions.includes(path20.extname(item.name))) return true;
|
|
14386
14662
|
if (item.isDirectory()) {
|
|
14387
14663
|
if (isSourceDir(childPath)) return true;
|
|
14388
14664
|
}
|
|
@@ -14390,7 +14666,7 @@ async function optima_validate_logic(worktree) {
|
|
|
14390
14666
|
return false;
|
|
14391
14667
|
};
|
|
14392
14668
|
function validateMap(filePath) {
|
|
14393
|
-
const content =
|
|
14669
|
+
const content = fs19.readFileSync(filePath, "utf8");
|
|
14394
14670
|
let map;
|
|
14395
14671
|
try {
|
|
14396
14672
|
map = import_yaml5.default.parse(content);
|
|
@@ -14402,32 +14678,32 @@ async function optima_validate_logic(worktree) {
|
|
|
14402
14678
|
errors.push(`${filePath}: Invalid YAML.`);
|
|
14403
14679
|
return;
|
|
14404
14680
|
}
|
|
14405
|
-
const dir =
|
|
14681
|
+
const dir = path20.dirname(filePath);
|
|
14406
14682
|
const pathBase = filePath === rootCodemapPath ? worktree : dir;
|
|
14407
14683
|
const indexedPaths = /* @__PURE__ */ new Set();
|
|
14408
14684
|
const sectionsToVerify = ["modules", "entrypoints", "sources_of_truth", "links", "internals"];
|
|
14409
14685
|
for (const section of sectionsToVerify) {
|
|
14410
14686
|
for (const item of getSectionEntries(map[section])) {
|
|
14411
14687
|
if (item?.path) {
|
|
14412
|
-
indexedPaths.add(
|
|
14688
|
+
indexedPaths.add(path20.normalize(item.path));
|
|
14413
14689
|
if (section === "links" && (item.path.startsWith("http://") || item.path.startsWith("https://"))) {
|
|
14414
14690
|
continue;
|
|
14415
14691
|
}
|
|
14416
|
-
const absPath =
|
|
14417
|
-
if (!
|
|
14692
|
+
const absPath = path20.isAbsolute(item.path) ? item.path : path20.join(pathBase, item.path);
|
|
14693
|
+
if (!fs19.existsSync(absPath)) {
|
|
14418
14694
|
errors.push(`${filePath}: ${section.slice(0, -1)} path does not exist: ${item.path}`);
|
|
14419
14695
|
}
|
|
14420
14696
|
}
|
|
14421
14697
|
}
|
|
14422
14698
|
}
|
|
14423
|
-
const relDir =
|
|
14699
|
+
const relDir = path20.relative(worktree, dir);
|
|
14424
14700
|
const isOperational = isOperationalRelPath2(relDir);
|
|
14425
14701
|
if (map.scope === "module" && !isOperational) {
|
|
14426
|
-
const items =
|
|
14702
|
+
const items = fs19.readdirSync(dir, { withFileTypes: true });
|
|
14427
14703
|
for (const item of items) {
|
|
14428
|
-
if (item.isFile() && sourceExtensions.includes(
|
|
14704
|
+
if (item.isFile() && sourceExtensions.includes(path20.extname(item.name))) {
|
|
14429
14705
|
if (item.name === "codemap.yml") continue;
|
|
14430
|
-
if (!indexedPaths.has(
|
|
14706
|
+
if (!indexedPaths.has(path20.normalize(item.name))) {
|
|
14431
14707
|
errors.push(`${filePath}: Unindexed source file found: '${item.name}'. Every source file must be categorized in a section (e.g., 'internals').`);
|
|
14432
14708
|
}
|
|
14433
14709
|
}
|
|
@@ -14437,7 +14713,7 @@ async function optima_validate_logic(worktree) {
|
|
|
14437
14713
|
for (const key of pathKeys) {
|
|
14438
14714
|
for (const entry of getSectionEntries(map[key])) {
|
|
14439
14715
|
if (!entry?.path || entry.path.startsWith("http://") || entry.path.startsWith("https://")) continue;
|
|
14440
|
-
if (
|
|
14716
|
+
if (path20.isAbsolute(entry.path)) continue;
|
|
14441
14717
|
const normalizedPath = normalizeRelativePath(entry.path);
|
|
14442
14718
|
if (!normalizedPath || normalizedPath === ".") continue;
|
|
14443
14719
|
const parts = normalizedPath.split("/").filter((p) => p && p !== ".");
|
|
@@ -14449,18 +14725,18 @@ async function optima_validate_logic(worktree) {
|
|
|
14449
14725
|
}
|
|
14450
14726
|
}
|
|
14451
14727
|
const walk = (dir) => {
|
|
14452
|
-
const relDir =
|
|
14728
|
+
const relDir = path20.relative(worktree, dir);
|
|
14453
14729
|
if (relDir && ig.ignores(relDir)) return;
|
|
14454
14730
|
if (isOperationalRelPath2(relDir)) return;
|
|
14455
14731
|
if (isHiddenTree2(relDir)) return;
|
|
14456
|
-
const hasCodemap =
|
|
14457
|
-
const items =
|
|
14458
|
-
if (!relDir.startsWith(
|
|
14732
|
+
const hasCodemap = fs19.existsSync(path20.join(dir, "codemap.yml"));
|
|
14733
|
+
const items = fs19.readdirSync(dir, { withFileTypes: true });
|
|
14734
|
+
if (!relDir.startsWith(path20.join(".optima", "tasks", "done"))) {
|
|
14459
14735
|
for (const item of items) {
|
|
14460
14736
|
if (item.isFile() && item.name.endsWith(".md")) {
|
|
14461
|
-
const content =
|
|
14737
|
+
const content = fs19.readFileSync(path20.join(dir, item.name), "utf8");
|
|
14462
14738
|
if (content.includes("[To be defined]") || content.includes("[Insert ")) {
|
|
14463
|
-
const relFilePath =
|
|
14739
|
+
const relFilePath = path20.join(relDir, item.name);
|
|
14464
14740
|
errors.push(`Documentation Placeholder found: '${relFilePath}' still contains [To be defined] or [Insert ...] placeholders.`);
|
|
14465
14741
|
}
|
|
14466
14742
|
}
|
|
@@ -14470,9 +14746,9 @@ async function optima_validate_logic(worktree) {
|
|
|
14470
14746
|
if (relDir !== "" && !hasCodemap && isSourceDir(dir) && !isOperational) {
|
|
14471
14747
|
errors.push(`Missing CodeMap: Directory '${relDir}' contains source but has no codemap.yml.`);
|
|
14472
14748
|
}
|
|
14473
|
-
if (hasCodemap) validateMap(
|
|
14749
|
+
if (hasCodemap) validateMap(path20.join(dir, "codemap.yml"));
|
|
14474
14750
|
for (const item of items) {
|
|
14475
|
-
if (item.isDirectory()) walk(
|
|
14751
|
+
if (item.isDirectory()) walk(path20.join(dir, item.name));
|
|
14476
14752
|
}
|
|
14477
14753
|
};
|
|
14478
14754
|
validateMap(rootCodemapPath);
|
|
@@ -14492,7 +14768,7 @@ function normalizeWorkflowTaskPath(taskPath) {
|
|
|
14492
14768
|
const trimmed = taskPath.trim();
|
|
14493
14769
|
if (!trimmed) return { ok: false, message: "Error: task_path is required." };
|
|
14494
14770
|
const normalized = trimmed.replace(/\\/g, "/");
|
|
14495
|
-
if (
|
|
14771
|
+
if (path21.isAbsolute(trimmed)) return { ok: true, taskPath: trimmed };
|
|
14496
14772
|
if (normalized === "tasks" || normalized.startsWith("tasks/")) {
|
|
14497
14773
|
return {
|
|
14498
14774
|
ok: false,
|
|
@@ -14509,10 +14785,10 @@ function normalizeWorkflowTaskPath(taskPath) {
|
|
|
14509
14785
|
}
|
|
14510
14786
|
function readTaskMetadata(taskPath, worktree) {
|
|
14511
14787
|
if (!taskPath) return {};
|
|
14512
|
-
const absoluteTaskPath =
|
|
14513
|
-
if (!
|
|
14788
|
+
const absoluteTaskPath = path21.isAbsolute(taskPath) ? taskPath : path21.join(worktree, taskPath);
|
|
14789
|
+
if (!fs20.existsSync(absoluteTaskPath)) return {};
|
|
14514
14790
|
try {
|
|
14515
|
-
const raw =
|
|
14791
|
+
const raw = fs20.readFileSync(absoluteTaskPath, "utf8");
|
|
14516
14792
|
const { data } = parseFrontmatter(raw);
|
|
14517
14793
|
return {
|
|
14518
14794
|
complexity: typeof data.complexity === "string" ? data.complexity.trim().toLowerCase() : void 0,
|
|
@@ -14535,15 +14811,15 @@ function hasActiveImplementationWorkflow() {
|
|
|
14535
14811
|
function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktree, clickUpWebhookValidation } = {}) {
|
|
14536
14812
|
const safe = safeWorktreeOrFailure(context, pluginWorktree);
|
|
14537
14813
|
if (!safe.ok) return { ok: false, error: safe.message };
|
|
14538
|
-
const requested = String(requestedDirectory || "").trim() ?
|
|
14814
|
+
const requested = String(requestedDirectory || "").trim() ? path21.resolve(safe.worktree, String(requestedDirectory).trim()) : safe.worktree;
|
|
14539
14815
|
if (!isSafeWritableDirectory(requested)) return { ok: false, error: `Directory is not a safe writable directory: ${requested}` };
|
|
14540
14816
|
if (isSameOrNestedPath(requested, safe.worktree)) return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "context_worktree" };
|
|
14541
14817
|
const clickUpBasePath = clickUpWebhookValidation?.complete === true && clickUpWebhookValidation?.ok !== false ? clickUpWebhookValidation.config?.basePath : "";
|
|
14542
14818
|
if (clickUpBasePath && isSameOrNestedPath(requested, clickUpBasePath)) {
|
|
14543
|
-
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath:
|
|
14819
|
+
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path21.resolve(clickUpBasePath) };
|
|
14544
14820
|
}
|
|
14545
14821
|
if (clickUpBasePath && isClickUpDerivedWorktreeSibling(requested, clickUpBasePath)) {
|
|
14546
|
-
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_derived_worktree", clickupBasePath:
|
|
14822
|
+
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_derived_worktree", clickupBasePath: path21.resolve(clickUpBasePath) };
|
|
14547
14823
|
}
|
|
14548
14824
|
return {
|
|
14549
14825
|
ok: false,
|
|
@@ -14558,9 +14834,9 @@ async function OptimaPlugin(input = {}, pluginOptions = {}) {
|
|
|
14558
14834
|
const configPath = resolveConfigPath(worktree);
|
|
14559
14835
|
const discussionRegistry = loadDiscussionRegistry(worktree);
|
|
14560
14836
|
let repoCfg = { agents: {}, defaults: {}, features: {} };
|
|
14561
|
-
if (
|
|
14837
|
+
if (fs20.existsSync(configPath)) {
|
|
14562
14838
|
try {
|
|
14563
|
-
repoCfg = import_yaml6.default.parse(
|
|
14839
|
+
repoCfg = import_yaml6.default.parse(fs20.readFileSync(configPath, "utf8")) || repoCfg;
|
|
14564
14840
|
} catch (e) {
|
|
14565
14841
|
console.error(`[Optima] Failed to parse config at ${configPath}:`, e);
|
|
14566
14842
|
}
|
|
@@ -14865,10 +15141,10 @@ Evidencia: ${evidencePath}` : ""
|
|
|
14865
15141
|
}
|
|
14866
15142
|
migrateLegacyOptimaLayout(toolWorktree);
|
|
14867
15143
|
const cfgDir = optimaConfigDir(toolWorktree);
|
|
14868
|
-
if (!
|
|
14869
|
-
const optimaTmplPath =
|
|
14870
|
-
const codemapTmplPath =
|
|
14871
|
-
if (!
|
|
15144
|
+
if (!fs20.existsSync(cfgDir)) fs20.mkdirSync(cfgDir, { recursive: true });
|
|
15145
|
+
const optimaTmplPath = path21.join(TEMPLATES_DIR, "optima.yaml.template");
|
|
15146
|
+
const codemapTmplPath = path21.join(TEMPLATES_DIR, "codemap.yml.template");
|
|
15147
|
+
if (!fs20.existsSync(optimaTmplPath) || !fs20.existsSync(codemapTmplPath)) {
|
|
14872
15148
|
return "Error: Initialization templates not found in plugin.";
|
|
14873
15149
|
}
|
|
14874
15150
|
scaffoldOptimaConfig(toolWorktree, requestedTeamMode);
|
|
@@ -14989,14 +15265,14 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
|
|
|
14989
15265
|
async execute(args, context) {
|
|
14990
15266
|
const safe = safeWorktreeOrFailure(context, worktree);
|
|
14991
15267
|
if (!safe.ok) return safe.message;
|
|
14992
|
-
const summaryPath =
|
|
14993
|
-
if (!
|
|
14994
|
-
const taskPath = args.task_path ?
|
|
15268
|
+
const summaryPath = path21.resolve(safe.worktree, args.summary_path || "");
|
|
15269
|
+
if (!fs20.existsSync(summaryPath)) return `FAIL: summary_path not found: ${summaryPath}`;
|
|
15270
|
+
const taskPath = args.task_path ? path21.resolve(safe.worktree, args.task_path) : "";
|
|
14995
15271
|
const payload = buildClickUpSummaryPayload({
|
|
14996
|
-
summaryMarkdown:
|
|
14997
|
-
summaryPath:
|
|
14998
|
-
taskMarkdown: taskPath &&
|
|
14999
|
-
taskPath: taskPath ?
|
|
15272
|
+
summaryMarkdown: fs20.readFileSync(summaryPath, "utf8"),
|
|
15273
|
+
summaryPath: path21.relative(safe.worktree, summaryPath),
|
|
15274
|
+
taskMarkdown: taskPath && fs20.existsSync(taskPath) ? fs20.readFileSync(taskPath, "utf8") : "",
|
|
15275
|
+
taskPath: taskPath ? path21.relative(safe.worktree, taskPath) : "",
|
|
15000
15276
|
branch: args.branch,
|
|
15001
15277
|
worktree: args.worktree,
|
|
15002
15278
|
pr: args.pr
|
|
@@ -15163,7 +15439,7 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
|
|
|
15163
15439
|
commandJson: args.command_json,
|
|
15164
15440
|
startUrl: args.start_url || "https://chatgpt.com/"
|
|
15165
15441
|
});
|
|
15166
|
-
return JSON.stringify({ ok:
|
|
15442
|
+
return JSON.stringify({ ok: result.ok !== false, lease: persisted.state.active, notifications: persisted.notifications, chrome: result }, null, 2);
|
|
15167
15443
|
} catch (error) {
|
|
15168
15444
|
return JSON.stringify({ ok: false, error: error.message, lease: persisted.state.active, notifications: persisted.notifications }, null, 2);
|
|
15169
15445
|
}
|
|
@@ -15211,12 +15487,12 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
|
|
|
15211
15487
|
async execute(args, context) {
|
|
15212
15488
|
const safe = safeWorktreeOrFailure(context, worktree);
|
|
15213
15489
|
if (!safe.ok) return safe.message;
|
|
15214
|
-
const markdownPath =
|
|
15215
|
-
if (!
|
|
15490
|
+
const markdownPath = path21.resolve(safe.worktree, args.markdown_path || "");
|
|
15491
|
+
if (!fs20.existsSync(markdownPath)) return `FAIL: markdown_path not found: ${markdownPath}`;
|
|
15216
15492
|
const payload = buildClickUpCreateSubtasksPayload({
|
|
15217
15493
|
parentTaskId: args.parent_task_id,
|
|
15218
|
-
markdown:
|
|
15219
|
-
sourcePath:
|
|
15494
|
+
markdown: fs20.readFileSync(markdownPath, "utf8"),
|
|
15495
|
+
sourcePath: path21.relative(safe.worktree, markdownPath),
|
|
15220
15496
|
parentBranch: args.parent_branch,
|
|
15221
15497
|
parentTaskType: args.parent_task_type || "Tarea",
|
|
15222
15498
|
apply: String(args.apply || "").toLowerCase() === "true"
|
|
@@ -15586,7 +15862,7 @@ Backfilled messages: ${backfilled}`;
|
|
|
15586
15862
|
if (!existing) {
|
|
15587
15863
|
return "FAIL: No active discussion exists for this session.";
|
|
15588
15864
|
}
|
|
15589
|
-
const discussionPath =
|
|
15865
|
+
const discussionPath = path21.join(toolWorktree, existing.transcriptPath);
|
|
15590
15866
|
setDiscussionStatus(discussionPath, "summarizing");
|
|
15591
15867
|
existing.status = "summarizing";
|
|
15592
15868
|
saveDiscussionRegistry(toolWorktree, toolRegistry);
|
|
@@ -15638,7 +15914,7 @@ Reason: ${err.message}`;
|
|
|
15638
15914
|
try {
|
|
15639
15915
|
const sessionResult = await client.session.create({
|
|
15640
15916
|
query: { directory: workflowDirectory },
|
|
15641
|
-
body: { title: `Workflow Run: ${
|
|
15917
|
+
body: { title: `Workflow Run: ${path21.basename(workflowTaskPath)}` }
|
|
15642
15918
|
});
|
|
15643
15919
|
const sessionId = sessionResult.data.id;
|
|
15644
15920
|
activeWorkflows.set(sessionId, { pmaSessionId, taskPath: workflowTaskPath, track: workflowTrack, directory: workflowDirectory });
|