@deepstorm/cli 0.10.2 → 0.11.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/dist/cli.js
CHANGED
|
@@ -1187,13 +1187,13 @@ var require_ast = __commonJS({
|
|
|
1187
1187
|
helperExpression: function helperExpression(node) {
|
|
1188
1188
|
return node.type === "SubExpression" || (node.type === "MustacheStatement" || node.type === "BlockStatement") && !!(node.params && node.params.length || node.hash);
|
|
1189
1189
|
},
|
|
1190
|
-
scopedId: function scopedId(
|
|
1191
|
-
return /^\.|this\b/.test(
|
|
1190
|
+
scopedId: function scopedId(path26) {
|
|
1191
|
+
return /^\.|this\b/.test(path26.original);
|
|
1192
1192
|
},
|
|
1193
1193
|
// an ID is simple if it only has one part, and that part is not
|
|
1194
1194
|
// `..` or `this`.
|
|
1195
|
-
simpleId: function simpleId(
|
|
1196
|
-
return
|
|
1195
|
+
simpleId: function simpleId(path26) {
|
|
1196
|
+
return path26.parts.length === 1 && !AST.helpers.scopedId(path26) && !path26.depth;
|
|
1197
1197
|
}
|
|
1198
1198
|
}
|
|
1199
1199
|
};
|
|
@@ -2263,12 +2263,12 @@ var require_helpers2 = __commonJS({
|
|
|
2263
2263
|
loc
|
|
2264
2264
|
};
|
|
2265
2265
|
}
|
|
2266
|
-
function prepareMustache(
|
|
2266
|
+
function prepareMustache(path26, params, hash, open, strip, locInfo) {
|
|
2267
2267
|
var escapeFlag = open.charAt(3) || open.charAt(2), escaped = escapeFlag !== "{" && escapeFlag !== "&";
|
|
2268
2268
|
var decorator = /\*/.test(open);
|
|
2269
2269
|
return {
|
|
2270
2270
|
type: decorator ? "Decorator" : "MustacheStatement",
|
|
2271
|
-
path:
|
|
2271
|
+
path: path26,
|
|
2272
2272
|
params,
|
|
2273
2273
|
hash,
|
|
2274
2274
|
escaped,
|
|
@@ -2586,9 +2586,9 @@ var require_compiler = __commonJS({
|
|
|
2586
2586
|
},
|
|
2587
2587
|
DecoratorBlock: function DecoratorBlock(decorator) {
|
|
2588
2588
|
var program2 = decorator.program && this.compileProgram(decorator.program);
|
|
2589
|
-
var params = this.setupFullMustacheParams(decorator, program2, void 0),
|
|
2589
|
+
var params = this.setupFullMustacheParams(decorator, program2, void 0), path26 = decorator.path;
|
|
2590
2590
|
this.useDecorators = true;
|
|
2591
|
-
this.opcode("registerDecorator", params.length,
|
|
2591
|
+
this.opcode("registerDecorator", params.length, path26.original);
|
|
2592
2592
|
},
|
|
2593
2593
|
PartialStatement: function PartialStatement(partial) {
|
|
2594
2594
|
this.usePartial = true;
|
|
@@ -2652,46 +2652,46 @@ var require_compiler = __commonJS({
|
|
|
2652
2652
|
}
|
|
2653
2653
|
},
|
|
2654
2654
|
ambiguousSexpr: function ambiguousSexpr(sexpr, program2, inverse) {
|
|
2655
|
-
var
|
|
2656
|
-
this.opcode("getContext",
|
|
2655
|
+
var path26 = sexpr.path, name = path26.parts[0], isBlock = program2 != null || inverse != null;
|
|
2656
|
+
this.opcode("getContext", path26.depth);
|
|
2657
2657
|
this.opcode("pushProgram", program2);
|
|
2658
2658
|
this.opcode("pushProgram", inverse);
|
|
2659
|
-
|
|
2660
|
-
this.accept(
|
|
2659
|
+
path26.strict = true;
|
|
2660
|
+
this.accept(path26);
|
|
2661
2661
|
this.opcode("invokeAmbiguous", name, isBlock);
|
|
2662
2662
|
},
|
|
2663
2663
|
simpleSexpr: function simpleSexpr(sexpr) {
|
|
2664
|
-
var
|
|
2665
|
-
|
|
2666
|
-
this.accept(
|
|
2664
|
+
var path26 = sexpr.path;
|
|
2665
|
+
path26.strict = true;
|
|
2666
|
+
this.accept(path26);
|
|
2667
2667
|
this.opcode("resolvePossibleLambda");
|
|
2668
2668
|
},
|
|
2669
2669
|
helperSexpr: function helperSexpr(sexpr, program2, inverse) {
|
|
2670
|
-
var params = this.setupFullMustacheParams(sexpr, program2, inverse),
|
|
2670
|
+
var params = this.setupFullMustacheParams(sexpr, program2, inverse), path26 = sexpr.path, name = path26.parts[0];
|
|
2671
2671
|
if (this.options.knownHelpers[name]) {
|
|
2672
2672
|
this.opcode("invokeKnownHelper", params.length, name);
|
|
2673
2673
|
} else if (this.options.knownHelpersOnly) {
|
|
2674
2674
|
throw new _exception2["default"]("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr);
|
|
2675
2675
|
} else {
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
this.accept(
|
|
2679
|
-
this.opcode("invokeHelper", params.length,
|
|
2676
|
+
path26.strict = true;
|
|
2677
|
+
path26.falsy = true;
|
|
2678
|
+
this.accept(path26);
|
|
2679
|
+
this.opcode("invokeHelper", params.length, path26.original, _ast2["default"].helpers.simpleId(path26));
|
|
2680
2680
|
}
|
|
2681
2681
|
},
|
|
2682
|
-
PathExpression: function PathExpression(
|
|
2683
|
-
this.addDepth(
|
|
2684
|
-
this.opcode("getContext",
|
|
2685
|
-
var name =
|
|
2682
|
+
PathExpression: function PathExpression(path26) {
|
|
2683
|
+
this.addDepth(path26.depth);
|
|
2684
|
+
this.opcode("getContext", path26.depth);
|
|
2685
|
+
var name = path26.parts[0], scoped = _ast2["default"].helpers.scopedId(path26), blockParamId = !path26.depth && !scoped && this.blockParamIndex(name);
|
|
2686
2686
|
if (blockParamId) {
|
|
2687
|
-
this.opcode("lookupBlockParam", blockParamId,
|
|
2687
|
+
this.opcode("lookupBlockParam", blockParamId, path26.parts);
|
|
2688
2688
|
} else if (!name) {
|
|
2689
2689
|
this.opcode("pushContext");
|
|
2690
|
-
} else if (
|
|
2690
|
+
} else if (path26.data) {
|
|
2691
2691
|
this.options.data = true;
|
|
2692
|
-
this.opcode("lookupData",
|
|
2692
|
+
this.opcode("lookupData", path26.depth, path26.parts, path26.strict);
|
|
2693
2693
|
} else {
|
|
2694
|
-
this.opcode("lookupOnContext",
|
|
2694
|
+
this.opcode("lookupOnContext", path26.parts, path26.falsy, path26.strict, scoped);
|
|
2695
2695
|
}
|
|
2696
2696
|
},
|
|
2697
2697
|
StringLiteral: function StringLiteral(string) {
|
|
@@ -3041,16 +3041,16 @@ var require_util = __commonJS({
|
|
|
3041
3041
|
}
|
|
3042
3042
|
exports2.urlGenerate = urlGenerate;
|
|
3043
3043
|
function normalize(aPath) {
|
|
3044
|
-
var
|
|
3044
|
+
var path26 = aPath;
|
|
3045
3045
|
var url = urlParse(aPath);
|
|
3046
3046
|
if (url) {
|
|
3047
3047
|
if (!url.path) {
|
|
3048
3048
|
return aPath;
|
|
3049
3049
|
}
|
|
3050
|
-
|
|
3050
|
+
path26 = url.path;
|
|
3051
3051
|
}
|
|
3052
|
-
var isAbsolute = exports2.isAbsolute(
|
|
3053
|
-
var parts =
|
|
3052
|
+
var isAbsolute = exports2.isAbsolute(path26);
|
|
3053
|
+
var parts = path26.split(/\/+/);
|
|
3054
3054
|
for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
|
|
3055
3055
|
part = parts[i];
|
|
3056
3056
|
if (part === ".") {
|
|
@@ -3067,18 +3067,18 @@ var require_util = __commonJS({
|
|
|
3067
3067
|
}
|
|
3068
3068
|
}
|
|
3069
3069
|
}
|
|
3070
|
-
|
|
3071
|
-
if (
|
|
3072
|
-
|
|
3070
|
+
path26 = parts.join("/");
|
|
3071
|
+
if (path26 === "") {
|
|
3072
|
+
path26 = isAbsolute ? "/" : ".";
|
|
3073
3073
|
}
|
|
3074
3074
|
if (url) {
|
|
3075
|
-
url.path =
|
|
3075
|
+
url.path = path26;
|
|
3076
3076
|
return urlGenerate(url);
|
|
3077
3077
|
}
|
|
3078
|
-
return
|
|
3078
|
+
return path26;
|
|
3079
3079
|
}
|
|
3080
3080
|
exports2.normalize = normalize;
|
|
3081
|
-
function
|
|
3081
|
+
function join24(aRoot, aPath) {
|
|
3082
3082
|
if (aRoot === "") {
|
|
3083
3083
|
aRoot = ".";
|
|
3084
3084
|
}
|
|
@@ -3110,7 +3110,7 @@ var require_util = __commonJS({
|
|
|
3110
3110
|
}
|
|
3111
3111
|
return joined;
|
|
3112
3112
|
}
|
|
3113
|
-
exports2.join =
|
|
3113
|
+
exports2.join = join24;
|
|
3114
3114
|
exports2.isAbsolute = function(aPath) {
|
|
3115
3115
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
3116
3116
|
};
|
|
@@ -3283,7 +3283,7 @@ var require_util = __commonJS({
|
|
|
3283
3283
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
3284
3284
|
}
|
|
3285
3285
|
}
|
|
3286
|
-
sourceURL =
|
|
3286
|
+
sourceURL = join24(urlGenerate(parsed), sourceURL);
|
|
3287
3287
|
}
|
|
3288
3288
|
return normalize(sourceURL);
|
|
3289
3289
|
}
|
|
@@ -5858,8 +5858,8 @@ var require_printer = __commonJS({
|
|
|
5858
5858
|
return this.accept(sexpr.path) + " " + params + hash;
|
|
5859
5859
|
};
|
|
5860
5860
|
PrintVisitor.prototype.PathExpression = function(id) {
|
|
5861
|
-
var
|
|
5862
|
-
return (id.data ? "@" : "") + "PATH:" +
|
|
5861
|
+
var path26 = id.parts.join("/");
|
|
5862
|
+
return (id.data ? "@" : "") + "PATH:" + path26;
|
|
5863
5863
|
};
|
|
5864
5864
|
PrintVisitor.prototype.StringLiteral = function(string) {
|
|
5865
5865
|
return '"' + string.value + '"';
|
|
@@ -5898,8 +5898,8 @@ var require_lib = __commonJS({
|
|
|
5898
5898
|
handlebars.print = printer.print;
|
|
5899
5899
|
module2.exports = handlebars;
|
|
5900
5900
|
function extension(module3, filename) {
|
|
5901
|
-
var
|
|
5902
|
-
var templateString =
|
|
5901
|
+
var fs30 = require("fs");
|
|
5902
|
+
var templateString = fs30.readFileSync(filename, "utf8");
|
|
5903
5903
|
module3.exports = handlebars.compile(templateString);
|
|
5904
5904
|
}
|
|
5905
5905
|
if (typeof require !== "undefined" && require.extensions) {
|
|
@@ -5911,8 +5911,8 @@ var require_lib = __commonJS({
|
|
|
5911
5911
|
|
|
5912
5912
|
// src/index.ts
|
|
5913
5913
|
var import_commander = require("commander");
|
|
5914
|
-
var
|
|
5915
|
-
var
|
|
5914
|
+
var fs29 = __toESM(require("node:fs"));
|
|
5915
|
+
var path25 = __toESM(require("node:path"));
|
|
5916
5916
|
|
|
5917
5917
|
// src/commands/setup.ts
|
|
5918
5918
|
var path9 = __toESM(require("node:path"));
|
|
@@ -10507,13 +10507,380 @@ function registerPilotCommands(program2) {
|
|
|
10507
10507
|
(0, import_pilot.registerPilotCommands)(program2);
|
|
10508
10508
|
}
|
|
10509
10509
|
|
|
10510
|
-
// src/
|
|
10511
|
-
var
|
|
10510
|
+
// src/record/browser-recorder.ts
|
|
10511
|
+
var path22 = __toESM(require("node:path"));
|
|
10512
|
+
var fs26 = __toESM(require("node:fs"));
|
|
10513
|
+
var import_playwright = require("playwright");
|
|
10514
|
+
|
|
10515
|
+
// src/record/recorder.ts
|
|
10512
10516
|
var path21 = __toESM(require("node:path"));
|
|
10517
|
+
var fs25 = __toESM(require("node:fs"));
|
|
10518
|
+
function filterNoiseEvents(events) {
|
|
10519
|
+
const noiseTypes = [];
|
|
10520
|
+
const noiseSet = new Set(noiseTypes);
|
|
10521
|
+
return events.filter((e) => !noiseSet.has(e.type));
|
|
10522
|
+
}
|
|
10523
|
+
function eventGroupKey(e) {
|
|
10524
|
+
const selector = e.data?.cssSelector || "";
|
|
10525
|
+
return { cssSelector: selector, type: e.type };
|
|
10526
|
+
}
|
|
10527
|
+
function dedupEvents(events) {
|
|
10528
|
+
if (events.length === 0) return [];
|
|
10529
|
+
const result = [];
|
|
10530
|
+
const inputElements = /* @__PURE__ */ new Map();
|
|
10531
|
+
for (let i = 0; i < events.length; i++) {
|
|
10532
|
+
const current = events[i];
|
|
10533
|
+
if (current.type === "input" || current.type === "select") {
|
|
10534
|
+
const key = eventGroupKey(current);
|
|
10535
|
+
const dedupKey = `${key.cssSelector}|${key.type}`;
|
|
10536
|
+
inputElements.set(dedupKey, current);
|
|
10537
|
+
continue;
|
|
10538
|
+
}
|
|
10539
|
+
if (current.type === "click") {
|
|
10540
|
+
const lastEvent = result.length > 0 ? result[result.length - 1] : null;
|
|
10541
|
+
if (lastEvent && lastEvent.type === "click") {
|
|
10542
|
+
const currentKey = eventGroupKey(current);
|
|
10543
|
+
const lastKey = eventGroupKey(lastEvent);
|
|
10544
|
+
const sameElement = currentKey.cssSelector === lastKey.cssSelector;
|
|
10545
|
+
const withinThreshold = current.ts - lastEvent.ts <= 500;
|
|
10546
|
+
if (sameElement && withinThreshold) {
|
|
10547
|
+
continue;
|
|
10548
|
+
}
|
|
10549
|
+
}
|
|
10550
|
+
}
|
|
10551
|
+
result.push(current);
|
|
10552
|
+
}
|
|
10553
|
+
inputElements.forEach((event) => {
|
|
10554
|
+
result.push(event);
|
|
10555
|
+
});
|
|
10556
|
+
result.sort((a, b) => a.ts - b.ts);
|
|
10557
|
+
return result;
|
|
10558
|
+
}
|
|
10559
|
+
function serializeRecording(data) {
|
|
10560
|
+
return JSON.stringify(data, null, 2);
|
|
10561
|
+
}
|
|
10562
|
+
function buildRecordingFileName(seq = 1) {
|
|
10563
|
+
const now = /* @__PURE__ */ new Date();
|
|
10564
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
10565
|
+
const dateTime = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
|
10566
|
+
const seqStr = seq > 1 ? `-${seq}` : "";
|
|
10567
|
+
return `${dateTime}${seqStr}.recording.json`;
|
|
10568
|
+
}
|
|
10569
|
+
function recordingsDir() {
|
|
10570
|
+
return path21.join(process.cwd(), ".deepstorm", "recordings");
|
|
10571
|
+
}
|
|
10572
|
+
function getNextSeq(datePrefix) {
|
|
10573
|
+
const dir = recordingsDir();
|
|
10574
|
+
if (!fs25.existsSync(dir)) return 1;
|
|
10575
|
+
const files = fs25.readdirSync(dir).filter((f) => f.startsWith(datePrefix));
|
|
10576
|
+
if (files.length === 0) return 1;
|
|
10577
|
+
let maxSeq = 0;
|
|
10578
|
+
for (const f of files) {
|
|
10579
|
+
const match = f.match(/(?:-(\d+))?\.recording\.json$/);
|
|
10580
|
+
if (match) {
|
|
10581
|
+
const s = match[1] ? parseInt(match[1], 10) : 1;
|
|
10582
|
+
maxSeq = Math.max(maxSeq, s);
|
|
10583
|
+
}
|
|
10584
|
+
}
|
|
10585
|
+
return maxSeq + 1;
|
|
10586
|
+
}
|
|
10587
|
+
|
|
10588
|
+
// src/record/browser-recorder.ts
|
|
10589
|
+
async function recordBrowserSession(url) {
|
|
10590
|
+
let targetUrl;
|
|
10591
|
+
try {
|
|
10592
|
+
targetUrl = new URL(url);
|
|
10593
|
+
} catch {
|
|
10594
|
+
throw new Error(`\u65E0\u6548\u7684 URL: ${url}`);
|
|
10595
|
+
}
|
|
10596
|
+
if (!await isPlaywrightAvailable()) {
|
|
10597
|
+
console.error("Playwright \u6D4F\u89C8\u5668\u672A\u5B89\u88C5\uFF0C\u8BF7\u6267\u884C npx playwright install");
|
|
10598
|
+
process.exit(1);
|
|
10599
|
+
}
|
|
10600
|
+
const startTime = Date.now();
|
|
10601
|
+
const browser = await import_playwright.chromium.launch({ headless: false });
|
|
10602
|
+
const context = await browser.newContext();
|
|
10603
|
+
const page = await context.newPage();
|
|
10604
|
+
const events = [];
|
|
10605
|
+
const requestMethods = /* @__PURE__ */ new Map();
|
|
10606
|
+
const cdpSession = await context.newCDPSession(page);
|
|
10607
|
+
cdpSession.on("Network.requestWillBeSent", (params) => {
|
|
10608
|
+
const { request, type, requestId } = params;
|
|
10609
|
+
requestMethods.set(requestId, request.method);
|
|
10610
|
+
if (type === "XHR" || type === "Fetch") {
|
|
10611
|
+
events.push({
|
|
10612
|
+
ts: Date.now() - startTime,
|
|
10613
|
+
type: "network",
|
|
10614
|
+
data: {
|
|
10615
|
+
url: request.url,
|
|
10616
|
+
method: request.method,
|
|
10617
|
+
type: "request"
|
|
10618
|
+
}
|
|
10619
|
+
});
|
|
10620
|
+
}
|
|
10621
|
+
});
|
|
10622
|
+
cdpSession.on("Network.responseReceived", (params) => {
|
|
10623
|
+
const { response, type, requestId } = params;
|
|
10624
|
+
const method = requestMethods.get(requestId) ?? "GET";
|
|
10625
|
+
if (type === "XHR" || type === "Fetch") {
|
|
10626
|
+
events.push({
|
|
10627
|
+
ts: Date.now() - startTime,
|
|
10628
|
+
type: "network",
|
|
10629
|
+
data: {
|
|
10630
|
+
url: response.url,
|
|
10631
|
+
method,
|
|
10632
|
+
statusCode: response.status,
|
|
10633
|
+
type: "response"
|
|
10634
|
+
}
|
|
10635
|
+
});
|
|
10636
|
+
}
|
|
10637
|
+
});
|
|
10638
|
+
cdpSession.on("Page.frameNavigated", (params) => {
|
|
10639
|
+
const { frame } = params;
|
|
10640
|
+
if (frame.parentId === void 0 || frame.parentId === null) {
|
|
10641
|
+
events.push({
|
|
10642
|
+
ts: Date.now() - startTime,
|
|
10643
|
+
type: "navigation",
|
|
10644
|
+
data: {
|
|
10645
|
+
url: frame.url,
|
|
10646
|
+
title: frame.name || frame.url,
|
|
10647
|
+
type: "full"
|
|
10648
|
+
}
|
|
10649
|
+
});
|
|
10650
|
+
}
|
|
10651
|
+
});
|
|
10652
|
+
cdpSession.on("Page.navigatedWithinDocument", (params) => {
|
|
10653
|
+
events.push({
|
|
10654
|
+
ts: Date.now() - startTime,
|
|
10655
|
+
type: "navigation",
|
|
10656
|
+
data: {
|
|
10657
|
+
url: params.url,
|
|
10658
|
+
type: "spa"
|
|
10659
|
+
}
|
|
10660
|
+
});
|
|
10661
|
+
});
|
|
10662
|
+
await page.exposeFunction("__deepstorm_recordEvent", (type, data) => {
|
|
10663
|
+
events.push({
|
|
10664
|
+
ts: Date.now() - startTime,
|
|
10665
|
+
type,
|
|
10666
|
+
data
|
|
10667
|
+
});
|
|
10668
|
+
});
|
|
10669
|
+
await page.goto(targetUrl.href);
|
|
10670
|
+
await page.evaluate(`(function() {
|
|
10671
|
+
var send = window.__deepstorm_recordEvent;
|
|
10672
|
+
|
|
10673
|
+
// Click listener (capture phase)
|
|
10674
|
+
document.addEventListener('click', function(e) {
|
|
10675
|
+
var target = e.target;
|
|
10676
|
+
if (!target || target === document.body || target === document.documentElement) return;
|
|
10677
|
+
|
|
10678
|
+
var info = {
|
|
10679
|
+
tagName: target.tagName.toLowerCase(),
|
|
10680
|
+
id: target.id || undefined,
|
|
10681
|
+
className: (target.className || '').toString().slice(0, 100) || undefined,
|
|
10682
|
+
textContent: (target.textContent || '').trim().slice(0, 100) || undefined
|
|
10683
|
+
};
|
|
10684
|
+
|
|
10685
|
+
var role = target.getAttribute('role');
|
|
10686
|
+
if (role) info.role = role;
|
|
10687
|
+
var ariaLabel = target.getAttribute('aria-label');
|
|
10688
|
+
if (ariaLabel) info.ariaLabel = ariaLabel;
|
|
10689
|
+
var placeholder = target.getAttribute('placeholder');
|
|
10690
|
+
if (placeholder) info.placeholder = placeholder;
|
|
10691
|
+
var dataTestId = target.getAttribute('data-testid');
|
|
10692
|
+
if (dataTestId) info.dataTestId = dataTestId;
|
|
10693
|
+
|
|
10694
|
+
info.cssSelector = buildSimpleSelector(target);
|
|
10695
|
+
send('click', info);
|
|
10696
|
+
}, true);
|
|
10697
|
+
|
|
10698
|
+
// Input listener (change event for final value)
|
|
10699
|
+
document.addEventListener('change', function(e) {
|
|
10700
|
+
var target = e.target;
|
|
10701
|
+
if (!target) return;
|
|
10702
|
+
|
|
10703
|
+
if (target.tagName === 'SELECT') {
|
|
10704
|
+
send('select', {
|
|
10705
|
+
tagName: 'select',
|
|
10706
|
+
value: target.value,
|
|
10707
|
+
name: target.name || undefined,
|
|
10708
|
+
cssSelector: buildSimpleSelector(target)
|
|
10709
|
+
});
|
|
10710
|
+
return;
|
|
10711
|
+
}
|
|
10712
|
+
|
|
10713
|
+
if (target.type === 'password') {
|
|
10714
|
+
send('input', {
|
|
10715
|
+
tagName: target.tagName.toLowerCase(),
|
|
10716
|
+
type: 'password',
|
|
10717
|
+
value: '****',
|
|
10718
|
+
name: target.name || undefined,
|
|
10719
|
+
placeholder: target.placeholder || undefined,
|
|
10720
|
+
cssSelector: buildSimpleSelector(target)
|
|
10721
|
+
});
|
|
10722
|
+
return;
|
|
10723
|
+
}
|
|
10724
|
+
|
|
10725
|
+
send('input', {
|
|
10726
|
+
tagName: target.tagName.toLowerCase(),
|
|
10727
|
+
type: target.type || undefined,
|
|
10728
|
+
value: target.value,
|
|
10729
|
+
name: target.name || undefined,
|
|
10730
|
+
placeholder: target.placeholder || undefined,
|
|
10731
|
+
cssSelector: buildSimpleSelector(target)
|
|
10732
|
+
});
|
|
10733
|
+
}, true);
|
|
10734
|
+
|
|
10735
|
+
// Submit listener
|
|
10736
|
+
document.addEventListener('submit', function(e) {
|
|
10737
|
+
var form = e.target;
|
|
10738
|
+
if (!form) return;
|
|
10739
|
+
send('submit', {
|
|
10740
|
+
cssSelector: buildSimpleSelector(form),
|
|
10741
|
+
id: form.id || undefined,
|
|
10742
|
+
action: form.action || undefined
|
|
10743
|
+
});
|
|
10744
|
+
}, true);
|
|
10745
|
+
|
|
10746
|
+
// Helper: build simple CSS selector
|
|
10747
|
+
function buildSimpleSelector(el) {
|
|
10748
|
+
if (el.id) return '#' + CSS.escape(el.id);
|
|
10749
|
+
var testId = el.getAttribute('data-testid');
|
|
10750
|
+
if (testId) return '[data-testid="' + CSS.escape(testId) + '"]';
|
|
10751
|
+
var tag = el.tagName.toLowerCase();
|
|
10752
|
+
var cls = '';
|
|
10753
|
+
for (var i = 0; i < el.classList.length; i++) {
|
|
10754
|
+
cls += '.' + CSS.escape(el.classList[i]);
|
|
10755
|
+
}
|
|
10756
|
+
if (cls) return tag + cls;
|
|
10757
|
+
var parent = el.parentElement;
|
|
10758
|
+
if (parent) {
|
|
10759
|
+
var siblings = Array.from(parent.children).filter(function(s) {
|
|
10760
|
+
return s.tagName === el.tagName;
|
|
10761
|
+
});
|
|
10762
|
+
if (siblings.length > 1) {
|
|
10763
|
+
var idx = siblings.indexOf(el) + 1;
|
|
10764
|
+
return tag + ':nth-child(' + idx + ')';
|
|
10765
|
+
}
|
|
10766
|
+
}
|
|
10767
|
+
return tag;
|
|
10768
|
+
}
|
|
10769
|
+
})();`);
|
|
10770
|
+
console.log("\u{1F3A5} \u5F55\u5236\u4E2D... \u6309 Ctrl+D \u505C\u6B62");
|
|
10771
|
+
const stopPromise = new Promise((resolve4) => {
|
|
10772
|
+
const wasRaw = process.stdin.isRaw;
|
|
10773
|
+
process.stdin.setRawMode?.(true);
|
|
10774
|
+
process.stdin.resume();
|
|
10775
|
+
process.stdin.on("data", (chunk) => {
|
|
10776
|
+
if (chunk.length === 1 && chunk[0] === 4) {
|
|
10777
|
+
cleanup();
|
|
10778
|
+
resolve4();
|
|
10779
|
+
}
|
|
10780
|
+
});
|
|
10781
|
+
process.stdin.on("end", () => {
|
|
10782
|
+
cleanup();
|
|
10783
|
+
resolve4();
|
|
10784
|
+
});
|
|
10785
|
+
function cleanup() {
|
|
10786
|
+
process.stdin.setRawMode?.(wasRaw ?? false);
|
|
10787
|
+
process.stdin.pause();
|
|
10788
|
+
}
|
|
10789
|
+
});
|
|
10790
|
+
const crashPromise = new Promise((_resolve, reject) => {
|
|
10791
|
+
browser.on("disconnected", () => {
|
|
10792
|
+
reject(new Error("\u6D4F\u89C8\u5668\u8FDE\u63A5\u65AD\u5F00"));
|
|
10793
|
+
});
|
|
10794
|
+
});
|
|
10795
|
+
try {
|
|
10796
|
+
await Promise.race([stopPromise, crashPromise]);
|
|
10797
|
+
} catch (err) {
|
|
10798
|
+
console.error("\n\u6D4F\u89C8\u5668\u8FDE\u63A5\u65AD\u5F00\uFF0C\u5F55\u5236\u5DF2\u7EC8\u6B62");
|
|
10799
|
+
throw err;
|
|
10800
|
+
} finally {
|
|
10801
|
+
process.stdin.setRawMode?.(false);
|
|
10802
|
+
process.stdin.pause();
|
|
10803
|
+
}
|
|
10804
|
+
const duration = Date.now() - startTime;
|
|
10805
|
+
try {
|
|
10806
|
+
const screenshotBuffer = await page.screenshot({ type: "jpeg", quality: 70 });
|
|
10807
|
+
events.push({
|
|
10808
|
+
ts: Date.now() - startTime,
|
|
10809
|
+
type: "screenshot",
|
|
10810
|
+
data: {
|
|
10811
|
+
label: "final",
|
|
10812
|
+
data: screenshotBuffer.toString("base64")
|
|
10813
|
+
}
|
|
10814
|
+
});
|
|
10815
|
+
} catch {
|
|
10816
|
+
}
|
|
10817
|
+
await browser.close();
|
|
10818
|
+
const filteredEvents = dedupEvents(filterNoiseEvents(events));
|
|
10819
|
+
const recordingData = {
|
|
10820
|
+
meta: {
|
|
10821
|
+
url: targetUrl.href,
|
|
10822
|
+
recordedAt: new Date(startTime).toISOString(),
|
|
10823
|
+
duration,
|
|
10824
|
+
browser: `Playwright Chromium ${browser.version()}`
|
|
10825
|
+
},
|
|
10826
|
+
events: filteredEvents
|
|
10827
|
+
};
|
|
10828
|
+
const dir = recordingsDir();
|
|
10829
|
+
fs26.mkdirSync(dir, { recursive: true });
|
|
10830
|
+
const datePrefix = buildRecordingFileName().replace(".recording.json", "");
|
|
10831
|
+
const seq = getNextSeq(datePrefix);
|
|
10832
|
+
const fileName = buildRecordingFileName(seq);
|
|
10833
|
+
const filePath = path22.join(dir, fileName);
|
|
10834
|
+
fs26.writeFileSync(filePath, serializeRecording(recordingData), "utf-8");
|
|
10835
|
+
console.log(`
|
|
10836
|
+
\u2705 \u5F55\u5236\u5B8C\u6210`);
|
|
10837
|
+
console.log(` \u6301\u7EED\u65F6\u95F4: ${(duration / 1e3).toFixed(1)} \u79D2`);
|
|
10838
|
+
console.log(` \u4E8B\u4EF6\u603B\u6570: ${filteredEvents.length}`);
|
|
10839
|
+
console.log(` \u6587\u4EF6\u8DEF\u5F84: ${filePath}`);
|
|
10840
|
+
return filePath;
|
|
10841
|
+
}
|
|
10842
|
+
async function isPlaywrightAvailable() {
|
|
10843
|
+
try {
|
|
10844
|
+
const { execSync: execSync3 } = await import("node:child_process");
|
|
10845
|
+
execSync3(
|
|
10846
|
+
"npx playwright install --dry-run 2>/dev/null || npx playwright --version 2>/dev/null",
|
|
10847
|
+
{ stdio: "ignore" }
|
|
10848
|
+
);
|
|
10849
|
+
const browser = await import_playwright.chromium.launch({ headless: true });
|
|
10850
|
+
await browser.close();
|
|
10851
|
+
return true;
|
|
10852
|
+
} catch {
|
|
10853
|
+
return false;
|
|
10854
|
+
}
|
|
10855
|
+
}
|
|
10856
|
+
|
|
10857
|
+
// src/commands/record.ts
|
|
10858
|
+
function registerRecordCommand(program2) {
|
|
10859
|
+
const recordCmd = program2.command("record").description("\u6D4F\u89C8\u5668\u64CD\u4F5C\u5F55\u5236 \u2014 \u542F\u52A8 headed \u6D4F\u89C8\u5668\u5F55\u5236\u7528\u6237\u64CD\u4F5C\uFF0C\u8F93\u51FA .recording.json");
|
|
10860
|
+
recordCmd.command("start").description("\u5F00\u59CB\u5F55\u5236 \u2014 \u542F\u52A8 headed \u6D4F\u89C8\u5668\u5E76\u6253\u5F00\u6307\u5B9A URL").option("-u, --url <url>", "\u76EE\u6807 URL").action(async (options) => {
|
|
10861
|
+
if (!options.url) {
|
|
10862
|
+
console.error("\u8BF7\u4F7F\u7528 -u <url> \u6307\u5B9A\u76EE\u6807 URL");
|
|
10863
|
+
process.exit(1);
|
|
10864
|
+
}
|
|
10865
|
+
try {
|
|
10866
|
+
await recordBrowserSession(options.url);
|
|
10867
|
+
} catch (err) {
|
|
10868
|
+
console.error("\u5F55\u5236\u5931\u8D25:", err instanceof Error ? err.message : err);
|
|
10869
|
+
process.exit(1);
|
|
10870
|
+
}
|
|
10871
|
+
});
|
|
10872
|
+
recordCmd.command("stop").description("\u505C\u6B62\u5F55\u5236 \u2014 \u505C\u6B62\u5F53\u524D\u5F55\u5236\u5E76\u5199\u5165\u6587\u4EF6").action(() => {
|
|
10873
|
+
console.log("\u8BF7\u5728\u5F55\u5236\u7EC8\u7AEF\u6309 Ctrl+D \u505C\u6B62\u5F55\u5236");
|
|
10874
|
+
});
|
|
10875
|
+
}
|
|
10876
|
+
|
|
10877
|
+
// src/commands/doctor.ts
|
|
10878
|
+
var fs27 = __toESM(require("node:fs"));
|
|
10879
|
+
var path23 = __toESM(require("node:path"));
|
|
10513
10880
|
function getInstalledSkills(targetDir) {
|
|
10514
10881
|
const settingsPath = getDeepStormConfigPath(targetDir);
|
|
10515
10882
|
try {
|
|
10516
|
-
const settings = JSON.parse(
|
|
10883
|
+
const settings = JSON.parse(fs27.readFileSync(settingsPath, "utf-8"));
|
|
10517
10884
|
return settings.installedSkills || [];
|
|
10518
10885
|
} catch {
|
|
10519
10886
|
return [];
|
|
@@ -10530,7 +10897,7 @@ function runDoctor(targetDir) {
|
|
|
10530
10897
|
message: `v${version}\uFF08\u8FD0\u884C deepstorm update \u68C0\u67E5\u6700\u65B0\u7248\u672C\uFF09`
|
|
10531
10898
|
});
|
|
10532
10899
|
let hasDeepStorm = false;
|
|
10533
|
-
if (!
|
|
10900
|
+
if (!fs27.existsSync(settingsPath)) {
|
|
10534
10901
|
checks.push({
|
|
10535
10902
|
name: "\u914D\u7F6E\u6587\u4EF6",
|
|
10536
10903
|
status: "warn",
|
|
@@ -10538,7 +10905,7 @@ function runDoctor(targetDir) {
|
|
|
10538
10905
|
});
|
|
10539
10906
|
} else {
|
|
10540
10907
|
try {
|
|
10541
|
-
const config = JSON.parse(
|
|
10908
|
+
const config = JSON.parse(fs27.readFileSync(settingsPath, "utf-8"));
|
|
10542
10909
|
if (config && Object.keys(config).length > 0) {
|
|
10543
10910
|
hasDeepStorm = true;
|
|
10544
10911
|
checks.push({
|
|
@@ -10561,20 +10928,20 @@ function runDoctor(targetDir) {
|
|
|
10561
10928
|
});
|
|
10562
10929
|
}
|
|
10563
10930
|
}
|
|
10564
|
-
const skillsDir =
|
|
10565
|
-
if (
|
|
10566
|
-
const skillDirs =
|
|
10567
|
-
(n) =>
|
|
10931
|
+
const skillsDir = path23.join(targetDir, ".claude", "skills");
|
|
10932
|
+
if (fs27.existsSync(skillsDir)) {
|
|
10933
|
+
const skillDirs = fs27.readdirSync(skillsDir).filter(
|
|
10934
|
+
(n) => fs27.statSync(path23.join(skillsDir, n)).isDirectory()
|
|
10568
10935
|
);
|
|
10569
10936
|
let validCount = 0;
|
|
10570
10937
|
let invalidCount = 0;
|
|
10571
10938
|
for (const skillName of skillDirs) {
|
|
10572
|
-
const skillMd =
|
|
10573
|
-
if (!
|
|
10939
|
+
const skillMd = path23.join(skillsDir, skillName, "SKILL.md");
|
|
10940
|
+
if (!fs27.existsSync(skillMd)) {
|
|
10574
10941
|
invalidCount++;
|
|
10575
10942
|
continue;
|
|
10576
10943
|
}
|
|
10577
|
-
const content =
|
|
10944
|
+
const content = fs27.readFileSync(skillMd, "utf-8");
|
|
10578
10945
|
const frontmatter = parseFrontmatter(content);
|
|
10579
10946
|
if (frontmatter && frontmatter.name) {
|
|
10580
10947
|
validCount++;
|
|
@@ -10604,7 +10971,7 @@ function runDoctor(targetDir) {
|
|
|
10604
10971
|
const installedSkills = getInstalledSkills(targetDir);
|
|
10605
10972
|
const missingSkills = [];
|
|
10606
10973
|
for (const skillId of installedSkills) {
|
|
10607
|
-
if (!
|
|
10974
|
+
if (!fs27.existsSync(path23.join(skillsDir, skillId))) {
|
|
10608
10975
|
missingSkills.push(skillId);
|
|
10609
10976
|
}
|
|
10610
10977
|
}
|
|
@@ -10628,10 +10995,10 @@ function runDoctor(targetDir) {
|
|
|
10628
10995
|
message: ".claude/skills/ \u4E0D\u5B58\u5728"
|
|
10629
10996
|
});
|
|
10630
10997
|
}
|
|
10631
|
-
const mcpPath =
|
|
10632
|
-
if (
|
|
10998
|
+
const mcpPath = path23.join(targetDir, ".mcp.json");
|
|
10999
|
+
if (fs27.existsSync(mcpPath)) {
|
|
10633
11000
|
try {
|
|
10634
|
-
const mcp = JSON.parse(
|
|
11001
|
+
const mcp = JSON.parse(fs27.readFileSync(mcpPath, "utf-8"));
|
|
10635
11002
|
const hasServers = mcp.mcpServers && Object.keys(mcp.mcpServers).length > 0;
|
|
10636
11003
|
checks.push({
|
|
10637
11004
|
name: "MCP \u670D\u52A1\u5668",
|
|
@@ -10652,12 +11019,12 @@ function runDoctor(targetDir) {
|
|
|
10652
11019
|
message: ".mcp.json \u4E0D\u5B58\u5728"
|
|
10653
11020
|
});
|
|
10654
11021
|
}
|
|
10655
|
-
if (hasDeepStorm &&
|
|
11022
|
+
if (hasDeepStorm && fs27.existsSync(settingsPath)) {
|
|
10656
11023
|
try {
|
|
10657
|
-
const config = JSON.parse(
|
|
11024
|
+
const config = JSON.parse(fs27.readFileSync(settingsPath, "utf-8"));
|
|
10658
11025
|
const installedMcp = config.installedMcpServers;
|
|
10659
11026
|
if (installedMcp && installedMcp.length > 0) {
|
|
10660
|
-
const mcpExists =
|
|
11027
|
+
const mcpExists = fs27.existsSync(mcpPath);
|
|
10661
11028
|
if (!mcpExists) {
|
|
10662
11029
|
checks.push({
|
|
10663
11030
|
name: "MCP \u4E00\u81F4\u6027",
|
|
@@ -10666,7 +11033,7 @@ function runDoctor(targetDir) {
|
|
|
10666
11033
|
});
|
|
10667
11034
|
} else {
|
|
10668
11035
|
try {
|
|
10669
|
-
const mcpConfig = JSON.parse(
|
|
11036
|
+
const mcpConfig = JSON.parse(fs27.readFileSync(mcpPath, "utf-8"));
|
|
10670
11037
|
const servers = mcpConfig.mcpServers || {};
|
|
10671
11038
|
const missing = [];
|
|
10672
11039
|
for (const toolName of installedMcp) {
|
|
@@ -10694,9 +11061,9 @@ function runDoctor(targetDir) {
|
|
|
10694
11061
|
} catch {
|
|
10695
11062
|
}
|
|
10696
11063
|
}
|
|
10697
|
-
if (hasDeepStorm &&
|
|
11064
|
+
if (hasDeepStorm && fs27.existsSync(settingsPath)) {
|
|
10698
11065
|
try {
|
|
10699
|
-
const config = JSON.parse(
|
|
11066
|
+
const config = JSON.parse(fs27.readFileSync(settingsPath, "utf-8"));
|
|
10700
11067
|
const validKeys = loadValidConfigKeys();
|
|
10701
11068
|
if (validKeys.size > 0 && config) {
|
|
10702
11069
|
const configKeys = [];
|
|
@@ -10749,18 +11116,18 @@ function printDoctorReport(report) {
|
|
|
10749
11116
|
}
|
|
10750
11117
|
|
|
10751
11118
|
// src/commands/uninstall.ts
|
|
10752
|
-
var
|
|
10753
|
-
var
|
|
11119
|
+
var fs28 = __toESM(require("node:fs"));
|
|
11120
|
+
var path24 = __toESM(require("node:path"));
|
|
10754
11121
|
var import_prompts4 = require("@clack/prompts");
|
|
10755
11122
|
async function uninstallDeepStorm(targetDir) {
|
|
10756
11123
|
const settingsPath = getDeepStormConfigPath(targetDir);
|
|
10757
|
-
if (!
|
|
11124
|
+
if (!fs28.existsSync(settingsPath)) {
|
|
10758
11125
|
console.log("DeepStorm \u5C1A\u672A\u914D\u7F6E\uFF0C\u65E0\u9700\u5378\u8F7D");
|
|
10759
11126
|
return;
|
|
10760
11127
|
}
|
|
10761
11128
|
let hasDeepStorm = false;
|
|
10762
11129
|
try {
|
|
10763
|
-
const settings = JSON.parse(
|
|
11130
|
+
const settings = JSON.parse(fs28.readFileSync(settingsPath, "utf-8"));
|
|
10764
11131
|
hasDeepStorm = !!settings && Object.keys(settings).length > 0;
|
|
10765
11132
|
} catch {
|
|
10766
11133
|
}
|
|
@@ -10770,14 +11137,14 @@ async function uninstallDeepStorm(targetDir) {
|
|
|
10770
11137
|
}
|
|
10771
11138
|
cleanInstalled(targetDir);
|
|
10772
11139
|
resetConfig(targetDir);
|
|
10773
|
-
const templatesDir =
|
|
10774
|
-
if (
|
|
11140
|
+
const templatesDir = path24.join(targetDir, ".deepstorm", "templates");
|
|
11141
|
+
if (fs28.existsSync(templatesDir)) {
|
|
10775
11142
|
const shouldDelete = await (0, import_prompts4.confirm)({
|
|
10776
11143
|
message: "\u662F\u5426\u5220\u9664 .deepstorm/templates/ \u76EE\u5F55\uFF1F",
|
|
10777
11144
|
initialValue: false
|
|
10778
11145
|
});
|
|
10779
11146
|
if (shouldDelete) {
|
|
10780
|
-
|
|
11147
|
+
fs28.rmSync(templatesDir, { recursive: true, force: true });
|
|
10781
11148
|
console.log("\u2714 .deepstorm/templates/ \u5DF2\u5220\u9664");
|
|
10782
11149
|
} else {
|
|
10783
11150
|
console.log("\u4FDD\u7559 .deepstorm/templates/");
|
|
@@ -10790,9 +11157,9 @@ async function uninstallDeepStorm(targetDir) {
|
|
|
10790
11157
|
var program = new import_commander.Command();
|
|
10791
11158
|
program.name("deepstorm").description("DeepStorm CLI \u2014 \u4E00\u952E\u914D\u7F6E\u9879\u76EE\u5F00\u53D1\u73AF\u5883").version(getCliVersion(), "-v, --version", "\u8F93\u51FA\u7248\u672C\u53F7");
|
|
10792
11159
|
function loadRegistry() {
|
|
10793
|
-
const registryPath =
|
|
11160
|
+
const registryPath = path25.join(__dirname, "registry.json");
|
|
10794
11161
|
try {
|
|
10795
|
-
const raw =
|
|
11162
|
+
const raw = fs29.readFileSync(registryPath, "utf-8");
|
|
10796
11163
|
return JSON.parse(raw);
|
|
10797
11164
|
} catch {
|
|
10798
11165
|
return { version: "1", tools: {}, wizards: {}, skills: {} };
|
|
@@ -10806,6 +11173,7 @@ registerConfigCommand(program, registry);
|
|
|
10806
11173
|
registerTemplateCommand(program, registry);
|
|
10807
11174
|
registerUpdateCommand(program);
|
|
10808
11175
|
registerPilotCommands(program);
|
|
11176
|
+
registerRecordCommand(program);
|
|
10809
11177
|
program.command("doctor").description("\u8BCA\u65AD\u9879\u76EE DeepStorm \u914D\u7F6E\u72B6\u6001").action(() => {
|
|
10810
11178
|
const report = runDoctor(process.cwd());
|
|
10811
11179
|
printDoctorReport(report);
|