@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/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 import_fs6 = require("fs");
2026
+ var import_fs7 = require("fs");
2027
2027
  var import_proper_lockfile = require("proper-lockfile");
2028
- var import_path6 = require("path");
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 import_js_yaml = require("js-yaml");
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, import_js_yaml.load)(yaml3);
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 import_fs5 = require("fs");
2692
- var import_path5 = require("path");
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 relative of OTTER_SEARCH_PATHS) {
2722
- const candidate = (0, import_path5.join)(cwd, relative);
2923
+ for (const relative2 of OTTER_SEARCH_PATHS) {
2924
+ const candidate = (0, import_path6.join)(cwd, relative2);
2723
2925
  try {
2724
- (0, import_fs5.lstatSync)(candidate);
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, import_fs5.readdirSync)(otterDir);
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, import_path5.join)(otterDir, filename);
2739
- if ((0, import_fs5.lstatSync)(filePath).isSymbolicLink()) continue;
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, import_fs5.readFileSync)(filePath, "utf-8");
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, import_path5.join)(cwd, "node_modules", namespace);
3048
+ const nsDir = (0, import_path6.join)(cwd, "node_modules", namespace);
2847
3049
  let pkgDirNames;
2848
3050
  try {
2849
- pkgDirNames = (0, import_fs5.readdirSync)(nsDir);
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, import_path5.join)(nsDir, pkgDirName);
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, import_fs5.readFileSync)((0, import_path5.join)(pkgDir, "package.json"), "utf-8");
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, import_path5.join)(pkgDir, relPath);
3069
+ const otterFilePath = (0, import_path6.join)(pkgDir, relPath);
2868
3070
  try {
2869
- const raw = (0, import_fs5.readFileSync)(otterFilePath, "utf-8");
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, import_path6.join)(cwd, ".stackwright", "pipeline-state.json");
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, import_fs6.existsSync)(p)) return createDefaultState();
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, import_fs6.existsSync)(filePath)) {
2999
- const stat = (0, import_fs6.lstatSync)(filePath);
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, import_fs6.writeFileSync)(filePath, content);
3207
+ (0, import_fs7.writeFileSync)(filePath, content);
3005
3208
  }
3006
3209
  function safeReadSync(filePath) {
3007
- if ((0, import_fs6.existsSync)(filePath)) {
3008
- const stat = (0, import_fs6.lstatSync)(filePath);
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, import_fs6.readFileSync)(filePath, "utf-8");
3216
+ return (0, import_fs7.readFileSync)(filePath, "utf-8");
3014
3217
  }
3015
3218
  function writeState(cwd, state) {
3016
- const dir = (0, import_path6.join)(cwd, ".stackwright");
3017
- (0, import_fs6.mkdirSync)(dir, { recursive: true });
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, import_path6.join)(cwd, ".stackwright");
3023
- (0, import_fs6.mkdirSync)(dir, { recursive: true });
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, import_fs6.existsSync)(path5)) {
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, import_path6.join)(cwd, ".stackwright", "pipeline-keys.json");
3060
- if (!(0, import_fs6.existsSync)(keyPath)) {
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, import_path6.join)(cwd, ".stackwright", "answers", `${phase}.json`);
3192
- if (!(0, import_fs6.existsSync)(answerFile)) {
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, import_path6.join)(cwd, ".stackwright", "answers");
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, import_path6.join)(answersDir, `${phase2}.json`);
3221
- if ((0, import_fs6.existsSync)(answerFile)) {
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, import_path6.join)(cwd, ".stackwright", "artifacts");
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, import_path6.join)(artifactsDir, expectedFile);
3301
- const exists = (0, import_fs6.existsSync)(fullPath);
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, import_path6.join)(cwd, ".stackwright", "questions");
3355
- (0, import_fs6.mkdirSync)(questionsDir, { recursive: true });
3356
- const filePath = (0, import_path6.join)(questionsDir, `${phase}.json`);
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, import_path6.join)(cwd, ".stackwright", "answers", `${phase}.json`);
3599
+ const answersPath = (0, import_path7.join)(cwd, ".stackwright", "answers", `${phase}.json`);
3397
3600
  let answers = {};
