@stackwright-pro/mcp 0.2.0-alpha.105 → 0.2.0-alpha.106
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/pipeline-constants.js +16 -1
- package/dist/pipeline-constants.js.map +1 -1
- package/dist/pipeline-constants.mjs +16 -1
- package/dist/pipeline-constants.mjs.map +1 -1
- package/dist/server.js +428 -213
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +370 -155
- package/dist/server.mjs.map +1 -1
- package/package.json +4 -4
package/dist/server.js
CHANGED
|
@@ -2023,9 +2023,9 @@ function registerOrchestrationTools(server2) {
|
|
|
2023
2023
|
|
|
2024
2024
|
// src/tools/pipeline.ts
|
|
2025
2025
|
var import_zod13 = require("zod");
|
|
2026
|
-
var
|
|
2026
|
+
var import_fs7 = require("fs");
|
|
2027
2027
|
var import_proper_lockfile = require("proper-lockfile");
|
|
2028
|
-
var
|
|
2028
|
+
var import_path7 = require("path");
|
|
2029
2029
|
var import_crypto3 = require("crypto");
|
|
2030
2030
|
|
|
2031
2031
|
// src/artifact-signing.ts
|
|
@@ -2350,6 +2350,208 @@ function registerArtifactSigningTools(server2) {
|
|
|
2350
2350
|
);
|
|
2351
2351
|
}
|
|
2352
2352
|
|
|
2353
|
+
// src/tools/validate-pulse-content.ts
|
|
2354
|
+
var import_js_yaml = require("js-yaml");
|
|
2355
|
+
var import_fs5 = require("fs");
|
|
2356
|
+
var import_path5 = require("path");
|
|
2357
|
+
var import_pulse = require("@stackwright-pro/pulse");
|
|
2358
|
+
function getAllowedProps(schema) {
|
|
2359
|
+
let inner = schema;
|
|
2360
|
+
while (inner && typeof inner.unwrap === "function") {
|
|
2361
|
+
inner = inner.unwrap();
|
|
2362
|
+
}
|
|
2363
|
+
if (inner && typeof inner === "object" && inner.shape && typeof inner.shape === "object") {
|
|
2364
|
+
return Object.keys(inner.shape);
|
|
2365
|
+
}
|
|
2366
|
+
return [];
|
|
2367
|
+
}
|
|
2368
|
+
var COLUMN_ALLOWED_PROPS = getAllowedProps(import_pulse.ColumnSchema);
|
|
2369
|
+
function walk(node, path5, relativeFilePath, violations, counter) {
|
|
2370
|
+
if (node === null || node === void 0 || typeof node !== "object") return;
|
|
2371
|
+
if (Array.isArray(node)) {
|
|
2372
|
+
for (let i = 0; i < node.length; i++) {
|
|
2373
|
+
walk(node[i], `${path5}[${i}]`, relativeFilePath, violations, counter);
|
|
2374
|
+
}
|
|
2375
|
+
return;
|
|
2376
|
+
}
|
|
2377
|
+
const obj = node;
|
|
2378
|
+
const contentType = typeof obj["type"] === "string" ? obj["type"] : null;
|
|
2379
|
+
if (contentType !== null && contentType in import_pulse.PULSE_CONTENT_SCHEMAS) {
|
|
2380
|
+
counter.checked++;
|
|
2381
|
+
const schema = import_pulse.PULSE_CONTENT_SCHEMAS[contentType];
|
|
2382
|
+
const result = schema.safeParse(obj);
|
|
2383
|
+
if (!result.success) {
|
|
2384
|
+
violations.push({
|
|
2385
|
+
file: relativeFilePath,
|
|
2386
|
+
yamlPath: path5,
|
|
2387
|
+
contentType,
|
|
2388
|
+
issues: result.error.issues.map((issue) => ({
|
|
2389
|
+
path: issue.path.map(String),
|
|
2390
|
+
message: issue.message
|
|
2391
|
+
})),
|
|
2392
|
+
emittedProps: Object.keys(obj).filter((k) => k !== "type"),
|
|
2393
|
+
allowedProps: getAllowedProps(schema),
|
|
2394
|
+
rawItem: obj
|
|
2395
|
+
});
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
for (const [key, child] of Object.entries(obj)) {
|
|
2399
|
+
walk(child, `${path5}.${key}`, relativeFilePath, violations, counter);
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
function findContentYamlFiles(dir) {
|
|
2403
|
+
const results = [];
|
|
2404
|
+
if (!(0, import_fs5.existsSync)(dir)) return results;
|
|
2405
|
+
for (const entry of (0, import_fs5.readdirSync)(dir)) {
|
|
2406
|
+
const fullPath = (0, import_path5.join)(dir, entry);
|
|
2407
|
+
const stat = (0, import_fs5.statSync)(fullPath);
|
|
2408
|
+
if (stat.isDirectory()) {
|
|
2409
|
+
results.push(...findContentYamlFiles(fullPath));
|
|
2410
|
+
} else if (entry === "content.yml") {
|
|
2411
|
+
results.push(fullPath);
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
return results;
|
|
2415
|
+
}
|
|
2416
|
+
function validatePulseContent(projectRoot) {
|
|
2417
|
+
const pagesDir = (0, import_path5.join)(projectRoot, "pages");
|
|
2418
|
+
const contentFiles = findContentYamlFiles(pagesDir);
|
|
2419
|
+
const violations = [];
|
|
2420
|
+
const counter = { checked: 0 };
|
|
2421
|
+
for (const absolutePath of contentFiles) {
|
|
2422
|
+
const relPath = (0, import_path5.relative)(projectRoot, absolutePath);
|
|
2423
|
+
let parsed;
|
|
2424
|
+
try {
|
|
2425
|
+
const raw = (0, import_fs5.readFileSync)(absolutePath, "utf-8");
|
|
2426
|
+
parsed = (0, import_js_yaml.load)(raw);
|
|
2427
|
+
} catch {
|
|
2428
|
+
continue;
|
|
2429
|
+
}
|
|
2430
|
+
walk(parsed, "content", relPath, violations, counter);
|
|
2431
|
+
}
|
|
2432
|
+
return {
|
|
2433
|
+
valid: violations.length === 0,
|
|
2434
|
+
filesScanned: contentFiles.length,
|
|
2435
|
+
itemsChecked: counter.checked,
|
|
2436
|
+
violations
|
|
2437
|
+
};
|
|
2438
|
+
}
|
|
2439
|
+
function unknownProps(violation) {
|
|
2440
|
+
const allowed = new Set(violation.allowedProps);
|
|
2441
|
+
return violation.emittedProps.filter((p) => !allowed.has(p));
|
|
2442
|
+
}
|
|
2443
|
+
function extractColumnViolations(violation) {
|
|
2444
|
+
if (violation.contentType !== "data_table_pulse") return [];
|
|
2445
|
+
const byColumn = /* @__PURE__ */ new Map();
|
|
2446
|
+
for (const issue of violation.issues) {
|
|
2447
|
+
if (issue.path[0] === "columns" && typeof issue.path[1] === "string") {
|
|
2448
|
+
const colIdx = parseInt(issue.path[1], 10);
|
|
2449
|
+
if (!isNaN(colIdx)) {
|
|
2450
|
+
const missing = issue.path[2] ?? issue.message;
|
|
2451
|
+
if (!byColumn.has(colIdx)) byColumn.set(colIdx, []);
|
|
2452
|
+
byColumn.get(colIdx).push(String(missing));
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
if (byColumn.size === 0) return [];
|
|
2457
|
+
const rawColumns = Array.isArray(violation.rawItem["columns"]) ? violation.rawItem["columns"] : [];
|
|
2458
|
+
const columnAllowed = new Set(COLUMN_ALLOWED_PROPS);
|
|
2459
|
+
const summaries = [];
|
|
2460
|
+
for (const [colIdx, missingProps] of byColumn.entries()) {
|
|
2461
|
+
const rawCol = rawColumns[colIdx] ?? {};
|
|
2462
|
+
const emitted = Object.keys(rawCol);
|
|
2463
|
+
const unknown = emitted.filter((p) => !columnAllowed.has(p));
|
|
2464
|
+
summaries.push({
|
|
2465
|
+
index: colIdx,
|
|
2466
|
+
emittedProps: emitted,
|
|
2467
|
+
unknownProps: unknown,
|
|
2468
|
+
missingProps: [...new Set(missingProps)]
|
|
2469
|
+
});
|
|
2470
|
+
}
|
|
2471
|
+
return summaries.sort((a, b) => a.index - b.index);
|
|
2472
|
+
}
|
|
2473
|
+
function swapSuggestion(unknownPropNames, missingPropNames, itemType) {
|
|
2474
|
+
if (unknownPropNames.length !== 1 || missingPropNames.length !== 1) return null;
|
|
2475
|
+
const level = itemType === "column" ? "column property" : "property";
|
|
2476
|
+
return ` Fix: rename ${level} \`${unknownPropNames[0]}\` \u2192 \`${missingPropNames[0]}\``;
|
|
2477
|
+
}
|
|
2478
|
+
function formatPulseRetryPrompt(result) {
|
|
2479
|
+
if (result.valid) return "";
|
|
2480
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
2481
|
+
for (const v of result.violations) {
|
|
2482
|
+
if (!byFile.has(v.file)) byFile.set(v.file, []);
|
|
2483
|
+
byFile.get(v.file).push(v);
|
|
2484
|
+
}
|
|
2485
|
+
const fileCount = byFile.size;
|
|
2486
|
+
const totalViolations = result.violations.length;
|
|
2487
|
+
const lines = [
|
|
2488
|
+
`Pulse schema validation failed: ${totalViolations} violation(s) across ${fileCount} content.yml file(s).`,
|
|
2489
|
+
"",
|
|
2490
|
+
"You MUST fix ALL violations and re-call stackwright_pro_validate_artifact.",
|
|
2491
|
+
'Do NOT invent new prop names. Only use props listed in "Schema allows".',
|
|
2492
|
+
""
|
|
2493
|
+
];
|
|
2494
|
+
for (const [file, violations] of byFile.entries()) {
|
|
2495
|
+
lines.push(`${file} \u2014 ${violations.length} violation(s):`);
|
|
2496
|
+
for (const v of violations) {
|
|
2497
|
+
lines.push(` ${v.yamlPath} (${v.contentType}):`);
|
|
2498
|
+
const unknown = unknownProps(v);
|
|
2499
|
+
const colViolations = extractColumnViolations(v);
|
|
2500
|
+
if (colViolations.length > 0) {
|
|
2501
|
+
for (const col of colViolations) {
|
|
2502
|
+
lines.push(` columns[${col.index}]:`);
|
|
2503
|
+
if (col.unknownProps.length > 0) {
|
|
2504
|
+
lines.push(
|
|
2505
|
+
` Unknown prop(s) used: ${col.unknownProps.map((p) => `\`${p}\``).join(", ")}`
|
|
2506
|
+
);
|
|
2507
|
+
}
|
|
2508
|
+
if (col.missingProps.length > 0) {
|
|
2509
|
+
lines.push(
|
|
2510
|
+
` Missing required prop(s): ${col.missingProps.map((p) => `\`${p}\``).join(", ")}`
|
|
2511
|
+
);
|
|
2512
|
+
}
|
|
2513
|
+
const suggestion = swapSuggestion(col.unknownProps, col.missingProps, "column");
|
|
2514
|
+
if (suggestion) lines.push(suggestion);
|
|
2515
|
+
}
|
|
2516
|
+
lines.push(
|
|
2517
|
+
` Schema allows ONLY these column props: ${COLUMN_ALLOWED_PROPS.join(", ")}.`
|
|
2518
|
+
);
|
|
2519
|
+
lines.push(
|
|
2520
|
+
` Do NOT use: \`label\` (use \`header\`), \`renderAs\` (use \`type\`), \`severityMap\` (use \`colorMap\`), \`width\` (not supported).`
|
|
2521
|
+
);
|
|
2522
|
+
} else if (unknown.length > 0 || v.issues.length > 0) {
|
|
2523
|
+
const missingFromIssues = v.issues.filter((i) => i.path.length === 1 && !i.path[0].match(/^\d+$/)).map((i) => i.path[0]).filter(Boolean);
|
|
2524
|
+
if (unknown.length > 0) {
|
|
2525
|
+
lines.push(` Unknown prop(s) used: ${unknown.map((p) => `\`${p}\``).join(", ")}`);
|
|
2526
|
+
}
|
|
2527
|
+
if (missingFromIssues.length > 0) {
|
|
2528
|
+
lines.push(
|
|
2529
|
+
` Missing required prop(s): ${[...new Set(missingFromIssues)].map((p) => `\`${p}\``).join(", ")}`
|
|
2530
|
+
);
|
|
2531
|
+
}
|
|
2532
|
+
const suggestion = swapSuggestion(unknown, [...new Set(missingFromIssues)], "top");
|
|
2533
|
+
if (suggestion) lines.push(suggestion);
|
|
2534
|
+
lines.push(` Schema allows ONLY these props: ${v.allowedProps.join(", ")}.`);
|
|
2535
|
+
if (v.contentType === "metric_card_pulse") {
|
|
2536
|
+
lines.push(
|
|
2537
|
+
` Do NOT use: \`valueField\`, \`valuePath\`, \`dataField\`, \`value\`. The correct prop is \`field\` (dot-path into the collection).`
|
|
2538
|
+
);
|
|
2539
|
+
}
|
|
2540
|
+
} else {
|
|
2541
|
+
for (const issue of v.issues) {
|
|
2542
|
+
lines.push(` ${issue.path.join(".")}: ${issue.message}`);
|
|
2543
|
+
}
|
|
2544
|
+
lines.push(` Schema allows ONLY these props: ${v.allowedProps.join(", ")}.`);
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
lines.push("");
|
|
2548
|
+
}
|
|
2549
|
+
lines.push(
|
|
2550
|
+
"After fixing ALL violations above, re-call stackwright_pro_validate_artifact with the corrected artifact."
|
|
2551
|
+
);
|
|
2552
|
+
return lines.join("\n");
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2353
2555
|
// src/tools/pipeline.ts
|
|
2354
2556
|
var import_types3 = require("@stackwright-pro/types");
|
|
2355
2557
|
|
|
@@ -2359,7 +2561,7 @@ var import_types2 = require("@stackwright-pro/types");
|
|
|
2359
2561
|
|
|
2360
2562
|
// src/tools/validate-yaml-fragment.ts
|
|
2361
2563
|
var import_zod11 = require("zod");
|
|
2362
|
-
var
|
|
2564
|
+
var import_js_yaml2 = require("js-yaml");
|
|
2363
2565
|
var import_types = require("@stackwright-pro/types");
|
|
2364
2566
|
var SUPPORTED_SCHEMA_NAMES = [
|
|
2365
2567
|
"workflow_step",
|
|
@@ -2461,7 +2663,7 @@ function handleValidateYamlFragment(input) {
|
|
|
2461
2663
|
const name = schemaName;
|
|
2462
2664
|
let parsed;
|
|
2463
2665
|
try {
|
|
2464
|
-
parsed = (0,
|
|
2666
|
+
parsed = (0, import_js_yaml2.load)(yaml3);
|
|
2465
2667
|
} catch (err) {
|
|
2466
2668
|
return {
|
|
2467
2669
|
valid: false,
|
|
@@ -2688,8 +2890,8 @@ function registerGetSchemaTool(server2) {
|
|
|
2688
2890
|
}
|
|
2689
2891
|
|
|
2690
2892
|
// src/tools/pipeline-graph.ts
|
|
2691
|
-
var
|
|
2692
|
-
var
|
|
2893
|
+
var import_fs6 = require("fs");
|
|
2894
|
+
var import_path6 = require("path");
|
|
2693
2895
|
var MANIFEST_NAME_TO_PHASE = {
|
|
2694
2896
|
"stackwright-pro-designer-otter": "designer",
|
|
2695
2897
|
"stackwright-pro-theme-otter": "theme",
|
|
@@ -2718,10 +2920,10 @@ var OTTER_SEARCH_PATHS = [
|
|
|
2718
2920
|
];
|
|
2719
2921
|
function resolveOtterDirFromCwd() {
|
|
2720
2922
|
const cwd = process.cwd();
|
|
2721
|
-
for (const
|
|
2722
|
-
const candidate = (0,
|
|
2923
|
+
for (const relative2 of OTTER_SEARCH_PATHS) {
|
|
2924
|
+
const candidate = (0, import_path6.join)(cwd, relative2);
|
|
2723
2925
|
try {
|
|
2724
|
-
(0,
|
|
2926
|
+
(0, import_fs6.lstatSync)(candidate);
|
|
2725
2927
|
return candidate;
|
|
2726
2928
|
} catch {
|
|
2727
2929
|
}
|
|
@@ -2731,14 +2933,14 @@ function resolveOtterDirFromCwd() {
|
|
|
2731
2933
|
);
|
|
2732
2934
|
}
|
|
2733
2935
|
function loadOtterManifestsFromDir(otterDir) {
|
|
2734
|
-
const entries = (0,
|
|
2936
|
+
const entries = (0, import_fs6.readdirSync)(otterDir);
|
|
2735
2937
|
const manifests = [];
|
|
2736
2938
|
for (const filename of entries) {
|
|
2737
2939
|
if (!filename.endsWith("-otter.json")) continue;
|
|
2738
|
-
const filePath = (0,
|
|
2739
|
-
if ((0,
|
|
2940
|
+
const filePath = (0, import_path6.join)(otterDir, filename);
|
|
2941
|
+
if ((0, import_fs6.lstatSync)(filePath).isSymbolicLink()) continue;
|
|
2740
2942
|
try {
|
|
2741
|
-
const raw = (0,
|
|
2943
|
+
const raw = (0, import_fs6.readFileSync)(filePath, "utf-8");
|
|
2742
2944
|
const manifest = JSON.parse(raw);
|
|
2743
2945
|
manifests.push(manifest);
|
|
2744
2946
|
} catch (err) {
|
|
@@ -2843,19 +3045,19 @@ var DISTRIBUTED_NAMESPACES = ["@stackwright-pro", "@stackwright"];
|
|
|
2843
3045
|
function loadDistributedOtterManifests(cwd) {
|
|
2844
3046
|
const results = [];
|
|
2845
3047
|
for (const namespace of DISTRIBUTED_NAMESPACES) {
|
|
2846
|
-
const nsDir = (0,
|
|
3048
|
+
const nsDir = (0, import_path6.join)(cwd, "node_modules", namespace);
|
|
2847
3049
|
let pkgDirNames;
|
|
2848
3050
|
try {
|
|
2849
|
-
pkgDirNames = (0,
|
|
3051
|
+
pkgDirNames = (0, import_fs6.readdirSync)(nsDir);
|
|
2850
3052
|
} catch {
|
|
2851
3053
|
continue;
|
|
2852
3054
|
}
|
|
2853
3055
|
for (const pkgDirName of pkgDirNames) {
|
|
2854
|
-
const pkgDir = (0,
|
|
3056
|
+
const pkgDir = (0, import_path6.join)(nsDir, pkgDirName);
|
|
2855
3057
|
const packageName = `${namespace}/${pkgDirName}`;
|
|
2856
3058
|
let otterRelPaths;
|
|
2857
3059
|
try {
|
|
2858
|
-
const raw = (0,
|
|
3060
|
+
const raw = (0, import_fs6.readFileSync)((0, import_path6.join)(pkgDir, "package.json"), "utf-8");
|
|
2859
3061
|
const pkgJson = JSON.parse(raw);
|
|
2860
3062
|
const declared = pkgJson.stackwright?.otters;
|
|
2861
3063
|
if (!Array.isArray(declared) || declared.length === 0) continue;
|
|
@@ -2864,9 +3066,9 @@ function loadDistributedOtterManifests(cwd) {
|
|
|
2864
3066
|
continue;
|
|
2865
3067
|
}
|
|
2866
3068
|
for (const relPath of otterRelPaths) {
|
|
2867
|
-
const otterFilePath = (0,
|
|
3069
|
+
const otterFilePath = (0, import_path6.join)(pkgDir, relPath);
|
|
2868
3070
|
try {
|
|
2869
|
-
const raw = (0,
|
|
3071
|
+
const raw = (0, import_fs6.readFileSync)(otterFilePath, "utf-8");
|
|
2870
3072
|
const manifest = JSON.parse(raw);
|
|
2871
3073
|
results.push({ manifest, packageName });
|
|
2872
3074
|
} catch (err) {
|
|
@@ -2907,6 +3109,7 @@ function loadPipelineGraph() {
|
|
|
2907
3109
|
|
|
2908
3110
|
// src/tools/pipeline.ts
|
|
2909
3111
|
var import_telemetry = require("@stackwright-pro/telemetry");
|
|
3112
|
+
var PULSE_CONTENT_PHASES = /* @__PURE__ */ new Set(["pages", "dashboard", "geo", "workflow"]);
|
|
2910
3113
|
var PHASE_ORDER = [
|
|
2911
3114
|
"designer",
|
|
2912
3115
|
"theme",
|
|
@@ -2983,11 +3186,11 @@ function createDefaultState() {
|
|
|
2983
3186
|
};
|
|
2984
3187
|
}
|
|
2985
3188
|
function statePath(cwd) {
|
|
2986
|
-
return (0,
|
|
3189
|
+
return (0, import_path7.join)(cwd, ".stackwright", "pipeline-state.json");
|
|
2987
3190
|
}
|
|
2988
3191
|
function readState(cwd) {
|
|
2989
3192
|
const p = statePath(cwd);
|
|
2990
|
-
if (!(0,
|
|
3193
|
+
if (!(0, import_fs7.existsSync)(p)) return createDefaultState();
|
|
2991
3194
|
const raw = JSON.parse(safeReadSync(p));
|
|
2992
3195
|
if (typeof raw !== "object" || raw === null || raw.version !== "1.0") {
|
|
2993
3196
|
return createDefaultState();
|
|
@@ -2995,34 +3198,34 @@ function readState(cwd) {
|
|
|
2995
3198
|
return raw;
|
|
2996
3199
|
}
|
|
2997
3200
|
function safeWriteSync(filePath, content) {
|
|
2998
|
-
if ((0,
|
|
2999
|
-
const stat = (0,
|
|
3201
|
+
if ((0, import_fs7.existsSync)(filePath)) {
|
|
3202
|
+
const stat = (0, import_fs7.lstatSync)(filePath);
|
|
3000
3203
|
if (stat.isSymbolicLink()) {
|
|
3001
3204
|
throw new Error(`Refusing to write to symlink: ${filePath}`);
|
|
3002
3205
|
}
|
|
3003
3206
|
}
|
|
3004
|
-
(0,
|
|
3207
|
+
(0, import_fs7.writeFileSync)(filePath, content);
|
|
3005
3208
|
}
|
|
3006
3209
|
function safeReadSync(filePath) {
|
|
3007
|
-
if ((0,
|
|
3008
|
-
const stat = (0,
|
|
3210
|
+
if ((0, import_fs7.existsSync)(filePath)) {
|
|
3211
|
+
const stat = (0, import_fs7.lstatSync)(filePath);
|
|
3009
3212
|
if (stat.isSymbolicLink()) {
|
|
3010
3213
|
throw new Error(`Refusing to read symlink: ${filePath}`);
|
|
3011
3214
|
}
|
|
3012
3215
|
}
|
|
3013
|
-
return (0,
|
|
3216
|
+
return (0, import_fs7.readFileSync)(filePath, "utf-8");
|
|
3014
3217
|
}
|
|
3015
3218
|
function writeState(cwd, state) {
|
|
3016
|
-
const dir = (0,
|
|
3017
|
-
(0,
|
|
3219
|
+
const dir = (0, import_path7.join)(cwd, ".stackwright");
|
|
3220
|
+
(0, import_fs7.mkdirSync)(dir, { recursive: true });
|
|
3018
3221
|
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3019
3222
|
safeWriteSync(statePath(cwd), JSON.stringify(state, null, 2) + "\n");
|
|
3020
3223
|
}
|
|
3021
3224
|
function updateStateAtomic(cwd, mutator) {
|
|
3022
|
-
const dir = (0,
|
|
3023
|
-
(0,
|
|
3225
|
+
const dir = (0, import_path7.join)(cwd, ".stackwright");
|
|
3226
|
+
(0, import_fs7.mkdirSync)(dir, { recursive: true });
|
|
3024
3227
|
const path5 = statePath(cwd);
|
|
3025
|
-
if (!(0,
|
|
3228
|
+
if (!(0, import_fs7.existsSync)(path5)) {
|
|
3026
3229
|
safeWriteSync(path5, JSON.stringify(createDefaultState(), null, 2) + "\n");
|
|
3027
3230
|
}
|
|
3028
3231
|
const release = (0, import_proper_lockfile.lockSync)(path5, {
|
|
@@ -3056,8 +3259,8 @@ function handleGetPipelineState(_cwd) {
|
|
|
3056
3259
|
const cwd = _cwd ?? process.cwd();
|
|
3057
3260
|
try {
|
|
3058
3261
|
const state = readState(cwd);
|
|
3059
|
-
const keyPath = (0,
|
|
3060
|
-
if (!(0,
|
|
3262
|
+
const keyPath = (0, import_path7.join)(cwd, ".stackwright", "pipeline-keys.json");
|
|
3263
|
+
if (!(0, import_fs7.existsSync)(keyPath)) {
|
|
3061
3264
|
try {
|
|
3062
3265
|
const { fingerprint } = initPipelineKeys(cwd);
|
|
3063
3266
|
state["signingKeyFingerprint"] = fingerprint;
|
|
@@ -3188,8 +3391,8 @@ function handleCheckExecutionReady(_cwd, phase) {
|
|
|
3188
3391
|
isError: true
|
|
3189
3392
|
};
|
|
3190
3393
|
}
|
|
3191
|
-
const answerFile = (0,
|
|
3192
|
-
if (!(0,
|
|
3394
|
+
const answerFile = (0, import_path7.join)(cwd, ".stackwright", "answers", `${phase}.json`);
|
|
3395
|
+
if (!(0, import_fs7.existsSync)(answerFile)) {
|
|
3193
3396
|
return {
|
|
3194
3397
|
text: JSON.stringify({ ready: false, phase, reason: "Answer file not found" }),
|
|
3195
3398
|
isError: false
|
|
@@ -3213,12 +3416,12 @@ function handleCheckExecutionReady(_cwd, phase) {
|
|
|
3213
3416
|
}
|
|
3214
3417
|
}
|
|
3215
3418
|
try {
|
|
3216
|
-
const answersDir = (0,
|
|
3419
|
+
const answersDir = (0, import_path7.join)(cwd, ".stackwright", "answers");
|
|
3217
3420
|
const answeredPhases = [];
|
|
3218
3421
|
const missingPhases = [];
|
|
3219
3422
|
for (const phase2 of PHASE_ORDER) {
|
|
3220
|
-
const answerFile = (0,
|
|
3221
|
-
if ((0,
|
|
3423
|
+
const answerFile = (0, import_path7.join)(answersDir, `${phase2}.json`);
|
|
3424
|
+
if ((0, import_fs7.existsSync)(answerFile)) {
|
|
3222
3425
|
try {
|
|
3223
3426
|
const raw = safeReadSync(answerFile);
|
|
3224
3427
|
const parsed = JSON.parse(raw);
|
|
@@ -3287,7 +3490,7 @@ function handleGetReadyPhases(_cwd) {
|
|
|
3287
3490
|
function handleListArtifacts(_cwd) {
|
|
3288
3491
|
const cwd = _cwd ?? process.cwd();
|
|
3289
3492
|
try {
|
|
3290
|
-
const artifactsDir = (0,
|
|
3493
|
+
const artifactsDir = (0, import_path7.join)(cwd, ".stackwright", "artifacts");
|
|
3291
3494
|
let manifest = null;
|
|
3292
3495
|
try {
|
|
3293
3496
|
manifest = loadSignatureManifest(cwd);
|
|
@@ -3297,8 +3500,8 @@ function handleListArtifacts(_cwd) {
|
|
|
3297
3500
|
let completedCount = 0;
|
|
3298
3501
|
for (const phase of PHASE_ORDER) {
|
|
3299
3502
|
const expectedFile = PHASE_ARTIFACT[phase];
|
|
3300
|
-
const fullPath = (0,
|
|
3301
|
-
const exists = (0,
|
|
3503
|
+
const fullPath = (0, import_path7.join)(artifactsDir, expectedFile);
|
|
3504
|
+
const exists = (0, import_fs7.existsSync)(fullPath);
|
|
3302
3505
|
if (exists) completedCount++;
|
|
3303
3506
|
let signed = false;
|
|
3304
3507
|
let signatureValid = null;
|
|
@@ -3351,9 +3554,9 @@ function handleWritePhaseQuestions(input) {
|
|
|
3351
3554
|
}
|
|
3352
3555
|
} catch {
|
|
3353
3556
|
}
|
|
3354
|
-
const questionsDir = (0,
|
|
3355
|
-
(0,
|
|
3356
|
-
const filePath = (0,
|
|
3557
|
+
const questionsDir = (0, import_path7.join)(cwd, ".stackwright", "questions");
|
|
3558
|
+
(0, import_fs7.mkdirSync)(questionsDir, { recursive: true });
|
|
3559
|
+
const filePath = (0, import_path7.join)(questionsDir, `${phase}.json`);
|
|
3357
3560
|
const payload = {
|
|
3358
3561
|
version: "1.0",
|
|
3359
3562
|
phase,
|
|
@@ -3393,14 +3596,14 @@ function handleBuildSpecialistPrompt(input) {
|
|
|
3393
3596
|
};
|
|
3394
3597
|
}
|
|
3395
3598
|
try {
|
|
3396
|
-
const answersPath = (0,
|
|
3599
|
+
const answersPath = (0, import_path7.join)(cwd, ".stackwright", "answers", `${phase}.json`);
|
|
3397
3600
|
let answers = {};
|
|
3398
|
-
if ((0,
|
|
3601
|
+
if ((0, import_fs7.existsSync)(answersPath)) {
|
|
3399
3602
|
answers = JSON.parse(safeReadSync(answersPath));
|
|
3400
3603
|
}
|
|
3401
3604
|
let buildContextText = "";
|
|
3402
|
-
const buildContextPath = (0,
|
|
3403
|
-
if ((0,
|
|
3605
|
+
const buildContextPath = (0, import_path7.join)(cwd, ".stackwright", "build-context.json");
|
|
3606
|
+
if ((0, import_fs7.existsSync)(buildContextPath)) {
|
|
3404
3607
|
try {
|
|
3405
3608
|
const bcRaw = JSON.parse(safeReadSync(buildContextPath));
|
|
3406
3609
|
if (typeof bcRaw.buildContext === "string" && bcRaw.buildContext.trim().length > 0) {
|
|
@@ -3415,8 +3618,8 @@ function handleBuildSpecialistPrompt(input) {
|
|
|
3415
3618
|
const missingDependencies = [];
|
|
3416
3619
|
for (const dep of deps) {
|
|
3417
3620
|
const artifactFile = PHASE_ARTIFACT[dep];
|
|
3418
|
-
const artifactPath = (0,
|
|
3419
|
-
if ((0,
|
|
3621
|
+
const artifactPath = (0, import_path7.join)(cwd, ".stackwright", "artifacts", artifactFile);
|
|
3622
|
+
if ((0, import_fs7.existsSync)(artifactPath)) {
|
|
3420
3623
|
const rawContent = safeReadSync(artifactPath);
|
|
3421
3624
|
const rawBytes = Buffer.from(rawContent, "utf-8");
|
|
3422
3625
|
const content = JSON.parse(rawContent);
|
|
@@ -3481,8 +3684,8 @@ ${JSON.stringify(content, null, 2)}`
|
|
|
3481
3684
|
parts.push("BUILD_CONTEXT:", buildContextText, "");
|
|
3482
3685
|
}
|
|
3483
3686
|
if (phase === "auth") {
|
|
3484
|
-
const initContextPath = (0,
|
|
3485
|
-
if ((0,
|
|
3687
|
+
const initContextPath = (0, import_path7.join)(cwd, ".stackwright", "init-context.json");
|
|
3688
|
+
if ((0, import_fs7.existsSync)(initContextPath)) {
|
|
3486
3689
|
try {
|
|
3487
3690
|
const initContext = JSON.parse(safeReadSync(initContextPath));
|
|
3488
3691
|
if (initContext.devOnly === true || initContext.nonInteractive === true) {
|
|
@@ -3987,13 +4190,13 @@ function _validateArtifactInner(input) {
|
|
|
3987
4190
|
// to a flow or state-machine in this services-config artifact.
|
|
3988
4191
|
// Skips gracefully when wizard-otter didn't run (Pro-only install) or declared no hooks.
|
|
3989
4192
|
services: (artifact2) => {
|
|
3990
|
-
const workflowArtifactPath = (0,
|
|
3991
|
-
if (!(0,
|
|
4193
|
+
const workflowArtifactPath = (0, import_path7.join)(cwd, ".stackwright", "artifacts", "workflow-config.json");
|
|
4194
|
+
if (!(0, import_fs7.existsSync)(workflowArtifactPath)) {
|
|
3992
4195
|
return { success: true };
|
|
3993
4196
|
}
|
|
3994
4197
|
let workflowArtifact;
|
|
3995
4198
|
try {
|
|
3996
|
-
workflowArtifact = JSON.parse((0,
|
|
4199
|
+
workflowArtifact = JSON.parse((0, import_fs7.readFileSync)(workflowArtifactPath, "utf-8"));
|
|
3997
4200
|
} catch {
|
|
3998
4201
|
return { success: true };
|
|
3999
4202
|
}
|
|
@@ -4063,11 +4266,23 @@ function _validateArtifactInner(input) {
|
|
|
4063
4266
|
return { text: JSON.stringify(result), isError: false };
|
|
4064
4267
|
}
|
|
4065
4268
|
}
|
|
4269
|
+
if (PULSE_CONTENT_PHASES.has(phase)) {
|
|
4270
|
+
const pulseResult = validatePulseContent(cwd);
|
|
4271
|
+
if (!pulseResult.valid) {
|
|
4272
|
+
const result = {
|
|
4273
|
+
valid: false,
|
|
4274
|
+
phase,
|
|
4275
|
+
violation: "schema-mismatch",
|
|
4276
|
+
retryPrompt: formatPulseRetryPrompt(pulseResult)
|
|
4277
|
+
};
|
|
4278
|
+
return { text: JSON.stringify(result), isError: false };
|
|
4279
|
+
}
|
|
4280
|
+
}
|
|
4066
4281
|
try {
|
|
4067
|
-
const artifactsDir = (0,
|
|
4068
|
-
(0,
|
|
4282
|
+
const artifactsDir = (0, import_path7.join)(cwd, ".stackwright", "artifacts");
|
|
4283
|
+
(0, import_fs7.mkdirSync)(artifactsDir, { recursive: true });
|
|
4069
4284
|
const artifactFile = phase === "api" && input.integrationName ? `api-config-${input.integrationName}.json` : PHASE_ARTIFACT[phase];
|
|
4070
|
-
const artifactPath = (0,
|
|
4285
|
+
const artifactPath = (0, import_path7.join)(artifactsDir, artifactFile);
|
|
4071
4286
|
const serialized = JSON.stringify(artifact, null, 2) + "\n";
|
|
4072
4287
|
const artifactBytes = Buffer.from(serialized, "utf-8");
|
|
4073
4288
|
safeWriteSync(artifactPath, serialized);
|
|
@@ -4286,10 +4501,10 @@ function registerPipelineTools(server2) {
|
|
|
4286
4501
|
isError: true
|
|
4287
4502
|
};
|
|
4288
4503
|
}
|
|
4289
|
-
const questionsDir = (0,
|
|
4290
|
-
(0,
|
|
4291
|
-
const outPath = (0,
|
|
4292
|
-
(0,
|
|
4504
|
+
const questionsDir = (0, import_path7.join)(process.cwd(), ".stackwright", "questions");
|
|
4505
|
+
(0, import_fs7.mkdirSync)(questionsDir, { recursive: true });
|
|
4506
|
+
const outPath = (0, import_path7.join)(questionsDir, `${phase}.json`);
|
|
4507
|
+
(0, import_fs7.writeFileSync)(
|
|
4293
4508
|
outPath,
|
|
4294
4509
|
JSON.stringify({ phase, questions, writtenAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
|
|
4295
4510
|
);
|
|
@@ -4376,8 +4591,8 @@ function registerPipelineTools(server2) {
|
|
|
4376
4591
|
|
|
4377
4592
|
// src/tools/safe-write.ts
|
|
4378
4593
|
var import_zod14 = require("zod");
|
|
4379
|
-
var
|
|
4380
|
-
var
|
|
4594
|
+
var import_fs8 = require("fs");
|
|
4595
|
+
var import_path8 = require("path");
|
|
4381
4596
|
var import_telemetry2 = require("@stackwright-pro/telemetry");
|
|
4382
4597
|
var OTTER_WRITE_ALLOWLISTS = {
|
|
4383
4598
|
"stackwright-pro-designer-otter": [
|
|
@@ -4543,7 +4758,7 @@ function getMaxBytesForPath(filePath) {
|
|
|
4543
4758
|
}
|
|
4544
4759
|
var PAGE_REGISTRY_FILE = ".stackwright/page-registry.json";
|
|
4545
4760
|
function extractPageSlug(filePath) {
|
|
4546
|
-
const match = (0,
|
|
4761
|
+
const match = (0, import_path8.normalize)(filePath).match(/^pages\/(.+?)\/content\.ya?ml$/);
|
|
4547
4762
|
return match?.[1] ?? null;
|
|
4548
4763
|
}
|
|
4549
4764
|
function extractContentTypes(yamlContent) {
|
|
@@ -4559,27 +4774,27 @@ function extractContentTypes(yamlContent) {
|
|
|
4559
4774
|
return types.length > 0 ? types : ["unknown"];
|
|
4560
4775
|
}
|
|
4561
4776
|
function readPageRegistry(cwd) {
|
|
4562
|
-
const regPath = (0,
|
|
4563
|
-
if (!(0,
|
|
4777
|
+
const regPath = (0, import_path8.join)(cwd, PAGE_REGISTRY_FILE);
|
|
4778
|
+
if (!(0, import_fs8.existsSync)(regPath)) return {};
|
|
4564
4779
|
try {
|
|
4565
|
-
const stat = (0,
|
|
4780
|
+
const stat = (0, import_fs8.lstatSync)(regPath);
|
|
4566
4781
|
if (stat.isSymbolicLink()) return {};
|
|
4567
|
-
return JSON.parse((0,
|
|
4782
|
+
return JSON.parse((0, import_fs8.readFileSync)(regPath, "utf-8"));
|
|
4568
4783
|
} catch {
|
|
4569
4784
|
return {};
|
|
4570
4785
|
}
|
|
4571
4786
|
}
|
|
4572
4787
|
function writePageRegistry(cwd, registry) {
|
|
4573
|
-
const dir = (0,
|
|
4574
|
-
(0,
|
|
4575
|
-
const regPath = (0,
|
|
4576
|
-
if ((0,
|
|
4577
|
-
const stat = (0,
|
|
4788
|
+
const dir = (0, import_path8.join)(cwd, ".stackwright");
|
|
4789
|
+
(0, import_fs8.mkdirSync)(dir, { recursive: true });
|
|
4790
|
+
const regPath = (0, import_path8.join)(cwd, PAGE_REGISTRY_FILE);
|
|
4791
|
+
if ((0, import_fs8.existsSync)(regPath)) {
|
|
4792
|
+
const stat = (0, import_fs8.lstatSync)(regPath);
|
|
4578
4793
|
if (stat.isSymbolicLink()) {
|
|
4579
4794
|
throw new Error("Refusing to write page registry through symlink");
|
|
4580
4795
|
}
|
|
4581
4796
|
}
|
|
4582
|
-
(0,
|
|
4797
|
+
(0, import_fs8.writeFileSync)(regPath, JSON.stringify(registry, null, 2) + "\n", { encoding: "utf-8" });
|
|
4583
4798
|
}
|
|
4584
4799
|
function checkPageOwnership(cwd, slug, callerOtter) {
|
|
4585
4800
|
const registry = readPageRegistry(cwd);
|
|
@@ -4598,11 +4813,11 @@ function stripNextjsBracketSegments(path5) {
|
|
|
4598
4813
|
return path5.replace(NEXTJS_BRACKET_SEGMENT_RE, "");
|
|
4599
4814
|
}
|
|
4600
4815
|
function checkPathAllowed(callerOtter, filePath) {
|
|
4601
|
-
const normalized = (0,
|
|
4816
|
+
const normalized = (0, import_path8.normalize)(filePath);
|
|
4602
4817
|
if (stripNextjsBracketSegments(normalized).includes("..")) {
|
|
4603
4818
|
return { allowed: false, error: 'Path traversal detected: ".." segments are not allowed' };
|
|
4604
4819
|
}
|
|
4605
|
-
if ((0,
|
|
4820
|
+
if ((0, import_path8.isAbsolute)(normalized)) {
|
|
4606
4821
|
return {
|
|
4607
4822
|
allowed: false,
|
|
4608
4823
|
error: "Absolute paths are not allowed \u2014 use paths relative to project root"
|
|
@@ -4744,11 +4959,11 @@ function _safeWriteInner(input) {
|
|
|
4744
4959
|
};
|
|
4745
4960
|
return { text: JSON.stringify(result), isError: true };
|
|
4746
4961
|
}
|
|
4747
|
-
const normalized = (0,
|
|
4748
|
-
const fullPath = (0,
|
|
4749
|
-
if ((0,
|
|
4962
|
+
const normalized = (0, import_path8.normalize)(filePath);
|
|
4963
|
+
const fullPath = (0, import_path8.join)(cwd, normalized);
|
|
4964
|
+
if ((0, import_fs8.existsSync)(fullPath)) {
|
|
4750
4965
|
try {
|
|
4751
|
-
const stat = (0,
|
|
4966
|
+
const stat = (0, import_fs8.lstatSync)(fullPath);
|
|
4752
4967
|
if (stat.isSymbolicLink()) {
|
|
4753
4968
|
const result = {
|
|
4754
4969
|
success: false,
|
|
@@ -4789,9 +5004,9 @@ function _safeWriteInner(input) {
|
|
|
4789
5004
|
}
|
|
4790
5005
|
try {
|
|
4791
5006
|
if (createDirectories) {
|
|
4792
|
-
(0,
|
|
5007
|
+
(0, import_fs8.mkdirSync)((0, import_path8.dirname)(fullPath), { recursive: true });
|
|
4793
5008
|
}
|
|
4794
|
-
(0,
|
|
5009
|
+
(0, import_fs8.writeFileSync)(fullPath, content, { encoding: "utf-8" });
|
|
4795
5010
|
if (pageSlug) {
|
|
4796
5011
|
try {
|
|
4797
5012
|
const registry = readPageRegistry(cwd);
|
|
@@ -4876,8 +5091,8 @@ function registerSafeWriteTools(server2) {
|
|
|
4876
5091
|
|
|
4877
5092
|
// src/tools/auth.ts
|
|
4878
5093
|
var import_zod15 = require("zod");
|
|
4879
|
-
var
|
|
4880
|
-
var
|
|
5094
|
+
var import_fs9 = require("fs");
|
|
5095
|
+
var import_path9 = require("path");
|
|
4881
5096
|
function buildHierarchy(roles) {
|
|
4882
5097
|
const h = {};
|
|
4883
5098
|
for (let i = 0; i < roles.length - 1; i++) {
|
|
@@ -4904,9 +5119,9 @@ ${indent} requiredRole: ${r.requiredRole}`).join("\n");
|
|
|
4904
5119
|
}
|
|
4905
5120
|
function detectNextMajorVersion(cwd) {
|
|
4906
5121
|
try {
|
|
4907
|
-
const pkgPath = (0,
|
|
4908
|
-
if (!(0,
|
|
4909
|
-
const pkg = JSON.parse((0,
|
|
5122
|
+
const pkgPath = (0, import_path9.join)(cwd, "package.json");
|
|
5123
|
+
if (!(0, import_fs9.existsSync)(pkgPath)) return null;
|
|
5124
|
+
const pkg = JSON.parse((0, import_fs9.readFileSync)(pkgPath, "utf8"));
|
|
4910
5125
|
const nextVersion = pkg.dependencies?.next ?? pkg.devDependencies?.next;
|
|
4911
5126
|
if (!nextVersion) return null;
|
|
4912
5127
|
const match = nextVersion.match(/(\d+)/);
|
|
@@ -5570,7 +5785,7 @@ async function configureAuthHandler(params, cwd) {
|
|
|
5570
5785
|
auditRetentionDays,
|
|
5571
5786
|
normalizedRoutes
|
|
5572
5787
|
);
|
|
5573
|
-
(0,
|
|
5788
|
+
(0, import_fs9.writeFileSync)((0, import_path9.join)(cwd, conventionFile), authFileContent, "utf8");
|
|
5574
5789
|
filesWritten.push(conventionFile);
|
|
5575
5790
|
} catch (err) {
|
|
5576
5791
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -5590,12 +5805,12 @@ async function configureAuthHandler(params, cwd) {
|
|
|
5590
5805
|
if (!devOnly) {
|
|
5591
5806
|
try {
|
|
5592
5807
|
const envBlock = generateEnvBlock(effectiveMethod, params);
|
|
5593
|
-
const envPath = (0,
|
|
5594
|
-
if ((0,
|
|
5595
|
-
const existing = (0,
|
|
5596
|
-
(0,
|
|
5808
|
+
const envPath = (0, import_path9.join)(cwd, ".env.example");
|
|
5809
|
+
if ((0, import_fs9.existsSync)(envPath)) {
|
|
5810
|
+
const existing = (0, import_fs9.readFileSync)(envPath, "utf8");
|
|
5811
|
+
(0, import_fs9.writeFileSync)(envPath, existing.trimEnd() + "\n\n" + envBlock, "utf8");
|
|
5597
5812
|
} else {
|
|
5598
|
-
(0,
|
|
5813
|
+
(0, import_fs9.writeFileSync)(envPath, envBlock, "utf8");
|
|
5599
5814
|
}
|
|
5600
5815
|
filesWritten.push(".env.example");
|
|
5601
5816
|
} catch (err) {
|
|
@@ -5613,10 +5828,10 @@ async function configureAuthHandler(params, cwd) {
|
|
|
5613
5828
|
}
|
|
5614
5829
|
if (devOnly) {
|
|
5615
5830
|
try {
|
|
5616
|
-
const mockAuthDir = (0,
|
|
5617
|
-
(0,
|
|
5831
|
+
const mockAuthDir = (0, import_path9.join)(cwd, "lib");
|
|
5832
|
+
(0, import_fs9.mkdirSync)(mockAuthDir, { recursive: true });
|
|
5618
5833
|
const mockAuthContent = generateMockAuthContent(roles, mockUsers);
|
|
5619
|
-
(0,
|
|
5834
|
+
(0, import_fs9.writeFileSync)((0, import_path9.join)(mockAuthDir, "mock-auth.ts"), mockAuthContent, "utf8");
|
|
5620
5835
|
filesWritten.push("lib/mock-auth.ts");
|
|
5621
5836
|
} catch (err) {
|
|
5622
5837
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -5634,11 +5849,11 @@ async function configureAuthHandler(params, cwd) {
|
|
|
5634
5849
|
};
|
|
5635
5850
|
}
|
|
5636
5851
|
try {
|
|
5637
|
-
const pkgPath = (0,
|
|
5638
|
-
if ((0,
|
|
5639
|
-
const existingPkg = (0,
|
|
5852
|
+
const pkgPath = (0, import_path9.join)(cwd, "package.json");
|
|
5853
|
+
if ((0, import_fs9.existsSync)(pkgPath)) {
|
|
5854
|
+
const existingPkg = (0, import_fs9.readFileSync)(pkgPath, "utf8");
|
|
5640
5855
|
const updatedPkg = updatePackageJsonScripts(existingPkg, roles, mockUsers);
|
|
5641
|
-
(0,
|
|
5856
|
+
(0, import_fs9.writeFileSync)(pkgPath, updatedPkg, "utf8");
|
|
5642
5857
|
filesWritten.push("package.json");
|
|
5643
5858
|
}
|
|
5644
5859
|
} catch (err) {
|
|
@@ -5679,7 +5894,7 @@ async function configureAuthHandler(params, cwd) {
|
|
|
5679
5894
|
normalizedRoutes,
|
|
5680
5895
|
useProxy
|
|
5681
5896
|
);
|
|
5682
|
-
(0,
|
|
5897
|
+
(0, import_fs9.writeFileSync)((0, import_path9.join)(cwd, "stackwright.auth.yml"), authYaml, "utf8");
|
|
5683
5898
|
filesWritten.push("stackwright.auth.yml");
|
|
5684
5899
|
} catch (err) {
|
|
5685
5900
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -5792,8 +6007,8 @@ function registerAuthTools(server2) {
|
|
|
5792
6007
|
|
|
5793
6008
|
// src/integrity.ts
|
|
5794
6009
|
var import_crypto4 = require("crypto");
|
|
5795
|
-
var
|
|
5796
|
-
var
|
|
6010
|
+
var import_fs10 = require("fs");
|
|
6011
|
+
var import_path10 = require("path");
|
|
5797
6012
|
var _checksums = /* @__PURE__ */ new Map([
|
|
5798
6013
|
[
|
|
5799
6014
|
"stackwright-pro-api-otter.json",
|
|
@@ -5876,14 +6091,14 @@ function safeEqual(a, b) {
|
|
|
5876
6091
|
return (0, import_crypto4.timingSafeEqual)(Buffer.from(a, "utf8"), Buffer.from(b, "utf8"));
|
|
5877
6092
|
}
|
|
5878
6093
|
function verifyOtterFile(filePath) {
|
|
5879
|
-
const filename = (0,
|
|
6094
|
+
const filename = (0, import_path10.basename)(filePath);
|
|
5880
6095
|
const expected = CANONICAL_CHECKSUMS.get(filename);
|
|
5881
6096
|
if (expected === void 0) {
|
|
5882
6097
|
return { verified: false, filename, error: `Unknown otter file: not in canonical set` };
|
|
5883
6098
|
}
|
|
5884
6099
|
let stat;
|
|
5885
6100
|
try {
|
|
5886
|
-
stat = (0,
|
|
6101
|
+
stat = (0, import_fs10.lstatSync)(filePath);
|
|
5887
6102
|
} catch (err) {
|
|
5888
6103
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5889
6104
|
return { verified: false, filename, error: `Cannot stat file: ${msg}` };
|
|
@@ -5901,7 +6116,7 @@ function verifyOtterFile(filePath) {
|
|
|
5901
6116
|
}
|
|
5902
6117
|
let raw;
|
|
5903
6118
|
try {
|
|
5904
|
-
raw = (0,
|
|
6119
|
+
raw = (0, import_fs10.readFileSync)(filePath);
|
|
5905
6120
|
} catch (err) {
|
|
5906
6121
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5907
6122
|
return { verified: false, filename, error: `Cannot read file: ${msg}` };
|
|
@@ -5951,7 +6166,7 @@ function verifyAllOtters(otterDir) {
|
|
|
5951
6166
|
const unknown = [];
|
|
5952
6167
|
let entries;
|
|
5953
6168
|
try {
|
|
5954
|
-
entries = (0,
|
|
6169
|
+
entries = (0, import_fs10.readdirSync)(otterDir);
|
|
5955
6170
|
} catch (err) {
|
|
5956
6171
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5957
6172
|
return {
|
|
@@ -5962,9 +6177,9 @@ function verifyAllOtters(otterDir) {
|
|
|
5962
6177
|
}
|
|
5963
6178
|
const otterFiles = entries.filter((f) => f.endsWith("-otter.json"));
|
|
5964
6179
|
for (const filename of otterFiles) {
|
|
5965
|
-
const filePath = (0,
|
|
6180
|
+
const filePath = (0, import_path10.join)(otterDir, filename);
|
|
5966
6181
|
try {
|
|
5967
|
-
if ((0,
|
|
6182
|
+
if ((0, import_fs10.lstatSync)(filePath).isSymbolicLink()) {
|
|
5968
6183
|
failed.push({ filename, error: "Skipped: symlink" });
|
|
5969
6184
|
continue;
|
|
5970
6185
|
}
|
|
@@ -5989,10 +6204,10 @@ function verifyAllOtters(otterDir) {
|
|
|
5989
6204
|
var DEFAULT_SEARCH_PATHS = ["node_modules/@stackwright-pro/otters/src/", "packages/otters/src/"];
|
|
5990
6205
|
function resolveOtterDir() {
|
|
5991
6206
|
const cwd = process.cwd();
|
|
5992
|
-
for (const
|
|
5993
|
-
const candidate = (0,
|
|
6207
|
+
for (const relative2 of DEFAULT_SEARCH_PATHS) {
|
|
6208
|
+
const candidate = (0, import_path10.join)(cwd, relative2);
|
|
5994
6209
|
try {
|
|
5995
|
-
(0,
|
|
6210
|
+
(0, import_fs10.lstatSync)(candidate);
|
|
5996
6211
|
return candidate;
|
|
5997
6212
|
} catch {
|
|
5998
6213
|
}
|
|
@@ -6071,13 +6286,13 @@ function registerIntegrityTools(server2) {
|
|
|
6071
6286
|
|
|
6072
6287
|
// src/tools/domain.ts
|
|
6073
6288
|
var import_zod16 = require("zod");
|
|
6074
|
-
var
|
|
6075
|
-
var
|
|
6289
|
+
var import_fs11 = require("fs");
|
|
6290
|
+
var import_path11 = require("path");
|
|
6076
6291
|
function handleListCollections(input) {
|
|
6077
6292
|
const cwd = input._cwd ?? process.cwd();
|
|
6078
6293
|
const sources = [
|
|
6079
6294
|
{
|
|
6080
|
-
path: (0,
|
|
6295
|
+
path: (0, import_path11.join)(cwd, ".stackwright", "artifacts", "data-config.json"),
|
|
6081
6296
|
source: "data-config.json",
|
|
6082
6297
|
parse: (raw) => {
|
|
6083
6298
|
const parsed = JSON.parse(raw);
|
|
@@ -6088,15 +6303,15 @@ function handleListCollections(input) {
|
|
|
6088
6303
|
}
|
|
6089
6304
|
},
|
|
6090
6305
|
{
|
|
6091
|
-
path: (0,
|
|
6306
|
+
path: (0, import_path11.join)(cwd, "stackwright.yml"),
|
|
6092
6307
|
source: "stackwright.yml",
|
|
6093
6308
|
parse: extractCollectionsFromYaml
|
|
6094
6309
|
}
|
|
6095
6310
|
];
|
|
6096
6311
|
for (const { path: path5, source, parse } of sources) {
|
|
6097
|
-
if (!(0,
|
|
6312
|
+
if (!(0, import_fs11.existsSync)(path5)) continue;
|
|
6098
6313
|
try {
|
|
6099
|
-
const collections = parse((0,
|
|
6314
|
+
const collections = parse((0, import_fs11.readFileSync)(path5, "utf8"));
|
|
6100
6315
|
return {
|
|
6101
6316
|
text: JSON.stringify({ collections, source, collectionCount: collections.length }),
|
|
6102
6317
|
isError: false
|
|
@@ -6247,8 +6462,8 @@ function handleValidateWorkflow(input) {
|
|
|
6247
6462
|
if (input.workflow && Object.keys(input.workflow).length > 0) {
|
|
6248
6463
|
raw = input.workflow;
|
|
6249
6464
|
} else {
|
|
6250
|
-
const artifactPath = (0,
|
|
6251
|
-
if (!(0,
|
|
6465
|
+
const artifactPath = (0, import_path11.join)(cwd, ".stackwright", "artifacts", "workflow-config.json");
|
|
6466
|
+
if (!(0, import_fs11.existsSync)(artifactPath)) {
|
|
6252
6467
|
return fail([
|
|
6253
6468
|
{
|
|
6254
6469
|
code: "NO_WORKFLOW",
|
|
@@ -6257,7 +6472,7 @@ function handleValidateWorkflow(input) {
|
|
|
6257
6472
|
]);
|
|
6258
6473
|
}
|
|
6259
6474
|
try {
|
|
6260
|
-
raw = JSON.parse((0,
|
|
6475
|
+
raw = JSON.parse((0, import_fs11.readFileSync)(artifactPath, "utf8"));
|
|
6261
6476
|
} catch (err) {
|
|
6262
6477
|
return fail([{ code: "INVALID_JSON", message: `Failed to parse workflow artifact: ${err}` }]);
|
|
6263
6478
|
}
|
|
@@ -6569,7 +6784,7 @@ var fs2 = __toESM(require("fs"));
|
|
|
6569
6784
|
var os = __toESM(require("os"));
|
|
6570
6785
|
var path3 = __toESM(require("path"));
|
|
6571
6786
|
var import_zod18 = require("zod");
|
|
6572
|
-
var
|
|
6787
|
+
var import_js_yaml3 = require("js-yaml");
|
|
6573
6788
|
var import_cli = require("@stackwright/cli");
|
|
6574
6789
|
var import_types4 = require("@stackwright-pro/types");
|
|
6575
6790
|
var BCP47_RE = /^[a-z]{2}(-[A-Z]{2})?$/;
|
|
@@ -6623,7 +6838,7 @@ function handleProWritePage(input) {
|
|
|
6623
6838
|
}
|
|
6624
6839
|
let parsed;
|
|
6625
6840
|
try {
|
|
6626
|
-
parsed = (0,
|
|
6841
|
+
parsed = (0, import_js_yaml3.load)(content);
|
|
6627
6842
|
} catch (err) {
|
|
6628
6843
|
return {
|
|
6629
6844
|
isError: true,
|
|
@@ -6637,7 +6852,7 @@ function handleProWritePage(input) {
|
|
|
6637
6852
|
}
|
|
6638
6853
|
const clone = JSON.parse(JSON.stringify(parsed));
|
|
6639
6854
|
const sanitized = sanitizeNode(clone);
|
|
6640
|
-
const sanitizedYaml = (0,
|
|
6855
|
+
const sanitizedYaml = (0, import_js_yaml3.dump)(sanitized);
|
|
6641
6856
|
const tmpDir = fs2.mkdtempSync(path3.join(os.tmpdir(), "sw-pro-validate-"));
|
|
6642
6857
|
try {
|
|
6643
6858
|
(0, import_cli.writePage)(path3.join(tmpDir, "pages"), "__validation__", sanitizedYaml);
|
|
@@ -6694,8 +6909,8 @@ function registerProPageTools(server2) {
|
|
|
6694
6909
|
}
|
|
6695
6910
|
|
|
6696
6911
|
// src/tools/scaffold-cleanup.ts
|
|
6697
|
-
var
|
|
6698
|
-
var
|
|
6912
|
+
var import_fs12 = require("fs");
|
|
6913
|
+
var import_path12 = require("path");
|
|
6699
6914
|
var SCAFFOLD_FILES_TO_DELETE = [
|
|
6700
6915
|
"content/posts/getting-started.yaml",
|
|
6701
6916
|
"content/posts/hello-world.yaml"
|
|
@@ -6720,12 +6935,12 @@ var FALLBACK_COLORS = {
|
|
|
6720
6935
|
mutedForeground: "#737373"
|
|
6721
6936
|
};
|
|
6722
6937
|
function readThemeColors(cwd) {
|
|
6723
|
-
const tokenPath = (0,
|
|
6724
|
-
if (!(0,
|
|
6725
|
-
const stat = (0,
|
|
6938
|
+
const tokenPath = (0, import_path12.join)(cwd, ".stackwright", "artifacts", "theme-tokens.json");
|
|
6939
|
+
if (!(0, import_fs12.existsSync)(tokenPath)) return { ...FALLBACK_COLORS };
|
|
6940
|
+
const stat = (0, import_fs12.lstatSync)(tokenPath);
|
|
6726
6941
|
if (stat.isSymbolicLink()) return { ...FALLBACK_COLORS };
|
|
6727
6942
|
try {
|
|
6728
|
-
const raw = JSON.parse((0,
|
|
6943
|
+
const raw = JSON.parse((0, import_fs12.readFileSync)(tokenPath, "utf-8"));
|
|
6729
6944
|
const css = raw?.cssVariables ?? {};
|
|
6730
6945
|
const toHsl = (hslValue) => {
|
|
6731
6946
|
if (!hslValue || typeof hslValue !== "string") return null;
|
|
@@ -6785,15 +7000,15 @@ function generateNotFoundPage(colors) {
|
|
|
6785
7000
|
`;
|
|
6786
7001
|
}
|
|
6787
7002
|
function isSafePath(fullPath) {
|
|
6788
|
-
if (!(0,
|
|
6789
|
-
const stat = (0,
|
|
7003
|
+
if (!(0, import_fs12.existsSync)(fullPath)) return true;
|
|
7004
|
+
const stat = (0, import_fs12.lstatSync)(fullPath);
|
|
6790
7005
|
return !stat.isSymbolicLink();
|
|
6791
7006
|
}
|
|
6792
7007
|
function isDirEmpty(dirPath) {
|
|
6793
|
-
if (!(0,
|
|
6794
|
-
const stat = (0,
|
|
7008
|
+
if (!(0, import_fs12.existsSync)(dirPath)) return false;
|
|
7009
|
+
const stat = (0, import_fs12.lstatSync)(dirPath);
|
|
6795
7010
|
if (!stat.isDirectory()) return false;
|
|
6796
|
-
return (0,
|
|
7011
|
+
return (0, import_fs12.readdirSync)(dirPath).length === 0;
|
|
6797
7012
|
}
|
|
6798
7013
|
function handleCleanupScaffold(_cwd) {
|
|
6799
7014
|
const cwd = _cwd ?? process.cwd();
|
|
@@ -6806,8 +7021,8 @@ function handleCleanupScaffold(_cwd) {
|
|
|
6806
7021
|
cleanupWarnings: []
|
|
6807
7022
|
};
|
|
6808
7023
|
for (const relPath of SCAFFOLD_FILES_TO_DELETE) {
|
|
6809
|
-
const fullPath = (0,
|
|
6810
|
-
if (!(0,
|
|
7024
|
+
const fullPath = (0, import_path12.join)(cwd, relPath);
|
|
7025
|
+
if (!(0, import_fs12.existsSync)(fullPath)) {
|
|
6811
7026
|
result.skipped.push(relPath);
|
|
6812
7027
|
continue;
|
|
6813
7028
|
}
|
|
@@ -6816,7 +7031,7 @@ function handleCleanupScaffold(_cwd) {
|
|
|
6816
7031
|
continue;
|
|
6817
7032
|
}
|
|
6818
7033
|
try {
|
|
6819
|
-
(0,
|
|
7034
|
+
(0, import_fs12.unlinkSync)(fullPath);
|
|
6820
7035
|
result.deleted.push(relPath);
|
|
6821
7036
|
} catch (err) {
|
|
6822
7037
|
result.errors.push(`Failed to delete ${relPath}: ${String(err)}`);
|
|
@@ -6824,19 +7039,19 @@ function handleCleanupScaffold(_cwd) {
|
|
|
6824
7039
|
}
|
|
6825
7040
|
{
|
|
6826
7041
|
const relPath = "pages/getting-started/content.yml";
|
|
6827
|
-
const fullPath = (0,
|
|
6828
|
-
if (!(0,
|
|
7042
|
+
const fullPath = (0, import_path12.join)(cwd, relPath);
|
|
7043
|
+
if (!(0, import_fs12.existsSync)(fullPath)) {
|
|
6829
7044
|
result.skipped.push(relPath);
|
|
6830
7045
|
} else if (!isSafePath(fullPath)) {
|
|
6831
7046
|
result.errors.push(`Refusing to delete symlink: ${relPath}`);
|
|
6832
7047
|
} else {
|
|
6833
|
-
const content = (0,
|
|
7048
|
+
const content = (0, import_fs12.readFileSync)(fullPath, "utf-8");
|
|
6834
7049
|
const isScaffoldDefault = GETTING_STARTED_SCAFFOLD_FINGERPRINTS.some(
|
|
6835
7050
|
(marker) => content.includes(marker)
|
|
6836
7051
|
);
|
|
6837
7052
|
if (isScaffoldDefault) {
|
|
6838
7053
|
try {
|
|
6839
|
-
(0,
|
|
7054
|
+
(0, import_fs12.unlinkSync)(fullPath);
|
|
6840
7055
|
result.deleted.push(relPath);
|
|
6841
7056
|
} catch (err) {
|
|
6842
7057
|
result.errors.push(`Failed to delete ${relPath}: ${String(err)}`);
|
|
@@ -6850,21 +7065,21 @@ function handleCleanupScaffold(_cwd) {
|
|
|
6850
7065
|
}
|
|
6851
7066
|
{
|
|
6852
7067
|
const relPath = `content/posts/${POSTS_COLLECTION_FILE}`;
|
|
6853
|
-
const fullPath = (0,
|
|
6854
|
-
const postsDir = (0,
|
|
6855
|
-
if (!(0,
|
|
7068
|
+
const fullPath = (0, import_path12.join)(cwd, relPath);
|
|
7069
|
+
const postsDir = (0, import_path12.join)(cwd, "content/posts");
|
|
7070
|
+
if (!(0, import_fs12.existsSync)(fullPath)) {
|
|
6856
7071
|
result.skipped.push(relPath);
|
|
6857
7072
|
} else if (!isSafePath(fullPath)) {
|
|
6858
7073
|
result.errors.push(`Refusing to delete symlink: ${relPath}`);
|
|
6859
|
-
} else if (!(0,
|
|
7074
|
+
} else if (!(0, import_fs12.existsSync)(postsDir)) {
|
|
6860
7075
|
result.skipped.push(relPath);
|
|
6861
7076
|
} else {
|
|
6862
|
-
const userPostFiles = (0,
|
|
7077
|
+
const userPostFiles = (0, import_fs12.readdirSync)(postsDir).filter(
|
|
6863
7078
|
(f) => f !== POSTS_COLLECTION_FILE && POST_FILE_EXTENSIONS.some((ext) => f.endsWith(ext))
|
|
6864
7079
|
);
|
|
6865
7080
|
if (userPostFiles.length === 0) {
|
|
6866
7081
|
try {
|
|
6867
|
-
(0,
|
|
7082
|
+
(0, import_fs12.unlinkSync)(fullPath);
|
|
6868
7083
|
result.deleted.push(relPath);
|
|
6869
7084
|
} catch (err) {
|
|
6870
7085
|
result.errors.push(`Failed to delete ${relPath}: ${String(err)}`);
|
|
@@ -6877,15 +7092,15 @@ function handleCleanupScaffold(_cwd) {
|
|
|
6877
7092
|
}
|
|
6878
7093
|
}
|
|
6879
7094
|
for (const relDir of SCAFFOLD_DIRS_TO_PRUNE) {
|
|
6880
|
-
const fullDir = (0,
|
|
6881
|
-
if (!(0,
|
|
7095
|
+
const fullDir = (0, import_path12.join)(cwd, relDir);
|
|
7096
|
+
if (!(0, import_fs12.existsSync)(fullDir)) continue;
|
|
6882
7097
|
if (!isSafePath(fullDir)) {
|
|
6883
7098
|
result.errors.push(`Refusing to prune symlink directory: ${relDir}`);
|
|
6884
7099
|
continue;
|
|
6885
7100
|
}
|
|
6886
7101
|
if (isDirEmpty(fullDir)) {
|
|
6887
7102
|
try {
|
|
6888
|
-
(0,
|
|
7103
|
+
(0, import_fs12.rmdirSync)(fullDir);
|
|
6889
7104
|
result.prunedDirs.push(relDir);
|
|
6890
7105
|
} catch (err) {
|
|
6891
7106
|
result.errors.push(`Failed to prune directory ${relDir}: ${String(err)}`);
|
|
@@ -6893,8 +7108,8 @@ function handleCleanupScaffold(_cwd) {
|
|
|
6893
7108
|
}
|
|
6894
7109
|
}
|
|
6895
7110
|
{
|
|
6896
|
-
const fullPath = (0,
|
|
6897
|
-
if (!(0,
|
|
7111
|
+
const fullPath = (0, import_path12.join)(cwd, NOT_FOUND_PATH);
|
|
7112
|
+
if (!(0, import_fs12.existsSync)(fullPath)) {
|
|
6898
7113
|
result.skipped.push(NOT_FOUND_PATH);
|
|
6899
7114
|
} else if (!isSafePath(fullPath)) {
|
|
6900
7115
|
result.errors.push(`Refusing to rewrite symlink: ${NOT_FOUND_PATH}`);
|
|
@@ -6902,9 +7117,9 @@ function handleCleanupScaffold(_cwd) {
|
|
|
6902
7117
|
try {
|
|
6903
7118
|
const colors = readThemeColors(cwd);
|
|
6904
7119
|
const content = generateNotFoundPage(colors);
|
|
6905
|
-
const dir = (0,
|
|
6906
|
-
(0,
|
|
6907
|
-
(0,
|
|
7120
|
+
const dir = (0, import_path12.dirname)(fullPath);
|
|
7121
|
+
(0, import_fs12.mkdirSync)(dir, { recursive: true });
|
|
7122
|
+
(0, import_fs12.writeFileSync)(fullPath, content, "utf-8");
|
|
6908
7123
|
result.rewritten.push(NOT_FOUND_PATH);
|
|
6909
7124
|
} catch (err) {
|
|
6910
7125
|
result.errors.push(`Failed to rewrite ${NOT_FOUND_PATH}: ${String(err)}`);
|
|
@@ -7173,23 +7388,23 @@ function registerContrastTools(server2) {
|
|
|
7173
7388
|
|
|
7174
7389
|
// src/tools/compile.ts
|
|
7175
7390
|
var import_zod20 = require("zod");
|
|
7176
|
-
var
|
|
7177
|
-
var
|
|
7391
|
+
var import_fs13 = __toESM(require("fs"));
|
|
7392
|
+
var import_path13 = __toESM(require("path"));
|
|
7178
7393
|
var import_server = require("@stackwright-pro/pulse/server");
|
|
7179
7394
|
var import_server2 = require("@stackwright-pro/auth-nextjs/server");
|
|
7180
7395
|
var import_server3 = require("@stackwright-pro/openapi/server");
|
|
7181
7396
|
function buildContext(projectRoot) {
|
|
7182
7397
|
return {
|
|
7183
7398
|
projectRoot,
|
|
7184
|
-
contentOutDir:
|
|
7185
|
-
imagesDir:
|
|
7399
|
+
contentOutDir: import_path13.default.join(projectRoot, "public", "stackwright-content"),
|
|
7400
|
+
imagesDir: import_path13.default.join(projectRoot, "public", "images"),
|
|
7186
7401
|
siteConfig: loadSiteConfig(projectRoot)
|
|
7187
7402
|
};
|
|
7188
7403
|
}
|
|
7189
7404
|
function loadSiteConfig(projectRoot) {
|
|
7190
7405
|
try {
|
|
7191
|
-
const sitePath =
|
|
7192
|
-
return JSON.parse(
|
|
7406
|
+
const sitePath = import_path13.default.join(projectRoot, "public", "stackwright-content", "_site.json");
|
|
7407
|
+
return JSON.parse(import_fs13.default.readFileSync(sitePath, "utf8"));
|
|
7193
7408
|
} catch {
|
|
7194
7409
|
return {};
|
|
7195
7410
|
}
|
|
@@ -7200,8 +7415,8 @@ function formatDuration(startMs) {
|
|
|
7200
7415
|
}
|
|
7201
7416
|
async function tryOssCompile(fn, ctx, extra) {
|
|
7202
7417
|
try {
|
|
7203
|
-
const bsPath =
|
|
7204
|
-
if (!
|
|
7418
|
+
const bsPath = import_path13.default.join(ctx.projectRoot, "node_modules", "@stackwright", "build-scripts");
|
|
7419
|
+
if (!import_fs13.default.existsSync(bsPath)) {
|
|
7205
7420
|
return {
|
|
7206
7421
|
ok: false,
|
|
7207
7422
|
error: `@stackwright/build-scripts not found at ${bsPath}. Is it installed in your project?`
|
|
@@ -7415,14 +7630,14 @@ ${results.join("\n")}`;
|
|
|
7415
7630
|
|
|
7416
7631
|
// src/tools/strip-legacy-integrations.ts
|
|
7417
7632
|
var import_zod21 = require("zod");
|
|
7418
|
-
var
|
|
7419
|
-
var
|
|
7633
|
+
var import_fs14 = require("fs");
|
|
7634
|
+
var import_path14 = require("path");
|
|
7420
7635
|
function handleStripLegacyIntegrations(input) {
|
|
7421
7636
|
const { projectRoot } = input;
|
|
7422
|
-
const ymlPath = (0,
|
|
7423
|
-
const yamlPath = (0,
|
|
7424
|
-
if (!(0,
|
|
7425
|
-
if ((0,
|
|
7637
|
+
const ymlPath = (0, import_path14.join)(projectRoot, "stackwright.yml");
|
|
7638
|
+
const yamlPath = (0, import_path14.join)(projectRoot, "stackwright.yaml");
|
|
7639
|
+
if (!(0, import_fs14.existsSync)(ymlPath)) {
|
|
7640
|
+
if ((0, import_fs14.existsSync)(yamlPath)) {
|
|
7426
7641
|
return {
|
|
7427
7642
|
changed: false,
|
|
7428
7643
|
removedEntries: 0,
|
|
@@ -7435,7 +7650,7 @@ function handleStripLegacyIntegrations(input) {
|
|
|
7435
7650
|
message: "stackwright.yml not found \u2014 no-op."
|
|
7436
7651
|
};
|
|
7437
7652
|
}
|
|
7438
|
-
const raw = (0,
|
|
7653
|
+
const raw = (0, import_fs14.readFileSync)(ymlPath, "utf-8");
|
|
7439
7654
|
const isCRLF = raw.includes("\r\n");
|
|
7440
7655
|
const content = isCRLF ? raw.replace(/\r\n/g, "\n") : raw;
|
|
7441
7656
|
const lines = content.split("\n");
|
|
@@ -7465,7 +7680,7 @@ function handleStripLegacyIntegrations(input) {
|
|
|
7465
7680
|
outputContent += "\n";
|
|
7466
7681
|
}
|
|
7467
7682
|
const outputRaw = isCRLF ? outputContent.replace(/\n/g, "\r\n") : outputContent;
|
|
7468
|
-
(0,
|
|
7683
|
+
(0, import_fs14.writeFileSync)(ymlPath, outputRaw, "utf-8");
|
|
7469
7684
|
return {
|
|
7470
7685
|
changed: true,
|
|
7471
7686
|
removedEntries,
|
|
@@ -7490,15 +7705,15 @@ function registerStripLegacyIntegrationsTool(server2) {
|
|
|
7490
7705
|
|
|
7491
7706
|
// src/tools/emitters.ts
|
|
7492
7707
|
var import_zod22 = require("zod");
|
|
7493
|
-
var
|
|
7494
|
-
var
|
|
7495
|
-
var
|
|
7708
|
+
var import_fs15 = require("fs");
|
|
7709
|
+
var import_path15 = require("path");
|
|
7710
|
+
var import_js_yaml4 = __toESM(require("js-yaml"));
|
|
7496
7711
|
var import_emitters = require("@stackwright-pro/emitters");
|
|
7497
7712
|
function readIntegrations(cwd) {
|
|
7498
|
-
const filePath = (0,
|
|
7499
|
-
if (!(0,
|
|
7713
|
+
const filePath = (0, import_path15.join)(cwd, "stackwright.integrations.yml");
|
|
7714
|
+
if (!(0, import_fs15.existsSync)(filePath)) return [];
|
|
7500
7715
|
try {
|
|
7501
|
-
const raw =
|
|
7716
|
+
const raw = import_js_yaml4.default.load((0, import_fs15.readFileSync)(filePath, "utf-8"));
|
|
7502
7717
|
if (!raw?.integrations || !Array.isArray(raw.integrations)) return [];
|
|
7503
7718
|
return raw.integrations.filter((i) => typeof i.name === "string").map((i) => ({
|
|
7504
7719
|
name: i.name,
|
|
@@ -7509,15 +7724,15 @@ function readIntegrations(cwd) {
|
|
|
7509
7724
|
}
|
|
7510
7725
|
}
|
|
7511
7726
|
function readServiceTokenRefs(cwd) {
|
|
7512
|
-
const servicesDir = (0,
|
|
7513
|
-
if (!(0,
|
|
7727
|
+
const servicesDir = (0, import_path15.join)(cwd, "services");
|
|
7728
|
+
if (!(0, import_fs15.existsSync)(servicesDir)) return [];
|
|
7514
7729
|
try {
|
|
7515
|
-
const files = (0,
|
|
7730
|
+
const files = (0, import_fs15.readdirSync)(servicesDir).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
|
|
7516
7731
|
const refs = [];
|
|
7517
7732
|
for (const file of files) {
|
|
7518
7733
|
try {
|
|
7519
|
-
const raw =
|
|
7520
|
-
(0,
|
|
7734
|
+
const raw = import_js_yaml4.default.load(
|
|
7735
|
+
(0, import_fs15.readFileSync)((0, import_path15.join)(servicesDir, file), "utf-8")
|
|
7521
7736
|
);
|
|
7522
7737
|
if (raw?.tokenEnv && typeof raw.tokenEnv === "string") {
|
|
7523
7738
|
refs.push({
|
|
@@ -7667,12 +7882,12 @@ This is the third concrete instance of the swp-zf9y deterministic emitter patter
|
|
|
7667
7882
|
|
|
7668
7883
|
// src/tools/list-specs.ts
|
|
7669
7884
|
var import_zod23 = require("zod");
|
|
7670
|
-
var
|
|
7671
|
-
var
|
|
7885
|
+
var import_fs16 = require("fs");
|
|
7886
|
+
var import_path16 = require("path");
|
|
7672
7887
|
var STRIP_SUFFIXES = ["-openapi", "-asyncapi", "-api", "-spec"];
|
|
7673
7888
|
var ALLOWED_EXTS = /* @__PURE__ */ new Set([".yaml", ".yml", ".json"]);
|
|
7674
7889
|
function deriveIntegrationName(fileName) {
|
|
7675
|
-
let name = (0,
|
|
7890
|
+
let name = (0, import_path16.basename)(fileName, (0, import_path16.extname)(fileName));
|
|
7676
7891
|
for (const suffix of STRIP_SUFFIXES) {
|
|
7677
7892
|
if (name.endsWith(suffix)) {
|
|
7678
7893
|
name = name.slice(0, -suffix.length);
|
|
@@ -7690,29 +7905,29 @@ function detectFormat(snippet) {
|
|
|
7690
7905
|
}
|
|
7691
7906
|
function handleListSpecs(input) {
|
|
7692
7907
|
const { projectRoot } = input;
|
|
7693
|
-
const specsDir = (0,
|
|
7908
|
+
const specsDir = (0, import_path16.join)(projectRoot, "specs");
|
|
7694
7909
|
const empty = { projectRoot, specs: [], totalCount: 0 };
|
|
7695
|
-
if (!(0,
|
|
7910
|
+
if (!(0, import_fs16.existsSync)(specsDir)) return empty;
|
|
7696
7911
|
let entries;
|
|
7697
7912
|
try {
|
|
7698
|
-
entries = (0,
|
|
7913
|
+
entries = (0, import_fs16.readdirSync)(specsDir);
|
|
7699
7914
|
} catch {
|
|
7700
7915
|
return empty;
|
|
7701
7916
|
}
|
|
7702
7917
|
const specs = [];
|
|
7703
7918
|
for (const entry of entries) {
|
|
7704
|
-
const fullPath = (0,
|
|
7919
|
+
const fullPath = (0, import_path16.join)(specsDir, entry);
|
|
7705
7920
|
let stat;
|
|
7706
7921
|
try {
|
|
7707
|
-
stat = (0,
|
|
7922
|
+
stat = (0, import_fs16.statSync)(fullPath);
|
|
7708
7923
|
} catch {
|
|
7709
7924
|
continue;
|
|
7710
7925
|
}
|
|
7711
7926
|
if (!stat.isFile()) continue;
|
|
7712
|
-
if (!ALLOWED_EXTS.has((0,
|
|
7927
|
+
if (!ALLOWED_EXTS.has((0, import_path16.extname)(entry).toLowerCase())) continue;
|
|
7713
7928
|
let snippet = "";
|
|
7714
7929
|
try {
|
|
7715
|
-
snippet = (0,
|
|
7930
|
+
snippet = (0, import_fs16.readFileSync)(fullPath, "utf-8").slice(0, 2048);
|
|
7716
7931
|
} catch {
|
|
7717
7932
|
}
|
|
7718
7933
|
specs.push({
|
|
@@ -7744,14 +7959,14 @@ function registerListSpecsTool(server2) {
|
|
|
7744
7959
|
|
|
7745
7960
|
// src/tools/consolidate-integrations.ts
|
|
7746
7961
|
var import_zod24 = require("zod");
|
|
7747
|
-
var
|
|
7962
|
+
var import_fs17 = require("fs");
|
|
7748
7963
|
var import_proper_lockfile2 = require("proper-lockfile");
|
|
7749
|
-
var
|
|
7750
|
-
var
|
|
7964
|
+
var import_path17 = require("path");
|
|
7965
|
+
var import_js_yaml5 = __toESM(require("js-yaml"));
|
|
7751
7966
|
var BASE_MOCK_PORT = 4011;
|
|
7752
7967
|
var STRIP_SUFFIXES2 = ["-openapi", "-asyncapi", "-api", "-spec"];
|
|
7753
7968
|
function deriveNameFromFilename(filename) {
|
|
7754
|
-
const base = (0,
|
|
7969
|
+
const base = (0, import_path17.basename)(filename, ".json").replace(/^api-config-/, "");
|
|
7755
7970
|
for (const suffix of STRIP_SUFFIXES2) {
|
|
7756
7971
|
if (base.endsWith(suffix)) return base.slice(0, -suffix.length);
|
|
7757
7972
|
}
|
|
@@ -7759,13 +7974,13 @@ function deriveNameFromFilename(filename) {
|
|
|
7759
7974
|
}
|
|
7760
7975
|
function handleConsolidateIntegrations(input) {
|
|
7761
7976
|
const { projectRoot } = input;
|
|
7762
|
-
const artifactsDir = (0,
|
|
7763
|
-
if (!(0,
|
|
7977
|
+
const artifactsDir = (0, import_path17.join)(projectRoot, ".stackwright", "artifacts");
|
|
7978
|
+
if (!(0, import_fs17.existsSync)(artifactsDir)) {
|
|
7764
7979
|
return { written: false, integrationCount: 0, reason: "no per-spec artifacts found" };
|
|
7765
7980
|
}
|
|
7766
7981
|
let entries;
|
|
7767
7982
|
try {
|
|
7768
|
-
entries = (0,
|
|
7983
|
+
entries = (0, import_fs17.readdirSync)(artifactsDir).filter(
|
|
7769
7984
|
(f) => f.startsWith("api-config-") && f.endsWith(".json") && f !== "api-config.json"
|
|
7770
7985
|
);
|
|
7771
7986
|
} catch {
|
|
@@ -7779,7 +7994,7 @@ function handleConsolidateIntegrations(input) {
|
|
|
7779
7994
|
entries.forEach((filename, index) => {
|
|
7780
7995
|
let artifact = {};
|
|
7781
7996
|
try {
|
|
7782
|
-
const raw = (0,
|
|
7997
|
+
const raw = (0, import_fs17.readFileSync)((0, import_path17.join)(artifactsDir, filename), "utf-8");
|
|
7783
7998
|
artifact = JSON.parse(raw);
|
|
7784
7999
|
} catch {
|
|
7785
8000
|
}
|
|
@@ -7805,20 +8020,20 @@ function handleConsolidateIntegrations(input) {
|
|
|
7805
8020
|
});
|
|
7806
8021
|
const integrations = Array.from(integrationsByName.values());
|
|
7807
8022
|
const dedupedCount = entries.length - integrations.length;
|
|
7808
|
-
const integrationsYmlPath = (0,
|
|
8023
|
+
const integrationsYmlPath = (0, import_path17.join)(projectRoot, "stackwright.integrations.yml");
|
|
7809
8024
|
let existing = {};
|
|
7810
|
-
if ((0,
|
|
8025
|
+
if ((0, import_fs17.existsSync)(integrationsYmlPath)) {
|
|
7811
8026
|
try {
|
|
7812
|
-
const raw = (0,
|
|
7813
|
-
existing =
|
|
8027
|
+
const raw = (0, import_fs17.readFileSync)(integrationsYmlPath, "utf-8");
|
|
8028
|
+
existing = import_js_yaml5.default.load(raw) ?? {};
|
|
7814
8029
|
} catch {
|
|
7815
8030
|
existing = {};
|
|
7816
8031
|
}
|
|
7817
8032
|
}
|
|
7818
8033
|
const merged = { ...existing, integrations };
|
|
7819
|
-
(0,
|
|
7820
|
-
if (!(0,
|
|
7821
|
-
(0,
|
|
8034
|
+
(0, import_fs17.mkdirSync)((0, import_path17.join)(projectRoot), { recursive: true });
|
|
8035
|
+
if (!(0, import_fs17.existsSync)(integrationsYmlPath)) {
|
|
8036
|
+
(0, import_fs17.writeFileSync)(integrationsYmlPath, "", "utf-8");
|
|
7822
8037
|
}
|
|
7823
8038
|
const release = (0, import_proper_lockfile2.lockSync)(integrationsYmlPath, {
|
|
7824
8039
|
realpath: false,
|
|
@@ -7827,8 +8042,8 @@ function handleConsolidateIntegrations(input) {
|
|
|
7827
8042
|
try {
|
|
7828
8043
|
const header = `# stackwright.integrations.yml \u2014 Auto-generated by stackwright_pro_consolidate_integrations
|
|
7829
8044
|
`;
|
|
7830
|
-
const body =
|
|
7831
|
-
(0,
|
|
8045
|
+
const body = import_js_yaml5.default.dump(merged, { lineWidth: 120, noRefs: true });
|
|
8046
|
+
(0, import_fs17.writeFileSync)(integrationsYmlPath, header + body, "utf-8");
|
|
7832
8047
|
} finally {
|
|
7833
8048
|
release();
|
|
7834
8049
|
}
|
|
@@ -7910,7 +8125,7 @@ var package_default = {
|
|
|
7910
8125
|
"test:coverage": "vitest run --coverage"
|
|
7911
8126
|
},
|
|
7912
8127
|
name: "@stackwright-pro/mcp",
|
|
7913
|
-
version: "0.2.0-alpha.
|
|
8128
|
+
version: "0.2.0-alpha.106",
|
|
7914
8129
|
description: "MCP tools for Stackwright Pro - Data Explorer, Security, ISR, and Dashboard generation",
|
|
7915
8130
|
license: "SEE LICENSE IN LICENSE",
|
|
7916
8131
|
main: "./dist/server.js",
|