@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/sanitize_cli.js
CHANGED
|
@@ -109,17 +109,17 @@ var require_visit = __commonJS({
|
|
|
109
109
|
visit.BREAK = BREAK;
|
|
110
110
|
visit.SKIP = SKIP;
|
|
111
111
|
visit.REMOVE = REMOVE;
|
|
112
|
-
function visit_(key, node, visitor,
|
|
113
|
-
const ctrl = callVisitor(key, node, visitor,
|
|
112
|
+
function visit_(key, node, visitor, path23) {
|
|
113
|
+
const ctrl = callVisitor(key, node, visitor, path23);
|
|
114
114
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
115
|
-
replaceNode(key,
|
|
116
|
-
return visit_(key, ctrl, visitor,
|
|
115
|
+
replaceNode(key, path23, ctrl);
|
|
116
|
+
return visit_(key, ctrl, visitor, path23);
|
|
117
117
|
}
|
|
118
118
|
if (typeof ctrl !== "symbol") {
|
|
119
119
|
if (identity.isCollection(node)) {
|
|
120
|
-
|
|
120
|
+
path23 = Object.freeze(path23.concat(node));
|
|
121
121
|
for (let i = 0; i < node.items.length; ++i) {
|
|
122
|
-
const ci = visit_(i, node.items[i], visitor,
|
|
122
|
+
const ci = visit_(i, node.items[i], visitor, path23);
|
|
123
123
|
if (typeof ci === "number")
|
|
124
124
|
i = ci - 1;
|
|
125
125
|
else if (ci === BREAK)
|
|
@@ -130,13 +130,13 @@ var require_visit = __commonJS({
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
} else if (identity.isPair(node)) {
|
|
133
|
-
|
|
134
|
-
const ck = visit_("key", node.key, visitor,
|
|
133
|
+
path23 = Object.freeze(path23.concat(node));
|
|
134
|
+
const ck = visit_("key", node.key, visitor, path23);
|
|
135
135
|
if (ck === BREAK)
|
|
136
136
|
return BREAK;
|
|
137
137
|
else if (ck === REMOVE)
|
|
138
138
|
node.key = null;
|
|
139
|
-
const cv = visit_("value", node.value, visitor,
|
|
139
|
+
const cv = visit_("value", node.value, visitor, path23);
|
|
140
140
|
if (cv === BREAK)
|
|
141
141
|
return BREAK;
|
|
142
142
|
else if (cv === REMOVE)
|
|
@@ -157,17 +157,17 @@ var require_visit = __commonJS({
|
|
|
157
157
|
visitAsync.BREAK = BREAK;
|
|
158
158
|
visitAsync.SKIP = SKIP;
|
|
159
159
|
visitAsync.REMOVE = REMOVE;
|
|
160
|
-
async function visitAsync_(key, node, visitor,
|
|
161
|
-
const ctrl = await callVisitor(key, node, visitor,
|
|
160
|
+
async function visitAsync_(key, node, visitor, path23) {
|
|
161
|
+
const ctrl = await callVisitor(key, node, visitor, path23);
|
|
162
162
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
163
|
-
replaceNode(key,
|
|
164
|
-
return visitAsync_(key, ctrl, visitor,
|
|
163
|
+
replaceNode(key, path23, ctrl);
|
|
164
|
+
return visitAsync_(key, ctrl, visitor, path23);
|
|
165
165
|
}
|
|
166
166
|
if (typeof ctrl !== "symbol") {
|
|
167
167
|
if (identity.isCollection(node)) {
|
|
168
|
-
|
|
168
|
+
path23 = Object.freeze(path23.concat(node));
|
|
169
169
|
for (let i = 0; i < node.items.length; ++i) {
|
|
170
|
-
const ci = await visitAsync_(i, node.items[i], visitor,
|
|
170
|
+
const ci = await visitAsync_(i, node.items[i], visitor, path23);
|
|
171
171
|
if (typeof ci === "number")
|
|
172
172
|
i = ci - 1;
|
|
173
173
|
else if (ci === BREAK)
|
|
@@ -178,13 +178,13 @@ var require_visit = __commonJS({
|
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
} else if (identity.isPair(node)) {
|
|
181
|
-
|
|
182
|
-
const ck = await visitAsync_("key", node.key, visitor,
|
|
181
|
+
path23 = Object.freeze(path23.concat(node));
|
|
182
|
+
const ck = await visitAsync_("key", node.key, visitor, path23);
|
|
183
183
|
if (ck === BREAK)
|
|
184
184
|
return BREAK;
|
|
185
185
|
else if (ck === REMOVE)
|
|
186
186
|
node.key = null;
|
|
187
|
-
const cv = await visitAsync_("value", node.value, visitor,
|
|
187
|
+
const cv = await visitAsync_("value", node.value, visitor, path23);
|
|
188
188
|
if (cv === BREAK)
|
|
189
189
|
return BREAK;
|
|
190
190
|
else if (cv === REMOVE)
|
|
@@ -211,23 +211,23 @@ var require_visit = __commonJS({
|
|
|
211
211
|
}
|
|
212
212
|
return visitor;
|
|
213
213
|
}
|
|
214
|
-
function callVisitor(key, node, visitor,
|
|
214
|
+
function callVisitor(key, node, visitor, path23) {
|
|
215
215
|
if (typeof visitor === "function")
|
|
216
|
-
return visitor(key, node,
|
|
216
|
+
return visitor(key, node, path23);
|
|
217
217
|
if (identity.isMap(node))
|
|
218
|
-
return visitor.Map?.(key, node,
|
|
218
|
+
return visitor.Map?.(key, node, path23);
|
|
219
219
|
if (identity.isSeq(node))
|
|
220
|
-
return visitor.Seq?.(key, node,
|
|
220
|
+
return visitor.Seq?.(key, node, path23);
|
|
221
221
|
if (identity.isPair(node))
|
|
222
|
-
return visitor.Pair?.(key, node,
|
|
222
|
+
return visitor.Pair?.(key, node, path23);
|
|
223
223
|
if (identity.isScalar(node))
|
|
224
|
-
return visitor.Scalar?.(key, node,
|
|
224
|
+
return visitor.Scalar?.(key, node, path23);
|
|
225
225
|
if (identity.isAlias(node))
|
|
226
|
-
return visitor.Alias?.(key, node,
|
|
226
|
+
return visitor.Alias?.(key, node, path23);
|
|
227
227
|
return void 0;
|
|
228
228
|
}
|
|
229
|
-
function replaceNode(key,
|
|
230
|
-
const parent =
|
|
229
|
+
function replaceNode(key, path23, node) {
|
|
230
|
+
const parent = path23[path23.length - 1];
|
|
231
231
|
if (identity.isCollection(parent)) {
|
|
232
232
|
parent.items[key] = node;
|
|
233
233
|
} else if (identity.isPair(parent)) {
|
|
@@ -835,10 +835,10 @@ var require_Collection = __commonJS({
|
|
|
835
835
|
var createNode = require_createNode();
|
|
836
836
|
var identity = require_identity();
|
|
837
837
|
var Node = require_Node();
|
|
838
|
-
function collectionFromPath(schema,
|
|
838
|
+
function collectionFromPath(schema, path23, value) {
|
|
839
839
|
let v = value;
|
|
840
|
-
for (let i =
|
|
841
|
-
const k =
|
|
840
|
+
for (let i = path23.length - 1; i >= 0; --i) {
|
|
841
|
+
const k = path23[i];
|
|
842
842
|
if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
|
|
843
843
|
const a = [];
|
|
844
844
|
a[k] = v;
|
|
@@ -857,7 +857,7 @@ var require_Collection = __commonJS({
|
|
|
857
857
|
sourceObjects: /* @__PURE__ */ new Map()
|
|
858
858
|
});
|
|
859
859
|
}
|
|
860
|
-
var isEmptyPath = (
|
|
860
|
+
var isEmptyPath = (path23) => path23 == null || typeof path23 === "object" && !!path23[Symbol.iterator]().next().done;
|
|
861
861
|
var Collection = class extends Node.NodeBase {
|
|
862
862
|
constructor(type, schema) {
|
|
863
863
|
super(type);
|
|
@@ -887,11 +887,11 @@ var require_Collection = __commonJS({
|
|
|
887
887
|
* be a Pair instance or a `{ key, value }` object, which may not have a key
|
|
888
888
|
* that already exists in the map.
|
|
889
889
|
*/
|
|
890
|
-
addIn(
|
|
891
|
-
if (isEmptyPath(
|
|
890
|
+
addIn(path23, value) {
|
|
891
|
+
if (isEmptyPath(path23))
|
|
892
892
|
this.add(value);
|
|
893
893
|
else {
|
|
894
|
-
const [key, ...rest] =
|
|
894
|
+
const [key, ...rest] = path23;
|
|
895
895
|
const node = this.get(key, true);
|
|
896
896
|
if (identity.isCollection(node))
|
|
897
897
|
node.addIn(rest, value);
|
|
@@ -905,8 +905,8 @@ var require_Collection = __commonJS({
|
|
|
905
905
|
* Removes a value from the collection.
|
|
906
906
|
* @returns `true` if the item was found and removed.
|
|
907
907
|
*/
|
|
908
|
-
deleteIn(
|
|
909
|
-
const [key, ...rest] =
|
|
908
|
+
deleteIn(path23) {
|
|
909
|
+
const [key, ...rest] = path23;
|
|
910
910
|
if (rest.length === 0)
|
|
911
911
|
return this.delete(key);
|
|
912
912
|
const node = this.get(key, true);
|
|
@@ -920,8 +920,8 @@ var require_Collection = __commonJS({
|
|
|
920
920
|
* scalar values from their surrounding node; to disable set `keepScalar` to
|
|
921
921
|
* `true` (collections are always returned intact).
|
|
922
922
|
*/
|
|
923
|
-
getIn(
|
|
924
|
-
const [key, ...rest] =
|
|
923
|
+
getIn(path23, keepScalar) {
|
|
924
|
+
const [key, ...rest] = path23;
|
|
925
925
|
const node = this.get(key, true);
|
|
926
926
|
if (rest.length === 0)
|
|
927
927
|
return !keepScalar && identity.isScalar(node) ? node.value : node;
|
|
@@ -939,8 +939,8 @@ var require_Collection = __commonJS({
|
|
|
939
939
|
/**
|
|
940
940
|
* Checks if the collection includes a value with the key `key`.
|
|
941
941
|
*/
|
|
942
|
-
hasIn(
|
|
943
|
-
const [key, ...rest] =
|
|
942
|
+
hasIn(path23) {
|
|
943
|
+
const [key, ...rest] = path23;
|
|
944
944
|
if (rest.length === 0)
|
|
945
945
|
return this.has(key);
|
|
946
946
|
const node = this.get(key, true);
|
|
@@ -950,8 +950,8 @@ var require_Collection = __commonJS({
|
|
|
950
950
|
* Sets a value in this collection. For `!!set`, `value` needs to be a
|
|
951
951
|
* boolean to add/remove the item from the set.
|
|
952
952
|
*/
|
|
953
|
-
setIn(
|
|
954
|
-
const [key, ...rest] =
|
|
953
|
+
setIn(path23, value) {
|
|
954
|
+
const [key, ...rest] = path23;
|
|
955
955
|
if (rest.length === 0) {
|
|
956
956
|
this.set(key, value);
|
|
957
957
|
} else {
|
|
@@ -3455,9 +3455,9 @@ var require_Document = __commonJS({
|
|
|
3455
3455
|
this.contents.add(value);
|
|
3456
3456
|
}
|
|
3457
3457
|
/** Adds a value to the document. */
|
|
3458
|
-
addIn(
|
|
3458
|
+
addIn(path23, value) {
|
|
3459
3459
|
if (assertCollection(this.contents))
|
|
3460
|
-
this.contents.addIn(
|
|
3460
|
+
this.contents.addIn(path23, value);
|
|
3461
3461
|
}
|
|
3462
3462
|
/**
|
|
3463
3463
|
* Create a new `Alias` node, ensuring that the target `node` has the required anchor.
|
|
@@ -3532,14 +3532,14 @@ var require_Document = __commonJS({
|
|
|
3532
3532
|
* Removes a value from the document.
|
|
3533
3533
|
* @returns `true` if the item was found and removed.
|
|
3534
3534
|
*/
|
|
3535
|
-
deleteIn(
|
|
3536
|
-
if (Collection.isEmptyPath(
|
|
3535
|
+
deleteIn(path23) {
|
|
3536
|
+
if (Collection.isEmptyPath(path23)) {
|
|
3537
3537
|
if (this.contents == null)
|
|
3538
3538
|
return false;
|
|
3539
3539
|
this.contents = null;
|
|
3540
3540
|
return true;
|
|
3541
3541
|
}
|
|
3542
|
-
return assertCollection(this.contents) ? this.contents.deleteIn(
|
|
3542
|
+
return assertCollection(this.contents) ? this.contents.deleteIn(path23) : false;
|
|
3543
3543
|
}
|
|
3544
3544
|
/**
|
|
3545
3545
|
* Returns item at `key`, or `undefined` if not found. By default unwraps
|
|
@@ -3554,10 +3554,10 @@ var require_Document = __commonJS({
|
|
|
3554
3554
|
* scalar values from their surrounding node; to disable set `keepScalar` to
|
|
3555
3555
|
* `true` (collections are always returned intact).
|
|
3556
3556
|
*/
|
|
3557
|
-
getIn(
|
|
3558
|
-
if (Collection.isEmptyPath(
|
|
3557
|
+
getIn(path23, keepScalar) {
|
|
3558
|
+
if (Collection.isEmptyPath(path23))
|
|
3559
3559
|
return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
|
|
3560
|
-
return identity.isCollection(this.contents) ? this.contents.getIn(
|
|
3560
|
+
return identity.isCollection(this.contents) ? this.contents.getIn(path23, keepScalar) : void 0;
|
|
3561
3561
|
}
|
|
3562
3562
|
/**
|
|
3563
3563
|
* Checks if the document includes a value with the key `key`.
|
|
@@ -3568,10 +3568,10 @@ var require_Document = __commonJS({
|
|
|
3568
3568
|
/**
|
|
3569
3569
|
* Checks if the document includes a value at `path`.
|
|
3570
3570
|
*/
|
|
3571
|
-
hasIn(
|
|
3572
|
-
if (Collection.isEmptyPath(
|
|
3571
|
+
hasIn(path23) {
|
|
3572
|
+
if (Collection.isEmptyPath(path23))
|
|
3573
3573
|
return this.contents !== void 0;
|
|
3574
|
-
return identity.isCollection(this.contents) ? this.contents.hasIn(
|
|
3574
|
+
return identity.isCollection(this.contents) ? this.contents.hasIn(path23) : false;
|
|
3575
3575
|
}
|
|
3576
3576
|
/**
|
|
3577
3577
|
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
@@ -3588,13 +3588,13 @@ var require_Document = __commonJS({
|
|
|
3588
3588
|
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
3589
3589
|
* boolean to add/remove the item from the set.
|
|
3590
3590
|
*/
|
|
3591
|
-
setIn(
|
|
3592
|
-
if (Collection.isEmptyPath(
|
|
3591
|
+
setIn(path23, value) {
|
|
3592
|
+
if (Collection.isEmptyPath(path23)) {
|
|
3593
3593
|
this.contents = value;
|
|
3594
3594
|
} else if (this.contents == null) {
|
|
3595
|
-
this.contents = Collection.collectionFromPath(this.schema, Array.from(
|
|
3595
|
+
this.contents = Collection.collectionFromPath(this.schema, Array.from(path23), value);
|
|
3596
3596
|
} else if (assertCollection(this.contents)) {
|
|
3597
|
-
this.contents.setIn(
|
|
3597
|
+
this.contents.setIn(path23, value);
|
|
3598
3598
|
}
|
|
3599
3599
|
}
|
|
3600
3600
|
/**
|
|
@@ -5546,9 +5546,9 @@ var require_cst_visit = __commonJS({
|
|
|
5546
5546
|
visit.BREAK = BREAK;
|
|
5547
5547
|
visit.SKIP = SKIP;
|
|
5548
5548
|
visit.REMOVE = REMOVE;
|
|
5549
|
-
visit.itemAtPath = (cst,
|
|
5549
|
+
visit.itemAtPath = (cst, path23) => {
|
|
5550
5550
|
let item = cst;
|
|
5551
|
-
for (const [field, index] of
|
|
5551
|
+
for (const [field, index] of path23) {
|
|
5552
5552
|
const tok = item?.[field];
|
|
5553
5553
|
if (tok && "items" in tok) {
|
|
5554
5554
|
item = tok.items[index];
|
|
@@ -5557,23 +5557,23 @@ var require_cst_visit = __commonJS({
|
|
|
5557
5557
|
}
|
|
5558
5558
|
return item;
|
|
5559
5559
|
};
|
|
5560
|
-
visit.parentCollection = (cst,
|
|
5561
|
-
const parent = visit.itemAtPath(cst,
|
|
5562
|
-
const field =
|
|
5560
|
+
visit.parentCollection = (cst, path23) => {
|
|
5561
|
+
const parent = visit.itemAtPath(cst, path23.slice(0, -1));
|
|
5562
|
+
const field = path23[path23.length - 1][0];
|
|
5563
5563
|
const coll = parent?.[field];
|
|
5564
5564
|
if (coll && "items" in coll)
|
|
5565
5565
|
return coll;
|
|
5566
5566
|
throw new Error("Parent collection not found");
|
|
5567
5567
|
};
|
|
5568
|
-
function _visit(
|
|
5569
|
-
let ctrl = visitor(item,
|
|
5568
|
+
function _visit(path23, item, visitor) {
|
|
5569
|
+
let ctrl = visitor(item, path23);
|
|
5570
5570
|
if (typeof ctrl === "symbol")
|
|
5571
5571
|
return ctrl;
|
|
5572
5572
|
for (const field of ["key", "value"]) {
|
|
5573
5573
|
const token = item[field];
|
|
5574
5574
|
if (token && "items" in token) {
|
|
5575
5575
|
for (let i = 0; i < token.items.length; ++i) {
|
|
5576
|
-
const ci = _visit(Object.freeze(
|
|
5576
|
+
const ci = _visit(Object.freeze(path23.concat([[field, i]])), token.items[i], visitor);
|
|
5577
5577
|
if (typeof ci === "number")
|
|
5578
5578
|
i = ci - 1;
|
|
5579
5579
|
else if (ci === BREAK)
|
|
@@ -5584,10 +5584,10 @@ var require_cst_visit = __commonJS({
|
|
|
5584
5584
|
}
|
|
5585
5585
|
}
|
|
5586
5586
|
if (typeof ctrl === "function" && field === "key")
|
|
5587
|
-
ctrl = ctrl(item,
|
|
5587
|
+
ctrl = ctrl(item, path23);
|
|
5588
5588
|
}
|
|
5589
5589
|
}
|
|
5590
|
-
return typeof ctrl === "function" ? ctrl(item,
|
|
5590
|
+
return typeof ctrl === "function" ? ctrl(item, path23) : ctrl;
|
|
5591
5591
|
}
|
|
5592
5592
|
exports.visit = visit;
|
|
5593
5593
|
}
|
|
@@ -6872,14 +6872,14 @@ var require_parser = __commonJS({
|
|
|
6872
6872
|
case "scalar":
|
|
6873
6873
|
case "single-quoted-scalar":
|
|
6874
6874
|
case "double-quoted-scalar": {
|
|
6875
|
-
const
|
|
6875
|
+
const fs22 = this.flowScalar(this.type);
|
|
6876
6876
|
if (atNextItem || it.value) {
|
|
6877
|
-
map.items.push({ start, key:
|
|
6877
|
+
map.items.push({ start, key: fs22, sep: [] });
|
|
6878
6878
|
this.onKeyLine = true;
|
|
6879
6879
|
} else if (it.sep) {
|
|
6880
|
-
this.stack.push(
|
|
6880
|
+
this.stack.push(fs22);
|
|
6881
6881
|
} else {
|
|
6882
|
-
Object.assign(it, { key:
|
|
6882
|
+
Object.assign(it, { key: fs22, sep: [] });
|
|
6883
6883
|
this.onKeyLine = true;
|
|
6884
6884
|
}
|
|
6885
6885
|
return;
|
|
@@ -7007,13 +7007,13 @@ var require_parser = __commonJS({
|
|
|
7007
7007
|
case "scalar":
|
|
7008
7008
|
case "single-quoted-scalar":
|
|
7009
7009
|
case "double-quoted-scalar": {
|
|
7010
|
-
const
|
|
7010
|
+
const fs22 = this.flowScalar(this.type);
|
|
7011
7011
|
if (!it || it.value)
|
|
7012
|
-
fc.items.push({ start: [], key:
|
|
7012
|
+
fc.items.push({ start: [], key: fs22, sep: [] });
|
|
7013
7013
|
else if (it.sep)
|
|
7014
|
-
this.stack.push(
|
|
7014
|
+
this.stack.push(fs22);
|
|
7015
7015
|
else
|
|
7016
|
-
Object.assign(it, { key:
|
|
7016
|
+
Object.assign(it, { key: fs22, sep: [] });
|
|
7017
7017
|
return;
|
|
7018
7018
|
}
|
|
7019
7019
|
case "flow-map-end":
|
|
@@ -7551,17 +7551,17 @@ var require_ignore = __commonJS({
|
|
|
7551
7551
|
var throwError = (message, Ctor) => {
|
|
7552
7552
|
throw new Ctor(message);
|
|
7553
7553
|
};
|
|
7554
|
-
var checkPath = (
|
|
7555
|
-
if (!isString(
|
|
7554
|
+
var checkPath = (path23, originalPath, doThrow) => {
|
|
7555
|
+
if (!isString(path23)) {
|
|
7556
7556
|
return doThrow(
|
|
7557
7557
|
`path must be a string, but got \`${originalPath}\``,
|
|
7558
7558
|
TypeError
|
|
7559
7559
|
);
|
|
7560
7560
|
}
|
|
7561
|
-
if (!
|
|
7561
|
+
if (!path23) {
|
|
7562
7562
|
return doThrow(`path must not be empty`, TypeError);
|
|
7563
7563
|
}
|
|
7564
|
-
if (checkPath.isNotRelative(
|
|
7564
|
+
if (checkPath.isNotRelative(path23)) {
|
|
7565
7565
|
const r = "`path.relative()`d";
|
|
7566
7566
|
return doThrow(
|
|
7567
7567
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -7570,7 +7570,7 @@ var require_ignore = __commonJS({
|
|
|
7570
7570
|
}
|
|
7571
7571
|
return true;
|
|
7572
7572
|
};
|
|
7573
|
-
var isNotRelative = (
|
|
7573
|
+
var isNotRelative = (path23) => REGEX_TEST_INVALID_PATH.test(path23);
|
|
7574
7574
|
checkPath.isNotRelative = isNotRelative;
|
|
7575
7575
|
checkPath.convert = (p) => p;
|
|
7576
7576
|
var Ignore = class {
|
|
@@ -7629,7 +7629,7 @@ var require_ignore = __commonJS({
|
|
|
7629
7629
|
// setting `checkUnignored` to `false` could reduce additional
|
|
7630
7630
|
// path matching.
|
|
7631
7631
|
// @returns {TestResult} true if a file is ignored
|
|
7632
|
-
_testOne(
|
|
7632
|
+
_testOne(path23, checkUnignored) {
|
|
7633
7633
|
let ignored = false;
|
|
7634
7634
|
let unignored = false;
|
|
7635
7635
|
this._rules.forEach((rule) => {
|
|
@@ -7637,7 +7637,7 @@ var require_ignore = __commonJS({
|
|
|
7637
7637
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
7638
7638
|
return;
|
|
7639
7639
|
}
|
|
7640
|
-
const matched = rule.regex.test(
|
|
7640
|
+
const matched = rule.regex.test(path23);
|
|
7641
7641
|
if (matched) {
|
|
7642
7642
|
ignored = !negative;
|
|
7643
7643
|
unignored = negative;
|
|
@@ -7650,24 +7650,24 @@ var require_ignore = __commonJS({
|
|
|
7650
7650
|
}
|
|
7651
7651
|
// @returns {TestResult}
|
|
7652
7652
|
_test(originalPath, cache, checkUnignored, slices) {
|
|
7653
|
-
const
|
|
7653
|
+
const path23 = originalPath && checkPath.convert(originalPath);
|
|
7654
7654
|
checkPath(
|
|
7655
|
-
|
|
7655
|
+
path23,
|
|
7656
7656
|
originalPath,
|
|
7657
7657
|
this._allowRelativePaths ? RETURN_FALSE : throwError
|
|
7658
7658
|
);
|
|
7659
|
-
return this._t(
|
|
7659
|
+
return this._t(path23, cache, checkUnignored, slices);
|
|
7660
7660
|
}
|
|
7661
|
-
_t(
|
|
7662
|
-
if (
|
|
7663
|
-
return cache[
|
|
7661
|
+
_t(path23, cache, checkUnignored, slices) {
|
|
7662
|
+
if (path23 in cache) {
|
|
7663
|
+
return cache[path23];
|
|
7664
7664
|
}
|
|
7665
7665
|
if (!slices) {
|
|
7666
|
-
slices =
|
|
7666
|
+
slices = path23.split(SLASH);
|
|
7667
7667
|
}
|
|
7668
7668
|
slices.pop();
|
|
7669
7669
|
if (!slices.length) {
|
|
7670
|
-
return cache[
|
|
7670
|
+
return cache[path23] = this._testOne(path23, checkUnignored);
|
|
7671
7671
|
}
|
|
7672
7672
|
const parent = this._t(
|
|
7673
7673
|
slices.join(SLASH) + SLASH,
|
|
@@ -7675,24 +7675,24 @@ var require_ignore = __commonJS({
|
|
|
7675
7675
|
checkUnignored,
|
|
7676
7676
|
slices
|
|
7677
7677
|
);
|
|
7678
|
-
return cache[
|
|
7678
|
+
return cache[path23] = parent.ignored ? parent : this._testOne(path23, checkUnignored);
|
|
7679
7679
|
}
|
|
7680
|
-
ignores(
|
|
7681
|
-
return this._test(
|
|
7680
|
+
ignores(path23) {
|
|
7681
|
+
return this._test(path23, this._ignoreCache, false).ignored;
|
|
7682
7682
|
}
|
|
7683
7683
|
createFilter() {
|
|
7684
|
-
return (
|
|
7684
|
+
return (path23) => !this.ignores(path23);
|
|
7685
7685
|
}
|
|
7686
7686
|
filter(paths) {
|
|
7687
7687
|
return makeArray(paths).filter(this.createFilter());
|
|
7688
7688
|
}
|
|
7689
7689
|
// @returns {TestResult}
|
|
7690
|
-
test(
|
|
7691
|
-
return this._test(
|
|
7690
|
+
test(path23) {
|
|
7691
|
+
return this._test(path23, this._testCache, true);
|
|
7692
7692
|
}
|
|
7693
7693
|
};
|
|
7694
7694
|
var factory = (options) => new Ignore(options);
|
|
7695
|
-
var isPathValid = (
|
|
7695
|
+
var isPathValid = (path23) => checkPath(path23 && checkPath.convert(path23), path23, RETURN_FALSE);
|
|
7696
7696
|
factory.isPathValid = isPathValid;
|
|
7697
7697
|
factory.default = factory;
|
|
7698
7698
|
module.exports = factory;
|
|
@@ -7703,22 +7703,22 @@ var require_ignore = __commonJS({
|
|
|
7703
7703
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
7704
7704
|
checkPath.convert = makePosix;
|
|
7705
7705
|
const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
7706
|
-
checkPath.isNotRelative = (
|
|
7706
|
+
checkPath.isNotRelative = (path23) => REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path23) || isNotRelative(path23);
|
|
7707
7707
|
}
|
|
7708
7708
|
}
|
|
7709
7709
|
});
|
|
7710
7710
|
|
|
7711
7711
|
// src/sanitize_cli.js
|
|
7712
|
-
import
|
|
7712
|
+
import fs21 from "node:fs";
|
|
7713
7713
|
import os7 from "node:os";
|
|
7714
|
-
import
|
|
7714
|
+
import path22 from "node:path";
|
|
7715
7715
|
import { execFileSync as execFileSync2, spawnSync } from "node:child_process";
|
|
7716
7716
|
|
|
7717
7717
|
// src/plugin.js
|
|
7718
|
-
import
|
|
7718
|
+
import fs20 from "node:fs";
|
|
7719
7719
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
7720
7720
|
var import_ignore3 = __toESM(require_ignore(), 1);
|
|
7721
|
-
import
|
|
7721
|
+
import path21 from "node:path";
|
|
7722
7722
|
import { tool } from "@opencode-ai/plugin/tool";
|
|
7723
7723
|
|
|
7724
7724
|
// src/agents.js
|
|
@@ -13507,28 +13507,285 @@ function createGitHubApiClient(config = {}, fetchImpl = globalThis.fetch) {
|
|
|
13507
13507
|
}
|
|
13508
13508
|
|
|
13509
13509
|
// src/qa/chrome.js
|
|
13510
|
-
import
|
|
13510
|
+
import fs17 from "node:fs";
|
|
13511
13511
|
import os6 from "node:os";
|
|
13512
|
-
import
|
|
13512
|
+
import path18 from "node:path";
|
|
13513
13513
|
|
|
13514
|
-
// src/qa/
|
|
13514
|
+
// src/qa/cdp.js
|
|
13515
13515
|
import fs15 from "node:fs";
|
|
13516
|
-
import os5 from "node:os";
|
|
13517
13516
|
import path16 from "node:path";
|
|
13517
|
+
var DEFAULT_CDP_URL = "http://127.0.0.1:9222";
|
|
13518
|
+
function normalizeBaseUrl(cdpUrl = "") {
|
|
13519
|
+
return String(cdpUrl || process.env.OPTIMA_QA_CHROME_CDP_URL || DEFAULT_CDP_URL).trim().replace(/\/+$/, "");
|
|
13520
|
+
}
|
|
13521
|
+
async function cdpJson(baseUrl, route, options = {}) {
|
|
13522
|
+
const response = await fetch(`${baseUrl}${route}`, options);
|
|
13523
|
+
if (!response.ok) throw new Error(`cdp_http_${response.status}: ${route}`);
|
|
13524
|
+
return response.json();
|
|
13525
|
+
}
|
|
13526
|
+
async function listCdpTargets({ cdpUrl = "" } = {}) {
|
|
13527
|
+
const baseUrl = normalizeBaseUrl(cdpUrl);
|
|
13528
|
+
return cdpJson(baseUrl, "/json/list");
|
|
13529
|
+
}
|
|
13530
|
+
async function cdpBrowserStatus({ cdpUrl = "", clickupTaskId = "", qaWindowName: qaWindowName2 = null } = {}) {
|
|
13531
|
+
const targets = await listCdpTargets({ cdpUrl });
|
|
13532
|
+
const pages = [];
|
|
13533
|
+
for (let index = 0; index < targets.length; index += 1) {
|
|
13534
|
+
const target = targets[index];
|
|
13535
|
+
if (target.type !== "page") continue;
|
|
13536
|
+
let windowName = "";
|
|
13537
|
+
if (target.webSocketDebuggerUrl) {
|
|
13538
|
+
const session = await CdpSession.connect(target.webSocketDebuggerUrl).catch(() => null);
|
|
13539
|
+
if (session) {
|
|
13540
|
+
try {
|
|
13541
|
+
const evaluated = await session.evaluate("window.name || ''");
|
|
13542
|
+
windowName = String(evaluated?.value || "");
|
|
13543
|
+
} finally {
|
|
13544
|
+
session.close();
|
|
13545
|
+
}
|
|
13546
|
+
}
|
|
13547
|
+
}
|
|
13548
|
+
pages.push({
|
|
13549
|
+
index,
|
|
13550
|
+
id: target.id,
|
|
13551
|
+
role: index === 0 ? "persistent_session_tab" : qaWindowName2 && windowName === qaWindowName2(clickupTaskId) ? "qa_task_tab" : "other",
|
|
13552
|
+
url: target.url,
|
|
13553
|
+
title: target.title || "",
|
|
13554
|
+
windowName
|
|
13555
|
+
});
|
|
13556
|
+
}
|
|
13557
|
+
return { ok: true, pages, serviceWorkers: targets.filter((target) => target.type === "service_worker").map((target) => target.url) };
|
|
13558
|
+
}
|
|
13559
|
+
var CdpSession = class _CdpSession {
|
|
13560
|
+
constructor(ws) {
|
|
13561
|
+
this.ws = ws;
|
|
13562
|
+
this.nextId = 1;
|
|
13563
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
13564
|
+
this.ws.addEventListener("message", (event) => this.handleMessage(event));
|
|
13565
|
+
this.ws.addEventListener("close", () => this.rejectAll(new Error("cdp_websocket_closed")));
|
|
13566
|
+
this.ws.addEventListener("error", () => this.rejectAll(new Error("cdp_websocket_error")));
|
|
13567
|
+
}
|
|
13568
|
+
static connect(wsUrl, { timeoutMs = 1e4 } = {}) {
|
|
13569
|
+
return new Promise((resolve, reject) => {
|
|
13570
|
+
const ws = new WebSocket(wsUrl);
|
|
13571
|
+
const timer = setTimeout(() => {
|
|
13572
|
+
try {
|
|
13573
|
+
ws.close();
|
|
13574
|
+
} catch {
|
|
13575
|
+
}
|
|
13576
|
+
reject(new Error("cdp_websocket_connect_timeout"));
|
|
13577
|
+
}, timeoutMs);
|
|
13578
|
+
ws.addEventListener("open", () => {
|
|
13579
|
+
clearTimeout(timer);
|
|
13580
|
+
resolve(new _CdpSession(ws));
|
|
13581
|
+
}, { once: true });
|
|
13582
|
+
ws.addEventListener("error", () => {
|
|
13583
|
+
clearTimeout(timer);
|
|
13584
|
+
reject(new Error("cdp_websocket_connect_failed"));
|
|
13585
|
+
}, { once: true });
|
|
13586
|
+
});
|
|
13587
|
+
}
|
|
13588
|
+
handleMessage(event) {
|
|
13589
|
+
let message = null;
|
|
13590
|
+
try {
|
|
13591
|
+
message = JSON.parse(event.data);
|
|
13592
|
+
} catch {
|
|
13593
|
+
return;
|
|
13594
|
+
}
|
|
13595
|
+
if (!message?.id || !this.pending.has(message.id)) return;
|
|
13596
|
+
const pending = this.pending.get(message.id);
|
|
13597
|
+
this.pending.delete(message.id);
|
|
13598
|
+
clearTimeout(pending.timer);
|
|
13599
|
+
if (message.error) pending.reject(new Error(`${message.error.message || "cdp_error"}${message.error.data ? `: ${message.error.data}` : ""}`));
|
|
13600
|
+
else pending.resolve(message.result || {});
|
|
13601
|
+
}
|
|
13602
|
+
rejectAll(error) {
|
|
13603
|
+
for (const pending of this.pending.values()) {
|
|
13604
|
+
clearTimeout(pending.timer);
|
|
13605
|
+
pending.reject(error);
|
|
13606
|
+
}
|
|
13607
|
+
this.pending.clear();
|
|
13608
|
+
}
|
|
13609
|
+
send(method, params = {}, { timeoutMs = 3e4 } = {}) {
|
|
13610
|
+
const id = this.nextId;
|
|
13611
|
+
this.nextId += 1;
|
|
13612
|
+
return new Promise((resolve, reject) => {
|
|
13613
|
+
const timer = setTimeout(() => {
|
|
13614
|
+
this.pending.delete(id);
|
|
13615
|
+
reject(new Error(`cdp_command_timeout: ${method}`));
|
|
13616
|
+
}, timeoutMs);
|
|
13617
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
13618
|
+
this.ws.send(JSON.stringify({ id, method, params }));
|
|
13619
|
+
});
|
|
13620
|
+
}
|
|
13621
|
+
async evaluate(expression, { timeoutMs = 3e4 } = {}) {
|
|
13622
|
+
const result = await this.send("Runtime.evaluate", {
|
|
13623
|
+
expression,
|
|
13624
|
+
awaitPromise: true,
|
|
13625
|
+
returnByValue: true
|
|
13626
|
+
}, { timeoutMs });
|
|
13627
|
+
if (result.exceptionDetails) throw new Error(result.exceptionDetails.text || "runtime_evaluate_failed");
|
|
13628
|
+
return result.result || null;
|
|
13629
|
+
}
|
|
13630
|
+
close() {
|
|
13631
|
+
try {
|
|
13632
|
+
this.ws.close();
|
|
13633
|
+
} catch {
|
|
13634
|
+
}
|
|
13635
|
+
}
|
|
13636
|
+
};
|
|
13637
|
+
async function newCdpTarget({ cdpUrl = "", startUrl = "about:blank" } = {}) {
|
|
13638
|
+
const baseUrl = normalizeBaseUrl(cdpUrl);
|
|
13639
|
+
return cdpJson(baseUrl, `/json/new?${encodeURIComponent(startUrl)}`, { method: "PUT" });
|
|
13640
|
+
}
|
|
13641
|
+
async function targetWindowName(target) {
|
|
13642
|
+
if (!target.webSocketDebuggerUrl) return "";
|
|
13643
|
+
const session = await CdpSession.connect(target.webSocketDebuggerUrl);
|
|
13644
|
+
try {
|
|
13645
|
+
const value = await session.evaluate("window.name || ''");
|
|
13646
|
+
return String(value?.value || "");
|
|
13647
|
+
} finally {
|
|
13648
|
+
session.close();
|
|
13649
|
+
}
|
|
13650
|
+
}
|
|
13651
|
+
async function ensureCdpQaTarget({ cdpUrl = "", clickupTaskId = "", startUrl = "about:blank", qaWindowName: qaWindowName2 } = {}) {
|
|
13652
|
+
const expected = qaWindowName2(clickupTaskId);
|
|
13653
|
+
const targets = (await listCdpTargets({ cdpUrl })).filter((target2) => target2.type === "page");
|
|
13654
|
+
for (let index = 1; index < targets.length; index += 1) {
|
|
13655
|
+
if (await targetWindowName(targets[index]).catch(() => "") === expected) return targets[index];
|
|
13656
|
+
}
|
|
13657
|
+
const target = await newCdpTarget({ cdpUrl, startUrl });
|
|
13658
|
+
const session = await CdpSession.connect(target.webSocketDebuggerUrl);
|
|
13659
|
+
try {
|
|
13660
|
+
await session.evaluate(`window.name = ${JSON.stringify(expected)}`);
|
|
13661
|
+
} finally {
|
|
13662
|
+
session.close();
|
|
13663
|
+
}
|
|
13664
|
+
return target;
|
|
13665
|
+
}
|
|
13666
|
+
function parseCdpCommand(commandJson = "") {
|
|
13667
|
+
if (!String(commandJson || "").trim()) return { action: "status" };
|
|
13668
|
+
try {
|
|
13669
|
+
const parsed = JSON.parse(commandJson);
|
|
13670
|
+
return parsed && typeof parsed === "object" ? parsed : { action: "invalid" };
|
|
13671
|
+
} catch {
|
|
13672
|
+
return { action: "script", script: String(commandJson || "") };
|
|
13673
|
+
}
|
|
13674
|
+
}
|
|
13675
|
+
async function pageSnapshot(session) {
|
|
13676
|
+
const evaluated = await session.evaluate("({ url: location.href, title: document.title })");
|
|
13677
|
+
return evaluated?.value || { url: "", title: "" };
|
|
13678
|
+
}
|
|
13679
|
+
async function cdpRunChromeCommand({ cdpUrl = "", clickupTaskId = "", commandJson = "", startUrl = "about:blank", artifactsDir, qaWindowName: qaWindowName2 } = {}) {
|
|
13680
|
+
const command = parseCdpCommand(commandJson);
|
|
13681
|
+
const target = await ensureCdpQaTarget({ cdpUrl, clickupTaskId, startUrl, qaWindowName: qaWindowName2 });
|
|
13682
|
+
const session = await CdpSession.connect(target.webSocketDebuggerUrl);
|
|
13683
|
+
try {
|
|
13684
|
+
const action = String(command.action || "status").toLowerCase();
|
|
13685
|
+
let result = null;
|
|
13686
|
+
if (action === "status") {
|
|
13687
|
+
result = { ok: true, page: await pageSnapshot(session) };
|
|
13688
|
+
} else if (action === "goto") {
|
|
13689
|
+
await session.send("Page.enable");
|
|
13690
|
+
await session.send("Page.navigate", { url: String(command.url || startUrl || "about:blank") });
|
|
13691
|
+
if (command.wait_ms !== false) await new Promise((resolve) => setTimeout(resolve, Number(command.wait_ms || 1e3)));
|
|
13692
|
+
result = { ok: true, page: await pageSnapshot(session) };
|
|
13693
|
+
} else if (action === "evaluate") {
|
|
13694
|
+
const evaluated = await session.evaluate(String(command.expression || "undefined"), { timeoutMs: Number(command.timeout_ms || 3e4) });
|
|
13695
|
+
result = { ok: true, result: evaluated?.value ?? evaluated };
|
|
13696
|
+
} else if (action === "screenshot") {
|
|
13697
|
+
await session.send("Page.enable");
|
|
13698
|
+
const captured = await session.send("Page.captureScreenshot", { format: command.format || "png", captureBeyondViewport: command.full_page !== false });
|
|
13699
|
+
const name = String(command.name || `screenshot-${Date.now()}.png`).replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
13700
|
+
const outPath = path16.join(artifactsDir, name);
|
|
13701
|
+
fs15.mkdirSync(path16.dirname(outPath), { recursive: true });
|
|
13702
|
+
fs15.writeFileSync(outPath, Buffer.from(captured.data || "", "base64"));
|
|
13703
|
+
result = { ok: true, path: outPath };
|
|
13704
|
+
} else if (action === "script") {
|
|
13705
|
+
const script = String(command.script || "");
|
|
13706
|
+
if (!script.trim()) return { ok: false, error: "script_required" };
|
|
13707
|
+
const cdp = { send: (method, params = {}, options = {}) => session.send(method, params, options), evaluate: (expression, options = {}) => session.evaluate(expression, options) };
|
|
13708
|
+
const fn = new Function("cdp", "target", "artifactsDir", "command", `return (async () => {
|
|
13709
|
+
${script}
|
|
13710
|
+
})()`);
|
|
13711
|
+
result = { ok: true, result: await fn(cdp, target, artifactsDir, command) };
|
|
13712
|
+
} else {
|
|
13713
|
+
result = { ok: false, error: `unsupported_cdp_command_action: ${action}` };
|
|
13714
|
+
}
|
|
13715
|
+
return {
|
|
13716
|
+
ok: result.ok !== false,
|
|
13717
|
+
command: command.action || "script",
|
|
13718
|
+
tab: { windowName: qaWindowName2(clickupTaskId), ...await pageSnapshot(session) },
|
|
13719
|
+
artifactsDir,
|
|
13720
|
+
result,
|
|
13721
|
+
transport: "cdp"
|
|
13722
|
+
};
|
|
13723
|
+
} finally {
|
|
13724
|
+
session.close();
|
|
13725
|
+
}
|
|
13726
|
+
}
|
|
13727
|
+
async function cdpPrepareExtension({ cdpUrl = "", extensionId = "", reset = true, reload = true } = {}) {
|
|
13728
|
+
const targets = await listCdpTargets({ cdpUrl });
|
|
13729
|
+
const normalized = String(extensionId || "").trim();
|
|
13730
|
+
const worker = targets.find((target) => target.type === "service_worker" && (!normalized || String(target.url || "").startsWith(`chrome-extension://${normalized}/`)));
|
|
13731
|
+
if (!worker?.webSocketDebuggerUrl) return { ok: false, error: "extension_service_worker_not_found", serviceWorkers: targets.filter((target) => target.type === "service_worker").map((target) => target.url) };
|
|
13732
|
+
const session = await CdpSession.connect(worker.webSocketDebuggerUrl);
|
|
13733
|
+
try {
|
|
13734
|
+
let resetResult = { ok: true, skipped: true };
|
|
13735
|
+
let reloadResult = { ok: true, skipped: true };
|
|
13736
|
+
if (reset) {
|
|
13737
|
+
const evaluated = await session.evaluate(`(async () => {
|
|
13738
|
+
const deletedCaches = [];
|
|
13739
|
+
const deletedDbs = [];
|
|
13740
|
+
if (globalThis.chrome?.storage?.local) await chrome.storage.local.clear();
|
|
13741
|
+
if (globalThis.chrome?.storage?.session?.clear) await chrome.storage.session.clear();
|
|
13742
|
+
if (globalThis.chrome?.storage?.sync) await chrome.storage.sync.clear();
|
|
13743
|
+
if (globalThis.caches?.keys) {
|
|
13744
|
+
for (const name of await caches.keys()) {
|
|
13745
|
+
await caches.delete(name);
|
|
13746
|
+
deletedCaches.push(name);
|
|
13747
|
+
}
|
|
13748
|
+
}
|
|
13749
|
+
if (globalThis.indexedDB?.databases) {
|
|
13750
|
+
for (const db of await indexedDB.databases()) {
|
|
13751
|
+
if (db.name) {
|
|
13752
|
+
indexedDB.deleteDatabase(db.name);
|
|
13753
|
+
deletedDbs.push(db.name);
|
|
13754
|
+
}
|
|
13755
|
+
}
|
|
13756
|
+
}
|
|
13757
|
+
return { ok: true, deletedCaches, deletedDbs };
|
|
13758
|
+
})()`);
|
|
13759
|
+
resetResult = evaluated?.value || { ok: true };
|
|
13760
|
+
}
|
|
13761
|
+
if (reload) {
|
|
13762
|
+
await session.evaluate("chrome.runtime.reload()");
|
|
13763
|
+
reloadResult = { ok: true };
|
|
13764
|
+
}
|
|
13765
|
+
return { ok: true, reset: resetResult, reload: reloadResult };
|
|
13766
|
+
} finally {
|
|
13767
|
+
session.close();
|
|
13768
|
+
}
|
|
13769
|
+
}
|
|
13770
|
+
|
|
13771
|
+
// src/qa/queue.js
|
|
13772
|
+
import fs16 from "node:fs";
|
|
13773
|
+
import os5 from "node:os";
|
|
13774
|
+
import path17 from "node:path";
|
|
13518
13775
|
var DEFAULT_QA_LEASE_MS = 5 * 60 * 1e3;
|
|
13519
13776
|
var DEFAULT_QA_PROVIDER = "chatgpt";
|
|
13520
13777
|
function dataHome() {
|
|
13521
|
-
return process.env.XDG_DATA_HOME &&
|
|
13778
|
+
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");
|
|
13522
13779
|
}
|
|
13523
13780
|
function qaRuntimeDir() {
|
|
13524
|
-
return
|
|
13781
|
+
return path17.join(dataHome(), "opencode-optima", "qa");
|
|
13525
13782
|
}
|
|
13526
13783
|
function normalizeQaProvider(provider = DEFAULT_QA_PROVIDER) {
|
|
13527
13784
|
const normalized = String(provider || DEFAULT_QA_PROVIDER).trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-");
|
|
13528
13785
|
return normalized || DEFAULT_QA_PROVIDER;
|
|
13529
13786
|
}
|
|
13530
13787
|
function qaQueueStatePath(provider = DEFAULT_QA_PROVIDER) {
|
|
13531
|
-
return
|
|
13788
|
+
return path17.join(qaRuntimeDir(), `${normalizeQaProvider(provider)}-queue.json`);
|
|
13532
13789
|
}
|
|
13533
13790
|
function nowIso(now = /* @__PURE__ */ new Date()) {
|
|
13534
13791
|
return now instanceof Date ? now.toISOString() : new Date(now).toISOString();
|
|
@@ -13546,7 +13803,7 @@ function emptyQaQueueState(provider = DEFAULT_QA_PROVIDER) {
|
|
|
13546
13803
|
}
|
|
13547
13804
|
function readQaQueueState(provider = DEFAULT_QA_PROVIDER, statePath = qaQueueStatePath(provider)) {
|
|
13548
13805
|
try {
|
|
13549
|
-
const raw =
|
|
13806
|
+
const raw = fs16.readFileSync(statePath, "utf8");
|
|
13550
13807
|
const parsed = JSON.parse(raw);
|
|
13551
13808
|
if (!isPlainObject(parsed)) return emptyQaQueueState(provider);
|
|
13552
13809
|
return {
|
|
@@ -13568,8 +13825,8 @@ function writeQaQueueState(state, statePath = qaQueueStatePath(state?.provider))
|
|
|
13568
13825
|
queue: Array.isArray(state?.queue) ? state.queue.filter(isPlainObject) : [],
|
|
13569
13826
|
history: Array.isArray(state?.history) ? state.history.filter(isPlainObject).slice(-50) : []
|
|
13570
13827
|
};
|
|
13571
|
-
|
|
13572
|
-
|
|
13828
|
+
fs16.mkdirSync(path17.dirname(statePath), { recursive: true });
|
|
13829
|
+
fs16.writeFileSync(statePath, `${JSON.stringify(normalized, null, 2)}
|
|
13573
13830
|
`, { mode: 384 });
|
|
13574
13831
|
return normalized;
|
|
13575
13832
|
}
|
|
@@ -13676,14 +13933,15 @@ function finishQaSlot(state, { clickupTaskId, now = /* @__PURE__ */ new Date(),
|
|
|
13676
13933
|
|
|
13677
13934
|
// src/qa/chrome.js
|
|
13678
13935
|
var DEFAULT_QA_CDP_URL = "http://127.0.0.1:9222";
|
|
13936
|
+
var DEFAULT_QA_PLAYWRIGHT_CONNECT_TIMEOUT_MS = 5e3;
|
|
13679
13937
|
function providerDir(provider = DEFAULT_QA_PROVIDER) {
|
|
13680
|
-
return
|
|
13938
|
+
return path18.join(qaRuntimeDir(), normalizeQaProvider(provider));
|
|
13681
13939
|
}
|
|
13682
13940
|
function defaultQaExtensionStageDir(provider = DEFAULT_QA_PROVIDER) {
|
|
13683
|
-
return
|
|
13941
|
+
return path18.join(providerDir(provider), "extension-under-test");
|
|
13684
13942
|
}
|
|
13685
13943
|
function defaultQaArtifactsDir(provider = DEFAULT_QA_PROVIDER, clickupTaskId = "unknown") {
|
|
13686
|
-
return
|
|
13944
|
+
return path18.join(providerDir(provider), "artifacts", String(clickupTaskId || "unknown"));
|
|
13687
13945
|
}
|
|
13688
13946
|
function normalizeCdpUrl(value = "") {
|
|
13689
13947
|
return String(value || process.env.OPTIMA_QA_CHROME_CDP_URL || DEFAULT_QA_CDP_URL).trim() || DEFAULT_QA_CDP_URL;
|
|
@@ -13739,11 +13997,11 @@ async function ensureQaPage(context, { clickupTaskId, startUrl = "https://chatgp
|
|
|
13739
13997
|
function copyExtensionSource(sourcePath, stageDir) {
|
|
13740
13998
|
const source = String(sourcePath || "").trim();
|
|
13741
13999
|
if (!source) return { ok: true, skipped: true, reason: "extension_path_not_provided", stageDir };
|
|
13742
|
-
const resolved =
|
|
13743
|
-
if (!
|
|
13744
|
-
|
|
13745
|
-
|
|
13746
|
-
|
|
14000
|
+
const resolved = path18.resolve(source.replace(/^~(?=$|\/)/, os6.homedir()));
|
|
14001
|
+
if (!fs17.existsSync(resolved)) return { ok: false, error: `extension_path_not_found: ${resolved}`, stageDir };
|
|
14002
|
+
fs17.rmSync(stageDir, { recursive: true, force: true });
|
|
14003
|
+
fs17.mkdirSync(path18.dirname(stageDir), { recursive: true });
|
|
14004
|
+
fs17.cpSync(resolved, stageDir, {
|
|
13747
14005
|
recursive: true,
|
|
13748
14006
|
filter: (src) => !/[/\\](node_modules|\.git|dist|build|test-results)([/\\]|$)/.test(src)
|
|
13749
14007
|
});
|
|
@@ -13832,8 +14090,8 @@ async function runQaCommandOnPage(page, context, browser, command, { artifactsDi
|
|
|
13832
14090
|
}
|
|
13833
14091
|
if (action === "screenshot") {
|
|
13834
14092
|
const name = String(command.name || `screenshot-${Date.now()}.png`).replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
13835
|
-
const outPath =
|
|
13836
|
-
|
|
14093
|
+
const outPath = path18.join(artifactsDir, name);
|
|
14094
|
+
fs17.mkdirSync(path18.dirname(outPath), { recursive: true });
|
|
13837
14095
|
await page.screenshot({ path: outPath, fullPage: command.full_page !== false });
|
|
13838
14096
|
return { ok: true, path: outPath };
|
|
13839
14097
|
}
|
|
@@ -13855,7 +14113,9 @@ ${script}
|
|
|
13855
14113
|
}
|
|
13856
14114
|
async function withQaBrowser({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "", clickupTaskId = "", startUrl = "https://chatgpt.com/" } = {}, callback) {
|
|
13857
14115
|
const chromium = await loadPlaywrightChromium();
|
|
13858
|
-
const browser = await chromium.connectOverCDP(normalizeCdpUrl(cdpUrl)
|
|
14116
|
+
const browser = await chromium.connectOverCDP(normalizeCdpUrl(cdpUrl), {
|
|
14117
|
+
timeout: Number(process.env.OPTIMA_QA_PLAYWRIGHT_CONNECT_TIMEOUT_MS || DEFAULT_QA_PLAYWRIGHT_CONNECT_TIMEOUT_MS)
|
|
14118
|
+
});
|
|
13859
14119
|
try {
|
|
13860
14120
|
const context = browser.contexts()[0] || await browser.newContext();
|
|
13861
14121
|
const page = clickupTaskId ? await ensureQaPage(context, { clickupTaskId, startUrl }) : null;
|
|
@@ -13866,7 +14126,10 @@ async function withQaBrowser({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "", clic
|
|
|
13866
14126
|
}
|
|
13867
14127
|
}
|
|
13868
14128
|
async function qaBrowserStatus(options = {}) {
|
|
13869
|
-
return withQaBrowser(options, async ({ context }) => ({ ok: true, ...await summarizeBrowser(context, { clickupTaskId: options.clickupTaskId }) })).catch((error) =>
|
|
14129
|
+
return withQaBrowser(options, async ({ context }) => ({ ok: true, ...await summarizeBrowser(context, { clickupTaskId: options.clickupTaskId }) })).catch(async (error) => {
|
|
14130
|
+
const fallback = await cdpBrowserStatus({ cdpUrl: options.cdpUrl, clickupTaskId: options.clickupTaskId, qaWindowName }).catch((fallbackError) => ({ ok: false, error: fallbackError.message }));
|
|
14131
|
+
return fallback.ok ? { ...fallback, fallback: "cdp", playwrightError: error.message } : { ok: false, error: error.message, fallbackError: fallback.error, cdpUrl: normalizeCdpUrl(options.cdpUrl) };
|
|
14132
|
+
});
|
|
13870
14133
|
}
|
|
13871
14134
|
async function qaPrepareExtension({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "", extensionPath = "", extensionId = "", reset = true, reload = true } = {}) {
|
|
13872
14135
|
const stageDir = defaultQaExtensionStageDir(provider);
|
|
@@ -13875,7 +14138,10 @@ async function qaPrepareExtension({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "",
|
|
|
13875
14138
|
const resetResult = reset ? await resetExtensionState(context, { extensionId }).catch((error) => ({ ok: false, error: error.message })) : { ok: true, skipped: true };
|
|
13876
14139
|
const reloadResult = reload ? await reloadExtension(context, { extensionId }).catch((error) => ({ ok: false, error: error.message })) : { ok: true, skipped: true };
|
|
13877
14140
|
return { reset: resetResult, reload: reloadResult, browser: await summarizeBrowser(context) };
|
|
13878
|
-
}).catch((error) =>
|
|
14141
|
+
}).catch(async (error) => {
|
|
14142
|
+
const fallback = await cdpPrepareExtension({ cdpUrl, extensionId, reset, reload }).catch((fallbackError) => ({ ok: false, error: fallbackError.message }));
|
|
14143
|
+
return fallback.ok ? { ...fallback, fallback: "cdp", playwrightError: error.message } : { ok: false, error: error.message, fallbackError: fallback.error };
|
|
14144
|
+
});
|
|
13879
14145
|
return { sync, ...browserResult };
|
|
13880
14146
|
}
|
|
13881
14147
|
async function qaRunChromeCommand({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "", clickupTaskId = "", commandJson = "", startUrl = "https://chatgpt.com/" } = {}) {
|
|
@@ -13884,14 +14150,24 @@ async function qaRunChromeCommand({ provider = DEFAULT_QA_PROVIDER, cdpUrl = "",
|
|
|
13884
14150
|
return withQaBrowser({ provider, cdpUrl, clickupTaskId, startUrl }, async ({ browser, context, page }) => {
|
|
13885
14151
|
const result = await runQaCommandOnPage(page, context, browser, command, { artifactsDir });
|
|
13886
14152
|
return { ok: result.ok !== false, command: command.action || "script", tab: { windowName: qaWindowName(clickupTaskId), url: page.url(), title: await page.title().catch(() => "") }, artifactsDir, result };
|
|
14153
|
+
}).catch(async (error) => {
|
|
14154
|
+
const fallback = await cdpRunChromeCommand({
|
|
14155
|
+
cdpUrl,
|
|
14156
|
+
clickupTaskId,
|
|
14157
|
+
commandJson,
|
|
14158
|
+
startUrl,
|
|
14159
|
+
artifactsDir,
|
|
14160
|
+
qaWindowName
|
|
14161
|
+
}).catch((fallbackError) => ({ ok: false, error: fallbackError.message }));
|
|
14162
|
+
return fallback.ok ? { ...fallback, fallback: "cdp", playwrightError: error.message } : { ok: false, error: error.message, fallbackError: fallback.error };
|
|
13887
14163
|
});
|
|
13888
14164
|
}
|
|
13889
14165
|
|
|
13890
14166
|
// src/repair.js
|
|
13891
14167
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
13892
14168
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
13893
|
-
import
|
|
13894
|
-
import
|
|
14169
|
+
import fs18 from "node:fs";
|
|
14170
|
+
import path19 from "node:path";
|
|
13895
14171
|
var CODEMAP_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
13896
14172
|
".js",
|
|
13897
14173
|
".ts",
|
|
@@ -13929,10 +14205,10 @@ var LEGACY_OPERATIONAL_ROOTS = /* @__PURE__ */ new Set([
|
|
|
13929
14205
|
]);
|
|
13930
14206
|
var OPTIMA_OPERATIONAL_FOLDERS = [".optima", "templates", "dist"];
|
|
13931
14207
|
function relPath(worktree, targetPath) {
|
|
13932
|
-
return
|
|
14208
|
+
return path19.relative(worktree, targetPath).split(path19.sep).join("/") || ".";
|
|
13933
14209
|
}
|
|
13934
14210
|
function normalizeCodemapRelPath(relPathValue) {
|
|
13935
|
-
return
|
|
14211
|
+
return path19.normalize(relPathValue).replace(/\\/g, "/").replace(/\/$/, "");
|
|
13936
14212
|
}
|
|
13937
14213
|
function firstPathSegment(relPathValue) {
|
|
13938
14214
|
return normalizeCodemapRelPath(relPathValue).split("/").filter(Boolean)[0] || "";
|
|
@@ -13951,8 +14227,8 @@ function isHiddenTree(relPathValue) {
|
|
|
13951
14227
|
function loadGitIgnoreMatcher(worktree) {
|
|
13952
14228
|
const ig = (0, import_ignore.default)();
|
|
13953
14229
|
ig.add(".git");
|
|
13954
|
-
const gitignorePath =
|
|
13955
|
-
if (
|
|
14230
|
+
const gitignorePath = path19.join(worktree, ".gitignore");
|
|
14231
|
+
if (fs18.existsSync(gitignorePath)) ig.add(fs18.readFileSync(gitignorePath, "utf8"));
|
|
13956
14232
|
return ig;
|
|
13957
14233
|
}
|
|
13958
14234
|
function codemapSectionEntries(value) {
|
|
@@ -13971,7 +14247,7 @@ function codemapIndexedPaths(map) {
|
|
|
13971
14247
|
}
|
|
13972
14248
|
function readCodemap(filePath, unresolved, worktree) {
|
|
13973
14249
|
try {
|
|
13974
|
-
const parsed = import_yaml4.default.parse(
|
|
14250
|
+
const parsed = import_yaml4.default.parse(fs18.readFileSync(filePath, "utf8"));
|
|
13975
14251
|
if (!parsed || typeof parsed !== "object") {
|
|
13976
14252
|
unresolved.push({ category: "codemap", path: relPath(worktree, filePath), message: "CodeMap is empty or invalid; manual repair required." });
|
|
13977
14253
|
return null;
|
|
@@ -13983,42 +14259,42 @@ function readCodemap(filePath, unresolved, worktree) {
|
|
|
13983
14259
|
}
|
|
13984
14260
|
}
|
|
13985
14261
|
function writeCodemap(filePath, map) {
|
|
13986
|
-
|
|
14262
|
+
fs18.writeFileSync(filePath, import_yaml4.default.stringify(map), "utf8");
|
|
13987
14263
|
}
|
|
13988
14264
|
function isIgnoredPath(ig, relativePath) {
|
|
13989
14265
|
const normalized = normalizeCodemapRelPath(relativePath);
|
|
13990
14266
|
return Boolean(normalized) && ig.ignores(normalized);
|
|
13991
14267
|
}
|
|
13992
14268
|
function hasImmediateSourceFile(dirPath, ig, worktree) {
|
|
13993
|
-
if (!
|
|
13994
|
-
for (const item of
|
|
13995
|
-
const childPath =
|
|
13996
|
-
const relative =
|
|
14269
|
+
if (!fs18.existsSync(dirPath)) return false;
|
|
14270
|
+
for (const item of fs18.readdirSync(dirPath, { withFileTypes: true })) {
|
|
14271
|
+
const childPath = path19.join(dirPath, item.name);
|
|
14272
|
+
const relative = path19.relative(worktree, childPath);
|
|
13997
14273
|
if (isIgnoredPath(ig, relative) || isOperationalRelPath(relative)) continue;
|
|
13998
|
-
if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(
|
|
14274
|
+
if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(path19.extname(item.name))) return true;
|
|
13999
14275
|
}
|
|
14000
14276
|
return false;
|
|
14001
14277
|
}
|
|
14002
14278
|
function containsSource(dirPath, ig, worktree) {
|
|
14003
|
-
if (!
|
|
14004
|
-
const dirRelPath =
|
|
14279
|
+
if (!fs18.existsSync(dirPath)) return false;
|
|
14280
|
+
const dirRelPath = path19.relative(worktree, dirPath);
|
|
14005
14281
|
if (isOperationalRelPath(dirRelPath) || isHiddenTree(dirRelPath)) return false;
|
|
14006
|
-
for (const item of
|
|
14007
|
-
const childPath =
|
|
14008
|
-
const relative =
|
|
14282
|
+
for (const item of fs18.readdirSync(dirPath, { withFileTypes: true })) {
|
|
14283
|
+
const childPath = path19.join(dirPath, item.name);
|
|
14284
|
+
const relative = path19.relative(worktree, childPath);
|
|
14009
14285
|
if (isIgnoredPath(ig, relative) || isOperationalRelPath(relative) || isHiddenTree(relative)) continue;
|
|
14010
|
-
if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(
|
|
14286
|
+
if (item.isFile() && CODEMAP_SOURCE_EXTENSIONS.has(path19.extname(item.name))) return true;
|
|
14011
14287
|
if (item.isDirectory() && containsSource(childPath, ig, worktree)) return true;
|
|
14012
14288
|
}
|
|
14013
14289
|
return false;
|
|
14014
14290
|
}
|
|
14015
14291
|
function createModuleCodemap(dirPath, worktree, deps) {
|
|
14016
|
-
const entries =
|
|
14292
|
+
const entries = fs18.readdirSync(dirPath, { withFileTypes: true });
|
|
14017
14293
|
const entrypoints = [];
|
|
14018
14294
|
const internals = [];
|
|
14019
|
-
const relToRoot =
|
|
14295
|
+
const relToRoot = path19.relative(dirPath, deps.optimaCodemapPath(worktree)).split(path19.sep).join("/");
|
|
14020
14296
|
for (const item of entries) {
|
|
14021
|
-
if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(
|
|
14297
|
+
if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(path19.extname(item.name))) continue;
|
|
14022
14298
|
const bucket = /^index\.(js|ts|tsx|jsx)$|^main\.(js|ts|tsx|jsx|py|go|rs|java)$/.test(item.name) ? entrypoints : internals;
|
|
14023
14299
|
bucket.push({ path: item.name });
|
|
14024
14300
|
}
|
|
@@ -14031,7 +14307,7 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
|
|
|
14031
14307
|
const map = readCodemap(codemapPath, unresolved, worktree);
|
|
14032
14308
|
if (!map) return;
|
|
14033
14309
|
const isRootMap = codemapPath === deps.optimaCodemapPath(worktree);
|
|
14034
|
-
const mapDir =
|
|
14310
|
+
const mapDir = path19.dirname(codemapPath);
|
|
14035
14311
|
const pathBase = isRootMap ? worktree : mapDir;
|
|
14036
14312
|
let changed = false;
|
|
14037
14313
|
for (const section of ["modules", "entrypoints", "sources_of_truth", "links", "internals"]) {
|
|
@@ -14042,13 +14318,13 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
|
|
|
14042
14318
|
}
|
|
14043
14319
|
const nextEntries = [];
|
|
14044
14320
|
for (const entry of originalEntries) {
|
|
14045
|
-
if (!entry?.path || entry.path.startsWith("http://") || entry.path.startsWith("https://") ||
|
|
14321
|
+
if (!entry?.path || entry.path.startsWith("http://") || entry.path.startsWith("https://") || path19.isAbsolute(entry.path)) {
|
|
14046
14322
|
nextEntries.push(entry);
|
|
14047
14323
|
continue;
|
|
14048
14324
|
}
|
|
14049
14325
|
const normalizedPath = normalizeCodemapRelPath(entry.path);
|
|
14050
|
-
const absPath =
|
|
14051
|
-
if (!
|
|
14326
|
+
const absPath = path19.join(pathBase, normalizedPath);
|
|
14327
|
+
if (!fs18.existsSync(absPath)) {
|
|
14052
14328
|
registerAction({ category: "codemap", action: apply ? "removed" : "would_remove", path: relPath(worktree, codemapPath), detail: `Remove broken ${section.slice(0, -1)} reference '${entry.path}'.` });
|
|
14053
14329
|
changed = true;
|
|
14054
14330
|
continue;
|
|
@@ -14057,8 +14333,8 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
|
|
|
14057
14333
|
const maxParts = isRootMap ? 2 : 1;
|
|
14058
14334
|
if (parts.length > maxParts) {
|
|
14059
14335
|
const localPath = isRootMap ? parts.slice(0, 2).join("/") : parts[0];
|
|
14060
|
-
const localAbs =
|
|
14061
|
-
if (
|
|
14336
|
+
const localAbs = path19.join(pathBase, localPath);
|
|
14337
|
+
if (fs18.existsSync(localAbs)) {
|
|
14062
14338
|
nextEntries.push({ ...entry, path: localPath });
|
|
14063
14339
|
changed = true;
|
|
14064
14340
|
registerAction({ category: "codemap", action: apply ? "updated" : "would_update", path: relPath(worktree, codemapPath), detail: `Shorten '${entry.path}' to local path '${localPath}'.` });
|
|
@@ -14072,11 +14348,11 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
|
|
|
14072
14348
|
}
|
|
14073
14349
|
if (Array.isArray(map[section])) map[section] = nextEntries;
|
|
14074
14350
|
}
|
|
14075
|
-
if (map.scope === "module" && !isOperationalRelPath(
|
|
14351
|
+
if (map.scope === "module" && !isOperationalRelPath(path19.relative(worktree, mapDir))) {
|
|
14076
14352
|
const indexed = codemapIndexedPaths(map);
|
|
14077
14353
|
const internals = Array.isArray(map.internals) ? map.internals : [];
|
|
14078
|
-
for (const item of
|
|
14079
|
-
if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(
|
|
14354
|
+
for (const item of fs18.readdirSync(mapDir, { withFileTypes: true })) {
|
|
14355
|
+
if (!item.isFile() || item.name === "codemap.yml" || !CODEMAP_SOURCE_EXTENSIONS.has(path19.extname(item.name))) continue;
|
|
14080
14356
|
if (indexed.has(item.name)) continue;
|
|
14081
14357
|
internals.push({ path: item.name });
|
|
14082
14358
|
indexed.add(item.name);
|
|
@@ -14090,13 +14366,13 @@ function repairSingleCodemap(codemapPath, worktree, apply, registerAction, unres
|
|
|
14090
14366
|
function repairCodemaps(worktree, apply, actions, unresolved, deps) {
|
|
14091
14367
|
const ig = loadGitIgnoreMatcher(worktree);
|
|
14092
14368
|
const rootCodemapPath = deps.optimaCodemapPath(worktree);
|
|
14093
|
-
const rootCodemapMissing = !
|
|
14369
|
+
const rootCodemapMissing = !fs18.existsSync(rootCodemapPath);
|
|
14094
14370
|
if (rootCodemapMissing) {
|
|
14095
14371
|
actions.push({ category: "codemap", action: apply ? "created" : "would_create", path: ".optima/codemap.yml", detail: "Create missing root CodeMap from template." });
|
|
14096
14372
|
if (apply) deps.scaffoldOptimaRootCodemap(worktree);
|
|
14097
14373
|
}
|
|
14098
|
-
if (
|
|
14099
|
-
const rootMap =
|
|
14374
|
+
if (fs18.existsSync(rootCodemapPath)) repairSingleCodemap(rootCodemapPath, worktree, apply, (action) => actions.push(action), unresolved, deps);
|
|
14375
|
+
const rootMap = fs18.existsSync(rootCodemapPath) ? readCodemap(rootCodemapPath, unresolved, worktree) : null;
|
|
14100
14376
|
let rootChanged = false;
|
|
14101
14377
|
const rootModulesRepairable = rootMap && (rootMap.modules === void 0 || Array.isArray(rootMap.modules));
|
|
14102
14378
|
if (rootMap) {
|
|
@@ -14108,10 +14384,10 @@ function repairCodemaps(worktree, apply, actions, unresolved, deps) {
|
|
|
14108
14384
|
}
|
|
14109
14385
|
}
|
|
14110
14386
|
function walk(dirPath) {
|
|
14111
|
-
const relative =
|
|
14387
|
+
const relative = path19.relative(worktree, dirPath);
|
|
14112
14388
|
if (relative && (isIgnoredPath(ig, relative) || isOperationalRelPath(relative) || isHiddenTree(relative))) return;
|
|
14113
|
-
const codemapPath =
|
|
14114
|
-
const hasCodemap =
|
|
14389
|
+
const codemapPath = path19.join(dirPath, "codemap.yml");
|
|
14390
|
+
const hasCodemap = fs18.existsSync(codemapPath);
|
|
14115
14391
|
const sourceDir = relative && containsSource(dirPath, ig, worktree);
|
|
14116
14392
|
if (sourceDir && !hasCodemap && dirPath !== worktree) {
|
|
14117
14393
|
if (hasImmediateSourceFile(dirPath, ig, worktree)) {
|
|
@@ -14130,19 +14406,19 @@ function repairCodemaps(worktree, apply, actions, unresolved, deps) {
|
|
|
14130
14406
|
actions.push({ category: "codemap", action: apply ? "updated" : "would_update", path: ".optima/codemap.yml", detail: `Register top-level source module '${normalizeCodemapRelPath(relative)}'.` });
|
|
14131
14407
|
}
|
|
14132
14408
|
}
|
|
14133
|
-
if (
|
|
14134
|
-
for (const item of
|
|
14135
|
-
if (item.isDirectory()) walk(
|
|
14409
|
+
if (fs18.existsSync(codemapPath) && codemapPath !== rootCodemapPath) repairSingleCodemap(codemapPath, worktree, apply, (action) => actions.push(action), unresolved, deps);
|
|
14410
|
+
for (const item of fs18.readdirSync(dirPath, { withFileTypes: true })) {
|
|
14411
|
+
if (item.isDirectory()) walk(path19.join(dirPath, item.name));
|
|
14136
14412
|
}
|
|
14137
14413
|
}
|
|
14138
|
-
if (
|
|
14414
|
+
if (fs18.existsSync(worktree)) walk(worktree);
|
|
14139
14415
|
if (rootMap && rootChanged && apply) writeCodemap(rootCodemapPath, rootMap);
|
|
14140
14416
|
}
|
|
14141
14417
|
function walkMarkdownFiles(dirPath) {
|
|
14142
|
-
if (!
|
|
14418
|
+
if (!fs18.existsSync(dirPath)) return [];
|
|
14143
14419
|
const files = [];
|
|
14144
|
-
for (const entry of
|
|
14145
|
-
const entryPath =
|
|
14420
|
+
for (const entry of fs18.readdirSync(dirPath, { withFileTypes: true })) {
|
|
14421
|
+
const entryPath = path19.join(dirPath, entry.name);
|
|
14146
14422
|
if (entry.isDirectory()) {
|
|
14147
14423
|
files.push(...walkMarkdownFiles(entryPath));
|
|
14148
14424
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -14181,7 +14457,7 @@ function rewriteOptimaMarkdownReferences(content, evidenceBasePath = null) {
|
|
|
14181
14457
|
}
|
|
14182
14458
|
function optimaEvidenceBaseForFile(worktree, filePath, deps) {
|
|
14183
14459
|
const evidenceRoot = deps.optimaEvidencesDir(worktree);
|
|
14184
|
-
const relative =
|
|
14460
|
+
const relative = path19.relative(evidenceRoot, filePath).split(path19.sep).join("/");
|
|
14185
14461
|
const [taskId] = relative.split("/");
|
|
14186
14462
|
if (!taskId || taskId === ".." || relative.startsWith("../")) return null;
|
|
14187
14463
|
return `.optima/evidences/${taskId}`;
|
|
@@ -14194,11 +14470,11 @@ function normalizeOptimaMarkdownReferences(worktree, deps) {
|
|
|
14194
14470
|
];
|
|
14195
14471
|
const changed = [];
|
|
14196
14472
|
for (const filePath of scanRoots.flatMap(walkMarkdownFiles)) {
|
|
14197
|
-
const raw =
|
|
14198
|
-
const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) +
|
|
14473
|
+
const raw = fs18.readFileSync(filePath, "utf8");
|
|
14474
|
+
const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) + path19.sep) ? optimaEvidenceBaseForFile(worktree, filePath, deps) : null;
|
|
14199
14475
|
const rewritten = rewriteOptimaMarkdownReferences(raw, evidenceBasePath);
|
|
14200
14476
|
if (rewritten !== raw) {
|
|
14201
|
-
|
|
14477
|
+
fs18.writeFileSync(filePath, rewritten, "utf8");
|
|
14202
14478
|
changed.push(relPath(worktree, filePath));
|
|
14203
14479
|
}
|
|
14204
14480
|
}
|
|
@@ -14206,8 +14482,8 @@ function normalizeOptimaMarkdownReferences(worktree, deps) {
|
|
|
14206
14482
|
}
|
|
14207
14483
|
function missingOptimaGitignoreRules(worktree, deps) {
|
|
14208
14484
|
if (!deps.isGitRepository(worktree)) return [];
|
|
14209
|
-
const gitignorePath =
|
|
14210
|
-
const existing =
|
|
14485
|
+
const gitignorePath = path19.join(worktree, ".gitignore");
|
|
14486
|
+
const existing = fs18.existsSync(gitignorePath) ? fs18.readFileSync(gitignorePath, "utf8") : "";
|
|
14211
14487
|
const existingRules = new Set(existing.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
|
|
14212
14488
|
return deps.optimaGitignoreRules.filter((rule) => !existingRules.has(rule));
|
|
14213
14489
|
}
|
|
@@ -14224,11 +14500,11 @@ function planOptimaRepair(worktree, args = {}, deps) {
|
|
|
14224
14500
|
const apply = mode === "apply";
|
|
14225
14501
|
const actions = [];
|
|
14226
14502
|
const unresolved = [];
|
|
14227
|
-
const hadOptima =
|
|
14503
|
+
const hadOptima = fs18.existsSync(deps.optimaDir(worktree));
|
|
14228
14504
|
const missingGitignoreRules = missingOptimaGitignoreRules(worktree, deps);
|
|
14229
14505
|
const markdownBefore = apply ? [] : walkMarkdownFiles(deps.optimaDir(worktree)).filter((filePath) => {
|
|
14230
|
-
const raw =
|
|
14231
|
-
const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) +
|
|
14506
|
+
const raw = fs18.readFileSync(filePath, "utf8");
|
|
14507
|
+
const evidenceBasePath = filePath.startsWith(deps.optimaEvidencesDir(worktree) + path19.sep) ? optimaEvidenceBaseForFile(worktree, filePath, deps) : null;
|
|
14232
14508
|
return rewriteOptimaMarkdownReferences(raw, evidenceBasePath) !== raw;
|
|
14233
14509
|
}).map((filePath) => relPath(worktree, filePath));
|
|
14234
14510
|
if (!hadOptima) pushRepairAction(actions, "operational", apply ? "created" : "would_create", ".optima/", "Create Optima operational root.");
|
|
@@ -14237,31 +14513,31 @@ function planOptimaRepair(worktree, args = {}, deps) {
|
|
|
14237
14513
|
[".staticeng/", deps.legacyStaticEngDir(worktree)],
|
|
14238
14514
|
[".nomadwork/", deps.legacyNomadworkDir(worktree)],
|
|
14239
14515
|
[".nomadworks/", deps.legacyNomadworksDir(worktree)],
|
|
14240
|
-
["tasks/",
|
|
14241
|
-
["evidences/",
|
|
14242
|
-
["docs/scrs/",
|
|
14243
|
-
["codemap.yml",
|
|
14244
|
-
["codemap.yaml",
|
|
14516
|
+
["tasks/", path19.join(worktree, "tasks")],
|
|
14517
|
+
["evidences/", path19.join(worktree, "evidences")],
|
|
14518
|
+
["docs/scrs/", path19.join(worktree, "docs", "scrs")],
|
|
14519
|
+
["codemap.yml", path19.join(worktree, "codemap.yml")],
|
|
14520
|
+
["codemap.yaml", path19.join(worktree, "codemap.yaml")]
|
|
14245
14521
|
];
|
|
14246
|
-
if (!deps.isOptimaPluginPackageWorktree(worktree)) legacySources.push(["policies/",
|
|
14522
|
+
if (!deps.isOptimaPluginPackageWorktree(worktree)) legacySources.push(["policies/", path19.join(worktree, "policies")]);
|
|
14247
14523
|
for (const [display, sourcePath] of legacySources) {
|
|
14248
|
-
if (
|
|
14524
|
+
if (fs18.existsSync(sourcePath)) pushRepairAction(actions, "legacy", apply ? "migrated" : "would_migrate", display, "Move or merge legacy/root Optima artifact into .optima using preservation safeguards.");
|
|
14249
14525
|
}
|
|
14250
14526
|
if (apply) deps.migrateLegacyOptimaLayout(worktree);
|
|
14251
|
-
const configMissing = !
|
|
14527
|
+
const configMissing = !fs18.existsSync(deps.repoConfigPath(worktree));
|
|
14252
14528
|
if (configMissing) pushRepairAction(actions, "config", apply ? "created" : "would_create", ".optima/.config/optima.yaml", "Create missing local Optima config from template.");
|
|
14253
14529
|
if (apply) deps.scaffoldOptimaConfig(worktree, args.team_mode || "full");
|
|
14254
14530
|
const requiredFiles = [
|
|
14255
|
-
[
|
|
14256
|
-
[
|
|
14257
|
-
[
|
|
14258
|
-
[
|
|
14259
|
-
[
|
|
14260
|
-
[
|
|
14261
|
-
[
|
|
14531
|
+
[path19.join(deps.optimaTasksDir(worktree), "current.md"), "registry", ".optima/tasks/current.md", deps.currentTasksRegistryContent()],
|
|
14532
|
+
[path19.join(deps.optimaTasksDir(worktree), "done.md"), "registry", ".optima/tasks/done.md", deps.doneTasksRegistryContent()],
|
|
14533
|
+
[path19.join(deps.optimaScrsDir(worktree), "current.md"), "registry", ".optima/docs/scrs/current.md", deps.currentScrRegistryContent()],
|
|
14534
|
+
[path19.join(deps.optimaScrsDir(worktree), "done.md"), "registry", ".optima/docs/scrs/done.md", deps.doneScrRegistryContent()],
|
|
14535
|
+
[path19.join(deps.optimaTasksDir(worktree), "task-template.md"), "template", ".optima/tasks/task-template.md", deps.taskTemplateContent()],
|
|
14536
|
+
[path19.join(deps.optimaTasksDir(worktree), "subtask-template.md"), "template", ".optima/tasks/subtask-template.md", deps.subtaskTemplateContent()],
|
|
14537
|
+
[path19.join(deps.repoPoliciesDir(worktree), "README.md"), "policy", ".optima/policies/README.md", deps.repoLocalPoliciesReadme]
|
|
14262
14538
|
];
|
|
14263
14539
|
for (const [filePath, category, displayPath, content] of requiredFiles) {
|
|
14264
|
-
if (!
|
|
14540
|
+
if (!fs18.existsSync(filePath)) {
|
|
14265
14541
|
pushRepairAction(actions, category, apply ? "created" : "would_create", displayPath, "Create missing Optima scaffold file without overwriting existing content.");
|
|
14266
14542
|
if (apply) deps.ensureFileIfMissing(filePath, content);
|
|
14267
14543
|
}
|
|
@@ -14315,18 +14591,18 @@ function formatRepairResult(plan, validationResult = null, formatValidationResul
|
|
|
14315
14591
|
// src/validate_logic.js
|
|
14316
14592
|
var import_yaml5 = __toESM(require_dist(), 1);
|
|
14317
14593
|
var import_ignore2 = __toESM(require_ignore(), 1);
|
|
14318
|
-
import
|
|
14319
|
-
import
|
|
14594
|
+
import fs19 from "node:fs";
|
|
14595
|
+
import path20 from "node:path";
|
|
14320
14596
|
async function optima_validate_logic(worktree) {
|
|
14321
|
-
const rootCodemapPath =
|
|
14322
|
-
if (!
|
|
14597
|
+
const rootCodemapPath = path20.join(worktree, ".optima", "codemap.yml");
|
|
14598
|
+
if (!fs19.existsSync(rootCodemapPath)) return { ok: false, errors: [".optima/codemap.yml not found."], warnings: [] };
|
|
14323
14599
|
const errors = [];
|
|
14324
14600
|
const warnings = [];
|
|
14325
14601
|
const ig = (0, import_ignore2.default)();
|
|
14326
14602
|
ig.add(".git");
|
|
14327
|
-
const gitignorePath =
|
|
14328
|
-
if (
|
|
14329
|
-
ig.add(
|
|
14603
|
+
const gitignorePath = path20.join(worktree, ".gitignore");
|
|
14604
|
+
if (fs19.existsSync(gitignorePath)) {
|
|
14605
|
+
ig.add(fs19.readFileSync(gitignorePath, "utf8"));
|
|
14330
14606
|
}
|
|
14331
14607
|
const sourceExtensions = [
|
|
14332
14608
|
".js",
|
|
@@ -14366,30 +14642,30 @@ async function optima_validate_logic(worktree) {
|
|
|
14366
14642
|
const operationalFolders = [".optima", "templates", "dist"];
|
|
14367
14643
|
const isHiddenTree2 = (relPath2) => {
|
|
14368
14644
|
if (!relPath2) return false;
|
|
14369
|
-
return relPath2.split(
|
|
14645
|
+
return relPath2.split(path20.sep).some((part) => part.startsWith("."));
|
|
14370
14646
|
};
|
|
14371
|
-
const firstPathSegment2 = (relPath2) => relPath2.split(
|
|
14647
|
+
const firstPathSegment2 = (relPath2) => relPath2.split(path20.sep).filter(Boolean)[0] || "";
|
|
14372
14648
|
const isOperationalRelPath2 = (relPath2) => {
|
|
14373
14649
|
if (!relPath2) return false;
|
|
14374
14650
|
const firstSegment = firstPathSegment2(relPath2);
|
|
14375
14651
|
if (legacyOperationalRoots.has(firstSegment)) return true;
|
|
14376
|
-
return operationalFolders.some((f) => relPath2 === f || relPath2.startsWith(f +
|
|
14652
|
+
return operationalFolders.some((f) => relPath2 === f || relPath2.startsWith(f + path20.sep));
|
|
14377
14653
|
};
|
|
14378
14654
|
const getSectionEntries = (value) => {
|
|
14379
14655
|
if (Array.isArray(value)) return value;
|
|
14380
14656
|
if (value && typeof value === "object") return Object.values(value);
|
|
14381
14657
|
return [];
|
|
14382
14658
|
};
|
|
14383
|
-
const normalizeRelativePath = (relPath2) =>
|
|
14659
|
+
const normalizeRelativePath = (relPath2) => path20.normalize(relPath2).replace(/\\/g, "/").replace(/\/$/, "");
|
|
14384
14660
|
const isSourceDir = (dirPath) => {
|
|
14385
|
-
const dirRelPath =
|
|
14661
|
+
const dirRelPath = path20.relative(worktree, dirPath);
|
|
14386
14662
|
if (isOperationalRelPath2(dirRelPath)) return false;
|
|
14387
|
-
const items =
|
|
14663
|
+
const items = fs19.readdirSync(dirPath, { withFileTypes: true });
|
|
14388
14664
|
for (const item of items) {
|
|
14389
|
-
const childPath =
|
|
14390
|
-
const relPath2 =
|
|
14665
|
+
const childPath = path20.join(dirPath, item.name);
|
|
14666
|
+
const relPath2 = path20.relative(worktree, childPath);
|
|
14391
14667
|
if (ig.ignores(relPath2) || isOperationalRelPath2(relPath2)) continue;
|
|
14392
|
-
if (item.isFile() && sourceExtensions.includes(
|
|
14668
|
+
if (item.isFile() && sourceExtensions.includes(path20.extname(item.name))) return true;
|
|
14393
14669
|
if (item.isDirectory()) {
|
|
14394
14670
|
if (isSourceDir(childPath)) return true;
|
|
14395
14671
|
}
|
|
@@ -14397,7 +14673,7 @@ async function optima_validate_logic(worktree) {
|
|
|
14397
14673
|
return false;
|
|
14398
14674
|
};
|
|
14399
14675
|
function validateMap(filePath) {
|
|
14400
|
-
const content =
|
|
14676
|
+
const content = fs19.readFileSync(filePath, "utf8");
|
|
14401
14677
|
let map;
|
|
14402
14678
|
try {
|
|
14403
14679
|
map = import_yaml5.default.parse(content);
|
|
@@ -14409,32 +14685,32 @@ async function optima_validate_logic(worktree) {
|
|
|
14409
14685
|
errors.push(`${filePath}: Invalid YAML.`);
|
|
14410
14686
|
return;
|
|
14411
14687
|
}
|
|
14412
|
-
const dir =
|
|
14688
|
+
const dir = path20.dirname(filePath);
|
|
14413
14689
|
const pathBase = filePath === rootCodemapPath ? worktree : dir;
|
|
14414
14690
|
const indexedPaths = /* @__PURE__ */ new Set();
|
|
14415
14691
|
const sectionsToVerify = ["modules", "entrypoints", "sources_of_truth", "links", "internals"];
|
|
14416
14692
|
for (const section of sectionsToVerify) {
|
|
14417
14693
|
for (const item of getSectionEntries(map[section])) {
|
|
14418
14694
|
if (item?.path) {
|
|
14419
|
-
indexedPaths.add(
|
|
14695
|
+
indexedPaths.add(path20.normalize(item.path));
|
|
14420
14696
|
if (section === "links" && (item.path.startsWith("http://") || item.path.startsWith("https://"))) {
|
|
14421
14697
|
continue;
|
|
14422
14698
|
}
|
|
14423
|
-
const absPath =
|
|
14424
|
-
if (!
|
|
14699
|
+
const absPath = path20.isAbsolute(item.path) ? item.path : path20.join(pathBase, item.path);
|
|
14700
|
+
if (!fs19.existsSync(absPath)) {
|
|
14425
14701
|
errors.push(`${filePath}: ${section.slice(0, -1)} path does not exist: ${item.path}`);
|
|
14426
14702
|
}
|
|
14427
14703
|
}
|
|
14428
14704
|
}
|
|
14429
14705
|
}
|
|
14430
|
-
const relDir =
|
|
14706
|
+
const relDir = path20.relative(worktree, dir);
|
|
14431
14707
|
const isOperational = isOperationalRelPath2(relDir);
|
|
14432
14708
|
if (map.scope === "module" && !isOperational) {
|
|
14433
|
-
const items =
|
|
14709
|
+
const items = fs19.readdirSync(dir, { withFileTypes: true });
|
|
14434
14710
|
for (const item of items) {
|
|
14435
|
-
if (item.isFile() && sourceExtensions.includes(
|
|
14711
|
+
if (item.isFile() && sourceExtensions.includes(path20.extname(item.name))) {
|
|
14436
14712
|
if (item.name === "codemap.yml") continue;
|
|
14437
|
-
if (!indexedPaths.has(
|
|
14713
|
+
if (!indexedPaths.has(path20.normalize(item.name))) {
|
|
14438
14714
|
errors.push(`${filePath}: Unindexed source file found: '${item.name}'. Every source file must be categorized in a section (e.g., 'internals').`);
|
|
14439
14715
|
}
|
|
14440
14716
|
}
|
|
@@ -14444,7 +14720,7 @@ async function optima_validate_logic(worktree) {
|
|
|
14444
14720
|
for (const key of pathKeys) {
|
|
14445
14721
|
for (const entry of getSectionEntries(map[key])) {
|
|
14446
14722
|
if (!entry?.path || entry.path.startsWith("http://") || entry.path.startsWith("https://")) continue;
|
|
14447
|
-
if (
|
|
14723
|
+
if (path20.isAbsolute(entry.path)) continue;
|
|
14448
14724
|
const normalizedPath = normalizeRelativePath(entry.path);
|
|
14449
14725
|
if (!normalizedPath || normalizedPath === ".") continue;
|
|
14450
14726
|
const parts = normalizedPath.split("/").filter((p) => p && p !== ".");
|
|
@@ -14456,18 +14732,18 @@ async function optima_validate_logic(worktree) {
|
|
|
14456
14732
|
}
|
|
14457
14733
|
}
|
|
14458
14734
|
const walk = (dir) => {
|
|
14459
|
-
const relDir =
|
|
14735
|
+
const relDir = path20.relative(worktree, dir);
|
|
14460
14736
|
if (relDir && ig.ignores(relDir)) return;
|
|
14461
14737
|
if (isOperationalRelPath2(relDir)) return;
|
|
14462
14738
|
if (isHiddenTree2(relDir)) return;
|
|
14463
|
-
const hasCodemap =
|
|
14464
|
-
const items =
|
|
14465
|
-
if (!relDir.startsWith(
|
|
14739
|
+
const hasCodemap = fs19.existsSync(path20.join(dir, "codemap.yml"));
|
|
14740
|
+
const items = fs19.readdirSync(dir, { withFileTypes: true });
|
|
14741
|
+
if (!relDir.startsWith(path20.join(".optima", "tasks", "done"))) {
|
|
14466
14742
|
for (const item of items) {
|
|
14467
14743
|
if (item.isFile() && item.name.endsWith(".md")) {
|
|
14468
|
-
const content =
|
|
14744
|
+
const content = fs19.readFileSync(path20.join(dir, item.name), "utf8");
|
|
14469
14745
|
if (content.includes("[To be defined]") || content.includes("[Insert ")) {
|
|
14470
|
-
const relFilePath =
|
|
14746
|
+
const relFilePath = path20.join(relDir, item.name);
|
|
14471
14747
|
errors.push(`Documentation Placeholder found: '${relFilePath}' still contains [To be defined] or [Insert ...] placeholders.`);
|
|
14472
14748
|
}
|
|
14473
14749
|
}
|
|
@@ -14477,9 +14753,9 @@ async function optima_validate_logic(worktree) {
|
|
|
14477
14753
|
if (relDir !== "" && !hasCodemap && isSourceDir(dir) && !isOperational) {
|
|
14478
14754
|
errors.push(`Missing CodeMap: Directory '${relDir}' contains source but has no codemap.yml.`);
|
|
14479
14755
|
}
|
|
14480
|
-
if (hasCodemap) validateMap(
|
|
14756
|
+
if (hasCodemap) validateMap(path20.join(dir, "codemap.yml"));
|
|
14481
14757
|
for (const item of items) {
|
|
14482
|
-
if (item.isDirectory()) walk(
|
|
14758
|
+
if (item.isDirectory()) walk(path20.join(dir, item.name));
|
|
14483
14759
|
}
|
|
14484
14760
|
};
|
|
14485
14761
|
validateMap(rootCodemapPath);
|
|
@@ -14499,7 +14775,7 @@ function normalizeWorkflowTaskPath(taskPath) {
|
|
|
14499
14775
|
const trimmed = taskPath.trim();
|
|
14500
14776
|
if (!trimmed) return { ok: false, message: "Error: task_path is required." };
|
|
14501
14777
|
const normalized = trimmed.replace(/\\/g, "/");
|
|
14502
|
-
if (
|
|
14778
|
+
if (path21.isAbsolute(trimmed)) return { ok: true, taskPath: trimmed };
|
|
14503
14779
|
if (normalized === "tasks" || normalized.startsWith("tasks/")) {
|
|
14504
14780
|
return {
|
|
14505
14781
|
ok: false,
|
|
@@ -14516,10 +14792,10 @@ function normalizeWorkflowTaskPath(taskPath) {
|
|
|
14516
14792
|
}
|
|
14517
14793
|
function readTaskMetadata(taskPath, worktree) {
|
|
14518
14794
|
if (!taskPath) return {};
|
|
14519
|
-
const absoluteTaskPath =
|
|
14520
|
-
if (!
|
|
14795
|
+
const absoluteTaskPath = path21.isAbsolute(taskPath) ? taskPath : path21.join(worktree, taskPath);
|
|
14796
|
+
if (!fs20.existsSync(absoluteTaskPath)) return {};
|
|
14521
14797
|
try {
|
|
14522
|
-
const raw =
|
|
14798
|
+
const raw = fs20.readFileSync(absoluteTaskPath, "utf8");
|
|
14523
14799
|
const { data } = parseFrontmatter(raw);
|
|
14524
14800
|
return {
|
|
14525
14801
|
complexity: typeof data.complexity === "string" ? data.complexity.trim().toLowerCase() : void 0,
|
|
@@ -14542,15 +14818,15 @@ function hasActiveImplementationWorkflow() {
|
|
|
14542
14818
|
function resolveSessionToolDirectory({ requestedDirectory, context, pluginWorktree, clickUpWebhookValidation } = {}) {
|
|
14543
14819
|
const safe = safeWorktreeOrFailure(context, pluginWorktree);
|
|
14544
14820
|
if (!safe.ok) return { ok: false, error: safe.message };
|
|
14545
|
-
const requested = String(requestedDirectory || "").trim() ?
|
|
14821
|
+
const requested = String(requestedDirectory || "").trim() ? path21.resolve(safe.worktree, String(requestedDirectory).trim()) : safe.worktree;
|
|
14546
14822
|
if (!isSafeWritableDirectory(requested)) return { ok: false, error: `Directory is not a safe writable directory: ${requested}` };
|
|
14547
14823
|
if (isSameOrNestedPath(requested, safe.worktree)) return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "context_worktree" };
|
|
14548
14824
|
const clickUpBasePath = clickUpWebhookValidation?.complete === true && clickUpWebhookValidation?.ok !== false ? clickUpWebhookValidation.config?.basePath : "";
|
|
14549
14825
|
if (clickUpBasePath && isSameOrNestedPath(requested, clickUpBasePath)) {
|
|
14550
|
-
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath:
|
|
14826
|
+
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_base_path", clickupBasePath: path21.resolve(clickUpBasePath) };
|
|
14551
14827
|
}
|
|
14552
14828
|
if (clickUpBasePath && isClickUpDerivedWorktreeSibling(requested, clickUpBasePath)) {
|
|
14553
|
-
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_derived_worktree", clickupBasePath:
|
|
14829
|
+
return { ok: true, directory: requested, safeWorktree: safe.worktree, scope: "clickup_derived_worktree", clickupBasePath: path21.resolve(clickUpBasePath) };
|
|
14554
14830
|
}
|
|
14555
14831
|
return {
|
|
14556
14832
|
ok: false,
|
|
@@ -14565,9 +14841,9 @@ async function OptimaPlugin(input = {}, pluginOptions = {}) {
|
|
|
14565
14841
|
const configPath = resolveConfigPath(worktree);
|
|
14566
14842
|
const discussionRegistry = loadDiscussionRegistry(worktree);
|
|
14567
14843
|
let repoCfg = { agents: {}, defaults: {}, features: {} };
|
|
14568
|
-
if (
|
|
14844
|
+
if (fs20.existsSync(configPath)) {
|
|
14569
14845
|
try {
|
|
14570
|
-
repoCfg = import_yaml6.default.parse(
|
|
14846
|
+
repoCfg = import_yaml6.default.parse(fs20.readFileSync(configPath, "utf8")) || repoCfg;
|
|
14571
14847
|
} catch (e) {
|
|
14572
14848
|
console.error(`[Optima] Failed to parse config at ${configPath}:`, e);
|
|
14573
14849
|
}
|
|
@@ -14872,10 +15148,10 @@ Evidencia: ${evidencePath}` : ""
|
|
|
14872
15148
|
}
|
|
14873
15149
|
migrateLegacyOptimaLayout(toolWorktree);
|
|
14874
15150
|
const cfgDir = optimaConfigDir(toolWorktree);
|
|
14875
|
-
if (!
|
|
14876
|
-
const optimaTmplPath =
|
|
14877
|
-
const codemapTmplPath =
|
|
14878
|
-
if (!
|
|
15151
|
+
if (!fs20.existsSync(cfgDir)) fs20.mkdirSync(cfgDir, { recursive: true });
|
|
15152
|
+
const optimaTmplPath = path21.join(TEMPLATES_DIR, "optima.yaml.template");
|
|
15153
|
+
const codemapTmplPath = path21.join(TEMPLATES_DIR, "codemap.yml.template");
|
|
15154
|
+
if (!fs20.existsSync(optimaTmplPath) || !fs20.existsSync(codemapTmplPath)) {
|
|
14879
15155
|
return "Error: Initialization templates not found in plugin.";
|
|
14880
15156
|
}
|
|
14881
15157
|
scaffoldOptimaConfig(toolWorktree, requestedTeamMode);
|
|
@@ -14996,14 +15272,14 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
|
|
|
14996
15272
|
async execute(args, context) {
|
|
14997
15273
|
const safe = safeWorktreeOrFailure(context, worktree);
|
|
14998
15274
|
if (!safe.ok) return safe.message;
|
|
14999
|
-
const summaryPath =
|
|
15000
|
-
if (!
|
|
15001
|
-
const taskPath = args.task_path ?
|
|
15275
|
+
const summaryPath = path21.resolve(safe.worktree, args.summary_path || "");
|
|
15276
|
+
if (!fs20.existsSync(summaryPath)) return `FAIL: summary_path not found: ${summaryPath}`;
|
|
15277
|
+
const taskPath = args.task_path ? path21.resolve(safe.worktree, args.task_path) : "";
|
|
15002
15278
|
const payload = buildClickUpSummaryPayload({
|
|
15003
|
-
summaryMarkdown:
|
|
15004
|
-
summaryPath:
|
|
15005
|
-
taskMarkdown: taskPath &&
|
|
15006
|
-
taskPath: taskPath ?
|
|
15279
|
+
summaryMarkdown: fs20.readFileSync(summaryPath, "utf8"),
|
|
15280
|
+
summaryPath: path21.relative(safe.worktree, summaryPath),
|
|
15281
|
+
taskMarkdown: taskPath && fs20.existsSync(taskPath) ? fs20.readFileSync(taskPath, "utf8") : "",
|
|
15282
|
+
taskPath: taskPath ? path21.relative(safe.worktree, taskPath) : "",
|
|
15007
15283
|
branch: args.branch,
|
|
15008
15284
|
worktree: args.worktree,
|
|
15009
15285
|
pr: args.pr
|
|
@@ -15170,7 +15446,7 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
|
|
|
15170
15446
|
commandJson: args.command_json,
|
|
15171
15447
|
startUrl: args.start_url || "https://chatgpt.com/"
|
|
15172
15448
|
});
|
|
15173
|
-
return JSON.stringify({ ok:
|
|
15449
|
+
return JSON.stringify({ ok: result.ok !== false, lease: persisted.state.active, notifications: persisted.notifications, chrome: result }, null, 2);
|
|
15174
15450
|
} catch (error) {
|
|
15175
15451
|
return JSON.stringify({ ok: false, error: error.message, lease: persisted.state.active, notifications: persisted.notifications }, null, 2);
|
|
15176
15452
|
}
|
|
@@ -15218,12 +15494,12 @@ Restart or reload OpenCode manually if the newly scaffolded config or agents are
|
|
|
15218
15494
|
async execute(args, context) {
|
|
15219
15495
|
const safe = safeWorktreeOrFailure(context, worktree);
|
|
15220
15496
|
if (!safe.ok) return safe.message;
|
|
15221
|
-
const markdownPath =
|
|
15222
|
-
if (!
|
|
15497
|
+
const markdownPath = path21.resolve(safe.worktree, args.markdown_path || "");
|
|
15498
|
+
if (!fs20.existsSync(markdownPath)) return `FAIL: markdown_path not found: ${markdownPath}`;
|
|
15223
15499
|
const payload = buildClickUpCreateSubtasksPayload({
|
|
15224
15500
|
parentTaskId: args.parent_task_id,
|
|
15225
|
-
markdown:
|
|
15226
|
-
sourcePath:
|
|
15501
|
+
markdown: fs20.readFileSync(markdownPath, "utf8"),
|
|
15502
|
+
sourcePath: path21.relative(safe.worktree, markdownPath),
|
|
15227
15503
|
parentBranch: args.parent_branch,
|
|
15228
15504
|
parentTaskType: args.parent_task_type || "Tarea",
|
|
15229
15505
|
apply: String(args.apply || "").toLowerCase() === "true"
|
|
@@ -15593,7 +15869,7 @@ Backfilled messages: ${backfilled}`;
|
|
|
15593
15869
|
if (!existing) {
|
|
15594
15870
|
return "FAIL: No active discussion exists for this session.";
|
|
15595
15871
|
}
|
|
15596
|
-
const discussionPath =
|
|
15872
|
+
const discussionPath = path21.join(toolWorktree, existing.transcriptPath);
|
|
15597
15873
|
setDiscussionStatus(discussionPath, "summarizing");
|
|
15598
15874
|
existing.status = "summarizing";
|
|
15599
15875
|
saveDiscussionRegistry(toolWorktree, toolRegistry);
|
|
@@ -15645,7 +15921,7 @@ Reason: ${err.message}`;
|
|
|
15645
15921
|
try {
|
|
15646
15922
|
const sessionResult = await client.session.create({
|
|
15647
15923
|
query: { directory: workflowDirectory },
|
|
15648
|
-
body: { title: `Workflow Run: ${
|
|
15924
|
+
body: { title: `Workflow Run: ${path21.basename(workflowTaskPath)}` }
|
|
15649
15925
|
});
|
|
15650
15926
|
const sessionId = sessionResult.data.id;
|
|
15651
15927
|
activeWorkflows.set(sessionId, { pmaSessionId, taskPath: workflowTaskPath, track: workflowTrack, directory: workflowDirectory });
|
|
@@ -15830,13 +16106,13 @@ function usage() {
|
|
|
15830
16106
|
}
|
|
15831
16107
|
function expandHome(inputPath) {
|
|
15832
16108
|
if (!inputPath || inputPath === "~") return os7.homedir();
|
|
15833
|
-
if (inputPath.startsWith("~/")) return
|
|
16109
|
+
if (inputPath.startsWith("~/")) return path22.join(os7.homedir(), inputPath.slice(2));
|
|
15834
16110
|
return inputPath;
|
|
15835
16111
|
}
|
|
15836
16112
|
function resolveOpenCodeDbPath(inputPath = null) {
|
|
15837
16113
|
const expanded = expandHome(inputPath || process.env.OPTIMA_OPENCODE_DB_PATH || DEFAULT_DB_PATH);
|
|
15838
16114
|
try {
|
|
15839
|
-
if (
|
|
16115
|
+
if (fs21.existsSync(expanded) && fs21.statSync(expanded).isDirectory()) return path22.join(expanded, "opencode.db");
|
|
15840
16116
|
} catch {
|
|
15841
16117
|
return expanded;
|
|
15842
16118
|
}
|
|
@@ -15900,12 +16176,12 @@ function extractOpenedPathValue(value) {
|
|
|
15900
16176
|
}
|
|
15901
16177
|
function normalizePathCandidate(candidate) {
|
|
15902
16178
|
const expanded = expandHome(candidate);
|
|
15903
|
-
if (!
|
|
15904
|
-
return
|
|
16179
|
+
if (!path22.isAbsolute(expanded)) return null;
|
|
16180
|
+
return path22.resolve(expanded);
|
|
15905
16181
|
}
|
|
15906
16182
|
function discoverOpenCodePaths(dbPath) {
|
|
15907
16183
|
const resolvedDb = resolveOpenCodeDbPath(dbPath);
|
|
15908
|
-
if (!
|
|
16184
|
+
if (!fs21.existsSync(resolvedDb)) throw new Error(`OpenCode database not found: ${resolvedDb}`);
|
|
15909
16185
|
const tables = sqliteJson(resolvedDb, "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name");
|
|
15910
16186
|
const discovered = /* @__PURE__ */ new Set();
|
|
15911
16187
|
for (const table of tables) {
|
|
@@ -15930,27 +16206,27 @@ function discoverOpenCodePaths(dbPath) {
|
|
|
15930
16206
|
function collectMarkdownOverridesFrom(baseDir) {
|
|
15931
16207
|
const files = [];
|
|
15932
16208
|
for (const dirName of OVERRIDE_DIRS) {
|
|
15933
|
-
const dirPath =
|
|
15934
|
-
if (!
|
|
15935
|
-
for (const entry of
|
|
16209
|
+
const dirPath = path22.join(baseDir, dirName);
|
|
16210
|
+
if (!fs21.existsSync(dirPath)) continue;
|
|
16211
|
+
for (const entry of fs21.readdirSync(dirPath, { withFileTypes: true })) {
|
|
15936
16212
|
if (!entry.isFile()) continue;
|
|
15937
16213
|
if (!entry.name.endsWith(".md")) continue;
|
|
15938
16214
|
if (entry.name.toLowerCase() === "readme.md") continue;
|
|
15939
|
-
files.push(
|
|
16215
|
+
files.push(path22.join(dirPath, entry.name));
|
|
15940
16216
|
}
|
|
15941
16217
|
}
|
|
15942
16218
|
return files;
|
|
15943
16219
|
}
|
|
15944
16220
|
function collectOverrideFiles(worktree) {
|
|
15945
|
-
return collectMarkdownOverridesFrom(
|
|
16221
|
+
return collectMarkdownOverridesFrom(path22.join(worktree, ".optima")).sort();
|
|
15946
16222
|
}
|
|
15947
16223
|
function collectPlannedOverrideFiles(worktree) {
|
|
15948
16224
|
return [
|
|
15949
16225
|
...collectOverrideFiles(worktree),
|
|
15950
|
-
...collectMarkdownOverridesFrom(
|
|
15951
|
-
...collectMarkdownOverridesFrom(
|
|
15952
|
-
...collectMarkdownOverridesFrom(
|
|
15953
|
-
...collectMarkdownOverridesFrom(
|
|
16226
|
+
...collectMarkdownOverridesFrom(path22.join(worktree, ".staticeng")),
|
|
16227
|
+
...collectMarkdownOverridesFrom(path22.join(worktree, ".orbita")),
|
|
16228
|
+
...collectMarkdownOverridesFrom(path22.join(worktree, ".nomadwork")),
|
|
16229
|
+
...collectMarkdownOverridesFrom(path22.join(worktree, ".nomadworks"))
|
|
15954
16230
|
].sort();
|
|
15955
16231
|
}
|
|
15956
16232
|
var CRC_TABLE = (() => {
|
|
@@ -15983,14 +16259,14 @@ function writeUInt16LE(value) {
|
|
|
15983
16259
|
return buffer;
|
|
15984
16260
|
}
|
|
15985
16261
|
function createZipBackup(files, backupPath) {
|
|
15986
|
-
|
|
16262
|
+
fs21.mkdirSync(path22.dirname(backupPath), { recursive: true });
|
|
15987
16263
|
const localParts = [];
|
|
15988
16264
|
const centralParts = [];
|
|
15989
16265
|
let offset = 0;
|
|
15990
16266
|
const now = dosTimeDate();
|
|
15991
16267
|
for (const filePath of files) {
|
|
15992
|
-
const data =
|
|
15993
|
-
const name =
|
|
16268
|
+
const data = fs21.readFileSync(filePath);
|
|
16269
|
+
const name = path22.resolve(filePath).replace(/^\//, "").split(path22.sep).join("/");
|
|
15994
16270
|
const nameBuffer = Buffer.from(name, "utf8");
|
|
15995
16271
|
const crc = crc32(data);
|
|
15996
16272
|
const local = Buffer.concat([
|
|
@@ -16042,7 +16318,7 @@ function createZipBackup(files, backupPath) {
|
|
|
16042
16318
|
writeUInt32LE(offset),
|
|
16043
16319
|
writeUInt16LE(0)
|
|
16044
16320
|
]);
|
|
16045
|
-
|
|
16321
|
+
fs21.writeFileSync(backupPath, Buffer.concat([...localParts, ...centralParts, end]));
|
|
16046
16322
|
}
|
|
16047
16323
|
function timestamp() {
|
|
16048
16324
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
@@ -16052,17 +16328,17 @@ function validationStatus(result) {
|
|
|
16052
16328
|
return result.ok ? "passed" : "failed";
|
|
16053
16329
|
}
|
|
16054
16330
|
function hasLegacyMarker(worktree) {
|
|
16055
|
-
return
|
|
16331
|
+
return fs21.existsSync(path22.join(worktree, ".staticeng")) || fs21.existsSync(path22.join(worktree, ".orbita")) || fs21.existsSync(path22.join(worktree, ".nomadwork")) || fs21.existsSync(path22.join(worktree, ".nomadworks"));
|
|
16056
16332
|
}
|
|
16057
16333
|
function rootOptimaArtifacts(worktree) {
|
|
16058
16334
|
const artifacts = [
|
|
16059
|
-
["tasks/",
|
|
16060
|
-
["evidences/",
|
|
16061
|
-
["docs/scrs/",
|
|
16062
|
-
["codemap.yml",
|
|
16063
|
-
["codemap.yaml",
|
|
16335
|
+
["tasks/", path22.join(worktree, "tasks")],
|
|
16336
|
+
["evidences/", path22.join(worktree, "evidences")],
|
|
16337
|
+
["docs/scrs/", path22.join(worktree, "docs", "scrs")],
|
|
16338
|
+
["codemap.yml", path22.join(worktree, "codemap.yml")],
|
|
16339
|
+
["codemap.yaml", path22.join(worktree, "codemap.yaml")]
|
|
16064
16340
|
];
|
|
16065
|
-
return artifacts.map(([display, artifactPath]) => ({ display, path: artifactPath })).filter((item) =>
|
|
16341
|
+
return artifacts.map(([display, artifactPath]) => ({ display, path: artifactPath })).filter((item) => fs21.existsSync(item.path));
|
|
16066
16342
|
}
|
|
16067
16343
|
function hasSanitizableOverrides(worktree) {
|
|
16068
16344
|
return collectPlannedOverrideFiles(worktree).length > 0;
|
|
@@ -16088,7 +16364,7 @@ function planOptimaMigration(worktree, dryRun) {
|
|
|
16088
16364
|
...overrides.map((file) => ({
|
|
16089
16365
|
category: "override",
|
|
16090
16366
|
action: dryRun ? "would_remove_after_backup" : "removed_after_backup",
|
|
16091
|
-
path:
|
|
16367
|
+
path: path22.relative(worktree, file).split(path22.sep).join("/"),
|
|
16092
16368
|
detail: "Remove implicit agent/policy override after host-level backup."
|
|
16093
16369
|
}))
|
|
16094
16370
|
],
|
|
@@ -16109,12 +16385,12 @@ async function sanitizeHost(options = {}) {
|
|
|
16109
16385
|
const repoStates = [];
|
|
16110
16386
|
for (const candidate of paths) {
|
|
16111
16387
|
try {
|
|
16112
|
-
if (!
|
|
16388
|
+
if (!fs21.existsSync(candidate)) {
|
|
16113
16389
|
report.totals.skipped += 1;
|
|
16114
16390
|
report.repos.push({ path: candidate, status: "skipped", reason: "missing" });
|
|
16115
16391
|
continue;
|
|
16116
16392
|
}
|
|
16117
|
-
if (!
|
|
16393
|
+
if (!fs21.statSync(candidate).isDirectory()) {
|
|
16118
16394
|
report.totals.skipped += 1;
|
|
16119
16395
|
report.repos.push({ path: candidate, status: "skipped", reason: "not_directory" });
|
|
16120
16396
|
continue;
|
|
@@ -16136,7 +16412,7 @@ async function sanitizeHost(options = {}) {
|
|
|
16136
16412
|
const overrides = repoStates.flatMap((state) => state.overrideFiles.map((file) => ({ repo: state.repo, file })));
|
|
16137
16413
|
report.totals.overrideFiles = overrides.length;
|
|
16138
16414
|
if (!dryRun && overrides.length > 0) {
|
|
16139
|
-
const backupPath =
|
|
16415
|
+
const backupPath = path22.join(os7.homedir(), BACKUP_DIRNAME, `${timestamp()}.zip`);
|
|
16140
16416
|
try {
|
|
16141
16417
|
createZipBackup(overrides.map((item) => item.file), backupPath);
|
|
16142
16418
|
report.backupPath = backupPath;
|
|
@@ -16152,7 +16428,7 @@ async function sanitizeHost(options = {}) {
|
|
|
16152
16428
|
for (const state of repoStates) {
|
|
16153
16429
|
try {
|
|
16154
16430
|
if (!dryRun) {
|
|
16155
|
-
for (const file of state.overrideFiles)
|
|
16431
|
+
for (const file of state.overrideFiles) fs21.rmSync(file, { force: true });
|
|
16156
16432
|
}
|
|
16157
16433
|
const validation = !dryRun && hasLegacyMarker(state.repo) ? await optima_validate_logic(state.repo) : null;
|
|
16158
16434
|
const status = (!validation || validation.ok) && state.plan.unresolved.length === 0 ? "repaired" : "failed";
|
|
@@ -16165,7 +16441,7 @@ async function sanitizeHost(options = {}) {
|
|
|
16165
16441
|
repairActions: state.plan.actions.length,
|
|
16166
16442
|
repairSkipped: state.plan.skippedRepair === true,
|
|
16167
16443
|
overrideFiles: state.overrideFiles.length,
|
|
16168
|
-
overridePaths: state.overrideFiles.map((file) =>
|
|
16444
|
+
overridePaths: state.overrideFiles.map((file) => path22.relative(state.repo, file).split(path22.sep).join("/")),
|
|
16169
16445
|
validation: validation ? validationStatus(validation) : "skipped",
|
|
16170
16446
|
unresolved: state.plan.unresolved
|
|
16171
16447
|
});
|