3398
- if ((0, import_fs6.existsSync)(answersPath)) {
3601
+ if ((0, import_fs7.existsSync)(answersPath)) {
3399
3602
  answers = JSON.parse(safeReadSync(answersPath));
3400
3603
  }
3401
3604
  let buildContextText = "";
3402
- const buildContextPath = (0, import_path6.join)(cwd, ".stackwright", "build-context.json");
3403
- if ((0, import_fs6.existsSync)(buildContextPath)) {
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, import_path6.join)(cwd, ".stackwright", "artifacts", artifactFile);
3419
- if ((0, import_fs6.existsSync)(artifactPath)) {
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, import_path6.join)(cwd, ".stackwright", "init-context.json");
3485
- if ((0, import_fs6.existsSync)(initContextPath)) {
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, import_path6.join)(cwd, ".stackwright", "artifacts", "workflow-config.json");
3991
- if (!(0, import_fs6.existsSync)(workflowArtifactPath)) {
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, import_fs6.readFileSync)(workflowArtifactPath, "utf-8"));
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, import_path6.join)(cwd, ".stackwright", "artifacts");
4068
- (0, import_fs6.mkdirSync)(artifactsDir, { recursive: true });
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, import_path6.join)(artifactsDir, artifactFile);
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, import_path6.join)(process.cwd(), ".stackwright", "questions");
4290
- (0, import_fs6.mkdirSync)(questionsDir, { recursive: true });
4291
- const outPath = (0, import_path6.join)(questionsDir, `${phase}.json`);
4292
- (0, import_fs6.writeFileSync)(
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 import_fs7 = require("fs");
4380
- var import_path7 = require("path");
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, import_path7.normalize)(filePath).match(/^pages\/(.+?)\/content\.ya?ml$/);
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, import_path7.join)(cwd, PAGE_REGISTRY_FILE);
4563
- if (!(0, import_fs7.existsSync)(regPath)) return {};
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, import_fs7.lstatSync)(regPath);
4780
+ const stat = (0, import_fs8.lstatSync)(regPath);
4566
4781
  if (stat.isSymbolicLink()) return {};
4567
- return JSON.parse((0, import_fs7.readFileSync)(regPath, "utf-8"));
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, import_path7.join)(cwd, ".stackwright");
4574
- (0, import_fs7.mkdirSync)(dir, { recursive: true });
4575
- const regPath = (0, import_path7.join)(cwd, PAGE_REGISTRY_FILE);
4576
- if ((0, import_fs7.existsSync)(regPath)) {
4577
- const stat = (0, import_fs7.lstatSync)(regPath);
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, import_fs7.writeFileSync)(regPath, JSON.stringify(registry, null, 2) + "\n", { encoding: "utf-8" });
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, import_path7.normalize)(filePath);
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, import_path7.isAbsolute)(normalized)) {
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, import_path7.normalize)(filePath);
4748
- const fullPath = (0, import_path7.join)(cwd, normalized);
4749
- if ((0, import_fs7.existsSync)(fullPath)) {
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, import_fs7.lstatSync)(fullPath);
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, import_fs7.mkdirSync)((0, import_path7.dirname)(fullPath), { recursive: true });
5007
+ (0, import_fs8.mkdirSync)((0, import_path8.dirname)(fullPath), { recursive: true });
4793
5008
  }
