@exodus/xqa 1.15.1 → 1.16.0
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/README.md +2 -0
- package/dist/xqa.cjs +611 -538
- package/package.json +4 -4
package/dist/xqa.cjs
CHANGED
|
@@ -3539,11 +3539,11 @@ var require_index_cjs = __commonJS({
|
|
|
3539
3539
|
try {
|
|
3540
3540
|
step(g3[n3](v2));
|
|
3541
3541
|
} catch (e3) {
|
|
3542
|
-
|
|
3542
|
+
settle(q4[0][3], e3);
|
|
3543
3543
|
}
|
|
3544
3544
|
}
|
|
3545
3545
|
function step(r3) {
|
|
3546
|
-
r3.value instanceof __await2 ? Promise.resolve(r3.value.v).then(fulfill, reject) :
|
|
3546
|
+
r3.value instanceof __await2 ? Promise.resolve(r3.value.v).then(fulfill, reject) : settle(q4[0][2], r3);
|
|
3547
3547
|
}
|
|
3548
3548
|
function fulfill(value) {
|
|
3549
3549
|
resume("next", value);
|
|
@@ -3551,7 +3551,7 @@ var require_index_cjs = __commonJS({
|
|
|
3551
3551
|
function reject(value) {
|
|
3552
3552
|
resume("throw", value);
|
|
3553
3553
|
}
|
|
3554
|
-
function
|
|
3554
|
+
function settle(f6, v2) {
|
|
3555
3555
|
if (f6(v2), q4.shift(), q4.length) resume(q4[0][0], q4[0][1]);
|
|
3556
3556
|
}
|
|
3557
3557
|
}
|
|
@@ -3577,11 +3577,11 @@ var require_index_cjs = __commonJS({
|
|
|
3577
3577
|
function verb(n3) {
|
|
3578
3578
|
i3[n3] = o3[n3] && function(v2) {
|
|
3579
3579
|
return new Promise(function(resolve, reject) {
|
|
3580
|
-
v2 = o3[n3](v2),
|
|
3580
|
+
v2 = o3[n3](v2), settle(resolve, reject, v2.done, v2.value);
|
|
3581
3581
|
});
|
|
3582
3582
|
};
|
|
3583
3583
|
}
|
|
3584
|
-
function
|
|
3584
|
+
function settle(resolve, reject, d, v2) {
|
|
3585
3585
|
Promise.resolve(v2).then(function(v3) {
|
|
3586
3586
|
resolve({ value: v3, done: d });
|
|
3587
3587
|
}, reject);
|
|
@@ -19623,8 +19623,8 @@ var require_queue = __commonJS({
|
|
|
19623
19623
|
var errorHandler = null;
|
|
19624
19624
|
var self2 = {
|
|
19625
19625
|
push,
|
|
19626
|
-
drain:
|
|
19627
|
-
saturated:
|
|
19626
|
+
drain: noop2,
|
|
19627
|
+
saturated: noop2,
|
|
19628
19628
|
pause,
|
|
19629
19629
|
paused: false,
|
|
19630
19630
|
get concurrency() {
|
|
@@ -19647,7 +19647,7 @@ var require_queue = __commonJS({
|
|
|
19647
19647
|
length,
|
|
19648
19648
|
getQueue,
|
|
19649
19649
|
unshift,
|
|
19650
|
-
empty:
|
|
19650
|
+
empty: noop2,
|
|
19651
19651
|
kill,
|
|
19652
19652
|
killAndDrain,
|
|
19653
19653
|
error: error48,
|
|
@@ -19699,7 +19699,7 @@ var require_queue = __commonJS({
|
|
|
19699
19699
|
current.context = context;
|
|
19700
19700
|
current.release = release;
|
|
19701
19701
|
current.value = value;
|
|
19702
|
-
current.callback = done ||
|
|
19702
|
+
current.callback = done || noop2;
|
|
19703
19703
|
current.errorHandler = errorHandler;
|
|
19704
19704
|
if (_running >= _concurrency || self2.paused) {
|
|
19705
19705
|
if (queueTail) {
|
|
@@ -19720,7 +19720,7 @@ var require_queue = __commonJS({
|
|
|
19720
19720
|
current.context = context;
|
|
19721
19721
|
current.release = release;
|
|
19722
19722
|
current.value = value;
|
|
19723
|
-
current.callback = done ||
|
|
19723
|
+
current.callback = done || noop2;
|
|
19724
19724
|
current.errorHandler = errorHandler;
|
|
19725
19725
|
if (_running >= _concurrency || self2.paused) {
|
|
19726
19726
|
if (queueHead) {
|
|
@@ -19762,13 +19762,13 @@ var require_queue = __commonJS({
|
|
|
19762
19762
|
function kill() {
|
|
19763
19763
|
queueHead = null;
|
|
19764
19764
|
queueTail = null;
|
|
19765
|
-
self2.drain =
|
|
19765
|
+
self2.drain = noop2;
|
|
19766
19766
|
}
|
|
19767
19767
|
function killAndDrain() {
|
|
19768
19768
|
queueHead = null;
|
|
19769
19769
|
queueTail = null;
|
|
19770
19770
|
self2.drain();
|
|
19771
|
-
self2.drain =
|
|
19771
|
+
self2.drain = noop2;
|
|
19772
19772
|
}
|
|
19773
19773
|
function abort() {
|
|
19774
19774
|
var current = queueHead;
|
|
@@ -19781,7 +19781,7 @@ var require_queue = __commonJS({
|
|
|
19781
19781
|
var val = current.value;
|
|
19782
19782
|
var context2 = current.context;
|
|
19783
19783
|
current.value = null;
|
|
19784
|
-
current.callback =
|
|
19784
|
+
current.callback = noop2;
|
|
19785
19785
|
current.errorHandler = null;
|
|
19786
19786
|
if (errorHandler2) {
|
|
19787
19787
|
errorHandler2(new Error("abort"), val);
|
|
@@ -19790,19 +19790,19 @@ var require_queue = __commonJS({
|
|
|
19790
19790
|
current.release(current);
|
|
19791
19791
|
current = next;
|
|
19792
19792
|
}
|
|
19793
|
-
self2.drain =
|
|
19793
|
+
self2.drain = noop2;
|
|
19794
19794
|
}
|
|
19795
19795
|
function error48(handler) {
|
|
19796
19796
|
errorHandler = handler;
|
|
19797
19797
|
}
|
|
19798
19798
|
}
|
|
19799
|
-
function
|
|
19799
|
+
function noop2() {
|
|
19800
19800
|
}
|
|
19801
19801
|
function Task3() {
|
|
19802
19802
|
this.value = null;
|
|
19803
|
-
this.callback =
|
|
19803
|
+
this.callback = noop2;
|
|
19804
19804
|
this.next = null;
|
|
19805
|
-
this.release =
|
|
19805
|
+
this.release = noop2;
|
|
19806
19806
|
this.context = null;
|
|
19807
19807
|
this.errorHandler = null;
|
|
19808
19808
|
var self2 = this;
|
|
@@ -19811,7 +19811,7 @@ var require_queue = __commonJS({
|
|
|
19811
19811
|
var errorHandler = self2.errorHandler;
|
|
19812
19812
|
var val = self2.value;
|
|
19813
19813
|
self2.value = null;
|
|
19814
|
-
self2.callback =
|
|
19814
|
+
self2.callback = noop2;
|
|
19815
19815
|
if (self2.errorHandler) {
|
|
19816
19816
|
errorHandler(err20, val);
|
|
19817
19817
|
}
|
|
@@ -19847,7 +19847,7 @@ var require_queue = __commonJS({
|
|
|
19847
19847
|
resolve(result);
|
|
19848
19848
|
});
|
|
19849
19849
|
});
|
|
19850
|
-
p.catch(
|
|
19850
|
+
p.catch(noop2);
|
|
19851
19851
|
return p;
|
|
19852
19852
|
}
|
|
19853
19853
|
function unshift(value) {
|
|
@@ -19860,7 +19860,7 @@ var require_queue = __commonJS({
|
|
|
19860
19860
|
resolve(result);
|
|
19861
19861
|
});
|
|
19862
19862
|
});
|
|
19863
|
-
p.catch(
|
|
19863
|
+
p.catch(noop2);
|
|
19864
19864
|
return p;
|
|
19865
19865
|
}
|
|
19866
19866
|
function drained() {
|
|
@@ -52021,12 +52021,15 @@ var safeParseSimctlOutput = (0, import_neverthrow3.fromThrowable)(
|
|
|
52021
52021
|
cause
|
|
52022
52022
|
})
|
|
52023
52023
|
);
|
|
52024
|
+
function findBootedDeviceUdid(devices) {
|
|
52025
|
+
const booted = devices.find((device) => device.state === "Booted");
|
|
52026
|
+
return booted?.udid;
|
|
52027
|
+
}
|
|
52024
52028
|
function findBootedUdid(parsed) {
|
|
52025
52029
|
for (const devices of Object.values(parsed.devices)) {
|
|
52026
|
-
|
|
52027
|
-
|
|
52028
|
-
|
|
52029
|
-
}
|
|
52030
|
+
const udid = findBootedDeviceUdid(devices);
|
|
52031
|
+
if (udid !== void 0) {
|
|
52032
|
+
return udid;
|
|
52030
52033
|
}
|
|
52031
52034
|
}
|
|
52032
52035
|
return {
|
|
@@ -52062,24 +52065,6 @@ var DEFAULT_SCREEN_WIDTH = 375;
|
|
|
52062
52065
|
var DEFAULT_SCREEN_HEIGHT = 812;
|
|
52063
52066
|
var STABILITY_POLL_ATTEMPTS = 10;
|
|
52064
52067
|
var STABILITY_POLL_DELAY_MS = 500;
|
|
52065
|
-
function structuralSignature(elements) {
|
|
52066
|
-
const lines = [];
|
|
52067
|
-
const walk = (nodes) => {
|
|
52068
|
-
for (const element of nodes) {
|
|
52069
|
-
const frame = element.frame ?? { x: 0, y: 0, width: 0, height: 0 };
|
|
52070
|
-
const type2 = element.type ?? "unknown";
|
|
52071
|
-
const childCount = (element.children ?? []).length;
|
|
52072
|
-
lines.push(
|
|
52073
|
-
`${type2}|${String(frame.x)},${String(frame.y)},${String(frame.width)},${String(frame.height)}|${String(childCount)}`
|
|
52074
|
-
);
|
|
52075
|
-
if (element.children) {
|
|
52076
|
-
walk(element.children);
|
|
52077
|
-
}
|
|
52078
|
-
}
|
|
52079
|
-
};
|
|
52080
|
-
walk(elements);
|
|
52081
|
-
return lines.join("\n");
|
|
52082
|
-
}
|
|
52083
52068
|
function isInViewport(frame, screen) {
|
|
52084
52069
|
return frame.width > 0 && frame.height > 0 && frame.x + frame.width > 0 && frame.x < screen.width && frame.y + frame.height > 0 && frame.y < screen.height;
|
|
52085
52070
|
}
|
|
@@ -52098,14 +52083,16 @@ function hasEnabledDescendant(element) {
|
|
|
52098
52083
|
const children = element.children ?? [];
|
|
52099
52084
|
return children.some((child) => child.enabled !== false || hasEnabledDescendant(child));
|
|
52100
52085
|
}
|
|
52086
|
+
function isRicher(current, best) {
|
|
52087
|
+
if (current.hasEnabled !== best.hasEnabled) {
|
|
52088
|
+
return current.hasEnabled;
|
|
52089
|
+
}
|
|
52090
|
+
return current.count >= best.count;
|
|
52091
|
+
}
|
|
52101
52092
|
function selectRichest(scores) {
|
|
52102
52093
|
let best = scores[0];
|
|
52103
52094
|
for (const current of scores.slice(1)) {
|
|
52104
|
-
if (current
|
|
52105
|
-
if (current.hasEnabled) {
|
|
52106
|
-
best = current;
|
|
52107
|
-
}
|
|
52108
|
-
} else if (current.count >= best.count) {
|
|
52095
|
+
if (isRicher(current, best)) {
|
|
52109
52096
|
best = current;
|
|
52110
52097
|
}
|
|
52111
52098
|
}
|
|
@@ -52179,18 +52166,6 @@ function formatElement(element, screen) {
|
|
|
52179
52166
|
const clipping = resolveClippingTags(frame, screen);
|
|
52180
52167
|
return `[${type2}] "${label}" at (${String(cx)}, ${String(cy)}) size ${String(Math.round(frame.width))}x${String(Math.round(frame.height))}${state}${clipping}`;
|
|
52181
52168
|
}
|
|
52182
|
-
function formatAccessibilityElements(elements) {
|
|
52183
|
-
const app = elements.find((element) => element.type === "Application");
|
|
52184
|
-
const screenWidth = app?.frame?.width ?? DEFAULT_SCREEN_WIDTH;
|
|
52185
|
-
const screenHeight = app?.frame?.height ?? DEFAULT_SCREEN_HEIGHT;
|
|
52186
|
-
const screen = { width: screenWidth, height: screenHeight };
|
|
52187
|
-
const visible = collectElements(elements, screen);
|
|
52188
|
-
const elementList = visible.length === 0 ? "No elements found." : visible.map((element) => formatElement(element, screen)).join("\n");
|
|
52189
|
-
const appName = app?.AXLabel;
|
|
52190
|
-
return appName ? `Running app: ${appName}
|
|
52191
|
-
|
|
52192
|
-
${elementList}` : elementList;
|
|
52193
|
-
}
|
|
52194
52169
|
function fetchSnapshot(udid) {
|
|
52195
52170
|
return runCommand("idb", ["ui", "describe-all", "--udid", udid, "--json", "--nested"]);
|
|
52196
52171
|
}
|
|
@@ -52220,7 +52195,37 @@ async function pollUntilStable(udid) {
|
|
|
52220
52195
|
return (0, import_neverthrow.ok)(previousRaw);
|
|
52221
52196
|
}
|
|
52222
52197
|
function waitForStableSnapshot(udid) {
|
|
52223
|
-
return
|
|
52198
|
+
return import_neverthrow.ResultAsync.fromSafePromise(pollUntilStable(udid)).andThen((result) => result);
|
|
52199
|
+
}
|
|
52200
|
+
function structuralSignature(elements) {
|
|
52201
|
+
const lines = [];
|
|
52202
|
+
const walk = (nodes) => {
|
|
52203
|
+
for (const element of nodes) {
|
|
52204
|
+
const frame = element.frame ?? { x: 0, y: 0, width: 0, height: 0 };
|
|
52205
|
+
const type2 = element.type ?? "unknown";
|
|
52206
|
+
const childCount = (element.children ?? []).length;
|
|
52207
|
+
lines.push(
|
|
52208
|
+
`${type2}|${String(frame.x)},${String(frame.y)},${String(frame.width)},${String(frame.height)}|${String(childCount)}`
|
|
52209
|
+
);
|
|
52210
|
+
if (element.children) {
|
|
52211
|
+
walk(element.children);
|
|
52212
|
+
}
|
|
52213
|
+
}
|
|
52214
|
+
};
|
|
52215
|
+
walk(elements);
|
|
52216
|
+
return lines.join("\n");
|
|
52217
|
+
}
|
|
52218
|
+
function formatAccessibilityElements(elements) {
|
|
52219
|
+
const app = elements.find((element) => element.type === "Application");
|
|
52220
|
+
const screenWidth = app?.frame?.width ?? DEFAULT_SCREEN_WIDTH;
|
|
52221
|
+
const screenHeight = app?.frame?.height ?? DEFAULT_SCREEN_HEIGHT;
|
|
52222
|
+
const screen = { width: screenWidth, height: screenHeight };
|
|
52223
|
+
const visible = collectElements(elements, screen);
|
|
52224
|
+
const elementList = visible.length === 0 ? "No elements found." : visible.map((element) => formatElement(element, screen)).join("\n");
|
|
52225
|
+
const appName = app?.AXLabel;
|
|
52226
|
+
return appName ? `Running app: ${appName}
|
|
52227
|
+
|
|
52228
|
+
${elementList}` : elementList;
|
|
52224
52229
|
}
|
|
52225
52230
|
function captureAccessibilityTree(udid = "booted") {
|
|
52226
52231
|
return resolveUdid(udid).andThen((resolvedUdid) => waitForStableSnapshot(resolvedUdid)).andThen((raw) => parseIdbTree(raw));
|
|
@@ -52740,17 +52745,13 @@ function parseRuntime(runtimeKey) {
|
|
|
52740
52745
|
}
|
|
52741
52746
|
return match[1].replaceAll("-", ".");
|
|
52742
52747
|
}
|
|
52748
|
+
function extractBootedFromDevices(devices, runtime) {
|
|
52749
|
+
return devices.filter((device) => device.state === "Booted" && device.isAvailable).map((device) => ({ udid: device.udid, name: device.name, runtime }));
|
|
52750
|
+
}
|
|
52743
52751
|
function extractBootedSimulators(output) {
|
|
52744
|
-
|
|
52745
|
-
|
|
52746
|
-
|
|
52747
|
-
for (const device of devices) {
|
|
52748
|
-
if (device.state === "Booted" && device.isAvailable) {
|
|
52749
|
-
results.push({ udid: device.udid, name: device.name, runtime });
|
|
52750
|
-
}
|
|
52751
|
-
}
|
|
52752
|
-
}
|
|
52753
|
-
return results;
|
|
52752
|
+
return Object.entries(output.devices).flatMap(
|
|
52753
|
+
([runtimeKey, devices]) => extractBootedFromDevices(devices, parseRuntime(runtimeKey))
|
|
52754
|
+
);
|
|
52754
52755
|
}
|
|
52755
52756
|
function handleClose(code) {
|
|
52756
52757
|
if (code === 0) {
|
|
@@ -53449,9 +53450,6 @@ function createInputManager(stream) {
|
|
|
53449
53450
|
}
|
|
53450
53451
|
};
|
|
53451
53452
|
}
|
|
53452
|
-
function plainDecorator(frame, deps) {
|
|
53453
|
-
return frame.logAppend.flatMap((entry) => renderEntry(entry, deps)).join("");
|
|
53454
|
-
}
|
|
53455
53453
|
function renderEntry(entry, deps) {
|
|
53456
53454
|
const context = { itemId: entry.itemId, deps };
|
|
53457
53455
|
return entry.lines.flatMap((line) => renderLine(line, context));
|
|
@@ -53475,6 +53473,9 @@ function renderLine(line, context) {
|
|
|
53475
53473
|
}
|
|
53476
53474
|
}
|
|
53477
53475
|
}
|
|
53476
|
+
function plainDecorator(frame, deps) {
|
|
53477
|
+
return frame.logAppend.flatMap((entry) => renderEntry(entry, deps)).join("");
|
|
53478
|
+
}
|
|
53478
53479
|
var TRUECOLOR_LEVEL = 3;
|
|
53479
53480
|
var ERROR_COLOR = "#c0504d";
|
|
53480
53481
|
var TOOL_COLOR = "#7a9e82";
|
|
@@ -53575,7 +53576,7 @@ function emitTty(frame, state) {
|
|
|
53575
53576
|
previousDashboardLines: state.previousDashboardLines,
|
|
53576
53577
|
itemName: config3.itemName
|
|
53577
53578
|
});
|
|
53578
|
-
state.
|
|
53579
|
+
state.setPreviousDashboardLines(newDashboardLines);
|
|
53579
53580
|
if (output !== "") {
|
|
53580
53581
|
config3.stream.write(output);
|
|
53581
53582
|
}
|
|
@@ -53602,7 +53603,10 @@ function createWriter(config3) {
|
|
|
53602
53603
|
const state = {
|
|
53603
53604
|
config: config3,
|
|
53604
53605
|
previousDashboardLines: 0,
|
|
53605
|
-
cleaned: false
|
|
53606
|
+
cleaned: false,
|
|
53607
|
+
setPreviousDashboardLines(value) {
|
|
53608
|
+
this.previousDashboardLines = value;
|
|
53609
|
+
}
|
|
53606
53610
|
};
|
|
53607
53611
|
config3.stream.write(HIDE_CURSOR);
|
|
53608
53612
|
return {
|
|
@@ -53622,30 +53626,6 @@ var OVERVIEW_HINT = "[1-9] zoom [e] expand [q] quit";
|
|
|
53622
53626
|
var FOCUSED_HINT = "[esc] back [q] quit";
|
|
53623
53627
|
var SOLO_HINT = "";
|
|
53624
53628
|
var MIN_ITEMS_FOR_ZOOM = 2;
|
|
53625
|
-
function buildDashboard(state) {
|
|
53626
|
-
if (state.ui.role === "solo") {
|
|
53627
|
-
return [];
|
|
53628
|
-
}
|
|
53629
|
-
if (typeof state.ui.zoomedIndex === "number") {
|
|
53630
|
-
return buildZoomed(state, state.ui.zoomedIndex);
|
|
53631
|
-
}
|
|
53632
|
-
if (state.ui.isExpanded) {
|
|
53633
|
-
return buildExpanded(state);
|
|
53634
|
-
}
|
|
53635
|
-
return buildOverview(state);
|
|
53636
|
-
}
|
|
53637
|
-
function buildHint(state) {
|
|
53638
|
-
if (state.ui.role === "solo") {
|
|
53639
|
-
return SOLO_HINT;
|
|
53640
|
-
}
|
|
53641
|
-
if (typeof state.ui.zoomedIndex === "number" || state.ui.isExpanded) {
|
|
53642
|
-
return FOCUSED_HINT;
|
|
53643
|
-
}
|
|
53644
|
-
if (state.itemOrder.length < MIN_ITEMS_FOR_ZOOM) {
|
|
53645
|
-
return "[q] quit";
|
|
53646
|
-
}
|
|
53647
|
-
return OVERVIEW_HINT;
|
|
53648
|
-
}
|
|
53649
53629
|
function buildOverview(state) {
|
|
53650
53630
|
return state.itemOrder.flatMap((id, index) => {
|
|
53651
53631
|
const item = state.items.get(id);
|
|
@@ -53694,6 +53674,33 @@ function prefixTextLine(line, name) {
|
|
|
53694
53674
|
}
|
|
53695
53675
|
return [{ ...line, text: `[${name}] ${line.text}` }];
|
|
53696
53676
|
}
|
|
53677
|
+
function buildDashboard(state) {
|
|
53678
|
+
if (state.ui.role === "solo") {
|
|
53679
|
+
return [];
|
|
53680
|
+
}
|
|
53681
|
+
if (typeof state.ui.zoomedIndex === "number") {
|
|
53682
|
+
return buildZoomed(state, state.ui.zoomedIndex);
|
|
53683
|
+
}
|
|
53684
|
+
if (state.ui.isExpanded) {
|
|
53685
|
+
return buildExpanded(state);
|
|
53686
|
+
}
|
|
53687
|
+
return buildOverview(state);
|
|
53688
|
+
}
|
|
53689
|
+
function buildHint(state) {
|
|
53690
|
+
if (state.ui.role === "solo") {
|
|
53691
|
+
return SOLO_HINT;
|
|
53692
|
+
}
|
|
53693
|
+
if (typeof state.ui.zoomedIndex === "number" || state.ui.isExpanded) {
|
|
53694
|
+
return FOCUSED_HINT;
|
|
53695
|
+
}
|
|
53696
|
+
if (state.itemOrder.length < MIN_ITEMS_FOR_ZOOM) {
|
|
53697
|
+
return "[q] quit";
|
|
53698
|
+
}
|
|
53699
|
+
return OVERVIEW_HINT;
|
|
53700
|
+
}
|
|
53701
|
+
function dashboardEqual(left, right) {
|
|
53702
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
53703
|
+
}
|
|
53697
53704
|
function render(state, previous) {
|
|
53698
53705
|
const dashboard = buildDashboard(state);
|
|
53699
53706
|
const logAppend = state.log.length > previous.log.length ? state.log.slice(previous.log.length) : [];
|
|
@@ -53705,9 +53712,6 @@ function render(state, previous) {
|
|
|
53705
53712
|
dashboardChanged: !dashboardEqual(previousDashboard, dashboard)
|
|
53706
53713
|
};
|
|
53707
53714
|
}
|
|
53708
|
-
function dashboardEqual(left, right) {
|
|
53709
|
-
return JSON.stringify(left) === JSON.stringify(right);
|
|
53710
|
-
}
|
|
53711
53715
|
var MS_PER_SECOND3 = 1e3;
|
|
53712
53716
|
function formatDuration(ms) {
|
|
53713
53717
|
return `${String(Math.round(ms / MS_PER_SECOND3))}s`;
|
|
@@ -53789,6 +53793,22 @@ var ALL_VERBOSE_CATEGORIES = /* @__PURE__ */ new Set([
|
|
|
53789
53793
|
"screen",
|
|
53790
53794
|
"memory"
|
|
53791
53795
|
]);
|
|
53796
|
+
function parseForceColor(value) {
|
|
53797
|
+
const forced = Number(value);
|
|
53798
|
+
if (forced === 0 || forced === 1 || forced === 2 || forced === COLOR_LEVEL_TRUECOLOR) {
|
|
53799
|
+
return forced;
|
|
53800
|
+
}
|
|
53801
|
+
return 1;
|
|
53802
|
+
}
|
|
53803
|
+
function isTruecolorTerm(colorterm) {
|
|
53804
|
+
return colorterm === "truecolor" || colorterm === "24bit";
|
|
53805
|
+
}
|
|
53806
|
+
function detectStreamColorLevel(stream) {
|
|
53807
|
+
if (stream.hasColors?.() === true) {
|
|
53808
|
+
return 1;
|
|
53809
|
+
}
|
|
53810
|
+
return 0;
|
|
53811
|
+
}
|
|
53792
53812
|
function isVerboseEnabled(config3, category) {
|
|
53793
53813
|
return config3?.has(category) ?? false;
|
|
53794
53814
|
}
|
|
@@ -53806,19 +53826,12 @@ function resolveColorLevel(stream) {
|
|
|
53806
53826
|
return 0;
|
|
53807
53827
|
}
|
|
53808
53828
|
if (process.env.FORCE_COLOR !== void 0) {
|
|
53809
|
-
|
|
53810
|
-
if (forced === 0 || forced === 1 || forced === 2 || forced === COLOR_LEVEL_TRUECOLOR) {
|
|
53811
|
-
return forced;
|
|
53812
|
-
}
|
|
53813
|
-
return 1;
|
|
53829
|
+
return parseForceColor(process.env.FORCE_COLOR);
|
|
53814
53830
|
}
|
|
53815
|
-
if (process.env.COLORTERM
|
|
53831
|
+
if (isTruecolorTerm(process.env.COLORTERM)) {
|
|
53816
53832
|
return COLOR_LEVEL_TRUECOLOR;
|
|
53817
53833
|
}
|
|
53818
|
-
|
|
53819
|
-
return 0;
|
|
53820
|
-
}
|
|
53821
|
-
return 1;
|
|
53834
|
+
return detectStreamColorLevel(stream);
|
|
53822
53835
|
}
|
|
53823
53836
|
var BYTES_PER_BASE64_CHAR = 0.75;
|
|
53824
53837
|
var BYTES_PER_KB = 1024;
|
|
@@ -54504,17 +54517,6 @@ function startSpinner(config3, onEvent) {
|
|
|
54504
54517
|
onEvent({ type: "TICK", at: Date.now() });
|
|
54505
54518
|
}, SPINNER_INTERVAL_MS);
|
|
54506
54519
|
}
|
|
54507
|
-
function cleanupRuntime(runtime) {
|
|
54508
|
-
if (runtime.cleaned) {
|
|
54509
|
-
return;
|
|
54510
|
-
}
|
|
54511
|
-
runtime.cleaned = true;
|
|
54512
|
-
if (runtime.spinnerHandle !== void 0) {
|
|
54513
|
-
clearInterval(runtime.spinnerHandle);
|
|
54514
|
-
}
|
|
54515
|
-
runtime.writer?.cleanup();
|
|
54516
|
-
runtime.inputManager?.cleanup();
|
|
54517
|
-
}
|
|
54518
54520
|
function createRuntime(role) {
|
|
54519
54521
|
return {
|
|
54520
54522
|
state: initialState(role),
|
|
@@ -54523,7 +54525,18 @@ function createRuntime(role) {
|
|
|
54523
54525
|
writer: void 0,
|
|
54524
54526
|
inputManager: void 0,
|
|
54525
54527
|
spinnerHandle: void 0,
|
|
54526
|
-
cleaned: false
|
|
54528
|
+
cleaned: false,
|
|
54529
|
+
cleanup() {
|
|
54530
|
+
if (this.cleaned) {
|
|
54531
|
+
return;
|
|
54532
|
+
}
|
|
54533
|
+
this.cleaned = true;
|
|
54534
|
+
if (this.spinnerHandle !== void 0) {
|
|
54535
|
+
clearInterval(this.spinnerHandle);
|
|
54536
|
+
}
|
|
54537
|
+
this.writer?.cleanup();
|
|
54538
|
+
this.inputManager?.cleanup();
|
|
54539
|
+
}
|
|
54527
54540
|
};
|
|
54528
54541
|
}
|
|
54529
54542
|
function createDisplay(config3) {
|
|
@@ -54540,7 +54553,7 @@ function createDisplay(config3) {
|
|
|
54540
54553
|
return {
|
|
54541
54554
|
onEvent,
|
|
54542
54555
|
cleanup: () => {
|
|
54543
|
-
|
|
54556
|
+
runtime.cleanup();
|
|
54544
54557
|
}
|
|
54545
54558
|
};
|
|
54546
54559
|
}
|
|
@@ -54943,11 +54956,11 @@ function __asyncGenerator(thisArg, _arguments, generator) {
|
|
|
54943
54956
|
try {
|
|
54944
54957
|
step(g3[n3](v2));
|
|
54945
54958
|
} catch (e3) {
|
|
54946
|
-
|
|
54959
|
+
settle(q4[0][3], e3);
|
|
54947
54960
|
}
|
|
54948
54961
|
}
|
|
54949
54962
|
function step(r3) {
|
|
54950
|
-
r3.value instanceof __await ? Promise.resolve(r3.value.v).then(fulfill, reject) :
|
|
54963
|
+
r3.value instanceof __await ? Promise.resolve(r3.value.v).then(fulfill, reject) : settle(q4[0][2], r3);
|
|
54951
54964
|
}
|
|
54952
54965
|
function fulfill(value) {
|
|
54953
54966
|
resume("next", value);
|
|
@@ -54955,7 +54968,7 @@ function __asyncGenerator(thisArg, _arguments, generator) {
|
|
|
54955
54968
|
function reject(value) {
|
|
54956
54969
|
resume("throw", value);
|
|
54957
54970
|
}
|
|
54958
|
-
function
|
|
54971
|
+
function settle(f6, v2) {
|
|
54959
54972
|
if (f6(v2), q4.shift(), q4.length) resume(q4[0][0], q4[0][1]);
|
|
54960
54973
|
}
|
|
54961
54974
|
}
|
|
@@ -56006,30 +56019,6 @@ async function uploadVideoFile(fileManager, videoPath) {
|
|
|
56006
56019
|
});
|
|
56007
56020
|
return uploadResponse.file.uri;
|
|
56008
56021
|
}
|
|
56009
|
-
function uploadVideo(videoPath, apiKey) {
|
|
56010
|
-
const fileManager = new GoogleAIFileManager(apiKey);
|
|
56011
|
-
return (0, import_neverthrow11.fromAsyncThrowable)(
|
|
56012
|
-
uploadVideoFile,
|
|
56013
|
-
(cause) => ({ type: "UPLOAD_FAILED", cause })
|
|
56014
|
-
)(fileManager, videoPath);
|
|
56015
|
-
}
|
|
56016
|
-
function pollUntilActive(fileUri, options) {
|
|
56017
|
-
const fileManager = new GoogleAIFileManager(options.apiKey);
|
|
56018
|
-
const fileName = extractFileName(fileUri);
|
|
56019
|
-
const checkState = async () => checkFileState(fileManager, fileName);
|
|
56020
|
-
return (0, import_neverthrow11.fromAsyncThrowable)(
|
|
56021
|
-
runPollLoop,
|
|
56022
|
-
(cause) => ({ type: "UPLOAD_FAILED", cause })
|
|
56023
|
-
)(checkState, options.onTick).andThen((outcome) => {
|
|
56024
|
-
if (outcome === "active") {
|
|
56025
|
-
return (0, import_neverthrow11.ok)(fileUri);
|
|
56026
|
-
}
|
|
56027
|
-
if (outcome === "failed") {
|
|
56028
|
-
return (0, import_neverthrow11.err)({ type: "PROCESSING_FAILED", fileUri });
|
|
56029
|
-
}
|
|
56030
|
-
return (0, import_neverthrow11.err)({ type: "POLL_TIMEOUT", fileUri });
|
|
56031
|
-
});
|
|
56032
|
-
}
|
|
56033
56022
|
async function generateAnalysisText({
|
|
56034
56023
|
genModel,
|
|
56035
56024
|
videoUri,
|
|
@@ -56063,6 +56052,30 @@ function buildGenerativeModel(apiKey, model) {
|
|
|
56063
56052
|
}
|
|
56064
56053
|
});
|
|
56065
56054
|
}
|
|
56055
|
+
function uploadVideo(videoPath, apiKey) {
|
|
56056
|
+
const fileManager = new GoogleAIFileManager(apiKey);
|
|
56057
|
+
return (0, import_neverthrow11.fromAsyncThrowable)(
|
|
56058
|
+
uploadVideoFile,
|
|
56059
|
+
(cause) => ({ type: "UPLOAD_FAILED", cause })
|
|
56060
|
+
)(fileManager, videoPath);
|
|
56061
|
+
}
|
|
56062
|
+
function pollUntilActive(fileUri, options) {
|
|
56063
|
+
const fileManager = new GoogleAIFileManager(options.apiKey);
|
|
56064
|
+
const fileName = extractFileName(fileUri);
|
|
56065
|
+
const checkState = async () => checkFileState(fileManager, fileName);
|
|
56066
|
+
return (0, import_neverthrow11.fromAsyncThrowable)(
|
|
56067
|
+
runPollLoop,
|
|
56068
|
+
(cause) => ({ type: "UPLOAD_FAILED", cause })
|
|
56069
|
+
)(checkState, options.onTick).andThen((outcome) => {
|
|
56070
|
+
if (outcome === "active") {
|
|
56071
|
+
return (0, import_neverthrow11.ok)(fileUri);
|
|
56072
|
+
}
|
|
56073
|
+
if (outcome === "failed") {
|
|
56074
|
+
return (0, import_neverthrow11.err)({ type: "PROCESSING_FAILED", fileUri });
|
|
56075
|
+
}
|
|
56076
|
+
return (0, import_neverthrow11.err)({ type: "POLL_TIMEOUT", fileUri });
|
|
56077
|
+
});
|
|
56078
|
+
}
|
|
56066
56079
|
function analyseArtifacts(options) {
|
|
56067
56080
|
const { videoUri, prompt, apiKey, model } = options;
|
|
56068
56081
|
const genModel = buildGenerativeModel(apiKey, model);
|
|
@@ -62231,7 +62244,6 @@ var import_neverthrow21 = __toESM(require_index_cjs(), 1);
|
|
|
62231
62244
|
var import_promises12 = require("node:fs/promises");
|
|
62232
62245
|
var import_node_path6 = __toESM(require("node:path"), 1);
|
|
62233
62246
|
var import_neverthrow22 = __toESM(require_index_cjs(), 1);
|
|
62234
|
-
var VIEW_UI_TOOL_NAME = "mcp__mobile-ios__view_ui";
|
|
62235
62247
|
var VIEW_UI_DESCRIPTION = `Capture current screen state: accessibility tree (element labels, positions, attributes) and screenshot in one call. Use when you need to tap an element, assert element presence or labels, check attributes, or track screen identity via <screen_id>.
|
|
62236
62248
|
|
|
62237
62249
|
The result begins with a <screen_id> tag containing the current screen identifier. Use this to detect screen changes and track navigation history.
|
|
@@ -62239,14 +62251,9 @@ The result begins with a <screen_id> tag containing the current screen identifie
|
|
|
62239
62251
|
Do not call \`screenshot\` immediately before or after this tool for the same state \u2014 this tool already includes the screenshot.
|
|
62240
62252
|
|
|
62241
62253
|
IMPORTANT: Snapshot coordinates and screenshot pixels are in the same logical point space. Do not apply any scaling factor (no 2x retina adjustment).`;
|
|
62242
|
-
|
|
62243
|
-
const match = /\[\w+\]\s+"([^"]+)"/.exec(tree);
|
|
62244
|
-
if (!match?.[1]) {
|
|
62245
|
-
return `step-${String(stepIndex)}`;
|
|
62246
|
-
}
|
|
62247
|
-
return match[1].replaceAll(/([A-Z])/g, "-$1").toLowerCase().replaceAll(/[^a-z\d]+/g, "-").replaceAll(/^-|-$/g, "");
|
|
62248
|
-
}
|
|
62254
|
+
var VIEW_UI_TOOL_NAME = "mcp__mobile-ios__view_ui";
|
|
62249
62255
|
async function persistScreenshot(params) {
|
|
62256
|
+
const targetSnapshot = params.snapshot;
|
|
62250
62257
|
const screenshotPath = import_node_path4.default.join(params.screenshotsDirectory, `${params.screenLabel}.png`);
|
|
62251
62258
|
const safeWriteFile = (0, import_neverthrow17.fromAsyncThrowable)(
|
|
62252
62259
|
import_promises10.writeFile,
|
|
@@ -62258,7 +62265,7 @@ async function persistScreenshot(params) {
|
|
|
62258
62265
|
() => false
|
|
62259
62266
|
);
|
|
62260
62267
|
if (succeeded) {
|
|
62261
|
-
|
|
62268
|
+
targetSnapshot.screenshotPath = screenshotPath;
|
|
62262
62269
|
}
|
|
62263
62270
|
}
|
|
62264
62271
|
function buildTextContent(structuralHash, formatted) {
|
|
@@ -62337,13 +62344,14 @@ async function enrichContentWithScreenshot(params) {
|
|
|
62337
62344
|
if (data) {
|
|
62338
62345
|
await handleScreenshotData(data, params);
|
|
62339
62346
|
}
|
|
62340
|
-
params.lastEmittedHash
|
|
62347
|
+
const hashReference = params.lastEmittedHash;
|
|
62348
|
+
hashReference.value = maybeEmitVisualStep({
|
|
62341
62349
|
snapshot: params.snapshot,
|
|
62342
62350
|
stepIndex: params.stepIndex,
|
|
62343
62351
|
formatted: params.formatted,
|
|
62344
62352
|
structuralHash: params.structuralHash,
|
|
62345
62353
|
screenLabel: params.screenLabel,
|
|
62346
|
-
lastEmittedHash:
|
|
62354
|
+
lastEmittedHash: hashReference.value,
|
|
62347
62355
|
onEvent: params.context.onEvent
|
|
62348
62356
|
});
|
|
62349
62357
|
}
|
|
@@ -62392,11 +62400,19 @@ async function runViewUiCapture(context, state) {
|
|
|
62392
62400
|
function createViewUiHandler(context) {
|
|
62393
62401
|
const lastEmittedHash = { value: void 0 };
|
|
62394
62402
|
const labelCounters = /* @__PURE__ */ new Map();
|
|
62403
|
+
const stepCounterReference = context.stepCounter;
|
|
62395
62404
|
return async () => {
|
|
62396
|
-
const stepIndex =
|
|
62405
|
+
const stepIndex = stepCounterReference.value++;
|
|
62397
62406
|
return runViewUiCapture(context, { stepIndex, lastEmittedHash, labelCounters });
|
|
62398
62407
|
};
|
|
62399
62408
|
}
|
|
62409
|
+
function deriveScreenLabel(tree, stepIndex) {
|
|
62410
|
+
const match = /\[\w+\]\s+"([^"]+)"/.exec(tree);
|
|
62411
|
+
if (!match?.[1]) {
|
|
62412
|
+
return `step-${String(stepIndex)}`;
|
|
62413
|
+
}
|
|
62414
|
+
return match[1].replaceAll(/([A-Z])/g, "-$1").toLowerCase().replaceAll(/[^a-z\d]+/g, "-").replaceAll(/^-|-$/g, "");
|
|
62415
|
+
}
|
|
62400
62416
|
function createViewUiTool(context) {
|
|
62401
62417
|
return _x("view_ui", VIEW_UI_DESCRIPTION, {}, createViewUiHandler(context));
|
|
62402
62418
|
}
|
|
@@ -62423,19 +62439,6 @@ function captureToolUse(blk, state) {
|
|
|
62423
62439
|
state.closeQueue();
|
|
62424
62440
|
}
|
|
62425
62441
|
}
|
|
62426
|
-
function captureFromAssistant(content, state) {
|
|
62427
|
-
for (const block of content) {
|
|
62428
|
-
if (typeof block !== "object" || block === null) {
|
|
62429
|
-
continue;
|
|
62430
|
-
}
|
|
62431
|
-
const blk = block;
|
|
62432
|
-
if ((blk.type === "thinking" || blk.type === "text") && typeof blk[blk.type] === "string") {
|
|
62433
|
-
captureThinkingOrText(blk, state);
|
|
62434
|
-
} else if (blk.type === "tool_use") {
|
|
62435
|
-
captureToolUse(blk, state);
|
|
62436
|
-
}
|
|
62437
|
-
}
|
|
62438
|
-
}
|
|
62439
62442
|
function extractResultText(block) {
|
|
62440
62443
|
const typed = block;
|
|
62441
62444
|
if (typeof typed.content === "string") {
|
|
@@ -62448,27 +62451,49 @@ function extractResultText(block) {
|
|
|
62448
62451
|
(item) => typeof item === "object" && item !== null && item.type === "text"
|
|
62449
62452
|
).map((item) => item.text).join("\n");
|
|
62450
62453
|
}
|
|
62451
|
-
function
|
|
62454
|
+
function emitToolResultEvent(emission) {
|
|
62455
|
+
const { block, toolName, blk, state } = emission;
|
|
62456
|
+
if (toolName === VIEW_UI_TOOL_NAME) {
|
|
62457
|
+
return;
|
|
62458
|
+
}
|
|
62459
|
+
const resultText = extractResultText(block);
|
|
62460
|
+
if (blk.is_error === true) {
|
|
62461
|
+
state.onEvent?.({ type: "TOOL_ERROR", agent: "explorer", toolName, error: resultText });
|
|
62462
|
+
return;
|
|
62463
|
+
}
|
|
62464
|
+
state.onEvent?.({ type: "TOOL_RESULT", agent: "explorer", toolName, result: resultText });
|
|
62465
|
+
}
|
|
62466
|
+
function captureToolResult(block, state) {
|
|
62467
|
+
const blk = block;
|
|
62468
|
+
if (blk.type !== "tool_result" || typeof blk.tool_use_id !== "string") {
|
|
62469
|
+
return;
|
|
62470
|
+
}
|
|
62471
|
+
const toolName = state.pendingToolCallNames.get(blk.tool_use_id);
|
|
62472
|
+
if (toolName === void 0) {
|
|
62473
|
+
return;
|
|
62474
|
+
}
|
|
62475
|
+
emitToolResultEvent({ block, toolName, blk, state });
|
|
62476
|
+
state.pendingToolCallNames.delete(blk.tool_use_id);
|
|
62477
|
+
}
|
|
62478
|
+
function captureFromAssistant(content, state) {
|
|
62452
62479
|
for (const block of content) {
|
|
62453
62480
|
if (typeof block !== "object" || block === null) {
|
|
62454
62481
|
continue;
|
|
62455
62482
|
}
|
|
62456
62483
|
const blk = block;
|
|
62457
|
-
if (blk.type
|
|
62458
|
-
|
|
62484
|
+
if ((blk.type === "thinking" || blk.type === "text") && typeof blk[blk.type] === "string") {
|
|
62485
|
+
captureThinkingOrText(blk, state);
|
|
62486
|
+
} else if (blk.type === "tool_use") {
|
|
62487
|
+
captureToolUse(blk, state);
|
|
62459
62488
|
}
|
|
62460
|
-
|
|
62461
|
-
|
|
62462
|
-
|
|
62463
|
-
|
|
62464
|
-
|
|
62465
|
-
|
|
62466
|
-
} else {
|
|
62467
|
-
state.onEvent?.({ type: "TOOL_RESULT", agent: "explorer", toolName, result: resultText });
|
|
62468
|
-
}
|
|
62469
|
-
}
|
|
62470
|
-
state.pendingToolCallNames.delete(blk.tool_use_id);
|
|
62489
|
+
}
|
|
62490
|
+
}
|
|
62491
|
+
function captureFromUser(content, state) {
|
|
62492
|
+
for (const block of content) {
|
|
62493
|
+
if (typeof block !== "object" || block === null) {
|
|
62494
|
+
continue;
|
|
62471
62495
|
}
|
|
62496
|
+
captureToolResult(block, state);
|
|
62472
62497
|
}
|
|
62473
62498
|
}
|
|
62474
62499
|
function processMessage(message, state) {
|
|
@@ -62655,8 +62680,9 @@ function buildInterruptErrorEvent(agent, error48) {
|
|
|
62655
62680
|
return { type: "ERROR", agent, message, stack };
|
|
62656
62681
|
}
|
|
62657
62682
|
function startHardTimer(gracePeriodMs, context) {
|
|
62683
|
+
const timedOutReference = context.state.timedOut;
|
|
62658
62684
|
return setTimeout(() => {
|
|
62659
|
-
|
|
62685
|
+
timedOutReference.value = true;
|
|
62660
62686
|
context.queryRunner.interrupt().catch((error48) => {
|
|
62661
62687
|
context.state.onEvent?.(buildInterruptErrorEvent(context.agent, error48));
|
|
62662
62688
|
});
|
|
@@ -62668,6 +62694,7 @@ function startSoftTimer({
|
|
|
62668
62694
|
hardTimerRef,
|
|
62669
62695
|
context
|
|
62670
62696
|
}) {
|
|
62697
|
+
const targetReference = hardTimerRef;
|
|
62671
62698
|
return setTimeout(() => {
|
|
62672
62699
|
context.state.onEvent?.({
|
|
62673
62700
|
type: "TIMEOUT_GRACE_ENTERED",
|
|
@@ -62675,7 +62702,7 @@ function startSoftTimer({
|
|
|
62675
62702
|
gracePeriodMs
|
|
62676
62703
|
});
|
|
62677
62704
|
context.state.sendMessage(SOFT_DEADLINE_MESSAGE);
|
|
62678
|
-
|
|
62705
|
+
targetReference.value = startHardTimer(gracePeriodMs, context);
|
|
62679
62706
|
}, timeoutMs);
|
|
62680
62707
|
}
|
|
62681
62708
|
function startActiveTimeout({
|
|
@@ -62727,8 +62754,9 @@ async function drainInterruptThenAbort(context) {
|
|
|
62727
62754
|
linkedController?.abort(reason);
|
|
62728
62755
|
}
|
|
62729
62756
|
function registerSignalAbortListeners(config3, { queryRunner, state, linkedController }) {
|
|
62757
|
+
const abortedReference = state.aborted;
|
|
62730
62758
|
const onAbort = () => {
|
|
62731
|
-
|
|
62759
|
+
abortedReference.value = true;
|
|
62732
62760
|
void drainInterruptThenAbort({
|
|
62733
62761
|
queryRunner,
|
|
62734
62762
|
state,
|
|
@@ -62756,16 +62784,16 @@ function startQueryTimers(config3, context) {
|
|
|
62756
62784
|
inputQueue.close();
|
|
62757
62785
|
};
|
|
62758
62786
|
}
|
|
62759
|
-
function awaitMessagesAndResolve({ queryRunner, state }, { cleanup:
|
|
62787
|
+
function awaitMessagesAndResolve({ queryRunner, state }, { cleanup: cleanup2, getOutput }) {
|
|
62760
62788
|
const messagesPromise = processMessages(queryRunner, state);
|
|
62761
62789
|
return import_neverthrow15.ResultAsync.fromPromise(messagesPromise, String).andThen((innerResult) => {
|
|
62762
|
-
|
|
62790
|
+
cleanup2();
|
|
62763
62791
|
if (innerResult.isErr()) {
|
|
62764
62792
|
return (0, import_neverthrow15.err)(innerResult.error);
|
|
62765
62793
|
}
|
|
62766
62794
|
return (0, import_neverthrow15.ok)(getOutput());
|
|
62767
62795
|
}).orElse((sdkError) => {
|
|
62768
|
-
|
|
62796
|
+
cleanup2();
|
|
62769
62797
|
if (!state.timedOut.value && !state.aborted.value) {
|
|
62770
62798
|
return (0, import_neverthrow15.err)(sdkError);
|
|
62771
62799
|
}
|
|
@@ -62788,14 +62816,14 @@ function executeQuery({
|
|
|
62788
62816
|
return (0, import_neverthrow15.errAsync)(queryRunnerResult.error);
|
|
62789
62817
|
}
|
|
62790
62818
|
const queryRunner = queryRunnerResult.value;
|
|
62791
|
-
const
|
|
62819
|
+
const cleanup2 = startQueryTimers(config3, { state, queryRunner, inputQueue, linkedController });
|
|
62792
62820
|
const getOutput = () => ({
|
|
62793
62821
|
findings: (outputTools.getOutput()?.findings ?? []).map(
|
|
62794
62822
|
(raw) => stampExplorerAgent(raw)
|
|
62795
62823
|
),
|
|
62796
62824
|
snapshots: state.snapshots
|
|
62797
62825
|
});
|
|
62798
|
-
return awaitMessagesAndResolve({ queryRunner, state }, { cleanup:
|
|
62826
|
+
return awaitMessagesAndResolve({ queryRunner, state }, { cleanup: cleanup2, getOutput });
|
|
62799
62827
|
}
|
|
62800
62828
|
function runQuery(prompt, config3) {
|
|
62801
62829
|
const outputTools = createOutputTool({ findings: external_exports.array(EXPLORER_FINDING_SCHEMA) });
|
|
@@ -63124,15 +63152,6 @@ var FREESTYLE_TEMPLATE = (options) => {
|
|
|
63124
63152
|
${DEV_ENVIRONMENT_SECTION}` : "";
|
|
63125
63153
|
return buildFreestyleBody({ contextBlock, environmentSection });
|
|
63126
63154
|
};
|
|
63127
|
-
function generateExplorerPrompt({
|
|
63128
|
-
mode,
|
|
63129
|
-
specs,
|
|
63130
|
-
appContext,
|
|
63131
|
-
initialState: initialState2,
|
|
63132
|
-
buildEnv
|
|
63133
|
-
}) {
|
|
63134
|
-
return mode === "spec" ? buildSpecModePrompt(specs, { appContext, initialState: initialState2, buildEnv }) : FREESTYLE_TEMPLATE({ appContext, initialState: initialState2, buildEnv });
|
|
63135
|
-
}
|
|
63136
63155
|
function renderStep(step, index) {
|
|
63137
63156
|
const stepNumber = String(index + 1);
|
|
63138
63157
|
const base = `${stepNumber}. ${step.action}`;
|
|
@@ -63160,6 +63179,15 @@ function buildSpecModePrompt(specs, options) {
|
|
|
63160
63179
|
const specContent = specs.map((spec) => renderSpec(spec)).join("\n\n---\n\n");
|
|
63161
63180
|
return SPEC_MODE_TEMPLATE(specContent, options);
|
|
63162
63181
|
}
|
|
63182
|
+
function generateExplorerPrompt({
|
|
63183
|
+
mode,
|
|
63184
|
+
specs,
|
|
63185
|
+
appContext,
|
|
63186
|
+
initialState: initialState2,
|
|
63187
|
+
buildEnv
|
|
63188
|
+
}) {
|
|
63189
|
+
return mode === "spec" ? buildSpecModePrompt(specs, { appContext, initialState: initialState2, buildEnv }) : FREESTYLE_TEMPLATE({ appContext, initialState: initialState2, buildEnv });
|
|
63190
|
+
}
|
|
63163
63191
|
var FRONTMATTER_FENCE = "---";
|
|
63164
63192
|
var INLINE_ASSERTION_DELIMITER = " \u2192 ";
|
|
63165
63193
|
var NUMBERED_STEP_PREFIX = /^\d+\.\s+/;
|
|
@@ -63283,10 +63311,6 @@ function parseTestSpec(name, content) {
|
|
|
63283
63311
|
});
|
|
63284
63312
|
});
|
|
63285
63313
|
}
|
|
63286
|
-
function resolveSpecs(config3, repoRoot = process.cwd()) {
|
|
63287
|
-
const source = config3.specFiles && config3.specFiles.length > 0 ? loadFromFiles(config3.specFiles) : loadFromDirectory(import_node_path6.default.join(repoRoot, "openspec", "specs"));
|
|
63288
|
-
return source.map((specs) => filterByNames(specs, config3.specNames));
|
|
63289
|
-
}
|
|
63290
63314
|
function loadFromFiles(paths) {
|
|
63291
63315
|
const entries = paths.map((filePath) => ({
|
|
63292
63316
|
path: filePath,
|
|
@@ -63357,6 +63381,10 @@ function filterByNames(specs, specNames) {
|
|
|
63357
63381
|
}
|
|
63358
63382
|
return specs.filter((spec) => specNames.includes(spec.name));
|
|
63359
63383
|
}
|
|
63384
|
+
function resolveSpecs(config3, repoRoot = process.cwd()) {
|
|
63385
|
+
const source = config3.specFiles && config3.specFiles.length > 0 ? loadFromFiles(config3.specFiles) : loadFromDirectory(import_node_path6.default.join(repoRoot, "openspec", "specs"));
|
|
63386
|
+
return source.map((specs) => filterByNames(specs, config3.specNames));
|
|
63387
|
+
}
|
|
63360
63388
|
var ISO_DATE_LENGTH = 10;
|
|
63361
63389
|
function buildPrompt(safeConfig, specs) {
|
|
63362
63390
|
return generateExplorerPrompt({
|
|
@@ -66105,6 +66133,19 @@ var jsYaml = {
|
|
|
66105
66133
|
// ../../agents/inspector/dist/index.js
|
|
66106
66134
|
var import_neverthrow29 = __toESM(require_index_cjs(), 1);
|
|
66107
66135
|
var MS_PER_DAY = 864e5;
|
|
66136
|
+
function dequeue(context, current) {
|
|
66137
|
+
if (current.remainingQueue.length === 0 || context.activeCount + current.events.length >= context.maxConcurrency) {
|
|
66138
|
+
return current;
|
|
66139
|
+
}
|
|
66140
|
+
if (context.signal?.aborted === true) {
|
|
66141
|
+
return { events: current.events, remainingQueue: [] };
|
|
66142
|
+
}
|
|
66143
|
+
const [event, ...rest] = current.remainingQueue;
|
|
66144
|
+
if (!event) {
|
|
66145
|
+
return { events: current.events, remainingQueue: rest };
|
|
66146
|
+
}
|
|
66147
|
+
return dequeue(context, { events: [...current.events, event], remainingQueue: rest });
|
|
66148
|
+
}
|
|
66108
66149
|
function checkStaleness({ lastUpdated, thresholdDays, now }) {
|
|
66109
66150
|
if (!lastUpdated) {
|
|
66110
66151
|
return { isStale: false, ageDays: 0 };
|
|
@@ -66119,19 +66160,6 @@ function tryResolve(state) {
|
|
|
66119
66160
|
}
|
|
66120
66161
|
return { shouldResolve: false, result };
|
|
66121
66162
|
}
|
|
66122
|
-
function dequeue(context, current) {
|
|
66123
|
-
if (current.remainingQueue.length === 0 || context.activeCount + current.events.length >= context.maxConcurrency) {
|
|
66124
|
-
return current;
|
|
66125
|
-
}
|
|
66126
|
-
if (context.signal?.aborted === true) {
|
|
66127
|
-
return { events: current.events, remainingQueue: [] };
|
|
66128
|
-
}
|
|
66129
|
-
const [event, ...rest] = current.remainingQueue;
|
|
66130
|
-
if (!event) {
|
|
66131
|
-
return { events: current.events, remainingQueue: rest };
|
|
66132
|
-
}
|
|
66133
|
-
return dequeue(context, { events: [...current.events, event], remainingQueue: rest });
|
|
66134
|
-
}
|
|
66135
66163
|
function scheduleNext(state, maxConcurrency) {
|
|
66136
66164
|
if (state.signal?.aborted === true) {
|
|
66137
66165
|
return { events: [], remainingQueue: [] };
|
|
@@ -66144,16 +66172,6 @@ function scheduleNext(state, maxConcurrency) {
|
|
|
66144
66172
|
var CONFIDENCE_HIGH = 0.9;
|
|
66145
66173
|
var CONFIDENCE_MEDIUM = 0.6;
|
|
66146
66174
|
var CONFIDENCE_LOW = 0.3;
|
|
66147
|
-
function isValidSeverity(value) {
|
|
66148
|
-
return value === "low" || value === "medium" || value === "high";
|
|
66149
|
-
}
|
|
66150
|
-
function isRawFinding(value) {
|
|
66151
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
66152
|
-
return false;
|
|
66153
|
-
}
|
|
66154
|
-
const object2 = value;
|
|
66155
|
-
return typeof object2.type === "string" && typeof object2.element === "string" && typeof object2.description === "string" && typeof object2.severity === "string" && isValidSeverity(object2.severity);
|
|
66156
|
-
}
|
|
66157
66175
|
function toTriggerType(type2) {
|
|
66158
66176
|
return type2 === "localization-issue" ? "localization-issue" : "visual-regression";
|
|
66159
66177
|
}
|
|
@@ -66166,6 +66184,19 @@ function toConfidence(severity) {
|
|
|
66166
66184
|
}
|
|
66167
66185
|
return CONFIDENCE_LOW;
|
|
66168
66186
|
}
|
|
66187
|
+
function parseJson(raw) {
|
|
66188
|
+
return JSON.parse(raw);
|
|
66189
|
+
}
|
|
66190
|
+
function isValidSeverity(value) {
|
|
66191
|
+
return value === "low" || value === "medium" || value === "high";
|
|
66192
|
+
}
|
|
66193
|
+
function isRawFinding(value) {
|
|
66194
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
66195
|
+
return false;
|
|
66196
|
+
}
|
|
66197
|
+
const object2 = value;
|
|
66198
|
+
return typeof object2.type === "string" && typeof object2.element === "string" && typeof object2.description === "string" && typeof object2.severity === "string" && isValidSeverity(object2.severity);
|
|
66199
|
+
}
|
|
66169
66200
|
function mapRawFinding(item) {
|
|
66170
66201
|
return {
|
|
66171
66202
|
triggerType: toTriggerType(item.type),
|
|
@@ -66177,9 +66208,6 @@ function mapRawFinding(item) {
|
|
|
66177
66208
|
agent: "inspector"
|
|
66178
66209
|
};
|
|
66179
66210
|
}
|
|
66180
|
-
function parseJson(raw) {
|
|
66181
|
-
return JSON.parse(raw);
|
|
66182
|
-
}
|
|
66183
66211
|
var safeJsonParse3 = (0, import_neverthrow26.fromThrowable)(parseJson);
|
|
66184
66212
|
function parseClaudeResponse(raw) {
|
|
66185
66213
|
const parseResult = safeJsonParse3(raw);
|
|
@@ -66402,25 +66430,6 @@ var SEVERITY_CONFIDENCE = {
|
|
|
66402
66430
|
low: CONFIDENCE_LOW2
|
|
66403
66431
|
};
|
|
66404
66432
|
var safeJsonParse22 = (0, import_neverthrow28.fromThrowable)(JSON.parse);
|
|
66405
|
-
function buildFindCandidatesMessages(screenshotBase64, artboardNames) {
|
|
66406
|
-
return [
|
|
66407
|
-
{
|
|
66408
|
-
role: "user",
|
|
66409
|
-
content: [
|
|
66410
|
-
{
|
|
66411
|
-
type: "image",
|
|
66412
|
-
source: { type: "base64", media_type: "image/png", data: screenshotBase64 }
|
|
66413
|
-
},
|
|
66414
|
-
{
|
|
66415
|
-
type: "text",
|
|
66416
|
-
text: `Which of these design artboards are most visually similar to this screenshot (same app, same design system)? Reply with a JSON array of up to ${String(MAX_CANDIDATES)} artboard names from the list below, or [] if none are sufficiently similar. Only include names exactly as listed.
|
|
66417
|
-
|
|
66418
|
-
Artboards: ${artboardNames.join(", ")}`
|
|
66419
|
-
}
|
|
66420
|
-
]
|
|
66421
|
-
}
|
|
66422
|
-
];
|
|
66423
|
-
}
|
|
66424
66433
|
function resolveNamesFromParsed(parsed, artboardNames) {
|
|
66425
66434
|
return parsed.filter((name) => typeof name === "string").map((name) => {
|
|
66426
66435
|
const lower = name.toLowerCase();
|
|
@@ -66446,19 +66455,6 @@ async function fetchCandidateNames({
|
|
|
66446
66455
|
}
|
|
66447
66456
|
return resolveNamesFromParsed(parsed.value, artboardNames);
|
|
66448
66457
|
}
|
|
66449
|
-
function findCandidates(screenshot, artboardNames) {
|
|
66450
|
-
if (artboardNames.length === 0) {
|
|
66451
|
-
return (0, import_neverthrow28.okAsync)([]);
|
|
66452
|
-
}
|
|
66453
|
-
const anthropic = new Anthropic();
|
|
66454
|
-
return downscale(screenshot).andThen((scaled) => {
|
|
66455
|
-
const screenshotBase64 = scaled.toString("base64");
|
|
66456
|
-
return (0, import_neverthrow28.fromAsyncThrowable)(
|
|
66457
|
-
fetchCandidateNames,
|
|
66458
|
-
(cause) => ({ type: "CLAUDE_API_FAILED", cause })
|
|
66459
|
-
)({ anthropic, screenshotBase64, artboardNames });
|
|
66460
|
-
});
|
|
66461
|
-
}
|
|
66462
66458
|
function buildArtboardTextBlock(index, total) {
|
|
66463
66459
|
const base = {
|
|
66464
66460
|
type: "text",
|
|
@@ -66478,24 +66474,6 @@ function buildArtboardContentBlocks(artboardBase64s) {
|
|
|
66478
66474
|
buildArtboardTextBlock(index, artboardBase64s.length)
|
|
66479
66475
|
]);
|
|
66480
66476
|
}
|
|
66481
|
-
function buildDesignContextMessages(screenshotBase64, artboardBase64s) {
|
|
66482
|
-
return [
|
|
66483
|
-
{
|
|
66484
|
-
role: "user",
|
|
66485
|
-
content: [
|
|
66486
|
-
...buildArtboardContentBlocks(artboardBase64s),
|
|
66487
|
-
{
|
|
66488
|
-
type: "image",
|
|
66489
|
-
source: { type: "base64", media_type: "image/png", data: screenshotBase64 }
|
|
66490
|
-
},
|
|
66491
|
-
{
|
|
66492
|
-
type: "text",
|
|
66493
|
-
text: "This is the actual screenshot. List all design system violations as JSON."
|
|
66494
|
-
}
|
|
66495
|
-
]
|
|
66496
|
-
}
|
|
66497
|
-
];
|
|
66498
|
-
}
|
|
66499
66477
|
function parseConservativeResponse(raw) {
|
|
66500
66478
|
const parseResult = safeJsonParse22(raw);
|
|
66501
66479
|
if (parseResult.isErr()) {
|
|
@@ -66547,6 +66525,56 @@ function toDesignContextFindings(text) {
|
|
|
66547
66525
|
async function downscaleAll(buffers) {
|
|
66548
66526
|
return Promise.all(buffers.map(async (buf) => downscaleBuffer(buf)));
|
|
66549
66527
|
}
|
|
66528
|
+
function buildFindCandidatesMessages(screenshotBase64, artboardNames) {
|
|
66529
|
+
return [
|
|
66530
|
+
{
|
|
66531
|
+
role: "user",
|
|
66532
|
+
content: [
|
|
66533
|
+
{
|
|
66534
|
+
type: "image",
|
|
66535
|
+
source: { type: "base64", media_type: "image/png", data: screenshotBase64 }
|
|
66536
|
+
},
|
|
66537
|
+
{
|
|
66538
|
+
type: "text",
|
|
66539
|
+
text: `Which of these design artboards are most visually similar to this screenshot (same app, same design system)? Reply with a JSON array of up to ${String(MAX_CANDIDATES)} artboard names from the list below, or [] if none are sufficiently similar. Only include names exactly as listed.
|
|
66540
|
+
|
|
66541
|
+
Artboards: ${artboardNames.join(", ")}`
|
|
66542
|
+
}
|
|
66543
|
+
]
|
|
66544
|
+
}
|
|
66545
|
+
];
|
|
66546
|
+
}
|
|
66547
|
+
function findCandidates(screenshot, artboardNames) {
|
|
66548
|
+
if (artboardNames.length === 0) {
|
|
66549
|
+
return (0, import_neverthrow28.okAsync)([]);
|
|
66550
|
+
}
|
|
66551
|
+
const anthropic = new Anthropic();
|
|
66552
|
+
return downscale(screenshot).andThen((scaled) => {
|
|
66553
|
+
const screenshotBase64 = scaled.toString("base64");
|
|
66554
|
+
return (0, import_neverthrow28.fromAsyncThrowable)(
|
|
66555
|
+
fetchCandidateNames,
|
|
66556
|
+
(cause) => ({ type: "CLAUDE_API_FAILED", cause })
|
|
66557
|
+
)({ anthropic, screenshotBase64, artboardNames });
|
|
66558
|
+
});
|
|
66559
|
+
}
|
|
66560
|
+
function buildDesignContextMessages(screenshotBase64, artboardBase64s) {
|
|
66561
|
+
return [
|
|
66562
|
+
{
|
|
66563
|
+
role: "user",
|
|
66564
|
+
content: [
|
|
66565
|
+
...buildArtboardContentBlocks(artboardBase64s),
|
|
66566
|
+
{
|
|
66567
|
+
type: "image",
|
|
66568
|
+
source: { type: "base64", media_type: "image/png", data: screenshotBase64 }
|
|
66569
|
+
},
|
|
66570
|
+
{
|
|
66571
|
+
type: "text",
|
|
66572
|
+
text: "This is the actual screenshot. List all design system violations as JSON."
|
|
66573
|
+
}
|
|
66574
|
+
]
|
|
66575
|
+
}
|
|
66576
|
+
];
|
|
66577
|
+
}
|
|
66550
66578
|
var downscaleAllBuffers = (0, import_neverthrow28.fromAsyncThrowable)(
|
|
66551
66579
|
downscaleAll,
|
|
66552
66580
|
(cause) => ({ type: "CLAUDE_API_FAILED", cause })
|
|
@@ -66601,6 +66629,23 @@ function resolveExactMatchOutcome({
|
|
|
66601
66629
|
}
|
|
66602
66630
|
return stepFinding ? { outcome: "fail", finding: stepFinding } : { outcome: "pass" };
|
|
66603
66631
|
}
|
|
66632
|
+
async function collectDesignContextFindings(context) {
|
|
66633
|
+
let stepFinding;
|
|
66634
|
+
await compareWithDesignContext(context.screenshot, context.artboardBuffers).match(
|
|
66635
|
+
(findings) => {
|
|
66636
|
+
const mapped = findings.map((finding) => ({
|
|
66637
|
+
...finding,
|
|
66638
|
+
screenshots: [context.screenshotPath]
|
|
66639
|
+
}));
|
|
66640
|
+
context.state.findings.push(...mapped);
|
|
66641
|
+
stepFinding = mapped[0];
|
|
66642
|
+
},
|
|
66643
|
+
(error48) => {
|
|
66644
|
+
pushClaudeError(context.state, { stepIndex: context.stepIndex, error: error48 });
|
|
66645
|
+
}
|
|
66646
|
+
);
|
|
66647
|
+
return { stepFinding };
|
|
66648
|
+
}
|
|
66604
66649
|
async function compareArtboardExact({
|
|
66605
66650
|
screenshot,
|
|
66606
66651
|
artboard,
|
|
@@ -66625,23 +66670,6 @@ async function compareArtboardExact({
|
|
|
66625
66670
|
});
|
|
66626
66671
|
return resolveExactMatchOutcome({ stepFinding, isStale, ageDays });
|
|
66627
66672
|
}
|
|
66628
|
-
async function collectDesignContextFindings(context) {
|
|
66629
|
-
let stepFinding;
|
|
66630
|
-
await compareWithDesignContext(context.screenshot, context.artboardBuffers).match(
|
|
66631
|
-
(findings) => {
|
|
66632
|
-
const mapped = findings.map((finding) => ({
|
|
66633
|
-
...finding,
|
|
66634
|
-
screenshots: [context.screenshotPath]
|
|
66635
|
-
}));
|
|
66636
|
-
context.state.findings.push(...mapped);
|
|
66637
|
-
stepFinding = mapped[0];
|
|
66638
|
-
},
|
|
66639
|
-
(error48) => {
|
|
66640
|
-
pushClaudeError(context.state, { stepIndex: context.stepIndex, error: error48 });
|
|
66641
|
-
}
|
|
66642
|
-
);
|
|
66643
|
-
return { stepFinding };
|
|
66644
|
-
}
|
|
66645
66673
|
async function compareWithCandidates(context) {
|
|
66646
66674
|
const { stepFinding } = await collectDesignContextFindings(context);
|
|
66647
66675
|
if (stepFinding) {
|
|
@@ -66775,19 +66803,20 @@ function resolveStepEvent({ stepIndex, screenLabel, outcome }) {
|
|
|
66775
66803
|
return { stepIndex, screenLabel, outcome: "pass" };
|
|
66776
66804
|
}
|
|
66777
66805
|
async function initArtboardNames({ designStore, config: config3, state }) {
|
|
66778
|
-
state.
|
|
66779
|
-
(
|
|
66780
|
-
|
|
66781
|
-
|
|
66806
|
+
return state.getOrInitArtboardNames(
|
|
66807
|
+
async () => designStore.listArtboards().match(
|
|
66808
|
+
(names) => {
|
|
66809
|
+
if (names.length === 0) {
|
|
66810
|
+
emitProgress(config3, "no artboards found in designs directory");
|
|
66811
|
+
}
|
|
66812
|
+
return names;
|
|
66813
|
+
},
|
|
66814
|
+
(error48) => {
|
|
66815
|
+
emitProgress(config3, `Failed to list artboards: ${error48.type}`);
|
|
66816
|
+
return [];
|
|
66782
66817
|
}
|
|
66783
|
-
|
|
66784
|
-
},
|
|
66785
|
-
(error48) => {
|
|
66786
|
-
emitProgress(config3, `Failed to list artboards: ${error48.type}`);
|
|
66787
|
-
return [];
|
|
66788
|
-
}
|
|
66818
|
+
)
|
|
66789
66819
|
);
|
|
66790
|
-
return state.artboardNamesPromise;
|
|
66791
66820
|
}
|
|
66792
66821
|
function readScreenshot(screenshotPath, stepIndex) {
|
|
66793
66822
|
return import_neverthrow24.ResultAsync.fromThrowable(
|
|
@@ -66812,43 +66841,40 @@ async function processStep(context) {
|
|
|
66812
66841
|
});
|
|
66813
66842
|
config3.onStepComplete?.(resolveStepEvent({ stepIndex, screenLabel, outcome }));
|
|
66814
66843
|
}
|
|
66844
|
+
var StepState = class {
|
|
66845
|
+
findings = [];
|
|
66846
|
+
errors = [];
|
|
66847
|
+
artboardNames = void 0;
|
|
66848
|
+
async getOrInitArtboardNames(init) {
|
|
66849
|
+
this.artboardNames ??= init();
|
|
66850
|
+
return this.artboardNames;
|
|
66851
|
+
}
|
|
66852
|
+
};
|
|
66815
66853
|
var MAX_CONCURRENCY = 3;
|
|
66816
66854
|
function applyTryResolve(state) {
|
|
66817
66855
|
const { shouldResolve, result } = tryResolve(state);
|
|
66818
66856
|
if (shouldResolve && state.resolve) {
|
|
66819
66857
|
state.resolve(result);
|
|
66820
|
-
state.
|
|
66858
|
+
state.clearResolve();
|
|
66821
66859
|
}
|
|
66822
66860
|
}
|
|
66823
66861
|
function applyScheduleNext(state, context) {
|
|
66824
66862
|
const { events, remainingQueue } = scheduleNext(state, MAX_CONCURRENCY);
|
|
66825
|
-
state.
|
|
66863
|
+
state.setQueue(remainingQueue);
|
|
66826
66864
|
for (const event of events) {
|
|
66827
|
-
state.
|
|
66865
|
+
state.incrementActive();
|
|
66828
66866
|
void processStep({
|
|
66829
66867
|
event,
|
|
66830
66868
|
designStore: context.designStore,
|
|
66831
66869
|
config: context.config,
|
|
66832
66870
|
state
|
|
66833
66871
|
}).finally(() => {
|
|
66834
|
-
state.
|
|
66872
|
+
state.decrementActive();
|
|
66835
66873
|
applyScheduleNext(state, context);
|
|
66836
66874
|
applyTryResolve(state);
|
|
66837
66875
|
});
|
|
66838
66876
|
}
|
|
66839
66877
|
}
|
|
66840
|
-
function createRunnerState(config3) {
|
|
66841
|
-
return {
|
|
66842
|
-
findings: [],
|
|
66843
|
-
errors: [],
|
|
66844
|
-
activeCount: 0,
|
|
66845
|
-
queue: [],
|
|
66846
|
-
closed: false,
|
|
66847
|
-
resolve: void 0,
|
|
66848
|
-
signal: config3.signal,
|
|
66849
|
-
artboardNamesPromise: void 0
|
|
66850
|
-
};
|
|
66851
|
-
}
|
|
66852
66878
|
function buildInspector(state, context) {
|
|
66853
66879
|
return {
|
|
66854
66880
|
enqueue(event) {
|
|
@@ -66859,12 +66885,12 @@ function buildInspector(state, context) {
|
|
|
66859
66885
|
applyScheduleNext(state, context);
|
|
66860
66886
|
},
|
|
66861
66887
|
close() {
|
|
66862
|
-
state.
|
|
66888
|
+
state.markClosed();
|
|
66863
66889
|
applyTryResolve(state);
|
|
66864
66890
|
},
|
|
66865
66891
|
drain() {
|
|
66866
66892
|
const { promise: promise2, resolve } = Promise.withResolvers();
|
|
66867
|
-
state.resolve
|
|
66893
|
+
state.setResolve(resolve);
|
|
66868
66894
|
applyTryResolve(state);
|
|
66869
66895
|
return (0, import_neverthrow23.fromSafePromise)(promise2);
|
|
66870
66896
|
}
|
|
@@ -66872,9 +66898,38 @@ function buildInspector(state, context) {
|
|
|
66872
66898
|
}
|
|
66873
66899
|
function createInspector(config3, designStore) {
|
|
66874
66900
|
const context = { designStore, config: config3 };
|
|
66875
|
-
const state =
|
|
66901
|
+
const state = new RunnerState(config3.signal);
|
|
66876
66902
|
return buildInspector(state, context);
|
|
66877
66903
|
}
|
|
66904
|
+
var RunnerState = class extends StepState {
|
|
66905
|
+
activeCount = 0;
|
|
66906
|
+
queue = [];
|
|
66907
|
+
closed = false;
|
|
66908
|
+
resolve = void 0;
|
|
66909
|
+
signal;
|
|
66910
|
+
constructor(signal) {
|
|
66911
|
+
super();
|
|
66912
|
+
this.signal = signal;
|
|
66913
|
+
}
|
|
66914
|
+
setQueue(queue) {
|
|
66915
|
+
this.queue = queue;
|
|
66916
|
+
}
|
|
66917
|
+
incrementActive() {
|
|
66918
|
+
this.activeCount += 1;
|
|
66919
|
+
}
|
|
66920
|
+
decrementActive() {
|
|
66921
|
+
this.activeCount -= 1;
|
|
66922
|
+
}
|
|
66923
|
+
markClosed() {
|
|
66924
|
+
this.closed = true;
|
|
66925
|
+
}
|
|
66926
|
+
setResolve(resolve) {
|
|
66927
|
+
this.resolve = resolve;
|
|
66928
|
+
}
|
|
66929
|
+
clearResolve() {
|
|
66930
|
+
this.resolve = void 0;
|
|
66931
|
+
}
|
|
66932
|
+
};
|
|
66878
66933
|
function parseMeta(raw) {
|
|
66879
66934
|
const parsed = jsYaml.load(raw);
|
|
66880
66935
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
@@ -67210,7 +67265,7 @@ async function drainAfterExplorer(options) {
|
|
|
67210
67265
|
return (0, import_neverthrow34.ok)({ artifacts: explorerResult.value, inspectorFindings });
|
|
67211
67266
|
}
|
|
67212
67267
|
function runExplorerAndDrain(options) {
|
|
67213
|
-
return
|
|
67268
|
+
return import_neverthrow34.ResultAsync.fromSafePromise(drainAfterExplorer(options)).andThen((result) => result);
|
|
67214
67269
|
}
|
|
67215
67270
|
function createDefaultMcpServers(udid) {
|
|
67216
67271
|
return {
|
|
@@ -67717,8 +67772,8 @@ function buildAnalyseIdentity() {
|
|
|
67717
67772
|
simulatorUdid: ""
|
|
67718
67773
|
};
|
|
67719
67774
|
}
|
|
67720
|
-
function buildAnalyseEventHandler(identity,
|
|
67721
|
-
const debugLogger = createDebugLogger({ enabled:
|
|
67775
|
+
function buildAnalyseEventHandler(identity, isDebug) {
|
|
67776
|
+
const debugLogger = createDebugLogger({ enabled: isDebug });
|
|
67722
67777
|
const baseHandler = (event) => {
|
|
67723
67778
|
identity.display.onEvent({ ...event, itemId: ITEM_ID });
|
|
67724
67779
|
};
|
|
@@ -69370,7 +69425,7 @@ function createPrompt(view) {
|
|
|
69370
69425
|
effectScheduler.clearAll();
|
|
69371
69426
|
throw error48;
|
|
69372
69427
|
}).finally(() => {
|
|
69373
|
-
cleanups.forEach((
|
|
69428
|
+
cleanups.forEach((cleanup2) => cleanup2());
|
|
69374
69429
|
screen.done({ clearContent: Boolean(context.clearPromptOnDone) });
|
|
69375
69430
|
output.end();
|
|
69376
69431
|
}).then(() => promise2), { cancel });
|
|
@@ -70664,43 +70719,6 @@ var DEFAULT_TERMINAL_WIDTH = 80;
|
|
|
70664
70719
|
var CURSOR_MARGIN = 4;
|
|
70665
70720
|
var ELLIPSIS_LENGTH = 3;
|
|
70666
70721
|
var PAGE_SIZE = 15;
|
|
70667
|
-
function dismissalKey(finding) {
|
|
70668
|
-
return `${finding.flow}\0${finding.description}`;
|
|
70669
|
-
}
|
|
70670
|
-
function buildChoiceName(finding, state) {
|
|
70671
|
-
const suffix = state === "dismissed" ? " [dismissed]" : state === "reconsidered" ? " [reconsidered]" : "";
|
|
70672
|
-
const terminalWidth = process.stdout.columns > 0 ? process.stdout.columns : DEFAULT_TERMINAL_WIDTH;
|
|
70673
|
-
const maxDescWidth = terminalWidth - CURSOR_MARGIN - FIXED_COLS_WIDTH - suffix.length;
|
|
70674
|
-
const flow = source_default.bold(finding.flow.padEnd(FLOW_COL_WIDTH));
|
|
70675
|
-
const triggerType = source_default.dim(finding.triggerType.padEnd(TRIGGER_COL_WIDTH));
|
|
70676
|
-
const confidence = `${String(Math.round(finding.confidence * CONFIDENCE_PERCENT))}%`.padEnd(
|
|
70677
|
-
CONFIDENCE_COL_WIDTH
|
|
70678
|
-
);
|
|
70679
|
-
const rawDescription = finding.description.split(".")[0] ?? finding.description;
|
|
70680
|
-
const description = rawDescription.length > maxDescWidth ? `${rawDescription.slice(0, maxDescWidth - ELLIPSIS_LENGTH)}...` : rawDescription;
|
|
70681
|
-
return `${flow} ${triggerType} ${confidence} ${description}${suffix ? source_default.dim(suffix) : ""}`;
|
|
70682
|
-
}
|
|
70683
|
-
function printDetail(finding) {
|
|
70684
|
-
process.stdout.write(source_default.bold("\nDescription:\n"));
|
|
70685
|
-
process.stdout.write(`${finding.description}
|
|
70686
|
-
`);
|
|
70687
|
-
process.stdout.write(source_default.bold("\nSteps:\n"));
|
|
70688
|
-
for (const [index, step] of finding.steps.entries()) {
|
|
70689
|
-
process.stdout.write(` ${String(index + 1)}. ${step}
|
|
70690
|
-
`);
|
|
70691
|
-
}
|
|
70692
|
-
process.stdout.write(
|
|
70693
|
-
`${source_default.bold("\nConfidence: ")}${String(Math.round(finding.confidence * CONFIDENCE_PERCENT))}%
|
|
70694
|
-
`
|
|
70695
|
-
);
|
|
70696
|
-
if (finding.screenshots.length > 0) {
|
|
70697
|
-
process.stdout.write(source_default.bold("\nScreenshots:\n"));
|
|
70698
|
-
for (const screenshot of finding.screenshots) {
|
|
70699
|
-
process.stdout.write(` ${screenshot}
|
|
70700
|
-
`);
|
|
70701
|
-
}
|
|
70702
|
-
}
|
|
70703
|
-
}
|
|
70704
70722
|
async function handleFindingDetail(finding, state) {
|
|
70705
70723
|
printDetail(finding);
|
|
70706
70724
|
if (state === "dismissed") {
|
|
@@ -70791,6 +70809,43 @@ async function runLoopIteration(findings, state) {
|
|
|
70791
70809
|
}
|
|
70792
70810
|
return true;
|
|
70793
70811
|
}
|
|
70812
|
+
function dismissalKey(finding) {
|
|
70813
|
+
return `${finding.flow}\0${finding.description}`;
|
|
70814
|
+
}
|
|
70815
|
+
function buildChoiceName(finding, state) {
|
|
70816
|
+
const suffix = state === "dismissed" ? " [dismissed]" : state === "reconsidered" ? " [reconsidered]" : "";
|
|
70817
|
+
const terminalWidth = process.stdout.columns > 0 ? process.stdout.columns : DEFAULT_TERMINAL_WIDTH;
|
|
70818
|
+
const maxDescWidth = terminalWidth - CURSOR_MARGIN - FIXED_COLS_WIDTH - suffix.length;
|
|
70819
|
+
const flow = source_default.bold(finding.flow.padEnd(FLOW_COL_WIDTH));
|
|
70820
|
+
const triggerType = source_default.dim(finding.triggerType.padEnd(TRIGGER_COL_WIDTH));
|
|
70821
|
+
const confidence = `${String(Math.round(finding.confidence * CONFIDENCE_PERCENT))}%`.padEnd(
|
|
70822
|
+
CONFIDENCE_COL_WIDTH
|
|
70823
|
+
);
|
|
70824
|
+
const rawDescription = finding.description.split(".")[0] ?? finding.description;
|
|
70825
|
+
const description = rawDescription.length > maxDescWidth ? `${rawDescription.slice(0, maxDescWidth - ELLIPSIS_LENGTH)}...` : rawDescription;
|
|
70826
|
+
return `${flow} ${triggerType} ${confidence} ${description}${suffix ? source_default.dim(suffix) : ""}`;
|
|
70827
|
+
}
|
|
70828
|
+
function printDetail(finding) {
|
|
70829
|
+
process.stdout.write(source_default.bold("\nDescription:\n"));
|
|
70830
|
+
process.stdout.write(`${finding.description}
|
|
70831
|
+
`);
|
|
70832
|
+
process.stdout.write(source_default.bold("\nSteps:\n"));
|
|
70833
|
+
for (const [index, step] of finding.steps.entries()) {
|
|
70834
|
+
process.stdout.write(` ${String(index + 1)}. ${step}
|
|
70835
|
+
`);
|
|
70836
|
+
}
|
|
70837
|
+
process.stdout.write(
|
|
70838
|
+
`${source_default.bold("\nConfidence: ")}${String(Math.round(finding.confidence * CONFIDENCE_PERCENT))}%
|
|
70839
|
+
`
|
|
70840
|
+
);
|
|
70841
|
+
if (finding.screenshots.length > 0) {
|
|
70842
|
+
process.stdout.write(source_default.bold("\nScreenshots:\n"));
|
|
70843
|
+
for (const screenshot of finding.screenshots) {
|
|
70844
|
+
process.stdout.write(` ${screenshot}
|
|
70845
|
+
`);
|
|
70846
|
+
}
|
|
70847
|
+
}
|
|
70848
|
+
}
|
|
70794
70849
|
async function runInteractiveLoop(findings, existing) {
|
|
70795
70850
|
const state = {
|
|
70796
70851
|
dismissedKeys: new Set(existing.map((dismissal) => dismissalKey(dismissal.finding))),
|
|
@@ -70981,6 +71036,9 @@ var import_node_path17 = __toESM(require("node:path"), 1);
|
|
|
70981
71036
|
// src/spec-slug.ts
|
|
70982
71037
|
var import_node_path15 = __toESM(require("node:path"), 1);
|
|
70983
71038
|
var SPECS_DIR = "specs";
|
|
71039
|
+
function stripExtensions(filename) {
|
|
71040
|
+
return filename.replace(/\.test\.md$/, "").replace(/\.[^.]+$/, "");
|
|
71041
|
+
}
|
|
70984
71042
|
function deriveSpecSlug(specFilePath) {
|
|
70985
71043
|
const parts = specFilePath.split(import_node_path15.default.sep);
|
|
70986
71044
|
const specsIndex = parts.lastIndexOf(SPECS_DIR);
|
|
@@ -70992,9 +71050,6 @@ function deriveSpecSlug(specFilePath) {
|
|
|
70992
71050
|
}
|
|
70993
71051
|
return stripExtensions(import_node_path15.default.basename(specFilePath));
|
|
70994
71052
|
}
|
|
70995
|
-
function stripExtensions(filename) {
|
|
70996
|
-
return filename.replace(/\.test\.md$/, "").replace(/\.[^.]+$/, "");
|
|
70997
|
-
}
|
|
70998
71053
|
|
|
70999
71054
|
// src/commands/spec-resolver.ts
|
|
71000
71055
|
var import_node_fs8 = require("node:fs");
|
|
@@ -71027,16 +71082,6 @@ function parseTimeout(fields) {
|
|
|
71027
71082
|
}
|
|
71028
71083
|
return (0, import_neverthrow42.ok)(parsed);
|
|
71029
71084
|
}
|
|
71030
|
-
function parseSpecFrontmatter(content) {
|
|
71031
|
-
return extractFrontmatterBlock(content).andThen((block) => {
|
|
71032
|
-
const fields = parseYamlFields(block);
|
|
71033
|
-
const feature = fields.get("feature");
|
|
71034
|
-
if (feature === void 0) {
|
|
71035
|
-
return (0, import_neverthrow42.err)({ type: "MISSING_FIELD", field: "feature" });
|
|
71036
|
-
}
|
|
71037
|
-
return parseTimeout(fields).map((timeout) => ({ feature, timeout }));
|
|
71038
|
-
});
|
|
71039
|
-
}
|
|
71040
71085
|
function parseYamlFields(block) {
|
|
71041
71086
|
const map3 = /* @__PURE__ */ new Map();
|
|
71042
71087
|
for (const line of block.split("\n")) {
|
|
@@ -71052,6 +71097,16 @@ function parseYamlFields(block) {
|
|
|
71052
71097
|
}
|
|
71053
71098
|
return map3;
|
|
71054
71099
|
}
|
|
71100
|
+
function parseSpecFrontmatter(content) {
|
|
71101
|
+
return extractFrontmatterBlock(content).andThen((block) => {
|
|
71102
|
+
const fields = parseYamlFields(block);
|
|
71103
|
+
const feature = fields.get("feature");
|
|
71104
|
+
if (feature === void 0) {
|
|
71105
|
+
return (0, import_neverthrow42.err)({ type: "MISSING_FIELD", field: "feature" });
|
|
71106
|
+
}
|
|
71107
|
+
return parseTimeout(fields).map((timeout) => ({ feature, timeout }));
|
|
71108
|
+
});
|
|
71109
|
+
}
|
|
71055
71110
|
|
|
71056
71111
|
// src/commands/spec-resolver.ts
|
|
71057
71112
|
var safeReadFile4 = (0, import_neverthrow43.fromThrowable)((filePath) => (0, import_node_fs8.readFileSync)(filePath, "utf8"));
|
|
@@ -71063,25 +71118,6 @@ var safeSelect = import_neverthrow43.ResultAsync.fromThrowable(
|
|
|
71063
71118
|
esm_default11,
|
|
71064
71119
|
(error48) => error48 instanceof Error && error48.name === "ExitPromptError" ? "cancelled" : "failed"
|
|
71065
71120
|
);
|
|
71066
|
-
function readAndParseSpec(absolutePath) {
|
|
71067
|
-
const readResult = safeReadFile4(absolutePath);
|
|
71068
|
-
if (readResult.isErr()) {
|
|
71069
|
-
const isEnoent3 = readResult.error.code === "ENOENT";
|
|
71070
|
-
const message = isEnoent3 ? `Spec file not found: ${absolutePath}` : `Failed to read spec file: ${absolutePath}`;
|
|
71071
|
-
process.stderr.write(`${message}
|
|
71072
|
-
`);
|
|
71073
|
-
process.exit(1);
|
|
71074
|
-
return;
|
|
71075
|
-
}
|
|
71076
|
-
const frontmatterResult = parseSpecFrontmatter(readResult.value);
|
|
71077
|
-
if (frontmatterResult.isErr()) {
|
|
71078
|
-
process.stderr.write(`Invalid spec frontmatter: ${frontmatterResult.error.type}
|
|
71079
|
-
`);
|
|
71080
|
-
process.exit(1);
|
|
71081
|
-
return;
|
|
71082
|
-
}
|
|
71083
|
-
return frontmatterResult.value;
|
|
71084
|
-
}
|
|
71085
71121
|
function findSpecFiles(xqaDirectory) {
|
|
71086
71122
|
const specsDirectory = import_node_path16.default.join(xqaDirectory, "specs");
|
|
71087
71123
|
return safeReaddir(specsDirectory).unwrapOr([]).filter((file2) => file2.endsWith(".test.md")).map((file2) => import_node_path16.default.join(specsDirectory, file2));
|
|
@@ -71104,6 +71140,25 @@ async function promptForSpec(specFiles, xqaDirectory) {
|
|
|
71104
71140
|
}
|
|
71105
71141
|
return result.value;
|
|
71106
71142
|
}
|
|
71143
|
+
function readAndParseSpec(absolutePath) {
|
|
71144
|
+
const readResult = safeReadFile4(absolutePath);
|
|
71145
|
+
if (readResult.isErr()) {
|
|
71146
|
+
const isEnoent3 = readResult.error.code === "ENOENT";
|
|
71147
|
+
const message = isEnoent3 ? `Spec file not found: ${absolutePath}` : `Failed to read spec file: ${absolutePath}`;
|
|
71148
|
+
process.stderr.write(`${message}
|
|
71149
|
+
`);
|
|
71150
|
+
process.exit(1);
|
|
71151
|
+
return;
|
|
71152
|
+
}
|
|
71153
|
+
const frontmatterResult = parseSpecFrontmatter(readResult.value);
|
|
71154
|
+
if (frontmatterResult.isErr()) {
|
|
71155
|
+
process.stderr.write(`Invalid spec frontmatter: ${frontmatterResult.error.type}
|
|
71156
|
+
`);
|
|
71157
|
+
process.exit(1);
|
|
71158
|
+
return;
|
|
71159
|
+
}
|
|
71160
|
+
return frontmatterResult.value;
|
|
71161
|
+
}
|
|
71107
71162
|
async function resolveSpecFile(specFile, xqaDirectory) {
|
|
71108
71163
|
if (specFile !== void 0) {
|
|
71109
71164
|
return specFile;
|
|
@@ -75567,17 +75622,6 @@ function deriveSpecName(filePath) {
|
|
|
75567
75622
|
function deriveSpecId(name) {
|
|
75568
75623
|
return `spec-${name.replaceAll("/", "__")}`;
|
|
75569
75624
|
}
|
|
75570
|
-
function buildSpecItems(filePaths) {
|
|
75571
|
-
return [...new Set(filePaths)].map((filePath) => {
|
|
75572
|
-
const name = deriveSpecName(filePath);
|
|
75573
|
-
return {
|
|
75574
|
-
type: "spec",
|
|
75575
|
-
id: deriveSpecId(name),
|
|
75576
|
-
name,
|
|
75577
|
-
specPath: filePath
|
|
75578
|
-
};
|
|
75579
|
-
});
|
|
75580
|
-
}
|
|
75581
75625
|
function buildFreestyleItem(entry, index) {
|
|
75582
75626
|
const position = String(index);
|
|
75583
75627
|
const label = String(index + 1);
|
|
@@ -75592,6 +75636,17 @@ function buildFreestyleItem(entry, index) {
|
|
|
75592
75636
|
}
|
|
75593
75637
|
return base;
|
|
75594
75638
|
}
|
|
75639
|
+
function buildSpecItems(filePaths) {
|
|
75640
|
+
return [...new Set(filePaths)].map((filePath) => {
|
|
75641
|
+
const name = deriveSpecName(filePath);
|
|
75642
|
+
return {
|
|
75643
|
+
type: "spec",
|
|
75644
|
+
id: deriveSpecId(name),
|
|
75645
|
+
name,
|
|
75646
|
+
specPath: filePath
|
|
75647
|
+
};
|
|
75648
|
+
});
|
|
75649
|
+
}
|
|
75595
75650
|
function buildFreestyleItems(entries) {
|
|
75596
75651
|
return entries.map((entry, index) => buildFreestyleItem(entry, index));
|
|
75597
75652
|
}
|
|
@@ -75649,18 +75704,18 @@ var PriorityQueue = class {
|
|
|
75649
75704
|
};
|
|
75650
75705
|
|
|
75651
75706
|
// src/suite/shell/item-result-builder.ts
|
|
75652
|
-
function getErrorMessage(cause) {
|
|
75653
|
-
if (cause instanceof Error) {
|
|
75654
|
-
return cause.message;
|
|
75655
|
-
}
|
|
75656
|
-
return String(cause);
|
|
75657
|
-
}
|
|
75658
75707
|
function getSpecPath(item) {
|
|
75659
75708
|
if (item.type === "spec") {
|
|
75660
75709
|
return item.specPath;
|
|
75661
75710
|
}
|
|
75662
75711
|
return null;
|
|
75663
75712
|
}
|
|
75713
|
+
function getErrorMessage(cause) {
|
|
75714
|
+
if (cause instanceof Error) {
|
|
75715
|
+
return cause.message;
|
|
75716
|
+
}
|
|
75717
|
+
return String(cause);
|
|
75718
|
+
}
|
|
75664
75719
|
function buildCompletedItem(context, result) {
|
|
75665
75720
|
return {
|
|
75666
75721
|
id: context.item.id,
|
|
@@ -75721,14 +75776,6 @@ function buildAbortedItem(item, simulatorUdid) {
|
|
|
75721
75776
|
}
|
|
75722
75777
|
|
|
75723
75778
|
// src/suite/shell/item-result-recorder.ts
|
|
75724
|
-
function buildNotifyBase(itemContext) {
|
|
75725
|
-
return {
|
|
75726
|
-
itemId: itemContext.item.id,
|
|
75727
|
-
itemName: itemContext.item.name,
|
|
75728
|
-
durationMs: itemContext.durationMs,
|
|
75729
|
-
at: Date.now()
|
|
75730
|
-
};
|
|
75731
|
-
}
|
|
75732
75779
|
function isTimeoutError(error48) {
|
|
75733
75780
|
return error48.type.toUpperCase().includes("TIMEOUT");
|
|
75734
75781
|
}
|
|
@@ -75752,6 +75799,14 @@ function notifyItemResult(context, observer) {
|
|
|
75752
75799
|
error: getErrorMessage(context.result.error.cause)
|
|
75753
75800
|
});
|
|
75754
75801
|
}
|
|
75802
|
+
function buildNotifyBase(itemContext) {
|
|
75803
|
+
return {
|
|
75804
|
+
itemId: itemContext.item.id,
|
|
75805
|
+
itemName: itemContext.item.name,
|
|
75806
|
+
durationMs: itemContext.durationMs,
|
|
75807
|
+
at: Date.now()
|
|
75808
|
+
};
|
|
75809
|
+
}
|
|
75755
75810
|
function recordItemResult(input) {
|
|
75756
75811
|
const { context, results, observer } = input;
|
|
75757
75812
|
const { itemContext, result } = context;
|
|
@@ -75836,96 +75891,96 @@ function buildHookEnv(input) {
|
|
|
75836
75891
|
// src/suite/shell/hook-runner.ts
|
|
75837
75892
|
var import_node_child_process6 = require("node:child_process");
|
|
75838
75893
|
var import_neverthrow50 = __toESM(require_index_cjs(), 1);
|
|
75839
|
-
var noop2 = () => void 0;
|
|
75840
|
-
function cleanup2(context) {
|
|
75841
|
-
clearTimeout(context.timeoutHandle);
|
|
75842
|
-
context.signal.removeEventListener("abort", context.onAbort);
|
|
75843
|
-
}
|
|
75844
|
-
function settle(context, outcome) {
|
|
75845
|
-
if (context.settled.value) {
|
|
75846
|
-
return;
|
|
75847
|
-
}
|
|
75848
|
-
context.settled.value = true;
|
|
75849
|
-
cleanup2(context);
|
|
75850
|
-
context.deferred.resolve(outcome);
|
|
75851
|
-
}
|
|
75852
75894
|
function makeDeferred() {
|
|
75853
75895
|
const raw = Promise.withResolvers();
|
|
75854
75896
|
return { promise: raw.promise, resolve: raw.resolve };
|
|
75855
75897
|
}
|
|
75856
|
-
function
|
|
75857
|
-
|
|
75858
|
-
|
|
75898
|
+
async function spawnHook(options) {
|
|
75899
|
+
const runtime = new HookRuntime(options);
|
|
75900
|
+
return runtime.start();
|
|
75901
|
+
}
|
|
75902
|
+
var HookRuntime = class {
|
|
75903
|
+
child;
|
|
75904
|
+
signal;
|
|
75905
|
+
deferred;
|
|
75906
|
+
timeoutMs;
|
|
75907
|
+
stderrBuffer = "";
|
|
75908
|
+
settled = false;
|
|
75909
|
+
timeoutHandle;
|
|
75910
|
+
onAbort;
|
|
75911
|
+
constructor(options) {
|
|
75912
|
+
const { script, cwd, env: env2, baseEnv, nodeExecPath, timeoutMs, signal } = options;
|
|
75913
|
+
this.child = (0, import_node_child_process6.spawn)(nodeExecPath, [script], {
|
|
75914
|
+
cwd,
|
|
75915
|
+
env: { ...baseEnv, ...env2 },
|
|
75916
|
+
stdio: ["ignore", "inherit", "pipe"]
|
|
75917
|
+
});
|
|
75918
|
+
this.signal = signal;
|
|
75919
|
+
this.timeoutMs = timeoutMs;
|
|
75920
|
+
this.deferred = makeDeferred();
|
|
75921
|
+
this.onAbort = () => {
|
|
75922
|
+
this.child.kill("SIGTERM");
|
|
75923
|
+
this.settle((0, import_neverthrow50.err)({ type: "HOOK_ABORTED" }));
|
|
75924
|
+
};
|
|
75859
75925
|
}
|
|
75860
|
-
|
|
75861
|
-
|
|
75862
|
-
|
|
75863
|
-
|
|
75864
|
-
|
|
75865
|
-
|
|
75866
|
-
|
|
75867
|
-
|
|
75868
|
-
|
|
75869
|
-
|
|
75870
|
-
|
|
75871
|
-
|
|
75872
|
-
|
|
75873
|
-
settle(context, (0, import_neverthrow50.err)({ type: "HOOK_SPAWN_FAILED", cause }));
|
|
75874
|
-
});
|
|
75875
|
-
child.on("exit", (code) => {
|
|
75876
|
-
if (code === 0) {
|
|
75877
|
-
settle(context, (0, import_neverthrow50.ok)());
|
|
75926
|
+
async start() {
|
|
75927
|
+
this.collectStderr();
|
|
75928
|
+
this.attachTimeout();
|
|
75929
|
+
if (this.signal.aborted) {
|
|
75930
|
+
this.onAbort();
|
|
75931
|
+
return this.deferred.promise;
|
|
75932
|
+
}
|
|
75933
|
+
this.signal.addEventListener("abort", this.onAbort, { once: true });
|
|
75934
|
+
this.attachChildListeners();
|
|
75935
|
+
return this.deferred.promise;
|
|
75936
|
+
}
|
|
75937
|
+
collectStderr() {
|
|
75938
|
+
if (this.child.stderr === null) {
|
|
75878
75939
|
return;
|
|
75879
75940
|
}
|
|
75880
|
-
|
|
75881
|
-
|
|
75882
|
-
|
|
75883
|
-
type: "HOOK_EXIT_NONZERO",
|
|
75884
|
-
code: code ?? -1,
|
|
75885
|
-
stderr: stderrReference.value
|
|
75886
|
-
})
|
|
75887
|
-
);
|
|
75888
|
-
});
|
|
75889
|
-
}
|
|
75890
|
-
function attachTimeout(context, timeoutMs) {
|
|
75891
|
-
clearTimeout(context.timeoutHandle);
|
|
75892
|
-
context.timeoutHandle = setTimeout(() => {
|
|
75893
|
-
context.child.kill("SIGTERM");
|
|
75894
|
-
settle(context, (0, import_neverthrow50.err)({ type: "HOOK_TIMEOUT", timeoutMs }));
|
|
75895
|
-
}, timeoutMs);
|
|
75896
|
-
}
|
|
75897
|
-
function buildContext2(options) {
|
|
75898
|
-
const { script, cwd, env: env2, baseEnv, nodeExecPath } = options;
|
|
75899
|
-
const deferred = makeDeferred();
|
|
75900
|
-
const stderrReference = { value: "" };
|
|
75901
|
-
const child = (0, import_node_child_process6.spawn)(nodeExecPath, [script], {
|
|
75902
|
-
cwd,
|
|
75903
|
-
env: { ...baseEnv, ...env2 },
|
|
75904
|
-
stdio: ["ignore", "inherit", "pipe"]
|
|
75905
|
-
});
|
|
75906
|
-
collectStderr(child, stderrReference);
|
|
75907
|
-
return {
|
|
75908
|
-
child,
|
|
75909
|
-
signal: options.signal,
|
|
75910
|
-
timeoutHandle: setTimeout(noop2, 0),
|
|
75911
|
-
onAbort: noop2,
|
|
75912
|
-
deferred,
|
|
75913
|
-
stderrReference,
|
|
75914
|
-
settled: { value: false }
|
|
75915
|
-
};
|
|
75916
|
-
}
|
|
75917
|
-
async function spawnHook(options) {
|
|
75918
|
-
const context = buildContext2(options);
|
|
75919
|
-
attachTimeout(context, options.timeoutMs);
|
|
75920
|
-
context.onAbort = buildOnAbort(context);
|
|
75921
|
-
if (options.signal.aborted) {
|
|
75922
|
-
context.onAbort();
|
|
75923
|
-
return context.deferred.promise;
|
|
75941
|
+
this.child.stderr.on("data", (chunk) => {
|
|
75942
|
+
this.stderrBuffer += chunk.toString();
|
|
75943
|
+
});
|
|
75924
75944
|
}
|
|
75925
|
-
|
|
75926
|
-
|
|
75927
|
-
|
|
75928
|
-
}
|
|
75945
|
+
attachTimeout() {
|
|
75946
|
+
this.timeoutHandle = setTimeout(() => {
|
|
75947
|
+
this.child.kill("SIGTERM");
|
|
75948
|
+
this.settle((0, import_neverthrow50.err)({ type: "HOOK_TIMEOUT", timeoutMs: this.timeoutMs }));
|
|
75949
|
+
}, this.timeoutMs);
|
|
75950
|
+
}
|
|
75951
|
+
attachChildListeners() {
|
|
75952
|
+
this.child.on("error", (cause) => {
|
|
75953
|
+
this.settle((0, import_neverthrow50.err)({ type: "HOOK_SPAWN_FAILED", cause }));
|
|
75954
|
+
});
|
|
75955
|
+
this.child.on("exit", (code) => {
|
|
75956
|
+
if (code === 0) {
|
|
75957
|
+
this.settle((0, import_neverthrow50.ok)());
|
|
75958
|
+
return;
|
|
75959
|
+
}
|
|
75960
|
+
this.settle(
|
|
75961
|
+
(0, import_neverthrow50.err)({
|
|
75962
|
+
type: "HOOK_EXIT_NONZERO",
|
|
75963
|
+
code: code ?? -1,
|
|
75964
|
+
stderr: this.stderrBuffer
|
|
75965
|
+
})
|
|
75966
|
+
);
|
|
75967
|
+
});
|
|
75968
|
+
}
|
|
75969
|
+
settle(outcome) {
|
|
75970
|
+
if (this.settled) {
|
|
75971
|
+
return;
|
|
75972
|
+
}
|
|
75973
|
+
this.settled = true;
|
|
75974
|
+
this.cleanup();
|
|
75975
|
+
this.deferred.resolve(outcome);
|
|
75976
|
+
}
|
|
75977
|
+
cleanup() {
|
|
75978
|
+
if (this.timeoutHandle !== void 0) {
|
|
75979
|
+
clearTimeout(this.timeoutHandle);
|
|
75980
|
+
}
|
|
75981
|
+
this.signal.removeEventListener("abort", this.onAbort);
|
|
75982
|
+
}
|
|
75983
|
+
};
|
|
75929
75984
|
var safeSpawn = import_neverthrow50.ResultAsync.fromThrowable(
|
|
75930
75985
|
spawnHook,
|
|
75931
75986
|
(cause) => ({ type: "HOOK_SPAWN_FAILED", cause })
|
|
@@ -76122,31 +76177,29 @@ function resolveFreestyleTimeout(item, config3) {
|
|
|
76122
76177
|
}
|
|
76123
76178
|
return config3.QA_EXPLORE_TIMEOUT_SECONDS ?? DEFAULT_FREESTYLE_TIMEOUT_SECONDS2;
|
|
76124
76179
|
}
|
|
76125
|
-
function buildFreestyleExplorerConfig(input) {
|
|
76126
|
-
const { item, context, simulatorUdid } = input;
|
|
76127
|
-
const { config: config3, date: date5, appContext } = context;
|
|
76128
|
-
return {
|
|
76129
|
-
mode: "freestyle",
|
|
76130
|
-
date: date5,
|
|
76131
|
-
mcpServers: createDefaultMcpServers(simulatorUdid),
|
|
76132
|
-
allowedTools: ALLOWED_TOOLS,
|
|
76133
|
-
timeoutMs: resolveFreestyleTimeout(item, config3) * MS_PER_SECOND4,
|
|
76134
|
-
appContext: composeAppContext([buildDeviceInstruction(simulatorUdid), appContext, item.prompt]),
|
|
76135
|
-
buildEnv: config3.QA_BUILD_ENV,
|
|
76136
|
-
cwd: ensureWorkerCwd(simulatorUdid),
|
|
76137
|
-
record: true
|
|
76138
|
-
};
|
|
76139
|
-
}
|
|
76140
76180
|
function buildFreestylePipelineConfig(input) {
|
|
76141
76181
|
const { item, context, signal, simulatorUdid, onEvent } = input;
|
|
76142
|
-
const { xqaDirectory, runId } = context;
|
|
76182
|
+
const { config: config3, xqaDirectory, runId, date: date5, appContext } = context;
|
|
76143
76183
|
return {
|
|
76144
76184
|
outputDir: import_node_path21.default.join(xqaDirectory, "output", item.id),
|
|
76145
76185
|
runId,
|
|
76146
76186
|
simulatorUdid,
|
|
76147
76187
|
signal,
|
|
76148
76188
|
onEvent,
|
|
76149
|
-
explorer:
|
|
76189
|
+
explorer: {
|
|
76190
|
+
mode: "freestyle",
|
|
76191
|
+
date: date5,
|
|
76192
|
+
mcpServers: createDefaultMcpServers(simulatorUdid),
|
|
76193
|
+
allowedTools: ALLOWED_TOOLS,
|
|
76194
|
+
timeoutMs: resolveFreestyleTimeout(item, config3) * MS_PER_SECOND4,
|
|
76195
|
+
appContext: composeAppContext([
|
|
76196
|
+
buildDeviceInstruction(simulatorUdid),
|
|
76197
|
+
appContext,
|
|
76198
|
+
item.prompt
|
|
76199
|
+
]),
|
|
76200
|
+
buildEnv: config3.QA_BUILD_ENV,
|
|
76201
|
+
cwd: ensureWorkerCwd(simulatorUdid)
|
|
76202
|
+
}
|
|
76150
76203
|
};
|
|
76151
76204
|
}
|
|
76152
76205
|
function executeFreestyleItem(input) {
|
|
@@ -76168,8 +76221,7 @@ function buildSpecPipelineConfig(input) {
|
|
|
76168
76221
|
allowedTools: ALLOWED_TOOLS,
|
|
76169
76222
|
appContext: composeAppContext([buildDeviceInstruction(simulatorUdid), appContext]),
|
|
76170
76223
|
buildEnv: config3.QA_BUILD_ENV,
|
|
76171
|
-
cwd: ensureWorkerCwd(simulatorUdid)
|
|
76172
|
-
record: true
|
|
76224
|
+
cwd: ensureWorkerCwd(simulatorUdid)
|
|
76173
76225
|
}
|
|
76174
76226
|
};
|
|
76175
76227
|
}
|
|
@@ -76416,12 +76468,28 @@ async function runSuite(input) {
|
|
|
76416
76468
|
aborted: input.signal.aborted
|
|
76417
76469
|
});
|
|
76418
76470
|
}
|
|
76471
|
+
async function resolveAndFilterItems(input) {
|
|
76472
|
+
const resolvedRaw = await resolveWorkItems(input);
|
|
76473
|
+
if (resolvedRaw === void 0) {
|
|
76474
|
+
return;
|
|
76475
|
+
}
|
|
76476
|
+
if (input.only === void 0) {
|
|
76477
|
+
return resolvedRaw;
|
|
76478
|
+
}
|
|
76479
|
+
const filtered = resolvedRaw.items.filter((item) => item.id === input.only);
|
|
76480
|
+
if (filtered.length === 0) {
|
|
76481
|
+
process.stderr.write(`No work item matched id: ${input.only}
|
|
76482
|
+
`);
|
|
76483
|
+
return;
|
|
76484
|
+
}
|
|
76485
|
+
return { ...resolvedRaw, items: filtered };
|
|
76486
|
+
}
|
|
76419
76487
|
async function runSuiteCommand(input) {
|
|
76420
76488
|
const preflightExit = await runPreflightChecks();
|
|
76421
76489
|
if (preflightExit !== void 0) {
|
|
76422
76490
|
return preflightExit;
|
|
76423
76491
|
}
|
|
76424
|
-
const resolved = await
|
|
76492
|
+
const resolved = await resolveAndFilterItems(input);
|
|
76425
76493
|
if (resolved === void 0) {
|
|
76426
76494
|
return 1;
|
|
76427
76495
|
}
|
|
@@ -76460,7 +76528,7 @@ function resolveXqaDirectory() {
|
|
|
76460
76528
|
return result.value;
|
|
76461
76529
|
}
|
|
76462
76530
|
var program2 = new Command();
|
|
76463
|
-
program2.name("xqa").description("AI-powered QA agent CLI").version(`${"1.
|
|
76531
|
+
program2.name("xqa").description("AI-powered QA agent CLI").version(`${"1.16.0"}${false ? ` (dev build +${"3af4493"})` : ""}`);
|
|
76464
76532
|
program2.command("init").description("Initialize a new xqa project in the current directory").action(() => {
|
|
76465
76533
|
runInitCommand();
|
|
76466
76534
|
});
|
|
@@ -76516,11 +76584,15 @@ program2.command("spec").description("Run the explorer agent against a spec file
|
|
|
76516
76584
|
{ config: config2, xqaDirectory }
|
|
76517
76585
|
);
|
|
76518
76586
|
});
|
|
76519
|
-
program2.command("run").description("Run a test suite or a set of spec files").option("--suite <name>", "Name of the suite to run").option("--spec <globs...>", "Glob patterns matching spec files to run").option("--debug", "Log timing and event details to stderr").action(async (options) => {
|
|
76587
|
+
program2.command("run").description("Run a test suite or a set of spec files").option("--suite <name>", "Name of the suite to run").option("--spec <globs...>", "Glob patterns matching spec files to run").option("--only <id>", "Run only the work item with the given id (requires --suite)").option("--debug", "Log timing and event details to stderr").action(async (options) => {
|
|
76520
76588
|
if (options.suite === void 0 === (options.spec === void 0)) {
|
|
76521
76589
|
process.stderr.write("Exactly one of --suite or --spec must be provided\n");
|
|
76522
76590
|
process.exit(1);
|
|
76523
76591
|
}
|
|
76592
|
+
if (options.only !== void 0 && options.suite === void 0) {
|
|
76593
|
+
process.stderr.write("--only requires --suite\n");
|
|
76594
|
+
process.exit(1);
|
|
76595
|
+
}
|
|
76524
76596
|
const xqaDirectory = resolveXqaDirectory();
|
|
76525
76597
|
const mode = options.suite === void 0 ? { type: "spec", globs: options.spec ?? [] } : { type: "suite", name: options.suite };
|
|
76526
76598
|
const exitCode = await runSuiteCommand({
|
|
@@ -76528,7 +76600,8 @@ program2.command("run").description("Run a test suite or a set of spec files").o
|
|
|
76528
76600
|
xqaDirectory,
|
|
76529
76601
|
config: config2,
|
|
76530
76602
|
debug: options.debug ?? false,
|
|
76531
|
-
signal: controller.signal
|
|
76603
|
+
signal: controller.signal,
|
|
76604
|
+
only: options.only
|
|
76532
76605
|
});
|
|
76533
76606
|
process.exit(exitCode);
|
|
76534
76607
|
});
|