staklink 0.3.54 → 0.3.55
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/proxy-server.cjs +210 -58
- package/dist/staklink-cli.cjs +1 -1
- package/package.json +1 -1
package/dist/proxy-server.cjs
CHANGED
|
@@ -1289,8 +1289,8 @@ var require_node = __commonJS({
|
|
|
1289
1289
|
}
|
|
1290
1290
|
break;
|
|
1291
1291
|
case "FILE":
|
|
1292
|
-
var
|
|
1293
|
-
stream3 = new
|
|
1292
|
+
var fs13 = require("fs");
|
|
1293
|
+
stream3 = new fs13.SyncWriteStream(fd2, { autoClose: false });
|
|
1294
1294
|
stream3._type = "fs";
|
|
1295
1295
|
break;
|
|
1296
1296
|
case "PIPE":
|
|
@@ -17508,8 +17508,8 @@ var require_node2 = __commonJS({
|
|
|
17508
17508
|
}
|
|
17509
17509
|
break;
|
|
17510
17510
|
case "FILE":
|
|
17511
|
-
var
|
|
17512
|
-
stream3 = new
|
|
17511
|
+
var fs13 = require("fs");
|
|
17512
|
+
stream3 = new fs13.SyncWriteStream(fd2, { autoClose: false });
|
|
17513
17513
|
stream3._type = "fs";
|
|
17514
17514
|
break;
|
|
17515
17515
|
case "PIPE":
|
|
@@ -18227,8 +18227,8 @@ var require_node3 = __commonJS({
|
|
|
18227
18227
|
}
|
|
18228
18228
|
break;
|
|
18229
18229
|
case "FILE":
|
|
18230
|
-
var
|
|
18231
|
-
stream3 = new
|
|
18230
|
+
var fs13 = require("fs");
|
|
18231
|
+
stream3 = new fs13.SyncWriteStream(fd2, { autoClose: false });
|
|
18232
18232
|
stream3._type = "fs";
|
|
18233
18233
|
break;
|
|
18234
18234
|
case "PIPE":
|
|
@@ -19120,7 +19120,7 @@ var require_view = __commonJS({
|
|
|
19120
19120
|
"use strict";
|
|
19121
19121
|
var debug = require_src3()("express:view");
|
|
19122
19122
|
var path11 = require("path");
|
|
19123
|
-
var
|
|
19123
|
+
var fs13 = require("fs");
|
|
19124
19124
|
var dirname2 = path11.dirname;
|
|
19125
19125
|
var basename2 = path11.basename;
|
|
19126
19126
|
var extname = path11.extname;
|
|
@@ -19186,7 +19186,7 @@ var require_view = __commonJS({
|
|
|
19186
19186
|
function tryStat(path12) {
|
|
19187
19187
|
debug('stat "%s"', path12);
|
|
19188
19188
|
try {
|
|
19189
|
-
return
|
|
19189
|
+
return fs13.statSync(path12);
|
|
19190
19190
|
} catch (e) {
|
|
19191
19191
|
return void 0;
|
|
19192
19192
|
}
|
|
@@ -19791,8 +19791,8 @@ var require_node4 = __commonJS({
|
|
|
19791
19791
|
}
|
|
19792
19792
|
break;
|
|
19793
19793
|
case "FILE":
|
|
19794
|
-
var
|
|
19795
|
-
stream3 = new
|
|
19794
|
+
var fs13 = require("fs");
|
|
19795
|
+
stream3 = new fs13.SyncWriteStream(fd2, { autoClose: false });
|
|
19796
19796
|
stream3._type = "fs";
|
|
19797
19797
|
break;
|
|
19798
19798
|
case "PIPE":
|
|
@@ -19979,7 +19979,7 @@ var require_types = __commonJS({
|
|
|
19979
19979
|
var require_mime = __commonJS({
|
|
19980
19980
|
"node_modules/mime/mime.js"(exports2, module2) {
|
|
19981
19981
|
var path11 = require("path");
|
|
19982
|
-
var
|
|
19982
|
+
var fs13 = require("fs");
|
|
19983
19983
|
function Mime() {
|
|
19984
19984
|
this.types = /* @__PURE__ */ Object.create(null);
|
|
19985
19985
|
this.extensions = /* @__PURE__ */ Object.create(null);
|
|
@@ -20000,7 +20000,7 @@ var require_mime = __commonJS({
|
|
|
20000
20000
|
};
|
|
20001
20001
|
Mime.prototype.load = function(file3) {
|
|
20002
20002
|
this._loading = file3;
|
|
20003
|
-
var map3 = {}, content =
|
|
20003
|
+
var map3 = {}, content = fs13.readFileSync(file3, "ascii"), lines = content.split(/[\r\n]+/);
|
|
20004
20004
|
lines.forEach(function(line) {
|
|
20005
20005
|
var fields = line.replace(/\s*#.*|^\s*|\s*$/g, "").split(/\s+/);
|
|
20006
20006
|
map3[fields.shift()] = fields;
|
|
@@ -20238,7 +20238,7 @@ var require_send = __commonJS({
|
|
|
20238
20238
|
var escapeHtml = require_escape_html();
|
|
20239
20239
|
var etag = require_etag();
|
|
20240
20240
|
var fresh = require_fresh();
|
|
20241
|
-
var
|
|
20241
|
+
var fs13 = require("fs");
|
|
20242
20242
|
var mime = require_mime();
|
|
20243
20243
|
var ms = require_ms5();
|
|
20244
20244
|
var onFinished = require_on_finished();
|
|
@@ -20571,7 +20571,7 @@ var require_send = __commonJS({
|
|
|
20571
20571
|
var i = 0;
|
|
20572
20572
|
var self = this;
|
|
20573
20573
|
debug('stat "%s"', path12);
|
|
20574
|
-
|
|
20574
|
+
fs13.stat(path12, function onstat(err, stat4) {
|
|
20575
20575
|
if (err && err.code === "ENOENT" && !extname(path12) && path12[path12.length - 1] !== sep2) {
|
|
20576
20576
|
return next(err);
|
|
20577
20577
|
}
|
|
@@ -20586,7 +20586,7 @@ var require_send = __commonJS({
|
|
|
20586
20586
|
}
|
|
20587
20587
|
var p = path12 + "." + self._extensions[i++];
|
|
20588
20588
|
debug('stat "%s"', p);
|
|
20589
|
-
|
|
20589
|
+
fs13.stat(p, function(err2, stat4) {
|
|
20590
20590
|
if (err2) return next(err2);
|
|
20591
20591
|
if (stat4.isDirectory()) return next();
|
|
20592
20592
|
self.emit("file", p, stat4);
|
|
@@ -20604,7 +20604,7 @@ var require_send = __commonJS({
|
|
|
20604
20604
|
}
|
|
20605
20605
|
var p = join7(path12, self._index[i]);
|
|
20606
20606
|
debug('stat "%s"', p);
|
|
20607
|
-
|
|
20607
|
+
fs13.stat(p, function(err2, stat4) {
|
|
20608
20608
|
if (err2) return next(err2);
|
|
20609
20609
|
if (stat4.isDirectory()) return next();
|
|
20610
20610
|
self.emit("file", p, stat4);
|
|
@@ -20616,7 +20616,7 @@ var require_send = __commonJS({
|
|
|
20616
20616
|
SendStream.prototype.stream = function stream2(path12, options) {
|
|
20617
20617
|
var self = this;
|
|
20618
20618
|
var res = this.res;
|
|
20619
|
-
var stream3 =
|
|
20619
|
+
var stream3 = fs13.createReadStream(path12, options);
|
|
20620
20620
|
this.emit("stream", stream3);
|
|
20621
20621
|
stream3.pipe(res);
|
|
20622
20622
|
function cleanup() {
|
|
@@ -24146,7 +24146,7 @@ var require_token_util = __commonJS({
|
|
|
24146
24146
|
});
|
|
24147
24147
|
module2.exports = __toCommonJS(token_util_exports);
|
|
24148
24148
|
var path11 = __toESM2(require("path"));
|
|
24149
|
-
var
|
|
24149
|
+
var fs13 = __toESM2(require("fs"));
|
|
24150
24150
|
var import_token_error = require_token_error();
|
|
24151
24151
|
var import_token_io = require_token_io();
|
|
24152
24152
|
function getVercelDataDir() {
|
|
@@ -24163,10 +24163,10 @@ var require_token_util = __commonJS({
|
|
|
24163
24163
|
return null;
|
|
24164
24164
|
}
|
|
24165
24165
|
const tokenPath = path11.join(dataDir, "auth.json");
|
|
24166
|
-
if (!
|
|
24166
|
+
if (!fs13.existsSync(tokenPath)) {
|
|
24167
24167
|
return null;
|
|
24168
24168
|
}
|
|
24169
|
-
const token =
|
|
24169
|
+
const token = fs13.readFileSync(tokenPath, "utf8");
|
|
24170
24170
|
if (!token) {
|
|
24171
24171
|
return null;
|
|
24172
24172
|
}
|
|
@@ -24208,10 +24208,10 @@ var require_token_util = __commonJS({
|
|
|
24208
24208
|
}
|
|
24209
24209
|
try {
|
|
24210
24210
|
const prjPath = path11.join(dir, ".vercel", "project.json");
|
|
24211
|
-
if (!
|
|
24211
|
+
if (!fs13.existsSync(prjPath)) {
|
|
24212
24212
|
throw new import_token_error.VercelOidcTokenError("project.json not found");
|
|
24213
24213
|
}
|
|
24214
|
-
const prj = JSON.parse(
|
|
24214
|
+
const prj = JSON.parse(fs13.readFileSync(prjPath, "utf8"));
|
|
24215
24215
|
if (typeof prj.projectId !== "string" && typeof prj.orgId !== "string") {
|
|
24216
24216
|
throw new TypeError("Expected a string-valued projectId property");
|
|
24217
24217
|
}
|
|
@@ -24228,9 +24228,9 @@ var require_token_util = __commonJS({
|
|
|
24228
24228
|
}
|
|
24229
24229
|
const tokenPath = path11.join(dir, "com.vercel.token", `${projectId}.json`);
|
|
24230
24230
|
const tokenJson = JSON.stringify(token);
|
|
24231
|
-
|
|
24232
|
-
|
|
24233
|
-
|
|
24231
|
+
fs13.mkdirSync(path11.dirname(tokenPath), { mode: 504, recursive: true });
|
|
24232
|
+
fs13.writeFileSync(tokenPath, tokenJson);
|
|
24233
|
+
fs13.chmodSync(tokenPath, 432);
|
|
24234
24234
|
return;
|
|
24235
24235
|
} catch (e) {
|
|
24236
24236
|
throw new import_token_error.VercelOidcTokenError(`Failed to save token`, e);
|
|
@@ -24243,10 +24243,10 @@ var require_token_util = __commonJS({
|
|
|
24243
24243
|
return null;
|
|
24244
24244
|
}
|
|
24245
24245
|
const tokenPath = path11.join(dir, "com.vercel.token", `${projectId}.json`);
|
|
24246
|
-
if (!
|
|
24246
|
+
if (!fs13.existsSync(tokenPath)) {
|
|
24247
24247
|
return null;
|
|
24248
24248
|
}
|
|
24249
|
-
const token = JSON.parse(
|
|
24249
|
+
const token = JSON.parse(fs13.readFileSync(tokenPath, "utf8"));
|
|
24250
24250
|
assertVercelOidcTokenResponse(token);
|
|
24251
24251
|
return token;
|
|
24252
24252
|
} catch (e) {
|
|
@@ -38067,7 +38067,7 @@ var require_snapshot_utils = __commonJS({
|
|
|
38067
38067
|
var require_snapshot_recorder = __commonJS({
|
|
38068
38068
|
"node_modules/undici/lib/mock/snapshot-recorder.js"(exports2, module2) {
|
|
38069
38069
|
"use strict";
|
|
38070
|
-
var { writeFile: writeFile3, readFile:
|
|
38070
|
+
var { writeFile: writeFile3, readFile: readFile6, mkdir: mkdir2 } = require("node:fs/promises");
|
|
38071
38071
|
var { dirname: dirname2, resolve: resolve3 } = require("node:path");
|
|
38072
38072
|
var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = require("node:timers");
|
|
38073
38073
|
var { InvalidArgumentError: InvalidArgumentError5, UndiciError } = require_errors();
|
|
@@ -38262,7 +38262,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
38262
38262
|
throw new InvalidArgumentError5("Snapshot path is required");
|
|
38263
38263
|
}
|
|
38264
38264
|
try {
|
|
38265
|
-
const data = await
|
|
38265
|
+
const data = await readFile6(resolve3(path11), "utf8");
|
|
38266
38266
|
const parsed = JSON.parse(data);
|
|
38267
38267
|
if (Array.isArray(parsed)) {
|
|
38268
38268
|
this.#snapshots.clear();
|
|
@@ -54565,8 +54565,8 @@ var PathScurryBase = class {
|
|
|
54565
54565
|
*
|
|
54566
54566
|
* @internal
|
|
54567
54567
|
*/
|
|
54568
|
-
constructor(cwd = process.cwd(), pathImpl, sep2, { nocase, childrenCacheSize = 16 * 1024, fs:
|
|
54569
|
-
this.#fs = fsFromOption(
|
|
54568
|
+
constructor(cwd = process.cwd(), pathImpl, sep2, { nocase, childrenCacheSize = 16 * 1024, fs: fs13 = defaultFS } = {}) {
|
|
54569
|
+
this.#fs = fsFromOption(fs13);
|
|
54570
54570
|
if (cwd instanceof URL || cwd.startsWith("file://")) {
|
|
54571
54571
|
cwd = (0, import_node_url.fileURLToPath)(cwd);
|
|
54572
54572
|
}
|
|
@@ -55124,8 +55124,8 @@ var PathScurryWin32 = class extends PathScurryBase {
|
|
|
55124
55124
|
/**
|
|
55125
55125
|
* @internal
|
|
55126
55126
|
*/
|
|
55127
|
-
newRoot(
|
|
55128
|
-
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs:
|
|
55127
|
+
newRoot(fs13) {
|
|
55128
|
+
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs13 });
|
|
55129
55129
|
}
|
|
55130
55130
|
/**
|
|
55131
55131
|
* Return true if the provided path string is an absolute path
|
|
@@ -55153,8 +55153,8 @@ var PathScurryPosix = class extends PathScurryBase {
|
|
|
55153
55153
|
/**
|
|
55154
55154
|
* @internal
|
|
55155
55155
|
*/
|
|
55156
|
-
newRoot(
|
|
55157
|
-
return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs:
|
|
55156
|
+
newRoot(fs13) {
|
|
55157
|
+
return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs13 });
|
|
55158
55158
|
}
|
|
55159
55159
|
/**
|
|
55160
55160
|
* Return true if the provided path string is an absolute path
|
|
@@ -56958,7 +56958,7 @@ var SSEManager = class {
|
|
|
56958
56958
|
var sseManager = new SSEManager();
|
|
56959
56959
|
|
|
56960
56960
|
// src/proxy/version.ts
|
|
56961
|
-
var VERSION = "0.3.
|
|
56961
|
+
var VERSION = "0.3.55";
|
|
56962
56962
|
|
|
56963
56963
|
// node_modules/uuid/dist/esm/stringify.js
|
|
56964
56964
|
var byteToHex = [];
|
|
@@ -111260,6 +111260,77 @@ function chooseAgent(agentName) {
|
|
|
111260
111260
|
return agent;
|
|
111261
111261
|
}
|
|
111262
111262
|
|
|
111263
|
+
// src/agent/validate.ts
|
|
111264
|
+
var fs10 = __toESM(require("fs/promises"), 1);
|
|
111265
|
+
var SYSTEM2 = `You are a frontend validation expert. Your job is to analyze logs and a screenshot to determine if a frontend application is running correctly.
|
|
111266
|
+
|
|
111267
|
+
You will be provided with:
|
|
111268
|
+
1. PM2 process logs from all services
|
|
111269
|
+
2. A screenshot of the frontend application
|
|
111270
|
+
|
|
111271
|
+
Analyze both to determine if the frontend is working properly. Look for:
|
|
111272
|
+
- Error messages in logs
|
|
111273
|
+
- Failed dependencies or missing services
|
|
111274
|
+
- Whether the screenshot shows a properly loaded page or an error page
|
|
111275
|
+
- Any indication the service is not functioning correctly
|
|
111276
|
+
|
|
111277
|
+
Respond with either "<status>OK</status>" if everything looks good, or "<status>ERROR</status><message>Description of what's wrong</message>" if there are issues.`;
|
|
111278
|
+
var makeValidationPrompt = (logs) => {
|
|
111279
|
+
return `Please validate that the frontend service is running correctly.
|
|
111280
|
+
|
|
111281
|
+
Here are the logs from all PM2 services:
|
|
111282
|
+
|
|
111283
|
+
${logs}
|
|
111284
|
+
|
|
111285
|
+
Please analyze:
|
|
111286
|
+
1. The logs above to check for errors, warnings, or issues
|
|
111287
|
+
2. The screenshot I've attached to verify the page loaded correctly
|
|
111288
|
+
3. Determine if the service is healthy or if there are problems
|
|
111289
|
+
|
|
111290
|
+
Return your analysis in the XML format specified in the system prompt.`;
|
|
111291
|
+
};
|
|
111292
|
+
async function runValidation(screenshotPath, logs, apiKey) {
|
|
111293
|
+
const imageBuffer = await fs10.readFile(screenshotPath);
|
|
111294
|
+
const base64Image = imageBuffer.toString("base64");
|
|
111295
|
+
const systemMessage = {
|
|
111296
|
+
role: "system",
|
|
111297
|
+
content: SYSTEM2
|
|
111298
|
+
};
|
|
111299
|
+
const userMessage = {
|
|
111300
|
+
role: "user",
|
|
111301
|
+
content: [
|
|
111302
|
+
{
|
|
111303
|
+
type: "text",
|
|
111304
|
+
text: makeValidationPrompt(logs)
|
|
111305
|
+
},
|
|
111306
|
+
{
|
|
111307
|
+
type: "image",
|
|
111308
|
+
image: base64Image,
|
|
111309
|
+
mediaType: "image/png"
|
|
111310
|
+
}
|
|
111311
|
+
]
|
|
111312
|
+
};
|
|
111313
|
+
const messages = [systemMessage, userMessage];
|
|
111314
|
+
const res = await callModel({
|
|
111315
|
+
provider: "anthropic",
|
|
111316
|
+
apiKey,
|
|
111317
|
+
messages,
|
|
111318
|
+
thinkingSpeed: "fast"
|
|
111319
|
+
});
|
|
111320
|
+
return res.text;
|
|
111321
|
+
}
|
|
111322
|
+
var parseValidationResponse = (rawResponse) => {
|
|
111323
|
+
const statusMatch = rawResponse.match(/<status>(.*?)<\/status>/);
|
|
111324
|
+
const messageMatch = rawResponse.match(/<message>(.*?)<\/message>/s);
|
|
111325
|
+
const status = statusMatch ? statusMatch[1] : "UNKNOWN";
|
|
111326
|
+
const message = messageMatch ? messageMatch[1].trim() : "";
|
|
111327
|
+
return {
|
|
111328
|
+
status,
|
|
111329
|
+
message,
|
|
111330
|
+
ok: status === "OK"
|
|
111331
|
+
};
|
|
111332
|
+
};
|
|
111333
|
+
|
|
111263
111334
|
// src/proxy/server.ts
|
|
111264
111335
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
111265
111336
|
var import_path2 = __toESM(require("path"), 1);
|
|
@@ -111711,7 +111782,7 @@ Stderr: ${error86.stderr}`
|
|
|
111711
111782
|
};
|
|
111712
111783
|
|
|
111713
111784
|
// src/proxy/playwright.ts
|
|
111714
|
-
var
|
|
111785
|
+
var fs11 = __toESM(require("fs/promises"), 1);
|
|
111715
111786
|
var path9 = __toESM(require("path"), 1);
|
|
111716
111787
|
var DEFAULT_CONFIG = `import { defineConfig } from "@playwright/test";
|
|
111717
111788
|
export default defineConfig({
|
|
@@ -111911,7 +111982,7 @@ async function findRepositoryLocation(repoName) {
|
|
|
111911
111982
|
async function verifyTestFileExists(repoLocation, testFilePath) {
|
|
111912
111983
|
if (testFilePath.startsWith("/")) {
|
|
111913
111984
|
try {
|
|
111914
|
-
await
|
|
111985
|
+
await fs11.access(testFilePath);
|
|
111915
111986
|
return testFilePath;
|
|
111916
111987
|
} catch {
|
|
111917
111988
|
throw new Error(`Test file not found: ${testFilePath}`);
|
|
@@ -111919,7 +111990,7 @@ async function verifyTestFileExists(repoLocation, testFilePath) {
|
|
|
111919
111990
|
}
|
|
111920
111991
|
const testFullPath = path9.join(repoLocation, testFilePath);
|
|
111921
111992
|
try {
|
|
111922
|
-
await
|
|
111993
|
+
await fs11.access(testFullPath);
|
|
111923
111994
|
return testFullPath;
|
|
111924
111995
|
} catch {
|
|
111925
111996
|
throw new Error(`Test file not found: ${testFilePath}`);
|
|
@@ -111934,7 +112005,7 @@ async function findPlaywrightConfig(repoLocation) {
|
|
|
111934
112005
|
for (const configFile of configFiles) {
|
|
111935
112006
|
const fullConfigPath = path9.join(repoLocation, configFile);
|
|
111936
112007
|
try {
|
|
111937
|
-
await
|
|
112008
|
+
await fs11.access(fullConfigPath);
|
|
111938
112009
|
return fullConfigPath;
|
|
111939
112010
|
} catch {
|
|
111940
112011
|
}
|
|
@@ -111943,13 +112014,13 @@ async function findPlaywrightConfig(repoLocation) {
|
|
|
111943
112014
|
}
|
|
111944
112015
|
async function createPlaywrightConfig(repoLocation) {
|
|
111945
112016
|
const configPath = path9.join(repoLocation, "playwright.config.ts");
|
|
111946
|
-
await
|
|
112017
|
+
await fs11.writeFile(configPath, DEFAULT_CONFIG);
|
|
111947
112018
|
log(`Created playwright config at ${configPath}`);
|
|
111948
112019
|
return configPath;
|
|
111949
112020
|
}
|
|
111950
112021
|
async function createTimestampReporter(repoLocation) {
|
|
111951
112022
|
const reporterPath = path9.join(repoLocation, "timestamp-reporter.ts");
|
|
111952
|
-
await
|
|
112023
|
+
await fs11.writeFile(reporterPath, TIMESTAMP_REPORTER_CODE);
|
|
111953
112024
|
log(`Created timestamp reporter at ${reporterPath}`);
|
|
111954
112025
|
return reporterPath;
|
|
111955
112026
|
}
|
|
@@ -111964,7 +112035,7 @@ async function setupPlaywrightConfig(repoLocation) {
|
|
|
111964
112035
|
wasCreated = true;
|
|
111965
112036
|
log("Created new playwright config");
|
|
111966
112037
|
} else {
|
|
111967
|
-
originalContent = await
|
|
112038
|
+
originalContent = await fs11.readFile(configPath, "utf-8");
|
|
111968
112039
|
wasModified = true;
|
|
111969
112040
|
const newConfig = `import { defineConfig } from "@playwright/test";
|
|
111970
112041
|
|
|
@@ -111984,7 +112055,7 @@ export default defineConfig({
|
|
|
111984
112055
|
},
|
|
111985
112056
|
});
|
|
111986
112057
|
`;
|
|
111987
|
-
await
|
|
112058
|
+
await fs11.writeFile(configPath, newConfig);
|
|
111988
112059
|
log(
|
|
111989
112060
|
`Overwrote existing config at ${configPath} (backed up for cleanup)`
|
|
111990
112061
|
);
|
|
@@ -112002,7 +112073,7 @@ async function ensureTestResultsInGitignore(repoLocation) {
|
|
|
112002
112073
|
const gitignorePath = path9.join(repoLocation, ".gitignore");
|
|
112003
112074
|
const testResultsEntry = "test-results";
|
|
112004
112075
|
try {
|
|
112005
|
-
const gitignoreContent = await
|
|
112076
|
+
const gitignoreContent = await fs11.readFile(gitignorePath, "utf-8");
|
|
112006
112077
|
const lines = gitignoreContent.split("\n");
|
|
112007
112078
|
const hasTestResults = lines.some(
|
|
112008
112079
|
(line) => line.trim() === testResultsEntry
|
|
@@ -112015,10 +112086,10 @@ async function ensureTestResultsInGitignore(repoLocation) {
|
|
|
112015
112086
|
` : `${gitignoreContent}
|
|
112016
112087
|
${testResultsEntry}
|
|
112017
112088
|
`;
|
|
112018
|
-
await
|
|
112089
|
+
await fs11.writeFile(gitignorePath, updatedContent);
|
|
112019
112090
|
log("Added test-results to .gitignore");
|
|
112020
112091
|
} catch (error86) {
|
|
112021
|
-
await
|
|
112092
|
+
await fs11.writeFile(gitignorePath, `${testResultsEntry}
|
|
112022
112093
|
`);
|
|
112023
112094
|
log("Created .gitignore with test-results");
|
|
112024
112095
|
}
|
|
@@ -112043,10 +112114,10 @@ async function findVideoFile(repoLocation) {
|
|
|
112043
112114
|
const testResultsDir = path9.join(repoLocation, "test-results");
|
|
112044
112115
|
const walkDir = async (dir) => {
|
|
112045
112116
|
try {
|
|
112046
|
-
const files = await
|
|
112117
|
+
const files = await fs11.readdir(dir);
|
|
112047
112118
|
for (const file3 of files) {
|
|
112048
112119
|
const fullPath = path9.join(dir, file3);
|
|
112049
|
-
const stat4 = await
|
|
112120
|
+
const stat4 = await fs11.stat(fullPath);
|
|
112050
112121
|
if (stat4.isDirectory()) {
|
|
112051
112122
|
const result = await walkDir(fullPath);
|
|
112052
112123
|
if (result) {
|
|
@@ -112072,10 +112143,10 @@ async function findTimestampJsonFile(repoLocation) {
|
|
|
112072
112143
|
const testResultsDir = path9.join(repoLocation, "test-results");
|
|
112073
112144
|
const walkDir = async (dir) => {
|
|
112074
112145
|
try {
|
|
112075
|
-
const files = await
|
|
112146
|
+
const files = await fs11.readdir(dir);
|
|
112076
112147
|
for (const file3 of files) {
|
|
112077
112148
|
const fullPath = path9.join(dir, file3);
|
|
112078
|
-
const stat4 = await
|
|
112149
|
+
const stat4 = await fs11.stat(fullPath);
|
|
112079
112150
|
if (stat4.isDirectory()) {
|
|
112080
112151
|
const result = await walkDir(fullPath);
|
|
112081
112152
|
if (result) {
|
|
@@ -112098,9 +112169,9 @@ async function findTimestampJsonFile(repoLocation) {
|
|
|
112098
112169
|
return jsonPath;
|
|
112099
112170
|
}
|
|
112100
112171
|
async function uploadVideo(videoPath, timestampJsonPath, responseUrl, apiKey) {
|
|
112101
|
-
const videoBuffer = await
|
|
112172
|
+
const videoBuffer = await fs11.readFile(videoPath);
|
|
112102
112173
|
log(`Read video file: ${videoBuffer.length} bytes`);
|
|
112103
|
-
const jsonBuffer = await
|
|
112174
|
+
const jsonBuffer = await fs11.readFile(timestampJsonPath);
|
|
112104
112175
|
log(`Read timestamp JSON file: ${jsonBuffer.length} bytes`);
|
|
112105
112176
|
const { FormData: FormData2, fetch: undiciFetch } = await Promise.resolve().then(() => __toESM(require_undici(), 1));
|
|
112106
112177
|
const formData = new FormData2();
|
|
@@ -112135,13 +112206,13 @@ async function uploadVideo(videoPath, timestampJsonPath, responseUrl, apiKey) {
|
|
|
112135
112206
|
}
|
|
112136
112207
|
async function deleteTestFiles(videoPath, timestampJsonPath) {
|
|
112137
112208
|
try {
|
|
112138
|
-
await
|
|
112209
|
+
await fs11.unlink(videoPath);
|
|
112139
112210
|
log(`Deleted video file: ${videoPath}`);
|
|
112140
112211
|
} catch (error86) {
|
|
112141
112212
|
error(`Error deleting video file ${videoPath}:`, error86);
|
|
112142
112213
|
}
|
|
112143
112214
|
try {
|
|
112144
|
-
await
|
|
112215
|
+
await fs11.unlink(timestampJsonPath);
|
|
112145
112216
|
log(`Deleted timestamp JSON: ${timestampJsonPath}`);
|
|
112146
112217
|
} catch (error86) {
|
|
112147
112218
|
error(`Error deleting timestamp JSON ${timestampJsonPath}:`, error86);
|
|
@@ -112151,12 +112222,12 @@ async function cleanupConfig(configState) {
|
|
|
112151
112222
|
if (configState.configPath) {
|
|
112152
112223
|
try {
|
|
112153
112224
|
if (configState.wasCreated) {
|
|
112154
|
-
await
|
|
112225
|
+
await fs11.unlink(configState.configPath);
|
|
112155
112226
|
log(
|
|
112156
112227
|
`Cleaned up created config file: ${configState.configPath}`
|
|
112157
112228
|
);
|
|
112158
112229
|
} else if (configState.wasModified && configState.originalContent) {
|
|
112159
|
-
await
|
|
112230
|
+
await fs11.writeFile(configState.configPath, configState.originalContent);
|
|
112160
112231
|
log(`Restored original config: ${configState.configPath}`);
|
|
112161
112232
|
}
|
|
112162
112233
|
} catch (error86) {
|
|
@@ -112165,7 +112236,7 @@ async function cleanupConfig(configState) {
|
|
|
112165
112236
|
}
|
|
112166
112237
|
if (configState.reporterPath && configState.reporterWasCreated) {
|
|
112167
112238
|
try {
|
|
112168
|
-
await
|
|
112239
|
+
await fs11.unlink(configState.reporterPath);
|
|
112169
112240
|
log(`Cleaned up reporter file: ${configState.reporterPath}`);
|
|
112170
112241
|
} catch (error86) {
|
|
112171
112242
|
error("Error cleaning up reporter:", error86);
|
|
@@ -112221,6 +112292,35 @@ async function runPlaywrightTestWithVideo(options) {
|
|
|
112221
112292
|
}
|
|
112222
112293
|
}
|
|
112223
112294
|
|
|
112295
|
+
// src/proxy/screenshot.ts
|
|
112296
|
+
var import_playwright_core = require("playwright-core");
|
|
112297
|
+
async function takeScreenshot(port) {
|
|
112298
|
+
const browser = await import_playwright_core.chromium.launch({
|
|
112299
|
+
headless: true,
|
|
112300
|
+
args: ["--no-sandbox", "--disable-setuid-sandbox"]
|
|
112301
|
+
});
|
|
112302
|
+
try {
|
|
112303
|
+
const context = await browser.newContext();
|
|
112304
|
+
const page = await context.newPage();
|
|
112305
|
+
const url3 = `http://localhost:${port}`;
|
|
112306
|
+
log(`Navigating to ${url3} for screenshot`);
|
|
112307
|
+
await page.goto(url3, {
|
|
112308
|
+
waitUntil: "networkidle",
|
|
112309
|
+
timeout: 3e4
|
|
112310
|
+
});
|
|
112311
|
+
const timestamp = Date.now();
|
|
112312
|
+
const screenshotPath = `/tmp/staklink-validation-${timestamp}.png`;
|
|
112313
|
+
await page.screenshot({
|
|
112314
|
+
path: screenshotPath,
|
|
112315
|
+
fullPage: true
|
|
112316
|
+
});
|
|
112317
|
+
log(`Screenshot saved to ${screenshotPath}`);
|
|
112318
|
+
return screenshotPath;
|
|
112319
|
+
} finally {
|
|
112320
|
+
await browser.close();
|
|
112321
|
+
}
|
|
112322
|
+
}
|
|
112323
|
+
|
|
112224
112324
|
// src/proxy/server.ts
|
|
112225
112325
|
var PORT = parseInt(process.env.STAKLINK_PORT || "15552") || 15552;
|
|
112226
112326
|
var VSCODE_EXTENSION_URL = `http://localhost:${PORT + 1}`;
|
|
@@ -113193,6 +113293,58 @@ ${diff.trim()}`);
|
|
|
113193
113293
|
}
|
|
113194
113294
|
}
|
|
113195
113295
|
);
|
|
113296
|
+
app.post(
|
|
113297
|
+
"/validate_frontend",
|
|
113298
|
+
async (req, res) => {
|
|
113299
|
+
log("===> POST /validate_frontend");
|
|
113300
|
+
try {
|
|
113301
|
+
const workspaceRoot2 = await workspaceRoot();
|
|
113302
|
+
const config3 = await findAndLoadPm2Config(workspaceRoot2, log);
|
|
113303
|
+
const apiKey = req.body.apiKey;
|
|
113304
|
+
if (!apiKey) {
|
|
113305
|
+
throw new Error("apiKey is required");
|
|
113306
|
+
}
|
|
113307
|
+
const runner = new Runner(workspaceRoot2, log);
|
|
113308
|
+
const logsMap = {};
|
|
113309
|
+
for (const app2 of config3.apps) {
|
|
113310
|
+
try {
|
|
113311
|
+
const logs = await runner.getProcessLogs(app2.name, 100);
|
|
113312
|
+
logsMap[app2.name] = logs;
|
|
113313
|
+
} catch (error86) {
|
|
113314
|
+
error(`Failed to get logs for ${app2.name}:`, error86);
|
|
113315
|
+
logsMap[app2.name] = `ERROR: ${error86}`;
|
|
113316
|
+
}
|
|
113317
|
+
}
|
|
113318
|
+
let logsContent = "";
|
|
113319
|
+
for (const [appName, logs] of Object.entries(logsMap)) {
|
|
113320
|
+
logsContent += `
|
|
113321
|
+
========== ${appName} ==========
|
|
113322
|
+
${logs}
|
|
113323
|
+
`;
|
|
113324
|
+
}
|
|
113325
|
+
const frontendApp = config3.apps.find(
|
|
113326
|
+
(app2) => app2.env?.PORT || app2.name.toLowerCase().includes("frontend")
|
|
113327
|
+
);
|
|
113328
|
+
const port = frontendApp?.env?.PORT || "3000";
|
|
113329
|
+
const screenshotPath = await takeScreenshot(Number(port));
|
|
113330
|
+
log(`Screenshot saved to: ${screenshotPath}`);
|
|
113331
|
+
const result = await runValidation(
|
|
113332
|
+
screenshotPath,
|
|
113333
|
+
logsContent,
|
|
113334
|
+
apiKey
|
|
113335
|
+
);
|
|
113336
|
+
const validation = parseValidationResponse(result);
|
|
113337
|
+
try {
|
|
113338
|
+
} catch (error86) {
|
|
113339
|
+
warn("Failed to cleanup screenshot:", error86);
|
|
113340
|
+
}
|
|
113341
|
+
res.json({ success: true, ...validation });
|
|
113342
|
+
} catch (error86) {
|
|
113343
|
+
error("Error in validate_frontend:", error86);
|
|
113344
|
+
fail(res, error86);
|
|
113345
|
+
}
|
|
113346
|
+
}
|
|
113347
|
+
);
|
|
113196
113348
|
app.get("/leaks", async (req, res) => {
|
|
113197
113349
|
log(`===> GET /leaks`);
|
|
113198
113350
|
try {
|
package/dist/staklink-cli.cjs
CHANGED
|
@@ -10967,7 +10967,7 @@ var glob = Object.assign(glob_, {
|
|
|
10967
10967
|
glob.glob = glob;
|
|
10968
10968
|
|
|
10969
10969
|
// src/proxy/version.ts
|
|
10970
|
-
var VERSION = "0.3.
|
|
10970
|
+
var VERSION = "0.3.55";
|
|
10971
10971
|
|
|
10972
10972
|
// src/cli.ts
|
|
10973
10973
|
var STAKLINK_PROXY = "staklink-proxy";
|