4794
- (0, import_fs7.writeFileSync)(fullPath, content, { encoding: "utf-8" });
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 import_fs8 = require("fs");
4880
- var import_path8 = require("path");
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, import_path8.join)(cwd, "package.json");
4908
- if (!(0, import_fs8.existsSync)(pkgPath)) return null;
4909
- const pkg = JSON.parse((0, import_fs8.readFileSync)(pkgPath, "utf8"));
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, import_fs8.writeFileSync)((0, import_path8.join)(cwd, conventionFile), authFileContent, "utf8");
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, import_path8.join)(cwd, ".env.example");
5594
- if ((0, import_fs8.existsSync)(envPath)) {
5595
- const existing = (0, import_fs8.readFileSync)(envPath, "utf8");
5596
- (0, import_fs8.writeFileSync)(envPath, existing.trimEnd() + "\n\n" + envBlock, "utf8");
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, import_fs8.writeFileSync)(envPath, envBlock, "utf8");
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, import_path8.join)(cwd, "lib");
5617
- (0, import_fs8.mkdirSync)(mockAuthDir, { recursive: true });
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, import_fs8.writeFileSync)((0, import_path8.join)(mockAuthDir, "mock-auth.ts"), mockAuthContent, "utf8");
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, import_path8.join)(cwd, "package.json");
5638
- if ((0, import_fs8.existsSync)(pkgPath)) {
5639
- const existingPkg = (0, import_fs8.readFileSync)(pkgPath, "utf8");
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, import_fs8.writeFileSync)(pkgPath, updatedPkg, "utf8");
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, import_fs8.writeFileSync)((0, import_path8.join)(cwd, "stackwright.auth.yml"), authYaml, "utf8");
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 import_fs9 = require("fs");
5796
- var import_path9 = require("path");
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, import_path9.basename)(filePath);
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, import_fs9.lstatSync)(filePath);
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, import_fs9.readFileSync)(filePath);
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, import_fs9.readdirSync)(otterDir);
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, import_path9.join)(otterDir, filename);
6180
+ const filePath = (0, import_path10.join)(otterDir, filename);
5966
6181
  try {
5967
- if ((0, import_fs9.lstatSync)(filePath).isSymbolicLink()) {
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 relative of DEFAULT_SEARCH_PATHS) {
5993
- const candidate = (0, import_path9.join)(cwd, relative);
6207
+ for (const relative2 of DEFAULT_SEARCH_PATHS) {
6208
+ const candidate = (0, import_path10.join)(cwd, relative2);
5994
6209
  try {
5995
- (0, import_fs9.lstatSync)(candidate);
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 import_fs10 = require("fs");
6075
- var import_path10 = require("path");
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, import_path10.join)(cwd, ".stackwright", "artifacts", "data-config.json"),
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, import_path10.join)(cwd, "stackwright.yml"),
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, import_fs10.existsSync)(path5)) continue;
6312
+ if (!(0, import_fs11.existsSync)(path5)) continue;
6098
6313
  try {
6099
- const collections = parse((0, import_fs10.readFileSync)(path5, "utf8"));
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, import_path10.join)(cwd, ".stackwright", "artifacts", "workflow-config.json");
6251
- if (!(0, import_fs10.existsSync)(artifactPath)) {
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, import_fs10.readFileSync)(artifactPath, "utf8"));
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 import_js_yaml2 = require("js-yaml");
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, import_js_yaml2.load)(content);
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, import_js_yaml2.dump)(sanitized);
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 import_fs11 = require("fs");
6698
- var import_path11 = require("path");
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, import_path11.join)(cwd, ".stackwright", "artifacts", "theme-tokens.json");
6724
- if (!(0, import_fs11.existsSync)(tokenPath)) return { ...FALLBACK_COLORS };
6725
- const stat = (0, import_fs11.lstatSync)(tokenPath);
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, import_fs11.readFileSync)(tokenPath, "utf-8"));
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, import_fs11.existsSync)(fullPath)) return true;
6789
- const stat = (0, import_fs11.lstatSync)(fullPath);
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, import_fs11.existsSync)(dirPath)) return false;
6794
- const stat = (0, import_fs11.lstatSync)(dirPath);
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, import_fs11.readdirSync)(dirPath).length === 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, import_path11.join)(cwd, relPath);
6810
- if (!(0, import_fs11.existsSync)(fullPath)) {
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, import_fs11.unlinkSync)(fullPath);
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, import_path11.join)(cwd, relPath);
6828
- if (!(0, import_fs11.existsSync)(fullPath)) {
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, import_fs11.readFileSync)(fullPath, "utf-8");
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, import_fs11.unlinkSync)(fullPath);
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, import_path11.join)(cwd, relPath);
6854
- const postsDir = (0, import_path11.join)(cwd, "content/posts");
6855
- if (!(0, import_fs11.existsSync)(fullPath)) {
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, import_fs11.existsSync)(postsDir)) {
7074
+ } else if (!(0, import_fs12.existsSync)(postsDir)) {
6860
7075
  result.skipped.push(relPath);
6861
7076
  } else {
6862
- const userPostFiles = (0, import_fs11.readdirSync)(postsDir).filter(
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, import_fs11.unlinkSync)(fullPath);
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, import_path11.join)(cwd, relDir);
6881
- if (!(0, import_fs11.existsSync)(fullDir)) continue;
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, import_fs11.rmdirSync)(fullDir);
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, import_path11.join)(cwd, NOT_FOUND_PATH);
6897
- if (!(0, import_fs11.existsSync)(fullPath)) {
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, import_path11.dirname)(fullPath);
6906
- (0, import_fs11.mkdirSync)(dir, { recursive: true });
6907
- (0, import_fs11.writeFileSync)(fullPath, content, "utf-8");
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 import_fs12 = __toESM(require("fs"));
7177
- var import_path12 = __toESM(require("path"));
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: import_path12.default.join(projectRoot, "public", "stackwright-content"),
7185
- imagesDir: import_path12.default.join(projectRoot, "public", "images"),
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 = import_path12.default.join(projectRoot, "public", "stackwright-content", "_site.json");
7192
- return JSON.parse(import_fs12.default.readFileSync(sitePath, "utf8"));
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 = import_path12.default.join(ctx.projectRoot, "node_modules", "@stackwright", "build-scripts");
7204
- if (!import_fs12.default.existsSync(bsPath)) {
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 import_fs13 = require("fs");
7419
- var import_path13 = require("path");
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, import_path13.join)(projectRoot, "stackwright.yml");
7423
- const yamlPath = (0, import_path13.join)(projectRoot, "stackwright.yaml");
7424
- if (!(0, import_fs13.existsSync)(ymlPath)) {
7425
- if ((0, import_fs13.existsSync)(yamlPath)) {
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, import_fs13.readFileSync)(ymlPath, "utf-8");
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, import_fs13.writeFileSync)(ymlPath, outputRaw, "utf-8");
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 import_fs14 = require("fs");
7494
- var import_path14 = require("path");
7495
- var import_js_yaml3 = __toESM(require("js-yaml"));
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, import_path14.join)(cwd, "stackwright.integrations.yml");
7499
- if (!(0, import_fs14.existsSync)(filePath)) return [];
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 = import_js_yaml3.default.load((0, import_fs14.readFileSync)(filePath, "utf-8"));
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, import_path14.join)(cwd, "services");
7513
- if (!(0, import_fs14.existsSync)(servicesDir)) return [];
7727
+ const servicesDir = (0, import_path15.join)(cwd, "services");
7728
+ if (!(0, import_fs15.existsSync)(servicesDir)) return [];
7514
7729
  try {
7515
- const files = (0, import_fs14.readdirSync)(servicesDir).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
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 = import_js_yaml3.default.load(
7520
- (0, import_fs14.readFileSync)((0, import_path14.join)(servicesDir, file), "utf-8")
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 import_fs15 = require("fs");
7671
- var import_path15 = require("path");
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, import_path15.basename)(fileName, (0, import_path15.extname)(fileName));
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, import_path15.join)(projectRoot, "specs");
7908
+ const specsDir = (0, import_path16.join)(projectRoot, "specs");
7694
7909
  const empty = { projectRoot, specs: [], totalCount: 0 };
7695
- if (!(0, import_fs15.existsSync)(specsDir)) return empty;
7910
+ if (!(0, import_fs16.existsSync)(specsDir)) return empty;
7696
7911
  let entries;
7697
7912
  try {
7698
- entries = (0, import_fs15.readdirSync)(specsDir);
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, import_path15.join)(specsDir, entry);
7919
+ const fullPath = (0, import_path16.join)(specsDir, entry);
7705
7920
  let stat;
7706
7921
  try {
7707
- stat = (0, import_fs15.statSync)(fullPath);
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, import_path15.extname)(entry).toLowerCase())) continue;
7927
+ if (!ALLOWED_EXTS.has((0, import_path16.extname)(entry).toLowerCase())) continue;
7713
7928
  let snippet = "";
7714
7929
  try {
7715
- snippet = (0, import_fs15.readFileSync)(fullPath, "utf-8").slice(0, 2048);
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 import_fs16 = require("fs");
7962
+ var import_fs17 = require("fs");
7748
7963
  var import_proper_lockfile2 = require("proper-lockfile");
7749
- var import_path16 = require("path");
7750
- var import_js_yaml4 = __toESM(require("js-yaml"));
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, import_path16.basename)(filename, ".json").replace(/^api-config-/, "");
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, import_path16.join)(projectRoot, ".stackwright", "artifacts");
7763
- if (!(0, import_fs16.existsSync)(artifactsDir)) {
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, import_fs16.readdirSync)(artifactsDir).filter(
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, import_fs16.readFileSync)((0, import_path16.join)(artifactsDir, filename), "utf-8");
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, import_path16.join)(projectRoot, "stackwright.integrations.yml");
8023
+ const integrationsYmlPath = (0, import_path17.join)(projectRoot, "stackwright.integrations.yml");
7809
8024
  let existing = {};
7810
- if ((0, import_fs16.existsSync)(integrationsYmlPath)) {
8025
+ if ((0, import_fs17.existsSync)(integrationsYmlPath)) {
7811
8026
  try {
7812
- const raw = (0, import_fs16.readFileSync)(integrationsYmlPath, "utf-8");
7813
- existing = import_js_yaml4.default.load(raw) ?? {};
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, import_fs16.mkdirSync)((0, import_path16.join)(projectRoot), { recursive: true });
7820
- if (!(0, import_fs16.existsSync)(integrationsYmlPath)) {
7821
- (0, import_fs16.writeFileSync)(integrationsYmlPath, "", "utf-8");
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 = import_js_yaml4.default.dump(merged, { lineWidth: 120, noRefs: true });
7831
- (0, import_fs16.writeFileSync)(integrationsYmlPath, header + body, "utf-8");
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.105",
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",